Search code examples
resolutionfabricjs

Fabricjs resize loses resolution


I have a website and there is one part of it where the person can upload an image and resize this image. To change the size of the image is used the Fabricjs (http://fabricjs.com/).

The problem is when the image is resized it loses resolution, it appears very ugly after changing size. Here is the code used to accomplish that:

function addImage(imgSrc, img_name, colorArr)
{
    console.log("add image call")
    var splitArr = colorArr.split(",");

    show_image();
    jQuery("#img_name").html(img_name);

   fabric.Image.fromURL(imgSrc, function (img) {
             var theScaleFactor=getScaleFactor(img.width,img.height,parseInt(jQuery(".canvas-container").css("width")),parseInt(jQuery(".canvas-container").css("height")));                               
            img.set({
                left : 0,
                top : 0,
                id:'redux',
                orig_name:img_name,
                imgColor:colorArr
            }).scale(theScaleFactor.scale).setCoords(); //HERE THE IMAGE IS DECREASED/RESIZED
            canvas.add(img);

            //console.log("wt = "+img.get('width')+" ht = "+img.get('height')+" scale = "+theScaleFactor.scale)
            img.set({left:((canvas.getWidth()/2) - (parseInt(img.get('width'))*theScaleFactor.scale)/2), top:(45-(parseInt(img.get('height')*theScaleFactor.scale)/2))});

            canvas.setActiveObject(img);
            canvas.renderAll();
            countColors();

    });
    jQuery("#dropbox").hide();
    jQuery(".preloader").hide();

}

I found this link and tried to reduce the image's size gradually, but it didn't work. I tried this way:

img.set({
    left : 0,
    top : 0,
    id:'redux',
    orig_name:img_name,
    imgColor:colorArr
});

img.scale(0.5);
img.scale(0.5);
img.scale(0.5);
img.scale(0.5);
img.scale(0.5);
img.scale(0.5);
img.scale(0.5);
img.scale(0.5);
img.setCoords();
canvas.add(img);

I found this link too and tried to reduce image's size like below, but it didn't work as well:

 img.set({
    left : 0,
    top : 0,
    id:'redux',
    orig_name:img_name,
    imgColor:colorArr
    });

    img.filters.push(new fabric.Image.filters.Resize({scaleX: 0.2, scaleY: 0.2}));                        
    img.applyFilters(canvas.renderAll.bind(canvas)).setCoords();
    canvas.add(img);

I hope someone can help. I appreciate any help.

===============================

UPDATE with answer:

This way it worked:

fabric.Image.fromURL(imgSrc, function (img) {
    var theScaleFactor = getScaleFactor(img.width,img.height,parseInt(jQuery(".canvas-container").css("width")),parseInt(jQuery(".canvas-container").css("height")));
    img.set({
        left : 0,
        top : 0,
        id:'redux',
        orig_name:img_name,
        imgColor:colorArr
    });//.scale(theScaleFactor.scale).setCoords();

    img.filters.push( new fabric.Image.filters.Resize( { resizeType: 'sliceHack', scaleX: theScaleFactor.scale, scaleY: theScaleFactor.scale } ) );
    img.applyFilters();
    img.setCoords();

    canvas.add(img);

    //console.log("wt = "+img.get('width')+" ht = "+img.get('height')+" scale = "+theScaleFactor.scale)
    img.set({left:((canvas.getWidth()/2) - (parseInt(img.get('width'))*theScaleFactor.scale)/2), top:(45-(parseInt(img.get('height')*theScaleFactor.scale)/2))});

    canvas.setActiveObject(img);
    canvas.renderAll();
    countColors();
});

jQuery("#dropbox").hide();
jQuery(".preloader").hide();
}

Solution

  • The image does not lose resolution, the ugly effect you notice is from the "nearest neighbour" resize algorithm that the canvas uses.

    To solve this, fabricJS implemented a resize filter class that allows you to use 'bilinear', 'hermite', 'lanczos' or this 'sliceHack' you quoted.

    The filter can be applied one time at loading or during every manual resize.

    regarding your tries, take note that fabricJS does not scale the image when you call image.scale(0.5), but just on rendering.

    So calling image.scale() multiple time does not have any effect. The image is scaled by the internal property scaleX and scaleY once at rendering time.