pdf: a basic pdf post-processor
[neatpost.git] / pdf.c
blob69304d53b51f3b808ef19bb9947ace89e7e2cace
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 */
17 static char **font_ps; /* document font names */
18 static int *font_id; /* font object */
19 static int *font_ct; /* font content stream object */
20 static int *font_ix; /* font index */
21 static int font_sz, font_n; /* number of fonts */
23 static struct sbuf *pg; /* current page contents */
24 static int o_f, o_s, o_m; /* font and size */
25 static int o_h, o_v; /* current user position */
26 static int p_h, p_v; /* current output position */
27 static int o_pf, p_pf; /* output and pdf fonts; indices into o_fs[] */
28 static int p_f, p_s, p_m; /* output font */
29 static int o_queued; /* queued character type */
30 static int *o_fs; /* page fonts */
31 static int o_fsn, o_fssz; /* page fonts */
33 /* print pdf output */
34 static void pdfout(char *s, ...)
36 va_list ap;
37 va_start(ap, s);
38 pdf_pos += vprintf(s, ap);
39 va_end(ap);
42 /* allocate an object number */
43 static int obj_map(void)
45 if (obj_n == obj_sz) {
46 obj_sz += 1024;
47 obj_off = mextend(obj_off, obj_n, obj_sz, sizeof(obj_off[0]));
49 return obj_n++;
52 /* start the definition of an object */
53 static int obj_beg(int id)
55 if (id <= 0)
56 id = obj_map();
57 obj_off[id] = pdf_pos;
58 pdfout("%d 0 obj\n", id);
59 return id;
62 /* end an object definition */
63 static void obj_end(void)
65 pdfout("endobj\n\n");
68 /* embed font; return stream object identifier */
69 static int font_outdat(char *path, char *name, int ix)
71 struct sbuf *sb;
72 FILE *fp;
73 int c, i, id;
74 for (i = 0; i < font_n; i++)
75 if (!strcmp(name, font_ps[i]) && font_ct[i] >= 0)
76 return font_ct[i];
77 fp = fopen(path, "r");
78 if (!fp)
79 return -1;
80 sb = sbuf_make();
81 c = fgetc(fp);
82 for (i = 0; c != EOF; i++) {
83 sbuf_printf(sb, "%02x", c);
84 c = fgetc(fp);
85 if (i % 40 == 39 && c != EOF)
86 sbuf_chr(sb, '\n');
88 sbuf_str(sb, ">\n");
89 fclose(fp);
90 id = obj_beg(0);
91 pdfout("<<\n");
92 pdfout(" /Filter /ASCIIHexDecode\n");
93 pdfout(" /Length %d\n", sbuf_len(sb));
94 pdfout(" /Length1 %d\n", i);
95 pdfout(">>\n");
96 pdfout("stream\n");
97 pdfout("%s", sbuf_buf(sb));
98 pdfout("endstream\n");
99 obj_end();
100 sbuf_free(sb);
101 return id;
104 /* write the object corresponding to font font_id[f] */
105 static void font_out(struct font *fn, int f)
107 int i;
108 int enc_obj, des_obj;
109 char *path = font_path(fn);
110 char *ext = path ? strrchr(path, '.') : NULL;
111 /* the encoding object */
112 enc_obj = obj_beg(0);
113 pdfout("<<\n");
114 pdfout(" /Type /Encoding\n");
115 pdfout(" /Differences [ 0");
116 for (i = 0; i < 256; i++) {
117 struct glyph *g = font_glget(fn, font_ix[f] * 256 + i);
118 pdfout(" /%s", g ? g->id : ".notdef");
120 pdfout(" ]\n");
121 pdfout(">>\n");
122 obj_end();
123 /* embedding the font */
124 if (ext && !strcmp(".ttf", ext))
125 font_ct[f] = font_outdat(path, font_ps[f], font_ix[f]);
126 /* the font descriptor */
127 des_obj = obj_beg(0);
128 pdfout("<<\n");
129 pdfout(" /Type /FontDescriptor\n");
130 pdfout(" /FontName /%s\n", font_ps[f]);
131 pdfout(" /Flags 0\n");
132 pdfout(" /MissingWidth 255\n");
133 pdfout(" /StemV 100\n");
134 pdfout(" /StemH 100\n");
135 pdfout(" /CapHeight 100\n");
136 pdfout(" /Ascent 100\n");
137 pdfout(" /Descent 100\n");
138 if (font_ct[f] >= 0)
139 pdfout(" /FontFile2 %d 0 R\n", font_ct[f]);
140 pdfout(">>\n");
141 obj_end();
142 /* the font object */
143 obj_beg(font_id[f]);
144 pdfout("<<\n");
145 pdfout(" /Type /Font\n");
146 pdfout(" /Subtype /%s\n",
147 ext && !strcmp(".ttf", ext) ? "TrueType" : "Type1");
148 pdfout(" /BaseFont /%s\n", font_ps[f]);
149 pdfout(" /FirstChar 0\n");
150 pdfout(" /LastChar 255\n");
151 pdfout(" /Widths [");
152 for (i = 0; i < 256; i++) {
153 struct glyph *g = font_glget(fn, font_ix[f] * 256 + i);
154 pdfout(" %d", (g ? g->wid : 0) * dev_res / 72);
156 pdfout(" ]\n");
157 pdfout(" /FontDescriptor %d 0 R\n", des_obj);
158 pdfout(" /Encoding %d 0 R\n", enc_obj);
159 pdfout(">>\n");
160 obj_end();
163 static int font_put(struct font *fn, int ix)
165 int i;
166 char *name = font_name(fn);
167 for (i = 0; i < font_n; i++)
168 if (!strcmp(font_ps[i], font_name(fn)) && font_ix[i] == ix)
169 return i;
170 if (font_n == font_sz) {
171 font_sz += 128;
172 font_id = mextend(font_id, font_n, font_sz, sizeof(font_id[0]));
173 font_ps = mextend(font_ps, font_n, font_sz, sizeof(font_ps[0]));
174 font_ix = mextend(font_ix, font_n, font_sz, sizeof(font_ix[0]));
175 font_ct = mextend(font_ct, font_n, font_sz, sizeof(font_ct[0]));
177 font_id[font_n] = obj_map();
178 font_ix[font_n] = ix;
179 font_ps[font_n] = malloc(strlen(name) + 1);
180 font_ct[font_n] = -1;
181 strcpy(font_ps[font_n], name);
182 font_n++;
183 font_out(fn, font_n - 1);
184 return font_n - 1;
187 void out(char *s, ...)
191 static void o_flush(void)
193 if (o_queued == 1)
194 sbuf_printf(pg, ") Tj\n");
195 o_queued = 0;
198 static int o_loadfont(struct glyph *g)
200 struct font *fn = g ? g->font : dev_font(o_f);
201 int ix = font_glnum(fn, g) / 256;
202 char *name = font_name(fn);
203 int i;
204 int id;
205 for (i = 0; i < o_fsn; i++)
206 if (!strcmp(name, font_ps[o_fs[i]]) && font_ix[o_fs[i]] == ix)
207 return i;
208 id = font_put(fn, ix);
209 if (o_fsn == o_fssz) {
210 o_fssz += 128;
211 o_fs = mextend(o_fs, o_fsn, o_fssz, sizeof(o_fs[0]));
213 o_fs[o_fsn++] = id;
214 return o_fsn - 1;
217 #define PREC 1000
218 #define PRECN "3"
220 static void o_queue(struct glyph *g)
222 int pos;
223 if (o_h != p_h || o_v != p_v) {
224 long h = o_h * PREC * 72 / dev_res;
225 long v = pdf_height * PREC - (o_v * PREC * 72 / dev_res);
226 o_flush();
227 sbuf_printf(pg, "1 0 0 1 %d.%0" PRECN "d %d.%0" PRECN "d Tm\n",
228 h / PREC, h % PREC, v / PREC, v % PREC);
229 p_h = o_h;
230 p_v = o_v;
232 if (!o_queued)
233 sbuf_printf(pg, "(");
234 o_queued = 1;
235 pos = font_glnum(g->font, g) % 256;
236 sbuf_printf(pg, "\\%d%d%d", (pos >> 6) & 7, (pos >> 3) & 7, pos & 7);
237 p_h += font_wid(g->font, o_s, g->wid);
240 static void out_fontup(void)
242 if (o_m != p_m) {
243 o_flush();
244 p_m = o_m;
246 if (o_pf != p_pf || o_s != p_s) {
247 int f = o_fs[o_pf];
248 o_flush();
249 sbuf_printf(pg, "/%s.%d %d Tf\n", font_ps[f], font_ix[f], o_s);
250 p_pf = o_pf;
251 p_s = o_s;
255 void outc(char *c)
257 struct glyph *g;
258 struct font *fn;
259 g = dev_glyph(c, o_f);
260 fn = g ? g->font : dev_font(o_f);
261 if (!g) {
262 outrel(*c == ' ' && fn ? font_swid(fn, o_s) : 1, 0);
263 return;
265 o_pf = o_loadfont(g);
266 out_fontup();
267 o_queue(g);
270 void outh(int h)
272 o_h = h;
275 void outv(int v)
277 o_v = v;
280 void outrel(int h, int v)
282 o_h += h;
283 o_v += v;
286 void outfont(int f)
288 if (dev_font(f))
289 o_f = f;
292 void outsize(int s)
294 if (s > 0)
295 o_s = s;
298 void outcolor(int c)
300 o_m = c;
303 void outrotate(int deg)
307 void outeps(char *eps)
311 void outlink(char *spec)
315 void outpage(void)
317 o_v = 0;
318 o_h = 0;
319 p_v = 0;
320 p_h = 0;
321 p_s = 0;
322 p_f = 0;
323 p_m = 0;
326 void outmnt(int f)
328 if (p_f == f)
329 p_f = -1;
332 void outgname(int g)
336 void drawbeg(void)
340 void drawend(int close, int fill)
344 void drawmbeg(char *s)
348 void drawmend(char *s)
352 void drawl(int h, int v)
356 void drawc(int c)
360 void drawe(int h, int v)
364 void drawa(int h1, int v1, int h2, int v2)
368 void draws(int h1, int v1, int h2, int v2)
372 void ps_header(char *title, int pagewidth, int pageheight, int linewidth)
374 pdf_title = title;
375 obj_map();
376 pdf_root = obj_map();
377 pdf_pages = obj_map();
378 pdf_title = title;
379 pdfout("%%PDF-1.6\n");
380 pdf_width = (pagewidth * 72 + 127) / 254;
381 pdf_height = (pageheight * 72 + 127) / 254;
384 void ps_trailer(int pages)
386 int i;
387 int xref_off;
388 int info_id;
389 /* pdf pages object */
390 obj_beg(pdf_pages);
391 pdfout("<<\n");
392 pdfout(" /Type /Pages\n");
393 pdfout(" /MediaBox [ 0 0 %d %d ]\n", pdf_width, pdf_height);
394 pdfout(" /Count %d\n", page_n);
395 pdfout(" /Kids [");
396 for (i = 0; i < page_n; i++)
397 pdfout(" %d 0 R", page_id[i]);
398 pdfout(" ]\n");
399 pdfout(">>\n");
400 obj_end();
401 /* pdf root object */
402 obj_beg(pdf_root);
403 pdfout("<<\n");
404 pdfout(" /Type /Catalog\n");
405 pdfout(" /Pages %d 0 R\n", pdf_pages);
406 pdfout(">>\n");
407 obj_end();
408 /* info object */
409 info_id = obj_beg(0);
410 pdfout("<<\n");
411 if (pdf_title)
412 pdfout(" /Title (%s)\n", pdf_title);
413 pdfout(" /Creator (Neatroff)\n");
414 pdfout(" /Producer (Neatpost)\n");
415 pdfout(">>\n");
416 obj_end();
417 /* the xref */
418 xref_off = pdf_pos;
419 pdfout("xref\n");
420 pdfout("0 %d\n", obj_n);
421 pdfout("0000000000 65535 f \n");
422 for (i = 1; i < obj_n; i++)
423 pdfout("%010d 00000 n \n", obj_off[i]);
424 /* the trailer */
425 pdfout("trailer\n");
426 pdfout("<<\n");
427 pdfout(" /Size %d\n", obj_n);
428 pdfout(" /Root %d 0 R\n", pdf_root);
429 pdfout(" /Info %d 0 R\n", info_id);
430 pdfout(">>\n");
431 pdfout("startxref\n");
432 pdfout("%d\n", xref_off);
433 pdfout("%%%%EOF\n");
434 free(page_id);
435 free(obj_off);
436 for (i = 0; i < font_n; i++)
437 free(font_ps[i]);
438 free(font_ps);
439 free(font_ct);
440 free(font_id);
441 free(font_ix);
444 void ps_pagebeg(int n)
446 pg = sbuf_make();
447 sbuf_printf(pg, "BT\n");
450 void ps_pageend(int n)
452 int cont_id;
453 int i;
454 o_flush();
455 sbuf_printf(pg, "ET\n");
456 /* page contents */
457 cont_id = obj_beg(0);
458 pdfout("<<\n");
459 pdfout(" /Length %d\n", sbuf_len(pg));
460 pdfout(">>\n");
461 pdfout("stream\n");
462 pdfout("%s", sbuf_buf(pg));
463 pdfout("endstream\n");
464 obj_end();
465 /* the page object */
466 if (page_n == page_sz) {
467 page_sz += 1024;
468 page_id = mextend(page_id, page_n, page_sz, sizeof(page_id[0]));
470 page_id[page_n++] = obj_beg(0);
471 pdfout("<<\n");
472 pdfout(" /Type /Page\n");
473 pdfout(" /Parent %d 0 R\n", pdf_pages);
474 pdfout(" /Resources <<\n");
475 pdfout(" /Font <<");
476 for (i = 0; i < o_fsn; i++)
477 pdfout(" /%s.%d %d 0 R",
478 font_ps[o_fs[i]], font_ix[o_fs[i]], font_id[o_fs[i]]);
479 pdfout(" >>\n");
480 pdfout(" >>\n");
481 pdfout(" /Contents %d 0 R\n", cont_id);
482 pdfout(">>\n");
483 obj_end();
484 sbuf_free(pg);
485 free(o_fs);
486 o_fs = NULL;
487 o_fsn = 0;
488 o_fssz = 0;