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 開發文檔