• .NET中操作IPicture、IPictureDisp的小随笔


    【题外话】

    最近在做一个调用某实验仪器的程序,这个仪器提供了Windows上COM的接口。调用仪器的时候需要传输图片,提供的接口里使用了IPicture这个接口,由于以前没接触过,所以查找了一些资料,整理了一下与.NET中System.Drawing.Image的互转的方式。

    【文章索引】

    1. IPicture和IPictureDisp是什么
    2. 使用AxHost实现与System.Drawing.Image的互转
    3. 使用VB6 compatibility library实现互转
    4. Alpha通道的问题

    【一、IPicture和IPictureDisp是什么】

    根据MSDN上对IPicture和IPictureDisp的说明来看,IPicture与IPictureDisp提供了与语言无关的接口,这个接口用来提供对位图(Bitmap)、图标(Icon)、图元文件(Metafile)的抽象,其中后者还实现了IDispatch接口以实现COM的自动化接口。总之,如果通过COM接口传输图像的话,可能会接触到这两个接口。

    【二、使用AxHost实现与System.Drawing.Image的互转】

    .NET在System.Windows.Forms下提供了一个叫AxHost的类来实现与ActiveX控件进行访问,不过这里用到的只是在AxHost里的protected的静态方法而已。由于是protected的方法,所以没有办法直接调用,好在AxHost不是密封的类,所以我们还可以通过集成AxHost来实现调用,例如以下的代码:

     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 }

     

    【三、使用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通道的问题】

    如果你的图片包含Alpha通道的话,上述转换可能会导致颜色有些问题,由于IPicture没有办法支持Alpha通道,所以妥协的办法只能是要么不用Alpha通道,要么在转换为IPicture前在图片底下垫上一个纯色的背景(比如对方程序中要显示图片的位置的背景),比如How to Convert a System.Drawing.Image to an IPictureDisp with Alpha Transparency这篇文章就是这么做的。

    【相关链接】

    1. IPicture interface:http://msdn.microsoft.com/en-us/library/ms680761.aspx
    2. IPictureDisp interface:http://msdn.microsoft.com/en-us/library/ms680762.aspx
    3. Converting between IPictureDisp and System.Drawing.Image:http://blogs.msdn.com/b/andreww/archive/2007/07/30/converting-between-ipicturedisp-and-system-drawing-image.aspx
  • 相关阅读:
    1.权限管理系统
    Django实战1-权限管理功能实现-01:搭建开发环境
    Django实战1-权限管理功能实现-02:项目设置
    Django实战1-权限管理功能实现-03:用户认证
    Django实战1-权限管理功能实现-04:系统入口
    Django实战1-权限管理功能实现-05:组织架构的添加
    Django实战1-权限管理功能实现-06:知识扩展-Django表单
    2.项目环境搭建
    mysql 基础
    Spring Security中 SecurityContextHolder.getContext().getAuthentication().getPrincipal()获取当前用户
  • 原文地址:https://www.cnblogs.com/mayswind/p/3347875.html
Copyright © 2020-2023  润新知