VB自己的绘图语句都需要用LoadPicture载入图片,同样,GDI+中也需要。
1.载入(初始化)图片资源
(1)来自文件:GdipLoadImageFromFile
我们先来看看这个最简单基本的载入图片来自文件:
Dim img As Long , img_W As Long , img_H As Long GdipLoadImageFromFile StrPtr( "C:TestImage.png" ), img '如果你希望得到长宽信息,可以使用下面的语句: GdipGetImageWidth img, img_W GdipGetImageHeight img, img_H Msgbox "长为:" & CStr (img_W) & "px, 宽为:" & CStr (img_H) & "px." 'GdipDisposeImage img |
载入图像之后别忘记释放Image,否则会造成MemoryLeak内存泄漏(另外如果没有Dispose掉的话这个文件是被占用的)。
(2)来自资源文件:GdipLoadImageFromStream (2010/2/9修改)
这个函数主要是用来从资源文件(RES)载入图像的,怎么载入呢?我们来看函数,函数是从Stream载入,但是我们VB6没有集成Stream对象,从RES读取出来(LoadResData)也只是返回Byte()。不过很好,OLE提供了一个函数能够将Byte()变为一个IStream对象——我们需要这个API [注:声明已于2011/2/9修改]。
Declare Sub CreateStreamOnHGlobal Lib "ole32.dll" ( ByVal hGlobal As Long , ByVal fDeleteOnRelease As Long , ByRef ppstm As Any) |
但是,函数第一个参数需要的是一个内存句柄而不是内存地址,这两个值有时一样有时不一样。当调用申请内存GlobalAlloc函数使用GMEM_FIXED参数时候它们相同,其它时候它们不同,一个数组的内存空间是否是GMEM_FIXED申请的取决于数组的声明位置等各种因素。所以我们可不能这么冒险假定hMem=pMem。那我们如何得到数据的内存句柄呢?新申请一块内存就得到句柄了,然后我们只需要复制数据即可。
示例代码 [2011/8/8 更新 感谢Марков]:
'声明部分如下 Private Declare Function GlobalAlloc Lib "kernel32" ( ByVal wFlags As Long , ByVal dwBytes As Long ) As Long Private Declare Function GlobalUnlock Lib "kernel32" ( ByVal hMem As Long ) As Long Private Declare Function GlobalLock Lib "kernel32" ( ByVal hMem As Long ) As Long Private Declare Function GlobalFree Lib "kernel32" ( ByVal hMem As Long ) As Long Private Declare Sub RtlMoveMemory Lib "kernel32" ( ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long ) Const GMEM_MOVEABLE As Long = &H2 '实现部分如下 Dim img As Long Dim ResData() As Byte , IStream As Object ResData = LoadResData(101, "CUSTOM" ) '获取数据 '接下来需要一个内存句柄而不是内存地址 Dim hMemObj As Long , pMem As Long hMemObj = GlobalAlloc(GMEM_MOVEABLE, UBound(ResData) + 1) '申请新内存获得句柄 pMem = GlobalLock(hMemObj) If pMem = 0 Then '分配内存失败 Msgbox "Global alloc failed!" Exit Sub End If RtlMoveMemory ByVal pMem, ResData(0), UBound(ResData)+1 '复制源数据到新内存 GlobalUnlock hMemObj CreateStreamOnHGlobal ByVal hMemObj, False , IStream '根据新内存句柄创建IStream GdipLoadImageFromStream IStream, img '建立Image Set IStream = Nothing GlobalFree hMemObj '释放新内存 'GdipDisposeImage img '图片不要忘记释放了 |
2.绘制图片
(1)GdipDrawImage(I)
这是Gdi+绘图的一种基础画法,不需要进行长宽设置,不过我们平时不怎么用它。它按照图片的物理大小绘制,完全无视所有Graphics的Scale等缩放参数。这个函数支持32位透明通道绘制。(技巧:有I的一般 坐标、长宽都是Long型 没有I的一般都是Single型)
什么是物理大小?这个就要跟图像的分辨率(dpi)有关了。打开你的Photoshop或者是Fireworks或者是AI或者其他专业绘图软件,新建一个文档,你就会发现有分辨率选项,一般你看到的是72像素/英寸。但是,请注意,一般屏幕的分辨率是96像素/英寸。
96这个值可以在系统的显示设置中看到。在Windows7中的查看步骤是:桌面右键->屏幕分辨率->放大或缩小文本和其他项目->(左侧)设置自定义文本大小(DPI),在弹出对话框中有显示“每英寸 X 像素”。
图片一般的分辨率与屏幕的分辨率不一致,这会有什么结果?一般不会有问题,因为我们一般图像的绘制以px为单位,无论分辨率多高(结果是物理尺寸变小),图像都是包含了同样数量的像素点。可是现在这个函数是按照物理大小绘制的,这样Dpi的不同势必就会造成绘制出来的图像有“缩放”,一般呈现为比正常大小大。
分辨率如何调整?以后再说。
Dim img As Long GdipLoadImageFromFile StrPtr( "C:TestImage.png" ), img '此处请初始化GDI+以及graphics GdipDrawImage graphics, img, 0, 0 |
拓展阅读:
(2)GdipDrawImageRect(I) 推荐
这是我们常用的画法,一般Gdi+画图就用这个函数。我们可以对图片的大小进行平滑的拉伸缩放。
Dim img As Long GdipLoadImageFromFile StrPtr( "C:TestImage.png" ), img '此处请初始化GDI+以及graphics GdipDrawImageRect graphics, img, 0, 0, 100, 200 '拉伸到100*200 |
(3)GdipDrawImageRectRect(I)
还有个有点常用的函数就是这个了。通过它我们可以画一个图的一个部分,并且同样可以改变大小(好处:我们可以把所有的图片资源综合到一个图片中),另外它支持一个叫做ImageAttribs的东西,这是图片的滤镜,我们可以改变图片透明度和各种颜色参数(如二值化,灰度化等)。ImageAttrib(utes)会在之后的教程中有所涉及。
代码如下:
Dim img As Long GdipLoadImageFromFile StrPtr( "C:TestImage.png" ), img '此处请初始化GDI+以及graphics GdipDrawImageRectRectI graphics, img, 20, 20, 10, 10, 0, 0, 100, 200, UnitPixel |
注意咯
第三~第六个参数是原来图片中要截取的部分;第七~第十呢则是画到哪里以及画出来多大的设置
第三~第六个参数是为绘制位置和绘制尺寸;第七~第十则是截取位置和截取尺寸。
(4)贴图刷
贴图刷子主要用来绘制平铺的内容。贴图刷子跟其它刷子一样,我们需要创建刷子,另外对于这个刷子我们需要先初始化图片:)
Dim img As Long , textureBrush As Long GdipLoadImageFromFile StrPtr( "C:TestImage.png" ), img '此处请初始化GDI+以及graphics GdipCreateTexture img, WrapModeTileFlipX, textureBrush GdipFillRectangle graphics, textureBrush, 0, 0, 100, 100 |
贴图刷子跟其它刷子有什么区别呢?普通的图片绘制(如DrawImageRectI)支持的是拉伸,贴图刷则是平铺。另外贴图刷还要注意定位问题。因为贴图刷纹理起始点是Graphics的0,0,而不是绘制内容的左上角坐标。
贴个图,直观明了。
那么贴图刷子中如何调整图片起始位置呢?我们可以平移图片——GdipTranslateTextureTransform。参数很简单 是平移量。(注意:这是个相对平移,也就是这个平移是参照之前量的,而不是原图片;因此建议更改平移量要先Reset下:GdipResetTextureTransform)