vue实现图片压缩的功能进行封装和调用

单页面实现图片压缩 - 小那 - 博客园 (cnblogs.com)

对上述链接的单页面实现图片压缩的功能进行进一步的修改,并应用到项目中

整体思路:

  1. 第一次压缩,将图片转为base64
  2. 第二次压缩,利用canvas画布生成图片
  3. 最后将base64转为文件流形式返回
function convertImageToBase64(fileinput, callback) {
    // 创建一个FileReader对象,它允许Web应用程序异步读取存储在计算机上的文件
    // 也就是file对象
    let reader = new FileReader()
    let file = fileinput.files[0];

    // 添加一个load事件,load会在加载完毕之后进行触发(也就是readAsDataURL读取完毕后触发)
    reader.addEventListener("load", function (e) {
        const base64Image = e.target.result // 相当于reader.result 获取文件的Base64
        // 回收内存
        // callback && callback(base64Image) // 调用callback压缩
        compress(base64Image, file, callback)
        reader = null
    })

    // readAsDataURL方法读取指定的file或blob对象
    reader.readAsDataURL(file)
}
// 压缩算法函数
/* 
1.首先拿到了base64的图片字符串 
2.创建一个image对象,获得原始图片的宽度和高度
3.对原始图片的宽度和高度进行压缩达到符合条件(第一次压缩-从尺寸压缩)
4.调用canvasAPI进行绘制新的图片
5.绘制成功之后调用canvasAPI进行绘制(canvasAPI支持压缩-二次压缩-从质量压缩)
6.得到压缩后的base64
 */
function compress(base64Image, file, callback) {
    let maxW = 1024;
    let maxH = 1024;
    let size  = 1024 * 1024 * 2
    const image = new Image() // 创建image对象 相当于创建a标签
    image.addEventListener('load', function (e) {
        // image加载完成后就会触发 也就是src加载后
        let radio; // 压缩比例
        let needCompress = false; // 是否需要压缩
        // image.naturalWidth/naturalHeight H5新属性 获取源生图片的宽高
        if (file.size > size) {
            needCompress = true;
            // 获得压缩宽高过后的大小(保证等比例缩放)
            radio = image.naturalWidth / maxW
            maxH = image.naturalHeight / radio
            // 第一次压缩完成
            // 接下来使用canvas进行质量压缩
            const canvas = document.createElement('canvas')
            canvas.height = maxH;
            canvas.width = maxW;
            canvas.setAttribute("id", "_compress_")
            // visibility hidden 需要创建的canvas隐藏 而不是不渲染DOM
            canvas.style.visibility = 'hidden'
            document.body.appendChild(canvas)

            const ctx = canvas.getContext('2d')
            // canvas.clearRect() 方法清空给定矩形内的指定像素。(x1,y1,width,height)
            // 防止重新上传覆盖 
            ctx.clearRect(0, 0, maxW, maxH)
            // canvas.drawImage() 方法在画布(canvas)上绘制图像、画布或视频。
            // 传入 视频/图片对象 起始点x 起始点y 绘制宽 绘制高 
            ctx.drawImage(image, 0, 0, maxW, maxH)
            // 接来下就是压缩canvas 通过API将canvas输出成base64格式

            /**
             * @HTMLCanvasElement.toDataURL(type, encoderOptions);  注意调用这是 Canvas的Dom对象而非ctx
             * @param {String} 可以使用 type 参数其类型, type 图片格式,默认为image/png,图片的分辨率为96dpi。
             * @param {Number}  encoderOptions 可选 指定图片格式是image/jpeg或image/webp的情况下,可以从0到1区间内进行选择图片的质量(1原质量)。如果超出取值方位,使用默认0.92 
             * @returns {dataURL}  方法返回一个包含图片展示的 data URI (Base64)
             */
            /* 注意这里是Canvas DOM 节点 而非canvas对象*/
            const compressImage = canvas.toDataURL('image/jpeg', 0.8) // 通常压缩是0.8-0.9
            let filedata = convertBase64ToBlob(compressImage)
            callback && callback(filedata); // 压缩完成进行后台传输逻辑
            // 压缩完的图片就已经保存在内存(compressImage)中了 
            // 接下来移除canvas元素 调用DOM.remove()
            canvas.remove()
            // 需要的上传预览的话可以单独建一个new image进行预览
            const _image = new Image()
            _image.src = compressImage;
            document.body.appendChild(_image)
            //计算压缩比 使用src(base)的长度就可以对比了
            // console.log(`压缩比${image.src.length / _image.src.length}`)
        } else {
            let filedata2 = new File([file], Date.now() + '.png', { type: file.type })
            callback && callback(filedata2); // 无需压缩的文件直接返回
        }
        
        

        // 不需要压缩
        if (!needCompress) {
            maxW = image.naturalWidth;
            maxH = image.naturalHeight;
        }
        
    })
    image.src = base64Image;
    // document.body.appendChild(image) // 挂载
}


// 将压缩后图片的base64转成文件流形式返回
function convertBase64ToBlob(dataURI) {
    var byteString = atob(dataURI.split(',')[1]);
    var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
    var ab = new ArrayBuffer(byteString.length);
    var ia = new Uint8Array(ab);
    for (var i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
    }
    // return new Blob([ab], { type: mimeString });
    let blob = new Blob([ab], { type: mimeString });
    let file = new File([blob], Date.now() + '.png', { type: mimeString })
    return file
}



export default {
    convertImageToBase64
}

修改过程:

  • 新建compressImage.js文件,将方法粘贴到该文件中
  • 压缩方法修改
    •   原方法的第一步压缩是通过图片的宽高大小,判断是否进行压缩操作,我修改为通过判断文件大小来判断是否进行压缩图片
    •   原方法的第二步压缩是无论图片大小都进行canvas压缩,改为通过判断文件大小并进行第一步压缩后再进行canvas压缩
  • 增加base64转成文件流的方法,以便传参给后台

调用方法

// 上传图片压缩
import CompressImage from "../utils/compressImage";

CompressImage.convertImageToBase64(fileInput, (fileData) => {
            fileData.tenantId = SYUserAuth.getTenantId();

            FileUpload(fileData).then((res) => {
              let imgUrl = window.CDN_URL + res.data.data.fileUrl;
              let length = self.quill.getSelection(true).index;
              self.quill.insertEmbed(length, "image", imgUrl);
            }).catch(() => {
              Message({ message: "上传失败", type: "error" });
            });
          });

 

posted @ 2023-02-27 16:56  小那  阅读(1185)  评论(0编辑  收藏  举报