From 7fab01aeca63d471a3fe51e727fa6d8799d0ddd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9l=C3=A8ne=20Corbineau?= Date: Wed, 10 Jun 2026 08:18:07 +0200 Subject: [PATCH] Add support for max_folio_size --- foliator.py | 55 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/foliator.py b/foliator.py index 6dc2676..17e0132 100755 --- a/foliator.py +++ b/foliator.py @@ -6,21 +6,16 @@ from pypdf.annotations import Line from pypdf.generic import ArrayObject, FloatObject, NameObject import math -# Interprets input_pdf as a list of A6 pages, and appends to append_to with -# A5 pages using the following rules: -# a. Odd/even page pairs correspond to front/back pages of a single sheet, printed -# with "mirror around **short** edge" -# b. when grouped as consecutive sequences of max_folio_size or less, the printed -# sheets can be folded in the middle and assembled as a folio -# FIXME: currently max_folio_size is ignored, and the output is one large folio. -def foliate_A6(input_pdf, max_folio_size=-1, append_to=PdfWriter()): - num_A5 = math.ceil(len(input_pdf.pages)/4.0) * 2 - writer = append_to +def append_folio_A6(input_pdf, offset, size, append_to): + # Handles edge case where folio has 1 page + num_A5 = min(math.ceil(size / 4.0) * 2, size) + writer = append_to + w_offset = len(writer.pages) for i in range(num_A5): dpage = writer.add_blank_page(width=PaperSize.A5.height, height=PaperSize.A5.width) - ipage = input_pdf.pages[i] + ipage = input_pdf.pages[i+offset] ipage.mediabox = dpage.mediabox if i % 2 == 0: # Even pages are filled right to left @@ -28,10 +23,10 @@ def foliate_A6(input_pdf, max_folio_size=-1, append_to=PdfWriter()): 0)) dpage.merge_page(ipage) - # Now for the fun part: work backwards to fill the remaining pages - for j in range(len(input_pdf.pages) - num_A5): - dpage = writer.pages[num_A5 - 1 - j] - ipage = input_pdf.pages[num_A5+j] + # Now for the fun part: work backwards to fill the remaining pages + for j in range(size - num_A5): + dpage = writer.pages[w_offset + num_A5 - 1 - j] + ipage = input_pdf.pages[num_A5+j+offset] ipage.mediabox = dpage.mediabox if (num_A5 - 1 - j) % 2 == 1: ipage.add_transformation(Transformation().translate(PaperSize.A6.width, @@ -39,6 +34,32 @@ def foliate_A6(input_pdf, max_folio_size=-1, append_to=PdfWriter()): dpage.merge_page(ipage) return writer + +# Interprets input_pdf as a list of A6 pages, and appends to append_to with +# A5 pages using the following rules: +# a. Odd/even page pairs correspond to front/back pages of a single sheet, printed +# with "mirror around **short** edge" +# b. when grouped as consecutive sequences of max_folio_size or less, the printed +# sheets can be folded in the middle and assembled as a folio +def foliate_A6(input_pdf, max_folio_size=-1, append_to=PdfWriter()): + current_page = 0 + doc_length = len(input_pdf.pages) + writer = append_to + if max_folio_size < 0: + max_folio_size = doc_length + + folio_page_size = 0 + while(current_page < doc_length): + # max_folio_size is a number of _sheets_, each containing 4 pages + folio_page_size = min(doc_length - current_page, 4*max_folio_size) + append_folio_A6(input_pdf, current_page, folio_page_size, append_to) + current_page += folio_page_size + + print("Dangling folio has",folio_page_size,"pages", + "(",int(math.ceil(folio_page_size/4.0)),"sheets).") + + return writer + # Take an A5 printing plan, with odd/even pages being understood # as front/back pairs of sheets, short edge mirroring. Produces an A4 printing plan # containing two A5 panels per sheet, long edge mirroring. @@ -79,10 +100,12 @@ parser.add_argument("infile", help="input document, A6 pages") parser.add_argument("outfile", help="output document") parser.add_argument("-a5", help="output as a5, reverse on short edge", action="store_true") +parser.add_argument("-fs", help="maximum folio size, in sheets", + action="store", default=-1, type=int) args = parser.parse_args() input_pdf = PdfReader(args.infile) -a5 = foliate_A6(input_pdf) +a5 = foliate_A6(input_pdf, args.fs) if (args.a5): a5.write(args.outfile) else: