FIRST
This commit is contained in:
76
linkedin_carousel_app/utils.py
Normal file
76
linkedin_carousel_app/utils.py
Normal file
@@ -0,0 +1,76 @@
|
||||
import os
|
||||
import requests
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
import textwrap
|
||||
|
||||
FONT_DIR = "assets/fonts"
|
||||
FONT_PATH = os.path.join(FONT_DIR, "Roboto-Bold.ttf")
|
||||
BODY_FONT_PATH = os.path.join(FONT_DIR, "Roboto-Regular.ttf")
|
||||
|
||||
def download_fonts():
|
||||
"""Downloads Roboto font if not present."""
|
||||
if not os.path.exists(FONT_DIR):
|
||||
os.makedirs(FONT_DIR)
|
||||
|
||||
fonts = {
|
||||
"Roboto-Bold.ttf": "https://github.com/google/fonts/raw/main/apache/roboto/Roboto-Bold.ttf",
|
||||
"Roboto-Regular.ttf": "https://github.com/google/fonts/raw/main/apache/roboto/Roboto-Regular.ttf"
|
||||
}
|
||||
|
||||
for name, url in fonts.items():
|
||||
path = os.path.join(FONT_DIR, name)
|
||||
if not os.path.exists(path):
|
||||
try:
|
||||
print(f"Downloading {name}...")
|
||||
response = requests.get(url)
|
||||
if response.status_code == 200:
|
||||
with open(path, "wb") as f:
|
||||
f.write(response.content)
|
||||
except Exception as e:
|
||||
print(f"Failed to download font {name}: {e}")
|
||||
|
||||
def format_slide(slide_image: Image.Image, slide_number: int, total_slides: int, style_config: dict) -> Image.Image:
|
||||
"""
|
||||
Formats the AI-generated slide (with text) by adding a subtle footer for navigation.
|
||||
"""
|
||||
# Ensure fonts are available (for footer)
|
||||
if not os.path.exists(FONT_PATH):
|
||||
download_fonts()
|
||||
|
||||
target_size = (1080, 1350)
|
||||
img = slide_image.resize(target_size, Image.Resampling.LANCZOS)
|
||||
|
||||
# We remove the heavy overlay because the AI image already has text and design integrated.
|
||||
# A very subtle gradient at the bottom might be nice for the footer, but let's keep it minimal.
|
||||
|
||||
draw = ImageDraw.Draw(img)
|
||||
|
||||
# Load Fonts (only for footer)
|
||||
try:
|
||||
footer_font = ImageFont.truetype(BODY_FONT_PATH, 30)
|
||||
except:
|
||||
footer_font = ImageFont.load_default()
|
||||
|
||||
text_color = style_config["text_color"]
|
||||
margin = 80
|
||||
|
||||
# Footer (Slide Number)
|
||||
footer_text = f"{slide_number} / {total_slides}"
|
||||
bbox = draw.textbbox((0, 0), footer_text, font=footer_font)
|
||||
|
||||
# Draw a small background for readability if needed, or just text
|
||||
# Let's draw text with a slight shadow or outline for readability on varied backgrounds
|
||||
x = target_size[0] - bbox[2] - margin
|
||||
y = target_size[1] - 80
|
||||
|
||||
# Simple shadow
|
||||
shadow_color = (0, 0, 0) if sum(text_color) > 300 else (255, 255, 255)
|
||||
draw.text((x+2, y+2), footer_text, font=footer_font, fill=shadow_color)
|
||||
draw.text((x, y), footer_text, font=footer_font, fill=text_color)
|
||||
|
||||
# Branding (Optional) - REMOVED
|
||||
# branding = "Generated by Gemini"
|
||||
# draw.text((margin+2, y+2), branding, font=footer_font, fill=shadow_color)
|
||||
# draw.text((margin, y), branding, font=footer_font, fill=text_color)
|
||||
|
||||
return img
|
||||
Reference in New Issue
Block a user