Skip to content

Commit 623adc7

Browse files
committed
Handle transparent hDIBs from VbPng
1 parent 8f036ba commit 623adc7

File tree

1 file changed

+103
-50
lines changed

1 file changed

+103
-50
lines changed

src/AlphaBlendImage.ctl

+103-50
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ Private Const InterpolationModeHighQualityBicubic As Long = 7
5858
Private Const MatrixOrderAppend As Long = 1
5959

6060
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpDst As Any, lpSrc As Any, ByVal ByteLength As Long)
61+
Private Declare Function ArrPtr Lib "msvbvm60" Alias "VarPtr" (Ptr() As Any) As Long
6162
Private Declare Function OleTranslateColor Lib "oleaut32" (ByVal lOleColor As Long, ByVal lHPalette As Long, ByVal lColorRef As Long) As Long
6263
Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hDC As Long) As Long
6364
Private Declare Function DeleteDC Lib "gdi32" (ByVal hDC As Long) As Long
@@ -73,6 +74,8 @@ Private Declare Function CreateBitmap Lib "gdi32" (ByVal nWidth As Long, ByVal n
7374
Private Declare Function CreateIconIndirect Lib "user32" (pIconInfo As ICONINFO) As Long
7475
Private Declare Function DestroyIcon Lib "user32" (ByVal hIcon As Long) As Long
7576
Private Declare Function SHCreateMemStream Lib "shlwapi" Alias "#12" (ByRef pInit As Any, ByVal cbInit As Long) As IUnknown
77+
Private Declare Function CreateSolidBrush Lib "gdi32" (ByVal clrColor As Long) As Long
78+
Private Declare Function FillRect Lib "user32" (ByVal hDC As Long, lpRect As RECT, ByVal hBrush As Long) As Long
7679
'--- gdi+
7780
Private Declare Function GdiplusStartup Lib "gdiplus" (hToken As Long, pInputBuf As Any, Optional ByVal pOutputBuf As Long = 0) As Long
7881
Private Declare Function GdipCreateBitmapFromScan0 Lib "gdiplus" (ByVal lWidth As Long, ByVal lHeight As Long, ByVal lStride As Long, ByVal lPixelFormat As Long, ByVal Scan0 As Long, hBitmap As Long) As Long
@@ -125,6 +128,23 @@ Private Type PICTDESC
125128
hPal As Long
126129
End Type
127130

131+
Private Type SAFEARRAY1D
132+
cDims As Integer
133+
fFeatures As Integer
134+
cbElements As Long
135+
cLocks As Long
136+
pvData As Long
137+
cElements As Long
138+
lLbound As Long
139+
End Type
140+
141+
Private Type RECT
142+
Left As Long
143+
Top As Long
144+
Right As Long
145+
Bottom As Long
146+
End Type
147+
128148
'=========================================================================
129149
' Constants and member variables
130150
'=========================================================================
@@ -629,87 +649,98 @@ Private Function pvPreparePicture(oPicture As StdPicture, ByVal clrMask As OLE_C
629649
Dim hMemDC As Long
630650
Dim uInfo As ICONINFO
631651
Dim baColorBits() As Byte
632-
Dim bHasAlpha As Boolean
633652
Dim hDib As Long
634653
Dim lpBits As Long
635654
Dim hPrevDib As Long
636-
Dim lIdx As Long
637655
Dim pPic As IPicture
656+
Dim hBrush As Long
657+
Dim rc As RECT
638658

639659
On Error GoTo EH
640660
If Not oPicture Is Nothing Then
641661
If oPicture.Handle <> 0 Then
642-
Select Case oPicture.Type
643-
Case vbPicTypeBitmap
644-
If GdipCreateBitmapFromHBITMAP(oPicture.Handle, 0, hNewBitmap) <> 0 Then
662+
lWidth = HM2Pix(oPicture.Width)
663+
lHeight = HM2Pix(oPicture.Height)
664+
hMemDC = CreateCompatibleDC(0)
665+
If hMemDC = 0 Then
666+
GoTo QH
667+
End If
668+
With uHdr
669+
.biSize = Len(uHdr)
670+
.biPlanes = 1
671+
.biBitCount = 32
672+
.biWidth = lWidth
673+
.biHeight = -lHeight
674+
.biSizeImage = (4 * lWidth) * lHeight
675+
End With
676+
If oPicture.Type = vbPicTypeIcon Then
677+
If GetIconInfo(oPicture.Handle, uInfo) = 0 Then
645678
GoTo QH
646679
End If
647-
If clrMask <> -1 Then
648-
If GdipCreateImageAttributes(hNewAttributes) <> 0 Then
680+
ReDim baColorBits(0 To uHdr.biSizeImage - 1) As Byte
681+
If GetDIBits(hMemDC, uInfo.hbmColor, 0, lHeight, baColorBits(0), uHdr, DIB_RGB_COLORS) = 0 Then
682+
GoTo QH
683+
End If
684+
If Not pvHasAlpha(VarPtr(baColorBits(0)), uHdr.biSizeImage) Then
685+
'--- note: GdipCreateBitmapFromHICON is working ok for old-style (single-bit) transparent icons only
686+
If GdipCreateBitmapFromHICON(oPicture.Handle, hNewBitmap) <> 0 Then
649687
GoTo QH
650688
End If
651-
If GdipSetImageAttributesColorKeys(hNewAttributes, 0, 1, TranslateColor(clrMask), TranslateColor(clrMask)) <> 0 Then
689+
Else
690+
If GdipCreateBitmapFromScan0(lWidth, lHeight, 4 * lWidth, PixelFormat32bppPARGB, VarPtr(baColorBits(0)), hTempBitmap) <> 0 Then
691+
GoTo QH
692+
End If
693+
If GdipCloneBitmapAreaI(0, 0, lWidth, lHeight, PixelFormat32bppARGB, hTempBitmap, hNewBitmap) <> 0 Then
652694
GoTo QH
653695
End If
654696
End If
655-
Case Else
656-
lWidth = HM2Pix(oPicture.Width)
657-
lHeight = HM2Pix(oPicture.Height)
658-
hMemDC = CreateCompatibleDC(0)
659-
If hMemDC = 0 Then
697+
Else
698+
hDib = CreateDIBSection(hMemDC, uHdr, DIB_RGB_COLORS, lpBits, 0, 0)
699+
If hDib = 0 Then
660700
GoTo QH
661701
End If
662-
With uHdr
663-
.biSize = Len(uHdr)
664-
.biPlanes = 1
665-
.biBitCount = 32
666-
.biWidth = lWidth
667-
.biHeight = -lHeight
668-
.biSizeImage = (4 * lWidth) * lHeight
669-
End With
670-
If oPicture.Type = vbPicTypeIcon Then
671-
If GetIconInfo(oPicture.Handle, uInfo) = 0 Then
672-
GoTo QH
673-
End If
674-
ReDim baColorBits(0 To uHdr.biSizeImage - 1) As Byte
675-
If GetDIBits(hMemDC, uInfo.hbmColor, 0, lHeight, baColorBits(0), uHdr, DIB_RGB_COLORS) = 0 Then
676-
GoTo QH
677-
End If
678-
For lIdx = 3 To UBound(baColorBits) Step 4
679-
If baColorBits(lIdx) <> 0 Then
680-
bHasAlpha = True
681-
Exit For
682-
End If
683-
Next
684-
If Not bHasAlpha Then
685-
'--- note: GdipCreateBitmapFromHICON working ok for old-style (single-bit) transparent icons only
686-
If GdipCreateBitmapFromHICON(oPicture.Handle, hNewBitmap) <> 0 Then
702+
hPrevDib = SelectObject(hMemDC, hDib)
703+
If oPicture.Type = vbPicTypeMetafile Or oPicture.Type = vbPicTypeEMetafile Then
704+
clrMask = vbMagenta
705+
End If
706+
If clrMask <> -1 Then
707+
Call OleTranslateColor(clrMask, 0, VarPtr(clrMask))
708+
hBrush = CreateSolidBrush(clrMask)
709+
rc.Right = lWidth
710+
rc.Bottom = lHeight
711+
Call FillRect(hMemDC, rc, hBrush)
712+
Call DeleteObject(hBrush)
713+
End If
714+
Set pPic = oPicture
715+
pPic.Render hMemDC, 0, 0, lWidth, lHeight, 0, oPicture.Height, oPicture.Width, -oPicture.Height, ByVal 0
716+
If Not pvHasAlpha(lpBits, uHdr.biSizeImage) Then
717+
'--- note: GdipCreateBitmapFromHBITMAP is working ok for non-transparent bitmaps
718+
If oPicture.Type = vbPicTypeBitmap Then
719+
If GdipCreateBitmapFromHBITMAP(oPicture.Handle, oPicture.hPal, hNewBitmap) <> 0 Then
687720
GoTo QH
688721
End If
689722
Else
690-
If GdipCreateBitmapFromScan0(lWidth, lHeight, 4 * lWidth, PixelFormat32bppPARGB, VarPtr(baColorBits(0)), hTempBitmap) <> 0 Then
691-
GoTo QH
692-
End If
693-
If GdipCloneBitmapAreaI(0, 0, lWidth, lHeight, PixelFormat32bppARGB, hTempBitmap, hNewBitmap) <> 0 Then
723+
If GdipCreateBitmapFromHBITMAP(hDib, 0, hNewBitmap) <> 0 Then
694724
GoTo QH
695725
End If
696726
End If
697727
Else
698-
hDib = CreateDIBSection(hMemDC, uHdr, DIB_RGB_COLORS, lpBits, 0, 0)
699-
If hDib = 0 Then
700-
GoTo QH
701-
End If
702-
hPrevDib = SelectObject(hMemDC, hDib)
703-
Set pPic = oPicture
704-
pPic.Render hMemDC, 0, 0, lWidth, lHeight, 0, oPicture.Height, oPicture.Width, -oPicture.Height, ByVal 0
705728
If GdipCreateBitmapFromScan0(lWidth, lHeight, 4 * lWidth, PixelFormat32bppPARGB, lpBits, hTempBitmap) <> 0 Then
706729
GoTo QH
707730
End If
708731
If GdipCloneBitmapAreaI(0, 0, lWidth, lHeight, PixelFormat32bppARGB, hTempBitmap, hNewBitmap) <> 0 Then
709732
GoTo QH
710733
End If
711734
End If
712-
End Select
735+
End If
736+
If clrMask <> -1 Then
737+
If GdipCreateImageAttributes(hNewAttributes) <> 0 Then
738+
GoTo QH
739+
End If
740+
If GdipSetImageAttributesColorKeys(hNewAttributes, 0, 1, TranslateColor(clrMask), TranslateColor(clrMask)) <> 0 Then
741+
GoTo QH
742+
End If
743+
End If
713744
End If
714745
End If
715746
'--- commit
@@ -789,6 +820,28 @@ Private Sub pvHandleMouseDown(Button As Integer, Shift As Integer, X As Single,
789820
m_sngDownY = Y
790821
End Sub
791822

823+
Private Function pvHasAlpha(ByVal lPtr As Long, ByVal lSize As Long) As Boolean
824+
Dim uArray As SAFEARRAY1D
825+
Dim baBuffer() As Byte
826+
Dim lIdx As Long
827+
828+
With uArray
829+
.cDims = 1
830+
.fFeatures = 1 ' FADF_AUTO
831+
.cbElements = 1
832+
.pvData = lPtr
833+
.cElements = lSize
834+
End With
835+
Call CopyMemory(ByVal ArrPtr(baBuffer), VarPtr(uArray), 4)
836+
For lIdx = 3 To UBound(baBuffer) Step 4
837+
If baBuffer(lIdx) <> 0 Then
838+
pvHasAlpha = True
839+
Exit Function
840+
End If
841+
Next
842+
End Function
843+
844+
792845
'= common ================================================================
793846

794847
Private Function pvCreateDib(ByVal hMemDC As Long, ByVal lWidth As Long, ByVal lHeight As Long, hDib As Long) As Boolean

0 commit comments

Comments
 (0)