You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
87 lines
2.8 KiB
87 lines
2.8 KiB
const { fabric } = require('fabric');
|
|
const nodeCanvas = require('canvas');
|
|
|
|
const { canvasToRgba } = require('./shared');
|
|
|
|
|
|
// Fabric is used as a fundament for compositing layers in editly
|
|
|
|
function fabricCanvasToRgba(canvas) {
|
|
// https://github.com/fabricjs/fabric.js/blob/26e1a5b55cbeeffb59845337ced3f3f91d533d7d/src/static_canvas.class.js
|
|
// https://github.com/fabricjs/fabric.js/issues/3885
|
|
const internalCanvas = fabric.util.getNodeCanvas(canvas.lowerCanvasEl);
|
|
const ctx = internalCanvas.getContext('2d');
|
|
|
|
// require('fs').writeFileSync(`${Math.floor(Math.random() * 1e12)}.png`, internalCanvas.toBuffer('image/png'));
|
|
// throw new Error('abort');
|
|
|
|
return canvasToRgba(ctx);
|
|
}
|
|
|
|
function createFabricCanvas({ width, height }) {
|
|
return new fabric.StaticCanvas(null, { width, height });
|
|
}
|
|
|
|
async function renderFabricCanvas(canvas) {
|
|
canvas.renderAll();
|
|
const rgba = fabricCanvasToRgba(canvas);
|
|
canvas.clear();
|
|
canvas.dispose();
|
|
return rgba;
|
|
}
|
|
|
|
async function rgbaToFabricImage({ width, height, rgba }) {
|
|
const canvas = nodeCanvas.createCanvas(width, height);
|
|
const ctx = canvas.getContext('2d');
|
|
// https://developer.mozilla.org/en-US/docs/Web/API/ImageData/ImageData
|
|
// https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/putImageData
|
|
ctx.putImageData(new nodeCanvas.ImageData(Uint8ClampedArray.from(rgba), width, height), 0, 0);
|
|
// https://stackoverflow.com/questions/58209996/unable-to-render-tiff-images-and-add-it-as-a-fabric-object
|
|
return new fabric.Image(canvas);
|
|
}
|
|
|
|
async function createFabricFrameSource(func, { width, height, ...rest }) {
|
|
const onInit = async () => func(({ width, height, fabric, ...rest }));
|
|
|
|
const { onRender = () => {}, onClose = () => {} } = await onInit() || {};
|
|
|
|
return {
|
|
renderFrame: onRender,
|
|
close: onClose,
|
|
};
|
|
}
|
|
|
|
async function createCustomCanvasFrameSource({ width, height, params }) {
|
|
const canvas = nodeCanvas.createCanvas(width, height);
|
|
const context = canvas.getContext('2d');
|
|
|
|
const { onClose, onRender } = await params.func(({ width, height, canvas }));
|
|
|
|
async function renderFrame(progress) {
|
|
context.clearRect(0, 0, canvas.width, canvas.height);
|
|
await onRender(progress);
|
|
// require('fs').writeFileSync(`${new Date().getTime()}.png`, canvas.toBuffer('image/png'));
|
|
// I don't know any way to draw a node-canvas as a layer on a fabric.js canvas, other than converting to rgba first:
|
|
return canvasToRgba(context);
|
|
}
|
|
|
|
return {
|
|
renderFrame,
|
|
// Node canvas needs no cleanup https://github.com/Automattic/node-canvas/issues/1216#issuecomment-412390668
|
|
close: onClose,
|
|
};
|
|
}
|
|
|
|
function registerFont(...args) {
|
|
fabric.nodeCanvas.registerFont(...args);
|
|
}
|
|
|
|
module.exports = {
|
|
registerFont,
|
|
createFabricFrameSource,
|
|
createCustomCanvasFrameSource,
|
|
|
|
createFabricCanvas,
|
|
renderFabricCanvas,
|
|
rgbaToFabricImage,
|
|
};
|