import os from PIL import Image, ImageDraw, ImageFont import docx from docx import Document from docx.shared import Inches, Pt, RGBColor from docx.enum.text import WD_ALIGN_PARAGRAPH from docx.enum.table import WD_TABLE_ALIGNMENT, WD_ALIGN_VERTICAL from docx.oxml import OxmlElement, parse_xml from docx.oxml.ns import nsdecls, qn os.makedirs("assets", exist_ok=True) # Website color palette extracted from user's screenshot: # Deep dark navy background: #0D1326 # Card/table secondary dark navy: #151F38 # Table alt row navy: #111A30 # Border navy: #263354 # Accent bright lime green: #5CE116 # Primary royal blue button color: #1D52F3 # Pure white text: #FFFFFF # Muted cool grey-blue text: #94A3B8 BG_HEX = "0D1326" CARD_HEX = "151F38" ALT_ROW_HEX = "111A30" BORDER_HEX = "263354" GREEN_HEX = "5CE116" BLUE_HEX = "1D52F3" WHITE_HEX = "FFFFFF" MUTED_HEX = "94A3B8" def get_font(size, bold=False): font_paths = [ "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf" if bold else "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", "/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf" if bold else "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf", ] for p in font_paths: if os.path.exists(p): return ImageFont.truetype(p, size) return ImageFont.load_default() # 1. Create Top Website-Style Pill Badges Banner def create_pills_banner(filename): w, h = 1200, 130 img = Image.new("RGB", (w, h), (13, 19, 38)) draw = ImageDraw.Draw(img) font = get_font(22, bold=False) pills_row1 = ["ВКонтакте", "Яндекс Директ", "Senler / Боты", "Авито", "Яндекс Карты"] x = 10 y = 15 for text in pills_row1: bbox = draw.textbbox((0, 0), text, font=font) tw = bbox[2] - bbox[0] pw = tw + 58 ph = 46 draw.rounded_rectangle([x, y, x + pw, y + ph], radius=23, fill=(21, 31, 56), outline=(45, 59, 92), width=2) # Green dot draw.ellipse([x + 18, y + 17, x + 30, y + 29], fill=(92, 225, 22)) draw.text((x + 38, y + 10), text, font=font, fill=(255, 255, 255)) x += pw + 16 pills_row2 = ["Практический гайд 2026", "Исследования Ehrenberg-Bass", "Для всех ниш"] x = 10 y = 72 for text in pills_row2: bbox = draw.textbbox((0, 0), text, font=font) tw = bbox[2] - bbox[0] pw = tw + 58 ph = 46 draw.rounded_rectangle([x, y, x + pw, y + ph], radius=23, fill=(21, 31, 56), outline=(45, 59, 92), width=2) draw.ellipse([x + 18, y + 17, x + 30, y + 29], fill=(92, 225, 22)) draw.text((x + 38, y + 10), text, font=font, fill=(203, 213, 225)) x += pw + 16 img.save(filename) # 2. Create VK Ads Banner Icon def create_vk_banner(filename): w, h = 1200, 130 img = Image.new("RGB", (w, h), (13, 19, 38)) draw = ImageDraw.Draw(img) # Outer card draw.rounded_rectangle([4, 4, w - 4, h - 4], radius=22, fill=(21, 31, 56), outline=(29, 82, 243), width=3) # VK icon square draw.rounded_rectangle([24, 23, 108, 107], radius=20, fill=(0, 119, 255)) font_icon = get_font(38, bold=True) draw.text((38, 42), "VK", font=font_icon, fill=(255, 255, 255)) # Green indicator dot on icon draw.ellipse([92, 17, 114, 39], fill=(92, 225, 22), outline=(21, 31, 56), width=3) font_title = get_font(30, bold=True) font_sub = get_font(21, bold=False) draw.text((134, 26), "VK РЕКЛАМА (ТАРГЕТ)", font=font_title, fill=(255, 255, 255)) draw.text((134, 68), "Заход на 95% холодной аудитории: создаём повод и вытаскиваем из спячки", font=font_sub, fill=(92, 225, 22)) img.save(filename) # 3. Create Yandex Direct Banner Icon def create_yd_banner(filename): w, h = 1200, 130 img = Image.new("RGB", (w, h), (13, 19, 38)) draw = ImageDraw.Draw(img) # Outer card draw.rounded_rectangle([4, 4, w - 4, h - 4], radius=22, fill=(21, 31, 56), outline=(92, 225, 22), width=3) # Yandex icon square (Red/Yellow brand nod) draw.rounded_rectangle([24, 23, 108, 107], radius=20, fill=(252, 63, 29)) font_icon = get_font(44, bold=True) draw.text((48, 38), "Я", font=font_icon, fill=(255, 255, 255)) draw.ellipse([92, 17, 114, 39], fill=(92, 225, 22), outline=(21, 31, 56), width=3) font_title = get_font(30, bold=True) font_sub = get_font(21, bold=False) draw.text((134, 26), "ЯНДЕКС ДИРЕКТ (ПОИСК + РСЯ)", font=font_title, fill=(255, 255, 255)) draw.text((134, 68), "Заход на 5% горячего спроса и дожим: даём расчёт, конкретику и забираем заявку", font=font_sub, fill=(92, 225, 22)) img.save(filename) # 4. Create 95/5 Rule Minimalist Diagram def create_95_5_diagram(filename): w, h = 1200, 220 img = Image.new("RGB", (w, h), (13, 19, 38)) draw = ImageDraw.Draw(img) draw.rounded_rectangle([4, 4, w - 4, h - 4], radius=22, fill=(21, 31, 56), outline=(38, 51, 84), width=2) font_h = get_font(24, bold=True) font_b = get_font(20, bold=False) font_big = get_font(34, bold=True) draw.text((32, 22), "ПРАВИЛО 95/5 В РЕКЛАМЕ (EHRENBERG-BASS INSTITUTE)", font=font_h, fill=(255, 255, 255)) # Bar chart: 95% vs 5% bar_x, bar_y, bar_w, bar_h = 32, 70, 1136, 64 w_95 = int(bar_w * 0.88) # visual proportion so 5% is clearly readable # 95% segment (Royal blue) draw.rounded_rectangle([bar_x, bar_y, bar_x + w_95, bar_y + bar_h], radius=14, fill=(29, 82, 243)) # 5% segment (Bright Lime Green) draw.rounded_rectangle([bar_x + w_95 + 8, bar_y, bar_x + bar_w, bar_y + bar_h], radius=14, fill=(92, 225, 22)) draw.text((bar_x + 24, bar_y + 13), "95% АУДИТОРИИ — «МНЕ ПОКА НЕ НАДО» (НУЖЕН ПОВОД)", font=font_h, fill=(255, 255, 255)) draw.text((bar_x + w_95 + 22, bar_y + 13), "5% ИЩУТ", font=font_h, fill=(13, 19, 38)) draw.text((32, 152), "• 95% людей не ищут ваш продукт сегодня — скидки они пролистывают. Их цепляет только триггерная ситуация.", font=font_b, fill=(203, 213, 225)) draw.text((32, 182), "• За 5% готовых купить дерутся все конкуренты. Здесь решает не «скидка 30%», а расчёт и простая посадка.", font=font_b, fill=(92, 225, 22)) img.save(filename) create_pills_banner("assets/pills_banner.png") create_vk_banner("assets/vk_banner.png") create_yd_banner("assets/yd_banner.png") create_95_5_diagram("assets/rule_95_5.png") print("Images generated successfully.")
Made on
Tilda