00001
00002
00003
00004
00005
00006
00007 #include <stdio.h>
00008 #include <stdlib.h>
00009 #include <errno.h>
00010 #include <string.h>
00011 #include <getopt.h>
00012 #include <math.h>
00013
00014 #include "main.h"
00015 #include "potracelib.h"
00016 #include "backend_pdf.h"
00017 #include "backend_eps.h"
00018 #include "backend_pgm.h"
00019 #include "backend_svg.h"
00020 #include "backend_hpgl.h"
00021 #include "backend_gimp.h"
00022 #include "backend_xfig.h"
00023 #include "potracelib.h"
00024 #include "bitmap_io.h"
00025 #include "bitmap.h"
00026 #include "platform.h"
00027 #include "auxiliary.h"
00028
00029 #ifdef HAVE_CONFIG_H
00030 #include "config.h"
00031 #endif
00032
00033 #ifndef M_PI
00034 #define M_PI 3.14159265358979323846
00035 #endif
00036
00037 #define UNDEF ((double)(1e30))
00038 #define INFTY ((double)(1e30))
00039
00040 struct info_s info;
00041
00042 #define COL0 "\033[G"
00043
00044
00045
00046
00047 struct simple_progress_s {
00048 char name[22];
00049 double dnext;
00050 };
00051 typedef struct simple_progress_s simple_progress_t;
00052
00053
00054
00055
00056 static void simple_progress(double d, void *data) {
00057 simple_progress_t *p = (simple_progress_t *)data;
00058 static char b[] = "========================================";
00059 int tick;
00060 int perc;
00061
00062
00063
00064
00065 if (d >= p->dnext) {
00066 tick = (int) floor(d*40+0.01);
00067 perc = (int) floor(d*100+0.025);
00068 fprintf(stderr, "%-21s |%-40s| %d%% "COL0"", p->name, b+40-tick, perc);
00069 p->dnext = (tick+0.995) / 40.0;
00070 }
00071 }
00072
00073
00074
00075
00076 static inline void init_progress(potrace_progress_t *prog, simple_progress_t *p, const char *filename, int count) {
00077 const char *q, *s;
00078 int len;
00079
00080
00081 p->dnext = 0;
00082
00083 if (count != 0) {
00084 sprintf(p->name, " (p.%d):", count+1);
00085 } else {
00086 s = filename;
00087 if ((q = strrchr(s, '/')) != NULL) {
00088 s = q+1;
00089 }
00090 len = strlen(s);
00091 strncpy(p->name, s, 21);
00092 p->name[20] = 0;
00093 if (len > 20) {
00094 p->name[17] = '.';
00095 p->name[18] = '.';
00096 p->name[19] = '.';
00097 }
00098 strcat(p->name, ":");
00099 }
00100
00101
00102 prog->callback = &simple_progress;
00103 prog->data = (void *)p;
00104 prog->min = 0.0;
00105 prog->max = 1.0;
00106 prog->epsilon = 0.0;
00107
00108
00109 simple_progress(0.0, prog->data);
00110 return;
00111 }
00112
00113
00114
00115
00116 struct pageformat_s {
00117 char *name;
00118 int w, h;
00119 };
00120 typedef struct pageformat_s pageformat_t;
00121
00122
00123 static pageformat_t pageformat[] = {
00124 { "a4", 595, 842 },
00125 { "a3", 842, 1191 },
00126 { "a5", 421, 595 },
00127 { "b5", 516, 729 },
00128 { "letter", 612, 792 },
00129 { "legal", 612, 1008 },
00130 { "tabloid", 792, 1224 },
00131 { "statement", 396, 612 },
00132 { "executive", 540, 720 },
00133 { "folio", 612, 936 },
00134 { "quarto", 610, 780 },
00135 { "10x14", 720, 1008 },
00136 { NULL, 0, 0 },
00137 };
00138
00139 struct turnpolicy_s {
00140 char *name;
00141 int n;
00142 };
00143 typedef struct turnpolicy_s turnpolicy_t;
00144
00145
00146 static turnpolicy_t turnpolicy[] = {
00147 {"black", POTRACE_TURNPOLICY_BLACK},
00148 {"white", POTRACE_TURNPOLICY_WHITE},
00149 {"left", POTRACE_TURNPOLICY_LEFT},
00150 {"right", POTRACE_TURNPOLICY_RIGHT},
00151 {"minority", POTRACE_TURNPOLICY_MINORITY},
00152 {"majority", POTRACE_TURNPOLICY_MAJORITY},
00153 {"random", POTRACE_TURNPOLICY_RANDOM},
00154 {NULL, 0},
00155 };
00156
00157
00158 struct backend_s {
00159 char *name;
00160 char *ext;
00161 int fixed;
00162 int pixel;
00163 int multi;
00164 int (*init_f)(FILE *fout);
00165 int (*page_f)(FILE *fout, potrace_path_t *plist, imginfo_t *imginfo);
00166
00167 int (*term_f)(FILE *fout);
00168 int opticurve;
00169 };
00170 typedef struct backend_s backend_t;
00171
00172 static backend_t backend[] = {
00173 {"eps", ".eps", 0, 0, 0, NULL, page_eps, NULL, 1},
00174 {"postscript", ".ps", 1, 0, 1, init_ps, page_ps, term_ps, 1},
00175 {"ps", ".ps", 1, 0, 1, init_ps, page_ps, term_ps, 1},
00176 {"pdf", ".pdf", 0, 0, 1, init_pdf,page_pdf, term_pdf, 1},
00177 {"svg", ".svg", 0, 0, 0, NULL, page_svg, NULL, 1},
00178 {"hpgl", ".plt", 0, 0, 0, NULL, page_hpgl, NULL, 1},
00179 {"pgm", ".pgm", 0, 1, 1, NULL, page_pgm, NULL, 1},
00180 {"gimppath", ".gimppath", 0, 1, 0, NULL, page_gimp, NULL, 1},
00181 {"xfig", ".fig", 1, 0, 0, NULL, page_xfig, NULL, 0},
00182 {NULL, NULL, 0, 0, 0, NULL, NULL, NULL},
00183 };
00184
00185
00186
00187
00188 static int backend_lookup(char *name, backend_t **bp) {
00189 int i;
00190 int m=0;
00191 backend_t *b = NULL;
00192
00193 for (i=0; backend[i].name; i++) {
00194 if (strcasecmp(backend[i].name, name)==0) {
00195 *bp = &backend[i];
00196 return 0;
00197 } else if (strncasecmp(backend[i].name, name, strlen(name))==0) {
00198 m++;
00199 b = &backend[i];
00200 }
00201 }
00202
00203 if (m==1) {
00204 *bp = b;
00205 return 0;
00206 } else if (m) {
00207 return 2;
00208 } else {
00209 return 1;
00210 }
00211 }
00212
00213
00214
00215
00216
00217 static int backend_list(FILE *fout, int j, int linelen) {
00218 int i;
00219
00220 for (i=0; backend[i].name; i++) {
00221 if (j + (int)strlen(backend[i].name) > linelen) {
00222 fprintf(fout, "\n");
00223 j = 0;
00224 }
00225 j += fprintf(fout, "%s", backend[i].name);
00226 if (backend[i+1].name) {
00227 j += fprintf(fout, ", ");
00228 }
00229 }
00230 return j;
00231 }
00232
00233
00234
00235
00236 static void license(FILE *f) {
00237 fprintf(f,
00238 "This program is free software; you can redistribute it and/or modify\n"
00239 "it under the terms of the GNU General Public License as published by\n"
00240 "the Free Software Foundation; either version 2 of the License, or\n"
00241 "(at your option) any later version.\n"
00242 "\n"
00243 "This program is distributed in the hope that it will be useful,\n"
00244 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
00245 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
00246 "GNU General Public License for more details.\n"
00247 "\n"
00248 "You should have received a copy of the GNU General Public License\n"
00249 "along with this program; if not, write to the Free Software\n"
00250 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.\n"
00251 );
00252 }
00253
00254 static void show_defaults(FILE *f) {
00255 fprintf(f, "This version of Potrace was compiled with the following defaults:\n");
00256 fprintf(f, "Default unit: "DEFAULT_DIM_NAME"\n");
00257 fprintf(f, "Default page size: "DEFAULT_PAPERFORMAT"\n");
00258 }
00259
00260 static void usage(FILE *f) {
00261 int j;
00262
00263 fprintf(f, "Usage: "POTRACE" [options] [file...]\n");
00264 fprintf(f, "General options:\n");
00265 fprintf(f, " -h, --help - print this help message and exit\n");
00266 fprintf(f, " -v, --version - print version info and exit\n");
00267 fprintf(f, " -l, --license - print license info and exit\n");
00268 fprintf(f, " -V, --show-defaults - print compiled-in defaults and exit\n");
00269 fprintf(f, " --progress - show progress bar\n");
00270 fprintf(f, "Input/output options:\n");
00271 fprintf(f, " -o, --output <file> - output to file\n");
00272 fprintf(f, "Backend selection:\n");
00273 fprintf(f, " -e, --eps - EPS backend (encapsulated postscript) (default)\n");
00274 fprintf(f, " -p, --postscript - Postscript backend\n");
00275 fprintf(f, " -s, --svg - SVG backend (scalable vector graphics)\n");
00276 fprintf(f, " -g, --pgm - PGM backend (portable greymap)\n");
00277 fprintf(f, " -b, --backend <name> - select backend by name\n");
00278 fprintf(f, "Algorithm options:\n");
00279 fprintf(f, " -z, --turnpolicy <policy> - how to resolve ambiguities in path decomposition\n");
00280 fprintf(f, " -t, --turdsize <n> - suppress speckles of up to this size (default 2)\n");
00281 fprintf(f, " -a, --alphamax <n> - corner threshold parameter (default 1)\n");
00282 fprintf(f, " -n, --longcurve - turn off curve optimization\n");
00283 fprintf(f, " -O, --opttolerance <n> - curve optimization tolerance (default 0.2)\n");
00284 fprintf(f, " -u, --unit <n> - quantize output to 1/unit pixels (default 10)\n");
00285 fprintf(f, " -d, --debug <n> - produce debugging output of type n (n=1,2,3)\n");
00286 fprintf(f, "Scaling and placement options:\n");
00287 fprintf(f, " -W, --width <dim> - width of output image\n");
00288 fprintf(f, " -H, --height <dim> - height of output image\n");
00289 fprintf(f, " -r, --resolution <n>[x<n>] - resolution (in dpi)\n");
00290 fprintf(f, " -x, --scale <n>[x<n>] - scaling factor (pgm backend)\n");
00291 fprintf(f, " -S, --stretch <n> - yresolution/xresolution\n");
00292 fprintf(f, " -A, --rotate <angle> - rotate counterclockwise by angle\n");
00293 fprintf(f, " -M, --margin <dim> - margin\n");
00294 fprintf(f, " -L, --leftmargin <dim> - left margin\n");
00295 fprintf(f, " -R, --rightmargin <dim> - right margin\n");
00296 fprintf(f, " -T, --topmargin <dim> - top margin\n");
00297 fprintf(f, " -B, --bottommargin <dim> - bottom margin\n");
00298 fprintf(f, "Output options, supported by some backends:\n");
00299 fprintf(f, " -C, --color #rrggbb - set line color (default black)\n");
00300 fprintf(f, " --fillcolor #rrggbb - set fill color (default transparent)\n");
00301 fprintf(f, " --opaque - make white shapes opaque\n");
00302 fprintf(f, " --group - group related paths together\n");
00303 fprintf(f, "Postscript/EPS options:\n");
00304 fprintf(f, " -P, --pagesize <format> - page size (default is "DEFAULT_PAPERFORMAT")\n");
00305 fprintf(f, " -c, --cleartext - do not compress the output\n");
00306 fprintf(f, " -2, --level2 - use postscript level 2 compression (default)\n");
00307 #ifdef HAVE_ZLIB
00308 fprintf(f, " -3, --level3 - use postscript level 3 compression\n");
00309 #endif
00310 fprintf(f, " -q, --longcoding - do not optimize for file size\n");
00311 fprintf(f, "PGM options:\n");
00312 fprintf(f, " -G, --gamma <n> - gamma value for anti-aliasing (default 2.2)\n");
00313 fprintf(f, "Frontend options:\n");
00314 fprintf(f, " -k, --blacklevel <n> - black/white cutoff in input file (default 0.5)\n");
00315 fprintf(f, " -i, --invert - invert bitmap\n");
00316 fprintf(f, "\n");
00317 fprintf(f, "Dimensions can have optional units, e.g. 6.5in, 15cm, 100pt.\n");
00318 fprintf(f, "Default is "DEFAULT_DIM_NAME" (or pixels for pgm and gimppath backends).\n");
00319 fprintf(f, "Possible input file formats are: pnm (pbm, pgm, ppm), bmp.\n");
00320 j = fprintf(f, "Backends are: ");
00321 backend_list(f, j, 70);
00322 fprintf(f, ".\n");
00323 }
00324
00325
00326
00327
00328
00329
00330
00331 static dim_t parse_dimension(char *s, char **endptr) {
00332 char *p;
00333 dim_t res;
00334
00335 res.x = strtod(s, &p);
00336 res.d = 0;
00337 if (p!=s) {
00338 if (!strncasecmp(p, "in", 2)) {
00339 res.d = DIM_IN;
00340 p += 2;
00341 } else if (!strncasecmp(p, "cm", 2)) {
00342 res.d = DIM_CM;
00343 p += 2;
00344 } else if (!strncasecmp(p, "mm", 2)) {
00345 res.d = DIM_MM;
00346 p += 2;
00347 } else if (!strncasecmp(p, "pt", 2)) {
00348 res.d = DIM_PT;
00349 p += 2;
00350 }
00351 }
00352 if (endptr!=NULL) {
00353 *endptr = p;
00354 }
00355 return res;
00356 }
00357
00358
00359 static void parse_dimensions(char *s, char **endptr, dim_t *dxp, dim_t *dyp) {
00360 char *p, *q;
00361 dim_t dx, dy;
00362
00363 dx = parse_dimension(s, &p);
00364 if (p==s) {
00365 goto fail;
00366 }
00367 if (*p != 'x') {
00368 goto fail;
00369 }
00370 p++;
00371 dy = parse_dimension(p, &q);
00372 if (q==p) {
00373 goto fail;
00374 }
00375 if (dx.d && !dy.d) {
00376 dy.d = dx.d;
00377 } else if (!dx.d && dy.d) {
00378 dx.d = dy.d;
00379 }
00380 *dxp = dx;
00381 *dyp = dy;
00382 if (endptr != NULL) {
00383 *endptr = q;
00384 }
00385 return;
00386
00387 fail:
00388 dx.x = dx.d = dy.x = dy.d = 0;
00389 *dxp = dx;
00390 *dyp = dy;
00391 if (endptr != NULL) {
00392 *endptr = s;
00393 }
00394 return;
00395 }
00396
00397 static inline double double_of_dim(dim_t d, double def) {
00398 if (d.d) {
00399 return d.x * d.d;
00400 } else {
00401 return d.x * def;
00402 }
00403 }
00404
00405 static int parse_color(char *s) {
00406 int i, d;
00407 int col = 0;
00408
00409 if (s[0] != '#' || strlen(s) != 7) {
00410 return -1;
00411 }
00412 for (i=0; i<6; i++) {
00413 d = s[6-i];
00414 if (d >= '0' && d <= '9') {
00415 col |= (d-'0') << (4*i);
00416 } else if (d >= 'a' && d <= 'f') {
00417 col |= (d-'a'+10) << (4*i);
00418 } else if (d >= 'A' && d <= 'F') {
00419 col |= (d-'A'+10) << (4*i);
00420 } else {
00421 return -1;
00422 }
00423 }
00424 return col;
00425 }
00426
00427
00428
00429
00430
00431 #define OPT_GROUP 300
00432 #define OPT_OPAQUE 301
00433 #define OPT_FILLCOLOR 302
00434 #define OPT_PROGRESS 303
00435
00436 static struct option longopts[] = {
00437 {"help", 0, 0, 'h'},
00438 {"version", 0, 0, 'v'},
00439 {"license", 0, 0, 'l'},
00440 {"show-defaults", 0, 0, 'V'},
00441 {"progress", 0, 0, OPT_PROGRESS},
00442 {"width", 1, 0, 'W'},
00443 {"height", 1, 0, 'H'},
00444 {"resolution", 1, 0, 'r'},
00445 {"scale", 1, 0, 'x'},
00446 {"stretch", 1, 0, 'S'},
00447 {"margin", 1, 0, 'M'},
00448 {"leftmargin", 1, 0, 'L'},
00449 {"rightmargin", 1, 0, 'R'},
00450 {"topmargin", 1, 0, 'T'},
00451 {"bottommargin", 1, 0, 'B'},
00452 {"rotate", 1, 0, 'A'},
00453 {"pagesize", 1, 0, 'P'},
00454 {"turdsize", 1, 0, 't'},
00455 {"unit", 1, 0, 'u'},
00456 {"cleartext", 0, 0, 'c'},
00457 {"level2", 0, 0, '2'},
00458 {"level3", 0, 0, '3'},
00459 {"eps", 0, 0, 'e'},
00460 {"postscript", 0, 0, 'p'},
00461 {"svg", 0, 0, 's'},
00462 {"pgm", 0, 0, 'g'},
00463 {"backend", 1, 0, 'b'},
00464 {"debug", 1, 0, 'd'},
00465 {"color", 1, 0, 'C'},
00466 {"fillcolor", 1, 0, OPT_FILLCOLOR},
00467 {"turnpolicy", 1, 0, 'z'},
00468 {"gamma", 1, 0, 'G'},
00469 {"longcurve", 0, 0, 'n'},
00470 {"longcoding", 0, 0, 'q'},
00471 {"alphamax", 1, 0, 'a'},
00472 {"opttolerance", 1, 0, 'O'},
00473 {"output", 1, 0, 'o'},
00474 {"blacklevel", 1, 0, 'k'},
00475 {"invert", 0, 0, 'i'},
00476 {"opaque", 0, 0, OPT_OPAQUE},
00477 {"group", 0, 0, OPT_GROUP},
00478
00479 {0, 0, 0, 0}
00480 };
00481
00482 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";
00483
00484 static void dopts(int ac, char *av[]) {
00485 int c;
00486 char *p;
00487 int i, j, r;
00488 dim_t dim, dimx, dimy;
00489 int matches, bestmatch;
00490
00491
00492 backend_lookup("eps", &info.backend);
00493 info.debug = 0;
00494 info.width_d.x = UNDEF;
00495 info.height_d.x = UNDEF;
00496 info.rx = UNDEF;
00497 info.ry = UNDEF;
00498 info.sx = UNDEF;
00499 info.sy = UNDEF;
00500 info.stretch = 1;
00501 info.lmar_d.x = UNDEF;
00502 info.rmar_d.x = UNDEF;
00503 info.tmar_d.x = UNDEF;
00504 info.bmar_d.x = UNDEF;
00505 info.angle = 0;
00506 info.paperwidth = DEFAULT_PAPERWIDTH;
00507 info.paperheight = DEFAULT_PAPERHEIGHT;
00508 info.unit = 10;
00509 info.compress = 1;
00510 info.pslevel = 2;
00511 info.color = 0x000000;
00512 info.gamma = 2.2;
00513 info.param = potrace_param_default();
00514 if (!info.param) {
00515 fprintf(stderr, ""POTRACE": %s\n", strerror(errno));
00516 exit(1);
00517 }
00518 info.longcoding = 0;
00519 info.outfile = NULL;
00520 info.blacklevel = 0.5;
00521 info.invert = 0;
00522 info.opaque = 0;
00523 info.group = 0;
00524 info.fillcolor = 0xffffff;
00525 info.progress = 0;
00526
00527 while ((c = getopt_long(ac, av, shortopts, longopts, NULL)) != -1) {
00528 switch (c) {
00529 case 'h':
00530 fprintf(stdout, ""POTRACE" "VERSION". Transforms bitmaps into vector graphics.\n\n");
00531 usage(stdout);
00532 exit(0);
00533 break;
00534 case 'v':
00535 fprintf(stdout, ""POTRACE" "VERSION". Copyright (C) 2001-2007 Peter Selinger.\n");
00536 fprintf(stdout, "Library version: %s\n", potrace_version());
00537 exit(0);
00538 break;
00539 case 'l':
00540 fprintf(stdout, ""POTRACE" "VERSION". Copyright (C) 2001-2007 Peter Selinger.\n\n");
00541 license(stdout);
00542 exit(0);
00543 break;
00544 case 'V':
00545 fprintf(stdout, ""POTRACE" "VERSION". Copyright (C) 2001-2007 Peter Selinger.\n");
00546 show_defaults(stdout);
00547 exit(0);
00548 break;
00549 case OPT_PROGRESS:
00550 info.progress = 1;
00551 break;
00552 case 'W':
00553 info.width_d = parse_dimension(optarg, &p);
00554 if (*p) {
00555 fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg);
00556 exit(1);
00557 }
00558 break;
00559 case 'H':
00560 info.height_d = parse_dimension(optarg, &p);
00561 if (*p) {
00562 fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg);
00563 exit(1);
00564 }
00565 break;
00566 case 'r':
00567 parse_dimensions(optarg, &p, &dimx, &dimy);
00568 if (*p == 0 && dimx.d == 0 && dimy.d == 0) {
00569 info.rx = dimx.x;
00570 info.ry = dimy.x;
00571 break;
00572 }
00573 dim = parse_dimension(optarg, &p);
00574 if (*p == 0 && dim.d == 0) {
00575 info.rx = info.ry = dim.x;
00576 break;
00577 }
00578 fprintf(stderr, ""POTRACE": invalid resolution -- %s\n", optarg);
00579 exit(1);
00580 break;
00581 case 'x':
00582 parse_dimensions(optarg, &p, &dimx, &dimy);
00583 if (*p == 0 && dimx.d == 0 && dimy.d == 0) {
00584 info.sx = dimx.x;
00585 info.sy = dimy.x;
00586 break;
00587 }
00588 dim = parse_dimension(optarg, &p);
00589 if (*p == 0 && dim.d == 0) {
00590 info.sx = info.sy = dim.x;
00591 break;
00592 }
00593 fprintf(stderr, ""POTRACE": invalid scaling factor -- %s\n", optarg);
00594 exit(1);
00595 break;
00596 case 'S':
00597 info.stretch = atof(optarg);
00598 break;
00599 case 'M':
00600 info.lmar_d = parse_dimension(optarg, &p);
00601 if (*p) {
00602 fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg);
00603 exit(1);
00604 }
00605 info.rmar_d = info.tmar_d = info.bmar_d = info.lmar_d;
00606 break;
00607 case 'L':
00608 info.lmar_d = parse_dimension(optarg, &p);
00609 if (*p) {
00610 fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg);
00611 exit(1);
00612 }
00613 break;
00614 case 'R':
00615 info.rmar_d = parse_dimension(optarg, &p);
00616 if (*p) {
00617 fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg);
00618 exit(1);
00619 }
00620 break;
00621 case 'T':
00622 info.tmar_d = parse_dimension(optarg, &p);
00623 if (*p) {
00624 fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg);
00625 exit(1);
00626 }
00627 break;
00628 case 'B':
00629 info.bmar_d = parse_dimension(optarg, &p);
00630 if (*p) {
00631 fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg);
00632 exit(1);
00633 }
00634 break;
00635 case 'A':
00636 info.angle = strtod(optarg, &p);
00637 if (*p) {
00638 fprintf(stderr, ""POTRACE": invalid angle -- %s\n", optarg);
00639 exit(1);
00640 }
00641 break;
00642 case 'P':
00643 matches = 0;
00644 bestmatch = 0;
00645 for (i=0; pageformat[i].name!=NULL; i++) {
00646 if (strcasecmp(pageformat[i].name, optarg)==0) {
00647 matches = 1;
00648 bestmatch = i;
00649 break;
00650 } else if (strncasecmp(pageformat[i].name, optarg, strlen(optarg))==0) {
00651
00652 if (optarg[0] != '1') {
00653 matches++;
00654 bestmatch = i;
00655 }
00656 }
00657 }
00658 if (matches == 1) {
00659 info.paperwidth = pageformat[bestmatch].w;
00660 info.paperheight = pageformat[bestmatch].h;
00661 break;
00662 }
00663 parse_dimensions(optarg, &p, &dimx, &dimy);
00664 if (*p == 0) {
00665 info.paperwidth = (int)rint(double_of_dim(dimx, DEFAULT_DIM));
00666 info.paperheight = (int)rint(double_of_dim(dimy, DEFAULT_DIM));
00667 break;
00668 }
00669 if (matches == 0) {
00670 fprintf(stderr, ""POTRACE": unrecognized page format -- %s\n", optarg);
00671 } else {
00672 fprintf(stderr, ""POTRACE": ambiguous page format -- %s\n", optarg);
00673 }
00674 j = fprintf(stderr, "Use one of: ");
00675 for (i=0; pageformat[i].name!=NULL; i++) {
00676 if (j + strlen(pageformat[i].name) > 75) {
00677 fprintf(stderr, "\n");
00678 j = 0;
00679 }
00680 j += fprintf(stderr, "%s, ", pageformat[i].name);
00681 }
00682 fprintf(stderr, "or specify <dim>x<dim>.\n");
00683 exit(1);
00684 break;
00685 case 't':
00686 info.param->turdsize = atoi(optarg);
00687 break;
00688 case 'u':
00689 info.unit = strtod(optarg, &p);
00690 if (*p) {
00691 fprintf(stderr, ""POTRACE": invalid unit -- %s\n", optarg);
00692 exit(1);
00693 }
00694 break;
00695 case 'c':
00696 info.pslevel = 2;
00697 info.compress = 0;
00698 break;
00699 case '2':
00700 info.pslevel = 2;
00701 info.compress = 1;
00702 break;
00703 case '3':
00704 #ifdef HAVE_ZLIB
00705 info.pslevel = 3;
00706 info.compress = 1;
00707 #else
00708 fprintf(stderr, ""POTRACE": option -3 not supported, using -2 instead.\n");
00709 info.pslevel = 2;
00710 info.compress = 1;
00711 #endif
00712 break;
00713 case 'e':
00714 backend_lookup("eps", &info.backend);
00715 break;
00716 case 'p':
00717 backend_lookup("postscript", &info.backend);
00718 break;
00719 case 's':
00720 backend_lookup("svg", &info.backend);
00721 break;
00722 case 'g':
00723 backend_lookup("pgm", &info.backend);
00724 break;
00725 case 'b':
00726 r = backend_lookup(optarg, &info.backend);
00727 if (r==1 || r==2) {
00728 if (r==1) {
00729 fprintf(stderr, ""POTRACE": unrecognized backend -- %s\n", optarg);
00730 } else {
00731 fprintf(stderr, ""POTRACE": ambiguous backend -- %s\n", optarg);
00732 }
00733 j = fprintf(stderr, "Use one of: ");
00734 backend_list(stderr, j, 70);
00735 fprintf(stderr, ".\n");
00736 exit(1);
00737 }
00738 break;
00739 case 'd':
00740 info.debug = atoi(optarg);
00741 break;
00742 case 'C':
00743 info.color = parse_color(optarg);
00744 if (info.color == -1) {
00745 fprintf(stderr, ""POTRACE": invalid color -- %s\n", optarg);
00746 exit(1);
00747 }
00748 break;
00749 case OPT_FILLCOLOR:
00750 info.fillcolor = parse_color(optarg);
00751 if (info.fillcolor == -1) {
00752 fprintf(stderr, ""POTRACE": invalid color -- %s\n", optarg);
00753 exit(1);
00754 }
00755 info.opaque = 1;
00756 break;
00757 case 'z':
00758 matches = 0;
00759 bestmatch = 0;
00760 for (i=0; turnpolicy[i].name!=NULL; i++) {
00761 if (strcasecmp(turnpolicy[i].name, optarg)==0) {
00762 matches = 1;
00763 bestmatch = i;
00764 break;
00765 } else if (strncasecmp(turnpolicy[i].name, optarg, strlen(optarg))==0) {
00766 matches++;
00767 bestmatch = i;
00768 }
00769 }
00770 if (matches == 1) {
00771 info.param->turnpolicy = turnpolicy[bestmatch].n;
00772 break;
00773 }
00774 if (matches == 0) {
00775 fprintf(stderr, ""POTRACE": unrecognized turnpolicy -- %s\n", optarg);
00776 } else {
00777 fprintf(stderr, ""POTRACE": ambiguous turnpolicy -- %s\n", optarg);
00778 }
00779 j = fprintf(stderr, "Use one of: ");
00780 for (i=0; turnpolicy[i].name!=NULL; i++) {
00781 if (j + strlen(turnpolicy[i].name) > 75) {
00782 fprintf(stderr, "\n");
00783 j = 0;
00784 }
00785 j += fprintf(stderr, "%s%s", turnpolicy[i].name, turnpolicy[i+1].name ? ", " : "");
00786 }
00787 fprintf(stderr, ".\n");
00788 exit(1);
00789 break;
00790 case 'G':
00791 info.gamma = atof(optarg);
00792 break;
00793 case 'n':
00794 info.param->opticurve = 0;
00795 break;
00796 case 'q':
00797 info.longcoding = 1;
00798 break;
00799 case 'a':
00800 info.param->alphamax = strtod(optarg, &p);
00801 if (*p) {
00802 fprintf(stderr, ""POTRACE": invalid alphamax -- %s\n", optarg);
00803 exit(1);
00804 }
00805 break;
00806 case 'O':
00807 info.param->opttolerance = strtod(optarg, &p);
00808 if (*p) {
00809 fprintf(stderr, ""POTRACE": invalid opttolerance -- %s\n", optarg);
00810 exit(1);
00811 }
00812 break;
00813 case 'o':
00814 free(info.outfile);
00815 info.outfile = strdup(optarg);
00816 break;
00817 case 'k':
00818 info.blacklevel = strtod(optarg, &p);
00819 if (*p) {
00820 fprintf(stderr, ""POTRACE": invalid blacklevel -- %s\n", optarg);
00821 exit(1);
00822 }
00823 break;
00824 case 'i':
00825 info.invert = 1;
00826 break;
00827 case OPT_OPAQUE:
00828 info.opaque = 1;
00829 break;
00830 case OPT_GROUP:
00831 info.group = 1;
00832 break;
00833 case '?':
00834 fprintf(stderr, "Try --help for more info\n");
00835 exit(1);
00836 break;
00837 default:
00838 fprintf(stderr, ""POTRACE": Unimplemented option -- %c\n", c);
00839 exit(1);
00840 }
00841 }
00842 info.infiles = &av[optind];
00843 info.infilecount = ac-optind;
00844 }
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854 static void rotate_dim(double alpha, double w, double h, rect_t *r) {
00855 double s, c, x0, x1, y0, y1;
00856
00857 s = sin(alpha/180*M_PI);
00858 c = cos(alpha/180*M_PI);
00859
00860
00861 x0 = c*w;
00862 x1 = s*w;
00863 y0 = -s*h;
00864 y1 = c*h;
00865
00866
00867 r->bb[0] = fabs(x0) + fabs(y0);
00868 r->bb[1] = fabs(x1) + fabs(y1);
00869 r->orig[0] = - min(x0,0) - min(y0,0);
00870 r->orig[1] = - min(x1,0) - min(y1,0);
00871 }
00872
00873
00874
00875 static void calc_dimensions(imginfo_t *imginfo) {
00876 double dim_def;
00877 double maxwidth, maxheight, sc;
00878 rect_t r;
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888 if (imginfo->pixwidth == 0) {
00889 imginfo->pixwidth = 1;
00890 }
00891 if (imginfo->pixheight == 0) {
00892 imginfo->pixheight = 1;
00893 }
00894
00895
00896 if (info.backend->pixel) {
00897 dim_def = DIM_PT;
00898 } else {
00899 dim_def = DEFAULT_DIM;
00900 }
00901
00902
00903 imginfo->width = info.width_d.x == UNDEF ? UNDEF : double_of_dim(info.width_d, dim_def);
00904 imginfo->height = info.height_d.x == UNDEF ? UNDEF : double_of_dim(info.height_d, dim_def);
00905 imginfo->lmar = info.lmar_d.x == UNDEF ? UNDEF : double_of_dim(info.lmar_d, dim_def);
00906 imginfo->rmar = info.rmar_d.x == UNDEF ? UNDEF : double_of_dim(info.rmar_d, dim_def);
00907 imginfo->tmar = info.tmar_d.x == UNDEF ? UNDEF : double_of_dim(info.tmar_d, dim_def);
00908 imginfo->bmar = info.bmar_d.x == UNDEF ? UNDEF : double_of_dim(info.bmar_d, dim_def);
00909
00910
00911
00912 if (info.backend->pixel) {
00913 if (imginfo->width == UNDEF && info.sx != UNDEF) {
00914 imginfo->width = imginfo->pixwidth * info.sx;
00915 }
00916 if (imginfo->height == UNDEF && info.sy != UNDEF) {
00917 imginfo->height = imginfo->pixheight * info.sy;
00918 }
00919 } else {
00920 if (imginfo->width == UNDEF && info.rx != UNDEF) {
00921 imginfo->width = imginfo->pixwidth / info.rx * 72;
00922 }
00923 if (imginfo->height == UNDEF && info.ry != UNDEF) {
00924 imginfo->height = imginfo->pixheight / info.ry * 72;
00925 }
00926 }
00927
00928
00929 if (imginfo->width == UNDEF && imginfo->height != UNDEF) {
00930 imginfo->width = imginfo->height / imginfo->pixheight * imginfo->pixwidth / info.stretch;
00931 } else if (imginfo->width != UNDEF && imginfo->height == UNDEF) {
00932 imginfo->height = imginfo->width / imginfo->pixwidth * imginfo->pixheight * info.stretch;
00933 }
00934
00935
00936 if (imginfo->width == UNDEF && imginfo->height == UNDEF) {
00937
00938 if (info.backend->fixed) {
00939
00940
00941 maxwidth = UNDEF;
00942 maxheight = UNDEF;
00943
00944 if (imginfo->lmar != UNDEF && imginfo->rmar != UNDEF) {
00945 maxwidth = info.paperwidth - imginfo->lmar - imginfo->rmar;
00946 }
00947 if (imginfo->bmar != UNDEF && imginfo->tmar != UNDEF) {
00948 maxheight = info.paperheight - imginfo->bmar - imginfo->tmar;
00949 }
00950 if (maxwidth == UNDEF && maxheight == UNDEF) {
00951 maxwidth = max(info.paperwidth - 144, info.paperwidth * 0.75);
00952 maxheight = max(info.paperheight - 144, info.paperheight * 0.75);
00953 }
00954
00955 rotate_dim(info.angle, imginfo->pixwidth, imginfo->pixheight * info.stretch, &r);
00956
00957 sc = min(maxwidth == UNDEF ? INFTY : maxwidth / r.bb[0], maxheight == UNDEF ? INFTY : maxheight / r.bb[1]);
00958 imginfo->width = imginfo->pixwidth * sc;
00959 imginfo->height = imginfo->pixheight * info.stretch * sc;
00960
00961 } else if (info.backend->pixel) {
00962
00963
00964
00965 imginfo->width = imginfo->pixwidth;
00966 imginfo->height = imginfo->pixheight * info.stretch;
00967 } else {
00968
00969
00970
00971 maxwidth = max(info.paperwidth - 144, info.paperwidth * 0.75);
00972 maxheight = max(info.paperheight - 144, info.paperheight * 0.75);
00973
00974 sc = min(maxwidth / imginfo->pixwidth, maxheight / imginfo->pixheight / info.stretch);
00975 imginfo->width = imginfo->pixwidth * sc;
00976 imginfo->height = imginfo->pixheight * info.stretch * sc;
00977 }
00978 }
00979
00980
00981 rotate_dim(info.angle, imginfo->width, imginfo->height, &imginfo->trans);
00982
00983
00984 if (info.backend->fixed) {
00985 if (imginfo->lmar == UNDEF && imginfo->rmar == UNDEF) {
00986 imginfo->lmar = (info.paperwidth-imginfo->trans.bb[0])/2;
00987 } else if (imginfo->lmar == UNDEF) {
00988 imginfo->lmar = (info.paperwidth-imginfo->trans.bb[0]-imginfo->rmar);
00989 } else if (imginfo->lmar != UNDEF && imginfo->rmar != UNDEF) {
00990 imginfo->lmar += (info.paperwidth-imginfo->trans.bb[0]-imginfo->lmar-imginfo->rmar)/2;
00991 }
00992 if (imginfo->bmar == UNDEF && imginfo->tmar == UNDEF) {
00993 imginfo->bmar = (info.paperheight-imginfo->trans.bb[1])/2;
00994 } else if (imginfo->bmar == UNDEF) {
00995 imginfo->bmar = (info.paperheight-imginfo->trans.bb[1]-imginfo->tmar);
00996 } else if (imginfo->bmar != UNDEF && imginfo->tmar != UNDEF) {
00997 imginfo->bmar += (info.paperheight-imginfo->trans.bb[1]-imginfo->bmar-imginfo->tmar)/2;
00998 }
00999 } else {
01000 if (imginfo->lmar == UNDEF) {
01001 imginfo->lmar = 0;
01002 }
01003 if (imginfo->rmar == UNDEF) {
01004 imginfo->rmar = 0;
01005 }
01006 if (imginfo->bmar == UNDEF) {
01007 imginfo->bmar = 0;
01008 }
01009 if (imginfo->tmar == UNDEF) {
01010 imginfo->tmar = 0;
01011 }
01012 }
01013 }
01014
01015
01016
01017
01018
01019 static FILE *my_fopen_read(char *filename) {
01020 if (filename == NULL || strcmp(filename, "-") == 0) {
01021 return stdin;
01022 }
01023 return fopen(filename, "rb");
01024 }
01025
01026
01027 static FILE *my_fopen_write(char *filename) {
01028 if (filename == NULL || strcmp(filename, "-") == 0) {
01029 return stdout;
01030 }
01031 return fopen(filename, "wb");
01032 }
01033
01034
01035 static void my_fclose(FILE *f, char *filename) {
01036 if (filename == NULL || strcmp(filename, "-") == 0) {
01037 return;
01038 }
01039 fclose(f);
01040 }
01041
01042
01043 static char *make_outfilename(char *infile, char *ext) {
01044 char *outfile;
01045 char *p;
01046
01047 if (strcmp(infile, "-") == 0) {
01048 return strdup("-");
01049 }
01050
01051 outfile = (char *) malloc(strlen(infile)+strlen(ext)+5);
01052 if (!outfile) {
01053 return NULL;
01054 }
01055 strcpy(outfile, infile);
01056 p = strrchr(outfile, '.');
01057 if (p) {
01058 *p = 0;
01059 }
01060 strcat(outfile, ext);
01061
01062
01063 if (strcmp(infile, outfile) == 0) {
01064 strcpy(outfile, infile);
01065 strcat(outfile, "-out");
01066 }
01067
01068 return outfile;
01069 }
01070
01071
01072
01073
01074
01075
01076
01077 static void process_file(backend_t *b, const char *infile, const char *outfile, FILE *fin, FILE *fout) {
01078 int r;
01079 potrace_bitmap_t *bm = NULL;
01080 imginfo_t imginfo;
01081 int eof_flag = 0;
01082 int count;
01083 potrace_state_t *st;
01084 simple_progress_t progress_data;
01085
01086 for (count=0; ; count++) {
01087
01088 r = bm_read(fin, info.blacklevel, &bm);
01089 switch (r) {
01090 case -1:
01091 fprintf(stderr, ""POTRACE": %s: %s\n", infile, strerror(errno));
01092 exit(2);
01093 case -2:
01094 fprintf(stderr, ""POTRACE": %s: file format error: %s\n", infile, bm_read_error);
01095 exit(2);
01096 case -3:
01097 if (count>0) {
01098 return;
01099 }
01100 fprintf(stderr, ""POTRACE": %s: empty file\n", infile);
01101 exit(2);
01102 case -4:
01103 if (count>0) {
01104 fprintf(stderr, ""POTRACE": %s: warning: junk at end of file\n", infile);
01105 return;
01106 }
01107 fprintf(stderr, ""POTRACE": %s: file format not recognized\n", infile);
01108 fprintf(stderr, "Possible input file formats are: pnm (pbm, pgm, ppm), bmp.\n");
01109 exit(2);
01110 case 1:
01111 fprintf(stderr, ""POTRACE": warning: %s: premature end of file\n", infile);
01112 eof_flag = 1;
01113 break;
01114 }
01115
01116
01117 if (info.progress) {
01118 init_progress(&info.param->progress, &progress_data, infile, count);
01119 } else {
01120 info.param->progress.callback = NULL;
01121 }
01122
01123 if (info.invert) {
01124 bm_invert(bm);
01125 }
01126
01127
01128 st = potrace_trace(info.param, bm);
01129 if (!st || st->status != POTRACE_STATUS_OK) {
01130 fprintf(stderr, ""POTRACE": %s: %s\n", infile, strerror(errno));
01131 exit(2);
01132 }
01133
01134
01135 imginfo.pixwidth = bm->w;
01136 imginfo.pixheight = bm->h;
01137 calc_dimensions(&imginfo);
01138
01139 bm_free(bm);
01140
01141 r = b->page_f(fout, st->plist, &imginfo);
01142 if (r) {
01143 fprintf(stderr, ""POTRACE": %s: %s\n", outfile, strerror(errno));
01144 exit(2);
01145 }
01146
01147 potrace_state_free(st);
01148
01149 if (info.progress) {
01150 fprintf(stderr, "\n");
01151 }
01152
01153 if (eof_flag || !b->multi) {
01154 return;
01155 }
01156 }
01157
01158 }
01159
01160
01161
01162
01163 #define TRY(x) if (x) goto try_error
01164
01165 int main(int ac, char *av[]) {
01166 backend_t *b;
01167 FILE *fin, *fout;
01168 int i;
01169 char *outfile;
01170
01171
01172 platform_init();
01173
01174
01175 dopts(ac, av);
01176
01177 b = info.backend;
01178 if (b==NULL) {
01179 fprintf(stderr, ""POTRACE": internal error: selected backend not found\n");
01180 exit(1);
01181 }
01182
01183
01184
01185 if (b->opticurve == 0) {
01186 info.param->opticurve = 0;
01187 }
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200 if (info.infilecount == 0) {
01201
01202 fout = my_fopen_write(info.outfile);
01203 if (!fout) {
01204 fprintf(stderr, ""POTRACE": %s: %s\n", info.outfile ? info.outfile : "stdout", strerror(errno));
01205 exit(2);
01206 }
01207 if (b->init_f) {
01208 TRY(b->init_f(fout));
01209 }
01210 process_file(b, "stdin", info.outfile ? info.outfile : "stdout", stdin, fout);
01211 if (b->term_f) {
01212 TRY(b->term_f(fout));
01213 }
01214 my_fclose(fout, info.outfile);
01215 return 0;
01216
01217 } else if (!info.outfile) {
01218
01219 for (i=0; i<info.infilecount; i++) {
01220 outfile = make_outfilename(info.infiles[i], b->ext);
01221 if (!outfile) {
01222 fprintf(stderr, ""POTRACE": %s\n", strerror(errno));
01223 exit(2);
01224 }
01225 fin = my_fopen_read(info.infiles[i]);
01226 if (!fin) {
01227 fprintf(stderr, ""POTRACE": %s: %s\n", info.infiles[i], strerror(errno));
01228 exit(2);
01229 }
01230 fout = my_fopen_write(outfile);
01231 if (!fout) {
01232 fprintf(stderr, ""POTRACE": %s: %s\n", outfile, strerror(errno));
01233 exit(2);
01234 }
01235 if (b->init_f) {
01236 TRY(b->init_f(fout));
01237 }
01238 process_file(b, info.infiles[i], outfile, fin, fout);
01239 if (b->term_f) {
01240 TRY(b->term_f(fout));
01241 }
01242 my_fclose(fin, info.infiles[i]);
01243 my_fclose(fout, outfile);
01244 free(outfile);
01245 }
01246 return 0;
01247
01248 } else {
01249
01250 if (!b->multi && info.infilecount >= 2) {
01251 fprintf(stderr, ""POTRACE": cannot use multiple input files with -o in %s mode\n", b->name);
01252 exit(1);
01253 }
01254
01255 fout = my_fopen_write(info.outfile);
01256 if (!fout) {
01257 fprintf(stderr, ""POTRACE": %s: %s\n", info.outfile, strerror(errno));
01258 exit(2);
01259 }
01260 if (b->init_f) {
01261 TRY(b->init_f(fout));
01262 }
01263 for (i=0; i<info.infilecount; i++) {
01264 fin = my_fopen_read(info.infiles[i]);
01265 if (!fin) {
01266 fprintf(stderr, ""POTRACE": %s: %s\n", info.infiles[i], strerror(errno));
01267 exit(2);
01268 }
01269 process_file(b, info.infiles[i], info.outfile, fin, fout);
01270 my_fclose(fin, info.infiles[i]);
01271 }
01272 if (b->term_f) {
01273 TRY(b->term_f(fout));
01274 }
01275 my_fclose(fout, info.outfile);
01276 return 0;
01277
01278 }
01279
01280
01281
01282 try_error:
01283 fprintf(stderr, ""POTRACE": %s\n", strerror(errno));
01284 exit(2);
01285 }