CUT_DEPTH = 1.95 * POINTS_PER_CM
CUT_WIDTH = 1.05 * POINTS_PER_CM
MIDDLE_POINT_DEPTH = 0.4 * POINTS_PER_CM
-SPINE_LIMIT = 1 * POINTS_PER_CM
+INNER_SPINE_MARGIN_PER_PAGE = 1 * POINTS_PER_CM
QUARTER_SCALE_FACTOR = 0.5
PAGE_ORDER_FOR_NUP4 = (3,0,7,4,1,2,5,6)
-# some helpers
+
class PageCrop:
def __init__(self, left_cm=0, bottom_cm=0, right_cm=0, top_cm=0):
return PageCrop(left_cm=self.right_cm, bottom_cm=self.bottom_cm, right_cm=self.left_cm, top_cm=self.top_cm)
-class PrintableMargin:
+class Nup4Geometry:
- def __init__(self, size_cm):
- self.size = size_cm * POINTS_PER_CM
- self.zoom = (A4_WIDTH - 2 * self.size)/A4_WIDTH
+ def __init__(self, margin_cm):
+ self.margin = margin_cm * POINTS_PER_CM
+ self.shrink_for_margin = (A4_WIDTH - 2 * self.margin)/A4_WIDTH
+ # NB: We define spine size un-shrunk, but .shrink_for_spine is used with values shrunk for the margin, which we undo here.
+ spine_part_of_page = (INNER_SPINE_MARGIN_PER_PAGE / A4_HALF_WIDTH) / self.shrink_for_margin
+ self.shrink_for_spine = 1 - spine_part_of_page
class HandledException(Exception):
odd_page = not odd_page
print(f"built page number {i+1} (of {len(pages_to_add)})")
+
def build_nup4_output(writer, pages_to_add, crop_at_page, args_print_margin, args_analyze, canvas_class):
print("-n: building 4-input-pages-per-output-page book")
print(f"-m: applying printable-area margin of {args_print_margin}cm")
if args_analyze:
print("-a: drawing page borders, spine limits")
- printable_margin = PrintableMargin(args_print_margin)
- spine_part_of_page = (SPINE_LIMIT / A4_HALF_WIDTH) / printable_margin.zoom
- bonus_shrink_factor = 1 - spine_part_of_page
+ nup4_geometry = Nup4Geometry(args_print_margin)
pages_to_add, new_i_order = resort_pages_for_nup4(pages_to_add)
- nup4_position = 0
+ nup4_i = 0
page_count = 0
is_front_page = True
for i, page in enumerate(pages_to_add):
- if nup4_position == 0:
+ if nup4_i == 0:
new_page = pypdf.PageObject.create_blank_page(width=A4_WIDTH, height=A4_HEIGHT)
corrected_i = new_i_order[i]
- nup4_inner_page_transform(page, crop_at_page[corrected_i], bonus_shrink_factor, printable_margin, nup4_position)
- nup4_outer_page_transform(page, bonus_shrink_factor, nup4_position)
+ nup4_inner_page_transform(page, crop_at_page[corrected_i], nup4_geometry, nup4_i)
+ nup4_outer_page_transform(page, nup4_geometry, nup4_i)
new_page.merge_page(page)
page_count += 1
print(f"merged page number {page_count} (of {len(pages_to_add)})")
- nup4_position += 1
- if nup4_position > 3:
- ornate_nup4(writer, args_analyze, is_front_page, new_page, printable_margin, bonus_shrink_factor, canvas_class)
+ nup4_i += 1
+ if nup4_i > 3:
+ ornate_nup4(writer, args_analyze, is_front_page, new_page, nup4_geometry, canvas_class)
writer.add_page(new_page)
- nup4_position = 0
+ nup4_i = 0
is_front_page = not is_front_page
return new_page_order, new_i_order
-def nup4_inner_page_transform(page, crop, bonus_shrink_factor, printable_margin, nup4_position):
+def nup4_inner_page_transform(page, crop, nup4_geometry, nup4_i):
page.add_transformation(pypdf.Transformation().translate(ty=(A4_HEIGHT / crop.zoom - (A4_HEIGHT - crop.top))))
- if nup4_position == 0 or nup4_position == 2:
+ if nup4_i == 0 or nup4_i == 2:
page.add_transformation(pypdf.Transformation().translate(tx=-crop.left))
- elif nup4_position == 1 or nup4_position == 3:
+ elif nup4_i == 1 or nup4_i == 3:
page.add_transformation(pypdf.Transformation().translate(tx=(A4_WIDTH / crop.zoom - (A4_WIDTH - crop.right))))
- page.add_transformation(pypdf.Transformation().scale(crop.zoom * bonus_shrink_factor, crop.zoom * bonus_shrink_factor))
- if nup4_position == 2 or nup4_position == 3:
- page.add_transformation(pypdf.Transformation().translate(ty=-2*printable_margin.size/printable_margin.zoom))
+ page.add_transformation(pypdf.Transformation().scale(crop.zoom * nup4_geometry.shrink_for_spine, crop.zoom * nup4_geometry.shrink_for_spine))
+ if nup4_i == 2 or nup4_i == 3:
+ page.add_transformation(pypdf.Transformation().translate(ty=-2*nup4_geometry.margin/nup4_geometry.shrink_for_margin))
-def nup4_outer_page_transform(page, bonus_shrink_factor, nup4_position):
- page.add_transformation(pypdf.Transformation().translate(ty=(1-bonus_shrink_factor)*A4_HEIGHT))
- if nup4_position == 0 or nup4_position == 1:
+def nup4_outer_page_transform(page, nup4_geometry, nup4_i):
+ page.add_transformation(pypdf.Transformation().translate(ty=(1-nup4_geometry.shrink_for_spine)*A4_HEIGHT))
+ if nup4_i == 0 or nup4_i == 1:
y_section = A4_HEIGHT
page.mediabox.bottom = A4_HALF_HEIGHT
page.mediabox.top = A4_HEIGHT
- if nup4_position == 2 or nup4_position == 3:
+ if nup4_i == 2 or nup4_i == 3:
y_section = 0
page.mediabox.bottom = 0
page.mediabox.top = A4_HALF_HEIGHT
- if nup4_position == 0 or nup4_position == 2:
+ if nup4_i == 0 or nup4_i == 2:
x_section = 0
page.mediabox.left = 0
page.mediabox.right = A4_HALF_WIDTH
- if nup4_position == 1 or nup4_position == 3:
- page.add_transformation(pypdf.Transformation().translate(tx=(1-bonus_shrink_factor)*A4_WIDTH))
+ if nup4_i == 1 or nup4_i == 3:
+ page.add_transformation(pypdf.Transformation().translate(tx=(1-nup4_geometry.shrink_for_spine)*A4_WIDTH))
x_section = A4_WIDTH
page.mediabox.left = A4_HALF_WIDTH
page.mediabox.right = A4_WIDTH
page.add_transformation(pypdf.Transformation().scale(QUARTER_SCALE_FACTOR, QUARTER_SCALE_FACTOR))
-def ornate_nup4(writer, args_analyze, is_front_page, new_page, printable_margin, bonus_shrink_factor, canvas_class):
+def ornate_nup4(writer, args_analyze, is_front_page, new_page, nup4_geometry, canvas_class):
if args_analyze:
# borders
packet = io.BytesIO()
c.save()
new_pdf = pypdf.PdfReader(packet)
new_page.merge_page(new_pdf.pages[0])
- printable_offset_x = printable_margin.size
- printable_offset_y = printable_margin.size * A4_HEIGHT / A4_WIDTH
- new_page.add_transformation(pypdf.Transformation().scale(printable_margin.zoom, printable_margin.zoom))
+ printable_offset_x = nup4_geometry.margin
+ printable_offset_y = nup4_geometry.margin * A4_HEIGHT / A4_WIDTH
+ new_page.add_transformation(pypdf.Transformation().scale(nup4_geometry.shrink_for_margin, nup4_geometry.shrink_for_margin))
new_page.add_transformation(pypdf.Transformation().translate(tx=printable_offset_x, ty=printable_offset_y))
- x_left_spine_limit = A4_HALF_WIDTH * bonus_shrink_factor
+ x_left_spine_limit = A4_HALF_WIDTH * nup4_geometry.shrink_for_spine
x_right_spine_limit = A4_WIDTH - x_left_spine_limit
if args_analyze or is_front_page:
packet = io.BytesIO()