I'm struggling to be able to draw a TBitmap
with transparency onto a TDirect2DCanvas
without losing the transparency.
Having created a TBitmap
which acts as the back-buffer for my drawing operation as follows:
bmp := TBitmap.Create;
bmp.Canvas.Brush.Handle := 0;
bmp.SetSize(100, 100);
bmp.Canvas.Brush.Color := clRed;
bmp.Transparent := true;
bmp.TransparentColor := clRed;
bmp.Canvas.Rectangle(bmp.Canvas.ClipRect);
bmp.Canvas.Pen.Color := clGreen;
bmp.Canvas.Ellipse(bmp.Canvas.ClipRect);
I then need to draw it onto my TDirect2DCanvas
, however the following draws the TBitmap
but removes all transparency - the background colour is drawn as red whereas if I just draw onto the TForm.Canvas
then the background is transparent.
// Drawing onto the TDirect2DCanvas results in a red background
AEventArgs.Canvas.Draw(0, 0, bmp);
// Drawing onto the TForm.Canvas gives the correct result
Self.Canvas.Draw(0, 0, bmp);
My understanding now leads me on to ID2D1Bitmap
and IWICBitmap
interfaces, so, I can attempt to create an ID2D1Bitmap
from the TBitmap
using the following code (and assuming that the pixel format is copied across):
var
bmp : TBitmap;
temp : ID2D1Bitmap;
begin
// Code to initialize the TBitmap goes here (from above)
// Create an ID2D1Bitmap from a TBitmap
temp := AEventArgs.Canvas.CreateBitmap(bmp);
// Draw the ID2D1Bitmap onto the TDirect2DCanvas
AEventArgs.Canvas.RenderTarget.DrawBitmap(temp);
Now that I have an ID2D1Bitmap
, the result is still the same - a red background with no transparency. I guess its entirely feasible that the Direct2D side of things uses a different method for transparency but looking at the propertys of the ID2D1Bitmap
provides no clues.
My next guess is to go down the IWICBitmap
interface.
Ultimately, my question is: is there a more straightforward or obvious thing that I've missed from the above which would allow the transparent TBitmap
to be drawn onto the TDirect2DCanvas
surface? Or is all this pain necessary in order to maintain the transparency?
Update
Ok, so after doing a bit more digging around, I can now convert the TBitmap
to an IWICBitmap
and then onto an ID2D1Bitmap
however the issue still remains - transparency which is present in the TBitmap
is not copied through when rendering to the TDirect2DCanvas
.
// Create the IWICBitmap from the TBitmap
GetWICFactory.CreateBitmapFromHBITMAP(bmp.Handle, bmp.Palette, WICBitmapUsePremultipliedAlpha, wic);
wic.GetPixelFormat(pif);
// The PixelFormat is correct as `GUID_WICPixelFormat32bppPBGRA` which is
// B8G8R8A8_UNORM and PREMULTIPLIED
// Create the IWICFormatConverter
GetWICFactory.CreateFormatConverter(fc);
fc.Initialize(wic, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, nil, 0.0, WICBitmapPaletteTypeCustom);
// Now, create the ID2D1Bitmap
AEventArgs.Canvas.RenderTarget.CreateBitmapFromWicBitmap(fc, nil, temp);
temp.GetPixelFormat(fmt);
// Here, PixelFormat is correct matching the PixelFormat from the IWICBitmap
// Draw the bitmap to the Canvas
AEventArgs.Canvas.RenderTarget.DrawBitmap(temp);
And the result is still a non-transparent bitmap.
So the final thing I've looked into is the PixelFormat of the ID2D1RenderTarget which is the underlying render target of the TDirect2DCanvas.
// Create the canvas
fCanvas := TDirect2DCanvas.Create(Self.Handle);
fCanvas.RenderTarget.GetPixelFormat(pf);
// This gives me a PixelFormat of
// B8G8R8A8_UNORM but D2D1_ALPHA_MODE_IGNORE
So I'm guessing that the real issue is to do with the fact that the ID2D1RenderTarget
PixelFormat is ignoring the alpha.
TransparentStretchBlt
in 'graphics'). – Sertac Akyuz