s/lower_upper/upper_lower/.
[ttfautohint.git] / frontend / main.cpp
blob81609ecc39083e95f47516926092551a1b3bb2c0
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 #else
40 # include "info.h"
41 #endif
43 #include <ttfautohint.h>
45 using namespace std;
48 #ifndef BUILD_GUI
49 extern "C" {
51 typedef struct Progress_Data_
53 long last_sfnt;
54 bool begin;
55 int last_percent;
56 } Progress_Data;
59 int
60 progress(long curr_idx,
61 long num_glyphs,
62 long curr_sfnt,
63 long num_sfnts,
64 void* user)
66 Progress_Data* data = (Progress_Data*)user;
68 if (num_sfnts > 1 && curr_sfnt != data->last_sfnt)
70 fprintf(stderr, "subfont %ld of %ld\n", curr_sfnt + 1, num_sfnts);
71 data->last_sfnt = curr_sfnt;
72 data->begin = true;
75 if (data->begin)
77 fprintf(stderr, " %ld glyphs\n"
78 " ", num_glyphs);
79 data->begin = false;
82 // print progress approx. every 10%
83 int curr_percent = curr_idx * 100 / num_glyphs;
84 int curr_diff = curr_percent - data->last_percent;
86 if (curr_diff >= 10)
88 fprintf(stderr, " %d%%", curr_percent);
89 data->last_percent = curr_percent - curr_percent % 10;
92 if (curr_idx + 1 == num_glyphs)
93 fprintf(stderr, "\n");
95 return 0;
98 } // extern "C"
99 #endif // !BUILD_GUI
102 #ifdef CONSOLE_OUTPUT
103 static void
104 show_help(bool
105 #ifdef BUILD_GUI
107 #endif
109 bool is_error)
111 FILE* handle = is_error ? stderr : stdout;
113 fprintf(handle,
114 #ifdef BUILD_GUI
115 "Usage: ttfautohintGUI [OPTION]...\n"
116 "A GUI application to replace hints in a TrueType font.\n"
117 #else
118 "Usage: ttfautohint [OPTION]... IN-FILE OUT-FILE\n"
119 "Replace hints in TrueType font IN-FILE and write output to OUT-FILE.\n"
120 #endif
121 "The new hints are based on FreeType's autohinter.\n"
122 "\n"
123 "This program is a simple front-end to the `ttfautohint' library.\n"
124 "\n");
126 fprintf(handle,
127 "Long options can be given with one or two dashes,\n"
128 "and with and without equal sign between option and argument.\n"
129 "This means that the following forms are acceptable:\n"
130 "`-foo=bar', `--foo=bar', `-foo bar', `--foo bar'.\n"
131 "\n"
132 "Mandatory arguments to long options are mandatory for short options too.\n"
133 #ifdef BUILD_GUI
134 "Options not related to Qt or X11 set default values.\n"
135 #endif
136 "\n"
139 fprintf(handle,
140 "Options:\n"
141 " -f, --latin-fallback set fallback script to latin\n"
142 " -G, --hinting-limit=N switch off hinting above this PPEM value\n"
143 " (default: %d); value 0 means no limit\n"
144 " -h, --help display this help and exit\n"
145 #ifdef BUILD_GUI
146 " --help-all show Qt and X11 specific options also\n"
147 #endif
148 " -i, --ignore-permissions override font license restrictions\n"
149 " -l, --hinting-range-min=N the minimum PPEM value for hint sets\n"
150 " (default: %d)\n"
151 " -n --no-info don't add ttfautohint info\n"
152 " to the version string(s) in the `name' table\n"
153 " -p, --pre-hinting apply original hints in advance\n",
154 TA_HINTING_LIMIT, TA_HINTING_RANGE_MIN);
155 fprintf(handle,
156 " -r, --hinting-range-max=N the maximum PPEM value for hint sets\n"
157 " (default: %d)\n"
158 " -s, --symbol input is symbol font\n"
159 " -v, --verbose show progress information\n"
160 " -V, --version print version information and exit\n"
161 " -x, --increase-x-height increase x height for small sizes\n"
162 " -X, --x-height-snapping-exceptions=STRING\n"
163 " specify a comma-separated list of\n"
164 " x-height snapping exceptions\n"
165 "\n",
166 TA_HINTING_RANGE_MAX);
168 #ifdef BUILD_GUI
169 if (all)
171 fprintf(handle,
172 "Qt Options:\n"
173 " --graphicssystem=SYSTEM\n"
174 " select a different graphics system backend\n"
175 " instead of the default one\n"
176 " (possible values: `raster', `opengl')\n"
177 " --reverse set layout direction to right-to-left\n");
178 fprintf(handle,
179 " --session=ID restore the application for the given ID\n"
180 " --style=STYLE set application GUI style\n"
181 " (possible values: motif, windows, platinum)\n"
182 " --stylesheet=SHEET apply the given Qt stylesheet\n"
183 " to the application widgets\n"
184 "\n");
186 fprintf(handle,
187 "X11 options:\n"
188 " --background=COLOR set the default background color\n"
189 " and an application palette\n"
190 " (light and dark shades are calculated)\n"
191 " --bg=COLOR same as --background\n"
192 " --btn=COLOR set the default button color\n"
193 " --button=COLOR same as --btn\n"
194 " --cmap use a private color map on an 8-bit display\n"
195 " --display=NAME use the given X-server display\n");
196 fprintf(handle,
197 " --fg=COLOR set the default foreground color\n"
198 " --fn=FONTNAME set the application font\n"
199 " --font=FONTNAME same as --fn\n"
200 " --foreground=COLOR same as --fg\n"
201 " --geometry=GEOMETRY set the client geometry of first window\n"
202 " --im=SERVER set the X Input Method (XIM) server\n"
203 " --inputstyle=STYLE set X Input Method input style\n"
204 " (possible values: onthespot, overthespot,\n"
205 " offthespot, root)\n");
206 fprintf(handle,
207 " --name=NAME set the application name\n"
208 " --ncols=COUNT limit the number of colors allocated\n"
209 " in the color cube on an 8-bit display,\n"
210 " if the application is using the\n"
211 " QApplication::ManyColor color specification\n"
212 " --title=TITLE set the application title (caption)\n"
213 " --visual=VISUAL force the application\n"
214 " to use the given visual on an 8-bit display\n"
215 " (only possible value: TrueColor)\n"
216 "\n");
218 #endif // BUILD_GUI
220 fprintf(handle,
221 "The program accepts both TTF and TTC files as input.\n"
222 "Use option -i only if you have a legal permission to modify the font.\n"
223 "If option -f is not set, glyphs not in the latin range stay unhinted.\n"
224 "The used PPEM value for option -p is FUnits per em, normally 2048.\n"
225 "With option -s, use default values for standard stem width and height,\n"
226 "otherwise they are derived from latin character `o'.\n"
227 "\n");
228 fprintf(handle,
229 "A hint set contains the optimal hinting for a certain PPEM value;\n"
230 "the larger the hint set range, the more hint sets get computed,\n"
231 "usually increasing the output font size. Note, however,\n"
232 "that the `gasp' table of the output file enables grayscale hinting\n"
233 "for all sizes (limited by option -G which is handled in the bytecode).\n"
234 "\n");
235 fprintf(handle,
236 #ifdef BUILD_GUI
237 "A command-line version of this program is called `ttfautohint'.\n"
238 #else
239 "A GUI version of this program is called `ttfautohintGUI'.\n"
240 #endif
241 "\n"
242 "Report bugs to: freetype-devel@nongnu.org\n"
243 "ttfautohint home page: <http://www.freetype.org/ttfautohint>\n");
245 if (is_error)
246 exit(EXIT_FAILURE);
247 else
248 exit(EXIT_SUCCESS);
252 static void
253 show_version()
255 fprintf(stdout,
256 #ifdef BUILD_GUI
257 "ttfautohintGUI " VERSION "\n"
258 #else
259 "ttfautohint " VERSION "\n"
260 #endif
261 "Copyright (C) 2011-2012 Werner Lemberg <wl@gnu.org>.\n"
262 "License: FreeType License (FTL) or GNU GPLv2.\n"
263 "This is free software: you are free to change and redistribute it.\n"
264 "There is NO WARRANTY, to the extent permitted by law.\n");
266 exit(EXIT_SUCCESS);
268 #endif // CONSOLE_OUTPUT
272 main(int argc,
273 char** argv)
275 int hinting_range_min = 0;
276 int hinting_range_max = 0;
277 int hinting_limit = 0;
278 bool have_hinting_range_min = false;
279 bool have_hinting_range_max = false;
280 bool have_hinting_limit = false;
282 bool ignore_permissions = false;
283 bool pre_hinting = false;
284 bool increase_x_height = false;
285 bool no_info = false;
286 int latin_fallback = 0; // leave it as int; this probably gets extended
287 bool symbol = false;
289 #ifndef BUILD_GUI
290 TA_Progress_Func progress_func = NULL;
291 TA_Info_Func info_func = info;
292 #endif
294 // make GNU, Qt, and X11 command line options look the same;
295 // we allow `--foo=bar', `--foo bar', `-foo=bar', `-foo bar',
296 // and short options specific to ttfautohint
298 // set up a new argument string
299 vector<string> new_arg_string;
300 new_arg_string.push_back(argv[0]);
302 while (1)
304 // use pseudo short options for long-only options
305 enum
307 PASS_THROUGH = CHAR_MAX + 1,
308 HELP_ALL_OPTION
311 static struct option long_options[] =
313 {"help", no_argument, NULL, 'h'},
314 #ifdef BUILD_GUI
315 {"help-all", no_argument, NULL, HELP_ALL_OPTION},
316 #endif
318 // ttfautohint options
319 {"hinting-limit", required_argument, NULL, 'G'},
320 {"hinting-range-max", required_argument, NULL, 'r'},
321 {"hinting-range-min", required_argument, NULL, 'l'},
322 {"ignore-permissions", no_argument, NULL, 'i'},
323 {"increase-x-height", no_argument, NULL, 'x'},
324 {"latin-fallback", no_argument, NULL, 'f'},
325 {"no-info", no_argument, NULL, 'n'},
326 {"pre-hinting", no_argument, NULL, 'p'},
327 {"symbol", no_argument, NULL, 's'},
328 {"verbose", no_argument, NULL, 'v'},
329 {"version", no_argument, NULL, 'V'},
330 {"x-height-snapping-exceptions", required_argument, NULL, 'X'},
332 // Qt options
333 {"graphicssystem", required_argument, NULL, PASS_THROUGH},
334 {"reverse", no_argument, NULL, PASS_THROUGH},
335 {"session", required_argument, NULL, PASS_THROUGH},
336 {"style", required_argument, NULL, PASS_THROUGH},
337 {"stylesheet", required_argument, NULL, PASS_THROUGH},
339 // X11 options
340 {"background", required_argument, NULL, PASS_THROUGH},
341 {"bg", required_argument, NULL, PASS_THROUGH},
342 {"btn", required_argument, NULL, PASS_THROUGH},
343 {"button", required_argument, NULL, PASS_THROUGH},
344 {"cmap", no_argument, NULL, PASS_THROUGH},
345 {"display", required_argument, NULL, PASS_THROUGH},
346 {"fg", required_argument, NULL, PASS_THROUGH},
347 {"fn", required_argument, NULL, PASS_THROUGH},
348 {"font", required_argument, NULL, PASS_THROUGH},
349 {"foreground", required_argument, NULL, PASS_THROUGH},
350 {"geometry", required_argument, NULL, PASS_THROUGH},
351 {"im", required_argument, NULL, PASS_THROUGH},
352 {"inputstyle", required_argument, NULL, PASS_THROUGH},
353 {"name", required_argument, NULL, PASS_THROUGH},
354 {"ncols", required_argument, NULL, PASS_THROUGH},
355 {"title", required_argument, NULL, PASS_THROUGH},
356 {"visual", required_argument, NULL, PASS_THROUGH},
358 {NULL, 0, NULL, 0}
361 int option_index;
362 int c = getopt_long_only(argc, argv, "fG:hil:npr:stVvxX:",
363 long_options, &option_index);
364 if (c == -1)
365 break;
367 switch (c)
369 case 'f':
370 latin_fallback = 1;
371 break;
373 case 'G':
374 hinting_limit = atoi(optarg);
375 have_hinting_limit = true;
376 break;
378 case 'h':
379 #ifdef CONSOLE_OUTPUT
380 show_help(false, false);
381 #endif
382 break;
384 case 'i':
385 ignore_permissions = true;
386 break;
388 case 'l':
389 hinting_range_min = atoi(optarg);
390 have_hinting_range_min = true;
391 break;
393 case 'n':
394 no_info = true;
395 break;
397 case 'p':
398 pre_hinting = true;
399 break;
401 case 'r':
402 hinting_range_max = atoi(optarg);
403 have_hinting_range_max = true;
404 break;
406 case 's':
407 symbol = true;
408 break;
410 case 'v':
411 #ifndef BUILD_GUI
412 progress_func = progress;
413 #endif
414 break;
416 case 'V':
417 #ifdef CONSOLE_OUTPUT
418 show_version();
419 #endif
420 break;
422 case 'x':
423 increase_x_height = true;
424 break;
426 case 'X':
427 #ifdef CONSOLE_OUTPUT
428 fprintf(stderr, "Option `-x' not implemented yet\n");
429 #endif
430 break;
432 case HELP_ALL_OPTION:
433 #ifdef CONSOLE_OUTPUT
434 show_help(true, false);
435 #endif
436 break;
438 case PASS_THROUGH:
440 // append argument with proper syntax for Qt
441 string arg;
442 arg += '-';
443 arg += long_options[option_index].name;
445 new_arg_string.push_back(arg);
446 if (optarg)
447 new_arg_string.push_back(optarg);
448 break;
451 default:
452 exit(EXIT_FAILURE);
456 if (!have_hinting_range_min)
457 hinting_range_min = TA_HINTING_RANGE_MIN;
458 if (!have_hinting_range_max)
459 hinting_range_max = TA_HINTING_RANGE_MAX;
460 if (!have_hinting_limit)
461 hinting_limit = TA_HINTING_LIMIT;
463 #ifndef BUILD_GUI
465 if (hinting_range_min < 2)
467 fprintf(stderr, "The hinting range minimum must be at least 2\n");
468 exit(EXIT_FAILURE);
470 if (hinting_range_max < hinting_range_min)
472 fprintf(stderr, "The hinting range maximum must not be smaller"
473 " than the minimum (%d)\n",
474 hinting_range_min);
475 exit(EXIT_FAILURE);
477 if (hinting_limit != 0 && hinting_limit < hinting_range_max)
479 fprintf(stderr, "A non-zero hinting limit must not be smaller"
480 " than the hinting range maximum (%d)\n",
481 hinting_range_max);
482 exit(EXIT_FAILURE);
485 // on the console we need in and out file arguments
486 if (argc - optind != 2)
487 show_help(false, true);
489 FILE* in = fopen(argv[optind], "rb");
490 if (!in)
492 fprintf(stderr, "The following error occurred while opening font `%s':\n"
493 "\n"
494 " %s\n",
495 argv[optind], strerror(errno));
496 exit(EXIT_FAILURE);
499 FILE* out = fopen(argv[optind + 1], "wb");
500 if (!out)
502 fprintf(stderr, "The following error occurred while opening font `%s':\n"
503 "\n"
504 " %s\n",
505 argv[optind + 1], strerror(errno));
506 exit(EXIT_FAILURE);
509 unsigned char version_data[128];
510 unsigned char version_data_wide[256];
512 const unsigned char* error_string;
513 Progress_Data progress_data = {-1, 1, 0};
514 Info_Data info_data;
516 if (no_info)
517 info_func = NULL;
518 else
520 info_data.data = version_data;
521 info_data.data_wide = version_data_wide;
523 info_data.hinting_range_min = hinting_range_min;
524 info_data.hinting_range_max = hinting_range_max;
525 info_data.hinting_limit = hinting_limit;
527 info_data.pre_hinting = pre_hinting;
528 info_data.increase_x_height = increase_x_height;
529 info_data.latin_fallback = latin_fallback;
530 info_data.symbol = symbol;
532 build_version_string(&info_data);
535 TA_Error error =
536 TTF_autohint("in-file, out-file,"
537 "hinting-range-min, hinting-range-max, hinting-limit,"
538 "error-string,"
539 "progress-callback, progress-callback-data,"
540 "info-callback, info-callback-data,"
541 "ignore-permissions, pre-hinting, increase-x-height,"
542 "fallback-script, symbol",
543 in, out,
544 hinting_range_min, hinting_range_max, hinting_limit,
545 &error_string,
546 progress_func, &progress_data,
547 info_func, &info_data,
548 ignore_permissions, pre_hinting, increase_x_height,
549 latin_fallback, symbol);
551 if (error)
553 if (error == TA_Err_Invalid_FreeType_Version)
554 fprintf(stderr,
555 "FreeType version 2.4.5 or higher is needed.\n"
556 "Perhaps using a wrong FreeType DLL?\n");
557 else if (error == TA_Err_Already_Processed)
558 fprintf(stderr,
559 "This font has already been processed with ttfautohint.\n");
560 else if (error == TA_Err_Missing_Legal_Permission)
561 fprintf(stderr,
562 "Bit 1 in the `fsType' field of the `OS/2' table is set:\n"
563 "This font must not be modified"
564 " without permission of the legal owner.\n"
565 "Use command line option `-i' to continue"
566 " if you have such a permission.\n");
567 else if (error == TA_Err_Missing_Unicode_CMap)
568 fprintf(stderr,
569 "No Unicode character map.\n");
570 else if (error == TA_Err_Missing_Glyph)
571 fprintf(stderr,
572 "No glyph for the key character"
573 " to derive standard width and height.\n"
574 "For the latin script, this key character is `o' (U+006F).\n");
575 else
576 fprintf(stderr,
577 "Error code `0x%02x' while autohinting font:\n"
578 " %s\n", error, error_string);
579 exit(EXIT_FAILURE);
582 fclose(in);
583 fclose(out);
585 exit(EXIT_SUCCESS);
587 return 0; // never reached
589 #else // BUILD_GUI
591 int new_argc = new_arg_string.size();
592 char** new_argv = new char*[new_argc];
594 // construct new argc and argv variables from collected data
595 for (int i = 0; i < new_argc; i++)
596 new_argv[i] = const_cast<char*>(new_arg_string[i].data());
598 QApplication app(new_argc, new_argv);
599 app.setApplicationName("TTFautohint");
600 app.setApplicationVersion(VERSION);
601 app.setOrganizationName("FreeType");
602 app.setOrganizationDomain("freetype.org");
604 Main_GUI gui(hinting_range_min, hinting_range_max, hinting_limit,
605 ignore_permissions, pre_hinting, increase_x_height,
606 no_info, latin_fallback, symbol);
607 gui.show();
609 return app.exec();
611 #endif // BUILD_GUI
614 // end of main.cpp