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

Dear Monks. I am new to perl and have been using the excellent PDF::API2 module.

I wish to create a series of paragraphs on a document so that the text flows from one to the other.

I can successfully create a paragraph using the following code

My paragraph is

my $paragraph="erci ent ulluptat vel eum zzriure feuguero core conseni +s adignim irilluptat praessit la con henit velis dio ex enim ex ex eu +guercilit il enismol eseniam, suscing essequis nit iliquip erci blam +dolutpatisi. Orpero do odipit ercilis ad er augait ing ex elit autatio od minisis a +mconsequam";

And my code snippet is

my $txt=$page->text; $txt->textstart; $txt->lead(7); $txt->font( $font{'Helvetica'}{'Bold'}, 7 / pt ); $txt->fillcolor('red'); $txt->translate(30,265); $txt->paragraph("$paragraph", 40 /mm, 70, align => "left" );

What I need to do is to collect the text that does not fit into this paragraph (i.e. the overflow text) into a variable $overflow_text. Then I can use the contents of $overflow_text to place the remaining text into another paragraph object. There appears to be some reference to overflow text in the documentation but I cannot quite get my head around it

Thanks for your help

Replies are listed 'Best First'.
Re: PDF::API2 Paragraphs and Overflow Text
by almut (Canon) on Sep 02, 2009 at 20:12 UTC

    The docs (and the source) suggests that the overflow text is simply the return value of the paragraph() method.  Have you tried

    my $overflow_text = $txt->paragraph("$paragraph", 40 /mm, 70, align => + "left" );

      Dear Almut - Thank you very much for your reply. It has worked

      I now have another question relating to the PDF::TextBlock module which can also be used to create nice paragraphs in PDFs

      .

      Firstly I have altered the code of the TextBlock.pm module at line 376

      # Don't yet know why we'd want to return @paragraphs... # unshift( @paragraphs, join( ' ', @paragraph ) ) if scalar(@paragr +aph); # return ( $endw, $ypos ); # , join( "\n", @paragraphs ) ) unshift( @paragraphs, join( ' ', @paragraph ) ) if scalar(@paragrap +h); my $overflow = join("\n",@paragraphs); return ( $endw, $ypos, $overflow); #$overflow text returned to s +cript

      to return the overflowed text from TextBlock.pm to my script .This overflow text is then placed into a second block by my script

      My entire script for this is :-

      use PDF::API2; use PDF::TextBlock; my $pdf = PDF::API2->new( -file => "/home/mytest.pdf" ); my $tb = PDF::TextBlock->new({ pdf => $pdf, x => 120, y => 350, w => 350, h => 300, fonts => { b => PDF::TextBlock::Font->new({ pdf => $pdf, font => $pdf->corefont( 'Helvetica-Bold', -encoding => ' +latin1' ), }), }, }); $tb->text( $tb->garbledy_gook . "<b>This fairly lengthy</b>\n\n". 'rather verbose sentence <b>is tagged</b> to appear ' . 'in a <b>different font, specifically the one we tagged b for "bo +ld".</b> ' . $tb->garbledy_gook . ' <href="http://www.omnihotels.com">Click here to visit Omni Hote +ls.</href> ' . $tb->garbledy_gook . "\n\n" . "New paragraph.\n\n" . "Another paragraph." ); #Get return values from altered TextBlock.pm ($endw,$ypos,$overflow)=$tb->apply; $overflow="Overflow text is :- $overflow"; #Now place the overflow text in a new text block my $tb = PDF::TextBlock->new({ pdf => $pdf, x => 120, y => 260, w => 250, h => 50, fonts => { b => PDF::TextBlock::Font->new({ pdf => $pdf, font => $pdf->corefont( 'Helvetica-Bold', -encoding => ' +latin1' ), }), }, }); $tb->text("$overflow"); $tb->apply; $pdf->save;

      However the second block containing the overflow text is on a second page

      I have 2 questions.

      1. There is a method or reference in the TextBlock.pm file for specifing which page to put the block of text on but what do I need to type in my script to access this method and put all the text blocks on page 1 or 2 etc?

      2. Would it be possible to alter the TextBlock.pm to change the colour of the text especially inside the 'markup' tags (so hyperlinks could appear blue or bold text appear red etc)? If this is not possible could one specify the colour of an entire text block

      Thank you in advance for your help

        1. There is a method or reference in the TextBlock.pm file for specifing which page to put the block of text on but what do I need to type in my script to access this method and put all the text blocks on page 1 or 2 etc?

        This isn't documented, but if you look in the source, you'll find

        sub _apply_defaults { ... # Create a new page inside our .pdf unless a page was provided. unless (defined $self->page) { $self->page($self->pdf->page); } ... }

        That is, if you supply an existing page to the constructor like this

        my $pdf = PDF::API2->new( -file => "mytest.pdf" ); my $page = $pdf->page(); my $tb = PDF::TextBlock->new({ pdf => $pdf, page => $page, # <--- ...

        then PDF::TextBlock won't create a new one itself within the apply() method.

        (you have to pass the same $page to the other constructor as well, of course, if you want both blocks to appear on the same page...)


        2. Would it be possible to alter the TextBlock.pm to change the colour of the text especially inside the 'markup' tags (so hyperlinks could appear blue or bold text appear red etc)? If this is not possible could one specify the colour of an entire text block

        For tags other than href you just have to define a fillcolor for the custom font that you're setting for the specific tag. E.g. for <b>:

        b => PDF::TextBlock::Font->new({ pdf => $pdf, font => $pdf->corefont( 'Helvetica-Bold', -encoding => ' +latin1' ), fillcolor => '#ff0000', # red }),

        An analogous approach for hyperlinks, such as

        href => PDF::TextBlock::Font->new({ pdf => $pdf, font => $pdf->corefont( 'Helvetica-Oblique', -encoding = +> 'latin1' ), fillcolor => '#0077ff', # blue }),

        unfortunately doesn't work out of the box... For one, because the href tag undergoes special built-in handling (underlining, link annotation, ...). Secondly, because the regex that's being used to filter out the tags is extracting the entire part in between <...> - i.e. href="http://www.omnihotels.com" in your case - so you'd have to define a separate custom font object for each and every link:

        'href="http://www.omnihotels.com"' => PDF::TextBlock::Font->ne +w({ ... }), 'href="http://www.foo.bar"' => ...,

        Probably not what you want...

        Anyway, here's a quick hack that seems to do the job (i.e. you can then use the above mentioned href => ... font definition similiarly to b => ..., etc.

        In case you need more functionality, it's probably time to get in contact with the author of the module... :)

        The complete diff is (your patch included (the last section)):

        $ diff -u TextBlock.pm.orig TextBlock.pm --- TextBlock.pm.orig 2009-07-13 18:45:27.000000000 +0200 +++ TextBlock.pm 2009-09-03 15:52:45.128961624 +0200 @@ -151,7 +151,7 @@ # Build %content_texts. A hash of all PDF::API2::Content::Text obj +ects, # one for each tag (<b> or <i> or whatever) in $text. my %content_texts; - foreach my $tag (($text =~ /<([^\/].*?)>/g), "default") { + foreach my $tag (($text =~ /<(\w*)[^\/].*?>/g), "default") { + next if ($content_texts{$tag}); my $content_text = $page->text; # PDF::API2::Content::Text + obj my $font; @@ -307,6 +307,7 @@ if ($tag =~ /^href/) { ($href) = ($tag =~ /href="(.*?)"/); # warn "href is now $href"; + $current_content_text = $content_texts{href} if ref + $content_texts{href}; } elsif ($tag !~ /\//) { $current_content_text = $content_texts{$tag}; } @@ -350,7 +351,8 @@ if ($word =~ /\//) { if ($word =~ /\/href/) { undef $href; - } else { + } + unless ($href) { $current_content_text = $content_texts{default}; } } @@ -374,7 +376,10 @@ # Don't yet know why we'd want to return @paragraphs... # unshift( @paragraphs, join( ' ', @paragraph ) ) if scalar(@parag +raph); - return ( $endw, $ypos ); # , join( "\n", @paragraphs ) ) + #return ( $endw, $ypos ); # , join( "\n", @paragraphs ) ) + unshift( @paragraphs, join( ' ', @paragraph ) ) if scalar(@paragra +ph); + my $overflow = join("\n",@paragraphs); + return ( $endw, $ypos, $overflow); #$overflow text returned to +script }