vue h5图片上传部分机型图片旋转bug处理

这段时间做的一个h5页面,其中有一个上传图片的功能,本来以为很简单,后来在自己的手机测试的时候发现图片被旋转了90度,用同事的手机又发现没有旋转,经过一系列的网上查资料整理出一个各平台都可以使用的js,直接放在外部,使用的时候直接引入到组件内即可

import EXIF from 'exif-js';
//获取图片方向
function getPhotoOrientation(img) {
    var orient;
    // var EXIF = new Worker('./static/js/exif.js');
    EXIF.getData(img, function () {
        orient = EXIF.getTag(this, 'Orientation');
        // console.log("666orient:"+orient)
    });
    return orient;
}
/*
三个参数
file:一个是文件(类型是图片格式),
w:一个是文件压缩的后宽度,宽度越小,字节越小
objDiv:一个是容器或者回调函数
photoCompress()
    */
function photoCompress(file, w, objDiv) {
    var ready = new FileReader();
    /*开始读取指定的Blob对象或File对象中的内容. 当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,则调用之.同时,result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容.*/
    ready.readAsDataURL(file);
    ready.onload = function () {
        var re = this.result;
        canvasDataURL(re, w, objDiv)
    }
}
function canvasDataURL(path, obj, callback) {
    var img = new Image();
    img.src = path;
    img.onload = function () {
        var that = this;
        // 默认按比例压缩
        var w = that.width,
         h = that.height,
         scale = w / h;
        w = obj.width || w;
        h = obj.height || (w / scale);
        if (w > 600) {
            h = (600 / w) * h;
            w = 600;
        }
        console.log("w:" + w)
        var quality = 0.3;  // 默认图片质量为0.6
        //生成canvas
        var canvas = document.createElement('canvas');
        var ctx = canvas.getContext('2d');
        // 创建属性节点
        var anw = document.createAttribute("width");
        anw.nodeValue = w;
        var anh = document.createAttribute("height");
        anh.nodeValue = h;
        canvas.setAttributeNode(anw);
        canvas.setAttributeNode(anh);

        var orient = getPhotoOrientation(img);
        debugger
        console.log("orient:" + orient)

        // 判断浏览器是否支持对图片进行回正操作
        IsAutoRotateImg().then(res => {
        debugger
        let IsAutoRotateImg = false
        //res为true时。浏览器支持对带 EXIF 信息的图片进行自动回正
        if (res) {
            IsAutoRotateImg = true
            // return resolve(imgData)
        }
        //res为false时。执行js,对带 EXIF 信息的图片进行回正
        // 8 表示 顺时针转了90
        // 3 表示 转了 180
        // 6 表示 逆时针转了90
        




        var u = navigator.userAgent;
        var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
        if ((isiOS || u.indexOf('iPhone') > -1)) {
            if (orient != "" && orient != 1 &&!IsAutoRotateImg) {
                switch (orient) {
                    case 6://需要顺时针(向左)90度旋转  
                        rotateImg(img, 'left', canvas, h, w);
                        // console.log("ios:第一次90")
                        // rotateImg(img, 'right', canvas, h, w);
                        // console.log("ios:第二次90")
                        // rotateImg(img, 'no', canvas, h, w);
                        break;
                    case 8://需要逆时针(向右)90度旋转  
                        rotateImg(img, 'right', canvas, h, w);
                        console.log("ios:向右90度旋转")
                        break;
                    case 3://需要180度旋转  
                        rotateImg(img, 'right', canvas, h, w);//转两次  
                        rotateImg(img, 'right', canvas, h, w);
                        break;
                    default:
                        rotateImg(img, 'no', canvas, h, w);
                        break;
                }
            } else {
                console.log("ios:不旋转")
                rotateImg(img, 'no', canvas, h, w);
            }
        } else if (navigator.userAgent.match(/Android/i)) {
            if (orient != "" && orient != 1) {
                switch (orient) {
                    case 6://需要顺时针(向左)90度旋转  
                        rotateImg(img, 'left', canvas, h, w);
                        break;
                    case 8://需要逆时针(向右)90度旋转  
                        rotateImg(img, 'right', canvas, h, w);
                        break;
                    case 3://需要180度旋转  
                        rotateImg(img, 'right', canvas, h, w);//转两次  
                        rotateImg(img, 'right', canvas, h, w);
                        break;
                    default:
                        rotateImg(img, 'no', canvas, h, w);
                        break;
                }
            }
            else {
                rotateImg(img, 'no', canvas, h, w);
            }
        } else {
            if (orient != "" && orient != 1) {
                switch (orient) {
                    case 6://需要顺时针(向左)90度旋转  
                        rotateImg(img, 'left', canvas, h, w);
                        break;
                    case 8://需要逆时针(向右)90度旋转  
                        rotateImg(img, 'right', canvas, h, w);
                        break;
                    case 3://需要180度旋转  
                        rotateImg(img, 'right', canvas, h, w);//转两次  
                        rotateImg(img, 'right', canvas, h, w);
                        break;
                    default:
                        rotateImg(img, 'no', canvas, h, w);
                        break;
                }
            } else {
                rotateImg(img, 'no', canvas, h, w);
            }
        }

        // 图像质量
        if (obj.quality && obj.quality <= 1 && obj.quality > 0) {
            quality = obj.quality;
        }
        
        // quality值越小,所绘制出的图像越模糊
        var base64 = canvas.toDataURL('image/png', quality);
        // 回调函数返回base64的值
        callback(base64);
        })
    }
}
/**  
 * 将以base64的图片url数据转换为Blob  
 * @param urlData  
 *            用url方式表示的base64图片数据  
 */
