File Coverage

blib/lib/PDF/Imposition.pm
Criterion Covered Total %
statement 78 78 100.0
branch 8 8 100.0
condition 5 8 62.5
subroutine 18 18 100.0
pod 4 4 100.0
total 113 116 97.4


line stmt bran cond sub pod time code
1             package PDF::Imposition;
2              
3 10     10   323310 use strict;
  10         14  
  10         247  
4 10     10   34 use warnings;
  10         14  
  10         210  
5 10     10   3919 use Module::Load;
  10         7803  
  10         46  
6 10     10   4678 use Types::Standard qw/Enum Object Maybe Str HashRef/;
  10         776080  
  10         110  
7 10     10   13359 use File::Temp;
  10         109319  
  10         629  
8 10     10   3788 use File::Copy;
  10         14812  
  10         432  
9 10     10   45 use File::Spec;
  10         11  
  10         136  
10 10     10   34 use File::Basename;
  10         12  
  10         515  
11 10     10   4393 use Data::Dumper;
  10         44006  
  10         484  
12 10     10   4177 use PDF::Cropmarks;
  10         1966113  
  10         375  
13 10     10   71 use namespace::clean;
  10         13  
  10         69  
14              
15             use constant {
16             DEBUG => $ENV{AMW_DEBUG},
17 10     10   3351 };
  10         13  
  10         618  
18              
19 10     10   38 use Moo;
  10         10  
  10         44  
