Jump to content
Steve Maughan

Combining bitmaps and preserving antialiased text quality...

Recommended Posts

In my mapping application I need to merge different layers together to create the map. 

 

Question: how do I merge a bitmap with anti-aliased text with a bitmap showing a multi-colored image? Is there a way to draw the anti-aliased text on a bitmap with the alpha channel enabled and then have the transparency preserved / respected when it is combined with the other bitmap?

 

Here's a simple example that shows the problem (code attached to this message):

procedure TForm2.FormPaint(Sender: TObject);
var
  f: TBitmap;
  b: TBitmap;
  x, y: integer;
  xText: string;
  xWidth, xHeight: integer;
begin

  //-- Size of image
  xWidth := Form2.Width;
  xHeight := Form2.Height;

  //-- Create the background bitmap
  f := TBitmap.Create;
  f.PixelFormat := pf32bit;
  f.SetSize(xWidth, xHeight);
  f.Canvas.Brush.Color := clFuchsia;
  f.Canvas.FillRect(f.Canvas.ClipRect);

  //-- Create the bitmap with the text
  b := TBitmap.Create;
  b.PixelFormat := pf32bit;
  b.Canvas.Brush.Color := clWhite;
  b.SetSize(xWidth, xHeight);

  b.Canvas.Font.Size := 32;
  b.Canvas.Font.Color := clBlack;
  b.Canvas.Font.Quality := TFontQuality.fqDefault;

  //-- Draw the text
  xText := 'Delphi 25th';
  x := (b.Width - b.Canvas.TextWidth(xText)) div 2;
  y := (b.Height - b.Canvas.TextHeight(xText)) div 2;
  b.Canvas.TextOut(x, y, xText);

  //-- Transfer the text layer to the background
  TransparentBlt(f.Canvas.Handle, 0, 0, xWidth, xHeight, b.Canvas.Handle, 0, 0, xWidth, xHeight, clWhite);

  //-- Transfer to the form's canvas
  Form2.Canvas.CopyRect(Form2.Canvas.ClipRect, f.Canvas, f.Canvas.ClipRect);

  b.Free;
  f.Free;
end;

This results in the following screen (also attached to this message):

 

https://ibb.co/GVWRZ6Y

 

You can see the ugly white around the text due to the anti-aliasing. Currently I use non anti-aliased text, but that also looks blocky and ugly too.

 

Thanks and Happy Delphi 25th!

 

Steve

 

2020-02-14_9-02-57.png

Anti-Aliased-Text.zip

Share this post


Link to post
33 minutes ago, Vandrovnik said:

Recently I have changed drawing to Direct2D, where transparency is not a problem.

Interesting — how would you accomplish what I'd like to do using Direct2D?

 

Thanks, Steve

Share this post


Link to post

Hi Vandrovnik — I'm aware of the basics of Difect2D, but how could I merge two Direct2D canvases and preserve the anti-aliasing of the text? If I'm not mistaken this isn't easy using Direct2D (but I'm far from being an expert on this).

 

Thanks again, Steve

Share this post


Link to post

In general you can't do this. Anti-aliasing requires knowledge of the background at the point where the text is rendered. If the original background is a single colour then it may be possible, but will require clever processing. What you ought to do is simply render the text again on the new background. 

  • Like 1

Share this post


Link to post
Just now, David Heffernan said:

In general you can't do this. Anti-aliasing requires knowledge of the background at the point where the text is rendered. If the original background is a single colour then it may be possible, but will require clever processing. What you ought to do is simply render the text again on the new background. 

Thanks David — this is what is feared. I had hoped it would act like a PNG with transparency at the pixel level.

 

Cheers, Steve

Share this post


Link to post

I would just use Graphics32 but you can do it with regular TBitmap's - it's just more work.

What you do is draw white text onto a black bitmap. Make sure ClearType anti aliasing is disabled or you will get artifacts. Use regular greyscale anti aliasing instead.

