File Coverage

blib/lib/Mxpress/PDF.pm
Criterion Covered Total %
statement 1669 2285 73.0
branch 171 342 50.0
condition 269 805 33.4
subroutine 187 239 78.2
pod 32 103 31.0
total 2328 3774 61.6


line stmt bran cond sub pod time code
1 3     3   73784 use v5.18;
  3         10  
2 3     3   14 use strict;
  3         4  
  3         72  
3 3     3   13 use warnings;
  3         5  
  3         163  
4              
5             package Mxpress::PDF {
6             BEGIN {
7 3     3   9 our $VERSION = '0.28';
8 3         71 our $AUTHORITY = 'cpan:LNATION';
9             };
10 3     3   2022 use Zydeco;
  3         1042033  
  3         35  
11 3     3   93186 use Colouring::In;
  3         39439  
  3         15  
12 3     3   188 use constant mm => 25.4 / 72;
  3         7  
  3         227  
13 3     3   16 use constant pt => 1;
  3         7  
  3         638  
14 3     3   876520 class File (HashRef $args) {
  3         7  
  3         30  
  2         28  
  2         4  
15 2 50       28 my @plugins = (qw/font list border line box circle pie ellipse text title subtitle subsubtitle h1 h2 h3 h4 h5 h6 toc image form input textarea select annotation cover/, ($args->{plugins} ? @{$args->{plugins}} : ()));
  0         0  
16 2         6 for my $p (@plugins) {
17 52         845 my $meth = sprintf('_store_%s', $p);
  52         57  
18 52         55 has {$meth} (is => 'rw', type => Object);
  52         182  
  52         896  
19             method {$p} () {
20 52   33 0 0 346 my $klass = $self->$meth;
  765   0 171 0 1771  
  765   66 39 0 2745  
  765   66 0 0 1326  
  0   0 5 0 0  
  0   66 0 0 0  
  0   0 0 0 0  
  0   0 0 0 0  
  171   0 0 0 544  
  171   0 0 0 550  
  171   0 0 0 1685  
  171   0 0 0 1799  
  39   0 0 0 479  
  39   0 0 0 151  
  39   0 1 0 934  
  39   33 0 0 425  
  0   0 0 0 0  
  0   0 0 0 0  
  0   0 0 0 0  
  0   0 0 0 0  
  5   0 54 0 32  
  5   66 66 0 21  
  5   66 242 0 413  
  5   66 0 0 40  
  0   0 84 0 0  
  0   66 103 0 0  
  0   66     0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  1         14  
  1         9  
  1         384  
  1         9  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  54         541  
  54         175  
  54         859  
  54         513  
  66         677  
  66         240  
  66         893  
  66         667  
  242         1710  
  242         667  
  242         1315  
  242         1974  
  0         0  
  0         0  
  0         0  
  0         0  
  84         765  
  84         267  
  84         648  
  84         806  
  103         7982  
  103         519  
  103         931  
  103         1178  
21 765         13900 if (!$klass) {
22 765 100       6123 $klass = $class->FACTORY->$p($self, %{$args->{$p}});
23 11         245 $self->$meth($klass);
  11         130  
24 11         95270 }
25             return $klass;
26 765         6282 }
27 52         59 }
  2         31  
28 2         23 has file_name (is => 'rw', type => Str, required => 1);
  2         40  
29 2         14 has pdf (required => 1, is => 'rw', type => Object);
  2         37  
30 2         15 has pages (required => 1, is => 'rw', type => ArrayRef);
  2         51  
31 2         11 has page (is => 'rw', type => Object);
  2         34  
32 2         17 has page_args (is => 'rw', type => HashRef);
  2         52  
33 2         12 has onsave_cbs (is => 'rw', type => ArrayRef);
  2         81  
34 2         19 has page_offset (is => 'rw', type => Num);
  2         41  
35             method add_page (Map %args) {
36 140 50 33 140 0 430 $args{is_rotated} = 0;
  140   66     690  
  140         515  
  140         589  
  140         493  
  140         100851  
  140         844  
  140         3162  
  140         3134  
37 140         565 if ($self->page) {
38 140 100       2702 unless ($args{force_new_page}) {
39 138 100       1287 my $border = $self->border->active;
40 136         838 $self->border->end if $border;
41 136 50       579 my $next = $self->page->next_column();
42 136         1891 $next = $self->page->next_row() if !$next;
43 136 100       1229 if ($border) {
44 136 50       473 $self->border->start if $next;
45 0 0       0 $self->border->active(1);
46 0         0 }
47             return if $next;
48 136 100       574 }
49             $args{h_offset} = $self->page->h_offset;
50 37         495 $args{is_rotated} = $self->page->is_rotated;
51 37         1322 $args{columns} = $self->page->columns;
52 37         1282 }
53             my $border = $self->{_store_border} && $self->border->active;
54 39   66     904 $self->border->end if $border;
55 39 50       123  
56             my @attrs = qw/active padding show_page_num page_num_text onsave_cbs x y w h background columns column rows row row_y/;
57 39         402 my $page = $self->FACTORY->page(
58             $self->pdf,
59             page_size => 'A4',
60             %{ $self->page_args },
61 39 100       733 ($self->page ? (
  39         1443  
62             num => $self->page->num + 1,
63             header => $self->page->header->attrs(@attrs),
64             footer => $self->page->footer->attrs(@attrs)
65             ) : ()),
66             %args,
67             );
68             push @{$self->pages}, $page;
69 39         191 $self->page($page);
  39         734  
70 39         869 $self->box->add( fill_colour => $page->background, full => \1 ) if $page->background;
71 39 50       1578 $self->page->set_position($page->parse_position([]));
72 39         888 $self->border->start if $border;
73 39 50       120 $self;
74 39         295 }
  2         32  
75 2         39 method save {
76 1   33 1 0 3 $self->_handle_on_save;
  1         6  
  1         3  
  1         154  
77 1         7 $self->pdf->saveas();
78 1         17 $self->pdf->end();
79 1         2690450 }
  2         29  
80 2         25 method stringify {
81 0   0 0 0 0 $self->_handle_on_save;
  0         0  
  0         0  
  0         0  
82 0         0 my $string = $self->pdf->stringify();
83 0         0 $self->pdf->end();
84 0         0 return $string;
85 0         0 }
  2         30  
86 2         23 method _handle_on_save {
87 1   33 1   2 my @pages = @{$self->pages};
  1         4  
  1         2  
  1         4  
88 1         2 if ($self->cover->active) {
  1         24  
89 1 50       25 $self->page(shift @pages);
90 1         23 $self->page->current($self->pdf->openpage(1));
91 1         38 $self->cover->run_onsave_cbs($self);
92 1         118 }
93             if ($self->onsave_cbs) {
94 1 50       23 for my $cb (@{$self->onsave_cbs}) {
95 1         7 my ($plug, $meth, $args) = @{$cb};
  1         15  
96 1         5 $self->$plug->$meth(%{$args});
  1         4  
97 1         5 }
  1         5  
98             }
99             for my $page (@pages) {
100 1         21 $page->num($page->num + ($self->page_offset || 0));
101 35   50     489 $page->current($self->pdf->openpage($page->num));
102 35         2406 $self->page($page)->run_onsave_cbs($self);
103 35         3592 }
104 2         29 }
105 2         28 method onsave (Str $plug, Str $meth, Map %args) {
106 1 50 33 1 0 4 # todo role onsave
  1   33     5  
  1         4  
  1         5  
  1         3  
  1         11  
  1         11  
  1         1320  
  1         25  
107             my $cbs = $self->onsave_cbs || [];
108 1   50     25 push @{$cbs}, [$plug, $meth, \%args];
109 1         14 $self->onsave_cbs($cbs);
  1         4  
110 1         15 }
  2         30  
111 2         32 method mmp (Num $mm) {
112 2   33 2 0 6 return $mm/mm
  2   66     6  
  2         3  
  2         1025  
  2         16  
  2         864  
  2         23  
113 2         20 }
114 3     3   2297168 }
  3     3   15  
  3         48  
  2         1514  
  2         29  
  3         1628  
  3         7  
  3         11  
115 3     3   305735 class Page {
  3         38  
  3         30  
  3         39  
  0         0  
116 3         26 with Utils;
  3         67  
117 3         18 has page_size (is => 'rw', type => Str, required => 1);
  3         62  
118 3         14 has background (is => 'rw', type => Str);
  3         51  
119 3         24 has num (is => 'rw', type => Num, required => 1);
  3         53  
120 3         17 has current (is => 'rw', type => Object);
  3         65  
121 3         13 has columns (is => 'rw', type => Num);
  3         48  
122 3         13 has column (is => 'rw', type => Num);
  3         60  
123 3         15 has rows (is => 'rw', type => Num);
  3         47  
124 3         12 has row (is => 'rw', type => Num);
  3         51  
125 3         15 has row_y (is => 'rw', type => Num);
  3         48  
126 3         13 has is_rotated (is => 'rw', type => Num);
  3         50  
127 3         37 has header (is => 'rw', type => HashRef|Object);
  3         11166  
128 3         29 has footer (is => 'rw', type => HashRef|Object);
  3         535  
129 3         22 has x (is => 'rw', type => Num);
  3         56  
130 3         20 has y (is => 'rw', type => Num);
  3         53  
131 3         16 has w (is => 'rw', type => Num);
  3         48  
132 3         16 has h (is => 'rw', type => Num);
  3         54  
133 3         16 has oh (is => 'rw', type => Num);
  3         53  
134 3         13 has ow (is => 'rw', type => Num);
  3         48  
135 3         22 has saving (is => 'rw', type => Bool);
  3         49  
136 3         23 has onsave_cbs (is => 'rw', type => ArrayRef);
  3         75  
137             factory page (Object $pdf, Map %args) {
138 39 50 66 39 1 161 my $page = $args{open} ? $pdf->openpage($args{num}) : $pdf->page($args{num} || 0);
  39         137  
  39         276  
  39         86  
  39         4844  
  39         161  
  39         2190  
  39         1177  
139 39 50 100     488 $page->mediabox($args{page_size});
140 39         34475 my ($blx, $bly, $trx, $try) = $page->get_mediabox;
141 39         5813 @args{qw/x y w h oh ow/} = $args{is_rotated} ? (
142             0, $trx, $try, $trx, $trx, $try
143 39 100       2118 ) : (
144             0, $try, $trx, $try, $try, $trx
145             );
146             $args{num} ||= 1;
147 39   100     173 my $new_page = $class->new(
148 39         1267 current => $page,
149             padding => 0,
150             columns => 1,
151             column => 1,
152             rows => 1,
153             row => 1,
154             h_offset => 0,
155             %args
156             );
157             for (qw/header footer/) {
158 39         36905 $new_page->$_($factory->$_(
159             parent => $new_page,
160             %{$args{$_}},
161 78         1189 ));
  78         707  
162             }
163             return $new_page;
164 39         36443 }
  3         63  
165 3         57 method onsave (Str $plug, Str $meth, Any @args) {
166 3 50 33 3 0 8 my $cbs = $self->onsave_cbs || [];
  3   66     10  
  3         7  
  3         9  
  3         4  
  3         7  
  3         13  
  3         3132  
  3         57  
167 3   100     75 push @{$cbs}, [$plug, $meth, @args];
168 3         22 $self->onsave_cbs($cbs);
  3         9  
169 3         43 }
  3         52  
170 3         44 method run_onsave_cbs (Object $file) {
171 106   33 106 0 188 $self->saving(\1);
  106   66     292  
  106         139  
  106         911  
  106         225  
  106         872  
  106         953  
172 106         1682 if ($self->onsave_cbs) {
173 106 100       4980 for my $cb (@{$self->onsave_cbs}) {
174 71         381 my ($plug, $meth, @args) = @{$cb};
  71         855  
175 71         333 $file->$plug->$meth(@args);
  71         202  
176 71         187 }
177             }
178             $self->header->run_onsave_cbs($file) if $self->header && $self->header->active;
179 106 100 66     2442 $self->footer->run_onsave_cbs($file) if $self->footer && $self->footer->active;
180 106 100 66     1971 return $file;
181 106         826 }
  3         42  
182 3         37 method rotate {
183 1   33 1 0 3 my ($blx, $bly, $trx, $try) = $self->current->get_mediabox;
  1         4  
  1         3  
  1         4927  
184 1         20 $self->current->mediabox(
185 1         86 $self->x(0),
186             0,
187             $self->w($try),
188             $self->h($self->y($trx)),
189             );
190             $self->set_position($self->parse_position([]));
191 1         292 $self->is_rotated(!$self->is_rotated);
192 1         16 return $self;
193 1         32 }
  3         41  
194 3         31 method next_column {
195 136   33 136 0 319 if ($self->column < $self->columns) {
  136         669  
  136         226  
  136         1580  
196 136 100       2478 my $fh = !!$self->footer->active ? $self->footer->h : 0;
197 67 50       2615
198             $self->y($self->row_y ? $self->row_y : ($self->h + (($self->padding*2)/mm) + $fh));
199 67 100       5275 $self->column($self->column + 1);
200 67         5078 return 1;
201 67         2168 }
202             return;
203 69         1742 }
  3         86  
204 3         32 method next_row {
205 69   33 69 0 160 if ($self->row < $self->rows) {
  69         300  
  69         124  
  69         719  
206 69 100       1246 my $fh = $self->footer->active ? $self->header->h : 0;
207 34 50       1354 my ($blx, $bly, $trx, $try) = $self->current->get_mediabox;
208 34         2654 my $row_height = ($self->h + (($self->padding*2)/mm)) / $self->rows;
209 34         3220 my $offset = int($try - $fh - ($row_height * ($self->row)));
210 34         1748 $self->row_y($self->y($offset));
211 34         645 $self->column(1);
212 34         2595 $self->row($self->row + 1);
213 34         1379 return 1;
214 34         1159 }
215             return;
216 35         921 }
  3         45  
217 3         42 method attrs (Any @attrs) {
218 74 50 33 74 0 170 return {
  74   66     217  
  74         240  
  74         249  
  74         139  
  74         10501  
  74         246  
  74         5496  
  74         1112  
219             map +($_ => $self->$_), grep { defined $self->$_ } @attrs
220 74         120 }
  1110         19544  
221 3         64 }
222 3         42 method hf_offset {
223 1   33 1 0 2 return ($self->header->active ? $self->header->h : 0 ) + ($self->footer->active ? $self->footer->h : 0);
  1         5  
  1         2  
  1         86  
224 1 50       14 }
    50          
225 3     3   5094561 class Page::Component {
  3         8  
  3         57  
  3         40  
  0         0  
  3         36  
226 3         26 has parent (is => 'rw', type => Object);
  3         85  
227 3         29 has show_page_num (is => 'rw', type => Str);
  3         55  
228 3         28 has page_num_text (is => 'rw', type => Str);
  3         50  
229 3         24 has active (is => 'rw', type => Bool);
  3         54  
230             method add (Map %args) {
231 4 50 33 4 0 10 if ($args{cb}) {
  4   66     14  
  4         16  
  4         15  
  4         6  
  4         13  
  4         18  
  4         840  
  4         68  
232 4 100       13 $self->onsave(@{ delete $args{cb} });
233 3         5 }
  3         28  
234             $self->set_attrs(%args);
235 4         100 if (!$self->active) {
236 4 100       295 $self->activate();
237 3         41 # $self->parent->h_offset($self->parent->h_offset + $self->h);
238             }
239             return $self->parent;
240 4         79 }
  3         70  
241 3         47 method set_position () {
242 141   33 141 0 254 my $p = $self->padding/mm;
  141   66     311  
  141         182  
  141         289  
  141         290  
  141         668  
  141         906  
243 141         2047 $self->parent->set_position(
244 141 50       2400 ($self->x > 100 ? ($self->x - $p) : ($self->x + $p)),
    100          
245             ($self->y > 100 ? ($self->y - $p) : ($self->y + $p)),
246             ($self->w - $p),
247             $self->h
248             );
249 3         43 }
250 3         36 method process_page_num_text {
251 70   33 70 0 111 if ($self->page_num_text) {
  70         174  
  70         85  
  70         162  
252 70 100       954 (my $text = $self->page_num_text) =~ s/\{(.*)\}/$self->$1/eg;
253 35         579 return $text;
  35         707  
254 35         651 }
255             return $self->parent->num;
256 35         584 }
  3         54  
257 3         29 method activate () {
258 37   33 37 0 117 $self->active(\1);
  37   66     135  
  37         68  
  37         3500  
  37         129  
  37         566  
  37         415  
259 37         613 return $self;
260 37         1730 }
  3         41  
261 3         30 around run_onsave_cbs (Object $file) {
262 71   33     9440 $self->set_position();
  71         197  
  71         92  
263 71         199 $file->page->padding($self->padding);
264 71         1073 $file->page->column($self->column || 1);
265 71   100     3503 $file->page->columns($self->columns || 1);
266 71   100     4407 $file->page->row($self->row || 1);
267 71   100     4235 $file->page->rows($self->rows || 1);
268 71   100     4329 $self->$next($file);
269 71         3562 if ($self->show_page_num) {
270 71 100       943 $self->set_position();
271 70         484 $file->text->add($self->process_page_num_text, align => $self->show_page_num);
272 70         219 }
273 3         64 }
274 3     3   1289354 class Page::Component::Cover {
  3         8  
  3         26  
  3         71  
  3         45  
275 3         26 has file (is => 'rw', type => Object);
  3         108  
276             factory cover (Object $file, Map %args) {
277 1 50 33 1 1 4 $args{$_} //= $file->page->$_ for qw/x y w h padding oh ow column columns row rows num page_size/;
  1         4  
  1         5  
  1         2  
  1         5  
  1         9  
  1         1025  
  1         19  
278 1   66     29 return $class->new(
279 1         321 file => $file,
280             parent => $file->page,
281             current => $file->page->current,
282             %args
283             );
284 3         71 }
285 3         55 method end {
286 1   33 1 0 2 $self->file->page($self->parent);
  1         5  
  1         1  
  1         4  
287 1         31 $self->file->add_page(force_new_page => 1);
288 1         75 return $self->file;
289 1         17 }
  3         59  
290 3         35 around add {
291 2   33     48 $self->file->page($self);
  2         11  
  2         2  
292 2         46 $self->$next(@_);
293 2         103 return $self->file;
294 2         42 }
295 3     3   561841 }
  3     3   6  
  3         47  
  3         26  
  3         1326  
  3         6  
  3         23  
  3         4  
296 3     3   21960 class Page::Component::Header {
  3         31  
  3         27  
  3         67  
297             factory header (Map %args) {
298 39 50 66 39 1 143 $args{$_} //= $args{parent}->$_ for qw/num page_size/;
  39         156  
  39         280  
  39         94  
  39         164  
  39         136  
  39         1897  
  39         944  
299 39   33     1036 $args{x} //= 0;
300 39   100     1288 $args{w} //= $args{parent}->ow;
301 39   66     200 $args{y} //= $args{parent}->oh + ($args{parent}->padding/mm);
302 39   66     182 $args{h} //= 10/mm;
303 39   100     216 $args{padding} //= 10;
304 39   100     139 my $head = $class->new(onsave_cbs => [], %args);
305 39         799 $head->activate if !!$head->active;
306 39 100       59513 return $head;
307 39         825 }
  3         95  
308 3         52 before activate {
309 35   33     1114 $self->parent->y($self->parent->oh - $self->h);
  35         155  
  35         100  
310 35         611 }
311 3     3   288730 }
  3     3   6  
  3         51  
  3         29  
  3         1242  
  3         6  
  3         13  
312 3     3   15933 class Page::Component::Footer {
  3         6  
  3         22  
  3         62  
313             factory footer (Map %args) {
314 39 50 66 39 1 249 $args{$_} //= $args{parent}->$_ for qw/num page_size/;
  39         195  
  39         244  
  39         89  
  39         166  
  39         147  
  39         1897  
  39         872  
315 39   33     907 $args{x} //= 0;
316 39   100     1096 $args{w} //= $args{parent}->ow;
317 39   66     180 $args{y} //= (5/mm);
318 39   100     163 $args{h} //= (10/mm);
319 39   100     140 $args{padding} //= 10;
320 39   100     157 return $class->new(onsave_cbs => [], %args);
321 39         815 }
322 3     3   93386 }
  3     3   6  
  3         48  
  3         40  
  3         1305  
  3         7  
  3         13  
323 3     3   206 }
  3     3   5  
  3         26  
  3         829  
  3         6  
  3         10  
324 3     3   304 }
  3     3   6  
  3         28  
  3         1082  
  3         5  
  3         10  
325 3     3   214685 role Utils {
  3         7  
  3         34  
  3         75  
326 3         29 has full (is => 'rw', type => Bool);
  3         115  
327 3         29 has padding (is => 'rw', type => Num);
  3         61  
328 3         18 has margin_top (is => 'rw', type => Num);
  3         69  
329 3         18 has margin_bottom (is => 'rw', type => Num);
  3         56  
330 3         18 has h_offset (is => 'rw', type => Num);
  3         56  
331             method add_padding (Num $padding) {
332 0   0 0 0 0 $self->padding($self->padding + $padding);
  0   0     0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
333 0         0 }
  3         64  
334 3         51 method set_position (Num $x, Num $y, Num $w, Num $h) {
335 182   33 182 0 463 my $page = $self->can('file') ? $self->file->page : $self;
  182   66     575  
  182         230  
  182         13119  
  182         400  
  182         3562  
  182         3801  
336 182 100       688 $page->x($x);
337 182         2778 $page->y($y);
338 182         6214 $page->w($w);
339 182         5772 $page->h($h);
340 182         6122 return ($x, $y, $w, $h);
341 182         3985 }
  3         49  
342 3         41 method parse_position (ArrayRef $position, Bool $xy?) {
343 762   33 762 0 1962 my ($x, $y, $w, $h) = map {
  762   66     2213  
  762         1223  
  762         30413  
  762         2365  
  762         4948  
  762         10490  
344             $_ =~ m/[^\d\.]/ ? $_ : $_/mm
345 156 50       561 } @{$position};
346 762         1265 my $file = $self->can('file');
  762         1922  
347 762         3459 my $page = $file ? $self->file->page : $self;
348 762 100       10709 my $sp = $self->padding/mm;
349 762         24058 my $pp = $page->padding/mm;
350 762         13458 $x //= ($page->x + $sp);
351 762   100     14711 $y //= ($page->y - $sp);
352 762   66     15778 $w //= ($page->w - $sp);
353 762   66     15894 $h //= ($page->oh - ($page->oh - $y) - ($sp + $pp));
354 762   66     15615 $h = ((!$page->footer || !$page->footer->active) ? $h : $page->footer->saving ? ($h + $sp + $pp) : $h > $page->footer->h ? ($h - $page->footer->h) : 0);
355 762 100 100     19352 if ($file) {
    100          
    100          
356 762 100       93031 if ($page->columns > 1 && !$self->full) {
357 620 100 100     8667 $w = ($page->w / $page->columns);
358 438         16687 $x += ($w * ($page->column - 1));
359 438         14172 $w -= $sp;
360 438         3191 }
361             $w -= ($pp + $sp);
362 620         2735 if ($page->rows > 1 && !$self->full) {
363 620 100 100     8649 my $hh = $page->header && $page->header->active ? $page->header->h :0;
364 438 50 33     16471 my $fh = $page->footer && $page->footer->active ? $page->footer->h : 0;
365 438 50 33     33866 $h = ($page->h + ($pp*2)) / $page->rows;
366 438         31916 $h -= ((($page->h + ($pp*3)) - $y) - ($h * ($page->row - 1)));
367 438         13620 $h -= $fh;
368 438         10295 if ($page->row > 1 && $page->y == $page->row_y) {
369 438 100 100     5484 $y -= $pp;
370 67         2655 $h -= $pp;
371 67         140 }
372             }
373             $h -= $sp;
374 620         8082 }
375             return $xy ? ($x, $y) : ($x, $y, $w, $h);
376 762 50       4169 }
  3         49  
377 3         60 method set_y (Num $y) {
378 447   33 447 0 1183 $y -= ($self->margin_bottom/mm) if $self->margin_bottom;
  447   66     1410  
  447         754  
  447         1186  
  447         1227  
  447         2152  
  447         6074  
379 447 50       7501 my $page = $self->can('file') ? $self->file->page : $self;
380 447 50       9625 return $page->y($y);
381 447         13852 }
  3         48  
382 3         38 method valid_colour (Str $css) {
383 111   33 111 0 349 return Colouring::In->new($css)->toHEX(1);
  111   66     417  
  111         218  
  111         1357  
  111         459  
  111         1692  
  111         1744  
384 111         740 }
  3         47  
385 3         32 method set_attrs (Map %args) {
386 828 50 33 828 0 1917 $self->can($_) && $self->$_($args{$_}) for keys %args;
  828   66     2319  
  828         2139  
  828         2514  
  828         1177  
  828         2062  
  828         1946  
  828         3903  
  828         11399  
387 828   66     7436 }
  3         47  
388 3         35 method _recurse_find {
389 86   33 86   193 my ($self, $check, $recurse, $val, @items) = @_;
  86         304  
  86         177  
  86         1144  
390 86         500 for (@items) {
391 86         190 if (defined $_->$check && $_->$check =~ $val) {
392 113 100 66     2000 return $_;
    100 50        
393 59         1937 } elsif ($_->$recurse && scalar @{$_->$recurse}) {
394 54         3311 my $val = $self->_recurse_find($check, $recurse, $val, reverse @{$_->$recurse});
395 26         195 return $val if $val;
  26         349  
396 26 50       148 }
397             }
398             return undef;
399 1         8 }
400 3     3   1967921 }
  3     3   7  
  3         52  
  3         25  
  3         1366  
  3         6  
  3         13  
401 3     3   1317203 class Plugin {
  3         7  
  3         33  
  3         44  
  0         0  
402 3         14 with Utils;
  3         73  
403 3         20 has file (is => 'rw', type => Object);
  3         62  
404 3         20 has position (is => 'rw', type => ArrayRef);
  3         70  
405 3     3   448148 class Plugin::Font {
  3         9  
  3         29  
  3         83  
406 3         27 has colour (is => 'rw', type => Str);
  3         145  
407 3         26 has size (is => 'rw', type => Num);
  3         62  
408 3         16 has family (is => 'rw', type => Str);
  3         81  
409 3         25 has loaded (is => 'rw', type => HashRef);
  3         83  
410 3         16 has line_height ( is => 'rw', type => Num);
  3         68  
411             factory font (Object $file, Map %args) {
412 107 50 66 107 1 389 return $class->new(
  107         366  
  107         518  
  107         182  
  107         447  
  107         461  
  107         1493  
  107         2569  
413             file => $file,
414             colour => $file->page->valid_colour($args{colour} || '#000'),
415             size => 9,
416             line_height => $args{size} || 9,
417 107   50     2184 family => 'Times',
      100        
418             %args
419             );
420 3         74 }
421 3         57 method load () { $self->find($self->family); }
  3         57  
422 3   33 580 0 37 method find (Str $family, Str $enc?) {
  580   66     1408  
  580         1849  
  580         909  
  580         9325  
  580         4996  
  580         1735  
  580         2120  
  580         5196  
423 580   33 580 0 1558 my $loaded = $self->loaded;
  580   66     1969  
  580         1025  
  580         4806  
  580         1334  
  580         2780  
  580         8333  
424 580         9006 unless ($loaded->{$family}) {
425 580 100       4580 $loaded->{$family} = $self->file->pdf->corefont($family, -encoding => $enc || 'latin1');
426 107   50     1482 $self->loaded($loaded);
427 107         2609171 }
428             return $loaded->{$family};
429 580         13789 }
430 3     3   1390399 }
  3     3   8  
  3         50  
  3         29  
  3         1370  
  3         6  
  3         12  
  3         5  
431 3     3   222198 class Plugin::Shape {
  3         9  
  3         34  
  3         41  
  0         0  
432 3         24 has fill_colour ( is => 'rw', type => Str );
  3         84  
433 3         20 has radius ( is => 'rw', type => Num );
  3         57  
434 3         14 has start (is => 'rw', type => Num);
  3         50  
435 3         13 has end (is => 'rw', type => Num);
  3         50  
436             method generic_new (Object $file, Map %args) {
437 2 50 33 2 0 7 return $class->new(
  2   33     9  
  2         6  
  2         13  
  2         5  
  2         10  
  2         19  
  2         2026  
  2         38  
438             padding => $args{padding} || 0,
439             %args,
440             file => $file,
441             fill_colour => $file->page->valid_colour($args{fill_colour} || '#fff'),
442 2   50     55 );
      50        
443 3         49 }
444 3         53 method add (Map %args) {
445 39 50 33 39 0 119 $self->set_attrs(%args);
  39   66     180  
  39         189  
  39         177  
  39         66  
  39         414  
  39         148  
  39         1822  
  39         800  
446 39         214 my $shape = $self->file->page->current->gfx;
447 39         4309 $self->shape($shape);
448 39         11214 return $self->file;
449 39         1965 }
  3         46  
450 3     3   1200973 class Plugin::Shape::Line {
  3         9  
  3         31  
  3         40  
  0         0  
  3         42  
451 3         16 has end_position (is => 'rw');
  3         54  
452 3         26 has type (is => 'rw', type => Str);
  3         89  
453 3         17 has dash (is => 'rw', type => ArrayRef);
  3         67  
454 3         21 has join (is => 'rw', type => Num);
  3         51  
455             factory line (Object $file, Map %args) {
456 0 0 0 0 1 0 $args{line_join} ||= 2;
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
457 0   0     0 $args{line_type} ||= 'solid';
458 0   0     0 $class->generic_new($file, %args);
459 0         0 }
  3         54  
460 3         37 method shape (Object $shape) {
461 0   0 0 0 0 $shape->strokecolor($self->fill_colour);
  0   0     0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
462 0         0 my ($x, $y, $w, $h) = $self->parse_position($self->position || []);
463 0   0     0 $shape->move($x, $y);
464 0         0 ($x, $y) = $self->end_position ? $self->parse_position($self->end_position) : ($x + $w, $y);
465 0 0       0 if ($self->dash) {
466 0 0       0 $shape->linedash(@{$self->dash});
    0          
    0          
467 0         0 } elsif ($self->type eq 'dots') {
  0         0  
468             $shape->linedash(1, 1);
469 0         0 } elsif ($self->type eq 'dashed') {
470             $shape->linedash(5, 5);
471 0         0 }
472             $shape->linejoin($self->join);
473 0         0 $shape->line($x, $y);
474 0         0 $shape->stroke;
475 0         0 }
476 3     3   1169404 class Plugin::Shape::Line::Border {
  3         10  
  3         26  
  3         67  
  3         39  
477 3         23 has border_top (is => 'rw', type => ArrayRef);
  3         129  
478 3         20 has active (is => 'rw');
  3         46  
479             factory border (Object $file, Map %args) {
480 2 50 33 2 1 8 return $class->new(
  2         10  
  2         7  
  2         3  
  2         9  
  2         21  
  2         2220  
  2         37  
481             file => $file,
482             padding => 0,
483             fill_colour => $file->page->valid_colour($args{fill_colour} || '#fff'),
484 2   50     48 %args
485             );
486 3         73 }
487 3         53 method start (Map %args) {
488 0 0 0 0 0 0 if (!$args{border_top}) {
  0   0     0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
489 0 0       0 my $y = $self->file->page->y*mm;
490 0         0 if ($self->file->page->row > 1) {
491 0 0       0 $y -= $self->file->page->padding * ($self->file->page->row - 1);
492 0         0 }
493             $args{border_top} = [
494             $self->file->page->x*mm,
495 0         0 $y,
496             $self->file->page->w*mm
497             ];
498             }
499             $args{active} = 1;
500 0         0 $self->set_attrs(%args);
501 0         0 return $self->file;
502 0         0 }
  3         61  
503 3         59 method end (Map %args) {
504 0 0 0 0 0 0 $args{active} = 0;
  0   0     0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
505 0         0 $self->set_attrs(%args);
506 0         0 my $tx = $self->border_top->[0];
507 0         0 my $ty = $self->border_top->[1];
508 0         0 my ($bx, $by, $w) = map { $_*mm } $self->parse_position([]);
509 0         0 $self->add(
  0         0  
510 0         0 position => [$tx, $ty],
511             end_position => [$tx + $w, $ty]
512             );
513            
514             $self->add(
515 0         0 position => [$tx, $by],
516             end_position => [$tx + $w, $by]
517             );
518              
519             $self->add(
520 0         0 position => [$tx, $ty],
521             end_position => [$tx, $by],
522             );
523            
524             my $r = $tx + $w;
525 0         0 $self->add(
526 0         0 position => [$r, $ty],
527             end_position => [$r, $by],
528             );
529            
530             return $self->file;
531 0         0 }
532 3     3   737739 }
  3     3   7  
  3         48  
  3         27  
  3         1249  
  3         5  
  3         12  
533              
534 3     3   181 }
  3     3   7  
  3         25  
  3         813  
  3         5  
  3         11  
  3         4  
535 3     3   14041 class Plugin::Shape::Box {
  3         6  
  3         17  
  3         64  
536             factory box (Object $file, Map %args) {
537 2 50 33 2 1 8 return $class->generic_new($file, %args);
  2         8  
  2         6  
  2         4  
  2         9  
  2         21  
  2         2141  
  2         38  
538 2         34 }
  3         96  
539 3         47 method shape (Object $shape) {
540 39   33 39 0 111 my $box = $shape->rect(
  39   66     130  
  39         95  
  39         115  
  39         147  
  39         1414  
  39         607  
541 39   50     895 $self->parse_position(
542             $self->position || [0, 0, $self->file->page->w, $self->file->page->h]
543             )
544             );
545             $box->fillcolor($self->fill_colour);
546 39         6592 $box->fill;
547 39         5697 }
548 3     3   241383 }
  3     3   6  
  3         45  
  3         38  
  3         1254  
  3         6  
  3         11  
  3         6  
549 3     3   20147 class Plugin::Shape::Circle {
  3         8  
  3         19  
  3         64  
550             factory circle (Object $file, Map %args) {
551 0 0 0 0 1 0 $args{radius} ||= 50;
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
552 0   0     0 return $class->generic_new($file, %args);
553 0         0 }
  3         94  
554 3         47 method shape (Object $shape) {
555 0   0 0 0 0 my ($x, $y, $r) = $self->parse_position(
  0   0     0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
556 0   0     0 $self->position || [
557             ($self->file->page->x*mm) + $self->radius,
558             ($self->file->page->y*mm) - $self->radius,
559             ]
560             );
561             my $circle = $shape->circle(
562 0         0 $x, $y, $self->radius/mm
563             );
564             $circle->fillcolor($self->fill_colour);
565 0         0 $circle->fill;
566 0         0 }
567 3     3   248109 }
  3     3   5  
  3         45  
  3         32  
  3         1202  
  3         5  
  3         11  
  3         5  
568 3     3   23611 class Plugin::Shape::Pie {
  3         9  
  3         22  
  3         67  
569             factory pie (Object $file, Map %args) {
570 0 0 0 0 1 0 $args{radius} ||= 50;
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
571 0   0     0 $args{start} ||= 180;
572 0   0     0 $args{end} ||= 135;
573 0   0     0 return $class->generic_new($file, %args);
574 0         0 }
  3         95  
575 3         51 method shape (Object $shape) {
576 0   0 0 0 0 my ($x, $y, $r) = $self->parse_position($self->position || [
  0   0     0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
577 0   0     0 ($self->file->page->x*mm) + $self->radius,
578             ($self->file->page->y*mm) - $self->radius,
579             $self->radius,
580             ]);
581             my $pie = $shape->pie($x, $y, $r, $r, $self->start, $self->end);
582 0         0 $pie->fillcolor($self->fill_colour);
583 0         0 $pie->fill;
584 0         0 }
585 3     3   251068 }
  3     3   8  
  3         45  
  3         32  
  3         1285  
  3         5  
  3         13  
586 3     3   22115 class Plugin::Shape::Ellipse {
  3         5  
  3         26  
  3         67  
587             factory ellipse (Object $file, Map %args) {
588 0 0 0 0 1 0 $args{start} ||= 50;
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
589 0   0     0 $args{end} ||= 100;
590 0   0     0 return $class->generic_new($file, %args);
591 0         0 }
  3         98  
592 3         45 method shape (Object $shape) {
593 0   0 0 0 0 my ($x, $y) = $self->parse_position($self->position || [
  0   0     0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
594 0   0     0 ($self->file->page->x*mm) + $self->start,
595             ($self->file->page->y*mm) - ($self->end / 2),
596             ]);
597             my $ellipse = $shape->ellipse($x, $y, $self->start, $self->end);
598 0         0 $ellipse->fillcolor($self->fill_colour);
599 0         0 $ellipse->fill;
600 0         0 }
601 3     3   253925 }
  3     3   9  
  3         44  
  3         31  
  3         1253  
  3         6  
  3         13  
602 3     3   185 }
  3     3   7  
  3         23  
  3         826  
  3         6  
  3         12  
  3         4  
603 3     3   381740 class Plugin::Text {
  3         7  
  3         32  
  3         49  
  0         0  
604 3         26 has text (is => 'rw', type => Object);
  3         114  
605 3         16 has font (is => 'rw', type => Object);
  3         62  
606 3         30 has paragraph_space (is => 'rw', type => Num);
  3         60  
607 3         31 has paragraphs_to_columns (is => 'rw', type => Bool);
  3         64  
608 3         15 has first_line_indent (is => 'rw', type => Num);
  3         57  
609 3         16 has first_paragraph_indent (is => 'rw', type => Num);
  3         57  
610 3         32 has align (is => 'rw', type => Str); #enum
  3         58  
611 3         85 has margin_bottom (is => 'rw', type => Num);
  3         63  
612 3         18 has indent (is => 'rw', type => Num);
  3         57  
613 3         48 has pad (is => 'rw', type => Str);
  3         59  
614 3         16 has pad_end (is => 'rw', type => Str);
  3         55  
615 3         18 has no_space (is => 'rw', type => Bool);
  3         59  
616 3         15 has min_width (is => 'rw', type => Num);
  3         56  
617 3         17 has end_w (is => 'rw', type => Str);
  3         54  
618 3         15 has end_lw (is => 'rw', type => Str);
  3         55  
619 3         17 has concat (is => 'rw', type => Bool);
  3         62  
620 3         18 has next_page;
  3         49  
621             factory text (Object $file, Map %args) {
622 1 50 33 1 1 4 $class->generic_new($file, %args);
  1         4  
  1         4  
  1         3  
  1         4  
  1         10  
  1         1161  
  1         20  
623 1         9 }
  3         67  
624 3         48 method generic_new (Object $file, Map %args) {
625 4 50 33 4 0 15 return $class->new({
  4   66     19  
  4         14  
  4         19  
  4         8  
  4         28  
  4         21  
  4         1017  
  4         88  
626             file => $file,
627             page => $file->page,
628 4         24 next_page => do { method {
629 132   33     358 my $self = shift;
  132         540  
  132         320  
630 132         216 $file->add_page;
631 132         929 return $file->page;
632 132         2070 } },
633 4         81 min_width => 0,
634             padding => 0,
635             align => 'left',
636             font => $class->FACTORY->font(
637             $file,
638             %{$args{font}}
639 4         171 ),
640             position => $args{position} || [],
641             no_space => 0,
642             (map {
643             defined $args{$_} ? ( $_ => $args{$_} ) : ()
644 4 100 50     95 } qw/
  56         7521  
645             align margin_bottom margin_top indent align padding pad no_space pad_end first_line_indent
646             first_paragraph_indent paragrah_space paragraphs_to_columns min_width
647             /)
648             });
649 3         65 }
650 3         51 method add (Str $string, Map %args) {
651 580 50 33 580 0 1719 $self->set_attrs(%args);
  580   66     1757  
  580         1794  
  580         2113  
  580         1271  
  580         54280  
  580         2114  
  580         2976  
  580         12839  
652 580         2346 my ($xpos, $ypos);
653 580         6800 my @paragraphs = split /\n/, $string;
654 580         3408 my $columns = $self->file->page->columns;
655 580         10313 my $page_column;
656 580         21021 if ($columns == 1 && $self->paragraphs_to_columns) {
657 580 50 66     4040 @paragraphs = grep { $_ =~ m/\w/ } @paragraphs;
658 0         0 $self->file->page->columns(scalar grep { ($_ =~ m/\w/) } @paragraphs);
  0         0  
659 0         0 $page_column = 1;
  0         0  
660 0         0 }
661             my $text = $self->text($self->file->page->current->text);
662 580         8678 $text->font( $self->font->load, $self->font->size/pt );
663 580         227936 $text->fillcolor( $self->font->colour );
664 580         144682 my ($total_width, $space_width, %width) = $self->_calculate_widths($string, $text);
665 580         90578 my ($l, $x, $y, $w, $h) = (
666 580         12281 $self->font->line_height/pt,
667             $self->parse_position($self->position)
668             );
669             $ypos = $y - $l;
670 580         1351 my ($fl, $fp, @paragraph) = (1, 1, split ( / /, shift(@paragraphs) || '' ));
671 580   50     12513 # while we have enough height to add a new line
672             if ($h >= 0 && $y >= 0) {
673 580 50 33     3109 while ($ypos + 0 >= ($y - $h)) {
674 580         1582 unless (scalar @paragraph) {
675 5443 100       13955 last unless scalar @paragraphs;
676 446 50       1519 @paragraph = split( / /, shift(@paragraphs) );
677 0         0 if ($page_column) {
678 0 0       0 $page_column++;
679 0         0 $x += 50/mm;
680 0         0 $ypos = $y;
681 0         0 }
682             $ypos -= $l;
683 0         0 $ypos -= ($self->paragraph_space/mm) if $self->paragraph_space;
684 0 0       0 last unless $ypos >= ($y - $h);
685 0 0       0 ($fl, $fp) = (1, 0);
686 0         0 }
687             my ($xpos, $lw, $line_width, @line) = ($x, $w, 0);
688 4997         11631 if (!!$self->concat) {
689 4997 50       86129 $self->concat(!!0);
690 0         0 $xpos = $self->end_w + $text->advancewidth(' ');
691 0         0 $ypos = $y;
692 0         0 $lw = $self->end_lw - $text->advancewidth(' ');
693 0         0 } else {
694             ($xpos, $lw) = $self->_set_indent($xpos, $lw, $fl, $fp);
695 4997         44978 }
696             while (@paragraph and ($line_width + (scalar(@line) * $space_width) + ($width{$paragraph[0]}||0)) < $lw) {
697 4997   50     33243 $line_width += $width{$paragraph[0]} || 0;
      100        
698 52055   50     81825 push @line, shift(@paragraph);
699 52055         159775 }
700             if (!@line && @paragraph) {
701 4997 50 33     12113 my $temp = shift(@paragraph);
702 0         0 my @letters = split //, $temp;
703 0         0 my ($wid, $lin) = (0, '');
704 0         0 while ($wid < $lw) {
705 0         0 my $letter = shift @letters;
706 0         0 $wid += $text->advancewidth($letter);
707 0         0 $lin .= $letter;
708 0         0 }
709             $width{$lin} = $wid;
710 0         0 my $rest = join '', @letters;
711 0         0 $width{$rest} = $text->advancewidth($rest);
712 0         0 $line_width += $wid;
713 0         0 push @line, $lin;
714 0         0 unshift(@paragraph, $rest);
715 0         0 }
716             my ($wordspace, $align);
717 4997         7596 if ($self->align eq 'fulljustify' or $self->align eq 'justify' and @paragraph) {
718 4997 100 100     75597 if (scalar(@line) == 1) {
      66        
719 4523 50       113793 @line = split( //, $line[0] );
720 0         0 }
721             $wordspace = ($lw - $line_width) / (scalar(@line) - 1);
722 4523         11513 $align = 'justify';
723 4523         6806 } else {
724             $align = ($self->align eq 'justify') ? 'left' : $self->align;
725 474 100       15933 $wordspace = $space_width;
726 474         7668 }
727             $line_width += $wordspace * (scalar(@line) - 1);
728 4997         10547 if ($align eq 'justify') {
729 4997 100       12792 foreach my $word (@line) {
730 4523         7471 $text->translate($xpos, $ypos);
731 50529         128300 $text->text($word);
732 50529         18911232 $width{$word} ||= $text->advancewidth($word);
733 50529   33     7259625 $xpos += ($width{$word} + $wordspace);
734 50529         102589 }
735             } else {
736             if ($align eq 'right') {
737 474 100       1346 $xpos += $lw - $line_width;
    100          
738 35         61 } elsif ($align eq 'center') {
739             $xpos += ($lw/2) - ($line_width / 2);
740 70         112 }
741             $text->translate($xpos, $ypos);
742 474         1777 my $sep = $self->no_space ? '' : ' ';
743 474 50       204176 $text->text(join($sep, @line));
744 474         5073 }
745             if (@paragraph) {
746 4997 100 66     133889 $ypos -= $l if @paragraph;
    100          
747 4551 50       12214 } elsif ($self->pad && $line_width < $lw) {
748             my $mw = $self->min_width ? $self->min_width/mm : 0;
749 101 50       2428 if ($xpos < $mw) {
750 101 50       840 $line_width = $self->end_w($mw);
751 0         0 } else {
752             $self->end_w($xpos + $line_width);
753 101         1560 }
754             my $pad_end = $self->pad_end || '';
755 101   50     4462 my $pad = sprintf ("%s%s",
756 101         1999 $self->pad x int((
757             (((($lw + $wordspace) - $line_width) - $text->advancewidth($self->pad . $pad_end)))
758             ) / $text->advancewidth($self->pad)),
759             $pad_end
760             );
761             $text->translate($xpos + ( $lw - $text->advancewidth($pad) ), $ypos) if (!$self->no_space);
762 101 50       17651 $text->text($pad);
763 101         69938 }
764             $self->end_w($xpos + $line_width);
765 4997         203557 $self->end_lw($lw - $line_width);
766 4997         229067 $fl = 0;
767 4997         136571 }
768             }
769             unshift( @paragraphs, join( ' ', @paragraph ) ) if scalar(@paragraph);
770 580 100       5577 if ($self->padding) {
771 580 50       10076 $ypos -= $self->padding/mm;
772 0         0 }
773             $self->file->page->y($ypos);
774 580         11913 $self->file->page->columns($columns);
775 580         42619 if (scalar @paragraphs && $self->next_page) {
776 580 100 66     33487 my $next_page = $self->next_page->($self);
777 134         646 return $self->add(join("\n", @paragraphs), %args);
778 134         2163 }
779             $self->set_y($ypos);
780 446         2077 return $self->file;
781 446         14734 }
  3         51  
782 3         75 method _set_indent (Num $xpos, Num $w, Num $fl, Num $fp) {
783 4997   33 4997   15176 if ($fl && $self->first_line_indent) {
  4997   66     17187  
  4997         7455  
  4997         14357  
  4997         12317  
  4997         17802  
  4997         128023  
784 4997 50 66     100159 $xpos += $self->first_line_indent/mm;
    50 33        
    100          
785 0         0 $w -= $self->first_line_indent/mm;
786 0         0 } elsif ($fp && $self->first_paragraph_indent) {
787             $xpos += $self->first_paragraph_indent/mm;
788 0         0 $w -= $self->first_paragraph_indent/mm;
789 0         0 } elsif ($self->indent) {
790             $xpos += $self->indent/mm;
791 59         3430 $w -= $self->indent/mm
792 59         984 }
793             return ($xpos, $w);
794 4997         138017 }
  3         47  
795 3         50 method _calculate_widths (Str $string, Object $text) {
796 580   33 580   1669 my @words = split /\s+/, $string;
  580   66     1845  
  580         953  
  580         1623  
  580         1702  
  580         2967  
  580         9887  
797 580         30042 # calculate width of space
798             my $space_width = $self->no_space ? 0 : $text->advancewidth(' ');
799 580 50       12281 # calculate the width of each word
800             my %width = ();
801 580         46422 my $total_width = 0;
802 580         936 foreach (@words) {
803 580         1462 next if exists $width{$_};
804 91198 100       125205 $width{$_} = $text->advancewidth($_);
805 2137         4347 $total_width += $width{$_} + $space_width;
806 2137         138913 }
807             return ($total_width, $space_width, %width);
808 580         7304 }
  3         49  
809 3     3   4887042 class Plugin::Text::Title {
  3         9  
  3         30  
  3         71  
  3         38  
810             factory title (Object $file, Map %args) {
811 1 50 33 1 1 3 $args{font}->{size} ||= 50/pt;
  1         5  
  1         5  
  1         2  
  1         4  
  1         10  
  1         1033  
  1         19  
812 1   50     7 $args{font}->{line_height} ||= 40/pt;
813 1   50     8 $class->generic_new($file, %args);
814 1         16 }
815 3     3   182148 }
  3     3   10  
  3         50  
  3         55  
  3         1427  
  3         5  
  3         16  
  3         5  
816 3     3   8229 class Plugin::Text::Subtitle {
  3         6  
  3         20  
  3         66  
817             factory subtitle (Object $file, Map %args) {
818 1 50 33 1 1 4 $args{font}->{size} ||= 25;
  1         4  
  1         4  
  1         2  
  1         4  
  1         13  
  1         1321  
  1         21  
819 1   50     8 $args{font}->{line_height} ||= 20;
820 1   50     6 $class->generic_new($file, %args);
821 1         17 }
822 3     3   176348 }
  3     3   7  
  3         51  
  3         45  
  3         1387  
  3         7  
  3         13  
  3         14  
823 3     3   8101 class Plugin::Text::Subsubtitle {
  3         8  
  3         21  
  3         80  
824             factory subsubtitle (Object $file, Map %args) {
825 1 50 33 1 1 4 $args{font}->{size} ||= 20;
  1         4  
  1         3  
  1         3  
  1         4  
  1         25  
  1         1255  
  1         19  
826 1   50     8 $args{font}->{line_height} ||= 15;
827 1   50     6 $class->generic_new($file, %args);
828 1         16 }
829 3     3   178169 }
  3     3   6  
  3         52  
  3         48  
  3         1474  
  3         8  
  3         14  
  3         5  
830 3     3   9211 class Plugin::Text::H1 {
  3         6  
  3         19  
  3         69  
831             factory h1 (Object $file, Map %args) {
832 0 0 0 0 1 0 $args{font}->{size} ||= 50/pt;
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
833 0   0     0 $args{font}->{line_height} ||= 40/pt;
834 0   0     0 $class->generic_new($file, %args);
835 0         0 }
836 3     3   177856 }
  3     3   8  
  3         52  
  3         47  
  3         1359  
  3         10  
  3         13  
  3         6  
837 3     3   9269 class Plugin::Text::H2 {
  3         8  
  3         20  
  3         73  
838             factory h2 (Object $file, Map %args) {
839 0 0 0 0 1 0 $args{font}->{size} ||= 40/pt;
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
840 0   0     0 $args{font}->{line_height} ||= 30/pt;
841 0   0     0 $class->generic_new($file, %args);
842 0         0 }
843 3     3   177314 }
  3     3   8  
  3         52  
  3         50  
  3         1522  
  3         7  
  3         13  
  3         4  
844 3     3   9242 class Plugin::Text::H3 {
  3         7  
  3         20  
  3         80  
845             factory h3 (Object $file, Map %args) {
846 0 0 0 0 1 0 $args{font}->{size} ||= 30/pt;
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
847 0   0     0 $args{font}->{line_height} ||= 20/pt;
848 0   0     0 $class->generic_new($file, %args);
849 0         0 }
850 3     3   178197 }
  3     3   8  
  3         49  
  3         47  
  3         1521  
  3         7  
  3         15  
  3         4  
851 3     3   9158 class Plugin::Text::H4 {
  3         77  
  3         23  
  3         72  
852             factory h4 (Object $file, Map %args) {
853 0 0 0 0 1 0 $args{font}->{size} ||= 25/pt;
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
854 0   0     0 $args{font}->{line_height} ||= 15/pt;
855 0   0     0 $class->generic_new($file, %args);
856 0         0 }
857 3     3   179651 }
  3     3   7  
  3         49  
  3         47  
  3         1365  
  3         8  
  3         11  
  3         7  
858 3     3   9399 class Plugin::Text::H5 {
  3         7  
  3         22  
  3         71  
859             factory h5 (Object $file, Map %args) {
860 0 0 0 0 1 0 $args{font}->{size} ||= 20/pt;
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
861 0   0     0 $args{font}->{line_height} ||= 15/pt;
862 0   0     0 $class->generic_new($file, %args);
863 0         0 }
864 3     3   179917 }
  3     3   6  
  3         49  
  3         49  
  3         1395  
  3         7  
  3         13  
865 3     3   9274 class Plugin::Text::H6 {
  3         8  
  3         20  
  3         74  
866             factory h6 (Object $file, Map %args) {
867 0 0 0 0 1 0 $args{font}->{size} ||= 15/pt;
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
868 0   0     0 $args{font}->{line_height} ||= 10/pt;
869 0   0     0 $class->generic_new($file, %args);
870 0         0 }
871 3     3   182146 }
  3     3   10  
  3         51  
  3         50  
  3         1462  
  3         7  
  3         13  
872 3     3   330 }
  3     3   10  
  3         32  
  3         1012  
  3         6  
  3         13  
  3         7  
873 3     3   102400 class Plugin::TOC::Outline extends Plugin::Text {
  3         8  
  3         28  
  3         87  
  3         6  
874 3         94 has outline (is => 'rw', type => Object);
  3         28  
  3         109  
875 3         27 has x (is => 'rw', type => Num);
  3         62  
876 3         18 has y (is => 'rw', type => Num);
  3         55  
877 3         68 has title (is => 'rw', type => Str);
  3         64  
878 3         18 has page (is => 'rw', type => Object);
  3         62  
879 3         18 has level (is => 'rw', type => Num);
  3         57  
880 3         26 has children (is => 'rw', type => ArrayRef);
  3         151  
881             factory add_outline (Object $file, Object $outline, Map %args) {
882 101 50 66 101 1 366 my ($x, $y) = $file->page->parse_position($args{position} || []);
  101         338  
  101         469  
  101         258  
  101         4629  
  101         330  
  101         1768  
  101         3175  
883 101   50     1807 $y += $args{jump_lh};
884 101         347 my $new = $outline->outline()->open()
885             ->title($args{outline_title})
886             ->dest($file->page->current, '-xyz' => [$x, $y, 0]);
887 101         559 return $class->new(
888             x => $x,
889             y => $y,
890             children => [],
891             level => $args{level} || 0,
892             title => $args{outline_title},
893             file => $file,
894             page => $file->page,
895             outline => $new,
896             font => $class->FACTORY->font(
897             $file,
898             %{$args{font}}
899 101         2884 ),
900             pad => $args{pad} || '.',
901             next_page => $args{next_page} || do { method {
902             my $self = shift;
903             $file->add_page(open => 1);
904             #$file->page->set_position($file->toc->parse_position([]));
905             return $file->page;
906             } },
907             padding => $args{padding} || 0,
908             align => $args{align} || 'left',
909             position => $args{position} || [],
910             (map {
911             $args{$_} ? ( $_ => $args{$_} ) : ()
912 101 50 100     35076 } qw/margin_bottom margin_top indent align pad_end/)
  505   50     6251  
      33        
      50        
      50        
      50        
913             );
914 3         81 }
915 3         59 method render (Map %args) {
916 101 50 33 101 0 272 $self->set_attrs(%args);
  101   66     363  
  101         378  
  101         340  
  101         159  
  101         346  
  101         367  
  101         1165  
  101         2132  
917 101         504 $self->pad_end($self->page->num + $args{page_offset});
918 101         1914 $self->add($self->title);
919 101         7686 my ($x, $y, $w) = ($self->file->page->x, $self->file->page->y, $self->file->page->w);
920 101         2428 my $annotation = $self->file->page->current->annotation()->rect(
921 101         12408 $x, $y + 3.5, $w, $y - 3.5
922             )->link($self->page->current, -xyz => [$self->x, $self->y, 0]);
923             for (@{$self->children}) {
924 101         50568 $_->render(%args);
  101         2002  
925 59         835 }
926             }
927 3     3   1982678 }
  3     3   6  
  3         52  
  3         35  
  3         1441  
  3         7  
  3         13  
  3         5  
928 3     3   157231 class Plugin::TOC {
  3         9  
  3         28  
  3         76  
929 3         28 has count (is => 'rw', type => Num);
  3         122  
930 3         28 has toc_placeholder (is => 'rw', type => HashRef);
  3         90  
931 3         25 has outline (is => 'rw', type => Object);
  3         62  
932 3         21 has outlines (is => 'rw', type => ArrayRef);
  3         83  
933 3         16 has indent (is => 'rw', type => Num);
  3         58  
934 3         17 has levels (is => 'rw', type => ArrayRef);
  3         70  
935 3         16 has toc_line_offset (is => 'rw', type => Num);
  3         56  
936 3         18 has font (is => 'rw', type => HashRef);
  3         76  
937             factory toc (Object $file, Map %args) {
938 1 50 33 1 1 4 return $class->new(
  1         5  
  1         4  
  1         3  
  1         4  
  1         11  
  1         1132  
  1         19  
939             file => $file,
940             outline => $file->pdf->outlines()->outline,
941             outlines => [],
942             count => 0,
943             toc_line_offset => $args{toc_line_offset} || 0,
944             padding => $args{padding} || 0,
945             levels => $args{levels} || [qw/title subtitle subsubtitle/],
946             indent => $args{indent} || 5,
947             ($args{font} ? (font => $args{font}) : ())
948 1 50 50     25 );
      50        
      50        
      50        
949 3         167 }
950 3         60 method placeholder (Map %args) {
951 1 50 33 1 0 3 $self->set_attrs(%args);
  1   33     5  
  1         4  
  1         5  
  1         3  
  1         5  
  1         14  
  1         1099  
  1         16  
952 1         11 #$self->file->subtitle->add($args{title} ? @{$args{title}} : 'Table of contents');
953             $self->toc_placeholder({
954             page => $self->file->page,
955             position => [$self->file->page->parse_position($args{position} || [])]
956 1   50     27 });
957             $self->file->onsave('toc', 'render', %args);
958 1         41 $self->file->add_page(force_new_page => 1);
959 1         44 return $self->file;
960 1         18 }
  3         68  
961 3         46 method add (Map %args) {
962 101 50 33 101 0 355 $self->set_attrs(%args);
  101   66     422  
  101         572  
  101         433  
  101         149  
  101         1821  
  101         406  
  101         1684  
  101         2209  
963 101         652 $self->count($self->count + 1);
964 101         2248 $args{level} = 0;
965 101         3780 my ($text, %targs, $level);
966 101         243 for (@{$self->levels}) {
967 101         212 if (defined $args{$_}) {
  101         1745  
968 188 100       1283 ($text, %targs) = ref $args{$_} ? @{$args{$_}} : $args{$_};
969 101 50       530 $level = $_;
  0         0  
970 101         230 $args{outline_title} ||= $text;
971 101   33     751 $args{jump_lh} = $self->file->$level->font->line_height;
972 101         1698 last;
973 101         2794 }
974             $args{level}++;
975 87         236 }
976             $args{font} ||= $self->font;
977 101   33     1801 my $outline;
978 101         829 $outline = $self->_recurse_find('level', 'children', $args{level} - 1, reverse @{$self->outlines}) if $args{level};
979 101 100       456 my $add = $self->FACTORY->add_outline($self->file, ($outline ? $outline->outline : $self->outline), %args);
  60         992  
980 101 100       1824 if ($outline) {
981 101 100       44862 $add->indent($self->indent * $add->level);
982 59         1315 push @{ $outline->children }, $add;
983 59         3899 } else {
  59         1004  
984             push @{ $self->outlines }, $add;
985 42         84 }
  42         926  
986             $self->file->$level->add($text, %targs);
987 101         2237 return $self->file;
988 101         2172 }
  3         48  
989 3         47 method render (Map %args) {
990 1 50 33 1 0 3 $self->set_attrs(%args);
  1   33     5  
  1         3  
  1         5  
  1         2  
  1         4  
  1         10  
  1         859  
  1         15  
991 1         5 my $placeholder = $self->toc_placeholder;
992 1         54 my ($x, $y, $w, $h) = $self->set_position(@{$placeholder->{position}});
993 1         9 $args{page_offset} = 0;
  1         22  
994 1         4 my $one_toc_link = $self->outlines->[0]->font->size + $self->toc_line_offset/mm;
995 1         17 $self->file->page($placeholder->{page});
996 1         72 my $total_height = ($self->count * $one_toc_link) - ($h + ($self->file->page->columns > 1
997 1 50       47 ? ($self->file->page->h * ($self->file->page->columns - $self->file->page->column))
998             : 0
999             ));
1000             while ($total_height > 0) {
1001 1         200 $args{page_offset}++;
1002 0         0 $self->file->add_page(num => $placeholder->{page}->num + $args{page_offset});
1003 0         0 $total_height -= $self->file->page->h;
1004 0         0 }
1005             $self->file->page($placeholder->{page});
1006 1         21 $self->file->page->h($self->file->page->h - $self->file->page->hf_offset);
1007 1         46 for my $outline (@{$self->outlines}) {
1008 1         124 $outline->render(%args);
  1         14  
1009 42         802 }
1010             }
1011 3     3   2364699 }
  3     3   8  
  3         52  
  3         37  
  3         1423  
  3         7  
  3         15  
  3         4  
1012 3     3   107630 class Plugin::Image {
  3         10  
  3         134  
  3         76  
1013 3         30 has width (is => 'rw', type => Num);
  3         126  
1014 3         19 has height (is => 'rw', type => Num);
  3         64  
1015 3         27 has align (is => 'rw', type => Str);
  3         62  
1016 3         27 has valid_mime (is => 'rw', type => HashRef, builder => 1);
  3         94  
1017             method _build_valid_mime {
1018 1   33 1   3 return {
  1         6  
  1         2  
  1         4966  
1019             jpeg => 'image_jpeg',
1020 1         24 tiff => 'image_tiff',
1021             pnm => 'image_pnm',
1022             png => 'image_png',
1023             gif => 'image_gif'
1024             };
1025 3         69 }
1026 3         48 factory image (Object $file, Map %args) {
1027 1 50 33 1 1 3 return $class->new(
  1         5  
  1         3  
  1         3  
  1         4  
  1         10  
  1         1103  
  1         19  
1028 1         12 file => $file,
1029             padding => 0,
1030             align => 'center',
1031             %args
1032             );
1033 3         101 }
1034 3         47 multi method add (FileHandle $image, Str $type, Map %args) {
1035 0 0 0     0 $self->set_attrs(%args);
  0         0  
  0         0  
  0         0  
  0         0  
1036 0         0 $type = $self->valid_mime->{$type};
1037 0         0 return $self->_add($self->file->pdf->$type($image));
1038 0         0 }
  3         92  
1039 3         45 multi method add (Str $image, Map %args) {
1040 1 50 33     3128 $self->set_attrs(%args);
  1         6  
  1         3  
  1         5  
  1         2  
1041 1         11 my $type = $self->_identify_type($image);
1042 1         5 return $self->_add($self->file->pdf->$type($image));
1043 1         34 }
  3         59  
1044 3         39 method _add (Object $image) {
1045 1   33 1   4 my ($x, $y, $w, $h) = $self->_image_position($image);
  1   33     5  
  1         3  
  1         686225  
  1         20  
  1         1200  
  1         15  
1046 1         6 my $photo = $self->file->page->current->gfx;
1047 1         15 $photo->image(
1048 1         314 $image,
1049             $x, $y, $w, $h
1050             );
1051             $self->set_y($y);
1052 1         515 return $self->file;
1053 1         43 }
  3         51  
1054 3         38 method _identify_type (Str $image) {
1055 1   33 1   4 my $reg = sprintf '\.(%s)$', join ("|", keys %{$self->valid_mime});
  1   33     5  
  1         1  
  1         4  
  1         13  
  1         671  
  1         13  
1056 1         3 $image =~ m/$reg/;
  1         24  
1057 1         63 return $self->valid_mime->{$1} || 'image_png';
1058 1   50     17 }
  3         48  
1059 3         33 method _image_position (Object $image) {
1060 1   33 1   3 my ($x, $y, $w, $h) = $self->parse_position($self->position || []);
  1   33     5  
  1         2  
  1         4  
  1         24  
  1         637  
  1         14  
1061 1   50     52 my $height = $self->height || $image->height;
1062 1   33     18 my $width = $self->width || $image->width;
1063 1   33     43 $width = $w if $width > $w;
1064 1 50       23 if ($self->align eq 'fill') {
1065 1 50       17 $height = $h;
    50          
    50          
1066 0         0 $width = $w;
1067 0         0 } elsif ($self->align eq 'right') {
1068             $x += ($w - $width);
1069 0         0 } elsif ($self->align eq 'center') {
1070             $x = ($w - $width) / 2;
1071 1         42 }
1072             # todo scale
1073             if ($height <= $h) {
1074 1 50       5 $y -= $height;
1075 1         3 } else {
1076             $self->file->add_page;
1077 0         0 ($x, $y, $w, $h) = $self->parse_position([]);
1078 0         0 if ($height > $h) {
1079 0 0       0 $height = $h;
1080 0         0 }
1081             $y -= $height;
1082 0         0 }
1083             return ($x, $y, $width, $height);
1084 1         5 }
1085 3     3   1977121 }
  3     3   17  
  3         54  
  3         32  
  3         1473  
  3         6  
  3         14  
  3         6  
1086 3     3   58751 class Plugin::Annotation {
  3         10  
  3         55  
  3         72  
1087 3         29 has type (is => 'rw', type => Str);
  3         120  
1088 3         22 has w (is => 'rw', type => Num);
  3         63  
1089 3         14 has h (is => 'rw', type => Num);
  3         55  
1090 3         27 has open (is => 'rw', type => Bool);
  3         69  
1091 3         25 has rect (is => 'rw', type => ArrayRef);
  3         84  
1092 3         17 has border (is => 'rw', type => ArrayRef);
  3         67  
1093             factory annotation (Object $file, Map %args) {
1094 0 0 0 0 1 0 return $class->new(
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
1095 0         0 file => $file,
1096             padding => 0,
1097             is => 'rw', type => 'text',
1098             open => 0,
1099             w => 0,
1100             h => 0,
1101             %args
1102             );
1103 3         79 }
1104 3         54 method add (Str $text, %args) {
1105 0 0 0 0 0 0 my $annotation = $self->file->page->current->annotation;
  0   0     0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
1106 0         0 return $self->_add_annotation($self->type, $text, %args);
1107 0         0 }
  3         67  
1108 3         42 method _add_annotation (Str $type, Str $cont, Map %args) {
1109 0 0 0 0   0 $self->set_attrs(%args);
  0   0     0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
1110 0         0 my $annotation = $self->file->page->current->annotation;
1111 0         0 my @xy = $self->parse_position(($self->position || []), 1);
1112 0   0     0 $annotation->$type($cont,
1113 0   0     0 -rect => $self->rect || [@xy, $self->w, $self->h],
      0        
1114             -open => $self->open,
1115             -border => $self->border || [@xy, $self->w]
1116             ); # :/
1117             return $self->file;
1118 0         0 }
1119 3     3   1945152 }
  3     3   7  
  3         51  
  3         31  
  3         1374  
  3         9  
  3         15  
  3         4  
1120 3     3   48879 class Plugin::List extends Plugin::Text {
  3         7  
  3         26  
  3         85  
  3         7  
1121 3         92 has type ( is => 'rw', type => Str );
  3         26  
  3         103  
1122             factory list (Object $file, Map %args) {
1123 0 0 0 0 1 0 my $self = $class->generic_new($file, %args);
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
1124 0         0 $self->type($args{type} || 'bullet');
1125 0   0     0 return $self;
1126 0         0 }
  3         80  
1127 3         61 around add (ArrayRef $list, Map %args) {
1128 0 0 0     0 $self->set_attrs(%args);
  0         0  
  0         0  
  0         0  
  0         0  
1129 0         0 my $i = 0;
1130 0         0 for my $item (@{$list}) {
1131 0         0 $i++;
  0         0  
1132 0         0 my ($x, $y) = $self->parse_position([]);
1133 0         0 my $offset;
1134 0         0 if ($self->type eq 'number') {
1135 0 0       0 $offset = 5;
1136 0         0 $self->$next("$i\.", position => [$x*mm, $y*mm]);
1137 0         0 } else {
1138             $offset = (($self->font->line_height*mm)/2) + 0.6;
1139 0         0 $self->file->circle->add(
1140 0         0 fill_colour => '#000',
1141             radius => 0.5,
1142             position => [($x*mm), ($y*mm) - $offset]
1143             );
1144             }
1145             $self->$next($item, position => [($x*mm) + $offset, $y*mm]);
1146 0         0 }
1147             }
1148 3     3   821209 }
  3     3   6  
  3         48  
  3         39  
  3         1374  
  3         8  
  3         24  
1149 3     3   229023 class Plugin::Form {
  3         10  
  3         35  
  0         0  
1150 3     3   2185 use PDF::API2::Basic::PDF::Utils;
  3         283360  
  3         565  
  3         44  
1151 3         17 has acro (is => 'rw', type => Object);
  3         72  
1152 3         19 has fields (is => 'rw', type => ArrayRef);
  3         83  
1153             factory form (Object $file, Map %args) {
1154 0 0 0 0 1 0 return $class->new(
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
1155 0         0 file => $file,
1156             %args
1157             );
1158 3         64 }
1159 3         38 method add (Map %args) {
1160 0 0 0 0 0 0 return $self if $self->acro;
  0   0     0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
1161 0 0       0 my $form = PDFDict();
1162 0         0 $form->{NeedAppearances} = PDFBool( 'true' );
1163 0         0 $self->acro($form);
1164 0         0 $self->file->onsave('form', 'end', why => 1);
1165 0         0 }
  3         51  
1166 3         35 method end (Map %args) {
1167 0 0 0 0 0 0 $self->acro->{Fields} = PDFArray(@{$self->fields});
  0   0     0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
1168 0         0 $self->file->pdf->{catalog}->{'AcroForm'} = $self->acro;
  0         0  
1169 0         0 }
  3         46  
1170 3         34 method _add_to_fields (Object $field) {
1171 0   0 0   0 $self->add();
  0   0     0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
1172 0         0 my $fields = $self->fields;
1173 0         0 push @{$fields}, $field;
1174 0         0 return $self->fields($fields);
  0         0  
1175 0         0 }
1176 3     3   1093696 class Plugin::Form::Field extends Plugin::Text {
  3         8  
  3         32  
  3         52  
  3         32  
1177 3     3   426 use PDF::API2::Basic::PDF::Literal;
  3         10  
  3         110  
  0         0  
1178 3     3   18 use PDF::API2::Basic::PDF::Utils;
  3         7  
  3         362  
  3         5  
1179 3         25 has xo (is => 'rw', type => Object);
  3         83  
1180 3         17 has annotate (is => 'rw', type => Object);
  3         53  
1181 3         25 has name (is => 'rw', type => Str);
  3         55  
1182             around add (Str $text, Map %args) {
1183 0 0 0     0 return $self->$next($text, %args) if $args{noconfigure};
  0         0  
  0         0  
  0         0  
  0         0  
1184 0 0       0 my @pos = ($self->parse_position([]));
1185 0         0 $self->file->form->add; #REMOVE
1186 0         0 my $form = $self->xo(
1187 0         0 $self->file->pdf->xo_form()
1188             );
1189             my $file = $self->$next($text, %args);
1190 0         0 my $annotate = $self->annotate(
1191 0         0 $self->file->page->current->annotation
1192             );
1193             $form->{OpenAction} = PDFArray($self->annotate, PDFName('XYZ'), PDFNull, PDFNull, PDFNum(0));
1194 0         0 $form->bbox(0, 0, 149.8, 14.4);
1195 0         0 $annotate->{DR} = $self->font->load();
1196 0         0 $annotate->{T} = PDFStr($self->name || $text);
1197 0   0     0 $annotate->{Subtype} = PDFName('Widget');
1198 0         0 $annotate->{P} = $self->file->page->current;
1199 0         0 $args{position} ||= \@pos;
1200 0   0     0 $self->configure(%args) if $self->can('configure');
1201 0 0       0 $self->_set_rect(%args) if $self->can('_set_rect');
1202 0 0       0 $self->file->form->_add_to_fields($self->annotate);
1203 0         0 return $file;
1204 0         0 }
  3         71  
1205 3         46 method _set_rect (Map %args) {
1206 0 0 0 0   0 my @pos = @{$args{position}};
  0   0     0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
1207 0         0 @pos = (
  0         0  
1208 0         0 $self->end_w + $self->text->advancewidth(' '),
1209             $pos[1] + ($self->font->line_height/3),
1210             $pos[2] + ($self->file->page->padding/mm),
1211             $pos[1] - ($self->font->line_height*2)
1212             );
1213             $self->annotate->rect(@pos);
1214 0         0 }
  3         48  
1215 3     3   1260874 class Plugin::Form::Field::Input {
  3         9  
  3         32  
  3         70  
  0         0  
  3         36  
1216             factory input (Object $file, Map %args) {
1217 0 0 0 0 1 0 $args{pad} ||= '_';
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
1218 0   0     0 $args{margin_bottom} ||= 1.7;
1219 0   0     0 $class->generic_new($file, %args);
1220 0         0 }
  3         94  
1221 3         58 method configure (Map %args) {
1222 0 0 0 0 0 0 $self->annotate->{FT} = PDFName('Tx');
  0   0     0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
1223 0         0 }
1224 3     3   333727 class Plugin::Form::Field::Textarea {
  3         8  
  3         31  
  3         73  
  3         34  
1225 3         27 has lines (is => 'rw', type => Num);
  3         119  
1226             factory textarea (Object $file, Map %args) {
1227 0 0 0 0 1 0 $args{pad} ||= '_';
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
1228 0   0     0 $args{margin_bottom} ||= 1.7;
1229 0   0     0 my $self = $class->generic_new($file, %args);
1230 0         0 $self->lines($args{lines} ||= 4);
1231 0   0     0 return $self;
1232 0         0 }
  3         96  
1233 3         56 around configure (Map %args) {
1234 0 0 0     0 $self->$next(%args);
  0         0  
  0         0  
  0         0  
  0         0  
1235 0         0 my $ew = $self->end_w;
1236 0         0 my $ns = $self->no_space;
1237 0         0 my $tp = $self->text->advancewidth($self->pad);
1238 0         0 my $x = ($ew + $tp)*mm;
1239 0         0 for (1 .. $self->lines) {
1240 0         0 $self->add(
1241 0         0 ' ' . $self->pad,
1242             position => [
1243             $x,
1244             ($self->file->page->y*mm) - $self->padding,
1245             (($self->file->page->w+$tp)*mm) + $self->file->page->padding + - $x
1246             ],
1247             noconfigure => 1,
1248             no_space => 1
1249             );
1250             }
1251             $self->no_space($ns);
1252 0         0 }
  3         76  
1253 3         53 method _set_rect (Map %args) {
1254 0 0 0 0   0 my @pos = @{$args{position}};
  0   0     0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
1255 0         0 @pos = (
  0         0  
1256 0         0 $self->end_w - $self->text->advancewidth(' ' . $self->pad),
1257             $pos[1] + ($self->font->line_height/3),
1258             $pos[2] + ($self->file->page->padding/mm),
1259             $pos[1] - ($self->font->line_height* 2 * $self->lines)
1260             );
1261             $self->annotate->rect(@pos);
1262 0         0 }
1263 3     3   848764 }
  3     3   9  
  3         50  
  3         33  
  3         1379  
  3         7  
  3         14  
1264 3     3   189 }
  3     3   7  
  3         29  
  3         977  
  3         6  
  3         14  
  3         7  
1265 3     3   47070 class Plugin::Form::Field::Select {
  3         7  
  3         30  
  3         68  
1266             factory select (Object $file, Map %args) {
1267 0 0 0 0 1 0 $args{pad} ||= '_';
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
1268 0   0     0 $args{margin_bottom} ||= 1.7;
1269 0   0     0 $class->generic_new($file, %args);
1270 0         0 }
  3         98  
1271 3         51 method configure (Map %args) {
1272 0 0 0 0 0 0 $self->annotate->{V} = do {
  0   0     0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
1273 0         0 my $s = PDFStr('');
1274 0         0 $s->{' isutf'} = PDFBool(1);
1275 0         0 $s;
1276 0         0 };
1277             $self->annotate->{DA} = PDFStr('0 0 0 rg /F3 11 Tf');
1278 0         0 $self->annotate->{DV} = $self->annotate->{V};
1279 0         0 $self->annotate->{FT} = PDFName('Ch');
1280 0         0 $self->annotate->{Ff} = PDFNum(393216);
1281 0         0 $self->annotate->{Opt} = PDFArray(map { PDFStr($_); } @{$args{options}});
1282 0         0 }
  0         0  
  0         0  
  3         65  
1283 3         37 method _set_rect (Map %args) {
1284 0 0 0 0   0 my @pos = @{$args{position}};
  0   0     0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
1285 0         0 @pos = (
  0         0  
1286 0         0 $self->end_w + $self->text->advancewidth($self->pad),
1287             $pos[1] + ($self->font->line_height/2),
1288             $pos[2] + ($self->file->page->padding/mm),
1289             $pos[1] - ($self->font->line_height)
1290             );
1291             $self->annotate->rect(@pos);
1292 0         0 }
1293 3     3   391129 }
  3     3   8  
  3         46  
  3         28  
  3         1260  
  3         6  
  3         13  
1294 3     3   212 }
  3     3   6  
  3         26  
  3         78  
  3         882  
  3         8  
  3         11  
1295 3     3   193 }
  3     3   5  
  3         28  
  3         895  
  3         6  
  3         12  
1296 3     3   164 }
  3     3   6  
  3         30  
  3         867  
  3         7  
  3         11  
1297 3     3   35424 class Factory {
  3         9  
  3         25  
1298 3     3   2422 use PDF::API2;
  3         320489  
  3         333  
  3         67  
1299             factory new_pdf (Str $name, Map %args) {
1300 2 50 33 2 1 8 return $factory->generate_file(\%args)->new(
  2         9  
  2         10  
  2         4  
  2         1828  
  2         18  
  2         2530  
  2         42  
1301             file_name => $name,
1302             pages => [],
1303             num => 0,
1304             page_size => 'A4',
1305             page_args => $args{page} || {},
1306             pdf => PDF::API2->new( -file => sprintf("%s.pdf", $name)),
1307 2   50     56 )->add_page;
1308 3         118 }
1309 3         57 factory open (Str $name, Map %args) {
1310 0 0 0 0 1 0 my $pdf = PDF::API2->open($name);
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
1311 0         0 my $file = $factory->generate_file(\%args)->new(
1312             pdf => $pdf,
1313             file_name => $name,
1314             pages => [],
1315             page_size => 'A4',
1316             page_args => $args{page} || {},
1317             );
1318 0   0     0 $file->page($factory->page($pdf,
1319             open => 1,
1320             num => 1,
1321             page_size => 'A4',
1322             %{$args{page}}
1323 0         0 ));
  0         0  
1324             return $file;
1325 0         0 }
1326 3     3   351906 }
  3     3   8  
  3         49  
  3         29  
  3         1264  
  3         8  
  3         12  
1327             }
1328              
1329             # probably should dry-run to calculate positions
1330              
1331             1;
1332              
1333             __END__
1334              
1335             =head1 NAME
1336              
1337             Mxpress::PDF - PDF
1338              
1339             =head1 VERSION
1340              
1341             Version 0.28
1342              
1343             =cut
1344              
1345             =head1 Note
1346              
1347             This is experimental and may yet still change.
1348              
1349             =head1 SYNOPSIS
1350              
1351             use Mxpress::PDF;
1352              
1353             my @data = qw/
1354             Brian
1355             Dougal
1356             Dylan
1357             Ermintrude
1358             Florence
1359             Zebedee
1360             /;
1361              
1362             my $gen_text = sub { join( ' ', map { $data[int(rand(scalar @data))] } 0 .. int(rand(shift))) };
1363              
1364             my $pdf = Mxpress::PDF->new_pdf('test',
1365             page => {
1366             background => '#000',
1367             padding => 15,
1368             columns => 3,
1369             },
1370             cover => {
1371             columns => 1
1372             },
1373             toc => {
1374             font => { colour => '#00f' },
1375             },
1376             title => {
1377             font => {
1378             colour => '#f00',
1379             },
1380             margin_bottom => 3,
1381             padding => 5,
1382             },
1383             subtitle => {
1384             font => {
1385             colour => '#0ff',
1386             },
1387             margin_bottom => 3,
1388             padding => 5,
1389             },
1390             subsubtitle => {
1391             font => {
1392             colour => '#f0f',
1393             },
1394             padding => 5,
1395             margin_bottom => 3
1396             },
1397             text => {
1398             font => { colour => '#fff' },
1399             margin_bottom => 3,
1400             padding => 5,
1401             align => 'justify'
1402             },
1403             );
1404              
1405             $pdf->cover->add->title->add(
1406             'Add a cover page'
1407             )->image->add(
1408             't/hand-cross.png'
1409             )->cover->add(
1410             cb => ['text', 'add', q|you're welcome|]
1411             )->cover->end;
1412              
1413             $pdf->title->add(
1414             'Table Of Contents'
1415             )->toc->placeholder;
1416              
1417             $pdf->page->header->add(
1418             show_page_num => 'right',
1419             page_num_text => "page {num}",
1420             cb => ['text', 'add', 'Header of the page', align => 'center', font => Mxpress::PDF->font($pdf, colour => '#f00') ],
1421             h => $pdf->mmp(10),
1422             padding => 5
1423             );
1424              
1425             $pdf->page->footer->add(
1426             show_page_num => 'left',
1427             cb => ['text', 'add', 'Footer of the page', align => 'center', font => Mxpress::PDF->font($pdf, colour => '#f00') ],
1428             h => $pdf->mmp(10),
1429             padding => 5
1430             );
1431              
1432              
1433             my $default = $pdf->text->font;
1434             my $bold = Mxpress::PDF->font($pdf, colour => '#fff', family => 'Times-Bold');
1435             my $italic = Mxpress::PDF->font($pdf, colour => '#fff', family => 'Times-Italic');
1436              
1437             $pdf->text->add('default text,');
1438             $pdf->text->add('bold text,', font => $bold, concat => \1);
1439             $pdf->text->add('italic text,', font => $italic, concat => \1);
1440             $pdf->text->add('default text.', font => $default, concat => \1);
1441              
1442             $pdf->list->add([
1443             'First',
1444             'Second',
1445             'Third'
1446             ], type => 'number');
1447              
1448             $pdf->border->start(type => 'dots');
1449             for (0 .. 100) {
1450             $pdf->toc->add(
1451             [qw/title subtitle subsubtitle/]->[int(rand(3))] => $gen_text->(4)
1452             )->text->add( $gen_text->(1000) );
1453             }
1454             $pdf->border->end;
1455              
1456             $pdf->save();
1457              
1458             =head1 Description
1459              
1460             This module currently allows you to easily create a PDF. Why? For fun.
1461              
1462             =head1 Factory
1463              
1464             Mxpress::PDF is a factory package and the entry point for Mxpress::PDF::* objects.
1465              
1466             =head2 new_pdf
1467              
1468             Returns a new Mxpress::PDF::File object. This is the MAIN object for working on the PDF file.
1469              
1470             my $file = Mxpress::PDF->new_pdf($filename, %page_args);
1471              
1472             =cut
1473              
1474             =head2 page
1475              
1476             Returns a new Mxpress::PDF::Page Object. This object is for managing an individual PDF page.
1477              
1478             my $page = Mxpress::PDF->page(%page_args);
1479              
1480             =head2 cover
1481              
1482             Returns a new Mxpress::PDF::Page::Component::Cover Object. This object is for managing the PDF cover page.
1483              
1484             my $cover = Mxpress::PDF->cover(%cover_args);
1485              
1486             =head2 header
1487              
1488             Returns a new Mxpress::PDF::Page::Component::Header Object. This object is for managing an individual PDF page header.
1489              
1490             my $header = Mxpress::PDF->header(%header_args);
1491              
1492             =head2 footer
1493              
1494             Returns a new Mxpress::PDF::Page::Component::Footer Object. This object is for managing an individual PDF page footer.
1495              
1496             my $footer = Mxpress::PDF->footer(%footer_args);
1497              
1498             =head2 font
1499              
1500             Returns a new Mxpress::PDF::Plugin::Font Object. This object is for loading a PDFs text font.
1501              
1502             my $font = Mxpress::PDF->font($file, %font_args);
1503              
1504              
1505             =head2 border
1506              
1507             Returns a new Mxpress::PDF::Plugin::Border Object. This object is for drawing borders.
1508              
1509             my $border = Mxpress::PDF->border($file, %line_args);
1510              
1511             =head2 line
1512              
1513             Returns a new Mxpress::PDF::Plugin::Shape::Line Object. This object is for drawing lines.
1514              
1515             my $line = Mxpress::PDF->line($file, %line_args);
1516              
1517             =head2 box
1518              
1519             Returns a new Mxpress::PDF::Plugin::Shape::Box Object. This object is for drawing box shapes.
1520              
1521             my $box = Mxpress::PDF->box($file, %box_args);
1522              
1523             =head2 circle
1524              
1525             Returns a new Mxpress::PDF::Plugin::Shape::Circle Object. This object is for drawing circle shapes.
1526              
1527             my $box = Mxpress::PDF->circle($file, %circle_args);
1528              
1529             =head2 pie
1530              
1531             Returns a new Mxpress::PDF::Plugin::Shape::Pie Object. This object is for drawing pie shapes.
1532              
1533             my $pie = Mxpress::PDF->pie($file, %pie_args);
1534              
1535             =head2 ellipse
1536              
1537             Returns a new Mxpress::PDF::Plugin::Shape::Ellipse Object. This object is for drawing ellipse shapes.
1538              
1539             my $ellipse = Mxpress::PDF->ellipse($file, %ellise_args);
1540              
1541             =head2 text
1542              
1543             Returns a new Mxpress::PDF::Plugin::Text Object. This object aids with writing text to a pdf page.
1544              
1545             my $text = Mxpress::PDF->text($file, %text_args);
1546              
1547             =head2 title
1548              
1549             Returns a new Mxpress::PDF::Plugin::Text::Title Object. This object aids with writing 'title' text to a pdf page.
1550              
1551             my $title = Mxpress::PDF->title($file, %title_args);
1552              
1553             =head2 subtitle
1554              
1555             Returns a new Mxpress::PDF::Plugin::Text::Subtitle Object. This object aids with writing 'subtitle' text to a pdf page.
1556              
1557             my $subtitle = Mxpress::PDF->subtitle($file, %subtitle_args);
1558              
1559             =head2 subsubtitle
1560              
1561             Returns a new Mxpress::PDF::Plugin::Text::Subsubtitle Object. This object aids with writing 'subsubtitle' text to a pdf page.
1562              
1563             my $subsubtitle = Mxpress::PDF->subsubtitle($file, %subsubtitle_args);
1564              
1565             =head2 h1
1566              
1567             Returns a new Mxpress::PDF::Plugin::Text::H1 Object. This object aids with writing 'heading' text to a pdf page.
1568              
1569             my $h1 = Mxpress::PDF->h1($file, %h1_args);
1570              
1571             =head2 h2
1572              
1573             Returns a new Mxpress::PDF::Plugin::Text::H2 Object. This object aids with writing 'heading' text to a pdf page.
1574              
1575             my $h1 = Mxpress::PDF->h2($file, %h2_args);
1576              
1577             =head2 h3
1578              
1579             Returns a new Mxpress::PDF::Plugin::Text::H3 Object. This object aids with writing 'heading' text to a pdf page.
1580              
1581             my $h1 = Mxpress::PDF->h3($file, %h3_args);
1582              
1583             =head2 h4
1584              
1585             Returns a new Mxpress::PDF::Plugin::Text::H4 Object. This object aids with writing 'heading' text to a pdf page.
1586              
1587             my $h1 = Mxpress::PDF->h2($file, %h4_args);
1588              
1589             =head2 h5
1590              
1591             Returns a new Mxpress::PDF::Plugin::Text::H5 Object. This object aids with writing 'heading' text to a pdf page.
1592              
1593             my $h1 = Mxpress::PDF->h2($file, %h5_args);
1594              
1595             =head2 h6
1596              
1597             Returns a new Mxpress::PDF::Plugin::Text::H6 Object. This object aids with writing 'heading' text to a pdf page.
1598              
1599             my $h1 = Mxpress::PDF->h2($file, %h6_args);
1600              
1601             =head2 list
1602              
1603             Returns a new Mxpress::PDF::Plugin::List Object. This object aids with writing lists to a pdf page.
1604              
1605             my $text = Mxpress::PDF->list($file, %list_args);
1606              
1607             =head2 toc
1608              
1609             Returns a new Mxpress::PDF::Plugin::TOC Object. This object is for managing a table of contents.
1610              
1611             my $toc = Mxpress::PDF->toc($file, %toc_args);
1612              
1613             =head2 add_outline
1614              
1615             Returns a new Mxpress::PDF::Plugin::TOC::Outline Object. This object is for managing an indivual outline for the table of contents.
1616              
1617             my $outline = Mxpress::PDF->add_outline($file, %ouline_args);
1618              
1619             =head2 image
1620              
1621             Returns a new Mxpress::PDF::Plugin::Image Object. This object aids with adding images to a pdf page.
1622              
1623             my $image = Mxpress::PDF->image($file, %image_args);
1624              
1625             =head2 annotation
1626              
1627             Returns a new Mxpress::PDF::Plugin::Annotation Object. This object aids with adding annotations to a pdf page.
1628              
1629             my $annotation = Mxpress::PDF->annotation($file, %annotation_args);
1630              
1631             =head2 form
1632              
1633             Returns a new Mxpress::PDF::Plugin::Form Object. This object is for managing the AcroForm..
1634              
1635             my $form = Mxpress::PDF->form($file, %form_args);
1636              
1637             =head2 input
1638              
1639             Returns a new Mxpress::PDF::Plugin::Field::Input Object. This object aids with adding fillable text fields to a pdf page.
1640              
1641             my $input = Mxpress::PDF->input($file, %input_args);
1642              
1643             =head2 textarea
1644              
1645             Returns a new Mxpress::PDF::Plugin::Field::Input::Textarea Object. This object aids with adding fillable milti line text fields to a pdf page.
1646              
1647             my $textarea = Mxpress::PDF->textarea($file, %textarea_args);
1648              
1649             =head2 select
1650              
1651             Returns a new Mxpress::PDF::Plugin::Field::Select Object. This object aids with adding select fields to a pdf page.
1652              
1653             my $select = Mxpress::PDF->select($file, %select_args);
1654              
1655             =head1 File
1656              
1657             Mxpress::PDF::File is the main object that you will use when creating a pdf using this library. To instantiate call add_file
1658             with a file name and any plugin attributes.
1659              
1660             my $file = Mxpress::PDF->add_file($filename,
1661             page => {},
1662             toc => {},
1663             title => {},
1664             subtitle => {},
1665             subsubtitle => {},
1666             text => {},
1667             toc => {},
1668             box => {},
1669             line => {},
1670             circle => {},
1671             pie => {},
1672             ellipse => {}
1673             );
1674              
1675             =head2 Attributes
1676              
1677             The following attributes can be configured for a Mxpress::PDF::File, they are all optional.
1678              
1679             $file->$attr
1680              
1681             =head3 file_name (is => 'rw', type => Str);
1682              
1683             The file name of the pdf
1684              
1685             $file->file_name;
1686              
1687             =head3 pdf (is => 'rw', type => Object);
1688              
1689             A PDF::API2 Object.
1690              
1691             $file->pdf;
1692              
1693             =head3 pages (is => 'rw', type => ArrayRef);
1694              
1695             A list of Mxpress::PDF::Page objects.
1696              
1697             $file->pages;
1698              
1699             =head3 page (is => 'rw', type => Object);
1700              
1701             An open Mxpress::PDF::Page object.
1702              
1703             $file->page;
1704              
1705             =head3 onsave_cbs (is => 'rw', type => ArrayRef);
1706              
1707             An array of arrays that define cbs, triggered when $file->save() is called.
1708              
1709             [
1710             [$plugin, $method_name, @%args]
1711             ]
1712              
1713             =head3 font (is => 'rw', type => Object)
1714              
1715             A Mxpress:PDF::Plugin::Font Object.
1716              
1717             $file->font->load;
1718              
1719             =head3 border (is => 'rw', type => Object)
1720              
1721             A Mxpress:PDF::Plugin::Border Object.
1722              
1723             $file->border->start;
1724             ...
1725             $file->border->end;
1726              
1727             =head3 line (is => 'rw', type => Object)
1728              
1729             A Mxpress::PDF::Plugin::Shape::Line Object.
1730              
1731             $file->line->add;
1732              
1733             =head3 box (is => 'rw', type => Object)
1734              
1735             A Mxpress::PDF::Plugin::Shape::Box Object.
1736              
1737             $file->box->add;
1738              
1739             =head3 circle
1740              
1741             A Mxpress::PDF::Plugin::Shape::Circle Object.
1742              
1743             $file->circle->add;
1744              
1745             =head3 pie
1746              
1747             A Mxpress::PDF::Plugin::Shape::Pie Object.
1748              
1749             $file->pie->add;
1750              
1751             =head3 ellipse
1752              
1753             A Mxpress::PDF::Plugin::Shape::Ellipse Object.
1754              
1755             $file->ellipse->add;
1756              
1757             =head3 toc
1758              
1759             A Mxpress::PDF::Plugin::TOC Object.
1760              
1761             $file->toc->placeholder->toc->add(
1762             title => 'A title'
1763             );
1764              
1765             =head3 title
1766              
1767             A Mxpress::PDF::Plugin::Title Object.
1768              
1769             $file->title->add;
1770              
1771             =head3 subtitle
1772              
1773             A Mxpress::PDF::Plugin::Subtitle Object.
1774              
1775             $file->title->add;
1776              
1777             =head3 subsubtitle
1778              
1779             A Mxpress::PDF::Plugin::Subsubtitle Object
1780              
1781             $file->subsubtitle->add;
1782              
1783             =head3 h1
1784              
1785             A Mxpress::PDF::Plugin::H1 Object.
1786              
1787             $file->h1->add;
1788              
1789             =head3 h2
1790              
1791             A Mxpress::PDF::Plugin::H2 Object.
1792              
1793             $file->h2->add;
1794              
1795             =head3 h3
1796              
1797             A Mxpress::PDF::Plugin::H3 Object.
1798              
1799             $file->h3->add;
1800              
1801             =head3 h4
1802              
1803             A Mxpress::PDF::Plugin::H4 Object.
1804              
1805             $file->h4->add;
1806              
1807             =head3 h5
1808              
1809             A Mxpress::PDF::Plugin::H5 Object.
1810              
1811             $file->h5->add;
1812              
1813             =head3 h6
1814              
1815             A Mxpress::PDF::Plugin::H6 Object.
1816              
1817             $file->h6->add;
1818              
1819             =head3 text
1820              
1821             A Mxpress::PDF::Plugin::Text Object
1822              
1823             $file->text->add;
1824              
1825             =head3 list
1826              
1827             A Mxpress::PDF::Plugin::List Object.
1828              
1829             $file->list->add;
1830              
1831             =head2 Methods
1832              
1833             The following methods can be called from a Mxpress::PDF::File Object.
1834              
1835             =head3 add_page
1836              
1837             This will add a new Mxpress::PDF::Page to the file. You can pass any page attributes defined in
1838             the documentation below.
1839              
1840             $file->add_page(%page_attrs)
1841              
1842             =head3 save
1843              
1844             This will save the pdf file. Note call only once you are finished generating the pdf file.
1845              
1846             $file->save();
1847              
1848             =head3 onsave
1849              
1850             Add a onsave callback to the file. The callbacks will be triggered when you call $file->save();.
1851              
1852             $file->onsave($plugin, $cb, \%plugin_args);
1853              
1854             =head3 mmp
1855              
1856             Convert mm to pt.
1857              
1858             my $pt = $file->mmp(10);
1859              
1860             =head1 Page
1861              
1862             An open Mxpress::PDF::Page object.
1863             Mxpress::PDF::Page is for managing an individual PDF page. To access the current open page call the attribute on the file object.
1864              
1865             my $page = $file->page;
1866              
1867             To add a new page to the pdf call add_page on the file object.
1868              
1869             my $new_page = $file->add_page(%page_attributes)->page;
1870              
1871             =head2 Attributes
1872              
1873             The following attributes can be configured for a Mxpress::PDF::File, they are all optional.
1874              
1875             $page->$attr
1876              
1877             =head3 page_size (is => 'rw', type => Str);
1878              
1879             The page size of the pdf, default is A4.
1880              
1881             $page->page_size('A4');
1882              
1883             =head3 background (is => 'rw', type => Str);
1884              
1885             The background colour of the page.
1886              
1887             $page->background('#000');
1888              
1889             =head3 num (is => 'rw', type => Num, required => 1);
1890              
1891             The page number.
1892              
1893             $page->num;
1894              
1895             =head3 current (is => 'rw', type => Object);
1896              
1897             The current PDF::API2::Page Object.
1898              
1899             $page->current;
1900              
1901             =head3 columns (is => 'rw', type => Num);
1902              
1903             The number of columns configured for the page, default is 1.
1904              
1905             $page->columns(5);
1906              
1907             =head3 column (is => 'rw', type => Num);
1908              
1909             The current column that is being generated, default is 1.
1910              
1911             $page->column(2);
1912              
1913             =head3 rows (is => 'rw', type => Num);
1914              
1915             The number of rows configured for the page, default is 1.
1916              
1917             $page->rows(5);
1918              
1919             =head3 row (is => 'rw', type => Num);
1920              
1921             The number of rows configured for the page, default is 1.
1922              
1923             $page->row(2);
1924              
1925             =head3 is_rotated (is => 'rw', type => Num);
1926              
1927             Is the page rotated (portrait/landscape).
1928              
1929             $page->is_rotated;
1930              
1931             =head3 x (is => 'rw', type => Num);
1932              
1933             The current x coordinate.
1934              
1935             $page->x($x);
1936              
1937             =head3 y (is => 'rw', type => Num);
1938              
1939             The current y coordinate.
1940              
1941             $page->y($y);
1942              
1943             =head3 w (is => 'rw', type => Num);
1944              
1945             The available page width.
1946              
1947             $page->w($w);
1948              
1949             =head3 h (is => 'rw', type => Num);
1950              
1951             The available page height.
1952              
1953             $page->h($h);
1954              
1955             =head3 full (is => 'rw', type => Bool);
1956              
1957             Disable any column/row configuration and render full width/height.
1958              
1959             $page->full(\1);
1960              
1961             =head3 padding (is => 'rw', type => Num);
1962              
1963             Add padding to the page (mm).
1964              
1965             $page->padding($mm);
1966              
1967             =head3 margin_top (is => 'rw', type => Num);
1968              
1969             Add margin to the top of the page (mm).
1970              
1971             $page->margin_top($mm);
1972              
1973             =head3 margin_bottom (is => 'rw', type => Num);
1974              
1975             Add margin to the bottom of the page (mm).
1976              
1977             $page->margin_bottom($mm);
1978              
1979             =head3 onsave_cbs (is => 'rw', type => ArrayRef);
1980              
1981             Callbacks that will be triggered when $file->save is called.
1982              
1983             $page->onsave_cbs([
1984             [$plugin, $method_name, @%args]
1985             ]);
1986              
1987             =head3 header (is => 'rw', type => HashRef|Object);
1988              
1989             A Mxpress::PDF::Page::Component::Header Object.
1990              
1991             $page->header;
1992              
1993             =head3 footer (is => 'rw', type => HashRef|Object);
1994              
1995             A Mxpress::PDF::Page::Component::Footer Object.
1996              
1997             $page->footer;
1998              
1999             =head2 Methods
2000              
2001             The following methods can be called from a Mxpress::PDF::Page Object.
2002              
2003             =head3 rotate
2004              
2005             Rotate the current page.
2006              
2007             $page->rotate();
2008              
2009             =head3 next_column
2010              
2011             Find the next column of the page.
2012              
2013             $page->next_column();
2014              
2015             =head3 next_row
2016              
2017             Find the next row of the page.
2018              
2019             $page->next_row();
2020              
2021             =head2 onsave
2022              
2023             Add a onsave callback to the page. The callbacks will be triggered when you call $file->save();.
2024              
2025             $page->onsave($plugin, $cb, @%plugin_args);
2026              
2027             =head2 attrs
2028              
2029             Return attributes for the page.
2030              
2031             my $attrs = $page->attrs(@attrs);
2032              
2033             =head1 Component
2034              
2035              
2036             =head1 Cover
2037              
2038             Mxpress::PDF::Page::Component::Cover extends Mxpress::PDF::Page::Component and is for managing an the PDF cover page.
2039              
2040             You can pass default attributes when instantiating the page object.
2041              
2042             $file->add_page(
2043             cover => { %cover_atts }
2044             );
2045              
2046             or when calling the objects add method.
2047              
2048             $page->cover->add(
2049             %cover_attrs
2050             );
2051              
2052             =head2 Attributes
2053              
2054             The following additional attributes can be configured for a Mxpress::PDF::Page::Component::Cover, they are all optional.
2055              
2056             $page->cover->$attr
2057              
2058             =head3 show_page_num (is => 'rw', type => Str);
2059              
2060             Alignment for the page number
2061              
2062             show_page_num => 'right'
2063              
2064             =head3 page_num_text (is => 'rw', type => Str);
2065              
2066             Text to display around the page number.
2067              
2068             page_num_text => 'Page {num}'
2069              
2070             =head3 active (is => 'rw', type => Bool);
2071              
2072             Control whether to display the cover, default is false however it is set to true if ->cover->add() is called.
2073              
2074             active => true
2075              
2076             =head2 Methods
2077              
2078             The following methods can be called from a Mxpress::PDF::Page::Component Object.
2079              
2080             =head3 add
2081              
2082             Add content to the cover. You can pass any attribute for the header along with a cb function which will be added to
2083             the onsave_cbs.
2084              
2085             $page->coverr->add(
2086             cb => [...],
2087             %cover_atts
2088             );
2089              
2090             =head3 set_position
2091              
2092             Set the position of the header.
2093              
2094             $page->header->position($x, $y, $w, $h);
2095              
2096             =head3 process_page_num_text
2097              
2098             Process the page_num_text into printable form.
2099              
2100             $self->header->processs_page_num_text();
2101              
2102             =head3 activate
2103              
2104             Activate the header.
2105              
2106             $page->activate()
2107              
2108             =head3 end
2109              
2110             Move to page 2.
2111              
2112             $page->end;
2113              
2114             =head1 Header
2115              
2116             Mxpress::PDF::Page::Component::Header extends Mxpress::PDF::Page::Component and is for managing an individual PDF page header.
2117              
2118             You can pass default attributes when instantiating the page object.
2119              
2120             $file->add_page(
2121             header => { %header_atts }
2122             );
2123              
2124             or when calling the objects add method.
2125              
2126             $page->header->add(
2127             %header_attrs
2128             );
2129              
2130             =head2 Attributes
2131              
2132             The following additional attributes can be configured for a Mxpress::PDF::Page::Component::Header, they are all optional.
2133              
2134             $page->header->$attr
2135              
2136             =head3 show_page_num (is => 'rw', type => Str);
2137              
2138             Alignment for the page number
2139              
2140             show_page_num => 'right'
2141              
2142             =head3 page_num_text (is => 'rw', type => Str);
2143              
2144             Text to display around the page number.
2145              
2146             page_num_text => 'Page {num}'
2147              
2148             =head3 active (is => 'rw', type => Bool);
2149              
2150             Control whether to display the header, default is false however it is set to true if ->header->add() is called.
2151              
2152             active => true
2153              
2154             =head2 Methods
2155              
2156             The following methods can be called from a Mxpress::PDF::Page::Header Object.
2157              
2158             =head3 add
2159              
2160             Add content to the header. You can pass any attribute for the header along with a cb function which will be added to
2161             the onsave_cbs.
2162              
2163             $page->header->add(
2164             cb => [...],
2165             %header_atts
2166             );
2167              
2168             =head3 set_position
2169              
2170             Set the position of the header.
2171              
2172             $page->header->position($x, $y, $w, $h);
2173              
2174             =head3 process_page_num_text
2175              
2176             Process the page_num_text into printable form.
2177              
2178             $self->header->processs_page_num_text();
2179              
2180             =head3 activate
2181              
2182             Activate the header.
2183              
2184             $page->activate()
2185              
2186             =head1 Footer
2187              
2188             Mxpress::PDF::Page::Component::Footer extends Mxpress::PDF::Page and is for managing an individual PDF page footer.
2189              
2190             You can pass default attributes when instantiating the page object.
2191              
2192             $file->add_page(
2193             footer => { %footer_atts }
2194             );
2195              
2196             or when calling the objects add method.
2197              
2198             $page->footer->add(
2199             %footer_attrs
2200             );
2201              
2202             =head2 Attributes
2203              
2204             The following additional attributes can be configured for a Mxpress::PDF::Page::Component::Footer, they are all optional.
2205              
2206             $page->footer->$attr
2207              
2208             =head3 show_page_num (is => 'rw', type => Str);
2209              
2210             Alignment for the page number
2211              
2212             show_page_num => 'right'
2213              
2214             =head3 page_num_text (is => 'rw', type => Str);
2215              
2216             Text to display around the page number.
2217              
2218             page_num_text => 'Page {num}'
2219              
2220             =head3 active (is => 'rw', type => Bool);
2221              
2222             Control whether to display the header, default is false however it is set to true if ->footer->add() is called.
2223              
2224             active => true
2225              
2226             =head2 Methods
2227              
2228             The following methods can be called from a Mxpress::PDF::Page::Footer Object.
2229              
2230             =head3 add
2231              
2232             Add content to the footer. You can pass any attribute for the footer along with a cb function which will be added to
2233             the onsave_cbs.
2234              
2235             $page->footer->add(
2236             cb => [...],
2237             %footer_atts
2238             );
2239              
2240             =head3 set_position
2241              
2242             Set the position of the footer.
2243              
2244             $page->footer->position($x, $y, $w, $h);
2245              
2246             =head3 process_page_num_text
2247              
2248             Process the page_num_text into printable form.
2249              
2250             $self->header->processs_page_num_text();
2251              
2252             =head3 activate
2253              
2254             Activate the header.
2255              
2256             $page->activate()
2257              
2258             =head1 Plugin
2259              
2260             Mxpress::PDF::Plugin is a base class for plugins, it includes Mxpress::PDF::Utils.
2261              
2262             =head1 Font
2263              
2264             Mxpress::PDF::Plugin::Font extends Mxpress::PDF::Plugin and is for managing pdf fonts.
2265              
2266             You can pass default attributes when instantiating the file object.
2267              
2268             Mxpress::PDF->add_file($filename,
2269             font => { %font_atts },
2270             text => {
2271             font => { %font_attrs }
2272             }
2273             );
2274              
2275             or when calling some objects add methods like Mxpress::PDF::Plugin::Text->add.
2276              
2277             $file->text->add(
2278             font => { %font_attrs },
2279             );
2280              
2281             =head2 Attributes
2282              
2283             The following attributes can be configured for a Mxpress::PDF::Plugin::Font object, they are all optional.
2284              
2285             $font->$attr();
2286              
2287             =head3 colour (is => 'rw', type => Str);
2288              
2289             The font colour.
2290              
2291             =head3 size (is => 'rw', type => Num);
2292              
2293             The font size.
2294              
2295             =head3 family (is => 'rw', type => Str);
2296              
2297             The font family.
2298              
2299             =head3 loaded (is => 'rw', type => HashRef);
2300              
2301             Loaded hashref of PDF::API2 fonts.
2302              
2303             =head3 line_height ( is => 'rw', type => Num);
2304              
2305             Line height of the font.
2306              
2307             =head2 Methods
2308              
2309             The following methods can be called from a Mxpress::PDF::Plugin::Font Object.
2310              
2311             =head3 load
2312              
2313             Load the PDF::API2 font object.
2314              
2315             $font->load()
2316              
2317             =head3 find
2318              
2319             Find a PDF::API2 font object.
2320              
2321             $font->find($famild, $enc?)
2322              
2323             =head1 Border
2324              
2325             Mxpress::PDF::Plugin::Border extends Mxpress::PDF::Plugin::Shape::Line and is for aiding with drawing borders on a Mxpress::PDF::Page.
2326              
2327             You can pass default attributes when instantiating the file object.
2328              
2329             Mxpress::PDF->add_file($filename,
2330             border => { %border_attrs },
2331             );
2332              
2333             or when calling the objects start method.
2334              
2335             $file->border->start(
2336             %border_attrs
2337             );
2338              
2339             =head2 Attributes
2340              
2341             The following attributes can be configured for a Mxpress::PDF::Plugin::Border object, they are all optional.
2342              
2343             $line->$attr();
2344              
2345             =head3 fill_colour (is => 'rw', type => Str);
2346              
2347             The colour of the line.
2348              
2349             $line->fill_colour('#000');
2350              
2351             =head3 border_top (is => 'rw', type => ArrayRef);
2352              
2353             The position of the top border line
2354              
2355             $line->border_top([$x, $y]);
2356              
2357             =head2 Methods
2358              
2359             The following methods can be called from a Mxpress::PDF::Plugin::Border Object.
2360              
2361             =head3 start
2362              
2363             Start the border this will track the current position of the pdf.
2364            
2365             $border->start;
2366              
2367             =head3 end
2368              
2369             Stop the border, this will render the border to the page.
2370              
2371             $border->end;
2372              
2373             =head1 Shape
2374              
2375             Mxpress::PDF::Plugin::Shape extends Mxpress::PDF::Plugin and is the base class for all shape plugins.
2376              
2377             =head1 Line
2378              
2379             Mxpress::PDF::Plugin::Shape::Line extends Mxpress::PDF::Plugin::Shape and is for aiding with drawing lines on a Mxpress::PDF::Page.
2380              
2381             You can pass default attributes when instantiating the file object.
2382              
2383             Mxpress::PDF->add_file($filename,
2384             line => { %line_attrs },
2385             );
2386              
2387             or when calling the objects add method.
2388              
2389             $file->line->add(
2390             %line_attrs
2391             );
2392              
2393             =head2 Attributes
2394              
2395             The following attributes can be configured for a Mxpress::PDF::Plugin::Line object, they are all optional.
2396              
2397             $line->$attr();
2398              
2399             =head3 fill_colour (is => 'rw', type => Str);
2400              
2401             The colour of the line.
2402              
2403             $line->fill_colour('#000');
2404              
2405             =head3 position (is => 'rw', type => ArrayRef);
2406              
2407             The position of the line
2408              
2409             $line->position([$x, $y]);
2410              
2411             =head3 end_position (is => 'rw', type => ArrayRef);
2412              
2413             $line->end_position([$x, $y]);
2414              
2415             =head3 type (is => 'rw', type => Str);
2416              
2417             Sets the type of line style.
2418              
2419             =over
2420              
2421             =item solid
2422              
2423             The default which is a solid line.
2424              
2425             =item dots
2426              
2427             A line built out of dots, equivelant to setting dash as:
2428              
2429             [1, 1]
2430              
2431             =item dashed
2432              
2433             A line built out of dashes, equivelant to setting dash as:
2434              
2435             [5, 5]
2436              
2437             =back
2438              
2439             =head3 dash (is => 'rw', type => ArrayRef);
2440              
2441             The arguments represent alternating dash and gap lengths.
2442              
2443             [10, 10]
2444              
2445             =head3 join (is => 'rw', type => Num);
2446              
2447             Sets the style of join to be used at corners of a path.
2448            
2449             =over
2450            
2451             =item 0 = Miter Join
2452            
2453             The outer edges of the stroke extend until they meet, up to the limit
2454             specified below. If the limit would be surpassed, a bevel join is
2455             used instead.
2456            
2457             =item 1 = Round Join
2458            
2459             A circle with a diameter equal to the linewidth is drawn around the
2460             corner point, producing a rounded corner.
2461            
2462             =item 2 = Bevel Join
2463            
2464             A triangle is drawn to fill in the notch between the two strokes.
2465            
2466             =back
2467              
2468             =head2 Methods
2469              
2470             The following methods can be called from a Mxpress::PDF::Plugin::Shape::Line Object.
2471              
2472             =head3 add
2473              
2474             Add a new line to the current Mxpress::PDF::Page.
2475              
2476             $line->add(%line_args);
2477              
2478             =head1 Box
2479              
2480             Mxpress::PDF::Plugin::Shape::Box extends Mxpress::PDF::Plugin::Shape and is for aiding with drawing boxes on a Mxpress::PDF::Page.
2481              
2482             You can pass default attributes when instantiating the file object.
2483              
2484             Mxpress::PDF->add_file($filename,
2485             box => { %box_attrs },
2486             );
2487              
2488             or when calling the objects add method.
2489              
2490             $file->box->add(
2491             %box_attrs
2492             );
2493              
2494             my $box = $file->box;
2495              
2496             =head2 Attributes
2497              
2498             The following attributes can be configured for a Mxpress::PDF::Plugin::Box object, they are all optional.
2499              
2500             $box->$attr();
2501              
2502             =head3 fill_colour (is => 'rw', type => Str);
2503              
2504             The background colour of the box.
2505              
2506             $box->fill('#000');
2507              
2508             =head3 position (is => 'rw', type => ArrayRef);
2509              
2510             The position of the box.
2511              
2512             $box->position([$x, $y, $w, $h]);
2513              
2514             =head2 Methods
2515              
2516             The following methods can be called from a Mxpress::PDF::Plugin::Shape::Box Object.
2517              
2518             =head3 add
2519              
2520             Add a new box to the current Mxpress::PDF::Page.
2521              
2522             $box->add(%box_attrs);
2523              
2524             =head1 Circle
2525              
2526             Mxpress::PDF::Plugin::Shape::Circle extends Mxpress::PDF::Plugin::Shape and is for aiding with drawing circles on a Mxpress::PDF::Page.
2527              
2528             You can pass default attributes when instantiating the file object.
2529              
2530             Mxpress::PDF->add_file($filename,
2531             circle => { %circle_attrs },
2532             );
2533              
2534             or when calling the objects add method.
2535              
2536             $file->box->add(
2537             %circle_attrs
2538             );
2539              
2540             my $circle = $file->circle;
2541              
2542             =head2 Attributes
2543              
2544             The following attributes can be configured for a Mxpress::PDF::Plugin::Shape::Circle object, they are all optional.
2545              
2546             $circle->$attr();
2547              
2548             =head3 fill_colour (is => 'rw', type => Str);
2549              
2550             The background colour of the circle.
2551              
2552             $circle->fill_colour('#000');
2553              
2554             =head3 radius (is => 'rw', type => Num);
2555              
2556             The radius of the circle. (mm)
2557              
2558             $circle->radius($num);
2559              
2560             =head3 position (is => 'rw', type => ArrayRef);
2561              
2562             The position of the circle. (pt)
2563              
2564             $circle->position([$x, $y, $w, $h]);
2565              
2566             =head2 Methods
2567              
2568             The following methods can be called from a Mxpress::PDF::Plugin::Shape::Circle Object.
2569              
2570             =head3 add
2571              
2572             Add a new circle shape to the current Mxpress::PDF::Page.
2573              
2574             $circle->add(%line_args);
2575              
2576             =head1 Pie
2577              
2578             Mxpress::PDF::Plugin::Shape::Pie extends Mxpress::PDF::Plugin::Shape and is for aiding with drawing pies on a Mxpress::PDF::Page.
2579              
2580             You can pass default attributes when instantiating the file object.
2581              
2582             Mxpress::PDF->add_file($filename,
2583             pie => { %pie_attrs },
2584             );
2585              
2586             or when calling the objects add method.
2587              
2588             $file->pie->add(
2589             %pie_attrs
2590             );
2591              
2592             my $pie = $file->pie;
2593              
2594             =head2 Attributes
2595              
2596             The following attributes can be configured for a Mxpress::PDF::Plugin::Shape::Pie object, they are all optional.
2597              
2598             $pie->$attr();
2599              
2600             =head3 fill_colour (is => 'rw', type => Str);
2601              
2602             The background colour of the pie.
2603              
2604             $pie->fill_colour('#000');
2605              
2606             =head3 radius (is => 'rw', type => Num);
2607              
2608             The radius of the pie.
2609              
2610             $pie->radius($num);
2611              
2612             =head3 start (is => 'rw', type => Num);
2613              
2614             Start percent of the pie.
2615              
2616             $pie->start(180)
2617              
2618             =head3 end (is => 'rw', type => Num);
2619              
2620             End percent of the pie.
2621              
2622             $pie->end(90);
2623              
2624             =head3 position (is => 'rw', type => ArrayRef);
2625              
2626             The position of the pie (pt)
2627              
2628             $pie->position([$x, $y, $w, $h]);
2629              
2630             =head2 Methods
2631              
2632             The following methods can be called from a Mxpress::PDF::Plugin::Shape::Pie Object.
2633              
2634             =head3 add
2635              
2636             Add a new pie shape to the current Mxpress::PDF::Page.
2637              
2638             $pie->add(%pie_attrs);
2639              
2640             =head1 Ellipse
2641              
2642             Mxpress::PDF::Plugin::Shape::Ellipse extends Mxpress::PDF::Plugin::Shape and is for aiding with drawing ellipses on a Mxpress::PDF::Page.
2643              
2644             You can pass default attributes when instantiating the file object.
2645              
2646             Mxpress::PDF->add_file($filename,
2647             ellipse => { %ellise_attrs },
2648             );
2649              
2650             or when calling the objects add method.
2651              
2652             $file->ellipse->add(
2653             %pie_attrs
2654             );
2655              
2656             my $pie = $file->ellipse;
2657              
2658             =head2 Attributes
2659              
2660             The following attributes can be configured for a Mxpress::PDF::Plugin::Shape::Ellipse object, they are all optional.
2661              
2662             $ellipse->$attr();
2663              
2664             =head2 Attributes
2665              
2666             =head3 fill_colour (is => 'rw', type => Str);
2667              
2668             The background colour of the ellipse.
2669              
2670             $ellipse->fill_colour('#000');
2671              
2672             =head3 radius (is => 'rw', type => Num);
2673              
2674             The radius of the ellispe.
2675              
2676             $ellispse->radius($r);
2677              
2678             =head3 start (is => 'rw', type => Num);
2679              
2680             Start percent of the ellipse
2681              
2682             $ellipse->start($p)
2683              
2684             =head3 end (is => 'rw', type => Num);
2685              
2686             End percent of the ellipse.
2687              
2688             $ellipse->end($p);
2689              
2690             =head3 position (is => 'rw', type => ArrayRef);
2691              
2692             The position of the ellipse (pt)
2693              
2694             $pie->position([$x, $y, $w, $h]);
2695              
2696             =head2 Methods
2697              
2698             The following methods can be called from a Mxpress::PDF::Plugin::Shape::Ellipse Object.
2699              
2700             =head3 add
2701              
2702             Add a new ellipse shape to the current Mxpress::PDF::Page.
2703              
2704             $ellipse->add(%ellipse_attrs);
2705              
2706             =head1 Text
2707              
2708             Mxpress::PDF::Plugin::Text extends Mxpress::PDF::Plugin and is for aiding with writing text to a Mxpress::PDF::Page.
2709              
2710             You can pass default attributes when instantiating the file object.
2711              
2712             Mxpress::PDF->add_file($filename,
2713             text => { %text_attrs },
2714             );
2715              
2716             or when calling the objects add method.
2717              
2718             $file->text->add(
2719             %text_attrs
2720             );
2721              
2722             my $text = $file->text;
2723              
2724             =head2 Attributes
2725              
2726             The following attributes can be configured for a Mxpress::PDF::Plugin::Text object, they are all optional.
2727              
2728             $text->$attrs();
2729              
2730             =head3 font (is => 'rw', type => Object);
2731              
2732             An Mxpress::PDF::Plugin::Font object.
2733              
2734             $text->font(Mxpress::PDF->font($file, %font_args));
2735              
2736             =head3 paragraph_space (is => 'rw', type => Num);
2737              
2738             Configure the spacing between paragraphs.
2739              
2740             $text->paragraph_space($mm);
2741              
2742             =head3 paragraphs_to_columns (is => 'rw', type => Bool);
2743              
2744             If true then paragraphs within the passed text string will be split into individual columns.
2745              
2746             $text->paragraphs_to_columns(\1);
2747              
2748             =head3 first_line_indent (is => 'rw', type => Num);
2749              
2750             Indent the first line when rendering given text.
2751              
2752             $text->first_line_indent($mm);
2753              
2754             =head3 first_paragraph_indent (is => 'rw', type => Num);
2755              
2756             Indent the first line when rendering given text.
2757              
2758             $text->first_paragraph_indent($mm);
2759              
2760             =head3 align (is => 'rw', type => Str); #enum
2761              
2762             Align the text on each line. (left|justify|center|right)
2763              
2764             $text->align('justify');
2765              
2766             =head3 margin_bottom (is => 'rw', type => Num);
2767              
2768             Set a bottom margin to be added after text has been rendered.
2769              
2770             $text->margin($mm);
2771              
2772             =head3 indent (is => 'rw', type => Num);
2773              
2774             Set an indent for the block of text.
2775              
2776             $text->indent($mm);
2777              
2778             =head3 pad (is => 'rw', type => Str);
2779              
2780             Pad the passed text to fit the available space, default is undefined.
2781              
2782             $text->pad('.');
2783              
2784             =head3 pad_end (is => 'rw', type => Str);
2785              
2786             Append a string to the padded text.
2787              
2788             $text->pad_end('!');
2789              
2790             =head3 concat (is => 'rw', type => Bool);
2791              
2792             Concatenate the text to the end of the last line/text segmant.
2793              
2794             $text->concat(!!1);
2795              
2796             =head2 Methods
2797              
2798             The following methods can be called from a Mxpress::PDF::Plugin::Text Object.
2799              
2800             =head2 add
2801              
2802             Add a text to the current Mxpress::PDF::Page.
2803              
2804             $text->add($string_of_text, %text_args);
2805              
2806             =head1 Title
2807              
2808             Mxpress::PDF::Plugin::Title extends Mxpress::PDF::Plugin::Text and is for aiding with adding titles to a Mxpress::PDF::Page.
2809              
2810             You can pass default attributes when instantiating the file object.
2811              
2812             Mxpress::PDF->add_file($filename,
2813             title => { %title_attrs },
2814             );
2815              
2816             or when calling the objects add method.
2817              
2818             $file->title->add(
2819             %title_attrs
2820             );
2821              
2822             =head1 Subtitle
2823              
2824             Mxpress::PDF::Plugin::Subtitle extends Mxpress::PDF::Plugin::Text and is for aiding with adding subtitles to a Mxpress::PDF::Page.
2825              
2826             You can pass default attributes when instantiating the file object.
2827              
2828             Mxpress::PDF->add_file($filename,
2829             subtitle => { %subtitle_attrs },
2830             );
2831              
2832             or when calling the objects add method.
2833              
2834             $file->subtitle->add(
2835             %subtitle_attrs
2836             );
2837              
2838             =head1 Subsubtitle
2839              
2840             Mxpress::PDF::Plugin::Subsubtitle extends Mxpress::PDF::Plugin::Text and is for aiding with adding subsubtitles to a Mxpress::PDF::Page.
2841              
2842             You can pass default attributes when instantiating the file object.
2843              
2844             Mxpress::PDF->add_file($filename,
2845             subsubtitle => { %subsubtitle_attrs },
2846             );
2847              
2848             or when calling the objects add method.
2849              
2850             $file->subsubtitle->add(
2851             %subsubtitle_attrs
2852             );
2853              
2854             =head1 H1
2855              
2856             Mxpress::PDF::Plugin::H1 extends Mxpress::PDF::Plugin::Text and is for aiding with adding headings to a Mxpress::PDF::Page.
2857              
2858             You can pass default attributes when instantiating the file object.
2859              
2860             Mxpress::PDF->add_file($filename,
2861             h1 => { %heading_attrs },
2862             );
2863              
2864             or when calling the objects add method.
2865              
2866             $file->h1->add(
2867             %heading_attrs
2868             );
2869              
2870             =head1 H2
2871              
2872             Mxpress::PDF::Plugin::H2 extends Mxpress::PDF::Plugin::Text and is for aiding with adding headings to a Mxpress::PDF::Page.
2873              
2874             You can pass default attributes when instantiating the file object.
2875              
2876             Mxpress::PDF->add_file($filename,
2877             h2 => { %heading_attrs },
2878             );
2879              
2880             or when calling the objects add method.
2881              
2882             $file->h2->add(
2883             %heading_attrs
2884             );
2885              
2886             =head1 H3
2887              
2888             Mxpress::PDF::Plugin::H3 extends Mxpress::PDF::Plugin::Text and is for aiding with adding headings to a Mxpress::PDF::Page.
2889              
2890             You can pass default attributes when instantiating the file object.
2891              
2892             Mxpress::PDF->add_file($filename,
2893             h3 => { %heading_attrs },
2894             );
2895              
2896             or when calling the objects add method.
2897              
2898             $file->h3->add(
2899             %heading_attrs
2900             );
2901              
2902             =head1 H4
2903              
2904             Mxpress::PDF::Plugin::H4 extends Mxpress::PDF::Plugin::Text and is for aiding with adding headings to a Mxpress::PDF::Page.
2905              
2906             You can pass default attributes when instantiating the file object.
2907              
2908             Mxpress::PDF->add_file($filename,
2909             h4 => { %heading_attrs },
2910             );
2911              
2912             or when calling the objects add method.
2913              
2914             $file->h4->add(
2915             %heading_attrs
2916             );
2917              
2918             =head1 H5
2919              
2920             Mxpress::PDF::Plugin::H5 extends Mxpress::PDF::Plugin::Text and is for aiding with adding headings to a Mxpress::PDF::Page.
2921              
2922             You can pass default attributes when instantiating the file object.
2923              
2924             Mxpress::PDF->add_file($filename,
2925             h5 => { %heading_attrs },
2926             );
2927              
2928             or when calling the objects add method.
2929              
2930             $file->h5->add(
2931             %heading_attrs
2932             );
2933              
2934             =head1 H6
2935              
2936             Mxpress::PDF::Plugin::H6 extends Mxpress::PDF::Plugin::Text and is for aiding with adding headings to a Mxpress::PDF::Page.
2937              
2938             You can pass default attributes when instantiating the file object.
2939              
2940             Mxpress::PDF->add_file($filename,
2941             h6 => { %heading_attrs },
2942             );
2943              
2944             or when calling the objects add method.
2945              
2946             $file->h6->add(
2947             %heading_attrs
2948             );
2949              
2950             =head1 List
2951              
2952             Mxpress::PDF::Plugin::List extends Mxpress::PDF::Plugin::Text and is for aiding with adding lists to a Mxpress::PDF::Page.
2953              
2954             You can pass default attributes when instantiating the file object.
2955              
2956             Mxpress::PDF->add_file($filename,
2957             list => { %list_attrs },
2958             );
2959              
2960             or when calling the objects add method.
2961              
2962             $file->list->add(
2963             %list_attrs
2964             );
2965              
2966             =head2 Attributes
2967              
2968             The following attributes can be configured for a Mxpress::PDF::Plugin::List object, they are all optional.
2969              
2970             $list->$attr();
2971              
2972             =head3 type (is => 'rw', type => Str);
2973              
2974             The type of list that will be rendered. The current options are either bullet, for a bullet point list, or number,
2975             for a number ordered list.
2976              
2977             $file->list->type('number');
2978              
2979             =head1 TOC
2980              
2981             Mxpress::PDF::Plugin::TOC extends Mxpress::PDF::Plugin and is for managing a table of contents.
2982              
2983             You can pass default attributes when instantiating the file object.
2984              
2985             Mxpress::PDF->add_file($filename,
2986             toc => { %toc_attrs },
2987             );
2988              
2989             or when calling the objects add method.
2990              
2991             $file->toc->add(
2992             %toc_attrs
2993             );
2994              
2995             my $toc = $file->toc;
2996              
2997             =head2 Attributes
2998              
2999             The following attributes can be configured for a Mxpress::PDF::Plugin::TOC object, they are all optional.
3000              
3001             $toc->$attr();
3002              
3003             =head3 count (is => 'rw', type => Num);
3004              
3005             The current count of toc links
3006              
3007             $file->toc->count;
3008              
3009             =head3 indent (is => 'rw', type => Num);
3010              
3011             The indent used for each level, default is 5.
3012              
3013             $file->toc->indent(0);
3014              
3015             =head3 levels (is => 'rw', type => ArrayRef);
3016              
3017             The levels that can be used for TOC. For now we just have title|subtitle|subsubtitle but this is where you could extend.
3018              
3019             $file->toc->levels;
3020              
3021             =head3 toc_line_offset (is => 'rw', type => Num);
3022              
3023             The line height offset when rendering the table of contents.
3024              
3025             $file->toc_line_offset($mm);
3026              
3027             =head3 font (is => 'rw', type => HashRef);
3028              
3029             Attributes to be used for building the font class for TOC outlines
3030              
3031             $toc->font(\%font_attrs);
3032              
3033             =head2 Methods
3034              
3035             The following methods can be called from a Mxpress::PDF::Plugin::TOC Object.
3036              
3037             =head3 placeholder
3038              
3039             The placeholder position where the table of contents will be rendered.
3040              
3041             $toc->placeholder(%placeholder_attrs);
3042              
3043             =head3 add
3044              
3045             Add to the table of contents
3046              
3047             $toc->add(
3048             title => $title,
3049             %toc_attrs
3050             )
3051              
3052             $toc->add(
3053             subtitle => [$subtitle, %subtitle_attrs]
3054             );
3055              
3056             =head1 TOC Outline
3057              
3058             Mxpress::PDF::Plugin::TOC::Outline extends Mxpress::PDF::Plugin and is for managing a table of content outline.
3059              
3060             my $outline = $file->FACTORY->add_outline()
3061              
3062             =head2 Attributes
3063              
3064             The following attributes can be configured for a Mxpress::PDF::Plugin::TOC::Object object.
3065              
3066             $outline->$attrs();
3067              
3068             =head3 outline (is => 'rw', type => Object);
3069              
3070             The PDF::API2 Outline object.
3071              
3072             $outline->outline;
3073              
3074             =head3 x (is => 'rw', type => Num);
3075              
3076             The x coordinates of the outline.
3077              
3078             $outline->x($x);
3079              
3080             =head3 y (is => 'rw', type => Num);
3081              
3082             The y coordinates of the outline.
3083              
3084             $outline->y($y);
3085              
3086             =head3 title (is => 'rw', type => Str);
3087              
3088             The title text used to render in the table of contents.
3089              
3090             $outline->title($text);
3091              
3092             =head3 page (is => 'rw', type => Object);
3093              
3094             The linked Mxpress::PDF::Page object.
3095              
3096             $ouline->page();
3097              
3098             =head3 level (is => 'rw', type => Num);
3099              
3100             The level of the outline.
3101              
3102             $ouline->level(1);
3103              
3104             =head3 children (is => 'rw', type => ArrayRef);
3105              
3106             An arrarref of linked Mxpress::PDF::Plugin::TOC::Outline objects.
3107              
3108             $ouline->children
3109              
3110             =head1 Image
3111              
3112             Mxpress::PDF::Plugin::Image extends Mxpress::PDF::Plugin and is for adding images to a Mxpress::PDF::Page.
3113              
3114             You can pass default attributes when instantiating the file object.
3115              
3116             Mxpress::PDF->add_file($filename,
3117             image => { %image_attrs },
3118             );
3119              
3120             or when calling the objects add method.
3121              
3122             $file->image->add(
3123             %image_attrs
3124             );
3125              
3126             my $image = $file->image;
3127              
3128             =head2 Attributes
3129              
3130             The following attributes can be configured for a Mxpress::PDF::Plugin::Image object, they are all optional.
3131              
3132             $img->$attrs();
3133              
3134             =head3 width (is => 'rw', type => Num);
3135              
3136             The width of the image.
3137              
3138             $img->width($pt);
3139              
3140             =head3 height (is => 'rw', type => Num);
3141              
3142             The height of the image.
3143              
3144             $img->height($pt);
3145              
3146             =head3 align (is => 'rw', type => Str);
3147              
3148             Align the image - left|center|right
3149              
3150             $img->align('right');
3151              
3152             =head2 Methods
3153              
3154             The following methods can be called from a Mxpress::PDF::Plugin::Image Object.
3155              
3156             =head3 add
3157              
3158             Add an image to the current Mxpress::PDF::Page.
3159              
3160             $img->add($image_fh, $type, %image_attrs)
3161              
3162             or
3163              
3164             $img->add($image_file_path, %image_attrs)
3165              
3166             =head1 Annotation
3167              
3168             Mxpress::PDF::Plugin::Annotation extends Mxpress::PDF::Plugin and is for adding annotations to a
3169             Mxpress::PDF::Page.
3170              
3171             You can pass default attributes when instantiating the file object.
3172              
3173             Mxpress::PDF->add_file($filename,
3174             annotation => { %annotation_attrs },
3175             );
3176              
3177             or when calling the objects add method.
3178              
3179             $file->annotation->add(
3180             %annotation_attrs
3181             );
3182              
3183             my $annotation = $annotation->annotation;
3184              
3185             =head2 Attributes
3186              
3187             The following attributes can be configured for a Mxpress::PDF::Plugin::Annotation object, they are all optional.
3188              
3189             $annotation->$attrs();
3190              
3191             =head3 type (is => 'rw', type => Num)
3192              
3193             The type of annotation text|file|.
3194              
3195             $annotation->type;
3196              
3197             =head3 w (is => 'rw', type => Num)
3198              
3199             The width of the annotation.
3200              
3201             $annotation->w;
3202              
3203             =head3 h (is => 'rw', type => Num)
3204              
3205             The hieght of the annotation.
3206              
3207             $annotation->h;
3208              
3209             =head2 open (is => 'rw', type => Bool)
3210              
3211             Toggle whether annotation is open.
3212              
3213             $annotation->open;
3214              
3215             =head2 Methods
3216              
3217             The following methods can be called from a Mxpress::PDF::Plugin::Annotation Object.
3218              
3219             =head3 add
3220              
3221             Add an annotation to the current Mxpress::PDF::Page.
3222              
3223             $annotation->add('add some text', %annotation_attrs)
3224              
3225             =head1 Form
3226              
3227             Mxpress::PDF::Plugin::Form extends Mxpress::PDF::Plugin and provides access to the PDF AcroForm.
3228              
3229             =head1 Field
3230              
3231             Mxpress::PDF::Plugin::Form::Field extends Mxpress::PDF::Plugin::Text and is the base class for Form 'Fields'.
3232              
3233             =head1 Input
3234              
3235             Mxpress::PDF::Plugin::Form::Field::Input extends Mxpress::PDF::Plugin::Form::Field and is for adding fillable text fields to a Mxpress::PDF::Page
3236              
3237             You can pass default attributes when instantiating the file object.
3238              
3239             Mxpress::PDF->add_file($filename,
3240             field => { %text_attrs },
3241             );
3242              
3243             or when calling the objects add method.
3244              
3245             $file->input->add(
3246             %input_attrs
3247             );
3248              
3249             my $input = $pdf->input
3250              
3251             =head2 Methods
3252              
3253             The following methods can be called from a Mxpress::PDF::Plugin::Form::Field::Input Object.
3254              
3255             =head3 add
3256              
3257             Add a text field to the current Mxpress::PDF::Page.
3258              
3259             $input->add('First Name:', %input_attrs)
3260              
3261             =head1 Textarea
3262              
3263             Mxpress::PDF::Plugin::Form::Field::Input::Textarea extends Mxpress::PDF::Plugin::Form::Field::Input and is for adding fillable multiline textarea fields to a Mxpress::PDF::Page
3264              
3265             You can pass default attributes when instantiating the file object.
3266              
3267             Mxpress::PDF->add_file($filename,
3268             textarea => { %text_attrs },
3269             );
3270              
3271             or when calling the objects add method.
3272              
3273             $file->textarea->add(
3274             %textarea_attrs
3275             );
3276              
3277             my $textarea = $pdf->textarea
3278              
3279             =head2 Methods
3280              
3281             The following methods can be called from a Mxpress::PDF::Plugin::Form::Field::Input::Textarea Object.
3282              
3283             =head3 add
3284              
3285             Add a text field to the current Mxpress::PDF::Page.
3286              
3287             $textarea->add('A Textarea:', lines => 10)
3288              
3289             =head1 Select
3290              
3291             Mxpress::PDF::Plugin::Form::Field::Select extends Mxpress::PDF::Plugin::Form::Field and is for adding interactive select fields to a Mxpress::PDF::Page
3292              
3293             You can pass default attributes when instantiating the file object.
3294              
3295             Mxpress::PDF->add_file($filename,
3296             select => { %select_attrs },
3297             );
3298              
3299             or when calling the objects add method.
3300              
3301             $file->select->add(
3302             %select_attrs
3303             );
3304              
3305             my $select = $pdf->select;
3306              
3307             =head2 Methods
3308              
3309             The following methods can be called from a Mxpress::PDF::Plugin::Form::Field::Select Object.
3310              
3311             =head3 add
3312              
3313             Add a text field to the current Mxpress::PDF::Page.
3314              
3315             $select->add('A Textarea:', options => [qw/a b c/]);
3316              
3317             =head1 AUTHOR
3318              
3319             LNATION, C<< <thisusedtobeanemail at gmail.com> >>
3320              
3321             =head1 BUGS
3322              
3323             Please report any bugs or feature requests to C<bug-mxpress-pdf at rt.cpan.org>, or through
3324             the web interface at L<https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Mxpress-PDF>. I will be notified, and then you'll
3325             automatically be notified of progress on your bug as I make changes.
3326              
3327             =head1 SUPPORT
3328              
3329             You can find documentation for this module with the perldoc command.
3330              
3331             perldoc Mxpress::PDF
3332              
3333             You can also look for information at:
3334              
3335             =over 4
3336              
3337             =item * RT: CPAN's request tracker (report bugs here)
3338              
3339             L<https://rt.cpan.org/NoAuth/Bugs.html?Dist=Mxpress-PDF>
3340              
3341             =item * AnnoCPAN: Annotated CPAN documentation
3342              
3343             L<http://annocpan.org/dist/Mxpress-PDF>
3344              
3345             =item * CPAN Ratings
3346              
3347             L<https://cpanratings.perl.org/d/Mxpress-PDF>
3348              
3349             =item * Search CPAN
3350              
3351             L<https://metacpan.org/release/Mxpress-PDF>
3352              
3353             =back
3354              
3355             =head1 ACKNOWLEDGEMENTS
3356              
3357             =head1 LICENSE AND COPYRIGHT
3358              
3359             This software is Copyright (c) 2020 by LNATION.
3360              
3361             This is free software, licensed under:
3362              
3363             The Artistic License 2.0 (GPL Compatible)
3364              
3365             =cut
3366              
3367             1; # End of Mxpress::PDF