diff options
30 files changed, 754 insertions, 1 deletions
diff --git a/Build/source/texk/texlive/linked_scripts/Makefile.am b/Build/source/texk/texlive/linked_scripts/Makefile.am index 09e66a19753..3f84ef1b853 100644 --- a/Build/source/texk/texlive/linked_scripts/Makefile.am +++ b/Build/source/texk/texlive/linked_scripts/Makefile.am @@ -140,6 +140,7 @@ texmf_other_scripts = \ musixtex/musixtex.lua \ oberdiek/pdfatfi.pl \ pax/pdfannotextractor.pl \ + pdfbook2/pdfbook2 \ pdfcrop/pdfcrop.pl \ pedigree-perl/pedigree.pl \ perltex/perltex.pl \ diff --git a/Build/source/texk/texlive/linked_scripts/Makefile.in b/Build/source/texk/texlive/linked_scripts/Makefile.in index bfba303b51f..a5650b423ac 100644 --- a/Build/source/texk/texlive/linked_scripts/Makefile.in +++ b/Build/source/texk/texlive/linked_scripts/Makefile.in @@ -358,6 +358,7 @@ texmf_other_scripts = \ musixtex/musixtex.lua \ oberdiek/pdfatfi.pl \ pax/pdfannotextractor.pl \ + pdfbook2/pdfbook2 \ pdfcrop/pdfcrop.pl \ pedigree-perl/pedigree.pl \ perltex/perltex.pl \ diff --git a/Build/source/texk/texlive/linked_scripts/pdfbook2/pdfbook2 b/Build/source/texk/texlive/linked_scripts/pdfbook2/pdfbook2 new file mode 100755 index 00000000000..a288df70fd5 --- /dev/null +++ b/Build/source/texk/texlive/linked_scripts/pdfbook2/pdfbook2 @@ -0,0 +1,237 @@ +#!/usr/bin/env python +""" pdfbook2 - transform pdf files to booklets + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + """ + + +import sys +import subprocess +import os +from optparse import OptionParser, OptionGroup, HelpFormatter +import shutil + + +#=============================================================================== +# Create booklet for file $name +#=============================================================================== + +def booklify( name, opts ): + #------------------------------------------------------ Check if file exists + print "\nProcessing", name + if not os.path.isfile( name ): + print "SKIP: file not found." + return + print "Getting bounds...", + sys.stdout.flush() + + #---------------------------------------------------------- useful constants + bboxName = "%%HiResBoundingBox:" + tmpFile = ".crop-tmp.pdf" + + #------------------------------------------------- find min/max bounding box + if opts.crop: + p = subprocess.Popen( ["pdfcrop", "--verbose", + "--resolution", repr( opts.resolution ), + name, tmpFile], + stdout = subprocess.PIPE, + stderr = subprocess.PIPE ) + p.wait() + out, err = p.communicate() + if len( err ) != 0: + print err + print "\n\nABORT: Problem getting bounds" + sys.exit( 1 ) + lines = out.splitlines() + bboxes = [s[len( bboxName ) + 1:] for s in lines if s.startswith( bboxName )] + bounds = [[float( x ) for x in bbox.split()] for bbox in bboxes ] + minLOdd = min( [bound[0] for bound in bounds[::2] ] ) + maxROdd = max( [bound[2] for bound in bounds[::2] ] ) + minLEven = min( [bound[0] for bound in bounds[1::2] ] ) + maxREven = max( [bound[2] for bound in bounds[1::2] ] ) + minT = min( [bound[1] for bound in bounds ] ) + maxB = max( [bound[3] for bound in bounds ] ) + + widthOdd = maxROdd - minLOdd + widthEven = maxREven - minLEven + maxWidth = max( widthOdd, widthEven ) + minLOdd -= maxWidth - widthOdd + maxREven += maxWidth - widthEven + + print "done" + sys.stdout.flush() + + #--------------------------------------------- crop file to area of interest + print "cropping...", + sys.stdout.flush() + p = subprocess.Popen( ["pdfcrop", + "--bbox-odd", "{L} {T} {R} {B}".format( L = minLOdd - opts.innerMargin / 2, + T = minT - opts.topMargin, + R = maxROdd + opts.outerMargin, + B = maxB + opts.outerMargin ), + "--bbox-even", "{L} {T} {R} {B}".format( L = minLEven - opts.outerMargin, + T = minT - opts.topMargin, + R = maxREven + opts.innerMargin / 2, + B = maxB + opts.outerMargin ), + "--resolution", repr( opts.resolution ), + name, + tmpFile], + stdout = subprocess.PIPE, + stderr = subprocess.PIPE ) + p.wait() + out, err = p.communicate() + if len( err ) != 0: + print err + print "\n\nABORT: Problem with cropping" + sys.exit( 1 ) + print "done" + sys.stdout.flush() + else: + shutil.copy( name, tmpFile ) + + #-------------------------------------------------------- create the booklet + print "create booklet...", + sys.stdout.flush() + pdfJamCallList = [ "pdfjam", + "--booklet", "true", + "--landscape", + "--suffix", "book", + "--signature", repr( opts.signature ), + tmpFile ] + + # add option --paper to call + if opts.paper is not None: + pdfJamCallList.append( "--paper" ) + pdfJamCallList.append( opts.paper ) + + # add option --short-edge to call + if opts.shortedge: + # check if everyshi.sty exists as texlive recommends + p = subprocess.Popen( ["kpsewhich", "everyshi.sty"], + stdout = subprocess.PIPE, + stderr = subprocess.PIPE ) + p.wait() + out, err = p.communicate() + if len( out ) == 0: + print "\n\nABORT: The everyshi.sty latex package is needed for short-edge." + sys.exit( 1 ) + else: + pdfJamCallList.append( "--preamble" ) + pdfJamCallList.append( r"\usepackage{everyshi}\makeatletter\EveryShipout{\ifodd\c@page\pdfpageattr{/Rotate 180}\fi}\makeatother" ) + + # run call to pdfJam to make booklet + p = subprocess.Popen( pdfJamCallList, + stdout = subprocess.PIPE, + stderr = subprocess.PIPE ) + p.wait() + + #-------------------------------------------- move file and remove temp file + os.rename( tmpFile[:-4] + "-book.pdf", name[:-4] + "-book.pdf" ) + os.remove( tmpFile ) + print "done" + sys.stdout.flush() + + +#=============================================================================== +# Help formatter +#=============================================================================== + +class MyHelpFormatter ( HelpFormatter ): + """Format help with indented section bodies. + """ + + def __init__( self, + indent_increment = 4, + max_help_position = 16, + width = None, + short_first = 0 ): + HelpFormatter.__init__( + self, indent_increment, max_help_position, width, short_first ) + + def format_usage( self, usage ): + return ( "USAGE\n\n%*s%s\n" ) % ( self.indent_increment, "", usage ) + + def format_heading( self, heading ): + return "%*s%s\n\n" % ( self.current_indent, "", heading.upper() ) + + +#=============================================================================== +# main programm +#=============================================================================== + +if __name__ == "__main__": + #------------------------------------------------------------ useful strings + usageString = "Usage: %prog [options] file1 [file2 ...]" + versionString = """ + %prog v1.2 + (c) 2015 Johannes Neumann (http://www.neumannjo.de) + licensed under GPLv3 (http://www.gnu.org/licenses/gpl-3.0) + based on pdfbook by David Firth with help from Marco Pessotto\n""" + defaultString = " (default: %default)" + + #------------------------------------------------- create commandline parser + parser = OptionParser( usage = usageString, version = versionString, + formatter = MyHelpFormatter( indent_increment = 4 ) ) + + generalGroup = OptionGroup( parser, "General" ) + generalGroup.add_option( "-p", "--paper", dest = "paper", type = "str", action = "store", + metavar = "STR", + help = "Format of the output paper dimensions as latex keyword (e.g. a4paper, letterpaper, legalpaper, ...)" ) + generalGroup.add_option( "-s", "--short-edge", dest = "shortedge", action = "store_true", + help = "Format the booklet for short-edge double-sided printing", + default = False ) + generalGroup.add_option( "-n", "--no-crop", dest = "crop", action = "store_false", + help = "Prevent the cropping to the content area", + default = True ) + parser.add_option_group( generalGroup ) + + marginGroup = OptionGroup( parser, "Margins" ) + marginGroup.add_option( "-o", "--outer-margin", type = "int", default = 40, + dest = "outerMargin", action = "store", metavar = "INT", + help = "Defines the outer margin in the booklet" + defaultString ) + marginGroup.add_option( "-i", "--inner-margin", type = "int", default = 150, + dest = "innerMargin", action = "store", metavar = "INT", + help = "Defines the inner margin between the pages in the booklet" + defaultString ) + marginGroup.add_option( "-t", "--top-margin", type = "int", default = 30, + dest = "topMargin", action = "store", metavar = "INT", + help = "Defines the top margin in the booklet" + defaultString ) + marginGroup.add_option( "-b", "--bottom-margin", type = "int", default = 30, metavar = "INT", + dest = "bottomMargin", action = "store", + help = "Defines the bottom margin in the booklet" + defaultString ) + parser.add_option_group( marginGroup ) + + advancedGroup = OptionGroup( parser, "Advanced" ) + advancedGroup.add_option( "--signature", dest = "signature", action = "store", type = "int", + help = "Define the signature for the booklet handed to pdfjam, needs to be multiple of 4" + defaultString, + default = 4, metavar = "INT" ) + advancedGroup.add_option( "--signature*", dest = "signature", action = "store", type = "int", + help = "Same as --signature", metavar = "INT" ) + advancedGroup.add_option( "--resolution", dest = "resolution", action = "store", type = "int", + help = "Resolution used by ghostscript in bp" + defaultString, + metavar = "INT", default = 72 ) + parser.add_option_group( advancedGroup ) + + opts, args = parser.parse_args() + + #------------------------------------ show help if started without arguments + if len( args ) == 0: + parser.print_version() + parser.print_help() + print "" + sys.exit( 2 ) + + #------------------------------------------- run for each provided file name + parser.print_version() + for arg in args: + booklify( arg, opts ) diff --git a/Master/bin/alpha-linux/pdfbook2 b/Master/bin/alpha-linux/pdfbook2 new file mode 120000 index 00000000000..bb39290d77a --- /dev/null +++ b/Master/bin/alpha-linux/pdfbook2 @@ -0,0 +1 @@ +../../texmf-dist/scripts/pdfbook2/pdfbook2
\ No newline at end of file diff --git a/Master/bin/amd64-freebsd/pdfbook2 b/Master/bin/amd64-freebsd/pdfbook2 new file mode 120000 index 00000000000..bb39290d77a --- /dev/null +++ b/Master/bin/amd64-freebsd/pdfbook2 @@ -0,0 +1 @@ +../../texmf-dist/scripts/pdfbook2/pdfbook2
\ No newline at end of file diff --git a/Master/bin/amd64-netbsd/pdfbook2 b/Master/bin/amd64-netbsd/pdfbook2 new file mode 120000 index 00000000000..bb39290d77a --- /dev/null +++ b/Master/bin/amd64-netbsd/pdfbook2 @@ -0,0 +1 @@ +../../texmf-dist/scripts/pdfbook2/pdfbook2
\ No newline at end of file diff --git a/Master/bin/armel-linux/pdfbook2 b/Master/bin/armel-linux/pdfbook2 new file mode 120000 index 00000000000..bb39290d77a --- /dev/null +++ b/Master/bin/armel-linux/pdfbook2 @@ -0,0 +1 @@ +../../texmf-dist/scripts/pdfbook2/pdfbook2
\ No newline at end of file diff --git a/Master/bin/armhf-linux/pdfbook2 b/Master/bin/armhf-linux/pdfbook2 new file mode 120000 index 00000000000..bb39290d77a --- /dev/null +++ b/Master/bin/armhf-linux/pdfbook2 @@ -0,0 +1 @@ +../../texmf-dist/scripts/pdfbook2/pdfbook2
\ No newline at end of file diff --git a/Master/bin/i386-cygwin/pdfbook2 b/Master/bin/i386-cygwin/pdfbook2 new file mode 120000 index 00000000000..bb39290d77a --- /dev/null +++ b/Master/bin/i386-cygwin/pdfbook2 @@ -0,0 +1 @@ +../../texmf-dist/scripts/pdfbook2/pdfbook2
\ No newline at end of file diff --git a/Master/bin/i386-freebsd/pdfbook2 b/Master/bin/i386-freebsd/pdfbook2 new file mode 120000 index 00000000000..bb39290d77a --- /dev/null +++ b/Master/bin/i386-freebsd/pdfbook2 @@ -0,0 +1 @@ +../../texmf-dist/scripts/pdfbook2/pdfbook2
\ No newline at end of file diff --git a/Master/bin/i386-linux/pdfbook2 b/Master/bin/i386-linux/pdfbook2 new file mode 120000 index 00000000000..bb39290d77a --- /dev/null +++ b/Master/bin/i386-linux/pdfbook2 @@ -0,0 +1 @@ +../../texmf-dist/scripts/pdfbook2/pdfbook2
\ No newline at end of file diff --git a/Master/bin/i386-netbsd/pdfbook2 b/Master/bin/i386-netbsd/pdfbook2 new file mode 120000 index 00000000000..bb39290d77a --- /dev/null +++ b/Master/bin/i386-netbsd/pdfbook2 @@ -0,0 +1 @@ +../../texmf-dist/scripts/pdfbook2/pdfbook2
\ No newline at end of file diff --git a/Master/bin/i386-solaris/pdfbook2 b/Master/bin/i386-solaris/pdfbook2 new file mode 120000 index 00000000000..bb39290d77a --- /dev/null +++ b/Master/bin/i386-solaris/pdfbook2 @@ -0,0 +1 @@ +../../texmf-dist/scripts/pdfbook2/pdfbook2
\ No newline at end of file diff --git a/Master/bin/mipsel-linux/pdfbook2 b/Master/bin/mipsel-linux/pdfbook2 new file mode 120000 index 00000000000..bb39290d77a --- /dev/null +++ b/Master/bin/mipsel-linux/pdfbook2 @@ -0,0 +1 @@ +../../texmf-dist/scripts/pdfbook2/pdfbook2
\ No newline at end of file diff --git a/Master/bin/powerpc-linux/pdfbook2 b/Master/bin/powerpc-linux/pdfbook2 new file mode 120000 index 00000000000..bb39290d77a --- /dev/null +++ b/Master/bin/powerpc-linux/pdfbook2 @@ -0,0 +1 @@ +../../texmf-dist/scripts/pdfbook2/pdfbook2
\ No newline at end of file diff --git a/Master/bin/sparc-solaris/pdfbook2 b/Master/bin/sparc-solaris/pdfbook2 new file mode 120000 index 00000000000..bb39290d77a --- /dev/null +++ b/Master/bin/sparc-solaris/pdfbook2 @@ -0,0 +1 @@ +../../texmf-dist/scripts/pdfbook2/pdfbook2
\ No newline at end of file diff --git a/Master/bin/universal-darwin/pdfbook2 b/Master/bin/universal-darwin/pdfbook2 new file mode 120000 index 00000000000..bb39290d77a --- /dev/null +++ b/Master/bin/universal-darwin/pdfbook2 @@ -0,0 +1 @@ +../../texmf-dist/scripts/pdfbook2/pdfbook2
\ No newline at end of file diff --git a/Master/bin/win32/pdfbook2.exe b/Master/bin/win32/pdfbook2.exe Binary files differnew file mode 100755 index 00000000000..5777d90a17a --- /dev/null +++ b/Master/bin/win32/pdfbook2.exe diff --git a/Master/bin/x86_64-cygwin/pdfbook2 b/Master/bin/x86_64-cygwin/pdfbook2 new file mode 120000 index 00000000000..bb39290d77a --- /dev/null +++ b/Master/bin/x86_64-cygwin/pdfbook2 @@ -0,0 +1 @@ +../../texmf-dist/scripts/pdfbook2/pdfbook2
\ No newline at end of file diff --git a/Master/bin/x86_64-darwin/pdfbook2 b/Master/bin/x86_64-darwin/pdfbook2 new file mode 120000 index 00000000000..bb39290d77a --- /dev/null +++ b/Master/bin/x86_64-darwin/pdfbook2 @@ -0,0 +1 @@ +../../texmf-dist/scripts/pdfbook2/pdfbook2
\ No newline at end of file diff --git a/Master/bin/x86_64-linux/pdfbook2 b/Master/bin/x86_64-linux/pdfbook2 new file mode 120000 index 00000000000..bb39290d77a --- /dev/null +++ b/Master/bin/x86_64-linux/pdfbook2 @@ -0,0 +1 @@ +../../texmf-dist/scripts/pdfbook2/pdfbook2
\ No newline at end of file diff --git a/Master/bin/x86_64-solaris/pdfbook2 b/Master/bin/x86_64-solaris/pdfbook2 new file mode 120000 index 00000000000..bb39290d77a --- /dev/null +++ b/Master/bin/x86_64-solaris/pdfbook2 @@ -0,0 +1 @@ +../../texmf-dist/scripts/pdfbook2/pdfbook2
\ No newline at end of file diff --git a/Master/texmf-dist/doc/man/man1/pdfbook2.1 b/Master/texmf-dist/doc/man/man1/pdfbook2.1 new file mode 100644 index 00000000000..713ad258d7a --- /dev/null +++ b/Master/texmf-dist/doc/man/man1/pdfbook2.1 @@ -0,0 +1,121 @@ +.TH pdfbook2 1 "June 3, 2015" "" "pdfbook2 - transform pdf files to booklets" + +.SH NAME +pdfbook2 \- transform pdf files into booklets for double-sided printing + +.SH SYNOPSIS +\fBpdfbook2\fR [ \fIoptions\fR ] \fIINPUT\fR [ \fIINPUT\fR, ...] + +.SH DESCRIPTION +Create print-ready PDF files from some \fIINPUT\fR PDF files for booklet printing. The resulting files need to be printed in landscape/long edge double sided printing. The default paper format depends on the locale and is choosen by pdfjam. It can be set with the --paper option. +.PP +Before the pdf is composed the \fIINPUT\fR file is cropped to the relevant area in order to discard unnecessary white spaces. In this process, all pages are cropped to the same dimensions. Extra margins can be defined at the edges of the booklet and in the middle where the binding occurs. +.PP +The \fIOUTPUT\fR is written to \fIINPUT\fR-book.pdf. Existing files will be overwritten. All input files are processed seperatly. + +.SH EXAMPLE +To simply \fBcreate a booklet\fR from input.pdf you can use +.PP +.nf +.RS +pdfbook2 input.pdf +.RE +.fi +.PP +to create input-book.pdf. To select a special \fBtype of paper\fR you can do +.PP +.nf +.RS +pdfbook2 --paper=letter input.pdf +.RE +.fi +.PP +for letter or +.PP +.nf +.RS +pdfbook2 --paper=a4paper input.pdf +.RE +.fi +.PP +for standard A4. To increase the \fBinner margin for binding\fR use +.PP +.nf +.RS +pdfbook2 --inner-margin=200 input.pdf +.RE +.fi +.PP +to increase the default value of 150. You can submit \fBmultiple files\fR to the +script for processing like +.PP +.nf +.RS +pdfbook2 input1.pdf input2.pdf +.RE +.fi +.PP +which will result in input1-book.pdf and input2-book.pdf. + +.SH OPTIONS +.TP +.BR \-\-version +show program's version number and exit +.TP +.BR -h ", " --help +show help message and exit + +.SS GENERAL +.TP +.BR -p ", " --paper = \fISTR\fR +Format of the output paper dimensions as latex keyword (e.g. a4paper, letterpaper, legalpaper, ...) +.TP +.BR -s ", " --short-edge +Format the booklet for short-edge double-sided printing +.TP +.BR -n ", " --no-crop +Prevent the cropping to the content area + +.SS MARGINS +.TP +.BR -o ", " --outer-margin = \fIINT\fR +Defines the outer margin in the booklet (default: 40) +.TP +.BR -i ", " --inner-margin = \fIINT\fR +Defines the inner margin between the pages in the booklet (default: 150) +.TP +.BR -t ", " --top-margin = \fIINT\fR +Defines the top margin in the booklet (default: 30) +.TP +.BR -b ", " --bottom-margin = \fIINT\fR +Defines the bottom margin in the booklet (default: 30) + +.SS ADVANCED +.TP +.BR --signature = \fIINT\fR +Define the signature for the booklet handed to pdfjam, needs to be multiple of 4 (default: 4) +.TP +.BR --signature* = \fIINT\fR +Same as --signature +.TP +.BR --resolution = \fIINT\fR +Resolution used by ghostscript in bp (default: 72) + +.SH "SEE ALSO" +.BR pdfbook (1), +.BR pdfjam (1), +.BR pdfcrop (1) + +.SH ABOUT +pdfbook2 v1.2 +.br +(c) 2015 Johannes Neumann (http://www.neumannjo.de) +.br +licensed under GPLv3 (http://www.gnu.org/licenses/gpl-3.0) +.br +based on pdfbook by David Firth with help from Marco Pessotto + +.SH LICENSE +This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. diff --git a/Master/texmf-dist/doc/man/man1/pdfbook2.man1.pdf b/Master/texmf-dist/doc/man/man1/pdfbook2.man1.pdf Binary files differnew file mode 100644 index 00000000000..4e0a92cdad1 --- /dev/null +++ b/Master/texmf-dist/doc/man/man1/pdfbook2.man1.pdf diff --git a/Master/texmf-dist/doc/support/pdfbook2/README b/Master/texmf-dist/doc/support/pdfbook2/README new file mode 100644 index 00000000000..fd7dfa406f1 --- /dev/null +++ b/Master/texmf-dist/doc/support/pdfbook2/README @@ -0,0 +1,133 @@ +pdfbook2 - transform pdf files to booklets +========================================== + + pdfbook2 v1.2 + (c) 2015 Johannes Neumann (http://www.neumannjo.de) + licensed under GPLv3 (http://www.gnu.org/licenses/gpl-3.0) + based on pdfbook by David Firth with help from Marco Pessotto + +DESCRIPTION + + Create print-ready PDF files from some INPUT PDF files for booklet printing. + The resulting files need to be printed in landscape/long edge double sided + printing. The default paper format depends on the locale and is choosen by + pdfjam. It can be set with the --paper option. + + Before the pdf is composed the INPUT file is cropped to the relevant area in + order to discard unnecessary white spaces. In this process, all pages are + cropped to the same dimensions. Extra margins can be defined at the edges of + the booklet and in the middle where the binding occurs. + + The OUTPUT is written to INPUT-book.pdf. Existing files will be overwritten. + All input files are processed seperatly. + +LICENSE + + This program is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. You should have received a copy of the GNU General Public + License along with this program. If not, see <http://www.gnu.org/licenses/>. + +INSTALLATION + + Simply copy the file to any convenient location preferably covered by the + PATH variable of your shell. Make sure it is set as executable like + + chmod +x pdfbook2 + + for unix like systems. + +REQUIREMENTS + + python 2.7, pdfjam, pdfcrop and their dependencies. + +EXAMPLES + + To simply create a booklet from input.pdf you can use + + pdfbook2 input.pdf + + to create input-book.pdf. To select a special type of paper you can do + + pdfbook2 --paper=letter input.pdf + + for letter or + + pdfbook2 --paper=a4paper input.pdf + + for standard A4. To increase the inner margin for binding use + + pdfbook2 --inner-margin=200 input.pdf + + to increase the default value of 150. You can submit multiple files to the + script for processing like + + pdfbook2 input1.pdf input2.pdf + + which will result in input1-book.pdf and input2-book.pdf. + +USAGE + + pdfbook2 [options] file1 [file2 ...] + +OPTIONS + + --version show program's version number and exit + --help, -h show this help message and exit + + GENERAL + + --paper=STR, -p STR + Format of the output paper dimensions as latex keyword (e.g. + a4paper, letterpaper, legalpaper, ...) + --short-edge, -s + Format the booklet for short-edge double-sided printing + --no-crop, -n + Prevent the cropping to the content area + + MARGINS + + --outer-margin=INT, -o INT + Defines the outer margin in the booklet (default: 40) + --inner-margin=INT, -i INT + Defines the inner margin between the pages in the booklet + (default: 150) + --top-margin=INT, -t INT + Defines the top margin in the booklet (default: 30) + --bottom-margin=INT, -b INT + Defines the bottom margin in the booklet (default: 30) + + ADVANCED + + --signature=INT + Define the signature for the booklet handed to pdfjam, needs to + be multiple of 4 (default: 4) + --signature*=INT + Same as --signature + --resolution=INT + Resolution used by ghostscript in bp (default: 72) + +CHANGELOG + + 1.2 2015/06/03 + + - added man page + + 1.1 2015/06/01 + + - added resolution, signature, no-crop options + - better handling of input files with different margins on odd and + even pages + - added short options + - speedup for bound calculations and cropping by setting ghostscript + resolution to 72 (ref. --resolution option) + + 1.0 2015/05/27 + + - initial version diff --git a/Master/texmf-dist/scripts/pdfbook2/pdfbook2 b/Master/texmf-dist/scripts/pdfbook2/pdfbook2 new file mode 100755 index 00000000000..a288df70fd5 --- /dev/null +++ b/Master/texmf-dist/scripts/pdfbook2/pdfbook2 @@ -0,0 +1,237 @@ +#!/usr/bin/env python +""" pdfbook2 - transform pdf files to booklets + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + """ + + +import sys +import subprocess +import os +from optparse import OptionParser, OptionGroup, HelpFormatter +import shutil + + +#=============================================================================== +# Create booklet for file $name +#=============================================================================== + +def booklify( name, opts ): + #------------------------------------------------------ Check if file exists + print "\nProcessing", name + if not os.path.isfile( name ): + print "SKIP: file not found." + return + print "Getting bounds...", + sys.stdout.flush() + + #---------------------------------------------------------- useful constants + bboxName = "%%HiResBoundingBox:" + tmpFile = ".crop-tmp.pdf" + + #------------------------------------------------- find min/max bounding box + if opts.crop: + p = subprocess.Popen( ["pdfcrop", "--verbose", + "--resolution", repr( opts.resolution ), + name, tmpFile], + stdout = subprocess.PIPE, + stderr = subprocess.PIPE ) + p.wait() + out, err = p.communicate() + if len( err ) != 0: + print err + print "\n\nABORT: Problem getting bounds" + sys.exit( 1 ) + lines = out.splitlines() + bboxes = [s[len( bboxName ) + 1:] for s in lines if s.startswith( bboxName )] + bounds = [[float( x ) for x in bbox.split()] for bbox in bboxes ] + minLOdd = min( [bound[0] for bound in bounds[::2] ] ) + maxROdd = max( [bound[2] for bound in bounds[::2] ] ) + minLEven = min( [bound[0] for bound in bounds[1::2] ] ) + maxREven = max( [bound[2] for bound in bounds[1::2] ] ) + minT = min( [bound[1] for bound in bounds ] ) + maxB = max( [bound[3] for bound in bounds ] ) + + widthOdd = maxROdd - minLOdd + widthEven = maxREven - minLEven + maxWidth = max( widthOdd, widthEven ) + minLOdd -= maxWidth - widthOdd + maxREven += maxWidth - widthEven + + print "done" + sys.stdout.flush() + + #--------------------------------------------- crop file to area of interest + print "cropping...", + sys.stdout.flush() + p = subprocess.Popen( ["pdfcrop", + "--bbox-odd", "{L} {T} {R} {B}".format( L = minLOdd - opts.innerMargin / 2, + T = minT - opts.topMargin, + R = maxROdd + opts.outerMargin, + B = maxB + opts.outerMargin ), + "--bbox-even", "{L} {T} {R} {B}".format( L = minLEven - opts.outerMargin, + T = minT - opts.topMargin, + R = maxREven + opts.innerMargin / 2, + B = maxB + opts.outerMargin ), + "--resolution", repr( opts.resolution ), + name, + tmpFile], + stdout = subprocess.PIPE, + stderr = subprocess.PIPE ) + p.wait() + out, err = p.communicate() + if len( err ) != 0: + print err + print "\n\nABORT: Problem with cropping" + sys.exit( 1 ) + print "done" + sys.stdout.flush() + else: + shutil.copy( name, tmpFile ) + + #-------------------------------------------------------- create the booklet + print "create booklet...", + sys.stdout.flush() + pdfJamCallList = [ "pdfjam", + "--booklet", "true", + "--landscape", + "--suffix", "book", + "--signature", repr( opts.signature ), + tmpFile ] + + # add option --paper to call + if opts.paper is not None: + pdfJamCallList.append( "--paper" ) + pdfJamCallList.append( opts.paper ) + + # add option --short-edge to call + if opts.shortedge: + # check if everyshi.sty exists as texlive recommends + p = subprocess.Popen( ["kpsewhich", "everyshi.sty"], + stdout = subprocess.PIPE, + stderr = subprocess.PIPE ) + p.wait() + out, err = p.communicate() + if len( out ) == 0: + print "\n\nABORT: The everyshi.sty latex package is needed for short-edge." + sys.exit( 1 ) + else: + pdfJamCallList.append( "--preamble" ) + pdfJamCallList.append( r"\usepackage{everyshi}\makeatletter\EveryShipout{\ifodd\c@page\pdfpageattr{/Rotate 180}\fi}\makeatother" ) + + # run call to pdfJam to make booklet + p = subprocess.Popen( pdfJamCallList, + stdout = subprocess.PIPE, + stderr = subprocess.PIPE ) + p.wait() + + #-------------------------------------------- move file and remove temp file + os.rename( tmpFile[:-4] + "-book.pdf", name[:-4] + "-book.pdf" ) + os.remove( tmpFile ) + print "done" + sys.stdout.flush() + + +#=============================================================================== +# Help formatter +#=============================================================================== + +class MyHelpFormatter ( HelpFormatter ): + """Format help with indented section bodies. + """ + + def __init__( self, + indent_increment = 4, + max_help_position = 16, + width = None, + short_first = 0 ): + HelpFormatter.__init__( + self, indent_increment, max_help_position, width, short_first ) + + def format_usage( self, usage ): + return ( "USAGE\n\n%*s%s\n" ) % ( self.indent_increment, "", usage ) + + def format_heading( self, heading ): + return "%*s%s\n\n" % ( self.current_indent, "", heading.upper() ) + + +#=============================================================================== +# main programm +#=============================================================================== + +if __name__ == "__main__": + #------------------------------------------------------------ useful strings + usageString = "Usage: %prog [options] file1 [file2 ...]" + versionString = """ + %prog v1.2 + (c) 2015 Johannes Neumann (http://www.neumannjo.de) + licensed under GPLv3 (http://www.gnu.org/licenses/gpl-3.0) + based on pdfbook by David Firth with help from Marco Pessotto\n""" + defaultString = " (default: %default)" + + #------------------------------------------------- create commandline parser + parser = OptionParser( usage = usageString, version = versionString, + formatter = MyHelpFormatter( indent_increment = 4 ) ) + + generalGroup = OptionGroup( parser, "General" ) + generalGroup.add_option( "-p", "--paper", dest = "paper", type = "str", action = "store", + metavar = "STR", + help = "Format of the output paper dimensions as latex keyword (e.g. a4paper, letterpaper, legalpaper, ...)" ) + generalGroup.add_option( "-s", "--short-edge", dest = "shortedge", action = "store_true", + help = "Format the booklet for short-edge double-sided printing", + default = False ) + generalGroup.add_option( "-n", "--no-crop", dest = "crop", action = "store_false", + help = "Prevent the cropping to the content area", + default = True ) + parser.add_option_group( generalGroup ) + + marginGroup = OptionGroup( parser, "Margins" ) + marginGroup.add_option( "-o", "--outer-margin", type = "int", default = 40, + dest = "outerMargin", action = "store", metavar = "INT", + help = "Defines the outer margin in the booklet" + defaultString ) + marginGroup.add_option( "-i", "--inner-margin", type = "int", default = 150, + dest = "innerMargin", action = "store", metavar = "INT", + help = "Defines the inner margin between the pages in the booklet" + defaultString ) + marginGroup.add_option( "-t", "--top-margin", type = "int", default = 30, + dest = "topMargin", action = "store", metavar = "INT", + help = "Defines the top margin in the booklet" + defaultString ) + marginGroup.add_option( "-b", "--bottom-margin", type = "int", default = 30, metavar = "INT", + dest = "bottomMargin", action = "store", + help = "Defines the bottom margin in the booklet" + defaultString ) + parser.add_option_group( marginGroup ) + + advancedGroup = OptionGroup( parser, "Advanced" ) + advancedGroup.add_option( "--signature", dest = "signature", action = "store", type = "int", + help = "Define the signature for the booklet handed to pdfjam, needs to be multiple of 4" + defaultString, + default = 4, metavar = "INT" ) + advancedGroup.add_option( "--signature*", dest = "signature", action = "store", type = "int", + help = "Same as --signature", metavar = "INT" ) + advancedGroup.add_option( "--resolution", dest = "resolution", action = "store", type = "int", + help = "Resolution used by ghostscript in bp" + defaultString, + metavar = "INT", default = 72 ) + parser.add_option_group( advancedGroup ) + + opts, args = parser.parse_args() + + #------------------------------------ show help if started without arguments + if len( args ) == 0: + parser.print_version() + parser.print_help() + print "" + sys.exit( 2 ) + + #------------------------------------------- run for each provided file name + parser.print_version() + for arg in args: + booklify( arg, opts ) diff --git a/Master/tlpkg/bin/tlpkg-ctan-check b/Master/tlpkg/bin/tlpkg-ctan-check index 5a1c291d7ed..ac342aca497 100755 --- a/Master/tlpkg/bin/tlpkg-ctan-check +++ b/Master/tlpkg/bin/tlpkg-ctan-check @@ -408,7 +408,7 @@ my @TLP_working = qw( patch patchcmd patgen2-tutorial path pauldoc pawpict pax pbox pb-diagram pbsheet pdf14 - pdf-trans pdfcomment pdfcprot pdfcrop pdfjam pdfmarginpar + pdf-trans pdfbook2 pdfcomment pdfcprot pdfcrop pdfjam pdfmarginpar pdfpages pdfscreen pdfslide pdfsync pdftex-def pdftricks pdftricks2 pdfx pecha pedigree-perl perception perfectcut perltex permute persian-bib diff --git a/Master/tlpkg/libexec/ctan2tds b/Master/tlpkg/libexec/ctan2tds index b987c3b8e67..052a4d18d40 100755 --- a/Master/tlpkg/libexec/ctan2tds +++ b/Master/tlpkg/libexec/ctan2tds @@ -2633,6 +2633,7 @@ $standardttf = '\.ttf'; 'mkjobtexmf' => 'mkjobtexmf\.pl$', 'mkpic' => '^mkpic$', 'musixtex' => '\.lua$', + 'pdfbook2' => 'pdfbook2$', 'pdfcrop' => '\.pl$', # doscripts() does r* 'pdfjam' => 'pdf[^.]*$', 'pedigree-perl' => '\.pl$', @@ -2699,6 +2700,7 @@ $standardttf = '\.ttf'; 'musixtnt' => '\.1$', 'pedigree-perl' => '\.1$', 'perltex' => 'perltex.1', + 'pdfbook2' => '\.1$', 'pdfjam' => '\.1$', 'pkfix-helper' => 'pkfix-helper.1', 'pmx' => '\.1$', diff --git a/Master/tlpkg/tlpsrc/collection-binextra.tlpsrc b/Master/tlpkg/tlpsrc/collection-binextra.tlpsrc index 432a3af040c..f9cf3050f79 100644 --- a/Master/tlpkg/tlpsrc/collection-binextra.tlpsrc +++ b/Master/tlpkg/tlpsrc/collection-binextra.tlpsrc @@ -50,6 +50,7 @@ depend listings-ext depend match_parens depend mkjobtexmf depend patgen +depend pdfbook2 depend pdfcrop depend pdfjam depend pdftools diff --git a/Master/tlpkg/tlpsrc/pdfbook2.tlpsrc b/Master/tlpkg/tlpsrc/pdfbook2.tlpsrc new file mode 100644 index 00000000000..aefd3a571c4 --- /dev/null +++ b/Master/tlpkg/tlpsrc/pdfbook2.tlpsrc @@ -0,0 +1,2 @@ +binpattern f bin/${ARCH}/${PKGNAME} + |