67 lines
2.0 KiB
Python
67 lines
2.0 KiB
Python
from io import BytesIO
|
|
from PIL import Image, ImageDraw, ImageFilter
|
|
|
|
|
|
Image.MAX_IMAGE_PIXELS = 50_000_000
|
|
|
|
|
|
def insert_logo(
|
|
background,
|
|
logo,
|
|
scale_factor=0.095,
|
|
padding=8,
|
|
radius=15,
|
|
quality=95
|
|
):
|
|
background = background.copy().convert("RGBA")
|
|
|
|
# Логотип
|
|
logo = logo.copy().convert("RGBA")
|
|
|
|
# Масштабирование
|
|
logo_w, logo_h = logo.size
|
|
back_w, back_h = background.size
|
|
new_w = max(1, int(back_w * scale_factor))
|
|
ratio = logo_w / logo_h if logo_h > 0 else 1
|
|
new_h = max(1, int(new_w / ratio))
|
|
logo = logo.resize((new_w, new_h), Image.Resampling.LANCZOS)
|
|
|
|
# === Создаём полностью прозрачный фон ===
|
|
transparent = Image.new("RGBA", (new_w, new_h), (0, 0, 0, 0))
|
|
|
|
# Компонуем логотип на полностью прозрачный фон (убирает все артефакты)
|
|
logo = Image.alpha_composite(transparent, logo)
|
|
|
|
# === Маска закругления ===
|
|
mask = Image.new("L", (new_w, new_h), 0)
|
|
draw = ImageDraw.Draw(mask)
|
|
draw.rounded_rectangle([(0, 0), (new_w-1, new_h-1)], radius=radius, fill=255)
|
|
mask = mask.filter(ImageFilter.SMOOTH)
|
|
|
|
# Применяем маску через composite (самый чистый способ)
|
|
logo = Image.composite(logo, transparent, mask)
|
|
|
|
# Позиция (нижний левый угол)
|
|
pos_x = padding
|
|
pos_y = back_h - new_h - padding
|
|
if pos_y < 0:
|
|
pos_y = 0
|
|
|
|
# Вставка
|
|
background.paste(logo, (pos_x, pos_y), logo)
|
|
|
|
# Сохранение
|
|
out = BytesIO()
|
|
background.convert("RGB").save(out, format="JPEG", quality=quality, optimize=True)
|
|
out.seek(0)
|
|
return out
|
|
|
|
|
|
async def convert_bio_to_webp(bio: BytesIO, quality: int = 95) -> BytesIO:
|
|
bio.seek(0)
|
|
im = Image.open(bio).convert("RGB")
|
|
out = BytesIO()
|
|
im.save(out, format="WEBP", quality=quality, method=6)
|
|
out.seek(0)
|
|
return out
|