【问题标题】:How to compress image size in JavaScript?如何在 JavaScript 中压缩图像大小?
【发布时间】:2022-02-03 10:12:37
【问题描述】:

我正在尝试使用 JavaScript 压缩图像大小。但它返回画布错误。 下面是我的代码。

 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);
};

错误:

【问题讨论】:

    标签: javascript angularjs html


    【解决方案1】:

    我觉得你看起来像这样~

    这个实现有两种方法来减小图像的大小。一种方法是调整图像大小,而另一种方法是在保持相同大小的情况下对其进行压缩,但会降低质量。

    此实现基于FileReader() 读取存储在用户计算机上的文件(或 Blob 对象的原始数据缓冲区)的内容。

    // 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>

    【讨论】:

    • 我想将 8 到 10 mb 的图像压缩到小于等于 1 mb
    • 我添加了一种方法来压缩图像,保持相同的大小。
    【解决方案2】:

    您可能需要调整画布大小

    参考下面的例子 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();    
    }
    

    【讨论】:

    • 我想将 8 到 10 mb 的图像压缩到小于等于 1 mb
    【解决方案3】:

    要压缩文件(从输入类型文件获得),您可以使用此功能。只需用文件调用它,它就会返回相同的文件但被压缩:

    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);
        });
    };
    

    用法是:

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

    还有 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 });
        });
    

    【讨论】: