Lazarus

Programming => Graphics and Multimedia => Graphics => Topic started by: user5 on September 06, 2020, 11:32:31 am

Title: Text anti aliasing
Post by: user5 on September 06, 2020, 11:32:31 am
    Does anyone know what the algorithms are for applying anti aliasing to block text and other shapes? I have seen the code on this forum for standard shapes, lines etc. but I'm talking about applying a TrueType kind of edge softening to images on video frames that can change and morph into any shape at all. Just by studying TrueType text edge softening up close I can see that the edge softening only applies to 'curved' portions of raster scan text images but I haven't got it all figured out yet.
Title: Re: Text anti aliasing
Post by: Handoko on September 06, 2020, 11:55:57 am
For lines, Xiaolin Wu's line algorithm:
https://stackoverflow.com/questions/3613130/simple-anti-aliasing-function-for-delphi-7#3613953
https://en.wikipedia.org/wiki/Xiaolin_Wu's_line_algorithm

For 3D objects, FSAA and multi sample anti-aliasing:
https://en.wikipedia.org/wiki/Spatial_anti-aliasing#Super_sampling_/_full-scene_anti-aliasing

For font, subpixel rendering:
https://szafranek.net/blog/2009/02/22/font-smoothing-explained/
Title: Re: Text anti aliasing
Post by: circular on September 06, 2020, 05:51:48 pm
Roughly explained, you need to draw the pictures 3 times as wide in grayscale. Then shrink it by assigning 3 values to one pixel into each channel (red, green, blue).
Title: Re: Text anti aliasing
Post by: user5 on September 07, 2020, 04:43:33 pm
    Thank you for your responses. I hope that what you say isn't over my head but I will check out Handoko's suggestions and ponder what circular said which I assume involves BGRABitmap and that's fine with me. I may have some questions again later if that's okay. By the way, I now think that BGRABitmap is more reliable than RawImage though the latter has its very useful applications.
Title: Re: Text anti aliasing
Post by: user5 on September 07, 2020, 05:09:13 pm
    I thought of something else. I was thinking about what circular said and it reminded of an edge softening sub-program that I've been working on which can also be used in reverse to do de-edging. It does its work in a way similar to what circular said, if I understand him correctly. This edging sub-program and another de-edging feature make the background shrink down (perfectly proportional) onto and into the foreground image which obliterates the previous anti aliasing so that it can be re-edged later. The great thing about this technique is that it preserves any existing internal edge softening. It would be nice to offer the user the ability to apply a TrueType kind of edge softening as well as the current ones. I will shortly check out your suggestions.
Title: Re: Text anti aliasing
Post by: Handoko on September 07, 2020, 05:39:59 pm
I believe what circular meant is subpixel rendering too.

Subpixel rendering is a bit too technical for me to understand. But it is interesting to see how it works:
https://en.wikipedia.org/wiki/Subpixel_rendering
Title: Re: Text anti aliasing
Post by: circular on September 07, 2020, 10:18:48 pm
Yes I am talking about sub pixel rendering.

Basically you have two things to consider:
- in a way, because the RGB channels are next to each other, the actual resolution of the screen is 3 times as wide. So a simple approach for example would be to render a grayscale image using each channel as a pixel. This kind of works but is not really nice, because of the second point:
- secondly, the color perceived depends on the 3 channels, so for example, if you have a thin line that would be 1 third of a pixel, of you change let's say only the red channel, then it would appear as a red line, even though you wanted a white line. To avoid this, you need to distribue the value to the adjacent channels.

Examples (values from 0 to 9)
grayscale     0    0    9             0     0    0
RGB            0    3    3             3     0    0
color         ---dark cyan--    ---dark red----
perceived         ----dark gray-----   -----black-----

you get some blurry effect though:
grayscale     0    0    0              9    9    9             0     0    0
RGB            0    0    3              6    9    6             3     0    0
color           ---dark blue---    ---pale green--      ---dark red----
perceived    --black--  ---pale orange/pale sky------   --black--

so probably you could get some mixed mechanism like:
grayscale     0    0    0              9    9    6             0     0    0
RGB gray     0    0    0              6    6    6             0     0    0   
remainder    0    0    0              3    3    0             0     0    0
RGB remain  0   0    1              2     2    1            0     0    0
RGB             0   0    1              8     8    7            0     0    0
color            --dkdkblue--       --cream---            ---black----
perceived     --black--   ----lightsilver----             ---black----
 
