Statistics
| Revision:

gvsig-raster / libjni-potrace / trunk / libjni-potrace / resources / potrace-1.8 / src / main.c @ 1780

History | View | Annotate | Download (38.3 KB)

1
/* Copyright (C) 2001-2007 Peter Selinger.
2
   This file is part of Potrace. It is free software and it is covered
3
   by the GNU General Public License. See the file COPYING for details. */
4

    
5
/* $Id: main.c 147 2007-04-09 00:44:09Z selinger $ */
6

    
7
#include <stdio.h>
8
#include <stdlib.h>
9
#include <errno.h>
10
#include <string.h>
11
#include <getopt.h>
12
#include <math.h>
13

    
14
#include "main.h"
15
#include "potracelib.h"
16
#include "backend_pdf.h"
17
#include "backend_eps.h"
18
#include "backend_pgm.h"
19
#include "backend_svg.h"
20
#include "backend_gimp.h"
21
#include "backend_xfig.h"
22
#include "potracelib.h"
23
#include "bitmap_io.h"
24
#include "bitmap.h"
25
#include "platform.h"
26
#include "auxiliary.h"
27

    
28
#ifdef HAVE_CONFIG_H
29
#include "config.h"
30
#endif
31

    
32
#ifndef M_PI
33
#define M_PI 3.14159265358979323846
34
#endif
35

    
36
#define UNDEF ((double)(1e30))   /* a value to represent "undefined" */
37
#define INFTY ((double)(1e30))   /* a value to represent +infinity */
38

    
39
struct info_s info;
40

    
41
#define COL0 "\033[G"  /* reset cursor to column 0 */
42

    
43
/* ---------------------------------------------------------------------- */
44
/* callback function for progress bar */
45

    
46
struct simple_progress_s {
47
  char name[22];          /* filename for status bar */
48
  double dnext;           /* threshold value for next tick */
49
};
50
typedef struct simple_progress_s simple_progress_t;
51

    
52
/* print a simple progress bar. This is a callback function that is
53
   potentially called often; thus, it has been optimized for the
54
   typical case, which is when the progress bar does not need updating. */
55
static void simple_progress(double d, void *data) {
56
  simple_progress_t *p = (simple_progress_t *)data;
57
  static char b[] = "========================================";
58
  int tick;    /* number of visible tickmarks, 0..40 */
59
  int perc;    /* visible percentage, 0..100 */
60

    
61
  /* note: the 0.01 and 0.025 ensure that we always end on 40
62
     tickmarks and 100%, despite any rounding errors. The 0.995
63
     ensures that tick always increases when d >= p->dnext. */
64
  if (d >= p->dnext) {
65
    tick = (int) floor(d*40+0.01);
66
    perc = (int) floor(d*100+0.025);
67
    fprintf(stderr, "%-21s |%-40s| %d%% "COL0"", p->name, b+40-tick, perc);
68
    p->dnext = (tick+0.995) / 40.0;
69
  }
70
}
71

    
72
/* Initialize parameters for simple progress bar. The caller passes an
73
   allocated simple_progress_t structure to avoid having to malloc it
74
   here and free it later. */
75
static inline void init_progress(potrace_progress_t *prog, simple_progress_t *p, const char *filename, int count) {
76
  const char *q, *s;
77
  int len;
78

    
79
  /* initialize callback function's data */
80
  p->dnext = 0;
81

    
82
  if (count != 0) {
83
    sprintf(p->name, " (p.%d):", count+1);
84
  } else {
85
    s = filename;
86
    if ((q = strrchr(s, '/')) != NULL) {
87
      s = q+1;
88
    }
89
    len = strlen(s);
90
    strncpy(p->name, s, 21);
91
    p->name[20] = 0;
92
    if (len > 20) {
93
      p->name[17] = '.';
94
      p->name[18] = '.';
95
      p->name[19] = '.';
96
    }
97
    strcat(p->name, ":");
98
  }
99

    
100
  /* initialize progress parameters */
101
  prog->callback = &simple_progress;
102
  prog->data = (void *)p;
103
  prog->min = 0.0;
104
  prog->max = 1.0;
105
  prog->epsilon = 0.0;
106
  
107
  /* draw first progress bar */
108
  simple_progress(0.0, prog->data);
109
  return;
110
}
111

    
112
/* ---------------------------------------------------------------------- */
113
/* some data structures for option processing */
114

    
115
struct pageformat_s {
116
  char *name;
117
  int w, h;
118
};
119
typedef struct pageformat_s pageformat_t;
120

    
121
/* dimensions of the various page formats, in postscript points */
122
static pageformat_t pageformat[] = {
123
  { "a4",        595,  842 },
124
  { "a3",        842, 1191 },
125
  { "a5",        421,  595 },
126
  { "b5",        516,  729 },
127
  { "letter",    612,  792 },
128
  { "legal",     612, 1008 },
129
  { "tabloid",   792, 1224 },
130
  { "statement", 396,  612 },
131
  { "executive", 540,  720 },
132
  { "folio",     612,  936 },
133
  { "quarto",    610,  780 },
134
  { "10x14",     720, 1008 },
135
  { NULL, 0, 0 },
136
};
137

    
138
struct turnpolicy_s {
139
  char *name;
140
  int n;
141
};
142
typedef struct turnpolicy_s turnpolicy_t;
143

    
144
/* names of turn policies */
145
static turnpolicy_t turnpolicy[] = {
146
  {"black",    POTRACE_TURNPOLICY_BLACK},
147
  {"white",    POTRACE_TURNPOLICY_WHITE},
148
  {"left",     POTRACE_TURNPOLICY_LEFT},
149
  {"right",    POTRACE_TURNPOLICY_RIGHT},
150
  {"minority", POTRACE_TURNPOLICY_MINORITY},
151
  {"majority", POTRACE_TURNPOLICY_MAJORITY},
152
  {"random",   POTRACE_TURNPOLICY_RANDOM},
153
  {NULL, 0},
154
};
155

    
156
/* backends and their characteristics */
157
struct backend_s {
158
  char *name;       /* name of this backend */
159
  char *ext;        /* file extension */
160
  int fixed;        /* fixed page size backend? */
161
  int pixel;        /* pixel-based backend? */
162
  int multi;        /* multi-page backend? */
163
  int (*init_f)(FILE *fout);                 /* initialization function */
164
  int (*page_f)(FILE *fout, potrace_path_t *plist, imginfo_t *imginfo);
165
                                             /* per-bitmap function */
166
  int (*term_f)(FILE *fout);                 /* finalization function */
167
  int opticurve;    /* opticurve capable (true Bezier curves?) */
168
};
169
typedef struct backend_s backend_t;  
170

    
171
static backend_t backend[] = {
172
  {"eps",        ".eps",      0, 0, 0, NULL,    page_eps,   NULL,     1},
173
  {"postscript", ".ps",       1, 0, 1, init_ps, page_ps,    term_ps,  1},
174
  {"ps",         ".ps",       1, 0, 1, init_ps, page_ps,    term_ps,  1},
175
  {"pdf",        ".pdf",      0, 0, 1, init_pdf,page_pdf,   term_pdf, 1},
176
  {"svg",        ".svg",      0, 0, 0, NULL,    page_svg,   NULL,     1},
177
  {"pgm",        ".pgm",      0, 1, 1, NULL,    page_pgm,   NULL,     1},
178
  {"gimppath",   ".gimppath", 0, 1, 0, NULL,    page_gimp,  NULL,     1},
179
  {"xfig",       ".fig",      1, 0, 0, NULL,    page_xfig,  NULL,     0},
180
  {NULL, NULL, 0, 0, 0, NULL, NULL, NULL},
181
};
182

    
183
/* look up a backend by name. If found, return 0 and set *bp. If not
184
   found leave *bp unchanged and return 1, or 2 on ambiguous
185
   prefix. */
