File Coverage

blib/lib/PDF/API2.pm
Criterion Covered Total %
statement 638 1034 61.7
branch 239 590 40.5
condition 55 220 25.0
subroutine 83 119 69.7
pod 89 95 93.6
total 1104 2058 53.6


line stmt bran cond sub pod time code
1             package PDF::API2;
2              
3 39     39   2513046 use strict;
  39         418  
  39         1262  
4 39     39   202 no warnings qw[ deprecated recursion uninitialized ];
  39         66  
  39         1989  
5              
6             our $VERSION = '2.045'; # VERSION
7              
8 39     39   255 use Carp;
  39         79  
  39         2840  
9 39     39   21411 use Encode qw(:all);
  39         394500  
  39         9566  
10 39     39   18062 use English;
  39         132418  
  39         224  
11 39     39   31865 use FileHandle;
  39         366116  
  39         221  
12              
13 39     39   28815 use PDF::API2::Basic::PDF::Utils;
  39         137  
  39         3215  
14 39     39   17690 use PDF::API2::Util;
  39         146  
  39         5380  
15              
16 39     39   24742 use PDF::API2::Basic::PDF::File;
  39         127  
  39         1541  
17 39     39   278 use PDF::API2::Basic::PDF::Pages;
  39         83  
  39         772  
18 39     39   19581 use PDF::API2::Page;
  39         127  
  39         1508  
19              
20 39     39   16705 use PDF::API2::Resource::XObject::Form::Hybrid;
  39         103  
  39         1346  
21              
22 39     39   16812 use PDF::API2::Resource::ExtGState;
  39         115  
  39         1315  
23 39     39   15655 use PDF::API2::Resource::Pattern;
  39         101  
  39         1171  
24 39     39   15395 use PDF::API2::Resource::Shading;
  39         114  
  39         1197  
25              
26 39     39   16174 use PDF::API2::NamedDestination;
  39         99  
  39         1326  
27              
28 39     39   267 use List::Util qw(max);
  39         85  
  39         2496  
29 39     39   253 use Scalar::Util qw(weaken);
  39         77  
  39         518430  
30              
31             my @font_path = __PACKAGE__->set_font_path('/usr/share/fonts',
32             '/usr/local/share/fonts',
33             'c:/windows/fonts');
34              
35             =head1 NAME
36              
37             PDF::API2 - Create, modify, and examine PDF files
38              
39             =head1 SYNOPSIS
40              
41             use PDF::API2;
42              
43             # Create a blank PDF file
44             $pdf = PDF::API2->new();
45              
46             # Open an existing PDF file
47             $pdf = PDF::API2->open('some.pdf');
48              
49             # Add a blank page
50             $page = $pdf->page();
51              
52             # Retrieve an existing page
53             $page = $pdf->open_page($page_number);
54              
55             # Set the page size
56             $page->size('Letter');
57              
58             # Add a built-in font to the PDF
59             $font = $pdf->font('Helvetica-Bold');
60              
61             # Add an external TrueType font to the PDF
62             $font = $pdf->font('/path/to/font.ttf');
63              
64             # Add some text to the page
65             $text = $page->text();
66             $text->font($font, 20);
67             $text->position(200, 700);
68             $text->text('Hello World!');
69              
70             # Save the PDF
71             $pdf->save('/path/to/new.pdf');
72              
73             =head1 INPUT/OUTPUT METHODS
74              
75             =head2 new
76              
77             my $pdf = PDF::API2->new(%options);
78              
79             Create a new PDF.
80              
81             The following options are available:
82              
83             =over
84              
85             =item * file
86              
87             If you will be saving the PDF to disk and already know the filename, you can
88             include it here to open the file for writing immediately. C may also be
89             a filehandle.
90              
91             =item * compress
92              
93             By default, most of the PDF will be compressed to save space. To turn this off
94             (generally only useful for testing or debugging), set C to 0.
95              
96             =back
97              
98             =cut
99              
100             sub new {
101 164     164 1 16353 my ($class, %options) = @_;
102              
103 164         366 my $self = {};
104 164         340 bless $self, $class;
105 164         1145 $self->{'pdf'} = PDF::API2::Basic::PDF::File->new();
106              
107 164         558 $self->{'pdf'}->{' version'} = '1.4';
108 164         964 $self->{'pages'} = PDF::API2::Basic::PDF::Pages->new($self->{'pdf'});
109 164         699 $self->{'pages'}->proc_set(qw(PDF Text ImageB ImageC ImageI));
110 164   33     486 $self->{'pages'}->{'Resources'} ||= PDFDict();
111 164 50       647 $self->{'pdf'}->new_obj($self->{'pages'}->{'Resources'}) unless $self->{'pages'}->{'Resources'}->is_obj($self->{'pdf'});
112 164         407 $self->{'catalog'} = $self->{'pdf'}->{'Root'};
113 164         647 weaken $self->{'catalog'};
114 164         343 $self->{'fonts'} = {};
115 164         343 $self->{'pagestack'} = [];
116              
117             # -compress is deprecated (remove the hyphen)
118 164 100       428 if (exists $options{'-compress'}) {
119 27   33     186 $options{'compress'} //= delete $options{'-compress'};
120             }
121              
122 164 100       422 if (exists $options{'compress'}) {
123 114 50       311 $self->{'forcecompress'} = $options{'compress'} ? 1 : 0;
124             }
125             else {
126 50         106 $self->{'forcecompress'} = 1;
127             }
128 164         1633 $self->preferences(%options);
129              
130             # -file is deprecated (remove the hyphen)
131 164 50 0     461 $options{'file'} //= $options{'-file'} if $options{'-file'};
132              
133 164 50       372 if ($options{'file'}) {
134 0         0 $self->{'pdf'}->create_file($options{'file'});
135 0         0 $self->{'partial_save'} = 1;
136             }
137              
138             # Deprecated; used by info and infoMetaAttributes but not their replacements
139 164         599 $self->{'infoMeta'} = [qw(Author CreationDate ModDate Creator Producer Title
140             Subject Keywords)];
141              
142 164   50     298 my $version = eval { $PDF::API2::VERSION } || 'Development Version';
143 164         954 $self->producer("PDF::API2 $version ($OSNAME)");
144              
145 164         979 return $self;
146             }
147              
148             =head2 open
149              
150             my $pdf = PDF::API2->open('/path/to/file.pdf', %options);
151              
152             Open an existing PDF file.
153              
154             The following option is available:
155              
156             =over
157              
158             =item * compress
159              
160             By default, most of the PDF will be compressed to save space. To turn this off
161             (generally only useful for testing or debugging), set C to 0.
162              
163             =back
164              
165             =cut
166              
167             sub open {
168 8     8 1 1869 my ($class, $file, %options) = @_;
169 8 50       157 croak "File '$file' does not exist" unless -f $file;
170 8 50       111 croak "File '$file' is not readable" unless -r $file;
171              
172 8         29 my $self = {};
173 8         21 bless $self, $class;
174 8         33 foreach my $parameter (keys %options) {
175 2         11 $self->default($parameter, $options{$parameter});
176             }
177              
178 8         94 my $is_writable = -w $file;
179 8         90 $self->{'pdf'} = PDF::API2::Basic::PDF::File->open($file, $is_writable);
180 8         37 _open_common($self, %options);
181 8         19 $self->{'pdf'}->{' fname'} = $file;
182 8 50       25 $self->{'opened_readonly'} = 1 unless $is_writable;
183              
184 8         69 return $self;
185             }
186              
187             sub _open_common {
188 16     16   44 my ($self, %options) = @_;
189              
190 16         88 $self->{'pdf'}->{'Root'}->realise();
191 16   50     82 $self->{'pdf'}->{' version'} ||= '1.3';
192              
193 16         94 $self->{'pages'} = $self->{'pdf'}->{'Root'}->{'Pages'}->realise();
194 16         82 weaken $self->{'pages'};
195 16         82 my @pages = proc_pages($self->{'pdf'}, $self->{'pages'});
196 16         81 $self->{'pagestack'} = [sort { $a->{' pnum'} <=> $b->{' pnum'} } @pages];
  3         16  
197 16         35 weaken $self->{'pagestack'}->[$_] for (0 .. scalar @{$self->{'pagestack'}});
  16         155  
198              
199 16         52 $self->{'catalog'} = $self->{'pdf'}->{'Root'};
200 16         59 weaken $self->{'catalog'};
201              
202 16         40 $self->{'opened'} = 1;
203              
204             # -compress is deprecated (remove the hyphen)
205 16 100       49 if (exists $options{'-compress'}) {
206 2   33     9 $options{'compress'} //= delete $options{'-compress'};
207             }
208              
209 16 100       49 if (exists $options{'compress'}) {
210 2 50       6 $self->{'forcecompress'} = $options{'compress'} ? 1 : 0;
211             }
212             else {
213 14         37 $self->{'forcecompress'} = 1;
214             }
215 16         57 $self->{'fonts'} = {};
216 16         84 $self->{'infoMeta'} = [qw(Author CreationDate ModDate Creator Producer Title Subject Keywords)];
217 16         39 return $self;
218             }
219              
220             =head2 save
221              
222             $pdf->save('/path/to/file.pdf');
223              
224             Write the PDF to disk and close the file. A filename is optional if one was
225             specified while opening or creating the PDF.
226              
227             As a side effect, the document structure is removed from memory when the file is
228             saved, so it will no longer be usable.
229              
230             =cut
231              
232             # Deprecated (renamed)
233 0     0 1 0 sub saveas { return save(@_) } ## no critic
234              
235             sub save {
236 1     1 1 6 my ($self, $file) = @_;
237              
238 1 50 33     7 if ($self->{'partial_save'} and not $file) {
    50          
239 0         0 $self->{'pdf'}->close_file();
240             }
241             elsif ($self->{'opened_scalar'}) {
242 0 0       0 croak 'A filename argument is required' unless $file;
243 0         0 $self->{'pdf'}->append_file();
244 0         0 my $fh;
245 0 0       0 CORE::open($fh, '>', $file) or die "Unable to open $file for writing: $!";
246 0         0 binmode($fh, ':raw');
247 0         0 print $fh ${$self->{'content_ref'}};
  0         0  
248 0         0 CORE::close($fh);
249             }
250             else {
251 1 50       4 croak 'A filename argument is required' unless $file;
252 1 50       6 unless ($self->{'pdf'}->{' fname'}) {
    50          
253 0         0 $self->{'pdf'}->out_file($file);
254             }
255 0         0 elsif ($self->{'pdf'}->{' fname'} eq $file) {
256 1 50       3 croak "File is read-only" if $self->{'opened_readonly'};
257 1         5 $self->{'pdf'}->close_file();
258             }
259             else {
260 0         0 $self->{'pdf'}->clone_file($file);
261 0         0 $self->{'pdf'}->close_file();
262             }
263             }
264              
265             # This can be eliminated once we're confident that circular references are
266             # no longer an issue. See t/circular-references.t.
267 1         7 $self->close();
268              
269 1         3 return;
270             }
271              
272             # Deprecated (use save instead)
273             #
274             # This method allows for objects to be written to disk in advance of finally
275             # saving and closing the file. Otherwise, it's no different than just calling
276             # save when all changes have been made. There's no memory advantage since
277             # ship_out doesn't remove objects from memory.
278             sub finishobjects {
279 0     0 1 0 my ($self, @objs) = @_;
280              
281 0 0       0 if ($self->{'partial_save'}) {
282 0         0 $self->{'pdf'}->ship_out(@objs);
283             }
284              
285 0         0 return;
286             }
287              
288             # Deprecated (use save instead)
289             sub update {
290 0     0 1 0 my $self = shift();
291 0 0       0 croak "File is read-only" if $self->{'opened_readonly'};
292 0         0 $self->{'pdf'}->close_file();
293 0         0 return;
294             }
295              
296             =head2 close
297              
298             $pdf->close();
299              
300             Close an open file (if relevant) and remove the object structure from memory.
301              
302             PDF::API2 contains circular references, so this call is necessary in
303             long-running processes to keep from running out of memory.
304              
305             This will be called automatically when you save or stringify a PDF.
306             You should only need to call it explicitly if you are reading PDF
307             files and not writing them.
308              
309             =cut
310              
311             # Deprecated (renamed)
312 150     150 1 431 sub release { return $_[0]->close() }
313 0     0 1 0 sub end { return $_[0]->close() }
314              
315             sub close {
316 298     298 1 458 my $self = shift();
317 298 100       1401 $self->{'pdf'}->release() if defined $self->{'pdf'};
318              
319 298         838 foreach my $key (keys %$self) {
320 1054         1564 $self->{$key} = undef;
321 1054         1455 delete $self->{$key};
322             }
323              
324 298         813 return;
325             }
326              
327             =head2 from_string
328              
329             my $pdf = PDF::API2->from_string($pdf_string, %options);
330              
331             Read a PDF document contained in a string.
332              
333             The following option is available:
334              
335             =over
336              
337             =item * compress
338              
339             By default, most of the PDF will be compressed to save space. To turn this off
340             (generally only useful for testing or debugging), set C to 0.
341              
342             =back
343              
344             =cut
345              
346             # Deprecated (renamed)
347 1     1 1 8 sub openScalar { return from_string(@_); } ## no critic
348 0     0 1 0 sub open_scalar { return from_string(@_); } ## no critic
349              
350             sub from_string {
351 8     8 1 1618 my ($class, $content, %options) = @_;
352              
353 8         19 my $self = {};
354 8         18 bless $self, $class;
355 8         23 foreach my $parameter (keys %options) {
356 0         0 $self->default($parameter, $options{$parameter});
357             }
358              
359 8         36 $self->{'content_ref'} = \$content;
360 8         15 my $fh;
361 8 50       119 CORE::open($fh, '+<', \$content) or die "Can't begin scalar IO";
362              
363 8         65 $self->{'pdf'} = PDF::API2::Basic::PDF::File->open($fh, 1);
364 8         42 _open_common($self, %options);
365 8         20 $self->{'opened_scalar'} = 1;
366              
367 8         68 return $self;
368             }
369              
370             =head2 to_string
371              
372             my $string = $pdf->to_string();
373              
374             Return the PDF document as a string.
375              
376             As a side effect, the document structure is removed from memory when the string
377             is created, so it will no longer be usable.
378              
379             =cut
380              
381             # Maintainer's note: The object is being destroyed because it contains
382             # (contained?) circular references that would otherwise result in memory not
383             # being freed if the object merely goes out of scope. If possible, the circular
384             # references should be eliminated so that to_string doesn't need to be
385             # destructive. See t/circular-references.t.
386             #
387             # I've opted not to just require a separate call to close() because it would
388             # likely introduce memory leaks in many existing programs that use this module.
389              
390             # Deprecated (renamed)
391 0     0 1 0 sub stringify { return to_string(@_) } ## no critic
392              
393             sub to_string {
394 147     147 1 1103 my $self = shift();
395              
396 147         250 my $string = '';
397 147 100       475 if ($self->{'opened_scalar'}) {
    100          
398 3         13 $self->{'pdf'}->append_file();
399 3         7 $string = ${$self->{'content_ref'}};
  3         16  
400             }
401             elsif ($self->{'opened'}) {
402 4         27 my $fh = FileHandle->new();
403 4 50       235 CORE::open($fh, '>', \$string) || die "Can't begin scalar IO";
404 4         1469 $self->{'pdf'}->clone_file($fh);
405 4         19 $self->{'pdf'}->close_file();
406 4         18 $fh->close();
407             }
408             else {
409 140         806 my $fh = FileHandle->new();
410 140 50   25   7215 CORE::open($fh, '>', \$string) || die "Can't begin scalar IO";
  25         174  
  25         44  
  25         170  
411 140         18197 $self->{'pdf'}->out_file($fh);
412 140         483 $fh->close();
413             }
414              
415             # This can be eliminated once we're confident that circular references are
416             # no longer an issue. See t/circular-references.t.
417 147         1291 $self->close();
418              
419 147         1621 return $string;
420             }
421              
422             =head1 METADATA METHODS
423              
424             =head2 title
425              
426             $title = $pdf->title();
427             $pdf = $pdf->title($title);
428              
429             Get/set/clear the document's title.
430              
431             =cut
432              
433             sub title {
434 0     0 1 0 my $self = shift();
435 0         0 return $self->info_metadata('Title', @_);
436             }
437              
438             =head2 author
439              
440             $author = $pdf->author();
441             $pdf = $pdf->author($author);
442              
443             Get/set/clear the name of the person who created the document.
444              
445             =cut
446              
447             sub author {
448 0     0 1 0 my $self = shift();
449 0         0 return $self->info_metadata('Author', @_);
450             }
451              
452             =head2 subject
453              
454             $subject = $pdf->subject();
455             $pdf = $pdf->subject($subject);
456              
457             Get/set/clear the subject of the document.
458              
459             =cut
460              
461             sub subject {
462 0     0 1 0 my $self = shift();
463 0         0 return $self->info_metadata('Subject', @_);
464             }
465              
466             =head2 keywords
467              
468             $keywords = $pdf->keywords();
469             $pdf = $pdf->keywords($keywords);
470              
471             Get/set/clear a space-separated string of keywords associated with the document.
472              
473             =cut
474              
475             sub keywords {
476 0     0 1 0 my $self = shift();
477 0         0 return $self->info_metadata('Keywords', @_);
478             }
479              
480             =head2 creator
481              
482             $creator = $pdf->creator();
483             $pdf = $pdf->creator($creator);
484              
485             Get/set/clear the name of the product that created the document prior to its
486             conversion to PDF.
487              
488             =cut
489              
490             sub creator {
491 0     0 1 0 my $self = shift();
492 0         0 return $self->info_metadata('Creator', @_);
493             }
494              
495             =head2 producer
496              
497             $producer = $pdf->producer();
498             $pdf = $pdf->producer($producer);
499              
500             Get/set/clear the name of the product that converted the original document to
501             PDF.
502              
503             PDF::API2 fills in this field when creating a PDF.
504              
505             =cut
506              
507             sub producer {
508 169     169 1 305 my $self = shift();
509 169         557 return $self->info_metadata('Producer', @_);
510             }
511              
512             =head2 created
513              
514             $date = $pdf->created();
515             $pdf = $pdf->created($date);
516              
517             Get/set/clear the document's creation date.
518              
519             The date format is C, where C is a static prefix
520             identifying the string as a PDF date. The date may be truncated at any point
521             after the year. C is one of C<+>, C<->, or C, with the following C
522             representing an offset from UTC.
523              
524             When setting the date, C will be prepended automatically if omitted.
525              
526             =cut
527              
528             sub created {
529 1     1 1 3 my $self = shift();
530 1         7 return $self->info_metadata('CreationDate', @_);
531             }
532              
533             =head2 modified
534              
535             $date = $pdf->modified();
536             $pdf = $pdf->modified($date);
537              
538             Get/set/clear the document's modification date. The date format is as described
539             in C above.
540              
541             =cut
542              
543             sub modified {
544 0     0 1 0 my $self = shift();
545 0         0 return $self->info_metadata('ModDate', @_);
546             }
547              
548             sub _is_date {
549 32     32   162 my $value = shift();
550              
551             # PDF 1.7 section 7.9.4 describes the required date format. Other than the
552             # D: prefix and the year, all components are optional but must be present if
553             # a later component is present. No provision is made in the specification
554             # for leap seconds, etc.
555             #
556             # The Adobe PDF specifications (including 1.7) state that the offset minutes
557             # must have a trailing apostrophe. Beginning with the ISO version of the
558             # 1.7 specification, a trailing apostrophe is not permitted after the offset
559             # minutes. For compatibility, we accept either version as valid.
560 32 100       346 return unless $value =~ /^D:([0-9]{4}) # D:YYYY (required)
561             (?:([01][0-9]) # Month (01-12)
562             (?:([0123][0-9]) # Day (01-31)
563             (?:([012][0-9]) # Hour (00-23)
564             (?:([012345][0-9]) # Minute (00-59)
565             (?:([012345][0-9]) # Second (00-59)
566             (?:([Z+-]) # UT Offset Direction
567             (?:([012][0-9])\'? # UT Offset Hours
568             (?:([012345][0-9])\'? # UT Offset Minutes
569             )?)?)?)?)?)?)?)?$/x;
570 22         122 my ($year, $month, $day, $hour, $minute, $second, $od, $oh, $om)
571             = ($1, $2, $3, $4, $5, $6, $7, $8, $9);
572              
573             # Do some basic validation to catch accidental date formatting issues.
574             # Complete date validation is out of scope.
575 22 100       58 if (defined $month) {
576 21 100 66     111 return unless $month >= 1 and $month <= 12;
577             }
578 21 100       44 if (defined $day) {
579 19 100 66     72 return unless $day >= 1 and $day <= 31;
580             }
581 20 100       42 if (defined $hour) {
582 17 100       38 return unless $hour <= 23;
583             }
584 19 100       40 if (defined $minute) {
585 15 50       36 return unless $minute <= 59;
586             }
587 19 100       34 if (defined $second) {
588 14 50       27 return unless $second <= 59;
589             }
590 19 100       37 if (defined $od) {
591 13 50 66     43 return if $od eq 'Z' and defined($oh);
592             }
593 19 100       36 if (defined $oh) {
594 11 100       38 return unless $oh <= 23;
595             }
596 17 100       35 if (defined $om) {
597 6 50       14 return unless $om <= 59;
598             }
599 17 100 100     48 if (defined $oh and $om) {
600             # Apostrophe is required between offset hour and minute
601 6 100       75 return unless $value =~ /$oh\'$om\'?/;
602             }
603              
604 15         72 return 1;
605             }
606              
607             =head2 info_metadata
608              
609             # Get all keys and values
610             %info = $pdf->info_metadata();
611              
612             # Get the value of one key
613             $value = $pdf->info_metadata($key);
614              
615             # Set the value of one key
616             $pdf = $pdf->info_metadata($key, $value);
617              
618             Get/set/clear a key in the document's information dictionary. The standard keys
619             (title, author, etc.) have their own accessors, so this is primarily intended
620             for interacting with custom metadata.
621              
622             Pass C as the value in order to remove the key from the dictionary.
623              
624             =cut
625              
626             sub info_metadata {
627 170     170 1 267 my $self = shift();
628 170         236 my $field = shift();
629              
630             # Return a hash of the Info table if called without arguments
631 170 50       415 unless (defined $field) {
632 0 0       0 return unless exists $self->{'pdf'}->{'Info'};
633 0         0 $self->{'pdf'}->{'Info'}->realise();
634 0         0 my %info;
635 0         0 foreach my $key (keys %{$self->{'pdf'}->{'Info'}}) {
  0         0  
636 0 0       0 next if $key =~ /^ /;
637 0 0       0 next unless defined $self->{'pdf'}->{'Info'}->{$key};
638 0         0 $info{$key} = $self->{'pdf'}->{'Info'}->{$key}->val();
639             }
640 0         0 return %info;
641             }
642              
643             # Set
644 170 100       441 if (@_) {
645 167         285 my $value = shift();
646 167 50 66     734 $value = undef if defined($value) and not length($value);
647              
648 167 100 66     691 if ($field eq 'CreationDate' or $field eq 'ModDate') {
649 1 50       3 if (defined ($value)) {
650 1 50       6 $value = 'D:' . $value unless $value =~ /^D:/;
651 1 50       4 croak "Invalid date string: $value" unless _is_date($value);
652             }
653             }
654              
655 167 100       2065 unless (exists $self->{'pdf'}->{'Info'}) {
656 164 50       3088 return $self unless defined $value;
657 164         506 $self->{'pdf'}->{'Info'} = PDFDict();
658 164         545 $self->{'pdf'}->new_obj($self->{'pdf'}->{'Info'});
659             }
660             else {
661 3         16 $self->{'pdf'}->{'Info'}->realise();
662             }
663              
664 167 100       398 if (defined $value) {
665 166         424 $self->{'pdf'}->{'Info'}->{$field} = PDFStr($value);
666             }
667             else {
668 1         3 delete $self->{'pdf'}->{'Info'}->{$field};
669             }
670              
671 167         354 return $self;
672             }
673              
674             # Get
675 3 50       8 return unless $self->{'pdf'}->{'Info'};
676 3         13 $self->{'pdf'}->{'Info'}->realise();
677 3 100       13 return unless $self->{'pdf'}->{'Info'}->{$field};
678 2         5 return $self->{'pdf'}->{'Info'}->{$field}->val();
679             }
680              
681             # Deprecated; replace with individual accessors or info_metadata
682             sub info {
683 3     3 1 17 my ($self, %opt) = @_;
684              
685 3 50       10 if (not defined($self->{'pdf'}->{'Info'})) {
686 0         0 $self->{'pdf'}->{'Info'} = PDFDict();
687 0         0 $self->{'pdf'}->new_obj($self->{'pdf'}->{'Info'});
688             }
689             else {
690 3         11 $self->{'pdf'}->{'Info'}->realise();
691             }
692              
693             # Maintenance Note: Since we're not shifting at the beginning of
694             # this sub, this "if" will always be true
695 3 50       9 if (scalar @_) {
696 3         4 foreach my $k (@{$self->{'infoMeta'}}) {
  3         8  
697 24 100       45 next unless defined $opt{$k};
698 1   50     4 $self->{'pdf'}->{'Info'}->{$k} = PDFStr($opt{$k} || 'NONE');
699             }
700 3         9 $self->{'pdf'}->out_obj($self->{'pdf'}->{'Info'});
701             }
702              
703 3 50       8 if (defined $self->{'pdf'}->{'Info'}) {
704 3         6 %opt = ();
705 3         3 foreach my $k (@{$self->{'infoMeta'}}) {
  3         8  
706 24 100       47 next unless defined $self->{'pdf'}->{'Info'}->{$k};
707 3         9 $opt{$k} = $self->{'pdf'}->{'Info'}->{$k}->val();
708 3 50 33     23 if ( (unpack('n', $opt{$k}) == 0xfffe)
709             or (unpack('n', $opt{$k}) == 0xfeff))
710             {
711 0         0 $opt{$k} = decode('UTF-16', $self->{'pdf'}->{'Info'}->{$k}->val());
712             }
713             }
714             }
715              
716 3         12 return %opt;
717             }
718              
719             # Deprecated; replace with info_metadata
720             sub infoMetaAttributes {
721 0     0 1 0 my ($self, @attr) = @_;
722              
723 0 0       0 if (scalar @attr) {
724 0         0 my %at = map { $_ => 1 } @{$self->{'infoMeta'}}, @attr;
  0         0  
  0         0  
725 0         0 @{$self->{'infoMeta'}} = keys %at;
  0         0  
726             }
727              
728 0         0 return @{$self->{'infoMeta'}};
  0         0  
729             }
730              
731             =head2 xml_metadata
732              
733             $xml = $pdf->xml_metadata();
734             $pdf = $pdf->xml_metadata($xml);
735              
736             Get/set the document's XML metadata stream.
737              
738             =cut
739              
740             # Deprecated (renamed, changed set return value for consistency)
741             sub xmpMetadata {
742 0     0 1 0 my $self = shift();
743 0 0       0 if (@_) {
744 0         0 my $value = shift();
745 0         0 $self->xml_metadata($value);
746 0         0 return $value;
747             }
748              
749 0         0 return $self->xml_metadata();
750             }
751              
752             sub xml_metadata {
753 0     0 1 0 my ($self, $value) = @_;
754              
755 0 0       0 if (not defined($self->{'catalog'}->{'Metadata'})) {
756 0         0 $self->{'catalog'}->{'Metadata'} = PDFDict();
757 0         0 $self->{'catalog'}->{'Metadata'}->{'Type'} = PDFName('Metadata');
758 0         0 $self->{'catalog'}->{'Metadata'}->{'Subtype'} = PDFName('XML');
759 0         0 $self->{'pdf'}->new_obj($self->{'catalog'}->{'Metadata'});
760             }
761             else {
762 0         0 $self->{'catalog'}->{'Metadata'}->realise();
763 0         0 $self->{'catalog'}->{'Metadata'}->{' stream'} = unfilter($self->{'catalog'}->{'Metadata'}->{'Filter'}, $self->{'catalog'}->{'Metadata'}->{' stream'});
764 0         0 delete $self->{'catalog'}->{'Metadata'}->{' nofilt'};
765 0         0 delete $self->{'catalog'}->{'Metadata'}->{'Filter'};
766             }
767              
768 0         0 my $md = $self->{'catalog'}->{'Metadata'};
769              
770 0 0       0 if (defined $value) {
771 0         0 $md->{' stream'} = $value;
772 0         0 delete $md->{'Filter'};
773 0         0 delete $md->{' nofilt'};
774 0         0 $self->{'pdf'}->out_obj($md);
775 0         0 $self->{'pdf'}->out_obj($self->{'catalog'});
776             }
777              
778 0         0 return $md->{' stream'};
779             }
780              
781             =head2 version
782              
783             $version = $pdf->version($new_version);
784              
785             Get/set the PDF version (e.g. 1.4).
786              
787             =cut
788              
789             sub version {
790 5     5 1 13 my $self = shift();
791 5         13 return $self->{'pdf'}->version(@_);
792             }
793              
794             =head2 is_encrypted
795              
796             $boolean = $pdf->is_encrypted();
797              
798             Returns true if the opened PDF is encrypted.
799              
800             =cut
801              
802             # Deprecated (renamed)
803 0     0 1 0 sub isEncrypted { return is_encrypted(@_) }
804              
805             sub is_encrypted {
806 0     0 1 0 my $self = shift();
807 0 0       0 return defined($self->{'pdf'}->{'Encrypt'}) ? 1 : 0;
808             }
809              
810             =head1 INTERACTIVE FEATURE METHODS
811              
812             =head2 outline
813              
814             $outline = $pdf->outlines();
815              
816             Creates (if needed) and returns the document's outline tree, which is also known
817             as its bookmarks or the table of contents, depending on the PDF reader.
818              
819             To examine or modify the outline tree, see L.
820              
821             =cut
822              
823             # Deprecated (renamed)
824 4     4 1 22 sub outlines { return outline(@_) }
825              
826             sub outline {
827 4     4 1 9 my $self = shift();
828              
829 4         531 require PDF::API2::Outlines;
830 4         13 my $obj = $self->{'pdf'}->{'Root'}->{'Outlines'};
831 4 100       15 if ($obj) {
832 1         4 $obj->realise();
833 1         5 bless $obj, 'PDF::API2::Outlines';
834 1         3 $obj->{' api'} = $self;
835 1         4 weaken $obj->{' api'};
836             }
837             else {
838 3         17 $obj = PDF::API2::Outlines->new($self);
839              
840 3         13 $self->{'pdf'}->{'Root'}->{'Outlines'} = $obj;
841 3 50       14 $self->{'pdf'}->new_obj($obj) unless $obj->is_obj($self->{'pdf'});
842 3         10 $self->{'pdf'}->out_obj($obj);
843 3         8 $self->{'pdf'}->out_obj($self->{'pdf'}->{'Root'});
844             }
845              
846 4         17 return $obj;
847             }
848              
849             =head2 open_action
850              
851             $pdf = $pdf->open_action($page, $location, @args);
852              
853             Set the destination in the PDF that should be displayed when the document is
854             opened.
855              
856             C<$page> may be either a page number or a page object. The other parameters are
857             as described in L.
858              
859             =cut
860              
861             sub open_action {
862 2     2 1 17 my ($self, $page, @args) = @_;
863              
864             # $page can be either a page number or a page object
865 2 100       7 $page = PDFNum($page) unless ref($page);
866              
867 2         8 require PDF::API2::NamedDestination;
868 2         9 my $array = PDF::API2::NamedDestination::_destination($page, @args);
869 2         7 $self->{'catalog'}->{'OpenAction'} = $array;
870 2         7 $self->{'pdf'}->out_obj($self->{'catalog'});
871 2         4 return $self;
872             }
873              
874             =head2 page_layout
875              
876             $layout = $pdf->page_layout();
877             $pdf = $pdf->page_layout($layout);
878              
879             Get/set the page layout that should be used when the PDF is opened.
880              
881             C<$layout> is one of the following:
882              
883             =over
884              
885             =item * single_page (or undef)
886              
887             Display one page at a time.
888              
889             =item * one_column
890              
891             Display the pages in one column (a.k.a. continuous).
892              
893             =item * two_column_left
894              
895             Display the pages in two columns, with odd-numbered pages on the left.
896              
897             =item * two_column_right
898              
899             Display the pages in two columns, with odd-numbered pages on the right.
900              
901             =item * two_page_left
902              
903             Display two pages at a time, with odd-numbered pages on the left.
904              
905             =item * two_page_right
906              
907             Display two pages at a time, with odd-numbered pages on the right.
908              
909             =back
910              
911             =cut
912              
913             sub page_layout {
914 169     169 1 285 my $self = shift();
915              
916 169 50       389 unless (@_) {
917 0 0       0 return 'single_page' unless $self->{'catalog'}->{'PageLayout'};
918 0         0 my $layout = $self->{'catalog'}->{'PageLayout'}->val();
919 0 0       0 return 'single_page' if $layout eq 'SinglePage';
920 0 0       0 return 'one_column' if $layout eq 'OneColumn';
921 0 0       0 return 'two_column_left' if $layout eq 'TwoColumnLeft';
922 0 0       0 return 'two_column_right' if $layout eq 'TwoColumnRight';
923 0 0       0 return 'two_page_left' if $layout eq 'TwoPageLeft';
924 0 0       0 return 'two_page_right' if $layout eq 'TwoPageRight';
925 0         0 warn "Unknown page layout: $layout";
926 0         0 return $layout;
927             }
928              
929 169   50     407 my $name = shift() // 'single_page';
930 169 0       508 my $layout = ($name eq 'single_page' ? 'SinglePage' :
    0          
    0          
    0          
    0          
    50          
931             $name eq 'one_column' ? 'OneColumn' :
932             $name eq 'two_column_left' ? 'TwoColumnLeft' :
933             $name eq 'two_column_right' ? 'TwoColumnRight' :
934             $name eq 'two_page_left' ? 'TwoPageLeft' :
935             $name eq 'two_page_right' ? 'TwoPageRight' : '');
936              
937 169 50       363 croak "Invalid page layout: $name" unless $layout;
938 169         405 $self->{'catalog'}->{'PageLayout'} = PDFName($layout);
939 169         598 $self->{'pdf'}->out_obj($self->{'catalog'});
940 169         307 return $self;
941             }
942              
943             =head2 page_mode
944              
945             # Get
946             $mode = $pdf->page_mode();
947              
948             # Set
949             $pdf = $pdf->page_mode($mode);
950              
951             Get/set the page mode, which describes how the PDF should be displayed when
952             opened.
953              
954             C<$mode> is one of the following:
955              
956             =over
957              
958             =item * none (or undef)
959              
960             Neither outlines nor thumbnails should be displayed.
961              
962             =item * outlines
963              
964             Show the document outline.
965              
966             =item * thumbnails
967              
968             Show the page thumbnails.
969              
970             =item * full_screen
971              
972             Open in full-screen mode, with no menu bar, window controls, or any other window
973             visible.
974              
975             =item * optional_content
976              
977             Show the optional content group panel.
978              
979             =item * attachments
980              
981             Show the attachments panel.
982              
983             =back
984              
985             =cut
986              
987             sub page_mode {
988 169     169 1 321 my $self = shift();
989              
990 169 50       431 unless (@_) {
991 0 0       0 return 'none' unless $self->{'catalog'}->{'PageMode'};
992 0         0 my $mode = $self->{'catalog'}->{'PageMode'}->val();
993 0 0       0 return 'none' if $mode eq 'UseNone';
994 0 0       0 return 'outlines' if $mode eq 'UseOutlines';
995 0 0       0 return 'thumbnails' if $mode eq 'UseThumbs';
996 0 0       0 return 'full_screen' if $mode eq 'FullScreen';
997 0 0       0 return 'optional_content' if $mode eq 'UseOC';
998 0 0       0 return 'attachments' if $mode eq 'UseAttachments';
999 0         0 warn "Unknown page mode: $mode";
1000 0         0 return $mode;
1001             }
1002              
1003 169   50     427 my $name = shift() // 'none';
1004 169 0       434 my $mode = ($name eq 'none' ? 'UseNone' :
    0          
    0          
    0          
    0          
    50          
1005             $name eq 'outlines' ? 'UseOutlines' :
1006             $name eq 'thumbnails' ? 'UseThumbs' :
1007             $name eq 'full_screen' ? 'FullScreen' :
1008             $name eq 'optional_content' ? 'UseOC' :
1009             $name eq 'attachments' ? 'UseAttachments' : '');
1010              
1011 169 50       379 croak "Invalid page mode: $name" unless $mode;
1012 169         471 $self->{'catalog'}->{'PageMode'} = PDFName($mode);
1013 169         581 $self->{'pdf'}->out_obj($self->{'catalog'});
1014 169         325 return $self;
1015             }
1016              
1017             =head2 viewer_preferences
1018              
1019             # Get
1020             %preferences = $pdf->viewer_preferences();
1021              
1022             # Set
1023             $pdf = $pdf->viewer_preferences(%preferences);
1024              
1025             Get or set PDF viewer preferences, as described in
1026             L.
1027              
1028             =cut
1029              
1030             sub viewer_preferences {
1031 172     172 1 267 my $self = shift();
1032 172         14577 require PDF::API2::ViewerPreferences;
1033 172         1006 my $prefs = PDF::API2::ViewerPreferences->new($self);
1034 172 50       833 unless (@_) {
1035 0         0 return $prefs->get_preferences();
1036             }
1037 172         544 return $prefs->set_preferences(@_);
1038             }
1039              
1040             # Deprecated; the various preferences have been split out into their own methods
1041             sub preferences {
1042 169     169 1 517 my ($self, %options) = @_;
1043              
1044             # Page Mode Options
1045 169 50       662 if ($options{'-fullscreen'}) {
    50          
    50          
1046 0         0 $self->page_mode('full_screen');
1047             }
1048             elsif ($options{'-thumbs'}) {
1049 0         0 $self->page_mode('thumbnails');
1050             }
1051             elsif ($options{'-outlines'}) {
1052 0         0 $self->page_mode('outlines');
1053             }
1054             else {
1055 169         465 $self->page_mode('none');
1056             }
1057              
1058             # Page Layout Options
1059 169 50       715 if ($options{'-singlepage'}) {
    50          
    50          
    50          
1060 0         0 $self->page_layout('single_page');
1061             }
1062             elsif ($options{'-onecolumn'}) {
1063 0         0 $self->page_layout('one_column');
1064             }
1065             elsif ($options{'-twocolumnleft'}) {
1066 0         0 $self->page_layout('two_column_left');
1067             }
1068             elsif ($options{'-twocolumnright'}) {
1069 0         0 $self->page_layout('two_column_right');
1070             }
1071             else {
1072 169         477 $self->page_layout('single_page');
1073             }
1074              
1075             # Viewer Preferences
1076 169 50       479 if ($options{'-hidetoolbar'}) {
1077 0         0 $self->viewer_preferences(hide_toolbar => 1);
1078             }
1079 169 50       420 if ($options{'-hidemenubar'}) {
1080 0         0 $self->viewer_preferences(hide_menubar => 1);
1081             }
1082 169 50       366 if ($options{'-hidewindowui'}) {
1083 0         0 $self->viewer_preferences(hide_window_ui => 1);
1084             }
1085 169 50       385 if ($options{'-fitwindow'}) {
1086 0         0 $self->viewer_preferences(fit_window => 1);
1087             }
1088 169 50       378 if ($options{'-centerwindow'}) {
1089 0         0 $self->viewer_preferences(center_window => 1);
1090             }
1091 169 50       318 if ($options{'-displaytitle'}) {
1092 0         0 $self->viewer_preferences(display_doc_title => 1);
1093             }
1094 169 50       358 if ($options{'-righttoleft'}) {
1095 0         0 $self->viewer_preferences(direction => 'r2l');
1096             }
1097              
1098 169 50       486 if ($options{'-afterfullscreenthumbs'}) {
    50          
1099 0         0 $self->viewer_preferences(non_full_screen_page_mode => 'thumbnails');
1100             }
1101             elsif ($options{'-afterfullscreenoutlines'}) {
1102 0         0 $self->viewer_preferences(non_full_screen_page_mode => 'outlines');
1103             }
1104             else {
1105 169         421 $self->viewer_preferences(non_full_screen_page_mode => 'none');
1106             }
1107              
1108 169 50       462 if ($options{'-printscalingnone'}) {
1109 0         0 $self->viewer_preferences(print_scaling => 'none');
1110             }
1111              
1112 169 100       628 if ($options{'-simplex'}) {
    100          
    100          
1113 1         2 $self->viewer_preferences(duplex => 'simplex');
1114             }
1115             elsif ($options{'-duplexfliplongedge'}) {
1116 1         3 $self->viewer_preferences(duplex => 'duplex_long');
1117             }
1118             elsif ($options{'-duplexflipshortedge'}) {
1119 1         2 $self->viewer_preferences(duplex => 'duplex_short');
1120             }
1121              
1122             # Open Action
1123 169 100       357 if ($options{'-firstpage'}) {
1124 2         3 my ($page, %args) = @{$options{'-firstpage'}};
  2         5  
1125 2 50       6 $args{'-fit'} = 1 unless keys %args;
1126              
1127 2 50       5 if (defined $args{'-fit'}) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1128 2         6 $self->open_action($page, 'fit');
1129             }
1130             elsif (defined $args{'-fith'}) {
1131 0         0 $self->open_action($page, 'fith', $args{'-fith'});
1132             }
1133             elsif (defined $args{'-fitb'}) {
1134 0         0 $self->open_action($page, 'fitb');
1135             }
1136             elsif (defined $args{'-fitbh'}) {
1137 0         0 $self->open_action($page, 'fitbh', $args{'-fitbh'});
1138             }
1139             elsif (defined $args{'-fitv'}) {
1140 0         0 $self->open_action($page, 'fitv', $args{'-fitv'});
1141             }
1142             elsif (defined $args{'-fitbv'}) {
1143 0         0 $self->open_action($page, 'fitbv', $args{'-fitbv'});
1144             }
1145             elsif (defined $args{'-fitr'}) {
1146 0         0 $self->open_action($page, 'fitr', @{$args{'-fitr'}});
  0         0  
1147             }
1148             elsif (defined $args{'-xyz'}) {
1149 0         0 $self->open_action($page, 'xyz', @{$args{'-xyz'}});
  0         0  
1150             }
1151             }
1152 169         542 $self->{'pdf'}->out_obj($self->{'catalog'});
1153              
1154 169         297 return $self;
1155             }
1156              
1157             sub proc_pages {
1158 16     16 0 54 my ($pdf, $object) = @_;
1159              
1160 16 50       54 if (defined $object->{'Resources'}) {
1161 16         30 eval {
1162 16         53 $object->{'Resources'}->realise();
1163             };
1164             }
1165              
1166 16         37 my @pages;
1167 16   50     114 $pdf->{' apipagecount'} ||= 0;
1168 16         72 foreach my $page ($object->{'Kids'}->elements()) {
1169 18         61 $page->realise();
1170 18 50       75 if ($page->{'Type'}->val() eq 'Pages') {
1171 0         0 push @pages, proc_pages($pdf, $page);
1172             }
1173             else {
1174 18         38 $pdf->{' apipagecount'}++;
1175 18         50 $page->{' pnum'} = $pdf->{' apipagecount'};
1176 18 50       71 if (defined $page->{'Resources'}) {
1177 18         31 eval {
1178 18         85 $page->{'Resources'}->realise();
1179             };
1180             }
1181 18         55 push @pages, $page;
1182             }
1183             }
1184              
1185 16         62 return @pages;
1186             }
1187              
1188             =head1 PAGE METHODS
1189              
1190             =head2 page
1191              
1192             # Add a page to the end of the document
1193             $page = $pdf->page();
1194              
1195             # Insert a page before the specified page number
1196             $page = $pdf->page($page_number);
1197              
1198             Returns a new page object. By default, the page is added to the end
1199             of the document. If you include an existing page number, the new page
1200             will be inserted in that position, pushing existing pages back.
1201              
1202             If C<$page_number> is -1, the new page is inserted as the second-last page; if
1203             C<$page_number> is 0, the new page is inserted as the last page.
1204              
1205             =cut
1206              
1207             sub page {
1208 142     142 1 19579 my $self = shift();
1209 142   100     527 my $index = shift() || 0;
1210 142         204 my $page;
1211 142 100       329 if ($index == 0) {
1212 140         848 $page = PDF::API2::Page->new($self->{'pdf'}, $self->{'pages'});
1213             }
1214             else {
1215 2         11 $page = PDF::API2::Page->new($self->{'pdf'}, $self->{'pages'}, $index - 1);
1216             }
1217 142         350 $page->{' apipdf'} = $self->{'pdf'};
1218 142         318 $page->{' api'} = $self;
1219 142         443 weaken $page->{' apipdf'};
1220 142         328 weaken $page->{' api'};
1221 142         437 $self->{'pdf'}->out_obj($page);
1222 142         416 $self->{'pdf'}->out_obj($self->{'pages'});
1223 142 100       304 if ($index == 0) {
    50          
1224 140         247 push @{$self->{'pagestack'}}, $page;
  140         329  
1225 140         443 weaken $self->{'pagestack'}->[-1];
1226             }
1227             elsif ($index < 0) {
1228 0         0 splice @{$self->{'pagestack'}}, $index, 0, $page;
  0         0  
1229 0         0 weaken $self->{'pagestack'}->[$index];
1230             }
1231             else {
1232 2         4 splice @{$self->{'pagestack'}}, $index - 1, 0, $page;
  2         5  
1233 2         7 weaken $self->{'pagestack'}->[$index - 1];
1234             }
1235             # $page->{'Resources'} = $self->{'pages'}->{'Resources'};
1236 142         696 return $page;
1237             }
1238              
1239             =head2 open_page
1240              
1241             $page = $pdf->open_page($page_number);
1242              
1243             Returns the L object of page C<$page_number>, if it exists.
1244              
1245             If $page_number is 0 or -1, it will return the last page in the document.
1246              
1247             =cut
1248              
1249             # Deprecated (renamed)
1250 1     1 1 9 sub openpage { return open_page(@_); } ## no critic
1251              
1252             sub open_page {
1253 6     6 1 26 my $self = shift();
1254 6   50     43 my $index = shift() || 0;
1255 6         15 my ($page, $rotate, $media, $trans);
1256              
1257 6 50       35 if ($index == 0) {
    50          
1258 0         0 $page = $self->{'pagestack'}->[-1];
1259             }
1260             elsif ($index < 0) {
1261 0         0 $page = $self->{'pagestack'}->[$index];
1262             }
1263             else {
1264 6         22 $page = $self->{'pagestack'}->[$index - 1];
1265             }
1266 6 50       21 return unless ref($page);
1267              
1268 6 100       66 if (ref($page) ne 'PDF::API2::Page') {
1269 5         23 bless $page, 'PDF::API2::Page';
1270 5         22 $page->{' apipdf'} = $self->{'pdf'};
1271 5         20 $page->{' api'} = $self;
1272 5         35 weaken $page->{' apipdf'};
1273 5         18 weaken $page->{' api'};
1274 5         22 $self->{'pdf'}->out_obj($page);
1275 5 50 33     20 if (($rotate = $page->find_prop('Rotate')) and not $page->{' opened'}) {
1276 0         0 $rotate = ($rotate->val() + 360) % 360;
1277              
1278 0 0 0     0 if ($rotate != 0 and not $self->default('nounrotate')) {
1279 0         0 $page->{'Rotate'} = PDFNum(0);
1280 0         0 foreach my $mediatype (qw(MediaBox CropBox BleedBox TrimBox ArtBox)) {
1281 0 0       0 if ($media = $page->find_prop($mediatype)) {
1282 0         0 $media = [ map { $_->val() } $media->elements() ];
  0         0  
1283             }
1284             else {
1285 0         0 $media = [0, 0, 612, 792];
1286 0 0       0 next if $mediatype ne 'MediaBox';
1287             }
1288 0 0       0 if ($rotate == 90) {
    0          
    0          
1289 0 0       0 $trans = "0 -1 1 0 0 $media->[2] cm" if $mediatype eq 'MediaBox';
1290 0         0 $media = [$media->[1], $media->[0], $media->[3], $media->[2]];
1291             }
1292             elsif ($rotate == 180) {
1293 0 0       0 $trans = "-1 0 0 -1 $media->[2] $media->[3] cm" if $mediatype eq 'MediaBox';
1294             }
1295             elsif ($rotate == 270) {
1296 0 0       0 $trans = "0 1 -1 0 $media->[3] 0 cm" if $mediatype eq 'MediaBox';
1297 0         0 $media = [$media->[1], $media->[0], $media->[3], $media->[2]];
1298             }
1299 0         0 $page->{$mediatype} = PDFArray(map { PDFNum($_) } @$media);
  0         0  
1300             }
1301             }
1302             else {
1303 0         0 $trans = '';
1304             }
1305             }
1306             else {
1307 5         33 $trans = '';
1308             }
1309              
1310 5 100 66     37 if (defined $page->{'Contents'} and not $page->{' opened'}) {
1311 3         15 $page->fixcontents();
1312 3         11 my $uncontent = delete $page->{'Contents'};
1313 3         11 my $content = $page->gfx();
1314 3         17 $content->add(" $trans ");
1315              
1316 3 50       13 if ($self->default('pageencaps')) {
1317 0         0 $content->{' stream'} .= ' q ';
1318             }
1319 3         14 foreach my $k ($uncontent->elements()) {
1320 3         10 $k->realise();
1321 3         18 $content->{' stream'} .= ' ' . unfilter($k->{'Filter'}, $k->{' stream'}) . ' ';
1322             }
1323 3 50       12 if ($self->default('pageencaps')) {
1324 0         0 $content->{' stream'} .= ' Q ';
1325             }
1326              
1327             # if we like compress we will do it now to do quicker saves
1328 3 50       18 if ($self->{'forcecompress'}) {
1329 3         16 $content->{' stream'} = dofilter($content->{'Filter'}, $content->{' stream'});
1330 3         16 $content->{' nofilt'} = 1;
1331 3         7 delete $content->{'-docompress'};
1332 3         13 $content->{'Length'} = PDFNum(length($content->{' stream'}));
1333             }
1334             }
1335 5         13 $page->{' opened'} = 1;
1336             }
1337              
1338 6         71 $self->{'pdf'}->out_obj($page);
1339 6         26 $self->{'pdf'}->out_obj($self->{'pages'});
1340 6         13 $page->{' apipdf'} = $self->{'pdf'};
1341 6         13 $page->{' api'} = $self;
1342 6         21 weaken $page->{' apipdf'};
1343 6         19 weaken $page->{' api'};
1344 6         22 return $page;
1345             }
1346              
1347             =head2 import_page
1348              
1349             $page = $pdf->import_page($source_pdf, $source_page_num, $target_page_num);
1350              
1351             Imports a page from C<$source_pdf> and adds it to the specified position in
1352             C<$pdf>.
1353              
1354             If C<$source_page_num> or C<$target_page_num> is 0, -1, or unspecified, the last
1355             page in the document is used.
1356              
1357             B If you pass a page object instead of a page number for
1358             C<$target_page_num>, the contents of the page will be merged into the existing
1359             page.
1360              
1361             B
1362              
1363             my $pdf = PDF::API2->new();
1364             my $source = PDF::API2->open('source.pdf');
1365              
1366             # Add page 2 from the source PDF as page 1 of the new PDF
1367             my $page = $pdf->import_page($source, 2);
1368              
1369             $pdf->save('sample.pdf');
1370              
1371             B You can only import a page from an existing PDF file.
1372              
1373             =cut
1374              
1375             # Deprecated (renamed)
1376 1     1 1 11 sub importpage { return import_page(@_); } ## no critic
1377              
1378             sub import_page {
1379 1     1 1 3 my ($self, $s_pdf, $s_idx, $t_idx) = @_;
1380 1   50     4 $s_idx ||= 0;
1381 1   50     18 $t_idx ||= 0;
1382 1         5 my ($s_page, $t_page);
1383              
1384 1 50 33     35 unless (ref($s_pdf) and $s_pdf->isa('PDF::API2')) {
1385 0         0 die "Invalid usage: first argument must be PDF::API2 instance, not: " . ref($s_pdf);
1386             }
1387              
1388 1 50       7 if (ref($s_idx) eq 'PDF::API2::Page') {
1389 0         0 $s_page = $s_idx;
1390             }
1391             else {
1392 1         5 $s_page = $s_pdf->open_page($s_idx);
1393 1 50       4 die "Unable to open page '$s_idx' in source PDF" unless defined $s_page;
1394             }
1395              
1396 1 50       5 if (ref($t_idx) eq 'PDF::API2::Page') {
1397 0         0 $t_page = $t_idx;
1398             }
1399             else {
1400 1 50       5 if ($self->pages() < $t_idx) {
1401 0         0 $t_page = $self->page();
1402             }
1403             else {
1404 1         4 $t_page = $self->page($t_idx);
1405             }
1406             }
1407              
1408 1   50     9 $self->{'apiimportcache'} = $self->{'apiimportcache'} || {};
1409 1   50     7 $self->{'apiimportcache'}->{$s_pdf} = $self->{'apiimportcache'}->{$s_pdf} || {};
1410              
1411             # we now import into a form to keep
1412             # all that nasty resources from polluting
1413             # our very own resource naming space.
1414 1         6 my $xo = $self->importPageIntoForm($s_pdf, $s_page);
1415              
1416             # copy all page dimensions
1417 1         4 foreach my $k (qw(MediaBox ArtBox TrimBox BleedBox CropBox)) {
1418 5         11 my $prop = $s_page->find_prop($k);
1419 5 50       12 next unless defined $prop;
1420              
1421 0         0 my $box = walk_obj({}, $s_pdf->{'pdf'}, $self->{'pdf'}, $prop);
1422 0         0 my $method = lc $k;
1423              
1424 0         0 $t_page->$method(map { $_->val() } $box->elements());
  0         0  
1425             }
1426              
1427 1         6 $t_page->gfx->formimage($xo, 0, 0, 1);
1428              
1429             # copy annotations and/or form elements as well
1430 1 0 33     9 if (exists $s_page->{'Annots'} and $s_page->{'Annots'} and $self->{'copyannots'}) {
      0        
1431             # first set up the AcroForm, if required
1432 0         0 my $AcroForm;
1433 0 0       0 if (my $a = $s_pdf->{'pdf'}->{'Root'}->realise->{'AcroForm'}) {
1434 0         0 $a->realise();
1435              
1436 0         0 $AcroForm = walk_obj({}, $s_pdf->{'pdf'}, $self->{'pdf'}, $a, qw(NeedAppearances SigFlags CO DR DA Q));
1437             }
1438 0         0 my @Fields = ();
1439 0         0 my @Annots = ();
1440 0         0 foreach my $a ($s_page->{'Annots'}->elements()) {
1441 0         0 $a->realise();
1442 0         0 my $t_a = PDFDict();
1443 0         0 $self->{'pdf'}->new_obj($t_a);
1444             # these objects are likely to be both annotations and Acroform fields
1445             # key names are copied from PDF Reference 1.4 (Tables)
1446 0         0 my @k = (
1447             qw( Type Subtype Contents P Rect NM M F BS Border AP AS C CA T Popup A AA StructParent Rotate
1448             ), # Annotations - Common (8.10)
1449             qw( Subtype Contents Open Name ), # Text Annotations (8.15)
1450             qw( Subtype Contents Dest H PA ), # Link Annotations (8.16)
1451             qw( Subtype Contents DA Q ), # Free Text Annotations (8.17)
1452             qw( Subtype Contents L BS LE IC ) , # Line Annotations (8.18)
1453             qw( Subtype Contents BS IC ), # Square and Circle Annotations (8.20)
1454             qw( Subtype Contents QuadPoints ), # Markup Annotations (8.21)
1455             qw( Subtype Contents Name ), # Rubber Stamp Annotations (8.22)
1456             qw( Subtype Contents InkList BS ), # Ink Annotations (8.23)
1457             qw( Subtype Contents Parent Open ), # Popup Annotations (8.24)
1458             qw( Subtype FS Contents Name ), # File Attachment Annotations (8.25)
1459             qw( Subtype Sound Contents Name ), # Sound Annotations (8.26)
1460             qw( Subtype Movie Contents A ), # Movie Annotations (8.27)
1461             qw( Subtype Contents H MK ), # Widget Annotations (8.28)
1462             # Printers Mark Annotations (none)
1463             # Trap Network Annotations (none)
1464             );
1465              
1466 0 0       0 push @k, (
1467             qw( Subtype FT Parent Kids T TU TM Ff V DV AA
1468             ), # Fields - Common (8.49)
1469             qw( DR DA Q ), # Fields containing variable text (8.51)
1470             qw( Opt ), # Checkbox field (8.54)
1471             qw( Opt ), # Radio field (8.55)
1472             qw( MaxLen ), # Text field (8.57)
1473             qw( Opt TI I ), # Choice field (8.59)
1474             ) if $AcroForm;
1475              
1476             # sorting out dups
1477 0         0 my %ky = map { $_ => 1 } @k;
  0         0  
1478             # we do P separately, as it points to the page the Annotation is on
1479 0         0 delete $ky{'P'};
1480             # copy everything else
1481 0         0 foreach my $k (keys %ky) {
1482 0 0       0 next unless defined $a->{$k};
1483 0         0 $a->{$k}->realise();
1484 0         0 $t_a->{$k} = walk_obj({}, $s_pdf->{'pdf'}, $self->{'pdf'}, $a->{$k});
1485             }
1486 0         0 $t_a->{'P'} = $t_page;
1487 0         0 push @Annots, $t_a;
1488 0 0 0     0 push @Fields, $t_a if ($AcroForm and $t_a->{'Subtype'}->val() eq 'Widget');
1489             }
1490 0         0 $t_page->{'Annots'} = PDFArray(@Annots);
1491 0 0       0 $AcroForm->{'Fields'} = PDFArray(@Fields) if $AcroForm;
1492 0         0 $self->{'pdf'}->{'Root'}->{'AcroForm'} = $AcroForm;
1493             }
1494 1         4 $t_page->{' imported'} = 1;
1495              
1496 1         8 $self->{'pdf'}->out_obj($t_page);
1497 1         6 $self->{'pdf'}->out_obj($self->{'pages'});
1498              
1499 1         5 return $t_page;
1500             }
1501              
1502             =head2 embed_page
1503              
1504             $xobject = $pdf->embed_page($source_pdf, $source_page_number);
1505              
1506             Returns a Form XObject created by extracting the specified page from a
1507             C<$source_pdf>.
1508              
1509             This is useful if you want to transpose the imported page somewhat differently
1510             onto a page (e.g. two-up, four-up, etc.).
1511              
1512             If $source_page_number is 0 or -1, it will return the last page in the document.
1513              
1514             B
1515              
1516             my $pdf = PDF::API2->new();
1517             my $source = PDF::API2->open('source.pdf');
1518             my $page = $pdf->page();
1519              
1520             # Import Page 2 from the source PDF
1521             my $object = $pdf->embed_page($source, 2);
1522              
1523             # Add it to the new PDF's first page at 1/2 scale
1524             my ($x, $y) = (0, 0);
1525             $page->object($object, $x, $y, 0.5);
1526              
1527             $pdf->save('sample.pdf');
1528              
1529             B You can only import a page from an existing PDF file.
1530              
1531             =cut
1532              
1533             # Deprecated (renamed)
1534 4     4 1 28 sub importPageIntoForm { return embed_page(@_) }
1535              
1536             sub embed_page {
1537 4     4 1 13 my ($self, $s_pdf, $s_idx) = @_;
1538 4   50     12 $s_idx ||= 0;
1539              
1540 4 50 33     57 unless (ref($s_pdf) and $s_pdf->isa('PDF::API2')) {
1541 0         0 croak "Invalid usage: first argument must be PDF::API2 instance, not: " . ref($s_pdf);
1542             }
1543              
1544 4         11 my ($s_page, $xo);
1545              
1546 4         15 $xo = $self->xo_form();
1547              
1548 4 100       17 if (ref($s_idx) eq 'PDF::API2::Page') {
1549 1         3 $s_page = $s_idx;
1550             }
1551             else {
1552 3         18 $s_page = $s_pdf->open_page($s_idx);
1553 3 50       11 croak "Unable to open page $s_idx in source PDF" unless defined $s_page;
1554             }
1555              
1556 4   100     24 $self->{'apiimportcache'} ||= {};
1557 4   100     21 $self->{'apiimportcache'}->{$s_pdf} ||= {};
1558              
1559             # This should never get past MediaBox, since it's a required object.
1560 4         14 foreach my $k (qw(MediaBox ArtBox TrimBox BleedBox CropBox)) {
1561             # next unless defined $s_page->{$k};
1562             # my $box = walk_obj($self->{'apiimportcache'}->{$s_pdf}, $s_pdf->{'pdf'}, $self->{'pdf'}, $s_page->{$k});
1563 12 100       27 next unless defined $s_page->find_prop($k);
1564 2         12 my $box = walk_obj($self->{'apiimportcache'}->{$s_pdf}, $s_pdf->{'pdf'}, $self->{'pdf'}, $s_page->find_prop($k));
1565 2         9 $xo->bbox(map { $_->val() } $box->elements());
  8         20  
1566 2         4 last;
1567             }
1568 4 100       28 $xo->bbox(0, 0, 612, 792) unless defined $xo->{'BBox'};
1569              
1570 4         13 foreach my $k (qw(Resources)) {
1571 4         14 $s_page->{$k} = $s_page->find_prop($k);
1572 4 50       15 next unless defined $s_page->{$k};
1573 4 50       17 $s_page->{$k}->realise() if ref($s_page->{$k}) =~ /Objind$/;
1574              
1575 4         13 foreach my $sk (qw(XObject ExtGState Font ProcSet Properties ColorSpace Pattern Shading)) {
1576 32 100       69 next unless defined $s_page->{$k}->{$sk};
1577 5 50       18 $s_page->{$k}->{$sk}->realise() if ref($s_page->{$k}->{$sk}) =~ /Objind$/;
1578 5         10 foreach my $ssk (keys %{$s_page->{$k}->{$sk}}) {
  5         20  
1579 10 100       37 next if $ssk =~ /^ /;
1580 1         4 $xo->resource($sk, $ssk, walk_obj($self->{'apiimportcache'}->{$s_pdf}, $s_pdf->{'pdf'}, $self->{'pdf'}, $s_page->{$k}->{$sk}->{$ssk}));
1581             }
1582             }
1583             }
1584              
1585             # create a whole content stream
1586             ## technically it is possible to submit an unfinished
1587             ## (eg. newly created) source-page, but that's nonsense,
1588             ## so we expect a page fixed by open_page and die otherwise
1589 4 50       19 unless ($s_page->{' opened'}) {
1590 0         0 croak join(' ',
1591             "Pages may only be imported from a complete PDF.",
1592             "Save and reopen the source PDF object first");
1593             }
1594              
1595 4 100       26 if (defined $s_page->{'Contents'}) {
1596 3         27 $s_page->fixcontents();
1597              
1598 3         7 $xo->{' stream'} = '';
1599             # open_page pages only contain one stream
1600 3         11 my ($k) = $s_page->{'Contents'}->elements();
1601 3         17 $k->realise();
1602 3 50       10 if ($k->{' nofilt'}) {
1603             # we have a finished stream here so we unfilter
1604 3         13 $xo->add('q', unfilter($k->{'Filter'}, $k->{' stream'}), 'Q');
1605             }
1606             else {
1607             # stream is an unfinished/unfiltered content
1608             # so we just copy it and add the required "qQ"
1609 0         0 $xo->add('q', $k->{' stream'}, 'Q');
1610             }
1611 3 50       27 $xo->compressFlate() if $self->{'forcecompress'};
1612             }
1613              
1614 4         25 return $xo;
1615             }
1616              
1617             # Used by embed_page and import_page
1618             sub walk_obj {
1619 16     16 0 29 my ($object_cache, $source_pdf, $target_pdf, $source_object, @keys) = @_;
1620              
1621 16 100       33 if (ref($source_object) =~ /Objind$/) {
1622 1         3 $source_object->realise();
1623             }
1624              
1625 16 50       31 return $object_cache->{scalar $source_object} if defined $object_cache->{scalar $source_object};
1626             # die "infinite loop while copying objects" if $source_object->{' copied'};
1627              
1628 16         31 my $target_object = $source_object->copy($source_pdf); ## thanks to: yaheath // Fri, 17 Sep 2004
1629              
1630             # $source_object->{' copied'} = 1;
1631 16 100       26 $target_pdf->new_obj($target_object) if $source_object->is_obj($source_pdf);
1632              
1633 16         40 $object_cache->{scalar $source_object} = $target_object;
1634              
1635 16 100       53 if (ref($source_object) =~ /Array$/) {
    100          
1636 2         11 $target_object->{' val'} = [];
1637 2         7 foreach my $k ($source_object->elements()) {
1638 8 50       19 $k->realise() if ref($k) =~ /Objind$/;
1639 8         27 $target_object->add_elements(walk_obj($object_cache, $source_pdf, $target_pdf, $k));
1640             }
1641             }
1642             elsif (ref($source_object) =~ /Dict$/) {
1643 1 50       5 @keys = keys(%$target_object) unless scalar @keys;
1644 1         3 foreach my $k (@keys) {
1645 6 100       11 next if $k =~ /^ /;
1646 5 50       9 next unless defined $source_object->{$k};
1647 5         11 $target_object->{$k} = walk_obj($object_cache, $source_pdf, $target_pdf, $source_object->{$k});
1648             }
1649 1 50       9 if ($source_object->{' stream'}) {
1650 0 0       0 if ($target_object->{'Filter'}) {
1651 0         0 $target_object->{' nofilt'} = 1;
1652             }
1653             else {
1654 0         0 delete $target_object->{' nofilt'};
1655 0         0 $target_object->{'Filter'} = PDFArray(PDFName('FlateDecode'));
1656             }
1657 0         0 $target_object->{' stream'} = $source_object->{' stream'};
1658             }
1659             }
1660 16         19 delete $target_object->{' streamloc'};
1661 16         17 delete $target_object->{' streamsrc'};
1662              
1663 16         39 return $target_object;
1664             }
1665              
1666             =head2 page_count
1667              
1668             $integer = $pdf->page_count();
1669              
1670             Return the number of pages in the document.
1671              
1672             =cut
1673              
1674             # Deprecated (renamed)
1675 3     3 1 409 sub pages { return page_count(@_) }
1676              
1677             sub page_count {
1678 3     3 1 6 my $self = shift();
1679 3         4 return scalar @{$self->{'pagestack'}};
  3         17  
1680             }
1681              
1682             =head2 page_labels
1683              
1684             $pdf = $pdf->page_labels($page_number, %options);
1685              
1686             Describes how pages should be numbered beginning at the specified page number.
1687              
1688             # Generate a 30-page PDF
1689             my $pdf = PDF::API2->new();
1690             $pdf->page() for 1..30;
1691              
1692             # Number pages i to v, 1 to 20, and A-1 to A-5, respectively
1693             $pdf->page_labels(1, style => 'roman');
1694             $pdf->page_labels(6, style => 'decimal');
1695             $pdf->page_labels(26, style => 'decimal', prefix => 'A-');
1696              
1697             $pdf->save('sample.pdf');
1698              
1699             The following options are available:
1700              
1701             =over
1702              
1703             =item * style
1704              
1705             One of C (standard decimal arabic numerals), C (uppercase roman
1706             numerals), C (lowercase roman numerals), C (uppercase letters),
1707             or C (lowercase letters).
1708              
1709             There is no default numbering style. If omitted, the page label will be just
1710             the prefix (if set) or an empty string.
1711              
1712             =item * prefix
1713              
1714             The label prefix for pages in this range.
1715              
1716             =item * start
1717              
1718             An integer (default: 1) representing the first value to be used in this page
1719             range.
1720              
1721             =back
1722              
1723             =cut
1724              
1725             # Deprecated; replace with page_labels, updating arguments as shown
1726             sub pageLabel {
1727 8     8 1 58 my $self = shift();
1728 8         20 while (@_) {
1729 8         9 my $page_index = shift();
1730              
1731             # Pass options as a hash rather than a hashref
1732 8   50     12 my %options = %{shift() // {}};
  8         31  
1733              
1734             # Remove leading hyphens from option names
1735 8 100       23 if (exists $options{'-prefix'}) {
1736 1         4 $options{'prefix'} = delete $options{'-prefix'};
1737             }
1738 8 100       19 if (exists $options{'-start'}) {
1739 1         3 $options{'start'} = delete $options{'-start'};
1740             }
1741 8 100       15 if (exists $options{'-style'}) {
1742 6         13 $options{'style'} = delete $options{'-style'};
1743 6 100       28 unless ($options{'style'} =~ /^(?:[Rr]oman|[Aa]lpha|decimal)$/) {
1744 1         150 carp "Invalid -style for page labels; defaulting to decimal";
1745 1         77 $options{'style'} = 'decimal';
1746             }
1747             }
1748              
1749             # page_labels doesn't have a default numbering style, to be consistent
1750             # with the spec.
1751 8   100     22 $options{'style'} //= 'D';
1752              
1753             # Set one set of page labels at a time (support for multiple sets of
1754             # page labels by pageLabel was undocumented). Switch from 0-based to
1755             # 1-based numbering.
1756 8         29 $self->page_labels($page_index + 1, %options);
1757             }
1758              
1759             # Return nothing (page_labels returns $self, matching other setters)
1760 8         18 return;
1761             }
1762              
1763             sub page_labels {
1764 8     8 1 21 my ($self, $page_number, %options) = @_;
1765              
1766             # $page_number is 1-based in order to be consistent with other PDF::API2
1767             # methods, but the page label numbering is 0-based.
1768 8         15 my $page_index = $page_number - 1;
1769              
1770 8   33     43 $self->{'catalog'}->{'PageLabels'} //= PDFDict();
1771 8   33     35 $self->{'catalog'}->{'PageLabels'}->{'Nums'} //= PDFArray();
1772              
1773 8         14 my $nums = $self->{'catalog'}->{'PageLabels'}->{'Nums'};
1774 8         18 $nums->add_elements(PDFNum($page_index));
1775              
1776 8         16 my $d = PDFDict();
1777 8 50       18 if (exists $options{'style'}) {
1778 8 50 33     51 unless ($options{'style'} and $options{'style'} =~ /^([rad])/i) {
1779 0         0 croak 'Invalid page numbering style';
1780             }
1781 8 100       31 $d->{'S'} = PDFName($1 eq 'd' ? 'D' : $1);
1782             }
1783              
1784 8 100       20 if (exists $options{'prefix'}) {
1785 1   50     7 $d->{'P'} = PDFStr($options{'prefix'} // '');
1786             }
1787              
1788 8 100       18 if (exists $options{'start'}) {
1789 1   50     5 $d->{'St'} = PDFNum($options{'start'} // '');
1790             }
1791              
1792 8         19 $nums->add_elements($d);
1793              
1794 8         26 return $self;
1795             }
1796              
1797             =head2 default_page_size
1798              
1799             # Set
1800             $pdf->default_page_size($size);
1801              
1802             # Get
1803             @rectangle = $pdf->default_page_size()
1804              
1805             Set the default physical size for pages in the PDF. If called without
1806             arguments, return the coordinates of the rectangle describing the default
1807             physical page size.
1808              
1809             See L for possible values.
1810              
1811             =cut
1812              
1813             sub default_page_size {
1814 1     1 1 2088 my $self = shift();
1815              
1816             # Set
1817 1 50       5 if (@_) {
1818 1         4 return $self->default_page_boundaries(media => @_);
1819             }
1820              
1821             # Get
1822 0         0 my $boundaries = $self->default_page_boundaries();
1823 0         0 return @{$boundaries->{'media'}};
  0         0  
1824             }
1825              
1826             =head2 default_page_boundaries
1827              
1828             # Set
1829             $pdf->default_page_boundaries(%boundaries);
1830              
1831             # Get
1832             %boundaries = $pdf->default_page_boundaries();
1833              
1834             Set default prepress page boundaries for pages in the PDF. If called without
1835             arguments, returns the coordinates of the rectangles describing each of the
1836             supported page boundaries.
1837              
1838             See the equivalent C method in L for details.
1839              
1840             =cut
1841              
1842             # Called by PDF::API2::Page::boundaries via the default_page_* methods below
1843             sub _bounding_box {
1844 17     17   2055 my $self = shift();
1845 17         34 my $type = shift();
1846              
1847             # Get
1848 17 100       39 unless (scalar @_) {
1849 6 100       16 unless ($self->{'pages'}->{$type}) {
1850 1 50       9 return if $type eq 'MediaBox';
1851              
1852             # Use defaults per PDF 1.7 section 14.11.2 Page Boundaries
1853 0 0       0 return $self->_bounding_box('MediaBox') if $type eq 'CropBox';
1854 0         0 return $self->_bounding_box('CropBox');
1855             }
1856 5         15 return map { $_->val() } $self->{'pages'}->{$type}->elements();
  20         39  
1857             }
1858              
1859             # Set
1860 11         19 $self->{'pages'}->{$type} = PDFArray(map { PDFNum(float($_)) } @_);
  44         92  
1861 11         24 return $self;
1862             }
1863              
1864             sub default_page_boundaries {
1865 3     3 1 4165 return PDF::API2::Page::boundaries(@_);
1866             }
1867              
1868             # Deprecated; use default_page_size or default_page_boundaries
1869             sub mediabox {
1870 5     5 1 19 my $self = shift();
1871 5 100       19 return $self->_bounding_box('MediaBox') unless @_;
1872 3         15 return $self->_bounding_box('MediaBox', page_size(@_));
1873             }
1874              
1875             # Deprecated; use default_page_boundaries
1876             sub cropbox {
1877 1     1 1 2718 my $self = shift();
1878 1 50       4 return $self->_bounding_box('CropBox') unless @_;
1879 1         3 return $self->_bounding_box('CropBox', page_size(@_));
1880             }
1881              
1882             # Deprecated; use default_page_boundaries
1883             sub bleedbox {
1884 1     1 1 2068 my $self = shift();
1885 1 50       5 return $self->_bounding_box('BleedBox') unless @_;
1886 1         5 return $self->_bounding_box('BleedBox', page_size(@_));
1887             }
1888              
1889             # Deprecated; use default_page_boundaries
1890             sub trimbox {
1891 1     1 1 2117 my $self = shift();
1892 1 50       4 return $self->_bounding_box('TrimBox') unless @_;
1893 1         4 return $self->_bounding_box('TrimBox', page_size(@_));
1894             }
1895              
1896             # Deprecated; use default_page_boundaries
1897             sub artbox {
1898 1     1 1 2091 my $self = shift();
1899 1 50       4 return $self->_bounding_box('ArtBox') unless @_;
1900 1         4 return $self->_bounding_box('ArtBox', page_size(@_));
1901             }
1902              
1903             =head1 FONT METHODS
1904              
1905             =head2 font
1906              
1907             my $font = $pdf->font($name, %options)
1908              
1909             Add a font to the PDF. Returns the font object, to be used by
1910             L.
1911              
1912             The font C<$name> is either the name of one of the L
1913             fonts|PDF::API2::Resource::Font::CoreFont/"STANDARD FONTS"> (e.g. Helvetica) or
1914             the path to a font file.
1915              
1916             my $pdf = PDF::API2->new();
1917             my $font1 = $pdf->font('Helvetica-Bold');
1918             my $font2 = $pdf->font('/path/to/ComicSans.ttf');
1919             my $page = $pdf->page();
1920             my $content = $page->text();
1921              
1922             $content->position(1 * 72, 9 * 72);
1923             $content->font($font1, 24);
1924             $content->text('Hello, World!');
1925              
1926             $content->position(0, -36);
1927             $content->font($font2, 12);
1928             $content->text('This is some sample text.');
1929              
1930             $pdf->save('sample.pdf');
1931              
1932             The path can be omitted if the font file is in the current directory or one of
1933             the directories returned by C.
1934              
1935             TrueType (ttf/otf), Adobe PostScript Type 1 (pfa/pfb), and Adobe Glyph Bitmap
1936             Distribution Format (bdf) fonts are supported.
1937              
1938             The following C<%options> are available:
1939              
1940             =over
1941              
1942             =item * format
1943              
1944             The font format is normally detected automatically based on the file's
1945             extension. If you're using a font with an atypical extension, you can set
1946             C to one of C (TrueType or OpenType), C (PostScript
1947             Type 1), or C (Adobe Bitmap).
1948              
1949             =item * kerning
1950              
1951             Kerning (automatic adjustment of space between pairs of characters) is enabled
1952             by default if the font includes this information. Set this option to false to
1953             disable.
1954              
1955             =item * afm_file (PostScript Type 1 fonts only)
1956              
1957             Specifies the location of the font metrics file.
1958              
1959             =item * pfm_file (PostScript Type 1 fonts only)
1960              
1961             Specifies the location of the printer font metrics file. This option overrides
1962             the -encode option.
1963              
1964             =item * embed (TrueType fonts only)
1965              
1966             Fonts are embedded in the PDF by default, which is required to ensure that they
1967             can be viewed properly on a device that doesn't have the font installed. Set
1968             this option to false to prevent the font from being embedded.
1969              
1970             =back
1971              
1972             =cut
1973              
1974             sub font {
1975 1     1 1 10 my ($self, $name, %options) = @_;
1976              
1977 1 50       7 if (exists $options{'kerning'}) {
1978 0         0 $options{'-dokern'} = delete $options{'kerning'};
1979             }
1980              
1981 1         842 require PDF::API2::Resource::Font::CoreFont;
1982 1 50 0     13 if (PDF::API2::Resource::Font::CoreFont->is_standard($name)) {
    0          
1983 1         11 return $self->corefont($name, %options);
1984             }
1985             elsif ($name eq 'Times' and not $options{'format'}) {
1986             # Accept Times as an alias for Times-Roman to follow the pattern set by
1987             # Courier and Helvetica.
1988 0         0 carp "Times is not a standard font; substituting Times-Roman";
1989 0         0 return $self->corefont('Times-Roman', %options);
1990             }
1991              
1992 0         0 my $format = $options{'format'};
1993 0 0 0     0 $format //= ($name =~ /\.[ot]tf$/i ? 'truetype' :
    0          
    0          
1994             $name =~ /\.pf[ab]$/i ? 'type1' :
1995             $name =~ /\.bdf$/i ? 'bitmap' : '');
1996              
1997 0 0       0 if ($format eq 'truetype') {
    0          
    0          
    0          
    0          
1998 0   0     0 $options{'embed'} //= 1;
1999 0         0 return $self->ttfont($name, %options);
2000             }
2001             elsif ($format eq 'type1') {
2002 0 0       0 if (exists $options{'afm_file'}) {
2003 0         0 $options{'-afmfile'} = delete $options{'afm_file'};
2004             }
2005 0 0       0 if (exists $options{'pfm_file'}) {
2006 0         0 $options{'-pfmfile'} = delete $options{'pfm_file'};
2007             }
2008 0         0 return $self->psfont($name, %options);
2009             }
2010             elsif ($format eq 'bitmap') {
2011 0         0 return $self->bdfont($name, %options);
2012             }
2013             elsif ($format) {
2014 0         0 croak "Unrecognized font format: $format";
2015             }
2016             elsif ($name =~ /(\..*)$/) {
2017 0         0 croak "Unrecognized font file extension: $1";
2018             }
2019             else {
2020 0         0 croak "Unrecognized font: $name";
2021             }
2022             }
2023              
2024             =head2 synthetic_font
2025              
2026             $font = $pdf->synthetic_font($base_font, %options)
2027              
2028             Create and return a new synthetic font object. See
2029             L for details.
2030              
2031             =cut
2032              
2033             # Deprecated (renamed)
2034 0     0 1 0 sub synfont { return synthetic_font(@_) }
2035              
2036             sub synthetic_font {
2037 0     0 1 0 my ($self, $font, %opts) = @_;
2038              
2039             # PDF::API2 doesn't set BaseEncoding for TrueType fonts, so text
2040             # isn't searchable unless a ToUnicode CMap is included. Include
2041             # the ToUnicode CMap by default, but allow it to be disabled (for
2042             # performance and file size reasons) by setting -unicodemap to 0.
2043 0 0       0 $opts{-unicodemap} = 1 unless exists $opts{-unicodemap};
2044              
2045 0         0 require PDF::API2::Resource::Font::SynFont;
2046 0         0 my $obj = PDF::API2::Resource::Font::SynFont->new($self->{'pdf'}, $font, %opts);
2047              
2048 0         0 $self->{'pdf'}->out_obj($self->{'pages'});
2049 0 0       0 $obj->tounicodemap() if $opts{-unicodemap};
2050              
2051 0         0 return $obj;
2052             }
2053              
2054             =head2 font_path
2055              
2056             @directories = PDF::API2->font_path()
2057              
2058             Return the list of directories that will be searched (in order) in addition to
2059             the current directory when you add a font to a PDF without including the full
2060             path to the font file.
2061              
2062             =cut
2063              
2064             sub font_path {
2065 0     0 1 0 return @font_path;
2066             }
2067              
2068             =head2 add_to_font_path
2069              
2070             @directories = PDF::API2->add_to_font_path('/my/fonts', '/path/to/fonts');
2071              
2072             Add one or more directories to the list of paths to be searched for font files.
2073              
2074             Returns the font search path.
2075              
2076             =cut
2077              
2078             # Deprecated (renamed)
2079 0     0 1 0 sub addFontDirs { return add_to_font_path(@_) }
2080              
2081             sub add_to_font_path {
2082             # Allow this method to be called using either :: or -> notation.
2083 0 0   0 1 0 shift() if ref($_[0]);
2084 0 0       0 shift() if $_[0] eq __PACKAGE__;
2085              
2086 0         0 push @font_path, @_;
2087 0         0 return @font_path;
2088             }
2089              
2090             =head2 set_font_path
2091              
2092             @directories = PDF::API2->set_font_path('/my/fonts', '/path/to/fonts');
2093              
2094             Replace the existing font search path. This should only be necessary if you
2095             need to remove a directory from the path for some reason, or if you need to
2096             reorder the list.
2097              
2098             Returns the font search path.
2099              
2100             =cut
2101              
2102             sub set_font_path {
2103             # Allow this method to be called using either :: or -> notation.
2104 39 50   39 1 214 shift() if ref($_[0]);
2105 39 50       223 shift() if $_[0] eq __PACKAGE__;
2106              
2107 39         123 @font_path = ((map { "$_/PDF/API2/fonts" } @INC), @_);
  429         959  
2108              
2109 39         183 return @font_path;
2110             }
2111              
2112             sub _find_font {
2113 0     0   0 my $font = shift();
2114              
2115             # Check the current directory
2116 0 0       0 return $font if -f $font;
2117              
2118             # Check the font search path
2119 0         0 foreach my $directory (@font_path) {
2120 0 0       0 return "$directory/$font" if -f "$directory/$font";
2121             }
2122              
2123 0         0 return;
2124             }
2125              
2126             sub corefont {
2127 53     53 1 26381 my ($self, $name, %opts) = @_;
2128 53         4076 require PDF::API2::Resource::Font::CoreFont;
2129 53         426 my $obj = PDF::API2::Resource::Font::CoreFont->new($self->{'pdf'}, $name, %opts);
2130 53         400 $self->{'pdf'}->out_obj($self->{'pages'});
2131 53 50       182 $obj->tounicodemap() if $opts{-unicodemap};
2132 53         485 return $obj;
2133             }
2134              
2135             sub psfont {
2136 0     0 1 0 my ($self, $psf, %opts) = @_;
2137              
2138 0         0 foreach my $o (qw(-afmfile -pfmfile)) {
2139 0 0       0 next unless defined $opts{$o};
2140 0         0 $opts{$o} = _find_font($opts{$o});
2141             }
2142 0 0       0 $psf = _find_font($psf) or croak "Unable to find font \"$psf\"";
2143 0         0 require PDF::API2::Resource::Font::Postscript;
2144 0         0 my $obj = PDF::API2::Resource::Font::Postscript->new($self->{'pdf'}, $psf, %opts);
2145              
2146 0         0 $self->{'pdf'}->out_obj($self->{'pages'});
2147 0 0       0 $obj->tounicodemap() if $opts{-unicodemap};
2148              
2149 0         0 return $obj;
2150             }
2151              
2152             sub ttfont {
2153 0     0 1 0 my ($self, $name, %opts) = @_;
2154              
2155             # PDF::API2 doesn't set BaseEncoding for TrueType fonts, so text
2156             # isn't searchable unless a ToUnicode CMap is included. Include
2157             # the ToUnicode CMap by default, but allow it to be disabled (for
2158             # performance and file size reasons) by setting -unicodemap to 0.
2159 0 0       0 $opts{-unicodemap} = 1 unless exists $opts{-unicodemap};
2160              
2161             # -noembed is deprecated (replace with embed => 0)
2162 0 0       0 if ($opts{'-noembed'}) {
2163 0   0     0 $opts{'embed'} //= 1;
2164             }
2165 0   0     0 $opts{'embed'} //= 1;
2166              
2167 0 0       0 my $file = _find_font($name) or croak "Unable to find font \"$name\"";
2168 0         0 require PDF::API2::Resource::CIDFont::TrueType;
2169 0         0 my $obj = PDF::API2::Resource::CIDFont::TrueType->new($self->{'pdf'}, $file, %opts);
2170              
2171 0         0 $self->{'pdf'}->out_obj($self->{'pages'});
2172 0 0       0 $obj->tounicodemap() if $opts{-unicodemap};
2173              
2174 0         0 return $obj;
2175             }
2176              
2177             sub bdfont {
2178 0     0 1 0 my ($self, @opts) = @_;
2179              
2180 0         0 require PDF::API2::Resource::Font::BdFont;
2181 0         0 my $obj = PDF::API2::Resource::Font::BdFont->new($self->{'pdf'}, @opts);
2182              
2183 0         0 $self->{'pdf'}->out_obj($self->{'pages'});
2184             # $obj->tounicodemap(); # does not support Unicode
2185              
2186 0         0 return $obj;
2187             }
2188              
2189             # Deprecated. Use Unicode-supporting TrueType fonts instead.
2190             # See PDF::API2::Resource::CIDFont::CJKFont for details.
2191             sub cjkfont {
2192 1     1 1 6 my ($self, $name, %opts) = @_;
2193              
2194 1         460 require PDF::API2::Resource::CIDFont::CJKFont;
2195 1         12 my $obj = PDF::API2::Resource::CIDFont::CJKFont->new($self->{'pdf'}, $name, %opts);
2196              
2197 1         8 $self->{'pdf'}->out_obj($self->{'pages'});
2198 1 50       3 $obj->tounicodemap() if $opts{-unicodemap};
2199              
2200 1         6 return $obj;
2201             }
2202              
2203             # Deprecated. Use Unicode-supporting TrueType fonts instead.
2204             sub unifont {
2205 1     1 1 12 my ($self, @opts) = @_;
2206              
2207 1         556 require PDF::API2::Resource::UniFont;
2208 1         9 my $obj = PDF::API2::Resource::UniFont->new($self->{'pdf'}, @opts);
2209              
2210 1         3 return $obj;
2211             }
2212              
2213             =head1 GRAPHICS METHODS
2214              
2215             =head2 image
2216              
2217             $object = $pdf->image($file, %options);
2218              
2219             Import a supported image type and return an object that can be placed as part of
2220             a page's content:
2221              
2222             my $pdf = PDF::API2->new();
2223             my $page = $pdf->page();
2224              
2225             my $image = $pdf->image('/path/to/image.jpg');
2226             $page->object($image, 100, 100);
2227              
2228             $pdf->save('sample.pdf');
2229              
2230             C<$file> may be either a file name, a filehandle, or a L object.
2231              
2232             See L for details about placing images on a page
2233             once they're imported.
2234              
2235             The image format is normally detected automatically based on the file's
2236             extension. If passed a filehandle, image formats GIF, JPEG, and PNG will be
2237             detected based on the file's header.
2238              
2239             If the file has an atypical extension or the filehandle is for a different kind
2240             of image, you can set the C option to one of the supported types:
2241             C, C, C, C, or C.
2242              
2243             Note: PNG images that include an alpha (transparency) channel go through a
2244             relatively slow process of splitting the image into separate RGB and alpha
2245             components as is required by images in PDFs. If you're having performance
2246             issues, install PDF::API2::XS or Image::PNG::Libpng to speed this process up by
2247             an order of magnitude; either module will be used automatically if available.
2248              
2249             =cut
2250              
2251             sub image {
2252 3     3 1 192 my ($self, $file, %options) = @_;
2253              
2254 3   50     29 my $format = lc($options{'format'} // '');
2255              
2256 3 50       23 if (ref($file) eq 'GD::Image') {
    50          
2257 0         0 return $self->image_gd($file, %options);
2258             }
2259             elsif (ref($file)) {
2260 3   33     20 $format ||= _detect_image_format($file);
2261             }
2262 3 50       16 unless (ref($file)) {
2263 0 0 0     0 $format ||= ($file =~ /\.jpe?g$/i ? 'jpeg' :
    0          
    0          
    0          
    0          
2264             $file =~ /\.png$/i ? 'png' :
2265             $file =~ /\.gif$/i ? 'gif' :
2266             $file =~ /\.tiff?$/i ? 'tiff' :
2267             $file =~ /\.p[bgp]m$/i ? 'pnm' : '');
2268             }
2269              
2270 3 100       19 if ($format eq 'jpeg') {
    100          
    50          
    0          
    0          
    0          
    0          
    0          
2271 1         6 return $self->image_jpeg($file, %options);
2272             }
2273             elsif ($format eq 'png') {
2274 1         6 return $self->image_png($file, %options);
2275             }
2276             elsif ($format eq 'gif') {
2277 1         5 return $self->image_gif($file, %options);
2278             }
2279             elsif ($format eq 'tiff') {
2280 0         0 return $self->image_tiff($file, %options);
2281             }
2282             elsif ($format eq 'pnm') {
2283 0         0 return $self->image_pnm($file, %options);
2284             }
2285             elsif ($format) {
2286 0         0 croak "Unrecognized image format: $format";
2287             }
2288             elsif (ref($file)) {
2289 0         0 croak "Unspecified image format";
2290             }
2291             elsif ($file =~ /(\..*)$/) {
2292 0         0 croak "Unrecognized image extension: $1";
2293             }
2294             else {
2295 0         0 croak "Unrecognized image: $file";
2296             }
2297             }
2298              
2299             sub _detect_image_format {
2300 3     3   8 my $fh = shift();
2301 3         28 $fh->seek(0, 0);
2302 3         52 binmode $fh, ':raw';
2303              
2304 3         7 my $test;
2305 3         21 my $bytes_read = $fh->read($test, 8);
2306 3         84 $fh->seek(0, 0);
2307 3 50 33     63 return unless $bytes_read and $bytes_read == 8;
2308              
2309 3 100       21 return 'gif' if $test =~ /^GIF\d\d[a-z]/;
2310 2 100       15 return 'jpeg' if $test =~ /^\xFF\xD8\xFF/;
2311 1 50       8 return 'png' if $test =~ /^\x89PNG\x0D\x0A\x1A\x0A/;
2312 0         0 return;
2313             }
2314              
2315             sub image_jpeg {
2316 3     3 1 19 my ($self, $file, %opts) = @_;
2317              
2318 3         504 require PDF::API2::Resource::XObject::Image::JPEG;
2319 3         22 my $obj = PDF::API2::Resource::XObject::Image::JPEG->new($self->{'pdf'}, $file);
2320              
2321 2         12 $self->{'pdf'}->out_obj($self->{'pages'});
2322              
2323 2         21 return $obj;
2324             }
2325              
2326             sub image_tiff {
2327 4     4 1 59 my ($self, $file, %opts) = @_;
2328              
2329 4         411 require PDF::API2::Resource::XObject::Image::TIFF;
2330 4         24 my $obj = PDF::API2::Resource::XObject::Image::TIFF->new($self->{'pdf'}, $file);
2331              
2332 3         15 $self->{'pdf'}->out_obj($self->{'pages'});
2333              
2334 3         19 return $obj;
2335             }
2336              
2337             sub image_pnm {
2338 3     3 1 57 my ($self, $file, %opts) = @_;
2339              
2340 3   66     14 $opts{'-compress'} //= $self->{'forcecompress'};
2341              
2342 3         448 require PDF::API2::Resource::XObject::Image::PNM;
2343 3         22 my $obj = PDF::API2::Resource::XObject::Image::PNM->new($self->{'pdf'}, $file, %opts);
2344              
2345 2         7 $self->{'pdf'}->out_obj($self->{'pages'});
2346              
2347 2         14 return $obj;
2348             }
2349              
2350             sub image_png {
2351 5     5 1 21 my ($self, $file, %opts) = @_;
2352              
2353 5         493 require PDF::API2::Resource::XObject::Image::PNG;
2354 5         36 my $obj = PDF::API2::Resource::XObject::Image::PNG->new($self->{'pdf'}, $file);
2355              
2356 4         37 $self->{'pdf'}->out_obj($self->{'pages'});
2357              
2358 4         44 return $obj;
2359             }
2360              
2361             sub image_gif {
2362 3     3 1 17 my ($self, $file, %opts) = @_;
2363              
2364 3         495 require PDF::API2::Resource::XObject::Image::GIF;
2365 3         60 my $obj = PDF::API2::Resource::XObject::Image::GIF->new($self->{'pdf'}, $file);
2366              
2367 2         10 $self->{'pdf'}->out_obj($self->{'pages'});
2368              
2369 2         20 return $obj;
2370             }
2371              
2372             sub image_gd {
2373 0     0 1 0 my ($self, $gd, %opts) = @_;
2374              
2375 0         0 require PDF::API2::Resource::XObject::Image::GD;
2376 0         0 my $obj = PDF::API2::Resource::XObject::Image::GD->new($self->{'pdf'}, $gd, undef, %opts);
2377              
2378 0         0 $self->{'pdf'}->out_obj($self->{'pages'});
2379              
2380 0         0 return $obj;
2381             }
2382              
2383             =head2 barcode
2384              
2385             $object = $pdf->barcode($format, $code, %options);
2386              
2387             Generate and return a barcode that can be placed as part of a page's content:
2388              
2389             my $pdf = PDF::API2->new();
2390             my $page = $pdf->page();
2391              
2392             my $barcode = $pdf->barcode('ean13', '0123456789012');
2393             $page->object($barcode, 100, 100);
2394              
2395             my $qr_code = $pdf->barcode('qr', 'http://www.example.com');
2396             $page->object($qr_code, 100, 300, 144 / $qr_code->width())
2397              
2398             $pdf->save('sample.pdf');
2399              
2400             C<$format> can be one of C, C, C (a.k.a. 3 of 9),
2401             C, C, C (a.k.a. interleaved 2 of 5), or C.
2402              
2403             C<$code> is the value to be encoded. Start and stop characters are only
2404             required when they're not static (e.g. for Codabar).
2405              
2406             The following options are available:
2407              
2408             =over
2409              
2410             =item * bar_width
2411              
2412             The width of the smallest bar or space in points (72 points = 1 inch).
2413              
2414             If you're following a specification that gives bar width in mils (thousandths of
2415             an inch), use this conversion: C<$points = $mils / 1000 * 72>.
2416              
2417             =item * bar_height
2418              
2419             The base height of the barcode in points.
2420              
2421             =item * bar_extend
2422              
2423             If present and applicable, bars for non-printing characters (e.g. start and stop
2424             characters) will be extended downward by this many points, and printing
2425             characters will be shown below their respective bars.
2426              
2427             This is enabled by default for EAN-13 barcodes.
2428              
2429             =item * caption
2430              
2431             If present, this value will be printed, centered, beneath the barcode, and
2432             should be a human-readable representation of the barcode. This option is
2433             ignored for QR codes.
2434              
2435             =item * font
2436              
2437             A font object (created by L) that will be used to print the caption, or
2438             the printable characters when C is set.
2439              
2440             Helvetica will be used by default.
2441              
2442             =item * font_size
2443              
2444             The size of the font used for printing the caption or printable characters.
2445              
2446             The default will be calculated based on the barcode size, if C is
2447             set, or 10 otherwise.
2448              
2449             =item * quiet_zone
2450              
2451             A margin, in points, that will be place before the left and bottom edges of the
2452             barcode (including the caption, if present). This is used to help barcode
2453             scanners tell where the barcode begins and ends.
2454              
2455             The default is the width of one encoded character, or four squares for QR codes.
2456              
2457             =item * bar_overflow
2458              
2459             Shrinks the horizontal width of bars by this amount in points to account for ink
2460             spread when printing. This option is ignored for QR codes.
2461              
2462             The default is 0.01 points.
2463              
2464             =item * color
2465              
2466             Draw bars using this color, which may be any value accepted by
2467             L.
2468              
2469             The default is black.
2470              
2471             =back
2472              
2473             QR codes have
2474             L for
2475             customizing the error correction level and other niche settings.
2476              
2477             =cut
2478              
2479             sub barcode {
2480 0     0 1 0 my ($self, $format, $value, %options) = @_;
2481 0 0       0 croak "Missing barcode format" unless defined $format;
2482 0 0       0 croak "Missing barcode value" unless defined $value;
2483              
2484             # Set defaults to approximately the minimums for each barcode format.
2485 0 0 0     0 if ($format eq 'codabar') {
    0 0        
    0          
    0          
    0          
2486 0   0     0 $options{'bar_width'} //= 1.8; # 0.025"
2487 0   0     0 $options{'bar_extend'} //= 0;
2488 0   0     0 $options{'quiet_zone'} //= 10 * $options{'bar_width'};
2489 0 0       0 if ($options{'bar_extend'}) {
2490 0   0     0 $options{'font_size'} //= 9 * $options{'bar_width'};
2491             }
2492              
2493             # Minimum height is the larger of 0.25" or 15% of barcode length.
2494 0         0 my $length = (10 * length($value) + 2) * $options{'bar_width'};
2495 0   0     0 $options{'bar_height'} //= max(18, $length * 0.15);
2496             }
2497             elsif ($format eq 'code128' or $format eq 'ean128' or $format eq 'code39') {
2498 0   0     0 $options{'bar_width'} //= 1;
2499 0   0     0 $options{'bar_extend'} //= 0;
2500 0   0     0 $options{'quiet_zone'} //= 11 * $options{'bar_width'};
2501 0 0       0 if ($options{'bar_extend'}) {
2502 0   0     0 $options{'font_size'} //= 10 * $options{'bar_width'};
2503             }
2504              
2505             # Minimum height is the larger of 0.5" or 15% of barcode length.
2506 0         0 my $length = 11 * (length($value) + 1) * $options{'bar_width'};
2507 0   0     0 $options{'bar_height'} //= max(36, $length * 0.15);
2508             }
2509             elsif ($format eq 'itf') {
2510 0   0     0 $options{'bar_width'} //= 1;
2511 0   0     0 $options{'bar_height'} //= 40;
2512 0   0     0 $options{'bar_extend'} //= 0;
2513 0   0     0 $options{'quiet_zone'} //= 10 * $options{'bar_width'};
2514 0 0       0 if ($options{'bar_extend'}) {
2515 0   0     0 $options{'font_size'} //= 9 * $options{'bar_width'};
2516             }
2517             }
2518             elsif ($format eq 'ean13') {
2519 0   0     0 $options{'bar_width'} //= 1;
2520 0   0     0 $options{'bar_height'} //= 64.8;
2521 0   0     0 $options{'quiet_zone'} //= 11 * $options{'bar_width'};
2522 0 0       0 unless ($options{'caption'}) {
2523 0   0     0 $options{'bar_extend'} //= 5 * $options{'bar_width'};
2524             }
2525 0 0       0 if ($options{'bar_extend'}) {
2526 0   0     0 $options{'font_size'} //= 10 * $options{'bar_width'};
2527             }
2528             }
2529             elsif ($format eq 'qr') {
2530 0   0     0 $options{'bar_width'} //= 1;
2531 0   0     0 $options{'bar_height'} //= $options{'bar_width'};
2532 0   0     0 $options{'quiet_zone'} //= 4 * $options{'bar_width'};
2533             }
2534             else {
2535 0         0 croak "Unrecognized barcode format: $format";
2536             }
2537              
2538 0 0       0 if (exists $options{'caption'}) {
2539 0   0     0 $options{'font_size'} //= 10;
2540             }
2541 0 0 0     0 if ($options{'bar_extend'} or $options{'font_size'}) {
2542 0   0     0 $options{'font'} //= $self->font('Helvetica');
2543             }
2544              
2545             # Convert from new arguments to old arguments
2546 0         0 $options{'-color'} = delete $options{'color'};
2547 0         0 $options{'-fnsz'} = delete $options{'font_size'};
2548 0         0 $options{'-font'} = delete $options{'font'};
2549 0         0 $options{'-lmzn'} = delete $options{'bar_extend'};
2550 0         0 $options{'-mils'} = (delete $options{'bar_width'}) * 1000 / 72;
2551 0         0 $options{'-ofwt'} = delete $options{'bar_overflow'};
2552 0         0 $options{'-quzn'} = delete $options{'quiet_zone'};
2553 0         0 $options{'-zone'} = delete $options{'bar_height'};
2554              
2555 0 0       0 if ($format eq 'codabar') {
    0          
    0          
    0          
    0          
    0          
    0          
2556 0         0 return $self->xo_codabar(%options, -code => $value);
2557             }
2558             elsif ($format eq 'code128') {
2559 0         0 return $self->xo_code128(%options, -code => $value);
2560             }
2561             elsif ($format eq 'code39') {
2562 0         0 return $self->xo_3of9(%options, -code => $value);
2563             }
2564             elsif ($format eq 'ean128') {
2565 0         0 return $self->xo_code128(%options, -code => $value, -ean => 1);
2566             }
2567             elsif ($format eq 'ean13') {
2568 0         0 return $self->xo_ean13(%options, -code => $value);
2569             }
2570             elsif ($format eq 'itf') {
2571 0         0 return $self->xo_2of5int(%options, -code => $value);
2572             }
2573             elsif ($format eq 'qr') {
2574 0         0 my $qr_class = 'PDF::API2::Resource::XObject::Form::BarCode::qrcode';
2575 0         0 eval "require $qr_class";
2576 0         0 my $obj = $qr_class->new($self->{'pdf'}, %options, code => $value);
2577             # $self->{'pdf'}->out_obj($self->{'pages'});
2578 0         0 return $obj;
2579             }
2580             }
2581              
2582             sub xo_code128 {
2583 1     1 1 981 my ($self, @opts) = @_;
2584              
2585 1         557 require PDF::API2::Resource::XObject::Form::BarCode::code128;
2586 1         6 my $obj = PDF::API2::Resource::XObject::Form::BarCode::code128->new($self->{'pdf'}, @opts);
2587              
2588 1         6 $self->{'pdf'}->out_obj($self->{'pages'});
2589              
2590 1         3 return $obj;
2591             }
2592              
2593             sub xo_codabar {
2594 1     1 1 9 my ($self, @opts) = @_;
2595              
2596 1         529 require PDF::API2::Resource::XObject::Form::BarCode::codabar;
2597 1         18 my $obj = PDF::API2::Resource::XObject::Form::BarCode::codabar->new($self->{'pdf'}, @opts);
2598              
2599 1         5 $self->{'pdf'}->out_obj($self->{'pages'});
2600              
2601 1         4 return $obj;
2602             }
2603              
2604             sub xo_2of5int {
2605 1     1 1 523 my ($self, @opts) = @_;
2606              
2607 1         574 require PDF::API2::Resource::XObject::Form::BarCode::int2of5;
2608 1         8 my $obj = PDF::API2::Resource::XObject::Form::BarCode::int2of5->new($self->{'pdf'}, @opts);
2609              
2610 1         6 $self->{'pdf'}->out_obj($self->{'pages'});
2611              
2612 1         3 return $obj;
2613             }
2614              
2615             sub xo_3of9 {
2616 2     2 1 507 my ($self, @opts) = @_;
2617              
2618 2         551 require PDF::API2::Resource::XObject::Form::BarCode::code3of9;
2619 2         17 my $obj = PDF::API2::Resource::XObject::Form::BarCode::code3of9->new($self->{'pdf'}, @opts);
2620              
2621 2         10 $self->{'pdf'}->out_obj($self->{'pages'});
2622              
2623 2         7 return $obj;
2624             }
2625              
2626             sub xo_ean13 {
2627 1     1 1 521 my ($self, @opts) = @_;
2628              
2629 1         517 require PDF::API2::Resource::XObject::Form::BarCode::ean13;
2630 1         7 my $obj = PDF::API2::Resource::XObject::Form::BarCode::ean13->new($self->{'pdf'}, @opts);
2631              
2632 1         7 $self->{'pdf'}->out_obj($self->{'pages'});
2633              
2634 1         3 return $obj;
2635             }
2636              
2637             =head2 colorspace
2638              
2639             $colorspace = $pdf->colorspace($type, @arguments);
2640              
2641             Colorspaces can be added to a PDF to either specifically control the output
2642             color on a particular device (spot colors, device colors) or to save space by
2643             limiting the available colors to a defined color palette (web-safe palette, ACT
2644             file).
2645              
2646             Once added to the PDF, they can be used in place of regular hex codes or named
2647             colors:
2648              
2649             my $pdf = PDF::API2->new();
2650             my $page = $pdf->page();
2651             my $content = $page->graphics();
2652              
2653             # Add colorspaces for a spot color and the web-safe color palette
2654             my $spot = $pdf->colorspace('spot', 'PANTONE Red 032 C', '#EF3340');
2655             my $web = $pdf->colorspace('web');
2656              
2657             # Fill using the spot color with 100% coverage
2658             $content->fill_color($spot, 1.0);
2659              
2660             # Stroke using the first color of the web-safe palette
2661             $content->stroke_color($web, 0);
2662              
2663             # Add a rectangle to the page
2664             $content->rectangle(100, 100, 200, 200);
2665             $content->paint();
2666              
2667             $pdf->save('sample.pdf');
2668              
2669             The following types of colorspaces are supported
2670              
2671             =over
2672              
2673             =item * spot
2674              
2675             my $spot = $pdf->colorspace('spot', $tint, $alt_color);
2676              
2677             Spot colors are used to instruct a device (usually a printer) to use or emulate
2678             a particular ink color (C<$tint>) for parts of the document. An C<$alt_color>
2679             is provided for devices (e.g. PDF viewers) that don't know how to produce the
2680             named color. It can either be an approximation of the color in RGB, CMYK, or
2681             HSV formats, or a wildly different color (e.g. 100% magenta, C<%0F00>) to make
2682             it clear if the spot color isn't being used as expected.
2683              
2684             =item * web
2685              
2686             my $web = $pdf->colorspace('web');
2687              
2688             The web-safe color palette is a historical collection of colors that was used
2689             when many display devices only supported 256 colors.
2690              
2691             =item * act
2692              
2693             my $act = $pdf->colorspace('act', $filename);
2694              
2695             An Adobe Color Table (ACT) file provides a custom palette of colors that can be
2696             referenced by PDF graphics and text drawing commands.
2697              
2698             =item * device
2699              
2700             my $devicen = $pdf->colorspace('device', @colorspaces);
2701              
2702             A device-specific colorspace allows for precise color output on a given device
2703             (typically a printing press), bypassing the normal color interpretation
2704             performed by raster image processors (RIPs).
2705              
2706             Device colorspaces are also needed if you want to blend spot colors:
2707              
2708             my $pdf = PDF::API2->new();
2709             my $page = $pdf->page();
2710             my $content = $page->graphics();
2711              
2712             # Create a two-color device colorspace
2713             my $yellow = $pdf->colorspace('spot', 'Yellow', '%00F0');
2714             my $spot = $pdf->colorspace('spot', 'PANTONE Red 032 C', '#EF3340');
2715             my $device = $pdf->colorspace('device', $yellow, $spot);
2716              
2717             # Fill using a blend of 25% yellow and 75% spot color
2718             $content->fill_color($device, 0.25, 0.75);
2719              
2720             # Stroke using 100% spot color
2721             $content->stroke_color($device, 0, 1);
2722              
2723             # Add a rectangle to the page
2724             $content->rectangle(100, 100, 200, 200);
2725             $content->paint();
2726              
2727             $pdf->save('sample.pdf');
2728              
2729             =back
2730              
2731             =cut
2732              
2733             sub colorspace {
2734 0     0 1 0 my $self = shift();
2735 0         0 my $type = shift();
2736              
2737 0 0       0 if ($type eq 'act') {
    0          
    0          
    0          
    0          
2738 0         0 my $file = shift();
2739 0         0 return $self->colorspace_act($file);
2740             }
2741             elsif ($type eq 'web') {
2742 0         0 return $self->colorspace_web();
2743             }
2744             elsif ($type eq 'hue') {
2745             # This type is undocumented until either a reference can be found for
2746             # this being a standard palette like the web color palette, or POD is
2747             # added to the Hue colorspace class that describes how to use it.
2748 0         0 return $self->colorspace_hue();
2749             }
2750             elsif ($type eq 'spot') {
2751 0         0 my $name = shift();
2752 0         0 my $alt_color = shift();
2753 0         0 return $self->colorspace_separation($name, $alt_color);
2754             }
2755             elsif ($type eq 'device') {
2756 0         0 my @colors = @_;
2757 0         0 return $self->colorspace_devicen(\@colors);
2758             }
2759             else {
2760 0         0 croak "Unrecognized or unsupported colorspace: $type";
2761             }
2762             }
2763              
2764             sub colorspace_act {
2765 0     0 1 0 my ($self, $file) = @_;
2766              
2767 0         0 require PDF::API2::Resource::ColorSpace::Indexed::ACTFile;
2768 0         0 return PDF::API2::Resource::ColorSpace::Indexed::ACTFile->new($self->{'pdf'},
2769             $file);
2770             }
2771              
2772             sub colorspace_web {
2773 1     1 1 5 my $self = shift();
2774              
2775 1         469 require PDF::API2::Resource::ColorSpace::Indexed::WebColor;
2776 1         11 return PDF::API2::Resource::ColorSpace::Indexed::WebColor->new($self->{'pdf'});
2777             }
2778              
2779             sub colorspace_hue {
2780 0     0 1 0 my $self = shift();
2781              
2782 0         0 require PDF::API2::Resource::ColorSpace::Indexed::Hue;
2783 0         0 return PDF::API2::Resource::ColorSpace::Indexed::Hue->new($self->{'pdf'});
2784             }
2785              
2786             sub colorspace_separation {
2787 0     0 1 0 my ($self, $name, @clr) = @_;
2788              
2789 0         0 require PDF::API2::Resource::ColorSpace::Separation;
2790 0         0 return PDF::API2::Resource::ColorSpace::Separation->new($self->{'pdf'},
2791             pdfkey(),
2792             $name,
2793             @clr);
2794             }
2795              
2796             sub colorspace_devicen {
2797 0     0 1 0 my ($self, $clrs) = @_;
2798              
2799 0         0 require PDF::API2::Resource::ColorSpace::DeviceN;
2800 0         0 return PDF::API2::Resource::ColorSpace::DeviceN->new($self->{'pdf'},
2801             pdfkey(),
2802             $clrs);
2803             }
2804              
2805             =head2 egstate
2806              
2807             $resource = $pdf->egstate();
2808              
2809             Creates and returns a new extended graphics state object, described in
2810             L.
2811              
2812             =cut
2813              
2814             sub egstate {
2815 3     3 1 16 my $self = shift();
2816              
2817 3         13 my $obj = PDF::API2::Resource::ExtGState->new($self->{'pdf'}, pdfkey());
2818              
2819 3         11 $self->{'pdf'}->out_obj($self->{'pages'});
2820              
2821 3         12 return $obj;
2822             }
2823              
2824             sub default {
2825 8     8 1 21 my ($self, $parameter, $value) = @_;
2826              
2827             # Parameter names may consist of lowercase letters, numbers, and underscores
2828 8         18 $parameter = lc $parameter;
2829 8         24 $parameter =~ s/[^a-z\d_]//g;
2830              
2831 8         16 my $previous_value = $self->{$parameter};
2832 8 100       24 if (defined $value) {
2833 2         5 $self->{$parameter} = $value;
2834             }
2835 8         30 return $previous_value;
2836             }
2837              
2838             sub xo_form {
2839 4     4 0 11 my $self = shift();
2840              
2841 4         42 my $obj = PDF::API2::Resource::XObject::Form::Hybrid->new($self->{'pdf'});
2842              
2843 4         18 $self->{'pdf'}->out_obj($self->{'pages'});
2844              
2845 4         9 return $obj;
2846             }
2847              
2848             sub pattern {
2849 0     0 0 0 my ($self, %opts) = @_;
2850              
2851 0         0 my $obj = PDF::API2::Resource::Pattern->new($self->{'pdf'}, undef, %opts);
2852              
2853 0         0 $self->{'pdf'}->out_obj($self->{'pages'});
2854              
2855 0         0 return $obj;
2856             }
2857              
2858             sub shading {
2859 0     0 0 0 my ($self, %opts) = @_;
2860              
2861 0         0 my $obj = PDF::API2::Resource::Shading->new($self->{'pdf'}, undef, %opts);
2862              
2863 0         0 $self->{'pdf'}->out_obj($self->{'pages'});
2864              
2865 0         0 return $obj;
2866             }
2867              
2868             sub named_destination {
2869 0     0 0 0 my ($self, $cat, $name, $obj) = @_;
2870 0         0 my $root = $self->{'catalog'};
2871              
2872 0   0     0 $root->{'Names'} ||= PDFDict();
2873 0   0     0 $root->{'Names'}->{$cat} ||= PDFDict();
2874 0   0     0 $root->{'Names'}->{$cat}->{'-vals'} ||= {};
2875 0   0     0 $root->{'Names'}->{$cat}->{'Limits'} ||= PDFArray();
2876 0   0     0 $root->{'Names'}->{$cat}->{'Names'} ||= PDFArray();
2877              
2878 0 0       0 unless (defined $obj) {
2879 0         0 $obj = PDF::API2::NamedDestination->new($self->{'pdf'});
2880             }
2881 0         0 $root->{'Names'}->{$cat}->{'-vals'}->{$name} = $obj;
2882              
2883 0         0 my @names = sort {$a cmp $b} keys %{$root->{'Names'}->{$cat}->{'-vals'}};
  0         0  
  0         0  
2884              
2885 0         0 $root->{'Names'}->{$cat}->{'Limits'}->{' val'}->[0] = PDFStr($names[0]);
2886 0         0 $root->{'Names'}->{$cat}->{'Limits'}->{' val'}->[1] = PDFStr($names[-1]);
2887              
2888 0         0 @{$root->{'Names'}->{$cat}->{'Names'}->{' val'}} = ();
  0         0  
2889              
2890 0         0 foreach my $k (@names) {
2891 0         0 push @{$root->{'Names'}->{$cat}->{'Names'}->{' val'}}, (
2892             PDFStr($k),
2893 0         0 $root->{'Names'}->{$cat}->{'-vals'}->{$k}
2894             );
2895             }
2896              
2897 0         0 return $obj;
2898             }
2899              
2900             1;
2901              
2902             __END__