将 32x32 StdPicture 图标转换为 PNG

Converting 32x32 StdPicture icons to PNG

我正在尝试将 StdPicture 转换为 PNG,然后再将其编码为 Base64 以通过 XML 发送。我已经获取了 Base64 编码部分(请参阅函数的近端 EncodeImageToBase64())但是我无法将 StdPicture 对象转换为 PNG 字节数组。

这是我的函数:

Private Function EncodeImageToBase64(ByRef Image As StdPicture) As String
  Dim xmlDoc As DOMDocument60
  Dim xmlNode As MSXML2.IXMLDOMElement
  Dim bColor() As Byte
  Dim bMask() As Byte
  Dim bImage() As Byte
  Dim lCrcTable() As Long
  Dim lWidth As Long
  Dim lHeight As Long
  EncodeImageToBase64 = vbNullString

  If Image Is Nothing Then
    Exit Function
  End If

  Call MakeCRC32Table(lCrcTable)
  Call IconPicToArrays(Image, bColor, bMask, lWidth, lHeight)
  If Not CreatePngByteArray(bImage, lWidth, lHeight, bColor, bMask, lCrcTable) Then
    Debug.Assert False
    Exit Function
  End If
  'Call GetPictureBits(bImage, Image)

  Set xmlDoc = New DOMDocument60
  Set xmlNode = xmlDoc.createElement("b64")
  xmlNode.DataType = "bin.base64"
  xmlNode.nodeTypedValue = bImage
  EncodeImageToBase64 = xmlNode.Text

  Set xmlNode = Nothing
  Set xmlDoc = Nothing
End Function

问题是写 CreatePngByteArray 的人只打算用这个函数来转换 PNG 的 16x16。因此,我的 32x32 图标无法通过函数中的断言:

