Spaces:
Running
Running
Download scripts/icons.mjs from davanstrien/phonon-reader: direct link, hf CLI and curl.
- Browser
- Download file 2.89 kB
-
https://huggingface.co/spaces/davanstrien/phonon-reader/resolve/main/scripts/icons.mjs
- Command line
-
hf download hf://spaces/davanstrien/phonon-reader/scripts/icons.mjs
-
curl -L -o icons.mjs https://huggingface.co/spaces/davanstrien/phonon-reader/resolve/main/scripts/icons.mjs
2.89 kB
| // Draws the app icons (a waveform on terracotta) as PNGs with no dependencies. | |
| import { deflateSync } from 'node:zlib'; | |
| import { writeFileSync, mkdirSync } from 'node:fs'; | |
| import { join } from 'node:path'; | |
| const crcTable = Array.from({ length: 256 }, (_, n) => { | |
| let c = n; | |
| for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1; | |
| return c >>> 0; | |
| }); | |
| const crc = (buf) => { let c = ~0; for (const b of buf) c = crcTable[(c ^ b) & 255] ^ (c >>> 8); return ~c >>> 0; }; | |
| const chunk = (type, data) => { | |
| const len = Buffer.alloc(4); len.writeUInt32BE(data.length); | |
| const td = Buffer.concat([Buffer.from(type), data]); | |
| const c = Buffer.alloc(4); c.writeUInt32BE(crc(td)); | |
| return Buffer.concat([len, td, c]); | |
| }; | |
| function draw(size, maskable) { | |
| const ss = 3, S = size * ss; // supersample for smooth edges | |
| const BG = [180, 83, 42], FG = [244, 239, 230]; | |
| const heights = [0.18, 0.36, 0.56, 0.36, 0.24, 0.46, 0.2]; | |
| const scale = maskable ? 0.62 : 0.8; | |
| const n = heights.length, w = (S * scale) / (n * 1.7); | |
| const total = n * w + (n - 1) * w * 0.7; | |
| const x0 = (S - total) / 2, R = S * 0.22; | |
| const inRound = (x, y, x1, y1, x2, y2, r) => { | |
| if (x < x1 || x > x2 || y < y1 || y > y2) return false; | |
| const cx = Math.min(Math.max(x, x1 + r), x2 - r), cy = Math.min(Math.max(y, y1 + r), y2 - r); | |
| return (x - cx) ** 2 + (y - cy) ** 2 <= r * r; | |
| }; | |
| const px = (x, y) => { | |
| if (!maskable && !inRound(x, y, 0, 0, S, S, R)) return null; | |
| for (let i = 0; i < n; i++) { | |
| const bx = x0 + i * w * 1.7, hh = S * heights[i] * scale; | |
| if (inRound(x, y, bx, S / 2 - hh / 2, bx + w, S / 2 + hh / 2, w / 2)) return FG; | |
| } | |
| return BG; | |
| }; | |
| const raw = Buffer.alloc(size * (size * 4 + 1)); | |
| for (let y = 0; y < size; y++) { | |
| raw[y * (size * 4 + 1)] = 0; | |
| for (let x = 0; x < size; x++) { | |
| let r = 0, g = 0, b = 0, a = 0; | |
| for (let sy = 0; sy < ss; sy++) for (let sx = 0; sx < ss; sx++) { | |
| const c = px(x * ss + sx + 0.5, y * ss + sy + 0.5); | |
| if (c) { r += c[0]; g += c[1]; b += c[2]; a++; } | |
| } | |
| const o = y * (size * 4 + 1) + 1 + x * 4; | |
| if (a) { raw[o] = r / a; raw[o + 1] = g / a; raw[o + 2] = b / a; } | |
| raw[o + 3] = Math.round((a / (ss * ss)) * 255); | |
| } | |
| } | |
| const ihdr = Buffer.alloc(13); | |
| ihdr.writeUInt32BE(size, 0); ihdr.writeUInt32BE(size, 4); | |
| ihdr[8] = 8; ihdr[9] = 6; ihdr[10] = 0; ihdr[11] = 0; ihdr[12] = 0; | |
| return Buffer.concat([ | |
| Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]), | |
| chunk('IHDR', ihdr), chunk('IDAT', deflateSync(raw, { level: 9 })), chunk('IEND', Buffer.alloc(0)), | |
| ]); | |
| } | |
| export function writeIcons(dir) { | |
| mkdirSync(dir, { recursive: true }); | |
| writeFileSync(join(dir, 'icon-192.png'), draw(192, false)); | |
| writeFileSync(join(dir, 'icon-512.png'), draw(512, false)); | |
| writeFileSync(join(dir, 'maskable-512.png'), draw(512, true)); | |
| } | |