C#调用GDI实现.NET中XOR、AND和OR模式的贴图

来源:互联网 发布:电视直播软件哪个清晰 编辑:程序博客网 时间:2024/06/10 09:20

.NET GDI+提供了比GDI更好的封装,但是它对底层操作的屏蔽导致我们无法用它来实现位图的运算,比如与(SRCAND)、或(SRCPAINT)、异或(SRCINVERT)等方式的贴图。为了实现这些样式的贴图,我们不得不调用GDI。

首先加入下面两行代码,它指明了我们会用到微软的非托管dll的函数:

using System.Runtime.InteropServices;
using System.Reflection; 

下面,我们声明一些GDI函数。由于以前有过使用GDI进行开发的经历,所以很容易想到应该用到的一些函数:SelectObject、DeleteObject、CreateCompatibleDC、DeleteDC、BitBlt等等。

  [DllImport("gdi32.dll")]
  static public extern IntPtr CreateCompatibleDC(IntPtr hDC);
  [DllImport("gdi32.dll",EntryPoint="BitBlt")]
  public static extern bool BitBlt(IntPtr hdcDest,int nXDest,
   int nYDest,int nWidth,int nHeight,IntPtr hdcSrc,
   int nXSrc,int nYSrc,int dwRop);
  [DllImport("user32.dll",EntryPoint="GetDC")]
  public static extern IntPtr GetDC(IntPtr hWnd);
  [DllImport("gdi32.dll")]
  public static extern int SetROP2(int h,int op);
  [DllImport("gdi32.dll")]
  static public extern bool DeleteObject(IntPtr hObject);
  [DllImport("gdi32.dll")]
  static public extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
  [DllImport("gdi32.dll")]
  static public extern IntPtr DeleteDC(IntPtr hDC);

假定我们有一幅Bitmap叫做m_background,我们需要将它和另两个Bitmap:m_filter和m_foreground进行下面的操作:

m_filter是一个黑白图片,我们需要在m_filter为白的部分保持m_background的图像,而在m_filter为黑的部分贴上m_foreground的图像。

容易想到,这可以用(m_background AND m_filter) OR m_foreground来完成。

这里的一个AND和一个OR操作需要用BitBlt函数完成。我们先声明表示操作的一些常量:

  const int SRCAND = 0x8800C6; // (DWORD) dest = source AND dest
  const int SRCCOPY = 0xCC0020; // (DWORD) dest = source
  const int SRCERASE = 0x440328; // (DWORD) dest = source AND (NOT dest )
  const int SRCINVERT = 0x660046; // (DWORD) dest = source XOR dest
  const int SRCPAINT = 0xEE0086; // (DWORD) dest = source OR dest

(其实只要SRCAND和SRCPAINT就可以了,因为本文只讲到了AND和OR模式的贴图。其他模式的贴图可以类似操作。)

然后,我们在内存中建立一个缓冲区保存操作中生成的图片的中间结果:

System.IntPtr hMemBackground=CreateCompatibleDC(hdc);

System.IntPtr hMemTemp=CreateCompatibleDC(hdc);

其中,hdc可以这样获得:比如我们要在一个变量名为pic的PictureBox上贴图,那么首先获得它的Graphics对象:

Graphics g=pic.CreateGraphics();

随后获取它对应的设备指针:

System.IntPtr hdc=g.GetHdc();

其后的操作就简单许多,先把背景和过滤器图片分别选到hMemBackground和hMemTemp中,不过要注意保存原来的位图以便结束以后恢复内存空间:

System.IntPtr hBmpBackground=SelectObject(hMemBackground,m_background.GetHBitmap());

System.IntPtr hBmpTemp=SelectObject(hMemTemp,m_filter.GetHBitmap());

随后是AND模式的贴图:

BitBlt(hMemBackground,0,0,m_filter.Width,m_filter.Height,hMemTemp,0,0,SRCAND);

(这里假设m_filter、m_background和m_foreground都是一个大小的。如果你想用不同大小的m_foreground和m_background,也是可以的,不过要注意贴图的坐标。)

照猫画虎,完成第二步OR模式的贴图:

SelectObject(hMemTemp,m_foreground.GetHbitmap());
BitBlt(hMemBackground,i*23+1,i*23+1,m_foreground.Width,m_foreground.Height,hMemTemp,0,0,SRCPAINT);

结束了吗?

没有。别忘了,还要恢复原来的位图,以及清理掉一些垃圾哦:

SelectObject(hMemBackground,hBmpBackground);
SelectObject(hMemTemp,hBmpTemp);

g.ReleaseDC();

DeleteDC(hMemTemp);

DeleteDC(hMemBackground);

qpcegg

2007.01.09凌晨