javascriptcanvasfabricjstodataurl

How to disable smoothing of images in Fabric.js when toDataUrl() is called?


Is it possible to disable smoothing of images within the canvas of Fabric.js when I export the canvas with toDataUrl()? I'm using version 3.6.2.

I have created the canvas with this code:

const canvas = new fabric.Canvas('canvas-1', {
    imageSmoothingEnabled: false
});

imageSmoothingEnabled turns off the smoothing in the canvas. However, when I call toDataUrl() with an multiplier and I show the result in an img, the smoothing is still there and it was also multiplied.

const dataUrl = canvas.toDataURL({format: 'png', multiplier: 3});
$imgageElement.attr('src', dataUrl); //jQuery

What do I have to do so that I get exactly what is displayed in the canvas?

Here is a fiddle. And here is report, since I think it is a bug.


Solution

  • One workaround seems to be overriding toCanvasElement with:

    const canvas = new fabric.Canvas('canvas-1', {
        imageSmoothingEnabled: false
    });
    
    canvas.toCanvasElement = function (multiplier, cropping) {
        multiplier               = multiplier || 1;
        cropping                 = cropping || {};
        var scaledWidth          = (cropping.width || this.width) * multiplier,
            scaledHeight         = (cropping.height || this.height) * multiplier,
            zoom                 = this.getZoom(),
            originalWidth        = this.width,
            originalHeight       = this.height,
            newZoom              = zoom * multiplier,
            vp                   = this.viewportTransform,
            translateX           = (vp[4] - (cropping.left || 0)) * multiplier,
            translateY           = (vp[5] - (cropping.top || 0)) * multiplier,
            originalInteractive  = this.interactive,
            newVp                = [newZoom, 0, 0, newZoom, translateX, translateY],
            originalRetina       = this.enableRetinaScaling,
            canvasEl             = fabric.util.createCanvasElement(),
            originalContextTop   = this.contextTop;
        canvasEl.width           = scaledWidth;
        canvasEl.height          = scaledHeight;
        this.contextTop          = null;
        this.enableRetinaScaling = false;
        this.interactive         = false;
        this.viewportTransform   = newVp;
        this.width               = scaledWidth;
        this.height              = scaledHeight;
        this.calcViewportBoundaries();
        var ctx                   = canvasEl.getContext('2d');    // replaced
        ctx.imageSmoothingEnabled = false;                        // this.renderCanvas(canvasEl.getContext('2d'), this._objects);
        this.renderCanvas(ctx, this._objects);                    // with these 3 lines
        this.viewportTransform = vp;
        this.width             = originalWidth;
        this.height            = originalHeight;
        this.calcViewportBoundaries();
        this.interactive         = originalInteractive;
        this.enableRetinaScaling = originalRetina;
        this.contextTop          = originalContextTop;
        return canvasEl;
    };