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)
67 typedef struct Progress_Data_
76 progress(long curr_idx
,
82 Progress_Data
* data
= (Progress_Data
*)user
;
84 if (num_sfnts
> 1 && curr_sfnt
!= data
->last_sfnt
)
86 fprintf(stderr
, "subfont %ld of %ld\n", curr_sfnt
+ 1, num_sfnts
);
87 data
->last_sfnt
= curr_sfnt
;
88 data
->last_percent
= 0;
94 fprintf(stderr
, " %ld glyphs\n"
99 // print progress approx. every 10%
100 int curr_percent
= curr_idx
* 100 / num_glyphs
;
101 int curr_diff
= curr_percent
- data
->last_percent
;
105 fprintf(stderr
, " %d%%", curr_percent
);
106 data
->last_percent
= curr_percent
- curr_percent
% 10;
109 if (curr_idx
+ 1 == num_glyphs
)
110 fprintf(stderr
, "\n");
119 #ifdef CONSOLE_OUTPUT
128 FILE* handle
= is_error
? stderr
: stdout
;
132 "Usage: ttfautohintGUI [OPTION]...\n"
133 "A GUI application to replace hints in a TrueType font.\n"
135 "Usage: ttfautohint [OPTION]... [IN-FILE [OUT-FILE]]\n"
136 "Replace hints in TrueType font IN-FILE and write output to OUT-FILE.\n"
137 "If OUT-FILE is missing, standard output is used instead;\n"
138 "if IN-FILE is missing also, standard input and output are used.\n"
141 "The new hints are based on FreeType's auto-hinter.\n"
143 "This program is a simple front-end to the `ttfautohint' library.\n"
147 "Long options can be given with one or two dashes,\n"
148 "and with and without equal sign between option and argument.\n"
149 "This means that the following forms are acceptable:\n"
150 "`-foo=bar', `--foo=bar', `-foo bar', `--foo bar'.\n"
152 "Mandatory arguments to long options are mandatory for short options too.\n"
154 "Options not related to Qt or X11 set default values.\n"
162 " --debug print debugging information\n"
164 " -c, --composites hint glyph composites also\n"
165 " -d, --dehint remove all hints\n"
166 " -f, --latin-fallback set fallback script to latin\n"
167 " -G, --hinting-limit=N switch off hinting above this PPEM value\n"
168 " (default: %d); value 0 means no limit\n"
169 " -h, --help display this help and exit\n"
171 " --help-all show Qt and X11 specific options also\n"
173 " -i, --ignore-restrictions override font license restrictions\n"
174 " -l, --hinting-range-min=N the minimum PPEM value for hint sets\n"
176 " -n, --no-info don't add ttfautohint info\n"
177 " to the version string(s) in the `name' table\n"
178 " -p, --pre-hinting apply original hints in advance\n",
179 TA_HINTING_LIMIT
, TA_HINTING_RANGE_MIN
);
181 " -r, --hinting-range-max=N the maximum PPEM value for hint sets\n"
183 " -s, --symbol input is symbol font\n"
184 " -v, --verbose show progress information\n"
185 " -V, --version print version information and exit\n"
186 " -w, --strong-stem-width=S use strong stem width routine for modes S,\n"
187 " where S is a string of up to three letters\n"
188 " with possible values `g' for grayscale,\n"
189 " `G' for GDI ClearType, and `D' for\n"
190 " DirectWrite ClearType (default: G)\n"
191 " -W, --windows-compatibility\n"
192 " add blue zones for `usWinAscent' and\n"
193 " `usWinDescent' to avoid clipping\n"
194 " -x, --increase-x-height=N increase x height for sizes in the range\n"
195 " 6<=PPEM<=N; value 0 switches off this feature\n"
197 " -X, --x-height-snapping-exceptions=STRING\n"
198 " specify a comma-separated list of\n"
199 " x-height snapping exceptions, for example\n"
200 " \"-9, 13-17, 19\" (default: \"\")\n"
202 TA_HINTING_RANGE_MAX
, TA_INCREASE_X_HEIGHT
);
209 " --graphicssystem=SYSTEM\n"
210 " select a different graphics system backend\n"
211 " instead of the default one\n"
212 " (possible values: `raster', `opengl')\n"
213 " --reverse set layout direction to right-to-left\n");
215 " --session=ID restore the application for the given ID\n"
216 " --style=STYLE set application GUI style\n"
217 " (possible values: motif, windows, platinum)\n"
218 " --stylesheet=SHEET apply the given Qt stylesheet\n"
219 " to the application widgets\n"
224 " --background=COLOR set the default background color\n"
225 " and an application palette\n"
226 " (light and dark shades are calculated)\n"
227 " --bg=COLOR same as --background\n"
228 " --btn=COLOR set the default button color\n"
229 " --button=COLOR same as --btn\n"
230 " --cmap use a private color map on an 8-bit display\n"
231 " --display=NAME use the given X-server display\n");
233 " --fg=COLOR set the default foreground color\n"
234 " --fn=FONTNAME set the application font\n"
235 " --font=FONTNAME same as --fn\n"
236 " --foreground=COLOR same as --fg\n"
237 " --geometry=GEOMETRY set the client geometry of first window\n"
238 " --im=SERVER set the X Input Method (XIM) server\n"
239 " --inputstyle=STYLE set X Input Method input style\n"
240 " (possible values: onthespot, overthespot,\n"
241 " offthespot, root)\n");
243 " --name=NAME set the application name\n"
244 " --ncols=COUNT limit the number of colors allocated\n"
245 " in the color cube on an 8-bit display,\n"
246 " if the application is using the\n"
247 " QApplication::ManyColor color specification\n"
248 " --title=TITLE set the application title (caption)\n"
249 " --visual=VISUAL force the application\n"
250 " to use the given visual on an 8-bit display\n"
251 " (only possible value: TrueColor)\n"
257 "The program accepts both TTF and TTC files as input.\n"
258 "Use option -i only if you have a legal permission to modify the font.\n"
259 "If option -f is not set, glyphs not in the latin range stay unhinted.\n"
260 "The used PPEM value for option -p is FUnits per em, normally 2048.\n"
261 "With option -s, use default values for standard stem width and height,\n"
262 "otherwise they are derived from latin character `o'.\n"
265 "A hint set contains the optimal hinting for a certain PPEM value;\n"
266 "the larger the hint set range, the more hint sets get computed,\n"
267 "usually increasing the output font size. Note, however,\n"
268 "that the `gasp' table of the output file enables grayscale hinting\n"
269 "for all sizes (limited by option -G which is handled in the bytecode).\n"
273 "A command-line version of this program is called `ttfautohint'.\n"
275 "A GUI version of this program is called `ttfautohintGUI'.\n"
278 "Report bugs to: freetype-devel@nongnu.org\n"
279 "ttfautohint home page: <http://www.freetype.org/ttfautohint>\n");
293 "ttfautohintGUI " VERSION
"\n"
295 "ttfautohint " VERSION
"\n"
297 "Copyright (C) 2011-2013 Werner Lemberg <wl@gnu.org>.\n"
298 "License: FreeType License (FTL) or GNU GPLv2.\n"
299 "This is free software: you are free to change and redistribute it.\n"
300 "There is NO WARRANTY, to the extent permitted by law.\n");
304 #endif // CONSOLE_OUTPUT
311 int hinting_range_min
= 0;
312 int hinting_range_max
= 0;
313 int hinting_limit
= 0;
314 int increase_x_height
= 0;
315 bool have_hinting_range_min
= false;
316 bool have_hinting_range_max
= false;
317 bool have_hinting_limit
= false;
318 bool have_increase_x_height
= false;
320 bool gray_strong_stem_width
= false;
321 bool gdi_cleartype_strong_stem_width
= true;
322 bool dw_cleartype_strong_stem_width
= false;
324 bool ignore_restrictions
= false;
325 bool windows_compatibility
= false;
326 bool pre_hinting
= false;
327 bool hint_composites
= false;
328 bool no_info
= false;
329 int latin_fallback
= 0; // leave it as int; this probably gets extended
332 const char* x_height_snapping_exceptions_string
= NULL
;
333 bool have_x_height_snapping_exceptions_string
= false;
340 TA_Progress_Func progress_func
= NULL
;
341 TA_Info_Func info_func
= info
;
344 // make GNU, Qt, and X11 command line options look the same;
345 // we allow `--foo=bar', `--foo bar', `-foo=bar', `-foo bar',
346 // and short options specific to ttfautohint
348 // set up a new argument string
349 vector
<string
> new_arg_string
;
350 new_arg_string
.push_back(argv
[0]);
354 // use pseudo short options for long-only options
357 PASS_THROUGH
= CHAR_MAX
+ 1,
362 static struct option long_options
[] =
364 {"help", no_argument
, NULL
, 'h'},
366 {"help-all", no_argument
, NULL
, HELP_ALL_OPTION
},
369 // ttfautohint options
370 {"composites", no_argument
, NULL
, 'c'},
372 {"debug", no_argument
, NULL
, DEBUG_OPTION
},
374 {"dehint", no_argument
, NULL
, 'd'},
375 {"hinting-limit", required_argument
, NULL
, 'G'},
376 {"hinting-range-max", required_argument
, NULL
, 'r'},
377 {"hinting-range-min", required_argument
, NULL
, 'l'},
378 {"ignore-restrictions", no_argument
, NULL
, 'i'},
379 {"increase-x-height", required_argument
, NULL
, 'x'},
380 {"latin-fallback", no_argument
, NULL
, 'f'},
381 {"no-info", no_argument
, NULL
, 'n'},
382 {"pre-hinting", no_argument
, NULL
, 'p'},
383 {"strong-stem-width", required_argument
, NULL
, 'w'},
384 {"symbol", no_argument
, NULL
, 's'},
385 {"verbose", no_argument
, NULL
, 'v'},
386 {"version", no_argument
, NULL
, 'V'},
387 {"windows-compatibility", no_argument
, NULL
, 'W'},
388 {"x-height-snapping-exceptions", required_argument
, NULL
, 'X'},
391 {"graphicssystem", required_argument
, NULL
, PASS_THROUGH
},
392 {"reverse", no_argument
, NULL
, PASS_THROUGH
},
393 {"session", required_argument
, NULL
, PASS_THROUGH
},
394 {"style", required_argument
, NULL
, PASS_THROUGH
},
395 {"stylesheet", required_argument
, NULL
, PASS_THROUGH
},
398 {"background", required_argument
, NULL
, PASS_THROUGH
},
399 {"bg", required_argument
, NULL
, PASS_THROUGH
},
400 {"btn", required_argument
, NULL
, PASS_THROUGH
},
401 {"button", required_argument
, NULL
, PASS_THROUGH
},
402 {"cmap", no_argument
, NULL
, PASS_THROUGH
},
403 {"display", required_argument
, NULL
, PASS_THROUGH
},
404 {"fg", required_argument
, NULL
, PASS_THROUGH
},
405 {"fn", required_argument
, NULL
, PASS_THROUGH
},
406 {"font", required_argument
, NULL
, PASS_THROUGH
},
407 {"foreground", required_argument
, NULL
, PASS_THROUGH
},
408 {"geometry", required_argument
, NULL
, PASS_THROUGH
},
409 {"im", required_argument
, NULL
, PASS_THROUGH
},
410 {"inputstyle", required_argument
, NULL
, PASS_THROUGH
},
411 {"name", required_argument
, NULL
, PASS_THROUGH
},
412 {"ncols", required_argument
, NULL
, PASS_THROUGH
},
413 {"title", required_argument
, NULL
, PASS_THROUGH
},
414 {"visual", required_argument
, NULL
, PASS_THROUGH
},
420 int c
= getopt_long_only(argc
, argv
, "cdfG:hil:npr:stVvw:Wx:X:",
421 long_options
, &option_index
);
428 hint_composites
= true;
440 hinting_limit
= atoi(optarg
);
441 have_hinting_limit
= true;
445 #ifdef CONSOLE_OUTPUT
446 show_help(false, false);
451 ignore_restrictions
= true;
455 hinting_range_min
= atoi(optarg
);
456 have_hinting_range_min
= true;
468 hinting_range_max
= atoi(optarg
);
469 have_hinting_range_max
= true;
478 progress_func
= progress
;
483 #ifdef CONSOLE_OUTPUT
489 gray_strong_stem_width
= strchr(optarg
, 'g') ? true : false;
490 gdi_cleartype_strong_stem_width
= strchr(optarg
, 'G') ? true : false;
491 dw_cleartype_strong_stem_width
= strchr(optarg
, 'D') ? true : false;
495 windows_compatibility
= true;
499 increase_x_height
= atoi(optarg
);
500 have_increase_x_height
= true;
504 x_height_snapping_exceptions_string
= optarg
;
505 have_x_height_snapping_exceptions_string
= true;
515 case HELP_ALL_OPTION
:
516 #ifdef CONSOLE_OUTPUT
517 show_help(true, false);
524 // append argument with proper syntax for Qt
527 arg
+= long_options
[option_index
].name
;
529 new_arg_string
.push_back(arg
);
531 new_arg_string
.push_back(optarg
);
542 // -d makes ttfautohint ignore all other hinting options
543 have_hinting_range_min
= false;
544 have_hinting_range_max
= false;
545 have_hinting_limit
= false;
546 have_increase_x_height
= false;
547 have_x_height_snapping_exceptions_string
= false;
550 if (!have_hinting_range_min
)
551 hinting_range_min
= TA_HINTING_RANGE_MIN
;
552 if (!have_hinting_range_max
)
553 hinting_range_max
= TA_HINTING_RANGE_MAX
;
554 if (!have_hinting_limit
)
555 hinting_limit
= TA_HINTING_LIMIT
;
556 if (!have_increase_x_height
)
557 increase_x_height
= TA_INCREASE_X_HEIGHT
;
558 if (!have_x_height_snapping_exceptions_string
)
559 x_height_snapping_exceptions_string
= "";
563 if (!isatty(fileno(stderr
)) && !debug
)
564 setvbuf(stderr
, (char*)NULL
, _IONBF
, BUFSIZ
);
566 if (hinting_range_min
< 2)
568 fprintf(stderr
, "The hinting range minimum must be at least 2\n");
571 if (hinting_range_max
< hinting_range_min
)
573 fprintf(stderr
, "The hinting range maximum must not be smaller"
574 " than the minimum (%d)\n",
578 if (hinting_limit
!= 0 && hinting_limit
< hinting_range_max
)
580 fprintf(stderr
, "A non-zero hinting limit must not be smaller"
581 " than the hinting range maximum (%d)\n",
585 if (increase_x_height
!= 0 && increase_x_height
< 6)
587 fprintf(stderr
, "A non-zero x height increase limit"
588 " must be larger than or equal to 6\n");
592 number_range
* x_height_snapping_exceptions
= NULL
;
594 if (have_x_height_snapping_exceptions_string
)
599 s
= number_set_parse(x_height_snapping_exceptions_string
,
600 &x_height_snapping_exceptions
,
604 if (x_height_snapping_exceptions
== NUMBERSET_ALLOCATION_ERROR
)
605 fprintf(stderr
, "Allocation error while scanning"
606 " x height snapping exceptions\n");
608 if (x_height_snapping_exceptions
== NUMBERSET_INVALID_CHARACTER
)
609 fprintf(stderr
, "Invalid character");
610 else if (x_height_snapping_exceptions
== NUMBERSET_OVERFLOW
)
611 fprintf(stderr
, "Overflow");
612 else if (x_height_snapping_exceptions
== NUMBERSET_INVALID_RANGE
)
613 fprintf(stderr
, "Invalid range");
614 else if (x_height_snapping_exceptions
== NUMBERSET_OVERLAPPING_RANGES
)
615 fprintf(stderr
, "Overlapping ranges");
616 else if (x_height_snapping_exceptions
== NUMBERSET_NOT_ASCENDING
)
617 fprintf(stderr
, "Values und ranges must be ascending");
618 fprintf(stderr
, " in x height snapping exceptions:\n"
621 x_height_snapping_exceptions_string
,
622 s
- x_height_snapping_exceptions_string
+ 1, "^");
628 int num_args
= argc
- optind
;
631 show_help(false, true);
636 in
= fopen(argv
[optind
], "rb");
639 fprintf(stderr
, "The following error occurred while opening font `%s':\n"
642 argv
[optind
], strerror(errno
));
648 if (isatty(fileno(stdin
)))
649 show_help(false, true);
656 if (!strcmp(argv
[optind
], argv
[optind
+ 1]))
658 fprintf(stderr
, "Input and output file names must not be identical\n");
662 out
= fopen(argv
[optind
+ 1], "wb");
665 fprintf(stderr
, "The following error occurred while opening font `%s':\n"
668 argv
[optind
+ 1], strerror(errno
));
674 if (isatty(fileno(stdout
)))
675 show_help(false, true);
679 const unsigned char* error_string
;
680 Progress_Data progress_data
= {-1, 1, 0};
687 info_data
.data
= NULL
; // must be deallocated after use
688 info_data
.data_wide
= NULL
; // must be deallocated after use
689 info_data
.data_len
= 0;
690 info_data
.data_wide_len
= 0;
692 info_data
.hinting_range_min
= hinting_range_min
;
693 info_data
.hinting_range_max
= hinting_range_max
;
694 info_data
.hinting_limit
= hinting_limit
;
696 info_data
.gray_strong_stem_width
= gray_strong_stem_width
;
697 info_data
.gdi_cleartype_strong_stem_width
= gdi_cleartype_strong_stem_width
;
698 info_data
.dw_cleartype_strong_stem_width
= dw_cleartype_strong_stem_width
;
700 info_data
.windows_compatibility
= windows_compatibility
;
701 info_data
.pre_hinting
= pre_hinting
;
702 info_data
.hint_composites
= hint_composites
;
703 info_data
.increase_x_height
= increase_x_height
;
704 info_data
.x_height_snapping_exceptions
= x_height_snapping_exceptions
;
705 info_data
.latin_fallback
= latin_fallback
;
706 info_data
.symbol
= symbol
;
708 info_data
.dehint
= dehint
;
710 int ret
= build_version_string(&info_data
);
712 fprintf(stderr
, "Warning: Can't allocate memory"
713 " for ttfautohint options string in `name' table\n");
715 fprintf(stderr
, "Warning: ttfautohint options string"
716 " in `name' table too long\n");
725 TTF_autohint("in-file, out-file,"
726 "hinting-range-min, hinting-range-max, hinting-limit,"
727 "gray-strong-stem-width, gdi-cleartype-strong-stem-width,"
728 "dw-cleartype-strong-stem-width,"
730 "progress-callback, progress-callback-data,"
731 "info-callback, info-callback-data,"
732 "ignore-restrictions, windows-compatibility,"
733 "pre-hinting, hint-composites,"
734 "increase-x-height, x-height-snapping-exceptions,"
735 "fallback-script, symbol,"
738 hinting_range_min
, hinting_range_max
, hinting_limit
,
739 gray_strong_stem_width
, gdi_cleartype_strong_stem_width
,
740 dw_cleartype_strong_stem_width
,
742 progress_func
, &progress_data
,
743 info_func
, &info_data
,
744 ignore_restrictions
, windows_compatibility
,
745 pre_hinting
, hint_composites
,
746 increase_x_height
, x_height_snapping_exceptions_string
,
747 latin_fallback
, symbol
,
752 free(info_data
.data
);
753 free(info_data
.data_wide
);
756 number_set_free(x_height_snapping_exceptions
);
760 if (error
== TA_Err_Invalid_FreeType_Version
)
762 "FreeType version 2.4.5 or higher is needed.\n"
763 "Perhaps using a wrong FreeType DLL?\n");
764 else if (error
== TA_Err_Invalid_Font_Type
)
766 "This font is not a valid font"
767 " in SFNT format with TrueType outlines.\n"
768 "In particular, CFF outlines are not supported.\n");
769 else if (error
== TA_Err_Already_Processed
)
771 "This font has already been processed with ttfautohint.\n");
772 else if (error
== TA_Err_Missing_Legal_Permission
)
774 "Bit 1 in the `fsType' field of the `OS/2' table is set:\n"
775 "This font must not be modified"
776 " without permission of the legal owner.\n"
777 "Use command line option `-i' to continue"
778 " if you have such a permission.\n");
779 else if (error
== TA_Err_Missing_Unicode_CMap
)
781 "No Unicode character map.\n");
782 else if (error
== TA_Err_Missing_Symbol_CMap
)
784 "No symbol character map.\n");
785 else if (error
== TA_Err_Missing_Glyph
)
787 "No glyph for the key character"
788 " to derive standard width and height.\n"
789 "For the latin script, this key character is `o' (U+006F).\n");
792 "Error code `0x%02x' while autohinting font:\n"
793 " %s\n", error
, error_string
);
804 return 0; // never reached
808 int new_argc
= new_arg_string
.size();
809 char** new_argv
= new char*[new_argc
];
811 // construct new argc and argv variables from collected data
812 for (int i
= 0; i
< new_argc
; i
++)
813 new_argv
[i
] = const_cast<char*>(new_arg_string
[i
].data());
815 QApplication
app(new_argc
, new_argv
);
816 app
.setApplicationName("TTFautohint");
817 app
.setApplicationVersion(VERSION
);
818 app
.setOrganizationName("FreeType");
819 app
.setOrganizationDomain("freetype.org");
821 Main_GUI
gui(hinting_range_min
, hinting_range_max
, hinting_limit
,
822 gray_strong_stem_width
, gdi_cleartype_strong_stem_width
,
823 dw_cleartype_strong_stem_width
, increase_x_height
,
824 x_height_snapping_exceptions_string
,
825 ignore_restrictions
, windows_compatibility
, pre_hinting
,
826 hint_composites
, no_info
, latin_fallback
, symbol
,