Recent

Author Topic: [SOLVED] Font character being clipped.  (Read 888 times)

Coxy

  • New Member
  • *
  • Posts: 36
[SOLVED] Font character being clipped.
« on: June 16, 2025, 02:25:10 pm »
Hi,

I'm using font "Computer Modern" from American Mathematical Society as used in LaTeX. When I fillText() with a TBGRACanvas2D the asterisk character is clipped on the right-hand side.

Code
Code: Pascal  [Select][+][-]
  1. procedure TForm1.BtnTestClick(Sender: TObject);
  2. var
  3.   Bitmap : TBGRABitmap;
  4.   cvs : TBGRACanvas2D;
  5.   FontMet : TFontPixelMetricF;
  6.   ms : TCanvas2dTextSize;
  7.   s : string;
  8.   Bounds : TRect;
  9. begin
  10.   Bitmap:=TBGRABitmap.Create(200,200);
  11.   Bitmap.FillTransparent;
  12.  
  13.   cvs:=Bitmap.Canvas2D;
  14.  
  15.   s:='*';
  16.   cvs.textBaseline:='top';
  17.   cvs.fontName:='CMU Classical Serif';
  18.   cvs.fontEmHeight:=100;
  19.   cvs.fontStyle:=[];
  20.   cvs.fillStyle(BGRA(10,10,10));
  21.  
  22.   FontMet := cvs.fontRenderer.GetFontPixelMetricF;
  23.  
  24.   ms := cvs.measureText(s);
  25.  
  26.   Memo1.Lines.Add('Text:        "'+s+'"');
  27.  
  28.   Memo1.Lines.Add('');
  29.   Memo1.Lines.Add('Font');
  30.   Memo1.Lines.Add('Name:        '+cvs.fontName);
  31.   Memo1.Lines.Add('EmHeight:    '+FloatToStr(cvs.fontEmHeight));
  32.   Memo1.Lines.Add('Base Line:   '+cvs.textBaseline);
  33.   Memo1.Lines.Add('');
  34.   Memo1.Lines.Add('FontMet');
  35.   Memo1.Lines.Add('CapLine:     '+FloatToStr(FontMet.CapLine));
  36.   Memo1.Lines.Add('XLine:       '+FloatToStr(FontMet.xLine));
  37.   Memo1.Lines.Add('BaseLine:    '+FloatToStr(FontMet.Baseline));
  38.   Memo1.Lines.Add('DescentLine: '+FloatToStr(FontMet.DescentLine));
  39.   Memo1.Lines.Add('LineHeight:  '+FloatToStr(FontMet.Lineheight));
  40.   Memo1.Lines.Add('');
  41.   Memo1.Lines.Add('Measure Text');
  42.   Memo1.Lines.Add('Width:       '+FloatToStr(ms.width));
  43.   Memo1.Lines.Add('Height:      '+FloatToStr(ms.height));
  44.   Memo1.Lines.Add('');
  45.  
  46.   cvs.fillText(s,50,50);
  47.  
  48.   Bounds := Bitmap.GetImageBounds;
  49.   Memo1.Lines.Add('Bounds');
  50.   Memo1.Lines.Add('Width:       '+IntToStr(Bounds.Width));
  51.   Memo1.Lines.Add('Height:      '+IntToStr(Bounds.Height));
  52.   Memo1.Lines.Add('Top:         '+IntToStr(Bounds.Top));
  53.   Memo1.Lines.Add('Left:        '+IntToStr(Bounds.Left));
  54.  
  55.   Bitmap.SaveToFile('Text.png');
  56.  
  57.   Bitmap.Free;
  58. end;

Outputs
Quote
Text:        "*"

Font
Name:        CMU Classical Serif
EmHeight:    100
Base Line:   top

FontMet
CapLine:     23
XLine:       49
BaseLine:    94
DescentLine: 113
LineHeight:  118

Measure Text
Width:       52
Height:      118

Bounds
Width:       33
Height:      44
Top:         67
Left:        68

Example image attached.

