fix: regenerate clean app icons with Pillow (fix corrupted favicon)
Co-authored-by: Cursor <cursoragent@cursor.com>
@@ -1,31 +1,17 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" role="img" aria-label="Crypto Monitor">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient id="ring" x1="0%" y1="0%" x2="100%" y2="100%">
|
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
|
||||||
<stop offset="0%" stop-color="#00d4ff"/>
|
<stop offset="0%" stop-color="#22d3ee"/>
|
||||||
<stop offset="55%" stop-color="#3d8bff"/>
|
<stop offset="100%" stop-color="#34d399"/>
|
||||||
<stop offset="100%" stop-color="#00ff9d"/>
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient id="up" x1="0%" y1="100%" x2="0%" y2="0%">
|
|
||||||
<stop offset="0%" stop-color="#00ff9d"/>
|
|
||||||
<stop offset="100%" stop-color="#7dffc8"/>
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient id="down" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
||||||
<stop offset="0%" stop-color="#ff6b8a"/>
|
|
||||||
<stop offset="100%" stop-color="#ff4d6d"/>
|
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
</defs>
|
</defs>
|
||||||
<rect width="512" height="512" rx="112" fill="#0b0e18"/>
|
<rect width="512" height="512" rx="108" fill="#0c1019"/>
|
||||||
<rect x="28" y="28" width="456" height="456" rx="96" fill="#12182a"/>
|
<rect x="36" y="36" width="440" height="440" rx="88" fill="#141b2d"/>
|
||||||
<rect x="28" y="28" width="456" height="456" rx="96" fill="none" stroke="url(#ring)" stroke-width="10" opacity="0.9"/>
|
<rect x="36" y="36" width="440" height="440" rx="88" fill="none" stroke="url(#g)" stroke-width="12"/>
|
||||||
<path d="M96 348 L176 268 L248 308 L352 168 L416 228" fill="none" stroke="url(#ring)" stroke-width="18" stroke-linecap="round" stroke-linejoin="round" opacity="0.35"/>
|
<path d="M120 320 L200 248 L280 272 L392 168" fill="none" stroke="url(#g)" stroke-width="20" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
<line x1="148" y1="332" x2="148" y2="228" stroke="url(#down)" stroke-width="16" stroke-linecap="round"/>
|
<circle cx="392" cy="168" r="18" fill="#34d399"/>
|
||||||
<rect x="132" y="252" width="32" height="52" rx="6" fill="url(#down)"/>
|
<rect x="168" y="268" width="28" height="64" rx="6" fill="#f87171"/>
|
||||||
<line x1="228" y1="352" x2="228" y2="196" stroke="url(#up)" stroke-width="16" stroke-linecap="round"/>
|
<line x1="182" y1="248" x2="182" y2="340" stroke="#f87171" stroke-width="10" stroke-linecap="round"/>
|
||||||
<rect x="212" y="220" width="32" height="88" rx="6" fill="url(#up)"/>
|
<rect x="268" y="220" width="28" height="96" rx="6" fill="#34d399"/>
|
||||||
<line x1="308" y1="320" x2="308" y2="240" stroke="url(#up)" stroke-width="16" stroke-linecap="round"/>
|
<line x1="282" y1="200" x2="282" y2="340" stroke="#34d399" stroke-width="10" stroke-linecap="round"/>
|
||||||
<rect x="292" y="264" width="32" height="40" rx="6" fill="url(#up)"/>
|
|
||||||
<line x1="384" y1="300" x2="384" y2="180" stroke="url(#up)" stroke-width="16" stroke-linecap="round"/>
|
|
||||||
<rect x="368" y="208" width="32" height="64" rx="6" fill="url(#up)"/>
|
|
||||||
<circle cx="256" cy="256" r="52" fill="none" stroke="url(#ring)" stroke-width="6" opacity="0.55"/>
|
|
||||||
<path d="M236 276 L256 220 L276 276 Z" fill="url(#ring)" opacity="0.95"/>
|
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 181 B |
|
Before Width: | Height: | Size: 224 B After Width: | Height: | Size: 162 B |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 538 B After Width: | Height: | Size: 497 B |
|
After Width: | Height: | Size: 612 B |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 5.9 KiB |
@@ -1,31 +1,17 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" role="img" aria-label="Crypto Monitor">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient id="ring" x1="0%" y1="0%" x2="100%" y2="100%">
|
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
|
||||||
<stop offset="0%" stop-color="#00d4ff"/>
|
<stop offset="0%" stop-color="#22d3ee"/>
|
||||||
<stop offset="55%" stop-color="#3d8bff"/>
|
<stop offset="100%" stop-color="#34d399"/>
|
||||||
<stop offset="100%" stop-color="#00ff9d"/>
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient id="up" x1="0%" y1="100%" x2="0%" y2="0%">
|
|
||||||
<stop offset="0%" stop-color="#00ff9d"/>
|
|
||||||
<stop offset="100%" stop-color="#7dffc8"/>
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient id="down" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
||||||
<stop offset="0%" stop-color="#ff6b8a"/>
|
|
||||||
<stop offset="100%" stop-color="#ff4d6d"/>
|
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
</defs>
|
</defs>
|
||||||
<rect width="512" height="512" rx="112" fill="#0b0e18"/>
|
<rect width="512" height="512" rx="108" fill="#0c1019"/>
|
||||||
<rect x="28" y="28" width="456" height="456" rx="96" fill="#12182a"/>
|
<rect x="36" y="36" width="440" height="440" rx="88" fill="#141b2d"/>
|
||||||
<rect x="28" y="28" width="456" height="456" rx="96" fill="none" stroke="url(#ring)" stroke-width="10" opacity="0.9"/>
|
<rect x="36" y="36" width="440" height="440" rx="88" fill="none" stroke="url(#g)" stroke-width="12"/>
|
||||||
<path d="M96 348 L176 268 L248 308 L352 168 L416 228" fill="none" stroke="url(#ring)" stroke-width="18" stroke-linecap="round" stroke-linejoin="round" opacity="0.35"/>
|
<path d="M120 320 L200 248 L280 272 L392 168" fill="none" stroke="url(#g)" stroke-width="20" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
<line x1="148" y1="332" x2="148" y2="228" stroke="url(#down)" stroke-width="16" stroke-linecap="round"/>
|
<circle cx="392" cy="168" r="18" fill="#34d399"/>
|
||||||
<rect x="132" y="252" width="32" height="52" rx="6" fill="url(#down)"/>
|
<rect x="168" y="268" width="28" height="64" rx="6" fill="#f87171"/>
|
||||||
<line x1="228" y1="352" x2="228" y2="196" stroke="url(#up)" stroke-width="16" stroke-linecap="round"/>
|
<line x1="182" y1="248" x2="182" y2="340" stroke="#f87171" stroke-width="10" stroke-linecap="round"/>
|
||||||
<rect x="212" y="220" width="32" height="88" rx="6" fill="url(#up)"/>
|
<rect x="268" y="220" width="28" height="96" rx="6" fill="#34d399"/>
|
||||||
<line x1="308" y1="320" x2="308" y2="240" stroke="url(#up)" stroke-width="16" stroke-linecap="round"/>
|
<line x1="282" y1="200" x2="282" y2="340" stroke="#34d399" stroke-width="10" stroke-linecap="round"/>
|
||||||
<rect x="292" y="264" width="32" height="40" rx="6" fill="url(#up)"/>
|
|
||||||
<line x1="384" y1="300" x2="384" y2="180" stroke="url(#up)" stroke-width="16" stroke-linecap="round"/>
|
|
||||||
<rect x="368" y="208" width="32" height="64" rx="6" fill="url(#up)"/>
|
|
||||||
<circle cx="256" cy="256" r="52" fill="none" stroke="url(#ring)" stroke-width="6" opacity="0.55"/>
|
|
||||||
<path d="M236 276 L256 220 L276 276 Z" fill="url(#ring)" opacity="0.95"/>
|
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 181 B |
|
Before Width: | Height: | Size: 224 B After Width: | Height: | Size: 162 B |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 538 B After Width: | Height: | Size: 497 B |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 5.9 KiB |
@@ -1,31 +1,17 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" role="img" aria-label="Crypto Monitor">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient id="ring" x1="0%" y1="0%" x2="100%" y2="100%">
|
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
|
||||||
<stop offset="0%" stop-color="#00d4ff"/>
|
<stop offset="0%" stop-color="#22d3ee"/>
|
||||||
<stop offset="55%" stop-color="#3d8bff"/>
|
<stop offset="100%" stop-color="#34d399"/>
|
||||||
<stop offset="100%" stop-color="#00ff9d"/>
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient id="up" x1="0%" y1="100%" x2="0%" y2="0%">
|
|
||||||
<stop offset="0%" stop-color="#00ff9d"/>
|
|
||||||
<stop offset="100%" stop-color="#7dffc8"/>
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient id="down" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
||||||
<stop offset="0%" stop-color="#ff6b8a"/>
|
|
||||||
<stop offset="100%" stop-color="#ff4d6d"/>
|
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
</defs>
|
</defs>
|
||||||
<rect width="512" height="512" rx="112" fill="#0b0e18"/>
|
<rect width="512" height="512" rx="108" fill="#0c1019"/>
|
||||||
<rect x="28" y="28" width="456" height="456" rx="96" fill="#12182a"/>
|
<rect x="36" y="36" width="440" height="440" rx="88" fill="#141b2d"/>
|
||||||
<rect x="28" y="28" width="456" height="456" rx="96" fill="none" stroke="url(#ring)" stroke-width="10" opacity="0.9"/>
|
<rect x="36" y="36" width="440" height="440" rx="88" fill="none" stroke="url(#g)" stroke-width="12"/>
|
||||||
<path d="M96 348 L176 268 L248 308 L352 168 L416 228" fill="none" stroke="url(#ring)" stroke-width="18" stroke-linecap="round" stroke-linejoin="round" opacity="0.35"/>
|
<path d="M120 320 L200 248 L280 272 L392 168" fill="none" stroke="url(#g)" stroke-width="20" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
<line x1="148" y1="332" x2="148" y2="228" stroke="url(#down)" stroke-width="16" stroke-linecap="round"/>
|
<circle cx="392" cy="168" r="18" fill="#34d399"/>
|
||||||
<rect x="132" y="252" width="32" height="52" rx="6" fill="url(#down)"/>
|
<rect x="168" y="268" width="28" height="64" rx="6" fill="#f87171"/>
|
||||||
<line x1="228" y1="352" x2="228" y2="196" stroke="url(#up)" stroke-width="16" stroke-linecap="round"/>
|
<line x1="182" y1="248" x2="182" y2="340" stroke="#f87171" stroke-width="10" stroke-linecap="round"/>
|
||||||
<rect x="212" y="220" width="32" height="88" rx="6" fill="url(#up)"/>
|
<rect x="268" y="220" width="28" height="96" rx="6" fill="#34d399"/>
|
||||||
<line x1="308" y1="320" x2="308" y2="240" stroke="url(#up)" stroke-width="16" stroke-linecap="round"/>
|
<line x1="282" y1="200" x2="282" y2="340" stroke="#34d399" stroke-width="10" stroke-linecap="round"/>
|
||||||
<rect x="292" y="264" width="32" height="40" rx="6" fill="url(#up)"/>
|
|
||||||
<line x1="384" y1="300" x2="384" y2="180" stroke="url(#up)" stroke-width="16" stroke-linecap="round"/>
|
|
||||||
<rect x="368" y="208" width="32" height="64" rx="6" fill="url(#up)"/>
|
|
||||||
<circle cx="256" cy="256" r="52" fill="none" stroke="url(#ring)" stroke-width="6" opacity="0.55"/>
|
|
||||||
<path d="M236 276 L256 220 L276 276 Z" fill="url(#ring)" opacity="0.95"/>
|
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 181 B |
|
Before Width: | Height: | Size: 224 B After Width: | Height: | Size: 162 B |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 538 B After Width: | Height: | Size: 497 B |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 5.9 KiB |
@@ -1,31 +1,17 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" role="img" aria-label="Crypto Monitor">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient id="ring" x1="0%" y1="0%" x2="100%" y2="100%">
|
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
|
||||||
<stop offset="0%" stop-color="#00d4ff"/>
|
<stop offset="0%" stop-color="#22d3ee"/>
|
||||||
<stop offset="55%" stop-color="#3d8bff"/>
|
<stop offset="100%" stop-color="#34d399"/>
|
||||||
<stop offset="100%" stop-color="#00ff9d"/>
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient id="up" x1="0%" y1="100%" x2="0%" y2="0%">
|
|
||||||
<stop offset="0%" stop-color="#00ff9d"/>
|
|
||||||
<stop offset="100%" stop-color="#7dffc8"/>
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient id="down" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
||||||
<stop offset="0%" stop-color="#ff6b8a"/>
|
|
||||||
<stop offset="100%" stop-color="#ff4d6d"/>
|
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
</defs>
|
</defs>
|
||||||
<rect width="512" height="512" rx="112" fill="#0b0e18"/>
|
<rect width="512" height="512" rx="108" fill="#0c1019"/>
|
||||||
<rect x="28" y="28" width="456" height="456" rx="96" fill="#12182a"/>
|
<rect x="36" y="36" width="440" height="440" rx="88" fill="#141b2d"/>
|
||||||
<rect x="28" y="28" width="456" height="456" rx="96" fill="none" stroke="url(#ring)" stroke-width="10" opacity="0.9"/>
|
<rect x="36" y="36" width="440" height="440" rx="88" fill="none" stroke="url(#g)" stroke-width="12"/>
|
||||||
<path d="M96 348 L176 268 L248 308 L352 168 L416 228" fill="none" stroke="url(#ring)" stroke-width="18" stroke-linecap="round" stroke-linejoin="round" opacity="0.35"/>
|
<path d="M120 320 L200 248 L280 272 L392 168" fill="none" stroke="url(#g)" stroke-width="20" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
<line x1="148" y1="332" x2="148" y2="228" stroke="url(#down)" stroke-width="16" stroke-linecap="round"/>
|
<circle cx="392" cy="168" r="18" fill="#34d399"/>
|
||||||
<rect x="132" y="252" width="32" height="52" rx="6" fill="url(#down)"/>
|
<rect x="168" y="268" width="28" height="64" rx="6" fill="#f87171"/>
|
||||||
<line x1="228" y1="352" x2="228" y2="196" stroke="url(#up)" stroke-width="16" stroke-linecap="round"/>
|
<line x1="182" y1="248" x2="182" y2="340" stroke="#f87171" stroke-width="10" stroke-linecap="round"/>
|
||||||
<rect x="212" y="220" width="32" height="88" rx="6" fill="url(#up)"/>
|
<rect x="268" y="220" width="28" height="96" rx="6" fill="#34d399"/>
|
||||||
<line x1="308" y1="320" x2="308" y2="240" stroke="url(#up)" stroke-width="16" stroke-linecap="round"/>
|
<line x1="282" y1="200" x2="282" y2="340" stroke="#34d399" stroke-width="10" stroke-linecap="round"/>
|
||||||
<rect x="292" y="264" width="32" height="40" rx="6" fill="url(#up)"/>
|
|
||||||
<line x1="384" y1="300" x2="384" y2="180" stroke="url(#up)" stroke-width="16" stroke-linecap="round"/>
|
|
||||||
<rect x="368" y="208" width="32" height="64" rx="6" fill="url(#up)"/>
|
|
||||||
<circle cx="256" cy="256" r="52" fill="none" stroke="url(#ring)" stroke-width="6" opacity="0.55"/>
|
|
||||||
<path d="M236 276 L256 220 L276 276 Z" fill="url(#ring)" opacity="0.95"/>
|
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 181 B |
|
Before Width: | Height: | Size: 224 B After Width: | Height: | Size: 162 B |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 538 B After Width: | Height: | Size: 497 B |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 5.9 KiB |
@@ -1,31 +1,17 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" role="img" aria-label="Crypto Monitor">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient id="ring" x1="0%" y1="0%" x2="100%" y2="100%">
|
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
|
||||||
<stop offset="0%" stop-color="#00d4ff"/>
|
<stop offset="0%" stop-color="#22d3ee"/>
|
||||||
<stop offset="55%" stop-color="#3d8bff"/>
|
<stop offset="100%" stop-color="#34d399"/>
|
||||||
<stop offset="100%" stop-color="#00ff9d"/>
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient id="up" x1="0%" y1="100%" x2="0%" y2="0%">
|
|
||||||
<stop offset="0%" stop-color="#00ff9d"/>
|
|
||||||
<stop offset="100%" stop-color="#7dffc8"/>
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient id="down" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
||||||
<stop offset="0%" stop-color="#ff6b8a"/>
|
|
||||||
<stop offset="100%" stop-color="#ff4d6d"/>
|
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
</defs>
|
</defs>
|
||||||
<rect width="512" height="512" rx="112" fill="#0b0e18"/>
|
<rect width="512" height="512" rx="108" fill="#0c1019"/>
|
||||||
<rect x="28" y="28" width="456" height="456" rx="96" fill="#12182a"/>
|
<rect x="36" y="36" width="440" height="440" rx="88" fill="#141b2d"/>
|
||||||
<rect x="28" y="28" width="456" height="456" rx="96" fill="none" stroke="url(#ring)" stroke-width="10" opacity="0.9"/>
|
<rect x="36" y="36" width="440" height="440" rx="88" fill="none" stroke="url(#g)" stroke-width="12"/>
|
||||||
<path d="M96 348 L176 268 L248 308 L352 168 L416 228" fill="none" stroke="url(#ring)" stroke-width="18" stroke-linecap="round" stroke-linejoin="round" opacity="0.35"/>
|
<path d="M120 320 L200 248 L280 272 L392 168" fill="none" stroke="url(#g)" stroke-width="20" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
<line x1="148" y1="332" x2="148" y2="228" stroke="url(#down)" stroke-width="16" stroke-linecap="round"/>
|
<circle cx="392" cy="168" r="18" fill="#34d399"/>
|
||||||
<rect x="132" y="252" width="32" height="52" rx="6" fill="url(#down)"/>
|
<rect x="168" y="268" width="28" height="64" rx="6" fill="#f87171"/>
|
||||||
<line x1="228" y1="352" x2="228" y2="196" stroke="url(#up)" stroke-width="16" stroke-linecap="round"/>
|
<line x1="182" y1="248" x2="182" y2="340" stroke="#f87171" stroke-width="10" stroke-linecap="round"/>
|
||||||
<rect x="212" y="220" width="32" height="88" rx="6" fill="url(#up)"/>
|
<rect x="268" y="220" width="28" height="96" rx="6" fill="#34d399"/>
|
||||||
<line x1="308" y1="320" x2="308" y2="240" stroke="url(#up)" stroke-width="16" stroke-linecap="round"/>
|
<line x1="282" y1="200" x2="282" y2="340" stroke="#34d399" stroke-width="10" stroke-linecap="round"/>
|
||||||
<rect x="292" y="264" width="32" height="40" rx="6" fill="url(#up)"/>
|
|
||||||
<line x1="384" y1="300" x2="384" y2="180" stroke="url(#up)" stroke-width="16" stroke-linecap="round"/>
|
|
||||||
<rect x="368" y="208" width="32" height="64" rx="6" fill="url(#up)"/>
|
|
||||||
<circle cx="256" cy="256" r="52" fill="none" stroke="url(#ring)" stroke-width="6" opacity="0.55"/>
|
|
||||||
<path d="M236 276 L256 220 L276 276 Z" fill="url(#ring)" opacity="0.95"/>
|
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 181 B |
|
Before Width: | Height: | Size: 224 B After Width: | Height: | Size: 162 B |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 538 B After Width: | Height: | Size: 497 B |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 5.9 KiB |
@@ -1,31 +1,17 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" role="img" aria-label="Crypto Monitor">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient id="ring" x1="0%" y1="0%" x2="100%" y2="100%">
|
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
|
||||||
<stop offset="0%" stop-color="#00d4ff"/>
|
<stop offset="0%" stop-color="#22d3ee"/>
|
||||||
<stop offset="55%" stop-color="#3d8bff"/>
|
<stop offset="100%" stop-color="#34d399"/>
|
||||||
<stop offset="100%" stop-color="#00ff9d"/>
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient id="up" x1="0%" y1="100%" x2="0%" y2="0%">
|
|
||||||
<stop offset="0%" stop-color="#00ff9d"/>
|
|
||||||
<stop offset="100%" stop-color="#7dffc8"/>
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient id="down" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
||||||
<stop offset="0%" stop-color="#ff6b8a"/>
|
|
||||||
<stop offset="100%" stop-color="#ff4d6d"/>
|
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
</defs>
|
</defs>
|
||||||
<rect width="512" height="512" rx="112" fill="#0b0e18"/>
|
<rect width="512" height="512" rx="108" fill="#0c1019"/>
|
||||||
<rect x="28" y="28" width="456" height="456" rx="96" fill="#12182a"/>
|
<rect x="36" y="36" width="440" height="440" rx="88" fill="#141b2d"/>
|
||||||
<rect x="28" y="28" width="456" height="456" rx="96" fill="none" stroke="url(#ring)" stroke-width="10" opacity="0.9"/>
|
<rect x="36" y="36" width="440" height="440" rx="88" fill="none" stroke="url(#g)" stroke-width="12"/>
|
||||||
<path d="M96 348 L176 268 L248 308 L352 168 L416 228" fill="none" stroke="url(#ring)" stroke-width="18" stroke-linecap="round" stroke-linejoin="round" opacity="0.35"/>
|
<path d="M120 320 L200 248 L280 272 L392 168" fill="none" stroke="url(#g)" stroke-width="20" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
<line x1="148" y1="332" x2="148" y2="228" stroke="url(#down)" stroke-width="16" stroke-linecap="round"/>
|
<circle cx="392" cy="168" r="18" fill="#34d399"/>
|
||||||
<rect x="132" y="252" width="32" height="52" rx="6" fill="url(#down)"/>
|
<rect x="168" y="268" width="28" height="64" rx="6" fill="#f87171"/>
|
||||||
<line x1="228" y1="352" x2="228" y2="196" stroke="url(#up)" stroke-width="16" stroke-linecap="round"/>
|
<line x1="182" y1="248" x2="182" y2="340" stroke="#f87171" stroke-width="10" stroke-linecap="round"/>
|
||||||
<rect x="212" y="220" width="32" height="88" rx="6" fill="url(#up)"/>
|
<rect x="268" y="220" width="28" height="96" rx="6" fill="#34d399"/>
|
||||||
<line x1="308" y1="320" x2="308" y2="240" stroke="url(#up)" stroke-width="16" stroke-linecap="round"/>
|
<line x1="282" y1="200" x2="282" y2="340" stroke="#34d399" stroke-width="10" stroke-linecap="round"/>
|
||||||
<rect x="292" y="264" width="32" height="40" rx="6" fill="url(#up)"/>
|
|
||||||
<line x1="384" y1="300" x2="384" y2="180" stroke="url(#up)" stroke-width="16" stroke-linecap="round"/>
|
|
||||||
<rect x="368" y="208" width="32" height="64" rx="6" fill="url(#up)"/>
|
|
||||||
<circle cx="256" cy="256" r="52" fill="none" stroke="url(#ring)" stroke-width="6" opacity="0.55"/>
|
|
||||||
<path d="M236 276 L256 220 L276 276 Z" fill="url(#ring)" opacity="0.95"/>
|
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.0 KiB |
@@ -9,7 +9,7 @@
|
|||||||
3. `link rel="icon"` / `favicon.ico`
|
3. `link rel="icon"` / `favicon.ico`
|
||||||
4. 若都没有 → 灰色地球或网页标题首字
|
4. 若都没有 → 灰色地球或网页标题首字
|
||||||
|
|
||||||
本仓库已在 **中控** 与 **四所监控页** 配置统一品牌图标(深色底 + 青绿渐变 K 线),与页面 UI 一致。
|
本仓库已在 **中控** 与 **四所监控页** 配置统一品牌图标(深色圆角底 + 青绿趋势线 + 简化的 K 线),与页面 UI 一致。PNG/ICO 由 **Pillow** 生成,避免损坏的 favicon 出现花屏。
|
||||||
|
|
||||||
## 文件位置
|
## 文件位置
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 181 B |
|
Before Width: | Height: | Size: 224 B After Width: | Height: | Size: 162 B |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 538 B After Width: | Height: | Size: 497 B |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 5.9 KiB |
@@ -1,31 +1,17 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" role="img" aria-label="Crypto Monitor">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient id="ring" x1="0%" y1="0%" x2="100%" y2="100%">
|
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
|
||||||
<stop offset="0%" stop-color="#00d4ff"/>
|
<stop offset="0%" stop-color="#22d3ee"/>
|
||||||
<stop offset="55%" stop-color="#3d8bff"/>
|
<stop offset="100%" stop-color="#34d399"/>
|
||||||
<stop offset="100%" stop-color="#00ff9d"/>
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient id="up" x1="0%" y1="100%" x2="0%" y2="0%">
|
|
||||||
<stop offset="0%" stop-color="#00ff9d"/>
|
|
||||||
<stop offset="100%" stop-color="#7dffc8"/>
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient id="down" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
||||||
<stop offset="0%" stop-color="#ff6b8a"/>
|
|
||||||
<stop offset="100%" stop-color="#ff4d6d"/>
|
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
</defs>
|
</defs>
|
||||||
<rect width="512" height="512" rx="112" fill="#0b0e18"/>
|
<rect width="512" height="512" rx="108" fill="#0c1019"/>
|
||||||
<rect x="28" y="28" width="456" height="456" rx="96" fill="#12182a"/>
|
<rect x="36" y="36" width="440" height="440" rx="88" fill="#141b2d"/>
|
||||||
<rect x="28" y="28" width="456" height="456" rx="96" fill="none" stroke="url(#ring)" stroke-width="10" opacity="0.9"/>
|
<rect x="36" y="36" width="440" height="440" rx="88" fill="none" stroke="url(#g)" stroke-width="12"/>
|
||||||
<path d="M96 348 L176 268 L248 308 L352 168 L416 228" fill="none" stroke="url(#ring)" stroke-width="18" stroke-linecap="round" stroke-linejoin="round" opacity="0.35"/>
|
<path d="M120 320 L200 248 L280 272 L392 168" fill="none" stroke="url(#g)" stroke-width="20" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
<line x1="148" y1="332" x2="148" y2="228" stroke="url(#down)" stroke-width="16" stroke-linecap="round"/>
|
<circle cx="392" cy="168" r="18" fill="#34d399"/>
|
||||||
<rect x="132" y="252" width="32" height="52" rx="6" fill="url(#down)"/>
|
<rect x="168" y="268" width="28" height="64" rx="6" fill="#f87171"/>
|
||||||
<line x1="228" y1="352" x2="228" y2="196" stroke="url(#up)" stroke-width="16" stroke-linecap="round"/>
|
<line x1="182" y1="248" x2="182" y2="340" stroke="#f87171" stroke-width="10" stroke-linecap="round"/>
|
||||||
<rect x="212" y="220" width="32" height="88" rx="6" fill="url(#up)"/>
|
<rect x="268" y="220" width="28" height="96" rx="6" fill="#34d399"/>
|
||||||
<line x1="308" y1="320" x2="308" y2="240" stroke="url(#up)" stroke-width="16" stroke-linecap="round"/>
|
<line x1="282" y1="200" x2="282" y2="340" stroke="#34d399" stroke-width="10" stroke-linecap="round"/>
|
||||||
<rect x="292" y="264" width="32" height="40" rx="6" fill="url(#up)"/>
|
|
||||||
<line x1="384" y1="300" x2="384" y2="180" stroke="url(#up)" stroke-width="16" stroke-linecap="round"/>
|
|
||||||
<rect x="368" y="208" width="32" height="64" rx="6" fill="url(#up)"/>
|
|
||||||
<circle cx="256" cy="256" r="52" fill="none" stroke="url(#ring)" stroke-width="6" opacity="0.55"/>
|
|
||||||
<path d="M236 276 L256 220 L276 276 Z" fill="url(#ring)" opacity="0.95"/>
|
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.0 KiB |
@@ -1,212 +1,110 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""从 brand/icon.svg 逻辑绘制 PNG/ICO,供 Chrome 快捷方式、PWA manifest 使用。"""
|
"""生成品牌 PNG/ICO(Pillow),供 Chrome 快捷方式与 manifest 使用。"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import struct
|
import shutil
|
||||||
import zlib
|
|
||||||
|
|
||||||
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
OUT = os.path.join(REPO, "brand", "icons")
|
OUT = os.path.join(REPO, "brand", "icons")
|
||||||
|
|
||||||
|
BG = (12, 16, 25, 255)
|
||||||
|
PANEL = (20, 27, 45, 255)
|
||||||
|
CYAN = (34, 211, 238, 255)
|
||||||
|
GREEN = (52, 211, 153, 255)
|
||||||
|
RED = (248, 113, 113, 255)
|
||||||
|
|
||||||
def _png_chunk(tag: bytes, data: bytes) -> bytes:
|
|
||||||
return (
|
def _lerp(c1: tuple[int, ...], c2: tuple[int, ...], t: float) -> tuple[int, int, int, int]:
|
||||||
struct.pack(">I", len(data))
|
t = max(0.0, min(1.0, t))
|
||||||
+ tag
|
return tuple(int(c1[i] + (c2[i] - c1[i]) * t) for i in range(4)) # type: ignore
|
||||||
+ data
|
|
||||||
+ struct.pack(">I", zlib.crc32(tag + data) & 0xFFFFFFFF)
|
|
||||||
|
def _rounded_rect(draw, box, radius: int, fill) -> None:
|
||||||
|
draw.rounded_rectangle(box, radius=radius, fill=fill)
|
||||||
|
|
||||||
|
|
||||||
|
def render_icon(size: int):
|
||||||
|
from PIL import Image, ImageDraw
|
||||||
|
|
||||||
|
img = Image.new("RGBA", (size, size), (0, 0, 0, 0))
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
m = max(6, size // 12)
|
||||||
|
r = max(8, size // 6)
|
||||||
|
_rounded_rect(draw, (m, m, size - m, size - m), r, BG)
|
||||||
|
inner = m + max(2, size // 28)
|
||||||
|
_rounded_rect(draw, (inner, inner, size - inner, size - inner), max(6, r - 4), PANEL)
|
||||||
|
|
||||||
|
# 渐变描边(四角采样)
|
||||||
|
border = max(2, size // 42)
|
||||||
|
for i in range(border):
|
||||||
|
t0 = i / max(1, border - 1)
|
||||||
|
for x in range(inner, size - inner):
|
||||||
|
t = (x - inner) / max(1, size - 2 * inner)
|
||||||
|
col = _lerp(CYAN, GREEN, (t + t0) * 0.5)
|
||||||
|
draw.point((x, inner + i), fill=col)
|
||||||
|
draw.point((x, size - inner - 1 - i), fill=col)
|
||||||
|
for y in range(inner, size - inner):
|
||||||
|
t = (y - inner) / max(1, size - 2 * inner)
|
||||||
|
col = _lerp(CYAN, GREEN, (t + t0) * 0.5)
|
||||||
|
draw.point((inner + i, y), fill=col)
|
||||||
|
draw.point((size - inner - 1 - i, y), fill=col)
|
||||||
|
|
||||||
|
def sx(v: float) -> int:
|
||||||
|
return int(v * size / 512)
|
||||||
|
|
||||||
|
def sy(v: float) -> int:
|
||||||
|
return int(v * size / 512)
|
||||||
|
|
||||||
|
# 趋势线
|
||||||
|
pts = [(120, 320), (200, 248), (280, 272), (392, 168)]
|
||||||
|
scaled = [(sx(x), sy(y)) for x, y in pts]
|
||||||
|
draw.line(scaled, fill=CYAN, width=max(2, size // 26), joint="curve")
|
||||||
|
ex, ey = scaled[-1]
|
||||||
|
draw.ellipse(
|
||||||
|
(ex - size // 28, ey - size // 28, ex + size // 28, ey + size // 28),
|
||||||
|
fill=GREEN,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 蜡烛
|
||||||
def _write_png(path: str, size: int, rgba: bytes) -> None:
|
def candle(cx, top, bottom, body_top, body_bottom, color):
|
||||||
raw = b""
|
w = max(1, size // 64)
|
||||||
stride = size * 4
|
bh = max(2, size // 32)
|
||||||
for y in range(size):
|
draw.line((cx, top, cx, bottom), fill=color, width=w)
|
||||||
raw += b"\x00" + rgba[y * stride : (y + 1) * stride]
|
draw.rounded_rectangle(
|
||||||
ihdr = struct.pack(">IIBBBBB", size, size, 8, 6, 0, 0, 0)
|
(cx - bh, body_top, cx + bh, body_bottom),
|
||||||
idat = zlib.compress(raw, 9)
|
radius=max(1, bh // 3),
|
||||||
png = (
|
fill=color,
|
||||||
b"\x89PNG\r\n\x1a\n"
|
|
||||||
+ _png_chunk(b"IHDR", ihdr)
|
|
||||||
+ _png_chunk(b"IDAT", idat)
|
|
||||||
+ _png_chunk(b"IEND", b"")
|
|
||||||
)
|
|
||||||
with open(path, "wb") as f:
|
|
||||||
f.write(png)
|
|
||||||
|
|
||||||
|
|
||||||
def _lerp(a: float, b: float, t: float) -> float:
|
|
||||||
return a + (b - a) * t
|
|
||||||
|
|
||||||
|
|
||||||
def _gradient(t: float) -> tuple[int, int, int]:
|
|
||||||
if t < 0.55:
|
|
||||||
u = t / 0.55
|
|
||||||
return (
|
|
||||||
int(_lerp(0, 0, u)),
|
|
||||||
int(_lerp(212, 139, u)),
|
|
||||||
int(_lerp(255, 255, u)),
|
|
||||||
)
|
|
||||||
u = (t - 0.55) / 0.45
|
|
||||||
return (
|
|
||||||
int(_lerp(61, 0, u)),
|
|
||||||
int(_lerp(255, 255, u)),
|
|
||||||
int(_lerp(157, 157, u)),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
candle(sx(182), sy(248), sy(340), sy(268), sy(332), RED)
|
||||||
|
candle(sx(282), sy(200), sy(340), sy(220), sy(316), GREEN)
|
||||||
|
|
||||||
def _inside_round_rect(x: int, y: int, size: int, pad: int, radius: int) -> bool:
|
return img
|
||||||
if x < pad or y < pad or x >= size - pad or y >= size - pad:
|
|
||||||
return False
|
|
||||||
r = radius
|
|
||||||
if x < pad + r and y < pad + r:
|
|
||||||
return (x - pad - r) ** 2 + (y - pad - r) ** 2 <= r * r
|
|
||||||
if x >= size - pad - r and y < pad + r:
|
|
||||||
return (x - (size - pad - r)) ** 2 + (y - pad - r) ** 2 <= r * r
|
|
||||||
if x < pad + r and y >= size - pad - r:
|
|
||||||
return (x - pad - r) ** 2 + (y - (size - pad - r)) ** 2 <= r * r
|
|
||||||
if x >= size - pad - r and y >= size - pad - r:
|
|
||||||
return (x - (size - pad - r)) ** 2 + (y - (size - pad - r)) ** 2 <= r * r
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def _draw_candle(
|
|
||||||
buf: bytearray,
|
|
||||||
size: int,
|
|
||||||
cx: int,
|
|
||||||
top: int,
|
|
||||||
bottom: int,
|
|
||||||
body_top: int,
|
|
||||||
body_bottom: int,
|
|
||||||
rgb: tuple[int, int, int],
|
|
||||||
wick_w: int = 2,
|
|
||||||
body_half: int = 7,
|
|
||||||
) -> None:
|
|
||||||
for y in range(max(0, top), min(size, bottom + 1)):
|
|
||||||
for x in range(cx - wick_w, cx + wick_w + 1):
|
|
||||||
if 0 <= x < size:
|
|
||||||
i = (y * size + x) * 4
|
|
||||||
buf[i : i + 3] = bytes((*rgb, 255))
|
|
||||||
for y in range(max(0, body_top), min(size, body_bottom + 1)):
|
|
||||||
for x in range(cx - body_half, cx + body_half + 1):
|
|
||||||
if 0 <= x < size:
|
|
||||||
i = (y * size + x) * 4
|
|
||||||
buf[i : i + 3] = bytes((*rgb, 255))
|
|
||||||
|
|
||||||
|
|
||||||
def render_icon_rgba(size: int) -> bytes:
|
|
||||||
buf = bytearray(size * size * 4)
|
|
||||||
pad = max(4, size // 14)
|
|
||||||
radius = size // 5
|
|
||||||
inner_pad = pad + max(2, size // 32)
|
|
||||||
ring_w = max(2, size // 48)
|
|
||||||
|
|
||||||
for y in range(size):
|
|
||||||
for x in range(size):
|
|
||||||
i = (y * size + x) * 4
|
|
||||||
if not _inside_round_rect(x, y, size, pad, radius):
|
|
||||||
buf[i : i + 4] = b"\x00\x00\x00\x00"
|
|
||||||
continue
|
|
||||||
if _inside_round_rect(x, y, size, inner_pad, radius - 4):
|
|
||||||
buf[i : i + 4] = bytes((18, 24, 42, 255))
|
|
||||||
else:
|
|
||||||
t = (x + y) / (2 * size)
|
|
||||||
r, g, b = _gradient(t)
|
|
||||||
buf[i : i + 4] = bytes((r, g, b, 220))
|
|
||||||
|
|
||||||
s = size / 512.0
|
|
||||||
def sc(v: int) -> int:
|
|
||||||
return int(v * s)
|
|
||||||
|
|
||||||
_draw_candle(buf, size, sc(148), sc(228), sc(332), sc(252), sc(304), (255, 77, 109), sc(8), sc(16))
|
|
||||||
_draw_candle(buf, size, sc(228), sc(196), sc(352), sc(220), sc(308), (0, 255, 157), sc(8), sc(16))
|
|
||||||
_draw_candle(buf, size, sc(308), sc(240), sc(320), sc(264), sc(304), (0, 255, 157), sc(8), sc(14))
|
|
||||||
_draw_candle(buf, size, sc(384), sc(180), sc(300), sc(208), sc(272), (0, 255, 157), sc(8), sc(16))
|
|
||||||
|
|
||||||
ccx, ccy = sc(256), sc(256)
|
|
||||||
cr = sc(52)
|
|
||||||
for y in range(size):
|
|
||||||
for x in range(size):
|
|
||||||
d = ((x - ccx) ** 2 + (y - ccy) ** 2) ** 0.5
|
|
||||||
if cr - ring_w <= d <= cr:
|
|
||||||
t = (x + y) / (2 * size)
|
|
||||||
r, g, b = _gradient(t)
|
|
||||||
i = (y * size + x) * 4
|
|
||||||
buf[i : i + 4] = bytes((r, g, b, 200))
|
|
||||||
tri = [
|
|
||||||
(sc(236), sc(276)),
|
|
||||||
(sc(256), sc(220)),
|
|
||||||
(sc(276), sc(276)),
|
|
||||||
]
|
|
||||||
|
|
||||||
def _in_tri(px: int, py: int) -> bool:
|
|
||||||
x1, y1 = tri[0]
|
|
||||||
x2, y2 = tri[1]
|
|
||||||
x3, y3 = tri[2]
|
|
||||||
d1 = (px - x2) * (y1 - y2) - (x1 - x2) * (py - y2)
|
|
||||||
d2 = (px - x3) * (y2 - y3) - (x2 - x3) * (py - y3)
|
|
||||||
d3 = (px - x1) * (y3 - y1) - (x3 - x1) * (py - y1)
|
|
||||||
has_neg = d1 < 0 or d2 < 0 or d3 < 0
|
|
||||||
has_pos = d1 > 0 or d2 > 0 or d3 > 0
|
|
||||||
return not (has_neg and has_pos)
|
|
||||||
|
|
||||||
for y in range(size):
|
|
||||||
for x in range(size):
|
|
||||||
if _in_tri(x, y):
|
|
||||||
t = (x + y) / (2 * size)
|
|
||||||
r, g, b = _gradient(t)
|
|
||||||
i = (y * size + x) * 4
|
|
||||||
buf[i : i + 4] = bytes((r, g, b, 255))
|
|
||||||
return bytes(buf)
|
|
||||||
|
|
||||||
|
|
||||||
def _write_ico(path: str, sizes: list[int]) -> None:
|
|
||||||
images = []
|
|
||||||
for sz in sizes:
|
|
||||||
rgba = render_icon_rgba(sz)
|
|
||||||
# BGRA bottom-up for ICO
|
|
||||||
row = sz * 4
|
|
||||||
pixels = bytearray()
|
|
||||||
for y in range(sz - 1, -1, -1):
|
|
||||||
for x in range(sz):
|
|
||||||
i = (y * sz + x) * 4
|
|
||||||
pixels.extend([rgba[i + 2], rgba[i + 1], rgba[i], rgba[i + 3]])
|
|
||||||
and_row = (sz * 4 + 3) & ~3
|
|
||||||
if and_row > sz * 4:
|
|
||||||
pixels.extend(b"\x00" * (and_row - sz * 4))
|
|
||||||
bmp = b"BM" + struct.pack("<I", 40 + len(pixels)) + b"\x00\x00\x00\x00" + struct.pack(
|
|
||||||
"<I", 40
|
|
||||||
) + struct.pack("<i", sz) + struct.pack("<i", sz * 2) + struct.pack("<H", 1) + struct.pack(
|
|
||||||
"<H", 32
|
|
||||||
) + struct.pack("<I", 0) + struct.pack("<I", len(pixels)) + struct.pack("<i", 0) * 4
|
|
||||||
images.append((sz, bmp + bytes(pixels)))
|
|
||||||
|
|
||||||
offset = 6 + 16 * len(images)
|
|
||||||
parts = [struct.pack("<HHH", 0, 1, len(images))]
|
|
||||||
data_parts = []
|
|
||||||
for sz, data in images:
|
|
||||||
parts.append(
|
|
||||||
struct.pack("<BBBBHHII", 32, 32, 0, 0, 1, 32, len(data), offset)
|
|
||||||
)
|
|
||||||
offset += len(data)
|
|
||||||
data_parts.append(data)
|
|
||||||
with open(path, "wb") as f:
|
|
||||||
f.write(b"".join(parts) + b"".join(data_parts))
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
os.makedirs(OUT, exist_ok=True)
|
from PIL import Image
|
||||||
import shutil
|
|
||||||
|
|
||||||
shutil.copy2(
|
os.makedirs(OUT, exist_ok=True)
|
||||||
os.path.join(REPO, "brand", "icon.svg"),
|
shutil.copy2(os.path.join(REPO, "brand", "icon.svg"), os.path.join(OUT, "icon.svg"))
|
||||||
os.path.join(OUT, "icon.svg"),
|
|
||||||
|
sizes = [16, 32, 48, 180, 192, 512]
|
||||||
|
images: dict[int, Image.Image] = {}
|
||||||
|
for sz in sizes:
|
||||||
|
im = render_icon(sz)
|
||||||
|
images[sz] = im
|
||||||
|
name = "apple-touch-icon.png" if sz == 180 else f"icon-{sz}.png"
|
||||||
|
im.save(os.path.join(OUT, name), format="PNG", optimize=True)
|
||||||
|
|
||||||
|
ico_sizes = [16, 32, 48]
|
||||||
|
ico_imgs = [images[s] for s in ico_sizes]
|
||||||
|
ico_imgs[0].save(
|
||||||
|
os.path.join(OUT, "favicon.ico"),
|
||||||
|
format="ICO",
|
||||||
|
sizes=[(s, s) for s in ico_sizes],
|
||||||
|
append_images=ico_imgs[1:],
|
||||||
)
|
)
|
||||||
for sz in (16, 32, 180, 192, 512):
|
|
||||||
_write_png(os.path.join(OUT, f"icon-{sz}.png"), sz, render_icon_rgba(sz))
|
|
||||||
shutil.copy2(os.path.join(OUT, "icon-180.png"), os.path.join(OUT, "apple-touch-icon.png"))
|
|
||||||
_write_ico(os.path.join(OUT, "favicon.ico"), [16, 32, 48])
|
|
||||||
print(f"DONE {OUT}")
|
print(f"DONE {OUT}")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||