H5拍照上传填坑汇总

栏目: Html5 · 发布时间: 5年前

内容简介:最近工作一直在使用vue+vux做移动端项目,有一个拍照上传照片的需求,发现vux里并没有实现,调研过非官方的其实网上已经可以找到很多已经实现的成熟方案,但是在调研这个需求的时候,我发现在各种实现方案中也有一些puzzle的知识点,因此自己动手撸了一个轮子组件的交互功能要求如下:

最近工作一直在使用vue+vux做移动端项目,有一个拍照上传照片的需求,发现vux里并没有实现,调研过非官方的 vux-uploader 后,感觉还不是很理想。

其实网上已经可以找到很多已经实现的成熟方案,但是在调研这个需求的时候,我发现在各种实现方案中也有一些puzzle的知识点,因此自己动手撸了一个轮子 vux-uploader-component ,并记录一二。

需求

组件的交互功能要求如下:

  1. html5调用手机相机
  2. 渲染图片为缩略图
  3. 前端压缩图片
  4. 预览大图
  5. 删除当前图片
  6. 自动上传

部分关键技术点的实现方案

  1. 使用html media capture调用手机端的相机

    <input type="file" accept="image/*"  capture />
    复制代码

    既然是在HTML5规范中,那最关心的问题肯定是兼容性了

    H5拍照上传填坑汇总

    html-media-capture

    可以看到,在大部分的主流平台,兼容性还可以接受, andriod 2-4 都支持,只是在 ios 6-10支持不太好。

    感兴趣的可以在自己的手机上测测兼容性

    H5拍照上传填坑汇总

    html-media-capture demo

  2. 使用 ULR.createObjectURL 获取图片地址

    blobURL = ULR.createObjectURL(object)
    复制代码

    object参数可以为 FileBlobMediaSource

    在这一块可以衍生出好几个问题:

    • 已知获取图片地址的方法有 URL.createObjectURLFileReader.readAsDataURL ,那应该使用哪个?为什么?
    • IOS 中拍照获取的图片会自动旋转,为什么?怎么解决?
    • FileBlob 是什么关系? Blob URLData URL 又有什么区别? Data URL 怎么转换成 Blob ?
  3. 使用 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之间的 encoderOptions

      dataURL = canvas.toDataURL("image/jpeg", encoderOptions)
      复制代码

    最后生成的图片大小 = 原图大小 * ratio * encoderOption

  4. 使用 FormData 来上传

    const formData = new FormData()
    formData.append('file', blob)
    复制代码

    这是 XHR Level2的产物 ,可以方便的以键值对的形式插入。

    最大的优势是可以通过 XMLHttpRequest.send() 来异步提交二进制文件。

    后期还可以通过 Blobslice 来扩展分片上传功能。

知识点剖析

FileReader和URL.createObjectURL的区别

关于 FileReaderURL.createObjectURL 的用法就不详细介绍了,感兴趣的自行google。

我们现在只需要知道

  • 通过 FileReader.readAsDataURL(file) 可以获取一段 data:base64 的字符串

  • 通过 URL.createObjectURL(blob) 可以获取当前文件的一个内存 URL

既然这两个API都可以满足我们获取图片地址的需求,那它们之间的 区别 在哪呢?

1、执行时机

createObjectURL
FileReader.readAsDataURL

2、内存使用

  • createObjectURL 返回一段带 hashurl ,并且一直存储在内存中,直到 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

目前只有 jpeg 格式的图片会有

H5拍照上传填坑汇总

: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,支持 FileBlob 两种格式。

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;

}
复制代码

参考


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Growth Hack 這樣做

Growth Hack 這樣做

Xdite / PCuSER電腦人文化 / 2016-5-7 / 300.00台幣

◎具體教你在預算有限的情況之下,把成長做出來的可行與必要方法! ◎帶動台灣成長駭客話題的專業講師,親授讓產品突破80分的成長秘笈 @這本書要給誰看? 1. 創業者、個人品牌經營者,想要提高自己服務轉換率的人。 2. 空有產品,但是賣不出去,花了錢投廣告卻效果低落的人。 @這本書有什麼不一樣? 1.全球最重要的趨勢,台灣最知名的 Growth Hack 講師 Xd......一起来看看 《Growth Hack 這樣做》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

在线进制转换器
在线进制转换器

各进制数互转换器