1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
|
#!/usr/bin/perl -w
# pdftops.pl - wrapper script for xpdf's pdftops utility to act as a CUPS filter
# ==============================================================================
# 1.00 - 2004-10-05/Bl
# Initial implementation
# 1.10 - 2006-09-27/Bl
# Alternatively, use Adobe Reader in place of Xpdf's pdftops
# 1.20 - 2007-12-03/Bl
# Safe temp file creation (fix gentoo bug # 201042)
#
# Copyright: Helge Blischke / SRZ Berlin 2004-2006
# This program is free seoftware and governed by the GNU Public License Version 2.
#
# Description:
# ------------
# This program wraps the pdftops utility from the xpdf 3.00 (and higher) suite
# to behave as a CUPS filter as a replacement for the original pdftops filter.
# As an alternative the Adobe Reader may be used.
#
# The main purpose of this approach is to keep the properties of a PDF to be
# printed as undesturbed as possible, especially with respect to page size,
# scaling, and positioning.
#
# The pdftops utility reads a configuration file 'pdftops.conf' or 'acroread.conf',
# respectively, in the CUPS_SERVERROOT directory, which must exist but may be empty.
# The sample configuration file accompanying this program sets the defaults which
# seem plausible to me with respect to high end production printers.
#
# To give the user highest possible flexibility, this program accepts and
# evaluates a set of job attributes special to this filter, which are
# described below:
#
# pdf-pages=<f>,<l>
# expands to the -f and -l options of pdftops
# or the -start and -end options of acroread, respectively
# to select a page range to process. This is independent
# of the page-ranges attribute and may significantly
# increase throughput when printing page ranges.
# Either of these numbers may be omitted.
#
# pdf-paper=<name>
# For pdftops, <name> may be one of "letter", "legal",
# "A4", "A3", or "match"; for acroread, the permetted values
# are "letter", "legal", "tabloid", "ledger", "executive",
# "a3", "a4", "a5", "b4", "b5", respectively (without the
# quotes; the names are treated case independent).
# In case of acroread, no paper specification is equivalent
# to pdsftops's "match".
# pdf-paper=<width>x<height>
# <name> may be one of letter, legal , A4, A3, or match;
# <width> and <height> are the paper width and height
# in printers points (1/72 inch). This expands to
# either the -paper or the -paperh and -paperw options
# of pdftops or the -size option of acroread.
#
# pdf-opw=<password>
# pdf-upw=<password>
# expand to the -opw and -upw options of pdftops,
# respectively and permit printing of password
# protected PDFs.
#
# pdf-<option> where <option> is one of
# level1, level1sep, level2, level2sep, level3, level3sep,
# opi, nocrop, expand, noshrink, nocenter.
# See the pdftops manpage for a detailed description of
# the respective options.
# In case of acroread, the options level1, level?sep, opi,
# nocrop, noshrink, and nocenter are silently ignored.
#
# All other pdftops commandline options are refused.
#
# The return code of the pdftops utility or acroread, if nonzero, is used as the exit code
# of this program; error messages of the pdftops utility are only visible
# if 'debug' is specified as LogLevel in cupsd.conf.
#
# NOTE:
# -----
# This wrapper script has been initially designed to use the original pdftops utility
# as a CUPS filter and now extended to alternately use acroread.
# But there are situations where you need to be able to select either variant, thus it
# is possible to configure the wrapper to both programs but select one of them by default;
# the other one then may be selected by command line option:
#
# use-pdftops selects pdftops
# use-acroread selects acroread
#
# if both are configured (by defining the appropriate configuration file).
#
#
# Site specific parameters - modify as needed
# ----------------------------------------------------------------------------------
$pdftops_path = "/usr/bin/pdftops"; # path to the xpdf utility
$acroread_path = "/opt/bin/acroread"; # path to Adobe Reader
$default_app = 'use-pdftops'; # the default if both are configured
$use_pdftops = 1; # default on gentoo and highly recommended
$use_acroread = 0; # not supported/working on gentoo yet, use at your own risk
# ----------------------------------------------------------------------------------
use File::Temp qw( tempfile );
#
# Check which app to use - pdftops or acroread
#
$rootdir = $ENV{CUPS_SERVERROOT} || die ("ERROR: CUPS server root directory undefined\n");
$use_both = $use_pdftops && $use_acroread;
#
# Check the arguments
#
die ("ERROR: wrong number of arguments\n") if (scalar @ARGV < 5);
$jobid = $username = $title = $copies = undef;
$jobid = shift; # Job ID
$username = shift; # Job requesting user name
$title = shift; # Job title
$copies = shift; # Number of requested copies
$options = shift; # Textual representation of job attributes
$pdffile = shift; # Pathname of PDF file to process
if (defined $use_both && $use_both)
{
my $optstr = " $options ";
my $to_use = '';
if ($optstr =~ /\s+(use-acroread|use-pdftops)\s+/)
{
$to_use = $1;
}
else
{
$to_use = $default_app;
}
if ($to_use eq 'use-acroread')
{
undef $use_pdftops;
}
elsif ($to_use eq 'use-pdftops')
{
undef $use_acroread;
}
else
{
die ("ERROR: cannot use both pdftops and acroread simultaneously\n");
}
}
if (defined $use_pdftops)
{
# If we are reading from STDIN, we must copy the input to a temporary file
# as the PDF consumer needs a seekable input.
if (! defined $pdffile)
{
my $template = "pdfinXXXXXX";
my $tmpdir = $ENV{TMPDIR};
my ($bytes, $buffer);
my ($tmpfh, $tmpfile) = tempfile ($template, OPEN => 1, DIR => $tmpdir, UNLINK => 0, SUFFIX => '.tmp');
while (($bytes = read (STDIN, $buffer, 1024)) > 0)
{
print $tmpfh "$buffer";
}
if ($bytes < 0)
{
close ($tmpfh);
unlink $tmpfile;
die ("ERROR: pdftops wrapper: $tmpfile: $!\n");
}
close ($tmpfh);
$pdffile = $tmpfile;
$delete_input = 1; # for deleting the temp file after converting
}
}
#
# Check the options string for options to modify the bahaviour of the pdftops utility:
#
@optarr = split (/\s+/, $options);
if (defined $use_pdftops)
{
$cmdopt = ""; # do not pass the -cfg argument to the poppler pdftops util
# The following are the (parameterless) command line options that may be used to change the
# defaults defiend by pdftops.conf
$simple = 'level1|level1sep|level2|level2sep|level3|level3sep|opi|nocrop|expand|noshrink|nocenter';
%papernames = (
'letter' => '-paper letter',
'tabloid' => '-paperw 792 -paperh 1224',
'ledger' => '-paperw 1224 -paperh 792',
'legal' => '-paper legal',
'executive' => '-paperw 756 -paperh 522',
'a3' => '-paper A3',
'a4' => '-paper A4',
'a5' => '-paperw 421 -paperh 595',
'b4' => '-paperw 709 -paperh 1002',
'b5' => '-paperw 501 -paperh 709',
'match' => '-paper match'
);
}
else
{
open (CFG, "<$rootdir/acroread.conf") || die ("ERROR: acroread.conf: $!\n");
$cmdopt = '-toPostScript';
while (<CFG>)
{
chomp;
next if (/^\s*#/); # skip comment lines
next if (/^\s*$/); # skip blank lines
s/^-\s*//; # discard leading '-' and white space, as it will be generated later
s/\s+$//; # discard trailing white space
$cmdopt .= " -$_";
}
close (CFG);
$simple = 'level1|level1sep|level2|level2sep|level3|level3sep|opi|nocrop|expand|noshrink|nocenter';
%papernames = (
'letter' => '-size letter',
'tabloid' => '-size tabloid',
'ledger' => '-size ledger',
'legal' => '-size legal',
'executive' => '-size executive',
'a3' => '-size a3',
'a4' => '-size a4',
'a5' => '-size a5',
'b4' => '-size b4',
'b5' => '-size b5',
'match' => '' # this is the default with acroread
);
}
foreach my $option (@optarr)
{
if ($option =~ /^pdf-(.+)$/)
{ # We assume this is an option to evaluate
my $optkey = $1; # possible pdftops option
if ($optkey =~ /^pages=(\d*),(\d*)$/)
{
# We do this hack here to avoid clashes with the page-ranges atrribute
# which is handled by the pstops filter. And we allow one of the numbers
# to be omitted.
my $first = $1;
my $lastp = $2;
if (defined $use_pdftops)
{
$cmdopt .= " -f $1" if ($1); # first page
$cmdopt .= " -l $2" if ($2); # last page
}
else
{
$cmdopt .= " -start $1" if ($1); # first page
$cmdopt .= " -end $2" if ($2); # last page
}
}
elsif ($optkey =~ /^paper=(letter|tabloid|ledger|legal|[Aa]3|[Aa]4|[Aa]5|[Bb]4|[Bb]5|match)$/)
{
# evaluate paper name
my $paper = $1;
$paper =~ tr/A-Z/a-z/;
my $value = $papernames{$paper};
$cmdopt .= " $value" if ($value);
}
elsif ($optkey =~ /^paper=(\d+)x(\d+)$/)
{
# evaluate paper dimensions
if (defined $use_pdftops)
{
$cmdopt .= " -paperw $1 -paperh $2";
}
else
{
$cmdopt .= " -size $1" . 'x' . "$2";
}
}
elsif ($optkey =~ /^(o|u)pw=(\S+)$/)
{
$cmdopt .= " $1" . 'pw ' . $2 if (defined $use_pdftops); # owner/user password
}
elsif ($optkey =~ /^($simple)$/)
{
my $thisopt = $1;
if (defined $use_pdftops)
{
$cmdopt .= ' -' . $1; # allowed simple options
}
else
{
$thisopt =~ s/sep$//; # ignore the ...sep suffix
if ($thisopt =~ /level1|opi|nocrop|nocenter/)
{
$thisopt = '';
}
elsif ($thisopt eq 'noshrink')
{
$thisopt = '';
$cmdopt =~ s/ -shrink//;
}
$cmdopt .= " -" . $thisopt if ($thisopt);
}
}
else
{
warn ("ERROR: pdftops wrapper: illegal attribute \"pdf-$optkey\"\n");
}
}
# All other attributes are processed elsewhere
}
#
# Complete the command
#
if (defined $use_pdftops)
{
warn ("ERROR: pdftops-options: $cmdopt\n");
}
else
{
warn ("ERROR: acroread-options: $cmdopt\n");
}
if (defined $use_pdftops)
{
$rc = system ("$pdftops_path $cmdopt $pdffile -");
}
else
{
if (defined $pdffile && $pdffile)
{
$rc = system ("$acroread_path $cmdopt < $pdffile")
}
else
{
$rc = system ("$acroread_path $cmdopt");
}
}
if ($rc)
{
$ir = $rc & 127;
$rc >>= 8;
my $temp = (defined $use_pdftops) ? $pdftops_path : $acroread_path;
warn ("ERROR: $temp exited with ", ($ir) ? "signal $ir, " : " exit code $rc", "\n");
exit $rc;
}
unlink ($pdffile) if (defined $delete_input); # Delete the temp file if any
exit 0;
|