构建React Native PDF应用:pdf-lib移动端实践
你是否还在为React Native应用中的PDF处理功能头疼?原生模块集成复杂、性能不佳、跨平台兼容性差?本文将带你使用pdf-lib库,以纯JavaScript方式在React Native应用中实现PDF创建、编辑和展示功能,无需原生开发经验,轻松搞定移动端PDF处理。
读完本文你将学到:
- 如何在React Native项目中集成pdf-lib
- 使用pdf-lib创建和编辑PDF文档
- 添加文本、图片和表单到PDF
- 实现PDF预览和保存功能
- 优化移动端PDF处理性能
环境准备与项目配置
首先需要创建或准备一个React Native项目。我们以项目中的React Native示例应用为例,其目录结构位于apps/rn/。
安装依赖
pdf-lib库已在项目中通过相对路径引入,相关依赖配置可查看apps/rn/package.json:
{
"dependencies": {
"@pdf-lib/fontkit": "^0.0.4",
"pdf-lib": "./../..",
"react": "16.8.3",
"react-native": "0.59.10",
"react-native-pdf": "^6.1.1",
"rn-fetch-blob": "0.10.15"
}
}
核心依赖包括:
pdf-lib: 用于创建和修改PDF文档的核心库react-native-pdf: 用于在React Native中展示PDFrn-fetch-blob: 处理文件系统操作和文件下载
安装命令:
cd gh_mirrors/pd/pdf-lib/apps/rn && yarn install
项目结构
React Native示例应用的主要结构:
apps/rn/
├── __tests__/ # 测试文件
├── android/ # Android原生代码
├── ios/ # iOS原生代码
├── src/ # 源代码目录
│ ├── components/ # React组件
│ │ ├── App.js # 应用入口组件
│ │ └── ...
│ └── tests/ # PDF测试代码
├── index.js # 应用入口文件
└── package.json # 项目配置
应用入口文件index.js注册了主组件:
import { AppRegistry } from 'react-native';
import App from './src/components/App';
import { name as appName } from './app.json';
AppRegistry.registerComponent(appName, () => App);
创建第一个PDF文档
让我们从创建一个简单的PDF文档开始。以下是使用pdf-lib创建PDF的基本流程:
初始化PDF文档
import { PDFDocument } from 'pdf-lib';
async function createPdf() {
// 创建新的PDF文档
const pdfDoc = await PDFDocument.create();
// 设置文档元数据
pdfDoc.setTitle('我的第一个PDF文档');
pdfDoc.setAuthor('React Native应用');
pdfDoc.setSubject('使用pdf-lib创建');
// 添加页面
const page = pdfDoc.addPage([550, 800]); // 设置页面大小
// 保存PDF为base64格式
const base64Pdf = await pdfDoc.saveAsBase64({ dataUri: true });
return base64Pdf;
}
添加文本内容
要在PDF中添加文本,需要先嵌入字体。我们可以使用标准字体或自定义字体:
// 嵌入标准字体
const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman);
// 在页面上绘制文本
page.drawText('Hello React Native!', {
x: 50,
y: 750,
font: timesRomanFont,
size: 24,
});
// 添加多行文本
const ipsumLines = [
'这是使用pdf-lib创建的PDF文档。',
'pdf-lib允许你在任何JavaScript环境中',
'创建和修改PDF文档,包括React Native应用。',
];
page.drawText(ipsumLines.join('\n'), {
x: 50,
y: 700,
font: timesRomanFont,
size: 14,
lineHeight: 20,
});
绘制图形和路径
pdf-lib提供了绘制各种图形的API:
// 绘制矩形
page.drawRectangle({
x: 50,
y: 600,
width: 450,
height: 80,
color: rgb(0.95, 0.95, 0.95),
borderWidth: 2,
borderColor: rgb(0.5, 0.5, 0.5),
});
// 绘制圆形
page.drawCircle({
x: 100,
y: 500,
size: 30,
color: rgb(1, 0.5, 0),
});
// 绘制线条
page.drawLine({
start: { x: 50, y: 450 },
end: { x: 500, y: 450 },
thickness: 2,
color: rgb(0, 0.5, 1),
dashArray: [10, 5],
});
添加图片和多媒体
pdf-lib支持嵌入JPG和PNG图片,包括带有透明度的图片。
嵌入图片
// 从文件系统加载图片
import { fetchAsset } from './assets';
// 嵌入JPG图片
const catRidingUnicornBytes = await fetchAsset('images/cat_riding_unicorn_resized.jpg');
const catImage = await pdfDoc.embedJpg(catRidingUnicornBytes);
// 嵌入PNG图片(支持透明度)
const marioBytes = await fetchAsset('images/small_mario_resized.png');
const marioImage = await pdfDoc.embedPng(marioBytes);
绘制图片
// 计算图片尺寸(保持原始比例)
const catDims = catImage.scale(0.5);
// 绘制图片
page.drawImage(catImage, {
x: 50,
y: 250,
width: catDims.width,
height: catDims.height,
});
// 绘制带有旋转和透明度的图片
page.drawImage(marioImage, {
x: 350,
y: 300,
width: marioImage.width * 0.8,
height: marioImage.height * 0.8,
rotate: degrees(15),
opacity: 0.8,
});
以下是我们嵌入的示例图片效果:
创建交互式表单
pdf-lib支持创建各种交互式表单字段,如文本框、复选框、单选按钮等。
创建表单字段
// 获取表单实例
const form = pdfDoc.getForm();
// 创建文本字段
const nameField = form.createTextField('full_name');
nameField.setText('请输入您的姓名');
nameField.addToPage(page, {
x: 50,
y: 180,
width: 200,
height: 30,
borderWidth: 1,
backgroundColor: rgb(1, 1, 1),
});
// 创建复选框
const agreeCheckbox = form.createCheckBox('agree_terms');
agreeCheckbox.addToPage(page, {
x: 50,
y: 140,
width: 20,
height: 20,
});
// 在复选框旁添加文本
page.drawText('我同意条款和条件', {
x: 80,
y: 142,
font: timesRomanFont,
size: 12,
});
// 创建单选按钮组
const radioGroup = form.createRadioGroup('preferred_color');
radioGroup.addOptionToPage('红色', page, {
x: 50,
y: 100,
width: 20,
height: 20,
});
page.drawText('红色', { x: 80, y: 102, font: timesRomanFont, size: 12 });
radioGroup.addOptionToPage('蓝色', page, {
x: 150,
y: 100,
width: 20,
height: 20,
});
page.drawText('蓝色', { x: 180, y: 102, font: timesRomanFont, size: 12 });
radioGroup.select('蓝色'); // 默认选中"蓝色"
在React Native中展示PDF
创建完PDF后,我们需要在React Native应用中展示它。我们使用react-native-pdf库来实现这一功能。
渲染PDF
import PdfView from 'react-native-pdf';
function PDFViewer({ base64Pdf }) {
return (
<PdfView
source={{ uri: base64Pdf, cache: true }}
style={{ flex: 1 }}
onLoadComplete={(numberOfPages, filePath) => {
console.log(`加载完成,共${numberOfPages}页`);
}}
onPageChanged={(page, numberOfPages) => {
console.log(`当前第${page}页,共${numberOfPages}页`);
}}
onError={(error) => {
console.log('PDF加载错误:', error);
}}
enableAntialiasing={true}
/>
);
}
完整的PDF创建和预览流程
以下是将PDF创建和预览整合到React Native组件中的完整示例:
import React, { useState } from 'react';
import { View, Button, ActivityIndicator } from 'react-native';
import PdfView from 'react-native-pdf';
import { PDFDocument, StandardFonts, rgb } from 'pdf-lib';
const PDFCreator = () => {
const [pdfData, setPdfData] = useState(null);
const [isCreating, setIsCreating] = useState(false);
const createAndDisplayPdf = async () => {
setIsCreating(true);
try {
// 创建PDF文档
const pdfDoc = await PDFDocument.create();
// 嵌入字体
const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
// 添加页面
const page = pdfDoc.addPage([550, 800]);
// 添加内容
page.drawText('React Native PDF示例', {
x: 50,
y: 750,
font,
size: 24,
});
// 保存为base64
const base64Pdf = await pdfDoc.saveAsBase64({ dataUri: true });
setPdfData(base64Pdf);
} catch (error) {
console.error('创建PDF失败:', error);
} finally {
setIsCreating(false);
}
};
if (isCreating) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<ActivityIndicator size="large" />
</View>
);
}
return (
<View style={{ flex: 1 }}>
{!pdfData ? (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Button title="创建PDF文档" onPress={createAndDisplayPdf} />
</View>
) : (
<PdfView
source={{ uri: pdfData }}
style={{ flex: 1 }}
/>
)}
</View>
);
};
export default PDFCreator;
高级功能与性能优化
合并和拆分PDF
pdf-lib可以合并多个PDF文档或拆分PDF文档:
// 合并PDF
async function mergePdfs(pdfUris) {
const mergedPdf = await PDFDocument.create();
for (const uri of pdfUris) {
// 从URI加载PDF
const pdfBytes = await fetch(uri).then(res => res.arrayBuffer());
const pdfDoc = await PDFDocument.load(pdfBytes);
// 复制页面
const pages = await mergedPdf.copyPages(pdfDoc, pdfDoc.getPageIndices());
pages.forEach(page => mergedPdf.addPage(page));
}
return await mergedPdf.saveAsBase64({ dataUri: true });
}
性能优化技巧
- 字体子集化:只嵌入文档中使用的字符,减小PDF文件大小
// 启用字体子集化
const customFont = await pdfDoc.embedFont(customFontBytes, { subset: true });
- 图片优化:调整图片大小和质量,使用适当的格式
// 缩小图片尺寸
const image = await pdfDoc.embedJpg(imageBytes);
const scaledImage = image.scale(0.3); // 缩小到30%
- 延迟加载:对于大型PDF,考虑分页面处理
// 只处理当前需要的页面
const pdfDoc = await PDFDocument.load(pdfBytes, {
parseSpeed: ParseSpeeds.Fastest, // 快速解析模式
});
测试与调试
项目中的测试代码位于apps/rn/src/tests/目录,包含各种PDF操作的测试用例。例如test1.js演示了完整的PDF创建流程,包括文本、图形、图片和表单。
运行测试的方法:
cd gh_mirrors/pd/pdf-lib/apps/rn && yarn test
总结与后续学习
通过本文,我们学习了如何在React Native应用中使用pdf-lib库创建和修改PDF文档。主要内容包括:
- 环境配置和项目结构
- 创建PDF文档和添加内容
- 嵌入字体和绘制文本
- 添加图片和图形
- 创建交互式表单
- 在React Native中展示PDF
- 高级功能和性能优化
进一步学习资源
- 官方文档:docs/
- API参考:src/api/
- 更多示例:apps/rn/src/tests/
- 核心实现:src/core/
pdf-lib为React Native应用提供了强大的PDF处理能力,无需原生开发即可实现专业的PDF功能。无论是创建报告、生成发票,还是实现表单收集,pdf-lib都能满足你的需求。
现在就开始在你的React Native项目中尝试使用pdf-lib吧!如有任何问题,可以查阅项目文档或提交issue。
本文示例代码基于pdf-lib的React Native示例应用,完整项目可在apps/rn/目录找到。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考




