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

Hi Monks!
I am going to answer someone's question posted here a little while with another question to someone that really understand about this module. The problem with adding each element of the array @user_acc, I assume that these numbers are account numbers, to each link of the first column of the table generated by this code can be done by subtracting the number of rows ($row) minus one, as you can see on the code I am posting here. But the issue is when you have multiple pages, on the second page and all others if more than one page, the row count starts at the header and not on the second row like it is on the first page. Is there a way to fix this problem by starting counting the rows after the header on all pages after the first page? If not, the last rows will generate an error "Use of uninitialized value in concatenation...". This is because after the first page the row count starts on the wrong row, it starts on top of the header row, if there are more pages each header will count and more uninitialized values will be at the end of the process.
Please take a second to run this code and look at the last row, there will be no value for the link and you will also get an error "Use of uninitialized value ..."
Thanks and here is the code:

#!/usr/bin/perl use strict; use warnings; use PDF::API2; use PDF::Table; use Data::Dumper; my $pdftable = new PDF::Table; my $pdf = new PDF::API2(-file => "test.pdf"); # save where you want th +e file to be $pdf->preferences( -thumbs => 1, ); my $page_num = 1; my @user_acc = ( "11111", "22222", "29989","23957", "20467", "39989"," +7723457", "013467", "288989", "345778", "33454", "23787", "19998","23957", "20460", "39980"," +7023457", "913467", "288869", "999876", "87497", "56467", "29344","23957", "12467", "37989"," +7726667", "013488", "238989", "119876", "20417", "23067", "89980","23957", "20117", "23989"," +4423457", "223467", "788989", "945876", "29457", "23467", "299895","239u7", "20467", "39h89", +"7o23457", "013467", "288989", "341778", "03454", "23784", "199989","23957", "20460", "39980", +"7023457", "913467", "218869", "999836", "87487", "56467", "900344","23953", "12467", "37989", +"7726667", "0134p8", "238989", "117876", "2B2417","23067", "899808","23957", "20919", "23989", +"4423457", "223467", "788789", "88888", ); # some data to layout my $some_data =[ ["Name", "Address", "City", "State", "Zip", "Phone", "Address 2", "Address 3", "Address 4", "Email", ], # content, 80 rows x 10 columns map { my $row = $_; [ map "$_", 1..10 ] } 1..80, ]; main_table($pdf, $some_data); $pdf->saveas(); ############## ###### ##### sub main_table { my $pdf = shift; my $data = shift; my $page = newpage(); # first page my $col_props = [ map{ #{}, # This is an empty hash so the next one will hold the propert +ies for the second row from left to right. { min_w => 5, # Minimum column width. justify => 'center', # One of left|right , font => $pdf->corefont("Times", -encoding => "latin1"), font_size => 5, font_color=> '#003366', background_color => '#000000', }, # etc. } 1..10, ]; # build the table layout $pdftable->table( # required params $pdf, $page, $data, x => 5, w => 780, start_y => 537, # 550 next_y => 537, start_h => 500, next_h => 500, # some optional params #max_word_length=> 20, # add a space after every 20th symbol in +long words like serial numbers padding => 1, # cell padding padding_top => 2, # top cell padding, overides padding padding_right => 2, # right cell padding, overides padding padding_left => 2, # left cell padding, overides padding padding_bottom => 2, # bottom padding, overides -padding border => 1, # border width, default 1, use 0 for no bo +rder border_color => '#000000', # default black font => $pdf->corefont("Helvetica", -encoding => "utf8") +, # default font #font => $pdf->corefont("Times", -encoding => "latin1"), background_color => '#FFFF00', font_size => 7, font_color_odd => '#000000', font_color_even=> '#000000', background_color_odd => '#e0e0e0', #gray cell background colo +r for odd rows - #d2d2d2 background_color_even => '#ffffff', #lightblue cell background + color for even rows new_page_func => \&newpage, # as defined above cell_render_hook => sub { # this is our newly introduced ca +llback function my ($page, $row, $col, $x, $y, $w, $h) = @_; #print Dumper $_[1]; #my @array=qw(0 1 2 3 4 5 6 7 8); #if ($col == 0) { # do nothing except for first column if (( $col == 0) && ($row >= 1) ) { # do nothing except f +or first column #$c++; my $url; my $c=-1; foreach my $user(@user_acc){ $c++; #$url = "http://www.mysite.com?test=$row&all_rows=$ +array[0]&useraccount=$user_acc[$col]"; } my $t = $row-1; $url = "http://www.mysite.com?test=$row&all_rows=$user +_acc[$t]"; print Dumper $url."x=".$x."y=".$y."w=".$w."h=".$h; + my $annot = $page->annotation(); $annot->url( $url, -rect => [$x, $y, $x+$w, $y+$h], -border => [1,1,1] ); } }, #header_props => { repeat => 1}, header_props => { font => $pdf->corefont("Helvetica", -encodi +ng => "uft8"), font_size => 7, font_color => '#ffffff', bg_color => '#003366', repeat => 1, }, #column_props => $col_props, column_props => [ map{{justify => 'center' }}1..10, ], ); } sub newpage { my $page = $pdf->page; $page->mediabox(792,612); header($page); footer($page); page_nr($page, $page_num++); return $page; } sub header { my $page = shift; # we need a page to place ourselves on my $head_data =[ ["User Information",], ["Data 1",], ["Auto Report System",] ]; $pdftable->table( # required params $pdf, $page, $head_data, x => 20, w => 750, start_y => 594, # top od doc on page - 594 next_y => 594, start_h => 100, next_h => 100, #OPTIONAL PARAMS BELOW #max_word_length=> 20, # add a space after every 20th symbo +l in long words like serial numbers padding => 3, # cell padding padding_top => 1, # top cell padding, overides padding #padding_right => 1, # right cell padding, overides paddi +ng #padding_left => 5, # left cell padding, overides paddin +g #padding_bottom => 5, # bottom padding, overides -padding border => 1, # border width, default 1, use 0 for + no border border_color => '#ffffff', # default black #font => $pdf->corefont("Helvetica", -encoding => " +utf8"), # default font #font_size => 10, #font_color_odd => 'black', #font_color_even=> 'black', #background_color_odd => "#ffffff", #background_color_even => "#003366", #cell background color f +or even rows #header_props => $hdr_props, column_props => [ { justify => 'center' } ], ); } sub footer { my $page = shift; # we need a page to place ourselves on my $footer_data =[ [ get_date() ] ]; $pdftable->table( # required params $pdf, $page, $footer_data, x => 20, w => 750, start_y => 30, # top od doc on page next_y => 30, start_h => 30, next_h => 30, #OPTIONAL PARAMS BELOW #max_word_length=> 20, # add a space after every 20th symbo +l in long words like serial numbers padding => 1, # cell padding border => 1, # border width, default 1, use 0 for + no border border_color => '#ffffff', # default black font => $pdf->corefont("Helvetica", -encoding => "u +tf8"), # default font font_size => 7, #header_props => $hdr_props, column_props => [ { justify => 'center' } ], ); } sub page_nr { my $page = shift; my $num = shift; $page->gfx->textlabel( # PDF::API2 method 760, 15, # x, y $pdf->corefont("Helvetica"), 8, # font, size "Page $num", # text -color => '#808080', -align => 'right', ); } sub get_date { my ($mon, $mday, $year) = (localtime)[4,3,5]; return sprintf '%02d-%02d-%04d', $mon+1, $mday, $year+1900; }


