import {readFileSync} from 'node:fs'; import {createHash} from 'node:crypto'; import path from 'node:path'; export function sha256(value) { return createHash('sha256').update(value).digest('hex'); } export function imageFormat(bytes) { if (bytes.length >= 24 && bytes.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))) { return {mime: 'image/png', extension: 'png', width: bytes.readUInt32BE(16), height: bytes.readUInt32BE(20)}; } if (bytes.length >= 3 && bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) return {mime: 'image/jpeg', extension: 'jpg'}; if (bytes.length >= 12 && bytes.toString('ascii', 0, 4) === 'RIFF' && bytes.toString('ascii', 8, 12) === 'WEBP') return {mime: 'image/webp', extension: 'webp'}; throw new Error('图片数据不是支持的 PNG/JPEG/WebP 格式'); } export function readImage(file, {pngOnly = false} = {}) { const bytes = readFileSync(file); const format = imageFormat(bytes); if (pngOnly && (format.extension !== 'png' || !format.width || !format.height)) throw new Error('结构理解与局部画布当前要求非空 PNG 图片'); return {file: path.resolve(file), bytes, ...format, sha256: sha256(bytes)}; } export function dataUrl(image) { return `data:${image.mime};base64,${image.bytes.toString('base64')}`; }