File Coverage

blib/lib/PDF/Builder.pm
Criterion Covered Total %
statement 971 1646 58.9
branch 383 982 39.0
condition 154 458 33.6
subroutine 93 140 66.4
pod 100 110 90.9
total 1701 3336 50.9


line stmt bran cond sub pod time code
1             package PDF::Builder;
2              
3 39     39   5431259 use strict;
  39         118  
  39         1677  
4 39     39   440 use warnings;
  39         87  
  39         5638  
5              
6             # $VERSION defined here so developers can run PDF::Builder from git.
7             # it should be automatically updated as part of the CPAN build.
8             our $VERSION = '3.028'; # VERSION
9             our $LAST_UPDATE = '3.028'; # manually update whenever code is changed
10              
11             # updated during CPAN build
12             my $GrTFversion = 19; # minimum version of Graphics::TIFF
13             my $HBShaperVer = 0.024; # minimum version of HarfBuzz::Shaper
14             my $LpngVersion = 0.57; # minimum version of Image::PNG::Libpng
15             my $TextMarkdown = 1.000031; # minimum version of Text::Markdown
16             my $HTMLTreeBldr = 5.07; # minimum version of HTML::TreeBuilder
17             my $PodSimpleXHTML = 3.45; # minimum version of Pod::Simple::XHTML
18             my $SVGPDFver = 0.087; # minimum version of SVGPDF
19              
20 39     39   294 use Carp;
  39         133  
  39         3541  
21 39     39   25446 use Encode qw(:all);
  39         844794  
  39         13036  
22 39     39   20487 use English;
  39         118112  
  39         246  
23 39     39   38983 use FileHandle;
  39         431993  
  39         315  
24 39     39   32461 use version;
  39         88297  
  39         259  
25              
26 39     39   29185 use PDF::Builder::Basic::PDF::Utils;
  39         222  
  39         4947  
27 39     39   25169 use PDF::Builder::Util;
  39         223  
  39         7594  
28              
29 39     39   35615 use PDF::Builder::Basic::PDF::File;
  39         235  
  39         2510  
30 39     39   385 use PDF::Builder::Basic::PDF::Pages;
  39         190  
  39         1087  
31 39     39   28454 use PDF::Builder::Page;
  39         220  
  39         2530  
32              
33 39     39   29046 use PDF::Builder::Resource::XObject::Form::Hybrid;
  39         209  
  39         1812  
34              
35 39     39   22758 use PDF::Builder::Resource::ExtGState;
  39         165  
  39         1675  
36 39     39   21479 use PDF::Builder::Resource::Pattern;
  39         144  
  39         1670  
37 39     39   20924 use PDF::Builder::Resource::Shading;
  39         141  
  39         1657  
38              
39 39     39   22632 use PDF::Builder::NamedDestination;
  39         157  
  39         1715  
40 39     39   26811 use PDF::Builder::FontManager;
  39         151  
  39         2116  
41              
42 39     39   330 use List::Util qw(max);
  39         86  
  39         3315  
43 39     39   249 use Scalar::Util qw(weaken);
  39         88  
  39         1110205  
