fabric
Version:
Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.
66 lines (63 loc) • 2.38 kB
text/typescript
/**
* Canvas 2D filter backend.
*/
import type { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TPipelineResources } from './typedefs';
export class Canvas2dFilterBackend {
/**
* Experimental. This object is a sort of repository of help layers used to avoid
* of recreating them during frequent filtering. If you are previewing a filter with
* a slider you probably do not want to create help layers every filter step.
* in this object there will be appended some canvases, created once, resized sometimes
* cleared never. Clearing is left to the developer.
**/
resources: TPipelineResources = {};
/**
* Apply a set of filters against a source image and draw the filtered output
* to the provided destination canvas.
*
* @param {EnhancedFilter} filters The filter to apply.
* @param {HTMLImageElement|HTMLCanvasElement} sourceElement The source to be filtered.
* @param {Number} sourceWidth The width of the source input.
* @param {Number} sourceHeight The height of the source input.
* @param {HTMLCanvasElement} targetCanvas The destination for filtered output to be drawn.
*/
applyFilters(
filters: BaseFilter<string, Record<string, any>>[],
sourceElement: CanvasImageSource,
sourceWidth: number,
sourceHeight: number,
targetCanvas: HTMLCanvasElement,
): T2DPipelineState | void {
const ctx = targetCanvas.getContext('2d');
if (!ctx) {
return;
}
ctx.drawImage(sourceElement, 0, 0, sourceWidth, sourceHeight);
const imageData = ctx.getImageData(0, 0, sourceWidth, sourceHeight);
const originalImageData = ctx.getImageData(0, 0, sourceWidth, sourceHeight);
const pipelineState: T2DPipelineState = {
sourceWidth,
sourceHeight,
imageData,
originalEl: sourceElement,
originalImageData,
canvasEl: targetCanvas,
ctx,
filterBackend: this,
};
filters.forEach((filter) => {
filter.applyTo(pipelineState);
});
const { imageData: imageDataPostFilter } = pipelineState;
if (
imageDataPostFilter.width !== sourceWidth ||
imageDataPostFilter.height !== sourceHeight
) {
targetCanvas.width = imageDataPostFilter.width;
targetCanvas.height = imageDataPostFilter.height;
}
ctx.putImageData(imageDataPostFilter, 0, 0);
return pipelineState;
}
}