Is the problem with my code, the font or BGRABitmap. Any help greatly appreciated.

Setup:
Windows x86_64
Lazarus IDE v3.2
FPC v3.2.2
BGRABitmap
   bglcontrols.lpk      1.2.0.0
   bgrabitmappack.lpk   11.6.6.0
BGRAControls
   bgracontrols.lpk    9.0.1.3
   bgrapascalscriptcomponent.lpk   9.0.1.3

« Last Edit: June 28, 2025, 12:17:35 pm by Coxy »

dsiders

  • Hero Member
  • *****
  • Posts: 1453
Re: Font character being clipped.
« Reply #1 on: June 16, 2025, 04:43:31 pm »
Hi,

I'm using font "Computer Modern" from American Mathematical Society as used in LaTeX. When I fillText() with a TBGRACanvas2D the asterisk character is clipped on the right-hand side.

Code
Code: Pascal  [Select][+][-]
  1. procedure TForm1.BtnTestClick(Sender: TObject);
  2. var
  3.   Bitmap : TBGRABitmap;
  4.   cvs : TBGRACanvas2D;
  5.   FontMet : TFontPixelMetricF;
  6.   ms : TCanvas2dTextSize;
  7.   s : string;
  8.   Bounds : TRect;
  9. begin
  10.   Bitmap:=TBGRABitmap.Create(200,200);
  11.   Bitmap.FillTransparent;
  12.  
  13.   cvs:=Bitmap.Canvas2D;
  14.  
  15.   s:='*';
  16.   cvs.textBaseline:='top';
  17.   cvs.fontName:='CMU Classical Serif';
  18.   cvs.fontEmHeight:=100;
  19.   cvs.fontStyle:=[];
  20.   cvs.fillStyle(BGRA(10,10,10));
  21.  
  22.   FontMet := cvs.fontRenderer.GetFontPixelMetricF;
  23.  
  24.   ms := cvs.measureText(s);
  25.  
  26.   Memo1.Lines.Add('Text:        "'+s+'"');
  27.  
  28.   Memo1.Lines.Add('');
  29.   Memo1.Lines.Add('Font');
  30.   Memo1.Lines.Add('Name:        '+cvs.fontName);
  31.   Memo1.Lines.Add('EmHeight:    '+FloatToStr(cvs.fontEmHeight));
  32.   Memo1.Lines.Add('Base Line:   '+cvs.textBaseline);
  33.   Memo1.Lines.Add('');
  34.   Memo1.Lines.Add('FontMet');
  35.   Memo1.Lines.Add('CapLine:     '+FloatToStr(FontMet.CapLine));
  36.   Memo1.Lines.Add('XLine:       '+FloatToStr(FontMet.xLine));
  37.   Memo1.Lines.Add('BaseLine:    '+FloatToStr(FontMet.Baseline));
  38.   Memo1.Lines.Add('DescentLine: '+FloatToStr(FontMet.DescentLine));
  39.   Memo1.Lines.Add('LineHeight:  '+FloatToStr(FontMet.Lineheight));
  40.   Memo1.Lines.Add('');
  41.   Memo1.Lines.Add('Measure Text');
  42.   Memo1.Lines.Add('Width:       '+FloatToStr(ms.width));
  43.   Memo1.Lines.Add('Height:      '+FloatToStr(ms.height));
  44.   Memo1.Lines.Add('');
  45.  
  46.   cvs.fillText(s,50,50);
  47.  
  48.   Bounds := Bitmap.GetImageBounds;
  49.   Memo1.Lines.Add('Bounds');
  50.   Memo1.Lines.Add('Width:       '+IntToStr(Bounds.Width));
  51.   Memo1.Lines.Add('Height:      '+IntToStr(Bounds.Height));
  52.   Memo1.Lines.Add('Top:         '+IntToStr(Bounds.Top));
  53.   Memo1.Lines.Add('Left:        '+IntToStr(Bounds.Left));
  54.  
  55.   Bitmap.SaveToFile('Text.png');
  56.  
  57.   Bitmap.Free;
  58. end;

