| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package PDF::Builder; |
|
2
|
|
|
|
|
|
|
|
|
3
|
39
|
|
|
39
|
|
5431259
|
use strict; |
|
|
39
|
|
|
|
|
118
|
|
|
|
39
|
|
|
|
|
1677
|
|
|
4
|
39
|
|
|
39
|
|
440
|
use warnings; |
|
|
39
|
|
|
|
|
87
|
|
|
|
39
|
|
|
|
|
5638
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
# $VERSION defined here so developers can run PDF::Builder from git. |
|
7
|
|
|
|
|
|
|
# it should be automatically updated as part of the CPAN build. |
|
8
|
|
|
|
|
|
|
our $VERSION = '3.028'; # VERSION |
|
9
|
|
|
|
|
|
|
our $LAST_UPDATE = '3.028'; # manually update whenever code is changed |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
# updated during CPAN build |
|
12
|
|
|
|
|
|
|
my $GrTFversion = 19; # minimum version of Graphics::TIFF |
|
13
|
|
|
|
|
|
|
my $HBShaperVer = 0.024; # minimum version of HarfBuzz::Shaper |
|
14
|
|
|
|
|
|
|
my $LpngVersion = 0.57; # minimum version of Image::PNG::Libpng |
|
15
|
|
|
|
|
|
|
my $TextMarkdown = 1.000031; # minimum version of Text::Markdown |
|
16
|
|
|
|
|
|
|
my $HTMLTreeBldr = 5.07; # minimum version of HTML::TreeBuilder |
|
17
|
|
|
|
|
|
|
my $PodSimpleXHTML = 3.45; # minimum version of Pod::Simple::XHTML |
|
18
|
|
|
|
|
|
|
my $SVGPDFver = 0.087; # minimum version of SVGPDF |
|
19
|
|
|
|
|
|
|
|
|
20
|
39
|
|
|
39
|
|
294
|
use Carp; |
|
|
39
|
|
|
|
|
133
|
|
|
|
39
|
|
|
|
|
3541
|
|
|
21
|
39
|
|
|
39
|
|
25446
|
use Encode qw(:all); |
|
|
39
|
|
|
|
|
844794
|
|
|
|
39
|
|
|
|
|
13036
|
|
|
22
|
39
|
|
|
39
|
|
20487
|
use English; |
|
|
39
|
|
|
|
|
118112
|
|
|
|
39
|
|
|
|
|
246
|
|
|
23
|
39
|
|
|
39
|
|
38983
|
use FileHandle; |
|
|
39
|
|
|
|
|
431993
|
|
|
|
39
|
|
|
|
|
315
|
|
|
24
|
39
|
|
|
39
|
|
32461
|
use version; |
|
|
39
|
|
|
|
|
88297
|
|
|
|
39
|
|
|
|
|
259
|
|
|
25
|
|
|
|
|
|
|
|
|
26
|
39
|
|
|
39
|
|
29185
|
use PDF::Builder::Basic::PDF::Utils; |
|
|
39
|
|
|
|
|
222
|
|
|
|
39
|
|
|
|
|
4947
|
|
|
27
|
39
|
|
|
39
|
|
25169
|
use PDF::Builder::Util; |
|
|
39
|
|
|
|
|
223
|
|
|
|
39
|
|
|
|
|
7594
|
|
|
28
|
|
|
|
|
|
|
|
|
29
|
39
|
|
|
39
|
|
35615
|
use PDF::Builder::Basic::PDF::File; |
|
|
39
|
|
|
|
|
235
|
|
|
|
39
|
|
|
|
|
2510
|
|
|
30
|
39
|
|
|
39
|
|
385
|
use PDF::Builder::Basic::PDF::Pages; |
|
|
39
|
|
|
|
|
190
|
|
|
|
39
|
|
|
|
|
1087
|
|
|
31
|
39
|
|
|
39
|
|
28454
|
use PDF::Builder::Page; |
|
|
39
|
|
|
|
|
220
|
|
|
|
39
|
|
|
|
|
2530
|
|
|
32
|
|
|
|
|
|
|
|
|
33
|
39
|
|
|
39
|
|
29046
|
use PDF::Builder::Resource::XObject::Form::Hybrid; |
|
|
39
|
|
|
|
|
209
|
|
|
|
39
|
|
|
|
|
1812
|
|
|
34
|
|
|
|
|
|
|
|
|
35
|
39
|
|
|
39
|
|
22758
|
use PDF::Builder::Resource::ExtGState; |
|
|
39
|
|
|
|
|
165
|
|
|
|
39
|
|
|
|
|
1675
|
|
|
36
|
39
|
|
|
39
|
|
21479
|
use PDF::Builder::Resource::Pattern; |
|
|
39
|
|
|
|
|
144
|
|
|
|
39
|
|
|
|
|
1670
|
|
|
37
|
39
|
|
|
39
|
|
20924
|
use PDF::Builder::Resource::Shading; |
|
|
39
|
|
|
|
|
141
|
|
|
|
39
|
|
|
|
|
1657
|
|
|
38
|
|
|
|
|
|
|
|
|
39
|
39
|
|
|
39
|
|
22632
|
use PDF::Builder::NamedDestination; |
|
|
39
|
|
|
|
|
157
|
|
|
|
39
|
|
|
|
|
1715
|
|
|
40
|
39
|
|
|
39
|
|
26811
|
use PDF::Builder::FontManager; |
|
|
39
|
|
|
|
|
151
|
|
|
|
39
|
|
|
|
|
2116
|
|
|
41
|
|
|
|
|
|
|
|
|
42
|
39
|
|
|
39
|
|
330
|
use List::Util qw(max); |
|
|
39
|
|
|
|
|
86
|
|
|
|
39
|
|
|
|
|
3315
|
|
|
43
|
39
|
|
|
39
|
|
249
|
use Scalar::Util qw(weaken); |
|
|
39
|
|
|
|
|
88
|
|
|
|
39
|
|
|
|
|
1110205
|
|
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# Note that every Linux distribution seems to put font files in a different |
|
46
|
|
|
|
|
|
|
# place, and even Windows is consistent only for TTF/OTF font files. |
|
47
|
|
|
|
|
|
|
my @font_path = __PACKAGE__->set_font_path( |
|
48
|
|
|
|
|
|
|
'.', # could a font ever be a security risk? |
|
49
|
|
|
|
|
|
|
'/usr/share/fonts', |
|
50
|
|
|
|
|
|
|
'/usr/local/share/fonts', |
|
51
|
|
|
|
|
|
|
'/usr/share/fonts/type1/gsfonts', |
|
52
|
|
|
|
|
|
|
'/usr/share/X11/fonts/urw-fonts', |
|
53
|
|
|
|
|
|
|
'/usr/share/fonts/urw-base35', |
|
54
|
|
|
|
|
|
|
'/usr/share/fonts/dejavu-sans-fonts', |
|
55
|
|
|
|
|
|
|
'/usr/share/fonts/truetype/ttf-dejavu', |
|
56
|
|
|
|
|
|
|
'/usr/share/fonts/truetype/dejavu', |
|
57
|
|
|
|
|
|
|
'/var/lib/defoma/gs.d/dirs/fonts', |
|
58
|
|
|
|
|
|
|
'/Windows/Fonts', |
|
59
|
|
|
|
|
|
|
'/Users/XXXX/AppData/Local/Microsoft/Windows/Fonts', |
|
60
|
|
|
|
|
|
|
'/WinNT/Fonts' |
|
61
|
|
|
|
|
|
|
); |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
our @MSG_COUNT = (0, # [0] Graphics::TIFF not installed |
|
64
|
|
|
|
|
|
|
0, # [1] Image::PNG::Libpng not installed |
|
65
|
|
|
|
|
|
|
0, # [2] save/restore in text mode |
|
66
|
|
|
|
|
|
|
0, # [3] Times-Roman core font substituted for Times |
|
67
|
|
|
|
|
|
|
0, # [4] TBD... |
|
68
|
|
|
|
|
|
|
); |
|
69
|
|
|
|
|
|
|
our $outVer = 1.4; # desired PDF version for output, bump up w/ warning on read or feature output |
|
70
|
|
|
|
|
|
|
our $msgVer = 1; # 0=don't, 1=do issue message when PDF output version is bumped up |
|
71
|
|
|
|
|
|
|
our $myself; # holds self->pdf |
|
72
|
|
|
|
|
|
|
our $global_pdf; # holds self ($pdf) |
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
require PDF::Builder::FontManager; |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
=head1 NAME |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
PDF::Builder - Facilitates the creation and modification of PDF files |
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
use PDF::Builder; |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
# Create a blank PDF file |
|
85
|
|
|
|
|
|
|
$pdf = PDF::Builder->new(); |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
# Open an existing PDF file |
|
88
|
|
|
|
|
|
|
$pdf = PDF::Builder->open('some.pdf'); |
|
89
|
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
# Add a blank page |
|
91
|
|
|
|
|
|
|
$page = $pdf->page(); |
|
92
|
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
# Retrieve an existing page |
|
94
|
|
|
|
|
|
|
$page = $pdf->open_page($page_number); |
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# Set the page size |
|
97
|
|
|
|
|
|
|
$page->size('Letter'); # or mediabox('Letter') |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
# Add a built-in font to the PDF |
|
100
|
|
|
|
|
|
|
$font = $pdf->font('Helvetica-Bold'); # or corefont('Helvetica-Bold') |
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
# Add an external TrueType (TTF) font to the PDF |
|
103
|
|
|
|
|
|
|
$font = $pdf->font('/path/to/font.ttf'); # or ttfont() in this case |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
# Add some text to the page |
|
106
|
|
|
|
|
|
|
$text = $page->text(); |
|
107
|
|
|
|
|
|
|
$text->font($font, 20); |
|
108
|
|
|
|
|
|
|
$text->position(200, 700); # or translate() |
|
109
|
|
|
|
|
|
|
$text->text('Hello World!'); |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
# Save the PDF |
|
112
|
|
|
|
|
|
|
$pdf->saveas('/path/to/new.pdf'); |
|
113
|
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
=head1 SOME SPECIAL NOTES |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
See the file README.md (in downloadable package and on CPAN) for a summary of |
|
117
|
|
|
|
|
|
|
prerequisites and tools needed to install PDF::Builder, both mandatory and |
|
118
|
|
|
|
|
|
|
optional. |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
=head2 SOFTWARE DEVELOPMENT KIT |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
There are four levels of involvement with PDF::Builder. Depending on what you |
|
123
|
|
|
|
|
|
|
want to do, different kinds of installs are recommended. |
|
124
|
|
|
|
|
|
|
See L<PDF::Builder::Docs/Software Development Kit> for suggestions. |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
=head2 OPTIONAL LIBRARIES |
|
127
|
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
PDF::Builder can make use of some optional libraries, which are not I<required> |
|
129
|
|
|
|
|
|
|
for a successful installation, but improve speed and capabilities. See |
|
130
|
|
|
|
|
|
|
L<PDF::Builder::Docs/Optional Libraries> for more information. |
|
131
|
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
=head2 STRINGS (CHARACTER TEXT) |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
There are some things you should know about character encoding (for text), |
|
135
|
|
|
|
|
|
|
before you dive in to coding. Please go to L<PDF::Builder::Docs/Strings (Character Text)> and have a read. |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
=head2 RENDERING ORDER |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
Invoking "text" and "graphics" methods can lead to unexpected results (a |
|
140
|
|
|
|
|
|
|
different ordering of output than intended). See L<PDF::Builder::Docs/Rendering Order> for more information. |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
=head2 PDF VERSIONS SUPPORTED |
|
143
|
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
PDF::Builder is mostly PDF 1.4-compliant, but there I<are> complications you |
|
145
|
|
|
|
|
|
|
should be aware of. Please read L<PDF::Builder::Docs/PDF Versions Supported> |
|
146
|
|
|
|
|
|
|
for details. |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=head2 SUPPORTED PERL VERSIONS (BACKWARDS COMPATIBILITY GOALS) |
|
149
|
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
PDF::Builder intends to support all major Perl versions that were released in |
|
151
|
|
|
|
|
|
|
the past six years, plus one, in order to continue working for the life of |
|
152
|
|
|
|
|
|
|
most long-term-stable (LTS) server distributions. |
|
153
|
|
|
|
|
|
|
See L<PDF::Builder::Docs/Supported Perl Versions> for more information, |
|
154
|
|
|
|
|
|
|
including expected cutoff dates for Perl versions. |
|
155
|
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
=head2 KNOWN ISSUES |
|
157
|
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
This module does not work with Perl's -l command-line switch. |
|
159
|
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
There is a file INFO/KNOWN_INCOMP which lists known incompatibilities with |
|
161
|
|
|
|
|
|
|
PDF::API2, in case you're thinking of porting over something from that world, |
|
162
|
|
|
|
|
|
|
or have experience there and want to try PDF::Builder. There is also a file |
|
163
|
|
|
|
|
|
|
INFO/DEPRECATED, which lists things which are planned to be removed at some |
|
164
|
|
|
|
|
|
|
point. |
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
=head2 HISTORY |
|
167
|
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
The history of PDF::Builder is a complex and exciting saga... OK, it may be |
|
169
|
|
|
|
|
|
|
mildly interesting. Have a look at L<PDF::Builder::Docs/History> section. |
|
170
|
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
=head2 AUTHOR |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
PDF::API2 was originally written by Alfred Reibenschuh. See the HISTORY section |
|
174
|
|
|
|
|
|
|
for more information. |
|
175
|
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
It was maintained by Steve Simms, who is still contributing new code to it |
|
177
|
|
|
|
|
|
|
(which often ends up in PDF::Builder). |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
PDF::Builder is currently being maintained by Phil M. Perry. |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
=head2 SUPPORT |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
The full source is on https://github.com/PhilterPaper/Perl-PDF-Builder. |
|
184
|
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
The release distribution is on CPAN: https://metacpan.org/pod/PDF::Builder. |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
A formatted copy of the documentation (POD) may be found online, for your |
|
188
|
|
|
|
|
|
|
convenience, at https://www.catskilltech.com/Documentation/PDF/Builder.html. |
|
189
|
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
Copies of most of the output of "examples/" sample programs may be found |
|
191
|
|
|
|
|
|
|
online at https://www.catskilltech.com/Examples/PDF/Builder.html. |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
Bug reports are on https://github.com/PhilterPaper/Perl-PDF-Builder/issues?q=is%3Aissue+sort%3Aupdated-desc |
|
194
|
|
|
|
|
|
|
(with "bug" label), feature requests have an "enhancement" label, and general |
|
195
|
|
|
|
|
|
|
discussions (architecture, roadmap, etc.) have a "general discussion" label. |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
Do B<not> under I<any> circumstances open a PR (Pull Request) to report a bug. |
|
198
|
|
|
|
|
|
|
That's B<not> what a PR is for, and |
|
199
|
|
|
|
|
|
|
is a waste of both your and our time and effort. Open a regular ticket |
|
200
|
|
|
|
|
|
|
(issue), and attach a Perl (.pl) program illustrating the problem, if possible. |
|
201
|
|
|
|
|
|
|
If you believe that you have a program patch, and offer to share it as a PR, we |
|
202
|
|
|
|
|
|
|
may give the go-ahead. Unsolicited PRs may be closed without further action. |
|
203
|
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
=head2 LICENSE |
|
205
|
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
This software is Copyright (c) 2017-2025 by Phil M. Perry. |
|
207
|
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
This is free software, licensed under: |
|
209
|
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
The GNU Lesser General Public License (LGPL) Version 2.1, February 1999 |
|
211
|
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
(The master copy of this license lives on the GNU website.) |
|
213
|
|
|
|
|
|
|
(A copy is provided in the INFO/LICENSE file for your convenience.) |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
This section of Builder.pm is intended only as a very brief summary |
|
216
|
|
|
|
|
|
|
of the license; please consider INFO/LICENSE to be the controlling version, |
|
217
|
|
|
|
|
|
|
if there is any conflict or ambiguity between the two. |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it under |
|
220
|
|
|
|
|
|
|
the terms of the GNU Lesser General Public License, as published by the Free |
|
221
|
|
|
|
|
|
|
Software Foundation, either version 2.1 of the License, or (at your option) any |
|
222
|
|
|
|
|
|
|
later version of this license. |
|
223
|
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
NOTE: there are several files in this distribution which were incorporated from |
|
225
|
|
|
|
|
|
|
outside sources and carry different licenses. If a file states that it is under |
|
226
|
|
|
|
|
|
|
a license different than LGPL 2.1, that license and its terms will apply to |
|
227
|
|
|
|
|
|
|
that file, and not LGPL 2.1. |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful, but WITHOUT ANY |
|
230
|
|
|
|
|
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A |
|
231
|
|
|
|
|
|
|
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
=head1 GENERAL PURPOSE METHODS |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
=head2 new |
|
236
|
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
$pdf = PDF::Builder->new(%opts) |
|
238
|
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
=over |
|
240
|
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
Creates a new PDF object. |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
B<Options> |
|
244
|
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
=back |
|
246
|
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
=over |
|
248
|
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
=item file |
|
250
|
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
If you will be saving it as a file and |
|
252
|
|
|
|
|
|
|
already know the filename, you can give the 'file' option to minimize |
|
253
|
|
|
|
|
|
|
possible memory requirements later on (the file is opened immediately for |
|
254
|
|
|
|
|
|
|
writing, rather than waiting until the C<save>). The C<file> may also be |
|
255
|
|
|
|
|
|
|
a filehandle. |
|
256
|
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
=item compress |
|
258
|
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
The 'compress' option can be |
|
260
|
|
|
|
|
|
|
given to specify stream compression: default is 'flate', 'none' (or 0) is no |
|
261
|
|
|
|
|
|
|
compression. No other compression methods are currently supported. |
|
262
|
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
=item outver |
|
264
|
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
The 'outver' option defaults to 1.4 as the output PDF version and the highest |
|
266
|
|
|
|
|
|
|
allowed feature version (attempts to use anything higher will give a warning). |
|
267
|
|
|
|
|
|
|
If an existing PDF with a higher version is read in, C<outver> will be |
|
268
|
|
|
|
|
|
|
increased to that version, with a warning. |
|
269
|
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
=item msgver |
|
271
|
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
The 'msgver' option value of 1 (default) gives a warning message if the |
|
273
|
|
|
|
|
|
|
'outver' PDF level has to be bumped up due to either a higher PDF level file |
|
274
|
|
|
|
|
|
|
being read in, or a higher level feature was requested. A value of 0 |
|
275
|
|
|
|
|
|
|
suppresses the warning message. |
|
276
|
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
=item diaglevel |
|
278
|
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
The 'diaglevel' option can be |
|
280
|
|
|
|
|
|
|
given to specify the level of diagnostics given by IntegrityCheck(). The |
|
281
|
|
|
|
|
|
|
default is level 2 (errors and warnings). |
|
282
|
|
|
|
|
|
|
See L<PDF::Builder::Docs/IntegrityCheck> for more information. |
|
283
|
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
=back |
|
285
|
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
B<Example:> |
|
287
|
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
$pdf = PDF::Builder->new(); |
|
289
|
|
|
|
|
|
|
... |
|
290
|
|
|
|
|
|
|
print $pdf->to_string(); |
|
291
|
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
$pdf = PDF::Builder->new(compress => 'none'); |
|
293
|
|
|
|
|
|
|
# equivalent to $pdf->{'forcecompress'} = 'none'; (or older, 0) |
|
294
|
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
$pdf = PDF::Builder->new(); |
|
296
|
|
|
|
|
|
|
... |
|
297
|
|
|
|
|
|
|
$pdf->saveas('our/new.pdf'); |
|
298
|
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
$pdf = PDF::Builder->new(file => 'our/new.pdf'); |
|
300
|
|
|
|
|
|
|
... |
|
301
|
|
|
|
|
|
|
$pdf->save(); |
|
302
|
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
=cut |
|
304
|
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
sub new { |
|
306
|
234
|
|
|
234
|
1
|
8473012
|
my ($class, %opts) = @_; |
|
307
|
|
|
|
|
|
|
# copy dashed option names to preferred undashed names |
|
308
|
234
|
100
|
66
|
|
|
1674
|
if (defined $opts{'-compress'} && !defined $opts{'compress'}) { $opts{'compress'} = delete($opts{'-compress'}); } |
|
|
19
|
|
|
|
|
85
|
|
|
309
|
234
|
50
|
33
|
|
|
1233
|
if (defined $opts{'-diaglevel'} && !defined $opts{'diaglevel'}) { $opts{'diaglevel'} = delete($opts{'-diaglevel'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
310
|
234
|
50
|
33
|
|
|
1468
|
if (defined $opts{'-outver'} && !defined $opts{'outver'}) { $opts{'outver'} = delete($opts{'-outver'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
311
|
234
|
50
|
33
|
|
|
1074
|
if (defined $opts{'-msgver'} && !defined $opts{'msgver'}) { $opts{'msgver'} = delete($opts{'-msgver'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
312
|
234
|
50
|
33
|
|
|
1110
|
if (defined $opts{'-file'} && !defined $opts{'file'}) { $opts{'file'} = delete($opts{'-file'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
313
|
|
|
|
|
|
|
|
|
314
|
234
|
|
|
|
|
615
|
my $self = {}; |
|
315
|
234
|
|
|
|
|
557
|
bless $self, $class; |
|
316
|
234
|
|
|
|
|
2663
|
$self->{'pdf'} = PDF::Builder::Basic::PDF::File->new(); |
|
317
|
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
# make available to other routines |
|
319
|
234
|
|
|
|
|
1455
|
$myself = $self->{'pdf'}; |
|
320
|
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
# default output version |
|
322
|
234
|
|
|
|
|
757
|
$self->{'pdf'}->{' version'} = $outVer; |
|
323
|
234
|
|
|
|
|
2399
|
$self->{'pages'} = PDF::Builder::Basic::PDF::Pages->new($self->{'pdf'}); |
|
324
|
234
|
|
|
|
|
1397
|
$self->{'pages'}->proc_set(qw(PDF Text ImageB ImageC ImageI)); |
|
325
|
234
|
|
33
|
|
|
3351
|
$self->{'pages'}->{'Resources'} ||= PDFDict(); |
|
326
|
|
|
|
|
|
|
$self->{'pdf'}->new_obj($self->{'pages'}->{'Resources'}) |
|
327
|
234
|
50
|
|
|
|
1364
|
unless $self->{'pages'}->{'Resources'}->is_obj($self->{'pdf'}); |
|
328
|
234
|
|
|
|
|
856
|
$self->{'catalog'} = $self->{'pdf'}->{'Root'}; |
|
329
|
234
|
|
|
|
|
616
|
weaken $self->{'catalog'}; |
|
330
|
234
|
|
|
|
|
620
|
$self->{'fonts'} = {}; |
|
331
|
234
|
|
|
|
|
714
|
$self->{'pagestack'} = []; |
|
332
|
|
|
|
|
|
|
|
|
333
|
234
|
|
|
|
|
823
|
$self->{'pdf'}->{' userUnit'} = 1.0; # default global User Unit |
|
334
|
234
|
|
|
|
|
1502
|
$self->mediabox('letter'); # PDF defaults to US Letter 8.5in x 11in |
|
335
|
|
|
|
|
|
|
|
|
336
|
234
|
100
|
|
|
|
957
|
if (exists $opts{'compress'}) { |
|
337
|
154
|
|
|
|
|
575
|
$self->{'forcecompress'} = $opts{'compress'}; |
|
338
|
|
|
|
|
|
|
# at this point, no validation of given value! none/flate (0/1). |
|
339
|
|
|
|
|
|
|
# note that >0 is often used as equivalent to 'flate' |
|
340
|
|
|
|
|
|
|
} else { |
|
341
|
80
|
|
|
|
|
358
|
$self->{'forcecompress'} = 'flate'; |
|
342
|
|
|
|
|
|
|
# code should also allow integers 0 (= 'none') and >0 (= 'flate') |
|
343
|
|
|
|
|
|
|
# for compatibility with old usage where forcecompress is directly set. |
|
344
|
|
|
|
|
|
|
} |
|
345
|
234
|
50
|
|
|
|
688
|
if (exists $opts{'diaglevel'}) { |
|
346
|
0
|
|
|
|
|
0
|
my $diaglevel = $opts{'diaglevel'}; |
|
347
|
0
|
0
|
0
|
|
|
0
|
if ($diaglevel < 0 || $diaglevel > 5) { |
|
348
|
0
|
|
|
|
|
0
|
print "diaglevel must be in range 0-5. using 2\n"; |
|
349
|
0
|
|
|
|
|
0
|
$diaglevel = 2; |
|
350
|
|
|
|
|
|
|
} |
|
351
|
0
|
|
|
|
|
0
|
$self->{'diaglevel'} = $diaglevel; |
|
352
|
|
|
|
|
|
|
} else { |
|
353
|
234
|
|
|
|
|
903
|
$self->{'diaglevel'} = 2; # default: errors and warnings |
|
354
|
|
|
|
|
|
|
} |
|
355
|
|
|
|
|
|
|
|
|
356
|
234
|
|
|
|
|
1499
|
$self->preferences(%opts); |
|
357
|
234
|
100
|
|
|
|
794
|
if (defined $opts{'outver'}) { |
|
358
|
1
|
50
|
|
|
|
4
|
if ($opts{'outver'} >= 1.4) { |
|
359
|
1
|
|
|
|
|
4
|
$self->{'pdf'}->{' version'} = $opts{'outver'}; |
|
360
|
|
|
|
|
|
|
} else { |
|
361
|
0
|
|
|
|
|
0
|
print STDERR "Invalid outver given, or less than 1.4. Ignored.\n"; |
|
362
|
|
|
|
|
|
|
} |
|
363
|
|
|
|
|
|
|
} |
|
364
|
234
|
100
|
|
|
|
808
|
if (defined $opts{'msgver'}) { |
|
365
|
1
|
50
|
33
|
|
|
5
|
if ($opts{'msgver'} == 0 || $opts{'msgver'} == 1) { |
|
366
|
1
|
|
|
|
|
2
|
$msgVer = $opts{'msgver'}; |
|
367
|
|
|
|
|
|
|
} else { |
|
368
|
0
|
|
|
|
|
0
|
print STDERR "Invalid msgver given, not 0 or 1. Ignored.\n"; |
|
369
|
|
|
|
|
|
|
} |
|
370
|
|
|
|
|
|
|
} |
|
371
|
234
|
50
|
|
|
|
771
|
if ($opts{'file'}) { |
|
372
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->create_file($opts{'file'}); |
|
373
|
0
|
|
|
|
|
0
|
$self->{'partial_save'} = 1; |
|
374
|
|
|
|
|
|
|
} |
|
375
|
|
|
|
|
|
|
# used by info and infoMetaAttributes but not by their replacements |
|
376
|
234
|
|
|
|
|
1318
|
$self->{'infoMeta'} = [qw(Author CreationDate ModDate Creator Producer |
|
377
|
|
|
|
|
|
|
Title Subject Keywords)]; |
|
378
|
|
|
|
|
|
|
|
|
379
|
234
|
|
50
|
|
|
535
|
my $version = eval { $PDF::Builder::VERSION } || '(Development Version)'; |
|
380
|
|
|
|
|
|
|
#$self->info('Producer' => "PDF::Builder $version [$^O]"); |
|
381
|
234
|
|
|
|
|
1969
|
$self->info('Producer' => "PDF::Builder $version [see ". |
|
382
|
|
|
|
|
|
|
"https://github.com/PhilterPaper/Perl-PDF-Builder/blob/master/INFO/SUPPORT]"); |
|
383
|
|
|
|
|
|
|
|
|
384
|
234
|
|
|
|
|
603
|
$global_pdf = $self; |
|
385
|
|
|
|
|
|
|
# initialize Font Manager |
|
386
|
234
|
|
|
|
|
2440
|
require PDF::Builder::FontManager; |
|
387
|
234
|
|
|
|
|
2365
|
$self->{' FM'} = PDF::Builder::FontManager->new($self); |
|
388
|
|
|
|
|
|
|
|
|
389
|
234
|
|
|
|
|
4745
|
return $self; |
|
390
|
|
|
|
|
|
|
} # end of new() |
|
391
|
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
=head2 default_page_size |
|
393
|
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
@rectangle = $pdf->default_page_size($size); # Set |
|
395
|
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
@rectangle = $pdf->default_page_size() # Get |
|
397
|
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
=over |
|
399
|
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
Set the default physical size for pages in the PDF. If called without |
|
401
|
|
|
|
|
|
|
arguments (Get), return an array of the coordinates of the rectangle |
|
402
|
|
|
|
|
|
|
describing the default physical page size (the Media Box). I<Setting> the |
|
403
|
|
|
|
|
|
|
size also returns the resulting media size. |
|
404
|
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
This is essentially an alternate method of defining the C<mediabox()> call, |
|
406
|
|
|
|
|
|
|
and added for compatibility with PDF::API2. |
|
407
|
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
See L<PDF::Builder::Page/Page Sizes> for possible values. |
|
409
|
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
Note that this method is I<only> at the PDF (document) level. It is not |
|
411
|
|
|
|
|
|
|
implemented at the page level. If you want to set or get the page-level |
|
412
|
|
|
|
|
|
|
override of the media size, use the C<mediabox()> method. |
|
413
|
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
=back |
|
415
|
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
=cut |
|
417
|
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
sub default_page_size { |
|
419
|
1
|
|
|
1
|
1
|
6258
|
my $self = shift(); |
|
420
|
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
# Set |
|
422
|
1
|
50
|
|
|
|
6
|
if (@_) { |
|
423
|
1
|
|
|
|
|
8
|
return $self->mediabox(@_); |
|
424
|
|
|
|
|
|
|
} |
|
425
|
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
# Get |
|
427
|
|
|
|
|
|
|
# up to 5 hash elements of 4 number arrays |
|
428
|
0
|
|
|
|
|
0
|
my %boundaries = $self->default_page_boundaries(); |
|
429
|
0
|
|
|
|
|
0
|
return @{$boundaries{'media'}}; # s/b 4 element array |
|
|
0
|
|
|
|
|
0
|
|
|
430
|
|
|
|
|
|
|
} |
|
431
|
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
=head2 default_page_boundaries |
|
433
|
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
%boundaries = $pdf->default_page_boundaries('media' => |
|
435
|
|
|
|
|
|
|
[xmin, ymin, xmax, ymax]); # Set the media box |
|
436
|
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
%boundaries = $pdf->default_page_boundaries(); # Get (all five) |
|
438
|
|
|
|
|
|
|
@media_rect = @{ $boundaries{'media'} }; # show 'media' box |
|
439
|
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
=over |
|
441
|
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
Set default prepress page boundaries ('boxes') for pages in the PDF. If called |
|
443
|
|
|
|
|
|
|
without arguments, returns the coordinates of the rectangles describing each |
|
444
|
|
|
|
|
|
|
of the supported page boundaries, as a hash of array refs. Each will be US |
|
445
|
|
|
|
|
|
|
Letter size, unless it has been explicitly changed. I<Setting> the values |
|
446
|
|
|
|
|
|
|
will also return the hash. |
|
447
|
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
See the equivalent C<page_boundaries> method in L<PDF::Builder::Page> for |
|
449
|
|
|
|
|
|
|
details. |
|
450
|
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
=back |
|
452
|
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
=cut |
|
454
|
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
# Called by PDF::Builder::Page::boundaries via the default_page_* methods below |
|
456
|
|
|
|
|
|
|
sub _bounding_box { |
|
457
|
7
|
|
|
7
|
|
10487
|
my $self = shift(); |
|
458
|
7
|
|
|
|
|
18
|
my $type = shift(); |
|
459
|
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
# Get |
|
461
|
7
|
100
|
|
|
|
57
|
unless (scalar @_) { |
|
462
|
4
|
50
|
|
|
|
964
|
unless ($self->{'pages'}->{$type}) { |
|
463
|
0
|
0
|
|
|
|
0
|
return if $type eq 'MediaBox'; |
|
464
|
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
# Use defaults per PDF 1.7 section 14.11.2 Page Boundaries |
|
466
|
0
|
0
|
|
|
|
0
|
return $self->_bounding_box('MediaBox') if $type eq 'CropBox'; |
|
467
|
0
|
|
|
|
|
0
|
return $self->_bounding_box('CropBox'); |
|
468
|
|
|
|
|
|
|
} |
|
469
|
4
|
|
|
|
|
25
|
my @xxx = $self->{'pages'}->{$type}->elements(); # 4 element array of hashes |
|
470
|
4
|
|
|
|
|
12
|
return (map { $_->val() } @xxx); |
|
|
16
|
|
|
|
|
42
|
|
|
471
|
|
|
|
|
|
|
} |
|
472
|
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
# Set |
|
474
|
3
|
|
|
|
|
8
|
$self->{'pages'}->{$type} = PDFArray(map { PDFNum(float($_)) } @_); |
|
|
12
|
|
|
|
|
38
|
|
|
475
|
3
|
|
|
|
|
12
|
return $self; |
|
476
|
|
|
|
|
|
|
} |
|
477
|
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
sub default_page_boundaries { |
|
479
|
2
|
|
|
2
|
1
|
10612
|
my %xxx = PDF::Builder::Page::boundaries(@_); |
|
480
|
|
|
|
|
|
|
# 5 element 'media' etc. hash of anonymous arrays each 4 numbers |
|
481
|
2
|
|
|
|
|
10
|
return %xxx; |
|
482
|
|
|
|
|
|
|
} |
|
483
|
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
# Deprecated; use default_page_size or default_page_boundaries |
|
485
|
|
|
|
|
|
|
# alternate implementations of media, crop, etc. boxes |
|
486
|
|
|
|
|
|
|
#sub mediabox { |
|
487
|
|
|
|
|
|
|
# my $self = shift(); |
|
488
|
|
|
|
|
|
|
# return $self->_bounding_box('MediaBox') unless @_; |
|
489
|
|
|
|
|
|
|
# return $self->_bounding_box('MediaBox', page_size(@_)); |
|
490
|
|
|
|
|
|
|
#} |
|
491
|
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
# Deprecated; use default_page_boundaries |
|
493
|
|
|
|
|
|
|
#sub cropbox { |
|
494
|
|
|
|
|
|
|
# my $self = shift(); |
|
495
|
|
|
|
|
|
|
# return $self->_bounding_box('CropBox') unless @_; |
|
496
|
|
|
|
|
|
|
# return $self->_bounding_box('CropBox', page_size(@_)); |
|
497
|
|
|
|
|
|
|
#} |
|
498
|
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
# Deprecated; use default_page_boundaries |
|
500
|
|
|
|
|
|
|
#sub bleedbox { |
|
501
|
|
|
|
|
|
|
# my $self = shift(); |
|
502
|
|
|
|
|
|
|
# return $self->_bounding_box('BleedBox') unless @_; |
|
503
|
|
|
|
|
|
|
# return $self->_bounding_box('BleedBox', page_size(@_)); |
|
504
|
|
|
|
|
|
|
#} |
|
505
|
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
# Deprecated; use default_page_boundaries |
|
507
|
|
|
|
|
|
|
#sub trimbox { |
|
508
|
|
|
|
|
|
|
# my $self = shift(); |
|
509
|
|
|
|
|
|
|
# return $self->_bounding_box('TrimBox') unless @_; |
|
510
|
|
|
|
|
|
|
# return $self->_bounding_box('TrimBox', page_size(@_)); |
|
511
|
|
|
|
|
|
|
#} |
|
512
|
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
# Deprecated; use default_page_boundaries |
|
514
|
|
|
|
|
|
|
#sub artbox { |
|
515
|
|
|
|
|
|
|
# my $self = shift(); |
|
516
|
|
|
|
|
|
|
# return $self->_bounding_box('ArtBox') unless @_; |
|
517
|
|
|
|
|
|
|
# return $self->_bounding_box('ArtBox', page_size(@_)); |
|
518
|
|
|
|
|
|
|
#} |
|
519
|
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
=head1 INPUT/OUTPUT METHODS |
|
521
|
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
=head2 open |
|
523
|
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
$pdf = PDF::Builder->open($pdf_file, %opts) |
|
525
|
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
=over |
|
527
|
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
Opens an existing PDF file. See C<new()> for options. |
|
529
|
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
B<Example:> |
|
531
|
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
=back |
|
533
|
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
$pdf = PDF::Builder->open('our/old.pdf'); |
|
535
|
|
|
|
|
|
|
... |
|
536
|
|
|
|
|
|
|
$pdf->saveas('our/new.pdf'); |
|
537
|
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
$pdf = PDF::Builder->open('our/to/be/updated.pdf'); |
|
539
|
|
|
|
|
|
|
... |
|
540
|
|
|
|
|
|
|
$pdf->update(); |
|
541
|
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
=cut |
|
543
|
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
sub open { ## no critic |
|
545
|
8
|
|
|
8
|
1
|
804961
|
my ($class, $file, %opts) = @_; |
|
546
|
8
|
50
|
|
|
|
317
|
croak "File '$file' does not exist" unless -f $file; |
|
547
|
8
|
50
|
|
|
|
143
|
croak "File '$file' is not readable" unless -r $file; |
|
548
|
|
|
|
|
|
|
|
|
549
|
8
|
|
|
|
|
33
|
my $content; |
|
550
|
8
|
|
|
|
|
101
|
my $scalar_fh = FileHandle->new(); |
|
551
|
8
|
50
|
|
|
|
723
|
CORE::open($scalar_fh, '+<', \$content) or croak "Can't begin scalar IO"; |
|
552
|
8
|
|
|
|
|
50
|
binmode $scalar_fh, ':raw'; |
|
553
|
|
|
|
|
|
|
|
|
554
|
8
|
|
|
|
|
42
|
my $disk_fh = FileHandle->new(); |
|
555
|
8
|
50
|
|
|
|
652
|
CORE::open($disk_fh, '<', $file) or croak "Can't open $file for reading: $!"; |
|
556
|
8
|
|
|
|
|
52
|
binmode $disk_fh, ':raw'; |
|
557
|
8
|
|
|
|
|
64
|
$disk_fh->seek(0, 0); |
|
558
|
8
|
|
|
|
|
84
|
my $data; |
|
559
|
8
|
|
|
|
|
52
|
while (not $disk_fh->eof()) { |
|
560
|
49
|
|
|
|
|
1045
|
$disk_fh->read($data, 512); |
|
561
|
49
|
|
|
|
|
331
|
$scalar_fh->print($data); |
|
562
|
|
|
|
|
|
|
} |
|
563
|
|
|
|
|
|
|
# check if final %%EOF lacks a carriage return on the end (add one) |
|
564
|
8
|
50
|
|
|
|
226
|
if ($data =~ m/%%EOF$/) { |
|
565
|
|
|
|
|
|
|
#print "open() says missing final EOF\n"; |
|
566
|
8
|
|
|
|
|
31
|
$scalar_fh->print("\n"); |
|
567
|
|
|
|
|
|
|
} |
|
568
|
8
|
|
|
|
|
79
|
$disk_fh->close(); |
|
569
|
8
|
|
|
|
|
202
|
$scalar_fh->seek(0, 0); |
|
570
|
|
|
|
|
|
|
|
|
571
|
8
|
|
|
|
|
101
|
my $self = $class->from_string($content, %opts); |
|
572
|
8
|
|
|
|
|
55
|
$self->{'pdf'}->{' fname'} = $file; |
|
573
|
|
|
|
|
|
|
|
|
574
|
8
|
|
|
|
|
404
|
return $self; |
|
575
|
|
|
|
|
|
|
} # end of open() |
|
576
|
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
=head2 from_string, open_scalar, openScalar |
|
578
|
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
$pdf = PDF::Builder->from_string($pdf_string, %opts) |
|
580
|
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
=over |
|
582
|
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
Opens a PDF contained in a string. See C<new()> for other options. |
|
584
|
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
=back |
|
586
|
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
=over |
|
588
|
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
=item diags => 1 |
|
590
|
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
Display warnings when non-conforming PDF structure is found, and fix up |
|
592
|
|
|
|
|
|
|
where possible. See L<PDF::Builder::Basic::PDF::File> for more information. |
|
593
|
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
=back |
|
595
|
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
B<Example:> |
|
597
|
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
# Read a PDF into a string, for the purpose of demonstration |
|
599
|
|
|
|
|
|
|
open $fh, 'our/old.pdf' or croak $@; |
|
600
|
|
|
|
|
|
|
undef $/; # Read the whole file at once |
|
601
|
|
|
|
|
|
|
$pdf_string = <$fh>; |
|
602
|
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
$pdf = PDF::Builder->from_string($pdf_string); |
|
604
|
|
|
|
|
|
|
... |
|
605
|
|
|
|
|
|
|
$pdf->saveas('our/new.pdf'); |
|
606
|
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
=over |
|
608
|
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
B<Alternate name:> C<open_scalar> |
|
610
|
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
C<from_string> was formerly known as C<open_scalar> (and even before that, |
|
612
|
|
|
|
|
|
|
as C<openScalar>), and this older name is still |
|
613
|
|
|
|
|
|
|
valid as an alternative to C<from_string>. It is I<possible> that C<open_scalar> |
|
614
|
|
|
|
|
|
|
will be deprecated and then removed some time in the future, so it may be |
|
615
|
|
|
|
|
|
|
advisable to use C<from_string> in new work. |
|
616
|
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
=back |
|
618
|
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
=cut |
|
620
|
|
|
|
|
|
|
|
|
621
|
1
|
|
|
1
|
1
|
1382
|
sub open_scalar { return from_string(@_); } ## no critic |
|
622
|
1
|
|
|
1
|
1
|
14
|
sub openScalar { return from_string(@_); } ## no critic |
|
623
|
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
sub from_string { |
|
625
|
18
|
|
|
18
|
1
|
3631
|
my ($class, $content, %opts) = @_; |
|
626
|
|
|
|
|
|
|
# copy dashed option names to preferred undashed names |
|
627
|
18
|
50
|
33
|
|
|
133
|
if (defined $opts{'-diags'} && !defined $opts{'diags'}) { $opts{'diags'} = delete($opts{'-diags'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
628
|
18
|
50
|
33
|
|
|
86
|
if (defined $opts{'-compress'} && !defined $opts{'compress'}) { $opts{'compress'} = delete($opts{'-compress'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
629
|
18
|
50
|
33
|
|
|
110
|
if (defined $opts{'-diaglevel'} && !defined $opts{'diaglevel'}) { $opts{'diaglevel'} = delete($opts{'-diaglevel'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
630
|
|
|
|
|
|
|
|
|
631
|
18
|
50
|
|
|
|
64
|
if (ref($class)) { $class = ref($class); } |
|
|
0
|
|
|
|
|
0
|
|
|
632
|
|
|
|
|
|
|
# my $self = {}; |
|
633
|
|
|
|
|
|
|
# bless $self, $class; |
|
634
|
|
|
|
|
|
|
# foreach my $parameter (keys %opts) { |
|
635
|
|
|
|
|
|
|
# $self->default($parameter, $opts{$parameter}); |
|
636
|
|
|
|
|
|
|
# } |
|
637
|
18
|
|
|
|
|
99
|
my $self = $class->new(%opts); |
|
638
|
|
|
|
|
|
|
|
|
639
|
18
|
|
|
|
|
61
|
$self->{'content_ref'} = \$content; |
|
640
|
18
|
|
|
|
|
52
|
my $diaglevel = 2; |
|
641
|
18
|
50
|
|
|
|
79
|
if (defined $self->{'diaglevel'}) { $diaglevel = $self->{'diaglevel'}; } |
|
|
18
|
|
|
|
|
50
|
|
|
642
|
18
|
50
|
33
|
|
|
150
|
if ($diaglevel < 0 || $diaglevel > 5) { $diaglevel = 2; } |
|
|
0
|
|
|
|
|
0
|
|
|
643
|
18
|
|
|
|
|
141
|
my $newVer = $self->IntegrityCheck($diaglevel, $content); |
|
644
|
|
|
|
|
|
|
# if Version override defined in PDF, need to overwrite the %PDF-x.y |
|
645
|
|
|
|
|
|
|
# statement with the new (if higher) value. it's too late to wait until |
|
646
|
|
|
|
|
|
|
# after File->open, as it's already complained about some >1.4 features. |
|
647
|
18
|
50
|
|
|
|
65
|
if (defined $newVer) { |
|
648
|
18
|
|
|
|
|
56
|
my ($verStr, $currentVer, $pos); |
|
649
|
18
|
|
|
|
|
66
|
$pos = index $content, "%PDF-"; |
|
650
|
18
|
50
|
|
|
|
62
|
if ($pos < 0) { croak "no PDF version found in PDF input!"; } |
|
|
0
|
|
|
|
|
0
|
|
|
651
|
|
|
|
|
|
|
# assume major and minor PDF version numbers max 2 digits each for now |
|
652
|
|
|
|
|
|
|
# (are 1 or 2 and 0-7 at this writing) |
|
653
|
18
|
|
|
|
|
64
|
$verStr = substr($content, $pos, 10); |
|
654
|
18
|
50
|
|
|
|
145
|
if ($verStr =~ m#^%PDF-(\d+)\.(\d+)#) { |
|
655
|
18
|
|
|
|
|
91
|
$currentVer = "$1.$2"; |
|
656
|
|
|
|
|
|
|
} else { |
|
657
|
0
|
|
|
|
|
0
|
croak "unable to get PDF input's version number."; |
|
658
|
|
|
|
|
|
|
} |
|
659
|
18
|
50
|
|
|
|
138
|
if ($newVer > $currentVer) { |
|
660
|
0
|
0
|
|
|
|
0
|
if (length($newVer) > length($currentVer)) { |
|
661
|
0
|
|
|
|
|
0
|
print STDERR "Unable to update 'content' version because override '$newVer' is longer ". |
|
662
|
|
|
|
|
|
|
"than header version '$currentVer'.\nYou may receive warnings about features ". |
|
663
|
|
|
|
|
|
|
"that bump up the PDF level.\n"; |
|
664
|
|
|
|
|
|
|
} else { |
|
665
|
0
|
0
|
|
|
|
0
|
if (length($newVer) < length($currentVer)) { |
|
666
|
|
|
|
|
|
|
# unlikely, but cover all the bases |
|
667
|
0
|
|
|
|
|
0
|
$newVer = substr($newVer, 0, length($currentVer)); |
|
668
|
|
|
|
|
|
|
} |
|
669
|
0
|
|
|
|
|
0
|
substr($content, $pos+5, length($newVer)) = $newVer; |
|
670
|
0
|
|
|
|
|
0
|
$self->pdf_version($newVer); |
|
671
|
|
|
|
|
|
|
} |
|
672
|
|
|
|
|
|
|
} |
|
673
|
|
|
|
|
|
|
} |
|
674
|
|
|
|
|
|
|
|
|
675
|
18
|
|
|
|
|
45
|
my $fh; |
|
676
|
18
|
50
|
|
|
|
375
|
CORE::open($fh, '+<', \$content) or croak "Can't begin scalar IO"; |
|
677
|
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
# this would replace any existing self->pdf with a new one |
|
679
|
18
|
|
|
|
|
264
|
$self->{'pdf'} = PDF::Builder::Basic::PDF::File->open($fh, 1, %opts); |
|
680
|
18
|
|
|
|
|
114
|
$self->{'pdf'}->{'Root'}->realise(); |
|
681
|
18
|
|
|
|
|
109
|
$self->{'pages'} = $self->{'pdf'}->{'Root'}->{'Pages'}->realise(); |
|
682
|
18
|
|
|
|
|
58
|
weaken $self->{'pages'}; |
|
683
|
|
|
|
|
|
|
|
|
684
|
18
|
|
50
|
|
|
83
|
$self->{'pdf'}->{' version'} ||= 1.4; # default minimum |
|
685
|
|
|
|
|
|
|
# if version higher than desired output PDF level, give warning and |
|
686
|
|
|
|
|
|
|
# bump up desired output PDF level |
|
687
|
18
|
|
|
|
|
124
|
$self->verCheckInput($self->{'pdf'}->{' version'}); |
|
688
|
|
|
|
|
|
|
|
|
689
|
18
|
|
|
|
|
192
|
my @pages = _proc_pages($self->{'pdf'}, $self->{'pages'}); |
|
690
|
18
|
|
|
|
|
127
|
$self->{'pagestack'} = [sort { $a->{' pnum'} <=> $b->{' pnum'} } @pages]; |
|
|
3
|
|
|
|
|
23
|
|
|
691
|
18
|
|
|
|
|
52
|
weaken $self->{'pagestack'}->[$_] for (0 .. scalar @{$self->{'pagestack'}}); |
|
|
18
|
|
|
|
|
146
|
|
|
692
|
18
|
|
|
|
|
75
|
$self->{'catalog'} = $self->{'pdf'}->{'Root'}; |
|
693
|
18
|
|
|
|
|
41
|
weaken $self->{'catalog'}; |
|
694
|
18
|
|
|
|
|
90
|
$self->{'opened_scalar'} = 1; |
|
695
|
18
|
100
|
|
|
|
109
|
if (exists $opts{'compress'}) { |
|
696
|
3
|
|
|
|
|
11
|
$self->{'forcecompress'} = $opts{'compress'}; |
|
697
|
|
|
|
|
|
|
# at this point, no validation of given value! none/flate (0/1). |
|
698
|
|
|
|
|
|
|
# note that >0 is often used as equivalent to 'flate' |
|
699
|
|
|
|
|
|
|
} else { |
|
700
|
15
|
|
|
|
|
65
|
$self->{'forcecompress'} = 'flate'; |
|
701
|
|
|
|
|
|
|
# code should also allow integers 0 (= 'none') and >0 (= 'flate') |
|
702
|
|
|
|
|
|
|
# for compatibility with old usage where forcecompress is directly set. |
|
703
|
|
|
|
|
|
|
} |
|
704
|
18
|
50
|
|
|
|
69
|
if (exists $opts{'diaglevel'}) { |
|
705
|
0
|
|
|
|
|
0
|
$self->{'diaglevel'} = $opts{'diaglevel'}; |
|
706
|
0
|
0
|
0
|
|
|
0
|
if ($self->{'diaglevel'} < 0 || $self->{'diaglevel'} > 5) { |
|
707
|
0
|
|
|
|
|
0
|
$self->{'diaglevel'} = 2; |
|
708
|
|
|
|
|
|
|
} |
|
709
|
|
|
|
|
|
|
} else { |
|
710
|
18
|
|
|
|
|
43
|
$self->{'diaglevel'} = 2; |
|
711
|
|
|
|
|
|
|
} |
|
712
|
18
|
|
|
|
|
62
|
$self->{'fonts'} = {}; |
|
713
|
18
|
|
|
|
|
204
|
$self->{'infoMeta'} = [qw(Author CreationDate ModDate Creator Producer Title Subject Keywords)]; |
|
714
|
|
|
|
|
|
|
|
|
715
|
18
|
|
|
|
|
497
|
return $self; |
|
716
|
|
|
|
|
|
|
} # end of from_string() |
|
717
|
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
=head2 to_string, stringify |
|
719
|
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
$string = $pdf->to_string() |
|
721
|
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
=over |
|
723
|
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
Return the document as a string and remove the object structure from memory. |
|
725
|
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
B<Caution:> Although the object C<$pdf> will still exist, it is no longer |
|
727
|
|
|
|
|
|
|
usable for any purpose after invoking this method! You will receive error |
|
728
|
|
|
|
|
|
|
messages about "can't call method new_obj on an undefined value". |
|
729
|
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
B<Example:> |
|
731
|
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
=back |
|
733
|
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
$pdf = PDF::Builder->new(); |
|
735
|
|
|
|
|
|
|
... |
|
736
|
|
|
|
|
|
|
print $pdf->to_string(); |
|
737
|
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
=over |
|
739
|
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
B<Alternate name:> C<stringify> |
|
741
|
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
C<to_string> was formerly known as C<stringify>, and this older name is still |
|
743
|
|
|
|
|
|
|
valid as an alternative to C<to_string>. It is I<possible> that C<stringify> |
|
744
|
|
|
|
|
|
|
will be deprecated and then removed some time in the future, so it may be |
|
745
|
|
|
|
|
|
|
advisable to use C<to_string> in new work. |
|
746
|
|
|
|
|
|
|
|
|
747
|
|
|
|
|
|
|
=back |
|
748
|
|
|
|
|
|
|
|
|
749
|
|
|
|
|
|
|
=cut |
|
750
|
|
|
|
|
|
|
|
|
751
|
|
|
|
|
|
|
# Maintainer's note: The object is being destroyed because it contains |
|
752
|
|
|
|
|
|
|
# circular references that would otherwise result in memory not being |
|
753
|
|
|
|
|
|
|
# freed if the object merely goes out of scope. If possible, the |
|
754
|
|
|
|
|
|
|
# circular references should be eliminated so that to_string doesn't |
|
755
|
|
|
|
|
|
|
# need to be destructive. See t/circular-references.t. |
|
756
|
|
|
|
|
|
|
# |
|
757
|
|
|
|
|
|
|
# I've opted not to just require a separate call to release() because |
|
758
|
|
|
|
|
|
|
# it would likely introduce memory leaks in many existing programs |
|
759
|
|
|
|
|
|
|
# that use this module. |
|
760
|
|
|
|
|
|
|
# - Steve S. (see bug RT 81530) |
|
761
|
|
|
|
|
|
|
|
|
762
|
0
|
|
|
0
|
1
|
0
|
sub stringify { return to_string(@_); } ## no critic |
|
763
|
|
|
|
|
|
|
|
|
764
|
|
|
|
|
|
|
sub to_string { |
|
765
|
177
|
|
|
177
|
1
|
2352
|
my $self = shift(); |
|
766
|
|
|
|
|
|
|
|
|
767
|
177
|
|
|
|
|
655
|
my $string = ''; |
|
768
|
|
|
|
|
|
|
# is only set to 1 (within from_string()), otherwise is undef |
|
769
|
177
|
100
|
|
|
|
613
|
if ($self->{'opened_scalar'}) { |
|
770
|
7
|
|
|
|
|
60
|
$self->{'pdf'}->append_file(); |
|
771
|
7
|
|
|
|
|
15
|
$string = ${$self->{'content_ref'}}; |
|
|
7
|
|
|
|
|
73
|
|
|
772
|
|
|
|
|
|
|
} else { |
|
773
|
170
|
|
|
|
|
1760
|
my $fh = FileHandle->new(); |
|
774
|
|
|
|
|
|
|
# we should be writing to the STRING $str |
|
775
|
170
|
50
|
|
|
|
12132
|
CORE::open($fh, '>', \$string) || croak "Can't begin scalar IO"; |
|
776
|
170
|
|
|
|
|
1615
|
$self->{'pdf'}->out_file($fh); |
|
777
|
170
|
|
|
|
|
938
|
$fh->close(); |
|
778
|
|
|
|
|
|
|
} |
|
779
|
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
# This can be eliminated once we're confident that circular references are |
|
781
|
|
|
|
|
|
|
# no longer an issue. See t/circular-references.t |
|
782
|
177
|
|
|
|
|
2336
|
$self->end(); |
|
783
|
|
|
|
|
|
|
|
|
784
|
177
|
|
|
|
|
3870
|
return $string; |
|
785
|
|
|
|
|
|
|
} |
|
786
|
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
=head2 finishobjects |
|
788
|
|
|
|
|
|
|
|
|
789
|
|
|
|
|
|
|
$pdf->finishobjects(@objects) |
|
790
|
|
|
|
|
|
|
|
|
791
|
|
|
|
|
|
|
=over |
|
792
|
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
Force objects to be written to file if possible. |
|
794
|
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
B<Example:> |
|
796
|
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
=back |
|
798
|
|
|
|
|
|
|
|
|
799
|
|
|
|
|
|
|
$pdf = PDF::Builder->new(file => 'our/new.pdf'); |
|
800
|
|
|
|
|
|
|
... |
|
801
|
|
|
|
|
|
|
$pdf->finishobjects($page, $gfx, $txt); |
|
802
|
|
|
|
|
|
|
... |
|
803
|
|
|
|
|
|
|
$pdf->save(); |
|
804
|
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
=over |
|
806
|
|
|
|
|
|
|
|
|
807
|
|
|
|
|
|
|
B<Note:> this method is now considered obsolete, and may be deprecated. It |
|
808
|
|
|
|
|
|
|
allows for objects to be written to disk in advance of finally |
|
809
|
|
|
|
|
|
|
saving and closing the file. Otherwise, it's no different than just calling |
|
810
|
|
|
|
|
|
|
C<save()> when all changes have been made. There's no memory advantage since |
|
811
|
|
|
|
|
|
|
C<ship_out> doesn't remove objects from memory. |
|
812
|
|
|
|
|
|
|
|
|
813
|
|
|
|
|
|
|
=back |
|
814
|
|
|
|
|
|
|
|
|
815
|
|
|
|
|
|
|
=cut |
|
816
|
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
# obsolete, use save instead |
|
818
|
|
|
|
|
|
|
# |
|
819
|
|
|
|
|
|
|
# This method allows for objects to be written to disk in advance of finally |
|
820
|
|
|
|
|
|
|
# saving and closing the file. Otherwise, it's no different than just calling |
|
821
|
|
|
|
|
|
|
# save when all changes have been made. There's no memory advantage since |
|
822
|
|
|
|
|
|
|
# ship_out doesn't remove objects from memory. |
|
823
|
|
|
|
|
|
|
sub finishobjects { |
|
824
|
0
|
|
|
0
|
1
|
0
|
my ($self, @objs) = @_; |
|
825
|
|
|
|
|
|
|
|
|
826
|
0
|
0
|
|
|
|
0
|
if ($self->{'opened_scalar'}) { |
|
|
|
0
|
|
|
|
|
|
|
827
|
0
|
|
|
|
|
0
|
croak "invalid method invocation: no file, use 'saveas' instead."; |
|
828
|
|
|
|
|
|
|
} elsif ($self->{'partial_save'}) { |
|
829
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->ship_out(@objs); |
|
830
|
|
|
|
|
|
|
} else { |
|
831
|
0
|
|
|
|
|
0
|
croak "invalid method invocation: no file, use 'saveas' instead."; |
|
832
|
|
|
|
|
|
|
} |
|
833
|
|
|
|
|
|
|
|
|
834
|
0
|
|
|
|
|
0
|
return; |
|
835
|
|
|
|
|
|
|
} |
|
836
|
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
sub _proc_pages { |
|
838
|
18
|
|
|
18
|
|
64
|
my ($pdf, $object) = @_; |
|
839
|
|
|
|
|
|
|
|
|
840
|
18
|
50
|
|
|
|
93
|
if (defined $object->{'Resources'}) { |
|
841
|
18
|
|
|
|
|
42
|
eval { |
|
842
|
18
|
|
|
|
|
111
|
$object->{'Resources'}->realise(); |
|
843
|
|
|
|
|
|
|
}; |
|
844
|
|
|
|
|
|
|
} |
|
845
|
|
|
|
|
|
|
|
|
846
|
18
|
|
|
|
|
42
|
my @pages; |
|
847
|
18
|
|
50
|
|
|
155
|
$pdf->{' apipagecount'} ||= 0; |
|
848
|
18
|
|
|
|
|
93
|
foreach my $page ($object->{'Kids'}->elements()) { |
|
849
|
20
|
|
|
|
|
132
|
$page->realise(); |
|
850
|
|
|
|
|
|
|
#if ($page->{'Type'}->val() eq 'Pages') { |
|
851
|
20
|
50
|
33
|
|
|
154
|
if (defined $page->{'Type'} && $page->{'Type'}->val() eq 'Pages') { |
|
852
|
0
|
|
|
|
|
0
|
push @pages, _proc_pages($pdf, $page); |
|
853
|
|
|
|
|
|
|
} else { |
|
854
|
20
|
|
|
|
|
50
|
$pdf->{' apipagecount'}++; |
|
855
|
20
|
|
|
|
|
92
|
$page->{' pnum'} = $pdf->{' apipagecount'}; |
|
856
|
20
|
50
|
|
|
|
97
|
if (defined $page->{'Resources'}) { |
|
857
|
20
|
|
|
|
|
42
|
eval { |
|
858
|
20
|
|
|
|
|
112
|
$page->{'Resources'}->realise(); |
|
859
|
|
|
|
|
|
|
}; |
|
860
|
|
|
|
|
|
|
} |
|
861
|
20
|
|
|
|
|
77
|
push @pages, $page; |
|
862
|
|
|
|
|
|
|
} |
|
863
|
|
|
|
|
|
|
} |
|
864
|
|
|
|
|
|
|
|
|
865
|
18
|
|
|
|
|
74
|
return @pages; |
|
866
|
|
|
|
|
|
|
} # end of _proc_pages() |
|
867
|
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
=head2 update |
|
869
|
|
|
|
|
|
|
|
|
870
|
|
|
|
|
|
|
$pdf->update() |
|
871
|
|
|
|
|
|
|
|
|
872
|
|
|
|
|
|
|
=over |
|
873
|
|
|
|
|
|
|
|
|
874
|
|
|
|
|
|
|
Saves a previously opened document. |
|
875
|
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
B<Example:> |
|
877
|
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
=back |
|
879
|
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
$pdf = PDF::Builder->open('our/to/be/updated.pdf'); |
|
881
|
|
|
|
|
|
|
... |
|
882
|
|
|
|
|
|
|
$pdf->update(); |
|
883
|
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
=over |
|
885
|
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
B<Note:> it is considered better to simply C<save()> the file, rather than |
|
887
|
|
|
|
|
|
|
calling C<update()>. They end up doing the same thing, anyway. This method |
|
888
|
|
|
|
|
|
|
may be deprecated in the future. |
|
889
|
|
|
|
|
|
|
|
|
890
|
|
|
|
|
|
|
=back |
|
891
|
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
=cut |
|
893
|
|
|
|
|
|
|
|
|
894
|
|
|
|
|
|
|
# obsolete, use save instead |
|
895
|
|
|
|
|
|
|
sub update { |
|
896
|
0
|
|
|
0
|
1
|
0
|
my $self = shift(); |
|
897
|
0
|
|
|
|
|
0
|
$self->saveas($self->{'pdf'}->{' fname'}); |
|
898
|
0
|
|
|
|
|
0
|
return; |
|
899
|
|
|
|
|
|
|
} |
|
900
|
|
|
|
|
|
|
|
|
901
|
|
|
|
|
|
|
=head2 saveas |
|
902
|
|
|
|
|
|
|
|
|
903
|
|
|
|
|
|
|
$pdf->saveas($file) |
|
904
|
|
|
|
|
|
|
|
|
905
|
|
|
|
|
|
|
=over |
|
906
|
|
|
|
|
|
|
|
|
907
|
|
|
|
|
|
|
Save the document to $file and remove the object structure from memory. |
|
908
|
|
|
|
|
|
|
|
|
909
|
|
|
|
|
|
|
B<Caution:> Although the object C<$pdf> will still exist, it is no longer |
|
910
|
|
|
|
|
|
|
usable for any purpose after invoking this method! You will receive error |
|
911
|
|
|
|
|
|
|
messages about "can't call method new_obj on an undefined value". |
|
912
|
|
|
|
|
|
|
|
|
913
|
|
|
|
|
|
|
B<Example:> |
|
914
|
|
|
|
|
|
|
|
|
915
|
|
|
|
|
|
|
=back |
|
916
|
|
|
|
|
|
|
|
|
917
|
|
|
|
|
|
|
$pdf = PDF::Builder->new(); |
|
918
|
|
|
|
|
|
|
... |
|
919
|
|
|
|
|
|
|
$pdf->saveas('our/new.pdf'); |
|
920
|
|
|
|
|
|
|
|
|
921
|
|
|
|
|
|
|
=cut |
|
922
|
|
|
|
|
|
|
|
|
923
|
|
|
|
|
|
|
sub saveas { |
|
924
|
1
|
|
|
1
|
1
|
9
|
my ($self, $file) = @_; |
|
925
|
|
|
|
|
|
|
|
|
926
|
1
|
50
|
|
|
|
6
|
if ($self->{'opened_scalar'}) { |
|
|
|
0
|
|
|
|
|
|
|
927
|
1
|
|
|
|
|
10
|
$self->{'pdf'}->append_file(); |
|
928
|
1
|
|
|
|
|
3
|
my $fh; |
|
929
|
1
|
50
|
|
|
|
140
|
CORE::open($fh, '>', $file) or croak "Can't open $file for writing: $!"; |
|
930
|
1
|
|
|
|
|
10
|
binmode($fh, ':raw'); |
|
931
|
1
|
|
|
|
|
4
|
print $fh ${$self->{'content_ref'}}; |
|
|
1
|
|
|
|
|
8
|
|
|
932
|
1
|
|
|
|
|
235
|
CORE::close($fh); |
|
933
|
|
|
|
|
|
|
} elsif ($self->{'partial_save'}) { |
|
934
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->close_file(); |
|
935
|
|
|
|
|
|
|
} else { |
|
936
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->out_file($file); |
|
937
|
|
|
|
|
|
|
} |
|
938
|
|
|
|
|
|
|
|
|
939
|
1
|
|
|
|
|
10
|
$self->end(); |
|
940
|
1
|
|
|
|
|
69
|
return; |
|
941
|
|
|
|
|
|
|
} |
|
942
|
|
|
|
|
|
|
|
|
943
|
|
|
|
|
|
|
=head2 save |
|
944
|
|
|
|
|
|
|
|
|
945
|
|
|
|
|
|
|
$pdf->save() |
|
946
|
|
|
|
|
|
|
|
|
947
|
|
|
|
|
|
|
$pdf->save(filename) |
|
948
|
|
|
|
|
|
|
|
|
949
|
|
|
|
|
|
|
=over |
|
950
|
|
|
|
|
|
|
|
|
951
|
|
|
|
|
|
|
Save the document to an already-defined file (or filename) and |
|
952
|
|
|
|
|
|
|
remove the object structure from memory. |
|
953
|
|
|
|
|
|
|
Optionally, a new filename may be given. |
|
954
|
|
|
|
|
|
|
|
|
955
|
|
|
|
|
|
|
B<Caution:> Although the object C<$pdf> will still exist, it is no longer |
|
956
|
|
|
|
|
|
|
usable for any purpose after invoking this method! You will receive error |
|
957
|
|
|
|
|
|
|
messages about "can't call method new_obj on an undefined value". |
|
958
|
|
|
|
|
|
|
|
|
959
|
|
|
|
|
|
|
B<Example:> |
|
960
|
|
|
|
|
|
|
|
|
961
|
|
|
|
|
|
|
=back |
|
962
|
|
|
|
|
|
|
|
|
963
|
|
|
|
|
|
|
$pdf = PDF::Builder->new(file => 'file_to_output'); |
|
964
|
|
|
|
|
|
|
... |
|
965
|
|
|
|
|
|
|
$pdf->save(); |
|
966
|
|
|
|
|
|
|
|
|
967
|
|
|
|
|
|
|
=over |
|
968
|
|
|
|
|
|
|
|
|
969
|
|
|
|
|
|
|
B<Note:> now that C<save()> can take a filename as an argument, it effectively |
|
970
|
|
|
|
|
|
|
is interchangeable with C<saveas()>. This is strictly for compatibility with |
|
971
|
|
|
|
|
|
|
recent changes to PDF::API2. Unlike PDF::API2, we are not deprecating |
|
972
|
|
|
|
|
|
|
the C<saveas()> method, because in user interfaces, "save" normally means that |
|
973
|
|
|
|
|
|
|
the current filename is known and is to be used, while "saveas" normally means |
|
974
|
|
|
|
|
|
|
that (whether or not there is a current filename) a new filename is to be used. |
|
975
|
|
|
|
|
|
|
|
|
976
|
|
|
|
|
|
|
=back |
|
977
|
|
|
|
|
|
|
|
|
978
|
|
|
|
|
|
|
=cut |
|
979
|
|
|
|
|
|
|
|
|
980
|
|
|
|
|
|
|
sub save { |
|
981
|
0
|
|
|
0
|
1
|
0
|
my ($self, $file) = @_; |
|
982
|
|
|
|
|
|
|
|
|
983
|
0
|
0
|
|
|
|
0
|
if (defined $file) { |
|
984
|
0
|
|
|
|
|
0
|
return $self->saveas($file); |
|
985
|
|
|
|
|
|
|
} |
|
986
|
|
|
|
|
|
|
|
|
987
|
|
|
|
|
|
|
# NOTE: the current PDF::API2 version is quite different, but this may be |
|
988
|
|
|
|
|
|
|
# a consequence of merging save() and saveas(). Let's give this unchanged |
|
989
|
|
|
|
|
|
|
# version a try. |
|
990
|
0
|
0
|
|
|
|
0
|
if ($self->{'opened_scalar'}) { |
|
|
|
0
|
|
|
|
|
|
|
991
|
0
|
|
|
|
|
0
|
croak "Invalid method invocation: use 'saveas' instead of 'save'."; |
|
992
|
|
|
|
|
|
|
} elsif ($self->{'partial_save'}) { |
|
993
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->close_file(); |
|
994
|
|
|
|
|
|
|
} else { |
|
995
|
0
|
|
|
|
|
0
|
croak "Invalid method invocation: use 'saveas' instead of 'save'."; |
|
996
|
|
|
|
|
|
|
} |
|
997
|
|
|
|
|
|
|
|
|
998
|
0
|
|
|
|
|
0
|
$self->end(); |
|
999
|
0
|
|
|
|
|
0
|
return; |
|
1000
|
|
|
|
|
|
|
} |
|
1001
|
|
|
|
|
|
|
|
|
1002
|
|
|
|
|
|
|
=head2 close, release, end |
|
1003
|
|
|
|
|
|
|
|
|
1004
|
|
|
|
|
|
|
$pdf->close(); |
|
1005
|
|
|
|
|
|
|
|
|
1006
|
|
|
|
|
|
|
=over |
|
1007
|
|
|
|
|
|
|
|
|
1008
|
|
|
|
|
|
|
Close an open file (if relevant) and remove the object structure from memory. |
|
1009
|
|
|
|
|
|
|
|
|
1010
|
|
|
|
|
|
|
PDF::API2 contains circular references, so this call is necessary in |
|
1011
|
|
|
|
|
|
|
long-running processes to keep from running out of memory. |
|
1012
|
|
|
|
|
|
|
|
|
1013
|
|
|
|
|
|
|
This will be called automatically when you save or stringify a PDF. |
|
1014
|
|
|
|
|
|
|
You should only need to call it explicitly if you are reading PDF |
|
1015
|
|
|
|
|
|
|
files and not writing them. |
|
1016
|
|
|
|
|
|
|
|
|
1017
|
|
|
|
|
|
|
B<Alternate names:> C<release> and C<end> |
|
1018
|
|
|
|
|
|
|
|
|
1019
|
|
|
|
|
|
|
=back |
|
1020
|
|
|
|
|
|
|
|
|
1021
|
|
|
|
|
|
|
=cut |
|
1022
|
|
|
|
|
|
|
|
|
1023
|
|
|
|
|
|
|
=head2 end |
|
1024
|
|
|
|
|
|
|
|
|
1025
|
|
|
|
|
|
|
$pdf->end() |
|
1026
|
|
|
|
|
|
|
|
|
1027
|
|
|
|
|
|
|
=over |
|
1028
|
|
|
|
|
|
|
|
|
1029
|
|
|
|
|
|
|
Remove the object structure from memory. PDF::Builder contains circular |
|
1030
|
|
|
|
|
|
|
references, so this call is necessary in long-running processes to |
|
1031
|
|
|
|
|
|
|
keep from running out of memory. |
|
1032
|
|
|
|
|
|
|
|
|
1033
|
|
|
|
|
|
|
This will be called automatically when you save or to_string a PDF. |
|
1034
|
|
|
|
|
|
|
You should only need to call it explicitly if you are reading PDF |
|
1035
|
|
|
|
|
|
|
files and not writing them. |
|
1036
|
|
|
|
|
|
|
|
|
1037
|
|
|
|
|
|
|
This (and I<release>) are older and now deprecated names formerly used in |
|
1038
|
|
|
|
|
|
|
PDF::API2 and PDF::Builder. You should try to avoid having to explicitly |
|
1039
|
|
|
|
|
|
|
call them. |
|
1040
|
|
|
|
|
|
|
|
|
1041
|
|
|
|
|
|
|
=back |
|
1042
|
|
|
|
|
|
|
|
|
1043
|
|
|
|
|
|
|
=cut |
|
1044
|
|
|
|
|
|
|
|
|
1045
|
|
|
|
|
|
|
# Deprecated (renamed) |
|
1046
|
0
|
|
|
0
|
1
|
0
|
sub release { return $_[0]->close(); } |
|
1047
|
178
|
|
|
178
|
1
|
823
|
sub end { return $_[0]->close(); } |
|
1048
|
|
|
|
|
|
|
|
|
1049
|
|
|
|
|
|
|
sub close { |
|
1050
|
178
|
|
|
178
|
1
|
400
|
my $self = shift(); |
|
1051
|
178
|
50
|
|
|
|
1642
|
$self->{'pdf'}->release() if defined $self->{'pdf'}; |
|
1052
|
|
|
|
|
|
|
|
|
1053
|
178
|
|
|
|
|
1254
|
foreach my $key (keys %$self) { |
|
1054
|
1620
|
|
|
|
|
13698
|
$self->{$key} = undef; |
|
1055
|
1620
|
|
|
|
|
2975
|
delete $self->{$key}; |
|
1056
|
|
|
|
|
|
|
} |
|
1057
|
|
|
|
|
|
|
|
|
1058
|
178
|
|
|
|
|
789
|
return; |
|
1059
|
|
|
|
|
|
|
} |
|
1060
|
|
|
|
|
|
|
|
|
1061
|
|
|
|
|
|
|
=head2 METADATA METHODS |
|
1062
|
|
|
|
|
|
|
|
|
1063
|
|
|
|
|
|
|
=head3 title |
|
1064
|
|
|
|
|
|
|
|
|
1065
|
|
|
|
|
|
|
$title = $pdf->title(); |
|
1066
|
|
|
|
|
|
|
|
|
1067
|
|
|
|
|
|
|
$pdf = $pdf->title($title); |
|
1068
|
|
|
|
|
|
|
|
|
1069
|
|
|
|
|
|
|
=over |
|
1070
|
|
|
|
|
|
|
|
|
1071
|
|
|
|
|
|
|
Get/set/clear the document's title. |
|
1072
|
|
|
|
|
|
|
|
|
1073
|
|
|
|
|
|
|
=back |
|
1074
|
|
|
|
|
|
|
|
|
1075
|
|
|
|
|
|
|
=cut |
|
1076
|
|
|
|
|
|
|
|
|
1077
|
|
|
|
|
|
|
sub title { |
|
1078
|
0
|
|
|
0
|
1
|
0
|
my $self = shift(); |
|
1079
|
0
|
|
|
|
|
0
|
return $self->info_metadata('Title', @_); |
|
1080
|
|
|
|
|
|
|
} |
|
1081
|
|
|
|
|
|
|
|
|
1082
|
|
|
|
|
|
|
=head3 author |
|
1083
|
|
|
|
|
|
|
|
|
1084
|
|
|
|
|
|
|
$author = $pdf->author(); |
|
1085
|
|
|
|
|
|
|
|
|
1086
|
|
|
|
|
|
|
$pdf = $pdf->author($author); |
|
1087
|
|
|
|
|
|
|
|
|
1088
|
|
|
|
|
|
|
=over |
|
1089
|
|
|
|
|
|
|
|
|
1090
|
|
|
|
|
|
|
Get/set/clear the name of the person who created the document. |
|
1091
|
|
|
|
|
|
|
|
|
1092
|
|
|
|
|
|
|
=back |
|
1093
|
|
|
|
|
|
|
|
|
1094
|
|
|
|
|
|
|
=cut |
|
1095
|
|
|
|
|
|
|
|
|
1096
|
|
|
|
|
|
|
sub author { |
|
1097
|
0
|
|
|
0
|
1
|
0
|
my $self = shift(); |
|
1098
|
0
|
|
|
|
|
0
|
return $self->info_metadata('Author', @_); |
|
1099
|
|
|
|
|
|
|
} |
|
1100
|
|
|
|
|
|
|
|
|
1101
|
|
|
|
|
|
|
=head3 subject |
|
1102
|
|
|
|
|
|
|
|
|
1103
|
|
|
|
|
|
|
$subject = $pdf->subject(); |
|
1104
|
|
|
|
|
|
|
|
|
1105
|
|
|
|
|
|
|
$pdf = $pdf->subject($subject); |
|
1106
|
|
|
|
|
|
|
|
|
1107
|
|
|
|
|
|
|
=over |
|
1108
|
|
|
|
|
|
|
|
|
1109
|
|
|
|
|
|
|
Get/set/clear the subject of the document. |
|
1110
|
|
|
|
|
|
|
|
|
1111
|
|
|
|
|
|
|
=back |
|
1112
|
|
|
|
|
|
|
|
|
1113
|
|
|
|
|
|
|
=cut |
|
1114
|
|
|
|
|
|
|
|
|
1115
|
|
|
|
|
|
|
sub subject { |
|
1116
|
0
|
|
|
0
|
1
|
0
|
my $self = shift(); |
|
1117
|
0
|
|
|
|
|
0
|
return $self->info_metadata('Subject', @_); |
|
1118
|
|
|
|
|
|
|
} |
|
1119
|
|
|
|
|
|
|
|
|
1120
|
|
|
|
|
|
|
=head3 keywords |
|
1121
|
|
|
|
|
|
|
|
|
1122
|
|
|
|
|
|
|
$keywords = $pdf->keywords(); |
|
1123
|
|
|
|
|
|
|
|
|
1124
|
|
|
|
|
|
|
$pdf = $pdf->keywords($keywords); |
|
1125
|
|
|
|
|
|
|
|
|
1126
|
|
|
|
|
|
|
=over |
|
1127
|
|
|
|
|
|
|
|
|
1128
|
|
|
|
|
|
|
Get/set/clear a space-separated string of keywords associated with the document. |
|
1129
|
|
|
|
|
|
|
|
|
1130
|
|
|
|
|
|
|
=back |
|
1131
|
|
|
|
|
|
|
|
|
1132
|
|
|
|
|
|
|
=cut |
|
1133
|
|
|
|
|
|
|
|
|
1134
|
|
|
|
|
|
|
sub keywords { |
|
1135
|
0
|
|
|
0
|
1
|
0
|
my $self = shift(); |
|
1136
|
0
|
|
|
|
|
0
|
return $self->info_metadata('Keywords', @_); |
|
1137
|
|
|
|
|
|
|
} |
|
1138
|
|
|
|
|
|
|
|
|
1139
|
|
|
|
|
|
|
=head3 creator |
|
1140
|
|
|
|
|
|
|
|
|
1141
|
|
|
|
|
|
|
$creator = $pdf->creator(); |
|
1142
|
|
|
|
|
|
|
|
|
1143
|
|
|
|
|
|
|
$pdf = $pdf->creator($creator); |
|
1144
|
|
|
|
|
|
|
|
|
1145
|
|
|
|
|
|
|
=over |
|
1146
|
|
|
|
|
|
|
|
|
1147
|
|
|
|
|
|
|
Get/set/clear the name of the product that created the document prior to its |
|
1148
|
|
|
|
|
|
|
conversion to PDF. |
|
1149
|
|
|
|
|
|
|
|
|
1150
|
|
|
|
|
|
|
=back |
|
1151
|
|
|
|
|
|
|
|
|
1152
|
|
|
|
|
|
|
=cut |
|
1153
|
|
|
|
|
|
|
|
|
1154
|
|
|
|
|
|
|
sub creator { |
|
1155
|
0
|
|
|
0
|
1
|
0
|
my $self = shift(); |
|
1156
|
0
|
|
|
|
|
0
|
return $self->info_metadata('Creator', @_); |
|
1157
|
|
|
|
|
|
|
} |
|
1158
|
|
|
|
|
|
|
|
|
1159
|
|
|
|
|
|
|
=head3 producer |
|
1160
|
|
|
|
|
|
|
|
|
1161
|
|
|
|
|
|
|
$producer = $pdf->producer(); |
|
1162
|
|
|
|
|
|
|
|
|
1163
|
|
|
|
|
|
|
$pdf = $pdf->producer($producer); |
|
1164
|
|
|
|
|
|
|
|
|
1165
|
|
|
|
|
|
|
=over |
|
1166
|
|
|
|
|
|
|
|
|
1167
|
|
|
|
|
|
|
Get/set/clear the name of the product that converted the original document to |
|
1168
|
|
|
|
|
|
|
PDF. |
|
1169
|
|
|
|
|
|
|
|
|
1170
|
|
|
|
|
|
|
PDF::Builder fills in this field when creating a PDF. |
|
1171
|
|
|
|
|
|
|
|
|
1172
|
|
|
|
|
|
|
=back |
|
1173
|
|
|
|
|
|
|
|
|
1174
|
|
|
|
|
|
|
=cut |
|
1175
|
|
|
|
|
|
|
|
|
1176
|
|
|
|
|
|
|
sub producer { |
|
1177
|
5
|
|
|
5
|
1
|
16
|
my $self = shift(); |
|
1178
|
5
|
|
|
|
|
19
|
return $self->info_metadata('Producer', @_); |
|
1179
|
|
|
|
|
|
|
} |
|
1180
|
|
|
|
|
|
|
|
|
1181
|
|
|
|
|
|
|
=head3 created |
|
1182
|
|
|
|
|
|
|
|
|
1183
|
|
|
|
|
|
|
$date = $pdf->created(); |
|
1184
|
|
|
|
|
|
|
|
|
1185
|
|
|
|
|
|
|
$pdf = $pdf->created($date); |
|
1186
|
|
|
|
|
|
|
|
|
1187
|
|
|
|
|
|
|
=over |
|
1188
|
|
|
|
|
|
|
|
|
1189
|
|
|
|
|
|
|
Get/set/clear the document's creation date. |
|
1190
|
|
|
|
|
|
|
|
|
1191
|
|
|
|
|
|
|
The date format is C<D:YYYYMMDDHHmmSSOHH'mm>, where C<D:> is a static prefix |
|
1192
|
|
|
|
|
|
|
identifying the string as a PDF date. The date may be truncated at any point |
|
1193
|
|
|
|
|
|
|
after the year. C<O> is one of C<+>, C<->, or C<Z>, with the following C<HH'mm> |
|
1194
|
|
|
|
|
|
|
representing an offset from UTC. |
|
1195
|
|
|
|
|
|
|
|
|
1196
|
|
|
|
|
|
|
See comments in the internal function C<_is_date()> for more information on |
|
1197
|
|
|
|
|
|
|
the inconsistency of PDF standards on exactly what the date format should be! |
|
1198
|
|
|
|
|
|
|
|
|
1199
|
|
|
|
|
|
|
When setting the date, C<D:> will be prepended automatically if omitted. |
|
1200
|
|
|
|
|
|
|
|
|
1201
|
|
|
|
|
|
|
=back |
|
1202
|
|
|
|
|
|
|
|
|
1203
|
|
|
|
|
|
|
=cut |
|
1204
|
|
|
|
|
|
|
|
|
1205
|
|
|
|
|
|
|
sub created { |
|
1206
|
1
|
|
|
1
|
1
|
3
|
my $self = shift(); |
|
1207
|
1
|
|
|
|
|
5
|
return $self->info_metadata('CreationDate', @_); |
|
1208
|
|
|
|
|
|
|
} |
|
1209
|
|
|
|
|
|
|
|
|
1210
|
|
|
|
|
|
|
=head3 modified |
|
1211
|
|
|
|
|
|
|
|
|
1212
|
|
|
|
|
|
|
$date = $pdf->modified(); |
|
1213
|
|
|
|
|
|
|
|
|
1214
|
|
|
|
|
|
|
$pdf = $pdf->modified($date); |
|
1215
|
|
|
|
|
|
|
|
|
1216
|
|
|
|
|
|
|
=over |
|
1217
|
|
|
|
|
|
|
|
|
1218
|
|
|
|
|
|
|
Get/set/clear the document's modification date. The date format is as described |
|
1219
|
|
|
|
|
|
|
in C<created> above. |
|
1220
|
|
|
|
|
|
|
|
|
1221
|
|
|
|
|
|
|
See comments in the internal function C<_is_date()> for more information on |
|
1222
|
|
|
|
|
|
|
the inconsistency of PDF standards on exactly what the date format should be! |
|
1223
|
|
|
|
|
|
|
|
|
1224
|
|
|
|
|
|
|
=back |
|
1225
|
|
|
|
|
|
|
|
|
1226
|
|
|
|
|
|
|
=cut |
|
1227
|
|
|
|
|
|
|
|
|
1228
|
|
|
|
|
|
|
sub modified { |
|
1229
|
1
|
|
|
1
|
1
|
8
|
my $self = shift(); |
|
1230
|
1
|
|
|
|
|
4
|
return $self->info_metadata('ModDate', @_); |
|
1231
|
|
|
|
|
|
|
} |
|
1232
|
|
|
|
|
|
|
|
|
1233
|
|
|
|
|
|
|
sub _is_date { |
|
1234
|
2
|
|
|
2
|
|
5
|
my $value = shift(); |
|
1235
|
|
|
|
|
|
|
|
|
1236
|
|
|
|
|
|
|
# there are lists of leap seconds floating around, such as |
|
1237
|
|
|
|
|
|
|
# https://www.ietf.org/timezones/data/leap-seconds.list |
|
1238
|
|
|
|
|
|
|
# https://en.wikipedia.org/wiki/Leap_second |
|
1239
|
2
|
|
|
|
|
76
|
my %leap_sec = ('06'=>{ |
|
1240
|
|
|
|
|
|
|
1972=>1, 1981=>1, 1982=>1, 1983=>1, 1985=>1, 1992=>1, |
|
1241
|
|
|
|
|
|
|
1993=>1, 1994=>1, 1997=>1, 2012=>1, 2015=>1}, |
|
1242
|
|
|
|
|
|
|
'12'=>{ |
|
1243
|
|
|
|
|
|
|
1972=>1, 1973=>1, 1974=>1, 1975=>1, 1976=>1, 1977=>1, |
|
1244
|
|
|
|
|
|
|
1978=>1, 1979=>1, 1987=>1, 1989=>1, 1990=>1, 1995=>1, |
|
1245
|
|
|
|
|
|
|
1998=>1, 2005=>1, 2008=>1, 2016=>1}); |
|
1246
|
|
|
|
|
|
|
# some sources list Dec 1971 as having a leap second, others don't |
|
1247
|
|
|
|
|
|
|
|
|
1248
|
|
|
|
|
|
|
# PDF 1.7 section 7.9.4 describes the required date format. Other than the |
|
1249
|
|
|
|
|
|
|
# D: prefix and the year, all components are optional but must be present if |
|
1250
|
|
|
|
|
|
|
# a later component is present. |
|
1251
|
|
|
|
|
|
|
# |
|
1252
|
|
|
|
|
|
|
# comments by PM Perry: |
|
1253
|
|
|
|
|
|
|
# There is some conflict among various Adobe/ISO reference documents, as |
|
1254
|
|
|
|
|
|
|
# well as ambiguity within them (e.g., the example drops the seconds |
|
1255
|
|
|
|
|
|
|
# field, a trailing ' may or may not be required in a TZ offset). In |
|
1256
|
|
|
|
|
|
|
# addition, the PDF format seems to be something of a subset of ISO 8601. |
|
1257
|
|
|
|
|
|
|
# I have attempted to satisfy as many of the Adobe PDF reference documents |
|
1258
|
|
|
|
|
|
|
# as I could, but there are no guarantees that all PDF editors and readers |
|
1259
|
|
|
|
|
|
|
# will accept any given date/timestamp! |
|
1260
|
|
|
|
|
|
|
# See https://www.rfc-editor.org/rfc/rfc3339#section-5.6, remembering that |
|
1261
|
|
|
|
|
|
|
# many ISO 8601-compliant stamps will be considered invalid here. If there |
|
1262
|
|
|
|
|
|
|
# is demand for it, additional formats might be supported, and even a |
|
1263
|
|
|
|
|
|
|
# format or flag that says, "Here is my timestamp. Do not validate -- trust |
|
1264
|
|
|
|
|
|
|
# me, I know what I'm doing!" |
|
1265
|
|
|
|
|
|
|
|
|
1266
|
2
|
|
|
|
|
6
|
my ($year, $month, $day, $hour, $minute, $second, $od, $oh, $om, $ts, $tz); |
|
1267
|
2
|
50
|
|
|
|
14
|
if ($value =~ /([Z+-])/) { # should be only zero (leave od undef) or one |
|
1268
|
2
|
|
|
|
|
9
|
$od = $1; |
|
1269
|
|
|
|
|
|
|
} else { |
|
1270
|
0
|
|
|
|
|
0
|
$od = undef; # in case value left over from previous data |
|
1271
|
|
|
|
|
|
|
} |
|
1272
|
|
|
|
|
|
|
# make sure od defined (and not empty) |
|
1273
|
2
|
|
50
|
|
|
6
|
$od ||= 'Z'; |
|
1274
|
|
|
|
|
|
|
# ts must always have something, tz might not |
|
1275
|
2
|
|
|
|
|
13
|
($ts, $tz) = split /[Z+-]/, $value; |
|
1276
|
2
|
|
100
|
|
|
11
|
$tz ||= ''; |
|
1277
|
|
|
|
|
|
|
|
|
1278
|
2
|
50
|
|
|
|
27
|
return 0 unless $ts =~ /^D:([0-9]{4}) # D:YYYY (required) |
|
1279
|
|
|
|
|
|
|
(?:([0-1][0-9]) # Month (01-12) |
|
1280
|
|
|
|
|
|
|
(?:([0-3][0-9]) # Day (01-31) |
|
1281
|
|
|
|
|
|
|
(?:([0-2][0-9]) # Hour (00-23) |
|
1282
|
|
|
|
|
|
|
(?:([0-5][0-9]) # Minute (00-59) |
|
1283
|
|
|
|
|
|
|
(?:([0-6][0-9]) # Second (00-59), also leap sec |
|
1284
|
|
|
|
|
|
|
?)?)?)?)?)?$/x; |
|
1285
|
2
|
|
|
|
|
17
|
($year, $month, $day, $hour, $minute, $second) |
|
1286
|
|
|
|
|
|
|
= ($1, $2, $3, $4, $5, $6); |
|
1287
|
2
|
|
50
|
|
|
6
|
$month ||= 1; |
|
1288
|
2
|
|
50
|
|
|
6
|
$day ||= 1; |
|
1289
|
2
|
|
50
|
|
|
7
|
$hour ||= 0; |
|
1290
|
2
|
|
50
|
|
|
6
|
$minute ||= 0; |
|
1291
|
2
|
|
50
|
|
|
7
|
$second ||= 0; |
|
1292
|
|
|
|
|
|
|
|
|
1293
|
|
|
|
|
|
|
# od is Z (tz s/b ''), or od is + or - with hh or more |
|
1294
|
2
|
100
|
|
|
|
7
|
if ($od ne 'Z') { |
|
1295
|
|
|
|
|
|
|
# must be + or -, and at least an hour given |
|
1296
|
|
|
|
|
|
|
# ' before minutes (if given), optional ' after minutes |
|
1297
|
|
|
|
|
|
|
# regexp should fail if tz is '' |
|
1298
|
1
|
50
|
|
|
|
9
|
return 0 unless $tz =~ /^([0-2][0-9]) # UT Offset Hours |
|
1299
|
|
|
|
|
|
|
(?:'?([0-5][0-9]) # UT Offset Minutes |
|
1300
|
|
|
|
|
|
|
(?:' # optional ' |
|
1301
|
|
|
|
|
|
|
?)?)?$/x; |
|
1302
|
1
|
|
|
|
|
4
|
($oh, $om) = ($1, $2); |
|
1303
|
1
|
|
50
|
|
|
4
|
$oh ||= 0; |
|
1304
|
1
|
|
50
|
|
|
3
|
$om ||= 0; |
|
1305
|
1
|
50
|
33
|
|
|
5
|
if ($oh == 0 && $om == 0) { |
|
1306
|
|
|
|
|
|
|
# +/- 0 offset, so just make it Z |
|
1307
|
0
|
|
|
|
|
0
|
$od = 'Z'; |
|
1308
|
|
|
|
|
|
|
} |
|
1309
|
|
|
|
|
|
|
} else { |
|
1310
|
|
|
|
|
|
|
# explicit Z spec, shouldn't have an offset |
|
1311
|
1
|
50
|
|
|
|
4
|
if ($tz ne '') { |
|
1312
|
0
|
|
|
|
|
0
|
carp "Ignoring hour['minute] offset with Z timezone\n"; |
|
1313
|
|
|
|
|
|
|
} |
|
1314
|
1
|
|
|
|
|
2
|
$oh = $om = 0; |
|
1315
|
|
|
|
|
|
|
} |
|
1316
|
2
|
|
100
|
|
|
9
|
$oh ||= 0; |
|
1317
|
2
|
|
100
|
|
|
33
|
$om ||= 0; |
|
1318
|
2
|
100
|
66
|
|
|
10
|
if ($oh == 0 && $om == 0) { $od = 'Z'; |
|
|
1
|
|
|
|
|
2
|
|
|
1319
|
|
|
|
|
|
|
} |
|
1320
|
|
|
|
|
|
|
|
|
1321
|
|
|
|
|
|
|
# Do some basic validation to catch accidental date formatting issues. |
|
1322
|
|
|
|
|
|
|
# Complete date validation is out of scope. |
|
1323
|
|
|
|
|
|
|
# add determination of leap year and leap day |
|
1324
|
|
|
|
|
|
|
# treat ALL years as Gregorian calendar! |
|
1325
|
2
|
|
|
|
|
4
|
my $is_leap; |
|
1326
|
2
|
100
|
|
|
|
12
|
if ($year % 400 == 0) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
1327
|
1
|
|
|
|
|
3
|
$is_leap = 1; |
|
1328
|
|
|
|
|
|
|
} elsif ($year % 100 == 0) { |
|
1329
|
0
|
|
|
|
|
0
|
$is_leap = 0; |
|
1330
|
|
|
|
|
|
|
} elsif ($year % 4 == 0) { |
|
1331
|
0
|
|
|
|
|
0
|
$is_leap = 1; |
|
1332
|
|
|
|
|
|
|
} else { |
|
1333
|
1
|
|
|
|
|
3
|
$is_leap = 0; |
|
1334
|
|
|
|
|
|
|
} |
|
1335
|
2
|
|
|
|
|
8
|
my @mon_len = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); |
|
1336
|
2
|
100
|
|
|
|
6
|
if ($is_leap) { $mon_len[1]++; } |
|
|
1
|
|
|
|
|
2
|
|
|
1337
|
|
|
|
|
|
|
|
|
1338
|
2
|
50
|
33
|
|
|
14
|
return 0 unless $month >= 1 and $month <= 12; |
|
1339
|
2
|
50
|
33
|
|
|
20
|
return 0 unless $day >= 1 and $day <= 31; |
|
1340
|
2
|
50
|
|
|
|
8
|
return 0 if $day > $mon_len[$month-1]; # added exact month length check |
|
1341
|
2
|
50
|
|
|
|
6
|
return 0 unless $hour <= 23; |
|
1342
|
2
|
50
|
|
|
|
12
|
return 0 unless $minute <= 59; |
|
1343
|
2
|
50
|
|
|
|
11
|
return 0 unless $oh <= 23; |
|
1344
|
2
|
50
|
|
|
|
7
|
return 0 unless $om <= 59; |
|
1345
|
2
|
50
|
|
|
|
8
|
return 0 if $second > 60; |
|
1346
|
2
|
50
|
|
|
|
6
|
if ($second == 60) { |
|
1347
|
|
|
|
|
|
|
# claimed leap second -- verify |
|
1348
|
|
|
|
|
|
|
# remember that +oh/om can place local date into next year! |
|
1349
|
|
|
|
|
|
|
# correct local date and time (per offset) to UTC (Z) |
|
1350
|
0
|
|
|
|
|
0
|
my $newy = $year; |
|
1351
|
0
|
|
|
|
|
0
|
my $newM = $month; |
|
1352
|
0
|
|
|
|
|
0
|
my $newd = $day; |
|
1353
|
0
|
|
|
|
|
0
|
my $newh = $hour; |
|
1354
|
0
|
|
|
|
|
0
|
my $newm = $minute; |
|
1355
|
|
|
|
|
|
|
# assuming tz offset won't move more than 1 day either way |
|
1356
|
|
|
|
|
|
|
# (max offset 12 or 13 hours?) |
|
1357
|
|
|
|
|
|
|
# we're really only interested if date/time adjusted to Z is |
|
1358
|
|
|
|
|
|
|
# June 30 or December 31 at 23:59:60Z, for certain years |
|
1359
|
0
|
0
|
|
|
|
0
|
if ($od eq '+') { |
|
|
|
0
|
|
|
|
|
|
|
1360
|
|
|
|
|
|
|
# sub h:m could put us in previous day (and month, but not year) |
|
1361
|
|
|
|
|
|
|
# if not, it's not possibly 23:59:60Z |
|
1362
|
0
|
|
|
|
|
0
|
$newh -= $oh; |
|
1363
|
0
|
|
|
|
|
0
|
$newm -= $om; |
|
1364
|
0
|
0
|
|
|
|
0
|
if ($newm < 0) { |
|
1365
|
0
|
|
|
|
|
0
|
$newm += 60; |
|
1366
|
0
|
|
|
|
|
0
|
$newh--; |
|
1367
|
|
|
|
|
|
|
} |
|
1368
|
0
|
0
|
|
|
|
0
|
if ($newh < 0) { |
|
1369
|
0
|
|
|
|
|
0
|
$newh += 24; |
|
1370
|
0
|
|
|
|
|
0
|
$newd--; |
|
1371
|
0
|
0
|
|
|
|
0
|
if ($newd == 0) { |
|
1372
|
|
|
|
|
|
|
# local was first day of Jan or Jul? |
|
1373
|
0
|
|
|
|
|
0
|
$newM--; |
|
1374
|
0
|
0
|
|
|
|
0
|
if ($newM == 0) { |
|
|
|
0
|
|
|
|
|
|
|
1375
|
0
|
|
|
|
|
0
|
$newM = 12; |
|
1376
|
0
|
|
|
|
|
0
|
$newd = 31; |
|
1377
|
0
|
|
|
|
|
0
|
$newy--; |
|
1378
|
|
|
|
|
|
|
} elsif ($newM == 6) { |
|
1379
|
0
|
|
|
|
|
0
|
$newd = 30; |
|
1380
|
|
|
|
|
|
|
} else { |
|
1381
|
|
|
|
|
|
|
# last day of previous month, not Dec or Jun |
|
1382
|
0
|
|
|
|
|
0
|
return 0; |
|
1383
|
|
|
|
|
|
|
} |
|
1384
|
|
|
|
|
|
|
} else { |
|
1385
|
0
|
|
|
|
|
0
|
return 0; # wasn't last day of Dec or Jun (local date) |
|
1386
|
|
|
|
|
|
|
} |
|
1387
|
|
|
|
|
|
|
} else { |
|
1388
|
|
|
|
|
|
|
# if got to here, didn't back up to previous day |
|
1389
|
0
|
|
|
|
|
0
|
return 0; |
|
1390
|
|
|
|
|
|
|
} |
|
1391
|
|
|
|
|
|
|
|
|
1392
|
|
|
|
|
|
|
} elsif ($od eq '-') { |
|
1393
|
|
|
|
|
|
|
# add h:m could put us in next day (and month, and even year) |
|
1394
|
0
|
|
|
|
|
0
|
$newh += $oh; |
|
1395
|
0
|
|
|
|
|
0
|
$newm += $om; |
|
1396
|
0
|
0
|
|
|
|
0
|
if ($newm > 59) { |
|
1397
|
0
|
|
|
|
|
0
|
$newm -= 60; |
|
1398
|
0
|
|
|
|
|
0
|
$newh++; |
|
1399
|
|
|
|
|
|
|
} |
|
1400
|
0
|
0
|
|
|
|
0
|
if ($newh > 23) { |
|
1401
|
0
|
|
|
|
|
0
|
$newh -= 24; |
|
1402
|
0
|
|
|
|
|
0
|
$newd++; |
|
1403
|
0
|
0
|
|
|
|
0
|
if ($newd > $mon_len[$month-1]) { |
|
1404
|
|
|
|
|
|
|
# local was last day of month, now (Z) 1st, wrong date |
|
1405
|
0
|
|
|
|
|
0
|
$newM++; |
|
1406
|
0
|
|
|
|
|
0
|
$newd = 1; |
|
1407
|
0
|
0
|
|
|
|
0
|
if ($newM > 12) { |
|
1408
|
0
|
|
|
|
|
0
|
$newM = 1; |
|
1409
|
0
|
|
|
|
|
0
|
$newy++; |
|
1410
|
|
|
|
|
|
|
} |
|
1411
|
0
|
|
|
|
|
0
|
return 0; # ended up on 1st of a month, invalid leap second |
|
1412
|
|
|
|
|
|
|
} |
|
1413
|
|
|
|
|
|
|
} |
|
1414
|
|
|
|
|
|
|
# only Dec 31 and Jun 30 are eligible for consideration |
|
1415
|
0
|
0
|
0
|
|
|
0
|
if (!($newM == 6 && $newd == 30 || |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1416
|
|
|
|
|
|
|
$newM == 12 && $newd == 31)) { |
|
1417
|
0
|
|
|
|
|
0
|
return 0; |
|
1418
|
|
|
|
|
|
|
} |
|
1419
|
|
|
|
|
|
|
|
|
1420
|
|
|
|
|
|
|
} else { |
|
1421
|
|
|
|
|
|
|
# local time is already Z, just use newh and newm |
|
1422
|
0
|
0
|
0
|
|
|
0
|
if (!($newM == 6 && $newd == 30 || |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1423
|
|
|
|
|
|
|
$newM == 12 && $newd == 31)) { |
|
1424
|
0
|
|
|
|
|
0
|
return 0; # not Dec 31 or Jun 30 |
|
1425
|
|
|
|
|
|
|
} |
|
1426
|
|
|
|
|
|
|
} |
|
1427
|
|
|
|
|
|
|
|
|
1428
|
|
|
|
|
|
|
# time newh:newm corrected to Z. check if 23:59. |
|
1429
|
|
|
|
|
|
|
# date corrected to Z, is OK (Dec 31 or Jun 30), |
|
1430
|
|
|
|
|
|
|
# check if is actual leap second date. |
|
1431
|
0
|
0
|
0
|
|
|
0
|
if ($newh == 23 && $newm == 59 && # second is 60 |
|
|
|
|
0
|
|
|
|
|
|
1432
|
|
|
|
|
|
|
defined $leap_sec{$newM}->{$newy} |
|
1433
|
|
|
|
|
|
|
# assuming value is +1. if ever -1, need more code TBD |
|
1434
|
|
|
|
|
|
|
# (23:59:58 would be last second of month) |
|
1435
|
|
|
|
|
|
|
# already on last day of listed month. at 23:59:60Z? |
|
1436
|
|
|
|
|
|
|
# valid leap second |
|
1437
|
|
|
|
|
|
|
) { |
|
1438
|
|
|
|
|
|
|
} else { |
|
1439
|
0
|
|
|
|
|
0
|
return 0; |
|
1440
|
|
|
|
|
|
|
} |
|
1441
|
|
|
|
|
|
|
} |
|
1442
|
|
|
|
|
|
|
|
|
1443
|
2
|
|
|
|
|
23
|
return 1; |
|
1444
|
|
|
|
|
|
|
} |
|
1445
|
|
|
|
|
|
|
|
|
1446
|
|
|
|
|
|
|
=head3 info_metadata |
|
1447
|
|
|
|
|
|
|
|
|
1448
|
|
|
|
|
|
|
%info = $pdf->info_metadata(); # Get all keys and values |
|
1449
|
|
|
|
|
|
|
|
|
1450
|
|
|
|
|
|
|
$value = $pdf->info_metadata($key); # Get the value of one key |
|
1451
|
|
|
|
|
|
|
|
|
1452
|
|
|
|
|
|
|
$pdf = $pdf->info_metadata($key, $value); # Set the value of one key |
|
1453
|
|
|
|
|
|
|
|
|
1454
|
|
|
|
|
|
|
=over |
|
1455
|
|
|
|
|
|
|
|
|
1456
|
|
|
|
|
|
|
Get/set/clear a key in the document's information dictionary. The standard keys |
|
1457
|
|
|
|
|
|
|
(title, author, etc.) have their own accessors, so this is primarily intended |
|
1458
|
|
|
|
|
|
|
for interacting with custom metadata. |
|
1459
|
|
|
|
|
|
|
|
|
1460
|
|
|
|
|
|
|
Pass C<undef> as the value in order to remove the key from the dictionary. |
|
1461
|
|
|
|
|
|
|
|
|
1462
|
|
|
|
|
|
|
See comments in the internal function C<_is_date()> for more information on |
|
1463
|
|
|
|
|
|
|
the inconsistency of PDF standards on exactly what the date format should be! |
|
1464
|
|
|
|
|
|
|
This applies to CreationDate and ModDate keys. |
|
1465
|
|
|
|
|
|
|
|
|
1466
|
|
|
|
|
|
|
=back |
|
1467
|
|
|
|
|
|
|
|
|
1468
|
|
|
|
|
|
|
=cut |
|
1469
|
|
|
|
|
|
|
|
|
1470
|
|
|
|
|
|
|
sub info_metadata { |
|
1471
|
7
|
|
|
7
|
1
|
46
|
my $self = shift(); |
|
1472
|
7
|
|
|
|
|
16
|
my $field = shift(); |
|
1473
|
|
|
|
|
|
|
|
|
1474
|
|
|
|
|
|
|
# Return a hash of the Info table if called without arguments |
|
1475
|
7
|
50
|
|
|
|
19
|
unless (defined $field) { |
|
1476
|
0
|
0
|
|
|
|
0
|
return unless exists $self->{'pdf'}->{'Info'}; |
|
1477
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->{'Info'}->realise(); |
|
1478
|
0
|
|
|
|
|
0
|
my %info; |
|
1479
|
0
|
|
|
|
|
0
|
foreach my $key (keys %{$self->{'pdf'}->{'Info'}}) { |
|
|
0
|
|
|
|
|
0
|
|
|
1480
|
0
|
0
|
|
|
|
0
|
next if $key =~ /^ /; |
|
1481
|
0
|
0
|
|
|
|
0
|
next unless defined $self->{'pdf'}->{'Info'}->{$key}; |
|
1482
|
0
|
|
|
|
|
0
|
$info{$key} = $self->{'pdf'}->{'Info'}->{$key}->val(); |
|
1483
|
|
|
|
|
|
|
} |
|
1484
|
0
|
|
|
|
|
0
|
return %info; |
|
1485
|
|
|
|
|
|
|
} |
|
1486
|
|
|
|
|
|
|
|
|
1487
|
|
|
|
|
|
|
# Set |
|
1488
|
7
|
100
|
|
|
|
20
|
if (@_) { |
|
1489
|
4
|
|
|
|
|
7
|
my $value = shift(); |
|
1490
|
4
|
50
|
66
|
|
|
23
|
$value = undef if defined($value) and not length($value); |
|
1491
|
|
|
|
|
|
|
|
|
1492
|
4
|
100
|
100
|
|
|
19
|
if ($field eq 'CreationDate' or $field eq 'ModDate') { |
|
1493
|
2
|
50
|
|
|
|
9
|
if (defined ($value)) { |
|
1494
|
|
|
|
|
|
|
# make sure date/timestamp starts with D: |
|
1495
|
2
|
50
|
|
|
|
11
|
$value = 'D:' . $value unless $value =~ /^D:/; |
|
1496
|
2
|
50
|
|
|
|
8
|
croak "Invalid date string: $value" unless _is_date($value); |
|
1497
|
|
|
|
|
|
|
} |
|
1498
|
|
|
|
|
|
|
} |
|
1499
|
|
|
|
|
|
|
|
|
1500
|
4
|
50
|
|
|
|
16
|
unless (exists $self->{'pdf'}->{'Info'}) { |
|
1501
|
0
|
0
|
|
|
|
0
|
return $self unless defined $value; |
|
1502
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->{'Info'} = PDFDict(); |
|
1503
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->new_obj($self->{'pdf'}->{'Info'}); |
|
1504
|
|
|
|
|
|
|
} |
|
1505
|
|
|
|
|
|
|
else { |
|
1506
|
4
|
|
|
|
|
21
|
$self->{'pdf'}->{'Info'}->realise(); |
|
1507
|
|
|
|
|
|
|
} |
|
1508
|
|
|
|
|
|
|
|
|
1509
|
4
|
100
|
|
|
|
10
|
if (defined $value) { |
|
1510
|
3
|
|
|
|
|
13
|
$self->{'pdf'}->{'Info'}->{$field} = PDFStr($value); |
|
1511
|
|
|
|
|
|
|
} |
|
1512
|
|
|
|
|
|
|
else { |
|
1513
|
1
|
|
|
|
|
4
|
delete $self->{'pdf'}->{'Info'}->{$field}; |
|
1514
|
|
|
|
|
|
|
} |
|
1515
|
|
|
|
|
|
|
|
|
1516
|
4
|
|
|
|
|
12
|
return $self; |
|
1517
|
|
|
|
|
|
|
} |
|
1518
|
|
|
|
|
|
|
|
|
1519
|
|
|
|
|
|
|
# Get |
|
1520
|
3
|
50
|
|
|
|
10
|
return unless $self->{'pdf'}->{'Info'}; |
|
1521
|
3
|
|
|
|
|
13
|
$self->{'pdf'}->{'Info'}->realise(); |
|
1522
|
3
|
100
|
|
|
|
16
|
return unless $self->{'pdf'}->{'Info'}->{$field}; |
|
1523
|
2
|
|
|
|
|
10
|
return $self->{'pdf'}->{'Info'}->{$field}->val(); |
|
1524
|
|
|
|
|
|
|
} |
|
1525
|
|
|
|
|
|
|
|
|
1526
|
|
|
|
|
|
|
=head3 info |
|
1527
|
|
|
|
|
|
|
|
|
1528
|
|
|
|
|
|
|
%infohash = $pdf->info() |
|
1529
|
|
|
|
|
|
|
|
|
1530
|
|
|
|
|
|
|
%infohash = $pdf->info(%infohash) |
|
1531
|
|
|
|
|
|
|
|
|
1532
|
|
|
|
|
|
|
=over |
|
1533
|
|
|
|
|
|
|
|
|
1534
|
|
|
|
|
|
|
Gets/sets the info structure of the document. |
|
1535
|
|
|
|
|
|
|
|
|
1536
|
|
|
|
|
|
|
See L<PDF::Builder::Docs/info Example> section for an example of the use |
|
1537
|
|
|
|
|
|
|
of this method. |
|
1538
|
|
|
|
|
|
|
|
|
1539
|
|
|
|
|
|
|
B<Note:> this method is still available, for compatibility purposes. It is |
|
1540
|
|
|
|
|
|
|
better to use individual accessors or C<info_metadata> instead. |
|
1541
|
|
|
|
|
|
|
|
|
1542
|
|
|
|
|
|
|
=back |
|
1543
|
|
|
|
|
|
|
|
|
1544
|
|
|
|
|
|
|
=cut |
|
1545
|
|
|
|
|
|
|
|
|
1546
|
|
|
|
|
|
|
sub info { |
|
1547
|
237
|
|
|
237
|
1
|
1095
|
my ($self, %opt) = @_; |
|
1548
|
|
|
|
|
|
|
|
|
1549
|
237
|
100
|
|
|
|
1265
|
if (not defined($self->{'pdf'}->{'Info'})) { |
|
1550
|
234
|
|
|
|
|
856
|
$self->{'pdf'}->{'Info'} = PDFDict(); |
|
1551
|
234
|
|
|
|
|
13491
|
$self->{'pdf'}->new_obj($self->{'pdf'}->{'Info'}); |
|
1552
|
|
|
|
|
|
|
} else { |
|
1553
|
3
|
|
|
|
|
12
|
$self->{'pdf'}->{'Info'}->realise(); |
|
1554
|
|
|
|
|
|
|
} |
|
1555
|
|
|
|
|
|
|
|
|
1556
|
|
|
|
|
|
|
# Maintenance Note: Since we're not shifting at the beginning of |
|
1557
|
|
|
|
|
|
|
# this sub, this "if" will always be true |
|
1558
|
237
|
50
|
|
|
|
885
|
if (scalar @_) { |
|
1559
|
237
|
|
|
|
|
524
|
foreach my $k (@{$self->{'infoMeta'}}) { |
|
|
237
|
|
|
|
|
792
|
|
|
1560
|
1896
|
100
|
|
|
|
4473
|
next unless defined $opt{$k}; |
|
1561
|
235
|
|
50
|
|
|
1320
|
$self->{'pdf'}->{'Info'}->{$k} = PDFString($opt{$k} || 'NONE', 'm'); |
|
1562
|
|
|
|
|
|
|
} |
|
1563
|
237
|
|
|
|
|
1008
|
$self->{'pdf'}->out_obj($self->{'pdf'}->{'Info'}); |
|
1564
|
|
|
|
|
|
|
} |
|
1565
|
|
|
|
|
|
|
|
|
1566
|
237
|
50
|
|
|
|
802
|
if (defined $self->{'pdf'}->{'Info'}) { |
|
1567
|
237
|
|
|
|
|
626
|
%opt = (); |
|
1568
|
237
|
|
|
|
|
438
|
foreach my $k (@{$self->{'infoMeta'}}) { |
|
|
237
|
|
|
|
|
791
|
|
|
1569
|
1896
|
100
|
|
|
|
4732
|
next unless defined $self->{'pdf'}->{'Info'}->{$k}; |
|
1570
|
237
|
|
|
|
|
1085
|
$opt{$k} = $self->{'pdf'}->{'Info'}->{$k}->val(); |
|
1571
|
237
|
50
|
33
|
|
|
2275
|
if ((unpack('n', $opt{$k}) == 0xfffe) or (unpack('n', $opt{$k}) == 0xfeff)) { |
|
1572
|
0
|
|
|
|
|
0
|
$opt{$k} = decode('UTF-16', $self->{'pdf'}->{'Info'}->{$k}->val()); |
|
1573
|
|
|
|
|
|
|
} |
|
1574
|
|
|
|
|
|
|
} |
|
1575
|
|
|
|
|
|
|
} |
|
1576
|
|
|
|
|
|
|
|
|
1577
|
237
|
|
|
|
|
668
|
return %opt; |
|
1578
|
|
|
|
|
|
|
} # end of info() |
|
1579
|
|
|
|
|
|
|
|
|
1580
|
|
|
|
|
|
|
=head3 infoMetaAttributes |
|
1581
|
|
|
|
|
|
|
|
|
1582
|
|
|
|
|
|
|
@metadata_attributes = $pdf->infoMetaAttributes() |
|
1583
|
|
|
|
|
|
|
|
|
1584
|
|
|
|
|
|
|
@metadata_attributes = $pdf->infoMetaAttributes(@metadata_attributes) |
|
1585
|
|
|
|
|
|
|
|
|
1586
|
|
|
|
|
|
|
=over |
|
1587
|
|
|
|
|
|
|
|
|
1588
|
|
|
|
|
|
|
Gets/sets the supported info-structure tags. |
|
1589
|
|
|
|
|
|
|
|
|
1590
|
|
|
|
|
|
|
B<Example:> |
|
1591
|
|
|
|
|
|
|
|
|
1592
|
|
|
|
|
|
|
=back |
|
1593
|
|
|
|
|
|
|
|
|
1594
|
|
|
|
|
|
|
@attributes = $pdf->infoMetaAttributes; |
|
1595
|
|
|
|
|
|
|
print "Supported Attributes: @attr\n"; |
|
1596
|
|
|
|
|
|
|
|
|
1597
|
|
|
|
|
|
|
@attributes = $pdf->infoMetaAttributes('CustomField1'); |
|
1598
|
|
|
|
|
|
|
print "Supported Attributes: @attributes\n"; |
|
1599
|
|
|
|
|
|
|
|
|
1600
|
|
|
|
|
|
|
=over |
|
1601
|
|
|
|
|
|
|
|
|
1602
|
|
|
|
|
|
|
B<Note:> this method is still available for compatibility purposes, but the |
|
1603
|
|
|
|
|
|
|
use of C<info_metadata> instead is encouraged. |
|
1604
|
|
|
|
|
|
|
|
|
1605
|
|
|
|
|
|
|
=back |
|
1606
|
|
|
|
|
|
|
|
|
1607
|
|
|
|
|
|
|
=cut |
|
1608
|
|
|
|
|
|
|
|
|
1609
|
|
|
|
|
|
|
sub infoMetaAttributes { |
|
1610
|
0
|
|
|
0
|
1
|
0
|
my ($self, @attr) = @_; |
|
1611
|
|
|
|
|
|
|
|
|
1612
|
0
|
0
|
|
|
|
0
|
if (scalar @attr) { |
|
1613
|
0
|
|
|
|
|
0
|
my %at = map { $_ => 1 } @{$self->{'infoMeta'}}, @attr; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1614
|
0
|
|
|
|
|
0
|
@{$self->{'infoMeta'}} = keys %at; |
|
|
0
|
|
|
|
|
0
|
|
|
1615
|
|
|
|
|
|
|
} |
|
1616
|
|
|
|
|
|
|
|
|
1617
|
0
|
|
|
|
|
0
|
return @{$self->{'infoMeta'}}; |
|
|
0
|
|
|
|
|
0
|
|
|
1618
|
|
|
|
|
|
|
} |
|
1619
|
|
|
|
|
|
|
|
|
1620
|
|
|
|
|
|
|
=head3 xml_metadata |
|
1621
|
|
|
|
|
|
|
|
|
1622
|
|
|
|
|
|
|
$xml = $pdf->xml_metadata(); |
|
1623
|
|
|
|
|
|
|
|
|
1624
|
|
|
|
|
|
|
$pdf = $pdf->xml_metadata($xml); |
|
1625
|
|
|
|
|
|
|
|
|
1626
|
|
|
|
|
|
|
=over |
|
1627
|
|
|
|
|
|
|
|
|
1628
|
|
|
|
|
|
|
Gets/sets the document's XML metadata stream. |
|
1629
|
|
|
|
|
|
|
|
|
1630
|
|
|
|
|
|
|
=back |
|
1631
|
|
|
|
|
|
|
|
|
1632
|
|
|
|
|
|
|
=cut |
|
1633
|
|
|
|
|
|
|
|
|
1634
|
|
|
|
|
|
|
sub xml_metadata { |
|
1635
|
0
|
|
|
0
|
1
|
0
|
my ($self, $value) = @_; |
|
1636
|
|
|
|
|
|
|
|
|
1637
|
0
|
0
|
|
|
|
0
|
if (not defined($self->{'catalog'}->{'Metadata'})) { |
|
1638
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'Metadata'} = PDFDict(); |
|
1639
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'Metadata'}->{'Type'} = PDFName('Metadata'); |
|
1640
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'Metadata'}->{'Subtype'} = PDFName('XML'); |
|
1641
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->new_obj($self->{'catalog'}->{'Metadata'}); |
|
1642
|
|
|
|
|
|
|
} |
|
1643
|
|
|
|
|
|
|
else { |
|
1644
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'Metadata'}->realise(); |
|
1645
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'Metadata'}->{' stream'} = unfilter($self->{'catalog'}->{'Metadata'}->{'Filter'}, $self->{'catalog'}->{'Metadata'}->{' stream'}); |
|
1646
|
0
|
|
|
|
|
0
|
delete $self->{'catalog'}->{'Metadata'}->{' nofilt'}; |
|
1647
|
0
|
|
|
|
|
0
|
delete $self->{'catalog'}->{'Metadata'}->{'Filter'}; |
|
1648
|
|
|
|
|
|
|
} |
|
1649
|
|
|
|
|
|
|
|
|
1650
|
0
|
|
|
|
|
0
|
my $md = $self->{'catalog'}->{'Metadata'}; |
|
1651
|
|
|
|
|
|
|
|
|
1652
|
0
|
0
|
|
|
|
0
|
if (defined $value) { |
|
1653
|
0
|
|
|
|
|
0
|
$md->{' stream'} = $value; |
|
1654
|
0
|
|
|
|
|
0
|
delete $md->{'Filter'}; |
|
1655
|
0
|
|
|
|
|
0
|
delete $md->{' nofilt'}; |
|
1656
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->out_obj($md); |
|
1657
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->out_obj($self->{'catalog'}); |
|
1658
|
|
|
|
|
|
|
} |
|
1659
|
|
|
|
|
|
|
|
|
1660
|
0
|
|
|
|
|
0
|
return $md->{' stream'}; |
|
1661
|
|
|
|
|
|
|
} |
|
1662
|
|
|
|
|
|
|
|
|
1663
|
|
|
|
|
|
|
=head3 xmpMetadata |
|
1664
|
|
|
|
|
|
|
|
|
1665
|
|
|
|
|
|
|
$xml = $pdf->xmpMetadata() # Get |
|
1666
|
|
|
|
|
|
|
|
|
1667
|
|
|
|
|
|
|
$xml = $pdf->xmpMetadata($xml) # Set (also returns $xml value) |
|
1668
|
|
|
|
|
|
|
|
|
1669
|
|
|
|
|
|
|
=over |
|
1670
|
|
|
|
|
|
|
|
|
1671
|
|
|
|
|
|
|
Gets/sets the XMP XML data stream. |
|
1672
|
|
|
|
|
|
|
|
|
1673
|
|
|
|
|
|
|
See L<PDF::Builder::Docs/XMP XML example> section for an example of the use |
|
1674
|
|
|
|
|
|
|
of this method. |
|
1675
|
|
|
|
|
|
|
|
|
1676
|
|
|
|
|
|
|
This method is considered B<obsolete>. Use C<xml_metadata> instead. |
|
1677
|
|
|
|
|
|
|
|
|
1678
|
|
|
|
|
|
|
=back |
|
1679
|
|
|
|
|
|
|
|
|
1680
|
|
|
|
|
|
|
=cut |
|
1681
|
|
|
|
|
|
|
|
|
1682
|
|
|
|
|
|
|
sub xmpMetadata { |
|
1683
|
0
|
|
|
0
|
1
|
0
|
my ($self, $value) = @_; |
|
1684
|
|
|
|
|
|
|
|
|
1685
|
0
|
0
|
|
|
|
0
|
if (@_) { # Set |
|
1686
|
0
|
|
|
|
|
0
|
my $value = shift(); |
|
1687
|
0
|
|
|
|
|
0
|
$self->xml_metadata($value); |
|
1688
|
0
|
|
|
|
|
0
|
return $value; |
|
1689
|
|
|
|
|
|
|
} |
|
1690
|
|
|
|
|
|
|
|
|
1691
|
|
|
|
|
|
|
# Get |
|
1692
|
0
|
|
|
|
|
0
|
return $self->xml_metadata(); |
|
1693
|
|
|
|
|
|
|
} |
|
1694
|
|
|
|
|
|
|
|
|
1695
|
|
|
|
|
|
|
=head3 default |
|
1696
|
|
|
|
|
|
|
|
|
1697
|
|
|
|
|
|
|
$val = $pdf->default($parameter) |
|
1698
|
|
|
|
|
|
|
|
|
1699
|
|
|
|
|
|
|
$pdf->default($parameter, $value) |
|
1700
|
|
|
|
|
|
|
|
|
1701
|
|
|
|
|
|
|
=over |
|
1702
|
|
|
|
|
|
|
|
|
1703
|
|
|
|
|
|
|
Gets/sets the default value for a behavior of PDF::Builder. |
|
1704
|
|
|
|
|
|
|
|
|
1705
|
|
|
|
|
|
|
B<Supported Parameters:> |
|
1706
|
|
|
|
|
|
|
|
|
1707
|
|
|
|
|
|
|
=back |
|
1708
|
|
|
|
|
|
|
|
|
1709
|
|
|
|
|
|
|
=over |
|
1710
|
|
|
|
|
|
|
|
|
1711
|
|
|
|
|
|
|
=item nounrotate |
|
1712
|
|
|
|
|
|
|
|
|
1713
|
|
|
|
|
|
|
prohibits Builder from rotating imported/opened page to re-create a |
|
1714
|
|
|
|
|
|
|
default pdf-context. |
|
1715
|
|
|
|
|
|
|
|
|
1716
|
|
|
|
|
|
|
=item pageencaps |
|
1717
|
|
|
|
|
|
|
|
|
1718
|
|
|
|
|
|
|
enables Builder's adding save/restore commands upon importing/opening |
|
1719
|
|
|
|
|
|
|
pages to preserve graphics-state for modification. |
|
1720
|
|
|
|
|
|
|
|
|
1721
|
|
|
|
|
|
|
=item copyannots |
|
1722
|
|
|
|
|
|
|
|
|
1723
|
|
|
|
|
|
|
enables importing of annotations (B<*EXPERIMENTAL*>). |
|
1724
|
|
|
|
|
|
|
|
|
1725
|
|
|
|
|
|
|
=back |
|
1726
|
|
|
|
|
|
|
|
|
1727
|
|
|
|
|
|
|
=over |
|
1728
|
|
|
|
|
|
|
|
|
1729
|
|
|
|
|
|
|
B<CAUTION:> Perl::Critic (tools/1_pc.pl) has started flagging the name |
|
1730
|
|
|
|
|
|
|
"default" as a reserved keyword in higher Perl versions. Use with caution, and |
|
1731
|
|
|
|
|
|
|
be aware that this name I<may> have to be changed in the future. |
|
1732
|
|
|
|
|
|
|
|
|
1733
|
|
|
|
|
|
|
=back |
|
1734
|
|
|
|
|
|
|
|
|
1735
|
|
|
|
|
|
|
=cut |
|
1736
|
|
|
|
|
|
|
|
|
1737
|
|
|
|
|
|
|
sub default { |
|
1738
|
8
|
|
|
8
|
1
|
26
|
my ($self, $parameter, $value) = @_; |
|
1739
|
|
|
|
|
|
|
|
|
1740
|
|
|
|
|
|
|
# Parameter names may consist of lowercase letters, numbers, and underscores |
|
1741
|
8
|
|
|
|
|
18
|
$parameter = lc $parameter; |
|
1742
|
8
|
|
|
|
|
32
|
$parameter =~ s/[^a-z\d_]//g; |
|
1743
|
|
|
|
|
|
|
|
|
1744
|
8
|
|
|
|
|
18
|
my $previous_value = $self->{$parameter}; |
|
1745
|
8
|
50
|
|
|
|
30
|
if (defined $value) { |
|
1746
|
0
|
|
|
|
|
0
|
$self->{$parameter} = $value; |
|
1747
|
|
|
|
|
|
|
} |
|
1748
|
|
|
|
|
|
|
|
|
1749
|
8
|
|
|
|
|
62
|
return $previous_value; |
|
1750
|
|
|
|
|
|
|
} |
|
1751
|
|
|
|
|
|
|
|
|
1752
|
|
|
|
|
|
|
=head3 version |
|
1753
|
|
|
|
|
|
|
|
|
1754
|
|
|
|
|
|
|
$version = $pdf->pdf_version() # Get |
|
1755
|
|
|
|
|
|
|
|
|
1756
|
|
|
|
|
|
|
$version = $pdf->pdf_version($version) # Set (also returns newly set version) |
|
1757
|
|
|
|
|
|
|
|
|
1758
|
|
|
|
|
|
|
=over |
|
1759
|
|
|
|
|
|
|
|
|
1760
|
|
|
|
|
|
|
Gets/sets the PDF version (e.g., 1.5). |
|
1761
|
|
|
|
|
|
|
For compatibility with earlier releases, if no decimal point is given, assume |
|
1762
|
|
|
|
|
|
|
"1." precedes the number given. |
|
1763
|
|
|
|
|
|
|
|
|
1764
|
|
|
|
|
|
|
A warning message is given if you attempt to I<decrease> the PDF version, as you |
|
1765
|
|
|
|
|
|
|
might have already read in a higher level file, or used a higher level feature. |
|
1766
|
|
|
|
|
|
|
|
|
1767
|
|
|
|
|
|
|
See L<PDF::Builder::Basic::PDF::File> for additional information on the |
|
1768
|
|
|
|
|
|
|
C<version> method. |
|
1769
|
|
|
|
|
|
|
|
|
1770
|
|
|
|
|
|
|
=back |
|
1771
|
|
|
|
|
|
|
|
|
1772
|
|
|
|
|
|
|
=cut |
|
1773
|
|
|
|
|
|
|
|
|
1774
|
|
|
|
|
|
|
sub pdf_version { |
|
1775
|
27
|
|
|
27
|
0
|
93
|
my $self = shift(); # includes any %opts |
|
1776
|
|
|
|
|
|
|
|
|
1777
|
27
|
50
|
|
|
|
129
|
if (!defined $self->{'pdf'}) { |
|
1778
|
0
|
|
|
|
|
0
|
carp "'pdf' element not defined in pdf_version() call"; |
|
1779
|
0
|
|
|
|
|
0
|
return '1.4'; |
|
1780
|
|
|
|
|
|
|
} |
|
1781
|
27
|
|
|
|
|
192
|
return $self->{'pdf'}->pdf_version(@_); # just pass it over to the "real" one |
|
1782
|
|
|
|
|
|
|
} |
|
1783
|
|
|
|
|
|
|
|
|
1784
|
|
|
|
|
|
|
# when outputting a PDF feature, verCheckOutput(n, 'feature name') returns TRUE |
|
1785
|
|
|
|
|
|
|
# if n > $pdf->{' version'), plus a warning message. It returns FALSE otherwise. |
|
1786
|
|
|
|
|
|
|
# |
|
1787
|
|
|
|
|
|
|
# a typical use: |
|
1788
|
|
|
|
|
|
|
# |
|
1789
|
|
|
|
|
|
|
# $PDF::Builder::global_pdf->verCheckOutput(1.6, "portzebie with foo-dangle"); |
|
1790
|
|
|
|
|
|
|
# |
|
1791
|
|
|
|
|
|
|
# if msgver defaults to 1, a message will be output if the output PDF version |
|
1792
|
|
|
|
|
|
|
# has to be increased to 1.6 in order to use the "portzebie" feature |
|
1793
|
|
|
|
|
|
|
# |
|
1794
|
|
|
|
|
|
|
# this is still somewhat experimental, and as experience is gained, the code |
|
1795
|
|
|
|
|
|
|
# might have to be modified. |
|
1796
|
|
|
|
|
|
|
# |
|
1797
|
|
|
|
|
|
|
sub verCheckOutput { |
|
1798
|
3
|
|
|
3
|
0
|
11
|
my ($self, $PDFver, $featureName) = @_; |
|
1799
|
|
|
|
|
|
|
|
|
1800
|
|
|
|
|
|
|
# check if feature required PDF version is higher than planned output |
|
1801
|
3
|
|
|
|
|
22
|
my $version = $self->pdf_version(); # current version |
|
1802
|
3
|
100
|
|
|
|
11
|
if ($PDFver > $version) { |
|
1803
|
1
|
50
|
|
|
|
4
|
if ($msgVer) { |
|
1804
|
0
|
|
|
|
|
0
|
print "PDF version of requested feature '$featureName' is higher\n". " than current output version $version ". |
|
1805
|
|
|
|
|
|
|
"(version reset to $PDFver)\n"; |
|
1806
|
|
|
|
|
|
|
} |
|
1807
|
1
|
|
|
|
|
4
|
$self->pdf_version($PDFver); |
|
1808
|
1
|
|
|
|
|
3
|
return 1; |
|
1809
|
|
|
|
|
|
|
} else { |
|
1810
|
2
|
|
|
|
|
7
|
return 0; |
|
1811
|
|
|
|
|
|
|
} |
|
1812
|
|
|
|
|
|
|
} |
|
1813
|
|
|
|
|
|
|
|
|
1814
|
|
|
|
|
|
|
# when reading in a PDF, verCheckInput(n) gives a warning message if n (the PDF |
|
1815
|
|
|
|
|
|
|
# version just read in) > version, and resets version to n. return TRUE if |
|
1816
|
|
|
|
|
|
|
# version changed, FALSE otherwise. |
|
1817
|
|
|
|
|
|
|
# |
|
1818
|
|
|
|
|
|
|
# this is still somewhat experimental, and as experience is gained, the code |
|
1819
|
|
|
|
|
|
|
# might have to be modified. |
|
1820
|
|
|
|
|
|
|
# |
|
1821
|
|
|
|
|
|
|
# WARNING: just because the PDF output version has been increased does NOT |
|
1822
|
|
|
|
|
|
|
# guarantee that any particular content will be handled correctly! There are |
|
1823
|
|
|
|
|
|
|
# many known cases of PDF 1.5 and up files being read in, that have content |
|
1824
|
|
|
|
|
|
|
# that PDF::Builder does not handle correctly, corrupting the resulting PDF. |
|
1825
|
|
|
|
|
|
|
# Pay attention to run-time warning messages that the PDF output level has |
|
1826
|
|
|
|
|
|
|
# been increased due to a PDF file being read in, and check the resulting |
|
1827
|
|
|
|
|
|
|
# file carefully. |
|
1828
|
|
|
|
|
|
|
|
|
1829
|
|
|
|
|
|
|
sub verCheckInput { |
|
1830
|
18
|
|
|
18
|
0
|
59
|
my ($self, $PDFver) = @_; |
|
1831
|
|
|
|
|
|
|
|
|
1832
|
18
|
|
|
|
|
126
|
my $version = $self->pdf_version(); |
|
1833
|
|
|
|
|
|
|
# warning message and bump up version if read-in PDF level higher |
|
1834
|
18
|
50
|
|
|
|
79
|
if ($PDFver > $version) { |
|
1835
|
0
|
0
|
|
|
|
0
|
if ($msgVer) { |
|
1836
|
0
|
|
|
|
|
0
|
print "PDF version just read in is higher than version of $version (version reset to $PDFver)\n"; |
|
1837
|
|
|
|
|
|
|
} |
|
1838
|
0
|
|
|
|
|
0
|
$self->pdf_version($PDFver); |
|
1839
|
0
|
|
|
|
|
0
|
return 1; |
|
1840
|
|
|
|
|
|
|
} else { |
|
1841
|
18
|
|
|
|
|
43
|
return 0; |
|
1842
|
|
|
|
|
|
|
} |
|
1843
|
|
|
|
|
|
|
} |
|
1844
|
|
|
|
|
|
|
|
|
1845
|
|
|
|
|
|
|
=head3 is_encrypted, isEncrypted |
|
1846
|
|
|
|
|
|
|
|
|
1847
|
|
|
|
|
|
|
$bool = $pdf->is_encrypted() |
|
1848
|
|
|
|
|
|
|
|
|
1849
|
|
|
|
|
|
|
=over |
|
1850
|
|
|
|
|
|
|
|
|
1851
|
|
|
|
|
|
|
Checks if the previously opened PDF is encrypted. |
|
1852
|
|
|
|
|
|
|
|
|
1853
|
|
|
|
|
|
|
B<Alternate name:> C<isEncrypted> |
|
1854
|
|
|
|
|
|
|
|
|
1855
|
|
|
|
|
|
|
This is the older name; it is kept for compatibility with PDF::API2. |
|
1856
|
|
|
|
|
|
|
|
|
1857
|
|
|
|
|
|
|
=back |
|
1858
|
|
|
|
|
|
|
|
|
1859
|
|
|
|
|
|
|
=cut |
|
1860
|
|
|
|
|
|
|
|
|
1861
|
0
|
|
|
0
|
1
|
0
|
sub isEncrypted { return is_encrypted(@_); } ## no critic |
|
1862
|
|
|
|
|
|
|
|
|
1863
|
|
|
|
|
|
|
sub is_encrypted { |
|
1864
|
0
|
|
|
0
|
1
|
0
|
my $self = shift(); |
|
1865
|
0
|
0
|
|
|
|
0
|
return defined($self->{'pdf'}->{'Encrypt'}) ? 1 : 0; |
|
1866
|
|
|
|
|
|
|
} |
|
1867
|
|
|
|
|
|
|
|
|
1868
|
|
|
|
|
|
|
=head1 INTERACTIVE FEATURE METHODS |
|
1869
|
|
|
|
|
|
|
|
|
1870
|
|
|
|
|
|
|
=head2 outline, outlines |
|
1871
|
|
|
|
|
|
|
|
|
1872
|
|
|
|
|
|
|
$otls = $pdf->outline() |
|
1873
|
|
|
|
|
|
|
|
|
1874
|
|
|
|
|
|
|
=over |
|
1875
|
|
|
|
|
|
|
|
|
1876
|
|
|
|
|
|
|
Creates (if needed) and returns the document's 'outline' tree, which is also |
|
1877
|
|
|
|
|
|
|
known as its 'bookmarks' or the 'table of contents', depending on the |
|
1878
|
|
|
|
|
|
|
PDF reader being used. |
|
1879
|
|
|
|
|
|
|
|
|
1880
|
|
|
|
|
|
|
To examine or modify the outline tree, see L<PDF::Builder::Outlines>. |
|
1881
|
|
|
|
|
|
|
|
|
1882
|
|
|
|
|
|
|
B<Alternate name:> C<outlines> |
|
1883
|
|
|
|
|
|
|
|
|
1884
|
|
|
|
|
|
|
This is the older name; it is kept for compatibility. |
|
1885
|
|
|
|
|
|
|
|
|
1886
|
|
|
|
|
|
|
=back |
|
1887
|
|
|
|
|
|
|
|
|
1888
|
|
|
|
|
|
|
=cut |
|
1889
|
|
|
|
|
|
|
|
|
1890
|
4
|
|
|
4
|
1
|
32
|
sub outlines { return outline(@_); } ## no critic |
|
1891
|
|
|
|
|
|
|
|
|
1892
|
|
|
|
|
|
|
sub outline { |
|
1893
|
4
|
|
|
4
|
1
|
7
|
my $self = shift(); |
|
1894
|
|
|
|
|
|
|
|
|
1895
|
4
|
|
|
|
|
802
|
require PDF::Builder::Outlines; |
|
1896
|
4
|
|
|
|
|
15
|
my $obj = $self->{'pdf'}->{'Root'}->{'Outlines'}; |
|
1897
|
4
|
100
|
|
|
|
9
|
if ($obj) { |
|
1898
|
1
|
|
|
|
|
3
|
$obj->realise(); |
|
1899
|
1
|
|
|
|
|
5
|
bless $obj, 'PDF::Builder::Outlines'; |
|
1900
|
1
|
|
|
|
|
2
|
$obj->{' api'} = $self; |
|
1901
|
1
|
|
|
|
|
2
|
weaken $obj->{' api'}; |
|
1902
|
|
|
|
|
|
|
} else { |
|
1903
|
3
|
|
|
|
|
20
|
$obj = PDF::Builder::Outlines->new($self); |
|
1904
|
|
|
|
|
|
|
|
|
1905
|
3
|
|
|
|
|
10
|
$self->{'pdf'}->{'Root'}->{'Outlines'} = $obj; |
|
1906
|
3
|
50
|
|
|
|
13
|
$self->{'pdf'}->new_obj($obj) unless $obj->is_obj($self->{'pdf'}); |
|
1907
|
3
|
|
|
|
|
11
|
$self->{'pdf'}->out_obj($obj); |
|
1908
|
3
|
|
|
|
|
8
|
$self->{'pdf'}->out_obj($self->{'pdf'}->{'Root'}); |
|
1909
|
|
|
|
|
|
|
} |
|
1910
|
4
|
|
|
|
|
22
|
return $obj; |
|
1911
|
|
|
|
|
|
|
} |
|
1912
|
|
|
|
|
|
|
|
|
1913
|
|
|
|
|
|
|
#=item $pdf = $pdf->open_action($page, $location, @args); |
|
1914
|
|
|
|
|
|
|
# |
|
1915
|
|
|
|
|
|
|
#Set the destination in the PDF that should be displayed when the document is |
|
1916
|
|
|
|
|
|
|
#opened. |
|
1917
|
|
|
|
|
|
|
# |
|
1918
|
|
|
|
|
|
|
#C<$page> may be either a page number or a page object. The other parameters are |
|
1919
|
|
|
|
|
|
|
#as described in L<PDF::Builder::NamedDestination>. |
|
1920
|
|
|
|
|
|
|
# |
|
1921
|
|
|
|
|
|
|
#This has been split out from C<preferences()> for compatibility with PDF::API2. |
|
1922
|
|
|
|
|
|
|
#It also can both set (assign) and get (query) the settings used. |
|
1923
|
|
|
|
|
|
|
# |
|
1924
|
|
|
|
|
|
|
#=cut |
|
1925
|
|
|
|
|
|
|
# |
|
1926
|
|
|
|
|
|
|
#sub open_action { |
|
1927
|
|
|
|
|
|
|
# my ($self, $page, @args) = @_; |
|
1928
|
|
|
|
|
|
|
# |
|
1929
|
|
|
|
|
|
|
# # $page can be either a page number or a page object |
|
1930
|
|
|
|
|
|
|
# $page = PDFNum($page) unless ref($page); |
|
1931
|
|
|
|
|
|
|
# |
|
1932
|
|
|
|
|
|
|
# require PDF::Builder::NamedDestination; |
|
1933
|
|
|
|
|
|
|
# # PDF::API2 code incompatible with Builder! |
|
1934
|
|
|
|
|
|
|
# #my $array = PDF::Builder::NamedDestination::_destination($page, @args); |
|
1935
|
|
|
|
|
|
|
# |
|
1936
|
|
|
|
|
|
|
# $self->{'catalog'}->{'OpenAction'} = $array; |
|
1937
|
|
|
|
|
|
|
# $self->{'pdf'}->out_obj($self->{'catalog'}); |
|
1938
|
|
|
|
|
|
|
# return $self; |
|
1939
|
|
|
|
|
|
|
#} |
|
1940
|
|
|
|
|
|
|
|
|
1941
|
|
|
|
|
|
|
=head2 page_layout |
|
1942
|
|
|
|
|
|
|
|
|
1943
|
|
|
|
|
|
|
$layout = $pdf->page_layout(); |
|
1944
|
|
|
|
|
|
|
|
|
1945
|
|
|
|
|
|
|
$pdf = $pdf->page_layout($layout); |
|
1946
|
|
|
|
|
|
|
|
|
1947
|
|
|
|
|
|
|
=over |
|
1948
|
|
|
|
|
|
|
|
|
1949
|
|
|
|
|
|
|
Gets/sets the page layout that should be used when the PDF is opened. |
|
1950
|
|
|
|
|
|
|
|
|
1951
|
|
|
|
|
|
|
C<$layout> is one of the following: |
|
1952
|
|
|
|
|
|
|
|
|
1953
|
|
|
|
|
|
|
=back |
|
1954
|
|
|
|
|
|
|
|
|
1955
|
|
|
|
|
|
|
=over |
|
1956
|
|
|
|
|
|
|
|
|
1957
|
|
|
|
|
|
|
=item single_page (or undef) |
|
1958
|
|
|
|
|
|
|
|
|
1959
|
|
|
|
|
|
|
Display one page at a time. |
|
1960
|
|
|
|
|
|
|
|
|
1961
|
|
|
|
|
|
|
=item one_column |
|
1962
|
|
|
|
|
|
|
|
|
1963
|
|
|
|
|
|
|
Display the pages in one column (a.k.a. continuous). |
|
1964
|
|
|
|
|
|
|
|
|
1965
|
|
|
|
|
|
|
=item two_column_left |
|
1966
|
|
|
|
|
|
|
|
|
1967
|
|
|
|
|
|
|
Display the pages in two columns, with odd-numbered pages on the left. |
|
1968
|
|
|
|
|
|
|
|
|
1969
|
|
|
|
|
|
|
=item two_column_right |
|
1970
|
|
|
|
|
|
|
|
|
1971
|
|
|
|
|
|
|
Display the pages in two columns, with odd-numbered pages on the right. |
|
1972
|
|
|
|
|
|
|
|
|
1973
|
|
|
|
|
|
|
=item two_page_left |
|
1974
|
|
|
|
|
|
|
|
|
1975
|
|
|
|
|
|
|
Display two pages at a time, with odd-numbered pages on the left. |
|
1976
|
|
|
|
|
|
|
|
|
1977
|
|
|
|
|
|
|
=item two_page_right |
|
1978
|
|
|
|
|
|
|
|
|
1979
|
|
|
|
|
|
|
Display two pages at a time, with odd-numbered pages on the right. |
|
1980
|
|
|
|
|
|
|
|
|
1981
|
|
|
|
|
|
|
=back |
|
1982
|
|
|
|
|
|
|
|
|
1983
|
|
|
|
|
|
|
=over |
|
1984
|
|
|
|
|
|
|
|
|
1985
|
|
|
|
|
|
|
This has been split out from C<preferences()> for compatibility with PDF::API2. |
|
1986
|
|
|
|
|
|
|
It also can both set (assign) and get (query) the settings used. |
|
1987
|
|
|
|
|
|
|
|
|
1988
|
|
|
|
|
|
|
=back |
|
1989
|
|
|
|
|
|
|
|
|
1990
|
|
|
|
|
|
|
=cut |
|
1991
|
|
|
|
|
|
|
|
|
1992
|
|
|
|
|
|
|
sub page_layout { |
|
1993
|
0
|
|
|
0
|
1
|
0
|
my $self = shift(); |
|
1994
|
|
|
|
|
|
|
|
|
1995
|
0
|
0
|
|
|
|
0
|
unless (@_) { |
|
1996
|
0
|
0
|
|
|
|
0
|
return 'single_page' unless $self->{'catalog'}->{'PageLayout'}; |
|
1997
|
0
|
|
|
|
|
0
|
my $layout = $self->{'catalog'}->{'PageLayout'}->val(); |
|
1998
|
0
|
0
|
|
|
|
0
|
return 'single_page' if $layout eq 'SinglePage'; |
|
1999
|
0
|
0
|
|
|
|
0
|
return 'one_column' if $layout eq 'OneColumn'; |
|
2000
|
0
|
0
|
|
|
|
0
|
return 'two_column_left' if $layout eq 'TwoColumnLeft'; |
|
2001
|
0
|
0
|
|
|
|
0
|
return 'two_column_right' if $layout eq 'TwoColumnRight'; |
|
2002
|
0
|
0
|
|
|
|
0
|
return 'two_page_left' if $layout eq 'TwoPageLeft'; |
|
2003
|
0
|
0
|
|
|
|
0
|
return 'two_page_right' if $layout eq 'TwoPageRight'; |
|
2004
|
0
|
|
|
|
|
0
|
warn "Unknown page layout: $layout"; |
|
2005
|
0
|
|
|
|
|
0
|
return $layout; |
|
2006
|
|
|
|
|
|
|
} |
|
2007
|
|
|
|
|
|
|
|
|
2008
|
0
|
|
0
|
|
|
0
|
my $name = shift() // 'single_page'; |
|
2009
|
0
|
0
|
|
|
|
0
|
my $layout = ($name eq 'single_page' ? 'SinglePage' : |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
2010
|
|
|
|
|
|
|
$name eq 'one_column' ? 'OneColumn' : |
|
2011
|
|
|
|
|
|
|
$name eq 'two_column_left' ? 'TwoColumnLeft' : |
|
2012
|
|
|
|
|
|
|
$name eq 'two_column_right' ? 'TwoColumnRight' : |
|
2013
|
|
|
|
|
|
|
$name eq 'two_page_left' ? 'TwoPageLeft' : |
|
2014
|
|
|
|
|
|
|
$name eq 'two_page_right' ? 'TwoPageRight' : ''); |
|
2015
|
|
|
|
|
|
|
|
|
2016
|
0
|
0
|
|
|
|
0
|
croak "Invalid page layout: $name" unless $layout; |
|
2017
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'PageLayout'} = PDFName($layout); |
|
2018
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->out_obj($self->{'catalog'}); |
|
2019
|
0
|
|
|
|
|
0
|
return $self; |
|
2020
|
|
|
|
|
|
|
} |
|
2021
|
|
|
|
|
|
|
|
|
2022
|
|
|
|
|
|
|
=head2 page_mode |
|
2023
|
|
|
|
|
|
|
|
|
2024
|
|
|
|
|
|
|
$mode = $pdf->page_mode(); # Get |
|
2025
|
|
|
|
|
|
|
|
|
2026
|
|
|
|
|
|
|
$pdf = $pdf->page_mode($mode); # Set |
|
2027
|
|
|
|
|
|
|
|
|
2028
|
|
|
|
|
|
|
=over |
|
2029
|
|
|
|
|
|
|
|
|
2030
|
|
|
|
|
|
|
Gets/sets the page mode, which describes how the PDF should be displayed when |
|
2031
|
|
|
|
|
|
|
opened. |
|
2032
|
|
|
|
|
|
|
|
|
2033
|
|
|
|
|
|
|
C<$mode> is one of the following: |
|
2034
|
|
|
|
|
|
|
|
|
2035
|
|
|
|
|
|
|
=back |
|
2036
|
|
|
|
|
|
|
|
|
2037
|
|
|
|
|
|
|
=over |
|
2038
|
|
|
|
|
|
|
|
|
2039
|
|
|
|
|
|
|
=item none (or undef) |
|
2040
|
|
|
|
|
|
|
|
|
2041
|
|
|
|
|
|
|
Neither outlines nor thumbnails should be displayed. |
|
2042
|
|
|
|
|
|
|
|
|
2043
|
|
|
|
|
|
|
=item outlines |
|
2044
|
|
|
|
|
|
|
|
|
2045
|
|
|
|
|
|
|
Show the document outline. |
|
2046
|
|
|
|
|
|
|
|
|
2047
|
|
|
|
|
|
|
=item thumbnails |
|
2048
|
|
|
|
|
|
|
|
|
2049
|
|
|
|
|
|
|
Show the page thumbnails. |
|
2050
|
|
|
|
|
|
|
|
|
2051
|
|
|
|
|
|
|
=item full_screen |
|
2052
|
|
|
|
|
|
|
|
|
2053
|
|
|
|
|
|
|
Open in full-screen mode, with no menu bar, window controls, or any other window |
|
2054
|
|
|
|
|
|
|
visible. |
|
2055
|
|
|
|
|
|
|
|
|
2056
|
|
|
|
|
|
|
=item optional_content |
|
2057
|
|
|
|
|
|
|
|
|
2058
|
|
|
|
|
|
|
Show the optional content group panel. |
|
2059
|
|
|
|
|
|
|
|
|
2060
|
|
|
|
|
|
|
=item attachments |
|
2061
|
|
|
|
|
|
|
|
|
2062
|
|
|
|
|
|
|
Show the attachments panel. |
|
2063
|
|
|
|
|
|
|
|
|
2064
|
|
|
|
|
|
|
=back |
|
2065
|
|
|
|
|
|
|
|
|
2066
|
|
|
|
|
|
|
=over |
|
2067
|
|
|
|
|
|
|
|
|
2068
|
|
|
|
|
|
|
This has been split out from C<preferences()> for compatibility with PDF::API2. |
|
2069
|
|
|
|
|
|
|
It also can both set (assign) and get (query) the settings used. |
|
2070
|
|
|
|
|
|
|
|
|
2071
|
|
|
|
|
|
|
=back |
|
2072
|
|
|
|
|
|
|
|
|
2073
|
|
|
|
|
|
|
=cut |
|
2074
|
|
|
|
|
|
|
|
|
2075
|
|
|
|
|
|
|
sub page_mode { |
|
2076
|
0
|
|
|
0
|
1
|
0
|
my $self = shift(); |
|
2077
|
|
|
|
|
|
|
|
|
2078
|
0
|
0
|
|
|
|
0
|
unless (@_) { |
|
2079
|
0
|
0
|
|
|
|
0
|
return 'none' unless $self->{'catalog'}->{'PageMode'}; |
|
2080
|
0
|
|
|
|
|
0
|
my $mode = $self->{'catalog'}->{'PageMode'}->val(); |
|
2081
|
0
|
0
|
|
|
|
0
|
return 'none' if $mode eq 'UseNone'; |
|
2082
|
0
|
0
|
|
|
|
0
|
return 'outlines' if $mode eq 'UseOutlines'; |
|
2083
|
0
|
0
|
|
|
|
0
|
return 'thumbnails' if $mode eq 'UseThumbs'; |
|
2084
|
0
|
0
|
|
|
|
0
|
return 'full_screen' if $mode eq 'FullScreen'; |
|
2085
|
0
|
0
|
|
|
|
0
|
return 'optional_content' if $mode eq 'UseOC'; |
|
2086
|
0
|
0
|
|
|
|
0
|
return 'attachments' if $mode eq 'UseAttachments'; |
|
2087
|
0
|
|
|
|
|
0
|
warn "Unknown page mode: $mode"; |
|
2088
|
0
|
|
|
|
|
0
|
return $mode; |
|
2089
|
|
|
|
|
|
|
} |
|
2090
|
|
|
|
|
|
|
|
|
2091
|
0
|
|
0
|
|
|
0
|
my $name = shift() // 'none'; |
|
2092
|
0
|
0
|
|
|
|
0
|
my $mode = ($name eq 'none' ? 'UseNone' : |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
2093
|
|
|
|
|
|
|
$name eq 'outlines' ? 'UseOutlines' : |
|
2094
|
|
|
|
|
|
|
$name eq 'thumbnails' ? 'UseThumbs' : |
|
2095
|
|
|
|
|
|
|
$name eq 'full_screen' ? 'FullScreen' : |
|
2096
|
|
|
|
|
|
|
$name eq 'optional_content' ? 'UseOC' : |
|
2097
|
|
|
|
|
|
|
$name eq 'attachments' ? 'UseAttachments' : ''); |
|
2098
|
|
|
|
|
|
|
|
|
2099
|
0
|
0
|
|
|
|
0
|
croak "Invalid page mode: $name" unless $mode; |
|
2100
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'PageMode'} = PDFName($mode); |
|
2101
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->out_obj($self->{'catalog'}); |
|
2102
|
0
|
|
|
|
|
0
|
return $self; |
|
2103
|
|
|
|
|
|
|
} |
|
2104
|
|
|
|
|
|
|
|
|
2105
|
|
|
|
|
|
|
=head2 viewer_preferences |
|
2106
|
|
|
|
|
|
|
|
|
2107
|
|
|
|
|
|
|
%preferences = $pdf->viewer_preferences(); # Get |
|
2108
|
|
|
|
|
|
|
|
|
2109
|
|
|
|
|
|
|
$pdf = $pdf->viewer_preferences(%preferences); # Set |
|
2110
|
|
|
|
|
|
|
|
|
2111
|
|
|
|
|
|
|
=over |
|
2112
|
|
|
|
|
|
|
|
|
2113
|
|
|
|
|
|
|
Gets/sets PDF viewer preferences, as described in |
|
2114
|
|
|
|
|
|
|
L<PDF::Builder::ViewerPreferences>. |
|
2115
|
|
|
|
|
|
|
|
|
2116
|
|
|
|
|
|
|
This has been split out from C<preferences()> for compatibility with PDF::API2. |
|
2117
|
|
|
|
|
|
|
It also can both set (assign) and get (query) the settings used. |
|
2118
|
|
|
|
|
|
|
|
|
2119
|
|
|
|
|
|
|
=back |
|
2120
|
|
|
|
|
|
|
|
|
2121
|
|
|
|
|
|
|
=cut |
|
2122
|
|
|
|
|
|
|
|
|
2123
|
|
|
|
|
|
|
sub viewer_preferences { |
|
2124
|
0
|
|
|
0
|
1
|
0
|
my $self = shift(); |
|
2125
|
0
|
|
|
|
|
0
|
require PDF::Builder::ViewerPreferences; |
|
2126
|
0
|
|
|
|
|
0
|
my $prefs = PDF::Builder::ViewerPreferences->new($self); |
|
2127
|
0
|
0
|
|
|
|
0
|
unless (@_) { |
|
2128
|
0
|
|
|
|
|
0
|
return $prefs->get_preferences(); |
|
2129
|
|
|
|
|
|
|
} |
|
2130
|
0
|
|
|
|
|
0
|
return $prefs->set_preferences(@_); |
|
2131
|
|
|
|
|
|
|
} |
|
2132
|
|
|
|
|
|
|
|
|
2133
|
|
|
|
|
|
|
=head2 preferences |
|
2134
|
|
|
|
|
|
|
|
|
2135
|
|
|
|
|
|
|
$pdf->preferences(%opts) |
|
2136
|
|
|
|
|
|
|
|
|
2137
|
|
|
|
|
|
|
=over |
|
2138
|
|
|
|
|
|
|
|
|
2139
|
|
|
|
|
|
|
Controls viewing preferences for the PDF, including the B<Page Mode>, |
|
2140
|
|
|
|
|
|
|
B<Page Layout>, B<Viewer>, and B<Initial Page> Options. See |
|
2141
|
|
|
|
|
|
|
L<PDF::Builder::Docs/Preferences - set user display preferences> for details |
|
2142
|
|
|
|
|
|
|
on all these |
|
2143
|
|
|
|
|
|
|
option groups, and L<PDF::Builder::Docs/Page Fit Options> for page positioning. |
|
2144
|
|
|
|
|
|
|
|
|
2145
|
|
|
|
|
|
|
B<Note:> the various preferences have been split out into their own methods. |
|
2146
|
|
|
|
|
|
|
It is preferred that you use these specific methods. |
|
2147
|
|
|
|
|
|
|
|
|
2148
|
|
|
|
|
|
|
=back |
|
2149
|
|
|
|
|
|
|
|
|
2150
|
|
|
|
|
|
|
=cut |
|
2151
|
|
|
|
|
|
|
|
|
2152
|
|
|
|
|
|
|
sub preferences { |
|
2153
|
239
|
|
|
239
|
1
|
953
|
my ($self, %opts) = @_; |
|
2154
|
|
|
|
|
|
|
|
|
2155
|
|
|
|
|
|
|
# copy dashed option names to the preferred undashed format |
|
2156
|
|
|
|
|
|
|
# Page Mode Options |
|
2157
|
239
|
50
|
33
|
|
|
1119
|
if (defined $opts{'-fullscreen'} && !defined $opts{'fullscreen'}) { $opts{'fullscreen'} = delete($opts{'-fullscreen'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2158
|
239
|
50
|
33
|
|
|
1029
|
if (defined $opts{'-thumbs'} && !defined $opts{'thumbs'}) { $opts{'thumbs'} = delete($opts{'-thumbs'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2159
|
239
|
50
|
33
|
|
|
1042
|
if (defined $opts{'-outlines'} && !defined $opts{'outlines'}) { $opts{'outlines'} = delete($opts{'-outlines'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2160
|
|
|
|
|
|
|
# Page Layout Options |
|
2161
|
239
|
50
|
33
|
|
|
950
|
if (defined $opts{'-singlepage'} && !defined $opts{'singlepage'}) { $opts{'singlepage'} = delete($opts{'-singlepage'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2162
|
239
|
50
|
33
|
|
|
894
|
if (defined $opts{'-onecolumn'} && !defined $opts{'onecolumn'}) { $opts{'onecolumn'} = delete($opts{'-onecolumn'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2163
|
239
|
50
|
33
|
|
|
924
|
if (defined $opts{'-twocolumnleft'} && !defined $opts{'twocolumnleft'}) { $opts{'twocolumnleft'} = delete($opts{'-twocolumnleft'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2164
|
239
|
50
|
33
|
|
|
967
|
if (defined $opts{'-twocolumnright'} && !defined $opts{'twocolumnright'}) { $opts{'twocolumnright'} = delete($opts{'-twocolumnright'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2165
|
|
|
|
|
|
|
# Viewer Preferences |
|
2166
|
239
|
50
|
33
|
|
|
1065
|
if (defined $opts{'-hidetoolbar'} && !defined $opts{'hidetoolbar'}) { $opts{'hidetoolbar'} = delete($opts{'-hidetoolbar'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2167
|
239
|
50
|
33
|
|
|
952
|
if (defined $opts{'-hidemenubar'} && !defined $opts{'hidemenubar'}) { $opts{'hidemenubar'} = delete($opts{'-hidemenubar'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2168
|
239
|
50
|
33
|
|
|
923
|
if (defined $opts{'-hidewindowui'} && !defined $opts{'hidewindowui'}) { $opts{'hidewindowui'} = delete($opts{'-hidewindowui'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2169
|
239
|
50
|
33
|
|
|
869
|
if (defined $opts{'-fitwindow'} && !defined $opts{'fitwindow'}) { $opts{'fitwindow'} = delete($opts{'-fitwindow'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2170
|
239
|
50
|
33
|
|
|
940
|
if (defined $opts{'-centerwindow'} && !defined $opts{'centerwindow'}) { $opts{'centerwindow'} = delete($opts{'-centerwindow'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2171
|
239
|
50
|
33
|
|
|
827
|
if (defined $opts{'-displaytitle'} && !defined $opts{'displaytitle'}) { $opts{'displaytitle'} = delete($opts{'-displaytitle'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2172
|
239
|
50
|
33
|
|
|
905
|
if (defined $opts{'-righttoleft'} && !defined $opts{'righttoleft'}) { $opts{'righttoleft'} = delete($opts{'-righttoleft'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2173
|
239
|
50
|
33
|
|
|
910
|
if (defined $opts{'-afterfullscreenthumbs'} && !defined $opts{'afterfullscreenthumbs'}) { $opts{'afterfullscreenthumbs'} = delete($opts{'-afterfullscreenthumbs'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2174
|
239
|
50
|
33
|
|
|
962
|
if (defined $opts{'-afterfullscreenoutlines'} && !defined $opts{'afterfullscreenoutlines'}) { $opts{'afterfullscreenoutlines'} = delete($opts{'-afterfullscreenoutlines'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2175
|
239
|
50
|
33
|
|
|
879
|
if (defined $opts{'-printscalingnone'} && !defined $opts{'printscalingnone'}) { $opts{'printscalingnone'} = delete($opts{'-printscalingnone'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2176
|
239
|
100
|
66
|
|
|
832
|
if (defined $opts{'-simplex'} && !defined $opts{'simplex'}) { $opts{'simplex'} = delete($opts{'-simplex'}); } |
|
|
1
|
|
|
|
|
4
|
|
|
2177
|
239
|
100
|
66
|
|
|
868
|
if (defined $opts{'-duplexfliplongedge'} && !defined $opts{'duplexfliplongedge'}) { $opts{'duplexfliplongedge'} = delete($opts{'-duplexfliplongedge'}); } |
|
|
1
|
|
|
|
|
3
|
|
|
2178
|
239
|
100
|
66
|
|
|
893
|
if (defined $opts{'-duplexflipshortedge'} && !defined $opts{'duplexflipshortedge'}) { $opts{'duplexflipshortedge'} = delete($opts{'-duplexflipshortedge'}); } |
|
|
1
|
|
|
|
|
3
|
|
|
2179
|
|
|
|
|
|
|
# Open Action |
|
2180
|
239
|
100
|
66
|
|
|
997
|
if (defined $opts{'-firstpage'} && !defined $opts{'firstpage'}) { $opts{'firstpage'} = delete($opts{'-firstpage'}); } |
|
|
2
|
|
|
|
|
7
|
|
|
2181
|
239
|
50
|
33
|
|
|
1041
|
if (defined $opts{'-fit'} && !defined $opts{'fit'}) { $opts{'fit'} = delete($opts{'-fit'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2182
|
239
|
50
|
33
|
|
|
1037
|
if (defined $opts{'-fith'} && !defined $opts{'fith'}) { $opts{'fith'} = delete($opts{'-fith'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2183
|
239
|
50
|
33
|
|
|
930
|
if (defined $opts{'-fitb'} && !defined $opts{'fitb'}) { $opts{'fitb'} = delete($opts{'-fitb'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2184
|
239
|
50
|
33
|
|
|
878
|
if (defined $opts{'-fitbh'} && !defined $opts{'fitbh'}) { $opts{'fitbh'} = delete($opts{'-fitbh'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2185
|
239
|
50
|
33
|
|
|
894
|
if (defined $opts{'-fitv'} && !defined $opts{'fitv'}) { $opts{'fitv'} = delete($opts{'-fitv'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2186
|
239
|
50
|
33
|
|
|
868
|
if (defined $opts{'-fitbv'} && !defined $opts{'fitbv'}) { $opts{'fitbv'} = delete($opts{'-fitbv'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2187
|
239
|
50
|
33
|
|
|
797
|
if (defined $opts{'-fitr'} && !defined $opts{'fitr'}) { $opts{'fitr'} = delete($opts{'-fitr'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2188
|
239
|
50
|
33
|
|
|
857
|
if (defined $opts{'-xyz'} && !defined $opts{'xyz'}) { $opts{'xyz'} = delete($opts{'-xyz'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2189
|
|
|
|
|
|
|
|
|
2190
|
|
|
|
|
|
|
# Page Mode Options |
|
2191
|
239
|
50
|
|
|
|
1273
|
if ($opts{'fullscreen'}) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
2192
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'PageMode'} = PDFName('FullScreen'); |
|
2193
|
|
|
|
|
|
|
} elsif ($opts{'thumbs'}) { |
|
2194
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'PageMode'} = PDFName('UseThumbs'); |
|
2195
|
|
|
|
|
|
|
} elsif ($opts{'outlines'}) { |
|
2196
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'PageMode'} = PDFName('UseOutlines'); |
|
2197
|
|
|
|
|
|
|
} else { |
|
2198
|
239
|
|
|
|
|
955
|
$self->{'catalog'}->{'PageMode'} = PDFName('UseNone'); |
|
2199
|
|
|
|
|
|
|
} |
|
2200
|
|
|
|
|
|
|
|
|
2201
|
|
|
|
|
|
|
# Page Layout Options |
|
2202
|
239
|
50
|
|
|
|
1439
|
if ($opts{'singlepage'}) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
2203
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'PageLayout'} = PDFName('SinglePage'); |
|
2204
|
|
|
|
|
|
|
} elsif ($opts{'onecolumn'}) { |
|
2205
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'PageLayout'} = PDFName('OneColumn'); |
|
2206
|
|
|
|
|
|
|
} elsif ($opts{'twocolumnleft'}) { |
|
2207
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'PageLayout'} = PDFName('TwoColumnLeft'); |
|
2208
|
|
|
|
|
|
|
} elsif ($opts{'twocolumnright'}) { |
|
2209
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'PageLayout'} = PDFName('TwoColumnRight'); |
|
2210
|
|
|
|
|
|
|
} else { |
|
2211
|
239
|
|
|
|
|
673
|
$self->{'catalog'}->{'PageLayout'} = PDFName('SinglePage'); |
|
2212
|
|
|
|
|
|
|
} |
|
2213
|
|
|
|
|
|
|
|
|
2214
|
|
|
|
|
|
|
# Viewer Preferences |
|
2215
|
239
|
|
66
|
|
|
1636
|
$self->{'catalog'}->{'ViewerPreferences'} ||= PDFDict(); |
|
2216
|
239
|
|
|
|
|
1374
|
$self->{'catalog'}->{'ViewerPreferences'}->realise(); |
|
2217
|
|
|
|
|
|
|
|
|
2218
|
239
|
50
|
|
|
|
854
|
if ($opts{'hidetoolbar'}) { |
|
2219
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'ViewerPreferences'}->{'HideToolbar'} = PDFBool(1); |
|
2220
|
|
|
|
|
|
|
} |
|
2221
|
239
|
50
|
|
|
|
754
|
if ($opts{'hidemenubar'}) { |
|
2222
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'ViewerPreferences'}->{'HideMenubar'} = PDFBool(1); |
|
2223
|
|
|
|
|
|
|
} |
|
2224
|
239
|
50
|
|
|
|
794
|
if ($opts{'hidewindowui'}) { |
|
2225
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'ViewerPreferences'}->{'HideWindowUI'} = PDFBool(1); |
|
2226
|
|
|
|
|
|
|
} |
|
2227
|
239
|
50
|
|
|
|
773
|
if ($opts{'fitwindow'}) { |
|
2228
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'ViewerPreferences'}->{'FitWindow'} = PDFBool(1); |
|
2229
|
|
|
|
|
|
|
} |
|
2230
|
239
|
50
|
|
|
|
727
|
if ($opts{'centerwindow'}) { |
|
2231
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'ViewerPreferences'}->{'CenterWindow'} = PDFBool(1); |
|
2232
|
|
|
|
|
|
|
} |
|
2233
|
239
|
50
|
|
|
|
761
|
if ($opts{'displaytitle'}) { |
|
2234
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'ViewerPreferences'}->{'DisplayDocTitle'} = PDFBool(1); |
|
2235
|
|
|
|
|
|
|
} |
|
2236
|
239
|
50
|
|
|
|
823
|
if ($opts{'righttoleft'}) { |
|
2237
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'ViewerPreferences'}->{'Direction'} = PDFName('R2L'); |
|
2238
|
|
|
|
|
|
|
} |
|
2239
|
|
|
|
|
|
|
|
|
2240
|
239
|
50
|
|
|
|
978
|
if ($opts{'afterfullscreenthumbs'}) { |
|
|
|
50
|
|
|
|
|
|
|
2241
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'ViewerPreferences'}->{'NonFullScreenPageMode'} = PDFName('UseThumbs'); |
|
2242
|
|
|
|
|
|
|
} elsif ($opts{'afterfullscreenoutlines'}) { |
|
2243
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'ViewerPreferences'}->{'NonFullScreenPageMode'} = PDFName('UseOutlines'); |
|
2244
|
|
|
|
|
|
|
} else { |
|
2245
|
239
|
|
|
|
|
686
|
$self->{'catalog'}->{'ViewerPreferences'}->{'NonFullScreenPageMode'} = PDFName('UseNone'); |
|
2246
|
|
|
|
|
|
|
} |
|
2247
|
|
|
|
|
|
|
|
|
2248
|
239
|
50
|
|
|
|
804
|
if ($opts{'printscalingnone'}) { |
|
2249
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'ViewerPreferences'}->{'PrintScaling'} = PDFName('None'); |
|
2250
|
|
|
|
|
|
|
} |
|
2251
|
|
|
|
|
|
|
|
|
2252
|
239
|
100
|
|
|
|
1456
|
if ($opts{'simplex'}) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
2253
|
1
|
|
|
|
|
4
|
$self->{'catalog'}->{'ViewerPreferences'}->{'Duplex'} = PDFName('Simplex'); |
|
2254
|
|
|
|
|
|
|
} elsif ($opts{'duplexfliplongedge'}) { |
|
2255
|
1
|
|
|
|
|
3
|
$self->{'catalog'}->{'ViewerPreferences'}->{'Duplex'} = PDFName('DuplexFlipLongEdge'); |
|
2256
|
|
|
|
|
|
|
} elsif ($opts{'duplexflipshortedge'}) { |
|
2257
|
1
|
|
|
|
|
2
|
$self->{'catalog'}->{'ViewerPreferences'}->{'Duplex'} = PDFName('DuplexFlipShortEdge'); |
|
2258
|
|
|
|
|
|
|
} |
|
2259
|
|
|
|
|
|
|
|
|
2260
|
|
|
|
|
|
|
# Open Action |
|
2261
|
239
|
100
|
|
|
|
788
|
if ($opts{'firstpage'}) { |
|
2262
|
2
|
|
|
|
|
5
|
my ($page, %args) = @{$opts{'firstpage'}}; |
|
|
2
|
|
|
|
|
9
|
|
|
2263
|
2
|
50
|
|
|
|
10
|
$args{'fit'} = 1 unless scalar keys %args; |
|
2264
|
|
|
|
|
|
|
|
|
2265
|
|
|
|
|
|
|
# $page can be either a page number (which needs to be wrapped |
|
2266
|
|
|
|
|
|
|
# in PDFNum) or a page object (which doesn't). |
|
2267
|
2
|
100
|
|
|
|
34
|
$page = PDFNum($page) unless ref($page); |
|
2268
|
|
|
|
|
|
|
|
|
2269
|
|
|
|
|
|
|
# copy dashed args names to preferred undashed names |
|
2270
|
2
|
50
|
33
|
|
|
45
|
if (defined $args{'-fit'} && !defined $args{'fit'}) { $args{'fit'} = delete($args{'-fit'}); } |
|
|
2
|
|
|
|
|
7
|
|
|
2271
|
2
|
50
|
33
|
|
|
32
|
if (defined $args{'-fith'} && !defined $args{'fith'}) { $args{'fith'} = delete($args{'-fith'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2272
|
2
|
50
|
33
|
|
|
8
|
if (defined $args{'-fitb'} && !defined $args{'fitb'}) { $args{'fitb'} = delete($args{'-fitb'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2273
|
2
|
50
|
33
|
|
|
7
|
if (defined $args{'-fitbh'} && !defined $args{'fitbh'}) { $args{'fitbh'} = delete($args{'-fitbh'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2274
|
2
|
50
|
33
|
|
|
5
|
if (defined $args{'-fitv'} && !defined $args{'fitv'}) { $args{'fitv'} = delete($args{'-fitv'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2275
|
2
|
50
|
33
|
|
|
6
|
if (defined $args{'-fitbv'} && !defined $args{'fitbv'}) { $args{'fitbv'} = delete($args{'-fitbv'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2276
|
2
|
50
|
33
|
|
|
13
|
if (defined $args{'-fitr'} && !defined $args{'fitr'}) { $args{'fitr'} = delete($args{'-fitr'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2277
|
2
|
50
|
33
|
|
|
7
|
if (defined $args{'-xyz'} && !defined $args{'xyz'}) { $args{'xyz'} = delete($args{'-xyz'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
2278
|
|
|
|
|
|
|
|
|
2279
|
2
|
50
|
|
|
|
5
|
if (defined $args{'fit'}) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
2280
|
2
|
|
|
|
|
7
|
$self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('Fit')); |
|
2281
|
|
|
|
|
|
|
} elsif (defined $args{'fith'}) { |
|
2282
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('FitH'), PDFNum($args{'fith'})); |
|
2283
|
|
|
|
|
|
|
} elsif (defined $args{'fitb'}) { |
|
2284
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('FitB')); |
|
2285
|
|
|
|
|
|
|
} elsif (defined $args{'fitbh'}) { |
|
2286
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('FitBH'), PDFNum($args{'fitbh'})); |
|
2287
|
|
|
|
|
|
|
} elsif (defined $args{'fitv'}) { |
|
2288
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('FitV'), PDFNum($args{'fitv'})); |
|
2289
|
|
|
|
|
|
|
} elsif (defined $args{'fitbv'}) { |
|
2290
|
0
|
|
|
|
|
0
|
$self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('FitBV'), PDFNum($args{'fitbv'})); |
|
2291
|
|
|
|
|
|
|
} elsif (defined $args{'fitr'}) { |
|
2292
|
0
|
0
|
|
|
|
0
|
croak 'insufficient parameters to fitr => []' unless scalar @{$args{'fitr'}} == 4; |
|
|
0
|
|
|
|
|
0
|
|
|
2293
|
|
|
|
|
|
|
$self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('FitR'), |
|
2294
|
0
|
|
|
|
|
0
|
map { PDFNum($_) } @{$args{'fitr'}}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2295
|
|
|
|
|
|
|
} elsif (defined $args{'xyz'}) { |
|
2296
|
0
|
0
|
|
|
|
0
|
croak 'insufficient parameters to xyz => []' unless scalar @{$args{'xyz'}} == 3; |
|
|
0
|
|
|
|
|
0
|
|
|
2297
|
|
|
|
|
|
|
$self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('XYZ'), |
|
2298
|
0
|
|
|
|
|
0
|
map { PDFNum($_) } @{$args{'xyz'}}); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2299
|
|
|
|
|
|
|
} |
|
2300
|
|
|
|
|
|
|
} |
|
2301
|
239
|
|
|
|
|
1289
|
$self->{'pdf'}->out_obj($self->{'catalog'}); |
|
2302
|
|
|
|
|
|
|
|
|
2303
|
239
|
|
|
|
|
645
|
return $self; |
|
2304
|
|
|
|
|
|
|
} # end of preferences() |
|
2305
|
|
|
|
|
|
|
|
|
2306
|
|
|
|
|
|
|
sub proc_pages { |
|
2307
|
0
|
|
|
0
|
0
|
0
|
my ($pdf, $object) = @_; |
|
2308
|
|
|
|
|
|
|
|
|
2309
|
0
|
0
|
|
|
|
0
|
if (defined $object->{'Resources'}) { |
|
2310
|
0
|
|
|
|
|
0
|
eval { |
|
2311
|
0
|
|
|
|
|
0
|
$object->{'Resources'}->realise(); |
|
2312
|
|
|
|
|
|
|
}; |
|
2313
|
|
|
|
|
|
|
} |
|
2314
|
|
|
|
|
|
|
|
|
2315
|
0
|
|
|
|
|
0
|
my @pages; |
|
2316
|
0
|
|
0
|
|
|
0
|
$pdf->{' apipagecount'} ||= 0; |
|
2317
|
0
|
|
|
|
|
0
|
foreach my $page ($object->{'Kids'}->elements()) { |
|
2318
|
0
|
|
|
|
|
0
|
$page->realise(); |
|
2319
|
|
|
|
|
|
|
#if ($page->{'Type'}->val() eq 'Pages') { |
|
2320
|
0
|
0
|
0
|
|
|
0
|
if (defined $page->{'Type'} && $page->{'Type'}->val() eq 'Pages') { |
|
2321
|
0
|
|
|
|
|
0
|
push @pages, proc_pages($pdf, $page); |
|
2322
|
|
|
|
|
|
|
} |
|
2323
|
|
|
|
|
|
|
else { |
|
2324
|
0
|
|
|
|
|
0
|
$pdf->{' apipagecount'}++; |
|
2325
|
0
|
|
|
|
|
0
|
$page->{' pnum'} = $pdf->{' apipagecount'}; |
|
2326
|
0
|
0
|
|
|
|
0
|
if (defined $page->{'Resources'}) { |
|
2327
|
0
|
|
|
|
|
0
|
eval { |
|
2328
|
0
|
|
|
|
|
0
|
$page->{'Resources'}->realise(); |
|
2329
|
|
|
|
|
|
|
}; |
|
2330
|
|
|
|
|
|
|
} |
|
2331
|
0
|
|
|
|
|
0
|
push @pages, $page; |
|
2332
|
|
|
|
|
|
|
} |
|
2333
|
|
|
|
|
|
|
} |
|
2334
|
|
|
|
|
|
|
|
|
2335
|
0
|
|
|
|
|
0
|
return @pages; |
|
2336
|
|
|
|
|
|
|
} |
|
2337
|
|
|
|
|
|
|
|
|
2338
|
|
|
|
|
|
|
=head1 PAGE METHODS |
|
2339
|
|
|
|
|
|
|
|
|
2340
|
|
|
|
|
|
|
=head2 page |
|
2341
|
|
|
|
|
|
|
|
|
2342
|
|
|
|
|
|
|
$page = $pdf->page() |
|
2343
|
|
|
|
|
|
|
|
|
2344
|
|
|
|
|
|
|
$page = $pdf->page($page_number) |
|
2345
|
|
|
|
|
|
|
|
|
2346
|
|
|
|
|
|
|
=over |
|
2347
|
|
|
|
|
|
|
|
|
2348
|
|
|
|
|
|
|
Returns a I<new> page object. By default, the page is added to the end |
|
2349
|
|
|
|
|
|
|
of the document. If you give an existing page number, the new page |
|
2350
|
|
|
|
|
|
|
will be inserted in that position, pushing existing pages back by 1 (e.g., |
|
2351
|
|
|
|
|
|
|
C<page(5)> would insert an empty page 5, with the old page 5 now page 6, |
|
2352
|
|
|
|
|
|
|
etc. |
|
2353
|
|
|
|
|
|
|
|
|
2354
|
|
|
|
|
|
|
If $page_number is -1, the new page is inserted as the second-to-last page; |
|
2355
|
|
|
|
|
|
|
if $page_number is 0, the new page is inserted as the last page. |
|
2356
|
|
|
|
|
|
|
|
|
2357
|
|
|
|
|
|
|
B<Example:> |
|
2358
|
|
|
|
|
|
|
|
|
2359
|
|
|
|
|
|
|
$pdf = PDF::Builder->new(); |
|
2360
|
|
|
|
|
|
|
|
|
2361
|
|
|
|
|
|
|
# Add a page. This becomes page 1. |
|
2362
|
|
|
|
|
|
|
$page = $pdf->page(); |
|
2363
|
|
|
|
|
|
|
|
|
2364
|
|
|
|
|
|
|
# Add a new first page. $page becomes page 2. |
|
2365
|
|
|
|
|
|
|
$another_page = $pdf->page(1); |
|
2366
|
|
|
|
|
|
|
|
|
2367
|
|
|
|
|
|
|
=back |
|
2368
|
|
|
|
|
|
|
|
|
2369
|
|
|
|
|
|
|
=cut |
|
2370
|
|
|
|
|
|
|
|
|
2371
|
|
|
|
|
|
|
sub page { |
|
2372
|
192
|
|
|
192
|
1
|
20151
|
my $self = shift(); |
|
2373
|
192
|
|
100
|
|
|
909
|
my $index = shift() || 0; # default to new "last" page |
|
2374
|
192
|
|
|
|
|
384
|
my $page; |
|
2375
|
|
|
|
|
|
|
|
|
2376
|
192
|
100
|
|
|
|
853
|
if ($index == 0) { |
|
2377
|
190
|
|
|
|
|
3459
|
$page = PDF::Builder::Page->new($self->{'pdf'}, $self->{'pages'}); |
|
2378
|
|
|
|
|
|
|
} else { |
|
2379
|
2
|
|
|
|
|
12
|
$page = PDF::Builder::Page->new($self->{'pdf'}, $self->{'pages'}, $index-1); |
|
2380
|
|
|
|
|
|
|
} |
|
2381
|
|
|
|
|
|
|
|
|
2382
|
192
|
|
|
|
|
700
|
$page->{' apipdf'} = $self->{'pdf'}; |
|
2383
|
192
|
|
|
|
|
592
|
$page->{' api'} = $self; |
|
2384
|
192
|
|
|
|
|
575
|
weaken $page->{' apipdf'}; |
|
2385
|
192
|
|
|
|
|
440
|
weaken $page->{' api'}; |
|
2386
|
192
|
|
|
|
|
766
|
$self->{'pdf'}->out_obj($page); |
|
2387
|
192
|
|
|
|
|
705
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
2388
|
|
|
|
|
|
|
|
|
2389
|
|
|
|
|
|
|
# fix any bad $index value |
|
2390
|
192
|
|
|
|
|
416
|
my $pgs_size = @{$self->{'pagestack'}}; |
|
|
192
|
|
|
|
|
471
|
|
|
2391
|
192
|
100
|
|
|
|
670
|
if ($pgs_size == 0) { # empty page list, can only add at end |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
2392
|
180
|
50
|
|
|
|
591
|
warn "page($index) on empty page stack is out of range, use page() or page(0)" |
|
2393
|
|
|
|
|
|
|
if ($index != 0); |
|
2394
|
180
|
|
|
|
|
390
|
$index = 0; |
|
2395
|
|
|
|
|
|
|
} elsif ($pgs_size < -$index) { # index < 0 |
|
2396
|
0
|
|
|
|
|
0
|
warn "page($index) out of range, set to page(1) (before first)"; |
|
2397
|
0
|
|
|
|
|
0
|
$index = 1; |
|
2398
|
|
|
|
|
|
|
} elsif ($pgs_size < $index) { # index > 0 |
|
2399
|
0
|
|
|
|
|
0
|
warn "page($index) out of range, set to page(0) (after last)"; |
|
2400
|
0
|
|
|
|
|
0
|
$index = 0; |
|
2401
|
|
|
|
|
|
|
} |
|
2402
|
|
|
|
|
|
|
|
|
2403
|
192
|
100
|
|
|
|
508
|
if ($index == 0) { |
|
|
|
50
|
|
|
|
|
|
|
2404
|
190
|
|
|
|
|
343
|
push @{$self->{'pagestack'}}, $page; |
|
|
190
|
|
|
|
|
556
|
|
|
2405
|
190
|
|
|
|
|
577
|
weaken $self->{'pagestack'}->[-1]; |
|
2406
|
|
|
|
|
|
|
} elsif ($index < 0) { |
|
2407
|
|
|
|
|
|
|
# note that the new element's number is one less than $index, |
|
2408
|
|
|
|
|
|
|
# since we inserted _before_ $index value! |
|
2409
|
0
|
|
|
|
|
0
|
splice @{$self->{'pagestack'}}, $index, 0, $page; |
|
|
0
|
|
|
|
|
0
|
|
|
2410
|
0
|
|
|
|
|
0
|
weaken $self->{'pagestack'}->[$index-1]; |
|
2411
|
|
|
|
|
|
|
} else { # index > 0 |
|
2412
|
2
|
|
|
|
|
4
|
splice @{$self->{'pagestack'}}, $index-1, 0, $page; |
|
|
2
|
|
|
|
|
7
|
|
|
2413
|
2
|
|
|
|
|
5
|
weaken $self->{'pagestack'}->[$index-1]; |
|
2414
|
|
|
|
|
|
|
} |
|
2415
|
|
|
|
|
|
|
|
|
2416
|
|
|
|
|
|
|
# $page->{'Resources'}=$self->{'pages'}->{'Resources'}; |
|
2417
|
192
|
|
|
|
|
1400
|
return $page; |
|
2418
|
|
|
|
|
|
|
} # end of page() |
|
2419
|
|
|
|
|
|
|
|
|
2420
|
|
|
|
|
|
|
=head2 open_page, openpage |
|
2421
|
|
|
|
|
|
|
|
|
2422
|
|
|
|
|
|
|
$page = $pdf->open_page($page_number) |
|
2423
|
|
|
|
|
|
|
|
|
2424
|
|
|
|
|
|
|
=over |
|
2425
|
|
|
|
|
|
|
|
|
2426
|
|
|
|
|
|
|
Returns the L<PDF::Builder::Page> object of page $page_number. |
|
2427
|
|
|
|
|
|
|
This is similar to C<< $page = $pdf->page() >>, except that C<$page> is |
|
2428
|
|
|
|
|
|
|
I<not> a new, empty page; but contains the contents of that existing page. |
|
2429
|
|
|
|
|
|
|
|
|
2430
|
|
|
|
|
|
|
If C<$page_number> is 0, -1, or unspecified, |
|
2431
|
|
|
|
|
|
|
it will return the last page in the document. |
|
2432
|
|
|
|
|
|
|
If the requested page is out of range, the C<$page> returned will be undefined. |
|
2433
|
|
|
|
|
|
|
|
|
2434
|
|
|
|
|
|
|
B<Example:> |
|
2435
|
|
|
|
|
|
|
|
|
2436
|
|
|
|
|
|
|
=back |
|
2437
|
|
|
|
|
|
|
|
|
2438
|
|
|
|
|
|
|
$pdf = PDF::Builder->open('our/99page.pdf'); |
|
2439
|
|
|
|
|
|
|
$page = $pdf->open_page(1); # returns the first page |
|
2440
|
|
|
|
|
|
|
$page = $pdf->open_page(99); # returns the last page |
|
2441
|
|
|
|
|
|
|
$page = $pdf->open_page(-1); # returns the last page |
|
2442
|
|
|
|
|
|
|
$page = $pdf->open_page(999); # returns undef |
|
2443
|
|
|
|
|
|
|
$page = $pdf->open_page(0); # returns the last page |
|
2444
|
|
|
|
|
|
|
$page = $pdf->open_page(); # returns the last page |
|
2445
|
|
|
|
|
|
|
|
|
2446
|
|
|
|
|
|
|
=over |
|
2447
|
|
|
|
|
|
|
|
|
2448
|
|
|
|
|
|
|
B<Alternate name:> C<openpage> |
|
2449
|
|
|
|
|
|
|
|
|
2450
|
|
|
|
|
|
|
This is the older name; it is kept for compatibility until after June 2023 |
|
2451
|
|
|
|
|
|
|
(deprecated, as previously announced). |
|
2452
|
|
|
|
|
|
|
|
|
2453
|
|
|
|
|
|
|
=back |
|
2454
|
|
|
|
|
|
|
|
|
2455
|
|
|
|
|
|
|
=cut |
|
2456
|
|
|
|
|
|
|
|
|
2457
|
1
|
|
|
1
|
1
|
11
|
sub openpage { return open_page(@_); } ## no critic |
|
2458
|
|
|
|
|
|
|
|
|
2459
|
|
|
|
|
|
|
sub open_page { |
|
2460
|
7
|
|
|
7
|
1
|
1268
|
my $self = shift(); |
|
2461
|
7
|
|
50
|
|
|
27
|
my $index = shift() || 0; |
|
2462
|
7
|
|
|
|
|
18
|
my ($page, $rotate, $media, $trans); |
|
2463
|
|
|
|
|
|
|
|
|
2464
|
7
|
50
|
|
|
|
37
|
if ($index == 0) { |
|
|
|
50
|
|
|
|
|
|
|
2465
|
0
|
|
|
|
|
0
|
$page = $self->{'pagestack'}->[-1]; |
|
2466
|
|
|
|
|
|
|
} elsif ($index < 0) { |
|
2467
|
0
|
|
|
|
|
0
|
$page = $self->{'pagestack'}->[$index]; |
|
2468
|
|
|
|
|
|
|
} else { |
|
2469
|
7
|
|
|
|
|
61
|
$page = $self->{'pagestack'}->[$index - 1]; |
|
2470
|
|
|
|
|
|
|
} |
|
2471
|
7
|
50
|
|
|
|
45
|
return unless ref($page); |
|
2472
|
|
|
|
|
|
|
|
|
2473
|
7
|
100
|
|
|
|
30
|
if (ref($page) ne 'PDF::Builder::Page') { |
|
2474
|
6
|
|
|
|
|
44
|
bless $page, 'PDF::Builder::Page'; |
|
2475
|
6
|
|
|
|
|
27
|
$page->{' apipdf'} = $self->{'pdf'}; |
|
2476
|
6
|
|
|
|
|
25
|
$page->{' api'} = $self; |
|
2477
|
6
|
|
|
|
|
45
|
weaken $page->{' apipdf'}; |
|
2478
|
6
|
|
|
|
|
17
|
weaken $page->{' api'}; |
|
2479
|
6
|
|
|
|
|
39
|
$self->{'pdf'}->out_obj($page); |
|
2480
|
6
|
50
|
33
|
|
|
37
|
if (($rotate = $page->find_prop('Rotate')) and not $page->{' opened'}) { |
|
2481
|
0
|
|
|
|
|
0
|
$rotate = ($rotate->val() + 360) % 360; |
|
2482
|
|
|
|
|
|
|
|
|
2483
|
0
|
0
|
0
|
|
|
0
|
if ($rotate != 0 and not $self->default('nounrotate')) { |
|
2484
|
0
|
|
|
|
|
0
|
$page->{'Rotate'} = PDFNum(0); |
|
2485
|
0
|
|
|
|
|
0
|
foreach my $mediatype (qw(MediaBox CropBox BleedBox TrimBox ArtBox)) { |
|
2486
|
0
|
0
|
|
|
|
0
|
if ($media = $page->find_prop($mediatype)) { |
|
2487
|
0
|
|
|
|
|
0
|
$media = [ map { $_->val() } $media->elements() ]; |
|
|
0
|
|
|
|
|
0
|
|
|
2488
|
|
|
|
|
|
|
} else { |
|
2489
|
0
|
|
|
|
|
0
|
$media = [0, 0, 612, 792]; # US Letter default |
|
2490
|
0
|
0
|
|
|
|
0
|
next if $mediatype ne 'MediaBox'; |
|
2491
|
|
|
|
|
|
|
} |
|
2492
|
0
|
0
|
|
|
|
0
|
if ($rotate == 90) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
2493
|
0
|
0
|
|
|
|
0
|
$trans = "0 -1 1 0 0 $media->[2] cm" if $mediatype eq 'MediaBox'; |
|
2494
|
0
|
|
|
|
|
0
|
$media = [$media->[1], $media->[0], $media->[3], $media->[2]]; |
|
2495
|
|
|
|
|
|
|
} elsif ($rotate == 180) { |
|
2496
|
0
|
0
|
|
|
|
0
|
$trans = "-1 0 0 -1 $media->[2] $media->[3] cm" if $mediatype eq 'MediaBox'; |
|
2497
|
|
|
|
|
|
|
} elsif ($rotate == 270) { |
|
2498
|
0
|
0
|
|
|
|
0
|
$trans = "0 1 -1 0 $media->[3] 0 cm" if $mediatype eq 'MediaBox'; |
|
2499
|
0
|
|
|
|
|
0
|
$media = [$media->[1], $media->[0], $media->[3], $media->[2]]; |
|
2500
|
|
|
|
|
|
|
} |
|
2501
|
0
|
|
|
|
|
0
|
$page->{$mediatype} = PDFArray(map { PDFNum($_) } @$media); |
|
|
0
|
|
|
|
|
0
|
|
|
2502
|
|
|
|
|
|
|
} |
|
2503
|
|
|
|
|
|
|
} else { |
|
2504
|
0
|
|
|
|
|
0
|
$trans = ''; |
|
2505
|
|
|
|
|
|
|
} |
|
2506
|
|
|
|
|
|
|
} else { |
|
2507
|
6
|
|
|
|
|
27
|
$trans = ''; |
|
2508
|
|
|
|
|
|
|
} |
|
2509
|
|
|
|
|
|
|
|
|
2510
|
6
|
100
|
66
|
|
|
41
|
if (defined $page->{'Contents'} and not $page->{' opened'}) { |
|
2511
|
4
|
|
|
|
|
28
|
$page->fixcontents(); |
|
2512
|
4
|
|
|
|
|
13
|
my $uncontent = delete $page->{'Contents'}; |
|
2513
|
4
|
|
|
|
|
22
|
my $content = $page->gfx(); |
|
2514
|
4
|
|
|
|
|
32
|
$content->add(" $trans "); |
|
2515
|
|
|
|
|
|
|
|
|
2516
|
4
|
50
|
|
|
|
26
|
if ($self->default('pageencaps')) { |
|
2517
|
0
|
|
|
|
|
0
|
$content->{' stream'} .= ' q '; |
|
2518
|
|
|
|
|
|
|
} |
|
2519
|
4
|
|
|
|
|
20
|
foreach my $k ($uncontent->elements()) { |
|
2520
|
4
|
|
|
|
|
19
|
$k->realise(); |
|
2521
|
4
|
|
|
|
|
85
|
$content->{' stream'} .= ' ' . unfilter($k->{'Filter'}, $k->{' stream'}) . ' '; |
|
2522
|
|
|
|
|
|
|
} |
|
2523
|
4
|
50
|
|
|
|
22
|
if ($self->default('pageencaps')) { |
|
2524
|
0
|
|
|
|
|
0
|
$content->{' stream'} .= ' Q '; |
|
2525
|
|
|
|
|
|
|
} |
|
2526
|
|
|
|
|
|
|
|
|
2527
|
|
|
|
|
|
|
# if we like compress we will do it now to do quicker saves |
|
2528
|
4
|
50
|
33
|
|
|
22
|
if ($self->{'forcecompress'} eq 'flate' || |
|
2529
|
|
|
|
|
|
|
$self->{'forcecompress'} =~ m/^[1-9]\d*$/) { |
|
2530
|
4
|
|
|
|
|
25
|
$content->{' stream'} = dofilter($content->{'Filter'}, $content->{' stream'}); |
|
2531
|
4
|
|
|
|
|
14
|
$content->{' nofilt'} = 1; |
|
2532
|
4
|
|
|
|
|
12
|
delete $content->{'-docompress'}; |
|
2533
|
4
|
|
|
|
|
23
|
$content->{'Length'} = PDFNum(length($content->{' stream'})); |
|
2534
|
|
|
|
|
|
|
} |
|
2535
|
|
|
|
|
|
|
} |
|
2536
|
6
|
|
|
|
|
22
|
$page->{' opened'} = 1; |
|
2537
|
|
|
|
|
|
|
} |
|
2538
|
|
|
|
|
|
|
|
|
2539
|
7
|
|
|
|
|
47
|
$self->{'pdf'}->out_obj($page); |
|
2540
|
7
|
|
|
|
|
51
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
2541
|
7
|
|
|
|
|
40
|
$page->{' apipdf'} = $self->{'pdf'}; |
|
2542
|
7
|
|
|
|
|
20
|
$page->{' api'} = $self; |
|
2543
|
7
|
|
|
|
|
20
|
weaken $page->{' apipdf'}; |
|
2544
|
7
|
|
|
|
|
14
|
weaken $page->{' api'}; |
|
2545
|
|
|
|
|
|
|
|
|
2546
|
7
|
|
|
|
|
37
|
return $page; |
|
2547
|
|
|
|
|
|
|
} # end of open_page() |
|
2548
|
|
|
|
|
|
|
|
|
2549
|
|
|
|
|
|
|
=head2 import_page, importpage |
|
2550
|
|
|
|
|
|
|
|
|
2551
|
|
|
|
|
|
|
$page = $pdf->import_page($source_pdf) |
|
2552
|
|
|
|
|
|
|
|
|
2553
|
|
|
|
|
|
|
$page = $pdf->import_page($source_pdf, $source_page_number) |
|
2554
|
|
|
|
|
|
|
|
|
2555
|
|
|
|
|
|
|
$page = $pdf->import_page($source_pdf, $source_page_number, $target_page_number) |
|
2556
|
|
|
|
|
|
|
|
|
2557
|
|
|
|
|
|
|
$page = $pdf->import_page($source_pdf, $source_page_number, $target_page_object) |
|
2558
|
|
|
|
|
|
|
|
|
2559
|
|
|
|
|
|
|
=over |
|
2560
|
|
|
|
|
|
|
|
|
2561
|
|
|
|
|
|
|
Imports a page from $source_pdf and adds it to the specified position |
|
2562
|
|
|
|
|
|
|
in $pdf. |
|
2563
|
|
|
|
|
|
|
|
|
2564
|
|
|
|
|
|
|
If the C<$source_page_number> is omitted, 0, or -1; the last page of the |
|
2565
|
|
|
|
|
|
|
source is imported. |
|
2566
|
|
|
|
|
|
|
If the C<$target_page_number> is omitted, 0, or -1; the imported page will be |
|
2567
|
|
|
|
|
|
|
placed as the new last page of the target (C<$pdf>). |
|
2568
|
|
|
|
|
|
|
Otherwise, as with the C<page()> method, the page will be inserted before an |
|
2569
|
|
|
|
|
|
|
existing page of that number. |
|
2570
|
|
|
|
|
|
|
|
|
2571
|
|
|
|
|
|
|
B<Note:> If you pass a page I<object> instead of a page I<number> for |
|
2572
|
|
|
|
|
|
|
C<$target_page_number>, the contents of the page will be B<merged> into the |
|
2573
|
|
|
|
|
|
|
existing page. |
|
2574
|
|
|
|
|
|
|
|
|
2575
|
|
|
|
|
|
|
B<Example:> |
|
2576
|
|
|
|
|
|
|
|
|
2577
|
|
|
|
|
|
|
=back |
|
2578
|
|
|
|
|
|
|
|
|
2579
|
|
|
|
|
|
|
my $pdf = PDF::Builder->new(); |
|
2580
|
|
|
|
|
|
|
my $source = PDF::Builder->open('source.pdf'); |
|
2581
|
|
|
|
|
|
|
|
|
2582
|
|
|
|
|
|
|
# Add page 2 from the old PDF as page 1 of the new PDF |
|
2583
|
|
|
|
|
|
|
my $page = $pdf->import_page($source, 2); |
|
2584
|
|
|
|
|
|
|
|
|
2585
|
|
|
|
|
|
|
$pdf->saveas('sample.pdf'); |
|
2586
|
|
|
|
|
|
|
|
|
2587
|
|
|
|
|
|
|
=over |
|
2588
|
|
|
|
|
|
|
|
|
2589
|
|
|
|
|
|
|
B<Note:> You can only import a page from an existing PDF file. |
|
2590
|
|
|
|
|
|
|
|
|
2591
|
|
|
|
|
|
|
B<Alternate name:> importpage |
|
2592
|
|
|
|
|
|
|
|
|
2593
|
|
|
|
|
|
|
This name is still valid in PDF::API2, so it is included here for compatibility. |
|
2594
|
|
|
|
|
|
|
|
|
2595
|
|
|
|
|
|
|
=back |
|
2596
|
|
|
|
|
|
|
|
|
2597
|
|
|
|
|
|
|
=cut |
|
2598
|
|
|
|
|
|
|
|
|
2599
|
|
|
|
|
|
|
# removed years ago, but is still in API2, so for code compatibility... |
|
2600
|
0
|
|
|
0
|
1
|
0
|
sub importpage{ return import_page(@_); } ## no critic |
|
2601
|
|
|
|
|
|
|
|
|
2602
|
|
|
|
|
|
|
sub import_page { |
|
2603
|
1
|
|
|
1
|
1
|
10
|
my ($self, $s_pdf, $s_idx, $t_idx) = @_; |
|
2604
|
|
|
|
|
|
|
|
|
2605
|
1
|
|
50
|
|
|
5
|
$s_idx ||= 0; # default to last page |
|
2606
|
1
|
|
50
|
|
|
8
|
$t_idx ||= 0; # default to last page |
|
2607
|
1
|
|
|
|
|
2
|
my ($s_page, $t_page); |
|
2608
|
|
|
|
|
|
|
|
|
2609
|
1
|
50
|
33
|
|
|
41
|
unless (ref($s_pdf) and $s_pdf->isa('PDF::Builder')) { |
|
2610
|
0
|
|
|
|
|
0
|
croak "Invalid usage: first argument must be PDF::Builder instance, not: " . ref($s_pdf); |
|
2611
|
|
|
|
|
|
|
} |
|
2612
|
|
|
|
|
|
|
|
|
2613
|
1
|
50
|
|
|
|
8
|
if (ref($s_idx) eq 'PDF::Builder::Page') { |
|
2614
|
0
|
|
|
|
|
0
|
$s_page = $s_idx; |
|
2615
|
|
|
|
|
|
|
} else { |
|
2616
|
1
|
|
|
|
|
6
|
$s_page = $s_pdf->open_page($s_idx); |
|
2617
|
1
|
50
|
|
|
|
5
|
croak "Unable to open page '$s_idx' in source PDF" unless defined $s_page; |
|
2618
|
|
|
|
|
|
|
} |
|
2619
|
|
|
|
|
|
|
|
|
2620
|
1
|
50
|
|
|
|
5
|
if (ref($t_idx) eq 'PDF::Builder::Page') { |
|
2621
|
0
|
|
|
|
|
0
|
$t_page = $t_idx; |
|
2622
|
|
|
|
|
|
|
} else { |
|
2623
|
1
|
50
|
|
|
|
6
|
if ($self->pages() < $t_idx) { |
|
2624
|
0
|
|
|
|
|
0
|
$t_page = $self->page(); |
|
2625
|
|
|
|
|
|
|
} else { |
|
2626
|
1
|
|
|
|
|
6
|
$t_page = $self->page($t_idx); |
|
2627
|
|
|
|
|
|
|
} |
|
2628
|
|
|
|
|
|
|
} |
|
2629
|
|
|
|
|
|
|
|
|
2630
|
1
|
|
50
|
|
|
9
|
$self->{'apiimportcache'} = $self->{'apiimportcache'} || {}; |
|
2631
|
1
|
|
50
|
|
|
23
|
$self->{'apiimportcache'}->{$s_pdf} = $self->{'apiimportcache'}->{$s_pdf} || {}; |
|
2632
|
|
|
|
|
|
|
|
|
2633
|
|
|
|
|
|
|
# we now import into a form to keep |
|
2634
|
|
|
|
|
|
|
# all those nasty resources from polluting |
|
2635
|
|
|
|
|
|
|
# our very own resource naming space. |
|
2636
|
1
|
|
|
|
|
8
|
my $xo = $self->importPageIntoForm($s_pdf, $s_page); |
|
2637
|
|
|
|
|
|
|
|
|
2638
|
|
|
|
|
|
|
# copy all page dimensions |
|
2639
|
1
|
|
|
|
|
4
|
foreach my $k (qw(MediaBox ArtBox TrimBox BleedBox CropBox)) { |
|
2640
|
5
|
|
|
|
|
16
|
my $prop = $s_page->find_prop($k); |
|
2641
|
5
|
100
|
|
|
|
13
|
next unless defined $prop; |
|
2642
|
|
|
|
|
|
|
|
|
2643
|
1
|
|
|
|
|
5
|
my $box = _walk_obj({}, $s_pdf->{'pdf'}, $self->{'pdf'}, $prop); |
|
2644
|
1
|
|
|
|
|
6
|
my $method = lc $k; |
|
2645
|
|
|
|
|
|
|
|
|
2646
|
1
|
|
|
|
|
5
|
$t_page->$method(map { $_->val() } $box->elements()); |
|
|
4
|
|
|
|
|
10
|
|
|
2647
|
|
|
|
|
|
|
} |
|
2648
|
|
|
|
|
|
|
|
|
2649
|
1
|
|
|
|
|
7
|
$t_page->gfx()->formimage($xo, 0, 0, 1); |
|
2650
|
|
|
|
|
|
|
|
|
2651
|
|
|
|
|
|
|
# copy annotations and/or form elements as well |
|
2652
|
1
|
0
|
33
|
|
|
5
|
if (exists $s_page->{'Annots'} and $s_page->{'Annots'} and $self->{'copyannots'}) { |
|
|
|
|
0
|
|
|
|
|
|
2653
|
|
|
|
|
|
|
# first set up the AcroForm, if required |
|
2654
|
0
|
|
|
|
|
0
|
my $AcroForm; |
|
2655
|
0
|
0
|
|
|
|
0
|
if (my $a = $s_pdf->{'pdf'}->{'Root'}->realise()->{'AcroForm'}) { |
|
2656
|
0
|
|
|
|
|
0
|
$a->realise(); |
|
2657
|
|
|
|
|
|
|
|
|
2658
|
0
|
|
|
|
|
0
|
$AcroForm = _walk_obj({}, $s_pdf->{'pdf'}, $self->{'pdf'}, $a, |
|
2659
|
|
|
|
|
|
|
qw(NeedAppearances SigFlags CO DR DA Q)); |
|
2660
|
|
|
|
|
|
|
} |
|
2661
|
0
|
|
|
|
|
0
|
my @Fields = (); |
|
2662
|
0
|
|
|
|
|
0
|
my @Annots = (); |
|
2663
|
0
|
|
|
|
|
0
|
foreach my $a ($s_page->{'Annots'}->elements()) { |
|
2664
|
0
|
|
|
|
|
0
|
$a->realise(); |
|
2665
|
0
|
|
|
|
|
0
|
my $t_a = PDFDict(); |
|
2666
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->new_obj($t_a); |
|
2667
|
|
|
|
|
|
|
# these objects are likely to be both annotations and Acroform fields |
|
2668
|
|
|
|
|
|
|
# key names are copied from PDF Reference 1.4 (Tables) |
|
2669
|
0
|
|
|
|
|
0
|
my @k = ( |
|
2670
|
|
|
|
|
|
|
qw( Type Subtype Contents P Rect NM M F BS Border AP AS C CA T Popup A AA StructParent Rotate |
|
2671
|
|
|
|
|
|
|
), # Annotations - Common (8.10) |
|
2672
|
|
|
|
|
|
|
qw( Subtype Contents Open Name ), # Text Annotations (8.15) |
|
2673
|
|
|
|
|
|
|
qw( Subtype Contents Dest H PA ), # Link Annotations (8.16) |
|
2674
|
|
|
|
|
|
|
qw( Subtype Contents DA Q ), # Free Text Annotations (8.17) |
|
2675
|
|
|
|
|
|
|
qw( Subtype Contents L BS LE IC ), # Line Annotations (8.18) |
|
2676
|
|
|
|
|
|
|
qw( Subtype Contents BS IC ), # Square and Circle Annotations (8.20) |
|
2677
|
|
|
|
|
|
|
qw( Subtype Contents QuadPoints ), # Markup Annotations (8.21) |
|
2678
|
|
|
|
|
|
|
qw( Subtype Contents Name ), # Rubber Stamp Annotations (8.22) |
|
2679
|
|
|
|
|
|
|
qw( Subtype Contents InkList BS ), # Ink Annotations (8.23) |
|
2680
|
|
|
|
|
|
|
qw( Subtype Contents Parent Open ), # Popup Annotations (8.24) |
|
2681
|
|
|
|
|
|
|
qw( Subtype FS Contents Name ), # File Attachment Annotations (8.25) |
|
2682
|
|
|
|
|
|
|
qw( Subtype Sound Contents Name ), # Sound Annotations (8.26) |
|
2683
|
|
|
|
|
|
|
qw( Subtype Movie Contents A ), # Movie Annotations (8.27) |
|
2684
|
|
|
|
|
|
|
qw( Subtype Contents H MK ), # Widget Annotations (8.28) |
|
2685
|
|
|
|
|
|
|
# Printers Mark Annotations (none) |
|
2686
|
|
|
|
|
|
|
# Trap Network Annotations (none) |
|
2687
|
|
|
|
|
|
|
); |
|
2688
|
0
|
0
|
|
|
|
0
|
push @k, ( |
|
2689
|
|
|
|
|
|
|
qw( Subtype FT Parent Kids T TU TM Ff V DV AA |
|
2690
|
|
|
|
|
|
|
), # Fields - Common (8.49) |
|
2691
|
|
|
|
|
|
|
qw( DR DA Q ), # Fields containing variable text (8.51) |
|
2692
|
|
|
|
|
|
|
qw( Opt ), # Checkbox field (8.54) |
|
2693
|
|
|
|
|
|
|
qw( Opt ), # Radio field (8.55) |
|
2694
|
|
|
|
|
|
|
qw( MaxLen ), # Text field (8.57) |
|
2695
|
|
|
|
|
|
|
qw( Opt TI I ), # Choice field (8.59) |
|
2696
|
|
|
|
|
|
|
) if $AcroForm; |
|
2697
|
|
|
|
|
|
|
|
|
2698
|
|
|
|
|
|
|
# sorting out dupes |
|
2699
|
0
|
|
|
|
|
0
|
my %ky = map { $_ => 1 } @k; |
|
|
0
|
|
|
|
|
0
|
|
|
2700
|
|
|
|
|
|
|
# we do P separately, as it points to the page the Annotation is on |
|
2701
|
0
|
|
|
|
|
0
|
delete $ky{'P'}; |
|
2702
|
|
|
|
|
|
|
# copy everything else |
|
2703
|
0
|
|
|
|
|
0
|
foreach my $k (keys %ky) { |
|
2704
|
0
|
0
|
|
|
|
0
|
next unless defined $a->{$k}; |
|
2705
|
0
|
|
|
|
|
0
|
$a->{$k}->realise(); |
|
2706
|
0
|
|
|
|
|
0
|
$t_a->{$k} = _walk_obj({}, $s_pdf->{'pdf'}, $self->{'pdf'}, $a->{$k}); |
|
2707
|
|
|
|
|
|
|
} |
|
2708
|
0
|
|
|
|
|
0
|
$t_a->{'P'} = $t_page; |
|
2709
|
0
|
|
|
|
|
0
|
push @Annots, $t_a; |
|
2710
|
0
|
0
|
0
|
|
|
0
|
push @Fields, $t_a if ($AcroForm and $t_a->{'Subtype'}->val() eq 'Widget'); |
|
2711
|
|
|
|
|
|
|
} |
|
2712
|
0
|
|
|
|
|
0
|
$t_page->{'Annots'} = PDFArray(@Annots); |
|
2713
|
0
|
0
|
|
|
|
0
|
$AcroForm->{'Fields'} = PDFArray(@Fields) if $AcroForm; |
|
2714
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->{'Root'}->{'AcroForm'} = $AcroForm; |
|
2715
|
|
|
|
|
|
|
} |
|
2716
|
1
|
|
|
|
|
6
|
$t_page->{' imported'} = 1; |
|
2717
|
|
|
|
|
|
|
|
|
2718
|
1
|
|
|
|
|
5
|
$self->{'pdf'}->out_obj($t_page); |
|
2719
|
1
|
|
|
|
|
4
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
2720
|
|
|
|
|
|
|
|
|
2721
|
1
|
|
|
|
|
5
|
return $t_page; |
|
2722
|
|
|
|
|
|
|
} # end of import_page() |
|
2723
|
|
|
|
|
|
|
|
|
2724
|
|
|
|
|
|
|
=head2 embed_page, importPageIntoForm |
|
2725
|
|
|
|
|
|
|
|
|
2726
|
|
|
|
|
|
|
$xoform = $pdf->embed_page($source_pdf, $source_page_number) |
|
2727
|
|
|
|
|
|
|
|
|
2728
|
|
|
|
|
|
|
=over |
|
2729
|
|
|
|
|
|
|
|
|
2730
|
|
|
|
|
|
|
Returns a Form XObject created by extracting the specified page from |
|
2731
|
|
|
|
|
|
|
C<$source_pdf>. |
|
2732
|
|
|
|
|
|
|
|
|
2733
|
|
|
|
|
|
|
This is useful if you want to transpose the imported page somewhat |
|
2734
|
|
|
|
|
|
|
differently onto a page (e.g. two-up, four-up, etc.). |
|
2735
|
|
|
|
|
|
|
|
|
2736
|
|
|
|
|
|
|
If C<$source_page_number> is 0 or -1, it will return the last page in the |
|
2737
|
|
|
|
|
|
|
document. The B<default> value for the C<$source_page_number> is 0 (return |
|
2738
|
|
|
|
|
|
|
last page). |
|
2739
|
|
|
|
|
|
|
|
|
2740
|
|
|
|
|
|
|
B<Example:> |
|
2741
|
|
|
|
|
|
|
|
|
2742
|
|
|
|
|
|
|
=back |
|
2743
|
|
|
|
|
|
|
|
|
2744
|
|
|
|
|
|
|
# take page 2 of source.pdf and add to empty doc sample.pdf at half size |
|
2745
|
|
|
|
|
|
|
# note that sample.pdf could be an existing document! |
|
2746
|
|
|
|
|
|
|
# |
|
2747
|
|
|
|
|
|
|
my $pdf = PDF::Builder->new(); # so far, empty document |
|
2748
|
|
|
|
|
|
|
my $source = PDF::Builder->open('source.pdf'); # content to copy over |
|
2749
|
|
|
|
|
|
|
my $page = $pdf->page(); # place to be actually updated |
|
2750
|
|
|
|
|
|
|
|
|
2751
|
|
|
|
|
|
|
# Import Page 2 from the source PDF |
|
2752
|
|
|
|
|
|
|
my $xo = $pdf->embed_page($source, 2); |
|
2753
|
|
|
|
|
|
|
|
|
2754
|
|
|
|
|
|
|
# Add it to the new PDF's first page at 1/2 scale |
|
2755
|
|
|
|
|
|
|
my ($x, $y) = (0, 0); |
|
2756
|
|
|
|
|
|
|
$page->object($xo, $x, $y, 0.5); |
|
2757
|
|
|
|
|
|
|
|
|
2758
|
|
|
|
|
|
|
$pdf->save('sample.pdf'); |
|
2759
|
|
|
|
|
|
|
|
|
2760
|
|
|
|
|
|
|
=over |
|
2761
|
|
|
|
|
|
|
|
|
2762
|
|
|
|
|
|
|
B<Note:> You can only import a page from an existing PDF file. |
|
2763
|
|
|
|
|
|
|
|
|
2764
|
|
|
|
|
|
|
B<Alternate name:> C<importPageIntoForm> |
|
2765
|
|
|
|
|
|
|
|
|
2766
|
|
|
|
|
|
|
This is the older name; it is kept for compatibility. |
|
2767
|
|
|
|
|
|
|
|
|
2768
|
|
|
|
|
|
|
=back |
|
2769
|
|
|
|
|
|
|
|
|
2770
|
|
|
|
|
|
|
=cut |
|
2771
|
|
|
|
|
|
|
|
|
2772
|
4
|
|
|
4
|
1
|
42
|
sub importPageIntoForm { return embed_page(@_); } ## no critic |
|
2773
|
|
|
|
|
|
|
|
|
2774
|
|
|
|
|
|
|
sub embed_page { |
|
2775
|
4
|
|
|
4
|
1
|
15
|
my ($self, $s_pdf, $s_idx) = @_; |
|
2776
|
4
|
|
50
|
|
|
17
|
$s_idx ||= 0; |
|
2777
|
|
|
|
|
|
|
|
|
2778
|
4
|
50
|
33
|
|
|
64
|
unless (ref($s_pdf) and $s_pdf->isa('PDF::Builder')) { |
|
2779
|
0
|
|
|
|
|
0
|
croak "Invalid usage: first argument must be PDF::Builder instance, not: " . ref($s_pdf); |
|
2780
|
|
|
|
|
|
|
} |
|
2781
|
|
|
|
|
|
|
|
|
2782
|
4
|
|
|
|
|
11
|
my ($s_page, $xo); |
|
2783
|
|
|
|
|
|
|
|
|
2784
|
4
|
|
|
|
|
26
|
$xo = $self->xo_form(); |
|
2785
|
|
|
|
|
|
|
|
|
2786
|
4
|
100
|
|
|
|
20
|
if (ref($s_idx) eq 'PDF::Builder::Page') { |
|
2787
|
1
|
|
|
|
|
15
|
$s_page = $s_idx; |
|
2788
|
|
|
|
|
|
|
} else { |
|
2789
|
3
|
|
|
|
|
20
|
$s_page = $s_pdf->open_page($s_idx); |
|
2790
|
3
|
50
|
|
|
|
13
|
croak "Unable to open page '$s_idx' in source PDF" unless defined $s_page; |
|
2791
|
|
|
|
|
|
|
} |
|
2792
|
|
|
|
|
|
|
|
|
2793
|
4
|
|
100
|
|
|
31
|
$self->{'apiimportcache'} ||= {}; |
|
2794
|
4
|
|
100
|
|
|
27
|
$self->{'apiimportcache'}->{$s_pdf} ||= {}; |
|
2795
|
|
|
|
|
|
|
|
|
2796
|
|
|
|
|
|
|
# This should never get past MediaBox, since it's a required object. |
|
2797
|
4
|
|
|
|
|
15
|
foreach my $k (qw(MediaBox ArtBox TrimBox BleedBox CropBox)) { |
|
2798
|
|
|
|
|
|
|
#next unless defined $s_page->{$k}; |
|
2799
|
|
|
|
|
|
|
#my $box = _walk_obj($self->{'apiimportcache'}->{$s_pdf}, $s_pdf->{'pdf'}, |
|
2800
|
|
|
|
|
|
|
# $self->{'pdf'}, $s_page->{$k}); |
|
2801
|
4
|
50
|
|
|
|
20
|
next unless defined $s_page->find_prop($k); |
|
2802
|
|
|
|
|
|
|
my $box = _walk_obj($self->{'apiimportcache'}->{$s_pdf}, $s_pdf->{'pdf'}, |
|
2803
|
4
|
|
|
|
|
43
|
$self->{'pdf'}, $s_page->find_prop($k)); |
|
2804
|
4
|
|
|
|
|
18
|
$xo->bbox(map { $_->val() } $box->elements()); |
|
|
16
|
|
|
|
|
44
|
|
|
2805
|
4
|
|
|
|
|
16
|
last; |
|
2806
|
|
|
|
|
|
|
} |
|
2807
|
4
|
50
|
|
|
|
22
|
$xo->bbox(0,0, 612,792) unless defined $xo->{'BBox'}; # US Letter default |
|
2808
|
|
|
|
|
|
|
|
|
2809
|
4
|
|
|
|
|
25
|
foreach my $k (qw(Resources)) { |
|
2810
|
4
|
|
|
|
|
24
|
$s_page->{$k} = $s_page->find_prop($k); |
|
2811
|
4
|
50
|
|
|
|
17
|
next unless defined $s_page->{$k}; |
|
2812
|
4
|
50
|
|
|
|
21
|
$s_page->{$k}->realise() if ref($s_page->{$k}) =~ /Objind$/; |
|
2813
|
|
|
|
|
|
|
|
|
2814
|
4
|
|
|
|
|
15
|
foreach my $sk (qw(XObject ExtGState Font ProcSet Properties ColorSpace Pattern Shading)) { |
|
2815
|
32
|
100
|
|
|
|
107
|
next unless defined $s_page->{$k}->{$sk}; |
|
2816
|
5
|
50
|
|
|
|
32
|
$s_page->{$k}->{$sk}->realise() if ref($s_page->{$k}->{$sk}) =~ /Objind$/; |
|
2817
|
5
|
|
|
|
|
14
|
foreach my $ssk (keys %{$s_page->{$k}->{$sk}}) { |
|
|
5
|
|
|
|
|
29
|
|
|
2818
|
10
|
100
|
|
|
|
43
|
next if $ssk =~ /^ /; |
|
2819
|
|
|
|
|
|
|
$xo->resource($sk, $ssk, _walk_obj($self->{'apiimportcache'}->{$s_pdf}, |
|
2820
|
1
|
|
|
|
|
8
|
$s_pdf->{'pdf'}, $self->{'pdf'}, $s_page->{$k}->{$sk}->{$ssk})); |
|
2821
|
|
|
|
|
|
|
} |
|
2822
|
|
|
|
|
|
|
} |
|
2823
|
|
|
|
|
|
|
} |
|
2824
|
|
|
|
|
|
|
|
|
2825
|
|
|
|
|
|
|
# create a whole content stream |
|
2826
|
|
|
|
|
|
|
## technically it is possible to submit an unfinished |
|
2827
|
|
|
|
|
|
|
## (e.g., newly created) source-page, but that's nonsense, |
|
2828
|
|
|
|
|
|
|
## so we expect a page fixed by open_page and croak otherwise |
|
2829
|
4
|
50
|
|
|
|
19
|
unless ($s_page->{' opened'}) { |
|
2830
|
0
|
|
|
|
|
0
|
croak "Pages may only be imported from a complete PDF. Save and reopen the source PDF object first."; |
|
2831
|
|
|
|
|
|
|
} |
|
2832
|
|
|
|
|
|
|
|
|
2833
|
4
|
100
|
|
|
|
15
|
if (defined $s_page->{'Contents'}) { |
|
2834
|
3
|
|
|
|
|
21
|
$s_page->fixcontents(); |
|
2835
|
|
|
|
|
|
|
|
|
2836
|
3
|
|
|
|
|
9
|
$xo->{' stream'} = ''; |
|
2837
|
|
|
|
|
|
|
# open_page pages only contain one stream |
|
2838
|
3
|
|
|
|
|
18
|
my ($k) = $s_page->{'Contents'}->elements(); |
|
2839
|
3
|
|
|
|
|
38
|
$k->realise(); |
|
2840
|
3
|
50
|
|
|
|
12
|
if ($k->{' nofilt'}) { |
|
2841
|
|
|
|
|
|
|
# we have a finished stream here, so we unfilter |
|
2842
|
3
|
|
|
|
|
33
|
$xo->add('q', unfilter($k->{'Filter'}, $k->{' stream'}), 'Q'); |
|
2843
|
|
|
|
|
|
|
} else { |
|
2844
|
|
|
|
|
|
|
# stream is an unfinished/unfiltered content |
|
2845
|
|
|
|
|
|
|
# so we just copy it and add the required "qQ" |
|
2846
|
0
|
|
|
|
|
0
|
$xo->add('q', $k->{' stream'}, 'Q'); |
|
2847
|
|
|
|
|
|
|
} |
|
2848
|
|
|
|
|
|
|
$xo->compressFlate() if $self->{'forcecompress'} eq 'flate' || |
|
2849
|
3
|
100
|
66
|
|
|
34
|
$self->{'forcecompress'} =~ m/^[1-9]\d*$/; |
|
2850
|
|
|
|
|
|
|
} |
|
2851
|
|
|
|
|
|
|
|
|
2852
|
4
|
|
|
|
|
159
|
return $xo; |
|
2853
|
|
|
|
|
|
|
} # end of embed_page() |
|
2854
|
|
|
|
|
|
|
|
|
2855
|
|
|
|
|
|
|
# internal utility used by embed_page and import_page |
|
2856
|
|
|
|
|
|
|
|
|
2857
|
|
|
|
|
|
|
sub _walk_obj { |
|
2858
|
518
|
|
|
518
|
|
1211
|
my ($object_cache, $source_pdf, $target_pdf, $source_object, @keys) = @_; |
|
2859
|
|
|
|
|
|
|
|
|
2860
|
518
|
100
|
|
|
|
2784
|
if (ref($source_object) =~ /Objind$/) { |
|
2861
|
1
|
|
|
|
|
5
|
$source_object->realise(); |
|
2862
|
|
|
|
|
|
|
} |
|
2863
|
|
|
|
|
|
|
|
|
2864
|
518
|
50
|
|
|
|
1831
|
return $object_cache->{scalar $source_object} if defined $object_cache->{scalar $source_object}; |
|
2865
|
|
|
|
|
|
|
#croak "infinite loop while copying objects" if $source_object->{' copied'}; |
|
2866
|
|
|
|
|
|
|
|
|
2867
|
518
|
|
|
|
|
1986
|
my $target_object = $source_object->copy($source_pdf); ## thanks to: yaheath // Fri, 17 Sep 2004 |
|
2868
|
|
|
|
|
|
|
|
|
2869
|
|
|
|
|
|
|
#$source_object->{' copied'} = 1; |
|
2870
|
518
|
100
|
|
|
|
1427
|
$target_pdf->new_obj($target_object) if $source_object->is_obj($source_pdf); |
|
2871
|
|
|
|
|
|
|
|
|
2872
|
518
|
|
|
|
|
5363
|
$object_cache->{scalar $source_object} = $target_object; |
|
2873
|
|
|
|
|
|
|
|
|
2874
|
518
|
100
|
|
|
|
2086
|
if (ref($source_object) =~ /Array$/) { |
|
|
|
100
|
|
|
|
|
|
|
2875
|
7
|
|
|
|
|
373
|
$target_object->{' val'} = []; |
|
2876
|
7
|
|
|
|
|
69
|
foreach my $k ($source_object->elements()) { |
|
2877
|
501
|
50
|
|
|
|
1493
|
$k->realise() if ref($k) =~ /Objind$/; |
|
2878
|
501
|
|
|
|
|
1320
|
$target_object->add_elements(_walk_obj($object_cache, $source_pdf, $target_pdf, $k)); |
|
2879
|
|
|
|
|
|
|
} |
|
2880
|
|
|
|
|
|
|
} elsif (ref($source_object) =~ /Dict$/) { |
|
2881
|
2
|
50
|
|
|
|
15
|
@keys = keys(%$target_object) unless scalar @keys; |
|
2882
|
2
|
|
|
|
|
7
|
foreach my $k (@keys) { |
|
2883
|
12
|
100
|
|
|
|
53
|
next if $k =~ /^ /; |
|
2884
|
11
|
50
|
|
|
|
53
|
next unless defined $source_object->{$k}; |
|
2885
|
11
|
|
|
|
|
39
|
$target_object->{$k} = _walk_obj($object_cache, $source_pdf, $target_pdf, $source_object->{$k}); |
|
2886
|
|
|
|
|
|
|
} |
|
2887
|
2
|
50
|
|
|
|
508
|
if ($source_object->{' stream'}) { |
|
2888
|
0
|
0
|
|
|
|
0
|
if ($target_object->{'Filter'}) { |
|
2889
|
0
|
|
|
|
|
0
|
$target_object->{' nofilt'} = 1; |
|
2890
|
|
|
|
|
|
|
} else { |
|
2891
|
0
|
|
|
|
|
0
|
delete $target_object->{' nofilt'}; |
|
2892
|
0
|
|
|
|
|
0
|
$target_object->{'Filter'} = PDFArray(PDFName('FlateDecode')); |
|
2893
|
|
|
|
|
|
|
} |
|
2894
|
0
|
|
|
|
|
0
|
$target_object->{' stream'} = $source_object->{' stream'}; |
|
2895
|
|
|
|
|
|
|
} |
|
2896
|
|
|
|
|
|
|
} |
|
2897
|
518
|
|
|
|
|
1257
|
delete $target_object->{' streamloc'}; |
|
2898
|
518
|
|
|
|
|
1027
|
delete $target_object->{' streamsrc'}; |
|
2899
|
|
|
|
|
|
|
|
|
2900
|
518
|
|
|
|
|
6394
|
return $target_object; |
|
2901
|
|
|
|
|
|
|
} # end of _walk_obj() |
|
2902
|
|
|
|
|
|
|
|
|
2903
|
|
|
|
|
|
|
=head2 page_count, pages |
|
2904
|
|
|
|
|
|
|
|
|
2905
|
|
|
|
|
|
|
$count = $pdf->page_count() |
|
2906
|
|
|
|
|
|
|
|
|
2907
|
|
|
|
|
|
|
=over |
|
2908
|
|
|
|
|
|
|
|
|
2909
|
|
|
|
|
|
|
Returns the number of pages in the document. |
|
2910
|
|
|
|
|
|
|
|
|
2911
|
|
|
|
|
|
|
B<Alternate name:> C<pages> |
|
2912
|
|
|
|
|
|
|
|
|
2913
|
|
|
|
|
|
|
This is the old name; it is kept for compatibility. |
|
2914
|
|
|
|
|
|
|
|
|
2915
|
|
|
|
|
|
|
=back |
|
2916
|
|
|
|
|
|
|
|
|
2917
|
|
|
|
|
|
|
=cut |
|
2918
|
|
|
|
|
|
|
|
|
2919
|
3
|
|
|
3
|
1
|
329
|
sub pages { return page_count(@_); } ## no critic |
|
2920
|
|
|
|
|
|
|
|
|
2921
|
|
|
|
|
|
|
sub page_count { |
|
2922
|
3
|
|
|
3
|
1
|
7
|
my $self = shift(); |
|
2923
|
3
|
|
|
|
|
5
|
return scalar @{$self->{'pagestack'}}; |
|
|
3
|
|
|
|
|
16
|
|
|
2924
|
|
|
|
|
|
|
} |
|
2925
|
|
|
|
|
|
|
|
|
2926
|
|
|
|
|
|
|
=head2 page_labels, pageLabel |
|
2927
|
|
|
|
|
|
|
|
|
2928
|
|
|
|
|
|
|
$pdf->page_labels($page_number, %opts) |
|
2929
|
|
|
|
|
|
|
|
|
2930
|
|
|
|
|
|
|
=over |
|
2931
|
|
|
|
|
|
|
|
|
2932
|
|
|
|
|
|
|
Sets page label numbering format, for the PDF Reader's page-selection slider |
|
2933
|
|
|
|
|
|
|
thumb (I<not> the outline/bookmarks). At this time, there is no method to |
|
2934
|
|
|
|
|
|
|
automatically synchronize a page's label with the outline/bookmarks, or to |
|
2935
|
|
|
|
|
|
|
somewhere on the printed page. |
|
2936
|
|
|
|
|
|
|
Depending on the PDF Reader you are using, this formatted page label I<may> |
|
2937
|
|
|
|
|
|
|
show up in the reader control area as the current page number. |
|
2938
|
|
|
|
|
|
|
|
|
2939
|
|
|
|
|
|
|
B<CAUTIONS:> |
|
2940
|
|
|
|
|
|
|
|
|
2941
|
|
|
|
|
|
|
=back |
|
2942
|
|
|
|
|
|
|
|
|
2943
|
|
|
|
|
|
|
=over |
|
2944
|
|
|
|
|
|
|
|
|
2945
|
|
|
|
|
|
|
=item 1. |
|
2946
|
|
|
|
|
|
|
|
|
2947
|
|
|
|
|
|
|
The given page index started at 0 for the old method (C<pageLabel()>), |
|
2948
|
|
|
|
|
|
|
which is the internal PDF array index, while for the new method |
|
2949
|
|
|
|
|
|
|
(C<page_labels()>) it starts with 1, the visible page number! Don't get |
|
2950
|
|
|
|
|
|
|
confused. |
|
2951
|
|
|
|
|
|
|
|
|
2952
|
|
|
|
|
|
|
=item 2. |
|
2953
|
|
|
|
|
|
|
|
|
2954
|
|
|
|
|
|
|
Options for the old method (C<pageLabel>) were a hashref, while for the |
|
2955
|
|
|
|
|
|
|
new method (C<page_labels>) it is a hash. This permits pageLabel() to accept |
|
2956
|
|
|
|
|
|
|
I<multiple> page number schemes in one call, rather than one per call as per |
|
2957
|
|
|
|
|
|
|
page_labels(). |
|
2958
|
|
|
|
|
|
|
|
|
2959
|
|
|
|
|
|
|
=item 3. |
|
2960
|
|
|
|
|
|
|
|
|
2961
|
|
|
|
|
|
|
Many PDF readers do not support page labels; they simply (at most) |
|
2962
|
|
|
|
|
|
|
label the sliding thumb with the physical page number. B<Adobe Acrobat Reader> |
|
2963
|
|
|
|
|
|
|
(free version) appears to have a bug in some versions, where if the only |
|
2964
|
|
|
|
|
|
|
page label is 'decimal' (the default), it labels the thumb as though no page |
|
2965
|
|
|
|
|
|
|
labels were defined ("Page I<m> of I<n>"). You can get around this problem by |
|
2966
|
|
|
|
|
|
|
using an explicit B<start> option value, e.g., C<'start' =E<gt> 1>. However, |
|
2967
|
|
|
|
|
|
|
for your convenience, the B<start> option now defaults to 1. |
|
2968
|
|
|
|
|
|
|
|
|
2969
|
|
|
|
|
|
|
=back |
|
2970
|
|
|
|
|
|
|
|
|
2971
|
|
|
|
|
|
|
# Generate a 30-page PDF |
|
2972
|
|
|
|
|
|
|
my $pdf = PDF::Builder->new(); |
|
2973
|
|
|
|
|
|
|
$pdf->page() for 1..30; |
|
2974
|
|
|
|
|
|
|
|
|
2975
|
|
|
|
|
|
|
# Number pages i to v, 1 to 20, and A-1 to A-5, respectively |
|
2976
|
|
|
|
|
|
|
$pdf->page_labels(1, 'style' => 'roman'); |
|
2977
|
|
|
|
|
|
|
$pdf->page_labels(6, 'style' => 'decimal'); |
|
2978
|
|
|
|
|
|
|
$pdf->page_labels(26, 'style' => 'decimal', 'prefix' => 'A-'); |
|
2979
|
|
|
|
|
|
|
|
|
2980
|
|
|
|
|
|
|
or... |
|
2981
|
|
|
|
|
|
|
|
|
2982
|
|
|
|
|
|
|
$pdf->pageLabel(0, { style => 'roman' }, |
|
2983
|
|
|
|
|
|
|
5, { style => 'decimal' }, |
|
2984
|
|
|
|
|
|
|
25, { style => 'decimal', prefix => 'A-' }); |
|
2985
|
|
|
|
|
|
|
|
|
2986
|
|
|
|
|
|
|
$pdf->save('sample.pdf'); |
|
2987
|
|
|
|
|
|
|
|
|
2988
|
|
|
|
|
|
|
B<Supported Options:> |
|
2989
|
|
|
|
|
|
|
|
|
2990
|
|
|
|
|
|
|
=over |
|
2991
|
|
|
|
|
|
|
|
|
2992
|
|
|
|
|
|
|
=item style |
|
2993
|
|
|
|
|
|
|
|
|
2994
|
|
|
|
|
|
|
B<Roman> (I,II,III,...), B<roman> (i,ii,iii,...), B<decimal> (1,2,3,...), |
|
2995
|
|
|
|
|
|
|
B<Alpha> (A,B,C,...), B<alpha> (a,b,c,...), or B<nocounter>. This is the |
|
2996
|
|
|
|
|
|
|
styling of the counter part of the label (unless C<nocounter>, in which case |
|
2997
|
|
|
|
|
|
|
there is no counter output). Note that B<arabic> is permitted as a synonym |
|
2998
|
|
|
|
|
|
|
for B<decimal>. |
|
2999
|
|
|
|
|
|
|
|
|
3000
|
|
|
|
|
|
|
=item start |
|
3001
|
|
|
|
|
|
|
|
|
3002
|
|
|
|
|
|
|
(Re)start numbering the I<counter> at given page number (this is a decimal |
|
3003
|
|
|
|
|
|
|
integer, I<not> the styled counter). By default it starts at 1, and B<resets> |
|
3004
|
|
|
|
|
|
|
to 1 at each call to C<page_labels()>! You need to explicitly give C<start> if |
|
3005
|
|
|
|
|
|
|
you want to I<continue> counting at the current page number when you call |
|
3006
|
|
|
|
|
|
|
C<page_labels()>, whether or not you are changing the format. |
|
3007
|
|
|
|
|
|
|
|
|
3008
|
|
|
|
|
|
|
Also note that the counter starts at physical page B<1>, while the page |
|
3009
|
|
|
|
|
|
|
C<$index> number in the C<page_labels()> call (as well as the PDF PageLabels |
|
3010
|
|
|
|
|
|
|
dictionary) starts at logical page (index) B<0>. |
|
3011
|
|
|
|
|
|
|
|
|
3012
|
|
|
|
|
|
|
=item prefix |
|
3013
|
|
|
|
|
|
|
|
|
3014
|
|
|
|
|
|
|
Text prefix for numbering, such as an Appendix letter B<B->. If C<style> is |
|
3015
|
|
|
|
|
|
|
I<nocounter>, just this text is used, otherwise a styled counter will be |
|
3016
|
|
|
|
|
|
|
appended. If C<style> is omitted, remember that it will default to a decimal |
|
3017
|
|
|
|
|
|
|
number, which will be appended to the prefix. |
|
3018
|
|
|
|
|
|
|
|
|
3019
|
|
|
|
|
|
|
According to the Adobe/ISO PDF specification, a prefix of 'Content' has a |
|
3020
|
|
|
|
|
|
|
special meaning, in that any /S counter is ignored and only that text is used. |
|
3021
|
|
|
|
|
|
|
However, this appears to be ignored (use a style of I<nocounter> to suppress |
|
3022
|
|
|
|
|
|
|
the counter). |
|
3023
|
|
|
|
|
|
|
|
|
3024
|
|
|
|
|
|
|
=back |
|
3025
|
|
|
|
|
|
|
|
|
3026
|
|
|
|
|
|
|
=over |
|
3027
|
|
|
|
|
|
|
|
|
3028
|
|
|
|
|
|
|
B<Dotted inserted page numbers> |
|
3029
|
|
|
|
|
|
|
|
|
3030
|
|
|
|
|
|
|
To easily insert a range of pages, e.g., 3 pages between existing pages 37 and |
|
3031
|
|
|
|
|
|
|
38, use a C<prefix> of '37.' and decimal numbering starting (C<start>) at 1 or |
|
3032
|
|
|
|
|
|
|
a specified point. This would produce pages 37.1, 37.2, and 37.3. To put |
|
3033
|
|
|
|
|
|
|
leading 0's on the numbers, if you find that you later need to insert additional |
|
3034
|
|
|
|
|
|
|
pages between those, e.g., page 37.05 between 37 and 37.1, use a C<prefix> of |
|
3035
|
|
|
|
|
|
|
'37.0' and C<start> at 5. |
|
3036
|
|
|
|
|
|
|
|
|
3037
|
|
|
|
|
|
|
Just remember that only the (rightmost) I<counter>, which begins at the |
|
3038
|
|
|
|
|
|
|
C<start> value, is incremented (and formatted) by the PDF Reader. Everything |
|
3039
|
|
|
|
|
|
|
else (the C<prefix>) is a constant string. At worst, you might have to define |
|
3040
|
|
|
|
|
|
|
a page label for each individual page. |
|
3041
|
|
|
|
|
|
|
|
|
3042
|
|
|
|
|
|
|
B<Example:> |
|
3043
|
|
|
|
|
|
|
|
|
3044
|
|
|
|
|
|
|
=back |
|
3045
|
|
|
|
|
|
|
|
|
3046
|
|
|
|
|
|
|
# Start with lowercase Roman Numerals at the 1st page, starting with i (1) |
|
3047
|
|
|
|
|
|
|
$pdf->page_labels(1, |
|
3048
|
|
|
|
|
|
|
'style' => 'roman', |
|
3049
|
|
|
|
|
|
|
); |
|
3050
|
|
|
|
|
|
|
|
|
3051
|
|
|
|
|
|
|
or, |
|
3052
|
|
|
|
|
|
|
|
|
3053
|
|
|
|
|
|
|
$pdf->pageLabel(0, |
|
3054
|
|
|
|
|
|
|
{ 'style' => 'roman' }, |
|
3055
|
|
|
|
|
|
|
); |
|
3056
|
|
|
|
|
|
|
|
|
3057
|
|
|
|
|
|
|
# Switch to Arabic (decimal) at the 5th page, starting with 1 |
|
3058
|
|
|
|
|
|
|
$pdf->page_labels(5, |
|
3059
|
|
|
|
|
|
|
'style' => 'decimal', |
|
3060
|
|
|
|
|
|
|
); |
|
3061
|
|
|
|
|
|
|
|
|
3062
|
|
|
|
|
|
|
or, |
|
3063
|
|
|
|
|
|
|
|
|
3064
|
|
|
|
|
|
|
$pdf->pageLabel(4, |
|
3065
|
|
|
|
|
|
|
{ 'style' => 'decimal' }, |
|
3066
|
|
|
|
|
|
|
); |
|
3067
|
|
|
|
|
|
|
|
|
3068
|
|
|
|
|
|
|
# invalid style at the 25th page, should just continue |
|
3069
|
|
|
|
|
|
|
# with decimal at the current counter |
|
3070
|
|
|
|
|
|
|
$pdf->page_labels(25, |
|
3071
|
|
|
|
|
|
|
'style' => 'raman_noodles', # fail over to decimal |
|
3072
|
|
|
|
|
|
|
# note that older versions of PDF::API2 may see the 'r' and |
|
3073
|
|
|
|
|
|
|
# treat it as 'roman' |
|
3074
|
|
|
|
|
|
|
'start' => 25, # necessary, otherwise would restart at 1 |
|
3075
|
|
|
|
|
|
|
); |
|
3076
|
|
|
|
|
|
|
|
|
3077
|
|
|
|
|
|
|
# No page label at the 31st and 32nd pages. Note that this could be |
|
3078
|
|
|
|
|
|
|
# confusing to the person viewing the PDF, but may be appropriate if |
|
3079
|
|
|
|
|
|
|
# the page itself has no numbering. |
|
3080
|
|
|
|
|
|
|
$pdf->page_labels(31, |
|
3081
|
|
|
|
|
|
|
'style' => 'nocounter', |
|
3082
|
|
|
|
|
|
|
); |
|
3083
|
|
|
|
|
|
|
|
|
3084
|
|
|
|
|
|
|
# Numbering for Appendix A at the 33rd page, A-1, A-2,... |
|
3085
|
|
|
|
|
|
|
$pdf->page_labels(33, |
|
3086
|
|
|
|
|
|
|
'start' => 1, # unnecessary |
|
3087
|
|
|
|
|
|
|
'prefix' => 'A-' |
|
3088
|
|
|
|
|
|
|
); |
|
3089
|
|
|
|
|
|
|
|
|
3090
|
|
|
|
|
|
|
# Numbering for Appendix B at the 37th page, B-1, B-2,... |
|
3091
|
|
|
|
|
|
|
$pdf->page_labels(37, |
|
3092
|
|
|
|
|
|
|
'prefix' => 'B-' |
|
3093
|
|
|
|
|
|
|
); |
|
3094
|
|
|
|
|
|
|
|
|
3095
|
|
|
|
|
|
|
# Numbering for the Index at the 41st page, Index I, Index II,... |
|
3096
|
|
|
|
|
|
|
$pdf->page_labels(41, |
|
3097
|
|
|
|
|
|
|
'style' => 'Roman', |
|
3098
|
|
|
|
|
|
|
'start' => 1, # unnecessary |
|
3099
|
|
|
|
|
|
|
'prefix' => 'Index ' # note trailing space |
|
3100
|
|
|
|
|
|
|
); |
|
3101
|
|
|
|
|
|
|
|
|
3102
|
|
|
|
|
|
|
# Unnumbered 'Index' at the 45th page, Index, Index,... |
|
3103
|
|
|
|
|
|
|
$pdf->page_labels(45, |
|
3104
|
|
|
|
|
|
|
'style' => 'nocounter', |
|
3105
|
|
|
|
|
|
|
'prefix' => 'Index ' |
|
3106
|
|
|
|
|
|
|
); |
|
3107
|
|
|
|
|
|
|
|
|
3108
|
|
|
|
|
|
|
=over |
|
3109
|
|
|
|
|
|
|
|
|
3110
|
|
|
|
|
|
|
B<Alternate name:> C<pageLabel> |
|
3111
|
|
|
|
|
|
|
|
|
3112
|
|
|
|
|
|
|
This old method name is retained for compatibility with old user code. |
|
3113
|
|
|
|
|
|
|
Note that with C<pageLabel>, you need to make the "options" list an anonymous |
|
3114
|
|
|
|
|
|
|
hash by placing B<{ }> around the entire list, even if it has only one item |
|
3115
|
|
|
|
|
|
|
in it. Also remember that the page number (index) for C<pageLabel> starts at 0 |
|
3116
|
|
|
|
|
|
|
(same as the PDF page index), rather than 1 (as in C<page_labels>). |
|
3117
|
|
|
|
|
|
|
Finally, pageLabel() still permits you to define multiple page numbering schemes |
|
3118
|
|
|
|
|
|
|
in one call. |
|
3119
|
|
|
|
|
|
|
|
|
3120
|
|
|
|
|
|
|
=back |
|
3121
|
|
|
|
|
|
|
|
|
3122
|
|
|
|
|
|
|
=cut |
|
3123
|
|
|
|
|
|
|
|
|
3124
|
|
|
|
|
|
|
# in the new method, parameters are organized a bit differently than in the |
|
3125
|
|
|
|
|
|
|
# old pageLabel(). rather than an opts hashref, it is a hash. |
|
3126
|
|
|
|
|
|
|
sub page_labels { |
|
3127
|
0
|
|
|
0
|
1
|
0
|
my ($self, $page_number, %opts) = @_; |
|
3128
|
0
|
0
|
|
|
|
0
|
if ($page_number <= 0) { |
|
3129
|
0
|
|
|
|
|
0
|
carp "page_labels() start at 1, not 0. page changed to 1."; |
|
3130
|
0
|
|
|
|
|
0
|
$page_number = 1; |
|
3131
|
|
|
|
|
|
|
} |
|
3132
|
|
|
|
|
|
|
# check if opts is a hash? |
|
3133
|
0
|
0
|
|
|
|
0
|
if (ref(%opts) ne '') { |
|
3134
|
0
|
|
|
|
|
0
|
carp "page_labels() options must be a hash. Ignored."; |
|
3135
|
0
|
|
|
|
|
0
|
%opts = (); |
|
3136
|
|
|
|
|
|
|
} |
|
3137
|
0
|
|
|
|
|
0
|
return pageLabel($self, $page_number-1, \%opts); |
|
3138
|
|
|
|
|
|
|
} |
|
3139
|
|
|
|
|
|
|
|
|
3140
|
|
|
|
|
|
|
# actually, the old code |
|
3141
|
|
|
|
|
|
|
sub pageLabel { |
|
3142
|
8
|
|
|
8
|
1
|
128
|
my $self = shift(); |
|
3143
|
|
|
|
|
|
|
|
|
3144
|
8
|
|
33
|
|
|
82
|
$self->{'catalog'}->{'PageLabels'} ||= PDFDict(); |
|
3145
|
8
|
|
33
|
|
|
66
|
$self->{'catalog'}->{'PageLabels'}->{'Nums'} ||= PDFArray(); |
|
3146
|
|
|
|
|
|
|
|
|
3147
|
8
|
|
|
|
|
25
|
my $nums = $self->{'catalog'}->{'PageLabels'}->{'Nums'}; |
|
3148
|
8
|
|
|
|
|
39
|
while (scalar @_) { # should we have only one trip through here? |
|
3149
|
8
|
|
|
|
|
20
|
my $index = shift(); |
|
3150
|
8
|
50
|
|
|
|
35
|
if ($index < 0) { |
|
3151
|
0
|
|
|
|
|
0
|
carp "page labels start at 0. page changed to 0."; |
|
3152
|
0
|
|
|
|
|
0
|
$index = 0; |
|
3153
|
|
|
|
|
|
|
} |
|
3154
|
8
|
|
|
|
|
18
|
my $opts = shift(); |
|
3155
|
|
|
|
|
|
|
# check if opts is a hashref? |
|
3156
|
8
|
50
|
|
|
|
36
|
if (ref($opts) ne 'HASH') { |
|
3157
|
0
|
|
|
|
|
0
|
carp "pageLabels() options must be a hash ref. Ignored."; |
|
3158
|
0
|
|
|
|
|
0
|
$opts = {}; |
|
3159
|
|
|
|
|
|
|
} |
|
3160
|
|
|
|
|
|
|
# copy dashed options to preferred undashed option names |
|
3161
|
8
|
50
|
33
|
|
|
41
|
if (defined $opts->{'-style'} && !defined $opts->{'style'}) { $opts->{'style'} = delete($opts->{'-style'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
3162
|
8
|
50
|
33
|
|
|
48
|
if (defined $opts->{'-prefix'} && !defined $opts->{'prefix'}) { $opts->{'prefix'} = delete($opts->{'-prefix'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
3163
|
8
|
50
|
33
|
|
|
38
|
if (defined $opts->{'-start'} && !defined $opts->{'start'}) { $opts->{'start'} = delete($opts->{'-start'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
3164
|
|
|
|
|
|
|
|
|
3165
|
8
|
|
|
|
|
36
|
$nums->add_elements(PDFNum($index)); |
|
3166
|
|
|
|
|
|
|
|
|
3167
|
8
|
|
|
|
|
28
|
my $d = PDFDict(); |
|
3168
|
8
|
100
|
|
|
|
35
|
if (defined $opts->{'style'}) { |
|
3169
|
6
|
50
|
|
|
|
28
|
if ($opts->{'style'} ne 'nocounter') { |
|
3170
|
|
|
|
|
|
|
# defaults to decimal if unrecogized style given |
|
3171
|
|
|
|
|
|
|
$d->{'S'} = PDFName($opts->{'style'} eq 'Roman' ? 'R' : |
|
3172
|
|
|
|
|
|
|
$opts->{'style'} eq 'roman' ? 'r' : |
|
3173
|
|
|
|
|
|
|
$opts->{'style'} eq 'Alpha' ? 'A' : |
|
3174
|
|
|
|
|
|
|
$opts->{'style'} eq 'alpha' ? 'a' : |
|
3175
|
|
|
|
|
|
|
$opts->{'style'} eq 'arabic' ? 'D' : |
|
3176
|
6
|
50
|
|
|
|
168
|
$opts->{'style'} eq 'decimal' ? 'D' : 'D'); |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
3177
|
|
|
|
|
|
|
} else { |
|
3178
|
|
|
|
|
|
|
# for nocounter (no styled counter), do not create /S entry |
|
3179
|
|
|
|
|
|
|
} |
|
3180
|
|
|
|
|
|
|
} else { |
|
3181
|
|
|
|
|
|
|
# default to decimal counter if no style given |
|
3182
|
2
|
|
|
|
|
7
|
$d->{'S'} = PDFName('D'); |
|
3183
|
|
|
|
|
|
|
} |
|
3184
|
|
|
|
|
|
|
|
|
3185
|
8
|
100
|
|
|
|
44
|
if (defined $opts->{'prefix'}) { |
|
3186
|
|
|
|
|
|
|
# 'Content' supposedly treated differently |
|
3187
|
1
|
|
|
|
|
7
|
$d->{'P'} = PDFString($opts->{'prefix'}, 's'); |
|
3188
|
|
|
|
|
|
|
} |
|
3189
|
|
|
|
|
|
|
|
|
3190
|
8
|
100
|
|
|
|
36
|
if (defined $opts->{'start'}) { |
|
3191
|
1
|
|
|
|
|
5
|
$d->{'St'} = PDFNum($opts->{'start'}); |
|
3192
|
|
|
|
|
|
|
} else { |
|
3193
|
|
|
|
|
|
|
# some PDF Readers (e.g., Adobe Acrobat Reader) ignore a decimal |
|
3194
|
|
|
|
|
|
|
# label if no Start given, so default to 1 |
|
3195
|
7
|
|
|
|
|
23
|
$d->{'St'} = PDFNum(1); |
|
3196
|
|
|
|
|
|
|
} |
|
3197
|
|
|
|
|
|
|
|
|
3198
|
8
|
|
|
|
|
38
|
$nums->add_elements($d); |
|
3199
|
|
|
|
|
|
|
} |
|
3200
|
|
|
|
|
|
|
|
|
3201
|
8
|
|
|
|
|
32
|
return; |
|
3202
|
|
|
|
|
|
|
} # end of page_labels() |
|
3203
|
|
|
|
|
|
|
|
|
3204
|
|
|
|
|
|
|
# set global User Unit scale factor (default 1.0) |
|
3205
|
|
|
|
|
|
|
|
|
3206
|
|
|
|
|
|
|
=head2 userunit |
|
3207
|
|
|
|
|
|
|
|
|
3208
|
|
|
|
|
|
|
$pdf->userunit($value) |
|
3209
|
|
|
|
|
|
|
|
|
3210
|
|
|
|
|
|
|
=over |
|
3211
|
|
|
|
|
|
|
|
|
3212
|
|
|
|
|
|
|
Sets the global UserUnit, defining the scale factor to multiply any size or |
|
3213
|
|
|
|
|
|
|
coordinate by. For example, C<userunit(72)> results in a User Unit of 72 points, |
|
3214
|
|
|
|
|
|
|
or 1 inch. |
|
3215
|
|
|
|
|
|
|
|
|
3216
|
|
|
|
|
|
|
See L<PDF::Builder::Docs/User Units> for more information. |
|
3217
|
|
|
|
|
|
|
|
|
3218
|
|
|
|
|
|
|
=back |
|
3219
|
|
|
|
|
|
|
|
|
3220
|
|
|
|
|
|
|
=cut |
|
3221
|
|
|
|
|
|
|
|
|
3222
|
|
|
|
|
|
|
sub userunit { |
|
3223
|
0
|
|
|
0
|
1
|
0
|
my ($self, $value) = @_; |
|
3224
|
|
|
|
|
|
|
|
|
3225
|
0
|
0
|
|
|
|
0
|
if (float($value) <= 0.0) { |
|
3226
|
0
|
|
|
|
|
0
|
warn "Invalid User Unit value '$value', set to 1.0"; |
|
3227
|
0
|
|
|
|
|
0
|
$value = 1.0; |
|
3228
|
|
|
|
|
|
|
} |
|
3229
|
|
|
|
|
|
|
|
|
3230
|
0
|
|
|
|
|
0
|
$self->verCheckOutput(1.6, "set User Unit"); |
|
3231
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->{' userUnit'} = float($value); |
|
3232
|
0
|
|
|
|
|
0
|
$self->{'pages'}->{'UserUnit'} = PDFNum(float($value)); |
|
3233
|
0
|
0
|
|
|
|
0
|
if (defined $self->{'pages'}->{'MediaBox'}) { # should be default letter |
|
3234
|
0
|
0
|
|
|
|
0
|
if ($value != 1.0) { # divide points by User Unit |
|
3235
|
0
|
|
|
|
|
0
|
my @corners = ( 0, 0, 612/$value, 792/$value ); |
|
3236
|
0
|
|
|
|
|
0
|
$self->{'pages'}->{'MediaBox'} = PDFArray( map { PDFNum(float($_)) } @corners ); |
|
|
0
|
|
|
|
|
0
|
|
|
3237
|
|
|
|
|
|
|
} |
|
3238
|
|
|
|
|
|
|
} |
|
3239
|
|
|
|
|
|
|
|
|
3240
|
0
|
|
|
|
|
0
|
return $self; |
|
3241
|
|
|
|
|
|
|
} |
|
3242
|
|
|
|
|
|
|
|
|
3243
|
|
|
|
|
|
|
# utility to handle calling page_size, and name with or without 'orient' setting |
|
3244
|
|
|
|
|
|
|
sub _bbox { |
|
3245
|
252
|
|
|
252
|
|
694
|
my ($self, @corners) = @_; |
|
3246
|
|
|
|
|
|
|
|
|
3247
|
|
|
|
|
|
|
# if 1 or 3 elements in @corners, and [0] contains a letter, it's a name |
|
3248
|
252
|
|
|
|
|
608
|
my $isName = 0; |
|
3249
|
252
|
100
|
66
|
|
|
3283
|
if (scalar @corners && $corners[0] =~ m/[a-z]/i) { $isName = 1; } |
|
|
236
|
|
|
|
|
534
|
|
|
3250
|
|
|
|
|
|
|
|
|
3251
|
252
|
50
|
|
|
|
1514
|
if (scalar @corners == 3) { |
|
3252
|
|
|
|
|
|
|
# name plus one option (orient) |
|
3253
|
0
|
|
|
|
|
0
|
my ($name, %opts) = @corners; |
|
3254
|
|
|
|
|
|
|
# copy dashed name options to preferred undashed name |
|
3255
|
0
|
0
|
0
|
|
|
0
|
if (defined $opts{'-orient'} && !defined $opts{'orient'}) { $opts{'orient'} = delete($opts{'-orient'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
3256
|
|
|
|
|
|
|
|
|
3257
|
0
|
|
|
|
|
0
|
@corners = page_size(($name)); # now 4 numeric values |
|
3258
|
0
|
0
|
|
|
|
0
|
if (defined $opts{'orient'}) { |
|
3259
|
0
|
0
|
|
|
|
0
|
if ($opts{'orient'} =~ m/^l/i) { # 'landscape' or just 'l' |
|
3260
|
|
|
|
|
|
|
# 0 0 W H -> 0 0 H W |
|
3261
|
0
|
|
|
|
|
0
|
my $temp; |
|
3262
|
0
|
|
|
|
|
0
|
$temp = $corners[2]; $corners[2] = $corners[3]; $corners[3] = $temp; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
3263
|
|
|
|
|
|
|
} |
|
3264
|
|
|
|
|
|
|
} |
|
3265
|
|
|
|
|
|
|
} else { |
|
3266
|
|
|
|
|
|
|
# name without [orient] option, or numeric coordinates given |
|
3267
|
252
|
|
|
|
|
1406
|
@corners = page_size(@corners); |
|
3268
|
|
|
|
|
|
|
} |
|
3269
|
|
|
|
|
|
|
|
|
3270
|
252
|
|
|
|
|
830
|
my $UU = $self->{'pdf'}->{' userUnit'}; |
|
3271
|
|
|
|
|
|
|
# scale down size if User Unit given (e.g., Letter => 0 0 8.5 11) |
|
3272
|
252
|
50
|
66
|
|
|
1395
|
if ($isName && $UU != 1.0) { |
|
3273
|
0
|
|
|
|
|
0
|
for (my $i=0; $i<4; $i++) { |
|
3274
|
0
|
|
|
|
|
0
|
$corners[$i] /= $UU; |
|
3275
|
|
|
|
|
|
|
} |
|
3276
|
|
|
|
|
|
|
} |
|
3277
|
|
|
|
|
|
|
|
|
3278
|
252
|
|
|
|
|
792
|
return (@corners); |
|
3279
|
|
|
|
|
|
|
} # end of _bbox() |
|
3280
|
|
|
|
|
|
|
|
|
3281
|
|
|
|
|
|
|
# utility to get a bounding box by name |
|
3282
|
|
|
|
|
|
|
sub _get_bbox { |
|
3283
|
274
|
|
|
274
|
|
811
|
my ($self, $boxname) = @_; |
|
3284
|
|
|
|
|
|
|
|
|
3285
|
|
|
|
|
|
|
# if requested box not set, return next higher box's corners |
|
3286
|
|
|
|
|
|
|
# MediaBox should always at least have a default value |
|
3287
|
274
|
100
|
|
|
|
1173
|
if (not defined $self->{'pages'}->{$boxname}) { |
|
3288
|
8
|
100
|
100
|
|
|
57
|
if ($boxname eq 'CropBox') { |
|
|
|
50
|
66
|
|
|
|
|
|
3289
|
2
|
|
|
|
|
5
|
$boxname = 'MediaBox'; |
|
3290
|
|
|
|
|
|
|
} elsif ($boxname eq 'BleedBox' || |
|
3291
|
|
|
|
|
|
|
$boxname eq 'TrimBox' || |
|
3292
|
|
|
|
|
|
|
$boxname eq 'ArtBox' ) { |
|
3293
|
6
|
50
|
|
|
|
20
|
if (defined $self->{'pages'}->{'CropBox'}) { |
|
3294
|
0
|
|
|
|
|
0
|
$boxname = 'CropBox'; |
|
3295
|
|
|
|
|
|
|
} else { |
|
3296
|
6
|
|
|
|
|
14
|
$boxname = 'MediaBox'; |
|
3297
|
|
|
|
|
|
|
} |
|
3298
|
|
|
|
|
|
|
} else { |
|
3299
|
|
|
|
|
|
|
# invalid box name (silent error). just use MediaBox |
|
3300
|
0
|
|
|
|
|
0
|
$boxname = 'MediaBox'; |
|
3301
|
|
|
|
|
|
|
} |
|
3302
|
|
|
|
|
|
|
} |
|
3303
|
|
|
|
|
|
|
|
|
3304
|
|
|
|
|
|
|
# now $boxname is known to exist |
|
3305
|
274
|
|
|
|
|
1258
|
return map { $_->val() } $self->{'pages'}->{$boxname}->elements(); |
|
|
1096
|
|
|
|
|
2909
|
|
|
3306
|
|
|
|
|
|
|
|
|
3307
|
|
|
|
|
|
|
} # end of _get_bbox() |
|
3308
|
|
|
|
|
|
|
|
|
3309
|
|
|
|
|
|
|
=head2 mediabox |
|
3310
|
|
|
|
|
|
|
|
|
3311
|
|
|
|
|
|
|
$pdf->mediabox($name) |
|
3312
|
|
|
|
|
|
|
|
|
3313
|
|
|
|
|
|
|
$pdf->mediabox($name, 'orient' => 'orientation') |
|
3314
|
|
|
|
|
|
|
|
|
3315
|
|
|
|
|
|
|
$pdf->mediabox($w,$h) |
|
3316
|
|
|
|
|
|
|
|
|
3317
|
|
|
|
|
|
|
$pdf->mediabox($llx,$lly, $urx,$ury) |
|
3318
|
|
|
|
|
|
|
|
|
3319
|
|
|
|
|
|
|
($llx,$lly, $urx,$ury) = $pdf->mediabox() |
|
3320
|
|
|
|
|
|
|
|
|
3321
|
|
|
|
|
|
|
=over |
|
3322
|
|
|
|
|
|
|
|
|
3323
|
|
|
|
|
|
|
Sets (or gets) the global MediaBox, defining the width and height (or by |
|
3324
|
|
|
|
|
|
|
corner coordinates, or by standard name) of the output page itself, such as |
|
3325
|
|
|
|
|
|
|
the physical paper size. |
|
3326
|
|
|
|
|
|
|
|
|
3327
|
|
|
|
|
|
|
See L<PDF::Builder::Docs/Media Box> for more information. |
|
3328
|
|
|
|
|
|
|
The method always returns the current bounds (after any set operation). |
|
3329
|
|
|
|
|
|
|
|
|
3330
|
|
|
|
|
|
|
=back |
|
3331
|
|
|
|
|
|
|
|
|
3332
|
|
|
|
|
|
|
=cut |
|
3333
|
|
|
|
|
|
|
|
|
3334
|
|
|
|
|
|
|
sub mediabox { |
|
3335
|
246
|
|
|
246
|
1
|
909
|
my ($self, @corners) = @_; |
|
3336
|
246
|
100
|
|
|
|
802
|
if (defined $corners[0]) { |
|
3337
|
240
|
|
|
|
|
1182
|
@corners = $self->_bbox(@corners); |
|
3338
|
240
|
|
|
|
|
701
|
$self->{'pages'}->{'MediaBox'} = PDFArray( map { PDFNum(float($_)) } @corners ); |
|
|
960
|
|
|
|
|
3078
|
|
|
3339
|
|
|
|
|
|
|
} |
|
3340
|
|
|
|
|
|
|
|
|
3341
|
246
|
|
|
|
|
1105
|
return $self->_get_bbox('MediaBox'); |
|
3342
|
|
|
|
|
|
|
} |
|
3343
|
|
|
|
|
|
|
|
|
3344
|
|
|
|
|
|
|
=head2 cropbox |
|
3345
|
|
|
|
|
|
|
|
|
3346
|
|
|
|
|
|
|
$pdf->cropbox($name) |
|
3347
|
|
|
|
|
|
|
|
|
3348
|
|
|
|
|
|
|
$pdf->cropbox($name, 'orient' => 'orientation') |
|
3349
|
|
|
|
|
|
|
|
|
3350
|
|
|
|
|
|
|
$pdf->cropbox($w,$h) |
|
3351
|
|
|
|
|
|
|
|
|
3352
|
|
|
|
|
|
|
$pdf->cropbox($llx,$lly, $urx,$ury) |
|
3353
|
|
|
|
|
|
|
|
|
3354
|
|
|
|
|
|
|
($llx,$lly, $urx,$ury) = $pdf->cropbox() |
|
3355
|
|
|
|
|
|
|
|
|
3356
|
|
|
|
|
|
|
=over |
|
3357
|
|
|
|
|
|
|
|
|
3358
|
|
|
|
|
|
|
Sets (or gets) the global CropBox. This will define the media size to which |
|
3359
|
|
|
|
|
|
|
the output will later be clipped. |
|
3360
|
|
|
|
|
|
|
|
|
3361
|
|
|
|
|
|
|
See L<PDF::Builder::Docs/Crop Box> for more information. |
|
3362
|
|
|
|
|
|
|
The method always returns the current bounds (after any set operation). |
|
3363
|
|
|
|
|
|
|
|
|
3364
|
|
|
|
|
|
|
=back |
|
3365
|
|
|
|
|
|
|
|
|
3366
|
|
|
|
|
|
|
=cut |
|
3367
|
|
|
|
|
|
|
|
|
3368
|
|
|
|
|
|
|
sub cropbox { |
|
3369
|
7
|
|
|
7
|
1
|
5768
|
my ($self, @corners) = @_; |
|
3370
|
7
|
100
|
|
|
|
26
|
if (defined $corners[0]) { |
|
3371
|
3
|
|
|
|
|
15
|
@corners = $self->_bbox(@corners); |
|
3372
|
3
|
|
|
|
|
9
|
$self->{'pages'}->{'CropBox'} = PDFArray( map { PDFNum(float($_)) } @corners ); |
|
|
12
|
|
|
|
|
37
|
|
|
3373
|
|
|
|
|
|
|
} |
|
3374
|
|
|
|
|
|
|
|
|
3375
|
7
|
|
|
|
|
25
|
return $self->_get_bbox('CropBox'); |
|
3376
|
|
|
|
|
|
|
} |
|
3377
|
|
|
|
|
|
|
|
|
3378
|
|
|
|
|
|
|
=head2 bleedbox |
|
3379
|
|
|
|
|
|
|
|
|
3380
|
|
|
|
|
|
|
$pdf->bleedbox($name) |
|
3381
|
|
|
|
|
|
|
|
|
3382
|
|
|
|
|
|
|
$pdf->bleedbox($name, 'orient' => 'orientation') |
|
3383
|
|
|
|
|
|
|
|
|
3384
|
|
|
|
|
|
|
$pdf->bleedbox($w,$h) |
|
3385
|
|
|
|
|
|
|
|
|
3386
|
|
|
|
|
|
|
$pdf->bleedbox($llx,$lly, $urx,$ury) |
|
3387
|
|
|
|
|
|
|
|
|
3388
|
|
|
|
|
|
|
($llx,$lly, $urx,$ury) = $pdf->bleedbox() |
|
3389
|
|
|
|
|
|
|
|
|
3390
|
|
|
|
|
|
|
=over |
|
3391
|
|
|
|
|
|
|
|
|
3392
|
|
|
|
|
|
|
Sets (or gets) the global BleedBox. This is typically used for hard copy |
|
3393
|
|
|
|
|
|
|
printing where you want ink to go to the edge of the cut paper. |
|
3394
|
|
|
|
|
|
|
|
|
3395
|
|
|
|
|
|
|
See L<PDF::Builder::Docs/Bleed Box> for more information. |
|
3396
|
|
|
|
|
|
|
The method always returns the current bounds (after any set operation). |
|
3397
|
|
|
|
|
|
|
|
|
3398
|
|
|
|
|
|
|
=back |
|
3399
|
|
|
|
|
|
|
|
|
3400
|
|
|
|
|
|
|
=cut |
|
3401
|
|
|
|
|
|
|
|
|
3402
|
|
|
|
|
|
|
sub bleedbox { |
|
3403
|
7
|
|
|
7
|
1
|
5402
|
my ($self, @corners) = @_; |
|
3404
|
7
|
100
|
|
|
|
62
|
if (defined $corners[0]) { |
|
3405
|
3
|
|
|
|
|
65
|
@corners = $self->_bbox(@corners); |
|
3406
|
3
|
|
|
|
|
11
|
$self->{'pages'}->{'BleedBox'} = PDFArray( map { PDFNum(float($_)) } @corners ); |
|
|
12
|
|
|
|
|
54
|
|
|
3407
|
|
|
|
|
|
|
} |
|
3408
|
|
|
|
|
|
|
|
|
3409
|
7
|
|
|
|
|
27
|
return $self->_get_bbox('BleedBox'); |
|
3410
|
|
|
|
|
|
|
} |
|
3411
|
|
|
|
|
|
|
|
|
3412
|
|
|
|
|
|
|
=head2 trimbox |
|
3413
|
|
|
|
|
|
|
|
|
3414
|
|
|
|
|
|
|
$pdf->trimbox($name) |
|
3415
|
|
|
|
|
|
|
|
|
3416
|
|
|
|
|
|
|
$pdf->trimbox($name, 'orient' => 'orientation') |
|
3417
|
|
|
|
|
|
|
|
|
3418
|
|
|
|
|
|
|
$pdf->trimbox($w,$h) |
|
3419
|
|
|
|
|
|
|
|
|
3420
|
|
|
|
|
|
|
$pdf->trimbox($llx,$lly, $urx,$ury) |
|
3421
|
|
|
|
|
|
|
|
|
3422
|
|
|
|
|
|
|
($llx,$lly, $urx,$ury) = $pdf->trimbox() |
|
3423
|
|
|
|
|
|
|
|
|
3424
|
|
|
|
|
|
|
=over |
|
3425
|
|
|
|
|
|
|
|
|
3426
|
|
|
|
|
|
|
Sets (or gets) the global TrimBox. This is supposed to be the actual |
|
3427
|
|
|
|
|
|
|
dimensions of the finished page (after trimming of the paper). |
|
3428
|
|
|
|
|
|
|
|
|
3429
|
|
|
|
|
|
|
See L<PDF::Builder::Docs/Trim Box> for more information. |
|
3430
|
|
|
|
|
|
|
The method always returns the current bounds (after any set operation). |
|
3431
|
|
|
|
|
|
|
|
|
3432
|
|
|
|
|
|
|
=back |
|
3433
|
|
|
|
|
|
|
|
|
3434
|
|
|
|
|
|
|
=cut |
|
3435
|
|
|
|
|
|
|
|
|
3436
|
|
|
|
|
|
|
sub trimbox { |
|
3437
|
7
|
|
|
7
|
1
|
4762
|
my ($self, @corners) = @_; |
|
3438
|
7
|
100
|
|
|
|
26
|
if (defined $corners[0]) { |
|
3439
|
3
|
|
|
|
|
13
|
@corners = $self->_bbox(@corners); |
|
3440
|
3
|
|
|
|
|
11
|
$self->{'pages'}->{'TrimBox'} = PDFArray( map { PDFNum(float($_)) } @corners ); |
|
|
12
|
|
|
|
|
33
|
|
|
3441
|
|
|
|
|
|
|
} |
|
3442
|
|
|
|
|
|
|
|
|
3443
|
7
|
|
|
|
|
27
|
return $self->_get_bbox('TrimBox'); |
|
3444
|
|
|
|
|
|
|
} |
|
3445
|
|
|
|
|
|
|
|
|
3446
|
|
|
|
|
|
|
=head2 artbox |
|
3447
|
|
|
|
|
|
|
|
|
3448
|
|
|
|
|
|
|
$pdf->artbox($name) |
|
3449
|
|
|
|
|
|
|
|
|
3450
|
|
|
|
|
|
|
$pdf->artbox($name, 'orient' => 'orientation') |
|
3451
|
|
|
|
|
|
|
|
|
3452
|
|
|
|
|
|
|
$pdf->artbox($w,$h) |
|
3453
|
|
|
|
|
|
|
|
|
3454
|
|
|
|
|
|
|
$pdf->artbox($llx,$lly, $urx,$ury) |
|
3455
|
|
|
|
|
|
|
|
|
3456
|
|
|
|
|
|
|
($llx,$lly, $urx,$ury) = $pdf->artbox() |
|
3457
|
|
|
|
|
|
|
|
|
3458
|
|
|
|
|
|
|
=over |
|
3459
|
|
|
|
|
|
|
|
|
3460
|
|
|
|
|
|
|
Sets (or gets) the global ArtBox. This is supposed to define "the extent of |
|
3461
|
|
|
|
|
|
|
the page's I<meaningful> content". What is considered "meaningful" is up to |
|
3462
|
|
|
|
|
|
|
the author of the page, but would usually exclude "decorative" graphics and |
|
3463
|
|
|
|
|
|
|
such; and possibly titles, headers, footers, and page numbers. |
|
3464
|
|
|
|
|
|
|
|
|
3465
|
|
|
|
|
|
|
See L<PDF::Builder::Docs/Art Box> for more information. |
|
3466
|
|
|
|
|
|
|
The method always returns the current bounds (after any set operation). |
|
3467
|
|
|
|
|
|
|
|
|
3468
|
|
|
|
|
|
|
=back |
|
3469
|
|
|
|
|
|
|
|
|
3470
|
|
|
|
|
|
|
=cut |
|
3471
|
|
|
|
|
|
|
|
|
3472
|
|
|
|
|
|
|
sub artbox { |
|
3473
|
7
|
|
|
7
|
1
|
5388
|
my ($self, @corners) = @_; |
|
3474
|
7
|
100
|
|
|
|
25
|
if (defined $corners[0]) { |
|
3475
|
3
|
|
|
|
|
16
|
@corners = $self->_bbox(@corners); |
|
3476
|
3
|
|
|
|
|
9
|
$self->{'pages'}->{'ArtBox'} = PDFArray( map { PDFNum(float($_)) } @corners ); |
|
|
12
|
|
|
|
|
32
|
|
|
3477
|
|
|
|
|
|
|
} |
|
3478
|
|
|
|
|
|
|
|
|
3479
|
7
|
|
|
|
|
28
|
return $self->_get_bbox('ArtBox'); |
|
3480
|
|
|
|
|
|
|
} |
|
3481
|
|
|
|
|
|
|
|
|
3482
|
|
|
|
|
|
|
=head1 FONT METHODS |
|
3483
|
|
|
|
|
|
|
|
|
3484
|
|
|
|
|
|
|
=head2 Embedding of Fonts |
|
3485
|
|
|
|
|
|
|
|
|
3486
|
|
|
|
|
|
|
B<CAUTION:> Some font routines (currently only C<ttfont()>) automatically embed |
|
3487
|
|
|
|
|
|
|
font definitions for the purpose of improving portability of PDF files. Note |
|
3488
|
|
|
|
|
|
|
that font copyright and licensing terms vary by font provider, and some may |
|
3489
|
|
|
|
|
|
|
prohibit embedding of their fonts, either entirely, or allowing only the subset |
|
3490
|
|
|
|
|
|
|
of glyphs actually used in the document. You should be aware of the terms, and |
|
3491
|
|
|
|
|
|
|
use the C<embed> and C<nosubset> flags as appropriate. The PDF::Builder font |
|
3492
|
|
|
|
|
|
|
routines currently have no means to automatically detect any embedding |
|
3493
|
|
|
|
|
|
|
limitations for a given font, and cannot default their behavior accordingly! |
|
3494
|
|
|
|
|
|
|
|
|
3495
|
|
|
|
|
|
|
=head2 Font-related Methods |
|
3496
|
|
|
|
|
|
|
|
|
3497
|
|
|
|
|
|
|
=head3 corefont |
|
3498
|
|
|
|
|
|
|
|
|
3499
|
|
|
|
|
|
|
$font = $pdf->corefont($fontname, %opts) |
|
3500
|
|
|
|
|
|
|
|
|
3501
|
|
|
|
|
|
|
=over |
|
3502
|
|
|
|
|
|
|
|
|
3503
|
|
|
|
|
|
|
Returns a new Adobe core font object. For details, |
|
3504
|
|
|
|
|
|
|
including supported C<%opts>, |
|
3505
|
|
|
|
|
|
|
see L<PDF::Builder::Resource::Font::CoreFont>. |
|
3506
|
|
|
|
|
|
|
Note that this is an Adobe-standard corefont I<name>, and not a file name. |
|
3507
|
|
|
|
|
|
|
|
|
3508
|
|
|
|
|
|
|
See also L<PDF::Builder::Docs/Core Fonts> for additional information, |
|
3509
|
|
|
|
|
|
|
including Notes and Limitations. |
|
3510
|
|
|
|
|
|
|
|
|
3511
|
|
|
|
|
|
|
=back |
|
3512
|
|
|
|
|
|
|
|
|
3513
|
|
|
|
|
|
|
=cut |
|
3514
|
|
|
|
|
|
|
|
|
3515
|
|
|
|
|
|
|
sub corefont { |
|
3516
|
37
|
|
|
37
|
1
|
9496
|
my ($self, $name, %opts) = @_; |
|
3517
|
|
|
|
|
|
|
# copy dashed name options to preferred undashed format |
|
3518
|
37
|
50
|
33
|
|
|
202
|
if (defined $opts{'-unicodemap'} && !defined $opts{'unicodemap'}) { $opts{'unicodemap'} = delete($opts{'-unicodemap'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
3519
|
|
|
|
|
|
|
|
|
3520
|
37
|
|
|
|
|
6112
|
require PDF::Builder::Resource::Font::CoreFont; |
|
3521
|
37
|
50
|
|
|
|
427
|
if (!PDF::Builder::Resource::Font::CoreFont->is_standard($name)) { |
|
3522
|
0
|
0
|
|
|
|
0
|
if ($name =~ /^Times$/i) { |
|
3523
|
|
|
|
|
|
|
# Accept Times as an alias for Times-Roman to follow the pattern |
|
3524
|
|
|
|
|
|
|
# set by Courier and Helvetica |
|
3525
|
0
|
0
|
|
|
|
0
|
if (!$MSG_COUNT[3]) { |
|
3526
|
|
|
|
|
|
|
# one message (per run) reminding user |
|
3527
|
0
|
|
|
|
|
0
|
carp "Times is not a standard font; substituting Times-Roman"; |
|
3528
|
0
|
|
|
|
|
0
|
$MSG_COUNT[3]++; |
|
3529
|
|
|
|
|
|
|
} |
|
3530
|
0
|
|
|
|
|
0
|
$name = 'Times-Roman'; |
|
3531
|
|
|
|
|
|
|
} |
|
3532
|
|
|
|
|
|
|
} |
|
3533
|
37
|
|
|
|
|
234
|
my $obj = PDF::Builder::Resource::Font::CoreFont->new($self->{'pdf'}, $name, %opts); |
|
3534
|
37
|
|
|
|
|
486
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
3535
|
37
|
50
|
|
|
|
160
|
$obj->tounicodemap() if $opts{'unicodemap'}; # UTF-8 not usable |
|
3536
|
|
|
|
|
|
|
|
|
3537
|
37
|
|
|
|
|
382
|
return $obj; |
|
3538
|
|
|
|
|
|
|
} |
|
3539
|
|
|
|
|
|
|
|
|
3540
|
|
|
|
|
|
|
=head3 psfont |
|
3541
|
|
|
|
|
|
|
|
|
3542
|
|
|
|
|
|
|
$font = $pdf->psfont($ps_file, %opts) |
|
3543
|
|
|
|
|
|
|
|
|
3544
|
|
|
|
|
|
|
=over |
|
3545
|
|
|
|
|
|
|
|
|
3546
|
|
|
|
|
|
|
Returns a new Adobe Type1 ("PostScript", "T1") font object. For details, |
|
3547
|
|
|
|
|
|
|
including supported C<%opts>, see L<PDF::Builder::Resource::Font::Postscript>. |
|
3548
|
|
|
|
|
|
|
|
|
3549
|
|
|
|
|
|
|
See also L<PDF::Builder::Docs/PS Fonts> for additional information, |
|
3550
|
|
|
|
|
|
|
including Notes and Limitations. |
|
3551
|
|
|
|
|
|
|
|
|
3552
|
|
|
|
|
|
|
=back |
|
3553
|
|
|
|
|
|
|
|
|
3554
|
|
|
|
|
|
|
=cut |
|
3555
|
|
|
|
|
|
|
|
|
3556
|
|
|
|
|
|
|
sub psfont { |
|
3557
|
0
|
|
|
0
|
1
|
0
|
my ($self, $psf, %opts) = @_; |
|
3558
|
|
|
|
|
|
|
# copy dashed name options to preferred undashed format |
|
3559
|
0
|
0
|
0
|
|
|
0
|
if (defined $opts{'-afmfile'} && !defined $opts{'afmfile'}) { $opts{'afmfile'} = delete($opts{'-afmfile'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
3560
|
0
|
0
|
0
|
|
|
0
|
if (defined $opts{'-afm_file'} && !defined $opts{'afm_file'}) { $opts{'afm_file'} = delete($opts{'-afm_file'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
3561
|
0
|
0
|
0
|
|
|
0
|
if (defined $opts{'-pfmfile'} && !defined $opts{'pfmfile'}) { $opts{'pfmfile'} = delete($opts{'-pfmfile'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
3562
|
0
|
0
|
0
|
|
|
0
|
if (defined $opts{'-pfm_file'} && !defined $opts{'pfm_file'}) { $opts{'pfm_file'} = delete($opts{'-pfm_file'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
3563
|
0
|
0
|
0
|
|
|
0
|
if (defined $opts{'-unicodemap'} && !defined $opts{'unicodemap'}) { $opts{'unicodemap'} = delete($opts{'-unicodemap'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
3564
|
|
|
|
|
|
|
|
|
3565
|
|
|
|
|
|
|
# preferred option names |
|
3566
|
0
|
0
|
|
|
|
0
|
if (defined $opts{'afm_file'}) { $opts{'afmfile'} = delete($opts{'afm_file'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
3567
|
0
|
0
|
|
|
|
0
|
if (defined $opts{'pfm_file'}) { $opts{'pfmfile'} = delete($opts{'pfm_file'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
3568
|
|
|
|
|
|
|
|
|
3569
|
0
|
|
|
|
|
0
|
foreach my $o (qw(afmfile pfmfile)) { |
|
3570
|
0
|
0
|
|
|
|
0
|
next unless defined $opts{$o}; |
|
3571
|
0
|
|
|
|
|
0
|
$opts{$o} = _findFont($opts{$o}); |
|
3572
|
|
|
|
|
|
|
} |
|
3573
|
0
|
|
|
|
|
0
|
$psf = _findFont($psf); |
|
3574
|
0
|
|
|
|
|
0
|
require PDF::Builder::Resource::Font::Postscript; |
|
3575
|
0
|
|
|
|
|
0
|
my $obj = PDF::Builder::Resource::Font::Postscript->new($self->{'pdf'}, $psf, %opts); |
|
3576
|
|
|
|
|
|
|
|
|
3577
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
3578
|
0
|
0
|
|
|
|
0
|
$obj->tounicodemap() if $opts{'unicodemap'}; # UTF-8 not usable |
|
3579
|
|
|
|
|
|
|
|
|
3580
|
0
|
|
|
|
|
0
|
return $obj; |
|
3581
|
|
|
|
|
|
|
} |
|
3582
|
|
|
|
|
|
|
|
|
3583
|
|
|
|
|
|
|
=head3 ttfont |
|
3584
|
|
|
|
|
|
|
|
|
3585
|
|
|
|
|
|
|
$font = $pdf->ttfont($ttf_file, %opts) |
|
3586
|
|
|
|
|
|
|
|
|
3587
|
|
|
|
|
|
|
=over |
|
3588
|
|
|
|
|
|
|
|
|
3589
|
|
|
|
|
|
|
Returns a new TrueType (or OpenType) font object. |
|
3590
|
|
|
|
|
|
|
For details, including supported C<%opts>, |
|
3591
|
|
|
|
|
|
|
see L<PDF::Builder::Resource::CIDFont::TrueType>. |
|
3592
|
|
|
|
|
|
|
|
|
3593
|
|
|
|
|
|
|
See also L<PDF::Builder::Docs/TrueType Fonts> for additional information, |
|
3594
|
|
|
|
|
|
|
including Notes and Limitations. |
|
3595
|
|
|
|
|
|
|
|
|
3596
|
|
|
|
|
|
|
=back |
|
3597
|
|
|
|
|
|
|
|
|
3598
|
|
|
|
|
|
|
=cut |
|
3599
|
|
|
|
|
|
|
|
|
3600
|
|
|
|
|
|
|
sub ttfont { |
|
3601
|
0
|
|
|
0
|
1
|
0
|
my ($self, $file, %opts) = @_; |
|
3602
|
|
|
|
|
|
|
# copy dashed name options to preferred undashed format |
|
3603
|
0
|
0
|
0
|
|
|
0
|
if (defined $opts{'-unicodemap'} && !defined $opts{'unicodemap'}) { $opts{'unicodemap'} = delete($opts{'-unicodemap'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
3604
|
|
|
|
|
|
|
|
|
3605
|
|
|
|
|
|
|
# noembed deprecated in API2, some may be using embed in code |
|
3606
|
0
|
0
|
0
|
|
|
0
|
if (defined $opts{'-noembed'} && !defined $opts{'noembed'}) { $opts{'noembed'} = delete($opts{'-noembed'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
3607
|
0
|
0
|
0
|
|
|
0
|
if (defined $opts{'-embed'} && !defined $opts{'embed'}) { $opts{'embed'} = delete($opts{'-embed'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
3608
|
|
|
|
|
|
|
|
|
3609
|
|
|
|
|
|
|
# PDF::Builder doesn't set BaseEncoding for TrueType fonts, so text |
|
3610
|
|
|
|
|
|
|
# isn't searchable unless a ToUnicode CMap is included. Include |
|
3611
|
|
|
|
|
|
|
# the ToUnicode CMap by default, but allow it to be disabled (for |
|
3612
|
|
|
|
|
|
|
# performance and file size reasons) by setting 'unicodemap' to 0. |
|
3613
|
0
|
0
|
|
|
|
0
|
$opts{'unicodemap'} = 1 unless exists $opts{'unicodemap'}; |
|
3614
|
|
|
|
|
|
|
# if BOTH embed and noembed given, use embed |
|
3615
|
0
|
0
|
0
|
|
|
0
|
if (defined $opts{'noembed'} && !defined $opts{'embed'}) { |
|
3616
|
0
|
|
|
|
|
0
|
$opts{'embed'} = !$opts{'noembed'}; |
|
3617
|
|
|
|
|
|
|
} |
|
3618
|
0
|
|
0
|
|
|
0
|
$opts{'embed'} //= 1; |
|
3619
|
|
|
|
|
|
|
|
|
3620
|
0
|
0
|
|
|
|
0
|
$file = UNIVERSAL::isa($file, 'Font::TTF::Font')? $file: |
|
|
|
0
|
|
|
|
|
|
|
3621
|
|
|
|
|
|
|
_findFont($file) or croak "Unable to find font \"$file\""; |
|
3622
|
0
|
|
|
|
|
0
|
require PDF::Builder::Resource::CIDFont::TrueType; |
|
3623
|
0
|
|
|
|
|
0
|
my $obj = PDF::Builder::Resource::CIDFont::TrueType->new($self->{'pdf'}, $file, %opts); |
|
3624
|
|
|
|
|
|
|
|
|
3625
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
3626
|
0
|
0
|
|
|
|
0
|
$obj->tounicodemap() if $opts{'unicodemap'}; |
|
3627
|
|
|
|
|
|
|
|
|
3628
|
0
|
|
|
|
|
0
|
return $obj; |
|
3629
|
|
|
|
|
|
|
} |
|
3630
|
|
|
|
|
|
|
|
|
3631
|
|
|
|
|
|
|
=head3 bdfont |
|
3632
|
|
|
|
|
|
|
|
|
3633
|
|
|
|
|
|
|
$font = $pdf->bdfont($bdf_file, @opts) |
|
3634
|
|
|
|
|
|
|
|
|
3635
|
|
|
|
|
|
|
=over |
|
3636
|
|
|
|
|
|
|
|
|
3637
|
|
|
|
|
|
|
Returns a new BDF (bitmapped distribution format) font object, based on the |
|
3638
|
|
|
|
|
|
|
specified Adobe BDF file. These are very low resolution fonts that appear to |
|
3639
|
|
|
|
|
|
|
have come off a dot-matrix printer, and should only be used for decorative |
|
3640
|
|
|
|
|
|
|
or novelty purposes. |
|
3641
|
|
|
|
|
|
|
|
|
3642
|
|
|
|
|
|
|
See also L<PDF::Builder::Resource::Font::BdFont> |
|
3643
|
|
|
|
|
|
|
|
|
3644
|
|
|
|
|
|
|
=back |
|
3645
|
|
|
|
|
|
|
|
|
3646
|
|
|
|
|
|
|
=cut |
|
3647
|
|
|
|
|
|
|
|
|
3648
|
|
|
|
|
|
|
sub bdfont { |
|
3649
|
0
|
|
|
0
|
1
|
0
|
my ($self, $bdf_file, @opts) = @_; |
|
3650
|
|
|
|
|
|
|
|
|
3651
|
0
|
|
|
|
|
0
|
require PDF::Builder::Resource::Font::BdFont; |
|
3652
|
0
|
|
|
|
|
0
|
my $obj = PDF::Builder::Resource::Font::BdFont->new($self->{'pdf'}, $bdf_file, @opts); |
|
3653
|
|
|
|
|
|
|
|
|
3654
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
3655
|
|
|
|
|
|
|
# $obj->tounicodemap(); # does not support Unicode! |
|
3656
|
|
|
|
|
|
|
|
|
3657
|
0
|
|
|
|
|
0
|
return $obj; |
|
3658
|
|
|
|
|
|
|
} |
|
3659
|
|
|
|
|
|
|
|
|
3660
|
|
|
|
|
|
|
=head3 cjkfont |
|
3661
|
|
|
|
|
|
|
|
|
3662
|
|
|
|
|
|
|
$font = $pdf->cjkfont($cjkname, %opts) |
|
3663
|
|
|
|
|
|
|
|
|
3664
|
|
|
|
|
|
|
=over |
|
3665
|
|
|
|
|
|
|
|
|
3666
|
|
|
|
|
|
|
Returns a new CJK font object. These are TrueType-like fonts for East Asian |
|
3667
|
|
|
|
|
|
|
languages (Chinese, Japanese, Korean). |
|
3668
|
|
|
|
|
|
|
For details, including supported C<%opts>, see L<PDF::Builder::Resource::CIDFont::CJKFont>, |
|
3669
|
|
|
|
|
|
|
as well as L<PDF::Builder::Docs/CJK Fonts>. |
|
3670
|
|
|
|
|
|
|
|
|
3671
|
|
|
|
|
|
|
B<NOTE:> C<cjkfont> is quite old and is not well supported. We recommend that |
|
3672
|
|
|
|
|
|
|
you try using C<ttfont> (or another font routine, if not TTF/OTF) with the |
|
3673
|
|
|
|
|
|
|
appropriate CJK font file. Most appear to be .ttf or .otf format. PDFs created |
|
3674
|
|
|
|
|
|
|
using C<cjkfont> may not be fully portable, and support for |
|
3675
|
|
|
|
|
|
|
C<cjkfont> I<may> be dropped in a future release. We would appreciate hearing |
|
3676
|
|
|
|
|
|
|
from you if you are successfully using C<cjkfont>, and are unable to use |
|
3677
|
|
|
|
|
|
|
C<ttfont> instead. |
|
3678
|
|
|
|
|
|
|
|
|
3679
|
|
|
|
|
|
|
Among other things, C<cjkfont> selections are limited, as they require CMAP |
|
3680
|
|
|
|
|
|
|
files; they may or may not subset correctly; and they can not be used as the |
|
3681
|
|
|
|
|
|
|
base for synthetic fonts. |
|
3682
|
|
|
|
|
|
|
|
|
3683
|
|
|
|
|
|
|
=back |
|
3684
|
|
|
|
|
|
|
|
|
3685
|
|
|
|
|
|
|
=cut |
|
3686
|
|
|
|
|
|
|
|
|
3687
|
|
|
|
|
|
|
sub cjkfont { |
|
3688
|
1
|
|
|
1
|
1
|
10
|
my ($self, $name, %opts) = @_; |
|
3689
|
|
|
|
|
|
|
# copy dashed name options to preferred undashed format |
|
3690
|
1
|
50
|
33
|
|
|
6
|
if (defined $opts{'-unicodemap'} && !defined $opts{'unicodemap'}) { $opts{'unicodemap'} = delete($opts{'-unicodemap'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
3691
|
|
|
|
|
|
|
|
|
3692
|
1
|
|
|
|
|
823
|
require PDF::Builder::Resource::CIDFont::CJKFont; |
|
3693
|
1
|
|
|
|
|
16
|
my $obj = PDF::Builder::Resource::CIDFont::CJKFont->new($self->{'pdf'}, $name, %opts); |
|
3694
|
|
|
|
|
|
|
|
|
3695
|
1
|
|
|
|
|
6
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
3696
|
1
|
50
|
|
|
|
4
|
$obj->tounicodemap() if $opts{'unicodemap'}; |
|
3697
|
|
|
|
|
|
|
|
|
3698
|
1
|
|
|
|
|
4
|
return $obj; |
|
3699
|
|
|
|
|
|
|
} |
|
3700
|
|
|
|
|
|
|
|
|
3701
|
|
|
|
|
|
|
=head3 font |
|
3702
|
|
|
|
|
|
|
|
|
3703
|
|
|
|
|
|
|
$font = $pdf->font($name, %opts) |
|
3704
|
|
|
|
|
|
|
|
|
3705
|
|
|
|
|
|
|
=over |
|
3706
|
|
|
|
|
|
|
|
|
3707
|
|
|
|
|
|
|
A convenience function to add a font to the PDF without having to specify the |
|
3708
|
|
|
|
|
|
|
format. Returns the font object, to be used by L<PDF::Builder::Content>. |
|
3709
|
|
|
|
|
|
|
|
|
3710
|
|
|
|
|
|
|
The font C<$name> is either the name of one of the standard 14 fonts |
|
3711
|
|
|
|
|
|
|
(L<PDF::Builder::Resource::Font::CoreFont/STANDARD FONTS>), such as |
|
3712
|
|
|
|
|
|
|
C<Helvetica>, a C<Font::TTF::Font> object, or the path to a font file |
|
3713
|
|
|
|
|
|
|
(including an extension/filetype). |
|
3714
|
|
|
|
|
|
|
There are 15 additional core fonts on a Windows system. |
|
3715
|
|
|
|
|
|
|
Note that the exact name of a core font needs to be given. |
|
3716
|
|
|
|
|
|
|
The file extension (if path given) determines what type of font file it is. |
|
3717
|
|
|
|
|
|
|
|
|
3718
|
|
|
|
|
|
|
=back |
|
3719
|
|
|
|
|
|
|
|
|
3720
|
|
|
|
|
|
|
my $pdf = PDF::Builder->new(); |
|
3721
|
|
|
|
|
|
|
my $font1 = $pdf->font('Helvetica-Bold'); |
|
3722
|
|
|
|
|
|
|
my $font2 = $pdf->font('/path/to/ComicSans.ttf'); |
|
3723
|
|
|
|
|
|
|
my $page = $pdf->page(); |
|
3724
|
|
|
|
|
|
|
my $content = $page->text(); |
|
3725
|
|
|
|
|
|
|
|
|
3726
|
|
|
|
|
|
|
$content->position(1 * 72, 9 * 72); |
|
3727
|
|
|
|
|
|
|
$content->font($font1, 24); |
|
3728
|
|
|
|
|
|
|
$content->text('Hello, World!'); |
|
3729
|
|
|
|
|
|
|
|
|
3730
|
|
|
|
|
|
|
$content->position(0, -36); |
|
3731
|
|
|
|
|
|
|
$content->font($font2, 12); |
|
3732
|
|
|
|
|
|
|
$content->text('This is some sample text.'); |
|
3733
|
|
|
|
|
|
|
|
|
3734
|
|
|
|
|
|
|
$pdf->saveas('sample.pdf'); |
|
3735
|
|
|
|
|
|
|
|
|
3736
|
|
|
|
|
|
|
=over |
|
3737
|
|
|
|
|
|
|
|
|
3738
|
|
|
|
|
|
|
The path can be omitted if the font file is in the current directory or one of |
|
3739
|
|
|
|
|
|
|
the directories returned by C<font_path>. |
|
3740
|
|
|
|
|
|
|
|
|
3741
|
|
|
|
|
|
|
Core, TrueType (ttf/otf), Adobe PostScript Type 1 (pfa/pfb/t1), and Adobe Glyph |
|
3742
|
|
|
|
|
|
|
Bitmap Distribution Format (bdf) fonts are supported. |
|
3743
|
|
|
|
|
|
|
|
|
3744
|
|
|
|
|
|
|
=back |
|
3745
|
|
|
|
|
|
|
|
|
3746
|
|
|
|
|
|
|
The following options (C<%opts>) are available: |
|
3747
|
|
|
|
|
|
|
|
|
3748
|
|
|
|
|
|
|
=over |
|
3749
|
|
|
|
|
|
|
|
|
3750
|
|
|
|
|
|
|
=item format |
|
3751
|
|
|
|
|
|
|
|
|
3752
|
|
|
|
|
|
|
The font format is normally detected automatically based on the file's |
|
3753
|
|
|
|
|
|
|
extension (if one is given, as in non-core fonts). If you're using a font with |
|
3754
|
|
|
|
|
|
|
an atypical extension, you can set |
|
3755
|
|
|
|
|
|
|
C<format> to one of C<truetype> (TrueType or OpenType), C<type1> (PostScript |
|
3756
|
|
|
|
|
|
|
Type 1), or C<bitmap> (Adobe Bitmap). There is no C<format> entry for Core |
|
3757
|
|
|
|
|
|
|
fonts, as the name must be an exact match. |
|
3758
|
|
|
|
|
|
|
|
|
3759
|
|
|
|
|
|
|
=item (other options) |
|
3760
|
|
|
|
|
|
|
|
|
3761
|
|
|
|
|
|
|
The C<%opts> entries are passed on to the appropriate font format routine |
|
3762
|
|
|
|
|
|
|
(C<corefont()>, C<ttfont()>, etc.), so they can be used here. These include |
|
3763
|
|
|
|
|
|
|
'encode', 'pdfname', 'pfmfile', 'dokern', etc. See the appropriate font routine |
|
3764
|
|
|
|
|
|
|
for a full list of the supported options. |
|
3765
|
|
|
|
|
|
|
|
|
3766
|
|
|
|
|
|
|
=back |
|
3767
|
|
|
|
|
|
|
|
|
3768
|
|
|
|
|
|
|
=cut |
|
3769
|
|
|
|
|
|
|
|
|
3770
|
|
|
|
|
|
|
sub font { |
|
3771
|
0
|
|
|
0
|
1
|
0
|
my ($self, $name, %opts) = @_; |
|
3772
|
|
|
|
|
|
|
# copy dashed name options to preferred undashed format |
|
3773
|
0
|
0
|
0
|
|
|
0
|
if (defined $opts{'-kerning'} && !defined $opts{'kerning'}) { $opts{'kerning'} = delete($opts{'-kerning'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
3774
|
0
|
0
|
0
|
|
|
0
|
if (defined $opts{'-dokern'} && !defined $opts{'dokern'}) { $opts{'dokern'} = delete($opts{'-dokern'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
3775
|
0
|
0
|
0
|
|
|
0
|
if (defined $opts{'-embed'} && !defined $opts{'embed'}) { $opts{'embed'} = delete($opts{'-embed'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
3776
|
|
|
|
|
|
|
|
|
3777
|
0
|
0
|
|
|
|
0
|
if (exists $opts{'kerning'}) { |
|
3778
|
0
|
|
|
|
|
0
|
$opts{'dokern'} = delete $opts{'kerning'}; |
|
3779
|
|
|
|
|
|
|
} |
|
3780
|
0
|
|
0
|
|
|
0
|
$opts{'dokern'} //= 1; # kerning ON by default for font() |
|
3781
|
|
|
|
|
|
|
|
|
3782
|
|
|
|
|
|
|
# see if it's a plain core font first |
|
3783
|
0
|
|
|
|
|
0
|
require PDF::Builder::Resource::Font::CoreFont; |
|
3784
|
0
|
0
|
0
|
|
|
0
|
if (PDF::Builder::Resource::Font::CoreFont->is_standard($name)) { |
|
|
|
0
|
|
|
|
|
|
|
3785
|
0
|
|
|
|
|
0
|
return $self->corefont($name, %opts); |
|
3786
|
|
|
|
|
|
|
} elsif ($name =~ /^Times$/i and not $opts{'format'}) { |
|
3787
|
|
|
|
|
|
|
# Accept Times as an alias for Times-Roman to follow the pattern set by |
|
3788
|
|
|
|
|
|
|
# Courier and Helvetica |
|
3789
|
0
|
|
|
|
|
0
|
carp "Times is not a standard font; substituting Times-Roman"; |
|
3790
|
0
|
|
|
|
|
0
|
return $self->corefont('Times-Roman', %opts); |
|
3791
|
|
|
|
|
|
|
} |
|
3792
|
|
|
|
|
|
|
|
|
3793
|
0
|
|
|
|
|
0
|
my $format = $opts{'format'}; |
|
3794
|
0
|
0
|
0
|
|
|
0
|
$format //= 'truetype' if UNIVERSAL::isa($name, 'Font::TTF::Font'); |
|
3795
|
0
|
0
|
0
|
|
|
0
|
$format //= ($name =~ /\.[ot]tf$/i ? 'truetype' : |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
3796
|
|
|
|
|
|
|
$name =~ /\.pf[ab]$/i ? 'type1' : |
|
3797
|
|
|
|
|
|
|
$name =~ /\.t1$/i ? 'type1' : |
|
3798
|
|
|
|
|
|
|
$name =~ /\.bdf$/i ? 'bitmap' : ''); |
|
3799
|
|
|
|
|
|
|
|
|
3800
|
0
|
0
|
|
|
|
0
|
if ($format eq 'truetype') { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
3801
|
0
|
|
0
|
|
|
0
|
$opts{'embed'} //= 1; |
|
3802
|
0
|
|
|
|
|
0
|
return $self->ttfont($name, %opts); |
|
3803
|
|
|
|
|
|
|
} elsif ($format eq 'type1') { |
|
3804
|
|
|
|
|
|
|
# psfont routine will check for afmfile and pfmfile |
|
3805
|
0
|
|
|
|
|
0
|
return $self->psfont($name, %opts); |
|
3806
|
|
|
|
|
|
|
} elsif ($format eq 'bitmap') { |
|
3807
|
0
|
|
|
|
|
0
|
return $self->bdfont($name, %opts); |
|
3808
|
|
|
|
|
|
|
} elsif ($format) { |
|
3809
|
0
|
|
|
|
|
0
|
croak "Unrecognized font format: $format"; |
|
3810
|
|
|
|
|
|
|
} elsif ($name =~ /(\..*)$/) { |
|
3811
|
0
|
|
|
|
|
0
|
croak "Unrecognized font file extension: $1"; |
|
3812
|
|
|
|
|
|
|
} else { |
|
3813
|
0
|
|
|
|
|
0
|
croak "Unrecognized font: $name"; |
|
3814
|
|
|
|
|
|
|
} |
|
3815
|
|
|
|
|
|
|
} |
|
3816
|
|
|
|
|
|
|
|
|
3817
|
|
|
|
|
|
|
=head3 standard_fonts |
|
3818
|
|
|
|
|
|
|
|
|
3819
|
|
|
|
|
|
|
@names = $pdf->standard_fonts($flag) |
|
3820
|
|
|
|
|
|
|
|
|
3821
|
|
|
|
|
|
|
Returns the names of the 14 standard (built-in) "core" fonts, if C<$flag> is |
|
3822
|
|
|
|
|
|
|
omitted or "false" (0). See |
|
3823
|
|
|
|
|
|
|
L<PDF::API2::Resource::Font::CoreFont> for details. |
|
3824
|
|
|
|
|
|
|
B<Note> that these do I<not> include the 14 additional Windows "core" |
|
3825
|
|
|
|
|
|
|
fonts extension, unless C<$flag> is given with a value of "true" (1). |
|
3826
|
|
|
|
|
|
|
|
|
3827
|
|
|
|
|
|
|
=cut |
|
3828
|
|
|
|
|
|
|
|
|
3829
|
|
|
|
|
|
|
sub standard_fonts { |
|
3830
|
2
|
|
|
2
|
1
|
2304
|
my $self = shift; |
|
3831
|
2
|
|
|
|
|
5
|
my $Windows_ext = 0; |
|
3832
|
2
|
50
|
66
|
|
|
16
|
if (@_ and $_[0]) { $Windows_ext = 1; } |
|
|
1
|
|
|
|
|
4
|
|
|
3833
|
|
|
|
|
|
|
|
|
3834
|
2
|
|
|
|
|
14
|
require PDF::Builder::Resource::Font::CoreFont; |
|
3835
|
|
|
|
|
|
|
|
|
3836
|
2
|
|
|
|
|
12
|
my @cores = PDF::Builder::Resource::Font::CoreFont->names($Windows_ext); |
|
3837
|
|
|
|
|
|
|
|
|
3838
|
2
|
|
|
|
|
18
|
return @cores; |
|
3839
|
|
|
|
|
|
|
} |
|
3840
|
|
|
|
|
|
|
|
|
3841
|
|
|
|
|
|
|
=head3 is_standard_font |
|
3842
|
|
|
|
|
|
|
|
|
3843
|
|
|
|
|
|
|
$boolean = PDF::Builder->is_standard_font($name); |
|
3844
|
|
|
|
|
|
|
|
|
3845
|
|
|
|
|
|
|
$boolean = PDF::Builder->is_standard_font($name, $flag); |
|
3846
|
|
|
|
|
|
|
|
|
3847
|
|
|
|
|
|
|
Returns true if C<$name> is an exact, case-sensitive match for one of the |
|
3848
|
|
|
|
|
|
|
standard font names. |
|
3849
|
|
|
|
|
|
|
|
|
3850
|
|
|
|
|
|
|
B<Note> that these do I<not> include the 14 additional Windows "core" |
|
3851
|
|
|
|
|
|
|
fonts extension, unless C<$flag> is given with a value of "true" (1), in which case, |
|
3852
|
|
|
|
|
|
|
C<$name> will also be checked against the additional font names. |
|
3853
|
|
|
|
|
|
|
|
|
3854
|
|
|
|
|
|
|
=cut |
|
3855
|
|
|
|
|
|
|
|
|
3856
|
|
|
|
|
|
|
sub is_standard_font { |
|
3857
|
2
|
|
|
2
|
1
|
665
|
my $self = shift; |
|
3858
|
2
|
|
|
|
|
5
|
my $name = shift; |
|
3859
|
2
|
|
|
|
|
4
|
my $Windows_ext = 0; |
|
3860
|
2
|
0
|
33
|
|
|
9
|
if (@_ and $_[0]) { $Windows_ext = 1; } |
|
|
0
|
|
|
|
|
0
|
|
|
3861
|
|
|
|
|
|
|
|
|
3862
|
2
|
|
|
|
|
18
|
require PDF::Builder::Resource::Font::CoreFont; |
|
3863
|
|
|
|
|
|
|
|
|
3864
|
2
|
|
|
|
|
16
|
return PDF::Builder::Resource::Font::CoreFont->is_standard($name, $Windows_ext); |
|
3865
|
|
|
|
|
|
|
} |
|
3866
|
|
|
|
|
|
|
|
|
3867
|
|
|
|
|
|
|
=head3 font_path |
|
3868
|
|
|
|
|
|
|
|
|
3869
|
|
|
|
|
|
|
@directories = PDF::Builder->font_path() |
|
3870
|
|
|
|
|
|
|
|
|
3871
|
|
|
|
|
|
|
=over |
|
3872
|
|
|
|
|
|
|
|
|
3873
|
|
|
|
|
|
|
Return the list of directories that will be searched (in order) in addition to |
|
3874
|
|
|
|
|
|
|
the current directory when you add a font to a PDF without including the full |
|
3875
|
|
|
|
|
|
|
path to the font file. |
|
3876
|
|
|
|
|
|
|
|
|
3877
|
|
|
|
|
|
|
=back |
|
3878
|
|
|
|
|
|
|
|
|
3879
|
|
|
|
|
|
|
=cut |
|
3880
|
|
|
|
|
|
|
|
|
3881
|
|
|
|
|
|
|
sub font_path { |
|
3882
|
234
|
|
|
234
|
1
|
2747
|
return @font_path; |
|
3883
|
|
|
|
|
|
|
} |
|
3884
|
|
|
|
|
|
|
|
|
3885
|
|
|
|
|
|
|
=head3 add_to_font_path, addFontDirs |
|
3886
|
|
|
|
|
|
|
|
|
3887
|
|
|
|
|
|
|
@directories = PDF::Builder::add_to_font_path('/my/fonts', '/path/to/fonts', ...) |
|
3888
|
|
|
|
|
|
|
|
|
3889
|
|
|
|
|
|
|
=over |
|
3890
|
|
|
|
|
|
|
|
|
3891
|
|
|
|
|
|
|
Adds one or more directories to the list of paths to be searched for font files. |
|
3892
|
|
|
|
|
|
|
|
|
3893
|
|
|
|
|
|
|
Returns the font search path. |
|
3894
|
|
|
|
|
|
|
|
|
3895
|
|
|
|
|
|
|
B<Alternate name:> C<addFontDirs> |
|
3896
|
|
|
|
|
|
|
|
|
3897
|
|
|
|
|
|
|
Prior to recent changes to PDF::API2, this method was addFontDirs(). This |
|
3898
|
|
|
|
|
|
|
method is still available, but may be deprecated some time in the future. |
|
3899
|
|
|
|
|
|
|
|
|
3900
|
|
|
|
|
|
|
=back |
|
3901
|
|
|
|
|
|
|
|
|
3902
|
|
|
|
|
|
|
=cut |
|
3903
|
|
|
|
|
|
|
|
|
3904
|
0
|
|
|
0
|
1
|
0
|
sub addFontDirs { return add_to_font_path(@_); } ## no critic |
|
3905
|
|
|
|
|
|
|
|
|
3906
|
|
|
|
|
|
|
sub add_to_font_path { |
|
3907
|
|
|
|
|
|
|
# Allow this method to be called using either :: or -> notation. |
|
3908
|
0
|
0
|
|
0
|
1
|
0
|
shift() if ref($_[0]); |
|
3909
|
0
|
0
|
|
|
|
0
|
shift() if $_[0] eq __PACKAGE__; |
|
3910
|
|
|
|
|
|
|
|
|
3911
|
0
|
|
|
|
|
0
|
push @font_path, @_; |
|
3912
|
0
|
|
|
|
|
0
|
return @font_path; |
|
3913
|
|
|
|
|
|
|
} |
|
3914
|
|
|
|
|
|
|
|
|
3915
|
|
|
|
|
|
|
=head3 set_font_path |
|
3916
|
|
|
|
|
|
|
|
|
3917
|
|
|
|
|
|
|
@directories = PDF::Builder->set_font_path('/my/fonts', '/path/to/fonts'); |
|
3918
|
|
|
|
|
|
|
|
|
3919
|
|
|
|
|
|
|
=over |
|
3920
|
|
|
|
|
|
|
|
|
3921
|
|
|
|
|
|
|
Replace the existing font search path. This should only be necessary if you |
|
3922
|
|
|
|
|
|
|
need to remove a directory from the path for some reason, or if you need to |
|
3923
|
|
|
|
|
|
|
reorder the list. |
|
3924
|
|
|
|
|
|
|
|
|
3925
|
|
|
|
|
|
|
Returns the font search path. |
|
3926
|
|
|
|
|
|
|
|
|
3927
|
|
|
|
|
|
|
=back |
|
3928
|
|
|
|
|
|
|
|
|
3929
|
|
|
|
|
|
|
=cut |
|
3930
|
|
|
|
|
|
|
|
|
3931
|
|
|
|
|
|
|
# I don't know why there are separate set and query methods, but to maintain |
|
3932
|
|
|
|
|
|
|
# compatibility, we'll follow that convention... |
|
3933
|
|
|
|
|
|
|
|
|
3934
|
|
|
|
|
|
|
sub set_font_path { |
|
3935
|
|
|
|
|
|
|
# Allow this method to be called using either :: or -> notation. |
|
3936
|
39
|
50
|
|
39
|
1
|
247
|
shift() if ref($_[0]); |
|
3937
|
39
|
50
|
|
|
|
190
|
shift() if $_[0] eq __PACKAGE__; |
|
3938
|
|
|
|
|
|
|
|
|
3939
|
|
|
|
|
|
|
#@font_path = ((map { "$_/PDF/Builder/fonts" } @INC), @_); |
|
3940
|
39
|
|
|
|
|
305
|
@font_path = @_; |
|
3941
|
|
|
|
|
|
|
|
|
3942
|
39
|
|
|
|
|
214
|
return @font_path; |
|
3943
|
|
|
|
|
|
|
} |
|
3944
|
|
|
|
|
|
|
|
|
3945
|
|
|
|
|
|
|
sub _findFont { |
|
3946
|
0
|
|
|
0
|
|
0
|
my $font = shift(); |
|
3947
|
|
|
|
|
|
|
|
|
3948
|
|
|
|
|
|
|
# Check the current directory or the path is absolute |
|
3949
|
0
|
0
|
|
|
|
0
|
return $font if -f $font; |
|
3950
|
0
|
0
|
|
|
|
0
|
return if substr($font, 0, 1) eq '/'; |
|
3951
|
|
|
|
|
|
|
|
|
3952
|
|
|
|
|
|
|
# Check the font search path |
|
3953
|
0
|
|
|
|
|
0
|
foreach my $directory (@font_path) { |
|
3954
|
0
|
0
|
|
|
|
0
|
return "$directory/$font" if -f "$directory/$font"; |
|
3955
|
|
|
|
|
|
|
} |
|
3956
|
|
|
|
|
|
|
|
|
3957
|
0
|
|
|
|
|
0
|
return; |
|
3958
|
|
|
|
|
|
|
} |
|
3959
|
|
|
|
|
|
|
|
|
3960
|
|
|
|
|
|
|
=head3 synfont, synthetic_font |
|
3961
|
|
|
|
|
|
|
|
|
3962
|
|
|
|
|
|
|
$font = $pdf->synfont($basefont, %opts) |
|
3963
|
|
|
|
|
|
|
|
|
3964
|
|
|
|
|
|
|
=over |
|
3965
|
|
|
|
|
|
|
|
|
3966
|
|
|
|
|
|
|
Returns a new synthetic font object. These are modifications to a core (or |
|
3967
|
|
|
|
|
|
|
PS/T1 or TTF/OTF) font, where the font may be replaced by a Type1 or Type3 |
|
3968
|
|
|
|
|
|
|
PostScript font. |
|
3969
|
|
|
|
|
|
|
This does not appear to work with CJK fonts (created with C<cjkfont> method). |
|
3970
|
|
|
|
|
|
|
For details, see L<PDF::Builder::Docs/Synthetic Fonts>. |
|
3971
|
|
|
|
|
|
|
|
|
3972
|
|
|
|
|
|
|
See also L<PDF::Builder::Resource::Font::SynFont> |
|
3973
|
|
|
|
|
|
|
|
|
3974
|
|
|
|
|
|
|
B<Alternate name:> C<synthetic_font> |
|
3975
|
|
|
|
|
|
|
|
|
3976
|
|
|
|
|
|
|
Prior to recent PDF::API2 changes, the routine to create modified fonts was |
|
3977
|
|
|
|
|
|
|
"synfont". PDF::API2 has renamed it to "synthetic_font", which I don't like, |
|
3978
|
|
|
|
|
|
|
but to maintain compatibility, "synthetic_font" is available as an alias. |
|
3979
|
|
|
|
|
|
|
|
|
3980
|
|
|
|
|
|
|
There are also some minor option differences (incompatibilities) |
|
3981
|
|
|
|
|
|
|
discussed in C<SynFont>, including the value of 'bold' between the two entry |
|
3982
|
|
|
|
|
|
|
points. |
|
3983
|
|
|
|
|
|
|
|
|
3984
|
|
|
|
|
|
|
=back |
|
3985
|
|
|
|
|
|
|
|
|
3986
|
|
|
|
|
|
|
=cut |
|
3987
|
|
|
|
|
|
|
|
|
3988
|
0
|
|
|
0
|
1
|
0
|
sub synthetic_font { return synfont(@_, '-entry_point'=>'synthetic_font'); } ## no critic |
|
3989
|
|
|
|
|
|
|
|
|
3990
|
|
|
|
|
|
|
sub synfont { |
|
3991
|
0
|
|
|
0
|
1
|
0
|
my ($self, $font, %opts) = @_; |
|
3992
|
|
|
|
|
|
|
# copy dashed name options to preferred undashed format |
|
3993
|
0
|
0
|
0
|
|
|
0
|
if (defined $opts{'-unicodemap'} && !defined $opts{'unicodemap'}) { $opts{'unicodemap'} = delete($opts{'-unicodemap'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
3994
|
|
|
|
|
|
|
# define entry point in options if synfont |
|
3995
|
0
|
0
|
|
|
|
0
|
if (!defined $opts{'-entry_point'}) { $opts{'-entry_point'} = 'synfont'; } |
|
|
0
|
|
|
|
|
0
|
|
|
3996
|
|
|
|
|
|
|
|
|
3997
|
|
|
|
|
|
|
# PDF::Builder doesn't set BaseEncoding for TrueType fonts, so text |
|
3998
|
|
|
|
|
|
|
# isn't searchable unless a ToUnicode CMap is included. Include |
|
3999
|
|
|
|
|
|
|
# the ToUnicode CMap by default, but allow it to be disabled (for |
|
4000
|
|
|
|
|
|
|
# performance and file size reasons) by setting unicodemap to 0. |
|
4001
|
0
|
0
|
|
|
|
0
|
$opts{'unicodemap'} = 1 unless exists $opts{'unicodemap'}; |
|
4002
|
|
|
|
|
|
|
|
|
4003
|
0
|
|
|
|
|
0
|
require PDF::Builder::Resource::Font::SynFont; |
|
4004
|
0
|
|
|
|
|
0
|
my $obj = PDF::Builder::Resource::Font::SynFont->new($self->{'pdf'}, $font, %opts); |
|
4005
|
|
|
|
|
|
|
|
|
4006
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
4007
|
0
|
0
|
|
|
|
0
|
$obj->tounicodemap() if $opts{'unicodemap'}; |
|
4008
|
|
|
|
|
|
|
|
|
4009
|
0
|
|
|
|
|
0
|
return $obj; |
|
4010
|
|
|
|
|
|
|
} |
|
4011
|
|
|
|
|
|
|
|
|
4012
|
|
|
|
|
|
|
=head3 unifont |
|
4013
|
|
|
|
|
|
|
|
|
4014
|
|
|
|
|
|
|
$font = $pdf->unifont(@fontspecs, %opts) |
|
4015
|
|
|
|
|
|
|
|
|
4016
|
|
|
|
|
|
|
=over |
|
4017
|
|
|
|
|
|
|
|
|
4018
|
|
|
|
|
|
|
Returns a new uni-font object, based on the specified fonts and options. |
|
4019
|
|
|
|
|
|
|
|
|
4020
|
|
|
|
|
|
|
B<BEWARE:> This is not a true PDF-object, but a virtual/abstract font definition! |
|
4021
|
|
|
|
|
|
|
|
|
4022
|
|
|
|
|
|
|
See also L<PDF::Builder::Resource::UniFont>. |
|
4023
|
|
|
|
|
|
|
|
|
4024
|
|
|
|
|
|
|
=back |
|
4025
|
|
|
|
|
|
|
|
|
4026
|
|
|
|
|
|
|
=cut |
|
4027
|
|
|
|
|
|
|
|
|
4028
|
|
|
|
|
|
|
# tentatively deprecated in PDF::API2. suggests using Unicode-supporting |
|
4029
|
|
|
|
|
|
|
# TTF instead. see also Resource/UniFont.pm (POD removed to discourage use). |
|
4030
|
|
|
|
|
|
|
sub unifont { |
|
4031
|
1
|
|
|
1
|
1
|
13
|
my ($self, @opts) = @_; |
|
4032
|
|
|
|
|
|
|
# must leave opts as an array, rather than as a hash, so option fixup |
|
4033
|
|
|
|
|
|
|
# needs to be done within new(). opts is not just options (hash), but |
|
4034
|
|
|
|
|
|
|
# also a variable-length array of refs, which doesn't take kindly to |
|
4035
|
|
|
|
|
|
|
# being hashified! |
|
4036
|
|
|
|
|
|
|
|
|
4037
|
1
|
|
|
|
|
741
|
require PDF::Builder::Resource::UniFont; |
|
4038
|
1
|
|
|
|
|
11
|
my $obj = PDF::Builder::Resource::UniFont->new($self->{'pdf'}, @opts); |
|
4039
|
|
|
|
|
|
|
|
|
4040
|
1
|
|
|
|
|
4
|
return $obj; |
|
4041
|
|
|
|
|
|
|
} |
|
4042
|
|
|
|
|
|
|
|
|
4043
|
|
|
|
|
|
|
=head2 Font Manager methods |
|
4044
|
|
|
|
|
|
|
|
|
4045
|
|
|
|
|
|
|
The Font Manager is automatically initialized. |
|
4046
|
|
|
|
|
|
|
|
|
4047
|
|
|
|
|
|
|
=head3 font_settings |
|
4048
|
|
|
|
|
|
|
|
|
4049
|
|
|
|
|
|
|
@list = $pdf->font_settings() # Get |
|
4050
|
|
|
|
|
|
|
|
|
4051
|
|
|
|
|
|
|
$pdf->font_settings(%info) # Set |
|
4052
|
|
|
|
|
|
|
|
|
4053
|
|
|
|
|
|
|
=over |
|
4054
|
|
|
|
|
|
|
|
|
4055
|
|
|
|
|
|
|
Change one or more default settings. |
|
4056
|
|
|
|
|
|
|
See L<PDF::Builder::FontManager>/font_settings for details. |
|
4057
|
|
|
|
|
|
|
|
|
4058
|
|
|
|
|
|
|
=back |
|
4059
|
|
|
|
|
|
|
|
|
4060
|
|
|
|
|
|
|
=cut |
|
4061
|
|
|
|
|
|
|
|
|
4062
|
|
|
|
|
|
|
sub font_settings { |
|
4063
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
4064
|
0
|
|
|
|
|
0
|
return $self->{' FM'}->font_settings(@_); |
|
4065
|
|
|
|
|
|
|
} |
|
4066
|
|
|
|
|
|
|
|
|
4067
|
|
|
|
|
|
|
=head3 add_font_path |
|
4068
|
|
|
|
|
|
|
|
|
4069
|
|
|
|
|
|
|
$rc = $pdf->add_font_path("a directory path", %opts) |
|
4070
|
|
|
|
|
|
|
|
|
4071
|
|
|
|
|
|
|
=over |
|
4072
|
|
|
|
|
|
|
|
|
4073
|
|
|
|
|
|
|
Add a search path for Font Manager font entries. |
|
4074
|
|
|
|
|
|
|
See L<PDF::Builder::FontManager>/add_font_path for details. |
|
4075
|
|
|
|
|
|
|
|
|
4076
|
|
|
|
|
|
|
=back |
|
4077
|
|
|
|
|
|
|
|
|
4078
|
|
|
|
|
|
|
=cut |
|
4079
|
|
|
|
|
|
|
|
|
4080
|
|
|
|
|
|
|
sub add_font_path { |
|
4081
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
4082
|
0
|
|
|
|
|
0
|
return $self->{' FM'}->add_font_path(@_); |
|
4083
|
|
|
|
|
|
|
} |
|
4084
|
|
|
|
|
|
|
|
|
4085
|
|
|
|
|
|
|
=head3 add_font |
|
4086
|
|
|
|
|
|
|
|
|
4087
|
|
|
|
|
|
|
$rc = $pdf->add_font(%info) |
|
4088
|
|
|
|
|
|
|
|
|
4089
|
|
|
|
|
|
|
=over |
|
4090
|
|
|
|
|
|
|
|
|
4091
|
|
|
|
|
|
|
Add a font (face) definition to the Font Manager list. |
|
4092
|
|
|
|
|
|
|
See L<PDF::Builder::FontManager>/add_font for details. |
|
4093
|
|
|
|
|
|
|
|
|
4094
|
|
|
|
|
|
|
=back |
|
4095
|
|
|
|
|
|
|
|
|
4096
|
|
|
|
|
|
|
=cut |
|
4097
|
|
|
|
|
|
|
|
|
4098
|
|
|
|
|
|
|
sub add_font { |
|
4099
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
4100
|
0
|
|
|
|
|
0
|
return $self->{' FM'}->add_font(@_); |
|
4101
|
|
|
|
|
|
|
} |
|
4102
|
|
|
|
|
|
|
|
|
4103
|
|
|
|
|
|
|
=head3 get_font |
|
4104
|
|
|
|
|
|
|
|
|
4105
|
|
|
|
|
|
|
@current = $pdf->get_font() # Get |
|
4106
|
|
|
|
|
|
|
|
|
4107
|
|
|
|
|
|
|
$font = $pdf->get_font(%info) # Set |
|
4108
|
|
|
|
|
|
|
|
|
4109
|
|
|
|
|
|
|
=over |
|
4110
|
|
|
|
|
|
|
|
|
4111
|
|
|
|
|
|
|
Retrieve a ready-to-use font, or find out what the current one is. |
|
4112
|
|
|
|
|
|
|
See L<PDF::Builder::FontManager>/get_font for details. |
|
4113
|
|
|
|
|
|
|
|
|
4114
|
|
|
|
|
|
|
=back |
|
4115
|
|
|
|
|
|
|
|
|
4116
|
|
|
|
|
|
|
=cut |
|
4117
|
|
|
|
|
|
|
|
|
4118
|
|
|
|
|
|
|
sub get_font { |
|
4119
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
4120
|
0
|
|
|
|
|
0
|
return $self->{' FM'}->get_font(@_); |
|
4121
|
|
|
|
|
|
|
} |
|
4122
|
|
|
|
|
|
|
|
|
4123
|
|
|
|
|
|
|
=head3 get_external_font |
|
4124
|
|
|
|
|
|
|
|
|
4125
|
|
|
|
|
|
|
$rc = $pdf->get_external_font() |
|
4126
|
|
|
|
|
|
|
|
|
4127
|
|
|
|
|
|
|
=over |
|
4128
|
|
|
|
|
|
|
|
|
4129
|
|
|
|
|
|
|
See if there is already a predefined (opened) font that the user wants to use. |
|
4130
|
|
|
|
|
|
|
See L<PDF::Builder::FontManager>/get_external_font for details. |
|
4131
|
|
|
|
|
|
|
|
|
4132
|
|
|
|
|
|
|
=back |
|
4133
|
|
|
|
|
|
|
|
|
4134
|
|
|
|
|
|
|
=cut |
|
4135
|
|
|
|
|
|
|
|
|
4136
|
|
|
|
|
|
|
sub get_external_font { |
|
4137
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
4138
|
0
|
|
|
|
|
0
|
return $self->{' FM'}->get_external_font(@_); |
|
4139
|
|
|
|
|
|
|
} |
|
4140
|
|
|
|
|
|
|
|
|
4141
|
|
|
|
|
|
|
=head3 dump_font_tables |
|
4142
|
|
|
|
|
|
|
|
|
4143
|
|
|
|
|
|
|
$pdf->dump_font_tables() |
|
4144
|
|
|
|
|
|
|
|
|
4145
|
|
|
|
|
|
|
=over |
|
4146
|
|
|
|
|
|
|
|
|
4147
|
|
|
|
|
|
|
Dump all known font information to STDOUT. |
|
4148
|
|
|
|
|
|
|
See L<PDF::Builder::FontManager>/dump_font_tables for details. |
|
4149
|
|
|
|
|
|
|
|
|
4150
|
|
|
|
|
|
|
=back |
|
4151
|
|
|
|
|
|
|
|
|
4152
|
|
|
|
|
|
|
=cut |
|
4153
|
|
|
|
|
|
|
|
|
4154
|
|
|
|
|
|
|
sub dump_font_tables { |
|
4155
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
4156
|
0
|
|
|
|
|
0
|
return $self->{' FM'}->dump_font_tables(@_); |
|
4157
|
|
|
|
|
|
|
} |
|
4158
|
|
|
|
|
|
|
|
|
4159
|
|
|
|
|
|
|
=head1 IMAGE METHODS |
|
4160
|
|
|
|
|
|
|
|
|
4161
|
|
|
|
|
|
|
=head2 image |
|
4162
|
|
|
|
|
|
|
|
|
4163
|
|
|
|
|
|
|
$object = $pdf->image($file, %opts); |
|
4164
|
|
|
|
|
|
|
|
|
4165
|
|
|
|
|
|
|
=over |
|
4166
|
|
|
|
|
|
|
|
|
4167
|
|
|
|
|
|
|
A convenience function to attempt to determine the image type, and import a |
|
4168
|
|
|
|
|
|
|
file of that type and return an object that can be placed as part of a page's |
|
4169
|
|
|
|
|
|
|
content: |
|
4170
|
|
|
|
|
|
|
|
|
4171
|
|
|
|
|
|
|
=back |
|
4172
|
|
|
|
|
|
|
|
|
4173
|
|
|
|
|
|
|
my $pdf = PDF::Builder->new(); |
|
4174
|
|
|
|
|
|
|
my $page = $pdf->page(); |
|
4175
|
|
|
|
|
|
|
|
|
4176
|
|
|
|
|
|
|
my $image = $pdf->image('/path/to/image.jpg'); |
|
4177
|
|
|
|
|
|
|
$page->object($image, 100, 100); |
|
4178
|
|
|
|
|
|
|
|
|
4179
|
|
|
|
|
|
|
$pdf->save('sample.pdf'); |
|
4180
|
|
|
|
|
|
|
|
|
4181
|
|
|
|
|
|
|
=over |
|
4182
|
|
|
|
|
|
|
|
|
4183
|
|
|
|
|
|
|
C<$file> may be either a file name, a filehandle, or a |
|
4184
|
|
|
|
|
|
|
L<PDF::Builder::Resource::XObject::Image::GD> object. |
|
4185
|
|
|
|
|
|
|
|
|
4186
|
|
|
|
|
|
|
B<Caution:> Do not confuse this C<image> ($pdf-E<gt>) with the image method |
|
4187
|
|
|
|
|
|
|
found in the graphics (gfx) class ($gfx-E<gt>), used to actually I<place> a |
|
4188
|
|
|
|
|
|
|
read-in or decoded image on the page! |
|
4189
|
|
|
|
|
|
|
|
|
4190
|
|
|
|
|
|
|
See L<PDF::Builder::Content/image> and L<PDF::Builder::Content/object> for |
|
4191
|
|
|
|
|
|
|
details about placing images on a page once they're imported. |
|
4192
|
|
|
|
|
|
|
|
|
4193
|
|
|
|
|
|
|
The image format is normally detected automatically based on the file's |
|
4194
|
|
|
|
|
|
|
extension (.gif, .png, .tif/.tiff, .jpg/.jpeg, .pnm/.pbm/.pgm/.ppm). If passed |
|
4195
|
|
|
|
|
|
|
a filehandle, image formats GIF, JPEG, PNM, and PNG will be |
|
4196
|
|
|
|
|
|
|
detected based on the file's header. Unfortunately, at this time, other image |
|
4197
|
|
|
|
|
|
|
formats (TIFF and GD) cannot be automatically detected. (TIFF I<could> be, |
|
4198
|
|
|
|
|
|
|
except that C<image_tiff()> cannot use a filehandle anyway as input when using |
|
4199
|
|
|
|
|
|
|
the libtiff library, which is highly recommended.) |
|
4200
|
|
|
|
|
|
|
|
|
4201
|
|
|
|
|
|
|
If the file has an atypical extension or the filehandle is for a different kind |
|
4202
|
|
|
|
|
|
|
of image, you can set the C<format> option to one of the supported types: |
|
4203
|
|
|
|
|
|
|
C<gif>, C<jpeg>, C<png>, C<pnm>, or C<tiff>. |
|
4204
|
|
|
|
|
|
|
|
|
4205
|
|
|
|
|
|
|
B<Note:> PNG images that include an alpha (transparency) channel go through a |
|
4206
|
|
|
|
|
|
|
relatively slow process of splitting the image into separate RGB and alpha |
|
4207
|
|
|
|
|
|
|
components as is required by images in PDFs. If you're having performance |
|
4208
|
|
|
|
|
|
|
issues, install Image::PNG::Libpng to speed up this process by |
|
4209
|
|
|
|
|
|
|
an order of magnitude; either module will be used automatically if available. |
|
4210
|
|
|
|
|
|
|
See the C<image_png> method for details. |
|
4211
|
|
|
|
|
|
|
|
|
4212
|
|
|
|
|
|
|
B<Note:> TIFF image processing is very slow if using the pure Perl decoder. |
|
4213
|
|
|
|
|
|
|
We highly recommend using the Graphics::TIFF library to improve performance. |
|
4214
|
|
|
|
|
|
|
See the C<image_tiff> method for details. |
|
4215
|
|
|
|
|
|
|
|
|
4216
|
|
|
|
|
|
|
=back |
|
4217
|
|
|
|
|
|
|
|
|
4218
|
|
|
|
|
|
|
=cut |
|
4219
|
|
|
|
|
|
|
|
|
4220
|
|
|
|
|
|
|
sub image { |
|
4221
|
3
|
|
|
3
|
1
|
262
|
my ($self, $file, %opts) = @_; |
|
4222
|
|
|
|
|
|
|
|
|
4223
|
3
|
|
50
|
|
|
27
|
my $format = lc($opts{'format'} // ''); |
|
4224
|
|
|
|
|
|
|
|
|
4225
|
3
|
50
|
|
|
|
20
|
if (ref($file) eq 'GD::Image') { |
|
|
|
50
|
|
|
|
|
|
|
4226
|
0
|
|
|
|
|
0
|
return $self->image_gd($file, %opts); |
|
4227
|
|
|
|
|
|
|
} elsif (ref($file)) { |
|
4228
|
3
|
|
33
|
|
|
20
|
$format ||= _detect_image_format($file); |
|
4229
|
|
|
|
|
|
|
# JPEG, PNG, GIF, and P*M files can be detected |
|
4230
|
|
|
|
|
|
|
# TIFF files cannot currently be detected |
|
4231
|
|
|
|
|
|
|
# GD images are created on-the-fly and don't have files |
|
4232
|
|
|
|
|
|
|
} |
|
4233
|
3
|
50
|
|
|
|
9
|
unless (ref($file)) { |
|
4234
|
0
|
0
|
0
|
|
|
0
|
$format ||= ($file =~ /\.jpe?g$/i ? 'jpeg' : |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
4235
|
|
|
|
|
|
|
$file =~ /\.png$/i ? 'png' : |
|
4236
|
|
|
|
|
|
|
$file =~ /\.gif$/i ? 'gif' : |
|
4237
|
|
|
|
|
|
|
$file =~ /\.tiff?$/i ? 'tiff' : |
|
4238
|
|
|
|
|
|
|
$file =~ /\.svg?$/i ? 'svg' : |
|
4239
|
|
|
|
|
|
|
$file =~ /\.p[bgpn]m$/i ? 'pnm' : ''); |
|
4240
|
|
|
|
|
|
|
# GD images are created on-the-fly and don't have files |
|
4241
|
|
|
|
|
|
|
} |
|
4242
|
|
|
|
|
|
|
|
|
4243
|
3
|
100
|
|
|
|
21
|
if ($format eq 'jpeg') { |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
4244
|
1
|
|
|
|
|
5
|
return $self->image_jpeg($file, %opts); |
|
4245
|
|
|
|
|
|
|
} elsif ($format eq 'png') { |
|
4246
|
1
|
|
|
|
|
7
|
return $self->image_png($file, %opts); |
|
4247
|
|
|
|
|
|
|
} elsif ($format eq 'gif') { |
|
4248
|
1
|
|
|
|
|
4
|
return $self->image_gif($file, %opts); |
|
4249
|
|
|
|
|
|
|
} elsif ($format eq 'tiff') { |
|
4250
|
0
|
|
|
|
|
0
|
return $self->image_tiff($file, %opts); |
|
4251
|
|
|
|
|
|
|
} elsif ($format eq 'svg') { |
|
4252
|
0
|
|
|
|
|
0
|
return $self->image_svg($file, %opts); |
|
4253
|
|
|
|
|
|
|
} elsif ($format eq 'pnm') { |
|
4254
|
0
|
|
|
|
|
0
|
return $self->image_pnm($file, %opts); |
|
4255
|
|
|
|
|
|
|
} elsif ($format) { |
|
4256
|
0
|
|
|
|
|
0
|
croak "Unrecognized image format: $format"; |
|
4257
|
|
|
|
|
|
|
} elsif (ref($file)) { |
|
4258
|
0
|
|
|
|
|
0
|
croak "Unspecified image format"; |
|
4259
|
|
|
|
|
|
|
} elsif ($file =~ /(\..*)$/) { |
|
4260
|
0
|
|
|
|
|
0
|
croak "Unrecognized image extension: $1"; |
|
4261
|
|
|
|
|
|
|
} else { |
|
4262
|
0
|
|
|
|
|
0
|
croak "Unrecognized image: $file"; |
|
4263
|
|
|
|
|
|
|
} |
|
4264
|
|
|
|
|
|
|
} |
|
4265
|
|
|
|
|
|
|
|
|
4266
|
|
|
|
|
|
|
# if passed a filehandle, attempt to read the format header to determine type |
|
4267
|
|
|
|
|
|
|
sub _detect_image_format { |
|
4268
|
3
|
|
|
3
|
|
6
|
my $fh = shift(); |
|
4269
|
3
|
50
|
|
|
|
12
|
if (ref($fh) ne 'SCALAR') { |
|
4270
|
3
|
|
|
|
|
35
|
$fh->seek(0, 0); |
|
4271
|
3
|
|
|
|
|
43
|
binmode $fh, ':raw'; |
|
4272
|
|
|
|
|
|
|
} |
|
4273
|
|
|
|
|
|
|
|
|
4274
|
3
|
|
|
|
|
10
|
my ($test, $bytes_read); |
|
4275
|
3
|
50
|
|
|
|
12
|
if (ref($fh) eq 'SCALAR') { |
|
4276
|
0
|
|
|
|
|
0
|
$test = substr($$fh, 0, 8); |
|
4277
|
0
|
|
|
|
|
0
|
$bytes_read = length($test); |
|
4278
|
|
|
|
|
|
|
} else { |
|
4279
|
3
|
|
|
|
|
23
|
$bytes_read = $fh->read($test, 8); |
|
4280
|
3
|
|
|
|
|
96
|
$fh->seek(0, 0); |
|
4281
|
|
|
|
|
|
|
} |
|
4282
|
3
|
50
|
33
|
|
|
49
|
return unless $bytes_read and $bytes_read == 8; |
|
4283
|
|
|
|
|
|
|
|
|
4284
|
3
|
100
|
|
|
|
18
|
return 'gif' if $test =~ /^GIF\d\d[a-z]/; |
|
4285
|
2
|
100
|
|
|
|
13
|
return 'jpeg' if $test =~ /^\xFF\xD8\xFF/; |
|
4286
|
1
|
50
|
|
|
|
9
|
return 'png' if $test =~ /^\x89PNG\x0D\x0A\x1A\x0A/; |
|
4287
|
0
|
0
|
|
|
|
0
|
return 'pnm' if $test =~ /^\s*P[1-6]/; |
|
4288
|
|
|
|
|
|
|
# II4200 | MM0042 for TIFF |
|
4289
|
0
|
0
|
|
|
|
0
|
return 'tiff' if $test =~ /^II\x2A\x00/; |
|
4290
|
0
|
0
|
|
|
|
0
|
return 'tiff' if $test =~ /^MM\x00\x2A/; |
|
4291
|
|
|
|
|
|
|
|
|
4292
|
|
|
|
|
|
|
# read up to 512 bytes for possible SVG file, expect to find '<svg\s' |
|
4293
|
0
|
|
|
|
|
0
|
$fh->seek(0, 0); |
|
4294
|
0
|
|
|
|
|
0
|
$bytes_read = $fh->read($test, 512); |
|
4295
|
0
|
|
|
|
|
0
|
$fh->seek(0, 0); |
|
4296
|
0
|
0
|
|
|
|
0
|
return 'svg' if $test =~ /<svg\s/is; |
|
4297
|
|
|
|
|
|
|
|
|
4298
|
|
|
|
|
|
|
# GD images do not have files. |
|
4299
|
0
|
|
|
|
|
0
|
return; |
|
4300
|
|
|
|
|
|
|
} |
|
4301
|
|
|
|
|
|
|
|
|
4302
|
|
|
|
|
|
|
=head2 image_jpeg |
|
4303
|
|
|
|
|
|
|
|
|
4304
|
|
|
|
|
|
|
$jpeg = $pdf->image_jpeg($file, %opts) |
|
4305
|
|
|
|
|
|
|
|
|
4306
|
|
|
|
|
|
|
=over |
|
4307
|
|
|
|
|
|
|
|
|
4308
|
|
|
|
|
|
|
Imports and returns a new JPEG image object. C<$file> may be either a filename |
|
4309
|
|
|
|
|
|
|
or a filehandle. |
|
4310
|
|
|
|
|
|
|
|
|
4311
|
|
|
|
|
|
|
See L<PDF::Builder::Resource::XObject::Image::JPEG> for additional information |
|
4312
|
|
|
|
|
|
|
and C<examples/Content.pl> for some examples of placing an image on a page. |
|
4313
|
|
|
|
|
|
|
|
|
4314
|
|
|
|
|
|
|
=back |
|
4315
|
|
|
|
|
|
|
|
|
4316
|
|
|
|
|
|
|
=cut |
|
4317
|
|
|
|
|
|
|
|
|
4318
|
|
|
|
|
|
|
sub image_jpeg { |
|
4319
|
3
|
|
|
3
|
1
|
25
|
my ($self, $file, %opts) = @_; |
|
4320
|
|
|
|
|
|
|
|
|
4321
|
3
|
|
|
|
|
1147
|
require PDF::Builder::Resource::XObject::Image::JPEG; |
|
4322
|
3
|
|
|
|
|
42
|
my $obj = PDF::Builder::Resource::XObject::Image::JPEG->new($self->{'pdf'}, $file, %opts); |
|
4323
|
|
|
|
|
|
|
|
|
4324
|
2
|
|
|
|
|
11
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
4325
|
|
|
|
|
|
|
|
|
4326
|
2
|
|
|
|
|
25
|
return $obj; |
|
4327
|
|
|
|
|
|
|
} |
|
4328
|
|
|
|
|
|
|
|
|
4329
|
|
|
|
|
|
|
=head2 image_tiff |
|
4330
|
|
|
|
|
|
|
|
|
4331
|
|
|
|
|
|
|
$tiff = $pdf->image_tiff($file, %opts) |
|
4332
|
|
|
|
|
|
|
|
|
4333
|
|
|
|
|
|
|
=over |
|
4334
|
|
|
|
|
|
|
|
|
4335
|
|
|
|
|
|
|
Imports and returns a new TIFF image object. C<$file> may be either a filename |
|
4336
|
|
|
|
|
|
|
or a filehandle. |
|
4337
|
|
|
|
|
|
|
For details, see L<PDF::Builder::Docs/TIFF Images>. |
|
4338
|
|
|
|
|
|
|
|
|
4339
|
|
|
|
|
|
|
See L<PDF::Builder::Resource::XObject::Image::TIFF> and |
|
4340
|
|
|
|
|
|
|
L<PDF::Builder::Resource::XObject::Image::TIFF_GT> for additional information |
|
4341
|
|
|
|
|
|
|
and C<examples/Content.pl> |
|
4342
|
|
|
|
|
|
|
for some examples of placing an image on a page (JPEG, but the principle is |
|
4343
|
|
|
|
|
|
|
the same). |
|
4344
|
|
|
|
|
|
|
There is an optional TIFF library (TIFF_GT) described, that gives more |
|
4345
|
|
|
|
|
|
|
capability than the default one. |
|
4346
|
|
|
|
|
|
|
See the TIFF_GT documentation for further information on using this library, |
|
4347
|
|
|
|
|
|
|
particularly when passing a I<filehandle> for the file. |
|
4348
|
|
|
|
|
|
|
|
|
4349
|
|
|
|
|
|
|
=back |
|
4350
|
|
|
|
|
|
|
|
|
4351
|
|
|
|
|
|
|
=cut |
|
4352
|
|
|
|
|
|
|
|
|
4353
|
|
|
|
|
|
|
sub image_tiff { |
|
4354
|
4
|
|
|
4
|
1
|
115
|
my ($self, $file, %opts) = @_; |
|
4355
|
|
|
|
|
|
|
# copy dashed name options to preferred undashed format |
|
4356
|
4
|
50
|
33
|
|
|
29
|
if (defined $opts{'-nouseGT'} && !defined $opts{'nouseGT'}) { $opts{'nouseGT'} = delete($opts{'-nouseGT'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
4357
|
4
|
50
|
33
|
|
|
17
|
if (defined $opts{'-silent'} && !defined $opts{'silent'}) { $opts{'silent'} = delete($opts{'-silent'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
4358
|
|
|
|
|
|
|
|
|
4359
|
4
|
|
|
|
|
9
|
my ($rc, $obj); |
|
4360
|
4
|
|
|
|
|
16
|
$rc = $self->LA_GT(); |
|
4361
|
4
|
50
|
|
|
|
11
|
if ($rc) { |
|
4362
|
|
|
|
|
|
|
# Graphics::TIFF available |
|
4363
|
0
|
0
|
0
|
|
|
0
|
if (defined $opts{'nouseGT'} && $opts{'nouseGT'} == 1) { |
|
4364
|
0
|
|
|
|
|
0
|
$rc = -1; # don't use it |
|
4365
|
|
|
|
|
|
|
} |
|
4366
|
|
|
|
|
|
|
} |
|
4367
|
4
|
50
|
|
|
|
14
|
if ($rc == 1) { |
|
4368
|
|
|
|
|
|
|
# Graphics::TIFF (_GT suffix) available and to be used |
|
4369
|
0
|
|
|
|
|
0
|
require PDF::Builder::Resource::XObject::Image::TIFF_GT; |
|
4370
|
0
|
|
|
|
|
0
|
$obj = PDF::Builder::Resource::XObject::Image::TIFF_GT->new($self->{'pdf'}, $file, %opts); |
|
4371
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
4372
|
|
|
|
|
|
|
} else { |
|
4373
|
|
|
|
|
|
|
# Graphics::TIFF not available, or is but is not to be used |
|
4374
|
4
|
|
|
|
|
1532
|
require PDF::Builder::Resource::XObject::Image::TIFF; |
|
4375
|
4
|
|
|
|
|
54
|
$obj = PDF::Builder::Resource::XObject::Image::TIFF->new($self->{'pdf'}, $file, %opts); |
|
4376
|
3
|
|
|
|
|
22
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
4377
|
|
|
|
|
|
|
|
|
4378
|
3
|
100
|
66
|
|
|
23
|
if ($rc == 0 && $MSG_COUNT[0]++ == 0) { |
|
4379
|
|
|
|
|
|
|
# give warning message once, unless silenced (silent) or |
|
4380
|
|
|
|
|
|
|
# deliberately not using Graphics::TIFF (rc == -1) |
|
4381
|
1
|
50
|
33
|
|
|
7
|
if (!defined $opts{'silent'} || $opts{'silent'} == 0) { |
|
4382
|
0
|
|
|
|
|
0
|
print STDERR "Your system does not have Graphics::TIFF installed, ". |
|
4383
|
|
|
|
|
|
|
"so some\nTIFF functions may not run correctly.\n"; |
|
4384
|
|
|
|
|
|
|
# even if silent only once, COUNT still incremented |
|
4385
|
|
|
|
|
|
|
} |
|
4386
|
|
|
|
|
|
|
} |
|
4387
|
|
|
|
|
|
|
} |
|
4388
|
3
|
|
|
|
|
13
|
$obj->{'usesGT'} = PDFNum($rc); # -1 available but unused |
|
4389
|
|
|
|
|
|
|
# 0 not available |
|
4390
|
|
|
|
|
|
|
# 1 available and used |
|
4391
|
|
|
|
|
|
|
# $tiff->usesLib() to get number |
|
4392
|
|
|
|
|
|
|
|
|
4393
|
3
|
|
|
|
|
35
|
return $obj; |
|
4394
|
|
|
|
|
|
|
} |
|
4395
|
|
|
|
|
|
|
|
|
4396
|
|
|
|
|
|
|
=head3 LA_GT |
|
4397
|
|
|
|
|
|
|
|
|
4398
|
|
|
|
|
|
|
$rc = $pdf->LA_GT() |
|
4399
|
|
|
|
|
|
|
|
|
4400
|
|
|
|
|
|
|
=over |
|
4401
|
|
|
|
|
|
|
|
|
4402
|
|
|
|
|
|
|
Returns 1 if the library name (package) Graphics::TIFF is installed, and |
|
4403
|
|
|
|
|
|
|
0 otherwise. For this optional library, this call can be used to know if it |
|
4404
|
|
|
|
|
|
|
is safe to use certain functions. For example: |
|
4405
|
|
|
|
|
|
|
|
|
4406
|
|
|
|
|
|
|
=back |
|
4407
|
|
|
|
|
|
|
|
|
4408
|
|
|
|
|
|
|
if ($pdf->LA_GT() { |
|
4409
|
|
|
|
|
|
|
# is installed and usable |
|
4410
|
|
|
|
|
|
|
} else { |
|
4411
|
|
|
|
|
|
|
# not available. you will be running the old, pure PERL code |
|
4412
|
|
|
|
|
|
|
} |
|
4413
|
|
|
|
|
|
|
|
|
4414
|
|
|
|
|
|
|
=cut |
|
4415
|
|
|
|
|
|
|
|
|
4416
|
|
|
|
|
|
|
# there doesn't seem to be a way to pass in a string (or bare) package name, |
|
4417
|
|
|
|
|
|
|
# to make a generic check routine |
|
4418
|
|
|
|
|
|
|
sub LA_GT { |
|
4419
|
4
|
|
|
4
|
1
|
9
|
my ($self) = @_; |
|
4420
|
|
|
|
|
|
|
|
|
4421
|
4
|
|
|
|
|
13
|
my ($rc); |
|
4422
|
4
|
|
|
|
|
9
|
$rc = eval { |
|
4423
|
4
|
|
|
|
|
618
|
require Graphics::TIFF; |
|
4424
|
0
|
|
|
|
|
0
|
1; |
|
4425
|
|
|
|
|
|
|
}; |
|
4426
|
4
|
50
|
|
|
|
17
|
if (!defined $rc) { $rc = 0; } # else is 1 |
|
|
4
|
|
|
|
|
10
|
|
|
4427
|
4
|
50
|
|
|
|
13
|
if ($rc) { |
|
4428
|
|
|
|
|
|
|
# installed, but not up to date? |
|
4429
|
0
|
0
|
|
|
|
0
|
if (version->parse("v$Graphics::TIFF::VERSION")->numify() < |
|
4430
|
0
|
|
|
|
|
0
|
version->parse("v$GrTFversion")->numify()) { $rc = 0; } |
|
4431
|
|
|
|
|
|
|
} |
|
4432
|
|
|
|
|
|
|
|
|
4433
|
4
|
|
|
|
|
13
|
return $rc; |
|
4434
|
|
|
|
|
|
|
} |
|
4435
|
|
|
|
|
|
|
|
|
4436
|
|
|
|
|
|
|
=head2 image_pnm |
|
4437
|
|
|
|
|
|
|
|
|
4438
|
|
|
|
|
|
|
$pnm = $pdf->image_pnm($file, %opts) |
|
4439
|
|
|
|
|
|
|
|
|
4440
|
|
|
|
|
|
|
=over |
|
4441
|
|
|
|
|
|
|
|
|
4442
|
|
|
|
|
|
|
Imports and returns a new PNM image object. C<$file> may be either a filename |
|
4443
|
|
|
|
|
|
|
or a filehandle. |
|
4444
|
|
|
|
|
|
|
|
|
4445
|
|
|
|
|
|
|
See L<PDF::Builder::Resource::XObject::Image::PNM> for additional information |
|
4446
|
|
|
|
|
|
|
and C<examples/Content.pl> for some examples of placing an image on a page |
|
4447
|
|
|
|
|
|
|
(JPEG, but the principle is the same). |
|
4448
|
|
|
|
|
|
|
|
|
4449
|
|
|
|
|
|
|
=back |
|
4450
|
|
|
|
|
|
|
|
|
4451
|
|
|
|
|
|
|
=cut |
|
4452
|
|
|
|
|
|
|
|
|
4453
|
|
|
|
|
|
|
sub image_pnm { |
|
4454
|
3
|
|
|
3
|
1
|
78
|
my ($self, $file, %opts) = @_; |
|
4455
|
|
|
|
|
|
|
|
|
4456
|
3
|
|
33
|
|
|
27
|
$opts{'compress'} //= $self->{'forcecompress'}; |
|
4457
|
|
|
|
|
|
|
|
|
4458
|
3
|
|
|
|
|
639
|
require PDF::Builder::Resource::XObject::Image::PNM; |
|
4459
|
3
|
|
|
|
|
26
|
my $obj = PDF::Builder::Resource::XObject::Image::PNM->new($self->{'pdf'}, $file, %opts); |
|
4460
|
|
|
|
|
|
|
|
|
4461
|
2
|
|
|
|
|
10
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
4462
|
|
|
|
|
|
|
|
|
4463
|
2
|
|
|
|
|
18
|
return $obj; |
|
4464
|
|
|
|
|
|
|
} |
|
4465
|
|
|
|
|
|
|
|
|
4466
|
|
|
|
|
|
|
=head2 image_png |
|
4467
|
|
|
|
|
|
|
|
|
4468
|
|
|
|
|
|
|
$png = $pdf->image_png($file, %opts) |
|
4469
|
|
|
|
|
|
|
|
|
4470
|
|
|
|
|
|
|
=over |
|
4471
|
|
|
|
|
|
|
|
|
4472
|
|
|
|
|
|
|
Imports and returns a new PNG image object. C<$file> may be either |
|
4473
|
|
|
|
|
|
|
a filename or a filehandle. |
|
4474
|
|
|
|
|
|
|
For details, see L<PDF::Builder::Docs/PNG Images>. |
|
4475
|
|
|
|
|
|
|
|
|
4476
|
|
|
|
|
|
|
See L<PDF::Builder::Resource::XObject::Image::PNG> and |
|
4477
|
|
|
|
|
|
|
L<PDF::Builder::Resource::XObject::Image::PNG_IPL> for additional information |
|
4478
|
|
|
|
|
|
|
and C<examples/Content.pl> |
|
4479
|
|
|
|
|
|
|
for some examples of placing an image on a page (JPEG, but the principle is |
|
4480
|
|
|
|
|
|
|
the same). |
|
4481
|
|
|
|
|
|
|
|
|
4482
|
|
|
|
|
|
|
There is an optional PNG library (PNG_IPL) described, that gives more |
|
4483
|
|
|
|
|
|
|
capability than the default one. |
|
4484
|
|
|
|
|
|
|
See the PNG_IPL documentation for further information on using this library, |
|
4485
|
|
|
|
|
|
|
particularly when passing a I<filehandle> for the file. |
|
4486
|
|
|
|
|
|
|
|
|
4487
|
|
|
|
|
|
|
=back |
|
4488
|
|
|
|
|
|
|
|
|
4489
|
|
|
|
|
|
|
=cut |
|
4490
|
|
|
|
|
|
|
|
|
4491
|
|
|
|
|
|
|
sub image_png { |
|
4492
|
5
|
|
|
5
|
1
|
44
|
my ($self, $file, %opts) = @_; |
|
4493
|
|
|
|
|
|
|
# copy dashed name options to preferred undashed format |
|
4494
|
5
|
50
|
33
|
|
|
25
|
if (defined $opts{'-nouseIPL'} && !defined $opts{'nouseIPL'}) { $opts{'nouseIPL'} = delete($opts{'-nouseIPL'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
4495
|
5
|
50
|
33
|
|
|
19
|
if (defined $opts{'-silent'} && !defined $opts{'silent'}) { $opts{'silent'} = delete($opts{'-silent'}); } |
|
|
0
|
|
|
|
|
0
|
|
|
4496
|
|
|
|
|
|
|
|
|
4497
|
5
|
|
|
|
|
13
|
my ($rc, $obj); |
|
4498
|
5
|
|
|
|
|
21
|
$rc = $self->LA_IPL(); |
|
4499
|
5
|
50
|
|
|
|
17
|
if ($rc) { |
|
4500
|
|
|
|
|
|
|
# Image::PNG::Libpng available |
|
4501
|
0
|
0
|
0
|
|
|
0
|
if (defined $opts{'nouseIPL'} && $opts{'nouseIPL'} == 1) { |
|
4502
|
0
|
|
|
|
|
0
|
$rc = -1; # don't use it |
|
4503
|
|
|
|
|
|
|
} |
|
4504
|
|
|
|
|
|
|
} |
|
4505
|
5
|
50
|
|
|
|
30
|
if ($rc == 1) { |
|
4506
|
|
|
|
|
|
|
# Image::PNG::Libpng (_IPL suffix) available and to be used |
|
4507
|
0
|
|
|
|
|
0
|
require PDF::Builder::Resource::XObject::Image::PNG_IPL; |
|
4508
|
0
|
|
|
|
|
0
|
$obj = PDF::Builder::Resource::XObject::Image::PNG_IPL->new($self->{'pdf'}, $file, %opts); |
|
4509
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
4510
|
|
|
|
|
|
|
} else { |
|
4511
|
|
|
|
|
|
|
# Image::PNG::Libpng not available, or is but is not to be used |
|
4512
|
5
|
|
|
|
|
908
|
require PDF::Builder::Resource::XObject::Image::PNG; |
|
4513
|
5
|
|
|
|
|
78
|
$obj = PDF::Builder::Resource::XObject::Image::PNG->new($self->{'pdf'}, $file, %opts); |
|
4514
|
4
|
|
|
|
|
46
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
4515
|
|
|
|
|
|
|
|
|
4516
|
4
|
100
|
66
|
|
|
50
|
if ($rc == 0 && $MSG_COUNT[1]++ == 0) { |
|
4517
|
|
|
|
|
|
|
# give warning message once, unless silenced (silent) or |
|
4518
|
|
|
|
|
|
|
# deliberately not using Image::PNG::Libpng (rc == -1) |
|
4519
|
1
|
50
|
33
|
|
|
7
|
if (!defined $opts{'silent'} || $opts{'silent'} == 0) { |
|
4520
|
0
|
|
|
|
|
0
|
print STDERR "Your system does not have Image::PNG::Libpng installed, ". |
|
4521
|
|
|
|
|
|
|
"so some\nPNG functions may not run correctly.\n"; |
|
4522
|
|
|
|
|
|
|
# even if silent only once, COUNT still incremented |
|
4523
|
|
|
|
|
|
|
} |
|
4524
|
|
|
|
|
|
|
} |
|
4525
|
|
|
|
|
|
|
} |
|
4526
|
4
|
|
|
|
|
24
|
$obj->{'usesIPL'} = PDFNum($rc); # -1 available but unused |
|
4527
|
|
|
|
|
|
|
# 0 not available |
|
4528
|
|
|
|
|
|
|
# 1 available and used |
|
4529
|
|
|
|
|
|
|
# $png->usesLib() to get number |
|
4530
|
4
|
|
|
|
|
91
|
return $obj; |
|
4531
|
|
|
|
|
|
|
} |
|
4532
|
|
|
|
|
|
|
|
|
4533
|
|
|
|
|
|
|
=head3 LA_IPL |
|
4534
|
|
|
|
|
|
|
|
|
4535
|
|
|
|
|
|
|
$rc = $pdf->LA_IPL() |
|
4536
|
|
|
|
|
|
|
|
|
4537
|
|
|
|
|
|
|
=over |
|
4538
|
|
|
|
|
|
|
|
|
4539
|
|
|
|
|
|
|
Returns 1 if the library name (package) Image::PNG::Libpng is installed, and |
|
4540
|
|
|
|
|
|
|
0 otherwise. For this optional library, this call can be used to know if it |
|
4541
|
|
|
|
|
|
|
is safe to use certain functions. For example: |
|
4542
|
|
|
|
|
|
|
|
|
4543
|
|
|
|
|
|
|
=back |
|
4544
|
|
|
|
|
|
|
|
|
4545
|
|
|
|
|
|
|
if ($pdf->LA_IPL() { |
|
4546
|
|
|
|
|
|
|
# is installed and usable |
|
4547
|
|
|
|
|
|
|
} else { |
|
4548
|
|
|
|
|
|
|
# not available. don't use 16bps or interlaced PNG image files |
|
4549
|
|
|
|
|
|
|
} |
|
4550
|
|
|
|
|
|
|
|
|
4551
|
|
|
|
|
|
|
=cut |
|
4552
|
|
|
|
|
|
|
|
|
4553
|
|
|
|
|
|
|
# there doesn't seem to be a way to pass in a string (or bare) package name, |
|
4554
|
|
|
|
|
|
|
# to make a generic check routine |
|
4555
|
|
|
|
|
|
|
sub LA_IPL { |
|
4556
|
5
|
|
|
5
|
1
|
15
|
my ($self) = @_; |
|
4557
|
|
|
|
|
|
|
|
|
4558
|
5
|
|
|
|
|
8
|
my ($rc); |
|
4559
|
5
|
|
|
|
|
10
|
$rc = eval { |
|
4560
|
5
|
|
|
|
|
879
|
require Image::PNG::Libpng; |
|
4561
|
0
|
|
|
|
|
0
|
1; |
|
4562
|
|
|
|
|
|
|
}; |
|
4563
|
5
|
50
|
|
|
|
25
|
if (!defined $rc) { $rc = 0; } # else is 1 |
|
|
5
|
|
|
|
|
11
|
|
|
4564
|
5
|
50
|
|
|
|
14
|
if ($rc) { |
|
4565
|
|
|
|
|
|
|
# installed, but not up to date? |
|
4566
|
0
|
0
|
|
|
|
0
|
if (version->parse("v$Image::PNG::Libpng::VERSION")->numify() < |
|
4567
|
0
|
|
|
|
|
0
|
version->parse("v$LpngVersion")->numify()) { $rc = 0; } |
|
4568
|
|
|
|
|
|
|
} |
|
4569
|
|
|
|
|
|
|
|
|
4570
|
5
|
|
|
|
|
15
|
return $rc; |
|
4571
|
|
|
|
|
|
|
} |
|
4572
|
|
|
|
|
|
|
|
|
4573
|
|
|
|
|
|
|
=head2 image_gif |
|
4574
|
|
|
|
|
|
|
|
|
4575
|
|
|
|
|
|
|
$gif = $pdf->image_gif($file, %opts) |
|
4576
|
|
|
|
|
|
|
|
|
4577
|
|
|
|
|
|
|
=over |
|
4578
|
|
|
|
|
|
|
|
|
4579
|
|
|
|
|
|
|
Imports and returns a new GIF image object. C<$file> may be either a filename |
|
4580
|
|
|
|
|
|
|
or a filehandle. |
|
4581
|
|
|
|
|
|
|
|
|
4582
|
|
|
|
|
|
|
See L<PDF::Builder::Resource::XObject::Image::GIF> for additional information |
|
4583
|
|
|
|
|
|
|
and C<examples/Content.pl> for some examples of placing an image on a page |
|
4584
|
|
|
|
|
|
|
(JPEG, but the principle is the same). |
|
4585
|
|
|
|
|
|
|
|
|
4586
|
|
|
|
|
|
|
=back |
|
4587
|
|
|
|
|
|
|
|
|
4588
|
|
|
|
|
|
|
=cut |
|
4589
|
|
|
|
|
|
|
|
|
4590
|
|
|
|
|
|
|
sub image_gif { |
|
4591
|
3
|
|
|
3
|
1
|
13
|
my ($self, $file, %opts) = @_; |
|
4592
|
|
|
|
|
|
|
|
|
4593
|
3
|
|
|
|
|
572
|
require PDF::Builder::Resource::XObject::Image::GIF; |
|
4594
|
3
|
|
|
|
|
21
|
my $obj = PDF::Builder::Resource::XObject::Image::GIF->new($self->{'pdf'}, $file); |
|
4595
|
2
|
|
|
|
|
9
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
4596
|
|
|
|
|
|
|
|
|
4597
|
2
|
|
|
|
|
33
|
return $obj; |
|
4598
|
|
|
|
|
|
|
} |
|
4599
|
|
|
|
|
|
|
|
|
4600
|
|
|
|
|
|
|
=head2 image_svg |
|
4601
|
|
|
|
|
|
|
|
|
4602
|
|
|
|
|
|
|
$pnm = $pdf->image_svg($file, %opts) |
|
4603
|
|
|
|
|
|
|
|
|
4604
|
|
|
|
|
|
|
=over |
|
4605
|
|
|
|
|
|
|
|
|
4606
|
|
|
|
|
|
|
Imports and returns a new SVG image object. C<$file> may be a filename, a |
|
4607
|
|
|
|
|
|
|
string, or a filehandle. |
|
4608
|
|
|
|
|
|
|
|
|
4609
|
|
|
|
|
|
|
See L<PDF::Builder::Resource::XObject::Image::SVG> for additional information |
|
4610
|
|
|
|
|
|
|
and C<examples/Content.pl> for some examples of placing an image on a page |
|
4611
|
|
|
|
|
|
|
(JPEG, but the principle is the same). Note that C<object()> is preferably |
|
4612
|
|
|
|
|
|
|
used rather than C<image()>. If C<image> determines that the image object is |
|
4613
|
|
|
|
|
|
|
a processed SVG array, it simply passes it on to C<object>. |
|
4614
|
|
|
|
|
|
|
|
|
4615
|
|
|
|
|
|
|
B<CAUTIONS:> |
|
4616
|
|
|
|
|
|
|
1. If using C<image()>, the final two (optional) parameters are I<not> width |
|
4617
|
|
|
|
|
|
|
and height, but instead the horizontal scale and vertical scale. |
|
4618
|
|
|
|
|
|
|
2. Results are unpredictable if allowing C<x> and C<y> positions to default |
|
4619
|
|
|
|
|
|
|
to I<Lower Left> corner at C<(0,0)>, due to different scaling. It is best to |
|
4620
|
|
|
|
|
|
|
explicitly give the C<x> and C<y> positions. |
|
4621
|
|
|
|
|
|
|
3. Be aware that due to different scaling, some resulting images may be much |
|
4622
|
|
|
|
|
|
|
larger than expected. Account for this when setting any C<scale> factor. |
|
4623
|
|
|
|
|
|
|
|
|
4624
|
|
|
|
|
|
|
=back |
|
4625
|
|
|
|
|
|
|
|
|
4626
|
|
|
|
|
|
|
=cut |
|
4627
|
|
|
|
|
|
|
|
|
4628
|
|
|
|
|
|
|
sub image_svg { |
|
4629
|
1
|
|
|
1
|
1
|
10
|
my ($self, $file, %opts) = @_; |
|
4630
|
|
|
|
|
|
|
|
|
4631
|
1
|
|
|
|
|
1
|
my $rc; |
|
4632
|
1
|
|
|
|
|
1
|
$rc = eval { |
|
4633
|
1
|
|
|
|
|
69
|
require SVGPDF; |
|
4634
|
0
|
|
|
|
|
0
|
1; |
|
4635
|
|
|
|
|
|
|
}; |
|
4636
|
1
|
50
|
|
|
|
3
|
if (!defined $rc) { $rc = 0; } # else is 1 |
|
|
1
|
|
|
|
|
2
|
|
|
4637
|
1
|
50
|
|
|
|
2
|
if ($rc) { |
|
4638
|
|
|
|
|
|
|
# installed, but not up to date? |
|
4639
|
0
|
0
|
|
|
|
0
|
if (version->parse("v$SVGPDF::VERSION")->numify() < |
|
4640
|
0
|
|
|
|
|
0
|
version->parse("v$SVGPDFver")->numify()) { $rc = 0; } |
|
4641
|
|
|
|
|
|
|
} |
|
4642
|
1
|
50
|
|
|
|
2
|
if (!$rc) { |
|
4643
|
1
|
|
|
|
|
326
|
carp "SVGPDF not available, so SVG image can not be processed"; |
|
4644
|
1
|
|
|
|
|
23
|
return []; |
|
4645
|
|
|
|
|
|
|
} |
|
4646
|
|
|
|
|
|
|
|
|
4647
|
0
|
|
|
|
|
0
|
require PDF::Builder::Resource::XObject::Image::SVG; |
|
4648
|
0
|
|
|
|
|
0
|
my $obj = PDF::Builder::Resource::XObject::Image::SVG->new($self, $file, %opts); |
|
4649
|
|
|
|
|
|
|
|
|
4650
|
0
|
0
|
0
|
|
|
0
|
if (defined $opts{'compress'} && $opts{'compress'} == 0) { |
|
4651
|
|
|
|
|
|
|
# suppress compression of stream |
|
4652
|
0
|
|
|
|
|
0
|
my $o = $obj->[0]->{'xo'}; |
|
4653
|
0
|
|
|
|
|
0
|
delete $o->{'Filter'}; |
|
4654
|
0
|
|
|
|
|
0
|
delete $o->{'-docompress'}; |
|
4655
|
|
|
|
|
|
|
} |
|
4656
|
|
|
|
|
|
|
|
|
4657
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
4658
|
|
|
|
|
|
|
|
|
4659
|
0
|
|
|
|
|
0
|
return $obj; |
|
4660
|
|
|
|
|
|
|
} |
|
4661
|
|
|
|
|
|
|
|
|
4662
|
|
|
|
|
|
|
=head3 LA_SVG |
|
4663
|
|
|
|
|
|
|
|
|
4664
|
|
|
|
|
|
|
$rc = $pdf->LA_SVG() |
|
4665
|
|
|
|
|
|
|
|
|
4666
|
|
|
|
|
|
|
=over |
|
4667
|
|
|
|
|
|
|
|
|
4668
|
|
|
|
|
|
|
Returns 1 if the library name (package) SVGPDF is installed, and |
|
4669
|
|
|
|
|
|
|
0 otherwise. For this optional library, this call can be used to know if it |
|
4670
|
|
|
|
|
|
|
is safe to use certain functions. For example: |
|
4671
|
|
|
|
|
|
|
|
|
4672
|
|
|
|
|
|
|
=back |
|
4673
|
|
|
|
|
|
|
|
|
4674
|
|
|
|
|
|
|
if ($pdf->LA_SVG() { |
|
4675
|
|
|
|
|
|
|
# is installed and usable |
|
4676
|
|
|
|
|
|
|
} else { |
|
4677
|
|
|
|
|
|
|
# not available. can't use image_svg or any other SVG function |
|
4678
|
|
|
|
|
|
|
} |
|
4679
|
|
|
|
|
|
|
|
|
4680
|
|
|
|
|
|
|
=cut |
|
4681
|
|
|
|
|
|
|
|
|
4682
|
|
|
|
|
|
|
# there doesn't seem to be a way to pass in a string (or bare) package name, |
|
4683
|
|
|
|
|
|
|
# to make a generic check routine |
|
4684
|
|
|
|
|
|
|
sub LA_SVG { |
|
4685
|
1
|
|
|
1
|
1
|
7
|
my ($self) = @_; |
|
4686
|
|
|
|
|
|
|
|
|
4687
|
1
|
|
|
|
|
2
|
my ($rc); |
|
4688
|
1
|
|
|
|
|
1
|
$rc = eval { |
|
4689
|
1
|
|
|
|
|
605
|
require SVGPDF; |
|
4690
|
0
|
|
|
|
|
0
|
1; |
|
4691
|
|
|
|
|
|
|
}; |
|
4692
|
1
|
50
|
|
|
|
5
|
if (!defined $rc) { $rc = 0; } # else is 1 |
|
|
1
|
|
|
|
|
1
|
|
|
4693
|
1
|
50
|
|
|
|
2
|
if ($rc) { |
|
4694
|
|
|
|
|
|
|
# installed, but not up to date? |
|
4695
|
0
|
0
|
|
|
|
0
|
if (version->parse("v$SVGPDF::VERSION")->numify() < |
|
4696
|
0
|
|
|
|
|
0
|
version->parse("v$SVGPDFver")->numify()) { $rc = 0; } |
|
4697
|
|
|
|
|
|
|
} |
|
4698
|
|
|
|
|
|
|
|
|
4699
|
1
|
|
|
|
|
4
|
return $rc; |
|
4700
|
|
|
|
|
|
|
} |
|
4701
|
|
|
|
|
|
|
|
|
4702
|
|
|
|
|
|
|
=head2 image_gd |
|
4703
|
|
|
|
|
|
|
|
|
4704
|
|
|
|
|
|
|
$gdf = $pdf->image_gd($gd_object, %opts) |
|
4705
|
|
|
|
|
|
|
|
|
4706
|
|
|
|
|
|
|
=over |
|
4707
|
|
|
|
|
|
|
|
|
4708
|
|
|
|
|
|
|
Imports and returns a new image object from Image::GD. |
|
4709
|
|
|
|
|
|
|
|
|
4710
|
|
|
|
|
|
|
See L<PDF::Builder::Resource::XObject::Image::GD> for additional information |
|
4711
|
|
|
|
|
|
|
and C<examples/Content.pl> for some examples of placing an image on a page |
|
4712
|
|
|
|
|
|
|
(JPEG, but the principle is the same). |
|
4713
|
|
|
|
|
|
|
|
|
4714
|
|
|
|
|
|
|
=back |
|
4715
|
|
|
|
|
|
|
|
|
4716
|
|
|
|
|
|
|
=cut |
|
4717
|
|
|
|
|
|
|
|
|
4718
|
|
|
|
|
|
|
sub image_gd { |
|
4719
|
0
|
|
|
0
|
1
|
0
|
my ($self, $gd, %opts) = @_; |
|
4720
|
|
|
|
|
|
|
|
|
4721
|
0
|
|
|
|
|
0
|
require PDF::Builder::Resource::XObject::Image::GD; |
|
4722
|
0
|
|
|
|
|
0
|
my $obj = PDF::Builder::Resource::XObject::Image::GD->new($self->{'pdf'}, $gd, %opts); |
|
4723
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
4724
|
|
|
|
|
|
|
|
|
4725
|
0
|
|
|
|
|
0
|
return $obj; |
|
4726
|
|
|
|
|
|
|
} |
|
4727
|
|
|
|
|
|
|
|
|
4728
|
|
|
|
|
|
|
=head1 COLORSPACE METHODS |
|
4729
|
|
|
|
|
|
|
|
|
4730
|
|
|
|
|
|
|
=head2 colorspace |
|
4731
|
|
|
|
|
|
|
|
|
4732
|
|
|
|
|
|
|
$colorspace = $pdf->colorspace($type, @arguments) |
|
4733
|
|
|
|
|
|
|
|
|
4734
|
|
|
|
|
|
|
=over |
|
4735
|
|
|
|
|
|
|
|
|
4736
|
|
|
|
|
|
|
Colorspaces can be added to a PDF to either specifically control the output |
|
4737
|
|
|
|
|
|
|
color on a particular device (spot colors, device colors) or to save space by |
|
4738
|
|
|
|
|
|
|
limiting the available colors to a defined color palette (web-safe palette, ACT |
|
4739
|
|
|
|
|
|
|
file). |
|
4740
|
|
|
|
|
|
|
|
|
4741
|
|
|
|
|
|
|
Once added to the PDF, they can be used in place of regular hex codes or named |
|
4742
|
|
|
|
|
|
|
colors: |
|
4743
|
|
|
|
|
|
|
|
|
4744
|
|
|
|
|
|
|
=back |
|
4745
|
|
|
|
|
|
|
|
|
4746
|
|
|
|
|
|
|
my $pdf = PDF::Builder->new(); |
|
4747
|
|
|
|
|
|
|
my $page = $pdf->page(); |
|
4748
|
|
|
|
|
|
|
my $content = $page->graphics(); |
|
4749
|
|
|
|
|
|
|
|
|
4750
|
|
|
|
|
|
|
# Add colorspaces for a spot color and the web-safe color palette |
|
4751
|
|
|
|
|
|
|
my $spot = $pdf->colorspace('spot', 'PANTONE Red 032 C', '#EF3340'); |
|
4752
|
|
|
|
|
|
|
my $web = $pdf->colorspace('web'); |
|
4753
|
|
|
|
|
|
|
|
|
4754
|
|
|
|
|
|
|
# Fill using the spot color with 100% coverage |
|
4755
|
|
|
|
|
|
|
$content->fill_color($spot, 1.0); |
|
4756
|
|
|
|
|
|
|
|
|
4757
|
|
|
|
|
|
|
# Stroke using the first color of the web-safe palette |
|
4758
|
|
|
|
|
|
|
$content->stroke_color($web, 0); |
|
4759
|
|
|
|
|
|
|
|
|
4760
|
|
|
|
|
|
|
# Add a rectangle to the page |
|
4761
|
|
|
|
|
|
|
$content->rectangle(100, 100, 200, 200); |
|
4762
|
|
|
|
|
|
|
$content->paint(); |
|
4763
|
|
|
|
|
|
|
|
|
4764
|
|
|
|
|
|
|
$pdf->save('sample.pdf'); |
|
4765
|
|
|
|
|
|
|
|
|
4766
|
|
|
|
|
|
|
=over |
|
4767
|
|
|
|
|
|
|
|
|
4768
|
|
|
|
|
|
|
The following types of colorspaces are supported |
|
4769
|
|
|
|
|
|
|
|
|
4770
|
|
|
|
|
|
|
=back |
|
4771
|
|
|
|
|
|
|
|
|
4772
|
|
|
|
|
|
|
=over |
|
4773
|
|
|
|
|
|
|
|
|
4774
|
|
|
|
|
|
|
=item spot |
|
4775
|
|
|
|
|
|
|
|
|
4776
|
|
|
|
|
|
|
Spot colors are used to instruct a device (usually a printer) to use or emulate |
|
4777
|
|
|
|
|
|
|
a particular ink color (C<$tint>) for parts of the document. An C<$alt_color> |
|
4778
|
|
|
|
|
|
|
is provided for devices (e.g. PDF viewers) that don't know how to produce the |
|
4779
|
|
|
|
|
|
|
named color. It can either be an approximation of the color in RGB, CMYK, or |
|
4780
|
|
|
|
|
|
|
HSV formats, or a wildly different color (e.g. 100% magenta, C<%0F00>) to make |
|
4781
|
|
|
|
|
|
|
it clear if the spot color isn't being used as expected. |
|
4782
|
|
|
|
|
|
|
|
|
4783
|
|
|
|
|
|
|
=back |
|
4784
|
|
|
|
|
|
|
|
|
4785
|
|
|
|
|
|
|
my $spot = $pdf->colorspace('spot', $tint, $alt_color); |
|
4786
|
|
|
|
|
|
|
|
|
4787
|
|
|
|
|
|
|
=over |
|
4788
|
|
|
|
|
|
|
|
|
4789
|
|
|
|
|
|
|
=item web |
|
4790
|
|
|
|
|
|
|
|
|
4791
|
|
|
|
|
|
|
The web-safe color palette is a historical collection of colors that was used |
|
4792
|
|
|
|
|
|
|
when many display devices only supported 256 colors. |
|
4793
|
|
|
|
|
|
|
|
|
4794
|
|
|
|
|
|
|
=back |
|
4795
|
|
|
|
|
|
|
|
|
4796
|
|
|
|
|
|
|
my $web = $pdf->colorspace('web'); |
|
4797
|
|
|
|
|
|
|
|
|
4798
|
|
|
|
|
|
|
=over |
|
4799
|
|
|
|
|
|
|
|
|
4800
|
|
|
|
|
|
|
=item act |
|
4801
|
|
|
|
|
|
|
|
|
4802
|
|
|
|
|
|
|
An Adobe Color Table (ACT) file provides a custom palette of colors that can be |
|
4803
|
|
|
|
|
|
|
referenced by PDF graphics and text drawing commands. |
|
4804
|
|
|
|
|
|
|
|
|
4805
|
|
|
|
|
|
|
=back |
|
4806
|
|
|
|
|
|
|
|
|
4807
|
|
|
|
|
|
|
my $act = $pdf->colorspace('act', $filename); |
|
4808
|
|
|
|
|
|
|
|
|
4809
|
|
|
|
|
|
|
=over |
|
4810
|
|
|
|
|
|
|
|
|
4811
|
|
|
|
|
|
|
=item device |
|
4812
|
|
|
|
|
|
|
|
|
4813
|
|
|
|
|
|
|
A device-specific colorspace allows for precise color output on a given device |
|
4814
|
|
|
|
|
|
|
(typically a printing press), bypassing the normal color interpretation |
|
4815
|
|
|
|
|
|
|
performed by raster image processors (RIPs). |
|
4816
|
|
|
|
|
|
|
|
|
4817
|
|
|
|
|
|
|
=back |
|
4818
|
|
|
|
|
|
|
|
|
4819
|
|
|
|
|
|
|
my $devicen = $pdf->colorspace('device', @colorspaces); |
|
4820
|
|
|
|
|
|
|
|
|
4821
|
|
|
|
|
|
|
=over |
|
4822
|
|
|
|
|
|
|
|
|
4823
|
|
|
|
|
|
|
Device colorspaces are also needed if you want to blend spot colors: |
|
4824
|
|
|
|
|
|
|
|
|
4825
|
|
|
|
|
|
|
=back |
|
4826
|
|
|
|
|
|
|
|
|
4827
|
|
|
|
|
|
|
my $pdf = PDF::Builder->new(); |
|
4828
|
|
|
|
|
|
|
my $page = $pdf->page(); |
|
4829
|
|
|
|
|
|
|
my $content = $page->graphics(); |
|
4830
|
|
|
|
|
|
|
|
|
4831
|
|
|
|
|
|
|
# Create a two-color device colorspace |
|
4832
|
|
|
|
|
|
|
my $yellow = $pdf->colorspace('spot', 'Yellow', '%00F0'); |
|
4833
|
|
|
|
|
|
|
my $spot = $pdf->colorspace('spot', 'PANTONE Red 032 C', '#EF3340'); |
|
4834
|
|
|
|
|
|
|
my $device = $pdf->colorspace('device', $yellow, $spot); |
|
4835
|
|
|
|
|
|
|
|
|
4836
|
|
|
|
|
|
|
# Fill using a blend of 25% yellow and 75% spot color |
|
4837
|
|
|
|
|
|
|
$content->fill_color($device, 0.25, 0.75); |
|
4838
|
|
|
|
|
|
|
|
|
4839
|
|
|
|
|
|
|
# Stroke using 100% spot color |
|
4840
|
|
|
|
|
|
|
$content->stroke_color($device, 0, 1); |
|
4841
|
|
|
|
|
|
|
|
|
4842
|
|
|
|
|
|
|
# Add a rectangle to the page |
|
4843
|
|
|
|
|
|
|
$content->rectangle(100, 100, 200, 200); |
|
4844
|
|
|
|
|
|
|
$content->paint(); |
|
4845
|
|
|
|
|
|
|
|
|
4846
|
|
|
|
|
|
|
$pdf->save('sample.pdf'); |
|
4847
|
|
|
|
|
|
|
|
|
4848
|
|
|
|
|
|
|
=cut |
|
4849
|
|
|
|
|
|
|
|
|
4850
|
|
|
|
|
|
|
sub colorspace { |
|
4851
|
0
|
|
|
0
|
1
|
0
|
my $self = shift(); |
|
4852
|
0
|
|
|
|
|
0
|
my $type = shift(); |
|
4853
|
|
|
|
|
|
|
|
|
4854
|
0
|
0
|
|
|
|
0
|
if ($type eq 'act') { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
4855
|
0
|
|
|
|
|
0
|
my $file = shift(); |
|
4856
|
0
|
|
|
|
|
0
|
return $self->colorspace_act($file); |
|
4857
|
|
|
|
|
|
|
} elsif ($type eq 'web') { |
|
4858
|
0
|
|
|
|
|
0
|
return $self->colorspace_web(); |
|
4859
|
|
|
|
|
|
|
} elsif ($type eq 'hue') { |
|
4860
|
|
|
|
|
|
|
# This type is undocumented until either a reference can be found for |
|
4861
|
|
|
|
|
|
|
# this being a standard palette like the web color palette, or POD is |
|
4862
|
|
|
|
|
|
|
# added to the Hue colorspace class that describes how to use it. |
|
4863
|
0
|
|
|
|
|
0
|
return $self->colorspace_hue(); |
|
4864
|
|
|
|
|
|
|
} elsif ($type eq 'spot') { |
|
4865
|
0
|
|
|
|
|
0
|
my $name = shift(); |
|
4866
|
0
|
|
|
|
|
0
|
my $alt_color = shift(); |
|
4867
|
0
|
|
|
|
|
0
|
return $self->colorspace_separation($name, $alt_color); |
|
4868
|
|
|
|
|
|
|
} elsif ($type eq 'device') { |
|
4869
|
0
|
|
|
|
|
0
|
my @colors = @_; |
|
4870
|
0
|
|
|
|
|
0
|
return $self->colorspace_devicen(\@colors); |
|
4871
|
|
|
|
|
|
|
} else { |
|
4872
|
0
|
|
|
|
|
0
|
croak "Unrecognized or unsupported colorspace: $type"; |
|
4873
|
|
|
|
|
|
|
} |
|
4874
|
|
|
|
|
|
|
} |
|
4875
|
|
|
|
|
|
|
|
|
4876
|
|
|
|
|
|
|
=head2 colorspace_act |
|
4877
|
|
|
|
|
|
|
|
|
4878
|
|
|
|
|
|
|
$cs = $pdf->colorspace_act($file) |
|
4879
|
|
|
|
|
|
|
|
|
4880
|
|
|
|
|
|
|
=over |
|
4881
|
|
|
|
|
|
|
|
|
4882
|
|
|
|
|
|
|
Returns a new colorspace object based on an Adobe Color Table file. |
|
4883
|
|
|
|
|
|
|
|
|
4884
|
|
|
|
|
|
|
See L<PDF::Builder::Resource::ColorSpace::Indexed::ACTFile> for a |
|
4885
|
|
|
|
|
|
|
reference to the file format's specification. |
|
4886
|
|
|
|
|
|
|
|
|
4887
|
|
|
|
|
|
|
=back |
|
4888
|
|
|
|
|
|
|
|
|
4889
|
|
|
|
|
|
|
=cut |
|
4890
|
|
|
|
|
|
|
|
|
4891
|
|
|
|
|
|
|
sub colorspace_act { |
|
4892
|
0
|
|
|
0
|
1
|
0
|
my ($self, $file) = @_; |
|
4893
|
|
|
|
|
|
|
|
|
4894
|
0
|
|
|
|
|
0
|
require PDF::Builder::Resource::ColorSpace::Indexed::ACTFile; |
|
4895
|
0
|
|
|
|
|
0
|
return PDF::Builder::Resource::ColorSpace::Indexed::ACTFile->new($self->{'pdf'}, $file); |
|
4896
|
|
|
|
|
|
|
} |
|
4897
|
|
|
|
|
|
|
|
|
4898
|
|
|
|
|
|
|
=head2 colorspace_web |
|
4899
|
|
|
|
|
|
|
|
|
4900
|
|
|
|
|
|
|
$cs = $pdf->colorspace_web() |
|
4901
|
|
|
|
|
|
|
|
|
4902
|
|
|
|
|
|
|
=over |
|
4903
|
|
|
|
|
|
|
|
|
4904
|
|
|
|
|
|
|
Returns a new colorspace-object based on the "web-safe" color palette. |
|
4905
|
|
|
|
|
|
|
|
|
4906
|
|
|
|
|
|
|
=back |
|
4907
|
|
|
|
|
|
|
|
|
4908
|
|
|
|
|
|
|
=cut |
|
4909
|
|
|
|
|
|
|
|
|
4910
|
|
|
|
|
|
|
sub colorspace_web { |
|
4911
|
1
|
|
|
1
|
1
|
7
|
my ($self) = @_; |
|
4912
|
|
|
|
|
|
|
|
|
4913
|
1
|
|
|
|
|
525
|
require PDF::Builder::Resource::ColorSpace::Indexed::WebColor; |
|
4914
|
1
|
|
|
|
|
20
|
return PDF::Builder::Resource::ColorSpace::Indexed::WebColor->new($self->{'pdf'}); |
|
4915
|
|
|
|
|
|
|
} |
|
4916
|
|
|
|
|
|
|
|
|
4917
|
|
|
|
|
|
|
=head2 colorspace_hue |
|
4918
|
|
|
|
|
|
|
|
|
4919
|
|
|
|
|
|
|
$cs = $pdf->colorspace_hue() |
|
4920
|
|
|
|
|
|
|
|
|
4921
|
|
|
|
|
|
|
=over |
|
4922
|
|
|
|
|
|
|
|
|
4923
|
|
|
|
|
|
|
Returns a new colorspace-object based on the hue color palette. |
|
4924
|
|
|
|
|
|
|
|
|
4925
|
|
|
|
|
|
|
See L<PDF::Builder::Resource::ColorSpace::Indexed::Hue> for an explanation. |
|
4926
|
|
|
|
|
|
|
|
|
4927
|
|
|
|
|
|
|
=back |
|
4928
|
|
|
|
|
|
|
|
|
4929
|
|
|
|
|
|
|
=cut |
|
4930
|
|
|
|
|
|
|
|
|
4931
|
|
|
|
|
|
|
sub colorspace_hue { |
|
4932
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
|
4933
|
|
|
|
|
|
|
|
|
4934
|
0
|
|
|
|
|
0
|
require PDF::Builder::Resource::ColorSpace::Indexed::Hue; |
|
4935
|
0
|
|
|
|
|
0
|
return PDF::Builder::Resource::ColorSpace::Indexed::Hue->new($self->{'pdf'}); |
|
4936
|
|
|
|
|
|
|
} |
|
4937
|
|
|
|
|
|
|
|
|
4938
|
|
|
|
|
|
|
=head2 colorspace_separation |
|
4939
|
|
|
|
|
|
|
|
|
4940
|
|
|
|
|
|
|
$cs = $pdf->colorspace_separation($tint, $color) |
|
4941
|
|
|
|
|
|
|
|
|
4942
|
|
|
|
|
|
|
=over |
|
4943
|
|
|
|
|
|
|
|
|
4944
|
|
|
|
|
|
|
Returns a new separation colorspace object based on the parameters. |
|
4945
|
|
|
|
|
|
|
|
|
4946
|
|
|
|
|
|
|
I<$tint> can be any valid ink identifier, including but not limited |
|
4947
|
|
|
|
|
|
|
to: 'Cyan', 'Magenta', 'Yellow', 'Black', 'Red', 'Green', 'Blue' or |
|
4948
|
|
|
|
|
|
|
'Orange'. |
|
4949
|
|
|
|
|
|
|
|
|
4950
|
|
|
|
|
|
|
I<$color> must be a valid color specification limited to: '#rrggbb', |
|
4951
|
|
|
|
|
|
|
'!hhssvv', '%ccmmyykk' or a "named color" (rgb). |
|
4952
|
|
|
|
|
|
|
|
|
4953
|
|
|
|
|
|
|
The colorspace model will automatically be chosen based on the |
|
4954
|
|
|
|
|
|
|
specified color. |
|
4955
|
|
|
|
|
|
|
|
|
4956
|
|
|
|
|
|
|
=back |
|
4957
|
|
|
|
|
|
|
|
|
4958
|
|
|
|
|
|
|
=cut |
|
4959
|
|
|
|
|
|
|
|
|
4960
|
|
|
|
|
|
|
sub colorspace_separation { |
|
4961
|
0
|
|
|
0
|
1
|
0
|
my ($self, $tint, @clr) = @_; |
|
4962
|
|
|
|
|
|
|
|
|
4963
|
0
|
|
|
|
|
0
|
require PDF::Builder::Resource::ColorSpace::Separation; |
|
4964
|
0
|
|
|
|
|
0
|
return PDF::Builder::Resource::ColorSpace::Separation->new($self->{'pdf'}, |
|
4965
|
|
|
|
|
|
|
pdfkey(), |
|
4966
|
|
|
|
|
|
|
$tint, |
|
4967
|
|
|
|
|
|
|
@clr); |
|
4968
|
|
|
|
|
|
|
} |
|
4969
|
|
|
|
|
|
|
|
|
4970
|
|
|
|
|
|
|
=head2 colorspace_devicen |
|
4971
|
|
|
|
|
|
|
|
|
4972
|
|
|
|
|
|
|
$cs = $pdf->colorspace_devicen(\@tintCSx, $samples) |
|
4973
|
|
|
|
|
|
|
|
|
4974
|
|
|
|
|
|
|
$cs = $pdf->colorspace_devicen(\@tintCSx) |
|
4975
|
|
|
|
|
|
|
|
|
4976
|
|
|
|
|
|
|
=over |
|
4977
|
|
|
|
|
|
|
|
|
4978
|
|
|
|
|
|
|
Returns a new DeviceN colorspace object based on the parameters. |
|
4979
|
|
|
|
|
|
|
|
|
4980
|
|
|
|
|
|
|
B<Example:> |
|
4981
|
|
|
|
|
|
|
|
|
4982
|
|
|
|
|
|
|
=back |
|
4983
|
|
|
|
|
|
|
|
|
4984
|
|
|
|
|
|
|
$cy = $pdf->colorspace_separation('Cyan', '%f000'); |
|
4985
|
|
|
|
|
|
|
$ma = $pdf->colorspace_separation('Magenta', '%0f00'); |
|
4986
|
|
|
|
|
|
|
$ye = $pdf->colorspace_separation('Yellow', '%00f0'); |
|
4987
|
|
|
|
|
|
|
$bk = $pdf->colorspace_separation('Black', '%000f'); |
|
4988
|
|
|
|
|
|
|
|
|
4989
|
|
|
|
|
|
|
$pms023 = $pdf->colorspace_separation('PANTONE 032CV', '%0ff0'); |
|
4990
|
|
|
|
|
|
|
|
|
4991
|
|
|
|
|
|
|
$dncs = $pdf->colorspace_devicen( [ $cy,$ma,$ye,$bk, $pms023 ] ); |
|
4992
|
|
|
|
|
|
|
|
|
4993
|
|
|
|
|
|
|
=over |
|
4994
|
|
|
|
|
|
|
|
|
4995
|
|
|
|
|
|
|
The colorspace model will automatically be chosen based on the first |
|
4996
|
|
|
|
|
|
|
colorspace specified. |
|
4997
|
|
|
|
|
|
|
|
|
4998
|
|
|
|
|
|
|
=back |
|
4999
|
|
|
|
|
|
|
|
|
5000
|
|
|
|
|
|
|
=cut |
|
5001
|
|
|
|
|
|
|
|
|
5002
|
|
|
|
|
|
|
sub colorspace_devicen { |
|
5003
|
0
|
|
|
0
|
1
|
0
|
my ($self, $clrs, $samples) = @_; |
|
5004
|
0
|
|
0
|
|
|
0
|
$samples ||= 2; |
|
5005
|
|
|
|
|
|
|
|
|
5006
|
0
|
|
|
|
|
0
|
require PDF::Builder::Resource::ColorSpace::DeviceN; |
|
5007
|
0
|
|
|
|
|
0
|
return PDF::Builder::Resource::ColorSpace::DeviceN->new($self->{'pdf'}, |
|
5008
|
|
|
|
|
|
|
pdfkey(), |
|
5009
|
|
|
|
|
|
|
$clrs, |
|
5010
|
|
|
|
|
|
|
$samples); |
|
5011
|
|
|
|
|
|
|
} |
|
5012
|
|
|
|
|
|
|
|
|
5013
|
|
|
|
|
|
|
=head1 BARCODE METHODS |
|
5014
|
|
|
|
|
|
|
|
|
5015
|
|
|
|
|
|
|
These are glue routines to the actual barcode rendering routines found |
|
5016
|
|
|
|
|
|
|
elsewhere. |
|
5017
|
|
|
|
|
|
|
|
|
5018
|
|
|
|
|
|
|
=head2 xo_* Bar Code routines |
|
5019
|
|
|
|
|
|
|
|
|
5020
|
|
|
|
|
|
|
$bc = $pdf->xo_codabar(%opts) |
|
5021
|
|
|
|
|
|
|
|
|
5022
|
|
|
|
|
|
|
$bc = $pdf->xo_code128(%opts) |
|
5023
|
|
|
|
|
|
|
|
|
5024
|
|
|
|
|
|
|
$bc = $pdf->xo_2of5int(%opts) |
|
5025
|
|
|
|
|
|
|
|
|
5026
|
|
|
|
|
|
|
$bc = $pdf->xo_3of9(%opts) |
|
5027
|
|
|
|
|
|
|
|
|
5028
|
|
|
|
|
|
|
$bc = $pdf->xo_ean13(%opts) |
|
5029
|
|
|
|
|
|
|
|
|
5030
|
|
|
|
|
|
|
=over |
|
5031
|
|
|
|
|
|
|
|
|
5032
|
|
|
|
|
|
|
Creates the specified barcode object as a form XObject. |
|
5033
|
|
|
|
|
|
|
|
|
5034
|
|
|
|
|
|
|
=back |
|
5035
|
|
|
|
|
|
|
|
|
5036
|
|
|
|
|
|
|
=cut |
|
5037
|
|
|
|
|
|
|
|
|
5038
|
|
|
|
|
|
|
# TBD PDF::API2 now has a convenience function to handle all the barcodes, |
|
5039
|
|
|
|
|
|
|
# but still keeps all the existing barcodes |
|
5040
|
|
|
|
|
|
|
# |
|
5041
|
|
|
|
|
|
|
# TBD consider moving these to a BarCodes subdirectory, as the number of bar |
|
5042
|
|
|
|
|
|
|
# code routines increases |
|
5043
|
|
|
|
|
|
|
|
|
5044
|
|
|
|
|
|
|
sub xo_code128 { |
|
5045
|
1
|
|
|
1
|
0
|
714
|
my ($self, @opts) = @_; |
|
5046
|
|
|
|
|
|
|
|
|
5047
|
1
|
|
|
|
|
828
|
require PDF::Builder::Resource::XObject::Form::BarCode::code128; |
|
5048
|
1
|
|
|
|
|
10
|
my $obj = PDF::Builder::Resource::XObject::Form::BarCode::code128->new($self->{'pdf'}, @opts); |
|
5049
|
1
|
|
|
|
|
9
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
5050
|
|
|
|
|
|
|
|
|
5051
|
1
|
|
|
|
|
5
|
return $obj; |
|
5052
|
|
|
|
|
|
|
} |
|
5053
|
|
|
|
|
|
|
|
|
5054
|
|
|
|
|
|
|
sub xo_codabar { |
|
5055
|
1
|
|
|
1
|
0
|
27
|
my ($self, @opts) = @_; |
|
5056
|
|
|
|
|
|
|
|
|
5057
|
1
|
|
|
|
|
828
|
require PDF::Builder::Resource::XObject::Form::BarCode::codabar; |
|
5058
|
1
|
|
|
|
|
15
|
my $obj = PDF::Builder::Resource::XObject::Form::BarCode::codabar->new($self->{'pdf'}, @opts); |
|
5059
|
1
|
|
|
|
|
8
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
5060
|
|
|
|
|
|
|
|
|
5061
|
1
|
|
|
|
|
4
|
return $obj; |
|
5062
|
|
|
|
|
|
|
} |
|
5063
|
|
|
|
|
|
|
|
|
5064
|
|
|
|
|
|
|
sub xo_2of5int { |
|
5065
|
1
|
|
|
1
|
0
|
1282
|
my ($self, @opts) = @_; |
|
5066
|
|
|
|
|
|
|
|
|
5067
|
1
|
|
|
|
|
853
|
require PDF::Builder::Resource::XObject::Form::BarCode::int2of5; |
|
5068
|
1
|
|
|
|
|
10
|
my $obj = PDF::Builder::Resource::XObject::Form::BarCode::int2of5->new($self->{'pdf'}, @opts); |
|
5069
|
1
|
|
|
|
|
9
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
5070
|
|
|
|
|
|
|
|
|
5071
|
1
|
|
|
|
|
4
|
return $obj; |
|
5072
|
|
|
|
|
|
|
} |
|
5073
|
|
|
|
|
|
|
|
|
5074
|
|
|
|
|
|
|
sub xo_3of9 { |
|
5075
|
2
|
|
|
2
|
0
|
1142
|
my ($self, @opts) = @_; |
|
5076
|
|
|
|
|
|
|
|
|
5077
|
2
|
|
|
|
|
832
|
require PDF::Builder::Resource::XObject::Form::BarCode::code3of9; |
|
5078
|
2
|
|
|
|
|
23
|
my $obj = PDF::Builder::Resource::XObject::Form::BarCode::code3of9->new($self->{'pdf'}, @opts); |
|
5079
|
2
|
|
|
|
|
16
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
5080
|
|
|
|
|
|
|
|
|
5081
|
2
|
|
|
|
|
8
|
return $obj; |
|
5082
|
|
|
|
|
|
|
} |
|
5083
|
|
|
|
|
|
|
|
|
5084
|
|
|
|
|
|
|
sub xo_ean13 { |
|
5085
|
1
|
|
|
1
|
0
|
1163
|
my ($self, @opts) = @_; |
|
5086
|
|
|
|
|
|
|
|
|
5087
|
1
|
|
|
|
|
875
|
require PDF::Builder::Resource::XObject::Form::BarCode::ean13; |
|
5088
|
1
|
|
|
|
|
8
|
my $obj = PDF::Builder::Resource::XObject::Form::BarCode::ean13->new($self->{'pdf'}, @opts); |
|
5089
|
1
|
|
|
|
|
12
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
5090
|
|
|
|
|
|
|
|
|
5091
|
1
|
|
|
|
|
6
|
return $obj; |
|
5092
|
|
|
|
|
|
|
} |
|
5093
|
|
|
|
|
|
|
|
|
5094
|
|
|
|
|
|
|
=head1 OTHER METHODS |
|
5095
|
|
|
|
|
|
|
|
|
5096
|
|
|
|
|
|
|
=head2 xo_form |
|
5097
|
|
|
|
|
|
|
|
|
5098
|
|
|
|
|
|
|
$xo = $pdf->xo_form() |
|
5099
|
|
|
|
|
|
|
|
|
5100
|
|
|
|
|
|
|
=over |
|
5101
|
|
|
|
|
|
|
|
|
5102
|
|
|
|
|
|
|
Returns a new form XObject. |
|
5103
|
|
|
|
|
|
|
|
|
5104
|
|
|
|
|
|
|
=back |
|
5105
|
|
|
|
|
|
|
|
|
5106
|
|
|
|
|
|
|
=cut |
|
5107
|
|
|
|
|
|
|
|
|
5108
|
|
|
|
|
|
|
sub xo_form { |
|
5109
|
4
|
|
|
4
|
1
|
11
|
my $self = shift(); |
|
5110
|
|
|
|
|
|
|
|
|
5111
|
4
|
|
|
|
|
72
|
my $obj = PDF::Builder::Resource::XObject::Form::Hybrid->new($self->{'pdf'}); |
|
5112
|
4
|
|
|
|
|
32
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
5113
|
|
|
|
|
|
|
|
|
5114
|
4
|
|
|
|
|
11
|
return $obj; |
|
5115
|
|
|
|
|
|
|
} |
|
5116
|
|
|
|
|
|
|
|
|
5117
|
|
|
|
|
|
|
=head2 egstate |
|
5118
|
|
|
|
|
|
|
|
|
5119
|
|
|
|
|
|
|
$egs = $pdf->egstate() |
|
5120
|
|
|
|
|
|
|
|
|
5121
|
|
|
|
|
|
|
=over |
|
5122
|
|
|
|
|
|
|
|
|
5123
|
|
|
|
|
|
|
Returns a new extended graphics state object, as described |
|
5124
|
|
|
|
|
|
|
in L<PDF::Builder::Resource::ExtGState>. |
|
5125
|
|
|
|
|
|
|
|
|
5126
|
|
|
|
|
|
|
=back |
|
5127
|
|
|
|
|
|
|
|
|
5128
|
|
|
|
|
|
|
=cut |
|
5129
|
|
|
|
|
|
|
|
|
5130
|
|
|
|
|
|
|
sub egstate { |
|
5131
|
3
|
|
|
3
|
1
|
18
|
my $self = shift(); |
|
5132
|
|
|
|
|
|
|
|
|
5133
|
3
|
|
|
|
|
21
|
my $obj = PDF::Builder::Resource::ExtGState->new($self->{'pdf'}, pdfkey()); |
|
5134
|
3
|
|
|
|
|
13
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
5135
|
|
|
|
|
|
|
|
|
5136
|
3
|
|
|
|
|
16
|
return $obj; |
|
5137
|
|
|
|
|
|
|
} |
|
5138
|
|
|
|
|
|
|
|
|
5139
|
|
|
|
|
|
|
=head2 pattern |
|
5140
|
|
|
|
|
|
|
|
|
5141
|
|
|
|
|
|
|
$obj = $pdf->pattern(%opts) |
|
5142
|
|
|
|
|
|
|
|
|
5143
|
|
|
|
|
|
|
=over |
|
5144
|
|
|
|
|
|
|
|
|
5145
|
|
|
|
|
|
|
Returns a new pattern object. |
|
5146
|
|
|
|
|
|
|
|
|
5147
|
|
|
|
|
|
|
=back |
|
5148
|
|
|
|
|
|
|
|
|
5149
|
|
|
|
|
|
|
=cut |
|
5150
|
|
|
|
|
|
|
|
|
5151
|
|
|
|
|
|
|
sub pattern { |
|
5152
|
0
|
|
|
0
|
1
|
0
|
my ($self, %opts) = @_; |
|
5153
|
|
|
|
|
|
|
|
|
5154
|
0
|
|
|
|
|
0
|
my $obj = PDF::Builder::Resource::Pattern->new($self->{'pdf'}, undef, %opts); |
|
5155
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
5156
|
|
|
|
|
|
|
|
|
5157
|
0
|
|
|
|
|
0
|
return $obj; |
|
5158
|
|
|
|
|
|
|
} |
|
5159
|
|
|
|
|
|
|
|
|
5160
|
|
|
|
|
|
|
=head2 shading |
|
5161
|
|
|
|
|
|
|
|
|
5162
|
|
|
|
|
|
|
$obj = $pdf->shading(%opts) |
|
5163
|
|
|
|
|
|
|
|
|
5164
|
|
|
|
|
|
|
=over |
|
5165
|
|
|
|
|
|
|
|
|
5166
|
|
|
|
|
|
|
Returns a new shading object. |
|
5167
|
|
|
|
|
|
|
|
|
5168
|
|
|
|
|
|
|
=back |
|
5169
|
|
|
|
|
|
|
|
|
5170
|
|
|
|
|
|
|
=cut |
|
5171
|
|
|
|
|
|
|
|
|
5172
|
|
|
|
|
|
|
sub shading { |
|
5173
|
0
|
|
|
0
|
1
|
0
|
my ($self, %opts) = @_; |
|
5174
|
|
|
|
|
|
|
|
|
5175
|
0
|
|
|
|
|
0
|
my $obj = PDF::Builder::Resource::Shading->new($self->{'pdf'}, undef, %opts); |
|
5176
|
0
|
|
|
|
|
0
|
$self->{'pdf'}->out_obj($self->{'pages'}); |
|
5177
|
|
|
|
|
|
|
|
|
5178
|
0
|
|
|
|
|
0
|
return $obj; |
|
5179
|
|
|
|
|
|
|
} |
|
5180
|
|
|
|
|
|
|
|
|
5181
|
|
|
|
|
|
|
=head2 named_destination |
|
5182
|
|
|
|
|
|
|
|
|
5183
|
|
|
|
|
|
|
$ndest = $pdf->named_destination($cat, $name, $obj) |
|
5184
|
|
|
|
|
|
|
|
|
5185
|
|
|
|
|
|
|
=over |
|
5186
|
|
|
|
|
|
|
|
|
5187
|
|
|
|
|
|
|
Returns a new named destination object. C<$cat> is the category, |
|
5188
|
|
|
|
|
|
|
and is normally the string C<'Dests'> (it's a PDF keyword). The C<$name> is |
|
5189
|
|
|
|
|
|
|
the B<unique> (within an entire PDF document) name, such as "foo" in the |
|
5190
|
|
|
|
|
|
|
example below. |
|
5191
|
|
|
|
|
|
|
|
|
5192
|
|
|
|
|
|
|
See L<PDF::Builder::NamedDestination> for more information. |
|
5193
|
|
|
|
|
|
|
|
|
5194
|
|
|
|
|
|
|
B<Example:> |
|
5195
|
|
|
|
|
|
|
|
|
5196
|
|
|
|
|
|
|
=back |
|
5197
|
|
|
|
|
|
|
|
|
5198
|
|
|
|
|
|
|
my $dest = PDF::Builder::NamedDestination->new($pdf); |
|
5199
|
|
|
|
|
|
|
#$dest->goto($page, 'xyz' => [undef, undef, undef]); old style |
|
5200
|
|
|
|
|
|
|
$dest->goto($page, 'xyz', (undef, undef, undef)); |
|
5201
|
|
|
|
|
|
|
$pdf->named_destination('Dests', 'foo', $dest); |
|
5202
|
|
|
|
|
|
|
|
|
5203
|
|
|
|
|
|
|
=cut |
|
5204
|
|
|
|
|
|
|
|
|
5205
|
|
|
|
|
|
|
sub named_destination { |
|
5206
|
1
|
|
|
1
|
1
|
10
|
my ($self, $cat, $name, $obj) = @_; |
|
5207
|
1
|
|
|
|
|
3
|
my $root = $self->{'catalog'}; |
|
5208
|
|
|
|
|
|
|
|
|
5209
|
1
|
|
33
|
|
|
56
|
$root->{'Names'} ||= PDFDict(); |
|
5210
|
1
|
|
33
|
|
|
10
|
$root->{'Names'}->{$cat} ||= PDFDict(); |
|
5211
|
1
|
|
50
|
|
|
7
|
$root->{'Names'}->{$cat}->{'-vals'} ||= {}; |
|
5212
|
1
|
|
33
|
|
|
7
|
$root->{'Names'}->{$cat}->{'Limits'} ||= PDFArray(); |
|
5213
|
1
|
|
33
|
|
|
16
|
$root->{'Names'}->{$cat}->{'Names'} ||= PDFArray(); |
|
5214
|
|
|
|
|
|
|
|
|
5215
|
1
|
50
|
|
|
|
4
|
unless (defined $obj) { |
|
5216
|
0
|
|
|
|
|
0
|
$obj = PDF::Builder::NamedDestination->new($self->{'pdf'}); |
|
5217
|
|
|
|
|
|
|
} |
|
5218
|
1
|
|
|
|
|
30
|
$root->{'Names'}->{$cat}->{'-vals'}->{$name} = $obj; |
|
5219
|
|
|
|
|
|
|
|
|
5220
|
1
|
|
|
|
|
3
|
my @names = sort {$a cmp $b} keys %{$root->{'Names'}->{$cat}->{'-vals'}}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
1
|
|
|
|
|
7
|
|
|
5221
|
|
|
|
|
|
|
|
|
5222
|
1
|
|
|
|
|
5
|
$root->{'Names'}->{$cat}->{'Limits'}->{' val'}->[0] = PDFString($names[0], 'n'); |
|
5223
|
1
|
|
|
|
|
3
|
$root->{'Names'}->{$cat}->{'Limits'}->{' val'}->[1] = PDFString($names[-1], 'n'); |
|
5224
|
|
|
|
|
|
|
|
|
5225
|
1
|
|
|
|
|
4
|
@{$root->{'Names'}->{$cat}->{'Names'}->{' val'}} = (); |
|
|
1
|
|
|
|
|
6
|
|
|
5226
|
|
|
|
|
|
|
|
|
5227
|
1
|
|
|
|
|
4
|
foreach my $k (@names) { |
|
5228
|
1
|
|
|
|
|
22
|
push @{$root->{'Names'}->{$cat}->{'Names'}->{' val'}}, |
|
5229
|
|
|
|
|
|
|
( PDFString($k, 'n'), |
|
5230
|
1
|
|
|
|
|
4
|
$root->{'Names'}->{$cat}->{'-vals'}->{$k} |
|
5231
|
|
|
|
|
|
|
); |
|
5232
|
|
|
|
|
|
|
} |
|
5233
|
|
|
|
|
|
|
|
|
5234
|
1
|
|
|
|
|
6
|
return $obj; |
|
5235
|
|
|
|
|
|
|
} # end of named_destination() |
|
5236
|
|
|
|
|
|
|
|
|
5237
|
|
|
|
|
|
|
=head2 init_state() |
|
5238
|
|
|
|
|
|
|
|
|
5239
|
|
|
|
|
|
|
Initialize 'state' variable that carries information across multiple |
|
5240
|
|
|
|
|
|
|
document passes for C<column()> call. |
|
5241
|
|
|
|
|
|
|
See L<PDF::Builder::Content::Column_docs> for documentation. |
|
5242
|
|
|
|
|
|
|
|
|
5243
|
|
|
|
|
|
|
=cut |
|
5244
|
|
|
|
|
|
|
|
|
5245
|
|
|
|
|
|
|
# initialize state holder hash |
|
5246
|
|
|
|
|
|
|
sub init_state { |
|
5247
|
0
|
|
|
0
|
1
|
0
|
my ($self, $lists) = @_; |
|
5248
|
|
|
|
|
|
|
|
|
5249
|
0
|
|
|
|
|
0
|
my %state = (); |
|
5250
|
0
|
|
|
|
|
0
|
$state{'settings'} = {}; # hold settings between column() calls, TBD |
|
5251
|
|
|
|
|
|
|
# remember: multiple xrefs may point to the same target xreft, so no |
|
5252
|
|
|
|
|
|
|
# way to automatically point back to link source in xrefs! |
|
5253
|
|
|
|
|
|
|
# self-contained links (Named Destination, physical page) will |
|
5254
|
|
|
|
|
|
|
# have a '#' or '##' target id and not match an xreft list entry |
|
5255
|
|
|
|
|
|
|
# self-contained links have xrefs entry with or without a |
|
5256
|
|
|
|
|
|
|
# filepath (for external or internal links, respectively) |
|
5257
|
0
|
|
|
|
|
0
|
$state{'sindex'} = 0; # current size/next write of xrefs array |
|
5258
|
0
|
|
|
|
|
0
|
$state{'xrefs'} = []; # source (<_ref>) link data |
|
5259
|
|
|
|
|
|
|
# each array element is an anonymous hash containing: |
|
5260
|
|
|
|
|
|
|
# |
|
5261
|
|
|
|
|
|
|
# {'id'} target's id ('#ND' or '##ppn if self-contained link) |
|
5262
|
|
|
|
|
|
|
# {'tfn'} filepath (final position and name) for external links |
|
5263
|
|
|
|
|
|
|
# give for all links, even if internal, to permit external linking |
|
5264
|
|
|
|
|
|
|
# {'tppn'} physical page number of target |
|
5265
|
|
|
|
|
|
|
# {'sppn'} physical page number of source |
|
5266
|
|
|
|
|
|
|
# {'fit'} fit information ('' if not given) |
|
5267
|
|
|
|
|
|
|
# {'tfpn'} formatted page number of target |
|
5268
|
|
|
|
|
|
|
# {'page_numbers'} TBD in case want to override global default |
|
5269
|
|
|
|
|
|
|
# {'other_pg'} # other page text ("on page N", "on facing page", etc.) |
|
5270
|
|
|
|
|
|
|
# if $page_numbers > 0 (TBD) |
|
5271
|
|
|
|
|
|
|
# {'prev_other_pg'}* see if 'other_pg' changed |
|
5272
|
|
|
|
|
|
|
# {'tx'} and {'ty'} location on page of target |
|
5273
|
|
|
|
|
|
|
# {'title'} title= or natural text for link |
|
5274
|
|
|
|
|
|
|
# if none found yet, '[no title text]' is used |
|
5275
|
|
|
|
|
|
|
# for Index, user-defined term |
|
5276
|
|
|
|
|
|
|
# {'tag'} # tag (type) that produced this target |
|
5277
|
|
|
|
|
|
|
# useful for formatting TOC, etc |
|
5278
|
|
|
|
|
|
|
# {'click'} [] of click area(s) for this _ref, each [sppn, [x,y, x,y]] |
|
5279
|
|
|
|
|
|
|
# |
|
5280
|
|
|
|
|
|
|
# * = for discovering changes to visible text, requiring another pass |
|
5281
|
0
|
|
|
|
|
0
|
$state{'xreft'} = (); # target (<_reft> et al.) link data |
|
5282
|
|
|
|
|
|
|
# |
|
5283
|
|
|
|
|
|
|
# {$listname} e.g., '_reft', 'TOC', etc. |
|
5284
|
|
|
|
|
|
|
# {'id'} target id= |
|
5285
|
|
|
|
|
|
|
# {'tfn'} filepath (final position and name) for external links |
|
5286
|
|
|
|
|
|
|
# give for all links, even if internal, to permit external linking |
|
5287
|
|
|
|
|
|
|
# {'tppn'}* physical page number of target |
|
5288
|
|
|
|
|
|
|
# {'sppn'}* physical page number of source |
|
5289
|
|
|
|
|
|
|
# {'tfpn'}* formatted page number of target |
|
5290
|
|
|
|
|
|
|
# used if $page_number > 0 (TBD) |
|
5291
|
|
|
|
|
|
|
# {'tx'}* and {'ty'}* location on page of target |
|
5292
|
|
|
|
|
|
|
# {'title'} title= or natural text for link |
|
5293
|
|
|
|
|
|
|
# if none found yet, '[no title text]' is used |
|
5294
|
|
|
|
|
|
|
# copied to xrefs entry if it does not have its own title |
|
5295
|
|
|
|
|
|
|
# {'tag'} tag (type) that produced this entry |
|
5296
|
|
|
|
|
|
|
# useful for formatting TOC, etc. |
|
5297
|
|
|
|
|
|
|
# |
|
5298
|
|
|
|
|
|
|
# * liable to change as text shifts around. copy to xrefs. if visible |
|
5299
|
|
|
|
|
|
|
# change (change to title and/or formatted page number) -- will need |
|
5300
|
|
|
|
|
|
|
# another pass (see 'changed_target') |
|
5301
|
0
|
|
|
|
|
0
|
$state{'changed_target'} = {}; # list of tgtids whose data changed |
|
5302
|
|
|
|
|
|
|
# enough (AFTER the last text output by xrefs) to change the printed |
|
5303
|
|
|
|
|
|
|
# content and thus require another pass |
|
5304
|
0
|
|
|
|
|
0
|
$state{'tag_lists'} = {}; # user-defined lists of tags, e.g., TOC for |
|
5305
|
|
|
|
|
|
|
# {$list_name} = [ tag1, tag2, ... ] |
|
5306
|
|
|
|
|
|
|
# to define what tags (with ids) get listed as targets. |
|
5307
|
|
|
|
|
|
|
# _reft is predefined with '_reft' for use as <_ref> tgtids. |
|
5308
|
|
|
|
|
|
|
# add TOC for table of contents, Index for index, LoT for List of |
|
5309
|
|
|
|
|
|
|
# Tables, etc. |
|
5310
|
0
|
|
|
|
|
0
|
$state{'nameddest'} = {}; # <_nameddest> defs save up for final output |
|
5311
|
|
|
|
|
|
|
# these are ND's defined in THIS document, NOT targets in links |
|
5312
|
|
|
|
|
|
|
# {'name'} name of Named Destination |
|
5313
|
|
|
|
|
|
|
# {'ppn'} physical page number |
|
5314
|
|
|
|
|
|
|
# {'x'} x location in page |
|
5315
|
|
|
|
|
|
|
# {'y'} y location in page |
|
5316
|
|
|
|
|
|
|
# {'fit'} fit (location, parms) information |
|
5317
|
|
|
|
|
|
|
|
|
5318
|
|
|
|
|
|
|
# predefined (started) lists |
|
5319
|
0
|
|
|
|
|
0
|
$state{'tag_lists'}{'_reft'} = [ '_reft' ]; |
|
5320
|
|
|
|
|
|
|
|
|
5321
|
|
|
|
|
|
|
# extend _reft and add additional tags lists per user input |
|
5322
|
0
|
|
|
|
|
0
|
foreach my $listname (keys %{$lists}) { |
|
|
0
|
|
|
|
|
0
|
|
|
5323
|
|
|
|
|
|
|
# add the anonymous list of tag names to an existing list ($listname |
|
5324
|
|
|
|
|
|
|
# element) by this key, or create if none already exists. |
|
5325
|
|
|
|
|
|
|
# a given tag may appear in multiple lists |
|
5326
|
0
|
|
|
|
|
0
|
my @list; # one user-given tag list |
|
5327
|
0
|
0
|
|
|
|
0
|
if (exists $state{'tag_lists'}{$listname}) { |
|
5328
|
0
|
|
|
|
|
0
|
@list = @{ $state{'tag_lists'}{$listname} }; |
|
|
0
|
|
|
|
|
0
|
|
|
5329
|
0
|
|
|
|
|
0
|
push @list, @{ $lists->{$listname} }; |
|
|
0
|
|
|
|
|
0
|
|
|
5330
|
|
|
|
|
|
|
} else { |
|
5331
|
|
|
|
|
|
|
# create new list |
|
5332
|
0
|
|
|
|
|
0
|
$state{'tag_lists'}{$listname} = []; # empty, so far |
|
5333
|
0
|
|
|
|
|
0
|
@list = @{ $lists->{$listname} }; |
|
|
0
|
|
|
|
|
0
|
|
|
5334
|
|
|
|
|
|
|
} |
|
5335
|
|
|
|
|
|
|
# cull any duplicates from the list, such as user misunderstanding and |
|
5336
|
|
|
|
|
|
|
# explicitly specifying '_reft' in the _reft tag list |
|
5337
|
0
|
|
|
|
|
0
|
for (my $ti=0; $ti<scalar(@list)-1; $ti++) { |
|
5338
|
0
|
|
|
|
|
0
|
for (my $tj=$ti+1; $tj<@list; $tj++) { |
|
5339
|
0
|
0
|
|
|
|
0
|
if ($list[$ti] eq $list[$tj]) { |
|
5340
|
|
|
|
|
|
|
# duplicate found, delete second one |
|
5341
|
0
|
|
|
|
|
0
|
splice(@list, $tj--, 1); |
|
5342
|
|
|
|
|
|
|
} |
|
5343
|
|
|
|
|
|
|
} |
|
5344
|
|
|
|
|
|
|
} |
|
5345
|
|
|
|
|
|
|
# fill or replace existing entry |
|
5346
|
0
|
|
|
|
|
0
|
$state{'tag_lists'}{$listname} = \@list; |
|
5347
|
|
|
|
|
|
|
|
|
5348
|
|
|
|
|
|
|
# create xreft target list heads |
|
5349
|
0
|
|
|
|
|
0
|
$state{'xreft'}->{$listname} = {}; # always will have _reft list |
|
5350
|
|
|
|
|
|
|
} |
|
5351
|
|
|
|
|
|
|
|
|
5352
|
0
|
|
|
|
|
0
|
return %state; |
|
5353
|
|
|
|
|
|
|
} |
|
5354
|
|
|
|
|
|
|
|
|
5355
|
|
|
|
|
|
|
=head2 pass_start_state() |
|
5356
|
|
|
|
|
|
|
|
|
5357
|
|
|
|
|
|
|
Update 'state' variable that carries information across multiple |
|
5358
|
|
|
|
|
|
|
document passes for C<column()> call, at the beginning of each pass. |
|
5359
|
|
|
|
|
|
|
See L<PDF::Builder::Content::Column_docs> for documentation. |
|
5360
|
|
|
|
|
|
|
|
|
5361
|
|
|
|
|
|
|
=cut |
|
5362
|
|
|
|
|
|
|
|
|
5363
|
|
|
|
|
|
|
sub pass_start_state { |
|
5364
|
0
|
|
|
0
|
1
|
0
|
my ($self, $pass_no, $max_passes, $state) = @_; |
|
5365
|
|
|
|
|
|
|
# $state = ref to %state structure |
|
5366
|
|
|
|
|
|
|
|
|
5367
|
|
|
|
|
|
|
# TBD this may disappear, if clear changed_target flag upon text output |
|
5368
|
|
|
|
|
|
|
# if ($pass_no > 1) { |
|
5369
|
|
|
|
|
|
|
# $state->{'changed_target'} = {}; # clear all |
|
5370
|
|
|
|
|
|
|
# |
|
5371
|
|
|
|
|
|
|
# # changed visible text (fpn), reset "previous" version |
|
5372
|
|
|
|
|
|
|
# for (my $sindex=0; $sindex<scalar(@{$state->{'xrefs'}}); $sindex++) { |
|
5373
|
|
|
|
|
|
|
# $state->{'prev_other_pg'} = $state->{'other_pg'}; # not always used |
|
5374
|
|
|
|
|
|
|
# } |
|
5375
|
|
|
|
|
|
|
# } |
|
5376
|
|
|
|
|
|
|
|
|
5377
|
0
|
|
|
|
|
0
|
$state->{'sindex'} = 0; # position to write on first pass, update > 1 |
|
5378
|
|
|
|
|
|
|
|
|
5379
|
|
|
|
|
|
|
|
|
5380
|
0
|
|
|
|
|
0
|
return; |
|
5381
|
|
|
|
|
|
|
} |
|
5382
|
|
|
|
|
|
|
|
|
5383
|
|
|
|
|
|
|
# ================================================== |
|
5384
|
|
|
|
|
|
|
# input: level of checking, PDF as a string |
|
5385
|
|
|
|
|
|
|
# level: 0 just return with any version override |
|
5386
|
|
|
|
|
|
|
# 1 return version override, and errors |
|
5387
|
|
|
|
|
|
|
# 2 return version override, and errors and warnings |
|
5388
|
|
|
|
|
|
|
# 3 return version override, plus errors, warnings, notes |
|
5389
|
|
|
|
|
|
|
# 4 like (3), plus dump analysis data |
|
5390
|
|
|
|
|
|
|
# 5 like (4), plus dump $self (PDF) contents |
|
5391
|
|
|
|
|
|
|
# returns any /Version value found in Catalog, last one if multiple ones found, |
|
5392
|
|
|
|
|
|
|
# else undefined |
|
5393
|
|
|
|
|
|
|
|
|
5394
|
|
|
|
|
|
|
sub IntegrityCheck { |
|
5395
|
18
|
|
|
18
|
0
|
64
|
my ($self, $level, $string) = @_; |
|
5396
|
|
|
|
|
|
|
|
|
5397
|
18
|
|
|
|
|
37
|
my $level_nodiag = 0; |
|
5398
|
18
|
|
|
|
|
34
|
my $level_error = 1; |
|
5399
|
18
|
|
|
|
|
61
|
my $level_warning = 2; |
|
5400
|
18
|
|
|
|
|
39
|
my $level_note = 3; |
|
5401
|
18
|
|
|
|
|
58
|
my $level_dump = 4; |
|
5402
|
18
|
|
|
|
|
33
|
my $level_dumpself = 5; |
|
5403
|
|
|
|
|
|
|
|
|
5404
|
18
|
|
|
|
|
46
|
my $IC = "PDF Integrity Check:"; |
|
5405
|
|
|
|
|
|
|
|
|
5406
|
|
|
|
|
|
|
#print "$IC level $level\n" if $level >= $level_error; |
|
5407
|
18
|
|
|
|
|
40
|
my $Version = undef; |
|
5408
|
18
|
|
|
|
|
45
|
my ($Info, $Root, $str, $pos, $Parent, @Kids, @others); |
|
5409
|
|
|
|
|
|
|
|
|
5410
|
18
|
|
|
|
|
57
|
my $idx_defined = 0; # has this object been explicitly defined? |
|
5411
|
18
|
|
|
|
|
38
|
my $idx_refcount = 1; # count of all pointing to this obj except as Kid |
|
5412
|
18
|
|
|
|
|
36
|
my $idx_par_clmd = 2; # other object claiming this object as Kid |
|
5413
|
18
|
|
|
|
|
54
|
my $idx_parent = 3; # this object's /Parent entry |
|
5414
|
18
|
|
|
|
|
40
|
my $idx_kid_cnt = 4; # size of kid_list |
|
5415
|
18
|
|
|
|
|
32
|
my $idx_kid_list = 5; # this object's /Kids list |
|
5416
|
|
|
|
|
|
|
# intialize each element to [ 0 0 -1 -1 -1 [] ] |
|
5417
|
|
|
|
|
|
|
|
|
5418
|
18
|
50
|
|
|
|
69
|
return $Version if !length($string); # nothing to examine? |
|
5419
|
|
|
|
|
|
|
# basic PDF version on line 1 |
|
5420
|
18
|
50
|
|
|
|
157
|
if ($string =~ m/^%PDF-([\d.]+)/) { |
|
5421
|
18
|
|
|
|
|
102
|
$Version = $1; |
|
5422
|
|
|
|
|
|
|
} |
|
5423
|
|
|
|
|
|
|
# even if $level 0, still want to get any higher /Version |
|
5424
|
|
|
|
|
|
|
# build analysis data and issue errors/warnings at appropriate $level |
|
5425
|
18
|
|
|
|
|
199
|
my @major = split /%%EOF/, $string; # typically [0] entire PDF [1] empty |
|
5426
|
18
|
|
|
|
|
43
|
my %objList; |
|
5427
|
18
|
|
|
|
|
40
|
my $update = -1; |
|
5428
|
18
|
|
|
|
|
50
|
foreach (@major) { |
|
5429
|
|
|
|
|
|
|
# update section number 0, 1, 2... with %%EOF in-between |
|
5430
|
38
|
|
|
|
|
70
|
$update++; |
|
5431
|
38
|
50
|
|
|
|
100
|
next if !length($_); |
|
5432
|
|
|
|
|
|
|
|
|
5433
|
|
|
|
|
|
|
# split on "endobj" |
|
5434
|
38
|
|
|
|
|
209
|
my @rawObjects = split /endobj/, $_; |
|
5435
|
|
|
|
|
|
|
# each element contains an object plus leading stuff, not incl endobj |
|
5436
|
|
|
|
|
|
|
|
|
5437
|
38
|
|
|
|
|
94
|
foreach my $rawObject (@rawObjects) { |
|
5438
|
171
|
50
|
|
|
|
407
|
next if !length($rawObject); |
|
5439
|
|
|
|
|
|
|
|
|
5440
|
|
|
|
|
|
|
# remove bulky and unwanted stream...endstream |
|
5441
|
171
|
100
|
|
|
|
584
|
if ($rawObject =~ m/^(.*)stream\s.*\sendstream(.*)$/s) { |
|
5442
|
23
|
|
|
|
|
113
|
$rawObject = $1.$2; |
|
5443
|
|
|
|
|
|
|
} |
|
5444
|
|
|
|
|
|
|
|
|
5445
|
|
|
|
|
|
|
# trim off anything before obj clause. endobj already gone. |
|
5446
|
171
|
100
|
66
|
|
|
1165
|
if ($rawObject =~ m/^(.*?)\s?(\d+) (\d+) obj\s(.*)$/s || |
|
5447
|
|
|
|
|
|
|
$rawObject =~ m/^(.*?)\s?(\d+) (\d+) obj(.*)$/s) { |
|
5448
|
133
|
|
|
|
|
537
|
$rawObject = $4; |
|
5449
|
|
|
|
|
|
|
|
|
5450
|
|
|
|
|
|
|
# found an obj, full string is $rawObject. parse into |
|
5451
|
|
|
|
|
|
|
# selected fields, build $objList{key} entry. |
|
5452
|
133
|
|
|
|
|
433
|
my $objKey = "$2.$3"; # e.g., 4 0 obj -> 4.0 |
|
5453
|
|
|
|
|
|
|
# if this is a replacement object in an update, clear Parent |
|
5454
|
|
|
|
|
|
|
# and Kids |
|
5455
|
133
|
100
|
100
|
|
|
531
|
if (defined $objList{$objKey} && $update > 0) { |
|
5456
|
9
|
|
|
|
|
21
|
$objList{$objKey}->[$idx_parent] = -1; |
|
5457
|
9
|
|
|
|
|
18
|
$objList{$objKey}->[$idx_kid_cnt] = -1; |
|
5458
|
9
|
|
|
|
|
24
|
$objList{$objKey}->[$idx_kid_list] = []; |
|
5459
|
|
|
|
|
|
|
} |
|
5460
|
|
|
|
|
|
|
# might have already created this object element as target |
|
5461
|
|
|
|
|
|
|
# from another object |
|
5462
|
133
|
100
|
|
|
|
354
|
if (!defined $objList{$objKey}) { |
|
5463
|
49
|
|
|
|
|
333
|
$objList{$objKey} = [0, 0, -1, -1, -1, []]; |
|
5464
|
|
|
|
|
|
|
} |
|
5465
|
|
|
|
|
|
|
# mark object as defined |
|
5466
|
133
|
|
|
|
|
300
|
$objList{$objKey}->[$idx_defined] = 1; |
|
5467
|
|
|
|
|
|
|
|
|
5468
|
|
|
|
|
|
|
# found an object |
|
5469
|
|
|
|
|
|
|
# looking for /Parent x y R |
|
5470
|
|
|
|
|
|
|
# /Kids [ x y R ] |
|
5471
|
|
|
|
|
|
|
# /Type = /Catalog -> /Version /x.y |
|
5472
|
|
|
|
|
|
|
# for now, ignoring any /BaseVersion |
|
5473
|
|
|
|
|
|
|
# all other x y R |
|
5474
|
|
|
|
|
|
|
# remove from $rawObject as we find a match |
|
5475
|
|
|
|
|
|
|
|
|
5476
|
|
|
|
|
|
|
# /Parent x y R -> $Parent |
|
5477
|
133
|
100
|
|
|
|
536
|
if ($rawObject =~ m#/Parent(\s+)(\d+)(\s+)(\d+)(\s+)R#) { |
|
5478
|
27
|
|
|
|
|
96
|
$Parent = "$2.$4"; |
|
5479
|
27
|
|
|
|
|
144
|
$str = "/Parent$1$2$3$4$5R"; |
|
5480
|
27
|
|
|
|
|
62
|
$pos = index $rawObject, $str; |
|
5481
|
27
|
|
|
|
|
69
|
substr($rawObject, $pos, length($str)) = ''; |
|
5482
|
|
|
|
|
|
|
# TBD realistically, do we need to check for >1 /Parent ? |
|
5483
|
|
|
|
|
|
|
#if ($objList{$objKey}->[$idx_parent] == -1) { |
|
5484
|
|
|
|
|
|
|
# first /Parent (should not be more) |
|
5485
|
27
|
|
|
|
|
71
|
$objList{$objKey}->[$idx_parent] = $Parent; |
|
5486
|
|
|
|
|
|
|
#} else { |
|
5487
|
|
|
|
|
|
|
# print STDERR "$IC Additional Parent ($Parent) in object $objKey, already list ". |
|
5488
|
|
|
|
|
|
|
# "$objList{$objKey}->[$idx_parent] as Parent.\n" if $level >= $level_error; |
|
5489
|
|
|
|
|
|
|
#} |
|
5490
|
|
|
|
|
|
|
} |
|
5491
|
|
|
|
|
|
|
|
|
5492
|
|
|
|
|
|
|
# /Kids [ x y R ] -> @Kids |
|
5493
|
|
|
|
|
|
|
# should we check for multiple Kids arrays in one object (error)? |
|
5494
|
133
|
100
|
|
|
|
494
|
if ($rawObject =~ m#/Kids(\s+)\[(.*)\]#) { |
|
5495
|
20
|
|
|
|
|
102
|
$str = "/Kids$1\[$2\]"; |
|
5496
|
20
|
|
|
|
|
50
|
$pos = index $rawObject, $str; |
|
5497
|
20
|
|
|
|
|
78
|
substr($rawObject, $pos, length($str)) = ''; |
|
5498
|
|
|
|
|
|
|
|
|
5499
|
20
|
|
|
|
|
71
|
my $str2 = " $2"; # guarantee a leading \s |
|
5500
|
20
|
|
|
|
|
64
|
@Kids = (); |
|
5501
|
20
|
|
|
|
|
37
|
while (1) { |
|
5502
|
42
|
100
|
|
|
|
210
|
if ($str2 =~ m#(\s+)(\d+)(\s+)(\d+)(\s+)R#) { |
|
5503
|
22
|
|
|
|
|
113
|
$str = "$1$2$3$4$5R"; |
|
5504
|
22
|
|
|
|
|
84
|
push @Kids, "$2.$4"; |
|
5505
|
22
|
|
|
|
|
63
|
$pos = index $str2, $str; |
|
5506
|
22
|
|
|
|
|
69
|
substr($str2, $pos, length($str)) = ''; |
|
5507
|
|
|
|
|
|
|
} else { |
|
5508
|
20
|
|
|
|
|
43
|
last; |
|
5509
|
|
|
|
|
|
|
} |
|
5510
|
|
|
|
|
|
|
} |
|
5511
|
|
|
|
|
|
|
# TBD: realistically, any need to check for >1 /Kids? |
|
5512
|
|
|
|
|
|
|
#if (!scalar(@{$objList{$objKey}->[$idx_kid_list]})) { |
|
5513
|
|
|
|
|
|
|
# first /Kids (should not be more) |
|
5514
|
20
|
|
|
|
|
63
|
@{$objList{$objKey}->[$idx_kid_list]} = @Kids; |
|
|
20
|
|
|
|
|
111
|
|
|
5515
|
20
|
|
|
|
|
64
|
$objList{$objKey}->[$idx_kid_cnt] = scalar(@Kids); |
|
5516
|
|
|
|
|
|
|
#} else { |
|
5517
|
|
|
|
|
|
|
# print STDERR "$IC Multiple Kids lists in object $objKey, already list ". |
|
5518
|
|
|
|
|
|
|
# "@{$objList{$objKey}->[$idx_kid_list]} as Kids.\n" if $level >= $level_error; |
|
5519
|
|
|
|
|
|
|
#} |
|
5520
|
|
|
|
|
|
|
} |
|
5521
|
|
|
|
|
|
|
|
|
5522
|
|
|
|
|
|
|
# /Type /Catalog -> /Version /x.y -> $Version |
|
5523
|
|
|
|
|
|
|
# both x and y are normally single digits, but allow room |
|
5524
|
|
|
|
|
|
|
# just global $Version, assuming that each one physically |
|
5525
|
|
|
|
|
|
|
# later overrides any earlier ones |
|
5526
|
133
|
100
|
|
|
|
402
|
if ($rawObject =~ m#/Type(\s+)/Catalog#) { |
|
5527
|
18
|
|
|
|
|
79
|
my $sp1 = $1; |
|
5528
|
18
|
50
|
|
|
|
116
|
if ($rawObject =~ m#/Version /(\d+)\.(\d+)#) { |
|
5529
|
0
|
|
|
|
|
0
|
$Version = "$1.$2"; |
|
5530
|
0
|
|
|
|
|
0
|
$str = "/Version$sp1/$Version"; |
|
5531
|
0
|
|
|
|
|
0
|
$pos = index $rawObject, $str; |
|
5532
|
0
|
|
|
|
|
0
|
substr($rawObject, $pos, length($str)) = ''; |
|
5533
|
|
|
|
|
|
|
} |
|
5534
|
|
|
|
|
|
|
} |
|
5535
|
|
|
|
|
|
|
|
|
5536
|
|
|
|
|
|
|
# if using cross-reference stream, will find /Root x y R |
|
5537
|
|
|
|
|
|
|
# and /Info x y R entries in an object of /Type /Xref |
|
5538
|
|
|
|
|
|
|
# it looks like last ones will win |
|
5539
|
133
|
100
|
66
|
|
|
619
|
if ($rawObject =~ m#/Type(\s+)/XRef# || |
|
5540
|
|
|
|
|
|
|
$rawObject =~ m#/Type/XRef#) { |
|
5541
|
3
|
50
|
|
|
|
18
|
if ($rawObject =~ m#/Root(\s+)(\d+)(\s+)(\d+)(\s+)R#) { |
|
5542
|
3
|
|
|
|
|
13
|
$Root = "$2.$4"; |
|
5543
|
3
|
|
|
|
|
16
|
$str = "/Root$1$2$3$4$5R"; |
|
5544
|
3
|
|
|
|
|
7
|
$pos = index $rawObject, $str; |
|
5545
|
3
|
|
|
|
|
10
|
substr($rawObject, $pos, length($str)) = ''; |
|
5546
|
|
|
|
|
|
|
} |
|
5547
|
3
|
50
|
|
|
|
18
|
if ($rawObject =~ m#/Info(\s+)(\d+)(\s+)(\d+)(\s+)R#) { |
|
5548
|
3
|
|
|
|
|
9
|
$Info = "$2.$4"; |
|
5549
|
3
|
|
|
|
|
13
|
$str = "/Info$1$2$3$4$5R"; |
|
5550
|
3
|
|
|
|
|
8
|
$pos = index $rawObject, $str; |
|
5551
|
3
|
|
|
|
|
8
|
substr($rawObject, $pos, length($str)) = ''; |
|
5552
|
|
|
|
|
|
|
} |
|
5553
|
|
|
|
|
|
|
} |
|
5554
|
|
|
|
|
|
|
|
|
5555
|
|
|
|
|
|
|
# all other x y R -> @others |
|
5556
|
133
|
|
|
|
|
259
|
@others = (); |
|
5557
|
133
|
|
|
|
|
201
|
while (1) { |
|
5558
|
207
|
100
|
|
|
|
2385
|
if ($rawObject =~ m#(\d+)(\s+)(\d+)(\s+)R#) { |
|
5559
|
74
|
|
|
|
|
282
|
$str = "$1$2$3$4R"; |
|
5560
|
74
|
|
|
|
|
261
|
push @others, "$1.$3"; |
|
5561
|
74
|
|
|
|
|
182
|
$pos = index $rawObject, $str; |
|
5562
|
74
|
|
|
|
|
179
|
substr($rawObject, $pos, length($str)) = ''; |
|
5563
|
|
|
|
|
|
|
} else { |
|
5564
|
133
|
|
|
|
|
229
|
last; |
|
5565
|
|
|
|
|
|
|
} |
|
5566
|
|
|
|
|
|
|
} |
|
5567
|
|
|
|
|
|
|
# go through all other refs and create element if necessary, |
|
5568
|
|
|
|
|
|
|
# then increment its refcnt array element |
|
5569
|
133
|
|
|
|
|
315
|
foreach (@others) { |
|
5570
|
74
|
100
|
|
|
|
1582
|
if (!defined $objList{$_}) { |
|
5571
|
63
|
|
|
|
|
295
|
$objList{$_} = [0, 0, -1, -1, -1, []]; |
|
5572
|
|
|
|
|
|
|
} |
|
5573
|
74
|
|
|
|
|
171
|
$objList{$_}->[$idx_refcount]++; |
|
5574
|
|
|
|
|
|
|
} |
|
5575
|
133
|
|
|
|
|
244
|
foreach (@Kids) { |
|
5576
|
129
|
100
|
|
|
|
301
|
if (!defined $objList{$_}) { |
|
5577
|
19
|
|
|
|
|
119
|
$objList{$_} = [0, 0, -1, -1, -1, []]; |
|
5578
|
|
|
|
|
|
|
} |
|
5579
|
129
|
|
|
|
|
306
|
$objList{$_}->[$idx_refcount]++; |
|
5580
|
|
|
|
|
|
|
} |
|
5581
|
|
|
|
|
|
|
|
|
5582
|
|
|
|
|
|
|
} else { |
|
5583
|
|
|
|
|
|
|
# not an object, but could be other stuff of interest |
|
5584
|
|
|
|
|
|
|
# looking for trailer -> /Root x y R & /Info x y R |
|
5585
|
38
|
100
|
|
|
|
159
|
if ($rawObject =~ m/trailer/) { |
|
5586
|
18
|
50
|
|
|
|
144
|
if ($rawObject =~ m#trailer(.*)/Info(\s+)(\d+)(\s+)(\d+)(\s+)R#s) { |
|
5587
|
18
|
|
|
|
|
70
|
$Info = "$3.$5"; |
|
5588
|
|
|
|
|
|
|
} |
|
5589
|
18
|
50
|
|
|
|
122
|
if ($rawObject =~ m#trailer(.*)/Root(\s+)(\d+)(\s+)(\d+)(\s+)R#s) { |
|
5590
|
18
|
|
|
|
|
147
|
$Root = "$3.$5"; |
|
5591
|
|
|
|
|
|
|
} |
|
5592
|
|
|
|
|
|
|
} |
|
5593
|
|
|
|
|
|
|
} |
|
5594
|
|
|
|
|
|
|
} |
|
5595
|
|
|
|
|
|
|
} |
|
5596
|
|
|
|
|
|
|
|
|
5597
|
|
|
|
|
|
|
# increment Root and Info objects reference counts |
|
5598
|
|
|
|
|
|
|
# they probably SHOULD already be defined (issue warning if not) |
|
5599
|
18
|
50
|
|
|
|
63
|
if (!defined $Root) { |
|
5600
|
0
|
0
|
|
|
|
0
|
print STDERR "$IC No Root object defined!\n" if $level >= $level_error; |
|
5601
|
|
|
|
|
|
|
} else { |
|
5602
|
|
|
|
|
|
|
# Look for expected Root object |
|
5603
|
18
|
50
|
|
|
|
127
|
if (!defined $objList{$Root}) { |
|
5604
|
0
|
0
|
|
|
|
0
|
if ($Version > 1.4) { |
|
5605
|
|
|
|
|
|
|
# PDF 1.5 and up, Root could be hiding in an Object Stream |
|
5606
|
|
|
|
|
|
|
# TBD: disassemble object stream(s) to expose all objects |
|
5607
|
0
|
0
|
|
|
|
0
|
print STDERR "$IC Root object $Root not found, but this may be\n the result of putting it in an Object Stream.\n" if $level >= $level_warning; |
|
5608
|
|
|
|
|
|
|
} else { |
|
5609
|
|
|
|
|
|
|
# PDF 1.4 or below, definitely an error if no Root found |
|
5610
|
0
|
0
|
|
|
|
0
|
print STDERR "$IC Root object $Root not found!\n" if $level >= $level_error; |
|
5611
|
|
|
|
|
|
|
} |
|
5612
|
0
|
|
|
|
|
0
|
$objList{$Root} = [1, 0, -1, -1, -1, []]; |
|
5613
|
|
|
|
|
|
|
} |
|
5614
|
18
|
|
|
|
|
50
|
$objList{$Root}->[$idx_refcount]++; |
|
5615
|
|
|
|
|
|
|
} |
|
5616
|
|
|
|
|
|
|
|
|
5617
|
|
|
|
|
|
|
# Info is optional |
|
5618
|
18
|
50
|
|
|
|
88
|
if (!defined $Info) { |
|
5619
|
0
|
0
|
|
|
|
0
|
print STDERR "$IC No Info object defined!\n" if $level >= $level_note; |
|
5620
|
|
|
|
|
|
|
} else { |
|
5621
|
18
|
50
|
|
|
|
78
|
if (!defined $objList{$Info}) { |
|
5622
|
0
|
|
|
|
|
0
|
$objList{$Info} = [1, 0, -1, -1, -1, []]; |
|
5623
|
0
|
0
|
|
|
|
0
|
if ($Version > 1.4) { |
|
5624
|
|
|
|
|
|
|
# PDF 1.5 and up, Info could be hiding in an Object Stream |
|
5625
|
|
|
|
|
|
|
# TBD: disassemble object stream(s) to expose all objects |
|
5626
|
0
|
0
|
|
|
|
0
|
print STDERR "$IC Info object $Root not found, but this may be\n the result of putting it in an Object Stream, or it may have been deleted.\n" if $level >= $level_warning; |
|
5627
|
|
|
|
|
|
|
} else { |
|
5628
|
|
|
|
|
|
|
# PDF 1.4 or below, definitely a warning if no Info found |
|
5629
|
0
|
0
|
|
|
|
0
|
print STDERR "$IC Root object $Root not found!\n" if $level >= $level_warning; |
|
5630
|
|
|
|
|
|
|
} |
|
5631
|
0
|
0
|
|
|
|
0
|
print STDERR "$IC Info object $Info not found!\n" if $level >= $level_warning; |
|
5632
|
|
|
|
|
|
|
# possibly in a deleted object (on free list) |
|
5633
|
|
|
|
|
|
|
} |
|
5634
|
18
|
|
|
|
|
51
|
$objList{$Info}->[$idx_refcount]++; |
|
5635
|
|
|
|
|
|
|
} |
|
5636
|
|
|
|
|
|
|
|
|
5637
|
|
|
|
|
|
|
# revisit each element in objList |
|
5638
|
|
|
|
|
|
|
# visit each Kid, their $idx_par_clmd should be -1 (set to this object) |
|
5639
|
|
|
|
|
|
|
# (if not -1, is on multiple Kids lists) |
|
5640
|
|
|
|
|
|
|
# their $idx_parent should be this object |
|
5641
|
|
|
|
|
|
|
# they should have a Parent declared |
|
5642
|
|
|
|
|
|
|
# any element with ref count of 0 and no Parent give warning unreachable |
|
5643
|
|
|
|
|
|
|
# TBD: anything else to add to things to check? |
|
5644
|
18
|
|
|
|
|
163
|
foreach my $thisObj (sort keys %objList) { |
|
5645
|
|
|
|
|
|
|
|
|
5646
|
|
|
|
|
|
|
# was an object actually defined for this entry? |
|
5647
|
|
|
|
|
|
|
# missing Info and Root messages already given, so flag is 1 ("defined") |
|
5648
|
131
|
100
|
|
|
|
349
|
if ($objList{$thisObj}->[$idx_defined] == 0) { |
|
5649
|
2
|
50
|
|
|
|
14
|
if ($Version > 1.4) { |
|
5650
|
2
|
50
|
|
|
|
8
|
print STDERR "$IC object $thisObj referenced, but no entry found\n (might be on the free list, or defined in an object stream).\n" if $level >= $level_note; |
|
5651
|
|
|
|
|
|
|
} else { |
|
5652
|
0
|
0
|
|
|
|
0
|
print STDERR "$IC object $thisObj referenced, but no entry found (might be on the free list).\n" if $level >= $level_warning; |
|
5653
|
|
|
|
|
|
|
} |
|
5654
|
|
|
|
|
|
|
# it's apparently OK if the missing object is on the free list -- |
|
5655
|
|
|
|
|
|
|
# it will just be ignored |
|
5656
|
|
|
|
|
|
|
} |
|
5657
|
|
|
|
|
|
|
|
|
5658
|
|
|
|
|
|
|
# check any Kids |
|
5659
|
131
|
100
|
|
|
|
305
|
if ($objList{$thisObj}[$idx_kid_cnt] > 0) { |
|
5660
|
|
|
|
|
|
|
# this object has children (/Kids), so explore them one level deep |
|
5661
|
17
|
|
|
|
|
115
|
for (my $kidObj=0; $kidObj<$objList{$thisObj}[$idx_kid_cnt]; $kidObj++) { |
|
5662
|
20
|
|
|
|
|
83
|
my $child = $objList{$thisObj}[$idx_kid_list]->[$kidObj]; |
|
5663
|
|
|
|
|
|
|
# child's claimed parent should be -1, set to thisObj |
|
5664
|
20
|
50
|
|
|
|
70
|
if ($objList{$child}[$idx_par_clmd] == -1) { |
|
5665
|
|
|
|
|
|
|
# no one has claimed to be parent, so set to thisObj |
|
5666
|
20
|
|
|
|
|
65
|
$objList{$child}[$idx_par_clmd] = $thisObj; |
|
5667
|
|
|
|
|
|
|
} else { |
|
5668
|
|
|
|
|
|
|
# someone else has already claimed to be parent |
|
5669
|
0
|
0
|
|
|
|
0
|
print STDERR "$IC object $thisObj wants to claim object $child as its child, ". |
|
5670
|
|
|
|
|
|
|
"but $objList{$child}[$idx_par_clmd] already has!\nPossibly $child ". |
|
5671
|
|
|
|
|
|
|
"is on more than one /Kids list?\n" if $level >= $level_error; |
|
5672
|
|
|
|
|
|
|
} |
|
5673
|
|
|
|
|
|
|
# if no object defined for child, already flagged as missing |
|
5674
|
20
|
50
|
|
|
|
72
|
if ($objList{$child}[$idx_defined] == 1) { |
|
5675
|
|
|
|
|
|
|
# child should list thisObj as its Parent |
|
5676
|
20
|
50
|
|
|
|
661
|
if ($objList{$child}[$idx_parent] == -1) { |
|
|
|
50
|
|
|
|
|
|
|
5677
|
0
|
0
|
|
|
|
0
|
print STDERR "$IC object $thisObj claims $child as a child (/Kids), but ". |
|
5678
|
|
|
|
|
|
|
"$child claims no Parent!\n" if $level >= $level_error; |
|
5679
|
0
|
|
|
|
|
0
|
$objList{$child}[$idx_parent] = $thisObj; |
|
5680
|
|
|
|
|
|
|
} elsif ($objList{$child}[$idx_parent] != $thisObj) { |
|
5681
|
0
|
0
|
|
|
|
0
|
print STDERR "$IC object $thisObj claims $child as a child (/Kids), but ". |
|
5682
|
|
|
|
|
|
|
"$child claims $objList{$child}[$idx_parent] as its parent!\n" |
|
5683
|
|
|
|
|
|
|
if $level >= $level_error; |
|
5684
|
|
|
|
|
|
|
} |
|
5685
|
|
|
|
|
|
|
} |
|
5686
|
|
|
|
|
|
|
} |
|
5687
|
|
|
|
|
|
|
} |
|
5688
|
|
|
|
|
|
|
|
|
5689
|
131
|
100
|
100
|
|
|
520
|
if ($objList{$thisObj}[$idx_parent] == -1 && |
|
5690
|
|
|
|
|
|
|
$objList{$thisObj}[$idx_refcount] == 0) { |
|
5691
|
8
|
50
|
|
|
|
24
|
print STDERR "$IC Warning: object $thisObj appears to be unreachable.\n" if $level >= $level_note; |
|
5692
|
|
|
|
|
|
|
} |
|
5693
|
|
|
|
|
|
|
} |
|
5694
|
|
|
|
|
|
|
|
|
5695
|
18
|
50
|
|
|
|
84
|
if ($level >= $level_dump) { |
|
5696
|
|
|
|
|
|
|
# dump analysis data |
|
5697
|
39
|
|
|
39
|
|
31619
|
use Data::Dumper; |
|
|
39
|
|
|
|
|
381194
|
|
|
|
39
|
|
|
|
|
6412
|
|
|
5698
|
0
|
|
|
|
|
0
|
my $d = Data::Dumper->new([\%objList]); |
|
5699
|
0
|
|
|
|
|
0
|
print "========= dump of $IC analysis data ===========\n"; |
|
5700
|
0
|
|
|
|
|
0
|
print $d->Dump(); |
|
5701
|
|
|
|
|
|
|
} |
|
5702
|
|
|
|
|
|
|
|
|
5703
|
|
|
|
|
|
|
# if have entire processed PDF in $self |
|
5704
|
18
|
50
|
|
|
|
63
|
if ($level >= $level_dumpself) { |
|
5705
|
|
|
|
|
|
|
# dump whole data |
|
5706
|
39
|
|
|
39
|
|
457
|
use Data::Dumper; |
|
|
39
|
|
|
|
|
85
|
|
|
|
39
|
|
|
|
|
14394
|
|
|
5707
|
0
|
|
|
|
|
0
|
my $d = Data::Dumper->new([$self]); |
|
5708
|
0
|
|
|
|
|
0
|
print "========= dump of $IC PDF (self) data ===========\n"; |
|
5709
|
0
|
|
|
|
|
0
|
print $d->Dump(); |
|
5710
|
|
|
|
|
|
|
} |
|
5711
|
|
|
|
|
|
|
|
|
5712
|
18
|
|
|
|
|
240
|
return $Version; |
|
5713
|
|
|
|
|
|
|
} |
|
5714
|
|
|
|
|
|
|
|
|
5715
|
|
|
|
|
|
|
1; |
|
5716
|
|
|
|
|
|
|
|
|
5717
|
|
|
|
|
|
|
__END__ |