gvsig-raster / libjni-potrace / trunk / libjni-potrace / src / main / native / jpotrace / backend_eps.c @ 1780
History | View | Annotate | Download (20 KB)
1 |
/* Copyright (C) 2001-2007 Peter Selinger.
|
---|---|
2 |
This file is part of Potrace. It is free software and it is covered
|
3 |
by the GNU General Public License. See the file COPYING for details. */
|
4 |
|
5 |
/* $Id: backend_eps.c 147 2007-04-09 00:44:09Z selinger $ */
|
6 |
|
7 |
/* The Postscript backend of Potrace. This can produce "ps" or "eps"
|
8 |
output, and different kinds of graphical debugging
|
9 |
output. Postscript compression is optionally supplied via the
|
10 |
functions in flate.c. */
|
11 |
|
12 |
#include <stdio.h> |
13 |
#include <stdarg.h> |
14 |
#include <string.h> |
15 |
#include <math.h> |
16 |
#include <stdlib.h> |
17 |
|
18 |
#include "potracelib.h" |
19 |
#include "curve.h" |
20 |
#include "main.h" |
21 |
#include "backend_eps.h" |
22 |
#include "flate.h" |
23 |
#include "lists.h" |
24 |
#include "auxiliary.h" |
25 |
|
26 |
#ifdef HAVE_CONFIG_H
|
27 |
#include "config.h" |
28 |
#endif
|
29 |
|
30 |
#define SAFE_MALLOC(var, n, typ) \
|
31 |
if ((var = (typ *)malloc((n)*sizeof(typ))) == NULL) goto malloc_error |
32 |
|
33 |
typedef int color_t; |
34 |
|
35 |
#define black 0x000000 |
36 |
#define red 0xff0000 |
37 |
#define green 0x008000 |
38 |
#define blue 0x0000ff |
39 |
|
40 |
/* ---------------------------------------------------------------------- */
|
41 |
/* functions for interfacing with compression backend */
|
42 |
|
43 |
/* xship: callback function that must be initialized before calling
|
44 |
any other functions of the "ship" family. xship_file must be
|
45 |
initialized too. */
|
46 |
|
47 |
/* print the token to f, but filtered through a compression
|
48 |
filter in case filter!=0 */
|
49 |
static int (*xship)(FILE *f, int filter, char *s, int len); |
50 |
static FILE *xship_file;
|
51 |
|
52 |
/* ship postscript code, filtered */
|
53 |
static int ship(const char *fmt, ...) { |
54 |
va_list args; |
55 |
static char buf[4096]; /* static string limit is okay here because |
56 |
we only use constant format strings - for
|
57 |
the same reason, it is okay to use
|
58 |
vsprintf instead of vsnprintf below. */
|
59 |
va_start(args, fmt); |
60 |
vsprintf(buf, fmt, args); |
61 |
buf[4095] = 0; |
62 |
va_end(args); |
63 |
|
64 |
xship(xship_file, 1, buf, strlen(buf));
|
65 |
return 0; |
66 |
} |
67 |
|
68 |
/* ship a postscript comment, unfiltered */
|
69 |
static int shipcom(char *fmt, ...) { |
70 |
static char buf[4096]; |
71 |
va_list args; |
72 |
|
73 |
va_start(args, fmt); |
74 |
vsprintf(buf, fmt, args); |
75 |
buf[4095] = 0; |
76 |
va_end(args); |
77 |
|
78 |
xship(xship_file, 0, buf, strlen(buf));
|
79 |
return 0; |
80 |
} |
81 |
|
82 |
/* set all callback functions */
|
83 |
static void eps_callbacks(FILE *fout) { |
84 |
if (info.compress && info.pslevel==2) { |
85 |
xship = lzw_xship; |
86 |
} else if (info.compress && info.pslevel==3) { |
87 |
xship = flate_xship; |
88 |
} else {
|
89 |
xship = dummy_xship; |
90 |
} |
91 |
xship_file = fout; |
92 |
} |
93 |
|
94 |
/* ---------------------------------------------------------------------- */
|
95 |
/* postscript path-drawing auxiliary functions */
|
96 |
|
97 |
/* coordinate quantization */
|
98 |
static inline point_t unit(dpoint_t p) { |
99 |
point_t q; |
100 |
|
101 |
q.x = (long)(floor(p.x*info.unit+.5)); |
102 |
q.y = (long)(floor(p.y*info.unit+.5)); |
103 |
return q;
|
104 |
} |
105 |
|
106 |
/* current point */
|
107 |
static point_t cur;
|
108 |
|
109 |
static void eps_coords(dpoint_t p) { |
110 |
cur = unit(p); |
111 |
ship("%ld %ld ", cur.x, cur.y);
|
112 |
} |
113 |
|
114 |
static void eps_rcoords(dpoint_t p) { |
115 |
point_t q; |
116 |
|
117 |
q = unit(p); |
118 |
ship("%ld %ld ", q.x-cur.x, q.y-cur.y);
|
119 |
cur = q; |
120 |
} |
121 |
|
122 |
static void eps_moveto(dpoint_t p) { |
123 |
eps_coords(p); |
124 |
ship("moveto\n");
|
125 |
} |
126 |
|
127 |
/* move to point + offset */
|
128 |
static void eps_moveto_offs(dpoint_t p, double xoffs, double yoffs) { |
129 |
/* note: structs are passed by value, so the following assignment
|
130 |
does not modify the original struct in the caller */
|
131 |
p.x += xoffs; |
132 |
p.y += yoffs; |
133 |
eps_coords(p); |
134 |
ship("moveto\n");
|
135 |
} |
136 |
|
137 |
static void eps_lineto(dpoint_t p) { |
138 |
eps_rcoords(p); |
139 |
ship("rlineto\n");
|
140 |
} |
141 |
|
142 |
static void eps_curveto(dpoint_t p1, dpoint_t p2, dpoint_t p3) { |
143 |
point_t q1, q2, q3; |
144 |
|
145 |
q1 = unit(p1); |
146 |
q2 = unit(p2); |
147 |
q3 = unit(p3); |
148 |
|
149 |
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);
|
150 |
|
151 |
cur = q3; |
152 |
} |
153 |
|
154 |
/* this procedure returns a statically allocated string */
|
155 |
static char *eps_colorstring(const color_t col) { |
156 |
double r, g, b;
|
157 |
static char buf[100]; |
158 |
|
159 |
r = (col & 0xff0000) >> 16; |
160 |
g = (col & 0x00ff00) >> 8; |
161 |
b = (col & 0x0000ff) >> 0; |
162 |
|
163 |
if (r==0 && g==0 && b==0) { |
164 |
return "0 setgray"; |
165 |
} else if (r==255 && g==255 && b==255) { |
166 |
return "1 setgray"; |
167 |
} else if (r == g && g == b) { |
168 |
sprintf(buf, "%.3f setgray", r/255.0); |
169 |
return buf;
|
170 |
} else {
|
171 |
sprintf(buf, "%.3f %.3f %.3f setrgbcolor", r/255.0, g/255.0, b/255.0); |
172 |
return buf;
|
173 |
} |
174 |
} |
175 |
|
176 |
static color_t eps_color = -1; |
177 |
static double eps_width = -1; |
178 |
|
179 |
static void eps_setcolor(const color_t col) { |
180 |
if (col == eps_color) {
|
181 |
return;
|
182 |
} |
183 |
eps_color = col; |
184 |
|
185 |
ship("%s\n", eps_colorstring(col));
|
186 |
} |
187 |
|
188 |
static void eps_linewidth(double w) { |
189 |
if (w == eps_width) {
|
190 |
return;
|
191 |
} |
192 |
eps_width = w; |
193 |
ship("%f setlinewidth\n", w * info.unit);
|
194 |
} |
195 |
|
196 |
/* ---------------------------------------------------------------------- */
|
197 |
/* functions for converting a path to postscript code */
|
198 |
|
199 |
/* ---------------------------------------------------------------------- */
|
200 |
/* ASCII encoding */
|
201 |
|
202 |
/* explicit encoding, does not use special macros */
|
203 |
static int eps_path_long(privcurve_t *curve) { |
204 |
int i;
|
205 |
dpoint_t *c; |
206 |
int m = curve->n;
|
207 |
|
208 |
c = curve->c[m-1];
|
209 |
eps_moveto(c[2]);
|
210 |
|
211 |
for (i=0; i<m; i++) { |
212 |
c = curve->c[i]; |
213 |
switch (curve->tag[i]) {
|
214 |
case POTRACE_CORNER:
|
215 |
eps_lineto(c[1]);
|
216 |
eps_lineto(c[2]);
|
217 |
break;
|
218 |
case POTRACE_CURVETO:
|
219 |
eps_curveto(c[0], c[1], c[2]); |
220 |
break;
|
221 |
} |
222 |
} |
223 |
return 0; |
224 |
} |
225 |
|
226 |
/* size-optimized encoding relies on special macros */
|
227 |
static int eps_path_short(privcurve_t *curve) { |
228 |
int i, i1;
|
229 |
long int *bq = NULL; /* bq[m] */ |
230 |
long int *aq = NULL; /* aq[m] */ |
231 |
point_t *v = NULL; /* v[m] */ |
232 |
dpoint_t *q = NULL; /* q[m] */ |
233 |
double M;
|
234 |
int m = curve->n;
|
235 |
|
236 |
SAFE_MALLOC(bq, m, long int); |
237 |
SAFE_MALLOC(aq, m, long int); |
238 |
SAFE_MALLOC(v, m, point_t); |
239 |
SAFE_MALLOC(q, m, dpoint_t); |
240 |
|
241 |
/* quantize vertices */
|
242 |
for (i=0; i<m; i++) { |
243 |
v[i] = unit(curve->vertex[i]); |
244 |
} |
245 |
|
246 |
/* quantize beta */
|
247 |
for (i=0; i<m; i++) { |
248 |
i1 = mod(i+1,m);
|
249 |
M = max(10, max(abs(v[i1].x-v[i].x), abs(v[i1].y-v[i].y)));
|
250 |
bq[i] = (int)(M * curve->beta[i] + 0.5); |
251 |
if (curve->beta[i] != 0.5) { |
252 |
q[i1] = interval(bq[i]/M, dpoint(v[i]), dpoint(v[i1])); |
253 |
} else {
|
254 |
q[i1] = interval(0.5, dpoint(v[i]), dpoint(v[i1])); |
255 |
} |
256 |
} |
257 |
|
258 |
/* quantize alpha */
|
259 |
for (i=0; i<m; i++) { |
260 |
i1 = mod(i+1,m);
|
261 |
M = max(10, max(max(abs(q[i].x-v[i].x), abs(q[i].y-v[i].y)),
|
262 |
max(abs(v[i].x-q[i1].x), abs(v[i].y-q[i1].y)))); |
263 |
if (curve->tag[i] == POTRACE_CURVETO) {
|
264 |
aq[i] = (int)(M * curve->alpha[i] + 0.5); |
265 |
if (aq[i] > M) {
|
266 |
aq[i]--; |
267 |
} |
268 |
} |
269 |
} |
270 |
|
271 |
/* generate output */
|
272 |
ship("%ld %ld ", v[m-1].x, v[m-1].y); |
273 |
ship("%ld %ld ", v[0].x - v[m-1].x, v[0].y - v[m-1].y); |
274 |
if (curve->beta[m-1] == 0.5) { |
275 |
ship("i\n");
|
276 |
} else {
|
277 |
ship("%ld I\n", bq[m-1]); |
278 |
} |
279 |
for (i=0; i<m; i++) { |
280 |
if (i<m-1) { |
281 |
ship("%ld %ld ", v[i+1].x - v[i].x, v[i+1].y - v[i].y); |
282 |
if (curve->beta[i] != 0.5) { |
283 |
ship("%ld ", bq[i]);
|
284 |
} |
285 |
} |
286 |
if (curve->tag[i] == POTRACE_CURVETO) {
|
287 |
ship(curve->beta[i] == 0.5 ? "%ld c\n" : "%ld C\n", aq[i]); |
288 |
} else {
|
289 |
ship(curve->beta[i] == 0.5 ? "v\n" : "V\n"); |
290 |
} |
291 |
} |
292 |
|
293 |
free(bq); |
294 |
free(aq); |
295 |
free(v); |
296 |
free(q); |
297 |
return 0; |
298 |
|
299 |
malloc_error:
|
300 |
free(bq); |
301 |
free(aq); |
302 |
free(v); |
303 |
free(q); |
304 |
return 1; |
305 |
} |
306 |
|
307 |
static int eps_path(privcurve_t *curve) { |
308 |
if (info.longcoding==0 && curve->alphacurve) { |
309 |
return eps_path_short(curve);
|
310 |
} else {
|
311 |
return eps_path_long(curve);
|
312 |
} |
313 |
} |
314 |
|
315 |
/* ---------------------------------------------------------------------- */
|
316 |
/* functions for rendering various internal data structures, used to
|
317 |
generate debugging output */
|
318 |
|
319 |
/* output jaggie curve in grey */
|
320 |
static void eps_jaggy(potrace_path_t *plist) { |
321 |
potrace_path_t *p; |
322 |
int i;
|
323 |
|
324 |
ship(".9 setgray\n");
|
325 |
list_forall (p, plist) { |
326 |
point_t *pt = p->priv->pt; |
327 |
point_t cur, prev; |
328 |
|
329 |
if (p->sign == '+') { |
330 |
cur = prev = pt[p->priv->len-1];
|
331 |
eps_moveto(dpoint(cur)); |
332 |
for (i=0; i<p->priv->len; i++) { |
333 |
if (pt[i].x != cur.x && pt[i].y != cur.y) {
|
334 |
cur = prev; |
335 |
eps_lineto(dpoint(cur)); |
336 |
} |
337 |
prev = pt[i]; |
338 |
} |
339 |
eps_lineto(dpoint(pt[p->priv->len-1]));
|
340 |
} else {
|
341 |
cur = prev = pt[0];
|
342 |
eps_moveto(dpoint(cur)); |
343 |
for (i=p->priv->len-1; i>=0; i--) { |
344 |
if (pt[i].x != cur.x && pt[i].y != cur.y) {
|
345 |
cur = prev; |
346 |
eps_lineto(dpoint(cur)); |
347 |
} |
348 |
prev = pt[i]; |
349 |
} |
350 |
eps_lineto(dpoint(pt[0]));
|
351 |
} |
352 |
if (p->next == NULL || p->next->sign == '+') { |
353 |
ship("fill\n");
|
354 |
} |
355 |
} |
356 |
} |
357 |
|
358 |
/* output polygon */
|
359 |
static void eps_polygon(privcurve_t *curve, const color_t col) { |
360 |
int i;
|
361 |
int m = curve->n;
|
362 |
|
363 |
eps_linewidth(.02);
|
364 |
eps_setcolor(col); |
365 |
eps_moveto(curve->vertex[m-1]);
|
366 |
for (i=0; i<m; i++) { |
367 |
eps_lineto(curve->vertex[i]); |
368 |
} |
369 |
ship("stroke\n");
|
370 |
} |
371 |
|
372 |
/* output lines L and parameter alpha */
|
373 |
static void eps_L(privcurve_t *curve, const color_t col) { |
374 |
int i, i1;
|
375 |
double gamma;
|
376 |
dpoint_t p1, p4, p1l, p4l; |
377 |
int m = curve->n;
|
378 |
|
379 |
for (i=0; i<m; i++) { |
380 |
i1 = mod(i+1, m);
|
381 |
gamma = curve->alpha0[i1] * 0.75; |
382 |
|
383 |
p1 = curve->c[i][2];
|
384 |
p4 = curve->c[i1][2];
|
385 |
p1l = interval(gamma, p1, curve->vertex[i1]); |
386 |
p4l = interval(gamma, p4, curve->vertex[i1]); |
387 |
eps_linewidth(.02);
|
388 |
eps_setcolor(col); |
389 |
eps_moveto(p1l); |
390 |
eps_lineto(p4l); |
391 |
ship("stroke\n");
|
392 |
eps_moveto_offs(curve->vertex[i1], -.4, -.4); |
393 |
ship("times (%.2f) show\n", curve->alpha0[i1]);
|
394 |
} |
395 |
} |
396 |
|
397 |
/* ---------------------------------------------------------------------- */
|
398 |
/* postscript macros */
|
399 |
|
400 |
/* special macros for size-optimized rendering of Bezier curves */
|
401 |
static char *optimacros = |
402 |
"/D{bind def}def\n"
|
403 |
"/R{roll}D\n"
|
404 |
"/K{copy}D\n"
|
405 |
"/P{pop}D\n"
|
406 |
"/p{3 2 R add 3 1 R add exch}D\n"
|
407 |
"/t{dup 4 3 R mul 3 1 R mul}D\n"
|
408 |
"/a{dup 1 sub neg 4 1 R t 5 2 R t p}D\n"
|
409 |
"/m{2 K le{exch}if P}D\n"
|
410 |
"/n{abs exch abs m}D\n"
|
411 |
"/d{-1 t p n}D\n"
|
412 |
"/s{[4 2 R] cvx def}D\n"
|
413 |
"/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"
|
414 |
"/e{4 2 R lineto lineto P P}D\n"
|
415 |
"/q{3 K P n 10 m div}D\n"
|
416 |
"/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"
|
417 |
"/C{4 1 R q f 7 6 R g}D\n"
|
418 |
"/V{q f e}D\n"
|
419 |
"/c{3 1 R .5 f 7 6 R g}D\n"
|
420 |
"/v{.5 f e}D\n"
|
421 |
"/j{5 K P p /y s 3 K t 7 5 R p /x s x moveto P}D\n"
|
422 |
"/i{.5 j}D\n"
|
423 |
"/I{dup 6 1 R q j 3 2 R}D\n"
|
424 |
"/z{closepath}D\n"
|
425 |
"/b{%s z fill}D\n"
|
426 |
"/w{%s z fill}D\n";
|
427 |
|
428 |
/* special macros for debug output */
|
429 |
static char *debugmacros = |
430 |
"/unit { %f } def\n"
|
431 |
"/box { newpath 0 0 moveto 0 1 lineto 1 1 lineto 1 0 lineto closepath } def\n"
|
432 |
"/circ { newpath 0 0 1 0 360 arc closepath } def\n"
|
433 |
"/dot { gsave .15 mul dup scale circ fill grestore } def\n"
|
434 |
"/sq { gsave unit unit scale -.5 -.5 translate box .02 setlinewidth stroke grestore } def\n"
|
435 |
"/sq1 { gsave translate sq unit .6 mul dot grestore } def\n"
|
436 |
"/dot2 { gsave translate unit dot grestore } def\n"
|
437 |
"/usq { gsave unit unit scale -.5 -.5 rmoveto 0 1 rlineto 1 0 rlineto 0 -1 rlineto closepath .02 setlinewidth stroke grestore } def\n"
|
438 |
"/dot1 { gsave translate unit .3 mul dup scale circ fill grestore } def\n"
|
439 |
"/times { /Times-Roman findfont unit .3 mul scalefont setfont } def\n"
|
440 |
"/times1 { /Times-Roman findfont unit 10 mul scalefont setfont 0 0 0 setrgbcolor } def\n"
|
441 |
"/times2 { /Times-Roman findfont unit 2 mul scalefont setfont 0 0 0 setrgbcolor } def\n";
|
442 |
|
443 |
/* ---------------------------------------------------------------------- */
|
444 |
/* Backends for various types of output. */
|
445 |
|
446 |
/* Normal output: black on transparent */
|
447 |
static int render0(potrace_path_t *plist) { |
448 |
potrace_path_t *p; |
449 |
|
450 |
if (info.longcoding) {
|
451 |
eps_setcolor(info.color); |
452 |
list_forall (p, plist) { |
453 |
eps_path(p->priv->fcurve); |
454 |
ship("closepath\n");
|
455 |
if (p->next == NULL || p->next->sign == '+') { |
456 |
ship("fill\n");
|
457 |
} |
458 |
} |
459 |
} else {
|
460 |
list_forall (p, plist) { |
461 |
eps_path(p->priv->fcurve); |
462 |
if (p->next == NULL || p->next->sign == '+') { |
463 |
ship("b\n");
|
464 |
} else {
|
465 |
ship("z\n");
|
466 |
} |
467 |
} |
468 |
} |
469 |
return 0; |
470 |
} |
471 |
|
472 |
/* Opaque output: alternating black and white */
|
473 |
static int render0_opaque(potrace_path_t *plist) { |
474 |
potrace_path_t *p; |
475 |
|
476 |
if (info.longcoding) {
|
477 |
list_forall (p, plist) { |
478 |
eps_path(p->priv->fcurve); |
479 |
ship("closepath\n");
|
480 |
eps_setcolor(p->sign=='+' ? info.color : info.fillcolor);
|
481 |
ship("fill\n");
|
482 |
} |
483 |
} else {
|
484 |
list_forall (p, plist) { |
485 |
eps_path(p->priv->fcurve); |
486 |
ship(p->sign=='+' ? "b\n" : "w\n"); |
487 |
} |
488 |
} |
489 |
return 0; |
490 |
} |
491 |
|
492 |
/* Debug output type 1 (show optimal polygon) */
|
493 |
static int render1(potrace_path_t *plist) { |
494 |
potrace_path_t *p; |
495 |
int i;
|
496 |
|
497 |
eps_jaggy(plist); |
498 |
|
499 |
list_forall (p, plist) { |
500 |
|
501 |
point_t *pt = p->priv->pt; |
502 |
int n = p->priv->len;
|
503 |
int m = p->priv->m;
|
504 |
int *po = p->priv->po;
|
505 |
|
506 |
eps_linewidth(.02);
|
507 |
eps_setcolor(black); |
508 |
/* output jaggie curve in boxed style */
|
509 |
for (i=1; i<n; i++) { |
510 |
eps_moveto(dpoint(pt[i-1]));
|
511 |
eps_lineto(dpoint(pt[i])); |
512 |
ship("stroke\n");
|
513 |
eps_coords(dpoint(pt[i])); |
514 |
ship("sq1\n");
|
515 |
} |
516 |
eps_moveto(dpoint(pt[n-1]));
|
517 |
eps_lineto(dpoint(pt[0]));
|
518 |
ship("stroke\n");
|
519 |
eps_coords(dpoint(pt[0]));
|
520 |
ship("sq1\n");
|
521 |
|
522 |
/* output the uncorrected polygon */
|
523 |
eps_linewidth(.1);
|
524 |
eps_setcolor(blue); |
525 |
eps_moveto(dpoint(pt[po[0]]));
|
526 |
for (i=1; i<m; i++) { |
527 |
eps_lineto(dpoint(pt[po[i]])); |
528 |
} |
529 |
eps_lineto(dpoint(pt[po[0]]));
|
530 |
ship("stroke\n");
|
531 |
for (i=0; i<m; i++) { |
532 |
eps_coords(dpoint(pt[po[i]])); |
533 |
ship("dot2\n");
|
534 |
} |
535 |
} |
536 |
return 0; |
537 |
} |
538 |
|
539 |
/* Debug output type 2 (show corrected polygon and edge detection) */
|
540 |
static int render2(potrace_path_t *plist) { |
541 |
potrace_path_t *p; |
542 |
int i;
|
543 |
|
544 |
/* output original bitmap in grey */
|
545 |
eps_jaggy(plist); |
546 |
|
547 |
list_forall (p, plist) { |
548 |
/* output polygon with corrected edges, lines L, and parameter alpha */
|
549 |
eps_polygon(&p->priv->curve, black); |
550 |
eps_L(&p->priv->curve, black); |
551 |
|
552 |
/* output the vertex unit squares */
|
553 |
for (i=0; i<p->priv->curve.n; i++) { |
554 |
eps_moveto(p->priv->curve.vertex[i]); |
555 |
ship("usq\n");
|
556 |
} |
557 |
|
558 |
/* output the path */
|
559 |
eps_linewidth(.1);
|
560 |
eps_setcolor(blue); |
561 |
eps_path(&p->priv->curve); |
562 |
ship("closepath\n");
|
563 |
ship("stroke\n");
|
564 |
|
565 |
if (info.param->opticurve && info.debug == 3) { |
566 |
|
567 |
/* output opticurve */
|
568 |
eps_linewidth(.05);
|
569 |
eps_setcolor(red); |
570 |
eps_path(&p->priv->ocurve); |
571 |
ship("closepath\n");
|
572 |
ship("stroke\n");
|
573 |
|
574 |
/* output dots */
|
575 |
for (i=0; i<p->priv->ocurve.n; i++) { |
576 |
eps_coords(p->priv->ocurve.c[i][2]);
|
577 |
ship("dot1\n");
|
578 |
} |
579 |
} |
580 |
} |
581 |
return 0; |
582 |
} |
583 |
|
584 |
/* Free-style debug output */
|
585 |
static int render_debug(potrace_path_t *plist) { |
586 |
potrace_path_t *p; |
587 |
int count;
|
588 |
int i;
|
589 |
|
590 |
/* output original bitmap in grey */
|
591 |
eps_jaggy(plist); |
592 |
|
593 |
count = -1;
|
594 |
list_forall (p, plist) { |
595 |
count++; |
596 |
|
597 |
/* output path numbers */
|
598 |
eps_moveto_offs(p->priv->curve.vertex[0], 0, 5); |
599 |
ship("times1 (%d) show\n", count);
|
600 |
|
601 |
/* output polygon with corrected edges, lines L, and parameter alpha */
|
602 |
eps_polygon(&p->priv->curve, black); |
603 |
eps_L(&p->priv->curve, black); |
604 |
|
605 |
/* output the vertex unit squares */
|
606 |
for (i=0; i<p->priv->curve.n; i++) { |
607 |
eps_moveto(p->priv->curve.vertex[i]); |
608 |
ship("usq\n");
|
609 |
} |
610 |
|
611 |
/* output the vertex numbers */
|
612 |
for (i=0; i<p->priv->curve.n; i++) { |
613 |
eps_moveto_offs(p->priv->curve.vertex[i], +1, +1); |
614 |
ship("times2 (%d) show\n", i);
|
615 |
} |
616 |
|
617 |
/* output the path */
|
618 |
eps_linewidth(.1);
|
619 |
eps_setcolor(blue); |
620 |
eps_path(&p->priv->curve); |
621 |
ship("closepath\n");
|
622 |
ship("stroke\n");
|
623 |
|
624 |
if (info.param->opticurve) {
|
625 |
|
626 |
/* output the opti-verteces polygon */
|
627 |
eps_polygon(&p->priv->ocurve, green); |
628 |
|
629 |
/* output opticurve */
|
630 |
eps_linewidth(.05);
|
631 |
eps_setcolor(red); |
632 |
eps_path(&p->priv->ocurve); |
633 |
ship("closepath\n");
|
634 |
ship("stroke\n");
|
635 |
|
636 |
/* output dots */
|
637 |
for (i=0; i<p->priv->ocurve.n; i++) { |
638 |
eps_coords(p->priv->ocurve.c[i][2]);
|
639 |
ship("dot1\n");
|
640 |
} |
641 |
|
642 |
/* output beta parameters */
|
643 |
for (i=0; i<p->priv->ocurve.n; i++) { |
644 |
eps_moveto_offs(p->priv->ocurve.c[i][2], +.4, -.4); |
645 |
ship("times (%.2f) show\n", p->priv->ocurve.beta[i]);
|
646 |
} |
647 |
} |
648 |
} |
649 |
return 0; |
650 |
} |
651 |
|
652 |
/* select the appropriate rendering function from above */
|
653 |
static int eps_render(potrace_path_t *plist) { |
654 |
int r;
|
655 |
|
656 |
switch (info.debug) {
|
657 |
case 0: |
658 |
if (info.opaque) {
|
659 |
r = render0_opaque(plist); |
660 |
} else {
|
661 |
r = render0(plist); |
662 |
} |
663 |
break;
|
664 |
case 1: |
665 |
r = render1(plist); |
666 |
break;
|
667 |
case 2: case 3: |
668 |
r = render2(plist); |
669 |
break;
|
670 |
default:
|
671 |
r = render_debug(plist); |
672 |
break;
|
673 |
} |
674 |
return r;
|
675 |
} |
676 |
|
677 |
/* ---------------------------------------------------------------------- */
|
678 |
/* EPS header and footer */
|
679 |
|
680 |
static int eps_init(imginfo_t *imginfo) { |
681 |
double origx = imginfo->trans.orig[0] + imginfo->lmar; |
682 |
double origy = imginfo->trans.orig[1] + imginfo->bmar; |
683 |
double scalex = imginfo->width / imginfo->pixwidth / info.unit;
|
684 |
double scaley = imginfo->height / imginfo->pixheight / info.unit;
|
685 |
char *c0, *c1;
|
686 |
|
687 |
shipcom("%%!PS-Adobe-3.0 EPSF-3.0\n");
|
688 |
shipcom("%%%%Creator: \"POTRACE\" \"VERSION\", written by Peter Selinger 2001-2007\n");
|
689 |
shipcom("%%%%LanguageLevel: %d\n", info.pslevel);
|
690 |
shipcom("%%%%BoundingBox: 0 0 %d %d\n",
|
691 |
(int)ceil(imginfo->trans.bb[0]+imginfo->lmar+imginfo->rmar), |
692 |
(int)ceil(imginfo->trans.bb[1]+imginfo->tmar+imginfo->bmar)); |
693 |
shipcom("%%%%Pages: 1\n");
|
694 |
shipcom("%%%%EndComments\n");
|
695 |
|
696 |
shipcom("%%%%Page: 1 1\n");
|
697 |
if (!info.longcoding) {
|
698 |
c0 = strdup(eps_colorstring(info.color)); |
699 |
c1 = strdup(eps_colorstring(info.fillcolor)); |
700 |
ship(optimacros, c0, c1); |
701 |
free(c0); |
702 |
free(c1); |
703 |
} |
704 |
if (info.debug) {
|
705 |
ship(debugmacros, info.unit); |
706 |
} |
707 |
ship("gsave\n");
|
708 |
if (origx != 0 || origy != 0) { |
709 |
ship("%.0f %.0f translate\n", origx, origy);
|
710 |
} |
711 |
if (info.angle != 0) { |
712 |
ship("%.2f rotate\n", info.angle);
|
713 |
} |
714 |
ship("%f %f scale\n", scalex, scaley);
|
715 |
|
716 |
return 0; |
717 |
} |
718 |
|
719 |
static int eps_term(void) { |
720 |
ship("grestore\n");
|
721 |
shipcom("%%%%EOF\n");
|
722 |
return 0; |
723 |
} |
724 |
|
725 |
/* public interface for EPS */
|
726 |
int page_eps(FILE *fout, potrace_path_t *plist, imginfo_t *imginfo) {
|
727 |
int r;
|
728 |
|
729 |
eps_callbacks(fout); |
730 |
|
731 |
eps_init(imginfo); |
732 |
|
733 |
r = eps_render(plist); |
734 |
if (r) {
|
735 |
return r;
|
736 |
} |
737 |
|
738 |
eps_term(); |
739 |
|
740 |
return 0; |
741 |
} |
742 |
|
743 |
/* ---------------------------------------------------------------------- */
|
744 |
/* PostScript header and footer */
|
745 |
|
746 |
static int eps_pagenumber; |
747 |
|
748 |
int init_ps(FILE *fout) {
|
749 |
char *c0, *c1;
|
750 |
|
751 |
/* set callback functions for shipping routines */
|
752 |
eps_callbacks(fout); |
753 |
|
754 |
shipcom("%%!PS-Adobe-3.0\n");
|
755 |
shipcom("%%%%Creator: \"POTRACE\" \"VERSION\", written by Peter Selinger 2001-2007\n");
|
756 |
shipcom("%%%%LanguageLevel: %d\n", info.pslevel);
|
757 |
shipcom("%%%%BoundingBox: 0 0 %d %d\n", info.paperwidth, info.paperheight);
|
758 |
shipcom("%%%%Pages: (atend)\n");
|
759 |
shipcom("%%%%EndComments\n");
|
760 |
if (!info.longcoding || info.debug) {
|
761 |
shipcom("%%%%BeginSetup\n");
|
762 |
if (!info.longcoding) {
|
763 |
c0 = strdup(eps_colorstring(info.color)); |
764 |
c1 = strdup(eps_colorstring(info.fillcolor)); |
765 |
ship(optimacros, c0, c1); |
766 |
free(c0); |
767 |
free(c1); |
768 |
} |
769 |
if (info.debug) {
|
770 |
ship(debugmacros, info.unit); |
771 |
} |
772 |
shipcom("%%%%EndSetup\n");
|
773 |
} |
774 |
eps_pagenumber = 0;
|
775 |
fflush(fout); |
776 |
return 0; |
777 |
} |
778 |
|
779 |
int term_ps(FILE *fout) {
|
780 |
eps_callbacks(fout); |
781 |
|
782 |
shipcom("%%%%Trailer\n");
|
783 |
shipcom("%%%%Pages: %d\n", eps_pagenumber);
|
784 |
shipcom("%%%%EOF\n");
|
785 |
fflush(fout); |
786 |
|
787 |
return 0; |
788 |
} |
789 |
|
790 |
static void eps_pageinit_ps(imginfo_t *imginfo) { |
791 |
double origx = imginfo->trans.orig[0] + imginfo->lmar; |
792 |
double origy = imginfo->trans.orig[1] + imginfo->bmar; |
793 |
double scalex = imginfo->width / imginfo->pixwidth / info.unit;
|
794 |
double scaley = imginfo->height / imginfo->pixheight / info.unit;
|
795 |
|
796 |
eps_pagenumber++; |
797 |
eps_color = -1;
|
798 |
eps_width = -1;
|
799 |
|
800 |
shipcom("%%%%Page: %d %d\n", eps_pagenumber, eps_pagenumber);
|
801 |
ship("gsave\n");
|
802 |
if (origx != 0 || origy != 0) { |
803 |
ship("%.0f %.0f translate\n", origx, origy);
|
804 |
} |
805 |
if (info.angle != 0) { |
806 |
ship("%.2f rotate\n", info.angle);
|
807 |
} |
808 |
ship("%f %f scale\n", scalex, scaley);
|
809 |
} |
810 |
|
811 |
static void eps_pageterm_ps(void) { |
812 |
ship("grestore\n");
|
813 |
ship("showpage\n");
|
814 |
} |
815 |
|
816 |
int page_ps(FILE *fout, potrace_path_t *plist, imginfo_t *imginfo) {
|
817 |
int r;
|
818 |
|
819 |
eps_callbacks(fout); |
820 |
|
821 |
eps_pageinit_ps(imginfo); |
822 |
|
823 |
r = eps_render(plist); |
824 |
if (r) {
|
825 |
return r;
|
826 |
} |
827 |
|
828 |
eps_pageterm_ps(); |
829 |
|
830 |
shipcom("");
|
831 |
|
832 |
fflush(fout); |
833 |
|
834 |
return 0; |
835 |
} |