diff --git a/src/Factory.ts b/src/Factory.ts index e5002957..daadeba5 100644 --- a/src/Factory.ts +++ b/src/Factory.ts @@ -166,5 +166,6 @@ export const Factory = { }, afterSetFilter(this: Node) { this._filterUpToDate = false; + this._filter2UpToDate = false; }, }; diff --git a/src/Node.ts b/src/Node.ts index 98a2f1ee..898d79e9 100644 --- a/src/Node.ts +++ b/src/Node.ts @@ -16,6 +16,10 @@ import { Shape } from './Shape'; import { Layer } from './Layer'; export type Filter = (this: Node, imageData: ImageData) => void; +/**### A combination of HTMLCanvas adn OffscreenCanvas */ +export type LegalCanvas = HTMLCanvasElement | OffscreenCanvas; +/**### different from Filter, which is use canvas instead of imageData */ +export type Filter2 = (this: Node, canvas: LegalCanvas) => LegalCanvas; type globalCompositeOperationType = | '' @@ -156,6 +160,8 @@ export abstract class Node { _needClearTransformCache = false; _filterUpToDate = false; + /** update signature for filter2 */ + _filter2UpToDate = false; _isUnderCache = false; nodeType!: string; className!: string; @@ -389,6 +395,7 @@ export abstract class Node { this._cache.delete(CANVAS); this._filterUpToDate = false; + this._filter2UpToDate = false; if (conf.imageSmoothingEnabled === false) { cachedSceneCanvas.getContext()._context.imageSmoothingEnabled = false; @@ -571,6 +578,7 @@ export abstract class Node { imageData, n, filter; + const filter2s = this.filter2s() if (filters) { if (!this._filterUpToDate) { @@ -625,6 +633,44 @@ export abstract class Node { return filterCanvas; } + if (filter2s && filter2s.length > 0) { + if (!this._filter2UpToDate) { + var ratio = sceneCanvas.pixelRatio; + filterCanvas.setSize( + sceneCanvas.width / sceneCanvas.pixelRatio, + sceneCanvas.height / sceneCanvas.pixelRatio + ); + try { + len = filter2s.length; + filterContext.clear(); + + // copy cached canvas onto filter context + filterContext.drawImage( + sceneCanvas._canvas, + 0, + 0, + sceneCanvas.getWidth() / ratio, + sceneCanvas.getHeight() / ratio + ); + let currentCanvas = filterCanvas._canvas; + for (n = 0; n < len; n++) { + currentCanvas = filter2s[n].call(this, currentCanvas); + } + filterContext.clearRect(0, 0, filterCanvas.getWidth(), filterCanvas.getHeight()); + filterContext.drawImage(currentCanvas, 0, 0); + } catch (e: any) { + Util.error( + 'Unable to apply filter. ' + + e.message + + ' This post my help you https://konvajs.org/docs/posts/Tainted_Canvas.html.' + ); + } + + this._filter2UpToDate = true; + } + + return filterCanvas; + } return sceneCanvas; } /** @@ -2644,6 +2690,7 @@ export abstract class Node { embossWhiteLevel: GetSet; enhance: GetSet; filters: GetSet; + filter2s: GetSet; position: GetSet; absolutePosition: GetSet; size: GetSet<{ width: number; height: number }, this>; @@ -3197,6 +3244,11 @@ addGetterSetter(Node, 'filters', null, function (this: Node, val) { this._filterUpToDate = false; return val; }); + +addGetterSetter(Node, 'filter2s', null, function (this: Node, val) { + this._filter2UpToDate = false; + return val; +}); /** * get/set filters. Filters are applied to cached canvases * @name Konva.Node#filters diff --git a/src/Util.ts b/src/Util.ts index 94102d64..6bf72582 100644 --- a/src/Util.ts +++ b/src/Util.ts @@ -512,6 +512,15 @@ export const Util = { } catch (e) {} return canvas; }, + createOffScreenCanvas(size: { width: number; height: number }) { + if (window.OffscreenCanvas !== undefined) { + return new OffscreenCanvas(size.width, size.height); + } + const canvas = this.createCanvasElement(); + canvas.width = size.width; + canvas.height = size.height; + return canvas; + } createImageElement() { return document.createElement('img'); },