File Coverage

blib/lib/PDF/Builder.pm
Criterion Covered Total %
statement 881 1450 60.7
branch 358 866 41.3
condition 130 387 33.5
subroutine 87 133 65.4
pod 88 103 85.4
total 1544 2939 52.5


line stmt bran cond sub pod time code
1             package PDF::Builder;
2              
3 38     38   2701783 use strict;
  38         454  
  38         1225  
4 38     38   222 use warnings;
  38         88  
  38         3294  
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.025'; # VERSION
9             our $LAST_UPDATE = '3.025'; # 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              
18 38     38   353 use Carp;
  38         92  
  38         2746  
19 38     38   23278 use Encode qw(:all);
  38         414013  
  38         10098  
20 38     38   18427 use English;
  38         135723  
  38         250  
21 38     38   32457 use FileHandle;
  38         375173  
  38         235  
22              
23 38     38   30661 use PDF::Builder::Basic::PDF::Utils;
  38         155  
  38         3550  
24 38     38   19782 use PDF::Builder::Util;
  38         153  
  38         5815  
25              
26 38     38   28099 use PDF::Builder::Basic::PDF::File;
  38         111  
  38         1595  
27 38     38   274 use PDF::Builder::Basic::PDF::Pages;
  38         75  
  38         845  
28 38     38   22342 use PDF::Builder::Page;
  38         153  
  38         1773  
29              
30 38     38   22745 use PDF::Builder::Resource::XObject::Form::Hybrid;
  38         129  
  38         1359  
31              
32 38     38   17718 use PDF::Builder::Resource::ExtGState;
  38         123  
  38         1318  
33 38     38   16610 use PDF::Builder::Resource::Pattern;
  38         109  
  38         1243  
34 38     38   16352 use PDF::Builder::Resource::Shading;
  38         125  
  38         1266  
35              
36 38     38   17172 use PDF::Builder::NamedDestination;
  38         120  
  38         1242  
37 38     38   23296 use PDF::Builder::FontManager;
  38         120  
  38         1757  
38              
39 38     38   317 use List::Util qw(max);
  38         103  
  38         3198  
40 38     38   273 use Scalar::Util qw(weaken);
  38         138  
  38         771632  
