Advertisement
Guest User

Untitled

a guest
Nov 18th, 2020
103
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.26 KB | None | 0 0
  1. #!/usr/bin/env python3
  2. import math
  3. import os
  4. import sys
  5.  
  6. from PyPDF2 import PdfFileReader, PdfFileWriter
  7.  
  8.  
  9.  
  10. class AfMatrix:
  11.     """ A matrix of a 2D affine transform. """
  12.  
  13.     __slots__ = ('__a', '__b', '__c', '__d', '__e', '__f')
  14.  
  15.     def __init__(self, a, b, c, d, e, f):
  16.         self.__a = float(a)
  17.         self.__b = float(b)
  18.         self.__c = float(c)
  19.         self.__d = float(d)
  20.         self.__e = float(e)
  21.         self.__f = float(f)
  22.  
  23.     def __iter__(self):
  24.         yield self.__a
  25.         yield self.__b
  26.         yield self.__c
  27.         yield self.__d
  28.         yield self.__e
  29.         yield self.__f
  30.  
  31.     def __hash__(self):
  32.         return hash(tuple(self))
  33.  
  34.     def __eq__(self, other):
  35.         return tuple(self) == tuple(other)
  36.  
  37.     @classmethod
  38.     def compose(cls, *what):
  39.         a, b, c, d, e, f = (
  40.             1, 0,
  41.             0, 1,
  42.             0, 0,
  43.         )
  44.  
  45.         for rhs in what:
  46.             A, B, C, D, E, F = rhs
  47.             a, b, c, d, e, f = (
  48.                 a * A + b * C,
  49.                 a * B + b * D,
  50.                 c * A + d * C,
  51.                 c * B + d * D,
  52.                 e * A + f * C + E,
  53.                 e * B + f * D + F,
  54.             )
  55.  
  56.         return cls(
  57.             a, b,
  58.             c, d,
  59.             e, f
  60.         )
  61.  
  62.     @classmethod
  63.     def translate(cls, x=0, y=0):
  64.         return cls(
  65.             1, 0,
  66.             0, 1,
  67.             x, y
  68.         )
  69.  
  70.     def __takes_origin(func):
  71.         def translated_func(cls, *args, origin=(0, 0), **kwargs):
  72.             if origin == (0, 0):
  73.                 return func(cls, *args, **kwargs)
  74.             return cls.compose(
  75.                 cls.translate(-origin[0], -origin[1]),
  76.                 func(cls, *args, **kwargs),
  77.                 cls.translate(origin[0], origin[1])
  78.             )
  79.         return translated_func
  80.  
  81.     @classmethod
  82.     @__takes_origin
  83.     def scale (cls, x=1, y=None):
  84.         if y is None:
  85.             y = x
  86.         return cls(
  87.             x, 0,
  88.             0, y,
  89.             0, 0
  90.         )
  91.  
  92.     @classmethod
  93.     @__takes_origin
  94.     def rotate(cls, angle):
  95.         from math import cos, sin, radians
  96.  
  97.         angle = radians(angle)
  98.         C = cos(angle)
  99.         S = sin(angle)
  100.  
  101.         return cls(
  102.             C, -S,
  103.             S,  C,
  104.             0,  0
  105.         )
  106.  
  107.  
  108.  
  109. def page_size (page):
  110.  
  111.     return (page.mediaBox.getWidth (), page.mediaBox.getHeight ())
  112.  
  113.  
  114.  
  115. def convert (reader, sheets_per_slice, num_blanks):
  116.  
  117.     writer = PdfFileWriter ()
  118.  
  119.     SIZE = page_size (reader.getPage (0))
  120.  
  121.     NUM_PAGES = reader.getNumPages ()
  122.  
  123.     PAGES_PER_SLICE = sheets_per_slice * 4
  124.  
  125.     MAX_PRODUCED_PAGES = NUM_PAGES + num_blanks + PAGES_PER_SLICE - 1
  126.  
  127.     NUM_SLICES = int (MAX_PRODUCED_PAGES / PAGES_PER_SLICE)
  128.  
  129.     def positive (x):
  130.         if x >= 0 and x < NUM_PAGES:
  131.             return x
  132.         else:
  133.             return None
  134.  
  135.     output_page_num = 0
  136.  
  137.     for i_slice in range (NUM_SLICES):
  138.  
  139.         print ("Slice {}/{} will read pages {} to {} of {}".format (
  140.             i_slice + 1,
  141.             NUM_SLICES,
  142.             i_slice * PAGES_PER_SLICE - num_blanks,
  143.             i_slice * PAGES_PER_SLICE + PAGES_PER_SLICE - num_blanks - 1,
  144.             NUM_PAGES))
  145.  
  146.         O = i_slice * PAGES_PER_SLICE - num_blanks
  147.  
  148.         for s in range (sheets_per_slice * 2):
  149.  
  150.             # Positive is clockwise (!)
  151.             angle = -90 if s%2 == 0 else +90
  152.  
  153.             out_page = writer.addBlankPage (*SIZE)
  154.  
  155.             i_bot = positive (O + sheets_per_slice * 2 - (s + 1))
  156.             i_top = positive (O + sheets_per_slice * 2 + s)
  157.  
  158.             def get (i):
  159.                 p = reader.getPage (i)
  160.                 if page_size (p) != SIZE:
  161.                     raise Exception ("Page {} has different size.".format (i+1))
  162.                 return p
  163.  
  164.             if i_bot is not None:
  165.                 out_page.mergeTransformedPage (
  166.                     get (i_bot),
  167.                     transform (angle, 0, SIZE))
  168.  
  169.             if i_top is not None:
  170.                 out_page.mergeTransformedPage (
  171.                     get (i_top),
  172.                     transform (angle, SIZE[1]/2, SIZE))
  173.  
  174.             print ("Output page {}:\n\tb: {}\n\tt: {}\n\ta: {}".format (
  175.                 output_page_num + 1,
  176.                 i_bot,
  177.                 i_top,
  178.                 angle))
  179.  
  180.             output_page_num += 1
  181.  
  182.     return writer
  183.  
  184.  
  185.  
  186. def transform (angle, y_offset, size):
  187.  
  188.     if angle < 0:
  189.         offset = (size[0], y_offset)
  190.     else:
  191.         offset = (0, y_offset + size[1]/2)
  192.  
  193.     return AfMatrix.compose (
  194.         # Rotate First
  195.         AfMatrix.rotate (angle, origin=(size[0]/2,size[1]/2)),
  196.         # Then shrink
  197.         AfMatrix.scale (1 / math.sqrt (2)),
  198.         # Then slide into position
  199.         AfMatrix.translate (0, y_offset),
  200.     )
  201. #    angle = 10
  202. #    return AfMatrix.translate (0, y_offset)
  203.  
  204.     return AfMatrix.compose (
  205.         AfMatrix.rotate (angle, origin=(size[0]/2,size[1]/2)),
  206.         AfMatrix.scale (1 / math.sqrt (2)),
  207.         AfMatrix.translate (0, y_offset+size[1]/5),
  208.     )
  209. #        AfMatrix.translate (*offset))
  210.  
  211.  
  212.  
  213. def main ():
  214.  
  215.     sys.argv.pop (0) # script name
  216.  
  217.     try:
  218.  
  219.         num_blanks = 0
  220.  
  221.         if '--blanks' == sys.argv[0]:
  222.             sys.argv.pop (0)
  223.             num_blanks = int (sys.argv.pop (0))
  224.  
  225.         sheets_per_slice = sys.argv.pop (0)
  226.         in_filename     = sys.argv.pop (0)
  227.         out_filename    = sys.argv.pop (0)
  228.  
  229.         sheets_per_slice = int (sheets_per_slice)
  230.  
  231.         reader = PdfFileReader (in_filename)
  232.  
  233.         if os.path.exists (out_filename):
  234.  
  235.             print ("{} exists. Overwrite? y/n".format (out_filename))
  236.  
  237.             yn = sys.stdin.readline ()
  238.  
  239.             if yn[0] not in ('Y', 'y'):
  240.                 sys.exit (1)
  241.  
  242.         ostream = open (out_filename, 'wb')
  243.  
  244.     except Exception as e:
  245.  
  246.         print ("{}\nArguments: sheets_per_slice in_file out_file".format (e))
  247.  
  248.         sys.exit (1)
  249.  
  250.     try:
  251.         writer = convert (reader, sheets_per_slice, num_blanks)
  252.     except Exception as e:
  253.         print ("Could not convert this document: {}".format (e))
  254.         raise
  255.         sys.exit (1)
  256.  
  257.     writer.write (ostream)
  258.  
  259.     ostream.close ()
  260.  
  261.  
  262.  
  263. if __name__ == '__main__':
  264.     main ()
  265.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement