Appearance
pdf-lib
支持以下功能
从头开始创建 PDF 文档,或修改现有的 PDF 文档。绘制文本、图像和矢量图形。嵌入您自己的字体。甚至可以嵌入和绘制其他 PDF 中的页面。
添加、插入和删除页面。将单个 PDF 拆分为单独的 PDF。或者将多个 PDF 合并到一个文档中。
创建新表单或填写和读取现有字段。复选框、按钮、单选按钮组、下拉列表、选项列表和文本字段均受支持。
pdfjs
版本 "pdfjs-dist": "^5.1.91",
可以读取pdf的图片和文档
js
import * as pdfjsLib from 'pdfjs-dist'
import workerSrc from 'pdfjs-dist/build/pdf.worker?worker&url'
// import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.mjs'
// const pdfjsWorker = await import('pdfjs-dist/build/pdf.worker.mjs')
// 确保 PDF.js 使用正确的 worker 路径
pdfjsLib.GlobalWorkerOptions.workerSrc = workerSrc
/**
* 提取 PDF 中的图片和文字
* @param {File} file - PDF 文件
* @returns {Promise<{ images: any, texts: string[] }>} - 提取的图片和文字
*/
export async function extractPDFContent(file: File): Promise<{ images: any; texts: string[] }> {
return new Promise((resolve, reject) => {
const fileReader = new FileReader()
fileReader.onload = async (e: any) => {
try {
const typedarray = new Uint8Array(e.target.result)
const loadingTask = pdfjsLib.getDocument(typedarray)
const { images, texts } = await processPDF(loadingTask)
resolve({ images, texts })
} catch (error) {
reject(error)
}
}
fileReader.onerror = (error) => {
reject(error)
}
fileReader.readAsArrayBuffer(file)
})
}
/**
* 处理 PDF 文件
* @param {Object} loadingTask - PDF 加载任务
* @returns {Promise<{ images: any, texts: string[] }>} - 提取的图片和文字
*/
async function processPDF(loadingTask: any) {
const pdf = await loadingTask.promise
const numPages = pdf.numPages
const images = new Map() // 存储图片的 URL 和对应的 Blob 数据
const texts = [] // 存储每页的文字内容
for (let curPage = 1; curPage <= numPages; curPage++) {
const page = await pdf.getPage(curPage)
// 提取图片
const scale = 1.5
const viewport = page.getViewport({ scale })
const outputScale = window.devicePixelRatio || 1
const canvas = document.createElement('canvas')
const context = canvas.getContext('2d')
const transform = outputScale !== 1 ? [outputScale, 0, 0, outputScale, 0, 0] : null
const renderContext = {
canvasContext: context,
transform,
viewport
}
const renderTask = page.render(renderContext)
await renderTask.promise
const ops = await page.getOperatorList()
const imageNames = ops.fnArray.reduce((acc, curr, i) => {
if ([pdfjsLib.OPS.paintImageXObject, pdfjsLib.OPS.paintJpegXObject].includes(curr)) {
acc.push(ops.argsArray[i][0])
}
return acc
}, [])
for (const imageName of imageNames) {
page.objs.get(imageName, (image: any) => {
;(async () => {
const bmp = image.bitmap
const resizeScale = 1 / 4
const width = bmp.width * resizeScale
const height = bmp.height * resizeScale
const canvas = new OffscreenCanvas(width, height)
const ctx: any = canvas.getContext('bitmaprenderer')
ctx.transferFromImageBitmap(bmp)
const blob = await canvas.convertToBlob()
const imageUrl = URL.createObjectURL(blob)
images.set(imageUrl, blob) // 将图片 URL 和对应的 Blob 数据存储到对象中
})()
})
}
// 提取文字
const textContent = await page.getTextContent()
const textItems = textContent.items.map((item) => item.str).join('\n')
if (textItems) {
texts.push(textItems)
}
}
return { images, texts }
}