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:
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?
The IPictureMarkerSymbol.CreateMarkerSymbolFromFile Method has a PNG in its esriIPictureType parameter.
I just tried it using this Snippet and It works fine.
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!