Recent

Author Topic: How can I drawing text with outline on a canvas?  (Read 4574 times)

HudchewMan

  • New member
  • *
  • Posts: 9
How can I drawing text with outline on a canvas?
« on: January 22, 2018, 07:49:40 pm »
Help me please.

I try to find the way to drawing text with outline on a canvas. But not found. :(
(Google with keyword 'Lazarus draw text outline' and another similar this.)

so I try to repeat write text around it but it's look very ugly. :o :'(

This is example of my code.

Code: Pascal  [Select]
  1. procedure TForm1.FormPaint(Sender: TObject);
  2. var
  3.   textarea: TRect;
  4.   mytext: string;
  5.   mytextstyle: TTextStyle;
  6.  
  7. begin
  8.   Canvas.GradientFill(Self.ClientRect, clNavy, clGreen, gdHorizontal);
  9.  
  10.   mytext      := 'Hello the world, Who am I.';
  11.   textarea    := Rect(20, Self.Height - 80, Self.Width - 20, Self.Height - 10);
  12.   mytextstyle := Canvas.TextStyle;
  13.   mytextstyle.Wordbreak  := False;
  14.   mytextstyle.SingleLine := True;
  15.  
  16.   Canvas.Font.Size  := 16;
  17.  
  18.   // Border
  19.   Canvas.Font.Color := clWhite;
  20.   Canvas.TextRect(textarea, 20 - 3, Self.Height - 80 - 0, mytext, mytextstyle);
  21.   Canvas.TextRect(textarea, 20 + 3, Self.Height - 80 + 0, mytext, mytextstyle);
  22.   Canvas.TextRect(textarea, 20 + 0, Self.Height - 80 - 3, mytext, mytextstyle);
  23.   Canvas.TextRect(textarea, 20 - 0, Self.Height - 80 + 3, mytext, mytextstyle);
  24.  
  25.   Canvas.TextRect(textarea, 20 - 3, Self.Height - 80 - 3, mytext, mytextstyle);
  26.   Canvas.TextRect(textarea, 20 + 3, Self.Height - 80 + 3, mytext, mytextstyle);
  27.   Canvas.TextRect(textarea, 20 + 3, Self.Height - 80 - 3, mytext, mytextstyle);
  28.   Canvas.TextRect(textarea, 20 - 3, Self.Height - 80 + 3, mytext, mytextstyle);
  29.  
  30.   // Text
  31.   Canvas.Font.Color := clBlue;
  32.   Canvas.TextRect(textarea, 20, Self.Height - 80, mytext, mytextstyle);
  33.  
  34. end;
  35.  

The result is here.

https://photos.app.goo.gl/uwNcFZ9KZsg7WXYV2

How should I do?

Thank you very much and sorry for my poor English.

* * * * *
My system:
Lazarus 1.8.0 + FPC 3.0.4
Linux elementary OS 0.4 Loki (base on Ubuntu 16.04)
« Last Edit: January 22, 2018, 07:55:58 pm by HudchewMan »
[My System]
 - Linux elementary OS 0.4 Loki 64bit (base on Ubuntu 16.04)
 - Lazarus 1.8.0 + FPC 3.0.4

Handoko

  • Hero Member
  • *****
  • Posts: 3221
  • My goal: build my own game engine using Lazarus
Re: How can I drawing text with outline on a canvas?
« Reply #1 on: January 22, 2018, 08:15:04 pm »
Hello HudchewMan,
Welcome to the forum.

Doing text outline requires complex calculation, you won't get it by simply repeat the writing.

Instead of reinventing the wheel, I recommend you to try BGRABitmap:
http://wiki.freepascal.org/Sample_Graphics#Text_Outline

Eugene Loza

  • Hero Member
  • *****
  • Posts: 563
    • My "almost daily" development blog
Re: How can I drawing text with outline on a canvas?
« Reply #2 on: January 22, 2018, 08:20:40 pm »
The problem you have is that the "outline" images you draw have smaller elements than 3 pixels you shift them.
This should be enough for 1 pixel outline.
Code: Pascal  [Select]
  1.   Canvas.TextRect(textarea, 20 - 1, Self.Height - 80 - 1, mytext, mytextstyle);
  2.   Canvas.TextRect(textarea, 20 + 1, Self.Height - 80 + 1, mytext, mytextstyle);
  3.   Canvas.TextRect(textarea, 20 + 1, Self.Height - 80 - 1, mytext, mytextstyle);
  4.   Canvas.TextRect(textarea, 20 - 1, Self.Height - 80 + 1, mytext, mytextstyle);
If you need a larger outline, but you may do it by
Code: Pascal  [Select]
  1. for i := -5 to 5 do
  2.   for j := -5 to 5 do
  3.   begin
  4.      Canvas.TextRect(textarea, 20 - i, Self.Height - 80 - j, mytext, mytextstyle);
  5.      Canvas.TextRect(textarea, 20 + i, Self.Height - 80 + j, mytext, mytextstyle);
  6.      Canvas.TextRect(textarea, 20 + i, Self.Height - 80 - j, mytext, mytextstyle);
  7.      Canvas.TextRect(textarea, 20 - i, Self.Height - 80 + j, mytext, mytextstyle);
  8.   end;
This is extremely inefficient, but will get you to the place you want simple and dirty :)

If you want to make it "Better" then you might want to look into gauss blur, make an clear image with gauss blur of several pixels, process it and then copyrect it into your main canvas. It'll be much more efficient and beautiful, but will require you to carefully work pixel-by-pixel.

Quote
you won't get it by simply repeat the writing
I always do outline and shadow by repeat writing, because I'm lazy to make complex calculations :D
Lazarus 1.9 + FPC 3.1.1 Debian Jessie 64 bit.

My Free and Open Source games in Lazarus/FreePascal/CastleGameEngine:
https://decoherence.itch.io/
(and some ancient games in Turbo Pascal too)
Sources are here: https://github.com/eugeneloza?tab=repositories

Handoko

  • Hero Member
  • *****
  • Posts: 3221
  • My goal: build my own game engine using Lazarus
Re: How can I drawing text with outline on a canvas?
« Reply #3 on: January 22, 2018, 08:27:58 pm »
Well, actually yes we can but the result is not good. I never do it programmatically but I ever tried it using GIMP and Inkspace. The result looked ugly on large text.
« Last Edit: January 22, 2018, 08:30:38 pm by Handoko »

HudchewMan

  • New member
  • *
  • Posts: 9
Re: How can I drawing text with outline on a canvas?
« Reply #4 on: January 22, 2018, 08:45:09 pm »
Thank you and thank you very much. :)
[My System]
 - Linux elementary OS 0.4 Loki 64bit (base on Ubuntu 16.04)
 - Lazarus 1.8.0 + FPC 3.0.4

