diff options
author | Karl Berry <karl@freefriends.org> | 2015-06-14 22:17:46 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2015-06-14 22:17:46 +0000 |
commit | 4cad9cf047cf4bb824a71c8af70edee1b20874f1 (patch) | |
tree | 9dca48848d460108937bd24f6d66179e16dfe1a2 /Build/source | |
parent | bf587c17edfdc46c03e91570278a8faa0c4285a0 (diff) |
pdfbook2 (4jun15)
git-svn-id: svn://tug.org/texlive/trunk@37537 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source')
-rw-r--r-- | Build/source/texk/texlive/linked_scripts/Makefile.am | 1 | ||||
-rw-r--r-- | Build/source/texk/texlive/linked_scripts/Makefile.in | 1 | ||||
-rwxr-xr-x | Build/source/texk/texlive/linked_scripts/pdfbook2/pdfbook2 | 237 |
3 files changed, 239 insertions, 0 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 ) |