gerbv  2.6A
main.c
Go to the documentation of this file.
1 /*
2  * gEDA - GNU Electronic Design Automation
3  * This file is a part of gerbv.
4  *
5  * Copyright (C) 2008 Julian Lamb
6  *
7  * $Id$
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
22  */
23 
29 #include "gerbv.h"
30 
31 #include <assert.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <errno.h>
35 #include <math.h>
36 
37 #ifdef HAVE_STRING_H
38 # include <string.h>
39 #endif
40 
41 #ifdef HAVE_UNISTD_H
42 # include <unistd.h>
43 #endif
44 
45 #ifdef HAVE_GETOPT_H
46 # include <getopt.h>
47 #endif
48 
49 #include <locale.h>
50 
51 #include "common.h"
52 #include "main.h"
53 #include "callbacks.h"
54 #include "interface.h"
55 #include "render.h"
56 #include "project.h"
57 
58 #if (DEBUG)
59 # define dprintf printf("%s(): ", __FUNCTION__); printf
60 #else
61 # define dprintf if(0) printf
62 #endif
63 
64 #define NUMBER_OF_DEFAULT_COLORS 18
65 #define NUMBER_OF_DEFAULT_TRANSFORMATIONS 20
66 
67 static gerbv_layer_color mainDefaultColors[NUMBER_OF_DEFAULT_COLORS] = {
68  {115,115,222,177},
69  {255,127,115,177},
70  {193,0,224,177},
71  {117,242,103,177},
72  {0,195,195,177},
73  {213,253,51,177},
74  {209,27,104,177},
75  {255,197,51,177},
76  {186,186,186,177},
77  {211,211,255,177},
78  {253,210,206,177},
79  {236,194,242,177},
80  {208,249,204,177},
81  {183,255,255,177},
82  {241,255,183,177},
83  {255,202,225,177},
84  {253,238,197,177},
85  {226,226,226,177}
86 };
87 
88 static gerbv_user_transformation_t mainDefaultTransformations[NUMBER_OF_DEFAULT_TRANSFORMATIONS] = {
89  {0,0,1,1,0,FALSE,FALSE,FALSE},
90  {0,0,1,1,0,FALSE,FALSE,FALSE},
91  {0,0,1,1,0,FALSE,FALSE,FALSE},
92  {0,0,1,1,0,FALSE,FALSE,FALSE},
93  {0,0,1,1,0,FALSE,FALSE,FALSE},
94  {0,0,1,1,0,FALSE,FALSE,FALSE},
95  {0,0,1,1,0,FALSE,FALSE,FALSE},
96  {0,0,1,1,0,FALSE,FALSE,FALSE},
97  {0,0,1,1,0,FALSE,FALSE,FALSE},
98  {0,0,1,1,0,FALSE,FALSE,FALSE},
99  {0,0,1,1,0,FALSE,FALSE,FALSE},
100  {0,0,1,1,0,FALSE,FALSE,FALSE},
101  {0,0,1,1,0,FALSE,FALSE,FALSE},
102  {0,0,1,1,0,FALSE,FALSE,FALSE},
103  {0,0,1,1,0,FALSE,FALSE,FALSE},
104  {0,0,1,1,0,FALSE,FALSE,FALSE},
105  {0,0,1,1,0,FALSE,FALSE,FALSE},
106  {0,0,1,1,0,FALSE,FALSE,FALSE},
107  {0,0,1,1,0,FALSE,FALSE,FALSE},
108  {0,0,1,1,0,FALSE,FALSE,FALSE},
109 };
110 
111 #ifdef HAVE_GETOPT_LONG
112 int longopt_val = 0;
113 int longopt_idx = 0;
114 const struct option longopts[] = {
115  /* name has_arg flag val */
116  {"border", required_argument, NULL, 'B'},
117  {"dpi", required_argument, NULL, 'D'},
118  {"version", no_argument, NULL, 'V'},
119  {"origin", required_argument, NULL, 'O'},
120  {"window_inch", required_argument, NULL, 'W'},
121  {"antialias", no_argument, NULL, 'a'},
122  {"background", required_argument, NULL, 'b'},
123  {"dump", no_argument, NULL, 'd'},
124  {"foreground", required_argument, NULL, 'f'},
125  {"rotate", required_argument, NULL, 'r'},
126  {"mirror", required_argument, NULL, 'm'},
127  {"help", no_argument, NULL, 'h'},
128  {"log", required_argument, NULL, 'l'},
129  {"output", required_argument, NULL, 'o'},
130  {"project", required_argument, NULL, 'p'},
131  {"tools", required_argument, NULL, 't'},
132  {"translate", required_argument, NULL, 'T'},
133  {"window", required_argument, NULL, 'w'},
134  {"export", required_argument, NULL, 'x'},
135  {"geometry", required_argument, &longopt_val, 1},
136  /* GDK/GDK debug flags to be "let through" */
137  {"gtk-module", required_argument, &longopt_val, 2},
138  {"g-fatal-warnings",no_argument, &longopt_val, 2},
139  {"gtk-debug", required_argument, &longopt_val, 2},
140  {"gtk-no-debug", required_argument, &longopt_val, 2},
141  {"gdk-debug", required_argument, &longopt_val, 2},
142  {"gdk-no-debug", required_argument, &longopt_val, 2},
143  {"display", required_argument, &longopt_val, 2},
144  {"sync", no_argument, &longopt_val, 2},
145  {"no-xshm", no_argument, &longopt_val, 2},
146  {"name", required_argument, &longopt_val, 2},
147  {"class", required_argument, &longopt_val, 2},
148  {0, 0, 0, 0},
149 };
150 #endif /* HAVE_GETOPT_LONG*/
151 const char *opt_options = "VadhB:D:O:W:b:f:r:m:l:o:p:t:T:w:x:";
152 
157 gerbv_screen_t screen;
158 
159 gboolean logToFileOption;
160 gchar *logToFileFilename;
161 
162 /* ------------------------------------------------------------------ */
163 void
164 main_open_project_from_filename(gerbv_project_t *gerbvProject, gchar *filename)
165 {
166  project_list_t *list, *plist;
167  gint i, max_layer_num = -1;
168  gerbv_fileinfo_t *file_info;
169 
170  dprintf(_("Opening project = %s\n"), (gchar *) filename);
171  list = read_project_file(filename);
172 
173  if (!list) {
174  GERB_MESSAGE(_("could not read %s[%d]"), (gchar *) filename,
175  gerbvProject->last_loaded);
176 
177  return;
178  }
179 
180  /* Get the max layer number in the project list */
181  plist = list;
182  while (plist) {
183  if (plist->layerno > max_layer_num)
184  max_layer_num = plist->layerno;
185 
186  plist = plist->next;
187  }
188 
189  /* Increase the layer count each time and find (if any) the
190  * corresponding entry */
191  for (i = -1; i <= max_layer_num; i++) {
192  plist = list;
193  while (plist) {
194  if (plist->layerno != i) {
195  plist = plist->next;
196  continue;
197  }
198 
199  GdkColor colorTemplate = {0,
200  plist->rgb[0], plist->rgb[1], plist->rgb[2]};
201  if (i == -1) {
202  gerbvProject->background = colorTemplate;
203  plist = plist->next;
204  continue;
205  }
206 
207  gchar *fullName = NULL;
208  gchar *dirName = NULL;
209  gint fileIndex = gerbvProject->last_loaded + 1;
210 
211  if (!g_path_is_absolute (plist->filename)) {
212  /* Build the full pathname to the layer */
213  dirName = g_path_get_dirname (filename);
214  fullName = g_build_filename (dirName,
215  plist->filename, NULL);
216  } else {
217  fullName = g_strdup (plist->filename);
218  }
219 
220  if (gerbv_open_image(gerbvProject, fullName,
221  fileIndex, FALSE,
222  plist->attr_list,
223  plist->n_attr, TRUE) == -1) {
224  GERB_MESSAGE(_("could not read file: %s"),
225  fullName);
226  plist = plist->next;
227  continue;
228  }
229 
230  g_free (dirName);
231  g_free (fullName);
232 
233  /* Change color from default to from the project list */
234  file_info = gerbvProject->file[fileIndex];
235  file_info->color = colorTemplate;
236  file_info->alpha = plist->alpha;
237  file_info->transform.inverted = plist->inverted;
238  file_info->transform.translateX = plist->translate_x;
239  file_info->transform.translateY = plist->translate_y;
240  file_info->transform.rotation = plist->rotation;
241  file_info->transform.scaleX = plist->scale_x;
242  file_info->transform.scaleY = plist->scale_y;
243  file_info->transform.mirrorAroundX = plist->mirror_x;
244  file_info->transform.mirrorAroundY = plist->mirror_y;
245  file_info->isVisible = plist->visible;
246 
247  plist = plist->next;
248  }
249  }
250 
251  project_destroy_project_list(list);
252 
253  /* Save project filename for later use */
254  if (gerbvProject->project) {
255  g_free(gerbvProject->project);
256  gerbvProject->project = NULL;
257  }
258  gerbvProject->project = g_strdup(filename);
259  if (gerbvProject->project == NULL)
260  GERB_FATAL_ERROR(_("malloc gerbvProject->project failed"));
261 } /* gerbv_open_project_from_filename */
262 
263 /* ------------------------------------------------------------------ */
264 void
265 main_save_project_from_filename(gerbv_project_t *gerbvProject, gchar *filename)
266 {
267  project_list_t *list, *plist;
268  gchar *dirName = g_path_get_dirname (filename);
269  gerbv_fileinfo_t *file_info;
270  int idx;
271 
272  list = g_new0 (project_list_t, 1);
273  list->next = NULL;
274  list->layerno = -1;
275  list->filename = g_strdup(gerbvProject->path);
276  list->rgb[0] = gerbvProject->background.red;
277  list->rgb[1] = gerbvProject->background.green;
278  list->rgb[2] = gerbvProject->background.blue;
279 
280  /* loop over all layer files */
281  for (idx = 0; idx <= gerbvProject->last_loaded; idx++) {
282  if (gerbvProject->file[idx]) {
283  plist = g_new0 (project_list_t, 1);
284  plist->next = list;
285  plist->layerno = idx;
286 
287  /* figure out the relative path to the layer from the project
288  directory */
289  if (strncmp (dirName, gerbvProject->file[idx]->fullPathname, strlen(dirName)) == 0) {
290  /* skip over the common dirname and the separator */
291  plist->filename = g_strdup(gerbvProject->file[idx]->fullPathname + strlen(dirName) + 1);
292  } else {
293  /* if we can't figure out a relative path, just save the
294  * absolute one */
295  plist->filename = g_strdup(gerbvProject->file[idx]->fullPathname);
296  }
297  file_info = gerbvProject->file[idx];
298  plist->rgb[0] = file_info->color.red;
299  plist->rgb[1] = file_info->color.green;
300  plist->rgb[2] = file_info->color.blue;
301  plist->alpha = file_info->alpha;
302  plist->inverted = file_info->transform.inverted;
303  plist->visible = file_info->isVisible;
304  plist->translate_x = file_info->transform.translateX;
305  plist->translate_y = file_info->transform.translateY;
306  plist->rotation = file_info->transform.rotation;
307  plist->scale_x = file_info->transform.scaleX;
308  plist->scale_y = file_info->transform.scaleY;
309  plist->mirror_x = file_info->transform.mirrorAroundX;
310  plist->mirror_y = file_info->transform.mirrorAroundY;
311  list= plist;
312  }
313  }
314 
315  if (write_project_file(gerbvProject, gerbvProject->project, list)) {
316  GERB_MESSAGE(_("Failed to write project"));
317  }
318  project_destroy_project_list(list);
319  g_free (dirName);
320 } /* gerbv_save_project_from_filename */
321 
322 /* ------------------------------------------------------------------ */
323 void
324 main_save_as_project_from_filename(gerbv_project_t *gerbvProject, gchar *filename)
325 {
326 
327  /*
328  * Save project filename for later use
329  */
330  if (gerbvProject->project) {
331  g_free(gerbvProject->project);
332  gerbvProject->project = NULL;
333  }
334  gerbvProject->project = g_strdup(filename);
335  if (gerbvProject->project == NULL)
336  GERB_FATAL_ERROR(_("malloc gerbvProject->project failed"));
337  main_save_project_from_filename (gerbvProject, filename);
338 } /* gerbv_save_as_project_from_filename */
339 
340 GArray *log_array_tmp = NULL;
341 
342 /* Temporary log messages handler. It will store log messages before GUI
343  * initialization. */
344 void
345 callbacks_temporary_handle_log_messages(const gchar *log_domain,
346  GLogLevelFlags log_level,
347  const gchar *message, gpointer user_data) {
348  struct log_struct item;
349 
350  item.domain = g_strdup (log_domain);
351  item.level = log_level;
352  item.message = g_strdup (message);
353  g_array_append_val (log_array_tmp, item);
354 
355  g_log_default_handler (log_domain, log_level, message, user_data);
356 }
357 /* ------------------------------------------------------------------ */
358 int
359 main(int argc, char *argv[])
360 {
361  int read_opt;
362  int i,r,g,b,a;
363  int req_width = -1, req_height = -1;
364 #ifdef HAVE_GETOPT_LONG
365  /*int req_x = 0, req_y = 0;*/
366  char *rest;
367 #endif
368  char *project_filename = NULL;
369  gboolean exportFromCommandline = FALSE, userSuppliedOrigin=FALSE, userSuppliedWindow=FALSE,
370  userSuppliedAntiAlias=FALSE, userSuppliedWindowInPixels=FALSE, userSuppliedDpi=FALSE;
371  gint layerctr =0, transformCount = 0, exportType = 0;
372  gdouble initial_rotation = 0.0;
373  gboolean initial_mirror_x = FALSE;
374  gboolean initial_mirror_y = FALSE;
375  gchar *exportFilename = NULL;
376  gfloat userSuppliedOriginX=0.0,userSuppliedOriginY=0.0,userSuppliedDpiX=72.0, userSuppliedDpiY=72.0,
377  userSuppliedWidth=0, userSuppliedHeight=0,
378  userSuppliedBorder = GERBV_DEFAULT_BORDER_COEFF;
379 
380 #if ENABLE_NLS
381  setlocale(LC_ALL, "");
382  bindtextdomain(PACKAGE, LOCALEDIR);
383 # ifdef WIN32
384  bind_textdomain_codeset(PACKAGE, "UTF-8");
385 # endif
386  textdomain(PACKAGE);
387 #endif
388 
389  /*
390  * Setup the screen info. Must do this before getopt, since getopt
391  * eventually will set some variables in screen.
392  */
393  memset((void *)&screen, 0, sizeof(gerbv_screen_t));
394  screen.state = NORMAL;
395 
396  mainProject = gerbv_create_project();
397  mainProject->execname = g_strdup(argv[0]);
398  mainProject->execpath = g_path_get_dirname(argv[0]);
399 
400  /* set default rendering mode */
401 #ifdef WIN32
402  /* Cairo seems to render faster on Windows, so use it for default */
403  screenRenderInfo.renderType = GERBV_RENDER_TYPE_CAIRO_NORMAL;
404 #else
405  screenRenderInfo.renderType = GERBV_RENDER_TYPE_GDK;
406 #endif
407 
408  logToFileOption = FALSE;
409  logToFileFilename = NULL;
410  /*
411  * Now process command line flags
412  */
413  while (
414 #ifdef HAVE_GETOPT_LONG
415  (read_opt = getopt_long(argc, argv, opt_options,
416  longopts, &longopt_idx))
417 #else
418  (read_opt = getopt(argc, argv, opt_options))
419 #endif /* HAVE_GETOPT_LONG */
420  != -1) {
421 
422  switch (read_opt) {
423 #ifdef HAVE_GETOPT_LONG
424  case 0:
425  /* Only long options like GDK/GTK debug */
426  switch (longopt_val) {
427  case 0: /* default value if nothing is set */
428  fprintf(stderr, _("Not handled option %s\n"), longopts[longopt_idx].name);
429  break;
430  case 1: /* geometry */
431  errno = 0;
432  req_width = (int)strtol(optarg, &rest, 10);
433  if (errno) {
434  perror(_("Width"));
435  break;
436  }
437  if (rest[0] != 'x'){
438  fprintf(stderr, _("Split X and Y parameters with an x\n"));
439  break;
440  }
441  rest++;
442  errno = 0;
443  req_height = (int)strtol(rest, &rest, 10);
444  if (errno) {
445  perror(_("Height"));
446  break;
447  }
448  /*
449  if ((rest[0] == 0) || ((rest[0] != '-') && (rest[0] != '+')))
450  break;
451  errno = 0;
452  req_x = (int)strtol(rest, &rest, 10);
453  if (errno) {
454  perror("X");
455  break;
456  }
457  if ((rest[0] == 0) || ((rest[0] != '-') && (rest[0] != '+')))
458  break;
459  errno = 0;
460  req_y = (int)strtol(rest, &rest, 10);
461  if (errno) {
462  perror("Y");
463  break;
464  }
465  */
466  break;
467  default:
468  break;
469  }
470  break;
471 #endif /* HAVE_GETOPT_LONG */
472  case 'B' :
473  if (optarg == NULL) {
474  fprintf(stderr, _("You must specify the border in the format <alpha>.\n"));
475  exit(1);
476  }
477  if (strlen (optarg) > 10) {
478  fprintf(stderr, _("Specified border is not recognized.\n"));
479  exit(1);
480  }
481  sscanf (optarg,"%f",&userSuppliedBorder);
482  if (userSuppliedBorder < 0) {
483  fprintf(stderr, _("Specified border is smaller than zero!\n"));
484  exit(1);
485  }
486  userSuppliedBorder/=100.0;
487  break;
488  case 'D' :
489  if (optarg == NULL) {
490  fprintf(stderr, _("You must give an resolution in the format <DPI_XxDPI_Y> or <DPI_X_and_Y>.\n"));
491  exit(1);
492  }
493  if (strlen (optarg) > 20) {
494  fprintf(stderr, _("Specified resolution is not recognized.\n"));
495  exit(1);
496  }
497  if(strchr(optarg, 'x')!=NULL){
498  sscanf (optarg,"%fx%f",&userSuppliedDpiX,&userSuppliedDpiY);
499  }else{
500  sscanf (optarg,"%f",&userSuppliedDpiX);
501  userSuppliedDpiY = userSuppliedDpiX;
502  }
503  if ((userSuppliedDpiX <= 0) || (userSuppliedDpiY <= 0)) {
504  fprintf(stderr, _("Specified resolution should be greater than 0.\n"));
505  exit(1);
506  }
507  userSuppliedDpi=TRUE;
508  break;
509  case 'O' :
510  if (optarg == NULL) {
511  fprintf(stderr, _("You must give an origin in the format <lower_left_X x lower_left_Y>.\n"));
512  exit(1);
513  }
514  if (strlen (optarg) > 20) {
515  fprintf(stderr, _("Specified origin is not recognized.\n"));
516  exit(1);
517  }
518  sscanf (optarg,"%fx%f",&userSuppliedOriginX,&userSuppliedOriginY);
519  userSuppliedOrigin=TRUE;
520  break;
521  case 'V' :
522  printf(_("gerbv version %s\n"), VERSION);
523  printf(_("Copyright (C) 2001 -- 2008 by Stefan Petersen\n"
524  "and the respective original authors listed in the source files.\n"));
525  exit(0);
526  case 'a' :
527  userSuppliedAntiAlias = TRUE;
528  break;
529  case 'b' : // Set background to this color
530  if (optarg == NULL) {
531  fprintf(stderr, _("You must give an background color in the hex-format <#RRGGBB>.\n"));
532  exit(1);
533  }
534  if ((strlen (optarg) != 7)||(optarg[0]!='#')) {
535  fprintf(stderr, _("Specified color format is not recognized.\n"));
536  exit(1);
537  }
538  r=g=b=-1;
539  sscanf (optarg,"#%2x%2x%2x",&r,&g,&b);
540  if ( (r<0)||(r>255)||(g<0)||(g>255)||(b<0)||(b>255)) {
541 
542  fprintf(stderr, _("Specified color values should be between 00 and FF.\n"));
543  exit(1);
544  }
545  mainProject->background.red = r*257;
546  mainProject->background.green = g*257;
547  mainProject->background.blue = b*257;
548  break;
549  case 'f' : // Set layer colors to this color (foreground color)
550  if (optarg == NULL) {
551  fprintf(stderr, _("You must give an foreground color in the hex-format <#RRGGBB> or <#RRGGBBAA>.\n"));
552  exit(1);
553  }
554  if (((strlen (optarg) != 7)&&(strlen (optarg) != 9))||(optarg[0]!='#')) {
555  fprintf(stderr, _("Specified color format is not recognized.\n"));
556  exit(1);
557  }
558  r=g=b=a=-1;
559  if(strlen(optarg)==7){
560  sscanf (optarg,"#%2x%2x%2x",&r,&g,&b);
561  a=177;
562  }
563  else{
564  sscanf (optarg,"#%2x%2x%2x%2x",&r,&g,&b,&a);
565  }
566 
567  if ( (r<0)||(r>255)||(g<0)||(g>255)||(b<0)||(b>255)||(a<0)||(a>255) ) {
568 
569  fprintf(stderr, _("Specified color values should be between 0x00 (0) and 0xFF (255).\n"));
570  exit(1);
571  }
572  mainDefaultColors[layerctr].red = r;
573  mainDefaultColors[layerctr].green = g;
574  mainDefaultColors[layerctr].blue = b;
575  mainDefaultColors[layerctr].alpha = a;
576  layerctr++;
577  /* just reset the counter back to 0 if we read too many */
578  if (layerctr == NUMBER_OF_DEFAULT_COLORS)
579  layerctr = 0;
580  break;
581  case 'r' : // Set initial orientation for all layers (rotation)
582  if (optarg == NULL) {
583  fprintf(stderr, _("You must give the initial rotation angle\n"));
584  exit(1);
585  }
586  errno = 0;
587  initial_rotation = (gdouble)strtod(optarg, &rest);
588  if (errno) {
589  perror(_("Rotate"));
590  exit(1);
591  }
592  if (*rest) {
593  fprintf(stderr, _("Failed parsing rotate value\n"));
594  exit(1);
595  }
596  break;
597  case 'm' : // Set initial mirroring state for all layers
598  if (optarg == NULL) {
599  fprintf(stderr, _("You must give the axis to mirror about\n"));
600  exit(1);
601  }
602  if (strchr(optarg, 'x') != NULL || strchr(optarg, 'X') != NULL) {
603  initial_mirror_x = TRUE;
604  }
605  if (strchr(optarg, 'y') != NULL || strchr(optarg, 'Y') != NULL) {
606  initial_mirror_y = TRUE;
607  }
608  if (!(initial_mirror_x || initial_mirror_y)) {
609  fprintf(stderr, _("Failed parsing mirror axis\n"));
610  exit(1);
611  }
612  break;
613  case 'l' :
614  if (optarg == NULL) {
615  fprintf(stderr, _("You must give a filename to send log to\n"));
616  exit(1);
617  }
618  logToFileOption = TRUE;
619  logToFileFilename = optarg;
620  break;
621  case 'o' :
622  if (optarg == NULL) {
623  fprintf(stderr, _("You must give a filename to export to.\n"));
624  exit(1);
625  }
626  exportFilename = optarg;
627  break;
628  case 'p' :
629  if (optarg == NULL) {
630  fprintf(stderr, _("You must give a project filename\n"));
631  exit(1);
632  }
633  project_filename = optarg;
634  break;
635  case 't' :
636  if (optarg == NULL) {
637  fprintf(stderr, _("You must give a filename to read the tools from.\n"));
638  exit(1);
639  }
640  if (!gerbv_process_tools_file(optarg)) {
641  fprintf(stderr, _("*** ERROR processing tools file \"%s\".\n"), optarg);
642  fprintf(stderr, _("Make sure all lines of the file are formatted like this:\n"
643  "T01 0.024\nT02 0.032\nT03 0.040\n...\n"
644  "*** EXITING to prevent erroneous display.\n"));
645  exit(1);
646  }
647  break;
648  case 'T' : // Translate the layer
649  if (optarg == NULL) {
650  fprintf(stderr, _("You must give a translation in the format <X,Y>.\n"));
651  exit(1);
652  }
653  if (strlen (optarg) > 30) {
654  fprintf(stderr, _("The translation format is not recognized.\n"));
655  exit(1);
656  }
657  float transX=0, transY=0;
658 
659  sscanf (optarg,"%f,%f",&transX,&transY);
660  mainDefaultTransformations[transformCount].translateX = transX;
661  mainDefaultTransformations[transformCount].translateY = transY;
662  transformCount++;
663  /* just reset the counter back to 0 if we read too many */
664  if (transformCount == NUMBER_OF_DEFAULT_TRANSFORMATIONS)
665  transformCount = 0;
666  break;
667  case 'w':
668  userSuppliedWindowInPixels = TRUE;
669  case 'W' :
670  if (optarg == NULL) {
671  fprintf(stderr, _("You must give a window size in the format <width x height>.\n"));
672  exit(1);
673  }
674  if (strlen (optarg) > 20) {
675  fprintf(stderr, _("Specified window size is not recognized.\n"));
676  exit(1);
677  }
678  sscanf (optarg, "%fx%f", &userSuppliedWidth, &userSuppliedHeight);
679  if (((userSuppliedWidth < 0.001) || (userSuppliedHeight < 0.001)) ||
680  ((userSuppliedWidth > 2000) || (userSuppliedHeight > 2000))) {
681  fprintf(stderr, _("Specified window size is out of bounds.\n"));
682  exit(1);
683  }
684  userSuppliedWindow = TRUE;
685  break;
686  case 'x' :
687  if (optarg == NULL) {
688  fprintf(stderr, _("You must supply an export type.\n"));
689  exit(1);
690  }
691  if (strcmp (optarg,"png") == 0) {
692  exportType = 1;
693  exportFromCommandline = TRUE;
694  }
695  else if (strcmp (optarg,"pdf") == 0) {
696  exportType = 2;
697  exportFromCommandline = TRUE;
698  } else if (strcmp (optarg,"svg") == 0) {
699  exportType = 3;
700  exportFromCommandline = TRUE;
701  } else if (strcmp (optarg,"ps") == 0) {
702  exportType = 4;
703  exportFromCommandline = TRUE;
704  }
705  else if (strcmp (optarg,"rs274x") == 0) {
706  exportType = 5;
707  exportFromCommandline = TRUE;
708  }
709  else if (strcmp (optarg,"drill") == 0) {
710  exportType = 6;
711  exportFromCommandline = TRUE;
712  }
713  else {
714  fprintf(stderr, _("Unrecognized export type.\n"));
715  exit(1);
716  }
717  break;
718  case 'd':
719  screen.dump_parsed_image = 1;
720  break;
721  case '?':
722  case 'h':
723 #ifdef HAVE_GETOPT_LONG
724  printf(_("Usage: gerbv [OPTIONS...] [FILE...]\n\n"
725  "Available options:\n"
726  " -B, --border=<b> Border around the image in percent of the\n"
727  " width/height. Defaults to %d%%.\n"
728  " -D, --dpi=<XxY>or<R> Resolution (Dots per inch) for the output\n"
729  " bitmap. With the format <XxY>, different\n"
730  " resolutions for X- and Y-direction are used.\n"
731  " With the format <R>, both are the same.\n"
732  " -O, --origin=<XxY> Use the specified coordinates (in inches).\n"
733  " for the lower left corner.\n"
734  " -V, --version Print version of gerbv.\n"
735  " -a, --antialias Use antialiasing for generated bitmap output.\n"
736  " -b, --background=<hex> Use background color <hex> (like #RRGGBB).\n"
737  " -f, --foreground=<hex> Use foreground color <hex> (like #RRGGBB or\n"
738  " #RRGGBBAA for setting the alpha).\n"
739  " Use multiple -f flags to set the color for\n"
740  " multiple layers.\n"
741  " -r, --rotate=<degree> Set initial orientation for all layers.\n"
742  " -m, --mirror=<axis> Set initial mirroring axis (X or Y).\n"
743  " -h, --help Print this help message.\n"
744  " -l, --log=<logfile> Send error messages to <logfile>.\n"
745  " -o, --output=<filename> Export to <filename>.\n"
746  " -p, --project=<prjfile> Load project file <prjfile>.\n"
747  " -W, --window_inch=<WxH> Window size in inches <WxH> for the\n"
748  " exported image.\n"
749  " -w, --window=<WxH> Window size in pixels <WxH> for the\n"
750  " exported image. Autoscales to fit\n"
751  " if no resolution is specified. If a\n"
752  " resolution is specified, it will clip.\n"
753  " -t, --tools=<toolfile> Read Excellon tools from file <toolfile>.\n"
754  " -T, --translate=<X,Y> Translate the image by <X,Y> (useful for\n"
755  " arranging panels). Use multiple -T flags\n"
756  " for multiple layers.\n"
757  " -x, --export=<png/pdf/ps/svg/ Export a rendered picture to a file with\n"
758  " rs274x/drill> the specified format.\n"),
759  (int)(GERBV_DEFAULT_BORDER_COEFF * 100));
760 #else
761  printf(_("Usage: gerbv [OPTIONS...] [FILE...]\n\n"
762  "Available options:\n"
763  " -B<b> Border around the image in percent of the\n"
764  " width/height. Defaults to %d%%.\n"
765  " -D<XxY>or<R> Resolution (Dots per inch) for the output\n"
766  " bitmap. With the format <XxY>, different\n"
767  " resolutions for X- and Y-direction are used.\n"
768  " With the format <R>, both are the same.\n"
769  " -O<XxY> Use the specified coordinates (in inches)\n"
770  " for the lower left corner.\n"
771  " -V Print version of gerbv.\n"
772  " -a Use antialiasing for generated bitmap output.\n"
773  " -b<hexcolor> Use background color <hexcolor> (like #RRGGBB).\n"
774  " -f<hexcolor> Use foreground color <hexcolor> (like #RRGGBB or\n"
775  " #RRGGBBAA for setting the alpha).\n"
776  " Use multiple -f flags to set the color for\n"
777  " multiple layers.\n"
778  " -r<degree> Set initial orientation for all layers.\n"
779  " -m<axis> Set initial mirroring axis (X or Y).\n"
780  " -h Print this help message.\n"
781  " -l<logfile> Send error messages to <logfile>.\n"
782  " -o<filename> Export to <filename>.\n"
783  " -p<prjfile> Load project file <prjfile>.\n"
784  " -W<WxH> Window size in inches <WxH> for the\n"
785  " exported image.\n"
786  " -w<WxH> Window size in pixels <WxH> for the\n"
787  " exported image. Autoscales to fit\n"
788  " if no resolution is specified. If a\n"
789  " resolution is specified, it will clip.\n"
790  " exported image.\n"
791  " -t<toolfile> Read Excellon tools from file <toolfile>\n"
792  " -T<X,Y> Translate the image by <X,Y> (useful for\n"
793  " arranging panels). Use multiple -T flags\n"
794  " for multiple layers.\n"
795  " -x <png/pdf/ps/svg/ Export a rendered picture to a file with\n"
796  " rs274x/drill> the specified format.\n"),
797  (int)(GERBV_DEFAULT_BORDER_COEFF * 100));
798 
799 #endif /* HAVE_GETOPT_LONG */
800  exit(1);
801  break;
802  default :
803  printf(_("Not handled option [%d=%c]\n"), read_opt, read_opt);
804  }
805  }
806 
807  /*
808  * If project is given, load that one and use it for files and colors.
809  * Else load files (eventually) given on the command line.
810  * This limits you to either give files on the commandline or just load
811  * a project.
812  */
813 
814  log_array_tmp = g_array_new (TRUE, FALSE, sizeof (struct log_struct));
815  g_log_set_handler (NULL,
816  G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION | G_LOG_LEVEL_MASK,
817  callbacks_temporary_handle_log_messages, NULL);
818  if (project_filename) {
819  printf(_("Loading project %s...\n"), project_filename);
820  /* calculate the absolute pathname to the project if the user
821  used a relative path */
822  g_free (mainProject->path);
823  if (!g_path_is_absolute(project_filename)) {
824  gchar *fullName = g_build_filename (g_get_current_dir (),
825  project_filename, NULL);
826  main_open_project_from_filename (mainProject, fullName);
827  mainProject->path = g_path_get_dirname (fullName);
828  g_free (fullName);
829  } else {
830  main_open_project_from_filename (mainProject, project_filename);
831  mainProject->path = g_path_get_dirname (project_filename);
832  }
833  } else {
834  gint loadedIndex = 0;
835  for(i = optind ; i < argc; i++) {
836  g_free (mainProject->path);
837  if (!g_path_is_absolute(argv[i])) {
838  gchar *fullName = g_build_filename (g_get_current_dir (),
839  argv[i], NULL);
840  gerbv_open_layer_from_filename_with_color (mainProject, fullName,
841  mainDefaultColors[loadedIndex % NUMBER_OF_DEFAULT_COLORS].red*257,
842  mainDefaultColors[loadedIndex % NUMBER_OF_DEFAULT_COLORS].green*257,
843  mainDefaultColors[loadedIndex % NUMBER_OF_DEFAULT_COLORS].blue*257,
844  mainDefaultColors[loadedIndex % NUMBER_OF_DEFAULT_COLORS].alpha*257);
845  mainProject->path = g_path_get_dirname (fullName);
846  g_free (fullName);
847  } else {
848  gerbv_open_layer_from_filename_with_color (mainProject, argv[i],
849  mainDefaultColors[loadedIndex % NUMBER_OF_DEFAULT_COLORS].red*257,
850  mainDefaultColors[loadedIndex % NUMBER_OF_DEFAULT_COLORS].green*257,
851  mainDefaultColors[loadedIndex % NUMBER_OF_DEFAULT_COLORS].blue*257,
852  mainDefaultColors[loadedIndex % NUMBER_OF_DEFAULT_COLORS].alpha*257);
853  mainProject->path = g_path_get_dirname (argv[i]);
854  }
855  loadedIndex++;
856  }
857  }
858 
859  if (initial_rotation != 0.0) {
860  /* Set initial layer orientation */
861 
862  gdouble initial_radians = M_PI*initial_rotation/180;
863 
864  dprintf("Rotating all layers by %.0f degrees\n", (float) initial_rotation);
865  for(i = 0; i < mainProject->max_files; i++) {
866  if (mainProject->file[i])
867  mainProject->file[i]->transform.rotation = initial_radians;
868  }
869  }
870 
871  if (initial_mirror_x || initial_mirror_y) {
872  /* Set initial mirroring of all layers */
873 
874  if (initial_mirror_x) {
875  dprintf("Mirroring all layers about x axis\n");
876  }
877  if (initial_mirror_y) {
878  dprintf("Mirroring all layers about y axis\n");
879  }
880 
881  for (i = 0; i < mainProject->max_files; i++) {
882  if (mainProject->file[i]) {
883  mainProject->file[i]->transform.mirrorAroundX = initial_mirror_x;
884  mainProject->file[i]->transform.mirrorAroundY = initial_mirror_y;
885  }
886  }
887  }
888 
889  screen.unit = GERBV_DEFAULT_UNIT;
890  if (exportFromCommandline) {
891  /* load the info struct with the default values */
892 
893  gboolean freeFilename = FALSE;
894 
895  if (!exportFilename) {
896  if (exportType == 1) {
897  exportFilename = g_strdup ("output.png");
898  } else if (exportType == 2) {
899  exportFilename = g_strdup ("output.pdf");
900  } else if (exportType == 3) {
901  exportFilename = g_strdup ("output.svg");
902  } else if (exportType == 4){
903  exportFilename = g_strdup ("output.ps");
904  } else if (exportType == 5){
905  exportFilename = g_strdup ("output.gbx");
906  } else {
907  exportFilename = g_strdup ("output.cnc");
908  }
909  freeFilename = TRUE;
910  }
911 
913  gerbv_render_get_boundingbox(mainProject, &bb);
914  // Set origin to the left-bottom corner if it is not specified
915  if(!userSuppliedOrigin){
916  userSuppliedOriginX = bb.left;
917  userSuppliedOriginY = bb.top;
918  }
919 
920  float width = bb.right - userSuppliedOriginX + 0.001; // Plus a little extra to prevent from
921  float height = bb.bottom - userSuppliedOriginY + 0.001; // missing items due to round-off errors
922  // If the user did not specify a height and width, autoscale w&h till full size from origin.
923  if(!userSuppliedWindow){
924  userSuppliedWidth = width;
925  userSuppliedHeight = height;
926  }else{
927  // If size was specified in pixels, and no resolution was specified, autoscale resolution till fit
928  if( (!userSuppliedDpi)&& userSuppliedWindowInPixels){
929  userSuppliedDpiX = MIN(((userSuppliedWidth-0.5) / width),((userSuppliedHeight-0.5) / height));
930  userSuppliedDpiY = userSuppliedDpiX;
931  userSuppliedOriginX -= 0.5/userSuppliedDpiX;
932  userSuppliedOriginY -= 0.5/userSuppliedDpiY;
933  }
934  }
935 
936  // Add the border size (if there is one)
937  if(userSuppliedBorder!=0){
938  // If supplied in inches, add a border around the image
939  if(!userSuppliedWindowInPixels){
940  userSuppliedOriginX -= (userSuppliedWidth*userSuppliedBorder)/2.0;
941  userSuppliedOriginY -= (userSuppliedHeight*userSuppliedBorder)/2.0;
942  userSuppliedWidth += userSuppliedWidth*userSuppliedBorder;
943  userSuppliedHeight += userSuppliedHeight*userSuppliedBorder;
944  }
945  // If supplied in pixels, shrink image content for border_size
946  else{
947  userSuppliedOriginX -= ((userSuppliedWidth/userSuppliedDpiX)*userSuppliedBorder)/2.0;
948  userSuppliedOriginY -= ((userSuppliedHeight/userSuppliedDpiX)*userSuppliedBorder)/2.0;
949  userSuppliedDpiX -= (userSuppliedDpiX*userSuppliedBorder);
950  userSuppliedDpiY -= (userSuppliedDpiY*userSuppliedBorder);
951  }
952  }
953 
954  if(!userSuppliedWindowInPixels){
955  userSuppliedWidth *= userSuppliedDpiX;
956  userSuppliedHeight *= userSuppliedDpiY;
957  }
958 
959  // Make sure there is something valid in it. It could become negative if
960  // the userSuppliedOrigin is further than the bb.right or bb.top.
961  if(userSuppliedWidth <=0)
962  userSuppliedWidth = 1;
963  if(userSuppliedHeight <=0)
964  userSuppliedHeight = 1;
965 
966 
967  gerbv_render_info_t renderInfo = {userSuppliedDpiX, userSuppliedDpiY,
968  userSuppliedOriginX, userSuppliedOriginY,
970  userSuppliedWidth,userSuppliedHeight };
971 
972  if (exportType == 1) {
973  gerbv_export_png_file_from_project (mainProject, &renderInfo, exportFilename);
974  } else if (exportType == 2) {
975  gerbv_export_pdf_file_from_project (mainProject, &renderInfo, exportFilename);
976  } else if (exportType == 3) {
977  gerbv_export_svg_file_from_project (mainProject, &renderInfo, exportFilename);
978  } else if (exportType == 4) {
979  gerbv_export_postscript_file_from_project (mainProject, &renderInfo, exportFilename);
980  } else if (exportType == 5) {
981  if (mainProject->file[0]->image) {
982  gerbv_image_t *exportImage;
983  exportImage = gerbv_image_duplicate_image (mainProject->file[0]->image, &mainDefaultTransformations[0]);
984  /* if we have more than one file, we need to merge them before exporting */
985  for(i = mainProject->last_loaded; i > 0; i--) {
986  if (mainProject->file[i]) {
987  gerbv_image_copy_image (mainProject->file[i]->image, &mainDefaultTransformations[i], exportImage);
988  }
989  }
990  gerbv_export_rs274x_file_from_image (exportFilename, exportImage,
991  &mainProject->file[0]->transform);
992  gerbv_destroy_image (exportImage);
993  }
994  else {
995  fprintf(stderr, _("A valid file was not loaded.\n"));
996  exit(1);
997  }
998  } else if (exportType == 6) {
999  if (mainProject->file[0]->image) {
1000  gerbv_image_t *exportImage;
1001  exportImage = gerbv_image_duplicate_image (mainProject->file[0]->image, &mainDefaultTransformations[0]);
1002  /* if we have more than one file, we need to merge them before exporting */
1003  for(i = mainProject->last_loaded; i > 0; i--) {
1004  if (mainProject->file[i]) {
1005  gerbv_image_copy_image (mainProject->file[i]->image, &mainDefaultTransformations[i], exportImage);
1006  }
1007  }
1008  gerbv_export_drill_file_from_image (exportFilename, exportImage,
1009  &mainProject->file[0]->transform);
1010  gerbv_destroy_image (exportImage);
1011  }
1012  else {
1013  fprintf(stderr, _("A valid file was not loaded.\n"));
1014  exit(1);
1015  }
1016  }
1017 
1018  if (freeFilename)
1019  free (exportFilename);
1020  /* exit now and don't start up gtk if this is a command line export */
1021  exit(0);
1022  }
1023  gtk_init (&argc, &argv);
1024  interface_create_gui (req_width, req_height);
1025 
1026  /* we've exited the GTK loop, so free all resources */
1027  render_free_screen_resources();
1028  gerbv_destroy_project (mainProject);
1029  return 0;
1030 } /* main */
1031