main.c
Go to the documentation of this file.
00001 /* Copyright (C) 2001-2007 Peter Selinger.
00002    This file is part of Potrace. It is free software and it is covered
00003    by the GNU General Public License. See the file COPYING for details. */
00004 
00005 /* $Id: main.c 147 2007-04-09 00:44:09Z selinger $ */
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))   /* a value to represent "undefined" */
00038 #define INFTY ((double)(1e30))   /* a value to represent +infinity */
00039 
00040 struct info_s info;
00041 
00042 #define COL0 "\033[G"  /* reset cursor to column 0 */
00043 
00044 /* ---------------------------------------------------------------------- */
00045 /* callback function for progress bar */
00046 
00047 struct simple_progress_s {
00048   char name[22];          /* filename for status bar */
00049   double dnext;           /* threshold value for next tick */
00050 };
00051 typedef struct simple_progress_s simple_progress_t;
00052 
00053 /* print a simple progress bar. This is a callback function that is
00054    potentially called often; thus, it has been optimized for the
00055    typical case, which is when the progress bar does not need updating. */
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;    /* number of visible tickmarks, 0..40 */
00060   int perc;    /* visible percentage, 0..100 */
00061 
00062   /* note: the 0.01 and 0.025 ensure that we always end on 40
00063      tickmarks and 100%, despite any rounding errors. The 0.995
00064      ensures that tick always increases when d >= p->dnext. */
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 /* Initialize parameters for simple progress bar. The caller passes an
00074    allocated simple_progress_t structure to avoid having to malloc it
00075    here and free it later. */
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   /* initialize callback function's data */
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   /* initialize progress parameters */
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   /* draw first progress bar */
00109   simple_progress(0.0, prog->data);
00110   return;
00111 }
00112 
00113 /* ---------------------------------------------------------------------- */
00114 /* some data structures for option processing */
00115 
00116 struct pageformat_s {
00117   char *name;
00118   int w, h;
00119 };
00120 typedef struct pageformat_s pageformat_t;
00121 
00122 /* dimensions of the various page formats, in postscript points */
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 /* names of turn policies */
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 /* backends and their characteristics */
00158 struct backend_s {
00159   char *name;       /* name of this backend */
00160   char *ext;        /* file extension */
00161   int fixed;        /* fixed page size backend? */
00162   int pixel;        /* pixel-based backend? */
00163   int multi;        /* multi-page backend? */
00164   int (*init_f)(FILE *fout);                 /* initialization function */
00165   int (*page_f)(FILE *fout, potrace_path_t *plist, imginfo_t *imginfo);
00166                                              /* per-bitmap function */
00167   int (*term_f)(FILE *fout);                 /* finalization function */
00168   int opticurve;    /* opticurve capable (true Bezier curves?) */
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 /* look up a backend by name. If found, return 0 and set *bp. If not
00186    found leave *bp unchanged and return 1, or 2 on ambiguous
00187    prefix. */
00188 static int backend_lookup(char *name, backend_t **bp) {
00189   int i;
00190   int m=0;  /* prefix matches */
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   /* if there was no exact match, and exactly one prefix match, use that */
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 /* list all available backends by name, in a comma separated list.
00214    Assume the cursor starts in column j, and break lines at length
00215    linelen. Do not output any trailing punctuation. Return the column
00216    the cursor is in. */
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 /* some info functions */
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 /* auxiliary functions for parameter parsing */
00327 
00328 /* parse a dimension of the kind "1.5in", "7cm", etc. Return result in
00329    postscript points (=1/72 in). If endptr!=NULL, store pointer to
00330    next character in *endptr in the manner of strtod(3). */
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 /* parse a pair of dimensions, such as "8.5x11in", "30mmx4cm" */
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 /* option processing */
00429 
00430 /* codes for options that don't have short form */
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   /* defaults */
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           /* don't allow partial match on "10x14" */
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 /* calculations with bitmap dimensions, positioning etc */
00848 
00849 /* consider a rectangle spanned by the vectors (w,0) and (0,h). Rotate
00850    it counterclockwise by angle alpha. Then set the rect_t structure
00851    to the resulting rectangle, setting its bounding box, origin,
00852    x-basis and y-basis. */
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   /* apply the transformation matrix to the basis vectors */
00861   x0 = c*w;
00862   x1 = s*w;
00863   y0 = -s*h;
00864   y1 = c*h;
00865 
00866   /* determine bounding box and origin relative to bounding box */
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 /* determine the dimensions of the output based on command line and
00874    image dimensions */
00875 static void calc_dimensions(imginfo_t *imginfo) {
00876   double dim_def;
00877   double maxwidth, maxheight, sc;
00878   rect_t r;
00879 
00880   /* we take care of a special case: if one of the image dimensions is
00881      0, we change it to 1. Such an image is empty anyway, so there
00882      will be 0 paths in it. Changing the dimensions avoids division by
00883      0 error in calculating scaling factors, bounding boxes and
00884      such. This doesn't quite do the right thing in all cases, but it
00885      is better than causing overflow errors or "nan" output in
00886      backends.  Human users don't tend to process images of size 0
00887      anyway; they might occur in some pipelines. */
00888   if (imginfo->pixwidth == 0) {
00889     imginfo->pixwidth = 1;
00890   }
00891   if (imginfo->pixheight == 0) {
00892     imginfo->pixheight = 1;
00893   }
00894 
00895   /* set the default dimension for width, height, margins */
00896   if (info.backend->pixel) {
00897     dim_def = DIM_PT;
00898   } else {
00899     dim_def = DEFAULT_DIM;
00900   }
00901 
00902   /* apply default dimension to width, height, margins */
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   /* determine width and height from desired resolution / scaling
00911      factor, if given */
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   /* if one of width/height is specified, determine the other */
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   /* if width and height are still variable, figure them out */
00936   if (imginfo->width == UNDEF && imginfo->height == UNDEF) {
00937    
00938     if (info.backend->fixed) {
00939 
00940       /* in fixed-size backends, try to squeeze it between margins */
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       /* in pixel-based backends, assume default scaling factor of 1 */
00964 
00965       imginfo->width = imginfo->pixwidth;
00966       imginfo->height = imginfo->pixheight * info.stretch;
00967     } else {
00968 
00969       /* otherwise, choose a default size based on the default paper format */
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   /* calculate coordinate system */
00981   rotate_dim(info.angle, imginfo->width, imginfo->height, &imginfo->trans);
00982 
00983   /* adjust margins */
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 /* auxiliary functions for file handling */
01017 
01018 /* open a file for reading. Return stdin if filename is NULL or "-" */ 
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 /* open a file for writing. Return stdout if filename is NULL or "-" */ 
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 /* close a file, but do nothing is filename is NULL or "-" */
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 /* make output filename from input filename. Return an allocated value. */
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   /* check that input and output filenames are different */
01063   if (strcmp(infile, outfile) == 0) {
01064     strcpy(outfile, infile);
01065     strcat(outfile, "-out");
01066   }
01067 
01068   return outfile;
01069 }
01070 
01071 /* ---------------------------------------------------------------------- */
01072 /* Process one infile */
01073 
01074 /* Process one or more bitmaps from fin, and write the results to fout
01075    using the page_f function of the appropriate backend. */
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;  /* to indicate premature eof */
01082   int count;         /* number of bitmaps successfully processed, this file */
01083   potrace_state_t *st;
01084   simple_progress_t progress_data;
01085 
01086   for (count=0; ; count++) {
01087     /* read a bitmap */
01088     r = bm_read(fin, info.blacklevel, &bm);
01089     switch (r) {
01090     case -1:  /* system error */
01091       fprintf(stderr, ""POTRACE": %s: %s\n", infile, strerror(errno));
01092       exit(2);
01093     case -2:  /* corrupt file format */
01094       fprintf(stderr, ""POTRACE": %s: file format error: %s\n", infile, bm_read_error);
01095       exit(2);
01096     case -3:  /* empty file */
01097       if (count>0) {  /* end of file */
01098         return;
01099       }
01100       fprintf(stderr, ""POTRACE": %s: empty file\n", infile);
01101       exit(2);
01102     case -4:  /* wrong magic */
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:  /* unexpected end of file */
01111       fprintf(stderr, ""POTRACE": warning: %s: premature end of file\n", infile);
01112       eof_flag = 1;
01113       break;
01114     }
01115 
01116     /* prepare progress bar, if requested */
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     /* process the image */
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     /* calculate image dimensions */
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   /* not reached */
01158 }
01159 
01160 /* ---------------------------------------------------------------------- */
01161 /* main: handle file i/o */
01162 
01163 #define TRY(x) if (x) goto try_error
01164 
01165 int main(int ac, char *av[]) {
01166   backend_t *b;  /* backend info */
01167   FILE *fin, *fout;
01168   int i;
01169   char *outfile;
01170 
01171   /* platform-specific initializations, e.g., set file i/o to binary */
01172   platform_init();
01173 
01174   /* process options */
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   /* fix some parameters */
01184   /* if backend cannot handle opticurve, disable it */
01185   if (b->opticurve == 0) {
01186     info.param->opticurve = 0;
01187   }
01188 
01189   /* there are several ways to call us:
01190      potrace                     -- stdin to stdout
01191      potrace -o outfile          -- stdin to outfile
01192      potrace file...             -- encode each file and generate outfile names
01193      potrace -o outfile file...  -- concatenate files and write to outfile
01194 
01195      The latter form is only allowed one file for single-page
01196      backends.  For multi-page backends, each file must contain 0 or
01197      more complete bitmaps.
01198   */
01199 
01200   if (info.infilecount == 0) {                 /* read from stdin */
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) {                /* infiles -> multiple outfiles */
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 {                                   /* infiles to outfile */
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   /* not reached */
01281 
01282  try_error:
01283   fprintf(stderr, ""POTRACE": %s\n", strerror(errno));
01284   exit(2);
01285 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines


portrait_painter
Author(s): Niklas Meinzer, Ina Baumgarten
autogenerated on Wed Dec 26 2012 16:00:43