File Coverage

blib/lib/PDF/Builder/NamedDestination.pm
Criterion Covered Total %
statement 47 112 41.9
branch 14 60 23.3
condition 8 30 26.6
subroutine 10 20 50.0
pod 6 13 46.1
total 85 235 36.1


line stmt bran cond sub pod time code
1             package PDF::Builder::NamedDestination;
2              
3 38     38   263 use base 'PDF::Builder::Basic::PDF::Dict';
  38         79  
  38         3219  
4              
5 38     38   224 use strict;
  38         96  
  38         638  
6 38     38   158 use warnings;
  38         70  
  38         885  
7              
8 38     38   177 use Carp;
  38         78  
  38         2186  
9 38     38   212 use Encode qw(:all);
  38         110  
  38         11208  
10              
11             our $VERSION = '3.024'; # VERSION
12             our $LAST_UPDATE = '3.024'; # manually update whenever code is changed
13              
14             # TBD: do rect and border apply to Named Destinations (link, url, file)?
15             # There is nothing to implement these options. Perhaps the code was copied
16             # from Annotations and never cleaned up? Disable mention of these options
17             # for now (in the POD). Only link handles the destination page fit option.
18              
19 38     38   261 use PDF::Builder::Util;
  38         107  
  38         4829  
20 38     38   246 use PDF::Builder::Basic::PDF::Utils;
  38         73  
  38         47179  
