cPNGparser.cls
上传用户:jnjasmy
上传日期:2015-01-04
资源大小:637k
文件大小:81k
源码类别:

GDI/图象编程

开发平台:

Visual Basic

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4.   Persistable = 0  'NotPersistable
  5.   DataBindingBehavior = 0  'vbNone
  6.   DataSourceBehavior  = 0  'vbNone
  7.   MTSTransactionMode  = 0  'NotAnMTSObject
  8. END
  9. Attribute VB_Name = "cPNGparser"
  10. Attribute VB_GlobalNameSpace = False
  11. Attribute VB_Creatable = True
  12. Attribute VB_PredeclaredId = False
  13. Attribute VB_Exposed = False
  14. Option Explicit
  15. ' PNG Parser & PNG to 32bpp converter
  16. ' The PNG will be parsed using the following resources if they are available
  17. ' and in the following order.
  18. ' 1) If GDI+ is available, the entire PNG will be processed via GDI+
  19. ' 2) If zLIB.DLL or zLIB1.DLL is available, the PNG will be decompressed via zLIB
  20. ' 3) If none of the above, the PNG will be decompressed with pure VB
  21. ' No APIs are declared public. This is to prevent possibly, differently
  22. ' declared APIs, or different versions of the same API, from conflciting
  23. ' with any APIs you declared in your project. Same rule for UDTs.
  24. ' Note: I did take some liberties in several API declarations throughout
  25. Private Declare Function ReadFile Lib "kernel32.dll" (ByVal hFile As Long, ByRef lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, ByRef lpNumberOfBytesRead As Long, ByRef lpOverlapped As Any) As Long
  26. Private Declare Function SetFilePointer Lib "kernel32.dll" (ByVal hFile As Long, ByVal lDistanceToMove As Long, ByRef lpDistanceToMoveHigh As Long, ByVal dwMoveMethod As Long) As Long
  27. Private Declare Function GetFileSize Lib "kernel32.dll" (ByVal hFile As Long, ByRef lpFileSizeHigh As Long) As Long
  28. Private Const FILE_CURRENT As Long = 1
  29. ' Used to create a return DIB section
  30. Private Declare Sub FillMemory Lib "kernel32.dll" Alias "RtlFillMemory" (ByRef Destination As Any, ByVal Length As Long, ByVal Fill As Byte)
  31. Private Declare Function CreateCompatibleDC Lib "gdi32.dll" (ByVal hDC As Long) As Long
  32. Private Declare Function DeleteDC Lib "gdi32.dll" (ByVal hDC As Long) As Long
  33. Private Declare Function SelectObject Lib "gdi32.dll" (ByVal hDC As Long, ByVal hObject As Long) As Long
  34. Private Declare Function DeleteObject Lib "gdi32.dll" (ByVal hObject As Long) As Long
  35. Private Declare Function GetDC Lib "user32.dll" (ByVal hwnd As Long) As Long
  36. Private Declare Function ReleaseDC Lib "user32.dll" (ByVal hwnd As Long, ByVal hDC As Long) As Long
  37. Private Declare Function CreateDIBSection Lib "gdi32.dll" (ByVal hDC As Long, ByRef pBitmapInfo As Any, ByVal un As Long, ByRef lplpVoid As Long, ByVal Handle As Long, ByVal dw As Long) As Long
  38. Private Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (Ptr() As Any) As Long
  39. Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
  40. Private Type SafeArrayBound
  41.     cElements As Long
  42.     lLbound As Long
  43. End Type
  44. Private Type SafeArray
  45.     cDims As Integer
  46.     fFeatures As Integer
  47.     cbElements As Long
  48.     cLocks As Long
  49.     pvData As Long
  50.     rgSABound(0 To 1) As SafeArrayBound
  51. End Type
  52. Private Type BITMAPINFOHEADER
  53.     biSize As Long
  54.     biWidth As Long
  55.     biHeight As Long
  56.     biPlanes As Integer
  57.     biBitCount As Integer
  58.     biCompression As Long
  59.     biSizeImage As Long
  60.     biXPelsPerMeter As Long
  61.     biYPelsPerMeter As Long
  62.     biClrUsed As Long
  63.     biClrImportant As Long
  64. End Type
  65. Private Type BITMAPINFO
  66.     bmiHeader As BITMAPINFOHEADER
  67.     bmiColors As Long
  68. End Type
  69. ' Following are used only if PNG file is being manually decompressed with pure VB
  70. Private Type CodesType
  71.     Length() As Long
  72.     code() As Long
  73. End Type
  74. Private OutPos As Long
  75. Private Inpos As Long
  76. Private ByteBuff As Long
  77. Private BitNum As Long
  78. Private BitMask() As Long
  79. Private Pow2() As Long
  80. Private LCodes As CodesType
  81. Private DCodes As CodesType
  82. Private LitLen As CodesType
  83. Private Dist As CodesType
  84. Private TempLit As CodesType
  85. Private TempDist As CodesType
  86. Private LenOrder() As Long
  87. ' Following are used if PNG will be decompressed by zLIB
  88. ' -- older version of zLIB (version 1.1.? or earlier)
  89. Private Declare Function Zuncompress Lib "zlib.dll" Alias "uncompress" (ByRef Dest As Any, ByRef destLen As Long, ByRef Source As Any, ByVal sourceLen As Long) As Long
  90. Private Declare Function Zcrc32 Lib "zlib.dll" Alias "crc32" (ByVal crc As Long, ByRef buf As Any, ByVal Length As Long) As Long
  91. ' -- latest version of zLIB (version 1.2.3)
  92. Private Declare Function Zuncompress1 Lib "zlib1.dll" Alias "uncompress" (ByRef Dest As Any, ByRef destLen As Long, ByRef Source As Any, ByVal sourceLen As Long) As Long
  93. Private Declare Function Zcrc321 Lib "zlib1.dll" Alias "crc32" (ByVal crc As Long, ByRef buf As Any, ByVal Length As Long) As Long
  94. ' following are the actual PNG image properties, exposed via class properties
  95. ' (**)Not all are translated until called from the appropriate class property
  96. Private m_Width As Long                 ' image width
  97. Private m_Height As Long                ' image height
  98. Private m_BitDepth As Byte              ' image bit depth/count: 1,2,4,8,16
  99. Private m_ColorType As Byte             ' image color type: 0,2,3,4,6
  100. Private m_Interlacing As Byte           ' interlaced: 0,1
  101. Private m_Palette() As Byte             ' image palette information
  102. Private m_TransSimple() As Byte         ' image simple transparency information
  103. Private m_TransColor As Long  ' translated simple transparency color (BGR or index value)
  104. ' matrix/lookup tables
  105. Private pow2x8() As Long                ' a look up table for bit shifting (1,2,4 bit pixels)
  106. Private m_MatrixDat() As Byte           ' see eMatrixType below & InitializeMatrix routine
  107. Private Enum eColorTypes ' internal use only
  108.     clrGrayScale = 0
  109.     clrTrueColor = 2
  110.     clrPalette = 3
  111.     clrGrayAlpha = 4
  112.     clrTrueAlpha = 6
  113. End Enum
  114. Private Enum eMatrixType ' internal use only
  115.     MatrixRow = 0           ' row where each pass starts within interlace matrix
  116.     MatrixCol = 1           ' column where each pass starts within interlace matrix
  117.     MatrixRowAdd = 2        ' gaps between each row withiin each pass
  118.     MatrixColAdd = 3        ' gaps between each column within each pass
  119.     MatrixPixelHeight = 4   ' height of each pixel in a scanline (progressive display)
  120.     MatrixPixelWidth = 5    ' width of each pixel in a scanline (progressive display)
  121. End Enum
  122. ' PNG chunk names & their numerical equivalent (those used in this class)
  123. ' Per png specs; using alpha chars is a no-no should system not support those characters
  124. ' http://www.libpng.org/pub/png/spec/1.1/PNG-Chunks.html
  125. Private Const chnk_IHDR As Long = &H52444849 'Image header
  126. Private Const chnk_IDAT As Long = &H54414449 'Image data
  127. Private Const chnk_IEND As Long = &H444E4549 'End of Image
  128. Private Const chnk_PLTE As Long = &H45544C50 'Palette
  129. Private Const chnk_tRNS As Long = &H534E5274 'Simple Transparency
  130. Private Const png_Signature1 As Long = 1196314761
  131. Private Const png_Signature2 As Long = 169478669
  132. '^^ Complete signature is 8 bytes: 137 80 78 71 13 10 26 10
  133. Private inStream() As Byte      ' overlay only for vbDecompress routine; nevery initialized
  134. Private cCfunction As cCDECL    ' allows calling DLL's that export _CDECL functions, not _StdCall functions
  135. Private m_ZLIBver As Long       ' indicates which zLIB version was found on system: 1=older, 2=newer, 0=dll not found
  136. Private pngStream() As Byte ' overlay of bytes when using LoadStream, else individual chunk bytes when using LoadFile
  137. Private cHost As c32bppDIB  ' owner of 32bpp destination image
  138. Public Function LoadStream(Stream() As Byte, dibClass As c32bppDIB, _
  139.             Optional ByVal streamOffset As Long = 0, _
  140.             Optional ByVal streamLength As Long = 0, _
  141.             Optional GlobalToken As Long) As Boolean
  142.     ' PURPOSE: Determine if passed array is a PNG & if it is, then convert it to
  143.     ' a 32bpp owned by dibClass
  144.     
  145.     ' Parameters.
  146.     ' Stream() :: a byte array containing the possible PNG image
  147.     ' dibClass :: an initialized c32bppDIB class
  148.     ' streamOffset :: array position for 1st byte in the stream
  149.     ' streamLength :: size of stream that contains the image
  150.     '   - If zero, then size is UBound(inStream)-streamOffset+1
  151.     ' IMPORTANT: the array offset & length are not checked in this class.
  152.     '   They were checked before this class was called. If this class is to
  153.     '   be pulled out and put in another project, ensure you include the
  154.     '   validation shown in c32bppDIB.LoadPicture_Stream
  155.     
  156.     Dim tSA As SafeArray
  157.     With tSA    ' prepare to overlay. Overlay prevents VB copying bytes into another array for processing
  158.         .cbElements = 1     ' as byte array
  159.         .cDims = 1          ' 1 dimensional
  160.         .pvData = VarPtr(Stream(streamOffset))
  161.         .rgSABound(0).cElements = streamLength
  162.     End With
  163.     CopyMemory ByVal VarPtrArray(pngStream), VarPtr(tSA), 4& ' establish overlay
  164.     Set cHost = dibClass
  165.     LoadStream = LoadPNG(0&, vbNullString, streamLength, GlobalToken)
  166.     CopyMemory ByVal VarPtrArray(pngStream), 0&, 4& ' remove overlay
  167.     Set cHost = Nothing
  168.     
  169. End Function
  170. Public Function LoadFile(ByVal FileHandle As Long, ByVal FileName As String, dibClass As c32bppDIB, Optional GlobalToken As Long) As Boolean
  171.     ' PURPOSE: Determine if passed file is a PNG & if it is, then convert it to
  172.     ' a 32bpp owned by dibClass
  173.     
  174.     ' Parameters.
  175.     ' FileName :: full path and file
  176.     ' dibClass :: an initialized c32bppDIB class
  177.     ' IMPORTANT: the existance and validity of the filename is not checked here.
  178.     '   They were checked before this class was called. If this class is to
  179.     '   be pulled out and put in another project, ensure you include the
  180.     '   validation shown in c32bppDIB.LoadPicture_File
  181.     Set cHost = dibClass
  182.     LoadFile = LoadPNG(FileHandle, FileName, 0&, GlobalToken)
  183.     Set cHost = Nothing
  184. End Function
  185. Private Function LoadPNG(FileHandle As Long, FileName As String, streamLength As Long, Optional GlobalToken As Long) As Boolean
  186.     ' PURPOSE: Determine if passed file is a PNG & if it is, then convert it to
  187.     ' a 32bpp owned by dibClass
  188.     
  189.     ' Parameters.
  190.     ' FileName :: full path and file
  191.     ' dibClass :: an initialized c32bppDIB class
  192.     Dim ptrLoc As Long          ' used to ensure parsing doesn't go past EOF of corrupted file
  193.     Dim ptrArray As Long
  194.     Dim FileNumber As Long      ' the file handle
  195.     Dim gpLong As Long          ' general purpose long value
  196.     Dim readRtn As Long
  197.     Dim lenIDAT As Long         ' running total of the png data size (compressed)
  198.     
  199.     Dim ChunkName As Long       ' name of the chunk
  200.     Dim ChunkLen As Long        ' length of the chunk
  201.     
  202.     Dim RawPNGdata() As Byte    ' uncompressed png data
  203.     Dim IDATdata() As Byte      ' compressed png data
  204.     
  205.     Dim uncmprssSize As Long    ' calculated size of uncompressed PNG data
  206.     Dim lError As Long
  207.     
  208.     Dim bCRCchecks As Boolean   ' whether or not to use CRC checks on chunks
  209.     Dim crc32value As Long      ' if CRC checks applied, the the CRC value
  210.     
  211.     Dim cGDIp As cGDIPlus
  212.     
  213.     ' reset class' only key property
  214.     m_TransColor = -1&
  215.     
  216.     ' attempt to open the file with read access
  217.     If FileName = vbNullString Then
  218.     
  219.         ptrLoc = 7&              ' counter to prevent overflow of array
  220.         ptrArray = 8&            ' current position in passed array
  221.         If IsPNG() = False Then
  222.             Exit Function
  223.         Else
  224.             LoadPNG = True ' & process it using GDI+ if available
  225.             Set cGDIp = New cGDIPlus
  226.             If cGDIp.GDIplusLoadPNG(FileName, pngStream(), cHost, GlobalToken) = True Then
  227.                 m_Width = cHost.Width
  228.                 m_Height = cHost.Height
  229.                 Exit Function
  230.             End If
  231.             Set cGDIp = Nothing
  232.         End If
  233.         
  234.     Else
  235.         On Error Resume Next
  236.         FileNumber = FileHandle
  237.         SetFilePointer FileNumber, 0&, 0&, 0&
  238.         
  239.         ' validate we are looking at a png file
  240.         streamLength = GetFileSize(FileHandle, 0&)
  241.         If streamLength > 56& Then ' minimal (signature=8;header=13,3 rqd chunks=36 min)
  242.             ReDim pngStream(0 To 57)
  243.             ReadFile FileNumber, pngStream(0), 58, readRtn, ByVal 0&
  244.             'Get FileNumber, 1, pngStream()
  245.             If IsPNG() = True Then
  246.                 LoadPNG = True
  247.             Else
  248.                 Exit Function
  249.             End If
  250.         End If
  251.         On Error GoTo 0
  252.         ' process using GDI+ if available
  253.         Set cGDIp = New cGDIPlus
  254.         If cGDIp.GDIplusLoadPNG(FileName, pngStream(), cHost, GlobalToken) = True Then
  255.             m_Width = cHost.Width
  256.             m_Height = cHost.Height
  257.             LoadPNG = True
  258.             Exit Function
  259.         End If
  260.         Set cGDIp = Nothing
  261.         ptrArray = -4&
  262.         ptrLoc = 8&                 ' next position in the file
  263.         SetFilePointer FileNumber, ptrLoc, 0&, 0&
  264.    End If
  265.     
  266.     ReDim IDATdata(0 To streamLength  2&)  ' array to hold compressed data; start with arbritrary length
  267.     bCRCchecks = zValidateZLIBversion()     ' verify we can use zLIB
  268.     
  269.     Do ' read & pre-process the png file
  270.     
  271.         ' Chunks consist of 4 bytes for the length of the chunk
  272.         '                 + n bytes for the chunk
  273.         '                 + 4 bytes for a CRC value
  274.         If FileNumber = 0& Then
  275.             CopyMemory gpLong, pngStream(ptrArray), 4& ' length of the current chunk
  276.         Else
  277.             'Get FileNumber, , gpLong ' number of bytes for the chunk
  278.             ReadFile FileNumber, gpLong, 4&, readRtn, ByVal 0&
  279.         End If
  280.         ChunkLen = iparseReverseLong(gpLong) ' longs are big endian, need little endian for Windows
  281.         
  282.         ' track position of pointer in the file
  283.         ptrLoc = ptrLoc + ChunkLen + 12& ' 12 = 4byte name + 4byte CRC + 4byte chunk count
  284.         If ptrLoc > streamLength Then
  285.             ' corrupted file; abort
  286.             lError = 1&
  287.             Exit Do
  288.         End If
  289.         
  290.         ' read chunk name & chunk data, read CRC separately
  291.         If FileNumber = 0& Then
  292.             If bCRCchecks = True Then CopyMemory crc32value, pngStream(ptrArray + ChunkLen + 8&), 4&
  293.         Else
  294.             ReDim pngStream(0 To ChunkLen + 3&)
  295.             'Get FileNumber, , pngStream
  296.             'Get FileNumber, , gpLong             ' read the CRC value (big endian)
  297.             ReadFile FileNumber, pngStream(0), ChunkLen + 4&, readRtn, ByVal 0&
  298.             ReadFile FileNumber, gpLong, 4&, readRtn, ByVal 0&
  299.             If bCRCchecks = True Then crc32value = gpLong
  300.         End If
  301.         CopyMemory ChunkName, pngStream(ptrArray + 4&), 4& ' extract the chunk name
  302.         
  303.         If ChunkLen < 1& Then
  304.             ' should never be <0; however can be zero at anytime
  305.             If ChunkName = chnk_IEND Then Exit Do
  306.         Else
  307.             
  308.             ' each of the chunk parsing routines will be in a separate function.
  309.             ' This is so that they can easily be modified without affecting any
  310.             ' of the other code. Additionally, it is possible that chunk types will
  311.             ' increase as PNG continues to evolve. Except IDAT, all chunks
  312.             ' are in their own routines
  313.             Select Case ChunkName
  314.             
  315.             Case chnk_IDAT ' UCase chunk names are critical - CRC check
  316.                 ' compressed, filtered image data
  317.                 On Error Resume Next
  318.                 ' error? what error? all precautions taken in zChunk_IHDR function
  319.                 ' However; no predicting "Out of Memory" errors
  320.                 If Not crc32value = 0& Then
  321.                     lError = Not (zCheckCRCvalue(VarPtr(pngStream(ptrArray + 4&)), ChunkLen + 4&, crc32value))
  322.                 End If
  323.                 If lError = 0& Then
  324.                     gpLong = lenIDAT + ChunkLen ' size of array needed
  325.                     If gpLong > UBound(IDATdata) Then ' test length & increment/buffer if needed
  326.                         ReDim Preserve IDATdata(0 To gpLong + streamLength  4&)
  327.                     End If
  328.                     CopyMemory IDATdata(lenIDAT), pngStream(ptrArray + 8&), ChunkLen ' & append the new data
  329.                     lenIDAT = gpLong  ' cache number of compressed bytes so far
  330.                     If Err Then
  331.                         lError = 1&
  332.                         Exit Do
  333.                     End If
  334.                 End If
  335.                 On Error GoTo 0
  336.             
  337.             Case chnk_PLTE ' UCase chunk names are critical - CRC check
  338.                 lError = zChunk_PLTE(ChunkLen, ptrArray + 4&, crc32value)
  339.             
  340.             Case chnk_tRNS ' simple transparency option
  341.                 ' CRC checked 'cause if invalid, we could generate an out of bounds
  342.                 ' error in one of the other routines that reference this array
  343.                 lError = zChunk_tRNS(ChunkLen, ptrArray + 4&, crc32value)
  344.                 
  345.             Case chnk_IHDR ' UCase chunk names are critical - CRC check
  346.                 ' Note: the zChunk_IHDR routine also calculates uncompressed size
  347.                 lError = zChunk_IHDR(ChunkLen, ptrArray + 4&, uncmprssSize, crc32value)
  348.                 
  349.             Case chnk_IEND ' UCase chunk names are critical - CRC check
  350.                 ' should CRC check for corrupted file; but why? we're at end of image
  351.                 Exit Do
  352.                 
  353.             End Select
  354.             If Not lError = 0& Then Exit Do
  355.     
  356.         End If
  357.         If FileNumber = 0& Then ptrArray = ptrArray + ChunkLen + 12& ' move to next position in the array
  358.     Loop
  359. ExitRoutine:
  360.     ' clean up
  361.     If Not FileNumber = 0& Then
  362.         'Close #FileNumber
  363.         Erase pngStream()
  364.     End If
  365.     
  366.     If lenIDAT = 0& Or Not lError = 0& Then  ' invalid png image
  367.         If Err Then Err.Clear
  368.     Else
  369.         ' process the compressed data
  370.         Call PostLoadPNG(IDATdata(), lenIDAT, uncmprssSize)
  371.     End If
  372. End Function
  373. Private Function PostLoadPNG(IDATdata() As Byte, lenIDAT As Long, uncmprssSize As Long) As Boolean
  374.     ' Purpose: Uncompress compressed bytes and send to the un-filtering routines
  375.     Dim RawPNGdata() As Byte
  376.     Dim bUncompressed As Boolean
  377.     Dim lRtn As Long
  378.     On Error Resume Next
  379.     ' we need to uncompress our PNG file
  380.     ReDim RawPNGdata(0 To uncmprssSize - 1&)
  381.     
  382.     ' if zLIB is available, let it uncompress; faster than pure VB
  383.     If Not m_ZLIBver = 0& Then   ' tested/set in LoadPNG routine
  384.         bUncompressed = zInflate(VarPtr(RawPNGdata(0)), VarPtr(uncmprssSize), VarPtr(IDATdata(0)), lenIDAT)
  385.     End If
  386.     If Not bUncompressed Then
  387.         ' either zLib returned an error or it wasn't available, uncompress by hand
  388.         bUncompressed = vbDecompress(RawPNGdata(), IDATdata(), uncmprssSize)
  389.         If Err Then Err.Clear
  390.     End If
  391.     Erase IDATdata()
  392.     
  393.     If Not bUncompressed Then
  394.         ' failed to uncompress & shouldn't happen 'cause if I calculated uncmprssSize
  395.         ' wrong, then other calculations in this routine are wrong too
  396.         ' See: CalcUncompressedWidth
  397.         Exit Function
  398.     End If
  399.     Call InitializePalette  ' if PNG is palettized, create palette
  400.     cHost.InitializeDIB m_Width, m_Height    ' create 32bpp DIB to hold PNG
  401.     
  402.     ' call function to begin converting PNG to Bitmap
  403.     If m_Interlacing = 0& Then
  404.         lRtn = UnfilterNI(RawPNGdata()) ' non-interlaced image
  405.     Else
  406.         lRtn = UnfilterInterlaced(RawPNGdata()) ' interlaced image
  407.     End If
  408.     ' return results
  409.     If lRtn = 0& Then
  410.         cHost.DestroyDIB ' failure decoding the PNG
  411.     Else
  412.         If m_ColorType > clrPalette Then
  413.             cHost.Alpha = True
  414.         ElseIf Not m_TransColor = -1& Then
  415.             cHost.Alpha = True
  416.         Else
  417.             cHost.Alpha = False
  418.         End If
  419.         cHost.ImageType = imgPNG
  420.         PostLoadPNG = True
  421.     End If
  422. End Function
  423. Private Function CalcUncompressedWidth() As Long
  424.     Dim uncompressedWidth As Long, iBitPP As Byte
  425.     Dim Pass As Long, passWidth As Long, passHeight As Long
  426.     On Error GoTo NoLoad
  427.     InitializeMatrix    ' build the interlacing matrix; also used for non-interlaced too
  428.     ' get the actual bits per pixel the png is using
  429.     ' (i.e., 16bitdepth png @ ColorType 6 = 64bits per pixel)
  430.     GetDepthInfo 0, 0, iBitPP, 0
  431.     
  432.     If m_Interlacing = 0& Then ' no interlacing
  433.         ' uncompressed width will be byte aligned width + 1 for filter byte
  434.         ' multiplied by the height
  435.         passWidth = GetBytesPerPixel(m_Width, iBitPP)
  436.         uncompressedWidth = passWidth * m_Height + m_Height
  437.     Else
  438.         ' interlaced will also be byte aligned but per scanline width
  439.         ' Each of the 7 passes can have different widths + 1 filter byte per line
  440.         For Pass = 1& To 7&
  441.             ' calculate number of pixels per scan line
  442.             passWidth = m_Width  m_MatrixDat(Pass, MatrixColAdd) - (m_Width Mod m_MatrixDat(Pass, MatrixColAdd) > m_MatrixDat(Pass, MatrixCol))
  443.             ' determine number of bytes needed for each scanline
  444.             passWidth = GetBytesPerPixel(passWidth, iBitPP)
  445.             ' calculate number of rows for this scan's pass
  446.             passHeight = m_Height  m_MatrixDat(Pass, MatrixRowAdd) - (m_Height Mod m_MatrixDat(Pass, MatrixRowAdd) > m_MatrixDat(Pass, MatrixRow))
  447.             ' now get the total bytes needed for the entire pass,
  448.             ' adding 1 filter byte for each line in the pass:  i.e., + passHeight
  449.             uncompressedWidth = uncompressedWidth + passWidth * passHeight + passHeight
  450.         Next
  451.         
  452.     End If
  453.     
  454.     CalcUncompressedWidth = uncompressedWidth
  455. NoLoad:
  456. End Function
  457. Private Sub InitializeMatrix()
  458.         
  459.     ' a quick look up table for bit shifting operations
  460.     If m_ColorType = clrGrayScale Or m_ColorType = clrPalette Then
  461.         Dim i As Integer
  462.         ReDim pow2x8(0 To 8)
  463.         pow2x8(0) = 1&
  464.         For i = 1& To 8&
  465.             pow2x8(i) = pow2x8(i - 1&) * 2&
  466.         Next
  467.     End If
  468.     ReDim m_MatrixDat(1 To 8, MatrixRow To MatrixColAdd)
  469.     ' for rendering progressive display:
  470.     '   - change 2D elements above: MatrixRow to MatrixPixelWidth
  471.     '   - unrem final array element assignments below
  472.     
  473.     ' initialize interlacing matrix, used in the ConvertPNGtoBMP routine and
  474.     ' also used to calculate the uncompressed size of the compressed PNG data
  475.     
  476.     ' Non-interlaced images are considered Pass#8, where interlaced images always
  477.     ' contain 7 passes (1 thru 7).
  478.     
  479.     ' determines what row in the interlaced image, the current pass begins at
  480.     CopyMemory m_MatrixDat(1, MatrixRow), 262144, 4&
  481.     CopyMemory m_MatrixDat(5, MatrixRow), 65538, 4&  'Array(0, 0, 4, 0, 2, 0, 1, 0)
  482.     ' determines what column in the interlaced image, the current pass begins at
  483.     CopyMemory m_MatrixDat(1, MatrixCol), 33555456, 4&
  484.     CopyMemory m_MatrixDat(5, MatrixCol), 256&, 4& 'Array(0, 4, 0, 2, 0, 1, 0, 0)
  485.     ' determines the row interval of the current pass
  486.     CopyMemory m_MatrixDat(1, MatrixRowAdd), 67635208, 4&
  487.     CopyMemory m_MatrixDat(5, MatrixRowAdd), 16908804, 4& 'Array(8, 8, 8, 4, 4, 2, 2, 1)
  488.     ' determines the column interval of the current pass
  489.     CopyMemory m_MatrixDat(1, MatrixColAdd), 67373064, 4&
  490.     CopyMemory m_MatrixDat(5, MatrixColAdd), 16843266, 4& 'Array(8, 8, 4, 4, 2, 2, 1, 1)
  491.     
  492.     ' 1st 7 elements of next 2 arrays used for pixellated interlaced images
  493.     
  494.     ' determines the width of each pixellated pixel for the current pass (Used only when progressive display rendering)
  495.     'CopyMemory m_MatrixDat(1, MatrixPixelWidth), 33817608, 4&
  496.     'CopyMemory m_MatrixDat(5, MatrixPixelWidth), 16843010, 4& 'Array(8, 4, 4, 2, 2, 1, 1, 1)
  497.     ' determines the height of each pixellated pixel for the current pass
  498.     'CopyMemory m_MatrixDat(1, MatrixPixelHeight), m_MatrixDat(1, MatrixColAdd), &H8 'Array(8, 8, 4, 4, 2, 2, 1, 1)
  499. End Sub
  500. Private Function ConvertPNGtoBMP_NonPalette(rawBytes() As Byte, ByVal scanPass As Byte, _
  501.                     ByVal scanCY As Long, ByVal rBPRow As Long, _
  502.                     Optional ByVal startOffset As Long = 0) As Boolean
  503. ' Routine processes only non-paletted, non-16bit PNG data
  504. ' rawBytes() are the png scanline bytes
  505. ' scanPass() is a valid number btwn 1-8 (8 indicates non-interlaced)
  506. ' scanCY is number of scanlines (btwn 1 and image height)
  507. ' rBPRow is the number of bytes per scanline of the rayBytes array (byte aligned)
  508.     Dim rRow As Long, rColumn As Long ' current row/column of the png image
  509.     Dim dRow As Long, dColumn As Long ' current row/column of destination bitmap
  510.     Dim dIndex As Long ' position of dRow in the destBytes() array
  511.     
  512.     Dim rBytePP As Byte ' nr of bytes per pixel in png image
  513.     Dim destPos As Long, rgbIncrR As Long, rgbIncrG As Long
  514.     
  515.     Dim destBytes() As Byte ' placeholders for DIB bits (DMA)
  516.     Dim tSA As SafeArray  ' array overlays for DIB bits (DMA)
  517.     
  518.     On Error GoTo err_h
  519.     
  520.     ' use direct memory access (DMA) to reference the DIB pixel data
  521.     With tSA
  522.         .cDims = 2                          ' Number of dimensions
  523.         .cbElements = 1                     ' Size of data elements
  524.         .pvData = cHost.BitsPointer         ' Data address
  525.         .rgSABound(0).cElements = m_Height
  526.         .rgSABound(1).cElements = m_Width * 4& ' Nr of Elements
  527.     End With
  528.     CopyMemory ByVal VarPtrArray(destBytes), VarPtr(tSA), 4&
  529.     ' determine the bits/bytes of the png and bitmap images
  530.     GetDepthInfo 0, 0, 0, rBytePP
  531.     ' get location of BMP scanline we are processing from PNG scanline
  532.     If startOffset = 0& Then
  533.         dRow = m_MatrixDat(scanPass, MatrixRow)
  534.     Else
  535.         dRow = startOffset
  536.     End If
  537.     If Not m_ColorType = clrGrayAlpha Then
  538.         rgbIncrR = 2&
  539.         rgbIncrG = 1&
  540.     End If
  541.     For rRow = startOffset To scanCY - 1& ' < in relation to rawBytes() array
  542.         
  543.         dIndex = (m_Height - dRow - 1&) '* dRowWidth ' < destBytes array pointer for 1st pixel in scanline
  544.         rColumn = rRow * rBPRow + 1&  ' < rawBytes array pointer for 1st pixel in scanline
  545.         
  546.         dColumn = m_MatrixDat(scanPass, MatrixCol) ' column in relation to the destBytes() array
  547.         
  548.         Do While dColumn < m_Width
  549.         
  550.             destPos = dColumn * 4& + 3&
  551.             
  552.             Select Case m_ColorType
  553.             
  554.             Case clrTrueAlpha ' true color with alpha (32 bit)
  555.                 destBytes(destPos, dIndex) = rawBytes(rColumn + 3&)  ' alpha channel
  556.                 
  557.             Case clrGrayAlpha  ' grayscale with alpha (1,2,4,8 bit)
  558.                 destBytes(destPos, dIndex) = rawBytes(rColumn + 1&)  ' alpha channel
  559.             
  560.             Case clrTrueColor ' true color + simple transparency (24 bit)
  561.                 destBytes(destPos, dIndex) = &HFF                    ' alpha channel
  562.                 If Not m_TransColor = -1& Then   ' transparency is used
  563.                     If (m_TransColor And &HFF) = rawBytes(rColumn + 2&) Then
  564.                         If ((m_TransColor  &H100&) And &HFF) = rawBytes(rColumn + 1&) Then
  565.                             If ((m_TransColor  &H10000) And &HFF) = rawBytes(rColumn) Then destBytes(destPos, dIndex) = 0&
  566.                         End If
  567.                     End If
  568.                 End If
  569.             End Select
  570.             
  571.             Select Case destBytes(destPos, dIndex)
  572.             Case 0: ' do nothing, RGB is zero
  573.             Case 255
  574.                 destBytes(destPos - 3&, dIndex) = rawBytes(rColumn + rgbIncrR)
  575.                 destBytes(destPos - 2&, dIndex) = rawBytes(rColumn + rgbIncrG)
  576.                 destBytes(destPos - 1&, dIndex) = rawBytes(rColumn)
  577.             Case Else
  578.                 destBytes(destPos - 3&, dIndex) = (0& + rawBytes(rColumn + rgbIncrR)) * destBytes(destPos, dIndex)  255
  579.                 destBytes(destPos - 2&, dIndex) = (0& + rawBytes(rColumn + rgbIncrG)) * destBytes(destPos, dIndex)  255
  580.                 destBytes(destPos - 1&, dIndex) = (0& + rawBytes(rColumn)) * destBytes(destPos, dIndex)  255
  581.             End Select
  582.             
  583.             rColumn = rColumn + rBytePP      ' else increment per source byte pp
  584.             dColumn = dColumn + m_MatrixDat(scanPass, MatrixColAdd)
  585.         
  586.         Loop
  587.         dRow = dRow + m_MatrixDat(scanPass, MatrixRowAdd)
  588.         
  589.     Next
  590.     ' clean up & return result
  591.     CopyMemory ByVal VarPtrArray(destBytes), 0&, 4&
  592.     ConvertPNGtoBMP_NonPalette = True
  593.     Exit Function
  594. err_h:  ' should never get here
  595. Err.Clear
  596. If tSA.cDims Then CopyMemory ByVal VarPtrArray(destBytes), 0&, 4&
  597. End Function
  598. Private Function ConvertPNGtoBMP_Palettes(rawBytes() As Byte, ByVal scanPass As Byte, _
  599.                     ByVal scanCY As Long, ByVal rBPRow As Long, _
  600.                     Optional ByVal startOffset As Long = 0) As Boolean
  601. ' Routine processes only paletted, non-16bit PNG data
  602. ' rawBytes() are the png scanline bytes
  603. ' scanPass() is a valid number btwn 1-8 (8 indicates non-interlaced)
  604. ' scanCY is number of scanlines (btwn 1 and image height)
  605. ' rBPRow is the number of bytes per scanline of the rayBytes array (byte aligned)
  606.     Dim rRow As Long, rColumn As Long ' current row/column of the png image
  607.     Dim dRow As Long, dColumn As Long ' current row/column of destination bitmap
  608.     Dim dIndex As Long ' position of dRow in the destBytes() array
  609.     
  610.     Dim rBytePP As Byte, rBitPP As Byte ' nr of bytes per pixel in png image
  611.     
  612.     Dim tColor(0 To 3) As Byte ' color value when copying 3 or 4 bytes to a 3 or 4 byte array
  613.     Dim palOffset As Long
  614.     Dim destPos As Long
  615.     Dim pIndex As Byte ' alpha related variables
  616.     
  617.     Dim destBytes() As Byte ' placeholders for DIB bits (DMA)
  618.     Dim tSA As SafeArray  ' array overlays for DIB bits (DMA)
  619.     
  620.     Dim maskShift As Long
  621.     On Error GoTo err_h
  622.     
  623.     ' use direct memory access (DMA) to reference the DIB pixel data
  624.     With tSA
  625.         .cDims = 2                          ' Number of dimensions
  626.         .cbElements = 1                     ' Size of data elements
  627.         .pvData = cHost.BitsPointer         ' Data address
  628.         .rgSABound(0).cElements = m_Height
  629.         .rgSABound(1).cElements = m_Width * 4& ' Nr of Elements
  630.     End With
  631.     CopyMemory ByVal VarPtrArray(destBytes), VarPtr(tSA), 4&
  632.     ' determine the bits/bytes of the png and bitmap images
  633.     GetDepthInfo 0, 0, 0, rBytePP
  634.     ' get location of BMP scanline we are processing from PNG scanline
  635.     If startOffset = 0& Then
  636.         dRow = m_MatrixDat(scanPass, MatrixRow)
  637.     Else
  638.         dRow = startOffset
  639.     End If
  640.     For rRow = startOffset To scanCY - 1& ' < in relation to rawBytes() array
  641.         
  642.         dIndex = (m_Height - dRow - 1&) '* dRowWidth ' < destBytes array pointer for 1st pixel in scanline
  643.         rColumn = rRow * rBPRow + 1&  ' < rawBytes array pointer for 1st pixel in scanline
  644.         
  645.         dColumn = m_MatrixDat(scanPass, MatrixCol) ' column in relation to the destBytes() array
  646.         maskShift = 8& - m_BitDepth
  647.         
  648.         Do While dColumn < m_Width
  649.         
  650.             destPos = dColumn * 4&
  651.             
  652.             Select Case m_ColorType
  653.             
  654.             Case clrPalette ' paletted with/without simple transparency in its own palette-alpha table
  655.                 ' 1,2,4,8 bit
  656.                 Call GetPaletteValue(maskShift, rawBytes(rColumn), pIndex)
  657.                 palOffset = pIndex * 3&
  658.                 If m_TransColor = -1& Then    ' no transparency used
  659.                     destBytes(destPos + 3&, dIndex) = &HFF
  660.                     destBytes(destPos, dIndex) = m_Palette(palOffset + 2&)
  661.                     destBytes(destPos + 1&, dIndex) = m_Palette(palOffset + 1&)
  662.                     destBytes(destPos + 2&, dIndex) = m_Palette(palOffset)
  663.                 Else
  664.                     destBytes(destPos + 3&, dIndex) = m_TransSimple(pIndex)
  665.                     Select Case m_TransSimple(pIndex)
  666.                     Case 0
  667.                     Case 255
  668.                         destBytes(destPos, dIndex) = m_Palette(palOffset + 2&)
  669.                         destBytes(destPos + 1&, dIndex) = m_Palette(palOffset + 1&)
  670.                         destBytes(destPos + 2&, dIndex) = m_Palette(palOffset)
  671.                     Case Else
  672.                         destBytes(destPos, dIndex) = (0& + m_Palette(palOffset + 2&)) * m_TransSimple(pIndex)  &HFF
  673.                         destBytes(destPos + 1&, dIndex) = (0& + m_Palette(palOffset + 1&)) * m_TransSimple(pIndex)  &HFF
  674.                         destBytes(destPos + 2&, dIndex) = (0& + m_Palette(palOffset)) * m_TransSimple(pIndex)  &HFF
  675.                     End Select
  676.                 End If
  677.             Case clrGrayScale ' grayscale with/without simple transparency
  678.                 ' 1,2,4,8 bit
  679.                 Call GetPaletteValue(maskShift, rawBytes(rColumn), pIndex)
  680.                 If Not m_TransColor = pIndex Then   ' else fully transparent
  681.                     destBytes(destPos + 3&, dIndex) = &HFF
  682.                     destBytes(destPos, dIndex) = m_Palette(3& * pIndex)
  683.                     destBytes(destPos + 1&, dIndex) = destBytes(destPos, dIndex)
  684.                     destBytes(destPos + 2&, dIndex) = destBytes(destPos, dIndex)
  685.                 End If
  686.             End Select
  687.             
  688.             ' ensure our source byte pointer is moved along appropriately
  689.             If m_BitDepth < 8& Then
  690.                 If maskShift = 0& Then
  691.                     rColumn = rColumn + 1&
  692.                     maskShift = 8& - m_BitDepth
  693.                 Else
  694.                     maskShift = maskShift - m_BitDepth
  695.                 End If
  696.             Else
  697.                 rColumn = rColumn + rBytePP      ' else increment per source byte pp
  698.             End If
  699.             dColumn = dColumn + m_MatrixDat(scanPass, MatrixColAdd)
  700.         
  701.         Loop
  702.         dRow = dRow + m_MatrixDat(scanPass, MatrixRowAdd)
  703.         
  704.     Next
  705.     ' clean up & return result
  706.     CopyMemory ByVal VarPtrArray(destBytes), 0&, 4&
  707.     ConvertPNGtoBMP_Palettes = True
  708.     Exit Function
  709. err_h:  ' should never get here
  710. Err.Clear
  711. If tSA.cDims Then CopyMemory ByVal VarPtrArray(destBytes), 0&, 4
  712. End Function
  713. Private Function ConvertPNGtoBMP_16Bit(rawBytes() As Byte, ByVal scanPass As Byte, _
  714.                     ByVal scanCY As Long, ByVal rBPRow As Long, _
  715.                     Optional ByVal startOffset As Long = 0) As Boolean
  716. ' Routine processes only 16bit PNG data
  717. ' rawBytes() are the png scanline bytes
  718. ' scanPass() is a valid number btwn 1-8 (8 indicates non-interlaced)
  719. ' scanCY is number of scanlines (btwn 1 and image height)
  720. ' rBPRow is the number of bytes per scanline of the rayBytes array (byte aligned)
  721.     Dim rRow As Long, rColumn As Long ' current row/column of the png image
  722.     Dim dRow As Long, dColumn As Long ' current row/column of destination bitmap
  723.     Dim dIndex As Long ' position of dRow in the destBytes() array
  724.     
  725.     Dim destPos As Long, rBytePP As Byte
  726.     Dim rgbIncrR As Long, rgbIncrG As Long
  727.     
  728.     Dim destBytes() As Byte ' placeholders for DIB bits (DMA)
  729.     Dim tSA As SafeArray  ' array overlays for DIB bits (DMA)
  730.     On Error GoTo err_h
  731.     
  732.     ' determine the bits/bytes of the png and bitmap images
  733.     GetDepthInfo 0, 0, 0, rBytePP
  734.     
  735.     ' use direct memory access (DMA) to reference the DIB pixel data
  736.     With tSA
  737.         .cDims = 2                          ' Number of dimensions
  738.         .cbElements = 1                     ' Size of data elements
  739.         .pvData = cHost.BitsPointer         ' Data address
  740.         .rgSABound(0).cElements = m_Height
  741.         .rgSABound(1).cElements = m_Width * 4& ' Nr of Elements
  742.     End With
  743.     CopyMemory ByVal VarPtrArray(destBytes), VarPtr(tSA), 4&
  744.     ' get location of BMP scanline we are processing from PNG scanline
  745.     If startOffset = 0& Then
  746.         dRow = m_MatrixDat(scanPass, MatrixRow)
  747.     Else
  748.         dRow = startOffset
  749.     End If
  750.     
  751.     If m_ColorType = clrTrueAlpha Or m_ColorType = clrTrueColor Then
  752.         rgbIncrR = 4&: rgbIncrG = 2&
  753.     End If
  754.     For rRow = startOffset To scanCY - 1& ' < in relation to rawBytes() array
  755.         
  756.         dIndex = (m_Height - dRow - 1&) '* dRowWidth ' < destBytes array pointer for 1st pixel in scanline
  757.         rColumn = rRow * rBPRow + 1&  ' < rawBytes array pointer for 1st pixel in scanline
  758.         
  759.         dColumn = m_MatrixDat(scanPass, MatrixCol) ' column in relation to the destBytes() array
  760.         
  761.         Do While dColumn < m_Width
  762.         
  763.             destPos = dColumn * 4& + 3&
  764.             
  765.             Select Case m_ColorType
  766.             
  767.             Case clrTrueAlpha ' true color with alpha (64 bit)
  768.                 destBytes(destPos, dIndex) = rawBytes(rColumn + 6&)  ' alpha channel
  769.             
  770.             Case clrGrayAlpha  ' grayscale with alpha (32 bit)
  771.                 destBytes(destPos, dIndex) = rawBytes(rColumn + 2&)
  772.             
  773.             Case clrTrueColor ' true color with/without simple transparency (48 bit)
  774.                 
  775.                 destBytes(destPos, dIndex) = &HFF
  776.                 If Not m_TransColor = -1& Then   ' transparency is used
  777.                     If rawBytes(rColumn + rgbIncrR) = m_TransSimple(rgbIncrR) Then
  778.                         If rawBytes(rColumn + rgbIncrG) = m_TransSimple(rgbIncrG) Then
  779.                             If rawBytes(rColumn) = m_TransSimple(0) Then destBytes(destPos, dIndex) = 0&
  780.                         End If
  781.                     End If
  782.                 End If
  783.             Case clrGrayScale ' grayscale with or without simple transparency (16 bit)
  784.                 If m_TransColor = -1& Then
  785.                     destBytes(destPos, dIndex) = &HFF
  786.                 ElseIf Not rawBytes(rColumn) = m_TransSimple(0) Then
  787.                     destBytes(destPos, dIndex) = &HFF
  788.                 End If
  789.             End Select
  790.             
  791.             Select Case destBytes(destPos, dIndex)
  792.             Case 0: ' do nothing, fully transparent
  793.             Case 255
  794.                 destBytes(destPos - 3&, dIndex) = rawBytes(rColumn + rgbIncrR)
  795.                 destBytes(destPos - 2&, dIndex) = rawBytes(rColumn + rgbIncrG)
  796.                 destBytes(destPos - 1&, dIndex) = rawBytes(rColumn)
  797.             Case Else
  798.                 destBytes(destPos - 3&, dIndex) = (0& + rawBytes(rColumn + rgbIncrR)) * destBytes(destPos, dIndex)  255
  799.                 destBytes(destPos - 2&, dIndex) = (0& + rawBytes(rColumn + rgbIncrG)) * destBytes(destPos, dIndex)  255
  800.                 destBytes(destPos - 1&, dIndex) = (0& + rawBytes(rColumn)) * destBytes(destPos, dIndex)  255
  801.             End Select
  802.             
  803.             ' ensure our source byte pointer is moved along appropriately
  804.             rColumn = rColumn + rBytePP
  805.             dColumn = dColumn + m_MatrixDat(scanPass, MatrixColAdd)
  806.         
  807.         Loop
  808.         dRow = dRow + m_MatrixDat(scanPass, MatrixRowAdd)
  809.         
  810.     Next
  811.     ' clean up & return result
  812.     CopyMemory ByVal VarPtrArray(destBytes), 0&, 4&
  813.     ConvertPNGtoBMP_16Bit = True
  814.     Exit Function
  815. err_h:  ' should never get here
  816. Err.Clear
  817. If tSA.cDims Then CopyMemory ByVal VarPtrArray(destBytes), 0&, 4&
  818. End Function
  819. Private Sub GetPaletteValue(ByVal PixelPos As Long, ByVal PixelValue As Byte, _
  820.                 Optional ByRef RtnIndex As Byte)
  821.     ' // LaVolpe, Dec 1 thru 10 - added from scratch
  822.     ' Returns a palette index and palette color from a compressed byte
  823.     RtnIndex = (PixelValue  pow2x8(PixelPos)) And (pow2x8(m_BitDepth) - 1)
  824.     
  825. End Sub
  826. Private Function GetBytesPerPixel(totalWidth As Long, btsPerPixel As Byte) As Long
  827.     ' // LaVolpe, Dec 1 thru 10
  828.     ' returns number of bytes required to display n pixels at p color depth (byte aligned)
  829.     GetBytesPerPixel = (totalWidth * btsPerPixel + 7&)  8&
  830. End Function
  831. Private Sub GetDepthInfo(destBitPP As Byte, destBytePP As Byte, _
  832.                         rawBitsPP As Byte, rawBytesPP As Byte)
  833.     
  834. ' returns the bits per pixel & bytes per pixel for the destination bitmap
  835. ' and also the respective values for the png image
  836.     
  837. ' PNG > DIB bmp (per pixel) conversion chart I use throughout the routines:
  838. 'Color Type     bit depth   PNG bits/bytes per pixel  BMP bits/bytes pp (ignore alpha)
  839. '----------     ---------   ------------------------- --------------------------------
  840. '0 gray scale   1                   1   1                   1   1   (?  ?)
  841. '               2                   2   1                   4   1   (?  ?)
  842. '               4                   4   1                   4   1   (?  ?)
  843. '               8                   8   1                   8   1   (8  1)
  844. '               16                  16  2                   8   1   (8  1)
  845. '2 true color   8                   24  3                   24  3   (24 3)
  846. '               16                  48  6                   24  3   (24 3)
  847. '3 palette      1                   1   1                   1   1   (?  ?)
  848. '               2                   2   1                   4   1   (?  ?)
  849. '               4                   4   1                   4   1   (?  ?)
  850. '               8                   8   1                   8   1   (8  1)
  851. '4 gray+alpha   8                   16  2                   32  4   (24 3)
  852. '               16                  32  4                   32  4   (24 3)
  853. '6 true+alpha   8                   32  4                   32  4   (24 3)
  854. '               16                  64  8                   32  4   (24 3)
  855. 'any bit depth that uses simple transparency (trns chunk)   32  4   (n/a)
  856. '--------------------------------------------------------------------------
  857.     
  858.     Select Case m_ColorType
  859.     
  860.     Case clrTrueAlpha ' true color w/alpha (only 8,16 bpp pngs)
  861.         rawBytesPP = 4& * (m_BitDepth  8&): rawBitsPP = m_BitDepth * 4&
  862.         
  863.     Case clrGrayAlpha: ' grayscale w/alpha (only 8,16 bpp pngs)
  864.         rawBytesPP = 2& * (m_BitDepth  8&): rawBitsPP = m_BitDepth * 2&
  865.         
  866.     Case clrTrueColor: ' true color (rgb triples) (8,16 bpp pngs)
  867.         rawBytesPP = 3& * (m_BitDepth  8&): rawBitsPP = m_BitDepth * 3&
  868.         
  869.     Case clrGrayScale ' grayscale images (all bit depths)
  870.         If m_BitDepth = 2& Then ' special case as MS bitmaps don't do 2bpp
  871.             rawBytesPP = 1&: rawBitsPP = 2&
  872.         ElseIf m_BitDepth > 4& Then ' (8,16 bpp pngs)
  873.             rawBytesPP = m_BitDepth  8&: rawBitsPP = m_BitDepth
  874.         Else ' (1,4 bpp pngs)
  875.             rawBytesPP = 1: rawBitsPP = m_BitDepth
  876.         End If
  877.         
  878.     Case clrPalette: ' palette entries (1,2,4,8 bpp pngs)
  879.         rawBytesPP = 1: rawBitsPP = m_BitDepth
  880.         
  881.     End Select
  882.     
  883.     ' our DIB will always be 32bpp
  884.     destBitPP = 32: destBytePP = 4
  885. End Sub
  886. Private Function PaethPredictor(ByVal Left As Integer, ByVal Above As Integer, ByVal UpperLeft As Integer) As Integer
  887.     ' // LaVolpe, Dec 1 thru 10 - rewrote for understanding & commented/linked
  888.     
  889.     ' http://www.w3.org/TR/PNG/#9-table91
  890.     ' algorithm is used for both encoding & decoding the png image's filter
  891.     ' based off of the formula created by Alan W. Paeth & provided fully in url above
  892.     Dim pa As Integer, pb As Integer, pC As Integer, p As Integer
  893.     p = (Left + Above - UpperLeft)
  894.     pa = Abs(p - Left)
  895.     pb = Abs(p - Above)
  896.     pC = Abs(p - UpperLeft)
  897.     
  898.     ' tie breaker
  899.     ' The order in which the comparisons are performed is critical and shall not be altered
  900.     If (pa <= pb) And (pa <= pC) Then
  901.         PaethPredictor = Left
  902.     ElseIf pb <= pC Then
  903.         PaethPredictor = Above
  904.     Else
  905.         PaethPredictor = UpperLeft
  906.     End If
  907. End Function
  908. Private Sub DecodeFilter_Avg(Filtered() As Byte, ByVal RowNr As Long, ByVal ScanLine As Long, ByVal stepVal As Integer)
  909.     ' // LaVolpe, Dec 1 thru 10 - rewrote for understanding; nothing wrong with original
  910.     'http://www.w3.org/TR/PNG/#9-table91
  911.     'Filters may use the original values of the following bytes to generate the new byte value:
  912.     '
  913.     'x  the byte being filtered;
  914.     'a  the byte corresponding to x in the pixel immediately before the pixel containing x (or the byte immediately before x, when the bit depth is less than 8);
  915.     'b  the byte corresponding to x in the previous scanline;
  916.     'c  the byte corresponding to b in the pixel immediately before the pixel containing b (or the byte immediately before b, when the bit depth is less than 8).
  917.     
  918.     ' algorithm: Recon(x) = Filt(x) + floor((Recon(a) + Recon(b)) / 2)
  919.     ' Unsigned arithmetic modulo 256 is used, so that both the inputs and outputs fit into bytes
  920.     Dim X As Long, startByte As Long
  921.     
  922.     startByte = RowNr * ScanLine + 1
  923.     
  924.     On Error GoTo eh
  925.     ' break out for faster loops, removing IF statements/combinations
  926.     If RowNr = 0 Then   ' 1st row; there will be no Top row to get data from
  927.         ' if png is encoded properly, shouldn't get here
  928.         ' now process the 2nd pixel on, to finish the scanline
  929.         For X = startByte + stepVal To startByte + ScanLine - 2
  930.             Filtered(X) = (0 + Filtered(X) + (Filtered(X - stepVal)  2)) Mod 256
  931.         Next
  932.         
  933.     Else    ' 2nd or subsequent rows
  934.         ' process the 1st n bytes (1st pixel only)
  935.         For X = startByte To startByte + stepVal - 1
  936.             Filtered(X) = (0 + Filtered(X) + (Filtered(X - ScanLine)  2)) Mod 256
  937.         Next
  938.         ' now process the 2nd pixel on, to finish the scanline
  939.         For X = X To startByte + ScanLine - 2
  940.             Filtered(X) = (0 + Filtered(X) + (0 + Filtered(X - stepVal) + Filtered(X - ScanLine))  2) Mod 256
  941.         Next
  942.     End If
  943. eh:
  944. End Sub
  945. Private Sub DecodeFilter_Paeth(Filtered() As Byte, ByVal RowNr As Long, ByVal ScanLine As Long, ByVal stepVal As Integer)
  946.     ' // LaVolpe, Dec 1 thru 10 - rewrote for understanding; nothing wrong with original
  947.     'http://www.w3.org/TR/PNG/#9-table91
  948.     
  949.     'Filters may use the original values of the following bytes to generate the new byte value:
  950.     '
  951.     'x  the byte being filtered;
  952.     'a  the byte corresponding to x in the pixel immediately before the pixel containing x (or the byte immediately before x, when the bit depth is less than 8);
  953.     'b  the byte corresponding to x in the previous scanline;
  954.     'c  the byte corresponding to b in the pixel immediately before the pixel containing b (or the byte immediately before b, when the bit depth is less than 8).
  955.     
  956.     ' algorithm: Recon(x) = Filt(x) + PaethPredictor(Recon(a), Recon(b), Recon(c))
  957.     ' Unsigned arithmetic modulo 256 is used, so that both the inputs and outputs fit into bytes
  958.     Dim X As Long, startByte As Long
  959.     startByte = RowNr * ScanLine + 1
  960.     
  961.     ' break out for faster loops, removing IF statements/combinations
  962.     On Error GoTo eh
  963.     
  964.     If RowNr = 0 Then    ' 1st row; there will be no Top row to get data from
  965.         ' if png is encoded properly, shouldn't get here
  966.         ' now process the 2nd pixel on, to finish the scanline
  967.         For X = startByte + stepVal To startByte + ScanLine - 2
  968.             Filtered(X) = (0 + Filtered(X) + Filtered(X - stepVal)) Mod 256
  969.         Next
  970.     
  971.     Else    ' 2nd or subsequent rows
  972.         ' process the 1st n bytes (1st pixel only)
  973.         For X = startByte To startByte + stepVal - 1
  974.             Filtered(X) = (0 + Filtered(X) + Filtered(X - ScanLine)) Mod 256
  975.         Next
  976.         ' now process the 2nd pixel on, to finish the scanline
  977.         For X = X To startByte + ScanLine - 2
  978.             Filtered(X) = (0 + Filtered(X) + PaethPredictor(Filtered(X - stepVal), Filtered(X - ScanLine), Filtered(X - ScanLine - stepVal))) Mod 256
  979.         Next
  980.     End If
  981. eh:
  982. End Sub
  983. Private Sub DecodeFilter_Sub(Filtered() As Byte, ByVal RowNr As Long, ByVal ScanLine As Long, ByVal stepVal As Integer)
  984.     ' // LaVolpe, Dec 1 thru 10 - rewrote for understanding; nothing wrong with original
  985.     'http://www.w3.org/TR/PNG/#9-table91
  986.     
  987.     'Filters may use the original values of the following bytes to generate the new byte value:
  988.     '
  989.     'x  the byte being filtered;
  990.     'a  the byte corresponding to x in the pixel immediately before the pixel containing x (or the byte immediately before x, when the bit depth is less than 8);
  991.     'b  the byte corresponding to x in the previous scanline;
  992.     'c  the byte corresponding to b in the pixel immediately before the pixel containing b (or the byte immediately before b, when the bit depth is less than 8).
  993.     
  994.     ' algorithm: Recon(x) = Filt(x) + Recon(a)
  995.     ' Unsigned arithmetic modulo 256 is used, so that both the inputs and outputs fit into bytes
  996.     Dim startByte As Long
  997.     Dim n As Long, X As Long
  998.     
  999.     startByte = RowNr * ScanLine + 1
  1000.     
  1001.     On Error GoTo eh
  1002.     ' 1st n bytes for 1st pixel are unfiltered
  1003.     For n = startByte + stepVal To startByte + ScanLine - 2 Step stepVal
  1004.         For X = n To n + stepVal - 1
  1005.             Filtered(X) = (0 + Filtered(X) + Filtered(X - stepVal)) Mod 256
  1006.         Next
  1007.     Next
  1008. eh:
  1009. End Sub
  1010. Private Sub DecodeFilter_Up(Filtered() As Byte, ByVal RowNr As Long, ByVal ScanLine As Long, ByVal stepVal As Integer)
  1011.     ' // LaVolpe, Dec 1 thru 10 - rewrote for understanding; nothing wrong with original
  1012.     'http://www.w3.org/TR/PNG/#9-table91
  1013.     
  1014.     'Filters may use the original values of the following bytes to generate the new byte value:
  1015.     '
  1016.     'x  the byte being filtered;
  1017.     'a  the byte corresponding to x in the pixel immediately before the pixel containing x (or the byte immediately before x, when the bit depth is less than 8);
  1018.     'b  the byte corresponding to x in the previous scanline;
  1019.     'c  the byte corresponding to b in the pixel immediately before the pixel containing b (or the byte immediately before b, when the bit depth is less than 8).
  1020.     
  1021.     ' algorithm:  Recon(x) = Filt(x) + Recon(b)
  1022.     ' Unsigned arithmetic modulo 256 is used, so that both the inputs and outputs fit into bytes
  1023.     
  1024.     Dim startByte As Long, X As Long
  1025.     
  1026.     On Error GoTo eh
  1027.     If Not RowNr = 0 Then    ' 1st row; there will be no Top row to get data from
  1028.         startByte = RowNr * ScanLine + 1
  1029.         For X = startByte To startByte + ScanLine - 2
  1030.             Filtered(X) = (0 + Filtered(X) + Filtered(X - ScanLine)) Mod 256
  1031.         Next
  1032.     End If
  1033. eh:
  1034. End Sub
  1035. Private Function UnfilterInterlaced(Filtered() As Byte) As Boolean
  1036.     ' // LaVolpe, Dec 1 thru 10 - built from scratch
  1037.     ' http://www.libpng.org/pub/png/spec/1.2/PNG-DataRep.html#DR.Interlaced-data-order
  1038.     
  1039.     ' Progressive display/scan order per 8 pixel blocks (64 total pixels)
  1040.     '   1 6 4 6 2 6 4 6     ' 1st scan: 1 pixel (@col 0), row 0 [1/64 of total image]
  1041.     '   7 7 7 7 7 7 7 7     ' 2nd scan: 1 pixel (@col 4), row 0 [1/32 of image shown]
  1042.     '   5 6 5 6 5 6 5 6     ' 3rd scan: 2 pixels (@cols 0:4), row 4 [1/16 of image]
  1043.     '   7 7 7 7 7 7 7 7     ' 4th scan: 4 pixels (@cols 2:6), rows 0:4 [1/8]
  1044.     '   3 6 4 6 3 6 4 6     ' 5th scan: 8 pixels (@cols 0:2:4:6), rows 2:6 [1/4]
  1045.     '   7 7 7 7 7 7 7 7     ' 6th scan: 16 pixels (@cols 1:3:5:7), rows 0:2:4:6 [1/2]
  1046.     '   5 6 5 6 5 6 5 6     ' 7th scan: 32 pixels (@cols all), rows 1:3:5:7 [100%]
  1047.     '   7 7 7 7 7 7 7 7                 64 pixels, 15 scanlines over 7 passes
  1048.     
  1049.     ' Note : all logic in this routine is based off of the above grid.
  1050.     ' Scanline widths are only guaranteed to be same for each scanline in the same pass.
  1051.     ' Scanlines can be padded both horizontally & vertically if the image doesn't fit into
  1052.     '   a nice 8x8 grid evenly.
  1053.     ' Each scanline in interlaced image is also filtered, but they are filtered in relation
  1054.     ' to only the other scanlines in the same pass, different than non-interlaced images.
  1055.     ' Think of non-interlaced images as single-pass interlaced images.
  1056.     ' counter variables
  1057.     Dim Pass As Byte, srcRow As Long
  1058.     ' sizing/bit alignment variables
  1059.     Dim nr8wide As Long, nr8high As Long
  1060.     Dim nrBytes As Long, passPtr As Long
  1061.     Dim InterlacePass() As Byte  ' unfiltered progressive display (used 7x for 7 passes)
  1062.     ' bytes and bits per pixel values
  1063.     Dim bytesPP As Byte, BPRow As Long, bitPP As Byte
  1064.     
  1065.     ' need bit & byte information
  1066.     GetDepthInfo 0, 0, bitPP, bytesPP
  1067.     
  1068.     ' oversize array for "pass" bytes to prevent reszing array on each pass
  1069.     BPRow = GetBytesPerPixel((m_Width  m_MatrixDat(7, MatrixColAdd)), bitPP)
  1070.     ' how many bytes are needed for the final pass; largest pass size in bytes
  1071.     nrBytes = (BPRow + 1) * (m_Height  m_MatrixDat(7, MatrixRowAdd))
  1072.     ReDim InterlacePass(0 To nrBytes - 1&)
  1073.     ' interlaced images always come in 7 passes; although not all passes may be used
  1074.     For Pass = 1 To 7
  1075.         ' ensure bounds are valid. If image is smaller than 8x8 not all passes are valid/used
  1076.         ' Tested with images as small as 1x1
  1077.     
  1078.         ' calculate nr of pixels for this pass that will fit in width of image
  1079.         nr8wide = m_Width  m_MatrixDat(Pass, MatrixColAdd) - (m_Width Mod m_MatrixDat(Pass, MatrixColAdd) > m_MatrixDat(Pass, MatrixCol))
  1080.         If nr8wide > 0& Then
  1081.             
  1082.             ' calcuate nr of rows for this pass that will fit in height of image
  1083.             nr8high = m_Height  m_MatrixDat(Pass, MatrixRowAdd) - (m_Height Mod m_MatrixDat(Pass, MatrixRowAdd) > m_MatrixDat(Pass, MatrixRow))
  1084.             If nr8high > 0& Then
  1085.     
  1086.                 ' calculate row bytes for the interlaced image, byte aligned
  1087.                 BPRow = GetBytesPerPixel(nr8wide, bitPP) + 1&
  1088.                 ' how many bytes are needed for the complete pass, less filter byte?
  1089.                 nrBytes = BPRow * nr8high
  1090.                 '^^ the filter routines expect the filter byte to be in its parameters, so add it
  1091.                 
  1092.                 ' unfilter the scanlines
  1093.                 CopyMemory InterlacePass(0), Filtered(passPtr), nrBytes
  1094.                 For srcRow = 0& To nr8high - 1&
  1095.                     Select Case Filtered(BPRow * srcRow + passPtr)
  1096.                     Case 0: ' no filtering
  1097.                     Case 1: ' sub filter
  1098.                         DecodeFilter_Sub InterlacePass, srcRow, BPRow, bytesPP
  1099.                     Case 2: ' up filter
  1100.                         DecodeFilter_Up InterlacePass, srcRow, BPRow, 0
  1101.                     Case 3: ' average filter
  1102.                         DecodeFilter_Avg InterlacePass, srcRow, BPRow, bytesPP
  1103.                     Case 4: ' paeth filter
  1104.                         DecodeFilter_Paeth InterlacePass, srcRow, BPRow, bytesPP
  1105.                     Case Else
  1106.                         ' If we got here, there is a different filtering mechanism at large
  1107.                         Exit Function
  1108.                     End Select
  1109.                 Next
  1110.         
  1111.                 ' offset the filtered array pointer to account for the 1byte filter flag per scanline
  1112.                 ' This will point to the next pass's X,Y position in the Unfiltered() array
  1113.                 passPtr = passPtr + nrBytes
  1114.             
  1115.                 ' send unfiltered array to be transfered to the DIB
  1116.                 ' color formats broken into different routines to help speed up transfering
  1117.                 Select Case m_ColorType
  1118.                 Case clrTrueAlpha, clrGrayAlpha, clrTrueColor
  1119.                     If m_BitDepth < 16& Then
  1120.                         If ConvertPNGtoBMP_NonPalette(InterlacePass(), Pass, nr8high, BPRow) = False Then Exit Function
  1121.                     Else
  1122.                         If ConvertPNGtoBMP_16Bit(InterlacePass(), Pass, nr8high, BPRow) = False Then Exit Function
  1123.                     End If
  1124.                 Case clrPalette, clrGrayScale
  1125.                     If m_BitDepth < 16& Then
  1126.                         If ConvertPNGtoBMP_Palettes(InterlacePass(), Pass, nr8high, BPRow) = False Then Exit Function
  1127.                     Else
  1128.                         If ConvertPNGtoBMP_16Bit(InterlacePass(), Pass, nr8high, BPRow) = False Then Exit Function
  1129.                     End If
  1130.                 End Select
  1131.             End If ' check for nr8high < 1
  1132.         End If ' check for nr8wide < 1
  1133.     
  1134.     Next Pass
  1135.     UnfilterInterlaced = True
  1136.     
  1137. End Function
  1138. Private Function UnfilterNI(filteredData() As Byte) As Boolean
  1139.     ' // LaVolpe, Dec 1 thru 10 - completely rewritten to remove excess large array usage
  1140.     ' http://www.w3.org/TR/PNG/#9-table91
  1141.     Dim Row As Long, BPRow As Long
  1142.     Dim lBpp As Byte, stepVal As Byte
  1143.     
  1144.     GetDepthInfo 0, 0, lBpp, stepVal
  1145.     BPRow = GetBytesPerPixel(m_Width, lBpp) + 1&
  1146.     '^^ the filtered row contains an extra byte (1st byte of each row)
  1147.     '   that identifies the filter algorithm used for that row
  1148.     
  1149.     For Row = 0& To m_Height - 1&
  1150.         Select Case filteredData(BPRow * Row)
  1151.         Case 0 'no filtering
  1152.         Case 1 'Sub
  1153.             DecodeFilter_Sub filteredData, Row, BPRow, stepVal
  1154.         Case 2 'Up
  1155.             DecodeFilter_Up filteredData, Row, BPRow, 0
  1156.         Case 3 'Average
  1157.             DecodeFilter_Avg filteredData, Row, BPRow, stepVal
  1158.         Case 4 'Paeth
  1159.             DecodeFilter_Paeth filteredData, Row, BPRow, stepVal
  1160.         Case Else
  1161.             ' invalid filter type; no action
  1162.         End Select
  1163.         
  1164.     Next Row
  1165.     
  1166.     ' color formats broken into different routines to help speed up transferring
  1167.     Select Case m_ColorType
  1168.     Case clrTrueAlpha, clrGrayAlpha, clrTrueColor
  1169.         If m_BitDepth < 16& Then
  1170.             UnfilterNI = ConvertPNGtoBMP_NonPalette(filteredData(), 8, Row, BPRow, 0)
  1171.         Else
  1172.             UnfilterNI = ConvertPNGtoBMP_16Bit(filteredData(), 8, Row, BPRow, 0)
  1173.         End If
  1174.     Case clrPalette, clrGrayScale
  1175.         If m_BitDepth < 16& Then
  1176.             UnfilterNI = ConvertPNGtoBMP_Palettes(filteredData(), 8, Row, BPRow, 0)
  1177.         Else
  1178.             UnfilterNI = ConvertPNGtoBMP_16Bit(filteredData(), 8, Row, BPRow, 0)
  1179.         End If
  1180.     End Select
  1181.     
  1182. End Function
  1183. Private Function zChunk_IHDR(bufLen As Long, streamOffset As Long, cmprSize As Long, crcValue As Long) As Long
  1184.                 
  1185.     ' IHDR structure
  1186.     '    Width As Long              << cannot be negative
  1187.     '    Height As Long             << cannot be negative
  1188.     '    BitDepth As Byte           << must be 1,2,4,8,16
  1189.     '    ColorType As Byte          << must be 0,2,3,4,6
  1190.     '    Compression As Byte        << must be zero
  1191.     '    Filter As Byte             << must be zero
  1192.     '    Interlacing As Byte        << must be zero or one
  1193.     
  1194.     On Error Resume Next
  1195.     Dim lRtn As Long, lValue As Long
  1196.     
  1197.     If Not crcValue = 0& Then
  1198.         lRtn = Not (zCheckCRCvalue(VarPtr(pngStream(streamOffset)), bufLen + 4&, crcValue))
  1199.     End If
  1200.     If lRtn = 0& Then
  1201.         
  1202.         CopyMemory m_Width, pngStream(streamOffset + 4&), 4&
  1203.         m_Width = iparseReverseLong(m_Width)
  1204.         CopyMemory m_Height, pngStream(streamOffset + 8&), 4&
  1205.         m_Height = iparseReverseLong(m_Height)
  1206.         
  1207.         If m_Width < 1& Or m_Height < 1& Then
  1208.             lRtn = 1& 'Corrupted Image Header. Cannot continue.
  1209.         
  1210.         Else
  1211.             
  1212.             If Not pngStream(streamOffset + 14&) = 0 Then
  1213.                 lRtn = 1& ' Invalid Compression Flag in Header. Cannot continue.
  1214.             Else
  1215.                 If Not pngStream(streamOffset + 15&) = 0 Then
  1216.                     lRtn = 1& 'Invalid Filter Flag in Header. Cannot continue.
  1217.                 Else
  1218.                     
  1219.                     m_BitDepth = pngStream(streamOffset + 12&)
  1220.                     Select Case m_BitDepth
  1221.                     Case 1&, 2&, 4&, 8&, 16&
  1222.                         ' it is a valid bit depth
  1223.                         m_ColorType = pngStream(streamOffset + 13&)
  1224.                         Select Case m_ColorType
  1225.                         Case 0&, 2&, 3&, 4&, 6&
  1226.                             ' it is a valid color type
  1227.                             m_Interlacing = pngStream(streamOffset + 16&)
  1228.                             If m_Interlacing > 1& Then
  1229.                                 lRtn = 1& 'Invalid Interlacing Flag in Header. Cannot continue.
  1230.                             End If
  1231.                         Case Else
  1232.                             lRtn = 1& 'Invalid Color Type Flag in Header. Cannot continue.
  1233.                         End Select
  1234.                     Case Else
  1235.                         lRtn = 1& 'Invalid Bit Depth Flag in Header. Cannot continue.
  1236.                     End Select
  1237.                     
  1238.                 End If  ' Filter flag
  1239.             End If  ' Compression flag
  1240.         End If  ' Dimensions
  1241.         
  1242.         If lRtn = 0& Then
  1243.             ' check for png sizes that would cause overflow errors in other calculations...
  1244.             ' This has 2 basic checks
  1245.             ' check DWord width alignment * height first are within bounds
  1246.             lValue = 32& * m_Width * m_Height     ' max number of bytes needed for DIB
  1247.             ' see if uncompress png data is too long
  1248.             If Not Err Then
  1249.                 cmprSize = CalcUncompressedWidth()
  1250.             End If
  1251.             If Err Then
  1252.                 Err.Clear
  1253.                 lRtn = 1&
  1254.             End If
  1255.         End If
  1256.     End If
  1257.     zChunk_IHDR = lRtn
  1258. End Function
  1259. Private Function zChunk_PLTE(bufLen As Long, streamOffset As Long, crcValue As Long) As Long
  1260.     ' http://www.w3.org/TR/PNG/#11PLTE
  1261.     If m_ColorType = 0& Or m_ColorType = 4& Then Exit Function
  1262.     '^^ per specs, palettes shall not appear for those color types
  1263.     '   Since we can ignore the palette, we won't trigger a critcal error
  1264.     
  1265.     Dim lRtn As Long
  1266.     If Not crcValue = 0& Then
  1267.         lRtn = Not (zCheckCRCvalue(VarPtr(pngStream(streamOffset)), bufLen + 4&, crcValue))
  1268.     End If
  1269.     If lRtn = 0& Then
  1270.         
  1271.         ' per png specs, palette must be divisible by 3
  1272.         If bufLen Mod 3& = 0& Then
  1273.             ReDim m_Palette(0 To bufLen - 1&)
  1274.             CopyMemory m_Palette(0), pngStream(streamOffset + 4&), bufLen
  1275.         Else ' error
  1276.             lRtn = 1& 'Invalid Palette. Cannot continue.
  1277.         End If
  1278.     End If
  1279.     zChunk_PLTE = lRtn
  1280. End Function
  1281. Private Function zChunk_tRNS(bufLen As Long, streamOffset As Long, crcValue As Long) As Long
  1282. 'http://www.w3.org/TR/PNG/#11tRNS
  1283.     
  1284.     If m_ColorType > clrPalette Then Exit Function
  1285.     ' Per specs, the tRNS chunk shall not be used for Color Types 4 and 6
  1286.     On Error GoTo ExitMe
  1287.     Dim UB As Long, palIndex As Byte, lRtn As Long
  1288.     
  1289.     If Not crcValue = 0& Then
  1290.         lRtn = Not (zCheckCRCvalue(VarPtr(pngStream(streamOffset)), bufLen + 4, crcValue))
  1291.     End If
  1292.     If lRtn = 0& Then
  1293.         
  1294.         ' we will ensure the passed array is dimensioned properly and also cache
  1295.         ' the simple transparency color for easier reference while processing
  1296.         
  1297.         ReDim m_TransSimple(0 To bufLen - 1&)
  1298.         CopyMemory m_TransSimple(0), pngStream(streamOffset + 4&), bufLen
  1299.     
  1300.         If m_ColorType = clrGrayScale Then ' grayscale with simple transparency
  1301.             ' least significant bits used. Tweak array to hold only those bits in byte format
  1302.             m_TransColor = m_TransSimple(1) ' color-index value not a color
  1303.             
  1304.         ElseIf m_ColorType = clrTrueColor Then ' rgb triple (true color)
  1305.             ' save as BGR to be compared against PNG samples
  1306.             m_TransColor = m_TransSimple(5) Or m_TransSimple(3) * &H100& Or m_TransSimple(1) * &H10000
  1307.             ' for 16bpp PNGs, the 0,2,4 array elements are needed also but will be tested in ConvertPngToBmp
  1308.             
  1309.         ElseIf m_ColorType = clrPalette Then ' TransSimple() is an array
  1310.             ' This array is directly related to the Palette. Each palette entry
  1311.             ' will have a related TransSimple() entry. Exception: When Palette entries
  1312.             ' are sorted (in ascending order of alpha value), then any Palette entries
  1313.             ' that have alpha values of 255 probably will not be in that related array.
  1314.             ' In these cases, we will fake it & provide the missing entries.
  1315.         
  1316.             ' to prevent out of bounds errors, ensure array is 255
  1317.             If UBound(m_TransSimple) < 255& Then ' pngs are not required to provide all
  1318.                 UB = UBound(m_TransSimple)
  1319.                 ReDim Preserve m_TransSimple(0 To 255)    ' prevent out ouf bounds errors
  1320.                 FillMemory m_TransSimple(UB + 1&), 255& - UB, 255
  1321.             End If
  1322.             m_TransColor = 0& ' simply a flag > -1, has no other meaning
  1323.         End If
  1324.         
  1325.         If Err Then
  1326.             Err.Clear   ' an error regarding the TransSimple() array
  1327.             m_TransColor = -1& ' no transparency color
  1328.         End If
  1329.     
  1330.     End If
  1331. ExitMe:
  1332. End Function
  1333. Private Sub InitializePalette()
  1334.     ' Purpose: Create a palette for the PNG file, if needed
  1335.     ' The colors from the palette will be transfered to the 32bpp image
  1336.     If m_ColorType = clrPalette Or m_ColorType = clrGrayScale Then
  1337.     
  1338.         Dim nrEntries As Long, stepVal As Long
  1339.         Dim X As Long, Index As Long, Color As Long
  1340.         ' PNG grayscale palettes are not provided, they are assumed...
  1341.         If iparseIsArrayEmpty(VarPtrArray(m_Palette)) = 0& Then
  1342.             
  1343.             ReDim m_Palette(0 To 767)
  1344.             If m_ColorType = clrGrayScale Then
  1345.             
  1346.                 nrEntries = pow2x8(m_BitDepth) - 1&       ' number grayscale palette entries
  1347.                 stepVal = 255  (pow2x8(m_BitDepth) - 1&) ' step value for the palette
  1348.                 For X = 1& To nrEntries
  1349.                     Color = X * stepVal
  1350.                     Index = X * 3&
  1351.                     m_Palette(Index) = Color
  1352.                     m_Palette(Index + 1&) = Color
  1353.                     m_Palette(Index + 2&) = Color
  1354.                 Next
  1355.                 
  1356.             ElseIf m_BitDepth = 1 Then              ' fix up 2 color palette
  1357.                 CopyMemory m_Palette(3), vbWhite, 3&
  1358.             End If
  1359.         End If
  1360.     
  1361.     End If
  1362.     
  1363. End Sub
  1364. Private Function IsPNG() As Boolean
  1365.     ' Purpose: Determine if PNG magic number exists in 1st 8 bytes of the file/array
  1366.     ' Note: array was already validated as not empty when class LoadStream/LoadFile was called
  1367.     Dim gpLong As Long
  1368.     
  1369.     ' validate we are looking at a png file
  1370.     CopyMemory gpLong, pngStream(LBound(pngStream)), 4&
  1371.     If gpLong = png_Signature1 Then
  1372.         CopyMemory gpLong, pngStream(LBound(pngStream) + 4), 4&
  1373.         IsPNG = (gpLong = png_Signature2)
  1374.     End If
  1375. End Function
  1376. ' decompression using pure VB, this is only run if system
  1377. ' does not have GDI+ nor does it have zLib.dll
  1378. ' source by: alfred.koppold@freenet.de
  1379. ' Note: This does have a calc error I haven't been able to track down yet.
  1380. '   The error is noticable in very few PNGs (especially 1bpp pngs), but can be visually noticed
  1381. Private Function vbDecompress(outStream() As Byte, CompressedArray() As Byte, ByVal UncompressedSize As Long, Optional ZIP64 As Boolean = False) As Boolean
  1382.     
  1383.     Dim IsLastBlock As Boolean
  1384.     Dim CompType As Long
  1385.     Dim Char As Long
  1386.     Dim Nubits As Long
  1387.     Dim L1 As Long
  1388.     Dim L2 As Long
  1389.     Dim X As Long
  1390.     Dim lRtn As Long
  1391.     Dim MinLLength As Long
  1392.     Dim MaxLLength As Long
  1393.     Dim MinDLength As Long
  1394.     Dim MaxDLength As Long
  1395.     Dim IsStaticBuild As Boolean
  1396.     
  1397.     On Error GoTo Stop_Decompression
  1398.     
  1399.     Dim tSAIN As SafeArray
  1400.     With tSAIN
  1401.         .cbElements = 1
  1402.         .cDims = 1
  1403.         .pvData = VarPtr(CompressedArray(0))
  1404.         .rgSABound(0).cElements = UBound(CompressedArray) + 1&
  1405.     End With
  1406.     CopyMemory ByVal VarPtrArray(inStream), VarPtr(tSAIN), 4&
  1407.     
  1408.     'InStream = ByteArray
  1409.     Call vbInit_Decompress
  1410.     Inpos = 2&
  1411.     Do
  1412.         IsLastBlock = vbGetBits(1)    ' last compressed block?
  1413.         CompType = vbGetBits(2)       ' compression type used for block
  1414.         If CompType = 0& Then
  1415.             If Inpos + 4& > UBound(inStream) Then
  1416.                 ' ensure 4 more bytes exist for L1 and L2 below
  1417.                 lRtn = -1&
  1418.                 Exit Do
  1419.             End If
  1420.         
  1421.             If BitNum >= 8& Then
  1422.                 Inpos = Inpos - (BitNum  8&)
  1423.                 BitNum = BitNum - ((BitNum  8&) * 8&)
  1424.             End If
  1425.             
  1426.             L1 = inStream(Inpos) Or (inStream(Inpos + 1&) * &H100&)
  1427.             L2 = inStream(Inpos + 2&) Or (inStream(Inpos + 3&) * &H100&)
  1428.             
  1429.             Inpos = Inpos + 4&
  1430.             If L1 - (Not (L2) And &HFFFF&) Then
  1431.                 lRtn = -2&
  1432.                 Exit Do
  1433.             End If
  1434.             If Inpos + L1 - 1& > UBound(inStream) Then
  1435.                 lRtn = -1&
  1436.                 Exit Do
  1437.             End If
  1438.             
  1439.             If OutPos + L1 > UncompressedSize Then
  1440.                 lRtn = -1&
  1441.                 Exit Do
  1442.             End If
  1443.             
  1444.             CopyMemory outStream(OutPos), inStream(Inpos), L1
  1445.             OutPos = OutPos + L1
  1446.             Inpos = Inpos + L1
  1447.             ByteBuff = 0&
  1448.             BitNum = 0&
  1449.             
  1450.         ElseIf CompType = 3& Then
  1451.             lRtn = -1&
  1452.             Exit Do
  1453.             
  1454.         Else
  1455.             If CompType = 1& Then
  1456.                 If Not vbCreate_Static_Tree(MinLLength, MaxLLength, MinDLength, MaxDLength, IsStaticBuild) = 0& Then
  1457.                     lRtn = 9&
  1458.                     Exit Do
  1459.                 End If
  1460.             Else
  1461.                 If Not vbCreate_Dynamic_Tree(MinLLength, MaxLLength, MinDLength, MaxDLength) = 0& Then
  1462.                     lRtn = 9&
  1463.                     Exit Do
  1464.                 End If
  1465.             End If
  1466.  
  1467.             Do
  1468.                 vbNeedBits MaxLLength
  1469.                 Nubits = MinLLength
  1470.                 Do While Not LitLen.Length(ByteBuff And BitMask(Nubits)) = Nubits
  1471.                     Nubits = Nubits + 1&
  1472.                 Loop
  1473.  
  1474.                 Char = LitLen.code(ByteBuff And BitMask(Nubits))
  1475.                 vbDropBits Nubits
  1476.                 
  1477.                 If Char < 256& Then
  1478.                     outStream(OutPos) = Char
  1479.                     OutPos = OutPos + 1&
  1480.                     
  1481.                 ElseIf Char > 256& Then
  1482.                     Char = Char - 257&
  1483.                     L1 = LCodes.code(Char) + vbGetBits(LCodes.Length(Char))
  1484.                     If (L1 = 258&) And ZIP64 Then L1 = vbGetBits(16) + 3&
  1485.                     vbNeedBits MaxDLength
  1486.                     Nubits = MinDLength
  1487.                     Do While Not Dist.Length(ByteBuff And BitMask(Nubits)) = Nubits
  1488.                         Nubits = Nubits + 1&
  1489.                     Loop
  1490.  
  1491.                     Char = Dist.code(ByteBuff And BitMask(Nubits))
  1492.                     vbDropBits Nubits
  1493.                     L2 = DCodes.code(Char) + vbGetBits(DCodes.Length(Char))
  1494.     
  1495.                     For X = 1& To L1
  1496.                         If OutPos > UncompressedSize Then
  1497.                             OutPos = UncompressedSize
  1498.                             GoTo Stop_Decompression
  1499.                         End If
  1500.                          outStream(OutPos) = outStream(OutPos - L2)
  1501.                          OutPos = OutPos + 1&
  1502.                     Next X
  1503.                 
  1504.                 End If
  1505.             Loop While Not Char = 256& 'EOF
  1506.         End If
  1507.     Loop While Not IsLastBlock
  1508.     
  1509. Stop_Decompression:
  1510. CopyMemory ByVal VarPtrArray(inStream), 0&, 4&
  1511. Erase BitMask
  1512. Erase Pow2
  1513. Erase LCodes.code
  1514. Erase LCodes.Length
  1515. Erase DCodes.code
  1516. Erase DCodes.Length
  1517. Erase LitLen.code
  1518. Erase LitLen.Length
  1519. Erase Dist.code
  1520. Erase Dist.Length
  1521. Erase LenOrder
  1522. If Err Then
  1523.     lRtn = Err.Number
  1524.     Err.Clear
  1525. End If
  1526. vbDecompress = (lRtn = 0&)
  1527. End Function
  1528. Private Function vbCreate_Static_Tree(MinLLength As Long, MaxLLength As Long, MinDLength As Long, MaxDLength As Long, IsStaticBuild As Boolean) As Long
  1529.     Dim X As Long
  1530.     Dim Length(0 To 287) As Long
  1531.     If IsStaticBuild = False Then
  1532.         ' quick fill the tree (tile Blt)
  1533.         For X = 0& To 7&: Length(X) = 8&: Next ' 0 to 143 elements = 8
  1534.         For X = X To 143& Step 8&
  1535.             CopyMemory Length(X), Length(0), 32&
  1536.         Next
  1537.         For X = X To X + 7&: Length(X) = 9&: Next ' 144 to 255 elements = 9
  1538.         For X = X To 255& Step 8&
  1539.             CopyMemory Length(X), Length(144), 32&
  1540.         Next
  1541.         For X = X To X + 7&: Length(X) = 7&: Next ' 256 to 279 elements = 7
  1542.         For X = X To 279& Step 8&
  1543.             CopyMemory Length(X), Length(256), 32&
  1544.         Next
  1545.         For X = X To X + 3&: Length(X) = 8&: Next ' 280 to 287 elements = 8
  1546.         CopyMemory Length(X), Length(280), 16&
  1547.         
  1548.         If Not vbCreate_Codes(TempLit, Length, 287&, MaxLLength, MinLLength) = 0& Then
  1549.              vbCreate_Static_Tree = -1&
  1550.             Exit Function
  1551.         End If
  1552.         
  1553.         For X = 0& To 7&: Length(X) = 5&: Next  ' reset 0 to 32 to 5's
  1554.         For X = X To 31& Step 8&
  1555.             CopyMemory Length(X), Length(0), 32&
  1556.         Next
  1557.         vbCreate_Static_Tree = vbCreate_Codes(TempDist, Length, 31&, MaxDLength, MinDLength)
  1558.         IsStaticBuild = True
  1559.         
  1560.     Else
  1561.         MinLLength = 7&
  1562.         MaxLLength = 9&
  1563.         MinDLength = 5&
  1564.         MaxDLength = 5&
  1565.     End If
  1566.     LitLen = TempLit
  1567.     Dist = TempDist
  1568. End Function
  1569. Private Function vbCreate_Dynamic_Tree(MinLLength As Long, MaxLLength As Long, MinDLength As Long, MaxDLength As Long) As Long
  1570.     Dim Length() As Long
  1571.     Dim Bl_Tree As CodesType
  1572.     Dim MinBL As Long
  1573.     Dim MaxBL As Long
  1574.     Dim NumLen As Long
  1575.     Dim Numdis As Long
  1576.     Dim NumCod As Long
  1577.     Dim Char As Long
  1578.     Dim Nubits As Long
  1579.     Dim LN As Long
  1580.     Dim Pos As Long
  1581.     Dim X As Long
  1582.     NumLen = vbGetBits(5) + 257&
  1583.     Numdis = vbGetBits(5) + 1&
  1584.     NumCod = vbGetBits(4) + 4&
  1585.     ReDim Length(18)
  1586.     For X = 0& To NumCod - 1&
  1587.         Length(LenOrder(X)) = vbGetBits(3)
  1588.     Next
  1589.     For X = NumCod To 18&
  1590.         Length(LenOrder(X)) = 0&
  1591.     Next
  1592.     If Not vbCreate_Codes(Bl_Tree, Length, 18&, MaxBL, MinBL) = 0& Then
  1593.         vbCreate_Dynamic_Tree = -1&
  1594.         Exit Function
  1595.     End If
  1596.     
  1597.     ReDim Length(NumLen + Numdis)
  1598.     Pos = 0&
  1599.     Do While Pos < NumLen + Numdis
  1600.         vbNeedBits MaxBL
  1601.         Nubits = MinBL
  1602.         
  1603.         Do While Not Bl_Tree.Length(ByteBuff And BitMask(Nubits)) = Nubits
  1604.              Nubits = Nubits + 1&
  1605.         Loop
  1606.         Char = Bl_Tree.code(ByteBuff And BitMask(Nubits))
  1607.         vbDropBits Nubits
  1608.         If Char < 16& Then
  1609.             Length(Pos) = Char
  1610.             Pos = Pos + 1&
  1611.         Else
  1612.             If Char = 16& Then
  1613.                 If Pos = 0& Then
  1614.                     vbCreate_Dynamic_Tree = -5&
  1615.                     Exit Function
  1616.                 End If
  1617.                 LN = Length(Pos - 1&)
  1618.                 Char = 3& + vbGetBits(2)
  1619.             ElseIf Char = 17 Then
  1620.                  Char = 3& + vbGetBits(3)
  1621.                  LN = 0&
  1622.             Else
  1623.                 Char = 11& + vbGetBits(7)
  1624.                 LN = 0&
  1625.             End If
  1626.             If Pos + Char > NumLen + Numdis Then
  1627.                 vbCreate_Dynamic_Tree = -6&
  1628.                 Exit Function
  1629.             End If
  1630.             Do While Char > 0&
  1631.                 Char = Char - 1&
  1632.                 Length(Pos) = LN
  1633.                 Pos = Pos + 1&
  1634.             Loop
  1635.         End If
  1636.     Loop
  1637.     If Not vbCreate_Codes(LitLen, Length, NumLen - 1, MaxLLength, MinLLength) = 0& Then
  1638.         vbCreate_Dynamic_Tree = -1&
  1639.         Exit Function
  1640.     End If
  1641.     For X = 0& To Numdis
  1642.         Length(X) = Length(X + NumLen)
  1643.     Next
  1644.     
  1645.     vbCreate_Dynamic_Tree = vbCreate_Codes(Dist, Length, Numdis - 1&, MaxDLength, MinDLength)
  1646. End Function
  1647. Private Function vbCreate_Codes(tree As CodesType, Lengths() As Long, NumCodes As Long, MaxBits As Long, Minbits As Long) As Long
  1648.     
  1649.     Dim Bits(16) As Long
  1650.     Dim next_code(16) As Long
  1651.     Dim code As Long
  1652.     Dim LN As Long
  1653.     Dim X As Long
  1654.     Minbits = 16&
  1655.     For X = 0& To NumCodes
  1656.         Bits(Lengths(X)) = Bits(Lengths(X)) + 1&
  1657.         If Lengths(X) > MaxBits Then MaxBits = Lengths(X)
  1658.         If Lengths(X) < Minbits And Lengths(X) > 0& Then Minbits = Lengths(X)
  1659.     Next
  1660.     LN = 1&
  1661.     For X = 1& To MaxBits
  1662.         LN = LN + LN
  1663.         LN = LN - Bits(X)
  1664.         If LN < 0& Then
  1665.             vbCreate_Codes = LN
  1666.             Exit Function
  1667.         End If
  1668.     Next
  1669.     vbCreate_Codes = LN
  1670.     ReDim tree.code(2& ^ MaxBits - 1&)
  1671.     ReDim tree.Length(2& ^ MaxBits - 1&)
  1672.     code = 0&
  1673.     Bits(0) = 0&
  1674.     
  1675.     For X = 1& To MaxBits
  1676.         code = (code + Bits(X - 1&)) * 2&
  1677.         next_code(X) = code
  1678.     Next
  1679.     For X = 0& To NumCodes
  1680.         LN = Lengths(X)
  1681.         If Not LN = 0& Then
  1682.             code = vbBit_Reverse(next_code(LN), LN)
  1683.             tree.Length(code) = LN
  1684.             tree.code(code) = X
  1685.             next_code(LN) = next_code(LN) + 1&
  1686.         End If
  1687.     Next
  1688. End Function
  1689. Private Function vbBit_Reverse(ByVal Value As Long, ByVal Numbits As Long) As Long
  1690.     Do While Numbits > 0&
  1691.         vbBit_Reverse = vbBit_Reverse * 2& + (Value And 1&)
  1692.         Numbits = Numbits - 1&
  1693.         Value = Value  2&
  1694.     Loop
  1695.     
  1696. End Function
  1697. Private Sub vbInit_Decompress()
  1698.     
  1699.     Dim Temp()
  1700.     Dim X As Long
  1701.     Erase LitLen.code
  1702.     Erase LitLen.Length
  1703.     Erase Dist.code
  1704.     Erase Dist.Length
  1705.     ReDim LCodes.code(31)
  1706.     ReDim LCodes.Length(31)
  1707.     ReDim DCodes.code(31)
  1708.     ReDim DCodes.Length(31)
  1709.     ReDim LenOrder(0 To 18)
  1710.     Temp() = Array(16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15)
  1711.     For X = 0 To UBound(Temp): LenOrder(X) = Temp(X): Next
  1712.      Temp() = Array(3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258)
  1713.     For X = 0 To UBound(Temp): LCodes.code(X) = Temp(X): Next
  1714.      Temp() = Array(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0)
  1715.     For X = 0 To UBound(Temp): LCodes.Length(X) = Temp(X): Next
  1716.      Temp() = Array(1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 32769, 49153)
  1717.     For X = 0 To UBound(Temp): DCodes.code(X) = Temp(X): Next
  1718.      Temp() = Array(0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14)
  1719.     For X = 0 To UBound(Temp): DCodes.Length(X) = Temp(X): Next
  1720.     
  1721.     ReDim Pow2(0 To 16)
  1722.     ReDim BitMask(0 To 16)
  1723.     Pow2(0) = 1&
  1724.     For X = 1& To 16&
  1725.      Pow2(X) = Pow2(X - 1&) * 2&
  1726.      BitMask(X) = Pow2(X) - 1&
  1727.     Next
  1728.     OutPos = 0&
  1729.     Inpos = 0&
  1730.     ByteBuff = 0&
  1731.     BitNum = 0&
  1732. End Sub
  1733. Private Sub vbNeedBits(Numbits As Long)
  1734.     Do While BitNum < Numbits
  1735.         If Inpos > UBound(inStream) Then Exit Do
  1736.         ByteBuff = ByteBuff + (inStream(Inpos) * Pow2(BitNum))
  1737.         BitNum = BitNum + 8&
  1738.         Inpos = Inpos + 1&
  1739.     Loop
  1740. End Sub
  1741. Private Sub vbDropBits(Numbits As Long)
  1742.     ByteBuff = ByteBuff  Pow2(Numbits)
  1743.     BitNum = BitNum - Numbits
  1744. End Sub
  1745. Private Function vbGetBits(Numbits As Long) As Long
  1746.     
  1747.     While BitNum < Numbits
  1748.         ByteBuff = ByteBuff + (inStream(Inpos) * Pow2(BitNum))
  1749.         BitNum = BitNum + 8&
  1750.         Inpos = Inpos + 1&
  1751.     Wend
  1752.     vbGetBits = ByteBuff And BitMask(Numbits)
  1753.     ByteBuff = ByteBuff  Pow2(Numbits)
  1754.     BitNum = BitNum - Numbits
  1755. End Function
  1756. ' =======================================
  1757. ' FOLLOWING 3 FUNCTIONS ARE ZLIB RELATED
  1758. ' =======================================
  1759. Private Function zValidateZLIBversion() As Boolean
  1760.     ' Test for zlib availability & compatibility
  1761.     ' see modParsers.iparseValidateZLib for details
  1762.     
  1763.     Dim b_cdecl As Boolean, DllName As String
  1764.     
  1765.     If iparseValidateZLIB(DllName, m_ZLIBver, b_cdecl, False) = True Then
  1766.         If b_cdecl = True Then
  1767.             Set cCfunction = New cCDECL
  1768.             cCfunction.DllLoad DllName
  1769.         End If
  1770.         zValidateZLIBversion = True
  1771.     End If
  1772.             
  1773.     
  1774. End Function
  1775. Private Function zCheckCRCvalue(ByVal crcTestRef As Long, ByVal valLength As Long, ByVal srcCRCvalue As Long) As Boolean
  1776.     ' function returns zLIB's CRC value for passed crcTestRef value.
  1777.     Dim lReturn As Long
  1778.     If cCfunction Is Nothing Then
  1779.         If m_ZLIBver = 1& Then
  1780.             lReturn = Zcrc32(0&, ByVal crcTestRef, valLength)
  1781.         ElseIf m_ZLIBver = 2& Then
  1782.             lReturn = Zcrc321(0&, ByVal crcTestRef, valLength)
  1783.         End If
  1784.     Else
  1785.         lReturn = cCfunction.CallFunc("crc32", 0&, crcTestRef, valLength)
  1786.     End If
  1787.     If Not lReturn = 0& Then
  1788.         zCheckCRCvalue = (srcCRCvalue = iparseReverseLong(lReturn))
  1789.     End If
  1790.     
  1791. End Function
  1792. Private Function zInflate(ByVal srcRef As Long, ByVal srcSizeRef As Long, ByVal destRef As Long, ByVal destSize As Long) As Boolean
  1793.     ' function uncompresses/inflates passed srcRef into passed destRef and modifies the destSizeRef to indicate byte count of destRef
  1794.     Dim lReturn As Long
  1795.     If cCfunction Is Nothing Then
  1796.         If m_ZLIBver = 1& Then
  1797.             zInflate = (Zuncompress(ByVal srcRef, ByVal srcSizeRef, ByVal destRef, destSize) = 0&)
  1798.         ElseIf m_ZLIBver = 2& Then
  1799.             zInflate = (Zuncompress1(ByVal srcRef, ByVal srcSizeRef, ByVal destRef, destSize) = 0&)
  1800.         End If
  1801.     Else
  1802.         zInflate = (cCfunction.CallFunc("uncompress", srcRef, srcSizeRef, destRef, destSize) = 0&)
  1803.     End If
  1804. End Function