React图片压缩上传统一处理

一、简介

最近项目需要对上传的图片文件进行压缩后才上传到服务器中,于是研究了一番,下面给出详细的压缩方法,笔者使用的是React Ant Design前端框架的Upload组件上传图片:

通过查看Ant Design官网文档,在上传文件前可以修改文件:

transformFile  在上传之前转换文件。支持返回一个 Promise 对象  Function(file): string | Blob | File | Promise<string | Blob | File>无  

二、压缩相关代码

图片压缩的原理:实际上根据图片大小有没有超过预定的最大最小时,如果超过指定的高度/宽度,在不怎么失真的前提下裁剪图片,然后使用canvas画布的drawImage()方法绘制图片。下面是关键的代码:

//在上传之前转换文件
    transformFile = (file) => {
        /**
         * 针对图片进行压缩,如果图片大小超过压缩阈值,则执行压缩,否则不压缩
         */
        //判断是否是图片类型
        if (this.checkIsImage(file.name)) {
            const {compressThreshold = 5, isPictureCompress = false, pictureQuality = 0.92} = this.props;
            let fileSize = file.size / 1024 / 1024;
            // console.log('before compress, the file size is : ', fileSize + "M");
            //当开启图片压缩且图片大小大于等于压缩阈值,进行压缩
            if ((fileSize >= compressThreshold) && isPictureCompress) {
                //判断浏览器内核是否支持base64图片压缩
                if (typeof (FileReader) === 'undefined') {
                    return file;
                } else {
                    try {
                        this.setState({
                            spinLoading: true
                        });
                        return new Promise(resolve => {
                            //声明FileReader文件读取对象
                            const reader = new FileReader();
                            reader.readAsDataURL(file);
                            reader.onload = () => {
                                // 生成canvas画布
                                const canvas = document.createElement('canvas');
                                // 生成img
                                const img = document.createElement('img');
                                img.src = reader.result;
                                img.onload = () => {
                                    const ctx = canvas.getContext('2d');
                                    //原始图片宽度、高度
                                    let originImageWidth = img.width, originImageHeight = img.height;
                                    //默认最大尺度的尺寸限制在(1920 * 1080)
                                    let maxWidth = 1920, maxHeight = 1080, ratio = maxWidth / maxHeight;
                                    //目标尺寸
                                    let targetWidth = originImageWidth, targetHeight = originImageHeight;
                                    //当图片的宽度或者高度大于指定的最大宽度或者最大高度时,进行缩放图片
                                    if (originImageWidth > maxWidth || originImageHeight > maxHeight) {
                                        //超过最大宽高比例
                                        if ((originImageWidth / originImageHeight) > ratio) {
                                            //宽度取最大宽度值maxWidth,缩放高度
                                            targetWidth = maxWidth;
                                            targetHeight = Math.round(maxWidth * (originImageHeight / originImageWidth));
                                        } else {
                                            //高度取最大高度值maxHeight,缩放宽度
                                            targetHeight = maxHeight;
                                            targetWidth = Math.round(maxHeight * (originImageWidth / originImageHeight));
                                        }
                                    }
                                    // canvas对图片进行缩放
                                    canvas.width = targetWidth;
                                    canvas.height = targetHeight;
                                    // 清除画布
                                    ctx.clearRect(0, 0, targetWidth, targetHeight);
                                    // 绘制图片
                                    ctx.drawImage(img, 0, 0, targetWidth, targetHeight);
                                    // quality值越小,图像越模糊,默认图片质量为0.92
                                    const imageDataURL = canvas.toDataURL(file.type || 'image/jpeg', pictureQuality);
                                    // 去掉URL的头,并转换为byte
                                    const imageBytes = window.atob(imageDataURL.split(',')[1]);
                                    // 处理异常,将ascii码小于0的转换为大于0
                                    const arrayBuffer = new ArrayBuffer(imageBytes.length);
                                    const uint8Array = new Uint8Array(arrayBuffer);
                                    for (let i = 0; i < imageBytes.length; i++) {
                                        uint8Array[i] = imageBytes.charCodeAt(i);
                                    }
                                    let mimeType = imageDataURL.split(',')[0].match(/:(.*?);/)[1];
                                    let newFile = new File([uint8Array], file.name, {type: mimeType || 'image/jpeg'});
                                    // console.log('after compress, the file size is : ', (newFile.size / 1024 / 1024) + "M");
                                    resolve(newFile);
                                };
                            };
                            reader.onerror = () => {
                                this.setState({
                                    spinLoading: false
                                });
                                return file;
                            }
                        }).then(res => {
                            this.setState({
                                spinLoading: false
                            });
                            return res;
                        }).catch(() => {
                            this.setState({
                                spinLoading: false
                            });
                            return file;
                        });
                    } catch (e) {
                        this.setState({
                            spinLoading: false
                        });
                        //压缩出错,直接返回原file对象
                        return file;
                    }
                }
            } else {
                //不需要压缩,直接返回原file对象
                return file;
            }
        } else {
            //非图片文件,不进行压缩,直接返回原file对象
            return file;
        }
    };

相关属性说明:

  • compressThreshold: 5,  //压缩的阈值,图片大小超过5M,则需要进行压缩
    isPictureCompress: false, //是否开启图片压缩
    pictureQuality: 0.92, //指定压缩的图片质量,取值范围为0~1,quality值越小,图像越模糊,默认图片质量为0.92
    

三、使用方法

<NHUpload
    uploadType={'file'}
    multiple={true}
    fileCountLimit={fjsl}
    maxFileSize={20}
    fileTypeLimit={fileTypeList}
    onChange={this.fjOnChange}
    isPictureCompress={true} //是否开启图片压缩
    pictureQuality={0.5}   //图片质量
    compressThreshold={1}  //压缩阈值
/>

在使用时,我们可以根据业务需求动态设置需要压缩的阈值,图片质量等等,对图片压缩可以大大节省服务器的资源,现在手机随便拍一张照片就是10几兆。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值