56 lines
1.8 KiB
JavaScript
56 lines
1.8 KiB
JavaScript
"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 });
|
||
})();
|