H5拍照上传填坑汇总

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

内容简介:最近工作一直在使用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;

}
复制代码

参考


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

查看所有标签

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

Build Your Own Web Site the Right Way Using HTML & CSS

Build Your Own Web Site the Right Way Using HTML & CSS

Ian Lloyd / SitePoint / 2006-05-02 / USD 29.95

Build Your Own Website The Right Way Using HTML & CSS teaches web development from scratch, without assuming any previous knowledge of HTML, CSS or web development techniques. This book introduces you......一起来看看 《Build Your Own Web Site the Right Way Using HTML & CSS》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

SHA 加密
SHA 加密

SHA 加密工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具