import { createHash } from 'node:crypto' import { existsSync } from 'node:fs' import { readFile, rename, writeFile } from 'node:fs/promises' import path from 'node:path' const TYPES = { png: 'image/png', jpg: 'image/jpeg', gif: 'image/gif', webp: 'image/webp', avif: 'image/avif', bmp: 'image/bmp', svg: 'image/svg+xml', } as const type ImageExtension = keyof typeof TYPES const FILE_NAME = /^[a-f0-9]{40}\.(png|jpg|gif|webp|avif|bmp|svg)$/ /** 根据文件头判断真实格式,不信任浏览器给的 Content-Type。 */ export function detectImageType(bytes: Uint8Array): ImageExtension | null { const ascii = (start: number, end: number) => String.fromCharCode(...bytes.subarray(start, end)) if (bytes.length < 12) return null if (bytes[0] === 0x89 && ascii(1, 4) === 'PNG') return 'png' if (bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff) return 'jpg' if (ascii(0, 4) === 'GIF8') return 'gif' if (ascii(0, 4) === 'RIFF' && ascii(8, 12) === 'WEBP') return 'webp' if (ascii(4, 8) === 'ftyp' && ['avif', 'avis'].includes(ascii(8, 12))) return 'avif' if (ascii(0, 2) === 'BM') return 'bmp' const head = new TextDecoder().decode(bytes.subarray(0, 1024)).trimStart().toLowerCase() if ((head.startsWith('