上篇文章说到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