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

Loading…
Cancel
Save