#! /usr/bin/env python
# -*- coding: utf-8 -*-
import os , tempfile , shlex , subprocess
from argparse import ArgumentParser
from random import shuffle
####
# Arguments
# TODO: add example to description
####
p = ArgumentParser ( description = ' Script converts 8 images (jpg or png) from a given directory into a single page 4x2 imposition. Example: python imposition.py --dir imgs/ --size a3 --order random ' )
p . add_argument ( " --dir " , metavar = ' ' , default = ' imgs ' , required = True , help = " Image directory, which stores the source images for the imposition " )
p . add_argument ( " --size " , metavar = ' ' , default = " A4 " , choices = [ ' A4 ' , ' a4 ' , ' A3 ' , ' a3 ' ] , help = " Size of the printing sheet: A4 or A3. Default:A4 " )
p . add_argument ( " --pages " , metavar = ' ' , type = int , choices = [ 1 , 2 ] , default = 1 , help = " Number of imposition pages. Default:1. Currently only 1 or 2 pages impositions are available. " )
p . add_argument ( " --order " , metavar = ' ' , default = " alphabet " , choices = [ " alphabet " , " reverse " , " random " ] , help = " Image distribution Order in the imposition. Possible Values: alphabet (alphabetically) , reverse (reverse alphabetically), random. Default: alphabet " )
p . add_argument ( " --output " , metavar = ' ' , default = " output.pdf " , help = " Output file. Can either be a pdf, jpg or png. Default: output.pdf " )
args = p . parse_args ( )
print args
temp_dir = tempfile . mkdtemp ( )
# dimensions
args . size = ( args . size ) . upper ( )
global size_sheet
if args . size == ' A4 ' :
size_sheet = ( 3508 , 2480 ) #landscape: widthxheight in px
elif args . size == ' A3 ' :
size_sheet = ( 4960 , 3508 ) #landscape: widthxheight in px
size_pages = ( size_sheet [ 0 ] / 4 , size_sheet [ 1 ] / 2 ) # size of each of the pages which makes up the printing sheet
# image selection
listdir = os . listdir ( os . path . abspath ( args . dir ) )
listdir = [ f for f in listdir if any ( x in f for x in [ ' .jpeg ' , ' .jpg ' , ' .png ' , ' .JPEG ' , ' .JPG ' , ' .PNG ' , ' .Jpg ' , ' .Jpeg ' , ' .Png ' ] ) ] #only bitmaps allowed
# create list of 8 ordered images
global listdir_order
if args . order == ' alphabet ' :
listdir . sort ( )
listdir_order = listdir
elif args . order == ' reverse ' :
listdir . sort ( )
listdir . reverse ( )
listdir_order = listdir
elif args . order == ' random ' :
shuffle ( listdir )
listdir_order = listdir
# print listdir_order
if args . pages == 1 :
listdir_order = listdir_order [ 0 : 8 ]
pagenumbers = [ 2 , 5 , 4 , 3 , 1 , 6 , 7 , 0 ] # from from top left to bottom right ( order in imagemagick creates mosaic)
elif args . pages == 2 :
listdir_order = listdir_order [ 0 : 16 ]
pagenumbers = [ 4 , 11 , 8 , 7 , 3 , 12 , 15 , 0 , 6 , 9 , 10 , 5 , 1 , 14 , 13 , 2 ]
listdir_order = [ listdir_order [ n ] for n in pagenumbers ] # reorder files according to pagenumbers
print ' selected files according to pagenumbers: ' , listdir_order
# image conversion: -extent
tmpfiles = [ ( temp_dir + ' / ' + str ( n ) + ' .jpg ' ) for n , img in enumerate ( listdir_order ) ]
for n , img in enumerate ( listdir_order ) :
template_convert = ' convert -background white " {targetimg} " -gravity Center -resize {w} x {h} -extent {w} x {h} {tmpfile} '
cmd_convert = template_convert . format ( targetimg = ( os . path . abspath ( args . dir ) ) + ' / ' + img ,
w = size_pages [ 0 ] ,
h = size_pages [ 1 ] ,
tmpfile = tmpfiles [ n ] )
cmd_convert_l = shlex . split ( cmd_convert )
subprocess . call ( cmd_convert_l )
# # montage
tmp_output = ( temp_dir + ' / ' + ' output.jpg ' )
if args . pages == 1 :
template_montage = " montage -geometry +1+1 -tile 4x2 \ ( -rotate 180 {topfiles_p1} \ ) {bottomfiles_p1} {output} "
cmd_montage = template_montage . format (
topfiles_p1 = ' ' . join ( tmpfiles [ : 4 ] ) ,
bottomfiles_p1 = ' ' . join ( tmpfiles [ 4 : 8 ] ) ,
output = tmp_output )
elif args . pages == 2 :
template_montage = " montage -geometry +1+1 -tile 4x2 \ ( -rotate 180 {topfiles_p1} \ ) {bottomfiles_p1} \ ( -rotate 180 {topfiles_p2} \ ) {bottomfiles_p2} {output} "
cmd_montage = template_montage . format (
topfiles_p1 = ' ' . join ( tmpfiles [ : 4 ] ) ,
bottomfiles_p1 = ' ' . join ( tmpfiles [ 4 : 8 ] ) ,
topfiles_p2 = ' ' . join ( tmpfiles [ 8 : 12 ] ) ,
bottomfiles_p2 = ' ' . join ( tmpfiles [ 12 : ] ) , output = tmp_output )
print ' Create montage cmd {} : ' . format ( cmd_montage )
cmd_montage_l = shlex . split ( cmd_montage )
subprocess . call ( cmd_montage_l )
# # resize output
tmp_output_files = [ ( temp_dir + ' / ' + f ) for f in ( os . listdir ( temp_dir ) ) if ' output ' in f ] #if more than 1 files results from montage
tmp_output_files = " " . join ( tmp_output_files ) # make into string
output_f = os . path . abspath ( ' ./ ' + args . output )
template_convert = " convert {input_f} -resize {w} x {h} -units PixelsPerInch -density 300x300 {output} "
cmd_convert = template_convert . format (
input_f = tmp_output_files ,
w = size_sheet [ 0 ] ,
h = size_sheet [ 1 ] ,
output = output_f )
cmd_convert_l = shlex . split ( cmd_convert )
print ' Convert montage to {} cmd: {} ' . format ( args . output , cmd_convert )
subprocess . call ( cmd_convert_l )
print ' ** imposition save in ' , output_f , ' ** '
# garbage collection
cmd_rm = shlex . split ( ( ' rm -rf ' + temp_dir ) )
subprocess . call ( cmd_rm ) # rm temp dir