import math from PIL import Image, ImageDraw, ImageFont, ImageFilter W, H = 1420, 640 font_title = "/System/Library/Fonts/Supplemental/Songti.ttc" font_text = "/System/Library/Fonts/STHeiti Medium.ttc" def create_gradient(w, h, c1, c2, horizontal=True): base = Image.new('RGBA', (w, h), c1) top = Image.new('RGBA', (w, h), c2) mask = Image.new('L', (w, h)) for y in range(h): for x in range(w): ratio = x / w if horizontal else y / h mask.putpixel((x, y), int(255 * ratio)) base.paste(top, (0, 0), mask) return base def draw_pill(draw, xy, fill, outline=None, width=1): draw.rounded_rectangle(xy, radius=xy[3]-xy[1], fill=fill, outline=outline, width=width) # ==================== BANNER 1: WINE ==================== def build_wine_banner(): # Base background: dark luxury burgundy bg = create_gradient(W, H, (35, 12, 14, 255), (15, 6, 8, 255), horizontal=True) draw = ImageDraw.Draw(bg) # Ambient gold glow circle glow = Image.new('RGBA', (W, H), (0, 0, 0, 0)) g_draw = ImageDraw.Draw(glow) g_draw.ellipse([900, -100, 1600, 700], fill=(212, 160, 89, 40)) glow = glow.filter(ImageFilter.GaussianBlur(80)) bg = Image.alpha_composite(bg, glow) draw = ImageDraw.Draw(bg) # Border & frame accents draw.rounded_rectangle([16, 16, W-16, H-16], radius=24, outline=(212, 175, 110, 80), width=2) # Tag font_tag = ImageFont.truetype(font_text, 28) tag_text = "✦ 国酿琼浆 · 东方名酒专区 ✦" draw.rounded_rectangle([80, 80, 520, 130], radius=25, fill=(60, 20, 24, 200), outline=(212, 175, 110, 200), width=2) draw.text((105, 92), tag_text, font=font_tag, fill=(245, 215, 160)) # Title font_t = ImageFont.truetype(font_title, 68) draw.text((80, 165), "贵州飞天盛世 · 龙抬头", font=font_t, fill=(255, 235, 195)) # Subtitle font_s = ImageFont.truetype(font_text, 34) draw.text((80, 265), "古法大曲坤沙足年窖藏 | 传世名酿 · 宴饮礼遇", font=font_s, fill=(210, 185, 170)) font_s2 = ImageFont.truetype(font_text, 28) draw.text((80, 325), "陶坛封坛 · 酱香幽雅 · 回味悠长 · 祥瑞尊享", font=font_s2, fill=(160, 140, 135)) # CTA Button draw.rounded_rectangle([80, 420, 460, 500], radius=40, fill=(197, 160, 89, 255)) font_btn = ImageFont.truetype(font_text, 32) draw.text((120, 442), "官方尊享价 ¥1398 立即品鉴 →", font=font_btn, fill=(25, 10, 12)) # Trust chips font_chip = ImageFont.truetype(font_text, 24) draw.text((80, 540), "✔ 官方正品保真 ✔ 原厂陶坛直采 ✔ 顺丰保价尊享配", font=font_chip, fill=(180, 155, 130)) # Right products: wine_blue & wine_red img_red = Image.open('/tmp/henglian_assets/wine_red.jpg').convert('RGBA') img_blue = Image.open('/tmp/henglian_assets/wine_blue.jpg').convert('RGBA') # Resize & crop red_w, red_h = 460, int(460 * (img_red.height / img_red.width)) img_red_r = img_red.resize((red_w, red_h), Image.Resampling.LANCZOS) blue_w, blue_h = 420, int(420 * (img_blue.height / img_blue.width)) img_blue_r = img_blue.resize((blue_w, blue_h), Image.Resampling.LANCZOS) # Crop to neat card style on right card_right = Image.new('RGBA', (W, H), (0, 0, 0, 0)) # Make rounded masks for product cards def rounded_card(img, size, radius=20): c = img.resize(size, Image.Resampling.LANCZOS) mask = Image.new('L', size, 0) m_draw = ImageDraw.Draw(mask) m_draw.rounded_rectangle([0, 0, size[0], size[1]], radius=radius, fill=255) res = Image.new('RGBA', size, (0, 0, 0, 0)) res.paste(c, (0, 0), mask) return res p1 = rounded_card(img_red, (380, 460), radius=24) p2 = rounded_card(img_blue, (360, 420), radius=24) # Border for product cards def add_border(img, radius=24): border = Image.new('RGBA', img.size, (0, 0, 0, 0)) b_draw = ImageDraw.Draw(border) b_draw.rounded_rectangle([0, 0, img.size[0]-1, img.size[1]-1], radius=radius, outline=(212, 175, 110, 180), width=3) return Image.alpha_composite(img, border) p1 = add_border(p1) p2 = add_border(p2) # Shadow for p1, p2 shadow = Image.new('RGBA', (W, H), (0, 0, 0, 0)) s_draw = ImageDraw.Draw(shadow) s_draw.rounded_rectangle([650, 110, 650+360, 110+420], radius=24, fill=(0, 0, 0, 120)) s_draw.rounded_rectangle([970, 80, 970+380, 80+460], radius=24, fill=(0, 0, 0, 150)) shadow = shadow.filter(ImageFilter.GaussianBlur(30)) bg = Image.alpha_composite(bg, shadow) bg.paste(p2, (660, 110), p2) bg.paste(p1, (980, 80), p1) bg.convert('RGB').save('/tmp/henglian_assets/banner_wine.jpg', quality=95) print("banner_wine.jpg generated") # ==================== BANNER 2: SKINCARE ==================== def build_skincare_banner(): # Base background: luxury emerald / jade green bg = create_gradient(W, H, (14, 38, 32, 255), (6, 18, 15, 255), horizontal=True) draw = ImageDraw.Draw(bg) # Ambient mint/teal glow glow = Image.new('RGBA', (W, H), (0, 0, 0, 0)) g_draw = ImageDraw.Draw(glow) g_draw.ellipse([900, -100, 1600, 700], fill=(64, 180, 140, 45)) glow = glow.filter(ImageFilter.GaussianBlur(80)) bg = Image.alpha_composite(bg, glow) draw = ImageDraw.Draw(bg) # Frame draw.rounded_rectangle([16, 16, W-16, H-16], radius=24, outline=(100, 200, 165, 80), width=2) # Tag font_tag = ImageFont.truetype(font_text, 28) tag_text = "✦ 极光凝时 · 医研美护专区 ✦" draw.rounded_rectangle([80, 80, 520, 130], radius=25, fill=(20, 55, 45, 200), outline=(100, 200, 165, 200), width=2) draw.text((105, 92), tag_text, font=font_tag, fill=(180, 240, 220)) # Title font_t = ImageFont.truetype(font_title, 68) draw.text((80, 165), "润泽优选 · 轻盈赋活系列", font=font_t, fill=(235, 255, 248)) # Subtitle font_s = ImageFont.truetype(font_text, 34) draw.text((80, 265), "医研级西林瓶锁鲜 | 一秒赋活 · 紧致淡纹抗皱", font=font_s, fill=(185, 225, 215)) font_s2 = ImageFont.truetype(font_text, 28) draw.text((80, 325), "高纯活性精粹 · 密集修护赋能 · 水润焕亮无负担", font=font_s2, fill=(130, 180, 168)) # CTA Button draw.rounded_rectangle([80, 420, 460, 500], radius=40, fill=(50, 150, 120, 255)) font_btn = ImageFont.truetype(font_text, 32) draw.text((120, 442), "官方尊享价 ¥1398 焕活美肌 →", font=font_btn, fill=(255, 255, 255)) # Trust chips font_chip = ImageFont.truetype(font_text, 24) draw.text((80, 540), "✔ 医研级鲜活锁鲜 ✔ 多维抗皱淡纹 ✔ 院线赋能滋养", font=font_chip, fill=(160, 215, 200)) # Right products: skincare_runze & skincare_qingying img_runze = Image.open('/tmp/henglian_assets/skincare_runze.png').convert('RGBA') img_qing = Image.open('/tmp/henglian_assets/skincare_qingying.png').convert('RGBA') def rounded_card(img, size, radius=20): c = img.resize(size, Image.Resampling.LANCZOS) mask = Image.new('L', size, 0) m_draw = ImageDraw.Draw(mask) m_draw.rounded_rectangle([0, 0, size[0], size[1]], radius=radius, fill=255) res = Image.new('RGBA', size, (0, 0, 0, 0)) res.paste(c, (0, 0), mask) return res def add_border(img, radius=24): border = Image.new('RGBA', img.size, (0, 0, 0, 0)) b_draw = ImageDraw.Draw(border) b_draw.rounded_rectangle([0, 0, img.size[0]-1, img.size[1]-1], radius=radius, outline=(100, 200, 165, 180), width=3) return Image.alpha_composite(img, border) p1 = add_border(rounded_card(img_runze, (380, 440), radius=24)) p2 = add_border(rounded_card(img_qing, (360, 420), radius=24)) shadow = Image.new('RGBA', (W, H), (0, 0, 0, 0)) s_draw = ImageDraw.Draw(shadow) s_draw.rounded_rectangle([660, 110, 660+360, 110+420], radius=24, fill=(0, 0, 0, 100)) s_draw.rounded_rectangle([980, 90, 980+380, 90+440], radius=24, fill=(0, 0, 0, 120)) shadow = shadow.filter(ImageFilter.GaussianBlur(30)) bg = Image.alpha_composite(bg, shadow) bg.paste(p2, (660, 110), p2) bg.paste(p1, (980, 90), p1) bg.convert('RGB').save('/tmp/henglian_assets/banner_skincare.jpg', quality=95) print("banner_skincare.jpg generated") # ==================== BANNER 3: PARTNER ==================== def build_partner_banner(): # Base background: prestige navy & gold bg = create_gradient(W, H, (12, 24, 45, 255), (5, 10, 20, 255), horizontal=True) draw = ImageDraw.Draw(bg) # Warm gold aura glow = Image.new('RGBA', (W, H), (0, 0, 0, 0)) g_draw = ImageDraw.Draw(glow) g_draw.ellipse([800, -50, 1500, 650], fill=(212, 175, 110, 40)) glow = glow.filter(ImageFilter.GaussianBlur(80)) bg = Image.alpha_composite(bg, glow) draw = ImageDraw.Draw(bg) draw.rounded_rectangle([16, 16, W-16, H-16], radius=24, outline=(212, 175, 110, 80), width=2) # Tag font_tag = ImageFont.truetype(font_text, 28) tag_text = "✦ 恒链合伙人 · 共享新零售红利 ✦" draw.rounded_rectangle([80, 80, 560, 130], radius=25, fill=(25, 40, 70, 200), outline=(212, 175, 110, 200), width=2) draw.text((105, 92), tag_text, font=font_tag, fill=(245, 220, 165)) # Title font_t = ImageFont.truetype(font_title, 68) draw.text((80, 165), "聚势共赢 · 开启数字化财富新篇", font=font_t, fill=(255, 240, 205)) # Subtitle font_s = ImageFont.truetype(font_text, 34) draw.text((80, 265), "零门槛赋能体系 | 高额佣金 · 裂变倍增 · 团队管理", font=font_s, fill=(195, 210, 235)) font_s2 = ImageFont.truetype(font_text, 28) draw.text((80, 325), "全链路数字分销 · 私域专属顾问 · 收益实时明细透明", font=font_s2, fill=(140, 165, 195)) # CTA Button draw.rounded_rectangle([80, 420, 460, 500], radius=40, fill=(212, 175, 110, 255)) font_btn = ImageFont.truetype(font_text, 32) draw.text((120, 442), "立即进入团队中心 · 查阅权益 →", font=font_btn, fill=(15, 25, 45)) # Trust chips font_chip = ImageFont.truetype(font_text, 24) draw.text((80, 540), "✔ 专属推广海报 ✔ 团队收益实时结算 ✔ 尊崇合伙人礼遇", font=font_chip, fill=(185, 200, 225)) # Right graphic: Golden geometric emblem / shield emblem = Image.new('RGBA', (480, 480), (0, 0, 0, 0)) e_draw = ImageDraw.Draw(emblem) # Concentric rings & diamond e_draw.ellipse([40, 40, 440, 440], outline=(212, 175, 110, 160), width=4) e_draw.ellipse([80, 80, 400, 400], outline=(212, 175, 110, 100), width=2) e_draw.ellipse([120, 120, 360, 360], fill=(30, 50, 85, 180), outline=(212, 175, 110, 220), width=4) font_emb = ImageFont.truetype(font_title, 48) font_emb_sub = ImageFont.truetype(font_text, 26) e_draw.text((150, 180), "恒链合伙", font=font_emb, fill=(255, 235, 185)) e_draw.text((170, 250), "VIP PARTNER", font=font_emb_sub, fill=(212, 175, 110)) e_draw.text((160, 290), "共创 · 共享 · 共赢", font=font_emb_sub, fill=(180, 200, 230)) bg.paste(emblem, (850, 80), emblem) bg.convert('RGB').save('/tmp/henglian_assets/banner_partner.jpg', quality=95) print("banner_partner.jpg generated") if __name__ == '__main__': build_wine_banner() build_skincare_banner() build_partner_banner() def build_menu_icons(): font_menu = ImageFont.truetype(font_title, 42) font_sub = ImageFont.truetype(font_text, 22) menus = [ ("menu_wine.png", "白酒", "典藏", (85, 25, 25), (212, 175, 110)), ("menu_skincare.png", "美护", "赋活", (25, 65, 50), (130, 220, 185)), ("menu_partner.png", "合伙", "中心", (25, 45, 80), (230, 200, 130)), ("menu_gift.png", "尊享", "礼盒", (95, 45, 20), (245, 210, 150)), ("menu_coupon.png", "领券", "福利", (90, 30, 60), (250, 180, 200)), ] for filename, t1, t2, bg_c, fg_c in menus: size = (160, 160) img = Image.new('RGBA', size, (0, 0, 0, 0)) d = ImageDraw.Draw(img) # Soft background circle with border d.ellipse([6, 6, 154, 154], fill=(*bg_c, 240), outline=(*fg_c, 200), width=3) d.ellipse([14, 14, 146, 146], outline=(*fg_c, 80), width=1) # Text d.text((40, 42), t1, font=font_menu, fill=(*fg_c, 255)) d.text((58, 96), t2, font=font_sub, fill=(240, 240, 240, 220)) img.save('/tmp/henglian_assets/' + filename) print(filename, "generated") build_menu_icons() def build_partner_centers_menu_icons(): import os font_menu = ImageFont.truetype(font_title, 96) font_sub = ImageFont.truetype(font_text, 48) font_sub_3 = ImageFont.truetype(font_text, 42) # 5个清新渐变配置: (文件名, t1, t2, c_top, c_bottom, is_3) items = [ ('menu_city_center.png', '市级', '运营', (68, 165, 255), (28, 118, 240), False), ('menu_city_partner.png', '市级', '合伙', (255, 115, 96), (235, 60, 68), False), ('menu_province_center.png', '省级', '服务', (58, 202, 148), (22, 160, 108), False), ('menu_province_partner.png', '省级', '合伙', (172, 118, 238), (128, 72, 210), False), ('menu_region_branch.png', '大区', '分公司', (252, 180, 68), (225, 132, 30), True), ] out_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '../public/uploads/decorate')) os.makedirs(out_dir, exist_ok=True) for fn, t1, t2, c1, c2, is_3 in items: size = 320 base = Image.new('RGBA', (size, size), (0, 0, 0, 0)) # 渐变 grad = Image.new('RGBA', (size, size)) for y in range(size): r = y / float(size) cr = int(c1[0] * (1 - r) + c2[0] * r) cg = int(c1[1] * (1 - r) + c2[1] * r) cb = int(c1[2] * (1 - r) + c2[2] * r) for x in range(size): grad.putpixel((x, y), (cr, cg, cb, 255)) pad = 12 mask = Image.new('L', (size, size), 0) m_draw = ImageDraw.Draw(mask) m_draw.ellipse([pad, pad, size - pad, size - pad], fill=255) base.paste(grad, (0, 0), mask) d = ImageDraw.Draw(base) # 高级细双环与微高光 d.ellipse([pad, pad, size - pad, size - pad], outline=(255, 255, 255, 230), width=6) d.ellipse([pad + 16, pad + 16, size - pad - 16, size - pad - 16], outline=(255, 255, 255, 110), width=2) # 顶部轻微晨光弧线 d.arc([pad + 20, pad + 20, size - pad - 20, size - pad - 20], start=210, end=330, fill=(255, 255, 255, 150), width=4) # 标题 1 bbox1 = d.textbbox((0, 0), t1, font=font_menu) w1 = bbox1[2] - bbox1[0] d.text(((size - w1) / 2.0, 66), t1, font=font_menu, fill=(255, 255, 255, 255)) # 标题 2 cur_sub_font = font_sub_3 if is_3 else font_sub bbox2 = d.textbbox((0, 0), t2, font=cur_sub_font) w2 = bbox2[2] - bbox2[0] y2 = 192 if is_3 else 188 d.text(((size - w2) / 2.0, y2), t2, font=cur_sub_font, fill=(255, 255, 255, 245)) save_path = os.path.join(out_dir, fn) v2_path = os.path.join(out_dir, fn.replace('.png', '_v2.png')) base.save(save_path) base.save(v2_path) print("Fresh icon generated at", save_path, "and", v2_path) build_partner_centers_menu_icons() def build_trust_bar(): size = (1420, 110) img = Image.new('RGBA', size, (0, 0, 0, 0)) d = ImageDraw.Draw(img) # Rounded card background d.rounded_rectangle([4, 4, 1416, 106], radius=20, fill=(255, 255, 255, 255), outline=(230, 215, 190, 200), width=2) font_bar = ImageFont.truetype(font_text, 28) items = [ ("✦ 100% 官方正品", 120, (197, 160, 89)), ("✦ 产地源头直采", 480, (197, 160, 89)), ("✦ 顺丰冷链速达", 830, (197, 160, 89)), ("✦ 尊崇私享服务", 1160, (197, 160, 89)), ] for text, x, col in items: d.text((x, 38), text, font=font_bar, fill=(50, 40, 35)) img.save('/tmp/henglian_assets/trust_bar.png') print("trust_bar.png generated") build_trust_bar()