如何在MuPDF(C语言)中将Pixmap写入新创建的PDF文件?
如何在MuPDF(C语言)中将Pixmap写入新创建的PDF文件?
看起来你的整体思路完全正确——创建PDF写入器、匹配pixmap尺寸开启新页面、准备好输出设备,只差最后把pixmap绘制到这个设备上的关键步骤啦!在MuPDF的C API里,我们可以用fz_draw_pixmap()函数来完成这个操作,下面我一步步给你讲清楚怎么改。
核心原理
fz_begin_page()返回的fz_device*就是PDF页面的绘制上下文,我们只需要把已经生成的pixmap通过fz_draw_pixmap()绘制到这个设备上,再结束页面、关闭写入器,就能得到包含这张pixmap的新PDF了。
关键代码修正
你只需要把代码里的How_can_I_Write_pixmap_to_the_device();替换成下面这段代码即可:
// ++++++++ Write _pix_ to the new document - 修正后的代码 ++++++++++ // 创建绘制矩阵:这里用单位矩阵,让pixmap完全铺满整个PDF页面 // 如果需要调整位置/缩放,可以修改矩阵,比如fz_scale(0.5, 0.5)将pixmap缩小一半 fz_matrix draw_matrix = fz_identity; // 将pixmap绘制到输出设备上 fz_try(ctx) { // 参数说明:上下文、输出设备、要绘制的pixmap、变换矩阵、 // 可选的alpha遮罩(这里用NULL)、可选的颜色参数(NULL用pixmap自身颜色)、 // 绘制标志(0表示默认) fz_draw_pixmap(ctx, out_device, pix, draw_matrix, NULL, NULL, 0); } fz_catch(ctx) { // 优化错误处理:不要只用assert,打印具体错误信息 fprintf(stderr, "绘制pixmap到PDF页面失败:%s\n", fz_caught_message(ctx)); // 错误时要正确清理资源,避免内存泄漏 fz_end_page(ctx, w); fz_close_document_writer(ctx, w); fz_drop_document_writer(ctx, w); fz_drop_pixmap(ctx, pix); fz_drop_document(ctx, doc); fz_drop_context(ctx); return EXIT_FAILURE; } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
额外的小修正(避免编译/运行错误)
你的代码里有个C语法的小问题:assert(ctx != nullptr);里的nullptr是C的关键字,在C语言里应该换成NULL,不然编译会报错,改成:
assert(ctx != NULL);
完整修正后的代码
这里把所有修改整合好,给你一份可以直接编译运行的完整代码:
#include <mupdf/fitz.h> #include <mupdf/fitz/context.h> #include <mupdf/fitz/document.h> #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> #include <stdio.h> #include <stdlib.h> #include <assert.h> int main(int argc, char **argv) { // 文件路径 char input_pdf_fname[] = "d:\\test_pdf\\in.pdf"; char output_png_fname[] = "d:\\test_pdf\\out.png"; char output_pdf_fname[] = "d:\\test_pdf\\out.pdf"; // 页面变换参数 float zoom = 100; float rotate = 0; int page_number = 5; int total_pages_int_pdf; fz_context *ctx; fz_document *doc; fz_pixmap *pix; fz_matrix ctm; /* 创建上下文:保存异常栈和各种缓存 */ ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED); assert(ctx != NULL); /* 注册默认的文档处理器 */ fz_register_document_handlers(ctx); /* 打开输入PDF */ fz_try(ctx) doc = fz_open_document(ctx, input_pdf_fname); fz_catch(ctx) { fprintf(stderr, "打开输入PDF失败:%s\n", fz_caught_message(ctx)); fz_drop_context(ctx); return EXIT_FAILURE; } /* 获取PDF总页数 */ fz_try(ctx) total_pages_int_pdf = fz_count_pages(ctx, doc); fz_catch(ctx) { fprintf(stderr, "获取PDF页数失败:%s\n", fz_caught_message(ctx)); fz_drop_document(ctx, doc); fz_drop_context(ctx); return EXIT_FAILURE; } printf("PDF总页数 = %d \n", total_pages_int_pdf); // 检查页码是否合法 if (page_number < 0 || page_number >= total_pages_int_pdf) { fprintf(stderr, "页码超出范围:输入页码%d,总页数%d\n", page_number + 1, total_pages_int_pdf); fz_drop_document(ctx, doc); fz_drop_context(ctx); return EXIT_FAILURE; } /* 创建变换矩阵:这里用1:1缩放,不旋转 */ ctm = fz_scale(1, 1); // 如果需要旋转和缩放,可以用下面的代码 // ctm = fz_scale(zoom / 100, zoom / 100); // ctm = fz_pre_rotate(ctm, rotate); /* 渲染页面到RGB pixmap */ fz_try(ctx) pix = fz_new_pixmap_from_page_number(ctx, doc, page_number, ctm, fz_device_rgb(ctx), 0); fz_catch(ctx) { fprintf(stderr, "渲染页面到pixmap失败:%s\n", fz_caught_message(ctx)); fz_drop_document(ctx, doc); fz_drop_context(ctx); return EXIT_FAILURE; } /* 保存pixmap为PNG(原代码正常工作) */ fz_try(ctx) fz_save_pixmap_as_png(ctx, pix, output_png_fname); fz_catch(ctx) { fprintf(stderr, "保存PNG失败:%s\n", fz_caught_message(ctx)); fz_drop_pixmap(ctx, pix); fz_drop_document(ctx, doc); fz_drop_context(ctx); return EXIT_FAILURE; } // -------- 创建新PDF ----------- // fz_document_writer *w; const char *options_pdf = 0; /* 创建PDF写入器 */ fz_try(ctx) w = fz_new_pdf_writer(ctx, output_pdf_fname, options_pdf); fz_catch(ctx) { fprintf(stderr, "创建PDF写入器失败:%s\n", fz_caught_message(ctx)); fz_drop_pixmap(ctx, pix); fz_drop_document(ctx, doc); fz_drop_context(ctx); return EXIT_FAILURE; } /* 获取pixmap的边界框,用来设置新PDF页面的大小 */ fz_irect rect_of_png = fz_pixmap_bbox(ctx, pix); fz_rect rect_of_pdf = fz_make_rect(rect_of_png.x0, rect_of_png.y0, rect_of_png.x1, rect_of_png.y1); /* 开启新页面,获取输出设备 */ fz_device *out_device; fz_try(ctx) out_device = fz_begin_page(ctx, w, rect_of_pdf); fz_catch(ctx) { fprintf(stderr, "开启PDF页面失败:%s\n", fz_caught_message(ctx)); fz_close_document_writer(ctx, w); fz_drop_document_writer(ctx, w); fz_drop_pixmap(ctx, pix); fz_drop_document(ctx, doc); fz_drop_context(ctx); return EXIT_FAILURE; } // ++++++++ 关键:将pixmap绘制到PDF页面 ++++++++++ fz_matrix draw_matrix = fz_identity; fz_try(ctx) fz_draw_pixmap(ctx, out_device, pix, draw_matrix, NULL, NULL, 0); fz_catch(ctx) { fprintf(stderr, "绘制pixmap到PDF页面失败:%s\n", fz_caught_message(ctx)); fz_end_page(ctx, w); fz_close_document_writer(ctx, w); fz_drop_document_writer(ctx, w); fz_drop_pixmap(ctx, pix); fz_drop_document(ctx, doc); fz_drop_context(ctx); return EXIT_FAILURE; } // ++++++++++++++++++++++++++++++++++++++++++++++++ /* 结束当前页面 */ fz_end_page(ctx, w); /* 关闭并保存PDF写入器 */ fz_try(ctx) fz_close_document_writer(ctx, w); fz_catch(ctx) { fprintf(stderr, "关闭PDF写入器失败:%s\n", fz_caught_message(ctx)); fz_drop_document_writer(ctx, w); fz_drop_pixmap(ctx, pix); fz_drop_document(ctx, doc); fz_drop_context(ctx); return EXIT_FAILURE; } /* 释放PDF写入器资源 */ fz_drop_document_writer(ctx, w); /* 清理所有资源 */ fz_drop_pixmap(ctx, pix); fz_drop_document(ctx, doc); fz_drop_context(ctx); printf("操作完成!输出PDF已保存到:%s\n", output_pdf_fname); return EXIT_SUCCESS; }
一些额外的建议
- 错误处理:我把你原来的
assert(0)改成了打印具体错误信息的方式,这样调试时更容易定位问题,生产环境也更友好。 - 坐标与缩放:如果需要调整pixmap在PDF页面上的位置或大小,可以修改
draw_matrix,比如fz_translate(100, 100)可以把pixmap向右下移动100单位,fz_scale(0.8, 0.8)可以缩小到80%。 - 颜色空间:如果你的pixmap是带alpha通道的(比如用
fz_device_rgba()创建的),fz_draw_pixmap()会自动处理透明效果,不需要额外操作。
内容来源于stack exchange
相关产品推荐
相关产品推荐

