#!/usr/bin/env python3 """ Делает обои: размытый затемнённый фон + исходник в квадрате со скруглёнными углами. Установка зависимости: pip install pillow Использование: python make_wallpaper.py photo.jpg python make_wallpaper.py photo.jpg -o wall.jpg --size 600 python make_wallpaper.py photo.jpg -W 2560 -H 1440 --size 800 --offset 0.35 """ import argparse from PIL import Image, ImageFilter, ImageEnhance, ImageDraw def make_wallpaper(src_path, out_path, W=1920, H=1080, square=600, radius_ratio=0.178, offset=0.5, blur=40, dim=0.6, rim=True, shadow=True): src = Image.open(src_path).convert("RGB") sw, sh = src.size # --- фон: масштабируем с запасом, обрезаем по центру, размываем и затемняем scale = max(W / sw, H / sh) * 1.15 bg = src.resize((int(sw * scale), int(sh * scale)), Image.LANCZOS) left, top = (bg.width - W) // 2, (bg.height - H) // 2 bg = bg.crop((left, top, left + W, top + H)) bg = bg.filter(ImageFilter.GaussianBlur(blur)) bg = ImageEnhance.Brightness(bg).enhance(dim) # --- квадратный кроп из исходника side = min(sw, sh) if sh >= sw: # вертикальное фото — двигаем по вертикали y = int((sh - side) * offset) box = (0, y, side, y + side) else: # горизонтальное — по горизонтали x = int((sw - side) * offset) box = (x, 0, x + side, side) S = min(square, W, H) R = int(S * radius_ratio) fg = src.crop(box).resize((S, S), Image.LANCZOS) fg = fg.filter(ImageFilter.UnsharpMask(radius=2, percent=40, threshold=3)) # --- маска со скруглением (рисуем крупно и уменьшаем = гладкие края) SS = 4 mask = Image.new("L", (S * SS, S * SS), 0) ImageDraw.Draw(mask).rounded_rectangle( [0, 0, S * SS - 1, S * SS - 1], radius=R * SS, fill=255) mask = mask.resize((S, S), Image.LANCZOS) px, py = (W - S) // 2, (H - S) // 2 # --- мягкая тень if shadow: sh_layer = Image.new("L", (W, H), 0) sh_layer.paste(mask.point(lambda v: int(v * 0.55)), (px, py + max(4, S // 40))) sh_layer = sh_layer.filter(ImageFilter.GaussianBlur(max(8, S // 22))) bg = Image.composite(Image.new("RGB", (W, H), (0, 0, 8)), bg, sh_layer) bg.paste(fg, (px, py), mask) # --- тонкая светлая рамка if rim: layer = Image.new("RGBA", (W, H), (0, 0, 0, 0)) ImageDraw.Draw(layer).rounded_rectangle( [px, py, px + S - 1, py + S - 1], radius=R, outline=(255, 255, 255, 45), width=2) bg = Image.alpha_composite(bg.convert("RGBA"), layer).convert("RGB") bg.save(out_path, quality=95) return out_path def main(): p = argparse.ArgumentParser(description="Обои с размытым фоном и скруглённым квадратом") p.add_argument("input") p.add_argument("-o", "--output", default="wallpaper.jpg") p.add_argument("-W", "--width", type=int, default=1920) p.add_argument("-H", "--height", type=int, default=1080) p.add_argument("--size", type=int, default=600, help="сторона квадрата в пикселях") p.add_argument("--radius", type=float, default=0.178, help="радиус скругления как доля стороны (0.178 ≈ стиль iOS)") p.add_argument("--offset", type=float, default=0.5, help="сдвиг кропа 0..1 (0 — верх/лево, 1 — низ/право)") p.add_argument("--blur", type=int, default=40) p.add_argument("--dim", type=float, default=0.6, help="яркость фона, 1.0 = без затемнения") p.add_argument("--no-rim", action="store_true") p.add_argument("--no-shadow", action="store_true") a = p.parse_args() out = make_wallpaper(a.input, a.output, a.width, a.height, a.size, a.radius, a.offset, a.blur, a.dim, rim=not a.no_rim, shadow=not a.no_shadow) print("Сохранено:", out) if __name__ == "__main__": main()