0xV3NOMx
Linux ip-172-26-7-228 5.4.0-1103-aws #111~18.04.1-Ubuntu SMP Tue May 23 20:04:10 UTC 2023 x86_64



Your IP : 3.21.244.240


Current Path : /proc/thread-self/root/proc/self/root/usr/bin/
Upload File :
Current File : //proc/thread-self/root/proc/self/root/usr/bin/pdfbook2

#!/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 )