File Coverage

blib/lib/PDF/API2/Annotation.pm
Criterion Covered Total %
statement 88 152 57.8
branch 13 60 21.6
condition 2 9 22.2
subroutine 17 23 73.9
pod 11 17 64.7
total 131 261 50.1


line stmt bran cond sub pod time code
1             package PDF::API2::Annotation;
2              
3 2     2   3858 use base 'PDF::API2::Basic::PDF::Dict';
  2         4  
  2         337  
4              
5 2     2   13 use strict;
  2         4  
  2         58  
6 2     2   8 use warnings;
  2         4  
  2         138  
7              
8             our $VERSION = '2.048'; # VERSION
9              
10 2     2   11 use Carp;
  2         4  
  2         138  
11 2     2   10 use PDF::API2::Basic::PDF::Utils;
  2         5  
  2         4381  
12              
13             =head1 NAME
14              
15             PDF::API2::Annotation - Add annotations to a PDF
16              
17             =head1 SYNOPSIS
18              
19             my $pdf = PDF::API2->new();
20             my $font = $pdf->font('Helvetica');
21             my $page1 = $pdf->page();
22             my $page2 = $pdf->page();
23              
24             my $content = $page1->text();
25             my $message = 'Go to Page 2';
26             my $size = 18;
27             $content->distance(1 * 72, 9 * 72);
28             $content->font($font, $size);
29             $content->text($message);
30              
31             my $annotation = $page1->annotation();
32             my $width = $content->text_width($message);
33             $annotation->rect(1 * 72, 9 * 72, 1 * 72 + $width, 9 * 72 + $size);
34             $annotation->link($page2);
35              
36             $pdf->save('sample.pdf');
37              
38             =head1 METHODS
39              
40             =cut
41              
42             sub new {
43 6     6 1 9 my $class = shift();
44 6         20 my $self = $class->SUPER::new();
45 6         15 $self->{'Type'} = PDFName('Annot');
46 6         11 $self->{'Border'} = PDFArray(PDFNum(0), PDFNum(0), PDFNum(0));
47 6         13 return $self;
48             }
49              
50             =head2 Annotation Types
51              
52             =head3 link
53              
54             $annotation = $annotation->link($destination, $location, @args);
55              
56             Link the annotation to another page in this PDF. C<$location> and C<@args> are
57             optional and set which part of the page should be displayed, as defined in
58             L.
59              
60             C<$destination> can be either a L object or the name of a named
61             destination defined elsewhere.
62              
63             =cut
64              
65             sub link {
66 1     1 1 5 my $self = shift();
67 1         2 my $destination = shift();
68              
69 1         2 my $location;
70             my @args;
71              
72             # Deprecated options
73 1         0 my %options;
74 1 50 33     4 if ($_[0] and $_[0] =~ /^-/) {
75 0         0 %options = @_;
76             }
77             else {
78 1         2 $location = shift();
79 1         1 @args = @_;
80             }
81              
82 1         3 $self->{'Subtype'} = PDFName('Link');
83 1 50       3 unless (ref($destination)) {
84 0         0 $self->{'Dest'} = PDFStr($destination);
85 0         0 return $self;
86             }
87              
88 1         14 $self->{'A'} = PDFDict();
89 1         2 $self->{'A'}->{'S'} = PDFName('GoTo');
90              
91 1 50       3 unless (%options) {
92 1         3 $self->{'A'}->{'D'} = _destination($destination, $location, @args);
93             }
94             else {
95             # Deprecated
96 0         0 $self->dest($destination, %options);
97 0 0       0 $self->rect(@{$options{'-rect'}}) if defined $options{'-rect'};
  0         0  
98 0 0       0 $self->border(@{$options{'-border'}}) if defined $options{'-border'};
  0         0  
99             }
100              
101 1         2 return $self;
102             }
103              
104             sub _destination {
105 2     2   14 require PDF::API2::NamedDestination;
106 2         10 return PDF::API2::NamedDestination::_destination(@_);
107             }
108              
109             =head3 url
110              
111             $annotation = $annotation->uri($uri);
112              
113             Launch C<$uri> -- typically a web page -- when the annotation is selected.
114              
115             =cut
116              
117             # Deprecated (renamed)
118 1     1 1 6 sub url { return uri(@_) }
119              
120             sub uri {
121 1     1 0 3 my ($self, $uri, %options) = @_;
122              
123 1         2 $self->{'Subtype'} = PDFName('Link');
124 1         2 $self->{'A'} = PDFDict();
125 1         3 $self->{'A'}->{'S'} = PDFName('URI');
126 1         3 $self->{'A'}->{'URI'} = PDFStr($uri);
127              
128             # Deprecated
129 1 50       2 $self->rect(@{$options{'-rect'}}) if defined $options{'-rect'};
  0         0  
130 1 50       2 $self->border(@{$options{'-border'}}) if defined $options{'-border'};
  0         0  
131              
132 1         2 return $self;
133             }
134              
135             =head3 file
136              
137             $annotation = $annotation->launch($file);
138              
139             Open C<$file> when the annotation is selected.
140              
141             =cut
142              
143 1     1 1 5 sub file { return launch(@_) }
144              
145             sub launch {
146 1     1 0 3 my ($self, $file, %options) = @_;
147 1         3 $self->{'Subtype'} = PDFName('Link');
148 1         3 $self->{'A'} = PDFDict();
149 1         122 $self->{'A'}->{'S'} = PDFName('Launch');
150 1         3 $self->{'A'}->{'F'} = PDFStr($file);
151              
152             # Deprecated
153 1 50       4 $self->rect(@{$options{'-rect'}}) if defined $options{'-rect'};
  0         0  
154 1 50       3 $self->border(@{$options{'-border'}}) if defined $options{'-border'};
  0         0  
155              
156 1         3 return $self;
157             }
158              
159             =head3 pdf
160              
161             $annotation = $annotation->pdf($file, $dest, $location, @args);
162              
163             Open the PDF file located at C<$file> to the specified destination.
164             C<$location> and C<@args> are optional and set which part of the page should be
165             displayed, as defined in L.
166              
167             C<$dest> can be a page number, or a named destination prefixed with C<#>.
168              
169             =cut
170              
171             # Deprecated
172 0     0 0 0 sub pdfile { return pdf_file(@_) }
173 1     1 0 9 sub pdf_file { return pdf(@_) }
174              
175             sub pdf {
176 1     1 1 3 my $self = shift();
177 1         3 my $file = shift();
178 1         2 my $dest = shift();
179 1         5 my $location;
180             my @args;
181              
182             # Deprecated options
183 1         0 my %options;
184 1 50 33     7 if ($_[0] and $_[0] =~ /^-/) {
185 0         0 %options = @_;
186             }
187             else {
188 1         2 $location = shift();
189 1         3 @args = @_;
190             }
191              
192 1         4 $self->{'Subtype'} = PDFName('Link');
193 1         4 $self->{'A'} = PDFDict();
194 1         4 $self->{'A'}->{'S'} = PDFName('GoToR');
195 1         4 $self->{'A'}->{'F'} = PDFStr($file);
196              
197 1 50       5 unless (%options) {
198 1 50       4 if ( $dest =~ /^\/(.+)/ ) { # named dest
199 0         0 $self->{'A'}->{'D'} = PDFName($1);
200             }
201             else {
202 1         4 my $page_number = PDFNum($dest);
203 1         5 $self->{'A'}->{'D'} = _destination($page_number, $location, @args);
204             }
205             }
206             else {
207             # Deprecated
208 0         0 $self->dest(PDFNum($dest), %options);
209 0 0       0 $self->rect(@{$options{'-rect'}}) if defined $options{'-rect'};
  0         0  
210 0 0       0 $self->border(@{$options{'-border'}}) if defined $options{'-border'};
  0         0  
211             }
212              
213 1         3 return $self;
214             }
215              
216             =head3 text
217              
218             $annotation = $annotation->text($text);
219              
220             Define the annotation as a text note with the specified content.
221              
222             =cut
223              
224             sub text {
225 2     2 1 16 my ($self, $text, %options) = @_;
226 2         5 $self->{'Subtype'} = PDFName('Text');
227 2         5 $self->content($text);
228              
229             # Deprecated
230 2 50       6 $self->rect(@{$options{'-rect'}}) if defined $options{'-rect'};
  2         5  
231 2 50       4 $self->open($options{'-open'}) if defined $options{'-open'};
232              
233 2         4 return $self;
234             }
235              
236             =head3 movie
237              
238             $annotation = $annotation->movie($filename, $content_type);
239              
240             Embed and link to the movie located at $filename with the specified MIME type.
241              
242             =cut
243              
244             sub movie {
245 0     0 1 0 my ($self, $file, $content_type, %options) = @_;
246 0         0 $self->{'Subtype'} = PDFName('Movie');
247 0         0 $self->{'A'} = PDFBool(1);
248 0         0 $self->{'Movie'} = PDFDict();
249 0         0 $self->{'Movie'}->{'F'} = PDFDict();
250              
251 0         0 $self->{' apipdf'}->new_obj($self->{'Movie'}->{'F'});
252 0         0 my $f = $self->{'Movie'}->{'F'};
253 0         0 $f->{'Type'} = PDFName('EmbeddedFile');
254 0         0 $f->{'Subtype'} = PDFName($content_type);
255 0         0 $f->{' streamfile'} = $file;
256              
257             # Deprecated
258 0 0       0 $self->rect(@{$options{'-rect'}}) if defined $options{'-rect'};
  0         0  
259              
260 0         0 return $self;
261             }
262              
263             =head2 Common Annotation Attributes
264              
265             =head3 rect
266              
267             $annotation = $annotation->rect($llx, $lly, $urx, $ury);
268              
269             Define the rectangle around the annotation.
270              
271             =cut
272              
273             sub rect {
274 2     2 1 3 my ($self, @coordinates) = @_;
275 2 50       5 unless (scalar @coordinates == 4) {
276 0         0 die "Incorrect number of parameters (expected four) for rectangle";
277             }
278 2         4 $self->{'Rect'} = PDFArray(map { PDFNum($_) } @coordinates);
  8         10  
279 2         2 return $self;
280             }
281              
282             =head3 border
283              
284             $annotation = $annotation->border($h_radius, $v_radius, $width);
285              
286             Define the border style. Defaults to 0, 0, 0 (no border).
287              
288             =cut
289              
290             sub border {
291 0     0 1 0 my ($self, @attributes) = @_;
292 0 0       0 unless (scalar @attributes == 3) {
293 0         0 croak "Incorrect number of parameters (expected three) for border";
294             }
295 0         0 $self->{'Border'} = PDFArray(map { PDFNum($_) } @attributes);
  0         0  
296 0         0 return $self;
297             }
298              
299             =head3 content
300              
301             $annotation = $annotation->content(@lines);
302              
303             Define the text content of the annotation, if applicable.
304              
305             =cut
306              
307             sub content {
308 2     2 1 4 my ($self, @lines) = @_;
309 2         5 my $text = join("\n", @lines);
310 2         4 $self->{'Contents'} = PDFStr($text);
311 2         2 return $self;
312             }
313              
314             sub name {
315 0     0 0   my ($self, $name) = @_;
316 0           $self->{'Name'} = PDFName($name);
317 0           return $self;
318             }
319              
320             =head3 open
321              
322             $annotation = $annotation->open($boolean);
323              
324             Set the annotation to initially be either open or closed. Only relevant for
325             text annotations.
326              
327             =cut
328              
329             sub open {
330 0     0 1   my ($self, $value) = @_;
331 0 0         $self->{'Open'} = PDFBool($value ? 1 : 0);
332 0           return $self;
333             }
334              
335             sub dest {
336 0     0 0   my ($self, $page, %options) = @_;
337              
338 0 0         unless (ref($page)) {
339 0           $self->{'Dest'} = PDFStr($page);
340 0           return $self;
341             }
342              
343 0   0       $self->{'A'} //= PDFDict();
344 0 0         $options{'-xyz'} = [undef, undef, undef] unless keys %options;
345              
346 0 0         if (defined $options{'-fit'}) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
347 0           $self->{'A'}->{'D'} = _destination($page, 'fit');
348             }
349             elsif (defined $options{'-fith'}) {
350 0           $self->{'A'}->{'D'} = _destination($page, 'fith', $options{'-fith'});
351             }
352             elsif (defined $options{'-fitb'}) {
353 0           $self->{'A'}->{'D'} = _destination($page, 'fitb');
354             }
355             elsif (defined $options{'-fitbh'}) {
356 0           $self->{'A'}->{'D'} = _destination($page, 'fitbh', $options{'-fitbh'});
357             }
358             elsif (defined $options{'-fitv'}) {
359 0           $self->{'A'}->{'D'} = _destination($page, 'fitv', $options{'-fitv'});
360             }
361             elsif (defined $options{'-fitbv'}) {
362 0           $self->{'A'}->{'D'} = _destination($page, 'fitbv', $options{'-fitbv'});
363             }
364             elsif (defined $options{'-fitr'}) {
365 0           $self->{'A'}->{'D'} = _destination($page, 'fitr', @{$options{'-fitr'}});
  0            
366             }
367             elsif (defined $options{'-xyz'}) {
368 0           $self->{'A'}->{'D'} = _destination($page, 'xyz', @{$options{'-xyz'}});
  0            
369             }
370              
371 0           return $self;
372             }
373              
374             1;