Outputs
Quote
Text:        "*"

Font
Name:        CMU Classical Serif
EmHeight:    100
Base Line:   top

FontMet
CapLine:     23
XLine:       49
BaseLine:    94
DescentLine: 113
LineHeight:  118

Measure Text
Width:       52
Height:      118

Bounds
Width:       33
Height:      44
Top:         67
Left:        68

Example image attached.

Is the problem with my code, the font or BGRABitmap. Any help greatly appreciated.

Setup:
Windows x86_64
Lazarus IDE v3.2
FPC v3.2.2
BGRABitmap
   bglcontrols.lpk      1.2.0.0
   bgrabitmappack.lpk   11.6.6.0
BGRAControls
   bgracontrols.lpk    9.0.1.3
   bgrapascalscriptcomponent.lpk   9.0.1.3

The font pictured in the attached image does not appear to match the font name specified in code. The font names (on FontSquirrel at leaat are different). The image has CMU Serif Oblique, while the code should probably request CMU Serif Upright. The applied Italics is skewing the character width. I don't know why it is selecting Oblique by default. That could be a BGRABitmap issue.
Preview the next Lazarus documentation release at: https://dsiders.gitlab.io/lazdocsnext

Coxy

  • New Member
  • *
  • Posts: 36
Re: Font character being clipped.
« Reply #2 on: June 16, 2025, 06:27:11 pm »
I used fonts from file cm-unicode-0.7.0-ttf.tar.xz found on www

Code: Text  [Select][+][-]
  1. Directory: M:\fonts\cm-unicode-0.7.0-ttf\cm-unicode-0.7.0
  2.  
  3. Mode                 LastWriteTime         Length Name                                                                
  4. ----                 -------------         ------ ----                                                                
  5. -a----        18/06/2009     08:42         476440 cmunbi.ttf                                                          
  6. -a----        18/06/2009     08:43         665780 cmunbl.ttf                                                          
  7. -a----        18/06/2009     08:53         609796 cmunbx.ttf                                                          
  8. -a----        18/06/2009     08:51         417560 cmunrb.ttf                                                          
  9. -a----        18/06/2009     09:03         639132 cmunrm.ttf                                                          
  10. -a----        18/06/2009     09:05         672956 cmunsl.ttf                                                          
  11. -a----        18/06/2009     09:12         486980 cmunti.ttf                                                          
  12. -a----        18/06/2009     09:12         408580 cmunui.ttf                                                          
  13. -a----        18/06/2009     09:25         549844 cmuntt.ttf                                                          
  14. -a----        18/06/2009     09:25         551972 cmunst.ttf                                                          
  15. -a----        18/06/2009     09:34         458764 cmunit.ttf                                                          
  16. -a----        18/06/2009     09:33         343948 cmunvt.ttf                                                          
  17. -a----        18/06/2009     09:41         406580 cmunvi.ttf                                                          
  18. -a----        18/06/2009     09:40         369888 cmunss.ttf                                                          
  19. -a----        18/06/2009     09:48         369464 cmunssdc.ttf                                                        
  20. -a----        18/06/2009     09:47         404772 cmunsi.ttf                                                          
  21. -a----        18/06/2009     09:59         462844 cmunso.ttf                                                          
  22. -a----        18/06/2009     10:02         480476 cmunsx.ttf                                                          
  23. -a----        18/06/2009     10:08         495692 cmunci.ttf                                                          
  24. -a----        18/06/2009     10:12         458064 cmuntx.ttf                                                          
  25. -a----        18/06/2009     10:19         397792 cmuntb.ttf                                                          
  26. -a----        18/06/2009     10:25         480216 cmunobi.ttf                                                          
  27. -a----        18/06/2009     10:28         462364 cmunobx.ttf                                                          
  28. -a----        18/06/2009     10:33         553960 cmunorm.ttf                                                          
  29. -a----        18/06/2009     10:39         476692 cmunoti.ttf                                                          
  30. -a----        18/06/2009     10:40         338508 cmunbbx.ttf                                                          
  31. -a----        18/06/2009     10:45         403248 cmunbmo.ttf                                                          
  32. -a----        18/06/2009     10:46         370388 cmunbmr.ttf                                                          
  33. -a----        18/06/2009     10:51         399976 cmunbso.ttf                                                          
  34. -a----        18/06/2009     10:52         338276 cmunbsr.ttf                                                          
  35. -a----        18/06/2009     10:59         392140 cmunbxo.ttf                                                          
  36. -a----        18/06/2009     11:01         410116 cmunbtl.ttf                                                          
  37. -a----        18/06/2009     11:08         462276 cmunbto.ttf                                                          
  38. -a----        17/03/2009     13:34           4820 OFL.txt                                                              
  39. -a----        08/03/2008     03:28          23824 OFL-FAQ.txt                                                          
  40. -a----        18/06/2009     11:33          10811 Changes                                                              
  41. -a----        08/04/2009     08:19           2296 INSTALL                                                              
  42. -a----        22/02/2009     10:27           1748 README                                                              
  43. -a----        03/05/2006     11:59            220 TODO                                                                
  44. -a----        09/11/2006     07:54           1879 FAQ                                                                  
  45. -a----        18/06/2009     11:33          10811 FontLog.txt                                                          
  46. -a----        18/06/2009     11:34           1862 Fontmap.CMU                                                          
  47. -a----        09/04/2009     07:07          37608 fonts.scale                                                          
  48.  

