From a75fb526888f76ddb4156d6375d8daebd3ab997c3add25d800a0db28cfd7f93a Mon Sep 17 00:00:00 2001 From: Vladislav Date: Tue, 30 Jun 2026 19:13:50 -0400 Subject: [PATCH] =?UTF-8?q?Bot=20commit:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=20=D1=84=D0=B0=D0=B9=D0=BB=20images.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- images.py | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 images.py diff --git a/images.py b/images.py new file mode 100644 index 0000000..95f1404 --- /dev/null +++ b/images.py @@ -0,0 +1,66 @@ +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