This bitmap can now be merged (RGB only, there's no alpha) directly onto the destination bitmap or it can be used as an alpha mask to draw in any color or pattern. To use it as an alpha mask you just transfer any of the R, G or B values (they're the same) to the A channel and then reset the RGB to whatever color you want.

Share this post


Link to post
2 hours ago, Steve Maughan said:

Hi Vandrovnik — I'm aware of the basics of Difect2D, but how could I merge two Direct2D canvases and preserve the anti-aliasing of the text? If I'm not mistaken this isn't easy using Direct2D (but I'm far from being an expert on this).

 

Thanks again, Steve

Hello, as David already wrote - just render the text on the map, there is no need to render it to a bitmap and then merge bitmaps.

Do you need to print the result? Because that was a pain with Direct2D and Delphi 😕

Share this post


Link to post
30 minutes ago, Vandrovnik said:

just render the text on the map, there is no need to render it to a bitmap and then merge bitmaps.

That will not preserve the alpha.

Share this post


Link to post
2 hours ago, Anders Melander said:

I would just use Graphics32 but you can do it with regular TBitmap's - it's just more work.

What you do is draw white text onto a black bitmap. Make sure ClearType anti aliasing is disabled or you will get artifacts. Use regular greyscale anti aliasing instead.

This bitmap can now be merged (RGB only, there's no alpha) directly onto the destination bitmap or it can be used as an alpha mask to draw in any color or pattern. To use it as an alpha mask you just transfer any of the R, G or B values (they're the same) to the A channel and then reset the RGB to whatever color you want.

Hi Anders - this sound like what I need. Do you know of any code snippets?

 

Thanks,

 

Steve

Share this post


Link to post
uses Direct2D;

procedure TMainForm.PaintBox1Paint(Sender: TObject);
 var D2Canvas: TDirect2DCanvas;
 begin
 D2Canvas:=TDirect2DCanvas.Create(PaintBox1.Canvas, PaintBox1.ClientRect);
 try
  D2Canvas.BeginDraw;
  try
   D2Canvas.Brush.Style:=bsSolid;
   D2Canvas.Brush.Color:=clFuchsia;
   D2Canvas.FillRect(PaintBox1.ClientRect);
   D2Canvas.Font.Size:=32;
   D2Canvas.Font.Color:=clBlack;
   D2Canvas.TextOut(100, 100, 'Delphi 25th');
  finally
   D2Canvas.EndDraw;
  end;
 finally
  FreeAndNil(D2Canvas);
 end;
end;

This is not OK?

d2d.png

Share this post


Link to post
24 minutes ago, Steve Maughan said:

Do you know of any code snippets?

It's left as an exercise for the student 🙂

The only code I have is a 10 year old example I once made in the Graphics32 newsgroup to demonstrate why cleartype AA shouldn't be used with the technique I described.

Code and executable attached. Note that the code probably requires a 10 year old version of Graphics32 to compile.

 

Here's the screenshots that accompanied the example (Looks like Win XP :classic_wacko:😞

 

Shows regular text output with no blending.
ClearType artifacts are clearly visible because of scaling. This is expected.

AA-opaque.thumb.png.78c2e50d61a34422f0122dd1af43c3c1.png

 

Shows text output with alpha blending. Alpha is calculated from a single channel.
Alpha blended Gray Scale AA is identical to opaque Gray Scale AA.
Alpha blended ClearType AA shows asymmetry.

AA-blend1channel.thumb.png.a0b0faf639527dabebb60c97030d90f3.png

 

Shows text output with alpha blending. Alpha is calculated from all three channels.
Alpha blended Gray Scale AA is identical to opaque Gray Scale AA.
Alpha blended ClearType AA is symmetric, but lacks detail.

AA-blend3channels.thumb.png.13c3952ffa5825fcfe4c1c0d043adf89.png

 

 

amAAtest.zip

AAtest.zip

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×