上篇文章说到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...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。