186
static int backend_lookup(char *name, backend_t **bp) {
187
  int i;
188
  int m=0;  /* prefix matches */
189
  backend_t *b = NULL;
190

    
191
  for (i=0; backend[i].name; i++) {
192
    if (strcasecmp(backend[i].name, name)==0) {
193
      *bp = &backend[i];
194
      return 0;
195
    } else if (strncasecmp(backend[i].name, name, strlen(name))==0) {
196
      m++;
197
      b = &backend[i];
198
    }      
199
  }
200
  /* if there was no exact match, and exactly one prefix match, use that */
201
  if (m==1) {  
202
    *bp = b;
203
    return 0;
204
  } else if (m) {
205
    return 2;
206
  } else {
207
    return 1;
208
  }
209
}
210

    
211
/* list all available backends by name, in a comma separated list.
212
   Assume the cursor starts in column j, and break lines at length
213
   linelen. Do not output any trailing punctuation. Return the column
214
   the cursor is in. */
215
static int backend_list(FILE *fout, int j, int linelen) {
216
  int i;
217

    
218
  for (i=0; backend[i].name; i++) {
219
    if (j + (int)strlen(backend[i].name) > linelen) {
220
      fprintf(fout, "\n");
221
      j = 0;
222
    }
223
    j += fprintf(fout, "%s", backend[i].name);
224
    if (backend[i+1].name) {
225
      j += fprintf(fout, ", ");
226
    }
227
  }
228
  return j;
229
}
230

    
231
/* ---------------------------------------------------------------------- */
232
/* some info functions */
233

    
234
static void license(FILE *f) {
235
  fprintf(f, 
236
  "This program is free software; you can redistribute it and/or modify\n"
237
  "it under the terms of the GNU General Public License as published by\n"
238
  "the Free Software Foundation; either version 2 of the License, or\n"
239
  "(at your option) any later version.\n"
240
  "\n"
241
  "This program is distributed in the hope that it will be useful,\n"
242
  "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
243
  "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
244
  "GNU General Public License for more details.\n"
245
  "\n"
246
  "You should have received a copy of the GNU General Public License\n"
247
  "along with this program; if not, write to the Free Software\n"
248
  "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.\n"
249
          );
250
}
251

    
252
static void show_defaults(FILE *f) {
253
  fprintf(f, "This version of Potrace was compiled with the following defaults:\n");
254
  fprintf(f, "Default unit: "DEFAULT_DIM_NAME"\n");
255
  fprintf(f, "Default page size: "DEFAULT_PAPERFORMAT"\n");
256
}
257

    
258
static void usage(FILE *f) {
259
  int j;
260

    
261
  fprintf(f, "Usage: "POTRACE" [options] [file...]\n");
262
  fprintf(f, "General options:\n");
263
  fprintf(f, " -h, --help                 - print this help message and exit\n");
264
  fprintf(f, " -v, --version              - print version info and exit\n");
265
  fprintf(f, " -l, --license              - print license info and exit\n");
266
  fprintf(f, " -V, --show-defaults        - print compiled-in defaults and exit\n");
267
  fprintf(f, " --progress                 - show progress bar\n");
268
  fprintf(f, "Input/output options:\n");
269
  fprintf(f, " -o, --output <file>        - output to file\n");
270
  fprintf(f, "Backend selection:\n");
271
  fprintf(f, " -e, --eps                  - EPS backend (encapsulated postscript) (default)\n");
272
  fprintf(f, " -p, --postscript           - Postscript backend\n");
273
  fprintf(f, " -s, --svg                  - SVG backend (scalable vector graphics)\n");
274
  fprintf(f, " -g, --pgm                  - PGM backend (portable greymap)\n");
275
  fprintf(f, " -b, --backend <name>       - select backend by name\n");
276
  fprintf(f, "Algorithm options:\n");
277
  fprintf(f, " -z, --turnpolicy <policy>  - how to resolve ambiguities in path decomposition\n");
278
  fprintf(f, " -t, --turdsize <n>         - suppress speckles of up to this size (default 2)\n");
279
  fprintf(f, " -a, --alphamax <n>         - corner threshold parameter (default 1)\n");
280
  fprintf(f, " -n, --longcurve            - turn off curve optimization\n");
281
  fprintf(f, " -O, --opttolerance <n>     - curve optimization tolerance (default 0.2)\n");
282
  fprintf(f, " -u, --unit <n>             - quantize output to 1/unit pixels (default 10)\n");
283
  fprintf(f, " -d, --debug <n>            - produce debugging output of type n (n=1,2,3)\n");
284
  fprintf(f, "Scaling and placement options:\n");
285
  fprintf(f, " -W, --width <dim>          - width of output image\n");
286
  fprintf(f, " -H, --height <dim>         - height of output image\n");
287
  fprintf(f, " -r, --resolution <n>[x<n>] - resolution (in dpi)\n");
288
  fprintf(f, " -x, --scale <n>[x<n>]      - scaling factor (pgm backend)\n");
289
  fprintf(f, " -S, --stretch <n>          - yresolution/xresolution\n");
290
  fprintf(f, " -A, --rotate <angle>       - rotate counterclockwise by angle\n");
291
  fprintf(f, " -M, --margin <dim>         - margin\n");
292
  fprintf(f, " -L, --leftmargin <dim>     - left margin\n");
293
  fprintf(f, " -R, --rightmargin <dim>    - right margin\n");
294
  fprintf(f, " -T, --topmargin <dim>      - top margin\n");
295
  fprintf(f, " -B, --bottommargin <dim>   - bottom margin\n");
296
  fprintf(f, "Output options, supported by some backends:\n");
297
  fprintf(f, " -C, --color #rrggbb        - set line color (default black)\n");
298
  fprintf(f, " --fillcolor #rrggbb        - set fill color (default transparent)\n");
299
  fprintf(f, " --opaque                   - make white shapes opaque\n");
300
  fprintf(f, " --group                    - group related paths together\n");
301
  fprintf(f, "Postscript/EPS options:\n");
302
  fprintf(f, " -P, --pagesize <format>    - page size (default is "DEFAULT_PAPERFORMAT")\n");
303
  fprintf(f, " -c, --cleartext            - do not compress the output\n");
304
  fprintf(f, " -2, --level2               - use postscript level 2 compression (default)\n");
305
#ifdef HAVE_ZLIB
306
  fprintf(f, " -3, --level3               - use postscript level 3 compression\n");
307
#endif
308
  fprintf(f, " -q, --longcoding           - do not optimize for file size\n");
309
  fprintf(f, "PGM options:\n");
310
  fprintf(f, " -G, --gamma <n>            - gamma value for anti-aliasing (default 2.2)\n");
311
  fprintf(f, "Frontend options:\n");
312
  fprintf(f, " -k, --blacklevel <n>       - black/white cutoff in input file (default 0.5)\n");
313
  fprintf(f, " -i, --invert               - invert bitmap\n");
314
  fprintf(f, "\n");
315
  fprintf(f, "Dimensions can have optional units, e.g. 6.5in, 15cm, 100pt.\n");
316
  fprintf(f, "Default is "DEFAULT_DIM_NAME" (or pixels for pgm and gimppath backends).\n");
317
  fprintf(f, "Possible input file formats are: pnm (pbm, pgm, ppm), bmp.\n");
318
  j = fprintf(f, "Backends are: ");
319
  backend_list(f, j, 70);
320
  fprintf(f, ".\n");
321
}
322

    
323
/* ---------------------------------------------------------------------- */
324
/* auxiliary functions for parameter parsing */
325

    
326
/* parse a dimension of the kind "1.5in", "7cm", etc. Return result in
327
   postscript points (=1/72 in). If endptr!=NULL, store pointer to
328
   next character in *endptr in the manner of strtod(3). */
