File Coverage

blib/lib/PDF/API2.pm
Criterion Covered Total %
statement 640 1037 61.7
branch 239 594 40.2
condition 54 222 24.3
subroutine 84 120 70.0
pod 91 97 93.8
total 1108 2070 53.5


line stmt bran cond sub pod time code
1             package PDF::API2;
2              
3 39     39   4664470 use strict;
  39         102  
  39         1774  
4 39     39   379 no warnings qw[ deprecated recursion uninitialized ];
  39         81  
  39         2763  
5              
6             our $VERSION = '2.048'; # VERSION
7              
8 39     39   250 use Carp;
  39         72  
  39         3040  
9 39     39   23404 use Encode qw(:all);
  39         811557  
  39         13342  
10 39     39   21411 use English;
  39         140864  
  39         269  
11 39     39   49399 use FileHandle;
  39         449285  
  39         291  
12              
13 39     39   38936 use PDF::API2::Basic::PDF::Utils;
  39         198  
  39         5049  
14 39     39   23437 use PDF::API2::Util;
  39         279  
  39         6426  
15              
16 39     39   30854 use PDF::API2::Basic::PDF::File;
  39         203  
  39         2164  
17 39     39   327 use PDF::API2::Basic::PDF::Pages;
  39         70  
  39         879  
18 39     39   23916 use PDF::API2::Page;
  39         166  
  39         1989  
19              
20 39     39   21484 use PDF::API2::Resource::XObject::Form::Hybrid;
  39         157  
  39         1811  
21              
22 39     39   20881 use PDF::API2::Resource::ExtGState;
  39         156  
  39         1722  
23 39     39   18153 use PDF::API2::Resource::Pattern;
  39         144  
  39         1524  
24 39     39   18073 use PDF::API2::Resource::Shading;
  39         156  
  39         1466  
25              
26 39     39   19200 use PDF::API2::NamedDestination;
  39         198  
  39         1852  
27              
28 39     39   329 use List::Util qw(max);
  39         71  
  39         3056  
29 39     39   231 use Scalar::Util qw(weaken);
  39         82  
  39         725340  
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 7072302 my ($class, %options) = @_;
102              
103 164         384 my $self = {};
104 164         466 bless $self, $class;
105 164         1702 $self->{'pdf'} = PDF::API2::Basic::PDF::File->new();
106              
107 164         462 $self->{'pdf'}->{' version'} = '1.4';
108 164         1510 $self->{'pages'} = PDF::API2::Basic::PDF::Pages->new($self->{'pdf'});
109 164         830 $self->{'pages'}->proc_set(qw(PDF Text ImageB ImageC ImageI));
110 164   33     627 $self->{'pages'}->{'Resources'} ||= PDFDict();
111 164 50       812 $self->{'pdf'}->new_obj($self->{'pages'}->{'Resources'}) unless $self->{'pages'}->{'Resources'}->is_obj($self->{'pdf'});
112 164         542 $self->{'catalog'} = $self->{'pdf'}->{'Root'};
113 164         377 weaken $self->{'catalog'};
114 164         423 $self->{'fonts'} = {};
115 164         419 $self->{'pagestack'} = [];
116              
117             # -compress is deprecated (remove the hyphen)
118 164 100       550 if (exists $options{'-compress'}) {
119 27   33     177 $options{'compress'} //= delete $options{'-compress'};
120             }
121              
122 164 100       494 if (exists $options{'compress'}) {
123 114 50       386 $self->{'forcecompress'} = $options{'compress'} ? 1 : 0;
124             }
125             else {
126 50         159 $self->{'forcecompress'} = 1;
127             }
128 164         977 $self->preferences(%options);
129              
130             # -file is deprecated (remove the hyphen)
131 164 50 0     582 $options{'file'} //= $options{'-file'} if $options{'-file'};
132              
133 164 50       522 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         1038 $self->{'infoMeta'} = [qw(Author CreationDate ModDate Creator Producer Title
140             Subject Keywords)];
141              
142 164   50     364 my $version = eval { $PDF::API2::VERSION } || 'Development Version';
143 164         1323 $self->producer("PDF::API2 $version ($OSNAME)");
144              
145 164         1520 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 1102883 my ($class, $file, %options) = @_;
169 8 50       277 croak "File '$file' does not exist" unless -f $file;
170 8 50       165 croak "File '$file' is not readable" unless -r $file;
171              
172 8         23 my $self = {};
173 8         24 bless $self, $class;
174 8         34 foreach my $parameter (keys %options) {
175 2         10 $self->default($parameter, $options{$parameter});
176             }
177              
178 8         80 my $is_writable = -w $file;
179 8         124 $self->{'pdf'} = PDF::API2::Basic::PDF::File->open($file, $is_writable);
180 8         46 _open_common($self, %options);
181 8         30 $self->{'pdf'}->{' fname'} = $file;
182 8 50       29 $self->{'opened_readonly'} = 1 unless $is_writable;
183              
184 8         136 return $self;
185             }
186              
187             sub _open_common {
188 16     16   45 my ($self, %options) = @_;
189              
190 16         148 $self->{'pdf'}->{'Root'}->realise();
191 16   50     118 $self->{'pdf'}->{' version'} ||= '1.3';
192              
193 16         90 $self->{'pages'} = $self->{'pdf'}->{'Root'}->{'Pages'}->realise();
194 16         47 weaken $self->{'pages'};
195 16         123 my @pages = proc_pages($self->{'pdf'}, $self->{'pages'});
196 16         78 $self->{'pagestack'} = [sort { $a->{' pnum'} <=> $b->{' pnum'} } @pages];
  3         17  
197 16         59 weaken $self->{'pagestack'}->[$_] for (0 .. scalar @{$self->{'pagestack'}});
  16         124  
198              
199 16         94 $self->{'catalog'} = $self->{'pdf'}->{'Root'};
200 16         39 weaken $self->{'catalog'};
201              
202 16         65 $self->{'opened'} = 1;
203              
204             # -compress is deprecated (remove the hyphen)
205 16 100       63 if (exists $options{'-compress'}) {
206 2   33     9 $options{'compress'} //= delete $options{'-compress'};
207             }
208              
209 16 100       57 if (exists $options{'compress'}) {
210 2 50       6 $self->{'forcecompress'} = $options{'compress'} ? 1 : 0;
211             }
212             else {
213 14         64 $self->{'forcecompress'} = 1;
214             }
215 16         84 $self->{'fonts'} = {};
216 16         94 $self->{'infoMeta'} = [qw(Author CreationDate ModDate Creator Producer Title Subject Keywords)];
217 16         49 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 7 my ($self, $file) = @_;
237              
238 1 50 33     8 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       3 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       4 croak "File is read-only" if $self->{'opened_readonly'};
257 1         20 $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         5 $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 158     158 1 514 sub release { return $_[0]->close() }
313 0     0 1 0 sub end { return $_[0]->close() }
314              
315             sub close {
316 306     306 1 531 my $self = shift();
317 306 100       1453 $self->{'pdf'}->release() if defined $self->{'pdf'};
318              
319 306         994 foreach my $key (keys %$self) {
320 1054         1895 $self->{$key} = undef;
321 1054         1596 delete $self->{$key};
322             }
323              
324 306         926 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 12 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 2646 my ($class, $content, %options) = @_;
352              
353 8         21 my $self = {};
354 8         19 bless $self, $class;
355 8         27 foreach my $parameter (keys %options) {
356 0         0 $self->default($parameter, $options{$parameter});
357             }
358              
359 8         28 $self->{'content_ref'} = \$content;
360 8         15 my $fh;
361 8 50       122 CORE::open($fh, '+<', \$content) or die "Can't begin scalar IO";
362              
363 8         75 $self->{'pdf'} = PDF::API2::Basic::PDF::File->open($fh, 1);
364 8         44 _open_common($self, %options);
365 8         19 $self->{'opened_scalar'} = 1;
366              
367 8         88 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 1379 my $self = shift();
395              
396 147         355 my $string = '';
397 147 100       728 if ($self->{'opened_scalar'}) {
    100          
398 3         16 $self->{'pdf'}->append_file();
399 3         5 $string = ${$self->{'content_ref'}};
  3         15  
400             }
401             elsif ($self->{'opened'}) {
402 4         42 my $fh = FileHandle->new();
403 4 50       291 CORE::open($fh, '>', \$string) || die "Can't begin scalar IO";
404 4         25 $self->{'pdf'}->clone_file($fh);
405 4         24 $self->{'pdf'}->close_file();
406 4         24 $fh->close();
407             }
408             else {
409 140         1108 my $fh = FileHandle->new();
410 140 50       8711 CORE::open($fh, '>', \$string) || die "Can't begin scalar IO";
411 140         982 $self->{'pdf'}->out_file($fh);
412 140         685 $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         1491 $self->close();
418              
419 147         2067 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 301 my $self = shift();
509 169         795 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         4 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   242382 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       264 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         108 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       42 if (defined $month) {
576 21 100 66     76 return unless $month >= 1 and $month <= 12;
577             }
578 21 100       50 if (defined $day) {
579 19 100 66     57 return unless $day >= 1 and $day <= 31;
580             }
581 20 100       31 if (defined $hour) {
582 17 100       30 return unless $hour <= 23;
583             }
584 19 100       28 if (defined $minute) {
585 15 50       26 return unless $minute <= 59;
586             }
587 19 100       25 if (defined $second) {
588 14 50       22 return unless $second <= 59;
589             }
590 19 100       28 if (defined $od) {
591 13 50 66     48 return if $od eq 'Z' and defined($oh);
592             }
593 19 100       42 if (defined $oh) {
594 11 100       23 return unless $oh <= 23;
595             }
596 17 100       25 if (defined $om) {
597 6 50       8 return unless $om <= 59;
598             }
599 17 100 100     37 if (defined $oh and $om) {
600             # Apostrophe is required between offset hour and minute
601 6 100       66 return unless $value =~ /$oh\'$om\'?/;
602             }
603              
604 15         51 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 290 my $self = shift();
628 170         319 my $field = shift();
629              
630             # Return a hash of the Info table if called without arguments
631 170 50       527 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       524 if (@_) {
645 167         371 my $value = shift();
646 167 50 66     948 $value = undef if defined($value) and not length($value);
647              
648 167 100 66     872 if ($field eq 'CreationDate' or $field eq 'ModDate') {
649 1 50       4 if (defined ($value)) {
650 1 50       6 $value = 'D:' . $value unless $value =~ /^D:/;
651 1 50       5 croak "Invalid date string: $value" unless _is_date($value);
652             }
653             }
654              
655 167 100       560 unless (exists $self->{'pdf'}->{'Info'}) {
656 164 50       398 return $self unless defined $value;
657 164         571 $self->{'pdf'}->{'Info'} = PDFDict();
658 164         739 $self->{'pdf'}->new_obj($self->{'pdf'}->{'Info'});
659             }
660             else {
661 3         16 $self->{'pdf'}->{'Info'}->realise();
662             }
663              
664 167 100       478 if (defined $value) {
665 166         592 $self->{'pdf'}->{'Info'}->{$field} = PDFStr($value);
666             }
667             else {
668 1         6 delete $self->{'pdf'}->{'Info'}->{$field};
669             }
670              
671 167         422 return $self;
672             }
673              
674             # Get
675 3 50       12 return unless $self->{'pdf'}->{'Info'};
676 3         14 $self->{'pdf'}->{'Info'}->realise();
677 3 100       15 return unless $self->{'pdf'}->{'Info'}->{$field};
678 2         12 return $self->{'pdf'}->{'Info'}->{$field}->val();
679             }
680              
681             # Deprecated; replace with individual accessors or info_metadata
682             sub info {
683 3     3 1 20 my ($self, %opt) = @_;
684              
685 3 50       9 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         16 $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         5 foreach my $k (@{$self->{'infoMeta'}}) {
  3         8  
697 24 100       51 next unless defined $opt{$k};
698 1   50     5 $self->{'pdf'}->{'Info'}->{$k} = PDFStr($opt{$k} || 'NONE');
699             }
700 3         11 $self->{'pdf'}->out_obj($self->{'pdf'}->{'Info'});
701             }
702              
703 3 50       8 if (defined $self->{'pdf'}->{'Info'}) {
704 3         5 %opt = ();
705 3         5 foreach my $k (@{$self->{'infoMeta'}}) {
  3         7  
706 24 100       50 next unless defined $self->{'pdf'}->{'Info'}->{$k};
707 3         11 $opt{$k} = $self->{'pdf'}->{'Info'}->{$k}->val();
708 3 50 33     33 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         13 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         23 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->outline();
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 31 sub outlines { return outline(@_) }
825              
826             sub outline {
827 4     4 1 8 my $self = shift();
828              
829 4         600 require PDF::API2::Outlines;
830 4         18 my $obj = $self->{'pdf'}->{'Root'}->{'Outlines'};
831 4 100       14 if ($obj) {
832 1         5 $obj->realise();
833 1         9 bless $obj, 'PDF::API2::Outlines';
834 1         33 $obj->{' api'} = $self;
835 1         4 weaken $obj->{' api'};
836             }
837             else {
838 3         24 $obj = PDF::API2::Outlines->new($self);
839              
840 3         15 $self->{'pdf'}->{'Root'}->{'Outlines'} = $obj;
841 3 50       16 $self->{'pdf'}->new_obj($obj) unless $obj->is_obj($self->{'pdf'});
842 3         11 $self->{'pdf'}->out_obj($obj);
843 3         10 $self->{'pdf'}->out_obj($self->{'pdf'}->{'Root'});
844             }
845              
846 4         27 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 9 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         9 require PDF::API2::NamedDestination;
868 2         8 my $array = PDF::API2::NamedDestination::_destination($page, @args);
869 2         7 $self->{'catalog'}->{'OpenAction'} = $array;
870 2         12 $self->{'pdf'}->out_obj($self->{'catalog'});
871 2         5 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 411 my $self = shift();
915              
916 169 50       508 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     496 my $name = shift() // 'single_page';
930 169 0       487 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       566 croak "Invalid page layout: $name" unless $layout;
938 169         521 $self->{'catalog'}->{'PageLayout'} = PDFName($layout);
939 169         647 $self->{'pdf'}->out_obj($self->{'catalog'});
940 169         322 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 378 my $self = shift();
989              
990 169 50       520 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     516 my $name = shift() // 'none';
1004 169 0       531 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       421 croak "Invalid page mode: $name" unless $mode;
1012 169         548 $self->{'catalog'}->{'PageMode'} = PDFName($mode);
1013 169         713 $self->{'pdf'}->out_obj($self->{'catalog'});
1014 169         331 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 315 my $self = shift();
1032 172         23065 require PDF::API2::ViewerPreferences;
1033 172         1530 my $prefs = PDF::API2::ViewerPreferences->new($self);
1034 172 50       527 unless (@_) {
1035 0         0 return $prefs->get_preferences();
1036             }
1037 172         615 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 530 my ($self, %options) = @_;
1043              
1044             # Page Mode Options
1045 169 50       901 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         623 $self->page_mode('none');
1056             }
1057              
1058             # Page Layout Options
1059 169 50       927 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         628 $self->page_layout('single_page');
1073             }
1074              
1075             # Viewer Preferences
1076 169 50       528 if ($options{'-hidetoolbar'}) {
1077 0         0 $self->viewer_preferences(hide_toolbar => 1);
1078             }
1079 169 50       537 if ($options{'-hidemenubar'}) {
1080 0         0 $self->viewer_preferences(hide_menubar => 1);
1081             }
1082 169 50       450 if ($options{'-hidewindowui'}) {
1083 0         0 $self->viewer_preferences(hide_window_ui => 1);
1084             }
1085 169 50       516 if ($options{'-fitwindow'}) {
1086 0         0 $self->viewer_preferences(fit_window => 1);
1087             }
1088 169 50       471 if ($options{'-centerwindow'}) {
1089 0         0 $self->viewer_preferences(center_window => 1);
1090             }
1091 169 50       481 if ($options{'-displaytitle'}) {
1092 0         0 $self->viewer_preferences(display_doc_title => 1);
1093             }
1094 169 50       422 if ($options{'-righttoleft'}) {
1095 0         0 $self->viewer_preferences(direction => 'r2l');
1096             }
1097              
1098 169 50       620 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         541 $self->viewer_preferences(non_full_screen_page_mode => 'none');
1106             }
1107              
1108 169 50       630 if ($options{'-printscalingnone'}) {
1109 0         0 $self->viewer_preferences(print_scaling => 'none');
1110             }
1111              
1112 169 100       849 if ($options{'-simplex'}) {
    100          
    100          
1113 1         4 $self->viewer_preferences(duplex => 'simplex');
1114             }
1115             elsif ($options{'-duplexfliplongedge'}) {
1116 1         16 $self->viewer_preferences(duplex => 'duplex_long');
1117             }
1118             elsif ($options{'-duplexflipshortedge'}) {
1119 1         3 $self->viewer_preferences(duplex => 'duplex_short');
1120             }
1121              
1122             # Open Action
1123 169 100       520 if ($options{'-firstpage'}) {
1124 2         3 my ($page, %args) = @{$options{'-firstpage'}};
  2         6  
1125 2 50       7 $args{'-fit'} = 1 unless keys %args;
1126              
1127 2 50       5 if (defined $args{'-fit'}) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1128 2         7 $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         700 $self->{'pdf'}->out_obj($self->{'catalog'});
1153              
1154 169         371 return $self;
1155             }
1156              
1157             sub proc_pages {
1158 16     16 0 51 my ($pdf, $object) = @_;
1159              
1160 16 50       94 if (defined $object->{'Resources'}) {
1161 16         32 eval {
1162 16         72 $object->{'Resources'}->realise();
1163             };
1164             }
1165              
1166 16         33 my @pages;
1167 16   50     143 $pdf->{' apipagecount'} ||= 0;
1168 16         88 foreach my $page ($object->{'Kids'}->elements()) {
1169 18         62 $page->realise();
1170 18 50       77 if ($page->{'Type'}->val() eq 'Pages') {
1171 0         0 push @pages, proc_pages($pdf, $page);
1172             }
1173             else {
1174 18         48 $pdf->{' apipagecount'}++;
1175 18         52 $page->{' pnum'} = $pdf->{' apipagecount'};
1176 18 50       57 if (defined $page->{'Resources'}) {
1177 18         36 eval {
1178 18         93 $page->{'Resources'}->realise();
1179             };
1180             }
1181 18         77 push @pages, $page;
1182             }
1183             }
1184              
1185 16         66 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 16157 my $self = shift();
1209 142   100     594 my $index = shift() || 0;
1210 142         257 my $page;
1211 142 100       330 if ($index == 0) {
1212 140         1273 $page = PDF::API2::Page->new($self->{'pdf'}, $self->{'pages'});
1213             }
1214             else {
1215 2         10 $page = PDF::API2::Page->new($self->{'pdf'}, $self->{'pages'}, $index - 1);
1216             }
1217 142         573 $page->{' apipdf'} = $self->{'pdf'};
1218 142         359 $page->{' api'} = $self;
1219 142         341 weaken $page->{' apipdf'};
1220 142         257 weaken $page->{' api'};
1221 142         528 $self->{'pdf'}->out_obj($page);
1222 142         542 $self->{'pdf'}->out_obj($self->{'pages'});
1223 142 100       369 if ($index == 0) {
    50          
1224 140         232 push @{$self->{'pagestack'}}, $page;
  140         362  
1225 140         323 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         12 weaken $self->{'pagestack'}->[$index - 1];
1234             }
1235             # $page->{'Resources'} = $self->{'pages'}->{'Resources'};
1236 142         747 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 17 my $self = shift();
1254 6   50     31 my $index = shift() || 0;
1255 6         13 my ($page, $rotate, $media, $trans);
1256              
1257 6 50       24 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         23 $page = $self->{'pagestack'}->[$index - 1];
1265             }
1266 6 50       30 return unless ref($page);
1267              
1268 6 100       26 if (ref($page) ne 'PDF::API2::Page') {
1269 5         27 bless $page, 'PDF::API2::Page';
1270 5         14 $page->{' apipdf'} = $self->{'pdf'};
1271 5         30 $page->{' api'} = $self;
1272 5         15 weaken $page->{' apipdf'};
1273 5         10 weaken $page->{' api'};
1274 5         24 $self->{'pdf'}->out_obj($page);
1275 5 50 33     22 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         30 $trans = '';
1308             }
1309              
1310 5 100 66     95 if (defined $page->{'Contents'} and not $page->{' opened'}) {
1311 3         21 $page->fixcontents();
1312 3         8 my $uncontent = delete $page->{'Contents'};
1313 3         14 my $content = $page->gfx();
1314 3         18 $content->add(" $trans ");
1315              
1316 3 50       16 if ($self->default('pageencaps')) {
1317 0         0 $content->{' stream'} .= ' q ';
1318             }
1319 3         29 foreach my $k ($uncontent->elements()) {
1320 3         14 $k->realise();
1321 3         22 $content->{' stream'} .= ' ' . unfilter($k->{'Filter'}, $k->{' stream'}) . ' ';
1322             }
1323 3 50       15 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       12 if ($self->{'forcecompress'}) {
1329 3         18 $content->{' stream'} = dofilter($content->{'Filter'}, $content->{' stream'});
1330 3         12 $content->{' nofilt'} = 1;
1331 3         7 delete $content->{'-docompress'};
1332 3         15 $content->{'Length'} = PDFNum(length($content->{' stream'}));
1333             }
1334             }
1335 5         18 $page->{' opened'} = 1;
1336             }
1337              
1338 6         34 $self->{'pdf'}->out_obj($page);
1339 6         27 $self->{'pdf'}->out_obj($self->{'pages'});
1340 6         15 $page->{' apipdf'} = $self->{'pdf'};
1341 6         15 $page->{' api'} = $self;
1342 6         14 weaken $page->{' apipdf'};
1343 6         13 weaken $page->{' api'};
1344 6         19 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 9 sub importpage { return import_page(@_); } ## no critic
1377              
1378             sub import_page {
1379 1     1 1 4 my ($self, $s_pdf, $s_idx, $t_idx) = @_;
1380 1   50     21 $s_idx ||= 0;
1381 1   50     7 $t_idx ||= 0;
1382 1         2 my ($s_page, $t_page);
1383              
1384 1 50 33     21 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       4 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         5 $t_page = $self->page($t_idx);
1405             }
1406             }
1407              
1408 1   50     11 $self->{'apiimportcache'} = $self->{'apiimportcache'} || {};
1409 1   50     37 $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         7 my $xo = $self->importPageIntoForm($s_pdf, $s_page);
1415              
1416             # copy all page dimensions
1417 1         15 foreach my $k (qw(MediaBox ArtBox TrimBox BleedBox CropBox)) {
1418 5         15 my $prop = $s_page->find_prop($k);
1419 5 50       13 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         5 $t_page->gfx->formimage($xo, 0, 0, 1);
1428              
1429             # copy annotations and/or form elements as well
1430 1 0 33     6 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         5 $self->{'pdf'}->out_obj($t_page);
1497 1         5 $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 84 sub importPageIntoForm { return embed_page(@_) }
1535              
1536             sub embed_page {
1537 4     4 1 15 my ($self, $s_pdf, $s_idx) = @_;
1538 4   50     17 $s_idx ||= 0;
1539              
1540 4 50 33     47 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         9 my ($s_page, $xo);
1545              
1546 4         22 $xo = $self->xo_form();
1547              
1548 4 100       17 if (ref($s_idx) eq 'PDF::API2::Page') {
1549 1         2 $s_page = $s_idx;
1550             }
1551             else {
1552 3         23 $s_page = $s_pdf->open_page($s_idx);
1553 3 50       9 croak "Unable to open page $s_idx in source PDF" unless defined $s_page;
1554             }
1555              
1556 4   100     27 $self->{'apiimportcache'} ||= {};
1557 4   100     26 $self->{'apiimportcache'}->{$s_pdf} ||= {};
1558              
1559             # This should never get past MediaBox, since it's a required object.
1560 4         12 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       49 next unless defined $s_page->find_prop($k);
1564 2         11 my $box = walk_obj($self->{'apiimportcache'}->{$s_pdf}, $s_pdf->{'pdf'}, $self->{'pdf'}, $s_page->find_prop($k));
1565 2         7 $xo->bbox(map { $_->val() } $box->elements());
  8         16  
1566 2         6 last;
1567             }
1568 4 100       42 $xo->bbox(0, 0, 612, 792) unless defined $xo->{'BBox'};
1569              
1570 4         12 foreach my $k (qw(Resources)) {
1571 4         18 $s_page->{$k} = $s_page->find_prop($k);
1572 4 50       18 next unless defined $s_page->{$k};
1573 4 50       22 $s_page->{$k}->realise() if ref($s_page->{$k}) =~ /Objind$/;
1574              
1575 4         12 foreach my $sk (qw(XObject ExtGState Font ProcSet Properties ColorSpace Pattern Shading)) {
1576 32 100       103 next unless defined $s_page->{$k}->{$sk};
1577 5 50       19 $s_page->{$k}->{$sk}->realise() if ref($s_page->{$k}->{$sk}) =~ /Objind$/;
1578 5         8 foreach my $ssk (keys %{$s_page->{$k}->{$sk}}) {
  5         21  
1579 10 100       48 next if $ssk =~ /^ /;
1580 1         5 $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       16 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       14 if (defined $s_page->{'Contents'}) {
1596 3         16 $s_page->fixcontents();
1597              
1598 3         8 $xo->{' stream'} = '';
1599             # open_page pages only contain one stream
1600 3         13 my ($k) = $s_page->{'Contents'}->elements();
1601 3         47 $k->realise();
1602 3 50       11 if ($k->{' nofilt'}) {
1603             # we have a finished stream here so we unfilter
1604 3         16 $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       21 $xo->compressFlate() if $self->{'forcecompress'};
1612             }
1613              
1614 4         30 return $xo;
1615             }
1616              
1617             # Used by embed_page and import_page
1618             sub walk_obj {
1619 16     16 0 45 my ($object_cache, $source_pdf, $target_pdf, $source_object, @keys) = @_;
1620              
1621 16 100       36 if (ref($source_object) =~ /Objind$/) {
1622 1         4 $source_object->realise();
1623             }
1624              
1625 16 50       43 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         33 my $target_object = $source_object->copy($source_pdf); ## thanks to: yaheath // Fri, 17 Sep 2004
1629              
1630             # $source_object->{' copied'} = 1;
1631 16 100       30 $target_pdf->new_obj($target_object) if $source_object->is_obj($source_pdf);
1632              
1633 16         32 $object_cache->{scalar $source_object} = $target_object;
1634              
1635 16 100       52 if (ref($source_object) =~ /Array$/) {
    100          
1636 2         10 $target_object->{' val'} = [];
1637 2         8 foreach my $k ($source_object->elements()) {
1638 8 50       19 $k->realise() if ref($k) =~ /Objind$/;
1639 8         35 $target_object->add_elements(walk_obj($object_cache, $source_pdf, $target_pdf, $k));
1640             }
1641             }
1642             elsif (ref($source_object) =~ /Dict$/) {
1643 1 50       4 @keys = keys(%$target_object) unless scalar @keys;
1644 1         3 foreach my $k (@keys) {
1645 6 100       10 next if $k =~ /^ /;
1646 5 50       9 next unless defined $source_object->{$k};
1647 5         7 $target_object->{$k} = walk_obj($object_cache, $source_pdf, $target_pdf, $source_object->{$k});
1648             }
1649 1 50       3 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         22 delete $target_object->{' streamloc'};
1661 16         18 delete $target_object->{' streamsrc'};
1662              
1663 16         43 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 513 sub pages { return page_count(@_) }
1676              
1677             sub page_count {
1678 3     3 1 6 my $self = shift();
1679 3         7 return scalar @{$self->{'pagestack'}};
  3         18  
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 60 my $self = shift();
1728 8         24 while (@_) {
1729 8         14 my $page_index = shift();
1730              
1731             # Pass options as a hash rather than a hashref
1732 8   50     12 my %options = %{shift() // {}};
  8         33  
1733              
1734             # Remove leading hyphens from option names
1735 8 100       25 if (exists $options{'-prefix'}) {
1736 1         3 $options{'prefix'} = delete $options{'-prefix'};
1737             }
1738 8 100       19 if (exists $options{'-start'}) {
1739 1         2 $options{'start'} = delete $options{'-start'};
1740             }
1741 8 100       20 if (exists $options{'-style'}) {
1742 6         16 $options{'style'} = delete $options{'-style'};
1743 6 100       37 unless ($options{'style'} =~ /^(?:[Rr]oman|[Aa]lpha|decimal)$/) {
1744 1         237 carp "Invalid -style for page labels; defaulting to decimal";
1745 1         10 $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     25 $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         31 $self->page_labels($page_index + 1, %options);
1757             }
1758              
1759             # Return nothing (page_labels returns $self, matching other setters)
1760 8         16 return;
1761             }
1762              
1763             sub page_labels {
1764 8     8 1 20 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         13 my $page_index = $page_number - 1;
1769              
1770 8   33     39 $self->{'catalog'}->{'PageLabels'} //= PDFDict();
1771 8   33     33 $self->{'catalog'}->{'PageLabels'}->{'Nums'} //= PDFArray();
1772              
1773 8         15 my $nums = $self->{'catalog'}->{'PageLabels'}->{'Nums'};
1774 8         20 $nums->add_elements(PDFNum($page_index));
1775              
1776 8         18 my $d = PDFDict();
1777 8 50       19 if (exists $options{'style'}) {
1778 8 50 33     47 unless ($options{'style'} and $options{'style'} =~ /^([rad])/i) {
1779 0         0 croak 'Invalid page numbering style';
1780             }
1781 8 100       34 $d->{'S'} = PDFName($1 eq 'd' ? 'D' : $1);
1782             }
1783              
1784 8 100       24 if (exists $options{'prefix'}) {
1785 1   50     4 $d->{'P'} = PDFStr($options{'prefix'} // '');
1786             }
1787              
1788 8 100       20 if (exists $options{'start'}) {
1789 1   50     8 $d->{'St'} = PDFNum($options{'start'} // '');
1790             }
1791              
1792 8         24 $nums->add_elements($d);
1793              
1794 8         42 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 3878 my $self = shift();
1815              
1816             # Set
1817 1 50       5 if (@_) {
1818 1         7 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   3979 my $self = shift();
1845 17         36 my $type = shift();
1846              
1847             # Get
1848 17 100       48 unless (scalar @_) {
1849 6 100       26 unless ($self->{'pages'}->{$type}) {
1850 1 50       10 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         23 return map { $_->val() } $self->{'pages'}->{$type}->elements();
  20         74  
1857             }
1858              
1859             # Set
1860 11         53 $self->{'pages'}->{$type} = PDFArray(map { PDFNum(float($_)) } @_);
  44         114  
1861 11         43 return $self;
1862             }
1863              
1864             sub default_page_boundaries {
1865 3     3 1 7812 return PDF::API2::Page::boundaries(@_);
1866             }
1867              
1868             # Deprecated; use default_page_size or default_page_boundaries
1869             sub mediabox {
1870 5     5 1 23 my $self = shift();
1871 5 100       24 return $self->_bounding_box('MediaBox') unless @_;
1872 3         491 return $self->_bounding_box('MediaBox', page_size(@_));
1873             }
1874              
1875             # Deprecated; use default_page_boundaries
1876             sub cropbox {
1877 1     1 1 2498 my $self = shift();
1878 1 50       6 return $self->_bounding_box('CropBox') unless @_;
1879 1         7 return $self->_bounding_box('CropBox', page_size(@_));
1880             }
1881              
1882             # Deprecated; use default_page_boundaries
1883             sub bleedbox {
1884 1     1 1 3883 my $self = shift();
1885 1 50       6 return $self->_bounding_box('BleedBox') unless @_;
1886 1         6 return $self->_bounding_box('BleedBox', page_size(@_));
1887             }
1888              
1889             # Deprecated; use default_page_boundaries
1890             sub trimbox {
1891 1     1 1 3840 my $self = shift();
1892 1 50       6 return $self->_bounding_box('TrimBox') unless @_;
1893 1         7 return $self->_bounding_box('TrimBox', page_size(@_));
1894             }
1895              
1896             # Deprecated; use default_page_boundaries
1897             sub artbox {
1898 1     1 1 3918 my $self = shift();
1899 1 50       6 return $self->_bounding_box('ArtBox') unless @_;
1900 1         6 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),
1914             a C object, or 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 6 my ($self, $name, %options) = @_;
1976              
1977 1 50       4 if (exists $options{'kerning'}) {
1978 0         0 $options{'-dokern'} = delete $options{'kerning'};
1979             }
1980              
1981 1         727 require PDF::API2::Resource::Font::CoreFont;
1982 1 50 0     11 if (PDF::API2::Resource::Font::CoreFont->is_standard($name)) {
    0          
1983 1         6 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 //= 'truetype' if UNIVERSAL::isa($name, 'Font::TTF::Font');
1994 0 0 0     0 $format //= ($name =~ /\.[ot]tf$/i ? 'truetype' :
    0          
    0          
1995             $name =~ /\.pf[ab]$/i ? 'type1' :
1996             $name =~ /\.bdf$/i ? 'bitmap' : '');
1997              
1998 0 0       0 if ($format eq 'truetype') {
    0          
    0          
    0          
    0          
1999 0   0     0 $options{'embed'} //= 1;
2000 0         0 return $self->ttfont($name, %options);
2001             }
2002             elsif ($format eq 'type1') {
2003 0 0       0 if (exists $options{'afm_file'}) {
2004 0         0 $options{'-afmfile'} = delete $options{'afm_file'};
2005             }
2006 0 0       0 if (exists $options{'pfm_file'}) {
2007 0         0 $options{'-pfmfile'} = delete $options{'pfm_file'};
2008             }
2009 0         0 return $self->psfont($name, %options);
2010             }
2011             elsif ($format eq 'bitmap') {
2012 0         0 return $self->bdfont($name, %options);
2013             }
2014             elsif ($format) {
2015 0         0 croak "Unrecognized font format: $format";
2016             }
2017             elsif ($name =~ /(\..*)$/) {
2018 0         0 croak "Unrecognized font file extension: $1";
2019             }
2020             else {
2021 0         0 croak "Unrecognized font: $name";
2022             }
2023             }
2024              
2025             =head2 synthetic_font
2026              
2027             $font = $pdf->synthetic_font($base_font, %options)
2028              
2029             Creates and returns a new synthetic font object. See
2030             L for details.
2031              
2032             =cut
2033              
2034             # Deprecated (renamed)
2035 0     0 1 0 sub synfont { return synthetic_font(@_) }
2036              
2037             sub synthetic_font {
2038 0     0 1 0 my ($self, $font, %opts) = @_;
2039              
2040             # PDF::API2 doesn't set BaseEncoding for TrueType fonts, so text
2041             # isn't searchable unless a ToUnicode CMap is included. Include
2042             # the ToUnicode CMap by default, but allow it to be disabled (for
2043             # performance and file size reasons) by setting -unicodemap to 0.
2044 0 0       0 $opts{-unicodemap} = 1 unless exists $opts{-unicodemap};
2045              
2046 0         0 require PDF::API2::Resource::Font::SynFont;
2047 0         0 my $obj = PDF::API2::Resource::Font::SynFont->new($self->{'pdf'}, $font, %opts);
2048              
2049 0         0 $self->{'pdf'}->out_obj($self->{'pages'});
2050 0 0       0 $obj->tounicodemap() if $opts{-unicodemap};
2051              
2052 0         0 return $obj;
2053             }
2054              
2055             =head2 standard_fonts
2056              
2057             @names = $pdf->standard_fonts()
2058              
2059             Returns the names of the 14 standard (built-in) fonts. See
2060             L for details.
2061              
2062             =cut
2063              
2064             sub standard_fonts {
2065 1     1 1 1060 require PDF::API2::Resource::Font::CoreFont;
2066 1         4 return PDF::API2::Resource::Font::CoreFont->names();
2067             }
2068              
2069             =head2 is_standard_font
2070              
2071             $boolean = PDF::API2->is_standard_font($name);
2072              
2073             Returns true if C<$name> is an exact, case-sensitive match for one of the
2074             standard font names.
2075              
2076             =cut
2077              
2078             sub is_standard_font {
2079 2     2 1 395 my $name = pop();
2080 2         10 require PDF::API2::Resource::Font::CoreFont;
2081 2         9 return PDF::API2::Resource::Font::CoreFont->is_standard($name);
2082             }
2083              
2084             =head2 font_path
2085              
2086             @directories = PDF::API2->font_path()
2087              
2088             Return the list of directories that will be searched (in order) in addition to
2089             the current directory when you add a font to a PDF without including the full
2090             path to the font file.
2091              
2092             =cut
2093              
2094             sub font_path {
2095 0     0 1 0 return @font_path;
2096             }
2097              
2098             =head2 add_to_font_path
2099              
2100             @directories = PDF::API2->add_to_font_path('/my/fonts', '/path/to/fonts');
2101              
2102             Add one or more directories to the list of paths to be searched for font files.
2103              
2104             Returns the font search path.
2105              
2106             =cut
2107              
2108             # Deprecated (renamed)
2109 0     0 1 0 sub addFontDirs { return add_to_font_path(@_) }
2110              
2111             sub add_to_font_path {
2112             # Allow this method to be called using either :: or -> notation.
2113 0 0   0 1 0 shift() if ref($_[0]);
2114 0 0       0 shift() if $_[0] eq __PACKAGE__;
2115              
2116 0         0 push @font_path, @_;
2117 0         0 return @font_path;
2118             }
2119              
2120             =head2 set_font_path
2121              
2122             @directories = PDF::API2->set_font_path('/my/fonts', '/path/to/fonts');
2123              
2124             Replace the existing font search path. This should only be necessary if you
2125             need to remove a directory from the path for some reason, or if you need to
2126             reorder the list.
2127              
2128             Returns the font search path.
2129              
2130             =cut
2131              
2132             sub set_font_path {
2133             # Allow this method to be called using either :: or -> notation.
2134 39 50   39 1 254 shift() if ref($_[0]);
2135 39 50       194 shift() if $_[0] eq __PACKAGE__;
2136              
2137 39         206 @font_path = ((map { "$_/PDF/API2/fonts" } @INC), @_);
  312         1164  
2138              
2139 39         218 return @font_path;
2140             }
2141              
2142             sub _find_font {
2143 0     0   0 my $font = shift();
2144              
2145             # Check the current directory
2146 0 0       0 return $font if -f $font;
2147              
2148             # Check the font search path
2149 0         0 foreach my $directory (@font_path) {
2150 0 0       0 return "$directory/$font" if -f "$directory/$font";
2151             }
2152              
2153 0         0 return;
2154             }
2155              
2156             sub corefont {
2157 53     53 1 17947 my ($self, $name, %opts) = @_;
2158 53         6128 require PDF::API2::Resource::Font::CoreFont;
2159 53         548 my $obj = PDF::API2::Resource::Font::CoreFont->new($self->{'pdf'}, $name, %opts);
2160 53         635 $self->{'pdf'}->out_obj($self->{'pages'});
2161 53 50       505 $obj->tounicodemap() if $opts{-unicodemap};
2162 53         616 return $obj;
2163             }
2164              
2165             sub psfont {
2166 0     0 1 0 my ($self, $psf, %opts) = @_;
2167              
2168 0         0 foreach my $o (qw(-afmfile -pfmfile)) {
2169 0 0       0 next unless defined $opts{$o};
2170 0         0 $opts{$o} = _find_font($opts{$o});
2171             }
2172 0 0       0 $psf = _find_font($psf) or croak "Unable to find font \"$psf\"";
2173 0         0 require PDF::API2::Resource::Font::Postscript;
2174 0         0 my $obj = PDF::API2::Resource::Font::Postscript->new($self->{'pdf'}, $psf, %opts);
2175              
2176 0         0 $self->{'pdf'}->out_obj($self->{'pages'});
2177 0 0       0 $obj->tounicodemap() if $opts{-unicodemap};
2178              
2179 0         0 return $obj;
2180             }
2181              
2182             sub ttfont {
2183 0     0 1 0 my ($self, $name, %opts) = @_;
2184              
2185             # PDF::API2 doesn't set BaseEncoding for TrueType fonts, so text
2186             # isn't searchable unless a ToUnicode CMap is included. Include
2187             # the ToUnicode CMap by default, but allow it to be disabled (for
2188             # performance and file size reasons) by setting -unicodemap to 0.
2189 0 0       0 $opts{-unicodemap} = 1 unless exists $opts{-unicodemap};
2190              
2191             # -noembed is deprecated (replace with embed => 0)
2192 0 0       0 if ($opts{'-noembed'}) {
2193 0   0     0 $opts{'embed'} //= 0;
2194             }
2195 0   0     0 $opts{'embed'} //= 1;
2196              
2197 0 0       0 my $file = UNIVERSAL::isa($name,'Font::TTF::Font') ? $name : _find_font($name) or croak "Unable to find font \"$name\"";
    0          
2198 0         0 require PDF::API2::Resource::CIDFont::TrueType;
2199 0         0 my $obj = PDF::API2::Resource::CIDFont::TrueType->new($self->{'pdf'}, $file, %opts);
2200              
2201 0         0 $self->{'pdf'}->out_obj($self->{'pages'});
2202 0 0       0 $obj->tounicodemap() if $opts{-unicodemap};
2203              
2204 0         0 return $obj;
2205             }
2206              
2207             sub bdfont {
2208 0     0 1 0 my ($self, @opts) = @_;
2209              
2210 0         0 require PDF::API2::Resource::Font::BdFont;
2211 0         0 my $obj = PDF::API2::Resource::Font::BdFont->new($self->{'pdf'}, @opts);
2212              
2213 0         0 $self->{'pdf'}->out_obj($self->{'pages'});
2214             # $obj->tounicodemap(); # does not support Unicode
2215              
2216 0         0 return $obj;
2217             }
2218              
2219             # Deprecated. Use Unicode-supporting TrueType fonts instead.
2220             # See PDF::API2::Resource::CIDFont::CJKFont for details.
2221             sub cjkfont {
2222 1     1 1 10 my ($self, $name, %opts) = @_;
2223              
2224 1         668 require PDF::API2::Resource::CIDFont::CJKFont;
2225 1         18 my $obj = PDF::API2::Resource::CIDFont::CJKFont->new($self->{'pdf'}, $name, %opts);
2226              
2227 1         8 $self->{'pdf'}->out_obj($self->{'pages'});
2228 1 50       4 $obj->tounicodemap() if $opts{-unicodemap};
2229              
2230 1         6 return $obj;
2231             }
2232              
2233             # Deprecated. Use Unicode-supporting TrueType fonts instead.
2234             sub unifont {
2235 1     1 1 18 my ($self, @opts) = @_;
2236              
2237 1         794 require PDF::API2::Resource::UniFont;
2238 1         15 my $obj = PDF::API2::Resource::UniFont->new($self->{'pdf'}, @opts);
2239              
2240 1         6 return $obj;
2241             }
2242              
2243             =head1 GRAPHICS METHODS
2244              
2245             =head2 image
2246              
2247             $object = $pdf->image($file, %options);
2248              
2249             Import a supported image type and return an object that can be placed as part of
2250             a page's content:
2251              
2252             my $pdf = PDF::API2->new();
2253             my $page = $pdf->page();
2254              
2255             my $image = $pdf->image('/path/to/image.jpg');
2256             $page->object($image, 100, 100);
2257              
2258             $pdf->save('sample.pdf');
2259              
2260             C<$file> may be either a file name, a filehandle, or a L object.
2261              
2262             See L for details about placing images on a page
2263             once they're imported.
2264              
2265             The image format is normally detected automatically based on the file's
2266             extension. If passed a filehandle, image formats GIF, JPEG, and PNG will be
2267             detected based on the file's header.
2268              
2269             If the file has an atypical extension or the filehandle is for a different kind
2270             of image, you can set the C option to one of the supported types:
2271             C, C, C, C, or C.
2272              
2273             Note: PNG images that include an alpha (transparency) channel go through a
2274             relatively slow process of splitting the image into separate RGB and alpha
2275             components as is required by images in PDFs. If you're having performance
2276             issues, install PDF::API2::XS or Image::PNG::Libpng to speed this process up by
2277             an order of magnitude; either module will be used automatically if available.
2278              
2279             =cut
2280              
2281             sub image {
2282 3     3 1 249 my ($self, $file, %options) = @_;
2283              
2284 3   50     28 my $format = lc($options{'format'} // '');
2285              
2286 3 50       24 if (ref($file) eq 'GD::Image') {
    50          
2287 0         0 return $self->image_gd($file, %options);
2288             }
2289             elsif (ref($file)) {
2290 3   33     25 $format ||= _detect_image_format($file);
2291             }
2292 3 50       12 unless (ref($file)) {
2293 0 0 0     0 $format ||= ($file =~ /\.jpe?g$/i ? 'jpeg' :
    0          
    0          
    0          
    0          
2294             $file =~ /\.png$/i ? 'png' :
2295             $file =~ /\.gif$/i ? 'gif' :
2296             $file =~ /\.tiff?$/i ? 'tiff' :
2297             $file =~ /\.p[bgp]m$/i ? 'pnm' : '');
2298             }
2299              
2300 3 100       18 if ($format eq 'jpeg') {
    100          
    50          
    0          
    0          
    0          
    0          
    0          
2301 1         6 return $self->image_jpeg($file, %options);
2302             }
2303             elsif ($format eq 'png') {
2304 1         7 return $self->image_png($file, %options);
2305             }
2306             elsif ($format eq 'gif') {
2307 1         6 return $self->image_gif($file, %options);
2308             }
2309             elsif ($format eq 'tiff') {
2310 0         0 return $self->image_tiff($file, %options);
2311             }
2312             elsif ($format eq 'pnm') {
2313 0         0 return $self->image_pnm($file, %options);
2314             }
2315             elsif ($format) {
2316 0         0 croak "Unrecognized image format: $format";
2317             }
2318             elsif (ref($file)) {
2319 0         0 croak "Unspecified image format";
2320             }
2321             elsif ($file =~ /(\..*)$/) {
2322 0         0 croak "Unrecognized image extension: $1";
2323             }
2324             else {
2325 0         0 croak "Unrecognized image: $file";
2326             }
2327             }
2328              
2329             sub _detect_image_format {
2330 3     3   9 my $fh = shift();
2331 3         34 $fh->seek(0, 0);
2332 3         48 binmode $fh, ':raw';
2333              
2334 3         7 my $test;
2335 3         21 my $bytes_read = $fh->read($test, 8);
2336 3         97 $fh->seek(0, 0);
2337 3 50 33     56 return unless $bytes_read and $bytes_read == 8;
2338              
2339 3 100       22 return 'gif' if $test =~ /^GIF\d\d[a-z]/;
2340 2 100       10 return 'jpeg' if $test =~ /^\xFF\xD8\xFF/;
2341 1 50       9 return 'png' if $test =~ /^\x89PNG\x0D\x0A\x1A\x0A/;
2342 0         0 return;
2343             }
2344              
2345             sub image_jpeg {
2346 3     3 1 40 my ($self, $file, %opts) = @_;
2347              
2348 3         705 require PDF::API2::Resource::XObject::Image::JPEG;
2349 3         26 my $obj = PDF::API2::Resource::XObject::Image::JPEG->new($self->{'pdf'}, $file);
2350              
2351 2         10 $self->{'pdf'}->out_obj($self->{'pages'});
2352              
2353 2         18 return $obj;
2354             }
2355              
2356             sub image_tiff {
2357 4     4 1 70 my ($self, $file, %opts) = @_;
2358              
2359 4         450 require PDF::API2::Resource::XObject::Image::TIFF;
2360 4         29 my $obj = PDF::API2::Resource::XObject::Image::TIFF->new($self->{'pdf'}, $file);
2361              
2362 3         13 $self->{'pdf'}->out_obj($self->{'pages'});
2363              
2364 3         22 return $obj;
2365             }
2366              
2367             sub image_pnm {
2368 3     3 1 91 my ($self, $file, %opts) = @_;
2369              
2370 3   33     24 $opts{'-compress'} //= $self->{'forcecompress'};
2371              
2372 3         707 require PDF::API2::Resource::XObject::Image::PNM;
2373 3         33 my $obj = PDF::API2::Resource::XObject::Image::PNM->new($self->{'pdf'}, $file, %opts);
2374              
2375 2         37 $self->{'pdf'}->out_obj($self->{'pages'});
2376              
2377 2         25 return $obj;
2378             }
2379              
2380             sub image_png {
2381 5     5 1 32 my ($self, $file, %opts) = @_;
2382              
2383 5         572 require PDF::API2::Resource::XObject::Image::PNG;
2384 5         3946 my $obj = PDF::API2::Resource::XObject::Image::PNG->new($self->{'pdf'}, $file);
2385              
2386 4         40 $self->{'pdf'}->out_obj($self->{'pages'});
2387              
2388 4         64 return $obj;
2389             }
2390              
2391             sub image_gif {
2392 3     3 1 22 my ($self, $file, %opts) = @_;
2393              
2394 3         725 require PDF::API2::Resource::XObject::Image::GIF;
2395 3         38 my $obj = PDF::API2::Resource::XObject::Image::GIF->new($self->{'pdf'}, $file);
2396              
2397 2         14 $self->{'pdf'}->out_obj($self->{'pages'});
2398              
2399 2         47 return $obj;
2400             }
2401              
2402             sub image_gd {
2403 0     0 1 0 my ($self, $gd, %opts) = @_;
2404              
2405 0         0 require PDF::API2::Resource::XObject::Image::GD;
2406 0         0 my $obj = PDF::API2::Resource::XObject::Image::GD->new($self->{'pdf'}, $gd, undef, %opts);
2407              
2408 0         0 $self->{'pdf'}->out_obj($self->{'pages'});
2409              
2410 0         0 return $obj;
2411             }
2412              
2413             =head2 barcode
2414              
2415             $object = $pdf->barcode($format, $code, %options);
2416              
2417             Generate and return a barcode that can be placed as part of a page's content:
2418              
2419             my $pdf = PDF::API2->new();
2420             my $page = $pdf->page();
2421              
2422             my $barcode = $pdf->barcode('ean13', '0123456789012');
2423             $page->object($barcode, 100, 100);
2424              
2425             my $qr_code = $pdf->barcode('qr', 'http://www.example.com');
2426             $page->object($qr_code, 100, 300, 144 / $qr_code->width())
2427              
2428             $pdf->save('sample.pdf');
2429              
2430             C<$format> can be one of C, C, C (a.k.a. 3 of 9),
2431             C, C, C (a.k.a. interleaved 2 of 5), or C.
2432              
2433             C<$code> is the value to be encoded. Start and stop characters are only
2434             required when they're not static (e.g. for Codabar).
2435              
2436             The following options are available:
2437              
2438             =over
2439              
2440             =item * bar_width
2441              
2442             The width of the smallest bar or space in points (72 points = 1 inch).
2443              
2444             If you're following a specification that gives bar width in mils (thousandths of
2445             an inch), use this conversion: C<$points = $mils / 1000 * 72>.
2446              
2447             =item * bar_height
2448              
2449             The base height of the barcode in points.
2450              
2451             =item * bar_extend
2452              
2453             If present and applicable, bars for non-printing characters (e.g. start and stop
2454             characters) will be extended downward by this many points, and printing
2455             characters will be shown below their respective bars.
2456              
2457             This is enabled by default for EAN-13 barcodes.
2458              
2459             =item * caption
2460              
2461             If present, this value will be printed, centered, beneath the barcode, and
2462             should be a human-readable representation of the barcode. This option is
2463             ignored for QR codes.
2464              
2465             =item * font
2466              
2467             A font object (created by L) that will be used to print the caption, or
2468             the printable characters when C is set.
2469              
2470             Helvetica will be used by default.
2471              
2472             =item * font_size
2473              
2474             The size of the font used for printing the caption or printable characters.
2475              
2476             The default will be calculated based on the barcode size, if C is
2477             set, or 10 otherwise.
2478              
2479             =item * quiet_zone
2480              
2481             A margin, in points, that will be place before the left and bottom edges of the
2482             barcode (including the caption, if present). This is used to help barcode
2483             scanners tell where the barcode begins and ends.
2484              
2485             The default is the width of one encoded character, or four squares for QR codes.
2486              
2487             =item * bar_overflow
2488              
2489             Shrinks the horizontal width of bars by this amount in points to account for ink
2490             spread when printing. This option is ignored for QR codes.
2491              
2492             The default is 0.01 points.
2493              
2494             =item * color
2495              
2496             Draw bars using this color, which may be any value accepted by
2497             L.
2498              
2499             The default is black.
2500              
2501             =back
2502              
2503             QR codes have
2504             L for
2505             customizing the error correction level and other niche settings.
2506              
2507             =cut
2508              
2509             sub barcode {
2510 0     0 1 0 my ($self, $format, $value, %options) = @_;
2511 0 0       0 croak "Missing barcode format" unless defined $format;
2512 0 0       0 croak "Missing barcode value" unless defined $value;
2513              
2514             # Set defaults to approximately the minimums for each barcode format.
2515 0 0 0     0 if ($format eq 'codabar') {
    0 0        
    0          
    0          
    0          
2516 0   0     0 $options{'bar_width'} //= 1.8; # 0.025"
2517 0   0     0 $options{'bar_extend'} //= 0;
2518 0   0     0 $options{'quiet_zone'} //= 10 * $options{'bar_width'};
2519 0 0       0 if ($options{'bar_extend'}) {
2520 0   0     0 $options{'font_size'} //= 9 * $options{'bar_width'};
2521             }
2522              
2523             # Minimum height is the larger of 0.25" or 15% of barcode length.
2524 0         0 my $length = (10 * length($value) + 2) * $options{'bar_width'};
2525 0   0     0 $options{'bar_height'} //= max(18, $length * 0.15);
2526             }
2527             elsif ($format eq 'code128' or $format eq 'ean128' or $format eq 'code39') {
2528 0   0     0 $options{'bar_width'} //= 1;
2529 0   0     0 $options{'bar_extend'} //= 0;
2530 0   0     0 $options{'quiet_zone'} //= 11 * $options{'bar_width'};
2531 0 0       0 if ($options{'bar_extend'}) {
2532 0   0     0 $options{'font_size'} //= 10 * $options{'bar_width'};
2533             }
2534              
2535             # Minimum height is the larger of 0.5" or 15% of barcode length.
2536 0         0 my $length = 11 * (length($value) + 1) * $options{'bar_width'};
2537 0   0     0 $options{'bar_height'} //= max(36, $length * 0.15);
2538             }
2539             elsif ($format eq 'itf') {
2540 0   0     0 $options{'bar_width'} //= 1;
2541 0   0     0 $options{'bar_height'} //= 40;
2542 0   0     0 $options{'bar_extend'} //= 0;
2543 0   0     0 $options{'quiet_zone'} //= 10 * $options{'bar_width'};
2544 0 0       0 if ($options{'bar_extend'}) {
2545 0   0     0 $options{'font_size'} //= 9 * $options{'bar_width'};
2546             }
2547             }
2548             elsif ($format eq 'ean13') {
2549 0   0     0 $options{'bar_width'} //= 1;
2550 0   0     0 $options{'bar_height'} //= 64.8;
2551 0   0     0 $options{'quiet_zone'} //= 11 * $options{'bar_width'};
2552 0 0       0 unless ($options{'caption'}) {
2553 0   0     0 $options{'bar_extend'} //= 5 * $options{'bar_width'};
2554             }
2555 0 0       0 if ($options{'bar_extend'}) {
2556 0   0     0 $options{'font_size'} //= 10 * $options{'bar_width'};
2557             }
2558             }
2559             elsif ($format eq 'qr') {
2560 0   0     0 $options{'bar_width'} //= 1;
2561 0   0     0 $options{'bar_height'} //= $options{'bar_width'};
2562 0   0     0 $options{'quiet_zone'} //= 4 * $options{'bar_width'};
2563             }
2564             else {
2565 0         0 croak "Unrecognized barcode format: $format";
2566             }
2567              
2568 0 0       0 if (exists $options{'caption'}) {
2569 0   0     0 $options{'font_size'} //= 10;
2570             }
2571 0 0 0     0 if ($options{'bar_extend'} or $options{'font_size'}) {
2572 0   0     0 $options{'font'} //= $self->font('Helvetica');
2573             }
2574              
2575             # Convert from new arguments to old arguments
2576 0         0 $options{'-color'} = delete $options{'color'};
2577 0         0 $options{'-fnsz'} = delete $options{'font_size'};
2578 0         0 $options{'-font'} = delete $options{'font'};
2579 0         0 $options{'-lmzn'} = delete $options{'bar_extend'};
2580 0         0 $options{'-mils'} = (delete $options{'bar_width'}) * 1000 / 72;
2581 0         0 $options{'-ofwt'} = delete $options{'bar_overflow'};
2582 0         0 $options{'-quzn'} = delete $options{'quiet_zone'};
2583 0         0 $options{'-zone'} = delete $options{'bar_height'};
2584              
2585 0 0       0 if ($format eq 'codabar') {
    0          
    0          
    0          
    0          
    0          
    0          
2586 0         0 return $self->xo_codabar(%options, -code => $value);
2587             }
2588             elsif ($format eq 'code128') {
2589 0         0 return $self->xo_code128(%options, -code => $value);
2590             }
2591             elsif ($format eq 'code39') {
2592 0         0 return $self->xo_3of9(%options, -code => $value);
2593             }
2594             elsif ($format eq 'ean128') {
2595 0         0 return $self->xo_code128(%options, -code => $value, -ean => 1);
2596             }
2597             elsif ($format eq 'ean13') {
2598 0         0 return $self->xo_ean13(%options, -code => $value);
2599             }
2600             elsif ($format eq 'itf') {
2601 0         0 return $self->xo_2of5int(%options, -code => $value);
2602             }
2603             elsif ($format eq 'qr') {
2604 0         0 my $qr_class = 'PDF::API2::Resource::XObject::Form::BarCode::qrcode';
2605 0         0 eval "require $qr_class";
2606 0         0 my $obj = $qr_class->new($self->{'pdf'}, %options, code => $value);
2607             # $self->{'pdf'}->out_obj($self->{'pages'});
2608 0         0 return $obj;
2609             }
2610             }
2611              
2612             sub xo_code128 {
2613 1     1 1 720 my ($self, @opts) = @_;
2614              
2615 1         707 require PDF::API2::Resource::XObject::Form::BarCode::code128;
2616 1         44 my $obj = PDF::API2::Resource::XObject::Form::BarCode::code128->new($self->{'pdf'}, @opts);
2617              
2618 1         9 $self->{'pdf'}->out_obj($self->{'pages'});
2619              
2620 1         4 return $obj;
2621             }
2622              
2623             sub xo_codabar {
2624 1     1 1 9 my ($self, @opts) = @_;
2625              
2626 1         734 require PDF::API2::Resource::XObject::Form::BarCode::codabar;
2627 1         13 my $obj = PDF::API2::Resource::XObject::Form::BarCode::codabar->new($self->{'pdf'}, @opts);
2628              
2629 1         16 $self->{'pdf'}->out_obj($self->{'pages'});
2630              
2631 1         5 return $obj;
2632             }
2633              
2634             sub xo_2of5int {
2635 1     1 1 613 my ($self, @opts) = @_;
2636              
2637 1         778 require PDF::API2::Resource::XObject::Form::BarCode::int2of5;
2638 1         8 my $obj = PDF::API2::Resource::XObject::Form::BarCode::int2of5->new($self->{'pdf'}, @opts);
2639              
2640 1         8 $self->{'pdf'}->out_obj($self->{'pages'});
2641              
2642 1         4 return $obj;
2643             }
2644              
2645             sub xo_3of9 {
2646 2     2 1 567 my ($self, @opts) = @_;
2647              
2648 2         774 require PDF::API2::Resource::XObject::Form::BarCode::code3of9;
2649 2         29 my $obj = PDF::API2::Resource::XObject::Form::BarCode::code3of9->new($self->{'pdf'}, @opts);
2650              
2651 2         15 $self->{'pdf'}->out_obj($self->{'pages'});
2652              
2653 2         11 return $obj;
2654             }
2655              
2656             sub xo_ean13 {
2657 1     1 1 589 my ($self, @opts) = @_;
2658              
2659 1         808 require PDF::API2::Resource::XObject::Form::BarCode::ean13;
2660 1         8 my $obj = PDF::API2::Resource::XObject::Form::BarCode::ean13->new($self->{'pdf'}, @opts);
2661              
2662 1         9 $self->{'pdf'}->out_obj($self->{'pages'});
2663              
2664 1         5 return $obj;
2665             }
2666              
2667             =head2 colorspace
2668              
2669             $colorspace = $pdf->colorspace($type, @arguments);
2670              
2671             Colorspaces can be added to a PDF to either specifically control the output
2672             color on a particular device (spot colors, device colors) or to save space by
2673             limiting the available colors to a defined color palette (web-safe palette, ACT
2674             file).
2675              
2676             Once added to the PDF, they can be used in place of regular hex codes or named
2677             colors:
2678              
2679             my $pdf = PDF::API2->new();
2680             my $page = $pdf->page();
2681             my $content = $page->graphics();
2682              
2683             # Add colorspaces for a spot color and the web-safe color palette
2684             my $spot = $pdf->colorspace('spot', 'PANTONE Red 032 C', '#EF3340');
2685             my $web = $pdf->colorspace('web');
2686              
2687             # Fill using the spot color with 100% coverage
2688             $content->fill_color($spot, 1.0);
2689              
2690             # Stroke using the first color of the web-safe palette
2691             $content->stroke_color($web, 0);
2692              
2693             # Add a rectangle to the page
2694             $content->rectangle(100, 100, 200, 200);
2695             $content->paint();
2696              
2697             $pdf->save('sample.pdf');
2698              
2699             The following types of colorspaces are supported
2700              
2701             =over
2702              
2703             =item * spot
2704              
2705             my $spot = $pdf->colorspace('spot', $tint, $alt_color);
2706              
2707             Spot colors are used to instruct a device (usually a printer) to use or emulate
2708             a particular ink color (C<$tint>) for parts of the document. An C<$alt_color>
2709             is provided for devices (e.g. PDF viewers) that don't know how to produce the
2710             named color. It can either be an approximation of the color in RGB, CMYK, or
2711             HSV formats, or a wildly different color (e.g. 100% magenta, C<%0F00>) to make
2712             it clear if the spot color isn't being used as expected.
2713              
2714             =item * web
2715              
2716             my $web = $pdf->colorspace('web');
2717              
2718             The web-safe color palette is a historical collection of colors that was used
2719             when many display devices only supported 256 colors.
2720              
2721             =item * act
2722              
2723             my $act = $pdf->colorspace('act', $filename);
2724              
2725             An Adobe Color Table (ACT) file provides a custom palette of colors that can be
2726             referenced by PDF graphics and text drawing commands.
2727              
2728             =item * device
2729              
2730             my $devicen = $pdf->colorspace('device', @colorspaces);
2731              
2732             A device-specific colorspace allows for precise color output on a given device
2733             (typically a printing press), bypassing the normal color interpretation
2734             performed by raster image processors (RIPs).
2735              
2736             Device colorspaces are also needed if you want to blend spot colors:
2737              
2738             my $pdf = PDF::API2->new();
2739             my $page = $pdf->page();
2740             my $content = $page->graphics();
2741              
2742             # Create a two-color device colorspace
2743             my $yellow = $pdf->colorspace('spot', 'Yellow', '%00F0');
2744             my $spot = $pdf->colorspace('spot', 'PANTONE Red 032 C', '#EF3340');
2745             my $device = $pdf->colorspace('device', $yellow, $spot);
2746              
2747             # Fill using a blend of 25% yellow and 75% spot color
2748             $content->fill_color($device, 0.25, 0.75);
2749              
2750             # Stroke using 100% spot color
2751             $content->stroke_color($device, 0, 1);
2752              
2753             # Add a rectangle to the page
2754             $content->rectangle(100, 100, 200, 200);
2755             $content->paint();
2756              
2757             $pdf->save('sample.pdf');
2758              
2759             =back
2760              
2761             =cut
2762              
2763             sub colorspace {
2764 0     0 1 0 my $self = shift();
2765 0         0 my $type = shift();
2766              
2767 0 0       0 if ($type eq 'act') {
    0          
    0          
    0          
    0          
2768 0         0 my $file = shift();
2769 0         0 return $self->colorspace_act($file);
2770             }
2771             elsif ($type eq 'web') {
2772 0         0 return $self->colorspace_web();
2773             }
2774             elsif ($type eq 'hue') {
2775             # This type is undocumented until either a reference can be found for
2776             # this being a standard palette like the web color palette, or POD is
2777             # added to the Hue colorspace class that describes how to use it.
2778 0         0 return $self->colorspace_hue();
2779             }
2780             elsif ($type eq 'spot') {
2781 0         0 my $name = shift();
2782 0         0 my $alt_color = shift();
2783 0         0 return $self->colorspace_separation($name, $alt_color);
2784             }
2785             elsif ($type eq 'device') {
2786 0         0 my @colors = @_;
2787 0         0 return $self->colorspace_devicen(\@colors);
2788             }
2789             else {
2790 0         0 croak "Unrecognized or unsupported colorspace: $type";
2791             }
2792             }
2793              
2794             sub colorspace_act {
2795 0     0 1 0 my ($self, $file) = @_;
2796              
2797 0         0 require PDF::API2::Resource::ColorSpace::Indexed::ACTFile;
2798 0         0 return PDF::API2::Resource::ColorSpace::Indexed::ACTFile->new($self->{'pdf'},
2799             $file);
2800             }
2801              
2802             sub colorspace_web {
2803 1     1 1 9 my $self = shift();
2804              
2805 1         661 require PDF::API2::Resource::ColorSpace::Indexed::WebColor;
2806 1         16 return PDF::API2::Resource::ColorSpace::Indexed::WebColor->new($self->{'pdf'});
2807             }
2808              
2809             sub colorspace_hue {
2810 0     0 1 0 my $self = shift();
2811              
2812 0         0 require PDF::API2::Resource::ColorSpace::Indexed::Hue;
2813 0         0 return PDF::API2::Resource::ColorSpace::Indexed::Hue->new($self->{'pdf'});
2814             }
2815              
2816             sub colorspace_separation {
2817 0     0 1 0 my ($self, $name, @clr) = @_;
2818              
2819 0         0 require PDF::API2::Resource::ColorSpace::Separation;
2820 0         0 return PDF::API2::Resource::ColorSpace::Separation->new($self->{'pdf'},
2821             pdfkey(),
2822             $name,
2823             @clr);
2824             }
2825              
2826             sub colorspace_devicen {
2827 0     0 1 0 my ($self, $clrs) = @_;
2828              
2829 0         0 require PDF::API2::Resource::ColorSpace::DeviceN;
2830 0         0 return PDF::API2::Resource::ColorSpace::DeviceN->new($self->{'pdf'},
2831             pdfkey(),
2832             $clrs);
2833             }
2834              
2835             =head2 egstate
2836              
2837             $resource = $pdf->egstate();
2838              
2839             Creates and returns a new extended graphics state object, described in
2840             L.
2841              
2842             =cut
2843              
2844             sub egstate {
2845 3     3 1 18 my $self = shift();
2846              
2847 3         22 my $obj = PDF::API2::Resource::ExtGState->new($self->{'pdf'}, pdfkey());
2848              
2849 3         17 $self->{'pdf'}->out_obj($self->{'pages'});
2850              
2851 3         23 return $obj;
2852             }
2853              
2854             sub default {
2855 8     8 1 36 my ($self, $parameter, $value) = @_;
2856              
2857             # Parameter names may consist of lowercase letters, numbers, and underscores
2858 8         19 $parameter = lc $parameter;
2859 8         56 $parameter =~ s/[^a-z\d_]//g;
2860              
2861 8         21 my $previous_value = $self->{$parameter};
2862 8 100       24 if (defined $value) {
2863 2         6 $self->{$parameter} = $value;
2864             }
2865 8         23 return $previous_value;
2866             }
2867              
2868             sub xo_form {
2869 4     4 0 10 my $self = shift();
2870              
2871 4         74 my $obj = PDF::API2::Resource::XObject::Form::Hybrid->new($self->{'pdf'});
2872              
2873 4         26 $self->{'pdf'}->out_obj($self->{'pages'});
2874              
2875 4         10 return $obj;
2876             }
2877              
2878             sub pattern {
2879 0     0 0   my ($self, %opts) = @_;
2880              
2881 0           my $obj = PDF::API2::Resource::Pattern->new($self->{'pdf'}, undef, %opts);
2882              
2883 0           $self->{'pdf'}->out_obj($self->{'pages'});
2884              
2885 0           return $obj;
2886             }
2887              
2888             sub shading {
2889 0     0 0   my ($self, %opts) = @_;
2890              
2891 0           my $obj = PDF::API2::Resource::Shading->new($self->{'pdf'}, undef, %opts);
2892              
2893 0           $self->{'pdf'}->out_obj($self->{'pages'});
2894              
2895 0           return $obj;
2896             }
2897              
2898             sub named_destination {
2899 0     0 0   my ($self, $cat, $name, $obj) = @_;
2900 0           my $root = $self->{'catalog'};
2901              
2902 0   0       $root->{'Names'} ||= PDFDict();
2903 0   0       $root->{'Names'}->{$cat} ||= PDFDict();
2904 0   0       $root->{'Names'}->{$cat}->{'-vals'} ||= {};
2905 0   0       $root->{'Names'}->{$cat}->{'Limits'} ||= PDFArray();
2906 0   0       $root->{'Names'}->{$cat}->{'Names'} ||= PDFArray();
2907              
2908 0 0         unless (defined $obj) {
2909 0           $obj = PDF::API2::NamedDestination->new($self->{'pdf'});
2910             }
2911 0           $root->{'Names'}->{$cat}->{'-vals'}->{$name} = $obj;
2912              
2913 0           my @names = sort {$a cmp $b} keys %{$root->{'Names'}->{$cat}->{'-vals'}};
  0            
  0            
2914              
2915 0           $root->{'Names'}->{$cat}->{'Limits'}->{' val'}->[0] = PDFStr($names[0]);
2916 0           $root->{'Names'}->{$cat}->{'Limits'}->{' val'}->[1] = PDFStr($names[-1]);
2917              
2918 0           @{$root->{'Names'}->{$cat}->{'Names'}->{' val'}} = ();
  0            
2919              
2920 0           foreach my $k (@names) {
2921 0           push @{$root->{'Names'}->{$cat}->{'Names'}->{' val'}}, (
2922             PDFStr($k),
2923 0           $root->{'Names'}->{$cat}->{'-vals'}->{$k}
2924             );
2925             }
2926              
2927 0           return $obj;
2928             }
2929              
2930             1;
2931              
2932             __END__