图像处理系列教程二:GDI+版图像数据的获取

GDI+是对GDI的很大程度上的改进,其设计理念以及操作的方式和GDI相比有了本质的不同,因其优秀的抗锯齿功能以丰富接口函数深受广大图像和图形编程者的爱好,同GDI相比,在编程上有着较大的不同。

在GDI+的一些列函数中,有两个比较特殊,他们是GdiplusStartup以及GdiplusShutdown,在执行所有的GDI+图形或图像的函数前,一定要先调用GdiplusStartup函数,否则将返回GdiplusNotInitialized的错误,在程序关闭之前一定要调用GdiplusShutdown,否则如果你是处于VB的IDE中,则不定时的会出现VB的IDE需要关闭的错误,此时,即使你不管他,一旦在VB中有输入中文或复制等动作时,VB就会出现假死,VB中的任何按钮都不可点击。

GDI+对图像格式的支持相对于GDI有了很大的扩展,在VB6.0中,不支持透明图像,比如Png格式,这个是有历史原因的,在VB6.0发行的时候,Png格式并未获得流行。GDI+可打开的格式有BMP、JPEG、GIF、PNG、TIFF 等,其中GIF、TIFF可包含多帧图像。同样,GDI+亦支持对上述格式的保存,但是不能保存多帧的GIF,这和GIF的版权可能有关。

在VB中调用GDI+也是一件简单的事情,网络上已经有完整的平板化GDI+的API下载,无法找到链接或者需要的可以直接和我联系。

好了,废话少说,下文我们简单谈谈如何利用GDI+获取图像的数据。

首先,我们需要做的是打开一副图像,这个在GDI+中有个函数GdipLoadImageFromFile,这个函数我们经常看到有两个版本的声明,分别为:

Private Declare Function GdipLoadImageFromFile Lib "gdiplus" (ByVal FileName As String,Image As Long) As Long

Private Declare Function GdipLoadImageFromFile Lib "gdiplus" (ByVal FileName As Long,hImage As Long) As Long

其中第一个版本的FileName不能直接用我们的路径,而是用StrConv(FileName,vbUnicode),否则调用会失败,第二个版本则用StrPtr(FileName)。

如果我们调用成功,则Image的值不为0。

如果image不为0,则说明我们调用成功,此时如果需要显示他,则可以直接调用GdipDrawImage或其其他重载函数。

为了得到图像数据以便我们进一步处理,我们需要寻找合适的函数,GDI+中同样有类似于GDI的GetPixel函数,即GdipBitmapGetPixel,同样这个不适合于图像处理,接着我们在GDI+的平板化API中寻找了GdipBitmapLockBits/ GdipBitmapUnlockBits这样一对函数,其声明如下:

Public Declare Function GdipBitmapLockBits Lib "gdiplus" (ByVal bitmap As Long,rect As RECTL,ByVal flags As ImageLockMode,ByVal PixelFormat As Long,lockedBitmapData As BitmapData) As long

Public Declare Function GdipBitmapUnlockBits Lib "gdiplus" (ByVal bitmap As Long,lockedBitmapData As BitmapData) As long

我们先看看这个BitmapData结构。

Public Type BitmapData
   Width As Long
   Height As Long
   stride As Long
   PixelFormat As Long
   scan0 As Long
   Reserved As Long
End Type

查看MSDN,可以知道Width、Height分别表示图像的宽度和高度,stride表示图像的扫描行宽度,PixelFormat表示图像格式,而这个scan0则表示图像的内存地址。这个scan0真是个令人欢喜的东西令人忧的东西啊,欢喜的是我们找到图像的数据了,忧的而是他是个指针,而VB没有指针。在我很久前发布的一篇文章vb.net中彩色图像数据的快速获取中所采用的方法是用Marshal.Copy把数据拷贝到一个临时数组中,那是因为在VB.NET真的无法用指针,并且使用这种方法一会造成速度缓慢,因为图像数据处理完后又要拷贝回去,二是占用的内存要多一倍。令人欣慰的是,在VB6.0中,我们可以用模拟指针的方法间接实现直接访问内存。具体请参考 图像处理系列教程之三:VB中的指针。

