From d7a8e03d2c336ea533db865b2ecccd08855bf9a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Miquel?= Date: Sat, 25 Apr 2026 09:17:48 +0200 Subject: [PATCH] Initial support for _F output file --- add_final_score.py | 8 +++ enonce_info.py | 7 ++- giving_names.py | 4 +- reading_grouped_annotations.py | 102 +++++++++++++++++++++++++++++---- 4 files changed, 106 insertions(+), 15 deletions(-) diff --git a/add_final_score.py b/add_final_score.py index 7d1bc57..799ee24 100644 --- a/add_final_score.py +++ b/add_final_score.py @@ -2,6 +2,7 @@ import argparse import math import sys import os +import shutil from pathlib import Path import pandas as pd from PIL import Image, ImageDraw, ImageFont @@ -96,6 +97,13 @@ def process_images(base_dir): except Exception as e: print(f"Error processing image for '{student_name}': {e}") + for pdf_path in sorted(search_path.glob("*/*.pdf")): + student_name = pdf_path.stem # Filename without extension + save_path = OUTPUT_DIR / f"{student_name}.pdf" + + shutil.copy(str(pdf_path), str(save_path)) + + if __name__ == "__main__": parser = argparse.ArgumentParser(description="Stamp scores on exam copies.") parser.add_argument("dir", type=Path, help="Root directory containing 'A Rendre' folder") diff --git a/enonce_info.py b/enonce_info.py index 615f022..a2fdf61 100644 --- a/enonce_info.py +++ b/enonce_info.py @@ -8,17 +8,20 @@ import subprocess import tempfile import shutil -def compile_to_pdf(text, output_pdf_path): +def compile_to_pdf(text, output_pdf_path): # 21 cm + 3.8 (dimension de la marge de gauche) """Wraps text in a standalone template and compiles it to PDF.""" - latex_template = f"""\\documentclass[varwidth=21cm,margin=0.2cm]{{standalone}} + latex_template = f"""\\documentclass[varwidth=24.8cm,margin=0.4cm]{{standalone}} \\usepackage[utf8]{{inputenc}} \\usepackage[T1]{{fontenc}} \\usepackage{{lmodern}} \\usepackage{{amsmath, amssymb}} \\usepackage{{commands}} +\\usepackage{{graphicx}} \\usepackage{{enumitem}} \\begin{{document}} + \\begin{{minipage}}{{24.8cm}} {text} + \\end{{minipage}} \\end{{document}} """ with tempfile.TemporaryDirectory() as temp_dir: diff --git a/giving_names.py b/giving_names.py index a69f40a..8119796 100644 --- a/giving_names.py +++ b/giving_names.py @@ -73,13 +73,13 @@ def main(): dest_path = os.path.join(target_subdir, dest_folder_name) os.makedirs(dest_path, exist_ok=True) - links = [("Concat.jpg", f"{safe_name}.jpg"), ("score.json", "score.json")] + links = [("Concat.jpg", f"{safe_name}.jpg"),("Concat_F.pdf", f"{safe_name}.pdf"), ("score.json", "score.json")] for src_name, dst_name in links: src_file = os.path.join(source_folder, src_name) dst_link = os.path.join(dest_path, dst_name) try: if os.path.lexists(dst_link): os.remove(dst_link) - os.symlink(src_file, dst_link) + if os.path.exists(src_file): os.symlink(src_file, dst_link) except Exception as e: print(f"Error linking {src_name} for {dest_folder_name}: {e}") diff --git a/reading_grouped_annotations.py b/reading_grouped_annotations.py index 359b032..e89b520 100644 --- a/reading_grouped_annotations.py +++ b/reading_grouped_annotations.py @@ -4,7 +4,7 @@ import json import collections import concurrent.futures from pathlib import Path -from PIL import Image +from PIL import Image, ImageDraw import threading import annotating @@ -12,6 +12,79 @@ import annotating from utils import natural_key from reading_annotations import detect_checks_and_notes, has_significant_notes +def get_extra_pdfs_as_images(root_dir, label, annotating_module): + """Fetches Text and Sol pdfs for a given label and converts them to images.""" + extra_images = [] + for folder in ["Text", "Sol"]: + pdf_path = os.path.join(root_dir, folder, f"{label}.pdf") + if os.path.exists(pdf_path): + img, _, _ = annotating_module.make_base_image(pdf_path) + if img: + extra_images.append(img) + return extra_images + +def save_paginated_pdf(image_groups, output_path): + """Concatenates groups of images vertically, adding specific inner borders.""" + if not image_groups: + return + + max_w = max(img.width for group in image_groups for img in group) + max_page_h = int(max_w * 1.414 * 1.3) + + # Calculate 0.2 cm in pixels at 100 DPI (0.2 / 2.54 inches * 100) + border_px = int((0.2 / 2.54) * 100) + + pages = [] + current_page_imgs = [] + current_h = 0 + + for group in image_groups: + if not group: + continue + + # Process the group to add borders + processed_group = [] + for i, img in enumerate(group): + if i in (0, 1): + img = img.copy() # Do not modify the original image object in memory + draw = ImageDraw.Draw(img) + color = "black" if i == 0 else "blue" + + # Draw the border inside the image edges + draw.rectangle( + [0, 0, img.width - 1, img.height - 1], + outline=color, + width=border_px + ) + processed_group.append(img) + + group_h = sum(img.height for img in processed_group) + + if current_page_imgs and (current_h + group_h > max_page_h): + page = Image.new("RGB", (max_w, current_h), "white") + y = 0 + for c_img in current_page_imgs: + page.paste(c_img, (0, y)) + y += c_img.height + pages.append(page) + + current_page_imgs = processed_group + current_h = group_h + else: + current_page_imgs.extend(processed_group) + current_h += group_h + + if current_page_imgs: + page = Image.new("RGB", (max_w, current_h), "white") + y = 0 + for c_img in current_page_imgs: + page.paste(c_img, (0, y)) + y += c_img.height + pages.append(page) + + if pages: + pages[0].save(output_path, "PDF", resolution=100.0, save_all=True, append_images=pages[1:]) + def apply_actions_and_regenerate_grouped(root_dir, data, student_id, actions, label_notes, all_labels): """ Modifies data based on actions, pastes label-specific note crops, @@ -136,8 +209,11 @@ def apply_actions_and_regenerate_grouped(root_dir, data, student_id, actions, la else: if len(result.get('feedback', [])) != 0: perfect_no_comment = False + if not perfect_no_comment: - concat_list_F.append(final_img) + extras = get_extra_pdfs_as_images(root_dir, label, annotating) + extras.append(final_img) + concat_list_F.append(extras) # --- 3. Save Final Outputs --- with open(score_path, "w") as f: @@ -158,17 +234,21 @@ def apply_actions_and_regenerate_grouped(root_dir, data, student_id, actions, la logs.append(f" Saved regenerated Concat.jpg") if concat_list_F: - max_w = max(i.width for i in concat_list_F) - total_h = sum(i.height for i in concat_list_F) - full_img = Image.new("RGB", (max_w, total_h), "white") + pdf_out_path = os.path.join(output_dir, "Concat_F.pdf") + save_paginated_pdf(concat_list_F, pdf_out_path) + logs.append(f" Saved regenerated Concat_F.pdf") - y = 0 - for img in concat_list_F: - full_img.paste(img, (0, y)) - y += img.height + # max_w = max(i.width for i in concat_list_F) + # total_h = sum(i.height for i in concat_list_F) + # full_img = Image.new("RGB", (max_w, total_h), "white") - full_img.save(os.path.join(output_dir, "Concat_F.jpg")) - logs.append(f" Saved regenerated Concat_F.jpg") + # y = 0 + # for img in concat_list_F: + # full_img.paste(img, (0, y)) + # y += img.height + + # full_img.save(os.path.join(output_dir, "Concat_F.jpg")) + # logs.append(f" Saved regenerated Concat_F.jpg") return "\n".join(logs)