2

I am trying to compress image size using JavaScript. but it returns canvas error. below is my code.

 var reader = new FileReader();
        reader.readAsDataURL(fileItem._file);
        reader.onload = function (event) {
            var base64 = event.target.result.substring(event.target.result.indexOf(',') + 1, event.target.result.length);
     var cvs = document.createElement('canvas');
            var source_img_obj = event.target.result;
            cvs.width = source_img_obj.naturalWidth;
            cvs.height = source_img_obj.naturalHeight;
            var ctx = cvs.getContext("2d").drawImage(source_img_obj, 0, 0);
            var newImageData = cvs.toDataURL(type, 70 / 100);
            var result_image_obj = new Image();
            result_image_obj.src = newImageData;
            console.log(result_image_obj);
};

Error: enter image description here

ccy
  • 1,735
  • 16
  • 19
Sharma Vikram
  • 2,440
  • 6
  • 23
  • 46

3 Answers3

10

I think you are looking something like this~

This implementation has two methods to reduce the size of the image. One method resize the image while the other compress it maintaining the same size but it reduces the quality.

This implementation is based on FileReader() to read the contents of files (or raw data buffers for Blob objects) stored on the user's computer.

// Console logging (html)
if (!window.console) console = {}
const consoleOut = document.getElementById('console-out')
console.log = message => {
    consoleOut.innerHTML += message + '<br />'
    consoleOut.scrollTop = consoleOut.scrollHeight
}

const outputFormat = 'jpg'

const encodeButton = document.getElementById('jpeg-encode-button')
const encodeQuality = document.getElementById('jpeg-encode-quality')

function previewFile() {
    const preview = document.getElementById('source-image')
    const previewResize = document.getElementById('result-resize-image')
    const previewCompress = document.getElementById('result-compress-image')

    const file = document.querySelector('input[type=file]').files[0]
    const reader = new FileReader()
    reader.onload = e => {
        preview.onload = () => {
            resizeFile(preview, previewResize)
            compressFile(preview, previewCompress)
        }
        preview.src = e.target.result
        // preview.src = reader.result
    }

    if (file) {
        reader.readAsDataURL(file)
    }
}

function resizeFile(loadedData, preview) {
    console.log('Image resizing:')
    console.log(`Resolution: ${loadedData.width}x${loadedData.height}`)
    const canvas = document.createElement('canvas')
    canvas.width = Math.round(loadedData.width / 2)
    canvas.height = Math.round(loadedData.height / 2)

    preview.appendChild(canvas)
    // document.body.appendChild(canvas)

    const ctx = canvas.getContext('2d')
    ctx.drawImage(loadedData, 0, 0, canvas.width, canvas.height)
    console.log(`New resolution: ${canvas.width}x${canvas.height}`)
    console.log('---')
}

function compressFile(loadedData, preview) {
    console.log('Image compressing:')
    console.log(`width: ${loadedData.width} | height: ${loadedData.height}`)

    const quality = parseInt(encodeQuality.value)
    console.log(`Quality >> ${quality}`)

    const timeStart = performance.now()
    console.log('process started...')

    const mimeType = typeof outputFormat !== 'undefined' && outputFormat === 'png' ? 'image/png' : 'image/jpeg'

    const canvas = document.createElement('canvas')
    canvas.width = loadedData.width;
    canvas.height = loadedData.height;
    
    const ctx = canvas.getContext('2d').drawImage(loadedData, 0, 0)
    const newImageData = canvas.toDataURL(mimeType, quality / 100)
    const img = new Image()
    img.src = newImageData

    preview.src = img.src
    preview.onload = () => {}

    const duration = performance.now() - timeStart;
    console.log('process finished...')
    console.log(`Processed in: ${duration}ms`)
    console.log('---')
}
<input type="file" onchange="previewFile()"><br>
<div>
  <h3>Original Image</h3>
  <img id="source-image" />
</div>
<div>
  <h3>Resized Image</h3>
  <div id="result-resize-image">
  </div>
</div>
<div>
  <h3>Compressed Image</h3>
  <img id="result-compress-image" class='img-container' />
</div>
<br><br>
<div>
  <fieldset>
    <legend>Compressor settings</legend>
    <div id='controls-wrapper'>
      Compression ratio : <input id="jpeg-encode-quality" size='3' readonly='true' type="text" value="30" /> %
    </div>
  </fieldset>
</div>
<div>
  <fieldset>
    <legend>Console output</legend>
    <div id='console-out'></div>
  </fieldset>
</div>
Teocci
  • 7,189
  • 1
  • 50
  • 48
1

You might have to resize the canvas size

refer the following example here

function resizeImg(base, width, height) {
    var canvas = document.createElement("canvas");
    canvas.width = width;
    canvas.height = height;
    var context = canvas.getContext("2d");
    var deferred = $.Deferred();
    $("<img/>").attr("src", "data:image/gif;base," + base).load(function() {
        context.scale(width/this.width,  height/this.height);
        context.drawImage(this, 0, 0); 
        deferred.resolve($("<img/>").attr("src", canvas.toDataURL()));               
    });
    return deferred.promise();    
}
Community
  • 1
  • 1
BhandariS
  • 606
  • 8
  • 20
0

To compress a File (got from input type file) you can use this function. Just call it with the file, and it will return the same file but compressed:

const compressImage = (imageFile, quality) => {
    return new Promise((resolve, reject) => {
        const $canvas = document.createElement("canvas");
        const image = new Image();
        image.onload = () => {
            $canvas.width = image.width;
            $canvas.height = image.height;
            $canvas.getContext("2d").drawImage(image, 0, 0);
            $canvas.toBlob(
                (blob) => {
                    if (blob === null) {
                        return reject(blob);
                    } else {
                        resolve(blob);
                    }
                },
                "image/jpeg",
                quality / 100
            );
        };
        image.src = URL.createObjectURL(imageFile);
    });
};

Usage is:

<input type="file" id="my_input">

And JS:

const $inputFile = document.querySelector("#my_input");
    $inputFile.addEventListener("change", async () => {
        const file = $inputFile.files[0];
        const blob = await compressImage(file, 50);
        // Upload the blob with FormData or something similar
        console.log({ blob });
    });
Luis Cabrera Benito
  • 1,558
  • 13
  • 21