1/***********************************************************************
2 *                                                                     *
3 * $Id: hpgs.c 390 2007-03-19 15:56:42Z softadm $
4 *                                                                     *
5 * hpgs - HPGl Script, a hpgl/2 interpreter, which uses a Postscript   *
6 *        API for rendering a scene and thus renders to a variety of   *
7 *        devices and fileformats.                                     *
8 *                                                                     *
9 * (C) 2004-2006 EV-i Informationstechnologie GmbH  http://www.ev-i.at *
10 *                                                                     *
11 * Author: Wolfgang Glas                                               *
12 *                                                                     *
13 *  hpgs is free software; you can redistribute it and/or              *
14 * modify it under the terms of the GNU Lesser General Public          *
15 * License as published by the Free Software Foundation; either        *
16 * version 2.1 of the License, or (at your option) any later version.  *
17 *                                                                     *
18 * hpgs is distributed in the hope that it will be useful,             *
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of      *
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   *
21 * Lesser General Public License for more details.                     *
22 *                                                                     *
23 * You should have received a copy of the GNU Lesser General Public    *
24 * License along with this library; if not, write to the               *
25 * Free Software  Foundation, Inc., 59 Temple Place, Suite 330,        *
26 * Boston, MA  02111-1307  USA                                         *
27 *                                                                     *
28 ***********************************************************************
29 *                                                                     *
30 * The main program.                                                   *
31 *                                                                     *
32 ***********************************************************************/
33
34#include <hpgs.h>
35#include <string.h>
36#include <math.h>
37#include <errno.h>
38#include <locale.h>
39
40#if defined ( __MINGW32__ ) || defined ( _MSC_VER )
41#include<malloc.h>
42#else
43#include<alloca.h>
44#endif
45
46/*! \mainpage The HPGS documentation
47
48    \section intro_sec Introduction
49
50
51    HPGS has been developed by
52    <A HREF="http://www.ev-i.at">EV-i Informationstechnologie GmbH</A>
53    and has been published under the
54    <A HREF="http://www.fsf.org/licenses/lgpl.html">LGPL</A>.
55
56    For Details visit the <A HREF="http://hpgs.berlios.de">project's homepage</A>.
57
58    \section install_sec Installation
59
60     See the file INSTALL of the distribution.
61
62    \section invoke_sec Invoking hpgs
63
64    \verbinclude hpgs-args.txt
65
66    \section api_sec The hpgs API.
67
68    HPGS is designed to be highly modular and may be used inside
69    C or C++ programs for either displaying HPGL files or
70    drawing a vector graphics sceneery to an image.
71
72    Refer to the \ref reader, \ref device, \ref paint_device and
73    \ref image modules in order to get an impression what the hpgs API
74    can do for you.
75 */
76
77
78#ifdef WIN32
79
80#include <windows.h>
81
82static char *get_aux_path(void)
83{
84  const char *key = "SOFTWARE\\ev-i\\hpgs";
85  DWORD len;
86  HKEY hkey;
87  char *ret;
88  const char *prg;
89
90  if ((RegOpenKeyEx(HKEY_CURRENT_USER,
91		    key, 0, KEY_READ, &hkey) == ERROR_SUCCESS ||
92       RegOpenKeyEx(HKEY_LOCAL_MACHINE,
93		    key, 0, KEY_READ, &hkey) == ERROR_SUCCESS    )&&
94      RegQueryValueEx(hkey,"prefix",NULL,NULL,NULL,&len) == ERROR_SUCCESS)
95    {
96      ret = malloc(len+2);
97
98      if (RegQueryValueEx(hkey,"prefix",NULL,NULL,ret,&len) != ERROR_SUCCESS)
99	{ free (ret); ret = 0; }
100
101      RegCloseKey(hkey);
102
103      return ret;
104    }
105
106  prg = getenv("PROGRAMFILES");
107
108  if (prg)
109    return hpgs_sprintf_malloc("%s\\EV-i",prg);
110
111  return strdup("C:\\Programme\\EV-i");
112}
113#else
114
115#ifndef HPGS_DEFAULT_PREFIX
116#define HPGS_DEFAULT_PREFIX "/usr/local"
117#endif
118
119static char *get_aux_path(void)
120{
121  char *p=getenv("EV_I_PREFIX");
122
123  if (!p)
124    return strdup(HPGS_DEFAULT_PREFIX);
125
126  return strdup(p);
127}
128#endif
129
130static int usage (void)
131{
132  fprintf (stderr,hpgs_i18n(
133	   "\n"
134	   " hpgs v%s - HPGl Script, a hpgl/2 interpreter/renderer.\n"
135	   "\n"
136	   " (C) 2004-2006 ev-i Informationstechnologie GmbH (http://www.ev-i.at)\n"
137	   "     published under the LGPL (http://www.fsf.org/licenses/lgpl.html).\n"
138	   "\n"
139	   "Type `hpgs --help' for a detailed description of cmd line options.\n")
140	   ,HPGS_VERSION  );
141
142  hpgs_cleanup();
143
144  return 0;
145}
146
147static int help (void)
148{
149  fprintf (stderr,hpgs_i18n(
150	   "\n"
151	   " hpgs v%s - HPGl Script, a hpgl/2 interpreter/renderer.\n"
152	   "\n"
153	   " (C) 2004-2006 ev-i Informationstechnologie GmbH (http://www.ev-i.at)\n"
154	   "     published under the LGPL (http://www.fsf.org/licenses/lgpl.html).\n"
155	   "\n"
156	   "usage: hpgs [-i] [-v] [-q] [-d <dev>] [options...] [-o <out>] <in1> <in2>...\n"
157	   "       -i ... Ignore plotsize from PS and determine\n"
158	   "              the plotsize from the file content.\n"
159	   "       --linewidth-size ... Account for linewidths in the plotsize\n"
160	   "              calculation for -i (default behaviour).\n"
161	   "       --no-linewidth-size ... Ignore linewidths in the plotsize\n"
162	   "              calculation for -i.\n"
163	   "       -v ... Increase verbosity.\n"
164	   "       -q ... Decrease verbosity, be quiet.\n"
165	   "       -o <out> ... specifiy the output filename. If not specified, write\n"
166	   "                    to stdout.\n"
167	   "       -m ... Switch to multipage mode, if a single file is given on the.\n"
168	   "              command line. If not specified, only the first page of the input\n"
169           "              file is processed.\n"
170	   "       -w ... Correct linewidth by given factor (default: 1).\n"
171	   "       -d ... Specifiy the output device. The default is the\n"
172	   "              native 'eps' device, which writes a simple eps file.\n"
173	   "              See section `Supported devices' below.\n"
174	   "       -a ... Use antialiasing when rendering to a png image.\n"
175	   "       --thin-alpha=<a>\n"
176           "              Specifiy the minimal alpha value for thin lines.\n"
177	   "              allowed values lie in the interval [0.001,1.0] (default: 0.25).\n"
178	   "       -I ... Specifiy image interpolation.\n"
179	   "       --rop3 ... Use ROP3 raster operations for rendering on devices\n"
180	   "              with ROP3 capabilities (default).\n"
181	   "       --no-rop3 ... Suppress usage of ROP3 raster operations.\n"
182	   "       -c ... Specifiy the compression level for png writing.\n"
183	   "       -r ... Specifiy the device resolution in dpi.\n"
184	   "              If no y-resolution is given, the y-resolution\n"
185	   "              is set to the same value as the x-resolution.\n"
186	   "       -p ... Specifiy the maximum pixel size of the device.\n"
187	   "              This is in fact an alternate method to specify the\n"
188	   "              resolution of the device. If -p is given, the device\n"
189	   "              resolution is caclulated in a way, that the plot fits\n"
190	   "              into the given rectangle.\n"
191	   "              If no y-size is given, the size y-size\n"
192	   "              is set to the same value as the x-size.\n"
193	   "       -s<papersize> ... Specifiy the plot size in pt (1/72 inch).\n"
194	   "              If -s is not given, the size is calculated from\n"
195	   "              the contents of the hpgl file.\n"
196           "              The <papersize> may be either one of the standard\n"
197           "              paper sizes A0,A1,A2,A3 or A4, their landscape versions\n"
198           "              A0l,A1l,A2l,A3l or A4l or a size in the format <width>x<height>\n"
199           "              where <width> and <height> specify a physical length in one of the\n"
200           "              formats <l>,<l>mm,<l>cm,<l>inch or <l>pt. <l> is a floating point\n"
201           "              number, the default unit is PostScript pt (1/72 inch).\n"
202	   "       --paper=<papersize>\n"
203           "              Specify a paper size of the output device. All plots\n"
204           "              are scaled to this paper size respecting the given border.\n"
205           "              If no fixed paper size is given, each page in the output\n"
206           "              file has an individual size adapted to the size of the HPGL\n"
207           "              content of the page.\n"
208           "              The format of <papersize> is decribed above for -s.\n"
209	   "       --border=<border>\n"
210           "              Specify a border for placing plots on output pages.\n"
211	   "       --rotation=<angle>\n"
212           "              Specify an angle for placing plots on output pages.\n"
213	   "       --stamp=<stamp>\n"
214           "              Specify a string, which is printed in the background.\n"
215	   "       --stamp-encoding=<enc>\n"
216           "              Specify an the name of the encoding of the string, which\n"
217	   "              is given in --stamp. Default is iso-8859-1.\n"
218	   "       --stamp-size=<pt>\n"
219           "              Specify the size of the stamp specified with --stamp\n"
220	   "              in point. Default value: 500pt.\n"
221	   "       --dump-png=<filename>\n"
222           "              Specify a filename for dumping inline PCL images in.\n"
223           "              PNG format. The actual filenames written are:\n"
224           "                 <filename>0001.png\n"
225           "                 <filename>0002.png\n"
226           "                  .....\n"
227           "              If <filename> contains an extension '.png' the counter\n"
228           "              is put between the basename and the '.png' extension.\n"
229	   "       --help\n"
230           "              Displays this usage information.\n"
231	   "       --version\n"
232           "              Displays the version information.\n"
233	   "\n"
234	   "Supported devices (option -d):\n"
235	   "\n"
236	   "       bbox    ... writes a PostScript BoundingBox to stdout.\n"
237	   "       ps      ... writes a multipage PostScript file.\n"
238	   "       eps     ... writes an eps files.\n"
239	   "       png_256 ... writes an indexed 8bpp png image.\n"
240	   "       png_gray... writes a grayscale 8bpp png image.\n"
241	   "       png_rgb ... writes a rgb 24bpp png image.\n"
242	   "       png_gray_alpha ... writes a grayscale 16bpp png image\n"
243	   "                          with an alpha channel.\n"
244	   "       png_rgb_alpha ... writes a rgb 32bpp png image\n"
245	   "                         with an alpha channel.\n"
246	   "       cairo_png ... writes a rgb 32bpp png image using\n"
247	   "                     the cairo library (experimental).\n")
248	   ,HPGS_VERSION );
249
250  hpgs_cleanup();
251
252  return 0;
253}
254
255static int get_double_arg(const char *arg, double *val)
256{
257  char * endptr = (char*)arg;
258  *val = strtod(arg,&endptr);
259  return (*endptr || endptr == arg) ? -1 : 0;
260}
261
262static int get_double_pair(const char *arg, double *xval, double *yval)
263{
264  char * endptr = (char*)arg;
265  *xval = strtod(arg,&endptr);
266
267  if (endptr == arg) return -1;
268  if (*endptr == '\0') { *yval = *xval; return 0; }
269  if (*endptr != 'x') return -1;
270
271  const char *yarg=endptr+1;
272
273  *yval = strtod(yarg,&endptr);
274  return (*endptr || endptr == yarg) ? -1 : 0;
275}
276
277static int get_int_arg(const char *arg, int *val)
278{
279  char * endptr = (char*)arg;
280  *val = strtol(arg,&endptr,10);
281  return (*endptr) ? -1 : 0;
282}
283
284static int get_int_pair(const char *arg, int *xval, int *yval)
285{
286  char * endptr = (char*)arg;
287  *xval = strtod(arg,&endptr);
288
289  if (*endptr == '\0') { *yval = *xval; return 0; }
290  if (*endptr != 'x') return -1;
291
292  const char *yarg=endptr+1;
293
294  *yval = strtod(yarg,&endptr);
295  return (*endptr || endptr == yarg) ? -1 : 0;
296}
297
298// helper function for supporting old device-specific options, which
299// are now global ones.
300static int get_dev_arg_value(const char *dev_name,int dev_name_len,
301                             const char *opt, const char *argv[],
302                             const char **value, int *narg)
303{
304  char *opt_name = alloca(4+dev_name_len+strlen(opt));
305
306  // contruct string --<dev_name><opt>
307  opt_name[1] = opt_name[0] = '-';
308  memcpy(opt_name+2,dev_name,dev_name_len);
309  strcpy(&opt_name[2+dev_name_len],opt);
310
311  return  hpgs_get_arg_value(opt_name,argv,value,narg);
312}
313
314/*
315   The main program analyses the cmd line argument and delegates the work.
316*/
317
318#define HPGS_MAX_PLUGIN_ARGS 32
319
320int main(int argc, const char *argv[])
321{
322  const char *dev_name="eps";
323  int dev_name_len = 3;
324  const char *out_fn=0;
325  const char *stamp=0;
326  const char *stamp_enc=0;
327  const char *png_dump_fn=0;
328  int ifile;
329  char *aux_path;
330  double x_dpi=72.0;
331  double y_dpi=72.0;
332  hpgs_bbox bbox= { 0.0, 0.0, 0.0, 0.0 };
333  double paper_angle = 0.0;
334  double paper_border = 0.0;
335  double paper_width = 0.0;
336  double paper_height = 0.0;
337  double lw_factor=-1.0;
338  double thin_alpha=0.25;
339  double stamp_size=500.0;
340  int x_px_size=0;
341  int y_px_size=0;
342  hpgs_bool multipage=HPGS_FALSE;
343  hpgs_bool ignore_ps=HPGS_FALSE;
344  hpgs_bool do_linewidth=HPGS_TRUE;
345  hpgs_bool do_rop3=HPGS_TRUE;
346  int verbosity=1;
347  int compression=6;
348  hpgs_bool antialias=HPGS_FALSE;
349  int image_interpolation=0;
350  hpgs_device *size_dev = 0;
351  hpgs_device *plot_dev = 0;
352  hpgs_istream *in = 0;
353  hpgs_reader  *reader = 0;
354  hpgs_png_image *image = 0;
355  const char *plugin_argv[HPGS_MAX_PLUGIN_ARGS];
356  int plugin_argc = 0;
357  int ret = 1;
358
359#ifdef LC_MESSAGES
360  setlocale(LC_MESSAGES,"");
361#endif
362  setlocale(LC_CTYPE,"");
363
364  aux_path = get_aux_path();
365
366  if (!aux_path)
367    {
368      fprintf(stderr,hpgs_i18n("Error getting installation path: %s.\n"),
369	      strerror(errno));
370      return 1;
371    }
372
373  hpgs_init(aux_path);
374  free(aux_path);
375
376  memset(plugin_argv,0,sizeof(plugin_argv));
377
378  ++argv;
379  --argc;
380
381  while (argc>0)
382    {
383      int narg = 1;
384      const char *value;
385
386      if (strcmp(argv[0],"--") == 0)
387	{
388	  ++argv;
389	  --argc;
390	  break;
391	}
392      else       if (strcmp(argv[0],"-v") == 0)
393	{
394	  ++verbosity;
395	}
396      else if (strcmp(argv[0],"-q") == 0 || strcmp(argv[0],"-dQUIET") == 0)
397	{
398	  --verbosity;
399	}
400      else if (strcmp(argv[0],"-i") == 0)
401	{
402	  ignore_ps=HPGS_TRUE;
403	}
404      else if (strcmp(argv[0],"-m") == 0)
405	{
406	  multipage=HPGS_TRUE;
407	}
408      else if (hpgs_get_arg_value("-d",argv,&value,&narg))
409	{
410	  dev_name = value;
411          dev_name_len = strlen(dev_name);
412
413          if (plugin_argc)
414	    {
415	      fprintf(stderr,hpgs_i18n("Error: Device options specified before -d argument.\n"));
416	      return usage();
417	    }
418	}
419      else if (hpgs_get_arg_value("--stamp=",argv,&value,&narg))
420	{
421	  stamp = value;
422	}
423      else if (hpgs_get_arg_value("--stamp-encoding=",argv,&value,&narg))
424	{
425	  stamp_enc = value;
426	}
427      else if (hpgs_get_arg_value("--stamp-size=",argv,&value,&narg))
428	{
429          if (hpgs_parse_length(value,&stamp_size))
430	    {
431	      fprintf(stderr,hpgs_i18n("Error: --stamp-size= must be followed by a valid length.\n"));
432	      return usage();
433	    }
434
435	  if (stamp_size < 20.0 || stamp_size > 2000.0)
436	    {
437	      fprintf(stderr,hpgs_i18n("Error: stamp-size must lie in the interval [20,2000]pt.\n"));
438	      return usage();
439	    }
440	}
441      else if (hpgs_get_arg_value("--dump-png=",argv,&value,&narg))
442	{
443          png_dump_fn = value;
444	}
445       else if (hpgs_get_arg_value("-o",argv,&value,&narg))
446	{
447	  out_fn = value;
448	}
449      else if (strcmp(argv[0],"-a") == 0)
450	{
451          antialias = HPGS_TRUE;
452	}
453      else if (hpgs_get_arg_value("-I",argv,&value,&narg))
454	{
455	  if (get_int_arg(value,&image_interpolation))
456	    {
457	      if (narg == 1)
458		{
459		  fprintf(stderr,hpgs_i18n("Error: -I must be followed by an integer number.\n"));
460		  return usage();
461		}
462	      else
463		{
464		  image_interpolation= 1;
465		  narg = 1;
466		}
467	    }
468
469	  if (image_interpolation < 0 || image_interpolation > 1)
470	    {
471	      fprintf(stderr,hpgs_i18n("Error: The argument to -I must be 0 or 1.\n"));
472	      return usage();
473	    }
474	}
475      else if (hpgs_get_arg_value("-c",argv,&value,&narg))
476	{
477	  if (get_int_arg(value,&compression))
478	    {
479	      fprintf(stderr,hpgs_i18n("Error: -c must be followed by an integer number.\n"));
480	      return usage();
481	    }
482
483	  if (compression < 1 || compression > 9)
484	    {
485	      fprintf(stderr,hpgs_i18n("Error: compression factor must lie in the interval [1,9].\n"));
486	      return usage();
487	    }
488	}
489      else if (hpgs_get_arg_value("-w",argv,&value,&narg))
490	{
491	  if (get_double_arg(value,&lw_factor))
492	    {
493	      fprintf(stderr,hpgs_i18n("Error: -w must be followed by a floating point number.\n"));
494	      return usage();
495	    }
496
497	  if (lw_factor < 0.0 || lw_factor > 10.0)
498	    {
499	      fprintf(stderr,hpgs_i18n("Error: Linewidth factor must lie in the interval [0.0,10.0].\n"));
500	      return usage();
501	    }
502	}
503      else if (hpgs_get_arg_value("--thin-alpha=",argv,&value,&narg))
504	{
505	  if (get_double_arg(value,&thin_alpha))
506	    {
507	      fprintf(stderr,hpgs_i18n("Error: --thin-alpha= must be followed by a floating point number.\n"));
508	      return usage();
509	    }
510
511	  if (thin_alpha < 0.01 || thin_alpha > 10.0)
512	    {
513	      fprintf(stderr,hpgs_i18n("Error: Thin alpha must lie in the interval [0.01,10.0].\n"));
514	      return usage();
515	    }
516	}
517      else if (hpgs_get_arg_value("-r",argv,&value,&narg))
518	{
519	  if (get_double_pair(value,&x_dpi,&y_dpi))
520	    {
521	      fprintf(stderr,hpgs_i18n("Error: -r must be followed by <res> or <xres>x<yres>.\n"));
522	      return usage();
523            }
524
525          if (x_dpi < 5.0 || y_dpi < 5.0)
526            {
527              fprintf(stderr,hpgs_i18n("Error: Resolutions must be at least 5 dpi.\n"));
528              return usage();
529            }
530	}
531      else if (hpgs_get_arg_value("-p",argv,&value,&narg))
532	{
533	  if (get_int_pair(value,&x_px_size,&y_px_size))
534	    {
535	      fprintf(stderr,hpgs_i18n("Error: -p must be followed by <sz> or <xsz>x<ysz>.\n"));
536	      return usage();
537            }
538
539          if (y_px_size < 20 ||  x_px_size < 20)
540            {
541              fprintf(stderr,hpgs_i18n("Error: Pixel sizes must be at least 20px.\n"));
542              return usage();
543            }
544	}
545      else if (hpgs_get_arg_value("-s",argv,&value,&narg))
546	{
547          double x_size,y_size;
548
549          if (hpgs_parse_papersize(value,&x_size, &y_size)<0)
550            {
551	      fprintf(stderr,hpgs_i18n("Error: -s must be followed by a valid paper size.\n"));
552	      return usage();
553            }
554
555          if (x_size < 72.0 || y_size < 72.0)
556            {
557              fprintf(stderr,hpgs_i18n("Error: The plot size must be at least 72 pt.\n"));
558              return usage();
559            }
560
561          bbox.urx = x_size;
562          bbox.ury = y_size;
563	}
564      else if (hpgs_get_arg_value("--paper=",argv,&value,&narg))
565	{
566          if (hpgs_parse_papersize(value,&paper_width,&paper_height)<0)
567            {
568	      fprintf(stderr,hpgs_i18n("Error: --paper= must be followed by a valid paper size.\n"));
569	      return usage();
570            }
571
572          if (paper_width < 72.0 || paper_height < 72.0)
573            {
574              fprintf(stderr,hpgs_i18n("Error: The paper size must be at least 72 pt.\n"));
575              return usage();
576            }
577	}
578      else if (hpgs_get_arg_value("--border=",argv,&value,&narg) ||
579               // Allow old device-specific border parameters.
580               get_dev_arg_value(dev_name,dev_name_len,"-border=",argv,&value,&narg)     )
581	{
582          if (hpgs_parse_length(value,&paper_border)<0)
583            {
584	      fprintf(stderr,hpgs_i18n("Error: --border= must be followed by a valid length.\n"));
585	      return usage();
586            }
587
588          if (paper_border < 0.0 || paper_border > 144.0)
589            {
590              fprintf(stderr,hpgs_i18n("Error: The page border must lie in the interval [0,144] pt.\n"));
591              return usage();
592            }
593	}
594      else if (hpgs_get_arg_value("--rotation=",argv,&value,&narg) ||
595               // Allow old device-specific rotation parameters.
596               get_dev_arg_value(dev_name,dev_name_len,"-rotation=",argv,&value,&narg)       )
597	{
598          if (hpgs_parse_length(value,&paper_angle)<0)
599            {
600	      fprintf(stderr,hpgs_i18n("Error: --angle= must be followed by a valid angle.\n"));
601	      return usage();
602            }
603	}
604      else if (strcmp(argv[0],"--linewidth-size") == 0)
605	{
606	  do_linewidth = HPGS_TRUE;
607	}
608      else if (strcmp(argv[0],"--no-linewidth-size") == 0)
609  	{
610	  do_linewidth = HPGS_FALSE;
611	}
612      else if (strcmp(argv[0],"--rop3") == 0)
613	{
614	  do_rop3 = HPGS_TRUE;
615	}
616      else if (strcmp(argv[0],"--no-rop3") == 0)
617	{
618	  do_rop3 = HPGS_FALSE;
619	}
620      else if (strcmp(argv[0],"--help") == 0)
621	{
622	  return help();
623	}
624      else if (strcmp(argv[0],"--version") == 0)
625	{
626	  usage();
627	  return 0;
628	}
629      else if (strncmp(argv[0],"--",2) == 0 &&
630               strncmp(argv[0]+2,dev_name,dev_name_len) == 0 &&
631               argv[0][dev_name_len+2] == '-')
632	{
633          int l=strlen(argv[0]);
634
635          if (plugin_argc >= HPGS_MAX_PLUGIN_ARGS-1)
636	    {
637	      fprintf(stderr,hpgs_i18n("Error: Number of plugin-args exceeds maximum of %d.\n"),
638                      HPGS_MAX_PLUGIN_ARGS-1);
639	      return usage();
640	    }
641
642          plugin_argv[plugin_argc] = argv[0]+dev_name_len+2;
643          ++plugin_argc;
644
645          if (argv[0][l-1] == '=')
646            {
647              if (plugin_argc >= HPGS_MAX_PLUGIN_ARGS-1)
648                {
649                  fprintf(stderr,hpgs_i18n("Error: Number of plugin-args exceed maximum of %d.\n"),
650                          HPGS_MAX_PLUGIN_ARGS-1);
651                  usage();
652                }
653
654              plugin_argv[plugin_argc] = argv[2];
655              ++plugin_argc;
656
657              narg=2;
658            }
659	}
660      else
661	{
662	  if (argv[0][0] == '-')
663	    {
664	      fprintf(stderr,hpgs_i18n("Error: Unknown option %s given.\n"),argv[0]);
665	      return usage();
666	    }
667
668          break;
669	}
670
671      argv+=narg;
672      argc-=narg;
673    }
674
675  if (argc < 1)
676    {
677      fprintf(stderr,hpgs_i18n("Error: No input file given.\n"));
678      return usage();
679    }
680
681  if (argc > 1 && !multipage)
682    {
683      multipage = HPGS_TRUE;
684    }
685
686  // adjust default linewidth factor.
687  if (lw_factor < 0.0)
688    {
689      // This is the best choice for our basic, non-antialiased renderer,
690      // which rounds up pixel line widths.
691      if (antialias == 0 && strncmp(dev_name,"png_",4) == 0)
692        lw_factor = 0.5;
693      else
694        lw_factor = 1.0;
695    }
696
697  size_dev = (hpgs_device*)hpgs_new_plotsize_device(ignore_ps,do_linewidth);
698
699  if (!size_dev)
700    {
701      fprintf(stderr,hpgs_i18n("Error: Cannot create plotsize device.\n"));
702      goto cleanup;
703    }
704
705  in = hpgs_new_file_istream(argv[0]);
706
707  if (!in)
708    {
709      fprintf(stderr,hpgs_i18n("Error: Cannot open input file %s: %s\n"),
710	      argv[0],strerror(errno));
711      hpgs_device_destroy((hpgs_device*)size_dev);
712      goto cleanup;
713    }
714
715  reader = hpgs_new_reader(in,size_dev,
716			   multipage,verbosity);
717
718  if (!reader)
719    {
720      fprintf(stderr,hpgs_i18n("Error: Cannot create hpgl reader: %s\n"),strerror(errno));
721      goto cleanup;
722    }
723
724  hpgs_reader_set_lw_factor(reader,lw_factor);
725
726  // determine plot size, if not specified on the cmd line
727  if (bbox.urx < 72.0 || bbox.ury < 72.0)
728    {
729      // read in multiple pages.
730      for (ifile = 1; ifile < argc; ++ifile)
731        {
732          if (hpgs_read(reader,HPGS_FALSE))
733            {
734              fprintf(stderr,hpgs_i18n("Error: Cannot determine plot size of file %s: %s\n"),
735                      argv[ifile-1],hpgs_get_error());
736              goto cleanup;
737            }
738
739          in = hpgs_new_file_istream(argv[ifile]);
740
741          if (!in)
742            {
743              fprintf(stderr,hpgs_i18n("Error: Cannot open input file %s: %s\n"),
744                      argv[ifile],strerror(errno));
745              goto cleanup;
746            }
747
748          hpgs_reader_attach(reader,in);
749        }
750
751      if (hpgs_read(reader,HPGS_TRUE))
752	{
753	  fprintf(stderr,hpgs_i18n("Error: Cannot determine plot size of file %s: %s\n"),
754		  argv[ifile-1],hpgs_get_error());
755	  goto cleanup;
756	}
757
758      // get bounding box of first page.
759      // (will return overall boundingbox, if in singlepage mode.)
760      if (hpgs_getplotsize(size_dev,1,&bbox)<0)
761	{
762	  fprintf(stderr,hpgs_i18n("Error: Cannot determine plotsize: %s\n"),
763		  hpgs_get_error());
764	  goto cleanup;
765	}
766
767      if (hpgs_bbox_isempty(&bbox))
768	{
769	  fprintf(stderr,hpgs_i18n("Error: Empty bounding:  %g %g %g %g.\n"),
770		  bbox.llx,bbox.lly,bbox.urx,bbox.ury);
771	  goto cleanup;
772	}
773
774      if (verbosity >= 1)
775	fprintf(stderr,"BoundingBox: %g %g %g %g.\n",bbox.llx,bbox.lly,bbox.urx,bbox.ury);
776    }
777
778  // set the appropriate page placement.
779  if (paper_width > 0.0 && paper_height > 0.0)
780    {
781      hpgs_reader_set_fixed_page(reader,&bbox,
782                                 paper_width,paper_height,
783                                 paper_border,paper_angle );
784    }
785  else
786    {
787      paper_width = 200.0 * 72.0;
788      paper_height = 200.0 * 72.0;
789
790      hpgs_reader_set_dynamic_page(reader,&bbox,
791                                   paper_width,paper_height,
792                                   paper_border,paper_angle );
793    }
794
795  if (strcmp(dev_name,"bbox") == 0)
796    {
797      int i;
798      FILE *out = out_fn ? fopen(out_fn,"wb") : stdout;
799
800      if (!out)
801	{
802	  fprintf(stderr,hpgs_i18n("Error: Cannot open output file <%s>.\n"),out_fn);
803	  goto cleanup;
804	}
805
806      for (i=0;i<10000;++i)
807        {
808          int r = hpgs_getplotsize(size_dev,i,&bbox);
809
810          if (r < 0)
811            {
812              fprintf(stderr,hpgs_i18n("Error: Cannot determine plotsize: %s\n"),
813                      hpgs_get_error());
814              fclose(out);
815              goto cleanup;
816            }
817
818          if (r) break;
819
820          if (i>0)
821            {
822              fprintf(out,"%%%%Page: %d %d.\n",i,i);
823              fprintf(out,"%%%%PageBoundingBox: %d %d %d %d.\n",
824                      (int)floor(bbox.llx),(int)floor(bbox.lly),
825                      (int)ceil(bbox.urx),(int)ceil(bbox.ury));
826              fprintf(out,"%%%%PageHiResBoundingBox: %g %g %g %g.\n",bbox.llx,bbox.lly,bbox.urx,bbox.ury);
827            }
828          else
829            {
830              fprintf(out,"%%%%BoundingBox: %d %d %d %d.\n",
831                      (int)floor(bbox.llx),(int)floor(bbox.lly),
832                      (int)ceil(bbox.urx),(int)ceil(bbox.ury));
833              fprintf(out,"%%%%HiResBoundingBox: %g %g %g %g.\n",bbox.llx,bbox.lly,bbox.urx,bbox.ury);
834            }
835        }
836
837      if (out != stdout) fclose(out);
838
839      ret=0;
840      goto cleanup;
841    }
842  else if (strcmp(dev_name,"eps") == 0)
843    {
844      plot_dev =
845	(hpgs_device*)hpgs_new_eps_device(out_fn,&bbox,do_rop3);
846
847      if (!plot_dev)
848	{
849	  fprintf(stderr,hpgs_i18n("Error: Cannot create eps device.\n"));
850	  goto cleanup;
851	}
852    }
853  else if (strcmp(dev_name,"ps") == 0)
854    {
855      plot_dev =
856	(hpgs_device*)hpgs_new_ps_device(out_fn,&bbox,do_rop3);
857
858      if (!plot_dev)
859	{
860	  fprintf(stderr,hpgs_i18n("Error: Cannot create postscript device.\n"));
861	  goto cleanup;
862	}
863    }
864  else if (strncmp(dev_name,"png_",4) == 0)
865    {
866      int depth = 8;
867      int palette = 0;
868      hpgs_paint_device *pdv;
869
870      if (strcmp(dev_name+4,"gray") == 0)
871	depth = 8;
872      else if (strcmp(dev_name+4,"gray_alpha") == 0)
873	depth = 16;
874      else if (strcmp(dev_name+4,"rgb") == 0)
875	depth = 24;
876      else if (strcmp(dev_name+4,"rgb_alpha") == 0)
877	depth = 32;
878      else if (strcmp(dev_name+4,"256") == 0)
879	palette = 1;
880      else
881	{
882	  fprintf(stderr,hpgs_i18n("Error: png device %s in not supported.\n"),
883		  dev_name);
884	  goto cleanup;
885	}
886
887      if (x_px_size >= 20 && y_px_size >= 20)
888	{
889          // get overall bounding box, if pixel size is specified.
890          // This way no page image exceeds the given size and
891          // all images have the same resolution.
892          hpgs_bbox bb;
893
894          if (hpgs_getplotsize(size_dev,0,&bb)<0)
895            {
896              fprintf(stderr,hpgs_i18n("Error: Cannot determine overall plotsize: %s\n"),
897                      hpgs_get_error());
898              goto cleanup;
899            }
900
901	  x_dpi = 72.0 * x_px_size / (bb.urx-bb.llx);
902	  y_dpi = 72.0 * y_px_size / (bb.ury-bb.lly);
903
904	  if (x_dpi > y_dpi)
905	    {
906	      x_dpi = y_dpi;
907	      x_px_size = x_dpi * (bb.urx-bb.llx) / 72.0;
908	    }
909	  else
910	    {
911	      y_dpi = x_dpi;
912	      y_px_size = y_dpi * (bb.ury-bb.lly) / 72.0;
913	    }
914	}
915      else
916	{
917          // initialize the pixel size from the first page.
918	  x_px_size = x_dpi * (bbox.urx-bbox.llx) / 72.0;
919	  y_px_size = y_dpi * (bbox.ury-bbox.lly) / 72.0;
920	}
921
922      image = hpgs_new_png_image(x_px_size,y_px_size,depth,palette,do_rop3);
923
924      if (!image)
925	{
926	  fprintf(stderr,hpgs_i18n("Error creating %dx%dx%d sized png image: %s.\n"),
927		  x_px_size,y_px_size,depth,strerror(errno));
928	  goto cleanup;
929	}
930
931      hpgs_png_image_set_compression(image,compression);
932
933      pdv = hpgs_new_paint_device((hpgs_image*)image,
934                                  out_fn,&bbox,
935                                  antialias);
936      if (!pdv)
937	{
938	  fprintf(stderr,hpgs_i18n("Error: Cannot create paint device.\n"));
939	  goto cleanup;
940	}
941
942      hpgs_paint_device_set_image_interpolation(pdv,image_interpolation);
943      hpgs_paint_device_set_thin_alpha(pdv,thin_alpha);
944      // set the resolution of the image, although
945      // hpgs_new_paint_device has done this before.
946      // The reason is, that we know the resolution with more precision
947      // than hpgs_new_paint_device.
948      hpgs_image_set_resolution((hpgs_image*)image,x_dpi,y_dpi);
949
950      plot_dev = (hpgs_device *)pdv;
951    }
952  else
953    {
954      if (x_px_size >= 20 && y_px_size >= 20)
955	{
956          // calculate resolution from overall bounding box,
957          // if pixel size is specified.
958          // This way no page image exceeds the given size and
959          // all images have the same resolution.
960          hpgs_bbox bb;
961
962          if (hpgs_getplotsize(size_dev,0,&bb)<0)
963            {
964              fprintf(stderr,hpgs_i18n("Error: Cannot determine overall plotsize: %s\n"),
965                      hpgs_get_error());
966              goto cleanup;
967            }
968
969	  x_dpi = 72.0 * x_px_size / (bb.urx-bb.llx);
970	  y_dpi = 72.0 * y_px_size / (bb.ury-bb.lly);
971
972	  if (x_dpi > y_dpi)
973	    x_dpi = y_dpi;
974	  else
975	    y_dpi = x_dpi;
976	}
977
978      void *page_asset_ctxt = 0;
979      hpgs_reader_asset_func_t page_asset_func = 0;
980      void *frame_asset_ctxt = 0;
981      hpgs_reader_asset_func_t frame_asset_func = 0;
982
983      if (hpgs_new_plugin_device(&plot_dev,
984                                 &page_asset_ctxt,
985                                 &page_asset_func,
986                                 &frame_asset_ctxt,
987                                 &frame_asset_func,
988                                 dev_name,out_fn,&bbox,
989                                 x_dpi,y_dpi,do_rop3,
990                                 plugin_argc,plugin_argv))
991	{
992	  fprintf(stderr,hpgs_i18n("Error: Cannot create plugin device: %s\n"),
993                  hpgs_get_error());
994	  goto cleanup;
995	}
996
997      if (page_asset_func)
998        hpgs_reader_set_page_asset_func(reader,page_asset_ctxt,page_asset_func);
999
1000      if (frame_asset_func)
1001        hpgs_reader_set_frame_asset_func(reader,frame_asset_ctxt,frame_asset_func);
1002    }
1003
1004  if (!plot_dev)
1005    {
1006      fprintf (stderr,hpgs_i18n("Error: invalid plot device name %s specified.\n"),dev_name);
1007      goto cleanup;
1008    }
1009
1010  if (png_dump_fn && hpgs_reader_set_png_dump(reader,png_dump_fn))
1011    {
1012      fprintf(stderr,hpgs_i18n("Error: Cannot set png_dump filename to reader: %s\n"),
1013	      hpgs_get_error());
1014      goto cleanup;
1015    }
1016
1017  if (stamp && hpgs_device_stamp(plot_dev,&bbox,stamp,stamp_enc,stamp_size))
1018    {
1019      fprintf(stderr,hpgs_i18n("Error: Cannot stamp plot: %s\n"),
1020	      hpgs_get_error());
1021      goto cleanup;
1022    }
1023
1024  if (hpgs_reader_imbue(reader,plot_dev))
1025    {
1026      fprintf(stderr,hpgs_i18n("Error: Cannot imbue plot device to reader: %s\n"),
1027	      hpgs_get_error());
1028      goto cleanup;
1029    }
1030
1031  // re-open first file, if we have more than one input file.
1032  if (argc > 1)
1033    {
1034      in = hpgs_new_file_istream(argv[0]);
1035
1036      if (!in)
1037        {
1038          fprintf(stderr,hpgs_i18n("Error: Cannot open input file %s: %s\n"),
1039                  argv[0],strerror(errno));
1040          goto cleanup;
1041        }
1042      hpgs_reader_attach(reader,in);
1043    }
1044
1045  // read in multiple pages.
1046  for (ifile = 1; ifile < argc; ++ifile)
1047    {
1048      if (hpgs_read(reader,HPGS_FALSE))
1049        {
1050          fprintf(stderr,hpgs_i18n("Error: Cannot process plot file %s: %s\n"),
1051                  argv[ifile-1],hpgs_get_error());
1052          goto cleanup;
1053        }
1054
1055      in = hpgs_new_file_istream(argv[ifile]);
1056
1057      if (!in)
1058        {
1059          fprintf(stderr,hpgs_i18n("Error: Cannot open input file %s: %s\n"),
1060                  argv[ifile],strerror(errno));
1061          goto cleanup;
1062        }
1063
1064      hpgs_reader_attach(reader,in);
1065    }
1066
1067  if (hpgs_read(reader,HPGS_TRUE))
1068    {
1069      fprintf(stderr,hpgs_i18n("Error: Cannot process plot file %s: %s\n"),
1070	      argv[ifile-1],hpgs_get_error());
1071      goto cleanup;
1072    }
1073
1074  if (verbosity >= 2)
1075    fprintf(stderr,hpgs_i18n("Success.\n"));
1076
1077  ret = 0;
1078
1079 cleanup:
1080  if (reader)
1081    hpgs_destroy_reader(reader);
1082
1083  hpgs_cleanup();
1084
1085  return ret;
1086}
1087