http://qs321.pair.com?node_id=950758

preahkumpii has asked for the wisdom of the Perl Monks concerning the following question:

I am working with manipulating text files in Perl, not with Web. I need to be able to take a given string of text, and given a font name and size (ideal other options as well), to output the length of the string in pixels (or whatever unit) as it would appear in the font. I have looked the Tk module and on the web extensively. I cannot find a clear description of its use at all. Here is my sample code:
#!/usr/bin/perl use warnings; use strict; use Tk; my $happy = "This is my example sentence"; # I want the measurement of the above string in pixels given a font fa +ce and font size
Thanks for the help. Adam

Replies are listed 'Best First'.
Re: font measurement
by BrowserUk (Patriarch) on Jan 30, 2012 at 16:53 UTC

    You need to obtain a TK::Font object for the font you wish to use, then call the measure( $text ) method:

    #! perl -slw use strict; use Tk; use Tk::Font; my $mw = MainWindow->new(); for my $name ( 'system' ) { #$mw->fontNames print "Using font $name"; my $font = $mw->fontCreate( $name ); for my $text ( 'The quick brown fox jumps over the lazy dog', 'THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG' ) { printf "$text measures %d pixels\n", $font->measure( $text ); } } __END__ C:\test>junk44 Using font system The quick brown fox jumps over the lazy dog measures 302 pixels THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG measures 409 pixels

    See the Tk::Font POD for (a little) more info, then google for more.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    The start of some sanity?

      Thank you for your help. Pardon the ignorance, but I have 3 questions:
      1. I don't understand this comment. Why is it there? #$mw->fontNames
      2. What is the use of the %d variable?
      3. Why was the command $font->measure( $text ) placed after the print command?
      UPDATE: I must be missing something. I thought I would put the name of the font of my choice from my system in place of the 'system' in your code. No matter what font I put there, even a very wide one like Trajan Pro, I get the same pixel width.

        Sorry. That's what I assumed also. If it doesn't work, then you'll need to look for more or better documentation than this.

        1. The comment was left there to show my failed attempt to find a list of available fonts.
        2. %d isn't a variable, See the documentation for printf.
        3. See the documentation for printf

        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

        The start of some sanity?

Re: font measurement
by zentara (Archbishop) on Jan 30, 2012 at 15:30 UTC
    See Re: Tk: Set text size in a widget and "perldoc Tk::Font" and "perldoc Tk::X11Font", but using the Canvas is always a good bet.
    #!/usr/bin/perl use warnings; use strict; use Tk; my $mw = new MainWindow; $mw->fontCreate('big', -family=>'arial', -weight=>'bold', -size=> 28 ); my $c = $mw->Canvas(-bg=>'white')->pack; #---determine font spacing by making a capital W--- my $fonttest = $c->createText(100,100, -fill => 'black', -text => 'W', -font => 'big' ); my ($bx,$by,$bx1,$by1) = $c->bbox($fonttest); $c->{'f_width'} = $bx1 - $bx; $c->{'f_height'} = $by1 - $by; print 'width ',$c->{'f_width'},' ',$c->{'f_height'},"\n"; MainLoop;

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh
      I appears from this code (I am no perl professional) that a window is created for the text. In my case the measuring will only be used as a means to determine the length of the string to keep, and what to remove. So, it is just an intermediate step. So if this code opens a separate window I think that would have a significant performance hit on this already slow program (not the example I gave, but the real program I am working on).
        BrowserUk gave you the preferred answer below, but if you wanted to use my Canvas method, without invoking a window, all you need to do is comment out the line #MainLoop. Then if you run it, it will not show a window.

        Either way, you are loading Tk. You can either load Tk::Text or a Tk::Canvas. Tk is relatively light and fast to load.


        I'm not really a human, but I play one on earth.
        Old Perl Programmer Haiku ................... flash japh
Re: font measurement
by fisher (Priest) on Jan 30, 2012 at 12:23 UTC
    Your sample code looks great. What type of font do you plan to use? Is it ttf or what?
      A ttf, or otf. Really I just want to specify a font on my Windows system. The actual code I will use is much more complex, but seeing I can't even get the basic idea of measuring the string, I figured it would be better to make a simple program to test it first.

        Windows has some API functions that can be fed with a string and a font, returning some sizes. Start looking at Font and Text Functions.

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
        AFAIK the Font::Freetype suite can render you at least one given symbol. Assuming that spacing between characters will be constant, you can calculate the size of any string, using these data.

        But there is also Font::TTF, which I didn't used before - start reading from this point, I guess.