"use strict"; // DuskPNG – PNG export using pngjs (window.PNG) // Falls back to canvas.toBlob if pngjs is unavailable. const DuskPNG = (() => { function _pngAvailable() { return typeof PNG !== "undefined" && PNG.sync && typeof PNG.sync.write === "function"; } // Encode RGBA pixel data into a PNG Buffer via pngjs. // Returns a Uint8Array (Buffer) if pngjs is available, otherwise null. function encode(width, height, rgbaData) { if(!_pngAvailable()) return null; const png = new PNG({ width, height }); const src = rgbaData instanceof Uint8ClampedArray ? rgbaData : new Uint8ClampedArray(rgbaData); for(let i = 0; i < src.length; i++) { png.data[i] = src[i]; } return PNG.sync.write(png); // returns a Buffer (Uint8Array subclass) } // Trigger a browser download of the RGBA data as a PNG file. function download(filename, width, height, rgbaData) { const buf = encode(width, height, rgbaData); if(buf) { // pngjs path const blob = new Blob([buf], { type: "image/png" }); _triggerDownload(URL.createObjectURL(blob), filename); } else { // Canvas fallback const canvas = Object.assign(document.createElement("canvas"), { width, height }); const ctx = canvas.getContext("2d"); const src = rgbaData instanceof Uint8ClampedArray ? rgbaData : new Uint8ClampedArray(rgbaData); ctx.putImageData(new ImageData(src, width, height), 0, 0); canvas.toBlob(blob => _triggerDownload(URL.createObjectURL(blob), filename), "image/png"); } } function _triggerDownload(url, filename) { const a = Object.assign(document.createElement("a"), { href: url, download: filename }); a.click(); URL.revokeObjectURL(url); } return Object.freeze({ encode, download }); })();