32k pixel as hard group limit, better manual resolution support

This commit is contained in:
sebastien committed 2026-09-22 11:42:16 +02:00
1 parent a9c0703f03
commit 5009831c7c
9 files changed
+322 -58

No files matched your search

+41 -24
View File
@@ -27,7 +27,7 @@ from copienator.commands import annotating, annotating_with_checks
from copienator.filesystem import staged_directory
from copienator.utils import natural_key
MAX_HEIGHT_PX = 25000
MAX_HEIGHT_PX = 32000
def render_item(item):
@@ -63,6 +63,11 @@ def save_batch(batch, prefix, group_id, output_root: Path) -> None:
print(f"Generating group PDF: {prefix} G{group_id} ({len(batch)} elements)")
max_width = max(item[2].width for item in batch)
total_height = sum(item[2].height for item in batch)
if total_height > MAX_HEIGHT_PX:
raise CliError(
f"{prefix} G{group_id} would be {total_height} px high; "
f"the maximum is {MAX_HEIGHT_PX} px."
)
concatenated = Image.new("RGB", (max_width, total_height), "white")
draw = ImageDraw.Draw(concatenated)
checkbox_map: list[dict[str, Any]] = []
@@ -268,32 +273,44 @@ def _existing_group_state(
def split_batches(rendered):
def split(maximum_height: float):
batches = []
current = []
current_height = 0
previous_student = None
for item in rendered:
student_id = item[0]
image_height = item[2].height
if (
current
and current_height + image_height > maximum_height
and student_id != previous_student
):
batches.append(current)
current = []
current_height = 0
current.append(item)
current_height += image_height
previous_student = student_id
batches = []
current = []
current_height = 0
def flush() -> None:
nonlocal current, current_height
if current:
batches.append(current)
return batches
current = []
current_height = 0
strict = split(MAX_HEIGHT_PX)
relaxed = split(1.1 * MAX_HEIGHT_PX)
return relaxed if len(relaxed) < len(strict) else strict
index = 0
while index < len(rendered):
student_id = rendered[index][0]
end = index + 1
while end < len(rendered) and rendered[end][0] == student_id:
end += 1
student_items = rendered[index:end]
student_height = sum(item[2].height for item in student_items)
if student_height > MAX_HEIGHT_PX:
labels = ", ".join(item[1] for item in student_items)
raise CliError(
f"Copie{student_id} ({labels}) is {student_height} px high; "
f"one student's labels cannot be split across groups and the "
f"maximum group height is {MAX_HEIGHT_PX} px."
)
# Consider the student's complete block before adding its first image.
# Otherwise later images from that same student could overflow the batch.
if current and current_height + student_height > MAX_HEIGHT_PX:
flush()
current.extend(student_items)
current_height += student_height
index = end
flush()
return batches
def _generate_groups(