329
static dim_t parse_dimension(char *s, char **endptr) {
330
  char *p;
331
  dim_t res;
332

    
333
  res.x = strtod(s, &p);
334
  res.d = 0;
335
  if (p!=s) {
336
    if (!strncasecmp(p, "in", 2)) {
337
      res.d = DIM_IN;
338
      p += 2;
339
    } else if (!strncasecmp(p, "cm", 2)) {
340
      res.d = DIM_CM;
341
      p += 2;
342
    } else if (!strncasecmp(p, "mm", 2)) {
343
      res.d = DIM_MM;
344
      p += 2;
345
    } else if (!strncasecmp(p, "pt", 2)) {
346
      res.d = DIM_PT;
347
      p += 2;
348
    }
349
  }
350
  if (endptr!=NULL) {
351
    *endptr = p;
352
  }
353
  return res;
354
}
355

    
356
/* parse a pair of dimensions, such as "8.5x11in", "30mmx4cm" */
357
static void parse_dimensions(char *s, char **endptr, dim_t *dxp, dim_t *dyp) {
358
  char *p, *q;
359
  dim_t dx, dy;
360

    
361
  dx = parse_dimension(s, &p);
362
  if (p==s) {
363
    goto fail;
364
  }
365
  if (*p != 'x') {
366
    goto fail;
367
  }
368
  p++;
369
  dy = parse_dimension(p, &q);
370
  if (q==p) {
371
    goto fail;
372
  }
373
  if (dx.d && !dy.d) {
374
    dy.d = dx.d;
375
  } else if (!dx.d && dy.d) {
376
    dx.d = dy.d;
377
  }
378
  *dxp = dx;
379
  *dyp = dy;
380
  if (endptr != NULL) {
381
    *endptr = q;
382
  }
383
  return;
384

    
385
 fail:
386
  dx.x = dx.d = dy.x = dy.d = 0;
387
  *dxp = dx;
388
  *dyp = dy;
389
  if (endptr != NULL) {
390
    *endptr = s;
391
  }
392
  return;
393
}
394

    
395
static inline double double_of_dim(dim_t d, double def) {
396
  if (d.d) {
397
    return d.x * d.d;
398
  } else {
399
    return d.x * def;
400
  }
401
}
402

    
403
static int parse_color(char *s) {
404
  int i, d;
405
  int col = 0;
406

    
407
  if (s[0] != '#' || strlen(s) != 7) {
408
    return -1;
409
  }
410
  for (i=0; i<6; i++) {
411
    d = s[6-i];
412
    if (d >= '0' && d <= '9') {
413
      col |= (d-'0') << (4*i);
414
    } else if (d >= 'a' && d <= 'f') {
415
      col |= (d-'a'+10) << (4*i);
416
    } else if (d >= 'A' && d <= 'F') {
417
      col |= (d-'A'+10) << (4*i);
418
    } else {
419
      return -1;
420
    }
421
  }
422
  return col;
423
}  
424

    
425
/* ---------------------------------------------------------------------- */
426
/* option processing */
427

    
428
/* codes for options that don't have short form */
429
#define OPT_GROUP     300
430
#define OPT_OPAQUE    301
431
#define OPT_FILLCOLOR 302
432
#define OPT_PROGRESS  303
433

    
434
static struct option longopts[] = {
435
  {"help",          0, 0, 'h'},
436
  {"version",       0, 0, 'v'},
437
  {"license",       0, 0, 'l'},
438
  {"show-defaults", 0, 0, 'V'},
439
  {"progress",      0, 0, OPT_PROGRESS},
440
  {"width",         1, 0, 'W'},
441
  {"height",        1, 0, 'H'},
442
  {"resolution",    1, 0, 'r'},
443
  {"scale",         1, 0, 'x'},
444
  {"stretch",       1, 0, 'S'},
445
  {"margin",        1, 0, 'M'},
446
  {"leftmargin",    1, 0, 'L'},
447
  {"rightmargin",   1, 0, 'R'},
448
  {"topmargin",     1, 0, 'T'},
449
  {"bottommargin",  1, 0, 'B'},
450
  {"rotate",        1, 0, 'A'},
451
  {"pagesize",      1, 0, 'P'},
452
  {"turdsize",      1, 0, 't'},
453
  {"unit",          1, 0, 'u'},
454
  {"cleartext",     0, 0, 'c'},
455
  {"level2",        0, 0, '2'},
456
  {"level3",        0, 0, '3'},
457
  {"eps",           0, 0, 'e'},
458
  {"postscript",    0, 0, 'p'},
459
  {"svg",           0, 0, 's'},
460
  {"pgm",           0, 0, 'g'},
461
  {"backend",       1, 0, 'b'},
462
  {"debug",         1, 0, 'd'},
463
  {"color",         1, 0, 'C'},
464
  {"fillcolor",     1, 0, OPT_FILLCOLOR},
465
  {"turnpolicy",    1, 0, 'z'},
466
  {"gamma",         1, 0, 'G'},
467
  {"longcurve",     0, 0, 'n'},
468
  {"longcoding",    0, 0, 'q'},
469
  {"alphamax",      1, 0, 'a'},
470
  {"opttolerance",  1, 0, 'O'},
471
  {"output",        1, 0, 'o'},
472
  {"blacklevel",    1, 0, 'k'},
473
  {"invert",        0, 0, 'i'},
474
  {"opaque",        0, 0, OPT_OPAQUE},
475
  {"group",         0, 0, OPT_GROUP},
476

    
477
  {0, 0, 0, 0}
478
};
479

    
480
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";
481

    
482
static void dopts(int ac, char *av[]) {
483
  int c;
484
  char *p;
485
  int i, j, r;
486
  dim_t dim, dimx, dimy;
487
  int matches, bestmatch;
488

    
489
  /* defaults */
490
  backend_lookup("eps", &info.backend);
491
  info.debug = 0;
492
  info.width_d.x = UNDEF;
493
  info.height_d.x = UNDEF;
494
  info.rx = UNDEF;
495
  info.ry = UNDEF;
496
  info.sx = UNDEF;
497
  info.sy = UNDEF;
498
  info.stretch = 1;
499
  info.lmar_d.x = UNDEF;
500
  info.rmar_d.x = UNDEF;
501
  info.tmar_d.x = UNDEF;
502
  info.bmar_d.x = UNDEF;
503
  info.angle = 0;
504
  info.paperwidth = DEFAULT_PAPERWIDTH;
505
  info.paperheight = DEFAULT_PAPERHEIGHT;
506
  info.unit = 10;
507
  info.compress = 1;
508
  info.pslevel = 2;
509
  info.color = 0x000000;
510
  info.gamma = 2.2;
511
  info.param = potrace_param_default();
512
  if (!info.param) {
513
    fprintf(stderr, ""POTRACE": %s\n", strerror(errno));
514
    exit(1);
515
  }
516
  info.longcoding = 0;
517
  info.outfile = NULL;
518
  info.blacklevel = 0.5;
519
  info.invert = 0;
520
  info.opaque = 0;
521
  info.group = 0;
522
  info.fillcolor = 0xffffff;
523
  info.progress = 0;
524

    
525
  while ((c = getopt_long(ac, av, shortopts, longopts, NULL)) != -1) {
526
    switch (c) {
527
    case 'h':
528
      fprintf(stdout, ""POTRACE" "VERSION". Transforms bitmaps into vector graphics.\n\n");
529
      usage(stdout);
530
      exit(0);
531
      break;
532
    case 'v':
533
      fprintf(stdout, ""POTRACE" "VERSION". Copyright (C) 2001-2007 Peter Selinger.\n");
534
      fprintf(stdout, "Library version: %s\n", potrace_version());
535
      exit(0);
536
      break;
537
    case 'l':
538
      fprintf(stdout, ""POTRACE" "VERSION". Copyright (C) 2001-2007 Peter Selinger.\n\n");
539
      license(stdout);
540
      exit(0);
541
      break;
542
    case 'V':
543
      fprintf(stdout, ""POTRACE" "VERSION". Copyright (C) 2001-2007 Peter Selinger.\n");
544
      show_defaults(stdout);
545
      exit(0);
546
      break;
547
    case OPT_PROGRESS:
548
      info.progress = 1;
549
      break;
550
    case 'W':
551
      info.width_d = parse_dimension(optarg, &p);
552
      if (*p) {
553
        fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg);
554
        exit(1);
555
      }
556
      break;
557
    case 'H':
558
      info.height_d = parse_dimension(optarg, &p);
559
      if (*p) {
560
        fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg);
561
        exit(1);
562
      }
563
      break;
564
    case 'r':
565
      parse_dimensions(optarg, &p, &dimx, &dimy);
566
      if (*p == 0 && dimx.d == 0 && dimy.d == 0) {
567
        info.rx = dimx.x;
568
        info.ry = dimy.x;
569
        break;
570
      }
571
      dim = parse_dimension(optarg, &p);
572
      if (*p == 0 && dim.d == 0) {
573
        info.rx = info.ry = dim.x;
574
        break;
575
      }
576
      fprintf(stderr, ""POTRACE": invalid resolution -- %s\n", optarg);
577
      exit(1);
578
      break;
579
    case 'x':
580
      parse_dimensions(optarg, &p, &dimx, &dimy);
581
      if (*p == 0 && dimx.d == 0 && dimy.d == 0) {
582
        info.sx = dimx.x;
583
        info.sy = dimy.x;
584
        break;
585
      }
586
      dim = parse_dimension(optarg, &p);
587
      if (*p == 0 && dim.d == 0) {
588
        info.sx = info.sy = dim.x;
589
        break;
590
      }
591
      fprintf(stderr, ""POTRACE": invalid scaling factor -- %s\n", optarg);
592
      exit(1);
593
      break;
594
    case 'S':
595
      info.stretch = atof(optarg);
596
      break;
597
    case 'M':
598
      info.lmar_d = parse_dimension(optarg, &p);
599
      if (*p) {
600
        fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg);
601
        exit(1);
602
      }
