前言
如果你还没有看过我之前写的让你的PDF合成后不再失真文章,那么请你一定先看完后再继续阅读。
因为上一篇文章的延伸,在之前文章的基础上,我们扩展了在pdf内合成文字的功能。
文字是真文字,不是一张图片。
同样的,能够保证pdf的流正确(矢量的pdf)
不想看过程的可以直接跳转到代码部分,Ctrl+C
Ctrl+V
开始
我们还是使用 pdf-lib
库来实现
第一步:注册字体工具
pdfDoc.registerFontkit(fontkit)
,这里需要引入 pdf-lib
自带的fontkit
工具,
第二步:加载字体,并转换成Buffer结构
javaStript
const defaultFontBuffer = await fetch(SIMFANGTTF).then(res =>
res.arrayBuffer()
)
实际上 pdf-lib
提供了好几种字体的引入方式(后面会介绍),这里我们选择最合适的一种
第三步:将Buffer结构的字体嵌入到pdf中
const helveticaFont = await pdfDoc.embedFont(defaultFontBuffer)
- 在此文档中嵌入字体。输入数据可以提供多个
- | 类型 | 描述 |
- | --------------- | ------------------------------------------------------- |
- |
StandardFonts
| pdf-lib自带的标准字体 |- |
string
| 包含字体的 base64 编码字符串(或数据 URI) |- |
Uint8Array
| 字体的原始字节 |- |
ArrayBuffer
| 字体的原始字节 |
js// font=StandardFonts import { StandardFonts } from 'pdf-lib' const font1 = await pdfDoc.embedFont(StandardFonts.Helvetica) // font=string const font2 = await pdfDoc.embedFont('AAEAAAAVAQAABABQRFNJRx/upe...') const font3 = await pdfDoc.embedFont('data:font/opentype;base64,AAEAAA...') // font=Uint8Array import fs from 'fs' const font4 = await pdfDoc.embedFont(fs.readFileSync('Ubuntu-R.ttf')) // font=ArrayBuffer const url = 'https://pdf-lib.js.org/assets/ubuntu/Ubuntu-R.ttf' const ubuntuBytes = await fetch(url).then(res => res.arrayBuffer()) const font5 = await pdfDoc.embedFont(ubuntuBytes)
第四步:在pdf的页面内设置该字体
page.setFont(helveticaFont)
第五步:使用 drawText 方法写入文字
javascript
page.drawText(`${el.src}`, {
x: el.x,
y: el.y,
size: 16, // 字体大小
lineHeight: 16 // 字体行高
})
第一个参数是文字的内容,第二个参数是文字的配置项
注意:这里有个新手容易犯的错误,pdf渲染文字,并不是我们传啥都能显示的,他是一种编码方式,我们文字传递的是
UTF-8
格式,要从字体库里面匹配到对应的编码后,才能将其文字显示出来
字体库这么大,我们要全部引用?
一般常见的字体库都是很庞大的(30+Mb),因为要涉及到世界各个地区的文字、特殊字符等等。
如果我们全量引入的话,工程打包出来的体积就非常大,这是不可取的。
所以这时候我们就得创建一个属于自己的字体库。
创建自己的字体库
推荐使用这个网站来创建
首先我们打开一个现成的字体库,然后我们自己新建一个自己的字体库
然后我们找到我们需要的字体,将他复制一份,然后切到我们自己的字体库,粘贴
如此反复之后,最后下载自己的字体库即可,这里我们选择TTF
的格式
以上就完成了自建字体库,是不是挺简单的!
代码
是基于上篇文章的代码内增加了字体部分的代码,新增的部分用 // +++++++++++++++
注释
js
import { PDFDocument } from "pdf-lib"
// +++++++++++++++
import fontkit from '@pdf-lib/fontkit'
import SIMFANGTTF from './SIMFANG.TTF'
// +++++++++++++++
const getNewPdf = async (pdfBase64, imagesList = []) => {
// 创建新的pdf
const pdfDoc = await PDFDocument.create()
// +++++++++++++++
// 加载字体
pdfDoc.registerFontkit(fontkit)
const defaultFontBuffer = await fetch(SIMFANGTTF).then(res =>
res.arrayBuffer()
)
const helveticaFont = await pdfDoc.embedFont(defaultFontBuffer)
// +++++++++++++++
let page = ""
// 传入的pdf进行格式转换
const usConstitutionPdf = await PDFDocument.load(pdfBase64)
// 获取转换后的每一页数据
const userPdf = usConstitutionPdf.getPages()
// 将每一个数据 导入到我们新建的pdf每一页上
for (let index = 0; index < userPdf.length; index++) {
const [existingPage] = await pdfDoc.copyPages(usConstitutionPdf,[index])
page = pdfDoc.addPage(existingPage)
// +++++++++++++++
page.setFont(helveticaFont)
// +++++++++++++++
// 如果有传入图片,则遍历信息,并将他合成到对应的页码上
const imageSel = imagesList.filter((i) => i.pageIndex === index)
if (imageSel.length > 0) {
for (let idx = 0; idx < imageSel.length; idx++) {
const el = imageSel[idx]
const pngImage = await pdfDoc.embedPng(el.src)
page.drawImage(pngImage, {
x: +el.x,
y: +el.y,
width: +el.width,
height: +el.height,
})
// +++++++++++++++
page.drawText(`${el.src}`, {
x: el.x,
y: el.y,
size: 16, // 字体大小
lineHeight: 16 // 字体行高
})
// +++++++++++++++
}
}
}
// 保存pdf
const pdfBytes = await pdfDoc.save()
// 将arrayButter 转换成 base64 格式
function ArrayBufferToBase64(buffer) {
//第一步,将ArrayBuffer转为二进制字符串
var binary = ""
var bytes = new Uint8Array(buffer)
for (var len = bytes.byteLength, i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i])
}
//将二进制字符串转为base64字符串
return window.btoa(binary)
}
// console.log("data:application/pdf;base64," + ArrayBufferToBase64(pdfBytes))
// 最后将合成的pdf返回
return "data:application/pdf;base64," + ArrayBufferToBase64(pdfBytes)
}
export default getNewPdf