I'm trying to implement a layered painting system inside one of our internal components and I have problems blending bitmaps containing text.
Following code fragment shows the problem:
uses
GR32;
procedure DrawBitmaps;
var
bmp1: TBitmap32;
bmp2: TBitmap32;
begin
bmp1 := TBitmap32.Create;
bmp1.Width := 100;
bmp1.Height := 100;
bmp1.FillRect(0, 0, 100, 100, clWhite32);
bmp1.FillRect(0, 0, 80, 80, clTrGreen32);
bmp1.Font.Size := -16;
bmp1.Font.Color := clBlack;
bmp1.TextOut(2, 10, 'Green');
bmp1.SaveToFile('c:\0\bmp1.bmp');
bmp2 := TBitmap32.Create;
bmp2.Width := 80;
bmp2.Height := 80;
bmp2.FillRect(0, 0, 80, 80, clTrRed32);
bmp2.Font.Size := -16;
bmp2.Font.Color := clBlack;
bmp2.TextOut(2, 50, 'Red');
bmp2.SaveToFile('c:\0\bmp2.bmp');
bmp2.DrawMode := dmBlend;
bmp2.DrawTo(bmp1, 20, 20);
bmp1.SaveToFile('c:\0\bmpcombined.bmp');
bmp1.Free;
bmp2.Free;
end;
Resulting images:
bmp1: bmp2: bmpcombined:
As you can see, text is painted in black on bmp
and bmp2
, but appears white on bmpcombined
.
I'm guessing the problem lies in TextOut
which maps to Windows.ExtTextOut
(via GR32_Backends_VCL.pas
, TGDIBackend.Textout
). That method doesn't handle transparency and paints text with alpha 00 (color is $000000 instead of $FF000000).
As a quick fix, setting bmp2.Font.Color
to $FF000000
doesn't help.
bmp2.Font.Color := TColor(clBlack32);
I am using fresh sources from GitHub
How should I paint a non-transparent text on a semi-transparent background so that I could blend this into a larger picture?
As far as I remember the TextOut function was only meant as a direct way to add some text to the bitmap, lacking all the fixes you mentioned above.
In order to remain full control over transparency you might want to use
procedure TBitmap32.RenderText(X, Y: Integer; const Text: string; AALevel: Integer; Color: TColor32);
instead.
It uses the techniques you mentioned in your own answer, but on a more sophisticated level. It also allows you to use anti-aliasing (based on oversampling), but today it's not actually recommended to use any other anti-aliasing technique other than what the font-engine outputs (to take full advantage of font-hinting).
As you are using the latest source code you could also consider to use VPR to render the text (see example 'TextVPR'). It converts the outline of the text as vectors and use the vector drawing capabilities of Graphics32 (by default the engine 'VPR' is used, hence the name) to render it onto the screen. There's also a stripped down engine of AGG included, which itself is based on the FreeType1 engine, which might be slightly faster for fonts.
Speaking of performance: Keep in mind that every other approach than TextOut will obviously decrease the performance. So if you aim for high performance might better cook your own code (based on TextOut).
Otherwise the TextVPR approach leaves you with more freedom, especially when it comes to filling the text (with a gradient for example) or transforming the text (to a curve or such).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With