解读位图文件

 

解读位图文件

告诉您:24位、8位、4位等格式位图的区别及转换

 

位图文件是最基础的图形文件,是以像素为单位进行图像信息记录的,有24位、8位、4位和1位等几种不同的记录方式。

 

文件的组成一般包含以下几个部分:

 

 位图文件头        位图信息头       [系统调色盘]       图片信息

 bmpfileheader      bmpinfoheader      rgbquad            rgbdata

   (14bytes)          (40bytes) 

注:详细说明见编程举例部分

 

 

 

 

 

 

 


位和字节:

位图文件保存在磁盘中,读写时是以二进制的形式进行操作的,而二制的存取是以字节byte为单位,1  byte = 8 bit,即一个字节存储了八位二进制信息,熟悉二进制的朋友就知道,8位的二进制可以表示0~255的数字。

 

不同格式的位图文件的区别:

24位位图文件    这种文件包含位图文件头、位图信息头和图片信息三个部分,而不包含系统调色盘。图片信息的记录方式为每个像素占3个字节大小(24位),分别用30~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。添加图片框picture1scalemode=3-pixelautoredraw=true;borderstyle=0-noneautosize=truebackcolor=白色。添加两个按钮command1caption=”Let’s go” command2caption=”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  每个像素占的位数,24841

        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色,其余不赋值,为000

  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

 

童跃   福建省华安县际头小学

tongyue2007@126.com

2007 5 1

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tongyue

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值