让你的PDF合成后不再失真2-文字合成

前言

如果你还没有看过我之前写的让你的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),因为要涉及到世界各个地区的文字、特殊字符等等。

如果我们全量引入的话,工程打包出来的体积就非常大,这是不可取的

所以这时候我们就得创建一个属于自己的字体库。

创建自己的字体库

推荐使用这个网站来创建

tophix.com/assets/js/f...

首先我们打开一个现成的字体库,然后我们自己新建一个自己的字体库

然后我们找到我们需要的字体,将他复制一份,然后切到我们自己的字体库,粘贴

如此反复之后,最后下载自己的字体库即可,这里我们选择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

结束!

相关推荐
Jiaberrr8 分钟前
Element UI教程:如何将Radio单选框的圆框改为方框
前端·javascript·vue.js·ui·elementui
Tiffany_Ho1 小时前
【TypeScript】知识点梳理(三)
前端·typescript
安冬的码畜日常2 小时前
【D3.js in Action 3 精译_029】3.5 给 D3 条形图加注图表标签(上)
开发语言·前端·javascript·信息可视化·数据可视化·d3.js
太阳花ˉ2 小时前
html+css+js实现step进度条效果
javascript·css·html
小白学习日记2 小时前
【复习】HTML常用标签<table>
前端·html
john_hjy3 小时前
11. 异步编程
运维·服务器·javascript
风清扬_jd3 小时前
Chromium 中JavaScript Fetch API接口c++代码实现(二)
javascript·c++·chrome
丁总学Java3 小时前
微信小程序-npm支持-如何使用npm包
前端·微信小程序·npm·node.js
yanlele3 小时前
前瞻 - 盘点 ES2025 已经定稿的语法规范
前端·javascript·代码规范