1 /* PDF post-processor functions */
11 static char pdf_title
[256]; /* document title */
12 static char pdf_author
[256]; /* document author */
13 static int pdf_width
; /* page width */
14 static int pdf_height
; /* page height */
15 static int pdf_linewid
; /* line width in thousands of ems */
16 static int pdf_linecap
= 1; /* line cap style: 0 (butt), 1 (round), 2 (projecting square) */
17 static int pdf_linejoin
= 1; /* line join style: 0 (miter), 1 (round), 2 (bevel) */
18 static int pdf_pages
; /* pages object id */
19 static int pdf_root
; /* root object id */
20 static int pdf_pos
; /* current pdf file offset */
21 static int *obj_off
; /* object offsets */
22 static int obj_sz
, obj_n
; /* number of pdf objects */
23 static int *page_id
; /* page object ids */
24 static int page_sz
, page_n
; /* number of pages */
25 static int pdf_outline
; /* pdf outline hierarchiy */
26 static int pdf_dests
; /* named destinations */
28 static struct sbuf
*pg
; /* current page contents */
29 static int o_f
, o_s
, o_m
; /* font and size */
30 static int o_h
, o_v
; /* current user position */
31 static int p_h
, p_v
; /* current output position */
32 static int o_i
, p_i
; /* output and pdf fonts (indices into pfont[]) */
33 static int p_f
, p_s
, p_m
; /* output font */
34 static int o_queued
; /* queued character type */
35 static char o_iset
[1024]; /* fonts accesssed in this page */
36 static int xobj
[128]; /* page xobject object ids */
37 static int xobj_n
; /* number of xobjects in this page */
38 static int ann
[128]; /* page annotations */
39 static int ann_n
; /* number of annotations in this page */
41 /* loaded PDF fonts */
43 char name
[128]; /* font PostScript name */
44 char path
[1024]; /* font path */
45 char desc
[1024]; /* font descriptor path */
46 int gbeg
; /* the first glyph */
47 int gend
; /* the last glyph */
48 int sub
; /* subfont number */
49 int obj
; /* the font object */
50 int des
; /* font descriptor */
51 int cid
; /* CID-indexed */
54 static struct pfont
*pfonts
;
55 static int pfonts_n
, pfonts_sz
;
57 /* print formatted pdf output */
58 static void pdfout(char *s
, ...)
62 pdf_pos
+= vprintf(s
, ap
);
66 /* print pdf output */
67 static void pdfmem(char *s
, int len
)
69 fwrite(s
, len
, 1, stdout
);
73 /* allocate an object number */
74 static int obj_map(void)
76 if (obj_n
== obj_sz
) {
78 obj_off
= mextend(obj_off
, obj_n
, obj_sz
, sizeof(obj_off
[0]));
83 /* start the definition of an object */
84 static int obj_beg(int id
)
88 obj_off
[id
] = pdf_pos
;
89 pdfout("%d 0 obj\n", id
);
93 /* end an object definition */
94 static void obj_end(void)
99 void out(char *s
, ...)
103 /* the length of the clear-text, encrypted, and fixed-content portions */
104 static int type1lengths(char *t1
, int l
, int *l1
, int *l2
, int *l3
)
107 char *cleartext
= t1
;
108 char *encrypted
= NULL
;
109 char *fixedcont
= NULL
;
110 for (i
= 0; i
< l
- 5 && !encrypted
; i
++)
111 if (t1
[i
] == 'e' && !memcmp("eexec", t1
+ i
, 5))
115 for (; i
< l
- 512 && !fixedcont
; i
++)
116 if (t1
[i
] == '0' && !memcmp("00000", t1
+ i
, 5))
118 *l1
= encrypted
- cleartext
;
119 *l2
= fixedcont
? fixedcont
- cleartext
: 0;
120 *l3
= fixedcont
? t1
+ l
- fixedcont
: 0;
124 /* return font type: 't': TrueType, '1': Type 1, 'o': OpenType */
125 static int fonttype(char *path
)
127 char *ext
= strrchr(path
, '.');
128 if (ext
&& !strcmp(".ttf", ext
))
130 if (ext
&& !strcmp(".otf", ext
))
132 if (ext
&& (!strcmp(".ttc", ext
) || !strcmp(".otc", ext
)))
137 /* write the object corresponding to the given font */
138 static void pfont_write(struct pfont
*ps
)
142 struct font
*fn
= dev_fontopen(ps
->desc
);
143 /* the encoding object */
144 enc_obj
= obj_beg(0);
146 pdfout(" /Type /Encoding\n");
147 pdfout(" /Differences [ %d", ps
->gbeg
% 256);
148 for (i
= ps
->gbeg
; i
<= ps
->gend
; i
++)
149 pdfout(" /%s", font_glget(fn
, i
)->id
);
153 /* the font object */
156 pdfout(" /Type /Font\n");
157 if (fonttype(ps
->path
) == 't')
158 pdfout(" /Subtype /TrueType\n");
160 pdfout(" /Subtype /Type1\n");
161 pdfout(" /BaseFont /%s\n", ps
->name
);
162 pdfout(" /FirstChar %d\n", ps
->gbeg
% 256);
163 pdfout(" /LastChar %d\n", ps
->gend
% 256);
164 pdfout(" /Widths [");
165 for (i
= ps
->gbeg
; i
<= ps
->gend
; i
++)
166 pdfout(" %d", (long) font_glget(fn
, i
)->wid
* 100 * 72 / dev_res
);
168 pdfout(" /FontDescriptor %d 0 R\n", ps
->des
);
169 pdfout(" /Encoding %d 0 R\n", enc_obj
);
175 static void encodehex(struct sbuf
*d
, char *s
, int n
)
177 static char hex
[] = "0123456789ABCDEF";
179 for (i
= 0; i
< n
; i
++) {
180 sbuf_chr(d
, hex
[((unsigned char) s
[i
]) >> 4]);
181 sbuf_chr(d
, hex
[((unsigned char) s
[i
]) & 0x0f]);
182 if (i
% 40 == 39 && i
+ 1 < n
)
188 /* write the object corresponding to this CID font */
189 static void pfont_writecid(struct pfont
*ps
)
192 struct font
*fn
= dev_fontopen(ps
->desc
);
196 cid_obj
= obj_beg(0);
198 pdfout(" /Type /Font\n");
199 pdfout(" /Subtype /CIDFontType2\n");
200 pdfout(" /BaseFont /%s\n", ps
->name
);
201 pdfout(" /CIDSystemInfo <</Ordering(Identity)/Registry(Adobe)/Supplement 0>>\n");
202 pdfout(" /FontDescriptor %d 0 R\n", ps
->des
);
203 pdfout(" /DW 1000\n");
204 while (font_glget(fn
, gcnt
))
206 pdfout(" /W [ %d [", ps
->gbeg
);
207 for (i
= ps
->gbeg
; i
<= ps
->gend
; i
++)
208 pdfout(" %d", (long) font_glget(fn
, i
)->wid
* 100 * 72 / dev_res
);
212 /* the font object */
215 pdfout(" /Type /Font\n");
216 pdfout(" /Subtype /Type0\n");
217 pdfout(" /BaseFont /%s\n", ps
->name
);
218 pdfout(" /Encoding /Identity-H\n");
219 pdfout(" /DescendantFonts [%d 0 R]\n", cid_obj
);
225 /* write font descriptor; returns its object ID */
226 static int writedesc(struct font
*fn
)
231 int fntype
= fonttype(font_path(fn
));
232 if (fntype
== '1' || fntype
== 't') {
233 int fd
= open(font_path(fn
), O_RDONLY
);
234 struct sbuf
*ffsb
= sbuf_make();
235 struct sbuf
*sb
= sbuf_make();
236 int l1
= 0, l2
= 0, l3
= 0;
238 /* reading the font file */
239 while ((nr
= read(fd
, buf
, sizeof(buf
))) > 0)
240 sbuf_mem(ffsb
, buf
, nr
);
243 /* initialize Type 1 lengths */
245 if (type1lengths(sbuf_buf(ffsb
), sbuf_len(ffsb
),
248 /* remove the fixed-content portion of the font */
250 sbuf_cut(ffsb
, l1
+ l2
);
254 /* encoding file contents */
255 encodehex(sb
, sbuf_buf(ffsb
), sbuf_len(ffsb
));
256 /* write font data if it has nonzero length */
258 str_obj
= obj_beg(0);
260 pdfout(" /Filter /ASCIIHexDecode\n");
261 pdfout(" /Length %d\n", sbuf_len(sb
));
262 pdfout(" /Length1 %d\n", l1
);
264 pdfout(" /Length2 %d\n", l2
);
266 pdfout(" /Length3 %d\n", l3
);
269 pdfmem(sbuf_buf(sb
), sbuf_len(sb
));
270 pdfout("endstream\n");
276 /* the font descriptor */
277 des_obj
= obj_beg(0);
279 pdfout(" /Type /FontDescriptor\n");
280 pdfout(" /FontName /%s\n", font_name(fn
));
281 pdfout(" /Flags 32\n");
282 pdfout(" /FontBBox [-1000 -1000 1000 1000]\n");
283 pdfout(" /MissingWidth 1000\n");
284 pdfout(" /StemV 100\n");
285 pdfout(" /ItalicAngle 0\n");
286 pdfout(" /CapHeight 100\n");
287 pdfout(" /Ascent 100\n");
288 pdfout(" /Descent 100\n");
290 pdfout(" /FontFile%s %d 0 R\n",
291 fntype
== 't' ? "2" : "", str_obj
);
297 static int pfont_find(struct glyph
*g
)
299 struct font
*fn
= g
->font
;
300 char *name
= font_name(fn
);
301 struct pfont
*ps
= NULL
;
302 int fntype
= fonttype(font_path(fn
));
303 int sub
= fntype
== '1' ? font_glnum(fn
, g
) / 256 : 0;
305 for (i
= 0; i
< pfonts_n
; i
++)
306 if (!strcmp(name
, pfonts
[i
].name
) && pfonts
[i
].sub
== sub
)
308 if (pfonts_n
== pfonts_sz
) {
310 pfonts
= mextend(pfonts
, pfonts_n
,
311 pfonts_sz
, sizeof(pfonts
[0]));
313 ps
= &pfonts
[pfonts_n
];
314 snprintf(ps
->name
, sizeof(ps
->name
), "%s", name
);
315 snprintf(ps
->path
, sizeof(ps
->path
), "%s", font_path(fn
));
316 snprintf(ps
->desc
, sizeof(ps
->desc
), "%s", font_desc(fn
));
317 ps
->cid
= fntype
== 't';
321 for (i
= 0; i
< pfonts_n
; i
++)
322 if (!strcmp(pfonts
[i
].name
, ps
->name
))
325 ps
->des
= pfonts
[i
].des
;
327 ps
->des
= writedesc(fn
);
331 static void pfont_done(void)
334 for (i
= 0; i
< pfonts_n
; i
++) {
336 pfont_writecid(&pfonts
[i
]);
338 pfont_write(&pfonts
[i
]);
343 static void o_flush(void)
346 sbuf_printf(pg
, ">] TJ\n");
350 static int o_loadfont(struct glyph
*g
)
352 int fn
= pfont_find(g
);
357 /* like pdfpos() but assume that uh and uv are multiplied by 100 */
358 static char *pdfpos00(int uh
, int uv
)
361 int h
= (long) uh
* 72 / dev_res
;
362 int v
= (long) pdf_height
* 100 - (long) uv
* 72 / dev_res
;
363 sprintf(buf
, "%s%d.%02d %s%d.%02d",
364 h
< 0 ? "-" : "", abs(h
) / 100, abs(h
) % 100,
365 v
< 0 ? "-" : "", abs(v
) / 100, abs(v
) % 100);
369 /* convert troff position to pdf position; returns a static buffer */
370 static char *pdfpos(int uh
, int uv
)
372 return pdfpos00(uh
* 100, uv
* 100);
375 /* troff length to thousands of a unit of text space; returns a static buffer */
376 static char *pdfunit(int uh
, int sz
)
379 int h
= (long) uh
* 1000 * 72 / sz
/ dev_res
;
380 sprintf(buf
, "%s%d", h
< 0 ? "-" : "", abs(h
));
384 /* convert troff color to pdf color; returns a static buffer */
385 static char *pdfcolor(int m
)
388 int r
= CLR_R(m
) * 1000 / 255;
389 int g
= CLR_G(m
) * 1000 / 255;
390 int b
= CLR_B(m
) * 1000 / 255;
391 sbuf_printf(pg
, "%d.%03d %d.%03d %d.%03d",
392 r
/ 1000, r
% 1000, g
/ 1000, g
% 1000, b
/ 1000, b
% 1000);
396 static void o_queue(struct glyph
*g
)
401 sbuf_printf(pg
, "1 0 0 1 %s Tm\n", pdfpos(o_h
, o_v
));
406 sbuf_printf(pg
, "[<");
409 sbuf_printf(pg
, "> %s <", pdfunit(p_h
- o_h
, o_s
));
410 /* printing glyph identifier */
411 gid
= font_glnum(g
->font
, g
);
413 sbuf_printf(pg
, "%04x", gid
);
415 sbuf_printf(pg
, "%02x", gid
% 256);
416 /* updating gbeg and gend */
417 if (gid
< pfonts
[o_i
].gbeg
)
418 pfonts
[o_i
].gbeg
= gid
;
419 if (gid
> pfonts
[o_i
].gend
)
420 pfonts
[o_i
].gend
= gid
;
422 p_h
= o_h
+ font_wid(g
->font
, o_s
, g
->wid
);
425 static void out_fontup(void)
429 sbuf_printf(pg
, "%s rg\n", pdfcolor(o_m
));
432 if (o_i
>= 0 && (o_i
!= p_i
|| o_s
!= p_s
)) {
433 struct pfont
*ps
= &pfonts
[o_i
];
436 sbuf_printf(pg
, "/%s %d Tf\n", ps
->name
, o_s
);
438 sbuf_printf(pg
, "/%s.%d %d Tf\n", ps
->name
, ps
->sub
, o_s
);
448 g
= dev_glyph(c
, o_f
);
449 fn
= g
? g
->font
: dev_font(o_f
);
451 outrel(*c
== ' ' && fn
? font_swid(fn
, o_s
) : 1, 0);
469 void outrel(int h
, int v
)
492 void outrotate(int deg
)
496 void outeps(char *eps
, int hwid
, int vwid
)
500 /* return a copy of a PDF object; returns a static buffer */
501 static char *pdf_copy(char *pdf
, int len
, int pos
)
503 static char buf
[1 << 12];
505 pos
+= pdf_ws(pdf
, len
, pos
);
506 datlen
= pdf_len(pdf
, len
, pos
);
507 if (datlen
> sizeof(buf
) - 1)
508 datlen
= sizeof(buf
) - 1;
509 memcpy(buf
, pdf
+ pos
, datlen
);
514 static void pdf_dictcopy(char *pdf
, int len
, int pos
, struct sbuf
*sb
);
516 /* write stream to sb */
517 static int pdf_strcopy(char *pdf
, int len
, int pos
, struct sbuf
*sb
)
521 if ((val
= pdf_dval_val(pdf
, len
, pos
, "/Length")) < 0)
523 slen
= atoi(pdf
+ val
);
524 pos
= pos
+ pdf_len(pdf
, len
, pos
);
525 pos
+= pdf_ws(pdf
, len
, pos
);
526 if (pos
+ slen
+ 15 > len
)
529 pos
+= strlen("stream");
530 if (pdf
[pos
] == '\r')
533 if (pdf
[pos
] == '\r' || pdf
[pos
] == ' ')
535 if (pdf
[pos
] == '\n')
537 pos
+= strlen("endstream") + 1;
538 sbuf_mem(sb
, pdf
+ beg
, pos
- beg
);
542 /* copy a PDF object and return its new identifier */
543 static int pdf_objcopy(char *pdf
, int len
, int pos
)
546 if ((pos
= pdf_ref(pdf
, len
, pos
)) < 0)
548 if (pdf_type(pdf
, len
, pos
) == 'd') {
549 struct sbuf
*sb
= sbuf_make();
550 pdf_dictcopy(pdf
, len
, pos
, sb
);
552 if (pdf_dval(pdf
, len
, pos
, "/Length") >= 0)
553 pdf_strcopy(pdf
, len
, pos
, sb
);
555 pdfmem(sbuf_buf(sb
), sbuf_len(sb
));
560 pdfmem(pdf
+ pos
, pdf_len(pdf
, len
, pos
));
567 /* copy a PDF dictionary recursively */
568 static void pdf_dictcopy(char *pdf
, int len
, int pos
, struct sbuf
*sb
)
572 sbuf_printf(sb
, "<<");
574 if ((key
= pdf_dkey(pdf
, len
, pos
, i
)) < 0)
576 sbuf_printf(sb
, " %s", pdf_copy(pdf
, len
, key
));
577 val
= pdf_dval(pdf
, len
, pos
, pdf_copy(pdf
, len
, key
));
578 if (pdf_type(pdf
, len
, val
) == 'r') {
579 if ((id
= pdf_objcopy(pdf
, len
, val
)) >= 0)
580 sbuf_printf(sb
, " %d 0 R", id
);
582 sbuf_printf(sb
, " %s", pdf_copy(pdf
, len
, val
));
585 sbuf_printf(sb
, " >>");
588 /* copy resources dictionary */
589 static void pdf_rescopy(char *pdf
, int len
, int pos
, struct sbuf
*sb
)
591 char *res_fields
[] = {"/ProcSet", "/ExtGState", "/ColorSpace",
592 "/Pattern", "/Shading", "/Properties", "/Font", "/XObject"};
594 sbuf_printf(sb
, " /Resources <<\n");
595 for (i
= 0; i
< LEN(res_fields
); i
++) {
596 if ((res
= pdf_dval_val(pdf
, len
, pos
, res_fields
[i
])) >= 0) {
597 if (pdf_type(pdf
, len
, res
) == 'd') {
598 sbuf_printf(sb
, " %s ", res_fields
[i
]);
599 pdf_dictcopy(pdf
, len
, res
, sb
);
600 sbuf_printf(sb
, "\n");
602 sbuf_printf(sb
, " %s %s\n", res_fields
[i
],
603 pdf_copy(pdf
, len
, res
));
607 sbuf_printf(sb
, " >>\n");
610 static int pdfbbox100(char *pdf
, int len
, int pos
, int dim
[4])
614 for (i
= 0; i
< 4; i
++) {
615 int n
= 0, f1
= 0, f2
= 0;
616 if ((val
= pdf_lval(pdf
, len
, pos
, i
)) < 0)
618 for (; isdigit((unsigned char) pdf
[val
]); val
++)
619 n
= n
* 10 + pdf
[val
] - '0';
620 if (pdf
[val
] == '.') {
621 if (isdigit((unsigned char) pdf
[val
+ 1])) {
622 f1
= pdf
[val
+ 1] - '0';
623 if (isdigit((unsigned char) pdf
[val
+ 2]))
624 f2
= pdf
[val
+ 2] - '0';
627 dim
[i
] = n
* 100 + f1
* 10 + f2
;
632 static int pdfext(char *pdf
, int len
, int hwid
, int vwid
)
634 char *cont_fields
[] = {"/Filter", "/DecodeParms"};
635 int trailer
, root
, cont
, pages
, page1
, res
;
636 int kids_val
, page1_val
, val
, bbox
;
639 int hzoom
= 100, vzoom
= 100;
642 if (xobj_n
== LEN(xobj
))
644 if ((trailer
= pdf_trailer(pdf
, len
)) < 0)
646 if ((root
= pdf_dval_obj(pdf
, len
, trailer
, "/Root")) < 0)
648 if ((pages
= pdf_dval_obj(pdf
, len
, root
, "/Pages")) < 0)
650 if ((kids_val
= pdf_dval_val(pdf
, len
, pages
, "/Kids")) < 0)
652 if ((page1_val
= pdf_lval(pdf
, len
, kids_val
, 0)) < 0)
654 if ((page1
= pdf_ref(pdf
, len
, page1_val
)) < 0)
656 if ((cont
= pdf_dval_obj(pdf
, len
, page1
, "/Contents")) < 0)
658 if ((val
= pdf_dval_val(pdf
, len
, cont
, "/Length")) < 0)
660 res
= pdf_dval_val(pdf
, len
, page1
, "/Resources");
661 length
= atoi(pdf
+ val
);
662 bbox
= pdf_dval_val(pdf
, len
, page1
, "/MediaBox");
664 bbox
= pdf_dval_val(pdf
, len
, pages
, "/MediaBox");
665 if (bbox
>= 0 && !pdfbbox100(pdf
, len
, bbox
, dim
)) {
667 hzoom
= (long) hwid
* (100 * 7200 / dev_res
) / (dim
[2] - dim
[0]);
669 vzoom
= (long) vwid
* (100 * 7200 / dev_res
) / (dim
[3] - dim
[1]);
676 sbuf_printf(sb
, "<<\n");
677 sbuf_printf(sb
, " /Type /XObject\n");
678 sbuf_printf(sb
, " /Subtype /Form\n");
679 sbuf_printf(sb
, " /FormType 1\n");
681 sbuf_printf(sb
, " /BBox %s\n", pdf_copy(pdf
, len
, bbox
));
682 sbuf_printf(sb
, " /Matrix [%d.%02d 0 0 %d.%02d %s]\n",
683 hzoom
/ 100, hzoom
% 100, vzoom
/ 100, vzoom
% 100,
686 pdf_rescopy(pdf
, len
, res
, sb
);
687 sbuf_printf(sb
, " /Length %d\n", length
);
688 for (i
= 0; i
< LEN(cont_fields
); i
++)
689 if ((val
= pdf_dval_val(pdf
, len
, cont
, cont_fields
[i
])) >= 0)
690 sbuf_printf(sb
, " %s %s\n", cont_fields
[i
],
691 pdf_copy(pdf
, len
, val
));
692 sbuf_printf(sb
, ">>\n");
693 pdf_strcopy(pdf
, len
, cont
, sb
);
694 xobj_id
= obj_beg(0);
695 pdfmem(sbuf_buf(sb
), sbuf_len(sb
));
698 xobj
[xobj_n
++] = xobj_id
;
702 void outpdf(char *pdf
, int hwid
, int vwid
)
708 /* reading the pdf file */
710 fd
= open(pdf
, O_RDONLY
);
711 while ((nr
= read(fd
, buf
, sizeof(buf
))) > 0)
712 sbuf_mem(sb
, buf
, nr
);
715 xobj_id
= pdfext(sbuf_buf(sb
), sbuf_len(sb
), hwid
, vwid
);
720 sbuf_printf(pg
, "ET /FO%d Do BT\n", xobj_id
);
725 void outlink(char *lnk
, int hwid
, int vwid
)
727 if (ann_n
== LEN(ann
))
730 ann
[ann_n
++] = obj_beg(0);
732 pdfout(" /Type /Annot\n");
733 pdfout(" /Subtype /Link\n");
734 pdfout(" /Rect [%s", pdfpos(o_h
, o_v
));
735 pdfout(" %s]\n", pdfpos(o_h
+ hwid
, o_v
+ vwid
));
736 if (lnk
[0] == '#') { /* internal links */
737 pdfout(" /A << /S /GoTo /D (%s) >>\n", lnk
+ 1);
738 } else { /* external links */
739 pdfout(" /A << /S /URI /URI %s >>\n", pdftext_static(lnk
));
745 void outname(int n
, char (*desc
)[64], int *page
, int *off
)
749 pdf_dests
= obj_beg(0);
751 for (i
= 0; i
< n
; i
++) {
752 if (page
[i
] > 0 && page
[i
] - 1 < page_n
)
753 pdfout(" /%s [ %d 0 R /XYZ 0 %d 0 ]\n",
754 desc
[i
], page_id
[page
[i
] - 1],
755 pdf_height
- (off
[i
] * 72 / dev_res
));
761 void outmark(int n
, char (*desc
)[256], int *page
, int *off
, int *level
)
763 int *objs
= malloc(n
* sizeof(objs
[0]));
766 /* allocating objects */
767 pdf_outline
= obj_map();
768 for (i
= 0; i
< n
; i
++)
772 obj_beg(pdf_outline
);
774 for (i
= 0; i
< n
; i
++)
775 if (level
[i
] == level
[0])
777 pdfout(" /Count %d\n", cnt
);
778 pdfout(" /First %d 0 R\n", objs
[0]);
779 for (i
= n
- 1; i
> 0 && level
[i
] > level
[0]; i
--)
781 pdfout(" /Last %d 0 R\n", objs
[i
]);
785 for (i
= 0; i
< n
; i
++) {
787 for (j
= i
+ 1; j
< n
&& level
[j
] > level
[i
]; j
++)
788 if (level
[j
] == level
[i
] + 1)
792 pdfout(" /Title %s\n", pdftext_static(desc
[i
]));
793 /* the parent field */
794 for (j
= i
- 1; j
>= 0 && level
[j
] >= level
[i
]; j
--)
796 pdfout(" /Parent %d 0 R\n", j
>= 0 ? objs
[j
] : pdf_outline
);
798 for (j
= i
+ 1; j
< n
&& level
[j
] > level
[i
]; j
++)
800 if (j
< n
&& level
[j
] == level
[i
])
801 pdfout(" /Next %d 0 R\n", objs
[j
]);
803 for (j
= i
- 1; j
>= 0 && level
[j
] > level
[i
]; j
--)
805 if (j
>= 0 && level
[j
] == level
[i
])
806 pdfout(" /Prev %d 0 R\n", objs
[j
]);
810 pdfout(" /Count %d\n", cnt
);
811 pdfout(" /First %d 0 R\n", objs
[i
+ 1]);
812 for (j
= i
+ 1; j
< n
&& level
[j
] > level
[i
]; j
++)
813 if (level
[j
] == level
[i
] + 1)
815 pdfout(" /Last %d 0 R\n", objs
[last
]);
817 if (page
[i
] > 0 && page
[i
] - 1 < page_n
)
818 pdfout(" /Dest [ %d 0 R /XYZ 0 %d 0 ]\n",
819 page_id
[page
[i
] - 1],
820 pdf_height
- (off
[i
] * 72 / dev_res
));
827 void outinfo(char *kwd
, char *val
)
829 if (!strcmp("Author", kwd
))
830 snprintf(pdf_author
, sizeof(pdf_author
), "%s", val
);
831 if (!strcmp("Title", kwd
))
832 snprintf(pdf_title
, sizeof(pdf_title
), "%s", val
);
835 void outset(char *var
, char *val
)
837 if (!strcmp("linewidth", var
))
838 pdf_linewid
= atoi(val
);
839 if (!strcmp("linecap", var
))
840 pdf_linecap
= atoi(val
);
841 if (!strcmp("linejoin", var
))
842 pdf_linejoin
= atoi(val
);
872 sbuf_printf(pg
, "%s m\n", pdfpos(o_h
, o_v
));
875 static int l_page
, l_size
, l_wid
, l_cap
, l_join
; /* drawing line properties */
877 void drawend(int close
, int fill
)
879 fill
= !fill
? 2 : fill
;
880 if (l_page
!= page_n
|| l_size
!= o_s
|| l_wid
!= pdf_linewid
||
881 l_cap
!= pdf_linecap
|| l_join
!= pdf_linejoin
) {
882 int lwid
= pdf_linewid
* o_s
;
883 sbuf_printf(pg
, "%d.%03d w\n", lwid
/ 1000, lwid
% 1000);
884 sbuf_printf(pg
, "%d J %d j\n", pdf_linecap
, pdf_linejoin
);
889 l_join
= pdf_linejoin
;
891 if (fill
& 2) /* stroking color */
892 sbuf_printf(pg
, "%s RG\n", pdfcolor(o_m
));
894 sbuf_printf(pg
, (fill
& 2) ? "b\n" : "f\n");
896 sbuf_printf(pg
, close
? "s\n" : "S\n");
901 void drawmbeg(char *s
)
905 void drawmend(char *s
)
909 void drawl(int h
, int v
)
912 sbuf_printf(pg
, "%s l\n", pdfpos(o_h
, o_v
));
915 /* draw circle/ellipse quadrant */
916 static void drawquad(int ch
, int cv
)
919 long x0
= o_h
* 1000;
920 long y0
= o_v
* 1000;
921 long x3
= x0
+ ch
* 1000 / 2;
922 long y3
= y0
+ cv
* 1000 / 2;
924 long y1
= y0
+ cv
* b
/ 1000 / 2;
925 long x2
= x0
+ ch
* b
/ 1000 / 2;
928 x1
= x3
- ch
* b
/ 1000 / 2;
931 y2
= y3
- cv
* b
/ 1000 / 2;
933 sbuf_printf(pg
, "%s ", pdfpos00(x1
/ 10, y1
/ 10));
934 sbuf_printf(pg
, "%s ", pdfpos00(x2
/ 10, y2
/ 10));
935 sbuf_printf(pg
, "%s c\n", pdfpos00(x3
/ 10, y3
/ 10));
936 outrel(ch
/ 2, cv
/ 2);
949 /* draw an ellipse */
950 void drawe(int h
, int v
)
960 void drawa(int h1
, int v1
, int h2
, int v2
)
962 drawl(h1
+ h2
, v1
+ v2
);
966 void draws(int h1
, int v1
, int h2
, int v2
)
975 sbuf_printf(pg
, "%s ", pdfpos((x0
+ 5 * x1
) / 6, (y0
+ 5 * y1
) / 6));
976 sbuf_printf(pg
, "%s ", pdfpos((x2
+ 5 * x1
) / 6, (y2
+ 5 * y1
) / 6));
977 sbuf_printf(pg
, "%s c\n", pdfpos((x1
+ x2
) / 2, (y1
+ y2
) / 2));
982 void docheader(char *title
, int pagewidth
, int pageheight
, int linewidth
)
985 outinfo("Title", title
);
987 pdf_root
= obj_map();
988 pdf_pages
= obj_map();
989 pdfout("%%PDF-1.6\n\n");
990 pdf_width
= (pagewidth
* 72 + 127) / 254;
991 pdf_height
= (pageheight
* 72 + 127) / 254;
992 pdf_linewid
= linewidth
;
995 void doctrailer(int pages
)
1000 /* pdf pages object */
1003 pdfout(" /Type /Pages\n");
1004 pdfout(" /MediaBox [ 0 0 %d %d ]\n", pdf_width
, pdf_height
);
1005 pdfout(" /Count %d\n", page_n
);
1007 for (i
= 0; i
< page_n
; i
++)
1008 pdfout(" %d 0 R", page_id
[i
]);
1012 /* pdf root object */
1015 pdfout(" /Type /Catalog\n");
1016 pdfout(" /Pages %d 0 R\n", pdf_pages
);
1018 pdfout(" /Dests %d 0 R\n", pdf_dests
);
1019 if (pdf_outline
> 0)
1020 pdfout(" /Outlines %d 0 R\n", pdf_outline
);
1026 info_id
= obj_beg(0);
1029 pdfout(" /Title %s\n", pdftext_static(pdf_title
));
1031 pdfout(" /Author %s\n", pdftext_static(pdf_author
));
1032 pdfout(" /Creator (Neatroff)\n");
1033 pdfout(" /Producer (Neatpost)\n");
1039 pdfout("0 %d\n", obj_n
);
1040 pdfout("0000000000 65535 f \n");
1041 for (i
= 1; i
< obj_n
; i
++)
1042 pdfout("%010d 00000 n \n", obj_off
[i
]);
1044 pdfout("trailer\n");
1046 pdfout(" /Size %d\n", obj_n
);
1047 pdfout(" /Root %d 0 R\n", pdf_root
);
1048 pdfout(" /Info %d 0 R\n", info_id
);
1050 pdfout("startxref\n");
1051 pdfout("%d\n", xref_off
);
1052 pdfout("%%%%EOF\n");
1057 void docpagebeg(int n
)
1060 sbuf_printf(pg
, "BT\n");
1063 void docpageend(int n
)
1068 sbuf_printf(pg
, "ET\n");
1070 cont_id
= obj_beg(0);
1072 pdfout(" /Length %d\n", sbuf_len(pg
) - 1);
1075 pdfmem(sbuf_buf(pg
), sbuf_len(pg
));
1076 pdfout("endstream\n");
1078 /* the page object */
1079 if (page_n
== page_sz
) {
1081 page_id
= mextend(page_id
, page_n
, page_sz
, sizeof(page_id
[0]));
1083 page_id
[page_n
++] = obj_beg(0);
1085 pdfout(" /Type /Page\n");
1086 pdfout(" /Parent %d 0 R\n", pdf_pages
);
1087 pdfout(" /Resources <<\n");
1088 pdfout(" /Font <<");
1089 for (i
= 0; i
< pfonts_n
; i
++) {
1091 struct pfont
*ps
= &pfonts
[i
];
1093 pdfout(" /%s %d 0 R", ps
->name
, ps
->obj
);
1095 pdfout(" /%s.%d %d 0 R", ps
->name
, ps
->sub
, ps
->obj
);
1099 if (xobj_n
) { /* XObjects */
1100 pdfout(" /XObject <<");
1101 for (i
= 0; i
< xobj_n
; i
++)
1102 pdfout(" /FO%d %d 0 R", i
, xobj
[i
]);
1106 pdfout(" /Contents %d 0 R\n", cont_id
);
1108 pdfout(" /Annots [");
1109 for (i
= 0; i
< ann_n
; i
++)
1110 pdfout(" %d 0 R", ann
[i
]);
1116 memset(o_iset
, 0, pfonts_n
* sizeof(o_iset
[0]));