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

Hi All:

I am working on generating pdf documents using API2. The format is tight and I have a small amount of real estate in which to display freeform text, which HAS to be in a variable pitch font. The only way to handle this situation is to dynamically change the text size output to the pdf document.

To date I have implemented a scheme to look at the block of text to determine the total number of characters, total number of words, characters per word, etc.. I then step through a matrix I setup to guess based on a certain font size the number of characters and/or words that will fit on a single line, and how many lines will fit into the given area, based on number of words, characters per word, number of resulting lines, etc.. I then dynamically adjust the font size and the number of words per line until I find a combination that will allow me to display the text in the allotted area.

Unfortunately, since it is a variable pitch font if try to use as much of the page as possible and I run into instances where if the text has a lot of "fat" characters the text is truncated off of the page. If I set my matrix up in conservative mode and the text has a lot of skinny characters then I am left with a lot of unused whitespace. I am continually tweaking this algorithm, making it better in some cases and worse in others!

Every time I revisit this code I keep thinking that there must be a better way. My problem is that I am basing my font size decisions based on the number of characters/words, where is really has to be based on the size of the character as rendered by API2. Is anyone aware of a way in API2 that I could to something like setup a text area and then let API2 determine the best way to present the data?

Thanks!

Replies are listed 'Best First'.
Re: Adjustable pdf text size in API2
by john_oshea (Priest) on Jan 31, 2006 at 16:42 UTC

    If you're using the core 14 fonts, the widths for each character are defined as part of the font's internal representation - in particular, there's a 'wx' hash which maps a width to each character. For non-core fonts, you could get at the bounding box of each character via PDF::API2::Basic::TTF::Glyph and derive the width from that.

    For either approach, you'd have to take the character width, multiply by whatever text size you're actually outputting at and get a final display width for a given character from that. It'd be tedious, but I can't (at the moment) see a higher-level way of getting the widths you need.

    Note: this doesn't take into account kerning pairs, which may or may not matter in your particular case.

    Hope that helps.

    Update: Ignore this - see GhodMode's reply for a much better answer.

Re: Adjustable pdf text size in API2
by GhodMode (Pilgrim) on Jan 31, 2006 at 16:44 UTC
    You can use the advancewidth( string ) method of the text object to tell you the exact width of a line. It will tell you the width of whatever string of characters you give it as an argument using the current font attributes of the text object. It's important to note that it doesn't matter at all what you've already added to the PDF with that text object. It just measures the string you give it. Here are some bits and pieces of code:
    my $page = $pdf->page; my $text = $page->text; my $font_size = 10; my $font = $pdf->corefont( "Times-Roman" ); my $bold = $pdf->corefont( "Times-Bold" ); my $italic = $pdf->corefont( "Times-Italic" ); $text->font( $bold, $font_size ); # ... sub text { my $text = $_[0]; my $x = $_[1]; my $y = $_[2]; my $alignment = $_[3]; my $string = $_[4]; $text->translate( $x, $y ); if ( $alignment eq "right" ) { $text->text_right( $string ); } elsif ( $alignment eq "center" ) { $text->text_center( $string ); } elsif ( $alignment eq "justified" ) { $text->text_justified( $string ); } else { $text->text( $string ); } return $text->advancewidth( $string ); } # End text subroutine
    Are you trying to make paragraphs that fit the page, or a section of the page? If you post some of your code, I could offer some ideas.
    --
    -- GhodMode