node(eggjs)下使用nsq 實現puppteer生成pdf服務(二)

上篇文章說到ctx.service.pdf.index.generate(data)方法是核心業務方法。在egg中調用根目錄下service/pdf/index.js下的generate方法。說到這裏先簡單介紹下eggjs。官網地址:https://eggjs.org/zh-cn/basic...html

初識eggjs

Egg.js 爲企業級框架和應用而生,你們應該都知道koa,而 Egg 選擇了 Koa 做爲其基礎框架,在它的模型基礎上,進一步對它進行了一些加強,因此它繼承了koa的洋蔥模型。ios

Egg.js 的特色git

想具體瞭解的同窗能夠自行去官網學習。github

puppteer生成img

Puppeteer 是 Chrome 開發團隊在 2017 年發佈的一個 Node.js 包,用來模擬 Chrome 瀏覽器的運行。canvas

因爲公司業務須要,很早就開始認識了這個功能強大的傢伙。可是不得不說這玩意好用歸好用,坑也是異常的多啊,後面我會說一下puppteer遇到的一些坑。因爲項目調研過程當中發現puppteer直接生成pdf會出現一些坑,而後決定用puppteer生成img而後用canvas轉成pdf。api

下面進入正題:
這裏是利用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...koa

相關文章
相關標籤/搜索