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

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 = "cGDIPlus"
  10. Attribute VB_GlobalNameSpace = False
  11. Attribute VB_Creatable = True
  12. Attribute VB_PredeclaredId = False
  13. Attribute VB_Exposed = False
  14. Option Explicit
  15. ' No APIs are declared public. This is to prevent possibly, differently
  16. ' declared APIs, or different versions of the same API, from conflciting
  17. ' with any APIs you declared in your project. Same rule for UDTs.
  18. ' Note: I did take some liberties in several API declarations throughout
  19. Private Declare Function CLSIDFromString Lib "ole32" (ByVal lpszProgID As Long, pCLSID As Any) As Long
  20. Private Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (ByRef Ptr() As Any) As Long
  21. ' following are used for saving dib to PNG (testing phase only)
  22. Private Declare Function GdipImageRotateFlip Lib "gdiplus" (ByVal Image As Long, ByVal rfType As Long) As Long
  23. Private Declare Function GdipCreateBitmapFromScan0 Lib "gdiplus" (ByVal Width As Long, ByVal Height As Long, ByVal stride As Long, ByVal PixelFormat As Long, scan0 As Any, BITMAP As Long) As Long
  24. Private Declare Function GdipCreateBitmapFromGdiDib Lib "gdiplus" (gdiBitmapInfo As BITMAPINFO, gdiBitmapData As Any, BITMAP As Long) As Long
  25. Private Declare Function lstrlenW Lib "kernel32" (ByVal psString As Any) As Long
  26. Private Declare Function GdipGetImageEncodersSize Lib "gdiplus" (numEncoders As Long, Size As Long) As Long
  27. Private Declare Function GdipGetImageEncoders Lib "gdiplus" (ByVal numEncoders As Long, ByVal Size As Long, Encoders As Any) As Long
  28. Private Declare Function GdipSaveImageToFile Lib "gdiplus" (ByVal hImage As Long, ByVal sFilename As String, clsidEncoder As Any, encoderParams As Any) As Long
  29. Private Declare Function GdipSaveImageToStream Lib "gdiplus" (ByVal Image As Long, ByVal Stream As IUnknown, clsidEncoder As Any, encoderParams As Any) As Long
  30. Private Enum EncoderParameterValueType
  31.     [EncoderParameterValueTypeByte] = 1
  32.     [EncoderParameterValueTypeASCII] = 2
  33.     [EncoderParameterValueTypeShort] = 3
  34.     [EncoderParameterValueTypeLong] = 4
  35.     [EncoderParameterValueTypeRational] = 5
  36.     [EncoderParameterValueTypeLongRange] = 6
  37.     [EncoderParameterValueTypeUndefined] = 7
  38.     [EncoderParameterValueTypeRationalRange] = 8
  39. End Enum
  40. Private Type EncoderParameter
  41.     GUID(0 To 3)   As Long
  42.     NumberOfValues As Long
  43.     Type           As EncoderParameterValueType
  44.     Value          As Long
  45. End Type
  46. '-- Encoder Parameters structure
  47. Private Type EncoderParameters
  48.     Count     As Long
  49.     Parameter As EncoderParameter
  50. End Type
  51. Private Type ImageCodecInfo
  52.     ClassID(0 To 3)   As Long
  53.     FormatID(0 To 3)  As Long
  54.     CodecName         As Long
  55.     DllName           As Long
  56.     FormatDescription As Long
  57.     FilenameExtension As Long
  58.     MimeType          As Long
  59.     Flags             As Long
  60.     Version           As Long
  61.     SigCount          As Long
  62.     SigSize           As Long
  63.     SigPattern        As Long
  64.     SigMask           As Long
  65. End Type
  66. Private Declare Function GdipSetInterpolationMode Lib "gdiplus" (ByVal hGraphics As Long, ByVal Interpolation As Long) As Long
  67. Private Declare Function GdipTranslateWorldTransform Lib "gdiplus" (ByVal graphics As Long, ByVal dX As Single, ByVal dY As Single, ByVal Order As Long) As Long
  68. Private Declare Function GdipRotateWorldTransform Lib "gdiplus" (ByVal graphics As Long, ByVal Angle As Single, ByVal Order As Long) As Long
  69. Private Declare Function GdipCreateImageAttributes Lib "gdiplus" (ByRef imgAttr As Long) As Long
  70. Private Declare Function GdipSetImageAttributesColorMatrix Lib "gdiplus" (ByVal imgAttr As Long, ByVal clrAdjust As Long, ByVal clrAdjustEnabled As Long, ByRef clrMatrix As Any, ByRef grayMatrix As Any, ByVal clrMatrixFlags As Long) As Long
  71. Private Declare Function GdipDisposeImageAttributes Lib "gdiplus" (ByVal imgAttr As Long) As Long
  72. Private Const ColorAdjustTypeBitmap As Long = 1
  73. Private Const PixelFormat32bppARGB As Long = &H26200A
  74. Private Const PixelFormat32bppPARGB As Long = &HE200B
  75. Private Const InterpolationModeNearestNeighbor As Long = &H5&
  76. Private Const InterpolationModeHighQualityBicubic As Long = &H7&
  77. Private Const InterpolationModeHighQualityBilinear As Long = &H6&
  78. ' Following are used only if PNG file is being processed by GDI+
  79. Private Type GdiplusStartupInput
  80.     GdiplusVersion           As Long
  81.     DebugEventCallback       As Long
  82.     SuppressBackgroundThread As Long
  83.     SuppressExternalCodecs   As Long
  84. End Type
  85. Private Declare Function GdiplusStartup Lib "gdiplus" (Token As Long, inputbuf As GdiplusStartupInput, Optional ByVal outputbuf As Long = 0) As Long
  86. Private Declare Sub GdiplusShutdown Lib "gdiplus" (ByVal Token As Long)
  87. Private Declare Function GdipLoadImageFromFile Lib "gdiplus" (ByVal FileName As String, hImage As Long) As Long
  88. Private Declare Function GdipLoadImageFromStream Lib "gdiplus" (ByVal Stream As IUnknown, Image As Long) As Long
  89. Private Declare Function GdipGetImageBounds Lib "gdiplus.dll" (ByVal nImage As Long, srcRect As RECTF, srcUnit As Long) As Long
  90. Private Declare Function GdipDisposeImage Lib "gdiplus" (ByVal Image As Long) As Long
  91. Private Declare Function GdipCreateFromHDC Lib "gdiplus" (ByVal hDC As Long, hGraphics As Long) As Long
  92. Private Declare Function GdipDeleteGraphics Lib "gdiplus" (ByVal hGraphics As Long) As Long
  93. Private Declare Function GdipDrawImageRectRectI Lib "gdiplus" (ByVal hGraphics As Long, ByVal hImage As Long, ByVal dstX As Long, ByVal dstY As Long, ByVal dstWidth As Long, ByVal dstHeight As Long, ByVal SrcX As Long, ByVal SrcY As Long, ByVal srcWidth As Long, ByVal srcHeight As Long, ByVal srcUnit As Long, Optional ByVal imageAttributes As Long = 0, Optional ByVal Callback As Long = 0, Optional ByVal CallbackData As Long = 0) As Long
  94. Private Declare Function GdipGetImagePixelFormat Lib "gdiplus" (ByVal Image As Long, PixelFormat As Long) As Long
  95. Private Const UnitPixel As Long = &H2&
  96. Private Type RECTF
  97.     nLeft As Single
  98.     nTop As Single
  99.     nWidth As Single
  100.     nHeight As Single
  101. End Type
  102. ' used for workaround of VB not exposing IStream interface
  103. Private Declare Function CreateStreamOnHGlobal Lib "ole32" (ByVal hGlobal As Long, ByVal fDeleteOnRelease As Long, ppstm As Any) As Long
  104. Private Declare Function GlobalAlloc Lib "kernel32" (ByVal uFlags As Long, ByVal dwBytes As Long) As Long
  105. Private Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
  106. Private Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
  107. Private Declare Function GlobalSize Lib "kernel32" (ByVal hMem As Long) As Long
  108. Private Declare Function GetHGlobalFromStream Lib "ole32" (ByVal ppstm As Long, hGlobal As Long) As Long
  109. Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
  110. Private Declare Sub FillMemory Lib "kernel32.dll" Alias "RtlFillMemory" (ByRef Destination As Any, ByVal Length As Long, ByVal Fill As Byte)
  111. Private Type BITMAPINFOHEADER
  112.     biSize As Long
  113.     biWidth As Long
  114.     biHeight As Long
  115.     biPlanes As Integer
  116.     biBitCount As Integer
  117.     biCompression As Long
  118.     biSizeImage As Long
  119.     biXPelsPerMeter As Long
  120.     biYPelsPerMeter As Long
  121.     biClrUsed As Long
  122.     biClrImportant As Long
  123. End Type
  124. Private Type BITMAPINFO
  125.     bmiHeader As BITMAPINFOHEADER
  126.     bmiColors As Long
  127. End Type
  128. Public Function isGDIplusOk(Optional gdiToken As Long, Optional KeepToken As Boolean = False) As Boolean
  129.     ' Function starts GDI+ and returns true if no errors occurred
  130.     
  131.     ' does the system even have GDI+ on it?
  132.     If iparseValidateDLL("gdiplus.dll", "GdiplusStartup") Then
  133.         ' it does, so attempt to start GDI+
  134.         isGDIplusOk = InitializeGDIplus(gdiToken, False)
  135.         If Not KeepToken Then InitializeGDIplus gdiToken, True    ' shut it down
  136.     End If
  137. End Function
  138. Public Function SaveToPNG(FileName As String, outStream() As Byte, cHost As c32bppDIB, Optional GlobalToken As Long) As Boolean
  139.     ' Function uses GDI+ to create a PNG file or stream
  140.     ' Parameters:
  141.     ' FileName. If PNG is to be saved to file, provide the file name, otherwise PNG will be saved to array
  142.     ' outStream(). If FileName is vbNullString, then PNG is saved to this array, zero-bound
  143.     ' cHost. The c32bppDIB class containing the image to convert to PNG
  144.     Dim gdiToken As Long
  145.     
  146.     If cHost.Handle = 0& Then Exit Function
  147.     ' does the system have GDI+ on it?
  148.     If GlobalToken = 0 Then
  149.         If iparseValidateDLL("gdiplus.dll", "GdiplusStartup") = False Then Exit Function
  150.         If InitializeGDIplus(gdiToken, False) = False Then Exit Function
  151.     Else
  152.         gdiToken = GlobalToken
  153.     End If
  154.     
  155.     Dim hImg         As Long
  156.     Dim uEncCLSID(0 To 3) As Long
  157.     Dim IIStream As IUnknown
  158.     
  159.     
  160.     ' Note: GdipCreateBitmapFromGdiDib does not handle 32bpp DIBs correctly
  161.     Call GdipCreateBitmapFromScan0(cHost.Width, cHost.Height, cHost.scanWidth, PixelFormat32bppPARGB, ByVal cHost.BitsPointer, hImg)
  162.     
  163.     If Not hImg = 0& Then
  164.         On Error Resume Next
  165.         ' retrieve information GDI+ will use for conversion
  166.         If Not pvGetEncoderClsID("image/png", uEncCLSID) = 0& Then
  167.             ' dib is bottom up, scan0 does top down, so flip it
  168.             GdipImageRotateFlip hImg, 6& ' flip vertically
  169.             If FileName = vbNullString Then
  170.                 ' Saving to stream/array. Create a null stream (IUnknown object)
  171.                 Erase outStream
  172.                 Set IIStream = CreateStream(outStream)
  173.                 ' have GDI+ save the 32bpp image to the IUnknown in a PNG format
  174.                 If GdipSaveImageToStream(hImg, IIStream, uEncCLSID(0&), ByVal 0&) = 0& Then
  175.                     ' now we need to get that array to pass back to client
  176.                     ArrayFromStream IIStream, outStream()
  177.                     SaveToPNG = True
  178.                 End If
  179.             Else    ' saving to file
  180.                 ' Note: If you are calling this from outside the c32bppDIB class, the file
  181.                 ' must not exist; otherwise, the function fails.
  182.                 SaveToPNG = (GdipSaveImageToFile(hImg, StrConv(FileName, vbUnicode), uEncCLSID(0&), ByVal 0&) = 0&)
  183.             End If
  184.         End If
  185.         GdipDisposeImage hImg   ' clean up
  186.     End If
  187.     ' shut down GDI+
  188.     If GlobalToken = 0 Then Call InitializeGDIplus(gdiToken, True)
  189.     
  190. End Function
  191. Private Function pvPtrToStrW(ByVal lpsz As Long) As String
  192.   ' supporting routine for SaveToPNG; converts String Pointer to String
  193.   Dim sOut As String
  194.   Dim lLen As Long
  195.     lLen = lstrlenW(lpsz)
  196.     If (lLen > 0&) Then
  197.         sOut = StrConv(String$(lLen, vbNullChar), vbUnicode)
  198.         Call CopyMemory(ByVal sOut, ByVal lpsz, lLen * 2&)
  199.         pvPtrToStrW = StrConv(sOut, vbFromUnicode)
  200.     End If
  201.     
  202. End Function
  203. Private Function pvGetEncoderClsID(strMimeType As String, ClassID() As Long) As Long
  204.   ' supporting routine for SaveToPNG
  205.   Dim Num      As Long
  206.   Dim Size     As Long
  207.   Dim lIdx     As Long
  208.   Dim ICI()    As ImageCodecInfo
  209.   Dim Buffer() As Byte
  210.     
  211.     pvGetEncoderClsID = -1 ' Failure flag
  212.     
  213.     '-- Get the encoder array size
  214.     Call GdipGetImageEncodersSize(Num, Size)
  215.     If (Size = 0&) Then Exit Function ' Failed!
  216.     
  217.     '-- Allocate room for the arrays dynamically
  218.     ReDim ICI(1 To Num) As ImageCodecInfo
  219.     ReDim Buffer(1 To Size) As Byte
  220.     
  221.     '-- Get the array and string data
  222.     Call GdipGetImageEncoders(Num, Size, Buffer(1))
  223.     '-- Copy the class headers
  224.     Call CopyMemory(ICI(1), Buffer(1), (Len(ICI(1)) * Num))
  225.     
  226.     '-- Loop through all the codecs
  227.     For lIdx = 1& To Num
  228.         '-- Must convert the pointer into a usable string
  229.         If (StrComp(pvPtrToStrW(ICI(lIdx).MimeType), strMimeType, vbTextCompare) = 0) Then
  230.             CopyMemory ClassID(0), ICI(lIdx).ClassID(0), 16& ' Save the Class ID
  231.             pvGetEncoderClsID = lIdx      ' Return the index number for success
  232.             Exit For
  233.         End If
  234.     Next lIdx
  235.     '-- Free the memory
  236.     Erase ICI
  237.     Erase Buffer
  238. End Function
  239. Friend Function RenderGDIplus(cHost As c32bppDIB, ByVal hDC As Long, _
  240.                             ByVal Angle As Single, ByVal Alpha As Long, _
  241.                             ByVal destX As Long, ByVal destY As Long, _
  242.                             ByVal destWidth As Long, ByVal destHeight As Long, _
  243.                             ByVal SrcX As Long, ByVal SrcY As Long, _
  244.                             ByVal srcWidth As Long, ByVal srcHeight As Long, _
  245.                             ByVal highQuality As Boolean, _
  246.                             ByVal grayScale As eGrayScaleFormulas, _
  247.                             ByVal GlobalToken As Long, _
  248.                             Optional ByVal LightnessAdj As Single = 0!) As Boolean
  249.     ' Function renders a 32bpp to passed DC.
  250.     ' GDI+ can literally do most anything with an image; just gotta know how to set it up
  251.     
  252.     ' Parameters
  253.     ' c32bppDIB. Class containing image to render
  254.     ' hDC. The destination DC to render to
  255.     ' Angle. A value between -360 and 360 used for rotation. 0 is no rotation
  256.     ' Alpha. A value between 0 and 100 used for global tranparency. 100 is fully opaque
  257.     ' destX,Y. The top,left corner of the DC to render the image to
  258.     ' destWidth,Height. The target size of the rendered image
  259.     ' srcX,Y. The top,left corner of the image to be rendered
  260.     ' srcWidth,Height. The size of the source to be rendered
  261.     ' highQuality. If true, then BiCubic interpolation will be used, else NearestNeighbor will be used
  262.     ' grayScale. One of the eGrayScaleFormulas
  263.     ' GlobalToken. When provided it is a valid GDI token
  264.     ' LigthnessAdj. Percentage (-100 to 100) of more/less lightness for the image
  265.     
  266.     If Alpha = 0& Then
  267.         RenderGDIplus = True    ' full transparent, nothing to render
  268.         Exit Function
  269.     End If
  270.     
  271.     Dim gdiToken As Long
  272.     If GlobalToken = 0 Then
  273.         If InitializeGDIplus(gdiToken, False) = False Then Exit Function
  274.     Else
  275.         gdiToken = GlobalToken
  276.     End If
  277.     Dim hImg         As Long
  278.     Dim hGraphics As Long, hImgAttr As Long
  279.     Dim clrMatrix(0 To 4, 0 To 4) As Single
  280.     Dim mirrorROP As Long, mirrorOffsetX As Long, mirrorOffsetY As Long
  281.     
  282.     ' have GDI+ create a DIB from our host pointer, DIB will be mirrored vertically (upside down)
  283.     Call GdipCreateBitmapFromScan0(cHost.Width, cHost.Height, cHost.scanWidth, PixelFormat32bppPARGB, ByVal cHost.BitsPointer, hImg)
  284.     
  285.     If Not hImg = 0& Then
  286.         
  287.         If GdipCreateFromHDC(hDC, hGraphics) = 0& Then   ' wrap GDI+ around our target DC
  288.             
  289.             If Not hGraphics = 0& Then
  290.                 
  291.                 ' Interpolation quality?
  292.                 If highQuality = True Then
  293.                     Call GdipSetInterpolationMode(hGraphics, InterpolationModeHighQualityBicubic)
  294.                 Else ' Note: There is a 3rd quality which falls between these: InterpolationModeHighQualityBilinear
  295.                     Call GdipSetInterpolationMode(hGraphics, InterpolationModeNearestNeighbor)
  296.                 End If
  297.                 
  298.                 ' calculate flags/offsets if we are mirroring and/or rotating
  299.                 mirrorOffsetX = 1&                         ' positive angle rotation offset (X)
  300.                 If destHeight < 0& Then
  301.                     destHeight = -destHeight               ' no flipping needed; bottom up dibs are flipped vertically naturally
  302.                     mirrorOffsetY = -mirrorOffsetX         ' reverse angle rotation offset
  303.                 Else
  304.                     mirrorROP = 6&                         ' flip vertically
  305.                     mirrorOffsetY = mirrorOffsetX          ' positive angle rotation offsets(Y)
  306.                 End If
  307.                 If destWidth < 0& Then
  308.                     mirrorROP = mirrorROP Xor 4&           ' flip horizontally (mirror horizontally)
  309.                     destWidth = -destWidth
  310.                     mirrorOffsetX = -mirrorOffsetX         ' reverse angle rotation offset
  311.                 End If
  312.                 
  313.                 GdipImageRotateFlip hImg, mirrorROP        ' flip image as needed
  314.                 
  315.                 If Not ((grayScale = gsclNone) And (LightnessAdj = 0!)) Then
  316.                     ' grayscaling is in play
  317.                     If GdipCreateImageAttributes(hImgAttr) = 0 Then
  318.                         If Not grayScale = gsclNone Then
  319.                             Call iparseGrayScaleRatios(grayScale, clrMatrix(0, 0), clrMatrix(0, 1), clrMatrix(0, 2))
  320.                             clrMatrix(1, 0) = clrMatrix(0, 0)
  321.                             clrMatrix(2, 0) = clrMatrix(0, 0)
  322.                             clrMatrix(1, 1) = clrMatrix(0, 1)
  323.                             clrMatrix(2, 1) = clrMatrix(0, 1)
  324.                             clrMatrix(1, 2) = clrMatrix(0, 2)
  325.                             clrMatrix(2, 2) = clrMatrix(0, 2)
  326.                         Else
  327.                             clrMatrix(0, 0) = 1
  328.                             clrMatrix(1, 1) = 1
  329.                             clrMatrix(2, 2) = 1
  330.                         End If
  331.                         clrMatrix(3, 3) = 1 ' global alpha value
  332.                         clrMatrix(4, 4) = 1 ' required; cannot be anything else
  333.                         If Not LightnessAdj = 0! Then
  334.                             clrMatrix(0, 4) = LightnessAdj / 100    ' red added/subtracted brightness
  335.                             clrMatrix(1, 4) = clrMatrix(0, 4)       ' same for blue
  336.                             clrMatrix(2, 4) = clrMatrix(0, 4)       ' same for green
  337.                         End If
  338.                         If Not GdipSetImageAttributesColorMatrix(hImgAttr, ColorAdjustTypeBitmap, -1&, clrMatrix(0, 0), clrMatrix(0, 0), 0&) = 0& Then
  339.                             GdipDisposeImageAttributes hImgAttr
  340.                             hImgAttr = 0&
  341.                         End If
  342.                     End If
  343.                 End If
  344.                 
  345.                 If Angle = 0& And Alpha = 100& Then ' no blending and no rotation being used
  346.                     RenderGDIplus = (GdipDrawImageRectRectI(hGraphics, hImg, destX, destY, destWidth, destHeight, SrcX, SrcY, srcWidth, srcHeight, UnitPixel, hImgAttr, 0&, 0&) = 0&)
  347.                 
  348.                 Else ' we are blending and/or rotating
  349.                     
  350.                     If hImgAttr = 0& Then ' else grayscaling also & hImagAttr already created
  351.                         If GdipCreateImageAttributes(hImgAttr) = 0& Then ' create image attributes for blending/rotating
  352.                             clrMatrix(0, 0) = 1
  353.                             clrMatrix(1, 1) = 1
  354.                             clrMatrix(2, 2) = 1
  355.                             clrMatrix(4, 4) = 1 ' required; cannot be anything else
  356.                         End If
  357.                         If Not LightnessAdj = 0! Then
  358.                             clrMatrix(0, 4) = LightnessAdj / 100!   ' red added/subtracted brightness
  359.                             clrMatrix(1, 4) = clrMatrix(0, 4)       ' same for blue
  360.                             clrMatrix(2, 4) = clrMatrix(0, 4)       ' same for green
  361.                         End If
  362.                     End If
  363.                     ' Global Blending?
  364.                     clrMatrix(3, 3) = CSng(Alpha / 100&) ' value between 0 & 1
  365.                     
  366.                     If GdipSetImageAttributesColorMatrix(hImgAttr, ColorAdjustTypeBitmap, -1&, clrMatrix(0, 0), clrMatrix(0, 0), 0&) = 0& Then
  367.                         If Angle = 0& Then   ' not rotating
  368.                             RenderGDIplus = (GdipDrawImageRectRectI(hGraphics, hImg, destX, destY, destWidth, destHeight, SrcX, SrcY, srcWidth, srcHeight, UnitPixel, hImgAttr, 0&, 0&) = 0&)
  369.                             
  370.                         Else ' rotating & maybe blending too... different coordinates system used when rotating
  371.                         
  372.                             If GdipRotateWorldTransform(hGraphics, Angle + 180, 0&) = 0& Then
  373.                                 GdipTranslateWorldTransform hGraphics, destX + (destWidth  2) * mirrorOffsetX, destY + (destHeight  2) * mirrorOffsetY, 1&
  374.                             End If
  375.                             RenderGDIplus = (GdipDrawImageRectRectI(hGraphics, hImg, destWidth  2, destHeight  2, -destWidth, -destHeight, SrcX, SrcY, srcWidth, srcHeight, UnitPixel, hImgAttr, 0&, 0&) = 0&)
  376.                         End If
  377.                     End If
  378.                 End If
  379.                     
  380.                 If Not hImgAttr = 0& Then GdipDisposeImageAttributes hImgAttr ' clean up
  381.                 GdipDeleteGraphics hGraphics ' clean up
  382.                 
  383.             End If
  384.         End If
  385.         
  386.         GdipDisposeImage hImg   ' clean up
  387.         
  388.     End If
  389.     
  390.     If GlobalToken = 0 Then Call InitializeGDIplus(gdiToken, True) ' terminate GDI+
  391. End Function
  392. Friend Function GDIplusLoadPNG(FileName As String, pngStream() As Byte, cHost As c32bppDIB, Optional ByVal GlobalToken As Long) As Boolean
  393. 'Exit Function      ' un-rem to test/force PNG loading without GDI+
  394.     ' Purpose: Use GDI+ to load a PNG either by fileName or by array/stream
  395.     ' FileName :: if vbNullString, then the pngStream() array will contain
  396.     '             the PNG else FileName is full path & name of the PNG file
  397.     ' Note: FileName and/or pngStream() have been validated before this routine is called
  398.     
  399.     Dim gdiToken As Long
  400.     ' does the system have GDI+ on it?
  401.     If GlobalToken = 0 Then
  402.         If iparseValidateDLL("gdiplus.dll", "GdiplusStartup") = False Then Exit Function
  403.         If InitializeGDIplus(gdiToken, False) = False Then Exit Function
  404.     Else
  405.         gdiToken = GlobalToken
  406.     End If
  407.      
  408.     Dim hImage As Long, hGraphics As Long
  409.     Dim tDC As Long, lRtn As Long
  410.     Dim rDimensions As RECTF, pStream As IUnknown
  411.     
  412.     On Error GoTo ExitRoutine
  413.     
  414.     If FileName = vbNullString Then ' we need an array vs file name
  415.         ' hack of my own. Create an IUnknown Stream that has the same properties
  416.         ' and minimum methods needed as the IStream interface which VB does not
  417.         ' expose. Once the stream is created, we have GDI+ load from it
  418.         Set pStream = CreateStream(pngStream())
  419.         If Not pStream Is Nothing Then Call GdipLoadImageFromStream(pStream, hImage)
  420.     Else    ' we use the passed file name; have GDI+ load the file
  421.         Call GdipLoadImageFromFile(StrConv(FileName, vbUnicode), hImage)
  422.     End If
  423.     
  424.     If Not hImage = 0& Then
  425.         ' get size of PNG
  426.         lRtn = GdipGetImageBounds(hImage, rDimensions, UnitPixel)
  427.         If lRtn = 0& Then
  428.             ' build 32bpp
  429.             cHost.InitializeDIB CLng(rDimensions.nWidth), CLng(rDimensions.nHeight)
  430.             ' wrap a GDI+ DC around our DIB's DC
  431.             tDC = cHost.LoadDIBinDC(True)
  432.             lRtn = GdipCreateFromHDC(tDC, hGraphics)
  433.             If lRtn = 0& Then
  434.                 ' now draw the PNG into our 32bpp. GDI+ is nice enough to pre-multiply
  435.                 ' the RGB values for us during the rendering
  436.                 With rDimensions
  437.                     GdipDrawImageRectRectI hGraphics, hImage, 0&, 0&, .nWidth, .nHeight, .nLeft, .nTop, .nWidth, .nHeight, UnitPixel, 0&, 0&, 0&
  438.                 End With
  439.                 GdipDeleteGraphics hGraphics    ' remove the GDI+ DC wrapper
  440.                 hGraphics = 0&
  441.             End If
  442.             cHost.LoadDIBinDC False ' unselect our DIB
  443.         End If
  444.         If lRtn = 0& Then                    ' return results
  445.             GDIplusLoadPNG = True
  446.             Call GdipGetImagePixelFormat(hImage, lRtn)
  447.             GdipDisposeImage hImage             ' destroy the GDI+ image
  448.             cHost.Alpha = (lRtn = PixelFormat32bppARGB Or lRtn = PixelFormat32bppPARGB)
  449.             cHost.ImageType = imgPNG
  450.         Else
  451.             GdipDisposeImage hImage             ' destroy the GDI+ image
  452.             cHost.DestroyDIB
  453.         End If
  454.         hImage = 0&
  455.     End If
  456.         
  457. ExitRoutine:
  458.     If Not gdiToken = 0& Then
  459.         If Not hGraphics = 0& Then GdipDeleteGraphics hGraphics
  460.         If Not hImage = 0& Then GdipDisposeImage hImage
  461.         If GlobalToken = 0 Then Call InitializeGDIplus(gdiToken, True) ' stop GDI+
  462.     End If
  463. End Function
  464. Private Function ArrayFromStream(Stream As IUnknown, arrayBytes() As Byte) As Boolean
  465.     ' Purpose: Return the array contained in an IUnknown interface
  466.     
  467.     Dim o_hMem As Long, o_lpMem As Long
  468.     Dim o_lngByteCount As Long
  469.     
  470.     If Not Stream Is Nothing Then
  471.     
  472.         If GetHGlobalFromStream(ByVal ObjPtr(Stream), o_hMem) = 0 Then
  473.             o_lngByteCount = GlobalSize(o_hMem)
  474.             If o_lngByteCount > 0 Then
  475.                 o_lpMem = GlobalLock(o_hMem)
  476.                 If o_lpMem <> 0 Then
  477.                     ReDim arrayBytes(0 To o_lngByteCount - 1)
  478.                     CopyMemory arrayBytes(0), ByVal o_lpMem, o_lngByteCount
  479.                     GlobalUnlock o_hMem
  480.                     ArrayFromStream = True
  481.                 End If
  482.             End If
  483.         End If
  484.     End If
  485.     
  486. End Function
  487. Private Function CreateStream(byteContent() As Byte, Optional byteOffset As Long = 0&) As stdole.IUnknown
  488.     
  489.     ' Purpose: Create an IStream-compatible IUnknown interface containing the
  490.     ' passed byte aray. This IUnknown interface can be passed to GDI+ functions
  491.     ' that expect an IStream interface -- neat hack
  492.     
  493.     On Error GoTo HandleError
  494.     Dim o_lngLowerBound As Long
  495.     Dim o_lngByteCount  As Long
  496.     Dim o_hMem As Long
  497.     Dim o_lpMem  As Long
  498.      
  499.     If iparseIsArrayEmpty(VarPtrArray(byteContent)) = 0& Then ' create a growing stream as needed
  500.          Call CreateStreamOnHGlobal(0, 1, CreateStream)
  501.     Else                                        ' create a fixed stream
  502.          o_lngByteCount = UBound(byteContent) - byteOffset + 1
  503.          o_hMem = GlobalAlloc(&H2&, o_lngByteCount)
  504.          If o_hMem <> 0 Then
  505.              o_lpMem = GlobalLock(o_hMem)
  506.              If o_lpMem <> 0 Then
  507.                  CopyMemory ByVal o_lpMem, byteContent(byteOffset), o_lngByteCount
  508.                  Call GlobalUnlock(o_hMem)
  509.                  Call CreateStreamOnHGlobal(o_hMem, 1, CreateStream)
  510.              End If
  511.          End If
  512.      End If
  513.     
  514. HandleError:
  515. End Function
  516. Friend Function InitializeGDIplus(gToken As Long, ShutDown As Boolean) As Boolean
  517.     
  518.     ' function starts/stops GDI+
  519.     On Error Resume Next
  520.     If ShutDown Then
  521.         If Not gToken = 0& Then GdiplusShutdown gToken
  522.         
  523.     Else
  524.     
  525.         Dim gdiSI As GdiplusStartupInput
  526.         gdiSI.GdiplusVersion = 1
  527.         If GdiplusStartup(gToken, gdiSI) = 0& Then
  528.             InitializeGDIplus = True
  529.         Else
  530.             gToken = 0&
  531.         End If
  532.      
  533.     End If
  534.     If Err Then Err.Clear
  535.     
  536. End Function