5 #define PANGO_ENABLE_BACKEND /* to access PangoFcFont.font_pattern */
8 #include <libgnomecanvas/libgnomecanvas.h>
12 #include <pango/pango.h>
13 #include <pango/pangofc-font.h>
14 #include <pango/pangoft2.h>
15 #include <fontconfig/fontconfig.h>
17 #include FT_FREETYPE_H
22 #include "ttsubset/sft.h"
25 #include "xo-support.h"
31 #define RGBA_RED(rgba) (((rgba>>24)&0xff)/255.0)
32 #define RGBA_GREEN(rgba) (((rgba>>16)&0xff)/255.0)
33 #define RGBA_BLUE(rgba) (((rgba>>8)&0xff)/255.0)
34 #define RGBA_ALPHA(rgba) (((rgba>>0)&0xff)/255.0)
35 #define RGBA_RGB(rgba) RGBA_RED(rgba), RGBA_GREEN(rgba), RGBA_BLUE(rgba)
37 /*********** Printing to PDF ************/
39 gboolean
ispdfspace(char c
)
41 return (c
==0 || c
==9 || c
==10 || c
==12 || c
==13 || c
==' ');
44 gboolean
ispdfdelim(char c
)
46 return (c
=='(' || c
==')' || c
=='<' || c
=='>' || c
=='[' || c
==']' ||
47 c
=='{' || c
=='}' || c
=='/' || c
=='%');
50 void skipspace(char **p
, char *eof
)
52 while (ispdfspace(**p
) || **p
=='%') {
53 if (**p
=='%') while (*p
!=eof
&& **p
!=10 && **p
!=13) (*p
)++;
59 void free_pdfobj(struct PdfObj
*obj
)
63 if (obj
==NULL
) return;
64 if ((obj
->type
== PDFTYPE_STRING
|| obj
->type
== PDFTYPE_NAME
||
65 obj
->type
== PDFTYPE_STREAM
) && obj
->str
!=NULL
)
67 if ((obj
->type
== PDFTYPE_ARRAY
|| obj
->type
== PDFTYPE_DICT
||
68 obj
->type
== PDFTYPE_STREAM
) && obj
->num
>0) {
69 for (i
=0; i
<obj
->num
; i
++)
70 free_pdfobj(obj
->elts
[i
]);
73 if ((obj
->type
== PDFTYPE_DICT
|| obj
->type
== PDFTYPE_STREAM
) && obj
->num
>0) {
74 for (i
=0; i
<obj
->num
; i
++)
75 g_free(obj
->names
[i
]);
81 struct PdfObj
*dup_pdfobj(struct PdfObj
*obj
)
86 if (obj
==NULL
) return NULL
;
87 dup
= g_memdup(obj
, sizeof(struct PdfObj
));
88 if ((obj
->type
== PDFTYPE_STRING
|| obj
->type
== PDFTYPE_NAME
||
89 obj
->type
== PDFTYPE_STREAM
) && obj
->str
!=NULL
) {
90 if (obj
->type
== PDFTYPE_NAME
) obj
->len
= strlen(obj
->str
);
91 dup
->str
= g_memdup(obj
->str
, obj
->len
+1);
93 if ((obj
->type
== PDFTYPE_ARRAY
|| obj
->type
== PDFTYPE_DICT
||
94 obj
->type
== PDFTYPE_STREAM
) && obj
->num
>0) {
95 dup
->elts
= g_malloc(obj
->num
*sizeof(struct PdfObj
*));
96 for (i
=0; i
<obj
->num
; i
++)
97 dup
->elts
[i
] = dup_pdfobj(obj
->elts
[i
]);
99 if ((obj
->type
== PDFTYPE_DICT
|| obj
->type
== PDFTYPE_STREAM
) && obj
->num
>0) {
100 dup
->names
= g_malloc(obj
->num
*sizeof(char *));
101 for (i
=0; i
<obj
->num
; i
++)
102 dup
->names
[i
] = g_strdup(obj
->names
[i
]);
107 void show_pdfobj(struct PdfObj
*obj
, GString
*str
)
110 if (obj
==NULL
) return;
113 if (obj
->intval
==1) g_string_append(str
, "true");
114 if (obj
->intval
==0) g_string_append(str
, "false");
115 if (obj
->intval
==-1) g_string_append(str
, "null");
118 g_string_append_printf(str
, "%d", obj
->intval
);
121 g_string_append_printf(str
, "%f", obj
->realval
);
124 g_string_append_len(str
, obj
->str
, obj
->len
);
127 g_string_append(str
, obj
->str
);
130 g_string_append_c(str
, '[');
131 for (i
=0;i
<obj
->num
;i
++) {
132 if (i
) g_string_append_c(str
, ' ');
133 show_pdfobj(obj
->elts
[i
], str
);
135 g_string_append_c(str
, ']');
138 g_string_append(str
, "<<");
139 for (i
=0;i
<obj
->num
;i
++) {
140 g_string_append_printf(str
, " %s ", obj
->names
[i
]);
141 show_pdfobj(obj
->elts
[i
], str
);
143 g_string_append(str
, " >>");
146 g_string_append_printf(str
, "%d %d R", obj
->intval
, obj
->num
);
151 void DEBUG_PRINTOBJ(struct PdfObj
*obj
)
153 GString
*s
= g_string_new("");
156 g_string_free(s
, TRUE
);
159 // parse a PDF object; returns NULL if fails
160 // THIS PARSER DOES NOT RECOGNIZE STREAMS YET
162 struct PdfObj
*parse_pdf_object(char **ptr
, char *eof
)
164 struct PdfObj
*obj
, *elt
;
165 char *p
, *q
, *r
, *eltname
;
168 obj
= g_malloc(sizeof(struct PdfObj
));
171 if (p
==eof
) { g_free(obj
); return NULL
; }
174 if (!strncmp(p
, "true", 4)) {
175 obj
->type
= PDFTYPE_CST
;
180 if (!strncmp(p
, "false", 5)) {
181 obj
->type
= PDFTYPE_CST
;
186 if (!strncmp(p
, "null", 4)) {
187 obj
->type
= PDFTYPE_CST
;
194 obj
->intval
= strtol(p
, &q
, 10);
198 obj
->type
= PDFTYPE_REAL
;
199 obj
->realval
= g_ascii_strtod(p
, ptr
);
202 if (ispdfspace(*q
)) {
203 // check for indirect reference
205 obj
->num
= strtol(q
, &r
, 10);
210 obj
->type
= PDFTYPE_REF
;
215 obj
->type
= PDFTYPE_INT
;
222 while (stack
>0 && q
!=eof
) {
223 if (*q
=='(') stack
++;
224 if (*q
==')') stack
--;
228 if (q
==eof
) { g_free(obj
); return NULL
; }
229 obj
->type
= PDFTYPE_STRING
;
231 obj
->str
= g_malloc(obj
->len
+1);
232 obj
->str
[obj
->len
] = 0;
233 g_memmove(obj
->str
, p
, obj
->len
);
237 if (*p
=='<' && p
[1]!='<') {
239 while (*q
!='>' && q
!=eof
) q
++;
240 if (q
==eof
) { g_free(obj
); return NULL
; }
242 obj
->type
= PDFTYPE_STRING
;
244 obj
->str
= g_malloc(obj
->len
+1);
245 obj
->str
[obj
->len
] = 0;
246 g_memmove(obj
->str
, p
, obj
->len
);
254 while (!ispdfspace(*q
) && !ispdfdelim(*q
)) q
++;
255 obj
->type
= PDFTYPE_NAME
;
256 obj
->str
= g_strndup(p
, q
-p
);
263 obj
->type
= PDFTYPE_ARRAY
;
266 q
=p
+1; skipspace(&q
, eof
);
268 elt
= parse_pdf_object(&q
, eof
);
269 if (elt
==NULL
) { free_pdfobj(obj
); return NULL
; }
271 obj
->elts
= g_realloc(obj
->elts
, obj
->num
*sizeof(struct PdfObj
*));
272 obj
->elts
[obj
->num
-1] = elt
;
280 if (*p
=='<' && p
[1]=='<') {
281 obj
->type
= PDFTYPE_DICT
;
285 q
=p
+2; skipspace(&q
, eof
);
286 while (*q
!='>' || q
[1]!='>') {
287 if (*q
!='/') { free_pdfobj(obj
); return NULL
; }
289 while (!ispdfspace(*r
) && !ispdfdelim(*r
)) r
++;
290 eltname
= g_strndup(q
, r
-q
);
291 q
=r
; skipspace(&q
, eof
);
292 elt
= parse_pdf_object(&q
, eof
);
293 if (elt
==NULL
) { g_free(eltname
); free_pdfobj(obj
); return NULL
; }
295 obj
->elts
= g_realloc(obj
->elts
, obj
->num
*sizeof(struct PdfObj
*));
296 obj
->names
= g_realloc(obj
->names
, obj
->num
*sizeof(char *));
297 obj
->elts
[obj
->num
-1] = elt
;
298 obj
->names
[obj
->num
-1] = eltname
;
305 // DOES NOT RECOGNIZE STREAMS YET (handle as subcase of dictionary)
311 struct PdfObj
*get_dict_entry(struct PdfObj
*dict
, char *name
)
315 if (dict
==NULL
) return NULL
;
316 if (dict
->type
!= PDFTYPE_DICT
) return NULL
;
317 for (i
=0; i
<dict
->num
; i
++)
318 if (!strcmp(dict
->names
[i
], name
)) return dict
->elts
[i
];
322 struct PdfObj
*get_pdfobj(GString
*pdfbuf
, struct XrefTable
*xref
, struct PdfObj
*obj
)
327 if (obj
==NULL
) return NULL
;
328 if (obj
->type
!=PDFTYPE_REF
) return dup_pdfobj(obj
);
329 if (obj
->intval
>xref
->last
) return NULL
;
330 offs
= xref
->data
[obj
->intval
];
331 if (offs
<=0 || offs
>= pdfbuf
->len
) return NULL
;
333 p
= pdfbuf
->str
+ offs
;
334 eof
= pdfbuf
->str
+ pdfbuf
->len
;
335 n
= strtol(p
, &p
, 10);
336 if (n
!=obj
->intval
) return NULL
;
338 n
= strtol(p
, &p
, 10);
340 if (strncmp(p
, "obj", 3)) return NULL
;
342 return parse_pdf_object(&p
, eof
);
345 // read the xref table of a PDF file in memory, and return the trailerdict
347 struct PdfObj
*parse_xref_table(GString
*pdfbuf
, struct XrefTable
*xref
, int offs
)
350 struct PdfObj
*trailerdict
, *obj
;
353 if (strncmp(pdfbuf
->str
+offs
, "xref", 4)) return NULL
;
354 p
= strstr(pdfbuf
->str
+offs
, "trailer");
355 eof
= pdfbuf
->str
+ pdfbuf
->len
;
356 if (p
==NULL
) return NULL
;
358 trailerdict
= parse_pdf_object(&p
, eof
);
359 obj
= get_dict_entry(trailerdict
, "/Size");
360 if (obj
!=NULL
&& obj
->type
== PDFTYPE_INT
&& obj
->intval
-1>xref
->last
)
361 make_xref(xref
, obj
->intval
-1, 0);
362 obj
= get_dict_entry(trailerdict
, "/Prev");
363 if (obj
!=NULL
&& obj
->type
== PDFTYPE_INT
&& obj
->intval
>0 && obj
->intval
!=offs
) {
364 // recurse into older xref table
365 obj
= parse_xref_table(pdfbuf
, xref
, obj
->intval
);
368 p
= pdfbuf
->str
+offs
+4;
370 if (*p
<'0' || *p
>'9') { free_pdfobj(trailerdict
); return NULL
; }
371 while (*p
>='0' && *p
<='9') {
372 start
= strtol(p
, &p
, 10);
374 len
= strtol(p
, &p
, 10);
376 if (len
<= 0 || 20*len
> eof
-p
) break;
377 if (start
+len
-1 > xref
->last
) make_xref(xref
, start
+len
-1, 0);
378 for (i
=start
; i
<start
+len
; i
++) {
379 xref
->data
[i
] = strtol(p
, NULL
, 10);
384 if (*p
!='t') { free_pdfobj(trailerdict
); return NULL
; }
388 // parse the page tree
390 int pdf_getpageinfo(GString
*pdfbuf
, struct XrefTable
*xref
,
391 struct PdfObj
*pgtree
, int nmax
, struct PdfPageDesc
*pages
)
393 struct PdfObj
*obj
, *kid
;
396 obj
= get_pdfobj(pdfbuf
, xref
, get_dict_entry(pgtree
, "/Type"));
397 if (obj
== NULL
|| obj
->type
!= PDFTYPE_NAME
)
399 if (!strcmp(obj
->str
, "/Page")) {
401 pages
->contents
= dup_pdfobj(get_dict_entry(pgtree
, "/Contents"));
402 obj
= get_pdfobj(pdfbuf
, xref
, get_dict_entry(pgtree
, "/Resources"));
404 free_pdfobj(pages
->resources
);
405 pages
->resources
= obj
;
407 obj
= get_pdfobj(pdfbuf
, xref
, get_dict_entry(pgtree
, "/MediaBox"));
409 free_pdfobj(pages
->mediabox
);
410 pages
->mediabox
= obj
;
412 obj
= get_pdfobj(pdfbuf
, xref
, get_dict_entry(pgtree
, "/Rotate"));
413 if (obj
!=NULL
&& obj
->type
== PDFTYPE_INT
)
414 pages
->rotate
= obj
->intval
;
418 else if (!strcmp(obj
->str
, "/Pages")) {
420 obj
= get_pdfobj(pdfbuf
, xref
, get_dict_entry(pgtree
, "/Count"));
421 if (obj
!=NULL
&& obj
->type
== PDFTYPE_INT
&&
422 obj
->intval
>0 && obj
->intval
<=nmax
) count
= obj
->intval
;
425 obj
= get_pdfobj(pdfbuf
, xref
, get_dict_entry(pgtree
, "/Resources"));
427 for (i
=0; i
<count
; i
++) {
428 free_pdfobj(pages
[i
].resources
);
429 pages
[i
].resources
= dup_pdfobj(obj
);
432 obj
= get_pdfobj(pdfbuf
, xref
, get_dict_entry(pgtree
, "/MediaBox"));
434 for (i
=0; i
<count
; i
++) {
435 free_pdfobj(pages
[i
].mediabox
);
436 pages
[i
].mediabox
= dup_pdfobj(obj
);
439 obj
= get_pdfobj(pdfbuf
, xref
, get_dict_entry(pgtree
, "/Rotate"));
440 if (obj
!=NULL
&& obj
->type
== PDFTYPE_INT
)
441 for (i
=0; i
<count
; i
++)
442 pages
[i
].rotate
= obj
->intval
;
444 obj
= get_pdfobj(pdfbuf
, xref
, get_dict_entry(pgtree
, "/Kids"));
445 if (obj
!=NULL
&& obj
->type
== PDFTYPE_ARRAY
) {
446 for (i
=0; i
<obj
->num
; i
++) {
447 kid
= get_pdfobj(pdfbuf
, xref
, obj
->elts
[i
]);
449 j
= pdf_getpageinfo(pdfbuf
, xref
, kid
, nmax
, pages
);
462 // parse a PDF file in memory
464 gboolean
pdf_parse_info(GString
*pdfbuf
, struct PdfInfo
*pdfinfo
, struct XrefTable
*xref
)
468 struct PdfObj
*obj
, *pages
;
470 xref
->n_alloc
= xref
->last
= 0;
472 p
= pdfbuf
->str
+ pdfbuf
->len
-1;
474 while (*p
!='s' && p
!=pdfbuf
->str
) p
--;
475 if (strncmp(p
, "startxref", 9)) return FALSE
; // fail
477 while (ispdfspace(*p
) && p
!=pdfbuf
->str
+pdfbuf
->len
) p
++;
478 offs
= strtol(p
, NULL
, 10);
479 if (offs
<= 0 || offs
> pdfbuf
->len
) return FALSE
; // fail
480 pdfinfo
->startxref
= offs
;
482 pdfinfo
->trailerdict
= parse_xref_table(pdfbuf
, xref
, offs
);
483 if (pdfinfo
->trailerdict
== NULL
) return FALSE
; // fail
485 obj
= get_pdfobj(pdfbuf
, xref
,
486 get_dict_entry(pdfinfo
->trailerdict
, "/Root"));
488 { free_pdfobj(pdfinfo
->trailerdict
); return FALSE
; }
489 pages
= get_pdfobj(pdfbuf
, xref
, get_dict_entry(obj
, "/Pages"));
492 { free_pdfobj(pdfinfo
->trailerdict
); return FALSE
; }
493 obj
= get_pdfobj(pdfbuf
, xref
, get_dict_entry(pages
, "/Count"));
494 if (obj
== NULL
|| obj
->type
!= PDFTYPE_INT
|| obj
->intval
<=0)
495 { free_pdfobj(pdfinfo
->trailerdict
); free_pdfobj(pages
);
496 free_pdfobj(obj
); return FALSE
; }
497 pdfinfo
->npages
= obj
->intval
;
500 pdfinfo
->pages
= g_malloc0(pdfinfo
->npages
*sizeof(struct PdfPageDesc
));
501 pdf_getpageinfo(pdfbuf
, xref
, pages
, pdfinfo
->npages
, pdfinfo
->pages
);
507 // add an entry to the xref table
509 void make_xref(struct XrefTable
*xref
, int nobj
, int offset
)
511 if (xref
->n_alloc
<= nobj
) {
512 xref
->n_alloc
= nobj
+ 10;
513 xref
->data
= g_realloc(xref
->data
, xref
->n_alloc
*sizeof(int));
515 if (xref
->last
< nobj
) xref
->last
= nobj
;
516 xref
->data
[nobj
] = offset
;
519 // a wrapper for deflate
521 GString
*do_deflate(char *in
, int len
)
528 deflateInit(&zs
, Z_DEFAULT_COMPRESSION
);
529 zs
.next_in
= (Bytef
*)in
;
531 zs
.avail_out
= deflateBound(&zs
, len
);
532 out
= g_string_sized_new(zs
.avail_out
);
533 zs
.next_out
= (Bytef
*)out
->str
;
534 deflate(&zs
, Z_FINISH
);
535 out
->len
= zs
.total_out
;
540 // prefix to scale the original page
542 GString
*make_pdfprefix(struct PdfPageDesc
*pgdesc
, double width
, double height
)
545 double v
[4], t
, xscl
, yscl
;
548 // push 3 times in case code to be annotated has unbalanced q/Q (B of A., ...)
549 str
= g_string_new("q q q ");
550 if (pgdesc
->rotate
== 90) {
551 g_string_append_printf(str
, "0 -1 1 0 0 %.2f cm ", height
);
552 t
= height
; height
= width
; width
= t
;
554 if (pgdesc
->rotate
== 270) {
555 g_string_append_printf(str
, "0 1 -1 0 %.2f 0 cm ", width
);
556 t
= height
; height
= width
; width
= t
;
558 if (pgdesc
->rotate
== 180) {
559 g_string_append_printf(str
, "-1 0 0 -1 %.2f %.2f cm ", width
, height
);
561 if (pgdesc
->mediabox
==NULL
|| pgdesc
->mediabox
->type
!= PDFTYPE_ARRAY
||
562 pgdesc
->mediabox
->num
!= 4) return str
;
563 for (i
=0; i
<4; i
++) {
564 if (pgdesc
->mediabox
->elts
[i
]->type
== PDFTYPE_INT
)
565 v
[i
] = pgdesc
->mediabox
->elts
[i
]->intval
;
566 else if (pgdesc
->mediabox
->elts
[i
]->type
== PDFTYPE_REAL
)
567 v
[i
] = pgdesc
->mediabox
->elts
[i
]->realval
;
570 if (v
[0]>v
[2]) { t
= v
[0]; v
[0] = v
[2]; v
[2] = t
; }
571 if (v
[1]>v
[3]) { t
= v
[1]; v
[1] = v
[3]; v
[3] = t
; }
572 if (v
[2]-v
[0] < 1. || v
[3]-v
[1] < 1.) return str
;
573 xscl
= width
/(v
[2]-v
[0]);
574 yscl
= height
/(v
[3]-v
[1]);
575 g_string_append_printf(str
, "%.4f 0 0 %.4f %.2f %.2f cm ",
576 xscl
, yscl
, -v
[0]*xscl
, -v
[1]*yscl
);
580 // add an entry to a subentry of a directory
582 struct PdfObj
*mk_pdfname(char *name
)
586 obj
= g_malloc(sizeof(struct PdfObj
));
587 obj
->type
= PDFTYPE_NAME
;
588 obj
->str
= g_strdup(name
);
592 struct PdfObj
*mk_pdfref(int num
)
596 obj
= g_malloc(sizeof(struct PdfObj
));
597 obj
->type
= PDFTYPE_REF
;
603 gboolean
iseq_obj(struct PdfObj
*a
, struct PdfObj
*b
)
605 if (a
==NULL
|| b
==NULL
) return (a
==b
);
606 if (a
->type
!=b
->type
) return FALSE
;
607 if (a
->type
== PDFTYPE_CST
|| a
->type
== PDFTYPE_INT
)
608 return (a
->intval
== b
->intval
);
609 if (a
->type
== PDFTYPE_REAL
)
610 return (a
->realval
== b
->realval
);
611 if (a
->type
== PDFTYPE_NAME
)
612 return !strcmp(a
->str
, b
->str
);
613 if (a
->type
== PDFTYPE_REF
)
614 return (a
->intval
== b
->intval
&& a
->num
== b
->num
);
618 void add_dict_subentry(GString
*pdfbuf
, struct XrefTable
*xref
,
619 struct PdfObj
*obj
, char *section
, int type
, char *name
, struct PdfObj
*entry
)
625 for (i
=0; i
<obj
->num
; i
++)
626 if (!strcmp(obj
->names
[i
], section
)) subpos
= i
;
630 obj
->elts
= g_realloc(obj
->elts
, obj
->num
*sizeof(struct PdfObj
*));
631 obj
->names
= g_realloc(obj
->names
, obj
->num
*sizeof(char *));
632 obj
->names
[subpos
] = g_strdup(section
);
633 obj
->elts
[subpos
] = NULL
;
635 if (obj
->elts
[subpos
]!=NULL
&& obj
->elts
[subpos
]->type
==PDFTYPE_REF
) {
636 sec
= get_pdfobj(pdfbuf
, xref
, obj
->elts
[subpos
]);
637 free_pdfobj(obj
->elts
[subpos
]);
638 obj
->elts
[subpos
] = sec
;
640 if (obj
->elts
[subpos
]!=NULL
&& obj
->elts
[subpos
]->type
!=type
)
641 { free_pdfobj(obj
->elts
[subpos
]); obj
->elts
[subpos
] = NULL
; }
642 if (obj
->elts
[subpos
] == NULL
) {
643 obj
->elts
[subpos
] = sec
= g_malloc(sizeof(struct PdfObj
));
649 sec
= obj
->elts
[subpos
];
652 if (type
==PDFTYPE_DICT
) {
653 for (i
=0; i
<sec
->num
; i
++)
654 if (!strcmp(sec
->names
[i
], name
)) subpos
= i
;
658 sec
->elts
= g_realloc(sec
->elts
, sec
->num
*sizeof(struct PdfObj
*));
659 sec
->names
= g_realloc(sec
->names
, sec
->num
*sizeof(char *));
660 sec
->names
[subpos
] = g_strdup(name
);
661 sec
->elts
[subpos
] = NULL
;
663 free_pdfobj(sec
->elts
[subpos
]);
664 sec
->elts
[subpos
] = entry
;
666 if (type
==PDFTYPE_ARRAY
) {
667 for (i
=0; i
<sec
->num
; i
++)
668 if (iseq_obj(sec
->elts
[i
], entry
)) subpos
= i
;
672 sec
->elts
= g_realloc(sec
->elts
, sec
->num
*sizeof(struct PdfObj
*));
673 sec
->elts
[subpos
] = entry
;
675 else free_pdfobj(entry
);
679 // draw a page's background
681 void pdf_draw_solid_background(struct Page
*pg
, GString
*str
)
685 g_string_append_printf(str
,
686 "%.2f %.2f %.2f rg 0 0 %.2f %.2f re f ",
687 RGBA_RGB(pg
->bg
->color_rgba
), pg
->width
, pg
->height
);
688 if (!ui
.print_ruling
) return;
689 if (pg
->bg
->ruling
== RULING_NONE
) return;
690 g_string_append_printf(str
,
691 "%.2f %.2f %.2f RG %.2f w ",
692 RGBA_RGB(RULING_COLOR
), RULING_THICKNESS
);
693 if (pg
->bg
->ruling
== RULING_GRAPH
) {
694 for (x
=RULING_GRAPHSPACING
; x
<pg
->width
-1; x
+=RULING_GRAPHSPACING
)
695 g_string_append_printf(str
, "%.2f 0 m %.2f %.2f l S ",
697 for (y
=RULING_GRAPHSPACING
; y
<pg
->height
-1; y
+=RULING_GRAPHSPACING
)
698 g_string_append_printf(str
, "0 %.2f m %.2f %.2f l S ",
702 for (y
=RULING_TOPMARGIN
; y
<pg
->height
-1; y
+=RULING_SPACING
)
703 g_string_append_printf(str
, "0 %.2f m %.2f %.2f l S ",
705 if (pg
->bg
->ruling
== RULING_LINED
)
706 g_string_append_printf(str
,
707 "%.2f %.2f %.2f RG %.2f 0 m %.2f %.2f l S ",
708 RGBA_RGB(RULING_MARGIN_COLOR
),
709 RULING_LEFTMARGIN
, RULING_LEFTMARGIN
, pg
->height
);
712 int pdf_draw_bitmap_background(struct Page
*pg
, GString
*str
,
713 struct XrefTable
*xref
, GString
*pdfbuf
)
718 PopplerPage
*pdfpage
;
720 int height
, width
, stride
, x
, y
, chan
;
721 double pgheight
, pgwidth
;
723 if (pg
->bg
->type
== BG_PDF
) {
724 if (!bgpdf
.document
) return -1;
725 pdfpage
= poppler_document_get_page(bgpdf
.document
, pg
->bg
->file_page_seq
-1);
726 if (!pdfpage
) return -1;
727 poppler_page_get_size(pdfpage
, &pgwidth
, &pgheight
);
728 width
= (int) (PDFTOPPM_PRINTING_DPI
* pgwidth
/72.0);
729 height
= (int) (PDFTOPPM_PRINTING_DPI
* pgheight
/72.0);
730 pix
= gdk_pixbuf_new(GDK_COLORSPACE_RGB
, FALSE
, 8, width
, height
);
731 wrapper_poppler_page_render_to_pixbuf(
732 pdfpage
, 0, 0, width
, height
, PDFTOPPM_PRINTING_DPI
/72.0, 0, pix
);
733 g_object_unref(pdfpage
);
735 else pix
= g_object_ref(pg
->bg
->pixbuf
);
737 if (gdk_pixbuf_get_bits_per_sample(pix
) != 8 ||
738 gdk_pixbuf_get_colorspace(pix
) != GDK_COLORSPACE_RGB
)
739 { g_object_unref(pix
); return -1; }
741 width
= gdk_pixbuf_get_width(pix
);
742 height
= gdk_pixbuf_get_height(pix
);
743 stride
= gdk_pixbuf_get_rowstride(pix
);
744 chan
= gdk_pixbuf_get_n_channels(pix
);
745 if (chan
!=3 && chan
!=4) { g_object_unref(pix
); return -1; }
747 g_string_append_printf(str
, "q %.2f 0 0 %.2f 0 %.2f cm /ImBg Do Q ",
748 pg
->width
, -pg
->height
, pg
->height
);
750 p2
= buf
= (char *)g_malloc(3*width
*height
);
751 for (y
=0; y
<height
; y
++) {
752 p1
= (char *)gdk_pixbuf_get_pixels(pix
)+stride
*y
;
753 for (x
=0; x
<width
; x
++) {
754 *(p2
++)=*(p1
++); *(p2
++)=*(p1
++); *(p2
++)=*(p1
++);
758 zpix
= do_deflate(buf
, 3*width
*height
);
762 make_xref(xref
, xref
->last
+1, pdfbuf
->len
);
763 g_string_append_printf(pdfbuf
,
764 "%d 0 obj\n<< /Length %zu /Filter /FlateDecode /Type /Xobject "
765 "/Subtype /Image /Width %d /Height %d /ColorSpace /DeviceRGB "
766 "/BitsPerComponent 8 >> stream\n",
767 xref
->last
, zpix
->len
, width
, height
);
768 g_string_append_len(pdfbuf
, zpix
->str
, zpix
->len
);
769 g_string_free(zpix
, TRUE
);
770 g_string_append(pdfbuf
, "endstream\nendobj\n");
775 // manipulate Pdf fonts
777 struct PdfFont
*new_pdffont(struct XrefTable
*xref
, GList
**fonts
,
778 char *filename
, int font_id
, FT_Face face
, int glyph_page
)
781 struct PdfFont
*font
;
785 for (list
= *fonts
; list
!=NULL
; list
= list
->next
) {
786 font
= (struct PdfFont
*)list
->data
;
787 if (!strcmp(font
->filename
, filename
) && font
->font_id
== font_id
788 && font
->glyph_page
== glyph_page
)
789 { font
->used_in_this_page
= TRUE
; return font
; }
791 font
= g_malloc(sizeof(struct PdfFont
));
792 *fonts
= g_list_append(*fonts
, font
);
793 font
->n_obj
= xref
->last
+1;
794 make_xref(xref
, xref
->last
+1, 0); // will give it a value later
795 font
->filename
= g_strdup(filename
);
796 font
->font_id
= font_id
;
797 font
->glyph_page
= glyph_page
;
798 font
->used_in_this_page
= TRUE
;
799 font
->num_glyphs_used
= 0;
800 for (i
=0; i
<256; i
++) {
801 font
->glyphmap
[i
] = -1;
802 font
->advance
[i
] = 0;
803 font
->glyphpsnames
[i
] = NULL
;
805 font
->glyphmap
[0] = 0;
806 // fill in info from the FT_Face
807 font
->is_truetype
= FT_IS_SFNT(face
);
808 font
->nglyphs
= face
->num_glyphs
;
809 font
->ft2ps
= 1000.0 / face
->units_per_EM
;
810 font
->ascender
= (int)(font
->ft2ps
*face
->ascender
);
811 font
->descender
= (int)(font
->ft2ps
*face
->descender
);
812 if (face
->bbox
.xMin
< -100000 || face
->bbox
.xMin
> 100000) font
->xmin
= 0;
813 else font
->xmin
= (int)(font
->ft2ps
*face
->bbox
.xMin
);
814 if (face
->bbox
.xMax
< -100000 || face
->bbox
.xMax
> 100000) font
->xmax
= 0;
815 else font
->xmax
= (int)(font
->ft2ps
*face
->bbox
.xMax
);
816 if (face
->bbox
.yMin
< -100000 || face
->bbox
.yMin
> 100000) font
->ymin
= 0;
817 else font
->ymin
= (int)(font
->ft2ps
*face
->bbox
.yMin
);
818 if (face
->bbox
.yMax
< -100000 || face
->bbox
.yMax
> 100000) font
->ymax
= 0;
819 else font
->ymax
= (int)(font
->ft2ps
*face
->bbox
.yMax
);
820 if (font
->is_truetype
) font
->flags
= 4; // symbolic
822 font
->flags
= 4; // symbolic
823 if (FT_IS_FIXED_WIDTH(face
)) font
->flags
|= 1;
824 if (face
->style_flags
& FT_STYLE_FLAG_ITALIC
) font
->flags
|= 64;
826 s
= FT_Get_Postscript_Name(face
);
827 if (s
==NULL
) s
= "Noname";
828 if (glyph_page
) font
->fontname
= g_strdup_printf("%s_%03d", s
, glyph_page
);
829 else font
->fontname
= g_strdup(s
);
833 #define pfb_get_length(x) (((x)[3]<<24) + ((x)[2]<<16) + ((x)[1]<<8) + (x)[0])
834 #define T1_SEGMENT_1_END "currentfile eexec"
835 #define T1_SEGMENT_3_END "cleartomark"
837 void embed_pdffont(GString
*pdfbuf
, struct XrefTable
*xref
, struct PdfFont
*font
)
839 // this code inspired by libgnomeprint
840 gboolean fallback
, is_binary
;
841 guchar encoding
[256];
851 int nobj_fontprog
, nobj_descr
, lastchar
;
854 // embed the font file: TrueType case
855 if (font
->is_truetype
) {
856 glyphs
[0] = encoding
[0] = 0;
858 for (i
=1; i
<=255; i
++)
859 if (font
->glyphmap
[i
]>=0) {
860 font
->glyphmap
[i
] = num
;
861 glyphs
[num
] = 255*font
->glyph_page
+i
-1;
865 font
->num_glyphs_used
= num
-1;
866 if (OpenTTFont(font
->filename
, 0, &ttfnt
) == SF_OK
) {
867 if (CreateTTFromTTGlyphs_tomemory(ttfnt
, (guint8
**)&fontdata
, &tt_len
, glyphs
, encoding
, num
,
868 0, NULL
, TTCF_AutoName
| TTCF_IncludeOS2
) == SF_OK
) {
869 make_xref(xref
, xref
->last
+1, pdfbuf
->len
);
870 nobj_fontprog
= xref
->last
;
871 g_string_append_printf(pdfbuf
,
872 "%d 0 obj\n<< /Length %u /Length1 %u >> stream\n",
873 nobj_fontprog
, tt_len
, tt_len
);
874 g_string_append_len(pdfbuf
, fontdata
, tt_len
);
875 g_string_append(pdfbuf
, "endstream\nendobj\n");
878 else fallback
= TRUE
;
881 else fallback
= TRUE
;
883 // embed the font file: Type1 case
884 if (g_file_get_contents(font
->filename
, &fontdata
, &t1_len
, NULL
) && t1_len
>=8) {
885 if (fontdata
[0]==(char)0x80 && fontdata
[1]==(char)0x01) {
887 len1
= pfb_get_length((unsigned char *)fontdata
+2);
888 if (fontdata
[len1
+6]!=(char)0x80 || fontdata
[len1
+7]!=(char)0x02) fallback
= TRUE
;
890 len2
= pfb_get_length((unsigned char *)fontdata
+len1
+8);
891 if (fontdata
[len1
+len2
+12]!=(char)0x80 || fontdata
[len1
+len2
+13]!=(char)0x01)
895 else if (!strncmp(fontdata
, "%!PS", 4)) {
897 p
= strstr(fontdata
, T1_SEGMENT_1_END
) + strlen(T1_SEGMENT_1_END
);
898 if (p
==NULL
) fallback
= TRUE
;
900 if (*p
=='\n' || *p
=='\r') p
++;
901 if (*p
=='\n' || *p
=='\r') p
++;
903 p
= g_strrstr_len(fontdata
, t1_len
, T1_SEGMENT_3_END
);
904 if (p
==NULL
) fallback
= TRUE
;
908 while (i
>0 && p
!=fontdata
&& (*p
=='0' || *p
=='\r' || *p
=='\n')) {
912 while (p
!=fontdata
&& (*p
=='\r' || *p
=='\n')) p
--;
914 if (i
>0) fallback
= TRUE
;
915 else len2
= p
-fontdata
-len1
;
919 else fallback
= TRUE
;
923 seg2
= fontdata
+ len1
+ 12;
926 seg2
= g_malloc(len2
/2);
929 while (p
+1 < fontdata
+len1
+len2
) {
930 if (*p
==' '||*p
=='\t'||*p
=='\n'||*p
=='\r') { p
++; continue; }
931 if (p
[0]>'9') { p
[0]|=0x20; p
[0]-=39; }
932 if (p
[1]>'9') { p
[1]|=0x20; p
[1]-=39; }
933 seg2
[j
++] = ((p
[0]-'0')<<4) + (p
[1]-'0');
938 make_xref(xref
, xref
->last
+1, pdfbuf
->len
);
939 nobj_fontprog
= xref
->last
;
940 g_string_append_printf(pdfbuf
,
941 "%d 0 obj\n<< /Length %u /Length1 %u /Length2 %u /Length3 0 >> stream\n",
942 nobj_fontprog
, len1
+len2
, len1
, len2
);
943 g_string_append_len(pdfbuf
, seg1
, len1
);
944 g_string_append_len(pdfbuf
, seg2
, len2
);
945 g_string_append(pdfbuf
, "endstream\nendobj\n");
946 if (!is_binary
) g_free(seg2
);
950 else fallback
= TRUE
;
953 // next, the font descriptor
955 make_xref(xref
, xref
->last
+1, pdfbuf
->len
);
956 nobj_descr
= xref
->last
;
957 g_string_append_printf(pdfbuf
,
958 "%d 0 obj\n<< /Type /FontDescriptor /FontName /%s /Flags %d "
959 "/FontBBox [%d %d %d %d] /ItalicAngle 0 /Ascent %d "
960 "/Descent %d /CapHeight %d /StemV 100 /%s %d 0 R >> endobj\n",
961 nobj_descr
, font
->fontname
, font
->flags
,
962 font
->xmin
, font
->ymin
, font
->xmax
, font
->ymax
,
963 font
->ascender
, -font
->descender
, font
->ascender
,
964 font
->is_truetype
? "FontFile2":"FontFile",
968 // finally, the font itself
969 /* Note: in Type1 case, font->glyphmap maps charcodes to glyph no's
970 in TrueType case, encoding lists the used charcodes by index,
971 glyphs list the used glyph no's by index
972 font->glyphmap maps charcodes to indices */
973 xref
->data
[font
->n_obj
] = pdfbuf
->len
;
974 if (font
->is_truetype
) lastchar
= encoding
[font
->num_glyphs_used
];
975 else lastchar
= font
->num_glyphs_used
;
977 font
->is_truetype
= FALSE
;
978 g_free(font
->fontname
);
979 font
->fontname
= g_strdup("Helvetica");
982 if (font
->is_truetype
) {
983 num
= font
->glyph_page
;
984 for (i
=0; i
<6; i
++) { prefix
[i
] = 'A'+(num
%26); num
/=26; }
985 prefix
[6]='+'; prefix
[7]=0;
987 g_string_append_printf(pdfbuf
,
988 "%d 0 obj\n<< /Type /Font /Subtype /%s /BaseFont /%s%s /Name /F%d ",
989 font
->n_obj
, font
->is_truetype
?"TrueType":"Type1",
990 prefix
, font
->fontname
, font
->n_obj
);
992 g_string_append_printf(pdfbuf
,
993 "/FontDescriptor %d 0 R /FirstChar 0 /LastChar %d /Widths [",
994 nobj_descr
, lastchar
);
995 for (i
=0; i
<=lastchar
; i
++)
996 g_string_append_printf(pdfbuf
, "%d ", font
->advance
[i
]);
997 g_string_append(pdfbuf
, "] ");
999 if (!font
->is_truetype
) { /* encoding */
1000 g_string_append(pdfbuf
, "/Encoding << /Type /Encoding "
1001 "/BaseEncoding /MacRomanEncoding /Differences [1 ");
1002 for (i
=1; i
<=lastchar
; i
++) {
1003 g_string_append_printf(pdfbuf
, "/%s ", font
->glyphpsnames
[i
]);
1004 g_free(font
->glyphpsnames
[i
]);
1006 g_string_append(pdfbuf
, "] >> ");
1008 g_string_append(pdfbuf
, ">> endobj\n");
1011 // draw a page's graphics
1013 void pdf_draw_page(struct Page
*pg
, GString
*str
, gboolean
*use_hiliter
,
1014 struct XrefTable
*xref
, GList
**pdffonts
)
1016 GList
*layerlist
, *itemlist
, *tmplist
;
1019 guint old_rgba
, old_text_rgba
;
1020 double old_thickness
;
1023 PangoFontDescription
*font_desc
;
1024 PangoContext
*context
;
1025 PangoLayout
*layout
;
1026 PangoLayoutIter
*iter
;
1027 PangoRectangle logical_rect
;
1028 PangoLayoutRun
*run
;
1029 PangoFcFont
*fcfont
;
1030 PangoFontMap
*fontmap
;
1032 int baseline
, advance
;
1033 int glyph_no
, glyph_page
, current_page
;
1038 struct PdfFont
*cur_font
;
1041 old_rgba
= old_text_rgba
= 0x12345678; // not any values we use, so we'll reset them
1042 old_thickness
= 0.0;
1043 for (tmplist
= *pdffonts
; tmplist
!=NULL
; tmplist
= tmplist
->next
) {
1044 cur_font
= (struct PdfFont
*)tmplist
->data
;
1045 cur_font
->used_in_this_page
= FALSE
;
1048 for (layerlist
= pg
->layers
; layerlist
!=NULL
; layerlist
= layerlist
->next
) {
1049 l
= (struct Layer
*)layerlist
->data
;
1050 for (itemlist
= l
->items
; itemlist
!=NULL
; itemlist
= itemlist
->next
) {
1051 item
= (struct Item
*)itemlist
->data
;
1052 if (item
->type
== ITEM_STROKE
) {
1053 if ((item
->brush
.color_rgba
& ~0xff) != old_rgba
)
1054 g_string_append_printf(str
, "%.2f %.2f %.2f RG ",
1055 RGBA_RGB(item
->brush
.color_rgba
));
1056 if (item
->brush
.thickness
!= old_thickness
)
1057 g_string_append_printf(str
, "%.2f w ", item
->brush
.thickness
);
1058 if ((item
->brush
.color_rgba
& 0xf0) != 0xf0) { // transparent
1059 g_string_append(str
, "q /XoHi gs ");
1060 *use_hiliter
= TRUE
;
1062 old_rgba
= item
->brush
.color_rgba
& ~0xff;
1063 old_thickness
= item
->brush
.thickness
;
1064 pt
= item
->path
->coords
;
1065 if (!item
->brush
.variable_width
) {
1066 g_string_append_printf(str
, "%.2f %.2f m ", pt
[0], pt
[1]);
1067 for (i
=1, pt
+=2; i
<item
->path
->num_points
; i
++, pt
+=2)
1068 g_string_append_printf(str
, "%.2f %.2f l ", pt
[0], pt
[1]);
1069 g_string_append_printf(str
,"S\n");
1070 old_thickness
= item
->brush
.thickness
;
1072 for (i
=0; i
<item
->path
->num_points
-1; i
++, pt
+=2)
1073 g_string_append_printf(str
, "%.2f w %.2f %.2f m %.2f %.2f l S\n",
1074 item
->widths
[i
], pt
[0], pt
[1], pt
[2], pt
[3]);
1075 old_thickness
= 0.0;
1077 if ((item
->brush
.color_rgba
& 0xf0) != 0xf0) // undo transparent
1078 g_string_append(str
, "Q ");
1080 else if (item
->type
== ITEM_TEXT
) {
1081 if ((item
->brush
.color_rgba
& ~0xff) != old_text_rgba
)
1082 g_string_append_printf(str
, "%.2f %.2f %.2f rg ",
1083 RGBA_RGB(item
->brush
.color_rgba
));
1084 old_text_rgba
= item
->brush
.color_rgba
& ~0xff;
1085 fontmap
= pango_ft2_font_map_new();
1086 pango_ft2_font_map_set_resolution(PANGO_FT2_FONT_MAP (fontmap
), 72, 72);
1087 context
= pango_context_new();
1088 pango_context_set_font_map(context
, fontmap
);
1089 layout
= pango_layout_new(context
);
1090 g_object_unref(fontmap
);
1091 g_object_unref(context
);
1092 font_desc
= pango_font_description_from_string(item
->font_name
);
1093 pango_font_description_set_absolute_size(font_desc
,
1094 item
->font_size
*PANGO_SCALE
);
1095 pango_layout_set_font_description(layout
, font_desc
);
1096 pango_font_description_free(font_desc
);
1097 pango_layout_set_text(layout
, item
->text
, -1);
1098 // this code inspired by the code in libgnomeprint
1099 iter
= pango_layout_get_iter(layout
);
1101 run
= pango_layout_iter_get_run(iter
);
1102 if (run
==NULL
) continue;
1103 pango_layout_iter_get_run_extents (iter
, NULL
, &logical_rect
);
1104 baseline
= pango_layout_iter_get_baseline (iter
);
1105 if (!PANGO_IS_FC_FONT(run
->item
->analysis
.font
)) continue;
1106 fcfont
= PANGO_FC_FONT(run
->item
->analysis
.font
);
1107 pattern
= fcfont
->font_pattern
;
1108 if (FcPatternGetString(pattern
, FC_FILE
, 0, (unsigned char **)&filename
) != FcResultMatch
||
1109 FcPatternGetInteger(pattern
, FC_INDEX
, 0, &font_id
) != FcResultMatch
)
1111 ftface
= pango_fc_font_lock_face(fcfont
);
1114 g_string_append_printf(str
, "BT %.2f 0 0 %.2f %.2f %.2f Tm ",
1115 item
->font_size
, -item
->font_size
,
1116 item
->bbox
.left
+ (gdouble
) logical_rect
.x
/PANGO_SCALE
,
1117 item
->bbox
.top
+ (gdouble
) baseline
/PANGO_SCALE
);
1119 for (i
=0; i
<run
->glyphs
->num_glyphs
; i
++) {
1120 glyph_no
= run
->glyphs
->glyphs
[i
].glyph
;
1121 if (FT_IS_SFNT(ftface
)) glyph_page
= glyph_no
/255;
1122 else glyph_page
= 0;
1123 if (glyph_page
!= current_page
) {
1124 cur_font
= new_pdffont(xref
, pdffonts
, filename
, font_id
,
1125 ftface
, glyph_page
);
1126 if (in_string
) g_string_append(str
, ") Tj ");
1128 g_string_append_printf(str
, "/F%d 1 Tf ", cur_font
->n_obj
);
1130 current_page
= glyph_page
;
1131 FT_Load_Glyph(ftface
, glyph_no
, FT_LOAD_NO_SCALE
| FT_LOAD_NO_HINTING
| FT_LOAD_NO_BITMAP
| FT_LOAD_IGNORE_TRANSFORM
);
1132 advance
= (int)(ftface
->glyph
->metrics
.horiAdvance
* cur_font
->ft2ps
+ 0.5);
1133 if (!in_string
) g_string_append_c(str
, '(');
1135 if (cur_font
->is_truetype
) {
1136 if (glyph_no
) glyph_no
= (glyph_no
%255)+1;
1137 cur_font
->glyphmap
[glyph_no
] = glyph_no
;
1140 for (j
=1; j
<=cur_font
->num_glyphs_used
; j
++)
1141 if (cur_font
->glyphmap
[j
] == glyph_no
) break;
1142 if (j
==256) j
=0; // font is full, what do we do?
1143 if (j
>cur_font
->num_glyphs_used
) {
1144 cur_font
->glyphmap
[j
] = glyph_no
;
1145 cur_font
->num_glyphs_used
++;
1146 if (FT_Get_Glyph_Name(ftface
, glyph_no
, tmpstr
, 200) == FT_Err_Ok
)
1147 cur_font
->glyphpsnames
[j
] = g_strdup(tmpstr
);
1148 else cur_font
->glyphpsnames
[j
] = g_strdup(".notdef");
1152 cur_font
->advance
[glyph_no
] = advance
;
1153 if (glyph_no
=='\\' || glyph_no
== '(' || glyph_no
== ')' || glyph_no
== 10 || glyph_no
== 13)
1154 g_string_append_c(str
, '\\');
1155 if (glyph_no
==10) g_string_append_c(str
,'n');
1156 else if (glyph_no
==13) g_string_append_c(str
,'r');
1157 else g_string_append_c(str
, glyph_no
);
1159 if (in_string
) g_string_append(str
, ") Tj ");
1160 g_string_append(str
, "ET ");
1161 pango_fc_font_unlock_face(fcfont
);
1162 } while (pango_layout_iter_next_run(iter
));
1163 pango_layout_iter_free(iter
);
1164 g_object_unref(layout
);
1170 // main printing function
1172 /* we use the following object numbers, starting with n_obj_catalog:
1173 0 the document catalog
1175 2 the GS for the hiliters
1176 3 ... the page objects
1179 gboolean
print_to_pdf(char *filename
)
1182 GString
*pdfbuf
, *pgstrm
, *zpgstrm
, *tmpstr
;
1183 int n_obj_catalog
, n_obj_pages_offs
, n_page
, n_obj_bgpix
, n_obj_prefix
;
1185 struct XrefTable xref
;
1188 gboolean annot
, uses_pdf
;
1189 gboolean use_hiliter
;
1190 struct PdfInfo pdfinfo
;
1192 GList
*pdffonts
, *list
;
1193 struct PdfFont
*font
;
1196 f
= fopen(filename
, "wb");
1197 if (f
== NULL
) return FALSE
;
1198 setlocale(LC_NUMERIC
, "C");
1203 for (pglist
= journal
.pages
; pglist
!=NULL
; pglist
= pglist
->next
) {
1204 pg
= (struct Page
*)pglist
->data
;
1205 if (pg
->bg
->type
== BG_PDF
) uses_pdf
= TRUE
;
1208 if (uses_pdf
&& bgpdf
.status
!= STATUS_NOT_INIT
&&
1209 bgpdf
.file_contents
!=NULL
&& !strncmp(bgpdf
.file_contents
, "%PDF-1.", 7)) {
1210 // parse the existing PDF file
1211 pdfbuf
= g_string_new_len(bgpdf
.file_contents
, bgpdf
.file_length
);
1212 if (pdfbuf
->str
[7]<'4') pdfbuf
->str
[7] = '4'; // upgrade to 1.4
1213 annot
= pdf_parse_info(pdfbuf
, &pdfinfo
, &xref
);
1215 g_string_free(pdfbuf
, TRUE
);
1216 if (xref
.data
!= NULL
) g_free(xref
.data
);
1221 pdfbuf
= g_string_new("%PDF-1.4\n%\370\357\365\362\n");
1222 xref
.n_alloc
= xref
.last
= 0;
1226 // catalog and page tree
1227 n_obj_catalog
= xref
.last
+1;
1228 n_obj_pages_offs
= xref
.last
+4;
1229 make_xref(&xref
, n_obj_catalog
, pdfbuf
->len
);
1230 g_string_append_printf(pdfbuf
,
1231 "%d 0 obj\n<< /Type /Catalog /Pages %d 0 R >> endobj\n",
1232 n_obj_catalog
, n_obj_catalog
+1);
1233 make_xref(&xref
, n_obj_catalog
+1, pdfbuf
->len
);
1234 g_string_append_printf(pdfbuf
,
1235 "%d 0 obj\n<< /Type /Pages /Kids [", n_obj_catalog
+1);
1236 for (i
=0;i
<journal
.npages
;i
++)
1237 g_string_append_printf(pdfbuf
, "%d 0 R ", n_obj_pages_offs
+i
);
1238 g_string_append_printf(pdfbuf
, "] /Count %d >> endobj\n", journal
.npages
);
1239 make_xref(&xref
, n_obj_catalog
+2, pdfbuf
->len
);
1240 g_string_append_printf(pdfbuf
,
1241 "%d 0 obj\n<< /Type /ExtGState /CA %.2f >> endobj\n",
1242 n_obj_catalog
+2, ui
.hiliter_opacity
);
1243 xref
.last
= n_obj_pages_offs
+ journal
.npages
-1;
1245 for (pglist
= journal
.pages
, n_page
= 0; pglist
!=NULL
;
1246 pglist
= pglist
->next
, n_page
++) {
1247 pg
= (struct Page
*)pglist
->data
;
1249 // draw the background and page into pgstrm
1250 pgstrm
= g_string_new("");
1251 g_string_printf(pgstrm
, "q 1 0 0 -1 0 %.2f cm 1 J 1 j ", pg
->height
);
1254 if (pg
->bg
->type
== BG_SOLID
)
1255 pdf_draw_solid_background(pg
, pgstrm
);
1256 else if (pg
->bg
->type
== BG_PDF
&& annot
&&
1257 pdfinfo
.pages
[pg
->bg
->file_page_seq
-1].contents
!=NULL
) {
1258 make_xref(&xref
, xref
.last
+1, pdfbuf
->len
);
1259 n_obj_prefix
= xref
.last
;
1260 tmpstr
= make_pdfprefix(pdfinfo
.pages
+(pg
->bg
->file_page_seq
-1),
1261 pg
->width
, pg
->height
);
1262 g_string_append_printf(pdfbuf
,
1263 "%d 0 obj\n<< /Length %zu >> stream\n%s\nendstream\nendobj\n",
1264 n_obj_prefix
, tmpstr
->len
, tmpstr
->str
);
1265 g_string_free(tmpstr
, TRUE
);
1266 g_string_prepend(pgstrm
, "Q Q Q ");
1268 else if (pg
->bg
->type
== BG_PIXMAP
|| pg
->bg
->type
== BG_PDF
)
1269 n_obj_bgpix
= pdf_draw_bitmap_background(pg
, pgstrm
, &xref
, pdfbuf
);
1270 // draw the page contents
1271 use_hiliter
= FALSE
;
1272 pdf_draw_page(pg
, pgstrm
, &use_hiliter
, &xref
, &pdffonts
);
1273 g_string_append_printf(pgstrm
, "Q\n");
1275 // deflate pgstrm and write it
1276 zpgstrm
= do_deflate(pgstrm
->str
, pgstrm
->len
);
1277 g_string_free(pgstrm
, TRUE
);
1279 make_xref(&xref
, xref
.last
+1, pdfbuf
->len
);
1280 g_string_append_printf(pdfbuf
,
1281 "%d 0 obj\n<< /Length %zu /Filter /FlateDecode>> stream\n",
1282 xref
.last
, zpgstrm
->len
);
1283 g_string_append_len(pdfbuf
, zpgstrm
->str
, zpgstrm
->len
);
1284 g_string_free(zpgstrm
, TRUE
);
1285 g_string_append(pdfbuf
, "endstream\nendobj\n");
1287 // write the page object
1289 make_xref(&xref
, n_obj_pages_offs
+n_page
, pdfbuf
->len
);
1290 g_string_append_printf(pdfbuf
,
1291 "%d 0 obj\n<< /Type /Page /Parent %d 0 R /MediaBox [0 0 %.2f %.2f] ",
1292 n_obj_pages_offs
+n_page
, n_obj_catalog
+1, pg
->width
, pg
->height
);
1293 if (n_obj_prefix
>0) {
1294 obj
= get_pdfobj(pdfbuf
, &xref
, pdfinfo
.pages
[pg
->bg
->file_page_seq
-1].contents
);
1295 if (obj
->type
!= PDFTYPE_ARRAY
) {
1297 obj
= dup_pdfobj(pdfinfo
.pages
[pg
->bg
->file_page_seq
-1].contents
);
1299 g_string_append_printf(pdfbuf
, "/Contents [%d 0 R ", n_obj_prefix
);
1300 if (obj
->type
== PDFTYPE_REF
)
1301 g_string_append_printf(pdfbuf
, "%d %d R ", obj
->intval
, obj
->num
);
1302 if (obj
->type
== PDFTYPE_ARRAY
) {
1303 for (i
=0; i
<obj
->num
; i
++) {
1304 show_pdfobj(obj
->elts
[i
], pdfbuf
);
1305 g_string_append_c(pdfbuf
, ' ');
1309 g_string_append_printf(pdfbuf
, "%d 0 R] ", xref
.last
);
1311 else g_string_append_printf(pdfbuf
, "/Contents %d 0 R ", xref
.last
);
1312 g_string_append(pdfbuf
, "/Resources ");
1315 obj
= dup_pdfobj(pdfinfo
.pages
[pg
->bg
->file_page_seq
-1].resources
);
1317 if (obj
!=NULL
&& obj
->type
!=PDFTYPE_DICT
)
1318 { free_pdfobj(obj
); obj
=NULL
; }
1320 obj
= g_malloc(sizeof(struct PdfObj
));
1321 obj
->type
= PDFTYPE_DICT
;
1326 add_dict_subentry(pdfbuf
, &xref
,
1327 obj
, "/ProcSet", PDFTYPE_ARRAY
, NULL
, mk_pdfname("/PDF"));
1329 add_dict_subentry(pdfbuf
, &xref
,
1330 obj
, "/ProcSet", PDFTYPE_ARRAY
, NULL
, mk_pdfname("/ImageC"));
1332 add_dict_subentry(pdfbuf
, &xref
,
1333 obj
, "/ExtGState", PDFTYPE_DICT
, "/XoHi", mk_pdfref(n_obj_catalog
+2));
1335 add_dict_subentry(pdfbuf
, &xref
,
1336 obj
, "/XObject", PDFTYPE_DICT
, "/ImBg", mk_pdfref(n_obj_bgpix
));
1337 for (list
=pdffonts
; list
!=NULL
; list
= list
->next
) {
1338 font
= (struct PdfFont
*)list
->data
;
1339 if (font
->used_in_this_page
) {
1340 add_dict_subentry(pdfbuf
, &xref
,
1341 obj
, "/ProcSet", PDFTYPE_ARRAY
, NULL
, mk_pdfname("/Text"));
1342 tmpbuf
= g_strdup_printf("/F%d", font
->n_obj
);
1343 add_dict_subentry(pdfbuf
, &xref
,
1344 obj
, "/Font", PDFTYPE_DICT
, tmpbuf
, mk_pdfref(font
->n_obj
));
1348 show_pdfobj(obj
, pdfbuf
);
1350 g_string_append(pdfbuf
, " >> endobj\n");
1353 // after the pages, we insert fonts
1354 for (list
= pdffonts
; list
!=NULL
; list
= list
->next
) {
1355 font
= (struct PdfFont
*)list
->data
;
1356 embed_pdffont(pdfbuf
, &xref
, font
);
1357 g_free(font
->filename
);
1358 g_free(font
->fontname
);
1361 g_list_free(pdffonts
);
1364 startxref
= pdfbuf
->len
;
1365 if (annot
) g_string_append_printf(pdfbuf
,
1366 "xref\n%d %d\n", n_obj_catalog
, xref
.last
-n_obj_catalog
+1);
1367 else g_string_append_printf(pdfbuf
,
1368 "xref\n0 %d\n0000000000 65535 f \n", xref
.last
+1);
1369 for (i
=n_obj_catalog
; i
<=xref
.last
; i
++)
1370 g_string_append_printf(pdfbuf
, "%010d 00000 n \n", xref
.data
[i
]);
1371 g_string_append_printf(pdfbuf
,
1372 "trailer\n<< /Size %d /Root %d 0 R ", xref
.last
+1, n_obj_catalog
);
1374 g_string_append_printf(pdfbuf
, "/Prev %d ", pdfinfo
.startxref
);
1375 // keeping encryption info somehow doesn't work.
1376 // xournal can't annotate encrypted PDFs anyway...
1378 obj = get_dict_entry(pdfinfo.trailerdict, "/Encrypt");
1380 g_string_append_printf(pdfbuf, "/Encrypt ");
1381 show_pdfobj(obj, pdfbuf);
1385 g_string_append_printf(pdfbuf
,
1386 ">>\nstartxref\n%d\n%%%%EOF\n", startxref
);
1390 free_pdfobj(pdfinfo
.trailerdict
);
1391 if (pdfinfo
.pages
!=NULL
)
1392 for (i
=0; i
<pdfinfo
.npages
; i
++) {
1393 free_pdfobj(pdfinfo
.pages
[i
].resources
);
1394 free_pdfobj(pdfinfo
.pages
[i
].mediabox
);
1395 free_pdfobj(pdfinfo
.pages
[i
].contents
);
1399 setlocale(LC_NUMERIC
, "");
1400 if (fwrite(pdfbuf
->str
, 1, pdfbuf
->len
, f
) < pdfbuf
->len
) {
1402 g_string_free(pdfbuf
, TRUE
);
1406 g_string_free(pdfbuf
, TRUE
);
1410 /*********** Printing via gtk-print **********/
1412 #if GTK_CHECK_VERSION(2, 10, 0)
1414 // does the same job as update_canvas_bg(), but to a print context
1416 void print_background(cairo_t
*cr
, struct Page
*pg
)
1421 PopplerPage
*pdfpage
;
1422 cairo_surface_t
*cr_pixbuf
;
1423 double pgwidth
, pgheight
;
1425 if (pg
->bg
->type
== BG_SOLID
) {
1426 cairo_set_source_rgb(cr
, RGBA_RGB(pg
->bg
->color_rgba
));
1427 cairo_rectangle(cr
, 0, 0, pg
->width
, pg
->height
);
1429 if (!ui
.print_ruling
) return;
1430 if (pg
->bg
->ruling
== RULING_NONE
) return;
1431 cairo_set_source_rgb(cr
, RGBA_RGB(RULING_COLOR
));
1432 cairo_set_line_width(cr
, RULING_THICKNESS
);
1434 if (pg
->bg
->ruling
== RULING_GRAPH
) {
1435 for (x
=RULING_GRAPHSPACING
; x
<pg
->width
-1; x
+=RULING_GRAPHSPACING
)
1436 { cairo_move_to(cr
, x
, 0); cairo_line_to(cr
, x
, pg
->height
); }
1437 for (y
=RULING_GRAPHSPACING
; y
<pg
->height
-1; y
+=RULING_GRAPHSPACING
)
1438 { cairo_move_to(cr
, 0, y
); cairo_line_to(cr
, pg
->width
, y
); }
1443 for (y
=RULING_TOPMARGIN
; y
<pg
->height
-1; y
+=RULING_SPACING
)
1444 { cairo_move_to(cr
, 0, y
); cairo_line_to(cr
, pg
->width
, y
); }
1446 if (pg
->bg
->ruling
== RULING_LINED
) {
1447 cairo_set_source_rgb(cr
, RGBA_RGB(RULING_MARGIN_COLOR
));
1448 cairo_move_to(cr
, RULING_LEFTMARGIN
, 0);
1449 cairo_line_to(cr
, RULING_LEFTMARGIN
, pg
->height
);
1455 if (pg
->bg
->type
== BG_PDF
) {
1456 if (!bgpdf
.document
) return;
1457 pdfpage
= poppler_document_get_page(bgpdf
.document
, pg
->bg
->file_page_seq
-1);
1458 if (!pdfpage
) return;
1459 poppler_page_get_size(pdfpage
, &pgwidth
, &pgheight
);
1461 cairo_scale(cr
, pg
->width
/pgwidth
, pg
->height
/pgheight
);
1462 poppler_page_render(pdfpage
, cr
);
1464 g_object_unref(pdfpage
);
1467 if (pg
->bg
->type
== BG_PIXMAP
) {
1469 cairo_scale(cr
, pg
->width
/gdk_pixbuf_get_width(pg
->bg
->pixbuf
),
1470 pg
->height
/gdk_pixbuf_get_height(pg
->bg
->pixbuf
));
1471 gdk_cairo_set_source_pixbuf(cr
, pg
->bg
->pixbuf
, 0, 0);
1472 cairo_rectangle(cr
, 0, 0, gdk_pixbuf_get_width(pg
->bg
->pixbuf
), gdk_pixbuf_get_height(pg
->bg
->pixbuf
));
1478 void print_job_render_page(GtkPrintOperation
*print
, GtkPrintContext
*context
, gint pageno
, gpointer user_data
)
1481 gdouble width
, height
, scale
;
1484 double old_thickness
;
1485 GList
*layerlist
, *itemlist
;
1490 PangoFontDescription
*font_desc
;
1491 PangoLayout
*layout
;
1493 pg
= (struct Page
*)g_list_nth_data(journal
.pages
, pageno
);
1494 cr
= gtk_print_context_get_cairo_context(context
);
1495 width
= gtk_print_context_get_width(context
);
1496 height
= gtk_print_context_get_height(context
);
1497 scale
= MIN(width
/pg
->width
, height
/pg
->height
);
1499 cairo_translate(cr
, (width
-scale
*pg
->width
)/2, (height
-scale
*pg
->height
)/2);
1500 cairo_scale(cr
, scale
, scale
);
1501 cairo_set_line_join(cr
, CAIRO_LINE_JOIN_ROUND
);
1502 cairo_set_line_cap(cr
, CAIRO_LINE_CAP_ROUND
);
1504 print_background(cr
, pg
);
1506 old_rgba
= predef_colors_rgba
[COLOR_BLACK
];
1507 cairo_set_source_rgb(cr
, 0, 0, 0);
1508 old_thickness
= 0.0;
1510 for (layerlist
= pg
->layers
; layerlist
!=NULL
; layerlist
= layerlist
->next
) {
1511 l
= (struct Layer
*)layerlist
->data
;
1512 for (itemlist
= l
->items
; itemlist
!=NULL
; itemlist
= itemlist
->next
) {
1513 item
= (struct Item
*)itemlist
->data
;
1514 if (item
->type
== ITEM_STROKE
|| item
->type
== ITEM_TEXT
) {
1515 if (item
->brush
.color_rgba
!= old_rgba
)
1516 cairo_set_source_rgba(cr
, RGBA_RGB(item
->brush
.color_rgba
),
1517 RGBA_ALPHA(item
->brush
.color_rgba
));
1518 old_rgba
= item
->brush
.color_rgba
;
1520 if (item
->type
== ITEM_STROKE
) {
1521 if (item
->brush
.thickness
!= old_thickness
)
1522 cairo_set_line_width(cr
, item
->brush
.thickness
);
1523 pt
= item
->path
->coords
;
1524 if (!item
->brush
.variable_width
) {
1525 cairo_move_to(cr
, pt
[0], pt
[1]);
1526 for (i
=1, pt
+=2; i
<item
->path
->num_points
; i
++, pt
+=2)
1527 cairo_line_to(cr
, pt
[0], pt
[1]);
1529 old_thickness
= item
->brush
.thickness
;
1531 for (i
=0; i
<item
->path
->num_points
-1; i
++, pt
+=2) {
1532 cairo_move_to(cr
, pt
[0], pt
[1]);
1533 cairo_set_line_width(cr
, item
->widths
[i
]);
1534 cairo_line_to(cr
, pt
[2], pt
[3]);
1537 old_thickness
= 0.0;
1540 if (item
->type
== ITEM_TEXT
) {
1541 layout
= gtk_print_context_create_pango_layout(context
);
1542 font_desc
= pango_font_description_from_string(item
->font_name
);
1543 if (item
->font_size
)
1544 pango_font_description_set_absolute_size(font_desc
,
1545 item
->font_size
*PANGO_SCALE
);
1546 pango_layout_set_font_description(layout
, font_desc
);
1547 pango_font_description_free(font_desc
);
1548 pango_layout_set_text(layout
, item
->text
, -1);
1549 cairo_move_to(cr
, item
->bbox
.left
, item
->bbox
.top
);
1550 pango_cairo_show_layout(cr
, layout
);
1551 g_object_unref(layout
);