内容简介:最近工作一直在使用vue+vux做移动端项目,有一个拍照上传照片的需求,发现vux里并没有实现,调研过非官方的其实网上已经可以找到很多已经实现的成熟方案,但是在调研这个需求的时候,我发现在各种实现方案中也有一些puzzle的知识点,因此自己动手撸了一个轮子组件的交互功能要求如下:
最近工作一直在使用vue+vux做移动端项目,有一个拍照上传照片的需求,发现vux里并没有实现,调研过非官方的 vux-uploader 后,感觉还不是很理想。
其实网上已经可以找到很多已经实现的成熟方案,但是在调研这个需求的时候,我发现在各种实现方案中也有一些puzzle的知识点,因此自己动手撸了一个轮子 vux-uploader-component ,并记录一二。
需求
组件的交互功能要求如下:
- html5调用手机相机
- 渲染图片为缩略图
- 前端压缩图片
- 预览大图
- 删除当前图片
- 自动上传
部分关键技术点的实现方案
-
使用html media capture调用手机端的相机
<input type="file" accept="image/*" capture /> 复制代码
既然是在HTML5规范中,那最关心的问题肯定是兼容性了
可以看到,在大部分的主流平台,兼容性还可以接受,
andriod2-4 都支持,只是在ios6-10支持不太好。感兴趣的可以在自己的手机上测测兼容性
-
使用
ULR.createObjectURL获取图片地址blobURL = ULR.createObjectURL(object) 复制代码
object参数可以为
File、Blob、MediaSource在这一块可以衍生出好几个问题:
- 已知获取图片地址的方法有
URL.createObjectURL和FileReader.readAsDataURL,那应该使用哪个?为什么? - 在
IOS中拍照获取的图片会自动旋转,为什么?怎么解决? -
File和Blob是什么关系?Blob URL和Data URL又有什么区别?Data URL怎么转换成Blob?
- 已知获取图片地址的方法有
-
使用
canvas来压缩图片可以从两个方面可以进行压缩:
-
取一个最大宽度的限制对图片的宽高尺寸进行等比例的缩小
canvas.width = Math.min(image.naturalWidth, option.maxWidth) const ratio = canvas.width / image.naturalWidth canvas.height = image.naturalHeight * ratio 复制代码
-
canvas.toDataURL指定生成jpeg或者webp格式的图片,可以指定0-1之间的encoderOptionsdataURL = canvas.toDataURL("image/jpeg", encoderOptions) 复制代码
最后生成的图片大小 = 原图大小 *
ratio*encoderOption。 -
-
使用
FormData来上传const formData = new FormData() formData.append('file', blob) 复制代码这是
XHRLevel2的产物 ,可以方便的以键值对的形式插入。最大的优势是可以通过
XMLHttpRequest.send()来异步提交二进制文件。后期还可以通过
Blob的slice来扩展分片上传功能。
知识点剖析
FileReader和URL.createObjectURL的区别
关于 FileReader 和 URL.createObjectURL 的用法就不详细介绍了,感兴趣的自行google。
我们现在只需要知道
-
通过
FileReader.readAsDataURL(file)可以获取一段data:base64的字符串 -
通过
URL.createObjectURL(blob)可以获取当前文件的一个内存URL
既然这两个API都可以满足我们获取图片地址的需求,那它们之间的 区别 在哪呢?
1、执行时机
createObjectURL FileReader.readAsDataURL
2、内存使用
-
createObjectURL返回一段带hash的url,并且一直存储在内存中,直到document触发了unload事件(例如:document close)或者执行revokeObjectURL来释放。 -
FileReader.readAsDataURL则返回包含很多字符的base64,并会比blob url消耗更多内存,但是在不用的时候会自动从内存中清除(通过垃圾回收机制)
3、兼容性
createObjectURL FileReader.readAsDataURL
从上面答案不难看出,两者的优劣势
- 使用
createObjectURL可以节省性能并更快速,只不过需要在不使用的情况下手动释放内存 - 如果不太在意设备性能问题,并想获取图片的
base64,则推荐使用FileReader.readAsDataURL
参考
相机拍照的图片会旋转
从上面的 createObjectURL 获取到图片的地址后,我们可以插入到页面元素的 background-image 属性展示这个图片,PC端模拟器展示没有问题,但手机真机拍照得到的图片会有逆时针的90°旋转。
为什么从相机拍照获取的图片会旋转呢?
是因为从相机拍照获取的图片的EXIF(Exchangeable image file format)会默认设置一个 orientation tag
:point_up_2:上图就是 orientation tag 与图片旋转角度的对应关系
如何解决这个问题呢?
1、获取图片的 orientation
- 需要考虑兼容的话,建议使用 Exif.js
- 如果不希望有外部依赖,而且对兼容性要求不是那么高的话,可以利用
DataView来获取,详情见 stackoverflow高赞回答
2、根据图片的 orientation 做对应的旋转
switch (orientation) {
case 2:
// horizontal flip
ctx.translate(width, 0);
ctx.scale(-1, 1);
break;
case 3:
// 180 rotate left
ctx.translate(width, height);
ctx.rotate(Math.PI);
break;
case 4:
// vertical flip
ctx.translate(0, height);
ctx.scale(1, -1);
break;
case 5:
// vertical flip + 90 rotate right
ctx.rotate(0.5 * Math.PI);
ctx.scale(1, -1);
break;
case 6:
// 90 rotate right
ctx.rotate(0.5 * Math.PI);
ctx.translate(0, -height);
break;
case 7:
// horizontal flip + 90 rotate right
ctx.rotate(0.5 * Math.PI);
ctx.translate(width, -height);
ctx.scale(-1, 1);
break;
case 8:
// 90 rotate left
ctx.rotate(-0.5 * Math.PI);
ctx.translate(-width, 0);
break;
复制代码
参考
File和Blob的关系?Blob Url和DataURL的区别?DataURL如何转成Blob?
File和Blob的关系
从 input onchange 中返回的图片对象其实就是一个 File 对象。
而 Blob 对象是一个用来包装二进制文件的容器, File 继承于 Blob 。
FileReader 是用来读取内存中的文件的API,支持 File 和 Blob 两种格式。
Blob Url和Data URLs的区别
Blob Url 只能在浏览器中通过 URL.createObjectURL(blob) 创建,当不使用的时候,需要 URL.revokeObjectURL(blobURL) 来进行释放。
可以简单理解为对应浏览器内存文件中的软链接。该链接只能存在于浏览器单一实例或对应会话中(例如:页面的生命周期)
blobURL = URL.createObjectURL(blob) // blob:http://localhost:8000/xxxxxxxx 复制代码
Data URLs 可以获取文件的 base64 。
data:[<mediatype>][;base64],<data> 复制代码
mediatype 是个 MIME 类型的字符串,例如 " image/jpeg " 表示 JPEG 图像文件。如果被省略,则默认值为 text/plain;charset=US-ASCII
可以通过 FileReader.readAsDataURL 获取
const reader = new FileReader();
reader.addEventListener("load", e => {
const dataURL = e.target.result;
})
reader.readAsDataURL(blob);
复制代码
DataURL如何转成Blob?
function dataURItoBlob(dataURI) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
var byteString = atob(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
// create a view into the buffer
var ia = new Uint8Array(ab);
// set the bytes of the buffer to the correct values
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
// write the ArrayBuffer to a blob, and you're done
var blob = new Blob([ab], {type: mimeString});
return blob;
}
复制代码
参考
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 拍照聚焦和曝光,AVFoundation 简明教程
- [译]WebRTC基础实践 - 9. 拍照并传给对方
- HTML5拍照、摄像机功能实战
- Javascript+PHP实现在线拍照功能_百度文库
- H5 和小程序拍照图片旋转、压缩和上传
- iOS调用UIImagePickerController相机拍照图片旋转了90度
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Effective Modern C++ 简体中文版
Scott Meyers / 高博 / 中国电力出版社 / 2018-4-23 / 99
想要彻底理解C++11和C++14,不可止步于熟悉它们引入的语言特性(例如,auto型别推导、移动语义、lambda表达式以及并发支持)。挑战在于高效地运用这些特性——从而使你的软件具备正确性、高效率、可维护性和可移植性。这正是这本实用的图书意欲达成的定位。它描述的正是使用C++11和C++14——现代C++来撰写真正卓越的软件之道。 涵盖以下主题: 大括号初始化、noexcept规格......一起来看看 《Effective Modern C++ 简体中文版》 这本书的介绍吧!