Files
mosen e9939ef9dc Initial release with production deploy config.
Add GitAtlas deploy assets, DATA_FILE support for isolated server data, and port documentation for sourcing.simosen.cn.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-15 00:52:31 +08:00

169 lines
6.3 KiB
Python

from pathlib import Path
from PIL import Image, ImageDraw, ImageFont
ROOT = Path(__file__).resolve().parents[1]
PUBLIC = ROOT / "public"
ASSETS = PUBLIC / "assets"
EXT_ICONS = ROOT / "extension" / "icons"
JADE_DARK = "#073C31"
JADE = "#0D6A54"
TURQUOISE = "#249B90"
PAPER = "#FFFDF5"
PAPER_GREEN = "#E8F6EF"
BRASS = "#A56F18"
BRASS_LIGHT = "#FFE6A1"
CINNABAR = "#C9544A"
MUTED = "#65766A"
SERIF = "/System/Library/Fonts/Supplemental/Songti.ttc"
SANS = "/Users/wangyuqiang/Library/Fonts/SourceHanSansCN-Regular.otf"
SANS_HEAVY = "/Users/wangyuqiang/Library/Fonts/SourceHanSansCN-Heavy.otf"
def font(path, size):
return ImageFont.truetype(path, size)
def rounded(draw, xy, radius, fill, outline=None, width=1):
draw.rounded_rectangle(xy, radius=radius, fill=fill, outline=outline, width=width)
def draw_mark(size=512):
scale = size / 256
image = Image.new("RGBA", (size, size), (0, 0, 0, 0))
draw = ImageDraw.Draw(image)
rounded(draw, (0, 0, size - 1, size - 1), int(56 * scale), PAPER)
rounded(draw, (int(12 * scale), int(12 * scale), int(244 * scale), int(244 * scale)), int(48 * scale), JADE)
rounded(
draw,
(int(25 * scale), int(25 * scale), int(231 * scale), int(231 * scale)),
int(38 * scale),
None,
"#2E8F7D",
max(1, int(2 * scale)),
)
stroke = max(8, int(13 * scale))
corner = "#FFF8E8"
segments = [
((57, 98), (57, 70), (70, 57), (98, 57)),
((158, 57), (186, 57), (199, 70), (199, 98)),
((199, 158), (199, 186), (186, 199), (158, 199)),
((98, 199), (70, 199), (57, 186), (57, 158)),
]
for points in segments:
scaled = [(int(x * scale), int(y * scale)) for x, y in points]
draw.line(scaled, fill=corner, width=stroke, joint="curve")
diamond = [(128, 72), (184, 128), (128, 184), (72, 128)]
draw.polygon([(int(x * scale), int(y * scale)) for x, y in diamond], fill=BRASS_LIGHT)
inner = [(128, 91), (165, 128), (128, 165), (91, 128)]
draw.polygon([(int(x * scale), int(y * scale)) for x, y in inner], fill="#FFF8E8")
draw.ellipse(
(int(111 * scale), int(111 * scale), int(145 * scale), int(145 * scale)),
fill=JADE,
)
draw.ellipse(
(int(162 * scale), int(70 * scale), int(186 * scale), int(94 * scale)),
fill=CINNABAR,
outline="#FFF8E8",
width=max(3, int(5 * scale)),
)
return image
def center_text(draw, xy, text, font_obj, fill):
x1, y1, x2, y2 = xy
box = draw.textbbox((0, 0), text, font=font_obj)
width = box[2] - box[0]
height = box[3] - box[1]
draw.text((x1 + (x2 - x1 - width) / 2, y1 + (y2 - y1 - height) / 2 - box[1]), text, font=font_obj, fill=fill)
def draw_share_card():
image = Image.new("RGB", (1200, 630), "#F8FFF9")
draw = ImageDraw.Draw(image)
for y in range(630):
ratio = y / 629
r = int(248 * (1 - ratio) + 255 * ratio)
g = int(255 * (1 - ratio) + 245 * ratio)
b = int(249 * (1 - ratio) + 222 * ratio)
draw.line((0, y, 1200, y), fill=(r, g, b))
for x in range(0, 1200, 32):
draw.line((x, 0, x, 630), fill="#D8E8DE", width=1)
for y in range(0, 630, 32):
draw.line((0, y, 1200, y), fill="#D8E8DE", width=1)
draw.ellipse((860, -228, 1380, 292), fill="#F3DE9E")
draw.ellipse((-210, 360, 290, 860), fill="#DDF2EF")
mark = draw_mark(208)
image.paste(mark, (66, 62), mark)
title_font = font(SERIF, 64)
subtitle_font = font(SANS_HEAVY, 30)
body_font = font(SANS, 22)
small_font = font(SANS_HEAVY, 17)
label_font = font(SANS, 15)
draw.text((66, 306), "选品采购台", font=title_font, fill=JADE_DARK)
draw.text((69, 394), "从商品机会,到放心采购", font=subtitle_font, fill="#315F55")
draw.text((69, 452), "采集竞品 · 匹配货源 · 利润测算 · 拿样决策", font=body_font, fill=MUTED)
rounded(draw, (660, 88, 1124, 540), 28, PAPER, "#B9D5C7", 2)
draw.text((694, 132), "PRODUCT OPPORTUNITY FLOW", font=small_font, fill=MUTED)
cards = [
((694, 174, 1092, 252), "#E2F3EE", "#B9D5C7", JADE, "发现高潜商品", "淘宝 / 小红书 / 更多平台线索"),
((694, 290, 1092, 368), "#FFF3CB", "#D9BD79", BRASS, "匹配优质货源", "1688 厂家 / 价格 / 保障"),
((694, 406, 1092, 502), JADE, JADE, PAPER, "形成采购决策", "筛选 / 利润 / 风险 / 拿样"),
]
for index, (box, fill, outline, accent, title, subtitle) in enumerate(cards):
rounded(draw, box, 14, fill, outline, 1)
x1, y1, x2, y2 = box
if index == 0:
draw.ellipse((x1 + 20, y1 + 19, x1 + 60, y1 + 59), fill=JADE)
center_text(draw, (x1 + 20, y1 + 19, x1 + 60, y1 + 59), "+", font(SANS, 29), PAPER)
text_fill = JADE_DARK
sub_fill = MUTED
elif index == 1:
draw.rectangle((x1 + 22, y1 + 25, x1 + 61, y1 + 55), fill=BRASS)
text_fill = "#5F4211"
sub_fill = "#7A6645"
else:
draw.ellipse((x1 + 18, y1 + 26, x1 + 62, y1 + 70), fill=PAPER)
draw.line((x1 + 30, y1 + 50, x1 + 38, y1 + 58, x1 + 53, y1 + 39), fill=JADE, width=5)
text_fill = PAPER
sub_fill = "#DDF2EF"
draw.ellipse((x2 - 39, y1 + 18, x2 - 23, y1 + 34), fill=CINNABAR)
draw.text((x1 + 76, y1 + 21), title, font=font(SANS_HEAVY, 21), fill=text_fill)
draw.text((x1 + 76, y1 + 49), subtitle, font=label_font, fill=sub_fill)
if index < 2:
cx = 892
draw.line((cx, y2 + 8, cx, y2 + 32), fill=BRASS, width=4)
draw.line((cx - 8, y2 + 24, cx, y2 + 32, cx + 8, y2 + 24), fill=BRASS, width=4)
return image
def main():
ASSETS.mkdir(parents=True, exist_ok=True)
EXT_ICONS.mkdir(parents=True, exist_ok=True)
mark = draw_mark(512)
mark.resize((256, 256), Image.Resampling.LANCZOS).save(ASSETS / "brand-mark.png")
draw_share_card().save(ASSETS / "share-card.png")
icon_sizes = [16, 32, 48, 64, 128, 256]
icons = [mark.resize((size, size), Image.Resampling.LANCZOS) for size in icon_sizes]
icons[-1].save(PUBLIC / "favicon.ico", sizes=[(size, size) for size in icon_sizes])
for size in [16, 32, 48, 128]:
mark.resize((size, size), Image.Resampling.LANCZOS).save(EXT_ICONS / f"icon{size}.png")
if __name__ == "__main__":
main()