21              
22             =head1 NAME
23              
24             PDF::Builder::NamedDestination - Add named destinations (views) to a PDF
25              
26             =head1 METHODS
27              
28             =over
29              
30             =item $dest = PDF::Builder::NamedDestination->new($pdf, ...)
31              
32             Creates a new named destination object. Any optional additional arguments
33             will be passed on to C.
34              
35             =back
36              
37             =head2 Destination types
38              
39             =over
40              
41             =cut
42              
43             sub new {
44 1     1 1 11 my $class = shift;
45 1         2 my $pdf = shift;
46              
47 1 50       9 $pdf = $pdf->{'pdf'} if $pdf->isa('PDF::Builder');
48 1         6 my $self = $class->SUPER::new($pdf);
49 1         4 $pdf->new_obj($self);
50              
51 1 50       4 if (@_) { # leftover arguments?
52 1         4 return $self->destination(@_);
53             }
54              
55 0         0 return $self;
56             }
57              
58             # Note: new_api() removed in favor of new():
59             # new_api($api, ...) replace with new($api->{'pdf'}, ...)
60             # Appears to be added back in, PDF::API2 2.042
61             sub new_api {
62 0     0 0 0 my ($class, $api2) = @_;
63 0         0 warnings::warnif('deprecated',
64             'Call to deprecated method new_api, replace with new');
65              
66 0         0 my $destination = $class->new($api2);
67 0         0 return $destination;
68             }
69              
70             =item $dest->dest($page, $location, @args)
71              
72             A destination (dest) is a particular view of a PDF, consisting of a page
73             object, the
74             location of the window on that page, and possible coordinate and zoom arguments.
75              
76             # The XYZ location takes three arguments
77             my $dest1 = PDF::Builder::NamedDestination->new($pdf);
78             $dest->dest($pdf->open_page(1), 'xyz' => [$x, $y, $zoom]);
79              
80             # The Fit location doesn't require any arguments, but one is still
81             # needed for the hash array
82             my $dest2 = PDF::Builder::NamedDestination->new($pdf);
83             $dest->dest($pdf->open_page(2), 'fit' => 1);
84              
85             See L for a listing of the available
86             locations and their syntax.
87              
88             "xyz" is the B fit setting, with position (left and top) and zoom
89             the same as the calling page's.
90              
91             =back
92              
93             B C
94              
95             This method was originally C, which PDF::API2 renamed to
96             C. We are keeping the original name, and for partial
97             compatibility, allow C as an alias. B the old PDF::API2
98             (and still, for PDF::Builder), uses a hash element for the location and
99             dimension/zoom information, while the new PDF::API2 uses a string and an array
100             (I supported in PDF::Builder).
101              
102             =cut
103              
104             # new in PDF::API2
105             #sub _array {
106             # my $page = shift();
107             # my $location = shift();
108             # return PDFArray($page, PDFName($location),
109             # map { defined($_) ? PDFNum($_) : PDFNull() } @_);
110             #}
111             #
112             #sub _destination {
113             # my ($page, $location, @args) = @_;
114             # return _array($page, 'XYZ', undef, undef, undef) unless $location;
115             #
116             # my %arg_counts = (
117             # xyz => 3,
118             # fit => 0,
119             # fith => 1,
120             # fitv => 1,
121             # fitr => 4,
122             # fitb => 0,
123             # fitbh => 1,
124             # fitbv => 1,
125             # );
126             # my $arg_count = $arg_counts{$location};
127             # croak "Invalid location $location" unless defined $arg_count;
128             #
129             # if ($arg_count == 0 and @args) {
130             # croak "$location doesn't take any arguments";
131             # } elsif ($arg_count == 1 and @args != 1) {
132             # croak "$location requires one argument";
133             # #} elsif ($arg_count == 2 and @args != 2) {
134             # # croak "$location requires two arguments";
135             # } elsif ($arg_count == 3 and @args != 3) {
136             # croak "$location requires three arguments";
137             # } elsif ($arg_count == 4 and @args != 4) {
138             # croak "$location requires four arguments";
139             # }
140             #
141             # return _array($page, 'XYZ', @args) if $location eq 'xyz';
142             # $location =~ s/^fit(.*)$/'Fit' . uc($1 or '')/e;
143             # return _array($page, $location, @args);
144             #}
145             #
146             #sub destination {
147             # my ($self, $page, $location, @args) = @_;
148             # $self->{'D'} = _destination($page, $location, @args);
149             # return $self;
150             #}
151              
152 1     1 0 4 sub destination { return dest(@_); } ## no critic
153              
154             # deprecated by PDF::API2, allowed here for compatibility
155             sub dest {
156 1     1 1 2 my $self = shift();
157 1         2 my $page = shift();
158 1         2 my %opts;
159 1 50       4 if (scalar(@_) == 1) {
    0          
160             # just one name. if [-]fit[b], assign a value of 1
161 1 50       11 if ($_[0] =~ m/^-?fitb?$/) {
162 1         3 $opts{$_[0]} = 1;
163             } else {
164             # don't know what to do with it
165 0         0 croak "Unknown location value ";
166             }
167             } elsif (scalar(@_)%2) {
168             # odd number 3+, presumably just 'fit' or 'fitb'. add a value
169             # assuming first element is fit name without value, remainder = options
170 0         0 $opts{$_[0]} = 1;
171 0         0 shift();
172             # probably shouldn't be additional items (options), but just in case...
173 0         0 while(@_) {
174 0         0 $opts{$_[0]} = $_[1];
175 0         0 shift(); shift();
  0         0  
176             }
177             } else {
178             # even number, presumably the %opts hash
179 0         0 %opts = @_; # might be empty!
180             }
181             # copy dashed names over to preferred non-dashed names
182 1 50 33     12 if (defined $opts{'-fit'} && !defined $opts{'fit'}) { $opts{'fit'} = delete($opts{'-fit'}); }
  0         0  
183 1 50 33     5 if (defined $opts{'-fith'} && !defined $opts{'fith'}) { $opts{'fith'} = delete($opts{'-fith'}); }
  0         0  
184 1 50 33     3 if (defined $opts{'-fitb'} && !defined $opts{'fitb'}) { $opts{'fitb'} = delete($opts{'-fitb'}); }
  0         0  
185 1 50 33     4 if (defined $opts{'-fitbh'} && !defined $opts{'fitbh'}) { $opts{'fitbh'} = delete($opts{'-fitbh'}); }
  0         0  
186 1 50 33     4 if (defined $opts{'-fitv'} && !defined $opts{'fitv'}) { $opts{'fitv'} = delete($opts{'-fitv'}); }
  0         0  
187 1 50 33     3 if (defined $opts{'-fitbv'} && !defined $opts{'fitbv'}) { $opts{'fitbv'} = delete($opts{'-fitbv'}); }
  0         0  
188 1 50 33     4 if (defined $opts{'-fitr'} && !defined $opts{'fitr'}) { $opts{'fitr'} = delete($opts{'-fitr'}); }
  0         0  
189 1 50 33     5 if (defined $opts{'-xyz'} && !defined $opts{'xyz'}) { $opts{'xyz'} = delete($opts{'-xyz'}); }
  0         0  
190              
191 1 50       3 if (ref($page)) {
192             # should be only one 'fit' hash value? other options in hash?
193             # TBD: check that single values are scalars, not ARRAYREFs?
194 1 50       3 if (defined $opts{'fit'}) { # 1 value, ignored
    0          
    0          
    0          
    0          
    0          
    0          
    0          
195 1         24 $self->{'D'} = PDFArray($page, PDFName('Fit'));
196             } elsif (defined $opts{ 'fith'}) {
197             croak "Expecting scalar value for fith entry "
198 0 0       0 unless ref($opts{'fith'}) eq '';
199             $self->{'D'} = PDFArray($page, PDFName('FitH'),
200 0         0 PDFNum($opts{'fith'}));
201             } elsif (defined $opts{'fitb'}) { # 1 value, ignored
202 0         0 $self->{'D'} = PDFArray($page, PDFName('FitB'));
203             } elsif (defined $opts{'fitbh'}) {
204             croak "Expecting scalar value for fitbh entry "
205 0 0       0 unless ref($opts{'fitbh'}) eq '';
206             $self->{'D'} = PDFArray($page, PDFName('FitBH'),
207 0         0 PDFNum($opts{'fitbh'}));
208             } elsif (defined $opts{'fitv'}) {
209             croak "Expecting scalar value for fitv entry "
210 0 0       0 unless ref($opts{'fitv'}) eq '';
211             $self->{'D'} = PDFArray($page, PDFName('FitV'),
212 0         0 PDFNum($opts{'fitv'}));
213             } elsif (defined $opts{'fitbv'}) {
214             croak "Expecting scalar value for fitbv entry "
215 0 0       0 unless ref($opts{'fitbv'}) eq '';
216             $self->{'D'} = PDFArray($page, PDFName('FitBV'),
217 0         0 PDFNum($opts{'fitbv'}));
218             } elsif (defined $opts{'fitr'}) { # anon array length 4
219             croak "Insufficient parameters to ->dest(page, fitr => []) "
220             unless ref($opts{'fitr'}) eq 'ARRAY' &&
221 0 0 0     0 scalar @{$opts{'fitr'}} == 4;
  0         0  
222             $self->{'D'} = PDFArray($page, PDFName('FitR'),
223 0         0 map {PDFNum($_)} @{$opts{'fitr'}});
  0         0  
  0         0  
224             } elsif (defined $opts{'xyz'}) { # anon array length 3
225             croak "Insufficient parameters to ->dest(page, xyz => []) "
226             unless ref($opts{'xyz'}) eq 'ARRAY' &&
227 0 0 0     0 scalar @{$opts{'xyz'}} == 3;
  0         0  
228             $self->{'D'} = PDFArray($page, PDFName('XYZ'),
229 0 0       0 map {defined $_ ? PDFNum($_) : PDFNull()} @{$opts{'xyz'}});
  0         0  
  0         0  
230             } else {
231             # no "fit" option found. use default of xyz.
232 0         0 $opts{'xyz'} = [undef,undef,undef];
233             $self->{'D'} = PDFArray($page, PDFName('XYZ'),
234 0 0       0 map {defined $_ ? PDFNum($_) : PDFNull()} @{$opts{'xyz'}});
  0         0  
  0         0  
235             }
236             }
237              
238 1         4 return $self;
239             }
240              
241             =head2 Target Destinations
242              
243             =over
244              
245             =item $dest->goto($page, $location, @args)
246              
247             A go-to action changes the view to a specified destination (page, location, and
248             magnification factor).
249              
250             Parameters are as described in C.
251              
252             B C
253              
254             Originally this method was C, but recently PDF::API2 changed the name
255             to C. "link" is retained for compatibility.
256              
257             =cut
258              
259 0     0 0   sub link { return goto(@_); } ## no critic
260              
261             sub goto {
262 0     0 1   my $self = shift();
263 0           $self->{'S'} = PDFName('GoTo');
264 0           return $self->dest(@_);
265             }
266              
267             =item $dest->uri($page, $location, @args)
268              
269             Defines the destination as launch-url with uri C<$url> and
270             page-fit options %opts.
271              
272             B C
273              
274             Originally this method was C, but recently PDF::API2 changed the name
275             to C. "url" is retained for compatibility.
276              
277             =cut
278              
279 0     0 0   sub url { return uri(@_); } ## no critic
280              
281             sub uri {
282 0     0 1   my ($self, $uri, %opts) = @_;
283              
284 0           $self->{'S'} = PDFName('URI');
285 0           $self->{'URI'} = PDFString($uri, 'u');
286              
287 0           return $self;
288             }
289              
290             =item $dest->launch($file, %opts)
291              
292             Defines the destination as launch-file with filepath C<$file> and
293             page-fit options %opts. The target application is run.
294              
295             B C
296              
297             Originally this method was C, but recently PDF::API2 changed the name
298             to C. "file" is retained for compatibility.
299              
300             =cut
301              
302 0     0 0   sub file { return launch(@_); } ## no critic
303              
304             sub launch {
305 0     0 1   my ($self, $file, %opts) = @_;
306              
307 0           $self->{'S'} = PDFName('Launch');
308 0           $self->{'F'} = PDFString($file, 'u');
309              
310 0           return $self;
311             }
312              
313             =item $dest->pdf($pdf_file, $pagenum, %opts)
314              
315             Defines the destination as a PDF-file with filepath C<$pdf_file>, on page
316             C<$pagenum>, and options %opts (same as dest()).
317              
318             B C and C
319              
320             Originally this method was C, and had been earlier renamed to
321             C, but recently PDF::API2 changed the name to C. "pdfile" and
322             "pdf_file" are retained for compatibility. B the position and zoom
323             information is still given as a hash element in PDF::Builder, while PDF::API2
324             has changed to a position string and an array of dimensions.
325              
326             =cut
327              
328 0     0 0   sub pdf_file { return pdf(@_); } ## no critic
329             # deprecated and removed earlier, but still in PDF::API2
330 0     0 0   sub pdfile { return pdf(@_); } ## no critic
331              
332             sub pdf{
333 0     0 1   my ($self, $file, $pnum, %opts) = @_;
334              
335 0           $self->{'S'} = PDFName('GoToR');
336 0           $self->{'F'} = PDFString($file, 'u');
337              
338 0           $self->dest(PDFNum($pnum), %opts);
339              
340 0           return $self;
341             }
342              
343             =back
344              
345             =cut
346              
347             1;