fix colors

master
Sébastien Miquel 2026-02-28 15:22:04 +01:00
parent e610c80a69
commit e5140a460a
2 changed files with 36 additions and 25 deletions

View File

@ -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) final_img.alpha_composite(img)
return final_img return final_img
import io
from PIL import Image
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors import matplotlib.colors as mcolors
from highlight_text import ax_text
def render_score_text(label, score, error, width_px, fontsize=18, def render_score_text(label, score, error, width_px, fontsize=18,
bg_color=(255, 255, 255, 255), bg_color=(255, 255, 255, 255),
with_error=True): with_error=True):
# 1. Calculate Color Gradient (0.0=DarkRed -> 4.0=Green) # 1. Calculate Color Gradient
# Clamp score between 0 and 4
t = max(0.0, min(1.0, float(score) / 4.0)) t = max(0.0, min(1.0, float(score) / 4.0))
t = t*1.5 - 0.25
# Dark Red (139, 0, 0) to Green (0, 128, 0) t = max(0.0, min(1.0, t))
red = 139 * (1 - t) red = 200 * (1 - t)
green = 128 * t green = 150 * t
hex_color = mcolors.to_hex((red/255, green/255, 0)) hex_color = mcolors.to_hex((red/255, green/255, 0))
# 2. Build Text with Mathtext Color # 2. Build highlight-text String & Properties
# We use \color{hex} to color specific parts in Matplotlib # Wrap colored parts in < >
score_str = f"{label} ; Note : \\color{{{hex_color}}}{{{score}}}" score_str = f"{label} ; Note : <{score}>"
hl_props = [{"color": hex_color, "fontweight": "bold"}]
if error and error != "null" and with_error: if error and error != "null" and with_error:
# Uses standard Matplotlib color name 'orange' score_str += f" | <Error: {error}>"
score_str += f" | \\color{{orange}}{{Error: {error}}}" hl_props.append({"color": "orange", "fontweight": "bold"})
# 3. Wrap Text (using your existing heuristic) # 3. Wrap Text
dpi = 100 dpi = 100
fig_width = width_px / dpi 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 # Note: Since there is no LaTeX anymore, standard textwrap works well here
wrapped_text = wrap_latex_text(score_str, chars_per_line) 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 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, # Replaces plt.text
verticalalignment='top', horizontalalignment='left', ax_text(0.01, 0.95, wrapped_text,
wrap=False) # wrap=False because wrap_latex_text handled it fontsize=fontsize,
verticalalignment='top',
plt.axis('off') horizontalalignment='left',
highlight_textprops=hl_props,
ax=ax)
buf = io.BytesIO() buf = io.BytesIO()
plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0.1, transparent=True) 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) process_student(student_id, labels, root_dir, all_labels, overwrite)
import argparse import argparse
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Annotate copies") parser = argparse.ArgumentParser(description="Annotate copies")
parser.add_argument("root_dir", help="Directory containing the copies") parser.add_argument("root_dir", help="Directory containing the copies")

View File

@ -103,13 +103,13 @@ def detect_checks_and_notes(output_dir):
actions.append(box) actions.append(box)
# It's checked, so we mask this area out for manual notes # It's checked, so we mask this area out for manual notes
# Expand mask slightly to catch sloppy ticks # 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: else:
mask_draw.rectangle([x1-2, y1-2, x2+2, y2+2], fill=0) mask_draw.rectangle([x1-2, y1-2, x2+2, y2+2], fill=0)
if box["type"] == "score" and box["value"] == 0.0: if box["type"] == "score" and box["value"] == 0.0:
# Mask the whole line # 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 --- # --- 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")) full_img.save(os.path.join(output_dir, "Concat.jpg"))
print(f" Saved regenerated Concat.jpg") print(f" Saved regenerated Concat.jpg")
from pathlib import Path
if __name__ == "__main__": if __name__ == "__main__":
if len(sys.argv) < 2: if len(sys.argv) < 2:
print("Usage: python reading_annotations.py <Dir>") print("Usage: python reading_annotations.py <Dir>")