How to Convert a System.Drawing.Image to an IPictureDisp with Alpha Transparency

Anyone who wants to build a professional looking add-in for Microsoft Outlook knows that it’s important to make their add-in appear flush/stock/standard/factory, which means implementing the add-in functionality directly into the native Outlook interface via the toolbar/ribbon/menu/property pages/etc. An important part of this is understanding how to use IPictureDisp, because this is the only image type that Outlook will allow you to use for CommandBar controls.

I’ve been working on a few add-ins for Outlook recently and ran into a problem trying to use .png images for the Outlook.CommandBar objects. What makes this difficult is the fact that Outlook’s CommandBar and related controls require images to be IPictureDisp objects; it does not support System.Drawing.Image objects directly. You can observe the Outlook.CommandBarButton.Picture and Outlook.CommandBarButton.Mask properties; they only accept an object of type IPictureDisp. Therefore, I needed a decent way to convert a System.Drawing.Image (including any alpha transparency) into an IPictureDisp in order to integrate my custom icons into the native Outlook toolbar.

Lo and behold, a quick Google for ipicturedisp mask digs up a solution on MSDN in an astounding 0.28 seconds. Hold on there cowboy!!! That solution was posted by me several years ago which I have since forgotten about….weird!

Anyhow, here’s the class that wraps up all this functionality:

Public Class IPictureDisp
  Inherits System.Windows.Forms.AxHost
  Public Sub New()
    MyBase.New("59EE46BA-677D-4d20-BF10-8D8067CB8B32")
  End Sub

  Public Shared Function FromImage(ByVal pImg As System.Drawing.Image) As stdole.IPictureDisp
    Dim b As New Bitmap(16, 16)
    Dim g As Graphics = Graphics.FromImage(b)
    ' fill the bitmap with white
    g.FillRectangle(Brushes.White, 0, 0, 16, 16)
    ' draw the image over the white bitmap
    g.DrawImage(pImg, 0, 0, 16, 16)
    ' return the opaque image
    Return GetIPictureFromPicture(b)
  End Function

  Public Shared Function MaskFromImage(ByVal pImg As System.Drawing.Image) As stdole.IPictureDisp
    Dim b As New Bitmap(16, 16)
    Dim g As Graphics = Graphics.FromImage(b)
    ' draw the image over the transparent bitmap
    g.DrawImage(pImg, 0, 0, 16, 16)
    ' convert pixels to grayscale
    For x As Integer = 0 To 15
      For y As Integer = 0 To 15
        ' get the pixel alpha
        Dim pa As Integer
        pa = b.GetPixel(x, y).A
        ' get the grayscale alpha equivalent of the pixel alpha
        Dim pg As Integer
        pg = 255 - pa
        ' replace the current pixel with a grayscale equivalent
        b.SetPixel(x, y, Color.FromArgb(pg, pg, pg))
      Next
    Next
    ' return the picture
    Return GetIPictureFromPicture(b)
  End Function
End Class

And to use the class, just do something like this:

Dim myButton as Outlook.CommandBarButton
myButton.Picture = IPictureDisp.FromImage(my.resources.icon1)
myButton.Mask = IPictureDisp.MaskFromImage(my.resources.icon1)

The original solution can be found in the MSDN article How to: Add Custom Icons to Toolbar and Menu Items

Related

Tags: , ,

2 Comments

  1. Thank you for the excellent article: I have a question:
    Is it possible to associate an icon to the Toolbar itself (in addition to the buttons’ icons) ?

  2. Thanks, I have searched this solution for 3 hours.

Leave a Reply

Your email address will not be published. Required fields are marked *