They're quite old so I'll source anther set of Computer Modern fonts and see if I get same problem. Thanks for the input I'll take a look at FontSquirrel.

Coxy

  • New Member
  • *
  • Posts: 36
Re: Font character being clipped.
« Reply #3 on: June 17, 2025, 12:04:54 pm »
Downloaded "Computer Modern" from FontSquirrel and installed them on a different machine. Compiled and ran code getting same result see picture below. I also noticed LibreOffice Writer exhibits similar behaviour, although it doesn't clip image, just the selection area (see example below).

Is it a font or programming error?

Setup

Linux Mint 22.1 Xia (x86_64)

Lazarus v3.6 (via fpcupdelux stable/stable, version taken from About dialog but desktop shortcut and folder say "Lazarus 4.0"!)
FPC v3.2.2
BGRABitmap
  bglcontrols.lpk    1.2.0.0
  bgrabitmappack.lpk   11.6.6.0

BobT

  • New Member
  • *
  • Posts: 20
Re: Font character being clipped.
« Reply #4 on: June 26, 2025, 01:43:39 pm »
Not the exact same situation, but I found BGRAbitmap.TextOut would sometimes clip RH edge of text final character, the extent of clipping effect varying with font size and X-position. This happened with several different fonts, though not always at the exact same size / location. Changing the text renderer and quailty settings didn't seem to make any difference, but I didn't carry out exhaustive tests. Rounding the computed 'X' position supplied to TextOut to an integer value seemed to avoid the problem, so needing a quick pragmatic fix that's what I did.

circular

  • Hero Member
  • *****
  • Posts: 4443
    • Personal webpage
Re: Font character being clipped.
« Reply #5 on: June 27, 2025, 01:40:38 pm »
Hi Coxy and BobT,

It can happen indeed that characters are clipped when they go outside of their bounding box. However the operating system can detect that the font is italic and so that the actual bounding box is greater.

When testing the font you provided on Windows, I've got the clipping as well. However, when specifying the italic style in the font, the clip didn't occur anymore. So I invite you to try setting the font style.

It might be that because the font is only provided as oblique, it is implicitly italic but that is not detected when rendering.

Regards
Conscience is the debugger of the mind

Coxy

  • New Member
  • *
  • Posts: 36
Re: Font character being clipped.
« Reply #6 on: June 27, 2025, 02:29:17 pm »

I tried "fsItalic" without success when I came across this comment

