diff --git a/annotating.py b/annotating.py index dea9370..c9fd6ce 100644 --- a/annotating.py +++ b/annotating.py @@ -219,47 +219,55 @@ def render_latex_text(text, width_px, bg_color=(255, 255, 255, 255), max_lines=N final_img.alpha_composite(img) return final_img +import io +from PIL import Image +import matplotlib.pyplot as plt import matplotlib.colors as mcolors +from highlight_text import ax_text def render_score_text(label, score, error, width_px, fontsize=18, bg_color=(255, 255, 255, 255), with_error=True): - # 1. Calculate Color Gradient (0.0=DarkRed -> 4.0=Green) - # Clamp score between 0 and 4 + # 1. Calculate Color Gradient t = max(0.0, min(1.0, float(score) / 4.0)) - - # Dark Red (139, 0, 0) to Green (0, 128, 0) - red = 139 * (1 - t) - green = 128 * t + t = t*1.5 - 0.25 + t = max(0.0, min(1.0, t)) + red = 200 * (1 - t) + green = 150 * t hex_color = mcolors.to_hex((red/255, green/255, 0)) - # 2. Build Text with Mathtext Color - # We use \color{hex} to color specific parts in Matplotlib - score_str = f"{label} ; Note : \\color{{{hex_color}}}{{{score}}}" + # 2. Build highlight-text String & Properties + # Wrap colored parts in < > + score_str = f"{label} ; Note : <{score}>" + hl_props = [{"color": hex_color, "fontweight": "bold"}] if error and error != "null" and with_error: - # Uses standard Matplotlib color name 'orange' - score_str += f" | \\color{{orange}}{{Error: {error}}}" + score_str += f" | " + hl_props.append({"color": "orange", "fontweight": "bold"}) - # 3. Wrap Text (using your existing heuristic) + # 3. Wrap Text dpi = 100 fig_width = width_px / dpi - chars_per_line = int(fig_width * 10) # Heuristic from your snippet + chars_per_line = int(fig_width * 10) - # Use your existing wrapper - wrapped_text = wrap_latex_text(score_str, chars_per_line) + # Note: Since there is no LaTeX anymore, standard textwrap works well here + import textwrap + wrapped_text = textwrap.fill(score_str, width=chars_per_line) - # 4. Render (Standard Matplotlib boilerplate) + # 4. Render using highlight_text.ax_text num_lines = wrapped_text.count('\n') + 1 - fig_height = num_lines * 0.4 + 0.2 # Slight padding adjustment + fig_height = num_lines * 0.4 + 0.2 - fig = plt.figure(figsize=(fig_width, fig_height), dpi=dpi) + fig, ax = plt.subplots(figsize=(fig_width, fig_height), dpi=dpi) + ax.axis('off') - plt.text(0.01, 0.95, wrapped_text, fontsize=fontsize, - verticalalignment='top', horizontalalignment='left', - wrap=False) # wrap=False because wrap_latex_text handled it - - plt.axis('off') + # Replaces plt.text + ax_text(0.01, 0.95, wrapped_text, + fontsize=fontsize, + verticalalignment='top', + horizontalalignment='left', + highlight_textprops=hl_props, + ax=ax) buf = io.BytesIO() plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0.1, transparent=True) @@ -491,6 +499,7 @@ def process_correction(root_dir, data, all_labels, overwrite=False): process_student(student_id, labels, root_dir, all_labels, overwrite) import argparse + if __name__ == "__main__": parser = argparse.ArgumentParser(description="Annotate copies") parser.add_argument("root_dir", help="Directory containing the copies") diff --git a/reading_annotations.py b/reading_annotations.py index 2a15f79..5f62032 100644 --- a/reading_annotations.py +++ b/reading_annotations.py @@ -103,13 +103,13 @@ def detect_checks_and_notes(output_dir): actions.append(box) # It's checked, so we mask this area out for manual notes # Expand mask slightly to catch sloppy ticks - mask_draw.rectangle([x1-5, y1-5, x2+5, y2+5], fill=0) + mask_draw.rectangle([x1-15, y1-15, x2+15, y2+15], fill=0) else: mask_draw.rectangle([x1-2, y1-2, x2+2, y2+2], fill=0) if box["type"] == "score" and box["value"] == 0.0: # Mask the whole line - mask_draw.rectangle([0, y1-5, ref_img.width, y2+5], fill=0) + mask_draw.rectangle([0, y1-10, ref_img.width, y2+10], fill=0) # --- Extraction Phase --- @@ -290,6 +290,8 @@ def apply_actions_and_regenerate(root_dir, data, student_id, actions, notes_laye full_img.save(os.path.join(output_dir, "Concat.jpg")) print(f" Saved regenerated Concat.jpg") +from pathlib import Path + if __name__ == "__main__": if len(sys.argv) < 2: print("Usage: python reading_annotations.py ")