Added Banner Mode, updated requirements.txt (oops)

This commit is contained in:
Ignacio Rivero 2025-06-24 02:58:28 -03:00
parent 638228a88d
commit 84c0be9742
2 changed files with 43 additions and 4 deletions

44
app.py
View File

@ -20,6 +20,7 @@ FONT_SIZE = 24
HEADER_SIZE_1 = 56
HEADER_SIZE_2 = 34
HEADER_SIZE_3 = 28
BANNER_FONT_SIZE = 300
IMAGE_WIDTH = 384
BULLET_CHAR = ""
@ -390,6 +391,12 @@ HTML_FORM = '''
<label for="userimg" style="display: inline-block; margin-bottom: 0.5em;">Subir imagen (opcional):</label><br>
<input type="file" name="userimg" accept="image/png, image/jpeg"><br>
<div class="options">
<div class="options-bannermode">
<label for="bannermode">
<input type="checkbox" name="bannermode" value="1" {% if current_bannermode %}checked{% endif %}>
Modo Banner (vertical)
</label>
</div>
<div class="options-dithering">
<label for="dithering">Dithering:</label>
<select name="dithering">
@ -619,10 +626,11 @@ def wrap_segments(segments, font, font_bold, font_italic, font_bolditalic, max_w
if line:
yield line
def render(md, dithering, printmode, uploaded_img_bytes=None):
def render(md, dithering, printmode, uploaded_img_bytes=None, bannermode=False):
font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
font_bold = ImageFont.truetype(FONT_PATH_BOLD, FONT_SIZE)
font_italic = ImageFont.truetype(FONT_PATH_OBLIQUE, FONT_SIZE)
font_banner = ImageFont.truetype(FONT_PATH_BOLD, BANNER_FONT_SIZE)
try:
font_bolditalic = ImageFont.truetype(FONT_PATH_BOLDITALIC, FONT_SIZE)
except:
@ -630,7 +638,33 @@ def render(md, dithering, printmode, uploaded_img_bytes=None):
font_h1 = ImageFont.truetype(FONT_PATH_BOLD, HEADER_SIZE_1)
font_h2 = ImageFont.truetype(FONT_PATH_BOLD, HEADER_SIZE_2)
font_h3 = ImageFont.truetype(FONT_PATH_BOLD, HEADER_SIZE_3)
if bannermode:
# Remove line breaks for single-line banner
md = md.replace('\r\n', ' ') # should change this if we're ever on windows
# Only render as a single text line (ignore markdown except bold/italic)
segments = parse_segments(md)
# Calculate total width needed
x = 0
for style, text in segments:
f = font_banner
x += f.getbbox(text)[2] - f.getbbox(text)[0]
width = max(x, 1)
# Create image: width x 384 (height is printer width)
image = Image.new("L", (width, IMAGE_WIDTH), 255)
draw = ImageDraw.Draw(image)
x = 0
y = (IMAGE_WIDTH - BANNER_FONT_SIZE) // 2 # Center vertically
for style, text in segments:
f = font_banner
draw.text((x, y), text, font=f, fill=0)
x += f.getbbox(text)[2] - f.getbbox(text)[0]
# Rotate so text is vertical
image = image.rotate(270, expand=True)
return image
lines_out = []
for src_line in md.splitlines():
if src_line.strip() == '':
lines_out.append(('blank', []))
@ -763,6 +797,8 @@ def render(md, dithering, printmode, uploaded_img_bytes=None):
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
if bannermode:
image = image.rotate(270, expand=True)
return image
@app.route("/", methods=["GET", "POST"])
@ -804,10 +840,12 @@ def index():
md = request.form["md"]
dithering = request.form.get("dithering", "floyd")
printmode = request.form.get("printmode", "1bpp")
image = render(md, dithering, printmode, uploaded_img_bytes)
bannermode = bool(request.form.get("bannermode"))
image = render(md, dithering, printmode, uploaded_img_bytes, bannermode=bannermode)
session['dithering'] = dithering
session['printmode'] = printmode
session['rotation'] = rotation
session['bannermode'] = bannermode
buf = io.BytesIO()
image.save(buf, format="PNG")
buf.seek(0)
@ -841,7 +879,7 @@ def index():
except Exception as e:
error = f"Failed to print: {e}"
return render_template_string(HTML_FORM, dithering_modes=DITHERING_MODES, img=img_data, default_md=md,
printed=printed, error=error, current_dithering=session.get('dithering', 'floyd'), current_rotation=session.get('rotation', 0), current_printmode=session.get('printmode', '1bpp'))
printed=printed, error=error, current_dithering=session.get('dithering', 'floyd'), current_rotation=session.get('rotation', 0), current_printmode=session.get('printmode', '1bpp'), current_bannermode=session.get('bannermode', False))
@app.route('/manifest.json')
def manifest():

View File

@ -1,3 +1,4 @@
Flask
markdown
Pillow
requests