Android PDFBox 使用指南
概述
PDFBox是一个强大的PDF处理库,在Android平台上也有对应的实现。本指南将介绍如何在Android项目中使用PDFBox进行PDF文件的加载、读取、修改等操作。
依赖配置
在 app/build.gradle
中添加PDFBox依赖:
dependencies {implementation 'com.tom-roush:pdfbox-android:2.0.27.0'
}
核心功能
1. 初始化PDFBox
在使用PDFBox之前,必须先初始化资源加载器:
// 在Application或Activity的onCreate中调用
PDFBoxResourceLoader.init(context)
2. 加载PDF文件
从Assets文件夹加载
fun loadPdfFromAssets(context: Context, fileName: String): PDDocument? {return try {context.assets.open(fileName).use { inputStream ->PDDocument.load(inputStream, MemoryUsageSetting.setupMixed(1000 * 1024 * 1024))}} catch (e: IOException) {null}
}
从文件路径加载
fun loadPdfFromFile(filePath: String): PDDocument? {return try {PDDocument.load(File(filePath), MemoryUsageSetting.setupMixed(1000 * 1024 * 1024))} catch (e: IOException) {null}
}
3. 获取PDF信息
fun getPdfInfo(document: PDDocument): String {val info = StringBuilder()// 获取页面数量val pageCount = document.numberOfPagesinfo.append("页面数量: $pageCount\n")// 获取文档信息val documentInformation = document.documentInformationif (documentInformation != null) {info.append("标题: ${documentInformation.title ?: "无"}\n")info.append("作者: ${documentInformation.author ?: "无"}\n")info.append("主题: ${documentInformation.subject ?: "无"}\n")info.append("创建者: ${documentInformation.creator ?: "无"}\n")info.append("创建日期: ${documentInformation.creationDate ?: "无"}\n")info.append("修改日期: ${documentInformation.modificationDate ?: "无"}\n")}return info.toString()
}
4. 提取文本内容
提取整个文档的文本
fun extractText(document: PDDocument): String {return try {val stripper = PDFTextStripper()stripper.text = document} catch (e: IOException) {"提取文本失败"}
}
提取指定页面的文本
fun extractTextFromPage(document: PDDocument, pageIndex: Int): String {return try {val stripper = PDFTextStripper()stripper.startPage = pageIndex + 1stripper.endPage = pageIndex + 1stripper.text = document} catch (e: IOException) {"提取页面文本失败"}
}
5. 获取页面信息
fun getPageInfo(document: PDDocument, pageIndex: Int): String {return try {val page = document.getPage(pageIndex)val mediaBox = page.mediaBoxval cropBox = page.cropBox"页面 ${pageIndex + 1}:\n" +"媒体框 - 宽度: ${mediaBox.width}, 高度: ${mediaBox.height}\n" +"裁剪框 - 宽度: ${cropBox.width}, 高度: ${cropBox.height}\n" +"旋转角度: ${page.rotation}°\n" +"注释数量: ${page.annotations.size}"} catch (e: Exception) {"获取页面信息失败"}
}
6. 添加注释
添加文本注释
fun addTextAnnotation(document: PDDocument, pageIndex: Int, x: Float, y: Float, text: String) {try {val page = document.getPage(pageIndex)val annotation = PDAnnotationInk()annotation.subtype = "FreeText"// 设置注释位置和大小val rect = PDRectangle(x, y, x + 100, y + 50)annotation.rectangle = rect// 设置注释内容annotation.contents = text// 设置颜色annotation.color = AWTColor.YELLOW// 添加到页面page.annotations.add(annotation)} catch (e: Exception) {Log.e(TAG, "添加文本注释失败: ${e.message}")}
}
添加手绘注释
fun addInkAnnotation(document: PDDocument, pageIndex: Int, points: List<FloatArray>) {try {val page = document.getPage(pageIndex)// 创建手绘注释val inkAnnotation = PDAnnotationInk()inkAnnotation.subtype = "Ink"// 计算边界val bounds = calculateInkBounds(points, page.mediaBox)inkAnnotation.rectangle = bounds// 创建外观流val normalAppearance = PDAppearanceStream(document)normalAppearance.bBox = bounds// 绘制轨迹PDPageContentStream(document, normalAppearance).use { cs ->cs.setStrokingColor(AWTColor.RED)cs.setLineWidth(2f)for (path in points) {if (path.size >= 4) {cs.moveTo(path[0], path[1])for (index in 2 until path.size step 2) {cs.lineTo(path[index], path[index + 1])}cs.stroke()}}}// 设置外观val apDict = COSDictionary()apDict.setItem(COSName.N, normalAppearance)inkAnnotation.cosObject.setItem(COSName.AP, apDict)// 添加到页面page.annotations.add(inkAnnotation)} catch (e: Exception) {Log.e(TAG, "添加手绘注释失败: ${e.message}")}
}
7. 保存PDF文件
fun savePdf(document: PDDocument, outputPath: String): Boolean {return try {document.save(outputPath)true} catch (e: IOException) {false}
}
8. 关闭文档
fun closeDocument(document: PDDocument) {try {document.close()} catch (e: IOException) {Log.e(TAG, "关闭PDF文档失败: ${e.message}")}
}
使用示例
完整处理流程示例
fun processPdfExample(context: Context, fileName: String) {// 1. 加载PDFval document = loadPdfFromAssets(context, fileName)if (document == null) {Log.e(TAG, "无法加载PDF文件")return}try {// 2. 获取PDF信息val info = getPdfInfo(document)Log.i(TAG, "PDF信息:\n$info")// 3. 提取文本val text = extractText(document)Log.i(TAG, "PDF文本内容:\n$text")// 4. 获取第一页信息if (document.numberOfPages > 0) {val pageInfo = getPageInfo(document, 0)Log.i(TAG, "第一页信息:\n$pageInfo")// 5. 添加文本注释addTextAnnotation(document, 0, 100f, 100f, "这是一个测试注释")// 6. 添加手绘注释示例val samplePoints = listOf(floatArrayOf(50f, 50f, 100f, 100f, 150f, 50f),floatArrayOf(200f, 200f, 250f, 250f, 300f, 200f))addInkAnnotation(document, 0, samplePoints)}// 7. 保存修改后的PDFval outputPath = context.getExternalFilesDir(null)?.absolutePath + "/modified_$fileName"if (savePdf(document, outputPath)) {Log.i(TAG, "PDF处理完成,已保存到: $outputPath")}} finally {// 8. 关闭文档closeDocument(document)}
}
注意事项
-
内存管理: PDFBox需要大量内存,建议使用
MemoryUsageSetting.setupMixed()
来优化内存使用。 -
异常处理: 所有PDF操作都应该包含适当的异常处理。
-
资源释放: 使用完PDF文档后,务必调用
close()
方法释放资源。 -
线程安全: PDFBox操作应该在后台线程中执行,避免阻塞UI线程。
-
文件权限: 确保应用有适当的文件读写权限。
更多资源
- PDFBox Android GitHub
- PDFBox 官方文档
- Android 开发文档