HarmonyOS鸿蒙Next中PDF合并有解决方法吗?
HarmonyOS鸿蒙Next中PDF合并有解决方法吗? 这边产品需要一个功能导入多分pdf能合并成一个,鸿蒙暂时有办法吗
【背景知识】
insertPageFromDocument接口提供能力,将其他Document的Page添加到当前Document,Page中的批注不支持插入到当前Document。
addHeaderFooter接口提供能力,插入PDF文档页眉页脚。该方法属于耗时业务,需要遍历每一页去添加页眉页脚,添加页面较多时建议放到线程里去处理。
【解决方案】
- aboutToAppear回调中,确保rawfile目录下有pdf文件,拷贝到沙箱内。
- 使用insertPageFromDocument接口将input_add.pdf文档页插入到input_src.pdf末尾的位置,并另存文档。
- 给生成的testInsertPageFromDocument.pdf文档添加页码。
完整示例代码如下:
import { pdfService } from '@kit.PDFKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { Font } from '@kit.ArkUI';
import { common } from '@kit.AbilityKit';
import { fileIo as fs } from '@kit.CoreFileKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { promptAction } from '@kit.ArkUI';
@Entry
@Component
struct PdfPage {
@State lastPage: number = 0;
private pdfDocument: pdfService.PdfDocument = new pdfService.PdfDocument();
private context = this.getUIContext().getHostContext() as Context;
async aboutToAppear(): Promise<void> {
try {
//确保rawfile目录下有pdf文件
await this.copyRawFileToSdcard(this.context, 'input_src.pdf');
await this.copyRawFileToSdcard(this.context, 'input_add.pdf');
promptAction.openToast({ message: '全部拷贝完成' });
} catch (error) {
promptAction.openToast({ message: '文件拷贝失败' });
}
}
build() {
Column() {
// 将input_add.pdf文档页插入到input_src.pdf末尾的位置,并另存文档
Button('insertPageFromDocument').onClick(async () => {
let filePath = this.context.filesDir + '/input_src.pdf';
let loadResult: pdfService.ParseResult = this.pdfDocument.loadDocument(filePath);
if (pdfService.ParseResult.PARSE_SUCCESS === loadResult) {
this.lastPage = this.pdfDocument.getPageCount();
} else {
promptAction.openToast({ message: '加载失败' });
}
let pdfDoc: pdfService.PdfDocument = new pdfService.PdfDocument();
// 确保该沙箱目录下有input_add.pdf文档
let res = pdfDoc.loadDocument(this.context.filesDir + '/input_add.pdf');
if (res === pdfService.ParseResult.PARSE_SUCCESS) {
this.pdfDocument.insertPageFromDocument(pdfDoc, 0, pdfDoc.getPageCount(), this.lastPage);
let outPdfPath = this.context.filesDir + '/testInsertPageFromDocument.pdf';
let result = this.pdfDocument.saveDocument(outPdfPath);
this.lastPage = this.pdfDocument.getPageCount();
hilog.info(0x0000, 'PdfPage', 'insertPageFromDocument %{public}s!', result ? 'success' : 'fail');
} else {
promptAction.openToast({ message: '加载失败' });
}
pdfDoc.releaseDocument();
})
Button('addHeaderFooter').onClick(async () => {
// 确保沙箱目录有testInsertPageFromDocument.pdf文档
let filePath = this.context.filesDir + '/testInsertPageFromDocument.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();
// 确保字体路径存在
let font: Font = new Font();
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;
let pdfPageCount = this.pdfDocument.getPageCount();
for (let index = 0; index < pdfPageCount; index++) {
hfInfo.footerCenterText = `${index + 1}`;
this.pdfDocument.addHeaderFooter(hfInfo, index, index, 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');
} else {
promptAction.openToast({ message: '加载失败' });
}
this.pdfDocument.releaseDocument();
})
}
}
// 拷贝pdf文件到应用沙箱目录
private copyRawFileToSdcard(context: common.Context, pdfName: string): Promise<void> {
return new Promise((resolve, reject) => {
let destRoot = context.filesDir;
// rawfile下的文件名
let srcFileName = pdfName;
let destFilePath = `${destRoot}/${srcFileName}`;
context.resourceManager.getRawFileContent(srcFileName, (error: BusinessError, data: Uint8Array) => {
if (error) {
promptAction.openToast({ message: '拷贝失败' });
hilog.error(0x0000, 'PdfCopy', `Copy failed: ${error.code}`);
return;
}
const fileStream = fs.createStreamSync(destFilePath, 'w+');
fileStream.writeSync(data.buffer);
fileStream.close();
promptAction.openToast({ message: '拷贝成功' });
resolve();
});
})
}
}
- 示例代码中input_src、input_add文件需要提前放在项目rawfile目录下,路径:项目-entry-src-main-resources-rawfile。
- 先点击insertPageFromDocument按钮将pdf文件合并。
- 再点击addHeaderFooter按钮给合并后的pdf文件添加页脚页码。
更多关于HarmonyOS鸿蒙Next中PDF合并有解决方法吗?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
我试了一下报错,好像虚拟器运行不了得要真机。,
开发者您好,x86版本模拟器不支持PDF Kit,建议使用真机或者云调试测试https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ide-emulator-specification#section38231424133213。
一、当前能力现状
- 原生接口限制
鸿蒙PDF Kit(版本5.0.0及以上)目前未直接提供PDF文件合并的API,但支持PDF文档的加载、编辑及保存操作。
二、替代实现方案
// 示例:基于现有能力的合并思路(需自行实现核心逻辑)
import { pdfService, pdfViewManager, PdfView } from '@kit.PDFKit';
import { fileIo } from '@kit.CoreFileKit';
// 步骤1:加载多个PDF文件
async function mergePDFs(filePaths: string[], outputPath: string) {
const pdfDoc = pdfService.createDocument();
// 遍历所有文件
for (const path of filePaths) {
try {
const controller = new pdfViewManager.PdfController();
await controller.loadDocument(path);
const pageCount = controller.getPageCount();
// 逐页提取内容(需自定义页面处理逻辑)
for (let i = 0; i < pageCount; i++) {
const page = controller.getPage(i);
pdfDoc.addPage(page); // 伪代码,实际需转存页面内容
}
} catch (error) {
console.error(`加载文件失败:${path}`, error);
}
}
// 步骤2:保存合并后文件
const content = pdfDoc.save();
const fd = fileIo.openSync(outputPath, fileIo.OpenMode.WRITE_ONLY | fileIo.OpenMode.CREATE);
fileIo.writeSync(fd, content);
fileIo.closeSync(fd);
}
三、关键注意事项
- 版本兼容性
需确认SDK版本不低于HarmonyOS 6.0.0 Release,且DevEco Studio版本为6.0.0及以上
- 文件权限管理
合并操作需申请文件访问权限:
"requestPermissions": [
"ohos.permission.READ_MEDIA",
"ohos.permission.WRITE_MEDIA"
]
- 替代方案建议
- 若需快速实现,可考虑:
- 将多份PDF转为图片格式,通过image组件合并后生成新PDF
- 调用服务端接口处理合并逻辑
- 参考文档扫描组件(DocumentScanner)的批量处理机制,如结果1中提到的多页扫描生成单个PDF功能
- 若需快速实现,可考虑:
HarmonyOS Next中PDF合并可通过ArkUI组件和系统文件管理API实现。开发者需使用@ohos.file.fs和@ohos.file.picker模块访问文件,通过PDF解析库(如第三方适配库)提取内容后,使用Canvas或PDF生成工具重新绘制合并。注意需申请ohos.permission.READ_MEDIA和ohos.permission.WRITE_MEDIA权限。目前官方未提供直接合并的API,需自行实现解析与合成逻辑。
目前HarmonyOS Next的ArkUI框架及API暂未提供原生的PDF文档合并功能。若需实现此功能,可以考虑以下技术路径:
-
集成第三方C/C++库:寻找支持PDF处理的成熟开源库(如PDFium、PoDoFo等),通过HarmonyOS的Native API(NDK)进行封装,以动态链接库形式调用核心合并功能。
-
使用纯JavaScript/TypeScript方案:评估是否可采用Web组件承载PDF.js等前端库,在渲染层实现客户端合并逻辑。需注意性能与大文件兼容性。
-
服务端处理:将PDF文件上传至后端服务进行合并,客户端通过网络接口获取结果。此方案可规避客户端性能限制,但依赖网络环境。
建议优先评估业务场景对离线处理、性能及文件大小的要求,再选择对应方案。若采用本地库集成,需重点关注Native内存管理及ArkTS/CPP数据交互的稳定性。

