Make strong and smooth stem width handling selectable.
[ttfautohint.git] / frontend / main.cpp
blobe2e8d024ce2a356294f6ccc48e5e06ba7e2c44b6
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-restrictions 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 " -w, --strong-stem-width=S use strong stem width routine for modes S,\n"
162 " where S is a string of up to three letters\n"
163 " with possible values `g' for grayscale,\n"
164 " `G' for GDI ClearType, and `D' for\n"
165 " DirectWrite ClearType (default: G)\n"
166 " -x, --increase-x-height=N increase x height for sizes in the range\n"
167 " 6<=PPEM<=N; value 0 switches off this feature\n"
168 " (default: %d)\n"
169 " -X, --x-height-snapping-exceptions=STRING\n"
170 " specify a comma-separated list of\n"
171 " x-height snapping exceptions\n"
172 "\n",
173 TA_HINTING_RANGE_MAX, TA_INCREASE_X_HEIGHT);
175 #ifdef BUILD_GUI
176 if (all)
178 fprintf(handle,
179 "Qt Options:\n"
180 " --graphicssystem=SYSTEM\n"
181 " select a different graphics system backend\n"
182 " instead of the default one\n"
183 " (possible values: `raster', `opengl')\n"
184 " --reverse set layout direction to right-to-left\n");
185 fprintf(handle,
186 " --session=ID restore the application for the given ID\n"
187 " --style=STYLE set application GUI style\n"
188 " (possible values: motif, windows, platinum)\n"
189 " --stylesheet=SHEET apply the given Qt stylesheet\n"
190 " to the application widgets\n"
191 "\n");
193 fprintf(handle,
194 "X11 options:\n"
195 " --background=COLOR set the default background color\n"
196 " and an application palette\n"
197 " (light and dark shades are calculated)\n"
198 " --bg=COLOR same as --background\n"
199 " --btn=COLOR set the default button color\n"
200 " --button=COLOR same as --btn\n"
201 " --cmap use a private color map on an 8-bit display\n"
202 " --display=NAME use the given X-server display\n");
203 fprintf(handle,
204 " --fg=COLOR set the default foreground color\n"
205 " --fn=FONTNAME set the application font\n"
206 " --font=FONTNAME same as --fn\n"
207 " --foreground=COLOR same as --fg\n"
208 " --geometry=GEOMETRY set the client geometry of first window\n"
209 " --im=SERVER set the X Input Method (XIM) server\n"
210 " --inputstyle=STYLE set X Input Method input style\n"
211 " (possible values: onthespot, overthespot,\n"
212 " offthespot, root)\n");
213 fprintf(handle,
214 " --name=NAME set the application name\n"
215 " --ncols=COUNT limit the number of colors allocated\n"
216 " in the color cube on an 8-bit display,\n"
217 " if the application is using the\n"
218 " QApplication::ManyColor color specification\n"
219 " --title=TITLE set the application title (caption)\n"
220 " --visual=VISUAL force the application\n"
221 " to use the given visual on an 8-bit display\n"
222 " (only possible value: TrueColor)\n"
223 "\n");
225 #endif // BUILD_GUI
227 fprintf(handle,
228 "The program accepts both TTF and TTC files as input.\n"
229 "Use option -i only if you have a legal permission to modify the font.\n"
230 "If option -f is not set, glyphs not in the latin range stay unhinted.\n"
231 "The used PPEM value for option -p is FUnits per em, normally 2048.\n"
232 "With option -s, use default values for standard stem width and height,\n"
233 "otherwise they are derived from latin character `o'.\n"
234 "\n");
235 fprintf(handle,
236 "A hint set contains the optimal hinting for a certain PPEM value;\n"
237 "the larger the hint set range, the more hint sets get computed,\n"
238 "usually increasing the output font size. Note, however,\n"
239 "that the `gasp' table of the output file enables grayscale hinting\n"
240 "for all sizes (limited by option -G which is handled in the bytecode).\n"
241 "\n");
242 fprintf(handle,
243 #ifdef BUILD_GUI
244 "A command-line version of this program is called `ttfautohint'.\n"
245 #else
246 "A GUI version of this program is called `ttfautohintGUI'.\n"
247 #endif
248 "\n"
249 "Report bugs to: freetype-devel@nongnu.org\n"
250 "ttfautohint home page: <http://www.freetype.org/ttfautohint>\n");
252 if (is_error)
253 exit(EXIT_FAILURE);
254 else
255 exit(EXIT_SUCCESS);
259 static void
260 show_version()
262 fprintf(stdout,
263 #ifdef BUILD_GUI
264 "ttfautohintGUI " VERSION "\n"
265 #else
266 "ttfautohint " VERSION "\n"
267 #endif
268 "Copyright (C) 2011-2012 Werner Lemberg <wl@gnu.org>.\n"
269 "License: FreeType License (FTL) or GNU GPLv2.\n"
270 "This is free software: you are free to change and redistribute it.\n"
271 "There is NO WARRANTY, to the extent permitted by law.\n");
273 exit(EXIT_SUCCESS);
275 #endif // CONSOLE_OUTPUT
279 main(int argc,
280 char** argv)
282 int hinting_range_min = 0;
283 int hinting_range_max = 0;
284 int hinting_limit = 0;
285 int increase_x_height = 0;
286 bool have_hinting_range_min = false;
287 bool have_hinting_range_max = false;
288 bool have_hinting_limit = false;
289 bool have_increase_x_height = false;
291 bool gray_strong_stem_width = false;
292 bool gdi_cleartype_strong_stem_width = true;
293 bool dw_cleartype_strong_stem_width = false;
295 bool ignore_restrictions = false;
296 bool pre_hinting = false;
297 bool no_info = false;
298 int latin_fallback = 0; // leave it as int; this probably gets extended
299 bool symbol = false;
301 #ifndef BUILD_GUI
302 TA_Progress_Func progress_func = NULL;
303 TA_Info_Func info_func = info;
304 #endif
306 // make GNU, Qt, and X11 command line options look the same;
307 // we allow `--foo=bar', `--foo bar', `-foo=bar', `-foo bar',
308 // and short options specific to ttfautohint
310 // set up a new argument string
311 vector<string> new_arg_string;
312 new_arg_string.push_back(argv[0]);
314 while (1)
316 // use pseudo short options for long-only options
317 enum
319 PASS_THROUGH = CHAR_MAX + 1,
320 HELP_ALL_OPTION
323 static struct option long_options[] =
325 {"help", no_argument, NULL, 'h'},
326 #ifdef BUILD_GUI
327 {"help-all", no_argument, NULL, HELP_ALL_OPTION},
328 #endif
330 // ttfautohint options
331 {"hinting-limit", required_argument, NULL, 'G'},
332 {"hinting-range-max", required_argument, NULL, 'r'},
333 {"hinting-range-min", required_argument, NULL, 'l'},
334 {"ignore-restrictions", no_argument, NULL, 'i'},
335 {"increase-x-height", required_argument, NULL, 'x'},
336 {"latin-fallback", no_argument, NULL, 'f'},
337 {"no-info", no_argument, NULL, 'n'},
338 {"pre-hinting", no_argument, NULL, 'p'},
339 {"strong-stem-width", required_argument, NULL, 'w'},
340 {"symbol", no_argument, NULL, 's'},
341 {"verbose", no_argument, NULL, 'v'},
342 {"version", no_argument, NULL, 'V'},
343 {"x-height-snapping-exceptions", required_argument, NULL, 'X'},
345 // Qt options
346 {"graphicssystem", required_argument, NULL, PASS_THROUGH},
347 {"reverse", no_argument, NULL, PASS_THROUGH},
348 {"session", required_argument, NULL, PASS_THROUGH},
349 {"style", required_argument, NULL, PASS_THROUGH},
350 {"stylesheet", required_argument, NULL, PASS_THROUGH},
352 // X11 options
353 {"background", required_argument, NULL, PASS_THROUGH},
354 {"bg", required_argument, NULL, PASS_THROUGH},
355 {"btn", required_argument, NULL, PASS_THROUGH},
356 {"button", required_argument, NULL, PASS_THROUGH},
357 {"cmap", no_argument, NULL, PASS_THROUGH},
358 {"display", required_argument, NULL, PASS_THROUGH},
359 {"fg", required_argument, NULL, PASS_THROUGH},
360 {"fn", required_argument, NULL, PASS_THROUGH},
361 {"font", required_argument, NULL, PASS_THROUGH},
362 {"foreground", required_argument, NULL, PASS_THROUGH},
363 {"geometry", required_argument, NULL, PASS_THROUGH},
364 {"im", required_argument, NULL, PASS_THROUGH},
365 {"inputstyle", required_argument, NULL, PASS_THROUGH},
366 {"name", required_argument, NULL, PASS_THROUGH},
367 {"ncols", required_argument, NULL, PASS_THROUGH},
368 {"title", required_argument, NULL, PASS_THROUGH},
369 {"visual", required_argument, NULL, PASS_THROUGH},
371 {NULL, 0, NULL, 0}
374 int option_index;
375 int c = getopt_long_only(argc, argv, "fG:hil:npr:stVvx:X:w:",
376 long_options, &option_index);
377 if (c == -1)
378 break;
380 switch (c)
382 case 'f':
383 latin_fallback = 1;
384 break;
386 case 'G':
387 hinting_limit = atoi(optarg);
388 have_hinting_limit = true;
389 break;
391 case 'h':
392 #ifdef CONSOLE_OUTPUT
393 show_help(false, false);
394 #endif
395 break;
397 case 'i':
398 ignore_restrictions = true;
399 break;
401 case 'l':
402 hinting_range_min = atoi(optarg);
403 have_hinting_range_min = true;
404 break;
406 case 'n':
407 no_info = true;
408 break;
410 case 'p':
411 pre_hinting = true;
412 break;
414 case 'r':
415 hinting_range_max = atoi(optarg);
416 have_hinting_range_max = true;
417 break;
419 case 's':
420 symbol = true;
421 break;
423 case 'v':
424 #ifndef BUILD_GUI
425 progress_func = progress;
426 #endif
427 break;
429 case 'V':
430 #ifdef CONSOLE_OUTPUT
431 show_version();
432 #endif
433 break;
435 case 'w':
436 gray_strong_stem_width = strchr(optarg, 'g') ? true : false;
437 gdi_cleartype_strong_stem_width = strchr(optarg, 'G') ? true : false;
438 dw_cleartype_strong_stem_width = strchr(optarg, 'D') ? true : false;
439 break;
441 case 'x':
442 increase_x_height = atoi(optarg);
443 have_increase_x_height = true;
444 break;
446 case 'X':
447 #ifdef CONSOLE_OUTPUT
448 fprintf(stderr, "Option `-x' not implemented yet\n");
449 #endif
450 break;
452 case HELP_ALL_OPTION:
453 #ifdef CONSOLE_OUTPUT
454 show_help(true, false);
455 #endif
456 break;
458 case PASS_THROUGH:
460 // append argument with proper syntax for Qt
461 string arg;
462 arg += '-';
463 arg += long_options[option_index].name;
465 new_arg_string.push_back(arg);
466 if (optarg)
467 new_arg_string.push_back(optarg);
468 break;
471 default:
472 exit(EXIT_FAILURE);
476 if (!have_hinting_range_min)
477 hinting_range_min = TA_HINTING_RANGE_MIN;
478 if (!have_hinting_range_max)
479 hinting_range_max = TA_HINTING_RANGE_MAX;
480 if (!have_hinting_limit)
481 hinting_limit = TA_HINTING_LIMIT;
482 if (!have_increase_x_height)
483 increase_x_height = TA_INCREASE_X_HEIGHT;
485 #ifndef BUILD_GUI
487 if (hinting_range_min < 2)
489 fprintf(stderr, "The hinting range minimum must be at least 2\n");
490 exit(EXIT_FAILURE);
492 if (hinting_range_max < hinting_range_min)
494 fprintf(stderr, "The hinting range maximum must not be smaller"
495 " than the minimum (%d)\n",
496 hinting_range_min);
497 exit(EXIT_FAILURE);
499 if (hinting_limit != 0 && hinting_limit < hinting_range_max)
501 fprintf(stderr, "A non-zero hinting limit must not be smaller"
502 " than the hinting range maximum (%d)\n",
503 hinting_range_max);
504 exit(EXIT_FAILURE);
506 if (increase_x_height != 0
507 && (increase_x_height < 6 || increase_x_height > 20))
509 fprintf(stderr, "A non-zero x height increase limit"
510 " must be in the range 6-20\n");
511 exit(EXIT_FAILURE);
514 // on the console we need in and out file arguments
515 if (argc - optind != 2)
516 show_help(false, true);
518 FILE* in = fopen(argv[optind], "rb");
519 if (!in)
521 fprintf(stderr, "The following error occurred while opening font `%s':\n"
522 "\n"
523 " %s\n",
524 argv[optind], strerror(errno));
525 exit(EXIT_FAILURE);
528 FILE* out = fopen(argv[optind + 1], "wb");
529 if (!out)
531 fprintf(stderr, "The following error occurred while opening font `%s':\n"
532 "\n"
533 " %s\n",
534 argv[optind + 1], strerror(errno));
535 exit(EXIT_FAILURE);
538 unsigned char version_data[128];
539 unsigned char version_data_wide[256];
541 const unsigned char* error_string;
542 Progress_Data progress_data = {-1, 1, 0};
543 Info_Data info_data;
545 if (no_info)
546 info_func = NULL;
547 else
549 info_data.data = version_data;
550 info_data.data_wide = version_data_wide;
552 info_data.hinting_range_min = hinting_range_min;
553 info_data.hinting_range_max = hinting_range_max;
554 info_data.hinting_limit = hinting_limit;
556 info_data.gray_strong_stem_width = gray_strong_stem_width;
557 info_data.gdi_cleartype_strong_stem_width = gdi_cleartype_strong_stem_width;
558 info_data.dw_cleartype_strong_stem_width = dw_cleartype_strong_stem_width;
560 info_data.pre_hinting = pre_hinting;
561 info_data.increase_x_height = increase_x_height;
562 info_data.latin_fallback = latin_fallback;
563 info_data.symbol = symbol;
565 build_version_string(&info_data);
568 TA_Error error =
569 TTF_autohint("in-file, out-file,"
570 "hinting-range-min, hinting-range-max, hinting-limit,"
571 "gray-strong-stem-width, gdi-cleartype-strong-stem-width,"
572 "dw-cleartype-strong-stem-width,"
573 "error-string,"
574 "progress-callback, progress-callback-data,"
575 "info-callback, info-callback-data,"
576 "ignore-restrictions, pre-hinting, increase-x-height,"
577 "fallback-script, symbol",
578 in, out,
579 hinting_range_min, hinting_range_max, hinting_limit,
580 gray_strong_stem_width, gdi_cleartype_strong_stem_width,
581 dw_cleartype_strong_stem_width,
582 &error_string,
583 progress_func, &progress_data,
584 info_func, &info_data,
585 ignore_restrictions, pre_hinting, increase_x_height,
586 latin_fallback, symbol);
588 if (error)
590 if (error == TA_Err_Invalid_FreeType_Version)
591 fprintf(stderr,
592 "FreeType version 2.4.5 or higher is needed.\n"
593 "Perhaps using a wrong FreeType DLL?\n");
594 else if (error == TA_Err_Invalid_Font_Type)
595 fprintf(stderr,
596 "This font is not a valid font"
597 " in SFNT format with TrueType outlines.\n"
598 "In particular, CFF outlines are not supported.\n");
599 else if (error == TA_Err_Already_Processed)
600 fprintf(stderr,
601 "This font has already been processed with ttfautohint.\n");
602 else if (error == TA_Err_Missing_Legal_Permission)
603 fprintf(stderr,
604 "Bit 1 in the `fsType' field of the `OS/2' table is set:\n"
605 "This font must not be modified"
606 " without permission of the legal owner.\n"
607 "Use command line option `-i' to continue"
608 " if you have such a permission.\n");
609 else if (error == TA_Err_Missing_Unicode_CMap)
610 fprintf(stderr,
611 "No Unicode character map.\n");
612 else if (error == TA_Err_Missing_Glyph)
613 fprintf(stderr,
614 "No glyph for the key character"
615 " to derive standard width and height.\n"
616 "For the latin script, this key character is `o' (U+006F).\n");
617 else
618 fprintf(stderr,
619 "Error code `0x%02x' while autohinting font:\n"
620 " %s\n", error, error_string);
621 exit(EXIT_FAILURE);
624 fclose(in);
625 fclose(out);
627 exit(EXIT_SUCCESS);
629 return 0; // never reached
631 #else // BUILD_GUI
633 int new_argc = new_arg_string.size();
634 char** new_argv = new char*[new_argc];
636 // construct new argc and argv variables from collected data
637 for (int i = 0; i < new_argc; i++)
638 new_argv[i] = const_cast<char*>(new_arg_string[i].data());
640 QApplication app(new_argc, new_argv);
641 app.setApplicationName("TTFautohint");
642 app.setApplicationVersion(VERSION);
643 app.setOrganizationName("FreeType");
644 app.setOrganizationDomain("freetype.org");
646 Main_GUI gui(hinting_range_min, hinting_range_max, hinting_limit,
647 gray_strong_stem_width, gdi_cleartype_strong_stem_width,
648 dw_cleartype_strong_stem_width,
649 increase_x_height, ignore_restrictions, pre_hinting,
650 no_info, latin_fallback, symbol);
651 gui.show();
653 return app.exec();
655 #endif // BUILD_GUI
658 // end of main.cpp