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

最近学习微信小程序,其实对于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
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345