illustrator.js
Version:
JavaScript image processing library
104 lines (103 loc) • 4.38 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ImageLoader = void 0;
const canvas_1 = require("@napi-rs/canvas");
const fs = require("fs");
const http = require("http");
const https = require("https");
const stream_1 = require("stream");
const Illustrator_1 = require("../illustrator/Illustrator");
const IllustratorImage_1 = require("./IllustratorImage");
const Layer_1 = require("../layer/Layer");
const isBufferLike = require("is-buffer-like");
const REDIRECT_STATUSES = new Set([301, 302]);
function createImage(source, bufferOnly = false) {
if (bufferOnly)
return source;
const image = new canvas_1.Image();
image.src = source;
return image;
}
// TODO: use stream/consumers for this?
function consumeStream(stream) {
return new Promise((resolve, reject) => {
const body = [];
stream.on("data", (chunk) => body.push(chunk));
stream.on("end", () => resolve(Buffer.concat(body)));
stream.on("error", (err) => reject(err));
});
}
function makeRequest(link, redirectCount, resolve, reject) {
const url = typeof link === "string" ? new URL(link) : link;
const reqBy = url.protocol === "http:" ? http : https;
reqBy.get(url, (res) => {
const shouldRedirect = REDIRECT_STATUSES.has(res.statusCode) && typeof res.headers.location === "string";
if (shouldRedirect && redirectCount > 0)
return makeRequest(res.headers.location, redirectCount - 1, resolve, reject);
if (typeof res.statusCode === "number" && (res.statusCode < 200 || res.statusCode >= 300)) {
return reject(new Error(`request for the given image source rejected with status code "${res.statusCode}"`));
}
consumeStream(res).then(resolve, reject);
});
}
function httpReq(link) {
return new Promise((resolve, reject) => makeRequest(link, 20, resolve, reject));
}
class ImageLoader extends null {
constructor() {
/* no-op */
}
static async loadImage(source, bufferOnly) {
if (source instanceof stream_1.Readable)
return createImage(await consumeStream(source), bufferOnly);
if (Buffer.isBuffer(source))
return createImage(source, bufferOnly);
// @ts-expect-error
if (isBufferLike(source))
return createImage(Buffer.from(source), bufferOnly);
if (source instanceof canvas_1.Image)
return createImage(source.src, bufferOnly);
if (source instanceof canvas_1.Canvas)
return createImage(await source.encode("png"), bufferOnly);
if (source instanceof Layer_1.Layer)
return createImage(await (await source.render()).encode("png"), bufferOnly);
if (source instanceof Illustrator_1.Illustrator)
return createImage(await source.export(), bufferOnly);
if (source instanceof IllustratorImage_1.IllustratorImage)
return createImage(await source.png(), bufferOnly);
if (source instanceof canvas_1.ImageData) {
const img = await IllustratorImage_1.IllustratorImage.fromImageData(source);
return createImage(await img.png(), bufferOnly);
}
if ((typeof source === "string" || source instanceof URL) && fs.existsSync(source)) {
const data = await fs.promises.readFile(source);
return createImage(data, bufferOnly);
}
if (typeof source === "string" || source instanceof URL) {
if (typeof fetch === "function") {
const ab = await fetch(source, {
method: "GET",
redirect: "follow"
}).then((res) => {
if (!res.ok)
throw new Error(`request for image source rejected with status code "${res.status}"`);
return res.arrayBuffer();
});
return createImage(Buffer.from(ab), bufferOnly);
}
else {
const res = await httpReq(source);
return createImage(res, bufferOnly);
}
}
throw new TypeError("Unsupported source type");
}
/**
* Creates `Image` instance
* @param data The image source data
*/
static createImage(data) {
return createImage(data, false);
}
}
exports.ImageLoader = ImageLoader;