taazz

  • Hero Member
  • *****
  • Posts: 5363
Re: How can I drawing text with outline on a canvas?
« Reply #5 on: January 22, 2018, 09:05:07 pm »
a faster windows only solution
Code: Pascal  [Select]
  1. uses windows;
  2.  
  3. {$R *.lfm}
  4.  
  5. { TForm1 }
  6.  
  7. procedure TForm1.FormPaint(Sender: TObject);
  8. var
  9.   textarea: TRect;
  10.   mytext: string;
  11.   mytextstyle: TTextStyle;
  12.  
  13. begin
  14.   canvas.Lock;
  15.   try
  16.     Canvas.GradientFill(Self.ClientRect, clNavy, clGreen, gdHorizontal);
  17.  
  18.     mytext      := 'Hello the world, Who am I.';
  19.     textarea    := Classes.Rect(20, Self.Height - 80, Self.Width - 20, Self.Height - 10);
  20.     mytextstyle := Canvas.TextStyle;
  21.     mytextstyle.Wordbreak  := False;
  22.     mytextstyle.SingleLine := True;
  23.  
  24.     Canvas.Pen.Style := psClear;
  25.     Canvas.Brush.Style := bsClear;
  26.  
  27.     Canvas.Font.Size  := 22;
  28.     Canvas.Font.Style := [fsBold];
  29.  
  30.     windows.BeginPath(Canvas.Handle);
  31.     //Canvas.TextRect(textarea, 20, Self.Height - 80, mytext, mytextstyle);
  32.     Canvas.TextOut(20,Height-80, mytext);
  33.     EndPath(Canvas.Handle);
  34.     Canvas.Brush.Color := clBlue;
  35.     Canvas.Brush.Style := bsSolid;
  36.     Canvas.Pen.Color   := clWhite;
  37.     Canvas.Pen.Style   := psSolid;
  38.  
  39.     windows.StrokeAndFillPath(canvas.Handle);
  40.  
  41.   finally
  42.     Canvas.Unlock;
  43.   end;
  44. end;                
  45.  
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

