[ttfautohint] Make the TTY application a filter.
[ttfautohint.git] / frontend / main.cpp
blob84c0f021c850d043ff86daddb92b8eb49290e3d1
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 "If OUT-FILE is missing, standard output is used instead;\n"
121 "if IN-FILE is missing also, standard input and output are used.\n"
122 #endif
123 "\n"
124 "The new hints are based on FreeType's auto-hinter.\n"
125 "\n"
126 "This program is a simple front-end to the `ttfautohint' library.\n"
127 "\n");
129 fprintf(handle,
130 "Long options can be given with one or two dashes,\n"
131 "and with and without equal sign between option and argument.\n"
132 "This means that the following forms are acceptable:\n"
133 "`-foo=bar', `--foo=bar', `-foo bar', `--foo bar'.\n"
134 "\n"
135 "Mandatory arguments to long options are mandatory for short options too.\n"
136 #ifdef BUILD_GUI
137 "Options not related to Qt or X11 set default values.\n"
138 #endif
139 "\n"
142 fprintf(handle,
143 "Options:\n"
144 #ifndef BUILD_GUI
145 " --debug print debugging information\n"
146 #endif
147 " -c, --components hint glyph components separately\n"
148 " -f, --latin-fallback set fallback script to latin\n"
149 " -G, --hinting-limit=N switch off hinting above this PPEM value\n"
150 " (default: %d); value 0 means no limit\n"
151 " -h, --help display this help and exit\n"
152 #ifdef BUILD_GUI
153 " --help-all show Qt and X11 specific options also\n"
154 #endif
155 " -i, --ignore-restrictions override font license restrictions\n"
156 " -l, --hinting-range-min=N the minimum PPEM value for hint sets\n"
157 " (default: %d)\n"
158 " -n --no-info don't add ttfautohint info\n"
159 " to the version string(s) in the `name' table\n"
160 " -p, --pre-hinting apply original hints in advance\n",
161 TA_HINTING_LIMIT, TA_HINTING_RANGE_MIN);
162 fprintf(handle,
163 " -r, --hinting-range-max=N the maximum PPEM value for hint sets\n"
164 " (default: %d)\n"
165 " -s, --symbol input is symbol font\n"
166 " -v, --verbose show progress information\n"
167 " -V, --version print version information and exit\n"
168 " -w, --strong-stem-width=S use strong stem width routine for modes S,\n"
169 " where S is a string of up to three letters\n"
170 " with possible values `g' for grayscale,\n"
171 " `G' for GDI ClearType, and `D' for\n"
172 " DirectWrite ClearType (default: G)\n"
173 " -x, --increase-x-height=N increase x height for sizes in the range\n"
174 " 6<=PPEM<=N; value 0 switches off this feature\n"
175 " (default: %d)\n"
176 " -X, --x-height-snapping-exceptions=STRING\n"
177 " specify a comma-separated list of\n"
178 " x-height snapping exceptions\n"
179 "\n",
180 TA_HINTING_RANGE_MAX, TA_INCREASE_X_HEIGHT);
182 #ifdef BUILD_GUI
183 if (all)
185 fprintf(handle,
186 "Qt Options:\n"
187 " --graphicssystem=SYSTEM\n"
188 " select a different graphics system backend\n"
189 " instead of the default one\n"
190 " (possible values: `raster', `opengl')\n"
191 " --reverse set layout direction to right-to-left\n");
192 fprintf(handle,
193 " --session=ID restore the application for the given ID\n"
194 " --style=STYLE set application GUI style\n"
195 " (possible values: motif, windows, platinum)\n"
196 " --stylesheet=SHEET apply the given Qt stylesheet\n"
197 " to the application widgets\n"
198 "\n");
200 fprintf(handle,
201 "X11 options:\n"
202 " --background=COLOR set the default background color\n"
203 " and an application palette\n"
204 " (light and dark shades are calculated)\n"
205 " --bg=COLOR same as --background\n"
206 " --btn=COLOR set the default button color\n"
207 " --button=COLOR same as --btn\n"
208 " --cmap use a private color map on an 8-bit display\n"
209 " --display=NAME use the given X-server display\n");
210 fprintf(handle,
211 " --fg=COLOR set the default foreground color\n"
212 " --fn=FONTNAME set the application font\n"
213 " --font=FONTNAME same as --fn\n"
214 " --foreground=COLOR same as --fg\n"
215 " --geometry=GEOMETRY set the client geometry of first window\n"
216 " --im=SERVER set the X Input Method (XIM) server\n"
217 " --inputstyle=STYLE set X Input Method input style\n"
218 " (possible values: onthespot, overthespot,\n"
219 " offthespot, root)\n");
220 fprintf(handle,
221 " --name=NAME set the application name\n"
222 " --ncols=COUNT limit the number of colors allocated\n"
223 " in the color cube on an 8-bit display,\n"
224 " if the application is using the\n"
225 " QApplication::ManyColor color specification\n"
226 " --title=TITLE set the application title (caption)\n"
227 " --visual=VISUAL force the application\n"
228 " to use the given visual on an 8-bit display\n"
229 " (only possible value: TrueColor)\n"
230 "\n");
232 #endif // BUILD_GUI
234 fprintf(handle,
235 "The program accepts both TTF and TTC files as input.\n"
236 "Use option -i only if you have a legal permission to modify the font.\n"
237 "If option -f is not set, glyphs not in the latin range stay unhinted.\n"
238 "The used PPEM value for option -p is FUnits per em, normally 2048.\n"
239 "With option -s, use default values for standard stem width and height,\n"
240 "otherwise they are derived from latin character `o'.\n"
241 "\n");
242 fprintf(handle,
243 "A hint set contains the optimal hinting for a certain PPEM value;\n"
244 "the larger the hint set range, the more hint sets get computed,\n"
245 "usually increasing the output font size. Note, however,\n"
246 "that the `gasp' table of the output file enables grayscale hinting\n"
247 "for all sizes (limited by option -G which is handled in the bytecode).\n"
248 "\n");
249 fprintf(handle,
250 #ifdef BUILD_GUI
251 "A command-line version of this program is called `ttfautohint'.\n"
252 #else
253 "A GUI version of this program is called `ttfautohintGUI'.\n"
254 #endif
255 "\n"
256 "Report bugs to: freetype-devel@nongnu.org\n"
257 "ttfautohint home page: <http://www.freetype.org/ttfautohint>\n");
259 if (is_error)
260 exit(EXIT_FAILURE);
261 else
262 exit(EXIT_SUCCESS);
266 static void
267 show_version()
269 fprintf(stdout,
270 #ifdef BUILD_GUI
271 "ttfautohintGUI " VERSION "\n"
272 #else
273 "ttfautohint " VERSION "\n"
274 #endif
275 "Copyright (C) 2011-2012 Werner Lemberg <wl@gnu.org>.\n"
276 "License: FreeType License (FTL) or GNU GPLv2.\n"
277 "This is free software: you are free to change and redistribute it.\n"
278 "There is NO WARRANTY, to the extent permitted by law.\n");
280 exit(EXIT_SUCCESS);
282 #endif // CONSOLE_OUTPUT
286 main(int argc,
287 char** argv)
289 int hinting_range_min = 0;
290 int hinting_range_max = 0;
291 int hinting_limit = 0;
292 int increase_x_height = 0;
293 bool have_hinting_range_min = false;
294 bool have_hinting_range_max = false;
295 bool have_hinting_limit = false;
296 bool have_increase_x_height = false;
298 bool gray_strong_stem_width = false;
299 bool gdi_cleartype_strong_stem_width = true;
300 bool dw_cleartype_strong_stem_width = false;
302 bool ignore_restrictions = false;
303 bool pre_hinting = false;
304 bool hint_with_components = true;
305 bool no_info = false;
306 int latin_fallback = 0; // leave it as int; this probably gets extended
307 bool symbol = false;
309 #ifndef BUILD_GUI
310 bool debug = false;
312 TA_Progress_Func progress_func = NULL;
313 TA_Info_Func info_func = info;
314 #endif
316 // make GNU, Qt, and X11 command line options look the same;
317 // we allow `--foo=bar', `--foo bar', `-foo=bar', `-foo bar',
318 // and short options specific to ttfautohint
320 // set up a new argument string
321 vector<string> new_arg_string;
322 new_arg_string.push_back(argv[0]);
324 while (1)
326 // use pseudo short options for long-only options
327 enum
329 PASS_THROUGH = CHAR_MAX + 1,
330 HELP_ALL_OPTION,
331 DEBUG_OPTION
334 static struct option long_options[] =
336 {"help", no_argument, NULL, 'h'},
337 #ifdef BUILD_GUI
338 {"help-all", no_argument, NULL, HELP_ALL_OPTION},
339 #endif
341 // ttfautohint options
342 {"components", no_argument, NULL, 'c'},
343 #ifndef BUILD_GUI
344 {"debug", no_argument, NULL, DEBUG_OPTION},
345 #endif
346 {"hinting-limit", required_argument, NULL, 'G'},
347 {"hinting-range-max", required_argument, NULL, 'r'},
348 {"hinting-range-min", required_argument, NULL, 'l'},
349 {"ignore-restrictions", no_argument, NULL, 'i'},
350 {"increase-x-height", required_argument, NULL, 'x'},
351 {"latin-fallback", no_argument, NULL, 'f'},
352 {"no-info", no_argument, NULL, 'n'},
353 {"pre-hinting", no_argument, NULL, 'p'},
354 {"strong-stem-width", required_argument, NULL, 'w'},
355 {"symbol", no_argument, NULL, 's'},
356 {"verbose", no_argument, NULL, 'v'},
357 {"version", no_argument, NULL, 'V'},
358 {"x-height-snapping-exceptions", required_argument, NULL, 'X'},
360 // Qt options
361 {"graphicssystem", required_argument, NULL, PASS_THROUGH},
362 {"reverse", no_argument, NULL, PASS_THROUGH},
363 {"session", required_argument, NULL, PASS_THROUGH},
364 {"style", required_argument, NULL, PASS_THROUGH},
365 {"stylesheet", required_argument, NULL, PASS_THROUGH},
367 // X11 options
368 {"background", required_argument, NULL, PASS_THROUGH},
369 {"bg", required_argument, NULL, PASS_THROUGH},
370 {"btn", required_argument, NULL, PASS_THROUGH},
371 {"button", required_argument, NULL, PASS_THROUGH},
372 {"cmap", no_argument, NULL, PASS_THROUGH},
373 {"display", required_argument, NULL, PASS_THROUGH},
374 {"fg", required_argument, NULL, PASS_THROUGH},
375 {"fn", required_argument, NULL, PASS_THROUGH},
376 {"font", required_argument, NULL, PASS_THROUGH},
377 {"foreground", required_argument, NULL, PASS_THROUGH},
378 {"geometry", required_argument, NULL, PASS_THROUGH},
379 {"im", required_argument, NULL, PASS_THROUGH},
380 {"inputstyle", required_argument, NULL, PASS_THROUGH},
381 {"name", required_argument, NULL, PASS_THROUGH},
382 {"ncols", required_argument, NULL, PASS_THROUGH},
383 {"title", required_argument, NULL, PASS_THROUGH},
384 {"visual", required_argument, NULL, PASS_THROUGH},
386 {NULL, 0, NULL, 0}
389 int option_index;
390 int c = getopt_long_only(argc, argv, "cfG:hil:npr:stVvx:X:w:",
391 long_options, &option_index);
392 if (c == -1)
393 break;
395 switch (c)
397 case 'c':
398 hint_with_components = false;
399 break;
401 case 'f':
402 latin_fallback = 1;
403 break;
405 case 'G':
406 hinting_limit = atoi(optarg);
407 have_hinting_limit = true;
408 break;
410 case 'h':
411 #ifdef CONSOLE_OUTPUT
412 show_help(false, false);
413 #endif
414 break;
416 case 'i':
417 ignore_restrictions = true;
418 break;
420 case 'l':
421 hinting_range_min = atoi(optarg);
422 have_hinting_range_min = true;
423 break;
425 case 'n':
426 no_info = true;
427 break;
429 case 'p':
430 pre_hinting = true;
431 break;
433 case 'r':
434 hinting_range_max = atoi(optarg);
435 have_hinting_range_max = true;
436 break;
438 case 's':
439 symbol = true;
440 break;
442 case 'v':
443 #ifndef BUILD_GUI
444 progress_func = progress;
445 #endif
446 break;
448 case 'V':
449 #ifdef CONSOLE_OUTPUT
450 show_version();
451 #endif
452 break;
454 case 'w':
455 gray_strong_stem_width = strchr(optarg, 'g') ? true : false;
456 gdi_cleartype_strong_stem_width = strchr(optarg, 'G') ? true : false;
457 dw_cleartype_strong_stem_width = strchr(optarg, 'D') ? true : false;
458 break;
460 case 'x':
461 increase_x_height = atoi(optarg);
462 have_increase_x_height = true;
463 break;
465 case 'X':
466 #ifdef CONSOLE_OUTPUT
467 fprintf(stderr, "Option `-x' not implemented yet\n");
468 #endif
469 break;
471 #ifndef BUILD_GUI
472 case DEBUG_OPTION:
473 debug = true;
474 break;
475 #endif
477 #ifdef BUILD_GUI
478 case HELP_ALL_OPTION:
479 #ifdef CONSOLE_OUTPUT
480 show_help(true, false);
481 #endif
482 break;
483 #endif
485 case PASS_THROUGH:
487 // append argument with proper syntax for Qt
488 string arg;
489 arg += '-';
490 arg += long_options[option_index].name;
492 new_arg_string.push_back(arg);
493 if (optarg)
494 new_arg_string.push_back(optarg);
495 break;
498 default:
499 exit(EXIT_FAILURE);
503 if (!have_hinting_range_min)
504 hinting_range_min = TA_HINTING_RANGE_MIN;
505 if (!have_hinting_range_max)
506 hinting_range_max = TA_HINTING_RANGE_MAX;
507 if (!have_hinting_limit)
508 hinting_limit = TA_HINTING_LIMIT;
509 if (!have_increase_x_height)
510 increase_x_height = TA_INCREASE_X_HEIGHT;
512 #ifndef BUILD_GUI
514 if (hinting_range_min < 2)
516 fprintf(stderr, "The hinting range minimum must be at least 2\n");
517 exit(EXIT_FAILURE);
519 if (hinting_range_max < hinting_range_min)
521 fprintf(stderr, "The hinting range maximum must not be smaller"
522 " than the minimum (%d)\n",
523 hinting_range_min);
524 exit(EXIT_FAILURE);
526 if (hinting_limit != 0 && hinting_limit < hinting_range_max)
528 fprintf(stderr, "A non-zero hinting limit must not be smaller"
529 " than the hinting range maximum (%d)\n",
530 hinting_range_max);
531 exit(EXIT_FAILURE);
533 if (increase_x_height != 0 && increase_x_height < 6)
535 fprintf(stderr, "A non-zero x height increase limit"
536 " must be larger than or equal to 6\n");
537 exit(EXIT_FAILURE);
540 int num_args = argc - optind;
542 if (num_args > 2)
543 show_help(false, true);
545 FILE* out;
546 if (num_args > 1)
548 out = fopen(argv[optind + 1], "wb");
549 if (!out)
551 fprintf(stderr, "The following error occurred while opening font `%s':\n"
552 "\n"
553 " %s\n",
554 argv[optind + 1], strerror(errno));
555 exit(EXIT_FAILURE);
558 else
559 out = stdout;
561 FILE* in;
562 if (num_args > 0)
564 in = fopen(argv[optind], "rb");
565 if (!in)
567 fprintf(stderr, "The following error occurred while opening font `%s':\n"
568 "\n"
569 " %s\n",
570 argv[optind], strerror(errno));
571 exit(EXIT_FAILURE);
574 else
575 in = stdin;
577 unsigned char version_data[128];
578 unsigned char version_data_wide[256];
580 const unsigned char* error_string;
581 Progress_Data progress_data = {-1, 1, 0};
582 Info_Data info_data;
584 if (no_info)
585 info_func = NULL;
586 else
588 info_data.data = version_data;
589 info_data.data_wide = version_data_wide;
591 info_data.hinting_range_min = hinting_range_min;
592 info_data.hinting_range_max = hinting_range_max;
593 info_data.hinting_limit = hinting_limit;
595 info_data.gray_strong_stem_width = gray_strong_stem_width;
596 info_data.gdi_cleartype_strong_stem_width = gdi_cleartype_strong_stem_width;
597 info_data.dw_cleartype_strong_stem_width = dw_cleartype_strong_stem_width;
599 info_data.pre_hinting = pre_hinting;
600 info_data.hint_with_components = hint_with_components;
601 info_data.increase_x_height = increase_x_height;
602 info_data.latin_fallback = latin_fallback;
603 info_data.symbol = symbol;
605 build_version_string(&info_data);
608 TA_Error error =
609 TTF_autohint("in-file, out-file,"
610 "hinting-range-min, hinting-range-max, hinting-limit,"
611 "gray-strong-stem-width, gdi-cleartype-strong-stem-width,"
612 "dw-cleartype-strong-stem-width,"
613 "error-string,"
614 "progress-callback, progress-callback-data,"
615 "info-callback, info-callback-data,"
616 "ignore-restrictions, pre-hinting, hint-with-components,"
617 "increase-x-height, fallback-script, symbol,"
618 "debug",
619 in, out,
620 hinting_range_min, hinting_range_max, hinting_limit,
621 gray_strong_stem_width, gdi_cleartype_strong_stem_width,
622 dw_cleartype_strong_stem_width,
623 &error_string,
624 progress_func, &progress_data,
625 info_func, &info_data,
626 ignore_restrictions, pre_hinting, hint_with_components,
627 increase_x_height, latin_fallback, symbol,
628 debug);
630 if (error)
632 if (error == TA_Err_Invalid_FreeType_Version)
633 fprintf(stderr,
634 "FreeType version 2.4.5 or higher is needed.\n"
635 "Perhaps using a wrong FreeType DLL?\n");
636 else if (error == TA_Err_Invalid_Font_Type)
637 fprintf(stderr,
638 "This font is not a valid font"
639 " in SFNT format with TrueType outlines.\n"
640 "In particular, CFF outlines are not supported.\n");
641 else if (error == TA_Err_Already_Processed)
642 fprintf(stderr,
643 "This font has already been processed with ttfautohint.\n");
644 else if (error == TA_Err_Missing_Legal_Permission)
645 fprintf(stderr,
646 "Bit 1 in the `fsType' field of the `OS/2' table is set:\n"
647 "This font must not be modified"
648 " without permission of the legal owner.\n"
649 "Use command line option `-i' to continue"
650 " if you have such a permission.\n");
651 else if (error == TA_Err_Missing_Unicode_CMap)
652 fprintf(stderr,
653 "No Unicode character map.\n");
654 else if (error == TA_Err_Missing_Symbol_CMap)
655 fprintf(stderr,
656 "No symbol character map.\n");
657 else if (error == TA_Err_Missing_Glyph)
658 fprintf(stderr,
659 "No glyph for the key character"
660 " to derive standard width and height.\n"
661 "For the latin script, this key character is `o' (U+006F).\n");
662 else
663 fprintf(stderr,
664 "Error code `0x%02x' while autohinting font:\n"
665 " %s\n", error, error_string);
666 exit(EXIT_FAILURE);
669 fclose(in);
670 fclose(out);
672 exit(EXIT_SUCCESS);
674 return 0; // never reached
676 #else // BUILD_GUI
678 int new_argc = new_arg_string.size();
679 char** new_argv = new char*[new_argc];
681 // construct new argc and argv variables from collected data
682 for (int i = 0; i < new_argc; i++)
683 new_argv[i] = const_cast<char*>(new_arg_string[i].data());
685 QApplication app(new_argc, new_argv);
686 app.setApplicationName("TTFautohint");
687 app.setApplicationVersion(VERSION);
688 app.setOrganizationName("FreeType");
689 app.setOrganizationDomain("freetype.org");
691 Main_GUI gui(hinting_range_min, hinting_range_max, hinting_limit,
692 gray_strong_stem_width, gdi_cleartype_strong_stem_width,
693 dw_cleartype_strong_stem_width,
694 increase_x_height, ignore_restrictions, pre_hinting,
695 hint_with_components, no_info, latin_fallback, symbol);
696 gui.show();
698 return app.exec();
700 #endif // BUILD_GUI
703 // end of main.cpp