File indexing completed on 2024-12-22 04:04:08
0001 /* Copyright (C) 2001-2019 Peter Selinger. 0002 This file is part of Potrace. It is free software and it is covered 0003 by the GNU General Public License. See the file COPYING for details. */ 0004 0005 0006 /* The Postscript backend of Potrace. This can produce "ps" or "eps" 0007 output, and different kinds of graphical debugging 0008 output. Postscript compression is optionally supplied via the 0009 functions in flate.c. */ 0010 0011 #ifdef HAVE_CONFIG_H 0012 #include <config.h> 0013 #endif 0014 0015 #include <stdio.h> 0016 #include <stdarg.h> 0017 #include <string.h> 0018 #include <math.h> 0019 #include <stdlib.h> 0020 0021 #include "potracelib.h" 0022 #include "curve.h" 0023 #include "main.h" 0024 #include "backend_eps.h" 0025 #include "flate.h" 0026 #include "lists.h" 0027 #include "auxiliary.h" 0028 0029 #define SAFE_CALLOC(var, n, typ) \ 0030 if ((var = (typ *)calloc(n, sizeof(typ))) == NULL) goto calloc_error 0031 0032 typedef int color_t; 0033 0034 #define black 0x000000 0035 #define red 0xff0000 0036 #define green 0x008000 0037 #define blue 0x0000ff 0038 0039 #define TRY(x) if (x) goto try_error 0040 0041 /* ---------------------------------------------------------------------- */ 0042 /* functions for interfacing with compression backend */ 0043 0044 /* xship: callback function that must be initialized before calling 0045 any other functions of the "ship" family. xship_file must be 0046 initialized too. */ 0047 0048 /* print the token to f, but filtered through a compression 0049 filter in case filter!=0 */ 0050 static int (*xship)(FILE *f, int filter, const char *s, int len); 0051 static FILE *xship_file; 0052 0053 /* ship postscript code, filtered */ 0054 static int ship(const char *fmt, ...) { 0055 va_list args; 0056 static char buf[4096]; /* static string limit is okay here because 0057 we only use constant format strings - for 0058 the same reason, it is okay to use 0059 vsprintf instead of vsnprintf below. */ 0060 va_start(args, fmt); 0061 vsprintf(buf, fmt, args); 0062 buf[4095] = 0; 0063 va_end(args); 0064 0065 xship(xship_file, 1, buf, strlen(buf)); 0066 return 0; 0067 } 0068 0069 /* ship a postscript comment, unfiltered */ 0070 static int shipcom(const char *fmt, ...) { 0071 static char buf[4096]; 0072 va_list args; 0073 0074 va_start(args, fmt); 0075 vsprintf(buf, fmt, args); 0076 buf[4095] = 0; 0077 va_end(args); 0078 0079 xship(xship_file, 0, buf, strlen(buf)); 0080 return 0; 0081 } 0082 0083 /* set all callback functions */ 0084 static void eps_callbacks(FILE *fout) { 0085 if (info.compress && info.pslevel==2) { 0086 xship = lzw_xship; 0087 } else if (info.compress && info.pslevel==3) { 0088 xship = flate_xship; 0089 } else { 0090 xship = dummy_xship; 0091 } 0092 xship_file = fout; 0093 } 0094 0095 /* ---------------------------------------------------------------------- */ 0096 /* postscript path-drawing auxiliary functions */ 0097 0098 /* coordinate quantization */ 0099 static inline point_t unit(dpoint_t p) { 0100 point_t q; 0101 0102 q.x = (long)(floor(p.x*info.unit+.5)); 0103 q.y = (long)(floor(p.y*info.unit+.5)); 0104 return q; 0105 } 0106 0107 /* current point */ 0108 static point_t cur; 0109 0110 static void eps_coords(dpoint_t p) { 0111 cur = unit(p); 0112 ship("%ld %ld ", cur.x, cur.y); 0113 } 0114 0115 static void eps_rcoords(dpoint_t p) { 0116 point_t q; 0117 0118 q = unit(p); 0119 ship("%ld %ld ", q.x-cur.x, q.y-cur.y); 0120 cur = q; 0121 } 0122 0123 static void eps_moveto(dpoint_t p) { 0124 eps_coords(p); 0125 ship("moveto\n"); 0126 } 0127 0128 /* move to point + offset */ 0129 static void eps_moveto_offs(dpoint_t p, double xoffs, double yoffs) { 0130 /* note: structs are passed by value, so the following assignment 0131 does not modify the original struct in the caller */ 0132 p.x += xoffs; 0133 p.y += yoffs; 0134 eps_coords(p); 0135 ship("moveto\n"); 0136 } 0137 0138 static void eps_lineto(dpoint_t p) { 0139 eps_rcoords(p); 0140 ship("rlineto\n"); 0141 } 0142 0143 static void eps_curveto(dpoint_t p1, dpoint_t p2, dpoint_t p3) { 0144 point_t q1, q2, q3; 0145 0146 q1 = unit(p1); 0147 q2 = unit(p2); 0148 q3 = unit(p3); 0149 0150 ship("%ld %ld %ld %ld %ld %ld rcurveto\n", q1.x-cur.x, q1.y-cur.y, q2.x-cur.x, q2.y-cur.y, q3.x-cur.x, q3.y-cur.y); 0151 0152 cur = q3; 0153 } 0154 0155 /* this procedure returns a statically allocated string */ 0156 static const char *eps_colorstring(const color_t col) { 0157 double r, g, b; 0158 static char buf[100]; 0159 0160 r = (col & 0xff0000) >> 16; 0161 g = (col & 0x00ff00) >> 8; 0162 b = (col & 0x0000ff) >> 0; 0163 0164 if (r==0 && g==0 && b==0) { 0165 return "0 setgray"; 0166 } else if (r==255 && g==255 && b==255) { 0167 return "1 setgray"; 0168 } else if (r == g && g == b) { 0169 sprintf(buf, "%.3f setgray", r/255.0); 0170 return buf; 0171 } else { 0172 sprintf(buf, "%.3f %.3f %.3f setrgbcolor", r/255.0, g/255.0, b/255.0); 0173 return buf; 0174 } 0175 } 0176 0177 static color_t eps_color = -1; 0178 static double eps_width = -1; 0179 0180 static void eps_setcolor(const color_t col) { 0181 if (col == eps_color) { 0182 return; 0183 } 0184 eps_color = col; 0185 0186 ship("%s\n", eps_colorstring(col)); 0187 } 0188 0189 static void eps_linewidth(double w) { 0190 if (w == eps_width) { 0191 return; 0192 } 0193 eps_width = w; 0194 ship("%f setlinewidth\n", w * info.unit); 0195 } 0196 0197 /* ---------------------------------------------------------------------- */ 0198 /* functions for converting a path to postscript code */ 0199 0200 /* ---------------------------------------------------------------------- */ 0201 /* ASCII encoding */ 0202 0203 /* explicit encoding, does not use special macros */ 0204 static int eps_path_long(privcurve_t *curve) { 0205 int i; 0206 dpoint_t *c; 0207 int m = curve->n; 0208 0209 c = curve->c[m-1]; 0210 eps_moveto(c[2]); 0211 0212 for (i=0; i<m; i++) { 0213 c = curve->c[i]; 0214 switch (curve->tag[i]) { 0215 case POTRACE_CORNER: 0216 eps_lineto(c[1]); 0217 eps_lineto(c[2]); 0218 break; 0219 case POTRACE_CURVETO: 0220 eps_curveto(c[0], c[1], c[2]); 0221 break; 0222 } 0223 } 0224 return 0; 0225 } 0226 0227 /* size-optimized encoding relies on special macros */ 0228 static int eps_path_short(privcurve_t *curve) { 0229 int i, i1; 0230 long int *bq = NULL; /* bq[m] */ 0231 long int *aq = NULL; /* aq[m] */ 0232 point_t *v = NULL; /* v[m] */ 0233 dpoint_t *q = NULL; /* q[m] */ 0234 double M; 0235 int m = curve->n; 0236 0237 SAFE_CALLOC(bq, m, long int); 0238 SAFE_CALLOC(aq, m, long int); 0239 SAFE_CALLOC(v, m, point_t); 0240 SAFE_CALLOC(q, m, dpoint_t); 0241 0242 /* quantize vertices */ 0243 for (i=0; i<m; i++) { 0244 v[i] = unit(curve->vertex[i]); 0245 } 0246 0247 /* quantize beta */ 0248 for (i=0; i<m; i++) { 0249 i1 = mod(i+1,m); 0250 M = max(10, max(abs(v[i1].x-v[i].x), abs(v[i1].y-v[i].y))); 0251 bq[i] = (int)(M * curve->beta[i] + 0.5); 0252 if (curve->beta[i] != 0.5) { 0253 q[i1] = interval(bq[i]/M, dpoint(v[i]), dpoint(v[i1])); 0254 } else { 0255 q[i1] = interval(0.5, dpoint(v[i]), dpoint(v[i1])); 0256 } 0257 } 0258 0259 /* quantize alpha */ 0260 for (i=0; i<m; i++) { 0261 i1 = mod(i+1,m); 0262 M = max(10, max(max(abs(q[i].x-v[i].x), abs(q[i].y-v[i].y)), 0263 max(abs(v[i].x-q[i1].x), abs(v[i].y-q[i1].y)))); 0264 if (curve->tag[i] == POTRACE_CURVETO) { 0265 aq[i] = (int)(M * curve->alpha[i] + 0.5); 0266 if (aq[i] > M) { 0267 aq[i]--; 0268 } 0269 } 0270 } 0271 0272 /* generate output */ 0273 ship("%ld %ld ", v[m-1].x, v[m-1].y); 0274 ship("%ld %ld ", v[0].x - v[m-1].x, v[0].y - v[m-1].y); 0275 if (curve->beta[m-1] == 0.5) { 0276 ship("i\n"); 0277 } else { 0278 ship("%ld I\n", bq[m-1]); 0279 } 0280 for (i=0; i<m; i++) { 0281 if (i<m-1) { 0282 ship("%ld %ld ", v[i+1].x - v[i].x, v[i+1].y - v[i].y); 0283 if (curve->beta[i] != 0.5) { 0284 ship("%ld ", bq[i]); 0285 } 0286 } 0287 if (curve->tag[i] == POTRACE_CURVETO) { 0288 ship(curve->beta[i] == 0.5 ? "%ld c\n" : "%ld C\n", aq[i]); 0289 } else { 0290 ship(curve->beta[i] == 0.5 ? "v\n" : "V\n"); 0291 } 0292 } 0293 0294 free(bq); 0295 free(aq); 0296 free(v); 0297 free(q); 0298 return 0; 0299 0300 calloc_error: 0301 free(bq); 0302 free(aq); 0303 free(v); 0304 free(q); 0305 return 1; 0306 } 0307 0308 static int eps_path(privcurve_t *curve) { 0309 if (info.longcoding==0 && curve->alphacurve) { 0310 return eps_path_short(curve); 0311 } else { 0312 return eps_path_long(curve); 0313 } 0314 } 0315 0316 /* ---------------------------------------------------------------------- */ 0317 /* functions for rendering various internal data structures, used to 0318 generate debugging output */ 0319 0320 /* output jaggie curve in grey */ 0321 static void eps_jaggy(potrace_path_t *plist) { 0322 potrace_path_t *p; 0323 int i; 0324 0325 ship(".9 setgray\n"); 0326 list_forall (p, plist) { 0327 point_t *pt = p->priv->pt; 0328 point_t cur, prev; 0329 0330 if (p->sign == '+') { 0331 cur = prev = pt[p->priv->len-1]; 0332 eps_moveto(dpoint(cur)); 0333 for (i=0; i<p->priv->len; i++) { 0334 if (pt[i].x != cur.x && pt[i].y != cur.y) { 0335 cur = prev; 0336 eps_lineto(dpoint(cur)); 0337 } 0338 prev = pt[i]; 0339 } 0340 eps_lineto(dpoint(pt[p->priv->len-1])); 0341 } else { 0342 cur = prev = pt[0]; 0343 eps_moveto(dpoint(cur)); 0344 for (i=p->priv->len-1; i>=0; i--) { 0345 if (pt[i].x != cur.x && pt[i].y != cur.y) { 0346 cur = prev; 0347 eps_lineto(dpoint(cur)); 0348 } 0349 prev = pt[i]; 0350 } 0351 eps_lineto(dpoint(pt[0])); 0352 } 0353 if (p->next == NULL || p->next->sign == '+') { 0354 ship("fill\n"); 0355 } 0356 } 0357 } 0358 0359 /* output polygon */ 0360 static void eps_polygon(privcurve_t *curve, const color_t col) { 0361 int i; 0362 int m = curve->n; 0363 0364 eps_linewidth(.02); 0365 eps_setcolor(col); 0366 eps_moveto(curve->vertex[m-1]); 0367 for (i=0; i<m; i++) { 0368 eps_lineto(curve->vertex[i]); 0369 } 0370 ship("stroke\n"); 0371 } 0372 0373 /* output lines L and parameter alpha */ 0374 static void eps_L(privcurve_t *curve, const color_t col) { 0375 int i, i1; 0376 double gamma; 0377 dpoint_t p1, p4, p1l, p4l; 0378 int m = curve->n; 0379 0380 for (i=0; i<m; i++) { 0381 i1 = mod(i+1, m); 0382 gamma = curve->alpha0[i1] * 0.75; 0383 0384 p1 = curve->c[i][2]; 0385 p4 = curve->c[i1][2]; 0386 p1l = interval(gamma, p1, curve->vertex[i1]); 0387 p4l = interval(gamma, p4, curve->vertex[i1]); 0388 eps_linewidth(.02); 0389 eps_setcolor(col); 0390 eps_moveto(p1l); 0391 eps_lineto(p4l); 0392 ship("stroke\n"); 0393 eps_moveto_offs(curve->vertex[i1], -.4, -.4); 0394 ship("times (%.2f) show\n", curve->alpha0[i1]); 0395 } 0396 } 0397 0398 /* ---------------------------------------------------------------------- */ 0399 /* postscript macros */ 0400 0401 /* special macros for size-optimized rendering of Bezier curves */ 0402 static const char *optimacros = 0403 "/D{bind def}def\n" 0404 "/R{roll}D\n" 0405 "/K{copy}D\n" 0406 "/P{pop}D\n" 0407 "/p{3 2 R add 3 1 R add exch}D\n" 0408 "/t{dup 4 3 R mul 3 1 R mul}D\n" 0409 "/a{dup 1 sub neg 4 1 R t 5 2 R t p}D\n" 0410 "/m{2 K le{exch}if P}D\n" 0411 "/n{abs exch abs m}D\n" 0412 "/d{-1 t p n}D\n" 0413 "/s{[4 2 R] cvx def}D\n" 0414 "/g{7 K P 4 K P P d 5 1 R d 10 m m div 5 K 12 8 R 5 4 R a 9 4 R 3 2 R a 6 4 R curveto}D\n" 0415 "/e{4 2 R lineto lineto P P}D\n" 0416 "/q{3 K P n 10 m div}D\n" 0417 "/f{x y 7 4 R 5 1 R 4 K p /y s 7 2 R 2 K 9 7 R 7 6 R t p 2 K /x s}D\n" 0418 "/C{4 1 R q f 7 6 R g}D\n" 0419 "/V{q f e}D\n" 0420 "/c{3 1 R .5 f 7 6 R g}D\n" 0421 "/v{.5 f e}D\n" 0422 "/j{5 K P p /y s 3 K t 7 5 R p /x s x moveto P}D\n" 0423 "/i{.5 j}D\n" 0424 "/I{dup 6 1 R q j 3 2 R}D\n" 0425 "/z{closepath}D\n" 0426 "/b{%s z fill}D\n" 0427 "/w{%s z fill}D\n"; 0428 0429 /* special macros for debug output */ 0430 static const char *debugmacros = 0431 "/unit { %f } def\n" 0432 "/box { newpath 0 0 moveto 0 1 lineto 1 1 lineto 1 0 lineto closepath } def\n" 0433 "/circ { newpath 0 0 1 0 360 arc closepath } def\n" 0434 "/dot { gsave .15 mul dup scale circ fill grestore } def\n" 0435 "/sq { gsave unit unit scale -.5 -.5 translate box .02 setlinewidth stroke grestore } def\n" 0436 "/sq1 { gsave translate sq unit .6 mul dot grestore } def\n" 0437 "/dot2 { gsave translate unit dot grestore } def\n" 0438 "/usq { gsave unit unit scale -.5 -.5 rmoveto 0 1 rlineto 1 0 rlineto 0 -1 rlineto closepath .02 setlinewidth stroke grestore } def\n" 0439 "/dot1 { gsave translate unit .3 mul dup scale circ fill grestore } def\n" 0440 "/times { /Times-Roman findfont unit .3 mul scalefont setfont } def\n" 0441 "/times1 { /Times-Roman findfont unit 10 mul scalefont setfont 0 0 0 setrgbcolor } def\n" 0442 "/times2 { /Times-Roman findfont unit 2 mul scalefont setfont 0 0 0 setrgbcolor } def\n"; 0443 0444 /* ---------------------------------------------------------------------- */ 0445 /* Backends for various types of output. */ 0446 0447 /* Normal output: black on transparent */ 0448 static int render0(potrace_path_t *plist) { 0449 potrace_path_t *p; 0450 0451 if (info.longcoding) { 0452 eps_setcolor(info.color); 0453 list_forall (p, plist) { 0454 TRY(eps_path(p->priv->fcurve)); 0455 ship("closepath\n"); 0456 if (p->next == NULL || p->next->sign == '+') { 0457 ship("fill\n"); 0458 } 0459 } 0460 } else { 0461 list_forall (p, plist) { 0462 TRY(eps_path(p->priv->fcurve)); 0463 if (p->next == NULL || p->next->sign == '+') { 0464 ship("b\n"); 0465 } else { 0466 ship("z\n"); 0467 } 0468 } 0469 } 0470 return 0; 0471 0472 try_error: 0473 return 1; 0474 } 0475 0476 /* Opaque output: alternating black and white */ 0477 static int render0_opaque(potrace_path_t *plist) { 0478 potrace_path_t *p; 0479 0480 if (info.longcoding) { 0481 list_forall (p, plist) { 0482 TRY(eps_path(p->priv->fcurve)); 0483 ship("closepath\n"); 0484 eps_setcolor(p->sign=='+' ? info.color : info.fillcolor); 0485 ship("fill\n"); 0486 } 0487 } else { 0488 list_forall (p, plist) { 0489 TRY(eps_path(p->priv->fcurve)); 0490 ship(p->sign=='+' ? "b\n" : "w\n"); 0491 } 0492 } 0493 return 0; 0494 0495 try_error: 0496 return 1; 0497 } 0498 0499 /* Debug output type 1 (show optimal polygon) */ 0500 static int render1(potrace_path_t *plist) { 0501 potrace_path_t *p; 0502 int i; 0503 0504 eps_jaggy(plist); 0505 0506 list_forall (p, plist) { 0507 0508 point_t *pt = p->priv->pt; 0509 int n = p->priv->len; 0510 int m = p->priv->m; 0511 int *po = p->priv->po; 0512 0513 eps_linewidth(.02); 0514 eps_setcolor(black); 0515 /* output jaggie curve in boxed style */ 0516 for (i=1; i<n; i++) { 0517 eps_moveto(dpoint(pt[i-1])); 0518 eps_lineto(dpoint(pt[i])); 0519 ship("stroke\n"); 0520 eps_coords(dpoint(pt[i])); 0521 ship("sq1\n"); 0522 } 0523 eps_moveto(dpoint(pt[n-1])); 0524 eps_lineto(dpoint(pt[0])); 0525 ship("stroke\n"); 0526 eps_coords(dpoint(pt[0])); 0527 ship("sq1\n"); 0528 0529 /* output the uncorrected polygon */ 0530 eps_linewidth(.1); 0531 eps_setcolor(blue); 0532 eps_moveto(dpoint(pt[po[0]])); 0533 for (i=1; i<m; i++) { 0534 eps_lineto(dpoint(pt[po[i]])); 0535 } 0536 eps_lineto(dpoint(pt[po[0]])); 0537 ship("stroke\n"); 0538 for (i=0; i<m; i++) { 0539 eps_coords(dpoint(pt[po[i]])); 0540 ship("dot2\n"); 0541 } 0542 } 0543 return 0; 0544 } 0545 0546 /* Debug output type 2 (show corrected polygon and edge detection) */ 0547 static int render2(potrace_path_t *plist) { 0548 potrace_path_t *p; 0549 int i; 0550 0551 /* output original bitmap in grey */ 0552 eps_jaggy(plist); 0553 0554 list_forall (p, plist) { 0555 /* output polygon with corrected edges, lines L, and parameter alpha */ 0556 eps_polygon(&p->priv->curve, black); 0557 eps_L(&p->priv->curve, black); 0558 0559 /* output the vertex unit squares */ 0560 for (i=0; i<p->priv->curve.n; i++) { 0561 eps_moveto(p->priv->curve.vertex[i]); 0562 ship("usq\n"); 0563 } 0564 0565 /* output the path */ 0566 eps_linewidth(.1); 0567 eps_setcolor(blue); 0568 TRY(eps_path(&p->priv->curve)); 0569 ship("closepath\n"); 0570 ship("stroke\n"); 0571 0572 if (info.param->opticurve && info.debug == 3) { 0573 0574 /* output opticurve */ 0575 eps_linewidth(.05); 0576 eps_setcolor(red); 0577 TRY(eps_path(&p->priv->ocurve)); 0578 ship("closepath\n"); 0579 ship("stroke\n"); 0580 0581 /* output dots */ 0582 for (i=0; i<p->priv->ocurve.n; i++) { 0583 eps_coords(p->priv->ocurve.c[i][2]); 0584 ship("dot1\n"); 0585 } 0586 } 0587 } 0588 return 0; 0589 0590 try_error: 0591 return 1; 0592 } 0593 0594 /* Free-style debug output */ 0595 static int render_debug(potrace_path_t *plist) { 0596 potrace_path_t *p; 0597 int count; 0598 int i; 0599 0600 /* output original bitmap in grey */ 0601 eps_jaggy(plist); 0602 0603 count = -1; 0604 list_forall (p, plist) { 0605 count++; 0606 0607 /* output path numbers */ 0608 eps_moveto_offs(p->priv->curve.vertex[0], 0, 5); 0609 ship("times1 (%d) show\n", count); 0610 0611 /* output polygon with corrected edges, lines L, and parameter alpha */ 0612 eps_polygon(&p->priv->curve, black); 0613 eps_L(&p->priv->curve, black); 0614 0615 /* output the vertex unit squares */ 0616 for (i=0; i<p->priv->curve.n; i++) { 0617 eps_moveto(p->priv->curve.vertex[i]); 0618 ship("usq\n"); 0619 } 0620 0621 /* output the vertex numbers */ 0622 for (i=0; i<p->priv->curve.n; i++) { 0623 eps_moveto_offs(p->priv->curve.vertex[i], +1, +1); 0624 ship("times2 (%d) show\n", i); 0625 } 0626 0627 /* output the path */ 0628 eps_linewidth(.1); 0629 eps_setcolor(blue); 0630 TRY(eps_path(&p->priv->curve)); 0631 ship("closepath\n"); 0632 ship("stroke\n"); 0633 0634 if (info.param->opticurve) { 0635 0636 /* output the opti-verteces polygon */ 0637 eps_polygon(&p->priv->ocurve, green); 0638 0639 /* output opticurve */ 0640 eps_linewidth(.05); 0641 eps_setcolor(red); 0642 TRY(eps_path(&p->priv->ocurve)); 0643 ship("closepath\n"); 0644 ship("stroke\n"); 0645 0646 /* output dots */ 0647 for (i=0; i<p->priv->ocurve.n; i++) { 0648 eps_coords(p->priv->ocurve.c[i][2]); 0649 ship("dot1\n"); 0650 } 0651 0652 /* output beta parameters */ 0653 for (i=0; i<p->priv->ocurve.n; i++) { 0654 eps_moveto_offs(p->priv->ocurve.c[i][2], +.4, -.4); 0655 ship("times (%.2f) show\n", p->priv->ocurve.beta[i]); 0656 } 0657 } 0658 } 0659 return 0; 0660 0661 try_error: 0662 return 1; 0663 } 0664 0665 /* select the appropriate rendering function from above */ 0666 static int eps_render(potrace_path_t *plist) { 0667 int r; 0668 0669 switch (info.debug) { 0670 case 0: 0671 if (info.opaque) { 0672 r = render0_opaque(plist); 0673 } else { 0674 r = render0(plist); 0675 } 0676 break; 0677 case 1: 0678 r = render1(plist); 0679 break; 0680 case 2: case 3: 0681 r = render2(plist); 0682 break; 0683 default: 0684 r = render_debug(plist); 0685 break; 0686 } 0687 return r; 0688 } 0689 0690 /* ---------------------------------------------------------------------- */ 0691 /* EPS header and footer */ 0692 0693 static int eps_init(imginfo_t *imginfo) { 0694 double origx = imginfo->trans.orig[0] + imginfo->lmar; 0695 double origy = imginfo->trans.orig[1] + imginfo->bmar; 0696 double scalex = imginfo->trans.scalex / info.unit; 0697 double scaley = imginfo->trans.scaley / info.unit; 0698 char *c0, *c1; 0699 0700 shipcom("%%!PS-Adobe-3.0 EPSF-3.0\n"); 0701 shipcom("%%%%Creator: " POTRACE " " VERSION ", written by Peter Selinger 2001-2019\n"); 0702 shipcom("%%%%LanguageLevel: %d\n", info.pslevel); 0703 shipcom("%%%%BoundingBox: 0 0 %.0f %.0f\n", 0704 ceil(imginfo->trans.bb[0]+imginfo->lmar+imginfo->rmar), 0705 ceil(imginfo->trans.bb[1]+imginfo->tmar+imginfo->bmar)); 0706 shipcom("%%%%HiResBoundingBox: 0 0 %f %f\n", 0707 imginfo->trans.bb[0]+imginfo->lmar+imginfo->rmar, 0708 imginfo->trans.bb[1]+imginfo->tmar+imginfo->bmar); 0709 shipcom("%%%%Pages: 1\n"); 0710 shipcom("%%%%EndComments\n"); 0711 0712 shipcom("%%%%Page: 1 1\n"); 0713 ship("save\n"); 0714 if (!info.longcoding) { 0715 c0 = strdup(eps_colorstring(info.color)); 0716 c1 = strdup(eps_colorstring(info.fillcolor)); 0717 if (!c0 || !c1) { 0718 free(c0); 0719 free(c1); 0720 return 1; 0721 } 0722 ship(optimacros, c0, c1); 0723 free(c0); 0724 free(c1); 0725 } 0726 if (info.debug) { 0727 ship(debugmacros, info.unit); 0728 } 0729 if (origx != 0 || origy != 0) { 0730 ship("%f %f translate\n", origx, origy); 0731 } 0732 if (info.angle != 0) { 0733 ship("%.2f rotate\n", info.angle); 0734 } 0735 ship("%f %f scale\n", scalex, scaley); 0736 0737 return 0; 0738 } 0739 0740 static void eps_term(void) { 0741 ship("restore\n"); 0742 shipcom("%%%%EOF\n"); 0743 } 0744 0745 /* public interface for EPS */ 0746 int page_eps(FILE *fout, potrace_path_t *plist, imginfo_t *imginfo) { 0747 eps_callbacks(fout); 0748 0749 TRY(eps_init(imginfo)); 0750 TRY(eps_render(plist)); 0751 eps_term(); 0752 return 0; 0753 0754 try_error: 0755 return 1; 0756 } 0757 0758 /* ---------------------------------------------------------------------- */ 0759 /* PostScript header and footer */ 0760 0761 static int eps_pagenumber; 0762 0763 int init_ps(FILE *fout) { 0764 char *c0, *c1; 0765 0766 /* set callback functions for shipping routines */ 0767 eps_callbacks(fout); 0768 0769 shipcom("%%!PS-Adobe-3.0\n"); 0770 shipcom("%%%%Creator: " POTRACE " " VERSION ", written by Peter Selinger 2001-2019\n"); 0771 shipcom("%%%%LanguageLevel: %d\n", info.pslevel); 0772 shipcom("%%%%BoundingBox: 0 0 %d %d\n", info.paperwidth, info.paperheight); 0773 shipcom("%%%%Pages: (atend)\n"); 0774 shipcom("%%%%EndComments\n"); 0775 if (!info.longcoding || info.debug) { 0776 shipcom("%%%%BeginSetup\n"); 0777 if (!info.longcoding) { 0778 c0 = strdup(eps_colorstring(info.color)); 0779 c1 = strdup(eps_colorstring(info.fillcolor)); 0780 if (!c0 || !c1) { 0781 free(c0); 0782 free(c1); 0783 return 1; 0784 } 0785 ship(optimacros, c0, c1); 0786 free(c0); 0787 free(c1); 0788 } 0789 if (info.debug) { 0790 ship(debugmacros, info.unit); 0791 } 0792 shipcom("%%%%EndSetup\n"); 0793 } 0794 eps_pagenumber = 0; 0795 fflush(fout); 0796 return 0; 0797 } 0798 0799 int term_ps(FILE *fout) { 0800 eps_callbacks(fout); 0801 0802 shipcom("%%%%Trailer\n"); 0803 shipcom("%%%%Pages: %d\n", eps_pagenumber); 0804 shipcom("%%%%EOF\n"); 0805 fflush(fout); 0806 0807 return 0; 0808 } 0809 0810 static void eps_pageinit_ps(imginfo_t *imginfo) { 0811 double origx = imginfo->trans.orig[0] + imginfo->lmar; 0812 double origy = imginfo->trans.orig[1] + imginfo->bmar; 0813 double scalex = imginfo->trans.scalex / info.unit; 0814 double scaley = imginfo->trans.scaley / info.unit; 0815 0816 eps_pagenumber++; 0817 eps_color = -1; 0818 eps_width = -1; 0819 0820 shipcom("%%%%Page: %d %d\n", eps_pagenumber, eps_pagenumber); 0821 ship("save\n"); 0822 if (origx != 0 || origy != 0) { 0823 ship("%f %f translate\n", origx, origy); 0824 } 0825 if (info.angle != 0) { 0826 ship("%.2f rotate\n", info.angle); 0827 } 0828 ship("%f %f scale\n", scalex, scaley); 0829 } 0830 0831 static void eps_pageterm_ps(void) { 0832 ship("restore\n"); 0833 ship("showpage\n"); 0834 } 0835 0836 int page_ps(FILE *fout, potrace_path_t *plist, imginfo_t *imginfo) { 0837 int r; 0838 0839 eps_callbacks(fout); 0840 0841 eps_pageinit_ps(imginfo); 0842 0843 r = eps_render(plist); 0844 if (r) { 0845 return r; 0846 } 0847 0848 eps_pageterm_ps(); 0849 0850 shipcom(""); 0851 0852 fflush(fout); 0853 0854 return 0; 0855 }