前端利用exif.js+canvas压缩上传图片

利用canvas作为媒介重新绘画一张图片达到压缩目的,由于ios存在图片翻转问题,所以需要借助exif.js对图片进行处理。

注意:base64转成file 用new File()在ios部分机型存在不兼容问题,所以转成blob,再转成file文件。

import EXIF from "exif-js";
 
 // 压缩图片
 export function changeFile(file,callback) {
     
    var Orientation = null;

    // 选择的文件是图片
    if (file.type.indexOf("image") === 0) {
        EXIF.getData(file, function() {
            EXIF.getAllTags(this);
            Orientation = EXIF.getTag(this, "Orientation");
        });


        // 压缩图片需要的一些元素和对象
        var reader = new FileReader(),
            //创建一个img对象
            img = new Image();

        reader.readAsDataURL(file);
        // 文件base64化,以便获知图片原始尺寸
        reader.onload = function(e) {
            img.src = e.target.result;
        };

        // base64地址图片加载完毕后执行
        img.onload = function() {
            // 缩放图片需要的canvas(也可以在DOM中直接定义canvas标签,这样就能把压缩完的图片不转base64也能直接显示出来)
            var canvas = document.createElement("canvas");
            var context = canvas.getContext("2d");

            // 图片原始尺寸
            var originWidth = this.width;
            var originHeight = this.height;

            // 最大尺寸限制,可通过设置宽高来实现图片压缩程度
            var maxWidth = 1500,
                maxHeight = 1500;
            // 目标尺寸
            var targetWidth = originWidth,
                targetHeight = originHeight;
            // 图片尺寸超过1500x1500的限制
            if (originWidth > maxWidth || originHeight > maxHeight) {
                if (originWidth / originHeight > maxWidth / maxHeight) {
                    // 更宽,按照宽度限定尺寸
                    targetWidth = maxWidth;
                    targetHeight = Math.round(
                        maxWidth * (originHeight / originWidth)
                    );
                } else {
                    targetHeight = maxHeight;
                    targetWidth = Math.round(
                        maxHeight * (originWidth / originHeight)
                    );
                }
            }
            // canvas对图片进行缩放
            canvas.width = targetWidth;
            canvas.height = targetHeight;
            // 清除画布
            context.clearRect(0, 0, targetWidth, targetHeight);
            // 图片压缩
            context.drawImage(img, 0, 0, targetWidth, targetHeight);

            /*第一个参数是创建的img对象;第二三个参数是左上角坐标,后面两个是画布区域宽高*/

            console.log("Orientation=" + Orientation);



            // 图片翻转问题
            if (
                Orientation != "" &&
                Orientation != 1 &&
                Orientation != undefined
            ) {
                switch (Orientation) {
                    case 6: //需要顺时针90度旋转
                        console.log("需要顺时针(向左)90度旋转");
                        rotateImg(img, "left", canvas);
                        break;
                    case 8: //需要逆时针90度旋转
                        console.log("需要逆时针(向右)90度旋转");
                        rotateImg(img, "right", canvas);
                        break;
                    case 3: //需要180度旋转
                        console.log("需要180度旋转");
                        rotateImg(img, "right", canvas);
                        rotateImg(img, "right", canvas);
                        break;
                }
            }

            //压缩后的图片转base64 url
            /*canvas.toDataURL(mimeType, qualityArgument),mimeType 默认值是'image/png';
             * qualityArgument表示导出的图片质量,只有导出为jpeg和webp格式的时候此参数才有效,默认值是0.92*/
            var base64 = canvas.toDataURL("image/jpeg", 0.92);
            var type = "jpeg";
            var fixtype = function(type) {
                type = type.toLocaleLowerCase().replace(/jpg/i, "jpeg");
                var r = type.match(/png|jpeg|bmp|gif/)[0];
                return "image/" + r;
            };
            base64 = base64.replace(fixtype(type), "image/jpeg");

            // 将base64转换成file对象
            var base64ToFile =  blobToFile( dataURLtoBlob(base64),file);

            // console.log(base64ToFile)

            if(callback){
                callback(base64ToFile.name)
            }

            //var initSize = img.src.length;
            // console.log("压缩前:" + initSize);
            // console.log("压缩后:" + newUrl.length);
            // console.log(
            //     "压缩率:" +
            //         ~~((100 * (initSize - newUrl.length)) / initSize) +
            //         "%"
            // );

        };
    }
}
// 将base64转换为blob
export function dataURLtoBlob(dataurl) {
    var arr = dataurl.split(","),
        mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]),
        n = bstr.length,
        u8arr = new Uint8Array(n);

    while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
    }

    return new Blob([u8arr], { type: mime });
}

// 将blob转换成file
export function blobToFile(theBlob, fileName) {
    theBlob.lastModifiedDate = new Date();

    theBlob.name = fileName;

    return theBlob;
}
// 选转图片
export function rotateImg(img, direction, canvas) {
    //最小与最大旋转方向,图片旋转4次后回到原方向
    const min_step = 0;
    const max_step = 3;
    if (img == null) return;
    //img的高度和宽度不能在img元素隐藏后获取,否则会出错
    let height = img.height;
    let width = img.width;
    let step = 2;
    if (step == null) {
        step = min_step;
    }
    if (direction == "right") {
        step++;
        //旋转到原位置,即超过最大值
        step > max_step && (step = min_step);
    } else {
        step--;
        step < min_step && (step = max_step);
    }
    //旋转角度以弧度值为参数
    let degree = (step * 90 * Math.PI) / 180;
    let ctx = canvas.getContext("2d");
    ctx.clearRect(0, 0, width, height);
    switch (step) {
        case 0:
            canvas.width = width;
            canvas.height = height;
            ctx.drawImage(img, 0, 0);
            break;
        case 1:
            canvas.width = height;
            canvas.height = width;
            ctx.rotate(degree);
            ctx.drawImage(img, 0, -height);
            break;
        case 2:
            canvas.width = width;
            canvas.height = height;
            ctx.rotate(degree);
            ctx.drawImage(img, -width, -height);
            break;
        case 3:
            canvas.width = height;
            canvas.height = width;
            ctx.rotate(degree);
            ctx.drawImage(img, -width, 0);
            break;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值