Make ttfautohint reject fonts already processed with ttfautohint.
[ttfautohint.git] / frontend / main.cpp
blobdc51c54c4dfc2ee1c262ae3586f58811449569b1
1 // main.cpp
3 // Copyright (C) 2011-2012 by Werner Lemberg.
4 //
5 // This file is part of the ttfautohint library, and may only be used,
6 // modified, and distributed under the terms given in `COPYING'. By
7 // continuing to use, modify, or distribute this file you indicate that you
8 // have read `COPYING' and understand and accept it fully.
9 //
10 // The file `COPYING' mentioned in the previous paragraph is distributed
11 // with the ttfautohint library.
14 // This program is a wrapper for `TTF_autohint'.
16 #ifdef BUILD_GUI
17 # ifndef _WIN32
18 # define CONSOLE_OUTPUT
19 # endif
20 #else
21 # define CONSOLE_OUTPUT
22 #endif
24 #include <config.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <getopt.h>
31 #include <limits.h>
33 #include <vector>
34 #include <string>
36 #if BUILD_GUI
37 # include <QApplication>
38 # include "maingui.h"
39 #endif
41 #include <ttfautohint.h>
43 using namespace std;
46 #ifndef BUILD_GUI
47 typedef struct Progress_Data_
49 long last_sfnt;
50 bool begin;
51 int last_percent;
52 } Progress_Data;
55 int
56 progress(long curr_idx,
57 long num_glyphs,
58 long curr_sfnt,
59 long num_sfnts,
60 void* user)
62 Progress_Data* data = (Progress_Data*)user;
64 if (num_sfnts > 1 && curr_sfnt != data->last_sfnt)
66 fprintf(stderr, "subfont %ld of %ld\n", curr_sfnt + 1, num_sfnts);
67 data->last_sfnt = curr_sfnt;
68 data->begin = true;
71 if (data->begin)
73 fprintf(stderr, " %ld glyphs\n"
74 " ", num_glyphs);
75 data->begin = false;
78 // print progress approx. every 10%
79 int curr_percent = curr_idx * 100 / num_glyphs;
80 int curr_diff = curr_percent - data->last_percent;
82 if (curr_diff >= 10)
84 fprintf(stderr, " %d%%", curr_percent);
85 data->last_percent = curr_percent - curr_percent % 10;
88 if (curr_idx + 1 == num_glyphs)
89 fprintf(stderr, "\n");
91 return 0;
93 #endif /* !BUILD_GUI */
96 #ifdef CONSOLE_OUTPUT
97 static void
98 show_help(bool all,
99 bool is_error)
101 FILE* handle = is_error ? stderr : stdout;
103 fprintf(handle,
104 "Usage: ttfautohint [OPTION]... IN-FILE OUT-FILE\n"
105 " or: ttfautohintGUI [OPTION]...\n"
106 "Replace hints in TrueType font IN-FILE and write output to OUT-FILE.\n"
107 "The new hints are based on FreeType's autohinter.\n"
108 "\n"
109 "These programs (for console and GUI, respectively)\n"
110 "are simple front-ends to the `ttfautohint' library.\n"
111 "\n");
113 fprintf(handle,
114 "Long options can be given with one or two dashes,\n"
115 "and with and without equal sign between option and argument.\n"
116 "This means that the following forms are acceptable:\n"
117 "`-foo=bar', `--foo=bar', `-foo bar', `--foo bar'.\n"
118 "\n");
120 fprintf(handle,
121 "Options:\n"
122 " -f, --latin-fallback set fallback script to latin\n"
123 " -G, --hinting-limit=N switch off hinting above this PPEM value\n"
124 " (default: %d)\n"
125 " -h, --help display this help and exit\n"
126 " --help-all show Qt and X11 specific options also\n"
127 " -i, --ignore-permissions override font license restrictions\n"
128 " -l, --hinting-range-min=N the minimum PPEM value for hint sets\n"
129 " (default: %d)\n"
130 " -p, --pre-hinting apply original hints in advance\n",
131 TA_HINTING_LIMIT, TA_HINTING_RANGE_MIN);
132 fprintf(handle,
133 " -r, --hinting-range-max=N the maximum PPEM value for hint sets\n"
134 " (default: %d)\n"
135 " -v, --verbose show progress information\n"
136 " -V, --version print version information and exit\n"
137 " -x, --increase-x-height increase x height for small sizes\n"
138 " -X, --x-height-snapping-exceptions=STRING\n"
139 " specify a comma-separated list of\n"
140 " x-height snapping exceptions\n"
141 "\n",
142 TA_HINTING_RANGE_MAX);
144 if (all)
146 fprintf(handle,
147 "Qt Options:\n"
148 " --graphicssystem=SYSTEM\n"
149 " select a different graphics system backend\n"
150 " instead of the default one\n"
151 " (possible values: `raster', `opengl')\n"
152 " --reverse set layout direction to right-to-left\n");
153 fprintf(handle,
154 " --session=ID restore the application for the given ID\n"
155 " --style=STYLE set application GUI style\n"
156 " (possible values: motif, windows, platinum)\n"
157 " --stylesheet=SHEET apply the given Qt stylesheet\n"
158 " to the application widgets\n"
159 "\n");
161 fprintf(handle,
162 "X11 options:\n"
163 " --background=COLOR set the default background color\n"
164 " and an application palette\n"
165 " (light and dark shades are calculated)\n"
166 " --bg=COLOR same as --background\n"
167 " --btn=COLOR set the default button color\n"
168 " --button=COLOR same as --btn\n"
169 " --cmap use a private color map on an 8-bit display\n"
170 " --display=NAME use the given X-server display\n");
171 fprintf(handle,
172 " --fg=COLOR set the default foreground color\n"
173 " --fn=FONTNAME set the application font\n"
174 " --font=FONTNAME same as --fn\n"
175 " --foreground=COLOR same as --fg\n"
176 " --geometry=GEOMETRY set the client geometry of first window\n"
177 " --im=SERVER set the X Input Method (XIM) server\n"
178 " --inputstyle=STYLE set X Input Method input style\n"
179 " (possible values: onthespot, overthespot,\n"
180 " offthespot, root)\n");
181 fprintf(handle,
182 " --name=NAME set the application name\n"
183 " --ncols=COUNT limit the number of colors allocated\n"
184 " in the color cube on an 8-bit display,\n"
185 " if the application is using the\n"
186 " QApplication::ManyColor color specification\n"
187 " --title=TITLE set the application title (caption)\n"
188 " --visual=VISUAL force the application\n"
189 " to use the given visual on an 8-bit display\n"
190 " (only possible value: TrueColor)\n"
191 "\n");
194 fprintf(handle,
195 "The programs accept both TTF and TTC files as input.\n"
196 "Use option -i only if you have a legal permission to modify the font.\n"
197 "If option -f is not set, glyphs not in the latin range stay unhinted.\n"
198 "The used PPEM value for option -p is FUnits per em, normally 2048.\n"
199 "\n");
200 fprintf(handle,
201 "A hint set contains the optimal hinting for a certain PPEM value;\n"
202 "the larger the hint set range, the more hint sets get computed,\n"
203 "usually increasing the output font size. Note, however,\n"
204 "that the `gasp' table of the output file enables grayscale hinting\n"
205 "for all sizes (limited by option -G which is handled in the bytecode).\n"
206 "\n");
207 fprintf(handle,
208 "If run in GUI mode, options not related to Qt or X11 set default values.\n"
209 "Additionally, there is no output to the console.\n"
210 "\n"
211 "GUI support might be disabled at compile time.\n"
212 "\n"
213 "Report bugs to: freetype-devel@nongnu.org\n"
214 "FreeType home page: <http://www.freetype.org>\n");
216 if (is_error)
217 exit(EXIT_FAILURE);
218 else
219 exit(EXIT_SUCCESS);
223 static void
224 show_version()
226 fprintf(stdout,
227 "ttfautohint " VERSION "\n"
228 "Copyright (C) 2011-2012 Werner Lemberg <wl@gnu.org>.\n"
229 "License: FreeType License (FTL) or GNU GPLv2.\n"
230 "This is free software: you are free to change and redistribute it.\n"
231 "There is NO WARRANTY, to the extent permitted by law.\n");
233 exit(EXIT_SUCCESS);
235 #endif /* CONSOLE_OUTPUT */
239 main(int argc,
240 char** argv)
242 int hinting_range_min = 0;
243 int hinting_range_max = 0;
244 int hinting_limit = 0;
245 bool have_hinting_range_min = false;
246 bool have_hinting_range_max = false;
247 bool have_hinting_limit = false;
249 bool ignore_permissions = false;
250 bool pre_hinting = false;
251 bool increase_x_height = false;
252 int latin_fallback = 0; // leave it as int; this probably gets extended
254 #ifndef BUILD_GUI
255 TA_Progress_Func progress_func = NULL;
256 #endif
258 // make GNU, Qt, and X11 command line options look the same;
259 // we allow `--foo=bar', `--foo bar', `-foo=bar', `-foo bar',
260 // and short options specific to ttfautohint
262 // set up a new argument string
263 vector<string> new_arg_string;
264 new_arg_string.push_back(argv[0]);
266 while (1)
268 // use pseudo short options for long-only options
269 enum
271 PASS_THROUGH = CHAR_MAX + 1,
272 HELP_ALL_OPTION
275 static struct option long_options[] =
277 {"help", no_argument, NULL, 'h'},
278 {"help-all", no_argument, NULL, HELP_ALL_OPTION},
280 // ttfautohint options
281 {"hinting-range-max", required_argument, NULL, 'r'},
282 {"hinting-range-min", required_argument, NULL, 'l'},
283 {"hinting-limit", required_argument, NULL, 'G'},
284 {"ignore-permissions", no_argument, NULL, 'i'},
285 {"latin-fallback", no_argument, NULL, 'f'},
286 {"pre-hinting", no_argument, NULL, 'p'},
287 {"verbose", no_argument, NULL, 'v'},
288 {"version", no_argument, NULL, 'V'},
289 {"increase-x-height", no_argument, NULL, 'x'},
290 {"x-height-snapping-exceptions", required_argument, NULL, 'X'},
292 // Qt options
293 {"graphicssystem", required_argument, NULL, PASS_THROUGH},
294 {"reverse", no_argument, NULL, PASS_THROUGH},
295 {"session", required_argument, NULL, PASS_THROUGH},
296 {"style", required_argument, NULL, PASS_THROUGH},
297 {"stylesheet", required_argument, NULL, PASS_THROUGH},
299 // X11 options
300 {"background", required_argument, NULL, PASS_THROUGH},
301 {"bg", required_argument, NULL, PASS_THROUGH},
302 {"btn", required_argument, NULL, PASS_THROUGH},
303 {"button", required_argument, NULL, PASS_THROUGH},
304 {"cmap", no_argument, NULL, PASS_THROUGH},
305 {"display", required_argument, NULL, PASS_THROUGH},
306 {"fg", required_argument, NULL, PASS_THROUGH},
307 {"fn", required_argument, NULL, PASS_THROUGH},
308 {"font", required_argument, NULL, PASS_THROUGH},
309 {"foreground", required_argument, NULL, PASS_THROUGH},
310 {"geometry", required_argument, NULL, PASS_THROUGH},
311 {"im", required_argument, NULL, PASS_THROUGH},
312 {"inputstyle", required_argument, NULL, PASS_THROUGH},
313 {"name", required_argument, NULL, PASS_THROUGH},
314 {"ncols", required_argument, NULL, PASS_THROUGH},
315 {"title", required_argument, NULL, PASS_THROUGH},
316 {"visual", required_argument, NULL, PASS_THROUGH},
318 {NULL, 0, NULL, 0}
321 int option_index;
322 int c = getopt_long_only(argc, argv, "fG:hil:r:ptVvxX:",
323 long_options, &option_index);
324 if (c == -1)
325 break;
327 switch (c)
329 case 'f':
330 latin_fallback = 1;
331 break;
333 case 'G':
334 hinting_limit = atoi(optarg);
335 have_hinting_limit = true;
336 break;
338 case 'h':
339 #ifdef CONSOLE_OUTPUT
340 show_help(false, false);
341 #endif
342 break;
344 case 'i':
345 ignore_permissions = true;
346 break;
348 case 'l':
349 hinting_range_min = atoi(optarg);
350 have_hinting_range_min = true;
351 break;
353 case 'r':
354 hinting_range_max = atoi(optarg);
355 have_hinting_range_max = true;
356 break;
358 case 'p':
359 pre_hinting = true;
360 break;
362 case 'v':
363 #ifndef BUILD_GUI
364 progress_func = progress;
365 #endif
366 break;
368 case 'V':
369 #ifdef CONSOLE_OUTPUT
370 show_version();
371 #endif
372 break;
374 case 'x':
375 increase_x_height = true;
376 break;
378 case 'X':
379 #ifdef CONSOLE_OUTPUT
380 fprintf(stderr, "Option `-x' not implemented yet\n");
381 #endif
382 break;
384 case HELP_ALL_OPTION:
385 #ifdef CONSOLE_OUTPUT
386 show_help(true, false);
387 #endif
388 break;
390 case PASS_THROUGH:
392 // append argument with proper syntax for Qt
393 string arg;
394 arg += '-';
395 arg += long_options[option_index].name;
397 new_arg_string.push_back(arg);
398 if (optarg)
399 new_arg_string.push_back(optarg);
400 break;
403 default:
404 exit(EXIT_FAILURE);
408 if (!have_hinting_range_min)
409 hinting_range_min = TA_HINTING_RANGE_MIN;
410 if (!have_hinting_range_max)
411 hinting_range_max = TA_HINTING_RANGE_MAX;
412 if (!have_hinting_limit)
413 hinting_limit = TA_HINTING_LIMIT;
415 #ifndef BUILD_GUI
417 if (hinting_range_min < 2)
419 fprintf(stderr, "The hinting range minimum must be at least 2\n");
420 exit(EXIT_FAILURE);
422 if (hinting_range_max < hinting_range_min)
424 fprintf(stderr, "The hinting range maximum must not be smaller"
425 " than the minimum (%d)\n",
426 hinting_range_min);
427 exit(EXIT_FAILURE);
429 if (hinting_limit != 0 && hinting_limit < hinting_range_max)
431 fprintf(stderr, "A non-zero hinting limit must not be smaller"
432 " than the hinting range maximum (%d)\n",
433 hinting_range_max);
434 exit(EXIT_FAILURE);
437 // on the console we need in and out file arguments
438 if (argc - optind != 2)
439 show_help(false, true);
441 FILE* in = fopen(argv[optind], "rb");
442 if (!in)
444 fprintf(stderr, "The following error occurred while opening font `%s':\n"
445 "\n"
446 " %s\n",
447 argv[optind], strerror(errno));
448 exit(EXIT_FAILURE);
451 FILE* out = fopen(argv[optind + 1], "wb");
452 if (!out)
454 fprintf(stderr, "The following error occurred while opening font `%s':\n"
455 "\n"
456 " %s\n",
457 argv[optind + 1], strerror(errno));
458 exit(EXIT_FAILURE);
461 const unsigned char* error_string;
462 Progress_Data progress_data = {-1, 1, 0};
464 TA_Error error =
465 TTF_autohint("in-file, out-file,"
466 "hinting-range-min, hinting-range-max, hinting-limit,"
467 "error-string,"
468 "progress-callback, progress-callback-data,"
469 "ignore-permissions, pre-hinting, increase-x-height,"
470 "fallback-script",
471 in, out,
472 hinting_range_min, hinting_range_max, hinting_limit,
473 &error_string,
474 progress_func, &progress_data,
475 ignore_permissions, pre_hinting, increase_x_height,
476 latin_fallback);
478 if (error)
480 if (error == TA_Err_Invalid_FreeType_Version)
481 fprintf(stderr,
482 "FreeType version 2.4.5 or higher is needed.\n"
483 "Perhaps using a wrong FreeType DLL?\n");
484 else if (error == TA_Err_Already_Processed)
485 fprintf(stderr,
486 "This font has already been processed with ttfautohint.\n");
487 else if (error == TA_Err_Missing_Legal_Permission)
488 fprintf(stderr,
489 "Bit 1 in the `fsType' field of the `OS/2' table is set:\n"
490 "This font must not be modified"
491 " without permission of the legal owner.\n"
492 "Use command line option `-i' to continue"
493 " if you have such a permission.\n");
494 else if (error == TA_Err_Missing_Unicode_CMap)
495 fprintf(stderr,
496 "No Unicode character map.\n");
497 else if (error == TA_Err_Missing_Glyph)
498 fprintf(stderr,
499 "No glyph for the key character"
500 " to derive standard width and height.\n"
501 "For the latin script, this key character is `o' (U+006F).\n");
502 else
503 fprintf(stderr,
504 "Error code `0x%02x' while autohinting font:\n"
505 " %s\n", error, error_string);
506 exit(EXIT_FAILURE);
509 fclose(in);
510 fclose(out);
512 exit(EXIT_SUCCESS);
514 return 0; // never reached
516 #else /* BUILD_GUI */
518 int new_argc = new_arg_string.size();
519 char** new_argv = new char*[new_argc];
521 // construct new argc and argv variables from collected data
522 for (int i = 0; i < new_argc; i++)
523 new_argv[i] = const_cast<char*>(new_arg_string[i].data());
525 QApplication app(new_argc, new_argv);
526 app.setApplicationName("TTFautohint");
527 app.setApplicationVersion(VERSION);
528 app.setOrganizationName("FreeType");
529 app.setOrganizationDomain("freetype.org");
531 Main_GUI gui(hinting_range_min, hinting_range_max, hinting_limit,
532 ignore_permissions, pre_hinting, increase_x_height,
533 latin_fallback);
534 gui.show();
536 return app.exec();
538 #endif /* BUILD_GUI */
541 // end of main.cpp