首次提交
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const zlib = require('zlib');
|
||||
|
||||
function crc32(buf) {
|
||||
let c = ~0 >>> 0;
|
||||
for (let i = 0; i < buf.length; i++) {
|
||||
c ^= buf[i];
|
||||
for (let k = 0; k < 8; k++) c = (c >>> 1) ^ (0xEDB88320 & -(c & 1));
|
||||
}
|
||||
return ~c >>> 0;
|
||||
}
|
||||
|
||||
function chunk(type, data) {
|
||||
const len = Buffer.alloc(4);
|
||||
len.writeUInt32BE(data.length, 0);
|
||||
const t = Buffer.from(type, 'ascii');
|
||||
const crc = Buffer.alloc(4);
|
||||
crc.writeUInt32BE(crc32(Buffer.concat([t, data])), 0);
|
||||
return Buffer.concat([len, t, data, crc]);
|
||||
}
|
||||
|
||||
function encodePNG(rgba, w, h) {
|
||||
const sig = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
|
||||
const ihdr = Buffer.alloc(13);
|
||||
ihdr.writeUInt32BE(w, 0);
|
||||
ihdr.writeUInt32BE(h, 4);
|
||||
ihdr[8] = 8; ihdr[9] = 6; ihdr[10] = 0; ihdr[11] = 0; ihdr[12] = 0;
|
||||
const stride = w * 4;
|
||||
const raw = Buffer.alloc((stride + 1) * h);
|
||||
for (let y = 0; y < h; y++) {
|
||||
raw[y * (stride + 1)] = 0;
|
||||
rgba.copy(raw, y * (stride + 1) + 1, y * stride, y * stride + stride);
|
||||
}
|
||||
const idat = zlib.deflateSync(raw, { level: 9 });
|
||||
return Buffer.concat([sig, chunk('IHDR', ihdr), chunk('IDAT', idat), chunk('IEND', Buffer.alloc(0))]);
|
||||
}
|
||||
|
||||
function makeICO(images) {
|
||||
const n = images.length;
|
||||
const header = Buffer.alloc(6);
|
||||
header.writeUInt16LE(0, 0);
|
||||
header.writeUInt16LE(1, 2);
|
||||
header.writeUInt16LE(n, 4);
|
||||
let offset = 6 + 16 * n;
|
||||
const entries = [];
|
||||
const datas = [];
|
||||
for (const im of images) {
|
||||
const e = Buffer.alloc(16);
|
||||
e[0] = im.w >= 256 ? 0 : im.w;
|
||||
e[1] = im.h >= 256 ? 0 : im.h;
|
||||
e[2] = 0; e[3] = 0;
|
||||
e.writeUInt16LE(1, 4);
|
||||
e.writeUInt16LE(32, 6);
|
||||
e.writeUInt32LE(im.png.length, 8);
|
||||
e.writeUInt32LE(offset, 12);
|
||||
entries.push(e);
|
||||
datas.push(im.png);
|
||||
offset += im.png.length;
|
||||
}
|
||||
return Buffer.concat([header, ...entries, ...datas]);
|
||||
}
|
||||
|
||||
function inRR(x, y, w, h, r) {
|
||||
if (x < r && y < r) return Math.hypot(r - x, r - y) <= r;
|
||||
if (x > w - 1 - r && y < r) return Math.hypot(w - 1 - r - x, r - y) <= r;
|
||||
if (x < r && y > h - 1 - r) return Math.hypot(r - x, h - 1 - r - y) <= r;
|
||||
if (x > w - 1 - r && y > h - 1 - r) return Math.hypot(w - 1 - r - x, h - 1 - r - y) <= r;
|
||||
return x >= 0 && y >= 0 && x < w && y < h;
|
||||
}
|
||||
|
||||
function inCapsule(x, y, x1, x2, cy, r) {
|
||||
const clampX = Math.max(x1, Math.min(x2, x));
|
||||
const dx = x - clampX;
|
||||
const dy = y - cy;
|
||||
return dx * dx + dy * dy <= r * r;
|
||||
}
|
||||
|
||||
function render(W) {
|
||||
const buf = Buffer.alloc(W * W * 4);
|
||||
const rad = W * 0.235;
|
||||
const A = [34, 211, 238];
|
||||
const B = [99, 102, 241];
|
||||
const bars = [
|
||||
{ x1: W * 0.30, x2: W * 0.74, cy: W * 0.40, r: W * 0.030 },
|
||||
{ x1: W * 0.22, x2: W * 0.80, cy: W * 0.515, r: W * 0.030 },
|
||||
{ x1: W * 0.36, x2: W * 0.70, cy: W * 0.63, r: W * 0.030 },
|
||||
];
|
||||
for (let y = 0; y < W; y++) {
|
||||
for (let x = 0; x < W; x++) {
|
||||
const i = (y * W + x) * 4;
|
||||
if (!inRR(x, y, W, W, rad)) {
|
||||
buf[i + 3] = 0;
|
||||
continue;
|
||||
}
|
||||
const t = (x + y) / (2 * (W - 1));
|
||||
let r = A[0] + (B[0] - A[0]) * t;
|
||||
let g = A[1] + (B[1] - A[1]) * t;
|
||||
let b = A[2] + (B[2] - A[2]) * t;
|
||||
let onBar = false;
|
||||
for (const bar of bars) {
|
||||
if (inCapsule(x, y, bar.x1, bar.x2, bar.cy, bar.r)) { onBar = true; break; }
|
||||
}
|
||||
if (onBar) { r = 255; g = 255; b = 255; }
|
||||
buf[i] = r | 0;
|
||||
buf[i + 1] = g | 0;
|
||||
buf[i + 2] = b | 0;
|
||||
buf[i + 3] = 255;
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
function downsampleAvg(buf, W, ss) {
|
||||
const size = W / ss;
|
||||
const out = Buffer.alloc(size * size * 4);
|
||||
for (let y = 0; y < size; y++) {
|
||||
for (let x = 0; x < size; x++) {
|
||||
let r = 0, g = 0, b = 0, a = 0;
|
||||
for (let dy = 0; dy < ss; dy++) {
|
||||
for (let dx = 0; dx < ss; dx++) {
|
||||
const i = ((y * ss + dy) * W + (x * ss + dx)) * 4;
|
||||
r += buf[i]; g += buf[i + 1]; b += buf[i + 2]; a += buf[i + 3];
|
||||
}
|
||||
}
|
||||
const n = ss * ss;
|
||||
const o = (y * size + x) * 4;
|
||||
out[o] = Math.round(r / n);
|
||||
out[o + 1] = Math.round(g / n);
|
||||
out[o + 2] = Math.round(b / n);
|
||||
out[o + 3] = Math.round(a / n);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function nearest(src, sw, sh, dw, dh) {
|
||||
const out = Buffer.alloc(dw * dh * 4);
|
||||
for (let y = 0; y < dh; y++) {
|
||||
for (let x = 0; x < dw; x++) {
|
||||
const sx = Math.min(sw - 1, Math.round((x * sw) / dw));
|
||||
const sy = Math.min(sh - 1, Math.round((y * sh) / dh));
|
||||
const si = (sy * sw + sx) * 4;
|
||||
const di = (y * dw + x) * 4;
|
||||
out[di] = src[si];
|
||||
out[di + 1] = src[si + 1];
|
||||
out[di + 2] = src[si + 2];
|
||||
out[di + 3] = src[si + 3];
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
const SS = 4;
|
||||
const BASE = 256;
|
||||
const hi = render(BASE * SS);
|
||||
const big = downsampleAvg(hi, BASE * SS, SS);
|
||||
const png256 = encodePNG(big, BASE, BASE);
|
||||
const png48 = encodePNG(nearest(big, BASE, BASE, 48, 48), 48, 48);
|
||||
const png32 = encodePNG(nearest(big, BASE, BASE, 32, 32), 32, 32);
|
||||
const png16 = encodePNG(nearest(big, BASE, BASE, 16, 16), 16, 16);
|
||||
const ico = makeICO([
|
||||
{ png: png256, w: 256, h: 256 },
|
||||
{ png: png48, w: 48, h: 48 },
|
||||
{ png: png32, w: 32, h: 32 },
|
||||
{ png: png16, w: 16, h: 16 },
|
||||
]);
|
||||
const outDir = path.join(__dirname, '..', 'build');
|
||||
fs.mkdirSync(outDir, { recursive: true });
|
||||
fs.writeFileSync(path.join(outDir, 'icon.ico'), ico);
|
||||
console.log('icon.ico written:', path.join(outDir, 'icon.ico'), ico.length, 'bytes');
|
||||
Reference in New Issue
Block a user