pdf: drawing circles and ellipses
[neatpost.git] / pdf.c
blobee812a4ee52d9803a867740bdc13f3d5f8c9fcb6
1 #include <stdarg.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include "post.h"
7 static char *pdf_title; /* document title */
8 static int pdf_width; /* page width */
9 static int pdf_height; /* page height */
10 static int pdf_pages; /* pages object id */
11 static int pdf_root; /* root object id */
12 static int pdf_pos; /* current pdf file offset */
13 static int *obj_off; /* object offsets */
14 static int obj_sz, obj_n; /* number of pdf objects */
15 static int *page_id; /* page object ids */
16 static int page_sz, page_n; /* number of pages */
18 static struct sbuf *pg; /* current page contents */
19 static int o_f, o_s, o_m; /* font and size */
20 static int o_h, o_v; /* current user position */
21 static int p_h, p_v; /* current output position */
22 static int o_pf, p_pf; /* output and pdf fonts; indices into o_fs[] */
23 static int p_f, p_s, p_m; /* output font */
24 static int o_queued; /* queued character type */
25 static int *o_fs; /* page fonts */
26 static int o_fsn, o_fssz; /* page fonts */
28 #define PSFN_MK(fn, ix) (((fn) << 16) | (ix))
29 #define PSFN_FN(fi) ((fi) >> 16)
30 #define PSFN_IX(fi) ((fi) & 0xffff)
32 struct psfont {
33 char name[128]; /* font PostScript name */
34 char path[1024]; /* font path */
35 char desc[1024]; /* font descriptor path */
36 int *gmap; /* the sub-font assigned to each glyph */
37 int *gpos; /* the location of the glyph in its sub-font */
38 int gcnt; /* glyph count */
39 int lastfn; /* the last sub-font */
40 int lastgl; /* the number of glyphs in the last subfont */
41 int obj[64]; /* sub-font object ids */
42 int objdes; /* font descriptor object id */
45 static struct psfont *psfonts;
46 static int psfonts_n, psfonts_sz;
48 /* print pdf output */
49 static void pdfout(char *s, ...)
51 va_list ap;
52 va_start(ap, s);
53 pdf_pos += vprintf(s, ap);
54 va_end(ap);
57 /* allocate an object number */
58 static int obj_map(void)
60 if (obj_n == obj_sz) {
61 obj_sz += 1024;
62 obj_off = mextend(obj_off, obj_n, obj_sz, sizeof(obj_off[0]));
64 return obj_n++;
67 /* start the definition of an object */
68 static int obj_beg(int id)
70 if (id <= 0)
71 id = obj_map();
72 obj_off[id] = pdf_pos;
73 pdfout("%d 0 obj\n", id);
74 return id;
77 /* end an object definition */
78 static void obj_end(void)
80 pdfout("endobj\n\n");
83 void out(char *s, ...)
87 /* include font descriptor; returns object id */
88 static int psfont_writedesc(struct psfont *ps)
90 int c, i;
91 int str_obj = -1;
92 int des_obj;
93 char *ext = strrchr(ps->path, '.');
94 if (ext && !strcmp(".ttf", ext)) {
95 FILE *fp = fopen(ps->path, "r");
96 struct sbuf *sb = sbuf_make();
97 c = fgetc(fp);
98 for (i = 0; c != EOF; i++) {
99 sbuf_printf(sb, "%02x", c);
100 c = fgetc(fp);
101 if (i % 40 == 39 && c != EOF)
102 sbuf_chr(sb, '\n');
104 sbuf_str(sb, ">\n");
105 fclose(fp);
106 str_obj = obj_beg(0);
107 pdfout("<<\n");
108 pdfout(" /Filter /ASCIIHexDecode\n");
109 pdfout(" /Length %d\n", sbuf_len(sb));
110 pdfout(" /Length1 %d\n", i);
111 pdfout(">>\n");
112 pdfout("stream\n");
113 pdfout("%s", sbuf_buf(sb));
114 pdfout("endstream\n");
115 obj_end();
116 sbuf_free(sb);
118 /* the font descriptor */
119 des_obj = obj_beg(0);
120 pdfout("<<\n");
121 pdfout(" /Type /FontDescriptor\n");
122 pdfout(" /FontName /%s\n", ps->name);
123 pdfout(" /Flags 4\n");
124 pdfout(" /FontBBox [-1000 -1000 1000 1000]\n");
125 pdfout(" /MissingWidth 1000\n");
126 pdfout(" /StemV 100\n");
127 pdfout(" /ItalicAngle 0\n");
128 pdfout(" /CapHeight 100\n");
129 pdfout(" /Ascent 100\n");
130 pdfout(" /Descent 100\n");
131 if (str_obj >= 0)
132 pdfout(" /FontFile2 %d 0 R\n", str_obj);
133 pdfout(">>\n");
134 obj_end();
135 return des_obj;
138 /* write the object corresponding to font font_id[f] */
139 static void psfont_write(struct psfont *ps, int ix)
141 int i;
142 int enc_obj;
143 char *ext = strrchr(ps->path, '.');
144 struct font *fn = dev_fontopen(ps->desc);
145 int map[256];
146 int gcnt = ix < ps->lastfn ? 256 : ps->lastgl;
147 /* finding out the mapping */
148 for (i = 0; i < 256; i++)
149 map[i] = -1;
150 for (i = 0; i < ps->gcnt; i++)
151 if (ps->gmap[i] == ix)
152 map[ps->gpos[i]] = i;
153 /* the encoding object */
154 enc_obj = obj_beg(0);
155 pdfout("<<\n");
156 pdfout(" /Type /Encoding\n");
157 pdfout(" /Differences [ 0");
158 for (i = 0; i < gcnt; i++)
159 pdfout(" /%s", map[i] >= 0 ? font_glget(fn, map[i])->id : ".notdef");
160 pdfout(" ]\n");
161 pdfout(">>\n");
162 obj_end();
163 /* the font object */
164 obj_beg(ps->obj[ix]);
165 pdfout("<<\n");
166 pdfout(" /Type /Font\n");
167 pdfout(" /Subtype /%s\n",
168 ext && !strcmp(".ttf", ext) ? "TrueType" : "Type1");
169 pdfout(" /BaseFont /%s\n", ps->name);
170 pdfout(" /FirstChar 0\n");
171 pdfout(" /LastChar %d\n", gcnt - 1);
172 pdfout(" /Widths [");
173 for (i = 0; i < gcnt; i++)
174 pdfout(" %d", (long) (map[i] >= 0 ? font_glget(fn, map[i])->wid : 0)
175 * 100 * 72 / dev_res);
176 pdfout(" ]\n");
177 pdfout(" /FontDescriptor %d 0 R\n", ps->objdes);
178 pdfout(" /Encoding %d 0 R\n", enc_obj);
179 pdfout(">>\n");
180 obj_end();
181 font_close(fn);
184 static int psfont_find(struct glyph *g)
186 struct font *fn = g->font;
187 char *name = font_name(fn);
188 struct psfont *ps = NULL;
189 int gidx;
190 int i;
191 for (i = 0; i < psfonts_n; i++)
192 if (!strcmp(name, psfonts[i].name))
193 break;
194 if (i == psfonts_n) {
195 if (psfonts_n == psfonts_sz) {
196 psfonts_sz += 16;
197 psfonts = mextend(psfonts, psfonts_n,
198 psfonts_sz, sizeof(psfonts[0]));
200 psfonts_n++;
201 ps = &psfonts[i];
202 snprintf(ps->name, sizeof(ps->name), "%s", name);
203 snprintf(ps->path, sizeof(ps->path), "%s", font_path(fn));
204 snprintf(ps->desc, sizeof(ps->desc), "%s", font_desc(fn));
205 while (font_glget(fn, ps->gcnt))
206 ps->gcnt++;
207 ps->gmap = calloc(ps->gcnt, sizeof(ps->gmap));
208 ps->gpos = calloc(ps->gcnt, sizeof(ps->gpos));
209 ps->lastfn = 0;
210 ps->lastgl = 256;
212 ps = &psfonts[i];
213 gidx = font_glnum(fn, g);
214 if (!ps->gmap[gidx]) {
215 if (ps->lastgl == 256) {
216 ps->lastgl = 0;
217 ps->lastfn++;
218 ps->obj[ps->lastfn] = obj_map();
220 ps->gmap[gidx] = ps->lastfn;
221 ps->gpos[gidx] = ps->lastgl++;
223 return PSFN_MK(i, ps->gmap[gidx]);
226 static int psfont_gpos(struct glyph *g)
228 int fn = psfont_find(g);
229 return psfonts[PSFN_FN(fn)].gpos[font_glnum(g->font, g)];
232 static void psfont_done(void)
234 int i, j;
235 for (i = 0; i < psfonts_n; i++) {
236 struct psfont *ps = &psfonts[i];
237 ps->objdes = psfont_writedesc(ps);
238 for (j = 1; j <= ps->lastfn; j++)
239 psfont_write(ps, j);
241 for (i = 0; i < psfonts_n; i++) {
242 free(psfonts[i].gmap);
243 free(psfonts[i].gpos);
245 free(psfonts);
248 static void o_flush(void)
250 if (o_queued == 1)
251 sbuf_printf(pg, ">] TJ\n");
252 o_queued = 0;
255 static int o_loadfont(struct glyph *g)
257 int fn = psfont_find(g);
258 int i;
259 for (i = 0; i < o_fsn; i++)
260 if (o_fs[i] == fn)
261 return i;
262 if (o_fsn == o_fssz) {
263 o_fssz += 128;
264 o_fs = mextend(o_fs, o_fsn, o_fssz, sizeof(o_fs[0]));
266 o_fs[o_fsn++] = fn;
267 return o_fsn - 1;
270 /* like pdfpos() but assume that uh and uv are multiplied by 100 */
271 static char *pdfpos00(int uh, int uv)
273 static char buf[64];
274 int h = (long) uh * 72 / dev_res;
275 int v = (long) pdf_height * 100 - (long) uv * 72 / dev_res;
276 sprintf(buf, "%s%d.%02d %s%d.%02d",
277 h < 0 ? "-" : "", abs(h) / 100, abs(h) % 100,
278 v < 0 ? "-" : "", abs(v) / 100, abs(v) % 100);
279 return buf;
282 /* convert troff position to pdf position; returns a static buffer */
283 static char *pdfpos(int uh, int uv)
285 return pdfpos00(uh * 100, uv * 100);
288 /* troff length to thousands of a unit of text space; returns a static buffer */
289 static char *pdfunit(int uh, int sz)
291 static char buf[64];
292 int h = (long) uh * 1000 * 72 / sz / dev_res;
293 sprintf(buf, "%s%d", h < 0 ? "-" : "", abs(h));
294 return buf;
297 /* convert troff color to pdf color; returns a static buffer */
298 static char *pdfcolor(int m)
300 static char buf[64];
301 int r = CLR_R(m) * 1000 / 255;
302 int g = CLR_G(m) * 1000 / 255;
303 int b = CLR_B(m) * 1000 / 255;
304 sbuf_printf(pg, "%d.%03d %d.%03d %d.%03d",
305 r / 1000, r % 1000, g / 1000, g % 1000, b / 1000, b % 1000);
306 return buf;
309 static void o_queue(struct glyph *g)
311 if (o_v != p_v) {
312 o_flush();
313 sbuf_printf(pg, "1 0 0 1 %s Tm\n", pdfpos(o_h, o_v));
314 p_h = o_h;
315 p_v = o_v;
317 if (!o_queued)
318 sbuf_printf(pg, "[<");
319 o_queued = 1;
320 if (o_h != p_h)
321 sbuf_printf(pg, "> %s <", pdfunit(p_h - o_h, o_s));
322 sbuf_printf(pg, "%02x", psfont_gpos(g));
323 p_h = o_h + font_wid(g->font, o_s, g->wid);
326 static void out_fontup(void)
328 if (o_m != p_m) {
329 o_flush();
330 sbuf_printf(pg, "%s rg\n", pdfcolor(o_m));
331 p_m = o_m;
333 if (o_pf >= 0 && (o_pf != p_pf || o_s != p_s)) {
334 int fn = PSFN_FN(o_fs[o_pf]);
335 int ix = PSFN_IX(o_fs[o_pf]);
336 o_flush();
337 sbuf_printf(pg, "/%s.%d %d Tf\n", psfonts[fn].name, ix, o_s);
338 p_pf = o_pf;
339 p_s = o_s;
343 void outc(char *c)
345 struct glyph *g;
346 struct font *fn;
347 g = dev_glyph(c, o_f);
348 fn = g ? g->font : dev_font(o_f);
349 if (!g) {
350 outrel(*c == ' ' && fn ? font_swid(fn, o_s) : 1, 0);
351 return;
353 o_pf = o_loadfont(g);
354 out_fontup();
355 o_queue(g);
358 void outh(int h)
360 o_h = h;
363 void outv(int v)
365 o_v = v;
368 void outrel(int h, int v)
370 o_h += h;
371 o_v += v;
374 void outfont(int f)
376 if (dev_font(f))
377 o_f = f;
380 void outsize(int s)
382 if (s > 0)
383 o_s = s;
386 void outcolor(int c)
388 o_m = c;
391 void outrotate(int deg)
395 void outeps(char *eps)
399 void outlink(char *spec)
403 void outpage(void)
405 o_v = 0;
406 o_h = 0;
407 p_pf = 0;
408 p_v = 0;
409 p_h = 0;
410 p_s = 0;
411 p_f = 0;
412 p_m = 0;
413 o_pf = -1;
416 void outmnt(int f)
418 if (p_f == f)
419 p_f = -1;
422 void outgname(int g)
426 static int draw_path; /* number of path segments */
427 static int draw_point; /* point was set for postscript newpath */
429 void drawbeg(void)
431 o_flush();
432 out_fontup();
433 if (draw_path)
434 return;
435 sbuf_printf(pg, "%s m\n", pdfpos(o_h, o_v));
438 void drawend(int close, int fill)
440 if (draw_path)
441 return;
442 draw_point = 0;
443 if (!fill) /* stroking color */
444 sbuf_printf(pg, "%s RG\n", pdfcolor(o_m));
445 if (fill)
446 sbuf_printf(pg, "f\n");
447 else
448 sbuf_printf(pg, close ? "s\n" : "S\n");
451 void drawmbeg(char *s)
455 void drawmend(char *s)
459 void drawl(int h, int v)
461 outrel(h, v);
462 sbuf_printf(pg, "%s l\n", pdfpos(o_h, o_v));
465 static void drawquad(int ch, int cv)
467 long b = 551915;
468 long x0 = o_h * 1000;
469 long y0 = o_v * 1000;
470 long x3 = x0 + ch * 1000 / 2;
471 long y3 = y0 + cv * 1000 / 2;
472 long x1 = x0;
473 long y1 = y0 + cv * b / 1000 / 2;
474 long x2 = x0 + ch * b / 1000 / 2;
475 long y2 = y3;
476 if (ch * cv < 0) {
477 x1 = x3 - ch * b / 1000 / 2;
478 y1 = y0;
479 x2 = x3;
480 y2 = y3 - cv * b / 1000 / 2;
482 sbuf_printf(pg, "%s ", pdfpos00(x1 / 10, y1 / 10));
483 sbuf_printf(pg, "%s ", pdfpos00(x2 / 10, y2 / 10));
484 sbuf_printf(pg, "%s c\n", pdfpos00(x3 / 10, y3 / 10));
485 outrel(ch / 2, cv / 2);
488 void drawc(int c)
490 drawquad(+c, +c);
491 drawquad(+c, -c);
492 drawquad(-c, -c);
493 drawquad(-c, +c);
494 outrel(c, 0);
497 void drawe(int h, int v)
499 drawquad(+h, +v);
500 drawquad(+h, -v);
501 drawquad(-h, -v);
502 drawquad(-h, +v);
503 outrel(h, 0);
506 void drawa(int h1, int v1, int h2, int v2)
508 outrel(h1 + h2, v1 + v2);
511 void draws(int h1, int v1, int h2, int v2)
513 outrel(h1, v1);
514 sbuf_printf(pg, "%s l\n", pdfpos(o_h, o_v));
517 void ps_header(char *title, int pagewidth, int pageheight, int linewidth)
519 pdf_title = title;
520 obj_map();
521 pdf_root = obj_map();
522 pdf_pages = obj_map();
523 pdf_title = title;
524 pdfout("%%PDF-1.6\n");
525 pdf_width = (pagewidth * 72 + 127) / 254;
526 pdf_height = (pageheight * 72 + 127) / 254;
529 void ps_trailer(int pages)
531 int i;
532 int xref_off;
533 int info_id;
534 /* pdf pages object */
535 obj_beg(pdf_pages);
536 pdfout("<<\n");
537 pdfout(" /Type /Pages\n");
538 pdfout(" /MediaBox [ 0 0 %d %d ]\n", pdf_width, pdf_height);
539 pdfout(" /Count %d\n", page_n);
540 pdfout(" /Kids [");
541 for (i = 0; i < page_n; i++)
542 pdfout(" %d 0 R", page_id[i]);
543 pdfout(" ]\n");
544 pdfout(">>\n");
545 obj_end();
546 /* pdf root object */
547 obj_beg(pdf_root);
548 pdfout("<<\n");
549 pdfout(" /Type /Catalog\n");
550 pdfout(" /Pages %d 0 R\n", pdf_pages);
551 pdfout(">>\n");
552 obj_end();
553 /* fonts */
554 psfont_done();
555 /* info object */
556 info_id = obj_beg(0);
557 pdfout("<<\n");
558 if (pdf_title)
559 pdfout(" /Title (%s)\n", pdf_title);
560 pdfout(" /Creator (Neatroff)\n");
561 pdfout(" /Producer (Neatpost)\n");
562 pdfout(">>\n");
563 obj_end();
564 /* the xref */
565 xref_off = pdf_pos;
566 pdfout("xref\n");
567 pdfout("0 %d\n", obj_n);
568 pdfout("0000000000 65535 f \n");
569 for (i = 1; i < obj_n; i++)
570 pdfout("%010d 00000 n \n", obj_off[i]);
571 /* the trailer */
572 pdfout("trailer\n");
573 pdfout("<<\n");
574 pdfout(" /Size %d\n", obj_n);
575 pdfout(" /Root %d 0 R\n", pdf_root);
576 pdfout(" /Info %d 0 R\n", info_id);
577 pdfout(">>\n");
578 pdfout("startxref\n");
579 pdfout("%d\n", xref_off);
580 pdfout("%%%%EOF\n");
581 free(page_id);
582 free(obj_off);
585 void ps_pagebeg(int n)
587 pg = sbuf_make();
588 sbuf_printf(pg, "BT\n");
591 void ps_pageend(int n)
593 int cont_id;
594 int i;
595 o_flush();
596 sbuf_printf(pg, "ET\n");
597 /* page contents */
598 cont_id = obj_beg(0);
599 pdfout("<<\n");
600 pdfout(" /Length %d\n", sbuf_len(pg));
601 pdfout(">>\n");
602 pdfout("stream\n");
603 pdfout("%s", sbuf_buf(pg));
604 pdfout("endstream\n");
605 obj_end();
606 /* the page object */
607 if (page_n == page_sz) {
608 page_sz += 1024;
609 page_id = mextend(page_id, page_n, page_sz, sizeof(page_id[0]));
611 page_id[page_n++] = obj_beg(0);
612 pdfout("<<\n");
613 pdfout(" /Type /Page\n");
614 pdfout(" /Parent %d 0 R\n", pdf_pages);
615 pdfout(" /Resources <<\n");
616 pdfout(" /Font <<");
617 for (i = 0; i < o_fsn; i++) {
618 int fn = PSFN_FN(o_fs[i]);
619 int ix = PSFN_IX(o_fs[i]);
620 pdfout(" /%s.%d %d 0 R",
621 psfonts[fn].name, ix, psfonts[fn].obj[ix]);
623 pdfout(" >>\n");
624 pdfout(" >>\n");
625 pdfout(" /Contents %d 0 R\n", cont_id);
626 pdfout(">>\n");
627 obj_end();
628 sbuf_free(pg);
629 free(o_fs);
630 o_fs = NULL;
631 o_fsn = 0;
632 o_fssz = 0;