移动端图片操作(二)——预览、旋转、合成

简介: 在上一节中已经提到了预览,预览可以通过data: URL格式或URL对象。

在上一节中已经提到了预览,预览可以通过data: URL格式或URL对象。


var file = upload.files[0];
//URL对象
var url = URL.createObjectURL(file);
var img = new Image();
img.style.width = '100%';
img.src = url;
img.onload = function(e) {
  window.URL.revokeObjectURL(this.src); //销毁
}


//data:URL格式
var img = new Image();
img.style.width = '100%';
var reader = new FileReader();
reader.onload = function() {
  img.src = this.result;
};
reader.readAsDataURL(file);


一切都很顺利,但其实有很多的坑,需要慢慢讲来。先从前面做的一个小功能说起。

这个小功能就是将两张图片合成起来,组成一张新的图片

 

一、技术实现


1)上传的控件就用“input[type=file]”实现


Android的webview不支持此控件,怪不得按钮怎么按都按不动,后面只得用客户端提供的接口做上传

期间发现UC浏览器会自动将上传控件包装成三个按钮的样子,只需设置为“opacity:0;”即可。


43.jpg

2)使用“FileReader”,通过方法readAsDataURL获取data URL格式的图片内容,赋值给image。

IOS在上传图片或拍照的时候,显示出来的宽高是反的,这个时候我们增加了一步旋转的操作,让用户自己来控制。

在给image赋src值的同时,赋“crossOrigin”的值,用于后面的图片跨域

3)将图片画在“canvas”上,旋转其实也就是转这个canvas。通过计算坐标和角度实现旋转

4)将旋转后的“canvas”与剩下的两张文字图片,通过一个新的“canvas”合并到一起。

在将两个“canvas”画在一起后,发现通过webview上传的图片,不能使用“toDataURL()”方法了,这是因为画布被污染,第一个画布中的图片是跨域的。

5)最后将data URL格式的内容上传到服务器中保存。

总共开发时间是3天,在这个过程中有过几次技术推翻重做或者逻辑重整,兼容性方面也还有很大问题,包括图片的宽高的自适应等,还很不完善。

下图是最终效果,挑了张松狮的写真照:


44.jpg


二、预览


原先我在做的时候,第2步和第3布是合在一起的,也就是图片显示出来的时候,已经校准好位置。

只是在实现的过程中碰到了很多麻烦,并且时间仓促,BUG修复起来比较费时,只得分两步。

先说说原先的过程


1)IOS图片上传或拍照,宽高相反


我用的是Android手机,刚开始并没有发现这个问题,后面别人帮忙测试的时候,才发现了这个重大问题,接下来就是折腾这个事儿,想要自动校正方向。

1. 通过exif.js获取图片元数据,通过获取“Orientation”属性判断方向【我的Android机中这个属性为undefined,IOS有值】,总共有8个值


45.jpg46.gif


左边是说明,右边是展示。表格中带“*”的是指翻转过来了。

接下来就是做计算,网上有很多计算方式,对于“>IOS7”的系统,计算逻辑可以参考下localResizeIMG插件195行

顺便说下,这个插件使用到了gulp的开发方式,如果要调试就要配置相关代码,可以参考《前端自动化构建工具gulp记录

插件中还大量使用了Promises/A+规范,关于这个规范可以参考《JavaScript中Promises/A+规范的实现


exif.getData(typeof file === 'object' ? file : img, function() {
  orientation = exif.getTag(this, "Orientation");
  //计算逻辑....
});


2. “<=IOS7”系统的计算方式略有不同。IOS6中图片拍照上传会被压扁(当照片超过2M时),这是IOS6的BUG,较大的图片可能会发生。

计算逻辑也可以参考localResizeIMG插件165行。要解决这个BUG需要引入megapix-image.js


require(['megapix-image'], function(MegaPixImage) {
  var mpImg = new MegaPixImage(img);
  //计算逻辑
});


47.jpg


2)将画布“canvas”通过方法“toDataURL”,变成data URL格式

1. 在手机QQ浏览器中,canvas对象使用toDataURL方法获取不到任何数据,需要引用jpeg-encoder.js解决。


var cvs = document.createElement('canvas');
var ctx = cvs.getContext("2d");
ctx.drawImage(theImg, 0, 0);
var theImgData = ctx.getImageData(0, 0, cvs.width, cvs.height);
// Encode the image and get a URI back, toRaw is false by default
var jpegURI = encoder.encode(theImgData, quality);


在开发的时候方向自动旋转花了很多时间。碰到各种问题,例如“orientation”属性获取不到、自动旋转的角度不对。

后面贪简单,就找了个canvasResize插件,虽然会自动校正,但是图片有点模糊,而且图片的宽高不容易控制。效果不尽如意,只好分两步做。


最终的过程


1)添加旋转页面


先计算起始坐标点X与Y,简单点就是宽度和高度各除以2,再通过canvas的“translate”,再用“rotate”计算角度。在“drawImage”的时候X和Y点变成负数,移位过去。


var xpos = canvas_width / 2;
var ypos = canvas_height / 2;
ctx.translate(xpos, ypos);
ctx.rotate(angle * Math.PI / 180);
ctx.drawImage(rotate_img, -width / 2, -height / 2, width, height);


48.jpg


三、合成


在上图中点击确认就会自动合成。


)图片宽高自适应


画布的宽高只做了简单的比率,画布的宽度除以图片的宽度,我把头部的图片和底部的图片宽度都做的相同,下图所示:


49.jpg

50.png


var multiple = width / header.width;//画布宽度除以图片宽度
var header_height = header.height * multiple;//顶部图片
var footer_height = footer.height * multiple;//底部图片
var footer_y = canvas_height - footer_height;


2)将顶部与底部图片、与上一个旋转后的canvas画一起在第二个画布上

ctx.drawImage(rotate_canvas, 0, 0, width, height);
ctx.drawImage(header, 0, 25, width, header_height);
ctx.drawImage(footer, 0, footer_y, width, footer_height);


这里碰到了一个画布污染的问题。上面的“rotate_canvas”,图片的获取有两种,一个是通过“file”控件上传的,另一个是在webview提供的接口上传的。

两个唯一的不同是跨域,第二个接口返回的是另外一个域名中的图片。图片跨域了,那么rotate_canvas也算是跨域了。

跨域的话,会影响“toDataURL()”方法。这个时候就需要img图片跨域。

1. 图片设置crossOrigin属性,这是一个HTML5属性,兼容性不是很好,测试了几台Android机,有的行,有的不行。“crossOrigin”属性设置要在“src”之前,否则IOS不可使用


rotate_img.crossOrigin = "Anonymous";


2. 服务器需要设置,可以正确响应 Access-Control-Allow-Origin 头。

调试的时候,如果服务器还没配置,可以用Fiddler模拟响应头。

a. 先找到filter选项


51.jpg


b. 设置请求头

52.jpg


c. 设置响应头,注意与请求头中的内容要一模一样,少个“http”都不行


53.jpg



相关文章
|
6月前
|
Android开发 开发者
Android开发之通过渲染纹理展示地球仪
该文阐述了如何使用OpenGL为三维物体添加纹理,以增强其真实感。纹理坐标是二维的,用于标记摊平后的“布料”对应物体的哪个部位,类似裁缝制作衣服的过程。在OpenGL中,启用纹理和深度测试是关键,还包括设置纹理参数、分配纹理编号、绑定位图材质等步骤。计算材质的纹理坐标后,通过`glDrawArrays`结合顶点和纹理坐标逐个贴图。最终示例展示了将世界地图贴到球体上形成逼真的地球仪效果。通过控制旋转、平移和缩放,能实现简单的三维动画效果。
76 2
Android开发之通过渲染纹理展示地球仪
|
6月前
|
索引
【sgPhotoPlayer】自定义组件:图片预览,支持点击放大、缩小、旋转图片
【sgPhotoPlayer】自定义组件:图片预览,支持点击放大、缩小、旋转图片
|
移动开发 前端开发 JavaScript
【移动端】实现相册的上传和缩放裁剪
做项目时,在移动端,需要实现用户相册图片的上传,并对图片进行缩放裁剪的功能。下面说一下实现流程。
219 1
【移动端】实现相册的上传和缩放裁剪
图片和文件预览组件(部分源码),可拖动,缩小,放大。 #41
图片和文件预览组件(部分源码),可拖动,缩小,放大。 #41
146 0
【图片操作】给图片添加滤镜
现在我们都喜欢给图片添加滤镜,现在很多相机也自带了许多滤镜。我们可以在拍照的时候选择需要的滤镜。但是有时候我们需要给大量图片添加同样的滤镜,这个时候手动添加就非常麻烦了。为了方便,我们可以使用程序来帮我们完成添加滤镜的操作。
263 0
|
编解码 算法 计算机视觉
案例分享:Qt内窥镜相机录像程序(打开摄像头、支持多种摄像头、分辨率调整、翻转、旋转、亮度调整、拍照、录像、回放图片、回放录像)
案例分享:Qt内窥镜相机录像程序(打开摄像头、支持多种摄像头、分辨率调整、翻转、旋转、亮度调整、拍照、录像、回放图片、回放录像)
案例分享:Qt内窥镜相机录像程序(打开摄像头、支持多种摄像头、分辨率调整、翻转、旋转、亮度调整、拍照、录像、回放图片、回放录像)
|
JavaScript 前端开发 API
使用copper实现图片在线裁剪
2017年写的文章,搬运一下,用cropper实现图片的裁剪。
2730 3
使用内置摄像头并优化显示结果大图片的方法
使用内置摄像头并优化显示结果大图片的方法
122 0
|
前端开发 HTML5 移动开发
移动端图片上传旋转、压缩的解决方案
在手机上通过网页 input 标签拍照上传图片,有一些手机会出现图片旋转了90度d的问题,包括 iPhone 和个别三星手机。这些手机竖着拍的时候才会出现这种问题,横拍出来的照片就正常显示。
1283 0