603
      info.rmar_d = info.tmar_d = info.bmar_d = info.lmar_d;
604
      break;
605
    case 'L':
606
      info.lmar_d = parse_dimension(optarg, &p);
607
      if (*p) {
608
        fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg);
609
        exit(1);
610
      }
611
      break;
612
    case 'R':
613
      info.rmar_d = parse_dimension(optarg, &p);
614
      if (*p) {
615
        fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg);
616
        exit(1);
617
      }
618
      break;
619
    case 'T':
620
      info.tmar_d = parse_dimension(optarg, &p);
621
      if (*p) {
622
        fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg);
623
        exit(1);
624
      }
625
      break;
626
    case 'B':
627
      info.bmar_d = parse_dimension(optarg, &p);
628
      if (*p) {
629
        fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg);
630
        exit(1);
631
      }
632
      break;
633
    case 'A':
634
      info.angle = strtod(optarg, &p);
635
      if (*p) {
636
        fprintf(stderr, ""POTRACE": invalid angle -- %s\n", optarg);
637
        exit(1);
638
      }
639
      break;
640
    case 'P':
641
      matches = 0;
642
      bestmatch = 0;
643
      for (i=0; pageformat[i].name!=NULL; i++) {
644
        if (strcasecmp(pageformat[i].name, optarg)==0) {
645
          matches = 1;
646
          bestmatch = i;
647
          break;
648
        } else if (strncasecmp(pageformat[i].name, optarg, strlen(optarg))==0) {
649
          /* don't allow partial match on "10x14" */
650
          if (optarg[0] != '1') {
651
            matches++;
652
            bestmatch = i;
653
          }
654
        }
655
      }