RAW

  • Hero Member
  • *****
  • Posts: 794
Re: How can I drawing text with outline on a canvas?
« Reply #6 on: January 23, 2018, 01:39:16 am »
If you like you can try...

Graphics32 // +GR32_LINES and GR32_Text
BGRABitmap // as Handoko already said...
VampyreImaging Lib
GDI+ (Windows)
...

Then you can use semitransparent pixel and you'll get a lot of ready to use functions/procedures... really nice...
Windows 7 Pro (x64 Sp1) And Windows XP Pro (x86 Sp3) - LAZARUS 2.0.4 FPC 3.0.4 - TRUNK 2.1.0 FPC 3.3.1

HudchewMan

  • New member
  • *
  • Posts: 9
Re: How can I drawing text with outline on a canvas?
« Reply #7 on: January 23, 2018, 04:47:17 pm »
Thank you very much. :)
[My System]
 - Linux elementary OS 0.4 Loki 64bit (base on Ubuntu 16.04)
 - Lazarus 1.8.0 + FPC 3.0.4

circular

  • Hero Member
  • *****
  • Posts: 3045
    • Personal webpage
Re: How can I drawing text with outline on a canvas?
« Reply #8 on: January 23, 2018, 08:10:29 pm »
In BGRABitmap, as mentioned Handoko you can use the Contour filter to draw an outline with BGRABitmap. You can also use the Outline* properties of the Font renderer:
http://wiki.freepascal.org/BGRABitmap_tutorial_Font_rendering
Conscience is the debugger of the mind

HudchewMan

  • New member
  • *
  • Posts: 9
Re: How can I drawing text with outline on a canvas?
« Reply #9 on: January 24, 2018, 07:57:58 am »
Thank you :)
« Last Edit: January 24, 2018, 08:07:48 am by HudchewMan »
[My System]
 - Linux elementary OS 0.4 Loki 64bit (base on Ubuntu 16.04)
 - Lazarus 1.8.0 + FPC 3.0.4

Awesome Programmer

  • Sr. Member
  • ****
  • Posts: 421
  • Programming is FUN only when it works :)
    • Cool Technology
Re: How can I drawing text with outline on a canvas?
« Reply #10 on: April 01, 2019, 07:58:26 pm »
In BGRABitmap, as mentioned Handoko you can use the Contour filter to draw an outline with BGRABitmap. You can also use the Outline* properties of the Font renderer:
http://wiki.freepascal.org/BGRABitmap_tutorial_Font_rendering

Hi circular link,

That's true Fontrenderer has Outline features and others like shadow. However, If you use Fontrenderer to apply font special effects like shadow, you can't use TextRect to word wrap your text and still have shadow, unless I am wrong.
It seems you can ONLY use TextOut with Fontrenderer for shadows and outline if you don't want to word wrap. If you do want to word wrap your text using TextRect, then you can't use Fontrenderer. Correct me if I am wrong.

Currently, that's what I am fighting with and can't seem to figure out a solution. I simply want to word wrap my text and still have the outline and shadow that I enabled or applied with Fontrenderer.  Is there any way to do that, circular link?

circular

  • Hero Member
  • *****
  • Posts: 3045
    • Personal webpage
Re: How can I drawing text with outline on a canvas?
« Reply #11 on: April 02, 2019, 03:35:09 pm »
Sorry Awesome programmer, I did not see your post.

You're right I forgot to implement TextRect/TextWordWrap in TBGRATextEffectFontRenderer.

In the meantime you can use the function TextMultiline of TBGRABitmap. Also, it handles better Unicode and supports tabs.

EDIT: I fixed the FX with TextRect on the dev branch.
« Last Edit: April 02, 2019, 05:38:58 pm by circular »
Conscience is the debugger of the mind