// main.cpp // Copyright (C) 2011-2021 by Werner Lemberg. // // This file is part of the ttfautohint library, and may only be used, // modified, and distributed under the terms given in `COPYING'. By // continuing to use, modify, or distribute this file you indicate that you // have read `COPYING' and understand and accept it fully. // // The file `COPYING' mentioned in the previous paragraph is distributed // with the ttfautohint library. // This program is a wrapper for `TTF_autohint'. #ifdef BUILD_GUI # ifndef _WIN32 # define CONSOLE_OUTPUT # endif #else # define CONSOLE_OUTPUT #endif #include #include #include #include #include #include #include #include #include #include #include #ifdef BUILD_GUI # include # include "maingui.h" #else # include # include FT_FREETYPE_H # include FT_TRUETYPE_TABLES_H // for option `-T' # include "info.h" #endif #include #include #ifndef BUILD_GUI # ifdef _WIN32 # include # define SET_BINARY(f) do { \ if (!isatty(fileno(f))) \ setmode(fileno(f), O_BINARY); \ } while (0) # endif # ifndef SET_BINARY # define SET_BINARY(f) do {} while (0) # endif #endif using namespace std; typedef struct Tag_Names_ { const char* tag; const char* description; } Tag_Names; // the available script tags and its descriptions are directly extracted // from `ttfautohint-scripts.h' #undef SCRIPT #define SCRIPT(s, S, d, h, H, ss) \ {#s, d}, const Tag_Names script_names[] = { #include {NULL, NULL} }; #ifndef BUILD_GUI // the available feature tags and its descriptions are directly extracted // from `ttfautohint-coverages.h' # undef COVERAGE # define COVERAGE(n, N, d, t, t1, t2, t3, t4) \ {#t, d}, const Tag_Names feature_names[] = { #include {NULL, NULL} }; #endif #ifndef BUILD_GUI extern "C" { typedef struct Progress_Data_ { long last_sfnt; bool begin; int last_percent; } Progress_Data; static int progress(long curr_idx, long num_glyphs, long curr_sfnt, long num_sfnts, void* user) { Progress_Data* data = (Progress_Data*)user; if (num_sfnts > 1 && curr_sfnt != data->last_sfnt) { fprintf(stderr, "subfont %ld of %ld\n", curr_sfnt + 1, num_sfnts); data->last_sfnt = curr_sfnt; data->last_percent = 0; data->begin = true; } if (data->begin) { fprintf(stderr, " %ld glyphs\n" " ", num_glyphs); data->begin = false; } // print progress approx. every 10% int curr_percent = int(curr_idx * 100 / num_glyphs); int curr_diff = curr_percent - data->last_percent; if (curr_diff >= 10) { fprintf(stderr, " %d%%", curr_percent); data->last_percent = curr_percent - curr_percent % 10; } if (curr_idx + 1 == num_glyphs) fprintf(stderr, "\n"); return 0; } typedef struct Error_Data_ { const char* control_name; } Error_Data; static void err(TA_Error error, const char* error_string, unsigned int errlinenum, const char* errline, const char* errpos, void* user) { Error_Data* data = static_cast(user); if (!error) return; // We replace some terse error strings with more user-friendly versions. if (error == TA_Err_Invalid_FreeType_Version) fprintf(stderr, "FreeType version 2.4.5 or higher is needed.\n" "Perhaps using a wrong FreeType DLL?\n"); else if (error == TA_Err_Invalid_Font_Type) fprintf(stderr, "This font is not a valid font" " in SFNT format with TrueType outlines.\n" "In particular, CFF outlines are not supported.\n"); else if (error == TA_Err_Already_Processed) fprintf(stderr, "This font has already been processed with ttfautohint.\n"); else if (error == TA_Err_Missing_Legal_Permission) fprintf(stderr, "Bit 1 in the `fsType' field of the `OS/2' table is set:\n" "This font must not be modified" " without permission of the legal owner.\n" "Use command line option `-i' to continue" " if you have such a permission.\n"); else if (error == TA_Err_Missing_Unicode_CMap) fprintf(stderr, "No Unicode character map.\n"); else if (error == TA_Err_Missing_Symbol_CMap) fprintf(stderr, "No symbol character map.\n"); else if (error == TA_Err_Missing_Glyph) fprintf(stderr, "No glyph for a standard character" " to derive standard width and height.\n" "Please check the documentation for a list of" " script-specific standard characters,\n" "or use option `--symbol'.\n"); else { if (error < 0x100) { fprintf(stderr, "An error with code 0x%02x occurred" " while autohinting fonts\n", error); if (error_string) fprintf(stderr, " %s", error_string); } else if (error >= 0x100 && error < 0x200) { fprintf(stderr, "An error with code 0x%03x occurred" " while parsing the argument of option `-X'", error); fprintf(stderr, errline ? ":\n" : ".\n"); if (errline) fprintf(stderr, " %s\n", errline); if (errpos && errline) fprintf(stderr, " %*s\n", int(errpos - errline + 1), "^"); } else if (error >= 0x200 && error < 0x300) { fprintf(stderr, "%s:", data->control_name); if (errlinenum) fprintf(stderr, "%u:", errlinenum); if (errpos && errline) fprintf(stderr, "%d:", int(errpos - errline + 1)); if (error_string) fprintf(stderr, " %s", error_string); fprintf(stderr, " (0x%02X)\n", error); if (errline) fprintf(stderr, " %s\n", errline); if (errpos && errline) fprintf(stderr, " %*s\n", int(errpos - errline + 1), "^"); } else if (error >= 0x300 && error < 0x400) { error -= 0x300; fprintf(stderr, "An error with code 0x%02x occurred" " while loading the reference font\n", error); if (error_string) fprintf(stderr, " %s", error_string); } } } } // extern "C" #endif // !BUILD_GUI #ifdef CONSOLE_OUTPUT static void show_help(bool #ifdef BUILD_GUI all #endif , bool is_error) { FILE* handle = is_error ? stderr : stdout; fprintf(handle, #ifdef BUILD_GUI "Usage: ttfautohintGUI [OPTION]...\n" "A GUI application to replace hints in a TrueType font.\n" #else "Usage: ttfautohint [OPTION]... [IN-FILE [OUT-FILE]]\n" "Replace hints in TrueType font IN-FILE and write output to OUT-FILE.\n" "If OUT-FILE is missing, standard output is used instead;\n" "if IN-FILE is missing also, standard input and output are used.\n" #endif "\n" "The new hints are based on FreeType's auto-hinter.\n" "\n" "This program is a simple front-end to the `ttfautohint' library.\n" "\n"); fprintf(handle, "Long options can be given with one or two dashes,\n" "and with and without equal sign between option and argument.\n" "This means that the following forms are acceptable:\n" "`-foo=bar', `--foo=bar', `-foo bar', `--foo bar'.\n" "\n" "Mandatory arguments to long options are mandatory for short options too.\n" #ifdef BUILD_GUI "Options not related to Qt or X11 set default values.\n" #endif "\n" ); fprintf(handle, "Options:\n" #ifndef BUILD_GUI " --debug print debugging information\n" #endif " -a, --stem-width-mode=S select stem width mode for grayscale, GDI\n" " ClearType, and DW ClearType, where S is a\n" " string of three letters with possible values\n" " `n' for natural, `q' for quantized, and `s'\n" " for strong (default: qsq)\n" " -c, --composites hint glyph composites also\n" " -d, --dehint remove all hints\n" " -D, --default-script=S set default OpenType script (default: latn)\n" " -f, --fallback-script=S set fallback script (default: none)\n" " -F, --family-suffix=S append suffix to the family name string(s)\n" " in the `name' table\n" " -G, --hinting-limit=N switch off hinting above this PPEM value\n" " (default: %d); value 0 means no limit\n" " -h, --help display this help and exit\n" " -H, --fallback-stem-width=N\n" " set fallback stem width\n" " (default: 50 font units at 2048 UPEM)\n" #ifdef BUILD_GUI " --help-all show Qt and X11 specific options also\n" #endif " -i, --ignore-restrictions override font license restrictions\n" " -I, --detailed-info add detailed ttfautohint info\n" " to the version string(s) in the `name' table\n" " -l, --hinting-range-min=N the minimum PPEM value for hint sets\n" " (default: %d)\n" #ifndef BUILD_GUI " -m, --control-file=FILE get control instructions from FILE\n" #endif " -n, --no-info don't add ttfautohint info\n" " to the version string(s) in the `name' table\n" " -p, --adjust-subglyphs handle subglyph adjustments in exotic fonts\n", TA_HINTING_LIMIT, TA_HINTING_RANGE_MIN); fprintf(handle, " -r, --hinting-range-max=N the maximum PPEM value for hint sets\n" " (default: %d)\n" #ifndef BUILD_GUI " -R, --reference=FILE derive blue zones from reference font FILE\n" #endif " -s, --symbol input is symbol font\n" " -S, --fallback-scaling use fallback scaling, not hinting\n" " -t, --ttfa-table add TTFA information table\n" #ifndef BUILD_GUI " -T, --ttfa-info display TTFA table in IN-FILE and exit\n" #endif " -v, --verbose show progress information\n" " -V, --version print version information and exit\n" " -W, --windows-compatibility\n" " add blue zones for `usWinAscent' and\n" " `usWinDescent' to avoid clipping\n" " -x, --increase-x-height=N increase x height for sizes in the range\n" " 6<=PPEM<=N; value 0 switches off this feature\n" " (default: %d)\n" " -X, --x-height-snapping-exceptions=STRING\n" " specify a comma-separated list of\n" " x-height snapping exceptions, for example\n" " \"-9, 13-17, 19\" (default: \"\")\n" #ifndef BUILD_GUI " -Z, --reference-index=N face index of reference font (default: 0)\n" #endif "\n", TA_HINTING_RANGE_MAX, TA_INCREASE_X_HEIGHT); #ifdef BUILD_GUI if (all) { fprintf(handle, "Qt Options:\n" #if QT_VERSION < 0x050000 " --graphicssystem=SYSTEM\n" " select a different graphics system backend\n" " instead of the default one\n" " (possible values: `raster', `opengl')\n" #endif " --reverse set layout direction to right-to-left\n"); fprintf(handle, #if QT_VERSION < 0x050000 " --session=ID restore the application for the given ID\n" #endif " --style=STYLE set application GUI style\n" " (available values like `windows' or `gtk'\n" " depend on Qt version and installed plug-ins)\n" " --stylesheet=SHEET apply the given Qt stylesheet\n" " to the application widgets\n" "\n"); #if QT_VERSION < 0x050000 fprintf(handle, "X11 options:\n" " --background=COLOR set the default background color\n" " and an application palette\n" " (light and dark shades are calculated)\n" " --bg=COLOR same as --background\n" " --btn=COLOR set the default button color\n" " --button=COLOR same as --btn\n" " --cmap use a private color map on an 8-bit display\n" " --display=NAME use the given X-server display\n"); fprintf(handle, " --fg=COLOR set the default foreground color\n" " --fn=FONTNAME set the application font\n" " --font=FONTNAME same as --fn\n" " --foreground=COLOR same as --fg\n" " --geometry=GEOMETRY set the client geometry of first window\n" " --im=SERVER set the X Input Method (XIM) server\n" " --inputstyle=STYLE set X Input Method input style\n" " (possible values: onthespot, overthespot,\n" " offthespot, root)\n"); fprintf(handle, " --name=NAME set the application name\n" " --ncols=COUNT limit the number of colors allocated\n" " in the color cube on an 8-bit display,\n" " if the application is using the\n" " QApplication::ManyColor color specification\n" " --title=TITLE set the application title (caption)\n" " --visual=VISUAL force the application\n" " to use the given visual on an 8-bit display\n" " (only possible value: TrueColor)\n" "\n"); #endif } #endif // BUILD_GUI fprintf(handle, "The program accepts both TTF and TTC files as input.\n" "Use option -i only if you have a legal permission to modify the font.\n" "The used PPEM value for option -p is FUnits per em, normally 2048.\n" "With option -s, use default values for standard stem width and height,\n" "otherwise they are derived from script-specific characters\n" "resembling the shape of character `o'.\n" "\n"); fprintf(handle, "A hint set contains the optimal hinting for a certain PPEM value;\n" "the larger the hint set range (as given by options -l and -r),\n" "the more hint sets get computed, usually increasing the output font size.\n" "The `gasp' table of the output file always enables grayscale hinting\n" "for all sizes (limited by option -G, which is handled in the bytecode).\n" "Increasing the value of -G does not increase the output font size.\n" "\n"); fprintf(handle, "Options -f and -D take a four-letter string that identifies a script.\n" "Option -f sets the script used as a fallback for glyphs that can't be\n" "associated with a known script. By default, such glyphs are hinted;\n" "if option -S is set, they are scaled only instead. Option -D sets the\n" "default script for handling OpenType features.\n" "\n" "Possible four-letter string values are\n" "\n"); const Tag_Names* sn = script_names; for(;;) { fprintf(handle, " %s (%s)", sn->tag, sn->description); sn++; if (sn->tag) fprintf(handle, ",\n"); else { fprintf(handle, ".\n"); break; } } fprintf(handle, #ifndef BUILD_GUI "\n" "A control instructions file contains entries of the form\n" "\n" " []