## 推荐 ##
这一篇文章是早年为了解决图片裁剪的探索性文章,现在已经开放出了falsh版及html5版本的图片裁剪插件,各位有时间可以看看:
[浮士德html5图片裁剪器2016开源版](http://blog.youkuaiyun.com/cdnight/article/details/51733087)
[浮士德头像裁剪flash版2016福利版](http://blog.youkuaiyun.com/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.youkuaiyun.com/cdnight/article/details/51733087)
[浮士德头像裁剪flash版2016福利版](http://blog.youkuaiyun.com/cdnight/article/details/51729407)
上面两个解决方案已经经过多个项目的成功应用,适用于低级浏览器及现代浏览器,ipad,android,iphone4s,iphone5,iphone5s,iphone6等设备等。