Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision a5a81f46

Von Moritz Bunkus vor mehr als 5 Jahren hinzugefügt

  • ID a5a81f46c232cbbc19ee1024194ff339708d22e1
  • Vorgänger 46e9355a
  • Nachfolger 7cb1a2fe

Module: Update von PDF::Table auf 0.10.1

Unterschiede anzeigen:

doc/modules/README.PDF-Table
1
PDF-Table version 0.9.3
2
=====================
3
SOME NOTES
1
# PDF::Table
4 2

  
5
This module is intended for table generation using PDF::API2
6
The current version is RC1 and I will apreciate any feedback.
7
Developed and tested on i586 Linux SuSE 10.0 and perl, v5.8.7 built for i586-linux-thread-multi
3
This module creates text blocks and tables into PDF documents using PDF::API2 Perl module.
8 4

  
9
CHANGES
5
The official repository for PDF::Table module collaboration:
6
https://github.com/kamenov/PDF-Table.git
10 7

  
11
Since version 0.02 there are many changes. 
12
See the ChangeLog file or make a diff from the tools menu in CPAN
8
Any patches, pull requests, issues and feedback are more than welcome.
13 9

  
14
CONTACTS 
10
## Installation
15 11

  
16
See http://search.cpan.org/~omega/
12
To install the module from CPAN, please type the following command:
17 13

  
18
INSTALLATION
14
```cpanm PDF::Table```
19 15

  
20
To install this module type the following:
16
To test or add features to this module, please type the following command:
21 17

  
22
   perl Makefile.PL
23
   make
24
   make test
25
   make install
18
```cpanm .```
26 19

  
27
DEPENDENCIES
20
## Changes
21
To see a list of changes, please do one or more of the following:
22
- Read the [Changes](Changes) file
23
- Review commits history on GitHub
24
- Make a diff from the tools menu at CPAN
28 25

  
29
This module requires these other modules and libraries:
26
## Contacts 
27
@deskata on Twitter 
30 28

  
31
  PDF::API2
