Compare commits

..

2 commits

Author SHA1 Message Date
Selene Corbineau
6566830258 Begin implementing strategy selection
Right now this is still unexposed to the users.
Pretty-printing the foliating plan is somewhat of
a problem. Hopefully they are always quite small.
2026-06-21 11:21:08 +02:00
Selene Corbineau
e3e84692e3 Fix import of create_blank_page 2026-06-21 11:20:44 +02:00
2 changed files with 29 additions and 16 deletions

View file

@ -1,9 +1,10 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import argparse import argparse
from pypdf import PaperSize, PdfReader, PdfWriter, Transformation import numpy as np
from pypdf.annotations import Line from pypdf import PaperSize, PdfReader, PdfWriter, Transformation, PageObject
from pypdf.generic import ArrayObject, FloatObject, NameObject from pypdf.generic import ArrayObject, FloatObject, NameObject
from pypdf.annotations import Line
import math import math
@ -38,7 +39,7 @@ def append_folio_A6(input_pdf, offset, size, append_to):
# num_sheets = max_folio_size * a + (max_folio_size - k) * b # num_sheets = max_folio_size * a + (max_folio_size - k) * b
# where k is minimal. We let n = max_folio_size and L = num_sheets. # where k is minimal. We let n = max_folio_size and L = num_sheets.
# Note that when L > n^2, then k = 1 must succeed. # Note that when L > n^2, then k = 1 must succeed.
def find_partition(num_sheets, max_folio_size): def find_partition_mink(num_sheets, max_folio_size):
max_a = num_sheets // max_folio_size max_a = num_sheets // max_folio_size
for k in range(1, max_folio_size): for k in range(1, max_folio_size):
# We want to solve a*k = L (mod n-k). This happens iff # We want to solve a*k = L (mod n-k). This happens iff
@ -57,7 +58,12 @@ def find_partition(num_sheets, max_folio_size):
# substracting almost mprime. # substracting almost mprime.
candidate = max_a - tosub candidate = max_a - tosub
if (candidate >= 0): if (candidate >= 0):
return (candidate, k) b = (num_sheets - max_folio_size * candidate)//(max_folio_size - k)
return [max_folio_size] * candidate + [max_folio_size - k] * b
def find_partition_greedy(num_sheets, max_folio_size):
q = num_sheets//max_folio_size
return [max_folio_size] * q + [num_sheets - q*max_folio_size]
# Interprets input_pdf as a list of A6 pages, and appends to append_to with # Interprets input_pdf as a list of A6 pages, and appends to append_to with
# A5 pages using the following rules: # A5 pages using the following rules:
@ -65,23 +71,29 @@ def find_partition(num_sheets, max_folio_size):
# with "mirror around **short** edge" # with "mirror around **short** edge"
# b. when grouped as consecutive sequences of max_folio_size or less, the printed # 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 # sheets can be folded in the middle and assembled as a folio
def foliate_A6(input_pdf, max_folio_size=-1, append_to=PdfWriter()): def foliate_A6(input_pdf, strat_func, max_folio_size, append_to=PdfWriter()):
current_page = 0
doc_length = len(input_pdf.pages) doc_length = len(input_pdf.pages)
writer = append_to writer = append_to
if max_folio_size < 0:
max_folio_size = doc_length num_sheets = math.ceil(doc_length/4.0)
print("Using", num_sheets, "two-sided A5 sheets")
L = [num_sheets]
if max_folio_size > 0:
L = strat_func(num_sheets, max_folio_size)
if(np.sum(L) != num_sheets):
print("[ERROR] strategy gave", np.sum(L), " A5 sheets")
exit(1)
folio_page_size = 0 folio_page_size = 0
while(current_page < doc_length): current_page = 0
# max_folio_size is a number of _sheets_, each containing 4 pages for l in L:
folio_page_size = min(doc_length - current_page, 4*max_folio_size) # l is a number of _sheets_, each containing 4 pages
folio_page_size = min(doc_length - current_page, 4*l)
append_folio_A6(input_pdf, current_page, folio_page_size, append_to) append_folio_A6(input_pdf, current_page, folio_page_size, append_to)
current_page += folio_page_size current_page += folio_page_size
print("Dangling folio has",folio_page_size,"pages",
"(",int(math.ceil(folio_page_size/4.0)),"sheets).")
return writer return writer
# Take an A5 printing plan, with odd/even pages being understood # Take an A5 printing plan, with odd/even pages being understood
@ -106,7 +118,7 @@ def blit_to_A4(input_pdf, append_to=PdfWriter()):
writer.add_annotation(front_page, midline) writer.add_annotation(front_page, midline)
front = input_pdf.pages[k] front = input_pdf.pages[k]
back = input_pdf.pages[k+1] if (k+1<L) else create_blank_page(None, PaperSize.A5.width, PaperSize.A5.height) back = input_pdf.pages[k+1] if (k+1<L) else PageObject.create_blank_page(None, PaperSize.A5.width, PaperSize.A5.height)
front.mediabox = front_page.mediabox front.mediabox = front_page.mediabox
back.mediabox = back_page.mediabox back.mediabox = back_page.mediabox
@ -129,7 +141,7 @@ parser.add_argument("-fs", help="maximum folio size, in sheets",
args = parser.parse_args() args = parser.parse_args()
input_pdf = PdfReader(args.infile) input_pdf = PdfReader(args.infile)
a5 = foliate_A6(input_pdf, args.fs) a5 = foliate_A6(input_pdf, find_partition_greedy, args.fs)
if (args.a5): if (args.a5):
a5.write(args.outfile) a5.write(args.outfile)
else: else:

View file

@ -6,6 +6,7 @@ pkgs.mkShell {
packages = [ packages = [
(pkgs.python3.withPackages (pythonPackages: with python3Packages; [ (pkgs.python3.withPackages (pythonPackages: with python3Packages; [
pypdf pypdf
numpy
])) ]))
]; ];
} }