移动端web头像上传实现截取和照片方向修复

实战所需js包:

jQuery、Jcrop、EXIF

本次实战功能是在 app 中的 我的客户 的客户信息页面中实现移动端web的头像上传,本次没有实现图像拖拽、缩放的触摸事件功能(Jcrop在这方面的扩展支持实在不够良好,弄了半天没弄出来),若后续有更好的移动端web头像上传插件,可考虑后续替代升级。

demo主要实现的关键功能: 图像的方向修正及图像截取

虽然没有实现图像拖拽和双指缩放,但其缩放后的相对于图像的比例计算和拖拽坐标计算规则是一致的,可以参考。同时图像的旋转功能也可参考其中的核心代码。(对于图像旋转及坐标计算真的是一个大坑,特别在移动端页面代码的调试困难比较大,主要来自于无法详尽地获取移动端页面的控制台信息而导致的。。目前的移动端web远程调试技术又仅限于windows+安卓机或mac+iphone,对于我这种windows+iphone的真是伤不起啊、、只能靠alert、、、)。以下demo代码可以说不算长。但其中某些坑爬了很久才爬出来。。有点小郁闷。

好,简单地介绍下截取图像及方向旋转吧。

首先我们的思路是利用Jcrop和canvas在前台完成图像截取,利用exif获得图像方向信息再利用canvas旋转图像至正确方向,随后把处理完后的图像由canvas转成base64传给后台,再存为图片文件。具体步骤:

1、通过input调用相机或相册,在app内获取到用户想要上传的源图像;

2、读取图像方向信息,以便于对图像进行截取区域的坐标转换,如下图例:

如上图,绿色为图像原本(真实)方向,红色为图像应该展示的方向;所以当我们取图像左上角区域的时候,实际上应该取图片真实方向的左下角;因为img标签它自己会修复展示的方向,但是实际图片的存放方向仍如绿色区域所示,所以如果我们直接将红色区域的坐标用在img中进行截取时,就会存在截取区域对应不上的问题;所以我们要进行坐标转换。

3、利用canvas获取截取区域图像数据信息,进行坐标转换后画入canvas中去;

4、进行方向修正,利用 canvas的rotate方法将已截取的图像旋转至正确方向,再重新画入canvas中;

5、从canvas中获取正确图像的base64码,并传给后台。

以下是分布代码展示:

h5部分:

在页面上画出一个span区域和一个隐藏的input:

1 <div class="header-img">
2 <span id="uploadImg"><!-- 自定义头像上传 -->
3 </span>
4 <input accept="image/gif,image/jpeg,image/jpg,image/png,image/bmp" type="file" style="display:none;" id="uploadImgInput">
5 <img id="myimg" src="${ctx }/resource/wo/img/man_1.png">
6 </div>

js部分:

用户点击span的时候手动触发input的click事件来调用相册或相机:

  1 //头像上传
  2 $("#uploadImg").on(‘click‘,function(){
  3 //input file的change事件只能触发一次,因此每次点击头像后都将原input绑定的事件解除,重新赋值并绑定。
  4 $("#uploadImgInput").off(‘change‘);
  5 $(‘#uploadImgInput‘).val(‘‘);
  6 $("#uploadImgInput").on(‘change‘,uploadImgInputChangeHandler);
  7 $("#uploadImgInput").click();//手动触发input点击事件
  8 });
  9 //头像上传点击事件触发方法
 10 function uploadImgInputChangeHandler(){
 11 var input = this;
 12 if (input.files && input.files[0]) {
 13 var reader = new FileReader();
 14 reader.readAsDataURL(input.files[0]); //获取选中的第一个图片文件
 15 //获取照片方向角属性,也可用于用户旋转控制
 16 EXIF.getData(input.files[0], function() {
 17 // alert(EXIF.pretty(this));
 18 EXIF.getAllTags(this);
 19 //alert("Orientation:"+EXIF.getTag(this, ‘Orientation‘));
 20 pageData.Orientation = EXIF.getTag(this, ‘Orientation‘); //将方向信息存入对象中
 21 //return;
 22 });
 23 reader.onload = function (e) {
 24 $("#displayImgDiv").show();
 25 $("#popupContent").hide();
 26 $(‘#displayImg‘).attr(‘src‘, e.target.result);
 27 $(‘#displayImg‘)[0].onload = function(){
 28 //调用Jcrop进行图像截取,具体参数配置可查看相关教程
 29 $(‘#displayImg‘).Jcrop( {
 30 allowSelect: true,
 31 allowMove: true,
 32 allowResize: true,
 33 setSelect: [ 10, 10, screenWidth-10, screenWidth-10],
 34 aspectRatio: 1 ,
 35 minSize: [200, 200 ],
 36 maxSize: [screenWidth, screenWidth ],
 37 dragEdges: true,
 38 onSelect: updateCoords,//截取框每次移动后的调用的方法
 39 trackDocument: false
 40 } ,function(){
 41 pageData.jcropApi = this;//将jcrop对象存入全局变量中,以便后续获取
 42 }
 43 );
 44 }
 45 }
 46 }
 47 }
 48
 49 //jcrop选框选择后处理事件
 50 function updateCoords(c){
 51 var img = document.getElementById("displayImg");
 52 var canvas = document.createElement(‘canvas‘);
 53 var ctx = canvas.getContext("2d");
 54 var imgW_ori = eval(img.width);//无视方向后的img标签中图片的原始方向角度的宽
 55 var imgH_ori = eval(img.height);//无视方向后的img标签中图片的原始方向角度的高
 56 var imgW_css = $(img).width();
 57 var imgH_css = $(img).height();
 58 //修复手机图像方向问题
 59 //1、坐标确定:由于img标签在浏览器中会根据Orientation属性自动调整展示方向
 60 //故修复方向实际上则是根据当前图像截取框与伪修复图像整体的位置,判断应该截取得区域于真实图片中的位置关系后,
 61 //对相关数据进行处理,canvas的drawImage一共有9个传参,其中需要根据方向调整的有4个:
 62 var sx,sy,sw,sh,wRatio,hRatio,tx,ty,degree;
 63 var Orientation = eval(pageData.Orientation);
 64 if(Orientation != 1 && typeof(Orientation)!="undefined" && Orientation != "" ){
 65 //如果方向角不为1,都需要进行旋转
 66 switch(Orientation){
 67 case 6://需要顺时针(向左)90度旋转
 68 //对于图片缩放过后,需获取图片实际缩放比例
 69 wRatio = imgW_ori/imgH_css;
 70 hRatio = imgH_ori/imgW_css;
 71 //alert(imgW_ori+","+imgH_ori+","+imgW_css+","+imgH_css);
 72 sx = c.y*wRatio;
 73 sy = (imgW_css-c.x-c.w)*hRatio;
 74 sw = c.h*wRatio;
 75 sh = c.w*hRatio;
 76 degree = 90 * Math.PI / 180;
 77 tx = 0;
 78 ty = -200;
 79 /* tx = 0;
 80 ty = -imgH_ori;
 81 canvas.width = imgH_ori;
 82 canvas.height = imgW_ori; */
 83 break;
 84 case 8://需要逆时针(向右)90度旋转
 85 wRatio = imgW_ori/imgH_css;
 86 hRatio = imgH_ori/imgW_css;
 87 sx = (imgH_css-c.y-c.h)*wRatio;
 88 sy = c.x*hRatio;
 89 sw = c.h*wRatio;
 90 sh = c.w*hRatio;
 91 degree = 3 * 90 * Math.PI / 180;
 92 tx = -200;
 93 ty = 0;
 94 /* tx = -imgW_ori;
 95 ty = 0;
 96 canvas.width = imgH_ori;
 97 canvas.height = imgW_ori; */
 98 break;
 99 case 3://需要180度旋转
100 wRatio = imgW_ori/imgW_css;
101 hRatio = imgH_ori/imgH_css;
102 sx = (imgW_css-c.x-c.w)*wRatio;
103 sy = (imgH_css-c.y-c.h)*hRatio;
104 sw = c.w*wRatio;
105 sh = c.h*hRatio;
106 degree = Math.PI;
107 tx = -200;
108 ty = -200;
109 /*tx = -imgW_ori;
110 ty = -imgH_ori;
111 canvas.width = imgW_ori;
112 canvas.height = imgH_ori; */
113 break;
114 }
115 }else{
116 wRatio = imgW_ori/imgW_css;
117 hRatio = imgH_ori/imgH_css;
118 sx = c.x*wRatio;
119 sy = c.y*hRatio;
120 sw = c.w*wRatio;
121 sh = c.h*hRatio;
122 tx = 0;
123 ty = 0;
124 }
125 var tempImage = new Image();//新建一个image对象,用于存放不带exif信息的图像数据,新建image的原因是若直接使用原来的image对象,会有图片展示区域与真实区域错位不一致从而导致无法获取正确的图像源数据
126 tempImage.src = img.src;
127 tempImage.onload = function(){//确保图像加载完毕后再进行下一步,不然可能会导致获取不到图片宽高
128 //将canvas画布的大小设为200x200大小并裁剪成圆形作为头像
129 canvas.width = 200;
130 canvas.height = 200;
131 ctx.arc(100, 100, 100, 0 ,2*Math.PI);
132 ctx.clip();
133 //alert("Orientation:"+Orientation+","+sx+","+sy+","+sw+","+sh+","+tx+","+ty+","+degree);
134 ctx.drawImage(tempImage, sx, sy, sw, sh, 0, 0, 200, 200); //在canvas中将裁剪后图片重新画出来
135 //ctx.drawImage(img, 0, 0, 3024, 4032, 0, 0, 200, 200);
136 var base64 = canvas.toDataURL(‘image/jpeg‘,0.5);
137 //window.open(base64);
138 //2、接下来进行旋转
139 var resultImg = new Image();//新建一个image对象,用于存放截图后的数据
140 resultImg.src = base64;
141 resultImg.onload = function(){
142 if(degree){
143 ctx.rotate(degree);//对方向进行修正
144 }
145 ctx.drawImage(resultImg, tx, ty);
146 pageData.base64 = canvas.toDataURL(‘image/jpeg‘);//将base64码存入全局变量中
147 //window.open(pageData.base64);
148 }
149 }
150 }

这样就拿到了每次截取后的截取区域的正确base64码,当用户点击确定的时候将该数据传给后台即可;

这种前台截取得方式适合用于图像清晰度要求低,否则图像太大还是建议使用输入输出流传给后台后再进行图像处理;优点是前台直接完成了图像处理工作,减轻了服务器的压力,同时能用js实现的为什么要麻烦后台呢对吧。

水平有限,以上经验仅供参考,若有不同意见或建议欢迎一起讨论和学习~

时间: 2024-08-24 15:12:13

移动端web头像上传实现截取和照片方向修复的相关文章

java web 网站头像上传处理 (springmvc +bootstrap+cropper)

制作头像上传.请根据您的实际需求,修改代码,不完全正确,仅供参考! 前端页面设计使用bootstrap ,头像预览和剪裁工具使用cropper 后台使用springmvc. 现在来看前端的页面设计 前端页面设计,自然需要bootstrap .jqury 和cropper ,这可以自行去网上百度查找 剪裁效果图 html 文件 <!DOCTYPE html> <html> <head lang="en"> <meta charset="

web开发经验——富头像上传编辑器的使用

富头像编辑器是一个很好的头像图片上传控件,能够对图片进行简单的处理,例如:剪切.调节亮度等功能:富头像编辑器拥有很的参数配置,可根据自己的需要配置控件的功能:该控件要求浏览器需安装Flash Player后才能使用:下面是我做的一个小的Demo以说明富头像编辑器的使用方法. 1.前台页面 需引用js文件和初始化富头像编辑器,脚本代码如下: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /

java web 站点头像上传处理 (springmvc +bootstrap+cropper)

制作头像上传.请依据您的实际需求.改动代码,不全然正确.仅供參考! 前端页面设计使用bootstrap ,头像预览和剪裁工具使用cropper 后台使用springmvc. 如今来看前端的页面设计 前端页面设计,自然须要bootstrap .jqury 和cropper ,这能够自行去网上百度查找 剪裁效果图 html 文件 <!DOCTYPE html> <html> <head lang="en"> <meta charset="

[Bootstrap-插件使用]Jcrop+fileinput组合实现头像上传功能

很久没有更新博客了,再不写点东西都烂了. 这次更新一个小内容,是两个插件的组合使用,实现头像上传功能. 业务需求: 头像上传功能,要对上传的文件进行剪切,且保证头像到服务器时必须是正方形的. 优化<input type="file">的显示样式,基础的样式实在太难看了. 上传的头像需要进行质量压缩跟大小裁剪,以减缓浏览器的压力. 成果预览: 使用到的技术插件 Jcrop:用于前端"裁剪"图片 bootstrap-fileinput:用于前端优化上传控件样

【Bootstrap-插件使用】Jcrop+fileinput组合实现头像上传功能

作者:Dreawer链接:https://zhuanlan.zhihu.com/p/24465742来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者:梦游的龙猫(转载已获得作者许可) 很久没有更新博客了,再不写点东西都烂了. 这次更新一个小内容,是两个插件的组合使用,实现头像上传功能. 业务需求: 头像上传功能,要对上传的文件进行剪切,且保证头像到服务器时必须是正方形的. 优化<input type="file">的显示样式,基础的样式实

Canvas处理头像上传

未分类 最近社区系统需要支持移动端,其中涉及到用户头像上传,头像有大中小三种尺寸,在PC端,社区用Flash来处理头像编辑和生成,但该Flash控件的界面不友好而且移动端对Flash的支持不好,考虑到这些问题,最后我们选用Canvas来完成图像尺寸缩放和图片数据获取. 等边处理 头像一般都是正方形,首先我们需要获取图片宽度和高度的最小值,用该最小值作为边长居中裁剪图片,最终得到一个正方形的图片: var ImageEditor = function() { // 用离线canvas处理图片数据

Java头像上传方法

import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import java.io.File; import java.io.IOException; /** * Created by Zenz. */ public class Upload { /** * 头像上传 * @param headImage 头像传出文件 * @param reque

使用spring mvc+localResizeIMG实现HTML5端图片压缩上传

最近在做一个移动端HTML5的应用,使用到了上传功能,起初使用传统的上传方式上传手机拍照的照片,由于手机拍照出来的照片一般都是好几MB, 所以上传速度是非常慢的. 在网上找了很久找到了localResizeIMG压缩框架,感觉非常的实用,所以在此分享给大家. 第一步:下载localResizeIMG localResizeIMG放在github中的,地址是:https://github.com/think2011/localResizeIMG. 第二步:在web工程中导入localResizeI

PHP+ajaxfileupload与jcrop插件结合 完成头像上传

昨天花了点时间整合了一下头像插件 东拼西凑的成果 先来看下效果 1.先使用ajaxfileupload插件做异步上传.这个地方我本来想做个上传进度的效果,但技术有限失败了.上传按钮我还做了一个文件大小的限制,但是由于浏览器兼容性的问题,不完美在IE6--IE9之间还有很多问题需要解决 getFileSize函数是用于判断文件大小的函数 function getFileSize(fileName) { var byteSize = 0; //console.log($("#" + fil