关于前端上传文件全面基础扫盲贴(零)
关于前端上传文件全面基础扫盲贴(一) ----- XMLHttpRequest
关于前端上传文件全面基础扫盲贴(二) ----- File
关于前端上传文件全面基础扫盲贴(三) ----- FormData
关于前端上传文件全面基础扫盲贴(四) ----- FileReader
关于前端上传文件全面基础扫盲贴(五) ----- H5拖拽事件
关于前端上传文件全面基础扫盲贴(六) ----- 图片上传,旋转,重绘,预览等实战(附DEMO)javascript
距离我上次写的系列文章好像都过了半年了,废话很少说,先来展现一下技术思路html
1、获取用户照片数据前端
2、编辑合成照片java
3、保存并上传照片
提交base64数据到服务器须要服务器支持,我跳过了。node
由于通常手机像素都很高,因此把原始图片尺寸限制在300里;git
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <meta name="format-detection" content="telphone=no, email=no"> <meta name="renderer" content="webkit"> <meta name="HandheldFriendly" content="true"> <meta name="screen-orientation" content="portrait"> <meta name="x5-orientation" content="portrait"> <title></title> <style media="screen"> * { margin: 0; padding: 0; } img { display: block; } </style> </head> <body> <div class='upload'> <input type="file" id='file' capture="camera" accept="image/*"> <label id="upload1"></label> <p>原始图片</p> <img class="old" width="300"> <p>修改图片</p> <img class="new"> </div> <script type="text/javascript"> window.onload = function () { var dom = document.getElementById('file'); dom.addEventListener('change', function (e) {}); } </script> </body> </html>
想要上传图片,就要用type="file"
得到文件信息,其中下面几个重要属性,(在pc浏览器打开文件要好久,因此能够选择性屏蔽)github
属性 | 描述 |
---|---|
accept | 表示能够选择的文件MIME类型,多个MIME类型用英文逗号分开 |
multiple | 是否能够选择多个文件,多个文件时其value值为第一个文件的虚拟路径 |
capture | 表示,能够捕获到系统默认的设备,好比:camera --照相机;camcorder --摄像机;microphone --录音 |
<input type="file" id='file' capture="camera" accept="image/*">
经过监听input变化触发方法web
window.onload = function () { var dom = document.getElementById('file'); dom.addEventListener('change', function (e) {}); }
Exif.js 提供了 JavaScript 读取图像的原始数据的功能扩展,例如:拍照方向、相机设备型号、拍摄时间、ISO 感光度、GPS 地理位置等数据。
EXIF 数据主要来自拍摄的照片,多用于移动端开发,PC 端也会用到,此插件兼容主流浏览器,IE10 如下不支持。npm
<script src="https://cdn.jsdelivr.net/npm/exif-js"></script>
为了避免让用户等待过久,咱们能够在一系列操做以前先展现获取的图片,能够直接从本地先读取出原始数据,而后在页面上展现出来,下面用到的知识点以前已经写过就再也不重复了,能够前往浏览文章
关于前端上传文件全面基础扫盲贴(二) ----- File
关于前端上传文件全面基础扫盲贴(四) ----- FileReadercanvas
var file = e.target.files[0], //旋转角度 orientation = null, fReader = new FileReader(); //限制大小格式 if (!filtration(file)) { return false; }
上面的filtration(file)是我抽离出去的过滤函数
filtration: function(file, extend) { var extend = extend || {}, settings = { size: extend.size || 5 * 1024 * 1024, reg: extend.reg || /image\/\w+/ }; if (file.size > settings.size || !settings.reg.test(file.type)) { alert(extend.msg || ('上传格式非图片类型或上传图片超过' + settings.size / 1024 / 1024 + 'M')) return false; } return true; },
接下来要获取图片信息了,解决部分手机会有旋转角度的问题的前提(可能连接格式问题,生成文章以后没带连接,只能本身复制粘贴访问地址了)
中文文档: http://code.ciaoca.com/javasc...
Demo: http://code.ciaoca.com/javasc...
EXIF.getData(file, function () { orientation = EXIF.getTag(this, 'Orientation'); console.log('旋转角度: ', orientation); });
咱们已经拿到原始数据,result
属性中将包含一个data: URL
格式的字符串以表示所读取文件的内容.而后新建img对象加载资源
//转码完成 fReader.onload = function (e) { //加载图片 var img = new Image(); img.src = e.target.result; img.onload = function () { } } //执行 fReader.readAsDataURL(file);
接着咱们使用canvas画布从新设定尺寸重绘达到压缩的功能,我只用到基础使用方法,详情(Canvas API)
var canvas = document.createElement('canvas'), ctx = canvas.getContext('2d'), nSize = resetSize(this, 300, 300, 1, 600); canvas.width = nSize.width; canvas.height = nSize.height; ctx.drawImage(this, 0, 0, nSize.width, nSize.height);
上面的resetSize
是我自定义的一个方法,能够设置高宽比例最大范围值,可能有点繁琐,由于我想控制的功能比较多,中间容易发生冲突,我暂时是后面设置能覆盖前面设置(注意:这里的this是上文的data: URL
格式)
resetSize: function(img, width, height, ratio, max) { var w = img.naturalWidth, h = img.naturalHeight, width = width || w, height = height || h; console.log('图片宽高: ', w, h, '入参: ', width, height, ratio, max); if (w != width) w = width; if (h != height) h = height; if (ratio && w / h != ratio) w = h * ratio; //限制最大值范围 if (max) { if (w > max && w >= h) { h = Math.ceil(h * max / w); w = max; } else if (h > max && h >= w) { w = Math.ceil(w * max / h); h = max; } } console.log('重设宽高: ', w, h); return { width: w, height: h } },
接下来就是比较复杂的图形操做了,只要掌握了中心点位置就还好理解,详情(HTML 5 Canvas 参考手册)
上面拿到的orientation不是真的旋转角度,只是给一个值表明拍摄方向,
最后返回新图片展现的 data URI,这里水比较深,我测试了jpg和png是没问题,可是gif什么的就输出一个静态图,详情(toDataURL)
var canvas = document.createElement('canvas'), ctx = canvas.getContext('2d'), nSize = picProcess.resetSize(this, 600, 400); switch (+ orientation) { case 3: canvas.width = nSize.width; canvas.height = nSize.height; ctx.rotate(180 * Math.PI / 180); ctx.drawImage(this, -nSize.width, -nSize.height, nSize.width, nSize.height); break; case 6: canvas.width = nSize.height; canvas.height = nSize.width; ctx.rotate(90 * Math.PI / 180); ctx.drawImage(this, 0, -nSize.height, nSize.width, nSize.height); break; case 8: canvas.width = nSize.height; canvas.height = nSize.width; ctx.rotate(270 * Math.PI / 180); ctx.drawImage(this, -nSize.width, 0, nSize.width, nSize.height); break; default: canvas.width = nSize.width; canvas.height = nSize.height; ctx.drawImage(this, 0, 0, nSize.width, nSize.height); break; } return canvas.toDataURL(file.type, 0.8);
如今回看上面,咱们已经实现了获取图片,重绘图片,读取本地图片,剩下就是预览了,我简单实现一个支持id和class的方法,也能判断出img和div智能设置展现方式
preview: function(selector, url) { var isId = /^#\w+/ig.test(selector), isClass = /^\.\w+/ig.test(selector), name = selector.slice(1), dom = null; //选择器类型 if (isId) { dom = document.getElementById(name); } else if (isClass) { dom = document.getElementsByClassName(name)[0]; } else { alert('选择器传参不支持!'); return false; } //判断类型 if (dom.nodeName == 'IMG') { dom.src = url; } else { dom.style.backgroundImage = 'url(' + url + ')'; }; }
而后咱们在监听方法里调用就行了.为了更加直观的看到代码效果,我简单写了一个demo版本,能够直接下载本地运行,不依赖任何环境实战Demo
你们且看且珍惜吧,我可能后续还会研究手势旋转处理之类更加复杂的东西,但也说很差,毕竟仍是太懒散了.循例仍是得加上一句,由于都没有很深刻测试过,因此确定会有些隐藏的问题,欢迎你们指出最好还有答案咯