Compare commits

..

3 Commits

Author SHA1 Message Date
55d3e69320 Added image support 2025-06-22 18:17:28 -03:00
c6a4396c4c New binary, added stdout support. 2025-06-22 17:15:54 -03:00
f464edb1da New binary, changed name 2025-06-22 16:52:37 -03:00
3 changed files with 64 additions and 24 deletions

88
app.py
View File

@ -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 = '''
<li><b>Encabezado chico:</b> <code>### Título</code></li>
<li><b>Lista con viñetas:</b> <code>- Elemento</code></li>
<li><b>Lista numerada:</b> <code>1. Elemento</code></li>
<li><b>Imágen:</b> <code>![Texto alternativo](Enlace a imágen)</code></li>
<li><b>Salto de línea:</b> Deje una línea vacía</li>
</ul>
</div>
</div>
'''
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"])
@ -516,17 +556,17 @@ def index():
buf.seek(0)
import base64
img_data = base64.b64encode(buf.getvalue()).decode()
# If print button pressed, send to catprinter-ble
# If print button pressed, send to driver
if "print" in request.form:
try:
with tempfile.NamedTemporaryFile(suffix=".png", delete=True) as tmpfile:
image.save(tmpfile, format="PNG")
tmpfile.flush()
# Run the catprinter-ble command
# Run the bleh command
# You can set dither method here if desired
result = subprocess.run([
"sudo",
"./catprinter-ble",
"./bleh",
"-mode", "1bpp",
"-intensity", "100",
tmpfile.name

BIN
bleh Executable file

Binary file not shown.

Binary file not shown.