关于前端:小程序canvas实现图片压缩

原本用小程序写了一个本地化的图片利用,不存在服务端的交互行为

后果提交审核的时候还是被打回了

好的!马上整改

利用的交互大略就是这样

咱们须要在抉择图片后

对图片做一次平安校验

启用云开发

当初咱们须要一个 后端接口 来实现图片的 平安校验 性能

这时候长期搭个Node服务如同不太事实

又不是什么正经我的项目

于是就想到了微信的云开发性能

用起来实在方便快捷

至于图片的校验办法

间接用云函数调用 security.imgSecCheck 接口就好了

流程

chooseImage() {
  /// 用户抉择图片
  wx.chooseImage({
    count: 1,
    sizeType: ['original', 'compressed'],
    sourceType: ['album', 'camera'],
    success: async res => {
      if (res.errMsg === 'chooseImage:ok') {
        wx.showLoading({ title: '图片加载中' })
        // 获取图片长期地址
        const path = res.tempFilePaths[0]
        // 将图片地址实例化为图片
        const image = await loadImage(path, this.canvas)
        // 压缩图片
        const filePath = await compress.call(this, image, 'canvas_compress')
        // 校验图片合法性
        const imgValid = await checkImage(filePath)
        wx.hideLoading()
        if (!imgValid) return
        // 图片平安检测通过,执行后续操作
        ...
    }
  })
}

图片压缩

因为 security.imgSecCheck 对图片有尺寸限度

所以在图片上传前要先对超出尺寸的图片进行压缩解决

根本逻辑就是

超出尺寸的图片等比例放大就好了

咱们先要有一个canvas元素

用来解决须要压缩的图片

<template>
  <view class="menu-background">
    <view class="item replace" bindtap="chooseImage">
      <i class="iconfont icon-image"></i>
      <text class="title">图片</text>
      <text class="sub-title">图片仅供本地应用</text>
    </view>
    //
    // canvas
    //
    <canvas
      type="2d"
      id="canvas_compress"
      class="canvas-compress"
      style="width: {{canvasCompress.width}}px; height: {{canvasCompress.height}}px"
    />
  </view>
</template>

将canvas移到视线不可见到地位

.canvas-compress
    position absolute
    left 0
    top 1000px

图片进行压缩解决

/**
 * 压缩图片
 * 将尺寸超过标准的图片最小限度压缩
 * @param {Image} image 须要压缩的图片实例
 * @param {String} canvasId 用来解决压缩图片的canvas对应的canvasId
 * @param {Object} config 压缩的图片标准 -> { maxWidth 最大宽度, maxHeight 最小宽度 }
 * @return {Promise} promise返回 压缩后的 图片门路
 */
export default function (image, canvasId, config = { maxWidth: 750, maxHeight: 1334 }) {
  // 援用的组件传入的this作用域
  const _this = this
  return new Promise((resolve, reject) => {
    // 获取图片原始宽高
    let width = image.width
    let height = image.height
    // 宽度 > 最大限宽 -> 重置尺寸
    if (width > config.maxWidth) {
      const ratio = width / config.maxWidth
      width = config.maxWidth
      height = height / ratio
    }
    // 高度 > 最大限高度 -> 重置尺寸
    if (height > config.maxHeight) {
      const ratio = height / config.maxHeight
      height = config.maxHeight
      width = width / ratio
    }
    // 设置canvas的css宽高
    _this.canvasCompress.width = width
    _this.canvasCompress.height = height
    const query = this.createSelectorQuery()
    query
      .select(`#${canvasId}`)
      .fields({ node: true, size: true })
      .exec(async res => {
        // 获取 canvas 实例
        const canvas = res[0].node
        // 获取 canvas 绘图上下文
        const ctx = canvas.getContext('2d')
        // 依据设施dpr解决尺寸
        const dpr = wx.getSystemInfoSync().pixelRatio
        canvas.width = width * dpr
        canvas.height = height * dpr
        ctx.scale(dpr, dpr)
        // 将图片绘制到 canvas
        ctx.drawImage(image, 0, 0, width, height)
        // 将canvas图片上传到微信临时文件
        wx.canvasToTempFilePath({
          canvas,
          x: 0,
          y: 0,
          destWidth: width,
          destHeight: height,
          complete (res) {
            if (res.errMsg === 'canvasToTempFilePath:ok') {
              // 返回临时文件门路
              resolve(res.tempFilePath)
            }
          },
          fail(err) {
            reject(err)
          }
        })
      })
  })
}

图片平安校验

云函数 checkImage.js
const cloud = require('wx-server-sdk')
cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV
})
/**
 * 校验图片合法性
 * @param {*} event.fileID 微信云存储的图片ID
 * @return {Number} 0:校验失败;1:校验通过
 */
exports.main = async (event, context) => {
  const contentType = 'image/png'
  const fileID = event.fileID
  try {
    // 依据fileID下载图片
    const file = await cloud.downloadFile({
      fileID
    })
    const value = file.fileContent
    // 调用 imgSecCheck 借口,校验不通过接口会抛错
    // 必要参数 media { contentType, value }
    const result = await cloud.openapi.security.imgSecCheck({
      media: {
        contentType,
        value
      }
    })
    return 1
  } catch (err) {
    return 0
  }
}
组件调用云函数封装
/**
 * 校验图片是否存在敏感信息
 * @param { String } filePath
 * @return { Promise } promise返回校验后果
 */
export default function (filePath) {
  return new Promise((resolve, reject) => {
    // 先将图片上传到云开发存储
    wx.cloud.uploadFile({
      cloudPath: `${new Date().getTime()}.png`,
      filePath,
      success (res) {
        // 调用云函数-checkImage
        wx.cloud.callFunction({
          name: 'checkImage',
          data: {
            fileID: res.fileID
          },
          success (res) {
            // res.result -> 0:存在敏感信息;1:校验通过
            resolve(res.result)
            if (!res.result) {
              wx.showToast({
                title: '图片可能含有敏感信息, 请从新抉择',
                icon: 'none'
              })
            }
          },
          fail (err) {
            reject(err)
          }
        })
      },
      fail (err) {
        reject(err)
      }
    })
  })
}
本文demo

本文代码仓库

https://github.com/luosijie/f…

谢谢浏览!!!

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理