鸿蒙学习实战之路-PDF页面添加与删除最佳实践

最近好多朋友问我:“西兰花啊,我用PDF Kit搞文档编辑,咋添加个新页面就报错?删除页面也没反应?这可咋整?” 害,这问题我太熟了!今天我就手把手带你搞定PDF页面的添加和删除,这可是PDF编辑的基础操作,学会了这个,你就能随便调整文档结构啦~

一、页面操作,核心接口有哪些?

PDF页面的添加删除,其实就四个核心接口:

接口名 功能描述
insertBlankPage 在指定位置插入空白PDF页
insertPageFromDocument 将其他文档的页添加到当前文档
getPage 获取指定页的对象
deletePage 删除指定的PDF页

这四个接口就是咱们今天要摆弄的"锅碗瓢盆",用好了,PDF页面任你调~

二、插入空白页,so easy!

1. 准备工作

import { pdfService } from '@kit.PDFKit';
import { hilog } from '@kit.PerformanceAnalysisKit';

@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 width = page.getWidth();
    let height = page.getHeight();
    
    // 在索引2的位置插入空白页(页码从0开始)
    this.pdfDocument.insertBlankPage(2, width, height);
    
    // 保存文档
    let outPdfPath = this.context.filesDir + '/testInsertBlankPage.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 width = page.getWidth();
    let height = page.getHeight();
    
    // 连续插入3个空白页
    for (let i = 0; i < 3; i++) {
      // 每次都在索引2的位置插入,这样新页会依次往后排
      this.pdfDocument.insertBlankPage(2, width, height);
    }
    
    // 保存文档
    let outPdfPath = this.context.filesDir + '/testInsertSomeBlankPage.pdf';
    let result = this.pdfDocument.saveDocument(outPdfPath);
    hilog.info(0x0000, 'PdfPage', '插入多个空白页 %{public}s!', result ? '成功' : '失败');
  })

三、合并文档,把其他PDF的页加进来

1. 合并文档页面

Button('合并其他PDF文档')
  .onClick(async () => {
    // 打开要合并的源文档
    let pdfDoc: pdfService.PdfDocument = new pdfService.PdfDocument();
    let sourceFilePath = this.context.filesDir + '/input2.pdf';
    pdfDoc.loadDocument(sourceFilePath);
    
    // 将input2.pdf的索引1、2、3页(共3页)插入到当前文档的索引0位置
    // 参数:源文档, 源文档起始页索引, 要插入的页数, 目标文档插入位置
    this.pdfDocument.insertPageFromDocument(pdfDoc, 1, 3, 0);
    
    // 保存文档
    let outPdfPath = this.context.filesDir + '/testInsertPageFromDocument.pdf';
    let result = this.pdfDocument.saveDocument(outPdfPath);
    hilog.info(0x0000, 'PdfPage', '合并文档 %{public}s!', result ? '成功' : '失败');
    
    // 别忘了关闭源文档,释放资源
    pdfDoc.close();
  })

四、删除页面,轻松搞定

1. 删除单个或多个页面

Button('删除页面')
  .onClick(async () => {
    // 删除从索引2开始的2个页面(即第3页和第4页,索引从0开始)
    this.pdfDocument.deletePage(2, 2);
    
    // 保存文档
    let outPdfPath = this.context.filesDir + '/testDeletePage.pdf';
    let result = this.pdfDocument.saveDocument(outPdfPath);
    hilog.info(0x0000, 'PdfPage', '删除页面 %{public}s!', result ? '成功' : '失败');
  })

🥦 西兰花警告

  • 索引从0开始:PDF页面的索引是从0开始的!别犯低级错误,想删第1页就写0,写1删的是第2页!
  • 页面尺寸一致:插入空白页时,最好和原文档页面尺寸一致,不然文档会很丑
  • 资源释放:合并文档时,源文档用完一定要close(),不然内存泄漏!
  • 异常处理:所有操作都要包在try-catch里,避免文件不存在、格式错误等情况导致崩溃!
  • 页面数量检查:删除页面时,先检查页面总数,别删不存在的页面!

🥦 西兰花小贴士

  • 批量操作:插入多个页面时,可以用循环,但要注意索引的变化
  • 文档备份:操作前最好先备份原文档,避免操作失误导致文件损坏
  • 页面顺序:insertBlankPage每次插入到指定位置,新页会往后排
  • 性能优化:处理大量页面时,尽量减少saveDocument的调用次数

五、常见问题与解决方案

1. 插入空白页时提示"索引越界"

问题:想在最后插入一页,结果报错"Index out of range"

解决方案:插入位置不能超过当前页数,想在最后插入,索引直接写当前页数:

// 正确写法
let pageCount = this.pdfDocument.getPageCount();
this.pdfDocument.insertBlankPage(pageCount, width, height);

2. 合并文档时提示"文件不存在"

问题:源文档路径写的是"/sdcard/input2.pdf",结果报错

解决方案:鸿蒙应用有沙箱限制,改用应用沙箱路径:

// 正确写法
let sourceFilePath = this.context.filesDir + '/input2.pdf';

3. 删除页面后,其他页面内容乱了

问题:删除页面后,文档内容顺序不对,或者内容丢失

解决方案:删除页面时,PDF的内部链接、书签等可能会失效,需要重新生成这些内容

六、完整代码示例

import { pdfService } from '@kit.PDFKit';
import { hilog } from '@kit.PerformanceAnalysisKit';

@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 width = page.getWidth();
            let height = page.getHeight();
            
            this.pdfDocument.insertBlankPage(2, width, height);
            
            let outPdfPath = this.context.filesDir + '/testInsertBlankPage.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 width = page.getWidth();
            let height = page.getHeight();
            
            for (let i = 0; i < 3; i++) {
              this.pdfDocument.insertBlankPage(2, width, height);
            }
            
            let outPdfPath = this.context.filesDir + '/testInsertSomeBlankPage.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));
          }
        })

      // 合并其他PDF文档
      Button('合并其他PDF文档')
        .margin(10)
        .onClick(async () => {
          try {
            let pdfDoc: pdfService.PdfDocument = new pdfService.PdfDocument();
            let sourceFilePath = this.context.filesDir + '/input2.pdf';
            pdfDoc.loadDocument(sourceFilePath);
            
            this.pdfDocument.insertPageFromDocument(pdfDoc, 1, 3, 0);
            
            let outPdfPath = this.context.filesDir + '/testInsertPageFromDocument.pdf';
            let result = this.pdfDocument.saveDocument(outPdfPath);
            hilog.info(0x0000, 'PdfPage', '合并文档 %{public}s!', result ? '成功' : '失败');
            
            pdfDoc.close();
          } catch (e) {
            hilog.error(0x0000, 'PdfPage', '合并文档失败: %{public}s', JSON.stringify(e));
          }
        })

      // 删除页面
      Button('删除页面')
        .margin(10)
        .onClick(async () => {
          try {
            this.pdfDocument.deletePage(2, 2);
            
            let outPdfPath = this.context.filesDir + '/testDeletePage.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));
          }
        })
    }
    .padding(20)
  }
}

七、实用资源推荐

📚 推荐资料


我是盐焗西兰花,
不教理论,只给你能跑的代码和避坑指南。
下期见!🥦

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