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?