import { PNG } from 'pngjs'; import { frameRect } from './frames.mjs'; /** * PNG 切分与重组。见 spec §4.2 ②。 * 切分是可逆操作,故「重组(切分(原图)) 的像素 === 原图像素」是对全部帧的完全验证。 */ /** 切分整图 → 帧 Buffer 数组,下标 0 对应帧 1。 */ export function splitSheet(sheetBuffer, image) { const sheet = PNG.sync.read(sheetBuffer); const out = []; for (let i = 1; i <= image.frame_all; i++) { const r = frameRect(image, i); const cell = new PNG({ width: r.width, height: r.height }); PNG.bitblt(sheet, cell, r.x, r.y, r.width, r.height, 0, 0); out.push(PNG.sync.write(cell)); } return out; } /** 把帧按原网格拼回整图。 */ export function reassemble(frameBuffers, image) { const sheet = new PNG({ width: image.w * image.w1, height: image.h * image.h1 }); frameBuffers.forEach((buf, i) => { const r = frameRect(image, i + 1); const cell = PNG.sync.read(buf); PNG.bitblt(cell, sheet, 0, 0, r.width, r.height, r.x, r.y); }); return PNG.sync.write(sheet); } /** * 比较两张 PNG 的**解码像素数据**。 * 不能比较文件字节——编码参数不同会让同像素的图产生不同字节。 */ export function pixelsEqual(bufA, bufB) { const a = PNG.sync.read(bufA); const b = PNG.sync.read(bufB); if (a.width !== b.width || a.height !== b.height) return false; return Buffer.compare(a.data, b.data) === 0; } /** 对一张多帧图做重组校验。 */ export function verifySheet(sheetBuffer, image) { const sheet = PNG.sync.read(sheetBuffer); const expectW = image.w * image.w1; const expectH = image.h * image.h1; if (sheet.width !== expectW || sheet.height !== expectH) { return { ok: false, reason: `尺寸不符: 实际 ${sheet.width}x${sheet.height},按网格应为 ${expectW}x${expectH}`, }; } const back = reassemble(splitSheet(sheetBuffer, image), image); if (!pixelsEqual(sheetBuffer, back)) { return { ok: false, reason: '重组后像素与原图不一致(切分逻辑有误)' }; } return { ok: true }; }