Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 380|回复: 0

利用exif.js解决ios或Android手机上传竖拍照片旋转90度问题

[复制链接]
  • TA的每日心情
    奋斗
    前天 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-5-24 05:52:23 | 显示全部楼层 |阅读模式

    html5+canvas进行移动端手机照片上传时,发现ios手机上传竖拍照片会逆时针旋转90度,横拍照片无此问题;Android手机没这个问题。

    因此解决这个问题的思路是:获取到照片拍摄的方向角,对非横拍的ios照片进行角度旋转修正。

    利用exif.js读取照片的拍摄信息,详见  http://code.ciaoca.com/javascript/exif-js/

    这里主要用到Orientation属性。

    Orientation属性说明如下:

     

    旋转角度 参数
    1
    顺时针90° 6
    逆时针90° 8
    180° 3

     

    下面就直接上代码了。

    主要有html5页面和一个js,示例功能包含了图片压缩和旋转。

    自己写的是uploadImage.js。

    html5测试页面如下:

    <!DOCTYPE html>  
    <html>  
    <head>  
        <meta charset="utf-8">  
        <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />  
        <title>图片上传</title>  
        <script type="text/javascript" src="js/jquery-1.8.3.js"></script>  
        <script type="text/javascript" src="js/uploadPicture/uploadImage.js" ></script>  
            <script type="text/javascript" src="js/exif.js" ></script>  
        <script>  
      
        </script>  
    </head>  
    <body>  
        <div style="height: 50px; line-height: 50px;text-align: center;border-bottom: 1px solid #171E28;">  
                上传图片:  
                <input type="file" accept="image/*" id="uploadImage" capture="camera" onchange="selectFileImage(this);" />  
            </div>  
            <div style="margin-top: 10px;">  
                <img alt="preview" src="" id="myImage"/>  
            </div>  
    </body>  
    </html>  
    uploadImage.js如下:
    [javascript] view plain copy
    function selectFileImage(fileObj) {  
        var file = fileObj.files['0'];  
        //图片方向角 added by lzk  
        var Orientation = null;  
          
        if (file) {  
            console.log("正在上传,请稍后...");  
            var rFilter = /^(image\/jpeg|image\/png)$/i; // 检查图片格式  
            if (!rFilter.test(file.type)) {  
                //showMyTips("请选择jpeg、png格式的图片", false);  
                return;  
            }  
            // var URL = URL || webkitURL;  
            //获取照片方向角属性,用户旋转控制  
            EXIF.getData(file, function() {  
               // alert(EXIF.pretty(this));  
                EXIF.getAllTags(this);   
                //alert(EXIF.getTag(this, 'Orientation'));   
                Orientation = EXIF.getTag(this, 'Orientation');  
                //return;  
            });  
              
            var oReader = new FileReader();  
            oReader.onload = function(e) {  
                //var blob = URL.createObjectURL(file);  
                //_compress(blob, file, basePath);  
                var image = new Image();  
                image.src = e.target.result;  
                image.onload = function() {  
                    var expectWidth = this.naturalWidth;  
                    var expectHeight = this.naturalHeight;  
                      
                    if (this.naturalWidth > this.naturalHeight && this.naturalWidth > 800) {  
                        expectWidth = 800;  
                        expectHeight = expectWidth * this.naturalHeight / this.naturalWidth;  
                    } else if (this.naturalHeight > this.naturalWidth && this.naturalHeight > 1200) {  
                        expectHeight = 1200;  
                        expectWidth = expectHeight * this.naturalWidth / this.naturalHeight;  
                    }  
                    var canvas = document.createElement("canvas");  
                    var ctx = canvas.getContext("2d");  
                    canvas.width = expectWidth;  
                    canvas.height = expectHeight;  
                    ctx.drawImage(this, 0, 0, expectWidth, expectHeight);  
                    var base64 = null;  
                    //修复ios  
                    if (navigator.userAgent.match(/iphone/i)) {  
                        console.log('iphone');  
                        //alert(expectWidth + ',' + expectHeight);  
                        //如果方向角不为1,都需要进行旋转 added by lzk  
                        if(Orientation != "" && Orientation != 1){  
                            alert('旋转处理');  
                            switch(Orientation){  
                                case 6://需要顺时针(向左)90度旋转  
                                    alert('需要顺时针(向左)90度旋转');  
                                    rotateImg(this,'left',canvas);  
                                    break;  
                                case 8://需要逆时针(向右)90度旋转  
                                    alert('需要顺时针(向右)90度旋转');  
                                    rotateImg(this,'right',canvas);  
                                    break;  
                                case 3://需要180度旋转  
                                    alert('需要180度旋转');  
                                    rotateImg(this,'right',canvas);//转两次  
                                    rotateImg(this,'right',canvas);  
                                    break;  
                            }         
                        }  
                          
                        /*var mpImg = new MegaPixImage(image); 
                        mpImg.render(canvas, { 
                            maxWidth: 800, 
                            maxHeight: 1200, 
                            quality: 0.8, 
                            orientation: 8 
                        });*/  
                        base64 = canvas.toDataURL("image/jpeg", 0.8);  
                    }else if (navigator.userAgent.match(/Android/i)) {// 修复android  
                        var encoder = new JPEGEncoder();  
                        base64 = encoder.encode(ctx.getImageData(0, 0, expectWidth, expectHeight), 80);  
                    }else{  
                        //alert(Orientation);  
                        if(Orientation != "" && Orientation != 1){  
                            //alert('旋转处理');  
                            switch(Orientation){  
                                case 6://需要顺时针(向左)90度旋转  
                                    alert('需要顺时针(向左)90度旋转');  
                                    rotateImg(this,'left',canvas);  
                                    break;  
                                case 8://需要逆时针(向右)90度旋转  
                                    alert('需要顺时针(向右)90度旋转');  
                                    rotateImg(this,'right',canvas);  
                                    break;  
                                case 3://需要180度旋转  
                                    alert('需要180度旋转');  
                                    rotateImg(this,'right',canvas);//转两次  
                                    rotateImg(this,'right',canvas);  
                                    break;  
                            }         
                        }  
                          
                        base64 = canvas.toDataURL("image/jpeg", 0.8);  
                    }  
                    //uploadImage(base64);  
                    $("#myImage").attr("src", base64);  
                };  
            };  
            oReader.readAsDataURL(file);  
        }  
    }  
      
    //对图片旋转处理 added by lzk  
    function rotateImg(img, direction,canvas) {    
            //alert(img);  
            //最小与最大旋转方向,图片旋转4次后回到原方向    
            var min_step = 0;    
            var max_step = 3;    
            //var img = document.getElementById(pid);    
            if (img == null)return;    
            //img的高度和宽度不能在img元素隐藏后获取,否则会出错    
            var height = img.height;    
            var width = img.width;    
            //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);    
            }    
            //img.setAttribute('step', step);    
            /*var canvas = document.getElementById('pic_' + pid);   
            if (canvas == null) {   
                img.style.display = 'none';   
                canvas = document.createElement('canvas');   
                canvas.setAttribute('id', 'pic_' + pid);   
                img.parentNode.appendChild(canvas);   
            }  */  
            //旋转角度以弧度值为参数    
            var degree = step * 90 * Math.PI / 180;    
            var ctx = canvas.getContext('2d');    
            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;    
            }    
        }    

    再看下Exif.js官网:

    http://code.ciaoca.com/javascript/exif-js/

    文档目录
    1. 使用方法
    2. API 方法
    3. EXIF 标识
    4. 相关信息

    使用方法

    载入 JavaScript 文件

    <script src="exif.js"></script>

    获取 EXIF 数据

    EXIF.getData(document.getElementById('imgElement'), function(){ EXIF.getAllTags(this); EXIF.getTag(this, 'Orientation'); }); 

    API 方法

    名称 说明
    EXIF.getData(img, callback)

    获取图像的数据

    能兼容尚未支持提供 EXIF 数据的浏览器获取到元数据。

    EXIF.getTag(img, tag) 获取图像的某个数据
    EXIF.getAllTags(img) 获取图像的全部数据,值以对象的方式返回
    EXIF.pretty(img) 获取图像的全部数据,值以字符串的方式返回

    EXIF 标识

    名称 说明
    ExifVersion Exif 版本
    FlashPixVersion FlashPix 版本
    ColorSpace 色域、色彩空间
    PixelXDimension 图像的有效宽度
    PixelYDimension 图像的有效高度
    ComponentsConfiguration 图像构造
    CompressedBitsPerPixel 压缩时每像素色彩位
    MakerNote 制造商设置的信息
    UserComment 用户评论
    RelatedSoundFile 关联的声音文件
    DateTimeOriginal 创建时间
    DateTimeDigitized 数字化创建时间
    SubsecTime 日期时间(秒)
    SubsecTimeOriginal 原始日期时间(秒)
    SubsecTimeDigitized 原始日期时间数字化(秒)
    ExposureTime 曝光时间
    FNumber 光圈值
    ExposureProgram 曝光程序
    SpectralSensitivity 光谱灵敏度
    ISOSpeedRatings 感光度
    OECF 光电转换功能
    ShutterSpeedValue 快门速度
    ApertureValue 镜头光圈
    BrightnessValue 亮度
    ExposureBiasValue 曝光补偿
    MaxApertureValue 最大光圈
    SubjectDistance 物距
    MeteringMode 测光方式
    Lightsource 光源
    Flash 闪光灯
    SubjectArea 主体区域
    FocalLength 焦距
    FlashEnergy 闪光灯强度
    SpatialFrequencyResponse 空间频率反应
    FocalPlaneXResolution 焦距平面X轴解析度
    FocalPlaneYResolution 焦距平面Y轴解析度
    FocalPlaneResolutionUnit 焦距平面解析度单位
    SubjectLocation 主体位置
    ExposureIndex 曝光指数
    SensingMethod 图像传感器类型
    FileSource 源文件
    SceneType 场景类型(1 == 直接拍摄)
    CFAPattern CFA 模式
    CustomRendered 自定义图像处理
    ExposureMode 曝光模式
    WhiteBalance 白平衡(1 == 自动,2 == 手动)
    DigitalZoomRation 数字变焦
    FocalLengthIn35mmFilm 35毫米胶片焦距
    SceneCaptureType 场景拍摄类型
    GainControl 场景控制
    Contrast 对比度
    Saturation 饱和度
    Sharpness 锐度
    DeviceSettingDescription 设备设定描述
    SubjectDistanceRange 主体距离范围
    InteroperabilityIFDPointer  
    ImageUniqueID 图像唯一ID
    Tiff 相关
    名称 说明
    ImageWidth 图像宽度
    ImageHeight 图像高度
    BitsPerSample 比特采样率
    Compression 压缩方法
    PhotometricInterpretation 像素合成
    Orientation 拍摄方向
    SamplesPerPixel 像素数
    PlanarConfiguration 数据排列
    YCbCrSubSampling 色相抽样比率
    YCbCrPositioning 色相配置
    XResolution X方向分辨率
    YResolution Y方向分辨率
    ResolutionUnit 分辨率单位
    StripOffsets 图像资料位置
    RowsPerStrip 每带行数
    StripByteCounts 每压缩带比特数
    JPEGInterchangeFormat JPEG SOI 偏移量
    JPEGInterchangeFormatLength JPEG 比特数
    TransferFunction 转移功能
    WhitePoint 白点色度
    PrimaryChromaticities 主要色度
    YCbCrCoefficients 颜色空间转换矩阵系数
    ReferenceBlackWhite 黑白参照值
    DateTime 日期和时间
    ImageDescription 图像描述、来源
    Make 生产者
    Model 型号
    Software 软件
    Artist 作者
    Copyright 版权信息
    GPS 相关
    名称 说明
    GPSVersionID GPS 版本
    GPSLatitudeRef 南北纬
    GPSLatitude 纬度
    GPSLongitudeRef 东西经
    GPSLongitude 经度
    GPSAltitudeRef 海拔参照值
    GPSAltitude 海拔
    GPSTimeStamp GPS 时间戳
    GPSSatellites 测量的卫星
    GPSStatus 接收器状态
    GPSMeasureMode 测量模式
    GPSDOP 测量精度
    GPSSpeedRef 速度单位
    GPSSpeed GPS 接收器速度
    GPSTrackRef 移动方位参照
    GPSTrack 移动方位
    GPSImgDirectionRef 图像方位参照
    GPSImgDirection 图像方位
    GPSMapDatum 地理测量资料
    GPSDestLatitudeRef 目标纬度参照
    GPSDestLatitude 目标纬度
    GPSDestLongitudeRef 目标经度参照
    GPSDestLongitude 目标经度
    GPSDestBearingRef 目标方位参照
    GPSDestBearing 目标方位
    GPSDestDistanceRef 目标距离参照
    GPSDestDistance 目标距离
    GPSProcessingMethod GPS 处理方法名
    GPSAreaInformation GPS 区功能变数名
    GPSDateStamp GPS 日期
    GPSDifferential GPS 修正
    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-11-26 02:43 , Processed in 0.154548 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表