美文网首页微信小程序开发微信小程序开发前端-全栈
微信小程序OCR客户端到服务端的实现

微信小程序OCR客户端到服务端的实现

作者: 维子Vanessa | 来源:发表于2022-08-18 15:36 被阅读0次

    最近学习微信小程序,其实对于ocr研究过程中的具体实现做个一个整理

    • 需求
    • 前期准备
    • 思路导图
    • 代码实现

    1.需求

    微信小程序拍照或者识别图片中的文字内容

    2.前期准备

    2.1 客户端微信小程序: appid, secret 用来获取access_token

    image.png

    2.2 基于nodejs开发的服务端(express, mongondb)

    2.3 小程序添加OCR插件

    image.png

    2.4 注意点: 一定要配置uploadFile域名,不然wx.uploadFile上传图片无法返回数据

    image.png

    3. 思维导图

    image.png

    4. 实现

    4.1 小程序

    server.js 对整个app网络请求封装的工具

    const baseUrl = 'https://XXXXXX.cn'
    const getHttp = (url, data, success, fail, complete) => {
      wx.request({
        url: baseUrl+url,
        data: data,
        header: {
          "Content-Type": "application/json"
        },
        success: success,
        fail: fail,
        complete: complete
      })  
    }
    const getToken = () => {
      return new Promise((resolve, reject) => {
        getHttp("/getToken", null, (res) => {
          resolve(res)
        }, null, null); 
      })
    }
    
    module.exports = {
      ...
      getToken: getToken
    }
    
    1. app.js 程序启动获取接口调用凭据
    App({
      onLaunch: function (val) {
          const getAccessToken = function () {
                let tokenRes = server.getToken()
                let tokenResData = tokenRes.data
                if (tokenResData.status === 0) {
                    let token = tokenResData.data
                    wx.setStorageSync('token', token)
                }  else {
                  wx.showToast({
                    title: '获取api token失败',
                  })
                }
          }
        getAccessToken()
      }
    })
    
    1. 解析图片页面实现
    chooseImg: async function () {
        var self = this
        const getAccessToken = async function () {
          return new Promise((resolve, reject) => {
            let token = wx.getStorageSync('token')
            resolve(token)
          })
        }
      
        const chooseImage = async function () {
          return new Promise((resolve, reject) => {
            wx.chooseMedia({
              count: 1,
              mediaType: 'image',
              sizeType: ['original', 'compressed'],
              sourceType: ['album', 'camera'],
              success(res) {
                // tempFilePaths可以作为img标签的src属性显示图片,回调结果
                const tempFilePaths = res.tempFiles
                resolve(tempFilePaths[0])
              }
            })
          })
        }
    
        // 1. 选择图片
        let temp = await chooseImage()
        if (!temp) return
        self.setData({
          searching: true
        })
        // 2. 获取api access_token
        let accessToken = await getAccessToken()
        if (!accessToken) {
          self.setData({
            searching: false
          })
          return
        }
        let url = server.baseUrl+'/parseImage?access_token='+accessToken
        // 3. 上传图片
        wx.uploadFile({
          url: url,
          filePath: temp.tempFilePath,
          name: 'img',
          formData: {
             contentType: 'image/png',
             value:"",
          },
          success (res){
            let parseData = JSON.parse(res.data)
            if (parseData.status === 0 && parseData.data && parseData.data.items && parseData.data.items.length > 0) {
              let {items} = parseData.data
              // item即解析出的图片文字数组,包含文字的位置信息以及内容
            } else {
              wx.showToast({
                title: '图片解析失败',
              })
            }
          },
          fail (err) {
            self.setData({
              items: newItems,
              searching: false
            })
            wx.showToast({
              title: '图片上传失败',
            })
          }
        })
        
      }
    

    4.2 服务端

    由于小程序代码中不能暴露appid和secret,不然审核不通过,因此把这俩参数记录在服务端
    先获取OCR需要的参数之一: access_token

    • 第一步:获取access_token
      router.get('/getToken', function (req, res) {
          let url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appId+"&secret="+appSerect
          let p = new Promise((resolve, reject) => {
            https.get(url, (response) => {
              let todo = '';
              // called when a data chunk is received.
              response.on('data', (chunk) => {
                todo += chunk;
              });
              // called when the complete response is received.
              response.on('end', () => {
                let resData = JSON.parse(todo)
                resolve(resData)
              });
            }).on("error", (error) => {
              reject(error)
              // console.log("Error: " + error.message);
            });
          })  
          p.then(_ => {
            // console.log(_.access_token)
            res.send_data({
                  status: 0,
                  data: Base64.encode(_.access_token) // 加密返回
            });
          })
      });
    
    • 第二步: 解析图片内容

    1.把上传的图片保存到服务器,返回一个获取图片地址的url
    2.根据上一步获取的url+access_token,调用api解析图片

      router.post('/parseImage', function (req, res) {
          if (!req.files)
                return res.status(400).send('No image were uploaded.');
          let img = req.files.img;
          // 1. 图片写入本地(简单化处理,返回的其实就是图片的名称)
          let writeP = OrderItem.uploadImage(img)
          // 2. 拼接图片地址传给小程序解析图片的api
          writeP.then(_ => {
            // 2.1 解析图片地址
            let imageLocalPath = _.data ? _.data : ''
            // 获取图片地址的url,作为参数传给微信小程序api,会根据url加载图片
            let imgPath = `https://XXXXXXX.cn/api/write/image/${imageLocalPath}`
            // 2.2 解析token(之前返回客户端的是加密后的,因此这里解密之后传入)
            let token = Base64.decode(req.query.access_token)
            let wxurl = 'https://api.weixin.qq.com/cv/ocr/comm?access_token='+token+'&img_url='+imgPath
            axios({
              url: wxurl,
              method: 'post'
            })
            .then(parseData => {
              // 3. 删除本地图片
              OrderItem.deleteImage(_.data, (err) => {
                console.log(err)
              })
              res.send_data({
                status: 0,
                data: parseData.data
              });
              return _
            })
            .catch(error => {
              // console.error(error);
              res.send_data({
                status: 400,
                data: error
              });
              return _
          });
      })
    

    读取图片实现

      // route.js文件
      router.get('/write/image/:path',function(req, res) {
          let path = req.params.path
          if (!path) 
              return res.status(400).send('No image path were read.');
    
          res.writeHead(200,{'Content-Type':'image/jpeg'});
          OrderItem.readImage(req.params.path).then(file => {
            res.write(file,'binary');
            res.end();
          })
      })
    

    OrderItem.js文件

    const fs = require('fs')
    
    function uploadImage(img) {
      // 写入本地
      let path = `${__dirname}/../../write/${img.name}`;
      return new Promise((resolve, reject) => {
        fs.writeFile(path, img.data, 'binary', (err) => {
          if (err) {
            console.log('写入文件错误')
            reject({
              data: false
            })
          } else {
            console.log('写入文件成功')
            resolve({
              data: Base64.encode(img.name) 
            })
          }
        })
      })
    }
    function readImage(path) {
        let imageName = Base64.decode(path)
        return new Promise((resolve, reject) => {
          fs.readFile(`${__dirname}/../../write/${imageName}`,'binary',function(err,file){
            if(err){
                console.log(err);
                reject(err)
                return;
            }else{
                console.log('输出图片');
                resolve(file)
            }
          })
        })
    }
    module.exports = {
        ...
        uploadImage,
        readImage,
        deleteImage
    }
    

    相关文章

      网友评论

        本文标题:微信小程序OCR客户端到服务端的实现

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