利用exif js及脚本修正图片的orientation显示



## 推荐 ##


这一篇文章是早年为了解决图片裁剪的探索性文章,现在已经开放出了falsh版及html5版本的图片裁剪插件,各位有时间可以看看:

[浮士德html5图片裁剪器2016开源版](http://blog.csdn.net/cdnight/article/details/51733087)


[浮士德头像裁剪flash版2016福利版](http://blog.csdn.net/cdnight/article/details/51729407)


上面两个解决方案已经经过多个项目的成功应用,适用于低级浏览器及现代浏览器,ipad,android,iphone4s,iphone5,iphone5s,iphone6等设备等。


假如图片是ios及数码相机拍摄,那么它就会带有exif信息,其中一个叫orientation的方向信息,这个方向是你拍摄的方向,假如有这个方向的话,在pc,安卓及ios上面的显示都不一样。下面是两个对比图。


【pc端效果】



【安卓端显示效果】




【ios上显示效果】




看到差别没有?下面我们给出demo及解决方案。


<!DOCTYPE html>
<html>
<head>
    <title></title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <script type="text/javascript" src="/static/lib/jquery-1.11.0.min.js"></script>
    <script type="text/javascript" src="/static/lib/util.js"></script>
    <script type="text/javascript" src="/static/vendor/exif-js/exif.min.js"></script>
    <script type="text/javascript" src="ImageOrientationFix.js"></script>

</head>
<body>
<h2>修正图片带有exif 的orientation信息时候,在安卓上面没办法正常显示问题。</h2>
<h3>三张例子图片</h3>
<div>
    <div>orientation 1:</div>
    <img src="oretation/exif_info_1.jpg" style="max-width: 200px;" id="p_1">
</div>

<div>
    <div>orientation 3:</div>
    <img src="oretation/exif_info_3.jpg" style="max-width: 200px;" id="p_3">
</div>

<div>
    <div>orientation 6:</div>
    <img src="oretation/exif_info_6.jpg" style="max-width: 200px;" id="p_6">
</div>
<div>
    <div>orientation 8:</div>
    <img src="oretation/exif_info_8.jpg" style="max-width: 200px;" id="p_8">
</div>
<h3>解决结果。</h3>
<div>
    <img id="pic_1" style="max-width: 200px"/>
</div>
<div>
    <img id="pic_3" style="max-width: 200px"/>
</div>
<div>
    <img id="pic_6" style="max-width: 200px"/>
</div>
<div>
    <img id="pic_8" style="max-width: 200px"/>
</div>

<div id="tmp_result"></div>
</body>
<script type="text/javascript">
    $(function(){
        ImageOrientationFix({
            image:"oretation/exif_info_1.jpg"
            ,onFix:function(base64_str){
                $("#pic_1").attr("src",base64_str);
            }
        });

        ImageOrientationFix({
            image:"oretation/exif_info_3.jpg"
            ,onFix:function(base64_str){
                $("#pic_3").attr("src",base64_str);
            }
        });

        ImageOrientationFix({
            image:"oretation/exif_info_6.jpg"
            ,onFix:function(base64_str){
                $("#pic_6").attr("src",base64_str);
            }
        });

        ImageOrientationFix({
            image:"oretation/exif_info_8.jpg"
            ,onFix:function(base64_str){
                $("#pic_8").attr("src",base64_str);
            }
        });
    });

    /*
    $("#tmp_result").html('<canvas width="2448" height="3264" id="tmp_canvas"></canvas>');

    var tmp_canvas=document.getElementById('tmp_canvas');
    var tmp_context=tmp_canvas.getContext("2d");

    var _tansX=parseInt(3264/2);
    var _tansY=parseInt(2448/2);
    tmp_context.translate(_tansY,_tansX);
    tmp_context.rotate(-0.5 * Math.PI);
    var _middle_canvas=window._middle_canvas;
    tmp_context.drawImage(_middle_canvas,0,0,_middle_canvas.width,_middle_canvas.height,0-_tansX,0-_tansY,_middle_canvas.width,_middle_canvas.height);
        */
</script>
</html>



核心脚本。

/**
 * 第一,该文件用到exifjs库,第二,ie9以下肯定没办法使用的,第三,该工具针对ios对大图片画到canvas时候变成细长的情况的bug也做了处理。
 *
 */
;var ImageOrientationFix=function(opts){
    var settings={
        //img:"" //图片元素,推荐用var _img=new Image() 然后用_img.οnlοad=function(){ EXIF.getData(this,function(exifdata){});_img.src=value; }这样使用。
        image:"" //分成三种类型,一种是服务端的url,一种是base64数据,还有一种是iamge原生元素。
        ,imgType:"url" //url,base64或者image
        ,onFix:function(base64ImgStr){

        }//处理以后得到的base64字符串。
    };

    var _exifInfo={};
    var _realImage="";

    $.extend(settings,opts);
    
    //---修正ios压扁问题。
//--修正ios下面canvas图片压缩的情况。
    /**
     * Detecting vertical squash in loaded image.
     * Fixes a bug which squash image vertically while drawing into canvas for some images.
     * This is a bug in iOS6 devices. This function from https://github.com/stomita/ios-imagefile-megapixel
     *
     */
    function detectVerticalSquash(img) {
        var iw = img.naturalWidth, ih = img.naturalHeight;
        var canvas = document.createElement('canvas');
        canvas.width = 1;
        canvas.height = ih;
        var ctx = canvas.getContext('2d');
        ctx.drawImage(img, 0, 0);
        var data = ctx.getImageData(0, 0, 1, ih).data;
        // search image edge pixel position in case it is squashed vertically.
        var sy = 0;
        var ey = ih;
        var py = ih;
        while (py > sy) {
            var alpha = data[(py - 1) * 4 + 3];
            if (alpha === 0) {
                ey = py;
            } else {
                sy = py;
            }
            py = (ey + sy) >> 1;
        }
        var ratio = (py / ih);
        return (ratio===0)?1:ratio;
    }

    /**
     * A replacement for context.drawImage
     * (args are for source and destination).
     */
    function drawImageIOSFix(ctx, img, sx, sy, sw, sh, dx, dy, dw, dh) {
        var vertSquashRatio =detectVerticalSquash(img);
        // Works only if whole image is displayed:
        // ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh / vertSquashRatio);
        // The following works correct also when only a part of the image is displayed:
        ctx.drawImage(img, sx * vertSquashRatio, sy * vertSquashRatio,
                sw * vertSquashRatio, sh * vertSquashRatio,
            dx, dy, dw, dh );
    }    
    var _app={
        init:function(){
            var __image = new Image();
            var _me=this;
            _realImage=__image;

            __image.onload = function () {
                EXIF.getData(this, function () {

                    _exifInfo = EXIF.getAllTags(this);
                    _me.__fix();
                });
            };
            if(settings.imgType=="image"){
                __image.src=$(settings.image).attr("src");
            }
            else{
                __image.src=settings.image;
            }
        }
        ,__fix:function(){
            
                //--修正ios6 7 颠倒,压扁问题。

                var Options={
                    width:_realImage.naturalWidth
                    ,height:_realImage.naturalHeight
                    ,transX:0
                    ,transY:0
                    ,XDimension:0
                    ,YDimension:0
                    ,Orientation:1
                };
                Options.Orientation=_exifInfo.Orientation;

                    if(Options.Orientation==undefined){
                        Options.Orientation=1;
                    }

                    var _realWidth=0;
                    var _realHeight=0;
                    //--计算是否需要旋转。
                    if(Options.Orientation!=1){
                        Options.transX=parseInt(Options.width/2);
                        Options.transY=parseInt(Options.height/2);

                    }
                    else{
                        Options.transX=0;
                        Options.transY=0;

                    }
                    _realWidth=_realImage.width;
                    _realHeight=_realImage.height;

                    var XDimension=_exifInfo["PixelXDimension"];// EXIF.getTag(this,"PixelXDimension");
                    var YDimension=_exifInfo["PixelYDimension"]; // EXIF.getTag(this,"PixelYDimension");
                    Options.XDimension=XDimension;
                    Options.YDimension=YDimension;

                    var tmpCanvas=document.createElement("canvas");

                    tmpCanvas.width=Options.width;
                    tmpCanvas.height=Options.height;
                    var tmpContext=tmpCanvas.getContext("2d");
                    //--放入临时画布。
                    tmpContext.clearRect(0,0,tmpCanvas.width,tmpCanvas.height);
                    //context.clearRect(0,0,canvas.width,canvas.height);
                    //context.drawImage(image, 0, 0, image.width, image.height, Options.cropLeft, Options.cropTop, Options_image.scaleWidth, Options_image.scaleHeight);
                    // context.drawImage(image, 0, 0, image.width, image.height, Options.cropLeft, Options.cropTop, canvas.width, canvas.height);
                    drawImageIOSFix(tmpContext,_realImage, 0, 0, _realWidth, _realHeight, 0, 0, _realWidth, _realHeight);


                    //--生成新的canvas。
                    var _canvas=document.createElement("canvas");

                    var _context=_canvas.getContext("2d");
                    //.clearRect(0,0,canvas.width,canvas.height);
                    //生成一个可以用的缩略图。

                    switch(Options.Orientation){
                        case 8:
                            // 90 rotate left     --需要90度向左旋转。。那么,这个 PixelYDimension就是宽度了,PixelXDimension就是高度了。
                            _realWidth=YDimension;
                            _realHeight=XDimension;
                            _canvas.width=_realWidth;
                            _canvas.height=_realHeight;
                            _context.translate(parseInt(_realWidth/2),parseInt(_realHeight/2));
                            _context.rotate(-0.5 * Math.PI);
                            _context.drawImage(tmpCanvas,0,0,tmpCanvas.width,tmpCanvas.height,0-Options.transX,0-Options.transY,tmpCanvas.width,tmpCanvas.height);
                            break;
                        case 3:
                            //180向左旋转
                            _realWidth=XDimension;
                            _realHeight=YDimension;
                            _canvas.width=_realWidth;
                            _canvas.height=_realHeight;
                            _context.translate(parseInt(_realWidth/2),parseInt(_realHeight/2));
                            _context.rotate(Math.PI);
                            _context.drawImage(tmpCanvas,0,0,tmpCanvas.width,tmpCanvas.height,0-Options.transX,0-Options.transY,tmpCanvas.width,tmpCanvas.height);
                            break;
                        case 6:
                            //90 rotate right 需要向右旋转90度,PixelYDimension就是宽度了,PixelXDimension就是高度了。
                            _realWidth=YDimension;
                            _realHeight=XDimension;
                            _canvas.width=_realWidth;
                            _canvas.height=_realHeight;

                            _context.translate(parseInt(_realWidth/2),parseInt(_realHeight/2));
                            _context.rotate(0.5 * Math.PI);


                            _context.drawImage(tmpCanvas,0,0,tmpCanvas.width,tmpCanvas.height,0-Options.transX,0-Options.transY,tmpCanvas.width,tmpCanvas.height);
                            break;
                        case 1:
                            _canvas.width=_realWidth;
                            _canvas.height=_realHeight;
                            _context.drawImage(tmpCanvas,0,0,_realWidth,_realHeight,0-Options.transX,0-Options.transY,tmpCanvas.width,tmpCanvas.height);
                            break;
                    }
                    var _base64=_canvas.toDataURL();
                    settings.onFix(_base64);
                   //$(document.body).append(_canvas);
                    //selection = new Selection("canvas",16,9);
                    // selection.drawScene();
                    //selection.addListerner();

            return;

        }

    };

    _app.init();

    var returnObject={
        getExif:function(){
            return _exifInfo;
        }

    };

    return returnObject;
};



解决界面显示。




个人建议


千万千万别在显示时候用这种方式处理图片,万一图片繁多你就等着卡死。。。在上传及裁剪时候可以先进行这种处理。切记切记。

## 推荐 ## 这一篇文章是早年为了解决图片裁剪的探索性文章,现在已经开放出了falsh版及html5版本的图片裁剪插件,各位有时间可以看看: [浮士德html5图片裁剪器2016开源版](http://blog.csdn.net/cdnight/article/details/51733087) [浮士德头像裁剪flash版2016福利版](http://blog.csdn.net/cdnight/article/details/51729407) 上面两个解决方案已经经过多个项目的成功应用,适用于低级浏览器及现代浏览器,ipad,android,iphone4s,iphone5,iphone5s,iphone6等设备等。
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值