node(eggjs)下使用nsq 实现puppteer生成pdf服务(二)

上篇文章说到ctx.service.pdf.index.generate(data)方法是核心业务方法。在egg中调用根目录下service/pdf/index.js下的generate方法。说到这里先简单介绍下eggjs。官网地址:https://eggjs.org/zh-cn/basic...

初识eggjs

Egg.js 为企业级框架和应用而生,大家应该都知道koa,而 Egg 选择了 Koa 作为其基础框架,在它的模型基础上,进一步对它进行了一些增强,所以它继承了koa的洋葱模型。

Egg.js 的特点

想具体了解的同学可以自行去官网学习。

puppteer生成img

Puppeteer 是 Chrome 开发团队在 2017 年发布的一个 Node.js 包,用来模拟 Chrome 浏览器的运行。

由于公司业务需要,很早就开始认识了这个功能强大的家伙。但是不得不说这玩意好用归好用,坑也是异常的多啊,后面我会说一下puppteer遇到的一些坑。由于项目调研过程中发现puppteer直接生成pdf会出现一些坑,然后决定用puppteer生成img然后用canvas转成pdf。

下面进入正题:
这里是利用puppteer生成img

async htmlToImg(url) {
    return new Promise(async (resolve, reject) => {
      try {
        let startTime, endPrintTime
  
        startTime = new Date()
        // 打开内置Chromium浏览器
        const brower = await puppeteer.launch({args: ['--no-sandbox', '--disable-dev-shm-usage']})
        // 打开浏览器一个tab页面
        const page = await brower.newPage()
  
        // 设置窗口参数
        await page.setViewport({
          width: tools.interceptWidth,
          height: tools.interceptHeight,
          deviceScaleFactor: tools.deviceScaleFactor
        })
  
        // 配置浏览器ua,我这里配置了手机模式
        await page.setUserAgent(
          'Mozilla/5.0 (iPhone; CPU iPhone OS 12_1_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16C101 ios/4.10.0'
        )
        
        browerpage = page

        // 让浏览器跳到对应的页面
        await browerpage.goto(url, { waitUntil: 'networkidle0' })
  
  
        const more = await this.moreThanOnePage(browerpage)

        // 判断首页是不是小于tools.interceptHeight
        let lastScrllTop = more === true ? -tools.interceptHeight : -more
        let obj = { scrollTop: 0 }
        let i = 0
  
        // 实例化一个imgToPDF,判断more是为了初始化imgToPdf画布的初始高度
        // 这里是一个canvas把img转pdf的过程,下面会单独说明imgToPdf
        let imgToPdfHeight = more === true ? tools.interceptHeight : more
        let toPdf = new imgToPdf(imgToPdfHeight * tools.deviceScaleFactor)
  
        while(obj.scrollTop > lastScrllTop) {
          let funCanScroll = true
  
          // 最后一页的高度
          let imgToPdfGetHeight = tools.interceptHeight * tools.deviceScaleFactor
  
          //最后一小于tools.interceptHeight情况
  
          if (obj.scrollTop - lastScrllTop < tools.interceptHeight) {
            funCanScroll = false
            // 因为deviceScaleFactor设置为2所以高度要乘以2才是真实高度
            imgToPdfGetHeight = (obj.scrollTop - lastScrllTop) * tools.deviceScaleFactor
  
            await browerpage.setViewport({
              width: tools.interceptWidth,
              height: imgToPdfGetHeight / tools.deviceScaleFactor,
              deviceScaleFactor: tools.deviceScaleFactor
            })
  
            await this.lastScroll(browerpage)
          }
  
          lastScrllTop = obj.scrollTop
  
           // 生成了最终的 buffer流
          let buffer = await browerpage.screenshot({
            type: 'png'
          })

           //   把生成的buffer流图片放在canvas生成的画布上
          await toPdf.set(buffer, imgToPdfGetHeight, i)
  
          i++
  
          obj = await this.scroll(browerpage)
  
          if (!funCanScroll) {
            break
          }
        }
  
        // 关闭内置浏览器
        await brower.close()
        // 导出最终的pdf即toPdf.get(),后面会介绍
        resolve({
          buffer: toPdf.get(),
          ext: 'pdf'
        })
      } catch(e) {
        reject(e)
      }
    })
  }

这里是 imgToPdf类,首先生成一个this.canvas画布。
通过设置set方法把puppteer生成的img的buffer流贴到画布上,然后立即清楚这个buffer流,从而达到减小内存的作用。
最后在上面文件中通过get方法获取最终生成的pdf。

const { createCanvas, loadImage } = require('canvas')

const { tools } = require('../../tools/index')

class imgToPdf {
  constructor(height) {
    // 创建画布大小
    this.canvas = createCanvas(tools.interceptWidth * tools.deviceScaleFactor, height, 'pdf')
    this.ctx = this.canvas.getContext('2d')
  }

  async set(bufferImage, height, index) {
    return new Promise(async (resolve, reject) => {
      try  {
        if (index) {
          this.ctx.addPage(tools.interceptWidth * tools.deviceScaleFactor, height)
        }
        await loadImage(bufferImage).then((image) => {
          this.ctx.drawImage(image, 0, 0)
        })
        resolve(true)
      } catch(e) {
        reject(e)
      }
    })
  }

  get() {
    return this.canvas.toBuffer()
  }
}

exports.imgToPdf = imgToPdf

这里就是大致的puppteer生成img,canvas把img转pdf的整个流程。
相对puppteer更加具体了解请查看:https://zhaoqize.github.io/pu...
详细代码请在我的github中查看:https://github.com/XIEJUNXIRU...

你可能感兴趣的:(eggjs,node.js,puppeteer,canvas)