VBA手动创建BMP

4
我正在开发一个用于生成QR码的VBA类,但在将QR数据位写入实际的BMP文件时遇到了难题。为了掌握BMP结构和代码,我一直试图使用下面的代码创建一个全白的21 x 21像素位图。这几乎可以正常工作,除了每行最左边的列是黄色而不是白色。有什么想法吗?我猜测我的头文件定义可能有问题,但我不确定。我对BMP毫无经验。我的代码基于http://answers.microsoft.com/en-us/office/forum/office_2007-customize/how-can-i-create-a-bitmap-image-with-vba/4976480a-d20b-4b2a-8ecc-436428d9586b找到的内容。
Private Type typHEADER
    strType As String * 2  ' Signature of file = "BM"
    lngSize As Long        ' File size
    intRes1 As Integer     ' reserved = 0
    intRes2 As Integer     ' reserved = 0
    lngOffset As Long      ' offset to the bitmap data (bits)
End Type
Private Type typINFOHEADER
    lngSize As Long        ' Size
    lngWidth As Long       ' Height
    lngHeight As Long      ' Length
    intPlanes As Integer   ' Number of image planes in file
    intBits As Integer     ' Number of bits per pixel
    lngCompression As Long ' Compression type (set to zero)
    lngImageSize As Long   ' Image size (bytes, set to zero)
    lngxResolution As Long ' Device resolution (set to zero)
    lngyResolution As Long ' Device resolution (set to zero)
    lngColorCount As Long  ' Number of colors (set to zero for 24 bits)
    lngImportantColors As Long ' "Important" colors (set to zero)
End Type
Private Type typPIXEL
    bytB As Byte    ' Blue
    bytG As Byte    ' Green
    bytR As Byte    ' Red
End Type
Private Type typBITMAPFILE
    bmfh As typHEADER
    bmfi As typINFOHEADER
    bmbits() As Byte
End Type

'==================================================

Public Sub makeBMP(intQR() As Integer)
    Dim bmpFile As typBITMAPFILE
    Dim lngRowSize As Long
    Dim lngPixelArraySize As Long
    Dim lngFileSize As Long
    Dim j, k, l, x As Integer

    Dim bytRed, bytGreen, bytBlue As Integer
    Dim lngRGBColoer() As Long

    Dim strBMP As String

    With bmpFile
        With .bmfh
            .strType = "BM"
            .lngSize = 0
            .intRes1 = 0
            .intRes2 = 0
            .lngOffset = 54
        End With
        With .bmfi
            .lngSize = 40
            .lngWidth = 21
            .lngHeight = 21
            .intPlanes = 1
            .intBits = 24
            .lngCompression = 0
            .lngImageSize = 0
            .lngxResolution = 0
            .lngyResolution = 0
            .lngColorCount = 0
            .lngImportantColors = 0
        End With
        lngRowSize = Round(.bmfi.intBits * .bmfi.lngWidth / 32) * 4
        lngPixelArraySize = lngRowSize * .bmfi.lngHeight

        ReDim .bmbits(lngPixelArraySize)
        ReDim lngRGBColor(21, 21)
        For j = 1 To 21  ' For each row, starting at the bottom and working up...
            'each column starting at the left
            For x = 1 To 21
                k = k + 1
                .bmbits(k) = 255
                k = k + 1
                .bmbits(k) = 255
                k = k + 1
                .bmbits(k) = 255
            Next x

            If (21 * .bmfi.intBits / 8 < lngRowSize) Then   ' Add padding if required
                For l = 21 * .bmfi.intBits / 8 + 1 To lngRowSize
                    k = k + 1
                    .bmbits(k) = 0
                Next l
            End If
        Next j
        .bmfh.lngSize = 14 + 40 + lngPixelArraySize
     End With ' Defining bmpFile

    strBMP = "C:\Desktop\Sample.BMP"

    Open strBMP For Binary Access Write As 1 Len = 1
        Put 1, 1, bmpFile.bmfh
        Put 1, , bmpFile.bmfi
        Put 1, , bmpFile.bmbits
    Close
End Sub

1
你在24 x 24的bmp图像上看到了相同的效果吗?我怀疑是每行字节对齐的问题,而24x24的图像不应该受到这个问题的影响。 - Seth Battin
谢谢,我觉得那就是问题所在。如果在进入循环之前将k设置为-1,则所有内容都会正确对齐。感谢您的帮助。 - DasPete
4个回答

3

2
这段BMP导出代码中存在一个小错误。
有一行代码是这样的:
lngRowSize = Round(.bmfi.intBits * .bmfi.lngWidth / 32) * 4

应该实际上说

'old line:    lngRowSize = Round(.bmfi.intBits * .bmfi.lngWidth / 32) * 4
 lngRowSize = WorksheetFunction.Ceiling_Precise(.bmfi.intBits * .bmfi.lngWidth / 32) * 4

之前,round函数会导致某些图像宽度不能正确导出,代码会抛出一个错误。之前被拒绝的宽度有:(3、6、7、11、14、15、19、22、23、27、30...)

我假设你不再需要这段代码了,但我从这里复制了它,我想其他人也会这样做。


1
我运行了您的代码以验证黄线。仔细查看后,我认为问题可以通过设置bmpfile.bmpbits字节数组的边界来解决。当您定义数组时,您将下限留空,因此数组默认将从0开始。如果您像这样重新定义数组大小
    ReDim .bmbits(1 To lngPixelArraySize)

你会得到一个实心的白色样本.bmp。我运行它进行验证,对我有效。
祝好运。我能看出让k从-1开始工作是可行的。唯一剩下的问题是你的数组大小将多一个字节。

0
为了使“ceiling”函数正确(VBA / excel 2007),不需要“precise”语句。宏与以下内容正常工作:
lngRowSize = WorksheetFunction.Ceiling(.bmfi.intBits * .bmfi.lngWidth / 32, 0.5) * 4       

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接