44              
45             # Note that every Linux distribution seems to put font files in a different
46             # place, and even Windows is consistent only for TTF/OTF font files.
47             my @font_path = __PACKAGE__->set_font_path(
48             '.', # could a font ever be a security risk?
49             '/usr/share/fonts',
50             '/usr/local/share/fonts',
51             '/usr/share/fonts/type1/gsfonts',
52             '/usr/share/X11/fonts/urw-fonts',
53             '/usr/share/fonts/urw-base35',
54             '/usr/share/fonts/dejavu-sans-fonts',
55             '/usr/share/fonts/truetype/ttf-dejavu',
56             '/usr/share/fonts/truetype/dejavu',
57             '/var/lib/defoma/gs.d/dirs/fonts',
58             '/Windows/Fonts',
59             '/Users/XXXX/AppData/Local/Microsoft/Windows/Fonts',
60             '/WinNT/Fonts'
61             );
62              
63             our @MSG_COUNT = (0, # [0] Graphics::TIFF not installed
64             0, # [1] Image::PNG::Libpng not installed
65             0, # [2] save/restore in text mode
66             0, # [3] Times-Roman core font substituted for Times
67             0, # [4] TBD...
68             );
69             our $outVer = 1.4; # desired PDF version for output, bump up w/ warning on read or feature output
70             our $msgVer = 1; # 0=don't, 1=do issue message when PDF output version is bumped up
71             our $myself; # holds self->pdf
72             our $global_pdf; # holds self ($pdf)
73              
74             require PDF::Builder::FontManager;
75              
76             =head1 NAME
77              
78             PDF::Builder - Facilitates the creation and modification of PDF files
79              
80             =head1 SYNOPSIS
81              
82             use PDF::Builder;
83              
84             # Create a blank PDF file
85             $pdf = PDF::Builder->new();
86              
87             # Open an existing PDF file
88             $pdf = PDF::Builder->open('some.pdf');
89              
90             # Add a blank page
91             $page = $pdf->page();
92              
93             # Retrieve an existing page
94             $page = $pdf->open_page($page_number);
95              
96             # Set the page size
97             $page->size('Letter'); # or mediabox('Letter')
98              
99             # Add a built-in font to the PDF
100             $font = $pdf->font('Helvetica-Bold'); # or corefont('Helvetica-Bold')
101              
102             # Add an external TrueType (TTF) font to the PDF
103             $font = $pdf->font('/path/to/font.ttf'); # or ttfont() in this case
104              
105             # Add some text to the page
106             $text = $page->text();
107             $text->font($font, 20);
108             $text->position(200, 700); # or translate()
109             $text->text('Hello World!');
110              
111             # Save the PDF
112             $pdf->saveas('/path/to/new.pdf');
113              
114             =head1 SOME SPECIAL NOTES
115              
116             See the file README.md (in downloadable package and on CPAN) for a summary of
117             prerequisites and tools needed to install PDF::Builder, both mandatory and
118             optional.
119              
120             =head2 SOFTWARE DEVELOPMENT KIT
121              
122             There are four levels of involvement with PDF::Builder. Depending on what you
123             want to do, different kinds of installs are recommended.
124             See L<PDF::Builder::Docs/Software Development Kit> for suggestions.
125              
126             =head2 OPTIONAL LIBRARIES
127              
128             PDF::Builder can make use of some optional libraries, which are not I<required>
129             for a successful installation, but improve speed and capabilities. See
130             L<PDF::Builder::Docs/Optional Libraries> for more information.
131              
132             =head2 STRINGS (CHARACTER TEXT)
133              
134             There are some things you should know about character encoding (for text),
135             before you dive in to coding. Please go to L<PDF::Builder::Docs/Strings (Character Text)> and have a read.
136              
137             =head2 RENDERING ORDER
138              
139             Invoking "text" and "graphics" methods can lead to unexpected results (a
140             different ordering of output than intended). See L<PDF::Builder::Docs/Rendering Order> for more information.
141              
142             =head2 PDF VERSIONS SUPPORTED
143              
144             PDF::Builder is mostly PDF 1.4-compliant, but there I<are> complications you
145             should be aware of. Please read L<PDF::Builder::Docs/PDF Versions Supported>
146             for details.
147              
148             =head2 SUPPORTED PERL VERSIONS (BACKWARDS COMPATIBILITY GOALS)
149              
150             PDF::Builder intends to support all major Perl versions that were released in
151             the past six years, plus one, in order to continue working for the life of
152             most long-term-stable (LTS) server distributions.
153             See L<PDF::Builder::Docs/Supported Perl Versions> for more information,
154             including expected cutoff dates for Perl versions.
155              
156             =head2 KNOWN ISSUES
157              
158             This module does not work with Perl's -l command-line switch.
159              
160             There is a file INFO/KNOWN_INCOMP which lists known incompatibilities with
161             PDF::API2, in case you're thinking of porting over something from that world,
162             or have experience there and want to try PDF::Builder. There is also a file
163             INFO/DEPRECATED, which lists things which are planned to be removed at some
164             point.
165              
166             =head2 HISTORY
167              
168             The history of PDF::Builder is a complex and exciting saga... OK, it may be
169             mildly interesting. Have a look at L<PDF::Builder::Docs/History> section.
170              
171             =head2 AUTHOR
172              
173             PDF::API2 was originally written by Alfred Reibenschuh. See the HISTORY section
174             for more information.
175              
176             It was maintained by Steve Simms, who is still contributing new code to it
177             (which often ends up in PDF::Builder).
178              
179             PDF::Builder is currently being maintained by Phil M. Perry.
180              
181             =head2 SUPPORT
182              
183             The full source is on https://github.com/PhilterPaper/Perl-PDF-Builder.
184              
185             The release distribution is on CPAN: https://metacpan.org/pod/PDF::Builder.
186              
187             A formatted copy of the documentation (POD) may be found online, for your
188             convenience, at https://www.catskilltech.com/Documentation/PDF/Builder.html.
189              
190             Copies of most of the output of "examples/" sample programs may be found
191             online at https://www.catskilltech.com/Examples/PDF/Builder.html.
192              
193             Bug reports are on https://github.com/PhilterPaper/Perl-PDF-Builder/issues?q=is%3Aissue+sort%3Aupdated-desc
194             (with "bug" label), feature requests have an "enhancement" label, and general
195             discussions (architecture, roadmap, etc.) have a "general discussion" label.
196              
197             Do B<not> under I<any> circumstances open a PR (Pull Request) to report a bug.
198             That's B<not> what a PR is for, and
199             is a waste of both your and our time and effort. Open a regular ticket
200             (issue), and attach a Perl (.pl) program illustrating the problem, if possible.
201             If you believe that you have a program patch, and offer to share it as a PR, we
202             may give the go-ahead. Unsolicited PRs may be closed without further action.
203              
204             =head2 LICENSE
205              
206             This software is Copyright (c) 2017-2025 by Phil M. Perry.
207              
208             This is free software, licensed under:
209              
210             The GNU Lesser General Public License (LGPL) Version 2.1, February 1999
211              
212             (The master copy of this license lives on the GNU website.)
213             (A copy is provided in the INFO/LICENSE file for your convenience.)
214              
215             This section of Builder.pm is intended only as a very brief summary
216             of the license; please consider INFO/LICENSE to be the controlling version,
217             if there is any conflict or ambiguity between the two.
218              
219             This program is free software; you can redistribute it and/or modify it under
220             the terms of the GNU Lesser General Public License, as published by the Free
221             Software Foundation, either version 2.1 of the License, or (at your option) any
222             later version of this license.
223              
224             NOTE: there are several files in this distribution which were incorporated from
225             outside sources and carry different licenses. If a file states that it is under
226             a license different than LGPL 2.1, that license and its terms will apply to
227             that file, and not LGPL 2.1.
228              
229             This library is distributed in the hope that it will be useful, but WITHOUT ANY
230             WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
231             PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
232              
233             =head1 GENERAL PURPOSE METHODS
234              
235             =head2 new
236              
237             $pdf = PDF::Builder->new(%opts)
238              
239             =over
240              
241             Creates a new PDF object.
242              
243             B<Options>
244              
245             =back
246              
247             =over
248              
249             =item file
250              
251             If you will be saving it as a file and
252             already know the filename, you can give the 'file' option to minimize
253             possible memory requirements later on (the file is opened immediately for
254             writing, rather than waiting until the C<save>). The C<file> may also be
255             a filehandle.
256              
257             =item compress
258              
259             The 'compress' option can be
260             given to specify stream compression: default is 'flate', 'none' (or 0) is no
261             compression. No other compression methods are currently supported.
262              
263             =item outver
264              
265             The 'outver' option defaults to 1.4 as the output PDF version and the highest
266             allowed feature version (attempts to use anything higher will give a warning).
267             If an existing PDF with a higher version is read in, C<outver> will be
268             increased to that version, with a warning.
269              
270             =item msgver
271              
272             The 'msgver' option value of 1 (default) gives a warning message if the
273             'outver' PDF level has to be bumped up due to either a higher PDF level file
274             being read in, or a higher level feature was requested. A value of 0
275             suppresses the warning message.
276              
277             =item diaglevel
278              
279             The 'diaglevel' option can be
280             given to specify the level of diagnostics given by IntegrityCheck(). The
281             default is level 2 (errors and warnings).
282             See L<PDF::Builder::Docs/IntegrityCheck> for more information.
283              
284             =back
285              
286             B<Example:>
287              
288             $pdf = PDF::Builder->new();
289             ...
290             print $pdf->to_string();
291              
292             $pdf = PDF::Builder->new(compress => 'none');
293             # equivalent to $pdf->{'forcecompress'} = 'none'; (or older, 0)
294              
295             $pdf = PDF::Builder->new();
296             ...
297             $pdf->saveas('our/new.pdf');
298              
299             $pdf = PDF::Builder->new(file => 'our/new.pdf');
300             ...
301             $pdf->save();
302              
303             =cut
304              
305             sub new {
306 234     234 1 8473012 my ($class, %opts) = @_;
307             # copy dashed option names to preferred undashed names
308 234 100 66     1674 if (defined $opts{'-compress'} && !defined $opts{'compress'}) { $opts{'compress'} = delete($opts{'-compress'}); }
  19         85  
309 234 50 33     1233 if (defined $opts{'-diaglevel'} && !defined $opts{'diaglevel'}) { $opts{'diaglevel'} = delete($opts{'-diaglevel'}); }
  0         0  
310 234 50 33     1468 if (defined $opts{'-outver'} && !defined $opts{'outver'}) { $opts{'outver'} = delete($opts{'-outver'}); }
  0         0  
311 234 50 33     1074 if (defined $opts{'-msgver'} && !defined $opts{'msgver'}) { $opts{'msgver'} = delete($opts{'-msgver'}); }
  0         0  
312 234 50 33     1110 if (defined $opts{'-file'} && !defined $opts{'file'}) { $opts{'file'} = delete($opts{'-file'}); }
  0         0  
313              
314 234         615 my $self = {};
315 234         557 bless $self, $class;
316 234         2663 $self->{'pdf'} = PDF::Builder::Basic::PDF::File->new();
317              
318             # make available to other routines
319 234         1455 $myself = $self->{'pdf'};
320              
321             # default output version
322 234         757 $self->{'pdf'}->{' version'} = $outVer;
323 234         2399 $self->{'pages'} = PDF::Builder::Basic::PDF::Pages->new($self->{'pdf'});
324 234         1397 $self->{'pages'}->proc_set(qw(PDF Text ImageB ImageC ImageI));
325 234   33     3351 $self->{'pages'}->{'Resources'} ||= PDFDict();
326             $self->{'pdf'}->new_obj($self->{'pages'}->{'Resources'})
327 234 50       1364 unless $self->{'pages'}->{'Resources'}->is_obj($self->{'pdf'});
328 234         856 $self->{'catalog'} = $self->{'pdf'}->{'Root'};
329 234         616 weaken $self->{'catalog'};
330 234         620 $self->{'fonts'} = {};
331 234         714 $self->{'pagestack'} = [];
332              
333 234         823 $self->{'pdf'}->{' userUnit'} = 1.0; # default global User Unit
334 234         1502 $self->mediabox('letter'); # PDF defaults to US Letter 8.5in x 11in
335              
336 234 100       957 if (exists $opts{'compress'}) {
337 154         575 $self->{'forcecompress'} = $opts{'compress'};
338             # at this point, no validation of given value! none/flate (0/1).
339             # note that >0 is often used as equivalent to 'flate'
340             } else {
341 80         358 $self->{'forcecompress'} = 'flate';
342             # code should also allow integers 0 (= 'none') and >0 (= 'flate')
343             # for compatibility with old usage where forcecompress is directly set.
344             }
345 234 50       688 if (exists $opts{'diaglevel'}) {
346 0         0 my $diaglevel = $opts{'diaglevel'};
347 0 0 0     0 if ($diaglevel < 0 || $diaglevel > 5) {
348 0         0 print "diaglevel must be in range 0-5. using 2\n";
349 0         0 $diaglevel = 2;
350             }
351 0         0 $self->{'diaglevel'} = $diaglevel;
352             } else {
353 234         903 $self->{'diaglevel'} = 2; # default: errors and warnings
354             }
355              
356 234         1499 $self->preferences(%opts);
357 234 100       794 if (defined $opts{'outver'}) {
358 1 50       4 if ($opts{'outver'} >= 1.4) {
359 1         4 $self->{'pdf'}->{' version'} = $opts{'outver'};
360             } else {
361 0         0 print STDERR "Invalid outver given, or less than 1.4. Ignored.\n";
362             }
363             }
364 234 100       808 if (defined $opts{'msgver'}) {
365 1 50 33     5 if ($opts{'msgver'} == 0 || $opts{'msgver'} == 1) {
366 1         2 $msgVer = $opts{'msgver'};
367             } else {
368 0         0 print STDERR "Invalid msgver given, not 0 or 1. Ignored.\n";
369             }
370             }
371 234 50       771 if ($opts{'file'}) {
372 0         0 $self->{'pdf'}->create_file($opts{'file'});
373 0         0 $self->{'partial_save'} = 1;
374             }
375             # used by info and infoMetaAttributes but not by their replacements
376 234         1318 $self->{'infoMeta'} = [qw(Author CreationDate ModDate Creator Producer
377             Title Subject Keywords)];
378              
379 234   50     535 my $version = eval { $PDF::Builder::VERSION } || '(Development Version)';
380             #$self->info('Producer' => "PDF::Builder $version [$^O]");
381 234         1969 $self->info('Producer' => "PDF::Builder $version [see ".
382             "https://github.com/PhilterPaper/Perl-PDF-Builder/blob/master/INFO/SUPPORT]");
383              
384 234         603 $global_pdf = $self;
385             # initialize Font Manager
386 234         2440 require PDF::Builder::FontManager;
387 234         2365 $self->{' FM'} = PDF::Builder::FontManager->new($self);
388              
389 234         4745 return $self;
390             } # end of new()
391              
392             =head2 default_page_size
393              
394             @rectangle = $pdf->default_page_size($size); # Set
395              
396             @rectangle = $pdf->default_page_size() # Get
397              
398             =over
399              
400             Set the default physical size for pages in the PDF. If called without
401             arguments (Get), return an array of the coordinates of the rectangle
402             describing the default physical page size (the Media Box). I<Setting> the
403             size also returns the resulting media size.
404              
405             This is essentially an alternate method of defining the C<mediabox()> call,
406             and added for compatibility with PDF::API2.
407              
408             See L<PDF::Builder::Page/Page Sizes> for possible values.
409              
410             Note that this method is I<only> at the PDF (document) level. It is not
411             implemented at the page level. If you want to set or get the page-level
412             override of the media size, use the C<mediabox()> method.
413              
414             =back
415              
416             =cut
417              
418             sub default_page_size {
419 1     1 1 6258 my $self = shift();
420              
421             # Set
422 1 50       6 if (@_) {
423 1         8 return $self->mediabox(@_);
424             }
425              
426             # Get
427             # up to 5 hash elements of 4 number arrays
428 0         0 my %boundaries = $self->default_page_boundaries();
429 0         0 return @{$boundaries{'media'}}; # s/b 4 element array
  0         0  
430             }
431              
432             =head2 default_page_boundaries
433              
434             %boundaries = $pdf->default_page_boundaries('media' =>
435             [xmin, ymin, xmax, ymax]); # Set the media box
436              
437             %boundaries = $pdf->default_page_boundaries(); # Get (all five)
438             @media_rect = @{ $boundaries{'media'} }; # show 'media' box
439              
440             =over
441              
442             Set default prepress page boundaries ('boxes') for pages in the PDF. If called
443             without arguments, returns the coordinates of the rectangles describing each
444             of the supported page boundaries, as a hash of array refs. Each will be US
445             Letter size, unless it has been explicitly changed. I<Setting> the values
446             will also return the hash.
447              
448             See the equivalent C<page_boundaries> method in L<PDF::Builder::Page> for
449             details.
450              
451             =back
452              
453             =cut
454              
455             # Called by PDF::Builder::Page::boundaries via the default_page_* methods below
456             sub _bounding_box {
457 7     7   10487 my $self = shift();
458 7         18 my $type = shift();
459              
460             # Get
461 7 100       57 unless (scalar @_) {
462 4 50       964 unless ($self->{'pages'}->{$type}) {
463 0 0       0 return if $type eq 'MediaBox';
464              
465             # Use defaults per PDF 1.7 section 14.11.2 Page Boundaries
466 0 0       0 return $self->_bounding_box('MediaBox') if $type eq 'CropBox';
467 0         0 return $self->_bounding_box('CropBox');
468             }
469 4         25 my @xxx = $self->{'pages'}->{$type}->elements(); # 4 element array of hashes
470 4         12 return (map { $_->val() } @xxx);
  16         42  
471             }
472              
473             # Set
474 3         8 $self->{'pages'}->{$type} = PDFArray(map { PDFNum(float($_)) } @_);
  12         38  
475 3         12 return $self;
476             }
477              
478             sub default_page_boundaries {
479 2     2 1 10612 my %xxx = PDF::Builder::Page::boundaries(@_);
480             # 5 element 'media' etc. hash of anonymous arrays each 4 numbers
481 2         10 return %xxx;
482             }
483              
484             # Deprecated; use default_page_size or default_page_boundaries
485             # alternate implementations of media, crop, etc. boxes
486             #sub mediabox {
487             # my $self = shift();
488             # return $self->_bounding_box('MediaBox') unless @_;
489             # return $self->_bounding_box('MediaBox', page_size(@_));
490             #}
491              
492             # Deprecated; use default_page_boundaries
493             #sub cropbox {
494             # my $self = shift();
495             # return $self->_bounding_box('CropBox') unless @_;
496             # return $self->_bounding_box('CropBox', page_size(@_));
497             #}
498              
499             # Deprecated; use default_page_boundaries
500             #sub bleedbox {
501             # my $self = shift();
502             # return $self->_bounding_box('BleedBox') unless @_;
503             # return $self->_bounding_box('BleedBox', page_size(@_));
504             #}
505              
506             # Deprecated; use default_page_boundaries
507             #sub trimbox {
508             # my $self = shift();
509             # return $self->_bounding_box('TrimBox') unless @_;
510             # return $self->_bounding_box('TrimBox', page_size(@_));
511             #}
512              
513             # Deprecated; use default_page_boundaries
514             #sub artbox {
515             # my $self = shift();
516             # return $self->_bounding_box('ArtBox') unless @_;
517             # return $self->_bounding_box('ArtBox', page_size(@_));
518             #}
519              
520             =head1 INPUT/OUTPUT METHODS
521              
522             =head2 open
523              
524             $pdf = PDF::Builder->open($pdf_file, %opts)
525              
526             =over
527              
528             Opens an existing PDF file. See C<new()> for options.
529              
530             B<Example:>
531              
532             =back
533              
534             $pdf = PDF::Builder->open('our/old.pdf');
535             ...
536             $pdf->saveas('our/new.pdf');
537              
538             $pdf = PDF::Builder->open('our/to/be/updated.pdf');
539             ...
540             $pdf->update();
541              
542             =cut
543              
544             sub open { ## no critic
545 8     8 1 804961 my ($class, $file, %opts) = @_;
546 8 50       317 croak "File '$file' does not exist" unless -f $file;
547 8 50       143 croak "File '$file' is not readable" unless -r $file;
548              
549 8         33 my $content;
550 8         101 my $scalar_fh = FileHandle->new();
551 8 50       723 CORE::open($scalar_fh, '+<', \$content) or croak "Can't begin scalar IO";
552 8         50 binmode $scalar_fh, ':raw';
553              
554 8         42 my $disk_fh = FileHandle->new();
555 8 50       652 CORE::open($disk_fh, '<', $file) or croak "Can't open $file for reading: $!";
556 8         52 binmode $disk_fh, ':raw';
557 8         64 $disk_fh->seek(0, 0);
558 8         84 my $data;
559 8         52 while (not $disk_fh->eof()) {
560 49         1045 $disk_fh->read($data, 512);
561 49         331 $scalar_fh->print($data);
562             }
563             # check if final %%EOF lacks a carriage return on the end (add one)
564 8 50       226 if ($data =~ m/%%EOF$/) {
565             #print "open() says missing final EOF\n";
566 8         31 $scalar_fh->print("\n");
567             }
568 8         79 $disk_fh->close();
569 8         202 $scalar_fh->seek(0, 0);
570              
571 8         101 my $self = $class->from_string($content, %opts);
572 8         55 $self->{'pdf'}->{' fname'} = $file;
573              
574 8         404 return $self;
575             } # end of open()
576              
577             =head2 from_string, open_scalar, openScalar
578              
579             $pdf = PDF::Builder->from_string($pdf_string, %opts)
580              
581             =over
582              
583             Opens a PDF contained in a string. See C<new()> for other options.
584              
585             =back
586              
587             =over
588              
589             =item diags => 1
590              
591             Display warnings when non-conforming PDF structure is found, and fix up
592             where possible. See L<PDF::Builder::Basic::PDF::File> for more information.
593              
594             =back
595              
596             B<Example:>
597              
598             # Read a PDF into a string, for the purpose of demonstration
599             open $fh, 'our/old.pdf' or croak $@;
600             undef $/; # Read the whole file at once
601             $pdf_string = <$fh>;
602              
603             $pdf = PDF::Builder->from_string($pdf_string);
604             ...
605             $pdf->saveas('our/new.pdf');
606              
607             =over
608              
609             B<Alternate name:> C<open_scalar>
610              
611             C<from_string> was formerly known as C<open_scalar> (and even before that,
612             as C<openScalar>), and this older name is still
613             valid as an alternative to C<from_string>. It is I<possible> that C<open_scalar>
614             will be deprecated and then removed some time in the future, so it may be
615             advisable to use C<from_string> in new work.
616              
617             =back
618              
619             =cut
620              
621 1     1 1 1382 sub open_scalar { return from_string(@_); } ## no critic
622 1     1 1 14 sub openScalar { return from_string(@_); } ## no critic
623              
624             sub from_string {
625 18     18 1 3631 my ($class, $content, %opts) = @_;
626             # copy dashed option names to preferred undashed names
627 18 50 33     133 if (defined $opts{'-diags'} && !defined $opts{'diags'}) { $opts{'diags'} = delete($opts{'-diags'}); }
  0         0  
628 18 50 33     86 if (defined $opts{'-compress'} && !defined $opts{'compress'}) { $opts{'compress'} = delete($opts{'-compress'}); }
  0         0  
629 18 50 33     110 if (defined $opts{'-diaglevel'} && !defined $opts{'diaglevel'}) { $opts{'diaglevel'} = delete($opts{'-diaglevel'}); }
  0         0  
630              
631 18 50       64 if (ref($class)) { $class = ref($class); }
  0         0  
632             # my $self = {};
633             # bless $self, $class;
634             # foreach my $parameter (keys %opts) {
635             # $self->default($parameter, $opts{$parameter});
636             # }
637 18         99 my $self = $class->new(%opts);
638              
639 18         61 $self->{'content_ref'} = \$content;
640 18         52 my $diaglevel = 2;
641 18 50       79 if (defined $self->{'diaglevel'}) { $diaglevel = $self->{'diaglevel'}; }
  18         50  
642 18 50 33     150 if ($diaglevel < 0 || $diaglevel > 5) { $diaglevel = 2; }
  0         0  
643 18         141 my $newVer = $self->IntegrityCheck($diaglevel, $content);
644             # if Version override defined in PDF, need to overwrite the %PDF-x.y
645             # statement with the new (if higher) value. it's too late to wait until
646             # after File->open, as it's already complained about some >1.4 features.
647 18 50       65 if (defined $newVer) {
648 18         56 my ($verStr, $currentVer, $pos);
649 18         66 $pos = index $content, "%PDF-";
650 18 50       62 if ($pos < 0) { croak "no PDF version found in PDF input!"; }
  0         0  
651             # assume major and minor PDF version numbers max 2 digits each for now
652             # (are 1 or 2 and 0-7 at this writing)
653 18         64 $verStr = substr($content, $pos, 10);
654 18 50       145 if ($verStr =~ m#^%PDF-(\d+)\.(\d+)#) {
655 18         91 $currentVer = "$1.$2";
656             } else {
657 0         0 croak "unable to get PDF input's version number.";
658             }
659 18 50       138 if ($newVer > $currentVer) {
660 0 0       0 if (length($newVer) > length($currentVer)) {
661 0         0 print STDERR "Unable to update 'content' version because override '$newVer' is longer ".
662             "than header version '$currentVer'.\nYou may receive warnings about features ".
663             "that bump up the PDF level.\n";
664             } else {
665 0 0       0 if (length($newVer) < length($currentVer)) {
666             # unlikely, but cover all the bases
667 0         0 $newVer = substr($newVer, 0, length($currentVer));
668             }
669 0         0 substr($content, $pos+5, length($newVer)) = $newVer;
670 0         0 $self->pdf_version($newVer);
671             }
672             }
673             }
674              
675 18         45 my $fh;
676 18 50       375 CORE::open($fh, '+<', \$content) or croak "Can't begin scalar IO";
677              
678             # this would replace any existing self->pdf with a new one
679 18         264 $self->{'pdf'} = PDF::Builder::Basic::PDF::File->open($fh, 1, %opts);
680 18         114 $self->{'pdf'}->{'Root'}->realise();
681 18         109 $self->{'pages'} = $self->{'pdf'}->{'Root'}->{'Pages'}->realise();
682 18         58 weaken $self->{'pages'};
683              
684 18   50     83 $self->{'pdf'}->{' version'} ||= 1.4; # default minimum
685             # if version higher than desired output PDF level, give warning and
686             # bump up desired output PDF level
687 18         124 $self->verCheckInput($self->{'pdf'}->{' version'});
688              
689 18         192 my @pages = _proc_pages($self->{'pdf'}, $self->{'pages'});
690 18         127 $self->{'pagestack'} = [sort { $a->{' pnum'} <=> $b->{' pnum'} } @pages];
  3         23  
691 18         52 weaken $self->{'pagestack'}->[$_] for (0 .. scalar @{$self->{'pagestack'}});
  18         146  
692 18         75 $self->{'catalog'} = $self->{'pdf'}->{'Root'};
693 18         41 weaken $self->{'catalog'};
694 18         90 $self->{'opened_scalar'} = 1;
695 18 100       109 if (exists $opts{'compress'}) {
696 3         11 $self->{'forcecompress'} = $opts{'compress'};
697             # at this point, no validation of given value! none/flate (0/1).
698             # note that >0 is often used as equivalent to 'flate'
699             } else {
700 15         65 $self->{'forcecompress'} = 'flate';
701             # code should also allow integers 0 (= 'none') and >0 (= 'flate')
702             # for compatibility with old usage where forcecompress is directly set.
703             }
704 18 50       69 if (exists $opts{'diaglevel'}) {
705 0         0 $self->{'diaglevel'} = $opts{'diaglevel'};
706 0 0 0     0 if ($self->{'diaglevel'} < 0 || $self->{'diaglevel'} > 5) {
707 0         0 $self->{'diaglevel'} = 2;
708             }
709             } else {
710 18         43 $self->{'diaglevel'} = 2;
711             }
712 18         62 $self->{'fonts'} = {};
713 18         204 $self->{'infoMeta'} = [qw(Author CreationDate ModDate Creator Producer Title Subject Keywords)];
714              
715 18         497 return $self;
716             } # end of from_string()
717              
718             =head2 to_string, stringify
719              
720             $string = $pdf->to_string()
721              
722             =over
723              
724             Return the document as a string and remove the object structure from memory.
725              
726             B<Caution:> Although the object C<$pdf> will still exist, it is no longer
727             usable for any purpose after invoking this method! You will receive error
728             messages about "can't call method new_obj on an undefined value".
729              
730             B<Example:>
731              
732             =back
733              
734             $pdf = PDF::Builder->new();
735             ...
736             print $pdf->to_string();
737              
738             =over
739              
740             B<Alternate name:> C<stringify>
741              
742             C<to_string> was formerly known as C<stringify>, and this older name is still
743             valid as an alternative to C<to_string>. It is I<possible> that C<stringify>
744             will be deprecated and then removed some time in the future, so it may be
745             advisable to use C<to_string> in new work.
746              
747             =back
748              
749             =cut
750              
751             # Maintainer's note: The object is being destroyed because it contains
752             # circular references that would otherwise result in memory not being
753             # freed if the object merely goes out of scope. If possible, the
754             # circular references should be eliminated so that to_string doesn't
755             # need to be destructive. See t/circular-references.t.
756             #
757             # I've opted not to just require a separate call to release() because
758             # it would likely introduce memory leaks in many existing programs
759             # that use this module.
760             # - Steve S. (see bug RT 81530)
761              
762 0     0 1 0 sub stringify { return to_string(@_); } ## no critic
763              
764             sub to_string {
765 177     177 1 2352 my $self = shift();
766              
767 177         655 my $string = '';
768             # is only set to 1 (within from_string()), otherwise is undef
769 177 100       613 if ($self->{'opened_scalar'}) {
770 7         60 $self->{'pdf'}->append_file();
771 7         15 $string = ${$self->{'content_ref'}};
  7         73  
772             } else {
773 170         1760 my $fh = FileHandle->new();
774             # we should be writing to the STRING $str
775 170 50       12132 CORE::open($fh, '>', \$string) || croak "Can't begin scalar IO";
776 170         1615 $self->{'pdf'}->out_file($fh);
777 170         938 $fh->close();
778             }
779              
780             # This can be eliminated once we're confident that circular references are
781             # no longer an issue. See t/circular-references.t
782 177         2336 $self->end();
783              
784 177         3870 return $string;
785             }
786              
787             =head2 finishobjects
788              
789             $pdf->finishobjects(@objects)
790              
791             =over
792              
793             Force objects to be written to file if possible.
794              
795             B<Example:>
796              
797             =back
798              
799             $pdf = PDF::Builder->new(file => 'our/new.pdf');
800             ...
801             $pdf->finishobjects($page, $gfx, $txt);
802             ...
803             $pdf->save();
804              
805             =over
806              
807             B<Note:> this method is now considered obsolete, and may be deprecated. It
808             allows for objects to be written to disk in advance of finally
809             saving and closing the file. Otherwise, it's no different than just calling
810             C<save()> when all changes have been made. There's no memory advantage since
811             C<ship_out> doesn't remove objects from memory.
812              
813             =back
814              
815             =cut
816              
817             # obsolete, use save instead
818             #
819             # This method allows for objects to be written to disk in advance of finally
820             # saving and closing the file. Otherwise, it's no different than just calling
821             # save when all changes have been made. There's no memory advantage since
822             # ship_out doesn't remove objects from memory.
823             sub finishobjects {
824 0     0 1 0 my ($self, @objs) = @_;
825              
826 0 0       0 if ($self->{'opened_scalar'}) {
    0          
827 0         0 croak "invalid method invocation: no file, use 'saveas' instead.";
828             } elsif ($self->{'partial_save'}) {
829 0         0 $self->{'pdf'}->ship_out(@objs);
830             } else {
831 0         0 croak "invalid method invocation: no file, use 'saveas' instead.";
832             }
833              
834 0         0 return;
835             }
836              
837             sub _proc_pages {
838 18     18   64 my ($pdf, $object) = @_;
839              
840 18 50       93 if (defined $object->{'Resources'}) {
841 18         42 eval {
842 18         111 $object->{'Resources'}->realise();
843             };
844             }
845              
846 18         42 my @pages;
847 18   50     155 $pdf->{' apipagecount'} ||= 0;
848 18         93 foreach my $page ($object->{'Kids'}->elements()) {
849 20         132 $page->realise();
850             #if ($page->{'Type'}->val() eq 'Pages') {
851 20 50 33     154 if (defined $page->{'Type'} && $page->{'Type'}->val() eq 'Pages') {
852 0         0 push @pages, _proc_pages($pdf, $page);
853             } else {
854 20         50 $pdf->{' apipagecount'}++;
855 20         92 $page->{' pnum'} = $pdf->{' apipagecount'};
856 20 50       97 if (defined $page->{'Resources'}) {
857 20         42 eval {
858 20         112 $page->{'Resources'}->realise();
859             };
860             }
861 20         77 push @pages, $page;
862             }
863             }
864              
865 18         74 return @pages;
866             } # end of _proc_pages()
867              
868             =head2 update
869              
870             $pdf->update()
871              
872             =over
873              
874             Saves a previously opened document.
875              
876             B<Example:>
877              
878             =back
879              
880             $pdf = PDF::Builder->open('our/to/be/updated.pdf');
881             ...
882             $pdf->update();
883              
884             =over
885              
886             B<Note:> it is considered better to simply C<save()> the file, rather than
887             calling C<update()>. They end up doing the same thing, anyway. This method
888             may be deprecated in the future.
889              
890             =back
891              
892             =cut
893              
894             # obsolete, use save instead
895             sub update {
896 0     0 1 0 my $self = shift();
897 0         0 $self->saveas($self->{'pdf'}->{' fname'});
898 0         0 return;
899             }
900              
901             =head2 saveas
902              
903             $pdf->saveas($file)
904              
905             =over
906              
907             Save the document to $file and remove the object structure from memory.
908              
909             B<Caution:> Although the object C<$pdf> will still exist, it is no longer
910             usable for any purpose after invoking this method! You will receive error
911             messages about "can't call method new_obj on an undefined value".
912              
913             B<Example:>
914              
915             =back
916              
917             $pdf = PDF::Builder->new();
918             ...
919             $pdf->saveas('our/new.pdf');
920              
921             =cut
922              
923             sub saveas {
924 1     1 1 9 my ($self, $file) = @_;
925              
926 1 50       6 if ($self->{'opened_scalar'}) {
    0          
927 1         10 $self->{'pdf'}->append_file();
928 1         3 my $fh;
929 1 50       140 CORE::open($fh, '>', $file) or croak "Can't open $file for writing: $!";
930 1         10 binmode($fh, ':raw');
931 1         4 print $fh ${$self->{'content_ref'}};
  1         8  
932 1         235 CORE::close($fh);
933             } elsif ($self->{'partial_save'}) {
934 0         0 $self->{'pdf'}->close_file();
935             } else {
936 0         0 $self->{'pdf'}->out_file($file);
937             }
938              
939 1         10 $self->end();
940 1         69 return;
941             }
942              
943             =head2 save
944              
945             $pdf->save()
946              
947             $pdf->save(filename)
948              
949             =over
950              
951             Save the document to an already-defined file (or filename) and
952             remove the object structure from memory.
953             Optionally, a new filename may be given.
954              
955             B<Caution:> Although the object C<$pdf> will still exist, it is no longer
956             usable for any purpose after invoking this method! You will receive error
957             messages about "can't call method new_obj on an undefined value".
958              
959             B<Example:>
960              
961             =back
962              
963             $pdf = PDF::Builder->new(file => 'file_to_output');
964             ...
965             $pdf->save();
966              
967             =over
968              
969             B<Note:> now that C<save()> can take a filename as an argument, it effectively
970             is interchangeable with C<saveas()>. This is strictly for compatibility with
971             recent changes to PDF::API2. Unlike PDF::API2, we are not deprecating
972             the C<saveas()> method, because in user interfaces, "save" normally means that
973             the current filename is known and is to be used, while "saveas" normally means
974             that (whether or not there is a current filename) a new filename is to be used.
975              
976             =back
977              
978             =cut
979              
980             sub save {
981 0     0 1 0 my ($self, $file) = @_;
982              
983 0 0       0 if (defined $file) {
984 0         0 return $self->saveas($file);
985             }
986              
987             # NOTE: the current PDF::API2 version is quite different, but this may be
988             # a consequence of merging save() and saveas(). Let's give this unchanged
989             # version a try.
990 0 0       0 if ($self->{'opened_scalar'}) {
    0          
991 0         0 croak "Invalid method invocation: use 'saveas' instead of 'save'.";
992             } elsif ($self->{'partial_save'}) {
993 0         0 $self->{'pdf'}->close_file();
994             } else {
995 0         0 croak "Invalid method invocation: use 'saveas' instead of 'save'.";
996             }
997              
998 0         0 $self->end();
999 0         0 return;
1000             }
1001              
1002             =head2 close, release, end
1003              
1004             $pdf->close();
1005              
1006             =over
1007              
1008             Close an open file (if relevant) and remove the object structure from memory.
1009              
1010             PDF::API2 contains circular references, so this call is necessary in
1011             long-running processes to keep from running out of memory.
1012              
1013             This will be called automatically when you save or stringify a PDF.
1014             You should only need to call it explicitly if you are reading PDF
1015             files and not writing them.
1016              
1017             B<Alternate names:> C<release> and C<end>
1018              
1019             =back
1020              
1021             =cut
1022              
1023             =head2 end
1024              
1025             $pdf->end()
1026              
1027             =over
1028              
1029             Remove the object structure from memory. PDF::Builder contains circular
1030             references, so this call is necessary in long-running processes to
1031             keep from running out of memory.
1032              
1033             This will be called automatically when you save or to_string a PDF.
1034             You should only need to call it explicitly if you are reading PDF
1035             files and not writing them.
1036              
1037             This (and I<release>) are older and now deprecated names formerly used in
1038             PDF::API2 and PDF::Builder. You should try to avoid having to explicitly
1039             call them.
1040              
1041             =back
1042              
1043             =cut
1044              
1045             # Deprecated (renamed)
1046 0     0 1 0 sub release { return $_[0]->close(); }
1047 178     178 1 823 sub end { return $_[0]->close(); }
1048              
1049             sub close {
1050 178     178 1 400 my $self = shift();
1051 178 50       1642 $self->{'pdf'}->release() if defined $self->{'pdf'};
1052              
1053 178         1254 foreach my $key (keys %$self) {
1054 1620         13698 $self->{$key} = undef;
1055 1620         2975 delete $self->{$key};
1056             }
1057              
1058 178         789 return;
1059             }
1060              
1061             =head2 METADATA METHODS
1062              
1063             =head3 title
1064              
1065             $title = $pdf->title();
1066              
1067             $pdf = $pdf->title($title);
1068              
1069             =over
1070              
1071             Get/set/clear the document's title.
1072              
1073             =back
1074              
1075             =cut
1076              
1077             sub title {
1078 0     0 1 0 my $self = shift();
1079 0         0 return $self->info_metadata('Title', @_);
1080             }
1081              
1082             =head3 author
1083              
1084             $author = $pdf->author();
1085              
1086             $pdf = $pdf->author($author);
1087              
1088             =over
1089              
1090             Get/set/clear the name of the person who created the document.
1091              
1092             =back
1093              
1094             =cut
1095              
1096             sub author {
1097 0     0 1 0 my $self = shift();
1098 0         0 return $self->info_metadata('Author', @_);
1099             }
1100              
1101             =head3 subject
1102              
1103             $subject = $pdf->subject();
1104              
1105             $pdf = $pdf->subject($subject);
1106              
1107             =over
1108              
1109             Get/set/clear the subject of the document.
1110              
1111             =back
1112              
1113             =cut
1114              
1115             sub subject {
1116 0     0 1 0 my $self = shift();
1117 0         0 return $self->info_metadata('Subject', @_);
1118             }
1119              
1120             =head3 keywords
1121              
1122             $keywords = $pdf->keywords();
1123              
1124             $pdf = $pdf->keywords($keywords);
1125              
1126             =over
1127              
1128             Get/set/clear a space-separated string of keywords associated with the document.
1129              
1130             =back
1131              
1132             =cut
1133              
1134             sub keywords {
1135 0     0 1 0 my $self = shift();
1136 0         0 return $self->info_metadata('Keywords', @_);
1137             }
1138              
1139             =head3 creator
1140              
1141             $creator = $pdf->creator();
1142              
1143             $pdf = $pdf->creator($creator);
1144              
1145             =over
1146              
1147             Get/set/clear the name of the product that created the document prior to its
1148             conversion to PDF.
1149              
1150             =back
1151              
1152             =cut
1153              
1154             sub creator {
1155 0     0 1 0 my $self = shift();
1156 0         0 return $self->info_metadata('Creator', @_);
1157             }
1158              
1159             =head3 producer
1160              
1161             $producer = $pdf->producer();
1162              
1163             $pdf = $pdf->producer($producer);
1164              
1165             =over
1166              
1167             Get/set/clear the name of the product that converted the original document to
1168             PDF.
1169              
1170             PDF::Builder fills in this field when creating a PDF.
1171              
1172             =back
1173              
1174             =cut
1175              
1176             sub producer {
1177 5     5 1 16 my $self = shift();
1178 5         19 return $self->info_metadata('Producer', @_);
1179             }
1180              
1181             =head3 created
1182              
1183             $date = $pdf->created();
1184              
1185             $pdf = $pdf->created($date);
1186              
1187             =over
1188              
1189             Get/set/clear the document's creation date.
1190              
1191             The date format is C<D:YYYYMMDDHHmmSSOHH'mm>, where C<D:> is a static prefix
1192             identifying the string as a PDF date. The date may be truncated at any point
1193             after the year. C<O> is one of C<+>, C<->, or C<Z>, with the following C<HH'mm>
1194             representing an offset from UTC.
1195              
1196             See comments in the internal function C<_is_date()> for more information on
1197             the inconsistency of PDF standards on exactly what the date format should be!
1198              
1199             When setting the date, C<D:> will be prepended automatically if omitted.
1200              
1201             =back
1202              
1203             =cut
1204              
1205             sub created {
1206 1     1 1 3 my $self = shift();
1207 1         5 return $self->info_metadata('CreationDate', @_);
1208             }
1209              
1210             =head3 modified
1211              
1212             $date = $pdf->modified();
1213              
1214             $pdf = $pdf->modified($date);
1215              
1216             =over
1217              
1218             Get/set/clear the document's modification date. The date format is as described
1219             in C<created> above.
1220              
1221             See comments in the internal function C<_is_date()> for more information on
1222             the inconsistency of PDF standards on exactly what the date format should be!
1223              
1224             =back
1225              
1226             =cut
1227              
1228             sub modified {
1229 1     1 1 8 my $self = shift();
1230 1         4 return $self->info_metadata('ModDate', @_);
1231             }
1232              
1233             sub _is_date {
1234 2     2   5 my $value = shift();
1235              
1236             # there are lists of leap seconds floating around, such as
1237             # https://www.ietf.org/timezones/data/leap-seconds.list
1238             # https://en.wikipedia.org/wiki/Leap_second
1239 2         76 my %leap_sec = ('06'=>{
1240             1972=>1, 1981=>1, 1982=>1, 1983=>1, 1985=>1, 1992=>1,
1241             1993=>1, 1994=>1, 1997=>1, 2012=>1, 2015=>1},
1242             '12'=>{
1243             1972=>1, 1973=>1, 1974=>1, 1975=>1, 1976=>1, 1977=>1,
1244             1978=>1, 1979=>1, 1987=>1, 1989=>1, 1990=>1, 1995=>1,
1245             1998=>1, 2005=>1, 2008=>1, 2016=>1});
1246             # some sources list Dec 1971 as having a leap second, others don't
1247              
1248             # PDF 1.7 section 7.9.4 describes the required date format. Other than the
1249             # D: prefix and the year, all components are optional but must be present if
1250             # a later component is present.
1251             #
1252             # comments by PM Perry:
1253             # There is some conflict among various Adobe/ISO reference documents, as
1254             # well as ambiguity within them (e.g., the example drops the seconds
1255             # field, a trailing ' may or may not be required in a TZ offset). In
1256             # addition, the PDF format seems to be something of a subset of ISO 8601.
1257             # I have attempted to satisfy as many of the Adobe PDF reference documents
1258             # as I could, but there are no guarantees that all PDF editors and readers
1259             # will accept any given date/timestamp!
1260             # See https://www.rfc-editor.org/rfc/rfc3339#section-5.6, remembering that
1261             # many ISO 8601-compliant stamps will be considered invalid here. If there
1262             # is demand for it, additional formats might be supported, and even a
1263             # format or flag that says, "Here is my timestamp. Do not validate -- trust
1264             # me, I know what I'm doing!"
1265            
1266 2         6 my ($year, $month, $day, $hour, $minute, $second, $od, $oh, $om, $ts, $tz);
1267 2 50       14 if ($value =~ /([Z+-])/) { # should be only zero (leave od undef) or one
1268 2         9 $od = $1;
1269             } else {
1270 0         0 $od = undef; # in case value left over from previous data
1271             }
1272             # make sure od defined (and not empty)
1273 2   50     6 $od ||= 'Z';
1274             # ts must always have something, tz might not
1275 2         13 ($ts, $tz) = split /[Z+-]/, $value;
1276 2   100     11 $tz ||= '';
1277              
1278 2 50       27 return 0 unless $ts =~ /^D:([0-9]{4}) # D:YYYY (required)
1279             (?:([0-1][0-9]) # Month (01-12)
1280             (?:([0-3][0-9]) # Day (01-31)
1281             (?:([0-2][0-9]) # Hour (00-23)
1282             (?:([0-5][0-9]) # Minute (00-59)
1283             (?:([0-6][0-9]) # Second (00-59), also leap sec
1284             ?)?)?)?)?)?$/x;
1285 2         17 ($year, $month, $day, $hour, $minute, $second)
1286             = ($1, $2, $3, $4, $5, $6);
1287 2   50     6 $month ||= 1;
1288 2   50     6 $day ||= 1;
1289 2   50     7 $hour ||= 0;
1290 2   50     6 $minute ||= 0;
1291 2   50     7 $second ||= 0;
1292              
1293             # od is Z (tz s/b ''), or od is + or - with hh or more
1294 2 100       7 if ($od ne 'Z') {
1295             # must be + or -, and at least an hour given
1296             # ' before minutes (if given), optional ' after minutes
1297             # regexp should fail if tz is ''
1298 1 50       9 return 0 unless $tz =~ /^([0-2][0-9]) # UT Offset Hours
1299             (?:'?([0-5][0-9]) # UT Offset Minutes
1300             (?:' # optional '
1301             ?)?)?$/x;
1302 1         4 ($oh, $om) = ($1, $2);
1303 1   50     4 $oh ||= 0;
1304 1   50     3 $om ||= 0;
1305 1 50 33     5 if ($oh == 0 && $om == 0) {
1306             # +/- 0 offset, so just make it Z
1307 0         0 $od = 'Z';
1308             }
1309             } else {
1310             # explicit Z spec, shouldn't have an offset
1311 1 50       4 if ($tz ne '') {
1312 0         0 carp "Ignoring hour['minute] offset with Z timezone\n";
1313             }
1314 1         2 $oh = $om = 0;
1315             }
1316 2   100     9 $oh ||= 0;
1317 2   100     33 $om ||= 0;
1318 2 100 66     10 if ($oh == 0 && $om == 0) { $od = 'Z';
  1         2  
1319             }
1320              
1321             # Do some basic validation to catch accidental date formatting issues.
1322             # Complete date validation is out of scope.
1323             # add determination of leap year and leap day
1324             # treat ALL years as Gregorian calendar!
1325 2         4 my $is_leap;
1326 2 100       12 if ($year % 400 == 0) {
    50          
    50          
1327 1         3 $is_leap = 1;
1328             } elsif ($year % 100 == 0) {
1329 0         0 $is_leap = 0;
1330             } elsif ($year % 4 == 0) {
1331 0         0 $is_leap = 1;
1332             } else {
1333 1         3 $is_leap = 0;
1334             }
1335 2         8 my @mon_len = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
1336 2 100       6 if ($is_leap) { $mon_len[1]++; }
  1         2  
1337              
1338 2 50 33     14 return 0 unless $month >= 1 and $month <= 12;
1339 2 50 33     20 return 0 unless $day >= 1 and $day <= 31;
1340 2 50       8 return 0 if $day > $mon_len[$month-1]; # added exact month length check
1341 2 50       6 return 0 unless $hour <= 23;
1342 2 50       12 return 0 unless $minute <= 59;
1343 2 50       11 return 0 unless $oh <= 23;
1344 2 50       7 return 0 unless $om <= 59;
1345 2 50       8 return 0 if $second > 60;
1346 2 50       6 if ($second == 60) {
1347             # claimed leap second -- verify
1348             # remember that +oh/om can place local date into next year!
1349             # correct local date and time (per offset) to UTC (Z)
1350 0         0 my $newy = $year;
1351 0         0 my $newM = $month;
1352 0         0 my $newd = $day;
1353 0         0 my $newh = $hour;
1354 0         0 my $newm = $minute;
1355             # assuming tz offset won't move more than 1 day either way
1356             # (max offset 12 or 13 hours?)
1357             # we're really only interested if date/time adjusted to Z is
1358             # June 30 or December 31 at 23:59:60Z, for certain years
1359 0 0       0 if ($od eq '+') {
    0          
1360             # sub h:m could put us in previous day (and month, but not year)
1361             # if not, it's not possibly 23:59:60Z
1362 0         0 $newh -= $oh;
1363 0         0 $newm -= $om;
1364 0 0       0 if ($newm < 0) {
1365 0         0 $newm += 60;
1366 0         0 $newh--;
1367             }
1368 0 0       0 if ($newh < 0) {
1369 0         0 $newh += 24;
1370 0         0 $newd--;
1371 0 0       0 if ($newd == 0) {
1372             # local was first day of Jan or Jul?
1373 0         0 $newM--;
1374 0 0       0 if ($newM == 0) {
    0          
1375 0         0 $newM = 12;
1376 0         0 $newd = 31;
1377 0         0 $newy--;
1378             } elsif ($newM == 6) {
1379 0         0 $newd = 30;
1380             } else {
1381             # last day of previous month, not Dec or Jun
1382 0         0 return 0;
1383             }
1384             } else {
1385 0         0 return 0; # wasn't last day of Dec or Jun (local date)
1386             }
1387             } else {
1388             # if got to here, didn't back up to previous day
1389 0         0 return 0;
1390             }
1391              
1392             } elsif ($od eq '-') {
1393             # add h:m could put us in next day (and month, and even year)
1394 0         0 $newh += $oh;
1395 0         0 $newm += $om;
1396 0 0       0 if ($newm > 59) {
1397 0         0 $newm -= 60;
1398 0         0 $newh++;
1399             }
1400 0 0       0 if ($newh > 23) {
1401 0         0 $newh -= 24;
1402 0         0 $newd++;
1403 0 0       0 if ($newd > $mon_len[$month-1]) {
1404             # local was last day of month, now (Z) 1st, wrong date
1405 0         0 $newM++;
1406 0         0 $newd = 1;
1407 0 0       0 if ($newM > 12) {
1408 0         0 $newM = 1;
1409 0         0 $newy++;
1410             }
1411 0         0 return 0; # ended up on 1st of a month, invalid leap second
1412             }
1413             }
1414             # only Dec 31 and Jun 30 are eligible for consideration
1415 0 0 0     0 if (!($newM == 6 && $newd == 30 ||
      0        
      0        
1416             $newM == 12 && $newd == 31)) {
1417 0         0 return 0;
1418             }
1419              
1420             } else {
1421             # local time is already Z, just use newh and newm
1422 0 0 0     0 if (!($newM == 6 && $newd == 30 ||
      0        
      0        
1423             $newM == 12 && $newd == 31)) {
1424 0         0 return 0; # not Dec 31 or Jun 30
1425             }
1426             }
1427              
1428             # time newh:newm corrected to Z. check if 23:59.
1429             # date corrected to Z, is OK (Dec 31 or Jun 30),
1430             # check if is actual leap second date.
1431 0 0 0     0 if ($newh == 23 && $newm == 59 && # second is 60
      0        
1432             defined $leap_sec{$newM}->{$newy}
1433             # assuming value is +1. if ever -1, need more code TBD
1434             # (23:59:58 would be last second of month)
1435             # already on last day of listed month. at 23:59:60Z?
1436             # valid leap second
1437             ) {
1438             } else {
1439 0         0 return 0;
1440             }
1441             }
1442              
1443 2         23 return 1;
1444             }
1445              
1446             =head3 info_metadata
1447              
1448             %info = $pdf->info_metadata(); # Get all keys and values
1449              
1450             $value = $pdf->info_metadata($key); # Get the value of one key
1451              
1452             $pdf = $pdf->info_metadata($key, $value); # Set the value of one key
1453              
1454             =over
1455              
1456             Get/set/clear a key in the document's information dictionary. The standard keys
1457             (title, author, etc.) have their own accessors, so this is primarily intended
1458             for interacting with custom metadata.
1459              
1460             Pass C<undef> as the value in order to remove the key from the dictionary.
1461              
1462             See comments in the internal function C<_is_date()> for more information on
1463             the inconsistency of PDF standards on exactly what the date format should be!
1464             This applies to CreationDate and ModDate keys.
1465              
1466             =back
1467              
1468             =cut
1469              
1470             sub info_metadata {
1471 7     7 1 46 my $self = shift();
1472 7         16 my $field = shift();
1473              
1474             # Return a hash of the Info table if called without arguments
1475 7 50       19 unless (defined $field) {
1476 0 0       0 return unless exists $self->{'pdf'}->{'Info'};
1477 0         0 $self->{'pdf'}->{'Info'}->realise();
1478 0         0 my %info;
1479 0         0 foreach my $key (keys %{$self->{'pdf'}->{'Info'}}) {
  0         0  
1480 0 0       0 next if $key =~ /^ /;
1481 0 0       0 next unless defined $self->{'pdf'}->{'Info'}->{$key};
1482 0         0 $info{$key} = $self->{'pdf'}->{'Info'}->{$key}->val();
1483             }
1484 0         0 return %info;
1485             }
1486              
1487             # Set
1488 7 100       20 if (@_) {
1489 4         7 my $value = shift();
1490 4 50 66     23 $value = undef if defined($value) and not length($value);
1491              
1492 4 100 100     19 if ($field eq 'CreationDate' or $field eq 'ModDate') {
1493 2 50       9 if (defined ($value)) {
1494             # make sure date/timestamp starts with D:
1495 2 50       11 $value = 'D:' . $value unless $value =~ /^D:/;
1496 2 50       8 croak "Invalid date string: $value" unless _is_date($value);
1497             }
1498             }
1499              
1500 4 50       16 unless (exists $self->{'pdf'}->{'Info'}) {
1501 0 0       0 return $self unless defined $value;
1502 0         0 $self->{'pdf'}->{'Info'} = PDFDict();
1503 0         0 $self->{'pdf'}->new_obj($self->{'pdf'}->{'Info'});
1504             }
1505             else {
1506 4         21 $self->{'pdf'}->{'Info'}->realise();
1507             }
1508              
1509 4 100       10 if (defined $value) {
1510 3         13 $self->{'pdf'}->{'Info'}->{$field} = PDFStr($value);
1511             }
1512             else {
1513 1         4 delete $self->{'pdf'}->{'Info'}->{$field};
1514             }
1515              
1516 4         12 return $self;
1517             }
1518              
1519             # Get
1520 3 50       10 return unless $self->{'pdf'}->{'Info'};
1521 3         13 $self->{'pdf'}->{'Info'}->realise();
1522 3 100       16 return unless $self->{'pdf'}->{'Info'}->{$field};
1523 2         10 return $self->{'pdf'}->{'Info'}->{$field}->val();
1524             }
1525              
1526             =head3 info
1527              
1528             %infohash = $pdf->info()
1529              
1530             %infohash = $pdf->info(%infohash)
1531              
1532             =over
1533              
1534             Gets/sets the info structure of the document.
1535              
1536             See L<PDF::Builder::Docs/info Example> section for an example of the use
1537             of this method.
1538              
1539             B<Note:> this method is still available, for compatibility purposes. It is
1540             better to use individual accessors or C<info_metadata> instead.
1541              
1542             =back
1543              
1544             =cut
1545              
1546             sub info {
1547 237     237 1 1095 my ($self, %opt) = @_;
1548              
1549 237 100       1265 if (not defined($self->{'pdf'}->{'Info'})) {
1550 234         856 $self->{'pdf'}->{'Info'} = PDFDict();
1551 234         13491 $self->{'pdf'}->new_obj($self->{'pdf'}->{'Info'});
1552             } else {
1553 3         12 $self->{'pdf'}->{'Info'}->realise();
1554             }
1555              
1556             # Maintenance Note: Since we're not shifting at the beginning of
1557             # this sub, this "if" will always be true
1558 237 50       885 if (scalar @_) {
1559 237         524 foreach my $k (@{$self->{'infoMeta'}}) {
  237         792  
1560 1896 100       4473 next unless defined $opt{$k};
1561 235   50     1320 $self->{'pdf'}->{'Info'}->{$k} = PDFString($opt{$k} || 'NONE', 'm');
1562             }
1563 237         1008 $self->{'pdf'}->out_obj($self->{'pdf'}->{'Info'});
1564             }
1565              
1566 237 50       802 if (defined $self->{'pdf'}->{'Info'}) {
1567 237         626 %opt = ();
1568 237         438 foreach my $k (@{$self->{'infoMeta'}}) {
  237         791  
1569 1896 100       4732 next unless defined $self->{'pdf'}->{'Info'}->{$k};
1570 237         1085 $opt{$k} = $self->{'pdf'}->{'Info'}->{$k}->val();
1571 237 50 33     2275 if ((unpack('n', $opt{$k}) == 0xfffe) or (unpack('n', $opt{$k}) == 0xfeff)) {
1572 0         0 $opt{$k} = decode('UTF-16', $self->{'pdf'}->{'Info'}->{$k}->val());
1573             }
1574             }
1575             }
1576              
1577 237         668 return %opt;
1578             } # end of info()
1579              
1580             =head3 infoMetaAttributes
1581              
1582             @metadata_attributes = $pdf->infoMetaAttributes()
1583              
1584             @metadata_attributes = $pdf->infoMetaAttributes(@metadata_attributes)
1585              
1586             =over
1587              
1588             Gets/sets the supported info-structure tags.
1589              
1590             B<Example:>
1591              
1592             =back
1593              
1594             @attributes = $pdf->infoMetaAttributes;
1595             print "Supported Attributes: @attr\n";
1596              
1597             @attributes = $pdf->infoMetaAttributes('CustomField1');
1598             print "Supported Attributes: @attributes\n";
1599              
1600             =over
1601              
1602             B<Note:> this method is still available for compatibility purposes, but the
1603             use of C<info_metadata> instead is encouraged.
1604              
1605             =back
1606              
1607             =cut
1608              
1609             sub infoMetaAttributes {
1610 0     0 1 0 my ($self, @attr) = @_;
1611              
1612 0 0       0 if (scalar @attr) {
1613 0         0 my %at = map { $_ => 1 } @{$self->{'infoMeta'}}, @attr;
  0         0  
  0         0  
1614 0         0 @{$self->{'infoMeta'}} = keys %at;
  0         0  
1615             }
1616              
1617 0         0 return @{$self->{'infoMeta'}};
  0         0  
1618             }
1619              
1620             =head3 xml_metadata
1621              
1622             $xml = $pdf->xml_metadata();
1623              
1624             $pdf = $pdf->xml_metadata($xml);
1625              
1626             =over
1627              
1628             Gets/sets the document's XML metadata stream.
1629              
1630             =back
1631              
1632             =cut
1633              
1634             sub xml_metadata {
1635 0     0 1 0 my ($self, $value) = @_;
1636              
1637 0 0       0 if (not defined($self->{'catalog'}->{'Metadata'})) {
1638 0         0 $self->{'catalog'}->{'Metadata'} = PDFDict();
1639 0         0 $self->{'catalog'}->{'Metadata'}->{'Type'} = PDFName('Metadata');
1640 0         0 $self->{'catalog'}->{'Metadata'}->{'Subtype'} = PDFName('XML');
1641 0         0 $self->{'pdf'}->new_obj($self->{'catalog'}->{'Metadata'});
1642             }
1643             else {
1644 0         0 $self->{'catalog'}->{'Metadata'}->realise();
1645 0         0 $self->{'catalog'}->{'Metadata'}->{' stream'} = unfilter($self->{'catalog'}->{'Metadata'}->{'Filter'}, $self->{'catalog'}->{'Metadata'}->{' stream'});
1646 0         0 delete $self->{'catalog'}->{'Metadata'}->{' nofilt'};
1647 0         0 delete $self->{'catalog'}->{'Metadata'}->{'Filter'};
1648             }
1649              
1650 0         0 my $md = $self->{'catalog'}->{'Metadata'};
1651              
1652 0 0       0 if (defined $value) {
1653 0         0 $md->{' stream'} = $value;
1654 0         0 delete $md->{'Filter'};
1655 0         0 delete $md->{' nofilt'};
1656 0         0 $self->{'pdf'}->out_obj($md);
1657 0         0 $self->{'pdf'}->out_obj($self->{'catalog'});
1658             }
1659              
1660 0         0 return $md->{' stream'};
1661             }
1662              
1663             =head3 xmpMetadata
1664              
1665             $xml = $pdf->xmpMetadata() # Get
1666              
1667             $xml = $pdf->xmpMetadata($xml) # Set (also returns $xml value)
1668              
1669             =over
1670              
1671             Gets/sets the XMP XML data stream.
1672              
1673             See L<PDF::Builder::Docs/XMP XML example> section for an example of the use
1674             of this method.
1675              
1676             This method is considered B<obsolete>. Use C<xml_metadata> instead.
1677              
1678             =back
1679              
1680             =cut
1681              
1682             sub xmpMetadata {
1683 0     0 1 0 my ($self, $value) = @_;
1684              
1685 0 0       0 if (@_) { # Set
1686 0         0 my $value = shift();
1687 0         0 $self->xml_metadata($value);
1688 0         0 return $value;
1689             }
1690              
1691             # Get
1692 0         0 return $self->xml_metadata();
1693             }
1694              
1695             =head3 default
1696              
1697             $val = $pdf->default($parameter)
1698              
1699             $pdf->default($parameter, $value)
1700              
1701             =over
1702              
1703             Gets/sets the default value for a behavior of PDF::Builder.
1704              
1705             B<Supported Parameters:>
1706              
1707             =back
1708              
1709             =over
1710              
1711             =item nounrotate
1712              
1713             prohibits Builder from rotating imported/opened page to re-create a
1714             default pdf-context.
1715              
1716             =item pageencaps
1717              
1718             enables Builder's adding save/restore commands upon importing/opening
1719             pages to preserve graphics-state for modification.
1720              
1721             =item copyannots
1722              
1723             enables importing of annotations (B<*EXPERIMENTAL*>).
1724              
1725             =back
1726              
1727             =over
1728              
1729             B<CAUTION:> Perl::Critic (tools/1_pc.pl) has started flagging the name
1730             "default" as a reserved keyword in higher Perl versions. Use with caution, and
1731             be aware that this name I<may> have to be changed in the future.
1732              
1733             =back
1734              
1735             =cut
1736              
1737             sub default {
1738 8     8 1 26 my ($self, $parameter, $value) = @_;
1739              
1740             # Parameter names may consist of lowercase letters, numbers, and underscores
1741 8         18 $parameter = lc $parameter;
1742 8         32 $parameter =~ s/[^a-z\d_]//g;
1743              
1744 8         18 my $previous_value = $self->{$parameter};
1745 8 50       30 if (defined $value) {
1746 0         0 $self->{$parameter} = $value;
1747             }
1748              
1749 8         62 return $previous_value;
1750             }
1751              
1752             =head3 version
1753              
1754             $version = $pdf->pdf_version() # Get
1755              
1756             $version = $pdf->pdf_version($version) # Set (also returns newly set version)
1757              
1758             =over
1759              
1760             Gets/sets the PDF version (e.g., 1.5).
1761             For compatibility with earlier releases, if no decimal point is given, assume
1762             "1." precedes the number given.
1763              
1764             A warning message is given if you attempt to I<decrease> the PDF version, as you
1765             might have already read in a higher level file, or used a higher level feature.
1766              
1767             See L<PDF::Builder::Basic::PDF::File> for additional information on the
1768             C<version> method.
1769              
1770             =back
1771              
1772             =cut
1773              
1774             sub pdf_version {
1775 27     27 0 93 my $self = shift(); # includes any %opts
1776              
1777 27 50       129 if (!defined $self->{'pdf'}) {
1778 0         0 carp "'pdf' element not defined in pdf_version() call";
1779 0         0 return '1.4';
1780             }
1781 27         192 return $self->{'pdf'}->pdf_version(@_); # just pass it over to the "real" one
1782             }
1783              
1784             # when outputting a PDF feature, verCheckOutput(n, 'feature name') returns TRUE
1785             # if n > $pdf->{' version'), plus a warning message. It returns FALSE otherwise.
1786             #
1787             # a typical use:
1788             #
1789             # $PDF::Builder::global_pdf->verCheckOutput(1.6, "portzebie with foo-dangle");
1790             #
1791             # if msgver defaults to 1, a message will be output if the output PDF version
1792             # has to be increased to 1.6 in order to use the "portzebie" feature
1793             #
1794             # this is still somewhat experimental, and as experience is gained, the code
1795             # might have to be modified.
1796             #
1797             sub verCheckOutput {
1798 3     3 0 11 my ($self, $PDFver, $featureName) = @_;
1799              
1800             # check if feature required PDF version is higher than planned output
1801 3         22 my $version = $self->pdf_version(); # current version
1802 3 100       11 if ($PDFver > $version) {
1803 1 50       4 if ($msgVer) {
1804 0         0 print "PDF version of requested feature '$featureName' is higher\n". " than current output version $version ".
1805             "(version reset to $PDFver)\n";
1806             }
1807 1         4 $self->pdf_version($PDFver);
1808 1         3 return 1;
1809             } else {
1810 2         7 return 0;
1811             }
1812             }
1813              
1814             # when reading in a PDF, verCheckInput(n) gives a warning message if n (the PDF
1815             # version just read in) > version, and resets version to n. return TRUE if
1816             # version changed, FALSE otherwise.
1817             #
1818             # this is still somewhat experimental, and as experience is gained, the code
1819             # might have to be modified.
1820             #
1821             # WARNING: just because the PDF output version has been increased does NOT
1822             # guarantee that any particular content will be handled correctly! There are
1823             # many known cases of PDF 1.5 and up files being read in, that have content
1824             # that PDF::Builder does not handle correctly, corrupting the resulting PDF.
1825             # Pay attention to run-time warning messages that the PDF output level has
1826             # been increased due to a PDF file being read in, and check the resulting
1827             # file carefully.
1828              
1829             sub verCheckInput {
1830 18     18 0 59 my ($self, $PDFver) = @_;
1831              
1832 18         126 my $version = $self->pdf_version();
1833             # warning message and bump up version if read-in PDF level higher
1834 18 50       79 if ($PDFver > $version) {
1835 0 0       0 if ($msgVer) {
1836 0         0 print "PDF version just read in is higher than version of $version (version reset to $PDFver)\n";
1837             }
1838 0         0 $self->pdf_version($PDFver);
1839 0         0 return 1;
1840             } else {
1841 18         43 return 0;
1842             }
1843             }
1844              
1845             =head3 is_encrypted, isEncrypted
1846              
1847             $bool = $pdf->is_encrypted()
1848              
1849             =over
1850              
1851             Checks if the previously opened PDF is encrypted.
1852              
1853             B<Alternate name:> C<isEncrypted>
1854              
1855             This is the older name; it is kept for compatibility with PDF::API2.
1856              
1857             =back
1858              
1859             =cut
1860              
1861 0     0 1 0 sub isEncrypted { return is_encrypted(@_); } ## no critic
1862              
1863             sub is_encrypted {
1864 0     0 1 0 my $self = shift();
1865 0 0       0 return defined($self->{'pdf'}->{'Encrypt'}) ? 1 : 0;
1866             }
1867              
1868             =head1 INTERACTIVE FEATURE METHODS
1869              
1870             =head2 outline, outlines
1871              
1872             $otls = $pdf->outline()
1873              
1874             =over
1875              
1876             Creates (if needed) and returns the document's 'outline' tree, which is also
1877             known as its 'bookmarks' or the 'table of contents', depending on the
1878             PDF reader being used.
1879              
1880             To examine or modify the outline tree, see L<PDF::Builder::Outlines>.
1881              
1882             B<Alternate name:> C<outlines>
1883              
1884             This is the older name; it is kept for compatibility.
1885              
1886             =back
1887              
1888             =cut
1889              
1890 4     4 1 32 sub outlines { return outline(@_); } ## no critic
1891              
1892             sub outline {
1893 4     4 1 7 my $self = shift();
1894              
1895 4         802 require PDF::Builder::Outlines;
1896 4         15 my $obj = $self->{'pdf'}->{'Root'}->{'Outlines'};
1897 4 100       9 if ($obj) {
1898 1         3 $obj->realise();
1899 1         5 bless $obj, 'PDF::Builder::Outlines';
1900 1         2 $obj->{' api'} = $self;
1901 1         2 weaken $obj->{' api'};
1902             } else {
1903 3         20 $obj = PDF::Builder::Outlines->new($self);
1904              
1905 3         10 $self->{'pdf'}->{'Root'}->{'Outlines'} = $obj;
1906 3 50       13 $self->{'pdf'}->new_obj($obj) unless $obj->is_obj($self->{'pdf'});
1907 3         11 $self->{'pdf'}->out_obj($obj);
1908 3         8 $self->{'pdf'}->out_obj($self->{'pdf'}->{'Root'});
1909             }
1910 4         22 return $obj;
1911             }
1912              
1913             #=item $pdf = $pdf->open_action($page, $location, @args);
1914             #
1915             #Set the destination in the PDF that should be displayed when the document is
1916             #opened.
1917             #
1918             #C<$page> may be either a page number or a page object. The other parameters are
1919             #as described in L<PDF::Builder::NamedDestination>.
1920             #
1921             #This has been split out from C<preferences()> for compatibility with PDF::API2.
1922             #It also can both set (assign) and get (query) the settings used.
1923             #
1924             #=cut
1925             #
1926             #sub open_action {
1927             # my ($self, $page, @args) = @_;
1928             #
1929             # # $page can be either a page number or a page object
1930             # $page = PDFNum($page) unless ref($page);
1931             #
1932             # require PDF::Builder::NamedDestination;
1933             # # PDF::API2 code incompatible with Builder!
1934             # #my $array = PDF::Builder::NamedDestination::_destination($page, @args);
1935             #
1936             # $self->{'catalog'}->{'OpenAction'} = $array;
1937             # $self->{'pdf'}->out_obj($self->{'catalog'});
1938             # return $self;
1939             #}
1940              
1941             =head2 page_layout
1942              
1943             $layout = $pdf->page_layout();
1944              
1945             $pdf = $pdf->page_layout($layout);
1946              
1947             =over
1948              
1949             Gets/sets the page layout that should be used when the PDF is opened.
1950              
1951             C<$layout> is one of the following:
1952              
1953             =back
1954              
1955             =over
1956              
1957             =item single_page (or undef)
1958              
1959             Display one page at a time.
1960              
1961             =item one_column
1962              
1963             Display the pages in one column (a.k.a. continuous).
1964              
1965             =item two_column_left
1966              
1967             Display the pages in two columns, with odd-numbered pages on the left.
1968              
1969             =item two_column_right
1970              
1971             Display the pages in two columns, with odd-numbered pages on the right.
1972              
1973             =item two_page_left
1974              
1975             Display two pages at a time, with odd-numbered pages on the left.
1976              
1977             =item two_page_right
1978              
1979             Display two pages at a time, with odd-numbered pages on the right.
1980              
1981             =back
1982              
1983             =over
1984              
1985             This has been split out from C<preferences()> for compatibility with PDF::API2.
1986             It also can both set (assign) and get (query) the settings used.
1987              
1988             =back
1989              
1990             =cut
1991              
1992             sub page_layout {
1993 0     0 1 0 my $self = shift();
1994              
1995 0 0       0 unless (@_) {
1996 0 0       0 return 'single_page' unless $self->{'catalog'}->{'PageLayout'};
1997 0         0 my $layout = $self->{'catalog'}->{'PageLayout'}->val();
1998 0 0       0 return 'single_page' if $layout eq 'SinglePage';
1999 0 0       0 return 'one_column' if $layout eq 'OneColumn';
2000 0 0       0 return 'two_column_left' if $layout eq 'TwoColumnLeft';
2001 0 0       0 return 'two_column_right' if $layout eq 'TwoColumnRight';
2002 0 0       0 return 'two_page_left' if $layout eq 'TwoPageLeft';
2003 0 0       0 return 'two_page_right' if $layout eq 'TwoPageRight';
2004 0         0 warn "Unknown page layout: $layout";
2005 0         0 return $layout;
2006             }
2007              
2008 0   0     0 my $name = shift() // 'single_page';
2009 0 0       0 my $layout = ($name eq 'single_page' ? 'SinglePage' :
    0          
    0          
    0          
    0          
    0          
2010             $name eq 'one_column' ? 'OneColumn' :
2011             $name eq 'two_column_left' ? 'TwoColumnLeft' :
2012             $name eq 'two_column_right' ? 'TwoColumnRight' :
2013             $name eq 'two_page_left' ? 'TwoPageLeft' :
2014             $name eq 'two_page_right' ? 'TwoPageRight' : '');
2015              
2016 0 0       0 croak "Invalid page layout: $name" unless $layout;
2017 0         0 $self->{'catalog'}->{'PageLayout'} = PDFName($layout);
2018 0         0 $self->{'pdf'}->out_obj($self->{'catalog'});
2019 0         0 return $self;
2020             }
2021              
2022             =head2 page_mode
2023              
2024             $mode = $pdf->page_mode(); # Get
2025              
2026             $pdf = $pdf->page_mode($mode); # Set
2027              
2028             =over
2029              
2030             Gets/sets the page mode, which describes how the PDF should be displayed when
2031             opened.
2032              
2033             C<$mode> is one of the following:
2034              
2035             =back
2036              
2037             =over
2038              
2039             =item none (or undef)
2040              
2041             Neither outlines nor thumbnails should be displayed.
2042              
2043             =item outlines
2044              
2045             Show the document outline.
2046              
2047             =item thumbnails
2048              
2049             Show the page thumbnails.
2050              
2051             =item full_screen
2052              
2053             Open in full-screen mode, with no menu bar, window controls, or any other window
2054             visible.
2055              
2056             =item optional_content
2057              
2058             Show the optional content group panel.
2059              
2060             =item attachments
2061              
2062             Show the attachments panel.
2063              
2064             =back
2065              
2066             =over
2067              
2068             This has been split out from C<preferences()> for compatibility with PDF::API2.
2069             It also can both set (assign) and get (query) the settings used.
2070              
2071             =back
2072              
2073             =cut
2074              
2075             sub page_mode {
2076 0     0 1 0 my $self = shift();
2077              
2078 0 0       0 unless (@_) {
2079 0 0       0 return 'none' unless $self->{'catalog'}->{'PageMode'};
2080 0         0 my $mode = $self->{'catalog'}->{'PageMode'}->val();
2081 0 0       0 return 'none' if $mode eq 'UseNone';
2082 0 0       0 return 'outlines' if $mode eq 'UseOutlines';
2083 0 0       0 return 'thumbnails' if $mode eq 'UseThumbs';
2084 0 0       0 return 'full_screen' if $mode eq 'FullScreen';
2085 0 0       0 return 'optional_content' if $mode eq 'UseOC';
2086 0 0       0 return 'attachments' if $mode eq 'UseAttachments';
2087 0         0 warn "Unknown page mode: $mode";
2088 0         0 return $mode;
2089             }
2090              
2091 0   0     0 my $name = shift() // 'none';
2092 0 0       0 my $mode = ($name eq 'none' ? 'UseNone' :
    0          
    0          
    0          
    0          
    0          
2093             $name eq 'outlines' ? 'UseOutlines' :
2094             $name eq 'thumbnails' ? 'UseThumbs' :
2095             $name eq 'full_screen' ? 'FullScreen' :
2096             $name eq 'optional_content' ? 'UseOC' :
2097             $name eq 'attachments' ? 'UseAttachments' : '');
2098              
2099 0 0       0 croak "Invalid page mode: $name" unless $mode;
2100 0         0 $self->{'catalog'}->{'PageMode'} = PDFName($mode);
2101 0         0 $self->{'pdf'}->out_obj($self->{'catalog'});
2102 0         0 return $self;
2103             }
2104              
2105             =head2 viewer_preferences
2106              
2107             %preferences = $pdf->viewer_preferences(); # Get
2108              
2109             $pdf = $pdf->viewer_preferences(%preferences); # Set
2110              
2111             =over
2112              
2113             Gets/sets PDF viewer preferences, as described in
2114             L<PDF::Builder::ViewerPreferences>.
2115              
2116             This has been split out from C<preferences()> for compatibility with PDF::API2.
2117             It also can both set (assign) and get (query) the settings used.
2118              
2119             =back
2120              
2121             =cut
2122              
2123             sub viewer_preferences {
2124 0     0 1 0 my $self = shift();
2125 0         0 require PDF::Builder::ViewerPreferences;
2126 0         0 my $prefs = PDF::Builder::ViewerPreferences->new($self);
2127 0 0       0 unless (@_) {
2128 0         0 return $prefs->get_preferences();
2129             }
2130 0         0 return $prefs->set_preferences(@_);
2131             }
2132              
2133             =head2 preferences
2134              
2135             $pdf->preferences(%opts)
2136              
2137             =over
2138              
2139             Controls viewing preferences for the PDF, including the B<Page Mode>,
2140             B<Page Layout>, B<Viewer>, and B<Initial Page> Options. See
2141             L<PDF::Builder::Docs/Preferences - set user display preferences> for details
2142             on all these
2143             option groups, and L<PDF::Builder::Docs/Page Fit Options> for page positioning.
2144              
2145             B<Note:> the various preferences have been split out into their own methods.
2146             It is preferred that you use these specific methods.
2147              
2148             =back
2149              
2150             =cut
2151              
2152             sub preferences {
2153 239     239 1 953 my ($self, %opts) = @_;
2154              
2155             # copy dashed option names to the preferred undashed format
2156             # Page Mode Options
2157 239 50 33     1119 if (defined $opts{'-fullscreen'} && !defined $opts{'fullscreen'}) { $opts{'fullscreen'} = delete($opts{'-fullscreen'}); }
  0         0  
2158 239 50 33     1029 if (defined $opts{'-thumbs'} && !defined $opts{'thumbs'}) { $opts{'thumbs'} = delete($opts{'-thumbs'}); }
  0         0  
2159 239 50 33     1042 if (defined $opts{'-outlines'} && !defined $opts{'outlines'}) { $opts{'outlines'} = delete($opts{'-outlines'}); }
  0         0  
2160             # Page Layout Options
2161 239 50 33     950 if (defined $opts{'-singlepage'} && !defined $opts{'singlepage'}) { $opts{'singlepage'} = delete($opts{'-singlepage'}); }
  0         0  
2162 239 50 33     894 if (defined $opts{'-onecolumn'} && !defined $opts{'onecolumn'}) { $opts{'onecolumn'} = delete($opts{'-onecolumn'}); }
  0         0  
2163 239 50 33     924 if (defined $opts{'-twocolumnleft'} && !defined $opts{'twocolumnleft'}) { $opts{'twocolumnleft'} = delete($opts{'-twocolumnleft'}); }
  0         0  
2164 239 50 33     967 if (defined $opts{'-twocolumnright'} && !defined $opts{'twocolumnright'}) { $opts{'twocolumnright'} = delete($opts{'-twocolumnright'}); }
  0         0  
2165             # Viewer Preferences
2166 239 50 33     1065 if (defined $opts{'-hidetoolbar'} && !defined $opts{'hidetoolbar'}) { $opts{'hidetoolbar'} = delete($opts{'-hidetoolbar'}); }
  0         0  
2167 239 50 33     952 if (defined $opts{'-hidemenubar'} && !defined $opts{'hidemenubar'}) { $opts{'hidemenubar'} = delete($opts{'-hidemenubar'}); }
  0         0  
2168 239 50 33     923 if (defined $opts{'-hidewindowui'} && !defined $opts{'hidewindowui'}) { $opts{'hidewindowui'} = delete($opts{'-hidewindowui'}); }
  0         0  
2169 239 50 33     869 if (defined $opts{'-fitwindow'} && !defined $opts{'fitwindow'}) { $opts{'fitwindow'} = delete($opts{'-fitwindow'}); }
  0         0  
2170 239 50 33     940 if (defined $opts{'-centerwindow'} && !defined $opts{'centerwindow'}) { $opts{'centerwindow'} = delete($opts{'-centerwindow'}); }
  0         0  
2171 239 50 33     827 if (defined $opts{'-displaytitle'} && !defined $opts{'displaytitle'}) { $opts{'displaytitle'} = delete($opts{'-displaytitle'}); }
  0         0  
2172 239 50 33     905 if (defined $opts{'-righttoleft'} && !defined $opts{'righttoleft'}) { $opts{'righttoleft'} = delete($opts{'-righttoleft'}); }
  0         0  
2173 239 50 33     910 if (defined $opts{'-afterfullscreenthumbs'} && !defined $opts{'afterfullscreenthumbs'}) { $opts{'afterfullscreenthumbs'} = delete($opts{'-afterfullscreenthumbs'}); }
  0         0  
2174 239 50 33     962 if (defined $opts{'-afterfullscreenoutlines'} && !defined $opts{'afterfullscreenoutlines'}) { $opts{'afterfullscreenoutlines'} = delete($opts{'-afterfullscreenoutlines'}); }
  0         0  
2175 239 50 33     879 if (defined $opts{'-printscalingnone'} && !defined $opts{'printscalingnone'}) { $opts{'printscalingnone'} = delete($opts{'-printscalingnone'}); }
  0         0  
2176 239 100 66     832 if (defined $opts{'-simplex'} && !defined $opts{'simplex'}) { $opts{'simplex'} = delete($opts{'-simplex'}); }
  1         4  
2177 239 100 66     868 if (defined $opts{'-duplexfliplongedge'} && !defined $opts{'duplexfliplongedge'}) { $opts{'duplexfliplongedge'} = delete($opts{'-duplexfliplongedge'}); }
  1         3  
2178 239 100 66     893 if (defined $opts{'-duplexflipshortedge'} && !defined $opts{'duplexflipshortedge'}) { $opts{'duplexflipshortedge'} = delete($opts{'-duplexflipshortedge'}); }
  1         3  
2179             # Open Action
2180 239 100 66     997 if (defined $opts{'-firstpage'} && !defined $opts{'firstpage'}) { $opts{'firstpage'} = delete($opts{'-firstpage'}); }
  2         7  
2181 239 50 33     1041 if (defined $opts{'-fit'} && !defined $opts{'fit'}) { $opts{'fit'} = delete($opts{'-fit'}); }
  0         0  
2182 239 50 33     1037 if (defined $opts{'-fith'} && !defined $opts{'fith'}) { $opts{'fith'} = delete($opts{'-fith'}); }
  0         0  
2183 239 50 33     930 if (defined $opts{'-fitb'} && !defined $opts{'fitb'}) { $opts{'fitb'} = delete($opts{'-fitb'}); }
  0         0  
2184 239 50 33     878 if (defined $opts{'-fitbh'} && !defined $opts{'fitbh'}) { $opts{'fitbh'} = delete($opts{'-fitbh'}); }
  0         0  
2185 239 50 33     894 if (defined $opts{'-fitv'} && !defined $opts{'fitv'}) { $opts{'fitv'} = delete($opts{'-fitv'}); }
  0         0  
2186 239 50 33     868 if (defined $opts{'-fitbv'} && !defined $opts{'fitbv'}) { $opts{'fitbv'} = delete($opts{'-fitbv'}); }
  0         0  
2187 239 50 33     797 if (defined $opts{'-fitr'} && !defined $opts{'fitr'}) { $opts{'fitr'} = delete($opts{'-fitr'}); }
  0         0  
2188 239 50 33     857 if (defined $opts{'-xyz'} && !defined $opts{'xyz'}) { $opts{'xyz'} = delete($opts{'-xyz'}); }
  0         0  
2189              
2190             # Page Mode Options
2191 239 50       1273 if ($opts{'fullscreen'}) {
    50          
    50          
2192 0         0 $self->{'catalog'}->{'PageMode'} = PDFName('FullScreen');
2193             } elsif ($opts{'thumbs'}) {
2194 0         0 $self->{'catalog'}->{'PageMode'} = PDFName('UseThumbs');
2195             } elsif ($opts{'outlines'}) {
2196 0         0 $self->{'catalog'}->{'PageMode'} = PDFName('UseOutlines');
2197             } else {
2198 239         955 $self->{'catalog'}->{'PageMode'} = PDFName('UseNone');
2199             }
2200              
2201             # Page Layout Options
2202 239 50       1439 if ($opts{'singlepage'}) {
    50          
    50          
    50          
2203 0         0 $self->{'catalog'}->{'PageLayout'} = PDFName('SinglePage');
2204             } elsif ($opts{'onecolumn'}) {
2205 0         0 $self->{'catalog'}->{'PageLayout'} = PDFName('OneColumn');
2206             } elsif ($opts{'twocolumnleft'}) {
2207 0         0 $self->{'catalog'}->{'PageLayout'} = PDFName('TwoColumnLeft');
2208             } elsif ($opts{'twocolumnright'}) {
2209 0         0 $self->{'catalog'}->{'PageLayout'} = PDFName('TwoColumnRight');
2210             } else {
2211 239         673 $self->{'catalog'}->{'PageLayout'} = PDFName('SinglePage');
2212             }
2213              
2214             # Viewer Preferences
2215 239   66     1636 $self->{'catalog'}->{'ViewerPreferences'} ||= PDFDict();
2216 239         1374 $self->{'catalog'}->{'ViewerPreferences'}->realise();
2217              
2218 239 50       854 if ($opts{'hidetoolbar'}) {
2219 0         0 $self->{'catalog'}->{'ViewerPreferences'}->{'HideToolbar'} = PDFBool(1);
2220             }
2221 239 50       754 if ($opts{'hidemenubar'}) {
2222 0         0 $self->{'catalog'}->{'ViewerPreferences'}->{'HideMenubar'} = PDFBool(1);
2223             }
2224 239 50       794 if ($opts{'hidewindowui'}) {
2225 0         0 $self->{'catalog'}->{'ViewerPreferences'}->{'HideWindowUI'} = PDFBool(1);
2226             }
2227 239 50       773 if ($opts{'fitwindow'}) {
2228 0         0 $self->{'catalog'}->{'ViewerPreferences'}->{'FitWindow'} = PDFBool(1);
2229             }
2230 239 50       727 if ($opts{'centerwindow'}) {
2231 0         0 $self->{'catalog'}->{'ViewerPreferences'}->{'CenterWindow'} = PDFBool(1);
2232             }
2233 239 50       761 if ($opts{'displaytitle'}) {
2234 0         0 $self->{'catalog'}->{'ViewerPreferences'}->{'DisplayDocTitle'} = PDFBool(1);
2235             }
2236 239 50       823 if ($opts{'righttoleft'}) {
2237 0         0 $self->{'catalog'}->{'ViewerPreferences'}->{'Direction'} = PDFName('R2L');
2238             }
2239              
2240 239 50       978 if ($opts{'afterfullscreenthumbs'}) {
    50          
2241 0         0 $self->{'catalog'}->{'ViewerPreferences'}->{'NonFullScreenPageMode'} = PDFName('UseThumbs');
2242             } elsif ($opts{'afterfullscreenoutlines'}) {
2243 0         0 $self->{'catalog'}->{'ViewerPreferences'}->{'NonFullScreenPageMode'} = PDFName('UseOutlines');
2244             } else {
2245 239         686 $self->{'catalog'}->{'ViewerPreferences'}->{'NonFullScreenPageMode'} = PDFName('UseNone');
2246             }
2247              
2248 239 50       804 if ($opts{'printscalingnone'}) {
2249 0         0 $self->{'catalog'}->{'ViewerPreferences'}->{'PrintScaling'} = PDFName('None');
2250             }
2251              
2252 239 100       1456 if ($opts{'simplex'}) {
    100          
    100          
2253 1         4 $self->{'catalog'}->{'ViewerPreferences'}->{'Duplex'} = PDFName('Simplex');
2254             } elsif ($opts{'duplexfliplongedge'}) {
2255 1         3 $self->{'catalog'}->{'ViewerPreferences'}->{'Duplex'} = PDFName('DuplexFlipLongEdge');
2256             } elsif ($opts{'duplexflipshortedge'}) {
2257 1         2 $self->{'catalog'}->{'ViewerPreferences'}->{'Duplex'} = PDFName('DuplexFlipShortEdge');
2258             }
2259              
2260             # Open Action
2261 239 100       788 if ($opts{'firstpage'}) {
2262 2         5 my ($page, %args) = @{$opts{'firstpage'}};
  2         9  
2263 2 50       10 $args{'fit'} = 1 unless scalar keys %args;
2264              
2265             # $page can be either a page number (which needs to be wrapped
2266             # in PDFNum) or a page object (which doesn't).
2267 2 100       34 $page = PDFNum($page) unless ref($page);
2268              
2269             # copy dashed args names to preferred undashed names
2270 2 50 33     45 if (defined $args{'-fit'} && !defined $args{'fit'}) { $args{'fit'} = delete($args{'-fit'}); }
  2         7  
2271 2 50 33     32 if (defined $args{'-fith'} && !defined $args{'fith'}) { $args{'fith'} = delete($args{'-fith'}); }
  0         0  
2272 2 50 33     8 if (defined $args{'-fitb'} && !defined $args{'fitb'}) { $args{'fitb'} = delete($args{'-fitb'}); }
  0         0  
2273 2 50 33     7 if (defined $args{'-fitbh'} && !defined $args{'fitbh'}) { $args{'fitbh'} = delete($args{'-fitbh'}); }
  0         0  
2274 2 50 33     5 if (defined $args{'-fitv'} && !defined $args{'fitv'}) { $args{'fitv'} = delete($args{'-fitv'}); }
  0         0  
2275 2 50 33     6 if (defined $args{'-fitbv'} && !defined $args{'fitbv'}) { $args{'fitbv'} = delete($args{'-fitbv'}); }
  0         0  
2276 2 50 33     13 if (defined $args{'-fitr'} && !defined $args{'fitr'}) { $args{'fitr'} = delete($args{'-fitr'}); }
  0         0  
2277 2 50 33     7 if (defined $args{'-xyz'} && !defined $args{'xyz'}) { $args{'xyz'} = delete($args{'-xyz'}); }
  0         0  
2278            
2279 2 50       5 if (defined $args{'fit'}) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
2280 2         7 $self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('Fit'));
2281             } elsif (defined $args{'fith'}) {
2282 0         0 $self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('FitH'), PDFNum($args{'fith'}));
2283             } elsif (defined $args{'fitb'}) {
2284 0         0 $self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('FitB'));
2285             } elsif (defined $args{'fitbh'}) {
2286 0         0 $self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('FitBH'), PDFNum($args{'fitbh'}));
2287             } elsif (defined $args{'fitv'}) {
2288 0         0 $self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('FitV'), PDFNum($args{'fitv'}));
2289             } elsif (defined $args{'fitbv'}) {
2290 0         0 $self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('FitBV'), PDFNum($args{'fitbv'}));
2291             } elsif (defined $args{'fitr'}) {
2292 0 0       0 croak 'insufficient parameters to fitr => []' unless scalar @{$args{'fitr'}} == 4;
  0         0  
2293             $self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('FitR'),
2294 0         0 map { PDFNum($_) } @{$args{'fitr'}});
  0         0  
  0         0  
2295             } elsif (defined $args{'xyz'}) {
2296 0 0       0 croak 'insufficient parameters to xyz => []' unless scalar @{$args{'xyz'}} == 3;
  0         0  
2297             $self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('XYZ'),
2298 0         0 map { PDFNum($_) } @{$args{'xyz'}});
  0         0  
  0         0  
2299             }
2300             }
2301 239         1289 $self->{'pdf'}->out_obj($self->{'catalog'});
2302              
2303 239         645 return $self;
2304             } # end of preferences()
2305              
2306             sub proc_pages {
2307 0     0 0 0 my ($pdf, $object) = @_;
2308              
2309 0 0       0 if (defined $object->{'Resources'}) {
2310 0         0 eval {
2311 0         0 $object->{'Resources'}->realise();
2312             };
2313             }
2314              
2315 0         0 my @pages;
2316 0   0     0 $pdf->{' apipagecount'} ||= 0;
2317 0         0 foreach my $page ($object->{'Kids'}->elements()) {
2318 0         0 $page->realise();
2319             #if ($page->{'Type'}->val() eq 'Pages') {
2320 0 0 0     0 if (defined $page->{'Type'} && $page->{'Type'}->val() eq 'Pages') {
2321 0         0 push @pages, proc_pages($pdf, $page);
2322             }
2323             else {
2324 0         0 $pdf->{' apipagecount'}++;
2325 0         0 $page->{' pnum'} = $pdf->{' apipagecount'};
2326 0 0       0 if (defined $page->{'Resources'}) {
2327 0         0 eval {
2328 0         0 $page->{'Resources'}->realise();
2329             };
2330             }
2331 0         0 push @pages, $page;
2332             }
2333             }
2334              
2335 0         0 return @pages;
2336             }
2337              
2338             =head1 PAGE METHODS
2339              
2340             =head2 page
2341              
2342             $page = $pdf->page()
2343              
2344             $page = $pdf->page($page_number)
2345              
2346             =over
2347              
2348             Returns a I<new> page object. By default, the page is added to the end
2349             of the document. If you give an existing page number, the new page
2350             will be inserted in that position, pushing existing pages back by 1 (e.g.,
2351             C<page(5)> would insert an empty page 5, with the old page 5 now page 6,
2352             etc.
2353              
2354             If $page_number is -1, the new page is inserted as the second-to-last page;
2355             if $page_number is 0, the new page is inserted as the last page.
2356              
2357             B<Example:>
2358              
2359             $pdf = PDF::Builder->new();
2360              
2361             # Add a page. This becomes page 1.
2362             $page = $pdf->page();
2363              
2364             # Add a new first page. $page becomes page 2.
2365             $another_page = $pdf->page(1);
2366              
2367             =back
2368              
2369             =cut
2370              
2371             sub page {
2372 192     192 1 20151 my $self = shift();
2373 192   100     909 my $index = shift() || 0; # default to new "last" page
2374 192         384 my $page;
2375              
2376 192 100       853 if ($index == 0) {
2377 190         3459 $page = PDF::Builder::Page->new($self->{'pdf'}, $self->{'pages'});
2378             } else {
2379 2         12 $page = PDF::Builder::Page->new($self->{'pdf'}, $self->{'pages'}, $index-1);
2380             }
2381              
2382 192         700 $page->{' apipdf'} = $self->{'pdf'};
2383 192         592 $page->{' api'} = $self;
2384 192         575 weaken $page->{' apipdf'};
2385 192         440 weaken $page->{' api'};
2386 192         766 $self->{'pdf'}->out_obj($page);
2387 192         705 $self->{'pdf'}->out_obj($self->{'pages'});
2388              
2389             # fix any bad $index value
2390 192         416 my $pgs_size = @{$self->{'pagestack'}};
  192         471  
2391 192 100       670 if ($pgs_size == 0) { # empty page list, can only add at end
    50          
    50          
2392 180 50       591 warn "page($index) on empty page stack is out of range, use page() or page(0)"
2393             if ($index != 0);
2394 180         390 $index = 0;
2395             } elsif ($pgs_size < -$index) { # index < 0
2396 0         0 warn "page($index) out of range, set to page(1) (before first)";
2397 0         0 $index = 1;
2398             } elsif ($pgs_size < $index) { # index > 0
2399 0         0 warn "page($index) out of range, set to page(0) (after last)";
2400 0         0 $index = 0;
2401             }
2402              
2403 192 100       508 if ($index == 0) {
    50          
2404 190         343 push @{$self->{'pagestack'}}, $page;
  190         556  
2405 190         577 weaken $self->{'pagestack'}->[-1];
2406             } elsif ($index < 0) {
2407             # note that the new element's number is one less than $index,
2408             # since we inserted _before_ $index value!
2409 0         0 splice @{$self->{'pagestack'}}, $index, 0, $page;
  0         0  
2410 0         0 weaken $self->{'pagestack'}->[$index-1];
2411             } else { # index > 0
2412 2         4 splice @{$self->{'pagestack'}}, $index-1, 0, $page;
  2         7  
2413 2         5 weaken $self->{'pagestack'}->[$index-1];
2414             }
2415              
2416             # $page->{'Resources'}=$self->{'pages'}->{'Resources'};
2417 192         1400 return $page;
2418             } # end of page()
2419              
2420             =head2 open_page, openpage
2421              
2422             $page = $pdf->open_page($page_number)
2423              
2424             =over
2425              
2426             Returns the L<PDF::Builder::Page> object of page $page_number.
2427             This is similar to C<< $page = $pdf->page() >>, except that C<$page> is
2428             I<not> a new, empty page; but contains the contents of that existing page.
2429              
2430             If C<$page_number> is 0, -1, or unspecified,
2431             it will return the last page in the document.
2432             If the requested page is out of range, the C<$page> returned will be undefined.
2433              
2434             B<Example:>
2435              
2436             =back
2437              
2438             $pdf = PDF::Builder->open('our/99page.pdf');
2439             $page = $pdf->open_page(1); # returns the first page
2440             $page = $pdf->open_page(99); # returns the last page
2441             $page = $pdf->open_page(-1); # returns the last page
2442             $page = $pdf->open_page(999); # returns undef
2443             $page = $pdf->open_page(0); # returns the last page
2444             $page = $pdf->open_page(); # returns the last page
2445              
2446             =over
2447              
2448             B<Alternate name:> C<openpage>
2449              
2450             This is the older name; it is kept for compatibility until after June 2023
2451             (deprecated, as previously announced).
2452              
2453             =back
2454              
2455             =cut
2456              
2457 1     1 1 11 sub openpage { return open_page(@_); } ## no critic
2458              
2459             sub open_page {
2460 7     7 1 1268 my $self = shift();
2461 7   50     27 my $index = shift() || 0;
2462 7         18 my ($page, $rotate, $media, $trans);
2463              
2464 7 50       37 if ($index == 0) {
    50          
2465 0         0 $page = $self->{'pagestack'}->[-1];
2466             } elsif ($index < 0) {
2467 0         0 $page = $self->{'pagestack'}->[$index];
2468             } else {
2469 7         61 $page = $self->{'pagestack'}->[$index - 1];
2470             }
2471 7 50       45 return unless ref($page);
2472              
2473 7 100       30 if (ref($page) ne 'PDF::Builder::Page') {
2474 6         44 bless $page, 'PDF::Builder::Page';
2475 6         27 $page->{' apipdf'} = $self->{'pdf'};
2476 6         25 $page->{' api'} = $self;
2477 6         45 weaken $page->{' apipdf'};
2478 6         17 weaken $page->{' api'};
2479 6         39 $self->{'pdf'}->out_obj($page);
2480 6 50 33     37 if (($rotate = $page->find_prop('Rotate')) and not $page->{' opened'}) {
2481 0         0 $rotate = ($rotate->val() + 360) % 360;
2482              
2483 0 0 0     0 if ($rotate != 0 and not $self->default('nounrotate')) {
2484 0         0 $page->{'Rotate'} = PDFNum(0);
2485 0         0 foreach my $mediatype (qw(MediaBox CropBox BleedBox TrimBox ArtBox)) {
2486 0 0       0 if ($media = $page->find_prop($mediatype)) {
2487 0         0 $media = [ map { $_->val() } $media->elements() ];
  0         0  
2488             } else {
2489 0         0 $media = [0, 0, 612, 792]; # US Letter default
2490 0 0       0 next if $mediatype ne 'MediaBox';
2491             }
2492 0 0       0 if ($rotate == 90) {
    0          
    0          
2493 0 0       0 $trans = "0 -1 1 0 0 $media->[2] cm" if $mediatype eq 'MediaBox';
2494 0         0 $media = [$media->[1], $media->[0], $media->[3], $media->[2]];
2495             } elsif ($rotate == 180) {
2496 0 0       0 $trans = "-1 0 0 -1 $media->[2] $media->[3] cm" if $mediatype eq 'MediaBox';
2497             } elsif ($rotate == 270) {
2498 0 0       0 $trans = "0 1 -1 0 $media->[3] 0 cm" if $mediatype eq 'MediaBox';
2499 0         0 $media = [$media->[1], $media->[0], $media->[3], $media->[2]];
2500             }
2501 0         0 $page->{$mediatype} = PDFArray(map { PDFNum($_) } @$media);
  0         0  
2502             }
2503             } else {
2504 0         0 $trans = '';
2505             }
2506             } else {
2507 6         27 $trans = '';
2508             }
2509              
2510 6 100 66     41 if (defined $page->{'Contents'} and not $page->{' opened'}) {
2511 4         28 $page->fixcontents();
2512 4         13 my $uncontent = delete $page->{'Contents'};
2513 4         22 my $content = $page->gfx();
2514 4         32 $content->add(" $trans ");
2515              
2516 4 50       26 if ($self->default('pageencaps')) {
2517 0         0 $content->{' stream'} .= ' q ';
2518             }
2519 4         20 foreach my $k ($uncontent->elements()) {
2520 4         19 $k->realise();
2521 4         85 $content->{' stream'} .= ' ' . unfilter($k->{'Filter'}, $k->{' stream'}) . ' ';
2522             }
2523 4 50       22 if ($self->default('pageencaps')) {
2524 0         0 $content->{' stream'} .= ' Q ';
2525             }
2526              
2527             # if we like compress we will do it now to do quicker saves
2528 4 50 33     22 if ($self->{'forcecompress'} eq 'flate' ||
2529             $self->{'forcecompress'} =~ m/^[1-9]\d*$/) {
2530 4         25 $content->{' stream'} = dofilter($content->{'Filter'}, $content->{' stream'});
2531 4         14 $content->{' nofilt'} = 1;
2532 4         12 delete $content->{'-docompress'};
2533 4         23 $content->{'Length'} = PDFNum(length($content->{' stream'}));
2534             }
2535             }
2536 6         22 $page->{' opened'} = 1;
2537             }
2538              
2539 7         47 $self->{'pdf'}->out_obj($page);
2540 7         51 $self->{'pdf'}->out_obj($self->{'pages'});
2541 7         40 $page->{' apipdf'} = $self->{'pdf'};
2542 7         20 $page->{' api'} = $self;
2543 7         20 weaken $page->{' apipdf'};
2544 7         14 weaken $page->{' api'};
2545              
2546 7         37 return $page;
2547             } # end of open_page()
2548              
2549             =head2 import_page, importpage
2550              
2551             $page = $pdf->import_page($source_pdf)
2552              
2553             $page = $pdf->import_page($source_pdf, $source_page_number)
2554              
2555             $page = $pdf->import_page($source_pdf, $source_page_number, $target_page_number)
2556              
2557             $page = $pdf->import_page($source_pdf, $source_page_number, $target_page_object)
2558              
2559             =over
2560              
2561             Imports a page from $source_pdf and adds it to the specified position
2562             in $pdf.
2563              
2564             If the C<$source_page_number> is omitted, 0, or -1; the last page of the
2565             source is imported.
2566             If the C<$target_page_number> is omitted, 0, or -1; the imported page will be
2567             placed as the new last page of the target (C<$pdf>).
2568             Otherwise, as with the C<page()> method, the page will be inserted before an
2569             existing page of that number.
2570              
2571             B<Note:> If you pass a page I<object> instead of a page I<number> for
2572             C<$target_page_number>, the contents of the page will be B<merged> into the
2573             existing page.
2574              
2575             B<Example:>
2576              
2577             =back
2578              
2579             my $pdf = PDF::Builder->new();
2580             my $source = PDF::Builder->open('source.pdf');
2581              
2582             # Add page 2 from the old PDF as page 1 of the new PDF
2583             my $page = $pdf->import_page($source, 2);
2584              
2585             $pdf->saveas('sample.pdf');
2586              
2587             =over
2588              
2589             B<Note:> You can only import a page from an existing PDF file.
2590              
2591             B<Alternate name:> importpage
2592              
2593             This name is still valid in PDF::API2, so it is included here for compatibility.
2594              
2595             =back
2596              
2597             =cut
2598              
2599             # removed years ago, but is still in API2, so for code compatibility...
2600 0     0 1 0 sub importpage{ return import_page(@_); } ## no critic
2601              
2602             sub import_page {
2603 1     1 1 10 my ($self, $s_pdf, $s_idx, $t_idx) = @_;
2604              
2605 1   50     5 $s_idx ||= 0; # default to last page
2606 1   50     8 $t_idx ||= 0; # default to last page
2607 1         2 my ($s_page, $t_page);
2608              
2609 1 50 33     41 unless (ref($s_pdf) and $s_pdf->isa('PDF::Builder')) {
2610 0         0 croak "Invalid usage: first argument must be PDF::Builder instance, not: " . ref($s_pdf);
2611             }
2612              
2613 1 50       8 if (ref($s_idx) eq 'PDF::Builder::Page') {
2614 0         0 $s_page = $s_idx;
2615             } else {
2616 1         6 $s_page = $s_pdf->open_page($s_idx);
2617 1 50       5 croak "Unable to open page '$s_idx' in source PDF" unless defined $s_page;
2618             }
2619              
2620 1 50       5 if (ref($t_idx) eq 'PDF::Builder::Page') {
2621 0         0 $t_page = $t_idx;
2622             } else {
2623 1 50       6 if ($self->pages() < $t_idx) {
2624 0         0 $t_page = $self->page();
2625             } else {
2626 1         6 $t_page = $self->page($t_idx);
2627             }
2628             }
2629              
2630 1   50     9 $self->{'apiimportcache'} = $self->{'apiimportcache'} || {};
2631 1   50     23 $self->{'apiimportcache'}->{$s_pdf} = $self->{'apiimportcache'}->{$s_pdf} || {};
2632              
2633             # we now import into a form to keep
2634             # all those nasty resources from polluting
2635             # our very own resource naming space.
2636 1         8 my $xo = $self->importPageIntoForm($s_pdf, $s_page);
2637              
2638             # copy all page dimensions
2639 1         4 foreach my $k (qw(MediaBox ArtBox TrimBox BleedBox CropBox)) {
2640 5         16 my $prop = $s_page->find_prop($k);
2641 5 100       13 next unless defined $prop;
2642              
2643 1         5 my $box = _walk_obj({}, $s_pdf->{'pdf'}, $self->{'pdf'}, $prop);
2644 1         6 my $method = lc $k;
2645              
2646 1         5 $t_page->$method(map { $_->val() } $box->elements());
  4         10  
2647             }
2648              
2649 1         7 $t_page->gfx()->formimage($xo, 0, 0, 1);
2650              
2651             # copy annotations and/or form elements as well
2652 1 0 33     5 if (exists $s_page->{'Annots'} and $s_page->{'Annots'} and $self->{'copyannots'}) {
      0        
2653             # first set up the AcroForm, if required
2654 0         0 my $AcroForm;
2655 0 0       0 if (my $a = $s_pdf->{'pdf'}->{'Root'}->realise()->{'AcroForm'}) {
2656 0         0 $a->realise();
2657              
2658 0         0 $AcroForm = _walk_obj({}, $s_pdf->{'pdf'}, $self->{'pdf'}, $a,
2659             qw(NeedAppearances SigFlags CO DR DA Q));
2660             }
2661 0         0 my @Fields = ();
2662 0         0 my @Annots = ();
2663 0         0 foreach my $a ($s_page->{'Annots'}->elements()) {
2664 0         0 $a->realise();
2665 0         0 my $t_a = PDFDict();
2666 0         0 $self->{'pdf'}->new_obj($t_a);
2667             # these objects are likely to be both annotations and Acroform fields
2668             # key names are copied from PDF Reference 1.4 (Tables)
2669 0         0 my @k = (
2670             qw( Type Subtype Contents P Rect NM M F BS Border AP AS C CA T Popup A AA StructParent Rotate
2671             ), # Annotations - Common (8.10)
2672             qw( Subtype Contents Open Name ), # Text Annotations (8.15)
2673             qw( Subtype Contents Dest H PA ), # Link Annotations (8.16)
2674             qw( Subtype Contents DA Q ), # Free Text Annotations (8.17)
2675             qw( Subtype Contents L BS LE IC ), # Line Annotations (8.18)
2676             qw( Subtype Contents BS IC ), # Square and Circle Annotations (8.20)
2677             qw( Subtype Contents QuadPoints ), # Markup Annotations (8.21)
2678             qw( Subtype Contents Name ), # Rubber Stamp Annotations (8.22)
2679             qw( Subtype Contents InkList BS ), # Ink Annotations (8.23)
2680             qw( Subtype Contents Parent Open ), # Popup Annotations (8.24)
2681             qw( Subtype FS Contents Name ), # File Attachment Annotations (8.25)
2682             qw( Subtype Sound Contents Name ), # Sound Annotations (8.26)
2683             qw( Subtype Movie Contents A ), # Movie Annotations (8.27)
2684             qw( Subtype Contents H MK ), # Widget Annotations (8.28)
2685             # Printers Mark Annotations (none)
2686             # Trap Network Annotations (none)
2687             );
2688 0 0       0 push @k, (
2689             qw( Subtype FT Parent Kids T TU TM Ff V DV AA
2690             ), # Fields - Common (8.49)
2691             qw( DR DA Q ), # Fields containing variable text (8.51)
2692             qw( Opt ), # Checkbox field (8.54)
2693             qw( Opt ), # Radio field (8.55)
2694             qw( MaxLen ), # Text field (8.57)
2695             qw( Opt TI I ), # Choice field (8.59)
2696             ) if $AcroForm;
2697              
2698             # sorting out dupes
2699 0         0 my %ky = map { $_ => 1 } @k;
  0         0  
2700             # we do P separately, as it points to the page the Annotation is on
2701 0         0 delete $ky{'P'};
2702             # copy everything else
2703 0         0 foreach my $k (keys %ky) {
2704 0 0       0 next unless defined $a->{$k};
2705 0         0 $a->{$k}->realise();
2706 0         0 $t_a->{$k} = _walk_obj({}, $s_pdf->{'pdf'}, $self->{'pdf'}, $a->{$k});
2707             }
2708 0         0 $t_a->{'P'} = $t_page;
2709 0         0 push @Annots, $t_a;
2710 0 0 0     0 push @Fields, $t_a if ($AcroForm and $t_a->{'Subtype'}->val() eq 'Widget');
2711             }
2712 0         0 $t_page->{'Annots'} = PDFArray(@Annots);
2713 0 0       0 $AcroForm->{'Fields'} = PDFArray(@Fields) if $AcroForm;
2714 0         0 $self->{'pdf'}->{'Root'}->{'AcroForm'} = $AcroForm;
2715             }
2716 1         6 $t_page->{' imported'} = 1;
2717              
2718 1         5 $self->{'pdf'}->out_obj($t_page);
2719 1         4 $self->{'pdf'}->out_obj($self->{'pages'});
2720              
2721 1         5 return $t_page;
2722             } # end of import_page()
2723              
2724             =head2 embed_page, importPageIntoForm
2725              
2726             $xoform = $pdf->embed_page($source_pdf, $source_page_number)
2727              
2728             =over
2729              
2730             Returns a Form XObject created by extracting the specified page from
2731             C<$source_pdf>.
2732              
2733             This is useful if you want to transpose the imported page somewhat
2734             differently onto a page (e.g. two-up, four-up, etc.).
2735              
2736             If C<$source_page_number> is 0 or -1, it will return the last page in the
2737             document. The B<default> value for the C<$source_page_number> is 0 (return
2738             last page).
2739              
2740             B<Example:>
2741              
2742             =back
2743              
2744             # take page 2 of source.pdf and add to empty doc sample.pdf at half size
2745             # note that sample.pdf could be an existing document!
2746             #
2747             my $pdf = PDF::Builder->new(); # so far, empty document
2748             my $source = PDF::Builder->open('source.pdf'); # content to copy over
2749             my $page = $pdf->page(); # place to be actually updated
2750              
2751             # Import Page 2 from the source PDF
2752             my $xo = $pdf->embed_page($source, 2);
2753              
2754             # Add it to the new PDF's first page at 1/2 scale
2755             my ($x, $y) = (0, 0);
2756             $page->object($xo, $x, $y, 0.5);
2757              
2758             $pdf->save('sample.pdf');
2759              
2760             =over
2761              
2762             B<Note:> You can only import a page from an existing PDF file.
2763              
2764             B<Alternate name:> C<importPageIntoForm>
2765              
2766             This is the older name; it is kept for compatibility.
2767              
2768             =back
2769              
2770             =cut
2771              
2772 4     4 1 42 sub importPageIntoForm { return embed_page(@_); } ## no critic
2773              
2774             sub embed_page {
2775 4     4 1 15 my ($self, $s_pdf, $s_idx) = @_;
2776 4   50     17 $s_idx ||= 0;
2777              
2778 4 50 33     64 unless (ref($s_pdf) and $s_pdf->isa('PDF::Builder')) {
2779 0         0 croak "Invalid usage: first argument must be PDF::Builder instance, not: " . ref($s_pdf);
2780             }
2781              
2782 4         11 my ($s_page, $xo);
2783              
2784 4         26 $xo = $self->xo_form();
2785              
2786 4 100       20 if (ref($s_idx) eq 'PDF::Builder::Page') {
2787 1         15 $s_page = $s_idx;
2788             } else {
2789 3         20 $s_page = $s_pdf->open_page($s_idx);
2790 3 50       13 croak "Unable to open page '$s_idx' in source PDF" unless defined $s_page;
2791             }
2792              
2793 4   100     31 $self->{'apiimportcache'} ||= {};
2794 4   100     27 $self->{'apiimportcache'}->{$s_pdf} ||= {};
2795              
2796             # This should never get past MediaBox, since it's a required object.
2797 4         15 foreach my $k (qw(MediaBox ArtBox TrimBox BleedBox CropBox)) {
2798             #next unless defined $s_page->{$k};
2799             #my $box = _walk_obj($self->{'apiimportcache'}->{$s_pdf}, $s_pdf->{'pdf'},
2800             # $self->{'pdf'}, $s_page->{$k});
2801 4 50       20 next unless defined $s_page->find_prop($k);
2802             my $box = _walk_obj($self->{'apiimportcache'}->{$s_pdf}, $s_pdf->{'pdf'},
2803 4         43 $self->{'pdf'}, $s_page->find_prop($k));
2804 4         18 $xo->bbox(map { $_->val() } $box->elements());
  16         44  
2805 4         16 last;
2806             }
2807 4 50       22 $xo->bbox(0,0, 612,792) unless defined $xo->{'BBox'}; # US Letter default
2808              
2809 4         25 foreach my $k (qw(Resources)) {
2810 4         24 $s_page->{$k} = $s_page->find_prop($k);
2811 4 50       17 next unless defined $s_page->{$k};
2812 4 50       21 $s_page->{$k}->realise() if ref($s_page->{$k}) =~ /Objind$/;
2813              
2814 4         15 foreach my $sk (qw(XObject ExtGState Font ProcSet Properties ColorSpace Pattern Shading)) {
2815 32 100       107 next unless defined $s_page->{$k}->{$sk};
2816 5 50       32 $s_page->{$k}->{$sk}->realise() if ref($s_page->{$k}->{$sk}) =~ /Objind$/;
2817 5         14 foreach my $ssk (keys %{$s_page->{$k}->{$sk}}) {
  5         29  
2818 10 100       43 next if $ssk =~ /^ /;
2819             $xo->resource($sk, $ssk, _walk_obj($self->{'apiimportcache'}->{$s_pdf},
2820 1         8 $s_pdf->{'pdf'}, $self->{'pdf'}, $s_page->{$k}->{$sk}->{$ssk}));
2821             }
2822             }
2823             }
2824              
2825             # create a whole content stream
2826             ## technically it is possible to submit an unfinished
2827             ## (e.g., newly created) source-page, but that's nonsense,
2828             ## so we expect a page fixed by open_page and croak otherwise
2829 4 50       19 unless ($s_page->{' opened'}) {
2830 0         0 croak "Pages may only be imported from a complete PDF. Save and reopen the source PDF object first.";
2831             }
2832              
2833 4 100       15 if (defined $s_page->{'Contents'}) {
2834 3         21 $s_page->fixcontents();
2835              
2836 3         9 $xo->{' stream'} = '';
2837             # open_page pages only contain one stream
2838 3         18 my ($k) = $s_page->{'Contents'}->elements();
2839 3         38 $k->realise();
2840 3 50       12 if ($k->{' nofilt'}) {
2841             # we have a finished stream here, so we unfilter
2842 3         33 $xo->add('q', unfilter($k->{'Filter'}, $k->{' stream'}), 'Q');
2843             } else {
2844             # stream is an unfinished/unfiltered content
2845             # so we just copy it and add the required "qQ"
2846 0         0 $xo->add('q', $k->{' stream'}, 'Q');
2847             }
2848             $xo->compressFlate() if $self->{'forcecompress'} eq 'flate' ||
2849 3 100 66     34 $self->{'forcecompress'} =~ m/^[1-9]\d*$/;
2850             }
2851              
2852 4         159 return $xo;
2853             } # end of embed_page()
2854              
2855             # internal utility used by embed_page and import_page
2856              
2857             sub _walk_obj {
2858 518     518   1211 my ($object_cache, $source_pdf, $target_pdf, $source_object, @keys) = @_;
2859              
2860 518 100       2784 if (ref($source_object) =~ /Objind$/) {
2861 1         5 $source_object->realise();
2862             }
2863              
2864 518 50       1831 return $object_cache->{scalar $source_object} if defined $object_cache->{scalar $source_object};
2865             #croak "infinite loop while copying objects" if $source_object->{' copied'};
2866              
2867 518         1986 my $target_object = $source_object->copy($source_pdf); ## thanks to: yaheath // Fri, 17 Sep 2004
2868              
2869             #$source_object->{' copied'} = 1;
2870 518 100       1427 $target_pdf->new_obj($target_object) if $source_object->is_obj($source_pdf);
2871              
2872 518         5363 $object_cache->{scalar $source_object} = $target_object;
2873              
2874 518 100       2086 if (ref($source_object) =~ /Array$/) {
    100          
2875 7         373 $target_object->{' val'} = [];
2876 7         69 foreach my $k ($source_object->elements()) {
2877 501 50       1493 $k->realise() if ref($k) =~ /Objind$/;
2878 501         1320 $target_object->add_elements(_walk_obj($object_cache, $source_pdf, $target_pdf, $k));
2879             }
2880             } elsif (ref($source_object) =~ /Dict$/) {
2881 2 50       15 @keys = keys(%$target_object) unless scalar @keys;
2882 2         7 foreach my $k (@keys) {
2883 12 100       53 next if $k =~ /^ /;
2884 11 50       53 next unless defined $source_object->{$k};
2885 11         39 $target_object->{$k} = _walk_obj($object_cache, $source_pdf, $target_pdf, $source_object->{$k});
2886             }
2887 2 50       508 if ($source_object->{' stream'}) {
2888 0 0       0 if ($target_object->{'Filter'}) {
2889 0         0 $target_object->{' nofilt'} = 1;
2890             } else {
2891 0         0 delete $target_object->{' nofilt'};
2892 0         0 $target_object->{'Filter'} = PDFArray(PDFName('FlateDecode'));
2893             }
2894 0         0 $target_object->{' stream'} = $source_object->{' stream'};
2895             }
2896             }
2897 518         1257 delete $target_object->{' streamloc'};
2898 518         1027 delete $target_object->{' streamsrc'};
2899              
2900 518         6394 return $target_object;
2901             } # end of _walk_obj()
2902              
2903             =head2 page_count, pages
2904              
2905             $count = $pdf->page_count()
2906              
2907             =over
2908              
2909             Returns the number of pages in the document.
2910              
2911             B<Alternate name:> C<pages>
2912              
2913             This is the old name; it is kept for compatibility.
2914              
2915             =back
2916              
2917             =cut
2918              
2919 3     3 1 329 sub pages { return page_count(@_); } ## no critic
2920              
2921             sub page_count {
2922 3     3 1 7 my $self = shift();
2923 3         5 return scalar @{$self->{'pagestack'}};
  3         16  
2924             }
2925              
2926             =head2 page_labels, pageLabel
2927              
2928             $pdf->page_labels($page_number, %opts)
2929              
2930             =over
2931              
2932             Sets page label numbering format, for the PDF Reader's page-selection slider
2933             thumb (I<not> the outline/bookmarks). At this time, there is no method to
2934             automatically synchronize a page's label with the outline/bookmarks, or to
2935             somewhere on the printed page.
2936             Depending on the PDF Reader you are using, this formatted page label I<may>
2937             show up in the reader control area as the current page number.
2938              
2939             B<CAUTIONS:>
2940              
2941             =back
2942              
2943             =over
2944              
2945             =item 1.
2946              
2947             The given page index started at 0 for the old method (C<pageLabel()>),
2948             which is the internal PDF array index, while for the new method
2949             (C<page_labels()>) it starts with 1, the visible page number! Don't get
2950             confused.
2951              
2952             =item 2.
2953              
2954             Options for the old method (C<pageLabel>) were a hashref, while for the
2955             new method (C<page_labels>) it is a hash. This permits pageLabel() to accept
2956             I<multiple> page number schemes in one call, rather than one per call as per
2957             page_labels().
2958              
2959             =item 3.
2960              
2961             Many PDF readers do not support page labels; they simply (at most)
2962             label the sliding thumb with the physical page number. B<Adobe Acrobat Reader>
2963             (free version) appears to have a bug in some versions, where if the only
2964             page label is 'decimal' (the default), it labels the thumb as though no page
2965             labels were defined ("Page I<m> of I<n>"). You can get around this problem by
2966             using an explicit B<start> option value, e.g., C<'start' =E<gt> 1>. However,
2967             for your convenience, the B<start> option now defaults to 1.
2968              
2969             =back
2970              
2971             # Generate a 30-page PDF
2972             my $pdf = PDF::Builder->new();
2973             $pdf->page() for 1..30;
2974              
2975             # Number pages i to v, 1 to 20, and A-1 to A-5, respectively
2976             $pdf->page_labels(1, 'style' => 'roman');
2977             $pdf->page_labels(6, 'style' => 'decimal');
2978             $pdf->page_labels(26, 'style' => 'decimal', 'prefix' => 'A-');
2979              
2980             or...
2981              
2982             $pdf->pageLabel(0, { style => 'roman' },
2983             5, { style => 'decimal' },
2984             25, { style => 'decimal', prefix => 'A-' });
2985              
2986             $pdf->save('sample.pdf');
2987              
2988             B<Supported Options:>
2989              
2990             =over
2991              
2992             =item style
2993              
2994             B<Roman> (I,II,III,...), B<roman> (i,ii,iii,...), B<decimal> (1,2,3,...),
2995             B<Alpha> (A,B,C,...), B<alpha> (a,b,c,...), or B<nocounter>. This is the
2996             styling of the counter part of the label (unless C<nocounter>, in which case
2997             there is no counter output). Note that B<arabic> is permitted as a synonym
2998             for B<decimal>.
2999              
3000             =item start
3001              
3002             (Re)start numbering the I<counter> at given page number (this is a decimal
3003             integer, I<not> the styled counter). By default it starts at 1, and B<resets>
3004             to 1 at each call to C<page_labels()>! You need to explicitly give C<start> if
3005             you want to I<continue> counting at the current page number when you call
3006             C<page_labels()>, whether or not you are changing the format.
3007              
3008             Also note that the counter starts at physical page B<1>, while the page
3009             C<$index> number in the C<page_labels()> call (as well as the PDF PageLabels
3010             dictionary) starts at logical page (index) B<0>.
3011              
3012             =item prefix
3013              
3014             Text prefix for numbering, such as an Appendix letter B<B->. If C<style> is
3015             I<nocounter>, just this text is used, otherwise a styled counter will be
3016             appended. If C<style> is omitted, remember that it will default to a decimal
3017             number, which will be appended to the prefix.
3018              
3019             According to the Adobe/ISO PDF specification, a prefix of 'Content' has a
3020             special meaning, in that any /S counter is ignored and only that text is used.
3021             However, this appears to be ignored (use a style of I<nocounter> to suppress
3022             the counter).
3023              
3024             =back
3025              
3026             =over
3027              
3028             B<Dotted inserted page numbers>
3029              
3030             To easily insert a range of pages, e.g., 3 pages between existing pages 37 and
3031             38, use a C<prefix> of '37.' and decimal numbering starting (C<start>) at 1 or
3032             a specified point. This would produce pages 37.1, 37.2, and 37.3. To put
3033             leading 0's on the numbers, if you find that you later need to insert additional
3034             pages between those, e.g., page 37.05 between 37 and 37.1, use a C<prefix> of
3035             '37.0' and C<start> at 5.
3036              
3037             Just remember that only the (rightmost) I<counter>, which begins at the
3038             C<start> value, is incremented (and formatted) by the PDF Reader. Everything
3039             else (the C<prefix>) is a constant string. At worst, you might have to define
3040             a page label for each individual page.
3041              
3042             B<Example:>
3043              
3044             =back
3045              
3046             # Start with lowercase Roman Numerals at the 1st page, starting with i (1)
3047             $pdf->page_labels(1,
3048             'style' => 'roman',
3049             );
3050              
3051             or,
3052              
3053             $pdf->pageLabel(0,
3054             { 'style' => 'roman' },
3055             );
3056              
3057             # Switch to Arabic (decimal) at the 5th page, starting with 1
3058             $pdf->page_labels(5,
3059             'style' => 'decimal',
3060             );
3061              
3062             or,
3063              
3064             $pdf->pageLabel(4,
3065             { 'style' => 'decimal' },
3066             );
3067              
3068             # invalid style at the 25th page, should just continue
3069             # with decimal at the current counter
3070             $pdf->page_labels(25,
3071             'style' => 'raman_noodles', # fail over to decimal
3072             # note that older versions of PDF::API2 may see the 'r' and
3073             # treat it as 'roman'
3074             'start' => 25, # necessary, otherwise would restart at 1
3075             );
3076              
3077             # No page label at the 31st and 32nd pages. Note that this could be
3078             # confusing to the person viewing the PDF, but may be appropriate if
3079             # the page itself has no numbering.
3080             $pdf->page_labels(31,
3081             'style' => 'nocounter',
3082             );
3083              
3084             # Numbering for Appendix A at the 33rd page, A-1, A-2,...
3085             $pdf->page_labels(33,
3086             'start' => 1, # unnecessary
3087             'prefix' => 'A-'
3088             );
3089              
3090             # Numbering for Appendix B at the 37th page, B-1, B-2,...
3091             $pdf->page_labels(37,
3092             'prefix' => 'B-'
3093             );
3094              
3095             # Numbering for the Index at the 41st page, Index I, Index II,...
3096             $pdf->page_labels(41,
3097             'style' => 'Roman',
3098             'start' => 1, # unnecessary
3099             'prefix' => 'Index ' # note trailing space
3100             );
3101              
3102             # Unnumbered 'Index' at the 45th page, Index, Index,...
3103             $pdf->page_labels(45,
3104             'style' => 'nocounter',
3105             'prefix' => 'Index '
3106             );
3107              
3108             =over
3109              
3110             B<Alternate name:> C<pageLabel>
3111              
3112             This old method name is retained for compatibility with old user code.
3113             Note that with C<pageLabel>, you need to make the "options" list an anonymous
3114             hash by placing B<{ }> around the entire list, even if it has only one item
3115             in it. Also remember that the page number (index) for C<pageLabel> starts at 0
3116             (same as the PDF page index), rather than 1 (as in C<page_labels>).
3117             Finally, pageLabel() still permits you to define multiple page numbering schemes
3118             in one call.
3119              
3120             =back
3121              
3122             =cut
3123              
3124             # in the new method, parameters are organized a bit differently than in the
3125             # old pageLabel(). rather than an opts hashref, it is a hash.
3126             sub page_labels {
3127 0     0 1 0 my ($self, $page_number, %opts) = @_;
3128 0 0       0 if ($page_number <= 0) {
3129 0         0 carp "page_labels() start at 1, not 0. page changed to 1.";
3130 0         0 $page_number = 1;
3131             }
3132             # check if opts is a hash?
3133 0 0       0 if (ref(%opts) ne '') {
3134 0         0 carp "page_labels() options must be a hash. Ignored.";
3135 0         0 %opts = ();
3136             }
3137 0         0 return pageLabel($self, $page_number-1, \%opts);
3138             }
3139              
3140             # actually, the old code
3141             sub pageLabel {
3142 8     8 1 128 my $self = shift();
3143              
3144 8   33     82 $self->{'catalog'}->{'PageLabels'} ||= PDFDict();
3145 8   33     66 $self->{'catalog'}->{'PageLabels'}->{'Nums'} ||= PDFArray();
3146              
3147 8         25 my $nums = $self->{'catalog'}->{'PageLabels'}->{'Nums'};
3148 8         39 while (scalar @_) { # should we have only one trip through here?
3149 8         20 my $index = shift();
3150 8 50       35 if ($index < 0) {
3151 0         0 carp "page labels start at 0. page changed to 0.";
3152 0         0 $index = 0;
3153             }
3154 8         18 my $opts = shift();
3155             # check if opts is a hashref?
3156 8 50       36 if (ref($opts) ne 'HASH') {
3157 0         0 carp "pageLabels() options must be a hash ref. Ignored.";
3158 0         0 $opts = {};
3159             }
3160             # copy dashed options to preferred undashed option names
3161 8 50 33     41 if (defined $opts->{'-style'} && !defined $opts->{'style'}) { $opts->{'style'} = delete($opts->{'-style'}); }
  0         0  
3162 8 50 33     48 if (defined $opts->{'-prefix'} && !defined $opts->{'prefix'}) { $opts->{'prefix'} = delete($opts->{'-prefix'}); }
  0         0  
3163 8 50 33     38 if (defined $opts->{'-start'} && !defined $opts->{'start'}) { $opts->{'start'} = delete($opts->{'-start'}); }
  0         0  
3164              
3165 8         36 $nums->add_elements(PDFNum($index));
3166              
3167 8         28 my $d = PDFDict();
3168 8 100       35 if (defined $opts->{'style'}) {
3169 6 50       28 if ($opts->{'style'} ne 'nocounter') {
3170             # defaults to decimal if unrecogized style given
3171             $d->{'S'} = PDFName($opts->{'style'} eq 'Roman' ? 'R' :
3172             $opts->{'style'} eq 'roman' ? 'r' :
3173             $opts->{'style'} eq 'Alpha' ? 'A' :
3174             $opts->{'style'} eq 'alpha' ? 'a' :
3175             $opts->{'style'} eq 'arabic' ? 'D' :
3176 6 50       168 $opts->{'style'} eq 'decimal' ? 'D' : 'D');
    100          
    100          
    100          
    100          
    100          
3177             } else {
3178             # for nocounter (no styled counter), do not create /S entry
3179             }
3180             } else {
3181             # default to decimal counter if no style given
3182 2         7 $d->{'S'} = PDFName('D');
3183             }
3184              
3185 8 100       44 if (defined $opts->{'prefix'}) {
3186             # 'Content' supposedly treated differently
3187 1         7 $d->{'P'} = PDFString($opts->{'prefix'}, 's');
3188             }
3189              
3190 8 100       36 if (defined $opts->{'start'}) {
3191 1         5 $d->{'St'} = PDFNum($opts->{'start'});
3192             } else {
3193             # some PDF Readers (e.g., Adobe Acrobat Reader) ignore a decimal
3194             # label if no Start given, so default to 1
3195 7         23 $d->{'St'} = PDFNum(1);
3196             }
3197              
3198 8         38 $nums->add_elements($d);
3199             }
3200              
3201 8         32 return;
3202             } # end of page_labels()
3203              
3204             # set global User Unit scale factor (default 1.0)
3205              
3206             =head2 userunit
3207              
3208             $pdf->userunit($value)
3209              
3210             =over
3211              
3212             Sets the global UserUnit, defining the scale factor to multiply any size or
3213             coordinate by. For example, C<userunit(72)> results in a User Unit of 72 points,
3214             or 1 inch.
3215              
3216             See L<PDF::Builder::Docs/User Units> for more information.
3217              
3218             =back
3219              
3220             =cut
3221              
3222             sub userunit {
3223 0     0 1 0 my ($self, $value) = @_;
3224              
3225 0 0       0 if (float($value) <= 0.0) {
3226 0         0 warn "Invalid User Unit value '$value', set to 1.0";
3227 0         0 $value = 1.0;
3228             }
3229              
3230 0         0 $self->verCheckOutput(1.6, "set User Unit");
3231 0         0 $self->{'pdf'}->{' userUnit'} = float($value);
3232 0         0 $self->{'pages'}->{'UserUnit'} = PDFNum(float($value));
3233 0 0       0 if (defined $self->{'pages'}->{'MediaBox'}) { # should be default letter
3234 0 0       0 if ($value != 1.0) { # divide points by User Unit
3235 0         0 my @corners = ( 0, 0, 612/$value, 792/$value );
3236 0         0 $self->{'pages'}->{'MediaBox'} = PDFArray( map { PDFNum(float($_)) } @corners );
  0         0  
3237             }
3238             }
3239              
3240 0         0 return $self;
3241             }
3242              
3243             # utility to handle calling page_size, and name with or without 'orient' setting
3244             sub _bbox {
3245 252     252   694 my ($self, @corners) = @_;
3246              
3247             # if 1 or 3 elements in @corners, and [0] contains a letter, it's a name
3248 252         608 my $isName = 0;
3249 252 100 66     3283 if (scalar @corners && $corners[0] =~ m/[a-z]/i) { $isName = 1; }
  236         534  
3250              
3251 252 50       1514 if (scalar @corners == 3) {
3252             # name plus one option (orient)
3253 0         0 my ($name, %opts) = @corners;
3254             # copy dashed name options to preferred undashed name
3255 0 0 0     0 if (defined $opts{'-orient'} && !defined $opts{'orient'}) { $opts{'orient'} = delete($opts{'-orient'}); }
  0         0  
3256              
3257 0         0 @corners = page_size(($name)); # now 4 numeric values
3258 0 0       0 if (defined $opts{'orient'}) {
3259 0 0       0 if ($opts{'orient'} =~ m/^l/i) { # 'landscape' or just 'l'
3260             # 0 0 W H -> 0 0 H W
3261 0         0 my $temp;
3262 0         0 $temp = $corners[2]; $corners[2] = $corners[3]; $corners[3] = $temp;
  0         0  
  0         0  
3263             }
3264             }
3265             } else {
3266             # name without [orient] option, or numeric coordinates given
3267 252         1406 @corners = page_size(@corners);
3268             }
3269              
3270 252         830 my $UU = $self->{'pdf'}->{' userUnit'};
3271             # scale down size if User Unit given (e.g., Letter => 0 0 8.5 11)
3272 252 50 66     1395 if ($isName && $UU != 1.0) {
3273 0         0 for (my $i=0; $i<4; $i++) {
3274 0         0 $corners[$i] /= $UU;
3275             }
3276             }
3277              
3278 252         792 return (@corners);
3279             } # end of _bbox()
3280              
3281             # utility to get a bounding box by name
3282             sub _get_bbox {
3283 274     274   811 my ($self, $boxname) = @_;
3284              
3285             # if requested box not set, return next higher box's corners
3286             # MediaBox should always at least have a default value
3287 274 100       1173 if (not defined $self->{'pages'}->{$boxname}) {
3288 8 100 100     57 if ($boxname eq 'CropBox') {
    50 66        
3289 2         5 $boxname = 'MediaBox';
3290             } elsif ($boxname eq 'BleedBox' ||
3291             $boxname eq 'TrimBox' ||
3292             $boxname eq 'ArtBox' ) {
3293 6 50       20 if (defined $self->{'pages'}->{'CropBox'}) {
3294 0         0 $boxname = 'CropBox';
3295             } else {
3296 6         14 $boxname = 'MediaBox';
3297             }
3298             } else {
3299             # invalid box name (silent error). just use MediaBox
3300 0         0 $boxname = 'MediaBox';
3301             }
3302             }
3303              
3304             # now $boxname is known to exist
3305 274         1258 return map { $_->val() } $self->{'pages'}->{$boxname}->elements();
  1096         2909  
3306              
3307             } # end of _get_bbox()
3308              
3309             =head2 mediabox
3310              
3311             $pdf->mediabox($name)
3312              
3313             $pdf->mediabox($name, 'orient' => 'orientation')
3314              
3315             $pdf->mediabox($w,$h)
3316              
3317             $pdf->mediabox($llx,$lly, $urx,$ury)
3318              
3319             ($llx,$lly, $urx,$ury) = $pdf->mediabox()
3320              
3321             =over
3322              
3323             Sets (or gets) the global MediaBox, defining the width and height (or by
3324             corner coordinates, or by standard name) of the output page itself, such as
3325             the physical paper size.
3326              
3327             See L<PDF::Builder::Docs/Media Box> for more information.
3328             The method always returns the current bounds (after any set operation).
3329              
3330             =back
3331              
3332             =cut
3333              
3334             sub mediabox {
3335 246     246 1 909 my ($self, @corners) = @_;
3336 246 100       802 if (defined $corners[0]) {
3337 240         1182 @corners = $self->_bbox(@corners);
3338 240         701 $self->{'pages'}->{'MediaBox'} = PDFArray( map { PDFNum(float($_)) } @corners );
  960         3078  
3339             }
3340              
3341 246         1105 return $self->_get_bbox('MediaBox');
3342             }
3343              
3344             =head2 cropbox
3345              
3346             $pdf->cropbox($name)
3347              
3348             $pdf->cropbox($name, 'orient' => 'orientation')
3349              
3350             $pdf->cropbox($w,$h)
3351              
3352             $pdf->cropbox($llx,$lly, $urx,$ury)
3353              
3354             ($llx,$lly, $urx,$ury) = $pdf->cropbox()
3355              
3356             =over
3357              
3358             Sets (or gets) the global CropBox. This will define the media size to which
3359             the output will later be clipped.
3360              
3361             See L<PDF::Builder::Docs/Crop Box> for more information.
3362             The method always returns the current bounds (after any set operation).
3363              
3364             =back
3365              
3366             =cut
3367              
3368             sub cropbox {
3369 7     7 1 5768 my ($self, @corners) = @_;
3370 7 100       26 if (defined $corners[0]) {
3371 3         15 @corners = $self->_bbox(@corners);
3372 3         9 $self->{'pages'}->{'CropBox'} = PDFArray( map { PDFNum(float($_)) } @corners );
  12         37  
3373             }
3374              
3375 7         25 return $self->_get_bbox('CropBox');
3376             }
3377              
3378             =head2 bleedbox
3379              
3380             $pdf->bleedbox($name)
3381              
3382             $pdf->bleedbox($name, 'orient' => 'orientation')
3383              
3384             $pdf->bleedbox($w,$h)
3385              
3386             $pdf->bleedbox($llx,$lly, $urx,$ury)
3387              
3388             ($llx,$lly, $urx,$ury) = $pdf->bleedbox()
3389              
3390             =over
3391              
3392             Sets (or gets) the global BleedBox. This is typically used for hard copy
3393             printing where you want ink to go to the edge of the cut paper.
3394              
3395             See L<PDF::Builder::Docs/Bleed Box> for more information.
3396             The method always returns the current bounds (after any set operation).
3397              
3398             =back
3399              
3400             =cut
3401              
3402             sub bleedbox {
3403 7     7 1 5402 my ($self, @corners) = @_;
3404 7 100       62 if (defined $corners[0]) {
3405 3         65 @corners = $self->_bbox(@corners);
3406 3         11 $self->{'pages'}->{'BleedBox'} = PDFArray( map { PDFNum(float($_)) } @corners );
  12         54  
3407             }
3408              
3409 7         27 return $self->_get_bbox('BleedBox');
3410             }
3411              
3412             =head2 trimbox
3413              
3414             $pdf->trimbox($name)
3415              
3416             $pdf->trimbox($name, 'orient' => 'orientation')
3417              
3418             $pdf->trimbox($w,$h)
3419              
3420             $pdf->trimbox($llx,$lly, $urx,$ury)
3421              
3422             ($llx,$lly, $urx,$ury) = $pdf->trimbox()
3423              
3424             =over
3425              
3426             Sets (or gets) the global TrimBox. This is supposed to be the actual
3427             dimensions of the finished page (after trimming of the paper).
3428              
3429             See L<PDF::Builder::Docs/Trim Box> for more information.
3430             The method always returns the current bounds (after any set operation).
3431              
3432             =back
3433              
3434             =cut
3435              
3436             sub trimbox {
3437 7     7 1 4762 my ($self, @corners) = @_;
3438 7 100       26 if (defined $corners[0]) {
3439 3         13 @corners = $self->_bbox(@corners);
3440 3         11 $self->{'pages'}->{'TrimBox'} = PDFArray( map { PDFNum(float($_)) } @corners );
  12         33  
3441             }
3442              
3443 7         27 return $self->_get_bbox('TrimBox');
3444             }
3445              
3446             =head2 artbox
3447              
3448             $pdf->artbox($name)
3449              
3450             $pdf->artbox($name, 'orient' => 'orientation')
3451              
3452             $pdf->artbox($w,$h)
3453              
3454             $pdf->artbox($llx,$lly, $urx,$ury)
3455              
3456             ($llx,$lly, $urx,$ury) = $pdf->artbox()
3457              
3458             =over
3459              
3460             Sets (or gets) the global ArtBox. This is supposed to define "the extent of
3461             the page's I<meaningful> content". What is considered "meaningful" is up to
3462             the author of the page, but would usually exclude "decorative" graphics and
3463             such; and possibly titles, headers, footers, and page numbers.
3464              
3465             See L<PDF::Builder::Docs/Art Box> for more information.
3466             The method always returns the current bounds (after any set operation).
3467              
3468             =back
3469              
3470             =cut
3471              
3472             sub artbox {
3473 7     7 1 5388 my ($self, @corners) = @_;
3474 7 100       25 if (defined $corners[0]) {
3475 3         16 @corners = $self->_bbox(@corners);
3476 3         9 $self->{'pages'}->{'ArtBox'} = PDFArray( map { PDFNum(float($_)) } @corners );
  12         32  
3477             }
3478              
3479 7         28 return $self->_get_bbox('ArtBox');
3480             }
3481              
3482             =head1 FONT METHODS
3483              
3484             =head2 Embedding of Fonts
3485              
3486             B<CAUTION:> Some font routines (currently only C<ttfont()>) automatically embed
3487             font definitions for the purpose of improving portability of PDF files. Note
3488             that font copyright and licensing terms vary by font provider, and some may
3489             prohibit embedding of their fonts, either entirely, or allowing only the subset
3490             of glyphs actually used in the document. You should be aware of the terms, and
3491             use the C<embed> and C<nosubset> flags as appropriate. The PDF::Builder font
3492             routines currently have no means to automatically detect any embedding
3493             limitations for a given font, and cannot default their behavior accordingly!
3494              
3495             =head2 Font-related Methods
3496              
3497             =head3 corefont
3498              
3499             $font = $pdf->corefont($fontname, %opts)
3500              
3501             =over
3502              
3503             Returns a new Adobe core font object. For details,
3504             including supported C<%opts>,
3505             see L<PDF::Builder::Resource::Font::CoreFont>.
3506             Note that this is an Adobe-standard corefont I<name>, and not a file name.
3507              
3508             See also L<PDF::Builder::Docs/Core Fonts> for additional information,
3509             including Notes and Limitations.
3510              
3511             =back
3512              
3513             =cut
3514              
3515             sub corefont {
3516 37     37 1 9496 my ($self, $name, %opts) = @_;
3517             # copy dashed name options to preferred undashed format
3518 37 50 33     202 if (defined $opts{'-unicodemap'} && !defined $opts{'unicodemap'}) { $opts{'unicodemap'} = delete($opts{'-unicodemap'}); }
  0         0  
3519              
3520 37         6112 require PDF::Builder::Resource::Font::CoreFont;
3521 37 50       427 if (!PDF::Builder::Resource::Font::CoreFont->is_standard($name)) {
3522 0 0       0 if ($name =~ /^Times$/i) {
3523             # Accept Times as an alias for Times-Roman to follow the pattern
3524             # set by Courier and Helvetica
3525 0 0       0 if (!$MSG_COUNT[3]) {
3526             # one message (per run) reminding user
3527 0         0 carp "Times is not a standard font; substituting Times-Roman";
3528 0         0 $MSG_COUNT[3]++;
3529             }
3530 0         0 $name = 'Times-Roman';
3531             }
3532             }
3533 37         234 my $obj = PDF::Builder::Resource::Font::CoreFont->new($self->{'pdf'}, $name, %opts);
3534 37         486 $self->{'pdf'}->out_obj($self->{'pages'});
3535 37 50       160 $obj->tounicodemap() if $opts{'unicodemap'}; # UTF-8 not usable
3536              
3537 37         382 return $obj;
3538             }
3539              
3540             =head3 psfont
3541              
3542             $font = $pdf->psfont($ps_file, %opts)
3543              
3544             =over
3545              
3546             Returns a new Adobe Type1 ("PostScript", "T1") font object. For details,
3547             including supported C<%opts>, see L<PDF::Builder::Resource::Font::Postscript>.
3548              
3549             See also L<PDF::Builder::Docs/PS Fonts> for additional information,
3550             including Notes and Limitations.
3551              
3552             =back
3553              
3554             =cut
3555              
3556             sub psfont {
3557 0     0 1 0 my ($self, $psf, %opts) = @_;
3558             # copy dashed name options to preferred undashed format
3559 0 0 0     0 if (defined $opts{'-afmfile'} && !defined $opts{'afmfile'}) { $opts{'afmfile'} = delete($opts{'-afmfile'}); }
  0         0  
3560 0 0 0     0 if (defined $opts{'-afm_file'} && !defined $opts{'afm_file'}) { $opts{'afm_file'} = delete($opts{'-afm_file'}); }
  0         0  
3561 0 0 0     0 if (defined $opts{'-pfmfile'} && !defined $opts{'pfmfile'}) { $opts{'pfmfile'} = delete($opts{'-pfmfile'}); }
  0         0  
3562 0 0 0     0 if (defined $opts{'-pfm_file'} && !defined $opts{'pfm_file'}) { $opts{'pfm_file'} = delete($opts{'-pfm_file'}); }
  0         0  
3563 0 0 0     0 if (defined $opts{'-unicodemap'} && !defined $opts{'unicodemap'}) { $opts{'unicodemap'} = delete($opts{'-unicodemap'}); }
  0         0  
3564              
3565             # preferred option names
3566 0 0       0 if (defined $opts{'afm_file'}) { $opts{'afmfile'} = delete($opts{'afm_file'}); }
  0         0  
3567 0 0       0 if (defined $opts{'pfm_file'}) { $opts{'pfmfile'} = delete($opts{'pfm_file'}); }
  0         0  
3568              
3569 0         0 foreach my $o (qw(afmfile pfmfile)) {
3570 0 0       0 next unless defined $opts{$o};
3571 0         0 $opts{$o} = _findFont($opts{$o});
3572             }
3573 0         0 $psf = _findFont($psf);
3574 0         0 require PDF::Builder::Resource::Font::Postscript;
3575 0         0 my $obj = PDF::Builder::Resource::Font::Postscript->new($self->{'pdf'}, $psf, %opts);
3576              
3577 0         0 $self->{'pdf'}->out_obj($self->{'pages'});
3578 0 0       0 $obj->tounicodemap() if $opts{'unicodemap'}; # UTF-8 not usable
3579              
3580 0         0 return $obj;
3581             }
3582              
3583             =head3 ttfont
3584              
3585             $font = $pdf->ttfont($ttf_file, %opts)
3586              
3587             =over
3588              
3589             Returns a new TrueType (or OpenType) font object.
3590             For details, including supported C<%opts>,
3591             see L<PDF::Builder::Resource::CIDFont::TrueType>.
3592              
3593             See also L<PDF::Builder::Docs/TrueType Fonts> for additional information,
3594             including Notes and Limitations.
3595              
3596             =back
3597              
3598             =cut
3599              
3600             sub ttfont {
3601 0     0 1 0 my ($self, $file, %opts) = @_;
3602             # copy dashed name options to preferred undashed format
3603 0 0 0     0 if (defined $opts{'-unicodemap'} && !defined $opts{'unicodemap'}) { $opts{'unicodemap'} = delete($opts{'-unicodemap'}); }
  0         0  
3604              
3605             # noembed deprecated in API2, some may be using embed in code
3606 0 0 0     0 if (defined $opts{'-noembed'} && !defined $opts{'noembed'}) { $opts{'noembed'} = delete($opts{'-noembed'}); }
  0         0  
3607 0 0 0     0 if (defined $opts{'-embed'} && !defined $opts{'embed'}) { $opts{'embed'} = delete($opts{'-embed'}); }
  0         0  
3608              
3609             # PDF::Builder doesn't set BaseEncoding for TrueType fonts, so text
3610             # isn't searchable unless a ToUnicode CMap is included. Include
3611             # the ToUnicode CMap by default, but allow it to be disabled (for
3612             # performance and file size reasons) by setting 'unicodemap' to 0.
3613 0 0       0 $opts{'unicodemap'} = 1 unless exists $opts{'unicodemap'};
3614             # if BOTH embed and noembed given, use embed
3615 0 0 0     0 if (defined $opts{'noembed'} && !defined $opts{'embed'}) {
3616 0         0 $opts{'embed'} = !$opts{'noembed'};
3617             }
3618 0   0     0 $opts{'embed'} //= 1;
3619              
3620 0 0       0 $file = UNIVERSAL::isa($file, 'Font::TTF::Font')? $file:
    0          
3621             _findFont($file) or croak "Unable to find font \"$file\"";
3622 0         0 require PDF::Builder::Resource::CIDFont::TrueType;
3623 0         0 my $obj = PDF::Builder::Resource::CIDFont::TrueType->new($self->{'pdf'}, $file, %opts);
3624              
3625 0         0 $self->{'pdf'}->out_obj($self->{'pages'});
3626 0 0       0 $obj->tounicodemap() if $opts{'unicodemap'};
3627              
3628 0         0 return $obj;
3629             }
3630              
3631             =head3 bdfont
3632              
3633             $font = $pdf->bdfont($bdf_file, @opts)
3634              
3635             =over
3636              
3637             Returns a new BDF (bitmapped distribution format) font object, based on the
3638             specified Adobe BDF file. These are very low resolution fonts that appear to
3639             have come off a dot-matrix printer, and should only be used for decorative
3640             or novelty purposes.
3641              
3642             See also L<PDF::Builder::Resource::Font::BdFont>
3643              
3644             =back
3645              
3646             =cut
3647              
3648             sub bdfont {
3649 0     0 1 0 my ($self, $bdf_file, @opts) = @_;
3650              
3651 0         0 require PDF::Builder::Resource::Font::BdFont;
3652 0         0 my $obj = PDF::Builder::Resource::Font::BdFont->new($self->{'pdf'}, $bdf_file, @opts);
3653              
3654 0         0 $self->{'pdf'}->out_obj($self->{'pages'});
3655             # $obj->tounicodemap(); # does not support Unicode!
3656              
3657 0         0 return $obj;
3658             }
3659              
3660             =head3 cjkfont
3661              
3662             $font = $pdf->cjkfont($cjkname, %opts)
3663              
3664             =over
3665              
3666             Returns a new CJK font object. These are TrueType-like fonts for East Asian
3667             languages (Chinese, Japanese, Korean).
3668             For details, including supported C<%opts>, see L<PDF::Builder::Resource::CIDFont::CJKFont>,
3669             as well as L<PDF::Builder::Docs/CJK Fonts>.
3670              
3671             B<NOTE:> C<cjkfont> is quite old and is not well supported. We recommend that
3672             you try using C<ttfont> (or another font routine, if not TTF/OTF) with the
3673             appropriate CJK font file. Most appear to be .ttf or .otf format. PDFs created
3674             using C<cjkfont> may not be fully portable, and support for
3675             C<cjkfont> I<may> be dropped in a future release. We would appreciate hearing
3676             from you if you are successfully using C<cjkfont>, and are unable to use
3677             C<ttfont> instead.
3678              
3679             Among other things, C<cjkfont> selections are limited, as they require CMAP
3680             files; they may or may not subset correctly; and they can not be used as the
3681             base for synthetic fonts.
3682              
3683             =back
3684              
3685             =cut
3686              
3687             sub cjkfont {
3688 1     1 1 10 my ($self, $name, %opts) = @_;
3689             # copy dashed name options to preferred undashed format
3690 1 50 33     6 if (defined $opts{'-unicodemap'} && !defined $opts{'unicodemap'}) { $opts{'unicodemap'} = delete($opts{'-unicodemap'}); }
  0         0  
3691              
3692 1         823 require PDF::Builder::Resource::CIDFont::CJKFont;
3693 1         16 my $obj = PDF::Builder::Resource::CIDFont::CJKFont->new($self->{'pdf'}, $name, %opts);
3694              
3695 1         6 $self->{'pdf'}->out_obj($self->{'pages'});
3696 1 50       4 $obj->tounicodemap() if $opts{'unicodemap'};
3697              
3698 1         4 return $obj;
3699             }
3700              
3701             =head3 font
3702              
3703             $font = $pdf->font($name, %opts)
3704              
3705             =over
3706              
3707             A convenience function to add a font to the PDF without having to specify the
3708             format. Returns the font object, to be used by L<PDF::Builder::Content>.
3709              
3710             The font C<$name> is either the name of one of the standard 14 fonts
3711             (L<PDF::Builder::Resource::Font::CoreFont/STANDARD FONTS>), such as
3712             C<Helvetica>, a C<Font::TTF::Font> object, or the path to a font file
3713             (including an extension/filetype).
3714             There are 15 additional core fonts on a Windows system.
3715             Note that the exact name of a core font needs to be given.
3716             The file extension (if path given) determines what type of font file it is.
3717              
3718             =back
3719              
3720             my $pdf = PDF::Builder->new();
3721             my $font1 = $pdf->font('Helvetica-Bold');
3722             my $font2 = $pdf->font('/path/to/ComicSans.ttf');
3723             my $page = $pdf->page();
3724             my $content = $page->text();
3725              
3726             $content->position(1 * 72, 9 * 72);
3727             $content->font($font1, 24);
3728             $content->text('Hello, World!');
3729              
3730             $content->position(0, -36);
3731             $content->font($font2, 12);
3732             $content->text('This is some sample text.');
3733              
3734             $pdf->saveas('sample.pdf');
3735              
3736             =over
3737              
3738             The path can be omitted if the font file is in the current directory or one of
3739             the directories returned by C<font_path>.
3740              
3741             Core, TrueType (ttf/otf), Adobe PostScript Type 1 (pfa/pfb/t1), and Adobe Glyph
3742             Bitmap Distribution Format (bdf) fonts are supported.
3743              
3744             =back
3745              
3746             The following options (C<%opts>) are available:
3747              
3748             =over
3749              
3750             =item format
3751              
3752             The font format is normally detected automatically based on the file's
3753             extension (if one is given, as in non-core fonts). If you're using a font with
3754             an atypical extension, you can set
3755             C<format> to one of C<truetype> (TrueType or OpenType), C<type1> (PostScript
3756             Type 1), or C<bitmap> (Adobe Bitmap). There is no C<format> entry for Core
3757             fonts, as the name must be an exact match.
3758              
3759             =item (other options)
3760              
3761             The C<%opts> entries are passed on to the appropriate font format routine
3762             (C<corefont()>, C<ttfont()>, etc.), so they can be used here. These include
3763             'encode', 'pdfname', 'pfmfile', 'dokern', etc. See the appropriate font routine
3764             for a full list of the supported options.
3765              
3766             =back
3767              
3768             =cut
3769              
3770             sub font {
3771 0     0 1 0 my ($self, $name, %opts) = @_;
3772             # copy dashed name options to preferred undashed format
3773 0 0 0     0 if (defined $opts{'-kerning'} && !defined $opts{'kerning'}) { $opts{'kerning'} = delete($opts{'-kerning'}); }
  0         0  
3774 0 0 0     0 if (defined $opts{'-dokern'} && !defined $opts{'dokern'}) { $opts{'dokern'} = delete($opts{'-dokern'}); }
  0         0  
3775 0 0 0     0 if (defined $opts{'-embed'} && !defined $opts{'embed'}) { $opts{'embed'} = delete($opts{'-embed'}); }
  0         0  
3776              
3777 0 0       0 if (exists $opts{'kerning'}) {
3778 0         0 $opts{'dokern'} = delete $opts{'kerning'};
3779             }
3780 0   0     0 $opts{'dokern'} //= 1; # kerning ON by default for font()
3781              
3782             # see if it's a plain core font first
3783 0         0 require PDF::Builder::Resource::Font::CoreFont;
3784 0 0 0     0 if (PDF::Builder::Resource::Font::CoreFont->is_standard($name)) {
    0          
3785 0         0 return $self->corefont($name, %opts);
3786             } elsif ($name =~ /^Times$/i and not $opts{'format'}) {
3787             # Accept Times as an alias for Times-Roman to follow the pattern set by
3788             # Courier and Helvetica
3789 0         0 carp "Times is not a standard font; substituting Times-Roman";
3790 0         0 return $self->corefont('Times-Roman', %opts);
3791             }
3792              
3793 0         0 my $format = $opts{'format'};
3794 0 0 0     0 $format //= 'truetype' if UNIVERSAL::isa($name, 'Font::TTF::Font');
3795 0 0 0     0 $format //= ($name =~ /\.[ot]tf$/i ? 'truetype' :
    0          
    0          
    0          
3796             $name =~ /\.pf[ab]$/i ? 'type1' :
3797             $name =~ /\.t1$/i ? 'type1' :
3798             $name =~ /\.bdf$/i ? 'bitmap' : '');
3799              
3800 0 0       0 if ($format eq 'truetype') {
    0          
    0          
    0          
    0          
3801 0   0     0 $opts{'embed'} //= 1;
3802 0         0 return $self->ttfont($name, %opts);
3803             } elsif ($format eq 'type1') {
3804             # psfont routine will check for afmfile and pfmfile
3805 0         0 return $self->psfont($name, %opts);
3806             } elsif ($format eq 'bitmap') {
3807 0         0 return $self->bdfont($name, %opts);
3808             } elsif ($format) {
3809 0         0 croak "Unrecognized font format: $format";
3810             } elsif ($name =~ /(\..*)$/) {
3811 0         0 croak "Unrecognized font file extension: $1";
3812             } else {
3813 0         0 croak "Unrecognized font: $name";
3814             }
3815             }
3816              
3817             =head3 standard_fonts
3818              
3819             @names = $pdf->standard_fonts($flag)
3820            
3821             Returns the names of the 14 standard (built-in) "core" fonts, if C<$flag> is
3822             omitted or "false" (0). See
3823             L<PDF::API2::Resource::Font::CoreFont> for details.
3824             B<Note> that these do I<not> include the 14 additional Windows "core"
3825             fonts extension, unless C<$flag> is given with a value of "true" (1).
3826              
3827             =cut
3828              
3829             sub standard_fonts {
3830 2     2 1 2304 my $self = shift;
3831 2         5 my $Windows_ext = 0;
3832 2 50 66     16 if (@_ and $_[0]) { $Windows_ext = 1; }
  1         4  
3833              
3834 2         14 require PDF::Builder::Resource::Font::CoreFont;
3835              
3836 2         12 my @cores = PDF::Builder::Resource::Font::CoreFont->names($Windows_ext);
3837              
3838 2         18 return @cores;
3839             }
3840            
3841             =head3 is_standard_font
3842              
3843             $boolean = PDF::Builder->is_standard_font($name);
3844            
3845             $boolean = PDF::Builder->is_standard_font($name, $flag);
3846            
3847             Returns true if C<$name> is an exact, case-sensitive match for one of the
3848             standard font names.
3849              
3850             B<Note> that these do I<not> include the 14 additional Windows "core"
3851             fonts extension, unless C<$flag> is given with a value of "true" (1), in which case,
3852             C<$name> will also be checked against the additional font names.
3853              
3854             =cut
3855              
3856             sub is_standard_font {
3857 2     2 1 665 my $self = shift;
3858 2         5 my $name = shift;
3859 2         4 my $Windows_ext = 0;
3860 2 0 33     9 if (@_ and $_[0]) { $Windows_ext = 1; }
  0         0  
3861              
3862 2         18 require PDF::Builder::Resource::Font::CoreFont;
3863              
3864 2         16 return PDF::Builder::Resource::Font::CoreFont->is_standard($name, $Windows_ext);
3865             }
3866            
3867             =head3 font_path
3868              
3869             @directories = PDF::Builder->font_path()
3870              
3871             =over
3872              
3873             Return the list of directories that will be searched (in order) in addition to
3874             the current directory when you add a font to a PDF without including the full
3875             path to the font file.
3876              
3877             =back
3878              
3879             =cut
3880              
3881             sub font_path {
3882 234     234 1 2747 return @font_path;
3883             }
3884              
3885             =head3 add_to_font_path, addFontDirs
3886              
3887             @directories = PDF::Builder::add_to_font_path('/my/fonts', '/path/to/fonts', ...)
3888              
3889             =over
3890              
3891             Adds one or more directories to the list of paths to be searched for font files.
3892              
3893             Returns the font search path.
3894              
3895             B<Alternate name:> C<addFontDirs>
3896              
3897             Prior to recent changes to PDF::API2, this method was addFontDirs(). This
3898             method is still available, but may be deprecated some time in the future.
3899              
3900             =back
3901              
3902             =cut
3903              
3904 0     0 1 0 sub addFontDirs { return add_to_font_path(@_); } ## no critic
3905              
3906             sub add_to_font_path {
3907             # Allow this method to be called using either :: or -> notation.
3908 0 0   0 1 0 shift() if ref($_[0]);
3909 0 0       0 shift() if $_[0] eq __PACKAGE__;
3910              
3911 0         0 push @font_path, @_;
3912 0         0 return @font_path;
3913             }
3914              
3915             =head3 set_font_path
3916              
3917             @directories = PDF::Builder->set_font_path('/my/fonts', '/path/to/fonts');
3918              
3919             =over
3920              
3921             Replace the existing font search path. This should only be necessary if you
3922             need to remove a directory from the path for some reason, or if you need to
3923             reorder the list.
3924              
3925             Returns the font search path.
3926              
3927             =back
3928              
3929             =cut
3930              
3931             # I don't know why there are separate set and query methods, but to maintain
3932             # compatibility, we'll follow that convention...
3933              
3934             sub set_font_path {
3935             # Allow this method to be called using either :: or -> notation.
3936 39 50   39 1 247 shift() if ref($_[0]);
3937 39 50       190 shift() if $_[0] eq __PACKAGE__;
3938              
3939             #@font_path = ((map { "$_/PDF/Builder/fonts" } @INC), @_);
3940 39         305 @font_path = @_;
3941              
3942 39         214 return @font_path;
3943             }
3944              
3945             sub _findFont {
3946 0     0   0 my $font = shift();
3947              
3948             # Check the current directory or the path is absolute
3949 0 0       0 return $font if -f $font;
3950 0 0       0 return if substr($font, 0, 1) eq '/';
3951              
3952             # Check the font search path
3953 0         0 foreach my $directory (@font_path) {
3954 0 0       0 return "$directory/$font" if -f "$directory/$font";
3955             }
3956              
3957 0         0 return;
3958             }
3959              
3960             =head3 synfont, synthetic_font
3961              
3962             $font = $pdf->synfont($basefont, %opts)
3963              
3964             =over
3965              
3966             Returns a new synthetic font object. These are modifications to a core (or
3967             PS/T1 or TTF/OTF) font, where the font may be replaced by a Type1 or Type3
3968             PostScript font.
3969             This does not appear to work with CJK fonts (created with C<cjkfont> method).
3970             For details, see L<PDF::Builder::Docs/Synthetic Fonts>.
3971              
3972             See also L<PDF::Builder::Resource::Font::SynFont>
3973              
3974             B<Alternate name:> C<synthetic_font>
3975              
3976             Prior to recent PDF::API2 changes, the routine to create modified fonts was
3977             "synfont". PDF::API2 has renamed it to "synthetic_font", which I don't like,
3978             but to maintain compatibility, "synthetic_font" is available as an alias.
3979              
3980             There are also some minor option differences (incompatibilities)
3981             discussed in C<SynFont>, including the value of 'bold' between the two entry
3982             points.
3983              
3984             =back
3985              
3986             =cut
3987              
3988 0     0 1 0 sub synthetic_font { return synfont(@_, '-entry_point'=>'synthetic_font'); } ## no critic
3989              
3990             sub synfont {
3991 0     0 1 0 my ($self, $font, %opts) = @_;
3992             # copy dashed name options to preferred undashed format
3993 0 0 0     0 if (defined $opts{'-unicodemap'} && !defined $opts{'unicodemap'}) { $opts{'unicodemap'} = delete($opts{'-unicodemap'}); }
  0         0  
3994             # define entry point in options if synfont
3995 0 0       0 if (!defined $opts{'-entry_point'}) { $opts{'-entry_point'} = 'synfont'; }
  0         0  
3996              
3997             # PDF::Builder doesn't set BaseEncoding for TrueType fonts, so text
3998             # isn't searchable unless a ToUnicode CMap is included. Include
3999             # the ToUnicode CMap by default, but allow it to be disabled (for
4000             # performance and file size reasons) by setting unicodemap to 0.
4001 0 0       0 $opts{'unicodemap'} = 1 unless exists $opts{'unicodemap'};
4002              
4003 0         0 require PDF::Builder::Resource::Font::SynFont;
4004 0         0 my $obj = PDF::Builder::Resource::Font::SynFont->new($self->{'pdf'}, $font, %opts);
4005              
4006 0         0 $self->{'pdf'}->out_obj($self->{'pages'});
4007 0 0       0 $obj->tounicodemap() if $opts{'unicodemap'};
4008              
4009 0         0 return $obj;
4010             }
4011              
4012             =head3 unifont
4013              
4014             $font = $pdf->unifont(@fontspecs, %opts)
4015              
4016             =over
4017              
4018             Returns a new uni-font object, based on the specified fonts and options.
4019              
4020             B<BEWARE:> This is not a true PDF-object, but a virtual/abstract font definition!
4021              
4022             See also L<PDF::Builder::Resource::UniFont>.
4023              
4024             =back
4025              
4026             =cut
4027              
4028             # tentatively deprecated in PDF::API2. suggests using Unicode-supporting
4029             # TTF instead. see also Resource/UniFont.pm (POD removed to discourage use).
4030             sub unifont {
4031 1     1 1 13 my ($self, @opts) = @_;
4032             # must leave opts as an array, rather than as a hash, so option fixup
4033             # needs to be done within new(). opts is not just options (hash), but
4034             # also a variable-length array of refs, which doesn't take kindly to
4035             # being hashified!
4036              
4037 1         741 require PDF::Builder::Resource::UniFont;
4038 1         11 my $obj = PDF::Builder::Resource::UniFont->new($self->{'pdf'}, @opts);
4039              
4040 1         4 return $obj;
4041             }
4042              
4043             =head2 Font Manager methods
4044              
4045             The Font Manager is automatically initialized.
4046              
4047             =head3 font_settings
4048              
4049             @list = $pdf->font_settings() # Get
4050              
4051             $pdf->font_settings(%info) # Set
4052              
4053             =over
4054              
4055             Change one or more default settings.
4056             See L<PDF::Builder::FontManager>/font_settings for details.
4057              
4058             =back
4059              
4060             =cut
4061              
4062             sub font_settings {
4063 0     0 1 0 my $self = shift;
4064 0         0 return $self->{' FM'}->font_settings(@_);
4065             }
4066              
4067             =head3 add_font_path
4068              
4069             $rc = $pdf->add_font_path("a directory path", %opts)
4070              
4071             =over
4072              
4073             Add a search path for Font Manager font entries.
4074             See L<PDF::Builder::FontManager>/add_font_path for details.
4075              
4076             =back
4077              
4078             =cut
4079              
4080             sub add_font_path {
4081 0     0 1 0 my $self = shift;
4082 0         0 return $self->{' FM'}->add_font_path(@_);
4083             }
4084              
4085             =head3 add_font
4086              
4087             $rc = $pdf->add_font(%info)
4088              
4089             =over
4090              
4091             Add a font (face) definition to the Font Manager list.
4092             See L<PDF::Builder::FontManager>/add_font for details.
4093              
4094             =back
4095              
4096             =cut
4097              
4098             sub add_font {
4099 0     0 1 0 my $self = shift;
4100 0         0 return $self->{' FM'}->add_font(@_);
4101             }
4102              
4103             =head3 get_font
4104              
4105             @current = $pdf->get_font() # Get
4106              
4107             $font = $pdf->get_font(%info) # Set
4108              
4109             =over
4110              
4111             Retrieve a ready-to-use font, or find out what the current one is.
4112             See L<PDF::Builder::FontManager>/get_font for details.
4113              
4114             =back
4115              
4116             =cut
4117              
4118             sub get_font {
4119 0     0 1 0 my $self = shift;
4120 0         0 return $self->{' FM'}->get_font(@_);
4121             }
4122              
4123             =head3 get_external_font
4124              
4125             $rc = $pdf->get_external_font()
4126              
4127             =over
4128              
4129             See if there is already a predefined (opened) font that the user wants to use.
4130             See L<PDF::Builder::FontManager>/get_external_font for details.
4131              
4132             =back
4133              
4134             =cut
4135              
4136             sub get_external_font {
4137 0     0 1 0 my $self = shift;
4138 0         0 return $self->{' FM'}->get_external_font(@_);
4139             }
4140              
4141             =head3 dump_font_tables
4142              
4143             $pdf->dump_font_tables()
4144              
4145             =over
4146              
4147             Dump all known font information to STDOUT.
4148             See L<PDF::Builder::FontManager>/dump_font_tables for details.
4149              
4150             =back
4151              
4152             =cut
4153              
4154             sub dump_font_tables {
4155 0     0 1 0 my $self = shift;
4156 0         0 return $self->{' FM'}->dump_font_tables(@_);
4157             }
4158              
4159             =head1 IMAGE METHODS
4160              
4161             =head2 image
4162              
4163             $object = $pdf->image($file, %opts);
4164              
4165             =over
4166              
4167             A convenience function to attempt to determine the image type, and import a
4168             file of that type and return an object that can be placed as part of a page's
4169             content:
4170              
4171             =back
4172              
4173             my $pdf = PDF::Builder->new();
4174             my $page = $pdf->page();
4175              
4176             my $image = $pdf->image('/path/to/image.jpg');
4177             $page->object($image, 100, 100);
4178              
4179             $pdf->save('sample.pdf');
4180              
4181             =over
4182              
4183             C<$file> may be either a file name, a filehandle, or a
4184             L<PDF::Builder::Resource::XObject::Image::GD> object.
4185              
4186             B<Caution:> Do not confuse this C<image> ($pdf-E<gt>) with the image method
4187             found in the graphics (gfx) class ($gfx-E<gt>), used to actually I<place> a
4188             read-in or decoded image on the page!
4189              
4190             See L<PDF::Builder::Content/image> and L<PDF::Builder::Content/object> for
4191             details about placing images on a page once they're imported.
4192              
4193             The image format is normally detected automatically based on the file's
4194             extension (.gif, .png, .tif/.tiff, .jpg/.jpeg, .pnm/.pbm/.pgm/.ppm). If passed
4195             a filehandle, image formats GIF, JPEG, PNM, and PNG will be
4196             detected based on the file's header. Unfortunately, at this time, other image
4197             formats (TIFF and GD) cannot be automatically detected. (TIFF I<could> be,
4198             except that C<image_tiff()> cannot use a filehandle anyway as input when using
4199             the libtiff library, which is highly recommended.)
4200              
4201             If the file has an atypical extension or the filehandle is for a different kind
4202             of image, you can set the C<format> option to one of the supported types:
4203             C<gif>, C<jpeg>, C<png>, C<pnm>, or C<tiff>.
4204              
4205             B<Note:> PNG images that include an alpha (transparency) channel go through a
4206             relatively slow process of splitting the image into separate RGB and alpha
4207             components as is required by images in PDFs. If you're having performance
4208             issues, install Image::PNG::Libpng to speed up this process by
4209             an order of magnitude; either module will be used automatically if available.
4210             See the C<image_png> method for details.
4211              
4212             B<Note:> TIFF image processing is very slow if using the pure Perl decoder.
4213             We highly recommend using the Graphics::TIFF library to improve performance.
4214             See the C<image_tiff> method for details.
4215              
4216             =back
4217              
4218             =cut
4219              
4220             sub image {
4221 3     3 1 262 my ($self, $file, %opts) = @_;
4222              
4223 3   50     27 my $format = lc($opts{'format'} // '');
4224              
4225 3 50       20 if (ref($file) eq 'GD::Image') {
    50          
4226 0         0 return $self->image_gd($file, %opts);
4227             } elsif (ref($file)) {
4228 3   33     20 $format ||= _detect_image_format($file);
4229             # JPEG, PNG, GIF, and P*M files can be detected
4230             # TIFF files cannot currently be detected
4231             # GD images are created on-the-fly and don't have files
4232             }
4233 3 50       9 unless (ref($file)) {
4234 0 0 0     0 $format ||= ($file =~ /\.jpe?g$/i ? 'jpeg' :
    0          
    0          
    0          
    0          
    0          
4235             $file =~ /\.png$/i ? 'png' :
4236             $file =~ /\.gif$/i ? 'gif' :
4237             $file =~ /\.tiff?$/i ? 'tiff' :
4238             $file =~ /\.svg?$/i ? 'svg' :
4239             $file =~ /\.p[bgpn]m$/i ? 'pnm' : '');
4240             # GD images are created on-the-fly and don't have files
4241             }
4242              
4243 3 100       21 if ($format eq 'jpeg') {
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
4244 1         5 return $self->image_jpeg($file, %opts);
4245             } elsif ($format eq 'png') {
4246 1         7 return $self->image_png($file, %opts);
4247             } elsif ($format eq 'gif') {
4248 1         4 return $self->image_gif($file, %opts);
4249             } elsif ($format eq 'tiff') {
4250 0         0 return $self->image_tiff($file, %opts);
4251             } elsif ($format eq 'svg') {
4252 0         0 return $self->image_svg($file, %opts);
4253             } elsif ($format eq 'pnm') {
4254 0         0 return $self->image_pnm($file, %opts);
4255             } elsif ($format) {
4256 0         0 croak "Unrecognized image format: $format";
4257             } elsif (ref($file)) {
4258 0         0 croak "Unspecified image format";
4259             } elsif ($file =~ /(\..*)$/) {
4260 0         0 croak "Unrecognized image extension: $1";
4261             } else {
4262 0         0 croak "Unrecognized image: $file";
4263             }
4264             }
4265              
4266             # if passed a filehandle, attempt to read the format header to determine type
4267             sub _detect_image_format {
4268 3     3   6 my $fh = shift();
4269 3 50       12 if (ref($fh) ne 'SCALAR') {
4270 3         35 $fh->seek(0, 0);
4271 3         43 binmode $fh, ':raw';
4272             }
4273              
4274 3         10 my ($test, $bytes_read);
4275 3 50       12 if (ref($fh) eq 'SCALAR') {
4276 0         0 $test = substr($$fh, 0, 8);
4277 0         0 $bytes_read = length($test);
4278             } else {
4279 3         23 $bytes_read = $fh->read($test, 8);
4280 3         96 $fh->seek(0, 0);
4281             }
4282 3 50 33     49 return unless $bytes_read and $bytes_read == 8;
4283              
4284 3 100       18 return 'gif' if $test =~ /^GIF\d\d[a-z]/;
4285 2 100       13 return 'jpeg' if $test =~ /^\xFF\xD8\xFF/;
4286 1 50       9 return 'png' if $test =~ /^\x89PNG\x0D\x0A\x1A\x0A/;
4287 0 0       0 return 'pnm' if $test =~ /^\s*P[1-6]/;
4288             # II4200 | MM0042 for TIFF
4289 0 0       0 return 'tiff' if $test =~ /^II\x2A\x00/;
4290 0 0       0 return 'tiff' if $test =~ /^MM\x00\x2A/;
4291              
4292             # read up to 512 bytes for possible SVG file, expect to find '<svg\s'
4293 0         0 $fh->seek(0, 0);
4294 0         0 $bytes_read = $fh->read($test, 512);
4295 0         0 $fh->seek(0, 0);
4296 0 0       0 return 'svg' if $test =~ /<svg\s/is;
4297              
4298             # GD images do not have files.
4299 0         0 return;
4300             }
4301              
4302             =head2 image_jpeg
4303              
4304             $jpeg = $pdf->image_jpeg($file, %opts)
4305              
4306             =over
4307              
4308             Imports and returns a new JPEG image object. C<$file> may be either a filename
4309             or a filehandle.
4310              
4311             See L<PDF::Builder::Resource::XObject::Image::JPEG> for additional information
4312             and C<examples/Content.pl> for some examples of placing an image on a page.
4313              
4314             =back
4315              
4316             =cut
4317              
4318             sub image_jpeg {
4319 3     3 1 25 my ($self, $file, %opts) = @_;
4320              
4321 3         1147 require PDF::Builder::Resource::XObject::Image::JPEG;
4322 3         42 my $obj = PDF::Builder::Resource::XObject::Image::JPEG->new($self->{'pdf'}, $file, %opts);
4323              
4324 2         11 $self->{'pdf'}->out_obj($self->{'pages'});
4325              
4326 2         25 return $obj;
4327             }
4328              
4329             =head2 image_tiff
4330              
4331             $tiff = $pdf->image_tiff($file, %opts)
4332              
4333             =over
4334              
4335             Imports and returns a new TIFF image object. C<$file> may be either a filename
4336             or a filehandle.
4337             For details, see L<PDF::Builder::Docs/TIFF Images>.
4338              
4339             See L<PDF::Builder::Resource::XObject::Image::TIFF> and
4340             L<PDF::Builder::Resource::XObject::Image::TIFF_GT> for additional information
4341             and C<examples/Content.pl>
4342             for some examples of placing an image on a page (JPEG, but the principle is
4343             the same).
4344             There is an optional TIFF library (TIFF_GT) described, that gives more
4345             capability than the default one.
4346             See the TIFF_GT documentation for further information on using this library,
4347             particularly when passing a I<filehandle> for the file.
4348              
4349             =back
4350              
4351             =cut
4352              
4353             sub image_tiff {
4354 4     4 1 115 my ($self, $file, %opts) = @_;
4355             # copy dashed name options to preferred undashed format
4356 4 50 33     29 if (defined $opts{'-nouseGT'} && !defined $opts{'nouseGT'}) { $opts{'nouseGT'} = delete($opts{'-nouseGT'}); }
  0         0  
4357 4 50 33     17 if (defined $opts{'-silent'} && !defined $opts{'silent'}) { $opts{'silent'} = delete($opts{'-silent'}); }
  0         0  
4358              
4359 4         9 my ($rc, $obj);
4360 4         16 $rc = $self->LA_GT();
4361 4 50       11 if ($rc) {
4362             # Graphics::TIFF available
4363 0 0 0     0 if (defined $opts{'nouseGT'} && $opts{'nouseGT'} == 1) {
4364 0         0 $rc = -1; # don't use it
4365             }
4366             }
4367 4 50       14 if ($rc == 1) {
4368             # Graphics::TIFF (_GT suffix) available and to be used
4369 0         0 require PDF::Builder::Resource::XObject::Image::TIFF_GT;
4370 0         0 $obj = PDF::Builder::Resource::XObject::Image::TIFF_GT->new($self->{'pdf'}, $file, %opts);
4371 0         0 $self->{'pdf'}->out_obj($self->{'pages'});
4372             } else {
4373             # Graphics::TIFF not available, or is but is not to be used
4374 4         1532 require PDF::Builder::Resource::XObject::Image::TIFF;
4375 4         54 $obj = PDF::Builder::Resource::XObject::Image::TIFF->new($self->{'pdf'}, $file, %opts);
4376 3         22 $self->{'pdf'}->out_obj($self->{'pages'});
4377              
4378 3 100 66     23 if ($rc == 0 && $MSG_COUNT[0]++ == 0) {
4379             # give warning message once, unless silenced (silent) or
4380             # deliberately not using Graphics::TIFF (rc == -1)
4381 1 50 33     7 if (!defined $opts{'silent'} || $opts{'silent'} == 0) {
4382 0         0 print STDERR "Your system does not have Graphics::TIFF installed, ".
4383             "so some\nTIFF functions may not run correctly.\n";
4384             # even if silent only once, COUNT still incremented
4385             }
4386             }
4387             }
4388 3         13 $obj->{'usesGT'} = PDFNum($rc); # -1 available but unused
4389             # 0 not available
4390             # 1 available and used
4391             # $tiff->usesLib() to get number
4392              
4393 3         35 return $obj;
4394             }
4395              
4396             =head3 LA_GT
4397              
4398             $rc = $pdf->LA_GT()
4399              
4400             =over
4401              
4402             Returns 1 if the library name (package) Graphics::TIFF is installed, and
4403             0 otherwise. For this optional library, this call can be used to know if it
4404             is safe to use certain functions. For example:
4405              
4406             =back
4407              
4408             if ($pdf->LA_GT() {
4409             # is installed and usable
4410             } else {
4411             # not available. you will be running the old, pure PERL code
4412             }
4413              
4414             =cut
4415              
4416             # there doesn't seem to be a way to pass in a string (or bare) package name,
4417             # to make a generic check routine
4418             sub LA_GT {
4419 4     4 1 9 my ($self) = @_;
4420              
4421 4         13 my ($rc);
4422 4         9 $rc = eval {
4423 4         618 require Graphics::TIFF;
4424 0         0 1;
4425             };
4426 4 50       17 if (!defined $rc) { $rc = 0; } # else is 1
  4         10  
4427 4 50       13 if ($rc) {
4428             # installed, but not up to date?
4429 0 0       0 if (version->parse("v$Graphics::TIFF::VERSION")->numify() <
4430 0         0 version->parse("v$GrTFversion")->numify()) { $rc = 0; }
4431             }
4432              
4433 4         13 return $rc;
4434             }
4435              
4436             =head2 image_pnm
4437              
4438             $pnm = $pdf->image_pnm($file, %opts)
4439              
4440             =over
4441              
4442             Imports and returns a new PNM image object. C<$file> may be either a filename
4443             or a filehandle.
4444              
4445             See L<PDF::Builder::Resource::XObject::Image::PNM> for additional information
4446             and C<examples/Content.pl> for some examples of placing an image on a page
4447             (JPEG, but the principle is the same).
4448              
4449             =back
4450              
4451             =cut
4452              
4453             sub image_pnm {
4454 3     3 1 78 my ($self, $file, %opts) = @_;
4455              
4456 3   33     27 $opts{'compress'} //= $self->{'forcecompress'};
4457              
4458 3         639 require PDF::Builder::Resource::XObject::Image::PNM;
4459 3         26 my $obj = PDF::Builder::Resource::XObject::Image::PNM->new($self->{'pdf'}, $file, %opts);
4460              
4461 2         10 $self->{'pdf'}->out_obj($self->{'pages'});
4462              
4463 2         18 return $obj;
4464             }
4465              
4466             =head2 image_png
4467              
4468             $png = $pdf->image_png($file, %opts)
4469              
4470             =over
4471              
4472             Imports and returns a new PNG image object. C<$file> may be either
4473             a filename or a filehandle.
4474             For details, see L<PDF::Builder::Docs/PNG Images>.
4475              
4476             See L<PDF::Builder::Resource::XObject::Image::PNG> and
4477             L<PDF::Builder::Resource::XObject::Image::PNG_IPL> for additional information
4478             and C<examples/Content.pl>
4479             for some examples of placing an image on a page (JPEG, but the principle is
4480             the same).
4481              
4482             There is an optional PNG library (PNG_IPL) described, that gives more
4483             capability than the default one.
4484             See the PNG_IPL documentation for further information on using this library,
4485             particularly when passing a I<filehandle> for the file.
4486              
4487             =back
4488              
4489             =cut
4490              
4491             sub image_png {
4492 5     5 1 44 my ($self, $file, %opts) = @_;
4493             # copy dashed name options to preferred undashed format
4494 5 50 33     25 if (defined $opts{'-nouseIPL'} && !defined $opts{'nouseIPL'}) { $opts{'nouseIPL'} = delete($opts{'-nouseIPL'}); }
  0         0  
4495 5 50 33     19 if (defined $opts{'-silent'} && !defined $opts{'silent'}) { $opts{'silent'} = delete($opts{'-silent'}); }
  0         0  
4496              
4497 5         13 my ($rc, $obj);
4498 5         21 $rc = $self->LA_IPL();
4499 5 50       17 if ($rc) {
4500             # Image::PNG::Libpng available
4501 0 0 0     0 if (defined $opts{'nouseIPL'} && $opts{'nouseIPL'} == 1) {
4502 0         0 $rc = -1; # don't use it
4503             }
4504             }
4505 5 50       30 if ($rc == 1) {
4506             # Image::PNG::Libpng (_IPL suffix) available and to be used
4507 0         0 require PDF::Builder::Resource::XObject::Image::PNG_IPL;
4508 0         0 $obj = PDF::Builder::Resource::XObject::Image::PNG_IPL->new($self->{'pdf'}, $file, %opts);
4509 0         0 $self->{'pdf'}->out_obj($self->{'pages'});
4510             } else {
4511             # Image::PNG::Libpng not available, or is but is not to be used
4512 5         908 require PDF::Builder::Resource::XObject::Image::PNG;
4513 5         78 $obj = PDF::Builder::Resource::XObject::Image::PNG->new($self->{'pdf'}, $file, %opts);
4514 4         46 $self->{'pdf'}->out_obj($self->{'pages'});
4515              
4516 4 100 66     50 if ($rc == 0 && $MSG_COUNT[1]++ == 0) {
4517             # give warning message once, unless silenced (silent) or
4518             # deliberately not using Image::PNG::Libpng (rc == -1)
4519 1 50 33     7 if (!defined $opts{'silent'} || $opts{'silent'} == 0) {
4520 0         0 print STDERR "Your system does not have Image::PNG::Libpng installed, ".
4521             "so some\nPNG functions may not run correctly.\n";
4522             # even if silent only once, COUNT still incremented
4523             }
4524             }
4525             }
4526 4         24 $obj->{'usesIPL'} = PDFNum($rc); # -1 available but unused
4527             # 0 not available
4528             # 1 available and used
4529             # $png->usesLib() to get number
4530 4         91 return $obj;
4531             }
4532              
4533             =head3 LA_IPL
4534              
4535             $rc = $pdf->LA_IPL()
4536              
4537             =over
4538              
4539             Returns 1 if the library name (package) Image::PNG::Libpng is installed, and
4540             0 otherwise. For this optional library, this call can be used to know if it
4541             is safe to use certain functions. For example:
4542              
4543             =back
4544              
4545             if ($pdf->LA_IPL() {
4546             # is installed and usable
4547             } else {
4548             # not available. don't use 16bps or interlaced PNG image files
4549             }
4550              
4551             =cut
4552              
4553             # there doesn't seem to be a way to pass in a string (or bare) package name,
4554             # to make a generic check routine
4555             sub LA_IPL {
4556 5     5 1 15 my ($self) = @_;
4557              
4558 5         8 my ($rc);
4559 5         10 $rc = eval {
4560 5         879 require Image::PNG::Libpng;
4561 0         0 1;
4562             };
4563 5 50       25 if (!defined $rc) { $rc = 0; } # else is 1
  5         11  
4564 5 50       14 if ($rc) {
4565             # installed, but not up to date?
4566 0 0       0 if (version->parse("v$Image::PNG::Libpng::VERSION")->numify() <
4567 0         0 version->parse("v$LpngVersion")->numify()) { $rc = 0; }
4568             }
4569              
4570 5         15 return $rc;
4571             }
4572              
4573             =head2 image_gif
4574              
4575             $gif = $pdf->image_gif($file, %opts)
4576              
4577             =over
4578              
4579             Imports and returns a new GIF image object. C<$file> may be either a filename
4580             or a filehandle.
4581              
4582             See L<PDF::Builder::Resource::XObject::Image::GIF> for additional information
4583             and C<examples/Content.pl> for some examples of placing an image on a page
4584             (JPEG, but the principle is the same).
4585              
4586             =back
4587              
4588             =cut
4589              
4590             sub image_gif {
4591 3     3 1 13 my ($self, $file, %opts) = @_;
4592              
4593 3         572 require PDF::Builder::Resource::XObject::Image::GIF;
4594 3         21 my $obj = PDF::Builder::Resource::XObject::Image::GIF->new($self->{'pdf'}, $file);
4595 2         9 $self->{'pdf'}->out_obj($self->{'pages'});
4596              
4597 2         33 return $obj;
4598             }
4599              
4600             =head2 image_svg
4601              
4602             $pnm = $pdf->image_svg($file, %opts)
4603              
4604             =over
4605              
4606             Imports and returns a new SVG image object. C<$file> may be a filename, a
4607             string, or a filehandle.
4608              
4609             See L<PDF::Builder::Resource::XObject::Image::SVG> for additional information
4610             and C<examples/Content.pl> for some examples of placing an image on a page
4611             (JPEG, but the principle is the same). Note that C<object()> is preferably
4612             used rather than C<image()>. If C<image> determines that the image object is
4613             a processed SVG array, it simply passes it on to C<object>.
4614              
4615             B<CAUTIONS:>
4616             1. If using C<image()>, the final two (optional) parameters are I<not> width
4617             and height, but instead the horizontal scale and vertical scale.
4618             2. Results are unpredictable if allowing C<x> and C<y> positions to default
4619             to I<Lower Left> corner at C<(0,0)>, due to different scaling. It is best to
4620             explicitly give the C<x> and C<y> positions.
4621             3. Be aware that due to different scaling, some resulting images may be much
4622             larger than expected. Account for this when setting any C<scale> factor.
4623              
4624             =back
4625              
4626             =cut
4627              
4628             sub image_svg {
4629 1     1 1 10 my ($self, $file, %opts) = @_;
4630              
4631 1         1 my $rc;
4632 1         1 $rc = eval {
4633 1         69 require SVGPDF;
4634 0         0 1;
4635             };
4636 1 50       3 if (!defined $rc) { $rc = 0; } # else is 1
  1         2  
4637 1 50       2 if ($rc) {
4638             # installed, but not up to date?
4639 0 0       0 if (version->parse("v$SVGPDF::VERSION")->numify() <
4640 0         0 version->parse("v$SVGPDFver")->numify()) { $rc = 0; }
4641             }
4642 1 50       2 if (!$rc) {
4643 1         326 carp "SVGPDF not available, so SVG image can not be processed";
4644 1         23 return [];
4645             }
4646            
4647 0         0 require PDF::Builder::Resource::XObject::Image::SVG;
4648 0         0 my $obj = PDF::Builder::Resource::XObject::Image::SVG->new($self, $file, %opts);
4649              
4650 0 0 0     0 if (defined $opts{'compress'} && $opts{'compress'} == 0) {
4651             # suppress compression of stream
4652 0         0 my $o = $obj->[0]->{'xo'};
4653 0         0 delete $o->{'Filter'};
4654 0         0 delete $o->{'-docompress'};
4655             }
4656              
4657 0         0 $self->{'pdf'}->out_obj($self->{'pages'});
4658              
4659 0         0 return $obj;
4660             }
4661              
4662             =head3 LA_SVG
4663              
4664             $rc = $pdf->LA_SVG()
4665              
4666             =over
4667              
4668             Returns 1 if the library name (package) SVGPDF is installed, and
4669             0 otherwise. For this optional library, this call can be used to know if it
4670             is safe to use certain functions. For example:
4671              
4672             =back
4673              
4674             if ($pdf->LA_SVG() {
4675             # is installed and usable
4676             } else {
4677             # not available. can't use image_svg or any other SVG function
4678             }
4679              
4680             =cut
4681              
4682             # there doesn't seem to be a way to pass in a string (or bare) package name,
4683             # to make a generic check routine
4684             sub LA_SVG {
4685 1     1 1 7 my ($self) = @_;
4686              
4687 1         2 my ($rc);
4688 1         1 $rc = eval {
4689 1         605 require SVGPDF;
4690 0         0 1;
4691             };
4692 1 50       5 if (!defined $rc) { $rc = 0; } # else is 1
  1         1  
4693 1 50       2 if ($rc) {
4694             # installed, but not up to date?
4695 0 0       0 if (version->parse("v$SVGPDF::VERSION")->numify() <
4696 0         0 version->parse("v$SVGPDFver")->numify()) { $rc = 0; }
4697             }
4698              
4699 1         4 return $rc;
4700             }
4701              
4702             =head2 image_gd
4703              
4704             $gdf = $pdf->image_gd($gd_object, %opts)
4705              
4706             =over
4707              
4708             Imports and returns a new image object from Image::GD.
4709              
4710             See L<PDF::Builder::Resource::XObject::Image::GD> for additional information
4711             and C<examples/Content.pl> for some examples of placing an image on a page
4712             (JPEG, but the principle is the same).
4713              
4714             =back
4715              
4716             =cut
4717              
4718             sub image_gd {
4719 0     0 1 0 my ($self, $gd, %opts) = @_;
4720              
4721 0         0 require PDF::Builder::Resource::XObject::Image::GD;
4722 0         0 my $obj = PDF::Builder::Resource::XObject::Image::GD->new($self->{'pdf'}, $gd, %opts);
4723 0         0 $self->{'pdf'}->out_obj($self->{'pages'});
4724              
4725 0         0 return $obj;
4726             }
4727              
4728             =head1 COLORSPACE METHODS
4729              
4730             =head2 colorspace
4731              
4732             $colorspace = $pdf->colorspace($type, @arguments)
4733              
4734             =over
4735              
4736             Colorspaces can be added to a PDF to either specifically control the output
4737             color on a particular device (spot colors, device colors) or to save space by
4738             limiting the available colors to a defined color palette (web-safe palette, ACT
4739             file).
4740              
4741             Once added to the PDF, they can be used in place of regular hex codes or named
4742             colors:
4743              
4744             =back
4745              
4746             my $pdf = PDF::Builder->new();
4747             my $page = $pdf->page();
4748             my $content = $page->graphics();
4749              
4750             # Add colorspaces for a spot color and the web-safe color palette
4751             my $spot = $pdf->colorspace('spot', 'PANTONE Red 032 C', '#EF3340');
4752             my $web = $pdf->colorspace('web');
4753              
4754             # Fill using the spot color with 100% coverage
4755             $content->fill_color($spot, 1.0);
4756              
4757             # Stroke using the first color of the web-safe palette
4758             $content->stroke_color($web, 0);
4759              
4760             # Add a rectangle to the page
4761             $content->rectangle(100, 100, 200, 200);
4762             $content->paint();
4763              
4764             $pdf->save('sample.pdf');
4765              
4766             =over
4767              
4768             The following types of colorspaces are supported
4769              
4770             =back
4771              
4772             =over
4773              
4774             =item spot
4775              
4776             Spot colors are used to instruct a device (usually a printer) to use or emulate
4777             a particular ink color (C<$tint>) for parts of the document. An C<$alt_color>
4778             is provided for devices (e.g. PDF viewers) that don't know how to produce the
4779             named color. It can either be an approximation of the color in RGB, CMYK, or
4780             HSV formats, or a wildly different color (e.g. 100% magenta, C<%0F00>) to make
4781             it clear if the spot color isn't being used as expected.
4782              
4783             =back
4784              
4785             my $spot = $pdf->colorspace('spot', $tint, $alt_color);
4786              
4787             =over
4788              
4789             =item web
4790              
4791             The web-safe color palette is a historical collection of colors that was used
4792             when many display devices only supported 256 colors.
4793              
4794             =back
4795              
4796             my $web = $pdf->colorspace('web');
4797              
4798             =over
4799              
4800             =item act
4801              
4802             An Adobe Color Table (ACT) file provides a custom palette of colors that can be
4803             referenced by PDF graphics and text drawing commands.
4804              
4805             =back
4806              
4807             my $act = $pdf->colorspace('act', $filename);
4808              
4809             =over
4810              
4811             =item device
4812              
4813             A device-specific colorspace allows for precise color output on a given device
4814             (typically a printing press), bypassing the normal color interpretation
4815             performed by raster image processors (RIPs).
4816              
4817             =back
4818              
4819             my $devicen = $pdf->colorspace('device', @colorspaces);
4820              
4821             =over
4822              
4823             Device colorspaces are also needed if you want to blend spot colors:
4824              
4825             =back
4826              
4827             my $pdf = PDF::Builder->new();
4828             my $page = $pdf->page();
4829             my $content = $page->graphics();
4830              
4831             # Create a two-color device colorspace
4832             my $yellow = $pdf->colorspace('spot', 'Yellow', '%00F0');
4833             my $spot = $pdf->colorspace('spot', 'PANTONE Red 032 C', '#EF3340');
4834             my $device = $pdf->colorspace('device', $yellow, $spot);
4835              
4836             # Fill using a blend of 25% yellow and 75% spot color
4837             $content->fill_color($device, 0.25, 0.75);
4838              
4839             # Stroke using 100% spot color
4840             $content->stroke_color($device, 0, 1);
4841              
4842             # Add a rectangle to the page
4843             $content->rectangle(100, 100, 200, 200);
4844             $content->paint();
4845              
4846             $pdf->save('sample.pdf');
4847              
4848             =cut
4849              
4850             sub colorspace {
4851 0     0 1 0 my $self = shift();
4852 0         0 my $type = shift();
4853              
4854 0 0       0 if ($type eq 'act') {
    0          
    0          
    0          
    0          
4855 0         0 my $file = shift();
4856 0         0 return $self->colorspace_act($file);
4857             } elsif ($type eq 'web') {
4858 0         0 return $self->colorspace_web();
4859             } elsif ($type eq 'hue') {
4860             # This type is undocumented until either a reference can be found for
4861             # this being a standard palette like the web color palette, or POD is
4862             # added to the Hue colorspace class that describes how to use it.
4863 0         0 return $self->colorspace_hue();
4864             } elsif ($type eq 'spot') {
4865 0         0 my $name = shift();
4866 0         0 my $alt_color = shift();
4867 0         0 return $self->colorspace_separation($name, $alt_color);
4868             } elsif ($type eq 'device') {
4869 0         0 my @colors = @_;
4870 0         0 return $self->colorspace_devicen(\@colors);
4871             } else {
4872 0         0 croak "Unrecognized or unsupported colorspace: $type";
4873             }
4874             }
4875              
4876             =head2 colorspace_act
4877              
4878             $cs = $pdf->colorspace_act($file)
4879              
4880             =over
4881              
4882             Returns a new colorspace object based on an Adobe Color Table file.
4883              
4884             See L<PDF::Builder::Resource::ColorSpace::Indexed::ACTFile> for a
4885             reference to the file format's specification.
4886              
4887             =back
4888              
4889             =cut
4890              
4891             sub colorspace_act {
4892 0     0 1 0 my ($self, $file) = @_;
4893              
4894 0         0 require PDF::Builder::Resource::ColorSpace::Indexed::ACTFile;
4895 0         0 return PDF::Builder::Resource::ColorSpace::Indexed::ACTFile->new($self->{'pdf'}, $file);
4896             }
4897              
4898             =head2 colorspace_web
4899              
4900             $cs = $pdf->colorspace_web()
4901              
4902             =over
4903              
4904             Returns a new colorspace-object based on the "web-safe" color palette.
4905              
4906             =back
4907              
4908             =cut
4909              
4910             sub colorspace_web {
4911 1     1 1 7 my ($self) = @_;
4912              
4913 1         525 require PDF::Builder::Resource::ColorSpace::Indexed::WebColor;
4914 1         20 return PDF::Builder::Resource::ColorSpace::Indexed::WebColor->new($self->{'pdf'});
4915             }
4916              
4917             =head2 colorspace_hue
4918              
4919             $cs = $pdf->colorspace_hue()
4920              
4921             =over
4922              
4923             Returns a new colorspace-object based on the hue color palette.
4924              
4925             See L<PDF::Builder::Resource::ColorSpace::Indexed::Hue> for an explanation.
4926              
4927             =back
4928              
4929             =cut
4930              
4931             sub colorspace_hue {
4932 0     0 1 0 my ($self) = @_;
4933              
4934 0         0 require PDF::Builder::Resource::ColorSpace::Indexed::Hue;
4935 0         0 return PDF::Builder::Resource::ColorSpace::Indexed::Hue->new($self->{'pdf'});
4936             }
4937              
4938             =head2 colorspace_separation
4939              
4940             $cs = $pdf->colorspace_separation($tint, $color)
4941              
4942             =over
4943              
4944             Returns a new separation colorspace object based on the parameters.
4945              
4946             I<$tint> can be any valid ink identifier, including but not limited
4947             to: 'Cyan', 'Magenta', 'Yellow', 'Black', 'Red', 'Green', 'Blue' or
4948             'Orange'.
4949              
4950             I<$color> must be a valid color specification limited to: '#rrggbb',
4951             '!hhssvv', '%ccmmyykk' or a "named color" (rgb).
4952              
4953             The colorspace model will automatically be chosen based on the
4954             specified color.
4955              
4956             =back
4957              
4958             =cut
4959              
4960             sub colorspace_separation {
4961 0     0 1 0 my ($self, $tint, @clr) = @_;
4962              
4963 0         0 require PDF::Builder::Resource::ColorSpace::Separation;
4964 0         0 return PDF::Builder::Resource::ColorSpace::Separation->new($self->{'pdf'},
4965             pdfkey(),
4966             $tint,
4967             @clr);
4968             }
4969              
4970             =head2 colorspace_devicen
4971              
4972             $cs = $pdf->colorspace_devicen(\@tintCSx, $samples)
4973              
4974             $cs = $pdf->colorspace_devicen(\@tintCSx)
4975              
4976             =over
4977              
4978             Returns a new DeviceN colorspace object based on the parameters.
4979              
4980             B<Example:>
4981              
4982             =back
4983              
4984             $cy = $pdf->colorspace_separation('Cyan', '%f000');
4985             $ma = $pdf->colorspace_separation('Magenta', '%0f00');
4986             $ye = $pdf->colorspace_separation('Yellow', '%00f0');
4987             $bk = $pdf->colorspace_separation('Black', '%000f');
4988              
4989             $pms023 = $pdf->colorspace_separation('PANTONE 032CV', '%0ff0');
4990              
4991             $dncs = $pdf->colorspace_devicen( [ $cy,$ma,$ye,$bk, $pms023 ] );
4992              
4993             =over
4994              
4995             The colorspace model will automatically be chosen based on the first
4996             colorspace specified.
4997              
4998             =back
4999              
5000             =cut
5001              
5002             sub colorspace_devicen {
5003 0     0 1 0 my ($self, $clrs, $samples) = @_;
5004 0   0     0 $samples ||= 2;
5005              
5006 0         0 require PDF::Builder::Resource::ColorSpace::DeviceN;
5007 0         0 return PDF::Builder::Resource::ColorSpace::DeviceN->new($self->{'pdf'},
5008             pdfkey(),
5009             $clrs,
5010             $samples);
5011             }
5012              
5013             =head1 BARCODE METHODS
5014              
5015             These are glue routines to the actual barcode rendering routines found
5016             elsewhere.
5017              
5018             =head2 xo_* Bar Code routines
5019              
5020             $bc = $pdf->xo_codabar(%opts)
5021              
5022             $bc = $pdf->xo_code128(%opts)
5023              
5024             $bc = $pdf->xo_2of5int(%opts)
5025              
5026             $bc = $pdf->xo_3of9(%opts)
5027              
5028             $bc = $pdf->xo_ean13(%opts)
5029              
5030             =over
5031              
5032             Creates the specified barcode object as a form XObject.
5033              
5034             =back
5035              
5036             =cut
5037              
5038             # TBD PDF::API2 now has a convenience function to handle all the barcodes,
5039             # but still keeps all the existing barcodes
5040             #
5041             # TBD consider moving these to a BarCodes subdirectory, as the number of bar
5042             # code routines increases
5043              
5044             sub xo_code128 {
5045 1     1 0 714 my ($self, @opts) = @_;
5046              
5047 1         828 require PDF::Builder::Resource::XObject::Form::BarCode::code128;
5048 1         10 my $obj = PDF::Builder::Resource::XObject::Form::BarCode::code128->new($self->{'pdf'}, @opts);
5049 1         9 $self->{'pdf'}->out_obj($self->{'pages'});
5050              
5051 1         5 return $obj;
5052             }
5053              
5054             sub xo_codabar {
5055 1     1 0 27 my ($self, @opts) = @_;
5056              
5057 1         828 require PDF::Builder::Resource::XObject::Form::BarCode::codabar;
5058 1         15 my $obj = PDF::Builder::Resource::XObject::Form::BarCode::codabar->new($self->{'pdf'}, @opts);
5059 1         8 $self->{'pdf'}->out_obj($self->{'pages'});
5060              
5061 1         4 return $obj;
5062             }
5063              
5064             sub xo_2of5int {
5065 1     1 0 1282 my ($self, @opts) = @_;
5066              
5067 1         853 require PDF::Builder::Resource::XObject::Form::BarCode::int2of5;
5068 1         10 my $obj = PDF::Builder::Resource::XObject::Form::BarCode::int2of5->new($self->{'pdf'}, @opts);
5069 1         9 $self->{'pdf'}->out_obj($self->{'pages'});
5070              
5071 1         4 return $obj;
5072             }
5073              
5074             sub xo_3of9 {
5075 2     2 0 1142 my ($self, @opts) = @_;
5076              
5077 2         832 require PDF::Builder::Resource::XObject::Form::BarCode::code3of9;
5078 2         23 my $obj = PDF::Builder::Resource::XObject::Form::BarCode::code3of9->new($self->{'pdf'}, @opts);
5079 2         16 $self->{'pdf'}->out_obj($self->{'pages'});
5080              
5081 2         8 return $obj;
5082             }
5083              
5084             sub xo_ean13 {
5085 1     1 0 1163 my ($self, @opts) = @_;
5086              
5087 1         875 require PDF::Builder::Resource::XObject::Form::BarCode::ean13;
5088 1         8 my $obj = PDF::Builder::Resource::XObject::Form::BarCode::ean13->new($self->{'pdf'}, @opts);
5089 1         12 $self->{'pdf'}->out_obj($self->{'pages'});
5090              
5091 1         6 return $obj;
5092             }
5093              
5094             =head1 OTHER METHODS
5095              
5096             =head2 xo_form
5097              
5098             $xo = $pdf->xo_form()
5099              
5100             =over
5101              
5102             Returns a new form XObject.
5103              
5104             =back
5105              
5106             =cut
5107              
5108             sub xo_form {
5109 4     4 1 11 my $self = shift();
5110              
5111 4         72 my $obj = PDF::Builder::Resource::XObject::Form::Hybrid->new($self->{'pdf'});
5112 4         32 $self->{'pdf'}->out_obj($self->{'pages'});
5113              
5114 4         11 return $obj;
5115             }
5116              
5117             =head2 egstate
5118              
5119             $egs = $pdf->egstate()
5120              
5121             =over
5122              
5123             Returns a new extended graphics state object, as described
5124             in L<PDF::Builder::Resource::ExtGState>.
5125              
5126             =back
5127              
5128             =cut
5129              
5130             sub egstate {
5131 3     3 1 18 my $self = shift();
5132              
5133 3         21 my $obj = PDF::Builder::Resource::ExtGState->new($self->{'pdf'}, pdfkey());
5134 3         13 $self->{'pdf'}->out_obj($self->{'pages'});
5135              
5136 3         16 return $obj;
5137             }
5138              
5139             =head2 pattern
5140              
5141             $obj = $pdf->pattern(%opts)
5142              
5143             =over
5144              
5145             Returns a new pattern object.
5146              
5147             =back
5148              
5149             =cut
5150              
5151             sub pattern {
5152 0     0 1 0 my ($self, %opts) = @_;
5153              
5154 0         0 my $obj = PDF::Builder::Resource::Pattern->new($self->{'pdf'}, undef, %opts);
5155 0         0 $self->{'pdf'}->out_obj($self->{'pages'});
5156              
5157 0         0 return $obj;
5158             }
5159              
5160             =head2 shading
5161              
5162             $obj = $pdf->shading(%opts)
5163              
5164             =over
5165              
5166             Returns a new shading object.
5167              
5168             =back
5169              
5170             =cut
5171              
5172             sub shading {
5173 0     0 1 0 my ($self, %opts) = @_;
5174              
5175 0         0 my $obj = PDF::Builder::Resource::Shading->new($self->{'pdf'}, undef, %opts);
5176 0         0 $self->{'pdf'}->out_obj($self->{'pages'});
5177              
5178 0         0 return $obj;
5179             }
5180              
5181             =head2 named_destination
5182              
5183             $ndest = $pdf->named_destination($cat, $name, $obj)
5184              
5185             =over
5186              
5187             Returns a new named destination object. C<$cat> is the category,
5188             and is normally the string C<'Dests'> (it's a PDF keyword). The C<$name> is
5189             the B<unique> (within an entire PDF document) name, such as "foo" in the
5190             example below.
5191              
5192             See L<PDF::Builder::NamedDestination> for more information.
5193              
5194             B<Example:>
5195              
5196             =back
5197              
5198             my $dest = PDF::Builder::NamedDestination->new($pdf);
5199             #$dest->goto($page, 'xyz' => [undef, undef, undef]); old style
5200             $dest->goto($page, 'xyz', (undef, undef, undef));
5201             $pdf->named_destination('Dests', 'foo', $dest);
5202              
5203             =cut
5204              
5205             sub named_destination {
5206 1     1 1 10 my ($self, $cat, $name, $obj) = @_;
5207 1         3 my $root = $self->{'catalog'};
5208              
5209 1   33     56 $root->{'Names'} ||= PDFDict();
5210 1   33     10 $root->{'Names'}->{$cat} ||= PDFDict();
5211 1   50     7 $root->{'Names'}->{$cat}->{'-vals'} ||= {};
5212 1   33     7 $root->{'Names'}->{$cat}->{'Limits'} ||= PDFArray();
5213 1   33     16 $root->{'Names'}->{$cat}->{'Names'} ||= PDFArray();
5214              
5215 1 50       4 unless (defined $obj) {
5216 0         0 $obj = PDF::Builder::NamedDestination->new($self->{'pdf'});
5217             }
5218 1         30 $root->{'Names'}->{$cat}->{'-vals'}->{$name} = $obj;
5219              
5220 1         3 my @names = sort {$a cmp $b} keys %{$root->{'Names'}->{$cat}->{'-vals'}};
  0         0  
  1         7  
5221              
5222 1         5 $root->{'Names'}->{$cat}->{'Limits'}->{' val'}->[0] = PDFString($names[0], 'n');
5223 1         3 $root->{'Names'}->{$cat}->{'Limits'}->{' val'}->[1] = PDFString($names[-1], 'n');
5224              
5225 1         4 @{$root->{'Names'}->{$cat}->{'Names'}->{' val'}} = ();
  1         6  
5226              
5227 1         4 foreach my $k (@names) {
5228 1         22 push @{$root->{'Names'}->{$cat}->{'Names'}->{' val'}},
5229             ( PDFString($k, 'n'),
5230 1         4 $root->{'Names'}->{$cat}->{'-vals'}->{$k}
5231             );
5232             }
5233              
5234 1         6 return $obj;
5235             } # end of named_destination()
5236              
5237             =head2 init_state()
5238              
5239             Initialize 'state' variable that carries information across multiple
5240             document passes for C<column()> call.
5241             See L<PDF::Builder::Content::Column_docs> for documentation.
5242            
5243             =cut
5244              
5245             # initialize state holder hash
5246             sub init_state {
5247 0     0 1 0 my ($self, $lists) = @_;
5248              
5249 0         0 my %state = ();
5250 0         0 $state{'settings'} = {}; # hold settings between column() calls, TBD
5251             # remember: multiple xrefs may point to the same target xreft, so no
5252             # way to automatically point back to link source in xrefs!
5253             # self-contained links (Named Destination, physical page) will
5254             # have a '#' or '##' target id and not match an xreft list entry
5255             # self-contained links have xrefs entry with or without a
5256             # filepath (for external or internal links, respectively)
5257 0         0 $state{'sindex'} = 0; # current size/next write of xrefs array
5258 0         0 $state{'xrefs'} = []; # source (<_ref>) link data
5259             # each array element is an anonymous hash containing:
5260             #
5261             # {'id'} target's id ('#ND' or '##ppn if self-contained link)
5262             # {'tfn'} filepath (final position and name) for external links
5263             # give for all links, even if internal, to permit external linking
5264             # {'tppn'} physical page number of target
5265             # {'sppn'} physical page number of source
5266             # {'fit'} fit information ('' if not given)
5267             # {'tfpn'} formatted page number of target
5268             # {'page_numbers'} TBD in case want to override global default
5269             # {'other_pg'} # other page text ("on page N", "on facing page", etc.)
5270             # if $page_numbers > 0 (TBD)
5271             # {'prev_other_pg'}* see if 'other_pg' changed
5272             # {'tx'} and {'ty'} location on page of target
5273             # {'title'} title= or natural text for link
5274             # if none found yet, '[no title text]' is used
5275             # for Index, user-defined term
5276             # {'tag'} # tag (type) that produced this target
5277             # useful for formatting TOC, etc
5278             # {'click'} [] of click area(s) for this _ref, each [sppn, [x,y, x,y]]
5279             #
5280             # * = for discovering changes to visible text, requiring another pass
5281 0         0 $state{'xreft'} = (); # target (<_reft> et al.) link data
5282             #
5283             # {$listname} e.g., '_reft', 'TOC', etc.
5284             # {'id'} target id=
5285             # {'tfn'} filepath (final position and name) for external links
5286             # give for all links, even if internal, to permit external linking
5287             # {'tppn'}* physical page number of target
5288             # {'sppn'}* physical page number of source
5289             # {'tfpn'}* formatted page number of target
5290             # used if $page_number > 0 (TBD)
5291             # {'tx'}* and {'ty'}* location on page of target
5292             # {'title'} title= or natural text for link
5293             # if none found yet, '[no title text]' is used
5294             # copied to xrefs entry if it does not have its own title
5295             # {'tag'} tag (type) that produced this entry
5296             # useful for formatting TOC, etc.
5297             #
5298             # * liable to change as text shifts around. copy to xrefs. if visible
5299             # change (change to title and/or formatted page number) -- will need
5300             # another pass (see 'changed_target')
5301 0         0 $state{'changed_target'} = {}; # list of tgtids whose data changed
5302             # enough (AFTER the last text output by xrefs) to change the printed
5303             # content and thus require another pass
5304 0         0 $state{'tag_lists'} = {}; # user-defined lists of tags, e.g., TOC for
5305             # {$list_name} = [ tag1, tag2, ... ]
5306             # to define what tags (with ids) get listed as targets.
5307             # _reft is predefined with '_reft' for use as <_ref> tgtids.
5308             # add TOC for table of contents, Index for index, LoT for List of
5309             # Tables, etc.
5310 0         0 $state{'nameddest'} = {}; # <_nameddest> defs save up for final output
5311             # these are ND's defined in THIS document, NOT targets in links
5312             # {'name'} name of Named Destination
5313             # {'ppn'} physical page number
5314             # {'x'} x location in page
5315             # {'y'} y location in page
5316             # {'fit'} fit (location, parms) information
5317              
5318             # predefined (started) lists
5319 0         0 $state{'tag_lists'}{'_reft'} = [ '_reft' ];
5320              
5321             # extend _reft and add additional tags lists per user input
5322 0         0 foreach my $listname (keys %{$lists}) {
  0         0  
5323             # add the anonymous list of tag names to an existing list ($listname
5324             # element) by this key, or create if none already exists.
5325             # a given tag may appear in multiple lists
5326 0         0 my @list; # one user-given tag list
5327 0 0       0 if (exists $state{'tag_lists'}{$listname}) {
5328 0         0 @list = @{ $state{'tag_lists'}{$listname} };
  0         0  
5329 0         0 push @list, @{ $lists->{$listname} };
  0         0  
5330             } else {
5331             # create new list
5332 0         0 $state{'tag_lists'}{$listname} = []; # empty, so far
5333 0         0 @list = @{ $lists->{$listname} };
  0         0  
5334             }
5335             # cull any duplicates from the list, such as user misunderstanding and
5336             # explicitly specifying '_reft' in the _reft tag list
5337 0         0 for (my $ti=0; $ti<scalar(@list)-1; $ti++) {
5338 0         0 for (my $tj=$ti+1; $tj<@list; $tj++) {
5339 0 0       0 if ($list[$ti] eq $list[$tj]) {
5340             # duplicate found, delete second one
5341 0         0 splice(@list, $tj--, 1);
5342             }
5343             }
5344             }
5345             # fill or replace existing entry
5346 0         0 $state{'tag_lists'}{$listname} = \@list;
5347              
5348             # create xreft target list heads
5349 0         0 $state{'xreft'}->{$listname} = {}; # always will have _reft list
5350             }
5351              
5352 0         0 return %state;
5353             }
5354              
5355             =head2 pass_start_state()
5356              
5357             Update 'state' variable that carries information across multiple
5358             document passes for C<column()> call, at the beginning of each pass.
5359             See L<PDF::Builder::Content::Column_docs> for documentation.
5360              
5361             =cut
5362              
5363             sub pass_start_state {
5364 0     0 1 0 my ($self, $pass_no, $max_passes, $state) = @_;
5365             # $state = ref to %state structure
5366              
5367             # TBD this may disappear, if clear changed_target flag upon text output
5368             # if ($pass_no > 1) {
5369             # $state->{'changed_target'} = {}; # clear all
5370             #
5371             # # changed visible text (fpn), reset "previous" version
5372             # for (my $sindex=0; $sindex<scalar(@{$state->{'xrefs'}}); $sindex++) {
5373             # $state->{'prev_other_pg'} = $state->{'other_pg'}; # not always used
5374             # }
5375             # }
5376              
5377 0         0 $state->{'sindex'} = 0; # position to write on first pass, update > 1
5378              
5379              
5380 0         0 return;
5381             }
5382              
5383             # ==================================================
5384             # input: level of checking, PDF as a string
5385             # level: 0 just return with any version override
5386             # 1 return version override, and errors
5387             # 2 return version override, and errors and warnings
5388             # 3 return version override, plus errors, warnings, notes
5389             # 4 like (3), plus dump analysis data
5390             # 5 like (4), plus dump $self (PDF) contents
5391             # returns any /Version value found in Catalog, last one if multiple ones found,
5392             # else undefined
5393              
5394             sub IntegrityCheck {
5395 18     18 0 64 my ($self, $level, $string) = @_;
5396              
5397 18         37 my $level_nodiag = 0;
5398 18         34 my $level_error = 1;
5399 18         61 my $level_warning = 2;
5400 18         39 my $level_note = 3;
5401 18         58 my $level_dump = 4;
5402 18         33 my $level_dumpself = 5;
5403              
5404 18         46 my $IC = "PDF Integrity Check:";
5405              
5406             #print "$IC level $level\n" if $level >= $level_error;
5407 18         40 my $Version = undef;
5408 18         45 my ($Info, $Root, $str, $pos, $Parent, @Kids, @others);
5409              
5410 18         57 my $idx_defined = 0; # has this object been explicitly defined?
5411 18         38 my $idx_refcount = 1; # count of all pointing to this obj except as Kid
5412 18         36 my $idx_par_clmd = 2; # other object claiming this object as Kid
5413 18         54 my $idx_parent = 3; # this object's /Parent entry
5414 18         40 my $idx_kid_cnt = 4; # size of kid_list
5415 18         32 my $idx_kid_list = 5; # this object's /Kids list
5416             # intialize each element to [ 0 0 -1 -1 -1 [] ]
5417              
5418 18 50       69 return $Version if !length($string); # nothing to examine?
5419             # basic PDF version on line 1
5420 18 50       157 if ($string =~ m/^%PDF-([\d.]+)/) {
5421 18         102 $Version = $1;
5422             }
5423             # even if $level 0, still want to get any higher /Version
5424             # build analysis data and issue errors/warnings at appropriate $level
5425 18         199 my @major = split /%%EOF/, $string; # typically [0] entire PDF [1] empty
5426 18         43 my %objList;
5427 18         40 my $update = -1;
5428 18         50 foreach (@major) {
5429             # update section number 0, 1, 2... with %%EOF in-between
5430 38         70 $update++;
5431 38 50       100 next if !length($_);
5432              
5433             # split on "endobj"
5434 38         209 my @rawObjects = split /endobj/, $_;
5435             # each element contains an object plus leading stuff, not incl endobj
5436            
5437 38         94 foreach my $rawObject (@rawObjects) {
5438 171 50       407 next if !length($rawObject);
5439              
5440             # remove bulky and unwanted stream...endstream
5441 171 100       584 if ($rawObject =~ m/^(.*)stream\s.*\sendstream(.*)$/s) {
5442 23         113 $rawObject = $1.$2;
5443             }
5444            
5445             # trim off anything before obj clause. endobj already gone.
5446 171 100 66     1165 if ($rawObject =~ m/^(.*?)\s?(\d+) (\d+) obj\s(.*)$/s ||
5447             $rawObject =~ m/^(.*?)\s?(\d+) (\d+) obj(.*)$/s) {
5448 133         537 $rawObject = $4;
5449              
5450             # found an obj, full string is $rawObject. parse into
5451             # selected fields, build $objList{key} entry.
5452 133         433 my $objKey = "$2.$3"; # e.g., 4 0 obj -> 4.0
5453             # if this is a replacement object in an update, clear Parent
5454             # and Kids
5455 133 100 100     531 if (defined $objList{$objKey} && $update > 0) {
5456 9         21 $objList{$objKey}->[$idx_parent] = -1;
5457 9         18 $objList{$objKey}->[$idx_kid_cnt] = -1;
5458 9         24 $objList{$objKey}->[$idx_kid_list] = [];
5459             }
5460             # might have already created this object element as target
5461             # from another object
5462 133 100       354 if (!defined $objList{$objKey}) {
5463 49         333 $objList{$objKey} = [0, 0, -1, -1, -1, []];
5464             }
5465             # mark object as defined
5466 133         300 $objList{$objKey}->[$idx_defined] = 1;
5467              
5468             # found an object
5469             # looking for /Parent x y R
5470             # /Kids [ x y R ]
5471             # /Type = /Catalog -> /Version /x.y
5472             # for now, ignoring any /BaseVersion
5473             # all other x y R
5474             # remove from $rawObject as we find a match
5475              
5476             # /Parent x y R -> $Parent
5477 133 100       536 if ($rawObject =~ m#/Parent(\s+)(\d+)(\s+)(\d+)(\s+)R#) {
5478 27         96 $Parent = "$2.$4";
5479 27         144 $str = "/Parent$1$2$3$4$5R";
5480 27         62 $pos = index $rawObject, $str;
5481 27         69 substr($rawObject, $pos, length($str)) = '';
5482             # TBD realistically, do we need to check for >1 /Parent ?
5483             #if ($objList{$objKey}->[$idx_parent] == -1) {
5484             # first /Parent (should not be more)
5485 27         71 $objList{$objKey}->[$idx_parent] = $Parent;
5486             #} else {
5487             # print STDERR "$IC Additional Parent ($Parent) in object $objKey, already list ".
5488             # "$objList{$objKey}->[$idx_parent] as Parent.\n" if $level >= $level_error;
5489             #}
5490             }
5491              
5492             # /Kids [ x y R ] -> @Kids
5493             # should we check for multiple Kids arrays in one object (error)?
5494 133 100       494 if ($rawObject =~ m#/Kids(\s+)\[(.*)\]#) {
5495 20         102 $str = "/Kids$1\[$2\]";
5496 20         50 $pos = index $rawObject, $str;
5497 20         78 substr($rawObject, $pos, length($str)) = '';
5498              
5499 20         71 my $str2 = " $2"; # guarantee a leading \s
5500 20         64 @Kids = ();
5501 20         37 while (1) {
5502 42 100       210 if ($str2 =~ m#(\s+)(\d+)(\s+)(\d+)(\s+)R#) {
5503 22         113 $str = "$1$2$3$4$5R";
5504 22         84 push @Kids, "$2.$4";
5505 22         63 $pos = index $str2, $str;
5506 22         69 substr($str2, $pos, length($str)) = '';
5507             } else {
5508 20         43 last;
5509             }
5510             }
5511             # TBD: realistically, any need to check for >1 /Kids?
5512             #if (!scalar(@{$objList{$objKey}->[$idx_kid_list]})) {
5513             # first /Kids (should not be more)
5514 20         63 @{$objList{$objKey}->[$idx_kid_list]} = @Kids;
  20         111  
5515 20         64 $objList{$objKey}->[$idx_kid_cnt] = scalar(@Kids);
5516             #} else {
5517             # print STDERR "$IC Multiple Kids lists in object $objKey, already list ".
5518             # "@{$objList{$objKey}->[$idx_kid_list]} as Kids.\n" if $level >= $level_error;
5519             #}
5520             }
5521              
5522             # /Type /Catalog -> /Version /x.y -> $Version
5523             # both x and y are normally single digits, but allow room
5524             # just global $Version, assuming that each one physically
5525             # later overrides any earlier ones
5526 133 100       402 if ($rawObject =~ m#/Type(\s+)/Catalog#) {
5527 18         79 my $sp1 = $1;
5528 18 50       116 if ($rawObject =~ m#/Version /(\d+)\.(\d+)#) {
5529 0         0 $Version = "$1.$2";
5530 0         0 $str = "/Version$sp1/$Version";
5531 0         0 $pos = index $rawObject, $str;
5532 0         0 substr($rawObject, $pos, length($str)) = '';
5533             }
5534             }
5535              
5536             # if using cross-reference stream, will find /Root x y R
5537             # and /Info x y R entries in an object of /Type /Xref
5538             # it looks like last ones will win
5539 133 100 66     619 if ($rawObject =~ m#/Type(\s+)/XRef# ||
5540             $rawObject =~ m#/Type/XRef#) {
5541 3 50       18 if ($rawObject =~ m#/Root(\s+)(\d+)(\s+)(\d+)(\s+)R#) {
5542 3         13 $Root = "$2.$4";
5543 3         16 $str = "/Root$1$2$3$4$5R";
5544 3         7 $pos = index $rawObject, $str;
5545 3         10 substr($rawObject, $pos, length($str)) = '';
5546             }
5547 3 50       18 if ($rawObject =~ m#/Info(\s+)(\d+)(\s+)(\d+)(\s+)R#) {
5548 3         9 $Info = "$2.$4";
5549 3         13 $str = "/Info$1$2$3$4$5R";
5550 3         8 $pos = index $rawObject, $str;
5551 3         8 substr($rawObject, $pos, length($str)) = '';
5552             }
5553             }
5554              
5555             # all other x y R -> @others
5556 133         259 @others = ();
5557 133         201 while (1) {
5558 207 100       2385 if ($rawObject =~ m#(\d+)(\s+)(\d+)(\s+)R#) {
5559 74         282 $str = "$1$2$3$4R";
5560 74         261 push @others, "$1.$3";
5561 74         182 $pos = index $rawObject, $str;
5562 74         179 substr($rawObject, $pos, length($str)) = '';
5563             } else {
5564 133         229 last;
5565             }
5566             }
5567             # go through all other refs and create element if necessary,
5568             # then increment its refcnt array element
5569 133         315 foreach (@others) {
5570 74 100       1582 if (!defined $objList{$_}) {
5571 63         295 $objList{$_} = [0, 0, -1, -1, -1, []];
5572             }
5573 74         171 $objList{$_}->[$idx_refcount]++;
5574             }
5575 133         244 foreach (@Kids) {
5576 129 100       301 if (!defined $objList{$_}) {
5577 19         119 $objList{$_} = [0, 0, -1, -1, -1, []];
5578             }
5579 129         306 $objList{$_}->[$idx_refcount]++;
5580             }
5581              
5582             } else {
5583             # not an object, but could be other stuff of interest
5584             # looking for trailer -> /Root x y R & /Info x y R
5585 38 100       159 if ($rawObject =~ m/trailer/) {
5586 18 50       144 if ($rawObject =~ m#trailer(.*)/Info(\s+)(\d+)(\s+)(\d+)(\s+)R#s) {
5587 18         70 $Info = "$3.$5";
5588             }
5589 18 50       122 if ($rawObject =~ m#trailer(.*)/Root(\s+)(\d+)(\s+)(\d+)(\s+)R#s) {
5590 18         147 $Root = "$3.$5";
5591             }
5592             }
5593             }
5594             }
5595             }
5596              
5597             # increment Root and Info objects reference counts
5598             # they probably SHOULD already be defined (issue warning if not)
5599 18 50       63 if (!defined $Root) {
5600 0 0       0 print STDERR "$IC No Root object defined!\n" if $level >= $level_error;
5601             } else {
5602             # Look for expected Root object
5603 18 50       127 if (!defined $objList{$Root}) {
5604 0 0       0 if ($Version > 1.4) {
5605             # PDF 1.5 and up, Root could be hiding in an Object Stream
5606             # TBD: disassemble object stream(s) to expose all objects
5607 0 0       0 print STDERR "$IC Root object $Root not found, but this may be\n the result of putting it in an Object Stream.\n" if $level >= $level_warning;
5608             } else {
5609             # PDF 1.4 or below, definitely an error if no Root found
5610 0 0       0 print STDERR "$IC Root object $Root not found!\n" if $level >= $level_error;
5611             }
5612 0         0 $objList{$Root} = [1, 0, -1, -1, -1, []];
5613             }
5614 18         50 $objList{$Root}->[$idx_refcount]++;
5615             }
5616              
5617             # Info is optional
5618 18 50       88 if (!defined $Info) {
5619 0 0       0 print STDERR "$IC No Info object defined!\n" if $level >= $level_note;
5620             } else {
5621 18 50       78 if (!defined $objList{$Info}) {
5622 0         0 $objList{$Info} = [1, 0, -1, -1, -1, []];
5623 0 0       0 if ($Version > 1.4) {
5624             # PDF 1.5 and up, Info could be hiding in an Object Stream
5625             # TBD: disassemble object stream(s) to expose all objects
5626 0 0       0 print STDERR "$IC Info object $Root not found, but this may be\n the result of putting it in an Object Stream, or it may have been deleted.\n" if $level >= $level_warning;
5627             } else {
5628             # PDF 1.4 or below, definitely a warning if no Info found
5629 0 0       0 print STDERR "$IC Root object $Root not found!\n" if $level >= $level_warning;
5630             }
5631 0 0       0 print STDERR "$IC Info object $Info not found!\n" if $level >= $level_warning;
5632             # possibly in a deleted object (on free list)
5633             }
5634 18         51 $objList{$Info}->[$idx_refcount]++;
5635             }
5636              
5637             # revisit each element in objList
5638             # visit each Kid, their $idx_par_clmd should be -1 (set to this object)
5639             # (if not -1, is on multiple Kids lists)
5640             # their $idx_parent should be this object
5641             # they should have a Parent declared
5642             # any element with ref count of 0 and no Parent give warning unreachable
5643             # TBD: anything else to add to things to check?
5644 18         163 foreach my $thisObj (sort keys %objList) {
5645              
5646             # was an object actually defined for this entry?
5647             # missing Info and Root messages already given, so flag is 1 ("defined")
5648 131 100       349 if ($objList{$thisObj}->[$idx_defined] == 0) {
5649 2 50       14 if ($Version > 1.4) {
5650 2 50       8 print STDERR "$IC object $thisObj referenced, but no entry found\n (might be on the free list, or defined in an object stream).\n" if $level >= $level_note;
5651             } else {
5652 0 0       0 print STDERR "$IC object $thisObj referenced, but no entry found (might be on the free list).\n" if $level >= $level_warning;
5653             }
5654             # it's apparently OK if the missing object is on the free list --
5655             # it will just be ignored
5656             }
5657              
5658             # check any Kids
5659 131 100       305 if ($objList{$thisObj}[$idx_kid_cnt] > 0) {
5660             # this object has children (/Kids), so explore them one level deep
5661 17         115 for (my $kidObj=0; $kidObj<$objList{$thisObj}[$idx_kid_cnt]; $kidObj++) {
5662 20         83 my $child = $objList{$thisObj}[$idx_kid_list]->[$kidObj];
5663             # child's claimed parent should be -1, set to thisObj
5664 20 50       70 if ($objList{$child}[$idx_par_clmd] == -1) {
5665             # no one has claimed to be parent, so set to thisObj
5666 20         65 $objList{$child}[$idx_par_clmd] = $thisObj;
5667             } else {
5668             # someone else has already claimed to be parent
5669 0 0       0 print STDERR "$IC object $thisObj wants to claim object $child as its child, ".
5670             "but $objList{$child}[$idx_par_clmd] already has!\nPossibly $child ".
5671             "is on more than one /Kids list?\n" if $level >= $level_error;
5672             }
5673             # if no object defined for child, already flagged as missing
5674 20 50       72 if ($objList{$child}[$idx_defined] == 1) {
5675             # child should list thisObj as its Parent
5676 20 50       661 if ($objList{$child}[$idx_parent] == -1) {
    50          
5677 0 0       0 print STDERR "$IC object $thisObj claims $child as a child (/Kids), but ".
5678             "$child claims no Parent!\n" if $level >= $level_error;
5679 0         0 $objList{$child}[$idx_parent] = $thisObj;
5680             } elsif ($objList{$child}[$idx_parent] != $thisObj) {
5681 0 0       0 print STDERR "$IC object $thisObj claims $child as a child (/Kids), but ".
5682             "$child claims $objList{$child}[$idx_parent] as its parent!\n"
5683             if $level >= $level_error;
5684             }
5685             }
5686             }
5687             }
5688              
5689 131 100 100     520 if ($objList{$thisObj}[$idx_parent] == -1 &&
5690             $objList{$thisObj}[$idx_refcount] == 0) {
5691 8 50       24 print STDERR "$IC Warning: object $thisObj appears to be unreachable.\n" if $level >= $level_note;
5692             }
5693             }
5694              
5695 18 50       84 if ($level >= $level_dump) {
5696             # dump analysis data
5697 39     39   31619 use Data::Dumper;
  39         381194  
  39         6412  
5698 0         0 my $d = Data::Dumper->new([\%objList]);
5699 0         0 print "========= dump of $IC analysis data ===========\n";
5700 0         0 print $d->Dump();
5701             }
5702              
5703             # if have entire processed PDF in $self
5704 18 50       63 if ($level >= $level_dumpself) {
5705             # dump whole data
5706 39     39   457 use Data::Dumper;
  39         85  
  39         14394  
5707 0         0 my $d = Data::Dumper->new([$self]);
5708 0         0 print "========= dump of $IC PDF (self) data ===========\n";
5709 0         0 print $d->Dump();
5710             }
5711              
5712 18         240 return $Version;
5713             }
5714              
5715             1;
5716              
5717             __END__