上篇文章說到ctx.service.pdf.index.generate(data)方法是核心業務方法。在egg中調用根目錄下service/pdf/index.js下的generate方法。說到這裏先簡單介紹下eggjs。官網地址:https://eggjs.org/zh-cn/basic...。html
Egg.js 爲企業級框架和應用而生,你們應該都知道koa,而 Egg 選擇了 Koa 做爲其基礎框架,在它的模型基礎上,進一步對它進行了一些加強,因此它繼承了koa的洋蔥模型。ios
Egg.js 的特色git
想具體瞭解的同窗能夠自行去官網學習。github
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