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   17628 use strict;
  9         12  
  9         293  
3 9     9   31 use warnings;
  9         10  
  9         259  
4              
5 9     9   448 use Types::Standard qw/Bool/;
  9         78489  
  9         115  
6 9     9   4440 use namespace::clean;
  9         11929  
  9         72  
7              
8 9     9   2032 use Moo;
  9         6032  
  9         57  
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 2348 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 760 my ($self, $pages, $signature) = @_;
127             # if set to 0, get the actual number
128 33   66     210 $signature ||= $self->computed_signature;
129 33   66     550 $pages ||= $self->total_pages;
130 33         240 my $maxpage = $self->total_output_pages;
131 33         52 my @pgs;
132             {
133 9     9   7717 use integer;
  9         79  
  9         37  
  33         45  
134 33         136 for (my $currentpg = 0; $currentpg < $maxpage; $currentpg++) {
135 476         374 my $actualpg = $currentpg - ($currentpg % $signature);
136 476         327 my $modulo = $currentpg % 4;
137 476 100 100     1474 if ($modulo == 0 or $modulo == 3) {
    50 66        
138 238         252 $actualpg += $signature - 1 - (($currentpg % $signature) / 2);
139             }
140             elsif ($modulo == 1 or $modulo == 2) {
141 238         199 $actualpg += ($currentpg % $signature) / 2;
142             }
143 476 100       467 if ($actualpg < $pages) {
144 439         269 $actualpg++;
145             } else {
146 37         37 $actualpg = undef;
147             }
148 476         640 push @pgs, $actualpg;
149             }
150             }
151 33         47 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       548 if ($self->cover) {
156 15         94 my $last;
157             my $firstundef;
158              
159             # find the last page
160 15         54 for (my $i = 0; $i < @pgs; $i++) {
161 220 100 100     664 if ($pgs[$i] and $pgs[$i] == $pages) {
162 15         34 $last = $i;
163             }
164             }
165              
166             # find the first empty page (inserted by us)
167 15         52 for (my $i = 0; $i < @pgs; $i++) {
168 130 100       237 if (not defined $pgs[$i]) {
169 6         7 $firstundef = $i;
170 6         10 last;
171             }
172             }
173              
174             # if we don't find a white page, there is nothing to do
175 15 100       42 if (defined $firstundef) {
176             # there is an undef, so swap;
177 6         10 $pgs[$firstundef] = $pgs[$last];
178 6         10 $pgs[$last] = undef;
179             }
180             }
181 33         170 while (@pgs) {
182 238         476 push @out, [ shift(@pgs), shift(@pgs) ];
183             }
184 33         87 return \@out;
185             }
186              
187             sub _do_impose {
188 22     22   44 my $self = shift;
189             # prototype
190 22         351 $self->out_pdf_obj->mediabox(
191             $self->orig_width * 2,
192             $self->orig_height,
193             );
194 21         2216 my $seq = $self->page_sequence_for_booklet;
195 21         55 foreach my $p (@$seq) {
196             # loop over the pages
197 150         23724 my $left = $self->get_imported_page($p->[0]);
198 150         3281688 my $right = $self->get_imported_page($p->[1]);
199 150         1602891 my $page = $self->out_pdf_obj->page();
200 150         40334 my $gfx = $page->gfx();
201 150 100       15092 if (defined $left) {
202 138         394 $gfx->formimage($left, 0, 0);
203             }
204 150 100       29261 if (defined $right) {
205 141         469 $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 107 my %options = (
221             top => 1,
222             bottom => 1,
223             inner => 0,
224             outer => 1,
225             twoside => 1,
226             );
227 15         208 return %options;
228             }
229              
230              
231             1;
232              
233             =head1 SEE ALSO
234              
235             L
236              
237             =cut
238