前言

在手机上通过网页 input 标签拍照上传图片,有一些手机会出现图片旋转了90度d的问题,包括 iPhone 和个别三星手机。这些手机竖着拍的时候才会出现这种问题,横拍出来的照片就正常显示。因此,可以通过获取手机拍照角度来对照片进行旋转,从而解决这个问题。

Orientation

这个参数并不是所有图片都有的,不过手机拍出来的图片是带有这个参数的。

旋转角度 参数值
1
顺时针90° 6
逆时针90° 8
180° 3

参数为 1 的时候显示正常,那么在这些横拍显示正常,即 Orientation = 1 的手机上,竖拍的参数为 6。

想要获取 Orientation 参数,可以通过 exif.js 库来操作。exif.js 功能很多,体积也很大,未压缩之前足足有 30k,这对手机页面加载来说是非常大影响的。而我只需要获取 Orientation 信息而已,所以我这里删减了 exif.js 库的一些代码,将代码缩小到几KB。

exif.js 获取 Orientation :

EXIF.getData(file, function() {  var Orientation = EXIF.getTag(this, 'Orientation'); });

file 则是 input 文件表单上传的文件。上传的文件经过 fileReader.readAsDataURL(file) 就可以实现预览图片了,这方面不清楚的可以查看:HTML5 进阶系列:文件上传下载

旋转

旋转需要用到 canvas 的 rotate() 方法。

ctx.rotate(angle);

rotate 方法的参数为旋转弧度。需要将角度转为弧度:degrees * Math.PI / 180

旋转的中心点默认都在 canvas 的起点,即 ( 0, 0 )。旋转的原理如下图:

旋转原理图

旋转之后,如果从 ( 0, 0 ) 点进行 drawImage(),那么画出来的位置就是在左图中的旋转 90 度后的位置,不在可视区域呢。旋转之后,坐标轴也跟着旋转了,想要显示在可视区域呢,需要将 ( 0, 0 ) 点往 y 轴的反方向移 y 个单位,此时的起始点则为 ( 0, -y )。

同理,可以获得旋转 -90 度后的起始点为 ( -x, 0 ),旋转 180 度后的起始点为 ( -x, -y )。

压缩

手机拍出来的照片太大,而且使用 base64 编码的照片会比原照片大,那么上传的时候进行压缩就非常有必要的。现在的手机像素这么高,拍出来的照片宽高都有几千像素,用 canvas 来渲染这照片的速度会相对比较慢。

因此第一步需要先对上传照片的宽高做限制,判断宽度或高度是否超出哪个范围,则等比压缩其宽高。

var ratio = width / height;
if(imgWidth > imgHeight && imgWidth > xx){imgWidth = xx;imgHeight = Math.ceil(xx / ratio);
}else if(imgWidth < imgHeight && imgHeight > yy){ imgWidth = Math.ceil(yy * ratio); imgHeight = yy; }

第二步就通过 canvas.toDataURL() 方法来压缩照片质量。

canvas.toDataURL("image/jpeg", 1);

toDataURL() 方法返回一个包含图片展示的 data URI 。使用两个参数,第一个参数为图片格式,默认为 image/png。第二个参数为压缩质量,在指定图片格式为 image/jpeg 或 image/webp的情况下,可以从 0 到 1 的区间内选择图片的质量。

总结

综合以上,例子的代码包括精简的exif.js库地址:file-demo

主要的核心代码如下:

