Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python3
- import math
- import os
- import sys
- from PyPDF2 import PdfFileReader, PdfFileWriter
- class AfMatrix:
- """ A matrix of a 2D affine transform. """
- __slots__ = ('__a', '__b', '__c', '__d', '__e', '__f')
- def __init__(self, a, b, c, d, e, f):
- self.__a = float(a)
- self.__b = float(b)
- self.__c = float(c)
- self.__d = float(d)
- self.__e = float(e)
- self.__f = float(f)
- def __iter__(self):
- yield self.__a
- yield self.__b
- yield self.__c
- yield self.__d
- yield self.__e
- yield self.__f
- def __hash__(self):
- return hash(tuple(self))
- def __eq__(self, other):
- return tuple(self) == tuple(other)
- @classmethod
- def compose(cls, *what):
- a, b, c, d, e, f = (
- 1, 0,
- 0, 1,
- 0, 0,
- )
- for rhs in what:
- A, B, C, D, E, F = rhs
- a, b, c, d, e, f = (
- a * A + b * C,
- a * B + b * D,
- c * A + d * C,
- c * B + d * D,
- e * A + f * C + E,
- e * B + f * D + F,
- )
- return cls(
- a, b,
- c, d,
- e, f
- )
- @classmethod
- def translate(cls, x=0, y=0):
- return cls(
- 1, 0,
- 0, 1,
- x, y
- )
- def __takes_origin(func):
- def translated_func(cls, *args, origin=(0, 0), **kwargs):
- if origin == (0, 0):
- return func(cls, *args, **kwargs)
- return cls.compose(
- cls.translate(-origin[0], -origin[1]),
- func(cls, *args, **kwargs),
- cls.translate(origin[0], origin[1])
- )
- return translated_func
- @classmethod
- @__takes_origin
- def scale (cls, x=1, y=None):
- if y is None:
- y = x
- return cls(
- x, 0,
- 0, y,
- 0, 0
- )
- @classmethod
- @__takes_origin
- def rotate(cls, angle):
- from math import cos, sin, radians
- angle = radians(angle)
- C = cos(angle)
- S = sin(angle)
- return cls(
- C, -S,
- S, C,
- 0, 0
- )
- def page_size (page):
- return (page.mediaBox.getWidth (), page.mediaBox.getHeight ())
- def convert (reader, sheets_per_slice, num_blanks):
- writer = PdfFileWriter ()
- SIZE = page_size (reader.getPage (0))
- print ("SIZE={}".format (SIZE))
- NUM_PAGES = reader.getNumPages ()
- PAGES_PER_SLICE = sheets_per_slice * 4
- MAX_PRODUCED_PAGES = NUM_PAGES + num_blanks + PAGES_PER_SLICE - 1
- NUM_SLICES = int (MAX_PRODUCED_PAGES / PAGES_PER_SLICE)
- def positive (x):
- if x >= 0 and x < NUM_PAGES:
- return x
- else:
- return None
- output_page_num = 0
- for i_slice in range (NUM_SLICES):
- print ("Slice {}/{} will read pages {} to {} of {}".format (
- i_slice + 1,
- NUM_SLICES,
- i_slice * PAGES_PER_SLICE - num_blanks,
- i_slice * PAGES_PER_SLICE + PAGES_PER_SLICE - num_blanks - 1,
- NUM_PAGES))
- O = i_slice * PAGES_PER_SLICE - num_blanks
- for s in range (sheets_per_slice * 2):
- # Positive is clockwise (!)
- angle = -90 if s%2 == 0 else +90
- out_page = writer.addBlankPage (*SIZE)
- i_bot = positive (O + sheets_per_slice * 2 - (s + 1))
- i_top = positive (O + sheets_per_slice * 2 + s)
- def get (i):
- p = reader.getPage (i)
- if page_size (p) != SIZE:
- raise Exception ("Page {} has different size.".format (i+1))
- return p
- if i_bot is not None:
- out_page.mergeTransformedPage (
- get (i_bot),
- transform (angle, 0, SIZE))
- if i_top is not None:
- out_page.mergeTransformedPage (
- get (i_top),
- transform (angle, SIZE[1]/2, SIZE))
- print ("Output page {}:\n\tb: {}\n\tt: {}\n\ta: {}".format (
- output_page_num + 1,
- i_bot,
- i_top,
- angle))
- output_page_num += 1
- return writer
- def transform (angle, y_offset, size):
- if angle < 0:
- offset = (size[0], y_offset)
- else:
- offset = (0, y_offset + size[1]/2)
- # When witdh is 595 for A4, empirically I found offset of 88 to work :-S
- HACK_OFFSET = 88 * size[0]/595
- return AfMatrix.compose (
- # Rotate First
- AfMatrix.rotate (angle, origin=(size[0]/2,size[1]/2)),
- # Then shrink
- AfMatrix.scale (1 / math.sqrt (2)),
- # Then slide into position
- AfMatrix.translate (0, y_offset),
- # HACK
- AfMatrix.translate (HACK_OFFSET, -HACK_OFFSET)
- )
- def main ():
- sys.argv.pop (0) # script name
- try:
- num_blanks = 0
- if '--blanks' == sys.argv[0]:
- sys.argv.pop (0)
- num_blanks = int (sys.argv.pop (0))
- sheets_per_slice = sys.argv.pop (0)
- in_filename = sys.argv.pop (0)
- out_filename = sys.argv.pop (0)
- sheets_per_slice = int (sheets_per_slice)
- reader = PdfFileReader (in_filename)
- if os.path.exists (out_filename):
- print ("{} exists. Overwrite? y/n".format (out_filename))
- yn = sys.stdin.readline ()
- if yn[0] not in ('Y', 'y'):
- sys.exit (1)
- ostream = open (out_filename, 'wb')
- except Exception as e:
- print ("{}\nArguments: sheets_per_slice in_file out_file".format (e))
- sys.exit (1)
- try:
- writer = convert (reader, sheets_per_slice, num_blanks)
- except Exception as e:
- print ("Could not convert this document: {}".format (e))
- raise
- sys.exit (1)
- writer.write (ostream)
- ostream.close ()
- if __name__ == '__main__':
- main ()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement