1

I need, in C in under a linux environment, to print documents with an image as a background. I found an example which use Cairo vector graphics library to author a PostScript, and then sends it that off to CUPS for printing. I modified the initial source code to integrate it with a background image (background-img.png) .

The text to be printed is more than one page, I would like to know how can I print on multiple pages keeping the same image as background and changing only the foreground text ? How can I resize the background image to match the size of an A4 page ?

Here is the code used as a starting point :

// compile with:
//   gcc -Wall -o cairo_print_png cairo_print_png.c `pkg-config --cflags --libs cairo` `cups-config --cflags --libs`

#include <stdio.h>
#include <cairo.h>
#include <cairo-ps.h>
#include <cups/cups.h>

// A4 width, height in points, from GhostView manual:
// http://www.gnu.org/software/gv/manual/html_node/Paper-Keywords-and-paper-size-in-points.html
#define WIDTH  595  
#define HEIGHT 842  

int main(int argc, char** argv) {
int widthPng, heightPng;

if (argc!= 2){
   fprintf (stderr, "usage: %s word\n", argv[0]);
   return 1;
}

// setup
char* tmpfilename = tempnam(NULL,NULL);
cairo_surface_t* surface = cairo_ps_surface_create(tmpfilename, 
                                                 WIDTH, 
                                                 HEIGHT);
  
cairo_t *context = cairo_create(surface);

// draw some text
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]); // the text we got as a parameter

// draw a dotted box
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);  

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");
}  
widthPng = cairo_image_surface_get_width(surface_png);
heightPng = cairo_image_surface_get_height(surface_png);

cairo_surface_set_device_scale (surface_png,
                           widthPng/WIDTH*1.33,
                            heightPng/HEIGHT*1.29);
cairo_set_operator(context, CAIRO_OPERATOR_DEST_OVER);
cairo_set_source_surface(context, surface_png, 0, 0);
cairo_paint(context);

/*** second page ***/
{
   cairo_t *cr;
   cr = cairo_create (surface);

   /* Duplicate the last frame onto another page. (This is just a
    * way to sneak cairo_copy_page into the test).
    */   
   cairo_show_page (cr);
   
   //draw text on second page
   cairo_select_font_face(cr, 
                     "mono", 
                     CAIRO_FONT_SLANT_NORMAL, 
                     CAIRO_FONT_WEIGHT_NORMAL);
   cairo_set_font_size(cr, 30);
   cairo_move_to(cr, WIDTH/2, HEIGHT/2);
   cairo_show_text(cr, "text over second page");       

   cairo_set_operator(cr, CAIRO_OPERATOR_DEST_OVER);
   cairo_set_source_surface(cr, surface_png, 0, 0);
   cairo_paint(cr);

   cairo_destroy (cr);
 }  

// finish up    
cairo_show_page(context);
cairo_destroy(context);
cairo_surface_flush(surface);
cairo_surface_destroy(surface);

cairo_surface_flush(surface_png);
cairo_surface_destroy(surface_png);

// print    
cupsPrintFile("Cups-PDF", tmpfilename, "cairo PS", 0, NULL);  
unlink(tmpfilename);

return 0;
}

Update : I added the text enclosed in "second page". I can create another page, but I can't resize the background image. How can I resize the image to fit the A4 size?

Update I used cairo_surface_set_device_scale to resize the image, and the mono font to use a fixed width font

Update The problem now is that the code works with cairo-1.15.12-4 while if I try to compile with cairo-1.8.8-3.1 I get undefined reference to cairo_surface_set_device_scale'. What can I solve the problem? At the moment I cannot update the libraries using rpm as I would have to update the whole operating system. Can I somehow replace the cairo_surface_set_device_scale with functions that perform the same task?

Update: In the Cairo Mailing Lists I found the following function that does the job :

cairo_surface_t *scale_to_half(cairo_surface_t *s, int orig_width, int
orig_height,  double x_scale, double y_scale)
{
   cairo_surface_t *result = cairo_surface_create_similar(s,
        cairo_surface_get_content(s), orig_width*x_scale, orig_height*y_scale);
   cairo_t *cr = cairo_create(result);
   cairo_scale(cr, x_scale, y_scale);
   cairo_set_source_surface(cr, s, 0, 0);
   cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
   cairo_paint(cr);
   cairo_destroy(cr);
   return result;
}

but the quality is very low compared to cairo_surface_set_device_scale.

famedoro
  • 1,223
  • 2
  • 17
  • 41
  • If you found an answer, write it as an answer to your own question, rather than "adding to the question"! – pmg Sep 17 '21 at 13:31
  • I haven't found the solution yet, the resized image quality is very low compared to that obtained with cairo_surface_set_device_scale – famedoro Sep 17 '21 at 13:34
  • Oh, my bad, sorry. Didn't read enough of the last upadte – pmg Sep 17 '21 at 13:36

0 Answers0