Move to real LaTeX rendering
This commit is contained in:
+68
-2
@@ -219,6 +219,71 @@ 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 os
|
||||
import tempfile
|
||||
import subprocess
|
||||
import PIL.ImageOps
|
||||
|
||||
|
||||
def render_real_latex_text(text, width_px, bg_color=(255, 255, 255, 255), max_lines=None, fontsize=19):
|
||||
dpi = 100
|
||||
width_in = width_px / dpi
|
||||
line_spacing = int(fontsize * 1.2)
|
||||
|
||||
# Use the 'standalone' class with 'varwidth' to auto-crop height while restricting width
|
||||
latex_template = f"""\\documentclass[varwidth={width_in}in,margin=0.2cm]{{standalone}}
|
||||
\\usepackage[utf8]{{inputenc}}
|
||||
\\usepackage[T1]{{fontenc}}
|
||||
\\usepackage{{lmodern}} % Enables arbitrary font scaling
|
||||
\\usepackage{{amsmath, amssymb}}
|
||||
%\\usepackage{{anyfontsize}} % replaces by lmodern
|
||||
\\begin{{document}}
|
||||
\\fontsize{{{fontsize}}}{{{line_spacing}}}\\selectfont
|
||||
{text}
|
||||
\\end{{document}}
|
||||
"""
|
||||
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
tex_path = os.path.join(temp_dir, 'text.tex')
|
||||
pdf_path = os.path.join(temp_dir, 'text.pdf')
|
||||
|
||||
with open(tex_path, 'w', encoding='utf-8') as f:
|
||||
f.write(latex_template)
|
||||
|
||||
# Compile to PDF
|
||||
result = subprocess.run(
|
||||
['pdflatex', '-interaction=nonstopmode', 'text.tex'],
|
||||
cwd=temp_dir,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL
|
||||
)
|
||||
|
||||
if not os.path.exists(pdf_path):
|
||||
raise RuntimeError("LaTeX compilation failed. Check your LaTeX syntax.")
|
||||
|
||||
# Convert PDF to grayscale (ignoring pdf2image's broken transparency)
|
||||
images = convert_from_path(pdf_path, dpi=dpi)
|
||||
gray_img = images[0].convert("L")
|
||||
|
||||
# 1. Invert grayscale to create an alpha mask (white bg = 0, black text = 255)
|
||||
alpha_mask = PIL.ImageOps.invert(gray_img)
|
||||
|
||||
# 2. Create a transparent image with black text using the mask
|
||||
text_img = Image.new("RGBA", gray_img.size, (0, 0, 0, 255))
|
||||
text_img.putalpha(alpha_mask)
|
||||
|
||||
# 3. Create the requested background and composite the text over it
|
||||
final_img = Image.new("RGBA", text_img.size, bg_color)
|
||||
final_img.alpha_composite(text_img)
|
||||
|
||||
# (Optional) Truncate image height if max_lines is strictly enforced
|
||||
if max_lines:
|
||||
max_height_px = int((fontsize * 1.2 / 72.0) * dpi * max_lines) # Points to pixels
|
||||
if final_img.height > max_height_px:
|
||||
final_img = final_img.crop((0, 0, final_img.width, max_height_px))
|
||||
|
||||
return final_img
|
||||
|
||||
import io
|
||||
from PIL import Image
|
||||
import matplotlib.pyplot as plt
|
||||
@@ -376,7 +441,7 @@ def compose_label_image(base_img, label, result, hmin,
|
||||
|
||||
# Render Text
|
||||
txt_img = render_fn(fb['text'], width_px=ANNOT_WIDTH,
|
||||
bg_color=(255, 200, 200, 180), max_lines=3)
|
||||
bg_color=(255, 200, 200, 180), max_lines=None)
|
||||
|
||||
# Calculate Position
|
||||
center_y = (target_ymin + target_ymax) / 2
|
||||
@@ -458,7 +523,8 @@ def process_student(student_id, labels_data, root_dir, all_labels, overwrite):
|
||||
d_notes[label] = str(score)
|
||||
|
||||
final_img, _ = compose_label_image(base_img, label, result, coordinates[0],
|
||||
with_empty=True)
|
||||
with_empty=True,
|
||||
render_fn=render_real_latex_text)
|
||||
# 7. Save Image
|
||||
save_path = os.path.join(output_dir, f"{label}.jpg")
|
||||
final_img.save(save_path)
|
||||
|
||||
Reference in New Issue
Block a user