3 // Copyright (C) 2011-2013 by Werner Lemberg.
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.
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'.
18 # define CONSOLE_OUTPUT
21 # define CONSOLE_OUTPUT
38 # include <QApplication>
44 #include <ttfautohint.h>
45 #include <numberset.h>
50 # define SET_BINARY(f) do { \
51 if (!isatty(fileno(f))) \
52 setmode(fileno(f), O_BINARY); \
57 # define SET_BINARY(f) do {} while (0)
64 // the available script tags and its descriptions are directly extracted
65 // from `ttfautohint-scripts.h'
66 typedef struct Script_Names_
69 const char* description
;
73 #define SCRIPT(s, S, d) \
76 const Script_Names script_names
[] =
78 #include <ttfautohint-scripts.h>
86 typedef struct Progress_Data_
95 progress(long curr_idx
,
101 Progress_Data
* data
= (Progress_Data
*)user
;
103 if (num_sfnts
> 1 && curr_sfnt
!= data
->last_sfnt
)
105 fprintf(stderr
, "subfont %ld of %ld\n", curr_sfnt
+ 1, num_sfnts
);
106 data
->last_sfnt
= curr_sfnt
;
107 data
->last_percent
= 0;
113 fprintf(stderr
, " %ld glyphs\n"
118 // print progress approx. every 10%
119 int curr_percent
= curr_idx
* 100 / num_glyphs
;
120 int curr_diff
= curr_percent
- data
->last_percent
;
124 fprintf(stderr
, " %d%%", curr_percent
);
125 data
->last_percent
= curr_percent
- curr_percent
% 10;
128 if (curr_idx
+ 1 == num_glyphs
)
129 fprintf(stderr
, "\n");
138 #ifdef CONSOLE_OUTPUT
147 FILE* handle
= is_error
? stderr
: stdout
;
151 "Usage: ttfautohintGUI [OPTION]...\n"
152 "A GUI application to replace hints in a TrueType font.\n"
154 "Usage: ttfautohint [OPTION]... [IN-FILE [OUT-FILE]]\n"
155 "Replace hints in TrueType font IN-FILE and write output to OUT-FILE.\n"
156 "If OUT-FILE is missing, standard output is used instead;\n"
157 "if IN-FILE is missing also, standard input and output are used.\n"
160 "The new hints are based on FreeType's auto-hinter.\n"
162 "This program is a simple front-end to the `ttfautohint' library.\n"
166 "Long options can be given with one or two dashes,\n"
167 "and with and without equal sign between option and argument.\n"
168 "This means that the following forms are acceptable:\n"
169 "`-foo=bar', `--foo=bar', `-foo bar', `--foo bar'.\n"
171 "Mandatory arguments to long options are mandatory for short options too.\n"
173 "Options not related to Qt or X11 set default values.\n"
181 " --debug print debugging information\n"
183 " -c, --composites hint glyph composites also\n"
184 " -d, --dehint remove all hints\n"
185 " -f, --fallback-script=S set fallback script (default: dflt)\n"
186 " -G, --hinting-limit=N switch off hinting above this PPEM value\n"
187 " (default: %d); value 0 means no limit\n"
188 " -h, --help display this help and exit\n"
190 " --help-all show Qt and X11 specific options also\n"
192 " -i, --ignore-restrictions override font license restrictions\n"
193 " -l, --hinting-range-min=N the minimum PPEM value for hint sets\n"
195 " -n, --no-info don't add ttfautohint info\n"
196 " to the version string(s) in the `name' table\n"
197 " -p, --pre-hinting apply original hints in advance\n",
198 TA_HINTING_LIMIT
, TA_HINTING_RANGE_MIN
);
200 " -r, --hinting-range-max=N the maximum PPEM value for hint sets\n"
202 " -s, --symbol input is symbol font\n"
203 " -v, --verbose show progress information\n"
204 " -V, --version print version information and exit\n"
205 " -w, --strong-stem-width=S use strong stem width routine for modes S,\n"
206 " where S is a string of up to three letters\n"
207 " with possible values `g' for grayscale,\n"
208 " `G' for GDI ClearType, and `D' for\n"
209 " DirectWrite ClearType (default: G)\n"
210 " -W, --windows-compatibility\n"
211 " add blue zones for `usWinAscent' and\n"
212 " `usWinDescent' to avoid clipping\n"
213 " -x, --increase-x-height=N increase x height for sizes in the range\n"
214 " 6<=PPEM<=N; value 0 switches off this feature\n"
216 " -X, --x-height-snapping-exceptions=STRING\n"
217 " specify a comma-separated list of\n"
218 " x-height snapping exceptions, for example\n"
219 " \"-9, 13-17, 19\" (default: \"\")\n"
221 TA_HINTING_RANGE_MAX
, TA_INCREASE_X_HEIGHT
);
228 " --graphicssystem=SYSTEM\n"
229 " select a different graphics system backend\n"
230 " instead of the default one\n"
231 " (possible values: `raster', `opengl')\n"
232 " --reverse set layout direction to right-to-left\n");
234 " --session=ID restore the application for the given ID\n"
235 " --style=STYLE set application GUI style\n"
236 " (possible values: motif, windows, platinum)\n"
237 " --stylesheet=SHEET apply the given Qt stylesheet\n"
238 " to the application widgets\n"
243 " --background=COLOR set the default background color\n"
244 " and an application palette\n"
245 " (light and dark shades are calculated)\n"
246 " --bg=COLOR same as --background\n"
247 " --btn=COLOR set the default button color\n"
248 " --button=COLOR same as --btn\n"
249 " --cmap use a private color map on an 8-bit display\n"
250 " --display=NAME use the given X-server display\n");
252 " --fg=COLOR set the default foreground color\n"
253 " --fn=FONTNAME set the application font\n"
254 " --font=FONTNAME same as --fn\n"
255 " --foreground=COLOR same as --fg\n"
256 " --geometry=GEOMETRY set the client geometry of first window\n"
257 " --im=SERVER set the X Input Method (XIM) server\n"
258 " --inputstyle=STYLE set X Input Method input style\n"
259 " (possible values: onthespot, overthespot,\n"
260 " offthespot, root)\n");
262 " --name=NAME set the application name\n"
263 " --ncols=COUNT limit the number of colors allocated\n"
264 " in the color cube on an 8-bit display,\n"
265 " if the application is using the\n"
266 " QApplication::ManyColor color specification\n"
267 " --title=TITLE set the application title (caption)\n"
268 " --visual=VISUAL force the application\n"
269 " to use the given visual on an 8-bit display\n"
270 " (only possible value: TrueColor)\n"
276 "The program accepts both TTF and TTC files as input.\n"
277 "Use option -i only if you have a legal permission to modify the font.\n"
278 "The used PPEM value for option -p is FUnits per em, normally 2048.\n"
279 "With option -s, use default values for standard stem width and height,\n"
280 "otherwise they are derived from latin character `o'.\n"
283 "A hint set contains the optimal hinting for a certain PPEM value;\n"
284 "the larger the hint set range, the more hint sets get computed,\n"
285 "usually increasing the output font size. Note, however,\n"
286 "that the `gasp' table of the output file enables grayscale hinting\n"
287 "for all sizes (limited by option -G, which is handled in the bytecode).\n"
290 "Option -f takes a four-letter string that identifies the script\n"
291 "to be used as a fallback for glyphs that have character codes\n"
292 "outside of known script ranges. Possible values are\n"
294 const Script_Names
* sn
= script_names
;
297 fprintf(handle
, " %s (%s)",
298 sn
->tag
, sn
->description
);
301 fprintf(handle
, ",\n");
304 fprintf(handle
, ".\n");
310 "If no option -f is given, or if its value is `dflt',\n"
311 "no fallback script is used.\n"
315 "A command-line version of this program is called `ttfautohint'.\n"
317 "A GUI version of this program is called `ttfautohintGUI'.\n"
320 "Report bugs to: freetype-devel@nongnu.org\n"
321 "ttfautohint home page: <http://www.freetype.org/ttfautohint>\n");
335 "ttfautohintGUI " VERSION
"\n"
337 "ttfautohint " VERSION
"\n"
339 "Copyright (C) 2011-2013 Werner Lemberg <wl@gnu.org>.\n"
340 "License: FreeType License (FTL) or GNU GPLv2.\n"
341 "This is free software: you are free to change and redistribute it.\n"
342 "There is NO WARRANTY, to the extent permitted by law.\n");
346 #endif // CONSOLE_OUTPUT
353 int hinting_range_min
= 0;
354 int hinting_range_max
= 0;
355 int hinting_limit
= 0;
356 int increase_x_height
= 0;
357 bool have_hinting_range_min
= false;
358 bool have_hinting_range_max
= false;
359 bool have_hinting_limit
= false;
360 bool have_increase_x_height
= false;
362 bool gray_strong_stem_width
= false;
363 bool gdi_cleartype_strong_stem_width
= true;
364 bool dw_cleartype_strong_stem_width
= false;
366 bool ignore_restrictions
= false;
367 bool windows_compatibility
= false;
368 bool pre_hinting
= false;
369 bool hint_composites
= false;
370 bool no_info
= false;
373 const char* fallback_script
= NULL
;
374 bool have_fallback_script
= false;
375 const char* x_height_snapping_exceptions_string
= NULL
;
376 bool have_x_height_snapping_exceptions_string
= false;
383 TA_Progress_Func progress_func
= NULL
;
384 TA_Info_Func info_func
= info
;
387 // make GNU, Qt, and X11 command line options look the same;
388 // we allow `--foo=bar', `--foo bar', `-foo=bar', `-foo bar',
389 // and short options specific to ttfautohint
391 // set up a new argument string
392 vector
<string
> new_arg_string
;
393 new_arg_string
.push_back(argv
[0]);
397 // use pseudo short options for long-only options
400 PASS_THROUGH
= CHAR_MAX
+ 1,
405 static struct option long_options
[] =
407 {"help", no_argument
, NULL
, 'h'},
409 {"help-all", no_argument
, NULL
, HELP_ALL_OPTION
},
412 // ttfautohint options
413 {"composites", no_argument
, NULL
, 'c'},
415 {"debug", no_argument
, NULL
, DEBUG_OPTION
},
417 {"dehint", no_argument
, NULL
, 'd'},
418 {"fallback-script", required_argument
, NULL
, 'f'},
419 {"hinting-limit", required_argument
, NULL
, 'G'},
420 {"hinting-range-max", required_argument
, NULL
, 'r'},
421 {"hinting-range-min", required_argument
, NULL
, 'l'},
422 {"ignore-restrictions", no_argument
, NULL
, 'i'},
423 {"increase-x-height", required_argument
, NULL
, 'x'},
424 {"no-info", no_argument
, NULL
, 'n'},
425 {"pre-hinting", no_argument
, NULL
, 'p'},
426 {"strong-stem-width", required_argument
, NULL
, 'w'},
427 {"symbol", no_argument
, NULL
, 's'},
428 {"verbose", no_argument
, NULL
, 'v'},
429 {"version", no_argument
, NULL
, 'V'},
430 {"windows-compatibility", no_argument
, NULL
, 'W'},
431 {"x-height-snapping-exceptions", required_argument
, NULL
, 'X'},
434 {"graphicssystem", required_argument
, NULL
, PASS_THROUGH
},
435 {"reverse", no_argument
, NULL
, PASS_THROUGH
},
436 {"session", required_argument
, NULL
, PASS_THROUGH
},
437 {"style", required_argument
, NULL
, PASS_THROUGH
},
438 {"stylesheet", required_argument
, NULL
, PASS_THROUGH
},
441 {"background", required_argument
, NULL
, PASS_THROUGH
},
442 {"bg", required_argument
, NULL
, PASS_THROUGH
},
443 {"btn", required_argument
, NULL
, PASS_THROUGH
},
444 {"button", required_argument
, NULL
, PASS_THROUGH
},
445 {"cmap", no_argument
, NULL
, PASS_THROUGH
},
446 {"display", required_argument
, NULL
, PASS_THROUGH
},
447 {"fg", required_argument
, NULL
, PASS_THROUGH
},
448 {"fn", required_argument
, NULL
, PASS_THROUGH
},
449 {"font", required_argument
, NULL
, PASS_THROUGH
},
450 {"foreground", required_argument
, NULL
, PASS_THROUGH
},
451 {"geometry", required_argument
, NULL
, PASS_THROUGH
},
452 {"im", required_argument
, NULL
, PASS_THROUGH
},
453 {"inputstyle", required_argument
, NULL
, PASS_THROUGH
},
454 {"name", required_argument
, NULL
, PASS_THROUGH
},
455 {"ncols", required_argument
, NULL
, PASS_THROUGH
},
456 {"title", required_argument
, NULL
, PASS_THROUGH
},
457 {"visual", required_argument
, NULL
, PASS_THROUGH
},
463 int c
= getopt_long_only(argc
, argv
, "cdf:G:hil:npr:stVvw:Wx:X:",
464 long_options
, &option_index
);
471 hint_composites
= true;
479 fallback_script
= optarg
;
480 have_fallback_script
= true;
484 hinting_limit
= atoi(optarg
);
485 have_hinting_limit
= true;
489 #ifdef CONSOLE_OUTPUT
490 show_help(false, false);
495 ignore_restrictions
= true;
499 hinting_range_min
= atoi(optarg
);
500 have_hinting_range_min
= true;
512 hinting_range_max
= atoi(optarg
);
513 have_hinting_range_max
= true;
522 progress_func
= progress
;
527 #ifdef CONSOLE_OUTPUT
533 gray_strong_stem_width
= strchr(optarg
, 'g') ? true : false;
534 gdi_cleartype_strong_stem_width
= strchr(optarg
, 'G') ? true : false;
535 dw_cleartype_strong_stem_width
= strchr(optarg
, 'D') ? true : false;
539 windows_compatibility
= true;
543 increase_x_height
= atoi(optarg
);
544 have_increase_x_height
= true;
548 x_height_snapping_exceptions_string
= optarg
;
549 have_x_height_snapping_exceptions_string
= true;
559 case HELP_ALL_OPTION
:
560 #ifdef CONSOLE_OUTPUT
561 show_help(true, false);
568 // append argument with proper syntax for Qt
571 arg
+= long_options
[option_index
].name
;
573 new_arg_string
.push_back(arg
);
575 new_arg_string
.push_back(optarg
);
586 // -d makes ttfautohint ignore all other hinting options
587 have_fallback_script
= false;
588 have_hinting_range_min
= false;
589 have_hinting_range_max
= false;
590 have_hinting_limit
= false;
591 have_increase_x_height
= false;
592 have_x_height_snapping_exceptions_string
= false;
595 if (!have_fallback_script
)
596 fallback_script
= "dflt";
597 if (!have_hinting_range_min
)
598 hinting_range_min
= TA_HINTING_RANGE_MIN
;
599 if (!have_hinting_range_max
)
600 hinting_range_max
= TA_HINTING_RANGE_MAX
;
601 if (!have_hinting_limit
)
602 hinting_limit
= TA_HINTING_LIMIT
;
603 if (!have_increase_x_height
)
604 increase_x_height
= TA_INCREASE_X_HEIGHT
;
605 if (!have_x_height_snapping_exceptions_string
)
606 x_height_snapping_exceptions_string
= "";
610 if (!isatty(fileno(stderr
)) && !debug
)
611 setvbuf(stderr
, (char*)NULL
, _IONBF
, BUFSIZ
);
613 if (hinting_range_min
< 2)
615 fprintf(stderr
, "The hinting range minimum must be at least 2\n");
618 if (hinting_range_max
< hinting_range_min
)
620 fprintf(stderr
, "The hinting range maximum must not be smaller"
621 " than the minimum (%d)\n",
625 if (hinting_limit
!= 0 && hinting_limit
< hinting_range_max
)
627 fprintf(stderr
, "A non-zero hinting limit must not be smaller"
628 " than the hinting range maximum (%d)\n",
632 if (increase_x_height
!= 0 && increase_x_height
< 6)
634 fprintf(stderr
, "A non-zero x height increase limit"
635 " must be larger than or equal to 6\n");
639 number_range
* x_height_snapping_exceptions
= NULL
;
641 if (have_x_height_snapping_exceptions_string
)
646 s
= number_set_parse(x_height_snapping_exceptions_string
,
647 &x_height_snapping_exceptions
,
651 if (x_height_snapping_exceptions
== NUMBERSET_ALLOCATION_ERROR
)
652 fprintf(stderr
, "Allocation error while scanning"
653 " x height snapping exceptions\n");
655 if (x_height_snapping_exceptions
== NUMBERSET_INVALID_CHARACTER
)
656 fprintf(stderr
, "Invalid character");
657 else if (x_height_snapping_exceptions
== NUMBERSET_OVERFLOW
)
658 fprintf(stderr
, "Overflow");
659 else if (x_height_snapping_exceptions
== NUMBERSET_INVALID_RANGE
)
660 fprintf(stderr
, "Invalid range");
661 else if (x_height_snapping_exceptions
== NUMBERSET_OVERLAPPING_RANGES
)
662 fprintf(stderr
, "Overlapping ranges");
663 else if (x_height_snapping_exceptions
== NUMBERSET_NOT_ASCENDING
)
664 fprintf(stderr
, "Values und ranges must be ascending");
665 fprintf(stderr
, " in x height snapping exceptions:\n"
668 x_height_snapping_exceptions_string
,
669 s
- x_height_snapping_exceptions_string
+ 1, "^");
675 if (have_fallback_script
)
677 const Script_Names
* sn
;
679 for (sn
= script_names
; sn
->tag
; sn
++)
680 if (!strcmp(fallback_script
, sn
->tag
))
684 fprintf(stderr
, "Unknown script tag `%s'\n", fallback_script
);
689 int num_args
= argc
- optind
;
692 show_help(false, true);
697 in
= fopen(argv
[optind
], "rb");
700 fprintf(stderr
, "The following error occurred while opening font `%s':\n"
703 argv
[optind
], strerror(errno
));
709 if (isatty(fileno(stdin
)))
710 show_help(false, true);
717 if (!strcmp(argv
[optind
], argv
[optind
+ 1]))
719 fprintf(stderr
, "Input and output file names must not be identical\n");
723 out
= fopen(argv
[optind
+ 1], "wb");
726 fprintf(stderr
, "The following error occurred while opening font `%s':\n"
729 argv
[optind
+ 1], strerror(errno
));
735 if (isatty(fileno(stdout
)))
736 show_help(false, true);
740 const unsigned char* error_string
;
741 Progress_Data progress_data
= {-1, 1, 0};
748 info_data
.data
= NULL
; // must be deallocated after use
749 info_data
.data_wide
= NULL
; // must be deallocated after use
750 info_data
.data_len
= 0;
751 info_data
.data_wide_len
= 0;
753 info_data
.hinting_range_min
= hinting_range_min
;
754 info_data
.hinting_range_max
= hinting_range_max
;
755 info_data
.hinting_limit
= hinting_limit
;
757 info_data
.gray_strong_stem_width
= gray_strong_stem_width
;
758 info_data
.gdi_cleartype_strong_stem_width
= gdi_cleartype_strong_stem_width
;
759 info_data
.dw_cleartype_strong_stem_width
= dw_cleartype_strong_stem_width
;
761 info_data
.windows_compatibility
= windows_compatibility
;
762 info_data
.pre_hinting
= pre_hinting
;
763 info_data
.hint_composites
= hint_composites
;
764 info_data
.increase_x_height
= increase_x_height
;
765 info_data
.x_height_snapping_exceptions
= x_height_snapping_exceptions
;
766 info_data
.symbol
= symbol
;
768 strncpy(info_data
.fallback_script
,
770 sizeof (info_data
.fallback_script
));
772 info_data
.dehint
= dehint
;
774 int ret
= build_version_string(&info_data
);
776 fprintf(stderr
, "Warning: Can't allocate memory"
777 " for ttfautohint options string in `name' table\n");
779 fprintf(stderr
, "Warning: ttfautohint options string"
780 " in `name' table too long\n");
789 TTF_autohint("in-file, out-file,"
790 "hinting-range-min, hinting-range-max, hinting-limit,"
791 "gray-strong-stem-width, gdi-cleartype-strong-stem-width,"
792 "dw-cleartype-strong-stem-width,"
794 "progress-callback, progress-callback-data,"
795 "info-callback, info-callback-data,"
796 "ignore-restrictions, windows-compatibility,"
797 "pre-hinting, hint-composites,"
798 "increase-x-height, x-height-snapping-exceptions,"
799 "fallback-script, symbol,"
802 hinting_range_min
, hinting_range_max
, hinting_limit
,
803 gray_strong_stem_width
, gdi_cleartype_strong_stem_width
,
804 dw_cleartype_strong_stem_width
,
806 progress_func
, &progress_data
,
807 info_func
, &info_data
,
808 ignore_restrictions
, windows_compatibility
,
809 pre_hinting
, hint_composites
,
810 increase_x_height
, x_height_snapping_exceptions_string
,
811 fallback_script
, symbol
,
816 free(info_data
.data
);
817 free(info_data
.data_wide
);
820 number_set_free(x_height_snapping_exceptions
);
824 if (error
== TA_Err_Invalid_FreeType_Version
)
826 "FreeType version 2.4.5 or higher is needed.\n"
827 "Perhaps using a wrong FreeType DLL?\n");
828 else if (error
== TA_Err_Invalid_Font_Type
)
830 "This font is not a valid font"
831 " in SFNT format with TrueType outlines.\n"
832 "In particular, CFF outlines are not supported.\n");
833 else if (error
== TA_Err_Already_Processed
)
835 "This font has already been processed with ttfautohint.\n");
836 else if (error
== TA_Err_Missing_Legal_Permission
)
838 "Bit 1 in the `fsType' field of the `OS/2' table is set:\n"
839 "This font must not be modified"
840 " without permission of the legal owner.\n"
841 "Use command line option `-i' to continue"
842 " if you have such a permission.\n");
843 else if (error
== TA_Err_Missing_Unicode_CMap
)
845 "No Unicode character map.\n");
846 else if (error
== TA_Err_Missing_Symbol_CMap
)
848 "No symbol character map.\n");
849 else if (error
== TA_Err_Missing_Glyph
)
851 "No glyph for the key character"
852 " to derive standard width and height.\n"
853 "For the latin script, this key character is `o' (U+006F).\n");
856 "Error code `0x%02x' while autohinting font:\n"
857 " %s\n", error
, error_string
);
868 return 0; // never reached
872 int new_argc
= new_arg_string
.size();
873 char** new_argv
= new char*[new_argc
];
875 // construct new argc and argv variables from collected data
876 for (int i
= 0; i
< new_argc
; i
++)
877 new_argv
[i
] = const_cast<char*>(new_arg_string
[i
].data());
879 QApplication
app(new_argc
, new_argv
);
880 app
.setApplicationName("TTFautohint");
881 app
.setApplicationVersion(VERSION
);
882 app
.setOrganizationName("FreeType");
883 app
.setOrganizationDomain("freetype.org");
885 Main_GUI
gui(hinting_range_min
, hinting_range_max
, hinting_limit
,
886 gray_strong_stem_width
, gdi_cleartype_strong_stem_width
,
887 dw_cleartype_strong_stem_width
, increase_x_height
,
888 x_height_snapping_exceptions_string
,
889 ignore_restrictions
, windows_compatibility
, pre_hinting
,
890 hint_composites
, no_info
, fallback_script
, symbol
,