File Coverage

blib/lib/PDF/Imposition/Schema2up.pm
Criterion Covered Total %
statement 65 65 100.0
branch 17 18 94.4
condition 12 15 80.0
subroutine 10 10 100.0
pod 3 3 100.0
total 107 111 96.4


line stmt bran cond sub pod time code
1             package PDF::Imposition::Schema2up;
2 9     9   80375 use strict;
  9         36  
  9         296  
3 9     9   49 use warnings;
  9         18  
  9         317  
4              
5 9     9   712 use Types::Standard qw/Bool/;
  9         88682  
  9         137  
6 9     9   6826 use namespace::clean;
  9         17477  
  9         85  
7              
8 9     9   2915 use Moo;
  9         8384  
  9         74  
9             with 'PDF::Imposition::Schema';
10              
11              
12              
13             =head1 NAME
14              
15             PDF::Imposition::Schema2up - Imposition schema 2up (booklet)
16              
17             =head1 SYNOPSIS
18              
19             use PDF::Imposition::Schema2up;
20             my $imposer = PDF::Imposition::Schema2up->new(
21             signature => "10-20",
22             file => "test.pdf",
23             output => "out.pdf",
24             cover => 1,
25             );
26             # or call the methods below to set the values, and then call:
27             $imposer->impose;
28              
29             The output pdf will be in C<$imposer->output>
30              
31             =head1 SCHEMA EXPLANATION
32              
33             This schema is a variable and dynamic method. The signature, i.e., the
34             booklets which compose the document, are not fixed-sized, but can be
35             altered. The purpose is to have 1 or more booklets that you print
36             recto-verso and just fold to have your home-made book (this schema is
37             aimed to DIY people).
38              
39             Say you have a text with 60 pages in A5: you would print it on A4,
40             double-side, take the pile out of the printer, fold it and clip it.
41              
42             The schema looks like (for a signature of 8 pages on 2 sheets):
43              
44             RECTO S.1 VERSO S.1
45             +-----+-----+ +-----+-----+
46             | | | | | |
47             | 8 | 1 | | 2 | 7 |
48             | | | | | |
49             +-----+-----+ +-----+-----+
50              
51             RECTO S.2 VERSO S.2
52             +-----+-----+ +-----+-----+
53             | | | | | |
54             | 6 | 3 | | 4 | 5 |
55             | | | | | |
56             +-----+-----+ +-----+-----+
57              
58             =head1 METHODS
59              
60             =head2 Public methods
61              
62             =head3 signature
63              
64             The signature, must be a multiple of 4, or a range, like the string
65             "20-100". If a range is selected, the signature is determined
66             heuristically to minimize the white pages left on the last signature.
67             The wider the range, the best the results.
68              
69             This is useful if you are doing batch processing, and you don't know
70             the number of page in advance (so you can't tweak the source pdf to
71             have a suitable number of page via text-block dimensions or font
72             changes).
73              
74             Typical case: you define a signature of 60 pages, and your PDF happens
75             to have 61 pages. How unfortunate, and you just can't put out a PDF
76             with 59 blank pages. The manual solution is to change something in the
77             document to get it under 60 pages, but this is not always viable or
78             desirable. So you define a dynamic range for signature, like 20-60,
79             (so the signature will vary between 20 and 60) and the routine will
80             find the best one, which in this particular case happens to be 32 (so
81             the text will have two booklets, and the second will have 3 blank
82             pages).
83              
84             Es.
85              
86             $imposer->signature("20-60");
87              
88             Keep in mind that a signature with more than 100 pages is not suitable
89             to be printed and folded at home (too thick), so to get some
90             acceptable result, the sheets must be cut and glued together by a
91             binder, so in this case you want to go with the single signature for
92             the whole pdf.
93              
94             If no signature is specified, the whole text will be imposed on a
95             single signature, regardeless of its size.
96              
97              
98             =cut
99              
100 1224     1224 1 3397 sub pages_per_sheet { 4 };
101              
102             =head3 cover
103              
104             This schema supports the cover option.
105              
106             =cut
107              
108             has cover => (is => 'rw', isa => Bool);
109              
110              
111             =head2 INTERNALS
112              
113             =head3 pages_per_sheet
114              
115             Always return 4.
116              
117             =head3 page_sequence_for_booklet($pages, $signature)
118              
119             Algorithm taken/stolen from C (Angus J. C. Duggan 1991-1995).
120             The C are still a viable solution if you want to go with the
121             PDF->PS->PDF route.
122              
123             =cut
124              
125             sub page_sequence_for_booklet {
126 33     33 1 1277 my ($self, $pages, $signature) = @_;
127             # if set to 0, get the actual number
128 33   66     258 $signature ||= $self->computed_signature;
129 33   66     672 $pages ||= $self->total_pages;
130 33         369 my $maxpage = $self->total_output_pages;
131 33         76 my @pgs;
132             {
133 9     9   10287 use integer;
  9         124  
  9         48  
  33         72  
134 33         149 for (my $currentpg = 0; $currentpg < $maxpage; $currentpg++) {
135 476         699 my $actualpg = $currentpg - ($currentpg % $signature);
136 476         652 my $modulo = $currentpg % 4;
137 476 100 100     1631 if ($modulo == 0 or $modulo == 3) {
    50 66        
138 238         414 $actualpg += $signature - 1 - (($currentpg % $signature) / 2);
139             }
140             elsif ($modulo == 1 or $modulo == 2) {
141 238         384 $actualpg += ($currentpg % $signature) / 2;
142             }
143 476 100       747 if ($actualpg < $pages) {
144 439         544 $actualpg++;
145             } else {
146 37         58 $actualpg = undef;
147             }
148 476         949 push @pgs, $actualpg;
149             }
150             }
151 33         73 my @out;
152             # if we want a cover, we need to find the index of the last page,
153             # and the first undef page, which could be at the beginning of the
154             # last signature, so we have to scan the array.
155 33 100       809 if ($self->cover) {
156 15         147 my $last;
157             my $firstundef;
158              
159             # find the last page
160 15         75 for (my $i = 0; $i < @pgs; $i++) {
161 220 100 100     734 if ($pgs[$i] and $pgs[$i] == $pages) {
162 15         47 $last = $i;
163             }
164             }
165              
166             # find the first empty page (inserted by us)
167 15         66 for (my $i = 0; $i < @pgs; $i++) {
168 130 100       307 if (not defined $pgs[$i]) {
169 6         15 $firstundef = $i;
170 6         13 last;
171             }
172             }
173              
174             # if we don't find a white page, there is nothing to do
175 15 100       57 if (defined $firstundef) {
176             # there is an undef, so swap;
177 6         17 $pgs[$firstundef] = $pgs[$last];
178 6         15 $pgs[$last] = undef;
179             }
180             }
181 33         254 while (@pgs) {
182 238         659 push @out, [ shift(@pgs), shift(@pgs) ];
183             }
184 33         122 return \@out;
185             }
186              
187             sub _do_impose {
188 22     22   55 my $self = shift;
189             # prototype
190 22         471 $self->out_pdf_obj->mediabox(
191             $self->orig_width * 2,
192             $self->orig_height,
193             );
194 21         3690 my $seq = $self->page_sequence_for_booklet;
195 21         95 foreach my $p (@$seq) {
196             # loop over the pages
197 150         54813 my $left = $self->get_imported_page($p->[0]);
198 150         5366640 my $right = $self->get_imported_page($p->[1]);
199 150         2829766 my $page = $self->out_pdf_obj->page();
200 150         94944 my $gfx = $page->gfx();
201 150 100       34555 if (defined $left) {
202 138         689 $gfx->formimage($left, 0, 0);
203             }
204 150 100       67271 if (defined $right) {
205 141         821 $gfx->formimage($right, $self->orig_width, 0);
206             }
207             }
208             }
209              
210             =head1 INTERNALS
211              
212             =head2 cropmarks_options
213              
214             Set inner to false.
215              
216             =cut
217              
218              
219             sub cropmarks_options {
220 15     15 1 158 my %options = (
221             top => 1,
222             bottom => 1,
223             inner => 0,
224             outer => 1,
225             twoside => 1,
226             );
227 15         246 return %options;
228             }
229              
230              
231             1;
232              
233             =head1 SEE ALSO
234              
235             L
236              
237             =cut
238