656
      if (matches == 1) {
657
        info.paperwidth = pageformat[bestmatch].w;
658
        info.paperheight = pageformat[bestmatch].h;
659
        break;
660
      }
661
      parse_dimensions(optarg, &p, &dimx, &dimy);
662
      if (*p == 0) {
663
        info.paperwidth = (int)rint(double_of_dim(dimx, DEFAULT_DIM));
664
        info.paperheight = (int)rint(double_of_dim(dimy, DEFAULT_DIM));
665
        break;
666
      }
667
      if (matches == 0) {
668
        fprintf(stderr, ""POTRACE": unrecognized page format -- %s\n", optarg);
669
      } else {
670
        fprintf(stderr, ""POTRACE": ambiguous page format -- %s\n", optarg);
671
      }
672
      j = fprintf(stderr, "Use one of: ");
673
      for (i=0; pageformat[i].name!=NULL; i++) {
674
        if (j + strlen(pageformat[i].name) > 75) {
675
          fprintf(stderr, "\n");
676
          j = 0;
677
        }
678
        j += fprintf(stderr, "%s, ", pageformat[i].name);
679
      }
680
      fprintf(stderr, "or specify <dim>x<dim>.\n");
681
      exit(1);
682
      break;
683
    case 't':
684
      info.param->turdsize = atoi(optarg);
685
      break;
686
    case 'u':
687
      info.unit = strtod(optarg, &p);
688
      if (*p) {
689
        fprintf(stderr, ""POTRACE": invalid unit -- %s\n", optarg);
690
        exit(1);
691
      }
692
      break;
693
    case 'c':
694
      info.pslevel = 2;
695
      info.compress = 0;
696
      break;
697
    case '2':
698
      info.pslevel = 2;
699
      info.compress = 1;
700
      break;
701
    case '3':
702
#ifdef HAVE_ZLIB
703
      info.pslevel = 3;
704
      info.compress = 1;
705
#else
706
      fprintf(stderr, ""POTRACE": option -3 not supported, using -2 instead.\n");
707
      info.pslevel = 2;
708
      info.compress = 1;
709
#endif
710
      break;
711
    case 'e':
712
      backend_lookup("eps", &info.backend);
713
      break;
714
    case 'p':
715
      backend_lookup("postscript", &info.backend);
716
      break;
717
    case 's':
718
      backend_lookup("svg", &info.backend);
719
      break;
720
    case 'g':
721
      backend_lookup("pgm", &info.backend);
722
      break;
723
    case 'b':
724
      r = backend_lookup(optarg, &info.backend);
725
      if (r==1 || r==2) {
726
        if (r==1) {
727
          fprintf(stderr, ""POTRACE": unrecognized backend -- %s\n", optarg);
728
        } else {
729
          fprintf(stderr, ""POTRACE": ambiguous backend -- %s\n", optarg);
730
        }
731
        j = fprintf(stderr, "Use one of: ");
732
        backend_list(stderr, j, 70);
733
        fprintf(stderr, ".\n");
734
        exit(1);
735
      }
736
      break;
737
    case 'd':
738
      info.debug = atoi(optarg);
739
      break;
740
    case 'C':
741
      info.color = parse_color(optarg);
742
      if (info.color == -1) {
743
        fprintf(stderr, ""POTRACE": invalid color -- %s\n", optarg);
744
        exit(1);
745
      }
746
      break;
747
    case OPT_FILLCOLOR:
748
      info.fillcolor = parse_color(optarg);
749
      if (info.fillcolor == -1) {
750
        fprintf(stderr, ""POTRACE": invalid color -- %s\n", optarg);
751
        exit(1);
752
      }
753
      info.opaque = 1;
754
      break;
755
    case 'z':
756
      matches = 0;
757
      bestmatch = 0;
758
      for (i=0; turnpolicy[i].name!=NULL; i++) {
759
        if (strcasecmp(turnpolicy[i].name, optarg)==0) {
760
          matches = 1;
761
          bestmatch = i;
762
          break;
763
        } else if (strncasecmp(turnpolicy[i].name, optarg, strlen(optarg))==0) {
764
          matches++;
765
          bestmatch = i;
766
        }
767
      }
768
      if (matches == 1) {
769
        info.param->turnpolicy = turnpolicy[bestmatch].n;
770
        break;
771
      }
772
      if (matches == 0) {
773
        fprintf(stderr, ""POTRACE": unrecognized turnpolicy -- %s\n", optarg);
774
      } else {
775
        fprintf(stderr, ""POTRACE": ambiguous turnpolicy -- %s\n", optarg);
776
      }
777
      j = fprintf(stderr, "Use one of: ");
778
      for (i=0; turnpolicy[i].name!=NULL; i++) {
779
        if (j + strlen(turnpolicy[i].name) > 75) {
780
          fprintf(stderr, "\n");
781
          j = 0;
782
        }
783
        j += fprintf(stderr, "%s%s", turnpolicy[i].name, turnpolicy[i+1].name ? ", " : "");
784
      }
785
      fprintf(stderr, ".\n");
786
      exit(1);
787
      break;
788
    case 'G':
789
      info.gamma = atof(optarg);
790
      break;
791
    case 'n':
792
      info.param->opticurve = 0;
793
      break;
794
    case 'q':
795
      info.longcoding = 1;
796
      break;
797
    case 'a':
798
      info.param->alphamax = strtod(optarg, &p);
799
      if (*p) {
800
        fprintf(stderr, ""POTRACE": invalid alphamax -- %s\n", optarg);
801
        exit(1);
802
      }
803
      break;
804
    case 'O':
805
      info.param->opttolerance = strtod(optarg, &p);
806
      if (*p) {
807
        fprintf(stderr, ""POTRACE": invalid opttolerance -- %s\n", optarg);
808
        exit(1);
809
      }
810
      break;
811
    case 'o':
812
      free(info.outfile);
813
      info.outfile = strdup(optarg);
814
      break;
815
    case 'k':
