pdf: a basic pdf post-processor
[neatpost.git] / ps.c
blob4ccd0178f65069d2a32dd9ecd3c87e3e88a88f68
1 #include <ctype.h>
2 #include <stdarg.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include "post.h"
8 static int o_f, o_s, o_m; /* font and size */
9 static int o_h, o_v; /* current user position */
10 static int p_f, p_s, p_m; /* output postscript font */
11 static int o_qtype; /* queued character type */
12 static int o_qv, o_qh, o_qend; /* queued character position */
13 static int o_rh, o_rv, o_rdeg; /* previous rotation position and degree */
14 static int o_gname; /* use glyphshow for all glyphs */
16 static char o_fonts[FNLEN * NFONTS] = " ";
18 static void outvf(char *s, va_list ap)
20 vfprintf(stdout, s, ap);
23 static void outf(char *s, ...)
25 va_list ap;
26 va_start(ap, s);
27 outvf(s, ap);
28 va_end(ap);
31 static void o_flush(void)
33 if (o_qtype == 1)
34 outf(") %d %d w\n", o_qh, o_qv);
35 if (o_qtype == 2)
36 outf("] %d %d g\n", o_qh, o_qv);
37 o_qtype = 0;
40 void outgname(int g)
42 o_gname = g;
45 void outpage(void)
47 o_flush();
48 o_v = 0;
49 o_h = 0;
50 p_s = 0;
51 p_f = 0;
52 p_m = 0;
53 o_rdeg = 0;
56 static void o_queue(struct glyph *g)
58 int type = 1 + (g->pos <= 0 || o_gname);
59 if (o_qtype != type || o_qend != o_h || o_qv != o_v) {
60 o_flush();
61 o_qh = o_h;
62 o_qv = o_v;
63 o_qtype = type;
64 outf(type == 1 ? "(" : "[");
66 if (o_qtype == 1) {
67 if (g->pos >= ' ' && g->pos <= '~')
68 outf("%s%c", strchr("()\\", g->pos) ? "\\" : "", g->pos);
69 else
70 outf("\\%d%d%d", (g->pos >> 6) & 7,
71 (g->pos >> 3) & 7, g->pos & 7);
72 } else {
73 outf("/%s", g->id);
75 o_qend = o_h + font_wid(g->font, o_s, g->wid);
78 /* calls o_flush() if necessary */
79 void out(char *s, ...)
81 va_list ap;
82 o_flush();
83 va_start(ap, s);
84 outvf(s, ap);
85 va_end(ap);
88 static void out_fontup(int fid)
90 char fnname[FNLEN];
91 struct font *fn;
92 if (o_m != p_m) {
93 out("%d %d %d rgb\n", CLR_R(o_m), CLR_G(o_m), CLR_B(o_m));
94 p_m = o_m;
96 if (fid != p_f || o_s != p_s) {
97 fn = dev_font(fid);
98 out("%d /%s f\n", o_s, font_name(fn));
99 p_f = fid;
100 p_s = o_s;
101 sprintf(fnname, " %s ", font_name(fn));
102 if (!strstr(o_fonts, fnname))
103 sprintf(strchr(o_fonts, '\0'), "%s ", font_name(fn));
107 void outc(char *c)
109 struct glyph *g;
110 struct font *fn;
111 g = dev_glyph(c, o_f);
112 fn = g ? g->font : dev_font(o_f);
113 if (!g) {
114 outrel(*c == ' ' && fn ? font_swid(fn, o_s) : 1, 0);
115 return;
117 out_fontup(dev_fontid(fn));
118 o_queue(g);
121 void outh(int h)
123 o_h = h;
126 void outv(int v)
128 o_v = v;
131 void outrel(int h, int v)
133 o_h += h;
134 o_v += v;
137 void outfont(int f)
139 if (dev_font(f))
140 o_f = f;
143 /* a font was mounted at pos f */
144 void outmnt(int f)
146 if (p_f == f)
147 p_f = -1;
150 void outsize(int s)
152 if (s > 0)
153 o_s = s;
156 void outcolor(int c)
158 o_m = c;
161 void outrotate(int deg)
163 o_flush();
164 out_fontup(o_f);
165 if (o_rdeg)
166 outf("%d %d %d rot\n", -o_rdeg, o_rh, o_rv);
167 o_rdeg = deg;
168 o_rh = o_h;
169 o_rv = o_v;
170 outf("%d %d %d rot\n", deg, o_h, o_v);
173 static int draw_path; /* number of path segments */
174 static int draw_point; /* point was set for postscript newpath */
176 static void drawmv(void)
178 if (!draw_point)
179 outf("%d %d m ", o_h, o_v);
180 draw_point = 1;
183 /* start a multi-segment path */
184 void drawmbeg(char *s)
186 o_flush();
187 out_fontup(o_f);
188 draw_path = 1;
189 outf("gsave newpath %s\n", s);
192 /* end a multi-segment path */
193 void drawmend(char *s)
195 draw_path = 0;
196 draw_point = 0;
197 outf("%s grestore\n", s);
200 void drawbeg(void)
202 o_flush();
203 out_fontup(o_f);
204 if (draw_path)
205 return;
206 outf("newpath ");
209 void drawend(int close, int fill)
211 if (draw_path)
212 return;
213 draw_point = 0;
214 if (close)
215 outf("closepath ");
216 if (fill)
217 outf("fill\n");
218 else
219 outf("stroke\n");
222 void drawl(int h, int v)
224 drawmv();
225 outrel(h, v);
226 outf("%d %d drawl ", o_h, o_v);
229 void drawc(int c)
231 drawmv();
232 outrel(c, 0);
233 outf("%d %d drawe ", c, c);
236 void drawe(int h, int v)
238 drawmv();
239 outrel(h, 0);
240 outf("%d %d drawe ", h, v);
243 void drawa(int h1, int v1, int h2, int v2)
245 drawmv();
246 outf("%d %d %d %d drawa ", h1, v1, h2, v2);
247 outrel(h1 + h2, v1 + v2);
250 void draws(int h1, int v1, int h2, int v2)
252 drawmv();
253 outf("%d %d %d %d %d %d draws ", o_h, o_v, o_h + h1, o_v + v1,
254 o_h + h1 + h2, o_v + v1 + v2);
255 outrel(h1, v1);
258 static char *strcut(char *dst, char *src)
260 while (*src == ' ' || *src == '\n')
261 src++;
262 if (src[0] == '"') {
263 src++;
264 while (*src && (src[0] != '"' || src[1] == '"')) {
265 if (*src == '"')
266 src++;
267 *dst++ = *src++;
269 if (*src == '"')
270 src++;
271 } else {
272 while (*src && *src != ' ' && *src != '\n')
273 *dst++ = *src++;
275 *dst = '\0';
276 return src;
279 void outeps(char *spec)
281 char eps[1 << 12];
282 char buf[1 << 12];
283 int llx, lly, urx, ury;
284 int hwid, vwid;
285 FILE *filp;
286 int nspec, nbb;
287 spec = strcut(eps, spec);
288 if (!eps[0])
289 return;
290 nspec = sscanf(spec, "%d %d", &hwid, &vwid);
291 if (nspec < 1)
292 hwid = 0;
293 if (nspec < 2)
294 vwid = 0;
295 if (!(filp = fopen(eps, "r")))
296 return;
297 if (!fgets(buf, sizeof(buf), filp) ||
298 (strcmp(buf, "%!PS-Adobe-2.0 EPSF-1.2\n") &&
299 strcmp(buf, "%!PS-Adobe-2.0 EPSF-2.0\n") &&
300 strcmp(buf, "%!PS-Adobe-3.0 EPSF-3.0\n"))) {
301 fclose(filp);
302 return;
304 nbb = 0;
305 while (fgets(buf, sizeof(buf), filp))
306 if (!strncmp(buf, "%%BoundingBox: ", 15))
307 if ((nbb = sscanf(buf + 15, "%d %d %d %d",
308 &llx, &lly, &urx, &ury)) == 4)
309 break;
310 fclose(filp);
311 if (nbb < 4) /* no BoundingBox comment */
312 return;
313 if (hwid <= 0 && vwid <= 0)
314 hwid = (urx - llx) * dev_res / 72;
315 if (vwid <= 0)
316 vwid = (ury - lly) * hwid / (urx - llx);
317 if (hwid <= 0)
318 hwid = (urx - llx) * vwid / (ury - lly);
319 /* output the EPS file */
320 o_flush();
321 out_fontup(o_f);
322 outf("%d %d %d %d %d %d %d %d EPSFBEG\n",
323 llx, lly, hwid, urx - llx, vwid, ury - lly, o_h, o_v);
324 outf("%%%%BeginDocument: %s\n", eps);
325 filp = fopen(eps, "r");
326 while (fgets(buf, sizeof(buf), filp))
327 out("%s", buf);
328 fclose(filp);
329 outf("%%%%EndDocument\n");
330 outf("EPSFEND\n");
333 void outlink(char *spec)
335 char lnk[1 << 12];
336 int hwid, vwid;
337 int nspec;
338 spec = strcut(lnk, spec);
339 if (!lnk[0] || (nspec = sscanf(spec, "%d %d", &hwid, &vwid)) != 2)
340 return;
341 o_flush();
342 if (lnk[0] == '#' || isdigit((unsigned char) lnk[0])) {
343 outf("[ /Rect [ %d %d t %d %d t ] %s%s "
344 "/Subtype /Link /LNK pdfmark\n",
345 o_h, o_v, o_h + hwid, o_v + vwid,
346 lnk[0] == '#' ? "/Dest /" : "/Page ",
347 lnk[0] == '#' ? lnk + 1 : lnk);
348 } else {
349 outf("[ /Rect [ %d %d t %d %d t ] "
350 "/Action << /Subtype /URI /URI (%s) >> /Open true "
351 "/Subtype /Link /LNK pdfmark\n",
352 o_h, o_v, o_h + hwid, o_v + vwid, lnk);
356 void ps_pagebeg(int n)
358 out("%%%%Page: %d %d\n", n, n);
359 out("/saveobj save def\n");
360 out("mark\n");
361 out("%d pagesetup\n", n);
364 void ps_pageend(int n)
366 out("cleartomark\n");
367 out("showpage\n");
368 out("saveobj restore\n");
371 void ps_trailer(int pages)
373 out("%%%%Trailer\n");
374 out("done\n");
375 out("%%%%DocumentFonts: %s\n", o_fonts);
376 out("%%%%Pages: %d\n", pages);
377 out("%%%%EOF\n");
380 static char *prolog =
381 "/setup {\n"
382 " counttomark 2 idiv {def} repeat pop\n"
383 " /scaling 72 resolution div def\n"
384 " linewidth setlinewidth\n"
385 " 1 setlinecap\n"
386 " 0 pagesize 1 get translate\n"
387 " scaling scaling scale\n"
388 " 0 0 moveto\n"
389 "} def\n"
390 "\n"
391 "/pagesetup {\n"
392 " /page exch def\n"
393 " currentdict /pagedict known currentdict page known and {\n"
394 " page load pagedict exch get cvx exec\n"
395 " } if\n"
396 "} def\n"
397 "\n"
398 "/pdfmark where\n"
399 " { pop globaldict /?pdfmark /exec load put }\n"
400 " { globaldict begin\n"
401 " /?pdfmark /pop load def\n"
402 " /pdfmark /cleartomark load def\n"
403 " end }\n"
404 " ifelse\n"
405 "\n"
406 "/t {neg} bind def\n"
407 "/w {neg moveto show} bind def\n"
408 "/m {neg moveto} bind def\n"
409 "/g {neg moveto {glyphshow} forall} bind def\n"
410 "/rgb {255 div 3 1 roll 255 div 3 1 roll 255 div 3 1 roll setrgbcolor} bind def\n"
411 "/rot {/y exch def /x exch def x y neg translate rotate x neg y translate} bind def\n"
412 "/done {/lastpage where {pop lastpage} if} def\n"
413 "\n"
414 "% caching fonts, as selectfont is supposed to be doing\n"
415 "/fncache 16 dict def\n"
416 "/selectfont_append { fncache exch dup findfont put } bind def\n"
417 "/selectfont_cached {\n"
418 " exch dup fncache exch known not { dup selectfont_append } if\n"
419 " fncache exch get exch scalefont setfont\n"
420 "} bind def\n"
421 "/f {\n"
422 " exch dup 3 1 roll scaling div selectfont_cached\n"
423 " linewidth mul scaling 10 mul div setlinewidth\n"
424 "} bind def\n"
425 "\n"
426 "/savedmatrix matrix def\n"
427 "/drawl {\n"
428 " neg lineto\n"
429 "} bind def\n"
430 "/drawe {\n"
431 " savedmatrix currentmatrix pop scale\n"
432 " .5 0 rmoveto currentpoint .5 0 rmoveto .5 0 360 arc\n"
433 " savedmatrix setmatrix\n"
434 "} bind def\n"
435 "/drawa {\n"
436 " /dy2 exch def\n"
437 " /dx2 exch def\n"
438 " /dy1 exch def\n"
439 " /dx1 exch def\n"
440 " currentpoint dy1 neg add exch dx1 add exch\n"
441 " dx1 dx1 mul dy1 dy1 mul add sqrt\n"
442 " dy1 dx1 neg atan\n"
443 " dy2 neg dx2 atan\n"
444 " arc\n"
445 "} bind def\n"
446 "/draws {\n"
447 " /y2 exch def\n"
448 " /x2 exch def\n"
449 " /y1 exch def\n"
450 " /x1 exch def\n"
451 " /y0 exch def\n"
452 " /x0 exch def\n"
453 " x0 5 x1 mul add 6 div\n"
454 " y0 5 y1 mul add -6 div\n"
455 " x2 5 x1 mul add 6 div\n"
456 " y2 5 y1 mul add -6 div\n"
457 " x1 x2 add 2 div\n"
458 " y1 y2 add -2 div\n"
459 " curveto\n"
460 "} bind def\n"
461 "% including EPS files\n"
462 "/EPSFBEG {\n"
463 " /epsf_state save def\n"
464 " neg translate\n"
465 " div 3 1 roll div exch scale\n"
466 " neg exch neg exch translate\n"
467 " /dict_count countdictstack def\n"
468 " /op_count count 1 sub def\n"
469 " userdict begin\n"
470 " /showpage { } def\n"
471 " 0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin\n"
472 " 10 setmiterlimit [ ] 0 setdash newpath\n"
473 "} bind def\n"
474 "/EPSFEND {\n"
475 " count op_count sub {pop} repeat\n"
476 " countdictstack dict_count sub {end} repeat\n"
477 " epsf_state restore\n"
478 "} bind def\n";
480 /* pagewidth and pageheight are in tenths of a millimetre */
481 void ps_header(char *title, int pagewidth, int pageheight, int linewidth)
483 out("%%!PS-Adobe-2.0\n");
484 out("%%%%Version: 1.0\n");
485 if (title)
486 out("%%%%Title: %s\n", title);
487 out("%%%%Creator: Neatroff\n");
488 out("%%%%DocumentFonts: (atend)\n");
489 out("%%%%Pages: (atend)\n");
490 out("%%%%EndComments\n");
492 out("%%%%BeginProlog\n");
493 out("/resolution %d def\n", dev_res);
494 out("/pagesize [%d %d] def\n", (pagewidth * 72 + 127) / 254,
495 (pageheight * 72 + 127) / 254);
496 out("/linewidth %d.%02d def\n\n", linewidth / 100, linewidth % 100);
497 out("%s", prolog);
498 out("%%%%EndProlog\n");
499 out("%%%%BeginSetup\n");
500 out("<< /PageSize pagesize /ImagingBBox null >> setpagedevice\n");
501 out("mark\n");
502 out("setup\n");
503 out("%%%%EndSetup\n");