解读位图文件
告诉您:24位、8位、4位等格式位图的区别及转换
位图文件是最基础的图形文件,是以像素为单位进行图像信息记录的,有24位、8位、4位和1位等几种不同的记录方式。
文件的组成一般包含以下几个部分:
位图文件头 位图信息头 [系统调色盘] 图片信息 bmpfileheader bmpinfoheader rgbquad rgbdata (14bytes) (40bytes) 注:详细说明见编程举例部分 |
位和字节:
位图文件保存在磁盘中,读写时是以二进制的形式进行操作的,而二制的存取是以字节byte为单位,1 byte = 8 bit,即一个字节存储了八位二进制信息,熟悉二进制的朋友就知道,8位的二进制可以表示0~255的数字。
不同格式的位图文件的区别:
24位位图文件 这种文件包含位图文件头、位图信息头和图片信息三个部分,而不包含系统调色盘。图片信息的记录方式为每个像素占3个字节大小(24位),分别用3个0~255的数字来表示该点的颜色所包含的红、绿、蓝的值。用这种方式来记录图片,可以表达的颜色种类就非常的多(255*255*255种),接近于无数种,被称为真色彩,表现出来的图像最逼真,最好看。然而,这种24位位图文件的体积也最大。
8位、4位、1位位图 为了使位图文件的体积变小,Windows采用牺牲图片质量的方式来进行压缩,即采用系统调色盘,在描叙图像像素信息之前,系统先建立若干种颜色,然后用这些有限的颜色去代替图像中无数的颜色。8位位图每个像素占1个字节(8位),可以表示的颜色种类有256种,系统调色盘中的颜色就有256个,也称256色位图文件;4位位图每个像素占4位,1个字节就可以表示2个像素的信息,可以表示的颜色种类有16种,系统调色盘颜色中就有16个;1位位图每个像素占1位,1个字节就可以表示8个像素的信息,可以表示的颜色种类有2种,系统调色盘颜色中就有2个,纯白和纯黑。
图像信息的扫描及文件的大小计算:
图像信息的扫描是从图像的左下角开始,逐行向上进行记录的。位图文件在每扫描一行完成的时候,为了对齐会多加0~3个值为0的字节的空间(图像的宽除以4的余数,Picture.width mod 4),这样,我们就可以计算出位图的各种格式文件的大小了:
(以100*100像素的图片为例来计算文件大小)
种类 | 文件头 | 信息头 | 调色盘 | 图片信息 | 文件大小 |
24bit | 14 | 40 | 0 | 100*100*3 | 30054 |
8bit | 14 | 40 | 4*256 | 100*100 | 11078 |
4bit | 14 | 40 | 4*16 | 100*100/2 | 5118 |
1bit | 14 | 40 | 4*2 | 100*100/8 | 1312 |
编程举例:(位图文件读取)
我们可以用二进制的方式读取位图文件,来获得图像的所有数据,然后对数据进行修改,来完成图像特效处理,并保存图片或修改原位图文件。如果修改系统调色盘的信息,将影响整幅图像的色调;如果修改位图像素的数据,则改变图像局部。下面用一个程序来说明位图文件的读取及通过修改图像像素的数据来完成图像复制的特效。
|
|
用VB6新建一个工程,命名为Sxing.vbp。添加一个窗体Sxing.frm ,caption=”Sxing”;scalemode=3-pixel。添加图片框picture1,scalemode=3-pixel;autoredraw=true;borderstyle=0-none;autosize=true;backcolor=白色。添加两个按钮command1的caption=”Let’s go”, command2的caption=”save to Sxing.bmp”; enabled=false,添加一个标签Label1。粘贴代码:
Option Explicit
Private Type BITMAPFILEHEADER '14bytes位图文件头
bftype As Integer ’为19778
bfsize As Long ’文件的总总字节数
bfreserved1 As Integer ’为0
bfreserved2 As Integer ’为0
bfoffbits As Long ’图片信息到文件开始的偏移量,即文件前三项的总字节数
End Type
Private Type BITMAPINFOHEADER '40 bytes位图信息头
biSize As Long ’信息头的长度,为40
biWidth As Long ’图像宽
biHeight As Long ’图像高
biPlanes As Integer ’为1
biBitCount As Integer ’每个像素占的位数,24或8或4或1
biCompression As Long ’为0
biSizeImage As Long ’图像信息总字节数
biXPelsPerMeter As Long ’为0
biYPelsPerMeter As Long ’为0
biClrUsed As Long ’为0
biClrImportant As Long ’为0
End Type
Private Type RGBDATA '24bitcolor位图文件中的RGB是倒置的
b As Byte
g As Byte
r As Byte
End Type
Private Type RGBQUAD '4bytes
rgbBlue As Byte
rgbGreen As Byte
rgbRed As Byte
rgbReserved As Byte
End Type
Private Type BITMAPINFOHEADER256
bmpinfo As BITMAPINFOHEADER
rgbq(255) As RGBQUAD
End Type
Dim picl() As Long
Dim w, h As Integer
Private Sub Command1_Click()
Command1.Enabled = False
Dim bfh As BITMAPFILEHEADER 'BMPfileheader
Dim bih As BITMAPINFOHEADER
Dim poin As Long
Dim size As Long
Dim i, j, ln As Integer
Dim rgbd() As RGBDATA
Dim id As Integer
Dim fname As String
fname = App.Path & "/laonainai.bmp"
Open fname For Binary As #1
Get #1, , bfh
Get #1, , bih
size = bih.biWidth * bih.biHeight
ReDim picl(bih.biHeight - 1, bih.biWidth - 1)
ReDim rgbd(bih.biWidth - 1)
poin = bfh.bfoffbits + 1
ln = bih.biWidth Mod 4 ’计算文件为对齐而添加的字节数
For i = 0 To bih.biHeight - 1
Get #1, poin, rgbd ’一次读取一行的图像信息
For j = 0 To bih.biWidth - 1
picl(i, j) = RGB(rgbd(j).r, rgbd(j).g, rgbd(j).b)
Next
poin = poin + bih.biWidth * 3 + ln ’重新定位文件读取位置
Next
Close #1
Picture1.Cls ’清除原图像
For i = 1 To 20 ’在图片框中绘制20个图形
prin i
DoEvents
Label1.Caption = i '显示进度
Next
Command2.Enabled = True
End Sub
Private Sub prin(ByVal id As Integer)
Dim x, y, ww, hh As Integer
Dim bili As Single
bili = (20 + id * 4) / 100
ww = w * bili
hh = h * bili
x = w / 2 - Sin(id * 18 * 3.14 / 180) * w / 2
x = x - ww / 2
y = CInt(h / 20 * id)
Dim i, j As Integer
Dim col As Long
Dim xx, yy As Integer
For i = 0 To hh - 1
For j = 0 To ww - 1
yy = Int(i / bili)
xx = Int(j / bili)
If yy > h - 1 Then yy = h - 1
If xx > w - 1 Then xx = ww - 1
col = picl(yy, xx)
If col < 16777215 Then Picture1.PSet (x + j, y - i - 1), col ’白色部分不画
Next
Next
End Sub
Private Sub Command2_Click() ’保存图片框中重新绘制的图形
Command2.Enabled = False
SavePicture Picture1.Image, App.Path & "/Sxing.bmp"
Label1.Caption = "已成功保存图片到" & App.Path & "/Sxing.bmp"
Command1.Enabled = True
End Sub
Private Sub Form_Load()
picture1.Picture =loadpicture(app.Path & "/laonainai.bmp")
’导入的位图是一幅24位位图
w = Picture1.Width
h = Picture1.Height
End Sub
编程原理:
窗体导入时,导入同目录下的24位位图“laonaiai.bmp”,command1按下时,以二进制方式读取位图的所有信息,并把图片信息组rgbd()利用RGB函数转化成long类型的数值,存入公共命名的rgbl()数组中,然后重复利用自定义的过程prin()在图片框中绘制出20个大小、位置不同的图像,注意在绘制的过程中,忽略了白色背景的部分,在循环绘制的过程中,用了DoEvents语句,这样就可以看到图像一幅一幅复制的过程了,而不必等到20幅全部复制完成才能看到。Command2按下时,就可以把结果保存在同目录下的“Sxing.bmp”中。
编程举例2:(位图文件格式转换)
在上面的例子中,用SavePicture Picture1.Image, App.Path & "/Sxing.bmp" 方法把图片框中的图像保存成文件,保存的是24位真色彩的位图文件。我们能把它转化成256色(或其他格式)的位图文件吗?这也是很简单的事:一,要设置好位图文件头和位图图片信息头的值;二,要获得图像的256色像素流,再依次写入文件即可。
怎样获得图像的256色(或其他格式)的像素流呢?最经典的办法是利用API 函数,我在这里就演示用API 函数的方法来获取图像像素流。(如果用运算的方法可能会更简单些,我将在下一篇文章中介绍)
在上面的程序中添加一个按钮command3 , caption=”as save 256colors”。在窗体的声明部分粘贴所需的API 函数,并编写command3 的转换程序代码。
Private Declare Function CreateDCAsNull Lib "gdi32" Alias "CreateDCA" (ByVal lpDriverName As String, lpDeviceName As Any, lpOutput As Any, lpInitData As Any) As Long
Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function GetObjectAPI Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare Function GetDIBits Lib "gdi32" (ByVal aHDC As Long, ByVal hBitmap As Long, ByVal nStartScan As Long, ByVal nNumScans As Long, lpBits As Any, lpbi As Any, ByVal wUsage As Long) As Long
Private Declare Function CreateDIBSection Lib "gdi32" (ByVal hdc As Long, pBitmapInfo As Any, ByVal un As Long, lplpVoid As Long, ByVal handle As Long, ByVal dw As Long) As Long
Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
Private Sub Command3_Click()
Dim bfh As BITMAPFILEHEADER '位图文件头
Dim bih As BITMAPINFOHEADER256 ’位图图片信息头
Dim bSize As Long ’图像256色像素流的长度
bSize = (w + w Mod 4) * h
Dim hDCScn, hDC256, hDib256, OldObj256 As Long
hDCScn = CreateDCAsNull("DISPLAY", ByVal 0&, ByVal 0&, ByVal 0&)
hDC256 = CreateCompatibleDC(hDCScn)
DeleteDC hDCScn
’设置位图图片信息头的值
With bih.bmpinfo
.biSize = Len(bih.bmpinfo)
.biWidth = w
.biHeight = h
.biPlanes = 1
.biBitCount = 8
.biCompression = 0&
.biSizeImage = bSize
End With
’创建调色盘中的颜色(可以自由创建,这里创建了216色,其余不赋值,为0,0,0)
Dim lIndex As Integer
Dim r, g, b As Integer
Dim buf() As Byte
For b = 0 To 255 Step 51
For g = 0 To 255 Step 51
For r = 0 To 255 Step 51
With bih.rgbq(lIndex)
.rgbRed = r: .rgbGreen = g: .rgbBlue = b
End With
lIndex = lIndex + 1
Next r
Next g
Next b
ReDim buf(bSize - 1) As Byte ’申请像素流内存空间
hDib256 = CreateDIBSection(hDC256, bih, 0, 0, 0, 0) ’在内存中创建一幅256色图像
OldObj256 = SelectObject(hDC256, hDib256)
Call BitBlt(hDC256, 0, 0, w, h, Picture1.hdc, 0, 0, vbSrcCopy) ’复制图像到内存
Call GetDIBits(hDC256, hDib256, 0, h, buf(0), bih, 0) ’获得像素流
SelectObject hDC256, OldObj256
DeleteObject hDib256
DeleteDC hDC256
’设置位图文件头的值
With bfh
.bfoffbits = 1078 '14+40+256*4
.bfsize = 1078 + bSize
.bftype = 19778
End With
’写入文件
Open App.Path & "/Sxing2.bmp" For Binary As #1
Put #1, , bfh
Put #1, , bih
Put #1, , buf
Close #1
Label1.Caption = "已成功保存图片到" & App.Path & "/Sxing2.bmp"
End Sub
童跃 福建省华安县际头小学
2007 年 5 月 1 日