41              
42             # Note that every Linux distribution seems to put font files in a different
43             # place, and even Windows is consistent only for TTF/OTF font files.
44             my @font_path = __PACKAGE__->set_font_path(
45             '.', # could a font ever be a security risk?
46             '/usr/share/fonts',
47             '/usr/local/share/fonts',
48             '/usr/share/fonts/type1/gsfonts',
49             '/usr/share/X11/fonts/urw-fonts',
50             '/usr/share/fonts/dejavu-sans-fonts',
51             '/usr/share/fonts/truetype/ttf-dejavu',
52             '/usr/share/fonts/truetype/dejavu',
53             '/var/lib/defoma/gs.d/dirs/fonts',
54             '/Windows/Fonts',
55             '/WinNT/Fonts'
56             );
57              
58             our @MSG_COUNT = (0, # [0] Graphics::TIFF not installed
59             0, # [1] Image::PNG::Libpng not installed
60             0, # [2] TBD...
61             );
62             our $outVer = 1.4; # desired PDF version for output, bump up w/ warning on read or feature output
63             our $msgVer = 1; # 0=don't, 1=do issue message when PDF output version is bumped up
64             our $myself; # holds self->pdf
65             our $global_pdf; # holds self ($pdf)
66              
67             require PDF::Builder::FontManager;
68              
69             =head1 NAME
70              
71             PDF::Builder - Facilitates the creation and modification of PDF files
72              
73             =head1 SYNOPSIS
74              
75             use PDF::Builder;
76              
77             # Create a blank PDF file
78             $pdf = PDF::Builder->new();
79              
80             # Open an existing PDF file
81             $pdf = PDF::Builder->open('some.pdf');
82              
83             # Add a blank page
84             $page = $pdf->page();
85              
86             # Retrieve an existing page
87             $page = $pdf->open_page($page_number);
88              
89             # Set the page size
90             $page->size('Letter'); # or mediabox('Letter')
91              
92             # Add a built-in font to the PDF
93             $font = $pdf->font('Helvetica-Bold'); # or corefont('Helvetica-Bold')
94              
95             # Add an external TrueType (TTF) font to the PDF
96             $font = $pdf->font('/path/to/font.ttf'); # or ttfont() in this case
97              
98             # Add some text to the page
99             $text = $page->text();
100             $text->font($font, 20);
101             $text->position(200, 700); # or translate()
102             $text->text('Hello World!');
103              
104             # Save the PDF
105             $pdf->saveas('/path/to/new.pdf');
106              
107             =head1 SOME SPECIAL NOTES
108              
109             See the file README.md (in downloadable package and on CPAN) for a summary of
110             prerequisites and tools needed to install PDF::Builder, both mandatory and
111             optional.
112              
113             =head2 SOFTWARE DEVELOPMENT KIT
114              
115             There are four levels of involvement with PDF::Builder. Depending on what you
116             want to do, different kinds of installs are recommended.
117             See L for suggestions.
118              
119             =head2 OPTIONAL LIBRARIES
120              
121             PDF::Builder can make use of some optional libraries, which are not I
122             for a successful installation, but improve speed and capabilities. See
123             L for more information.
124              
125             =head2 STRINGS (CHARACTER TEXT)
126              
127             There are some things you should know about character encoding (for text),
128             before you dive in to coding. Please go to L and have a read.
129              
130             =head2 RENDERING ORDER
131              
132             Invoking "text" and "graphics" methods can lead to unexpected results (a
133             different ordering of output than intended). See L for more information.
134              
135             =head2 PDF VERSIONS SUPPORTED
136              
137             PDF::Builder is mostly PDF 1.4-compliant, but there I complications you
138             should be aware of. Please read L
139             for details.
140              
141             =head2 SUPPORTED PERL VERSIONS (BACKWARDS COMPATIBILITY GOALS)
142              
143             PDF::Builder intends to support all major Perl versions that were released in
144             the past six years, plus one, in order to continue working for the life of
145             most long-term-stable (LTS) server distributions.
146             See the L table
147             B x.xxxx0 "Major" release dates.
148              
149             For example, a version of PDF::Builder released on 2018-06-05 would support
150             the last major version of Perl released I 2012-06-05 (5.18), and
151             then one before that, which would be 5.16. Alternatively, the last major
152             version of Perl released I 2012-06-05 is 5.16.
153              
154             The intent is to avoid expending unnecessary effort in supporting very old
155             (obsolete) versions of Perl.
156              
157             =head3 Anticipated Support Cutoff Dates
158              
159             B hard and fast dates. In particular, we develop
160             on Strawberry Perl, which is currently stuck at release 5.32! We'll have to
161             see whether we can get around this problem in the summer of 2023, if Strawberry
162             hasn't yet gotten up to at least 5.36 by then.>
163              
164             =over
165              
166             =item * 5.24 current minimum supported version, until next PDF::Builder release after 30 May, 2023
167              
168             =item * 5.26 future minimum supported version, until next PDF::Builder release after 23 June, 2024
169              
170             =item * 5.28 future minimum supported version, until next PDF::Builder release after 22 May, 2025
171              
172             =item * 5.30 future minimum supported version, until next PDF::Builder release after 20 June, 2026
173              
174             =item * 5.32 future minimum supported version, until next PDF::Builder release after 20 May, 2027
175              
176             =item * 5.34 future minimum supported version, until next PDF::Builder release after 28 May, 2028
177              
178             =back
179              
180             If you need to use this module on a server with an extremely out-of-date version
181             of Perl, consider using either plenv or Perlbrew to run a newer version of Perl
182             without needing admin privileges.
183              
184             On the other hand, any feature in PDF::Builder should continue to work
185             unchanged for the life of most long-term-stable (LTS) server distributions.
186             Their lifetime is usually about six (6) years. Note that this does B
187             constitute a statement of warranty, but that we I to try to keep any
188             particular release of PDF::Builder working for a period of years. Of course,
189             it helps if you periodically update your Perl installation to something
190             released in the recent past.
191              
192             =head2 KNOWN ISSUES
193              
194             This module does not work with perl's -l command-line switch.
195              
196             There is a file INFO/KNOWN_INCOMP which lists known incompatibilities with
197             PDF::API2, in case you're thinking of porting over something from that world,
198             or have experience there and want to try PDF::Builder. There is also a file
199             INFO/DEPRECATED, which lists things which are planned to be removed at some
200             point.
201              
202             =head2 HISTORY
203              
204             The history of PDF::Builder is a complex and exciting saga... OK, it may be
205             mildly interesting. Have a look at L section.
206              
207             =head2 AUTHOR
208              
209             PDF::API2 was originally written by Alfred Reibenschuh. See the HISTORY section
210             for more information.
211              
212             It was maintained by Steve Simms, who is still contributing new code to it
213             (which often ends up in PDF::Builder).
214              
215             PDF::Builder is currently being maintained by Phil M. Perry.
216              
217             =head2 SUPPORT
218              
219             The full source is on https://github.com/PhilterPaper/Perl-PDF-Builder.
220              
221             The release distribution is on CPAN: https://metacpan.org/pod/PDF::Builder.
222              
223             Bug reports are on https://github.com/PhilterPaper/Perl-PDF-Builder/issues?q=is%3Aissue+sort%3Aupdated-desc
224             (with "bug" label), feature requests have an "enhancement" label, and general
225             discussions (architecture, roadmap, etc.) have a "general discussion" label.
226              
227             Do B under I circumstances open a PR (Pull Request) to report a bug.
228             It is a waste of both your and our time and effort. Open a regular ticket
229             (issue), and attach a Perl (.pl) program illustrating the problem, if possible.
230             If you believe that you have a program patch, and offer to share it as a PR, we
231             may give the go-ahead. Unsolicited PRs may be closed without further action.
232              
233             =head2 LICENSE
234              
235             This software is Copyright (c) 2017-2023 by Phil M. Perry.
236              
237             This is free software, licensed under:
238              
239             The GNU Lesser General Public License (LGPL) Version 2.1, February 1999
240              
241             (The master copy of this license lives on the GNU website.)
242             (A copy is provided in the INFO/LICENSE file for your convenience.)
243              
244             This section of Builder.pm is intended only as a very brief summary
245             of the license; please consider INFO/LICENSE to be the controlling version,
246             if there is any conflict or ambiguity between the two.
247              
248             This program is free software; you can redistribute it and/or modify it under
249             the terms of the GNU Lesser General Public License, as published by the Free
250             Software Foundation, either version 2.1 of the License, or (at your option) any
251             later version of this license.
252              
253             NOTE: there are several files in this distribution which were incorporated from
254             outside sources and carry different licenses. If a file states that it is under
255             a license different than LGPL 2.1, that license and its terms will apply to
256             that file, and not LGPL 2.1.
257              
258             This library is distributed in the hope that it will be useful, but WITHOUT ANY
259             WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
260             PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
261              
262             =head1 GENERAL PURPOSE METHODS
263              
264             =over
265              
266             =item $pdf = PDF::Builder->new(%opts)
267              
268             Creates a new PDF object.
269              
270             B
271              
272             =over
273              
274             =item file
275              
276             If you will be saving it as a file and
277             already know the filename, you can give the 'file' option to minimize
278             possible memory requirements later on (the file is opened immediately for
279             writing, rather than waiting until the C). The C may also be
280             a filehandle.
281              
282             =item compress
283              
284             The 'compress' option can be
285             given to specify stream compression: default is 'flate', 'none' (or 0) is no
286             compression. No other compression methods are currently supported.
287              
288             =item outver
289              
290             The 'outver' option defaults to 1.4 as the output PDF version and the highest
291             allowed feature version (attempts to use anything higher will give a warning).
292             If an existing PDF with a higher version is read in, C will be
293             increased to that version, with a warning.
294              
295             =item msgver
296              
297             The 'msgver' option value of 1 (default) gives a warning message if the
298             'outver' PDF level has to be bumped up due to either a higher PDF level file
299             being read in, or a higher level feature was requested. A value of 0
300             suppresses the warning message.
301              
302             =item diaglevel
303              
304             The 'diaglevel' option can be
305             given to specify the level of diagnostics given by IntegrityCheck(). The
306             default is level 2 (errors and warnings).
307             See L for more information.
308              
309             =back
310              
311             B
312              
313             $pdf = PDF::Builder->new();
314             ...
315             print $pdf->to_string();
316              
317             $pdf = PDF::Builder->new(compress => 'none');
318             # equivalent to $pdf->{'forcecompress'} = 'none'; (or older, 0)
319              
320             $pdf = PDF::Builder->new();
321             ...
322             $pdf->saveas('our/new.pdf');
323              
324             $pdf = PDF::Builder->new(file => 'our/new.pdf');
325             ...
326             $pdf->save();
327              
328             =cut
329              
330             sub new {
331 217     217 1 27907 my ($class, %opts) = @_;
332             # copy dashed option names to preferred undashed names
333 217 100 66     1102 if (defined $opts{'-compress'} && !defined $opts{'compress'}) { $opts{'compress'} = delete($opts{'-compress'}); }
  99         254  
334 217 50 33     714 if (defined $opts{'-diaglevel'} && !defined $opts{'diaglevel'}) { $opts{'diaglevel'} = delete($opts{'-diaglevel'}); }
  0         0  
335 217 100 66     734 if (defined $opts{'-outver'} && !defined $opts{'outver'}) { $opts{'outver'} = delete($opts{'-outver'}); }
  1         4  
336 217 50 33     621 if (defined $opts{'-msgver'} && !defined $opts{'msgver'}) { $opts{'msgver'} = delete($opts{'-msgver'}); }
  0         0  
337 217 50 33     617 if (defined $opts{'-file'} && !defined $opts{'file'}) { $opts{'file'} = delete($opts{'-file'}); }
  0         0  
338              
339 217         450 my $self = {};
340 217         462 bless $self, $class;
341 217         1548 $self->{'pdf'} = PDF::Builder::Basic::PDF::File->new();
342              
343             # make available to other routines
344 217         735 $myself = $self->{'pdf'};
345              
346             # default output version
347 217         805 $self->{'pdf'}->{' version'} = $outVer;
348 217         2334 $self->{'pages'} = PDF::Builder::Basic::PDF::Pages->new($self->{'pdf'});
349 217         883 $self->{'pages'}->proc_set(qw(PDF Text ImageB ImageC ImageI));
350 217   33     792 $self->{'pages'}->{'Resources'} ||= PDFDict();
351             $self->{'pdf'}->new_obj($self->{'pages'}->{'Resources'})
352 217 50       883 unless $self->{'pages'}->{'Resources'}->is_obj($self->{'pdf'});
353 217         635 $self->{'catalog'} = $self->{'pdf'}->{'Root'};
354 217         840 weaken $self->{'catalog'};
355 217         437 $self->{'fonts'} = {};
356 217         511 $self->{'pagestack'} = [];
357              
358 217         450 $self->{'pdf'}->{' userUnit'} = 1.0; # default global User Unit
359 217         768 $self->mediabox('letter'); # PDF defaults to US Letter 8.5in x 11in
360              
361 217 100       651 if (exists $opts{'compress'}) {
362 152         420 $self->{'forcecompress'} = $opts{'compress'};
363             # at this point, no validation of given value! none/flate (0/1).
364             # note that >0 is often used as equivalent to 'flate'
365             } else {
366 65         186 $self->{'forcecompress'} = 'flate';
367             # code should also allow integers 0 (= 'none') and >0 (= 'flate')
368             # for compatibility with old usage where forcecompress is directly set.
369             }
370 217 50       549 if (exists $opts{'diaglevel'}) {
371 0         0 my $diaglevel = $opts{'diaglevel'};
372 0 0 0     0 if ($diaglevel < 0 || $diaglevel > 5) {
373 0         0 print "diaglevel must be in range 0-5. using 2\n";
374 0         0 $diaglevel = 2;
375             }
376 0         0 $self->{'diaglevel'} = $diaglevel;
377             } else {
378 217         455 $self->{'diaglevel'} = 2; # default: errors and warnings
379             }
380              
381 217         882 $self->preferences(%opts);
382 217 100       632 if (defined $opts{'outver'}) {
383 1 50       5 if ($opts{'outver'} >= 1.4) {
384 1         3 $self->{'pdf'}->{' version'} = $opts{'outver'};
385             } else {
386 0         0 print STDERR "Invalid outver given, or less than 1.4. Ignored.\n";
387             }
388             }
389 217 100       543 if (defined $opts{'msgver'}) {
390 1 50 33     5 if ($opts{'msgver'} == 0 || $opts{'msgver'} == 1) {
391 1         2 $msgVer = $opts{'msgver'};
392             } else {
393 0         0 print STDERR "Invalid msgver given, not 0 or 1. Ignored.\n";
394             }
395             }
396 217 50       571 if ($opts{'file'}) {
397 0         0 $self->{'pdf'}->create_file($opts{'file'});
398 0         0 $self->{'partial_save'} = 1;
399             }
400             # used by info and infoMetaAttributes but not by their replacements
401 217         1071 $self->{'infoMeta'} = [qw(Author CreationDate ModDate Creator Producer
402             Title Subject Keywords)];
403              
404 217   50     447 my $version = eval { $PDF::Builder::VERSION } || '(Development Version)';
405             #$self->info('Producer' => "PDF::Builder $version [$^O]");
406 217         1184 $self->info('Producer' => "PDF::Builder $version [see ".
407             "https://github.com/PhilterPaper/Perl-PDF-Builder/blob/master/INFO/SUPPORT]");
408              
409 217         474 $global_pdf = $self;
410             # initialize Font Manager
411 217         1890 require PDF::Builder::FontManager;
412 217         1291 $self->{' FM'} = PDF::Builder::FontManager->new($self);
413              
414 217         2099 return $self;
415             } # end of new()
416              
417             =item $pdf->default_page_size($size); # Set
418              
419             =item @rectangle = $pdf->default_page_size() # Get
420              
421             Set the default physical size for pages in the PDF. If called without
422             arguments, return the coordinates of the rectangle describing the default
423             physical page size.
424              
425             This is essentially an alternate method of defining the C call,
426             and added for compatibility with PDF::API2.
427              
428             See L for possible values.
429              
430             =cut
431              
432             sub default_page_size {
433 1     1 1 2909 my $self = shift();
434              
435             # Set
436 1 50       5 if (@_) {
437 1         4 return $self->default_page_boundaries(media => @_);
438             }
439              
440             # Get
441 0         0 my $boundaries = $self->default_page_boundaries();
442 0         0 return @{$boundaries->{'media'}};
  0         0  
443             }
444              
445             =item $pdf->default_page_boundaries(%boundaries); # Set
446              
447             =item %boundaries = $pdf->default_page_boundaries(); # Get
448              
449             Set default prepress page boundaries for pages in the PDF. If called without
450             arguments, returns the coordinates of the rectangles describing each of the
451             supported page boundaries.
452              
453             See the equivalent C method in L for
454             details.
455              
456             =cut
457              
458             # Called by PDF::Builder::Page::boundaries via the default_page_* methods below
459             sub _bounding_box {
460 8     8   2561 my $self = shift();
461 8         16 my $type = shift();
462              
463             # Get
464 8 100       19 unless (scalar @_) {
465 4 50       12 unless ($self->{'pages'}->{$type}) {
466 0 0       0 return if $type eq 'MediaBox';
467              
468             # Use defaults per PDF 1.7 section 14.11.2 Page Boundaries
469 0 0       0 return $self->_bounding_box('MediaBox') if $type eq 'CropBox';
470 0         0 return $self->_bounding_box('CropBox');
471             }
472 4         14 return map { $_->val() } $self->{'pages'}->{$type}->elements();
  16         34  
473             }
474              
475             # Set
476 4         8 $self->{'pages'}->{$type} = PDFArray(map { PDFNum(float($_)) } @_);
  16         37  
477 4         9 return $self;
478             }
479              
480             sub default_page_boundaries {
481 3     3 1 5123 return PDF::Builder::Page::boundaries(@_);
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             =back
521              
522             =head1 INPUT/OUTPUT METHODS
523              
524             =over
525              
526             =item $pdf = PDF::Builder->open($pdf_file, %opts)
527              
528             Opens an existing PDF file. See C for options.
529              
530             B
531              
532             $pdf = PDF::Builder->open('our/old.pdf');
533             ...
534             $pdf->saveas('our/new.pdf');
535              
536             $pdf = PDF::Builder->open('our/to/be/updated.pdf');
537             ...
538             $pdf->update();
539              
540             =cut
541              
542             sub open { ## no critic
543 8     8 1 1742 my ($class, $file, %opts) = @_;
544 8 50       166 croak "File '$file' does not exist" unless -f $file;
545 8 50       156 croak "File '$file' is not readable" unless -r $file;
546              
547 8         24 my $content;
548 8         73 my $scalar_fh = FileHandle->new();
549 8 50   28   636 CORE::open($scalar_fh, '+<', \$content) or croak "Can't begin scalar IO";
  28         228  
  28         72  
  28         210  
550 8         3916 binmode $scalar_fh, ':raw';
551              
552 8         47 my $disk_fh = FileHandle->new();
553 8 50       518 CORE::open($disk_fh, '<', $file) or croak "Can't open $file for reading: $!";
554 8         60 binmode $disk_fh, ':raw';
555 8         73 $disk_fh->seek(0, 0);
556 8         108 my $data;
557 8         43 while (not $disk_fh->eof()) {
558 49         835 $disk_fh->read($data, 512);
559 49         361 $scalar_fh->print($data);
560             }
561             # check if final %%EOF lacks a carriage return on the end (add one)
562 8 50       171 if ($data =~ m/%%EOF$/) {
563             #print "open() says missing final EOF\n";
564 8         41 $scalar_fh->print("\n");
565             }
566 8         89 $disk_fh->close();
567 8         170 $scalar_fh->seek(0, 0);
568              
569 8         93 my $self = $class->from_string($content, %opts);
570 8         27 $self->{'pdf'}->{' fname'} = $file;
571              
572 8         79 return $self;
573             } # end of open()
574              
575             =item $pdf = PDF::Builder->from_string($pdf_string, %opts)
576              
577             Opens a PDF contained in a string. See C for other options.
578              
579             =over
580              
581             =item diags => 1
582              
583             Display warnings when non-conforming PDF structure is found, and fix up
584             where possible. See L for more information.
585              
586             =back
587              
588             B
589              
590             # Read a PDF into a string, for the purpose of demonstration
591             open $fh, 'our/old.pdf' or croak $@;
592             undef $/; # Read the whole file at once
593             $pdf_string = <$fh>;
594              
595             $pdf = PDF::Builder->from_string($pdf_string);
596             ...
597             $pdf->saveas('our/new.pdf');
598              
599             B C
600              
601             C was formerly known as C (and even before that,
602             as C), and this older name is still
603             valid as an alternative to C. It is I that C
604             will be deprecated and then removed some time in the future, so it may be
605             advisable to use C in new work.
606              
607             =cut
608              
609 1     1 0 1361 sub open_scalar { return from_string(@_); } ## no critic
610 1     1 0 18 sub openScalar { return from_string(@_); } ## no critic
611              
612             sub from_string {
613 18     18 1 2325 my ($class, $content, %opts) = @_;
614             # copy dashed option names to preferred undashed names
615 18 50 33     164 if (defined $opts{'-diags'} && !defined $opts{'diags'}) { $opts{'diags'} = delete($opts{'-diags'}); }
  0         0  
616 18 50 33     90 if (defined $opts{'-compress'} && !defined $opts{'compress'}) { $opts{'compress'} = delete($opts{'-compress'}); }
  0         0  
617 18 50 33     73 if (defined $opts{'-diaglevel'} && !defined $opts{'diaglevel'}) { $opts{'diaglevel'} = delete($opts{'-diaglevel'}); }
  0         0  
618              
619 18         40 my $self = {};
620 18         53 bless $self, $class;
621 18         66 foreach my $parameter (keys %opts) {
622 3         20 $self->default($parameter, $opts{$parameter});
623             }
624              
625 18         90 $self->{'content_ref'} = \$content;
626 18         36 my $diaglevel = 2;
627 18 50       65 if (defined $self->{'diaglevel'}) { $diaglevel = $self->{'diaglevel'}; }
  0         0  
628 18 50 33     117 if ($diaglevel < 0 || $diaglevel > 5) { $diaglevel = 2; }
  0         0  
629 18         159 my $newVer = $self->IntegrityCheck($diaglevel, $content);
630             # if Version override defined in PDF, need to overwrite the %PDF-x.y
631             # statement with the new (if higher) value. it's too late to wait until
632             # after File->open, as it's already complained about some >1.4 features.
633 18 50       62 if (defined $newVer) {
634 0         0 my ($verStr, $currentVer, $pos);
635 0         0 $pos = index $content, "%PDF-";
636 0 0       0 if ($pos < 0) { croak "no PDF version found in PDF input!"; }
  0         0  
637             # assume major and minor PDF version numbers max 2 digits each for now
638             # (are 1 or 2 and 0-7 at this writing)
639 0         0 $verStr = substr($content, $pos, 10);
640 0 0       0 if ($verStr =~ m#^%PDF-(\d+)\.(\d+)#) {
641 0         0 $currentVer = "$1.$2";
642             } else {
643 0         0 croak "unable to get PDF input's version number.";
644             }
645 0 0       0 if ($newVer > $currentVer) {
646 0 0       0 if (length($newVer) > length($currentVer)) {
647 0         0 print STDERR "Unable to update 'content' version because override '$newVer' is longer ".
648             "than header version '$currentVer'.\nYou may receive warnings about features ".
649             "that bump up the PDF level.\n";
650             } else {
651 0 0       0 if (length($newVer) < length($currentVer)) {
652             # unlikely, but cover all the bases
653 0         0 $newVer = substr($newVer, 0, length($currentVer));
654             }
655 0         0 substr($content, $pos+5, length($newVer)) = $newVer;
656 0         0 $self->version($newVer);
657             }
658             }
659             }
660              
661 18         47 my $fh;
662 18 50       357 CORE::open($fh, '+<', \$content) or croak "Can't begin scalar IO";
663              
664             # this would replace any existing self->pdf with a new one
665 18         199 $self->{'pdf'} = PDF::Builder::Basic::PDF::File->open($fh, 1, %opts);
666 18         95 $self->{'pdf'}->{'Root'}->realise();
667 18         101 $self->{'pages'} = $self->{'pdf'}->{'Root'}->{'Pages'}->realise();
668 18         107 weaken $self->{'pages'};
669              
670 18   50     73 $self->{'pdf'}->{' version'} ||= 1.4; # default minimum
671             # if version higher than desired output PDF level, give warning and
672             # bump up desired output PDF level
673 18         93 $self->verCheckInput($self->{'pdf'}->{' version'});
674              
675 18         139 my @pages = _proc_pages($self->{'pdf'}, $self->{'pages'});
676 18         88 $self->{'pagestack'} = [sort { $a->{' pnum'} <=> $b->{' pnum'} } @pages];
  3         21  
677 18         40 weaken $self->{'pagestack'}->[$_] for (0 .. scalar @{$self->{'pagestack'}});
  18         170  
678 18         65 $self->{'catalog'} = $self->{'pdf'}->{'Root'};
679 18         80 weaken $self->{'catalog'};
680 18         44 $self->{'opened_scalar'} = 1;
681 18 100       88 if (exists $opts{'compress'}) {
682 3         13 $self->{'forcecompress'} = $opts{'compress'};
683             # at this point, no validation of given value! none/flate (0/1).
684             # note that >0 is often used as equivalent to 'flate'
685             } else {
686 15         61 $self->{'forcecompress'} = 'flate';
687             # code should also allow integers 0 (= 'none') and >0 (= 'flate')
688             # for compatibility with old usage where forcecompress is directly set.
689             }
690 18 50       72 if (exists $opts{'diaglevel'}) {
691 0         0 $self->{'diaglevel'} = $opts{'diaglevel'};
692 0 0 0     0 if ($self->{'diaglevel'} < 0 || $self->{'diaglevel'} > 5) {
693 0         0 $self->{'diaglevel'} = 2;
694             }
695             } else {
696 18         58 $self->{'diaglevel'} = 2;
697             }
698 18         63 $self->{'fonts'} = {};
699 18         109 $self->{'infoMeta'} = [qw(Author CreationDate ModDate Creator Producer Title Subject Keywords)];
700              
701 18         144 return $self;
702             } # end of from_string()
703              
704             =item $string = $pdf->to_string()
705              
706             Return the document as a string and remove the object structure from memory.
707              
708             B Although the object C<$pdf> will still exist, it is no longer
709             usable for any purpose after invoking this method! You will receive error
710             messages about "can't call method new_obj on an undefined value".
711              
712             B
713              
714             $pdf = PDF::Builder->new();
715             ...
716             print $pdf->to_string();
717              
718             B C
719              
720             C was formerly known as C, and this older name is still
721             valid as an alternative to C. It is I that C
722             will be deprecated and then removed some time in the future, so it may be
723             advisable to use C in new work.
724              
725             =cut
726              
727             # Maintainer's note: The object is being destroyed because it contains
728             # circular references that would otherwise result in memory not being
729             # freed if the object merely goes out of scope. If possible, the
730             # circular references should be eliminated so that to_string doesn't
731             # need to be destructive. See t/circular-references.t.
732             #
733             # I've opted not to just require a separate call to release() because
734             # it would likely introduce memory leaks in many existing programs
735             # that use this module.
736             # - Steve S. (see bug RT 81530)
737              
738 0     0 0 0 sub stringify { return to_string(@_); } ## no critic
739              
740             sub to_string {
741 178     178 1 1440 my $self = shift();
742              
743 178         353 my $string = '';
744             # is only set to 1 (within from_string()), otherwise is undef
745 178 100       469 if ($self->{'opened_scalar'}) {
746 7         47 $self->{'pdf'}->append_file();
747 7         18 $string = ${$self->{'content_ref'}};
  7         83  
748             } else {
749 171         973 my $fh = FileHandle->new();
750             # we should be writing to the STRING $str
751 171 50       9246 CORE::open($fh, '>', \$string) || croak "Can't begin scalar IO";
752 171         19918 $self->{'pdf'}->out_file($fh);
753 171         552 $fh->close();
754             }
755              
756             # This can be eliminated once we're confident that circular references are
757             # no longer an issue. See t/circular-references.t
758 178         1625 $self->end();
759              
760 178         3371 return $string;
761             }
762              
763             =item $pdf->finishobjects(@objects)
764              
765             Force objects to be written to file if possible.
766              
767             B
768              
769             $pdf = PDF::Builder->new(file => 'our/new.pdf');
770             ...
771             $pdf->finishobjects($page, $gfx, $txt);
772             ...
773             $pdf->save();
774              
775             B this method is now considered obsolete, and may be deprecated. It
776             allows for objects to be written to disk in advance of finally
777             saving and closing the file. Otherwise, it's no different than just calling
778             C when all changes have been made. There's no memory advantage since
779             C doesn't remove objects from memory.
780              
781             =cut
782              
783             # obsolete, use save instead
784             #
785             # This method allows for objects to be written to disk in advance of finally
786             # saving and closing the file. Otherwise, it's no different than just calling
787             # save when all changes have been made. There's no memory advantage since
788             # ship_out doesn't remove objects from memory.
789             sub finishobjects {
790 0     0 1 0 my ($self, @objs) = @_;
791              
792 0 0       0 if ($self->{'opened_scalar'}) {
    0          
793 0         0 croak "invalid method invocation: no file, use 'saveas' instead.";
794             } elsif ($self->{'partial_save'}) {
795 0         0 $self->{'pdf'}->ship_out(@objs);
796             } else {
797 0         0 croak "invalid method invocation: no file, use 'saveas' instead.";
798             }
799              
800 0         0 return;
801             }
802              
803             sub _proc_pages {
804 18     18   66 my ($pdf, $object) = @_;
805              
806 18 50       61 if (defined $object->{'Resources'}) {
807 18         54 eval {
808 18         560 $object->{'Resources'}->realise();
809             };
810             }
811              
812 18         43 my @pages;
813 18   50     120 $pdf->{' apipagecount'} ||= 0;
814 18         80 foreach my $page ($object->{'Kids'}->elements()) {
815 20         68 $page->realise();
816 20 50       95 if ($page->{'Type'}->val() eq 'Pages') {
817 0         0 push @pages, _proc_pages($pdf, $page);
818             }
819             else {
820 20         47 $pdf->{' apipagecount'}++;
821 20         70 $page->{' pnum'} = $pdf->{' apipagecount'};
822 20 50       71 if (defined $page->{'Resources'}) {
823 20         38 eval {
824 20         69 $page->{'Resources'}->realise();
825             };
826             }
827 20         69 push @pages, $page;
828             }
829             }
830              
831 18         69 return @pages;
832             } # end of _proc_pages()
833              
834             =item $pdf->update()
835              
836             Saves a previously opened document.
837              
838             B
839              
840             $pdf = PDF::Builder->open('our/to/be/updated.pdf');
841             ...
842             $pdf->update();
843              
844             B it is considered better to simply C the file, rather than
845             calling C. They end up doing the same thing, anyway. This method
846             may be deprecated in the future.
847              
848             =cut
849              
850             # obsolete, use save instead
851             sub update {
852 0     0 1 0 my $self = shift();
853 0         0 $self->saveas($self->{'pdf'}->{' fname'});
854 0         0 return;
855             }
856              
857             =item $pdf->saveas($file)
858              
859             Save the document to $file and remove the object structure from memory.
860              
861             B Although the object C<$pdf> will still exist, it is no longer
862             usable for any purpose after invoking this method! You will receive error
863             messages about "can't call method new_obj on an undefined value".
864              
865             B
866              
867             $pdf = PDF::Builder->new();
868             ...
869             $pdf->saveas('our/new.pdf');
870              
871             =cut
872              
873             sub saveas {
874 1     1 1 8 my ($self, $file) = @_;
875              
876 1 50       5 if ($self->{'opened_scalar'}) {
    0          
877 1         5 $self->{'pdf'}->append_file();
878 1         4 my $fh;
879 1 50       88 CORE::open($fh, '>', $file) or croak "Can't open $file for writing: $!";
880 1         10 binmode($fh, ':raw');
881 1         5 print $fh ${$self->{'content_ref'}};
  1         7  
882 1         120 CORE::close($fh);
883             } elsif ($self->{'partial_save'}) {
884 0         0 $self->{'pdf'}->close_file();
885             } else {
886 0         0 $self->{'pdf'}->out_file($file);
887             }
888              
889 1         9 $self->end();
890 1         3 return;
891             }
892              
893             =item $pdf->save()
894              
895             =item $pdf->save(filename)
896              
897             Save the document to an already-defined file (or filename) and
898             remove the object structure from memory.
899             Optionally, a new filename may be given.
900              
901             B Although the object C<$pdf> will still exist, it is no longer
902             usable for any purpose after invoking this method! You will receive error
903             messages about "can't call method new_obj on an undefined value".
904              
905             B
906              
907             $pdf = PDF::Builder->new(file => 'file_to_output');
908             ...
909             $pdf->save();
910              
911             B now that C can take a filename as an argument, it effectively
912             is interchangeable with C. This is strictly for compatibility with
913             recent changes to PDF::API2. Unlike PDF::API2, we are not deprecating
914             the C method, because in user interfaces, "save" normally means that
915             the current filename is known and is to be used, while "saveas" normally means
916             that (whether or not there is a current filename) a new filename is to be used.
917              
918             =cut
919              
920             sub save {
921 0     0 1 0 my ($self, $file) = @_;
922              
923 0 0       0 if (defined $file) {
924 0         0 return $self->saveas($file);
925             }
926              
927             # NOTE: the current PDF::API2 version is quite different, but this may be
928             # a consequence of merging save() and saveas(). Let's give this unchanged
929             # version a try.
930 0 0       0 if ($self->{'opened_scalar'}) {
    0          
931 0         0 croak "Invalid method invocation: use 'saveas' instead of 'save'.";
932             } elsif ($self->{'partial_save'}) {
933 0         0 $self->{'pdf'}->close_file();
934             } else {
935 0         0 croak "Invalid method invocation: use 'saveas' instead of 'save'.";
936             }
937              
938 0         0 $self->end();
939 0         0 return;
940             }
941              
942             =item $pdf->close();
943              
944             Close an open file (if relevant) and remove the object structure from memory.
945              
946             PDF::API2 contains circular references, so this call is necessary in
947             long-running processes to keep from running out of memory.
948              
949             This will be called automatically when you save or stringify a PDF.
950             You should only need to call it explicitly if you are reading PDF
951             files and not writing them.
952              
953             B C and C
954              
955             =cut
956              
957             =item $pdf->end()
958              
959             Remove the object structure from memory. PDF::Builder contains circular
960             references, so this call is necessary in long-running processes to
961             keep from running out of memory.
962              
963             This will be called automatically when you save or to_string a PDF.
964             You should only need to call it explicitly if you are reading PDF
965             files and not writing them.
966              
967             This (and I) are older and now deprecated names formerly used in
968             PDF::API2 and PDF::Builder. You should try to avoid having to explicitly
969             call them.
970              
971             =cut
972              
973             # Deprecated (renamed)
974 0     0 1 0 sub release { return $_[0]->close(); }
975 179     179 1 584 sub end { return $_[0]->close(); }
976              
977             sub close {
978 179     179 1 741 my $self = shift();
979 179 50       1028 $self->{'pdf'}->release() if defined $self->{'pdf'};
980              
981 179         802 foreach my $key (keys %$self) {
982 1624         5292 $self->{$key} = undef;
983 1624         2293 delete $self->{$key};
984             }
985              
986 179         443 return;
987             }
988              
989             =back
990              
991             =head2 METADATA METHODS
992              
993             =over
994              
995             =item $title = $pdf->title();
996              
997             =item $pdf = $pdf->title($title);
998              
999             Get/set/clear the document's title.
1000              
1001             =cut
1002              
1003             sub title {
1004 0     0 1 0 my $self = shift();
1005 0         0 return $self->info_metadata('Title', @_);
1006             }
1007              
1008             =item $author = $pdf->author();
1009              
1010             =item $pdf = $pdf->author($author);
1011              
1012             Get/set/clear the name of the person who created the document.
1013              
1014             =cut
1015              
1016             sub author {
1017 0     0 1 0 my $self = shift();
1018 0         0 return $self->info_metadata('Author', @_);
1019             }
1020              
1021             =item $subject = $pdf->subject();
1022              
1023             =item $pdf = $pdf->subject($subject);
1024              
1025             Get/set/clear the subject of the document.
1026              
1027             =cut
1028              
1029             sub subject {
1030 0     0 1 0 my $self = shift();
1031 0         0 return $self->info_metadata('Subject', @_);
1032             }
1033              
1034             =item $keywords = $pdf->keywords();
1035              
1036             =item $pdf = $pdf->keywords($keywords);
1037              
1038             Get/set/clear a space-separated string of keywords associated with the document.
1039              
1040             =cut
1041              
1042             sub keywords {
1043 0     0 1 0 my $self = shift();
1044 0         0 return $self->info_metadata('Keywords', @_);
1045             }
1046              
1047             =item $creator = $pdf->creator();
1048              
1049             =item $pdf = $pdf->creator($creator);
1050              
1051             Get/set/clear the name of the product that created the document prior to its
1052             conversion to PDF.
1053              
1054             =cut
1055              
1056             sub creator {
1057 0     0 1 0 my $self = shift();
1058 0         0 return $self->info_metadata('Creator', @_);
1059             }
1060              
1061             =item $producer = $pdf->producer();
1062              
1063             =item $pdf = $pdf->producer($producer);
1064              
1065             Get/set/clear the name of the product that converted the original document to
1066             PDF.
1067              
1068             PDF::Builder fills in this field when creating a PDF.
1069              
1070             =cut
1071              
1072             sub producer {
1073 5     5 1 14 my $self = shift();
1074 5         12 return $self->info_metadata('Producer', @_);
1075             }
1076              
1077             =item $date = $pdf->created();
1078              
1079             =item $pdf = $pdf->created($date);
1080              
1081             Get/set/clear the document's creation date.
1082              
1083             The date format is C, where C is a static prefix
1084             identifying the string as a PDF date. The date may be truncated at any point
1085             after the year. C is one of C<+>, C<->, or C, with the following C
1086             representing an offset from UTC.
1087              
1088             When setting the date, C will be prepended automatically if omitted.
1089              
1090             =cut
1091              
1092             sub created {
1093 1     1 1 7 my $self = shift();
1094 1         5 return $self->info_metadata('CreationDate', @_);
1095             }
1096              
1097             =item $date = $pdf->modified();
1098              
1099             =item $pdf = $pdf->modified($date);
1100              
1101             Get/set/clear the document's modification date. The date format is as described
1102             in C above.
1103              
1104             =cut
1105              
1106             sub modified {
1107 0     0 1 0 my $self = shift();
1108 0         0 return $self->info_metadata('ModDate', @_);
1109             }
1110              
1111             sub _is_date {
1112 1     1   3 my $value = shift();
1113              
1114             # PDF 1.7 section 7.9.4 describes the required date format. Other than the
1115             # D: prefix and the year, all components are optional but must be present if
1116             # a later component is present. No provision is made in the specification
1117             # for leap seconds, etc.
1118 1 50       9 return unless $value =~ /^D:([0-9]{4}) # D:YYYY (required)
1119             (?:([01][0-9]) # Month (01-12)
1120             (?:([0123][0-9]) # Day (01-31)
1121             (?:([012][0-9]) # Hour (00-23)
1122             (?:([012345][0-9]) # Minute (00-59)
1123             (?:([012345][0-9]) # Second (00-59)
1124             (?:([Z+-]) # UT Offset Direction
1125             (?:([012][0-9]) # UT Offset Hours
1126             (?:\'([012345][0-9]) # UT Offset Minutes
1127             )?)?)?)?)?)?)?)?$/x;
1128 1         19 my ($year, $month, $day, $hour, $minute, $second, $od, $oh, $om)
1129             = ($1, $2, $3, $4, $5, $6, $7, $8, $9);
1130              
1131             # Do some basic validation to catch accidental date formatting issues.
1132             # Complete date validation is out of scope.
1133 1 50       4 if (defined $month) {
1134 1 50 33     7 return unless $month >= 1 and $month <= 12;
1135             }
1136 1 50       3 if (defined $day) {
1137 1 50 33     6 return unless $day >= 1 and $day <= 31;
1138             }
1139 1 50       3 if (defined $hour) {
1140 1 50       3 return unless $hour <= 23;
1141             }
1142 1 50       4 if (defined $minute) {
1143 1 50       4 return unless $minute <= 59;
1144             }
1145 1 50       4 if (defined $second) {
1146 1 50       3 return unless $second <= 59;
1147             }
1148 1 50       3 if (defined $od) {
1149 1 50 33     5 return if $od eq 'Z' and defined($oh);
1150             }
1151 1 50       4 if (defined $oh) {
1152 0 0       0 return unless $oh <= 23;
1153             }
1154 1 50       4 if (defined $om) {
1155 0 0       0 return unless $om <= 59;
1156             }
1157              
1158 1         3 return 1;
1159             }
1160              
1161             =item %info = $pdf->info_metadata(); # Get all keys and values
1162              
1163             =item $value = $pdf->info_metadata($key); # Get the value of one key
1164              
1165             =item $pdf = $pdf->info_metadata($key, $value); # Set the value of one key
1166              
1167             Get/set/clear a key in the document's information dictionary. The standard keys
1168             (title, author, etc.) have their own accessors, so this is primarily intended
1169             for interacting with custom metadata.
1170              
1171             Pass C as the value in order to remove the key from the dictionary.
1172              
1173             =cut
1174              
1175             sub info_metadata {
1176 6     6 1 9 my $self = shift();
1177 6         10 my $field = shift();
1178              
1179             # Return a hash of the Info table if called without arguments
1180 6 50       12 unless (defined $field) {
1181 0 0       0 return unless exists $self->{'pdf'}->{'Info'};
1182 0         0 $self->{'pdf'}->{'Info'}->realise();
1183 0         0 my %info;
1184 0         0 foreach my $key (keys %{$self->{'pdf'}->{'Info'}}) {
  0         0  
1185 0 0       0 next if $key =~ /^ /;
1186 0 0       0 next unless defined $self->{'pdf'}->{'Info'}->{$key};
1187 0         0 $info{$key} = $self->{'pdf'}->{'Info'}->{$key}->val();
1188             }
1189 0         0 return %info;
1190             }
1191              
1192             # Set
1193 6 100       14 if (@_) {
1194 3         5 my $value = shift();
1195 3 50 66     14 $value = undef if defined($value) and not length($value);
1196              
1197 3 100 66     15 if ($field eq 'CreationDate' or $field eq 'ModDate') {
1198 1 50       6 if (defined ($value)) {
1199 1 50       7 $value = 'D:' . $value unless $value =~ /^D:/;
1200 1 50       3 croak "Invalid date string: $value" unless _is_date($value);
1201             }
1202             }
1203              
1204 3 50       10 unless (exists $self->{'pdf'}->{'Info'}) {
1205 0 0       0 return $self unless defined $value;
1206 0         0 $self->{'pdf'}->{'Info'} = PDFDict();
1207 0         0 $self->{'pdf'}->new_obj($self->{'pdf'}->{'Info'});
1208             }
1209             else {
1210 3         12 $self->{'pdf'}->{'Info'}->realise();
1211             }
1212              
1213 3 100       9 if (defined $value) {
1214 2         6 $self->{'pdf'}->{'Info'}->{$field} = PDFStr($value);
1215             }
1216             else {
1217 1         4 delete $self->{'pdf'}->{'Info'}->{$field};
1218             }
1219              
1220 3         10 return $self;
1221             }
1222              
1223             # Get
1224 3 50       8 return unless $self->{'pdf'}->{'Info'};
1225 3         10 $self->{'pdf'}->{'Info'}->realise();
1226 3 100       11 return unless $self->{'pdf'}->{'Info'}->{$field};
1227 2         7 return $self->{'pdf'}->{'Info'}->{$field}->val();
1228             }
1229              
1230             =item %infohash = $pdf->info()
1231              
1232             =item %infohash = $pdf->info(%infohash)
1233              
1234             Gets/sets the info structure of the document.
1235              
1236             See L section for an example of the use
1237             of this method.
1238              
1239             B this method is still available, for compatibility purposes. It is
1240             better to use individual accessors or C instead.
1241              
1242             =cut
1243              
1244             sub info {
1245 220     220 1 728 my ($self, %opt) = @_;
1246              
1247 220 100       660 if (not defined($self->{'pdf'}->{'Info'})) {
1248 217         618 $self->{'pdf'}->{'Info'} = PDFDict();
1249 217         801 $self->{'pdf'}->new_obj($self->{'pdf'}->{'Info'});
1250             } else {
1251 3         12 $self->{'pdf'}->{'Info'}->realise();
1252             }
1253              
1254             # Maintenance Note: Since we're not shifting at the beginning of
1255             # this sub, this "if" will always be true
1256 220 50       952 if (scalar @_) {
1257 220         417 foreach my $k (@{$self->{'infoMeta'}}) {
  220         553  
1258 1760 100       3690 next unless defined $opt{$k};
1259 218   50     905 $self->{'pdf'}->{'Info'}->{$k} = PDFString($opt{$k} || 'NONE', 'm');
1260             }
1261 220         729 $self->{'pdf'}->out_obj($self->{'pdf'}->{'Info'});
1262             }
1263              
1264 220 50       650 if (defined $self->{'pdf'}->{'Info'}) {
1265 220         517 %opt = ();
1266 220         353 foreach my $k (@{$self->{'infoMeta'}}) {
  220         522  
1267 1760 100       3750 next unless defined $self->{'pdf'}->{'Info'}->{$k};
1268 220         648 $opt{$k} = $self->{'pdf'}->{'Info'}->{$k}->val();
1269 220 50 33     1831 if ((unpack('n', $opt{$k}) == 0xfffe) or (unpack('n', $opt{$k}) == 0xfeff)) {
1270 0         0 $opt{$k} = decode('UTF-16', $self->{'pdf'}->{'Info'}->{$k}->val());
1271             }
1272             }
1273             }
1274              
1275 220         493 return %opt;
1276             } # end of info()
1277              
1278             =item @metadata_attributes = $pdf->infoMetaAttributes()
1279              
1280             =item @metadata_attributes = $pdf->infoMetaAttributes(@metadata_attributes)
1281              
1282             Gets/sets the supported info-structure tags.
1283              
1284             B
1285              
1286             @attributes = $pdf->infoMetaAttributes;
1287             print "Supported Attributes: @attr\n";
1288              
1289             @attributes = $pdf->infoMetaAttributes('CustomField1');
1290             print "Supported Attributes: @attributes\n";
1291              
1292             B this method is still available for compatibility purposes, but the
1293             use of C instead is encouraged.
1294              
1295             =cut
1296              
1297             sub infoMetaAttributes {
1298 0     0 1 0 my ($self, @attr) = @_;
1299              
1300 0 0       0 if (scalar @attr) {
1301 0         0 my %at = map { $_ => 1 } @{$self->{'infoMeta'}}, @attr;
  0         0  
  0         0  
1302 0         0 @{$self->{'infoMeta'}} = keys %at;
  0         0  
1303             }
1304              
1305 0         0 return @{$self->{'infoMeta'}};
  0         0  
1306             }
1307              
1308             =item $xml = $pdf->xml_metadata();
1309              
1310             =item $pdf = $pdf->xml_metadata($xml);
1311              
1312             Gets/sets the document's XML metadata stream.
1313              
1314             =cut
1315              
1316             sub xml_metadata {
1317 0     0 1 0 my ($self, $value) = @_;
1318              
1319 0 0       0 if (not defined($self->{'catalog'}->{'Metadata'})) {
1320 0         0 $self->{'catalog'}->{'Metadata'} = PDFDict();
1321 0         0 $self->{'catalog'}->{'Metadata'}->{'Type'} = PDFName('Metadata');
1322 0         0 $self->{'catalog'}->{'Metadata'}->{'Subtype'} = PDFName('XML');
1323 0         0 $self->{'pdf'}->new_obj($self->{'catalog'}->{'Metadata'});
1324             }
1325             else {
1326 0         0 $self->{'catalog'}->{'Metadata'}->realise();
1327 0         0 $self->{'catalog'}->{'Metadata'}->{' stream'} = unfilter($self->{'catalog'}->{'Metadata'}->{'Filter'}, $self->{'catalog'}->{'Metadata'}->{' stream'});
1328 0         0 delete $self->{'catalog'}->{'Metadata'}->{' nofilt'};
1329 0         0 delete $self->{'catalog'}->{'Metadata'}->{'Filter'};
1330             }
1331              
1332 0         0 my $md = $self->{'catalog'}->{'Metadata'};
1333              
1334 0 0       0 if (defined $value) {
1335 0         0 $md->{' stream'} = $value;
1336 0         0 delete $md->{'Filter'};
1337 0         0 delete $md->{' nofilt'};
1338 0         0 $self->{'pdf'}->out_obj($md);
1339 0         0 $self->{'pdf'}->out_obj($self->{'catalog'});
1340             }
1341              
1342 0         0 return $md->{' stream'};
1343             }
1344              
1345             =item $xml = $pdf->xmpMetadata() # Get
1346              
1347             =item $xml = $pdf->xmpMetadata($xml) # Set (also returns $xml value)
1348              
1349             Gets/sets the XMP XML data stream.
1350              
1351             See L section for an example of the use
1352             of this method.
1353              
1354             This method is considered B. Use C instead.
1355              
1356             =cut
1357              
1358             sub xmpMetadata {
1359 0     0 1 0 my ($self, $value) = @_;
1360              
1361 0 0       0 if (@_) { # Set
1362 0         0 my $value = shift();
1363 0         0 $self->xml_metadata($value);
1364 0         0 return $value;
1365             }
1366              
1367             # Get
1368 0         0 return $self->xml_metadata();
1369             }
1370              
1371             =item $val = $pdf->default($parameter)
1372              
1373             =item $pdf->default($parameter, $value)
1374              
1375             Gets/sets the default value for a behavior of PDF::Builder.
1376              
1377             B
1378              
1379             =over
1380              
1381             =item nounrotate
1382              
1383             prohibits Builder from rotating imported/opened page to re-create a
1384             default pdf-context.
1385              
1386             =item pageencaps
1387              
1388             enables Builder's adding save/restore commands upon importing/opening
1389             pages to preserve graphics-state for modification.
1390              
1391             =item copyannots
1392              
1393             enables importing of annotations (B<*EXPERIMENTAL*>).
1394              
1395             =back
1396              
1397             B Perl::Critic (tools/1_pc.pl) has started flagging the name
1398             "default" as a reserved keyword in higher Perl versions. Use with caution, and
1399             be aware that this name I have to be changed in the future.
1400              
1401             =cut
1402              
1403             sub default {
1404 11     11 1 29 my ($self, $parameter, $value) = @_;
1405              
1406             # Parameter names may consist of lowercase letters, numbers, and underscores
1407 11         27 $parameter = lc $parameter;
1408 11         41 $parameter =~ s/[^a-z\d_]//g;
1409              
1410 11         27 my $previous_value = $self->{$parameter};
1411 11 100       29 if (defined $value) {
1412 3         9 $self->{$parameter} = $value;
1413             }
1414              
1415 11         44 return $previous_value;
1416             }
1417              
1418             =item $version = $pdf->version() # Get
1419              
1420             =item $version = $pdf->version($version) # Set (also returns newly set version)
1421              
1422             Gets/sets the PDF version (e.g., 1.5).
1423             For compatibility with earlier releases, if no decimal point is given, assume
1424             "1." precedes the number given.
1425              
1426             A warning message is given if you attempt to I the PDF version, as you
1427             might have already read in a higher level file, or used a higher level feature.
1428              
1429             See L for additional information on the
1430             C method.
1431              
1432             =cut
1433              
1434             sub version {
1435 27     27 1 80 my $self = shift(); # includes any %opts
1436              
1437 27         111 return $self->{'pdf'}->version(@_); # just pass it over to the "real" one
1438             }
1439              
1440             # when outputting a PDF feature, verCheckOutput(n, 'feature name') returns TRUE
1441             # if n > $pdf->{' version'), plus a warning message. It returns FALSE otherwise.
1442             #
1443             # a typical use:
1444             #
1445             # $PDF::Builder::global_pdf->verCheckOutput(1.6, "portzebie with foo-dangle");
1446             #
1447             # if msgver defaults to 1, a message will be output if the output PDF version
1448             # has to be increased to 1.6 in order to use the "portzebie" feature
1449             #
1450             # this is still somewhat experimental, and as experience is gained, the code
1451             # might have to be modified.
1452             #
1453             sub verCheckOutput {
1454 3     3 0 10 my ($self, $PDFver, $featureName) = @_;
1455              
1456             # check if feature required PDF version is higher than planned output
1457 3         10 my $version = $self->version(); # current version
1458 3 100       25 if ($PDFver > $version) {
1459 1 50       3 if ($msgVer) {
1460 0         0 print "PDF version of requested feature '$featureName' is higher\n". " than current output version $version ".
1461             "(version reset to $PDFver)\n";
1462             }
1463 1         5 $self->version($PDFver);
1464 1         2 return 1;
1465             } else {
1466 2         7 return 0;
1467             }
1468             }
1469              
1470             # when reading in a PDF, verCheckInput(n) gives a warning message if n (the PDF
1471             # version just read in) > version, and resets version to n. return TRUE if
1472             # version changed, FALSE otherwise.
1473             #
1474             # this is still somewhat experimental, and as experience is gained, the code
1475             # might have to be modified.
1476             #
1477             # WARNING: just because the PDF output version has been increased does NOT
1478             # guarantee that any particular content will be handled correctly! There are
1479             # many known cases of PDF 1.5 and up files being read in, that have content
1480             # that PDF::Builder does not handle correctly, corrupting the resulting PDF.
1481             # Pay attention to run-time warning messages that the PDF output level has
1482             # been increased due to a PDF file being read in, and check the resulting
1483             # file carefully.
1484              
1485             sub verCheckInput {
1486 18     18 0 54 my ($self, $PDFver) = @_;
1487              
1488 18         60 my $version = $self->version();
1489             # warning message and bump up version if read-in PDF level higher
1490 18 50       85 if ($PDFver > $version) {
1491 0 0       0 if ($msgVer) {
1492 0         0 print "PDF version just read in is higher than version of $version (version reset to $PDFver)\n";
1493             }
1494 0         0 $self->version($PDFver);
1495 0         0 return 1;
1496             } else {
1497 18         45 return 0;
1498             }
1499             }
1500              
1501             =item $bool = $pdf->is_encrypted()
1502              
1503             Checks if the previously opened PDF is encrypted.
1504              
1505             B C
1506              
1507             This is the older name; it is kept for compatibility with PDF::API2.
1508              
1509             =cut
1510              
1511 0     0 0 0 sub isEncrypted { return is_encrypted(@_); } ## no critic
1512              
1513             sub is_encrypted {
1514 0     0 1 0 my $self = shift();
1515 0 0       0 return defined($self->{'pdf'}->{'Encrypt'}) ? 1 : 0;
1516             }
1517              
1518             =back
1519              
1520             =head1 INTERACTIVE FEATURE METHODS
1521              
1522             =over
1523              
1524             =item $otls = $pdf->outline()
1525              
1526             Creates (if needed) and returns the document's 'outline' tree, which is also
1527             known as its 'bookmarks' or the 'table of contents', depending on the
1528             PDF reader being used.
1529              
1530             To examine or modify the outline tree, see L.
1531              
1532             B C
1533              
1534             This is the older name; it is kept for compatibility.
1535              
1536             =cut
1537              
1538 4     4 1 27 sub outlines { return outline(@_); } ## no critic
1539              
1540             sub outline {
1541 4     4 1 7 my $self = shift();
1542              
1543 4         538 require PDF::Builder::Outlines;
1544 4         14 my $obj = $self->{'pdf'}->{'Root'}->{'Outlines'};
1545 4 100       10 if ($obj) {
1546 1         3 $obj->realise();
1547 1         5 bless $obj, 'PDF::Builder::Outlines';
1548 1         3 $obj->{' api'} = $self;
1549 1         4 weaken $obj->{' api'};
1550             } else {
1551 3         19 $obj = PDF::Builder::Outlines->new($self);
1552              
1553 3         11 $self->{'pdf'}->{'Root'}->{'Outlines'} = $obj;
1554 3 50       12 $self->{'pdf'}->new_obj($obj) unless $obj->is_obj($self->{'pdf'});
1555 3         11 $self->{'pdf'}->out_obj($obj);
1556 3         8 $self->{'pdf'}->out_obj($self->{'pdf'}->{'Root'});
1557             }
1558 4         16 return $obj;
1559             }
1560              
1561             #=item $pdf = $pdf->open_action($page, $location, @args);
1562             #
1563             #Set the destination in the PDF that should be displayed when the document is
1564             #opened.
1565             #
1566             #C<$page> may be either a page number or a page object. The other parameters are
1567             #as described in L.
1568             #
1569             #This has been split out from C for compatibility with PDF::API2.
1570             #It also can both set (assign) and get (query) the settings used.
1571             #
1572             #=cut
1573             #
1574             #sub open_action {
1575             # my ($self, $page, @args) = @_;
1576             #
1577             # # $page can be either a page number or a page object
1578             # $page = PDFNum($page) unless ref($page);
1579             #
1580             # require PDF::Builder::NamedDestination;
1581             # # PDF::API2 code incompatible with Builder!
1582             # #my $array = PDF::Builder::NamedDestination::_destination($page, @args);
1583             #
1584             # $self->{'catalog'}->{'OpenAction'} = $array;
1585             # $self->{'pdf'}->out_obj($self->{'catalog'});
1586             # return $self;
1587             #}
1588              
1589             =item $layout = $pdf->page_layout();
1590              
1591             =item $pdf = $pdf->page_layout($layout);
1592              
1593             Gets/sets the page layout that should be used when the PDF is opened.
1594              
1595             C<$layout> is one of the following:
1596              
1597             =over
1598              
1599             =item single_page (or undef)
1600              
1601             Display one page at a time.
1602              
1603             =item one_column
1604              
1605             Display the pages in one column (a.k.a. continuous).
1606              
1607             =item two_column_left
1608              
1609             Display the pages in two columns, with odd-numbered pages on the left.
1610              
1611             =item two_column_right
1612              
1613             Display the pages in two columns, with odd-numbered pages on the right.
1614              
1615             =item two_page_left
1616              
1617             Display two pages at a time, with odd-numbered pages on the left.
1618              
1619             =item two_page_right
1620              
1621             Display two pages at a time, with odd-numbered pages on the right.
1622              
1623             =back
1624              
1625             This has been split out from C for compatibility with PDF::API2.
1626             It also can both set (assign) and get (query) the settings used.
1627              
1628             =cut
1629              
1630             sub page_layout {
1631 0     0 1 0 my $self = shift();
1632              
1633 0 0       0 unless (@_) {
1634 0 0       0 return 'single_page' unless $self->{'catalog'}->{'PageLayout'};
1635 0         0 my $layout = $self->{'catalog'}->{'PageLayout'}->val();
1636 0 0       0 return 'single_page' if $layout eq 'SinglePage';
1637 0 0       0 return 'one_column' if $layout eq 'OneColumn';
1638 0 0       0 return 'two_column_left' if $layout eq 'TwoColumnLeft';
1639 0 0       0 return 'two_column_right' if $layout eq 'TwoColumnRight';
1640 0 0       0 return 'two_page_left' if $layout eq 'TwoPageLeft';
1641 0 0       0 return 'two_page_right' if $layout eq 'TwoPageRight';
1642 0         0 warn "Unknown page layout: $layout";
1643 0         0 return $layout;
1644             }
1645              
1646 0   0     0 my $name = shift() // 'single_page';
1647 0 0       0 my $layout = ($name eq 'single_page' ? 'SinglePage' :
    0          
    0          
    0          
    0          
    0          
1648             $name eq 'one_column' ? 'OneColumn' :
1649             $name eq 'two_column_left' ? 'TwoColumnLeft' :
1650             $name eq 'two_column_right' ? 'TwoColumnRight' :
1651             $name eq 'two_page_left' ? 'TwoPageLeft' :
1652             $name eq 'two_page_right' ? 'TwoPageRight' : '');
1653              
1654 0 0       0 croak "Invalid page layout: $name" unless $layout;
1655 0         0 $self->{'catalog'}->{'PageLayout'} = PDFName($layout);
1656 0         0 $self->{'pdf'}->out_obj($self->{'catalog'});
1657 0         0 return $self;
1658             }
1659              
1660             =item $mode = $pdf->page_mode(); # Get
1661              
1662             =item $pdf = $pdf->page_mode($mode); # Set
1663              
1664             Gets/sets the page mode, which describes how the PDF should be displayed when
1665             opened.
1666              
1667             C<$mode> is one of the following:
1668              
1669             =over
1670              
1671             =item none (or undef)
1672              
1673             Neither outlines nor thumbnails should be displayed.
1674              
1675             =item outlines
1676              
1677             Show the document outline.
1678              
1679             =item thumbnails
1680              
1681             Show the page thumbnails.
1682              
1683             =item full_screen
1684              
1685             Open in full-screen mode, with no menu bar, window controls, or any other window
1686             visible.
1687              
1688             =item optional_content
1689              
1690             Show the optional content group panel.
1691              
1692             =item attachments
1693              
1694             Show the attachments panel.
1695              
1696             =back
1697              
1698             This has been split out from C for compatibility with PDF::API2.
1699             It also can both set (assign) and get (query) the settings used.
1700              
1701             =cut
1702              
1703             sub page_mode {
1704 0     0 1 0 my $self = shift();
1705              
1706 0 0       0 unless (@_) {
1707 0 0       0 return 'none' unless $self->{'catalog'}->{'PageMode'};
1708 0         0 my $mode = $self->{'catalog'}->{'PageMode'}->val();
1709 0 0       0 return 'none' if $mode eq 'UseNone';
1710 0 0       0 return 'outlines' if $mode eq 'UseOutlines';
1711 0 0       0 return 'thumbnails' if $mode eq 'UseThumbs';
1712 0 0       0 return 'full_screen' if $mode eq 'FullScreen';
1713 0 0       0 return 'optional_content' if $mode eq 'UseOC';
1714 0 0       0 return 'attachments' if $mode eq 'UseAttachments';
1715 0         0 warn "Unknown page mode: $mode";
1716 0         0 return $mode;
1717             }
1718              
1719 0   0     0 my $name = shift() // 'none';
1720 0 0       0 my $mode = ($name eq 'none' ? 'UseNone' :
    0          
    0          
    0          
    0          
    0          
1721             $name eq 'outlines' ? 'UseOutlines' :
1722             $name eq 'thumbnails' ? 'UseThumbs' :
1723             $name eq 'full_screen' ? 'FullScreen' :
1724             $name eq 'optional_content' ? 'UseOC' :
1725             $name eq 'attachments' ? 'UseAttachments' : '');
1726              
1727 0 0       0 croak "Invalid page mode: $name" unless $mode;
1728 0         0 $self->{'catalog'}->{'PageMode'} = PDFName($mode);
1729 0         0 $self->{'pdf'}->out_obj($self->{'catalog'});
1730 0         0 return $self;
1731             }
1732              
1733             =item %preferences = $pdf->viewer_preferences(); # Get
1734              
1735             =item $pdf = $pdf->viewer_preferences(%preferences); # Set
1736              
1737             Gets/sets PDF viewer preferences, as described in
1738             L.
1739              
1740             This has been split out from C for compatibility with PDF::API2.
1741             It also can both set (assign) and get (query) the settings used.
1742              
1743             =cut
1744              
1745             sub viewer_preferences {
1746 0     0 1 0 my $self = shift();
1747 0         0 require PDF::Builder::ViewerPreferences;
1748 0         0 my $prefs = PDF::Builder::ViewerPreferences->new($self);
1749 0 0       0 unless (@_) {
1750 0         0 return $prefs->get_preferences();
1751             }
1752 0         0 return $prefs->set_preferences(@_);
1753             }
1754              
1755             =item $pdf->preferences(%opts)
1756              
1757             Controls viewing preferences for the PDF, including the B,
1758             B, B, and B Options. See
1759             L for details
1760             on all these
1761             option groups, and L for page positioning.
1762              
1763             B the various preferences have been split out into their own methods.
1764             It is preferred that you use these specific methods.
1765              
1766             =cut
1767              
1768             sub preferences {
1769 222     222 1 609 my ($self, %opts) = @_;
1770              
1771             # copy dashed option names to the preferred undashed format
1772             # Page Mode Options
1773 222 50 33     690 if (defined $opts{'-fullscreen'} && !defined $opts{'fullscreen'}) { $opts{'fullscreen'} = delete($opts{'-fullscreen'}); }
  0         0  
1774 222 50 33     602 if (defined $opts{'-thumbs'} && !defined $opts{'thumbs'}) { $opts{'thumbs'} = delete($opts{'-thumbs'}); }
  0         0  
1775 222 50 33     570 if (defined $opts{'-outlines'} && !defined $opts{'outlines'}) { $opts{'outlines'} = delete($opts{'-outlines'}); }
  0         0  
1776             # Page Layout Options
1777 222 50 33     634 if (defined $opts{'-singlepage'} && !defined $opts{'singlepage'}) { $opts{'singlepage'} = delete($opts{'-singlepage'}); }
  0         0  
1778 222 50 33     545 if (defined $opts{'-onecolumn'} && !defined $opts{'onecolumn'}) { $opts{'onecolumn'} = delete($opts{'-onecolumn'}); }
  0         0  
1779 222 50 33     667 if (defined $opts{'-twocolumnleft'} && !defined $opts{'twocolumnleft'}) { $opts{'twocolumnleft'} = delete($opts{'-twocolumnleft'}); }
  0         0  
1780 222 50 33     577 if (defined $opts{'-twocolumnright'} && !defined $opts{'twocolumnright'}) { $opts{'twocolumnright'} = delete($opts{'-twocolumnright'}); }
  0         0  
1781             # Viewer Preferences
1782 222 50 33     565 if (defined $opts{'-hidetoolbar'} && !defined $opts{'hidetoolbar'}) { $opts{'hidetoolbar'} = delete($opts{'-hidetoolbar'}); }
  0         0  
1783 222 50 33     575 if (defined $opts{'-hidemenubar'} && !defined $opts{'hidemenubar'}) { $opts{'hidemenubar'} = delete($opts{'-hidemenubar'}); }
  0         0  
1784 222 50 33     594 if (defined $opts{'-hidewindowui'} && !defined $opts{'hidewindowui'}) { $opts{'hidewindowui'} = delete($opts{'-hidewindowui'}); }
  0         0  
1785 222 50 33     575 if (defined $opts{'-fitwindow'} && !defined $opts{'fitwindow'}) { $opts{'fitwindow'} = delete($opts{'-fitwindow'}); }
  0         0  
1786 222 50 33     553 if (defined $opts{'-centerwindow'} && !defined $opts{'centerwindow'}) { $opts{'centerwindow'} = delete($opts{'-centerwindow'}); }
  0         0  
1787 222 50 33     603 if (defined $opts{'-displaytitle'} && !defined $opts{'displaytitle'}) { $opts{'displaytitle'} = delete($opts{'-displaytitle'}); }
  0         0  
1788 222 50 33     601 if (defined $opts{'-righttoleft'} && !defined $opts{'righttoleft'}) { $opts{'righttoleft'} = delete($opts{'-righttoleft'}); }
  0         0  
1789 222 50 33     662 if (defined $opts{'-afterfullscreenthumbs'} && !defined $opts{'afterfullscreenthumbs'}) { $opts{'afterfullscreenthumbs'} = delete($opts{'-afterfullscreenthumbs'}); }
  0         0  
1790 222 50 33     550 if (defined $opts{'-afterfullscreenoutlines'} && !defined $opts{'afterfullscreenoutlines'}) { $opts{'afterfullscreenoutlines'} = delete($opts{'-afterfullscreenoutlines'}); }
  0         0  
1791 222 50 33     542 if (defined $opts{'-printscalingnone'} && !defined $opts{'printscalingnone'}) { $opts{'printscalingnone'} = delete($opts{'-printscalingnone'}); }
  0         0  
1792 222 100 66     540 if (defined $opts{'-simplex'} && !defined $opts{'simplex'}) { $opts{'simplex'} = delete($opts{'-simplex'}); }
  1         5  
1793 222 100 66     566 if (defined $opts{'-duplexfliplongedge'} && !defined $opts{'duplexfliplongedge'}) { $opts{'duplexfliplongedge'} = delete($opts{'-duplexfliplongedge'}); }
  1         10  
1794 222 100 66     548 if (defined $opts{'-duplexflipshortedge'} && !defined $opts{'duplexflipshortedge'}) { $opts{'duplexflipshortedge'} = delete($opts{'-duplexflipshortedge'}); }
  1         3  
1795             # Open Action
1796 222 100 66     548 if (defined $opts{'-firstpage'} && !defined $opts{'firstpage'}) { $opts{'firstpage'} = delete($opts{'-firstpage'}); }
  2         5  
1797 222 50 33     578 if (defined $opts{'-fit'} && !defined $opts{'fit'}) { $opts{'fit'} = delete($opts{'-fit'}); }
  0         0  
1798 222 50 33     605 if (defined $opts{'-fith'} && !defined $opts{'fith'}) { $opts{'fith'} = delete($opts{'-fith'}); }
  0         0  
1799 222 50 33     561 if (defined $opts{'-fitb'} && !defined $opts{'fitb'}) { $opts{'fitb'} = delete($opts{'-fitb'}); }
  0         0  
1800 222 50 33     602 if (defined $opts{'-fitbh'} && !defined $opts{'fitbh'}) { $opts{'fitbh'} = delete($opts{'-fitbh'}); }
  0         0  
1801 222 50 33     531 if (defined $opts{'-fitv'} && !defined $opts{'fitv'}) { $opts{'fitv'} = delete($opts{'-fitv'}); }
  0         0  
1802 222 50 33     562 if (defined $opts{'-fitbv'} && !defined $opts{'fitbv'}) { $opts{'fitbv'} = delete($opts{'-fitbv'}); }
  0         0  
1803 222 50 33     537 if (defined $opts{'-fitr'} && !defined $opts{'fitr'}) { $opts{'fitr'} = delete($opts{'-fitr'}); }
  0         0  
1804 222 50 33     564 if (defined $opts{'-xyz'} && !defined $opts{'xyz'}) { $opts{'xyz'} = delete($opts{'-xyz'}); }
  0         0  
1805              
1806             # Page Mode Options
1807 222 50       775 if ($opts{'fullscreen'}) {
    50          
    50          
1808 0         0 $self->{'catalog'}->{'PageMode'} = PDFName('FullScreen');
1809             } elsif ($opts{'thumbs'}) {
1810 0         0 $self->{'catalog'}->{'PageMode'} = PDFName('UseThumbs');
1811             } elsif ($opts{'outlines'}) {
1812 0         0 $self->{'catalog'}->{'PageMode'} = PDFName('UseOutlines');
1813             } else {
1814 222         633 $self->{'catalog'}->{'PageMode'} = PDFName('UseNone');
1815             }
1816              
1817             # Page Layout Options
1818 222 50       1109 if ($opts{'singlepage'}) {
    50          
    50          
    50          
1819 0         0 $self->{'catalog'}->{'PageLayout'} = PDFName('SinglePage');
1820             } elsif ($opts{'onecolumn'}) {
1821 0         0 $self->{'catalog'}->{'PageLayout'} = PDFName('OneColumn');
1822             } elsif ($opts{'twocolumnleft'}) {
1823 0         0 $self->{'catalog'}->{'PageLayout'} = PDFName('TwoColumnLeft');
1824             } elsif ($opts{'twocolumnright'}) {
1825 0         0 $self->{'catalog'}->{'PageLayout'} = PDFName('TwoColumnRight');
1826             } else {
1827 222         568 $self->{'catalog'}->{'PageLayout'} = PDFName('SinglePage');
1828             }
1829              
1830             # Viewer Preferences
1831 222   66     1037 $self->{'catalog'}->{'ViewerPreferences'} ||= PDFDict();
1832 222         973 $self->{'catalog'}->{'ViewerPreferences'}->realise();
1833              
1834 222 50       551 if ($opts{'hidetoolbar'}) {
1835 0         0 $self->{'catalog'}->{'ViewerPreferences'}->{'HideToolbar'} = PDFBool(1);
1836             }
1837 222 50       532 if ($opts{'hidemenubar'}) {
1838 0         0 $self->{'catalog'}->{'ViewerPreferences'}->{'HideMenubar'} = PDFBool(1);
1839             }
1840 222 50       527 if ($opts{'hidewindowui'}) {
1841 0         0 $self->{'catalog'}->{'ViewerPreferences'}->{'HideWindowUI'} = PDFBool(1);
1842             }
1843 222 50       527 if ($opts{'fitwindow'}) {
1844 0         0 $self->{'catalog'}->{'ViewerPreferences'}->{'FitWindow'} = PDFBool(1);
1845             }
1846 222 50       531 if ($opts{'centerwindow'}) {
1847 0         0 $self->{'catalog'}->{'ViewerPreferences'}->{'CenterWindow'} = PDFBool(1);
1848             }
1849 222 50       508 if ($opts{'displaytitle'}) {
1850 0         0 $self->{'catalog'}->{'ViewerPreferences'}->{'DisplayDocTitle'} = PDFBool(1);
1851             }
1852 222 50       531 if ($opts{'righttoleft'}) {
1853 0         0 $self->{'catalog'}->{'ViewerPreferences'}->{'Direction'} = PDFName('R2L');
1854             }
1855              
1856 222 50       719 if ($opts{'afterfullscreenthumbs'}) {
    50          
1857 0         0 $self->{'catalog'}->{'ViewerPreferences'}->{'NonFullScreenPageMode'} = PDFName('UseThumbs');
1858             } elsif ($opts{'afterfullscreenoutlines'}) {
1859 0         0 $self->{'catalog'}->{'ViewerPreferences'}->{'NonFullScreenPageMode'} = PDFName('UseOutlines');
1860             } else {
1861 222         529 $self->{'catalog'}->{'ViewerPreferences'}->{'NonFullScreenPageMode'} = PDFName('UseNone');
1862             }
1863              
1864 222 50       612 if ($opts{'printscalingnone'}) {
1865 0         0 $self->{'catalog'}->{'ViewerPreferences'}->{'PrintScaling'} = PDFName('None');
1866             }
1867              
1868 222 100       836 if ($opts{'simplex'}) {
    100          
    100          
1869 1         9 $self->{'catalog'}->{'ViewerPreferences'}->{'Duplex'} = PDFName('Simplex');
1870             } elsif ($opts{'duplexfliplongedge'}) {
1871 1         4 $self->{'catalog'}->{'ViewerPreferences'}->{'Duplex'} = PDFName('DuplexFlipLongEdge');
1872             } elsif ($opts{'duplexflipshortedge'}) {
1873 1         4 $self->{'catalog'}->{'ViewerPreferences'}->{'Duplex'} = PDFName('DuplexFlipShortEdge');
1874             }
1875              
1876             # Open Action
1877 222 100       502 if ($opts{'firstpage'}) {
1878 2         3 my ($page, %args) = @{$opts{'firstpage'}};
  2         6  
1879 2 50       8 $args{'fit'} = 1 unless scalar keys %args;
1880              
1881             # $page can be either a page number (which needs to be wrapped
1882             # in PDFNum) or a page object (which doesn't).
1883 2 100       7 $page = PDFNum($page) unless ref($page);
1884              
1885             # copy dashed args names to preferred undashed names
1886 2 50 33     11 if (defined $args{'-fit'} && !defined $args{'fit'}) { $args{'fit'} = delete($args{'-fit'}); }
  2         5  
1887 2 50 33     21 if (defined $args{'-fith'} && !defined $args{'fith'}) { $args{'fith'} = delete($args{'-fith'}); }
  0         0  
1888 2 50 33     7 if (defined $args{'-fitb'} && !defined $args{'fitb'}) { $args{'fitb'} = delete($args{'-fitb'}); }
  0         0  
1889 2 50 33     5 if (defined $args{'-fitbh'} && !defined $args{'fitbh'}) { $args{'fitbh'} = delete($args{'-fitbh'}); }
  0         0  
1890 2 50 33     6 if (defined $args{'-fitv'} && !defined $args{'fitv'}) { $args{'fitv'} = delete($args{'-fitv'}); }
  0         0  
1891 2 50 33     6 if (defined $args{'-fitbv'} && !defined $args{'fitbv'}) { $args{'fitbv'} = delete($args{'-fitbv'}); }
  0         0  
1892 2 50 33     6 if (defined $args{'-fitr'} && !defined $args{'fitr'}) { $args{'fitr'} = delete($args{'-fitr'}); }
  0         0  
1893 2 50 33     6 if (defined $args{'-xyz'} && !defined $args{'xyz'}) { $args{'xyz'} = delete($args{'-xyz'}); }
  0         0  
1894            
1895 2 50       6 if (defined $args{'fit'}) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1896 2         6 $self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('Fit'));
1897             } elsif (defined $args{'fith'}) {
1898 0         0 $self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('FitH'), PDFNum($args{'fith'}));
1899             } elsif (defined $args{'fitb'}) {
1900 0         0 $self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('FitB'));
1901             } elsif (defined $args{'fitbh'}) {
1902 0         0 $self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('FitBH'), PDFNum($args{'fitbh'}));
1903             } elsif (defined $args{'fitv'}) {
1904 0         0 $self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('FitV'), PDFNum($args{'fitv'}));
1905             } elsif (defined $args{'fitbv'}) {
1906 0         0 $self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('FitBV'), PDFNum($args{'fitbv'}));
1907             } elsif (defined $args{'fitr'}) {
1908 0 0       0 croak 'insufficient parameters to fitr => []' unless scalar @{$args{'fitr'}} == 4;
  0         0  
1909             $self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('FitR'),
1910 0         0 map { PDFNum($_) } @{$args{'fitr'}});
  0         0  
  0         0  
