Font size support
This commit is contained in:
68
app.py
68
app.py
@@ -17,10 +17,16 @@ FONT_PATH = "./fonts/ubuntu/Ubuntu-Regular.ttf"
|
|||||||
FONT_PATH_BOLD = "./fonts/ubuntu/Ubuntu-Bold.ttf"
|
FONT_PATH_BOLD = "./fonts/ubuntu/Ubuntu-Bold.ttf"
|
||||||
FONT_PATH_OBLIQUE = "./fonts/ubuntu/Ubuntu-Italic.ttf"
|
FONT_PATH_OBLIQUE = "./fonts/ubuntu/Ubuntu-Italic.ttf"
|
||||||
FONT_PATH_BOLDITALIC = "./fonts/ubuntu/Ubuntu-BoldItalic.ttf"
|
FONT_PATH_BOLDITALIC = "./fonts/ubuntu/Ubuntu-BoldItalic.ttf"
|
||||||
FONT_SIZE = 24
|
DEFAULT_FONT_SIZE = 24
|
||||||
HEADER_SIZE_1 = 56
|
FONT_SIZE_OPTIONS = {
|
||||||
HEADER_SIZE_2 = 34
|
"small": 18,
|
||||||
HEADER_SIZE_3 = 28
|
"normal": 24,
|
||||||
|
"large": 30,
|
||||||
|
"xlarge": 36,
|
||||||
|
}
|
||||||
|
HEADER_RATIO_1 = 56 / 24
|
||||||
|
HEADER_RATIO_2 = 34 / 24
|
||||||
|
HEADER_RATIO_3 = 28 / 24
|
||||||
BANNER_FONT_SIZE = 300
|
BANNER_FONT_SIZE = 300
|
||||||
IMAGE_WIDTH = 384
|
IMAGE_WIDTH = 384
|
||||||
BULLET_CHAR = "• "
|
BULLET_CHAR = "• "
|
||||||
@@ -343,18 +349,24 @@ def wrap_segments(segments, font, font_bold, font_italic, font_bolditalic, max_w
|
|||||||
if line:
|
if line:
|
||||||
yield line
|
yield line
|
||||||
|
|
||||||
def render(md, dithering, printmode, uploaded_img_bytes=None, bannermode=False):
|
def render(md, dithering, printmode, uploaded_img_bytes=None, bannermode=False, font_size=None):
|
||||||
font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
if font_size is None:
|
||||||
font_bold = ImageFont.truetype(FONT_PATH_BOLD, FONT_SIZE)
|
font_size = DEFAULT_FONT_SIZE
|
||||||
font_italic = ImageFont.truetype(FONT_PATH_OBLIQUE, FONT_SIZE)
|
header_size_1 = round(font_size * HEADER_RATIO_1)
|
||||||
|
header_size_2 = round(font_size * HEADER_RATIO_2)
|
||||||
|
header_size_3 = round(font_size * HEADER_RATIO_3)
|
||||||
|
|
||||||
|
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)
|
font_banner = ImageFont.truetype(FONT_PATH_BOLD, BANNER_FONT_SIZE)
|
||||||
try:
|
try:
|
||||||
font_bolditalic = ImageFont.truetype(FONT_PATH_BOLDITALIC, FONT_SIZE)
|
font_bolditalic = ImageFont.truetype(FONT_PATH_BOLDITALIC, font_size)
|
||||||
except:
|
except:
|
||||||
font_bolditalic = None
|
font_bolditalic = None
|
||||||
font_h1 = ImageFont.truetype(FONT_PATH_BOLD, HEADER_SIZE_1)
|
font_h1 = ImageFont.truetype(FONT_PATH_BOLD, header_size_1)
|
||||||
font_h2 = ImageFont.truetype(FONT_PATH_BOLD, HEADER_SIZE_2)
|
font_h2 = ImageFont.truetype(FONT_PATH_BOLD, header_size_2)
|
||||||
font_h3 = ImageFont.truetype(FONT_PATH_BOLD, HEADER_SIZE_3)
|
font_h3 = ImageFont.truetype(FONT_PATH_BOLD, header_size_3)
|
||||||
|
|
||||||
if bannermode:
|
if bannermode:
|
||||||
# Remove line breaks for single-line banner
|
# Remove line breaks for single-line banner
|
||||||
@@ -392,17 +404,17 @@ def render(md, dithering, printmode, uploaded_img_bytes=None, bannermode=False):
|
|||||||
image = bleh_image_from_url(tag[1], dithering, printmode)
|
image = bleh_image_from_url(tag[1], dithering, printmode)
|
||||||
lines_out.append(('image', image))
|
lines_out.append(('image', image))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
lines_out.append(('text', [('text', f"[Imagen inválida: {e}]")], font, FONT_SIZE))
|
lines_out.append(('text', [('text', f"[Imagen inválida: {e}]")], font, font_size))
|
||||||
elif tag[0] == 'userimage':
|
elif tag[0] == 'userimage':
|
||||||
if uploaded_img_bytes:
|
if uploaded_img_bytes:
|
||||||
try:
|
try:
|
||||||
image = bleh_image_from_bytes(uploaded_img_bytes, dithering, printmode)
|
image = bleh_image_from_bytes(uploaded_img_bytes, dithering, printmode)
|
||||||
lines_out.append(('image', image))
|
lines_out.append(('image', image))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
lines_out.append(('text', [('text', f"[Error al procesar imagen]")], font, FONT_SIZE))
|
lines_out.append(('text', [('text', f"[Error al procesar imagen]")], font, font_size))
|
||||||
print(f"Image processing error: {e}")
|
print(f"Image processing error: {e}")
|
||||||
else:
|
else:
|
||||||
lines_out.append(('text', [('text', "[No se subió una imagen]")], font, FONT_SIZE))
|
lines_out.append(('text', [('text', "[No se subió una imagen]")], font, font_size))
|
||||||
elif tag[0] == 'hr':
|
elif tag[0] == 'hr':
|
||||||
lines_out.append(('hr',))
|
lines_out.append(('hr',))
|
||||||
elif tag[0] == 'header':
|
elif tag[0] == 'header':
|
||||||
@@ -410,13 +422,13 @@ def render(md, dithering, printmode, uploaded_img_bytes=None, bannermode=False):
|
|||||||
segments = tag[2]
|
segments = tag[2]
|
||||||
if header_level == 1:
|
if header_level == 1:
|
||||||
font_h = font_h1
|
font_h = font_h1
|
||||||
size_h = HEADER_SIZE_1
|
size_h = header_size_1
|
||||||
elif header_level == 2:
|
elif header_level == 2:
|
||||||
font_h = font_h2
|
font_h = font_h2
|
||||||
size_h = HEADER_SIZE_2
|
size_h = header_size_2
|
||||||
else:
|
else:
|
||||||
font_h = font_h3
|
font_h = font_h3
|
||||||
size_h = HEADER_SIZE_3
|
size_h = header_size_3
|
||||||
for wrapped in wrap_segments(segments, font_h, font_h, font_h, font_h, IMAGE_WIDTH):
|
for wrapped in wrap_segments(segments, font_h, font_h, font_h, font_h, IMAGE_WIDTH):
|
||||||
lines_out.append(('header', wrapped, font_h, size_h))
|
lines_out.append(('header', wrapped, font_h, size_h))
|
||||||
elif tag[0] == 'bullet':
|
elif tag[0] == 'bullet':
|
||||||
@@ -426,9 +438,9 @@ def render(md, dithering, printmode, uploaded_img_bytes=None, bannermode=False):
|
|||||||
wrapped_lines = list(wrap_segments(segments, font, font_bold, font_italic, font_bolditalic, IMAGE_WIDTH - bullet_w, start_x=0))
|
wrapped_lines = list(wrap_segments(segments, font, font_bold, font_italic, font_bolditalic, IMAGE_WIDTH - bullet_w, start_x=0))
|
||||||
for i, wrapped in enumerate(wrapped_lines):
|
for i, wrapped in enumerate(wrapped_lines):
|
||||||
if i == 0:
|
if i == 0:
|
||||||
lines_out.append(('bullet', wrapped, bullet_font, FONT_SIZE, True, bullet_w))
|
lines_out.append(('bullet', wrapped, bullet_font, font_size, True, bullet_w))
|
||||||
else:
|
else:
|
||||||
lines_out.append(('bullet', wrapped, bullet_font, FONT_SIZE, False, bullet_w))
|
lines_out.append(('bullet', wrapped, bullet_font, font_size, False, bullet_w))
|
||||||
elif tag[0] == 'ordered':
|
elif tag[0] == 'ordered':
|
||||||
idx, segments = tag[1], tag[2]
|
idx, segments = tag[1], tag[2]
|
||||||
num_str = f"{idx}. "
|
num_str = f"{idx}. "
|
||||||
@@ -437,13 +449,13 @@ def render(md, dithering, printmode, uploaded_img_bytes=None, bannermode=False):
|
|||||||
wrapped_lines = list(wrap_segments(segments, font, font_bold, font_italic, font_bolditalic, IMAGE_WIDTH - num_w, start_x=0))
|
wrapped_lines = list(wrap_segments(segments, font, font_bold, font_italic, font_bolditalic, IMAGE_WIDTH - num_w, start_x=0))
|
||||||
for i, wrapped in enumerate(wrapped_lines):
|
for i, wrapped in enumerate(wrapped_lines):
|
||||||
if i == 0:
|
if i == 0:
|
||||||
lines_out.append(('ordered', wrapped, number_font, FONT_SIZE, num_str, True, num_w))
|
lines_out.append(('ordered', wrapped, number_font, font_size, num_str, True, num_w))
|
||||||
else:
|
else:
|
||||||
lines_out.append(('ordered', wrapped, number_font, FONT_SIZE, num_str, False, num_w))
|
lines_out.append(('ordered', wrapped, number_font, font_size, num_str, False, num_w))
|
||||||
else: # normal text
|
else: # normal text
|
||||||
segments = tag[1]
|
segments = tag[1]
|
||||||
for wrapped in wrap_segments(segments, font, font_bold, font_italic, font_bolditalic, IMAGE_WIDTH):
|
for wrapped in wrap_segments(segments, font, font_bold, font_italic, font_bolditalic, IMAGE_WIDTH):
|
||||||
lines_out.append(('text', wrapped, font, FONT_SIZE))
|
lines_out.append(('text', wrapped, font, font_size))
|
||||||
|
|
||||||
# Compute total height, including images
|
# Compute total height, including images
|
||||||
height = 10 # Top margin
|
height = 10 # Top margin
|
||||||
@@ -453,7 +465,7 @@ def render(md, dithering, printmode, uploaded_img_bytes=None, bannermode=False):
|
|||||||
elif item[0] == 'hr':
|
elif item[0] == 'hr':
|
||||||
height += 10
|
height += 10
|
||||||
elif item[0] == 'blank':
|
elif item[0] == 'blank':
|
||||||
height += FONT_SIZE
|
height += font_size
|
||||||
elif item[0] == 'image':
|
elif item[0] == 'image':
|
||||||
img = item[1]
|
img = item[1]
|
||||||
height += img.height + 10 # add margin below image
|
height += img.height + 10 # add margin below image
|
||||||
@@ -463,7 +475,7 @@ def render(md, dithering, printmode, uploaded_img_bytes=None, bannermode=False):
|
|||||||
y = 0
|
y = 0
|
||||||
for item in lines_out:
|
for item in lines_out:
|
||||||
if item[0] == 'blank':
|
if item[0] == 'blank':
|
||||||
y += FONT_SIZE
|
y += font_size
|
||||||
elif item[0] == 'hr':
|
elif item[0] == 'hr':
|
||||||
draw.line((0, y + 5, IMAGE_WIDTH, y + 5), fill=0, width=2)
|
draw.line((0, y + 5, IMAGE_WIDTH, y + 5), fill=0, width=2)
|
||||||
y += 10
|
y += 10
|
||||||
@@ -572,11 +584,14 @@ def index():
|
|||||||
dithering = request.form.get("dithering", "floyd")
|
dithering = request.form.get("dithering", "floyd")
|
||||||
printmode = request.form.get("printmode", "1bpp")
|
printmode = request.form.get("printmode", "1bpp")
|
||||||
bannermode = bool(request.form.get("bannermode"))
|
bannermode = bool(request.form.get("bannermode"))
|
||||||
image = render(md, dithering, printmode, uploaded_img_bytes, bannermode=bannermode)
|
fontsize_key = request.form.get("fontsize", "normal")
|
||||||
|
font_size = FONT_SIZE_OPTIONS.get(fontsize_key, DEFAULT_FONT_SIZE)
|
||||||
|
image = render(md, dithering, printmode, uploaded_img_bytes, bannermode=bannermode, font_size=font_size)
|
||||||
session['dithering'] = dithering
|
session['dithering'] = dithering
|
||||||
session['printmode'] = printmode
|
session['printmode'] = printmode
|
||||||
session['rotation'] = rotation
|
session['rotation'] = rotation
|
||||||
session['bannermode'] = bannermode
|
session['bannermode'] = bannermode
|
||||||
|
session['fontsize'] = fontsize_key
|
||||||
buf = io.BytesIO()
|
buf = io.BytesIO()
|
||||||
image.save(buf, format="PNG")
|
image.save(buf, format="PNG")
|
||||||
buf.seek(0)
|
buf.seek(0)
|
||||||
@@ -617,6 +632,7 @@ def index():
|
|||||||
current_rotation=session.get('rotation', 0),
|
current_rotation=session.get('rotation', 0),
|
||||||
current_printmode=session.get('printmode', '1bpp'),
|
current_printmode=session.get('printmode', '1bpp'),
|
||||||
current_bannermode=session.get('bannermode', False),
|
current_bannermode=session.get('bannermode', False),
|
||||||
|
current_fontsize=session.get('fontsize', 'normal'),
|
||||||
t=t,
|
t=t,
|
||||||
lang=lang
|
lang=lang
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -33,7 +33,12 @@
|
|||||||
"image_url": "Image URL",
|
"image_url": "Image URL",
|
||||||
"leave_an_empty_line": "Leave an empty line",
|
"leave_an_empty_line": "Leave an empty line",
|
||||||
"uses_the_uploaded_image": "(uses the uploaded image)",
|
"uses_the_uploaded_image": "(uses the uploaded image)",
|
||||||
"no_dithering": "No dithering"
|
"no_dithering": "No dithering",
|
||||||
|
"font_size": "Font size:",
|
||||||
|
"font_small": "Small",
|
||||||
|
"font_normal": "Normal",
|
||||||
|
"font_large": "Large",
|
||||||
|
"font_xlarge": "Extra Large"
|
||||||
},
|
},
|
||||||
"es": {
|
"es": {
|
||||||
"catnote": "CatNote",
|
"catnote": "CatNote",
|
||||||
@@ -69,6 +74,11 @@
|
|||||||
"image_url": "URL de la imagen",
|
"image_url": "URL de la imagen",
|
||||||
"leave_an_empty_line": "Deje una línea vacía",
|
"leave_an_empty_line": "Deje una línea vacía",
|
||||||
"uses_the_uploaded_image": "(usa la imagen cargada)",
|
"uses_the_uploaded_image": "(usa la imagen cargada)",
|
||||||
"no_dithering": "Sin dithering"
|
"no_dithering": "Sin dithering",
|
||||||
|
"font_size": "Tamaño de fuente:",
|
||||||
|
"font_small": "Pequeño",
|
||||||
|
"font_normal": "Normal",
|
||||||
|
"font_large": "Grande",
|
||||||
|
"font_xlarge": "Extra grande"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -571,6 +571,15 @@
|
|||||||
<option value="270" {% if 270==current_rotation %}selected="selected" {% endif %}>270°</option>
|
<option value="270" {% if 270==current_rotation %}selected="selected" {% endif %}>270°</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="options-fontsize">
|
||||||
|
<label for="fontsize">{{ t['font_size'] }}</label>
|
||||||
|
<select name="fontsize">
|
||||||
|
<option value="small" {% if "small"==current_fontsize %}selected="selected" {% endif %}>{{ t['font_small'] }}</option>
|
||||||
|
<option value="normal" {% if "normal"==current_fontsize %}selected="selected" {% endif %}>{{ t['font_normal'] }}</option>
|
||||||
|
<option value="large" {% if "large"==current_fontsize %}selected="selected" {% endif %}>{{ t['font_large'] }}</option>
|
||||||
|
<option value="xlarge" {% if "xlarge"==current_fontsize %}selected="selected" {% endif %}>{{ t['font_xlarge'] }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<div class="options-printmode">
|
<div class="options-printmode">
|
||||||
<label for="printmode">{{ t['print_mode'] }}</label>
|
<label for="printmode">{{ t['print_mode'] }}</label>
|
||||||
<select name="printmode">
|
<select name="printmode">
|
||||||
|
|||||||
Reference in New Issue
Block a user