c32bppDIB: MakeOpaque does not work as expected
I'n using an image class named "pcMemDC". The variable is named "m_cMemDC".
It holds an image with transparent pixels.
I want to remove the transparency and make the transparent pixels white and save this opaque image as a PNG.
To do that, I use a LaVolpe's great c32bppDIB class, named "m_c32DIBBackground".
Code:
With m_c32DIBBackground
.ManageOwnDC = True
.InitializeDIB m_cMemDC.Width, m_cMemDC.Height 'I initialize it with the size of the source file
.Alpha = AlphaNone 'I don't want alpha
.CreateWhiteCanvas 'I create a white canvas
.MakeOpaque 'And again make sure it is opaque
m_cMemDC.Draw .hdc 'Now I draw the alpha image to the white opaque canvas.
.SaveToFile_PNG "d:\test1.png", False 'And save it out
End With
However, the resulting image has a black background instead of white.
I don't see where it goes wrong.
I even already suspected the problem in the other class, but I don't know:
Its "Draw" sub looks like this:
Code:
Public Sub Draw( _
ByVal uDstDc As Long, _
Optional ByVal xSrc As Long = 0, Optional ByVal ySrc As Long = 0, _
Optional ByVal WidthSrc As Long = 0, Optional ByVal HeightSrc As Long = 0, _
Optional ByVal xDst As Long = 0, Optional ByVal yDst As Long = 0 _
)
If WidthSrc <= 0 Then WidthSrc = m_lWidth
If HeightSrc <= 0 Then HeightSrc = m_lHeight
Dim lROP&
If Not m_bNoMirror Then
lROP = vbSrcCopy
Else
lROP = (vbSrcCopy Or NOMIRRORBITMAP)
End If
BitBlt uDstDc, xDst, yDst, WidthSrc, HeightSrc, m_hDC, xSrc, ySrc, lROP
End Sub
What am I doing wrong?
Re: c32bppDIB: MakeOpaque does not work as expected
Check the ".MakeOpaque" method, it's likely the problem is in there. You could also use "GetDIBits" to get an array of pixels from the bitmap, then change the alpha byte to 255 (white) and write the array back with "SetDIBits".
Re: c32bppDIB: MakeOpaque does not work as expected
Quote:
Originally Posted by
tmighty2
Code:
Public Sub Draw( _
ByVal uDstDc As Long, _
Optional ByVal xSrc As Long = 0, Optional ByVal ySrc As Long = 0, _
Optional ByVal WidthSrc As Long = 0, Optional ByVal HeightSrc As Long = 0, _
Optional ByVal xDst As Long = 0, Optional ByVal yDst As Long = 0 _
)
If WidthSrc <= 0 Then WidthSrc = m_lWidth
If HeightSrc <= 0 Then HeightSrc = m_lHeight
Dim lROP&
If Not m_bNoMirror Then
lROP = vbSrcCopy
Else
lROP = (vbSrcCopy Or NOMIRRORBITMAP)
End If
BitBlt uDstDc, xDst, yDst, WidthSrc, HeightSrc, m_hDC, xSrc, ySrc, lROP
End Sub
What am I doing wrong?
The above BitBlt-based Draw-method is not "Alpha-capable".
It neither respects a (potentially existing) AlphaChannel of "the Source-DIB" -
nor do you have a guarantee, that it leaves the AlphaChannel-Bytes of "the Destination-DIB" intact.
"GDI-wise",... only the AlphaBlend-GDI-API can handle that.
(in case the Source is a 32Bit-DIB with a proper Alpha-channel).
I'm also not quite sure, what you goal is...
Why would you want to write out something into a *.png, which priorily had "nice Alpha-Infos in it" -
(which are lost, after rendering this resource onto a solid, white Background).
FWIW, here's some code which requires an RC6-reference in your Project,
which shows how the task can be done with ease (although the comments raise the same question)...
Code:
Private Sub Form_Load()
'let's load an alpha-resource-surface - and also create a drawing-context on it in one line
With Cairo.ImageList.AddIconFromResourceFile("", "shell32", 167).CreateContext
'write out the just loaded Alpha-resource as a PNG with Alpha-channel
.Surface.WriteContentToPngFile "c:\temp\AlphaIcon.png"
'now we draw "a white UnderLay" on the just loaded resource-alpha-bytes of this surface(-context)
.Operator = CAIRO_OPERATOR_DEST_ATOP '...by telling the "Cairo-Blender" to switch what's "Destination and Source"
.Paint 1, Cairo.CreateSolidPatternLng(vbWhite) 'so that .Paint will now draw white underneath the already loaded Alpha-Bytes
'Ok, now we can visualize the result of the above "alpha-on-white"-operation (which all happened on this single-Pixel-surface)
Set Me.Picture = .Surface.Picture
'although the surface has now lost all its alpha-channel-info ... but we put it out as a PNG anyways
.Surface.WriteContentToPngFile "c:\temp\AlphaIcon_OnWhite.png"
End With
End Sub
HTH
Olaf
Re: c32bppDIB: MakeOpaque does not work as expected
Quote:
The above BitBlt-based Draw-method is not "Alpha-capable".
It neither respects a (potentially existing) AlphaChannel of "the Source-DIB" -
nor do you have a guarantee, that it leaves the AlphaChannel-Bytes of "the Destination-DIB" intact.
BitBlt/StretchBlt (and others which use raster operations) works with alpha channel according to the raster operation, so you can copy your alpha channel/set it/remove etc. using GDI functions.
Re: c32bppDIB: MakeOpaque does not work as expected
You MemDC.Draw method should be extended to accept ROP as a parameter so that you can use vbSrcPaint to OR blit source into all *black* target (not white) and *after* this call MakeOpaque (not before blitting).
Keep in mind that Raymond Chen’s technique for manipulating alpha channel is dubious for values other than 255 because 32-bit DIB are expected to be in precomputed alpha state i.e. for a pixel w/ alpha = 123 all the color components (R, G and B) cannot be more than 123 but blatantly OR blitting alpha values does *not* precompute color components so you might end up w/ invalid colors unless alpha being set is 255 which does not need precomputing so cannot render invalid colors per se.
Re: c32bppDIB: MakeOpaque does not work as expected
Quote:
Originally Posted by
The trick
That's interesting and might work (in the meantime, on newer Win-OSes only?) - but I was referring
to the Draw-method as posted (which had vbSrcCopy as the "hardwired" RasterOp-constant).
Also a "true PerPixel-AlphaBlending" via GDI (when the Src-DIB needs to be 32bpp - and contains Alpha-pre-multiplied-RGB-data),
is easiest (and fastest) to accomplish with the already mentioned AlphaBlend-API.
Trying to simulate the same render-output as "true PerPixel-AlphaBlending" -
via multiple BitBlt-calls (using different Raster-Op-Consts) -
is "adventurous" at best and I'd not recommend it.
Olaf
Re: c32bppDIB: MakeOpaque does not work as expected
BTW this is my old experiments with alpha and GDI. For example this allows to draw using VB6 native methods over alpha channel.
Re: c32bppDIB: MakeOpaque does not work as expected
Quote:
Originally Posted by
Schmidt
That's interesting and might work (in the meantime, on newer Win-OSes only?) - but I was referring
to the Draw-method as posted (which had vbSrcCopy as the "hardwired" RasterOp-constant).
Also a "true PerPixel-AlphaBlending" via GDI (when the Src-DIB needs to be 32bpp - and contains Alpha-pre-multiplied-RGB-data),
is easiest (and fastest) to accomplish with the already mentioned AlphaBlend-API.
Trying to simulate the same render-output as "true PerPixel-AlphaBlending" -
via multiple BitBlt-calls (using different Raster-Op-Consts) -
is "adventurous" at best and I'd not recommend it.
Olaf
I meant some GDI functions just process the alpha channel according to a raster operation. I didn't talk about blending. It works as least since WinXP.
Re: c32bppDIB: MakeOpaque does not work as expected
Here's some work I did to "see" an alpha channel with a standard PictureBox (not using GDI+).
Not sure if that helps or not though. EMF files can be a bit funky.
EDIT: Actually, I did use the GDI+ to read the PNG file.