使用Canvas来压缩图片

本文针对iOS设备在3G/2G网络环境下上传较大尺寸身份证图片时出现卡死的问题,提出了一种前端图片压缩的方法,通过将图片压缩至1MB内再上传,解决了上传失败的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【预置条件】3g/2g网络
【测试步骤】上传身份证2M左右的图片
【预期结果】正常上传
【测试结果】卡死状态
【重现概率】100%
【备注信息】仅ios

【解决方案】由前端在发送请求上传图片之前,对原图进行压缩,压缩控制在1M以内,然后再请求后台。



/***
* 前端图片压缩
* 参数传入图片文件对象,成功情况回调函数,失败情况回调函数
* 成功回调函数传入压缩后的图片文件对象
* 失败回调函数传入被catch的error对象
***/

// 压缩图片
var resizeImage = function(url,successHandle,errorHandle) {
    try {

        reader.onload = function(readerEvent) {
            var image = new Image();
            image.onload = function(imageEvent) {
                // Resize the image
                var canvas = document.createElement('canvas'),
                    max_size = 800, // 压缩后图片的最大宽度
                    width = image.width,
                    height = image.height;

                if (width > height) {
                    if (width > max_size) {
                        height *= max_size / width;
                        width = max_size;
                    }
                } else {
                    if (height > max_size) {
                        width *= max_size / height;
                        height = max_size;
                    }
                }
                canvas.width = width;
                canvas.height = height;
                canvas.getContext('2d').drawImage(image, 0, 0, width, height);//重绘图片
                var dataUrl = canvas.toDataURL('image/jpeg');
                var resizedImage = dataURLToBlob(dataUrl);// 将base64转化为blob对象

                successHandle(resizedImage);//成功后的回调函数
            }
            image.src = url;

    } catch(e) {
        // statements
        if (errorHandle){
            errorHandle(e);
        }
    }

}

// 将base64转化为blob对象
var dataURLToBlob = function(dataURL) {
    var BASE64_MARKER = ';base64,';
    if (dataURL.indexOf(BASE64_MARKER) == -1) {
        var parts = dataURL.split(',');
        var contentType = parts[0].split(':')[1];
        var raw = parts[1];

        return new Blob([raw], { type: contentType });
    }

    var parts = dataURL.split(BASE64_MARKER);
    var contentType = parts[0].split(':')[1];
    var raw = window.atob(parts[1]);
    var rawLength = raw.length;

    var uInt8Array = new Uint8Array(rawLength);

    for (var i = 0; i < rawLength; ++i) {
        uInt8Array[i] = raw.charCodeAt(i);
    }

    return new Blob([uInt8Array], { type: contentType });
}