1911             } elsif (defined $args{'xyz'}) {
1912 0 0       0 croak 'insufficient parameters to xyz => []' unless scalar @{$args{'xyz'}} == 3;
  0         0  
1913             $self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('XYZ'),
1914 0         0 map { PDFNum($_) } @{$args{'xyz'}});
  0         0  
  0         0  
1915             }
1916             }
1917 222         952 $self->{'pdf'}->out_obj($self->{'catalog'});
1918              
1919 222         483 return $self;
1920             } # end of preferences()
1921              
1922             sub proc_pages {
1923 0     0 0 0 my ($pdf, $object) = @_;
1924              
1925 0 0       0 if (defined $object->{'Resources'}) {
1926 0         0 eval {
1927 0         0 $object->{'Resources'}->realise();
1928             };
1929             }
1930              
1931 0         0 my @pages;
1932 0   0     0 $pdf->{' apipagecount'} ||= 0;
1933 0         0 foreach my $page ($object->{'Kids'}->elements()) {
1934 0         0 $page->realise();
1935 0 0       0 if ($page->{'Type'}->val() eq 'Pages') {
1936 0         0 push @pages, proc_pages($pdf, $page);
1937             }
1938             else {
1939 0         0 $pdf->{' apipagecount'}++;
1940 0         0 $page->{' pnum'} = $pdf->{' apipagecount'};
1941 0 0       0 if (defined $page->{'Resources'}) {
1942 0         0 eval {
1943 0         0 $page->{'Resources'}->realise();
1944             };
1945             }
1946 0         0 push @pages, $page;
1947             }
1948             }
1949              
1950 0         0 return @pages;
1951             }
1952              
1953             =back
1954              
1955             =head1 PAGE METHODS
1956              
1957             =over
1958              
1959             =item $page = $pdf->page()
1960              
1961             =item $page = $pdf->page($page_number)
1962              
1963             Returns a I page object. By default, the page is added to the end
1964             of the document. If you give an existing page number, the new page
1965             will be inserted in that position, pushing existing pages back by 1 (e.g.,
1966             C would insert an empty page 5, with the old page 5 now page 6,
1967             etc.
1968              
1969             If $page_number is -1, the new page is inserted as the second-to-last page;
1970             if $page_number is 0, the new page is inserted as the last page.
1971              
1972             B
1973              
1974             $pdf = PDF::Builder->new();
1975              
1976             # Add a page. This becomes page 1.
1977             $page = $pdf->page();
1978              
1979             # Add a new first page. $page becomes page 2.
1980             $another_page = $pdf->page(1);
1981              
1982             =cut
1983              
1984             sub page {
1985 194     194 1 19440 my $self = shift();
1986 194   100     652 my $index = shift() || 0; # default to new "last" page
1987 194         295 my $page;
1988              
1989 194 100       473 if ($index == 0) {
1990 192         1302 $page = PDF::Builder::Page->new($self->{'pdf'}, $self->{'pages'});
1991             } else {
1992 2         10 $page = PDF::Builder::Page->new($self->{'pdf'}, $self->{'pages'}, $index-1);
1993             }
1994              
1995 194         471 $page->{' apipdf'} = $self->{'pdf'};
1996 194         568 $page->{' api'} = $self;
1997 194         589 weaken $page->{' apipdf'};
1998 194         465 weaken $page->{' api'};
1999 194         598 $self->{'pdf'}->out_obj($page);
2000 194         590 $self->{'pdf'}->out_obj($self->{'pages'});
2001              
2002             # fix any bad $index value
2003 194         295 my $pgs_size = @{$self->{'pagestack'}};
  194         403  
2004 194 100       603 if ($pgs_size == 0) { # empty page list, can only add at end
    50          
    50          
2005 182 50       457 warn "page($index) on empty page stack is out of range, use page() or page(0)"
2006             if ($index != 0);
2007 182         296 $index = 0;
2008             } elsif ($pgs_size < -$index) { # index < 0
2009 0         0 warn "page($index) out of range, set to page(1) (before first)";
2010 0         0 $index = 1;
2011             } elsif ($pgs_size < $index) { # index > 0
2012 0         0 warn "page($index) out of range, set to page(0) (after last)";
2013 0         0 $index = 0;
2014             }
2015              
2016 194 100       400 if ($index == 0) {
    50          
2017 192         300 push @{$self->{'pagestack'}}, $page;
  192         404  
2018 192         687 weaken $self->{'pagestack'}->[-1];
2019             } elsif ($index < 0) {
2020             # note that the new element's number is one less than $index,
2021             # since we inserted _before_ $index value!
2022 0         0 splice @{$self->{'pagestack'}}, $index, 0, $page;
  0         0  
2023 0         0 weaken $self->{'pagestack'}->[$index-1];
2024             } else { # index > 0
2025 2         3 splice @{$self->{'pagestack'}}, $index-1, 0, $page;
  2         15  
2026 2         10 weaken $self->{'pagestack'}->[$index-1];
2027             }
2028              
2029             # $page->{'Resources'}=$self->{'pages'}->{'Resources'};
2030 194         1035 return $page;
2031             } # end of page()
2032              
2033             =item $page = $pdf->open_page($page_number)
2034              
2035             Returns the L object of page $page_number.
2036             This is similar to C<< $page = $pdf->page() >>, except that C<$page> is
2037             I a new, empty page; but contains the contents of that existing page.
2038              
2039             If C<$page_number> is 0, -1, or unspecified,
2040             it will return the last page in the document.
2041             If the requested page is out of range, the C<$page> returned will be undefined.
2042              
2043             B
2044              
2045             $pdf = PDF::Builder->open('our/99page.pdf');
2046             $page = $pdf->open_page(1); # returns the first page
2047             $page = $pdf->open_page(99); # returns the last page
2048             $page = $pdf->open_page(-1); # returns the last page
2049             $page = $pdf->open_page(999); # returns undef
2050             $page = $pdf->open_page(0); # returns the last page
2051             $page = $pdf->open_page(); # returns the last page
2052              
2053             B C
2054              
2055             This is the older name; it is kept for compatibility until after June 2023
2056             (deprecated, as previously announced).
2057              
2058             =cut
2059              
2060 1     1 0 13 sub openpage { return open_page(@_); } ## no critic
2061              
2062             sub open_page {
2063 7     7 1 804 my $self = shift();
2064 7   50     21 my $index = shift() || 0;
2065 7         18 my ($page, $rotate, $media, $trans);
2066              
2067 7 50       32 if ($index == 0) {
    50          
2068 0         0 $page = $self->{'pagestack'}->[-1];
2069             } elsif ($index < 0) {
2070 0         0 $page = $self->{'pagestack'}->[$index];
2071             } else {
2072 7         25 $page = $self->{'pagestack'}->[$index - 1];
2073             }
2074 7 50       24 return unless ref($page);
2075              
2076 7 100       24 if (ref($page) ne 'PDF::Builder::Page') {
2077 6         28 bless $page, 'PDF::Builder::Page';
2078 6         25 $page->{' apipdf'} = $self->{'pdf'};
2079 6         15 $page->{' api'} = $self;
2080 6         49 weaken $page->{' apipdf'};
2081 6         22 weaken $page->{' api'};
2082 6         29 $self->{'pdf'}->out_obj($page);
2083 6 50 33     37 if (($rotate = $page->find_prop('Rotate')) and not $page->{' opened'}) {
2084 0         0 $rotate = ($rotate->val() + 360) % 360;
2085              
2086 0 0 0     0 if ($rotate != 0 and not $self->default('nounrotate')) {
2087 0         0 $page->{'Rotate'} = PDFNum(0);
2088 0         0 foreach my $mediatype (qw(MediaBox CropBox BleedBox TrimBox ArtBox)) {
2089 0 0       0 if ($media = $page->find_prop($mediatype)) {
2090 0         0 $media = [ map { $_->val() } $media->elements() ];
  0         0  
2091             } else {
2092 0         0 $media = [0, 0, 612, 792]; # US Letter default
2093 0 0       0 next if $mediatype ne 'MediaBox';
2094             }
2095 0 0       0 if ($rotate == 90) {
    0          
    0          
2096 0 0       0 $trans = "0 -1 1 0 0 $media->[2] cm" if $mediatype eq 'MediaBox';
2097 0         0 $media = [$media->[1], $media->[0], $media->[3], $media->[2]];
2098             } elsif ($rotate == 180) {
2099 0 0       0 $trans = "-1 0 0 -1 $media->[2] $media->[3] cm" if $mediatype eq 'MediaBox';
2100             } elsif ($rotate == 270) {
2101 0 0       0 $trans = "0 1 -1 0 $media->[3] 0 cm" if $mediatype eq 'MediaBox';
2102 0         0 $media = [$media->[1], $media->[0], $media->[3], $media->[2]];
2103             }
2104 0         0 $page->{$mediatype} = PDFArray(map { PDFNum($_) } @$media);
  0         0  
2105             }
2106             } else {
2107 0         0 $trans = '';
2108             }
2109             } else {
2110 6         14 $trans = '';
2111             }
2112              
2113 6 100 66     43 if (defined $page->{'Contents'} and not $page->{' opened'}) {
2114 4         21 $page->fixcontents();
2115 4         13 my $uncontent = delete $page->{'Contents'};
2116 4         18 my $content = $page->gfx();
2117 4         26 $content->add(" $trans ");
2118              
2119 4 50       25 if ($self->default('pageencaps')) {
2120 0         0 $content->{' stream'} .= ' q ';
2121             }
2122 4         23 foreach my $k ($uncontent->elements()) {
2123 4         20 $k->realise();
2124 4         39 $content->{' stream'} .= ' ' . unfilter($k->{'Filter'}, $k->{' stream'}) . ' ';
2125             }
2126 4 50       14 if ($self->default('pageencaps')) {
2127 0         0 $content->{' stream'} .= ' Q ';
2128             }
2129              
2130             # if we like compress we will do it now to do quicker saves
2131 4 50 33     37 if ($self->{'forcecompress'} eq 'flate' ||
2132             $self->{'forcecompress'} =~ m/^[1-9]\d*$/) {
2133 4         23 $content->{' stream'} = dofilter($content->{'Filter'}, $content->{' stream'});
2134 4         10 $content->{' nofilt'} = 1;
2135 4         10 delete $content->{'-docompress'};
2136 4         17 $content->{'Length'} = PDFNum(length($content->{' stream'}));
2137             }
2138             }
2139 6         29 $page->{' opened'} = 1;
2140             }
2141              
2142 7         35 $self->{'pdf'}->out_obj($page);
2143 7         28 $self->{'pdf'}->out_obj($self->{'pages'});
2144 7         21 $page->{' apipdf'} = $self->{'pdf'};
2145 7         19 $page->{' api'} = $self;
2146 7         26 weaken $page->{' apipdf'};
2147 7         21 weaken $page->{' api'};
2148              
2149 7         18 return $page;
2150             } # end of open_page()
2151              
2152             =item $page = $pdf->import_page($source_pdf)
2153              
2154             =item $page = $pdf->import_page($source_pdf, $source_page_number)
2155              
2156             =item $page = $pdf->import_page($source_pdf, $source_page_number, $target_page_number)
2157              
2158             =item $page = $pdf->import_page($source_pdf, $source_page_number, $target_page_object)
2159              
2160             Imports a page from $source_pdf and adds it to the specified position
2161             in $pdf.
2162              
2163             If the C<$source_page_number> is omitted, 0, or -1; the last page of the
2164             source is imported.
2165             If the C<$target_page_number> is omitted, 0, or -1; the imported page will be
2166             placed as the new last page of the target (C<$pdf>).
2167             Otherwise, as with the C method, the page will be inserted before an
2168             existing page of that number.
2169              
2170             B If you pass a page I instead of a page I for
2171             C<$target_page_number>, the contents of the page will be B into the
2172             existing page.
2173              
2174             B
2175              
2176             my $pdf = PDF::Builder->new();
2177             my $source = PDF::Builder->open('source.pdf');
2178              
2179             # Add page 2 from the old PDF as page 1 of the new PDF
2180             my $page = $pdf->import_page($source, 2);
2181              
2182             $pdf->saveas('sample.pdf');
2183              
2184             B You can only import a page from an existing PDF file.
2185              
2186             =cut
2187              
2188             # removed years ago, but is still in API2, so for code compatibility...
2189 0     0 0 0 sub importpage{ return import_page(@_); } ## no critic
2190              
2191             sub import_page {
2192 1     1 1 8 my ($self, $s_pdf, $s_idx, $t_idx) = @_;
2193              
2194 1   50     5 $s_idx ||= 0; # default to last page
2195 1   50     19 $t_idx ||= 0; # default to last page
2196 1         139 my ($s_page, $t_page);
2197              
2198 1 50 33     140 unless (ref($s_pdf) and $s_pdf->isa('PDF::Builder')) {
2199 0         0 croak "Invalid usage: first argument must be PDF::Builder instance, not: " . ref($s_pdf);
2200             }
2201              
2202 1 50       13 if (ref($s_idx) eq 'PDF::Builder::Page') {
2203 0         0 $s_page = $s_idx;
2204             } else {
2205 1         8 $s_page = $s_pdf->open_page($s_idx);
2206 1 50       4 croak "Unable to open page '$s_idx' in source PDF" unless defined $s_page;
2207             }
2208              
2209 1 50       4 if (ref($t_idx) eq 'PDF::Builder::Page') {
2210 0         0 $t_page = $t_idx;
2211             } else {
2212 1 50       5 if ($self->pages() < $t_idx) {
2213 0         0 $t_page = $self->page();
2214             } else {
2215 1         4 $t_page = $self->page($t_idx);
2216             }
2217             }
2218              
2219 1   50     10 $self->{'apiimportcache'} = $self->{'apiimportcache'} || {};
2220 1   50     21 $self->{'apiimportcache'}->{$s_pdf} = $self->{'apiimportcache'}->{$s_pdf} || {};
2221              
2222             # we now import into a form to keep
2223             # all those nasty resources from polluting
2224             # our very own resource naming space.
2225 1         10 my $xo = $self->importPageIntoForm($s_pdf, $s_page);
2226              
2227             # copy all page dimensions
2228 1         5 foreach my $k (qw(MediaBox ArtBox TrimBox BleedBox CropBox)) {
2229 5         13 my $prop = $s_page->find_prop($k);
2230 5 100       10 next unless defined $prop;
2231              
2232 1         4 my $box = _walk_obj({}, $s_pdf->{'pdf'}, $self->{'pdf'}, $prop);
2233 1         3 my $method = lc $k;
2234              
2235 1         4 $t_page->$method(map { $_->val() } $box->elements());
  4         9  
2236             }
2237              
2238 1         5 $t_page->gfx()->formimage($xo, 0, 0, 1);
2239              
2240             # copy annotations and/or form elements as well
2241 1 0 33     15 if (exists $s_page->{'Annots'} and $s_page->{'Annots'} and $self->{'copyannots'}) {
      0        
2242             # first set up the AcroForm, if required
2243 0         0 my $AcroForm;
2244 0 0       0 if (my $a = $s_pdf->{'pdf'}->{'Root'}->realise()->{'AcroForm'}) {
2245 0         0 $a->realise();
2246              
2247 0         0 $AcroForm = _walk_obj({}, $s_pdf->{'pdf'}, $self->{'pdf'}, $a,
2248             qw(NeedAppearances SigFlags CO DR DA Q));
2249             }
2250 0         0 my @Fields = ();
2251 0         0 my @Annots = ();
2252 0         0 foreach my $a ($s_page->{'Annots'}->elements()) {
2253 0         0 $a->realise();
2254 0         0 my $t_a = PDFDict();
2255 0         0 $self->{'pdf'}->new_obj($t_a);
2256             # these objects are likely to be both annotations and Acroform fields
2257             # key names are copied from PDF Reference 1.4 (Tables)
2258 0         0 my @k = (
2259             qw( Type Subtype Contents P Rect NM M F BS Border AP AS C CA T Popup A AA StructParent Rotate
2260             ), # Annotations - Common (8.10)
2261             qw( Subtype Contents Open Name ), # Text Annotations (8.15)
2262             qw( Subtype Contents Dest H PA ), # Link Annotations (8.16)
2263             qw( Subtype Contents DA Q ), # Free Text Annotations (8.17)
2264             qw( Subtype Contents L BS LE IC ), # Line Annotations (8.18)
2265             qw( Subtype Contents BS IC ), # Square and Circle Annotations (8.20)
2266             qw( Subtype Contents QuadPoints ), # Markup Annotations (8.21)
2267             qw( Subtype Contents Name ), # Rubber Stamp Annotations (8.22)
2268             qw( Subtype Contents InkList BS ), # Ink Annotations (8.23)
2269             qw( Subtype Contents Parent Open ), # Popup Annotations (8.24)
2270             qw( Subtype FS Contents Name ), # File Attachment Annotations (8.25)
2271             qw( Subtype Sound Contents Name ), # Sound Annotations (8.26)
2272             qw( Subtype Movie Contents A ), # Movie Annotations (8.27)
2273             qw( Subtype Contents H MK ), # Widget Annotations (8.28)
2274             # Printers Mark Annotations (none)
2275             # Trap Network Annotations (none)
2276             );
2277 0 0       0 push @k, (
2278             qw( Subtype FT Parent Kids T TU TM Ff V DV AA
2279             ), # Fields - Common (8.49)
2280             qw( DR DA Q ), # Fields containing variable text (8.51)
2281             qw( Opt ), # Checkbox field (8.54)
2282             qw( Opt ), # Radio field (8.55)
2283             qw( MaxLen ), # Text field (8.57)
2284             qw( Opt TI I ), # Choice field (8.59)
2285             ) if $AcroForm;
2286              
2287             # sorting out dupes
2288 0         0 my %ky = map { $_ => 1 } @k;
  0         0  
2289             # we do P separately, as it points to the page the Annotation is on
2290 0         0 delete $ky{'P'};
2291             # copy everything else
2292 0         0 foreach my $k (keys %ky) {
2293 0 0       0 next unless defined $a->{$k};
2294 0         0 $a->{$k}->realise();
2295 0         0 $t_a->{$k} = _walk_obj({}, $s_pdf->{'pdf'}, $self->{'pdf'}, $a->{$k});
2296             }
2297 0         0 $t_a->{'P'} = $t_page;
2298 0         0 push @Annots, $t_a;
2299 0 0 0     0 push @Fields, $t_a if ($AcroForm and $t_a->{'Subtype'}->val() eq 'Widget');
2300             }
2301 0         0 $t_page->{'Annots'} = PDFArray(@Annots);
2302 0 0       0 $AcroForm->{'Fields'} = PDFArray(@Fields) if $AcroForm;
2303 0         0 $self->{'pdf'}->{'Root'}->{'AcroForm'} = $AcroForm;
2304             }
2305 1         3 $t_page->{' imported'} = 1;
2306              
2307 1         5 $self->{'pdf'}->out_obj($t_page);
2308 1         4 $self->{'pdf'}->out_obj($self->{'pages'});
2309              
2310 1         3 return $t_page;
2311             } # end of import_page()
2312              
2313             =item $xoform = $pdf->embed_page($source_pdf, $source_page_number)
2314              
2315             Returns a Form XObject created by extracting the specified page from
2316             C<$source_pdf>.
2317              
2318             This is useful if you want to transpose the imported page somewhat
2319             differently onto a page (e.g. two-up, four-up, etc.).
2320              
2321             If C<$source_page_number> is 0 or -1, it will return the last page in the
2322             document.
2323              
2324             B
2325              
2326             my $pdf = PDF::Builder->new();
2327             my $source = PDF::Builder->open('source.pdf');
2328             my $page = $pdf->page();
2329              
2330             # Import Page 2 from the source PDF
2331             my $object = $pdf->embed_page($source, 2);
2332              
2333             # Add it to the new PDF's first page at 1/2 scale
2334             my ($x, $y) = (0, 0);
2335             $page->object($xo, $x, $y, 0.5);
2336              
2337             $pdf->save('sample.pdf');
2338              
2339             B You can only import a page from an existing PDF file.
2340              
2341             B C
2342              
2343             This is the older name; it is kept for compatibility.
2344              
2345             =cut
2346              
2347 4     4 0 43 sub importPageIntoForm { return embed_page(@_); } ## no critic
2348              
2349             sub embed_page {
2350 4     4 1 14 my ($self, $s_pdf, $s_idx) = @_;
2351 4   50     15 $s_idx ||= 0;
2352              
2353 4 50 33     43 unless (ref($s_pdf) and $s_pdf->isa('PDF::Builder')) {
2354 0         0 croak "Invalid usage: first argument must be PDF::Builder instance, not: " . ref($s_pdf);
2355             }
2356              
2357 4         10 my ($s_page, $xo);
2358              
2359 4         33 $xo = $self->xo_form();
2360              
2361 4 100       23 if (ref($s_idx) eq 'PDF::Builder::Page') {
2362 1         10 $s_page = $s_idx;
2363             } else {
2364 3         18 $s_page = $s_pdf->open_page($s_idx);
2365 3 50       11 croak "Unable to open page '$s_idx' in source PDF" unless defined $s_page;
2366             }
2367              
2368 4   100     43 $self->{'apiimportcache'} ||= {};
2369 4   100     30 $self->{'apiimportcache'}->{$s_pdf} ||= {};
2370              
2371             # This should never get past MediaBox, since it's a required object.
2372 4         15 foreach my $k (qw(MediaBox ArtBox TrimBox BleedBox CropBox)) {
2373             #next unless defined $s_page->{$k};
2374             #my $box = _walk_obj($self->{'apiimportcache'}->{$s_pdf}, $s_pdf->{'pdf'},
2375             # $self->{'pdf'}, $s_page->{$k});
2376 4 50       17 next unless defined $s_page->find_prop($k);
2377             my $box = _walk_obj($self->{'apiimportcache'}->{$s_pdf}, $s_pdf->{'pdf'},
2378 4         20 $self->{'pdf'}, $s_page->find_prop($k));
2379 4         26 $xo->bbox(map { $_->val() } $box->elements());
  16         38  
2380 4         13 last;
2381             }
2382 4 50       22 $xo->bbox(0,0, 612,792) unless defined $xo->{'BBox'}; # US Letter default
2383              
2384 4         13 foreach my $k (qw(Resources)) {
2385 4         20 $s_page->{$k} = $s_page->find_prop($k);
2386 4 50       17 next unless defined $s_page->{$k};
2387 4 50       26 $s_page->{$k}->realise() if ref($s_page->{$k}) =~ /Objind$/;
2388              
2389 4         17 foreach my $sk (qw(XObject ExtGState Font ProcSet Properties ColorSpace Pattern Shading)) {
2390 32 100       88 next unless defined $s_page->{$k}->{$sk};
2391 5 50       24 $s_page->{$k}->{$sk}->realise() if ref($s_page->{$k}->{$sk}) =~ /Objind$/;
2392 5         12 foreach my $ssk (keys %{$s_page->{$k}->{$sk}}) {
  5         23  
2393 10 100       48 next if $ssk =~ /^ /;
2394             $xo->resource($sk, $ssk, _walk_obj($self->{'apiimportcache'}->{$s_pdf},
2395 1         6 $s_pdf->{'pdf'}, $self->{'pdf'}, $s_page->{$k}->{$sk}->{$ssk}));
2396             }
2397             }
2398             }
2399              
2400             # create a whole content stream
2401             ## technically it is possible to submit an unfinished
2402             ## (e.g., newly created) source-page, but that's nonsense,
2403             ## so we expect a page fixed by open_page and croak otherwise
2404 4 50       27 unless ($s_page->{' opened'}) {
2405 0         0 croak "Pages may only be imported from a complete PDF. Save and reopen the source PDF object first.";
2406             }
2407              
2408 4 100       14 if (defined $s_page->{'Contents'}) {
2409 3         18 $s_page->fixcontents();
2410              
2411 3         8 $xo->{' stream'} = '';
2412             # open_page pages only contain one stream
2413 3         26 my ($k) = $s_page->{'Contents'}->elements();
2414 3         40 $k->realise();
2415 3 50       13 if ($k->{' nofilt'}) {
2416             # we have a finished stream here, so we unfilter
2417 3         27 $xo->add('q', unfilter($k->{'Filter'}, $k->{' stream'}), 'Q');
2418             } else {
2419             # stream is an unfinished/unfiltered content
2420             # so we just copy it and add the required "qQ"
2421 0         0 $xo->add('q', $k->{' stream'}, 'Q');
2422             }
2423             $xo->compressFlate() if $self->{'forcecompress'} eq 'flate' ||
2424 3 100 66     31 $self->{'forcecompress'} =~ m/^[1-9]\d*$/;
2425             }
2426              
2427 4         67 return $xo;
2428             } # end of embed_page()
2429              
2430             # internal utility used by embed_page and import_page
2431              
2432             sub _walk_obj {
2433 518     518   865 my ($object_cache, $source_pdf, $target_pdf, $source_object, @keys) = @_;
2434              
2435 518 100       938 if (ref($source_object) =~ /Objind$/) {
2436 1         5 $source_object->realise();
2437             }
2438              
2439 518 50       1104 return $object_cache->{scalar $source_object} if defined $object_cache->{scalar $source_object};
2440             #croak "infinite loop while copying objects" if $source_object->{' copied'};
2441              
2442 518         1049 my $target_object = $source_object->copy($source_pdf); ## thanks to: yaheath // Fri, 17 Sep 2004
2443              
2444             #$source_object->{' copied'} = 1;
2445 518 100       982 $target_pdf->new_obj($target_object) if $source_object->is_obj($source_pdf);
2446              
2447 518         1535 $object_cache->{scalar $source_object} = $target_object;
2448              
2449 518 100       1442 if (ref($source_object) =~ /Array$/) {
    100          
2450 7         129 $target_object->{' val'} = [];
2451 7         33 foreach my $k ($source_object->elements()) {
2452 501 50       1028 $k->realise() if ref($k) =~ /Objind$/;
2453 501         837 $target_object->add_elements(_walk_obj($object_cache, $source_pdf, $target_pdf, $k));
2454             }
2455             } elsif (ref($source_object) =~ /Dict$/) {
2456 2 50       18 @keys = keys(%$target_object) unless scalar @keys;
2457 2         7 foreach my $k (@keys) {
2458 12 100       37 next if $k =~ /^ /;
2459 11 50       27 next unless defined $source_object->{$k};
2460 11         29 $target_object->{$k} = _walk_obj($object_cache, $source_pdf, $target_pdf, $source_object->{$k});
2461             }
2462 2 50       7 if ($source_object->{' stream'}) {
2463 0 0       0 if ($target_object->{'Filter'}) {
2464 0         0 $target_object->{' nofilt'} = 1;
2465             } else {
2466 0         0 delete $target_object->{' nofilt'};
2467 0         0 $target_object->{'Filter'} = PDFArray(PDFName('FlateDecode'));
2468             }
2469 0         0 $target_object->{' stream'} = $source_object->{' stream'};
2470             }
2471             }
2472 518         1054 delete $target_object->{' streamloc'};
2473 518         628 delete $target_object->{' streamsrc'};
2474              
2475 518         1561 return $target_object;
2476             } # end of _walk_obj()
2477              
2478             =item $count = $pdf->page_count()
2479              
2480             Returns the number of pages in the document.
2481              
2482             B C
2483              
2484             This is the old name; it is kept for compatibility.
2485              
2486             =cut
2487              
2488 3     3 0 376 sub pages { return page_count(@_); } ## no critic
2489              
2490             sub page_count {
2491 3     3 1 6 my $self = shift();
2492 3         6 return scalar @{$self->{'pagestack'}};
  3         13  
2493             }
2494              
2495             =item $pdf->page_labels($page_number, $opts)
2496              
2497             Sets page label numbering format, for the Reader's page-selection slider thumb
2498             (I the outline/bookmarks). At this time, there is no method to
2499             automatically synchronize a page's label with the outline/bookmarks, or to
2500             somewhere on the printed page.
2501              
2502             Note that many PDF Readers ignore these settings, and (at most) simply give
2503             you the physical page number 1, 2, 3,... instead of the page label specified
2504             here.
2505              
2506             # Generate a 30-page PDF
2507             my $pdf = PDF::Builder->new();
2508             $pdf->page() for 1..30;
2509              
2510             # Number pages i to v, 1 to 20, and A-1 to A-5, respectively
2511             $pdf->page_labels(1, 'style' => 'roman');
2512             $pdf->page_labels(6, 'style' => 'decimal');
2513             $pdf->page_labels(26, 'style' => 'decimal', 'prefix' => 'A-');
2514              
2515             $pdf->save('sample.pdf');
2516              
2517             B
2518              
2519             =over
2520              
2521             =item style
2522              
2523             B (I,II,III,...), B (i,ii,iii,...), B (1,2,3,...),
2524             B (A,B,C,...), B (a,b,c,...), or B. This is the
2525             styling of the counter part of the label (unless C, in which case
2526             there is no counter output).
2527              
2528             =item start
2529              
2530             (Re)start numbering the I at given page number (this is a decimal
2531             integer, I the styled counter). By default it starts at 1, and B
2532             to 1 at each call to C! You need to explicitly give C if
2533             you want to I counting at the current page number when you call
2534             C, whether or not you are changing the format.
2535              
2536             Also note that the counter starts at physical page B<1>, while the page
2537             C<$index> number in the C call (as well as the PDF PageLabels
2538             dictionary) starts at logical page (index) B<0>.
2539              
2540             =item prefix
2541              
2542             Text prefix for numbering, such as an Appendix letter B. If C