From 5367624808b9bf7401211593c9a60ee94173784b Mon Sep 17 00:00:00 2001 From: Ignacio Rivero Date: Sun, 22 Jun 2025 18:17:28 -0300 Subject: [PATCH] Added image support --- app.py | 82 +++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 61 insertions(+), 21 deletions(-) diff --git a/app.py b/app.py index 2d239be..1ff595f 100644 --- a/app.py +++ b/app.py @@ -1,6 +1,7 @@ import io import tempfile import subprocess +import requests from flask import Flask, render_template_string, request, send_from_directory from PIL import Image, ImageDraw, ImageFont import re @@ -286,27 +287,48 @@ HTML_FORM = '''
  • Encabezado chico: ### Título
  • Lista con viñetas: - Elemento
  • Lista numerada: 1. Elemento
  • +
  • Imágen: ![Texto alternativo](Enlace a imágen)
  • Salto de línea: Deje una línea vacía
  • ''' +def bleh_image_from_url(url): + resp = requests.get(url, stream=True) + resp.raise_for_status() + bleh = subprocess.Popen( + ["./bleh", "-o", "-", "-mode", "1bpp", "-d", "floyd", "-"], + stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = bleh.communicate(resp.content) + if bleh.returncode != 0: + raise RuntimeError(f"Driver failed: {err.decode()}") + img = Image.open(io.BytesIO(out)).convert("L") + # Optionally check width, pad/resize if needed + if img.width != IMAGE_WIDTH: + img = img.resize((IMAGE_WIDTH, img.height), Image.LANCZOS) + return img + def parse_line(line): - if re.match(r'^\s*---\s*$', line): - return ('hr', []) - header_match = re.match(r"^(#{1,3}) +(.*)", line) - if header_match: - header_level = len(header_match.group(1)) - line = header_match.group(2) - return ('header', header_level, parse_segments(line)) - bullet_match = re.match(r"^\s*([-*\u2022]) +(.*)", line) - if bullet_match: - return ('bullet', parse_segments(bullet_match.group(2))) - ordered_match = re.match(r"^\s*(\d+)\. +(.*)", line) - if ordered_match: - return ('ordered', int(ordered_match.group(1)), parse_segments(ordered_match.group(2))) - return ('text', parse_segments(line)) + image_match = re.match(r"^!\[(.*?)\]\((.+?)\)", line) + if image_match: + alt = image_match.group(1) + url = image_match.group(2) + return ('image', url, alt) + if re.match(r'^\s*---\s*$', line): + return ('hr', []) + header_match = re.match(r"^(#{1,3}) +(.*)", line) + if header_match: + header_level = len(header_match.group(1)) + line = header_match.group(2) + return ('header', header_level, parse_segments(line)) + bullet_match = re.match(r"^\s*([-*\u2022]) +(.*)", line) + if bullet_match: + return ('bullet', parse_segments(bullet_match.group(2))) + ordered_match = re.match(r"^\s*(\d+)\. +(.*)", line) + if ordered_match: + return ('ordered', int(ordered_match.group(1)), parse_segments(ordered_match.group(2))) + return ('text', parse_segments(line)) def parse_segments(line): # Handle escaped asterisks: replace them with a placeholder @@ -401,7 +423,13 @@ def render(md): lines_out.append(('blank', [])) continue tag = parse_line(src_line) - if tag[0] == 'hr': + if tag[0] == 'image': + try: + image = bleh_image_from_url(tag[1]) + lines_out.append(('image', image)) + except Exception as e: + lines_out.append(('text', [('text', f"[Imagen inválida: {e}]")], font, FONT_SIZE)) + elif tag[0] == 'hr': lines_out.append(('hr',)) elif tag[0] == 'header': header_level = tag[1] @@ -443,12 +471,18 @@ def render(md): for wrapped in wrap_segments(segments, font, font_bold, font_italic, font_bolditalic, IMAGE_WIDTH): lines_out.append(('text', wrapped, font, FONT_SIZE)) - height = sum( - item[3] if item[0] in ('header', 'text', 'bullet', 'ordered') else - 10 if item[0] == 'hr' else - FONT_SIZE - for item in lines_out - ) + 10 + # Compute total height, including images + height = 10 # Top margin + for item in lines_out: + if item[0] in ('header', 'text', 'bullet', 'ordered'): + height += item[3] + elif item[0] == 'hr': + height += 10 + elif item[0] == 'blank': + height += FONT_SIZE + elif item[0] == 'image': + img = item[1] + height += img.height + 10 # add margin below image image = Image.new("L", (IMAGE_WIDTH, height), 255) draw = ImageDraw.Draw(image) @@ -500,6 +534,12 @@ def render(md): draw.text((x, y), text, font=f, fill=0) x += f.getbbox(text)[2] - f.getbbox(text)[0] y += sz + elif item[0] == 'image': + img = item[1] + # Center image horizontally if narrower + img_x = (IMAGE_WIDTH - img.width) // 2 if img.width < IMAGE_WIDTH else 0 + image.paste(img, (img_x, y)) + y += img.height + 10 # vertical margin after image return image @app.route("/", methods=["GET", "POST"])