【鸿蒙开发】第五十二章 PDF Kit(PDF服务)
目录
1 概述
1.1 pdfService与PdfView能力比较
1.2 约束与限制
1.2.1 支持的设备
2 pdfService能力
2.1 打开和保存PDF文档
2.1.1 接口说明
2.1.2 示例代码
2.2 添加、删除PDF页
2.2.1 接口说明
2.2.2 示例代码
2.3 PDF页面文本、图片和批注
2.3.1 接口说明
2.3.2 添加文本和图片
2.3.3 添加文本批注
2.4 转换PDF文档指定页面或指定区域为图片
2.4.1 场景介绍
2.4.2 接口说明
2.4.3 示例代码
2.5 转换整个PDF文档为图片
2.5.1 场景介绍
2.5.2 接口说明
2.5.3 示例代码
2.6 判断PDF文档是否加密及删除加密
2.6.1 接口说明
2.6.2 示例代码
2.7 添加、删除书签
2.7.1 接口说明
2.7.2 示例代码
2.8 添加、删除页眉页脚
2.8.1 接口说明
2.8.2 示例代码
2.9 添加、删除水印
2.9.1 接口说明
2.9.2 示例代码
1、添加文本水印
2、添加图片水印
2.10 添加、删除背景
2.10.1 接口说明
2.10.2 示例代码
3 PdfView预览组件
3.1 预览PDF文档
3.1.1 示例代码
3.2 打开和保存PDF文档
3.2.1 场景介绍
3.2.2 接口说明
3.2.3 示例代码
3.3 设置PDF文档预览效果
3.3.1 接口说明
3.3.2 示例代码
3.4 搜索关键字
3.4.1 接口说明
3.4.2 示例代码
3.5 高亮显示PDF文档
3.5.1 接口说明
3.5.2 示例代码
3.6 批注
3.6.1 接口说明
3.6.2 示例代码
3.7 PDF页面转换为图片
3.7.1 场景介绍
3.7.2 接口说明
3.7.3 示例代码
1 概述
PDF Kit(PDF服务)包含pdfService和PdfView组件。
pdfService提供了加载和保存PDF文档、在PDF页面中添加文本内容、图片、批注、页眉页脚、水印、背景图片、书签、判断PDF文档是否加密及删除文档加密等相关的功能,对PDF文档的操作有更多的应用场景。
PdfView组件提供了文档预览功能,如:PDF文档预览、高亮显示、搜索关键字,批注等场景。
1.1 pdfService与PdfView能力比较
PDF Kit能力 | pdfService是否支持 | PdfView预览组件是否支持 |
---|---|---|
打开和保存文档 | 支持 | 支持 |
释放文档 | 支持 | 支持 |
PDF文档转图片 | 支持 | 支持 |
添加、删除批注 | 支持 | 支持 |
管理书签 | 支持 | 不支持 |
添加、编辑、删除PDF页 | 支持 | 不支持 |
添加、删除文本内容 | 支持 | 不支持 |
添加、删除图片内容 | 支持 | 不支持 |
编辑页眉页脚、水印、背景 | 支持 | 不支持 |
判断PDF文档是否加密 | 支持 | 不支持 |
删除文档加密 | 支持 | 不支持 |
PDF文档预览 | 不支持 | 支持 |
搜索关键字 | 不支持 | 支持 |
PDF文档监听回调 | 不支持 | 支持 |
1.2 约束与限制
1.2.1 支持的设备
当前PDF Kit相关能力只支持在真机上运行,华为Phone、Tablet和2in1,暂不支持在模拟器上运行。
2 pdfService能力
2.1 打开和保存PDF文档
对PDF文档添加内容、页眉页脚、水印、背景图片或书签等操作前,需要打开文档,并且在文档操作完成后,保存PDF文档。
pdfService和PdfView都可实现打开和保存文档,使用场景上有如下区别:
- 需要对PDF文档做相关的编辑和操作,建议使用pdfService的能力打开和保存文档。
- 需要预览、搜索关键字、监听PDF文档回调和批注等操作,推荐使用PdfView打开。
2.1.1 接口说明
接口名 | 描述 |
---|---|
loadDocument(path: string, password?: string, onProgress?: Callback<number>): ParseResult | 加载指定文档路径。 |
saveDocument(path: string, onProgress?: Callback<number>): boolean | 保存文档。 |
2.1.2 示例代码
- 调用loadDocument方法,加载PDF文档。
- 在【Save As】和【Save】两个按钮中调用saveDocument方法,分别实现了另存为PDF文档和保存覆盖源PDF文档的两种方式。
import { common } from '@kit.AbilityKit';
import { pdfService } from '@kit.PDFKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { fileIo } from '@kit.CoreFileKit';
@Entry
@Component
struct PdfPage {
private pdfDocument: pdfService.PdfDocument = new pdfService.PdfDocument();
private context = getContext() as common.UIAbilityContext;
private filePath = '';
@State saveEnable: boolean = false;
aboutToAppear(): void {
this.filePath = this.context.filesDir + '/input.pdf';
let res = fileIo.accessSync(this.filePath);
if(!res) {
// 确保在工程目录src/main/resources/rawfile里有input.pdf文档
let content: Uint8Array = this.context.resourceManager.getRawFileContentSync('rawfile/input.pdf');
let fdSand =
fileIo.openSync(this.filePath, fileIo.OpenMode.WRITE_ONLY | fileIo.OpenMode.CREATE | fileIo.OpenMode.TRUNC);
fileIo.writeSync(fdSand.fd, content.buffer);
fileIo.closeSync(fdSand.fd);
}
this.pdfDocument.loadDocument(this.filePath);
}
build() {
Column() {
// 另存为一份PDF文档
Button('Save As').onClick(() => {
// 可以对PDF文档添加页眉页脚,水印,背景等一些内容,然后另存文档
let outPdfPath = this.context.filesDir + '/testSaveAsPdf.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
this.saveEnable = true;
hilog.info(0x0000, 'PdfPage', 'saveAsPdf %{public}s!', result ? 'success' : 'fail');
})
// 保存覆盖源PDF文档
Button('Save').enabled(this.saveEnable).onClick(() => {
// 这里可以对PDF文档添加内容、页眉页脚、水印、背景等一些内容,然后保存文档
let tempDir = this.context.tempDir;
let tempFilePath = tempDir + `/temp${Math.random()}.pdf`;
fileIo.copyFileSync(this.filePath, tempFilePath);
let pdfDocument: pdfService.PdfDocument = new pdfService.PdfDocument();
// 加载临时文档
let loadResult = pdfDocument.loadDocument(tempFilePath, '');
if (loadResult === pdfService.ParseResult.PARSE_SUCCESS) {
let result = pdfDocument.saveDocument(this.filePath);
hilog.info(0x0000, 'PdfPage', 'savePdf %{public}s!', result ? 'success' : 'fail');
}
})
}
}
}
2.2 添加、删除PDF页
在PDF文档中添加或删除页面,包括:
- 添加单个、多个空白页到PDF文档。
- 删除PDF文档中单个、多个指定页。
- 将其他PDF文档页添加到本PDF文档。
2.2.1 接口说明
接口名 | 描述 |
---|---|
insertBlankPage(index: number, width: number, height: number): PdfPage | 在指定位置插入空白PDF页。 |
getPage(index: number): PdfPage | 获取指定页的对象。 |
insertPageFromDocument(document: PdfDocument, fromIndex: number, pageCount: number, index: number): PdfPage | 将其他文档的页添加到当前文档。 |
deletePage(index: number, count: number): void | 删除指定的PDF页。 |
2.2.2 示例代码
- 调用loadDocument方法,加载PDF文档。
- 调用getPage方法获取当前页,用于获取页面宽高。
- 调用insertBlankPage和insertPageFromDocument方法实现如下功能。
- 插入单个空白页。
- 插入多个空白页。
- 将input2.pdf文档的索引1、2、3页插入到input.pdf索引0的位置,并另存文档。
- 调用deletePage方法删除单个或多个索引页。
import { pdfService } from '@kit.PDFKit';
import { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
@Entry
@Component
struct PdfPage {
private pdfDocument: pdfService.PdfDocument = new pdfService.PdfDocument();
private context = getContext() as common.UIAbilityContext;
aboutToAppear(): void {
// 确保沙箱目录有input.pdf文档
let filePath = this.context.filesDir + '/input.pdf';
this.pdfDocument.loadDocument(filePath);
}
build() {
Column() {
// 插入单个空白页
Button('insertBankPage').onClick(async () => {
let page: pdfService.PdfPage = this.pdfDocument.getPage(0);
let page2: pdfService.PdfPage = this.pdfDocument.insertBlankPage(2, page.getWidth(), page.getHeight());
let outPdfPath = this.context.filesDir + '/testInsertBankPage.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
hilog.info(0x0000, 'PdfPage', 'insertBankPage %{public}s!', result ? 'success' : 'fail');
})
// 插入多个空白页
Button('insertSomeBankPage').onClick(async () => {
let page: pdfService.PdfPage = this.pdfDocument.getPage(0);
for (let i = 0; i < 3; i++) {
this.pdfDocument.insertBlankPage(2, page.getWidth(), page.getHeight());
}
let outPdfPath = this.context.filesDir + '/testInsertSomeBankPage.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
hilog.info(0x0000, 'PdfPage', 'insertSomeBankPage %{public}s!', result ? 'success' : 'fail');
})
// 将input2.pdf文档的索引1,2,3页插入到input.pdf索引0的位置,并另存文档
Button('insertPageFromDocument').onClick(async () => {
let pdfDoc: pdfService.PdfDocument = new pdfService.PdfDocument();
// 确保该沙箱目录下有 input2.pdf文档
pdfDoc.loadDocument(this.context.filesDir + '/input2.pdf');
this.pdfDocument.insertPageFromDocument(pdfDoc, 1, 3, 0);
let outPdfPath = this.context.filesDir + '/testInsertPageFromDocument.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
hilog.info(0x0000, 'PdfPage', 'insertPageFromDocument %{public}s!', result ? 'success' : 'fail');
})
// 删除单个或多个索引页
Button('deletePage').onClick(async () => {
this.pdfDocument.deletePage(2, 2);
let outPdfPath = this.context.filesDir + '/testDeletePage.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
hilog.info(0x0000, 'PdfPage', 'deletePage %{public}s!', result ? 'success' : 'fail');
})
}
}
}
2.3 PDF页面文本、图片和批注
支持编辑PDF页面内容,包括:
- 添加、删除文本。
- 添加、删除图片。
- 添加、修改、删除批注。
通过索引指定PDF页面添加批注,并对批注在页面中的位置,字体、批注边框等设置,批注提供了多种风格样式,包括:文本批注TextAnnotationInfo、下划线批注LineAnnotationInfo、高亮批注HighlightAnnotationInfo、删除线批注StrikethroughAnnotationInfo等共13种。
2.3.1 接口说明
接口名 | 描述 |
---|---|
addTextObject(text: string, x: number, y: number, style: TextStyle): void | 添加文本内容,只可按行添加。 |
addImageObject(path: string, x: number, y: number, width: number, height: number): void | 在PDF文档的页面中添加图片。 |
deleteGraphicsObject(object: GraphicsObject): void | 删除指定的GraphicsObject。 |
addAnnotation(annotationInfo: PdfAnnotationInfo): PdfAnnotation | 在当前页添加批注。 |
2.3.2 添加文本和图片
- 调用loadDocument方法,加载PDF文档。
- 在【addText】按钮中调用addTextObject的方法插入文本。
- 在【delText】按钮中调用deleteGraphicsObject方法来删除相应的页面文本。
- 在【addImage】按钮中调用addImageObject的方法插入图片。
import { pdfService } from '@kit.PDFKit';
import { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { font } from '@kit.ArkUI';
@Entry
@Component
struct PdfPage {
private pdfDocument: pdfService.PdfDocument = new pdfService.PdfDocument();
private context = getContext() as common.UIAbilityContext;
aboutToAppear(): void {
// 确保沙箱目录有input.pdf文档
let filePath = this.context.filesDir + '/input.pdf';
this.pdfDocument.loadDocument(filePath);
}
build() {
Column() {
// 添加文本
Button('addText').onClick(async () => {
let page: pdfService.PdfPage = this.pdfDocument.getPage(0);
let str = 'This is add text object!';
let fontInfo = new pdfService.FontInfo();
// 确保字体路径存在
fontInfo.fontPath = font.getFontByName('HarmonyOS Sans')?.path;
fontInfo.fontName = '';
let style: pdfService.TextStyle = { textColor: 0x000000, textSize: 30, fontInfo };
page.addTextObject(str, 10, 10, style);
let outPdfPath = this.context.filesDir + '/testAddText.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
hilog.info(0x0000, 'PdfPage', 'addText %{public}s!', result ? 'success' : 'fail');
})
// 删除文本
Button('delText').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', 'delText %{public}s!', result ? 'success' : 'fail');
})
// 添加图片
Button('addImage').onClick(async () => {
let page: pdfService.PdfPage = this.pdfDocument.getPage(0);
// 插入图片,确保沙箱目录有img.jpg图片
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', 'addImage %{public}s!', result ? 'success' : 'fail');
})
}
}
}
2.3.3 添加文本批注
- 调用loadDocument方法,加载PDF文档。
- 调用getPage方法获取指定页。
- 实例化TextAnnotationInfo文本批注,并设置相关属性。
- 调用addAnnotation或setAnnotation方法添加或修改批注。
- 调用removeAnnotation方法删除批注。
import { pdfService } from '@kit.PDFKit';
import { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
@Entry
@Component
struct PdfPage {
private pdfDocument: pdfService.PdfDocument = new pdfService.PdfDocument();
private context = getContext() as common.UIAbilityContext;
build() {
Column() {
// 添加批注
Button('addTextAnnotation').onClick(async () => {
// 确保沙箱目录有input.pdf文档
let filePath = this.context.filesDir + '/input.pdf';
this.pdfDocument.loadDocument(filePath);
let page: pdfService.PdfPage = this.pdfDocument.getPage(0);
let aInfo = new pdfService.TextAnnotationInfo();
aInfo.iconName = 'cument Format';
aInfo.content = 'this is a content';
aInfo.subject = 'Annotation';
aInfo.title = 'this is a title';
aInfo.state = pdfService.TextAnnotationState.MARKED;
aInfo.x = 200;
aInfo.y = 200;
aInfo.color = 0xf9b1b1;
aInfo.flag = pdfService.AnnotationFlag.PRINTED;
let annotation: pdfService.PdfAnnotation = page.addAnnotation(aInfo);
let outPdfPath = this.context.filesDir + '/testAddTextAnnotation.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
this.pdfDocument.releaseDocument();
hilog.info(0x0000, 'PdfPage', 'addTextAnnotation %{public}s!', result ? 'success' : 'fail');
})
// 修改批注
Button('setAnnotation').onClick(async () => {
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) {
let newAnno = annotations[0];
page.removeAnnotation(newAnno);
let annotation = page.addAnnotation(newAnno);
let newInfo = new pdfService.TextAnnotationInfo();
newInfo.title = "new Title";
newInfo.content = "new Info";
newInfo.state = pdfService.TextAnnotationState.MARKED;
newInfo.x = 100;
newInfo.y = 100;
page.setAnnotation(annotation, newInfo);
let outPdfPath = this.context.filesDir + '/testSetAnnotation.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
this.pdfDocument.releaseDocument();
hilog.info(0x0000, 'PdfPage', 'setAnnotation %{public}s!', result ? 'success' : 'fail');
}
}
})
// 删除批注
Button('removeAnnotation').onClick(async () => {
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 result = this.pdfDocument.saveDocument(outPdfPath);
this.pdfDocument.releaseDocument();
hilog.info(0x0000, 'PdfPage', 'removeAnnotation %{public}s!', result ? 'success' : 'fail');
}
}
})
}
}
}
2.4 转换PDF文档指定页面或指定区域为图片
2.4.1 场景介绍
PDF文档页面转换为图片,或将页面的指定区域转换为图片时使用。
2.4.2 接口说明
接口名 | 描述 |
---|---|
getPagePixelMap(): image.PixelMap | 获取当前页的图片。 |
getCustomPagePixelMap(matrix: PdfMatrix, isGray: boolean, drawAnnotations: boolean): image.PixelMap | 获取指定PdfPage区域的图片内容。 |
getAreaPixelMap(matrix: PdfMatrix, bitmapwidth: number, bitmapHeight: number, isGray: boolean, drawAnnotations: boolean): image.PixelMap | 获取指定PdfPage区域的图片内容,并指定图片的宽和高。 |
2.4.3 示例代码
- 调用loadDocument方法加载PDF文档。
- 调用getPage方法获取某个页面。
- 调用getPagePixelMap或getCustomPagePixelMap方法获取当前页面或者页面区域,这时获取的是image.PixelMap图像类型。
- 将image.PixelMap图像类型转化为二进制图片文件并保存,参考以下方法pixelMap2Buffer。
import { pdfService } from '@kit.PDFKit';
import { image } from '@kit.ImageKit';
import { fileIo as fs } from '@kit.CoreFileKit';
import { common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
struct PdfPage {
private pdfDocument: pdfService.PdfDocument = new pdfService.PdfDocument();
private context = getContext() as common.UIAbilityContext;
private loadResult: pdfService.ParseResult = pdfService.ParseResult.PARSE_ERROR_FORMAT;
aboutToAppear(): void {
// 确保沙箱目录有input.pdf文档
let filePath = this.context.filesDir + '/input.pdf';
this.loadResult = this.pdfDocument.loadDocument(filePath);
}
// 将 pixelMap 转成图片格式
pixelMap2Buffer(pixelMap: image.PixelMap): Promise<ArrayBuffer> {
return new Promise((resolve, reject) => {
/**
设置打包参数
format:图片打包格式,只支持 jpg 和 webp
quality:JPEG 编码输出图片质量
bufferSize:图片大小,默认 10M
*/
let packOpts: image.PackingOption = { format: 'image/jpeg', quality: 98 }
// 创建ImagePacker实例
const imagePackerApi = image.createImagePacker()
imagePackerApi.packToData(pixelMap, packOpts).then((buffer: ArrayBuffer) => {
resolve(buffer)
}).catch((err: BusinessError) => {
reject()
})
})
}
build() {
Column() {
// 获取为图片并保存到应用沙箱
Button('getPagePixelMap').onClick(async () => {
if (this.loadResult === pdfService.ParseResult.PARSE_SUCCESS) {
let page = this.pdfDocument.getPage(0)
let pixmap: image.PixelMap = page.getPagePixelMap();
if (!pixmap) {
return
}
const imgBuffer = await this.pixelMap2Buffer(pixmap)
const file =
fs.openSync(this.context.filesDir + `/${Date.now()}.png`, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
await fs.write(file.fd, imgBuffer)
// 关闭文档
await fs.close(file.fd)
}
})
// 获取指定PdfPage区域的图片内容。
Button('getCustomPagePixelMap').onClick(async () => {
if (this.loadResult === pdfService.ParseResult.PARSE_SUCCESS) {
let page = this.pdfDocument.getPage(0);
let matrix = new pdfService.PdfMatrix();
matrix.x = 100;
matrix.y = 100;
matrix.width = 500;
matrix.height = 500;
matrix.rotate = 0;
let pixmap: image.PixelMap = page.getCustomPagePixelMap(matrix, false, false);
if (!pixmap) {
return;
}
const imgBuffer = await this.pixelMap2Buffer(pixmap);
const file =
fs.openSync(this.context.filesDir + `/${Date.now()}.jpeg`, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
await fs.write(file.fd, imgBuffer);
// 关闭文件
await fs.close(file.fd);
}
})
// 获取指定PdfPage区域的图片内容
Button('getAreaPixelMap').onClick(async () => {
if (this.loadResult === pdfService.ParseResult.PARSE_SUCCESS) {
let page = this.pdfDocument.getPage(0);
let matrix = new pdfService.PdfMatrix();
matrix.x = 100;
matrix.y = 100;
matrix.width = 500;
matrix.height = 500;
matrix.rotate = 0;
let pixmap: image.PixelMap = page.getAreaPixelMap(matrix, 400, 400, true, false);
if (!pixmap) {
return
}
const imgBuffer = await this.pixelMap2Buffer(pixmap)
const file =
fs.openSync(this.context.filesDir + `/${Date.now()}.bmp`, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
await fs.write(file.fd, imgBuffer)
// 关闭文件
await fs.close(file.fd);
}
})
}
}
}
2.5 转换整个PDF文档为图片
2.5.1 场景介绍
将整个PDF文档的页面转换为图片,每页为一张图片,并且所有图片存放在指定的同一个文件夹下。
2.5.2 接口说明
接口名 | 描述 |
---|---|
convertToImage(path: string, format: ImageFormat, onProgress?: Callback<number>): boolean | 转换PDF文档为图片。 |
2.5.3 示例代码
- 调用loadDocument方法,加载PDF文档。
- 设置要输出图片的文件夹,调用convertToImage方法转化PDF文档所有页面为图片。
import { fileIo as fs } from '@kit.CoreFileKit';
import { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { pdfService } from '@kit.PDFKit';
@Entry
@Component
struct PdfPage {
private pdfDocument: pdfService.PdfDocument = new pdfService.PdfDocument();
private context = getContext() as common.UIAbilityContext;
private loadResult: pdfService.ParseResult = pdfService.ParseResult.PARSE_ERROR_FORMAT;
aboutToAppear(): void {
// 确保沙箱目录有input.pdf文档
let filePath = this.context.filesDir + '/input.pdf';
this.loadResult = this.pdfDocument.loadDocument(filePath);
}
build() {
Column() {
// 获取为图片并保存到应用沙箱
Button('convertToImage').onClick(async () => {
if (this.loadResult === pdfService.ParseResult.PARSE_SUCCESS) {
let outputPath = getContext().filesDir + '/output/';
fs.mkdir(outputPath);
// 将所有的页面转化为png图片,并存储在output文件夹里
let res = this.pdfDocument.convertToImage(outputPath, pdfService.ImageFormat.PNG);
hilog.info(0x0000, 'PdfPage', 'convertToImage %{public}s!', res ? 'success' : 'fail');
}
})
}
}
}
2.6 判断PDF文档是否加密及删除加密
PDF Kit支持判断PDF文档是否加密及删除PDF加密锁。
当前PDF Kit不支持PDF文档加密。
2.6.1 接口说明
接口名 | 描述 |
---|---|
isEncrypted(path: string): boolean | 判断当前文档是否已加密。 |
removeSecurity(): boolean | 删除文档加密锁。 |
2.6.2 示例代码
- 调用isEncrypted方法,判断的PDF文档是否加密。
- 如果是加密PDF文档,调用removeSecurity方法移除PDF文档的加密锁。
import { pdfService } from '@kit.PDFKit';
import { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
@Entry
@Component
struct PdfPage {
private pdfDocument: pdfService.PdfDocument = new pdfService.PdfDocument();
private context = getContext() as common.UIAbilityContext;
build() {
Column() {
// 判断文档是否加密,并删除加密
Button('isEncryptedAndRemoveSecurity').onClick(async () => {
// 确保沙箱目录有input.pdf文档
let filePath = this.context.filesDir + '/input.pdf';
let isEncrypt = this.pdfDocument.isEncrypted(filePath);
if (isEncrypt) {
let hasRemoveEncrypt = this.pdfDocument.removeSecurity();
hilog.info(0x0000, 'PdfPage', 'isEncryptedAndRemoveSecurity %{public}s!',
hasRemoveEncrypt ? 'success' : 'fail');
}
})
}
}
}
2.7 添加、删除书签
PDF Kit支持添加和删除PDF文档书签。
添加书签时,可设置标题、颜色,是否粗体、斜体、跳转信息等。
2.7.1 接口说明
接口名 | 描述 |
---|---|
createBookmark(): Bookmark | 创建PDF文档书签。 |
getRootBookmark(): Bookmark | 获取PDF文档第一个根书签。 |
insertBookmark(bookmark: Bookmark, parent: Bookmark, position: number): boolean | 插入PDF文档书签。 |
setBookmarkInfo(info: BookmarkInfo): void | 设置书签信息。 |
removeBookmark(bookmark: Bookmark): boolean | 移除PDF文档书签。 |
2.7.2 示例代码
- 调用loadDocument方法,加载PDF文档。
- 调用createBookmark方法,创建书签。
- 调用setDestInfo方法,设置书签的跳转信息。
- 调用setBookmarkInfo方法,设置书签内容及样式。
- 设置保存文档沙箱路径并保存。
import { pdfService } from '@kit.PDFKit';
import { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
@Entry
@Component
struct PdfPage {
private pdfDocument: pdfService.PdfDocument = new pdfService.PdfDocument();
private context = getContext() as common.UIAbilityContext;
build() {
Column() {
// 添加书签
Button('addBookmark').onClick(async () => {
// 确保沙箱目录有input.pdf文档
let filePath = this.context.filesDir + '/input.pdf';
this.pdfDocument.loadDocument(filePath);
// 创建书签
let mark1: pdfService.Bookmark = this.pdfDocument.createBookmark();
let mark2: pdfService.Bookmark = this.pdfDocument.createBookmark();
// 设置书签的跳转信息
let destInfo: pdfService.DestInfo = mark1.getDestInfo();
destInfo.fitMode = pdfService.FitMode.FIT_MODE_XYZ;
destInfo.pageIndex = 1;
destInfo.left = 20;
destInfo.top = 30;
destInfo.zoom = 1.5;
mark1.setDestInfo(destInfo);
// 设置书签内容及样式
let bookInfo: pdfService.BookmarkInfo = mark1.getBookmarkInfo();
bookInfo.title = '这里是跳到第一页的书签';
bookInfo.titleColor = 12;
bookInfo.isBold = true;
bookInfo.isItalic = true;
mark1.setBookmarkInfo(bookInfo);
// 把创建的书签插入到PDF页面
this.pdfDocument.insertBookmark(mark1, null, 1);
this.pdfDocument.insertBookmark(mark2, mark1, 1);
// 设置保存文档沙箱路径并保存
let outPdfPath = this.context.filesDir + '/testAddBookmark.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
hilog.info(0x0000, 'PdfPage', 'saveAddBookmark %{public}s!', result ? 'success' : 'fail');
})
// 删除书签
Button('removeBookmark').onClick(async () => {
// 确保沙箱目录有testAddBookmark.pdf文档
this.pdfDocument.loadDocument(this.context.filesDir + '/testAddBookmark.pdf');
let bookmarks: pdfService.Bookmark = this.pdfDocument.getRootBookmark();
if (bookmarks.isRootBookmark()) {
let hasRemoveBookmark: boolean = this.pdfDocument.removeBookmark(bookmarks);
hilog.info(0x0000, 'PdfPage', 'removeBookmark %{public}s!', hasRemoveBookmark ? 'success' : 'fail');
let outPdfPath = this.context.filesDir + '/testRemoveBookmark.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
hilog.info(0x0000, 'PdfPage', 'saveRemoveBookmark %{public}s!', result ? 'success' : 'fail');
}
})
}
}
}
2.8 添加、删除页眉页脚
PDF Kit支持对指定页面添加、删除页眉页脚。页眉页脚信息包含文字、日期和页码等相关内容,并可设置字体大小、颜色和间距等相关样式,具体属性参考HeaderFooterInfo。如下图:
2.8.1 接口说明
接口名 | 描述 |
---|---|
addHeaderFooter(info: HeaderFooterInfo, startIndex: number, endIndex: number, oddPages: boolean, evenPages: boolean): void | 插入PDF文档页眉页脚。 |
removeHeaderFooter(): boolean | 删除PDF文档页眉页脚。 |
注意
addHeaderFooter方法属于耗时业务,需要遍历每一页去添加页眉页脚,添加页面较多时建议放到线程里去处理。
2.8.2 示例代码
- 调用loadDocument方法,加载PDF文档。
- 实例化页眉页脚HeaderFooterInfo类,并设置相关属性,包括字体大小、颜色和间距等。
- 调用addHeaderFooter方法,添加页眉页脚到页面中。
- 保存PDF文档到应用沙箱。
import { pdfService } from '@kit.PDFKit';
import { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { font } from '@kit.ArkUI';
@Entry
@Component
struct PdfPage {
private pdfDocument: pdfService.PdfDocument = new pdfService.PdfDocument();
private context = getContext() as common.UIAbilityContext;
build() {
Column() {
Button('addHeaderFooter').onClick(async () => {
// 确保沙箱目录有input.pdf文档
let filePath = this.context.filesDir + '/input.pdf';
let res = this.pdfDocument.loadDocument(filePath);
if (res === pdfService.ParseResult.PARSE_SUCCESS) {
let hfInfo: pdfService.HeaderFooterInfo = new pdfService.HeaderFooterInfo();
hfInfo.fontInfo = new pdfService.FontInfo();
// 确保字体路径存在
hfInfo.fontInfo.fontPath = font.getFontByName('HarmonyOS Sans')?.path;
// 如果不知道字体的具体名称,可以为空字符串
hfInfo.fontInfo.fontName = '';
hfInfo.textSize = 10;
hfInfo.charset = pdfService.CharsetType.PDF_FONT_DEFAULT_CHARSET;
hfInfo.underline = false;
hfInfo.textColor = 0x00000000;
hfInfo.leftMargin = 1.0;
hfInfo.topMargin = 40.0;
hfInfo.rightMargin = 1.0;
hfInfo.bottomMargin = 40.0;
hfInfo.headerLeftText = 'left H <<dd.mm.yyyy>> <<1/n>>';
hfInfo.headerCenterText = 'center H <<m/d/yyyy>> <<1/n>>';
hfInfo.headerRightText = 'right H <<m/d>><<1>>';
hfInfo.footerLeftText = 'left F <<m/d>><<1>>';
hfInfo.footerCenterText = 'center F <<m/d>><<1>>';
hfInfo.footerRightText = 'right F <<dd.mm.yyyy>><<1>>';
this.pdfDocument.addHeaderFooter(hfInfo, 1, 5, true, true);
let outPdfPath = this.context.filesDir + '/testAddHeaderFooter.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
hilog.info(0x0000, 'PdfPage', 'addHeaderFooter %{public}s!', result ? 'success' : 'fail');
}
this.pdfDocument.releaseDocument();
})
Button('removeHeaderFooter').onClick(async () => {
let filePath = this.context.filesDir + '/testAddHeaderFooter.pdf';
let res = this.pdfDocument.loadDocument(filePath);
if (res === pdfService.ParseResult.PARSE_SUCCESS && this.pdfDocument.hasHeaderFooter()) {
let removeResult = this.pdfDocument.removeHeaderFooter();
if (removeResult) {
let outPdfPath = this.context.filesDir + '/removeHeaderFooter.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
hilog.info(0x0000, 'PdfPage', 'removeHeaderFooter %{public}s!', result ? 'success' : 'fail');
}
}
this.pdfDocument.releaseDocument();
})
}
}
}
2.9 添加、删除水印
对指定页面添加水印,包括文本水印或图片水印。
- 文本水印可以设置字体、大小、旋转,位置等属性。
- 图片水印可以设置缩放、旋转、透明度和位置等属性。
2.9.1 接口说明
接口名 | 描述 |
---|---|
addWatermark(info: WatermarkInfo, startIndex: number, endIndex: number, oddPages: boolean, evenPages: boolean): void | 插入水印到PDF文档。如果插入的是图片,支持的图片格式参考ImageFormat,文本字符无限制。 |
removeWatermark(): boolean | 删除PDF文档水印。 |
注意
addWatermark方法属于耗时业务,需要遍历每一页去添加水印,添加页面较多时建议放到线程里去处理。
2.9.2 示例代码
1、添加文本水印
- 调用loadDocument方法,加载PDF文档。
- 实例化文本水印TextWatermarkInfo类,并设置相关属性,包括字体、大小、旋转,位置等。
- 调用addWatermark或removeWatermark,添加或删除文本水印。
- 保存PDF文档到应用沙箱。
import { pdfService } from '@kit.PDFKit';
import { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { font } from '@kit.ArkUI';
@Entry
@Component
struct PdfPage {
private pdfDocument: pdfService.PdfDocument = new pdfService.PdfDocument();
private context = getContext() as common.UIAbilityContext;
build() {
Column() {
Button('addTextWatermark').onClick(async () => {
// 确保沙箱目录有input.pdf文档
let filePath = this.context.filesDir + '/input.pdf';
let res = this.pdfDocument.loadDocument(filePath);
if (res === pdfService.ParseResult.PARSE_SUCCESS) {
let wminfo: pdfService.TextWatermarkInfo = new pdfService.TextWatermarkInfo();
wminfo.watermarkType = pdfService.WatermarkType.WATERMARK_TEXT;
wminfo.content = 'This is Watermark';
wminfo.textSize = 30;
wminfo.textColor = 200;
wminfo.fontInfo = new pdfService.FontInfo();
// 确保字体路径存在
wminfo.fontInfo.fontPath = font.getFontByName('HarmonyOS Sans').path;
wminfo.opacity = 0.5;
wminfo.isOnTop = true;
wminfo.rotation = 45;
wminfo.scale = 1.5;
wminfo.opacity = 0.5;
wminfo.verticalAlignment = pdfService.WatermarkAlignment.WATERMARK_ALIGNMENT_TOP;
wminfo.horizontalAlignment = pdfService.WatermarkAlignment.WATERMARK_ALIGNMENT_LEFT;
wminfo.horizontalSpace = 1.0;
wminfo.verticalSpace = 1.0;
this.pdfDocument.addWatermark(wminfo, 0, 5, true, true);
let outPdfPath = this.context.filesDir + '/testTextWatermark.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
hilog.info(0x0000, 'PdfPage', 'addTextWatermark %{public}s!', result ? 'success' : 'fail');
}
this.pdfDocument.releaseDocument();
})
Button('removeTextWatermark').onClick(async () => {
let filePath = this.context.filesDir + '/testTextWatermark.pdf';
let res = this.pdfDocument.loadDocument(filePath);
if (res === pdfService.ParseResult.PARSE_SUCCESS && this.pdfDocument.hasWatermark()) {
let removeResult = this.pdfDocument.removeWatermark();
if (removeResult) {
let outPdfPath = this.context.filesDir + '/removeWatermark.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
hilog.info(0x0000, 'PdfPage', 'removeWatermark %{public}s!', result ? 'success' : 'fail');
}
}
this.pdfDocument.releaseDocument();
})
}
}
}
2、添加图片水印
- 调用loadDocument方法加载PDF文档。
- 实例化图片水印ImageWatermarkInfo类,并设置相关属性,包括缩放、旋转、透明度和位置等。
- 调用addWatermark或removeWatermark添加或删除图片水印。
- 保存PDF文档到应用沙箱。
import { pdfService } from '@kit.PDFKit';
import { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
@Entry
@Component
struct PdfPage {
private pdfDocument: pdfService.PdfDocument = new pdfService.PdfDocument();
private context = getContext() as common.UIAbilityContext;
build() {
Column() {
Button('addImageWatermark').onClick(async () => {
let filePath = this.context.filesDir + '/input.pdf';
let res = this.pdfDocument.loadDocument(filePath);
if (res === pdfService.ParseResult.PARSE_SUCCESS) {
let wminfo: pdfService.ImageWatermarkInfo = new pdfService.ImageWatermarkInfo();
wminfo.watermarkType = pdfService.WatermarkType.WATERMARK_IMAGE;
// 确保沙箱目录有img.jpg文档
wminfo.imagePath = this.context.filesDir + '/img.jpg';
wminfo.opacity = 0.5;
wminfo.isOnTop = true;
wminfo.rotation = 45;
wminfo.scale = 0.5;
wminfo.opacity = 0.5;
wminfo.verticalAlignment = pdfService.WatermarkAlignment.WATERMARK_ALIGNMENT_TOP;
wminfo.horizontalAlignment = pdfService.WatermarkAlignment.WATERMARK_ALIGNMENT_LEFT;
wminfo.horizontalSpace = 1.0;
wminfo.verticalSpace = 1.0;
this.pdfDocument.addWatermark(wminfo, 0, 5, true, true);
let outPdfPath = this.context.filesDir + '/testImageWatermark.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
hilog.info(0x0000, 'PdfPage', 'addImageWatermark %{public}s!', result ? 'success' : 'fail');
}
this.pdfDocument.releaseDocument();
})
Button('removeImageWatermark').onClick(async () => {
let filePath = this.context.filesDir + '/testImageWatermark.pdf';
let res = this.pdfDocument.loadDocument(filePath);
if (res === pdfService.ParseResult.PARSE_SUCCESS && this.pdfDocument.hasWatermark()) {
let removeResult = this.pdfDocument.removeWatermark();
if (removeResult) {
let outPdfPath = this.context.filesDir + '/removeImageWatermark.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
hilog.info(0x0000, 'PdfPage', 'removeImageWatermark %{public}s!', result ? 'success' : 'fail');
}
}
this.pdfDocument.releaseDocument();
})
}
}
}
2.10 添加、删除背景
对指定页面添加背景图片或背景颜色,并设置大小、旋转、透明度和位置等属性,支持图片格式:PNG、BMP、JPEG。
2.10.1 接口说明
接口名 | 描述 |
---|---|
addBackground(info: BackgroundInfo, startIndex: number, endIndex: number, oddPages: boolean, evenPages: boolean): void | 插入PDF文档背景。 |
removeBackground(): boolean | 删除PDF文档背景。 |
注意
addBackground方法属于耗时业务,需要遍历每一页去添加背景,添加页面较多时建议放到线程里去处理。
2.10.2 示例代码
- 调用loadDocument方法,加载PDF文档。
- 实例化背景BackgroundInfo类,并设置相关属性,包括大小、旋转、透明度和位置等。
- 保存PDF文档到应用沙箱。
import { pdfService } from '@kit.PDFKit';
import { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
@Entry
@Component
struct PdfPage {
private pdfDocument: pdfService.PdfDocument = new pdfService.PdfDocument();
private context = getContext() as common.UIAbilityContext;
build() {
Column() {
Button('addBackground').onClick(async () => {
// 确保沙箱目录有input.pdf文档
let filePath = this.context.filesDir + '/input.pdf';
let res = this.pdfDocument.loadDocument(filePath);
if (res === pdfService.ParseResult.PARSE_SUCCESS) {
let bginfo: pdfService.BackgroundInfo = new pdfService.BackgroundInfo();
// 确保沙箱目录有img.jpg文档
bginfo.imagePath = this.context.filesDir + '/img.jpg';
bginfo.backgroundColor = 50;
bginfo.isOnTop = true;
bginfo.rotation = 45;
bginfo.scale = 0.5;
bginfo.opacity = 0.3;
bginfo.verticalAlignment = pdfService.BackgroundAlignment.BACKGROUND_ALIGNMENT_TOP;
bginfo.horizontalAlignment = pdfService.BackgroundAlignment.BACKGROUND_ALIGNMENT_LEFT;
bginfo.horizontalSpace = 1.0;
bginfo.verticalSpace = 1.0;
this.pdfDocument.addBackground(bginfo, 0, 2, true, true);
let outPdfPath = this.context.filesDir + '/testAddBackground.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
hilog.info(0x0000, 'PdfPage', 'addBackground %{public}s!', result ? 'success' : 'fail');
}
this.pdfDocument.releaseDocument();
})
Button('removeBackground').onClick(async () => {
let filePath = this.context.filesDir + '/testAddBackground.pdf';
let res = this.pdfDocument.loadDocument(filePath);
if (res === pdfService.ParseResult.PARSE_SUCCESS && this.pdfDocument.hasBackground()) {
let removeResult = this.pdfDocument.removeBackground();
if (removeResult) {
let outPdfPath = this.context.filesDir + '/removeBackground.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
hilog.info(0x0000, 'PdfPage', 'removeBackground %{public}s!', result ? 'success' : 'fail');
}
}
this.pdfDocument.releaseDocument();
})
}
}
}
3 PdfView预览组件
3.1 预览PDF文档
PDF Kit提供了丰富的PDF文档预览能力,比如:
- 页面跳转
- 页面缩放
- 单双页显示
- 页面适配
- 滚动视图方式预览
3.1.1 示例代码
- 导入相关模块。
- 以下示例代码中以预览“input.pdf”文件名为例,此时需要确保在工程目录“src/main/resources/rawfile”里存在input.pdf文档,并且拷贝input.pdf文档到沙箱目录。
- 调用loadDocument方法,加载PDF文档。
- 调用PdfView预览组件,渲染显示。
import { pdfService, pdfViewManager, PdfView } from '@kit.PDFKit'
import { common } from '@kit.AbilityKit';
import { fileIo } from '@kit.CoreFileKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
@Entry
@Component
struct Index {
private controller: pdfViewManager.PdfController = new pdfViewManager.PdfController();
aboutToAppear(): void {
let context = getContext() as common.UIAbilityContext;
let dir: string = context.filesDir
// 确保在工程目录src/main/resources/rawfile里存在input.pdf文档
let filePath: string = dir + '/input.pdf';
let res = fileIo.accessSync(filePath);
if (!res) {
let content: Uint8Array = context.resourceManager.getRawFileContentSync('rawfile/input.pdf');
let fdSand =
fileIo.openSync(filePath, fileIo.OpenMode.WRITE_ONLY | fileIo.OpenMode.CREATE | fileIo.OpenMode.TRUNC);
fileIo.writeSync(fdSand.fd, content.buffer);
fileIo.closeSync(fdSand.fd);
}
(async () => {
// 该监听方法只能在文档加载前调用一次
this.controller.registerPageCountChangedListener((pageCount: number) => {
hilog.info(0x0000, 'registerPageCountChanged-', pageCount.toString());
});
let loadResult1: pdfService.ParseResult = await this.controller.loadDocument(filePath);
// 注意:这里刚加载文档,请不要在这里立即设置PDF文档的预览方式
})()
}
build() {
Row() {
PdfView({
controller: this.controller,
pageFit: pdfService.PageFit.FIT_WIDTH,
showScroll: true
})
.id('pdfview_app_view')
.layoutWeight(1);
}
.width('100%')
.height('100%')
}
}
3.2 打开和保存PDF文档
3.2.1 场景介绍
通过加载本地路径的PDF文档,实现打开PDF文档的预览功能。当PDF文档做了批注等相关的信息时,可以使用保存功能。
3.2.2 接口说明
接口名 | 描述 |
---|---|
loadDocument(path: string, password?: string, initPageIndex?: number, onProgress?: Callback<number>): Promise<ParseResult> | 加载PDF文档。 |
saveDocument(path: string, onProgress?: Callback<number>): Promise<number> | 保存PDF文档,使用Promise异步回调。 |
3.2.3 示例代码
- 在aboutToAppear函数里面加载PDF文档。
- 调用PdfView预览组件,渲染显示。
- 在【savePdfDocument】按钮中调用saveDocument方法另存PDF文档。
import { pdfService, PdfView, pdfViewManager } from '@kit.PDFKit';
import { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
@Entry
@Component
struct PdfPage {
private controller: pdfViewManager.PdfController = new pdfViewManager.PdfController();
private context = getContext() as common.UIAbilityContext;
private loadResult: pdfService.ParseResult = pdfService.ParseResult.PARSE_ERROR_FORMAT;
aboutToAppear(): void {
// 确保沙箱目录有input.pdf文档
let filePath = this.context.filesDir + '/input.pdf';
(async () => {
this.loadResult = await this.controller.loadDocument(filePath);
})()
}
build() {
Column() {
// 保存Pdf文档
Button('savePdfDocument').onClick(async () => {
if (this.loadResult === pdfService.ParseResult.PARSE_SUCCESS) {
let savePath = this.context.filesDir + '/savePdfDocument.pdf';
let result = await this.controller.saveDocument(savePath);
hilog.info(0x0000, 'PdfPage', 'savePdfDocument %{public}s!', result ? 'success' : 'fail');
}
})
PdfView({
controller: this.controller,
pageFit: pdfService.PageFit.FIT_WIDTH,
showScroll: true
})
.id('pdfview_app_view')
.layoutWeight(1);
}
.width('100%')
.height('100%')
}
}
3.3 设置PDF文档预览效果
pdfViewManager为PDF文档提供了丰富的预览特定特性。
- 单双页布局,是否连续滚动和页面适配方式。
- 页面跳转,如上一页,下一页,跳转到指定页。
- 页面放大、缩小。
图1:提供了双页预览布局,页面宽度适配和连续滚动的预览方式
3.3.1 接口说明
接口名 | 描述 |
---|---|
setPageLayout(columnCount: PageLayout): void | 设置页面布局模式。其中“columnCount”取值如下:
|
setPageContinuous(isContinuous: boolean): void | 设置页面滚动是否连续排列。 |
setPageFit(pageFit: PageFit): void | 设置页面的适配模式。 |
goToPage(pageIndex: number): void | 跳转到指定页。 |
setPageZoom(zoom: number): void | 设置视图的缩放比例。 |
3.3.2 示例代码
- 先加载PDF文档。
- 调用PdfView预览组件,渲染显示。
- 在按钮【setPreviewMode】里,调用setPageLayout、setPageContinuous等方法,设置文档预览效果。
- 在按钮【goTopage】里,调用goToPage方法,设置页面跳转。
- 在按钮【zoomPage2】里,调用setPageZoom方法,将页面放大2倍。
import { pdfService, PdfView, pdfViewManager } from '@kit.PDFKit';
import { common } from '@kit.AbilityKit';
@Entry
@Component
struct PdfPage {
private controller: pdfViewManager.PdfController = new pdfViewManager.PdfController();
private context = getContext() as common.UIAbilityContext;
private loadResult: pdfService.ParseResult = pdfService.ParseResult.PARSE_ERROR_FORMAT;
aboutToAppear(): void {
// 确保沙箱目录有input.pdf文档
let filePath = this.context.filesDir + '/input.pdf';
(async () => {
this.loadResult = await this.controller.loadDocument(filePath);
// 注意:这里刚加载文档,请不要在这里立即设置PDF文档的预览方法。
})()
}
build() {
Column() {
Row() {
// 设置预览方式
Button('setPreviewMode').onClick(() => {
if (this.loadResult === pdfService.ParseResult.PARSE_SUCCESS) {
// 单页布局
this.controller.setPageLayout(pdfService.PageLayout.LAYOUT_SINGLE);
// 是否连续滚动预览
this.controller.setPageContinuous(true);
// 适配页的预览方式
this.controller.setPageFit(pdfService.PageFit.FIT_PAGE);
}
})
// 跳转到第11页
Button('goTopage').onClick(() => {
if (this.loadResult === pdfService.ParseResult.PARSE_SUCCESS) {
this.controller.goToPage(10);
}
})
// 页面放大2倍
Button('zoomPage2').onClick(() => {
if (this.loadResult === pdfService.ParseResult.PARSE_SUCCESS) {
this.controller.setPageZoom(2);
}
})
}
PdfView({
controller: this.controller,
pageFit: pdfService.PageFit.FIT_WIDTH,
showScroll: true
})
.id('pdfview_app_view')
.layoutWeight(1);
}
}
}
3.4 搜索关键字
预览PDF文档时,可以对页面的关键词(英文字符不区分大小写)进行搜索并高亮显示,同时使用setSearchIndex方法高亮显示指定的搜索结果。
使用getSearchIndex方法获取当前高亮的索引,可以使用clearSearch方法清除所有搜索结果。
3.4.1 接口说明
接口名 | 描述 |
---|---|
searchKey(text: string, listener: Callback<number>): void | 搜索文本并返回匹配的总数。 |
3.4.2 示例代码
- 先加载PDF文档。
- 调用PdfView预览组件,渲染显示。
- 在按钮【searchKey】里,调用searchKey方法,搜索指定关键字。
- 上一个、下一个搜索按钮跳转到对应的结果。
- 在按钮【getSearchIndex】里,调用getSearchIndex方法,获取当前的搜索结果索引。
- 在按钮【clearSearch】里,调用clearSearch方法,清除搜索结果。
import { pdfService, PdfView, pdfViewManager } from '@kit.PDFKit';
import { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
@Entry
@Component
struct PdfPage {
private controller: pdfViewManager.PdfController = new pdfViewManager.PdfController();
private context = getContext() as common.UIAbilityContext;
private loadResult: pdfService.ParseResult = pdfService.ParseResult.PARSE_ERROR_FORMAT;
private searchIndex = 0;
private charCount = 0;
aboutToAppear(): void {
// 确保沙箱目录有input.pdf文档
let filePath = this.context.filesDir + '/input.pdf';
(async () => {
this.loadResult = await this.controller.loadDocument(filePath);
})()
}
build() {
Column() {
Row() {
// 搜索关键字
Button('searchKey').onClick(async () => {
if (this.loadResult === pdfService.ParseResult.PARSE_SUCCESS) {
this.controller.searchKey('C++', (index: number) => {
this.charCount = index;
hilog.info(0x0000, 'PdfPage', 'searchKey %{public}s!', index + '');
})
}
})
// 上一个
Button('setSearchPrevIndex').onClick(async () => {
if (this.loadResult === pdfService.ParseResult.PARSE_SUCCESS) {
if(this.searchIndex > 0) {
this.controller.setSearchIndex(--this.searchIndex);
}
}
})
// 下一个
Button('setSearchNextIndex').onClick(async () => {
if (this.loadResult === pdfService.ParseResult.PARSE_SUCCESS) {
if(this.searchIndex < this.charCount) {
this.controller.setSearchIndex(++this.searchIndex);
}
}
})
// 获取当前页索引
Button('getSearchIndex').onClick(async () => {
if (this.loadResult === pdfService.ParseResult.PARSE_SUCCESS) {
let curSearchIndex = this.controller.getSearchIndex();
hilog.info(0x0000, 'PdfPage', 'curSearchIndex %{public}s!', curSearchIndex + '');
}
})
// 清除搜索文本的高亮
Button('clearSearch').onClick(async () => {
if (this.loadResult === pdfService.ParseResult.PARSE_SUCCESS) {
this.controller.clearSearch();
}
})
}
PdfView({
controller: this.controller,
pageFit: pdfService.PageFit.FIT_WIDTH,
showScroll: true
})
.id('pdfview_app_view')
.layoutWeight(1);
}
}
}
3.5 高亮显示PDF文档
PDF文档在预览时,可以对页面的矩形区域或文本设置高亮显示,高亮颜色可以自定义。
setHighlightText可以同时高亮多个不同的文本。
3.5.1 接口说明
接口名 | 描述 |
---|---|
setHighlightText(pageIndex: number, textArray: string[], color: number): void | 高亮指定文本。 |
注意
setHighlightText和searchKey功能互斥。
3.5.2 示例代码
- 加载PDF文档。
- 调用PdfView预览组件,渲染显示。
- 在按钮【setHighlightText】里,调用setHighlightText方法,设置单个或多个要高亮的文本。
import { pdfService, PdfView, pdfViewManager } from '@kit.PDFKit';
import { common } from '@kit.AbilityKit';
@Entry
@Component
struct PdfPage {
private controller: pdfViewManager.PdfController = new pdfViewManager.PdfController();
private context = getContext() as common.UIAbilityContext;
private loadResult: pdfService.ParseResult = pdfService.ParseResult.PARSE_ERROR_FORMAT;
aboutToAppear(): void {
// 确保沙箱目录有input.pdf文档
let filePath = this.context.filesDir + '/input.pdf';
(async () => {
this.loadResult = await this.controller.loadDocument(filePath);
})()
}
build() {
Column() {
Row() {
// 设置文本的高亮显示风格
Button('setHighlightText').onClick(async () => {
if (this.loadResult === pdfService.ParseResult.PARSE_SUCCESS) {
this.controller.setHighlightText(0, ['白皮书'], 0xAAF9CC00);
}
})
}
// 加载PdfView组件进行预览
PdfView({
controller: this.controller,
pageFit: pdfService.PageFit.FIT_WIDTH,
showScroll: true
})
.id('pdfview_app_view')
.layoutWeight(1);
}
.width('100%').height('100%')
}
}
3.6 批注
进入批注模式,目前支持高亮、下划线和删除线类型批注。
3.6.1 接口说明
接口名 | 描述 |
---|---|
enableAnnotation(annotationType: SupportedAnnotationType, color?: number): void | 在常用操作之间切换并添加批注。 |
3.6.2 示例代码
- 先加载PDF文档。
- 调用PdfView预览组件,渲染显示。
- 调用enableAnnotation方法,进入批注模式。
import { pdfService, pdfViewManager, PdfView } from '@kit.PDFKit';
import { common } from '@kit.AbilityKit';
@Entry
@Component
struct PdfPage {
private pdfController = new pdfViewManager.PdfController();
private context = getContext() as common.UIAbilityContext;
aboutToAppear(): void {
// 确保沙箱目录有input.pdf文档
let filePath = this.context.filesDir + '/input.pdf';
(async () => {
let loadResult: pdfService.ParseResult = await this.pdfController.loadDocument(filePath);
if (pdfService.ParseResult.PARSE_SUCCESS === loadResult) {
// 添加删除线批注
this.pdfController.enableAnnotation(pdfViewManager.SupportedAnnotationType.STRIKETHROUGH, 0xAAEEEEEE);
}
})()
}
build() {
Column() {
// 加载PdfView组件进行预览
PdfView({
controller: this.pdfController,
pageFit: pdfService.PageFit.FIT_WIDTH,
showScroll: true
})
.id('pdfview_app_view')
.layoutWeight(1);
}
}
}
3.7 PDF页面转换为图片
3.7.1 场景介绍
调用getPagePixelMap方法,将指定PDF页面转化为图片。
3.7.2 接口说明
接口名 | 描述 |
---|---|
getPagePixelMap(pageIndex: number, isSync?: boolean): Promise<image.PixelMap> | 获取对应PDF页面的缩略图,使用Promise异步回调。 |
3.7.3 示例代码
- 调用loadDocument方法,加载PDF文档。
- 调用getPagePixelMap方法,获取image.PixelMap对象。
- 将image.PixelMap转化为二进制图片文件并保存。
import { pdfService, pdfViewManager } from '@kit.PDFKit';
import { image } from '@kit.ImageKit';
import { fileIo as fs } from '@kit.CoreFileKit';
import { common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
struct PdfPage {
private controller: pdfViewManager.PdfController = new pdfViewManager.PdfController();
private context = getContext() as common.UIAbilityContext;
private loadResult: pdfService.ParseResult = pdfService.ParseResult.PARSE_ERROR_FORMAT;
aboutToAppear(): void {
// 确保沙箱目录有input.pdf文档
let filePath = this.context.filesDir + '/input.pdf';
(async () => {
this.loadResult = await this.controller.loadDocument(filePath);
})()
}
// 将 pixelMap 转成图片格式
pixelMap2Buffer(pixelMap: image.PixelMap): Promise<ArrayBuffer> {
return new Promise((resolve, reject) => {
/**
设置打包参数
format:图片打包格式,只支持 jpg 和 webp
quality:JPEG 编码输出图片质量
bufferSize:图片大小,默认 10M
*/
let packOpts: image.PackingOption = { format: 'image/jpeg', quality: 98 }
// 创建ImagePacker实例
const imagePackerApi = image.createImagePacker()
imagePackerApi.packToData(pixelMap, packOpts).then((buffer: ArrayBuffer) => {
resolve(buffer)
}).catch((err: BusinessError) => {
reject()
})
})
}
build() {
Column() {
// 转换为图片并保存到应用沙箱
Button('getPagePixelMap').onClick(async () => {
if (this.loadResult === pdfService.ParseResult.PARSE_SUCCESS) {
let pixmap: image.PixelMap = await this.controller.getPagePixelMap(0, true);
if (!pixmap) {
return
}
const imgBuffer = await this.pixelMap2Buffer(pixmap)
const file =
fs.openSync(this.context.filesDir + `/${Date.now()}.png`, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
await fs.write(file.fd, imgBuffer);
// 关闭文件
await fs.close(file.fd)
}
})
}
}
}