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

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 = "c32bppDIB"
  10. Attribute VB_GlobalNameSpace = False
  11. Attribute VB_Creatable = True
  12. Attribute VB_PredeclaredId = False
  13. Attribute VB_Exposed = False
  14. Option Explicit
  15. ' Credits/Acknowledgements - Thanx goes to:
  16. '   Paul Caton for his class on calling non VB-Friendly DLLs that use _cdecl calling convention
  17. '       Used when calling non VB-friendly zLIB dll versions
  18. '   Alfred Koppold for his PNG, VB-only, decompression routines.
  19. '       Used when zLib & GDI+ not available
  20. '   Carles P.V for his pvResize logic
  21. '       Used when manually scaling images with NearestNeighbor or BiLinear interpolation
  22. '   www.zlib.net for their free zLIB.dll, the standard DLL for compressing/decompressing PNGs
  23. '       Without it, we'd be limited to GDI+ for creating PNGs
  24. '   coders like you that provide constructive criticism to make this class better & more all-inclusive
  25. '       Without your comments, this project probably would have died several versions/updates ago
  26. ' For most current updates/enhancements visit the following:
  27. '   Visit http://www.planetsourcecode.com/vb/scripts/ShowCode.asp?txtCodeId=67466&lngWId=1
  28. ' NOTE: ALL CLASSES AND MODULES WITHIN THIS CONTROL MAY HAVE BEEN MODIFIED AND SOME
  29. '       ROUTINES REMOVED.  THEREFORE COMMENTS MAY APPEAR REFERENCING ROUTINES THAT DO NOT EXIST
  30. '       FOR THE COMPLETE UP TO DATE VERSIONS OF THESE CLASSES VISIT:
  31. '       http://www.planetsourcecode.com/vb/scripts/ShowCode.asp?txtCodeId=67466&lngWId=1
  32. ' = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  33. '                                    O V E R V I E W
  34. ' = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  35. ' About 32bpp pre-multiplied RGB (pARGB) bitmaps, if you are not aware.
  36. '   - These are used specifically for the AlphaBlend API & are GDI+ compatible
  37. '   Advantages:
  38. '       - Images can be per-pixel alpha blended
  39. '       - Opacity can be simultaneously adjusted during rendering
  40. '       - AlphaBlend does both BitBlt & StretchBlt for pARGB images.
  41. '       - Speed: AlphaBlend & GDI+ are pretty quick APIs vs manual blending
  42. '   Disadvantages:
  43. '       - The original RGB values are permanently destroyed during pre-multiplying
  44. '           -- Premultiplied formula: preMultipliedRed=(OriginalRed * Alpha)  255
  45. '           -- There is no way to convert pARGB back to non-premultiplied RGB values
  46. '              The formula would be: reconstructedRed=(preMultipliedRed * 255)  Alpha.
  47. '               but because of integer division when pre-multiplying, the result is only
  48. '               close and if this should be premultiplied again & converted again, the
  49. '               alphas can get more transparent with every iteration.
  50. '               Fully opaque pixels & fully transparent pixels are not affected.
  51. '           ** Note: When images are converted to PNG formats, removal of
  52. '              premultiplication is performed to meet PNG specs.
  53. '       - Displaying a pre-multiplied bitmap without AlphaBlend will not result in
  54. '           the image being displayed as expected.
  55. '       - Not ideal for saving due to its size: SizeOf= W x H x 4
  56. '           -- better to save source image instead or compress the DIB bytes using favorite compression utility
  57. '           -- with GDI+ or zLib, image can be converted to PNG for storage
  58. '       - AlphaBlend (msimg32.dll) is not included/compatible with Win95, NT4 and lower
  59. '       - AlphaBlend on Win9x systems can be buggy, especially when rendering to DIBs vs DDBs
  60. ' Note that GDI+ is standard on WinXP+, and can be used on Win98,ME,2K, & on NT4 if SP6 is installed
  61. ' Download GDI+ from:
  62. ' http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdicpp/GDIPlus/GDIPlus.asp
  63. ' ----------------------------------------------
  64. ' About Win95, Win98, NT3.5, NT4 & WinME support
  65. ' ----------------------------------------------
  66. ' The routines will not honor AlphaBlend if it exists on those systems. Win98's version,
  67. ' for example, has several bugs that can crash the application when AlphaBlending to DIBs.
  68. ' NT4, NT3.5 & Win95 do not come with AlphaBlend and I do not have WinME to test with.
  69. ' Therefore, to support these systems, the Render routine will alphablend manually
  70. ' regardless if the AlhpaBlend API (msimg32.dll) exists on the system or not.
  71. ' However, this can be overridden by you. See isAlphaBlendFriendly routine
  72. ' Class Purpose:
  73. ' ----------------------------------------------
  74. ' This class holds the 32bpp image. It also marshals any new image thru
  75. ' the battery of parsers to determine best method for converting the image
  76. ' to a 32bpp alpha-compatible image. It handles rendering, rotating, scaling,
  77. ' mirroring of DIBs using manual processes, AlphaBlend, and/or GDI+.
  78. ' The parser order is very important for fastest/best results...
  79. ' cPNGparser :: will convert PNG, all bit depths; aborts quickly if not PNG
  80. ' cGIFparser :: will convert non-transparent/transparent GIFs; aborts quickly
  81. ' cICOpraser :: will convert XP-Alpha, paletted, true color, & Vista PNG icons
  82. '               -- can also convert most non-animated cursors
  83. ' cBMPparser :: will convert bitmaps, wmf/emf & jpgs
  84. ' The parsers are efficient. Most image formats have a magic number that give
  85. '   a hint to what type of image the file/stream is. However, checks need to
  86. '   be employed because non-image files could feasibly have those same magic
  87. '   numbers. If the image is determined not to be one the parser is designed
  88. '   to handle, the parser rejects it and the next parser takes over.  The
  89. '   icon parser is slightly different because PNG files can be included into
  90. '   a Vista ico file. When this occurs, the icon parser will pass off the
  91. '   PNG format to the PNG parser automatically.
  92. ' And last but not least, the parsers have no advanced knowledge of the image
  93. ' format; as far as they are concerned, anything passed is just a byte array
  94. ' = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  95. '                                       CHANGE HISTORY
  96. ' = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  97. ' Accompanying FAQ.rtf is updated with every change
  98. ' Last changed: 11 Apr 07. See change history within the FAQ file
  99. ' 26 Dec 06: First version
  100. ' = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  101. ' No APIs are declared public. This is to prevent possibly, differently
  102. ' declared APIs, or different versions of the same API, from conflciting
  103. ' with any APIs you declared in your project. Same rule for UDTs.
  104. ' Note: I did take liberties, changing parameter types, in several APIs throughout
  105. ' Used to determine operating system
  106. Private Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" (lpVersionInformation As Any) As Long
  107. Private Type OSVERSIONINFOEX
  108.    dwOSVersionInfoSize As Long
  109.    dwMajorVersion As Long
  110.    dwMinorVersion As Long
  111.    dwBuildNumber As Long
  112.    dwPlatformId As Long
  113.    szCSDVersion As String * 128 ' up to here is OSVERSIONINFO vs EX
  114.    wServicePackMajor As Integer ' 8 bytes larger than OSVERSIONINFO
  115.    wServicePackMinor As Integer
  116.    wSuiteMask As Integer
  117.    wProductType As Byte
  118.    wReserved As Byte
  119. End Type
  120. ' APIs used to manage the 32bpp DIB
  121. Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
  122. Private Declare Sub FillMemory Lib "kernel32.dll" Alias "RtlFillMemory" (ByRef Destination As Any, ByVal Length As Long, ByVal Fill As Byte)
  123. Private Declare Function CreateCompatibleDC Lib "gdi32.dll" (ByVal hDC As Long) As Long
  124. Private Declare Function GetDC Lib "user32.dll" (ByVal hwnd As Long) As Long
  125. Private Declare Function ReleaseDC Lib "user32.dll" (ByVal hwnd As Long, ByVal hDC As Long) As Long
  126. Private Declare Function DeleteDC Lib "gdi32.dll" (ByVal hDC As Long) As Long
  127. Private Declare Function SelectObject Lib "gdi32.dll" (ByVal hDC As Long, ByVal hObject As Long) As Long
  128. Private Declare Function DeleteObject Lib "gdi32.dll" (ByVal hObject As Long) As Long
  129. Private Declare Function CreateDIBSection Lib "gdi32.dll" (ByVal hDC As Long, ByRef pBitmapInfo As Any, ByVal un As Long, ByRef Pointer As Long, ByVal Handle As Long, ByVal dw As Long) As Long
  130. Private Declare Function AlphaBlend Lib "msimg32.dll" (ByVal hdcDest As Long, ByVal nXOriginDest As Long, ByVal nYOriginDest As Long, ByVal nWidthDest As Long, ByVal nHeightDest As Long, ByVal hdcSrc As Long, ByVal nXOriginSrc As Long, ByVal nYOriginSrc As Long, ByVal nWidthSrc As Long, ByVal nHeightSrc As Long, ByVal lBlendFunction As Long) As Long
  131. Private Declare Function SetStretchBltMode Lib "gdi32.dll" (ByVal hDC As Long, ByVal nStretchMode As Long) As Long
  132. Private Declare Function GetObjectType Lib "gdi32.dll" (ByVal hgdiobj As Long) As Long
  133. Private Declare Function GetCurrentObject Lib "gdi32.dll" (ByVal hDC As Long, ByVal uObjectType As Long) As Long
  134. Private Declare Function GetIconInfo Lib "user32.dll" (ByVal hIcon As Long, ByRef piconinfo As ICONINFO) As Long
  135. Private Declare Function BitBlt Lib "gdi32.dll" (ByVal hDestDC As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
  136. Private Declare Function SetDIBitsToDevice Lib "gdi32.dll" (ByVal hDC As Long, ByVal X As Long, ByVal Y As Long, ByVal dX As Long, ByVal dY As Long, ByVal SrcX As Long, ByVal SrcY As Long, ByVal Scan As Long, ByVal NumScans As Long, ByRef Bits As Any, ByRef BitsInfo As BITMAPINFO, ByVal wUsage As Long) As Long
  137. Private Declare Function GetDIBits Lib "gdi32.dll" (ByVal aHDC As Long, ByVal hBitmap As Long, ByVal nStartScan As Long, ByVal nNumScans As Long, ByRef lpBits As Any, ByRef lpBI As BITMAPINFO, ByVal wUsage As Long) As Long
  138. Private Declare Function OffsetRgn Lib "gdi32.dll" (ByVal hRgn As Long, ByVal X As Long, ByVal Y As Long) As Long
  139. Private Const STRETCH_HALFTONE As Long = &H4&
  140. Private Const OBJ_BITMAP As Long = &H7&
  141. Private Const OBJ_METAFILE As Long = &H9&
  142. Private Const OBJ_ENHMETAFILE As Long = &HD&
  143. ' APIs used to create files
  144. Private Declare Function WriteFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, lpOverlapped As Any) As Long
  145. Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
  146. Private Declare Function GetFileSize Lib "kernel32.dll" (ByVal hFile As Long, ByRef lpFileSizeHigh As Long) As Long
  147. 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
  148. 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
  149. Private Const INVALID_HANDLE_VALUE = -1&
  150. ' ////////////////////////////////////////////////////////////////
  151. ' Unicode-capable Drag and Drop of file names with wide characters
  152. ' ////////////////////////////////////////////////////////////////
  153. Private Declare Function DispCallFunc Lib "oleaut32" (ByVal pvInstance As Long, _
  154.     ByVal offsetinVft As Long, ByVal CallConv As Long, ByVal retTYP As VbVarType, _
  155.     ByVal paCNT As Long, ByRef paTypes As Integer, _
  156.     ByRef paValues As Long, ByRef retVAR As Variant) As Long
  157. Private Declare Function lstrlenW Lib "kernel32.dll" (lpString As Any) As Long
  158. Private Declare Function GlobalFree Lib "kernel32.dll" (ByVal hMem As Long) As Long
  159. ' ////////////////////////////////////////////////////////////////
  160. ' Unicode-capable Pasting of file names with wide characters
  161. ' ////////////////////////////////////////////////////////////////
  162. Private Declare Function DragQueryFile Lib "shell32.dll" Alias "DragQueryFileA" (ByVal hDrop As Long, ByVal UINT As Long, ByVal lpStr As String, ByVal ch As Long) As Long
  163. Private Declare Function OpenClipboard Lib "user32.dll" (ByVal hwnd As Long) As Long
  164. Private Declare Function GetClipboardData Lib "user32.dll" (ByVal wFormat As Long) As Long
  165. Private Declare Function CloseClipboard Lib "user32.dll" () As Long
  166. ' ////////////////////////////////////////////////////////////////
  167. Private Type FORMATETC
  168.     cfFormat As Long
  169.     pDVTARGETDEVICE As Long
  170.     dwAspect As Long
  171.     lIndex As Long
  172.     TYMED As Long
  173. End Type
  174. Private Type DROPFILES
  175.     pFiles As Long
  176.     ptX As Long
  177.     ptY As Long
  178.     fNC As Long
  179.     fWide As Long
  180. End Type
  181. Private Type STGMEDIUM
  182.     TYMED As Long
  183.     Data As Long
  184.     pUnkForRelease As IUnknown
  185. End Type
  186. ' used to create the checkerboard pattern on demand
  187. Private Declare Function FillRect Lib "user32.dll" (ByVal hDC As Long, ByRef lpRect As RECT, ByVal hBrush As Long) As Long
  188. Private Declare Function CreateSolidBrush Lib "gdi32.dll" (ByVal crColor As Long) As Long
  189. Private Declare Function OffsetRect Lib "user32.dll" (ByRef lpRect As RECT, ByVal X As Long, ByVal Y As Long) As Long
  190. Private Type RECT
  191.     Left As Long
  192.     Top As Long
  193.     Right As Long
  194.     Bottom As Long
  195. End Type
  196. ' used when saving an image or part of the image
  197. Private Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (Ptr() As Any) As Long
  198. Private Type SafeArrayBound
  199.     cElements As Long
  200.     lLbound As Long
  201. End Type
  202. Private Type SafeArray
  203.     cDims As Integer
  204.     fFeatures As Integer
  205.     cbElements As Long
  206.     cLocks As Long
  207.     pvData As Long
  208.     rgSABound(0 To 1) As SafeArrayBound ' reusable UDT for 1 & 2 dim arrays
  209. End Type
  210. Private Type ICONINFO
  211.     fIcon As Long
  212.     xHotspot As Long
  213.     yHotspot As Long
  214.     hbmMask As Long
  215.     hbmColor As Long
  216. End Type
  217. Private Type BITMAPINFOHEADER
  218.     biSize As Long
  219.     biWidth As Long
  220.     biHeight As Long
  221.     biPlanes As Integer
  222.     biBitCount As Integer
  223.     biCompression As Long
  224.     biSizeImage As Long
  225.     biXPelsPerMeter As Long
  226.     biYPelsPerMeter As Long
  227.     biClrUsed As Long
  228.     biClrImportant As Long
  229. End Type
  230. Private Type BITMAPINFO
  231.     bmiHeader As BITMAPINFOHEADER
  232.     bmiPalette As Long
  233. End Type
  234. Private Const AC_SRC_OVER = &H0&
  235. Private Const AC_SRC_ALPHA = &H1&
  236. Public Enum eImageFormat    ' source image format
  237.     imgError = -1  ' no DIB has been initialized
  238.     imgNone = 0    ' no image loaded
  239.     imgBitmap = 1  ' standard bitmap or jpg
  240.     imgIcon = 3    ' standard icon
  241.     imgWMF = 2     ' windows meta file
  242.     imgEMF = 4     ' enhanced WMF
  243.     imgCursor = 5  ' standard cursor
  244.     imgBmpARGB = 6  ' 32bpp bitmap where RGB is not pre-multiplied
  245.     imgBmpPARGB = 7 ' 32bpp bitmap where RGB is pre-multiplied
  246.     imgIconARGB = 8 ' XP-type icon; 32bpp ARGB
  247.     imgGIF = 9      ' gif; if class.Alpha=True, then transparent GIF
  248.     imgPNG = 10     ' PNG image
  249.     imgPNGicon = 11 ' PNG in icon file (Vista)
  250.     imgCursorARGB = 12 ' alpha blended cursors? do they exist yet?
  251.     imgCheckerBoard = 64 ' image is displaying own checkerboard pattern; no true image
  252. End Enum
  253. Public Enum ePngProperties ' following are recognized "Captions" within a PNG file
  254.     txtTitle = 1           ' See cPNGwriter.SetPngProperty for more information
  255.     txtAuthor = 2
  256.     txtDescription = 4
  257.     txtCopyright = 8
  258.     txtCreationTime = 16
  259.     txtSoftware = 32
  260.     txtDisclaimer = 64
  261.     txtWarning = 128
  262.     txtSource = 256
  263.     txtComment = 512
  264.     ' special properties
  265.     txtLargeBlockText = 1024 ' this is free-form text can be of any length & contain most any characters
  266.     dateTimeModified = 2048  ' date/time of the last image modification (not the time of initial image creation)
  267.     colorDefaultBkg = 4096   ' default background color to use if PNG viewer does not do transparency
  268.     filterType = 8192        ' one of the eFilterMethods values
  269.     ClearAllProperties = -1  ' resets all PNG properties
  270. End Enum
  271. Public Enum eTrimOptions    ' see TrimImage method
  272.     trimAll = 0             ' can be combined using OR
  273.     trimLeft = 1
  274.     trimTop = 2
  275.     trimRight = 4
  276.     trimBottom = 8
  277. End Enum
  278. Public Enum eGrayScaleFormulas
  279.     gsclNTSCPAL = 0     ' R=R*.299, G=G*.587, B=B*.114 - Default
  280.     gsclCCIR709 = 1     ' R=R*.213, G=G*.715, B=B*.072
  281.     gsclSimpleAvg = 2   ' R,G, and B = (R+G+B)/3
  282.     gsclRedMask = 3     ' uses only the Red sample value: RGB = Red / 3
  283.     gsclGreenMask = 4   ' uses only the Green sample value: RGB = Green / 3
  284.     gsclBlueMask = 5    ' uses only the Blue sample value: RGB = Blue / 3
  285.     gsclRedGreenMask = 6 ' uses Red & Green sample value: RGB = (Red+Green) / 2
  286.     gsclBlueGreenMask = 7 ' uses Blue & Green sample value: RGB = (Blue+Green) / 2
  287.     gsclNone = -1
  288. End Enum
  289. Public Enum eFilterMethods
  290.     filterDefault = 0     ' paletted PNGs will use filterNone while others will use filterPaeth
  291.     filterNone = 1        ' no byte preparation used; else preps bytes using one of the following
  292.     filterAdjLeft = 2     ' see cPNGwriter.EncodeFilter_Sub
  293.     filterAdjTop = 3      ' see cPNGwriter.EncodeFilter_Up
  294.     filterAdjAvg = 4      ' see cPNGwriter.EncodeFilter_Avg
  295.     filterPaeth = 5       ' see cPNGwriter.EncodeFilter_Paeth
  296.     filterAdaptive = 6    ' this is a best guess of the above 4 (can be different for each DIB scanline)
  297. End Enum
  298. Public Enum eRegionStyles     ' See CreateRegion
  299.     regionBounds = 0
  300.     regionEnclosed = 1
  301.     regionShaped = 2
  302. End Enum
  303. Public Enum eConstants      ' See SourceIconSizes
  304.     TRUE_COLOR = &HFF000000
  305.     HIGH_COLOR = &HFFFF00
  306.     TRUE_COLOR_ALPHA = &HFFFFFFFF
  307. End Enum
  308. Private m_PNGprops As cPNGwriter    ' used for more advanced PNG creation options
  309. Private m_StretchQuality As Boolean ' if true will use BiLinear or better interpolation
  310. Private m_Handle As Long        ' handle to 32bpp DIB
  311. Private m_Pointer As Long       ' pointer to DIB bits
  312. Private m_Height As Long        ' height of DIB
  313. Private m_Width As Long         ' width of DIB
  314. Private m_hDC As Long           ' DC if self-managing one
  315. Private m_prevObj As Long       ' object deselected from DC when needed
  316. Private m_osCAP As Long         ' See Class_Initialize
  317. Private m_Format As eImageFormat ' type of source image
  318. Private m_ManageDC As Boolean   ' does class manage its own DC
  319. Private m_AlphaImage As Boolean ' does the DIB contain alpha/transparency
  320. Private m_GDItoken As Long
  321. Private m_ImageByteCache() As Byte  ' should you want the DIB class to cache original bytes
  322. ' ^^ N/A if image is loaded by handle, stdPicture, or resource
  323. Public Function LoadPicture_File(ByVal FileName As String, _
  324.                                 Optional ByVal iconCx As Long, _
  325.                                 Optional ByVal iconCy As Long, _
  326.                                 Optional ByVal SaveFormat As Boolean, _
  327.                                 Optional ByVal iconBitDepth As Long = 32) As Boolean
  328.     ' PURPOSE: Convert passed image file into a 32bpp image
  329.     
  330.     ' Parameters.
  331.     ' FileName :: full path of file. Validation occurs before we continue
  332.     ' iconCx :: desired width of icon if file is an icon file. Default is 32x32
  333.     ' iconCy :: desired height of icon if file is an icon file. Default is 32x32
  334.     ' SaveFormat :: if true, then the image will be cached as a byte array only
  335.     '   if the image was successfully loaded. Call GetOrginalFormat to retrieve them.
  336.     ' iconBitDepth :: the desired bit depth of an icon if the resource is an icon file
  337.     
  338.     ' Why would you want to save the bytes? If this is being used in a usercontrol,
  339.     ' saving the bytes will almost always be less size than saving the 32bit DIB.
  340.     ' Additionally, these classes have the ability to get different sizes from
  341.     ' the original source (i.e., WMF, icon, cursors) if available, but if the
  342.     ' 32bit DIB is saved, it is a constant size. The potential of different sizes
  343.     ' could allow better resizing of the image vs stretching the DIB.
  344.     On Error Resume Next
  345.     Dim hFile As Long
  346.     
  347.     hFile = iparseGetFileHandle(FileName, True, ((m_osCAP And 24) = 8))
  348.     If hFile = INVALID_HANDLE_VALUE Then Exit Function
  349.     
  350.     If GetFileSize(hFile, 0&) > 56 Then
  351.         
  352.         ' no image file/stream can be less than 57 bytes and still be an image
  353.         Dim aDIB() As Byte  ' dummy array
  354.         LoadPicture_File = LoadPictureEx(hFile, FileName, aDIB(), iconCx, iconCy, 0&, 0&, SaveFormat, iconBitDepth)
  355.     
  356.     End If
  357.     CloseHandle hFile
  358.     
  359. End Function
  360. Public Function LoadPicture_Stream(inStream() As Byte, _
  361.                                     Optional ByVal iconCx As Long, _
  362.                                     Optional ByVal iconCy As Long, _
  363.                                     Optional ByVal streamStart As Long = 0&, _
  364.                                     Optional ByVal streamLength As Long = 0&, _
  365.                                     Optional ByVal SaveFormat As Boolean, _
  366.                                     Optional ByVal iconBitDepth As Long = 32) As Boolean
  367.     
  368.     ' PURPOSE: Convert passed array into a 32bpp image
  369.     
  370.     ' Parameters.
  371.     ' inStream:: byte stream containing the image. Validation occurs below
  372.     ' iconCx :: desired width of icon if file is an icon file. Default is 32x32
  373.     ' iconCy :: desired height of icon if file is an icon file. Default is 32x32
  374.     ' streamStart :: array position of 1st byte of the image file. Validated.
  375.     ' streamLength :: total length of the image file. Validated.
  376.     ' SaveFormat :: if true, then the image will be cached as a byte array only
  377.     '   if the image was successfully loaded. Call GetOrginalFormat to retrieve them.
  378.     ' iconBitDepth :: the desired bit depth of an icon if the resource is an icon stream
  379.     
  380.     ' Why would you want to save the bytes? If this is being used in a usercontrol,
  381.     ' saving the bytes will almost always be less size than saving the 32bit DIB.
  382.     ' Additionally, these classes have the ability to get different sizes from
  383.     ' the original source (i.e., WMF, icon, cursors) if available, but if the
  384.     ' 32bit DIB is saved, it is a constant size. The potential of different sizes
  385.     ' could allow better resizing of the image vs stretching the DIB.
  386.     
  387.     If iparseIsArrayEmpty(VarPtrArray(inStream)) = 0& Then Exit Function
  388.     If streamStart < LBound(inStream) Then streamStart = LBound(inStream)
  389.     If streamLength = 0& Then streamLength = UBound(inStream) - streamStart + 1&
  390.     If streamLength < 57 Then Exit Function
  391.     ' no image file/stream can be less than 57 bytes and still be an image
  392.     LoadPicture_Stream = LoadPictureEx(0&, vbNullString, inStream, iconCx, iconCy, streamStart, streamLength, SaveFormat, iconBitDepth)
  393. End Function
  394. Public Function LoadPicture_Resource(ByVal ResIndex As Variant, ByVal ResSection As Variant, _
  395.                             Optional VBglobal As IUnknown, _
  396.                             Optional ByVal iconCx As Long, _
  397.                             Optional ByVal iconCy As Long, _
  398.                             Optional ByVal streamStart As Long = 0&, _
  399.                             Optional ByVal streamLength As Long = 0&, _
  400.                             Optional ByVal iconBitDepth As Long) As Boolean
  401.     ' PURPOSE: Convert passed resource into a 32bpp image
  402.     
  403.     ' Parameters.
  404.     ' ResIndex :: the resource file index (i.e., 101)
  405.     ' ResSection :: one of the VB LoadResConstants or String value of
  406.     '       your resource section, i.e., vbResBitmap, vbResIcon, "Custom", etc
  407.     ' VbGlobal :: pass as VB.GLOBAL of the project containing the resource file
  408.     '       - Allows class to be mobile; can exist in DLL or OCX
  409.     '       - if not provided, class will use resource from existing workspace
  410.     '       - For example, if this class was in a compiled OCX, then the only way
  411.     '           to use the host's resource file is passing the host's VB.Global reference
  412.     ' iconCx :: desired width of icon if file is an icon file. Default is 32x32
  413.     ' iconCy :: desired height of icon if file is an icon file. Default is 32x32
  414.     ' streamStart :: array position of 1st byte of the image file. Validated.
  415.     ' streamLength :: total length of the image file. Validated.
  416.     '   -- See LoadPicture_Stream for the validation
  417.     ' iconBitDepth :: the desired bit depth of an icon if the resource is an icon
  418.     
  419.     ' Tips:
  420.     ' 1) Store 32bpp bitmaps in the "Custom" resource always. Storing in the
  421.     '       Bitmap resource can change color depth of the image created by VB
  422.     '       depending on your screen settings
  423.     ' 2) Icons, normal bitmaps, & cursors are generally stored in their own sections
  424.     '       However, with icons containing multiple formats, VB will extract the
  425.     '       closest format to 32x32. May want to consider storing these in "Custom"
  426.     ' 3) All other types of images are normally stored in the "Custom" section
  427.     On Error GoTo ExitRoutine
  428.     
  429.     Dim oWorkSpace As VB.Global, tPic As StdPicture
  430.     
  431.     If VBglobal Is Nothing Then
  432.         Set oWorkSpace = VB.Global
  433.     ElseIf TypeOf VBglobal Is VB.Global Then
  434.         Set oWorkSpace = VBglobal
  435.     Else
  436.         Set oWorkSpace = VB.Global
  437.     End If
  438.     
  439.     If VarType(ResSection) = vbString Then
  440.         Dim inStream() As Byte
  441.         ' could be anything, PNG,icon,gif,32bpp bitmap,wmf, etc
  442.         inStream = oWorkSpace.LoadResData(ResIndex, ResSection)
  443.         LoadPicture_Resource = LoadPicture_Stream(inStream, iconCx, iconCy, streamStart, streamLength, , iconBitDepth)
  444.     Else
  445.         ' can only be single icon, bitmap or cursor
  446.         Set tPic = oWorkSpace.LoadResPicture(ResIndex, ResSection)
  447.         LoadPicture_StdPicture tPic
  448.     End If
  449.     LoadPicture_Resource = Not (m_Handle = 0&)
  450.     
  451. ExitRoutine:
  452.     If Err Then Err.Clear
  453. End Function
  454. Public Function LoadPicture_StdPicture(Picture As StdPicture) As Boolean
  455.     ' PURPOSE: Convert passed stdPicture into a 32bpp image
  456.     ' Revised to allow 32bpp stdPicture objects which can be loaded
  457.     
  458.     Me.DestroyDIB
  459.     If Not Picture Is Nothing Then
  460.         ' simply pass off to other parsers
  461.         If Picture.Type = vbPicTypeIcon Then
  462.             ' pass to icon/cursor parser
  463.             Dim cICO As New cICOparser
  464.             Call cICO.ConvertstdPicTo32bpp(Picture.Handle, Me)
  465.             Set cICO = Nothing
  466.         ElseIf Not Picture.Type = vbPicTypeNone Then
  467.             ' pass to bmp,jpg,wmf parser
  468.             ' Note: transparent GIFs should not be passed as stdPictures
  469.             '   Pass transparent GIFs by Stream or FileName
  470.             Dim cBMP As New cBMPparser
  471.             If Picture.Type = vbPicTypeBitmap Then
  472.                 ' pass by handle to ensure 32bpp stdPicture objects are processed correctly
  473.                 Call cBMP.ConvertstdPicTo32bpp(Nothing, Picture.Handle, Me, 0&)
  474.             Else ' probably wmf/emf, pass by stdPicture
  475.                 Call cBMP.ConvertstdPicTo32bpp(Picture, 0&, Me, 0&)
  476.             End If
  477.             Set cBMP = Nothing
  478.         End If
  479.         LoadPicture_StdPicture = Not (m_Handle = 0&)
  480.     End If
  481.     
  482. End Function
  483. Public Function LoadPicture_ByHandle(Handle As Long) As Boolean
  484.     ' PURPOSE: Convert passed image handle into a 32bpp image
  485.     ' Revised. Previously, I cheated by creating a stdPicture from the handle
  486.     '           then used existing LoadPicture_stdPicture to process. This had
  487.     '           the nasty side effect of not processing 32bpp images correctly
  488.     '           if they were loaded from LoadImage API
  489.     Dim icoInfo As ICONINFO, tPic As StdPicture
  490.     DestroyDIB
  491.     If Not Handle = 0& Then
  492.         Select Case GetObjectType(Handle)
  493.         Case OBJ_BITMAP
  494.             ' process bitmaps by handle
  495.             Dim cBMP As New cBMPparser
  496.             LoadPicture_ByHandle = cBMP.ConvertstdPicTo32bpp(Nothing, Handle, Me, 0&)
  497.         Case OBJ_METAFILE, OBJ_ENHMETAFILE
  498.             ' we should be able to convert this to a stdPicture...
  499.             ' Really don't want to mess with metafile DCs if I don't have to
  500.             Set tPic = iparseHandleToStdPicture(Handle, vbPicTypeBitmap)
  501.             If Not tPic Is Nothing Then
  502.                 ' send to this routine to process
  503.                 LoadPicture_ByHandle = LoadPicture_StdPicture(tPic)
  504.             End If
  505.         Case Else
  506.             ' Test for icons & cursors
  507.             If Not GetIconInfo(Handle, icoInfo) = 0 Then
  508.                 ' got it; clean up the bitmap(s) created by GetIconInfo API
  509.                 If Not icoInfo.hbmColor = 0& Then DeleteObject icoInfo.hbmColor
  510.                 If Not icoInfo.hbmMask = 0& Then DeleteObject icoInfo.hbmMask
  511.                 Dim cICO As New cICOparser
  512.                 ' process icons by handle
  513.                 LoadPicture_ByHandle = cICO.ConvertstdPicTo32bpp(Handle, Me)
  514.             End If
  515.         End Select
  516.     End If
  517.     
  518. End Function
  519. Public Function LoadPicture_ClipBoard() As Boolean
  520.     
  521.     ' PURPOSE: Convert clipboard object into a 32bpp image
  522.     On Error Resume Next
  523.     With Clipboard
  524.         If (.GetFormat(vbCFBitmap) Or .GetFormat(vbCFDIB) Or .GetFormat(vbCFEMetafile) Or .GetFormat(vbCFMetafile)) Then
  525.             If Not Err Then LoadPicture_ClipBoard = LoadPicture_StdPicture(.GetData())
  526.         End If
  527.     End With
  528.     If Err Then Err.Clear
  529. End Function
  530. Public Function LoadPicture_FromOrignalFormat(Optional ByVal iconCx As Long, _
  531.                             Optional ByVal iconCy As Long, _
  532.                             Optional ByVal iconBitDepth As Long) As Boolean
  533.     ' PURPOSE: Reload the current image from the cached bytes (if any)
  534.     ' If the original bytes were not cached when the image was loaded, then no action
  535.     ' will be taken.  See LoadPicture_File & LoadPicture_Stream
  536.     
  537.     ' iconCx :: desired width of icon if file is an icon file. Default is 32x32
  538.     ' iconCy :: desired height of icon if file is an icon file. Default is 32x32
  539.     ' iconBitDepth :: the desired bit depth of an icon if the resource is an icon
  540.     
  541.     Dim tBytes() As Byte
  542.     tBytes() = m_ImageByteCache() ' copy bytes; original are destroyed when DIB is recreated
  543.     LoadPicture_FromOrignalFormat = Me.LoadPicture_Stream(tBytes, iconCx, iconCy, , , True, iconBitDepth)
  544.     
  545. End Function
  546. Public Function GetPixel(ByVal X As Long, ByVal Y As Long, Optional ByRef AlphaValue As Long, _
  547.                             Optional ByRef asPreMultiplied As Boolean) As Long
  548.     ' Function will return the pixel color value and alpha value from the DIB
  549.     ' Note that the DIB is always referenced top down within this function
  550.     
  551.     ' X is the left coordinate of the pixel to be returned, image always starts at 0,0
  552.     ' Y is the top coordinate of the pixel to be returned, image always starts at 0,0
  553.     ' AlphaValue will contain the alpha value of the pixel.
  554.     ' asPreMultiplied. If false, then premultiplication is removed else it isn't
  555.     
  556.     ' Return value is the RGB color value of the pixel.
  557.     ' If return value is -1 then the X,Y coordinates passed are invalid
  558.     
  559.     ' It is far more efficient to use GetDIBits or overlaying your own array when more than
  560.     ' one pixel is required to be returned; in other words, recommend not using this
  561.     ' function within a loop
  562.     
  563.     AlphaValue = 0&
  564.     If X < 0& Or X > m_Width - 1& Then
  565.         GetPixel = -1&
  566.     ElseIf Y < 0& Or Y > m_Height - 1& Then
  567.         GetPixel = -1&
  568.     Else
  569.         Dim pOffset As Long, pColor As Long
  570.         ' calculate the location of the X,Y coordinate in relation to a bottom-up DIB
  571.         pOffset = iparseSafeOffset(m_Pointer, X * 4& + ((m_Height - Y - 1&) * m_Width * 4&))
  572.         
  573.         ' get the alpha value
  574.         CopyMemory AlphaValue, ByVal iparseSafeOffset(pOffset, 3&), 1&
  575.         
  576.         ' get the pixel color & convert it to RGB
  577.         CopyMemory pColor, ByVal pOffset, 3&
  578.         If asPreMultiplied = True Or (AlphaValue Mod 255) = 0 Then
  579.             GetPixel = ((pColor And &HFF) * &H10000) Or ((pColor  &H100) And &HFF) * &H100 Or ((pColor  &H10000) And &HFF)
  580.         Else    ' remove premultiplication
  581.             pOffset = ((255& * (pColor And &HFF))  AlphaValue) * &H10000
  582.             pOffset = pOffset Or ((255& * ((pColor  &H100) And &HFF))  AlphaValue) * &H100
  583.             GetPixel = pOffset Or ((255& * ((pColor  &H10000) And &HFF))  AlphaValue)
  584.         End If
  585.     End If
  586. End Function
  587. Public Function GetDIBbits(outStream() As Byte, _
  588.                 Optional ByVal as2dArray As Boolean = True, _
  589.                 Optional ByVal asBGRformat As Boolean = True, _
  590.                 Optional ByVal as32bpp As Boolean = True, _
  591.                 Optional ByVal asWordAligned As Boolean = True, _
  592.                 Optional ByVal asBottomUp As Boolean = True, _
  593.                 Optional ByVal X As Long, Optional ByVal Y As Long, _
  594.                 Optional ByVal Width As Long, Optional ByVal Height As Long, _
  595.                 Optional ByVal asPreMultiplied As Boolean = True) As Boolean
  596.                 
  597.     ' Function replicates the GetDIBits API with more flexibility.
  598.     ' Note: Unless you need a copy of the bytes for other purposes than just
  599.     ' referencing them, it is much more efficient to overlay your own
  600.     ' SafeArray on the Me.BitsPointer property vs copying the bytes into an array
  601.     
  602.     ' Function returns True if an image exists and the array was filled.
  603.     
  604.     ' Parameters
  605.     ' outStream(). An array to hold the returned bytes. Array is always zero-bound
  606.     ' as2dArray. If True, array is returned as (0 to Columns*4-1, 0 to Rows-1) else (0 to Columns*Rows*4-1)
  607.     ' asBGRformat. If True, pixels are in BGRalpha format else RGBalpha format
  608.     '              The alpha byte may be excluded depending on as32bpp parameter
  609.     ' as32bpp. If true, pixels use 4 bytes else pixels use 3 bytes (24bpp)
  610.     ' asWordAligned. If true, scanlines/columns are word aligned else scanlines are byte aligned
  611.     ' asBottomUp. If true, 1st row of array is bottom of picture else is top of picture
  612.     ' X,Y. The left,top position of the image to return
  613.     ' Width,Height. The number of columns,rows to return. Defaults are entire image
  614.     ' asPreMultiplied. If true, returned pixels are in their default state, premultiplied
  615.     '                  If false, premultiplication is removed.
  616.     
  617.     ' Tip: How to determine the scanwidth of the returned rows?
  618.     ' 1. If as32bpp=True, then it is always Width parameter x 4
  619.     ' 2. Otherwise, regardless of asWordAligned parameter
  620.     '   a. If as2dArray=True, UBound(outStream,1)+1
  621.     '   b. If as2dArray=False, (UBound(outStream)+1)Height parameter
  622.     
  623.     If m_Handle = 0& Then Exit Function
  624.     If X < 0& Or Y < 0& Then Exit Function
  625.     
  626.     Dim dstX As Long, dstY As Long
  627.     Dim dstYincr As Long, bytesPP As Long
  628.     Dim dstScanWidth As Long, srcScanWidth As Long
  629.     
  630.     Dim dstBytes() As Byte, srcBytes() As Byte
  631.     Dim dstSA As SafeArray, srcSA As SafeArray
  632.     
  633.     Dim Rows As Long, Cols As Long, pAlpha As Byte
  634.     
  635.     ' validate parameters
  636.     If Width = 0 Then Width = m_Width
  637.     If Height = 0 Then Height = m_Height
  638.     If Width + X > m_Width Then Width = m_Width - X
  639.     If Height + Y > m_Height Then Height = m_Height - Y
  640.     ' now we will set up the scanwidth and dimensioning the return array
  641.     If as32bpp = True Then
  642.         bytesPP = 4&
  643.         dstScanWidth = Width * bytesPP
  644.     Else
  645.         bytesPP = 3&
  646.         If asWordAligned = True Then
  647.             dstScanWidth = iparseByteAlignOnWord(24, Width)
  648.         Else
  649.             dstScanWidth = Width * bytesPP
  650.         End If
  651.     End If
  652.     ' size the destination array
  653.     If as2dArray = True Then
  654.         ReDim outStream(0 To dstScanWidth - 1&, 0 To Height - 1&)
  655.         dstSA.pvData = VarPtr(outStream(0, 0)) ' track pointer of 1st element
  656.     Else
  657.         ReDim outStream(0 To dstScanWidth * Height - 1&)
  658.         dstSA.pvData = VarPtr(outStream(0)) ' track pointer of 1st element
  659.     End If
  660.     
  661.     ' quick check for copying. This is probably going to be most used
  662.     If as32bpp = True And asBGRformat = True And asBottomUp = True Then
  663.         If Width = m_Width And Height = m_Height And asPreMultiplied = True Then
  664.             If as2dArray = True Then
  665.                 CopyMemory outStream(0, 0), ByVal m_Pointer, scanWidth * Height
  666.             Else
  667.                 CopyMemory outStream(0), ByVal m_Pointer, scanWidth * Height
  668.             End If
  669.             GetDIBbits = True
  670.             Exit Function
  671.         End If
  672.     End If
  673.     
  674.     ' set up overlays using identical 2D arrays
  675.     With dstSA
  676.         .cbElements = 1
  677.         .cDims = 2
  678.         .rgSABound(0).cElements = Height
  679.         .rgSABound(1).cElements = dstScanWidth
  680.     End With
  681.     With srcSA
  682.         .cbElements = 1
  683.         .cDims = 2
  684.         .pvData = m_Pointer
  685.         .rgSABound(0).cElements = m_Height
  686.         .rgSABound(1).cElements = m_Width * 4&
  687.     End With
  688.     CopyMemory ByVal VarPtrArray(dstBytes), VarPtr(dstSA), 4&
  689.     CopyMemory ByVal VarPtrArray(srcBytes), VarPtr(srcSA), 4&
  690.     
  691.     ' calculate destination starting row
  692.     If asBottomUp = True Then
  693.         dstY = Height - 1&
  694.         dstYincr = -1&
  695.     Else
  696.         dstYincr = 1&
  697.     End If
  698.     
  699.     srcScanWidth = (Width + X) * 4& - 1& ' position of 1st byte in DIB
  700.     If asPreMultiplied = True Then
  701.         For Rows = m_Height - Y - 1& To m_Height - Height - Y Step -1&
  702.             dstX = 0&   ' destination column
  703.             For Cols = X * 4 To srcScanWidth Step 4&
  704.                 If asBGRformat = True Then
  705.                     CopyMemory dstBytes(dstX, dstY), srcBytes(Cols, Rows), bytesPP
  706.                 Else
  707.                     dstBytes(dstX, dstY) = srcBytes(Cols + 2&, Rows)
  708.                     dstBytes(dstX + 1&, dstY) = srcBytes(Cols + 1&, Rows)
  709.                     dstBytes(dstX + 2&, dstY) = srcBytes(Cols, Rows)
  710.                     If bytesPP = 4& Then ' want the alpha array too
  711.                         dstBytes(dstX + 3&, dstY) = srcBytes(Cols + 3&, Rows)
  712.                     End If
  713.                 End If
  714.                 dstX = dstX + bytesPP ' move to next destination column
  715.             Next
  716.             dstY = dstY + dstYincr ' next destination row
  717.         Next
  718.     
  719.     Else        ' remove premultiplication
  720.         
  721.         For Rows = m_Height - Y - 1& To m_Height - Height - Y Step -1&
  722.             dstX = 0&   ' destination column
  723.             For Cols = X * 4 To srcScanWidth Step 4&
  724.                 pAlpha = srcBytes(Cols + 3&, Rows)
  725.                 If asBGRformat = True Then
  726.                     If pAlpha = 255 Then
  727.                         CopyMemory dstBytes(dstX, dstY), srcBytes(Cols, Rows), 3&
  728.                     ElseIf Not pAlpha = 0 Then
  729.                         dstBytes(dstX, dstY) = (255& * srcBytes(Cols, Rows)  pAlpha)
  730.                         dstBytes(dstX + 1&, dstY) = (255& * srcBytes(Cols + 1&, Rows)  pAlpha)
  731.                         dstBytes(dstX + 2&, dstY) = (255& * srcBytes(Cols + 2&, Rows)  pAlpha)
  732.                     End If
  733.                 Else        ' convert to RGB
  734.                     If pAlpha = 255 Then
  735.                         dstBytes(dstX, dstY) = srcBytes(Cols + 2&, Rows)
  736.                         dstBytes(dstX + 1&, dstY) = srcBytes(Cols + 1&, Rows)
  737.                         dstBytes(dstX + 2&, dstY) = srcBytes(Cols, Rows)
  738.                     ElseIf Not pAlpha = 0 Then
  739.                         dstBytes(dstX, dstY) = (255& * srcBytes(Cols + 2&, Rows)  pAlpha)
  740.                         dstBytes(dstX + 1&, dstY) = (255& * srcBytes(Cols + 1&, Rows)  pAlpha)
  741.                         dstBytes(dstX + 2&, dstY) = (255& * srcBytes(Cols, Rows)  pAlpha)
  742.                     End If
  743.                 End If
  744.                 If bytesPP = 4& Then dstBytes(dstX + 3&, dstY) = pAlpha   ' want the alpha array too
  745.                 dstX = dstX + bytesPP ' move to next destination column
  746.             Next
  747.             dstY = dstY + dstYincr ' next destination row
  748.         Next
  749.     End If
  750.     ' release arrays
  751.     CopyMemory ByVal VarPtrArray(dstBytes), 0&, 4&
  752.     CopyMemory ByVal VarPtrArray(srcBytes), 0&, 4&
  753.     GetDIBbits = True
  754. eh:
  755.     If Err Then
  756.         Err.Clear
  757.         'Stop           ' troubleshooting only
  758.         'Resume
  759.     End If
  760. End Function
  761. Public Function SetDIBbits(inStream() As Byte, _
  762.                 Optional ByVal isBGRformat As Boolean = True, _
  763.                 Optional ByVal is32bpp As Boolean = True, _
  764.                 Optional ByVal isWordAligned As Boolean = True, _
  765.                 Optional ByVal isBottomUp As Boolean = True, _
  766.                 Optional ByVal dstX As Long, Optional ByVal dstY As Long, _
  767.                 Optional ByVal dstWidth As Long, Optional ByVal dstHeight As Long) As Boolean
  768.                 
  769.     ' Function replicates the SetDIBits API with more flexibility.
  770.     ' Note: It is much more efficient to overlay your own SafeArray on
  771.     ' the Me.BitsPointer property and updating directly
  772.     
  773.     ' Function returns True if an image exists and updated.
  774.     
  775.     ' Parameters
  776.     ' inStream(). An array containing new DIB bytes. Can be any dimension
  777.     ' isBGRformat. If True, pixels are in BGRalpha format else RGBalpha format
  778.     '              The alpha byte may be excluded depending on is32bpp parameter
  779.     ' is32bpp. If true, pixels use 4 bytes else pixels use 3 bytes (24bpp)
  780.     ' isWordAligned. If true, scanlines are word aligned else scanlines are byte aligned
  781.     ' isBottomUp. If true, 1st row of array is bottom of picture else is top of picture
  782.     ' dstX,Y. The left,top position of the image to update
  783.     ' dstWidth,Height. The number of columns,rows to update. Defaults are entire image
  784.     
  785.     If m_Handle = 0& Then Exit Function
  786.     If dstX < 0& Or dstY < 0& Then Exit Function
  787.     
  788.     Dim SrcX As Long, SrcY As Long
  789.     Dim srcYincr As Long, bytesPP As Long
  790.     Dim dstScanWidth As Long, srcScanWidth As Long
  791.     
  792.     Dim dstBytes() As Byte, srcBytes() As Byte
  793.     Dim dstSA As SafeArray, srcSA As SafeArray
  794.     Dim srcBounds() As Long
  795.     
  796.     Dim Rows As Long, Cols As Long
  797.     
  798.     ' test and cache the passed inStream's pointer
  799.     srcYincr = iparseIsArrayEmpty(VarPtrArray(inStream))
  800.     If srcYincr = 0& Then Exit Function
  801.     
  802.     ' validate parameters
  803.     If dstWidth = 0 Then dstWidth = m_Width
  804.     If dstHeight = 0 Then dstHeight = m_Height
  805.     If dstWidth + dstX > m_Width Then dstWidth = m_Width - dstX
  806.     If dstHeight + dstY > m_Height Then dstHeight = m_Height - dstY
  807.     
  808.     ' now we will set up the scanwidth of the source array
  809.     If is32bpp = True Then
  810.         bytesPP = 4&
  811.         srcScanWidth = dstWidth * bytesPP
  812.     Else
  813.         bytesPP = 3&
  814.         If isWordAligned = True Then
  815.             srcScanWidth = iparseByteAlignOnWord(24, dstWidth)
  816.         Else
  817.             srcScanWidth = dstWidth * bytesPP
  818.         End If
  819.     End If
  820.     ' Get 1st 16 bytes of source SafeArray
  821.     CopyMemory srcSA, ByVal srcYincr, 16&
  822.     ' copy the array dimension's bounds to tempoary array
  823.     ReDim srcBounds(1 To 2 * srcSA.cDims)
  824.     CopyMemory srcBounds(1), ByVal srcYincr + 16&, 8& * srcSA.cDims
  825.     ' tally up the amount of bytes contained in the array
  826.     dstScanWidth = srcBounds(1)
  827.     For srcSA.cDims = 3 To 2 * srcSA.cDims Step 2
  828.         dstScanWidth = (srcBounds(srcSA.cDims) * dstScanWidth)
  829.     Next
  830.     ' does passed array have enough bytes?
  831.     If dstScanWidth * srcSA.cbElements < srcScanWidth * Height Then Exit Function
  832.     Erase srcBounds()
  833.     
  834.     ' set up overlay on source array
  835.     With srcSA
  836.         .cbElements = 1
  837.         .cDims = 2
  838.         .cLocks = 0     ' remove may have been set when copied
  839.         .fFeatures = 0  ' remove may have been set when copied
  840.         '.pvData was set when we copied the structure
  841.         .rgSABound(0).cElements = dstHeight
  842.         .rgSABound(1).cElements = srcScanWidth
  843.     End With
  844.     CopyMemory ByVal VarPtrArray(srcBytes), VarPtr(srcSA), 4&
  845.     
  846.     ' set up overlay on our DIB
  847.     With dstSA
  848.         .cbElements = 1
  849.         .cDims = 2
  850.         .pvData = m_Pointer
  851.         .rgSABound(0).cElements = m_Height
  852.         .rgSABound(1).cElements = m_Width * 4&
  853.     End With
  854.     CopyMemory ByVal VarPtrArray(dstBytes), VarPtr(dstSA), 4&
  855.     
  856.     ' set source starting row
  857.     If isBottomUp = True Then
  858.         SrcY = dstHeight - 1
  859.         srcYincr = -1
  860.     Else
  861.         srcYincr = 1
  862.     End If
  863.     
  864.     dstScanWidth = (dstWidth + dstX) * 4& - 1& ' position for 1st byte in our DIB
  865.     For Rows = m_Height - dstY - 1& To m_Height - dstHeight - dstY Step -1&
  866.         SrcX = 0&
  867.         For Cols = dstX * 4 To dstScanWidth Step 4&
  868.             If isBGRformat = True Then
  869.                 CopyMemory dstBytes(Cols, Rows), srcBytes(SrcX, SrcY), bytesPP
  870.             Else
  871.                 dstBytes(Cols, Rows) = srcBytes(SrcX + 2&, SrcY)
  872.                 dstBytes(Cols + 1&, Rows) = srcBytes(SrcX + 1&, SrcY)
  873.                 dstBytes(Cols + 2&, Rows) = srcBytes(SrcX, SrcY)
  874.                 If bytesPP = 4& Then ' want the alpha byte too
  875.                     dstBytes(Cols + 3&, Rows) = srcBytes(SrcX + 3&, SrcY)
  876.                 End If
  877.             End If
  878.             SrcX = SrcX + bytesPP ' position of next source byte
  879.         Next
  880.         SrcY = SrcY + srcYincr  ' next source row
  881.     Next
  882.     ' release overlays
  883.     CopyMemory ByVal VarPtrArray(srcBytes), 0&, 4&
  884.     
  885.     ' our image must remain pre-multiplied, ensure it now
  886.     iparseValidateAlphaChannel dstBytes(), True, m_AlphaImage, 0&
  887.     CopyMemory ByVal VarPtrArray(dstBytes), 0&, 4&
  888.     
  889.     SetDIBbits = True
  890.     
  891. End Function
  892. Public Function CreateRegion(Optional ByVal Style As eRegionStyles = regionBounds, Optional ByVal xOffset As Long, Optional ByVal yOffset As Long) As Long
  893.     ' Creates a region that can be used for clipping, filling, hit testing
  894.     ' You ARE responsible for destroying the region with a call to DeleteObject
  895.     
  896.     ' Note: This region is created from this DIB, not the rendered DIB, therefore
  897.     '   should the rendered DIB be of different size, mirrored, rotated or otherwise modified
  898.     '   you should render this to a new/blank DIB and create the region from that one
  899.     
  900.     ' Style must be one of the following. Default is regionBounds
  901.     '   - regionShaped: region consists of only non-transparent pixels
  902.     '       :: example: region for the letter O would only contain the outline
  903.     '   - regionEnclosed: transparent pixels between furthest left and furtherst right
  904.     '       non-transparent pixels in each scan line are included in the region
  905.     '       :: example: region for the letter O would be like filling the center then creating the region
  906.     '   - regionBounds: all pixels within the rectangular bounds of the image are included
  907.     '       :: example: region for the letter O would be like drawing a tight rectangle around it then creating a solid rectangular region
  908.     ' xOffset is used to shift the region n pixels left or right
  909.     ' yOffset is used to shift the region n pixels up or down
  910.     
  911.     Dim hRgn As Long
  912.     If Not m_Handle = 0& Then
  913.         If Style >= regionBounds And Style <= regionShaped Then
  914.             hRgn = iparseCreateShapedRegion(Me, Style)
  915.             If Not ((xOffset Or yOffset) = 0&) Then OffsetRgn hRgn, xOffset, yOffset
  916.         End If
  917.     End If
  918.     CreateRegion = hRgn
  919.     
  920. End Function
  921. Public Sub CopyImageTo(cDIBclass As c32bppDIB, Optional ByVal newWidth As Long, _
  922.             Optional ByVal newHeight As Long, Optional ByVal CopyOriginalFormat As Boolean = False)
  923.     
  924.     ' Function replicates the the current image to another DIB class and optionally resizes it
  925.     
  926.     ' NewWidth is optional. if zero, will use the source DIB width. If negative will mirror & resize if needed
  927.     ' NewHeight is optional. if zero, will use the source DIB height. If negative will mirror & resize if needed
  928.     ' If CopyOriginalFormat = True then, and only, if class loaded its image
  929.     '   with the optional SaveFormat=True, then the original image bytes
  930.     '   were cached and will be copied to the target cDIBclass also
  931.     '   See LoadPicture_File & LoadPicture_Stream for more info
  932.     
  933.     Dim dDC As Long, aResized() As Byte
  934.     Dim bUnselect As Boolean, bResetAlphaCap As Boolean
  935.     
  936.     If Not m_Handle = 0& Then                ' do we have an image to copy?
  937.     
  938.         If newWidth = 0& Then newWidth = m_Width
  939.         If newHeight = 0& Then newHeight = m_Height
  940.         
  941.         If cDIBclass Is Nothing Then
  942.             Set cDIBclass = New c32bppDIB  ' was a valid ref passed?
  943.             cDIBclass.gdiToken = m_GDItoken
  944.             cDIBclass.isGDIplusEnabled = Me.isGDIplusEnabled
  945.             cDIBclass.HighQualityInterpolation = Me.HighQualityInterpolation
  946.             cDIBclass.InitializeDIB Abs(newWidth), Abs(newHeight) ' Create new one
  947.         Else
  948.             cDIBclass.gdiToken = m_GDItoken
  949.             If Not (Abs(newWidth) = cDIBclass.Width And Abs(newHeight) = cDIBclass.Height) Then
  950.                 cDIBclass.InitializeDIB Abs(newWidth), Abs(newHeight) ' Create new one
  951.             End If
  952.         End If
  953.         cDIBclass.Alpha = m_AlphaImage       ' carry over the alpha flag
  954.         cDIBclass.ImageType = m_Format       ' and image type flag
  955.             
  956.         If newWidth = m_Width And newHeight = m_Height Then
  957.             ' can copy using CopyMemory vs AlphaBlend
  958.             CopyMemory ByVal cDIBclass.BitsPointer, ByVal m_Pointer, newWidth * 4& * newHeight
  959.         Else
  960.             
  961.             If (m_osCAP And 17) = 17 Then ' system is Win98/ME with AlphaBlend capability overridden
  962.                 ' but we will be resizing DIB to DIB so disallow it for now
  963.                 m_osCAP = (m_osCAP And Not 1)
  964.                 bResetAlphaCap = True
  965.             End If
  966.                 
  967.             bUnselect = (m_prevObj = 0&)
  968.             If Me.isGDIplusEnabled And (m_StretchQuality = True Or Me.isAlphaBlendFriendly = False) Then ' use GDI+ to resize
  969.                 Dim cGDIp As New cGDIPlus
  970.                 dDC = cDIBclass.LoadDIBinDC(True)
  971.                 If bUnselect Then Me.LoadDIBinDC True
  972.                 cGDIp.RenderGDIplus Me, dDC, 0&, 100&, 0&, 0&, newWidth, newHeight, 0&, 0&, m_Width, m_Height, True, gsclNone, m_GDItoken
  973.                 cDIBclass.LoadDIBinDC False
  974.                 Set cGDIp = Nothing
  975.                 If bUnselect Then Me.LoadDIBinDC False
  976.         
  977.             ElseIf newWidth < 0& Or newHeight < 0& Then   ' handle mirroring, AlphaBlend cannot do mirroring
  978.                 MirrorDIB 0&, 0&, 0&, 0&, newWidth, newHeight, aResized(), cDIBclass ' routine mirrors directly to DIB bytes
  979.         
  980.             ElseIf Me.isAlphaBlendFriendly And m_StretchQuality = False Then ' O/S has no alphablending shortfalls that are known
  981.                 dDC = cDIBclass.LoadDIBinDC(True)   ' load target into a DC
  982.                 If bUnselect Then Me.LoadDIBinDC True
  983.                 Me.Render dDC, 0&, 0&, newWidth, newHeight, 0&, 0&, m_Width, m_Height, , , False, cDIBclass
  984.                 cDIBclass.LoadDIBinDC False         ' remove DIB from DC
  985.                 If bUnselect Then Me.LoadDIBinDC False
  986.             Else
  987.                 ' stretching is involved, resize
  988.                 Call pvResize(0&, aResized(), aResized(), cDIBclass) ' routine resizes directly to DIB bytes
  989.             End If
  990.             
  991.             If bResetAlphaCap Then m_osCAP = m_osCAP Or 1
  992.         
  993.         End If
  994.         ' if the original image bytes are to be copied, do them too
  995.         If CopyOriginalFormat = True Then Call cDIBclass.SetOriginalFormat(m_ImageByteCache)
  996.     
  997.     End If
  998.     
  999. End Sub
  1000. Public Function GetOrginalFormat(outStream() As Byte) As Boolean
  1001.     ' If SaveFormat is true when LoadPicture_Stream or LoadPicture_File was
  1002.     ' called, the original bytes were cached when the image was successfully
  1003.     ' loaded. Call this to return those original bytes
  1004.     ' If there are no original bytes, the function returns False & outStream is uninitialized
  1005.     
  1006.     outStream() = m_ImageByteCache()
  1007.     GetOrginalFormat = Not (iparseIsArrayEmpty(VarPtrArray(m_ImageByteCache)) = 0&)
  1008. End Function
  1009. Friend Property Let Alpha(isAlpha As Boolean)
  1010.     m_AlphaImage = isAlpha  ' determines the flags used for AlphaBlend API
  1011.     ' this flag is set by the various image parsers; setting it yourself
  1012.     ' can produce less than desirable effects.
  1013.     ' Used in Me.Render & Me.TrimImage, cPNGwriter.OptimizeTrueColor & cPNGwriter.PalettizeImage
  1014. End Property
  1015. Public Property Get Alpha() As Boolean
  1016.     Alpha = m_AlphaImage
  1017. End Property
  1018. Public Property Let HighQualityInterpolation(Value As Boolean)
  1019.     ' When possible GDI+ will be used for stretching & rotation.
  1020.     ' If GDI+ is used,then high quality equates to BiCubic interpolation
  1021.     ' If not used, then BiLinear (manual processing) will be used.
  1022.     ' If High Quality is false, then Nearest Neighbor (very fast) interpolation used
  1023.     m_StretchQuality = Value
  1024. End Property
  1025. Public Property Get HighQualityInterpolation() As Boolean
  1026.     HighQualityInterpolation = m_StretchQuality
  1027. End Property
  1028. Public Property Get ImageType() As eImageFormat
  1029.     ImageType = m_Format    ' returns image format of the source image
  1030. End Property
  1031. Friend Property Let ImageType(iType As eImageFormat)
  1032.     m_Format = iType    ' set by the various image parsers. This is not used
  1033.     ' anywhere in these classes, you can do with it what you want -- for now.
  1034. End Property
  1035. Public Property Get Width() As Long
  1036.     Width = m_Width     ' width of image in pixels
  1037. End Property
  1038. Public Property Get Height() As Long
  1039.     Height = m_Height   ' height of image in pixels
  1040. End Property
  1041. Public Property Get BitsPointer() As Long
  1042.     BitsPointer = m_Pointer ' pointer to the bits of the image
  1043. End Property
  1044. Public Property Get scanWidth() As Long
  1045.     scanWidth = m_Width * 4&    ' number of bytes per scan line
  1046. End Property
  1047. Public Property Get Handle() As Long
  1048.     Handle = m_Handle   ' the picture handle of the image
  1049. End Property
  1050. Public Function LoadDIBinDC(ByVal bLoad As Boolean) As Long
  1051.     ' Purpose: Select/Unselect the DIB into a DC.
  1052.     ' Returns the DC handle when image is loaded
  1053.     ' Called by image parser if it needs to paint the image into the DIB
  1054.        
  1055.     If bLoad = True Then
  1056.         Dim tDC As Long
  1057.         If Not m_Handle = 0& Then    ' do we have an image?
  1058.             If m_hDC = 0& Then        ' do we have a DC?
  1059.                 tDC = GetDC(0&)     ' if not create one
  1060.                 m_hDC = CreateCompatibleDC(tDC)
  1061.                 ReleaseDC 0&, tDC
  1062.             End If
  1063.             If m_prevObj = 0& Then
  1064.                 m_prevObj = SelectObject(m_hDC, m_Handle)
  1065.             End If
  1066.             LoadDIBinDC = m_hDC
  1067.         End If
  1068.     Else
  1069.         If Not m_prevObj = 0& Then
  1070.             SelectObject m_hDC, m_prevObj
  1071.             If m_ManageDC = False Then
  1072.                 DeleteObject m_hDC
  1073.                 m_hDC = 0&
  1074.             End If
  1075.             m_prevObj = 0&
  1076.         End If
  1077.     End If
  1078. End Function
  1079. Public Property Let ManageOwnDC(bManage As Boolean)
  1080.     ' Determines whether or not this class will manage its own DC
  1081.     ' If false, then a DC is created each time the image needs to be Rendered
  1082.     Dim tDC As Long
  1083.     If bManage = False Then     ' removing management of DC
  1084.         If Not m_hDC = 0& Then   ' DC does exist, destroy it
  1085.             ' first remove the dib, if one exists
  1086.             If Not m_Handle = 0& Then SelectObject m_hDC, m_prevObj
  1087.             m_prevObj = 0&
  1088.         End If
  1089.         DeleteDC m_hDC
  1090.         m_hDC = 0&
  1091.     Else                        ' allowing creation of dc
  1092.         If m_hDC = 0& Then        ' create DC only if we have a dib to put in it
  1093.             If Not m_Handle = 0& Then
  1094.                 tDC = GetDC(0&)
  1095.                 m_hDC = CreateCompatibleDC(tDC)
  1096.                 ReleaseDC 0&, tDC
  1097.             End If
  1098.         End If
  1099.     End If
  1100.     m_ManageDC = bManage
  1101. End Property
  1102. Public Property Get ManageOwnDC() As Boolean
  1103.     ManageOwnDC = m_ManageDC
  1104. End Property
  1105. Public Property Get isAlphaBlendFriendly() As Boolean
  1106.     isAlphaBlendFriendly = ((m_osCAP And 1) = 1)
  1107.     ' WinNT4 & below and Win95 are not shipped with msimg32.dll (AlphaBlend API)
  1108.     ' Win98 has bugs & would believe that WinME is buggy too but don't know for sure
  1109.     ' Therefore, the Rendering in this class will not use AlphaBlend on these
  1110.     ' operating systems even if the DLL exists, but will use GDI+ if available
  1111.     ' Can be overridden by setting this property to True
  1112. End Property
  1113. Public Property Let isAlphaBlendFriendly(Enabled As Boolean)
  1114.     ' This has been provided to override safety of using AlphaBlend on Win9x systems.
  1115.     ' Caution. Only set this when rendering to a known device dependent bitmap (DDB)
  1116.     ' Alphablend can crash when rendering DIB to DIB vs DIB to DDB. Be warned.
  1117.     If Enabled = True Then
  1118.         ' Overriding in play: allow AlphaBlend if system is Win98 or better
  1119.         ' By default this is already set for Win2K or better
  1120.         If ((m_osCAP And 8) = 8) Then m_osCAP = m_osCAP Or 1
  1121.     Else
  1122.         m_osCAP = m_osCAP And Not 1 ' disallow AlphaBlend
  1123.     End If
  1124. End Property
  1125. Public Property Get isGDIplusEnabled() As Boolean
  1126.     ' identifies if GDI+ is usable on the system.
  1127.     ' Before this property is set, GDI+ is tested to ensure it is usable
  1128.     isGDIplusEnabled = ((m_osCAP And 2) = 2)
  1129. End Property
  1130. Public Property Let isGDIplusEnabled(Enabled As Boolean)
  1131.     ' Sets the property. If set to False by you, GDI+ will not be used
  1132.     ' for any rendering, but still may be used to create PNG files if needed
  1133.     
  1134.     If Not Enabled = Me.isGDIplusEnabled Then
  1135.         m_osCAP = (m_osCAP And Not 2)
  1136.         If Enabled Then
  1137.             If (m_osCAP And 32) = 0 Then ' else Win95, NT4 SP5 or lower
  1138.                 Dim cGDIp As New cGDIPlus
  1139.                 If cGDIp.isGDIplusOk() = True Then m_osCAP = m_osCAP Or 2
  1140.             End If
  1141.         End If
  1142.     End If
  1143. End Property
  1144. Public Property Get isZlibEnabled() As Boolean
  1145.     ' Read Only
  1146.     ' To create PNG files, GDI+ or zLib is required. This property informs
  1147.     ' you if zLIB exists in the system's DLL path
  1148.     isZlibEnabled = iparseValidateZLIB(vbNullString, 0, False, False, True)
  1149.     
  1150. End Property
  1151. Public Function InitializeDIB(ByVal Width As Long, ByVal Height As Long) As Boolean
  1152.     ' Creates a blank (all black, all transparent) DIB of requested height & width
  1153.     
  1154.     Dim tBMPI As BITMAPINFO, tDC As Long
  1155.     
  1156.     DestroyDIB ' clear any pre-existing dib
  1157.     
  1158.     If Width < 0& Then Exit Function
  1159.     If Height = 0& Then
  1160.         Exit Function
  1161.     ElseIf Height < 0& Then
  1162.         Height = Abs(Height) ' no top-down dibs
  1163.     End If
  1164.     
  1165.     On Error Resume Next
  1166.     With tBMPI.bmiHeader
  1167.         .biBitCount = 32
  1168.         .biHeight = Height
  1169.         .biWidth = Width
  1170.         .biPlanes = 1
  1171.         .biSize = 40&
  1172.         .biSizeImage = .biHeight * .biWidth * 4&
  1173.     End With
  1174.     If Err Then
  1175.         Err.Clear
  1176.         ' only possible error would be that Width*Height*4& is absolutely huge
  1177.         Exit Function
  1178.     End If
  1179.     
  1180.     tDC = GetDC(0&) ' get screen DC
  1181.     m_Handle = CreateDIBSection(tDC, tBMPI, 0&, m_Pointer, 0&, 0&)
  1182.     If m_ManageDC = True Then
  1183.         ' create a DC if class is managing its own & one isn't created yet
  1184.         If m_hDC = 0& Then m_hDC = CreateCompatibleDC(tDC)
  1185.     End If
  1186.     ' release the screen DC if we captured it
  1187.     ReleaseDC 0&, tDC
  1188.     
  1189.     If Not m_Handle = 0& Then    ' let's hope system resources allowed DIB creation
  1190.         m_Width = Width
  1191.         m_Height = Height
  1192.         m_AlphaImage = True
  1193.         m_Format = imgNone
  1194.         InitializeDIB = True
  1195.     End If
  1196. End Function
  1197. Public Sub DestroyDIB()
  1198.     
  1199.     ' PURPOSE: Destroy any existing image
  1200.     If Not m_hDC = 0& Then   ' do we have a DC?
  1201.         ' do we have an image; if so get it out of the DC
  1202.         If Not m_prevObj = 0& Then SelectObject m_hDC, m_prevObj
  1203.         ' destroy our DC, no point in keeping it w/o image
  1204.         DeleteObject m_hDC
  1205.         m_hDC = 0&
  1206.     End If
  1207.     ' if we do have an image, destroy it now
  1208.     If Not m_Handle = 0& Then
  1209.         DeleteObject m_Handle
  1210.         Erase m_ImageByteCache
  1211.     End If
  1212.     ' reset other image attributes
  1213.     m_Width = 0&
  1214.     m_Height = 0&
  1215.     m_Handle = 0&
  1216.     m_Pointer = 0&
  1217.     m_prevObj = 0&
  1218.     m_AlphaImage = False
  1219.     m_Format = imgError
  1220. End Sub
  1221. Public Sub EraseDIB()
  1222.     ' Function clears out an existing DIB, making it 100% transparent/black
  1223.     If Not m_Handle = 0& Then
  1224.         FillMemory ByVal m_Pointer, m_Width * m_Height * 4&, 0
  1225.         m_Format = imgNone
  1226.         m_AlphaImage = True
  1227.     End If
  1228.     
  1229. End Sub
  1230. Public Function Render(ByVal destinationDC As Long, _
  1231.                 Optional ByVal destX As Long, Optional ByVal destY As Long, _
  1232.                 Optional ByVal destWidth As Long, Optional ByVal destHeight As Long, _
  1233.                 Optional ByVal SrcX As Long, Optional ByVal SrcY As Long, _
  1234.                 Optional ByVal srcWidth As Long, Optional ByVal srcHeight As Long, _
  1235.                 Optional ByVal Opacity As Long = 100&, _
  1236.                 Optional ByVal Blend As Boolean = True, _
  1237.                 Optional ByVal SetHalfTone As Boolean = True, _
  1238.                 Optional ByRef destHostDIB As c32bppDIB = Nothing, _
  1239.                 Optional ByVal grayScale As eGrayScaleFormulas = gsclNone, _
  1240.                 Optional ByVal LightAdjustment As Single = 0!, _
  1241.                 Optional ByVal Angle As Single = 0!, _
  1242.                 Optional ByVal CenterOnDestXY As Boolean = False) As Boolean
  1243.     ' PURPOSE: Render an existing 32bpp DIB to a target DC
  1244.     ' Angle & CenterOnDestXY added to allow this routine to replace the RotateAtCenterPoint & RotateAtTopLeft calls
  1245.     
  1246.     ' Mirroring: When destWidth & srcWidth are compared, if one is negative and the other positive, mirroring horizontally occurs
  1247.     '            When destHeight & srcHeight are compared, if one is negative and the other positive, mirroring vertically occurs
  1248.     ' All four of those parameters are optional & any that are not passed will default to the image's width/height as needed
  1249.     ' before the mirroring check is applied
  1250.     
  1251.     ' Parameters. Only destinationDC is required
  1252.     ' destinationDC :: target DC to draw to. Ignored if destHostDIB is passed
  1253.     ' destX, destY :: the top/left coordinates to draw to, default is 0,0
  1254.     ' destWidth, destHeight :: the width and height to draw to, default is the image's width & height
  1255.     ' srcX, srcY :: the left & top offset within the DIB
  1256.     ' srcWidth, srcHeight :: the amount of DIB to be rendered
  1257.     ' Opacity :: how opaque to draw the image, default is 100% opaque
  1258.     ' Blend :: no longer used, reserved & left in for backward compatibility
  1259.     ' SetHalfTone :: if True, then the destination DC's stretch mode will be modified to
  1260.     '       produce better quality results. This option is not available on Win9x systems.
  1261.     '       Tip: When AlphaBlending to another DIB set to False
  1262.     '            When AlphaBlending to CompatibleBitmap (DDB) or visible DC set to True
  1263.     ' destHostDIB :: When rendering from DIB class to DIB class, pass the destination
  1264.     '       DIB class to ensure alpha blending occurs correctly on systems that do not
  1265.     '       support GDI+ or AlphaBlend APIs. When passed, destinationDC is ignored
  1266.     ' grayscale :: one of several formulas to grayscale while rendering (optional)
  1267.     ' LightAdjustment :: values between -100 and 100 percent of added pixel darkeness/lightness
  1268.     '       -100% will display a black image & 100 percent will display a white image
  1269.     ' Angle :: between -360 and 360. Rotation is clockwise
  1270.     ' CenterOnDestXY :: If true then rendering is centered on the destX,destY coordinates
  1271.     
  1272.     Dim lBlendFunc As Long, tDC As Long, hOldImage As Long
  1273.     Dim lStretchMode As Long
  1274.     Dim aResizedBytes() As Byte, aMirrorBytes() As Byte
  1275.     Dim bStretching As Boolean
  1276.     Dim bMirroring As Boolean
  1277.     Dim bRotating As Boolean
  1278.     Dim bCanUseAlphaBlend As Boolean
  1279.     
  1280.     
  1281.     ' validate a few things
  1282.     If Opacity < 1& Then        ' nothing to render if image is 100% transparent
  1283.         Render = Not (m_Handle = 0)
  1284.         Exit Function
  1285.     ElseIf m_Handle = 0& Then
  1286.         Exit Function
  1287.     ElseIf destinationDC = 0& Then
  1288.         If destHostDIB Is Nothing Then Exit Function
  1289.     End If
  1290.     
  1291.     ' validate optional destination parameters
  1292.         If destWidth = 0& Then destWidth = m_Width
  1293.         If destHeight = 0& Then destHeight = m_Height
  1294.     
  1295.     ' validate optional parameters for source image
  1296.         If SrcX < 0& Then SrcX = 0&  ' source X,Y cannot be negative
  1297.         If SrcY < 0& Then SrcY = 0&  ' but the dest X,Y can be
  1298.         If srcWidth = 0& Then
  1299.             srcWidth = m_Width
  1300.         ElseIf srcWidth < 0& Then        ' locally, only the destWidth can be negative for mirroring, not srcHeight
  1301.             destWidth = -destWidth
  1302.             srcWidth = -srcWidth
  1303.         End If
  1304.         If srcHeight = 0& Then
  1305.             srcHeight = m_Height
  1306.         ElseIf srcHeight < 0& Then      ' locally, only the destHeight can be negative for mirroring, not srcHeight
  1307.             destHeight = -destHeight
  1308.             srcHeight = -srcHeight
  1309.         End If
  1310.         If SrcX + srcWidth > m_Width Then srcWidth = m_Width - SrcX
  1311.         If SrcY + srcHeight > m_Height Then srcHeight = m_Height - SrcY
  1312.         
  1313.     
  1314.     ' angle is Single. See if passed angle is evenly divisible by 360
  1315.     If Int(Angle) = Angle Then
  1316.         bRotating = Not ((Angle Mod 360) = 0)
  1317.     Else    ' angle has fractional component; therefore can't be Mod 360
  1318.         bRotating = True
  1319.     End If
  1320.     
  1321.     ' validate opacity is within range
  1322.     Opacity = Abs(Opacity) Mod 100
  1323.     If Opacity = 0& Then Opacity = 100&
  1324.     
  1325.     ' validate light adjustment is within range. Disqualify LigthAdjustmnet if out of range
  1326.     If Not LightAdjustment = 0! Then
  1327.         If LightAdjustment > 100! Then
  1328.             LightAdjustment = 0!
  1329.         ElseIf LightAdjustment < -100! Then
  1330.             LightAdjustment = 0!
  1331.         End If
  1332.     End If
  1333.     
  1334.     If CenterOnDestXY = True Then
  1335.         If bRotating Then
  1336.             destX = destX - destWidth  2       ' use negative destWidth,destHeight if mirroring - rotation routines expect it
  1337.             destY = destY - destHeight  2
  1338.             If Not destHostDIB Is Nothing Then destinationDC = destHostDIB.LoadDIBinDC(True)
  1339.             Render = RotateImage(destinationDC, Angle, destX, destY, destWidth, destHeight, SrcX, SrcY, srcWidth, srcHeight, Opacity, destHostDIB, grayScale, LightAdjustment)
  1340.             If Not destHostDIB Is Nothing Then destHostDIB.LoadDIBinDC False
  1341.             Exit Function
  1342.         Else
  1343.             destX = destX - Abs(destWidth  2)  ' not rotating, don't allow negative destWidth,destHeight for calculations
  1344.             destY = destY - Abs(destHeight  2)
  1345.         End If
  1346.     ElseIf bRotating Then
  1347.         If Not destHostDIB Is Nothing Then destinationDC = destHostDIB.LoadDIBinDC(True)
  1348.         Render = RotateImage(destinationDC, Angle, destX, destY, destWidth, destHeight, SrcX, SrcY, srcWidth, srcHeight, Opacity, destHostDIB, grayScale, LightAdjustment)
  1349.         If Not destHostDIB Is Nothing Then destHostDIB.LoadDIBinDC False
  1350.         Exit Function
  1351.     End If
  1352.     
  1353.     ' are we mirroring? rules out AlphaBlend usage if we are
  1354.     If destWidth > 0& Then
  1355.         bMirroring = (destHeight < 0&)
  1356.     Else
  1357.         bMirroring = True
  1358.     End If
  1359.     ' are we resizing? may rule out AlphaBlend usage (stretching DIB to DIB can crash on Win9x)
  1360.     If (Abs(destWidth) = srcWidth) Then
  1361.         bStretching = Not (Abs(destHeight) = srcHeight)
  1362.     Else
  1363.         bStretching = True
  1364.     End If
  1365.     
  1366.     ' The following IF tree and above boolean assignments are to determine:
  1367.     ' 1. Do we use AlphaBlend
  1368.     ' 2. Do we use GDI+
  1369.     ' 3. Do we do it manually.
  1370.     ' The answer depends on user settings, O/S, graphics manipulation & DLL abilities
  1371.     
  1372.     ' if user provided token, allow GDI+ to override AlphaBlend
  1373.     If Me.isGDIplusEnabled = False Or Me.gdiToken = 0& Then
  1374.         ' see if alphablend will support the various rendering options
  1375.         If Me.isAlphaBlendFriendly Then     ' Win98 or better with AlphaBlend enabled & GDI+ disabled
  1376.             If Not bMirroring Then                  ' can't use alphaBlend if mirroring
  1377.                 If grayScale = gsclNone Then        ' can't use alphaBlend if gray scaling
  1378.                     If LightAdjustment = 0! Then    ' can't use alphaBlend if modifying pixel brightness
  1379.                         If bStretching Then
  1380.                             bCanUseAlphaBlend = Not m_StretchQuality ' can't use alphaBlend if using Bilinear interpolation
  1381.                         Else
  1382.                             bCanUseAlphaBlend = True
  1383.                         End If
  1384.                     End If
  1385.                 End If
  1386.             End If
  1387.         End If
  1388.     End If
  1389.     
  1390.     If Me.isGDIplusEnabled = True And bCanUseAlphaBlend = False Then
  1391.         ' we will use GDI+ to render when higher quality interpolation is desired, system is not AlphaBlend friendly or user supplied gdi+ token
  1392.         Dim cGDIp As New cGDIPlus
  1393.         If Not destHostDIB Is Nothing Then destinationDC = destHostDIB.LoadDIBinDC(True)
  1394.         Render = cGDIp.RenderGDIplus(Me, destinationDC, 0&, Opacity, destX, destY, destWidth, destHeight, SrcX, SrcY, srcWidth, srcHeight, m_StretchQuality, grayScale, m_GDItoken, LightAdjustment)
  1395.         If Not destHostDIB Is Nothing Then destHostDIB.LoadDIBinDC False
  1396.         Set cGDIp = Nothing
  1397.     
  1398.     Else
  1399.         
  1400.         
  1401.         If m_hDC = 0& Then  ' do we have a DC to select our image into?
  1402.             tDC = GetDC(0&) ' if not create one, if ManageOwnDC=True, we will have one
  1403.             m_hDC = CreateCompatibleDC(tDC)
  1404.             ReleaseDC 0&, tDC
  1405.             hOldImage = SelectObject(m_hDC, m_Handle)
  1406.         Else
  1407.             ' we have a DC, but is the image selected into it?
  1408.             If m_prevObj = 0& Then hOldImage = SelectObject(m_hDC, m_Handle)
  1409.         End If
  1410.         
  1411.         If bCanUseAlphaBlend = False Then
  1412.             ' Ruled out use of AlphaBlend (preferred when GDI+ isn't available)
  1413.             ' Win95/NT4 - not shipped with AlphaBlend
  1414.             ' Mirroring or high quality interpolation stretching - can't use AlphaBlend
  1415.             ' Grayscaling/light adjustments on the fly - can't use AlphaBlend
  1416.             ' Stretching from DIB to destination - can crash with Win9x
  1417.             ' AlphaBlend can't do high quality interpolation
  1418.             
  1419.             ' doing it completely manually
  1420.             ' 1. Mirror and change light intensity as needed
  1421.             If bMirroring Then MirrorDIB SrcX, SrcY, srcWidth, srcHeight, destWidth, destHeight, aMirrorBytes(), , LightAdjustment
  1422.             ' 2. Resize using Nearest Neighbor or Bi-Linear algorithms & change light intensity as needed, then Render
  1423.             If bStretching Then
  1424.                 If pvResize(destinationDC, aResizedBytes(), aMirrorBytes(), Nothing, SrcX, SrcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, LightAdjustment) = False Then Exit Function
  1425.                 ' use custom blending routine, passing aResizedBytes array
  1426.                 Render = Win9xBlend(destinationDC, aResizedBytes(), SrcX, SrcY, destX, destY, destWidth, destHeight, (255& * Opacity)  100&, destHostDIB, grayScale, LightAdjustment)
  1427.             Else
  1428.                 ' use custom blending routine, passing aMirrorBytes array. If LigthAdjustment not applied above, it will be applied in spt_Win9xBlend
  1429.                 Render = Win9xBlend(destinationDC, aMirrorBytes(), SrcX, SrcY, destX, destY, destWidth, destHeight, (255& * Opacity)  100&, destHostDIB, grayScale, LightAdjustment)
  1430.             End If
  1431.             
  1432.         Else ' we can use AlphaBlend
  1433.         
  1434.             If Not destHostDIB Is Nothing Then destinationDC = destHostDIB.LoadDIBinDC(True)
  1435.             
  1436.             If SetHalfTone Then ' Stretch_Halftone not compatible with win9x
  1437.                 If ((m_osCAP And 16&) = 0&) Then lStretchMode = SetStretchBltMode(destinationDC, STRETCH_HALFTONE)
  1438.             End If
  1439.             
  1440.             ' calculate the opacity required & add it to the BlendFunction variable
  1441.             lBlendFunc = AC_SRC_OVER Or (((255& * Opacity)  100&) * &H10000)
  1442.             ' if the image has transparency, then we add the AC_SRC_ALPHA flag too
  1443.             If Me.Alpha = True Then lBlendFunc = lBlendFunc Or (AC_SRC_ALPHA * &H1000000)
  1444.             Render = Not (AlphaBlend(destinationDC, destX, destY, destWidth, destHeight, m_hDC, SrcX, SrcY, srcWidth, srcHeight, lBlendFunc) = 0&)
  1445.             
  1446.             If SetHalfTone Then ' Stretch_Halftone not compatible with win9x
  1447.                 If ((m_osCAP And 16&) = 0&) Then SetStretchBltMode destinationDC, lStretchMode
  1448.             End If
  1449.             If Not destHostDIB Is Nothing Then destHostDIB.LoadDIBinDC False
  1450.             
  1451.         End If
  1452.         
  1453.         ' remove the image from the DC if necessary
  1454.         If Not hOldImage = 0& Then SelectObject m_hDC, hOldImage
  1455.         If Not tDC = 0& Then    ' if we created a DC, let's destroy it now
  1456.             DeleteDC m_hDC
  1457.             m_hDC = 0&
  1458.         End If
  1459.         
  1460.     End If
  1461.     
  1462. End Function
  1463. Public Function SaveToStream(outStream() As Byte) As Boolean
  1464.     ' Should you want to serialize the 32bpp DIB.
  1465.     ' Stream is formatted as a complete bitmap; therefore,
  1466.     ' one could simply write the bytes to file and a true bitmap is created
  1467.     ' Use GetDibBits function to return just the pixel data
  1468.     
  1469.     On Error GoTo ExitRoutine   ' should out of memory occur?
  1470.     
  1471.     If m_Handle = 0& Then Exit Function
  1472.     
  1473.     Dim tBMPI As BITMAPINFO
  1474.     Dim b24bpp() As Byte
  1475.     
  1476.     With tBMPI.bmiHeader
  1477.         .biHeight = m_Height
  1478.         .biWidth = m_Width
  1479.         .biPlanes = 1
  1480.         .biSize = 40
  1481.         .biBitCount = 24 + m_AlphaImage * -8
  1482.         .biSizeImage = iparseByteAlignOnWord(.biBitCount, .biWidth) * .biHeight
  1483.     End With
  1484.     
  1485.     ReDim outStream(0 To 53 + tBMPI.bmiHeader.biSizeImage)
  1486.     
  1487.     CopyMemory outStream(0), &H4D42, 2& ' bmp magic number
  1488.     CopyMemory outStream(2), CLng(54 + tBMPI.bmiHeader.biSizeImage), 4& ' overall size of image
  1489.     ' ^^ 54 = 14 byte bmp header + 40 for the tBMPI structure
  1490.     CopyMemory outStream(10), 54&, 4& ' image offset from beginning of file
  1491.     CopyMemory outStream(14), tBMPI, 40&
  1492.     If tBMPI.bmiHeader.biBitCount = 32 Then
  1493.         CopyMemory outStream(54), ByVal m_Pointer, tBMPI.bmiHeader.biSizeImage
  1494.     Else
  1495.         GetDIBbits b24bpp(), , , False
  1496.         CopyMemory outStream(54), b24bpp(0, 0), tBMPI.bmiHeader.biSizeImage
  1497.     End If
  1498.     SaveToStream = True
  1499.     
  1500. ExitRoutine:
  1501.     If Err Then
  1502.         Err.Clear
  1503.         Erase outStream()
  1504.     End If
  1505. End Function
  1506. Public Function SaveToStream_PNG(outStream() As Byte) As Boolean
  1507.     ' Requires GDI+ and/or zLib installed on the system, otherwise function fails.
  1508.     ' Tesst isGDIplusEnabled or isZlibEnabled
  1509.     ' To use the optional PNG properties, isZlibEnabled must be True
  1510.     '   See PngPropertySet and PngPropertyGet
  1511.     
  1512.     ' Function saves the current 32bpp DIB to an array containing the DIB in PNG format
  1513.     ' Per PNG recommendations, the PNG is created with non-premultiplied pixels
  1514.         
  1515.     If m_Handle = 0& Then Exit Function
  1516.     Dim cGDIp As cGDIPlus, cZlib As cPNGwriter
  1517.     Dim bSuccess As Boolean
  1518.     
  1519.     If m_PNGprops Is Nothing Then   ' no special PNG properties set, use GDI+
  1520.         Set cGDIp = New cGDIPlus
  1521.         If cGDIp.SaveToPNG(vbNullString, outStream(), Me, m_GDItoken) = False Then
  1522.             Set cZlib = New cPNGwriter  ' failed, attempt to use zLIB
  1523.             bSuccess = cZlib.SavePNGex(Me, vbNullString, outStream())
  1524.         Else
  1525.             bSuccess = True         ' GDI+ created the PNG
  1526.         End If
  1527.     Else
  1528.         ' user set some optional PNG properties (See PngPropertySet), use zLib
  1529.         If m_PNGprops.SavePNGex(Me, vbNullString, outStream()) = False Then
  1530.             Set cGDIp = New cGDIPlus    ' failed, attempt to use GDI+
  1531.             bSuccess = cGDIp.SaveToPNG(vbNullString, outStream(), Me, m_GDItoken)
  1532.         Else
  1533.             bSuccess = True         ' zLIB created the PNG
  1534.         End If
  1535.     End If
  1536.     SaveToStream_PNG = bSuccess
  1537.         
  1538. End Function
  1539. Public Function SourceIconSizes(sizeArray() As Long) As Long
  1540.     ' Function will return a 2D array that contains the icon width, height,
  1541.     '   bit depth and color count for each icon in the source image/file
  1542.     ' The 2D array is always zero bound and the return value of the function
  1543.     ' indicates how many icons exist in the source
  1544.     
  1545.     ' 1st dimension of the array
  1546.     ' 0 element: icon width
  1547.     ' 1 element: icon height
  1548.     ' 2 element: icon bit depth: 1,2,4,8,16,24,32
  1549.     ' 3 element: icon colors: 2,4,16,256,HIGH_COLOR,TRUE_COLOR, TRUE_COLOR_ALPHA
  1550.     ' HIGH_COLOR, TRUE_COLOR,& TRUE_COLOR_ALPHA are public variables
  1551.     ' 2nd dimension of the array is 0 to number of icons - 1
  1552.     
  1553.     If m_Handle = 0& Then Exit Function
  1554.     Select Case m_Format
  1555.         Case imgIcon, imgIconARGB, imgPNGicon, imgCursor, imgCursorARGB
  1556.             If iparseIsArrayEmpty(VarPtrArray(m_ImageByteCache)) = 0& Then
  1557.                 ' original bytes were not kept, therefore, we only have one image
  1558.                 ReDim sizeArray(0 To 3, 0 To 0)
  1559.                 sizeArray(0, 0) = m_Width
  1560.                 sizeArray(1, 0) = m_Height
  1561.                 sizeArray(2, 0) = 32
  1562.                 sizeArray(3, 0) = TRUE_COLOR_ALPHA
  1563.                 SourceIconSizes = 1
  1564.             Else
  1565.                 Dim cICO As cICOparser, i As Long
  1566.                 Set cICO = New cICOparser
  1567.                 If cICO.LoadStream(m_ImageByteCache, 32, 32, Nothing, 0, UBound(m_ImageByteCache) + 1, 32) = True Then
  1568.                     ReDim sizeArray(0 To 3, 0 To cICO.IconCount - 1)
  1569.                     With cICO
  1570.                         For i = 1 To .IconCount
  1571.                             sizeArray(0, i - 1) = .Width(i)
  1572.                             sizeArray(1, i - 1) = .Height(i)
  1573.                             sizeArray(2, i - 1) = .bitDepth(i)
  1574.                             Select Case .bitDepth(i)
  1575.                                 Case 1: sizeArray(3, i - 1) = 2
  1576.                                 Case 2: sizeArray(3, i - 1) = 4
  1577.                                 Case 4: sizeArray(3, i - 1) = 16
  1578.                                 Case 8: sizeArray(3, i - 1) = 256
  1579.                                 Case Is < 24: sizeArray(3, i - 1) = HIGH_COLOR
  1580.                                 Case 24: sizeArray(3, i - 1) = TRUE_COLOR
  1581.                                 Case Else: sizeArray(3, i - 1) = TRUE_COLOR_ALPHA
  1582.                             End Select
  1583.                         Next
  1584.                     End With
  1585.                     SourceIconSizes = cICO.IconCount
  1586.                 End If
  1587.             End If
  1588.         Case Else
  1589.             ' not an icon/cursor source
  1590.     End Select
  1591. End Function
  1592. Public Function CreateCheckerBoard(Optional ByVal CheckerSize As Long = 12&, _
  1593.             Optional ByVal FirstColor As Long = vbWhite, Optional ByVal SecondColor As Long = 12632256) As Boolean
  1594.     ' Function simply creates a checkerboard pattern.  This can be desirable when the DIB currently has no
  1595.     ' image but something should be displayed. When this is set, you can test whether or not this class
  1596.     ' created the Checkerboard by testing class.ImageType = imgCheckerBoard
  1597.     
  1598.     ' The checker size is used for both the width and height of each square. Default value is 12.
  1599.     ' FirstColor is the colored checker at the top left corner of the pattern. Default is white
  1600.     ' SecondColor is the alternating checker color. Default is gray RGB: 192,192,192
  1601.     
  1602.     If m_Handle = 0& Then Exit Function
  1603.     Dim hBrush As Long, hBr1 As Long, hBr2 As Long
  1604.     Dim cRect As RECT, tSA As SafeArray
  1605.     Dim X As Long, Y As Long, tDC As Long
  1606.     Dim bUnselect As Boolean, bEven As Boolean
  1607.     Dim dibBytes() As Byte
  1608.     
  1609.     bUnselect = (m_prevObj = 0&)
  1610.     tDC = LoadDIBinDC(True)
  1611.     
  1612.     hBr1 = CreateSolidBrush(FirstColor)
  1613.     hBr2 = CreateSolidBrush(SecondColor)
  1614.     
  1615.     cRect.Right = CheckerSize
  1616.     cRect.Bottom = CheckerSize
  1617.     For Y = 0& To m_Height - 1& Step CheckerSize
  1618.         If bEven Then hBrush = hBr2 Else hBrush = hBr1
  1619.         For X = 0& To m_Width - 1& Step CheckerSize
  1620.             FillRect tDC, cRect, hBrush
  1621.             If hBrush = hBr1 Then hBrush = hBr2 Else hBrush = hBr1
  1622.             OffsetRect cRect, CheckerSize, 0&
  1623.         Next
  1624.         bEven = Not bEven
  1625.         OffsetRect cRect, -cRect.Left, CheckerSize
  1626.     Next
  1627.     DeleteObject hBr1
  1628.     DeleteObject hBr2
  1629.     
  1630.     If bUnselect Then LoadDIBinDC False
  1631.     
  1632.     ' here we will force every alpha byte to be fully opaque
  1633.     With tSA
  1634.         .cbElements = 1
  1635.         .cDims = 2
  1636.         .pvData = m_Pointer
  1637.         .rgSABound(0).cElements = m_Height
  1638.         .rgSABound(1).cElements = m_Width * 4&
  1639.     End With