You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PDFium库合并PDF文件失败求助:合并后内容为空

问题分析与解决建议

你的合并后PDF为空,核心是代码存在几处逻辑错误,以下是具体问题和修复方案:

1. 页面对象插入条件完全写反

代码中遍历页面对象时,判断条件是if (!object)才执行插入——这意味着仅当对象为空时才尝试插入,完全不符合逻辑。正确逻辑是仅当对象有效时才插入:

int count = FPDFPage_CountObjects(page);
for (int j = 0; j < count; j++)
{
  FPDF_PAGEOBJECT object = FPDFPage_GetObject(page, j);
  if (object)  // 修正条件:仅对象有效时执行插入
  {
    FPDFPage_InsertObject(newPage, object);
  }
}
// 所有对象插入完成后,再调用一次生成页面内容
FPDFPage_GenerateContent(newPage);

2. FPDFPage_GenerateContent调用时机错误

原代码在每次插入对象后都调用该函数,会导致页面内容重复生成且不完整。正确做法是所有页面对象插入完毕后,仅调用一次,让PDFium生成完整的页面内容流。

3. 页面资源未同步复制

仅复制页面对象不足以保留内容,PDF页面依赖的字体、图片等资源未同步到目标文档,会导致内容丢失。更可靠的方式是使用PDFium官方提供的FPDF_ImportPage接口直接导入整个页面,该接口会自动处理资源关联:

// 替换原有的页面复制逻辑
FPDF_PAGE importedPage = FPDF_ImportPage(output, pdf, i, FPDF_IMPORT_ALL);
if (!importedPage) {
  ELOG("import page %d from %s failed", i, item.c_str());
  continue;
}
// 将导入的页面插入到目标文档指定位置
if (!FPDFPage_Insert(output, importedPage, index)) {
  ELOG("insert page %d failed", index);
  FPDF_ClosePage(importedPage);
  continue;
}
FPDF_ClosePage(importedPage);
index++;

4. blockWriter回调未关联实际文件

原代码中blockWriter没有绑定输出文件,导致保存时没有实际写入数据。需要自定义写入器结构体关联文件指针,示例实现如下:

// 自定义写入器结构体,关联文件指针
struct CustomWriter {
  FPDF_FILEWRITE base;
  FILE* fp;
};

// 在保存文档前打开输出文件
FILE* outFile = fopen(mergePath.c_str(), "wb");
if (!outFile) {
  ELOG("open output file %s failed", mergePath.c_str());
  FPDF_CloseDocument(output);
  FPDF_DestroyLibrary();
  return;
}

// 初始化写入器
CustomWriter writer;
writer.base.version = 1;
writer.base.WriteBlock = [](FPDF_FILEWRITE* this_ptr, const void* data, unsigned long size) -> int {
  CustomWriter* customWriter = reinterpret_cast<CustomWriter*>(this_ptr);
  return static_cast<int>(fwrite(data, 1, size, customWriter->fp) == size);
};
writer.fp = outFile;

// 保存文档
FPDF_SaveAsCopy(output, &writer.base, FPDF_NO_INCREMENTAL);
fclose(outFile);

完整修正后的核心逻辑示例

void gcutMergePDF(const OdUtf8String &mergePath, const OdUtf8StringArray &array)
{
  FPDF_InitLibrary();

  FPDF_DOCUMENT output = FPDF_CreateNewDocument();
  if (!output)
  {
    ELOG("create merge file %s failed", mergePath.c_str());
    FPDF_DestroyLibrary();
    return;
  }

  int index = 0;

  for (const auto &item : array)
  {
    ELOG("add file %s to merge", item.c_str());  // 修正日志笔误:将"zip"改为"merge"

    FPDF_DOCUMENT pdf = FPDF_LoadDocument(item.c_str(), NULL);
    if (!pdf)
    {
      ELOG("load file %s failed", item.c_str());
      continue;
    }

    int pageCount = FPDF_GetPageCount(pdf);
    for (int i = 0; i < pageCount; ++i)
    {
      // 导入整个页面,自动处理资源
      FPDF_PAGE importedPage = FPDF_ImportPage(output, pdf, i, FPDF_IMPORT_ALL);
      if (!importedPage)
      {
        ELOG("import file %s page %d failed", item.c_str(), i);
        continue;
      }

      // 插入页面到目标文档
      if (!FPDFPage_Insert(output, importedPage, index))
      {
        ELOG("insert page %d failed", index);
        FPDF_ClosePage(importedPage);
        continue;
      }

      FPDF_ClosePage(importedPage);
      index++;
    }

    FPDF_CloseDocument(pdf);
  }

  // 打开输出文件
  FILE* outFile = fopen(mergePath.c_str(), "wb");
  if (!outFile)
  {
    ELOG("open output file %s failed", mergePath.c_str());
    FPDF_CloseDocument(output);
    FPDF_DestroyLibrary();
    return;
  }

  // 初始化自定义写入器
  struct CustomWriter {
    FPDF_FILEWRITE base;
    FILE* fp;
  };
  CustomWriter writer;
  writer.base.version = 1;
  writer.base.WriteBlock = [](FPDF_FILEWRITE* this_ptr, const void* data, unsigned long size) -> int {
    CustomWriter* customWriter = reinterpret_cast<CustomWriter*>(this_ptr);
    return static_cast<int>(fwrite(data, 1, size, customWriter->fp) == size);
  };
  writer.fp = outFile;

  // 保存合并后的文档
  if (!FPDF_SaveAsCopy(output, &writer.base, FPDF_NO_INCREMENTAL))
  {
    ELOG("save merge file %s failed", mergePath.c_str());
  }

  fclose(outFile);
  FPDF_CloseDocument(output);
  FPDF_DestroyLibrary();
}

额外注意事项

  • 确保使用最新版本的PDFium库,旧版本可能存在API兼容问题;
  • 确认输出文件路径正确且拥有读写权限;
  • 所有PDFium资源(文档、页面)都要正确关闭,避免内存泄漏。

内容的提问来源于stack exchange,提问作者jiaming wei

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 20:23:18