Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

PDF::API2 - Test text that will fit in area

by flexvault (Monsignor)
on Nov 11, 2013 at 17:57 UTC ( #1062029=perlquestion: print w/replies, xml ) Need Help??
flexvault has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,

I need to limit the size of text to what will fit in a specific PDF area. Everything I've searched on or tried has not worked. I'm sure I used something to do this in the past, but now I can't find a working version. Any pointers to current documentation that would provide this feature?

Regards...Ed

"Well done is better than well said." - Benjamin Franklin

  • Comment on PDF::API2 - Test text that will fit in area

Replies are listed 'Best First'.
Re: PDF::API2 - Test text that will fit in area
by tangent (Vicar) on Nov 11, 2013 at 18:25 UTC
    There is a method called textpos() which returns the current estimated text position. Perhaps you can use that to work out the size.

    See: PDF::API2::Content

Re: PDF::API2 - Test text that will fit in area
by ltriant (Scribe) on Nov 11, 2013 at 22:12 UTC

    Look at the advancewidth() method in PDF::API2::Content for the width of the text you want to write given the current text object's state, and, for height, I personally just used the rule of thumb that 0.6 x font size (in points) will give me a good-enough approximate height of the text I'm about to write.

    Hope that helps.

      Seconded.

      Here's a hack to temporarily turn-off output, if you're wanting to pre-compute sizes using one of the higher-level methods such as text_center() or paragraph() - Re: PDF::API2 paragraph vertical align.

Re: PDF::API2 - Test text that will fit in area
by Neighbour (Friar) on Nov 12, 2013 at 08:22 UTC
    This is what I've wrote to be used at work:
    use constant mm => 25.4 / 72; use constant pt => 1; # TextBlock($texthandler, $text, $hr_options); # $texthandler can be a single PDF:API2::Content::Text-object, or an a +rrayref of these. Text will be added on all. # Options must contain: # x => x-position for the first row of text in pt # y => y-position of the baseline of the bottom row of text +in pt # width => width of the textblock in pt # height => height of the textblock in pt # Options can also contain: # lead => vertical distance between lines in pt # align => horizontal alignment of text (left, right, center) # valign => vertical alignment of text (top, bottom, center) # parspace=> Extra height to be left white at the start of each par +agraph. # wordwrap=> 1 -> wraps at wordboundries instead of characters # margin => 1 -> adds a 6mm margin on the left and 10mm on the b +ottom # force => 1 -> Disregards height and continues adding lines unti +l everything's processed. Only works with valign=top (the default) # Paragraphs are extracted from $text delimited by \n sub TextBlock { my ($ar_texthandlers, $text, $hr_original_options) = @_; my $texthandler; # Make a copy of the given options $hr_options = { %{$hr_original_options} }; # Check for non-optional parameters if (!defined $hr_options->{x}) { Carp::confess("No starting x defi +ned"); } if (!defined $hr_options->{y}) { Carp::confess("No starting y defi +ned"); } if (!defined $hr_options->{width}) { Carp::confess("No width defin +ed"); } if (!defined $hr_options->{height}) { Carp::confess("No height def +ined"); } # Add small margin to the left and bottom if (defined $hr_options->{margin}) { $hr_options->{x} += 6/mm; $hr_options->{y} += 10/mm; } given (ref $ar_texthandlers) { when ($_ eq "ARRAY") { $texthandler = $ar_texthandlers->[0]; } when ($_ eq "PDF::API2::Content::Text") { $texthandler = $ar_texthandlers; } } # Adjust y-position to be the top instead of the bottom $hr_options->{y} += $hr_options->{height}; # Defaults for optional parameters if (not defined $hr_options->{lead}) { $hr_options->{lead} = 0; } if (not defined $hr_options->{align}) { $hr_options->{align} = "le +ft"; } if (not defined $hr_options->{valign}) { $hr_options->{valign} = " +top"; } if (defined $hr_options->{force} and $hr_options->{valign} ne 'top +') { delete $hr_options->{force}; } # Only allow force with valign=to +p # Split text into paragraphs my @paragraphs = split( /\n/, $text ); # calculate width of all characters my @chars = split( "", $text ); my %width = (); $space_width = $texthandler->advancewidth(' '); foreach (@chars) { if (exists $width{$_}) { next; } $width{$_} = $texthandler->advancewidth($_); } my ($xpos, $ypos) = ($hr_options->{x}, $hr_options->{y} - ($textha +ndler->{' fontsize'}/pt / 2)); my $ar_resultdata = []; while (@paragraphs) { my @Current_Paragraph; if ($hr_options->{wordwrap}) { @Current_Paragraph = split(' ', shift(@paragraphs)); # Cre +ate array of words of the first entry in @paragraphs. } else { @Current_Paragraph = split('', shift(@paragraphs)); # Crea +te array of characters of the first entry in @paragraphs. } my $line_in_paragraph = 0; if ($hr_options->{parspace}) { $ypos -= $hr_options->{parspace +}; } if ($ypos < $hr_options->{y} - $hr_options->{height}) { last; +} my $xpos = $hr_options->{x}; # New alinea starts again at $hr_ +options->{x} # while there's room on the line, add another word my @line = (); my $line_width = 0; while (@Current_Paragraph) { my $Current_Item = shift(@Current_Paragraph); if ($hr_options->{wordwrap}) { my $wordwidth = $width{' '}; foreach my $character (split('', $Current_Item)) { $wordwidth += $width{$character}; } if ($line_width + $wordwidth < $hr_options->{width}) { $line_width += $wordwidth; if (@line) { push(@line, ' '); } push(@line, $Current_Item); next; } elsif ($wordwidth > $hr_options->{width}) { # Current word is wider than the total allotted sp +ace. Skip this word. next; } } else { if ($line_width + $width{$Current_Item} < $hr_options- +>{width}) { $line_width += $width{$Current_Item}; push(@line, $Current_Item); next; } elsif ($width{$Current_Item} > $hr_options->{width}) + { Carp::carp("Single character doesn't fit in allott +ed width. Stopping."); @paragraphs = (); last; } } # Current word/character in $_ doesn't fit on the current +line. # Perform horizontal alignment given ($hr_options->{align}) { when ($_ eq 'right') { $xpos = $hr_options->{x} + $hr_options->{width} - +$line_width; } when ($_ eq 'center') { $xpos = $hr_options->{x} + $hr_options->{width} / +2 - $line_width / 2; } when ($_ eq 'justify') { # multiply spaces so that the full width is used # Not implemented yet } } # Save current line push(@{$ar_resultdata}, { x => $xpos, y => $ypos, text => +join('', @line) }); # Clear and reset current line and line_width @line = (); $line_width = 0; # Advance to the next line $ypos -= $hr_options->{lead}; if (!defined $hr_options->{force} and $ypos < $hr_options- +>{y} - $hr_options->{height}) { # No more room for another line Carp::carp("No room for the next line at ypos [$ypos], + ybegin [$hr_options->{y}], height [$hr_options->{height}]"); @paragraphs = (); # Cancel all remaining text last; # Stop processing } # There is room for another line. Try the current word/cha +racter in $_ again. unshift(@Current_Paragraph, $Current_Item); redo; } # If there is data in @line, there was an unfinished line bein +g processed. Finish and save it. if (@line) { # Perform horizontal alignment given ($hr_options->{align}) { when ($_ eq 'right') { $xpos = $hr_options->{x} + $hr_options->{width} - +$line_width; } when ($_ eq 'center') { $xpos = $hr_options->{x} + $hr_options->{width} / +2 - $line_width / 2; } when ($_ eq 'justify') { # multiply spaces so that the full width is used # Not implemented yet } } push(@{$ar_resultdata}, { x => $xpos, y => $ypos, width => + $line_width, text => join('', @line) }); @line = (); $line_width = 0; if (@paragraphs) { $ypos -= $hr_options->{lead}; } # Only +go to the new line if there's more text to be processed } } # Perform vertical alignment my $text_height = ($hr_options->{y} - $texthandler->{' fontsize'}/ +pt /2) - $ypos; given ($hr_options->{valign}) { when ($_ eq 'bottom') { foreach my $hr_line (@{$ar_resultdata}) { $hr_line->{y} = $hr_line->{y} - $hr_options->{height} ++ $text_height + ($texthandler->{' fontsize'}/pt /2); } } when ($_ eq 'center') { foreach my $hr_line (@{$ar_resultdata}) { $hr_line->{y} = $hr_line->{y} - ($hr_options->{height} + / 2) + ($text_height / 2) + ($texthandler->{' fontsize'}/pt / 4); } } } # render the lines given (ref $ar_texthandlers) { when ($_ eq "ARRAY") { foreach my $texthandler (@{$ar_texthandlers}) { foreach my $hr_line (@{$ar_resultdata}) { $texthandler->translate($hr_line->{x}, $hr_line->{ +y}); $texthandler->text($hr_line->{text}); } } } when ($_ eq "PDF::API2::Content::Text") { foreach my $hr_line (@{$ar_resultdata}) { $texthandler->translate($hr_line->{x}, $hr_line->{y}); $texthandler->text($hr_line->{text}); } } } }

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1062029]
Approved by Corion
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (4)
As of 2018-06-24 00:04 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?



    Results (126 votes). Check out past polls.

    Notices?