【题外话】redis
最近在作一个调用某实验仪器的程序,这个仪器提供了Windows上COM的接口。调用仪器的时候须要传输图片,提供的接口里使用了IPicture这个接口,因为之前没接触过,因此查找了一些资料,整理了一下与.NET中System.Drawing.Image的互转的方式。ui
【文章索引】spa
【1、IPicture和IPictureDisp是什么】.net
根据MSDN上对IPicture和IPictureDisp的说明来看,IPicture与IPictureDisp提供了与语言无关的接口,这个接口用来提供对位图(Bitmap)、图标(Icon)、图元文件(Metafile)的抽象,其中后者还实现了IDispatch接口以实现COM的自动化接口。总之,若是经过COM接口传输图像的话,可能会接触到这两个接口。code
【2、使用AxHost实现与System.Drawing.Image的互转】orm
.NET在System.Windows.Forms下提供了一个叫AxHost的类来实现与ActiveX控件进行访问,不过这里用到的只是在AxHost里的protected的静态方法而已。因为是protected的方法,因此没有办法直接调用,好在AxHost不是密封的类,因此咱们还能够经过集成AxHost来实现调用,例如如下的代码:blog
1 using System.Drawing; 2 using System.Windows.Forms; 3 4 public sealed class IPictureConverter : AxHost 5 { 6 private IPictureConverter() : base("") { } 7 8 #region IPictureDisp 9 public static stdole.IPictureDisp ImageToIPictureDisp(Image image) 10 { 11 return (stdole.IPictureDisp)GetIPictureDispFromPicture(image); 12 } 13 14 public static Image IPictureDispToImage(stdole.IPictureDisp pictureDisp) 15 { 16 return GetPictureFromIPictureDisp(pictureDisp); 17 } 18 #endregion 19 20 #region IPicture 21 public static stdole.IPicture ImageToIPicture(Image image) 22 { 23 return (stdole.IPicture)GetIPictureFromPicture(image); 24 } 25 26 public static Image IPictureToImage(stdole.IPicture picture) 27 { 28 return GetPictureFromIPicture(picture); 29 } 30 #endregion 31 }
【3、使用VB6 compatibility library实现互转】索引
除了AxHost,其实微软也提供了另一个库提供托管的Image与IPicture等互转,那就是Microsoft.VisualBasic.Compatibility.dll,其中有一个叫Support的类提供了不少向后兼容的方法。对于IPicture或IPictureDisp的转换,咱们能够写以下代码:接口
1 using System.Drawing; 2 using Microsoft.VisualBasic.Compatibility.VB6; 3 4 public static class IPictureConverter 5 { 6 #region IPictureDisp 7 public static stdole.IPictureDisp ImageToIPictureDisp(Image image) 8 { 9 return (stdole.IPictureDisp)Support.ImageToIPictureDisp(image); 10 } 11 12 public static Image IPictureDispToImage(stdole.IPictureDisp pictureDisp) 13 { 14 return Support.IPictureDispToImage(pictureDisp); 15 } 16 #endregion 17 18 #region IPicture 19 public static stdole.IPicture ImageToIPicture(Image image) 20 { 21 return (stdole.IPicture)Support.ImageToIPicture(image); 22 } 23 24 public static Image IPictureToImage(stdole.IPicture picture) 25 { 26 return Support.IPictureToImage(picture); 27 } 28 #endregion 29 }
仔细看其实与上一段代码很是相似,本着好奇的态度,咱们Relector一下这些方法实现的代码。图片
看起来二者几乎是同样的,不过有意思的是,虽然二者的不少方法如GetPICTDESCFromPicture等都不是同一个方法,甚至IPicture等接口都不是在一个库里定义的(AxHost是在System.Windows.Forms.UnsafeNativeMethods中定义的,而VB6 compatibility library则是在单独的一个stdole.dll中定义的),可是其调用的方法里执行的内容基本都相同,IPicture等接口也都是ComImport的同一个Guid,而两个方法实现的源头,更都是DllImport的oleaut32.dll,调用其中的“OleCreatePictureIndirect”方法,因此上述两种方法是彻底同样的。
不过在4.0的CLR下,提供的Microsoft.VisualBasic.Compatibility.dll的版本为10.0.0.0,Support类以及相应的方法都被标记为过期的(Obsolete),因此编译的时候提示的警告也蛮让人恶心的(2.0的CLR下提供的8.0.0.0的dll没有这个问题),因此倒不妨采用第一种方法。
若是你的图片包含Alpha通道的话,上述转换可能会致使颜色有些问题,因为IPicture没有办法支持Alpha通道,因此妥协的办法只能是要么不用Alpha通道,要么在转换为IPicture前在图片底下垫上一个纯色的背景(好比对方程序中要显示图片的位置的背景),好比How to Convert a System.Drawing.Image to an IPictureDisp with Alpha Transparency这篇文章就是这么作的。
【相关连接】