function convertBase64UrlToBlob(urlData) {
    var arr = urlData.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 });
}

//翻转图片
function rotateImg(img, direction, canvas, h, w) {
    //最小与最大旋转方向,图片旋转4次后回到原方向    
    var min_step = 0;
    var max_step = 3;
    //var img = document.getElementById(pid);    
    if (img == null) return;
    //img的高度和宽度不能在img元素隐藏后获取,否则会出错    
    var height = h;
    var width = w;
    //var step = img.getAttribute('step');    
    var 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);
    }
    //旋转角度以弧度值为参数    
    var degree = step * 90 * Math.PI / 180;
    console.log('旋转角度:'+degree)
    console.log('direction:'+direction)
    var ctx = canvas.getContext('2d');
    if (direction != "no") {
        switch (step) {
            case 0:
                canvas.width = width;
                canvas.height = height;
                ctx.drawImage(img, 0, 0, w, h);
                break;
            case 1:
                canvas.width = height;
                canvas.height = width;
                ctx.rotate(degree);
                ctx.drawImage(img, 0, -height, w, h);
                break;
            case 2:
                canvas.width = width;
                canvas.height = height;
                ctx.rotate(degree);
                ctx.drawImage(img, -width, -height, w, h);
                break;
            case 3:
                canvas.width = height;
                canvas.height = width;
                ctx.rotate(degree);
                ctx.drawImage(img, -width, 0, w, h);
                break;
        }
    } else {
        canvas.width = width;
        canvas.height = height;
        ctx.drawImage(img, 0, 0, w, h);
    }
}

 function IsAutoRotateImg(){
    // 判断浏览器是否支持对图片进行回正操作
    // 一张 2x1 的 JPEG 图片, EXIF Orientation: 6
    const testAutoOrientationImageURL =
    'data:image/jpeg;base64,/9j/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAYAAAA' +
    'AAAD/2wCEAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBA' +
    'QEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE' +
    'BAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAf/AABEIAAEAAgMBEQACEQEDEQH/x' +
    'ABKAAEAAAAAAAAAAAAAAAAAAAALEAEAAAAAAAAAAAAAAAAAAAAAAQEAAAAAAAAAAAAAAAA' +
    'AAAAAEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwA/8H//2Q==';
    let isImageAutomaticRotation;

    return new Promise((resolve) => {
        if (isImageAutomaticRotation === undefined) {
            const img = new Image();
            img.onload = () => {
                // 如果图片变成 1x2,说明浏览器对图片进行了回正
                isImageAutomaticRotation = img.width === 1 && img.height === 2;
                resolve(isImageAutomaticRotation);
            };
            img.src = testAutoOrientationImageURL;
        } else {
            // console.log('isImageAutomaticRotation === undefined');
            resolve(isImageAutomaticRotation);
        }
    });
    
}
//base64转图片
function dataURLtoFile(dataurl, filename = 'file') {
    let arr = dataurl.split(',')
    let mime = arr[0].match(/:(.*?);/)[1]
    let suffix = mime.split('/')[1]
    let bstr = atob(arr[1])
    let n = bstr.length
    let u8arr = new Uint8Array(n)
    while (n--) {
        u8arr[n] = bstr.charCodeAt(n)
    }
    return new File([u8arr], `${filename}.${suffix}`, {
        type: mime
    })
}
export default {
    photoCompress,convertBase64UrlToBlob,dataURLtoFile
}

在组件使用的时候

import  compressImg from "@/utils/compressImg"
// file 为未处理文件
compressImg.photoCompress(
   file,
   {
     quality: 0.9
   },
   function(base64Codes) {
     file = compressImg.dataURLtoFile(base64Codes);
     //file已经变成处理后的文件了,这写业务逻辑
   }
 );
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值