本来用小程序写了一个本地化的图片应用,不存在服务端的交互行为
结果提交审核的时候还是被打回了
应用的交互大概就是这样
我们需要在选择图片后
对图片做一次安全校验
现在我们需要一个 后端接口 来实现图片的 安全校验 功能
这时候临时搭个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) } }) }) }) }
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) } }) }) }
https://github.com/luosijie/f...