muPDF/C中渲染像素图后输出PDF显示空页的问题求助
muPDF/C中渲染像素图后输出PDF显示空页的问题求助
我最近在做muPDF相关开发时碰到了个头疼的问题:我把输入PDF的某一页渲染成像素图(pixmap)后,尝试将这个像素图写入新的输出PDF文件,但打开输出PDF时显示的是空页;不过只要取消注释DrawPathOnPage函数的调用,输出PDF就能正常显示红色矩形,这说明输出设备本身是工作正常的。而且我把pixmap保存成PNG时能正常显示内容,就是没法正确输出到PDF里,有没有大佬能帮我看看哪里出问题了?
以下是我的完整代码:
#include <mupdf/fitz.h> #include <mupdf/fitz/context.h> extern "C" { #include <mupdf/pdf/document.h> // pdf } #include <mupdf/fitz/pixmap.h> #include <mupdf/fitz/geometry.h> #include <mupdf/fitz/version.h> #include <mupdf/fitz/util.h> #include <mupdf/fitz/color.h> #include <mupdf/fitz/system.h> extern "C" { #include <mupdf/pdf/page.h> // page_pdf } extern "C" { #include <mupdf/pdf/xref.h> // pdf_trailer } #include <stdio.h> #include <stdlib.h> #include "MyUtils_LIB.h" void print_rect(const char* prefix, fz_rect r) { printf(" %s %d x %d --- %d x %d \n", prefix, (int)r.x0, (int)r.y0, (int)r.x1, (int)r.y1); } void DrawPathOnPage(fz_context* ctx, fz_device *dev //, pdf_document* dst_doc, int dst_page_num ) { // Draws a path in page #dst_page_num of the opened dst_doc. // === create path === fz_path* path = fz_new_path(ctx); // === fill rectangle === float x0 = 0; float y0 = 0; float x1 = 100; float y1 = 100; fz_rectto(ctx, path, x0, y0, x1, y1); fz_closepath(ctx, path); // load a page to modify //pdf_load_page(ctx, dst_doc, dst_page_num); // (Q) : how to link a device with a given page ??? //fz_device *dev = create_dev(); // write path float alpha = 0.9f; int even_odd = 0; fz_matrix ctm = fz_scale(1, 1); //fz_color_params fz_default_color_params; float color[3] ={1.0f, 0.0f, 0.0f}; fz_fill_path(ctx, dev, path, even_odd, ctm, fz_device_rgb(ctx), color, alpha, fz_default_color_params); fz_closepath(ctx, path); } // void DrawPathOnPage int main(int argc, char **argv) { printf("-------------------- Test 2 (small) -------------------\n"); // file names const char output_png_fname_mask[] = "d:\\test_pdf\\out_%d.png"; char input_pdf_fname[] = "d:\\test_pdf\\in.pdf"; char output_png_fname[200]; char output_pdf_fname[] = "d:\\test_pdf\\out.pdf"; int cur_page_number = 0; // page number to copy from // used to transform PDF page float zoom = 100; float rotate = 0; // total pages in PDF int total_pages_in_pdf; fz_context *ctx; fz_pixmap *pix; fz_matrix ctm; int x, y; /* Create a context to hold the exception stack and various caches. */ ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED); assert(ctx != nullptr); /* Register the default file types to handle. */ fz_register_document_handlers(ctx); /* Open the document. */ fz_document *doc = nullptr; fz_try(ctx) doc = fz_open_document(ctx, input_pdf_fname); fz_catch(ctx) { assert(0); } pdf_document *pdf_doc = nullptr; fz_try(ctx) pdf_doc = pdf_specifics(ctx, doc); fz_catch(ctx) { assert(0); } /* Count the number of pages. */ fz_try(ctx) total_pages_in_pdf = pdf_count_pages(ctx, pdf_doc); fz_catch(ctx) { assert(0); } printf("Total PDF pages = %d \n", total_pages_in_pdf); if (cur_page_number < 0 || cur_page_number >= total_pages_in_pdf) { fprintf(stderr, "page number out of range: cur=%d (total = %d)\n", cur_page_number, total_pages_in_pdf); pdf_drop_document(ctx, pdf_doc); fz_drop_context(ctx); return EXIT_FAILURE; } // -------- new PDF ----------- fz_document_writer *w; const char *options_pdf = NULL; // Create a new pdf document fz_try(ctx) w = fz_new_pdf_writer(ctx, output_pdf_fname, options_pdf); fz_catch(ctx) { assert(0); } printf("++++++ Copying page = %d ... ++++++\n", cur_page_number); printf(" From : %s\n", input_pdf_fname); printf(" To : %s\n", output_pdf_fname); pdf_page *page = nullptr; fz_try(ctx) page = pdf_load_page(ctx, pdf_doc, cur_page_number); fz_catch(ctx) { page = nullptr; assert(0); } // Output page boxes sizes fz_rect mediabox_media; fz_matrix ctm_media; pdf_page_transform_box(ctx, page, &mediabox_media, &ctm_media, FZ_MEDIA_BOX); print_rect(" :MEDIA BOX: ", mediabox_media); // 原代码错误复用了mediabox,这里修正为获取Crop Box fz_rect crop_box = pdf_page_bound_box(ctx, page, FZ_CROP_BOX); print_rect(" :CROP BOX: ", crop_box); int ppi = 72; float scale_factor = (float)ppi / 72.0; int alpha = 0; const char *usage = NULL; fz_box_type box_type = FZ_CROP_BOX; // --------- create pixmap from pdf ---------------- fz_try(ctx) pix = pdf_new_pixmap_from_page_contents_with_usage( ctx, page, fz_identity, fz_device_rgb(ctx), alpha, NULL, box_type); fz_catch(ctx) { assert(0); } // ------------------- 原代码缺失的关键绘制步骤 ------------------- // 1. 为输出PDF创建新页面,获取对应的绘制设备 fz_device *out_dev = fz_new_pdf_page(ctx, w, crop_box.x1 - crop_box.x0, crop_box.y1 - crop_box.y0, 0); if (!out_dev) { fprintf(stderr, "Failed to create output page device\n"); goto cleanup; } // 2. 设置变换矩阵:将pixmap对齐到页面左上角(因为原页面的Crop Box可能不是从(0,0)开始) fz_matrix draw_ctm = fz_translate(-crop_box.x0, -crop_box.y0); // 如果pixmap使用了非72PPI的分辨率,需要添加缩放,比如: // draw_ctm = fz_concat(draw_ctm, fz_scale(scale_factor, scale_factor)); // 3. 将pixmap绘制到输出设备上 fz_draw_pixmap(ctx, out_dev, draw_ctm, pix, NULL, NULL, 1.0f); // 4. 可选:取消注释可验证设备工作状态 // DrawPathOnPage(ctx, out_dev); // 5. 关闭设备并提交页面到PDF writer fz_close_device(ctx, out_dev); fz_drop_device(ctx, out_dev); // ------------------- 绘制步骤结束 ------------------- // 保存pixmap为PNG(可选) sprintf(output_png_fname, output_png_fname_mask, cur_page_number); fz_save_pixmap(ctx, pix, output_png_fname, NULL); printf("Saved PNG to %s\n", output_png_fname); cleanup: // 释放所有muPDF资源,避免内存泄漏 if (pix) fz_drop_pixmap(ctx, pix); if (page) fz_drop_page(ctx, (fz_page*)page); if (w) fz_close_document_writer(ctx, w); if (pdf_doc) pdf_drop_document(ctx, pdf_doc); fz_drop_context(ctx); printf("Done!\n"); return EXIT_SUCCESS; }
问题原因分析
你之前的代码核心缺失是:只创建了pixmap,但没有将pixmap的内容绘制到输出PDF的页面设备上。调用DrawPathOnPage时是直接在输出设备上绘制了路径,所以能显示内容;但pixmap的内容从未被传递到输出设备,因此PDF显示为空。
关键修改说明
- 修正页面尺寸获取:原代码错误地复用了Media Box的变量来打印Crop Box,现在改为正确获取原页面的Crop Box作为新页面的尺寸
- 添加输出页面设备:通过
fz_new_pdf_page为输出PDF创建新页面并获取绘制设备 - 设置变换矩阵:确保pixmap能正确对齐到页面的左上角位置,适配原页面的Crop Box偏移
- 绘制pixmap到设备:调用
fz_draw_pixmap将pixmap内容渲染到输出设备 - 完善资源清理:添加了统一的资源清理分支,避免内存泄漏
额外注意点
- 如果你的pixmap使用了非72PPI的分辨率(比如96PPI),需要在变换矩阵中加入对应的缩放因子,保证pixmap尺寸和页面匹配
- 所有muPDF创建的资源(pixmap、device、page等)必须用对应的
fz_drop_*函数释放 - 可以替换
FZ_CROP_BOX为FZ_MEDIA_BOX,根据需求选择页面的基准尺寸
内容来源于stack exchange
相关产品推荐
相关产品推荐

