How to recursively compress an image in js or jquery after cropping by Croppie.js

57 Views Asked by At

The user uploads an image and crops it using Croppie.js,

I compress the image recursively up to the size I define.

I create an img element, create a canvas with the img data, and lower the quality to 0.9 using canvas.toDataURL('image/jpeg', quality / 100);

The problem is that when the user crops the image to a circle, the image gets a black background outside the circle.

I understand that there is a problem with the format I set to 'image/jpeg', but only in this format can you set quality. I tried to change to 'image/png' format, but it doesn't work.

How can I do this without getting a black background?

This is the result I get

// After the user has cropped the image to circle

$('#modal-cropping-submit').on('click', function () {
    var points = $uploadCrop.croppie('get').points;
    var widthImage = parseInt(points[2]) - parseInt(points[0]);
    var heightImage = parseInt(points[3]) - parseInt(points[1]);

    $uploadCrop.croppie('result', {
        type: 'base64',
        size: 'original',
    }).then(function (resp) {
        var base64str = resp.substring(resp.indexOf(',') + 1);
        var sizeBytes = Math.ceil((base64str.length * (3 / 4)) - 2);
        if (sizeBytes > 52429) {  // 50kb
            compressFile(resp, 52429, 90, function (result) {
                base64str = result.substring(result.indexOf(',') + 1);

                //display the image in some element
                $('#src-img').css('backgroundImage', 'url(' + result + ')');
            });
        } else {
            //display the image in some element
            $('#src-img').css('backgroundImage', 'url(' + resp + ')');
        }
    });
});

function compressFile(sorce, maxsize, quality, callback) {
    const image = document.createElement('img');
    image.onload = () => {
        const canvas = document.createElement('canvas');
        canvas.width = image.width;
        canvas.height = image.height;
        canvas.getContext('2d').drawImage(image, 0, 0);
        var resp = canvas.toDataURL('image/jpeg', quality / 100);    //Here there is a problem
        var base64str = resp.substring(resp.indexOf(',') + 1);
        var sizeBytes = Math.ceil((base64str.length * (3 / 4)) - 2);
        if (sizeBytes > maxsize)
            compressFile(sorce, maxsize, quality - 10, callback);
        else
            callback(resp);
    }
    image.src = sorce;
}
1

There are 1 best solutions below

0
Nissim Elbaz On

Maybe this will help someone in the future,

I solved the problem by using the webp format.

I set the crop result to canvas in webp format.

And in the canvas.toDataURL('image/jpeg', quality / 100); function I changed to the 'image/webp' type, I understand that the webp format is good for use on websites.

I'm not sure if Safari browser supports this.

And I'm not sure what the implications of this format are.

This is the updated code:

// After the user has cropped the image to circle

$('#modal-cropping-submit').on('click', function () {
    var points = $uploadCrop.croppie('get').points;
    var widthImage = parseInt(points[2]) - parseInt(points[0]);
    var heightImage = parseInt(points[3]) - parseInt(points[1]);

    $uploadCrop.croppie('result', {
        type: 'canvas',
        size: 'original',
        format: 'webp'
    }).then(function (resp) {
        var base64str = resp.substring(resp.indexOf(',') + 1);
        var sizeBytes = Math.ceil((base64str.length * (3 / 4)) - 2);
        if (sizeBytes > 52429) {  // 50kb
            compressFile(resp, 52429, 90, function (result) {
                base64str = result.substring(result.indexOf(',') + 1);

                //display the image in some element
                $('#src-img').css('backgroundImage', 'url(' + result + ')');
            });
        } else {
            //display the image in some element
            $('#src-img').css('backgroundImage', 'url(' + resp + ')');
        }
    });
});

function compressFile(sorce, maxsize, quality, callback) {
    const image = document.createElement('img');
    image.onload = () => {
        const canvas = document.createElement('canvas');
        canvas.width = image.width;
        canvas.height = image.height;
        canvas.getContext('2d').drawImage(image, 0, 0);
        var resp = canvas.toDataURL('image/webp', quality / 100);
        var base64str = resp.substring(resp.indexOf(',') + 1);
        var sizeBytes = Math.ceil((base64str.length * (3 / 4)) - 2);
        if (sizeBytes > maxsize)
            compressFile(sorce, maxsize, quality - 10, callback);
        else
            callback(resp);
    }
    image.src = sorce;
}

I would love to know if there are any mistakes or comments on the answer I wrote, or information I need to know about this format.