在调用GdipBitmapLockBits后,如果调用成功,则会将相关信息填充到lockedBitmapData结构体中,类似于GetDIBits函数,该函数也可以设置要获取的格式,即PixelFormat参数,但是,由于GDI+的出发点不同,他会动态的加载Image,即调用GdipLoadImageFromFile函数并没有为图像分配对应的内存,因此我们强烈建议这里的PixelFormat设置成和图像实际的格式一致,这个格式可以通过GdipGetImagePixelFormat获得。

至于参数中的RECTL,则表示要获取数据的矩形区域,如果你只需获取部分数据,则可以在这里改变,一般我们都需要获取图像的整个数据,这里有几个函数可以使用。,如下:

GdipGetImageWidth/ GdipGetImageHeight  或者GdipGetImageDimension

在处理完图像的数据后,类似于SetDibits,我们要调用GdipBitmapUnlockBits来更新图像。

另外,在GDI+中除了可以利用GdipLoadImageFromFile从文件中创建GDI+的Image对象,还可利用GdipCreateBitmapFromGdiDib从GDI的DIB对象、利用GdipCreateBitmapFromHBITMAP从StdPicture对象,利用GdipCreateBitmapFromHICON从Icon的句柄,利用GdipCreateBitmapFromScan0从位图在内存的首地址等等对象创建Image,因此可方便的将GDI的图形对象转换到GDI+中。

GDI+中没有DC属性,取而代之的是Graphics对象,要绘制图像,必须先创建Graphics,GdipCreateFromHDC函数可以将DC转换为Graphics,然后调用绘图函数绘制后一定要记得GdipDeleteGraphics已删除。

同样,当不在使用Image对象时,也需要调用GdipDisposeImage释放他。

