Using nsq to generate pdf service with puppeter under node (eggjs)

The last article said ctx.service.pdf.index.generate(data) method is the core business method. Call service/pdf/ in root directory in egg index.js The generate method under. Let's talk about eggjs. Official website address:

Get to know eggjs

Egg.js Born for enterprise framework and application, we should all know Koa, and egg chose Koa as its basic framework, based on its model, further enhanced it, so it inherited the onion model of Koa.

Egg.js Characteristics of

Students who want to know more can go to the official website to study.

Puppeter generates img

Puppeter was released by the chrome development team in 2017 Node.js Package to simulate the operation of Chrome browser.

Because of the company's business needs, I began to know this powerful guy early. But I have to say that it's easy to use and put it back to use. There are many pits, too. I'll talk about some pits that Popper encountered later. In the process of project investigation, it was found that there would be some holes in generating pdf directly by puppeter, and then it was decided to generate img by puppeter and convert it to pdf by canvas.

Let's go to the main topic:
Here is the use of puppeter to generate img

async htmlToImg(url) {
    return new Promise(async (resolve, reject) => {
      try {
        let startTime, endPrintTime
        startTime = new Date()
        // Open the built-in Chrome browser
        const brower = await puppeteer.launch({args: ['--no-sandbox', '--disable-dev-shm-usage']})
        // Open a tab page of browser
        const page = await brower.newPage()
        // Set window parameters
        await page.setViewport({
          width: tools.interceptWidth,
          height: tools.interceptHeight,
          deviceScaleFactor: tools.deviceScaleFactor
        // Configure the browser ua, I have configured the mobile mode here
        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

        // Let browser jump to corresponding page
        await browerpage.goto(url, { waitUntil: 'networkidle0' })
        const more = await this.moreThanOnePage(browerpage)

        // Judge whether the home page is less than tools.interceptHeight
        let lastScrllTop = more === true ? -tools.interceptHeight : -more
        let obj = { scrollTop: 0 }
        let i = 0
        // Instantiate an imgToPdf and judge more to initialize the initial height of the imgToPdf canvas
        // Here is a process of converting img to pdf by canvas. imgToPdf will be described separately below
        let imgToPdfHeight = more === true ? tools.interceptHeight : more
        let toPdf = new imgToPdf(imgToPdfHeight * tools.deviceScaleFactor)
        while(obj.scrollTop > lastScrllTop) {
          let funCanScroll = true
          // Height of last page
          let imgToPdfGetHeight = tools.interceptHeight * tools.deviceScaleFactor
          //Last less than tools.interceptHeight situation
          if (obj.scrollTop - lastScrllTop < tools.interceptHeight) {
            funCanScroll = false
            // Because deviceScaleFactor is set to 2, the actual height is multiplied by 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
           // The final buffer stream is generated
          let buffer = await browerpage.screenshot({
            type: 'png'

           //   Put the generated buffer stream image on the canvas generated by canvas
          await toPdf.set(buffer, imgToPdfGetHeight, i)
          obj = await this.scroll(browerpage)
          if (!funCanScroll) {
        // Close built-in browser
        await brower.close()
        // Exporting the final pdf is toPdf.get(), later
          buffer: toPdf.get(),
          ext: 'pdf'
      } catch(e) {

Here is the imgToPdf class. First, generate a this.canvas Canvas.
By setting the set method, the buffer stream of img generated by puppeter is pasted on the canvas, and then the buffer stream is immediately clear, so as to reduce the memory.
Finally, get the final generated pdf through the get method in the above file.

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

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

class imgToPdf {
  constructor(height) {
    // Create canvas size
    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)
      } catch(e) {

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

exports.imgToPdf = imgToPdf

Here is the general process of generating img by puppeter, and converting img to pdf by canvas.
For more details about puppeter, please refer to:
Please check the detailed code in my github.

Tags: node.js Mobile less github Mac

Posted on Fri, 19 Jun 2020 06:35:49 -0400 by snake310