816
      info.blacklevel = strtod(optarg, &p);
817
      if (*p) {
818
        fprintf(stderr, ""POTRACE": invalid blacklevel -- %s\n", optarg);
819
        exit(1);
820
      }
821
      break;
822
    case 'i':
823
      info.invert = 1;
824
      break;
825
    case OPT_OPAQUE:
826
      info.opaque = 1;
827
      break;
828
    case OPT_GROUP:
829
      info.group = 1;
830
      break;
831
    case '?':
832
      fprintf(stderr, "Try --help for more info\n");
833
      exit(1);
834
      break;
835
    default:
836
      fprintf(stderr, ""POTRACE": Unimplemented option -- %c\n", c);
837
      exit(1);
838
    }
839
  }
840
  info.infiles = &av[optind];
841
  info.infilecount = ac-optind;
842
}
843

    
844
/* ---------------------------------------------------------------------- */
845
/* calculations with bitmap dimensions, positioning etc */
846

    
847
/* consider a rectangle spanned by the vectors (w,0) and (0,h). Rotate
848
   it counterclockwise by angle alpha. Then set the rect_t structure
849
   to the resulting rectangle, setting its bounding box, origin,
850
   x-basis and y-basis. */
851

    
852
static void rotate_dim(double alpha, double w, double h, rect_t *r) { 
853
  double s, c, x0, x1, y0, y1;
854

    
855
  s = sin(alpha/180*M_PI);
856
  c = cos(alpha/180*M_PI);
857

    
858
  /* apply the transformation matrix to the basis vectors */
859
  x0 = c*w;
860
  x1 = s*w;
861
  y0 = -s*h;
862
  y1 = c*h;
863

    
864
  /* determine bounding box and origin relative to bounding box */
865
  r->bb[0] = fabs(x0) + fabs(y0);
866
  r->bb[1] = fabs(x1) + fabs(y1);
867
  r->orig[0] = - min(x0,0) - min(y0,0);
868
  r->orig[1] = - min(x1,0) - min(y1,0);
869
}
870
  
871
/* determine the dimensions of the output based on command line and
872
   image dimensions */