代码下载地址见 :http://www.hellocpp.net/Articles/Article/457.aspx

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Format[$] ( expr [ , fmt ] ) format 返回变体型 format$ 强制返回为文本 -------------------------------- 数字类型的格式化 --------------------------------     固定格式参数:     General Number 普通数字,如可以用来去掉千位分隔号     format$("100,1
VB6或者ASP 格式化时间为 MM/dd/yyyy 格式,竟然没有好的办法, Format 或者FormatDateTime 竟然结果和系统设置的区域语言的日期和时间格式相关。意思是尽管你用诸如 Format(Now, "MM/dd/yyyy"),如果系统的设置格式区域语言的日期和时间格式分隔符是"-",那他还会显示为 MM-dd-yyyy     只有拼凑: <%response.write
在项目中添加如下代码:新建窗口来显示异常信息。 Namespace My ‘全局错误处理,新的解决方案直接添加本ApplicationEvents.vb 到工程即可 ‘添加后还需要一个From用来显示错误。如果到这步还不会则需要先打好基础啦 ‘======================================================== ‘以下事件
转了这一篇文章,原来一直想用C#做k3的插件开发,vb没有C#用的爽呀,这篇文章写与2011年,看来我以前没有认真去找这个方法呀。 https://blog.csdn.net/chzjxgd/article/details/6176325 金蝶K3 BOS的插件官方是用VB6编写的,如果  能用.Net下的语言工具开发BOS插件是一件很愉快的事情,其中缘由不言而喻,而本文则是个人首创,实现在了用V
Sub 分列() ‘以空格为分隔符,连续空格只算1个。对所选中的单元格进行处理 Dim m As Range, tmpStr As String, s As String Dim x As Integer, y As Integer, subStr As String If MsgBox("确定要分列处理吗?请确定分列的数据会覆盖它后面的单元格!", _
  窗体代码 1 Private Sub Text1_OLEDragDrop(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, X As Single, Y As Single) 2 Dim path As String, hash As String 3 For Each fil
  Imports MySql.Data.MySqlClient Public Class Form1 ‘ GLOBAL DECLARATIONS Dim conString As String = "Server=localhost;Database=net2;Uid=root;Pwd=123456;" Dim con As New MySqlConnection
‘導入命名空間 Imports ADODB Imports Microsoft.Office.Interop   Private Sub A1() Dim Sql As String Dim Cnn As New ADODB.Connection Dim Rs As New ADODB.Recordset Dim S As String   S = "Provider=OraOLEDB.Oracl
Imports System.IO Imports System.Threading Imports System.Diagnostics Public Class Form1 Dim A(254) As String    Function ping(ByVal IP As Integer) As String Dim IPAddress As String IPAddress = "10.0.
VB运行EXE程序,并等待其运行结束 参考:https://blog.csdn.net/useway/article/details/5494084 Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long Pr
今天碰到一个问题,登陆的时候,如果不需要验证手机号为空,则不去验证手机号 因为登陆的时候所有的验证信息都存放在一个数组里 Dim CheckUserInfo() As String ={UserBirthday, SecEmail, UserMob, UserSex, RealNameFirst, RealName, CheckCardID, CheckCardType, Contactemail
在VB6.0中,数据访问接口有三种: 1、ActiveX数据对象(ADO) 2、远程数据对象(RDO) 3、数据访问对象(DAO) 1.使用ADO(ActiveX Data Objec,ActiveX数据对象)连接SQL Server 1)使用ADO控件连接 使用ADO控件的ConnectionString属性就可以连接SQL Server,该属性包含一个由分号分隔的argument=value语
注:大家如果没有VB6.0的安装文件,可自行百度一下下载,一般文件大小在200M左右的均为完整版的软件,可以使用。   特别提示:安装此软件的时候最好退出360杀毒软件(包括360安全卫士,电脑管家等,如果电脑上有这些软件的话),因为现如今的360杀毒软件直接会对VB6.0软件误报,这样的话就可能会在安装过程中被误报阻止而导致安装失败,或者是安装后缺乏很多必须的组件(其它的杀毒软件或安全卫士之类的
Private Sub Form_Load() Call conndb End Sub Private Function conndb() Dim cn As New ADODB.Connection Dim rs As New ADODB.Recordset Dim strCn, sql As String Dim db_host As String Dim db_user As String
  PPSM06S70:  Add  moddate  EDITSPRINTJOB:  MAX(TO_CHAR(ETRN.MODDATE, ‘yyyy/mm/dd/HH24:MI AM‘)) ACTUAL_SHIPDATE   4.Test Scenario (1) :Query SQL Test DN:8016578337 SELECT CTRN.TKCTID TRUCK_ID,        
  沒有出現CrystalReportViewer時,須安裝CRforVS_13_0. 新增1個數據集,新增1個數據表,添加二列,列名要和資料庫名一樣. 修改目標Framework 修改app.config, <startup >改成<startup useLegacyV2RuntimeActivationPolicy ="true">  CrystalReport1.rpt增加數據庫專家 在表單
Imports System.Threading Imports System Public Class Form1 Dim th1, th2 As Thread Public Sub Method1() Dim i As Integer For i = 1 To 100 If Me.Label1.BackColor =
Friend Const PROCESS_ALL_ACCESS = &H1F0FFF = 2035711 Friend Const PROCESS_VM_READ = &H10 Friend Const PROCESS_VM_WRITE = &H20 Friend Const PAGE_READONLY = &H2 Friend Const PAGE_READWRITE = &H4 Friend
以下代码随手写的 并没有大量测试 效率也有待提升 如果需要C#的请自行转换 Function SplitBytes(Data As Byte(), Delimiter As Byte()) As List(Of Byte()) Dim i = 0 Dim List As New List(Of Byte()) Dim bytes As New
Imports System.Data.SqlClient Public Class Form1 REM Public conn1 As SqlConnection = New SqlConnection("server=.; Integrated Security=False;Initial Catalog= mydatabase1; User ID= sa;password")