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