Caylan Van Larson
Caylan Van Larson

Reputation: 41

FabricJS image filter with no fragmentSource?

I have a filter that isn't compatible with WebGL. Is there a way to skip writing a fragmentSource? I tried overriding fabric.Image.filters.BaseFilter applyTo on the filter subclass to only call this.applyTo2d(options); but I'm not getting any image data.

applyTo: function(options) {
    if (options.webgl) {
      if (options.passes > 1 && this.isNeutralState(options)) {
        // avoid doing something that we do not need
        return;
      }
      this._setupFrameBuffer(options);
      this.applyToWebGL(options);
      this._swapTextures(options);
    }
    else if (!this.isNeutralState()) {
      this.applyTo2d(options);
    }
  },

Upvotes: 1

Views: 454

Answers (1)

Caylan Van Larson
Caylan Van Larson

Reputation: 41

I as able to accomplish this in a non-optimized way with minimal code in webgl_backend.class.js.

First, the webgl backend needs a fallback for non-webgl filters:

this.fallback2dBackend = new fabric.Canvas2dFilterBackend();

Then, instead of running all filters: fabric.filterBackend.applyFilters(filters, this._originalElement, sourceWidth, sourceHeight, this._element, this.cacheKey);

Do this:

  var newSource = fabric.util.createCanvasElement();
  newSource.width = sourceWidth;
  newSource.height = sourceHeight;
  var newSourceCtx = newSource.getContext('2d');
  newSourceCtx.drawImage(this._originalElement, 0, 0, sourceWidth, sourceHeight);

  filters.forEach(function(filter) {
    if (!filter) {
      return;
    }
    var backend = fabric.filterBackend;
    if (filter.fragmentSource === null) {
      backend = backend.fallback2dBackend;
    }

    backend.applyFilters(
      [filter], newSource, sourceWidth, sourceHeight, this._element);

    newSourceCtx.clearRect(0, 0, sourceWidth, sourceHeight);
    newSourceCtx.drawImage(this._element, 0, 0, sourceWidth, sourceHeight);

  }, this);

I've published a fork in case someone wants to refactor this into a PR.

Upvotes: 1

Related Questions