| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package PDF::Create; |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
our $VERSION = '1.42'; |
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=head1 NAME |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
PDF::Create - Create PDF files. |
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
=head1 VERSION |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
Version 1.42 |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=cut |
|
14
|
|
|
|
|
|
|
|
|
15
|
18
|
|
|
18
|
|
44074
|
use 5.006; |
|
|
18
|
|
|
|
|
45
|
|
|
16
|
18
|
|
|
18
|
|
66
|
use strict; use warnings; |
|
|
18
|
|
|
18
|
|
16
|
|
|
|
18
|
|
|
|
|
338
|
|
|
|
18
|
|
|
|
|
60
|
|
|
|
18
|
|
|
|
|
23
|
|
|
|
18
|
|
|
|
|
534
|
|
|
17
|
|
|
|
|
|
|
|
|
18
|
18
|
|
|
18
|
|
75
|
use Carp qw(confess croak cluck carp); |
|
|
18
|
|
|
|
|
19
|
|
|
|
18
|
|
|
|
|
1432
|
|
|
19
|
18
|
|
|
18
|
|
9644
|
use Data::Dumper; |
|
|
18
|
|
|
|
|
126915
|
|
|
|
18
|
|
|
|
|
1054
|
|
|
20
|
18
|
|
|
18
|
|
7135
|
use FileHandle; |
|
|
18
|
|
|
|
|
133136
|
|
|
|
18
|
|
|
|
|
89
|
|
|
21
|
18
|
|
|
18
|
|
4774
|
use Scalar::Util qw(weaken); |
|
|
18
|
|
|
|
|
23
|
|
|
|
18
|
|
|
|
|
1256
|
|
|
22
|
|
|
|
|
|
|
|
|
23
|
18
|
|
|
18
|
|
7319
|
use PDF::Image::GIF; |
|
|
18
|
|
|
|
|
33
|
|
|
|
18
|
|
|
|
|
486
|
|
|
24
|
18
|
|
|
18
|
|
5696
|
use PDF::Image::JPEG; |
|
|
18
|
|
|
|
|
31
|
|
|
|
18
|
|
|
|
|
453
|
|
|
25
|
18
|
|
|
18
|
|
7131
|
use PDF::Create::Page; |
|
|
18
|
|
|
|
|
50
|
|
|
|
18
|
|
|
|
|
1452
|
|
|
26
|
18
|
|
|
18
|
|
7501
|
use PDF::Create::Outline; |
|
|
18
|
|
|
|
|
31
|
|
|
|
18
|
|
|
|
|
99950
|
|
|
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
|
68279
|
my ($this, %params) = @_; |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
# validate constructor keys |
|
173
|
42
|
|
|
|
|
4205
|
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
|
|
|
|
|
4022
|
foreach (keys %params) { |
|
187
|
|
|
|
|
|
|
croak "Invalid constructor key '$_' received." |
|
188
|
138
|
100
|
|
|
|
8401
|
unless (exists $valid_constructor_keys{$_}); |
|
189
|
|
|
|
|
|
|
} |
|
190
|
|
|
|
|
|
|
|
|
191
|
34
|
100
|
66
|
|
|
3964
|
if (exists $params{PageMode} && defined $params{PageMode}) { |
|
192
|
|
|
|
|
|
|
# validate PageMode key value |
|
193
|
26
|
|
|
|
|
4025
|
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
|
|
|
|
7886
|
unless (exists $valid_page_mode_values{$params{PageMode}}); |
|
200
|
|
|
|
|
|
|
} |
|
201
|
|
|
|
|
|
|
|
|
202
|
33
|
100
|
66
|
|
|
3971
|
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
|
|
|
4037
|
my $class = ref($this) || $this; |
|
209
|
32
|
|
|
|
|
3782
|
my $self = {}; |
|
210
|
32
|
|
|
|
|
3876
|
bless $self, $class; |
|
211
|
|
|
|
|
|
|
|
|
212
|
32
|
|
|
|
|
3875
|
$self->{'data'} = ''; |
|
213
|
32
|
|
100
|
|
|
4193
|
$self->{'version'} = $params{'Version'} || "1.2"; |
|
214
|
32
|
|
|
|
|
3915
|
$self->{'trailer'} = {}; |
|
215
|
|
|
|
|
|
|
|
|
216
|
32
|
|
|
|
|
4027
|
$self->{'pages'} = PDF::Create::Page->new(); |
|
217
|
32
|
|
|
|
|
3928
|
$self->{'current_page'} = $self->{'pages'}; |
|
218
|
|
|
|
|
|
|
# circular reference |
|
219
|
32
|
|
|
|
|
3903
|
$self->{'pages'}->{'pdf'} = $self; |
|
220
|
32
|
|
|
|
|
4126
|
weaken $self->{pages}{pdf}; |
|
221
|
32
|
|
|
|
|
3842
|
$self->{'page_count'} = 0; |
|
222
|
32
|
|
|
|
|
3861
|
$self->{'outline_count'} = 0; |
|
223
|
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
# cross-reference table start address |
|
225
|
32
|
|
|
|
|
4004
|
$self->{'crossreftblstartaddr'} = 0; |
|
226
|
32
|
|
|
|
|
3946
|
$self->{'generation_number'} = 0; |
|
227
|
32
|
|
|
|
|
3755
|
$self->{'object_number'} = 0; |
|
228
|
|
|
|
|
|
|
|
|
229
|
32
|
100
|
|
|
|
3968
|
if ( defined $params{'fh'} ) { |
|
|
|
100
|
|
|
|
|
|
|
230
|
1
|
|
|
|
|
2
|
$self->{'fh'} = $params{'fh'}; |
|
231
|
|
|
|
|
|
|
} elsif ( defined $params{'filename'} ) { |
|
232
|
26
|
|
|
|
|
3965
|
$self->{'filename'} = $params{'filename'}; |
|
233
|
26
|
|
|
|
|
4172
|
my $fh = FileHandle->new( "> $self->{'filename'}" ); |
|
234
|
26
|
50
|
|
|
|
107099
|
carp "PDF::Create.pm: $self->{'filename'}: $!\n" unless defined $fh; |
|
235
|
26
|
|
|
|
|
3782
|
binmode $fh, ':utf8'; |
|
236
|
26
|
|
|
|
|
7475
|
$self->{'fh'} = $fh; |
|
237
|
|
|
|
|
|
|
} |
|
238
|
|
|
|
|
|
|
|
|
239
|
32
|
|
|
|
|
3836
|
$self->{'catalog'} = {}; |
|
240
|
32
|
100
|
|
|
|
3750
|
$self->{'catalog'}{'PageMode'} = $params{'PageMode'} if defined $params{'PageMode'}; |
|
241
|
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
# Header: add version |
|
243
|
32
|
|
|
|
|
3829
|
$self->add_version; |
|
244
|
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
# Info |
|
246
|
32
|
100
|
|
|
|
3932
|
$self->{'Author'} = $params{'Author'} if defined $params{'Author'}; |
|
247
|
32
|
50
|
|
|
|
3723
|
$self->{'Creator'} = $params{'Creator'} if defined $params{'Creator'}; |
|
248
|
32
|
100
|
|
|
|
3853
|
$self->{'Title'} = $params{'Title'} if defined $params{'Title'}; |
|
249
|
32
|
50
|
|
|
|
3819
|
$self->{'Subject'} = $params{'Subject'} if defined $params{'Subject'}; |
|
250
|
32
|
50
|
|
|
|
3799
|
$self->{'Keywords'} = $params{'Keywords'} if defined $params{'Keywords'}; |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
# TODO: Default creation date from system date |
|
253
|
32
|
50
|
|
|
|
3885
|
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
|
|
|
|
3710
|
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
|
|
|
|
|
3861
|
debug( 1, "Debugging level $DEBUG" ); |
|
267
|
32
|
|
|
|
|
9687
|
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
|
9045
|
my ($self, %params) = @_; |
|
336
|
|
|
|
|
|
|
|
|
337
|
51
|
|
|
|
|
5626
|
my %valid_new_page_parameters = map { $_ => 1 } (qw/Parent Resources MediaBox CropBox ArtBox TrimBox BleedBox Rotate/); |
|
|
408
|
|
|
|
|
89580
|
|
|
338
|
51
|
|
|
|
|
5649
|
foreach my $key (keys %params) { |
|
339
|
|
|
|
|
|
|
croak "PDF::Create.pm - new_page(): Received invalid key [$key]" |
|
340
|
51
|
100
|
|
|
|
11200
|
unless (exists $valid_new_page_parameters{$key}); |
|
341
|
|
|
|
|
|
|
} |
|
342
|
|
|
|
|
|
|
|
|
343
|
50
|
|
66
|
|
|
6057
|
my $parent = $params{'Parent'} || $self->{'pages'}; |
|
344
|
50
|
|
|
|
|
6761
|
my $name = "Page " . ++$self->{'page_count'}; |
|
345
|
50
|
|
|
|
|
5758
|
my $page = $parent->add( $self->reserve( $name, "Page" ), $name ); |
|
346
|
50
|
50
|
|
|
|
5686
|
$page->{'resources'} = $params{'Resources'} if defined $params{'Resources'}; |
|
347
|
50
|
100
|
|
|
|
5561
|
$page->{'mediabox'} = $params{'MediaBox'} if defined $params{'MediaBox'}; |
|
348
|
50
|
50
|
|
|
|
5467
|
$page->{'cropbox'} = $params{'CropBox'} if defined $params{'CropBox'}; |
|
349
|
50
|
50
|
|
|
|
5677
|
$page->{'artbox'} = $params{'ArtBox'} if defined $params{'ArtBox'}; |
|
350
|
50
|
50
|
|
|
|
5784
|
$page->{'trimbox'} = $params{'TrimBox'} if defined $params{'TrimBox'}; |
|
351
|
50
|
50
|
|
|
|
5505
|
$page->{'bleedbox'} = $params{'BleedBox'} if defined $params{'BleedBox'}; |
|
352
|
50
|
50
|
|
|
|
5484
|
$page->{'rotate'} = $params{'Rotate'} if defined $params{'Rotate'}; |
|
353
|
|
|
|
|
|
|
|
|
354
|
50
|
|
|
|
|
5875
|
$self->{'current_page'} = $page; |
|
355
|
|
|
|
|
|
|
|
|
356
|
50
|
|
|
|
|
16380
|
$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
|
10219
|
my ($self, %params) = @_; |
|
392
|
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
my %valid_font_parameters = ( |
|
394
|
184
|
|
|
|
|
30626
|
'Subtype' => { map { $_ => 1 } qw/Type0 Type1 Type3 TrueType/ }, |
|
395
|
184
|
|
|
|
|
30543
|
'Encoding' => { map { $_ => 1 } qw/MacRomanEncoding MacExpertEncoding WinAnsiEncoding Symbol/ }, |
|
396
|
46
|
|
|
|
|
3789
|
'BaseFont' => { map { $_ => 1 } qw/Courier Courier-Bold Courier-BoldOblique Courier-Oblique |
|
|
598
|
|
|
|
|
102246
|
|
|
397
|
|
|
|
|
|
|
Helvetica Helvetica-Bold Helvetica-BoldOblique Helvetica-Oblique |
|
398
|
|
|
|
|
|
|
Times-Roman Times-Bold Times-Italic Times-BoldItalic Symbol/ }, |
|
399
|
|
|
|
|
|
|
); |
|
400
|
|
|
|
|
|
|
|
|
401
|
46
|
|
|
|
|
4146
|
foreach my $key (keys %params) { |
|
402
|
|
|
|
|
|
|
croak "PDF::Create.pm - font(): Received invalid key [$key]" |
|
403
|
130
|
100
|
|
|
|
11392
|
unless (exists $valid_font_parameters{$key}); |
|
404
|
129
|
|
|
|
|
10998
|
my $value = $params{$key}; |
|
405
|
|
|
|
|
|
|
croak "PDF::Create.pm - font(): Received invalid value [$value] for key [$key]" |
|
406
|
129
|
100
|
66
|
|
|
15586
|
if (defined $value && !(exists $valid_font_parameters{$key}->{$value})); |
|
407
|
|
|
|
|
|
|
} |
|
408
|
|
|
|
|
|
|
|
|
409
|
42
|
|
|
|
|
3738
|
my $num = 1 + scalar keys %{ $self->{'fonts'} }; |
|
|
42
|
|
|
|
|
8293
|
|
|
410
|
|
|
|
|
|
|
$self->{'fonts'}{$num} = { |
|
411
|
|
|
|
|
|
|
'Subtype' => $self->name( $params{'Subtype'} || 'Type1' ), |
|
412
|
|
|
|
|
|
|
'Encoding' => $self->name( $params{'Encoding'} || 'WinAnsiEncoding' ), |
|
413
|
42
|
|
100
|
|
|
3976
|
'BaseFont' => $self->name( $params{'BaseFont'} || 'Helvetica' ), |
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
414
|
|
|
|
|
|
|
'Name' => $self->name("F$num"), |
|
415
|
|
|
|
|
|
|
'Type' => $self->name("Font"), |
|
416
|
|
|
|
|
|
|
}; |
|
417
|
|
|
|
|
|
|
|
|
418
|
42
|
|
|
|
|
8919
|
$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
|
9362
|
my ($self, %params) = @_; |
|
453
|
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
croak "PDF::Create - new_outline(): Missing required key [Title]." |
|
455
|
34
|
50
|
|
|
|
6241
|
unless (exists $params{'Title'}); |
|
456
|
|
|
|
|
|
|
croak "PDF::Create - new_outline(): Required key [Title] undefined." |
|
457
|
34
|
50
|
|
|
|
6426
|
unless (defined $params{'Title'}); |
|
458
|
|
|
|
|
|
|
|
|
459
|
34
|
100
|
|
|
|
6568
|
if (defined $params{Destination}) { |
|
460
|
|
|
|
|
|
|
croak "PDF::Create - new_outline(): Invalid value for key [Destination]." |
|
461
|
14
|
50
|
|
|
|
3905
|
unless (ref($params{Destination}) eq 'PDF::Create::Page'); |
|
462
|
|
|
|
|
|
|
} |
|
463
|
|
|
|
|
|
|
|
|
464
|
34
|
100
|
|
|
|
6534
|
if (defined $params{Parent}) { |
|
465
|
|
|
|
|
|
|
croak "PDF::Create - new_outline(): Invalid value for key [Parent]." |
|
466
|
18
|
50
|
|
|
|
6724
|
unless (ref($params{Parent}) eq 'PDF::Create::Outline'); |
|
467
|
|
|
|
|
|
|
} |
|
468
|
|
|
|
|
|
|
|
|
469
|
34
|
100
|
|
|
|
6305
|
unless ( defined $self->{'outlines'} ) { |
|
470
|
9
|
|
|
|
|
1922
|
$self->{'outlines'} = PDF::Create::Outline->new(); |
|
471
|
|
|
|
|
|
|
# circular reference |
|
472
|
9
|
|
|
|
|
1880
|
$self->{'outlines'}->{'pdf'} = $self; |
|
473
|
9
|
|
|
|
|
1917
|
weaken $self->{'outlines'}->{'pdf'}; |
|
474
|
9
|
|
|
|
|
3837
|
$self->{'outlines'}->{'Status'} = 'opened'; |
|
475
|
|
|
|
|
|
|
} |
|
476
|
|
|
|
|
|
|
|
|
477
|
34
|
|
66
|
|
|
6379
|
my $parent = $params{'Parent'} || $self->{'outlines'}; |
|
478
|
34
|
|
|
|
|
6529
|
my $name = "Outline " . ++$self->{'outline_count'}; |
|
479
|
34
|
100
|
|
|
|
6307
|
$params{'Destination'} = $self->{'current_page'} unless defined $params{'Destination'}; |
|
480
|
34
|
|
|
|
|
6287
|
my $outline = $parent->add( $self->reserve( $name, "Outline" ), $name, %params ); |
|
481
|
34
|
|
|
|
|
18143
|
$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
|
4576
|
my ($self, $name) = @_; |
|
497
|
|
|
|
|
|
|
|
|
498
|
28
|
|
|
|
|
418
|
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
|
|
|
|
61
|
if (defined $name) { |
|
516
|
28
|
|
|
|
|
49
|
$name = uc($name); |
|
517
|
|
|
|
|
|
|
# validate page size |
|
518
|
28
|
100
|
|
|
|
165
|
croak "Invalid page size name '$name' received." unless (exists $pagesizes{$name}); |
|
519
|
|
|
|
|
|
|
} |
|
520
|
|
|
|
|
|
|
else { |
|
521
|
0
|
|
|
|
|
0
|
$name = 'A4'; |
|
522
|
|
|
|
|
|
|
} |
|
523
|
|
|
|
|
|
|
|
|
524
|
27
|
|
|
|
|
140
|
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
|
4
|
my ($self, $v) = @_; |
|
535
|
|
|
|
|
|
|
|
|
536
|
5
|
50
|
|
|
|
8
|
if (defined $v) { |
|
537
|
5
|
100
|
|
|
|
230
|
croak "ERROR: Invalid version number $v received.\n" |
|
538
|
|
|
|
|
|
|
unless ($v =~ /^1\.[0,1,2,3]$/); |
|
539
|
3
|
|
|
|
|
6
|
$self->{'version'} = $v; |
|
540
|
|
|
|
|
|
|
} |
|
541
|
3
|
|
|
|
|
4
|
$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
|
2498
|
my ($self, %params) = @_; |
|
558
|
|
|
|
|
|
|
|
|
559
|
15
|
|
|
|
|
999
|
debug( 2, "Closing PDF" ); |
|
560
|
15
|
|
|
|
|
929
|
my $raw_data = $self->flush; |
|
561
|
|
|
|
|
|
|
|
|
562
|
15
|
100
|
66
|
|
|
1042
|
if (defined $self->{'fh'} && defined $self->{'filename'}) { |
|
563
|
14
|
|
|
|
|
1082
|
$self->{'fh'}->close; |
|
564
|
|
|
|
|
|
|
} |
|
565
|
|
|
|
|
|
|
|
|
566
|
15
|
|
|
|
|
10312
|
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
|
1077
|
my ($self) = @_; |
|
577
|
|
|
|
|
|
|
|
|
578
|
15
|
|
|
|
|
950
|
debug( 2, "Flushing PDF" ); |
|
579
|
15
|
|
|
|
|
987
|
$self->page_stream; |
|
580
|
15
|
100
|
|
|
|
883
|
$self->add_outlines if defined $self->{'outlines'}; |
|
581
|
15
|
|
|
|
|
983
|
$self->add_catalog; |
|
582
|
15
|
|
|
|
|
909
|
$self->add_pages; |
|
583
|
15
|
|
|
|
|
997
|
$self->add_info; |
|
584
|
15
|
|
|
|
|
1271
|
$self->add_crossrefsection; |
|
585
|
15
|
|
|
|
|
1086
|
$self->add_trailer; |
|
586
|
|
|
|
|
|
|
|
|
587
|
15
|
|
|
|
|
1889
|
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
|
22916
|
my ($self, $name, $type) = @_;; |
|
598
|
|
|
|
|
|
|
|
|
599
|
227
|
100
|
|
|
|
22641
|
$type = $name unless defined $type; |
|
600
|
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
confess "Error: an object has already been reserved using this name '$name' " |
|
602
|
227
|
50
|
|
|
|
23621
|
if defined $self->{'reservations'}{$name}; |
|
603
|
227
|
|
|
|
|
22871
|
$self->{'object_number'}++; |
|
604
|
227
|
|
|
|
|
23505
|
debug( 2, "reserve(): name=$name type=$type number=$self->{'object_number'} generation=$self->{'generation_number'}" ); |
|
605
|
227
|
|
|
|
|
23031
|
$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
|
|
|
|
22835
|
if ($type eq 'Annotation') { |
|
613
|
2
|
|
|
|
|
4
|
$self->{'Annots'}{ $self->{'object_number'} } = $self->{'generation_number'}; |
|
614
|
|
|
|
|
|
|
} |
|
615
|
|
|
|
|
|
|
|
|
616
|
227
|
|
|
|
|
46143
|
[ $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
|
2305
|
my ($self, $comment) = @_; |
|
630
|
|
|
|
|
|
|
|
|
631
|
7
|
50
|
|
|
|
25
|
$comment = '' unless defined $comment; |
|
632
|
7
|
|
|
|
|
35
|
debug( 2, "add_comment(): $comment" ); |
|
633
|
7
|
|
|
|
|
23
|
$self->add( "%" . $comment ); |
|
634
|
7
|
|
|
|
|
15
|
$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
|
10
|
my ($self, %params) = @_; |
|
678
|
|
|
|
|
|
|
|
|
679
|
2
|
|
|
|
|
6
|
debug( 2, "annotation(): Subtype=$params{'Subtype'}" ); |
|
680
|
|
|
|
|
|
|
|
|
681
|
2
|
50
|
|
|
|
6
|
if ( $params{'Subtype'} eq 'Link' ) { |
|
682
|
2
|
50
|
|
|
|
5
|
confess "Must specify 'URI' for Link" unless defined $params{'URI'}; |
|
683
|
2
|
50
|
|
|
|
3
|
confess "Must specify 'x' for Link" unless defined $params{'x'}; |
|
684
|
2
|
50
|
|
|
|
7
|
confess "Must specify 'y' for Link" unless defined $params{'y'}; |
|
685
|
2
|
50
|
|
|
|
4
|
confess "Must specify 'w' for Link" unless defined $params{'w'}; |
|
686
|
2
|
50
|
|
|
|
3
|
confess "Must specify 'h' for Link" unless defined $params{'h'}; |
|
687
|
|
|
|
|
|
|
|
|
688
|
2
|
|
|
|
|
2
|
my $num = 1 + scalar keys %{ $self->{'annotations'} }; |
|
|
2
|
|
|
|
|
5
|
|
|
689
|
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
my $action = { |
|
691
|
|
|
|
|
|
|
'Type' => $self->name('Action'), |
|
692
|
|
|
|
|
|
|
'S' => $self->name('URI'), |
|
693
|
2
|
|
|
|
|
4
|
'URI' => $self->string( $params{'URI'} ), |
|
694
|
|
|
|
|
|
|
}; |
|
695
|
2
|
|
|
|
|
3
|
my $x2 = $params{'x'} + $params{'w'}; |
|
696
|
2
|
|
|
|
|
3
|
my $y2 = $params{'y'} + $params{'h'}; |
|
697
|
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
$self->{'annotations'}{$num} = { |
|
699
|
|
|
|
|
|
|
'Subtype' => $self->name('Link'), |
|
700
|
2
|
|
|
|
|
3
|
'Rect' => $self->verbatim( sprintf "[%f %f %f %f]", $params{'x'}, $params{'y'}, $x2, $y2 ), |
|
701
|
|
|
|
|
|
|
'A' => $self->dictionary(%$action), |
|
702
|
|
|
|
|
|
|
}; |
|
703
|
|
|
|
|
|
|
|
|
704
|
2
|
50
|
|
|
|
7
|
if ( defined $params{'Border'} ) { |
|
705
|
|
|
|
|
|
|
$self->{'annotations'}{$num}{'Border'} = |
|
706
|
2
|
|
|
|
|
12
|
$self->verbatim( sprintf "[%f %f %f]", $params{'Border'}[0], $params{'Border'}[1], $params{'Border'}[2] ); |
|
707
|
|
|
|
|
|
|
} |
|
708
|
2
|
|
|
|
|
5
|
$self->{'annot'}{$num}{'page_name'} = "Page " . $self->{'page_count'}; |
|
709
|
2
|
|
|
|
|
7
|
debug( 2, "annotation(): annotation number: $num, page name: $self->{'annot'}{$num}{'page_name'}" ); |
|
710
|
2
|
|
|
|
|
10
|
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
|
5
|
my ($self, $filename) = @_; |
|
747
|
|
|
|
|
|
|
|
|
748
|
2
|
|
|
|
|
3
|
my $num = 1 + scalar keys %{ $self->{'xobjects'} }; |
|
|
2
|
|
|
|
|
4
|
|
|
749
|
|
|
|
|
|
|
|
|
750
|
2
|
|
|
|
|
3
|
my $image; |
|
751
|
|
|
|
|
|
|
my $colorspace; |
|
752
|
0
|
|
|
|
|
0
|
my @a; |
|
753
|
|
|
|
|
|
|
|
|
754
|
2
|
100
|
33
|
|
|
13
|
if ( $filename =~ /\.gif$/i ) { |
|
|
|
50
|
|
|
|
|
|
|
755
|
1
|
|
|
|
|
7
|
$self->{'images'}{$num} = PDF::Image::GIF->new(); |
|
756
|
|
|
|
|
|
|
} elsif ( $filename =~ /\.jpg$/i || $filename =~ /\.jpeg$/i ) { |
|
757
|
1
|
|
|
|
|
6
|
$self->{'images'}{$num} = PDF::Image::JPEG->new(); |
|
758
|
|
|
|
|
|
|
} |
|
759
|
|
|
|
|
|
|
|
|
760
|
2
|
|
|
|
|
2
|
$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
|
|
|
|
10
|
if ($image->{colorspacesize}) { |
|
779
|
1
|
|
|
|
|
21
|
$colorspace = $self->reserve("ImageColorSpace$num"); |
|
780
|
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
$self->{'xobjects_colorspace'}{$num} = { |
|
782
|
|
|
|
|
|
|
'Data' => $image->{colorspacedata}, |
|
783
|
1
|
|
|
|
|
4
|
'Length' => $self->number( $image->{colorspacesize} ), |
|
784
|
|
|
|
|
|
|
}; |
|
785
|
|
|
|
|
|
|
|
|
786
|
1
|
|
|
|
|
6
|
$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
|
|
|
|
|
9
|
$#a = -1; |
|
794
|
2
|
|
|
|
|
3
|
foreach my $s ( @{ $image->{filter} } ) { |
|
|
2
|
|
|
|
|
7
|
|
|
795
|
2
|
|
|
|
|
5
|
push @a, $self->name($s); |
|
796
|
|
|
|
|
|
|
} |
|
797
|
2
|
50
|
|
|
|
5
|
if ( $#a >= 0 ) { |
|
798
|
2
|
|
|
|
|
6
|
$self->{'xobjects'}{$num}->{'Filter'} = $self->array(@a); |
|
799
|
|
|
|
|
|
|
} |
|
800
|
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
# Set additional DecodeParms |
|
802
|
2
|
|
|
|
|
4
|
$#a = -1; |
|
803
|
2
|
|
|
|
|
2
|
foreach my $s ( keys %{ $image->{decodeparms} } ) { |
|
|
2
|
|
|
|
|
8
|
|
|
804
|
1
|
|
|
|
|
2
|
push @a, $s; |
|
805
|
1
|
|
|
|
|
4
|
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
|
|
|
|
7
|
if ( $image->{transparent} ) { |
|
811
|
1
|
|
|
|
|
4
|
$self->{'xobjects'}{$num}->{'Mask'} = $self->array( $self->number( $image->{mask} ), $self->number( $image->{mask} ) ); |
|
812
|
|
|
|
|
|
|
} |
|
813
|
|
|
|
|
|
|
|
|
814
|
2
|
|
|
|
|
18
|
return { 'num' => $num, 'width' => $image->{width}, 'height' => $image->{height} }; |
|
815
|
|
|
|
|
|
|
} |
|
816
|
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
sub add_outlines { |
|
818
|
5
|
|
|
5
|
0
|
910
|
my ($self, %params) = @_; |
|
819
|
|
|
|
|
|
|
|
|
820
|
5
|
|
|
|
|
935
|
debug( 2, "add_outlines" ); |
|
821
|
5
|
|
|
|
|
825
|
my $outlines = $self->reserve("Outlines"); |
|
822
|
|
|
|
|
|
|
|
|
823
|
5
|
|
|
|
|
893
|
my ($First, $Last); |
|
824
|
5
|
|
|
|
|
896
|
my @list = $self->{'outlines'}->list; |
|
825
|
5
|
|
|
|
|
829
|
my $i = -1; |
|
826
|
5
|
|
|
|
|
825
|
for my $outline (@list) { |
|
827
|
30
|
|
|
|
|
5877
|
$i++; |
|
828
|
30
|
|
|
|
|
5579
|
my $name = $outline->{'name'}; |
|
829
|
30
|
100
|
|
|
|
5700
|
$First = $outline->{'id'} unless defined $First; |
|
830
|
30
|
|
|
|
|
5813
|
$Last = $outline->{'id'}; |
|
831
|
30
|
|
|
|
|
5707
|
my $content = { 'Title' => $self->string( $outline->{'Title'} ) }; |
|
832
|
30
|
100
|
50
|
|
|
5801
|
if ( defined $outline->{'Kids'} && scalar @{ $outline->{'Kids'} } ) { |
|
|
30
|
|
|
|
|
11346
|
|
|
833
|
9
|
|
|
|
|
1864
|
my $t = $outline->{'Kids'}; |
|
834
|
9
|
|
|
|
|
1771
|
$$content{'First'} = $self->indirect_ref( @{ $$t[0]->{'id'} } ); |
|
|
9
|
|
|
|
|
3582
|
|
|
835
|
9
|
|
|
|
|
1860
|
$$content{'Last'} = $self->indirect_ref( @{ $$t[$#$t]->{'id'} } ); |
|
|
9
|
|
|
|
|
3641
|
|
|
836
|
|
|
|
|
|
|
} |
|
837
|
30
|
|
|
|
|
5836
|
my $brothers = $outline->{'Parent'}->{'Kids'}; |
|
838
|
30
|
|
|
|
|
5548
|
my $j = -1; |
|
839
|
30
|
|
|
|
|
5720
|
for my $brother (@$brothers) { |
|
840
|
53
|
|
|
|
|
9895
|
$j++; |
|
841
|
53
|
100
|
|
|
|
15311
|
last if $brother == $outline; |
|
842
|
|
|
|
|
|
|
} |
|
843
|
30
|
100
|
|
|
|
5933
|
$$content{'Next'} = $self->indirect_ref( @{ $$brothers[ $j + 1 ]->{'id'} } ) |
|
|
16
|
|
|
|
|
5541
|
|
|
844
|
|
|
|
|
|
|
if $j < $#$brothers; |
|
845
|
30
|
100
|
|
|
|
5722
|
$$content{'Prev'} = $self->indirect_ref( @{ $$brothers[ $j - 1 ]->{'id'} } ) |
|
|
16
|
|
|
|
|
5772
|
|
|
846
|
|
|
|
|
|
|
if $j; |
|
847
|
|
|
|
|
|
|
$outline->{'Parent'}->{'id'} = $outlines |
|
848
|
30
|
100
|
|
|
|
5743
|
unless defined $outline->{'Parent'}->{'id'}; |
|
849
|
30
|
|
|
|
|
5734
|
$$content{'Parent'} = $self->indirect_ref( @{ $outline->{'Parent'}->{'id'} } ); |
|
|
30
|
|
|
|
|
11200
|
|
|
850
|
|
|
|
|
|
|
$$content{'Dest'} = |
|
851
|
30
|
|
|
|
|
6057
|
$self->array( $self->indirect_ref( @{ $outline->{'Dest'}->{'id'} } ), |
|
|
30
|
|
|
|
|
12035
|
|
|
852
|
|
|
|
|
|
|
$self->name('Fit'), $self->null, $self->null, $self->null ); |
|
853
|
30
|
|
|
|
|
5919
|
my $count = $outline->count; |
|
854
|
30
|
100
|
|
|
|
6302
|
$$content{'Count'} = $self->number($count) if $count; |
|
855
|
30
|
|
|
|
|
5924
|
my $t = $self->add_object( $self->indirect_obj( $self->dictionary(%$content), $name ) ); |
|
856
|
30
|
|
|
|
|
5779
|
$self->cr; |
|
857
|
|
|
|
|
|
|
} |
|
858
|
|
|
|
|
|
|
|
|
859
|
|
|
|
|
|
|
# Type (required) |
|
860
|
5
|
|
|
|
|
873
|
my $content = { 'Type' => $self->name('Outlines') }; |
|
861
|
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
# Count |
|
863
|
5
|
|
|
|
|
966
|
my $count = $self->{'outlines'}->count; |
|
864
|
5
|
50
|
|
|
|
925
|
$$content{'Count'} = $self->number($count) if $count; |
|
865
|
5
|
|
|
|
|
907
|
$$content{'First'} = $self->indirect_ref(@$First); |
|
866
|
5
|
|
|
|
|
946
|
$$content{'Last'} = $self->indirect_ref(@$Last); |
|
867
|
5
|
|
|
|
|
929
|
$self->add_object( $self->indirect_obj( $self->dictionary(%$content) ) ); |
|
868
|
5
|
|
|
|
|
909
|
$self->cr; |
|
869
|
|
|
|
|
|
|
} |
|
870
|
|
|
|
|
|
|
|
|
871
|
|
|
|
|
|
|
sub add_pages { |
|
872
|
15
|
|
|
15
|
0
|
885
|
my ($self) = @_; |
|
873
|
|
|
|
|
|
|
|
|
874
|
15
|
|
|
|
|
919
|
debug( 2, "add_pages():" ); |
|
875
|
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
# Type (required) |
|
877
|
15
|
|
|
|
|
891
|
my $content = { 'Type' => $self->name('Pages') }; |
|
878
|
|
|
|
|
|
|
|
|
879
|
|
|
|
|
|
|
# Kids (required) |
|
880
|
15
|
|
|
|
|
939
|
my $t = $self->{'pages'}->kids; |
|
881
|
15
|
50
|
|
|
|
913
|
confess "Error: document MUST contains at least one page. Abort." |
|
882
|
|
|
|
|
|
|
unless scalar @$t; |
|
883
|
|
|
|
|
|
|
|
|
884
|
15
|
|
|
|
|
904
|
my $kids = []; |
|
885
|
15
|
|
|
|
|
920
|
map { push @$kids, $self->indirect_ref(@$_) } @$t; |
|
|
15
|
|
|
|
|
905
|
|
|
886
|
15
|
|
|
|
|
903
|
$$content{'Kids'} = $self->array(@$kids); |
|
887
|
15
|
|
|
|
|
942
|
$$content{'Count'} = $self->number( $self->{'pages'}->count ); |
|
888
|
15
|
|
|
|
|
933
|
$self->add_object( $self->indirect_obj( $self->dictionary(%$content) ) ); |
|
889
|
15
|
|
|
|
|
933
|
$self->cr; |
|
890
|
|
|
|
|
|
|
|
|
891
|
15
|
|
|
|
|
934
|
for my $font ( sort keys %{ $self->{'fonts'} } ) { |
|
|
15
|
|
|
|
|
1878
|
|
|
892
|
34
|
|
|
|
|
1946
|
debug( 2, "add_pages(): font: $font" ); |
|
893
|
34
|
|
|
|
|
1812
|
$self->{'fontobj'}{$font} = $self->reserve('Font'); |
|
894
|
34
|
|
|
|
|
1824
|
$self->add_object( $self->indirect_obj( $self->dictionary( %{ $self->{'fonts'}{$font} } ), 'Font' ) ); |
|
|
34
|
|
|
|
|
3853
|
|
|
895
|
34
|
|
|
|
|
1960
|
$self->cr; |
|
896
|
|
|
|
|
|
|
} |
|
897
|
|
|
|
|
|
|
|
|
898
|
15
|
|
|
|
|
901
|
for my $xobject (sort keys %{$self->{'xobjects'}}) { |
|
|
15
|
|
|
|
|
1850
|
|
|
899
|
2
|
|
|
|
|
5
|
debug( 2, "add_pages(): xobject: $xobject" ); |
|
900
|
2
|
|
|
|
|
3
|
$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
|
|
|
|
|
9
|
$self->cr; |
|
903
|
|
|
|
|
|
|
|
|
904
|
2
|
100
|
|
|
|
6
|
if ( defined $self->{'reservations'}{"ImageColorSpace$xobject"}) { |
|
905
|
|
|
|
|
|
|
$self->add_object( |
|
906
|
1
|
|
|
|
|
2
|
$self->indirect_obj( $self->stream( %{ $self->{'xobjects_colorspace'}{$xobject} } ), "ImageColorSpace$xobject" ) ); |
|
|
1
|
|
|
|
|
5
|
|
|
907
|
1
|
|
|
|
|
4
|
$self->cr; |
|
908
|
|
|
|
|
|
|
} |
|
909
|
|
|
|
|
|
|
} |
|
910
|
|
|
|
|
|
|
|
|
911
|
15
|
|
|
|
|
951
|
for my $annotation (sort keys %{$self->{'annotations'}}) { |
|
|
15
|
|
|
|
|
1814
|
|
|
912
|
2
|
|
|
|
|
4
|
$self->{'annot'}{$annotation}{'object_info'} = $self->reserve('Annotation'); |
|
913
|
2
|
|
|
|
|
2
|
$self->add_object( $self->indirect_obj( $self->dictionary( %{ $self->{'annotations'}{$annotation} } ), 'Annotation' ) ); |
|
|
2
|
|
|
|
|
7
|
|
|
914
|
2
|
|
|
|
|
6
|
$self->cr; |
|
915
|
|
|
|
|
|
|
} |
|
916
|
|
|
|
|
|
|
|
|
917
|
15
|
|
|
|
|
964
|
for my $page ($self->{'pages'}->list) { |
|
918
|
38
|
|
|
|
|
2813
|
my $name = $page->{'name'}; |
|
919
|
38
|
|
|
|
|
2794
|
debug( 2, "add_pages: page: $name" ); |
|
920
|
38
|
100
|
50
|
|
|
2824
|
my $type = 'Page' . ( defined $page->{'Kids'} && scalar @{ $page->{'Kids'} } ? 's' : '' ); |
|
921
|
|
|
|
|
|
|
|
|
922
|
|
|
|
|
|
|
# Type (required) |
|
923
|
38
|
|
|
|
|
2810
|
my $content = { 'Type' => $self->name($type) }; |
|
924
|
|
|
|
|
|
|
|
|
925
|
|
|
|
|
|
|
# Resources (required, may be inherited). See page 195. |
|
926
|
38
|
|
|
|
|
2798
|
my $resources = {}; |
|
927
|
38
|
|
|
|
|
2735
|
for my $k ( keys %{ $page->{'resources'} } ) { |
|
|
38
|
|
|
|
|
5542
|
|
|
928
|
39
|
|
|
|
|
1819
|
my $v = $page->{'resources'}{$k}; |
|
929
|
|
|
|
|
|
|
( $k eq 'ProcSet' ) && do { |
|
930
|
19
|
|
|
|
|
926
|
my $l = []; |
|
931
|
19
|
50
|
|
|
|
946
|
if ( ref($v) eq 'ARRAY' ) { |
|
932
|
19
|
|
|
|
|
914
|
map { push @$l, $self->name($_) } @$v; |
|
|
38
|
|
|
|
|
1856
|
|
|
933
|
|
|
|
|
|
|
} else { |
|
934
|
0
|
|
|
|
|
0
|
push @$l, $self->name($v); |
|
935
|
|
|
|
|
|
|
} |
|
936
|
19
|
|
|
|
|
920
|
$$resources{'ProcSet'} = $self->array(@$l); |
|
937
|
|
|
|
|
|
|
} |
|
938
|
|
|
|
|
|
|
|| ( $k eq 'fonts' ) && do { |
|
939
|
19
|
|
|
|
|
913
|
my $l = {}; |
|
940
|
19
|
|
|
|
|
981
|
map { $$l{"F$_"} = $self->indirect_ref( @{ $self->{'fontobj'}{$_} } ); } keys %{ $page->{'resources'}{'fonts'} }; |
|
|
37
|
|
|
|
|
1801
|
|
|
|
37
|
|
|
|
|
3672
|
|
|
|
19
|
|
|
|
|
1820
|
|
|
941
|
19
|
|
|
|
|
961
|
$$resources{'Font'} = $self->dictionary(%$l); |
|
942
|
|
|
|
|
|
|
} |
|
943
|
39
|
100
|
33
|
|
|
1935
|
|| ( $k eq 'xobjects' ) && do { |
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
944
|
1
|
|
|
|
|
1
|
my $l = {}; |
|
945
|
2
|
|
|
|
|
82
|
map { $$l{"Image$_"} = $self->indirect_ref( @{ $self->{'xobj'}{$_} } ); } |
|
|
2
|
|
|
|
|
4
|
|
|
946
|
1
|
|
|
|
|
1
|
keys %{ $page->{'resources'}{'xobjects'} }; |
|
|
1
|
|
|
|
|
3
|
|
|
947
|
1
|
|
|
|
|
4
|
$$resources{'XObject'} = $self->dictionary(%$l); |
|
948
|
|
|
|
|
|
|
}; |
|
949
|
|
|
|
|
|
|
} |
|
950
|
38
|
50
|
|
|
|
2810
|
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
|
|
|
|
2775
|
if ( defined( $$resources{'XObject'} ) ) { |
|
956
|
1
|
|
|
|
|
3
|
my $r = $self->add_object( $self->indirect_obj( $self->dictionary(%$resources) ) ); |
|
957
|
1
|
|
|
|
|
4
|
$self->cr; |
|
958
|
1
|
|
|
|
|
3
|
$$content{'Resources'} = [ 'ref', [ $$r[0], $$r[1] ] ]; |
|
959
|
|
|
|
|
|
|
} else { |
|
960
|
37
|
100
|
|
|
|
4612
|
$$content{'Resources'} = $self->dictionary(%$resources) |
|
961
|
|
|
|
|
|
|
if scalar keys %$resources; |
|
962
|
|
|
|
|
|
|
} |
|
963
|
38
|
|
|
|
|
2759
|
for my $K ( 'MediaBox', 'CropBox', 'ArtBox', 'TrimBox', 'BleedBox' ) { |
|
964
|
190
|
|
|
|
|
13763
|
my $k = lc $K; |
|
965
|
190
|
100
|
|
|
|
16574
|
if ( defined $page->{$k} ) { |
|
966
|
15
|
|
|
|
|
937
|
my $l = []; |
|
967
|
15
|
|
|
|
|
901
|
map { push @$l, $self->number($_) } @{ $page->{$k} }; |
|
|
60
|
|
|
|
|
3701
|
|
|
|
15
|
|
|
|
|
1775
|
|
|
968
|
15
|
|
|
|
|
924
|
$$content{$K} = $self->array(@$l); |
|
969
|
|
|
|
|
|
|
} |
|
970
|
|
|
|
|
|
|
} |
|
971
|
38
|
50
|
|
|
|
2750
|
$$content{'Rotate'} = $self->number( $page->{'rotate'} ) if defined $page->{'rotate'}; |
|
972
|
38
|
100
|
|
|
|
2738
|
if ( $type eq 'Page' ) { |
|
973
|
24
|
|
|
|
|
1891
|
$$content{'Parent'} = $self->indirect_ref( @{ $page->{'Parent'}{'id'} } ); |
|
|
24
|
|
|
|
|
3775
|
|
|
974
|
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
# Content |
|
976
|
24
|
100
|
|
|
|
1912
|
if ( defined $page->{'contents'} ) { |
|
977
|
23
|
|
|
|
|
2150
|
my $contents = []; |
|
978
|
23
|
|
|
|
|
1887
|
map { push @$contents, $self->indirect_ref(@$_); } @{ $page->{'contents'} }; |
|
|
27
|
|
|
|
|
2793
|
|
|
|
23
|
|
|
|
|
3716
|
|
|
979
|
23
|
|
|
|
|
1869
|
$$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
|
|
|
|
3783
|
if ( defined $self->{'annot'} ) { |
|
986
|
1
|
|
|
|
|
2
|
my $Annots = '[ '; |
|
987
|
1
|
|
|
|
|
1
|
my $is_annots = 0; |
|
988
|
1
|
|
|
|
|
1
|
foreach my $annot_number ( keys %{ $self->{'annot'} } ) { |
|
|
1
|
|
|
|
|
2
|
|
|
989
|
2
|
50
|
|
|
|
9
|
next if ( $self->{'annot'}{$annot_number}{'page_name'} ne $name ); |
|
990
|
2
|
|
|
|
|
2
|
$is_annots = 1; |
|
991
|
2
|
|
|
|
|
8
|
debug( 2, |
|
992
|
|
|
|
|
|
|
sprintf "annotation number: $annot_number, page name: $self->{'annot'}{$annot_number}{'page_name'}" ); |
|
993
|
2
|
|
|
|
|
4
|
my $object_number = $self->{'annot'}{$annot_number}{'object_info'}[0]; |
|
994
|
2
|
|
|
|
|
2
|
my $generation_number = $self->{'annot'}{$annot_number}{'object_info'}[1]; |
|
995
|
2
|
|
|
|
|
5
|
debug( 2, sprintf "object_number: $object_number, generation_number: $generation_number" ); |
|
996
|
2
|
|
|
|
|
6
|
$Annots .= sprintf( "%s %s R ", $object_number, $generation_number ); |
|
997
|
|
|
|
|
|
|
} |
|
998
|
1
|
50
|
|
|
|
4
|
$$content{'Annots'} = $self->verbatim( $Annots . ']' ) if ($is_annots); |
|
999
|
|
|
|
|
|
|
} |
|
1000
|
|
|
|
|
|
|
} else { |
|
1001
|
14
|
|
|
|
|
931
|
my $kids = []; |
|
1002
|
14
|
|
|
|
|
945
|
map { push @$kids, $self->indirect_ref(@$_) } @{ $page->kids }; |
|
|
23
|
|
|
|
|
1841
|
|
|
|
14
|
|
|
|
|
928
|
|
|
1003
|
14
|
|
|
|
|
996
|
$$content{'Kids'} = $self->array(@$kids); |
|
1004
|
14
|
|
|
|
|
1843
|
$$content{'Parent'} = $self->indirect_ref( @{ $page->{'Parent'}{'id'} } ) |
|
1005
|
14
|
50
|
|
|
|
925
|
if defined $page->{'Parent'}; |
|
1006
|
14
|
|
|
|
|
963
|
$$content{'Count'} = $self->number( $page->count ); |
|
1007
|
|
|
|
|
|
|
} |
|
1008
|
38
|
|
|
|
|
2889
|
$self->add_object( $self->indirect_obj( $self->dictionary(%$content), $name ) ); |
|
1009
|
38
|
|
|
|
|
2873
|
$self->cr; |
|
1010
|
|
|
|
|
|
|
} |
|
1011
|
|
|
|
|
|
|
} |
|
1012
|
|
|
|
|
|
|
|
|
1013
|
|
|
|
|
|
|
sub add_crossrefsection { |
|
1014
|
15
|
|
|
15
|
0
|
1000
|
my ($self) = @_; |
|
1015
|
|
|
|
|
|
|
|
|
1016
|
15
|
|
|
|
|
946
|
debug( 2, "add_crossrefsection():" ); |
|
1017
|
|
|
|
|
|
|
|
|
1018
|
|
|
|
|
|
|
# ::= |
|
1019
|
|
|
|
|
|
|
# xref |
|
1020
|
|
|
|
|
|
|
# + |
|
1021
|
15
|
|
|
|
|
997
|
$self->{'crossrefstartpoint'} = $self->position; |
|
1022
|
15
|
|
|
|
|
996
|
$self->add('xref'); |
|
1023
|
15
|
|
|
|
|
951
|
$self->cr; |
|
1024
|
|
|
|
|
|
|
confess "Fatal error: should contains at least one cross reference subsection." |
|
1025
|
15
|
50
|
|
|
|
1055
|
unless defined $self->{'crossrefsubsection'}; |
|
1026
|
15
|
|
|
|
|
950
|
for my $subsection ( sort keys %{ $self->{'crossrefsubsection'} } ) { |
|
|
15
|
|
|
|
|
1895
|
|
|
1027
|
15
|
|
|
|
|
1061
|
$self->add_crossrefsubsection($subsection); |
|
1028
|
|
|
|
|
|
|
} |
|
1029
|
|
|
|
|
|
|
} |
|
1030
|
|
|
|
|
|
|
|
|
1031
|
|
|
|
|
|
|
sub add_crossrefsubsection { |
|
1032
|
15
|
|
|
15
|
0
|
949
|
my ($self, $subsection) = @_; |
|
1033
|
|
|
|
|
|
|
|
|
1034
|
15
|
|
|
|
|
976
|
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
|
|
|
|
|
933
|
$self->add( 0, ' ', 1 + scalar @{ $self->{'crossrefsubsection'}{$subsection} } ); |
|
|
15
|
|
|
|
|
1933
|
|
|
1054
|
15
|
|
|
|
|
979
|
$self->cr; |
|
1055
|
15
|
|
|
|
|
957
|
$self->add( sprintf "%010d %05d %s ", 0, 65535, 'f' ); |
|
1056
|
15
|
|
|
|
|
928
|
$self->cr; |
|
1057
|
15
|
|
|
|
|
921
|
for my $entry ( sort { $$a[0] <=> $$b[0] } @{ $self->{'crossrefsubsection'}{$subsection} } ) { |
|
|
551
|
|
|
|
|
119592
|
|
|
|
15
|
|
|
|
|
1967
|
|
|
1058
|
212
|
50
|
|
|
|
20583
|
$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
|
|
|
|
|
19880
|
$self->cr; |
|
1062
|
|
|
|
|
|
|
} |
|
1063
|
|
|
|
|
|
|
} |
|
1064
|
|
|
|
|
|
|
|
|
1065
|
|
|
|
|
|
|
sub add_trailer { |
|
1066
|
15
|
|
|
15
|
0
|
999
|
my $self = shift; |
|
1067
|
|
|
|
|
|
|
|
|
1068
|
15
|
|
|
|
|
988
|
debug( 2, "add_trailer():" ); |
|
1069
|
|
|
|
|
|
|
|
|
1070
|
|
|
|
|
|
|
# ::= trailer |
|
1071
|
|
|
|
|
|
|
# << |
|
1072
|
|
|
|
|
|
|
# + |
|
1073
|
|
|
|
|
|
|
# >> |
|
1074
|
|
|
|
|
|
|
# startxref |
|
1075
|
|
|
|
|
|
|
# |
|
1076
|
|
|
|
|
|
|
# %%EOF |
|
1077
|
|
|
|
|
|
|
|
|
1078
|
15
|
|
|
|
|
1032
|
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
|
|
|
|
|
1006
|
$self->add('trailer'); |
|
1089
|
15
|
|
|
|
|
984
|
$self->cr; |
|
1090
|
15
|
|
|
|
|
1324
|
$self->add('<<'); |
|
1091
|
15
|
|
|
|
|
1024
|
$self->cr; |
|
1092
|
15
|
|
|
|
|
947
|
$self->{'trailer'}{'Size'} = 1; |
|
1093
|
15
|
|
|
|
|
957
|
map { $self->{'trailer'}{'Size'} += scalar @{ $self->{'crossrefsubsection'}{$_} } } keys %{ $self->{'crossrefsubsection'} }; |
|
|
15
|
|
|
|
|
940
|
|
|
|
15
|
|
|
|
|
2893
|
|
|
|
15
|
|
|
|
|
1880
|
|
|
1094
|
15
|
|
|
|
|
922
|
$self->{'trailer'}{'Root'} = &encode( @{ $self->indirect_ref( @{ $self->{'catalog'} } ) } ); |
|
|
15
|
|
|
|
|
943
|
|
|
|
15
|
|
|
|
|
1892
|
|
|
1095
|
15
|
|
|
|
|
951
|
$self->{'trailer'}{'Info'} = &encode( @{ $self->indirect_ref( @{ $self->{'info'} } ) } ) |
|
|
15
|
|
|
|
|
1833
|
|
|
1096
|
15
|
50
|
|
|
|
1022
|
if defined $self->{'info'}; |
|
1097
|
|
|
|
|
|
|
|
|
1098
|
15
|
|
|
|
|
1001
|
for my $k (@keys) { |
|
1099
|
90
|
100
|
|
|
|
8409
|
next unless defined $self->{'trailer'}{$k}; |
|
1100
|
|
|
|
|
|
|
$self->add( "/$k ", |
|
1101
|
45
|
50
|
|
|
|
2938
|
ref $self->{'trailer'}{$k} eq 'ARRAY' ? join( ' ', @{ $self->{'trailer'}{$k} } ) : $self->{'trailer'}{$k} ); |
|
|
0
|
|
|
|
|
0
|
|
|
1102
|
45
|
|
|
|
|
2875
|
$self->cr; |
|
1103
|
|
|
|
|
|
|
} |
|
1104
|
15
|
|
|
|
|
937
|
$self->add('>>'); |
|
1105
|
15
|
|
|
|
|
928
|
$self->cr; |
|
1106
|
15
|
|
|
|
|
968
|
$self->add('startxref'); |
|
1107
|
15
|
|
|
|
|
957
|
$self->cr; |
|
1108
|
15
|
|
|
|
|
944
|
$self->add( $self->{'crossrefstartpoint'} ); |
|
1109
|
15
|
|
|
|
|
942
|
$self->cr; |
|
1110
|
15
|
|
|
|
|
972
|
$self->add('%%EOF'); |
|
1111
|
15
|
|
|
|
|
934
|
$self->cr; |
|
1112
|
|
|
|
|
|
|
} |
|
1113
|
|
|
|
|
|
|
|
|
1114
|
|
|
|
|
|
|
sub cr { |
|
1115
|
1564
|
|
|
1564
|
0
|
95417
|
my ($self) = @_; |
|
1116
|
|
|
|
|
|
|
|
|
1117
|
1564
|
|
|
|
|
95960
|
debug( 3, "cr():" ); |
|
1118
|
1564
|
|
|
|
|
95879
|
$self->add( &encode('cr') ); |
|
1119
|
|
|
|
|
|
|
} |
|
1120
|
|
|
|
|
|
|
|
|
1121
|
|
|
|
|
|
|
sub page_stream { |
|
1122
|
562
|
|
|
562
|
0
|
5779
|
my ($self, $page) = @_; |
|
1123
|
|
|
|
|
|
|
|
|
1124
|
562
|
|
|
|
|
5921
|
debug( 2, "page_stream():" ); |
|
1125
|
|
|
|
|
|
|
|
|
1126
|
562
|
100
|
|
|
|
6267
|
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
|
|
|
7702
|
&& $self->{'stream_page'} == $page; |
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1133
|
|
|
|
|
|
|
|
|
1134
|
|
|
|
|
|
|
# Remember the position |
|
1135
|
27
|
|
|
|
|
2826
|
my $len = $self->position - $self->{'stream_pos'} + 1; |
|
1136
|
|
|
|
|
|
|
|
|
1137
|
|
|
|
|
|
|
# Close the stream and the object |
|
1138
|
27
|
|
|
|
|
3052
|
$self->cr; |
|
1139
|
27
|
|
|
|
|
2695
|
$self->add('endstream'); |
|
1140
|
27
|
|
|
|
|
2633
|
$self->cr; |
|
1141
|
27
|
|
|
|
|
2705
|
$self->add('endobj'); |
|
1142
|
27
|
|
|
|
|
2741
|
$self->cr; |
|
1143
|
27
|
|
|
|
|
2977
|
$self->cr; |
|
1144
|
|
|
|
|
|
|
|
|
1145
|
|
|
|
|
|
|
# Add the length |
|
1146
|
27
|
|
|
|
|
2811
|
$self->add_object( $self->indirect_obj( $self->number($len), 'stream_length' ) ); |
|
1147
|
27
|
|
|
|
|
2951
|
$self->cr; |
|
1148
|
|
|
|
|
|
|
} |
|
1149
|
|
|
|
|
|
|
|
|
1150
|
|
|
|
|
|
|
# open a new stream if needed |
|
1151
|
42
|
100
|
|
|
|
4730
|
if (defined $page) { |
|
1152
|
|
|
|
|
|
|
|
|
1153
|
|
|
|
|
|
|
# get an object id for the stream |
|
1154
|
27
|
|
|
|
|
2818
|
my $obj = $self->reserve('stream'); |
|
1155
|
|
|
|
|
|
|
|
|
1156
|
|
|
|
|
|
|
# release it |
|
1157
|
27
|
|
|
|
|
2836
|
delete $self->{'reservations'}{'stream'}; |
|
1158
|
|
|
|
|
|
|
|
|
1159
|
|
|
|
|
|
|
# get another one for the length of this stream |
|
1160
|
27
|
|
|
|
|
2642
|
my $stream_length = $self->reserve('stream_length'); |
|
1161
|
27
|
|
|
|
|
2813
|
push @$stream_length, 'R'; |
|
1162
|
27
|
|
|
|
|
2695
|
push @{ $page->{'contents'} }, $obj; |
|
|
27
|
|
|
|
|
5423
|
|
|
1163
|
|
|
|
|
|
|
|
|
1164
|
|
|
|
|
|
|
# write the beginning of the object |
|
1165
|
27
|
|
|
|
|
2767
|
push @{ $self->{'crossrefsubsection'}{ $$obj[1] } }, [ $$obj[0], $self->position, 1 ]; |
|
|
27
|
|
|
|
|
5531
|
|
|
1166
|
27
|
|
|
|
|
2785
|
$self->add("$$obj[0] $$obj[1] obj"); |
|
1167
|
27
|
|
|
|
|
2712
|
$self->cr; |
|
1168
|
27
|
|
|
|
|
3695
|
$self->add('<<'); |
|
1169
|
27
|
|
|
|
|
2795
|
$self->cr; |
|
1170
|
27
|
|
|
|
|
2747
|
$self->add( '/Length ', join( ' ', @$stream_length ) ); |
|
1171
|
27
|
|
|
|
|
2703
|
$self->cr; |
|
1172
|
27
|
|
|
|
|
2920
|
$self->add('>>'); |
|
1173
|
27
|
|
|
|
|
2675
|
$self->cr; |
|
1174
|
27
|
|
|
|
|
2679
|
$self->add('stream'); |
|
1175
|
27
|
|
|
|
|
2653
|
$self->cr; |
|
1176
|
27
|
|
|
|
|
2900
|
$self->{'stream_pos'} = $self->position; |
|
1177
|
27
|
|
|
|
|
8365
|
$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
|
2954
|
my ($self, $page, $font) = @_; |
|
1195
|
|
|
|
|
|
|
|
|
1196
|
86
|
|
|
|
|
2897
|
$page->{'resources'}{'fonts'}{$font} = 1; |
|
1197
|
86
|
|
|
|
|
2934
|
$page->{'resources'}{'ProcSet'} = [ 'PDF', 'Text' ]; |
|
1198
|
86
|
|
|
|
|
5622
|
$self->{'fontobj'}{$font} = 1; |
|
1199
|
|
|
|
|
|
|
} |
|
1200
|
|
|
|
|
|
|
|
|
1201
|
|
|
|
|
|
|
sub uses_xobject { |
|
1202
|
2
|
|
|
2
|
0
|
4
|
my ($self, $page, $xobject) = @_; |
|
1203
|
|
|
|
|
|
|
|
|
1204
|
2
|
|
|
|
|
4
|
$page->{'resources'}{'xobjects'}{$xobject} = 1; |
|
1205
|
2
|
|
|
|
|
6
|
$page->{'resources'}{'ProcSet'} = [ 'PDF', 'Text' ]; |
|
1206
|
2
|
|
|
|
|
7
|
$self->{'xobj'}{$xobject} = 1; |
|
1207
|
|
|
|
|
|
|
} |
|
1208
|
|
|
|
|
|
|
|
|
1209
|
|
|
|
|
|
|
sub debug { |
|
1210
|
9204
|
|
|
9204
|
0
|
703014
|
my ($level, $msg) = @_; |
|
1211
|
|
|
|
|
|
|
|
|
1212
|
9204
|
50
|
|
|
|
1918047
|
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
|
171180
|
my $self = shift; |
|
1220
|
2924
|
|
|
|
|
172706
|
my $data = join '', @_; |
|
1221
|
|
|
|
|
|
|
|
|
1222
|
2924
|
|
|
|
|
172418
|
$self->{'size'} += length $data; |
|
1223
|
2924
|
100
|
|
|
|
172497
|
if ( defined $self->{'fh'} ) { |
|
1224
|
2914
|
|
|
|
|
172943
|
my $fh = $self->{'fh'}; |
|
1225
|
2914
|
|
|
|
|
634752
|
print $fh $data; |
|
1226
|
|
|
|
|
|
|
} else { |
|
1227
|
10
|
|
|
|
|
14
|
$self->{'data'} .= $data; |
|
1228
|
|
|
|
|
|
|
} |
|
1229
|
|
|
|
|
|
|
} |
|
1230
|
|
|
|
|
|
|
|
|
1231
|
|
|
|
|
|
|
sub position { |
|
1232
|
466
|
|
|
466
|
0
|
44391
|
my ($self) = @_; |
|
1233
|
|
|
|
|
|
|
|
|
1234
|
466
|
|
|
|
|
88119
|
$self->{'size'}; |
|
1235
|
|
|
|
|
|
|
} |
|
1236
|
|
|
|
|
|
|
|
|
1237
|
|
|
|
|
|
|
sub add_version { |
|
1238
|
32
|
|
|
32
|
0
|
3777
|
my ($self) = @_; |
|
1239
|
|
|
|
|
|
|
|
|
1240
|
32
|
|
|
|
|
4301
|
debug( 2, "add_version(): $self->{'version'}" ); |
|
1241
|
32
|
|
|
|
|
4045
|
$self->add( "%PDF-" . $self->{'version'} ); |
|
1242
|
32
|
|
|
|
|
3831
|
$self->cr; |
|
1243
|
|
|
|
|
|
|
} |
|
1244
|
|
|
|
|
|
|
|
|
1245
|
|
|
|
|
|
|
sub add_object { |
|
1246
|
185
|
|
|
185
|
0
|
17004
|
my ($self, $v) = @_; |
|
1247
|
|
|
|
|
|
|
|
|
1248
|
185
|
|
|
|
|
17201
|
my $val = &encode(@$v); |
|
1249
|
185
|
|
|
|
|
17110
|
$self->add($val); |
|
1250
|
185
|
|
|
|
|
16892
|
$self->cr; |
|
1251
|
185
|
|
|
|
|
17080
|
debug( 3, "add_object(): $v -> $val" ); |
|
1252
|
185
|
|
|
|
|
33864
|
[ $$v[1][0], $$v[1][1] ]; |
|
1253
|
|
|
|
|
|
|
} |
|
1254
|
|
|
|
|
|
|
|
|
1255
|
|
|
|
|
|
|
sub null { |
|
1256
|
90
|
|
|
90
|
0
|
18030
|
my ($self) = @_;; |
|
1257
|
|
|
|
|
|
|
|
|
1258
|
90
|
|
|
|
|
36001
|
[ '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
|
11280
|
my ($self, $val) = @_;; |
|
1269
|
|
|
|
|
|
|
|
|
1270
|
143
|
|
|
|
|
26668
|
[ 'number', $val ]; |
|
1271
|
|
|
|
|
|
|
} |
|
1272
|
|
|
|
|
|
|
|
|
1273
|
|
|
|
|
|
|
sub name { |
|
1274
|
396
|
|
|
396
|
0
|
34665
|
my ($self, $val) = @_; |
|
1275
|
|
|
|
|
|
|
|
|
1276
|
396
|
|
|
|
|
74063
|
[ 'name', $val ]; |
|
1277
|
|
|
|
|
|
|
} |
|
1278
|
|
|
|
|
|
|
|
|
1279
|
|
|
|
|
|
|
sub string { |
|
1280
|
73
|
|
|
73
|
0
|
8955
|
my ($self, $val) = @_; |
|
1281
|
|
|
|
|
|
|
|
|
1282
|
73
|
|
|
|
|
17126
|
[ 'string', $val ]; |
|
1283
|
|
|
|
|
|
|
} |
|
1284
|
|
|
|
|
|
|
|
|
1285
|
|
|
|
|
|
|
sub verbatim { |
|
1286
|
5
|
|
|
5
|
0
|
6
|
my ($self, $val) = @_; |
|
1287
|
|
|
|
|
|
|
|
|
1288
|
5
|
|
|
|
|
21
|
[ 'verbatim', $val ]; |
|
1289
|
|
|
|
|
|
|
} |
|
1290
|
|
|
|
|
|
|
|
|
1291
|
|
|
|
|
|
|
sub array { |
|
1292
|
123
|
|
|
123
|
0
|
11455
|
my $self = shift; |
|
1293
|
|
|
|
|
|
|
|
|
1294
|
123
|
|
|
|
|
26927
|
[ 'array', [@_] ]; |
|
1295
|
|
|
|
|
|
|
} |
|
1296
|
|
|
|
|
|
|
|
|
1297
|
|
|
|
|
|
|
sub dictionary { |
|
1298
|
197
|
|
|
197
|
0
|
15789
|
my $self = shift; |
|
1299
|
|
|
|
|
|
|
|
|
1300
|
197
|
|
|
|
|
35000
|
[ 'dictionary', {@_} ]; |
|
1301
|
|
|
|
|
|
|
} |
|
1302
|
|
|
|
|
|
|
|
|
1303
|
|
|
|
|
|
|
sub indirect_obj { |
|
1304
|
185
|
|
|
185
|
0
|
16872
|
my $self = shift; |
|
1305
|
|
|
|
|
|
|
|
|
1306
|
185
|
|
|
|
|
17088
|
my ($id, $gen, $type, $name); |
|
1307
|
185
|
|
|
|
|
17103
|
$name = $_[1]; |
|
1308
|
|
|
|
|
|
|
$type = $_[0][1]{'Type'}[1] |
|
1309
|
185
|
100
|
66
|
|
|
18202
|
if defined $_[0][1] && ref $_[0][1] eq 'HASH' && defined $_[0][1]{'Type'}; |
|
|
|
|
100
|
|
|
|
|
|
1310
|
|
|
|
|
|
|
|
|
1311
|
185
|
100
|
66
|
|
|
17531
|
if ( defined $name && defined $self->{'reservations'}{$name} ) { |
|
|
|
100
|
66
|
|
|
|
|
|
1312
|
134
|
|
|
|
|
13489
|
( $id, $gen ) = @{ $self->{'reservations'}{$name} }; |
|
|
134
|
|
|
|
|
26778
|
|
|
1313
|
134
|
|
|
|
|
27205
|
delete $self->{'reservations'}{$name}; |
|
1314
|
|
|
|
|
|
|
} elsif ( defined $type && defined $self->{'reservations'}{$type} ) { |
|
1315
|
50
|
|
|
|
|
3673
|
( $id, $gen ) = @{ $self->{'reservations'}{$type} }; |
|
|
50
|
|
|
|
|
7316
|
|
|
1316
|
50
|
|
|
|
|
7340
|
delete $self->{'reservations'}{$type}; |
|
1317
|
|
|
|
|
|
|
} else { |
|
1318
|
1
|
|
|
|
|
3
|
$id = ++$self->{'object_number'}; |
|
1319
|
1
|
|
|
|
|
1
|
$gen = $self->{'generation_number'}; |
|
1320
|
|
|
|
|
|
|
} |
|
1321
|
185
|
|
|
|
|
17304
|
debug( 3, "indirect_obj(): " . $self->position ); |
|
1322
|
185
|
|
|
|
|
17582
|
push @{ $self->{'crossrefsubsection'}{$gen} }, [ $id, $self->position, 1 ]; |
|
|
185
|
|
|
|
|
34991
|
|
|
1323
|
185
|
|
|
|
|
34739
|
[ 'object', [ $id, $gen, @_ ] ]; |
|
1324
|
|
|
|
|
|
|
} |
|
1325
|
|
|
|
|
|
|
|
|
1326
|
|
|
|
|
|
|
sub indirect_ref { |
|
1327
|
313
|
|
|
313
|
0
|
36459
|
my $self = shift; |
|
1328
|
|
|
|
|
|
|
|
|
1329
|
313
|
|
|
|
|
85576
|
[ 'ref', [@_] ]; |
|
1330
|
|
|
|
|
|
|
} |
|
1331
|
|
|
|
|
|
|
|
|
1332
|
|
|
|
|
|
|
sub stream { |
|
1333
|
3
|
|
|
3
|
0
|
1
|
my $self = shift; |
|
1334
|
|
|
|
|
|
|
|
|
1335
|
3
|
|
|
|
|
16
|
[ 'stream', {@_} ]; |
|
1336
|
|
|
|
|
|
|
} |
|
1337
|
|
|
|
|
|
|
|
|
1338
|
|
|
|
|
|
|
sub add_info { |
|
1339
|
15
|
|
|
15
|
0
|
921
|
my $self = shift; |
|
1340
|
|
|
|
|
|
|
|
|
1341
|
15
|
|
|
|
|
985
|
debug( 2, "add_info():" ); |
|
1342
|
15
|
|
|
|
|
982
|
my %params = @_; |
|
1343
|
15
|
100
|
|
|
|
985
|
$params{'Author'} = $self->{'Author'} if defined $self->{'Author'}; |
|
1344
|
15
|
50
|
|
|
|
959
|
$params{'Creator'} = $self->{'Creator'} if defined $self->{'Creator'}; |
|
1345
|
15
|
100
|
|
|
|
974
|
$params{'Title'} = $self->{'Title'} if defined $self->{'Title'}; |
|
1346
|
15
|
50
|
|
|
|
976
|
$params{'Subject'} = $self->{'Subject'} if defined $self->{'Subject'}; |
|
1347
|
15
|
50
|
|
|
|
941
|
$params{'Keywords'} = $self->{'Keywords'} if defined $self->{'Keywords'}; |
|
1348
|
|
|
|
|
|
|
$params{'CreationDate'} = $self->{'CreationDate'} |
|
1349
|
15
|
50
|
|
|
|
944
|
if defined $self->{'CreationDate'}; |
|
1350
|
|
|
|
|
|
|
|
|
1351
|
15
|
|
|
|
|
1006
|
$self->{'info'} = $self->reserve('Info'); |
|
1352
|
15
|
|
|
|
|
1017
|
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
|
|
|
|
991
|
if defined $params{'Author'}; |
|
1358
|
|
|
|
|
|
|
$$content{'Creator'} = $self->string( $params{'Creator'} ) |
|
1359
|
15
|
50
|
|
|
|
940
|
if defined $params{'Creator'}; |
|
1360
|
|
|
|
|
|
|
$$content{'Title'} = $self->string( $params{'Title'} ) |
|
1361
|
15
|
100
|
|
|
|
1001
|
if defined $params{'Title'}; |
|
1362
|
|
|
|
|
|
|
$$content{'Subject'} = $self->string( $params{'Subject'} ) |
|
1363
|
15
|
50
|
|
|
|
951
|
if defined $params{'Subject'}; |
|
1364
|
|
|
|
|
|
|
$$content{'Keywords'} = $self->string( $params{'Keywords'} ) |
|
1365
|
15
|
50
|
|
|
|
978
|
if defined $params{'Keywords'}; |
|
1366
|
|
|
|
|
|
|
$$content{'CreationDate'} = $self->string( $params{'CreationDate'} ) |
|
1367
|
15
|
50
|
|
|
|
942
|
if defined $params{'CreationDate'}; |
|
1368
|
|
|
|
|
|
|
|
|
1369
|
15
|
|
|
|
|
955
|
$self->add_object( $self->indirect_obj( $self->dictionary(%$content) ), 'Info' ); |
|
1370
|
15
|
|
|
|
|
1004
|
$self->cr; |
|
1371
|
|
|
|
|
|
|
} |
|
1372
|
|
|
|
|
|
|
|
|
1373
|
|
|
|
|
|
|
sub add_catalog { |
|
1374
|
15
|
|
|
15
|
0
|
897
|
my $self = shift; |
|
1375
|
|
|
|
|
|
|
|
|
1376
|
15
|
|
|
|
|
957
|
debug( 2, "add_catalog" ); |
|
1377
|
15
|
|
|
|
|
895
|
my %params = %{ $self->{'catalog'} }; |
|
|
15
|
|
|
|
|
1878
|
|
|
1378
|
|
|
|
|
|
|
|
|
1379
|
|
|
|
|
|
|
# Type (mandatory) |
|
1380
|
15
|
|
|
|
|
927
|
$self->{'catalog'} = $self->reserve('Catalog'); |
|
1381
|
15
|
|
|
|
|
1304
|
my $content = { 'Type' => $self->name('Catalog') }; |
|
1382
|
|
|
|
|
|
|
|
|
1383
|
|
|
|
|
|
|
# Pages (mandatory) [indirected reference] |
|
1384
|
15
|
|
|
|
|
917
|
my $pages = $self->reserve('Pages'); |
|
1385
|
15
|
|
|
|
|
939
|
$$content{'Pages'} = $self->indirect_ref(@$pages); |
|
1386
|
15
|
|
|
|
|
916
|
$self->{'pages'}{'id'} = $$content{'Pages'}[1]; |
|
1387
|
|
|
|
|
|
|
|
|
1388
|
|
|
|
|
|
|
# Outlines [indirected reference] |
|
1389
|
5
|
|
|
|
|
1996
|
$$content{'Outlines'} = $self->indirect_ref( @{ $self->{'outlines'}->{'id'} } ) |
|
1390
|
15
|
100
|
|
|
|
917
|
if defined $self->{'outlines'}; |
|
1391
|
|
|
|
|
|
|
|
|
1392
|
|
|
|
|
|
|
# PageMode |
|
1393
|
15
|
100
|
|
|
|
1070
|
$$content{'PageMode'} = $self->name($params{'PageMode'}) if defined $params{'PageMode'}; |
|
1394
|
|
|
|
|
|
|
|
|
1395
|
15
|
|
|
|
|
1026
|
$self->add_object( $self->indirect_obj( $self->dictionary(%$content) ) ); |
|
1396
|
15
|
|
|
|
|
930
|
$self->cr; |
|
1397
|
|
|
|
|
|
|
} |
|
1398
|
|
|
|
|
|
|
|
|
1399
|
|
|
|
|
|
|
sub encode { |
|
1400
|
6203
|
|
|
6203
|
0
|
529636
|
my ($type, $val) = @_; |
|
1401
|
|
|
|
|
|
|
|
|
1402
|
6203
|
100
|
|
|
|
524913
|
if ($val) { |
|
1403
|
2748
|
|
|
|
|
260087
|
debug( 4, "encode(): $type $val" ); |
|
1404
|
|
|
|
|
|
|
} else { |
|
1405
|
3455
|
|
|
|
|
267933
|
debug( 4, "encode(): $type (no val)" ); |
|
1406
|
|
|
|
|
|
|
} |
|
1407
|
|
|
|
|
|
|
|
|
1408
|
6203
|
100
|
|
|
|
526688
|
if (!$type) { |
|
1409
|
1
|
|
|
|
|
151
|
cluck "PDF::Create::encode: empty argument, called by "; |
|
1410
|
1
|
|
|
|
|
7
|
return 1; |
|
1411
|
|
|
|
|
|
|
} |
|
1412
|
|
|
|
|
|
|
|
|
1413
|
|
|
|
|
|
|
( $type eq 'null' || $type eq 'number' ) && do { |
|
1414
|
1243
|
|
|
|
|
266730
|
1; # do nothing |
|
1415
|
|
|
|
|
|
|
} |
|
1416
|
|
|
|
|
|
|
|| $type eq 'cr' && do { |
|
1417
|
2915
|
|
|
|
|
420376
|
$val = "\n"; |
|
1418
|
|
|
|
|
|
|
} |
|
1419
|
|
|
|
|
|
|
|| $type eq 'boolean' && do { |
|
1420
|
4
|
100
|
|
|
|
14
|
$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
|
|
|
|
|
15
|
$val = "$val"; |
|
1428
|
|
|
|
|
|
|
} |
|
1429
|
|
|
|
|
|
|
|| $type eq 'string' && do { |
|
1430
|
77
|
100
|
|
|
|
8930
|
$val = '' if not defined $val; |
|
1431
|
|
|
|
|
|
|
# TODO: split it. Quote parentheses. |
|
1432
|
77
|
|
|
|
|
17128
|
$val = "($val)"; |
|
1433
|
|
|
|
|
|
|
} |
|
1434
|
|
|
|
|
|
|
|| $type eq 'number' && do { |
|
1435
|
0
|
|
|
|
|
0
|
$val = "$val"; |
|
1436
|
|
|
|
|
|
|
} |
|
1437
|
|
|
|
|
|
|
|| $type eq 'name' && do { |
|
1438
|
1128
|
100
|
|
|
|
90135
|
$val = '' if not defined $val; |
|
1439
|
1128
|
|
|
|
|
180991
|
$val = "/$val"; |
|
1440
|
|
|
|
|
|
|
} |
|
1441
|
|
|
|
|
|
|
|| $type eq 'array' && do { |
|
1442
|
|
|
|
|
|
|
|
|
1443
|
|
|
|
|
|
|
# array, encode contents individually |
|
1444
|
125
|
|
|
|
|
11205
|
my $s = '['; |
|
1445
|
125
|
|
|
|
|
11566
|
for my $v (@$val) { |
|
1446
|
327
|
|
|
|
|
11583
|
$s .= &encode( $$v[0], $$v[1] ) . " "; |
|
1447
|
|
|
|
|
|
|
} |
|
1448
|
|
|
|
|
|
|
# remove the trailing space |
|
1449
|
125
|
|
|
|
|
10919
|
chop $s; |
|
1450
|
125
|
|
|
|
|
22001
|
$val = $s . "]"; |
|
1451
|
|
|
|
|
|
|
} |
|
1452
|
|
|
|
|
|
|
|| $type eq 'dictionary' && do { |
|
1453
|
197
|
|
|
|
|
16172
|
my $s = '<<' . &encode('cr'); |
|
1454
|
197
|
|
|
|
|
16305
|
for my $v ( keys %$val ) { |
|
1455
|
743
|
|
|
|
|
66593
|
$s .= &encode( 'name', $v ) . " "; |
|
1456
|
743
|
|
|
|
|
66181
|
$s .= &encode( ${ $$val{$v} }[0], ${ $$val{$v} }[1] ); # . " "; |
|
|
743
|
|
|
|
|
130771
|
|
|
|
743
|
|
|
|
|
132516
|
|
|
1457
|
743
|
|
|
|
|
66564
|
$s .= &encode('cr'); |
|
1458
|
|
|
|
|
|
|
} |
|
1459
|
197
|
|
|
|
|
32192
|
$val = $s . ">>"; |
|
1460
|
|
|
|
|
|
|
} |
|
1461
|
|
|
|
|
|
|
|| $type eq 'object' && do { |
|
1462
|
186
|
|
|
|
|
17189
|
my $s = &encode( 'number', $$val[0] ) . " " . &encode( 'number', $$val[1] ) . " obj"; |
|
1463
|
186
|
|
|
|
|
16601
|
$s .= &encode('cr'); |
|
1464
|
186
|
|
|
|
|
16750
|
$s .= &encode( $$val[2][0], $$val[2][1] ); # . " "; |
|
1465
|
186
|
|
|
|
|
16937
|
$s .= &encode('cr'); |
|
1466
|
186
|
|
|
|
|
34388
|
$val = $s . "endobj"; |
|
1467
|
|
|
|
|
|
|
} |
|
1468
|
|
|
|
|
|
|
|| $type eq 'ref' && do { |
|
1469
|
315
|
|
|
|
|
37466
|
my $s = &encode( 'number', $$val[0] ) . " " . &encode( 'number', $$val[1] ) . " R"; |
|
1470
|
315
|
|
|
|
|
72892
|
$val = $s; |
|
1471
|
|
|
|
|
|
|
} |
|
1472
|
6202
|
100
|
100
|
|
|
560538
|
|| $type eq 'stream' && do { |
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
1473
|
3
|
|
|
|
|
5
|
my $data = delete $$val{'Data'}; |
|
1474
|
3
|
|
|
|
|
6
|
my $s = '<<' . &encode('cr'); |
|
1475
|
3
|
|
|
|
|
8
|
for my $v ( keys %$val ) { |
|
1476
|
22
|
|
|
|
|
22
|
$s .= &encode( 'name', $v ) . " "; |
|
1477
|
22
|
|
|
|
|
16
|
$s .= &encode( ${ $$val{$v} }[0], ${ $$val{$v} }[1] ); # . " "; |
|
|
22
|
|
|
|
|
22
|
|
|
|
22
|
|
|
|
|
21
|
|
|
1478
|
22
|
|
|
|
|
23
|
$s .= &encode('cr'); |
|
1479
|
|
|
|
|
|
|
} |
|
1480
|
3
|
|
|
|
|
5
|
$s .= ">>" . &encode('cr') . "stream" . &encode('cr'); |
|
1481
|
3
|
|
|
|
|
4
|
$s .= $data . &encode('cr'); |
|
1482
|
3
|
|
|
|
|
18
|
$val = $s . "endstream" . &encode('cr'); |
|
1483
|
|
|
|
|
|
|
} |
|
1484
|
|
|
|
|
|
|
|| confess "Error: unknown type '$type'"; |
|
1485
|
|
|
|
|
|
|
|
|
1486
|
|
|
|
|
|
|
# TODO: add type 'text'; |
|
1487
|
6201
|
|
|
|
|
1073078
|
$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; |