Alberto Fornés 22 Posted March 22, 2023 I am rewriting an editor where I am looking to display some text on the screen, to which I can zoom and therefore increase or decrease its size, and ensure that what I display on the screen corresponds to what I get when printing what has been drawn. From what I've been reading, GDI doesn't always respect these relationships in terms of text sizes, although when printing it can display the result well. As I show in tests I've done where I want to draw a 10mm high text, when I double the height to 20mm, the width of the text is not equal to double, as seen in the image. Is there a way to get the ratio to hold and equal to what we get in print, thanks. I use this code to draw the text: procedure TForm3.Button4Click(Sender: TObject); var h: integer; TextOutSize: TSize; NewFont, OldFont: HFont; // holds the old and new fonts begin bmp:= TBitmap.Create(Image1.Width,Image1.Height); bmp.PixelFormat:= pf32bit; try bmp.Canvas.Brush.Color:= clWhite; bmp.Canvas.Brush.Style:= bsSolid; bmp.Canvas.FillRect(Rect(0,0,Image1.Width,Image1.Height)); bmp.Canvas.Pen.Color:= clSilver; d:= 0; h:= 0; while d<= Image1.Width do begin if (h = 5) then begin bmp.Canvas.Pen.Color:= clGray; h:= 0; end else bmp.Canvas.Pen.Color:= clSilver; bmp.Canvas.MoveTo(d,0); bmp.Canvas.LineTo(d,Image1.Height); Inc(d,10); Inc(h); end; d:= 0; h:= 0; while d<= Image1.Height do begin if (h = 5) then begin bmp.Canvas.Pen.Color:= clGray; h:= 0; end else bmp.Canvas.Pen.Color:= clSilver; bmp.Canvas.MoveTo(0,d); bmp.Canvas.LineTo(Image1.Width,d); Inc(d,10); Inc(h); end; bmp.Canvas.Brush.Style:= bsClear; bmp.Canvas.Font.Color:= clBlack; SetMapMode(bmp.Canvas.Handle,MM_ISOTROPIC); SetViewportExtEx(bmp.Canvas.Handle,Image1.Width,Image1.Height,0); SetWindowExtEx(bmp.Canvas.Handle,Round(Image1.Width * 25.4 / GetDeviceCaps(bmp.Canvas.Handle, LOGPIXELSX)),Round(Image1.Height * 25.4 / GetDeviceCaps(bmp.Canvas.Handle, LOGPIXELSY)),0); // Create a 10 mm font NewFont:= CreateFont(10, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH or FF_DONTCARE, 'Arial'); OldFont := SelectObject(bmp.Canvas.Handle, NewFont); bmp.Canvas.Pen.Width:= 0; bmp.Canvas.Pen.Color:= clBlue; TextOut(bmp.Canvas.Handle,0,10,txt, Length(txt)); MoveToEx(bmp.Canvas.Handle,0,10,nil); LineTo(bmp.Canvas.Handle,230,10); MoveToEx(bmp.Canvas.Handle,0,20,nil); LineTo(bmp.Canvas.Handle,230,20); GetTextExtentPoint32(bmp.Canvas.Handle, PWideChar(txt), Length(txt), TextOutSize); TextOut(bmp.Canvas.Handle,230,10,PWideChar('Width: ' + TextOutSize.cx.ToString), Length('Width: ' + TextOutSize.cx.ToString)); SelectObject(bmp.Canvas.Handle, OldFont); DeleteObject(NewFont); // Create a 20 mm font NewFont:= CreateFont(20, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH or FF_DONTCARE, 'Arial'); OldFont := SelectObject(bmp.Canvas.Handle, NewFont); bmp.Canvas.Pen.Width:= 0; bmp.Canvas.Pen.Color:= clBlue; TextOut(bmp.Canvas.Handle,0,30,txt, Length(txt)); MoveToEx(bmp.Canvas.Handle,0,30,nil); LineTo(bmp.Canvas.Handle,230,30); MoveToEx(bmp.Canvas.Handle,0,50,nil); LineTo(bmp.Canvas.Handle,230,50); GetTextExtentPoint32(bmp.Canvas.Handle, PWideChar(txt), Length(txt), TextOutSize); TextOut(bmp.Canvas.Handle,230,30,PWideChar('Width: ' + TextOutSize.cx.ToString), Length('Width: ' + TextOutSize.cx.ToString)); SelectObject(bmp.Canvas.Handle, OldFont); DeleteObject(NewFont); Image1.Picture.Assign(bmp); finally FreeAndNil(bmp); end; end; Share this post Link to post
PeterBelow 239 Posted March 22, 2023 What you see is due to rounding errors when scaling individual character widths, these accumulate over the text width. If you want true WYSIWYG display you have to basically place each character individually at positions calculated from the font information. The API offers a large group of functions for this purpose, see Font and Text Functions 2 Share this post Link to post
Alberto Fornés 22 Posted March 22, 2023 11 minutes ago, PeterBelow said: What you see is due to rounding errors when scaling individual character widths, these accumulate over the text width. If you want true WYSIWYG display you have to basically place each character individually at positions calculated from the font information. The API offers a large group of functions for this purpose, see Font and Text Functions Thanks Peter, I will investigate in that direction. Do you have experience about the speed performance to calculate widths and drawing character individually? Share this post Link to post
Anders Melander 1815 Posted March 22, 2023 In addition to the pixel grid (or rounding as Peter labeled it) there are other reasons why you can't expect a linear relationship between font and text size; The TrueType font rasterizer takes stuff like hinting and kerning into account when deciding how to rasterize a character and place it relative to the other characters. You should probably look into that if you are doing WYSIWYG. Here's some light reading to get you started: https://www.joelonsoftware.com/2007/06/12/font-smoothing-anti-aliasing-and-sub-pixel-rendering/ https://blog.codinghorror.com/font-rendering-respecting-the-pixel-grid/ https://blog.codinghorror.com/whats-wrong-with-apples-font-rendering/ https://agg.sourceforge.net/antigrain.com/research/font_rasterization/index.html https://freetype.org/freetype2/docs/hinting/text-rendering-general.html https://en.wikipedia.org/wiki/Font_rasterization 2 hours ago, Alberto Fornés said: Do you have experience about the speed performance to calculate widths and drawing character individually? The performance mostly depends on how smart you are about it (cache what you can) and what method you use to draw the text. If you just use the GDI the performance penalty should be negligible as you will just be doing the same thing as the GDI does internally. If you want better performance and quality you can use one of the usual graphics libraries; They have the functionality to rasterize and render text. 1 Share this post Link to post
limelect 48 Posted March 23, 2023 @Anders Melander could not find the demo you show in Graphics32 where is the source from? Share this post Link to post
Anders Melander 1815 Posted March 23, 2023 3 hours ago, limelect said: could not find the demo you show in Graphics32 where is the source from? https://github.com/graphics32/graphics32/tree/master/Examples/Drawing/TextVPR 1 Share this post Link to post