Linux下C语言结合Cairo与CUPS实现多页带背景打印问题求解
解决方案
1. 多页统一背景实现
将背景绘制逻辑封装为独立公用函数,每次新建页面后先绘制背景,再绘制当前页的前景文本即可。cairo_show_page()会完成上一页输出并重置上下文为空白新页,重复调用背景绘制函数就能实现每页背景一致。
2. A4尺寸背景适配+低版本Cairo兼容方案
不需要操作图片表面的缩放属性,直接调整绘制上下文的变换矩阵即可实现缩放,该方案兼容Cairo 1.8.8版本,配合滤波参数设置可达到和cairo_surface_set_device_scale完全一致的画质,解决你之前找到的缩放函数画质差的问题。
关键修改代码
封装背景绘制函数
#define WIDTH 595 #define HEIGHT 842 // 背景绘制公用函数,支持自适应A4,可选择是否保持图片宽高比 void draw_background(cairo_t *cr, cairo_surface_t *png_surf, int png_w, int png_h) { cairo_save(cr); // 保存当前上下文状态,避免缩放影响后续文本绘制 // 计算缩放比例 double scale_x = (double)WIDTH / png_w; double scale_y = (double)HEIGHT / png_h; // 如需保持图片宽高比不拉伸,取消下面一行的注释即可 // double scale = scale_x < scale_y ? scale_x : scale_y; scale_x = scale; scale_y = scale; // 如需保持宽高比且背景居中,取消下面两行注释 // double offset_x = (WIDTH - png_w * scale_x) / 2; // double offset_y = (HEIGHT - png_h * scale_y) / 2; // cairo_translate(cr, offset_x, offset_y); cairo_scale(cr, scale_x, scale_y); // 设置双线性滤波,解决缩放模糊问题 cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_BILINEAR); cairo_set_operator(cr, CAIRO_OPERATOR_DEST_OVER); cairo_set_source_surface(cr, png_surf, 0, 0); cairo_paint(cr); cairo_restore(cr); // 恢复上下文状态 }
简化多页绘制逻辑
int main(int argc, char** argv) { int widthPng, heightPng; if (argc!= 2){ fprintf (stderr, "usage: %s word\n", argv[0]); return 1; } char* tmpfilename = tempnam(NULL,NULL); cairo_surface_t* surface = cairo_ps_surface_create(tmpfilename, WIDTH, HEIGHT); cairo_t *context = cairo_create(surface); // 全局只加载一次背景图,无需每页重复加载 cairo_surface_t* surface_png = cairo_image_surface_create_from_png("background-img.png"); if (surface_png == NULL || cairo_surface_status (surface_png)) { printf("***** load error *****\n"); return 1; } widthPng = cairo_image_surface_get_width(surface_png); heightPng = cairo_image_surface_get_height(surface_png); // 绘制第一页 cairo_select_font_face(context, "mono", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_set_font_size(context, 30); cairo_move_to(context, WIDTH/2, HEIGHT/2); cairo_show_text(context, argv[1]); const double pattern[] = {15.0, 10.0}; cairo_set_dash(context, pattern, 2, 0); cairo_set_line_width(context, 5); cairo_rectangle(context, WIDTH*0.33, HEIGHT*0.33, WIDTH*0.5, WIDTH*0.5); cairo_stroke(context); // 调用公用函数绘制背景 draw_background(context, surface_png, widthPng, heightPng); // 切换到第二页 cairo_show_page(context); // 绘制第二页,仅修改前景内容即可 cairo_select_font_face(context, "mono", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_set_font_size(context, 30); cairo_move_to(context, WIDTH/2, HEIGHT/2); cairo_show_text(context, "text over second page"); draw_background(context, surface_png, widthPng, heightPng); // 收尾逻辑 cairo_show_page(context); cairo_destroy(context); cairo_surface_flush(surface); cairo_surface_destroy(surface); cairo_surface_destroy(surface_png); cupsPrintFile("Cups-PDF", tmpfilename, "cairo PS", 0, NULL); unlink(tmpfilename); return 0; }
方案优势
- 完全兼容Cairo 1.8.8版本,不需要依赖
cairo_surface_set_device_scale接口 - 双线性滤波保证缩放画质和原生设备缩放完全一致,无模糊锯齿
- 无需创建中间缩放表面,内存占用更低、绘制效率更高
- 背景逻辑复用,新增页面仅需修改前景内容,维护成本更低
内容的提问来源于stack exchange,提问作者famedoro
相关产品推荐
相关产品推荐

