svn-gvsig-desktop / branches / gvSIG_19_ext3D_osgVP_2_2_0 / libraries / libjni-potrace / src / main / native / jpotrace / potrace_raster.c @ 31855
History | View | Annotate | Download (26.7 KB)
1 |
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
|
---|---|
2 |
*
|
3 |
* Copyright (C) 2005 IVER T.I. and Generalitat Valenciana.
|
4 |
*
|
5 |
* This program is free software; you can redistribute it and/or
|
6 |
* modify it under the terms of the GNU General Public License
|
7 |
* as published by the Free Software Foundation; either version 2
|
8 |
* of the License, or (at your option) any later version.
|
9 |
*
|
10 |
* This program is distributed in the hope that it will be useful,
|
11 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13 |
* GNU General Public License for more details.
|
14 |
*
|
15 |
* You should have received a copy of the GNU General Public License
|
16 |
* along with this program; if not, write to the Free Software
|
17 |
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,USA.
|
18 |
*/
|
19 |
#include <stdio.h> |
20 |
#include <errno.h> |
21 |
#include <math.h> |
22 |
#include "getopt.h" |
23 |
|
24 |
#include "main.h" |
25 |
#include "platform.h" |
26 |
|
27 |
#include "backend_pdf.h" |
28 |
#include "backend_eps.h" |
29 |
#include "backend_pgm.h" |
30 |
#include "backend_svg.h" |
31 |
#include "backend_gimp.h" |
32 |
#include "backend_xfig.h" |
33 |
#include "bitmap_io.h" |
34 |
#include "auxiliary.h" |
35 |
|
36 |
#ifndef M_PI
|
37 |
#define M_PI 3.14159265358979323846 |
38 |
#endif
|
39 |
|
40 |
#if defined(_MSC_VER)
|
41 |
/* replacement of Unix rint() for Windows */
|
42 |
static int rint (double x) |
43 |
{ |
44 |
char *buf;
|
45 |
int i,dec,sig;
|
46 |
|
47 |
buf = _fcvt(x, 0, &dec, &sig);
|
48 |
i = atoi(buf); |
49 |
if(sig == 1) { |
50 |
i = i * -1;
|
51 |
} |
52 |
return(i);
|
53 |
} |
54 |
#define strcasecmp stricmp
|
55 |
#define strncasecmp strnicmp
|
56 |
#endif
|
57 |
|
58 |
#define UNDEF ((double)(1e30)) /* a value to represent "undefined" */ |
59 |
#define INFTY ((double)(1e30)) /* a value to represent +infinity */ |
60 |
|
61 |
/* backends and their characteristics */
|
62 |
struct backend_s {
|
63 |
char *name; /* name of this backend */ |
64 |
char *ext; /* file extension */ |
65 |
int fixed; /* fixed page size backend? */ |
66 |
int pixel; /* pixel-based backend? */ |
67 |
int multi; /* multi-page backend? */ |
68 |
int (*init_f)(FILE *fout); /* initialization function */ |
69 |
int (*page_f)(FILE *fout, potrace_path_t *plist, imginfo_t *imginfo);
|
70 |
/* per-bitmap function */
|
71 |
int (*term_f)(FILE *fout); /* finalization function */ |
72 |
int opticurve; /* opticurve capable (true Bezier curves?) */ |
73 |
}; |
74 |
typedef struct backend_s backend_t; |
75 |
|
76 |
static backend_t backend[] = { {"eps", ".eps", 0, 0, 0, NULL, page_eps, NULL, 1}, {"postscript", ".ps", 1, 0, 1, |
77 |
init_ps, page_ps, term_ps, 1}, {"ps", ".ps", 1, 0, 1, init_ps, page_ps, term_ps, 1}, {"pdf", ".pdf", 0, 0, 1, |
78 |
init_pdf, page_pdf, term_pdf, 1}, {"svg", ".svg", 0, 0, 0, NULL, page_svg, NULL, 1}, {"pgm", ".pgm", 0, 1, 1, NULL, |
79 |
page_pgm, NULL, 1}, {"gimppath", ".gimppath", 0, 1, 0, NULL, page_gimp, NULL, 1}, {"xfig", ".fig", 1, 0, 0, NULL, |
80 |
page_xfig, NULL, 0}, {NULL, NULL, 0, 0, 0, NULL, NULL, NULL}, }; |
81 |
|
82 |
struct info_s info;
|
83 |
|
84 |
#define COL0 "\033[G" /* reset cursor to column 0 */ |
85 |
|
86 |
/* ---------------------------------------------------------------------- */
|
87 |
/* callback function for progress bar */
|
88 |
|
89 |
struct simple_progress_s {
|
90 |
char name[22]; /* filename for status bar */ |
91 |
double dnext; /* threshold value for next tick */ |
92 |
}; |
93 |
typedef struct simple_progress_s simple_progress_t; |
94 |
|
95 |
static inline double double_of_dim(dim_t d, double def) { |
96 |
if (d.d) {
|
97 |
return d.x * d.d;
|
98 |
} else {
|
99 |
return d.x * def;
|
100 |
} |
101 |
} |
102 |
|
103 |
/* ---------------------------------------------------------------------- */
|
104 |
/* calculations with bitmap dimensions, positioning etc */
|
105 |
|
106 |
/* consider a rectangle spanned by the vectors (w,0) and (0,h). Rotate
|
107 |
it counterclockwise by angle alpha. Then set the rect_t structure
|
108 |
to the resulting rectangle, setting its bounding box, origin,
|
109 |
x-basis and y-basis. */
|
110 |
|
111 |
static void rotate_dim(double alpha, double w, double h, rect_t *r) { |
112 |
double s, c, x0, x1, y0, y1;
|
113 |
|
114 |
s = sin(alpha / 180 * M_PI);
|
115 |
c = cos(alpha / 180 * M_PI);
|
116 |
|
117 |
/* apply the transformation matrix to the basis vectors */
|
118 |
x0 = c * w; |
119 |
x1 = s * w; |
120 |
y0 = -s * h; |
121 |
y1 = c * h; |
122 |
|
123 |
/* determine bounding box and origin relative to bounding box */
|
124 |
r->bb[0] = fabs(x0) + fabs(y0);
|
125 |
r->bb[1] = fabs(x1) + fabs(y1);
|
126 |
r->orig[0] = -min(x0, 0) - min(y0, 0); |
127 |
r->orig[1] = -min(x1, 0) - min(y1, 0); |
128 |
} |
129 |
|
130 |
/* determine the dimensions of the output based on command line and
|
131 |
image dimensions */
|
132 |
static void calc_dimensions(imginfo_t *imginfo) { |
133 |
double dim_def;
|
134 |
double maxwidth, maxheight, sc;
|
135 |
rect_t r; |
136 |
|
137 |
/* we take care of a special case: if one of the image dimensions is
|
138 |
0, we change it to 1. Such an image is empty anyway, so there
|
139 |
will be 0 paths in it. Changing the dimensions avoids division by
|
140 |
0 error in calculating scaling factors, bounding boxes and
|
141 |
such. This doesn't quite do the right thing in all cases, but it
|
142 |
is better than causing overflow errors or "nan" output in
|
143 |
backends. Human users don't tend to process images of size 0
|
144 |
anyway; they might occur in some pipelines. */
|
145 |
if (imginfo->pixwidth == 0) { |
146 |
imginfo->pixwidth = 1;
|
147 |
} |
148 |
if (imginfo->pixheight == 0) { |
149 |
imginfo->pixheight = 1;
|
150 |
} |
151 |
|
152 |
/* set the default dimension for width, height, margins */
|
153 |
if (info.backend->pixel) {
|
154 |
dim_def = DIM_PT; |
155 |
} else {
|
156 |
dim_def = DEFAULT_DIM; |
157 |
} |
158 |
|
159 |
/* apply default dimension to width, height, margins */
|
160 |
imginfo->width = info.width_d.x == UNDEF ? UNDEF : double_of_dim(info.width_d, dim_def); |
161 |
imginfo->height = info.height_d.x == UNDEF ? UNDEF : double_of_dim(info.height_d, dim_def); |
162 |
imginfo->lmar = info.lmar_d.x == UNDEF ? UNDEF : double_of_dim(info.lmar_d, dim_def); |
163 |
imginfo->rmar = info.rmar_d.x == UNDEF ? UNDEF : double_of_dim(info.rmar_d, dim_def); |
164 |
imginfo->tmar = info.tmar_d.x == UNDEF ? UNDEF : double_of_dim(info.tmar_d, dim_def); |
165 |
imginfo->bmar = info.bmar_d.x == UNDEF ? UNDEF : double_of_dim(info.bmar_d, dim_def); |
166 |
|
167 |
/* determine width and height from desired resolution / scaling
|
168 |
factor, if given */
|
169 |
if (info.backend->pixel) {
|
170 |
if (imginfo->width == UNDEF && info.sx != UNDEF) {
|
171 |
imginfo->width = imginfo->pixwidth * info.sx; |
172 |
} |
173 |
if (imginfo->height == UNDEF && info.sy != UNDEF) {
|
174 |
imginfo->height = imginfo->pixheight * info.sy; |
175 |
} |
176 |
} else {
|
177 |
if (imginfo->width == UNDEF && info.rx != UNDEF) {
|
178 |
imginfo->width = imginfo->pixwidth / info.rx * 72;
|
179 |
} |
180 |
if (imginfo->height == UNDEF && info.ry != UNDEF) {
|
181 |
imginfo->height = imginfo->pixheight / info.ry * 72;
|
182 |
} |
183 |
} |
184 |
|
185 |
/* if one of width/height is specified, determine the other */
|
186 |
if (imginfo->width == UNDEF && imginfo->height != UNDEF) {
|
187 |
imginfo->width = imginfo->height / imginfo->pixheight * imginfo->pixwidth / info.stretch; |
188 |
} else
|
189 |
if (imginfo->width != UNDEF && imginfo->height == UNDEF) {
|
190 |
imginfo->height = imginfo->width / imginfo->pixwidth * imginfo->pixheight * info.stretch; |
191 |
} |
192 |
|
193 |
/* if width and height are still variable, figure them out */
|
194 |
if (imginfo->width == UNDEF && imginfo->height == UNDEF) {
|
195 |
|
196 |
if (info.backend->fixed) {
|
197 |
|
198 |
/* in fixed-size backends, try to squeeze it between margins */
|
199 |
maxwidth = UNDEF; |
200 |
maxheight = UNDEF; |
201 |
|
202 |
if (imginfo->lmar != UNDEF && imginfo->rmar != UNDEF) {
|
203 |
maxwidth = info.paperwidth - imginfo->lmar - imginfo->rmar; |
204 |
} |
205 |
if (imginfo->bmar != UNDEF && imginfo->tmar != UNDEF) {
|
206 |
maxheight = info.paperheight - imginfo->bmar - imginfo->tmar; |
207 |
} |
208 |
if (maxwidth == UNDEF && maxheight == UNDEF) {
|
209 |
maxwidth = max(info.paperwidth - 144, info.paperwidth * 0.75); |
210 |
maxheight = max(info.paperheight - 144, info.paperheight * 0.75); |
211 |
} |
212 |
|
213 |
rotate_dim(info.angle, imginfo->pixwidth, imginfo->pixheight * info.stretch, &r); |
214 |
|
215 |
sc = min(maxwidth == UNDEF ? INFTY : maxwidth / r.bb[0], maxheight == UNDEF ? INFTY : maxheight / r.bb[1]); |
216 |
imginfo->width = imginfo->pixwidth * sc; |
217 |
imginfo->height = imginfo->pixheight * info.stretch * sc; |
218 |
|
219 |
} else
|
220 |
if (info.backend->pixel) {
|
221 |
|
222 |
/* in pixel-based backends, assume default scaling factor of 1 */
|
223 |
|
224 |
imginfo->width = imginfo->pixwidth; |
225 |
imginfo->height = imginfo->pixheight * info.stretch; |
226 |
} else {
|
227 |
|
228 |
/* otherwise, choose a default size based on the default paper format */
|
229 |
|
230 |
maxwidth = max(info.paperwidth - 144, info.paperwidth * 0.75); |
231 |
maxheight = max(info.paperheight - 144, info.paperheight * 0.75); |
232 |
|
233 |
sc = min(maxwidth / imginfo->pixwidth, maxheight / imginfo->pixheight / info.stretch); |
234 |
imginfo->width = imginfo->pixwidth * sc; |
235 |
imginfo->height = imginfo->pixheight * info.stretch * sc; |
236 |
} |
237 |
} |
238 |
|
239 |
/* calculate coordinate system */
|
240 |
rotate_dim(info.angle, imginfo->width, imginfo->height, &imginfo->trans); |
241 |
|
242 |
/* adjust margins */
|
243 |
if (info.backend->fixed) {
|
244 |
if (imginfo->lmar == UNDEF && imginfo->rmar == UNDEF) {
|
245 |
imginfo->lmar = (info.paperwidth - imginfo->trans.bb[0]) / 2; |
246 |
} else
|
247 |
if (imginfo->lmar == UNDEF) {
|
248 |
imginfo->lmar = (info.paperwidth - imginfo->trans.bb[0] - imginfo->rmar);
|
249 |
} else
|
250 |
if (imginfo->lmar != UNDEF && imginfo->rmar != UNDEF) {
|
251 |
imginfo->lmar += (info.paperwidth - imginfo->trans.bb[0] - imginfo->lmar - imginfo->rmar) / 2; |
252 |
} |
253 |
if (imginfo->bmar == UNDEF && imginfo->tmar == UNDEF) {
|
254 |
imginfo->bmar = (info.paperheight - imginfo->trans.bb[1]) / 2; |
255 |
} else
|
256 |
if (imginfo->bmar == UNDEF) {
|
257 |
imginfo->bmar = (info.paperheight - imginfo->trans.bb[1] - imginfo->tmar);
|
258 |
} else
|
259 |
if (imginfo->bmar != UNDEF && imginfo->tmar != UNDEF) {
|
260 |
imginfo->bmar += (info.paperheight - imginfo->trans.bb[1] - imginfo->bmar - imginfo->tmar) / 2; |
261 |
} |
262 |
} else {
|
263 |
if (imginfo->lmar == UNDEF) {
|
264 |
imginfo->lmar = 0;
|
265 |
} |
266 |
if (imginfo->rmar == UNDEF) {
|
267 |
imginfo->rmar = 0;
|
268 |
} |
269 |
if (imginfo->bmar == UNDEF) {
|
270 |
imginfo->bmar = 0;
|
271 |
} |
272 |
if (imginfo->tmar == UNDEF) {
|
273 |
imginfo->tmar = 0;
|
274 |
} |
275 |
} |
276 |
} |
277 |
|
278 |
static FILE *my_fopen_read(const char *filename) { |
279 |
if (filename == NULL || strcmp(filename, "-") == 0) { |
280 |
return stdin;
|
281 |
} |
282 |
return fopen(filename, "rb"); |
283 |
} |
284 |
|
285 |
static FILE *my_fopen_write(const char *filename) { |
286 |
if (filename == NULL || strcmp(filename, "-") == 0) { |
287 |
return stdout;
|
288 |
} |
289 |
return fopen(filename, "wb"); |
290 |
} |
291 |
|
292 |
/* close a file, but do nothing is filename is NULL or "-" */
|
293 |
static void my_fclose(FILE *f, const char *filename) { |
294 |
if (filename == NULL || strcmp(filename, "-") == 0) { |
295 |
return;
|
296 |
} |
297 |
fclose(f); |
298 |
} |
299 |
|
300 |
/* print a simple progress bar. This is a callback function that is
|
301 |
potentially called often; thus, it has been optimized for the
|
302 |
typical case, which is when the progress bar does not need updating. */
|
303 |
static void simple_progress(double d, void *data) { |
304 |
simple_progress_t *p = (simple_progress_t *) data; |
305 |
static char b[] = "========================================"; |
306 |
int tick; /* number of visible tickmarks, 0..40 */ |
307 |
int perc; /* visible percentage, 0..100 */ |
308 |
|
309 |
/* note: the 0.01 and 0.025 ensure that we always end on 40
|
310 |
tickmarks and 100%, despite any rounding errors. The 0.995
|
311 |
ensures that tick always increases when d >= p->dnext. */
|
312 |
if (d >= p->dnext) {
|
313 |
tick = (int) floor(d * 40 + 0.01); |
314 |
perc = (int) floor(d * 100 + 0.025); |
315 |
fprintf(stderr, "%-21s |%-40s| %d%% "COL0"", p->name, b + 40 - tick, perc); |
316 |
p->dnext = (tick + 0.995) / 40.0; |
317 |
} |
318 |
} |
319 |
|
320 |
/* Initialize parameters for simple progress bar. The caller passes an
|
321 |
allocated simple_progress_t structure to avoid having to malloc it
|
322 |
here and free it later. */
|
323 |
static inline void init_progress(potrace_progress_t *prog, simple_progress_t *p, const char *filename, int count) { |
324 |
const char *q, *s; |
325 |
int len;
|
326 |
|
327 |
/* initialize callback function's data */
|
328 |
p->dnext = 0;
|
329 |
|
330 |
if (count != 0) { |
331 |
sprintf(p->name, " (p.%d):", count + 1); |
332 |
} else {
|
333 |
s = filename; |
334 |
if ((q = strrchr(s, '/')) != NULL) { |
335 |
s = q + 1;
|
336 |
} |
337 |
len = strlen(s); |
338 |
strncpy(p->name, s, 21);
|
339 |
p->name[20] = 0; |
340 |
if (len > 20) { |
341 |
p->name[17] = '.'; |
342 |
p->name[18] = '.'; |
343 |
p->name[19] = '.'; |
344 |
} |
345 |
strcat(p->name, ":");
|
346 |
} |
347 |
|
348 |
/* initialize progress parameters */
|
349 |
prog->callback = &simple_progress; |
350 |
prog->data = (void *) p;
|
351 |
prog->min = 0.0; |
352 |
prog->max = 1.0; |
353 |
prog->epsilon = 0.0; |
354 |
|
355 |
/* draw first progress bar */
|
356 |
simple_progress(0.0, prog->data); |
357 |
return;
|
358 |
} |
359 |
|
360 |
struct pageformat_s {
|
361 |
char *name;
|
362 |
int w, h;
|
363 |
}; |
364 |
typedef struct pageformat_s pageformat_t; |
365 |
|
366 |
/* dimensions of the various page formats, in postscript points */
|
367 |
static pageformat_t pageformat[] = {
|
368 |
{ "a4", 595, 842 }, |
369 |
{ "a3", 842, 1191 }, |
370 |
{ "a5", 421, 595 }, |
371 |
{ "b5", 516, 729 }, |
372 |
{ "letter", 612, 792 }, |
373 |
{ "legal", 612, 1008 }, |
374 |
{ "tabloid", 792, 1224 }, |
375 |
{ "statement", 396, 612 }, |
376 |
{ "executive", 540, 720 }, |
377 |
{ "folio", 612, 936 }, |
378 |
{ "quarto", 610, 780 }, |
379 |
{ "10x14", 720, 1008 }, |
380 |
{ NULL, 0, 0 }, |
381 |
}; |
382 |
|
383 |
struct turnpolicy_s {
|
384 |
char *name;
|
385 |
int n;
|
386 |
}; |
387 |
typedef struct turnpolicy_s turnpolicy_t; |
388 |
|
389 |
/* names of turn policies */
|
390 |
static turnpolicy_t turnpolicy[] = {
|
391 |
{"black", POTRACE_TURNPOLICY_BLACK},
|
392 |
{"white", POTRACE_TURNPOLICY_WHITE},
|
393 |
{"left", POTRACE_TURNPOLICY_LEFT},
|
394 |
{"right", POTRACE_TURNPOLICY_RIGHT},
|
395 |
{"minority", POTRACE_TURNPOLICY_MINORITY},
|
396 |
{"majority", POTRACE_TURNPOLICY_MAJORITY},
|
397 |
{"random", POTRACE_TURNPOLICY_RANDOM},
|
398 |
{NULL, 0}, |
399 |
}; |
400 |
|
401 |
static dim_t parse_dimension(char *s, char **endptr) { |
402 |
char *p;
|
403 |
dim_t res; |
404 |
|
405 |
res.x = strtod(s, &p); |
406 |
res.d = 0;
|
407 |
if (p!=s) {
|
408 |
if (!strncasecmp(p, "in", 2)) { |
409 |
res.d = DIM_IN; |
410 |
p += 2;
|
411 |
} else if (!strncasecmp(p, "cm", 2)) { |
412 |
res.d = DIM_CM; |
413 |
p += 2;
|
414 |
} else if (!strncasecmp(p, "mm", 2)) { |
415 |
res.d = DIM_MM; |
416 |
p += 2;
|
417 |
} else if (!strncasecmp(p, "pt", 2)) { |
418 |
res.d = DIM_PT; |
419 |
p += 2;
|
420 |
} |
421 |
} |
422 |
if (endptr!=NULL) { |
423 |
*endptr = p; |
424 |
} |
425 |
return res;
|
426 |
} |
427 |
|
428 |
/* parse a pair of dimensions, such as "8.5x11in", "30mmx4cm" */
|
429 |
static void parse_dimensions(char *s, char **endptr, dim_t *dxp, dim_t *dyp) { |
430 |
char *p, *q;
|
431 |
dim_t dx, dy; |
432 |
|
433 |
dx = parse_dimension(s, &p); |
434 |
if (p==s) {
|
435 |
goto fail;
|
436 |
} |
437 |
if (*p != 'x') { |
438 |
goto fail;
|
439 |
} |
440 |
p++; |
441 |
dy = parse_dimension(p, &q); |
442 |
if (q==p) {
|
443 |
goto fail;
|
444 |
} |
445 |
if (dx.d && !dy.d) {
|
446 |
dy.d = dx.d; |
447 |
} else if (!dx.d && dy.d) { |
448 |
dx.d = dy.d; |
449 |
} |
450 |
*dxp = dx; |
451 |
*dyp = dy; |
452 |
if (endptr != NULL) { |
453 |
*endptr = q; |
454 |
} |
455 |
return;
|
456 |
|
457 |
fail:
|
458 |
dx.x = dx.d = dy.x = dy.d = 0;
|
459 |
*dxp = dx; |
460 |
*dyp = dy; |
461 |
if (endptr != NULL) { |
462 |
*endptr = s; |
463 |
} |
464 |
return;
|
465 |
} |
466 |
|
467 |
#define OPT_GROUP 300 |
468 |
#define OPT_OPAQUE 301 |
469 |
#define OPT_FILLCOLOR 302 |
470 |
#define OPT_PROGRESS 303 |
471 |
|
472 |
static struct option longopts[] = { |
473 |
{"help", 0, 0, 'h'}, |
474 |
{"version", 0, 0, 'v'}, |
475 |
{"license", 0, 0, 'l'}, |
476 |
{"show-defaults", 0, 0, 'V'}, |
477 |
{"progress", 0, 0, OPT_PROGRESS}, |
478 |
{"width", 1, 0, 'W'}, |
479 |
{"height", 1, 0, 'H'}, |
480 |
{"resolution", 1, 0, 'r'}, |
481 |
{"scale", 1, 0, 'x'}, |
482 |
{"stretch", 1, 0, 'S'}, |
483 |
{"margin", 1, 0, 'M'}, |
484 |
{"leftmargin", 1, 0, 'L'}, |
485 |
{"rightmargin", 1, 0, 'R'}, |
486 |
{"topmargin", 1, 0, 'T'}, |
487 |
{"bottommargin", 1, 0, 'B'}, |
488 |
{"rotate", 1, 0, 'A'}, |
489 |
{"pagesize", 1, 0, 'P'}, |
490 |
{"turdsize", 1, 0, 't'}, |
491 |
{"unit", 1, 0, 'u'}, |
492 |
{"cleartext", 0, 0, 'c'}, |
493 |
{"level2", 0, 0, '2'}, |
494 |
{"level3", 0, 0, '3'}, |
495 |
{"eps", 0, 0, 'e'}, |
496 |
{"postscript", 0, 0, 'p'}, |
497 |
{"svg", 0, 0, 's'}, |
498 |
{"pgm", 0, 0, 'g'}, |
499 |
{"backend", 1, 0, 'b'}, |
500 |
{"debug", 1, 0, 'd'}, |
501 |
{"color", 1, 0, 'C'}, |
502 |
{"fillcolor", 1, 0, OPT_FILLCOLOR}, |
503 |
{"turnpolicy", 1, 0, 'z'}, |
504 |
{"gamma", 1, 0, 'G'}, |
505 |
{"longcurve", 0, 0, 'n'}, |
506 |
{"longcoding", 0, 0, 'q'}, |
507 |
{"alphamax", 1, 0, 'a'}, |
508 |
{"opttolerance", 1, 0, 'O'}, |
509 |
{"output", 1, 0, 'o'}, |
510 |
{"blacklevel", 1, 0, 'k'}, |
511 |
{"invert", 0, 0, 'i'}, |
512 |
{"opaque", 0, 0, OPT_OPAQUE}, |
513 |
{"group", 0, 0, OPT_GROUP}, |
514 |
|
515 |
{0, 0, 0, 0} |
516 |
}; |
517 |
|
518 |
static char *shortopts = "hvlVW:H:r:x:S:M:L:R:T:B:A:P:t:u:c23epsgb:d:C:z:G:nqa:O:o:k:i"; |
519 |
|
520 |
static void dopts(int ac, char *av[]) { |
521 |
int c;
|
522 |
char *p;
|
523 |
int i, j, r;
|
524 |
dim_t dim, dimx, dimy; |
525 |
int matches, bestmatch;
|
526 |
|
527 |
/* defaults */
|
528 |
info.backend = &backend[0];
|
529 |
|
530 |
info.debug = 0;
|
531 |
info.width_d.x = UNDEF; |
532 |
info.height_d.x = UNDEF; |
533 |
info.rx = UNDEF; |
534 |
info.ry = UNDEF; |
535 |
info.sx = UNDEF; |
536 |
info.sy = UNDEF; |
537 |
info.stretch = 1;
|
538 |
info.lmar_d.x = UNDEF; |
539 |
info.rmar_d.x = UNDEF; |
540 |
info.tmar_d.x = UNDEF; |
541 |
info.bmar_d.x = UNDEF; |
542 |
info.angle = 0;
|
543 |
info.paperwidth = DEFAULT_PAPERWIDTH; |
544 |
info.paperheight = DEFAULT_PAPERHEIGHT; |
545 |
info.unit = 10;
|
546 |
info.compress = 1;
|
547 |
info.pslevel = 2;
|
548 |
info.color = 0x000000;
|
549 |
info.gamma = 2.2; |
550 |
info.param = potrace_param_default(); |
551 |
if (!info.param) {
|
552 |
fprintf(stderr, ""POTRACE": %s\n", strerror(errno)); |
553 |
exit(1);
|
554 |
} |
555 |
info.longcoding = 0;
|
556 |
info.outfile = NULL;
|
557 |
info.blacklevel = 0.5; |
558 |
info.invert = 0;
|
559 |
info.opaque = 0;
|
560 |
info.group = 0;
|
561 |
info.fillcolor = 0xffffff;
|
562 |
info.progress = 0;
|
563 |
|
564 |
while ((c = getopt_long(ac, av, shortopts, longopts, NULL)) != -1) { |
565 |
switch (c) {
|
566 |
case OPT_PROGRESS:
|
567 |
info.progress = 1;
|
568 |
break;
|
569 |
case 'W': |
570 |
info.width_d = parse_dimension(optarg, &p); |
571 |
if (*p) {
|
572 |
fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg); |
573 |
exit(1);
|
574 |
} |
575 |
break;
|
576 |
case 'H': |
577 |
info.height_d = parse_dimension(optarg, &p); |
578 |
if (*p) {
|
579 |
fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg); |
580 |
exit(1);
|
581 |
} |
582 |
break;
|
583 |
case 'r': |
584 |
parse_dimensions(optarg, &p, &dimx, &dimy); |
585 |
if (*p == 0 && dimx.d == 0 && dimy.d == 0) { |
586 |
info.rx = dimx.x; |
587 |
info.ry = dimy.x; |
588 |
break;
|
589 |
} |
590 |
dim = parse_dimension(optarg, &p); |
591 |
if (*p == 0 && dim.d == 0) { |
592 |
info.rx = info.ry = dim.x; |
593 |
break;
|
594 |
} |
595 |
fprintf(stderr, ""POTRACE": invalid resolution -- %s\n", optarg); |
596 |
exit(1);
|
597 |
break;
|
598 |
case 'x': |
599 |
parse_dimensions(optarg, &p, &dimx, &dimy); |
600 |
if (*p == 0 && dimx.d == 0 && dimy.d == 0) { |
601 |
info.sx = dimx.x; |
602 |
info.sy = dimy.x; |
603 |
break;
|
604 |
} |
605 |
dim = parse_dimension(optarg, &p); |
606 |
if (*p == 0 && dim.d == 0) { |
607 |
info.sx = info.sy = dim.x; |
608 |
break;
|
609 |
} |
610 |
fprintf(stderr, ""POTRACE": invalid scaling factor -- %s\n", optarg); |
611 |
exit(1);
|
612 |
break;
|
613 |
case 'S': |
614 |
info.stretch = atof(optarg); |
615 |
break;
|
616 |
case 'M': |
617 |
info.lmar_d = parse_dimension(optarg, &p); |
618 |
if (*p) {
|
619 |
fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg); |
620 |
exit(1);
|
621 |
} |
622 |
info.rmar_d = info.tmar_d = info.bmar_d = info.lmar_d; |
623 |
break;
|
624 |
case 'L': |
625 |
info.lmar_d = parse_dimension(optarg, &p); |
626 |
if (*p) {
|
627 |
fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg); |
628 |
exit(1);
|
629 |
} |
630 |
break;
|
631 |
case 'R': |
632 |
info.rmar_d = parse_dimension(optarg, &p); |
633 |
if (*p) {
|
634 |
fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg); |
635 |
exit(1);
|
636 |
} |
637 |
break;
|
638 |
case 'T': |
639 |
info.tmar_d = parse_dimension(optarg, &p); |
640 |
if (*p) {
|
641 |
fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg); |
642 |
exit(1);
|
643 |
} |
644 |
break;
|
645 |
case 'B': |
646 |
info.bmar_d = parse_dimension(optarg, &p); |
647 |
if (*p) {
|
648 |
fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg); |
649 |
exit(1);
|
650 |
} |
651 |
break;
|
652 |
case 'A': |
653 |
info.angle = strtod(optarg, &p); |
654 |
if (*p) {
|
655 |
fprintf(stderr, ""POTRACE": invalid angle -- %s\n", optarg); |
656 |
exit(1);
|
657 |
} |
658 |
break;
|
659 |
case 'P': |
660 |
matches = 0;
|
661 |
bestmatch = 0;
|
662 |
for (i=0; pageformat[i].name!=NULL; i++) { |
663 |
if (strcasecmp(pageformat[i].name, optarg)==0) { |
664 |
matches = 1;
|
665 |
bestmatch = i; |
666 |
break;
|
667 |
} else if (strncasecmp(pageformat[i].name, optarg, strlen(optarg))==0) { |
668 |
/* don't allow partial match on "10x14" */
|
669 |
if (optarg[0] != '1') { |
670 |
matches++; |
671 |
bestmatch = i; |
672 |
} |
673 |
} |
674 |
} |
675 |
if (matches == 1) { |
676 |
info.paperwidth = pageformat[bestmatch].w; |
677 |
info.paperheight = pageformat[bestmatch].h; |
678 |
break;
|
679 |
} |
680 |
parse_dimensions(optarg, &p, &dimx, &dimy); |
681 |
if (*p == 0) { |
682 |
info.paperwidth = (int)rint(double_of_dim(dimx, DEFAULT_DIM));
|
683 |
info.paperheight = (int)rint(double_of_dim(dimy, DEFAULT_DIM));
|
684 |
break;
|
685 |
} |
686 |
if (matches == 0) { |
687 |
fprintf(stderr, ""POTRACE": unrecognized page format -- %s\n", optarg); |
688 |
} else {
|
689 |
fprintf(stderr, ""POTRACE": ambiguous page format -- %s\n", optarg); |
690 |
} |
691 |
j = fprintf(stderr, "Use one of: ");
|
692 |
for (i=0; pageformat[i].name!=NULL; i++) { |
693 |
if (j + strlen(pageformat[i].name) > 75) { |
694 |
fprintf(stderr, "\n");
|
695 |
j = 0;
|
696 |
} |
697 |
j += fprintf(stderr, "%s, ", pageformat[i].name);
|
698 |
} |
699 |
fprintf(stderr, "or specify <dim>x<dim>.\n");
|
700 |
exit(1);
|
701 |
break;
|
702 |
case 't': |
703 |
info.param->turdsize = atoi(optarg); |
704 |
break;
|
705 |
case 'u': |
706 |
info.unit = strtod(optarg, &p); |
707 |
if (*p) {
|
708 |
fprintf(stderr, ""POTRACE": invalid unit -- %s\n", optarg); |
709 |
exit(1);
|
710 |
} |
711 |
break;
|
712 |
case 'c': |
713 |
info.pslevel = 2;
|
714 |
info.compress = 0;
|
715 |
break;
|
716 |
case '2': |
717 |
info.pslevel = 2;
|
718 |
info.compress = 1;
|
719 |
break;
|
720 |
case '3': |
721 |
#ifdef HAVE_ZLIB
|
722 |
info.pslevel = 3;
|
723 |
info.compress = 1;
|
724 |
#else
|
725 |
fprintf(stderr, ""POTRACE": option -3 not supported, using -2 instead.\n"); |
726 |
info.pslevel = 2;
|
727 |
info.compress = 1;
|
728 |
#endif
|
729 |
break;
|
730 |
case 'd': |
731 |
info.debug = atoi(optarg); |
732 |
break;
|
733 |
case 'z': |
734 |
matches = 0;
|
735 |
bestmatch = 0;
|
736 |
for (i=0; turnpolicy[i].name!=NULL; i++) { |
737 |
if (strcasecmp(turnpolicy[i].name, optarg)==0) { |
738 |
matches = 1;
|
739 |
bestmatch = i; |
740 |
break;
|
741 |
} else if (strncasecmp(turnpolicy[i].name, optarg, strlen(optarg))==0) { |
742 |
matches++; |
743 |
bestmatch = i; |
744 |
} |
745 |
} |
746 |
if (matches == 1) { |
747 |
info.param->turnpolicy = turnpolicy[bestmatch].n; |
748 |
break;
|
749 |
} |
750 |
if (matches == 0) { |
751 |
fprintf(stderr, ""POTRACE": unrecognized turnpolicy -- %s\n", optarg); |
752 |
} else {
|
753 |
fprintf(stderr, ""POTRACE": ambiguous turnpolicy -- %s\n", optarg); |
754 |
} |
755 |
j = fprintf(stderr, "Use one of: ");
|
756 |
for (i=0; turnpolicy[i].name!=NULL; i++) { |
757 |
if (j + strlen(turnpolicy[i].name) > 75) { |
758 |
fprintf(stderr, "\n");
|
759 |
j = 0;
|
760 |
} |
761 |
j += fprintf(stderr, "%s%s", turnpolicy[i].name, turnpolicy[i+1].name ? ", " : ""); |
762 |
} |
763 |
fprintf(stderr, ".\n");
|
764 |
exit(1);
|
765 |
break;
|
766 |
case 'G': |
767 |
info.gamma = atof(optarg); |
768 |
break;
|
769 |
case 'n': |
770 |
info.param->opticurve = 0;
|
771 |
break;
|
772 |
case 'q': |
773 |
info.longcoding = 1;
|
774 |
break;
|
775 |
case 'a': |
776 |
info.param->alphamax = strtod(optarg, &p); |
777 |
|
778 |
if (*p) {
|
779 |
fprintf(stderr, ""POTRACE": invalid alphamax -- %s\n", optarg); |
780 |
exit(1);
|
781 |
} |
782 |
break;
|
783 |
case 'O': |
784 |
info.param->opttolerance = strtod(optarg, &p); |
785 |
if (*p) {
|
786 |
fprintf(stderr, ""POTRACE": invalid opttolerance -- %s\n", optarg); |
787 |
exit(1);
|
788 |
} |
789 |
break;
|
790 |
case 'o': |
791 |
free(info.outfile); |
792 |
info.outfile = strdup(optarg); |
793 |
break;
|
794 |
case 'k': |
795 |
info.blacklevel = strtod(optarg, &p); |
796 |
if (*p) {
|
797 |
fprintf(stderr, ""POTRACE": invalid blacklevel -- %s\n", optarg); |
798 |
exit(1);
|
799 |
} |
800 |
break;
|
801 |
case 'i': |
802 |
info.invert = 1;
|
803 |
break;
|
804 |
case OPT_OPAQUE:
|
805 |
info.opaque = 1;
|
806 |
break;
|
807 |
case OPT_GROUP:
|
808 |
info.group = 1;
|
809 |
break;
|
810 |
case '?': |
811 |
fprintf(stderr, "Try --help for more info\n");
|
812 |
exit(1);
|
813 |
break;
|
814 |
default:
|
815 |
fprintf(stderr, ""POTRACE": Unimplemented option -- %c\n", c); |
816 |
exit(1);
|
817 |
} |
818 |
} |
819 |
info.infiles = &av[optind]; |
820 |
info.infilecount = ac-optind; |
821 |
} |
822 |
|
823 |
static double* showList(potrace_path_t *plist) { |
824 |
int i;
|
825 |
int count;
|
826 |
potrace_path_t *p; |
827 |
int n, *tag;
|
828 |
potrace_dpoint_t (*c)[3];
|
829 |
double *memory;
|
830 |
|
831 |
p = plist; |
832 |
count = 0;
|
833 |
|
834 |
// Comprobamos cuanto va a ocupar la memoria a rellenar
|
835 |
while (p != NULL) { |
836 |
n = p->curve.n; |
837 |
tag = p->curve.tag; |
838 |
c = p->curve.c; |
839 |
count += 3; // moveTo(x, y) |
840 |
for (i = 0; i < n; i++) { |
841 |
switch (tag[i]) {
|
842 |
case POTRACE_CORNER:
|
843 |
count += 3; // lineTo(x, y) |
844 |
count += 3; // lineTo(x, y) |
845 |
break;
|
846 |
case POTRACE_CURVETO:
|
847 |
count += 7; // curveTo(x1, y1, x2, y2, x3, y3) |
848 |
break;
|
849 |
} |
850 |
} |
851 |
// at the end of a group of a positive path and its negative children, fill
|
852 |
if (p->next == NULL || p->next->sign == '+') |
853 |
count++; // closePath()
|
854 |
p = p->next; |
855 |
} |
856 |
count++; |
857 |
|
858 |
// Creamos la zona de memoria que devolveremos a Java
|
859 |
memory = (double *) malloc(sizeof(double) * count); |
860 |
|
861 |
// Rellenamos la memoria con la lista de operaciones a realizar
|
862 |
p = plist; |
863 |
count = 1;
|
864 |
while (p != NULL) { |
865 |
n = p->curve.n; |
866 |
tag = p->curve.tag; |
867 |
c = p->curve.c; |
868 |
|
869 |
// moveTo(x, y);
|
870 |
memory[count++] = 0;
|
871 |
memory[count++] = c[n - 1][2].x; |
872 |
memory[count++] = c[n - 1][2].y; |
873 |
for (i = 0; i < n; i++) { |
874 |
switch (tag[i]) {
|
875 |
case POTRACE_CORNER:
|
876 |
// lineTo(x, y);
|
877 |
memory[count++] = 1;
|
878 |
memory[count++] = c[i][1].x;
|
879 |
memory[count++] = c[i][1].y;
|
880 |
// lineTo(x, y);
|
881 |
memory[count++] = 1;
|
882 |
memory[count++] = c[i][2].x;
|
883 |
memory[count++] = c[i][2].y;
|
884 |
break;
|
885 |
case POTRACE_CURVETO:
|
886 |
// curveTo(x1, y1, x2, y2, x3, y3);
|
887 |
memory[count++] = 2;
|
888 |
memory[count++] = c[i][0].x;
|
889 |
memory[count++] = c[i][0].y;
|
890 |
memory[count++] = c[i][1].x;
|
891 |
memory[count++] = c[i][1].y;
|
892 |
memory[count++] = c[i][2].x;
|
893 |
memory[count++] = c[i][2].y;
|
894 |
break;
|
895 |
} |
896 |
} |
897 |
if (p->next == NULL || p->next->sign == '+') |
898 |
memory[count++] = 3;
|
899 |
p = p->next; |
900 |
} |
901 |
memory[0] = count;
|
902 |
return memory;
|
903 |
} |
904 |
|
905 |
static double* process_buffer(const long *inbuffer, int width, int height) { |
906 |
int r;
|
907 |
double *memory;
|
908 |
potrace_bitmap_t *bm = NULL;
|
909 |
imginfo_t imginfo; |
910 |
int eof_flag = 0; /* to indicate premature eof */ |
911 |
potrace_state_t *st; |
912 |
simple_progress_t progress_data; |
913 |
int dy;
|
914 |
|
915 |
bm = (potrace_bitmap_t *) malloc (sizeof(potrace_bitmap_t));
|
916 |
bm->w = width; |
917 |
bm->h = height; |
918 |
dy = (width + 32 - 1) / 32; |
919 |
bm->dy = dy; |
920 |
|
921 |
bm->map = (potrace_word *) inbuffer; |
922 |
|
923 |
/* prepare progress bar, if requested */
|
924 |
info.param->progress.callback = NULL;
|
925 |
|
926 |
// Invertir colores, el negro es blanco y el blanco es negro
|
927 |
if (info.invert)
|
928 |
bm_invert(bm); |
929 |
|
930 |
/* process the image */
|
931 |
|
932 |
st = potrace_trace(info.param, bm); |
933 |
if (!st || st->status != POTRACE_STATUS_OK) {
|
934 |
fprintf(stderr, ""POTRACE": %s\n", strerror(errno)); |
935 |
exit(2);
|
936 |
} |
937 |
/* calculate image dimensions */
|
938 |
imginfo.pixwidth = bm->w; |
939 |
imginfo.pixheight = bm->h; |
940 |
calc_dimensions(&imginfo); |
941 |
|
942 |
// rgaitan: We cannot use here bm_free (becouse it
|
943 |
// frees also the bm->map (that is a inbuffer, that in this
|
944 |
// case comes from java so, FAIL!.
|
945 |
//bm_free(bm);
|
946 |
|
947 |
memory = showList(st->plist); |
948 |
|
949 |
potrace_state_free(st); |
950 |
|
951 |
if (info.progress) {
|
952 |
fprintf(stderr, "\n");
|
953 |
} |
954 |
|
955 |
return memory;
|
956 |
} |
957 |
|
958 |
double* vectorizarBuffer(const long *bufferIn, int width, int height, int argc, char *argv[]) { |
959 |
/* platform-specific initializations, e.g., set file i/o to binary */
|
960 |
platform_init(); |
961 |
|
962 |
// Reiniciar el contador externo de los parametros
|
963 |
optind = 1;
|
964 |
|
965 |
/* process options */
|
966 |
dopts(argc, argv); |
967 |
|
968 |
return process_buffer(bufferIn, width, height);
|
969 |
} |