使用MuPDF(C语言)解析PDF Pages数组Kids条目时,解析后的对象显示为unknown的问题
我来帮你排查这个问题哈,结合你提供的代码和现象,咱们从几个常见的方向入手分析:
一、先检查pdf_print_obj的参数和输出对象是否正确
你当前调用pdf_print_obj时用的是自己传入的out对象,如果这个输出对象没有正确初始化(比如没有关联到标准输出),或者参数设置不对,都可能导致打印异常。
你可以先把输出对象替换为MuPDF提供的标准输出fz_stdout(ctx),同时调整print_raw参数(最后一个参数)试试:
// 替换原打印代码为: pdf_print_obj(ctx, fz_stdout(ctx), direct_obj, 0, 0);
fz_stdout(ctx)是MuPDF封装的标准输出流,能保证输出正常;- 最后一个参数设为
0时,会以格式化的方式打印对象,而不是原始字节,避免加密或特殊格式的对象被识别为unknown。
二、解析后的对象可能是PDF页/页节点字典,pdf_print_obj对这类特殊对象有处理逻辑
PDF的Kids数组里的条目本质是页节点(Pages)或页对象(Page),它们都是PDF字典类型。但pdf_print_obj默认可能不会直接打印这类特殊字典的完整内容,而是需要我们手动遍历字典的键值对来查看:
你可以在拿到direct_obj后,先判断它是不是字典,然后手动遍历打印:
if (pdf_is_dict(ctx, direct_obj)) { printf(" 这是一个PDF字典对象(页/页节点):\n"); int dict_len = pdf_dict_len(ctx, direct_obj); for (int j=0; j<dict_len; j++) { pdf_obj *key = pdf_dict_get_key(ctx, direct_obj, j); pdf_obj *val = pdf_dict_get_val(ctx, direct_obj, j); printf(" "); pdf_print_obj(ctx, fz_stdout(ctx), key, 0, 1); printf(": "); pdf_print_obj(ctx, fz_stdout(ctx), val, 0, 1); printf("\n"); } }
这样就能绕过pdf_print_obj的特殊处理,直接看到字典里的实际内容。
三、尝试用pdf_load_obj替代pdf_resolve_indirect加载间接对象
你当前用的pdf_resolve_indirect只是返回间接对象的引用,而pdf_load_obj会真正加载对象的完整内容,对于某些特殊的PDF结构,这个方法的解析更可靠:
// 替换原解析代码: pdf_obj *direct_obj = pdf_load_obj(ctx, cur_item_obj);
注意这个返回的对象同样需要用pdf_drop_obj释放,和你之前的逻辑一致。
四、关于你提到的kind=221的问题
这个数值明显超出了MuPDF公开的pdf_obj类型枚举范围(标准类型一般在0~20之间),这是因为你直接访问了pdf_obj结构体的内部私有成员——MuPDF的内部结构体字段是不对外公开的,这些数值可能是结构体的其他字段干扰值,或者是版本私有扩展,完全不能用来判断对象类型。你应该始终用MuPDF提供的公开API(比如pdf_is_dict、pdf_is_array等)来判断对象类型。
最后给你一个修改后的代码示例,整合了上面的优化点:
void print_pages_array_recurs(fz_output* out, fz_context* ctx, pdf_obj* array_obj, int level) { bool is_array = pdf_is_array(ctx, array_obj); if (!is_array) { printf("---------not array !!!!!!!!!!!!!\n"); return; } int n = pdf_array_len(ctx, array_obj); printf("===Array total elements: %d \n", n); // 使用MuPDF标准输出流,避免自定义out的问题 fz_output *std_out = fz_stdout(ctx); for (int i = 0; i < n; i++) { pdf_obj* cur_item_obj = pdf_array_get(ctx, array_obj, i); // 打印原始间接引用 printf(" %d.[%d]: ", level, i); pdf_print_obj(ctx, std_out, cur_item_obj, 0, 1); printf("\n"); bool cur_indirect = pdf_is_indirect(ctx, cur_item_obj); if (cur_indirect) { // 用pdf_load_obj加载完整对象 pdf_obj* direct_obj = pdf_load_obj(ctx, cur_item_obj); if (!direct_obj) { printf(" 加载间接对象失败!\n"); continue; } printf("__解析后的直接对象:\n"); // 按对象类型分别处理 if (pdf_is_dict(ctx, direct_obj)) { printf(" 类型:PDF字典(页/页节点)\n"); int dict_len = pdf_dict_len(ctx, direct_obj); for (int j=0; j<dict_len; j++) { pdf_obj *key = pdf_dict_get_key(ctx, direct_obj, j); pdf_obj *val = pdf_dict_get_val(ctx, direct_obj, j); printf(" "); pdf_print_obj(ctx, std_out, key, 0, 1); printf(": "); pdf_print_obj(ctx, std_out, val, 0, 1); printf("\n"); } } else if (pdf_is_array(ctx, direct_obj)) { printf(" 类型:PDF数组\n"); pdf_print_obj(ctx, std_out, direct_obj, 2, 0); } else { // 其他基础类型直接打印 pdf_print_obj(ctx, std_out, direct_obj, 2, 0); } printf("\n"); pdf_drop_obj(ctx, direct_obj); } } printf("\n"); }
内容来源于stack exchange