20              
21             =head1 NAME
22              
23             PDF::Imposition - Perl module to manage the PDF imposition
24              
25             =head1 VERSION
26              
27             Version 0.24
28              
29             =cut
30              
31             our $VERSION = '0.24';
32              
33             sub version {
34 87     87 1 384 return "PDF::Imposition $VERSION PDF::Cropmarks "
35             . $PDF::Cropmarks::VERSION;
36             }
37              
38              
39             =head1 SYNOPSIS
40              
41             This module is meant to simplify the so-called imposition, i.e.,
42             rearrange the pages of a PDF to get it ready to be printed and folded,
43             with more logical pages placed on the sheet, usually (but not
44             exclusively) on recto and verso.
45              
46             This is what the routine looks like:
47              
48             use PDF::Imposition;
49             my $imposer = PDF::Imposition->new(file => "test.pdf",
50             outfile => "out.pdf",
51             # or # suffix => "-imposed",
52             signature => "40-80",
53             cover => 0,
54             schema => "2up");
55             $imposer->impose;
56             print "Output left in " . $imposer->outfile;
57              
58              
59             Please note that you don't pass the PDF dimensions (which are
60             extracted from the source PDF itself by the class, using the very
61             first page: if you want imposition, I do the reasonable assumption you
62             have all the pages with the same dimensions).
63              
64             =head1 METHODS
65              
66             =head2 Costructor options and accessors
67              
68             =head3 file
69              
70             The input file
71              
72             =head3 outfile
73              
74             The output file
75              
76             =head3 suffix
77              
78             The suffix of the output file (don't mix the two options).
79              
80             =head3 schema
81              
82             The schema to use.
83              
84             =over 4
85              
86             =item 2up
87              
88             See L
89              
90             =item 2down
91              
92             See L
93              
94             =item 2x4x2
95              
96             See L
97              
98             =item 2side
99              
100             See L
101              
102             =item 4up
103              
104             See L
105              
106             =item 1x4x2cutfoldbind
107              
108             See L
109              
110             =item 1repeat2top
111              
112             See L
113              
114             =item 1repeat2side
115              
116             See L
117              
118             =item 1repeat4
119              
120             See L
121              
122             =item ea4x4
123              
124             See L
125              
126             =item 1x8x2
127              
128             See L
129              
130             =item 1x1
131              
132             See L
133              
134             =back
135              
136             =head3 cover
137              
138             If the last logical page must be placed at the very end, B the
139             blank pages used to pad the signature. (C<2up>, C<2down>
140             C<1x4x2cutfoldbind>, C<4up>, C<1x1> only).
141              
142             Often it happens that we want the last page of the pdf to be the last
143             one on the physical booklet after folding. If C is set to a
144             true value, the last page of the logical pdf will be placed on the
145             last page of the last signature.
146              
147             =head3 signature
148              
149             The signature (integer multiple of four or range): C<2up> and C<2down> only.
150              
151             =head3 paper
152              
153             Passing this option triggers the cropmarks. While the original
154             dimensions are left unchanged, this size represents the size of the
155             logical page which is actually imposed.
156              
157             For example, you have a PDF in a6, you pass C as paper, and schema
158             C<2up>, you are going to get an a4 with 2 a6 with cropmarks.
159              
160             This option is passed to L. See the module
161             documentation for the accepted values.
162              
163             =head3 title
164              
165             The title to set in the PDF meta information. Defaults to the basename.
166              
167             =head2 Cropmarks options
168              
169             The following options are passed verbatim to L. See
170             the module documentation for the meaning and accepted values.
171              
172             =head3 paper_thickness
173              
174             Defaults to C<0.1mm>
175              
176             =head3 font_size
177              
178             Defaults to C<8pt>
179              
180             =head3 cropmark_offset
181              
182             Defaults to C<1mm>
183              
184             =head3 cropmark_length
185              
186             Defaults to C<12mm>
187              
188             =head2 impose
189              
190             Main method which does the actual job. You have to call this to get
191             your file. It returns the output filename.
192              
193             =head2 version
194              
195             Return the version string.
196              
197             =cut
198              
199             sub BUILDARGS {
200 87     87 1 3208871 my ($class, %options) = @_;
201 87   100     553 my $schema = lc(delete $options{schema} || '2up'); # default
202 87         312 $options{_version} = $class->version;
203 87         206 my $loadclass = __PACKAGE__ . '::Schema' . $schema;
204 87         257 my %our_options;
205 87         233 foreach my $cropmark_opt (qw/paper
206             cropmark_offset
207             cropmark_length
208             font_size
209             paper_thickness/) {
210 435 100       762 if (exists $options{$cropmark_opt}) {
211 60         117 $our_options{$cropmark_opt} = $options{$cropmark_opt};
212             }
213             }
214 87         385 load $loadclass;
215 86 100       3556 unless ($options{title}) {
216 85 100       305 if ($options{file}) {
217 66         2936 $options{title} = basename($options{file});
218             }
219             }
220              
221 86         1378 my $imposer = $loadclass->new(%options);
222 86         2454 $our_options{imposer} = $imposer;
223 86         174 $our_options{schema} = $schema;
224 86         164 $our_options{_schema_class} = $loadclass;
225 86         150 $our_options{title} = $options{title};
226 86         307 $our_options{_schema_options} = { %options };
227 86         1400 return \%our_options;
228             }
229              
230             has schema => (is => 'ro',
231             required => 1,
232             isa => Enum[__PACKAGE__->available_schemas]);
233              
234             has _schema_class => (is => 'ro',
235             isa => Str,
236             required => 1);
237              
238             has _schema_options => (is => 'ro',
239             isa => HashRef,
240             required => 1);
241              
242             has imposer => (is => 'rwp',
243             required => 1,
244             handles => [qw/file outfile suffix
245             cover
246             signature
247             computed_signature
248             total_pages
249             orig_width
250             orig_height
251             dimensions
252             total_output_pages
253             /],
254             isa => Object);
255              
256             has paper => (is => 'ro',
257             isa => Maybe[Str]);
258              
259             has paper_thickness => (is => 'ro',
260             isa => Str,
261             default => sub { '0.1mm' });
262              
263             has cropmark_offset => (is => 'ro',
264             isa => Str,
265             default => sub { '1mm' });
266              
267             has cropmark_length => (is => 'ro',
268             isa => Str,
269             default => sub { '12mm' });
270              
271             has font_size => (is => 'ro',
272             isa => Str,
273             default => sub { '8pt' });
274              
275             has title => (is => 'ro',
276             isa => Maybe[Str]);
277              
278             has job_name => (is => 'lazy',
279             isa => Str);
280              
281             sub _build_job_name {
282 28     28   241 my $self = shift;
283 28   33     117 my $name = $self->title || basename($self->file);
284 28         371 return $name;
285             }
286              
287             sub impose {
288 66     66 1 18442 my $self = shift;
289 66         333 my $tmpdir = File::Temp->newdir(CLEANUP => !DEBUG);
290 66 100       26143 if (my $cropmark_paper = $self->paper) {
291 28         41 my %imposer_options = %{ $self->_schema_options };
  28         238  
292             # clone the parameter and set outfile and file
293              
294 28   66     99 $imposer_options{outfile} ||= $self->imposer->output_filename;
295 28         311 my $crop_output = $imposer_options{file} = File::Spec->catfile($tmpdir, 'with-crop-marks.pdf');
296              
297             # pass it to cropmarks
298             my %crop_args = (
299             title => $self->job_name,
300             input => $self->file,
301             output => $crop_output,
302             paper => $cropmark_paper,
303             cover => $imposer_options{cover},
304 28         836 signature => $self->imposer->computed_signature,
305             paper_thickness => $self->paper_thickness,
306             cropmark_offset => $self->cropmark_offset,
307             cropmark_length => $self->cropmark_length,
308             font_size => $self->font_size,
309             $self->imposer->cropmarks_options,
310             );
311 28         54 print Dumper(\%crop_args) if DEBUG;
312              
313             # rebuild the imposer, which should free the memory as well
314 28         669 $self->_set_imposer($self->_schema_class->new(%imposer_options));
315              
316 28         47281 my $cropper = PDF::Cropmarks->new(%crop_args);
317 28         59985 $cropper->add_cropmarks;
318 24         15217114 print "# cropping output in $crop_output\n" if DEBUG;
319 24         124 print Dumper($self->imposer) if DEBUG;
320             }
321             # in any case impose
322 62         16045 return $self->imposer->impose;
323             }
324              
325             =head2 available_schemas
326              
327             Called on the class (not on the object returned by C) will report
328             the list of available schema.
329              
330             E.g.
331              
332             PDF::Imposition->available_schemas;
333              
334             =cut
335              
336             sub available_schemas {
337 13     13 1 339 return qw/2up 2down 2side 2x4x2 1x4x2cutfoldbind
338             4up 1repeat2top 1repeat2side 1repeat4 ea4x4
339             1x8x2 1x1/
340             }
341              
342             =head1 INTERNALS
343              
344             =over 4
345              
346             =item BUILDARGS
347              
348             =item imposer
349              
350             =back
351              
352             =head1 AUTHOR
353              
354             Marco Pessotto, C<< >>
355              
356             =head1 BUGS
357              
358             Please report any bugs or feature requests to the author's email. If
359             you find a bug, please provide a minimal example file which reproduces
360             the problem (so I can add it to the test suite).
361              
362             Or, at your discretion, feel free to use the CPAN's RT.
363              
364             =head1 SUPPORT
365              
366             You can find documentation for this module with the perldoc command.
367              
368             perldoc PDF::Imposition
369              
370             =head1 REPOSITORY
371              
372             L
373              
374             =head1 SEE ALSO
375              
376             =over 4
377              
378             =item psutils
379              
380             L (shipped by any decent
381             GNU/Linux distro and in TeXlive!). If you don't bother the
382             PDF->PS->PDF route, it's a great and useful tool which just aged well.
383              
384             =item pdfpages
385              
386             L
387              
388             =item pdfjam
389              
390             L
391             (buil on the top of pdfpages)
392              
393             =item ConTeXt
394              
395             L
396              
397             The names of schemas are taken straight from the ConTeXt ones (if
398             existing), as described in the book I, by Willi
399             Egger, Hans Hagen and Taco Hoekwater, 2011.
400              
401             =back
402              
403             =head1 TODO
404              
405             The idea is to provide a wide range of imposition schemas (at least
406             the same provided by ConTeXt). This could require some time. If you
407             want to contribute, feel free to fork the repository and send a pull
408             request or a patch (please include documentation and at some tests).
409              
410             =head1 LICENSE
411              
412             This program is free software; you can redistribute it and/or modify
413             it under the terms of either: the GNU General Public License as
414             published by the Free Software Foundation; or the Artistic License.
415              
416             =cut
417              
418             1; # End of PDF::Imposition