<input type="file" id="files" > <img src="blank.gif" id="preview"> <script src="small-exif.js"></script> <script> var ipt = document.getElementById('files'), img = document.getElementById('preview'), Orientation = null; ipt.onchange = function () { var file = ipt.files[0], reader = new FileReader(), image = new Image(); if(file){ EXIF.getData(file, function() { Orientation = EXIF.getTag(this, 'Orientation'); }); reader.onload = function (ev) { image.src = ev.target.result; image.onload = function () { var imgWidth = this.width, imgHeight = this.height; // 控制上传图片的宽高 if(imgWidth > imgHeight && imgWidth > 750){ imgWidth = 750; imgHeight = Math.ceil(750 * this.height / this.width); }else if(imgWidth < imgHeight && imgHeight > 1334){ imgWidth = Math.ceil(1334 * this.width / this.height); imgHeight = 1334; } var canvas = document.createElement("canvas"), ctx = canvas.getContext('2d'); canvas.width = imgWidth; canvas.height = imgHeight; if(Orientation && Orientation != 1){ switch(Orientation){ case 6: // 旋转90度 canvas.width = imgHeight; canvas.height = imgWidth; ctx.rotate(Math.PI / 2); // (0,-imgHeight) 从旋转原理图那里获得的起始点 ctx.drawImage(this, 0, -imgHeight, imgWidth, imgHeight); break; case 3: // 旋转180度 ctx.rotate(Math.PI); ctx.drawImage(this, -imgWidth, -imgHeight, imgWidth, imgHeight); break; case 8: // 旋转-90度 canvas.width = imgHeight; canvas.height = imgWidth; ctx.rotate(3 * Math.PI / 2); ctx.drawImage(this, -imgWidth, 0, imgWidth, imgHeight); break; } }else{ ctx.drawImage(this, 0, 0, imgWidth, imgHeight); } img.src = canvas.toDataURL("image/jpeg", 0.8); } } reader.readAsDataURL(file); } } </script>

更多文章:lin-xin/blog

移动端图片上传旋转、压缩的解决方案相关推荐

  1. php 图片压缩旋转,移动端图片上传旋转、压缩问题的解决方案

    本篇文章就给大家带来移动端图片上传旋转.压缩问题的解决方案.有一定的参考价值,有需要的朋友可以参考一下,希望对你们有所帮助. 前言 在手机上通过网页 input 标签拍照上传图片,有一些手机会出现图片 ...

  2. 为什么手机上传图片这么慢 前端_移动端图片上传旋转、压缩的解决方案

    前言 在手机上通过网页 input 标签拍照上传图片,有一些手机会出现图片旋转了90度d的问题,包括 iPhone 和个别三星手机.这些手机竖着拍的时候才会出现这种问题,横拍出来的照片就正常显示.因此 ...

  3. 移动端图片上传后进行压缩功能

    移动端图片上传后进行压缩功能 在进行讲解上传图片压缩之前,我们先来了解下HTML5中的文件上传的基本知识点. 一: FileList对象与file对象. FileList对象表示用户选择的文件列表.在 ...

  4. 移动端图片上传解决方案localResizeIMG先压缩后ajax无刷新上传

    现在科技太发达,移动设备像素越来越高,随便一张照片2M+,但是要做移动端图片上传和pc上略有不同,移动端你不能去限制图片大小,让用户先处理图片再上传,这样不现实.所以理解的解决方案就是在上传先进行图片 ...

  5. JavaScript移动端图片上传方法

    移动端图片上传方法 实现效果 文件下载 http://files.cnblogs.com/files/sntetwt/%E7%A7%BB%E5%8A%A8%E7%AB%AF%E5%9B%BE%E7%8 ...

  6. php 实现图片上传并压缩功能

    前段时间由于项目需要,要实现图片上传并且压缩生成缩略图的功能. 接口代码如下: $allowext = array ( 'png', 'jpg', 'jpeg', 'gif','mp4','doc') ...

  7. vue移动端图片上传

    一.服务端环境准备 本文服务端主要为nodejs,利用multer中间件完成图片上传功能.服务端安装express框架和multer. npm install express --save npm i ...

  8. 移动端图片上传裁切(版权归秒为所有,仅为搬运)

    <!DOCTYPE html> <html lang="en"> <head> <meta name="viewport&quo ...

  9. vue图片上传及压缩组件的封装

    vue图片上传及压缩组件的封装 源码地址 使用方法: 先去上面的链接把组件,复制到自己的components文件夹内 1.先下载 cnpm install compressorjs --save-de ...

最新文章

  1. nginx的tmp文件过大导致磁盘空间不足一例
  2. 为所有PHP-FPM容器构建单独的NGinx Dock镜像
  3. php 挂马 密码123456,admin密码-常用密码加密md5值,123456,admin,admin888
  4. [1025]Noip 2009 Problem 2
  5. java多线程总结五:线程池的原理及实现
  6. 2020最后一天,送出家里书架全部好书,随意挑
  7. 【Android】dip、dp、sp、pt和px的区别
  8. Yii实现分页的两种方法
  9. springMVC 相对于 Structs 的优势
  10. 查看代码 index.html,Javascript查看大图功能代码实现
  11. Excel VBA 重要参考(原始的VBA代码)
  12. [转载]监控 Linux 性能的 18 个命令行工具
  13. 常用制作钓鱼网站的工具
  14. 微信小程序js数组倒序reverse
  15. 05.尚硅谷网课5-样式继承与其他概念
  16. 好嗨哟,这5个超牛的资源网站,让你轻松无忧找资源!
  17. IDEA创建JavaWeb项目配置
  18. Centos7安装fish shell,介绍及使用
  19. 电子元器件封装(3D或2D)下载攻略
  20. 继电保护整定值计算软件_继电保护整定电流

热门文章

  1. debian6更新网卡驱动
  2. [译]高效的TensorFlow 2.0:应用最佳实践以及有什么变化
  3. sed 每次只替换一行
  4. 第1条:考虑用静态工厂方法代替构造器
  5. [译] 沙箱中的间谍 - 可行的 JavaScript 高速缓存区攻击
  6. TabBarItem图片不显示的原因
  7. wpf slider 控件模板
  8. 从ASP.NET得到Microsoft Word文档
  9. python构建一个简单的备份脚本
  10. Python处理大数据