icons.gen.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. # -*- coding: utf-8 -*-
  2. """泓衍票据 · 应用图标方案生成器 —— 1024×1024 标准 SVG
  3. 每个方案输出:iOS 整图 / Android 自适应前景 / Android 自适应背景 / Android 单色
  4. """
  5. import pathlib
  6. OUT = pathlib.Path("/Users/guoguo/Desktop/HeHuiDeepBlue/设计/深空蓝/图标/svg")
  7. OUT.mkdir(parents=True, exist_ok=True)
  8. THEMES = {
  9. "deep": dict( # 深空蓝(主方案)
  10. bg=[("0","#3170FF"),(".48","#1B4FD8"),("1","#0A2A82")],
  11. glow="#A8C6FF", glowop=".42",
  12. ink=[("0","#FFFFFF"),("1","#D9E7FF")],
  13. sub="#8FB2FF",
  14. gold=[("0","#F8C263"),("1","#E08A17")],
  15. ),
  16. "frost": dict( # 霜白(浅色方案)
  17. bg=[("0","#FFFFFF"),(".52","#EDF3FF"),("1","#D6E3F9")],
  18. glow="#FFFFFF", glowop=".85",
  19. ink=[("0","#2A62EA"),("1","#0E3AAE")],
  20. sub="#FFFFFF",
  21. gold=[("0","#DCA02C"),("1","#A8680A")],
  22. ),
  23. "mono": dict( # Android 13+ 单色主题图标
  24. bg=[("0","#00000000"),("1","#00000000")],
  25. glow="#000000", glowop="0",
  26. ink=[("0","#FFFFFF"),("1","#FFFFFF")],
  27. sub="#000000",
  28. gold=[("0","#FFFFFF"),("1","#FFFFFF")],
  29. mono=True,
  30. ),
  31. }
  32. SAFE = 0.72 # Android 自适应安全区缩放
  33. def stops(l): return "".join(f'<stop offset="{o}" stop-color="{c}"/>' for o,c in l)
  34. # ── 图形本体:返回 (满版元素, 主体标记) ──────────────────────
  35. def mark_A(p): # A 三叠水 · 泓纹(水波三叠,末叠鎏金)
  36. def wave(x0, L, y, a=32):
  37. return (f"M {x0} {y} C {x0+L*0.16:.0f} {y-a} {x0+L*0.34:.0f} {y-a} {x0+L*0.5:.0f} {y} "
  38. f"S {x0+L*0.84:.0f} {y+a} {x0+L} {y}")
  39. return "", f'''
  40. <g fill="none" stroke-width="116" stroke-linecap="round">
  41. <path d="{wave(302,420,348)}" stroke="url(#inkg)"/>
  42. <path d="{wave(262,500,512)}" stroke="url(#inkg)"/>
  43. <path d="{wave(238,548,676)}" stroke="url(#goldg)"/>
  44. </g>'''
  45. def mark_B(p): # B 券印 · 票据 + 骑缝章
  46. return "", f'''
  47. <mask id="mB">
  48. <rect x="0" y="0" width="1024" height="1024" fill="#fff"/>
  49. <circle cx="734" cy="244" r="120" fill="#000"/>
  50. </mask>
  51. <g transform="translate(512,512) rotate(-7)">
  52. <g mask="url(#mB)" transform="rotate(7) translate(-512,-512)">
  53. <g transform="translate(512,512) rotate(-7)">
  54. <rect x="-243" y="-296" width="486" height="592" rx="70" fill="url(#inkg)"/>
  55. <rect x="-152" y="-150" width="238" height="50" rx="25" fill="{p['sub']}"/>
  56. <rect x="-152" y="-52" width="304" height="50" rx="25" fill="{p['sub']}"/>
  57. <rect x="-152" y="74" width="220" height="62" rx="31" fill="url(#goldg)"/>
  58. </g>
  59. </g>
  60. </g>
  61. <circle cx="734" cy="244" r="88" fill="url(#goldg)"/>'''
  62. def mark_C(p): # C 泓池 · 深水环 + 金色水面
  63. return "", f'''
  64. <clipPath id="cC"><circle cx="512" cy="512" r="{232 if p.get("mono") else 256}"/></clipPath>
  65. <circle cx="512" cy="512" r="300" fill="none" stroke="url(#inkg)" stroke-width="88"/>
  66. <g clip-path="url(#cC)">
  67. <path d="M 224 548 C 300 486 368 604 470 552 C 562 505 636 588 812 516 L 812 812 L 224 812 Z" fill="url(#goldg)"/>
  68. </g>'''
  69. def mark_D(p): # D 泓衡 · H 字标(斜梁)
  70. return "", f'''
  71. <g transform="translate(512,512) scale(.96)">
  72. <rect x="-250" y="-310" width="134" height="620" rx="42" fill="url(#inkg)"/>
  73. <rect x="116" y="-310" width="134" height="620" rx="42" fill="url(#inkg)"/>
  74. <path d="M -186 -12 L 186 -132 L 186 8 L -186 128 Z" fill="url(#goldg)"/>
  75. </g>'''
  76. def mark_E(p): # E 玺信 · 印章 + 泓
  77. return "", f'''
  78. <g transform="translate(512,512) rotate(-4)">
  79. <rect x="-302" y="-302" width="604" height="604" rx="116" fill="none" stroke="url(#goldg)" stroke-width="54"/>
  80. <text x="0" y="8" text-anchor="middle" dominant-baseline="central"
  81. font-family="PingFang SC, Heiti SC, STHeiti, sans-serif" font-weight="600" font-size="386"
  82. fill="url(#inkg)">泓</text>
  83. </g>'''
  84. def mark_F(p): # F 票角 · 整枚图标即一张票据,右下折角
  85. bleed = '<path d="M 1024 590 L 1024 1024 L 590 1024 Z" fill="url(#goldg)"/>'
  86. return bleed, f'''
  87. <g>
  88. <rect x="286" y="316" width="286" height="66" rx="33" fill="url(#inkg)"/>
  89. <rect x="286" y="440" width="400" height="66" rx="33" fill="url(#inkg)"/>
  90. <rect x="286" y="562" width="238" height="78" rx="39" fill="url(#goldg)"/>
  91. </g>'''
  92. MARKS = {"a":mark_A,"b":mark_B,"c":mark_C,"d":mark_D,"e":mark_E,"f":mark_F}
  93. NAMES = {"a":"sanshui","b":"quanyin","c":"hongchi","d":"hengbiao","e":"xixin","f":"piaojiao"}
  94. def build(key, theme, layer):
  95. """layer: full | fg | bg | mono"""
  96. p = THEMES["mono" if layer=="mono" else theme]
  97. bleed, mark = MARKS[key](p)
  98. d = f'''<linearGradient id="bgg" x1="0" y1="0" x2=".85" y2="1">{stops(p["bg"])}</linearGradient>
  99. <radialGradient id="glow" cx=".30" cy=".14" r=".82"><stop offset="0" stop-color="{p['glow']}" stop-opacity="{p['glowop']}"/><stop offset="1" stop-color="{p['glow']}" stop-opacity="0"/></radialGradient>
  100. <linearGradient id="inkg" x1=".2" y1="0" x2=".8" y2="1">{stops(p["ink"])}</linearGradient>
  101. <linearGradient id="goldg" x1=".1" y1="0" x2=".9" y2="1">{stops(p["gold"])}</linearGradient>'''
  102. plate = '<rect width="1024" height="1024" fill="url(#bgg)"/><rect width="1024" height="1024" fill="url(#glow)"/>'
  103. if layer == "full":
  104. inner = plate + bleed + mark
  105. elif layer == "bg":
  106. inner = plate + bleed
  107. elif layer == "fg":
  108. inner = f'<g transform="translate(512,512) scale({SAFE}) translate(-512,-512)">{mark}</g>'
  109. else: # mono:ink/gold→白、sub→黑,整组作为 mask 打到黑色实底上
  110. inner = (f'<mask id="mono"><rect width="1024" height="1024" fill="#000"/>'
  111. f'<g transform="translate(512,512) scale({SAFE}) translate(-512,-512)">{mark}</g></mask>'
  112. f'<rect width="1024" height="1024" fill="#000" mask="url(#mono)"/>')
  113. return (f'<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 1024 1024">'
  114. f'<defs>{d}</defs>{inner}</svg>')
  115. n = 0
  116. for k in MARKS:
  117. for t in ("deep","frost"):
  118. for layer, tag in (("full",""),("fg","-android-fg"),("bg","-android-bg")):
  119. (OUT/f"icon-{k}-{NAMES[k]}-{t}{tag}.svg").write_text(build(k,t,layer), encoding="utf-8")
  120. n += 1
  121. (OUT/f"icon-{k}-{NAMES[k]}-android-mono.svg").write_text(build(k,"deep","mono"), encoding="utf-8")
  122. n += 1
  123. print(f"生成 {n} 个 SVG → {OUT}")