Android PDFBox 的使用指南

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)}
}

注意事项

  1. 内存管理: PDFBox需要大量内存,建议使用MemoryUsageSetting.setupMixed()来优化内存使用。

  2. 异常处理: 所有PDF操作都应该包含适当的异常处理。

  3. 资源释放: 使用完PDF文档后,务必调用close()方法释放资源。

  4. 线程安全: PDFBox操作应该在后台线程中执行,避免阻塞UI线程。

  5. 文件权限: 确保应用有适当的文件读写权限。

更多资源

  • PDFBox Android GitHub
  • PDFBox 官方文档
  • Android 开发文档

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/92092.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/92092.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TFTP: Linux 系统安装 TFTP,文件系统启动后TFTP使用

安装 TFTP 服务器 sudo apt update sudo apt install tftpd-hpa配置 TFTP 服务器 编辑配置文件 /etc/default/tftpd-hpa&#xff1a; sudo nano /etc/default/tftpd-hpa 修改内容如下&#xff1a; TFTP_USERNAME"tftp" TFTP_DIRECTORY"/srv/tftp" TFTP_ADD…

昇思+昇腾开发板+DeepSeek模型LoRA微调

昇思昇腾开发板DeepSeek模型LoRA微调 LoRA微调原理核心思想&#xff1a;冻结预训练模型权重&#xff0c;仅训练橙色的低秩适配矩阵&#xff08;A/B矩阵&#xff09;优势&#xff1a; 训练参数量减少至全量微调的0.5%显存占用降低50%以上适配器权重仅需保存3MB&#xff08;原模型…

计算机网络:详解网络地址的计算步骤

网络地址计算是网络规划与配置的基础,核心是通过IP地址和子网掩码确定网络标识、广播地址、可用主机范围等关键信息。以下是详细的计算步骤,配合实例说明(以IPv4为例): 一、明确基础概念 在计算前,需先明确3个核心概念: IP地址:标识网络中主机的32位二进制数,通常以…

Spring AI 系列之三十五 - Spring AI Alibaba-Graph框架之MCP

之前做个几个大模型的应用&#xff0c;都是使用Python语言&#xff0c;后来有一个项目使用了Java&#xff0c;并使用了Spring AI框架。随着Spring AI不断地完善&#xff0c;最近它发布了1.0正式版&#xff0c;意味着它已经能很好的作为企业级生产环境的使用。对于Java开发者来说…

FastAPI后端工程化项目记录

以下是一个使用fastapi上传视频的接口&#xff0c;记录一下工程化后端程序的业务逻辑 重点是代码如何抽离 项目结构优化 project/ ├── .env # 环境变量配置 ├── app/ │ ├── __init__.py │ ├── main.py # 主应用入口 │ …

令牌桶限流算法

你提供的 Java 代码实现的是令牌桶限流算法&#xff08;Token Bucket Algorithm&#xff09;&#xff0c;这是目前最常用、最灵活的限流算法之一。它允许一定程度的“突发流量”&#xff0c;同时又能控制平均速率。下面我将&#xff1a;逐行详细解释 TokenBucketLimiter 类的每…

基于springboot的宠物商城设计与实现

管理员&#xff1a;登录&#xff0c;个人中心&#xff0c;用户管埋&#xff0c;宠物分类管理&#xff0c;宠物信息管理&#xff0c;留言反馈&#xff0c;宠物论坛&#xff0c;系统管理&#xff0c;订单管理用户&#xff1a;宠物信息&#xff0c;宠物论坛&#xff0c;公告信息&a…

Python day36

浙大疏锦行 Python day36. 复习日 本周内容&#xff1a; 如何导入模块以及库项目的规范拆分和写法官方文档的阅读MLP神经网络的训练在GPU上训练模型可视化以及推理

【gaussian-splatting】用自己的数据复现高斯泼溅(一)

1.环境准备1.1.下载diff-gaussian-rasterization这里本来没啥说的&#xff0c;直接从github上下载就行了&#xff0c;但是我踩坑了&#xff0c;下的版本不对&#xff0c;后续运行报错参数个数对不上&#xff0c;特在此给大家避坑&#xff0c;注意一定要下带3dgs版本的diff-gaus…

中国移动h10g-01_S905L处理器安卓7.1当贝纯净版线刷机包带root权限_融合终端网关

下载固件之前请先将主板上的屏蔽罩取下&#xff0c;查看处理器型号 是否为S905L型号&#xff0c;然后再下载固件进行刷机&#xff1b; 本页面的固件是采用双公头数据线进行刷机的哈&#xff1b; 安卓4.4.2版本固件下载地址&#xff1a;点此进行下载 安卓7.1版本固件下载地址…

夜天之书 #110 涓滴开源:Cronexpr 的故事

在年初的一篇关于商业开源的博文当中&#xff0c;我介绍了在开发商业软件的过程中&#xff0c;衍生出开源公共软件库的模式。在那篇博文里面&#xff0c;我只是简单罗列了相关开源库的名字及一句话总结。近期&#xff0c;我会结合商业开源实践的最新进展&#xff0c;对其中一些…

完整的登陆学生管理系统(配置数据库)

目录 要求 思路 1. 登录模块&#xff08;LoginFrame.java&#xff09; 2. 学生信息管理模块&#xff08;StudentFrame.java&#xff09; 3. 数据层&#xff08;StudentDAO.java&#xff09; 4. 业务层&#xff08;StudentService.java / UserService.java&#xff09; 5…

译 | 在 Python 中从头开始构建 Qwen-3 MoE

文章出自&#xff1a;基于 2个Expert 的 MoE 架构分步指南 本篇适合 MoE 架构初学者。文章亮点在于详细拆解 Qwen 3 MoE 架构&#xff0c;并用简单代码从零实现 MoE 路由器、RMSNorm 等核心组件&#xff0c;便于理解内部原理。 该方法适用于需部署高性能、高效率大模型&#x…

Spring Boot + ShardingSphere 分库分表实战

&#x1f680;Spring Boot ShardingSphere 实战&#xff1a;分库分表&#xff0c;性能暴增的终极指南&#xff01; ✅ 适用场景&#xff1a;千万级大表、高并发、读写分离场景 ✅ 核心框架&#xff1a;Spring Boot 3.x ShardingSphere-JDBC 5.4.1 ✅ 数据库&#xff1a;MySQL…

MaxKB 使用 MCP 连接 Oracle (免安装 cx_Oracle 和 Oracle Instant Client)

一、背景 安装cx_Oracle包和Oracle Instant Client来操作数据库&#xff0c;比较繁琐同时容易冲突&#xff0c;不同的 Oracle 版本都需要安装不同的插件。这篇文章将介绍使用 MCP 协议的连接方法。 二、操作步骤 1、使用 1Panel 安装 DBhub a) 数据库类型选择 Oracle 类型。…

基于Python的超声波OFDM数字通信链路设计与实现

基于Python的超声波OFDM数字通信链路设计与实现 摘要 本文详细介绍了使用Python实现的超声波OFDM(正交频分复用)数字通信链路系统。该系统能够在标准音响设备上运行&#xff0c;利用高于15kHz的超声波频段进行数据传输&#xff0c;采用48kHz采样率。文章涵盖了从OFDM基本原理、…

滑动窗口相关题目

近些年来&#xff0c;我国防沙治沙取得显著成果。某沙漠新种植N棵胡杨&#xff08;编号1-N&#xff09;&#xff0c;排成一排。一个月后&#xff0c;有M棵胡杨未能成活。现可补种胡杨K棵&#xff0c;请问如何补种&#xff08;只能补种&#xff0c;不能新种&#xff09;&#xf…

Java 工具类的“活化石”:Apache Commons 核心用法、性能陷阱与现代替代方案

在上一篇文章中&#xff0c;我们回顾了 Apache Commons 的经典组件。但作为 Java 世界中资历最老、影响最深远的工具库&#xff0c;它的价值远不止于此。许多开发者可能只使用了它 10% 的功能&#xff0c;却忽略了另外 80% 能极大提升代码质量的“隐藏宝石”。本文将提供一个更…

数据结构——图及其C++实现 多源最短路径 FloydWarshall算法

目录 一、前言 二、算法思想 三、代码实现 四、测试 五、源码 一、前言 前两篇学习的Dijkstra算法和Bellman-Ford算法都是用来求解图的单源最短路径&#xff0c;即从图中指定的一个源点出发到图中其他任意顶点的最短路径。Dijkstra算法不能求解带有负权重的图的最短路径&…

解决微软应用商店 (Microsoft store) 打不开,无网络连接的问题!

很多小伙伴都会遇见微软应用商店 (Microsoft store)打开后出现无网络的问题&#xff0c;一般出现这种问题基本都是因为你的电脑安装了某些银行的网银工具&#xff0c;因为网银工具为了安全会关闭Internet 选项中的最新版本的TLS协议&#xff0c;而微软商店又需要最新的TLS协议才…