32

  
33
COPYRIGHT AND LICENCE
34

  
35
Put the correct copyright and licence information here.
29
- Use the issue tracker on GitHub
30
- See http://search.cpan.org/~omega/
31
- See http://search.cpan.org/~jbazik/
36 32

  
33
## License
37 34
Copyright (C) 2006 by Daemmon Hughes
38 35

  
39 36
Extended by Desislav Kamenov since version 0.02
......
41 38
This library is free software; you can redistribute it and/or modify
42 39
it under the same terms as Perl itself, either Perl version 5.8.7 or,
43 40
at your option, any later version of Perl 5 you may have available.
44

  
45

  
modules/override/PDF/Table.pm
1
package PDF::Table;
1
#!/usr/bin/env perl
2
# vim: softtabstop=4 tabstop=4 shiftwidth=4 ft=perl expandtab smarttab
2 3

  
3 4
use 5.006;
4 5
use strict;
5 6
use warnings;
7

  
8
package PDF::Table;
9

  
6 10
use Carp;
7
use List::Util qw(sum);
8
our $VERSION = '0.9.10';
11
our $VERSION = '0.10.1';
9 12

  
10 13
print __PACKAGE__.' is version: '.$VERSION.$/ if($ENV{'PDF_TABLE_DEBUG'});
11 14

  
......
36 39
{
37 40
    my ($self, $pdf, $page, $data, %options ) = @_;
38 41

  
39
    # Check and set default values 
42
    # Check and set default values
40 43
    $self->set_defaults();
41 44

  
42 45
    # Check and set mandatory params
......
49 52
}
50 53

  
51 54
sub set_defaults{
52
	my $self = shift;
53
	
54
	$self->{'font_size'} = 12;
55
    my $self = shift;
56

  
57
    $self->{'font_size'} = 12;
55 58
}
56 59

  
57 60
sub set_pdf{
......
98 101
    my $text        = shift;    # The text to be displayed
99 102
    my %arg         = @_;       # Additional Arguments
100 103

  
101
    my  ( $align, $xpos, $ypos, $xbase, $ybase, $line_width, $wordspace, $endw , $width, $height) = 
104
    my  ( $align, $xpos, $ypos, $xbase, $ybase, $line_width, $wordspace, $endw , $width, $height) =
102 105
        ( undef , undef, undef, undef , undef , undef      , undef     , undef , undef , undef  );
103
    my @line        = ();       # Temp data array with words on one line 
106
    my @line        = ();       # Temp data array with words on one line
104 107
    my %width       = ();       # The width of every unique word in the givven text
105 108

  
106 109
    # Try to provide backward compatibility
......
129 132
    # Check if any text to display
130 133
    unless( defined( $text) and length($text) > 0 )
131 134
    {
132
#         carp "Warning: No input text found. Trying to add dummy '-' and not to break everything.\n";
133
        $text = ' ';
135
        carp "Warning: No input text found. Trying to add dummy '-' and not to break everything.\n";
136
        $text = '-';
134 137
    }
135 138

  
136 139
    # Strip any <CR> and Split the text into paragraphs
......
143 146
    # Calculate width of all words
144 147
    my $space_width = $text_object->advancewidth("\x20");
145 148
    my @words = split(/\s+/, $text);
146
    foreach (@words) 
149
    foreach (@words)
147 150
    {
148 151
        next if exists $width{$_};
149 152
        $width{$_} = $text_object->advancewidth($_);
......
157 160
    $xpos = $xbase;
158 161
    $ypos = $ybase;
159 162
    $ypos = $ybase + $line_space;
160
    my $bottom_border = $ypos - $height; 
163
    my $bottom_border = $ypos - $height;
161 164
    # While we can add another line
162
    while ( $ypos >= $bottom_border + $line_space ) 
165
    while ( $ypos >= $bottom_border + $line_space )
163 166
    {
164 167
        # Is there any text to render ?
165
        unless (@paragraph) 
168
        unless (@paragraph)
166 169
        {
167 170
            # Finish if nothing left
168 171
            last unless scalar @paragraphs;
......
178 181
        # While there's room on the line, add another word
179 182
        @line = ();
180 183
        $line_width = 0;
181
        if( $first_line && exists $arg{'hang'} ) 
184
        if( $first_line && exists $arg{'hang'} )
182 185
        {
183 186
            my $hang_width = $text_object->advancewidth($arg{'hang'});
184
    
187

  
185 188
            $text_object->translate( $xpos, $ypos );
186 189
            $text_object->text( $arg{'hang'} );
187
    
190

  
188 191
            $xpos         += $hang_width;
189 192
            $line_width   += $hang_width;
190 193
            $arg{'indent'} += $hang_width if $first_paragraph;
191 194
        }
192
        elsif( $first_line && exists $arg{'flindent'} && $arg{'flindent'} > 0 ) 
195
        elsif( $first_line && exists $arg{'flindent'} && $arg{'flindent'} > 0 )
193 196
        {
194 197
            $xpos += $arg{'flindent'};
195 198
            $line_width += $arg{'flindent'};
196 199
        }
197
        elsif( $first_paragraph && exists $arg{'fpindent'} && $arg{'fpindent'} > 0 ) 
200
        elsif( $first_paragraph && exists $arg{'fpindent'} && $arg{'fpindent'} > 0 )
198 201
        {
199 202
            $xpos += $arg{'fpindent'};
200 203
            $line_width += $arg{'fpindent'};
201 204
        }
202
        elsif (exists $arg{'indent'} && $arg{'indent'} > 0 ) 
205
        elsif (exists $arg{'indent'} && $arg{'indent'} > 0 )
203 206
        {
204 207
            $xpos += $arg{'indent'};
205 208
            $line_width += $arg{'indent'};
206 209
        }
207
    
208
        # Lets take from paragraph as many words as we can put into $width - $indent; 
209
        # Always take at least one word; otherwise we'd end up in an infinite loop.
210
        while ( !scalar(@line) || (
211
          @paragraph && (
212
            $text_object->advancewidth( join("\x20", @line)."\x20" . $paragraph[0]) + $line_width < $width
213
          )
214
        ))
210

  
211
        # Lets take from paragraph as many words as we can put into $width - $indent;
212
        while ( @paragraph and $text_object->advancewidth( join("\x20", @line)."\x20" . $paragraph[0]) +
213
                                $line_width < $width )
215 214
        {
216 215
            push(@line, shift(@paragraph));
217 216
        }
218 217
        $line_width += $text_object->advancewidth(join('', @line));
219
            
218

  
220 219
        # calculate the space width
221
        if( $arg{'align'} eq 'fulljustify' or ($arg{'align'} eq 'justify' and @paragraph)) 
220
        if( $arg{'align'} eq 'fulljustify' or ($arg{'align'} eq 'justify' and @paragraph))
222 221
        {
223 222
            @line = split(//,$line[0]) if (scalar(@line) == 1) ;
224 223
            $wordspace = ($width - $line_width) / (scalar(@line) - 1);
225 224
            $align='justify';
226
        } 
227
        else 
225
        }
226
        else
228 227
        {
229 228
            $align=($arg{'align'} eq 'justify') ? 'left' : $arg{'align'};
230 229
            $wordspace = $space_width;
231 230
        }
232 231
        $line_width += $wordspace * (scalar(@line) - 1);
233
    
234
        if( $align eq 'justify') 
232

  
233
        if( $align eq 'justify')
235 234
        {
236
            foreach my $word (@line) 
235
            foreach my $word (@line)
237 236
            {
238 237
                $text_object->translate( $xpos, $ypos );
239 238
                $text_object->text( $word );
240 239
                $xpos += ($width{$word} + $wordspace) if (@line);
241 240
            }
242 241
            $endw = $width;
243
        } 
244
        else 
242
        }
243
        else
245 244
        {
246 245
            # calculate the left hand position of the line
247
            if( $align eq 'right' ) 
246
            if( $align eq 'right' )
248 247
            {
249 248
                $xpos += $width - $line_width;
250
            } 
251
            elsif( $align eq 'center' ) 
249
            }
250
            elsif( $align eq 'center' )
252 251
            {
253 252
                $xpos += ( $width / 2 ) - ( $line_width / 2 );
254 253
            }
255
    
254

  
256 255
            # render the line
257 256
            $text_object->translate( $xpos, $ypos );
258 257
            $endw = $text_object->text( join("\x20", @line));
......
292 291

  
293 292
    # Validate settings key
294 293
    my %valid_settings_key = (
295
	x                     => 1,
294
        x                     => 1,
296 295
        w                     => 1,
297 296
        start_y               => 1,
298 297
        start_h               => 1,
......
313 312
        vertical_borders      => 1,
314 313
        font                  => 1,
315 314
        font_size             => 1,
315
        font_underline        => 1,
316 316
        font_color            => 1,
317 317
        font_color_even       => 1,
318
        font_color_odd        => 1,
318 319
        background_color_odd  => 1,
319 320
        background_color_even => 1,
320 321
        row_height            => 1,
......
323 324
        column_props          => 1,
324 325
        cell_props            => 1,
325 326
        max_word_length       => 1,
326
        num_header_rows       => 1,
327
        cell_render_hook      => 1,
328
        default_text          => 1,
327 329
    );
328
    foreach my $key (keys %arg) {
329
	croak "Error: Invalid setting key '$key' received." 
330
            unless (exists $valid_settings_key{$key});
331
    }
332

  
333
    # Try to provide backward compatibility
334 330
    foreach my $key (keys %arg)
335 331
    {
336
        my $newkey = $key;
337
        if($newkey =~ s#^-##)
338
        {
339
            $arg{$newkey} = $arg{$key};
340
            delete $arg{$key};
341
        }
332
        # Provide backward compatibility
333
        $arg{$key} = delete $arg{"-$key"} if $key =~ s/^-//;
334

  
335
        croak "Error: Invalid setting key '$key' received."
336
            unless exists $valid_settings_key{$key};
342 337
    }
343
    
338

  
339

  
344 340
    ######
345 341
    #TODO: Add code for header props compatibility and col_props comp....
346 342
    ######
347 343
    my ( $xbase, $ybase, $width, $height ) = ( undef, undef, undef, undef );
348 344
    # Could be 'int' or 'real' values
349
    $xbase  = $arg{'x'      } || -1;    
345
    $xbase  = $arg{'x'      } || -1;
350 346
    $ybase  = $arg{'start_y'} || -1;
351 347
    $width  = $arg{'w'      } || -1;
352 348
    $height = $arg{'start_h'} || -1;
353 349

  
354
    # Global geometry parameters are also mandatory. 
350
    # Global geometry parameters are also mandatory.
355 351
    unless( $xbase  > 0 ){ carp "Error: Left Edge of Table is NOT defined!\n";  return; }
356 352
    unless( $ybase  > 0 ){ carp "Error: Base Line of Table is NOT defined!\n"; return; }
357 353
    unless( $width  > 0 ){ carp "Error: Width of Table is NOT defined!\n";  return; }
......
365 361
    my $txt     = $page->text;
366 362

  
367 363
    # Set Default Properties
368
    my $fnt_name    = $arg{'font'            } || $pdf->corefont('Times',-encode => 'utf8');
369
    my $fnt_size    = $arg{'font_size'       } || 12;
370
    my $max_word_len= $arg{'max_word_length' } || 20;
364
    my $fnt_name       = $arg{'font'            } || $pdf->corefont('Times',-encode => 'utf8');
365
    my $fnt_size       = $arg{'font_size'       } || 12;
366
    my $fnt_underline  = $arg{'font_underline'  } || undef; # merely stating undef is the intended default
367
    my $max_word_len   = $arg{'max_word_length' } || 20;
371 368

  
372 369
    #=====================================
373 370
    # Table Header Section
374 371
    #=====================================
375 372
    # Disable header row into the table
376 373
    my $header_props = undef;
377
    my (@header_rows, @header_row_cell_props);
374

  
378 375
    # Check if the user enabled it ?
379 376
    if(defined $arg{'header_props'} and ref( $arg{'header_props'}) eq 'HASH')
380 377
    {
......
386 383
        $header_props->{'font'          } = $header_props->{'font'          } || $fnt_name;
387 384
        $header_props->{'font_color'    } = $header_props->{'font_color'    } || '#000066';
388 385
        $header_props->{'font_size'     } = $header_props->{'font_size'     } || $fnt_size + 2;
386
        $header_props->{'font_underline'} = $header_props->{'font_underline'} || $fnt_underline;
389 387
        $header_props->{'bg_color'      } = $header_props->{'bg_color'      } || '#FFFFAA';
390 388
        $header_props->{'justify'       } = $header_props->{'justify'       };
391
        $header_props->{num_header_rows } = $arg{num_header_rows } || 1;
392 389
    }
390

  
391
    my $header_row  = undef;
393 392
    #=====================================
394 393
    # Other Parameters check
395 394
    #=====================================
......
398 397
    my $pad_right     = $arg{'padding_right' } || $arg{'padding'} || 0;
399 398
    my $pad_top       = $arg{'padding_top'   } || $arg{'padding'} || 0;
400 399
    my $pad_bot       = $arg{'padding_bottom'} || $arg{'padding'} || 0;
400
    my $default_text  = $arg{'default_text'  } // '-';
401 401
    my $line_w        = defined $arg{'border'} ? $arg{'border'} : 1 ;
402 402
    my $horiz_borders = defined $arg{'horizontal_borders'}
403 403
        ? $arg{'horizontal_borders'}
......
405 405
    my $vert_borders  = defined $arg{'vertical_borders'}
406 406
        ? $arg{'vertical_borders'}
407 407
        : $line_w;
408
    
408

  
409 409
    my $background_color_even   = $arg{'background_color_even'  } || $arg{'background_color'} || undef;
410 410
    my $background_color_odd    = $arg{'background_color_odd'   } || $arg{'background_color'} || undef;
411 411
    my $font_color_even         = $arg{'font_color_even'        } || $arg{'font_color'      } || 'black';
......
413 413
    my $border_color            = $arg{'border_color'           } || 'black';
414 414

  
415 415
    my $min_row_h   = $fnt_size + $pad_top + $pad_bot;
416
    my $row_h       = defined ($arg{'row_height'}) 
417
                                && 
418
                    ($arg{'row_height'} > $min_row_h) 
419
                                ? 
416
    my $row_h       = defined ($arg{'row_height'})
417
                                &&
418
                    ($arg{'row_height'} > $min_row_h)
419
                                ?
420 420
                     $arg{'row_height'} : $min_row_h;
421 421

  
422 422
    my $pg_cnt      = 1;
......
431 431
    }
432 432

  
433 433
    # Copy the header row if header is enabled
434
    if (defined $header_props) {
435
      map { push @header_rows,           $$data[$_]       } (0..$header_props->{num_header_rows} - 1);
436
      map { push @header_row_cell_props, $$cell_props[$_] } (0..$header_props->{num_header_rows} - 1);
437
    }
434
    @$header_row = $$data[0] if defined $header_props;
438 435
    # Determine column widths based on content
439 436

  
440
    #  an arrayref whose values are a hashref holding 
437
    #  an arrayref whose values are a hashref holding
441 438
    #  the minimum and maximum width of that column
442 439
    my $col_props =  $arg{'column_props'} || [];
443 440

  
444
    # An array ref of arrayrefs whose values are 
441
    # An array ref of arrayrefs whose values are
445 442
    #  the actual widths of the column/row intersection
446 443
    my $row_col_widths = [];
447
    # An array ref with the widths of the header row 
448
    my @header_row_widths;
449
 
450
    # Scalars that hold sum of the maximum and minimum widths of all columns 
444
    # An array ref with the widths of the header row
445
    my $header_row_props = [];
446

  
447
    # Scalars that hold sum of the maximum and minimum widths of all columns
451 448
    my ( $max_col_w  , $min_col_w   ) = ( 0,0 );
452
    my ( $row, $col_name, $col_fnt_size, $space_w );
449
    my ( $row, $col_name, $col_fnt_size, $col_fnt_underline, $space_w );
453 450

  
454 451
    my $word_widths  = {};
455 452
    my $rows_height  = [];
453
    my $first_row    = 1;
456 454

  
457 455
    for( my $row_idx = 0; $row_idx < scalar(@$data) ; $row_idx++ )
458 456
    {
459
        #push @header_row_widths, [] if $row_idx < $header_props->{num_header_rows};
460

  
461 457
        my $column_widths = []; #holds the width of each column
462 458
        # Init the height for this row
463 459
        $rows_height->[$row_idx] = 0;
464
        
460

  
465 461
        for( my $column_idx = 0; $column_idx < scalar(@{$data->[$row_idx]}) ; $column_idx++ )
466 462
        {
467 463
            # look for font information for this column
468
            my ($cell_font, $cell_font_size);
469
            
464
            my ($cell_font, $cell_font_size, $cell_font_underline);
465

  
470 466
            if( !$row_idx and ref $header_props )
471
            {   
472
                $cell_font      = $header_props->{'font'};
473
                $cell_font_size = $header_props->{'font_size'};
467
            {
468
                $cell_font           = $header_props->{'font'};
469
                $cell_font_size      = $header_props->{'font_size'};
470
                $cell_font_underline = $header_props->{'font_underline'};
474 471
            }
475
            
472

  
476 473
            # Get the most specific value if none was already set from header_props
477
            $cell_font      ||= $cell_props->[$row_idx][$column_idx]->{'font'} 
474
            $cell_font      ||= $cell_props->[$row_idx][$column_idx]->{'font'}
478 475
                            ||  $col_props->[$column_idx]->{'font'}
479 476
                            ||  $fnt_name;
480
                              
477

  
481 478
            $cell_font_size ||= $cell_props->[$row_idx][$column_idx]->{'font_size'}
482 479
                            ||  $col_props->[$column_idx]->{'font_size'}
483 480
                            ||  $fnt_size;
484
                              
481

  
482
            $cell_font_underline ||= $cell_props->[$row_idx][$column_idx]->{'font_underline'}
483
                                 ||  $col_props->[$column_idx]->{'font_underline'}
484
                                 ||  $fnt_underline;
485

  
486
            # Set Font
487

  
485 488
            # Set Font
486
            $txt->font( $cell_font, $cell_font_size ); 
487
            
489
            $txt->font( $cell_font, $cell_font_size );
490

  
488 491
            # Set row height to biggest font size from row's cells
489 492
            if( $cell_font_size  > $rows_height->[$row_idx] )
490
            {   
493
            {
491 494
                $rows_height->[$row_idx] = $cell_font_size;
492 495
            }
493 496

  
494
            if (!defined $data->[$row_idx][$column_idx]) {
495
              $data->[$row_idx][$column_idx] = ' ';
496
            }
497

  
498 497
            # This should fix a bug with very long words like serial numbers etc.
499
            if( $max_word_len > 0 && $data->[$row_idx][$column_idx])
498
            if( $max_word_len > 0 )
500 499
            {
501 500
                $data->[$row_idx][$column_idx] =~ s#(\S{$max_word_len})(?=\S)#$1 #g;
502 501
            }
......
509 508

  
510 509
            my @words = split( /\s+/, $data->[$row_idx][$column_idx] );
511 510

  
512
            foreach( @words ) 
511
            foreach( @words )
513 512
            {
514 513
                unless( exists $word_widths->{$_} )
515 514
                {   # Calculate the width of every word and add the space width to it
516 515
                    $word_widths->{$_} = $txt->advancewidth( $_ ) + $space_w;
517 516
                }
518
                
517

  
519 518
                $column_widths->[$column_idx] += $word_widths->{$_};
520 519
                $min_col_w                     = $word_widths->{$_} if( $word_widths->{$_} > $min_col_w );
521 520
                $max_col_w                    += $word_widths->{$_};
522 521
            }
523
            
522

  
524 523
            $min_col_w                    += $pad_left + $pad_right;
525 524
            $max_col_w                    += $pad_left + $pad_right;
526 525
            $column_widths->[$column_idx] += $pad_left + $pad_right;
......
533 532
            {   # Calculated Minimum Column Width is more than user-defined
534 533
                $col_props->[$column_idx]->{'min_w'} = $min_col_w ;
535 534
            }
536
            
535

  
537 536
            if( $max_col_w > $col_props->[$column_idx]->{'max_w'} )
538 537
            {   # Calculated Maximum Column Width is more than user-defined
539 538
                $col_props->[$column_idx]->{'max_w'} = $max_col_w ;
540 539
            }
541 540
        }#End of for(my $column_idx....
542
        
541

  
543 542
        $row_col_widths->[$row_idx] = $column_widths;
544
        
545
        # Copy the calculated row properties of header row. 
546
        if (ref $header_props && $row_idx < $header_props->{num_header_rows}) {
547
          push @header_row_widths, [ @{ $column_widths } ];
548
        }
543

  
544
        # Copy the calculated row properties of header row.
545
        @$header_row_props = @$column_widths if(!$row_idx and ref $header_props);
549 546
    }
550 547

  
551 548
    # Calc real column widths and expand table width if needed.
552
    my $calc_column_widths; 
549
    my $calc_column_widths;
553 550
    ($calc_column_widths, $width) = CalcColumnWidths( $col_props, $width );
554
    my $num_cols = scalar @{ $calc_column_widths };
555 551

  
556 552
    # Lets draw what we have!
557 553
    my $row_index    = 0;
558 554
    # Store header row height for later use if headers have to be repeated
559
    my @header_row_heights = @$rows_height[0 .. $header_props->{num_header_rows}-1];
555
    my $header_row_height = $rows_height->[0];
560 556

  
561 557
    my ( $gfx, $gfx_bg, $background_color, $font_color, $bot_marg, $table_top_y, $text_start);
562 558

  
563
    my $remaining_header_rows = $header_props ? $header_props->{num_header_rows} : 0;
564

  
565 559
    # Each iteration adds a new page as neccessary
566 560
    while(scalar(@{$data}))
567 561
    {
568
        my ($page_header, $columns_number);
562
        my ($page_header);
563
        my $columns_number = 0;
569 564

  
570 565
        if($pg_cnt == 1)
571 566
        {
572 567
            $table_top_y = $ybase;
573 568
            $bot_marg = $table_top_y - $height;
569

  
570
            # Check for safety reasons
571
            if( $bot_marg < 0 )
572
            {   # This warning should remain i think
573
                carp "!!! Warning: !!! Incorrect Table Geometry! start_h (${height}) is above start_y (${table_top_y}). Setting bottom margin to end of sheet!\n";
574
                $bot_marg = 0;
575
            }
576

  
574 577
        }
575 578
        else
576 579
        {
577 580
            if(ref $arg{'new_page_func'})
578
            {   
579
                $page = &{$arg{'new_page_func'}};   
581
            {
582
                $page = &{$arg{'new_page_func'}};
580 583
            }
581 584
            else
582
            {   
583
                $page = $pdf->page; 
585
            {
586
                $page = $pdf->page;
584 587
            }
585
    
588

  
586 589
            $table_top_y = $next_y;
587 590
            $bot_marg = $table_top_y - $next_h;
588 591

  
592
            # Check for safety reasons
593
            if( $bot_marg < 0 )
594
            {   # This warning should remain i think
595
                carp "!!! Warning: !!! Incorrect Table Geometry! next_y or start_y (${next_y}) is above next_h or start_h (${next_h}). Setting bottom margin to end of sheet!\n";
596
                $bot_marg = 0;
597
            }
598

  
589 599
            if( ref $header_props and $header_props->{'repeat'})
590 600
            {
591
                unshift @$data,           @header_rows;
592
                unshift @$row_col_widths, @header_row_widths;
593
                unshift @$rows_height,    @header_row_heights;
594
                $remaining_header_rows = $header_props->{num_header_rows};
601
                # Copy Header Data
602
                @$page_header = @$header_row;
603
                my $hrp ;
604
                @$hrp = @$header_row_props ;
605
                # Then prepend it to master data array
606
                unshift @$data, @$page_header;
607
                unshift @$row_col_widths, $hrp;
608
                unshift @$rows_height, $header_row_height;
609

  
610
                $first_row = 1; # Means YES
611
                $row_index--; # Rollback the row_index because a new header row has been added
595 612
            }
596 613
        }
597 614

  
598
        # Check for safety reasons
599
        if( $bot_marg < 0 )
600
        {   # This warning should remain i think
601
#            carp "!!! Warning: !!! Incorrect Table Geometry! Setting bottom margin to end of sheet!\n";
602
            $bot_marg = 0;
603
        }
604

  
605 615
        $gfx_bg = $page->gfx;
606 616
        $txt = $page->text;
607
        $txt->font($fnt_name, $fnt_size); 
617
        $txt->font($fnt_name, $fnt_size);
608 618

  
609 619
        $cur_y = $table_top_y;
610 620

  
......
615 625
            $gfx->linewidth($line_w);
616 626

  
617 627
            # Draw the top line
618
            if ($horiz_borders) 
628
            if ($horiz_borders)
619 629
            {
620 630
                $gfx->move( $xbase , $cur_y );
621 631
                $gfx->hline($xbase + $width );
......
626 636
            $gfx = undef;
627 637
        }
628 638

  
629
        # Each iteration adds a row to the current page until the page is full 
639
        # Each iteration adds a row to the current page until the page is full
630 640
        #  or there are no more rows to add
631 641
        # Row_Loop
632 642
        while(scalar(@{$data}) and $cur_y-$row_h > $bot_marg)
633 643
        {
634 644
            # Remove the next item from $data
635 645
            my $record = shift @{$data};
636
            
637
            # Get columns number to know later how many vertical lines to draw
638
            # TODO: get the max number of columns per page as currently last row's columns overrides
639
            $columns_number = scalar(@$record);
646

  
647
            # Get max columns number to know later how many vertical lines to draw
648
            $columns_number = scalar(@$record)
649
                if scalar(@$record) > $columns_number;
640 650

  
641 651
            # Get the next set of row related settings
642 652
            # Row Height
......
649 659

  
650 660
            # Row cell props - TODO in another commit
651 661

  
652
            # Added to resolve infite loop bug with returned undef values
653
            for(my $d = 0; $d < scalar(@{$record}) ; $d++)
654
            { 
655
                $record->[$d] = ' ' unless( defined $record->[$d]);
656
            }
657 662

  
658 663
            # Choose colors for this row
659
            $background_color = ($row_index - $header_props->{num_header_rows}) % 2 ? $background_color_even  : $background_color_odd;
660
            $font_color       = ($row_index - $header_props->{num_header_rows}) % 2 ? $font_color_even        : $font_color_odd;
664
            $background_color = $row_index % 2 ? $background_color_even  : $background_color_odd;
665
            $font_color       = $row_index % 2 ? $font_color_even        : $font_color_odd;
661 666

  
662 667
            #Determine current row height
663 668
            my $current_row_height = $pad_top + $pre_calculated_row_height + $pad_bot;
......
675 680
            my $cur_x        = $xbase;
676 681
            my $leftovers    = undef;   # Reference to text that is returned from textblock()
677 682
            my $do_leftovers = 0;
678
            my ($colspan, @vertical_lines);
679 683

  
680 684
            # Process every cell(column) from current row
681
            for( my $column_idx = 0; $column_idx < scalar( @$record); $column_idx++ ) 
685
            for( my $column_idx = 0; $column_idx < scalar( @$record); $column_idx++ )
682 686
            {
683 687
                next unless $col_props->[$column_idx]->{'max_w'};
684
                next unless $col_props->[$column_idx]->{'min_w'};  
688
                next unless $col_props->[$column_idx]->{'min_w'};
685 689
                $leftovers->[$column_idx] = undef;
686 690

  
687 691
                # look for font information for this cell
688
                my ($cell_font, $cell_font_size, $cell_font_color, $justify);
689
                                    
690
                if( $remaining_header_rows and ref $header_props)
691
                {   
692
                    $cell_font       = $header_props->{'font'};
693
                    $cell_font_size  = $header_props->{'font_size'};
694
                    $cell_font_color = $header_props->{'font_color'};
695
                    $justify         = $header_props->{'justify'};
692
                my ($cell_font, $cell_font_size, $cell_font_color, $cell_font_underline, $justify);
693

  
694
                if( $first_row and ref $header_props)
695
                {
696
                    $cell_font           = $header_props->{'font'};
697
                    $cell_font_size      = $header_props->{'font_size'};
698
                    $cell_font_color     = $header_props->{'font_color'};
699
                    $cell_font_underline = $header_props->{'font_underline'};
700
                    $justify             = $header_props->{'justify'};
696 701
                }
697
                
702

  
698 703
                # Get the most specific value if none was already set from header_props
699
                $cell_font       ||= $cell_props->[$row_index][$column_idx]->{'font'} 
704
                $cell_font       ||= $cell_props->[$row_index][$column_idx]->{'font'}
700 705
                                 ||  $col_props->[$column_idx]->{'font'}
701 706
                                 ||  $fnt_name;
702
                                  
707

  
703 708
                $cell_font_size  ||= $cell_props->[$row_index][$column_idx]->{'font_size'}
704 709
                                 ||  $col_props->[$column_idx]->{'font_size'}
705 710
                                 ||  $fnt_size;
706
                                  
711

  
707 712
                $cell_font_color ||= $cell_props->[$row_index][$column_idx]->{'font_color'}
708 713
                                 ||  $col_props->[$column_idx]->{'font_color'}
709 714
                                 ||  $font_color;
710
                                
715

  
716
                $cell_font_underline ||= $cell_props->[$row_index][$column_idx]->{'font_underline'}
717
                                     ||  $col_props->[$column_idx]->{'font_underline'}
718
                                     ||  $fnt_underline;
719

  
720

  
711 721
                $justify         ||= $cell_props->[$row_index][$column_idx]->{'justify'}
712 722
                                 ||  $col_props->[$column_idx]->{'justify'}
713 723
                                 ||  $arg{'justify'}
714
                                 ||  'left';                                    
715
                
724
                                 ||  'left';
725

  
716 726
                # Init cell font object
717 727
                $txt->font( $cell_font, $cell_font_size );
718 728
                $txt->fillcolor($cell_font_color);
719 729

  
720
                my $this_width;
721
                if (!$remaining_header_rows && $cell_props->[$row_index + $header_props->{num_header_rows}][$column_idx]->{colspan}) {
722
                    $colspan = $cell_props->[$row_index + $header_props->{num_header_rows}][$column_idx]->{colspan};
723
                } elsif ($remaining_header_rows && ($header_row_cell_props[$header_props->{num_header_rows} - $remaining_header_rows][$column_idx]->{colspan})) {
724
                    $colspan = $header_row_cell_props[$header_props->{num_header_rows} - $remaining_header_rows][$column_idx]->{colspan};
725
                }
730
                # Added to resolve infite loop bug with returned undef values
731
                $record->[$column_idx] //= $cell_props->[$row_index][$column_idx]->{'default_text'}
732
                                       //  $col_props->[$column_idx]->{'default_text'}
733
                                       //  $default_text;
726 734

  
727
                if ($colspan) {
728
                    $colspan     = $num_cols - $column_idx if (-1 == $colspan);
729
                    my $last_idx = $column_idx + $colspan - 1;
730
                    $this_width  = sum @{ $calc_column_widths }[$column_idx..$last_idx];
731
                } else {
732
                    $this_width = $calc_column_widths->[$column_idx];
733
                }
734
 
735 735
                # If the content is wider than the specified width, we need to add the text as a text block
736 736
                if( $record->[$column_idx] !~ m/(.\n.)/ and
737
                    $record_widths->[$column_idx] and 
738
                    $record_widths->[$column_idx] <= $this_width
737
                    $record_widths->[$column_idx] and
738
                    $record_widths->[$column_idx] <= $calc_column_widths->[$column_idx]
739 739
                ){
740 740
                    my $space = $pad_left;
741 741
                    if ($justify eq 'right')
742 742
                    {
743
                        $space = $this_width -($txt->advancewidth($record->[$column_idx]) + $pad_right);
743
                        $space = $calc_column_widths->[$column_idx] -($txt->advancewidth($record->[$column_idx]) + $pad_right);
744 744
                    }
745 745
                    elsif ($justify eq 'center')
746 746
                    {
747
                        $space = ($this_width - $txt->advancewidth($record->[$column_idx])) / 2;
747
                        $space = ($calc_column_widths->[$column_idx] - $txt->advancewidth($record->[$column_idx])) / 2;
748 748
                    }
749 749
                    $txt->translate( $cur_x + $space, $text_start );
750
                    $txt->text( $record->[$column_idx] );
750
                    my %text_options;
751
                    $text_options{'-underline'} = $cell_font_underline if $cell_font_underline;
752
                    $txt->text( $record->[$column_idx], %text_options );
751 753
                }
752 754
                # Otherwise just use the $page->text() method
753 755
                else
......
757 759
                        $record->[$column_idx],
758 760
                        x        => $cur_x + $pad_left,
759 761
                        y        => $text_start,
760
                        w        => $this_width - $pad_left - $pad_right,
762
                        w        => $calc_column_widths->[$column_idx] - $pad_left - $pad_right,
761 763
                        h        => $cur_y - $bot_marg - $pad_top - $pad_bot,
762 764
                        align    => $justify,
763 765
                        lead     => $lead
......
768 770
                    {
769 771
                        $current_row_height = $current_cell_height;
770 772
                    }
771
                    
773

  
772 774
                    if( $left_over_text )
773 775
                    {
774 776
                        $leftovers->[$column_idx] = $left_over_text;
775 777
                        $do_leftovers = 1;
776 778
                    }
777 779
                }
778
                $cur_x += $calc_column_widths->[$column_idx];
779 780

  
780
                push @vertical_lines, (!$colspan || (1 >= $colspan)) ? 1 : 0;
781
                $colspan-- if $colspan;
781
                # Hook to pass coordinates back - http://www.perlmonks.org/?node_id=754777
782
                if (ref $arg{cell_render_hook} eq 'CODE') {
783
                   $arg{cell_render_hook}->(
784
                                            $page,
785
                                            $first_row,
786
                                            $row_index,
787
                                            $column_idx,
788
                                            $cur_x,
789
                                            $cur_y-$row_h,
790
                                            $calc_column_widths->[$column_idx],
791
                                            $row_h
792
                                           );
793
                }
794

  
795
                $cur_x += $calc_column_widths->[$column_idx];
782 796
            }
783 797
            if( $do_leftovers )
784 798
            {
......
786 800
                unshift @$row_col_widths, $record_widths;
787 801
                unshift @$rows_height, $pre_calculated_row_height;
788 802
            }
789
            
803

  
790 804
            # Draw cell bgcolor
791
            # This has to be separately from the text loop 
805
            # This has to be separately from the text loop
792 806
            #  because we do not know the final height of the cell until all text has been drawn
793 807
            $cur_x = $xbase;
794 808
            for(my $column_idx = 0 ; $column_idx < scalar(@$record) ; $column_idx++)
795 809
            {
796 810
                my $cell_bg_color;
797
                                    
798
                if( $remaining_header_rows and ref $header_props)
799
                {                                  #Compatibility                 Consistency with other props    
811

  
812
                if( $first_row and ref $header_props)
813
                {                                  #Compatibility                 Consistency with other props
800 814
                    $cell_bg_color = $header_props->{'bg_color'} || $header_props->{'background_color'};
801 815
                }
802
                
816

  
803 817
                # Get the most specific value if none was already set from header_props
804
                $cell_bg_color ||= $cell_props->[$row_index + $header_props->{num_header_rows}][$column_idx]->{'background_color'}
818
                $cell_bg_color ||= $cell_props->[$row_index][$column_idx]->{'background_color'}
805 819
                               ||  $col_props->[$column_idx]->{'background_color'}
806 820
                               ||  $background_color;
807 821

  
......
812 826
                    $gfx_bg->fill();
813 827
                }
814 828
                $cur_x += $calc_column_widths->[$column_idx];
815

  
816
                if ($line_w && $vertical_lines[$column_idx] && ($column_idx != (scalar(@{ $record }) - 1))) {
817
                    $gfx->move($cur_x, $cur_y);
818
                    $gfx->vline($cur_y - $current_row_height);
819
                    $gfx->fillcolor($border_color);
820
                }
821 829
            }#End of for(my $column_idx....
822 830

  
823 831
            $cur_y -= $current_row_height;
......
827 835
                $gfx->hline( $xbase + $width );
828 836
            }
829 837

  
830
            if ($remaining_header_rows) {
831
              $remaining_header_rows--;
832
            } else {
833
              $row_index++ unless $do_leftovers;
834
            }
838
            $row_index++ unless ( $do_leftovers );
839
            $first_row = 0;
835 840
        }# End of Row_Loop
836 841

  
837 842
        if ($gfx)
838 843
        {
839 844
            # Draw vertical lines
840
            if ($vert_borders) 
845
            if ($vert_borders)
841 846
            {
842 847
                $gfx->move(  $xbase, $table_top_y);
843 848
                $gfx->vline( $cur_y );
844
                $gfx->move($xbase + sum(@{ $calc_column_widths }[0..$num_cols - 1]), $table_top_y);
845
                $gfx->vline( $cur_y );
849
                my $cur_x = $xbase;
850
                for( my $j = 0; $j < $columns_number; $j++ )
851
                {
852
                    $cur_x += $calc_column_widths->[$j];
853
                    $gfx->move(  $cur_x, $table_top_y );
854
                    $gfx->vline( $cur_y );
855
                }
846 856
            }
847 857

  
848 858
            # ACTUALLY draw all the lines
......
893 903
        $calc_widths->[$j] = $col_props->[$j]->{min_w} || 0;;
894 904
    }
895 905

  
896
    my $span = 0;
897
    # Calculate how much can be added to every column to fit the available width
898
    $span = ($avail_width - $min_width) / scalar( @$col_props);
899
    for (my $j = 0; $j < scalar(@$col_props); $j++ ) {
900
      $calc_widths->[$j] = $col_props->[$j]->{min_w} + $span;
906
    # Allow columns to expand to max_w before applying extra space equally.
907
    my $is_last_iter;
908
    for (;;)
909
    {
910
        my $span = ($avail_width - $min_width) / scalar( @$col_props);
911
        last if $span <= 0;
912

  
913
        $min_width = 0;
914
        my $next_will_be_last_iter = 1;
915
        for(my $j = 0; $j < scalar(@$col_props); $j++ )
916
        {
917
            my $new_w = $calc_widths->[$j] + $span;
918

  
919
            if (!$is_last_iter && $new_w > $col_props->[$j]->{max_w})
920
            {
921
                $new_w = $col_props->[$j]->{max_w}
922
            }
923
            if ($calc_widths->[$j] != $new_w )
924
            {
925
                $calc_widths->[$j] = $new_w;
926
                $next_will_be_last_iter = 0;
927
            }
928
            $min_width += $new_w;
929
        }
930
        last if $is_last_iter;
931
        $is_last_iter = $next_will_be_last_iter;
901 932
    }
902 933

  
903 934
    return ($calc_widths,$avail_width);
......
963 994

  
964 995
=head1 DESCRIPTION
965 996

  
966
This class is a utility for use with the PDF::API2 module from CPAN. 
967
It can be used to display text data in a table layout within a PDF. 
968
The text data must be in a 2D array (such as returned by a DBI statement handle fetchall_arrayref() call). 
969
The PDF::Table will automatically add as many new pages as necessary to display all of the data. 
970
Various layout properties, such as font, font size, and cell padding and background color can be specified for each column and/or for even/odd rows. 
971
Also a (non)repeated header row with different layout properties can be specified. 
997
This class is a utility for use with the PDF::API2 module from CPAN.
998
It can be used to display text data in a table layout within a PDF.
999
The text data must be in a 2D array (such as returned by a DBI statement handle fetchall_arrayref() call).
1000
The PDF::Table will automatically add as many new pages as necessary to display all of the data.
1001
Various layout properties, such as font, font size, and cell padding and background color can be specified for each column and/or for even/odd rows.
1002
Also a (non)repeated header row with different layout properties can be specified.
972 1003

  
973 1004
See the L</METHODS> section for complete documentation of every parameter.
974 1005

  
......
986 1017

  
987 1018
=item Parameters
988 1019

  
989
There are no parameters. 
1020
There are no parameters.
990 1021

  
991 1022
=item Returns
992 1023

  
......
997 1028
=head2 table()
998 1029

  
999 1030
    my ($final_page, $number_of_pages, $final_y) = table($pdf, $page, $data, %settings)
1000
    
1031

  
1001 1032
=over
1002 1033

  
1003 1034
=item Description
......
1009 1040
    $pdf      - a PDF::API2 instance representing the document being created
1010 1041
    $page     - a PDF::API2::Page instance representing the current page of the document
1011 1042
    $data     - an ARRAY reference to a 2D data structure that will be used to build the table
1012
    %settings - HASH with geometry and formatting parameters. 
1043
    %settings - HASH with geometry and formatting parameters.
1013 1044

  
1014 1045
For full %settings description see section L</Table settings> below.
1015 1046

  
1016 1047
This method will add more pages to the pdf instance as required based on the formatting options and the amount of data.
1017 1048

  
1018
=item Reuturns
1049
=item Returns
1019 1050

  
1020
The return value is a 3 items list where 
1051
The return value is a 3 items list where
1021 1052

  
1022 1053
    $final_page - The first item is a PDF::API2::Page instance that the table ends on
1023 1054
    $number_of_pages - The second item is the count of pages that the table spans on
......
1037 1068
        start_y => 220,
1038 1069
        start_h => 180,
1039 1070
    );
1040
    
1071

  
1041 1072
    my ($final_page, $number_of_pages, $final_y) = $pdftable->table( $pdf, $page, $data, %options );
1042 1073

  
1043 1074
=back
......
1048 1079

  
1049 1080
There are some mandatory parameteres for setting table geometry and position across page(s)
1050 1081

  
1051
=over 
1082
=over
1052 1083

  
1053 1084
=item B<x> - X coordinate of upper left corner of the table. Left edge of the sheet is 0.
1054 1085

  
1055 1086
B<Value:> can be any whole number satisfying 0 =< X < PageWidth
1056
B<Default:> No default value 
1087
B<Default:> No default value
1057 1088

  
1058 1089
    x => 10
1059 1090

  
......
1077 1108
B<Default:> No default value
1078 1109

  
1079 1110
    start_h => 250
1080
    
1111

  
1081 1112
=back
1082 1113

  
1083 1114
=head4 Optional
......
1098 1129

  
1099 1130
    next_y  => 750
1100 1131

  
1101
=item B<max_word_length> - Breaks long words (like serial numbers hashes etc.) by adding a space after every Nth symbol 
1132
=item B<max_word_length> - Breaks long words (like serial numbers hashes etc.) by adding a space after every Nth symbol
1102 1133

  
1103 1134
B<Value:> can be any whole positive number
1104 1135
B<Default:> 20
1105 1136

  
1106 1137
    max_word_length => 20    # Will add a space after every 20 symbols
1107 1138

  
1108
=item B<padding> - Padding applied to every cell 
1139
=item B<padding> - Padding applied to every cell
1109 1140

  
1110 1141
=item B<padding_top>    - top cell padding, overrides 'padding'
1111 1142

  
......
1120 1151
B<Default padding:> 0
1121 1152

  
1122 1153
B<Default padding_*> $padding
1123
    
1154

  
1124 1155
    padding        => 5      # all sides cell padding
1125 1156
    padding_top    => 8,     # top cell padding, overrides 'padding'
1126 1157
    padding_right  => 6,     # right cell padding, overrides 'padding'
1127 1158
    padding_left   => 2,     # left cell padding, overrides 'padding'
1128 1159
    padding_bottom => undef  # bottom padding will be 5 as it will fallback to 'padding'
1129 1160

  
1130
=item B<border> - Width of table border lines. 
1161
=item B<border> - Width of table border lines.
1131 1162

  
1132 1163
=item B<horizontal_borders> - Width of horizontal border lines. Overrides 'border' value.
1133 1164

  
......
1135 1166

  
1136 1167
B<Value:> can be any whole positive number. When set to 0 will disable border lines.
1137 1168
B<Default:> 1
1138
      
1169

  
1139 1170
    border             => 3     # border width is 3
1140 1171
    horizontal_borders => 1     # horizontal borders will be 1 overriding 3
1141 1172
    vertical_borders   => undef # vertical borders will be 3 as it will fallback to 'border'
......
1158 1189

  
1159 1190
B<Value:> can be any positive number
1160 1191
B<Default:> 12
1161
    
1192

  
1162 1193
    font_size => 16
1163 1194

  
1164 1195
=item B<font_color> - Font color for all rows
1165 1196

  
1166 1197
=item B<font_color_odd> - Font color for odd rows
1167 1198

  
1168
=item B<font_color_even> - Font color for even rows 
1199
=item B<font_color_even> - Font color for even rows
1200

  
1201
=item B<font_underline> - Font underline of the header row
1202

  
1203
B<Value:> 'auto', integer of distance, or arrayref of distance & thickness (more than one pair will provide mlultiple underlines. Negative distance gives strike-through.
1204
B<Default:> none
1169 1205

  
1170 1206
=item B<background_color_odd> - Background color for odd rows
1171 1207

  
......
1177 1213
    font_color            => '#333333'
1178 1214
    font_color_odd        => 'purple'
1179 1215
    font_color_even       => '#00FF00'
1180
    background_color_odd  => 'gray'     
1216
    background_color_odd  => 'gray'
1181 1217
    background_color_even => 'lightblue'
1182 1218

  
1183 1219
=item B<row_height> - Desired row height but it will be honored only if row_height > font_size + padding_top + padding_bottom
1184 1220

  
1185 1221
B<Value:> can be any whole positive number
1186 1222
B<Default:> font_size + padding_top + padding_bottom
1187
    
1223

  
1188 1224
    row_height => 24
1189
 
1225

  
1190 1226
=item B<new_page_func> - CODE reference to a function that returns a PDF::API2::Page instance.
1191 1227

  
1192 1228
If used the parameter 'new_page_func' must be a function reference which when executed will create a new page and will return the object back to the module.
......
1195 1231
Don't forget that your function must return a page object created with PDF::API2 page() method.
1196 1232

  
1197 1233
    new_page_func  => $code_ref
1198
    
1234

  
1199 1235
=item B<header_props> - HASH reference to specific settings for the Header row of the table. See section L</Header Row Properties> below
1200
    
1236

  
1201 1237
    header_props => $hdr_props
1202 1238

  
1203 1239
=item B<column_props> - HASH reference to specific settings for each column of the table. See section L</Column Properties> below
......
1205 1241
    column_props => $col_props
1206 1242

  
1207 1243
=item B<cell_props> - HASH reference to specific settings for each column of the table. See section L</Cell Properties> below
1208
    
1244

  
1209 1245
    cell_props => $cel_props
1210 1246

  
1247
=item B<cell_render_hook> - CODE reference to a function called with the current cell coordinates.  If used the parameter 'cell_render_hook' must be a function reference. It is most useful for creating a url link inside of a cell. The following example adds a link in the first column of each non-header row:
1248

  
1249
    cell_render_hook  => sub {
1250
        my ($page, $first_row, $row, $col, $x, $y, $w, $h) = @_;
1251

  
1252
        # Do nothing except for first column (and not a header row)
1253
        return unless ($col == 0);
1254
        return if ($first_row);
1255

  
1256
        # Create link
1257
        my $value = $list_of_vals[$row-1];
1258
        my $url = "https://${hostname}/app/${value}";
1259

  
1260
        my $annot = $page->annotation();
1261
        $annot->url( $url, -rect => [$x, $y, $x+$w, $y+$h] );
1262
    },
1263

  
1211 1264
=back
1212 1265

  
1213 1266
=head4 Header Row Properties
......
1225 1278
=item B<font_size> - Font size of the header row
1226 1279

  
1227 1280
B<Value:> can be any positive number
1228
B<Default:> 'font_size' of the table + 2  
1281
B<Default:> 'font_size' of the table + 2
1229 1282

  
1230 1283
=item B<font_color> - Font color of the header row
1231 1284

  
1232 1285
B<Value:> Color specifier as 'name' or 'HEX'
1233 1286
B<Default:> '#000066'
1234 1287

  
1288
=item B<font_underline> - Font underline of the header row
1289

  
1290
B<Value:> 'auto', integer of distance, or arrayref of distance & thickness (more than one pair will provide mlultiple underlines. Negative distance gives strike-through.
1291
B<Default:> none
1292

  
1235 1293
=item B<bg_color> - Background color of the header row
1236 1294

  
1237 1295
B<Value:> Color specifier as 'name' or 'HEX'
......
1239 1297

  
1240 1298
=item B<repeat> - Flag showing if header row should be repeated on every new page
1241 1299

  
1242
B<Value:> 0,1   1-Yes/True, 0-No/False 
1300
B<Value:> 0,1   1-Yes/True, 0-No/False
1243 1301
B<Default:> 0
1244 1302

  
1245 1303
=item B<justify> - Alignment of text in the header row.
......
1247 1305
B<Value:> One of 'left', 'right', 'center'
1248 1306
B<Default:> Same as column alignment (or 'left' if undefined)
1249 1307

  
1250
    my $hdr_props = 
1308
    my $hdr_props =
1251 1309
    {
1252 1310
        font       => $pdf->corefont("Helvetica", -encoding => "utf8"),
1253 1311
        font_size  => 18,
1254 1312
        font_color => '#004444',
1255
        bg_color   => 'yellow', 
1256
        repeat     => 1,    
1313
        bg_color   => 'yellow',
1314
        repeat     => 1,
1257 1315
        justify    => 'center'
1258 1316
    };
1259 1317

  
......
1261 1319

  
1262 1320
=head4 Column Properties
1263 1321

  
1264
If the 'column_props' parameter is used, it should be an arrayref of hashrefs, 
1265
with one hashref for each column of the table. The columns are counted from left to right so the hash reference at $col_props[0] will hold properties for the first column from left to right. 
1322
If the 'column_props' parameter is used, it should be an arrayref of hashrefs,
1323
with one hashref for each column of the table. The columns are counted from left to right so the hash reference at $col_props[0] will hold properties for the first column from left to right.
1266 1324
If you DO NOT want to give properties for a column but to give for another just insert and empty hash reference into the array for the column that you want to skip. This will cause the counting to proceed as expected and the properties to be applyed at the right columns.
1267 1325

  
1268 1326
Each hashref can contain any of the keys shown below:
......
1294 1352
B<Value:> Color specifier as 'name' or 'HEX'
1295 1353
B<Default:> 'font_color' of the table.
1296 1354

  
1355
=item B<font_underline> - Font underline of this cell
1356

  
1357
B<Value:> 'auto', integer of distance, or arrayref of distance & thickness (more than one pair will provide mlultiple underlines. Negative distance gives strike-through.
1358
B<Default:> none
1359

  
1297 1360
=item B<background_color> - Background color of this column
1298 1361

  
1299 1362
B<Value:> Color specifier as 'name' or 'HEX'
......
1322 1385

  
1323 1386
=back
1324 1387

  
1325
NOTE: If 'min_w' and/or 'max_w' parameter is used in 'col_props', have in mind that it may be overriden by the calculated minimum/maximum cell witdh so that table can be created.
1388
NOTE: If 'min_w' and/or 'max_w' parameter is used in 'col_props', have in mind that it may be overridden by the calculated minimum/maximum cell witdh so that table can be created.
1326 1389
When this happens a warning will be issued with some advises what can be done.
1327 1390
In cases of a conflict between column formatting and odd/even row formatting, 'col_props' will override odd/even.
1328 1391

  
......
1350 1413
B<Value:> Color specifier as 'name' or 'HEX'
1351 1414
B<Default:> 'font_color' of the table.
1352 1415

  
1416
=item B<font_underline> - Font underline of this cell
1417

  
1418
B<Value:> 'auto', integer of distance, or arrayref of distance & thickness (more than one pair will provide mlultiple underlines. Negative distance gives strike-through.
1419
B<Default:> none
1420

  
1353 1421
=item B<background_color> - Background color of this cell
1354 1422

  
1355 1423
B<Value:> Color specifier as 'name' or 'HEX'
......
1367 1435
            {    #Row 1 cell 1
1368 1436
                background_color => '#AAAA00',
1369 1437
                font_color       => 'yellow',
1438
                font_underline   => [ 2, 2 ],
1370 1439
            },
1371 1440

  
1372 1441
            # etc.
......
1386 1455
    ];
1387 1456

  
1388 1457
    OR
1389
    
1458

  
1390 1459
    my $cell_props = [];
1391 1460
    $cell_props->[1][0] = {
1392 1461
        #Row 2 cell 1
......
1395 1464
    };
1396 1465

  
1397 1466
=back
1398
    
1399
NOTE: In case of a conflict between column, odd/even and cell formating, cell formating will overwrite the other two.
1400
In case of a conflict between header row and cell formating, header formating will override cell.
1467

  
1468
NOTE: In case of a conflict between column, odd/even and cell formatting, cell formatting will overwrite the other two.
1469
In case of a conflict between header row and cell formatting, header formatting will override cell.
1401 1470

  
1402 1471
=head2 text_block()
1403 1472

  
......
1408 1477
=item Description
1409 1478

  
1410 1479
Utility method to create a block of text. The block may contain multiple paragraphs.
1411
It is mainly used internaly but you can use it from outside for placing formated text anywhere on the sheet.
1480
It is mainly used internaly but you can use it from outside for placing formatted text anywhere on the sheet.
1412 1481

  
1413 1482
NOTE: This method will NOT add more pages to the pdf instance if the space is not enough to place the string inside the block.
1414 1483
Leftover text will be returned and has to be handled by the caller - i.e. add a new page and a new block with the leftover.
......
1418 1487
    $txt  - a PDF::API2::Page::Text instance representing the text tool
1419 1488
    $data - a string that will be placed inside the block
1420 1489
    %settings - HASH with geometry and formatting parameters.
1421
     
1490

  
1422 1491
=item Reuturns
1423 1492

  
1424
The return value is a 3 items list where 
1493
The return value is a 3 items list where
1425 1494

  
1426 1495
    $width_of_last_line - Width of last line in the block
1427 1496
    $final_y - The Y coordinate of the block bottom so that additional content can be added after it
1428 1497
    $left_over_text - Text that was did not fit in the provided box geometry.
1429
    
1498

  
1430 1499
=item Example
1431 1500

  
1432 1501
    # PDF::API2 objects
......
1438 1507
        y => 570,
1439 1508
        w => 220,
1440 1509
        h => 180
1441
        
1510

  
1442 1511
        #OPTIONAL PARAMS
1443 1512
        lead     => $font_size | $distance_between_lines,
1444 1513
        align    => "left|right|center|justify|fulljustify",
1445 1514
        hang     => $optional_hanging_indent,
1446
        Only one of the subsequent 3params can be given. 
1515
        Only one of the subsequent 3params can be given.
1447 1516
        They override each other.-parspace is the weightest
1448 1517
        parspace => $optional_vertical_space_before_first_paragraph,
1449 1518
        flindent => $optional_indent_of_first_line,
1450 1519
        fpindent => $optional_indent_of_first_paragraph,
1451 1520
        indent   => $optional_indent_of_text_to_every_non_first_line,
1452 1521
    );
1453
    
1522

  
1454 1523
    my ( $width_of_last_line, $final_y, $left_over_text ) = $pdftable->text_block( $txt, $data, %settings );
1455
 
1524

  
1456 1525
=back
1457 1526

  
1458 1527
=head1 VERSION
......
1478 1547

  
1479 1548
=head1 PLUGS
1480 1549

  
1481
=over 
1550
=over
1482 1551

  
1483 1552
=item by Daemmon Hughes
1484 1553

  
......
1486 1555
Stone Environmental Inc. (www.stone-env.com).
1487 1556

  
1488 1557
The text_block() method is a slightly modified copy of the one from
1489
Rick Measham's PDF::API2 L<tutorial|http://rick.measham.id.au/pdf-api2>.
1558
Rick Measham's PDF::API2 tutorial at
1559
http://pdfapi2.sourceforge.net/cgi-bin/view/Main/YourFirstDocument
1490 1560

  
1491 1561
=item by Desislav Kamenov (@deskata on Twitter)
1492 1562

  

Auch abrufbar als: Unified diff