Semi-transparent picture symbols in ArcObjects

11-28-2014 06:28 AM
New Contributor II

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);

  // 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;

    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();

    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();


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:


Does anyone know how to do this properly?

Tags (2)
2 Replies
Occasional Contributor III

The IPictureMarkerSymbol.CreateMarkerSymbolFromFile Method has a PNG in its esriIPictureType parameter.
I just tried it using this Snippet and It works fine.

New Contributor II

Wow, thanks Ahmed - it actually works. I was fooled by this in the CreateMarkerSymbolFromFile doc:

Supported types are esriIPictureBitmap (bitmap images) and esriIPictureEMF (emf files).

And it didn't work when I tried it before, but probably due to some other error. Anyway, problem solved!

0 Kudos