Search code examples
javascriptreactjsimagecanvasfabricjs

Fabric JS setting fill on an image is not working


I am trying to set fill on an image using Fabric JS.

To demonstrate my problem I refer to the Kitchensink demo on fabricjs.com http://fabricjs.com/kitchensink

On the image below I am trying to fill the image with a green color RGB(69,242,81) but when I set the color, nothing happens. Are there any workaround to this issue?

I have had a look at floodFilling but that is unfortunately too performance heavy for my use case.

Thanks!

enter image description here

Possible Solution

I might have found a possible solution when playing around with this demo: `http://fabricjs.com/image-filters`

I select an object and choose the mode tint and increase the alpha to maximum (see image below)

enter image description here

And I get the desired result (see image below) Is there anything wrong with using this approach?

enter image description here


Solution

  • Fill isn't currently a recognized property for images. One reason for this is because drawing a solid color behind an image that isn't transparent causes that color to appear along the edges of an image. Since the image class inherits the default fill color of rgb(0,0,0) (black) from the Object class, that would mean that every image would have an outline like this, unless the fill color is manually changed to transparent.

    outline example

    If however you really want your images to respect the fill property, you can do this with a simple override to the _renderFill method of the Image class. Just be sure to set the fill of any images that don't need a background color to transparent.

    fabric.Image.prototype._renderFill = function(ctx) {
          var elementToDraw = this._element;
          if (!elementToDraw) {
            return;
          }
          var scaleX = this._filterScalingX, scaleY = this._filterScalingY,
              w = this.width, h = this.height, min = Math.min, max = Math.max,
              // crop values cannot be lesser than 0.
              cropX = max(this.cropX, 0), cropY = max(this.cropY, 0),
              elWidth = elementToDraw.naturalWidth || elementToDraw.width,
              elHeight = elementToDraw.naturalHeight || elementToDraw.height,
              sX = cropX * scaleX,
              sY = cropY * scaleY,
              // the width height cannot exceed element width/height, starting from the crop offset.
              sW = min(w * scaleX, elWidth - sX),
              sH = min(h * scaleY, elHeight - sY),
              x = -w / 2, y = -h / 2,
              maxDestW = min(w, elWidth / scaleX - cropX),
              maxDestH = min(h, elHeight / scaleY - cropY);
              
          //fill override start
          ctx.beginPath();
          ctx.rect(x, y, sW, sH);
          ctx.fill();
          //fill override end
              
          elementToDraw && ctx.drawImage(elementToDraw, sX, sY, sW, sH, x, y, maxDestW, maxDestH);
        };
    

    Fill example