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凌晨