移动端上传照片 预览+Draw on Canvas's Demo(解决 iOS 等设备照片旋转 90 度的 bug)
背景:
本人的一个移动端H5项目,需求如下:
需求二:然后绘制在canvas画布上
这里,我们先看一个demo(http://jsfiddle.net/q3011893/83qfqpk8/embedded/)
需求二:drawPhoto方法
操作步骤:

1、点击选择文件,拍摄一张照片,此时"预览:"文字下会显示你刚才拍摄的照片;
2、再点击"draw on Canvas",该按钮下的画布会绘制你刚才拍摄的照片。
正常的结果:

--------------------------------------------------------------------------------------------------------
正文:
- <input accept="image/*" type="file" id="file" />
- //有一些特殊的安卓机还需要加上 capture="camera" 属性才能支持拍照
2、需求一的预览功能使用html5提供的新API:FileReader
介绍:
FileReader接口提供了一个异步API,使用该API可以在浏览器主线程中异步访问文件系统,读取文件中的数据。
API文档:
https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader
兼容性:
主流浏览器都支持。除了IE有点问题,详情看下图:
使用方法(使用drawTempPhoto方法实现需求一):
- //绘制照片
- function drawTempPhoto() {
- //检验是否为图像文件
- var file = document.getElementById("file").files[0];
- if (!/image\/\w+/.test(file.type)) {
- alert("看清楚哦,这个需要图片!");
- return false;
- }
- var reader = new FileReader();
- //将文件以Data URL形式读入页面
- reader.readAsDataURL(file);
- reader.onload = function (e) {
- //预览效果
- var img = $("#photo")[0];
- //加载图片,此处的this.result为base64格式
- img.src = this.result;
- }
- }
注:

在本人的三星note5的手机中,需求一会出现照片预览逆时针旋转90度的bug(其实用下面介绍的的exif.js方法,可以知道iOS和三星所拍的照片Orientation值都是6,而前者做了预览的修正,后者则直接显示了出来,导致了旋转)。
解决方案:
判断是否为三星手机设备,然后把预览的图片顺时针旋转90度恢复正常(例如可以用canvas技术模拟预览效果)。
于是修改的drawTempPhoto方法如下【line:21-27】:
- //绘制照片
- function drawTempPhoto() {
- //检验是否为图像文件
- var file = document.getElementById("file").files[0];
- if (!/image\/\w+/.test(file.type)) {
- alert("看清楚哦,这个需要图片!");
- return false;
- }
- var reader = new FileReader();
- //将文件以Data URL形式读入页面
- reader.readAsDataURL(file);
- reader.onload = function (e) {
- //预览效果
- var img = $("#photo")[0];
- //加载图片,此处的this.result为base64格式
- img.src = this.result;
- img.onload = function(){
- //获取照片的拍摄方向
- var orient = getPhotoOrientation(img);
- alert("orient1:" + orient);
- //判断是否是三星手机
- // if (isSamsung) {
- // 做旋转的适配……
- // }
- };
- }
- }
在iOS上,表现如下:

可见,在iOS上第一张图正常,而第二张图逆时针旋转了90度,而其他的安卓两步都是正常的显示。
那我们来看看exif.js是什么?
介绍:
Exif.js 提供了 JavaScript 读取图像的原始数据的功能扩展,例如:拍照方向、相机设备型号、拍摄时间、ISO 感光度、GPS 地理位置等数据。
兼容性:
EXIF 数据主要来自拍摄的照片,多用于移动端开发,PC 端也会用到,此插件兼容主流浏览器,IE10 以下不支持。
下载地址:
这里我们知道了exif.js其实是获取一张拍摄照片的元信息的,进而获取它最初的拍照方向,这很可能跟iOS图片旋转的bug有关。
而exif.js提供的一张照片的Orientation属性如下:

解决方案:
1、我首先引入exif.js:
- <script src="./js/exif.js"></script>
2、然后封装成getPhotoOrientation方法:
- //获取照片的元信息(拍摄方向)
- function getPhotoOrientation(img){
- var orient;
- EXIF.getData(img, function () {
- orient = EXIF.getTag(this, 'Orientation');
- });
- return orient;
- }
3、分别在操作步骤一选择图片和操作步骤二draw on Canvas,Alert照片的Orientation值,本人的测试机有限,请见谅,结果如下:
|
手机型号 |
Orientation值 |
|
iphone 6S |
|
|
小米4S |
undefined |
|
华为荣耀4A |
1 |
|
PC |
undefined |
可以看到,小米4S和PC都是undefined,表示图片没有拍摄方向或者根本没记录,华为荣耀4A是1,表示的是正确的方向,以上都没问题。但iphone 6S为6!所以之所以出现了图片的旋转,是因为它本身的Orientation就不正常!!
因此解决这个bug的思路是:获取到照片拍摄的方向,对ios照片进行角度旋转修正。
修改后的demo(http://jsfiddle.net/q3011893/k3z5ev26/embedded/)
除了上面引入的exif.js和添加的getPhotoOrientation方法,我又修改了drawPhoto方法:
①旧drawPhoto方法:
- //绘制照片
- function drawPhoto(photo, x, y, w, h) {
- var canvas = document.getElementById("canvas");
- if (canvas.getContext) {
- var ctx = canvas.getContext("2d");
- //draw on Canvas
- var img = new Image();
- img.onload = function () {
- var canvas_w = Number(ctx.canvas.width);
- var canvas_h = Number(ctx.canvas.height);
- // 执行Canvas的drawImage语句
- ctx.drawImage(img, x, y, w, h);
- }
- img.src = photo.src; // 设置图片源地址
- }
- }
②新drawPhoto方法【line:4-6,19-30】:
- //绘制照片
- function drawPhoto(photo, x, y, w, h) {
- //获取照片的拍摄方向
- var orient = getPhotoOrientation(photo);
- alert("orient2:"+orient);
- var canvas = document.getElementById("canvas");
- if (canvas.getContext) {
- var ctx = canvas.getContext("2d");
- //draw on Canvas
- var img = new Image();
- img.onload = function () {
- var canvas_w = Number(ctx.canvas.width);
- var canvas_h = Number(ctx.canvas.height);
- //判断图片拍摄方向是否旋转了90度
- if (orient == 6) {
- ctx.save();//保存状态
- ctx.translate(canvas_w / 2, canvas_h / 2);//设置画布上的(0,0)位置,也就是旋转的中心点
- ctx.rotate(90 * Math.PI / 180);//把画布旋转90度
- // 执行Canvas的drawImage语句
- ctx.drawImage(img, Number(y) - canvas_h / 2, Number(x) - canvas_w / 2, h, w);//把图片绘制在画布translate之前的中心点,
- ctx.restore();//恢复状态
- } else {
- // 执行Canvas的drawImage语句
- ctx.drawImage(img, x, y, w, h);
- }
- }
- img.src = photo.src; // 设置图片源地址
- }
- }
运行结果如下:

完美~
移动端上传照片 预览+Draw on Canvas's Demo(解决 iOS 等设备照片旋转 90 度的 bug)的更多相关文章
- hTML5实现表单内的上传文件框,上传前预览图片,针刷新预览images
hTML5实现表单内的上传文件框,上传前预览图片,针刷新预览images, 本例子主要是使用HTML5 的File API,建立一個可存取到该file的url, 一个空的img标签,ID为img0,把 ...
- html之file标签 --- 图片上传前预览 -- FileReader
记得以前做网站时,曾经需要实现一个图片上传到服务器前,先预览的功能.当时用html的<input type="file"/>标签一直实现不了,最后舍弃了这个标签,使用了 ...
- 【转】HTML5 jQuery图片上传前预览
hTML5实现表单内的上传文件框,上传前预览图片,针刷新预览images,本例子主要是使用HTML5 的File API,建立一個可存取到该 file的url,一个空的img标签,ID为img0,把选 ...
- ASP.NET MVC图片上传前预览
回老家过春节,大半个月,在家的日子里,吃好睡好,人也长了3.5Kg.没有电脑,没有网络,无需写代码,工作上相关的完全放下......开心与父母妻儿过个年,那样的生活令Insus.NET现在还在留恋.. ...
- Jcrop+uploadify+php实现上传头像预览裁剪
最近由于项目需要,所以做了一个上传头像预览并且可以预览裁剪的功能,大概思路是上传的图片先保存到服务器,然后通过ajax从服务器获取到图片信息,再利用Jcrop插件进行裁剪,之后通过PHP获取到的四个裁 ...
- 图片上传本地预览。兼容IE7+
基于JQUERY扩展,图片上传预览插件 目前兼容浏览器(IE 谷歌 火狐) 不支持safari 预览地址:http://www.jinbanmen.com/test/1.html js代码:/**名称 ...
- js上传和预览图片
[1].[代码] [HTML]代码 跳至 [1] <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ...
- DevExpress控件使用系列--ASPxUploadControl(图片上传及预览)
1.控件功能 列表控件展示数据.弹框控件执行编辑操作.Tab控件实现多标签编辑操官方说明 2.官方示例 2.1 ASPxImage http: ...
- HTML5 jQuery图片上传前预览
hTML5实现表单内的上传文件框,上传前预览图片,针刷新预览images,本例子主要是使用HTML5 的File API,建立一個可存取到该file的url,一个空的img标签,ID为img0,把选择 ...
随机推荐
- 谷歌浏览器允许ajax跨域以非安全模式打开
最近使用ajax的时候,因为是在本地测试调用 后台时一直会报错. 解决方案:用谷歌浏览器 以非安全的模式打开 在cmd命令行中 cd 到谷歌的安装目录下 (右键 属性 复制路径) 然后在 运行如下命令 ...
- python将图片转换为Framebuffer裸数据格式(终端显示图片)
要在ubuntu终端显示图片或者在板子的LCD显示图片,Framebuffer是一个简单易用的接口,直接写入像素信息即可. 但普通的图片带有头部信息或者编码格式不同,直接送入Framebuffer是显 ...
- USACO翻译:USACO 2012 JAN三题(1)
USACO 2012 JAN(题目一) 一.题目概览 中文题目名称 礼物 配送路线 游戏组合技 英文题目名称 gifts delivery combos 可执行文件名 gifts delivery c ...
- 《寒江独钓_Windows内核安全编程》中修改类驱动分发函数
最近在阅读<寒江独钓_Windows内核安全编程>一书的过程中,发现修改类驱动分发函数这一技术点,书中只给出了具体思路和部分代码,没有完整的例子. 按照作者的思路和代码,将例子补充完整,发 ...
- First Day:Starting My Coding Road
今天是2015年7月28日,星期二,晴,下午坐在科创园2楼的办公室里,窗明几净,继续我全新的Android之旅! 在调试和比较了N多IDE集成开发环境之后,最终决定在IDEA SDK环境下试试手,在已 ...
- Asp.Net Core 发布和部署( MacOS + Linux + Nginx )
前言 在上篇文章中,主要介绍了 Dotnet Core Run 命令,这篇文章主要是讲解如何在Linux中,对 Asp.Net Core 的程序进行发布和部署. 有关如何在 Jexus 中进行部署,请 ...
- Azure 新的管理模式 —— Resource Manager
var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...
- 谈谈对Spring IOC的理解
学习过Spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的,今天和大家 ...
- 从零3D基础入门XNA 4.0(1)——3D开发基础
[题外话] 最近要做一个3D动画演示的程序,由于比较熟悉C#语言,再加上XNA对模型的支持比较好,故选择了XNA平台.不过从网上找到很多XNA的入门文章,发现大都需要一些3D基础,而我之前并没有接触过 ...
- C语言 · 特殊回文数
问题描述 123321是一个非常特殊的数,它从左边读和从右边读是一样的. 输入一个正整数n, 编程求所有这样的五位和六位十进制数,满足各位数字之和等于n . 输入格式 输入一行,包含一个正整数n. 输 ...
