使用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
相关产品推荐
相关产品推荐

