Home > Back-end >  Reduce File Size Of An Image In A File Upload Preview, Without Affecting The Size Of The File To Be
Reduce File Size Of An Image In A File Upload Preview, Without Affecting The Size Of The File To Be

Time:10-23

I have some image preview functionality as part of a file uploader that shows the images prior to upload. Within this process the image previews use a htmlImageElement.decode() method that returns a promise so various frontend validations etc can happen on the images. This decode() method is run within a function that is called in a forEach() loop in relation to the files from a file <input> element.

The context

Even though I am limiting the number of files per upload to 10, because large files are allowed, if a user attaches 10 (large) files the image previewer is laggy, both in terms of image render, and also when any images are deleted from the previewer.

The Question

Is there anyway to reduce the file size of the image preview, without affecting the file size of the image to be uploaded?

You can add width and height parameters to the new Image() constructor, i.e. new Image(300,300), but these only affect the display size, not the file size, and if you alter the naturalHeight and naturalWidth properties, this changes the size of the file itself that is being uploaded, whereas what I want is just the preview file size to be smaller?

// this function is invoked in a forEach loop as part of a wider code block related to the individual files from a file <input> element

function showFiles(file) {

    let previewImage = new Image();

    // Set <img> src attribute
    previewImage.src = URL.createObjectURL(file);

    // get the original width and height values of the thumbnail using the decode() method
    previewImage.decode().then((response) => {

        // get image dimensions for validations
        let w = previewImage.naturalWidth;
        let h = previewImage.naturalHeight;

        let imgs = document.querySelectorAll('img') // redeclare under new var name inside promise

    }).catch((encodingError) => {
        // Do something with the error.
    });

} // end of showfiles(file)

CodePudding user response:

A canvas can be used to create a resized clone of the original image, then use the canvas blob as source for preview:

// this function is invoked in a forEach loop as part of a wider code block related to the individual files from a file <input> element

function showFiles(file) {

    let previewImage = new Image();

    // Set <img> src attribute
    previewImage.src = URL.createObjectURL(file);

    // get the original width and height values of the thumbnail using the decode() method
    previewImage.decode().then(() => {

        // get image dimensions for validations
        let w = previewImage.naturalWidth;
        let h = previewImage.naturalHeight;
        
        const W = w * 0.3, H = h * 0.3;

        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');
               
        canvas.width = W, canvas.height = H;
        
        ctx.drawImage(previewImage, 0, 0, W, H);
        
        canvas.toBlob((blob) => {
          previewImage.src = URL.createObjectURL(blob);
          document.body.append(previewImage);
        });

    }).catch((encodingError) => {
        // Do something with the error.
    });
} // end of showfiles(file)

images.addEventListener('change', (e) => {
  [...e.target.files].forEach(showFiles);
});
<input id="images" type="file" multiple>

  • Related