-sub table
-{
- my $self = shift;
- my $pdf = shift;
- my $page = shift;
- my $data = shift;
- my %arg = @_;
-
- #=====================================
- # Mandatory Arguments Section
- #=====================================
- unless($pdf and $page and $data)
- {
- print "Error: Mandatory parameter is missing pdf/page/data object!\n";
- return;
- }
- # Try to provide backward compatibility
- foreach my $key (keys %arg)
- {
- my $newkey = $key;
- if($newkey =~ s#^-##)
- {
- $arg{$newkey} = $arg{$key};
- delete $arg{$key};
- }
- }
- #TODO: Add code for header props compatibility and col_props comp....
- #####
- my ( $xbase, $ybase, $width, $height ) = ( undef, undef, undef, undef );
- # Could be 'int' or 'real' values
- $xbase = $arg{'x' } || -1;
- $ybase = $arg{'start_y'} || -1;
- $width = $arg{'w' } || -1;
- $height = $arg{'start_h'} || -1;
-
- # Global geometry parameters are also mandatory.
- unless( $xbase > 0 ){ print "Error: Left Edge of Table is NOT defined!\n"; return; }
- unless( $ybase > 0 ){ print "Error: Base Line of Table is NOT defined!\n"; return; }
- unless( $width > 0 ){ print "Error: Width of Table is NOT defined!\n"; return; }
- unless( $height > 0 ){ print "Error: Height of Table is NOT defined!\n"; return; }
-
- # Ensure default values for -next_y and -next_h
- my $next_y = $arg{'next_y'} || $arg{'start_y'} || 0;
- my $next_h = $arg{'next_h'} || $arg{'start_h'} || 0;
-
- # Create Text Object
- my $txt = $page->text;
- # Set Default Properties
- my $fnt_name = $arg{'font' } || $pdf->corefont('Times',-encode => 'utf8');
- my $fnt_size = $arg{'font_size' } || 12;
- my $max_word_len= $arg{'max_word_length' } || 20;
-
- #=====================================
- # Table Header Section
- #=====================================
- # Disable header row into the table
- my $header_props = 0;
- # Check if the user enabled it ?
- if(defined $arg{'header_props'} and ref( $arg{'header_props'}) eq 'HASH')
- {
- # Transfer the reference to local variable
- $header_props = $arg{'header_props'};
- # Check other params and put defaults if needed
- $header_props->{'repeat' } = $header_props->{'repeat' } || 0;
- $header_props->{'font' } = $header_props->{'font' } || $fnt_name;
- $header_props->{'font_color' } = $header_props->{'font_color' } || '#000066';
- $header_props->{'font_size' } = $header_props->{'font_size' } || $fnt_size + 2;
- $header_props->{'bg_color' } = $header_props->{'bg_color' } || '#FFFFAA';
- }
- my $header_row = undef;
- #=====================================
- # Other Parameters check
- #=====================================
-
- my $lead = $arg{'lead' } || $fnt_size;
- my $pad_left = $arg{'padding_left' } || $arg{'padding'} || 0;
- my $pad_right = $arg{'padding_right' } || $arg{'padding'} || 0;
- my $pad_top = $arg{'padding_top' } || $arg{'padding'} || 0;
- my $pad_bot = $arg{'padding_bottom' } || $arg{'padding'} || 0;
- my $pad_w = $pad_left + $pad_right;
- my $pad_h = $pad_top + $pad_bot ;
- my $line_w = defined $arg{'border'} ? $arg{'border'} : 1 ;
-
- my $background_color_even = $arg{'background_color_even' } || $arg{'background_color'} || undef;
- my $background_color_odd = $arg{'background_color_odd' } || $arg{'background_color'} || undef;
- my $font_color_even = $arg{'font_color_even' } || $arg{'font_color' } || 'black';
- my $font_color_odd = $arg{'font_color_odd' } || $arg{'font_color' } || 'black';
- my $border_color = $arg{'border_color' } || 'black';
-
- my $min_row_h = $fnt_size + $pad_top + $pad_bot;
- my $row_h = defined ($arg{'row_height'})
- &&
- ($arg{'row_height'} > $min_row_h)
- ?
- $arg{'row_height'} : $min_row_h;
-
- my $pg_cnt = 1;
- my $cur_y = $ybase;
- my $cell_props = $arg{cell_props} || []; # per cell properties
- my $row_cnt = ( ref $header_props and $header_props->{'repeat'} ) ? 1 : 0; # current row in user data
-
- #If there is valid data array reference use it!
- if(ref $data eq 'ARRAY')
- {
- # Copy the header row if header is enabled
- @$header_row = $$data[0] if defined $header_props;
- # Determine column widths based on content
-
- # an arrayref whose values are a hashref holding
- # the minimum and maximum width of that column
- my $col_props = $arg{'column_props'} || [];
-
- # An array ref of arrayrefs whose values are
- # the actual widths of the column/row intersection
- my $row_props = [];
- # An array ref with the widths of the header row
- my $header_row_props = [];
-
- # Scalars that hold sum of the maximum and minimum widths of all columns
- my ( $max_col_w , $min_col_w ) = ( 0,0 );
- my ( $row, $col_name, $col_fnt_size, $space_w );
-
- # Hash that will hold the width of every word from input text
- my $word_w = {};
- my $rows_counter = 0;
- my $first_row = 1;
-
- foreach $row ( @{$data} )
- {
- my $column_widths = []; #holds the width of each column
- for( my $j = 0; $j < scalar(@$row) ; $j++ )
- {
- # look for font information for this column
- $col_fnt_size = $col_props->[$j]->{'font_size'} || $fnt_size;
- if( !$rows_counter and ref $header_props)
- {
- $txt->font( $header_props->{'font'}, $header_props->{'font_size'} );
- }
- elsif( $col_props->[$j]->{'font'} )
- {
- $txt->font( $col_props->[$j]->{'font'}, $col_fnt_size );
- }
- else
- {
- $txt->font( $fnt_name, $col_fnt_size );
- }
-
- # This should fix a bug with very long word like serial numbers etc.
- # $myone is used because $1 gets out of scope in while condition
- my $myone;
- do{
- $myone = 0;
- # This RegEx will split any word that is longer than {25} symbols
- $row->[$j] =~ s#(\b\S{$max_word_len}?)(\S.*?\b)# $1 $2#;
- $myone = 1 if( defined $2 );
- }while( $myone );
-
- $space_w = $txt->advancewidth( "\x20" );
- $column_widths->[$j] = 0;
- $max_col_w = 0;
- $min_col_w = 0;
-
- my @words = split( /\s+/, $row->[$j] );
-
- foreach( @words )
- {
- unless( exists $word_w->{$_} )
- { # Calculate the width of every word and add the space width to it
- $word_w->{$_} = $txt->advancewidth( $_ ) + $space_w;
- }
- $column_widths->[$j] += $word_w->{$_};
- $min_col_w = $word_w->{$_} if $word_w->{$_} > $min_col_w;
- $max_col_w += $word_w->{$_};
- }
- $min_col_w += $pad_w;
- $max_col_w += $pad_w;
- $column_widths->[$j] += $pad_w;
-
- # Keep a running total of the overall min and max widths
- $col_props->[$j]->{min_w} = $col_props->[$j]->{min_w} || 0;
- $col_props->[$j]->{max_w} = $col_props->[$j]->{max_w} || 0;
-
- if( $min_col_w > $col_props->[$j]->{min_w} )
- { # Calculated Minimum Column Width is more than user-defined
- $col_props->[$j]->{min_w} = $min_col_w ;
- }
- if( $max_col_w > $col_props->[$j]->{max_w} )
- { # Calculated Maximum Column Width is more than user-defined
- $col_props->[$j]->{max_w} = $max_col_w ;
- }
- }#End of for(my $j....
- $row_props->[$rows_counter] = $column_widths;
- # Copy the calculated row properties of header row.
- @$header_row_props = @$column_widths if(!$rows_counter and ref $header_props);
- $rows_counter++;
- }
- # Calc real column widths and expand table width if needed.
- my $calc_column_widths;
- ($calc_column_widths, $width) = $self->CalcColumnWidths( $col_props, $width );
- my $num_cols = scalar @{ $calc_column_widths };
- my $comp_cnt = 1;
- $rows_counter = 0;
-
- my ( $gfx , $gfx_bg , $background_color , $font_color, );
- my ( $bot_marg, $table_top_y, $text_start , $record, $record_widths );
-
- # Each iteration adds a new page as neccessary
- while(scalar(@{$data}))
- {
- my $page_header;
- if($pg_cnt == 1)
- {
- $table_top_y = $ybase;
- $bot_marg = $table_top_y - $height;
- }
- else
- {
- if(ref $arg{'new_page_func'})
- {
- $page = &{$arg{'new_page_func'}};
- }
- else
- {
- $page = $pdf->page;
- }
-
- $table_top_y = $next_y;
- $bot_marg = $table_top_y - $next_h;
-
- if( ref $header_props and $header_props->{'repeat'})
- {
- # Copy Header Data
- @$page_header = @$header_row;
- my $hrp ;
- @$hrp = @$header_row_props ;
- # Then prepend it to master data array
- unshift @$data ,@$page_header ;
- unshift @$row_props ,$hrp ;
- $first_row = 1; # Means YES
- }
- }
-
- # Check for safety reasons
- if( $bot_marg < 0 )
- { # This warning should remain i think
-# print "!!! Warning: !!! Incorrect Table Geometry! Setting bottom margin to end of sheet!\n";
- $bot_marg = 0;
- }
-
- $gfx_bg = $page->gfx;
- $txt = $page->text;
- $txt->font($fnt_name, $fnt_size);
- $gfx = $page->gfx;
- $gfx->strokecolor($border_color);
- $gfx->linewidth($line_w);
-
- # Draw the top line
- $cur_y = $table_top_y;
- $gfx->move( $xbase , $cur_y );
- $gfx->hline($xbase + $width );
-
- # Each iteration adds a row to the current page until the page is full
- # or there are no more rows to add
- while(scalar(@{$data}) and $cur_y-$row_h > $bot_marg)
- {
- # Remove the next item from $data
- $record = shift @{$data};
- # Added to resolve infite loop bug with returned undef values
- for(my $d = 0; $d < scalar(@{$record}) ; $d++)
- {
- $record->[$d] = '-' unless( defined $record->[$d]);
- }
-
- $record_widths = shift @$row_props;
- next unless $record;
-
- # Choose colors for this row
- $background_color = $rows_counter % 2 ? $background_color_even : $background_color_odd;
- $font_color = $rows_counter % 2 ? $font_color_even : $font_color_odd;
-
- if($first_row and ref $header_props)
- {
- $background_color = $header_props->{'bg_color'}
- }
- $text_start = $cur_y - $fnt_size - $pad_top;
- my $cur_x = $xbase;
- my $leftovers = undef; # Reference to text that is returned from textblock()
- my $do_leftovers = 0;
-
- my ($colspan, @vertical_lines);
-
- # Process every column from current row
- for( my $j = 0; $j < scalar( @$record); $j++ )
- {
- next unless $col_props->[$j]->{max_w};
- next unless $col_props->[$j]->{min_w};
- $leftovers->[$j] = undef;
-
- # Choose font color
- if( $first_row and ref $header_props )
- {
- $txt->fillcolor( $header_props->{'font_color'} );
- }
- elsif( $cell_props->[$row_cnt][$j]{font_color} )
- {
- $txt->fillcolor( $cell_props->[$row_cnt][$j]{font_color} );
- }
- elsif( $col_props->[$j]->{'font_color'} )
- {
- $txt->fillcolor( $col_props->[$j]->{'font_color'} );
- }
- else
- {
- $txt->fillcolor($font_color);
- }
-
- # Choose font size
- if( $first_row and ref $header_props )
- {
- $col_fnt_size = $header_props->{'font_size'};
- }
- elsif( $col_props->[$j]->{'font_size'} )
- {
- $col_fnt_size = $col_props->[$j]->{'font_size'};
- }
- else
- {
- $col_fnt_size = $fnt_size;
- }
-
- # Choose font family
- if( $first_row and ref $header_props )
- {
- $txt->font( $header_props->{'font'}, $header_props->{'font_size'});
- }
- elsif( $col_props->[$j]->{'font'} )
- {
- $txt->font( $col_props->[$j]->{'font'}, $col_fnt_size);
- }
- else
- {
- $txt->font( $fnt_name, $col_fnt_size);
- }
- #TODO: Implement Center text align
- $col_props->[$j]->{justify} = $col_props->[$j]->{justify} || 'left';
-
- my $this_width;
- if (!$first_row && $cell_props->[$row_cnt]->[$j]->{colspan}) {
- $colspan = -1 == $cell_props->[$row_cnt]->[$j]->{colspan} ? $num_cols - $j : $cell_props->[$row_cnt]->[$j]->{colspan};
- my $last_idx = $j + $colspan - 1;
- $this_width = sum @{ $calc_column_widths }[$j..$last_idx];
-
- } else {
- $this_width = $calc_column_widths->[$j];
- }
-
- # If the content is wider than the specified width, we need to add the text as a text block
- if($record->[$j] !~ m#(.\n.)# and $record_widths->[$j] and ($record_widths->[$j] < $this_width))
- {
- my $space = $pad_left;
- if($col_props->[$j]->{justify} eq 'right')
- {
- $space = $this_width -($txt->advancewidth($record->[$j]) + $pad_right);
- }
- $txt->translate( $cur_x + $space, $text_start );
- $txt->text( $record->[$j] );
- }
- # Otherwise just use the $page->text() method
- else
- {
- my($width_of_last_line, $ypos_of_last_line, $left_over_text) = $self->text_block(
- $txt,
- $record->[$j],
- x => $cur_x + $pad_left,
- y => $text_start,
- w => $this_width - $pad_w,
- h => $cur_y - $bot_marg - $pad_top - $pad_bot,
- align => $col_props->[$j]->{justify},
- lead => $lead
- );
- # Desi - Removed $lead because of fixed incorrect ypos bug in text_block
- my $this_row_h = $cur_y - ( $ypos_of_last_line - $pad_bot );
- $row_h = $this_row_h if $this_row_h > $row_h;
- if( $left_over_text )
- {
- $leftovers->[$j] = $left_over_text;
- $do_leftovers = 1;
- }
- }
- $cur_x += $calc_column_widths->[$j];
-
- push @vertical_lines, (!$colspan || (1 >= $colspan)) ? 1 : 0;
- $colspan-- if ($colspan);
- }
- if( $do_leftovers )
- {
- unshift @$data, $leftovers;
- unshift @$row_props, $record_widths;
- $rows_counter--;
- }
- # Draw cell bgcolor
- # This has to be separately from the text loop
- # because we do not know the final height of the cell until all text has been drawn
- $cur_x = $xbase;
- for(my $j =0;$j < scalar(@$record);$j++)
- {
- if ( $cell_props->[$row_cnt][$j]->{'background_color'} ||
- $col_props->[$j]->{'background_color'} ||
- $background_color )
- {
- $gfx_bg->rect( $cur_x, $cur_y-$row_h, $calc_column_widths->[$j], $row_h);
- if ( $cell_props->[$row_cnt][$j]->{'background_color'} && !$first_row )
- {
- $gfx_bg->fillcolor($cell_props->[$row_cnt][$j]->{'background_color'});
- }
- elsif( $col_props->[$j]->{'background_color'} && !$first_row )
- {
- $gfx_bg->fillcolor($col_props->[$j]->{'background_color'});
- }
- else
- {
- $gfx_bg->fillcolor($background_color);
- }
- $gfx_bg->fill();
- }
-
- $cur_x += $calc_column_widths->[$j];
-
- if ($line_w && $vertical_lines[$j] && ($j != (scalar(@{ $record }) - 1))) {
- $gfx->move($cur_x, $cur_y);
- $gfx->vline($cur_y - $row_h);
- $gfx->fillcolor($border_color);
- }
- }#End of for(my $j....
-
- $cur_y -= $row_h;
- $row_h = $min_row_h;
- $gfx->move( $xbase , $cur_y );
- $gfx->hline( $xbase + $width );
- $rows_counter++;
- $row_cnt++ unless ( $first_row );
- $first_row = 0;
- }# End of while(scalar(@{$data}) and $cur_y-$row_h > $bot_marg)
-
- # Draw vertical lines
- if ($line_w) {
- $gfx->move($xbase, $table_top_y);
- $gfx->vline($cur_y);
- $gfx->move($xbase + sum(@{ $calc_column_widths }[0..$num_cols - 1]), $table_top_y);
- $gfx->vline($cur_y);
- $gfx->fillcolor($border_color);
- $gfx->stroke();
+sub table {
+ my $self = shift;
+ my $pdf = shift;
+ my $page = shift;
+ my $data = shift;
+ my %arg = @_;
+
+ #=====================================
+ # Mandatory Arguments Section
+ #=====================================
+ unless ($pdf and $page and $data) {
+ print "Error: Mandatory parameter is missing pdf/page/data object!\n";
+ return;
+ }
+ # Try to provide backward compatibility
+ foreach my $key (keys %arg) {
+ my $newkey = $key;
+ if ($newkey =~ s#^-##) {
+ $arg{$newkey} = $arg{$key};
+ delete $arg{$key};
+ }
+ }
+ #TODO: Add code for header props compatibility and col_props comp....
+ #####
+ my ( $xbase, $ybase, $width, $height ) = ( undef, undef, undef, undef );
+ # Could be 'int' or 'real' values
+ $xbase = $arg{'x' } || -1;
+ $ybase = $arg{'start_y'} || -1;
+ $width = $arg{'w' } || -1;
+ $height = $arg{'start_h'} || -1;
+
+ # Global geometry parameters are also mandatory.
+ unless ( $xbase > 0 ) { print "Error: Left Edge of Table is NOT defined!\n"; return; }
+ unless ( $ybase > 0 ) { print "Error: Base Line of Table is NOT defined!\n"; return; }
+ unless ( $width > 0 ) { print "Error: Width of Table is NOT defined!\n"; return; }
+ unless ( $height > 0 ) { print "Error: Height of Table is NOT defined!\n"; return; }
+
+ # Ensure default values for -next_y and -next_h
+ my $next_y = $arg{'next_y'} || $arg{'start_y'} || 0;
+ my $next_h = $arg{'next_h'} || $arg{'start_h'} || 0;
+
+ # Create Text Object
+ my $txt = $page->text;
+ # Set Default Properties
+ my $fnt_name = $arg{'font'} || $pdf->corefont('Times', -encode => 'utf8');
+ my $fnt_size = $arg{'font_size'} || 12;
+ my $max_word_len = $arg{'max_word_length'} || 20;
+
+ #=====================================
+ # Table Header Section
+ #=====================================
+ # Disable header row into the table
+ my $header_props = 0;
+ # Check if the user enabled it ?
+ if (defined $arg{'header_props'} and ref( $arg{'header_props'}) eq 'HASH') {
+ # Transfer the reference to local variable
+ $header_props = $arg{'header_props'};
+ # Check other params and put defaults if needed
+ $header_props->{'repeat'} = $header_props->{'repeat'} || 0;
+ $header_props->{'font'} = $header_props->{'font'} || $fnt_name;
+ $header_props->{'font_color'} = $header_props->{'font_color'} || '#000066';
+ $header_props->{'font_size'} = $header_props->{'font_size'} || $fnt_size + 2;
+ $header_props->{'bg_color'} = $header_props->{'bg_color'} || '#FFFFAA';
+ }
+ my $header_row = undef;
+ #=====================================
+ # Other Parameters check
+ #=====================================
+
+ my $lead = $arg{'lead'} || $fnt_size;
+ my $pad_left = $arg{'padding_left'} || $arg{'padding'} || 0;
+ my $pad_right = $arg{'padding_right'} || $arg{'padding'} || 0;
+ my $pad_top = $arg{'padding_top'} || $arg{'padding'} || 0;
+ my $pad_bot = $arg{'padding_bottom'} || $arg{'padding'} || 0;
+ my $pad_w = $pad_left + $pad_right;
+ my $pad_h = $pad_top + $pad_bot ;
+ my $line_w = defined $arg{'border'} ? $arg{'border'} : 1 ;
+
+ my $background_color_even = $arg{'background_color_even'} || $arg{'background_color'} || undef;
+ my $background_color_odd = $arg{'background_color_odd'} || $arg{'background_color'} || undef;
+ my $font_color_even = $arg{'font_color_even'} || $arg{'font_color'} || 'black';
+ my $font_color_odd = $arg{'font_color_odd'} || $arg{'font_color'} || 'black';
+ my $border_color = $arg{'border_color'} || 'black';
+
+ my $min_row_h = $fnt_size + $pad_top + $pad_bot;
+ my $row_h = defined ($arg{'row_height'}) && ($arg{'row_height'} > $min_row_h) ? $arg{'row_height'} : $min_row_h;
+
+ my $pg_cnt = 1;
+ my $cur_y = $ybase;
+ my $cell_props = $arg{cell_props} || []; # per cell properties
+ my $row_cnt = ( ref $header_props and $header_props->{'repeat'} ) ? 1 : 0; # current row in user data
+
+ #If there is valid data array reference use it!
+ if (ref $data eq 'ARRAY') {
+ # Copy the header row if header is enabled
+ @$header_row = $$data[0] if defined $header_props;
+ # Determine column widths based on content
+
+ # an arrayref whose values are a hashref holding
+ # the minimum and maximum width of that column
+ my $col_props = $arg{'column_props'} || [];
+
+ # An array ref of arrayrefs whose values are
+ # the actual widths of the column/row intersection
+ my $row_props = [];
+ # An array ref with the widths of the header row
+ my $header_row_props = [];
+
+ # Scalars that hold sum of the maximum and minimum widths of all columns
+ my ( $max_col_w, $min_col_w ) = ( 0,0 );
+ my ( $row, $col_name, $col_fnt_size, $space_w );
+
+ # Hash that will hold the width of every word from input text
+ my $word_w = {};
+ my $rows_counter = 0;
+ my $first_row = 1;
+
+ foreach $row ( @{$data} ) {
+ my $column_widths = []; #holds the width of each column
+ for( my $j = 0; $j < scalar(@$row) ; $j++ ) {
+ # look for font information for this column
+ $col_fnt_size = $col_props->[$j]->{'font_size'} || $fnt_size;
+ if ( !$rows_counter and ref $header_props) {
+ $txt->font( $header_props->{'font'}, $header_props->{'font_size'} );
+
+ } elsif ( $col_props->[$j]->{'font'} ) {
+ $txt->font( $col_props->[$j]->{'font'}, $col_fnt_size );
+
+ } else {
+ $txt->font( $fnt_name, $col_fnt_size );
+ }
+
+ # This should fix a bug with very long word like serial numbers etc.
+ # $myone is used because $1 gets out of scope in while condition
+ my $myone;
+ do {
+ $myone = 0;
+ # This RegEx will split any word that is longer than {25} symbols
+ $row->[$j] =~ s#(\b\S{$max_word_len}?)(\S.*?\b)# $1 $2#;
+ $myone = 1 if ( defined $2 );
+ } while( $myone );
+
+ $space_w = $txt->advancewidth( "\x20" );
+ $column_widths->[$j] = 0;
+ $max_col_w = 0;
+ $min_col_w = 0;
+
+ my @words = split( /\s+/, $row->[$j] );
+
+ foreach( @words ) {
+ unless ( exists $word_w->{$_} ) { # Calculate the width of every word and add the space width to it
+ $word_w->{$_} = $txt->advancewidth( $_ ) + $space_w;
+ }
+ $column_widths->[$j] += $word_w->{$_};
+ $min_col_w = $word_w->{$_} if $word_w->{$_} > $min_col_w;
+ $max_col_w += $word_w->{$_};
+ }
+ $min_col_w += $pad_w;
+ $max_col_w += $pad_w;
+ $column_widths->[$j] += $pad_w;
+
+ # Keep a running total of the overall min and max widths
+ $col_props->[$j]->{min_w} = $col_props->[$j]->{min_w} || 0;
+ $col_props->[$j]->{max_w} = $col_props->[$j]->{max_w} || 0;
+
+ if ( $min_col_w > $col_props->[$j]->{min_w} ) { # Calculated Minimum Column Width is more than user-defined
+ $col_props->[$j]->{min_w} = $min_col_w ;
+ }
+ if ( $max_col_w > $col_props->[$j]->{max_w} ) { # Calculated Maximum Column Width is more than user-defined
+ $col_props->[$j]->{max_w} = $max_col_w ;
+ }
+ }#End of for(my $j....
+ $row_props->[$rows_counter] = $column_widths;
+ # Copy the calculated row properties of header row.
+ @$header_row_props = @$column_widths if (!$rows_counter and ref $header_props);
+ $rows_counter++;
+ }
+ # Calc real column widths and expand table width if needed.
+ my $calc_column_widths;
+ ($calc_column_widths, $width) = $self->CalcColumnWidths( $col_props, $width );
+ my $num_cols = scalar @{ $calc_column_widths };
+ my $comp_cnt = 1;
+ $rows_counter = 0;
+
+ my ( $gfx , $gfx_bg , $background_color , $font_color, );
+ my ( $bot_marg, $table_top_y, $text_start , $record, $record_widths );
+
+ # Each iteration adds a new page as neccessary
+ while(scalar(@{$data})) {
+ my $page_header;
+ if ($pg_cnt == 1) {
+ $table_top_y = $ybase;
+ $bot_marg = $table_top_y - $height;
+
+ } else {
+ if (ref $arg{'new_page_func'}) {
+ $page = &{$arg{'new_page_func'}};
+
+ } else {
+ $page = $pdf->page;
+ }
+
+ $table_top_y = $next_y;
+ $bot_marg = $table_top_y - $next_h;
+
+ if ( ref $header_props and $header_props->{'repeat'}) {
+ # Copy Header Data
+ @$page_header = @$header_row;
+ my $hrp ;
+ @$hrp = @$header_row_props ;
+ # Then prepend it to master data array
+ unshift @$data ,@$page_header ;
+ unshift @$row_props ,$hrp ;
+ $first_row = 1; # Means YES
+ }
+ }
+
+ # Check for safety reasons
+ if ( $bot_marg < 0 ) { # This warning should remain i think
+# print "!!! Warning: !!! Incorrect Table Geometry! Setting bottom margin to end of sheet!\n";
+ $bot_marg = 0;
+ }
+
+ $gfx_bg = $page->gfx;
+ $txt = $page->text;
+ $txt->font($fnt_name, $fnt_size);
+ $gfx = $page->gfx;
+ $gfx->strokecolor($border_color);
+ $gfx->linewidth($line_w);
+
+ # Draw the top line
+ $cur_y = $table_top_y;
+ $gfx->move( $xbase , $cur_y );
+ $gfx->hline($xbase + $width );
+
+ # Each iteration adds a row to the current page until the page is full
+ # or there are no more rows to add
+ while(scalar(@{$data}) and $cur_y-$row_h > $bot_marg) {
+ # Remove the next item from $data
+ $record = shift @{$data};
+ # Added to resolve infite loop bug with returned undef values
+ for(my $d = 0; $d < scalar(@{$record}) ; $d++) {
+ $record->[$d] = '-' unless ( defined $record->[$d]);
+ }
+
+ $record_widths = shift @$row_props;
+ next unless $record;
+
+ # Choose colors for this row
+ $background_color = $rows_counter % 2 ? $background_color_even : $background_color_odd;
+ $font_color = $rows_counter % 2 ? $font_color_even : $font_color_odd;
+
+ if ($first_row and ref $header_props) {
+ $background_color = $header_props->{'bg_color'}
+ }
+ $text_start = $cur_y - $fnt_size - $pad_top;
+ my $cur_x = $xbase;
+ my $leftovers = undef; # Reference to text that is returned from textblock()
+ my $do_leftovers = 0;
+
+ my ($colspan, @vertical_lines);
+
+ # Process every column from current row
+ for( my $j = 0; $j < scalar( @$record); $j++ ) {
+ next unless $col_props->[$j]->{max_w};
+ next unless $col_props->[$j]->{min_w};
+ $leftovers->[$j] = undef;
+
+ # Choose font color
+ if ( $first_row and ref $header_props ) {
+ $txt->fillcolor( $header_props->{'font_color'} );
+
+ } elsif ( $cell_props->[$row_cnt][$j]{font_color} ) {
+ $txt->fillcolor( $cell_props->[$row_cnt][$j]{font_color} );
+
+ } elsif ( $col_props->[$j]->{'font_color'} ) {
+ $txt->fillcolor( $col_props->[$j]->{'font_color'} );
+
+ } else {
+ $txt->fillcolor($font_color);
+ }
+
+ # Choose font size
+ if ( $first_row and ref $header_props ) {
+ $col_fnt_size = $header_props->{'font_size'};
+
+ } elsif ( $col_props->[$j]->{'font_size'} ) {
+ $col_fnt_size = $col_props->[$j]->{'font_size'};
+
+ } else {
+ $col_fnt_size = $fnt_size;
+ }
+
+ # Choose font family
+ if ( $first_row and ref $header_props ) {
+ $txt->font( $header_props->{'font'}, $header_props->{'font_size'});
+
+ } elsif ( $col_props->[$j]->{'font'} ) {
+ $txt->font( $col_props->[$j]->{'font'}, $col_fnt_size);
+
+ } else {
+ $txt->font( $fnt_name, $col_fnt_size);
+ }
+ #TODO: Implement Center text align
+ $col_props->[$j]->{justify} = $col_props->[$j]->{justify} || 'left';
+
+ my $this_width;
+ if (!$first_row && $cell_props->[$row_cnt]->[$j]->{colspan}) {
+ $colspan = -1 == $cell_props->[$row_cnt]->[$j]->{colspan} ? $num_cols - $j : $cell_props->[$row_cnt]->[$j]->{colspan};
+ my $last_idx = $j + $colspan - 1;
+ $this_width = sum @{ $calc_column_widths }[$j..$last_idx];
+
+ } else {
+ $this_width = $calc_column_widths->[$j];
+ }
+
+ # If the content is wider than the specified width, we need to add the text as a text block
+ if ($record->[$j] !~ m#(.\n.)# and $record_widths->[$j] and ($record_widths->[$j] < $this_width)) {
+ my $space = $pad_left;
+ if ($col_props->[$j]->{justify} eq 'right') {
+ $space = $this_width -($txt->advancewidth($record->[$j]) + $pad_right);