美文网首页
小程序拍照压缩上传全攻略

小程序拍照压缩上传全攻略

作者: 回调的幸福时光 | 来源:发表于2019-04-29 20:35 被阅读0次

    前言

    以小程序 【识花君】为例子,分析下在小程序中如何实现拍照压缩上传。

    识花君

    一、camera 和 cover-view、cover-image 组件

    首先分析如何实现类似的设计:

    1. 引用 camera 组件,并且通过样式设置宽高为全屏。(拓展:可以在样式中设置宽高,或者定位来调整相机组件在页面中的大小以及位置。)
    2. 以 cover-view 为父容器设置定位,以嵌套的 cover-image 引用图片

    说明:

    • 为什么不直接对 cover-image,而要使用 在外面嵌套一层 cover-view ?
      答:因为对 cover-image 设置定位样式后,在真机上无效。基础库 1.9.90 起最外层 cover-view 支持 position: fixed 。
    • cover-image 使用本地图片路径会存在问题
      答:图标路径,支持临时路径、网络地址(1.6.0起支持)、云文件ID(2.2.3起支持)。暂不支持base64格式。

    二、从相册选取

    点击相册图标时,触发事件调用 wx.chooseImage(Object object) 即可。

    三、拍照

    • 图片 api :wx.chooseImage(Object object)
    • 相机 api :CameraContext.takePhoto(Object object)

    四、压缩

    现在的智能手机拍出的照片,很容易达到 5M 左右,上传时不仅占用带宽,且速度慢。

    小程序提供了 3 种方式可压缩图片:

    1. 选择照片时指定图片的尺寸或者拍照时指定成像质量
      经过测试,如果对压缩要求比较高,这种方法是不行的,因为压缩效果不显著。
    2. wx.compressImage(Object object)
      局限性:仅对 jpg 有效。实际业务中包含 pngjpg 等多种格式。
    3. 通过 canvas 来曲线救国

    原理:将一张大尺寸的图片通过 canvas 的提供的 drawImage() 方法绘制到小尺寸的画布上,再通过 canvasToTempFilePath 将画布内容生成图片,就完成了大尺寸到小尺寸的转换,完成了压缩。

    步骤

    • wx.getSystemInfoSync() 获取设备像素比
    • wx.chooseImg() 或者 CameraContext.takePhoto 获取图片
    • wx.getImageInfo() 获取图片信息,并检测图片是否超过指定尺寸
    • drawImage() 绘制图片到画布
    • draw()
    • wx.canvasToTempFilePath() 将画布内容生成图片

    说明:为什么需要设备像素比??

    看下不处理设备像素比时,普通屏和二倍屏的对比,只关注 width 即可

    pixelRatio = 1 pixelRatio = 2

    在高倍屏上面,1px 对应的物理像素会比普通屏幕更多,这就导致通过 drawImage() 方法绘制时,虽然在 css
    层面设置的宽高是一致的,比如(w: 300px),如果普通屏(pixelRatio: 1) 1px = 1 个物理像素,那么在二倍屏 (pixelRatio: 2) 上面 1 px = 4 个物理像素(宽是2, 高是2),所以实际上是将图片的宽绘制为 300 * 2 个物理像素,这时使用
    canvasToTempFilePath() 生成图片的宽度是 600, 而不是期望的 300

    设备像素比对 px 和物理像素的关系图

    主要代码
    模板 部分 (以下为 mpvue 中的语法)

    <canvas class="canvas-hidden" :style="{width: cWidth + 'px', height: cHeight + 'px'}" canvas-id="CanvasId"/>
    

    js 部分

    pixelRatio 通过 wx.getSystemInfoSync() 获取。

    // 将图片绘制到画布上
    drawImage(file) {
       const ctx = wx.createCanvasContext('CanvasId');
       wx.getImageInfo({
          src: file,
          success: (res) => {
            if (res.width > 300 || res.height > 300) { // 判断图片是否超过300像素
              this.cWidth = 300 / this.pixelRatio;
              this.cHeight = 300 / this.pixelRatio / scale;
              // 画出压缩图片
              ctx.drawImage(file, 0, 0, this.cWidth, this.cHeight);
              ctx.draw();
              setTimeout(() => {
                this.canvasToImg();
              }, 3000);
            } else {
              this.upload(file);
            }
          }
        });
      },
    // 将画布内容转成图片
    canvasToImg() {
       wx.canvasToTempFilePath({
          canvasId: 'CanvasId',
          success: (res) => {
            // 上传图片
         this.upload(res.tempFilePath);
         }
       });
     },
    

    五、兼容性

    1. 小米 android 9.0 版本无法渲染出 https 协议的图片。
      解决方案:前端强制转换成 http 。
    2. CanvasContext.draw(boolean reserve, function callback)
      callback 在某些机型上面无效。(当前基础库 2.6.5)
      解决方案:draw 之后强制 setTimeout 3s ,然后再去执行 wx.canvasToTempFilePath(Object object, Object this)

    2019/5/13 更改
    解决方案:通过wx.getSystemInfoSync()获取当前设备信息,其中的 platform 字段代表当前系统类型

    • ios
    CanvasContext.draw(false, () => {
      wx.canvasToTempFilePath(Object object, Object this)
    })
    
    • android
      draw 之后强制 setTimeout 3s ,然后再去执行 wx.canvasToTempFilePath(Object object, Object this)

    3: 对 canvas 应用样式 visibility 无效
    解决方案: 通过 left: -9999; 或者 tranlateX() 改变位置,移至不可见区域。

    相关文章

      网友评论

          本文标题:小程序拍照压缩上传全攻略

          本文链接:https://www.haomeiwen.com/subject/cscunqtx.html