VSmolensky
asked on
Vertical shift in Unicode fonts
In my Delphi project for Windows, I often render Japanese text on TCanvas of an image. Unfortunately, the vertical position of the rendered characters depends on the font family. When the font is MS Mincho or MS Gothic, it's positioned perfectly well. When it's Tahoma, the text goes a bit down. When it's Yu Mincho or Kozuka Gothic, it goes down a lot. So it's really difficult to align the text for all possible fonts. I need to calculate some parameter for every font to move the position upwards.
Some experts from another forum recommended to use the parameters from TTextMetric. There are several: tmAscent, tmDescent, tmExternalLeading, tmInternalLeading, etc. Theoretically, a certain combination of them and the font size in pixels should give me the desired value. But whatever I tried didn't work so far.
There must be a way to do it. Any ideas?
Some experts from another forum recommended to use the parameters from TTextMetric. There are several: tmAscent, tmDescent, tmExternalLeading, tmInternalLeading, etc. Theoretically, a certain combination of them and the font size in pixels should give me the desired value. But whatever I tried didn't work so far.
There must be a way to do it. Any ideas?
ASKER
My function is very simple (it's FireMonkey):
with MyImage.Bitmap.Canvas do
begin
BeginScene;
Font.Family := 'MS Mincho';
Font.Style := [];
Font.Size := 60;
FillText (RectF (0, 0, Width-1, Height-1), '字' , False , 1 , [] , TTextAlign.Leading, TTextAlign.Leading);
EndScene;
end;
I only need the characters to be drawn in the same area, not lower or higher, whatever font is chosen. At the moment this is what I have:
Thanks for the links, anyway.
with MyImage.Bitmap.Canvas do
begin
BeginScene;
Font.Family := 'MS Mincho';
Font.Style := [];
Font.Size := 60;
FillText (RectF (0, 0, Width-1, Height-1), '字' , False , 1 , [] , TTextAlign.Leading, TTextAlign.Leading);
EndScene;
end;
I only need the characters to be drawn in the same area, not lower or higher, whatever font is chosen. At the moment this is what I have:
Thanks for the links, anyway.
If it is for windows... I'm able to get TextMetic ...hee is my example:
I'm using external unit for getting TextMetric info:
Works for one character.. but for many - think that you should calculate each character separately and use Min of them as a padding value.
I follow this info about drawing text layout...
procedure MyCanvasFillText(Canvas: TCanvas; const ARect: TRectF; const AText: string;
const WordWrap: Boolean; const AOpacity: Single; const Flags: TFillTextFlags;
const ATextAlign, AVTextAlign: TTextAlign);
var
Layout: TTextLayout;
begin
Layout := TTextLayoutManager.TextLayoutByCanvas(Canvas.ClassType).Create(Canvas);
try
Layout.BeginUpdate;
Layout.TopLeft := ARect.TopLeft;
Layout.MaxSize := PointF(ARect.Width, ARect.Height);
Layout.Text := AText;
Layout.WordWrap := WordWrap;
Layout.Opacity := AOpacity;
Layout.HorizontalAlign := ATextAlign;
Layout.VerticalAlign := AVTextAlign;
Layout.Font := Canvas.Font;
Layout.Color := Canvas.Fill.Color;
Layout.RightToLeft := TFillTextFlag.RightToLeft in Flags;
//added line to original FillText method
Layout.Padding.Top := - GetTextExternalLeading(Canvas.Font.Family, Canvas.Font.Size,
Canvas.Font.Style, AText);
Layout.EndUpdate;
Layout.RenderLayout(Canvas);
finally
FreeAndNil(Layout);
end;
end;
....
with dst.Canvas do
begin
BeginScene;
Clear(TAlphaColorRec.White);
Font.Family := 'Tahoma'; //'MS Mincho';
Font.Style := [];
Font.Size := 60;
Fill.Color:=TAlphaColorRec.red;
MyCanvasFillText(dst.Canvas, RectF (0, 0, Width-1, Height-1), '字' , False , 1 , [] , TTextAlign.Leading, TTextAlign.Leading);
Label7.Text := r.Top.ToString;
EndScene;
end;
I'm using external unit for getting TextMetric info:
unit uTxtInfo;
interface
{$IFDEF MSWINDOWS}
uses Windows, VCL.Graphics, System.UITypes;
{$ELSE}
uses System.UITypes;
{$ENDIF}
function GetTextExternalLeading(FontName: String; FontSize: Single; FontStyle: System.UITypes.TFontStyles;
const AText: String): Integer;
implementation
{$IFDEF MSWINDOWS}
function GetTextExternalLeading(FontName: String; FontSize: Single; FontStyle: System.UITypes.TFontStyles;
const AText: String): Integer;
var
bmp: TBitmap;
tm: TEXTMETRIC;
begin
bmp := TBitmap.Create;
try
bmp.Width := 100;
bmp.Height := 100;
bmp.Canvas.Font.Name := FontName;
bmp.Canvas.Font.Size := Trunc(FontSize);
bmp.Canvas.Font.Style := FontStyle;
GetTextMetrics(bmp.Canvas.Handle, tm);
//output
Result := tm.tmExternalLeading + tm.tmInternalLeading;
finally
bmp.Free;
end;
end;
{$ELSE}
function GetTextExternalLeading(FontName: String; FontSize: Single; FontStyle: System.UITypes.TFontStyles;
const AText: String): Integer;
begin
Result := 0;
end;
{$ENDIF}
end.
(uTxtInfo.pas)Works for one character.. but for many - think that you should calculate each character separately and use Min of them as a padding value.
I follow this info about drawing text layout...
ASKER
Thank you for your code, but I already know how to get tmExternalLeading and tmInternalLeading from TextMetric. I had tried it before asking my question, and I wrote about it. This didn't solve my problem, the characters are still not aligned properly. A solution, as far as I can see, is supposed to be much more sophisticated.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I've posted a solution recommended to me at another forum. Maybe it'll be helpful for somebody else here. Please let this question stay.
Thanks. surely will help someone. I'm thinking about that method but then seems to me that would not fit as a solution.
Draw multi fonts in single line or do
some calc with TextMetric. You did not write if you need some alignment or what?