import { preprocessors, codecs as supportedFormats } from "./codecs.js"; import ImageData from "./image_data.js"; const DELAY_MS = 1e3; let _promise; function delayOnce(ms) { if (!_promise) { _promise = new Promise((resolve) => { setTimeout(resolve, ms); }); } return _promise; } function maybeDelay() { const isAppleM1 = process.arch === "arm64" && process.platform === "darwin"; if (isAppleM1) { return delayOnce(DELAY_MS); } return Promise.resolve(); } async function decodeBuffer(_buffer) { const buffer = Buffer.from(_buffer); const firstChunk = buffer.slice(0, 16); const firstChunkString = Array.from(firstChunk).map((v) => String.fromCodePoint(v)).join(""); if (firstChunkString.includes("GIF")) { throw Error(`GIF images are not supported, please use the Sharp image service`); } const key = Object.entries(supportedFormats).find( ([, { detectors }]) => detectors.some((detector) => detector.exec(firstChunkString)) )?.[0]; if (!key) { throw Error(`Buffer has an unsupported format`); } const encoder = supportedFormats[key]; const mod = await encoder.dec(); const rgba = mod.decode(new Uint8Array(buffer)); return rgba; } async function rotate(image, numRotations) { image = ImageData.from(image); const m = await preprocessors["rotate"].instantiate(); return await m(image.data, image.width, image.height, { numRotations }); } async function resize({ image, width, height }) { image = ImageData.from(image); const p = preprocessors["resize"]; const m = await p.instantiate(); await maybeDelay(); return await m(image.data, image.width, image.height, { ...p.defaultOptions, width, height }); } async function encodeJpeg(image, opts) { image = ImageData.from(image); const e = supportedFormats["mozjpeg"]; const m = await e.enc(); await maybeDelay(); const quality = opts.quality || e.defaultEncoderOptions.quality; const r = await m.encode(image.data, image.width, image.height, { ...e.defaultEncoderOptions, quality }); return r; } async function encodeWebp(image, opts) { image = ImageData.from(image); const e = supportedFormats["webp"]; const m = await e.enc(); await maybeDelay(); const quality = opts.quality || e.defaultEncoderOptions.quality; const r = await m.encode(image.data, image.width, image.height, { ...e.defaultEncoderOptions, quality }); return r; } async function encodeAvif(image, opts) { image = ImageData.from(image); const e = supportedFormats["avif"]; const m = await e.enc(); await maybeDelay(); const val = e.autoOptimize.min; const quality = opts.quality || 75; const r = await m.encode(image.data, image.width, image.height, { ...e.defaultEncoderOptions, // Think of cqLevel as the "amount" of quantization (0 to 62), // so a lower value yields higher quality (0 to 100). cqLevel: quality === 0 ? val : Math.round(val - quality / 100 * val) }); return r; } async function encodePng(image) { image = ImageData.from(image); const e = supportedFormats["oxipng"]; const m = await e.enc(); await maybeDelay(); const r = await m.encode(image.data, image.width, image.height, { ...e.defaultEncoderOptions }); return r; } export { decodeBuffer, encodeAvif, encodeJpeg, encodePng, encodeWebp, resize, rotate };