]> git.donarmstrong.com Git - xournal.git/blob - src/xo-print.c
Update to 0.3.1 (fix bug with LC_NUMERIC)
[xournal.git] / src / xo-print.c
1 #ifdef HAVE_CONFIG_H
2 #  include <config.h>
3 #endif
4
5 #include <gtk/gtk.h>
6 #include <libgnomecanvas/libgnomecanvas.h>
7 #include <libgnomeprint/gnome-print-job.h>
8 #include <zlib.h>
9 #include <string.h>
10 #include <locale.h>
11
12 #include "xournal.h"
13 #include "xo-misc.h"
14 #include "xo-paint.h"
15 #include "xo-print.h"
16 #include "xo-file.h"
17
18 #define RGBA_RED(rgba) (((rgba>>24)&0xff)/255.0)
19 #define RGBA_GREEN(rgba) (((rgba>>16)&0xff)/255.0)
20 #define RGBA_BLUE(rgba) (((rgba>>8)&0xff)/255.0)
21 #define RGBA_ALPHA(rgba) (((rgba>>0)&0xff)/255.0)
22 #define RGBA_RGB(rgba) RGBA_RED(rgba), RGBA_GREEN(rgba), RGBA_BLUE(rgba)
23
24 /*********** Printing to PDF ************/
25
26 gboolean ispdfspace(char c)
27 {
28   return (c==0 || c==9 || c==10 || c==12 || c==13 || c==' ');
29 }
30
31 gboolean ispdfdelim(char c)
32 {
33   return (c=='(' || c==')' || c=='<' || c=='>' || c=='[' || c==']' ||
34           c=='{' || c=='}' || c=='/' || c=='%');
35 }
36
37 void skipspace(char **p, char *eof)
38 {
39   while (ispdfspace(**p) || **p=='%') {
40     if (**p=='%') while (*p!=eof && **p!=10 && **p!=13) (*p)++;
41     if (*p==eof) return;
42     (*p)++;
43   }
44 }
45
46 void free_pdfobj(struct PdfObj *obj)
47 {
48   int i;
49   
50   if (obj==NULL) return;
51   if ((obj->type == PDFTYPE_STRING || obj->type == PDFTYPE_NAME ||
52       obj->type == PDFTYPE_STREAM) && obj->str!=NULL)
53     g_free(obj->str);
54   if ((obj->type == PDFTYPE_ARRAY || obj->type == PDFTYPE_DICT ||
55       obj->type == PDFTYPE_STREAM) && obj->num>0) {
56     for (i=0; i<obj->num; i++)
57       free_pdfobj(obj->elts[i]);
58     g_free(obj->elts);
59   }
60   if ((obj->type == PDFTYPE_DICT || obj->type == PDFTYPE_STREAM) && obj->num>0) {
61     for (i=0; i<obj->num; i++)
62       g_free(obj->names[i]);
63     g_free(obj->names);
64   }
65   g_free(obj);
66 }
67
68 struct PdfObj *dup_pdfobj(struct PdfObj *obj)
69 {
70   struct PdfObj *dup;
71   int i;
72   
73   if (obj==NULL) return NULL;
74   dup = g_memdup(obj, sizeof(struct PdfObj));
75   if ((obj->type == PDFTYPE_STRING || obj->type == PDFTYPE_NAME ||
76       obj->type == PDFTYPE_STREAM) && obj->str!=NULL) {
77     if (obj->type == PDFTYPE_NAME) obj->len = strlen(obj->str);
78     dup->str = g_memdup(obj->str, obj->len+1);
79   }
80   if ((obj->type == PDFTYPE_ARRAY || obj->type == PDFTYPE_DICT ||
81       obj->type == PDFTYPE_STREAM) && obj->num>0) {
82     dup->elts = g_malloc(obj->num*sizeof(struct PdfObj *));
83     for (i=0; i<obj->num; i++)
84       dup->elts[i] = dup_pdfobj(obj->elts[i]);
85   }
86   if ((obj->type == PDFTYPE_DICT || obj->type == PDFTYPE_STREAM) && obj->num>0) {
87     dup->names = g_malloc(obj->num*sizeof(char *));
88     for (i=0; i<obj->num; i++)
89       dup->names[i] = g_strdup(obj->names[i]);
90   }
91   return dup;
92 }
93
94 void show_pdfobj(struct PdfObj *obj, GString *str)
95 {
96   int i;
97   if (obj==NULL) return;
98   switch(obj->type) {
99     case PDFTYPE_CST:
100       if (obj->intval==1) g_string_append(str, "true");
101       if (obj->intval==0) g_string_append(str, "false");
102       if (obj->intval==-1) g_string_append(str, "null");
103       break;
104     case PDFTYPE_INT:
105       g_string_append_printf(str, "%d", obj->intval);
106       break;
107     case PDFTYPE_REAL:
108       g_string_append_printf(str, "%f", obj->realval);
109       break;
110     case PDFTYPE_STRING:
111       g_string_append_len(str, obj->str, obj->len);
112       break;
113     case PDFTYPE_NAME:
114       g_string_append(str, obj->str);
115       break;
116     case PDFTYPE_ARRAY:
117       g_string_append_c(str, '[');
118       for (i=0;i<obj->num;i++) {
119         if (i) g_string_append_c(str, ' ');
120         show_pdfobj(obj->elts[i], str);
121       }
122       g_string_append_c(str, ']');
123       break;
124     case PDFTYPE_DICT:
125       g_string_append(str, "<<");
126       for (i=0;i<obj->num;i++) {
127         g_string_append_printf(str, " %s ", obj->names[i]); 
128         show_pdfobj(obj->elts[i], str);
129       }
130       g_string_append(str, " >>");
131       break;
132     case PDFTYPE_REF:
133       g_string_append_printf(str, "%d %d R", obj->intval, obj->num);
134       break;
135   }
136 }
137
138 void DEBUG_PRINTOBJ(struct PdfObj *obj)
139 {
140   GString *s = g_string_new("");
141   show_pdfobj(obj, s);
142   puts(s->str);
143   g_string_free(s, TRUE);
144 }
145
146 // parse a PDF object; returns NULL if fails
147 // THIS PARSER DOES NOT RECOGNIZE STREAMS YET
148
149 struct PdfObj *parse_pdf_object(char **ptr, char *eof)
150 {
151   struct PdfObj *obj, *elt;
152   char *p, *q, *r, *eltname;
153   int stack;
154
155   obj = g_malloc(sizeof(struct PdfObj));
156   p = *ptr;
157   skipspace(&p, eof);
158   if (p==eof) { g_free(obj); return NULL; }
159   
160   // maybe a constant
161   if (!strncmp(p, "true", 4)) {
162     obj->type = PDFTYPE_CST;
163     obj->intval = 1;
164     *ptr = p+4;
165     return obj;
166   }
167   if (!strncmp(p, "false", 5)) {
168     obj->type = PDFTYPE_CST;
169     obj->intval = 0;
170     *ptr = p+5;
171     return obj;
172   }
173   if (!strncmp(p, "null", 4)) {
174     obj->type = PDFTYPE_CST;
175     obj->intval = -1;
176     *ptr = p+4;
177     return obj;
178   }
179
180   // or a number ?
181   obj->intval = strtol(p, &q, 10);
182   *ptr = q;
183   if (q!=p) {
184     if (*q == '.') {
185       obj->type = PDFTYPE_REAL;
186       obj->realval = g_ascii_strtod(p, ptr);
187       return obj;
188     }
189     if (ispdfspace(*q)) {
190       // check for indirect reference
191       skipspace(&q, eof);
192       obj->num = strtol(q, &r, 10);
193       if (r!=q) {
194         skipspace(&r, eof);
195         if (*r=='R') {
196           *ptr = r+1;
197           obj->type = PDFTYPE_REF;
198           return obj;
199         }
200       }
201     }
202     obj->type = PDFTYPE_INT;
203     return obj;
204   }
205
206   // a string ?
207   if (*p=='(') {
208     q=p+1; stack=1;
209     while (stack>0 && q!=eof) {
210       if (*q=='(') stack++;
211       if (*q==')') stack--;
212       if (*q=='\\') q++;
213       if (q!=eof) q++;
214     }
215     if (q==eof) { g_free(obj); return NULL; }
216     obj->type = PDFTYPE_STRING;
217     obj->len = q-p;
218     obj->str = g_malloc(obj->len+1);
219     obj->str[obj->len] = 0;
220     g_memmove(obj->str, p, obj->len);
221     *ptr = q;
222     return obj;
223   }  
224   if (*p=='<' && p[1]!='<') {
225     q=p+1;
226     while (*q!='>' && q!=eof) q++;
227     if (q==eof) { g_free(obj); return NULL; }
228     q++;
229     obj->type = PDFTYPE_STRING;
230     obj->len = q-p;
231     obj->str = g_malloc(obj->len+1);
232     obj->str[obj->len] = 0;
233     g_memmove(obj->str, p, obj->len);
234     *ptr = q;
235     return obj;
236   }
237   
238   // a name ?
239   if (*p=='/') {
240     q=p+1;
241     while (!ispdfspace(*q) && !ispdfdelim(*q)) q++;
242     obj->type = PDFTYPE_NAME;
243     obj->str = g_strndup(p, q-p);
244     *ptr = q;
245     return obj;
246   }
247
248   // an array ?
249   if (*p=='[') {
250     obj->type = PDFTYPE_ARRAY;
251     obj->num = 0;
252     obj->elts = NULL;
253     q=p+1; skipspace(&q, eof);
254     while (*q!=']') {
255       elt = parse_pdf_object(&q, eof);
256       if (elt==NULL) { free_pdfobj(obj); return NULL; }
257       obj->num++;
258       obj->elts = g_realloc(obj->elts, obj->num*sizeof(struct PdfObj *));
259       obj->elts[obj->num-1] = elt;
260       skipspace(&q, eof);
261     }
262     *ptr = q+1;
263     return obj;
264   }
265
266   // a dictionary ?
267   if (*p=='<' && p[1]=='<') {
268     obj->type = PDFTYPE_DICT;
269     obj->num = 0;
270     obj->elts = NULL;
271     obj->names = NULL;
272     q=p+2; skipspace(&q, eof);
273     while (*q!='>' || q[1]!='>') {
274       if (*q!='/') { free_pdfobj(obj); return NULL; }
275       r=q+1;
276       while (!ispdfspace(*r) && !ispdfdelim(*r)) r++;
277       eltname = g_strndup(q, r-q);
278       q=r; skipspace(&q, eof);
279       elt = parse_pdf_object(&q, eof);
280       if (elt==NULL) { g_free(eltname); free_pdfobj(obj); return NULL; }
281       obj->num++;
282       obj->elts = g_realloc(obj->elts, obj->num*sizeof(struct PdfObj *));
283       obj->names = g_realloc(obj->names, obj->num*sizeof(char *));
284       obj->elts[obj->num-1] = elt;
285       obj->names[obj->num-1] = eltname;
286       skipspace(&q, eof);
287     }
288     *ptr = q+2;
289     return obj;
290   }
291
292   // DOES NOT RECOGNIZE STREAMS YET (handle as subcase of dictionary)
293   
294   g_free(obj);
295   return NULL;
296 }
297
298 struct PdfObj *get_dict_entry(struct PdfObj *dict, char *name)
299 {
300   int i;
301   
302   if (dict==NULL) return NULL;
303   if (dict->type != PDFTYPE_DICT) return NULL;
304   for (i=0; i<dict->num; i++) 
305     if (!strcmp(dict->names[i], name)) return dict->elts[i];
306   return NULL;
307 }
308
309 struct PdfObj *get_pdfobj(GString *pdfbuf, struct XrefTable *xref, struct PdfObj *obj)
310 {
311   char *p, *eof;
312   int offs, n;
313
314   if (obj==NULL) return NULL;
315   if (obj->type!=PDFTYPE_REF) return dup_pdfobj(obj);
316   if (obj->intval>xref->last) return NULL;
317   offs = xref->data[obj->intval];
318   if (offs<=0 || offs >= pdfbuf->len) return NULL;
319
320   p = pdfbuf->str + offs;
321   eof = pdfbuf->str + pdfbuf->len;
322   n = strtol(p, &p, 10);
323   if (n!=obj->intval) return NULL;
324   skipspace(&p, eof);
325   n = strtol(p, &p, 10);
326   skipspace(&p, eof);
327   if (strncmp(p, "obj", 3)) return NULL;
328   p+=3;
329   return parse_pdf_object(&p, eof);
330 }
331
332 // read the xref table of a PDF file in memory, and return the trailerdict
333
334 struct PdfObj *parse_xref_table(GString *pdfbuf, struct XrefTable *xref, int offs)
335 {
336   char *p, *q, *eof;
337   struct PdfObj *trailerdict, *obj;
338   int start, len, i;
339   
340   if (strncmp(pdfbuf->str+offs, "xref", 4)) return NULL;
341   p = strstr(pdfbuf->str+offs, "trailer");
342   eof = pdfbuf->str + pdfbuf->len;
343   if (p==NULL) return NULL;
344   p+=8;
345   trailerdict = parse_pdf_object(&p, eof);
346   obj = get_dict_entry(trailerdict, "/Size");
347   if (obj!=NULL && obj->type == PDFTYPE_INT && obj->intval-1>xref->last)
348     make_xref(xref, obj->intval-1, 0);
349   obj = get_dict_entry(trailerdict, "/Prev");
350   if (obj!=NULL && obj->type == PDFTYPE_INT && obj->intval>0 && obj->intval!=offs) {
351     // recurse into older xref table
352     obj = parse_xref_table(pdfbuf, xref, obj->intval);
353     free_pdfobj(obj);
354   }
355   p = pdfbuf->str+offs+4;
356   skipspace(&p, eof);
357   if (*p<'0' || *p>'9') { free_pdfobj(trailerdict); return NULL; }
358   while (*p>='0' && *p<='9') {
359     start = strtol(p, &p, 10);
360     skipspace(&p, eof);
361     len = strtol(p, &p, 10);
362     skipspace(&p, eof);
363     if (len <= 0 || 20*len > eof-p) break;
364     if (start+len-1 > xref->last) make_xref(xref, start+len-1, 0);
365     for (i=start; i<start+len; i++) {
366       xref->data[i] = strtol(p, NULL, 10);
367       p+=20;
368     }
369     skipspace(&p, eof);
370   }
371   if (*p!='t') { free_pdfobj(trailerdict); return NULL; }
372   return trailerdict;
373 }
374
375 // parse the page tree
376
377 int pdf_getpageinfo(GString *pdfbuf, struct XrefTable *xref, 
378                 struct PdfObj *pgtree, int nmax, struct PdfPageDesc *pages)
379 {
380   struct PdfObj *obj, *kid;
381   int i, count, j;
382   
383   obj = get_pdfobj(pdfbuf, xref, get_dict_entry(pgtree, "/Type"));
384   if (obj == NULL || obj->type != PDFTYPE_NAME)
385     return 0;
386   if (!strcmp(obj->str, "/Page")) {
387     free_pdfobj(obj);
388     pages->contents = dup_pdfobj(get_dict_entry(pgtree, "/Contents"));
389     obj = get_pdfobj(pdfbuf, xref, get_dict_entry(pgtree, "/Resources"));
390     if (obj!=NULL) {
391       free_pdfobj(pages->resources);
392       pages->resources = obj;
393     }
394     obj = get_pdfobj(pdfbuf, xref, get_dict_entry(pgtree, "/MediaBox"));
395     if (obj!=NULL) {
396       free_pdfobj(pages->mediabox);
397       pages->mediabox = obj;
398     }
399     obj = get_pdfobj(pdfbuf, xref, get_dict_entry(pgtree, "/Rotate"));
400     if (obj!=NULL && obj->type == PDFTYPE_INT)
401       pages->rotate = obj->intval;
402     free_pdfobj(obj);
403     return 1;
404   }
405   else if (!strcmp(obj->str, "/Pages")) {
406     free_pdfobj(obj);
407     obj = get_pdfobj(pdfbuf, xref, get_dict_entry(pgtree, "/Count"));
408     if (obj!=NULL && obj->type == PDFTYPE_INT && 
409         obj->intval>0 && obj->intval<=nmax) count = obj->intval;
410     else count = 0;
411     free_pdfobj(obj);
412     obj = get_pdfobj(pdfbuf, xref, get_dict_entry(pgtree, "/Resources"));
413     if (obj!=NULL)
414       for (i=0; i<count; i++) {
415         free_pdfobj(pages[i].resources);
416         pages[i].resources = dup_pdfobj(obj);
417       }
418     free_pdfobj(obj);
419     obj = get_pdfobj(pdfbuf, xref, get_dict_entry(pgtree, "/MediaBox"));
420     if (obj!=NULL)
421       for (i=0; i<count; i++) {
422         free_pdfobj(pages[i].mediabox);
423         pages[i].mediabox = dup_pdfobj(obj);
424       }
425     free_pdfobj(obj);
426     obj = get_pdfobj(pdfbuf, xref, get_dict_entry(pgtree, "/Rotate"));
427     if (obj!=NULL && obj->type == PDFTYPE_INT)
428       for (i=0; i<count; i++)
429         pages[i].rotate = obj->intval;
430     free_pdfobj(obj);
431     obj = get_pdfobj(pdfbuf, xref, get_dict_entry(pgtree, "/Kids"));
432     if (obj!=NULL && obj->type == PDFTYPE_ARRAY) {
433       for (i=0; i<obj->num; i++) {
434         kid = get_pdfobj(pdfbuf, xref, obj->elts[i]);
435         if (kid!=NULL) {
436           j = pdf_getpageinfo(pdfbuf, xref, kid, nmax, pages);
437           nmax -= j;
438           pages += j;
439           free_pdfobj(kid);
440         }
441       }
442     }
443     free_pdfobj(obj);
444     return count;
445   }
446   return 0;
447 }
448
449 // parse a PDF file in memory
450
451 gboolean pdf_parse_info(GString *pdfbuf, struct PdfInfo *pdfinfo, struct XrefTable *xref)
452 {
453   char *p;
454   int i, offs;
455   struct PdfObj *obj, *pages;
456
457   xref->n_alloc = xref->last = 0;
458   xref->data = NULL;
459   p = pdfbuf->str + pdfbuf->len-1;
460   
461   while (*p!='s' && p!=pdfbuf->str) p--;
462   if (strncmp(p, "startxref", 9)) return FALSE; // fail
463   p+=9;
464   while (ispdfspace(*p) && p!=pdfbuf->str+pdfbuf->len) p++;
465   offs = strtol(p, NULL, 10);
466   if (offs <= 0 || offs > pdfbuf->len) return FALSE; // fail
467   pdfinfo->startxref = offs;
468   
469   pdfinfo->trailerdict = parse_xref_table(pdfbuf, xref, offs);
470   if (pdfinfo->trailerdict == NULL) return FALSE; // fail
471   
472   obj = get_pdfobj(pdfbuf, xref,
473      get_dict_entry(pdfinfo->trailerdict, "/Root"));
474   if (obj == NULL)
475     { free_pdfobj(pdfinfo->trailerdict); return FALSE; }
476   pages = get_pdfobj(pdfbuf, xref, get_dict_entry(obj, "/Pages"));
477   free_pdfobj(obj);
478   if (pages == NULL)
479     { free_pdfobj(pdfinfo->trailerdict); return FALSE; }
480   obj = get_pdfobj(pdfbuf, xref, get_dict_entry(pages, "/Count"));
481   if (obj == NULL || obj->type != PDFTYPE_INT || obj->intval<=0) 
482     { free_pdfobj(pdfinfo->trailerdict); free_pdfobj(pages); 
483       free_pdfobj(obj); return FALSE; }
484   pdfinfo->npages = obj->intval;
485   free_pdfobj(obj);
486   
487   pdfinfo->pages = g_malloc0(pdfinfo->npages*sizeof(struct PdfPageDesc));
488   pdf_getpageinfo(pdfbuf, xref, pages, pdfinfo->npages, pdfinfo->pages);
489   free_pdfobj(pages);
490   
491   return TRUE;
492 }
493
494 // add an entry to the xref table
495
496 void make_xref(struct XrefTable *xref, int nobj, int offset)
497 {
498   if (xref->n_alloc <= nobj) {
499     xref->n_alloc = nobj + 10;
500     xref->data = g_realloc(xref->data, xref->n_alloc*sizeof(int));
501   }
502   if (xref->last < nobj) xref->last = nobj;
503   xref->data[nobj] = offset;
504 }
505
506 // a wrapper for deflate
507
508 GString *do_deflate(char *in, int len)
509 {
510   GString *out;
511   z_stream zs;
512   
513   zs.zalloc = Z_NULL;
514   zs.zfree = Z_NULL;
515   deflateInit(&zs, Z_DEFAULT_COMPRESSION);
516   zs.next_in = (Bytef *)in;
517   zs.avail_in = len;
518   zs.avail_out = deflateBound(&zs, len);
519   out = g_string_sized_new(zs.avail_out);
520   zs.next_out = (Bytef *)out->str;
521   deflate(&zs, Z_FINISH);
522   out->len = zs.total_out;
523   deflateEnd(&zs);
524   return out;
525 }
526
527 // prefix to scale the original page
528
529 GString *make_pdfprefix(struct PdfPageDesc *pgdesc, double width, double height)
530 {
531   GString *str;
532   double v[4], t, xscl, yscl;
533   int i;
534   
535   str = g_string_new("q ");
536   if (pgdesc->rotate == 90) {
537     g_string_append_printf(str, "0 -1 1 0 0 %.2f cm ", height);
538     t = height; height = width; width = t;
539   }
540   if (pgdesc->rotate == 270) {
541     g_string_append_printf(str, "0 1 -1 0 %.2f 0 cm ", width);
542     t = height; height = width; width = t;
543   }
544   if (pgdesc->rotate == 180) {
545     g_string_append_printf(str, "-1 0 0 -1 %.2f %.2f cm ", width, height);
546   }
547   if (pgdesc->mediabox==NULL || pgdesc->mediabox->type != PDFTYPE_ARRAY ||
548       pgdesc->mediabox->num != 4) return str;
549   for (i=0; i<4; i++) {
550     if (pgdesc->mediabox->elts[i]->type == PDFTYPE_INT)
551       v[i] = pgdesc->mediabox->elts[i]->intval;
552     else if (pgdesc->mediabox->elts[i]->type == PDFTYPE_REAL)
553       v[i] = pgdesc->mediabox->elts[i]->realval;
554     else return str;
555   }
556   if (v[0]>v[2]) { t = v[0]; v[0] = v[2]; v[2] = t; }
557   if (v[1]>v[3]) { t = v[1]; v[1] = v[3]; v[3] = t; }
558   if (v[2]-v[0] < 1. || v[3]-v[1] < 1.) return str;
559   xscl = width/(v[2]-v[0]);
560   yscl = height/(v[3]-v[1]);
561   g_string_append_printf(str, "%.4f 0 0 %.4f %.2f %.2f cm ",
562     xscl, yscl, -v[0]*xscl, -v[1]*yscl);
563   return str;
564 }
565
566 // add an entry to a subentry of a directory
567
568 struct PdfObj *mk_pdfname(char *name)
569 {
570   struct PdfObj *obj;
571   
572   obj = g_malloc(sizeof(struct PdfObj));
573   obj->type = PDFTYPE_NAME;
574   obj->str = g_strdup(name);
575   return obj;
576 }
577
578 struct PdfObj *mk_pdfref(int num)
579 {
580   struct PdfObj *obj;
581   
582   obj = g_malloc(sizeof(struct PdfObj));
583   obj->type = PDFTYPE_REF;
584   obj->intval = num;
585   obj->num = 0;
586   return obj;
587 }
588
589 gboolean iseq_obj(struct PdfObj *a, struct PdfObj *b)
590 {
591   if (a==NULL || b==NULL) return (a==b);
592   if (a->type!=b->type) return FALSE;
593   if (a->type == PDFTYPE_CST || a->type == PDFTYPE_INT)
594     return (a->intval == b->intval);
595   if (a->type == PDFTYPE_REAL)
596     return (a->realval == b->realval);
597   if (a->type == PDFTYPE_NAME)
598     return !strcmp(a->str, b->str);
599   if (a->type == PDFTYPE_REF)
600     return (a->intval == b->intval && a->num == b->num);
601   return FALSE;
602 }
603
604 void add_dict_subentry(GString *pdfbuf, struct XrefTable *xref,
605    struct PdfObj *obj, char *section, int type, char *name, struct PdfObj *entry)
606 {
607   struct PdfObj *sec;
608   int i, subpos;
609   
610   subpos = -1;
611   for (i=0; i<obj->num; i++) 
612     if (!strcmp(obj->names[i], section)) subpos = i;
613   if (subpos == -1) {
614     subpos = obj->num;
615     obj->num++;
616     obj->elts = g_realloc(obj->elts, obj->num*sizeof(struct PdfObj*));
617     obj->names = g_realloc(obj->names, obj->num*sizeof(char *));
618     obj->names[subpos] = g_strdup(section);
619     obj->elts[subpos] = NULL;
620   }
621   if (obj->elts[subpos]!=NULL && obj->elts[subpos]->type==PDFTYPE_REF) {
622     sec = get_pdfobj(pdfbuf, xref, obj->elts[subpos]);
623     free_pdfobj(obj->elts[subpos]);
624     obj->elts[subpos] = sec;
625   }
626   if (obj->elts[subpos]!=NULL && obj->elts[subpos]->type!=type)
627     { free_pdfobj(obj->elts[subpos]); obj->elts[subpos] = NULL; }
628   if (obj->elts[subpos] == NULL) {
629     obj->elts[subpos] = sec = g_malloc(sizeof(struct PdfObj));
630     sec->type = type;
631     sec->num = 0;
632     sec->elts = NULL;
633     sec->names = NULL;
634   }
635   sec = obj->elts[subpos];
636
637   subpos = -1;
638   if (type==PDFTYPE_DICT) {
639     for (i=0; i<sec->num; i++) 
640       if (!strcmp(sec->names[i], name)) subpos = i;
641     if (subpos == -1) {
642       subpos = sec->num;
643       sec->num++;
644       sec->elts = g_realloc(sec->elts, sec->num*sizeof(struct PdfObj*));
645       sec->names = g_realloc(sec->names, sec->num*sizeof(char *));
646       sec->names[subpos] = g_strdup(name);
647       sec->elts[subpos] = NULL;
648     }
649     free_pdfobj(sec->elts[subpos]);
650     sec->elts[subpos] = entry;
651   } 
652   if (type==PDFTYPE_ARRAY) {
653     for (i=0; i<sec->num; i++)
654       if (iseq_obj(sec->elts[i], entry)) subpos = i;
655     if (subpos == -1) {
656       subpos = sec->num;
657       sec->num++;
658       sec->elts = g_realloc(sec->elts, sec->num*sizeof(struct PdfObj*));
659       sec->elts[subpos] = entry;
660     }
661     else free_pdfobj(entry);
662   }
663 }
664
665 // draw a page's background
666
667 void pdf_draw_solid_background(struct Page *pg, GString *str)
668 {
669   double x, y;
670
671   g_string_append_printf(str, 
672     "%.2f %.2f %.2f rg 0 0 %.2f %.2f re f ",
673     RGBA_RGB(pg->bg->color_rgba), pg->width, pg->height);
674   if (pg->bg->ruling == RULING_NONE) return;
675   g_string_append_printf(str,
676     "%.2f %.2f %.2f RG %.2f w ",
677     RGBA_RGB(RULING_COLOR), RULING_THICKNESS);
678   if (pg->bg->ruling == RULING_GRAPH) {
679     for (x=RULING_GRAPHSPACING; x<pg->width-1; x+=RULING_GRAPHSPACING)
680       g_string_append_printf(str, "%.2f 0 m %.2f %.2f l S ",
681         x, x, pg->height);
682     for (y=RULING_GRAPHSPACING; y<pg->height-1; y+=RULING_GRAPHSPACING)
683       g_string_append_printf(str, "0 %.2f m %.2f %.2f l S ",
684         y, pg->width, y);
685     return;
686   }
687   for (y=RULING_TOPMARGIN; y<pg->height-1; y+=RULING_SPACING)
688     g_string_append_printf(str, "0 %.2f m %.2f %.2f l S ",
689       y, pg->width, y);
690   if (pg->bg->ruling == RULING_LINED)
691     g_string_append_printf(str, 
692       "%.2f %.2f %.2f RG %.2f 0 m %.2f %.2f l S ",
693       RGBA_RGB(RULING_MARGIN_COLOR), 
694       RULING_LEFTMARGIN, RULING_LEFTMARGIN, pg->height);
695 }
696
697 int pdf_draw_bitmap_background(struct Page *pg, GString *str, 
698                                 struct XrefTable *xref, GString *pdfbuf)
699 {
700   BgPdfPage *pgpdf;
701   GdkPixbuf *pix;
702   GString *zpix;
703   char *buf, *p1, *p2;
704   int height, width, stride, x, y, chan;
705   
706   if (pg->bg->type == BG_PDF) {
707     pgpdf = (struct BgPdfPage *)g_list_nth_data(bgpdf.pages, pg->bg->file_page_seq-1);
708     if (pgpdf == NULL) return -1;
709     if (pgpdf->dpi != PDFTOPPM_PRINTING_DPI) {
710       add_bgpdf_request(pg->bg->file_page_seq, 0, TRUE);
711       while (pgpdf->dpi != PDFTOPPM_PRINTING_DPI && bgpdf.status == STATUS_RUNNING)
712         gtk_main_iteration();
713     }
714     pix = pgpdf->pixbuf;
715   }
716   else pix = pg->bg->pixbuf;
717   
718   if (gdk_pixbuf_get_bits_per_sample(pix) != 8) return -1;
719   if (gdk_pixbuf_get_colorspace(pix) != GDK_COLORSPACE_RGB) return -1;
720   
721   width = gdk_pixbuf_get_width(pix);
722   height = gdk_pixbuf_get_height(pix);
723   stride = gdk_pixbuf_get_rowstride(pix);
724   chan = gdk_pixbuf_get_n_channels(pix);
725   if (chan!=3 && chan!=4) return -1;
726
727   g_string_append_printf(str, "q %.2f 0 0 %.2f 0 %.2f cm /ImBg Do Q ",
728     pg->width, -pg->height, pg->height);
729   
730   p2 = buf = (char *)g_malloc(3*width*height);
731   for (y=0; y<height; y++) {
732     p1 = (char *)gdk_pixbuf_get_pixels(pix)+stride*y;
733     for (x=0; x<width; x++) {
734       *(p2++)=*(p1++); *(p2++)=*(p1++); *(p2++)=*(p1++);
735       if (chan==4) p1++;
736     }
737   }
738   zpix = do_deflate(buf, 3*width*height);
739   g_free(buf);
740
741   make_xref(xref, xref->last+1, pdfbuf->len);
742   g_string_append_printf(pdfbuf, 
743     "%d 0 obj\n<< /Length %d /Filter /FlateDecode /Type /Xobject "
744     "/Subtype /Image /Width %d /Height %d /ColorSpace /DeviceRGB "
745     "/BitsPerComponent 8 >> stream\n",
746     xref->last, zpix->len, width, height);
747   g_string_append_len(pdfbuf, zpix->str, zpix->len);
748   g_string_free(zpix, TRUE);
749   g_string_append(pdfbuf, "endstream\nendobj\n");
750  
751   return xref->last;
752 }
753
754 // draw a page's graphics
755
756 void pdf_draw_page(struct Page *pg, GString *str, gboolean *use_hiliter)
757 {
758   GList *layerlist, *itemlist;
759   struct Layer *l;
760   struct Item *item;
761   guint old_rgba;
762   double old_thickness;
763   double *pt;
764   int i;
765   
766   old_rgba = 0x12345678;    // not any values we use, so we'll reset them
767   old_thickness = 0.0;
768
769   for (layerlist = pg->layers; layerlist!=NULL; layerlist = layerlist->next) {
770     l = (struct Layer *)layerlist->data;
771     for (itemlist = l->items; itemlist!=NULL; itemlist = itemlist->next) {
772       item = (struct Item *)itemlist->data;
773       if (item->type == ITEM_STROKE) {
774         if ((item->brush.color_rgba & ~0xff) != old_rgba)
775           g_string_append_printf(str, "%.2f %.2f %.2f RG ",
776             RGBA_RGB(item->brush.color_rgba));
777         if (item->brush.thickness != old_thickness)
778           g_string_append_printf(str, "%.2f w ", item->brush.thickness);
779         if ((item->brush.color_rgba & 0xf0) != 0xf0) { // transparent
780           g_string_append(str, "q /XoHi gs ");
781           *use_hiliter = TRUE;
782         }
783         old_rgba = item->brush.color_rgba & ~0xff;
784         old_thickness = item->brush.thickness;
785         pt = item->path->coords;
786         g_string_append_printf(str, "%.2f %.2f m ", pt[0], pt[1]);
787         for (i=1, pt+=2; i<item->path->num_points; i++, pt+=2)
788           g_string_append_printf(str, "%.2f %.2f l ", pt[0], pt[1]);
789         g_string_append_printf(str,"S\n");
790         if ((item->brush.color_rgba & 0xf0) != 0xf0) // undo transparent
791           g_string_append(str, "Q ");
792       }
793     }
794   }
795 }
796
797 // main printing function
798
799 /* we use the following object numbers, starting with n_obj_catalog:
800     0 the document catalog
801     1 the page tree
802     2 the GS for the hiliters
803     3 ... the page objects
804 */
805
806 gboolean print_to_pdf(char *filename)
807 {
808   FILE *f;
809   GString *pdfbuf, *pgstrm, *zpgstrm, *tmpstr;
810   int n_obj_catalog, n_obj_pages_offs, n_page, n_obj_bgpix, n_obj_prefix;
811   int i, startxref;
812   struct XrefTable xref;
813   GList *pglist;
814   struct Page *pg;
815   char *buf;
816   unsigned int len;
817   gboolean annot, uses_pdf;
818   gboolean use_hiliter;
819   struct PdfInfo pdfinfo;
820   struct PdfObj *obj;
821   
822   f = fopen(filename, "w");
823   if (f == NULL) return FALSE;
824   setlocale(LC_NUMERIC, "C");
825   annot = FALSE;
826   xref.data = NULL;
827   uses_pdf = FALSE;
828   for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
829     pg = (struct Page *)pglist->data;
830     if (pg->bg->type == BG_PDF) uses_pdf = TRUE;
831   }
832   
833   if (uses_pdf && bgpdf.status != STATUS_NOT_INIT && 
834       g_file_get_contents(bgpdf.tmpfile_copy, &buf, &len, NULL) &&
835       !strncmp(buf, "%PDF-1.", 7)) {
836     // parse the existing PDF file
837     pdfbuf = g_string_new_len(buf, len);
838     g_free(buf);
839     if (pdfbuf->str[7]<'4') pdfbuf->str[7] = '4'; // upgrade to 1.4
840     annot = pdf_parse_info(pdfbuf, &pdfinfo, &xref);
841     if (!annot) {
842       g_string_free(pdfbuf, TRUE);
843       if (xref.data != NULL) g_free(xref.data);
844     }
845   }
846
847   if (!annot) {
848     pdfbuf = g_string_new("%PDF-1.4\n%\370\357\365\362\n");
849     xref.n_alloc = xref.last = 0;
850     xref.data = NULL;
851   }
852     
853   // catalog and page tree
854   n_obj_catalog = xref.last+1;
855   n_obj_pages_offs = xref.last+4;
856   make_xref(&xref, n_obj_catalog, pdfbuf->len);
857   g_string_append_printf(pdfbuf, 
858     "%d 0 obj\n<< /Type /Catalog /Pages %d 0 R >> endobj\n",
859      n_obj_catalog, n_obj_catalog+1);
860   make_xref(&xref, n_obj_catalog+1, pdfbuf->len);
861   g_string_append_printf(pdfbuf,
862     "%d 0 obj\n<< /Type /Pages /Kids [", n_obj_catalog+1);
863   for (i=0;i<journal.npages;i++)
864     g_string_append_printf(pdfbuf, "%d 0 R ", n_obj_pages_offs+i);
865   g_string_append_printf(pdfbuf, "] /Count %d >> endobj\n", journal.npages);
866   make_xref(&xref, n_obj_catalog+2, pdfbuf->len);
867   g_string_append_printf(pdfbuf, 
868     "%d 0 obj\n<< /Type /ExtGState /CA 0.5 >> endobj\n",
869      n_obj_catalog+2);
870   xref.last = n_obj_pages_offs + journal.npages-1;
871   
872   for (pglist = journal.pages, n_page = 0; pglist!=NULL;
873        pglist = pglist->next, n_page++) {
874     pg = (struct Page *)pglist->data;
875     
876     // draw the background and page into pgstrm
877     pgstrm = g_string_new("");
878     g_string_printf(pgstrm, "q 1 0 0 -1 0 %.2f cm 1 J 1 j ", pg->height);
879     n_obj_bgpix = -1;
880     n_obj_prefix = -1;
881     if (pg->bg->type == BG_SOLID)
882       pdf_draw_solid_background(pg, pgstrm);
883     else if (pg->bg->type == BG_PDF && annot && 
884              pdfinfo.pages[pg->bg->file_page_seq-1].contents!=NULL) {
885       make_xref(&xref, xref.last+1, pdfbuf->len);
886       n_obj_prefix = xref.last;
887       tmpstr = make_pdfprefix(pdfinfo.pages+(pg->bg->file_page_seq-1),
888                               pg->width, pg->height);
889       g_string_append_printf(pdfbuf,
890         "%d 0 obj\n<< /Length %d >> stream\n%s\nendstream\nendobj\n",
891         n_obj_prefix, tmpstr->len, tmpstr->str);
892       g_string_free(tmpstr, TRUE);
893       g_string_prepend(pgstrm, "Q ");
894     }
895     else if (pg->bg->type == BG_PIXMAP || pg->bg->type == BG_PDF)
896       n_obj_bgpix = pdf_draw_bitmap_background(pg, pgstrm, &xref, pdfbuf);
897     // draw the page contents
898     use_hiliter = FALSE;
899     pdf_draw_page(pg, pgstrm, &use_hiliter);
900     g_string_append_printf(pgstrm, "Q\n");
901     
902     // deflate pgstrm and write it
903     zpgstrm = do_deflate(pgstrm->str, pgstrm->len);
904     g_string_free(pgstrm, TRUE);
905     
906     make_xref(&xref, xref.last+1, pdfbuf->len);
907     g_string_append_printf(pdfbuf, 
908       "%d 0 obj\n<< /Length %d /Filter /FlateDecode>> stream\n",
909       xref.last, zpgstrm->len);
910     g_string_append_len(pdfbuf, zpgstrm->str, zpgstrm->len);
911     g_string_free(zpgstrm, TRUE);
912     g_string_append(pdfbuf, "endstream\nendobj\n");
913     
914     // write the page object
915     
916     make_xref(&xref, n_obj_pages_offs+n_page, pdfbuf->len);
917     g_string_append_printf(pdfbuf, 
918       "%d 0 obj\n<< /Type /Page /Parent %d 0 R /MediaBox [0 0 %.2f %.2f] ",
919       n_obj_pages_offs+n_page, n_obj_catalog+1, pg->width, pg->height);
920     if (n_obj_prefix>0) {
921       obj = get_pdfobj(pdfbuf, &xref, pdfinfo.pages[pg->bg->file_page_seq-1].contents);
922       if (obj->type != PDFTYPE_ARRAY) {
923         free_pdfobj(obj);
924         obj = dup_pdfobj(pdfinfo.pages[pg->bg->file_page_seq-1].contents);
925       }
926       g_string_append_printf(pdfbuf, "/Contents [%d 0 R ", n_obj_prefix);
927       if (obj->type == PDFTYPE_REF) 
928         g_string_append_printf(pdfbuf, "%d %d R ", obj->intval, obj->num);
929       if (obj->type == PDFTYPE_ARRAY) {
930         for (i=0; i<obj->num; i++) {
931           show_pdfobj(obj->elts[i], pdfbuf);
932           g_string_append_c(pdfbuf, ' ');
933         }
934       }
935       free_pdfobj(obj);
936       g_string_append_printf(pdfbuf, "%d 0 R] ", xref.last);
937     }
938     else g_string_append_printf(pdfbuf, "/Contents %d 0 R ", xref.last);
939     g_string_append(pdfbuf, "/Resources ");
940
941     if (n_obj_prefix>0)
942       obj = dup_pdfobj(pdfinfo.pages[pg->bg->file_page_seq-1].resources);
943     else obj = NULL;
944     if (obj!=NULL && obj->type!=PDFTYPE_DICT)
945       { free_pdfobj(obj); obj=NULL; }
946     if (obj==NULL) {
947       obj = g_malloc(sizeof(struct PdfObj));
948       obj->type = PDFTYPE_DICT;
949       obj->num = 0;
950       obj->elts = NULL;
951       obj->names = NULL;
952     }
953     add_dict_subentry(pdfbuf, &xref,
954         obj, "/ProcSet", PDFTYPE_ARRAY, NULL, mk_pdfname("/PDF"));
955     if (n_obj_bgpix>0)
956       add_dict_subentry(pdfbuf, &xref,
957         obj, "/ProcSet", PDFTYPE_ARRAY, NULL, mk_pdfname("/ImageC"));
958     if (use_hiliter)
959       add_dict_subentry(pdfbuf, &xref,
960         obj, "/ExtGState", PDFTYPE_DICT, "/XoHi", mk_pdfref(n_obj_catalog+2));
961     if (n_obj_bgpix>0)
962       add_dict_subentry(pdfbuf, &xref,
963         obj, "/XObject", PDFTYPE_DICT, "/ImBg", mk_pdfref(n_obj_bgpix));
964     show_pdfobj(obj, pdfbuf);
965     free_pdfobj(obj);
966     g_string_append(pdfbuf, " >> endobj\n");
967   }
968   
969   // PDF trailer
970   startxref = pdfbuf->len;
971   if (annot) g_string_append_printf(pdfbuf,
972         "xref\n%d %d\n", n_obj_catalog, xref.last-n_obj_catalog+1);
973   else g_string_append_printf(pdfbuf, 
974         "xref\n0 %d\n0000000000 65535 f \n", xref.last+1);
975   for (i=n_obj_catalog; i<=xref.last; i++)
976     g_string_append_printf(pdfbuf, "%010d 00000 n \n", xref.data[i]);
977   g_string_append_printf(pdfbuf, 
978     "trailer\n<< /Size %d /Root %d 0 R ", xref.last+1, n_obj_catalog);
979   if (annot) {
980     g_string_append_printf(pdfbuf, "/Prev %d ", pdfinfo.startxref);
981     // keeping encryption info somehow doesn't work.
982     // xournal can't annotate encrypted PDFs anyway...
983 /*    
984     obj = get_dict_entry(pdfinfo.trailerdict, "/Encrypt");
985     if (obj!=NULL) {
986       g_string_append_printf(pdfbuf, "/Encrypt ");
987       show_pdfobj(obj, pdfbuf);
988     } 
989 */
990   }
991   g_string_append_printf(pdfbuf, 
992     ">>\nstartxref\n%d\n%%%%EOF\n", startxref);
993   
994   g_free(xref.data);
995   if (annot) {
996     free_pdfobj(pdfinfo.trailerdict);
997     if (pdfinfo.pages!=NULL)
998       for (i=0; i<pdfinfo.npages; i++) {
999         free_pdfobj(pdfinfo.pages[i].resources);
1000         free_pdfobj(pdfinfo.pages[i].mediabox);
1001         free_pdfobj(pdfinfo.pages[i].contents);
1002       }
1003   }
1004   
1005   setlocale(LC_NUMERIC, "");
1006   if (fwrite(pdfbuf->str, 1, pdfbuf->len, f) < pdfbuf->len) {
1007     fclose(f);
1008     g_string_free(pdfbuf, TRUE);
1009     return FALSE;
1010   }
1011   fclose(f);
1012   g_string_free(pdfbuf, TRUE);
1013   return TRUE;
1014 }
1015
1016 /*********** Printing via libgnomeprint **********/
1017
1018 // does the same job as update_canvas_bg(), but to a print context
1019
1020 void print_background(GnomePrintContext *gpc, struct Page *pg, gboolean *abort)
1021 {
1022   double x, y;
1023   GdkPixbuf *pix;
1024   BgPdfPage *pgpdf;
1025
1026   if (pg->bg->type == BG_SOLID) {
1027     gnome_print_setopacity(gpc, 1.0);
1028     gnome_print_setrgbcolor(gpc, RGBA_RGB(pg->bg->color_rgba));
1029     gnome_print_rect_filled(gpc, 0, 0, pg->width, pg->height);
1030
1031     if (pg->bg->ruling == RULING_NONE) return;
1032     gnome_print_setrgbcolor(gpc, RGBA_RGB(RULING_COLOR));
1033     gnome_print_setlinewidth(gpc, RULING_THICKNESS);
1034     
1035     if (pg->bg->ruling == RULING_GRAPH) {
1036       for (x=RULING_GRAPHSPACING; x<pg->width-1; x+=RULING_GRAPHSPACING)
1037         gnome_print_line_stroked(gpc, x, 0, x, pg->height);
1038       for (y=RULING_GRAPHSPACING; y<pg->height-1; y+=RULING_GRAPHSPACING)
1039         gnome_print_line_stroked(gpc, 0, y, pg->width, y);
1040       return;
1041     }
1042     
1043     for (y=RULING_TOPMARGIN; y<pg->height-1; y+=RULING_SPACING)
1044       gnome_print_line_stroked(gpc, 0, y, pg->width, y);
1045     if (pg->bg->ruling == RULING_LINED) {
1046       gnome_print_setrgbcolor(gpc, RGBA_RGB(RULING_MARGIN_COLOR));
1047       gnome_print_line_stroked(gpc, RULING_LEFTMARGIN, 0, RULING_LEFTMARGIN, pg->height);
1048     }
1049     return;
1050   }
1051   else if (pg->bg->type == BG_PIXMAP || pg->bg->type == BG_PDF) {
1052     if (pg->bg->type == BG_PDF) {
1053       pgpdf = (struct BgPdfPage *)g_list_nth_data(bgpdf.pages, pg->bg->file_page_seq-1);
1054       if (pgpdf == NULL) return;
1055       if (pgpdf->dpi != PDFTOPPM_PRINTING_DPI) {
1056         add_bgpdf_request(pg->bg->file_page_seq, 0, TRUE);
1057         while (pgpdf->dpi != PDFTOPPM_PRINTING_DPI && bgpdf.status == STATUS_RUNNING) {
1058           gtk_main_iteration();
1059           if (*abort) return;
1060         }
1061       }
1062       pix = pgpdf->pixbuf;
1063     }
1064     else pix = pg->bg->pixbuf;
1065     if (gdk_pixbuf_get_bits_per_sample(pix) != 8) return;
1066     if (gdk_pixbuf_get_colorspace(pix) != GDK_COLORSPACE_RGB) return;
1067     gnome_print_gsave(gpc);
1068     gnome_print_scale(gpc, pg->width, -pg->height);
1069     gnome_print_translate(gpc, 0., -1.);
1070     if (gdk_pixbuf_get_n_channels(pix) == 3)
1071        gnome_print_rgbimage(gpc, gdk_pixbuf_get_pixels(pix),
1072          gdk_pixbuf_get_width(pix), gdk_pixbuf_get_height(pix), gdk_pixbuf_get_rowstride(pix));
1073     else if (gdk_pixbuf_get_n_channels(pix) == 4)
1074        gnome_print_rgbaimage(gpc, gdk_pixbuf_get_pixels(pix),
1075          gdk_pixbuf_get_width(pix), gdk_pixbuf_get_height(pix), gdk_pixbuf_get_rowstride(pix));
1076     gnome_print_grestore(gpc);
1077     return;
1078   }
1079 }
1080
1081 void print_page(GnomePrintContext *gpc, struct Page *pg, int pageno,
1082                 double pgwidth, double pgheight, gboolean *abort)
1083 {
1084   char tmp[10];
1085   gdouble scale;
1086   guint old_rgba;
1087   double old_thickness;
1088   GList *layerlist, *itemlist;
1089   struct Layer *l;
1090   struct Item *item;
1091   int i;
1092   double *pt;
1093   
1094   if (pg==NULL) return;
1095   
1096   g_snprintf(tmp, 10, "Page %d", pageno);
1097   gnome_print_beginpage(gpc, (guchar *)tmp);
1098   gnome_print_gsave(gpc);
1099   
1100   scale = MIN(pgwidth/pg->width, pgheight/pg->height)*0.95;
1101   gnome_print_translate(gpc,
1102      (pgwidth - scale*pg->width)/2, (pgheight + scale*pg->height)/2);
1103   gnome_print_scale(gpc, scale, -scale);
1104   gnome_print_setlinejoin(gpc, 1); // round
1105   gnome_print_setlinecap(gpc, 1); // round
1106
1107   print_background(gpc, pg, abort);
1108
1109   old_rgba = 0x12345678;    // not any values we use, so we'll reset them
1110   old_thickness = 0.0;
1111
1112   for (layerlist = pg->layers; layerlist!=NULL; layerlist = layerlist->next) {
1113     if (*abort) break;
1114     l = (struct Layer *)layerlist->data;
1115     for (itemlist = l->items; itemlist!=NULL; itemlist = itemlist->next) {
1116       if (*abort) break;
1117       item = (struct Item *)itemlist->data;
1118       if (item->type == ITEM_STROKE) {
1119         if ((item->brush.color_rgba & ~0xff) != (old_rgba & ~0xff))
1120           gnome_print_setrgbcolor(gpc, RGBA_RGB(item->brush.color_rgba));
1121         if ((item->brush.color_rgba & 0xff) != (old_rgba & 0xff))
1122           gnome_print_setopacity(gpc, RGBA_ALPHA(item->brush.color_rgba));
1123         if (item->brush.thickness != old_thickness)
1124           gnome_print_setlinewidth(gpc, item->brush.thickness);
1125         old_rgba = item->brush.color_rgba;
1126         old_thickness = item->brush.thickness;
1127         gnome_print_newpath(gpc);
1128         pt = item->path->coords;
1129         gnome_print_moveto(gpc, pt[0], pt[1]);
1130         for (i=1, pt+=2; i<item->path->num_points; i++, pt+=2)
1131           gnome_print_lineto(gpc, pt[0], pt[1]);
1132         gnome_print_stroke(gpc);
1133       }
1134     }
1135   }
1136   
1137   gnome_print_grestore(gpc);
1138   gnome_print_showpage(gpc);
1139 }
1140
1141 void cb_print_abort(GtkDialog *dialog, gint response, gboolean *abort)
1142 {
1143   *abort = TRUE;
1144 }
1145
1146 void print_job_render(GnomePrintJob *gpj, int fromPage, int toPage)
1147 {
1148   GnomePrintConfig *config;
1149   GnomePrintContext *gpc;
1150   GtkWidget *wait_dialog;
1151   double pgwidth, pgheight;
1152   int i;
1153   gboolean abort;
1154   
1155   config = gnome_print_job_get_config(gpj);
1156   gnome_print_config_get_page_size(config, &pgwidth, &pgheight);
1157   g_object_unref(G_OBJECT(config));
1158
1159   gpc = gnome_print_job_get_context(gpj);
1160
1161   abort = FALSE;
1162   wait_dialog = gtk_message_dialog_new(GTK_WINDOW(winMain), GTK_DIALOG_MODAL,
1163      GTK_MESSAGE_INFO, GTK_BUTTONS_CANCEL, "Preparing print job");
1164   gtk_widget_show(wait_dialog);
1165   g_signal_connect(wait_dialog, "response", G_CALLBACK (cb_print_abort), &abort);
1166   
1167   for (i = fromPage; i <= toPage; i++) {
1168 #if GTK_CHECK_VERSION(2,6,0)
1169     if (!gtk_check_version(2, 6, 0))
1170       gtk_message_dialog_format_secondary_text(
1171              GTK_MESSAGE_DIALOG(wait_dialog), "Page %d", i+1); 
1172 #endif
1173     while (gtk_events_pending()) gtk_main_iteration();
1174     print_page(gpc, (struct Page *)g_list_nth_data(journal.pages, i), i+1,
1175                                              pgwidth, pgheight, &abort);
1176     if (abort) break;
1177   }
1178 #if GTK_CHECK_VERSION(2,6,0)
1179   if (!gtk_check_version(2, 6, 0))
1180     gtk_message_dialog_format_secondary_text(
1181               GTK_MESSAGE_DIALOG(wait_dialog), "Finalizing...");
1182 #endif
1183   while (gtk_events_pending()) gtk_main_iteration();
1184
1185   gnome_print_context_close(gpc);  
1186   g_object_unref(G_OBJECT(gpc));  
1187
1188   gnome_print_job_close(gpj);
1189   if (!abort) gnome_print_job_print(gpj);
1190   g_object_unref(G_OBJECT(gpj));
1191
1192   gtk_widget_destroy(wait_dialog);
1193 }