gerbv
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 WIN32
38 # include <windows.h>
39 #endif
40 
41 #ifdef HAVE_STRING_H
42 # include <string.h>
43 #endif
44 
45 #ifdef HAVE_UNISTD_H
46 # include <unistd.h>
47 #endif
48 
49 #ifdef HAVE_GETOPT_H
50 # include <getopt.h>
51 #endif
52 
53 #include <glib/gstdio.h>
54 
55 #include "common.h"
56 #include "main.h"
57 #include "callbacks.h"
58 #include "interface.h"
59 #include "render.h"
60 #include "project.h"
61 
62 /* DEBUG printing. #define DEBUG 1 in config.h to use this fcn. */
63 #undef DPRINTF
64 #define DPRINTF(...) do { if (DEBUG) printf(__VA_ARGS__); } while (0)
65 
66 #define NUMBER_OF_DEFAULT_COLORS 18
67 #define NUMBER_OF_DEFAULT_TRANSFORMATIONS 20
68 
69 static void
70 gerbv_print_help(void);
71 
72 static int
73 getopt_configured(int argc, char * const argv[], const char *optstring,
74  const struct option *longopts, int *longindex);
75 static int
76 getopt_lengh_unit(const char *optarg, double *input_div,
77  gerbv_screen_t *screen);
78 
79 static gint
80 compare_strings(gconstpointer a, gconstpointer b)
81 {
82  return g_ascii_strcasecmp((const char *)a, (const char *)b);
83 }
84 
85 static GList *
86 scan_directory(const char *dirpath)
87 {
88  GDir *dir = g_dir_open(dirpath, 0, NULL);
89  if (!dir)
90  return NULL;
91 
92  GList *files = NULL;
93  const gchar *entry;
94  while ((entry = g_dir_read_name(dir)) != NULL) {
95  gchar *fullpath = g_build_filename(dirpath, entry, NULL);
96  if (g_file_test(fullpath, G_FILE_TEST_IS_REGULAR)
97  && gerbv_is_loadable_file(fullpath)) {
98  files = g_list_prepend(files, fullpath);
99  } else {
100  g_free(fullpath);
101  }
102  }
103  g_dir_close(dir);
104 
105  return g_list_sort(files, compare_strings);
106 }
107 
108 static gerbv_layer_color mainDefaultColors[NUMBER_OF_DEFAULT_COLORS] = {
109  {115,115,222,177},
110  {255,127,115,177},
111  {193,0,224,177},
112  {117,242,103,177},
113  {0,195,195,177},
114  {213,253,51,177},
115  {209,27,104,177},
116  {255,197,51,177},
117  {186,186,186,177},
118  {211,211,255,177},
119  {253,210,206,177},
120  {236,194,242,177},
121  {208,249,204,177},
122  {183,255,255,177},
123  {241,255,183,177},
124  {255,202,225,177},
125  {253,238,197,177},
126  {226,226,226,177}
127 };
128 
129 static gerbv_user_transformation_t mainDefaultTransformations[NUMBER_OF_DEFAULT_TRANSFORMATIONS] = {
130  {0,0,1,1,0,FALSE,FALSE,FALSE},
131  {0,0,1,1,0,FALSE,FALSE,FALSE},
132  {0,0,1,1,0,FALSE,FALSE,FALSE},
133  {0,0,1,1,0,FALSE,FALSE,FALSE},
134  {0,0,1,1,0,FALSE,FALSE,FALSE},
135  {0,0,1,1,0,FALSE,FALSE,FALSE},
136  {0,0,1,1,0,FALSE,FALSE,FALSE},
137  {0,0,1,1,0,FALSE,FALSE,FALSE},
138  {0,0,1,1,0,FALSE,FALSE,FALSE},
139  {0,0,1,1,0,FALSE,FALSE,FALSE},
140  {0,0,1,1,0,FALSE,FALSE,FALSE},
141  {0,0,1,1,0,FALSE,FALSE,FALSE},
142  {0,0,1,1,0,FALSE,FALSE,FALSE},
143  {0,0,1,1,0,FALSE,FALSE,FALSE},
144  {0,0,1,1,0,FALSE,FALSE,FALSE},
145  {0,0,1,1,0,FALSE,FALSE,FALSE},
146  {0,0,1,1,0,FALSE,FALSE,FALSE},
147  {0,0,1,1,0,FALSE,FALSE,FALSE},
148  {0,0,1,1,0,FALSE,FALSE,FALSE},
149  {0,0,1,1,0,FALSE,FALSE,FALSE},
150 };
151 
152 #ifdef HAVE_GETOPT_LONG
153 int longopt_val = 0;
154 int longopt_idx = 0;
155 const struct option longopts[] = {
156  /* name has_arg flag val */
157  {"border", required_argument, NULL, 'B'},
158  {"dpi", required_argument, NULL, 'D'},
159  {"version", no_argument, NULL, 'V'},
160  {"origin", required_argument, NULL, 'O'},
161  {"window_inch", required_argument, NULL, 'W'},
162  {"antialias", no_argument, NULL, 'a'},
163  {"background", required_argument, NULL, 'b'},
164  {"dump", no_argument, NULL, 'd'},
165  {"foreground", required_argument, NULL, 'f'},
166  {"rotate", required_argument, NULL, 'r'},
167  {"mirror", required_argument, NULL, 'm'},
168  {"help", no_argument, NULL, 'h'},
169  {"quiet", no_argument, NULL, 'q'},
170  {"log", required_argument, NULL, 'l'},
171  {"output", required_argument, NULL, 'o'},
172  {"project", required_argument, NULL, 'p'},
173  {"tools", required_argument, NULL, 't'},
174  {"translate", required_argument, NULL, 'T'},
175  {"units", required_argument, NULL, 'u'},
176  {"window", required_argument, NULL, 'w'},
177  {"export", required_argument, NULL, 'x'},
178  {"svg-layers", no_argument, &longopt_val, 3},
179  {"svg-cairo", no_argument, &longopt_val, 4},
180  {"geometry", required_argument, &longopt_val, 1},
181  /* GDK/GDK debug flags to be "let through" */
182  {"gtk-module", required_argument, &longopt_val, 2},
183  {"g-fatal-warnings",no_argument, &longopt_val, 2},
184  {"gtk-debug", required_argument, &longopt_val, 2},
185  {"gtk-no-debug", required_argument, &longopt_val, 2},
186  {"gdk-debug", required_argument, &longopt_val, 2},
187  {"gdk-no-debug", required_argument, &longopt_val, 2},
188  {"display", required_argument, &longopt_val, 2},
189  {"sync", no_argument, &longopt_val, 2},
190  {"no-xshm", no_argument, &longopt_val, 2},
191  {"name", required_argument, &longopt_val, 2},
192  {"class", required_argument, &longopt_val, 2},
193  {0, 0, 0, 0},
194 };
195 #endif /* HAVE_GETOPT_LONG*/
196 const char *opt_options = "VadqhB:D:O:W:b:f:r:m:l:o:p:t:T:u:w:x:";
197 
202 gerbv_screen_t screen;
203 
204 gboolean logToFileOption;
205 gchar *logToFileFilename;
206 static gboolean quietMode = FALSE;
207 static FILE *logFile = NULL;
208 
209 /* Coords like "0x2" parsed by "%fx%f" will result in first number = 2 and
210  second number 0. Replace 'x' in coordinate string with ';'*/
211 static void
212 care_for_x_in_cords(char *string)
213 {
214  char *found;
215  found = strchr(string, 'x');
216  if (!found)
217  found = strchr(string, 'X');
218  if (found)
219  *found = ';';
220 }
221 
222 /* ------------------------------------------------------------------ */
223 void
224 main_open_project_from_filename(gerbv_project_t *gerbvProject, gchar *filename)
225 {
226  project_list_t *list, *plist;
227  gint i, max_layer_num = -1;
228  gerbv_fileinfo_t *file_info;
229 
230  DPRINTF("Opening project = %s\n", (gchar *) filename);
231  list = read_project_file(filename);
232 
233  if (!list) {
234  GERB_COMPILE_WARNING(_("Could not read \"%s\" (loaded %d)"),
235  (gchar *) filename, gerbvProject->last_loaded);
236 
237  return;
238  }
239 
240  /* Get the max layer number in the project list */
241  plist = list;
242  while (plist) {
243  if (plist->layerno > max_layer_num)
244  max_layer_num = plist->layerno;
245 
246  plist = plist->next;
247  }
248 
249  /* Increase the layer count each time and find (if any) the
250  * corresponding entry */
251  for (i = -1; i <= max_layer_num; i++) {
252  plist = list;
253  while (plist) {
254  if (plist->layerno != i) {
255  plist = plist->next;
256  continue;
257  }
258 
259  GdkColor colorTemplate = {0,
260  plist->rgb[0], plist->rgb[1], plist->rgb[2]};
261  if (i == -1) {
262  screen.background_is_from_project= TRUE;
263  gerbvProject->background = colorTemplate;
264  plist = plist->next;
265  continue;
266  }
267 
268  gchar *fullName = NULL;
269  gchar *dirName = NULL;
270  gint fileIndex = gerbvProject->last_loaded + 1;
271 
272  if (!g_path_is_absolute (plist->filename)) {
273  /* Build the full pathname to the layer */
274  dirName = g_path_get_dirname (filename);
275  fullName = g_build_filename (dirName,
276  plist->filename, NULL);
277  } else {
278  fullName = g_strdup (plist->filename);
279  }
280 
281  if (gerbv_open_image(gerbvProject, fullName,
282  fileIndex, FALSE,
283  plist->attr_list,
284  plist->n_attr, TRUE) == -1) {
285  GERB_MESSAGE(_("could not read file: %s"),
286  fullName);
287  plist = plist->next;
288  continue;
289  }
290 
291  g_free (dirName);
292  g_free (fullName);
293 
294  /* Change color from default to from the project list */
295  file_info = gerbvProject->file[fileIndex];
296  file_info->color = colorTemplate;
297  file_info->alpha = plist->alpha;
298  file_info->transform.inverted = plist->inverted;
299  file_info->transform.translateX = plist->translate_x;
300  file_info->transform.translateY = plist->translate_y;
301  file_info->transform.rotation = plist->rotation;
302  file_info->transform.scaleX = plist->scale_x;
303  file_info->transform.scaleY = plist->scale_y;
304  file_info->transform.mirrorAroundX = plist->mirror_x;
305  file_info->transform.mirrorAroundY = plist->mirror_y;
306  file_info->isVisible = plist->visible;
307 
308  plist = plist->next;
309  }
310  }
311 
312  project_destroy_project_list(list);
313 
314  /* Save project filename for later use */
315  if (gerbvProject->project) {
316  g_free(gerbvProject->project);
317  gerbvProject->project = NULL;
318  }
319  gerbvProject->project = g_strdup(filename);
320  if (gerbvProject->project == NULL)
321  GERB_FATAL_ERROR("malloc gerbvProject->project failed in %s()",
322  __FUNCTION__);
323 } /* gerbv_open_project_from_filename */
324 
325 /* ------------------------------------------------------------------ */
326 void
327 main_save_project_from_filename(gerbv_project_t *gerbvProject, gchar *filename)
328 {
329  project_list_t *list, *plist;
330  gchar *dirName = g_path_get_dirname (filename);
331  gerbv_fileinfo_t *file_info;
332  int idx;
333 
334  list = g_new0 (project_list_t, 1);
335  list->next = NULL;
336  list->layerno = -1;
337  list->filename = g_strdup(gerbvProject->path);
338  list->rgb[0] = gerbvProject->background.red;
339  list->rgb[1] = gerbvProject->background.green;
340  list->rgb[2] = gerbvProject->background.blue;
341 
342  /* loop over all layer files */
343  for (idx = 0; idx <= gerbvProject->last_loaded; idx++) {
344  if (gerbvProject->file[idx]) {
345  plist = g_new0 (project_list_t, 1);
346  plist->next = list;
347  plist->layerno = idx;
348 
349  /* figure out the relative path to the layer from the project
350  directory */
351  if (strncmp (dirName, gerbvProject->file[idx]->fullPathname, strlen(dirName)) == 0) {
352  /* skip over the common dirname and the separator */
353  plist->filename = g_strdup(gerbvProject->file[idx]->fullPathname + strlen(dirName) + 1);
354  } else {
355  /* if we can't figure out a relative path, just save the
356  * absolute one */
357  plist->filename = g_strdup(gerbvProject->file[idx]->fullPathname);
358  }
359  file_info = gerbvProject->file[idx];
360  plist->rgb[0] = file_info->color.red;
361  plist->rgb[1] = file_info->color.green;
362  plist->rgb[2] = file_info->color.blue;
363  plist->alpha = file_info->alpha;
364  plist->inverted = file_info->transform.inverted;
365  plist->visible = file_info->isVisible;
366  plist->translate_x = file_info->transform.translateX;
367  plist->translate_y = file_info->transform.translateY;
368  plist->rotation = file_info->transform.rotation;
369  plist->scale_x = file_info->transform.scaleX;
370  plist->scale_y = file_info->transform.scaleY;
371  plist->mirror_x = file_info->transform.mirrorAroundX;
372  plist->mirror_y = file_info->transform.mirrorAroundY;
373  list= plist;
374  }
375  }
376 
377  if (write_project_file(gerbvProject, gerbvProject->project, list)) {
378  GERB_MESSAGE(_("Failed to write project"));
379  }
380  project_destroy_project_list(list);
381  g_free (dirName);
382 } /* gerbv_save_project_from_filename */
383 
384 /* ------------------------------------------------------------------ */
385 void
386 main_save_as_project_from_filename(gerbv_project_t *gerbvProject, gchar *filename)
387 {
388 
389  /*
390  * Save project filename for later use
391  */
392  if (gerbvProject->project) {
393  g_free(gerbvProject->project);
394  gerbvProject->project = NULL;
395  }
396  gerbvProject->project = g_strdup(filename);
397  if (gerbvProject->project == NULL)
398  GERB_FATAL_ERROR("malloc gerbvProject->project failed in %s()",
399  __FUNCTION__);
400  main_save_project_from_filename (gerbvProject, filename);
401 } /* gerbv_save_as_project_from_filename */
402 
403 GArray *log_array_tmp = NULL;
404 
405 /* Temporary log messages handler. It will store log messages before GUI
406  * initialization. In CLI mode this is the only handler, so it also formats
407  * messages for stderr with clean severity prefixes and respects --quiet. */
408 void
409 callbacks_temporary_handle_log_messages(const gchar *log_domain,
410  GLogLevelFlags log_level,
411  const gchar *message, gpointer user_data) {
412  struct log_struct item;
413  GLogLevelFlags level = log_level & G_LOG_LEVEL_MASK;
414 
415  /* Store for GUI replay */
416  item.domain = g_strdup (log_domain);
417  item.level = log_level;
418  item.message = g_strdup (message);
419  g_array_append_val (log_array_tmp, item);
420 
421  /* Print unless suppressed by quiet mode (INFO = note, DEBUG) */
422  if (!(quietMode && (level & (G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG)))) {
423  const gchar *prefix;
424 
425  switch (level) {
426  case G_LOG_LEVEL_ERROR: prefix = "fatal"; break;
427  case G_LOG_LEVEL_CRITICAL: prefix = "error"; break;
428  case G_LOG_LEVEL_WARNING: prefix = "warning"; break;
429  case G_LOG_LEVEL_MESSAGE: prefix = "info"; break;
430  case G_LOG_LEVEL_INFO: prefix = "note"; break;
431  case G_LOG_LEVEL_DEBUG: prefix = "debug"; break;
432  default: prefix = "log"; break;
433  }
434 
435  fprintf(stderr, "%s: %s\n", prefix, message);
436 
437  if (logFile)
438  fprintf(logFile, "%s: %s\n", prefix, message);
439  }
440 
441  /* GLib expects the default handler to abort on fatal errors */
442  if (log_level & G_LOG_FLAG_FATAL)
443  g_log_default_handler (log_domain, log_level, message, user_data);
444 }
445 
446 #ifdef WIN32
447 static void
448 wait_console_for_win(void)
449 {
450  FILE *console = fopen("CONOUT$", "w");
451 
452  fprintf(console, _("\n*** Press Enter to continue ***"));
453  fflush(console);
454 }
455 
456 /* Attach console in application which is build with -mwindows flag */
457 static void
458 attach_console_for_win(void)
459 {
460  if (((HANDLE)_get_osfhandle(fileno(stdout)) == INVALID_HANDLE_VALUE
461  || (HANDLE)_get_osfhandle(fileno(stderr)) == INVALID_HANDLE_VALUE)
462  && AttachConsole(ATTACH_PARENT_PROCESS)) {
463 
464  if ((HANDLE)_get_osfhandle(fileno (stdout)) == INVALID_HANDLE_VALUE)
465  freopen("CONOUT$", "w", stdout);
466 
467  if ((HANDLE)_get_osfhandle(fileno (stderr)) == INVALID_HANDLE_VALUE)
468  freopen("CONOUT$", "w", stderr);
469 
470  atexit(wait_console_for_win);
471  }
472 }
473 #else
474 static void
475 attach_console_for_win(void) {}
476 #endif
477 
478 /* ------------------------------------------------------------------ */
479 int
480 main(int argc, char *argv[])
481 {
482  int read_opt;
483  int i,r,g,b,a;
484  int req_width = -1, req_height = -1;
485 #ifdef HAVE_GETOPT_LONG
486  char *rest;
487 #endif
488  char *project_filename = NULL;
489  gboolean userSuppliedOrigin=FALSE, userSuppliedWindow=FALSE,
490  userSuppliedAntiAlias=FALSE, userSuppliedWindowInPixels=FALSE, userSuppliedDpi=FALSE;
491  gint layerctr =0, transformCount = 0;
492  gdouble initial_rotation = 0.0;
493  gdouble input_divisor = 1.0; /* 1.0 for inch */
494  int unit_flag_counter;
495  gboolean initial_mirror_x = FALSE;
496  gboolean initial_mirror_y = FALSE;
497  gboolean svgLayers = FALSE;
498  const gchar *exportFilename = NULL;
499  gfloat userSuppliedOriginX=0.0,userSuppliedOriginY=0.0,userSuppliedDpiX=72.0, userSuppliedDpiY=72.0,
500  userSuppliedWidth=0, userSuppliedHeight=0,
501  userSuppliedBorder = GERBV_DEFAULT_BORDER_COEFF;
502 
503  gerbv_image_t *exportImage;
504 
505  enum exp_type {
506  EXP_TYPE_NONE = -1,
507  EXP_TYPE_PNG,
508  EXP_TYPE_PDF,
509  EXP_TYPE_SVG,
510  EXP_TYPE_PS,
511  EXP_TYPE_RS274X,
512  EXP_TYPE_DRILL,
513  EXP_TYPE_IDRILL,
514  EXP_TYPE_DXF,
515  };
516  enum exp_type exportType = EXP_TYPE_NONE;
517  const char *export_type_names[] = {
518  "png",
519  "pdf",
520  "svg",
521  "ps",
522  "rs274x",
523  "drill",
524  "idrill",
525  "dxf",
526  NULL
527  };
528  const gchar *export_def_file_names[] = {
529  "output.png",
530  "output.pdf",
531  "output.svg",
532  "output.ps",
533  "output.gbx",
534  "output.cnc",
535  "output.ncp",
536  "output.dxf",
537  NULL
538  };
539 
540  const gchar *settings_schema_env = "GSETTINGS_SCHEMA_DIR";
541 #ifdef WIN32
542  /* On Windows executable can be not in bin/ dir */
543  const gchar *settings_schema_fallback_dir =
544  "share/glib-2.0/schemas" G_SEARCHPATH_SEPARATOR_S
545  "../share/glib-2.0/schemas";
546 #else
547  const gchar *settings_schema_fallback_dir = "../share/glib-2.0/schemas";
548 #endif
549  gchar *env_val;
550 
551 #ifdef ENABLE_NLS
552  setlocale(LC_ALL, "");
553  bindtextdomain(PACKAGE, GERBV_LOCALEDIR);
554 # ifdef WIN32
555  bind_textdomain_codeset(PACKAGE, "UTF-8");
556 # endif
557  textdomain(PACKAGE);
558 #endif
559 
560  attach_console_for_win();
561 
562 #ifdef WIN32
563  /* Convert argv from system codepage to UTF-8 for GLib functions.
564  * The original argv[i] pointers (owned by the C runtime) are
565  * intentionally overwritten and leaked — the converted strings
566  * must live for the entire process lifetime, and argv is not
567  * freed by the caller. This block only runs on Windows, so it
568  * will not appear in Linux Valgrind runs. */
569  for (i = 0; i < argc; i++) {
570  gchar *utf8_arg = g_locale_to_utf8(argv[i], -1, NULL, NULL, NULL);
571  if (utf8_arg) {
572  argv[i] = utf8_arg;
573  }
574  }
575 #endif
576 
577  /*
578  * Setup the screen info. Must do this before getopt, since getopt
579  * eventually will set some variables in screen.
580  */
581  memset((void *)&screen, 0, sizeof(gerbv_screen_t));
582  screen.state = NORMAL;
583  screen.unit = GERBV_DEFAULT_UNIT;
584 
586  mainProject->execname = g_strdup(argv[0]);
587  mainProject->execpath = g_path_get_dirname(argv[0]);
588 
589  /* Add "fallback" directory with settings schema file from this
590  * executable path */
591  if (NULL == g_getenv(settings_schema_env))
592  /* Empty env var */
593  env_val = g_strconcat(
594  mainProject->execpath, G_DIR_SEPARATOR_S,
595  settings_schema_fallback_dir,
596  NULL);
597  else
598  /* Not empty env var */
599  env_val = g_strconcat(g_getenv(settings_schema_env),
600  G_SEARCHPATH_SEPARATOR_S,
601  mainProject->execpath, G_DIR_SEPARATOR_S,
602  settings_schema_fallback_dir,
603  NULL);
604  g_setenv(settings_schema_env, env_val, TRUE);
605  g_free(env_val);
606 
607 #ifdef WIN32
608  /* Suppress "GdkPixbuf-WARNING: Error loading XPM image loader"
609  * on Windows. gerbv doesn't use any GdkPixbuf loaders — image
610  * export uses Cairo, and the only XPM usage is inline data via
611  * gdk_pixmap_create_from_xpm_d(). Point GDK_PIXBUF_MODULE_FILE
612  * at an empty cache so GdkPixbuf skips loader enumeration. */
613  if (!g_getenv("GDK_PIXBUF_MODULE_FILE")) {
614  gchar *cache_dir = g_build_filename(
615  g_get_user_cache_dir(), "gerbv", NULL);
616  g_mkdir_with_parents(cache_dir, 0755);
617  gchar *cache_path = g_build_filename(
618  cache_dir, "loaders.cache", NULL);
619 
620  if (!g_file_test(cache_path, G_FILE_TEST_EXISTS)) {
621  g_file_set_contents(cache_path,
622  "# GdkPixbuf Image Loader Modules file\n"
623  "# Intentionally empty — gerbv uses no loaders\n",
624  -1, NULL);
625  }
626 
627  g_setenv("GDK_PIXBUF_MODULE_FILE", cache_path, FALSE);
628  g_free(cache_path);
629  g_free(cache_dir);
630  }
631 #endif
632 
633  /* set default rendering mode */
634 #ifdef WIN32
635  /* Cairo seems to render faster on Windows, so use it for default */
636  screenRenderInfo.renderType = GERBV_RENDER_TYPE_CAIRO_NORMAL;
637 #else
638  screenRenderInfo.renderType = GERBV_RENDER_TYPE_GDK;
639 #endif
640 
641  logToFileOption = FALSE;
642  logToFileFilename = NULL;
643 
644  log_array_tmp = g_array_new (TRUE, FALSE, sizeof (struct log_struct));
645  g_log_set_handler (NULL,
646  G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION | G_LOG_LEVEL_MASK,
647  callbacks_temporary_handle_log_messages, NULL);
648 
649 
650  /* 1. Process flags needed before main option parsing */
651  unit_flag_counter = 0;
652  opterr = 0; /* Disable getopt() error messages */
653  while (-1 != (read_opt = getopt_configured(argc, argv, opt_options,
654  longopts, &longopt_idx))) {
655  switch (read_opt) {
656  case 'q':
657  quietMode = TRUE;
658  break;
659  case 'u':
660  unit_flag_counter++;
661 
662  if (!getopt_lengh_unit(optarg, &input_divisor, &screen))
663  GERB_COMPILE_WARNING(
664  _("Unrecognized length unit \"%s\" in command line"),
665  optarg);
666 
667  break;
668  }
669  }
670 
671  /* 2. Process all other command line flags */
672  optind = 0; /* Reset getopt() index */
673  opterr = 1; /* Enable getopt() error messages */
674  while (-1 != (read_opt = getopt_configured(argc, argv, opt_options,
675  longopts, &longopt_idx))) {
676  switch (read_opt) {
677 #ifdef HAVE_GETOPT_LONG
678  case 0:
679  /* Only long options like GDK/GTK debug */
680  switch (longopt_val) {
681  case 0: /* default value if nothing is set */
682  GERB_COMPILE_WARNING(
683  _("Not handled option \"%s\" in command line"),
684  longopts[longopt_idx].name);
685  break;
686  case 1: /* geometry */
687  errno = 0;
688  req_width = (int)strtol(optarg, &rest, 10);
689  if (errno) {
690  perror(_("Width"));
691  break;
692  }
693  if (rest[0] != 'x'){
694  fprintf(stderr, _("Split X and Y parameters with an x\n"));
695  break;
696  }
697  rest++;
698  errno = 0;
699  req_height = (int)strtol(rest, &rest, 10);
700  if (errno) {
701  perror(_("Height"));
702  break;
703  }
704  /*
705  if ((rest[0] == 0) || ((rest[0] != '-') && (rest[0] != '+')))
706  break;
707  errno = 0;
708  req_x = (int)strtol(rest, &rest, 10);
709  if (errno) {
710  perror("X");
711  break;
712  }
713  if ((rest[0] == 0) || ((rest[0] != '-') && (rest[0] != '+')))
714  break;
715  errno = 0;
716  req_y = (int)strtol(rest, &rest, 10);
717  if (errno) {
718  perror("Y");
719  break;
720  }
721  */
722  break;
723  case 3: /* svg-layers */
724  svgLayers = TRUE;
725  break;
726  case 4: /* svg-cairo */
727  mainProject->use_cairo_svg = TRUE;
728  break;
729  default:
730  break;
731  }
732  break;
733 #endif /* HAVE_GETOPT_LONG */
734  case 'B' :
735  if (optarg == NULL) {
736  fprintf(stderr, _("You must specify the border in the format <alpha>.\n"));
737  exit(1);
738  }
739  if (strlen (optarg) > 10) {
740  fprintf(stderr, _("Specified border is not recognized.\n"));
741  exit(1);
742  }
743  sscanf (optarg,"%f",&userSuppliedBorder);
744  if (userSuppliedBorder < 0) {
745  fprintf(stderr, _("Specified border is smaller than zero!\n"));
746  exit(1);
747  }
748  userSuppliedBorder/=100.0;
749  break;
750  case 'D' :
751  if (optarg == NULL) {
752  fprintf(stderr, _("You must give an resolution in the format <DPI_XxDPI_Y> or <DPI_X_and_Y>.\n"));
753  exit(1);
754  }
755  if (strlen (optarg) > 20) {
756  fprintf(stderr, _("Specified resolution is not recognized.\n"));
757  exit(1);
758  }
759  if(strchr(optarg, 'x')!=NULL){
760  sscanf (optarg,"%fx%f",&userSuppliedDpiX,&userSuppliedDpiY);
761  }else{
762  sscanf (optarg,"%f",&userSuppliedDpiX);
763  userSuppliedDpiY = userSuppliedDpiX;
764  }
765  if ((userSuppliedDpiX <= 0) || (userSuppliedDpiY <= 0)) {
766  fprintf(stderr, _("Specified resolution should be greater than 0.\n"));
767  exit(1);
768  }
769  userSuppliedDpi=TRUE;
770  break;
771  case 'O' :
772  if (optarg == NULL) {
773  fprintf(stderr, _("You must give an origin in the format "
774  "<XxY> or <X;Y>.\n"));
775  exit(1);
776  }
777  if (strlen (optarg) > 20) {
778  fprintf(stderr, _("Specified origin is not recognized.\n"));
779  exit(1);
780  }
781 
782  care_for_x_in_cords(optarg);
783  sscanf(optarg,"%f;%f", &userSuppliedOriginX, &userSuppliedOriginY);
784  userSuppliedOriginX /= input_divisor;
785  userSuppliedOriginY /= input_divisor;
786  userSuppliedOrigin=TRUE;
787  break;
788  case 'V' :
789  printf(_("gerbv version %s\n"), VERSION);
790  printf(_("Copyright (C) 2001-2008 by Stefan Petersen\n"
791  "and the respective original authors listed in the source files.\n"));
792  exit(0);
793  case 'a' :
794  userSuppliedAntiAlias = TRUE;
795  break;
796  case 'b' : // Set background to this color
797  if (optarg == NULL) {
798  fprintf(stderr, _("You must give an background color "
799  "in the hex-format <#RRGGBB>.\n"));
800  exit(1);
801  }
802  if ((strlen (optarg) != 7)||(optarg[0]!='#')) {
803  fprintf(stderr, _("Specified color format "
804  "is not recognized.\n"));
805  exit(1);
806  }
807  r=g=b=-1;
808  sscanf (optarg,"#%2x%2x%2x",&r,&g,&b);
809  if ( (r<0)||(r>255)||(g<0)||(g>255)||(b<0)||(b>255)) {
810 
811  fprintf(stderr, _("Specified color values should be "
812  "between 00 and FF.\n"));
813  exit(1);
814  }
815 
816  screen.background_is_from_cmdline = TRUE;
817  mainProject->background.red = r*257;
818  mainProject->background.green = g*257;
819  mainProject->background.blue = b*257;
820 
821  break;
822  case 'f' : // Set layer colors to this color (foreground color)
823  if (optarg == NULL) {
824  fprintf(stderr, _("You must give an foreground color in the hex-format <#RRGGBB> or <#RRGGBBAA>.\n"));
825  exit(1);
826  }
827  if (((strlen (optarg) != 7)&&(strlen (optarg) != 9))||(optarg[0]!='#')) {
828  fprintf(stderr, _("Specified color format is not recognized.\n"));
829  exit(1);
830  }
831  r=g=b=a=-1;
832  if(strlen(optarg)==7){
833  sscanf (optarg,"#%2x%2x%2x",&r,&g,&b);
834  a=177;
835  }
836  else{
837  sscanf (optarg,"#%2x%2x%2x%2x",&r,&g,&b,&a);
838  }
839 
840  if ( (r<0)||(r>255)||(g<0)||(g>255)||(b<0)||(b>255)||(a<0)||(a>255) ) {
841 
842  fprintf(stderr, _("Specified color values should be between 0x00 (0) and 0xFF (255).\n"));
843  exit(1);
844  }
845  mainDefaultColors[layerctr].red = r;
846  mainDefaultColors[layerctr].green = g;
847  mainDefaultColors[layerctr].blue = b;
848  mainDefaultColors[layerctr].alpha = a;
849  layerctr++;
850  /* just reset the counter back to 0 if we read too many */
851  if (layerctr == NUMBER_OF_DEFAULT_COLORS)
852  layerctr = 0;
853  break;
854  case 'r' : // Set initial orientation for all layers (rotation)
855  if (optarg == NULL) {
856  fprintf(stderr, _("You must give the initial rotation angle\n"));
857  exit(1);
858  }
859  errno = 0;
860  initial_rotation = (gdouble)strtod(optarg, &rest);
861  if (errno) {
862  perror(_("Rotate"));
863  exit(1);
864  }
865  if (*rest) {
866  fprintf(stderr, _("Failed parsing rotate value\n"));
867  exit(1);
868  }
869  break;
870  case 'm' : // Set initial mirroring state for all layers
871  if (optarg == NULL) {
872  fprintf(stderr, _("You must give the axis to mirror about\n"));
873  exit(1);
874  }
875  if (strchr(optarg, 'x') != NULL || strchr(optarg, 'X') != NULL) {
876  initial_mirror_x = TRUE;
877  }
878  if (strchr(optarg, 'y') != NULL || strchr(optarg, 'Y') != NULL) {
879  initial_mirror_y = TRUE;
880  }
881  if (!(initial_mirror_x || initial_mirror_y)) {
882  fprintf(stderr, _("Failed parsing mirror axis\n"));
883  exit(1);
884  }
885  break;
886  case 'l' :
887  if (optarg == NULL) {
888  fprintf(stderr, _("You must give a filename to send log to\n"));
889  exit(1);
890  }
891  logToFileOption = TRUE;
892  logToFileFilename = optarg;
893  break;
894  case 'o' :
895  if (optarg == NULL) {
896  fprintf(stderr, _("You must give a filename to export to.\n"));
897  exit(1);
898  }
899  exportFilename = optarg;
900  break;
901  case 'p' :
902  if (optarg == NULL) {
903  fprintf(stderr, _("You must give a project filename\n"));
904  exit(1);
905  }
906  project_filename = optarg;
907  break;
908  case 't' :
909  if (optarg == NULL) {
910  fprintf(stderr, _("You must give a filename to read the tools from.\n"));
911  exit(1);
912  }
913  if (!gerbv_process_tools_file(optarg)) {
914  fprintf(stderr, _("*** ERROR processing tools file \"%s\".\n"), optarg);
915  fprintf(stderr, _("Make sure all lines of the file are formatted like this:\n"
916  "T01 0.024\nT02 0.032\nT03 0.040\n...\n"
917  "*** EXITING to prevent erroneous display.\n"));
918  exit(1);
919  }
920  break;
921  case 'T' : // Translate the layer
922  if (optarg == NULL) {
923  fprintf(stderr, _("You must give a translation in the format "
924  "<XxY> or <X;Y>.\n"));
925  exit(1);
926  }
927  if (strlen (optarg) > 30) {
928  fprintf(stderr, _("The translation format is not recognized.\n"));
929  exit(1);
930  }
931 
932  float transX = 0, transY = 0, rotate = 0;
933 
934  care_for_x_in_cords(optarg);
935  sscanf(optarg, "%f;%fr%f", &transX, &transY, &rotate);
936  transX /= input_divisor;
937  transY /= input_divisor;
938  mainDefaultTransformations[transformCount].translateX = transX;
939  mainDefaultTransformations[transformCount].translateY = transY;
940  mainDefaultTransformations[transformCount].rotation = DEG2RAD(rotate);
941  transformCount++;
942  /* just reset the counter back to 0 if we read too many */
943  if (transformCount == NUMBER_OF_DEFAULT_TRANSFORMATIONS)
944  transformCount = 0;
945  break;
946  case 'u':
947  if (unit_flag_counter == 1)
948  /* Length unit flag occurred only once and processed */
949  break;
950 
951  /* Length unit flag occurred more than once, process each one */
952  if (!getopt_lengh_unit(optarg, &input_divisor, &screen))
953  GERB_COMPILE_WARNING(
954  _("Unrecognized length unit \"%s\" in command line"),
955  optarg);
956 
957  break;
958 
959  case 'w':
960  userSuppliedWindowInPixels = TRUE;
961  [[fallthrough]];
962  case 'W' :
963  if (optarg == NULL) {
964  fprintf(stderr, _("You must give a window size in the format <width x height>.\n"));
965  exit(1);
966  }
967  if (strlen (optarg) > 20) {
968  fprintf(stderr, _("Specified window size is not recognized.\n"));
969  exit(1);
970  }
971  sscanf (optarg, "%fx%f", &userSuppliedWidth, &userSuppliedHeight);
972  if (((userSuppliedWidth < 0.001) || (userSuppliedHeight < 0.001)) ||
973  ((userSuppliedWidth > 2000) || (userSuppliedHeight > 2000))) {
974  fprintf(stderr, _("Specified window size is out of bounds.\n"));
975  exit(1);
976  }
977  userSuppliedWindow = TRUE;
978  break;
979  case 'x' :
980  if (optarg == NULL) {
981  fprintf(stderr, _("You must supply an export type.\n"));
982  exit(1);
983  }
984 
985  for (i = 0; export_type_names[i] != NULL; i++) {
986  if (strcmp (optarg, export_type_names[i]) == 0) {
987  exportType = i;
988  break;
989  }
990  }
991 
992  if (exportType == EXP_TYPE_NONE) {
993  fprintf(stderr, _("Unrecognized \"%s\" export type.\n"),
994  optarg);
995  exit(1);
996  }
997  break;
998  case 'd':
999  screen.dump_parsed_image = 1;
1000  break;
1001  case 'q':
1002  quietMode = TRUE;
1003  break;
1004  case '?':
1005  case 'h':
1006  gerbv_print_help();
1007 
1008  exit(1);
1009  break;
1010  default :
1011  /* This should not be reached */
1012  GERB_COMPILE_WARNING(_("Not handled option '%c' in command line"),
1013  read_opt);
1014  }
1015  }
1016 
1017  if (logToFileOption) {
1018  logFile = g_fopen(logToFileFilename, "w");
1019  if (!logFile) {
1020  int saved_errno = errno;
1021  fprintf(stderr, "error: cannot open log file '%s': %s\n",
1022  logToFileFilename, strerror(saved_errno));
1023  exit(1);
1024  }
1025  }
1026 
1027  /*
1028  * If no project_filename and only file ends in .gvp, use as project file. -erco 02/20/2020
1029  */
1030  if ( !project_filename && // project not set?
1031  optind == (argc-1) && // only one file specified?
1032  gerbv_endswith(argv[optind], ".gvp") ) { // only file ends in .gvp?
1033  project_filename = argv[optind];
1034  }
1035 
1036  /*
1037  * If project is given, load that one and use it for files and colors.
1038  * Else load files (eventually) given on the command line.
1039  * This limits you to either give files on the commandline or just load
1040  * a project.
1041  */
1042 
1043  if (project_filename) {
1044  DPRINTF(_("Loading project %s...\n"), project_filename);
1045  /* calculate the absolute pathname to the project if the user
1046  used a relative path */
1047  g_free (mainProject->path);
1048  if (!g_path_is_absolute(project_filename)) {
1049  gchar *currentDir = g_get_current_dir ();
1050  gchar *fullName = g_build_filename (currentDir,
1051  project_filename, NULL);
1052  main_open_project_from_filename (mainProject, fullName);
1053  mainProject->path = g_path_get_dirname (fullName);
1054  g_free (fullName);
1055  g_free (currentDir);
1056  } else {
1057  main_open_project_from_filename (mainProject, project_filename);
1058  mainProject->path = g_path_get_dirname (project_filename);
1059  }
1060  } else {
1061  gint loadedIndex = 0;
1062  for(i = optind ; i < argc; i++) {
1063  gchar *arg = argv[i];
1064  gchar *absArg;
1065 
1066  if (!g_path_is_absolute(arg)) {
1067  gchar *currentDir = g_get_current_dir();
1068  absArg = g_build_filename(currentDir, arg, NULL);
1069  g_free(currentDir);
1070  } else {
1071  absArg = g_strdup(arg);
1072  }
1073 
1074  if (g_file_test(absArg, G_FILE_TEST_IS_DIR)) {
1075  GList *files = scan_directory(absArg);
1076  if (!files) {
1077  fprintf(stderr,
1078  _("No loadable files found in \"%s\"\n"), arg);
1079  }
1080  for (GList *l = files; l != NULL; l = l->next) {
1081  g_free(mainProject->path);
1083  (gchar *)l->data,
1084  mainDefaultColors[loadedIndex % NUMBER_OF_DEFAULT_COLORS].red*257,
1085  mainDefaultColors[loadedIndex % NUMBER_OF_DEFAULT_COLORS].green*257,
1086  mainDefaultColors[loadedIndex % NUMBER_OF_DEFAULT_COLORS].blue*257,
1087  mainDefaultColors[loadedIndex % NUMBER_OF_DEFAULT_COLORS].alpha*257);
1088  mainProject->path = g_path_get_dirname((gchar *)l->data);
1089  loadedIndex++;
1090  }
1091  g_list_free_full(files, g_free);
1092  } else {
1093  g_free(mainProject->path);
1095  mainDefaultColors[loadedIndex % NUMBER_OF_DEFAULT_COLORS].red*257,
1096  mainDefaultColors[loadedIndex % NUMBER_OF_DEFAULT_COLORS].green*257,
1097  mainDefaultColors[loadedIndex % NUMBER_OF_DEFAULT_COLORS].blue*257,
1098  mainDefaultColors[loadedIndex % NUMBER_OF_DEFAULT_COLORS].alpha*257);
1099  mainProject->path = g_path_get_dirname(absArg);
1100  loadedIndex++;
1101  }
1102  g_free(absArg);
1103  }
1104  }
1105 
1106  if (initial_rotation != 0.0) {
1107  /* Set initial layer orientation */
1108 
1109  gdouble initial_radians = DEG2RAD(initial_rotation);
1110 
1111  DPRINTF("Rotating all layers by %.0f degrees\n", (float) initial_rotation);
1112  for(i = 0; i < mainProject->max_files; i++) {
1113  if (mainProject->file[i])
1114  mainProject->file[i]->transform.rotation = initial_radians;
1115  }
1116  }
1117 
1118  if (initial_mirror_x || initial_mirror_y) {
1119  /* Set initial mirroring of all layers */
1120 
1121  if (initial_mirror_x) {
1122  DPRINTF("Mirroring all layers about x axis\n");
1123  }
1124  if (initial_mirror_y) {
1125  DPRINTF("Mirroring all layers about y axis\n");
1126  }
1127 
1128  for (i = 0; i < mainProject->max_files; i++) {
1129  if (mainProject->file[i]) {
1130  mainProject->file[i]->transform.mirrorAroundX = initial_mirror_x;
1131  mainProject->file[i]->transform.mirrorAroundY = initial_mirror_y;
1132  }
1133  }
1134  }
1135 
1136  if (exportType != EXP_TYPE_NONE) {
1137  /* load the info struct with the default values */
1138 
1139  if (!exportFilename)
1140  exportFilename = export_def_file_names[exportType];
1141 
1143  gerbv_render_get_boundingbox(mainProject, &bb);
1144  // Set origin to the left-bottom corner if it is not specified
1145  if(!userSuppliedOrigin){
1146  userSuppliedOriginX = bb.left;
1147  userSuppliedOriginY = bb.top;
1148  }
1149 
1150  float width = bb.right - userSuppliedOriginX + 0.001; // Plus a little extra to prevent from
1151  float height = bb.bottom - userSuppliedOriginY + 0.001; // missing items due to round-off errors
1152  // If the user did not specify a height and width, autoscale w&h till full size from origin.
1153  if(!userSuppliedWindow){
1154  userSuppliedWidth = width;
1155  userSuppliedHeight = height;
1156  }else{
1157  // If size was specified in pixels, and no resolution was specified, autoscale resolution till fit
1158  if( (!userSuppliedDpi)&& userSuppliedWindowInPixels){
1159  userSuppliedDpiX = MIN((userSuppliedWidth-0.5)/width,
1160  (userSuppliedHeight-0.5)/height);
1161  userSuppliedDpiY = userSuppliedDpiX;
1162  userSuppliedOriginX -= 0.5/userSuppliedDpiX;
1163  userSuppliedOriginY -= 0.5/userSuppliedDpiY;
1164  }
1165  }
1166 
1167  // Add the border size (if there is one)
1168  if(userSuppliedBorder!=0){
1169  // If supplied in inches, add a border around the image
1170  if(!userSuppliedWindowInPixels){
1171  userSuppliedOriginX -= (userSuppliedWidth*userSuppliedBorder)/2.0;
1172  userSuppliedOriginY -= (userSuppliedHeight*userSuppliedBorder)/2.0;
1173  userSuppliedWidth += userSuppliedWidth*userSuppliedBorder;
1174  userSuppliedHeight += userSuppliedHeight*userSuppliedBorder;
1175  }
1176  // If supplied in pixels, shrink image content for border_size
1177  else{
1178  userSuppliedOriginX -= ((userSuppliedWidth/userSuppliedDpiX)*userSuppliedBorder)/2.0;
1179  userSuppliedOriginY -= ((userSuppliedHeight/userSuppliedDpiX)*userSuppliedBorder)/2.0;
1180  userSuppliedDpiX -= (userSuppliedDpiX*userSuppliedBorder);
1181  userSuppliedDpiY -= (userSuppliedDpiY*userSuppliedBorder);
1182  }
1183  }
1184 
1185  if(!userSuppliedWindowInPixels){
1186  userSuppliedWidth *= userSuppliedDpiX;
1187  userSuppliedHeight *= userSuppliedDpiY;
1188  }
1189 
1190  // Make sure there is something valid in it. It could become negative if
1191  // the userSuppliedOrigin is further than the bb.right or bb.top.
1192  if(userSuppliedWidth <=0)
1193  userSuppliedWidth = 1;
1194  if(userSuppliedHeight <=0)
1195  userSuppliedHeight = 1;
1196 
1197 
1198  gerbv_render_info_t renderInfo = {userSuppliedDpiX, userSuppliedDpiY,
1199  userSuppliedOriginX, userSuppliedOriginY,
1201  userSuppliedWidth,userSuppliedHeight };
1202 
1203  switch (exportType) {
1204  case EXP_TYPE_PNG:
1206  &renderInfo, exportFilename);
1207  break;
1208  case EXP_TYPE_PDF:
1210  &renderInfo, exportFilename);
1211  break;
1212  case EXP_TYPE_SVG:
1214  &renderInfo, exportFilename, svgLayers);
1215  break;
1216  case EXP_TYPE_PS:
1218  &renderInfo, exportFilename);
1219  break;
1220  case EXP_TYPE_RS274X:
1221  case EXP_TYPE_DRILL:
1222  case EXP_TYPE_IDRILL:
1223  case EXP_TYPE_DXF:
1224  if (!mainProject->file[0]->image) {
1225  fprintf(stderr, _("A valid file was not loaded.\n"));
1226  if (logFile)
1227  fclose(logFile);
1228  exit(1);
1229  }
1230 
1231  exportImage = gerbv_image_duplicate_image(
1232  mainProject->file[0]->image,
1233  &mainDefaultTransformations[0]);
1234 
1235  /* If more than one file, merge them before exporting */
1236  for (i = mainProject->last_loaded; i > 0; i--) {
1237  if (mainProject->file[i])
1239  &mainDefaultTransformations[i], exportImage);
1240  }
1241 
1242  switch (exportType) {
1243  case EXP_TYPE_RS274X:
1244  gerbv_export_rs274x_file_from_image(exportFilename,
1245  exportImage, &mainProject->file[0]->transform);
1246  break;
1247  case EXP_TYPE_DRILL:
1248  gerbv_export_drill_file_from_image(exportFilename,
1249  exportImage, &mainProject->file[0]->transform);
1250  break;
1251  case EXP_TYPE_IDRILL:
1253  exportImage, &mainProject->file[0]->transform);
1254  break;
1255  case EXP_TYPE_DXF:
1256  gerbv_export_dxf_file_from_image(exportFilename,
1257  exportImage, &mainProject->file[0]->transform);
1258  break;
1259  default:
1260  break;
1261  }
1262 
1263  gerbv_destroy_image (exportImage);
1264  break;
1265  default:
1266  fprintf(stderr, _("A valid file was not loaded.\n"));
1267  if (logFile)
1268  fclose(logFile);
1269  exit(1);
1270  }
1271 
1272  /* exit now and don't start up gtk if this is a command line export */
1273  if (logFile)
1274  fclose(logFile);
1275  exit(0);
1276  }
1277  gtk_init (&argc, &argv);
1278  interface_create_gui (req_width, req_height);
1279 
1280  /* we've exited the GTK loop, so free all resources */
1281  render_free_screen_resources();
1283  if (logFile)
1284  fclose(logFile);
1285  return 0;
1286 } /* main */
1287 
1288 static int
1289 getopt_configured(int argc, char * const argv[], const char *optstring,
1290  const struct option *longopts, int *longindex)
1291 {
1292 #ifdef HAVE_GETOPT_LONG
1293  return getopt_long(argc, argv, optstring, longopts, longindex);
1294 #else
1295  return getopt(argc, argv, optstring);
1296 #endif
1297 }
1298 
1299 static int
1300 getopt_lengh_unit(const char *optarg, double *input_div, gerbv_screen_t *screen)
1301 {
1302  if (strncasecmp(optarg, "mm", 2) == 0) {
1303  *input_div = 25.4;
1304  screen->unit = GERBV_MMS;
1305  screen->unit_is_from_cmdline = TRUE;
1306  } else if (strncasecmp(optarg, "mil", 3) == 0) {
1307  *input_div = 1000.0;
1308  screen->unit = GERBV_MILS;
1309  screen->unit_is_from_cmdline = TRUE;
1310  } else if (strncasecmp(optarg, "inch", 4) == 0) {
1311  *input_div = 1.0;
1312  screen->unit = GERBV_INS;
1313  screen->unit_is_from_cmdline = TRUE;
1314  } else {
1315  return 0;
1316  }
1317 
1318  return 1;
1319 }
1320 
1321 static void
1322 gerbv_print_help(void)
1323 {
1324  printf(_(
1325 "Usage: gerbv [OPTIONS...] [FILE...]\n"
1326 "\n"
1327 "Available options:\n"));
1328 
1329 #ifdef HAVE_GETOPT_LONG
1330  printf(_(
1331 " -B, --border=<b> Border around the image in percent of the\n"
1332 " width/height. Defaults to %d%%.\n"),
1333  (int)(100*GERBV_DEFAULT_BORDER_COEFF));
1334 #else
1335  printf(_(
1336 " -B<b> Border around the image in percent of the\n"
1337 " width/height. Defaults to %d%%.\n"),
1338  (int)(100*GERBV_DEFAULT_BORDER_COEFF));
1339 #endif
1340 
1341 #ifdef HAVE_GETOPT_LONG
1342  printf(_(
1343 " -D, --dpi=<XxY|R> Resolution (Dots per inch) for the output\n"
1344 " bitmap. With the format <XxY>, different\n"
1345 " resolutions for X- and Y-direction are used.\n"
1346 " With the format <R>, both are the same.\n"));
1347 #else
1348  printf(_(
1349 " -D<XxY|R> Resolution (Dots per inch) for the output\n"
1350 " bitmap. With the format <XxY>, different\n"
1351 " resolutions for X- and Y-direction are used.\n"
1352 " With the format <R>, both are the same.\n"));
1353 #endif
1354 
1355 #ifdef HAVE_GETOPT_LONG
1356  printf(_(
1357 " -O, --origin=<XxY|X;Y> Use the specified coordinates (in inches)\n"
1358 " for the lower left corner.\n"));
1359 #else
1360  printf(_(
1361 " -O<XxY|X;Y> Use the specified coordinates (in inches)\n"
1362 " for the lower left corner.\n"));
1363 #endif
1364 
1365 #ifdef HAVE_GETOPT_LONG
1366  printf(_(
1367 " -V, --version Print version of Gerbv.\n"));
1368 #else
1369  printf(_(
1370 " -V Print version of Gerbv.\n"));
1371 #endif
1372 
1373 #ifdef HAVE_GETOPT_LONG
1374  printf(_(
1375 " -a, --antialias Use antialiasing for generated bitmap output.\n"));
1376 #else
1377  printf(_(
1378 " -a Use antialiasing for generated bitmap output.\n"));
1379 #endif
1380 
1381 #ifdef HAVE_GETOPT_LONG
1382  printf(_(
1383 " -b, --background=<hex> Use background color <hex> (like #RRGGBB).\n"));
1384 #else
1385  printf(_(
1386 " -b<hexcolor> Use background color <hexcolor> (like #RRGGBB).\n"));
1387 #endif
1388 
1389 #ifdef HAVE_GETOPT_LONG
1390  printf(_(
1391 " -f, --foreground=<hex> Use foreground color <hex> (like #RRGGBB or\n"
1392 " #RRGGBBAA for setting the alpha).\n"
1393 " Use multiple -f flags to set the color for\n"
1394 " multiple layers.\n"));
1395 #else
1396  printf(_(
1397 " -f<hexcolor> Use foreground color <hexcolor> (like #RRGGBB or\n"
1398 " #RRGGBBAA for setting the alpha).\n"
1399 " Use multiple -f flags to set the color for\n"
1400 " multiple layers.\n"));
1401 #endif
1402 
1403 #ifdef HAVE_GETOPT_LONG
1404  printf(_(
1405 " -r, --rotate=<degree> Set initial orientation for all layers.\n"));
1406 #else
1407  printf(_(
1408 " -r<degree> Set initial orientation for all layers.\n"));
1409 #endif
1410 
1411 #ifdef HAVE_GETOPT_LONG
1412  printf(_(
1413 " -m, --mirror=<axis> Set initial mirroring axis (X or Y).\n"));
1414 #else
1415  printf(_(
1416 " -m<axis> Set initial mirroring axis (X or Y).\n"));
1417 #endif
1418 
1419 #ifdef HAVE_GETOPT_LONG
1420  printf(_(
1421 " -h, --help Print this help message.\n"));
1422 #else
1423  printf(_(
1424 " -h Print this help message.\n"));
1425 #endif
1426 
1427 #ifdef HAVE_GETOPT_LONG
1428  printf(_(
1429 " -l, --log=<logfile> Send error messages to <logfile>.\n"));
1430 #else
1431  printf(_(
1432 " -l<logfile> Send error messages to <logfile>.\n"));
1433 #endif
1434 
1435 #ifdef HAVE_GETOPT_LONG
1436  printf(_(
1437 " -q, --quiet Suppress note-level messages.\n"));
1438 #else
1439  printf(_(
1440 " -q Suppress note-level messages.\n"));
1441 #endif
1442 
1443 #ifdef HAVE_GETOPT_LONG
1444  printf(_(
1445 " -o, --output=<filename> Export to <filename>.\n"));
1446 #else
1447  printf(_(
1448 " -o<filename> Export to <filename>.\n"));
1449 #endif
1450 
1451 #ifdef HAVE_GETOPT_LONG
1452  printf(_(
1453 " -p, --project=<prjfile> Load project file <prjfile>.\n"));
1454 #else
1455  printf(_(
1456 " -p<prjfile> Load project file <prjfile>.\n"));
1457 #endif
1458 
1459 #ifdef HAVE_GETOPT_LONG
1460  printf(_(
1461 " -u, --units=<inch|mm|mil>\n"
1462 " Use given unit for coordinates.\n"
1463 " Default to inch.\n"));
1464 #else
1465  printf(_(
1466 " -u<inch|mm|mil> Use given unit for coordinates.\n"
1467 " Default to inch.\n"));
1468 #endif
1469 
1470 #ifdef HAVE_GETOPT_LONG
1471  printf(_(
1472 " -W, --window_inch=<WxH> Window size in inches <WxH> for the exported image.\n"));
1473 #else
1474  printf(_(
1475 " -W<WxH> Window size in inches <WxH> for the exported image.\n"));
1476 #endif
1477 
1478 #ifdef HAVE_GETOPT_LONG
1479  printf(_(
1480 " -w, --window=<WxH> Window size in pixels <WxH> for the exported image.\n"
1481 " Autoscales to fit if no resolution is specified.\n"
1482 " If a resolution is specified, it will clip\n"
1483 " exported image.\n"));
1484 #else
1485  printf(_(
1486 " -w<WxH> Window size in pixels <WxH> for the exported image.\n"
1487 " Autoscales to fit if no resolution is specified.\n"
1488 " If a resolution is specified, it will clip\n"
1489 " exported image.\n"));
1490 #endif
1491 
1492 #ifdef HAVE_GETOPT_LONG
1493  printf(_(
1494 " -t, --tools=<toolfile> Read Excellon tools from file <toolfile>.\n"));
1495 #else
1496  printf(_(
1497 " -t<toolfile> Read Excellon tools from file <toolfile>\n"));
1498 #endif
1499 
1500 #ifdef HAVE_GETOPT_LONG
1501  printf(_(
1502 " -T, --translate=<XxYrR| Translate image by X and Y and rotate by R degree.\n"
1503 " X;YrR> Useful for arranging panels.\n"
1504 " Use multiple -T flags for multiple layers.\n"
1505 " Only evaluated when exporting as RS274X or drill.\n"));
1506 #else
1507  printf(_(
1508 " -T<XxYrR|X;YrR> Translate image by X and Y and rotate by R degree.\n"
1509 " Useful for arranging panels.\n"
1510 " Use multiple -T flags for multiple files.\n"
1511 " Only evaluated when exporting as RS274X or drill.\n"));
1512 #endif
1513 
1514 #ifdef HAVE_GETOPT_LONG
1515  printf(_(
1516 " -x, --export=<png|pdf|ps|svg|rs274x|drill|idrill|dxf>\n"
1517 " Export a rendered picture to a file with\n"
1518 " the specified format.\n"));
1519  printf(_(
1520 " --svg-layers Export visible layers as Inkscape SVG layers.\n"
1521 " Only used with --export=svg.\n"));
1522  printf(_(
1523 " --svg-cairo Use Cairo SVG surface (legacy, larger output).\n"
1524 " Only used with --export=svg.\n"));
1525 #else
1526  printf(_(
1527 " -x<png|pdf|ps|svg| Export a rendered picture to a file with\n"
1528 " rs274x|drill| the specified format.\n"
1529 " idrill|dxf>\n"
1530 ));
1531  printf(_(
1532 " --svg-layers Export visible layers as Inkscape SVG layers.\n"
1533 " Only used with -xsvg.\n"));
1534  printf(_(
1535 " --svg-cairo Use Cairo SVG surface (legacy, larger output).\n"
1536 " Only used with -xsvg.\n"));
1537 #endif
1538 
1539 }
Header info for the GUI callback functions.
gboolean gerbv_export_drill_file_from_image(const gchar *filename, gerbv_image_t *inputImage, gerbv_user_transformation_t *transform)
Export an image to a new file in Excellon drill format.
Definition: export-drill.c:42
gboolean gerbv_export_dxf_file_from_image(const gchar *file_name, gerbv_image_t *input_img, gerbv_user_transformation_t *trans)
Export an image to a new file in DXF format.
Definition: export-dxf.cpp:78
void gerbv_export_png_file_from_project(gerbv_project_t *gerbvProject, gerbv_render_info_t *renderInfo, gchar const *filename)
Render a project to a PNG file using user-specified render info.
Definition: export-image.c:229
void gerbv_export_postscript_file_from_project(gerbv_project_t *gerbvProject, gerbv_render_info_t *renderInfo, gchar const *filename)
Render a project to a Postscript file using user-specified render info.
Definition: export-image.c:259
void gerbv_export_svg_file_from_project_with_options(gerbv_project_t *gerbvProject, gerbv_render_info_t *renderInfo, gchar const *filename, gboolean exportLayersAsSvgLayers)
Render a project to a SVG file using user-specified render info and export options.
Definition: export-image.c:283
void gerbv_export_pdf_file_from_project(gerbv_project_t *gerbvProject, gerbv_render_info_t *renderInfo, gchar const *filename)
Render a project to a PDF file using user-specified render info.
Definition: export-image.c:246
gboolean gerbv_export_isel_drill_file_from_image(const gchar *filename, gerbv_image_t *inputImage, gerbv_user_transformation_t *transform)
Export an image to a new file in ISEL NCP drill format.
gboolean gerbv_export_rs274x_file_from_image(const gchar *filename, gerbv_image_t *inputImage, gerbv_user_transformation_t *transform)
Export an image to a new file in RS274X format.
void gerbv_destroy_image(gerbv_image_t *image)
Free an image structure.
Definition: gerb_image.c:106
void gerbv_image_copy_image(gerbv_image_t *sourceImage, gerbv_user_transformation_t *transform, gerbv_image_t *destinationImage)
Copy an image into an existing image, effectively merging the two together.
Definition: gerb_image.c:958
gerbv_image_t * gerbv_image_duplicate_image(gerbv_image_t *sourceImage, gerbv_user_transformation_t *transform)
Duplicate an existing image and return the new copy.
Definition: gerb_image.c:920
int gerbv_open_image(gerbv_project_t *gerbvProject, gchar const *filename, int idx, int reload, gerbv_HID_Attribute *fattr, int n_fattr, gboolean forceLoadFile)
Definition: gerbv.c:482
void gerbv_destroy_project(gerbv_project_t *gerbvProject)
Free a project and all related variables.
Definition: gerbv.c:207
void gerbv_open_layer_from_filename_with_color(gerbv_project_t *gerbvProject, gchar const *filename, guint16 red, guint16 green, guint16 blue, guint16 alpha)
Open a file, parse the contents, and add a new layer to an existing project while setting the color o...
Definition: gerbv.c:260
gerbv_project_t * gerbv_create_project(void)
Create a new project structure and initialize some important variables.
Definition: gerbv.c:190
gboolean gerbv_is_loadable_file(const char *filename)
Definition: gerbv.c:656
gboolean gerbv_endswith(const char *path, const char *ext)
Definition: gerbv.c:1191
The main header file for the libgerbv library.
@ GERBV_RENDER_TYPE_CAIRO_HIGH_QUALITY
Definition: gerbv.h:370
@ GERBV_RENDER_TYPE_GDK
Definition: gerbv.h:367
@ GERBV_RENDER_TYPE_CAIRO_NORMAL
Definition: gerbv.h:369
Header info for the GUI building functions for Gerber Viewer.
gerbv_project_t * mainProject
Global state variable to keep track of what's happening on the screen.
Definition: main.c:201
Header info for common structs and functions used for the GUI application.
project_list_t * read_project_file(char const *filename)
Reads the content of a project file.
Definition: project.c:944
Header info for loading and saving project files.
Header info for the rendering support functions for gerbv.
guint16 alpha
Definition: gerbv.h:745
gchar * fullPathname
Definition: gerbv.h:748
gerbv_image_t * image
Definition: gerbv.h:743
gerbv_user_transformation_t transform
Definition: gerbv.h:750
GdkColor color
Definition: gerbv.h:744
gboolean isVisible
Definition: gerbv.h:746
gboolean use_cairo_svg
Definition: gerbv.h:769
gerbv_fileinfo_t ** file
Definition: gerbv.h:759
gchar * project
Definition: gerbv.h:768
GdkColor background
Definition: gerbv.h:757
gchar * execname
Definition: gerbv.h:767
gchar * path
Definition: gerbv.h:765
gchar * execpath
Definition: gerbv.h:766
int max_files
Definition: gerbv.h:758
int last_loaded
Definition: gerbv.h:761
gerbv_render_types_t renderType
Definition: gerbv.h:786