鸿蒙学习实战之路-PDF页面文本图片与批注最佳实践
最近好多朋友问我:“西兰花啊,我用PDF Kit搞文档编辑,咋添加个文本图片就报错?批注也搞不明白?这可咋整?” 害,这问题我太熟了!今天我就手把手带你搞定PDF页面的文本添加、图片插入和批注功能,这些可是PDF编辑的核心操作,学会了这个,你就能随便丰富文档内容啦~
·
鸿蒙学习实战之路-PDF页面文本图片与批注最佳实践
最近好多朋友问我:“西兰花啊,我用PDF Kit搞文档编辑,咋添加个文本图片就报错?批注也搞不明白?这可咋整?” 害,这问题我太熟了!今天我就手把手带你搞定PDF页面的文本添加、图片插入和批注功能,这些可是PDF编辑的核心操作,学会了这个,你就能随便丰富文档内容啦~
一、核心接口速览
PDF页面内容编辑,主要就这些核心接口:
| 接口名 | 功能描述 |
|---|---|
| addTextObject | 添加文本内容(只可按行添加) |
| addImageObject | 在PDF文档页面中添加图片 |
| deleteGraphicsObject | 删除指定的图形对象 |
| addAnnotation | 在当前页添加批注 |
这几个接口就是咱们今天要摆弄的"画笔和颜料",用好了,PDF页面任你画~
二、添加文本,轻松搞定
1. 准备工作
import { pdfService } from '@kit.PDFKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { Font } from '@kit.ArkUI';
@Entry
@Component
struct PdfPage {
private pdfDocument: pdfService.PdfDocument = new pdfService.PdfDocument();
private context = this.getUIContext().getHostContext() as Context;
aboutToAppear(): void {
// 确保沙箱目录有input.pdf文档
let filePath = this.context.filesDir + '/input.pdf';
this.pdfDocument.loadDocument(filePath);
}
2. 添加文本内容
Button('添加文本')
.onClick(async () => {
// 获取要编辑的页面
let page: pdfService.PdfPage = this.pdfDocument.getPage(0);
// 准备要添加的文本
let textContent = '这是用鸿蒙PDF Kit添加的文本!';
// 设置字体信息
let fontInfo = new pdfService.FontInfo();
let font: Font = new Font();
fontInfo.fontPath = font.getFontByName('HarmonyOS Sans')?.path;
fontInfo.fontName = '';
// 设置文本样式
let style: pdfService.TextStyle = {
textColor: 0x000000, // 黑色文本
textSize: 30, // 30号字体
fontInfo: fontInfo // 使用的字体
};
// 在指定位置添加文本(x:10, y:10)
page.addTextObject(textContent, 10, 10, style);
// 保存文档
let outPdfPath = this.context.filesDir + '/testAddText.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
hilog.info(0x0000, 'PdfPage', '添加文本 %{public}s!', result ? '成功' : '失败');
})
3. 删除文本内容
Button('删除文本')
.onClick(async () => {
// 获取要编辑的页面
let page: pdfService.PdfPage = this.pdfDocument.getPage(0);
// 获取页面上所有的图形对象
let graphicsObjects = page.getGraphicsObjects();
// 找到第一个文本对象
let index = graphicsObjects.findIndex(
item => item.type === pdfService.GraphicsObjectType.OBJECT_TEXT
);
// 如果找到文本对象,就删除它
if (index > -1) {
page.deleteGraphicsObject(graphicsObjects[index]);
}
// 保存文档
let outPdfPath = this.context.filesDir + '/testDelText.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
hilog.info(0x0000, 'PdfPage', '删除文本 %{public}s!', result ? '成功' : '失败');
})
三、添加图片,so easy!
Button('添加图片')
.onClick(async () => {
// 获取要编辑的页面
let page: pdfService.PdfPage = this.pdfDocument.getPage(0);
// 设置图片路径(确保沙箱目录有img.jpg图片)
let imagePath = this.context.filesDir + '/img.jpg';
// 在指定位置添加图片(x:100, y:100),宽100,高120
page.addImageObject(imagePath, 100, 100, 100, 120);
// 保存文档
let outPdfPath = this.context.filesDir + '/testAddImage.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
hilog.info(0x0000, 'PdfPage', '添加图片 %{public}s!', result ? '成功' : '失败');
})
四、添加批注,让文档更生动
PDF Kit支持13种批注类型,包括文本批注、下划线批注、高亮批注、删除线批注等。咱们先从最常用的文本批注开始~
1. 添加文本批注
Button('添加文本批注')
.onClick(async () => {
// 确保沙箱目录有input.pdf文档
let filePath = this.context.filesDir + '/input.pdf';
this.pdfDocument.loadDocument(filePath);
// 获取要编辑的页面
let page: pdfService.PdfPage = this.pdfDocument.getPage(0);
// 创建文本批注对象
let annotationInfo = new pdfService.TextAnnotationInfo();
annotationInfo.iconName = 'cument Format';
annotationInfo.content = '这是批注内容,用来标注重要信息!';
annotationInfo.subject = '批注';
annotationInfo.title = '这是批注标题';
annotationInfo.state = pdfService.TextAnnotationState.MARKED;
annotationInfo.x = 200; // 批注位置x坐标
annotationInfo.y = 200; // 批注位置y坐标
annotationInfo.color = 0xf9b1b1; // 批注颜色(浅红色)
annotationInfo.flag = pdfService.AnnotationFlag.PRINTED; // 打印时包含批注
// 添加批注到页面
let annotation: pdfService.PdfAnnotation = page.addAnnotation(annotationInfo);
// 保存文档
let outPdfPath = this.context.filesDir + '/testAddTextAnnotation.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
this.pdfDocument.releaseDocument();
hilog.info(0x0000, 'PdfPage', '添加文本批注 %{public}s!', result ? '成功' : '失败');
})
2. 修改文本批注
Button('修改文本批注')
.onClick(async () => {
// 打开包含批注的PDF文档
let filePath = this.context.filesDir + '/testAddTextAnnotation.pdf';
let result = this.pdfDocument.loadDocument(filePath);
if (result === pdfService.ParseResult.PARSE_SUCCESS) {
// 获取要编辑的页面
let page: pdfService.PdfPage = this.pdfDocument.getPage(0);
// 获取页面上所有批注
let annotations = page.getAnnotations();
// 找到第一个文本批注
if (annotations.length > 0 && annotations[0].type === pdfService.AnnotationType.TEXT) {
// 先删除旧批注
page.removeAnnotation(annotations[0]);
// 创建新的批注信息
let newAnnotationInfo = new pdfService.TextAnnotationInfo();
newAnnotationInfo.title = '修改后的标题';
newAnnotationInfo.content = '修改后的批注内容!';
newAnnotationInfo.state = pdfService.TextAnnotationState.MARKED;
newAnnotationInfo.x = 100; // 新位置x坐标
newAnnotationInfo.y = 100; // 新位置y坐标
// 添加新批注
page.addAnnotation(newAnnotationInfo);
// 保存文档
let outPdfPath = this.context.filesDir + '/testSetAnnotation.pdf';
let saveResult = this.pdfDocument.saveDocument(outPdfPath);
this.pdfDocument.releaseDocument();
hilog.info(0x0000, 'PdfPage', '修改文本批注 %{public}s!', saveResult ? '成功' : '失败');
}
}
})
3. 删除文本批注
Button('删除文本批注')
.onClick(async () => {
// 打开包含批注的PDF文档
let filePath = this.context.filesDir + '/testAddTextAnnotation.pdf';
let result = this.pdfDocument.loadDocument(filePath);
if (result === pdfService.ParseResult.PARSE_SUCCESS) {
// 获取要编辑的页面
let page: pdfService.PdfPage = this.pdfDocument.getPage(0);
// 获取页面上所有批注
let annotations = page.getAnnotations();
// 找到第一个文本批注并删除
if (annotations.length > 0 && annotations[0].type === pdfService.AnnotationType.TEXT) {
page.removeAnnotation(annotations[0]);
// 保存文档
let outPdfPath = this.context.filesDir + '/testRemoveAnnotation.pdf';
let saveResult = this.pdfDocument.saveDocument(outPdfPath);
this.pdfDocument.releaseDocument();
hilog.info(0x0000, 'PdfPage', '删除文本批注 %{public}s!', saveResult ? '成功' : '失败');
}
}
})
🥦 西兰花警告
- 文本添加限制:addTextObject只能按行添加文本,不能自动换行,长文本需要自己处理换行逻辑!
- 字体路径问题:字体路径一定要正确,不然会导致文本显示异常或者添加失败!
- 图片格式支持:目前支持的图片格式有限,建议使用JPG格式,避免使用PNG透明图片!
- 资源释放:操作完文档一定要记得调用releaseDocument(),不然会内存泄漏!
- 坐标系统:PDF的坐标系统原点在左下角,和咱们平时用的屏幕坐标不太一样,别搞反了!
🥦 西兰花小贴士
- 文本样式:可以设置字体大小、颜色、字体类型等,让文本更美观
- 图片位置:添加图片时,要注意坐标和尺寸,避免图片超出页面范围
- 批注类型:PDF Kit支持13种批注类型,可以根据需要选择合适的批注样式
- 批量操作:如果要添加大量文本或图片,建议先缓存样式,减少重复创建
- 性能优化:处理大量内容时,尽量减少saveDocument的调用次数
五、常见问题与解决方案
1. 添加文本时提示"字体不存在"
问题:设置字体路径后,提示"Font not found"
解决方案:使用系统默认字体,或者确保字体文件存在:
// 正确写法
let font: Font = new Font();
fontInfo.fontPath = font.getFontByName('HarmonyOS Sans')?.path;
// 如果获取不到,使用系统默认字体
if (!fontInfo.fontPath) {
fontInfo.fontName = 'Helvetica'; // 使用默认字体
}
2. 添加图片时提示"文件不存在"
问题:图片路径写的是"/sdcard/img.jpg",结果报错
解决方案:鸿蒙应用有沙箱限制,改用应用沙箱路径:
// 正确写法
let imagePath = this.context.filesDir + '/img.jpg';
3. 批注显示位置不对
问题:设置的坐标看起来是对的,但批注显示位置却不对
解决方案:记住PDF的坐标系统原点在左下角,不是左上角:
// 调整坐标到页面上半部分
let pageHeight = page.getHeight();
annotationInfo.y = pageHeight - 200; // 距离顶部200像素
六、批注类型一览
PDF Kit支持13种批注类型,除了文本批注,还有这些常用的:
- LineAnnotationInfo:下划线批注
- HighlightAnnotationInfo:高亮批注
- StrikethroughAnnotationInfo:删除线批注
每种批注都有自己的特性和使用场景,可以根据需要选择合适的批注类型~
七、完整代码示例
import { pdfService } from '@kit.PDFKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { Font } from '@kit.ArkUI';
@Entry
@Component
struct PdfPage {
private pdfDocument: pdfService.PdfDocument = new pdfService.PdfDocument();
private context = this.getUIContext().getHostContext() as Context;
aboutToAppear(): void {
// 确保沙箱目录有input.pdf文档
let filePath = this.context.filesDir + '/input.pdf';
this.pdfDocument.loadDocument(filePath);
}
build() {
Column() {
// 添加文本
Button('添加文本')
.margin(10)
.onClick(async () => {
try {
let page: pdfService.PdfPage = this.pdfDocument.getPage(0);
let textContent = '这是用鸿蒙PDF Kit添加的文本!';
let fontInfo = new pdfService.FontInfo();
let font: Font = new Font();
fontInfo.fontPath = font.getFontByName('HarmonyOS Sans')?.path;
fontInfo.fontName = '';
let style: pdfService.TextStyle = {
textColor: 0x000000,
textSize: 30,
fontInfo: fontInfo
};
page.addTextObject(textContent, 10, 10, style);
let outPdfPath = this.context.filesDir + '/testAddText.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
hilog.info(0x0000, 'PdfPage', '添加文本 %{public}s!', result ? '成功' : '失败');
} catch (e) {
hilog.error(0x0000, 'PdfPage', '添加文本失败: %{public}s', JSON.stringify(e));
}
})
// 删除文本
Button('删除文本')
.margin(10)
.onClick(async () => {
try {
let page: pdfService.PdfPage = this.pdfDocument.getPage(0);
let graphicsObjects = page.getGraphicsObjects();
let index = graphicsObjects.findIndex(
item => item.type === pdfService.GraphicsObjectType.OBJECT_TEXT
);
if (index > -1) {
page.deleteGraphicsObject(graphicsObjects[index]);
}
let outPdfPath = this.context.filesDir + '/testDelText.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
hilog.info(0x0000, 'PdfPage', '删除文本 %{public}s!', result ? '成功' : '失败');
} catch (e) {
hilog.error(0x0000, 'PdfPage', '删除文本失败: %{public}s', JSON.stringify(e));
}
})
// 添加图片
Button('添加图片')
.margin(10)
.onClick(async () => {
try {
let page: pdfService.PdfPage = this.pdfDocument.getPage(0);
let imagePath = this.context.filesDir + '/img.jpg';
page.addImageObject(imagePath, 100, 100, 100, 120);
let outPdfPath = this.context.filesDir + '/testAddImage.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
hilog.info(0x0000, 'PdfPage', '添加图片 %{public}s!', result ? '成功' : '失败');
} catch (e) {
hilog.error(0x0000, 'PdfPage', '添加图片失败: %{public}s', JSON.stringify(e));
}
})
// 添加文本批注
Button('添加文本批注')
.margin(10)
.onClick(async () => {
try {
let filePath = this.context.filesDir + '/input.pdf';
this.pdfDocument.loadDocument(filePath);
let page: pdfService.PdfPage = this.pdfDocument.getPage(0);
let annotationInfo = new pdfService.TextAnnotationInfo();
annotationInfo.iconName = 'cument Format';
annotationInfo.content = '这是批注内容,用来标注重要信息!';
annotationInfo.subject = '批注';
annotationInfo.title = '这是批注标题';
annotationInfo.state = pdfService.TextAnnotationState.MARKED;
annotationInfo.x = 200;
annotationInfo.y = 200;
annotationInfo.color = 0xf9b1b1;
annotationInfo.flag = pdfService.AnnotationFlag.PRINTED;
let annotation: pdfService.PdfAnnotation = page.addAnnotation(annotationInfo);
let outPdfPath = this.context.filesDir + '/testAddTextAnnotation.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
this.pdfDocument.releaseDocument();
hilog.info(0x0000, 'PdfPage', '添加文本批注 %{public}s!', result ? '成功' : '失败');
} catch (e) {
hilog.error(0x0000, 'PdfPage', '添加文本批注失败: %{public}s', JSON.stringify(e));
}
})
}
.padding(20)
}
}
八、实用资源推荐
📚 推荐资料:
我是盐焗西兰花,
不教理论,只给你能跑的代码和避坑指南。
下期见!🥦
更多推荐

所有评论(0)