feat: tweak mosaic cover layout to use black background and bound image area
Made-with: Cursor
This commit is contained in:
23
src/cover.py
23
src/cover.py
@@ -114,21 +114,28 @@ def generate_mosaic_cover(
|
|||||||
) -> str:
|
) -> str:
|
||||||
os.makedirs(output_dir, exist_ok=True)
|
os.makedirs(output_dir, exist_ok=True)
|
||||||
w, h = config.COVER_SIZE
|
w, h = config.COVER_SIZE
|
||||||
img = PILImage.new("RGBA", (w, h), color=(245, 245, 245, 255))
|
img = PILImage.new("RGBA", (w, h), color=(0, 0, 0, 255))
|
||||||
|
|
||||||
|
bottom_headlines_height = 0
|
||||||
|
if headlines:
|
||||||
|
bottom_headlines_height = 28 + min(len(headlines), 5) * 26
|
||||||
|
|
||||||
|
mosaic_h = h - 90 - bottom_headlines_height
|
||||||
|
mosaic_canvas = PILImage.new("RGBA", (w, mosaic_h), color=(0, 0, 0, 255))
|
||||||
|
|
||||||
if len(image_paths) == 1:
|
if len(image_paths) == 1:
|
||||||
# Single image case
|
# Single image case
|
||||||
try:
|
try:
|
||||||
with PILImage.open(image_paths[0]) as source_img:
|
with PILImage.open(image_paths[0]) as source_img:
|
||||||
source_img = source_img.convert("RGBA")
|
source_img = source_img.convert("RGBA")
|
||||||
# Resize to fit within 480x800 preserving aspect ratio
|
# Resize to fit within 480x(mosaic_h) preserving aspect ratio
|
||||||
ratio = min(w / source_img.width, h / source_img.height)
|
ratio = min(w / source_img.width, mosaic_h / source_img.height)
|
||||||
new_size = (int(source_img.width * ratio), int(source_img.height * ratio))
|
new_size = (int(source_img.width * ratio), int(source_img.height * ratio))
|
||||||
resized = source_img.resize(new_size, PILImage.Resampling.LANCZOS)
|
resized = source_img.resize(new_size, PILImage.Resampling.LANCZOS)
|
||||||
# Center it
|
# Center it
|
||||||
x = (w - new_size[0]) // 2
|
x = (w - new_size[0]) // 2
|
||||||
y = (h - new_size[1]) // 2
|
y = (mosaic_h - new_size[1]) // 2
|
||||||
img.paste(resized, (x, y), resized)
|
mosaic_canvas.paste(resized, (x, y), resized)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("Failed to process single image for cover: %s", e)
|
logger.error("Failed to process single image for cover: %s", e)
|
||||||
elif len(image_paths) > 1:
|
elif len(image_paths) > 1:
|
||||||
@@ -137,7 +144,7 @@ def generate_mosaic_cover(
|
|||||||
col_heights = [4, 4]
|
col_heights = [4, 4]
|
||||||
|
|
||||||
for path in image_paths:
|
for path in image_paths:
|
||||||
if col_heights[0] > h and col_heights[1] > h:
|
if col_heights[0] > mosaic_h and col_heights[1] > mosaic_h:
|
||||||
break # Both columns full
|
break # Both columns full
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -150,11 +157,13 @@ def generate_mosaic_cover(
|
|||||||
x = 4 + col_idx * (col_width + 4)
|
x = 4 + col_idx * (col_width + 4)
|
||||||
y = col_heights[col_idx]
|
y = col_heights[col_idx]
|
||||||
|
|
||||||
img.paste(resized, (x, y), resized)
|
mosaic_canvas.paste(resized, (x, y), resized)
|
||||||
col_heights[col_idx] += new_h + 4
|
col_heights[col_idx] += new_h + 4
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("Failed to process image %s for mosaic: %s", path, e)
|
logger.error("Failed to process image %s for mosaic: %s", path, e)
|
||||||
|
|
||||||
|
img.paste(mosaic_canvas, (0, 90))
|
||||||
|
|
||||||
draw = ImageDraw.Draw(img)
|
draw = ImageDraw.Draw(img)
|
||||||
_draw_text_overlays(draw, w, h, week_start, week_end, headlines)
|
_draw_text_overlays(draw, w, h, week_start, week_end, headlines)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user