updated bookletify to automatically merge 2 pages per sheet

removeproofs
Francesco Baldino 2 years ago
parent 789c9308d4
commit 76ceb6dfb8

@ -1,72 +1,50 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os import os
import sys import argparse
from math import ceil from PyPDF2 import PageObject, PdfReader, PdfWriter, PaperSize, Transformation
from PyPDF2 import PdfReader, PdfWriter
def main(): def main():
def print_help(): PROGRAM_NAME="bookletify"
print('bookletify') DESCRIPTION = """Rearranges the pages of a pdf in order to print it as is,
print() so that you can take it, cut it in half and close it like you would
print('USAGE') with a book. The result will be the original pdf in the correct order,
print(' bookletify [OPTIONS] file') with the size of half a page. Especially useful to print pdfs to A5
print() size on A4 paper"""
print('DESCRIPTION')
print(' Rearranges the pages of a pdf in order to print it as is (double') parser = argparse.ArgumentParser(
print(' sided, flipped on the short edge) so that you can take it, cut ') prog=PROGRAM_NAME,
print(' in half and close it like you would do with a book. The result ') description=DESCRIPTION
print(' will be the original pdf in the correct order, with the size of ') )
print(' half a page')
print(' Especially useful to print pdfs to A5 size on A4 paper') parser.add_argument('filename')
print() parser.add_argument('-q', '--quiet',
print('OPTIONS') action='store_true',
print(' -h print help') help='suppress stdout')
print(' -q do not print anything to stdout') parser.add_argument('-s', '--size',
action='store',
def parse_argv(): choices=['A0', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'C4'],
opts = { default='A4',
"h": False, metavar='SIZE',
"q": False, help="""set final paper size. Possible values: 'A0',
} ..., 'A8' or 'C4'. Default value is 'A4'""")
filename = None
parser.add_argument('-b', '--binding-margin',
if len(sys.argv) < 2: default=10,
opts["h"] = True type=float,
metavar='MARGIN',
for arg in sys.argv[1:]: help="""internal margin for the binding, expressed in
if arg.startswith('-'): millimeters. Default value is 10""")
for opt in opts:
if opt in arg: args = parser.parse_args()
opts[opt] = True
elif not filename: info = lambda text='', end='\n': print(text, end=end)
filename = arg if args.quiet:
info = lambda text='', end='\n': None
return (opts, filename)
def info(text = '', end='\n'):
if not opts["q"]:
print(text, end=end)
def prog(curr, max_val):
# Overrides the current terminal line with a progressbar filled at curr/max_val
perc = float(curr) / float(max_val)
remaining = f'{curr:{len(str(max_val))}d}/{max_val}'
(cols, _) = os.get_terminal_size()
max_width = cols - len(remaining) - 3
size = min(max_width, max_val, 80)
bar = int(perc * size)
end = '\n' if curr == max_val else ''
info("\r|" + ("\u2588" * bar) + "_" * (size - bar) + "| " + remaining, end)
(opts, input_name) = parse_argv()
if opts["h"] or not input_name:
print_help()
exit(0)
prog = lambda curr, max: info(f"\r{curr} / {max}", '\n' if curr == max else '')
input_name = args.filename
if not os.path.isfile(input_name): if not os.path.isfile(input_name):
print(f'file {input_name} does not exist') print(f'file {input_name} does not exist')
exit(1) exit(1)
@ -75,47 +53,60 @@ def main():
if (input_name.endswith('.pdf')): if (input_name.endswith('.pdf')):
output_name = f'{input_name[0:-4]}-rearranged.pdf' output_name = f'{input_name[0:-4]}-rearranged.pdf'
fullwidth = getattr(PaperSize, args.size).width
fullheight = getattr(PaperSize, args.size).height
smallwidth = fullheight / 2
smallheight = fullwidth
# Convert mm to pixels at 72 dpi
bindingwidth = args.binding_margin * 72 / float(25.4)
smallblank = PageObject.create_blank_page(width=smallwidth - bindingwidth, height=smallheight)
# Read the input # Read the input
reader = PdfReader(input_name) reader = PdfReader(input_name)
# Write the result to a file
middle = PdfWriter()
info("Loading...")
n = len(reader.pages) n = len(reader.pages)
# Set m as the smallest multiple of 4 bigger or equal to n pages = []
m = ceil(n / 4) * 4
info("Reading...")
for i in range(n): for i in range(n):
prog(i, m) prog(i, n)
middle.add_page(reader.pages[i]) pages.append(reader.pages[i])
prog(n,n)
for i in range(m - n):
prog(n + i, m) while(len(pages) % 4 != 0):
middle.add_blank_page() pages.append(smallblank)
prog(m, m)
output = PdfWriter() output = PdfWriter()
info() info("\nRearranging...")
info("Rearranging...")
for i in range(int(m / 4)): def merge_srt_page(base, over, angle, tx, ty):
mod = i * 2 sx = float(smallwidth - bindingwidth) / float(over.mediabox.width)
prog(i * 4, m) sy = float(smallheight) / float(over.mediabox.height)
output.add_page(middle.pages[m - 1 - mod]) t = Transformation().scale(sx, sy).rotate(angle). translate(tx, ty)
prog(i * 4 + 1, m) over.add_transformation(t)
output.add_page(middle.pages[mod]) base.merge_page(over)
prog(i * 4 + 2, m)
output.add_page(middle.pages[1 + mod]) m = len(pages)
prog(i * 4 + 3, m) for i in range(int(m / 2)):
output.add_page(middle.pages[m - 2 - mod]) prog(i, int(m / 2))
prog(m, m) new_page = PageObject.create_blank_page(width=fullwidth, height=fullheight)
if i % 2 == 0:
info() merge_srt_page(new_page, pages[m - 1 - i], -90, 0, fullheight)
info("Saving...") merge_srt_page(new_page, pages[i], - 90, 0, smallwidth - bindingwidth)
pass
else:
merge_srt_page(new_page, pages[m - 1 - i], 90, smallheight, smallwidth + bindingwidth)
merge_srt_page(new_page, pages[i], 90, smallheight, 0)
output.add_page(new_page)
prog(int(m/2), int(m/2))
info("\nSaving...")
output.write(output_name) output.write(output_name)
info("Done!") info("\nDone!")
info()
if __name__ == "__main__": if __name__ == "__main__":
main() main()

Loading…
Cancel
Save