File Coverage

blib/lib/PDF/API2/ViewerPreferences.pm
Criterion Covered Total %
statement 46 108 42.5
branch 16 82 19.5
condition n/a
subroutine 9 12 75.0
pod 4 4 100.0
total 75 206 36.4


line stmt bran cond sub pod time code
1             package PDF::API2::ViewerPreferences;
2              
3 30     30   2078 use strict;
  30         72  
  30         1004  
4 30     30   163 use warnings;
  30         87  
  30         1358  
5              
6             our $VERSION = '2.043'; # VERSION
7              
8 30     30   168 use Carp;
  30         65  
  30         1961  
9 30     30   203 use PDF::API2::Basic::PDF::Utils;
  30         78  
  30         2893  
10 30     30   237 use Scalar::Util qw(weaken);
  30         82  
  30         49845  
11              
12             our @CARP_NOT;
13              
14             my @booleans = qw(HideToolbar HideMenubar HideWindowUI FitWindow CenterWindow
15             DisplayDocTitle PickTrayByPDFSize);
16              
17             my @names = qw(NonFullScreenPageMode Direction Duplex PrintScaling
18             ViewArea ViewClip PrintArea PrintClip);
19              
20             =head1 NAME
21              
22             PDF::API2::ViewerPreferences - How the PDF should be displayed or printed
23              
24             =head1 METHODS
25              
26             =over
27              
28             =cut
29              
30             sub _snake_case {
31 0     0   0 my $name = shift();
32 0         0 $name =~ s/^([A-Z]+)/lc($1)/e;
  0         0  
33 0         0 $name =~ s/([A-Z]+)/'_' . lc($1)/ge;
  0         0  
34 0         0 $name =~ s/pdfsize/pdf_size/;
35 0         0 return $name;
36             }
37              
38             sub _camel_case {
39 172     172   302 my $name = shift();
40 172         532 $name = ucfirst($name);
41 172         1343 $name =~ s/_([a-z]+)/ucfirst($1)/ge;
  676         2436  
42 172         399 $name =~ s/Ui$/UI/;
43 172         317 $name =~ s/Pdf/PDF/;
44 172         454 return $name;
45             }
46              
47             =item $self = $class->new($pdf)
48              
49             Creates a new ViewerPreferences object from a PDF::API2 object.
50              
51             =cut
52              
53             sub new {
54 172     172 1 397 my ($class, $pdf) = @_;
55 172         466 my $self = bless { pdf => $pdf }, $class;
56 172         877 weaken $self->{'pdf'};
57 172         404 return $self;
58             }
59              
60             =item %preferences = $self->get_preferences()
61              
62             Returns a hash containing all of the viewer preferences that are defined in the
63             PDF.
64              
65             =cut
66              
67             sub get_preferences {
68 0     0 1 0 my $self = shift();
69 0         0 my $prefs = $self->{'pdf'}->{'catalog'}->{'ViewerPreferences'};
70 0 0       0 return unless $prefs;
71 0         0 $prefs->realise();
72              
73 0         0 my %values;
74 0         0 foreach my $pref (@booleans) {
75 0 0       0 next unless $prefs->{$pref};
76 0 0       0 $values{_snake_case($pref)} = $prefs->{$pref}->val() eq 'true' ? 1 : 0;
77             }
78 0         0 foreach my $pref (@names) {
79 0 0       0 next unless $prefs->{$pref};
80 0 0       0 if ($pref eq 'Direction') {
    0          
81 0         0 $values{'direction'} = lc($prefs->{$pref}->val());
82             }
83             elsif ($pref eq 'Duplex') {
84 0         0 my $value = $prefs->{$pref}->val();
85 0         0 $value =~ s/Flip//;
86 0         0 $value =~ s/Edge//;
87 0         0 $values{'duplex'} = _snake_case($value);
88             }
89             else {
90 0         0 $values{_snake_case($pref)} = _snake_case($prefs->{$pref}->val());
91             }
92             }
93 0 0       0 if ($prefs->{'PrintPageRange'}) {
94 0         0 my @ranges = map { $_->val() } @{$prefs->{'PrintPageRange'}};
  0         0  
  0         0  
95 0         0 $values{'print_page_range'} = \@ranges;
96             }
97 0 0       0 if ($prefs->{'NumCopies'}) {
98 0         0 $values{'num_copies'} = $prefs->{'NumCopies'}->val();
99             }
100              
101 0         0 return %values;
102             }
103              
104             =item $value = $self->get_preference($name)
105              
106             Returns the value of the specified viewer preference if present, or C if
107             not.
108              
109             =cut
110              
111             sub get_preference {
112 0     0 1 0 my ($self, $name) = @_;
113 0         0 my %values = $self->get_preferences();
114 0         0 return $values{$name};
115             }
116              
117             =item $self->set_preferences(%values)
118              
119             Sets one or more viewer preferences, as described in the preferences section
120             below.
121              
122             =cut
123              
124             sub _init_preferences {
125 172     172   289 my $self = shift();
126 172 100       502 if ($self->{'pdf'}->{'catalog'}->{'ViewerPreferences'}) {
127 8         31 $self->{'pdf'}->{'catalog'}->{'ViewerPreferences'}->realise();
128             }
129             else {
130 164         427 $self->{'pdf'}->{'catalog'}->{'ViewerPreferences'} = PDFDict();
131             }
132 172         666 $self->{'pdf'}->{'pdf'}->out_obj($self->{'pdf'}->{'catalog'});
133 172         356 return $self->{'pdf'}->{'catalog'}->{'ViewerPreferences'};
134             }
135              
136             sub set_preferences {
137 172     172 1 580 my ($self, %values) = @_;
138 172         436 my $prefs = $self->_init_preferences();
139 172         831 local @CARP_NOT = qw(PDF::API2);
140 172         556 foreach my $snake (keys %values) {
141 172         399 my $camel = _camel_case($snake);
142 172 100       572 if ($camel eq 'NonFullScreenPageMode') {
    50          
    50          
    50          
    50          
    0          
    0          
    0          
143             my $name = ($values{$snake} eq 'none' ? 'UseNone' :
144             $values{$snake} eq 'outlines' ? 'UseOutlines' :
145             $values{$snake} eq 'thumbnails' ? 'UseThumbs' :
146 169 0       474 $values{$snake} eq 'optional_content' ? 'UseOC' :
    0          
    0          
    50          
147             '');
148 169 50       401 croak "Invalid value for $snake: $values{$snake}" unless $name;
149 169         447 $prefs->{$camel} = PDFName($name);
150             }
151             elsif ($camel eq 'Direction') {
152 0         0 my $name = $values{$snake};
153 0 0       0 unless ($name =~ /^(?:L2R|R2L)$/i) {
154 0         0 croak "Invalid value for $snake: $name";
155             }
156 0         0 $prefs->{$camel} = PDFName(uc $name);
157             }
158             elsif ($camel =~ /^(?:View|Print)(?:Area|Clip)$/) {
159             my $name = ($values{$snake} eq 'media_box' ? 'MediaBox' :
160             $values{$snake} eq 'crop_box' ? 'CropBox' :
161             $values{$snake} eq 'bleed_box' ? 'BleedBox' :
162             $values{$snake} eq 'trim_box' ? 'TrimBox' :
163 0 0       0 $values{$snake} eq 'art_box' ? 'ArtBox' : '');
    0          
    0          
    0          
    0          
164 0 0       0 croak "Invalid value for $snake: $name" unless $name;
165 0         0 $prefs->{$camel} = PDFName($name);
166             }
167             elsif ($camel eq 'PrintScaling') {
168 0         0 my $value = $values{$snake};
169 0 0       0 my $name = ($value eq 'none' ? 'None' :
    0          
170             $value eq 'app_default' ? 'AppDefault' : '');
171 0 0       0 croak "Invalid value for $snake: $name" unless $name;
172 0         0 $prefs->{$camel} = PDFName($name);
173             }
174             elsif ($camel eq 'Duplex') {
175 3         5 my $value = $values{$snake};
176 3 50       12 my $name = ($value eq 'simplex' ? 'Simplex' :
    100          
    100          
177             $value eq 'duplex_short' ? 'DuplexFlipShortEdge' :
178             $value eq 'duplex_long' ? 'DuplexFlipLongEdge' : '');
179 3 50       7 croak "Invalid value for $snake: $value" unless $name;
180 3         7 $prefs->{$camel} = PDFName($name);
181             }
182             elsif ($camel eq 'PrintPageRange') {
183 0 0       0 unless (ref($values{$snake}) eq 'ARRAY') {
184 0         0 croak "The value for $snake must be a reference to an array";
185             }
186 0         0 my @range = @{$values{$snake}};
  0         0  
187 0 0       0 unless (@range % 2 == 0) {
188 0         0 croak "The value for $snake must contain pairs of page numbers";
189             }
190 0 0       0 if (join('', @range) =~ /\D/) {
191 0         0 croak "The value for $snake may only contain page numbers";
192             }
193 0         0 $prefs->{$camel} = PDFArray(map { PDFNum($_) } @range);
  0         0  
194             }
195             elsif ($camel eq 'NumCopies') {
196 0 0       0 unless ($values{$snake} =~ /^\d+$/) {
197 0         0 croak "$snake: $values{$snake} is not an integer";
198             }
199 0         0 $prefs->{$camel} = PDFNum($values{$snake});
200             }
201 0         0 elsif (grep { $camel eq $_ } @booleans) {
202 0 0       0 $prefs->{$camel} = PDFBool($values{$snake} ? 1 : 0);
203             }
204             else {
205 0         0 croak "Unrecognized viewer preference '$snake'";
206             }
207             }
208 172         890 return $self;
209             }
210              
211             =back
212              
213             =head1 PREFERENCES
214              
215             Viewer Preferences describe how the document should be presented on screen or in
216             print. Not all PDF viewers will respect these preferences.
217              
218             Boolean preferences default to false and take (or return) 0 or 1 as arguments.
219              
220             Bounding Box preferences take (or return) one of C, C,
221             C, C, or C.
222              
223             =over
224              
225             =item hide_toolbar (boolean)
226              
227             A flag specifying whether to hide the tool bars when the document is active.
228              
229             =item hide_menubar (boolean)
230              
231             A flag specifying whether to hide the menu bar when the document is active.
232              
233             =item hide_window_ui (boolean)
234              
235             A flag specifying whether to hide the user interface elements in the document's
236             window (such as scroll bars and navigation controls), leaving only the
237             document's contents displayed.
238              
239             =item fit_window (boolean)
240              
241             A flag specifying whether to resize the document's window to fit the size of the
242             first displayed page.
243              
244             =item center_window (boolean)
245              
246             A flag specifying whether to position the document's window in the center of the
247             screen.
248              
249             =item display_doc_title (boolean)
250              
251             A flag specifying whether the window's title bar should display the document
252             title taken from the Title entry of the document information directory. If
253             false, the title bar should instead display the name of the PDF file containing
254             the document.
255              
256             =item non_full_screen_page_mode (name)
257              
258             The document's page mode, specifying how to display the document on exiting
259             full-screen mode. Options are the same as C in L.
260              
261             =item direction ('l2r' or 'r2l')
262              
263             The predominant reading order for text (left-to-right or right-to-left).
264              
265             This entry has no direct effect on the document's contents or page numbering but
266             may be used to determine the relative positioning of pages when displayed
267             side-by-side or printed n-up.
268              
269             =item view_area (bounding box)
270              
271             The name of the page boundary representing the area of a page that shall be
272             displayed when viewing the document on the screen.
273              
274             =item view_clip (bounding box)
275              
276             The name of the page boundary to which the contents of a page shall be clipped
277             when viewing the document on the screen.
278              
279             =item print_area (bounding box)
280              
281             The name of the page boundary representing the area of a page that shall be
282             rendered when printing the document.
283              
284             =item print_clip (bounding box)
285              
286             The name of the page boundary to which the contents of a page shall be clipped
287             when printing the document.
288              
289             =item print_scaling ('none' or 'app_default')
290              
291             The page scaling option that shall be selected when a print dialog is displayed
292             for this document. C represents no page scaling, and C
293             represents the reader's default print scaling.
294              
295             =item duplex ('simplex', 'duplex_short', or 'duplex_long')
296              
297             The paper handling option that shall be used when printing the file from the
298             print dialog. The duplex values represent whether the page should be flipped on
299             its short edge or long edge, respectively.
300              
301             =item pick_tray_by_pdf_size (boolean)
302              
303             A flag specifying whether the PDF page size shall be used to select the input
304             paper tray. This setting influences only the preset values used to populate the
305             print dialog presented by the reader.
306              
307             =item print_page_rage (an array of integer pairs)
308              
309             The page numbers used to initialize the print dialog box when the file is
310             printed. The array shall contain an even number of integers to be interpreted
311             in pairs, with each pair specifying the first and last pages in a sub-range of
312             pages to be printed. The first page of the PDF file shall be denoted by 1.
313              
314             =item num_copies (integer)
315              
316             The number of copies that shall be printed when the print dialog is opened for
317             this file.
318              
319             =back
320              
321             =cut
322              
323             1;