A recurring issue was observed in Autodesk Inventor where ribbon icons appeared distorted when using the Dark Theme. Developers reported icons looking fuzzy, losing transparency, or displaying unwanted white edges. This affected .bmp image formats across Inventor 2024, 2025, and 2026.
After detailed analysis, it was found that the problem originated from how icon images were being converted to IPictureDisp objects before being assigned to ribbon buttons.
This article explains the investigation, the cause, and the final working solution — including the enhanced PictureDispConverter.cs class that restores proper alpha transparency and consistent icon rendering.
Issue Summary
Observed Behavior
- Icons appear fuzzy or lose sharpness in dark theme.
- White pixels become transparent; semi-transparent edges turn white.
- Transparency artifacts persist across
.icoand.pngicons. - Conversion through
stdole.IPictureDispcauses transparency loss.
Root Cause
The standard conversion from .NET Image to stdole.IPictureDisp was creating a bitmap-based image (PICTYPE_BITMAP), which doesn’t preserve transparency when internally converted to an icon (HICON) by Inventor.
Technical Solution
The fix involves ensuring that the conversion explicitly creates a PICTYPE_ICON type IPictureDisp, preserving the alpha transparency of the icon.
This is achieved by customizing the PictureDispConverter.cs file from the Inventor SDK SimpleAddIn project.
Below is the complete working version.
Complete Code: PictureDispConverter.cs
using Inventor;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace InvAddIn
{
public static class PictureDispConverter
{
// IPictureDisp GUID reference
static Guid iPictureDispGuid = typeof(stdole.IPictureDisp).GUID;
/// Converts an Icon into an IPictureDisp (PICTYPE_ICON)
public static stdole.IPictureDisp ToIPictureDisp(Icon icon)
{
PICTDESC.Icon pictIcon = new PICTDESC.Icon(icon);
return NativeMethods.OleCreatePictureIndirect(pictIcon, ref iPictureDispGuid, true);
}
/// Converts a Bitmap into an IPictureDisp (PICTYPE_ICON)
public static stdole.IPictureDisp ToIPictureDisp(Bitmap bitmap)
{
PICTDESC.Icon pictIcon = new PICTDESC.Icon(bitmap);
return NativeMethods.OleCreatePictureIndirect(pictIcon, ref iPictureDispGuid, true);
}
/// Converts a general Image into an IPictureDisp (PICTYPE_BITMAP)
public static stdole.IPictureDisp ToIPictureDisp(Image image)
{
Bitmap bitmap = image as Bitmap;
if (bitmap == null)
bitmap = new Bitmap(image);
PICTDESC.Bitmap pictBit = new PICTDESC.Bitmap(bitmap);
return NativeMethods.OleCreatePictureIndirect(pictBit, ref iPictureDispGuid, true);
}
static class NativeMethods
{
#pragma warning disable CS0618
[DllImport("OleAut32.dll", EntryPoint = "OleCreatePictureIndirect", ExactSpelling = true, PreserveSig = false)]
public static extern stdole.IPictureDisp OleCreatePictureIndirect(
[MarshalAs(UnmanagedType.AsAny)] object picdesc,
ref Guid iid,
[MarshalAs(UnmanagedType.Bool)] bool fOwn);
#pragma warning restore CS0618
}
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;
internal int unused2;
internal Icon(System.Drawing.Icon icon)
{
this.hicon = icon.ToBitmap().GetHicon();
}
internal Icon(System.Drawing.Bitmap bitmap)
{
this.hicon = bitmap.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;
internal Bitmap(System.Drawing.Bitmap bitmap)
{
this.hbitmap = bitmap.GetHbitmap();
}
}
}
}
}
Key Code Highlights and Explanation
1. Switching from PICTYPE_BITMAP to PICTYPE_ICON
This is the core fix:
PICTDESC.Icon pictIcon = new PICTDESC.Icon(bitmap);
return NativeMethods.OleCreatePictureIndirect(pictIcon, ref iPictureDispGuid, true);
Inventor treats the result as a native HICON, preserving transparency during rendering.
2. Using OleCreatePictureIndirect for Native Conversion
OleCreatePictureIndirect (from OleAut32.dll) generates a COM-compatible IPictureDisp.
This avoids the internal bitmap conversions that cause transparency loss.
3. Internal Icon Conversion
The PICTDESC.Icon struct creates an HICON directly from a .NET bitmap:
this.hicon = bitmap.GetHicon();
This works consistently for:
.ico.png.bmp(where the issue was originally observed)
4. Maintaining Compatibility
ToIPictureDisp(Image image) still uses PICTYPE_BITMAP for older add-ins that rely on the previous behavior.
Results
After implementing this updated converter:
✔ Icons render cleanly in both Light and Dark themes
✔ Transparency and anti-aliasing are preserved
✔ No fuzzy or white borders
✔ Works consistently for .png, .ico, and .bmp sources
✔ Fix verified across Inventor 2024–2026
Takeaways
| Aspect | Before Fix | After Fix |
|---|---|---|
| Image Type | PICTYPE_BITMAP | PICTYPE_ICON |
| Transparency | Lost | Preserved |
| Dark Theme Rendering | Fuzzy, white edges | Crisp and clear |
| Conversion Method | AxHost.GetIPictureDispFromPicture | OleCreatePictureIndirect (Icon) |
Conclusion
By explicitly converting ribbon icons to PICTYPE_ICON using OleCreatePictureIndirect, developers can ensure:
- Full transparency preservation
- Clean rendering in both Light and Dark themes
- Reliable behavior across all supported Inventor versions
This small but impactful enhancement significantly improves the user experience and aligns Inventor add-in development with modern UI rendering standards.

Leave a Reply