for a colored image as input, then you would need do that 3 times, one for each channel.
Title: Re: Text anti aliasing
Post by: winni on September 08, 2020, 12:46:32 am
Hi!

And I hope that @circulars explanation shows why AntiAliasing is such a thieve of CPU cycles. And so of time.

Winni
Title: Re: Text anti aliasing
Post by: user5 on September 08, 2020, 01:48:44 pm
    A picture says a thousand words and it might help if I show you exactly what I'm trying to do. I'm sorry that I didn't do this before. The attached pictures are of an Arial Bold TrueType font before and after edge softening has been applied. b1.gif shows a part of the letter B in raster scan mode. b2.gif shows that letter after anti aliasing has been applied. All I want to know is how to do that anti aliasing. I know that the algorithms and possibly the code for this exist somewhere because the edge softening exists.
    The bold letter B is just a type of shape and as a shape changes its form then its edging must also change. circular, thank you for the information though I'm unsure how to apply it. You know more about this than I do and I'm floundering a bit. b3.gif shows a different type of anti aliasing, something that I did on my own.
Title: Re: Text anti aliasing
Post by: user5 on September 08, 2020, 01:55:37 pm
    By the way, the anti aliasing shown in b2.gif was made by Lazarus! How does Lazarus do it?
Title: Re: Text anti aliasing
Post by: furious programming on September 08, 2020, 02:00:51 pm
By the way, the anti aliasing shown in b2.gif was made by Lazarus!

So how? Lazarus is an IDE, so please provide more details.

