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

如何在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;
}

一些额外的建议

  1. 错误处理:我把你原来的assert(0)改成了打印具体错误信息的方式,这样调试时更容易定位问题,生产环境也更友好。
  2. 坐标与缩放:如果需要调整pixmap在PDF页面上的位置或大小,可以修改draw_matrix,比如fz_translate(100, 100)可以把pixmap向右下移动100单位,fz_scale(0.8, 0.8)可以缩小到80%。
  3. 颜色空间:如果你的pixmap是带alpha通道的(比如用fz_device_rgba()创建的),fz_draw_pixmap()会自动处理透明效果,不需要额外操作。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 11:18:02