Solved

Canvas.TextWidth is not correct!

Posted on 2000-04-19
8
1,044 Views
Last Modified: 2010-05-18
Problems with exactly scaling a Font:

I tried to fit a text into an Image, so that it starts on the left side and ends on the right side of the Image (as excactly as possible; I know, that
Font.Size is not available for all integer values!).

I used the following simple code:


  cvs:=Image.Canvas;
  tw:=cvs.TextWidth(ed_Text.Text);
  cvs.Font.Size:=30;
  while ((tw>=Image.Width) and (cvs.Font.Size>3))   do begin
    cvs.Font.Size:=cvs.Font.Size-1;
    tw:=cvs.TextWidth(ed_Text.Text);
  end; // while ...
  cvs.Textout(0,0,s);


(Hereby I will assume, that the Image is high enough to contain
the text, so I do not have to check this here).

The result: the text starts on the left, but does only fill about 80%
of the window leaving blanks on the right side. So it seems to me, that cvs.TextWidth returns a value,
which is too small (I can always find an existing Font.Size, which has a better fit!).

I could solve the problem this way:
  tw:=round(1.2 * cvs.TextWidth(ed_Text.Text);
but I think, there must be a more exact way to get the correct
size of the Font on the canvas to ensure exact scaling.

100 Points for a different approach to solve the problem of fitting
the text in width (or also in height), which results in a more exact
fit.

Thanks for any help

Gamba


0
Comment
Question by:Gamba
8 Comments
 
LVL 9

Expert Comment

by:ITugay
ID: 2729877
Hi Gamba,

try this sample
-----------
var tw,fs : integer;
    S     : string;
    cnv   : TCanvas;
begin
   cnv:=Image1.Canvas;
   cnv.Font.Size:=6;
   S:='sample';
   repeat
      cnv.Font.Size:=cnv.Font.Size+1;
      tw:=cnv.TextWidth(S);
   until Image1.Width < tw;
   cnv.Font.Size:=cnv.Font.Size-1; // you miss it in your sample
   cnv.TextOut(0,0,S);
end;
-----

Igor.
0
 
LVL 3

Expert Comment

by:shenqw
ID: 2729904
s=what?

I think you forgot s:=ed_Text.Text
0
 
LVL 9

Expert Comment

by:ITugay
ID: 2729929
S:='sample';) It's working sample, I check it before public.
----
Igor.
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:Gamba
ID: 2730211
Thanks, ITugay,
this works o.k., I added the
Height-Part and changed the line
with Font.Size:=Font.Size-1 (see comment). I did not expect it to be
a problem of the missed line!

Do you think, finding the correct Font.Size has to be done iterative
or can it be calculated somehow??

(please add a answer statement and
you will receive the points in any case).




procedure Draw;
var tw,th: integer;
    s     : string;
    cnv   : TCanvas;
    prevsize : word;
    prevw,prevh : integer;
begin
   cnv:=Image.Canvas;
   cnv.Rectangle(0,0,Image.Width,Image.Height);
   cnv.Font.Size:=5;
   prevw:=cnv.TextWidth(s);
   prevh:=cnv.TextHeight(s);
   tw:=prevw;
   th:=prevh;
   s:=ed_Text.Text;
   repeat
     if ((tw<>prevw) or (th<>prevh)) and ((Image.Width >= tw) or (Image.Height >= th))
     then begin
       prevsize:=cnv.Font.Size;
       prevw:=tw;
       prevh:=th;
     end; // if (tw<>prevw) or (th<>prevh)
     cnv.Font.Size:=cnv.Font.Size+1;
     tw:=cnv.TextWidth(s);
     th:=cnv.TextHeight(s);
   until ((Image.Width < tw) or (Image.Height < th));
   cnv.Font.Size:=prevsize;
     (* instead of cnv.Font.Size:=cnv.Font.Size-1, cause cnv.Font.Size-1 has not necessary other
      tw and th *)
   cnv.TextOut(0,0,S);
end;



Gamba


0
 
LVL 9

Expert Comment

by:ITugay
ID: 2730241
Ok, just a moment...
0
 
LVL 2

Expert Comment

by:mullet_attack
ID: 2730929
If you want an exact fit, use a truetype font. Using the default windows font cause Windows to perform a best-fit calculation of a scaled up/down font.

TextWidth returns the correct width in pixels only for truetype fonts and the pre-defined sizes of system fonts.

ITugay's sample doesn't work properly without a true-type font.
0
 
LVL 9

Accepted Solution

by:
ITugay earned 100 total points
ID: 2733648
mulet_attack,
try it at first then make your insennuations.
-----------

Hi Gamba,
Sorry for delay. Calculation of text metrics is very difficult, let TextWidth and TextHeight do it for you. I simplifyed your algorythm, now it look like this:
---------

procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
   with Image do with Canvas do
   begin
     Font.Name:='MS Serif'; // not truetype font (for mullet_attack especially)
     Font.Size:=6;
     repeat
        Font.Size:=Font.Size+1;
     until (Width < TextWidth(Ed_text.Text))
        or (Height < TextHeight(Ed_text.Text));
     Font.Size:=Font.Size-1;
     TextOut(0,0,Ed_text.Text);
   end;
end;
----------

Best regards,
Igor.
0
 

Author Comment

by:Gamba
ID: 2733736
Thanks

Gamba
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Delphi XE10 Round Image 2 193
Downloading email attachments 2 85
How to create virtual printer while installing my application 5 70
Firemonkey Tcameracomponent resultion 1 27
This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…

696 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question