Maybe the better question is: how the TFont.Quality (https://lazarus-ccr.sourceforge.io/docs/lcl/graphics/tfont.quality.html) works and what causes it in LCL/widgetset?
Title: Re: Text anti aliasing
Post by: user5 on September 08, 2020, 02:55:22 pm
    I'll try. As the attached code shows, the user picks a font and then pastes in over the form some memo box text in the chosen anti aliased font. The text appears in a non-transparent, movable banner that can be made transparent if desired. It occurred to me that maybe Lazarus didn't do the anti aliasing. Maybe the font itself does the edge softening and Lazarus merely sends it along. I am working with BMPs and PNGs that need this TrueType kind of edge softening. If text can be anti aliased this way then this should be applicable to any shape. Can the Lazarus antialiasing property be applied to BMPs and PNGs? It seems to me if I tried that but it didn't work out.

 
Code: Pascal  [Select][+][-]
  1. //The user chooses a font.
  2. procedure TForm5.MenuItem14Click(Sender: TObject);
  3. begin
  4.  if FontDialog1.execute then
  5.   StaticText10.font := FontDialog1.font;
  6. end;
  7.  
  8. //The user displays memo text in the chosen font. The movable text appears over the form
  9. //in a non-transparent colored banner that can be made transparent.
  10. procedure TForm5.MenuItem17Click(Sender: TObject);
  11. var tempnum:integer;
  12.     tempstr1:string;
  13. begin
  14.   text12visible := true;
  15.   statictext10loaded := true;
  16.   StaticText10.Visible := true;
  17.   StaticText10.Left := 34;
  18.   StaticText10.Top := 62;
  19.   StaticText10.Caption := Memo1.Text;
  20.  
  21.   if (custom = false) then
  22.   begin
  23.    if (statictext10.left + statictext10.width) > (paintbox6.left + 263) then
  24.     begin
  25.      tempnum := (statictext10.left + statictext10.width) - (paintbox6.left + 263);
  26.      statictext10.width := statictext10.width - tempnum;
  27.     end;
  28.  
  29.    if (statictext10.top + statictext10.height) > (paintbox6.top + 202) then
  30.     begin
  31.      tempnum := (statictext10.top + statictext10.height) - (paintbox6.top + 202);
  32.      statictext10.height := statictext10.height - tempnum;
  33.     end;
  34.   end;
  35.  
  36.    if (custom) then
  37.     begin
  38.      statictext10.Width := statictext10origwidth;
  39.      statictext10.height := statictext10origheight;
  40.      if (statictext10.left + statictext10.width) > (paintbox6.left + 551) then
  41.       begin
  42.        tempnum := (statictext10.left + statictext10.width) - (paintbox6.left + 551);
  43.        statictext10.width := statictext10.width - tempnum;
  44.       end;
  45.  
  46.      if (statictext10.top + statictext10.height) > (paintbox6.top + 408) then
  47.       begin
  48.        tempnum := (statictext10.top + statictext10.height) - (paintbox6.top + 408);
  49.        statictext10.height := statictext10.height - tempnum;
  50.       end;
  51.     end;
  52.  
  53. statictext10.height := statictext10newheight;
  54. if (statictext10.top + statictext10.height) > (paintbox6.top + 408) then
  55.  begin
  56.   tempnum := (statictext10.top + statictext10.height) - (paintbox6.top + 408);
  57.   statictext10.height := statictext10.height - tempnum;
  58.  end
  59. else
  60.  statictext10.height := statictext10newheight;
  61. ArrangeText;
  62.  
  63. statictext10.font.Quality := fqAntialiased;
  64. form78.ShowSettings;
  65.  
  66. if (statictext10loaded = true) and (borderextended = true) and (custom = true) then
  67.  AdjustWidthNow('StaticText10');
  68.  
  69.  
  70. end;

Title: Re: Text anti aliasing
Post by: Handoko on September 08, 2020, 03:05:44 pm
It occurred to me that maybe Lazarus didn't do the anti aliasing.

If you use TStaticText you can set the quality:

Code: Pascal  [Select][+][-]
  1. type
  2.   TStaticText.Font.Quality = (fqDefault, fqDraft, fqProof, fqNonAntialiased, fqAntialiased,
  3.     fqCleartype, fqCleartypeNatural);

TCanvas.Font has such setting too.
Title: Re: Text anti aliasing
Post by: marcov on September 08, 2020, 04:15:26 pm
Search for "signed distance font" both on google and on this forum.  This is a GPU acceleratable technique, and there are sources (from me) on this forum.
Title: Re: Text anti aliasing
Post by: user5 on September 08, 2020, 04:28:54 pm

    I don't need apply this type of anti aliasing to just fonts and text. I need to apply it to TImages, bitmaps, bgrabitmaps, BMPs and PNGs like the program currently does using a different method.
    I'm talking about transparent TImages and bitmaps that have a foreground image surrounded by a solid color bacground that will flawlessly go transparent. The edging that the Lazarus program does now is applied to the foreground image based on what is UNDER the TImage, bmp, png etc. when the image background is transparent.
    Just by talking about this I may have a plan forming. The BGRABitmap edging sub-program currently does its obverse edging by comparing and mixing colors in a certain way but it occurred to me that maybe all I need do is simply modify it a bit to do TrueType anti aliasing. Apparently I will have to come up with those algorithms and code on my own and that will take more time. At least I have that as a fallback plan. The program can optionally go at an object from four directions to apply edging. I really do want this though it will take me away from other stuff that I want to do.
Title: Re: Text anti aliasing
Post by: circular on September 08, 2020, 05:23:52 pm
If you have the actual polygon definition, you can draw it in white in a TBGRABitmap, and then draw that mask with FillClearTypeMask function of the target TBGRABitmap.

If you only have the the aliased image, you can create an image containing a mask of the non-transparent pixels, and then you can determine the contour using BGRAVectorize. Then you can do an antialiased fill poly of that. Though that would not be ClearType because ClearType antialias is not implemented yet for polygons. If you come up with some code to do that, I would be happy to know.
Title: Re: Text anti aliasing
Post by: ChrisR on September 08, 2020, 09:35:51 pm
One solution to this problem would be to use OpenGL. The project  font_gl.lpi https://github.com/neurolabusc/Metal-Demos/tree/master/font (http://font_gl.lpi https://github.com/neurolabusc/Metal-Demos/tree/master/font) uses multi-channel signed distance field fonts. This allows nicely scalable, sharp looking text. This does require a custom shader. For bitmaps and lines, the multi-sampling built into OpenGL will anti-alias edges nicely.

To see the benefit of multisampling on lines, try the cube_gl.lpi project https://github.com/neurolabusc/Metal-Demos/tree/master/cube (http://cube_gl.lpi project https://github.com/neurolabusc/Metal-Demos/tree/master/cube) and compare the difference between the default
  ViewGPU1.MultiSampling:=4;
 versus
  ViewGPU1.MultiSampling:=1;
Title: Re: Text anti aliasing
Post by: user5 on September 10, 2020, 11:55:34 pm
    I'm working now on some code to do TrueType or semi-TrueType edge softening and at some point I may have to rotate the image. I plan to use BGRABitmap for the rotation but for purposes of illustration the code below uses TImage canvas pixels and it rotates the image -90 degrees. I've studied topics on rotation is this forum and on the Web but I haven't been able to get anything else to work correctly. I wouldn't be surprised if I'm doing something wrong. Anyway, is there a way to rotate the image 90 degrees clockwise back to its original position without having to go counter clockwise around the dial until the image is back to its first position?

   
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button23Click(Sender: TObject);
  2. var x,y:integer;
  3. begin
  4.  for y := 0 to (image13.height - 1) do
  5.   begin
  6.    for x := 0 to (image13.width - 1) do
  7.     begin
  8.  
  9.      image16.canvas.pixels[y,x] := image13.canvas.pixels[x,y];
  10.  
  11.     end;
  12.   end;
  13.  
  14. end;
Title: Re: Text anti aliasing
Post by: user5 on September 11, 2020, 12:10:46 am
    I'm working now on some code to do TrueType or semi-TrueType edge softening. At some point I may have to rotate the image. I plan to use BGRABitmap but for purposes of illustration the code below uses TImage canvas pixels and it rotates the image -90 degrees. I've studied topics on rotation is this forum and on the Web but I haven't been able to get anything else to work correctly. I wouldn't be surprised if I'm doing something wrong. Anyway, is there a way to rotate the image 90 degrees clockwise back to its original position without having to go counter clockwise around the dial until the image is back to its first position?

 
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button23Click(Sender: TObject);
  2. var x,y:integer;
  3. begin
  4.  for y := 0 to (image13.height - 1) do
  5.   begin
  6.    for x := 0 to (image13.width - 1) do
  7.     begin
  8.  
  9.      image16.canvas.pixels[y,x] := image13.canvas.pixels[x,y];
  10.  
  11.     end;
  12.   end;
  13.  
  14. end;

Title: Re: Text anti aliasing
Post by: winni on September 11, 2020, 12:50:14 am
Hi!

I show you a simple procedure to rotate a TBitmap clockwise and counterclockwise.
For demonstration purpose all with TBitmap - awful slow.

But it's easy to convert it to BGRAbitmap.

Take a Form, an Image >= 100x300, a Button.

And this 2 procedures:

Code: Pascal  [Select][+][-]
  1. function rotate90 (Source: TBitmap; clockwise: Boolean) : TBitmap;
  2. var dest : TBitmap;
  3.       x,y : Integer;
  4.       col : TColor;
  5. begin
  6. dest := TBitmap.create;
  7. dest.setSize (Source.height,source.width);
  8. for x := 0 to Source.width - 1 do
  9.   begin
  10.      for y := 0 to Source.Height - 1 do
  11.        begin
  12.        col := Source.Canvas.pixels[x,y];
  13.        if clockwise then dest.canvas.pixels[y, dest.Height-x-1] := col else
  14.             dest.Canvas.Pixels[dest.Width-y-1, x] := col;
  15.        end;//y
  16.      end; // x
  17.  result := dest;
  18. end; // proc
  19.  
  20.  
  21.  
  22.  
  23. procedure TForm1.TestClick(Sender: TObject);
  24.   var
  25.   bmp, rot, rot2 : TBitmap;
  26.  
  27. begin
  28. Image1.Canvas.FillRect(0,0,Image1.Width,Image1.Height);
  29. bmp := TBitmap.Create;
  30. bmp.setSize(50,80);
  31. bmp.Canvas.Pen.Color := clRed;
  32. bmp.Canvas.Line(0,0,bmp.width, bmp.Height);
  33. bmp.Canvas.brush.Color := clLime;
  34. bmp.Canvas.FillRect(0,0,10,10);
  35. image1.Canvas.Draw(0,0,bmp);
  36. rot := rotate90(bmp, true);
  37. Image1.Canvas.Draw(0,100,rot);
  38. rot2 := rotate90 (rot, false);
  39. Image1.Canvas.Draw(0,200,rot2);
  40. bmp.Free;
  41. rot.free;
  42. rot2.Free;
  43. end;
  44.  
  45.  

Happy rotating!

Winni
Title: Re: Text anti aliasing
Post by: circular on September 11, 2020, 01:41:39 am
@user5: in general, I suggest you avoid using Image.Canvas. The image component draw the bitmap it contains. So that is rather Image.Picture.Bitmap.Canvas or something like that. This image needs to be sized of course.

If you are just using the area to draw things, then TPaintBox makes more sense. There you have no bitmap, just the control's canvas.

Also note that you are not supposed to access the control's canvas outside of its OnPaint event. Even though can work on Windows and Linux, it never does on MacOS.
Title: Re: Text anti aliasing
Post by: winni on September 11, 2020, 02:12:33 am

Also note that you are not supposed to access the control's canvas outside of its OnPaint event. Even though can work on Windows and Linux, it never does on MacOS.

This true for all kind of visible canvas - but again:
This is NOT true for a TImage.

Winni
Title: Re: Text anti aliasing
Post by: Blaazen on September 11, 2020, 02:49:47 am
In fact, you can paint on TImage.Canvas at OnPaint event conditionally.
See code of TCustomImage.Paint:
Code: Pascal  [Select][+][-]
  1. begin
  2.   // detect loop
  3.   if FUseAncestorCanvas then exit;
  4.  
  5.   if csDesigning in ComponentState
  6.   then DrawFrame;
  7.  
  8.   if Picture.Graphic = nil
  9.   then Exit;
  10.  
  11.   C := inherited Canvas;
  12.   R := DestRect;
  13.   C.AntialiasingMode := FAntialiasingMode;
  14.   FPainting:=true;
  15.   try
  16.     if Assigned(FOnPaintBackground) then
  17.       FOnPaintBackground(Self, C, R);
  18.     C.StretchDraw(R, Picture.Graphic);
  19.   finally
  20.     FPainting:=false;
  21.   end;
  22.  
  23.   FUseAncestorCanvas := True;
  24.   try
  25.     inherited Paint;
  26.   finally
  27.     FUseAncestorCanvas := False;
  28.   end;
  29. end;

If Picture.Graphic is nil then there's exit, i.e. OnPaintBackground and OnPaint are not triggered at all.
Title: Re: Text anti aliasing
Post by: winni on September 11, 2020, 12:50:22 pm
Hi!

To clarify the situation with the TImage :

There are two different Canvas in a TImage:

The Canvas which is shown to you: Image.Canvas

And the Canvas of the persistent data in the picture, which maybe a Bitmap, a PNG, a JPG .

The Picture data like Image.Picture.PNG.Canvas are not visible to you.
If the the Canvases both are unlocked the data is exchanged between them.

The code shown by @Blaazen is the painting on the Background, the invisible data in the picture.

You can draw at any time on an Image without violating any rules.

Winni

Title: Re: Text anti aliasing
Post by: circular on September 11, 2020, 08:03:51 pm
Also note that you are not supposed to access the control's canvas outside of its OnPaint event. Even though can work on Windows and Linux, it never does on MacOS.
This true for all kind of visible canvas - but again:
This is NOT true for a TImage.
That's why I am specifying "control's canvas". Otherwise you can access the canvas of a bitmap anytime indeed. In the case of a TImage, that would be Image1.Picture.Bitmap.Canvas.
Title: Re: Text anti aliasing
Post by: user5 on September 24, 2020, 06:19:29 pm
    Hey everyone. Some of you recently helped me on my quest to achieve TrueType/ClearType/super Wu type of edge softening/anti aliasing. TrueType is Apple and ClearType is Microsoft. I am happy to report that the results are very encouraging to say the least. I'm talking about applying this kind of anti aliasing to all foreground shapes, text and images in pictures and videos. The edging of this new process is based on what pictures or videos are under the edged foreground image when the background surrounding that foreground image is made transparent, even if the edged picture or video frame is itself moving.
    The processing time it takes to apply this type of edging to videos is pretty slow but the quality of the results appears at this point to exceed my expectations. In addition to this, I'm also working on another new faster edging feature that will do semi-TrueType edging. All of these methods are designed to work only on raster scan foreground images on transparencies since any existing edge softening screws up the results. Thus, the de-edging tools I made remove existing anti aliasing so that it can be re-applied later after other work is done to improve the image and make it be truly and universally transparent. The program does all this graphically without relying on any existing standard algorithms using BGRABitmap fast pixel access. The reason that the former process is slow to process videos is due to the many passes that are made though each video frame and it would be impossible w/o BGRA. An interesting thing is that these methods can be applied to both solid color backgrounds and non-changing or changing muli-colored backgrounds.
    Anyway, all this has been made possible by Lazarus and the Forum and I thank you very much. I am excited about this. I was unsure whether to post this note here or in the third party section. I hope that posting it here is okay. I had hoped that some of the folks who helped me here in the graphics section would see this note since they took so much effort, patience and time to help me. They sure know their stuff. Much work remains but the hard part is done.
TinyPortal © 2005-2018