Revision ca2ec834
Von Sven Schöling vor fast 9 Jahren hinzugefügt
modules/override/PDF/Table.pm | ||
---|---|---|
3 | 3 |
use 5.006; |
4 | 4 |
use strict; |
5 | 5 |
use warnings; |
6 |
our $VERSION = '0.9.3'; |
|
6 |
use Carp; |
|
7 |
our $VERSION = '0.9.10'; |
|
7 | 8 |
|
8 |
use List::Util qw(sum);
|
|
9 |
print __PACKAGE__.' is version: '.$VERSION.$/ if($ENV{'PDF_TABLE_DEBUG'});
|
|
9 | 10 |
|
10 | 11 |
############################################################ |
11 | 12 |
# |
... | ... | |
17 | 18 |
# |
18 | 19 |
############################################################ |
19 | 20 |
|
20 |
sub new { |
|
21 |
my ($type) = @_; |
|
21 |
sub new |
|
22 |
{ |
|
23 |
my $type = shift(@_); |
|
24 |
my $class = ref($type) || $type; |
|
25 |
my $self = {}; |
|
26 |
bless ($self, $class); |
|
22 | 27 |
|
23 |
my $class = ref($type) || $type; |
|
24 |
my $self = {}; |
|
25 |
bless ($self, $class); |
|
26 |
return $self; |
|
28 |
# Pass all the rest to init for validation and initialisation |
|
29 |
$self->_init(@_); |
|
30 |
|
|
31 |
return $self; |
|
32 |
} |
|
33 |
|
|
34 |
sub _init |
|
35 |
{ |
|
36 |
my ($self, $pdf, $page, $data, %options ) = @_; |
|
37 |
|
|
38 |
# Check and set default values |
|
39 |
$self->set_defaults(); |
|
40 |
|
|
41 |
# Check and set mandatory params |
|
42 |
$self->set_pdf($pdf); |
|
43 |
$self->set_page($page); |
|
44 |
$self->set_data($data); |
|
45 |
$self->set_options(\%options); |
|
46 |
|
|
47 |
return; |
|
48 |
} |
|
49 |
|
|
50 |
sub set_defaults{ |
|
51 |
my $self = shift; |
|
52 |
|
|
53 |
$self->{'font_size'} = 12; |
|
54 |
} |
|
55 |
|
|
56 |
sub set_pdf{ |
|
57 |
my ($self, $pdf) = @_; |
|
58 |
$self->{'pdf'} = $pdf; |
|
59 |
} |
|
60 |
|
|
61 |
sub set_page{ |
|
62 |
my ($self, $page) = @_; |
|
63 |
if ( defined($page) && ref($page) ne 'PDF::API2::Page' ){ |
|
64 |
|
|
65 |
if( ref($self->{'pdf'}) eq 'PDF::API2' ){ |
|
66 |
$self->{'page'} = $self->{'pdf'}->page(); |
|
67 |
} else { |
|
68 |
carp 'Warning: Page must be a PDF::API2::Page object but it seems to be: '.ref($page).$/; |
|
69 |
carp 'Error: Cannot set page from passed PDF object either as it is invalid!'.$/; |
|
70 |
} |
|
71 |
return; |
|
72 |
} |
|
73 |
$self->{'page'} = $page; |
|
74 |
|
|
75 |
} |
|
76 |
|
|
77 |
sub set_data{ |
|
78 |
my ($self, $data) = @_; |
|
79 |
#TODO: implement |
|
80 |
} |
|
81 |
|
|
82 |
sub set_options{ |
|
83 |
my ($self, $options) = @_; |
|
84 |
#TODO: implement |
|
27 | 85 |
} |
28 | 86 |
|
29 | 87 |
############################################################ |
... | ... | |
32 | 90 |
# |
33 | 91 |
############################################################ |
34 | 92 |
|
35 |
sub text_block { |
|
36 |
my $self = shift; |
|
37 |
my $text_object = shift; |
|
38 |
my $text = shift; # The text to be displayed |
|
39 |
my %arg = @_; # Additional Arguments |
|
40 |
|
|
41 |
my ($align, $xpos, $ypos, $xbase, $ybase, $line_width, $wordspace, $endw , $width, $height) |
|
42 |
= (undef , undef, undef, undef , undef , undef , undef , undef , undef , undef ); |
|
43 |
my @line = (); # Temp data array with words on one line |
|
44 |
my %width = (); # The width of every unique word in the givven text |
|
45 |
|
|
46 |
# Try to provide backward compatibility |
|
47 |
foreach my $key (keys %arg) { |
|
48 |
my $newkey = $key; |
|
49 |
if ($newkey =~ s#^-##) { |
|
50 |
$arg{$newkey} = $arg{$key}; |
|
51 |
delete $arg{$key}; |
|
93 |
sub text_block |
|
94 |
{ |
|
95 |
my $self = shift; |
|
96 |
my $text_object = shift; |
|
97 |
my $text = shift; # The text to be displayed |
|
98 |
my %arg = @_; # Additional Arguments |
|
99 |
|
|
100 |
my ( $align, $xpos, $ypos, $xbase, $ybase, $line_width, $wordspace, $endw , $width, $height) = |
|
101 |
( undef , undef, undef, undef , undef , undef , undef , undef , undef , undef ); |
|
102 |
my @line = (); # Temp data array with words on one line |
|
103 |
my %width = (); # The width of every unique word in the givven text |
|
104 |
|
|
105 |
# Try to provide backward compatibility |
|
106 |
foreach my $key (keys %arg) |
|
107 |
{ |
|
108 |
my $newkey = $key; |
|
109 |
if($newkey =~ s#^-##) |
|
110 |
{ |
|
111 |
$arg{$newkey} = $arg{$key}; |
|
112 |
delete $arg{$key}; |
|
113 |
} |
|
52 | 114 |
} |
53 |
} |
|
54 |
##### |
|
55 |
|
|
56 |
#--- |
|
57 |
# Lets check mandatory parameters with no default values |
|
58 |
#--- |
|
59 |
$xbase = $arg{'x'} || -1; |
|
60 |
$ybase = $arg{'y'} || -1; |
|
61 |
$width = $arg{'w'} || -1; |
|
62 |
$height = $arg{'h'} || -1; |
|
63 |
unless ( $xbase > 0 ) { print "Error: Left Edge of Block is NOT defined!\n"; return; } |
|
64 |
unless ( $ybase > 0 ) { print "Error: Base Line of Block is NOT defined!\n"; return; } |
|
65 |
unless ( $width > 0 ) { print "Error: Width of Block is NOT defined!\n"; return; } |
|
66 |
unless ( $height > 0 ) { print "Error: Height of Block is NOT defined!\n"; return; } |
|
67 |
# Check if any text to display |
|
68 |
unless ( defined( $text) and length($text) > 0 ) { |
|
69 |
print "Warning: No input text found. Trying to add dummy '-' and not to break everything.\n"; |
|
70 |
$text = '-'; |
|
71 |
} |
|
72 |
|
|
73 |
# Strip any <CR> and Split the text into paragraphs |
|
74 |
$text =~ s/\r//g; |
|
75 |
my @paragraphs = split(/\n/, $text); |
|
76 |
|
|
77 |
# Width between lines in pixels |
|
78 |
my $line_space = defined $arg{'lead'} && $arg{'lead'} > 0 ? $arg{'lead'} : 12; |
|
79 |
|
|
80 |
# Calculate width of all words |
|
81 |
my $space_width = $text_object->advancewidth("\x20"); |
|
82 |
my @words = split(/\s+/, $text); |
|
83 |
foreach (@words) { |
|
84 |
next if exists $width{$_}; |
|
85 |
$width{$_} = $text_object->advancewidth($_); |
|
86 |
} |
|
87 |
|
|
88 |
my @paragraph = split(' ', shift(@paragraphs)); |
|
89 |
my $first_line = 1; |
|
90 |
my $first_paragraph = 1; |
|
91 |
|
|
92 |
# Little Init |
|
93 |
$xpos = $xbase; |
|
94 |
$ypos = $ybase; |
|
95 |
$ypos = $ybase + $line_space; |
|
96 |
my $bottom_border = $ybase - $height; |
|
97 |
# While we can add another line |
|
98 |
while ( $ypos >= $bottom_border + $line_space ) { |
|
99 |
# Is there any text to render ? |
|
100 |
unless (@paragraph) { |
|
101 |
# Finish if nothing left |
|
102 |
last unless scalar @paragraphs; |
|
103 |
# Else take one line from the text |
|
104 |
@paragraph = split(' ', shift( @paragraphs ) ); |
|
105 |
|
|
106 |
$ypos -= $arg{'parspace'} if $arg{'parspace'}; |
|
107 |
last unless $ypos >= $bottom_border; |
|
115 |
##### |
|
116 |
|
|
117 |
#--- |
|
118 |
# Lets check mandatory parameters with no default values |
|
119 |
#--- |
|
120 |
$xbase = $arg{'x'} || -1; |
|
121 |
$ybase = $arg{'y'} || -1; |
|
122 |
$width = $arg{'w'} || -1; |
|
123 |
$height = $arg{'h'} || -1; |
|
124 |
unless( $xbase > 0 ){ carp "Error: Left Edge of Block is NOT defined!\n"; return; } |
|
125 |
unless( $ybase > 0 ){ carp "Error: Base Line of Block is NOT defined!\n"; return; } |
|
126 |
unless( $width > 0 ){ carp "Error: Width of Block is NOT defined!\n"; return; } |
|
127 |
unless( $height > 0 ){ carp "Error: Height of Block is NOT defined!\n"; return; } |
|
128 |
# Check if any text to display |
|
129 |
unless( defined( $text) and length($text) > 0 ) |
|
130 |
{ |
|
131 |
carp "Warning: No input text found. Trying to add dummy '-' and not to break everything.\n"; |
|
132 |
$text = '-'; |
|
108 | 133 |
} |
109 |
$ypos -= $line_space; |
|
110 |
$xpos = $xbase; |
|
111 | 134 |
|
112 |
# While there's room on the line, add another word |
|
113 |
@line = (); |
|
114 |
$line_width = 0; |
|
115 |
if ( $first_line && exists $arg{'hang'} ) { |
|
116 |
my $hang_width = $text_object->advancewidth($arg{'hang'}); |
|
135 |
# Strip any <CR> and Split the text into paragraphs |
|
136 |
$text =~ s/\r//g; |
|
137 |
my @paragraphs = split(/\n/, $text); |
|
117 | 138 |
|
118 |
$text_object->translate( $xpos, $ypos );
|
|
119 |
$text_object->text( $arg{'hang'} );
|
|
139 |
# Width between lines in pixels
|
|
140 |
my $line_space = defined $arg{'lead'} && $arg{'lead'} > 0 ? $arg{'lead'} : 12;
|
|
120 | 141 |
|
121 |
$xpos += $hang_width; |
|
122 |
$line_width += $hang_width; |
|
123 |
$arg{'indent'} += $hang_width if $first_paragraph; |
|
142 |
# Calculate width of all words |
|
143 |
my $space_width = $text_object->advancewidth("\x20"); |
|
144 |
my @words = split(/\s+/, $text); |
|
145 |
foreach (@words) |
|
146 |
{ |
|
147 |
next if exists $width{$_}; |
|
148 |
$width{$_} = $text_object->advancewidth($_); |
|
149 |
} |
|
124 | 150 |
|
125 |
} elsif ( $first_line && exists $arg{'flindent'} && $arg{'flindent'} > 0 ) { |
|
126 |
$xpos += $arg{'flindent'}; |
|
127 |
$line_width += $arg{'flindent'}; |
|
151 |
my @paragraph = split(' ', shift(@paragraphs)); |
|
152 |
my $first_line = 1; |
|
153 |
my $first_paragraph = 1; |
|
154 |
|
|
155 |
# Little Init |
|
156 |
$xpos = $xbase; |
|
157 |
$ypos = $ybase; |
|
158 |
$ypos = $ybase + $line_space; |
|
159 |
my $bottom_border = $ypos - $height; |
|
160 |
# While we can add another line |
|
161 |
while ( $ypos >= $bottom_border + $line_space ) |
|
162 |
{ |
|
163 |
# Is there any text to render ? |
|
164 |
unless (@paragraph) |
|
165 |
{ |
|
166 |
# Finish if nothing left |
|
167 |
last unless scalar @paragraphs; |
|
168 |
# Else take one line from the text |
|
169 |
@paragraph = split(' ', shift( @paragraphs ) ); |
|
170 |
|
|
171 |
$ypos -= $arg{'parspace'} if $arg{'parspace'}; |
|
172 |
last unless $ypos >= $bottom_border; |
|
173 |
} |
|
174 |
$ypos -= $line_space; |
|
175 |
$xpos = $xbase; |
|
176 |
|
|
177 |
# While there's room on the line, add another word |
|
178 |
@line = (); |
|
179 |
$line_width = 0; |
|
180 |
if( $first_line && exists $arg{'hang'} ) |
|
181 |
{ |
|
182 |
my $hang_width = $text_object->advancewidth($arg{'hang'}); |
|
183 |
|
|
184 |
$text_object->translate( $xpos, $ypos ); |
|
185 |
$text_object->text( $arg{'hang'} ); |
|
186 |
|
|
187 |
$xpos += $hang_width; |
|
188 |
$line_width += $hang_width; |
|
189 |
$arg{'indent'} += $hang_width if $first_paragraph; |
|
190 |
} |
|
191 |
elsif( $first_line && exists $arg{'flindent'} && $arg{'flindent'} > 0 ) |
|
192 |
{ |
|
193 |
$xpos += $arg{'flindent'}; |
|
194 |
$line_width += $arg{'flindent'}; |
|
195 |
} |
|
196 |
elsif( $first_paragraph && exists $arg{'fpindent'} && $arg{'fpindent'} > 0 ) |
|
197 |
{ |
|
198 |
$xpos += $arg{'fpindent'}; |
|
199 |
$line_width += $arg{'fpindent'}; |
|
200 |
} |
|
201 |
elsif (exists $arg{'indent'} && $arg{'indent'} > 0 ) |
|
202 |
{ |
|
203 |
$xpos += $arg{'indent'}; |
|
204 |
$line_width += $arg{'indent'}; |
|
205 |
} |
|
206 |
|
|
207 |
# Lets take from paragraph as many words as we can put into $width - $indent; |
|
208 |
while ( @paragraph and $text_object->advancewidth( join("\x20", @line)."\x20" . $paragraph[0]) + |
|
209 |
$line_width < $width ) |
|
210 |
{ |
|
211 |
push(@line, shift(@paragraph)); |
|
212 |
} |
|
213 |
$line_width += $text_object->advancewidth(join('', @line)); |
|
214 |
|
|
215 |
# calculate the space width |
|
216 |
if( $arg{'align'} eq 'fulljustify' or ($arg{'align'} eq 'justify' and @paragraph)) |
|
217 |
{ |
|
218 |
@line = split(//,$line[0]) if (scalar(@line) == 1) ; |
|
219 |
$wordspace = ($width - $line_width) / (scalar(@line) - 1); |
|
220 |
$align='justify'; |
|
221 |
} |
|
222 |
else |
|
223 |
{ |
|
224 |
$align=($arg{'align'} eq 'justify') ? 'left' : $arg{'align'}; |
|
225 |
$wordspace = $space_width; |
|
226 |
} |
|
227 |
$line_width += $wordspace * (scalar(@line) - 1); |
|
228 |
|
|
229 |
if( $align eq 'justify') |
|
230 |
{ |
|
231 |
foreach my $word (@line) |
|
232 |
{ |
|
233 |
$text_object->translate( $xpos, $ypos ); |
|
234 |
$text_object->text( $word ); |
|
235 |
$xpos += ($width{$word} + $wordspace) if (@line); |
|
236 |
} |
|
237 |
$endw = $width; |
|
238 |
} |
|
239 |
else |
|
240 |
{ |
|
241 |
# calculate the left hand position of the line |
|
242 |
if( $align eq 'right' ) |
|
243 |
{ |
|
244 |
$xpos += $width - $line_width; |
|
245 |
} |
|
246 |
elsif( $align eq 'center' ) |
|
247 |
{ |
|
248 |
$xpos += ( $width / 2 ) - ( $line_width / 2 ); |
|
249 |
} |
|
250 |
|
|
251 |
# render the line |
|
252 |
$text_object->translate( $xpos, $ypos ); |
|
253 |
$endw = $text_object->text( join("\x20", @line)); |
|
254 |
} |
|
255 |
$first_line = 0; |
|
256 |
}#End of while( |
|
257 |
unshift(@paragraphs, join(' ',@paragraph)) if scalar(@paragraph); |
|
258 |
return ($endw, $ypos, join("\n", @paragraphs)) |
|
259 |
} |
|
128 | 260 |
|
129 |
} elsif ( $first_paragraph && exists $arg{'fpindent'} && $arg{'fpindent'} > 0 ) { |
|
130 |
$xpos += $arg{'fpindent'}; |
|
131 |
$line_width += $arg{'fpindent'}; |
|
132 | 261 |
|
133 |
} elsif (exists $arg{'indent'} && $arg{'indent'} > 0 ) { |
|
134 |
$xpos += $arg{'indent'}; |
|
135 |
$line_width += $arg{'indent'}; |
|
262 |
################################################################ |
|
263 |
# table - utility method to build multi-row, multicolumn tables |
|
264 |
################################################################ |
|
265 |
sub table |
|
266 |
{ |
|
267 |
my $self = shift; |
|
268 |
my $pdf = shift; |
|
269 |
my $page = shift; |
|
270 |
my $data = shift; |
|
271 |
my %arg = @_; |
|
272 |
|
|
273 |
#===================================== |
|
274 |
# Mandatory Arguments Section |
|
275 |
#===================================== |
|
276 |
unless($pdf and $page and $data) |
|
277 |
{ |
|
278 |
carp "Error: Mandatory parameter is missing pdf/page/data object!\n"; |
|
279 |
return; |
|
136 | 280 |
} |
137 | 281 |
|
138 |
# Lets take from paragraph as many words as we can put into $width - $indent;. Always take at least one word; otherwise we'd end up in an infinite loop. |
|
139 |
while (!scalar(@line) || (@paragraph && ($text_object->advancewidth( join("\x20", @line)."\x20" . $paragraph[0]) + $line_width < $width))) { |
|
140 |
push(@line, shift(@paragraph)); |
|
282 |
# Validate mandatory argument data type |
|
283 |
croak "Error: Invalid pdf object received." unless (ref($pdf) eq 'PDF::API2'); |
|
284 |
croak "Error: Invalid page object received." unless (ref($page) eq 'PDF::API2::Page'); |
|
285 |
croak "Error: Invalid data received." unless ((ref($data) eq 'ARRAY') && scalar(@$data)); |
|
286 |
croak "Error: Missing required settings." unless (scalar(keys %arg)); |
|
287 |
|
|
288 |
# Validate settings key |
|
289 |
my %valid_settings_key = ( |
|
290 |
x => 1, |
|
291 |
w => 1, |
|
292 |
start_y => 1, |
|
293 |
start_h => 1, |
|
294 |
next_y => 1, |
|
295 |
next_h => 1, |
|
296 |
lead => 1, |
|
297 |
padding => 1, |
|
298 |
padding_right => 1, |
|
299 |
padding_left => 1, |
|
300 |
padding_top => 1, |
|
301 |
padding_bottom => 1, |
|
302 |
background_color => 1, |
|
303 |
background_color_odd => 1, |
|
304 |
background_color_even => 1, |
|
305 |
border => 1, |
|
306 |
border_color => 1, |
|
307 |
horizontal_borders => 1, |
|
308 |
vertical_borders => 1, |
|
309 |
font => 1, |
|
310 |
font_size => 1, |
|
311 |
font_color => 1, |
|
312 |
font_color_even => 1, |
|
313 |
background_color_odd => 1, |
|
314 |
background_color_even => 1, |
|
315 |
row_height => 1, |
|
316 |
new_page_func => 1, |
|
317 |
header_props => 1, |
|
318 |
column_props => 1, |
|
319 |
cell_props => 1, |
|
320 |
max_word_length => 1, |
|
321 |
); |
|
322 |
foreach my $key (keys %arg) { |
|
323 |
croak "Error: Invalid setting key '$key' received." |
|
324 |
unless (exists $valid_settings_key{$key}); |
|
141 | 325 |
} |
142 |
$line_width += $text_object->advancewidth(join('', @line)); |
|
143 | 326 |
|
144 |
# calculate the space width
|
|
145 |
if ( $arg{'align'} eq 'fulljustify' or ($arg{'align'} eq 'justify' and @paragraph)) {
|
|
146 |
@line = split(//,$line[0]) if (scalar(@line) == 1) ;
|
|
147 |
$wordspace = ($width - $line_width) / (scalar(@line) - 1);
|
|
148 |
$align ='justify';
|
|
149 |
|
|
150 |
} else {
|
|
151 |
$align = ($arg{'align'} eq 'justify') ? 'left' : $arg{'align'};
|
|
152 |
$wordspace = $space_width;
|
|
327 |
# Try to provide backward compatibility
|
|
328 |
foreach my $key (keys %arg)
|
|
329 |
{
|
|
330 |
my $newkey = $key;
|
|
331 |
if($newkey =~ s#^-##)
|
|
332 |
{ |
|
333 |
$arg{$newkey} = $arg{$key};
|
|
334 |
delete $arg{$key};
|
|
335 |
}
|
|
153 | 336 |
} |
154 |
$line_width += $wordspace * (scalar(@line) - 1); |
|
155 |
|
|
156 |
if ( $align eq 'justify') { |
|
157 |
foreach my $word (@line) { |
|
158 |
$text_object->translate( $xpos, $ypos ); |
|
159 |
$text_object->text( $word ); |
|
160 |
$xpos += ($width{$word} + $wordspace) if (@line); |
|
161 |
} |
|
162 |
$endw = $width; |
|
163 |
|
|
164 |
} else { |
|
165 |
# calculate the left hand position of the line |
|
166 |
if ( $align eq 'right' ) { |
|
167 |
$xpos += $width - $line_width; |
|
168 |
|
|
169 |
} elsif ( $align eq 'center' ) { |
|
170 |
$xpos += ( $width / 2 ) - ( $line_width / 2 ); |
|
171 |
} |
|
172 |
|
|
173 |
# render the line |
|
174 |
$text_object->translate( $xpos, $ypos ); |
|
175 |
$endw = $text_object->text( join("\x20", @line)); |
|
337 |
|
|
338 |
###### |
|
339 |
#TODO: Add code for header props compatibility and col_props comp.... |
|
340 |
###### |
|
341 |
my ( $xbase, $ybase, $width, $height ) = ( undef, undef, undef, undef ); |
|
342 |
# Could be 'int' or 'real' values |
|
343 |
$xbase = $arg{'x' } || -1; |
|
344 |
$ybase = $arg{'start_y'} || -1; |
|
345 |
$width = $arg{'w' } || -1; |
|
346 |
$height = $arg{'start_h'} || -1; |
|
347 |
|
|
348 |
# Global geometry parameters are also mandatory. |
|
349 |
unless( $xbase > 0 ){ carp "Error: Left Edge of Table is NOT defined!\n"; return; } |
|
350 |
unless( $ybase > 0 ){ carp "Error: Base Line of Table is NOT defined!\n"; return; } |
|
351 |
unless( $width > 0 ){ carp "Error: Width of Table is NOT defined!\n"; return; } |
|
352 |
unless( $height > 0 ){ carp "Error: Height of Table is NOT defined!\n"; return; } |
|
353 |
|
|
354 |
# Ensure default values for -next_y and -next_h |
|
355 |
my $next_y = $arg{'next_y'} || $arg{'start_y'} || 0; |
|
356 |
my $next_h = $arg{'next_h'} || $arg{'start_h'} || 0; |
|
357 |
|
|
358 |
# Create Text Object |
|
359 |
my $txt = $page->text; |
|
360 |
|
|
361 |
# Set Default Properties |
|
362 |
my $fnt_name = $arg{'font' } || $pdf->corefont('Times',-encode => 'utf8'); |
|
363 |
my $fnt_size = $arg{'font_size' } || 12; |
|
364 |
my $max_word_len= $arg{'max_word_length' } || 20; |
|
365 |
|
|
366 |
#===================================== |
|
367 |
# Table Header Section |
|
368 |
#===================================== |
|
369 |
# Disable header row into the table |
|
370 |
my $header_props = undef; |
|
371 |
|
|
372 |
# Check if the user enabled it ? |
|
373 |
if(defined $arg{'header_props'} and ref( $arg{'header_props'}) eq 'HASH') |
|
374 |
{ |
|
375 |
# Transfer the reference to local variable |
|
376 |
$header_props = $arg{'header_props'}; |
|
377 |
|
|
378 |
# Check other params and put defaults if needed |
|
379 |
$header_props->{'repeat' } = $header_props->{'repeat' } || 0; |
|
380 |
$header_props->{'font' } = $header_props->{'font' } || $fnt_name; |
|
381 |
$header_props->{'font_color' } = $header_props->{'font_color' } || '#000066'; |
|
382 |
$header_props->{'font_size' } = $header_props->{'font_size' } || $fnt_size + 2; |
|
383 |
$header_props->{'bg_color' } = $header_props->{'bg_color' } || '#FFFFAA'; |
|
384 |
$header_props->{'justify' } = $header_props->{'justify' }; |
|
176 | 385 |
} |
177 |
$first_line = 0; |
|
178 |
}#End of while( |
|
179 |
|
|
180 |
unshift(@paragraphs, join(' ',@paragraph)) if scalar(@paragraph); |
|
181 |
|
|
182 |
return ($endw, $ypos, join("\n", @paragraphs)) |
|
183 |
} |
|
184 |
|
|
185 | 386 |
|
186 |
############################################################ |
|
187 |
# table - utility method to build multi-row, multicolumn tables |
|
188 |
############################################################ |
|
189 |
sub table { |
|
190 |
my $self = shift; |
|
191 |
my $pdf = shift; |
|
192 |
my $page = shift; |
|
193 |
my $data = shift; |
|
194 |
my %arg = @_; |
|
195 |
|
|
196 |
#===================================== |
|
197 |
# Mandatory Arguments Section |
|
198 |
#===================================== |
|
199 |
unless ($pdf and $page and $data) { |
|
200 |
print "Error: Mandatory parameter is missing pdf/page/data object!\n"; |
|
201 |
return; |
|
202 |
} |
|
203 |
# Try to provide backward compatibility |
|
204 |
foreach my $key (keys %arg) { |
|
205 |
my $newkey = $key; |
|
206 |
if ($newkey =~ s#^-##) { |
|
207 |
$arg{$newkey} = $arg{$key}; |
|
208 |
delete $arg{$key}; |
|
387 |
my $header_row = undef; |
|
388 |
#===================================== |
|
389 |
# Other Parameters check |
|
390 |
#===================================== |
|
391 |
my $lead = $arg{'lead' } || $fnt_size; |
|
392 |
my $pad_left = $arg{'padding_left' } || $arg{'padding'} || 0; |
|
393 |
my $pad_right = $arg{'padding_right' } || $arg{'padding'} || 0; |
|
394 |
my $pad_top = $arg{'padding_top' } || $arg{'padding'} || 0; |
|
395 |
my $pad_bot = $arg{'padding_bottom'} || $arg{'padding'} || 0; |
|
396 |
my $line_w = defined $arg{'border'} ? $arg{'border'} : 1 ; |
|
397 |
my $horiz_borders = defined $arg{'horizontal_borders'} |
|
398 |
? $arg{'horizontal_borders'} |
|
399 |
: $line_w; |
|
400 |
my $vert_borders = defined $arg{'vertical_borders'} |
|
401 |
? $arg{'vertical_borders'} |
|
402 |
: $line_w; |
|
403 |
|
|
404 |
my $background_color_even = $arg{'background_color_even' } || $arg{'background_color'} || undef; |
|
405 |
my $background_color_odd = $arg{'background_color_odd' } || $arg{'background_color'} || undef; |
|
406 |
my $font_color_even = $arg{'font_color_even' } || $arg{'font_color' } || 'black'; |
|
407 |
my $font_color_odd = $arg{'font_color_odd' } || $arg{'font_color' } || 'black'; |
|
408 |
my $border_color = $arg{'border_color' } || 'black'; |
|
409 |
|
|
410 |
my $min_row_h = $fnt_size + $pad_top + $pad_bot; |
|
411 |
my $row_h = defined ($arg{'row_height'}) |
|
412 |
&& |
|
413 |
($arg{'row_height'} > $min_row_h) |
|
414 |
? |
|
415 |
$arg{'row_height'} : $min_row_h; |
|
416 |
|
|
417 |
my $pg_cnt = 1; |
|
418 |
my $cur_y = $ybase; |
|
419 |
my $cell_props = $arg{cell_props} || []; # per cell properties |
|
420 |
|
|
421 |
#If there is no valid data array reference warn and return! |
|
422 |
if(ref $data ne 'ARRAY') |
|
423 |
{ |
|
424 |
carp "Passed table data is not an ARRAY reference. It's actually a ref to ".ref($data); |
|
425 |
return ($page,0,$cur_y); |
|
209 | 426 |
} |
210 |
} |
|
211 |
#TODO: Add code for header props compatibility and col_props comp.... |
|
212 |
##### |
|
213 |
my ( $xbase, $ybase, $width, $height ) = ( undef, undef, undef, undef ); |
|
214 |
# Could be 'int' or 'real' values |
|
215 |
$xbase = $arg{'x' } || -1; |
|
216 |
$ybase = $arg{'start_y'} || -1; |
|
217 |
$width = $arg{'w' } || -1; |
|
218 |
$height = $arg{'start_h'} || -1; |
|
219 |
|
|
220 |
# Global geometry parameters are also mandatory. |
|
221 |
unless ( $xbase > 0 ) { print "Error: Left Edge of Table is NOT defined!\n"; return; } |
|
222 |
unless ( $ybase > 0 ) { print "Error: Base Line of Table is NOT defined!\n"; return; } |
|
223 |
unless ( $width > 0 ) { print "Error: Width of Table is NOT defined!\n"; return; } |
|
224 |
unless ( $height > 0 ) { print "Error: Height of Table is NOT defined!\n"; return; } |
|
225 |
|
|
226 |
# Ensure default values for -next_y and -next_h |
|
227 |
my $next_y = $arg{'next_y'} || $arg{'start_y'} || 0; |
|
228 |
my $next_h = $arg{'next_h'} || $arg{'start_h'} || 0; |
|
229 |
|
|
230 |
# Create Text Object |
|
231 |
my $txt = $page->text; |
|
232 |
# Set Default Properties |
|
233 |
my $fnt_name = $arg{'font'} || $pdf->corefont('Times', -encode => 'utf8'); |
|
234 |
my $fnt_size = $arg{'font_size'} || 12; |
|
235 |
my $max_word_len = $arg{'max_word_length'} || 20; |
|
236 |
|
|
237 |
#===================================== |
|
238 |
# Table Header Section |
|
239 |
#===================================== |
|
240 |
# Disable header row into the table |
|
241 |
my $header_props; |
|
242 |
my $num_header_rows = 0; |
|
243 |
my (@header_rows, @header_row_cell_props); |
|
244 |
# Check if the user enabled it ? |
|
245 |
if (defined $arg{'header_props'} and ref( $arg{'header_props'}) eq 'HASH') { |
|
246 |
# Transfer the reference to local variable |
|
247 |
$header_props = $arg{'header_props'}; |
|
248 |
# Check other params and put defaults if needed |
|
249 |
$header_props->{'repeat'} = $header_props->{'repeat'} || 0; |
|
250 |
$header_props->{'font'} = $header_props->{'font'} || $fnt_name; |
|
251 |
$header_props->{'font_color'} = $header_props->{'font_color'} || '#000066'; |
|
252 |
$header_props->{'font_size'} = $header_props->{'font_size'} || $fnt_size + 2; |
|
253 |
$header_props->{'bg_color'} = $header_props->{'bg_color'} || '#FFFFAA'; |
|
254 |
|
|
255 |
$num_header_rows = $arg{'num_header_rows'} || 1; |
|
256 |
} |
|
257 |
#===================================== |
|
258 |
# Other Parameters check |
|
259 |
#===================================== |
|
260 |
|
|
261 |
my $lead = $arg{'lead'} || $fnt_size; |
|
262 |
my $pad_left = $arg{'padding_left'} || $arg{'padding'} || 0; |
|
263 |
my $pad_right = $arg{'padding_right'} || $arg{'padding'} || 0; |
|
264 |
my $pad_top = $arg{'padding_top'} || $arg{'padding'} || 0; |
|
265 |
my $pad_bot = $arg{'padding_bottom'} || $arg{'padding'} || 0; |
|
266 |
my $pad_w = $pad_left + $pad_right; |
|
267 |
my $pad_h = $pad_top + $pad_bot ; |
|
268 |
my $line_w = defined $arg{'border'} ? $arg{'border'} : 1 ; |
|
269 |
|
|
270 |
my $background_color_even = $arg{'background_color_even'} || $arg{'background_color'} || undef; |
|
271 |
my $background_color_odd = $arg{'background_color_odd'} || $arg{'background_color'} || undef; |
|
272 |
my $font_color_even = $arg{'font_color_even'} || $arg{'font_color'} || 'black'; |
|
273 |
my $font_color_odd = $arg{'font_color_odd'} || $arg{'font_color'} || 'black'; |
|
274 |
my $border_color = $arg{'border_color'} || 'black'; |
|
275 |
|
|
276 |
my $min_row_h = $fnt_size + $pad_top + $pad_bot; |
|
277 |
my $row_h = defined ($arg{'row_height'}) && ($arg{'row_height'} > $min_row_h) ? $arg{'row_height'} : $min_row_h; |
|
278 |
|
|
279 |
my $pg_cnt = 1; |
|
280 |
my $cur_y = $ybase; |
|
281 |
my $cell_props = $arg{cell_props} || []; # per cell properties |
|
282 |
my $row_cnt = $num_header_rows; |
|
283 |
|
|
284 |
#If there is valid data array reference use it! |
|
285 |
if (ref $data eq 'ARRAY') { |
|
427 |
|
|
286 | 428 |
# Copy the header row if header is enabled |
287 |
if (defined $header_props) { |
|
288 |
map { push @header_rows, $$data[$_] } (0..$num_header_rows - 1); |
|
289 |
map { push @header_row_cell_props, $$cell_props[$_] } (0..$num_header_rows - 1); |
|
290 |
} |
|
429 |
@$header_row = $$data[0] if defined $header_props; |
|
291 | 430 |
# Determine column widths based on content |
292 | 431 |
|
293 |
# an arrayref whose values are a hashref holding |
|
432 |
# an arrayref whose values are a hashref holding
|
|
294 | 433 |
# the minimum and maximum width of that column |
295 | 434 |
my $col_props = $arg{'column_props'} || []; |
296 | 435 |
|
297 |
# An array ref of arrayrefs whose values are |
|
436 |
# An array ref of arrayrefs whose values are
|
|
298 | 437 |
# the actual widths of the column/row intersection |
299 |
my $row_props = [];
|
|
300 |
# An array ref with the widths of the header row |
|
301 |
my @header_row_widths;
|
|
302 |
|
|
303 |
# Scalars that hold sum of the maximum and minimum widths of all columns |
|
304 |
my ( $max_col_w, $min_col_w ) = ( 0,0 );
|
|
438 |
my $row_col_widths = [];
|
|
439 |
# An array ref with the widths of the header row
|
|
440 |
my $header_row_props = [];
|
|
441 |
|
|
442 |
# Scalars that hold sum of the maximum and minimum widths of all columns
|
|
443 |
my ( $max_col_w , $min_col_w ) = ( 0,0 );
|
|
305 | 444 |
my ( $row, $col_name, $col_fnt_size, $space_w ); |
306 | 445 |
|
307 |
# Hash that will hold the width of every word from input text |
|
308 |
my $word_w = {}; |
|
309 |
my $rows_counter = 0; |
|
310 |
|
|
311 |
foreach $row ( @{$data} ) { |
|
312 |
push(@header_row_widths, []) if ($rows_counter < $num_header_rows); |
|
446 |
my $word_widths = {}; |
|
447 |
my $rows_height = []; |
|
448 |
my $first_row = 1; |
|
313 | 449 |
|
314 |
my $column_widths = []; #holds the width of each column |
|
315 |
for( my $j = 0; $j < scalar(@$row) ; $j++ ) { |
|
316 |
# look for font information for this column |
|
317 |
$col_fnt_size = $col_props->[$j]->{'font_size'} || $fnt_size; |
|
318 |
if ( !$rows_counter and ref $header_props) { |
|
319 |
$txt->font( $header_props->{'font'}, $header_props->{'font_size'} ); |
|
320 |
|
|
321 |
} elsif ( $col_props->[$j]->{'font'} ) { |
|
322 |
$txt->font( $col_props->[$j]->{'font'}, $col_fnt_size ); |
|
323 |
|
|
324 |
} else { |
|
325 |
$txt->font( $fnt_name, $col_fnt_size ); |
|
326 |
} |
|
327 |
|
|
328 |
# This should fix a bug with very long word like serial numbers etc. |
|
329 |
# $myone is used because $1 gets out of scope in while condition |
|
330 |
my $myone; |
|
331 |
do { |
|
332 |
$myone = 0; |
|
333 |
# This RegEx will split any word that is longer than {25} symbols |
|
334 |
$row->[$j] =~ s#(\b\S{$max_word_len}?)(\S.*?\b)# $1 $2#; |
|
335 |
$myone = 1 if ( defined $2 ); |
|
336 |
} while( $myone ); |
|
337 |
$row->[$j] =~ s/^\s+//; |
|
338 |
|
|
339 |
$space_w = $txt->advancewidth( "\x20" ); |
|
340 |
$column_widths->[$j] = 0; |
|
341 |
$max_col_w = 0; |
|
342 |
$min_col_w = 0; |
|
343 |
|
|
344 |
my @words = split( /\s+/, $row->[$j] ); |
|
345 |
|
|
346 |
foreach( @words ) { |
|
347 |
unless ( exists $word_w->{$_} ) { # Calculate the width of every word and add the space width to it |
|
348 |
$word_w->{$_} = $txt->advancewidth( $_ ) + $space_w; |
|
349 |
} |
|
350 |
$column_widths->[$j] += $word_w->{$_}; |
|
351 |
$min_col_w = $word_w->{$_} if $word_w->{$_} > $min_col_w; |
|
352 |
$max_col_w += $word_w->{$_}; |
|
353 |
} |
|
354 |
$min_col_w += $pad_w; |
|
355 |
$max_col_w += $pad_w; |
|
356 |
$column_widths->[$j] += $pad_w; |
|
450 |
for( my $row_idx = 0; $row_idx < scalar(@$data) ; $row_idx++ ) |
|
451 |
{ |
|
452 |
my $column_widths = []; #holds the width of each column |
|
453 |
# Init the height for this row |
|
454 |
$rows_height->[$row_idx] = 0; |
|
455 |
|
|
456 |
for( my $column_idx = 0; $column_idx < scalar(@{$data->[$row_idx]}) ; $column_idx++ ) |
|
457 |
{ |
|
458 |
# look for font information for this column |
|
459 |
my ($cell_font, $cell_font_size); |
|
460 |
|
|
461 |
if( !$row_idx and ref $header_props ) |
|
462 |
{ |
|
463 |
$cell_font = $header_props->{'font'}; |
|
464 |
$cell_font_size = $header_props->{'font_size'}; |
|
465 |
} |
|
466 |
|
|
467 |
# Get the most specific value if none was already set from header_props |
|
468 |
$cell_font ||= $cell_props->[$row_idx][$column_idx]->{'font'} |
|
469 |
|| $col_props->[$column_idx]->{'font'} |
|
470 |
|| $fnt_name; |
|
471 |
|
|
472 |
$cell_font_size ||= $cell_props->[$row_idx][$column_idx]->{'font_size'} |
|
473 |
|| $col_props->[$column_idx]->{'font_size'} |
|
474 |
|| $fnt_size; |
|
475 |
|
|
476 |
# Set Font |
|
477 |
$txt->font( $cell_font, $cell_font_size ); |
|
478 |
|
|
479 |
# Set row height to biggest font size from row's cells |
|
480 |
if( $cell_font_size > $rows_height->[$row_idx] ) |
|
481 |
{ |
|
482 |
$rows_height->[$row_idx] = $cell_font_size; |
|
483 |
} |
|
357 | 484 |
|
358 |
# Keep a running total of the overall min and max widths |
|
359 |
$col_props->[$j]->{min_w} = $col_props->[$j]->{min_w} || 0; |
|
360 |
$col_props->[$j]->{max_w} = $col_props->[$j]->{max_w} || 0; |
|
485 |
# This should fix a bug with very long words like serial numbers etc. |
|
486 |
if( $max_word_len > 0 ) |
|
487 |
{ |
|
488 |
$data->[$row_idx][$column_idx] =~ s#(\S{$max_word_len})(?=\S)#$1 #g; |
|
489 |
} |
|
361 | 490 |
|
362 |
if ( $min_col_w > $col_props->[$j]->{min_w} ) { # Calculated Minimum Column Width is more than user-defined |
|
363 |
$col_props->[$j]->{min_w} = $min_col_w ; |
|
364 |
} |
|
365 |
if ( $max_col_w > $col_props->[$j]->{max_w} ) { # Calculated Maximum Column Width is more than user-defined |
|
366 |
$col_props->[$j]->{max_w} = $max_col_w ; |
|
367 |
} |
|
368 |
}#End of for(my $j.... |
|
369 |
$row_props->[$rows_counter] = $column_widths; |
|
370 |
# Copy the calculated row properties of header row. |
|
371 |
if (($rows_counter < $num_header_rows) && $header_props) { |
|
372 |
push(@header_row_widths, [ @{ $column_widths } ]); |
|
373 |
} |
|
374 |
$rows_counter++; |
|
491 |
# Init cell size limits |
|
492 |
$space_w = $txt->advancewidth( "\x20" ); |
|
493 |
$column_widths->[$column_idx] = 0; |
|
494 |
$max_col_w = 0; |
|
495 |
$min_col_w = 0; |
|
496 |
|
|
497 |
my @words = split( /\s+/, $data->[$row_idx][$column_idx] ); |
|
498 |
|
|
499 |
foreach( @words ) |
|
500 |
{ |
|
501 |
unless( exists $word_widths->{$_} ) |
|
502 |
{ # Calculate the width of every word and add the space width to it |
|
503 |
$word_widths->{$_} = $txt->advancewidth( $_ ) + $space_w; |
|
504 |
} |
|
505 |
|
|
506 |
$column_widths->[$column_idx] += $word_widths->{$_}; |
|
507 |
$min_col_w = $word_widths->{$_} if( $word_widths->{$_} > $min_col_w ); |
|
508 |
$max_col_w += $word_widths->{$_}; |
|
509 |
} |
|
510 |
|
|
511 |
$min_col_w += $pad_left + $pad_right; |
|
512 |
$max_col_w += $pad_left + $pad_right; |
|
513 |
$column_widths->[$column_idx] += $pad_left + $pad_right; |
|
514 |
|
|
515 |
# Keep a running total of the overall min and max widths |
|
516 |
$col_props->[$column_idx]->{'min_w'} ||= 0; |
|
517 |
$col_props->[$column_idx]->{'max_w'} ||= 0; |
|
518 |
|
|
519 |
if( $min_col_w > $col_props->[$column_idx]->{'min_w'} ) |
|
520 |
{ # Calculated Minimum Column Width is more than user-defined |
|
521 |
$col_props->[$column_idx]->{'min_w'} = $min_col_w ; |
|
522 |
} |
|
523 |
|
|
524 |
if( $max_col_w > $col_props->[$column_idx]->{'max_w'} ) |
|
525 |
{ # Calculated Maximum Column Width is more than user-defined |
|
526 |
$col_props->[$column_idx]->{'max_w'} = $max_col_w ; |
|
527 |
} |
|
528 |
}#End of for(my $column_idx.... |
|
529 |
|
|
530 |
$row_col_widths->[$row_idx] = $column_widths; |
|
531 |
|
|
532 |
# Copy the calculated row properties of header row. |
|
533 |
@$header_row_props = @$column_widths if(!$row_idx and ref $header_props); |
|
375 | 534 |
} |
535 |
|
|
376 | 536 |
# Calc real column widths and expand table width if needed. |
377 |
my $calc_column_widths; |
|
378 |
($calc_column_widths, $width) = $self->CalcColumnWidths( $col_props, $width ); |
|
379 |
my $num_cols = scalar @{ $calc_column_widths }; |
|
380 |
my $comp_cnt = 1; |
|
381 |
$rows_counter = 0; |
|
537 |
my $calc_column_widths; |
|
538 |
($calc_column_widths, $width) = CalcColumnWidths( $col_props, $width ); |
|
382 | 539 |
|
383 |
my ( $gfx , $gfx_bg , $background_color , $font_color, ); |
|
384 |
my ( $bot_marg, $table_top_y, $text_start , $record, $record_widths ); |
|
540 |
# Lets draw what we have! |
|
541 |
my $row_index = 0; |
|
542 |
# Store header row height for later use if headers have to be repeated |
|
543 |
my $header_row_height = $rows_height->[0]; |
|
385 | 544 |
|
386 |
my $remaining_header_rows = $header_props ? $num_header_rows : 0;
|
|
545 |
my ( $gfx, $gfx_bg, $background_color, $font_color, $bot_marg, $table_top_y, $text_start);
|
|
387 | 546 |
|
388 | 547 |
# Each iteration adds a new page as neccessary |
389 |
while(scalar(@{$data})) { |
|
390 |
my $page_header; |
|
391 |
if ($pg_cnt == 1) { |
|
392 |
$table_top_y = $ybase; |
|
393 |
$bot_marg = $table_top_y - $height; |
|
394 |
|
|
395 |
} else { |
|
396 |
if (ref $arg{'new_page_func'}) { |
|
397 |
$page = &{$arg{'new_page_func'}}; |
|
398 |
|
|
399 |
} else { |
|
400 |
$page = $pdf->page; |
|
401 |
} |
|
402 |
|
|
403 |
$table_top_y = $next_y; |
|
404 |
$bot_marg = $table_top_y - $next_h; |
|
548 |
while(scalar(@{$data})) |
|
549 |
{ |
|
550 |
my ($page_header, $columns_number); |
|
405 | 551 |
|
406 |
if ( ref $header_props and $header_props->{'repeat'}) { |
|
407 |
foreach my $idx (0 .. $num_header_rows - 1) { |
|
408 |
unshift @$data, [ @{ $header_rows[$idx] } ]; |
|
409 |
unshift @$row_props, [ @{ $header_row_widths[$idx] } ]; |
|
410 |
} |
|
411 |
$remaining_header_rows = $num_header_rows; |
|
552 |
if($pg_cnt == 1) |
|
553 |
{ |
|
554 |
$table_top_y = $ybase; |
|
555 |
$bot_marg = $table_top_y - $height; |
|
412 | 556 |
} |
413 |
}
|
|
414 |
|
|
415 |
# Check for safety reasons
|
|
416 |
if ( $bot_marg < 0 ) { # This warning should remain i think
|
|
417 |
# print "!!! Warning: !!! Incorrect Table Geometry! Setting bottom margin to end of sheet!\n";
|
|
418 |
$bot_marg = 0;
|
|
419 |
}
|
|
420 |
|
|
421 |
$gfx_bg = $page->gfx;
|
|
422 |
$txt = $page->text;
|
|
423 |
$txt->font($fnt_name, $fnt_size); |
|
424 |
$gfx = $page->gfx;
|
|
425 |
$gfx->strokecolor($border_color);
|
|
426 |
$gfx->linewidth($line_w); |
|
427 |
|
|
428 |
# Draw the top line
|
|
429 |
$cur_y = $table_top_y;
|
|
430 |
$gfx->move( $xbase , $cur_y );
|
|
431 |
$gfx->hline($xbase + $width );
|
|
432 |
|
|
433 |
# Each iteration adds a row to the current page until the page is full
|
|
434 |
# or there are no more rows to add
|
|
435 |
while(scalar(@{$data}) and $cur_y-$row_h > $bot_marg) {
|
|
436 |
# Remove the next item from $data
|
|
437 |
$record = shift @{$data}; |
|
438 |
# Added to resolve infite loop bug with returned undef values
|
|
439 |
for(my $d = 0; $d < scalar(@{$record}) ; $d++) {
|
|
440 |
$record->[$d] = '-' unless ( defined $record->[$d]);
|
|
557 |
else
|
|
558 |
{ |
|
559 |
if(ref $arg{'new_page_func'})
|
|
560 |
{
|
|
561 |
$page = &{$arg{'new_page_func'}};
|
|
562 |
}
|
|
563 |
else
|
|
564 |
{ |
|
565 |
$page = $pdf->page;
|
|
566 |
}
|
|
567 |
|
|
568 |
$table_top_y = $next_y;
|
|
569 |
$bot_marg = $table_top_y - $next_h;
|
|
570 |
|
|
571 |
if( ref $header_props and $header_props->{'repeat'}) |
|
572 |
{
|
|
573 |
# Copy Header Data
|
|
574 |
@$page_header = @$header_row;
|
|
575 |
my $hrp ;
|
|
576 |
@$hrp = @$header_row_props ; |
|
577 |
# Then prepend it to master data array
|
|
578 |
unshift @$data, @$page_header;
|
|
579 |
unshift @$row_col_widths, $hrp;
|
|
580 |
unshift @$rows_height, $header_row_height;
|
|
581 |
|
|
582 |
$first_row = 1; # Means YES
|
|
583 |
$row_index--; # Rollback the row_index because a new header row has been added
|
|
584 |
}
|
|
441 | 585 |
} |
442 | 586 |
|
443 |
$record_widths = shift @$row_props; |
|
444 |
next unless $record; |
|
445 |
|
|
446 |
# Choose colors for this row |
|
447 |
$background_color = $rows_counter % 2 ? $background_color_even : $background_color_odd; |
|
448 |
$font_color = $rows_counter % 2 ? $font_color_even : $font_color_odd; |
|
449 |
|
|
450 |
if ($remaining_header_rows and ref $header_props) { |
|
451 |
$background_color = $header_props->{'bg_color'} |
|
587 |
# Check for safety reasons |
|
588 |
if( $bot_marg < 0 ) |
|
589 |
{ # This warning should remain i think |
|
590 |
carp "!!! Warning: !!! Incorrect Table Geometry! Setting bottom margin to end of sheet!\n"; |
|
591 |
$bot_marg = 0; |
|
452 | 592 |
} |
453 |
$text_start = $cur_y - $fnt_size - $pad_top; |
|
454 |
my $cur_x = $xbase; |
|
455 |
my $leftovers = undef; # Reference to text that is returned from textblock() |
|
456 |
my $do_leftovers = 0; |
|
457 |
|
|
458 |
my ($colspan, @vertical_lines); |
|
459 | 593 |
|
460 |
# Process every column from current row |
|
461 |
for( my $j = 0; $j < scalar( @$record); $j++ ) { |
|
462 |
next unless $col_props->[$j]->{max_w}; |
|
463 |
next unless $col_props->[$j]->{min_w}; |
|
464 |
$leftovers->[$j] = undef; |
|
594 |
$gfx_bg = $page->gfx; |
|
595 |
$txt = $page->text; |
|
596 |
$txt->font($fnt_name, $fnt_size); |
|
465 | 597 |
|
466 |
# Choose font color |
|
467 |
if ( $remaining_header_rows and ref $header_props ) { |
|
468 |
$txt->fillcolor( $header_props->{'font_color'} ); |
|
598 |
$cur_y = $table_top_y; |
|
469 | 599 |
|
470 |
} elsif ( $cell_props->[$row_cnt][$j]{font_color} ) { |
|
471 |
$txt->fillcolor( $cell_props->[$row_cnt][$j]{font_color} ); |
|
600 |
if ($line_w) |
|
601 |
{ |
|
602 |
$gfx = $page->gfx; |
|
603 |
$gfx->strokecolor($border_color); |
|
604 |
$gfx->linewidth($line_w); |
|
472 | 605 |
|
473 |
} elsif ( $col_props->[$j]->{'font_color'} ) { |
|
474 |
$txt->fillcolor( $col_props->[$j]->{'font_color'} ); |
|
606 |
# Draw the top line |
|
607 |
if ($horiz_borders) |
|
608 |
{ |
|
609 |
$gfx->move( $xbase , $cur_y ); |
|
610 |
$gfx->hline($xbase + $width ); |
|
611 |
} |
|
612 |
} |
|
613 |
else |
|
614 |
{ |
|
615 |
$gfx = undef; |
|
616 |
} |
|
475 | 617 |
|
476 |
} else { |
|
477 |
$txt->fillcolor($font_color); |
|
478 |
} |
|
618 |
# Each iteration adds a row to the current page until the page is full |
|
619 |
# or there are no more rows to add |
|
620 |
# Row_Loop |
|
621 |
while(scalar(@{$data}) and $cur_y-$row_h > $bot_marg) |
|
622 |
{ |
|
623 |
# Remove the next item from $data |
|
624 |
my $record = shift @{$data}; |
|
625 |
|
|
626 |
# Get columns number to know later how many vertical lines to draw |
|
627 |
# TODO: get the max number of columns per page as currently last row's columns overrides |
|
628 |
$columns_number = scalar(@$record); |
|
629 |
|
|
630 |
# Get the next set of row related settings |
|
631 |
# Row Height |
|
632 |
my $pre_calculated_row_height = shift @$rows_height; |
|
633 |
|
|
634 |
# Row cell widths |
|
635 |
my $record_widths = shift @$row_col_widths; |
|
636 |
|
|
637 |
# Row coloumn props - TODO in another commit |
|
638 |
|
|
639 |
# Row cell props - TODO in another commit |
|
640 |
|
|
641 |
# Added to resolve infite loop bug with returned undef values |
|
642 |
for(my $d = 0; $d < scalar(@{$record}) ; $d++) |
|
643 |
{ |
|
644 |
$record->[$d] = '-' unless( defined $record->[$d]); |
|
645 |
} |
|
479 | 646 |
|
480 |
# Choose font size
|
|
481 |
if ( $remaining_header_rows and ref $header_props ) {
|
|
482 |
$col_fnt_size = $header_props->{'font_size'};
|
|
647 |
# Choose colors for this row
|
|
648 |
$background_color = $row_index % 2 ? $background_color_even : $background_color_odd;
|
|
649 |
$font_color = $row_index % 2 ? $font_color_even : $font_color_odd;
|
|
483 | 650 |
|
484 |
} elsif ( $col_props->[$j]->{'font_size'} ) {
|
|
485 |
$col_fnt_size = $col_props->[$j]->{'font_size'};
|
|
651 |
#Determine current row height
|
|
652 |
my $current_row_height = $pad_top + $pre_calculated_row_height + $pad_bot;
|
|
486 | 653 |
|
487 |
} else { |
|
488 |
$col_fnt_size = $fnt_size; |
|
489 |
} |
|
654 |
# $row_h is the calculated global user requested row height. |
|
655 |
# It will be honored, only if it has bigger value than the calculated one. |
|
656 |
# TODO: It's questionable if padding should be inclided in this calculation or not |
|
657 |
if($current_row_height < $row_h){ |
|
658 |
$current_row_height = $row_h; |
|
659 |
} |
|
490 | 660 |
|
491 |
# Choose font family |
|
492 |
if ( $remaining_header_rows and ref $header_props ) { |
|
493 |
$txt->font( $header_props->{'font'}, $header_props->{'font_size'}); |
|
661 |
# Define the font y base position for this line. |
|
662 |
$text_start = $cur_y - ($current_row_height - $pad_bot); |
|
663 |
|
|
664 |
my $cur_x = $xbase; |
|
665 |
my $leftovers = undef; # Reference to text that is returned from textblock() |
|
666 |
my $do_leftovers = 0; |
|
667 |
|
|
668 |
# Process every cell(column) from current row |
|
669 |
for( my $column_idx = 0; $column_idx < scalar( @$record); $column_idx++ ) |
|
670 |
{ |
|
671 |
next unless $col_props->[$column_idx]->{'max_w'}; |
|
672 |
next unless $col_props->[$column_idx]->{'min_w'}; |
|
673 |
$leftovers->[$column_idx] = undef; |
|
674 |
|
|
675 |
# look for font information for this cell |
|
676 |
my ($cell_font, $cell_font_size, $cell_font_color, $justify); |
|
677 |
|
|
678 |
if( $first_row and ref $header_props) |
|
679 |
{ |
|
680 |
$cell_font = $header_props->{'font'}; |
|
681 |
$cell_font_size = $header_props->{'font_size'}; |
|
682 |
$cell_font_color = $header_props->{'font_color'}; |
|
683 |
$justify = $header_props->{'justify'}; |
|
684 |
} |
|
685 |
|
|
686 |
# Get the most specific value if none was already set from header_props |
|
687 |
$cell_font ||= $cell_props->[$row_index][$column_idx]->{'font'} |
|
688 |
|| $col_props->[$column_idx]->{'font'} |
|
689 |
|| $fnt_name; |
|
690 |
|
|
691 |
$cell_font_size ||= $cell_props->[$row_index][$column_idx]->{'font_size'} |
|
692 |
|| $col_props->[$column_idx]->{'font_size'} |
|
693 |
|| $fnt_size; |
|
694 |
|
|
695 |
$cell_font_color ||= $cell_props->[$row_index][$column_idx]->{'font_color'} |
|
696 |
|| $col_props->[$column_idx]->{'font_color'} |
|
697 |
|| $font_color; |
|
698 |
|
|
699 |
$justify ||= $cell_props->[$row_index][$column_idx]->{'justify'} |
|
700 |
|| $col_props->[$column_idx]->{'justify'} |
|
701 |
|| $arg{'justify'} |
|
702 |
|| 'left'; |
|
703 |
|
|
704 |
# Init cell font object |
|
705 |
$txt->font( $cell_font, $cell_font_size ); |
|
706 |
$txt->fillcolor($cell_font_color); |
|
707 |
|
|
708 |
# If the content is wider than the specified width, we need to add the text as a text block |
|
709 |
if( $record->[$column_idx] !~ m/(.\n.)/ and |
|
710 |
$record_widths->[$column_idx] and |
|
711 |
$record_widths->[$column_idx] <= $calc_column_widths->[$column_idx] |
|
712 |
){ |
|
713 |
my $space = $pad_left; |
|
714 |
if ($justify eq 'right') |
|
715 |
{ |
|
716 |
$space = $calc_column_widths->[$column_idx] -($txt->advancewidth($record->[$column_idx]) + $pad_right); |
|
717 |
} |
|
718 |
elsif ($justify eq 'center') |
|
719 |
{ |
|
720 |
$space = ($calc_column_widths->[$column_idx] - $txt->advancewidth($record->[$column_idx])) / 2; |
|
721 |
} |
|
722 |
$txt->translate( $cur_x + $space, $text_start ); |
|
723 |
$txt->text( $record->[$column_idx] ); |
|
724 |
} |
|
725 |
# Otherwise just use the $page->text() method |
|
726 |
else |
|
727 |
{ |
|
728 |
my ($width_of_last_line, $ypos_of_last_line, $left_over_text) = $self->text_block( |
|
729 |
$txt, |
|
730 |
$record->[$column_idx], |
|
731 |
x => $cur_x + $pad_left, |
|
732 |
y => $text_start, |
|
733 |
w => $calc_column_widths->[$column_idx] - $pad_left - $pad_right, |
|
734 |
h => $cur_y - $bot_marg - $pad_top - $pad_bot, |
|
735 |
align => $justify, |
|
736 |
lead => $lead |
|
737 |
); |
|
738 |
# Desi - Removed $lead because of fixed incorrect ypos bug in text_block |
|
739 |
my $current_cell_height = $cur_y - $ypos_of_last_line + $pad_bot; |
|
740 |
if( $current_cell_height > $current_row_height ) |
|
741 |
{ |
|
742 |
$current_row_height = $current_cell_height; |
|
743 |
} |
|
744 |
|
|
745 |
if( $left_over_text ) |
|
746 |
{ |
|
747 |
$leftovers->[$column_idx] = $left_over_text; |
|
748 |
$do_leftovers = 1; |
|
749 |
} |
|
750 |
} |
|
751 |
$cur_x += $calc_column_widths->[$column_idx]; |
|
752 |
} |
|
753 |
if( $do_leftovers ) |
|
754 |
{ |
|
755 |
unshift @$data, $leftovers; |
|
756 |
unshift @$row_col_widths, $record_widths; |
|
757 |
unshift @$rows_height, $pre_calculated_row_height; |
|
758 |
} |
|
759 |
|
|
760 |
# Draw cell bgcolor |
|
761 |
# This has to be separately from the text loop |
|
762 |
# because we do not know the final height of the cell until all text has been drawn |
|
763 |
$cur_x = $xbase; |
|
764 |
for(my $column_idx = 0 ; $column_idx < scalar(@$record) ; $column_idx++) |
|
765 |
{ |
|
766 |
my $cell_bg_color; |
|
767 |
|
|
768 |
if( $first_row and ref $header_props) |
|
769 |
{ #Compatibility Consistency with other props |
|
770 |
$cell_bg_color = $header_props->{'bg_color'} || $header_props->{'background_color'}; |
|
771 |
} |
|
772 |
|
|
773 |
# Get the most specific value if none was already set from header_props |
|
774 |
$cell_bg_color ||= $cell_props->[$row_index][$column_idx]->{'background_color'} |
|
775 |
|| $col_props->[$column_idx]->{'background_color'} |
|
776 |
|| $background_color; |
|
777 |
|
|
778 |
if ($cell_bg_color) |
|
779 |
{ |
|
780 |
$gfx_bg->rect( $cur_x, $cur_y-$current_row_height, $calc_column_widths->[$column_idx], $current_row_height); |
|
781 |
$gfx_bg->fillcolor($cell_bg_color); |
|
782 |
$gfx_bg->fill(); |
|
783 |
} |
|
784 |
$cur_x += $calc_column_widths->[$column_idx]; |
|
785 |
}#End of for(my $column_idx.... |
|
786 |
|
|
787 |
$cur_y -= $current_row_height; |
|
788 |
if ($gfx && $horiz_borders) |
|
789 |
{ |
|
790 |
$gfx->move( $xbase , $cur_y ); |
|
791 |
$gfx->hline( $xbase + $width ); |
|
792 |
} |
|
494 | 793 |
|
495 |
} elsif ( $col_props->[$j]->{'font'} ) { |
|
496 |
$txt->font( $col_props->[$j]->{'font'}, $col_fnt_size); |
|
794 |
$row_index++ unless ( $do_leftovers ); |
|
795 |
$first_row = 0; |
|
796 |
}# End of Row_Loop |
|
797 |
|
|
798 |
if ($gfx) |
|
799 |
{ |
|
800 |
# Draw vertical lines |
|
801 |
if ($vert_borders) |
|
802 |
{ |
|
803 |
$gfx->move( $xbase, $table_top_y); |
|
804 |
$gfx->vline( $cur_y ); |
|
805 |
my $cur_x = $xbase; |
|
806 |
for( my $j = 0; $j < $columns_number; $j++ ) |
|
807 |
{ |
|
808 |
$cur_x += $calc_column_widths->[$j]; |
|
809 |
$gfx->move( $cur_x, $table_top_y ); |
|
810 |
$gfx->vline( $cur_y ); |
|
811 |
} |
|
812 |
} |
|
497 | 813 |
|
498 |
} else { |
|
499 |
$txt->font( $fnt_name, $col_fnt_size); |
|
500 |
} |
|
501 |
#TODO: Implement Center text align |
|
502 |
$col_props->[$j]->{justify} = $col_props->[$j]->{justify} || 'left'; |
|
814 |
# ACTUALLY draw all the lines |
|
815 |
$gfx->fillcolor( $border_color); |
|
816 |
$gfx->stroke; |
|
817 |
} |
|
818 |
$pg_cnt++; |
|
819 |
}# End of while(scalar(@{$data})) |
|
503 | 820 |
|
504 |
my $this_width; |
|
505 |
if (!$remaining_header_rows && $cell_props->[$row_cnt]->[$j]->{colspan}) { |
|
506 |
$colspan = $cell_props->[$row_cnt]->[$j]->{colspan}; |
|
821 |
return ($page,--$pg_cnt,$cur_y); |
|
822 |
} |
|
507 | 823 |
|
508 |
} elsif ($remaining_header_rows && $header_row_cell_props[$num_header_rows - $remaining_header_rows]->[$j]->{colspan}) { |
|
509 |
$colspan = $header_row_cell_props[$num_header_rows - $remaining_header_rows]->[$j]->{colspan}; |
|
510 | 824 |
|
511 |
} |
|
825 |
# calculate the column widths |
|
826 |
sub CalcColumnWidths |
|
827 |
{ |
|
828 |
my $col_props = shift; |
|
829 |
my $avail_width = shift; |
|
830 |
my $min_width = 0; |
|
512 | 831 |
|
513 |
if ($colspan) { |
|
514 |
$colspan = $num_cols - $j if (-1 == $colspan); |
|
515 |
my $last_idx = $j + $colspan - 1; |
|
516 |
$this_width = sum @{ $calc_column_widths }[$j..$last_idx]; |
|
832 |
my $calc_widths ; |
|
517 | 833 |
|
518 |
} else { |
|
519 |
$this_width = $calc_column_widths->[$j]; |
|
520 |
} |
|
834 |
for(my $j = 0; $j < scalar( @$col_props); $j++) |
|
835 |
{ |
|
836 |
$min_width += $col_props->[$j]->{min_w} || 0; |
|
837 |
} |
|
521 | 838 |
|
522 |
# If the content is wider than the specified width, we need to add the text as a text block |
|
523 |
if ($record->[$j] !~ m#(.\n.)# and $record_widths->[$j] and ($record_widths->[$j] < $this_width)) { |
|
524 |
my $space = $pad_left; |
|
525 |
if ($col_props->[$j]->{justify} eq 'right') { |
|
526 |
$space = $this_width -($txt->advancewidth($record->[$j]) + $pad_right); |
|
527 |
} |
|
528 |
$txt->translate( $cur_x + $space, $text_start ); |
|
529 |
$txt->text( $record->[$j] ); |
|
530 |
} else { # Otherwise just use the $page->text() method |
|
531 |
my($width_of_last_line, $ypos_of_last_line, $left_over_text) = |
|
532 |
$self->text_block($txt, |
|
533 |
$record->[$j], |
|
534 |
'x' => $cur_x + $pad_left, |
|
535 |
'y' => $text_start, |
|
536 |
'w' => $this_width - $pad_w, |
|
537 |
'h' => $cur_y - $bot_marg - $pad_top - $pad_bot, |
|
538 |
'align' => $col_props->[$j]->{justify}, |
|
539 |
'lead' => $lead |
|
540 |
); |
|
541 |
# Desi - Removed $lead because of fixed incorrect ypos bug in text_block |
|
542 |
my $this_row_h = $cur_y - ( $ypos_of_last_line - $pad_bot ); |
|
543 |
$row_h = $this_row_h if $this_row_h > $row_h; |
|
544 |
if ( $left_over_text ) { |
|
545 |
$leftovers->[$j] = $left_over_text; |
|
546 |
$do_leftovers = 1; |
|
547 |
} |
|
548 |
} |
|
549 |
$cur_x += $calc_column_widths->[$j]; |
|
839 |
# I think this is the optimal variant when good view can be guaranateed |
|
840 |
if($avail_width < $min_width) |
|
841 |
{ |
|
842 |
carp "!!! Warning !!!\n Calculated Mininal width($min_width) > Table width($avail_width).\n", |
|
843 |
' Expanding table width to:',int($min_width)+1,' but this could lead to unexpected results.',"\n", |
|
844 |
' Possible solutions:',"\n", |
|
845 |
' 0)Increase table width.',"\n", |
|
846 |
' 1)Decrease font size.',"\n", |
|
847 |
' 2)Choose a more narrow font.',"\n", |
|
848 |
' 3)Decrease "max_word_length" parameter.',"\n", |
|
849 |
' 4)Rotate page to landscape(if it is portrait).',"\n", |
|
850 |
' 5)Use larger paper size.',"\n", |
|
851 |
'!!! --------- !!!',"\n"; |
|
852 |
$avail_width = int( $min_width) + 1; |
|
550 | 853 |
|
551 |
push @vertical_lines, (!$colspan || (1 >= $colspan)) ? 1 : 0; |
|
552 |
$colspan-- if ($colspan); |
|
553 |
} |
|
854 |
} |
|
554 | 855 |
|
555 |
if ( $do_leftovers ) {
|
|
556 |
unshift @$data, $leftovers;
|
|
557 |
unshift @$row_props, $record_widths;
|
|
558 |
$rows_counter--;
|
|
559 |
}
|
|
856 |
# Calculate how much can be added to every column to fit the available width.
|
|
857 |
for(my $j = 0; $j < scalar(@$col_props); $j++ )
|
|
858 |
{
|
|
859 |
$calc_widths->[$j] = $col_props->[$j]->{min_w} || 0;;
|
|
860 |
} |
|
560 | 861 |
|
561 |
# Draw cell bgcolor |
|
562 |
# This has to be separately from the text loop |
|
563 |
# because we do not know the final height of the cell until all text has been drawn |
|
564 |
$cur_x = $xbase; |
|
565 |
for(my $j =0;$j < scalar(@$record);$j++) { |
|
566 |
if ( $cell_props->[$row_cnt][$j]->{'background_color'} || |
|
567 |
$col_props->[$j]->{'background_color'} || |
|
568 |
$background_color ) { |
|
569 |
$gfx_bg->rect( $cur_x, $cur_y-$row_h, $calc_column_widths->[$j], $row_h); |
|
570 |
if ( $cell_props->[$row_cnt][$j]->{'background_color'} && !$remaining_header_rows ) { |
|
571 |
$gfx_bg->fillcolor($cell_props->[$row_cnt][$j]->{'background_color'}); |
|
572 |
|
|
573 |
} elsif ( $col_props->[$j]->{'background_color'} && !$remaining_header_rows ) { |
|
574 |
$gfx_bg->fillcolor($col_props->[$j]->{'background_color'}); |
|
575 |
|
|
576 |
} else { |
|
577 |
$gfx_bg->fillcolor($background_color); |
|
862 |
# Allow columns to expand to max_w before applying extra space equally. |
|
863 |
my $is_last_iter; |
|
864 |
for (;;) |
|
865 |
{ |
|
866 |
my $span = ($avail_width - $min_width) / scalar( @$col_props); |
|
867 |
last if $span <= 0; |
|
868 |
|
|
869 |
$min_width = 0; |
|
870 |
my $next_will_be_last_iter = 1; |
|
871 |
for(my $j = 0; $j < scalar(@$col_props); $j++ ) |
|
872 |
{ |
|
873 |
my $new_w = $calc_widths->[$j] + $span; |
|
874 |
|
|
875 |
if (!$is_last_iter && $new_w > $col_props->[$j]->{max_w}) |
|
876 |
{ |
|
877 |
$new_w = $col_props->[$j]->{max_w} |
|
578 | 878 |
} |
579 |
$gfx_bg->fill(); |
|
580 |
} |
|
581 |
|
|
582 |
$cur_x += $calc_column_widths->[$j]; |
|
583 |
|
|
584 |
if ($line_w && $vertical_lines[$j] && ($j != (scalar(@{ $record }) - 1))) { |
|
585 |
$gfx->move($cur_x, $cur_y); |
|
586 |
$gfx->vline($cur_y - $row_h); |
|
587 |
$gfx->fillcolor($border_color); |
|
588 |
} |
|
589 |
}#End of for(my $j.... |
|
590 |
|
|
591 |
$cur_y -= $row_h; |
|
592 |
$row_h = $min_row_h; |
|
593 |
$gfx->move( $xbase , $cur_y ); |
|
594 |
$gfx->hline( $xbase + $width ); |
|
595 |
$rows_counter++; |
|
596 |
if ($remaining_header_rows) { |
|
597 |
$remaining_header_rows--; |
|
598 |
} else { |
|
599 |
$row_cnt++ unless $do_leftovers; |
|
879 |
if ($calc_widths->[$j] != $new_w ) |
|
880 |
{ |
|
881 |
$calc_widths->[$j] = $new_w; |
|
882 |
$next_will_be_last_iter = 0; |
|
883 |
} |
|
884 |
$min_width += $new_w; |
|
600 | 885 |
} |
601 |
}# End of while(scalar(@{$data}) and $cur_y-$row_h > $bot_marg) |
|
602 |
|
|
603 |
# Draw vertical lines |
|
604 |
if ($line_w) { |
|
605 |
$gfx->move($xbase, $table_top_y); |
|
606 |
$gfx->vline($cur_y); |
|
607 |
$gfx->move($xbase + sum(@{ $calc_column_widths }[0..$num_cols - 1]), $table_top_y); |
|
608 |
$gfx->vline($cur_y); |
|
609 |
$gfx->fillcolor($border_color); |
|
610 |
$gfx->stroke(); |
|
611 |
} |
|
612 |
$pg_cnt++; |
|
613 |
}# End of while(scalar(@{$data})) |
|
614 |
}# End of if (ref $data eq 'ARRAY') |
|
615 |
|
|
616 |
return ($page,--$pg_cnt,$cur_y); |
|
617 |
} |
|
618 |
|
|
886 |
last if $is_last_iter; |
|
887 |
$is_last_iter = $next_will_be_last_iter; |
|
888 |
} |
|
619 | 889 |
|
620 |
# calculate the column widths |
|
621 |
sub CalcColumnWidths { |
|
622 |
my $self = shift; |
|
623 |
my $col_props = shift; |
|
624 |
my $avail_width = shift; |
|
625 |
my $min_width = 0; |
|
626 |
|
|
627 |
my $calc_widths ; |
|
628 |
for(my $j = 0; $j < scalar( @$col_props); $j++) { |
|
629 |
$min_width += $col_props->[$j]->{min_w}; |
|
630 |
} |
|
631 |
|
|
632 |
# I think this is the optimal variant when good view can be guaranateed |
|
633 |
if ($avail_width < $min_width) { |
|
634 |
# print "!!! Warning !!!\n Calculated Mininal width($min_width) > Table width($avail_width).\n", |
|
635 |
# ' Expanding table width to:',int($min_width)+1,' but this could lead to unexpected results.',"\n", |
|
636 |
# ' Possible solutions:',"\n", |
|
637 |
# ' 0)Increase table width.',"\n", |
|
638 |
# ' 1)Decrease font size.',"\n", |
|
639 |
# ' 2)Choose a more narrow font.',"\n", |
|
640 |
# ' 3)Decrease "max_word_length" parameter.',"\n", |
|
641 |
# ' 4)Rotate page to landscape(if it is portrait).',"\n", |
|
642 |
# ' 5)Use larger paper size.',"\n", |
|
643 |
# '!!! --------- !!!',"\n"; |
|
644 |
$avail_width = int( $min_width) + 1; |
|
645 |
|
|
646 |
} |
|
647 |
|
|
648 |
my $span = 0; |
|
649 |
# Calculate how much can be added to every column to fit the available width |
|
650 |
$span = ($avail_width - $min_width) / scalar( @$col_props); |
|
651 |
for (my $j = 0; $j < scalar(@$col_props); $j++ ) { |
|
652 |
$calc_widths->[$j] = $col_props->[$j]->{min_w} + $span; |
|
653 |
} |
|
654 |
|
|
655 |
return ($calc_widths,$avail_width); |
|
890 |
return ($calc_widths,$avail_width); |
|
656 | 891 |
} |
657 | 892 |
1; |
658 | 893 |
|
... | ... | |
693 | 928 |
$some_data, |
694 | 929 |
x => $left_edge_of_table, |
695 | 930 |
w => 495, |
696 |
start_y => 750, |
|
697 |
next_y => 700, |
|
931 |
start_y => 500, |
|
698 | 932 |
start_h => 300, |
699 |
next_h => 500, |
|
700 | 933 |
# some optional params |
934 |
next_y => 750, |
|
935 |
next_h => 500, |
|
701 | 936 |
padding => 5, |
702 | 937 |
padding_right => 10, |
703 | 938 |
background_color_odd => "gray", |
... | ... | |
715 | 950 |
|
716 | 951 |
=head1 DESCRIPTION |
717 | 952 |
|
718 |
This class is a utility for use with the PDF::API2 module from CPAN. |
|
719 |
It can be used to display text data in a table layout within the PDF.
|
|
720 |
The text data must be in a 2d array (such as returned by a DBI statement handle fetchall_arrayref() call).
|
|
721 |
The PDF::Table will automatically add as many new pages as necessary to display all of the data. |
|
722 |
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. |
|
723 |
Also a (non)repeated header row with different layout properties can be specified. |
|
953 |
This class is a utility for use with the PDF::API2 module from CPAN.
|
|
954 |
It can be used to display text data in a table layout within a PDF.
|
|
955 |
The text data must be in a 2D array (such as returned by a DBI statement handle fetchall_arrayref() call).
|
|
956 |
The PDF::Table will automatically add as many new pages as necessary to display all of the data.
|
|
957 |
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.
|
|
958 |
Also a (non)repeated header row with different layout properties can be specified.
|
|
724 | 959 |
|
725 |
See the METHODS section for complete documentation of every parameter. |
Auch abrufbar als: Unified diff
PDF::Table update auf aktuelle Version aus git
cpan speist sich aus https://github.com/kamenov/PDF-Table
Diese hier ist aktuell aus Commit 5a9f499