pdf: add splines
[neatpost.git] / pdf.c
blobd8812665e1f61f8a206e5b739ab51a224102f7ed
1 /* PDF post-processor functions */
2 #include <ctype.h>
3 #include <fcntl.h>
4 #include <stdarg.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <unistd.h>
9 #include "post.h"
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 */
42 struct pfont {
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, ...)
60 va_list ap;
61 va_start(ap, s);
62 pdf_pos += vprintf(s, ap);
63 va_end(ap);
66 /* print pdf output */
67 static void pdfmem(char *s, int len)
69 fwrite(s, len, 1, stdout);
70 pdf_pos += len;
73 /* allocate an object number */
74 static int obj_map(void)
76 if (obj_n == obj_sz) {
77 obj_sz += 1024;
78 obj_off = mextend(obj_off, obj_n, obj_sz, sizeof(obj_off[0]));
80 return obj_n++;
83 /* start the definition of an object */
84 static int obj_beg(int id)
86 if (id <= 0)
87 id = obj_map();
88 obj_off[id] = pdf_pos;
89 pdfout("%d 0 obj\n", id);
90 return id;
93 /* end an object definition */
94 static void obj_end(void)
96 pdfout("endobj\n\n");
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)
106 int i;
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))
112 encrypted = t1 + i;
113 if (!encrypted)
114 return 1;
115 for (; i < l - 512 && !fixedcont; i++)
116 if (t1[i] == '0' && !memcmp("00000", t1 + i, 5))
117 fixedcont = t1 + i;
118 *l1 = encrypted - cleartext;
119 *l2 = fixedcont ? fixedcont - cleartext : 0;
120 *l3 = fixedcont ? t1 + l - fixedcont : 0;
121 return 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))
129 return 't';
130 if (ext && !strcmp(".otf", ext))
131 return 't';
132 if (ext && (!strcmp(".ttc", ext) || !strcmp(".otc", ext)))
133 return 't';
134 return '1';
137 /* write the object corresponding to the given font */
138 static void pfont_write(struct pfont *ps)
140 int i;
141 int enc_obj;
142 struct font *fn = dev_fontopen(ps->desc);
143 /* the encoding object */
144 enc_obj = obj_beg(0);
145 pdfout("<<\n");
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);
150 pdfout(" ]\n");
151 pdfout(">>\n");
152 obj_end();
153 /* the font object */
154 obj_beg(ps->obj);
155 pdfout("<<\n");
156 pdfout(" /Type /Font\n");
157 if (fonttype(ps->path) == 't')
158 pdfout(" /Subtype /TrueType\n");
159 else
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);
167 pdfout(" ]\n");
168 pdfout(" /FontDescriptor %d 0 R\n", ps->des);
169 pdfout(" /Encoding %d 0 R\n", enc_obj);
170 pdfout(">>\n");
171 obj_end();
172 font_close(fn);
175 static void encodehex(struct sbuf *d, char *s, int n)
177 static char hex[] = "0123456789ABCDEF";
178 int i;
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)
183 sbuf_chr(d, '\n');
185 sbuf_str(d, ">\n");
188 /* write the object corresponding to this CID font */
189 static void pfont_writecid(struct pfont *ps)
191 int cid_obj;
192 struct font *fn = dev_fontopen(ps->desc);
193 int gcnt = 0;
194 int i;
195 /* CIDFont */
196 cid_obj = obj_beg(0);
197 pdfout("<<\n");
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))
205 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);
209 pdfout(" ] ]\n");
210 pdfout(">>\n");
211 obj_end();
212 /* the font object */
213 obj_beg(ps->obj);
214 pdfout("<<\n");
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);
220 pdfout(">>\n");
221 obj_end();
222 font_close(fn);
225 /* write font descriptor; returns its object ID */
226 static int writedesc(struct font *fn)
228 int str_obj = -1;
229 int des_obj;
230 char buf[1 << 10];
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;
237 int nr;
238 /* reading the font file */
239 while ((nr = read(fd, buf, sizeof(buf))) > 0)
240 sbuf_mem(ffsb, buf, nr);
241 close(fd);
242 l1 = sbuf_len(ffsb);
243 /* initialize Type 1 lengths */
244 if (fntype == '1') {
245 if (type1lengths(sbuf_buf(ffsb), sbuf_len(ffsb),
246 &l1, &l2, &l3))
247 l1 = 0;
248 /* remove the fixed-content portion of the font */
249 if (l3)
250 sbuf_cut(ffsb, l1 + l2);
251 l1 -= l3;
252 l3 = 0;
254 /* encoding file contents */
255 encodehex(sb, sbuf_buf(ffsb), sbuf_len(ffsb));
256 /* write font data if it has nonzero length */
257 if (l1) {
258 str_obj = obj_beg(0);
259 pdfout("<<\n");
260 pdfout(" /Filter /ASCIIHexDecode\n");
261 pdfout(" /Length %d\n", sbuf_len(sb));
262 pdfout(" /Length1 %d\n", l1);
263 if (fntype == '1')
264 pdfout(" /Length2 %d\n", l2);
265 if (fntype == '1')
266 pdfout(" /Length3 %d\n", l3);
267 pdfout(">>\n");
268 pdfout("stream\n");
269 pdfmem(sbuf_buf(sb), sbuf_len(sb));
270 pdfout("endstream\n");
271 obj_end();
273 sbuf_free(ffsb);
274 sbuf_free(sb);
276 /* the font descriptor */
277 des_obj = obj_beg(0);
278 pdfout("<<\n");
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");
289 if (str_obj >= 0)
290 pdfout(" /FontFile%s %d 0 R\n",
291 fntype == 't' ? "2" : "", str_obj);
292 pdfout(">>\n");
293 obj_end();
294 return des_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;
304 int i;
305 for (i = 0; i < pfonts_n; i++)
306 if (!strcmp(name, pfonts[i].name) && pfonts[i].sub == sub)
307 return i;
308 if (pfonts_n == pfonts_sz) {
309 pfonts_sz += 16;
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';
318 ps->obj = obj_map();
319 ps->sub = sub;
320 ps->gbeg = 1 << 20;
321 for (i = 0; i < pfonts_n; i++)
322 if (!strcmp(pfonts[i].name, ps->name))
323 break;
324 if (i < pfonts_n)
325 ps->des = pfonts[i].des;
326 else
327 ps->des = writedesc(fn);
328 return pfonts_n++;
331 static void pfont_done(void)
333 int i;
334 for (i = 0; i < pfonts_n; i++) {
335 if (pfonts[i].cid)
336 pfont_writecid(&pfonts[i]);
337 else
338 pfont_write(&pfonts[i]);
340 free(pfonts);
343 static void o_flush(void)
345 if (o_queued == 1)
346 sbuf_printf(pg, ">] TJ\n");
347 o_queued = 0;
350 static int o_loadfont(struct glyph *g)
352 int fn = pfont_find(g);
353 o_iset[fn] = 1;
354 return fn;
357 /* like pdfpos() but assume that uh and uv are multiplied by 100 */
358 static char *pdfpos00(int uh, int uv)
360 static char buf[64];
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);
366 return buf;
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)
378 static char buf[64];
379 int h = (long) uh * 1000 * 72 / sz / dev_res;
380 sprintf(buf, "%s%d", h < 0 ? "-" : "", abs(h));
381 return buf;
384 /* convert troff color to pdf color; returns a static buffer */
385 static char *pdfcolor(int m)
387 static char buf[64];
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);
393 return buf;
396 static void o_queue(struct glyph *g)
398 int gid;
399 if (o_v != p_v) {
400 o_flush();
401 sbuf_printf(pg, "1 0 0 1 %s Tm\n", pdfpos(o_h, o_v));
402 p_h = o_h;
403 p_v = o_v;
405 if (!o_queued)
406 sbuf_printf(pg, "[<");
407 o_queued = 1;
408 if (o_h != p_h)
409 sbuf_printf(pg, "> %s <", pdfunit(p_h - o_h, o_s));
410 /* printing glyph identifier */
411 gid = font_glnum(g->font, g);
412 if (pfonts[o_i].cid)
413 sbuf_printf(pg, "%04x", gid);
414 else
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;
421 /* advancing */
422 p_h = o_h + font_wid(g->font, o_s, g->wid);
425 static void out_fontup(void)
427 if (o_m != p_m) {
428 o_flush();
429 sbuf_printf(pg, "%s rg\n", pdfcolor(o_m));
430 p_m = o_m;
432 if (o_i >= 0 && (o_i != p_i || o_s != p_s)) {
433 struct pfont *ps = &pfonts[o_i];
434 o_flush();
435 if (ps->cid)
436 sbuf_printf(pg, "/%s %d Tf\n", ps->name, o_s);
437 else
438 sbuf_printf(pg, "/%s.%d %d Tf\n", ps->name, ps->sub, o_s);
439 p_i = o_i;
440 p_s = o_s;
444 void outc(char *c)
446 struct glyph *g;
447 struct font *fn;
448 g = dev_glyph(c, o_f);
449 fn = g ? g->font : dev_font(o_f);
450 if (!g) {
451 outrel(*c == ' ' && fn ? font_swid(fn, o_s) : 1, 0);
452 return;
454 o_i = o_loadfont(g);
455 out_fontup();
456 o_queue(g);
459 void outh(int h)
461 o_h = h;
464 void outv(int v)
466 o_v = v;
469 void outrel(int h, int v)
471 o_h += h;
472 o_v += v;
475 void outfont(int f)
477 if (dev_font(f))
478 o_f = f;
481 void outsize(int s)
483 if (s > 0)
484 o_s = s;
487 void outcolor(int c)
489 o_m = c;
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];
504 int datlen;
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);
510 buf[datlen] = '\0';
511 return buf;
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)
519 int slen, val;
520 int beg;
521 if ((val = pdf_dval_val(pdf, len, pos, "/Length")) < 0)
522 return -1;
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)
527 return -1;
528 beg = pos;
529 pos += strlen("stream");
530 if (pdf[pos] == '\r')
531 pos++;
532 pos += 1 + slen;
533 if (pdf[pos] == '\r' || pdf[pos] == ' ')
534 pos++;
535 if (pdf[pos] == '\n')
536 pos++;
537 pos += strlen("endstream") + 1;
538 sbuf_mem(sb, pdf + beg, pos - beg);
539 return 0;
542 /* copy a PDF object and return its new identifier */
543 static int pdf_objcopy(char *pdf, int len, int pos)
545 int id;
546 if ((pos = pdf_ref(pdf, len, pos)) < 0)
547 return -1;
548 if (pdf_type(pdf, len, pos) == 'd') {
549 struct sbuf *sb = sbuf_make();
550 pdf_dictcopy(pdf, len, pos, sb);
551 sbuf_chr(sb, '\n');
552 if (pdf_dval(pdf, len, pos, "/Length") >= 0)
553 pdf_strcopy(pdf, len, pos, sb);
554 id = obj_beg(0);
555 pdfmem(sbuf_buf(sb), sbuf_len(sb));
556 obj_end();
557 sbuf_free(sb);
558 } else {
559 id = obj_beg(0);
560 pdfmem(pdf + pos, pdf_len(pdf, len, pos));
561 pdfout("\n");
562 obj_end();
564 return id;
567 /* copy a PDF dictionary recursively */
568 static void pdf_dictcopy(char *pdf, int len, int pos, struct sbuf *sb)
570 int i;
571 int key, val, id;
572 sbuf_printf(sb, "<<");
573 for (i = 0; ; i++) {
574 if ((key = pdf_dkey(pdf, len, pos, i)) < 0)
575 break;
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);
581 } else {
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"};
593 int res, i;
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");
601 } else {
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])
612 int val;
613 int i;
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)
617 return -1;
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;
629 return 0;
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;
637 int xobj_id, length;
638 int dim[4];
639 int hzoom = 100, vzoom = 100;
640 struct sbuf *sb;
641 int i;
642 if (xobj_n == LEN(xobj))
643 return -1;
644 if ((trailer = pdf_trailer(pdf, len)) < 0)
645 return -1;
646 if ((root = pdf_dval_obj(pdf, len, trailer, "/Root")) < 0)
647 return -1;
648 if ((pages = pdf_dval_obj(pdf, len, root, "/Pages")) < 0)
649 return -1;
650 if ((kids_val = pdf_dval_val(pdf, len, pages, "/Kids")) < 0)
651 return -1;
652 if ((page1_val = pdf_lval(pdf, len, kids_val, 0)) < 0)
653 return -1;
654 if ((page1 = pdf_ref(pdf, len, page1_val)) < 0)
655 return -1;
656 if ((cont = pdf_dval_obj(pdf, len, page1, "/Contents")) < 0)
657 return -1;
658 if ((val = pdf_dval_val(pdf, len, cont, "/Length")) < 0)
659 return -1;
660 res = pdf_dval_val(pdf, len, page1, "/Resources");
661 length = atoi(pdf + val);
662 bbox = pdf_dval_val(pdf, len, page1, "/MediaBox");
663 if (bbox < 0)
664 bbox = pdf_dval_val(pdf, len, pages, "/MediaBox");
665 if (bbox >= 0 && !pdfbbox100(pdf, len, bbox, dim)) {
666 if (hwid > 0)
667 hzoom = (long) hwid * (100 * 7200 / dev_res) / (dim[2] - dim[0]);
668 if (vwid > 0)
669 vzoom = (long) vwid * (100 * 7200 / dev_res) / (dim[3] - dim[1]);
670 if (vwid <= 0)
671 vzoom = hzoom;
672 if (hwid <= 0)
673 hzoom = vzoom;
675 sb = sbuf_make();
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");
680 if (bbox >= 0)
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,
684 pdfpos(o_h, o_v));
685 if (res >= 0)
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));
696 obj_end();
697 sbuf_free(sb);
698 xobj[xobj_n++] = xobj_id;
699 return xobj_n - 1;
702 void outpdf(char *pdf, int hwid, int vwid)
704 char buf[1 << 12];
705 struct sbuf *sb;
706 int xobj_id;
707 int fd, nr;
708 /* reading the pdf file */
709 sb = sbuf_make();
710 fd = open(pdf, O_RDONLY);
711 while ((nr = read(fd, buf, sizeof(buf))) > 0)
712 sbuf_mem(sb, buf, nr);
713 close(fd);
714 /* the XObject */
715 xobj_id = pdfext(sbuf_buf(sb), sbuf_len(sb), hwid, vwid);
716 sbuf_free(sb);
717 o_flush();
718 out_fontup();
719 if (xobj_id >= 0)
720 sbuf_printf(pg, "ET /FO%d Do BT\n", xobj_id);
721 p_h = -1;
722 p_v = -1;
725 void outlink(char *lnk, int hwid, int vwid)
727 if (ann_n == LEN(ann))
728 return;
729 o_flush();
730 ann[ann_n++] = obj_beg(0);
731 pdfout("<<\n");
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));
741 pdfout(">>\n");
742 obj_end();
745 void outname(int n, char (*desc)[64], int *page, int *off)
747 int i;
748 o_flush();
749 pdf_dests = obj_beg(0);
750 pdfout("<<\n");
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));
757 pdfout(">>\n");
758 obj_end();
761 void outmark(int n, char (*desc)[256], int *page, int *off, int *level)
763 int *objs = malloc(n * sizeof(objs[0]));
764 int i, j;
765 int cnt = 0;
766 /* allocating objects */
767 pdf_outline = obj_map();
768 for (i = 0; i < n; i++)
769 objs[i] = obj_map();
770 o_flush();
771 /* root object */
772 obj_beg(pdf_outline);
773 pdfout("<<\n");
774 for (i = 0; i < n; i++)
775 if (level[i] == level[0])
776 cnt++;
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]);
782 pdfout(">>\n");
783 obj_end();
784 /* other objects */
785 for (i = 0; i < n; i++) {
786 int cnt = 0;
787 for (j = i + 1; j < n && level[j] > level[i]; j++)
788 if (level[j] == level[i] + 1)
789 cnt++;
790 obj_beg(objs[i]);
791 pdfout("<<\n");
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);
797 /* the next field */
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]);
802 /* the prev field */
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]);
807 /* node children */
808 if (cnt) {
809 int last = 0;
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)
814 last = j;
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));
821 pdfout(">>\n");
822 obj_end();
824 free(objs);
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);
845 void outpage(void)
847 o_v = 0;
848 o_h = 0;
849 p_i = 0;
850 p_v = 0;
851 p_h = 0;
852 p_s = 0;
853 p_f = 0;
854 p_m = 0;
855 o_i = -1;
858 void outmnt(int f)
860 if (p_f == f)
861 p_f = -1;
864 void outgname(int g)
868 void drawbeg(void)
870 o_flush();
871 out_fontup();
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);
885 l_page = page_n;
886 l_size = o_s;
887 l_wid = pdf_linewid;
888 l_cap = pdf_linecap;
889 l_join = pdf_linejoin;
891 if (fill & 2) /* stroking color */
892 sbuf_printf(pg, "%s RG\n", pdfcolor(o_m));
893 if (fill & 1)
894 sbuf_printf(pg, (fill & 2) ? "b\n" : "f\n");
895 else
896 sbuf_printf(pg, close ? "s\n" : "S\n");
897 p_v = 0;
898 p_h = 0;
901 void drawmbeg(char *s)
905 void drawmend(char *s)
909 void drawl(int h, int v)
911 outrel(h, 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)
918 long b = 551915;
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;
923 long x1 = x0;
924 long y1 = y0 + cv * b / 1000 / 2;
925 long x2 = x0 + ch * b / 1000 / 2;
926 long y2 = y3;
927 if (ch * cv < 0) {
928 x1 = x3 - ch * b / 1000 / 2;
929 y1 = y0;
930 x2 = x3;
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);
939 /* draw a circle */
940 void drawc(int c)
942 drawquad(+c, +c);
943 drawquad(+c, -c);
944 drawquad(-c, -c);
945 drawquad(-c, +c);
946 outrel(c, 0);
949 /* draw an ellipse */
950 void drawe(int h, int v)
952 drawquad(+h, +v);
953 drawquad(+h, -v);
954 drawquad(-h, -v);
955 drawquad(-h, +v);
956 outrel(h, 0);
959 /* draw an arc */
960 void drawa(int h1, int v1, int h2, int v2)
962 drawl(h1 + h2, v1 + v2);
965 /* draw a spline */
966 void draws(int h1, int v1, int h2, int v2)
968 int x0 = o_h;
969 int y0 = o_v;
970 int x1 = x0 + h1;
971 int y1 = y0 + v1;
972 int x2 = x1 + h2;
973 int y2 = y1 + 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));
979 outrel(h1, v1);
982 void docheader(char *title, int pagewidth, int pageheight, int linewidth)
984 if (title)
985 outinfo("Title", title);
986 obj_map();
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)
997 int i;
998 int xref_off;
999 int info_id;
1000 /* pdf pages object */
1001 obj_beg(pdf_pages);
1002 pdfout("<<\n");
1003 pdfout(" /Type /Pages\n");
1004 pdfout(" /MediaBox [ 0 0 %d %d ]\n", pdf_width, pdf_height);
1005 pdfout(" /Count %d\n", page_n);
1006 pdfout(" /Kids [");
1007 for (i = 0; i < page_n; i++)
1008 pdfout(" %d 0 R", page_id[i]);
1009 pdfout(" ]\n");
1010 pdfout(">>\n");
1011 obj_end();
1012 /* pdf root object */
1013 obj_beg(pdf_root);
1014 pdfout("<<\n");
1015 pdfout(" /Type /Catalog\n");
1016 pdfout(" /Pages %d 0 R\n", pdf_pages);
1017 if (pdf_dests > 0)
1018 pdfout(" /Dests %d 0 R\n", pdf_dests);
1019 if (pdf_outline > 0)
1020 pdfout(" /Outlines %d 0 R\n", pdf_outline);
1021 pdfout(">>\n");
1022 obj_end();
1023 /* fonts */
1024 pfont_done();
1025 /* info object */
1026 info_id = obj_beg(0);
1027 pdfout("<<\n");
1028 if (pdf_title[0])
1029 pdfout(" /Title %s\n", pdftext_static(pdf_title));
1030 if (pdf_author[0])
1031 pdfout(" /Author %s\n", pdftext_static(pdf_author));
1032 pdfout(" /Creator (Neatroff)\n");
1033 pdfout(" /Producer (Neatpost)\n");
1034 pdfout(">>\n");
1035 obj_end();
1036 /* the xref */
1037 xref_off = pdf_pos;
1038 pdfout("xref\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]);
1043 /* the trailer */
1044 pdfout("trailer\n");
1045 pdfout("<<\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);
1049 pdfout(">>\n");
1050 pdfout("startxref\n");
1051 pdfout("%d\n", xref_off);
1052 pdfout("%%%%EOF\n");
1053 free(page_id);
1054 free(obj_off);
1057 void docpagebeg(int n)
1059 pg = sbuf_make();
1060 sbuf_printf(pg, "BT\n");
1063 void docpageend(int n)
1065 int cont_id;
1066 int i;
1067 o_flush();
1068 sbuf_printf(pg, "ET\n");
1069 /* page contents */
1070 cont_id = obj_beg(0);
1071 pdfout("<<\n");
1072 pdfout(" /Length %d\n", sbuf_len(pg) - 1);
1073 pdfout(">>\n");
1074 pdfout("stream\n");
1075 pdfmem(sbuf_buf(pg), sbuf_len(pg));
1076 pdfout("endstream\n");
1077 obj_end();
1078 /* the page object */
1079 if (page_n == page_sz) {
1080 page_sz += 1024;
1081 page_id = mextend(page_id, page_n, page_sz, sizeof(page_id[0]));
1083 page_id[page_n++] = obj_beg(0);
1084 pdfout("<<\n");
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++) {
1090 if (o_iset[i]) {
1091 struct pfont *ps = &pfonts[i];
1092 if (ps->cid)
1093 pdfout(" /%s %d 0 R", ps->name, ps->obj);
1094 else
1095 pdfout(" /%s.%d %d 0 R", ps->name, ps->sub, ps->obj);
1098 pdfout(" >>\n");
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]);
1103 pdfout(" >>\n");
1105 pdfout(" >>\n");
1106 pdfout(" /Contents %d 0 R\n", cont_id);
1107 if (ann_n) {
1108 pdfout(" /Annots [");
1109 for (i = 0; i < ann_n; i++)
1110 pdfout(" %d 0 R", ann[i]);
1111 pdfout(" ]\n");
1113 pdfout(">>\n");
1114 obj_end();
1115 sbuf_free(pg);
1116 memset(o_iset, 0, pfonts_n * sizeof(o_iset[0]));
1117 xobj_n = 0;
1118 ann_n = 0;