3
pdftools.pdfposter.cmd - scale and tile PDF images/pages to print on multiple pages.
6
# Copyright 2008-2013 by Hartmut Goebel <h.goebel@crazy-compilers.com>
8
# This program is free software: you can redistribute it and/or modify
9
# it under the terms of the GNU General Public License as published by
10
# the Free Software Foundation, either version 3 of the License, or
11
# (at your option) any later version.
13
# This program is distributed in the hope that it will be useful, but
14
# WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
# General Public License for more details.
18
# You should have received a copy of the GNU General Public License
19
# along with this program. If not, see <http://www.gnu.org/licenses/>.
22
__author__ = "Hartmut Goebel <h.goebel@crazy-compilers.com>"
23
__copyright__ = "Copyright 2008-2013 by Hartmut Goebel <h.goebel@crazy-compilers.com>"
24
__licence__ = "GNU General Public License version 3 (GPL v3)"
26
from . import main, __version__, DEFAULT_MEDIASIZE, papersizes, DecryptionError
30
# pattern for parsing user textual box spec
31
pat_box = re.compile(r'''
32
( (?P<width> (\d*\.)? \d+) x # width "x" height
33
(?P<height> (\d*\.)? \d+) )?
34
(?P<offset> \+ # "+" offset_x "," offset_y
35
(?P<offset_x> \d+\.? | \d*\.\d+)
37
(?P<offset_y> \d+\.? | \d*\.\d+) ) ?
38
(?P<unit> [a-z][a-z0-9\-\\_]*) # unit
41
def __parse_box(option, value, parser, allow_offset=False):
42
m = pat_box.match(value)
44
raise parser.error("I don't understand your box specification %r for %s" % (value, option))
46
if not allow_offset and res['offset'] is not None:
47
raise parser.error('Offset not allowed in box definition for %s' % option)
48
# res['offset'] is only used for error checking, remove it
51
# get meassures of unit
52
unit = res['unit'].lower()
53
if not papersizes.has_key(unit):
54
unit = [name for name in papersizes.keys()
55
if name.startswith(unit)]
57
parser.error("I don't understand your papersize name %r for %s." % (res['unit'], option))
59
parser.error('Your papersize name %r for %s is not unique, give more chars.' % (res['unit'], option))
61
unit_x, unit_y = papersizes[unit]
63
'width' : float(res['width'] or 1) * unit_x,
64
'height' : float(res['height'] or 1) * unit_y,
65
'offset_x': float(res['offset_x'] or 0) * unit_x,
66
'offset_y': float(res['offset_y'] or 0) * unit_y,
68
'units_x': float(res['width'] or 1),
69
'units_y': float(res['height'] or 1),
73
def _parse_box(option, opt, value, parser, allow_offset=False):
74
res = __parse_box(option, value, parser, allow_offset=False)
75
setattr(parser.values, option.dest, res)
79
parser = optparse.OptionParser('%prog [options] InputFile OutputFile',
81
parser.add_option('--help-media-names', action='store_true',
82
help='List available media and distance names')
83
parser.add_option('-v', '--verbose', action='count', default=0,
84
help='Be verbose. Tell about scaling, rotation and number of pages. Can be used more than once to increase the verbosity. ')
85
parser.add_option('-n', '--dry-run', action='store_true',
86
help='Show what would have been done, but do not generate files.')
88
parser.add_option('-A', '--art-box',
89
action='store_true', dest='use_ArtBox',
90
help='Use the content area defined by the ArtBox '
91
'(default: use the area defined by the TrimBox)')
93
group = parser.add_option_group('Define Target')
94
group.add_option('-m', '--media-size',
95
default=__parse_box('-m', DEFAULT_MEDIASIZE, parser),
96
action='callback', type='string', callback=_parse_box,
97
help='Specify the size of the output media size (default: %s)' % DEFAULT_MEDIASIZE)
98
group.add_option('-p', '--poster-size',
99
action='callback', type='string', callback=_parse_box,
100
help='Specify the poster size (defaults to media size). ')
101
group.add_option('-s', '--scale', type=float,
102
help='Specify a linear scaling factor to produce the poster.')
104
opts, args = parser.parse_args()
106
if opts.help_media_names:
107
names = papersizes.keys()
110
print parser.formatter.format_heading('Available media and distance names')
111
parser.formatter.indent()
112
print parser.formatter.format_description(' '.join(names))
116
parser.error('requires both input and output filename')
117
if opts.scale is not None and opts.poster_size is not None:
118
parser.error('Only one of -p/--poster-size and -s/--scale may be given at a time.')
119
if not opts.poster_size:
120
opts.poster_size = opts.media_size.copy()
121
if opts.scale is not None:
122
opts.poster_size = None
123
if opts.scale < 0.01:
124
parser.error("Scale value is much to small: %s" % opts.scale)
125
elif opts.scale > 1.0e6:
126
parser.error("Scale value is much to big: %s" % opts.scale)
130
except DecryptionError, e:
131
raise SystemExit(str(e))
132
except pyPdf.utils.PdfReadError:
133
parser.error('The input-file is either currupt or no PDF at all.')
136
if __name__ == '__main__':