line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package PDF::Create; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
our $VERSION = '1.43'; |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=head1 NAME |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
PDF::Create - Create PDF files. |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
=head1 VERSION |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
Version 1.43 |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=cut |
14
|
|
|
|
|
|
|
|
15
|
18
|
|
|
18
|
|
101213
|
use 5.006; |
|
18
|
|
|
|
|
168
|
|
16
|
18
|
|
|
18
|
|
112
|
use strict; use warnings; |
|
18
|
|
|
18
|
|
35
|
|
|
18
|
|
|
|
|
590
|
|
|
18
|
|
|
|
|
108
|
|
|
18
|
|
|
|
|
54
|
|
|
18
|
|
|
|
|
646
|
|
17
|
|
|
|
|
|
|
|
18
|
18
|
|
|
18
|
|
108
|
use Carp qw(confess croak cluck carp); |
|
18
|
|
|
|
|
34
|
|
|
18
|
|
|
|
|
1453
|
|
19
|
18
|
|
|
18
|
|
8233
|
use Data::Dumper; |
|
18
|
|
|
|
|
119141
|
|
|
18
|
|
|
|
|
1329
|
|
20
|
18
|
|
|
18
|
|
5338
|
use FileHandle; |
|
18
|
|
|
|
|
152766
|
|
|
18
|
|
|
|
|
118
|
|
21
|
18
|
|
|
18
|
|
6218
|
use Scalar::Util qw(weaken); |
|
18
|
|
|
|
|
53
|
|
|
18
|
|
|
|
|
1427
|
|
22
|
|
|
|
|
|
|
|
23
|
18
|
|
|
18
|
|
6939
|
use PDF::Image::GIF; |
|
18
|
|
|
|
|
55
|
|
|
18
|
|
|
|
|
606
|
|
24
|
18
|
|
|
18
|
|
5371
|
use PDF::Image::JPEG; |
|
18
|
|
|
|
|
54
|
|
|
18
|
|
|
|
|
633
|
|
25
|
18
|
|
|
18
|
|
6929
|
use PDF::Create::Page; |
|
18
|
|
|
|
|
66
|
|
|
18
|
|
|
|
|
1084
|
|
26
|
18
|
|
|
18
|
|
6347
|
use PDF::Create::Outline; |
|
18
|
|
|
|
|
47
|
|
|
18
|
|
|
|
|
120753
|
|
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
my $DEBUG = 0; |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=encoding utf8 |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
=head1 DESCRIPTION |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
C allows you to create PDF document using a number of primitives.The |
35
|
|
|
|
|
|
|
result is as a PDF file or stream. PDF stands for Portable Document Format. |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
Documents can have several pages, a table of content, an information section and |
38
|
|
|
|
|
|
|
many other PDF elements. |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=head1 SYNOPSIS |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
C provides an easy module to create PDF output from your perl script. |
43
|
|
|
|
|
|
|
It is designed to be easy to use and simple to install and maintain. It provides a |
44
|
|
|
|
|
|
|
couple of subroutines to handle text, fonts, images and drawing primitives. Simple |
45
|
|
|
|
|
|
|
documents are easy to create with the supplied routines. |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
In addition to be reasonable simple C is written in pure Perl and has |
48
|
|
|
|
|
|
|
no external dependencies (libraries, other modules, etc.). It should run on any |
49
|
|
|
|
|
|
|
platform where perl is available. |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
For complex stuff some understanding of the underlying Postscript/PDF format is |
52
|
|
|
|
|
|
|
necessary. In this case it might be better go with the more complete L |
53
|
|
|
|
|
|
|
modules to gain more features at the expense of a steeper learning curve. |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
Example PDF creation with C (see L for details |
56
|
|
|
|
|
|
|
of methods available on a page): |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
use strict; use warnings; |
59
|
|
|
|
|
|
|
use PDF::Create; |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
my $pdf = PDF::Create->new( |
62
|
|
|
|
|
|
|
'filename' => 'sample.pdf', |
63
|
|
|
|
|
|
|
'Author' => 'John Doe', |
64
|
|
|
|
|
|
|
'Title' => 'Sample PDF', |
65
|
|
|
|
|
|
|
'CreationDate' => [ localtime ] |
66
|
|
|
|
|
|
|
); |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
# Add a A4 sized page |
69
|
|
|
|
|
|
|
my $root = $pdf->new_page('MediaBox' => $pdf->get_page_size('A4')); |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
# Add a page which inherits its attributes from $root |
72
|
|
|
|
|
|
|
my $page1 = $root->new_page; |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
# Prepare a font |
75
|
|
|
|
|
|
|
my $font = $pdf->font('BaseFont' => 'Helvetica'); |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
# Prepare a Table of Content |
78
|
|
|
|
|
|
|
my $toc = $pdf->new_outline('Title' => 'Title Page', 'Destination' => $page1); |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
# Write some text |
81
|
|
|
|
|
|
|
$page1->stringc($font, 40, 306, 426, 'PDF::Create'); |
82
|
|
|
|
|
|
|
$page1->stringc($font, 20, 306, 396, "version $PDF::Create::VERSION"); |
83
|
|
|
|
|
|
|
$page1->stringc($font, 20, 306, 300, 'by John Doe '); |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# Add another page |
86
|
|
|
|
|
|
|
my $page2 = $root->new_page; |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
# Draw some lines |
89
|
|
|
|
|
|
|
$page2->line(0, 0, 592, 840); |
90
|
|
|
|
|
|
|
$page2->line(0, 840, 592, 0); |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
$toc->new_outline('Title' => 'Second Page', 'Destination' => $page2); |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
# Close the file and write the PDF |
95
|
|
|
|
|
|
|
$pdf->close; |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
=head1 CONSTRUCTOR |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
The method C create a new pdf structure for your PDF. It returns an |
100
|
|
|
|
|
|
|
object handle which can be used to add more stuff to the PDF. The parameter keys |
101
|
|
|
|
|
|
|
to the constructor are detailed as below: |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
+--------------+------------------------------------------------------------+ |
104
|
|
|
|
|
|
|
| Key | Description | |
105
|
|
|
|
|
|
|
+--------------+------------------------------------------------------------+ |
106
|
|
|
|
|
|
|
| | | |
107
|
|
|
|
|
|
|
| filename | Destination file that will contain resulting PDF or '-' for| |
108
|
|
|
|
|
|
|
| | stdout. If neither filename or fh are specified, the | |
109
|
|
|
|
|
|
|
| | content will be stored in memory and returned when calling | |
110
|
|
|
|
|
|
|
| | close(). | |
111
|
|
|
|
|
|
|
| | | |
112
|
|
|
|
|
|
|
| fh | Already opened filehandle that will contain resulting PDF. | |
113
|
|
|
|
|
|
|
| | See comment above regarding close(). | |
114
|
|
|
|
|
|
|
| | | |
115
|
|
|
|
|
|
|
| Version | PDF Version to claim, can be 1.0 to 1.3 (default: 1. | |
116
|
|
|
|
|
|
|
| | | |
117
|
|
|
|
|
|
|
| PageMode | How the document should appear when opened.Possible values | |
118
|
|
|
|
|
|
|
| | UseNone (Default), UseOutlines, UseThumbs and FullScreen | |
119
|
|
|
|
|
|
|
| | | |
120
|
|
|
|
|
|
|
| Author | The name of the person who created this document. | |
121
|
|
|
|
|
|
|
| | | |
122
|
|
|
|
|
|
|
| Creator | If the document was converted into a PDF document from | |
123
|
|
|
|
|
|
|
| | another form, this is the name of the application that | |
124
|
|
|
|
|
|
|
| | created the document. | |
125
|
|
|
|
|
|
|
| | | |
126
|
|
|
|
|
|
|
| Title | The title of the document. | |
127
|
|
|
|
|
|
|
| | | |
128
|
|
|
|
|
|
|
| Subject | The subject of the document. | |
129
|
|
|
|
|
|
|
| | | |
130
|
|
|
|
|
|
|
| Keywords | Keywords associated with the document. | |
131
|
|
|
|
|
|
|
| | | |
132
|
|
|
|
|
|
|
| CreationDate | The date the document was created.This is passed as an | |
133
|
|
|
|
|
|
|
| | anonymous array in the same format as localtime returns. | |
134
|
|
|
|
|
|
|
| | | |
135
|
|
|
|
|
|
|
| Debug | The debug level, defaults to 0. It can be any positive | |
136
|
|
|
|
|
|
|
| | integers. | |
137
|
|
|
|
|
|
|
| | | |
138
|
|
|
|
|
|
|
+--------------+------------------------------------------------------------+ |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
Example: |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
my $pdf = PDF::Create->new( |
143
|
|
|
|
|
|
|
'filename' => 'sample.pdf', |
144
|
|
|
|
|
|
|
'Version' => 1.2, |
145
|
|
|
|
|
|
|
'PageMode' => 'UseOutlines', |
146
|
|
|
|
|
|
|
'Author' => 'John Doe', |
147
|
|
|
|
|
|
|
'Title' => 'My Title', |
148
|
|
|
|
|
|
|
'CreationDate' => [ localtime ] |
149
|
|
|
|
|
|
|
); |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
If you are writing a CGI you can send your PDF on the fly to stdout / directly to |
152
|
|
|
|
|
|
|
the browser using '-' as filename. |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
CGI Example: |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
use CGI; |
157
|
|
|
|
|
|
|
use PDF::Create; |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
print CGI::header(-type => 'application/x-pdf', -attachment => 'sample.pdf'); |
160
|
|
|
|
|
|
|
my $pdf = PDF::Create->new( |
161
|
|
|
|
|
|
|
'filename' => '-', |
162
|
|
|
|
|
|
|
'Author' => 'John Doe', |
163
|
|
|
|
|
|
|
'Title' => 'My title', |
164
|
|
|
|
|
|
|
'CreationDate' => [ localtime ] |
165
|
|
|
|
|
|
|
); |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=cut |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
sub new { |
170
|
42
|
|
|
42
|
0
|
69855
|
my ($this, %params) = @_; |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
# validate constructor keys |
173
|
42
|
|
|
|
|
3634
|
my %valid_constructor_keys = ( |
174
|
|
|
|
|
|
|
'fh' => 1, |
175
|
|
|
|
|
|
|
'filename' => 1, |
176
|
|
|
|
|
|
|
'Version' => 1, |
177
|
|
|
|
|
|
|
'PageMode' => 1, |
178
|
|
|
|
|
|
|
'Author' => 1, |
179
|
|
|
|
|
|
|
'Creator' => 1, |
180
|
|
|
|
|
|
|
'Title' => 1, |
181
|
|
|
|
|
|
|
'Subject' => 1, |
182
|
|
|
|
|
|
|
'Keywords' => 1, |
183
|
|
|
|
|
|
|
'Debug' => 1, |
184
|
|
|
|
|
|
|
'CreationDate' => 1, |
185
|
|
|
|
|
|
|
); |
186
|
42
|
|
|
|
|
3466
|
foreach (keys %params) { |
187
|
|
|
|
|
|
|
croak "Invalid constructor key '$_' received." |
188
|
138
|
100
|
|
|
|
7674
|
unless (exists $valid_constructor_keys{$_}); |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
|
191
|
34
|
100
|
66
|
|
|
3665
|
if (exists $params{PageMode} && defined $params{PageMode}) { |
192
|
|
|
|
|
|
|
# validate PageMode key value |
193
|
26
|
|
|
|
|
3448
|
my %valid_page_mode_values = ( |
194
|
|
|
|
|
|
|
'UseNone' => 1, |
195
|
|
|
|
|
|
|
'UseOutlines' => 1, |
196
|
|
|
|
|
|
|
'UseThumbs' => 1, |
197
|
|
|
|
|
|
|
'FullScreen' => 1); |
198
|
|
|
|
|
|
|
croak "Invalid value for key 'PageMode' received '". $params{PageMode} . "'" |
199
|
26
|
100
|
|
|
|
6950
|
unless (exists $valid_page_mode_values{$params{PageMode}}); |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
|
202
|
33
|
100
|
66
|
|
|
3511
|
if (exists $params{Debug} && defined $params{Debug}) { |
203
|
|
|
|
|
|
|
# validate Debug key value |
204
|
|
|
|
|
|
|
croak "Invalid value for key 'Debug' received '". $params{Debug} . "'" |
205
|
2
|
100
|
66
|
|
|
89
|
unless (($params{Debug} =~ /^\d+$/) && ($params{Debug} >= 0)); |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
|
208
|
32
|
|
33
|
|
|
3540
|
my $class = ref($this) || $this; |
209
|
32
|
|
|
|
|
3704
|
my $self = {}; |
210
|
32
|
|
|
|
|
3475
|
bless $self, $class; |
211
|
|
|
|
|
|
|
|
212
|
32
|
|
|
|
|
3496
|
$self->{'data'} = ''; |
213
|
32
|
|
100
|
|
|
3459
|
$self->{'version'} = $params{'Version'} || "1.2"; |
214
|
32
|
|
|
|
|
3417
|
$self->{'trailer'} = {}; |
215
|
|
|
|
|
|
|
|
216
|
32
|
|
|
|
|
3552
|
$self->{'pages'} = PDF::Create::Page->new(); |
217
|
32
|
|
|
|
|
3771
|
$self->{'current_page'} = $self->{'pages'}; |
218
|
|
|
|
|
|
|
# circular reference |
219
|
32
|
|
|
|
|
3714
|
$self->{'pages'}->{'pdf'} = $self; |
220
|
32
|
|
|
|
|
3733
|
weaken $self->{pages}{pdf}; |
221
|
32
|
|
|
|
|
3746
|
$self->{'page_count'} = 0; |
222
|
32
|
|
|
|
|
3680
|
$self->{'outline_count'} = 0; |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
# cross-reference table start address |
225
|
32
|
|
|
|
|
3748
|
$self->{'crossreftblstartaddr'} = 0; |
226
|
32
|
|
|
|
|
3726
|
$self->{'generation_number'} = 0; |
227
|
32
|
|
|
|
|
3715
|
$self->{'object_number'} = 0; |
228
|
|
|
|
|
|
|
|
229
|
32
|
100
|
|
|
|
3793
|
if ( defined $params{'fh'} ) { |
|
|
100
|
|
|
|
|
|
230
|
1
|
|
|
|
|
2
|
$self->{'fh'} = $params{'fh'}; |
231
|
|
|
|
|
|
|
} elsif ( defined $params{'filename'} ) { |
232
|
26
|
|
|
|
|
3674
|
$self->{'filename'} = $params{'filename'}; |
233
|
26
|
|
|
|
|
3879
|
my $fh = FileHandle->new( "> $self->{'filename'}" ); |
234
|
26
|
50
|
|
|
|
104987
|
carp "PDF::Create.pm: $self->{'filename'}: $!\n" unless defined $fh; |
235
|
26
|
|
|
|
|
3492
|
binmode $fh; |
236
|
26
|
|
|
|
|
6727
|
$self->{'fh'} = $fh; |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
|
239
|
32
|
|
|
|
|
3425
|
$self->{'catalog'} = {}; |
240
|
32
|
100
|
|
|
|
3588
|
$self->{'catalog'}{'PageMode'} = $params{'PageMode'} if defined $params{'PageMode'}; |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
# Header: add version |
243
|
32
|
|
|
|
|
3627
|
$self->add_version; |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
# Info |
246
|
32
|
100
|
|
|
|
3530
|
$self->{'Author'} = $params{'Author'} if defined $params{'Author'}; |
247
|
32
|
50
|
|
|
|
3445
|
$self->{'Creator'} = $params{'Creator'} if defined $params{'Creator'}; |
248
|
32
|
100
|
|
|
|
3546
|
$self->{'Title'} = $params{'Title'} if defined $params{'Title'}; |
249
|
32
|
50
|
|
|
|
3523
|
$self->{'Subject'} = $params{'Subject'} if defined $params{'Subject'}; |
250
|
32
|
50
|
|
|
|
3632
|
$self->{'Keywords'} = $params{'Keywords'} if defined $params{'Keywords'}; |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
# TODO: Default creation date from system date |
253
|
32
|
50
|
|
|
|
3626
|
if ( defined $params{'CreationDate'} ) { |
254
|
|
|
|
|
|
|
$self->{'CreationDate'} = |
255
|
|
|
|
|
|
|
sprintf "D:%4u%0.2u%0.2u%0.2u%0.2u%0.2u", |
256
|
|
|
|
|
|
|
$params{'CreationDate'}->[5] + 1900, $params{'CreationDate'}->[4] + 1, |
257
|
|
|
|
|
|
|
$params{'CreationDate'}->[3], $params{'CreationDate'}->[2], |
258
|
0
|
|
|
|
|
0
|
$params{'CreationDate'}->[1], $params{'CreationDate'}->[0]; |
259
|
|
|
|
|
|
|
} |
260
|
32
|
100
|
|
|
|
3487
|
if ( defined $params{'Debug'} ) { |
261
|
1
|
|
|
|
|
2
|
$DEBUG = $params{'Debug'}; |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
# Enable stack trace for PDF::Create internal routines |
264
|
1
|
|
|
|
|
2
|
$Carp::Internal{ ('PDF::Create') }++; |
265
|
|
|
|
|
|
|
} |
266
|
32
|
|
|
|
|
3609
|
debug( 1, "Debugging level $DEBUG" ); |
267
|
32
|
|
|
|
|
8621
|
return $self; |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
=head1 METHODS |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
=head2 new_page(%params) |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
Add a page to the document using the given parameters. C must be called |
275
|
|
|
|
|
|
|
first to initialize a root page, used as model for further pages.Returns a handle |
276
|
|
|
|
|
|
|
to the newly created page. Parameters can be: |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
+-----------+---------------------------------------------------------------+ |
279
|
|
|
|
|
|
|
| Key | Description | |
280
|
|
|
|
|
|
|
+-----------+---------------------------------------------------------------+ |
281
|
|
|
|
|
|
|
| | | |
282
|
|
|
|
|
|
|
| Parent | The parent of this page in the pages tree.This is page object.| |
283
|
|
|
|
|
|
|
| | | |
284
|
|
|
|
|
|
|
| Resources | Resources required by this page. | |
285
|
|
|
|
|
|
|
| | | |
286
|
|
|
|
|
|
|
| MediaBox | Rectangle specifying the natural size of the page,for example | |
287
|
|
|
|
|
|
|
| | the dimensions of an A4 sheet of paper. The coordinates are | |
288
|
|
|
|
|
|
|
| | measured in default user space units It must be the reference | |
289
|
|
|
|
|
|
|
| | of 4 values array.You can use C to get to get | |
290
|
|
|
|
|
|
|
| | the size of standard paper sizes.C knows about | |
291
|
|
|
|
|
|
|
| | A0-A6, A4L (landscape), Letter, Legal, Broadsheet, Ledger, | |
292
|
|
|
|
|
|
|
| | Tabloid, Executive and 36x36. | |
293
|
|
|
|
|
|
|
| CropBox | Rectangle specifying the default clipping region for the page | |
294
|
|
|
|
|
|
|
| | when displayed or printed. The default is the value of the | |
295
|
|
|
|
|
|
|
| | MediaBox. | |
296
|
|
|
|
|
|
|
| | | |
297
|
|
|
|
|
|
|
| ArtBox | Rectangle specifying an area of the page to be used when | |
298
|
|
|
|
|
|
|
| | placing PDF content into another application. The default is | |
299
|
|
|
|
|
|
|
| | the value of the CropBox. [PDF 1.3] | |
300
|
|
|
|
|
|
|
| | | |
301
|
|
|
|
|
|
|
| TrimBox | Rectangle specifying the intended finished size of the page | |
302
|
|
|
|
|
|
|
| | (for example, the dimensions of an A4 sheet of paper).In some | |
303
|
|
|
|
|
|
|
| | cases,the MediaBox will be a larger rectangle, which includes | |
304
|
|
|
|
|
|
|
| | printing instructions, cut marks or other content.The default | |
305
|
|
|
|
|
|
|
| | is the value of the CropBox. [PDF 1.3]. | |
306
|
|
|
|
|
|
|
| | | |
307
|
|
|
|
|
|
|
| BleedBox | Rectangle specifying the region to which all page content | |
308
|
|
|
|
|
|
|
| | should be clipped if the page is being output in a production | |
309
|
|
|
|
|
|
|
| | environment. In such environments, a bleed area is desired, | |
310
|
|
|
|
|
|
|
| | to accommodate physical limitations of cutting, folding, and | |
311
|
|
|
|
|
|
|
| | trimming equipment. The actual printed page may include | |
312
|
|
|
|
|
|
|
| | printer's marks that fall outside the bleed box. The default | |
313
|
|
|
|
|
|
|
| | is the value of the CropBox.[PDF 1.3] | |
314
|
|
|
|
|
|
|
| | | |
315
|
|
|
|
|
|
|
| Rotate | Specifies the number of degrees the page should be rotated | |
316
|
|
|
|
|
|
|
| | clockwise when it is displayed or printed. This value must be | |
317
|
|
|
|
|
|
|
| | zero (the default) or a multiple of 90. The entire page, | |
318
|
|
|
|
|
|
|
| | including contents is rotated. | |
319
|
|
|
|
|
|
|
| | | |
320
|
|
|
|
|
|
|
+-----------+---------------------------------------------------------------+ |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
Example: |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
my $a4 = $pdf->new_page( 'MediaBox' => $pdf->get_page_size('A4') ); |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
my $page1 = $a4->new_page; |
327
|
|
|
|
|
|
|
$page1->string($f1, 20, 306, 396, "some text on page 1"); |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
my $page2 = $a4->new_page; |
330
|
|
|
|
|
|
|
$page2->string($f1, 20, 306, 396, "some text on page 2"); |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
=cut |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
sub new_page { |
335
|
51
|
|
|
51
|
1
|
10139
|
my ($self, %params) = @_; |
336
|
|
|
|
|
|
|
|
337
|
51
|
|
|
|
|
6684
|
my %valid_new_page_parameters = map { $_ => 1 } (qw/Parent Resources MediaBox CropBox ArtBox TrimBox BleedBox Rotate/); |
|
408
|
|
|
|
|
98586
|
|
338
|
51
|
|
|
|
|
6114
|
foreach my $key (keys %params) { |
339
|
|
|
|
|
|
|
croak "PDF::Create.pm - new_page(): Received invalid key [$key]" |
340
|
51
|
100
|
|
|
|
12037
|
unless (exists $valid_new_page_parameters{$key}); |
341
|
|
|
|
|
|
|
} |
342
|
|
|
|
|
|
|
|
343
|
50
|
|
66
|
|
|
6223
|
my $parent = $params{'Parent'} || $self->{'pages'}; |
344
|
50
|
|
|
|
|
5966
|
my $name = "Page " . ++$self->{'page_count'}; |
345
|
50
|
|
|
|
|
6375
|
my $page = $parent->add( $self->reserve( $name, "Page" ), $name ); |
346
|
50
|
50
|
|
|
|
6373
|
$page->{'resources'} = $params{'Resources'} if defined $params{'Resources'}; |
347
|
50
|
100
|
|
|
|
6120
|
$page->{'mediabox'} = $params{'MediaBox'} if defined $params{'MediaBox'}; |
348
|
50
|
50
|
|
|
|
6027
|
$page->{'cropbox'} = $params{'CropBox'} if defined $params{'CropBox'}; |
349
|
50
|
50
|
|
|
|
6422
|
$page->{'artbox'} = $params{'ArtBox'} if defined $params{'ArtBox'}; |
350
|
50
|
50
|
|
|
|
6555
|
$page->{'trimbox'} = $params{'TrimBox'} if defined $params{'TrimBox'}; |
351
|
50
|
50
|
|
|
|
6338
|
$page->{'bleedbox'} = $params{'BleedBox'} if defined $params{'BleedBox'}; |
352
|
50
|
50
|
|
|
|
5969
|
$page->{'rotate'} = $params{'Rotate'} if defined $params{'Rotate'}; |
353
|
|
|
|
|
|
|
|
354
|
50
|
|
|
|
|
5727
|
$self->{'current_page'} = $page; |
355
|
|
|
|
|
|
|
|
356
|
50
|
|
|
|
|
16135
|
$page; |
357
|
|
|
|
|
|
|
} |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
=head2 font(%params) |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
Prepare a font using the given arguments. This font will be added to the document |
362
|
|
|
|
|
|
|
only if it is used at least once before the close method is called.Parameters are |
363
|
|
|
|
|
|
|
listed below: |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
+----------+----------------------------------------------------------------+ |
366
|
|
|
|
|
|
|
| Key | Description | |
367
|
|
|
|
|
|
|
+----------+----------------------------------------------------------------+ |
368
|
|
|
|
|
|
|
| Subtype | Type of font. PDF defines some types of fonts. It must be one | |
369
|
|
|
|
|
|
|
| | of the predefined type Type1, Type3, TrueType or Type0.In this | |
370
|
|
|
|
|
|
|
| | version, only Type1 is supported. This is the default value. | |
371
|
|
|
|
|
|
|
| | | |
372
|
|
|
|
|
|
|
| Encoding | Specifies the encoding from which the new encoding differs. | |
373
|
|
|
|
|
|
|
| | It must be one of the predefined encodings MacRomanEncoding, | |
374
|
|
|
|
|
|
|
| | MacExpertEncoding or WinAnsiEncoding. In this version, only | |
375
|
|
|
|
|
|
|
| | WinAnsiEncoding is supported. This is the default value. | |
376
|
|
|
|
|
|
|
| | | |
377
|
|
|
|
|
|
|
| BaseFont | The PostScript name of the font. It can be one of the following| |
378
|
|
|
|
|
|
|
| | base fonts: Courier, Courier-Bold, Courier-BoldOblique, | |
379
|
|
|
|
|
|
|
| | Courier-Oblique, Helvetica, Helvetica-Bold, | |
380
|
|
|
|
|
|
|
| | Helvetica-BoldOblique, Helvetica-Oblique, Times-Roman, | |
381
|
|
|
|
|
|
|
| | Times-Bold, Times-Italic, Times-BoldItalic or Symbol. | |
382
|
|
|
|
|
|
|
+----------+----------------------------------------------------------------+ |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
The ZapfDingbats font is not supported in this version.Default font is Helvetica. |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
my $f1 = $pdf->font('BaseFont' => 'Helvetica'); |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
=cut |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
sub font { |
391
|
46
|
|
|
46
|
1
|
11888
|
my ($self, %params) = @_; |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
my %valid_font_parameters = ( |
394
|
184
|
|
|
|
|
29939
|
'Subtype' => { map { $_ => 1 } qw/Type0 Type1 Type3 TrueType/ }, |
395
|
184
|
|
|
|
|
30239
|
'Encoding' => { map { $_ => 1 } qw/MacRomanEncoding MacExpertEncoding WinAnsiEncoding Symbol/ }, |
396
|
46
|
|
|
|
|
3763
|
'BaseFont' => { map { $_ => 1 } qw/Courier Courier-Bold Courier-BoldOblique Courier-Oblique |
|
598
|
|
|
|
|
95909
|
|
397
|
|
|
|
|
|
|
Helvetica Helvetica-Bold Helvetica-BoldOblique Helvetica-Oblique |
398
|
|
|
|
|
|
|
Times-Roman Times-Bold Times-Italic Times-BoldItalic Symbol/ }, |
399
|
|
|
|
|
|
|
); |
400
|
|
|
|
|
|
|
|
401
|
46
|
|
|
|
|
4068
|
foreach my $key (keys %params) { |
402
|
|
|
|
|
|
|
croak "PDF::Create.pm - font(): Received invalid key [$key]" |
403
|
128
|
100
|
|
|
|
11820
|
unless (exists $valid_font_parameters{$key}); |
404
|
127
|
|
|
|
|
11693
|
my $value = $params{$key}; |
405
|
|
|
|
|
|
|
croak "PDF::Create.pm - font(): Received invalid value [$value] for key [$key]" |
406
|
127
|
100
|
66
|
|
|
15751
|
if (defined $value && !(exists $valid_font_parameters{$key}->{$value})); |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
|
409
|
42
|
|
|
|
|
3708
|
my $num = 1 + scalar keys %{ $self->{'fonts'} }; |
|
42
|
|
|
|
|
7580
|
|
410
|
|
|
|
|
|
|
$self->{'fonts'}{$num} = { |
411
|
|
|
|
|
|
|
'Subtype' => $self->name( $params{'Subtype'} || 'Type1' ), |
412
|
|
|
|
|
|
|
'Encoding' => $self->name( $params{'Encoding'} || 'WinAnsiEncoding' ), |
413
|
42
|
|
100
|
|
|
3913
|
'BaseFont' => $self->name( $params{'BaseFont'} || 'Helvetica' ), |
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
414
|
|
|
|
|
|
|
'Name' => $self->name("F$num"), |
415
|
|
|
|
|
|
|
'Type' => $self->name("Font"), |
416
|
|
|
|
|
|
|
}; |
417
|
|
|
|
|
|
|
|
418
|
42
|
|
|
|
|
8595
|
$num; |
419
|
|
|
|
|
|
|
} |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
=head2 new_outline(%params) |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
Adds an outline to the document using the given parameters. Return the newly |
424
|
|
|
|
|
|
|
created outline. Parameters can be: |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
+-------------+-------------------------------------------------------------+ |
427
|
|
|
|
|
|
|
| Key | Description | |
428
|
|
|
|
|
|
|
+-------------+-------------------------------------------------------------+ |
429
|
|
|
|
|
|
|
| | | |
430
|
|
|
|
|
|
|
| Title | The title of the outline. Mandatory. | |
431
|
|
|
|
|
|
|
| | | |
432
|
|
|
|
|
|
|
| Destination | The Destination of this outline item. In this version,it is | |
433
|
|
|
|
|
|
|
| | only possible to give a page as destination. The default | |
434
|
|
|
|
|
|
|
| | destination is the current page. | |
435
|
|
|
|
|
|
|
| | | |
436
|
|
|
|
|
|
|
| Parent | The parent of this outline in the outlines tree. This is an | |
437
|
|
|
|
|
|
|
| | outline object. This way you represent the tree of your | |
438
|
|
|
|
|
|
|
| | outlines. | |
439
|
|
|
|
|
|
|
| | | |
440
|
|
|
|
|
|
|
+-------------+-------------------------------------------------------------+ |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
Example: |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
my $outline = $pdf->new_outline('Title' => 'Item 1'); |
445
|
|
|
|
|
|
|
$pdf->new_outline('Title' => 'Item 1.1', 'Parent' => $outline); |
446
|
|
|
|
|
|
|
$pdf->new_outline('Title' => 'Item 1.2', 'Parent' => $outline); |
447
|
|
|
|
|
|
|
$pdf->new_outline('Title' => 'Item 2'); |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
=cut |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
sub new_outline { |
452
|
34
|
|
|
34
|
1
|
11525
|
my ($self, %params) = @_; |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
croak "PDF::Create - new_outline(): Missing required key [Title]." |
455
|
34
|
50
|
|
|
|
7623
|
unless (exists $params{'Title'}); |
456
|
|
|
|
|
|
|
croak "PDF::Create - new_outline(): Required key [Title] undefined." |
457
|
34
|
50
|
|
|
|
7432
|
unless (defined $params{'Title'}); |
458
|
|
|
|
|
|
|
|
459
|
34
|
100
|
|
|
|
7419
|
if (defined $params{Destination}) { |
460
|
|
|
|
|
|
|
croak "PDF::Create - new_outline(): Invalid value for key [Destination]." |
461
|
14
|
50
|
|
|
|
4405
|
unless (ref($params{Destination}) eq 'PDF::Create::Page'); |
462
|
|
|
|
|
|
|
} |
463
|
|
|
|
|
|
|
|
464
|
34
|
100
|
|
|
|
7516
|
if (defined $params{Parent}) { |
465
|
|
|
|
|
|
|
croak "PDF::Create - new_outline(): Invalid value for key [Parent]." |
466
|
18
|
50
|
|
|
|
8450
|
unless (ref($params{Parent}) eq 'PDF::Create::Outline'); |
467
|
|
|
|
|
|
|
} |
468
|
|
|
|
|
|
|
|
469
|
34
|
100
|
|
|
|
7403
|
unless ( defined $self->{'outlines'} ) { |
470
|
9
|
|
|
|
|
2326
|
$self->{'outlines'} = PDF::Create::Outline->new(); |
471
|
|
|
|
|
|
|
# circular reference |
472
|
9
|
|
|
|
|
2116
|
$self->{'outlines'}->{'pdf'} = $self; |
473
|
9
|
|
|
|
|
2183
|
weaken $self->{'outlines'}->{'pdf'}; |
474
|
9
|
|
|
|
|
4523
|
$self->{'outlines'}->{'Status'} = 'opened'; |
475
|
|
|
|
|
|
|
} |
476
|
|
|
|
|
|
|
|
477
|
34
|
|
66
|
|
|
7404
|
my $parent = $params{'Parent'} || $self->{'outlines'}; |
478
|
34
|
|
|
|
|
7310
|
my $name = "Outline " . ++$self->{'outline_count'}; |
479
|
34
|
100
|
|
|
|
7405
|
$params{'Destination'} = $self->{'current_page'} unless defined $params{'Destination'}; |
480
|
34
|
|
|
|
|
7390
|
my $outline = $parent->add( $self->reserve( $name, "Outline" ), $name, %params ); |
481
|
34
|
|
|
|
|
20610
|
$outline; |
482
|
|
|
|
|
|
|
} |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
=head2 get_page_size($name) |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
Returns the size of standard paper used for MediaBox-parameter of C. |
487
|
|
|
|
|
|
|
C has one optional parameter to specify the paper name. Possible |
488
|
|
|
|
|
|
|
values are a0-a6, a4l,letter,broadsheet,ledger,tabloid,legal,executive and 36x36. |
489
|
|
|
|
|
|
|
Default is a4. |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
my $root = $pdf->new_page( 'MediaBox' => $pdf->get_page_size('A4') ); |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
=cut |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
sub get_page_size { |
496
|
28
|
|
|
28
|
1
|
9041
|
my ($self, $name) = @_; |
497
|
|
|
|
|
|
|
|
498
|
28
|
|
|
|
|
450
|
my %pagesizes = ( |
499
|
|
|
|
|
|
|
'A0' => [ 0, 0, 2380, 3368 ], |
500
|
|
|
|
|
|
|
'A1' => [ 0, 0, 1684, 2380 ], |
501
|
|
|
|
|
|
|
'A2' => [ 0, 0, 1190, 1684 ], |
502
|
|
|
|
|
|
|
'A3' => [ 0, 0, 842, 1190 ], |
503
|
|
|
|
|
|
|
'A4' => [ 0, 0, 595, 842 ], |
504
|
|
|
|
|
|
|
'A4L' => [ 0, 0, 842, 595 ], |
505
|
|
|
|
|
|
|
'A5' => [ 0, 0, 421, 595 ], |
506
|
|
|
|
|
|
|
'A6' => [ 0, 0, 297, 421 ], |
507
|
|
|
|
|
|
|
'LETTER' => [ 0, 0, 612, 792 ], |
508
|
|
|
|
|
|
|
'BROADSHEET' => [ 0, 0, 1296, 1584 ], |
509
|
|
|
|
|
|
|
'LEDGER' => [ 0, 0, 1224, 792 ], |
510
|
|
|
|
|
|
|
'TABLOID' => [ 0, 0, 792, 1224 ], |
511
|
|
|
|
|
|
|
'LEGAL' => [ 0, 0, 612, 1008 ], |
512
|
|
|
|
|
|
|
'EXECUTIVE' => [ 0, 0, 522, 756 ], |
513
|
|
|
|
|
|
|
'36X36' => [ 0, 0, 2592, 2592 ], |
514
|
|
|
|
|
|
|
); |
515
|
28
|
50
|
|
|
|
91
|
if (defined $name) { |
516
|
28
|
|
|
|
|
67
|
$name = uc($name); |
517
|
|
|
|
|
|
|
# validate page size |
518
|
28
|
100
|
|
|
|
143
|
croak "Invalid page size name '$name' received." unless (exists $pagesizes{$name}); |
519
|
|
|
|
|
|
|
} |
520
|
|
|
|
|
|
|
else { |
521
|
0
|
|
|
|
|
0
|
$name = 'A4'; |
522
|
|
|
|
|
|
|
} |
523
|
|
|
|
|
|
|
|
524
|
27
|
|
|
|
|
160
|
return $pagesizes{$name}; |
525
|
|
|
|
|
|
|
} |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
=head2 version($number) |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
Set and return version number. Valid version numbers are 1.0, 1.1, 1.2 and 1.3. |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
=cut |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
sub version { |
534
|
5
|
|
|
5
|
1
|
10
|
my ($self, $v) = @_; |
535
|
|
|
|
|
|
|
|
536
|
5
|
50
|
|
|
|
7
|
if (defined $v) { |
537
|
5
|
100
|
|
|
|
234
|
croak "ERROR: Invalid version number $v received.\n" |
538
|
|
|
|
|
|
|
unless ($v =~ /^1\.[0,1,2,3]$/); |
539
|
3
|
|
|
|
|
5
|
$self->{'version'} = $v; |
540
|
|
|
|
|
|
|
} |
541
|
3
|
|
|
|
|
8
|
$self->{'version'}; |
542
|
|
|
|
|
|
|
} |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
=head2 close(%params) |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
Close does the work of creating the PDF data from the objects collected before. |
547
|
|
|
|
|
|
|
You must call C after you have added all the contents as most of the |
548
|
|
|
|
|
|
|
real work building the PDF is performed there. If omit calling close you get |
549
|
|
|
|
|
|
|
no PDF output. Returns the raw content of the PDF. |
550
|
|
|
|
|
|
|
If C was provided when creating object of C then it does not |
551
|
|
|
|
|
|
|
try to close the file handle. It is, therefore, advised you call C |
552
|
|
|
|
|
|
|
rather than C. |
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
=cut |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
sub close { |
557
|
15
|
|
|
15
|
1
|
3911
|
my ($self, %params) = @_; |
558
|
|
|
|
|
|
|
|
559
|
15
|
|
|
|
|
1455
|
debug( 2, "Closing PDF" ); |
560
|
15
|
|
|
|
|
1389
|
my $raw_data = $self->flush; |
561
|
|
|
|
|
|
|
|
562
|
15
|
100
|
66
|
|
|
1271
|
if (defined $self->{'fh'} && defined $self->{'filename'}) { |
563
|
14
|
|
|
|
|
1225
|
$self->{'fh'}->close; |
564
|
|
|
|
|
|
|
} |
565
|
|
|
|
|
|
|
|
566
|
15
|
|
|
|
|
11891
|
return $raw_data; |
567
|
|
|
|
|
|
|
} |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
=head2 flush() |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
Generate the PDF content and returns the raw content as it is. |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
=cut |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
sub flush { |
576
|
15
|
|
|
15
|
1
|
1385
|
my ($self) = @_; |
577
|
|
|
|
|
|
|
|
578
|
15
|
|
|
|
|
1436
|
debug( 2, "Flushing PDF" ); |
579
|
15
|
|
|
|
|
1391
|
$self->page_stream; |
580
|
15
|
100
|
|
|
|
1078
|
$self->add_outlines if defined $self->{'outlines'}; |
581
|
15
|
|
|
|
|
2095
|
$self->add_catalog; |
582
|
15
|
|
|
|
|
1103
|
$self->add_pages; |
583
|
15
|
|
|
|
|
1127
|
$self->add_info; |
584
|
15
|
|
|
|
|
1586
|
$self->add_crossrefsection; |
585
|
15
|
|
|
|
|
1130
|
$self->add_trailer; |
586
|
|
|
|
|
|
|
|
587
|
15
|
|
|
|
|
2406
|
return $self->{data}; |
588
|
|
|
|
|
|
|
} |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
=head2 reserve($name, $type) |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
Reserve the next object number for the given object type. |
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
=cut |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
sub reserve { |
597
|
227
|
|
|
227
|
1
|
26682
|
my ($self, $name, $type) = @_;; |
598
|
|
|
|
|
|
|
|
599
|
227
|
100
|
|
|
|
26198
|
$type = $name unless defined $type; |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
confess "Error: an object has already been reserved using this name '$name' " |
602
|
227
|
50
|
|
|
|
26131
|
if defined $self->{'reservations'}{$name}; |
603
|
227
|
|
|
|
|
26787
|
$self->{'object_number'}++; |
604
|
227
|
|
|
|
|
27508
|
debug( 2, "reserve(): name=$name type=$type number=$self->{'object_number'} generation=$self->{'generation_number'}" ); |
605
|
227
|
|
|
|
|
27927
|
$self->{'reservations'}{$name} = [ $self->{'object_number'}, $self->{'generation_number'}, $type ]; |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
# Annotations added here by Gary Lieberman. |
609
|
|
|
|
|
|
|
# |
610
|
|
|
|
|
|
|
# Store the Object ID and the Generation Number for later use when we write |
611
|
|
|
|
|
|
|
# out the /Page object. |
612
|
227
|
100
|
|
|
|
27486
|
if ($type eq 'Annotation') { |
613
|
2
|
|
|
|
|
17
|
$self->{'Annots'}{ $self->{'object_number'} } = $self->{'generation_number'}; |
614
|
|
|
|
|
|
|
} |
615
|
|
|
|
|
|
|
|
616
|
227
|
|
|
|
|
55287
|
[ $self->{'object_number'}, $self->{'generation_number'} ]; |
617
|
|
|
|
|
|
|
} |
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
=head2 add_comment($message) |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
Add comment to the document.The string will show up in the PDF as postscript-style |
622
|
|
|
|
|
|
|
comment: |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
% this is a postscript comment |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
=cut |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
sub add_comment { |
629
|
7
|
|
|
7
|
1
|
4081
|
my ($self, $comment) = @_; |
630
|
|
|
|
|
|
|
|
631
|
7
|
50
|
|
|
|
35
|
$comment = '' unless defined $comment; |
632
|
7
|
|
|
|
|
38
|
debug( 2, "add_comment(): $comment" ); |
633
|
7
|
|
|
|
|
36
|
$self->add( "%" . $comment ); |
634
|
7
|
|
|
|
|
22
|
$self->cr; |
635
|
|
|
|
|
|
|
} |
636
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
=head2 annotation(%params) |
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
Adds an annotation object, for the time being we only do the 'Link' - 'URI' kind |
640
|
|
|
|
|
|
|
This is a sensitive area in the PDF document where text annotations are shown or |
641
|
|
|
|
|
|
|
links launched. C only supports URI links at this time. |
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
URI links have two components,the text or graphics object and the area where the |
644
|
|
|
|
|
|
|
mouseclick should occur. |
645
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
For the object to be clicked on you'll use standard text of drawing methods. To |
647
|
|
|
|
|
|
|
define the click-sensitive area and the destination URI. |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
Example: |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
# Draw a string and undeline it to show it is a link |
652
|
|
|
|
|
|
|
$pdf->string($f1, 10, 450, 200, 'http://www.cpan.org'); |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
my $line = $pdf->string_underline($f1, 10, 450, 200, 'http://www.cpan.org'); |
655
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
# Create the hot area with the link to open on click |
657
|
|
|
|
|
|
|
$pdf->annotation( |
658
|
|
|
|
|
|
|
Subtype => 'Link', |
659
|
|
|
|
|
|
|
URI => 'http://www.cpan.org', |
660
|
|
|
|
|
|
|
x => 450, |
661
|
|
|
|
|
|
|
y => 200, |
662
|
|
|
|
|
|
|
w => $l, |
663
|
|
|
|
|
|
|
h => 15, |
664
|
|
|
|
|
|
|
Border => [0,0,0] |
665
|
|
|
|
|
|
|
); |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
The point (x, y) is the bottom left corner of the rectangle containing hotspot |
668
|
|
|
|
|
|
|
rectangle, (w, h) are the width and height of the hotspot rectangle. The Border |
669
|
|
|
|
|
|
|
describes the thickness of the border surrounding the rectangle hotspot. |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
The function C returns the width of the string, this can be used |
672
|
|
|
|
|
|
|
directly for the width of the hotspot rectangle. |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
=cut |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
sub annotation { |
677
|
2
|
|
|
2
|
1
|
18
|
my ($self, %params) = @_; |
678
|
|
|
|
|
|
|
|
679
|
2
|
|
|
|
|
15
|
debug( 2, "annotation(): Subtype=$params{'Subtype'}" ); |
680
|
|
|
|
|
|
|
|
681
|
2
|
50
|
|
|
|
12
|
if ( $params{'Subtype'} eq 'Link' ) { |
682
|
2
|
50
|
|
|
|
13
|
confess "Must specify 'URI' for Link" unless defined $params{'URI'}; |
683
|
2
|
50
|
|
|
|
9
|
confess "Must specify 'x' for Link" unless defined $params{'x'}; |
684
|
2
|
50
|
|
|
|
6
|
confess "Must specify 'y' for Link" unless defined $params{'y'}; |
685
|
2
|
50
|
|
|
|
7
|
confess "Must specify 'w' for Link" unless defined $params{'w'}; |
686
|
2
|
50
|
|
|
|
7
|
confess "Must specify 'h' for Link" unless defined $params{'h'}; |
687
|
|
|
|
|
|
|
|
688
|
2
|
|
|
|
|
6
|
my $num = 1 + scalar keys %{ $self->{'annotations'} }; |
|
2
|
|
|
|
|
9
|
|
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
my $action = { |
691
|
|
|
|
|
|
|
'Type' => $self->name('Action'), |
692
|
|
|
|
|
|
|
'S' => $self->name('URI'), |
693
|
2
|
|
|
|
|
8
|
'URI' => $self->string( $params{'URI'} ), |
694
|
|
|
|
|
|
|
}; |
695
|
2
|
|
|
|
|
8
|
my $x2 = $params{'x'} + $params{'w'}; |
696
|
2
|
|
|
|
|
6
|
my $y2 = $params{'y'} + $params{'h'}; |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
$self->{'annotations'}{$num} = { |
699
|
|
|
|
|
|
|
'Subtype' => $self->name('Link'), |
700
|
2
|
|
|
|
|
7
|
'Rect' => $self->verbatim( sprintf "[%f %f %f %f]", $params{'x'}, $params{'y'}, $x2, $y2 ), |
701
|
|
|
|
|
|
|
'A' => $self->dictionary(%$action), |
702
|
|
|
|
|
|
|
}; |
703
|
|
|
|
|
|
|
|
704
|
2
|
50
|
|
|
|
11
|
if ( defined $params{'Border'} ) { |
705
|
|
|
|
|
|
|
$self->{'annotations'}{$num}{'Border'} = |
706
|
2
|
|
|
|
|
32
|
$self->verbatim( sprintf "[%f %f %f]", $params{'Border'}[0], $params{'Border'}[1], $params{'Border'}[2] ); |
707
|
|
|
|
|
|
|
} |
708
|
2
|
|
|
|
|
93
|
$self->{'annot'}{$num}{'page_name'} = "Page " . $self->{'page_count'}; |
709
|
2
|
|
|
|
|
17
|
debug( 2, "annotation(): annotation number: $num, page name: $self->{'annot'}{$num}{'page_name'}" ); |
710
|
2
|
|
|
|
|
17
|
1; |
711
|
|
|
|
|
|
|
} else { |
712
|
0
|
|
|
|
|
0
|
confess "Only Annotations with Subtype 'Link' are supported for now\n"; |
713
|
|
|
|
|
|
|
} |
714
|
|
|
|
|
|
|
} |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
=head2 image($filename) |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
Prepare an XObject (image) using the given arguments. This image will be added to |
719
|
|
|
|
|
|
|
the document if it is referenced at least once before the close method is called. |
720
|
|
|
|
|
|
|
In this version GIF,interlaced GIF and JPEG is supported. Usage of interlaced GIFs |
721
|
|
|
|
|
|
|
are slower because they are decompressed, modified and compressed again. The gif |
722
|
|
|
|
|
|
|
support is limited to images with a LZW minimum code size of 8. Small images with |
723
|
|
|
|
|
|
|
few colors can have a smaller minimum code size and will not work. If you get |
724
|
|
|
|
|
|
|
errors regarding JPEG compression, then the compression method used in your |
725
|
|
|
|
|
|
|
JPEG file is not supported by C. Try resaving the JPEG file |
726
|
|
|
|
|
|
|
with different compression options (for example, disable progressive |
727
|
|
|
|
|
|
|
compression). |
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
Example: |
730
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
my $img = $pdf->image('image.jpg'); |
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
$page->image( |
734
|
|
|
|
|
|
|
image => $img, |
735
|
|
|
|
|
|
|
xscale => 0.25, # scale image for better quality |
736
|
|
|
|
|
|
|
yscale => 0.25, |
737
|
|
|
|
|
|
|
xpos => 50, |
738
|
|
|
|
|
|
|
ypos => 60, |
739
|
|
|
|
|
|
|
xalign => 0, |
740
|
|
|
|
|
|
|
yalign => 2, |
741
|
|
|
|
|
|
|
); |
742
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
=cut |
744
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
sub image { |
746
|
2
|
|
|
2
|
1
|
6
|
my ($self, $filename) = @_; |
747
|
|
|
|
|
|
|
|
748
|
2
|
|
|
|
|
3
|
my $num = 1 + scalar keys %{ $self->{'xobjects'} }; |
|
2
|
|
|
|
|
6
|
|
749
|
|
|
|
|
|
|
|
750
|
2
|
|
|
|
|
5
|
my $image; |
751
|
|
|
|
|
|
|
my $colorspace; |
752
|
2
|
|
|
|
|
0
|
my @a; |
753
|
|
|
|
|
|
|
|
754
|
2
|
100
|
33
|
|
|
11
|
if ( $filename =~ /\.gif$/i ) { |
|
|
50
|
|
|
|
|
|
755
|
1
|
|
|
|
|
11
|
$self->{'images'}{$num} = PDF::Image::GIF->new(); |
756
|
|
|
|
|
|
|
} elsif ( $filename =~ /\.jpg$/i || $filename =~ /\.jpeg$/i ) { |
757
|
1
|
|
|
|
|
7
|
$self->{'images'}{$num} = PDF::Image::JPEG->new(); |
758
|
|
|
|
|
|
|
} |
759
|
|
|
|
|
|
|
|
760
|
2
|
|
|
|
|
3
|
$image = $self->{'images'}{$num}; |
761
|
2
|
50
|
|
|
|
6
|
if ( !$image->Open($filename) ) { |
762
|
0
|
|
|
|
|
0
|
print $image->{error} . "\n"; |
763
|
0
|
|
|
|
|
0
|
return 0; |
764
|
|
|
|
|
|
|
} |
765
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
$self->{'xobjects'}{$num} = { |
767
|
|
|
|
|
|
|
'Subtype' => $self->name('Image'), |
768
|
|
|
|
|
|
|
'Name' => $self->name("Image$num"), |
769
|
|
|
|
|
|
|
'Type' => $self->name('XObject'), |
770
|
|
|
|
|
|
|
'Width' => $self->number( $image->{width} ), |
771
|
|
|
|
|
|
|
'Height' => $self->number( $image->{height} ), |
772
|
|
|
|
|
|
|
'BitsPerComponent' => $self->number( $image->{bpc} ), |
773
|
|
|
|
|
|
|
'Data' => $image->ReadData(), |
774
|
2
|
|
|
|
|
6
|
'Length' => $self->number( $image->{imagesize} ), |
775
|
|
|
|
|
|
|
}; |
776
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
# Indexed colorspace? |
778
|
2
|
100
|
|
|
|
7
|
if ($image->{colorspacesize}) { |
779
|
1
|
|
|
|
|
7
|
$colorspace = $self->reserve("ImageColorSpace$num"); |
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
$self->{'xobjects_colorspace'}{$num} = { |
782
|
|
|
|
|
|
|
'Data' => $image->{colorspacedata}, |
783
|
1
|
|
|
|
|
3
|
'Length' => $self->number( $image->{colorspacesize} ), |
784
|
|
|
|
|
|
|
}; |
785
|
|
|
|
|
|
|
|
786
|
1
|
|
|
|
|
5
|
$self->{'xobjects'}{$num}->{'ColorSpace'} = $self->array( $self->name('Indexed'), $self->name( $image->{colorspace} ), |
787
|
|
|
|
|
|
|
$self->number(255), $self->indirect_ref(@$colorspace) ); |
788
|
|
|
|
|
|
|
} else { |
789
|
1
|
|
|
|
|
3
|
$self->{'xobjects'}{$num}->{'ColorSpace'} = $self->array( $self->name( $image->{colorspace} ) ); |
790
|
|
|
|
|
|
|
} |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
# Set Filter |
793
|
2
|
|
|
|
|
8
|
$#a = -1; |
794
|
2
|
|
|
|
|
3
|
foreach my $s ( @{ $image->{filter} } ) { |
|
2
|
|
|
|
|
7
|
|
795
|
2
|
|
|
|
|
3
|
push @a, $self->name($s); |
796
|
|
|
|
|
|
|
} |
797
|
2
|
50
|
|
|
|
5
|
if ( $#a >= 0 ) { |
798
|
2
|
|
|
|
|
5
|
$self->{'xobjects'}{$num}->{'Filter'} = $self->array(@a); |
799
|
|
|
|
|
|
|
} |
800
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
# Set additional DecodeParms |
802
|
2
|
|
|
|
|
4
|
$#a = -1; |
803
|
2
|
|
|
|
|
4
|
foreach my $s ( keys %{ $image->{decodeparms} } ) { |
|
2
|
|
|
|
|
8
|
|
804
|
1
|
|
|
|
|
2
|
push @a, $s; |
805
|
1
|
|
|
|
|
3
|
push @a, $self->number( $image->{decodeparms}{$s} ); |
806
|
|
|
|
|
|
|
} |
807
|
2
|
|
|
|
|
6
|
$self->{'xobjects'}{$num}->{'DecodeParms'} = $self->array( $self->dictionary(@a) ); |
808
|
|
|
|
|
|
|
|
809
|
|
|
|
|
|
|
# Transparent? |
810
|
2
|
100
|
|
|
|
4
|
if ( $image->{transparent} ) { |
811
|
1
|
|
|
|
|
3
|
$self->{'xobjects'}{$num}->{'Mask'} = $self->array( $self->number( $image->{mask} ), $self->number( $image->{mask} ) ); |
812
|
|
|
|
|
|
|
} |
813
|
|
|
|
|
|
|
|
814
|
2
|
|
|
|
|
15
|
return { 'num' => $num, 'width' => $image->{width}, 'height' => $image->{height} }; |
815
|
|
|
|
|
|
|
} |
816
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
sub add_outlines { |
818
|
5
|
|
|
5
|
0
|
1019
|
my ($self, %params) = @_; |
819
|
|
|
|
|
|
|
|
820
|
5
|
|
|
|
|
991
|
debug( 2, "add_outlines" ); |
821
|
5
|
|
|
|
|
995
|
my $outlines = $self->reserve("Outlines"); |
822
|
|
|
|
|
|
|
|
823
|
5
|
|
|
|
|
976
|
my ($First, $Last); |
824
|
5
|
|
|
|
|
974
|
my @list = $self->{'outlines'}->list; |
825
|
5
|
|
|
|
|
1362
|
my $i = -1; |
826
|
5
|
|
|
|
|
1427
|
for my $outline (@list) { |
827
|
30
|
|
|
|
|
7942
|
$i++; |
828
|
30
|
|
|
|
|
7966
|
my $name = $outline->{'name'}; |
829
|
30
|
100
|
|
|
|
8794
|
$First = $outline->{'id'} unless defined $First; |
830
|
30
|
|
|
|
|
8565
|
$Last = $outline->{'id'}; |
831
|
30
|
|
|
|
|
8963
|
my $content = { 'Title' => $self->string( $outline->{'Title'} ) }; |
832
|
30
|
100
|
50
|
|
|
8603
|
if ( defined $outline->{'Kids'} && scalar @{ $outline->{'Kids'} } ) { |
|
30
|
|
|
|
|
16688
|
|
833
|
9
|
|
|
|
|
2160
|
my $t = $outline->{'Kids'}; |
834
|
9
|
|
|
|
|
2066
|
$$content{'First'} = $self->indirect_ref( @{ $$t[0]->{'id'} } ); |
|
9
|
|
|
|
|
4042
|
|
835
|
9
|
|
|
|
|
2020
|
$$content{'Last'} = $self->indirect_ref( @{ $$t[$#$t]->{'id'} } ); |
|
9
|
|
|
|
|
4112
|
|
836
|
|
|
|
|
|
|
} |
837
|
30
|
|
|
|
|
7968
|
my $brothers = $outline->{'Parent'}->{'Kids'}; |
838
|
30
|
|
|
|
|
8873
|
my $j = -1; |
839
|
30
|
|
|
|
|
8959
|
for my $brother (@$brothers) { |
840
|
53
|
|
|
|
|
13566
|
$j++; |
841
|
53
|
100
|
|
|
|
21412
|
last if $brother == $outline; |
842
|
|
|
|
|
|
|
} |
843
|
30
|
100
|
|
|
|
8439
|
$$content{'Next'} = $self->indirect_ref( @{ $$brothers[ $j + 1 ]->{'id'} } ) |
|
16
|
|
|
|
|
9464
|
|
844
|
|
|
|
|
|
|
if $j < $#$brothers; |
845
|
30
|
100
|
|
|
|
7063
|
$$content{'Prev'} = $self->indirect_ref( @{ $$brothers[ $j - 1 ]->{'id'} } ) |
|
16
|
|
|
|
|
6557
|
|
846
|
|
|
|
|
|
|
if $j; |
847
|
|
|
|
|
|
|
$outline->{'Parent'}->{'id'} = $outlines |
848
|
30
|
100
|
|
|
|
6900
|
unless defined $outline->{'Parent'}->{'id'}; |
849
|
30
|
|
|
|
|
6711
|
$$content{'Parent'} = $self->indirect_ref( @{ $outline->{'Parent'}->{'id'} } ); |
|
30
|
|
|
|
|
13292
|
|
850
|
|
|
|
|
|
|
$$content{'Dest'} = |
851
|
30
|
|
|
|
|
6169
|
$self->array( $self->indirect_ref( @{ $outline->{'Dest'}->{'id'} } ), |
|
30
|
|
|
|
|
12670
|
|
852
|
|
|
|
|
|
|
$self->name('Fit'), $self->null, $self->null, $self->null ); |
853
|
30
|
|
|
|
|
7019
|
my $count = $outline->count; |
854
|
30
|
100
|
|
|
|
6785
|
$$content{'Count'} = $self->number($count) if $count; |
855
|
30
|
|
|
|
|
6965
|
my $t = $self->add_object( $self->indirect_obj( $self->dictionary(%$content), $name ) ); |
856
|
30
|
|
|
|
|
7103
|
$self->cr; |
857
|
|
|
|
|
|
|
} |
858
|
|
|
|
|
|
|
|
859
|
|
|
|
|
|
|
# Type (required) |
860
|
5
|
|
|
|
|
1039
|
my $content = { 'Type' => $self->name('Outlines') }; |
861
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
# Count |
863
|
5
|
|
|
|
|
1484
|
my $count = $self->{'outlines'}->count; |
864
|
5
|
50
|
|
|
|
1034
|
$$content{'Count'} = $self->number($count) if $count; |
865
|
5
|
|
|
|
|
1019
|
$$content{'First'} = $self->indirect_ref(@$First); |
866
|
5
|
|
|
|
|
1014
|
$$content{'Last'} = $self->indirect_ref(@$Last); |
867
|
5
|
|
|
|
|
1029
|
$self->add_object( $self->indirect_obj( $self->dictionary(%$content) ) ); |
868
|
5
|
|
|
|
|
1402
|
$self->cr; |
869
|
|
|
|
|
|
|
} |
870
|
|
|
|
|
|
|
|
871
|
|
|
|
|
|
|
sub add_pages { |
872
|
15
|
|
|
15
|
0
|
1058
|
my ($self) = @_; |
873
|
|
|
|
|
|
|
|
874
|
15
|
|
|
|
|
1063
|
debug( 2, "add_pages():" ); |
875
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
# Type (required) |
877
|
15
|
|
|
|
|
1062
|
my $content = { 'Type' => $self->name('Pages') }; |
878
|
|
|
|
|
|
|
|
879
|
|
|
|
|
|
|
# Kids (required) |
880
|
15
|
|
|
|
|
1464
|
my $t = $self->{'pages'}->kids; |
881
|
15
|
50
|
|
|
|
1408
|
confess "Error: document MUST contains at least one page. Abort." |
882
|
|
|
|
|
|
|
unless scalar @$t; |
883
|
|
|
|
|
|
|
|
884
|
15
|
|
|
|
|
1378
|
my $kids = []; |
885
|
15
|
|
|
|
|
1429
|
map { push @$kids, $self->indirect_ref(@$_) } @$t; |
|
15
|
|
|
|
|
1404
|
|
886
|
15
|
|
|
|
|
1425
|
$$content{'Kids'} = $self->array(@$kids); |
887
|
15
|
|
|
|
|
1823
|
$$content{'Count'} = $self->number( $self->{'pages'}->count ); |
888
|
15
|
|
|
|
|
1103
|
$self->add_object( $self->indirect_obj( $self->dictionary(%$content) ) ); |
889
|
15
|
|
|
|
|
1104
|
$self->cr; |
890
|
|
|
|
|
|
|
|
891
|
15
|
|
|
|
|
1098
|
for my $font ( sort keys %{ $self->{'fonts'} } ) { |
|
15
|
|
|
|
|
2132
|
|
892
|
34
|
|
|
|
|
2210
|
debug( 2, "add_pages(): font: $font" ); |
893
|
34
|
|
|
|
|
2259
|
$self->{'fontobj'}{$font} = $self->reserve('Font'); |
894
|
34
|
|
|
|
|
2487
|
$self->add_object( $self->indirect_obj( $self->dictionary( %{ $self->{'fonts'}{$font} } ), 'Font' ) ); |
|
34
|
|
|
|
|
5232
|
|
895
|
34
|
|
|
|
|
2292
|
$self->cr; |
896
|
|
|
|
|
|
|
} |
897
|
|
|
|
|
|
|
|
898
|
15
|
|
|
|
|
1068
|
for my $xobject (sort keys %{$self->{'xobjects'}}) { |
|
15
|
|
|
|
|
2160
|
|
899
|
2
|
|
|
|
|
7
|
debug( 2, "add_pages(): xobject: $xobject" ); |
900
|
2
|
|
|
|
|
4
|
$self->{'xobj'}{$xobject} = $self->reserve('XObject'); |
901
|
2
|
|
|
|
|
3
|
$self->add_object( $self->indirect_obj( $self->stream( %{ $self->{'xobjects'}{$xobject} } ), 'XObject' ) ); |
|
2
|
|
|
|
|
10
|
|
902
|
2
|
|
|
|
|
10
|
$self->cr; |
903
|
|
|
|
|
|
|
|
904
|
2
|
100
|
|
|
|
8
|
if ( defined $self->{'reservations'}{"ImageColorSpace$xobject"}) { |
905
|
|
|
|
|
|
|
$self->add_object( |
906
|
1
|
|
|
|
|
3
|
$self->indirect_obj( $self->stream( %{ $self->{'xobjects_colorspace'}{$xobject} } ), "ImageColorSpace$xobject" ) ); |
|
1
|
|
|
|
|
16
|
|
907
|
1
|
|
|
|
|
4
|
$self->cr; |
908
|
|
|
|
|
|
|
} |
909
|
|
|
|
|
|
|
} |
910
|
|
|
|
|
|
|
|
911
|
15
|
|
|
|
|
1085
|
for my $annotation (sort keys %{$self->{'annotations'}}) { |
|
15
|
|
|
|
|
2112
|
|
912
|
2
|
|
|
|
|
7
|
$self->{'annot'}{$annotation}{'object_info'} = $self->reserve('Annotation'); |
913
|
2
|
|
|
|
|
6
|
$self->add_object( $self->indirect_obj( $self->dictionary( %{ $self->{'annotations'}{$annotation} } ), 'Annotation' ) ); |
|
2
|
|
|
|
|
13
|
|
914
|
2
|
|
|
|
|
13
|
$self->cr; |
915
|
|
|
|
|
|
|
} |
916
|
|
|
|
|
|
|
|
917
|
15
|
|
|
|
|
1273
|
for my $page ($self->{'pages'}->list) { |
918
|
38
|
|
|
|
|
3281
|
my $name = $page->{'name'}; |
919
|
38
|
|
|
|
|
3565
|
debug( 2, "add_pages: page: $name" ); |
920
|
38
|
100
|
50
|
|
|
3332
|
my $type = 'Page' . ( defined $page->{'Kids'} && scalar @{ $page->{'Kids'} } ? 's' : '' ); |
921
|
|
|
|
|
|
|
|
922
|
|
|
|
|
|
|
# Type (required) |
923
|
38
|
|
|
|
|
3312
|
my $content = { 'Type' => $self->name($type) }; |
924
|
|
|
|
|
|
|
|
925
|
|
|
|
|
|
|
# Resources (required, may be inherited). See page 195. |
926
|
38
|
|
|
|
|
3282
|
my $resources = {}; |
927
|
38
|
|
|
|
|
3243
|
for my $k ( keys %{ $page->{'resources'} } ) { |
|
38
|
|
|
|
|
6608
|
|
928
|
39
|
|
|
|
|
2213
|
my $v = $page->{'resources'}{$k}; |
929
|
|
|
|
|
|
|
( $k eq 'ProcSet' ) && do { |
930
|
19
|
|
|
|
|
1115
|
my $l = []; |
931
|
19
|
50
|
|
|
|
1128
|
if ( ref($v) eq 'ARRAY' ) { |
932
|
19
|
|
|
|
|
1142
|
map { push @$l, $self->name($_) } @$v; |
|
38
|
|
|
|
|
2177
|
|
933
|
|
|
|
|
|
|
} else { |
934
|
0
|
|
|
|
|
0
|
push @$l, $self->name($v); |
935
|
|
|
|
|
|
|
} |
936
|
19
|
|
|
|
|
1112
|
$$resources{'ProcSet'} = $self->array(@$l); |
937
|
|
|
|
|
|
|
} |
938
|
|
|
|
|
|
|
|| ( $k eq 'fonts' ) && do { |
939
|
19
|
|
|
|
|
1095
|
my $l = {}; |
940
|
19
|
|
|
|
|
1064
|
map { $$l{"F$_"} = $self->indirect_ref( @{ $self->{'fontobj'}{$_} } ); } keys %{ $page->{'resources'}{'fonts'} }; |
|
37
|
|
|
|
|
2142
|
|
|
37
|
|
|
|
|
4290
|
|
|
19
|
|
|
|
|
2133
|
|
941
|
19
|
|
|
|
|
1115
|
$$resources{'Font'} = $self->dictionary(%$l); |
942
|
|
|
|
|
|
|
} |
943
|
39
|
100
|
33
|
|
|
2307
|
|| ( $k eq 'xobjects' ) && do { |
|
|
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
944
|
1
|
|
|
|
|
2
|
my $l = {}; |
945
|
2
|
|
|
|
|
3
|
map { $$l{"Image$_"} = $self->indirect_ref( @{ $self->{'xobj'}{$_} } ); } |
|
2
|
|
|
|
|
3
|
|
946
|
1
|
|
|
|
|
2
|
keys %{ $page->{'resources'}{'xobjects'} }; |
|
1
|
|
|
|
|
3
|
|
947
|
1
|
|
|
|
|
4
|
$$resources{'XObject'} = $self->dictionary(%$l); |
948
|
|
|
|
|
|
|
}; |
949
|
|
|
|
|
|
|
} |
950
|
38
|
50
|
|
|
|
3280
|
if ( defined( $$resources{'Annotation'} ) ) { |
951
|
0
|
|
|
|
|
0
|
my $r = $self->add_object( $self->indirect_obj( $self->dictionary(%$resources) ) ); |
952
|
0
|
|
|
|
|
0
|
$self->cr; |
953
|
0
|
|
|
|
|
0
|
$$content{'Resources'} = [ 'ref', [ $$r[0], $$r[1] ] ]; |
954
|
|
|
|
|
|
|
} |
955
|
38
|
100
|
|
|
|
3271
|
if ( defined( $$resources{'XObject'} ) ) { |
956
|
1
|
|
|
|
|
3
|
my $r = $self->add_object( $self->indirect_obj( $self->dictionary(%$resources) ) ); |
957
|
1
|
|
|
|
|
5
|
$self->cr; |
958
|
1
|
|
|
|
|
3
|
$$content{'Resources'} = [ 'ref', [ $$r[0], $$r[1] ] ]; |
959
|
|
|
|
|
|
|
} else { |
960
|
37
|
100
|
|
|
|
5524
|
$$content{'Resources'} = $self->dictionary(%$resources) |
961
|
|
|
|
|
|
|
if scalar keys %$resources; |
962
|
|
|
|
|
|
|
} |
963
|
38
|
|
|
|
|
3240
|
for my $K ( 'MediaBox', 'CropBox', 'ArtBox', 'TrimBox', 'BleedBox' ) { |
964
|
190
|
|
|
|
|
16230
|
my $k = lc $K; |
965
|
190
|
100
|
|
|
|
19525
|
if ( defined $page->{$k} ) { |
966
|
15
|
|
|
|
|
1047
|
my $l = []; |
967
|
15
|
|
|
|
|
1050
|
map { push @$l, $self->number($_) } @{ $page->{$k} }; |
|
60
|
|
|
|
|
5082
|
|
|
15
|
|
|
|
|
2551
|
|
968
|
15
|
|
|
|
|
1089
|
$$content{$K} = $self->array(@$l); |
969
|
|
|
|
|
|
|
} |
970
|
|
|
|
|
|
|
} |
971
|
38
|
50
|
|
|
|
3358
|
$$content{'Rotate'} = $self->number( $page->{'rotate'} ) if defined $page->{'rotate'}; |
972
|
38
|
100
|
|
|
|
3310
|
if ( $type eq 'Page' ) { |
973
|
24
|
|
|
|
|
2179
|
$$content{'Parent'} = $self->indirect_ref( @{ $page->{'Parent'}{'id'} } ); |
|
24
|
|
|
|
|
4368
|
|
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
# Content |
976
|
24
|
100
|
|
|
|
2208
|
if ( defined $page->{'contents'} ) { |
977
|
23
|
|
|
|
|
2503
|
my $contents = []; |
978
|
23
|
|
|
|
|
2167
|
map { push @$contents, $self->indirect_ref(@$_); } @{ $page->{'contents'} }; |
|
27
|
|
|
|
|
3284
|
|
|
23
|
|
|
|
|
4298
|
|
979
|
23
|
|
|
|
|
2214
|
$$content{'Contents'} = $self->array(@$contents); |
980
|
|
|
|
|
|
|
} |
981
|
|
|
|
|
|
|
|
982
|
|
|
|
|
|
|
# Annotations added here by Gary Lieberman |
983
|
|
|
|
|
|
|
# |
984
|
|
|
|
|
|
|
# Tell the /Page object that annotations need to be drawn. |
985
|
24
|
100
|
|
|
|
4374
|
if ( defined $self->{'annot'} ) { |
986
|
1
|
|
|
|
|
3
|
my $Annots = '[ '; |
987
|
1
|
|
|
|
|
3
|
my $is_annots = 0; |
988
|
1
|
|
|
|
|
3
|
foreach my $annot_number ( keys %{ $self->{'annot'} } ) { |
|
1
|
|
|
|
|
5
|
|
989
|
2
|
50
|
|
|
|
13
|
next if ( $self->{'annot'}{$annot_number}{'page_name'} ne $name ); |
990
|
2
|
|
|
|
|
3
|
$is_annots = 1; |
991
|
2
|
|
|
|
|
17
|
debug( 2, |
992
|
|
|
|
|
|
|
sprintf "annotation number: $annot_number, page name: $self->{'annot'}{$annot_number}{'page_name'}" ); |
993
|
2
|
|
|
|
|
6
|
my $object_number = $self->{'annot'}{$annot_number}{'object_info'}[0]; |
994
|
2
|
|
|
|
|
5
|
my $generation_number = $self->{'annot'}{$annot_number}{'object_info'}[1]; |
995
|
2
|
|
|
|
|
13
|
debug( 2, sprintf "object_number: $object_number, generation_number: $generation_number" ); |
996
|
2
|
|
|
|
|
14
|
$Annots .= sprintf( "%s %s R ", $object_number, $generation_number ); |
997
|
|
|
|
|
|
|
} |
998
|
1
|
50
|
|
|
|
15
|
$$content{'Annots'} = $self->verbatim( $Annots . ']' ) if ($is_annots); |
999
|
|
|
|
|
|
|
} |
1000
|
|
|
|
|
|
|
} else { |
1001
|
14
|
|
|
|
|
1067
|
my $kids = []; |
1002
|
14
|
|
|
|
|
1049
|
map { push @$kids, $self->indirect_ref(@$_) } @{ $page->kids }; |
|
23
|
|
|
|
|
2159
|
|
|
14
|
|
|
|
|
1138
|
|
1003
|
14
|
|
|
|
|
1147
|
$$content{'Kids'} = $self->array(@$kids); |
1004
|
14
|
|
|
|
|
2105
|
$$content{'Parent'} = $self->indirect_ref( @{ $page->{'Parent'}{'id'} } ) |
1005
|
14
|
50
|
|
|
|
1083
|
if defined $page->{'Parent'}; |
1006
|
14
|
|
|
|
|
1077
|
$$content{'Count'} = $self->number( $page->count ); |
1007
|
|
|
|
|
|
|
} |
1008
|
38
|
|
|
|
|
3760
|
$self->add_object( $self->indirect_obj( $self->dictionary(%$content), $name ) ); |
1009
|
38
|
|
|
|
|
3833
|
$self->cr; |
1010
|
|
|
|
|
|
|
} |
1011
|
|
|
|
|
|
|
} |
1012
|
|
|
|
|
|
|
|
1013
|
|
|
|
|
|
|
sub add_crossrefsection { |
1014
|
15
|
|
|
15
|
0
|
1540
|
my ($self) = @_; |
1015
|
|
|
|
|
|
|
|
1016
|
15
|
|
|
|
|
1592
|
debug( 2, "add_crossrefsection():" ); |
1017
|
|
|
|
|
|
|
|
1018
|
|
|
|
|
|
|
# ::= |
1019
|
|
|
|
|
|
|
# xref |
1020
|
|
|
|
|
|
|
# + |
1021
|
15
|
|
|
|
|
1121
|
$self->{'crossrefstartpoint'} = $self->position; |
1022
|
15
|
|
|
|
|
1148
|
$self->add('xref'); |
1023
|
15
|
|
|
|
|
1136
|
$self->cr; |
1024
|
|
|
|
|
|
|
confess "Fatal error: should contains at least one cross reference subsection." |
1025
|
15
|
50
|
|
|
|
1202
|
unless defined $self->{'crossrefsubsection'}; |
1026
|
15
|
|
|
|
|
1178
|
for my $subsection ( sort keys %{ $self->{'crossrefsubsection'} } ) { |
|
15
|
|
|
|
|
2412
|
|
1027
|
15
|
|
|
|
|
1255
|
$self->add_crossrefsubsection($subsection); |
1028
|
|
|
|
|
|
|
} |
1029
|
|
|
|
|
|
|
} |
1030
|
|
|
|
|
|
|
|
1031
|
|
|
|
|
|
|
sub add_crossrefsubsection { |
1032
|
15
|
|
|
15
|
0
|
1176
|
my ($self, $subsection) = @_; |
1033
|
|
|
|
|
|
|
|
1034
|
15
|
|
|
|
|
1188
|
debug( 2, "add_crossrefsubsection():" ); |
1035
|
|
|
|
|
|
|
|
1036
|
|
|
|
|
|
|
# ::= |
1037
|
|
|
|
|
|
|
# |
1038
|
|
|
|
|
|
|
# |
1039
|
|
|
|
|
|
|
# + |
1040
|
|
|
|
|
|
|
# |
1041
|
|
|
|
|
|
|
# ::= | |
1042
|
|
|
|
|
|
|
# |
1043
|
|
|
|
|
|
|
# ::= n |
1044
|
|
|
|
|
|
|
# |
1045
|
|
|
|
|
|
|
# ::= |
1046
|
|
|
|
|
|
|
# | |
1047
|
|
|
|
|
|
|
# | |
1048
|
|
|
|
|
|
|
# |
1049
|
|
|
|
|
|
|
# ::= |
1050
|
|
|
|
|
|
|
# |
1051
|
|
|
|
|
|
|
# f |
1052
|
|
|
|
|
|
|
|
1053
|
15
|
|
|
|
|
1187
|
$self->add( 0, ' ', 1 + scalar @{ $self->{'crossrefsubsection'}{$subsection} } ); |
|
15
|
|
|
|
|
2344
|
|
1054
|
15
|
|
|
|
|
1233
|
$self->cr; |
1055
|
15
|
|
|
|
|
1191
|
$self->add( sprintf "%010d %05d %s ", 0, 65535, 'f' ); |
1056
|
15
|
|
|
|
|
1225
|
$self->cr; |
1057
|
15
|
|
|
|
|
1148
|
for my $entry ( sort { $$a[0] <=> $$b[0] } @{ $self->{'crossrefsubsection'}{$subsection} } ) { |
|
551
|
|
|
|
|
146097
|
|
|
15
|
|
|
|
|
2369
|
|
1058
|
212
|
50
|
|
|
|
26306
|
$self->add( sprintf "%010d %05d %s ", $$entry[1], $subsection, $$entry[2] ? 'n' : 'f' ); |
1059
|
|
|
|
|
|
|
|
1060
|
|
|
|
|
|
|
# printf "%010d %010x %05d n\n", $$entry[1], $$entry[1], $subsection; |
1061
|
212
|
|
|
|
|
26424
|
$self->cr; |
1062
|
|
|
|
|
|
|
} |
1063
|
|
|
|
|
|
|
} |
1064
|
|
|
|
|
|
|
|
1065
|
|
|
|
|
|
|
sub add_trailer { |
1066
|
15
|
|
|
15
|
0
|
1097
|
my $self = shift; |
1067
|
|
|
|
|
|
|
|
1068
|
15
|
|
|
|
|
1142
|
debug( 2, "add_trailer():" ); |
1069
|
|
|
|
|
|
|
|
1070
|
|
|
|
|
|
|
# ::= trailer |
1071
|
|
|
|
|
|
|
# << |
1072
|
|
|
|
|
|
|
# + |
1073
|
|
|
|
|
|
|
# >> |
1074
|
|
|
|
|
|
|
# startxref |
1075
|
|
|
|
|
|
|
# |
1076
|
|
|
|
|
|
|
# %%EOF |
1077
|
|
|
|
|
|
|
|
1078
|
15
|
|
|
|
|
1165
|
my @keys = ( |
1079
|
|
|
|
|
|
|
'Size', # integer (required) |
1080
|
|
|
|
|
|
|
'Prev', # integer (req only if more than one cross-ref section) |
1081
|
|
|
|
|
|
|
'Root', # dictionary (required) |
1082
|
|
|
|
|
|
|
'Info', # dictionary (optional) |
1083
|
|
|
|
|
|
|
'ID', # array (optional) (PDF 1.1) |
1084
|
|
|
|
|
|
|
'Encrypt' # dictionary (req if encrypted) (PDF 1.1) |
1085
|
|
|
|
|
|
|
); |
1086
|
|
|
|
|
|
|
|
1087
|
|
|
|
|
|
|
# TODO: should check for required fields |
1088
|
15
|
|
|
|
|
1125
|
$self->add('trailer'); |
1089
|
15
|
|
|
|
|
1195
|
$self->cr; |
1090
|
15
|
|
|
|
|
1182
|
$self->add('<<'); |
1091
|
15
|
|
|
|
|
1178
|
$self->cr; |
1092
|
15
|
|
|
|
|
1660
|
$self->{'trailer'}{'Size'} = 1; |
1093
|
15
|
|
|
|
|
1597
|
map { $self->{'trailer'}{'Size'} += scalar @{ $self->{'crossrefsubsection'}{$_} } } keys %{ $self->{'crossrefsubsection'} }; |
|
15
|
|
|
|
|
1878
|
|
|
15
|
|
|
|
|
5066
|
|
|
15
|
|
|
|
|
3200
|
|
1094
|
15
|
|
|
|
|
1630
|
$self->{'trailer'}{'Root'} = &encode( @{ $self->indirect_ref( @{ $self->{'catalog'} } ) } ); |
|
15
|
|
|
|
|
2250
|
|
|
15
|
|
|
|
|
2987
|
|
1095
|
15
|
|
|
|
|
1161
|
$self->{'trailer'}{'Info'} = &encode( @{ $self->indirect_ref( @{ $self->{'info'} } ) } ) |
|
15
|
|
|
|
|
3001
|
|
1096
|
15
|
50
|
|
|
|
1376
|
if defined $self->{'info'}; |
1097
|
|
|
|
|
|
|
|
1098
|
15
|
|
|
|
|
1179
|
for my $k (@keys) { |
1099
|
90
|
100
|
|
|
|
10740
|
next unless defined $self->{'trailer'}{$k}; |
1100
|
|
|
|
|
|
|
$self->add( "/$k ", |
1101
|
45
|
50
|
|
|
|
3628
|
ref $self->{'trailer'}{$k} eq 'ARRAY' ? join( ' ', @{ $self->{'trailer'}{$k} } ) : $self->{'trailer'}{$k} ); |
|
0
|
|
|
|
|
0
|
|
1102
|
45
|
|
|
|
|
3899
|
$self->cr; |
1103
|
|
|
|
|
|
|
} |
1104
|
15
|
|
|
|
|
1198
|
$self->add('>>'); |
1105
|
15
|
|
|
|
|
1521
|
$self->cr; |
1106
|
15
|
|
|
|
|
1405
|
$self->add('startxref'); |
1107
|
15
|
|
|
|
|
1185
|
$self->cr; |
1108
|
15
|
|
|
|
|
1222
|
$self->add( $self->{'crossrefstartpoint'} ); |
1109
|
15
|
|
|
|
|
1871
|
$self->cr; |
1110
|
15
|
|
|
|
|
1521
|
$self->add('%%EOF'); |
1111
|
15
|
|
|
|
|
1575
|
$self->cr; |
1112
|
|
|
|
|
|
|
} |
1113
|
|
|
|
|
|
|
|
1114
|
|
|
|
|
|
|
sub cr { |
1115
|
1564
|
|
|
1564
|
0
|
119463
|
my ($self) = @_; |
1116
|
|
|
|
|
|
|
|
1117
|
1564
|
|
|
|
|
120840
|
debug( 3, "cr():" ); |
1118
|
1564
|
|
|
|
|
118081
|
$self->add( &encode('cr') ); |
1119
|
|
|
|
|
|
|
} |
1120
|
|
|
|
|
|
|
|
1121
|
|
|
|
|
|
|
sub page_stream { |
1122
|
562
|
|
|
562
|
0
|
8268
|
my ($self, $page) = @_; |
1123
|
|
|
|
|
|
|
|
1124
|
562
|
|
|
|
|
7971
|
debug( 2, "page_stream():" ); |
1125
|
|
|
|
|
|
|
|
1126
|
562
|
100
|
|
|
|
7842
|
if (defined $self->{'reservations'}{'stream_length'}) { |
1127
|
|
|
|
|
|
|
## If it is the same page, use the same stream. |
1128
|
|
|
|
|
|
|
$self->cr, return |
1129
|
|
|
|
|
|
|
if defined $page |
1130
|
|
|
|
|
|
|
&& defined $self->{'stream_page'} |
1131
|
|
|
|
|
|
|
&& $page == $self->{'current_page'} |
1132
|
547
|
100
|
66
|
|
|
9078
|
&& $self->{'stream_page'} == $page; |
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
1133
|
|
|
|
|
|
|
|
1134
|
|
|
|
|
|
|
# Remember the position |
1135
|
27
|
|
|
|
|
3634
|
my $len = $self->position - $self->{'stream_pos'} + 1; |
1136
|
|
|
|
|
|
|
|
1137
|
|
|
|
|
|
|
# Close the stream and the object |
1138
|
27
|
|
|
|
|
3331
|
$self->cr; |
1139
|
27
|
|
|
|
|
3869
|
$self->add('endstream'); |
1140
|
27
|
|
|
|
|
4162
|
$self->cr; |
1141
|
27
|
|
|
|
|
3090
|
$self->add('endobj'); |
1142
|
27
|
|
|
|
|
3042
|
$self->cr; |
1143
|
27
|
|
|
|
|
3239
|
$self->cr; |
1144
|
|
|
|
|
|
|
|
1145
|
|
|
|
|
|
|
# Add the length |
1146
|
27
|
|
|
|
|
3323
|
$self->add_object( $self->indirect_obj( $self->number($len), 'stream_length' ) ); |
1147
|
27
|
|
|
|
|
3118
|
$self->cr; |
1148
|
|
|
|
|
|
|
} |
1149
|
|
|
|
|
|
|
|
1150
|
|
|
|
|
|
|
# open a new stream if needed |
1151
|
42
|
100
|
|
|
|
5058
|
if (defined $page) { |
1152
|
|
|
|
|
|
|
|
1153
|
|
|
|
|
|
|
# get an object id for the stream |
1154
|
27
|
|
|
|
|
3022
|
my $obj = $self->reserve('stream'); |
1155
|
|
|
|
|
|
|
|
1156
|
|
|
|
|
|
|
# release it |
1157
|
27
|
|
|
|
|
3059
|
delete $self->{'reservations'}{'stream'}; |
1158
|
|
|
|
|
|
|
|
1159
|
|
|
|
|
|
|
# get another one for the length of this stream |
1160
|
27
|
|
|
|
|
3075
|
my $stream_length = $self->reserve('stream_length'); |
1161
|
27
|
|
|
|
|
3057
|
push @$stream_length, 'R'; |
1162
|
27
|
|
|
|
|
3048
|
push @{ $page->{'contents'} }, $obj; |
|
27
|
|
|
|
|
6865
|
|
1163
|
|
|
|
|
|
|
|
1164
|
|
|
|
|
|
|
# write the beginning of the object |
1165
|
27
|
|
|
|
|
3223
|
push @{ $self->{'crossrefsubsection'}{ $$obj[1] } }, [ $$obj[0], $self->position, 1 ]; |
|
27
|
|
|
|
|
6367
|
|
1166
|
27
|
|
|
|
|
3455
|
$self->add("$$obj[0] $$obj[1] obj"); |
1167
|
27
|
|
|
|
|
3285
|
$self->cr; |
1168
|
27
|
|
|
|
|
3254
|
$self->add('<<'); |
1169
|
27
|
|
|
|
|
3034
|
$self->cr; |
1170
|
27
|
|
|
|
|
3294
|
$self->add( '/Length ', join( ' ', @$stream_length ) ); |
1171
|
27
|
|
|
|
|
3485
|
$self->cr; |
1172
|
27
|
|
|
|
|
3074
|
$self->add('>>'); |
1173
|
27
|
|
|
|
|
2971
|
$self->cr; |
1174
|
27
|
|
|
|
|
3027
|
$self->add('stream'); |
1175
|
27
|
|
|
|
|
3326
|
$self->cr; |
1176
|
27
|
|
|
|
|
3369
|
$self->{'stream_pos'} = $self->position; |
1177
|
27
|
|
|
|
|
11108
|
$self->{'stream_page'} = $page; |
1178
|
|
|
|
|
|
|
} |
1179
|
|
|
|
|
|
|
} |
1180
|
|
|
|
|
|
|
|
1181
|
|
|
|
|
|
|
=head2 get_data() |
1182
|
|
|
|
|
|
|
|
1183
|
|
|
|
|
|
|
If you did not ask the $pdf object to write its output to a file, you can pick up |
1184
|
|
|
|
|
|
|
the pdf code by calling this method. It returns a big string. You need to call |
1185
|
|
|
|
|
|
|
C first. |
1186
|
|
|
|
|
|
|
|
1187
|
|
|
|
|
|
|
=cut |
1188
|
|
|
|
|
|
|
|
1189
|
|
|
|
|
|
|
sub get_data { |
1190
|
0
|
|
|
0
|
1
|
0
|
shift->{'data'}; |
1191
|
|
|
|
|
|
|
} |
1192
|
|
|
|
|
|
|
|
1193
|
|
|
|
|
|
|
sub uses_font { |
1194
|
86
|
|
|
86
|
0
|
3543
|
my ($self, $page, $font) = @_; |
1195
|
|
|
|
|
|
|
|
1196
|
86
|
|
|
|
|
3575
|
$page->{'resources'}{'fonts'}{$font} = 1; |
1197
|
86
|
|
|
|
|
3556
|
$page->{'resources'}{'ProcSet'} = [ 'PDF', 'Text' ]; |
1198
|
86
|
|
|
|
|
6959
|
$self->{'fontobj'}{$font} = 1; |
1199
|
|
|
|
|
|
|
} |
1200
|
|
|
|
|
|
|
|
1201
|
|
|
|
|
|
|
sub uses_xobject { |
1202
|
2
|
|
|
2
|
0
|
5
|
my ($self, $page, $xobject) = @_; |
1203
|
|
|
|
|
|
|
|
1204
|
2
|
|
|
|
|
6
|
$page->{'resources'}{'xobjects'}{$xobject} = 1; |
1205
|
2
|
|
|
|
|
8
|
$page->{'resources'}{'ProcSet'} = [ 'PDF', 'Text' ]; |
1206
|
2
|
|
|
|
|
10
|
$self->{'xobj'}{$xobject} = 1; |
1207
|
|
|
|
|
|
|
} |
1208
|
|
|
|
|
|
|
|
1209
|
|
|
|
|
|
|
sub debug { |
1210
|
9204
|
|
|
9204
|
0
|
862025
|
my ($level, $msg) = @_; |
1211
|
|
|
|
|
|
|
|
1212
|
9204
|
50
|
|
|
|
2347597
|
return unless ( $DEBUG >= $level ); |
1213
|
0
|
0
|
|
|
|
0
|
my $s = scalar @_ ? sprintf $msg, @_ : $msg; |
1214
|
|
|
|
|
|
|
|
1215
|
0
|
|
|
|
|
0
|
warn "DEBUG ($level): $s\n"; |
1216
|
|
|
|
|
|
|
} |
1217
|
|
|
|
|
|
|
|
1218
|
|
|
|
|
|
|
sub add { |
1219
|
2924
|
|
|
2924
|
0
|
209016
|
my $self = shift; |
1220
|
2924
|
|
|
|
|
210606
|
my $data = join '', @_; |
1221
|
|
|
|
|
|
|
|
1222
|
2924
|
|
|
|
|
210915
|
$self->{'size'} += length $data; |
1223
|
2924
|
100
|
|
|
|
210848
|
if ( defined $self->{'fh'} ) { |
1224
|
2914
|
|
|
|
|
209911
|
my $fh = $self->{'fh'}; |
1225
|
2914
|
|
|
|
|
772606
|
print $fh $data; |
1226
|
|
|
|
|
|
|
} else { |
1227
|
10
|
|
|
|
|
16
|
$self->{'data'} .= $data; |
1228
|
|
|
|
|
|
|
} |
1229
|
|
|
|
|
|
|
} |
1230
|
|
|
|
|
|
|
|
1231
|
|
|
|
|
|
|
sub position { |
1232
|
466
|
|
|
466
|
0
|
51981
|
my ($self) = @_; |
1233
|
|
|
|
|
|
|
|
1234
|
466
|
|
|
|
|
104812
|
$self->{'size'}; |
1235
|
|
|
|
|
|
|
} |
1236
|
|
|
|
|
|
|
|
1237
|
|
|
|
|
|
|
sub add_version { |
1238
|
32
|
|
|
32
|
0
|
3432
|
my ($self) = @_; |
1239
|
|
|
|
|
|
|
|
1240
|
32
|
|
|
|
|
3638
|
debug( 2, "add_version(): $self->{'version'}" ); |
1241
|
32
|
|
|
|
|
3858
|
$self->add( "%PDF-" . $self->{'version'} ); |
1242
|
32
|
|
|
|
|
3835
|
$self->cr; |
1243
|
|
|
|
|
|
|
} |
1244
|
|
|
|
|
|
|
|
1245
|
|
|
|
|
|
|
sub add_object { |
1246
|
185
|
|
|
185
|
0
|
19852
|
my ($self, $v) = @_; |
1247
|
|
|
|
|
|
|
|
1248
|
185
|
|
|
|
|
19763
|
my $val = &encode(@$v); |
1249
|
185
|
|
|
|
|
20403
|
$self->add($val); |
1250
|
185
|
|
|
|
|
19901
|
$self->cr; |
1251
|
185
|
|
|
|
|
21861
|
debug( 3, "add_object(): $v -> $val" ); |
1252
|
185
|
|
|
|
|
41468
|
[ $$v[1][0], $$v[1][1] ]; |
1253
|
|
|
|
|
|
|
} |
1254
|
|
|
|
|
|
|
|
1255
|
|
|
|
|
|
|
sub null { |
1256
|
90
|
|
|
90
|
0
|
20530
|
my ($self) = @_;; |
1257
|
|
|
|
|
|
|
|
1258
|
90
|
|
|
|
|
41728
|
[ 'null', 'null' ]; |
1259
|
|
|
|
|
|
|
} |
1260
|
|
|
|
|
|
|
|
1261
|
|
|
|
|
|
|
sub boolean { |
1262
|
0
|
|
|
0
|
0
|
0
|
my ($self, $val) = @_; |
1263
|
|
|
|
|
|
|
|
1264
|
0
|
|
|
|
|
0
|
[ 'boolean', $val ]; |
1265
|
|
|
|
|
|
|
} |
1266
|
|
|
|
|
|
|
|
1267
|
|
|
|
|
|
|
sub number { |
1268
|
143
|
|
|
143
|
0
|
14036
|
my ($self, $val) = @_;; |
1269
|
|
|
|
|
|
|
|
1270
|
143
|
|
|
|
|
33113
|
[ 'number', $val ]; |
1271
|
|
|
|
|
|
|
} |
1272
|
|
|
|
|
|
|
|
1273
|
|
|
|
|
|
|
sub name { |
1274
|
396
|
|
|
396
|
0
|
37132
|
my ($self, $val) = @_; |
1275
|
|
|
|
|
|
|
|
1276
|
396
|
|
|
|
|
79384
|
[ 'name', $val ]; |
1277
|
|
|
|
|
|
|
} |
1278
|
|
|
|
|
|
|
|
1279
|
|
|
|
|
|
|
sub string { |
1280
|
73
|
|
|
73
|
0
|
12227
|
my ($self, $val) = @_; |
1281
|
|
|
|
|
|
|
|
1282
|
73
|
|
|
|
|
24038
|
[ 'string', $val ]; |
1283
|
|
|
|
|
|
|
} |
1284
|
|
|
|
|
|
|
|
1285
|
|
|
|
|
|
|
sub verbatim { |
1286
|
5
|
|
|
5
|
0
|
16
|
my ($self, $val) = @_; |
1287
|
|
|
|
|
|
|
|
1288
|
5
|
|
|
|
|
34
|
[ 'verbatim', $val ]; |
1289
|
|
|
|
|
|
|
} |
1290
|
|
|
|
|
|
|
|
1291
|
|
|
|
|
|
|
sub array { |
1292
|
123
|
|
|
123
|
0
|
13895
|
my $self = shift; |
1293
|
|
|
|
|
|
|
|
1294
|
123
|
|
|
|
|
34193
|
[ 'array', [@_] ]; |
1295
|
|
|
|
|
|
|
} |
1296
|
|
|
|
|
|
|
|
1297
|
|
|
|
|
|
|
sub dictionary { |
1298
|
197
|
|
|
197
|
0
|
19509
|
my $self = shift; |
1299
|
|
|
|
|
|
|
|
1300
|
197
|
|
|
|
|
41676
|
[ 'dictionary', {@_} ]; |
1301
|
|
|
|
|
|
|
} |
1302
|
|
|
|
|
|
|
|
1303
|
|
|
|
|
|
|
sub indirect_obj { |
1304
|
185
|
|
|
185
|
0
|
20799
|
my $self = shift; |
1305
|
|
|
|
|
|
|
|
1306
|
185
|
|
|
|
|
20467
|
my ($id, $gen, $type, $name); |
1307
|
185
|
|
|
|
|
20454
|
$name = $_[1]; |
1308
|
|
|
|
|
|
|
$type = $_[0][1]{'Type'}[1] |
1309
|
185
|
100
|
66
|
|
|
21309
|
if defined $_[0][1] && ref $_[0][1] eq 'HASH' && defined $_[0][1]{'Type'}; |
|
|
|
100
|
|
|
|
|
1310
|
|
|
|
|
|
|
|
1311
|
185
|
100
|
66
|
|
|
20561
|
if ( defined $name && defined $self->{'reservations'}{$name} ) { |
|
|
100
|
66
|
|
|
|
|
1312
|
134
|
|
|
|
|
15482
|
( $id, $gen ) = @{ $self->{'reservations'}{$name} }; |
|
134
|
|
|
|
|
31411
|
|
1313
|
134
|
|
|
|
|
31397
|
delete $self->{'reservations'}{$name}; |
1314
|
|
|
|
|
|
|
} elsif ( defined $type && defined $self->{'reservations'}{$type} ) { |
1315
|
50
|
|
|
|
|
4229
|
( $id, $gen ) = @{ $self->{'reservations'}{$type} }; |
|
50
|
|
|
|
|
8329
|
|
1316
|
50
|
|
|
|
|
8825
|
delete $self->{'reservations'}{$type}; |
1317
|
|
|
|
|
|
|
} else { |
1318
|
1
|
|
|
|
|
2
|
$id = ++$self->{'object_number'}; |
1319
|
1
|
|
|
|
|
2
|
$gen = $self->{'generation_number'}; |
1320
|
|
|
|
|
|
|
} |
1321
|
185
|
|
|
|
|
20677
|
debug( 3, "indirect_obj(): " . $self->position ); |
1322
|
185
|
|
|
|
|
20258
|
push @{ $self->{'crossrefsubsection'}{$gen} }, [ $id, $self->position, 1 ]; |
|
185
|
|
|
|
|
40379
|
|
1323
|
185
|
|
|
|
|
40020
|
[ 'object', [ $id, $gen, @_ ] ]; |
1324
|
|
|
|
|
|
|
} |
1325
|
|
|
|
|
|
|
|
1326
|
|
|
|
|
|
|
sub indirect_ref { |
1327
|
313
|
|
|
313
|
0
|
44945
|
my $self = shift; |
1328
|
|
|
|
|
|
|
|
1329
|
313
|
|
|
|
|
101059
|
[ 'ref', [@_] ]; |
1330
|
|
|
|
|
|
|
} |
1331
|
|
|
|
|
|
|
|
1332
|
|
|
|
|
|
|
sub stream { |
1333
|
3
|
|
|
3
|
0
|
4
|
my $self = shift; |
1334
|
|
|
|
|
|
|
|
1335
|
3
|
|
|
|
|
15
|
[ 'stream', {@_} ]; |
1336
|
|
|
|
|
|
|
} |
1337
|
|
|
|
|
|
|
|
1338
|
|
|
|
|
|
|
sub add_info { |
1339
|
15
|
|
|
15
|
0
|
1080
|
my $self = shift; |
1340
|
|
|
|
|
|
|
|
1341
|
15
|
|
|
|
|
1134
|
debug( 2, "add_info():" ); |
1342
|
15
|
|
|
|
|
1109
|
my %params = @_; |
1343
|
15
|
100
|
|
|
|
1118
|
$params{'Author'} = $self->{'Author'} if defined $self->{'Author'}; |
1344
|
15
|
50
|
|
|
|
1092
|
$params{'Creator'} = $self->{'Creator'} if defined $self->{'Creator'}; |
1345
|
15
|
100
|
|
|
|
1156
|
$params{'Title'} = $self->{'Title'} if defined $self->{'Title'}; |
1346
|
15
|
50
|
|
|
|
1104
|
$params{'Subject'} = $self->{'Subject'} if defined $self->{'Subject'}; |
1347
|
15
|
50
|
|
|
|
1097
|
$params{'Keywords'} = $self->{'Keywords'} if defined $self->{'Keywords'}; |
1348
|
|
|
|
|
|
|
$params{'CreationDate'} = $self->{'CreationDate'} |
1349
|
15
|
50
|
|
|
|
1091
|
if defined $self->{'CreationDate'}; |
1350
|
|
|
|
|
|
|
|
1351
|
15
|
|
|
|
|
1120
|
$self->{'info'} = $self->reserve('Info'); |
1352
|
15
|
|
|
|
|
1142
|
my $content = { |
1353
|
|
|
|
|
|
|
'Producer' => $self->string("PDF::Create version $VERSION"), |
1354
|
|
|
|
|
|
|
'Type' => $self->name('Info') |
1355
|
|
|
|
|
|
|
}; |
1356
|
|
|
|
|
|
|
$$content{'Author'} = $self->string( $params{'Author'} ) |
1357
|
15
|
100
|
|
|
|
1134
|
if defined $params{'Author'}; |
1358
|
|
|
|
|
|
|
$$content{'Creator'} = $self->string( $params{'Creator'} ) |
1359
|
15
|
50
|
|
|
|
1106
|
if defined $params{'Creator'}; |
1360
|
|
|
|
|
|
|
$$content{'Title'} = $self->string( $params{'Title'} ) |
1361
|
15
|
100
|
|
|
|
1141
|
if defined $params{'Title'}; |
1362
|
|
|
|
|
|
|
$$content{'Subject'} = $self->string( $params{'Subject'} ) |
1363
|
15
|
50
|
|
|
|
1109
|
if defined $params{'Subject'}; |
1364
|
|
|
|
|
|
|
$$content{'Keywords'} = $self->string( $params{'Keywords'} ) |
1365
|
15
|
50
|
|
|
|
1103
|
if defined $params{'Keywords'}; |
1366
|
|
|
|
|
|
|
$$content{'CreationDate'} = $self->string( $params{'CreationDate'} ) |
1367
|
15
|
50
|
|
|
|
1143
|
if defined $params{'CreationDate'}; |
1368
|
|
|
|
|
|
|
|
1369
|
15
|
|
|
|
|
1137
|
$self->add_object( $self->indirect_obj( $self->dictionary(%$content) ), 'Info' ); |
1370
|
15
|
|
|
|
|
1231
|
$self->cr; |
1371
|
|
|
|
|
|
|
} |
1372
|
|
|
|
|
|
|
|
1373
|
|
|
|
|
|
|
sub add_catalog { |
1374
|
15
|
|
|
15
|
0
|
2017
|
my $self = shift; |
1375
|
|
|
|
|
|
|
|
1376
|
15
|
|
|
|
|
2271
|
debug( 2, "add_catalog" ); |
1377
|
15
|
|
|
|
|
1494
|
my %params = %{ $self->{'catalog'} }; |
|
15
|
|
|
|
|
3058
|
|
1378
|
|
|
|
|
|
|
|
1379
|
|
|
|
|
|
|
# Type (mandatory) |
1380
|
15
|
|
|
|
|
1576
|
$self->{'catalog'} = $self->reserve('Catalog'); |
1381
|
15
|
|
|
|
|
1115
|
my $content = { 'Type' => $self->name('Catalog') }; |
1382
|
|
|
|
|
|
|
|
1383
|
|
|
|
|
|
|
# Pages (mandatory) [indirected reference] |
1384
|
15
|
|
|
|
|
1151
|
my $pages = $self->reserve('Pages'); |
1385
|
15
|
|
|
|
|
1140
|
$$content{'Pages'} = $self->indirect_ref(@$pages); |
1386
|
15
|
|
|
|
|
1097
|
$self->{'pages'}{'id'} = $$content{'Pages'}[1]; |
1387
|
|
|
|
|
|
|
|
1388
|
|
|
|
|
|
|
# Outlines [indirected reference] |
1389
|
5
|
|
|
|
|
2103
|
$$content{'Outlines'} = $self->indirect_ref( @{ $self->{'outlines'}->{'id'} } ) |
1390
|
15
|
100
|
|
|
|
1120
|
if defined $self->{'outlines'}; |
1391
|
|
|
|
|
|
|
|
1392
|
|
|
|
|
|
|
# PageMode |
1393
|
15
|
100
|
|
|
|
1114
|
$$content{'PageMode'} = $self->name($params{'PageMode'}) if defined $params{'PageMode'}; |
1394
|
|
|
|
|
|
|
|
1395
|
15
|
|
|
|
|
1112
|
$self->add_object( $self->indirect_obj( $self->dictionary(%$content) ) ); |
1396
|
15
|
|
|
|
|
1091
|
$self->cr; |
1397
|
|
|
|
|
|
|
} |
1398
|
|
|
|
|
|
|
|
1399
|
|
|
|
|
|
|
sub encode { |
1400
|
6203
|
|
|
6203
|
0
|
669506
|
my ($type, $val) = @_; |
1401
|
|
|
|
|
|
|
|
1402
|
6203
|
100
|
|
|
|
642424
|
if ($val) { |
1403
|
2748
|
|
|
|
|
319871
|
debug( 4, "encode(): $type $val" ); |
1404
|
|
|
|
|
|
|
} else { |
1405
|
3455
|
|
|
|
|
331037
|
debug( 4, "encode(): $type (no val)" ); |
1406
|
|
|
|
|
|
|
} |
1407
|
|
|
|
|
|
|
|
1408
|
6203
|
100
|
|
|
|
648567
|
if (!$type) { |
1409
|
1
|
|
|
|
|
221
|
cluck "PDF::Create::encode: empty argument, called by "; |
1410
|
1
|
|
|
|
|
10
|
return 1; |
1411
|
|
|
|
|
|
|
} |
1412
|
|
|
|
|
|
|
|
1413
|
|
|
|
|
|
|
( $type eq 'null' || $type eq 'number' ) && do { |
1414
|
1243
|
|
|
|
|
330048
|
1; # do nothing |
1415
|
|
|
|
|
|
|
} |
1416
|
|
|
|
|
|
|
|| $type eq 'cr' && do { |
1417
|
2915
|
|
|
|
|
515824
|
$val = "\n"; |
1418
|
|
|
|
|
|
|
} |
1419
|
|
|
|
|
|
|
|| $type eq 'boolean' && do { |
1420
|
4
|
100
|
|
|
|
31
|
$val = |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1421
|
|
|
|
|
|
|
$val eq 'true' ? $val |
1422
|
|
|
|
|
|
|
: $val eq 'false' ? $val |
1423
|
|
|
|
|
|
|
: $val eq '0' ? 'false' |
1424
|
|
|
|
|
|
|
: 'true'; |
1425
|
|
|
|
|
|
|
} |
1426
|
|
|
|
|
|
|
|| $type eq 'verbatim' && do { |
1427
|
8
|
|
|
|
|
44
|
$val = "$val"; |
1428
|
|
|
|
|
|
|
} |
1429
|
|
|
|
|
|
|
|| $type eq 'string' && do { |
1430
|
77
|
100
|
|
|
|
10123
|
$val = '' if not defined $val; |
1431
|
|
|
|
|
|
|
# TODO: split it. Quote parentheses. |
1432
|
77
|
|
|
|
|
20665
|
$val = "($val)"; |
1433
|
|
|
|
|
|
|
} |
1434
|
|
|
|
|
|
|
|| $type eq 'number' && do { |
1435
|
0
|
|
|
|
|
0
|
$val = "$val"; |
1436
|
|
|
|
|
|
|
} |
1437
|
|
|
|
|
|
|
|| $type eq 'name' && do { |
1438
|
1128
|
100
|
|
|
|
110751
|
$val = '' if not defined $val; |
1439
|
1128
|
|
|
|
|
221769
|
$val = "/$val"; |
1440
|
|
|
|
|
|
|
} |
1441
|
|
|
|
|
|
|
|| $type eq 'array' && do { |
1442
|
|
|
|
|
|
|
|
1443
|
|
|
|
|
|
|
# array, encode contents individually |
1444
|
125
|
|
|
|
|
13471
|
my $s = '['; |
1445
|
125
|
|
|
|
|
13607
|
for my $v (@$val) { |
1446
|
327
|
|
|
|
|
14626
|
$s .= &encode( $$v[0], $$v[1] ) . " "; |
1447
|
|
|
|
|
|
|
} |
1448
|
|
|
|
|
|
|
# remove the trailing space |
1449
|
125
|
|
|
|
|
14662
|
chop $s; |
1450
|
125
|
|
|
|
|
28153
|
$val = $s . "]"; |
1451
|
|
|
|
|
|
|
} |
1452
|
|
|
|
|
|
|
|| $type eq 'dictionary' && do { |
1453
|
197
|
|
|
|
|
19381
|
my $s = '<<' . &encode('cr'); |
1454
|
197
|
|
|
|
|
18830
|
for my $v ( keys %$val ) { |
1455
|
743
|
|
|
|
|
82908
|
$s .= &encode( 'name', $v ) . " "; |
1456
|
743
|
|
|
|
|
80279
|
$s .= &encode( ${ $$val{$v} }[0], ${ $$val{$v} }[1] ); # . " "; |
|
743
|
|
|
|
|
156542
|
|
|
743
|
|
|
|
|
157904
|
|
1457
|
743
|
|
|
|
|
83865
|
$s .= &encode('cr'); |
1458
|
|
|
|
|
|
|
} |
1459
|
197
|
|
|
|
|
40033
|
$val = $s . ">>"; |
1460
|
|
|
|
|
|
|
} |
1461
|
|
|
|
|
|
|
|| $type eq 'object' && do { |
1462
|
186
|
|
|
|
|
19913
|
my $s = &encode( 'number', $$val[0] ) . " " . &encode( 'number', $$val[1] ) . " obj"; |
1463
|
186
|
|
|
|
|
20917
|
$s .= &encode('cr'); |
1464
|
186
|
|
|
|
|
20870
|
$s .= &encode( $$val[2][0], $$val[2][1] ); # . " "; |
1465
|
186
|
|
|
|
|
20381
|
$s .= &encode('cr'); |
1466
|
186
|
|
|
|
|
40380
|
$val = $s . "endobj"; |
1467
|
|
|
|
|
|
|
} |
1468
|
|
|
|
|
|
|
|| $type eq 'ref' && do { |
1469
|
315
|
|
|
|
|
44093
|
my $s = &encode( 'number', $$val[0] ) . " " . &encode( 'number', $$val[1] ) . " R"; |
1470
|
315
|
|
|
|
|
90185
|
$val = $s; |
1471
|
|
|
|
|
|
|
} |
1472
|
6202
|
100
|
100
|
|
|
679403
|
|| $type eq 'stream' && do { |
|
|
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
1473
|
3
|
|
|
|
|
6
|
my $data = delete $$val{'Data'}; |
1474
|
3
|
|
|
|
|
6
|
my $s = '<<' . &encode('cr'); |
1475
|
3
|
|
|
|
|
10
|
for my $v ( keys %$val ) { |
1476
|
22
|
|
|
|
|
32
|
$s .= &encode( 'name', $v ) . " "; |
1477
|
22
|
|
|
|
|
26
|
$s .= &encode( ${ $$val{$v} }[0], ${ $$val{$v} }[1] ); # . " "; |
|
22
|
|
|
|
|
31
|
|
|
22
|
|
|
|
|
28
|
|
1478
|
22
|
|
|
|
|
30
|
$s .= &encode('cr'); |
1479
|
|
|
|
|
|
|
} |
1480
|
3
|
|
|
|
|
6
|
$s .= ">>" . &encode('cr') . "stream" . &encode('cr'); |
1481
|
3
|
|
|
|
|
7
|
$s .= $data . &encode('cr'); |
1482
|
3
|
|
|
|
|
17
|
$val = $s . "endstream" . &encode('cr'); |
1483
|
|
|
|
|
|
|
} |
1484
|
|
|
|
|
|
|
|| confess "Error: unknown type '$type'"; |
1485
|
|
|
|
|
|
|
|
1486
|
|
|
|
|
|
|
# TODO: add type 'text'; |
1487
|
6201
|
|
|
|
|
1314133
|
$val; |
1488
|
|
|
|
|
|
|
} |
1489
|
|
|
|
|
|
|
|
1490
|
|
|
|
|
|
|
=head1 LIMITATIONS |
1491
|
|
|
|
|
|
|
|
1492
|
|
|
|
|
|
|
C comes with a couple of limitations or known caveats: |
1493
|
|
|
|
|
|
|
|
1494
|
|
|
|
|
|
|
=head2 PDF Size / Memory |
1495
|
|
|
|
|
|
|
|
1496
|
|
|
|
|
|
|
Unless using a filehandle, C assembles the entire PDF in memory. |
1497
|
|
|
|
|
|
|
If you create very large documents on a machine with a small amount of memory |
1498
|
|
|
|
|
|
|
your program can fail because it runs out of memory. If using a filehandle, |
1499
|
|
|
|
|
|
|
data will be written immediately to the filehandle after each method. |
1500
|
|
|
|
|
|
|
|
1501
|
|
|
|
|
|
|
=head2 Small GIF images |
1502
|
|
|
|
|
|
|
|
1503
|
|
|
|
|
|
|
Some gif images get created with a minimal lzw code size of less than 8. C |
1504
|
|
|
|
|
|
|
can not decode those and they must be converted. |
1505
|
|
|
|
|
|
|
|
1506
|
|
|
|
|
|
|
=head1 SUPPORT |
1507
|
|
|
|
|
|
|
|
1508
|
|
|
|
|
|
|
I support C in my spare time between work and family, so the amount |
1509
|
|
|
|
|
|
|
of work I put in is limited. |
1510
|
|
|
|
|
|
|
|
1511
|
|
|
|
|
|
|
If you experience a problem make sure you are at the latest version first many of |
1512
|
|
|
|
|
|
|
things have already been fixed. |
1513
|
|
|
|
|
|
|
|
1514
|
|
|
|
|
|
|
Please register bug at the CPAN bug tracking system at L or |
1515
|
|
|
|
|
|
|
send email to C |
1516
|
|
|
|
|
|
|
|
1517
|
|
|
|
|
|
|
Be sure to include the following information: |
1518
|
|
|
|
|
|
|
|
1519
|
|
|
|
|
|
|
=over 4 |
1520
|
|
|
|
|
|
|
|
1521
|
|
|
|
|
|
|
=item - PDF::Create Version you are running |
1522
|
|
|
|
|
|
|
|
1523
|
|
|
|
|
|
|
=item - Perl version (perl -v) |
1524
|
|
|
|
|
|
|
|
1525
|
|
|
|
|
|
|
=item - Operating System vendor and version |
1526
|
|
|
|
|
|
|
|
1527
|
|
|
|
|
|
|
=item - Details about your operating environment that might be related to the issue |
1528
|
|
|
|
|
|
|
being described |
1529
|
|
|
|
|
|
|
|
1530
|
|
|
|
|
|
|
=item - Exact cut and pasted error or warning messages |
1531
|
|
|
|
|
|
|
|
1532
|
|
|
|
|
|
|
=item - The shortest, clearest code you can manage to write which reproduces the |
1533
|
|
|
|
|
|
|
bug described. |
1534
|
|
|
|
|
|
|
|
1535
|
|
|
|
|
|
|
=back |
1536
|
|
|
|
|
|
|
|
1537
|
|
|
|
|
|
|
I appreciate patches against the latest released version of C which |
1538
|
|
|
|
|
|
|
fix the bug. |
1539
|
|
|
|
|
|
|
|
1540
|
|
|
|
|
|
|
B can be submitted like bugs. If you provide patch for a feature |
1541
|
|
|
|
|
|
|
which does not go against the C philosophy (keep it simple) then you |
1542
|
|
|
|
|
|
|
have a good chance for it to be accepted. |
1543
|
|
|
|
|
|
|
|
1544
|
|
|
|
|
|
|
=head1 SEE ALSO |
1545
|
|
|
|
|
|
|
|
1546
|
|
|
|
|
|
|
L |
1547
|
|
|
|
|
|
|
|
1548
|
|
|
|
|
|
|
L Routines to produce formatted pages of mailing labels in PDF, uses L internally. |
1549
|
|
|
|
|
|
|
|
1550
|
|
|
|
|
|
|
L Perl interface to Haru Free PDF Library. |
1551
|
|
|
|
|
|
|
|
1552
|
|
|
|
|
|
|
L PDF creation from a one-file module, similar to L. |
1553
|
|
|
|
|
|
|
|
1554
|
|
|
|
|
|
|
L Yet another PDF creation module |
1555
|
|
|
|
|
|
|
|
1556
|
|
|
|
|
|
|
L A wrapper written for L. |
1557
|
|
|
|
|
|
|
|
1558
|
|
|
|
|
|
|
=head1 AUTHORS |
1559
|
|
|
|
|
|
|
|
1560
|
|
|
|
|
|
|
Fabien Tassin |
1561
|
|
|
|
|
|
|
|
1562
|
|
|
|
|
|
|
GIF and JPEG-support: Michael Gross (info@mdgrosse.net) |
1563
|
|
|
|
|
|
|
|
1564
|
|
|
|
|
|
|
Maintenance since 2007: Markus Baertschi (markus@markus.org) |
1565
|
|
|
|
|
|
|
|
1566
|
|
|
|
|
|
|
Currently maintained by Mohammad S Anwar (MANWAR) C<< >> |
1567
|
|
|
|
|
|
|
|
1568
|
|
|
|
|
|
|
=head1 REPOSITORY |
1569
|
|
|
|
|
|
|
|
1570
|
|
|
|
|
|
|
L |
1571
|
|
|
|
|
|
|
|
1572
|
|
|
|
|
|
|
=head1 COPYRIGHT |
1573
|
|
|
|
|
|
|
|
1574
|
|
|
|
|
|
|
Copyright 1999-2001,Fabien Tassin.All rights reserved.It may be used and modified |
1575
|
|
|
|
|
|
|
freely, but I do request that this copyright notice remain attached to the file. |
1576
|
|
|
|
|
|
|
You may modify this module as you wish,but if you redistribute a modified version |
1577
|
|
|
|
|
|
|
, please attach a note listing the modifications you have made. |
1578
|
|
|
|
|
|
|
|
1579
|
|
|
|
|
|
|
Copyright 2007 Markus Baertschi |
1580
|
|
|
|
|
|
|
|
1581
|
|
|
|
|
|
|
Copyright 2010 Gary Lieberman |
1582
|
|
|
|
|
|
|
|
1583
|
|
|
|
|
|
|
=head1 LICENSE |
1584
|
|
|
|
|
|
|
|
1585
|
|
|
|
|
|
|
This is free software; you can redistribute it and / or modify it under the same |
1586
|
|
|
|
|
|
|
terms as Perl 5.6.0. |
1587
|
|
|
|
|
|
|
|
1588
|
|
|
|
|
|
|
=cut |
1589
|
|
|
|
|
|
|
|
1590
|
|
|
|
|
|
|
1; |