Files
wanghu 25147ec74e
build / build-push (push) Successful in 50s
commit
2026-10-10 15:42:52 +08:00

64 lines
2.5 KiB
JavaScript

import fs from "node:fs";
import zlib from "node:zlib";
const file = process.argv[2];
const buf = fs.readFileSync(file);
// ---- 解析 PNG ----
let pos = 8;
let W = 0, H = 0, bitDepth = 0, colorType = 0, idat = [];
while (pos < buf.length) {
const len = buf.readUInt32BE(pos);
const type = buf.toString("ascii", pos + 4, pos + 8);
const data = buf.subarray(pos + 8, pos + 8 + len);
if (type === "IHDR") {
W = data.readUInt32BE(0); H = data.readUInt32BE(4);
bitDepth = data[8]; colorType = data[9];
} else if (type === "IDAT") idat.push(data);
else if (type === "IEND") break;
pos += 12 + len;
}
console.log(`size=${W}x${H} bitDepth=${bitDepth} colorType=${colorType}`);
const raw = zlib.inflateSync(Buffer.concat(idat));
const ch = colorType === 6 ? 4 : colorType === 2 ? 3 : colorType === 0 ? 1 : 0;
if (!ch || bitDepth !== 8) { console.log("unsupported format"); process.exit(0); }
const stride = W * ch;
const px = Buffer.alloc(H * stride);
// ---- 反 filter ----
let p = 0;
for (let y = 0; y < H; y++) {
const ft = raw[p++];
const line = raw.subarray(p, p + stride); p += stride;
const cur = px.subarray(y * stride, (y + 1) * stride);
const prev = y > 0 ? px.subarray((y - 1) * stride, y * stride) : null;
for (let x = 0; x < stride; x++) {
const a = x >= ch ? cur[x - ch] : 0;
const b = prev ? prev[x] : 0;
const c = prev && x >= ch ? prev[x - ch] : 0;
let v = line[x];
if (ft === 1) v += a;
else if (ft === 2) v += b;
else if (ft === 3) v += (a + b) >> 1;
else if (ft === 4) {
const pa = Math.abs(b - c), pb = Math.abs(a - c), pc = Math.abs(a + b - 2 * c);
v += (pa <= pb && pa <= pc) ? a : (pb <= pc ? b : c);
}
cur[x] = v & 255;
}
}
const at = (x, y) => { const o = (y * W + x) * ch; return [px[o], px[o + 1], px[o + 2]]; };
const near = (c, t, tol) => Math.abs(c[0]-t[0])<=tol && Math.abs(c[1]-t[1])<=tol && Math.abs(c[2]-t[2])<=tol;
// ---- 直方图:统计出现最多的颜色 ----
const hist = new Map();
for (let y = 0; y < H; y += 2) for (let x = 0; x < W; x += 2) {
const c = at(x, y); const k = `${c[0]},${c[1]},${c[2]}`;
hist.set(k, (hist.get(k) || 0) + 1);
}
const top = [...hist.entries()].sort((a, b) => b[1] - a[1]).slice(0, 12);
console.log("主色 Top12(含占比):");
for (const [k, v] of top) console.log(` #${k.split(",").map(n=>Number(n).toString(16).padStart(2,"0")).join("")} ${(v/((W/2)*(H/2))*100).toFixed(1)}% (${k})`);
fs.writeFileSync(process.argv[3] || "png-px.bin", Buffer.from(px));