pdf: optimize encoding hex streams
[neatpost.git] / pdf.c
blobd883417087e62fbef2b8a0e4ebbea98ee02076b1
1 #include <fcntl.h>
2 #include <stdarg.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <unistd.h>
7 #include "post.h"
9 static char *pdf_title; /* document title */
10 static int pdf_width; /* page width */
11 static int pdf_height; /* page height */
12 static int pdf_pages; /* pages object id */
13 static int pdf_root; /* root object id */
14 static int pdf_pos; /* current pdf file offset */
15 static int *obj_off; /* object offsets */
16 static int obj_sz, obj_n; /* number of pdf objects */
17 static int *page_id; /* page object ids */
18 static int page_sz, page_n; /* number of pages */
20 static struct sbuf *pg; /* current page contents */
21 static int o_f, o_s, o_m; /* font and size */
22 static int o_h, o_v; /* current user position */
23 static int p_h, p_v; /* current output position */
24 static int o_pf, p_pf; /* output and pdf fonts; indices into o_fs[] */
25 static int p_f, p_s, p_m; /* output font */
26 static int o_queued; /* queued character type */
27 static int *o_fs; /* page fonts */
28 static int o_fsn, o_fssz; /* page fonts */
30 #define PSFN_MK(fn, ix) (((fn) << 16) | (ix))
31 #define PSFN_FN(fi) ((fi) >> 16)
32 #define PSFN_IX(fi) ((fi) & 0xffff)
34 struct psfont {
35 char name[128]; /* font PostScript name */
36 char path[1024]; /* font path */
37 char desc[1024]; /* font descriptor path */
38 int *gmap; /* the sub-font assigned to each glyph */
39 int *gpos; /* the location of the glyph in its sub-font */
40 int gcnt; /* glyph count */
41 int lastfn; /* the last sub-font */
42 int lastgl; /* the number of glyphs in the last subfont */
43 int obj[64]; /* sub-font object ids */
44 int objdes; /* font descriptor object id */
47 static struct psfont *psfonts;
48 static int psfonts_n, psfonts_sz;
50 /* print formatted pdf output */
51 static void pdfout(char *s, ...)
53 va_list ap;
54 va_start(ap, s);
55 pdf_pos += vprintf(s, ap);
56 va_end(ap);
59 /* print pdf output */
60 static void pdfouts(char *s)
62 fputs(s, stdout);
63 pdf_pos += strlen(s);
66 /* allocate an object number */
67 static int obj_map(void)
69 if (obj_n == obj_sz) {
70 obj_sz += 1024;
71 obj_off = mextend(obj_off, obj_n, obj_sz, sizeof(obj_off[0]));
73 return obj_n++;
76 /* start the definition of an object */
77 static int obj_beg(int id)
79 if (id <= 0)
80 id = obj_map();
81 obj_off[id] = pdf_pos;
82 pdfout("%d 0 obj\n", id);
83 return id;
86 /* end an object definition */
87 static void obj_end(void)
89 pdfout("endobj\n\n");
92 void out(char *s, ...)
96 /* the length of the clear-text, encrypted, and fixed-content portions */
97 static int type1lengths(char *t1, int l, int *l1, int *l2, int *l3)
99 int i;
100 char *cleartext = t1;
101 char *encrypted = NULL;
102 char *fixedcont = NULL;
103 for (i = 0; i < l - 5 && !encrypted; i++)
104 if (t1[i] == 'e' && !memcmp("eexec", t1 + i, 5))
105 encrypted = t1 + i;
106 if (!encrypted)
107 return 1;
108 for (; i < l - 512 && !fixedcont; i++)
109 if (t1[i] == '0' && !memcmp("00000", t1 + i, 5))
110 fixedcont = t1 + i;
111 *l1 = encrypted - cleartext;
112 *l2 = fixedcont ? fixedcont - cleartext : 0;
113 return 0;
116 /* return font type: 't': TrueType, '1': Type 1, 'o': OpenType */
117 static int fonttype(char *path)
119 char *ext = strrchr(path, '.');
120 if (ext && !strcmp(".ttf", ext))
121 return 't';
122 if (ext && !strcmp(".otf", ext))
123 return 'o';
124 return '1';
127 static void encodehex(struct sbuf *d, char *s, int n)
129 static char hex[] = "0123456789ABCDEF";
130 int i;
131 for (i = 0; i < n; i++) {
132 sbuf_chr(d, hex[((unsigned char) s[i]) >> 4]);
133 sbuf_chr(d, hex[((unsigned char) s[i]) & 0x0f]);
134 if (i % 80 == 79 && i + 1 < n)
135 sbuf_chr(d, '\n');
137 sbuf_str(d, ">\n");
140 /* include font descriptor; returns object id */
141 static int psfont_writedesc(struct psfont *ps)
143 int str_obj = -1;
144 int des_obj;
145 char buf[1 << 10];
146 if (fonttype(ps->path) == '1' || fonttype(ps->path) == 't') {
147 int fd = open(ps->path, O_RDONLY);
148 struct sbuf *ffsb = sbuf_make();
149 struct sbuf *sb = sbuf_make();
150 int l1 = 0, l2 = 0, l3 = 0;
151 int nr;
152 /* reading the font file */
153 while ((nr = read(fd, buf, sizeof(buf))) > 0)
154 sbuf_mem(ffsb, buf, nr);
155 close(fd);
156 l1 = sbuf_len(ffsb);
157 /* initialize Type 1 lengths */
158 if (fonttype(ps->path) == '1') {
159 if (type1lengths(sbuf_buf(ffsb), sbuf_len(ffsb),
160 &l1, &l2, &l3))
161 l1 = 0;
162 /* remove the fixed-content portion of the font */
163 if (l3)
164 sbuf_cut(ffsb, l1 + l2);
165 l1 -= l3;
167 /* encoding file contents */
168 encodehex(sb, sbuf_buf(ffsb), sbuf_len(ffsb));
169 /* write font data if it has nonzero length */
170 if (l1) {
171 str_obj = obj_beg(0);
172 pdfout("<<\n");
173 pdfout(" /Filter /ASCIIHexDecode\n");
174 pdfout(" /Length %d\n", sbuf_len(sb));
175 pdfout(" /Length1 %d\n", l1);
176 if (fonttype(ps->path) == '1')
177 pdfout(" /Length2 %d\n", l2);
178 if (fonttype(ps->path) == '1')
179 pdfout(" /Length3 %d\n", l3);
180 pdfout(">>\n");
181 pdfout("stream\n");
182 pdfouts(sbuf_buf(sb));
183 pdfout("endstream\n");
184 obj_end();
186 sbuf_free(ffsb);
187 sbuf_free(sb);
189 /* the font descriptor */
190 des_obj = obj_beg(0);
191 pdfout("<<\n");
192 pdfout(" /Type /FontDescriptor\n");
193 pdfout(" /FontName /%s\n", ps->name);
194 pdfout(" /Flags 4\n");
195 pdfout(" /FontBBox [-1000 -1000 1000 1000]\n");
196 pdfout(" /MissingWidth 1000\n");
197 pdfout(" /StemV 100\n");
198 pdfout(" /ItalicAngle 0\n");
199 pdfout(" /CapHeight 100\n");
200 pdfout(" /Ascent 100\n");
201 pdfout(" /Descent 100\n");
202 if (str_obj >= 0)
203 pdfout(" /FontFile%s %d 0 R\n",
204 fonttype(ps->path) == 't' ? "2" : "", str_obj);
205 pdfout(">>\n");
206 obj_end();
207 return des_obj;
210 /* write the object corresponding to font font_id[f] */
211 static void psfont_write(struct psfont *ps, int ix)
213 int i;
214 int enc_obj;
215 struct font *fn = dev_fontopen(ps->desc);
216 int map[256];
217 int gcnt = ix < ps->lastfn ? 256 : ps->lastgl;
218 /* finding out the mapping */
219 for (i = 0; i < 256; i++)
220 map[i] = -1;
221 for (i = 0; i < ps->gcnt; i++)
222 if (ps->gmap[i] == ix)
223 map[ps->gpos[i]] = i;
224 /* the encoding object */
225 enc_obj = obj_beg(0);
226 pdfout("<<\n");
227 pdfout(" /Type /Encoding\n");
228 pdfout(" /Differences [ 0");
229 for (i = 0; i < gcnt; i++)
230 pdfout(" /%s", map[i] >= 0 ? font_glget(fn, map[i])->id : ".notdef");
231 pdfout(" ]\n");
232 pdfout(">>\n");
233 obj_end();
234 /* the font object */
235 obj_beg(ps->obj[ix]);
236 pdfout("<<\n");
237 pdfout(" /Type /Font\n");
238 if (fonttype(ps->path) == 't')
239 pdfout(" /Subtype /TrueType\n");
240 else
241 pdfout(" /Subtype /Type1\n");
242 pdfout(" /BaseFont /%s\n", ps->name);
243 pdfout(" /FirstChar 0\n");
244 pdfout(" /LastChar %d\n", gcnt - 1);
245 pdfout(" /Widths [");
246 for (i = 0; i < gcnt; i++)
247 pdfout(" %d", (long) (map[i] >= 0 ? font_glget(fn, map[i])->wid : 0)
248 * 100 * 72 / dev_res);
249 pdfout(" ]\n");
250 pdfout(" /FontDescriptor %d 0 R\n", ps->objdes);
251 pdfout(" /Encoding %d 0 R\n", enc_obj);
252 pdfout(">>\n");
253 obj_end();
254 font_close(fn);
257 static int psfont_find(struct glyph *g)
259 struct font *fn = g->font;
260 char *name = font_name(fn);
261 struct psfont *ps = NULL;
262 int gidx;
263 int i;
264 for (i = 0; i < psfonts_n; i++)
265 if (!strcmp(name, psfonts[i].name))
266 break;
267 if (i == psfonts_n) {
268 if (psfonts_n == psfonts_sz) {
269 psfonts_sz += 16;
270 psfonts = mextend(psfonts, psfonts_n,
271 psfonts_sz, sizeof(psfonts[0]));
273 psfonts_n++;
274 ps = &psfonts[i];
275 snprintf(ps->name, sizeof(ps->name), "%s", name);
276 snprintf(ps->path, sizeof(ps->path), "%s", font_path(fn));
277 snprintf(ps->desc, sizeof(ps->desc), "%s", font_desc(fn));
278 while (font_glget(fn, ps->gcnt))
279 ps->gcnt++;
280 ps->gmap = calloc(ps->gcnt, sizeof(ps->gmap));
281 ps->gpos = calloc(ps->gcnt, sizeof(ps->gpos));
282 ps->lastfn = 0;
283 ps->lastgl = 256;
285 ps = &psfonts[i];
286 gidx = font_glnum(fn, g);
287 if (!ps->gmap[gidx]) {
288 if (ps->lastgl == 256) {
289 ps->lastgl = 0;
290 ps->lastfn++;
291 ps->obj[ps->lastfn] = obj_map();
293 ps->gmap[gidx] = ps->lastfn;
294 ps->gpos[gidx] = ps->lastgl++;
296 return PSFN_MK(i, ps->gmap[gidx]);
299 static int psfont_gpos(struct glyph *g)
301 int fn = psfont_find(g);
302 return psfonts[PSFN_FN(fn)].gpos[font_glnum(g->font, g)];
305 static void psfont_done(void)
307 int i, j;
308 for (i = 0; i < psfonts_n; i++) {
309 struct psfont *ps = &psfonts[i];
310 ps->objdes = psfont_writedesc(ps);
311 for (j = 1; j <= ps->lastfn; j++)
312 psfont_write(ps, j);
314 for (i = 0; i < psfonts_n; i++) {
315 free(psfonts[i].gmap);
316 free(psfonts[i].gpos);
318 free(psfonts);
321 static void o_flush(void)
323 if (o_queued == 1)
324 sbuf_printf(pg, ">] TJ\n");
325 o_queued = 0;
328 static int o_loadfont(struct glyph *g)
330 int fn = psfont_find(g);
331 int i;
332 for (i = 0; i < o_fsn; i++)
333 if (o_fs[i] == fn)
334 return i;
335 if (o_fsn == o_fssz) {
336 o_fssz += 128;
337 o_fs = mextend(o_fs, o_fsn, o_fssz, sizeof(o_fs[0]));
339 o_fs[o_fsn++] = fn;
340 return o_fsn - 1;
343 /* like pdfpos() but assume that uh and uv are multiplied by 100 */
344 static char *pdfpos00(int uh, int uv)
346 static char buf[64];
347 int h = (long) uh * 72 / dev_res;
348 int v = (long) pdf_height * 100 - (long) uv * 72 / dev_res;
349 sprintf(buf, "%s%d.%02d %s%d.%02d",
350 h < 0 ? "-" : "", abs(h) / 100, abs(h) % 100,
351 v < 0 ? "-" : "", abs(v) / 100, abs(v) % 100);
352 return buf;
355 /* convert troff position to pdf position; returns a static buffer */
356 static char *pdfpos(int uh, int uv)
358 return pdfpos00(uh * 100, uv * 100);
361 /* troff length to thousands of a unit of text space; returns a static buffer */
362 static char *pdfunit(int uh, int sz)
364 static char buf[64];
365 int h = (long) uh * 1000 * 72 / sz / dev_res;
366 sprintf(buf, "%s%d", h < 0 ? "-" : "", abs(h));
367 return buf;
370 /* convert troff color to pdf color; returns a static buffer */
371 static char *pdfcolor(int m)
373 static char buf[64];
374 int r = CLR_R(m) * 1000 / 255;
375 int g = CLR_G(m) * 1000 / 255;
376 int b = CLR_B(m) * 1000 / 255;
377 sbuf_printf(pg, "%d.%03d %d.%03d %d.%03d",
378 r / 1000, r % 1000, g / 1000, g % 1000, b / 1000, b % 1000);
379 return buf;
382 static void o_queue(struct glyph *g)
384 if (o_v != p_v) {
385 o_flush();
386 sbuf_printf(pg, "1 0 0 1 %s Tm\n", pdfpos(o_h, o_v));
387 p_h = o_h;
388 p_v = o_v;
390 if (!o_queued)
391 sbuf_printf(pg, "[<");
392 o_queued = 1;
393 if (o_h != p_h)
394 sbuf_printf(pg, "> %s <", pdfunit(p_h - o_h, o_s));
395 sbuf_printf(pg, "%02x", psfont_gpos(g));
396 p_h = o_h + font_wid(g->font, o_s, g->wid);
399 static void out_fontup(void)
401 if (o_m != p_m) {
402 o_flush();
403 sbuf_printf(pg, "%s rg\n", pdfcolor(o_m));
404 p_m = o_m;
406 if (o_pf >= 0 && (o_pf != p_pf || o_s != p_s)) {
407 int fn = PSFN_FN(o_fs[o_pf]);
408 int ix = PSFN_IX(o_fs[o_pf]);
409 o_flush();
410 sbuf_printf(pg, "/%s.%d %d Tf\n", psfonts[fn].name, ix, o_s);
411 p_pf = o_pf;
412 p_s = o_s;
416 void outc(char *c)
418 struct glyph *g;
419 struct font *fn;
420 g = dev_glyph(c, o_f);
421 fn = g ? g->font : dev_font(o_f);
422 if (!g) {
423 outrel(*c == ' ' && fn ? font_swid(fn, o_s) : 1, 0);
424 return;
426 o_pf = o_loadfont(g);
427 out_fontup();
428 o_queue(g);
431 void outh(int h)
433 o_h = h;
436 void outv(int v)
438 o_v = v;
441 void outrel(int h, int v)
443 o_h += h;
444 o_v += v;
447 void outfont(int f)
449 if (dev_font(f))
450 o_f = f;
453 void outsize(int s)
455 if (s > 0)
456 o_s = s;
459 void outcolor(int c)
461 o_m = c;
464 void outrotate(int deg)
468 void outeps(char *eps)
472 void outlink(char *spec)
476 void outpage(void)
478 o_v = 0;
479 o_h = 0;
480 p_pf = 0;
481 p_v = 0;
482 p_h = 0;
483 p_s = 0;
484 p_f = 0;
485 p_m = 0;
486 o_pf = -1;
489 void outmnt(int f)
491 if (p_f == f)
492 p_f = -1;
495 void outgname(int g)
499 static int draw_path; /* number of path segments */
500 static int draw_point; /* point was set for postscript newpath */
502 void drawbeg(void)
504 o_flush();
505 out_fontup();
506 if (draw_path)
507 return;
508 sbuf_printf(pg, "%s m\n", pdfpos(o_h, o_v));
511 void drawend(int close, int fill)
513 if (draw_path)
514 return;
515 draw_point = 0;
516 if (!fill) /* stroking color */
517 sbuf_printf(pg, "%s RG\n", pdfcolor(o_m));
518 if (fill)
519 sbuf_printf(pg, "f\n");
520 else
521 sbuf_printf(pg, close ? "s\n" : "S\n");
524 void drawmbeg(char *s)
528 void drawmend(char *s)
532 void drawl(int h, int v)
534 outrel(h, v);
535 sbuf_printf(pg, "%s l\n", pdfpos(o_h, o_v));
538 /* draw circle/ellipse quadrant */
539 static void drawquad(int ch, int cv)
541 long b = 551915;
542 long x0 = o_h * 1000;
543 long y0 = o_v * 1000;
544 long x3 = x0 + ch * 1000 / 2;
545 long y3 = y0 + cv * 1000 / 2;
546 long x1 = x0;
547 long y1 = y0 + cv * b / 1000 / 2;
548 long x2 = x0 + ch * b / 1000 / 2;
549 long y2 = y3;
550 if (ch * cv < 0) {
551 x1 = x3 - ch * b / 1000 / 2;
552 y1 = y0;
553 x2 = x3;
554 y2 = y3 - cv * b / 1000 / 2;
556 sbuf_printf(pg, "%s ", pdfpos00(x1 / 10, y1 / 10));
557 sbuf_printf(pg, "%s ", pdfpos00(x2 / 10, y2 / 10));
558 sbuf_printf(pg, "%s c\n", pdfpos00(x3 / 10, y3 / 10));
559 outrel(ch / 2, cv / 2);
562 /* draw a circle */
563 void drawc(int c)
565 drawquad(+c, +c);
566 drawquad(+c, -c);
567 drawquad(-c, -c);
568 drawquad(-c, +c);
569 outrel(c, 0);
572 /* draw an ellipse */
573 void drawe(int h, int v)
575 drawquad(+h, +v);
576 drawquad(+h, -v);
577 drawquad(-h, -v);
578 drawquad(-h, +v);
579 outrel(h, 0);
582 /* draw an arc */
583 void drawa(int h1, int v1, int h2, int v2)
585 drawl(h1 + h2, v1 + v2);
588 /* draw an spline */
589 void draws(int h1, int v1, int h2, int v2)
591 outrel(h1, v1);
592 sbuf_printf(pg, "%s l\n", pdfpos(o_h, o_v));
595 void ps_header(char *title, int pagewidth, int pageheight, int linewidth)
597 pdf_title = title;
598 obj_map();
599 pdf_root = obj_map();
600 pdf_pages = obj_map();
601 pdf_title = title;
602 pdfout("%%PDF-1.6\n");
603 pdf_width = (pagewidth * 72 + 127) / 254;
604 pdf_height = (pageheight * 72 + 127) / 254;
607 void ps_trailer(int pages)
609 int i;
610 int xref_off;
611 int info_id;
612 /* pdf pages object */
613 obj_beg(pdf_pages);
614 pdfout("<<\n");
615 pdfout(" /Type /Pages\n");
616 pdfout(" /MediaBox [ 0 0 %d %d ]\n", pdf_width, pdf_height);
617 pdfout(" /Count %d\n", page_n);
618 pdfout(" /Kids [");
619 for (i = 0; i < page_n; i++)
620 pdfout(" %d 0 R", page_id[i]);
621 pdfout(" ]\n");
622 pdfout(">>\n");
623 obj_end();
624 /* pdf root object */
625 obj_beg(pdf_root);
626 pdfout("<<\n");
627 pdfout(" /Type /Catalog\n");
628 pdfout(" /Pages %d 0 R\n", pdf_pages);
629 pdfout(">>\n");
630 obj_end();
631 /* fonts */
632 psfont_done();
633 /* info object */
634 info_id = obj_beg(0);
635 pdfout("<<\n");
636 if (pdf_title)
637 pdfout(" /Title (%s)\n", pdf_title);
638 pdfout(" /Creator (Neatroff)\n");
639 pdfout(" /Producer (Neatpost)\n");
640 pdfout(">>\n");
641 obj_end();
642 /* the xref */
643 xref_off = pdf_pos;
644 pdfout("xref\n");
645 pdfout("0 %d\n", obj_n);
646 pdfout("0000000000 65535 f \n");
647 for (i = 1; i < obj_n; i++)
648 pdfout("%010d 00000 n \n", obj_off[i]);
649 /* the trailer */
650 pdfout("trailer\n");
651 pdfout("<<\n");
652 pdfout(" /Size %d\n", obj_n);
653 pdfout(" /Root %d 0 R\n", pdf_root);
654 pdfout(" /Info %d 0 R\n", info_id);
655 pdfout(">>\n");
656 pdfout("startxref\n");
657 pdfout("%d\n", xref_off);
658 pdfout("%%%%EOF\n");
659 free(page_id);
660 free(obj_off);
663 void ps_pagebeg(int n)
665 pg = sbuf_make();
666 sbuf_printf(pg, "BT\n");
669 void ps_pageend(int n)
671 int cont_id;
672 int i;
673 o_flush();
674 sbuf_printf(pg, "ET\n");
675 /* page contents */
676 cont_id = obj_beg(0);
677 pdfout("<<\n");
678 pdfout(" /Length %d\n", sbuf_len(pg));
679 pdfout(">>\n");
680 pdfout("stream\n");
681 pdfouts(sbuf_buf(pg));
682 pdfout("endstream\n");
683 obj_end();
684 /* the page object */
685 if (page_n == page_sz) {
686 page_sz += 1024;
687 page_id = mextend(page_id, page_n, page_sz, sizeof(page_id[0]));
689 page_id[page_n++] = obj_beg(0);
690 pdfout("<<\n");
691 pdfout(" /Type /Page\n");
692 pdfout(" /Parent %d 0 R\n", pdf_pages);
693 pdfout(" /Resources <<\n");
694 pdfout(" /Font <<");
695 for (i = 0; i < o_fsn; i++) {
696 int fn = PSFN_FN(o_fs[i]);
697 int ix = PSFN_IX(o_fs[i]);
698 pdfout(" /%s.%d %d 0 R",
699 psfonts[fn].name, ix, psfonts[fn].obj[ix]);
701 pdfout(" >>\n");
702 pdfout(" >>\n");
703 pdfout(" /Contents %d 0 R\n", cont_id);
704 pdfout(">>\n");
705 obj_end();
706 sbuf_free(pg);
707 free(o_fs);
708 o_fs = NULL;
709 o_fsn = 0;
710 o_fssz = 0;