| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162 |
- // 从行业切图 PNG 取主色(支持全部 5 种扫描线滤波器;RGBA 8bit)
- import { readFileSync } from 'node:fs'
- import { inflateSync } from 'node:zlib'
- function pngColors(file) {
- const buf = readFileSync(file)
- let off = 8
- const idats = []
- let w = 0
- let h = 0
- let colorType = 6
- while (off < buf.length) {
- const len = buf.readUInt32BE(off)
- const type = buf.toString('ascii', off + 4, off + 8)
- if (type === 'IHDR') {
- w = buf.readUInt32BE(off + 8)
- h = buf.readUInt32BE(off + 12)
- colorType = buf[off + 17]
- }
- if (type === 'IDAT') idats.push(buf.slice(off + 8, off + 8 + len))
- off += 12 + len
- }
- const bpp = colorType === 6 ? 4 : colorType === 2 ? 3 : 4
- const raw = inflateSync(Buffer.concat(idats))
- const stride = w * bpp
- const recon = Buffer.alloc(h * stride)
- for (let y = 0; y < h; y += 1) {
- const filter = raw[y * (stride + 1)]
- const row = raw.slice(y * (stride + 1) + 1, y * (stride + 1) + 1 + stride)
- const prev = y > 0 ? recon.slice((y - 1) * stride, y * stride) : Buffer.alloc(stride)
- const cur = recon.slice(y * stride, (y + 1) * stride)
- for (let x = 0; x < stride; x += 1) {
- const a = x >= bpp ? cur[x - bpp] : 0
- const b = prev[x]
- const c = x >= bpp ? prev[x - bpp] : 0
- let val = row[x]
- if (filter === 1) val += a
- else if (filter === 2) val += b
- else if (filter === 3) val += Math.floor((a + b) / 2)
- else if (filter === 4) {
- const p = a + b - c
- const pa = Math.abs(p - a)
- const pb = Math.abs(p - b)
- const pc = Math.abs(p - c)
- val += pa <= pb && pa <= pc ? a : pb <= pc ? b : c
- }
- cur[x] = val & 0xff
- }
- }
- const colors = new Map()
- for (let i = 0; i < recon.length; i += bpp) {
- const alpha = bpp === 4 ? recon[i + 3] : 255
- if (alpha < 128) continue
- const key = `#${[recon[i], recon[i + 1], recon[i + 2]].map((v) => v.toString(16).padStart(2, '0')).join('')}`
- colors.set(key, (colors.get(key) || 0) + 1)
- }
- return [...colors.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5).map(([k, v]) => `${k}×${v}`).join(' ')
- }
- for (const f of ['industry-gas', 'industry-water', 'industry-drainage', 'manhole']) {
- console.log(`${f}: ${pngColors(`public/cockpit/assets/icons/${f}.png`)}`)
- }
|