873
static void calc_dimensions(imginfo_t *imginfo) {
874
  double dim_def;
875
  double maxwidth, maxheight, sc;
876
  rect_t r;
877

    
878
  /* we take care of a special case: if one of the image dimensions is
879
     0, we change it to 1. Such an image is empty anyway, so there
880
     will be 0 paths in it. Changing the dimensions avoids division by
881
     0 error in calculating scaling factors, bounding boxes and
882
     such. This doesn't quite do the right thing in all cases, but it
883
     is better than causing overflow errors or "nan" output in
884
     backends.  Human users don't tend to process images of size 0
885
     anyway; they might occur in some pipelines. */
886
  if (imginfo->pixwidth == 0) {
887
    imginfo->pixwidth = 1;
888
  }
889
  if (imginfo->pixheight == 0) {
890
    imginfo->pixheight = 1;
891
  }
892

    
893
  /* set the default dimension for width, height, margins */
894
  if (info.backend->pixel) {
895
    dim_def = DIM_PT;
896
  } else {
897
    dim_def = DEFAULT_DIM;
898
  }
899

    
900
  /* apply default dimension to width, height, margins */
901
  imginfo->width = info.width_d.x == UNDEF ? UNDEF : double_of_dim(info.width_d, dim_def);
902
  imginfo->height = info.height_d.x == UNDEF ? UNDEF : double_of_dim(info.height_d, dim_def);
903
  imginfo->lmar = info.lmar_d.x == UNDEF ? UNDEF : double_of_dim(info.lmar_d, dim_def);
904
  imginfo->rmar = info.rmar_d.x == UNDEF ? UNDEF : double_of_dim(info.rmar_d, dim_def);
905
  imginfo->tmar = info.tmar_d.x == UNDEF ? UNDEF : double_of_dim(info.tmar_d, dim_def);
906
  imginfo->bmar = info.bmar_d.x == UNDEF ? UNDEF : double_of_dim(info.bmar_d, dim_def);
907

    
908
  /* determine width and height from desired resolution / scaling
909
     factor, if given */
910
  if (info.backend->pixel) {
911
    if (imginfo->width == UNDEF && info.sx != UNDEF) {
912
      imginfo->width = imginfo->pixwidth * info.sx;
913
    }
914
    if (imginfo->height == UNDEF && info.sy != UNDEF) {
915
      imginfo->height = imginfo->pixheight * info.sy;
916
    }
917
  } else {
918
    if (imginfo->width == UNDEF && info.rx != UNDEF) {
919
      imginfo->width = imginfo->pixwidth / info.rx * 72;
920
    }
921
    if (imginfo->height == UNDEF && info.ry != UNDEF) {
922
      imginfo->height = imginfo->pixheight / info.ry * 72;
923
    }
924
  }
925

    
926
  /* if one of width/height is specified, determine the other */
927
  if (imginfo->width == UNDEF && imginfo->height != UNDEF) {
928
    imginfo->width = imginfo->height / imginfo->pixheight * imginfo->pixwidth / info.stretch;
929
  } else if (imginfo->width != UNDEF && imginfo->height == UNDEF) {
930
    imginfo->height = imginfo->width / imginfo->pixwidth * imginfo->pixheight * info.stretch;
931
  }
932

    
933
  /* if width and height are still variable, figure them out */
934
  if (imginfo->width == UNDEF && imginfo->height == UNDEF) {
935
   
936
    if (info.backend->fixed) {
937

    
938
      /* in fixed-size backends, try to squeeze it between margins */
939
      maxwidth = UNDEF;
940
      maxheight = UNDEF;
941
      
942
      if (imginfo->lmar != UNDEF && imginfo->rmar != UNDEF) {
943
        maxwidth = info.paperwidth - imginfo->lmar - imginfo->rmar;
944
      } 
945
      if (imginfo->bmar != UNDEF && imginfo->tmar != UNDEF) {
946
        maxheight = info.paperheight - imginfo->bmar - imginfo->tmar;
947
      }
948
      if (maxwidth == UNDEF && maxheight == UNDEF) {
949
        maxwidth = max(info.paperwidth - 144, info.paperwidth * 0.75);
950
        maxheight = max(info.paperheight - 144, info.paperheight * 0.75);
951
      }
952
      
953
      rotate_dim(info.angle, imginfo->pixwidth, imginfo->pixheight * info.stretch, &r);
954
      
955
      sc = min(maxwidth == UNDEF ? INFTY : maxwidth / r.bb[0], maxheight == UNDEF ? INFTY : maxheight / r.bb[1]);
956
      imginfo->width = imginfo->pixwidth * sc;
957
      imginfo->height = imginfo->pixheight * info.stretch * sc;
958

    
959
    } else if (info.backend->pixel) {
960

    
961
      /* in pixel-based backends, assume default scaling factor of 1 */
962

    
963
      imginfo->width = imginfo->pixwidth;
964
      imginfo->height = imginfo->pixheight * info.stretch;
965
    } else {
966

    
967
      /* otherwise, choose a default size based on the default paper format */
968

    
969
      maxwidth = max(info.paperwidth - 144, info.paperwidth * 0.75);
970
      maxheight = max(info.paperheight - 144, info.paperheight * 0.75);
971
      
972
      sc = min(maxwidth / imginfo->pixwidth, maxheight / imginfo->pixheight / info.stretch);
973
      imginfo->width = imginfo->pixwidth * sc;
974
      imginfo->height = imginfo->pixheight * info.stretch * sc;
975
    }
976
  }
977

    
978
  /* calculate coordinate system */
979
  rotate_dim(info.angle, imginfo->width, imginfo->height, &imginfo->trans);
980

    
981
  /* adjust margins */
982
  if (info.backend->fixed) {
983
    if (imginfo->lmar == UNDEF && imginfo->rmar == UNDEF) {
984
      imginfo->lmar = (info.paperwidth-imginfo->trans.bb[0])/2;
985
    } else if (imginfo->lmar == UNDEF) {
986
      imginfo->lmar = (info.paperwidth-imginfo->trans.bb[0]-imginfo->rmar);
987
    } else if (imginfo->lmar != UNDEF && imginfo->rmar != UNDEF) {
988
      imginfo->lmar += (info.paperwidth-imginfo->trans.bb[0]-imginfo->lmar-imginfo->rmar)/2;
989
    }
990
    if (imginfo->bmar == UNDEF && imginfo->tmar == UNDEF) {
991
      imginfo->bmar = (info.paperheight-imginfo->trans.bb[1])/2;
992
    } else if (imginfo->bmar == UNDEF) {
993
      imginfo->bmar = (info.paperheight-imginfo->trans.bb[1]-imginfo->tmar);
994
    } else if (imginfo->bmar != UNDEF && imginfo->tmar != UNDEF) {
995
      imginfo->bmar += (info.paperheight-imginfo->trans.bb[1]-imginfo->bmar-imginfo->tmar)/2;
996
    }
997
  } else {
998
    if (imginfo->lmar == UNDEF) {
999
      imginfo->lmar = 0;
1000
    }
1001
    if (imginfo->rmar == UNDEF) {
1002
      imginfo->rmar = 0;
1003
    }
1004
    if (imginfo->bmar == UNDEF) {
1005
      imginfo->bmar = 0;
1006
    }
1007
    if (imginfo->tmar == UNDEF) {
1008
      imginfo->tmar = 0;
1009
    }
1010
  }
1011
}
1012

    
1013
/* ---------------------------------------------------------------------- */
1014
/* auxiliary functions for file handling */
1015

    
1016
/* open a file for reading. Return stdin if filename is NULL or "-" */ 
1017
static FILE *my_fopen_read(char *filename) {
1018
  if (filename == NULL || strcmp(filename, "-") == 0) {
1019
    return stdin;
1020
  }
1021
  return fopen(filename, "rb");
1022
}
1023

    
1024
/* open a file for writing. Return stdout if filename is NULL or "-" */ 
1025
static FILE *my_fopen_write(char *filename) {
1026
  if (filename == NULL || strcmp(filename, "-") == 0) {
1027
    return stdout;
1028
  }
1029
  return fopen(filename, "wb");
1030
}
1031

    
1032
/* close a file, but do nothing is filename is NULL or "-" */
1033
static void my_fclose(FILE *f, char *filename) {
1034
  if (filename == NULL || strcmp(filename, "-") == 0) {
1035
    return;
1036
  }
1037
  fclose(f);
1038
}
1039

    
1040
/* make output filename from input filename. Return an allocated value. */
1041
static char *make_outfilename(char *infile, char *ext) {
1042
  char *outfile;
1043
  char *p;
1044

    
1045
  if (strcmp(infile, "-") == 0) {
1046
    return strdup("-");
1047
  }
1048

    
1049
  outfile = (char *) malloc(strlen(infile)+strlen(ext)+5);
1050
  if (!outfile) {
1051
    return NULL;
1052
  }
1053
  strcpy(outfile, infile);
1054
  p = strrchr(outfile, '.');
1055
  if (p) {
1056
    *p = 0;
1057
  }
1058
  strcat(outfile, ext);
1059

    
1060
  /* check that input and output filenames are different */
1061
  if (strcmp(infile, outfile) == 0) {
1062
    strcpy(outfile, infile);
1063
    strcat(outfile, "-out");
1064
  }
1065

    
1066
  return outfile;
1067
}
1068

    
1069
/* ---------------------------------------------------------------------- */
1070
/* Process one infile */
1071

    
1072
/* Process one or more bitmaps from fin, and write the results to fout
1073
   using the page_f function of the appropriate backend. */
