Hi,
Long silence? I hope, you are interested in a solution...
Here is a source code sample for better GDI+ text results. I have deleted your special code for publication. If you need the full code, please contact me per E-Mail.
Code: Select all
TTeeFontMetric=record
Name : String;
Height : Integer;
Style : TFontStyles;
OX,OY:Single;
BaseLine:Integer;
TextHeight:Integer;
Rotation:Integer; //0..359
end;
procedure TGDIPlusCanvas.DoChangedFont;
begin
if Assigned(FGPFont) and ((Font.Name<>FontMetric.Name) or (Font.Height<>FontMetric.Height) or (Font.Style<>FontMetric.Style)) then
FreeAndNil(FGPFont);
end;
procedure TGDIPlusCanvas.NeedGPFont;
var
tmpFontStyle : TFontStyle;
tmpHeight:Integer;
Family:TGPFontFamily;
tmpQuality : TGDIPlusFontQuality;
R: TGPRectF;
begin
if Assigned(FGPFont) or not (Assigned(Font) and Assigned(FGraphics)) then Exit;
if Font.Height<3 then
tmpHeight:=Max(1,abs(Font.Height))
else begin
//Simple trick
tmpHeight:=Font.Height;
Font.Height:=-tmpHeight;
while (Font.Height<-3) and (TextHeight('X')>tmpHeight) do
Font.Height:=Font.Height+1;
exit;
end;
FGPFont.Free;
tmpFontStyle:=FontStyleRegular;
if Font.Style<>[] then // optimization
begin
if fsBold in Font.Style then tmpFontStyle:=tmpFontStyle or FontStyleBold;
if fsItalic in Font.Style then tmpFontStyle:=tmpFontStyle or FontStyleItalic;
if fsUnderline in Font.Style then tmpFontStyle:=tmpFontStyle or FontStyleUnderline;
if fsStrikeOut in Font.Style then tmpFontStyle:=tmpFontStyle or FontStyleStrikeout;
end;
FGPFont:=TGPFont.Create(Font.Name,tmpHeight,tmpFontStyle,UnitPixel);
FontMetric.Name:=Font.Name;
FontMetric.Height:=tmpHeight;
FontMetric.Style:=Font.Style;
R:=CalcTextRange('X');
FontMetric.OX:=R.X;
FontMetric.OY:=R.Y;
FontMetric.TextHeight:=Round(R.Height+R.Y+0.1);
Family:=TGPFontFamily.Create;
FGPFont.GetFamily(Family);
FontMetric.BaseLine:=Round(FGPFont.GetSize*Family.GetCellAscent(FGPFont.GetStyle)/Family.GetEmHeight(FGPFont.GetStyle))+Round(R.Y-0.1);
Family.Free;
end;
function TGDIPlusCanvas.CalcTextRange(const Text:string):TGPRectF;
var
format:TGPStringFormat;
rect:TGPRectF;
ranges: TCharacterRange;
regions:array [0..0] of TGPRegion;
begin
Result.Width:=0; Result.Height:=0; Result.X:=0; Result.Y:=0;
if length(Text)=0 then exit;
NeedGPFont;
format:=TGPStringFormat.Create(StringFormatFlagsMeasureTrailingSpaces);
rect.X:=0; rect.Y:=0; rect.Width:=9999999; rect.Height:=9999999;
ranges := MakeCharacterRange(0,length(Text));
format.SetMeasurableCharacterRanges(1,@ranges);
regions[0]:=TGPRegion.Create;
FGraphics.MeasureCharacterRanges(text, -1, FGPFont, rect, format, 1, regions);
regions[0].GetBounds(Result,FGraphics);
regions[0].Free;
format.Free;
end;
Function TGDIPlusCanvas.TextSize(const St:String):TPointFloat;
begin
NeedGPFont;
if (FontMetric.Rotation mod 90)<>0 then with CalcTextRange(St) do
Result.x:=Round(Width+X*2-FontMetric.OX) //Approximation
else
Result.x:=Round(CalcTextRange(St).Width); //Excat Textwidth
Result.y:=FontMetric.TextHeight;
end;
Function TGDIPlusCanvas.TextWidth(const St:String):Integer;
begin
Result:=Round(TextSize(St).x);
end;
Function TGDIPlusCanvas.TextHeight(const St:String):Integer;
begin
Result:=Round(TextSize('').y);
end;
Procedure TGDIPlusCanvas.TextOut(X,Y:Single; const Text:String);
var
Origin : TGPPointF;
matrix : TGPMatrix;
tmpBack: TCanvasBackMode;
begin
Origin.X:=X; Origin.Y:=Y;
NeedGPFont;
matrix:=nil;
FontMetric.Rotation:=(Round(ITextRotation)+360000000) mod 360; //0..359
if (FontMetric.Rotation<>0) then begin
matrix:=TGPMatrix.Create;
if FGraphics.GetTransform(matrix) = Ok then
if matrix.RotateAt(FontMetric.Rotation,Origin) = Ok then
FGraphics.MultiplyTransform(matrix);
end;
case TextAlign and (TA_RIGHT or TA_CENTER) of
TA_RIGHT: Origin.X:=Origin.X-TextWidth(Text);
TA_CENTER: Origin.X:=Origin.X-(TextWidth(Text) div 2); //avoid half pixels
end;
case TextAlign and (TA_BOTTOM or TA_BASELINE) of
TA_BOTTOM: Origin.Y:=Origin.Y-TextHeight(Text);
TA_BASELINE: Origin.Y:=Origin.Y-FontMetric.BaseLine;
end;
tmpBack:=BackMode;
if (BackMode=cbmOpaque) then begin
Brush.Color:=BackColor;
FillRect(CalcTextRect(Origin,Text));
end;
FGPBrush.Free;
FGPBrush:=TextBrush(Font.Color,Origin,Text);
Origin.X:=Origin.X-(FontMetric.OX*0.6); //negative Offset
if (FontMetric.Rotation mod 90)<>0 then Origin.Y:=Origin.Y+FontMetric.OY; //Bug or Feature???
FGraphics.DrawString(Text,Length(Text),FGPFont,Origin,FGPBrush);
BackMode:=tmpBack;
if Assigned(matrix) then begin
if FGraphics.ResetTransform = Ok then FreeAndNil(matrix);
FontMetric.Rotation:=0;
end;
Truly, the GDI+ text function are very strange. But the result with the new code is not bad and you can also use the HTML-Out functions with GDI+:
- PicTee1.png (18.16 KiB) Viewed 20199 times
Code: Select all
procedure TForm1.Draw3D1Paint(Sender: TObject; const ARect: TRect);
var
s:String;
x,y,h,xp,yp:Integer;
w:Single;
begin
x:=10; y:=10;
with Draw3D1.Canvas do begin
Brush.Clear;
h:=TextHeight('-');
TextOut(x,y,Format('%s TH=%d FH=%d %s',[ClassName,h,Font.Height,Font.Name]));
h:=h+5;
y:=y+h;
s:='XXXXXXXXXXXX█XXXXXXXXXXXXXXX';
Brush.Color:=clSilver;
FillRect(Rect(x,y,x+TextWidth(s),y+TextHeight(s)));
TextOut(x,y,s); y:=y+h;
s:='FFFFFFFFFFFF█FFFFFFFFFFFFFFF';
Brush.Color:=clSilver;
FillRect(Rect(x,y,x+TextWidth(s),y+TextHeight(s)));
TextOut(x,y,s); y:=y+h;
s:='AAAAAAAAAAAA█AAAAAAAAAAAAAAA';
Brush.Color:=clSilver;
FillRect(Rect(x,y,x+TextWidth(s),y+TextHeight(s)));
TextOut(x,y,s); y:=y+h;
Font.Style:=[];
TextOut(x,y,'HtmlText<i>Out</i>: FFFF</b>FF<font color=#FF0000>F</font><font color=#00FF00>F</font><b>HH</b> ',True); y:=y+h;
TextOut(x,y,'HtmlText<i>Out</i>: AAAA</b>AAAA<b>HH</b> ',True); y:=y+h;
Font.Style:=[];
y:=y+20;
TextAlign:=TA_BASELINE;
xp:=x; s:='H';
Brush.Color:=clSilver;
FillRect(Rect(x,y,x+300,y+1));
for yp:=6 to 28 do begin
Font.Height:=-yp;
TextOut(xp,y,s);
xp:=xp+TextWidth(s);
end;
Font.Height:=-11;
s:='WWW█WWW';
//TextAlign:=TA_RIGHT; h:=100;
//TextAlign:=TA_CENTER; h:=50;
//TextAlign:=TA_BASELINE;
//TextAlign:=TA_BOTTOM;
x:=(ARect.Left+Arect.Height) div 2; y:=y+110;
Brush.Color:=clWhite;
Ellipse(x-h,y-h,x+h,y+h);
w:=0;
while (w<360) do begin
xp:=x+Round(h*cos(w/180*PI));
yp:=y-Round(h*sin(w/180*PI));
BackColor:=clSilver;
BackMode:=cbmOpaque;
RotateLabel(xp,yp,s,w);
w:=w+45;
end;
end;
end;
I hope, I could help you and you can improve your software.
Another problem: Please look to the function TeEngine.TChartAxis.DrawAxisLabel. You define tmpAlign but don't use it. I think, all Axis Labels are drawn with center alignment. The result is not good.
Thanks,
Jens Gr.