Thanks again!

Replies are listed 'Best First'.
Re: PDF::API2 Bug
by jethro (Monsignor) on May 29, 2009 at 18:04 UTC

    I ran your code with perl10.0 on linux and there was no "unititialized value" error. The table in the pdf file was full of numbers 1 to 10 in each row and no link

    Apart from that your description of the problem is very confusing. You don't say what this program should do, why you need to subtract 1 from $row, WHERE in the code this subtracting is happening, where in the code the warning is produced. Sure I could read the code, but this is a lot of code to read.

      Place your mouse on the links on the values inside the cells of the first column, notice that on the second page the last value of the link is empty. On the second page the header "Name" gets the link and the last row value for the link is empty, the count on the second page should start on the row below the header not on the first row.
        Not what I am seeing. There are no links, even if I hoover with the mouse over the numbers inside the cells (I'm looking at the pdf with adobe reader 9.1).
Re: PDF::API2 Bug
by almut (Canon) on May 29, 2009 at 23:53 UTC

    The solution for that problem (nothing to do with PDF::API2, btw) would be to patch my patch :)  i.e. pass $row_cnt instead of $rows_counter to the callback function (from within PDF::Table). The latter counts all displayed rows irrespective of whether they're headers, while the former counts data rows only.

    And while you're at it, you might also want to pass $first_row, which indicates whether it's a header row — so you can then write

    cell_render_hook => sub { my ($page, $row, $col, $is_first_row, $x, $y, $w, $h) = +@_; if (( $col == 0) && (!$is_first_row) ) { # ...instead of this (which doesn't work) # if (( $col == 0) && ($row >= 1) ) { my $t = $row-1; ...

    For reference, the corresponding modified patch to PDF::Table would then look like this:

    if (ref $arg{cell_render_hook} eq 'CODE') { $arg{cell_render_hook}->( $page, $row_cnt, $j, $first_row, $cur_x, $cur_y-$row_h, $calc_column_widths->[$j], $row_h ); }
      Thank you! That was exactly the where the problem was!