5 #define PANGO_ENABLE_BACKEND /* to access PangoFcFont.font_pattern */
8 #include <libgnomecanvas/libgnomecanvas.h>
9 #include <libgnomeprint/gnome-print-job.h>
10 #include <libgnomeprint/gnome-print-pango.h>
14 #include <pango/pango.h>
15 #include <pango/pangofc-font.h>
16 #include <fontconfig/fontconfig.h>
18 #include FT_FREETYPE_H
19 #include "sft.h" /* Sun Font Tools, embedded in libgnomeprint */
22 #include "xo-support.h"
28 #define RGBA_RED(rgba) (((rgba>>24)&0xff)/255.0)
29 #define RGBA_GREEN(rgba) (((rgba>>16)&0xff)/255.0)
30 #define RGBA_BLUE(rgba) (((rgba>>8)&0xff)/255.0)
31 #define RGBA_ALPHA(rgba) (((rgba>>0)&0xff)/255.0)
32 #define RGBA_RGB(rgba) RGBA_RED(rgba), RGBA_GREEN(rgba), RGBA_BLUE(rgba)
34 /*********** Printing to PDF ************/
36 gboolean
ispdfspace(char c
)
38 return (c
==0 || c
==9 || c
==10 || c
==12 || c
==13 || c
==' ');
41 gboolean
ispdfdelim(char c
)
43 return (c
=='(' || c
==')' || c
=='<' || c
=='>' || c
=='[' || c
==']' ||
44 c
=='{' || c
=='}' || c
=='/' || c
=='%');
47 void skipspace(char **p
, char *eof
)
49 while (ispdfspace(**p
) || **p
=='%') {
50 if (**p
=='%') while (*p
!=eof
&& **p
!=10 && **p
!=13) (*p
)++;
56 void free_pdfobj(struct PdfObj
*obj
)
60 if (obj
==NULL
) return;
61 if ((obj
->type
== PDFTYPE_STRING
|| obj
->type
== PDFTYPE_NAME
||
62 obj
->type
== PDFTYPE_STREAM
) && obj
->str
!=NULL
)
64 if ((obj
->type
== PDFTYPE_ARRAY
|| obj
->type
== PDFTYPE_DICT
||
65 obj
->type
== PDFTYPE_STREAM
) && obj
->num
>0) {
66 for (i
=0; i
<obj
->num
; i
++)
67 free_pdfobj(obj
->elts
[i
]);
70 if ((obj
->type
== PDFTYPE_DICT
|| obj
->type
== PDFTYPE_STREAM
) && obj
->num
>0) {
71 for (i
=0; i
<obj
->num
; i
++)
72 g_free(obj
->names
[i
]);
78 struct PdfObj
*dup_pdfobj(struct PdfObj
*obj
)
83 if (obj
==NULL
) return NULL
;
84 dup
= g_memdup(obj
, sizeof(struct PdfObj
));
85 if ((obj
->type
== PDFTYPE_STRING
|| obj
->type
== PDFTYPE_NAME
||
86 obj
->type
== PDFTYPE_STREAM
) && obj
->str
!=NULL
) {
87 if (obj
->type
== PDFTYPE_NAME
) obj
->len
= strlen(obj
->str
);
88 dup
->str
= g_memdup(obj
->str
, obj
->len
+1);
90 if ((obj
->type
== PDFTYPE_ARRAY
|| obj
->type
== PDFTYPE_DICT
||
91 obj
->type
== PDFTYPE_STREAM
) && obj
->num
>0) {
92 dup
->elts
= g_malloc(obj
->num
*sizeof(struct PdfObj
*));
93 for (i
=0; i
<obj
->num
; i
++)
94 dup
->elts
[i
] = dup_pdfobj(obj
->elts
[i
]);
96 if ((obj
->type
== PDFTYPE_DICT
|| obj
->type
== PDFTYPE_STREAM
) && obj
->num
>0) {
97 dup
->names
= g_malloc(obj
->num
*sizeof(char *));
98 for (i
=0; i
<obj
->num
; i
++)
99 dup
->names
[i
] = g_strdup(obj
->names
[i
]);
104 void show_pdfobj(struct PdfObj
*obj
, GString
*str
)
107 if (obj
==NULL
) return;
110 if (obj
->intval
==1) g_string_append(str
, "true");
111 if (obj
->intval
==0) g_string_append(str
, "false");
112 if (obj
->intval
==-1) g_string_append(str
, "null");
115 g_string_append_printf(str
, "%d", obj
->intval
);
118 g_string_append_printf(str
, "%f", obj
->realval
);
121 g_string_append_len(str
, obj
->str
, obj
->len
);
124 g_string_append(str
, obj
->str
);
127 g_string_append_c(str
, '[');
128 for (i
=0;i
<obj
->num
;i
++) {
129 if (i
) g_string_append_c(str
, ' ');
130 show_pdfobj(obj
->elts
[i
], str
);
132 g_string_append_c(str
, ']');
135 g_string_append(str
, "<<");
136 for (i
=0;i
<obj
->num
;i
++) {
137 g_string_append_printf(str
, " %s ", obj
->names
[i
]);
138 show_pdfobj(obj
->elts
[i
], str
);
140 g_string_append(str
, " >>");
143 g_string_append_printf(str
, "%d %d R", obj
->intval
, obj
->num
);
148 void DEBUG_PRINTOBJ(struct PdfObj
*obj
)
150 GString
*s
= g_string_new("");
153 g_string_free(s
, TRUE
);
156 // parse a PDF object; returns NULL if fails
157 // THIS PARSER DOES NOT RECOGNIZE STREAMS YET
159 struct PdfObj
*parse_pdf_object(char **ptr
, char *eof
)
161 struct PdfObj
*obj
, *elt
;
162 char *p
, *q
, *r
, *eltname
;
165 obj
= g_malloc(sizeof(struct PdfObj
));
168 if (p
==eof
) { g_free(obj
); return NULL
; }
171 if (!strncmp(p
, "true", 4)) {
172 obj
->type
= PDFTYPE_CST
;
177 if (!strncmp(p
, "false", 5)) {
178 obj
->type
= PDFTYPE_CST
;
183 if (!strncmp(p
, "null", 4)) {
184 obj
->type
= PDFTYPE_CST
;
191 obj
->intval
= strtol(p
, &q
, 10);
195 obj
->type
= PDFTYPE_REAL
;
196 obj
->realval
= g_ascii_strtod(p
, ptr
);
199 if (ispdfspace(*q
)) {
200 // check for indirect reference
202 obj
->num
= strtol(q
, &r
, 10);
207 obj
->type
= PDFTYPE_REF
;
212 obj
->type
= PDFTYPE_INT
;
219 while (stack
>0 && q
!=eof
) {
220 if (*q
=='(') stack
++;
221 if (*q
==')') stack
--;
225 if (q
==eof
) { g_free(obj
); return NULL
; }
226 obj
->type
= PDFTYPE_STRING
;
228 obj
->str
= g_malloc(obj
->len
+1);
229 obj
->str
[obj
->len
] = 0;
230 g_memmove(obj
->str
, p
, obj
->len
);
234 if (*p
=='<' && p
[1]!='<') {
236 while (*q
!='>' && q
!=eof
) q
++;
237 if (q
==eof
) { g_free(obj
); return NULL
; }
239 obj
->type
= PDFTYPE_STRING
;
241 obj
->str
= g_malloc(obj
->len
+1);
242 obj
->str
[obj
->len
] = 0;
243 g_memmove(obj
->str
, p
, obj
->len
);
251 while (!ispdfspace(*q
) && !ispdfdelim(*q
)) q
++;
252 obj
->type
= PDFTYPE_NAME
;
253 obj
->str
= g_strndup(p
, q
-p
);
260 obj
->type
= PDFTYPE_ARRAY
;
263 q
=p
+1; skipspace(&q
, eof
);
265 elt
= parse_pdf_object(&q
, eof
);
266 if (elt
==NULL
) { free_pdfobj(obj
); return NULL
; }
268 obj
->elts
= g_realloc(obj
->elts
, obj
->num
*sizeof(struct PdfObj
*));
269 obj
->elts
[obj
->num
-1] = elt
;
277 if (*p
=='<' && p
[1]=='<') {
278 obj
->type
= PDFTYPE_DICT
;
282 q
=p
+2; skipspace(&q
, eof
);
283 while (*q
!='>' || q
[1]!='>') {
284 if (*q
!='/') { free_pdfobj(obj
); return NULL
; }
286 while (!ispdfspace(*r
) && !ispdfdelim(*r
)) r
++;
287 eltname
= g_strndup(q
, r
-q
);
288 q
=r
; skipspace(&q
, eof
);
289 elt
= parse_pdf_object(&q
, eof
);
290 if (elt
==NULL
) { g_free(eltname
); free_pdfobj(obj
); return NULL
; }
292 obj
->elts
= g_realloc(obj
->elts
, obj
->num
*sizeof(struct PdfObj
*));
293 obj
->names
= g_realloc(obj
->names
, obj
->num
*sizeof(char *));
294 obj
->elts
[obj
->num
-1] = elt
;
295 obj
->names
[obj
->num
-1] = eltname
;
302 // DOES NOT RECOGNIZE STREAMS YET (handle as subcase of dictionary)
308 struct PdfObj
*get_dict_entry(struct PdfObj
*dict
, char *name
)
312 if (dict
==NULL
) return NULL
;
313 if (dict
->type
!= PDFTYPE_DICT
) return NULL
;
314 for (i
=0; i
<dict
->num
; i
++)
315 if (!strcmp(dict
->names
[i
], name
)) return dict
->elts
[i
];
319 struct PdfObj
*get_pdfobj(GString
*pdfbuf
, struct XrefTable
*xref
, struct PdfObj
*obj
)
324 if (obj
==NULL
) return NULL
;
325 if (obj
->type
!=PDFTYPE_REF
) return dup_pdfobj(obj
);
326 if (obj
->intval
>xref
->last
) return NULL
;
327 offs
= xref
->data
[obj
->intval
];
328 if (offs
<=0 || offs
>= pdfbuf
->len
) return NULL
;
330 p
= pdfbuf
->str
+ offs
;
331 eof
= pdfbuf
->str
+ pdfbuf
->len
;
332 n
= strtol(p
, &p
, 10);
333 if (n
!=obj
->intval
) return NULL
;
335 n
= strtol(p
, &p
, 10);
337 if (strncmp(p
, "obj", 3)) return NULL
;
339 return parse_pdf_object(&p
, eof
);
342 // read the xref table of a PDF file in memory, and return the trailerdict
344 struct PdfObj
*parse_xref_table(GString
*pdfbuf
, struct XrefTable
*xref
, int offs
)
347 struct PdfObj
*trailerdict
, *obj
;
350 if (strncmp(pdfbuf
->str
+offs
, "xref", 4)) return NULL
;
351 p
= strstr(pdfbuf
->str
+offs
, "trailer");
352 eof
= pdfbuf
->str
+ pdfbuf
->len
;
353 if (p
==NULL
) return NULL
;
355 trailerdict
= parse_pdf_object(&p
, eof
);
356 obj
= get_dict_entry(trailerdict
, "/Size");
357 if (obj
!=NULL
&& obj
->type
== PDFTYPE_INT
&& obj
->intval
-1>xref
->last
)
358 make_xref(xref
, obj
->intval
-1, 0);
359 obj
= get_dict_entry(trailerdict
, "/Prev");
360 if (obj
!=NULL
&& obj
->type
== PDFTYPE_INT
&& obj
->intval
>0 && obj
->intval
!=offs
) {
361 // recurse into older xref table
362 obj
= parse_xref_table(pdfbuf
, xref
, obj
->intval
);
365 p
= pdfbuf
->str
+offs
+4;
367 if (*p
<'0' || *p
>'9') { free_pdfobj(trailerdict
); return NULL
; }
368 while (*p
>='0' && *p
<='9') {
369 start
= strtol(p
, &p
, 10);
371 len
= strtol(p
, &p
, 10);
373 if (len
<= 0 || 20*len
> eof
-p
) break;
374 if (start
+len
-1 > xref
->last
) make_xref(xref
, start
+len
-1, 0);
375 for (i
=start
; i
<start
+len
; i
++) {
376 xref
->data
[i
] = strtol(p
, NULL
, 10);
381 if (*p
!='t') { free_pdfobj(trailerdict
); return NULL
; }
385 // parse the page tree
387 int pdf_getpageinfo(GString
*pdfbuf
, struct XrefTable
*xref
,
388 struct PdfObj
*pgtree
, int nmax
, struct PdfPageDesc
*pages
)
390 struct PdfObj
*obj
, *kid
;
393 obj
= get_pdfobj(pdfbuf
, xref
, get_dict_entry(pgtree
, "/Type"));
394 if (obj
== NULL
|| obj
->type
!= PDFTYPE_NAME
)
396 if (!strcmp(obj
->str
, "/Page")) {
398 pages
->contents
= dup_pdfobj(get_dict_entry(pgtree
, "/Contents"));
399 obj
= get_pdfobj(pdfbuf
, xref
, get_dict_entry(pgtree
, "/Resources"));
401 free_pdfobj(pages
->resources
);
402 pages
->resources
= obj
;
404 obj
= get_pdfobj(pdfbuf
, xref
, get_dict_entry(pgtree
, "/MediaBox"));
406 free_pdfobj(pages
->mediabox
);
407 pages
->mediabox
= obj
;
409 obj
= get_pdfobj(pdfbuf
, xref
, get_dict_entry(pgtree
, "/Rotate"));
410 if (obj
!=NULL
&& obj
->type
== PDFTYPE_INT
)
411 pages
->rotate
= obj
->intval
;
415 else if (!strcmp(obj
->str
, "/Pages")) {
417 obj
= get_pdfobj(pdfbuf
, xref
, get_dict_entry(pgtree
, "/Count"));
418 if (obj
!=NULL
&& obj
->type
== PDFTYPE_INT
&&
419 obj
->intval
>0 && obj
->intval
<=nmax
) count
= obj
->intval
;
422 obj
= get_pdfobj(pdfbuf
, xref
, get_dict_entry(pgtree
, "/Resources"));
424 for (i
=0; i
<count
; i
++) {
425 free_pdfobj(pages
[i
].resources
);
426 pages
[i
].resources
= dup_pdfobj(obj
);
429 obj
= get_pdfobj(pdfbuf
, xref
, get_dict_entry(pgtree
, "/MediaBox"));
431 for (i
=0; i
<count
; i
++) {
432 free_pdfobj(pages
[i
].mediabox
);
433 pages
[i
].mediabox
= dup_pdfobj(obj
);
436 obj
= get_pdfobj(pdfbuf
, xref
, get_dict_entry(pgtree
, "/Rotate"));
437 if (obj
!=NULL
&& obj
->type
== PDFTYPE_INT
)
438 for (i
=0; i
<count
; i
++)
439 pages
[i
].rotate
= obj
->intval
;
441 obj
= get_pdfobj(pdfbuf
, xref
, get_dict_entry(pgtree
, "/Kids"));
442 if (obj
!=NULL
&& obj
->type
== PDFTYPE_ARRAY
) {
443 for (i
=0; i
<obj
->num
; i
++) {
444 kid
= get_pdfobj(pdfbuf
, xref
, obj
->elts
[i
]);
446 j
= pdf_getpageinfo(pdfbuf
, xref
, kid
, nmax
, pages
);
459 // parse a PDF file in memory
461 gboolean
pdf_parse_info(GString
*pdfbuf
, struct PdfInfo
*pdfinfo
, struct XrefTable
*xref
)
465 struct PdfObj
*obj
, *pages
;
467 xref
->n_alloc
= xref
->last
= 0;
469 p
= pdfbuf
->str
+ pdfbuf
->len
-1;
471 while (*p
!='s' && p
!=pdfbuf
->str
) p
--;
472 if (strncmp(p
, "startxref", 9)) return FALSE
; // fail
474 while (ispdfspace(*p
) && p
!=pdfbuf
->str
+pdfbuf
->len
) p
++;
475 offs
= strtol(p
, NULL
, 10);
476 if (offs
<= 0 || offs
> pdfbuf
->len
) return FALSE
; // fail
477 pdfinfo
->startxref
= offs
;
479 pdfinfo
->trailerdict
= parse_xref_table(pdfbuf
, xref
, offs
);
480 if (pdfinfo
->trailerdict
== NULL
) return FALSE
; // fail
482 obj
= get_pdfobj(pdfbuf
, xref
,
483 get_dict_entry(pdfinfo
->trailerdict
, "/Root"));
485 { free_pdfobj(pdfinfo
->trailerdict
); return FALSE
; }
486 pages
= get_pdfobj(pdfbuf
, xref
, get_dict_entry(obj
, "/Pages"));
489 { free_pdfobj(pdfinfo
->trailerdict
); return FALSE
; }
490 obj
= get_pdfobj(pdfbuf
, xref
, get_dict_entry(pages
, "/Count"));
491 if (obj
== NULL
|| obj
->type
!= PDFTYPE_INT
|| obj
->intval
<=0)
492 { free_pdfobj(pdfinfo
->trailerdict
); free_pdfobj(pages
);
493 free_pdfobj(obj
); return FALSE
; }
494 pdfinfo
->npages
= obj
->intval
;
497 pdfinfo
->pages
= g_malloc0(pdfinfo
->npages
*sizeof(struct PdfPageDesc
));
498 pdf_getpageinfo(pdfbuf
, xref
, pages
, pdfinfo
->npages
, pdfinfo
->pages
);
504 // add an entry to the xref table
506 void make_xref(struct XrefTable
*xref
, int nobj
, int offset
)
508 if (xref
->n_alloc
<= nobj
) {
509 xref
->n_alloc
= nobj
+ 10;
510 xref
->data
= g_realloc(xref
->data
, xref
->n_alloc
*sizeof(int));
512 if (xref
->last
< nobj
) xref
->last
= nobj
;
513 xref
->data
[nobj
] = offset
;
516 // a wrapper for deflate
518 GString
*do_deflate(char *in
, int len
)
525 deflateInit(&zs
, Z_DEFAULT_COMPRESSION
);
526 zs
.next_in
= (Bytef
*)in
;
528 zs
.avail_out
= deflateBound(&zs
, len
);
529 out
= g_string_sized_new(zs
.avail_out
);
530 zs
.next_out
= (Bytef
*)out
->str
;
531 deflate(&zs
, Z_FINISH
);
532 out
->len
= zs
.total_out
;
537 // prefix to scale the original page
539 GString
*make_pdfprefix(struct PdfPageDesc
*pgdesc
, double width
, double height
)
542 double v
[4], t
, xscl
, yscl
;
545 // push 3 times in case code to be annotated has unbalanced q/Q (B of A., ...)
546 str
= g_string_new("q q q ");
547 if (pgdesc
->rotate
== 90) {
548 g_string_append_printf(str
, "0 -1 1 0 0 %.2f cm ", height
);
549 t
= height
; height
= width
; width
= t
;
551 if (pgdesc
->rotate
== 270) {
552 g_string_append_printf(str
, "0 1 -1 0 %.2f 0 cm ", width
);
553 t
= height
; height
= width
; width
= t
;
555 if (pgdesc
->rotate
== 180) {
556 g_string_append_printf(str
, "-1 0 0 -1 %.2f %.2f cm ", width
, height
);
558 if (pgdesc
->mediabox
==NULL
|| pgdesc
->mediabox
->type
!= PDFTYPE_ARRAY
||
559 pgdesc
->mediabox
->num
!= 4) return str
;
560 for (i
=0; i
<4; i
++) {
561 if (pgdesc
->mediabox
->elts
[i
]->type
== PDFTYPE_INT
)
562 v
[i
] = pgdesc
->mediabox
->elts
[i
]->intval
;
563 else if (pgdesc
->mediabox
->elts
[i
]->type
== PDFTYPE_REAL
)
564 v
[i
] = pgdesc
->mediabox
->elts
[i
]->realval
;
567 if (v
[0]>v
[2]) { t
= v
[0]; v
[0] = v
[2]; v
[2] = t
; }
568 if (v
[1]>v
[3]) { t
= v
[1]; v
[1] = v
[3]; v
[3] = t
; }
569 if (v
[2]-v
[0] < 1. || v
[3]-v
[1] < 1.) return str
;
570 xscl
= width
/(v
[2]-v
[0]);
571 yscl
= height
/(v
[3]-v
[1]);
572 g_string_append_printf(str
, "%.4f 0 0 %.4f %.2f %.2f cm ",
573 xscl
, yscl
, -v
[0]*xscl
, -v
[1]*yscl
);
577 // add an entry to a subentry of a directory
579 struct PdfObj
*mk_pdfname(char *name
)
583 obj
= g_malloc(sizeof(struct PdfObj
));
584 obj
->type
= PDFTYPE_NAME
;
585 obj
->str
= g_strdup(name
);
589 struct PdfObj
*mk_pdfref(int num
)
593 obj
= g_malloc(sizeof(struct PdfObj
));
594 obj
->type
= PDFTYPE_REF
;
600 gboolean
iseq_obj(struct PdfObj
*a
, struct PdfObj
*b
)
602 if (a
==NULL
|| b
==NULL
) return (a
==b
);
603 if (a
->type
!=b
->type
) return FALSE
;
604 if (a
->type
== PDFTYPE_CST
|| a
->type
== PDFTYPE_INT
)
605 return (a
->intval
== b
->intval
);
606 if (a
->type
== PDFTYPE_REAL
)
607 return (a
->realval
== b
->realval
);
608 if (a
->type
== PDFTYPE_NAME
)
609 return !strcmp(a
->str
, b
->str
);
610 if (a
->type
== PDFTYPE_REF
)
611 return (a
->intval
== b
->intval
&& a
->num
== b
->num
);
615 void add_dict_subentry(GString
*pdfbuf
, struct XrefTable
*xref
,
616 struct PdfObj
*obj
, char *section
, int type
, char *name
, struct PdfObj
*entry
)
622 for (i
=0; i
<obj
->num
; i
++)
623 if (!strcmp(obj
->names
[i
], section
)) subpos
= i
;
627 obj
->elts
= g_realloc(obj
->elts
, obj
->num
*sizeof(struct PdfObj
*));
628 obj
->names
= g_realloc(obj
->names
, obj
->num
*sizeof(char *));
629 obj
->names
[subpos
] = g_strdup(section
);
630 obj
->elts
[subpos
] = NULL
;
632 if (obj
->elts
[subpos
]!=NULL
&& obj
->elts
[subpos
]->type
==PDFTYPE_REF
) {
633 sec
= get_pdfobj(pdfbuf
, xref
, obj
->elts
[subpos
]);
634 free_pdfobj(obj
->elts
[subpos
]);
635 obj
->elts
[subpos
] = sec
;
637 if (obj
->elts
[subpos
]!=NULL
&& obj
->elts
[subpos
]->type
!=type
)
638 { free_pdfobj(obj
->elts
[subpos
]); obj
->elts
[subpos
] = NULL
; }
639 if (obj
->elts
[subpos
] == NULL
) {
640 obj
->elts
[subpos
] = sec
= g_malloc(sizeof(struct PdfObj
));
646 sec
= obj
->elts
[subpos
];
649 if (type
==PDFTYPE_DICT
) {
650 for (i
=0; i
<sec
->num
; i
++)
651 if (!strcmp(sec
->names
[i
], name
)) subpos
= i
;
655 sec
->elts
= g_realloc(sec
->elts
, sec
->num
*sizeof(struct PdfObj
*));
656 sec
->names
= g_realloc(sec
->names
, sec
->num
*sizeof(char *));
657 sec
->names
[subpos
] = g_strdup(name
);
658 sec
->elts
[subpos
] = NULL
;
660 free_pdfobj(sec
->elts
[subpos
]);
661 sec
->elts
[subpos
] = entry
;
663 if (type
==PDFTYPE_ARRAY
) {
664 for (i
=0; i
<sec
->num
; i
++)
665 if (iseq_obj(sec
->elts
[i
], entry
)) subpos
= i
;
669 sec
->elts
= g_realloc(sec
->elts
, sec
->num
*sizeof(struct PdfObj
*));
670 sec
->elts
[subpos
] = entry
;
672 else free_pdfobj(entry
);
676 // draw a page's background
678 void pdf_draw_solid_background(struct Page
*pg
, GString
*str
)
682 g_string_append_printf(str
,
683 "%.2f %.2f %.2f rg 0 0 %.2f %.2f re f ",
684 RGBA_RGB(pg
->bg
->color_rgba
), pg
->width
, pg
->height
);
685 if (!ui
.print_ruling
) return;
686 if (pg
->bg
->ruling
== RULING_NONE
) return;
687 g_string_append_printf(str
,
688 "%.2f %.2f %.2f RG %.2f w ",
689 RGBA_RGB(RULING_COLOR
), RULING_THICKNESS
);
690 if (pg
->bg
->ruling
== RULING_GRAPH
) {
691 for (x
=RULING_GRAPHSPACING
; x
<pg
->width
-1; x
+=RULING_GRAPHSPACING
)
692 g_string_append_printf(str
, "%.2f 0 m %.2f %.2f l S ",
694 for (y
=RULING_GRAPHSPACING
; y
<pg
->height
-1; y
+=RULING_GRAPHSPACING
)
695 g_string_append_printf(str
, "0 %.2f m %.2f %.2f l S ",
699 for (y
=RULING_TOPMARGIN
; y
<pg
->height
-1; y
+=RULING_SPACING
)
700 g_string_append_printf(str
, "0 %.2f m %.2f %.2f l S ",
702 if (pg
->bg
->ruling
== RULING_LINED
)
703 g_string_append_printf(str
,
704 "%.2f %.2f %.2f RG %.2f 0 m %.2f %.2f l S ",
705 RGBA_RGB(RULING_MARGIN_COLOR
),
706 RULING_LEFTMARGIN
, RULING_LEFTMARGIN
, pg
->height
);
709 int pdf_draw_bitmap_background(struct Page
*pg
, GString
*str
,
710 struct XrefTable
*xref
, GString
*pdfbuf
)
715 PopplerPage
*pdfpage
;
717 int height
, width
, stride
, x
, y
, chan
;
718 double pgheight
, pgwidth
;
720 if (pg
->bg
->type
== BG_PDF
) {
721 if (!bgpdf
.document
) return -1;
722 pdfpage
= poppler_document_get_page(bgpdf
.document
, pg
->bg
->file_page_seq
-1);
723 if (!pdfpage
) return -1;
724 poppler_page_get_size(pdfpage
, &pgwidth
, &pgheight
);
725 width
= (int) (PDFTOPPM_PRINTING_DPI
* pgwidth
/72.0);
726 height
= (int) (PDFTOPPM_PRINTING_DPI
* pgheight
/72.0);
727 pix
= gdk_pixbuf_new(GDK_COLORSPACE_RGB
, FALSE
, 8, width
, height
);
728 poppler_page_render_to_pixbuf(
729 pdfpage
, 0, 0, width
, height
, PDFTOPPM_PRINTING_DPI
/72.0, 0, pix
);
730 g_object_unref(pdfpage
);
732 else pix
= g_object_ref(pg
->bg
->pixbuf
);
734 if (gdk_pixbuf_get_bits_per_sample(pix
) != 8 ||
735 gdk_pixbuf_get_colorspace(pix
) != GDK_COLORSPACE_RGB
)
736 { g_object_unref(pix
); return -1; }
738 width
= gdk_pixbuf_get_width(pix
);
739 height
= gdk_pixbuf_get_height(pix
);
740 stride
= gdk_pixbuf_get_rowstride(pix
);
741 chan
= gdk_pixbuf_get_n_channels(pix
);
742 if (chan
!=3 && chan
!=4) { g_object_unref(pix
); return -1; }
744 g_string_append_printf(str
, "q %.2f 0 0 %.2f 0 %.2f cm /ImBg Do Q ",
745 pg
->width
, -pg
->height
, pg
->height
);
747 p2
= buf
= (char *)g_malloc(3*width
*height
);
748 for (y
=0; y
<height
; y
++) {
749 p1
= (char *)gdk_pixbuf_get_pixels(pix
)+stride
*y
;
750 for (x
=0; x
<width
; x
++) {
751 *(p2
++)=*(p1
++); *(p2
++)=*(p1
++); *(p2
++)=*(p1
++);
755 zpix
= do_deflate(buf
, 3*width
*height
);
759 make_xref(xref
, xref
->last
+1, pdfbuf
->len
);
760 g_string_append_printf(pdfbuf
,
761 "%d 0 obj\n<< /Length %d /Filter /FlateDecode /Type /Xobject "
762 "/Subtype /Image /Width %d /Height %d /ColorSpace /DeviceRGB "
763 "/BitsPerComponent 8 >> stream\n",
764 xref
->last
, zpix
->len
, width
, height
);
765 g_string_append_len(pdfbuf
, zpix
->str
, zpix
->len
);
766 g_string_free(zpix
, TRUE
);
767 g_string_append(pdfbuf
, "endstream\nendobj\n");
772 // manipulate Pdf fonts
774 struct PdfFont
*new_pdffont(struct XrefTable
*xref
, GList
**fonts
,
775 char *filename
, int font_id
, FT_Face face
, int glyph_page
)
778 struct PdfFont
*font
;
782 for (list
= *fonts
; list
!=NULL
; list
= list
->next
) {
783 font
= (struct PdfFont
*)list
->data
;
784 if (!strcmp(font
->filename
, filename
) && font
->font_id
== font_id
785 && font
->glyph_page
== glyph_page
)
786 { font
->used_in_this_page
= TRUE
; return font
; }
788 font
= g_malloc(sizeof(struct PdfFont
));
789 *fonts
= g_list_append(*fonts
, font
);
790 font
->n_obj
= xref
->last
+1;
791 make_xref(xref
, xref
->last
+1, 0); // will give it a value later
792 font
->filename
= g_strdup(filename
);
793 font
->font_id
= font_id
;
794 font
->glyph_page
= glyph_page
;
795 font
->used_in_this_page
= TRUE
;
796 font
->num_glyphs_used
= 0;
797 for (i
=0; i
<256; i
++) {
798 font
->glyphmap
[i
] = -1;
799 font
->advance
[i
] = 0;
800 font
->glyphpsnames
[i
] = NULL
;
802 font
->glyphmap
[0] = 0;
803 // fill in info from the FT_Face
804 font
->is_truetype
= FT_IS_SFNT(face
);
805 font
->nglyphs
= face
->num_glyphs
;
806 font
->ft2ps
= 1000.0 / face
->units_per_EM
;
807 font
->ascender
= (int)(font
->ft2ps
*face
->ascender
);
808 font
->descender
= (int)(font
->ft2ps
*face
->descender
);
809 if (face
->bbox
.xMin
< -100000 || face
->bbox
.xMin
> 100000) font
->xmin
= 0;
810 else font
->xmin
= (int)(font
->ft2ps
*face
->bbox
.xMin
);
811 if (face
->bbox
.xMax
< -100000 || face
->bbox
.xMax
> 100000) font
->xmax
= 0;
812 else font
->xmax
= (int)(font
->ft2ps
*face
->bbox
.xMax
);
813 if (face
->bbox
.yMin
< -100000 || face
->bbox
.yMin
> 100000) font
->ymin
= 0;
814 else font
->ymin
= (int)(font
->ft2ps
*face
->bbox
.yMin
);
815 if (face
->bbox
.yMax
< -100000 || face
->bbox
.yMax
> 100000) font
->ymax
= 0;
816 else font
->ymax
= (int)(font
->ft2ps
*face
->bbox
.yMax
);
817 if (font
->is_truetype
) font
->flags
= 4; // symbolic
819 font
->flags
= 4; // symbolic
820 if (FT_IS_FIXED_WIDTH(face
)) font
->flags
|= 1;
821 if (face
->style_flags
& FT_STYLE_FLAG_ITALIC
) font
->flags
|= 64;
823 s
= FT_Get_Postscript_Name(face
);
824 if (s
==NULL
) s
= "Noname";
825 if (glyph_page
) font
->fontname
= g_strdup_printf("%s_%03d", s
, glyph_page
);
826 else font
->fontname
= g_strdup(s
);
830 #define pfb_get_length(x) (((x)[3]<<24) + ((x)[2]<<16) + ((x)[1]<<8) + (x)[0])
831 #define T1_SEGMENT_1_END "currentfile eexec"
832 #define T1_SEGMENT_3_END "cleartomark"
834 void embed_pdffont(GString
*pdfbuf
, struct XrefTable
*xref
, struct PdfFont
*font
)
836 // this code inspired by libgnomeprint
837 gboolean fallback
, is_binary
;
838 guchar encoding
[256];
840 int i
, j
, num
, len1
, len2
;
843 char *tmpfile
, *seg1
, *seg2
;
846 int nobj_fontprog
, nobj_descr
, lastchar
;
849 // embed the font file: TrueType case
850 if (font
->is_truetype
) {
851 glyphs
[0] = encoding
[0] = 0;
853 for (i
=1; i
<=255; i
++)
854 if (font
->glyphmap
[i
]>=0) {
855 font
->glyphmap
[i
] = num
;
856 glyphs
[num
] = 255*font
->glyph_page
+i
-1;
860 font
->num_glyphs_used
= num
-1;
861 if (OpenTTFont(font
->filename
, 0, &ttfnt
) == SF_OK
) {
862 tmpfile
= mktemp(g_strdup(TMPDIR_TEMPLATE
));
863 CreateTTFromTTGlyphs(ttfnt
, tmpfile
, glyphs
, encoding
, num
,
864 0, NULL
, TTCF_AutoName
| TTCF_IncludeOS2
);
866 if (g_file_get_contents(tmpfile
, &fontdata
, &len
, NULL
) && len
>=8) {
867 make_xref(xref
, xref
->last
+1, pdfbuf
->len
);
868 nobj_fontprog
= xref
->last
;
869 g_string_append_printf(pdfbuf
,
870 "%d 0 obj\n<< /Length %d /Length1 %d >> stream\n",
871 nobj_fontprog
, (int)len
, (int)len
);
872 g_string_append_len(pdfbuf
, fontdata
, len
);
873 g_string_append(pdfbuf
, "endstream\nendobj\n");
876 else fallback
= TRUE
;
880 else fallback
= TRUE
;
882 // embed the font file: Type1 case
883 if (g_file_get_contents(font
->filename
, &fontdata
, &len
, NULL
) && len
>=8) {
884 if (fontdata
[0]==(char)0x80 && fontdata
[1]==(char)0x01) {
886 len1
= pfb_get_length((unsigned char *)fontdata
+2);
887 if (fontdata
[len1
+6]!=(char)0x80 || fontdata
[len1
+7]!=(char)0x02) fallback
= TRUE
;
889 len2
= pfb_get_length((unsigned char *)fontdata
+len1
+8);
890 if (fontdata
[len1
+len2
+12]!=(char)0x80 || fontdata
[len1
+len2
+13]!=(char)0x01)
894 else if (!strncmp(fontdata
, "%!PS", 4)) {
896 p
= strstr(fontdata
, T1_SEGMENT_1_END
) + strlen(T1_SEGMENT_1_END
);
897 if (p
==NULL
) fallback
= TRUE
;
899 if (*p
=='\n' || *p
=='\r') p
++;
900 if (*p
=='\n' || *p
=='\r') p
++;
902 p
= g_strrstr_len(fontdata
, len
, T1_SEGMENT_3_END
);
903 if (p
==NULL
) fallback
= TRUE
;
907 while (i
>0 && p
!=fontdata
&& (*p
=='0' || *p
=='\r' || *p
=='\n')) {
911 while (p
!=fontdata
&& (*p
=='\r' || *p
=='\n')) p
--;
913 if (i
>0) fallback
= TRUE
;
914 else len2
= p
-fontdata
-len1
;
918 else fallback
= TRUE
;
922 seg2
= fontdata
+ len1
+ 12;
925 seg2
= g_malloc(len2
/2);
928 while (p
+1 < fontdata
+len1
+len2
) {
929 if (*p
==' '||*p
=='\t'||*p
=='\n'||*p
=='\r') { p
++; continue; }
930 if (p
[0]>'9') { p
[0]|=0x20; p
[0]-=39; }
931 if (p
[1]>'9') { p
[1]|=0x20; p
[1]-=39; }
932 seg2
[j
++] = ((p
[0]-'0')<<4) + (p
[1]-'0');
937 make_xref(xref
, xref
->last
+1, pdfbuf
->len
);
938 nobj_fontprog
= xref
->last
;
939 g_string_append_printf(pdfbuf
,
940 "%d 0 obj\n<< /Length %d /Length1 %d /Length2 %d /Length3 0 >> stream\n",
941 nobj_fontprog
, len1
+len2
, len1
, len2
);
942 g_string_append_len(pdfbuf
, seg1
, len1
);
943 g_string_append_len(pdfbuf
, seg2
, len2
);
944 g_string_append(pdfbuf
, "endstream\nendobj\n");
945 if (!is_binary
) g_free(seg2
);
949 else fallback
= TRUE
;
952 // next, the font descriptor
954 make_xref(xref
, xref
->last
+1, pdfbuf
->len
);
955 nobj_descr
= xref
->last
;
956 g_string_append_printf(pdfbuf
,
957 "%d 0 obj\n<< /Type /FontDescriptor /FontName /%s /Flags %d "
958 "/FontBBox [%d %d %d %d] /ItalicAngle 0 /Ascent %d "
959 "/Descent %d /CapHeight %d /StemV 100 /%s %d 0 R >> endobj\n",
960 nobj_descr
, font
->fontname
, font
->flags
,
961 font
->xmin
, font
->ymin
, font
->xmax
, font
->ymax
,
962 font
->ascender
, -font
->descender
, font
->ascender
,
963 font
->is_truetype
? "FontFile2":"FontFile",
967 // finally, the font itself
968 /* Note: in Type1 case, font->glyphmap maps charcodes to glyph no's
969 in TrueType case, encoding lists the used charcodes by index,
970 glyphs list the used glyph no's by index
971 font->glyphmap maps charcodes to indices */
972 xref
->data
[font
->n_obj
] = pdfbuf
->len
;
973 if (font
->is_truetype
) lastchar
= encoding
[font
->num_glyphs_used
];
974 else lastchar
= font
->num_glyphs_used
;
976 font
->is_truetype
= FALSE
;
977 g_free(font
->fontname
);
978 font
->fontname
= g_strdup("Helvetica");
981 if (font
->is_truetype
) {
982 num
= font
->glyph_page
;
983 for (i
=0; i
<6; i
++) { prefix
[i
] = 'A'+(num
%26); num
/=26; }
984 prefix
[6]='+'; prefix
[7]=0;
986 g_string_append_printf(pdfbuf
,
987 "%d 0 obj\n<< /Type /Font /Subtype /%s /BaseFont /%s%s /Name /F%d ",
988 font
->n_obj
, font
->is_truetype
?"TrueType":"Type1",
989 prefix
, font
->fontname
, font
->n_obj
);
991 g_string_append_printf(pdfbuf
,
992 "/FontDescriptor %d 0 R /FirstChar 0 /LastChar %d /Widths [",
993 nobj_descr
, lastchar
);
994 for (i
=0; i
<=lastchar
; i
++)
995 g_string_append_printf(pdfbuf
, "%d ", font
->advance
[i
]);
996 g_string_append(pdfbuf
, "] ");
998 if (!font
->is_truetype
) { /* encoding */
999 g_string_append(pdfbuf
, "/Encoding << /Type /Encoding "
1000 "/BaseEncoding /MacRomanEncoding /Differences [1 ");
1001 for (i
=1; i
<=lastchar
; i
++) {
1002 g_string_append_printf(pdfbuf
, "/%s ", font
->glyphpsnames
[i
]);
1003 g_free(font
->glyphpsnames
[i
]);
1005 g_string_append(pdfbuf
, "] >> ");
1007 g_string_append(pdfbuf
, ">> endobj\n");
1010 // draw a page's graphics
1012 void pdf_draw_page(struct Page
*pg
, GString
*str
, gboolean
*use_hiliter
,
1013 struct XrefTable
*xref
, GList
**pdffonts
)
1015 GList
*layerlist
, *itemlist
, *tmplist
;
1018 guint old_rgba
, old_text_rgba
;
1019 double old_thickness
;
1022 PangoFontDescription
*font_desc
;
1023 PangoContext
*context
;
1024 PangoLayout
*layout
;
1025 PangoLayoutIter
*iter
;
1026 PangoRectangle logical_rect
;
1027 PangoLayoutRun
*run
;
1028 PangoFcFont
*fcfont
;
1030 int baseline
, advance
;
1031 int glyph_no
, glyph_page
, current_page
;
1036 struct PdfFont
*cur_font
;
1039 old_rgba
= old_text_rgba
= 0x12345678; // not any values we use, so we'll reset them
1040 old_thickness
= 0.0;
1041 for (tmplist
= *pdffonts
; tmplist
!=NULL
; tmplist
= tmplist
->next
) {
1042 cur_font
= (struct PdfFont
*)tmplist
->data
;
1043 cur_font
->used_in_this_page
= FALSE
;
1046 for (layerlist
= pg
->layers
; layerlist
!=NULL
; layerlist
= layerlist
->next
) {
1047 l
= (struct Layer
*)layerlist
->data
;
1048 for (itemlist
= l
->items
; itemlist
!=NULL
; itemlist
= itemlist
->next
) {
1049 item
= (struct Item
*)itemlist
->data
;
1050 if (item
->type
== ITEM_STROKE
) {
1051 if ((item
->brush
.color_rgba
& ~0xff) != old_rgba
)
1052 g_string_append_printf(str
, "%.2f %.2f %.2f RG ",
1053 RGBA_RGB(item
->brush
.color_rgba
));
1054 if (item
->brush
.thickness
!= old_thickness
)
1055 g_string_append_printf(str
, "%.2f w ", item
->brush
.thickness
);
1056 if ((item
->brush
.color_rgba
& 0xf0) != 0xf0) { // transparent
1057 g_string_append(str
, "q /XoHi gs ");
1058 *use_hiliter
= TRUE
;
1060 old_rgba
= item
->brush
.color_rgba
& ~0xff;
1061 old_thickness
= item
->brush
.thickness
;
1062 pt
= item
->path
->coords
;
1063 if (!item
->brush
.variable_width
) {
1064 g_string_append_printf(str
, "%.2f %.2f m ", pt
[0], pt
[1]);
1065 for (i
=1, pt
+=2; i
<item
->path
->num_points
; i
++, pt
+=2)
1066 g_string_append_printf(str
, "%.2f %.2f l ", pt
[0], pt
[1]);
1067 g_string_append_printf(str
,"S\n");
1068 old_thickness
= item
->brush
.thickness
;
1070 for (i
=0; i
<item
->path
->num_points
-1; i
++, pt
+=2)
1071 g_string_append_printf(str
, "%.2f w %.2f %.2f m %.2f %.2f l S\n",
1072 item
->widths
[i
], pt
[0], pt
[1], pt
[2], pt
[3]);
1073 old_thickness
= 0.0;
1075 if ((item
->brush
.color_rgba
& 0xf0) != 0xf0) // undo transparent
1076 g_string_append(str
, "Q ");
1078 else if (item
->type
== ITEM_TEXT
) {
1079 if ((item
->brush
.color_rgba
& ~0xff) != old_text_rgba
)
1080 g_string_append_printf(str
, "%.2f %.2f %.2f rg ",
1081 RGBA_RGB(item
->brush
.color_rgba
));
1082 old_text_rgba
= item
->brush
.color_rgba
& ~0xff;
1083 context
= gnome_print_pango_create_context(gnome_print_pango_get_default_font_map());
1084 layout
= pango_layout_new(context
);
1085 g_object_unref(context
);
1086 font_desc
= pango_font_description_from_string(item
->font_name
);
1087 pango_font_description_set_absolute_size(font_desc
,
1088 item
->font_size
*PANGO_SCALE
);
1089 pango_layout_set_font_description(layout
, font_desc
);
1090 pango_font_description_free(font_desc
);
1091 pango_layout_set_text(layout
, item
->text
, -1);
1092 // this code inspired by the code in libgnomeprint
1093 iter
= pango_layout_get_iter(layout
);
1095 run
= pango_layout_iter_get_run(iter
);
1096 if (run
==NULL
) continue;
1097 pango_layout_iter_get_run_extents (iter
, NULL
, &logical_rect
);
1098 baseline
= pango_layout_iter_get_baseline (iter
);
1099 if (!PANGO_IS_FC_FONT(run
->item
->analysis
.font
)) continue;
1100 fcfont
= PANGO_FC_FONT(run
->item
->analysis
.font
);
1101 pattern
= fcfont
->font_pattern
;
1102 if (FcPatternGetString(pattern
, FC_FILE
, 0, (unsigned char **)&filename
) != FcResultMatch
||
1103 FcPatternGetInteger(pattern
, FC_INDEX
, 0, &font_id
) != FcResultMatch
)
1105 ftface
= pango_fc_font_lock_face(fcfont
);
1108 g_string_append_printf(str
, "BT %.2f 0 0 %.2f %.2f %.2f Tm ",
1109 item
->font_size
, -item
->font_size
,
1110 item
->bbox
.left
+ (gdouble
) logical_rect
.x
/PANGO_SCALE
,
1111 item
->bbox
.top
+ (gdouble
) baseline
/PANGO_SCALE
);
1113 for (i
=0; i
<run
->glyphs
->num_glyphs
; i
++) {
1114 glyph_no
= run
->glyphs
->glyphs
[i
].glyph
;
1115 if (FT_IS_SFNT(ftface
)) glyph_page
= glyph_no
/255;
1116 else glyph_page
= 0;
1117 if (glyph_page
!= current_page
) {
1118 cur_font
= new_pdffont(xref
, pdffonts
, filename
, font_id
,
1119 ftface
, glyph_page
);
1120 if (in_string
) g_string_append(str
, ") Tj ");
1122 g_string_append_printf(str
, "/F%d 1 Tf ", cur_font
->n_obj
);
1124 current_page
= glyph_page
;
1125 FT_Load_Glyph(ftface
, glyph_no
, FT_LOAD_NO_SCALE
| FT_LOAD_NO_HINTING
| FT_LOAD_NO_BITMAP
| FT_LOAD_IGNORE_TRANSFORM
);
1126 advance
= (int)(ftface
->glyph
->metrics
.horiAdvance
* cur_font
->ft2ps
+ 0.5);
1127 if (!in_string
) g_string_append_c(str
, '(');
1129 if (cur_font
->is_truetype
) {
1130 if (glyph_no
) glyph_no
= (glyph_no
%255)+1;
1131 cur_font
->glyphmap
[glyph_no
] = glyph_no
;
1134 for (j
=1; j
<=cur_font
->num_glyphs_used
; j
++)
1135 if (cur_font
->glyphmap
[j
] == glyph_no
) break;
1136 if (j
==256) j
=0; // font is full, what do we do?
1137 if (j
>cur_font
->num_glyphs_used
) {
1138 cur_font
->glyphmap
[j
] = glyph_no
;
1139 cur_font
->num_glyphs_used
++;
1140 if (FT_Get_Glyph_Name(ftface
, glyph_no
, tmpstr
, 200) == FT_Err_Ok
)
1141 cur_font
->glyphpsnames
[j
] = g_strdup(tmpstr
);
1142 else cur_font
->glyphpsnames
[j
] = g_strdup(".notdef");
1146 cur_font
->advance
[glyph_no
] = advance
;
1147 if (glyph_no
=='\\' || glyph_no
== '(' || glyph_no
== ')' || glyph_no
== 10 || glyph_no
== 13)
1148 g_string_append_c(str
, '\\');
1149 if (glyph_no
==10) g_string_append_c(str
,'n');
1150 else if (glyph_no
==13) g_string_append_c(str
,'r');
1151 else g_string_append_c(str
, glyph_no
);
1153 if (in_string
) g_string_append(str
, ") Tj ");
1154 g_string_append(str
, "ET ");
1155 pango_fc_font_unlock_face(fcfont
);
1156 } while (pango_layout_iter_next_run(iter
));
1157 pango_layout_iter_free(iter
);
1158 g_object_unref(layout
);
1164 // main printing function
1166 /* we use the following object numbers, starting with n_obj_catalog:
1167 0 the document catalog
1169 2 the GS for the hiliters
1170 3 ... the page objects
1173 gboolean
print_to_pdf(char *filename
)
1176 GString
*pdfbuf
, *pgstrm
, *zpgstrm
, *tmpstr
;
1177 int n_obj_catalog
, n_obj_pages_offs
, n_page
, n_obj_bgpix
, n_obj_prefix
;
1179 struct XrefTable xref
;
1182 gboolean annot
, uses_pdf
;
1183 gboolean use_hiliter
;
1184 struct PdfInfo pdfinfo
;
1186 GList
*pdffonts
, *list
;
1187 struct PdfFont
*font
;
1190 f
= fopen(filename
, "w");
1191 if (f
== NULL
) return FALSE
;
1192 setlocale(LC_NUMERIC
, "C");
1197 for (pglist
= journal
.pages
; pglist
!=NULL
; pglist
= pglist
->next
) {
1198 pg
= (struct Page
*)pglist
->data
;
1199 if (pg
->bg
->type
== BG_PDF
) uses_pdf
= TRUE
;
1202 if (uses_pdf
&& bgpdf
.status
!= STATUS_NOT_INIT
&&
1203 bgpdf
.file_contents
!=NULL
&& !strncmp(bgpdf
.file_contents
, "%PDF-1.", 7)) {
1204 // parse the existing PDF file
1205 pdfbuf
= g_string_new_len(bgpdf
.file_contents
, bgpdf
.file_length
);
1206 if (pdfbuf
->str
[7]<'4') pdfbuf
->str
[7] = '4'; // upgrade to 1.4
1207 annot
= pdf_parse_info(pdfbuf
, &pdfinfo
, &xref
);
1209 g_string_free(pdfbuf
, TRUE
);
1210 if (xref
.data
!= NULL
) g_free(xref
.data
);
1215 pdfbuf
= g_string_new("%PDF-1.4\n%\370\357\365\362\n");
1216 xref
.n_alloc
= xref
.last
= 0;
1220 // catalog and page tree
1221 n_obj_catalog
= xref
.last
+1;
1222 n_obj_pages_offs
= xref
.last
+4;
1223 make_xref(&xref
, n_obj_catalog
, pdfbuf
->len
);
1224 g_string_append_printf(pdfbuf
,
1225 "%d 0 obj\n<< /Type /Catalog /Pages %d 0 R >> endobj\n",
1226 n_obj_catalog
, n_obj_catalog
+1);
1227 make_xref(&xref
, n_obj_catalog
+1, pdfbuf
->len
);
1228 g_string_append_printf(pdfbuf
,
1229 "%d 0 obj\n<< /Type /Pages /Kids [", n_obj_catalog
+1);
1230 for (i
=0;i
<journal
.npages
;i
++)
1231 g_string_append_printf(pdfbuf
, "%d 0 R ", n_obj_pages_offs
+i
);
1232 g_string_append_printf(pdfbuf
, "] /Count %d >> endobj\n", journal
.npages
);
1233 make_xref(&xref
, n_obj_catalog
+2, pdfbuf
->len
);
1234 g_string_append_printf(pdfbuf
,
1235 "%d 0 obj\n<< /Type /ExtGState /CA %.2f >> endobj\n",
1236 n_obj_catalog
+2, ui
.hiliter_opacity
);
1237 xref
.last
= n_obj_pages_offs
+ journal
.npages
-1;
1239 for (pglist
= journal
.pages
, n_page
= 0; pglist
!=NULL
;
1240 pglist
= pglist
->next
, n_page
++) {
1241 pg
= (struct Page
*)pglist
->data
;
1243 // draw the background and page into pgstrm
1244 pgstrm
= g_string_new("");
1245 g_string_printf(pgstrm
, "q 1 0 0 -1 0 %.2f cm 1 J 1 j ", pg
->height
);
1248 if (pg
->bg
->type
== BG_SOLID
)
1249 pdf_draw_solid_background(pg
, pgstrm
);
1250 else if (pg
->bg
->type
== BG_PDF
&& annot
&&
1251 pdfinfo
.pages
[pg
->bg
->file_page_seq
-1].contents
!=NULL
) {
1252 make_xref(&xref
, xref
.last
+1, pdfbuf
->len
);
1253 n_obj_prefix
= xref
.last
;
1254 tmpstr
= make_pdfprefix(pdfinfo
.pages
+(pg
->bg
->file_page_seq
-1),
1255 pg
->width
, pg
->height
);
1256 g_string_append_printf(pdfbuf
,
1257 "%d 0 obj\n<< /Length %d >> stream\n%s\nendstream\nendobj\n",
1258 n_obj_prefix
, tmpstr
->len
, tmpstr
->str
);
1259 g_string_free(tmpstr
, TRUE
);
1260 g_string_prepend(pgstrm
, "Q Q Q ");
1262 else if (pg
->bg
->type
== BG_PIXMAP
|| pg
->bg
->type
== BG_PDF
)
1263 n_obj_bgpix
= pdf_draw_bitmap_background(pg
, pgstrm
, &xref
, pdfbuf
);
1264 // draw the page contents
1265 use_hiliter
= FALSE
;
1266 pdf_draw_page(pg
, pgstrm
, &use_hiliter
, &xref
, &pdffonts
);
1267 g_string_append_printf(pgstrm
, "Q\n");
1269 // deflate pgstrm and write it
1270 zpgstrm
= do_deflate(pgstrm
->str
, pgstrm
->len
);
1271 g_string_free(pgstrm
, TRUE
);
1273 make_xref(&xref
, xref
.last
+1, pdfbuf
->len
);
1274 g_string_append_printf(pdfbuf
,
1275 "%d 0 obj\n<< /Length %d /Filter /FlateDecode>> stream\n",
1276 xref
.last
, zpgstrm
->len
);
1277 g_string_append_len(pdfbuf
, zpgstrm
->str
, zpgstrm
->len
);
1278 g_string_free(zpgstrm
, TRUE
);
1279 g_string_append(pdfbuf
, "endstream\nendobj\n");
1281 // write the page object
1283 make_xref(&xref
, n_obj_pages_offs
+n_page
, pdfbuf
->len
);
1284 g_string_append_printf(pdfbuf
,
1285 "%d 0 obj\n<< /Type /Page /Parent %d 0 R /MediaBox [0 0 %.2f %.2f] ",
1286 n_obj_pages_offs
+n_page
, n_obj_catalog
+1, pg
->width
, pg
->height
);
1287 if (n_obj_prefix
>0) {
1288 obj
= get_pdfobj(pdfbuf
, &xref
, pdfinfo
.pages
[pg
->bg
->file_page_seq
-1].contents
);
1289 if (obj
->type
!= PDFTYPE_ARRAY
) {
1291 obj
= dup_pdfobj(pdfinfo
.pages
[pg
->bg
->file_page_seq
-1].contents
);
1293 g_string_append_printf(pdfbuf
, "/Contents [%d 0 R ", n_obj_prefix
);
1294 if (obj
->type
== PDFTYPE_REF
)
1295 g_string_append_printf(pdfbuf
, "%d %d R ", obj
->intval
, obj
->num
);
1296 if (obj
->type
== PDFTYPE_ARRAY
) {
1297 for (i
=0; i
<obj
->num
; i
++) {
1298 show_pdfobj(obj
->elts
[i
], pdfbuf
);
1299 g_string_append_c(pdfbuf
, ' ');
1303 g_string_append_printf(pdfbuf
, "%d 0 R] ", xref
.last
);
1305 else g_string_append_printf(pdfbuf
, "/Contents %d 0 R ", xref
.last
);
1306 g_string_append(pdfbuf
, "/Resources ");
1309 obj
= dup_pdfobj(pdfinfo
.pages
[pg
->bg
->file_page_seq
-1].resources
);
1311 if (obj
!=NULL
&& obj
->type
!=PDFTYPE_DICT
)
1312 { free_pdfobj(obj
); obj
=NULL
; }
1314 obj
= g_malloc(sizeof(struct PdfObj
));
1315 obj
->type
= PDFTYPE_DICT
;
1320 add_dict_subentry(pdfbuf
, &xref
,
1321 obj
, "/ProcSet", PDFTYPE_ARRAY
, NULL
, mk_pdfname("/PDF"));
1323 add_dict_subentry(pdfbuf
, &xref
,
1324 obj
, "/ProcSet", PDFTYPE_ARRAY
, NULL
, mk_pdfname("/ImageC"));
1326 add_dict_subentry(pdfbuf
, &xref
,
1327 obj
, "/ExtGState", PDFTYPE_DICT
, "/XoHi", mk_pdfref(n_obj_catalog
+2));
1329 add_dict_subentry(pdfbuf
, &xref
,
1330 obj
, "/XObject", PDFTYPE_DICT
, "/ImBg", mk_pdfref(n_obj_bgpix
));
1331 for (list
=pdffonts
; list
!=NULL
; list
= list
->next
) {
1332 font
= (struct PdfFont
*)list
->data
;
1333 if (font
->used_in_this_page
) {
1334 add_dict_subentry(pdfbuf
, &xref
,
1335 obj
, "/ProcSet", PDFTYPE_ARRAY
, NULL
, mk_pdfname("/Text"));
1336 tmpbuf
= g_strdup_printf("/F%d", font
->n_obj
);
1337 add_dict_subentry(pdfbuf
, &xref
,
1338 obj
, "/Font", PDFTYPE_DICT
, tmpbuf
, mk_pdfref(font
->n_obj
));
1342 show_pdfobj(obj
, pdfbuf
);
1344 g_string_append(pdfbuf
, " >> endobj\n");
1347 // after the pages, we insert fonts
1348 for (list
= pdffonts
; list
!=NULL
; list
= list
->next
) {
1349 font
= (struct PdfFont
*)list
->data
;
1350 embed_pdffont(pdfbuf
, &xref
, font
);
1351 g_free(font
->filename
);
1352 g_free(font
->fontname
);
1355 g_list_free(pdffonts
);
1358 startxref
= pdfbuf
->len
;
1359 if (annot
) g_string_append_printf(pdfbuf
,
1360 "xref\n%d %d\n", n_obj_catalog
, xref
.last
-n_obj_catalog
+1);
1361 else g_string_append_printf(pdfbuf
,
1362 "xref\n0 %d\n0000000000 65535 f \n", xref
.last
+1);
1363 for (i
=n_obj_catalog
; i
<=xref
.last
; i
++)
1364 g_string_append_printf(pdfbuf
, "%010d 00000 n \n", xref
.data
[i
]);
1365 g_string_append_printf(pdfbuf
,
1366 "trailer\n<< /Size %d /Root %d 0 R ", xref
.last
+1, n_obj_catalog
);
1368 g_string_append_printf(pdfbuf
, "/Prev %d ", pdfinfo
.startxref
);
1369 // keeping encryption info somehow doesn't work.
1370 // xournal can't annotate encrypted PDFs anyway...
1372 obj = get_dict_entry(pdfinfo.trailerdict, "/Encrypt");
1374 g_string_append_printf(pdfbuf, "/Encrypt ");
1375 show_pdfobj(obj, pdfbuf);
1379 g_string_append_printf(pdfbuf
,
1380 ">>\nstartxref\n%d\n%%%%EOF\n", startxref
);
1384 free_pdfobj(pdfinfo
.trailerdict
);
1385 if (pdfinfo
.pages
!=NULL
)
1386 for (i
=0; i
<pdfinfo
.npages
; i
++) {
1387 free_pdfobj(pdfinfo
.pages
[i
].resources
);
1388 free_pdfobj(pdfinfo
.pages
[i
].mediabox
);
1389 free_pdfobj(pdfinfo
.pages
[i
].contents
);
1393 setlocale(LC_NUMERIC
, "");
1394 if (fwrite(pdfbuf
->str
, 1, pdfbuf
->len
, f
) < pdfbuf
->len
) {
1396 g_string_free(pdfbuf
, TRUE
);
1400 g_string_free(pdfbuf
, TRUE
);
1404 /*********** Printing via libgnomeprint **********/
1406 // does the same job as update_canvas_bg(), but to a print context
1408 void print_background(GnomePrintContext
*gpc
, struct Page
*pg
, gboolean
*abort
)
1413 PopplerPage
*pdfpage
;
1415 double pgwidth
, pgheight
;
1417 if (pg
->bg
->type
== BG_SOLID
) {
1418 gnome_print_setopacity(gpc
, 1.0);
1419 gnome_print_setrgbcolor(gpc
, RGBA_RGB(pg
->bg
->color_rgba
));
1420 gnome_print_rect_filled(gpc
, 0, 0, pg
->width
, -pg
->height
);
1422 if (!ui
.print_ruling
) return;
1423 if (pg
->bg
->ruling
== RULING_NONE
) return;
1424 gnome_print_setrgbcolor(gpc
, RGBA_RGB(RULING_COLOR
));
1425 gnome_print_setlinewidth(gpc
, RULING_THICKNESS
);
1427 if (pg
->bg
->ruling
== RULING_GRAPH
) {
1428 for (x
=RULING_GRAPHSPACING
; x
<pg
->width
-1; x
+=RULING_GRAPHSPACING
)
1429 gnome_print_line_stroked(gpc
, x
, 0, x
, -pg
->height
);
1430 for (y
=RULING_GRAPHSPACING
; y
<pg
->height
-1; y
+=RULING_GRAPHSPACING
)
1431 gnome_print_line_stroked(gpc
, 0, -y
, pg
->width
, -y
);
1435 for (y
=RULING_TOPMARGIN
; y
<pg
->height
-1; y
+=RULING_SPACING
)
1436 gnome_print_line_stroked(gpc
, 0, -y
, pg
->width
, -y
);
1437 if (pg
->bg
->ruling
== RULING_LINED
) {
1438 gnome_print_setrgbcolor(gpc
, RGBA_RGB(RULING_MARGIN_COLOR
));
1439 gnome_print_line_stroked(gpc
, RULING_LEFTMARGIN
, 0, RULING_LEFTMARGIN
, -pg
->height
);
1444 if (pg
->bg
->type
== BG_PIXMAP
|| pg
->bg
->type
== BG_PDF
) {
1445 if (pg
->bg
->type
== BG_PDF
) {
1446 if (!bgpdf
.document
) return;
1447 pdfpage
= poppler_document_get_page(bgpdf
.document
, pg
->bg
->file_page_seq
-1);
1448 if (!pdfpage
) return;
1449 poppler_page_get_size(pdfpage
, &pgwidth
, &pgheight
);
1450 width
= (int) (PDFTOPPM_PRINTING_DPI
* pgwidth
/72.0);
1451 height
= (int) (PDFTOPPM_PRINTING_DPI
* pgheight
/72.0);
1452 pix
= gdk_pixbuf_new(GDK_COLORSPACE_RGB
, FALSE
, 8, width
, height
);
1453 poppler_page_render_to_pixbuf(
1454 pdfpage
, 0, 0, width
, height
, PDFTOPPM_PRINTING_DPI
/72.0, 0, pix
);
1455 g_object_unref(pdfpage
);
1457 else pix
= g_object_ref(pg
->bg
->pixbuf
);
1459 if (gdk_pixbuf_get_bits_per_sample(pix
) != 8 ||
1460 gdk_pixbuf_get_colorspace(pix
) != GDK_COLORSPACE_RGB
)
1461 { g_object_unref(pix
); return; }
1462 gnome_print_gsave(gpc
);
1463 gnome_print_scale(gpc
, pg
->width
, pg
->height
);
1464 gnome_print_translate(gpc
, 0., -1.);
1465 if (gdk_pixbuf_get_n_channels(pix
) == 3)
1466 gnome_print_rgbimage(gpc
, gdk_pixbuf_get_pixels(pix
),
1467 gdk_pixbuf_get_width(pix
), gdk_pixbuf_get_height(pix
), gdk_pixbuf_get_rowstride(pix
));
1468 else if (gdk_pixbuf_get_n_channels(pix
) == 4)
1469 gnome_print_rgbaimage(gpc
, gdk_pixbuf_get_pixels(pix
),
1470 gdk_pixbuf_get_width(pix
), gdk_pixbuf_get_height(pix
), gdk_pixbuf_get_rowstride(pix
));
1471 g_object_unref(pix
);
1472 gnome_print_grestore(gpc
);
1477 void print_page(GnomePrintContext
*gpc
, struct Page
*pg
, int pageno
,
1478 double pgwidth
, double pgheight
, gboolean
*abort
)
1483 double old_thickness
;
1484 GList
*layerlist
, *itemlist
;
1489 PangoFontDescription
*font_desc
;
1490 PangoLayout
*layout
;
1492 if (pg
==NULL
) return;
1494 g_snprintf(tmp
, 10, _("Page %d"), pageno
);
1495 gnome_print_beginpage(gpc
, (guchar
*)tmp
);
1496 gnome_print_gsave(gpc
);
1498 scale
= MIN(pgwidth
/pg
->width
, pgheight
/pg
->height
)*0.95;
1499 gnome_print_translate(gpc
,
1500 (pgwidth
- scale
*pg
->width
)/2, (pgheight
+ scale
*pg
->height
)/2);
1501 gnome_print_scale(gpc
, scale
, scale
);
1502 gnome_print_setlinejoin(gpc
, 1); // round
1503 gnome_print_setlinecap(gpc
, 1); // round
1505 print_background(gpc
, pg
, abort
);
1507 old_rgba
= 0x12345678; // not any values we use, so we'll reset them
1508 old_thickness
= 0.0;
1510 for (layerlist
= pg
->layers
; layerlist
!=NULL
; layerlist
= layerlist
->next
) {
1512 l
= (struct Layer
*)layerlist
->data
;
1513 for (itemlist
= l
->items
; itemlist
!=NULL
; itemlist
= itemlist
->next
) {
1515 item
= (struct Item
*)itemlist
->data
;
1516 if (item
->type
== ITEM_STROKE
|| item
->type
== ITEM_TEXT
) {
1517 if ((item
->brush
.color_rgba
& ~0xff) != (old_rgba
& ~0xff))
1518 gnome_print_setrgbcolor(gpc
, RGBA_RGB(item
->brush
.color_rgba
));
1519 if ((item
->brush
.color_rgba
& 0xff) != (old_rgba
& 0xff))
1520 gnome_print_setopacity(gpc
, RGBA_ALPHA(item
->brush
.color_rgba
));
1521 old_rgba
= item
->brush
.color_rgba
;
1523 if (item
->type
== ITEM_STROKE
) {
1524 if (item
->brush
.thickness
!= old_thickness
)
1525 gnome_print_setlinewidth(gpc
, item
->brush
.thickness
);
1526 gnome_print_newpath(gpc
);
1527 pt
= item
->path
->coords
;
1528 if (!item
->brush
.variable_width
) {
1529 gnome_print_moveto(gpc
, pt
[0], -pt
[1]);
1530 for (i
=1, pt
+=2; i
<item
->path
->num_points
; i
++, pt
+=2)
1531 gnome_print_lineto(gpc
, pt
[0], -pt
[1]);
1532 gnome_print_stroke(gpc
);
1533 old_thickness
= item
->brush
.thickness
;
1535 for (i
=0; i
<item
->path
->num_points
-1; i
++, pt
+=2) {
1536 gnome_print_moveto(gpc
, pt
[0], -pt
[1]);
1537 gnome_print_setlinewidth(gpc
, item
->widths
[i
]);
1538 gnome_print_lineto(gpc
, pt
[2], -pt
[3]);
1539 gnome_print_stroke(gpc
);
1541 old_thickness
= 0.0;
1544 if (item
->type
== ITEM_TEXT
) {
1545 layout
= gnome_print_pango_create_layout(gpc
);
1546 font_desc
= pango_font_description_from_string(item
->font_name
);
1547 pango_font_description_set_absolute_size(font_desc
,
1548 item
->font_size
*PANGO_SCALE
);
1549 pango_layout_set_font_description(layout
, font_desc
);
1550 pango_font_description_free(font_desc
);
1551 pango_layout_set_text(layout
, item
->text
, -1);
1552 gnome_print_moveto(gpc
, item
->bbox
.left
, -item
->bbox
.top
);
1553 gnome_print_pango_layout(gpc
, layout
);
1554 g_object_unref(layout
);
1559 gnome_print_grestore(gpc
);
1560 gnome_print_showpage(gpc
);
1563 void cb_print_abort(GtkDialog
*dialog
, gint response
, gboolean
*abort
)
1568 void print_job_render(GnomePrintJob
*gpj
, int fromPage
, int toPage
)
1570 GnomePrintConfig
*config
;
1571 GnomePrintContext
*gpc
;
1572 GtkWidget
*wait_dialog
;
1573 double pgwidth
, pgheight
;
1577 config
= gnome_print_job_get_config(gpj
);
1578 gnome_print_config_get_page_size(config
, &pgwidth
, &pgheight
);
1579 g_object_unref(G_OBJECT(config
));
1581 gpc
= gnome_print_job_get_context(gpj
);
1584 wait_dialog
= gtk_message_dialog_new(GTK_WINDOW(winMain
), GTK_DIALOG_MODAL
,
1585 GTK_MESSAGE_INFO
, GTK_BUTTONS_CANCEL
, _("Preparing print job"));
1586 gtk_widget_show(wait_dialog
);
1587 g_signal_connect(wait_dialog
, "response", G_CALLBACK (cb_print_abort
), &abort
);
1589 for (i
= fromPage
; i
<= toPage
; i
++) {
1590 #if GTK_CHECK_VERSION(2,6,0)
1591 if (!gtk_check_version(2, 6, 0))
1592 gtk_message_dialog_format_secondary_text(
1593 GTK_MESSAGE_DIALOG(wait_dialog
), _("Page %d"), i
+1);
1595 while (gtk_events_pending()) gtk_main_iteration();
1596 print_page(gpc
, (struct Page
*)g_list_nth_data(journal
.pages
, i
), i
+1,
1597 pgwidth
, pgheight
, &abort
);
1600 #if GTK_CHECK_VERSION(2,6,0)
1601 if (!gtk_check_version(2, 6, 0))
1602 gtk_message_dialog_format_secondary_text(
1603 GTK_MESSAGE_DIALOG(wait_dialog
), _("Finalizing..."));
1605 while (gtk_events_pending()) gtk_main_iteration();
1607 gnome_print_context_close(gpc
);
1608 g_object_unref(G_OBJECT(gpc
));
1610 gnome_print_job_close(gpj
);
1611 if (!abort
) gnome_print_job_print(gpj
);
1612 g_object_unref(G_OBJECT(gpj
));
1614 gtk_widget_destroy(wait_dialog
);