1

When creating a new point layer with picture symbols in ArcMap 10.2.1 using ArcObjects, I have tried several ways to load semi-transparent symbol images from .png files, but to no avail, the transparency is always lost and appearing opaque.

Since IPictureMarkerSymbol.CreateMarkerSymbolFromFile doesn't handle .png, I think I will have to create the IPictureDisp myself. I know it should work somehow, since I can load the same semi-transparent .png file manually in the picture symbol in ArcMap, resulting in correct semi-transparency. And I know about the support for setting a transparency color, but it wouldn't handle semi-transparency.

My current solution, inspired from this post, goes something like this (except for the creation of the actual layer) but doesn't work either:

class IPictureDispConverter
{
  public static Guid iPictureDispGuid = typeof(stdole.IPictureDisp).GUID;

  /// Converts an Icon into a IPictureDisp
  public static IPictureDisp ConvertBitmapToIPictureDisp(Bitmap bitmap)
  {
    PICTDESC.Bitmap pictBit = new PICTDESC.Bitmap(bitmap);
    return OleCreatePictureIndirect(pictBit, ref iPictureDispGuid, true);
  }

  [DllImport("OleAut32.dll", EntryPoint = "OleCreatePictureIndirect", ExactSpelling = true, PreserveSig = false)]
  private static extern stdole.IPictureDisp OleCreatePictureIndirect([MarshalAs(UnmanagedType.AsAny)] object picdesc, ref Guid iid, bool fOwn);

  // WINFORMS COMMENT:
  // PICTDESC is a union in native, so we'll just
  // define different ones for the different types
  // the "unused" fields are there to make it the right
  // size, since the struct in native is as big as the biggest
  // union.
  private static class PICTDESC
  {
    //Picture Types
    public const short PICTYPE_UNINITIALIZED = -1;
    public const short PICTYPE_NONE = 0;
    public const short PICTYPE_BITMAP = 1;
    public const short PICTYPE_METAFILE = 2;
    public const short PICTYPE_ICON = 3;
    public const short PICTYPE_ENHMETAFILE = 4;

    [StructLayout(LayoutKind.Sequential)]
    public class Icon
    {
      internal int cbSizeOfStruct = Marshal.SizeOf(typeof(PICTDESC.Icon));
      internal int picType = PICTDESC.PICTYPE_ICON;
      internal IntPtr hicon = IntPtr.Zero;
      internal int unused1 = 0;
      internal int unused2 = 0;

      internal Icon(System.Drawing.Icon icon)
      {
        this.hicon = icon.ToBitmap().GetHicon();
      }
    }

    [StructLayout(LayoutKind.Sequential)]
    public class Bitmap
    {
      internal int cbSizeOfStruct = Marshal.SizeOf(typeof(PICTDESC.Bitmap));
      internal int picType = PICTDESC.PICTYPE_BITMAP;
      internal IntPtr hbitmap = IntPtr.Zero;
      internal IntPtr hpal = IntPtr.Zero;
      internal int unused = 0;

      internal Bitmap(System.Drawing.Bitmap bitmap)
      {
        this.hbitmap = bitmap.GetHbitmap();
      }
    }
  }
}

// FROM ANOTHER PART OF THE CODE:

IPictureMarkerSymbol markerSymbol = new PictureMarkerSymbolClass();
Bitmap bitmap = new Bitmap(pngFilename);
markerSymbol.Picture = IPictureDispConverter.ConvertBitmapToIPictureDisp(bitmap);

ISimpleRenderer renderer = new SimpleRendererClass();
((IGeoFeatureLayer)layer).Renderer = renderer as IFeatureRenderer;
renderer.Symbol = markerSymbol.Picture as ISymbol;

Here is the result with my code:

Doesn't work

And here it is when I have pointed out the same .png file manually for the same layer in ArcMap afterwards:

Works

Does anyone know how to do this properly?

0

Turns out that CreateMarkerSymbolFromFile actually works with PNG, despite of the docs saying it only works with BMP and EMF. Didn't work when I tried it at first, but probably due to some other error. Anyway, just use CreateMarkerSymbolFromFile with esriIPictureType.esriIPicturePNG and it works fine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.