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   73849 use strict;
  9         30  
  9         324  
3 9     9   51 use warnings;
  9         21  
  9         329  
4              
5 9     9   678 use Types::Standard qw/Bool/;
  9         77115  
  9         180  
6 9     9   7147 use namespace::clean;
  9         15771  
  9         116  
7              
8 9     9   2941 use Moo;
  9         7020  
  9         85  
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 1226     1226 1 2956 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 34     34 1 1437 my ($self, $pages, $signature) = @_;
127             # if set to 0, get the actual number
128 34   66     283 $signature ||= $self->computed_signature;
129 34   66     672 $pages ||= $self->total_pages;
130 34         428 my $maxpage = $self->total_output_pages;
131 34         89 my @pgs;
132             {
133 9     9   11424 use integer;
  9         139  
  9         55  
  34         74  
134 34         181 for (my $currentpg = 0; $currentpg < $maxpage; $currentpg++) {
135 484         772 my $actualpg = $currentpg - ($currentpg % $signature);
136 484         691 my $modulo = $currentpg % 4;
137 484 100 100     1759 if ($modulo == 0 or $modulo == 3) {
    50 66        
138 242         481 $actualpg += $signature - 1 - (($currentpg % $signature) / 2);
139             }
140             elsif ($modulo == 1 or $modulo == 2) {
141 242         391 $actualpg += ($currentpg % $signature) / 2;
142             }
143 484 100       818 if ($actualpg < $pages) {
144 447         592 $actualpg++;
145             } else {
146 37         60 $actualpg = undef;
147             }
148 484         1021 push @pgs, $actualpg;
149             }
150             }
151 34         89 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 34 100       808 if ($self->cover) {
156 15         162 my $last;
157             my $firstundef;
158              
159             # find the last page
160 15         76 for (my $i = 0; $i < @pgs; $i++) {
161 220 100 100     715 if ($pgs[$i] and $pgs[$i] == $pages) {
162 15         49 $last = $i;
163             }
164             }
165              
166             # find the first empty page (inserted by us)
167 15         77 for (my $i = 0; $i < @pgs; $i++) {
168 130 100       308 if (not defined $pgs[$i]) {
169 6         11 $firstundef = $i;
170 6         20 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         16 $pgs[$firstundef] = $pgs[$last];
178 6         16 $pgs[$last] = undef;
179             }
180             }
181 34         289 while (@pgs) {
182 242         658 push @out, [ shift(@pgs), shift(@pgs) ];
183             }
184 34         136 return \@out;
185             }
186              
187             sub _do_impose {
188 22     22   63 my $self = shift;
189             # prototype
190 22         433 $self->out_pdf_obj->mediabox(
191             $self->orig_width * 2,
192             $self->orig_height,
193             );
194 21         4234 my $seq = $self->page_sequence_for_booklet;
195 21         95 foreach my $p (@$seq) {
196             # loop over the pages
197 150         48563 my $left = $self->get_imported_page($p->[0]);
198 150         5463983 my $right = $self->get_imported_page($p->[1]);
199 150         2746271 my $page = $self->out_pdf_obj->page();
200 150         129252 my $gfx = $page->gfx();
201 150 100       32483 if (defined $left) {
202 138         612 $gfx->formimage($left, 0, 0);
203             }
204 150 100       59762 if (defined $right) {
205 141         764 $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 172 my %options = (
221             top => 1,
222             bottom => 1,
223             inner => 0,
224             outer => 1,
225             twoside => 1,
226             );
227 15         270 return %options;
228             }
229              
230              
231             1;
232              
233             =head1 SEE ALSO
234              
235             L
236              
237             =cut
238