Quote
  // Theoretically, we need to augment the returned rect by the text overhang
  // The overhang is returned in the abcC field as documented in the
  // following article: http://support.microsoft.com/kb/94646/en-us
  // for italic text, usually this value is negative, so the adjusted
  // value could be calculated by Rect.Right:=Rect.Right-aABC.abcC, oddly enough
  // sometimes this it's positive, yielding an incorrect Rect.Right value.
  // As the objective is to return a more correct value so the text overhang
  // is not clipped out, I found the next solution works better most times.
  //
  // NOTE. this doesn't solve (most of the times) the problem of right
  // aligned bold italic text. The DrawText windows function is documented to
  // clip out text in some special cases, specially when drawing italic text,
  // but I found it's even worse with drawing bold italic text.

In function TWin32WidgetSet.DrawText unit win32winapi.inc.

However my solution to the problem was to modify procedure BGRATextOut in unit BGRAText. At the bottom it draws an inverted image to a temp bitmap.


Code: Pascal  [Select][+][-]
  1.   temp := BGRABitmapFactory.Create(sizeWithMargin.cx, sizeWithMargin.cy, BGRABlack);
  2.   with temp do begin
  3.   {$ENDIF}
  4.     Canvas.Font := Font;
  5.     Canvas.Font.Orientation := 0;
  6.     Canvas.Font.Height := Font.Height * sizeFactor;
  7.     Canvas.Font.Color := clWhite;
  8.     BitmapTextOut({$IFDEF RENDER_TEXT_ON_TBITMAP}tempLCL{$ELSE}temp.Bitmap{$ENDIF},
  9.          Point(HalfUp((xf - floor(xf)) * sizeFactor) + iMargin.cx,
  10.            HalfUp((yf - floor(yf)) * sizeFactor) + iMargin.cy),
  11.          sUTF8);
  12.     temp.Bitmap.SaveToFile('temp.Bitmap.png');    // Temp code for debugging
  13.   end;

The saved image shows the clipping (first image below), so I modified the width by multiplying by 2,

Code: Pascal  [Select][+][-]
  1.   xMarginF := textSize.cy/sizeFactor;
  2.   iMargin := size(ceil(xMarginF) * sizeFactor, sizeFactor);
  3.   sizeWithMargin := size(textSize.cx + iMargin.cx*2, textSize.cy + iMargin.cy);

This gives second image below.

Output is third image.

I need to do more testing to see if there are any unwanted side effects.







circular

  • Hero Member
  • *****
  • Posts: 4443
    • Personal webpage
Re: Font character being clipped.
« Reply #7 on: June 28, 2025, 10:08:25 am »
Yes, adding some margin can solve this issue. The left margin that is already there looks probably too big to me, I don't remember why I made it so big. So I suggest, on top of adding the right margin, to set initially the iMargin.cx to be half of what it is. So that we end up with the same total margin, but on both sides.

So that would be:
Code: Pascal  [Select][+][-]
  1.   xMarginF := textSize.cy/2/sizeFactor;
  2.   iMargin := size(ceil(xMarginF) * sizeFactor, sizeFactor);
  3.   sizeWithMargin := size(textSize.cx + iMargin.cx*2, textSize.cy + iMargin.cy);
Conscience is the debugger of the mind

Mr.Madguy

  • Hero Member
  • *****
  • Posts: 875
Re: [SOLVED] Font character being clipped.
« Reply #8 on: June 28, 2025, 03:46:09 pm »
This isn't issue. It's intended behavior. TextExtent =/= TextWidth. In some cases A and C values in ABC can be negative. And even more. Negative C value of previous character can theoretically be larger, than whole ABC of next one. So, extra checks should be performed. But in most cases in order to obtain real with, simple Extent - FirstA - LastC formula should be used. I have very old project, where I tried to solve this problem. But then I realized, that real applications usually don't bother about it. They just add margins.
Is it healthy for project not to have regular stable releases?
Just for fun: Code::Blocks, GCC 13 and DOS - is it possible?

 

TinyPortal © 2005-2018