'Create PNG (RFC-2083) image based on a 16x16 icon's color and mask bitmaps
Public Function CreatePngByteArray(ByRef bTarget() As Byte, ByVal Width As Long, ByVal _
      Height As Long, bColor() As Byte, bMask() As Byte, lCrcTable() As Long) As Boolean
  Dim bIndex() As Byte
  Dim bPalette() As Byte
  Dim lPos As Long
  Dim lCRC As Long
  Dim X As Long
  Dim Y As Long
  Dim z As Long
  Dim lPalSize As Long

  If Width > 16 Or Height > 16 Then Exit Function

  lPalSize = RGBtoPalette(bColor, bMask, bIndex, bPalette, Width, Height)

  ReDim bTarget(0 To 364 + lPalSize) As Byte '8+25+(12+lPalSize)+13+295+12-1

  'PNG signature 'long val = -1991225785  'hex value = 89504E47
  bTarget(0) = 137
  bTarget(1) = 80
  bTarget(2) = 78
  bTarget(3) = 71
  bTarget(4) = 13
  bTarget(5) = 10
  bTarget(6) = 26
  bTarget(7) = 10
  lPos = 8

  'IHDR
  Call FlipLongToArray(13, bTarget(), lPos)
  Call FlipLongToArray(pctIHDR, bTarget(), lPos + 4) 'add chunk flag
  Call FlipLongToArray(Width, bTarget(), lPos + 8)
  Call FlipLongToArray(Height, bTarget(), lPos + 12)
  bTarget(lPos + 16) = 8  'bit depth
  bTarget(lPos + 17) = 3  'color type
  bTarget(lPos + 18) = 0  'compression - none
  bTarget(lPos + 19) = 0  'filter
  bTarget(lPos + 20) = 0  'interlace
  lCRC = CRC32(bTarget(), lPos + 4, lPos + 20, lCrcTable())
  Call FlipLongToArray(lCRC, bTarget(), lPos + 21)
  lPos = lPos + 25

  'PLTE
  Call FlipLongToArray(lPalSize, bTarget(), lPos)
  Call FlipLongToArray(pctPLTE, bTarget(), lPos + 4)   'add chunk flag
  Call CopyMemory(bTarget(lPos + 8), bPalette(0), lPalSize)
  lCRC = CRC32(bTarget(), lPos + 4, lPos + lPalSize + 7, lCrcTable())
  Call FlipLongToArray(lCRC, bTarget(), lPos + lPalSize + 8)
  lPos = lPos + lPalSize + 12

  'tRNS
  Call FlipLongToArray(1, bTarget(), lPos)
  Call FlipLongToArray(pcttRNS, bTarget(), lPos + 4)  'add chunk flag
  bTarget(lPos + 8) = 0 'alpha
  lCRC = CRC32(bTarget(), lPos + 4, lPos + 8, lCrcTable())
  Call FlipLongToArray(lCRC, bTarget(), lPos + 9)
  lPos = lPos + 13

  'IDAT
  Call FlipLongToArray(283, bTarget(), lPos)
  Call FlipLongToArray(pctIDAT, bTarget(), lPos + 4)  'add chunk flag
  bTarget(lPos + 8) = 24 '8=deflate + 16=512b LZ77 window (RFC-1950)
  bTarget(lPos + 9) = 25 'so that (CompMethod*256 + AddlFlags) Mod 31=0 (RFC-1950)
  bTarget(lPos + 10) = 1 '(RFC-1951)
  bTarget(lPos + 11) = 16 '272: LEN 0 (RFC-1951)
  bTarget(lPos + 12) = 1 '272: LEN 1
  bTarget(lPos + 13) = &HEF '~272: NLEN 0 (RFC-1951)
  bTarget(lPos + 14) = &HFE '~272: NLEN 1
  For X = 0 To 15
    bTarget(lPos + 15 + z) = 0
    Call CopyMemory(bTarget(lPos + 16 + z), bIndex(Y), 16)
    Y = Y + 16
    z = z + 17
  Next X
  lCRC = Adler32(bTarget(), lPos + 15, lPos + 286)
  Call FlipLongToArray(lCRC, bTarget(), lPos + 287) 'Adler32 is supposed to be safe to leave empty, but isn't
  lCRC = CRC32(bTarget(), lPos + 4, lPos + 290, lCrcTable())
  Call FlipLongToArray(lCRC, bTarget(), lPos + 291)
  lPos = lPos + 295

  'IEND
  Call FlipLongToArray(0, bTarget(), lPos)
  Call FlipLongToArray(pctIEND, bTarget(), lPos + 4)   'add chunk flag
  lCRC = CRC32(bTarget(), lPos + 4, lPos + 7, lCrcTable())
  Call FlipLongToArray(lCRC, bTarget(), lPos + 8)

  CreatePngByteArray = True
End Function

我不厌其烦地查看了这段代码,但我并没有做太多的低级编程(处理字节和诸如此类的东西),而且还差得很远。

有没有什么方法可以改变它的用途,或者有什么其他方法可以将任何大小的 PNG 图像转换为字节数组?如果我要使用库 /.dll,我更喜欢它们是标准的 Microsoft 库。

谢谢!

你可以像这样使用 属性 包

Option Explicit

Private Sub Form_Load()
    Dim encoded     As String

    encoded = EncodeImageToBase64(LoadPicture("d:\temp\aaa.gif"))
    Caption = "Encoded Size: " & Len(encoded)
    Set Picture = DecodeImageFromBase64(encoded)
End Sub

Private Function EncodeImageToBase64(ByRef Image As StdPicture) As String
    Dim oBag        As PropertyBag

    Set oBag = New PropertyBag
    oBag.WriteProperty "i", Image, Nothing
    With VBA.CreateObject("MSXML2.DOMDocument").createElement("dummy")
        .DataType = "bin.base64"
        .NodeTypedValue = oBag.Contents
        EncodeImageToBase64 = .Text
    End With
End Function

Private Function DecodeImageFromBase64(ByRef Base64 As String) As StdPicture
    Dim oBag        As PropertyBag
    Dim QH          As Long

    On Error GoTo QH
    Set oBag = New PropertyBag
    With VBA.CreateObject("MSXML2.DOMDocument").createElement("dummy")
        .DataType = "bin.base64"
        .Text = Base64
        oBag.Contents = .NodeTypedValue
    End With
    Set DecodeImageFromBase64 = oBag.ReadProperty("i", Nothing)
QH:
End Function