1074

    
1075
static void process_file(backend_t *b, const char *infile, const char *outfile, FILE *fin, FILE *fout) { 
1076
  int r; 
1077
  potrace_bitmap_t *bm = NULL; 
1078
  imginfo_t imginfo;
1079
  int eof_flag = 0;  /* to indicate premature eof */
1080
  int count;         /* number of bitmaps successfully processed, this file */
1081
  potrace_state_t *st;
1082
  simple_progress_t progress_data;
1083

    
1084
  for (count=0; ; count++) {
1085
    /* read a bitmap */
1086
    r = bm_read(fin, info.blacklevel, &bm);
1087
    switch (r) {
1088
    case -1:  /* system error */
1089
      fprintf(stderr, ""POTRACE": %s: %s\n", infile, strerror(errno));
1090
      exit(2);
1091
    case -2:  /* corrupt file format */
1092
      fprintf(stderr, ""POTRACE": %s: file format error: %s\n", infile, bm_read_error);
1093
      exit(2);
1094
    case -3:  /* empty file */
1095
      if (count>0) {  /* end of file */
1096
        return;
1097
      }
1098
      fprintf(stderr, ""POTRACE": %s: empty file\n", infile);
1099
      exit(2);
1100
    case -4:  /* wrong magic */
1101
      if (count>0) { 
1102
        fprintf(stderr, ""POTRACE": %s: warning: junk at end of file\n", infile);
1103
        return;
1104
      }
1105
      fprintf(stderr, ""POTRACE": %s: file format not recognized\n", infile);
1106
      fprintf(stderr, "Possible input file formats are: pnm (pbm, pgm, ppm), bmp.\n");
1107
      exit(2);
1108
    case 1:  /* unexpected end of file */
1109
      fprintf(stderr, ""POTRACE": warning: %s: premature end of file\n", infile);
1110
      eof_flag = 1;
1111
      break;
1112
    }
1113

    
1114
    /* prepare progress bar, if requested */
1115
    if (info.progress) {
1116
      init_progress(&info.param->progress, &progress_data, infile, count);
1117
    } else {
1118
      info.param->progress.callback = NULL;
1119
    }
1120

    
1121
    if (info.invert) {
1122
      bm_invert(bm);
1123
    }
1124

    
1125
    /* process the image */
1126
    st = potrace_trace(info.param, bm);
1127
    if (!st || st->status != POTRACE_STATUS_OK) {
1128
      fprintf(stderr, ""POTRACE": %s: %s\n", infile, strerror(errno));
1129
      exit(2);
1130
    }
1131

    
1132
    /* calculate image dimensions */
1133
    imginfo.pixwidth = bm->w;
1134
    imginfo.pixheight = bm->h;
1135
    calc_dimensions(&imginfo);
1136

    
1137
    bm_free(bm);
1138

    
1139
    r = b->page_f(fout, st->plist, &imginfo);
1140
    if (r) {
1141
      fprintf(stderr, ""POTRACE": %s: %s\n", outfile, strerror(errno));
1142
      exit(2);
1143
    }
1144

    
1145
    potrace_state_free(st);
1146

    
1147
    if (info.progress) {
1148
      fprintf(stderr, "\n");
1149
    }
1150

    
1151
    if (eof_flag || !b->multi) {
1152
      return;
1153
    }
1154
  }
1155
  /* not reached */
1156
}
1157

    
1158
/* ---------------------------------------------------------------------- */
1159
/* main: handle file i/o */
1160

    
1161
#define TRY(x) if (x) goto try_error
1162

    
1163
int main(int ac, char *av[]) {
1164
  backend_t *b;  /* backend info */
1165
  FILE *fin, *fout;
1166
  int i;
1167
  char *outfile;
1168

    
1169
  /* platform-specific initializations, e.g., set file i/o to binary */
1170
  platform_init();
1171

    
1172
  /* process options */
1173
  dopts(ac, av);
1174

    
1175
  b = info.backend;
1176
  if (b==NULL) {
1177
    fprintf(stderr, ""POTRACE": internal error: selected backend not found\n");
1178
    exit(1);
1179
  }
1180

    
1181
  /* fix some parameters */
1182
  /* if backend cannot handle opticurve, disable it */
1183
  if (b->opticurve == 0) {
1184
    info.param->opticurve = 0;
1185
  }
1186

    
1187
  /* there are several ways to call us:
1188
     potrace                     -- stdin to stdout
1189
     potrace -o outfile          -- stdin to outfile
1190
     potrace file...             -- encode each file and generate outfile names
1191
     potrace -o outfile file...  -- concatenate files and write to outfile
1192

1193
     The latter form is only allowed one file for single-page
1194
     backends.  For multi-page backends, each file must contain 0 or
1195
     more complete bitmaps.
1196
  */
1197

    
1198
  if (info.infilecount == 0) {                 /* read from stdin */
1199

    
1200
    fout = my_fopen_write(info.outfile);
1201
    if (!fout) {
1202
      fprintf(stderr, ""POTRACE": %s: %s\n", info.outfile ? info.outfile : "stdout", strerror(errno));
1203
      exit(2); 
1204
    }
1205
    if (b->init_f) {
1206
      TRY(b->init_f(fout));
1207
    }
1208
    process_file(b, "stdin", info.outfile ? info.outfile : "stdout", stdin, fout);
1209
    if (b->term_f) {
1210
      TRY(b->term_f(fout));
1211
    }
1212
    my_fclose(fout, info.outfile);
1213
    return 0;
1214

    
1215
  } else if (!info.outfile) {                /* infiles -> multiple outfiles */
1216

    
1217
    for (i=0; i<info.infilecount; i++) {
1218
      outfile = make_outfilename(info.infiles[i], b->ext);
1219
      if (!outfile) {
1220
        fprintf(stderr, ""POTRACE": %s\n", strerror(errno));
1221
        exit(2);
1222
      }
1223
      fin = my_fopen_read(info.infiles[i]);
1224
      if (!fin) {
1225
        fprintf(stderr, ""POTRACE": %s: %s\n", info.infiles[i], strerror(errno));
1226
        exit(2);
1227
      }
1228
      fout = my_fopen_write(outfile);
1229
      if (!fout) {
1230
        fprintf(stderr, ""POTRACE": %s: %s\n", outfile, strerror(errno));
1231
        exit(2);
1232
      }
1233
      if (b->init_f) {
1234
        TRY(b->init_f(fout));
1235
      }
1236
      process_file(b, info.infiles[i], outfile, fin, fout);
1237
      if (b->term_f) {
1238
        TRY(b->term_f(fout));
1239
      }
1240
      my_fclose(fin, info.infiles[i]);
1241
      my_fclose(fout, outfile);
1242
      free(outfile);
1243
    }
1244
    return 0; 
1245

    
1246
  } else {                                   /* infiles to outfile */
1247

    
1248
    if (!b->multi && info.infilecount >= 2) {
1249
      fprintf(stderr, ""POTRACE": cannot use multiple input files with -o in %s mode\n", b->name);
1250
      exit(1);
1251
    }
1252
    
1253
    fout = my_fopen_write(info.outfile);
1254
    if (!fout) {
1255
      fprintf(stderr, ""POTRACE": %s: %s\n", info.outfile, strerror(errno));
1256
      exit(2);
1257
    }
1258
    if (b->init_f) {
1259
      TRY(b->init_f(fout));
1260
    }
1261
    for (i=0; i<info.infilecount; i++) {
1262
      fin = my_fopen_read(info.infiles[i]);
1263
      if (!fin) {
1264
        fprintf(stderr, ""POTRACE": %s: %s\n", info.infiles[i], strerror(errno));
1265
        exit(2);
1266
      }
1267
      process_file(b, info.infiles[i], info.outfile, fin, fout);
1268
      my_fclose(fin, info.infiles[i]);
1269
    }
1270
    if (b->term_f) {
1271
      TRY(b->term_f(fout));
1272
    }
1273
    my_fclose(fout, info.outfile);
1274
    return 0;
1275

    
1276
  }
1277

    
1278
  /* not reached */
1279

    
1280
 try_error:
1281
  fprintf(stderr, ""POTRACE": %s\n", strerror(errno));
1282
  exit(2);
1283
}