diff options
Diffstat (limited to 'Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/mmafm/main.cc')
-rw-r--r-- | Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/mmafm/main.cc | 434 |
1 files changed, 434 insertions, 0 deletions
diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/mmafm/main.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/mmafm/main.cc new file mode 100644 index 00000000000..d3dd50b20b6 --- /dev/null +++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/mmafm/main.cc @@ -0,0 +1,434 @@ +/* main.cc -- driver for mmafm program + * + * Copyright (c) 1997-2013 Eddie Kohler + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <efont/findmet.hh> +#include <efont/psres.hh> +#include <lcdf/slurper.hh> +#include <efont/afm.hh> +#include <efont/afmw.hh> +#include <efont/amfm.hh> +#include <lcdf/error.hh> +#include <lcdf/clp.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <math.h> +#ifdef HAVE_CTIME +# include <time.h> +#endif + +#define WEIGHT_OPT 300 +#define WIDTH_OPT 301 +#define OPSIZE_OPT 302 +#define STYLE_OPT 303 +#define N1_OPT 304 +#define N2_OPT 305 +#define N3_OPT 306 +#define N4_OPT 307 +#define VERSION_OPT 308 +#define HELP_OPT 309 +#define OUTPUT_OPT 310 +#define PRECISION_OPT 311 +#define KERN_PREC_OPT 312 + +const Clp_Option options[] = { + { "1", '1', N1_OPT, Clp_ValDouble, 0 }, + { "2", '2', N2_OPT, Clp_ValDouble, 0 }, + { "3", '3', N3_OPT, Clp_ValDouble, 0 }, + { "4", '4', N4_OPT, Clp_ValDouble, 0 }, + { "weight", 'w', WEIGHT_OPT, Clp_ValDouble, 0 }, + { "width", 'W', WIDTH_OPT, Clp_ValDouble, 0 }, + { "optical-size", 'O', OPSIZE_OPT, Clp_ValDouble, 0 }, + { "style", 0, STYLE_OPT, Clp_ValDouble, 0 }, + { "wt", 0, WEIGHT_OPT, Clp_ValDouble, 0 }, + { "wd", 0, WIDTH_OPT, Clp_ValDouble, 0 }, + { "min-kern", 'k', KERN_PREC_OPT, Clp_ValDouble, 0 }, + { "minimum-kern", 'k', KERN_PREC_OPT, Clp_ValDouble, 0 }, + { "kern-precision", 'k', KERN_PREC_OPT, Clp_ValDouble, 0 }, + { "output", 'o', OUTPUT_OPT, Clp_ValString, 0 }, + { "precision", 'p', PRECISION_OPT, Clp_ValInt, 0 }, + { "version", 'v', VERSION_OPT, 0, 0 }, + { "help", 'h', HELP_OPT, 0, 0 }, +}; + +using namespace Efont; + + +static const char *program_name; +static ErrorHandler *errh; +static AmfmMetrics *amfm; + +static Vector<PermString> ax_names; +static Vector<int> ax_nums; +static Vector<double> values; + +static void +set_design(PermString a, double v) +{ + ax_names.push_back(a); + ax_nums.push_back(-1); + values.push_back(v); +} + +static void +set_design(int a, double v) +{ + ax_names.push_back(PermString()); + ax_nums.push_back(a); + values.push_back(v); +} + +static void +set_amfm(AmfmMetrics *a) +{ + if (a) { + if (amfm) errh->fatal("already read one AMFM file"); + amfm = a; + } +} + + +// apply precision +static inline void +pround(double &v, double multiplier, double divider) +{ + if (KNOWN(v)) + v = floor(v * multiplier + 0.5) * divider; +} + +static void +apply_precision(Metrics *m, int precision) +{ + if (precision < 0) + return; + + double multiplier = 1, divider = 1; + for (int i = 0; i < precision; i++) + multiplier *= 10, divider /= 10; + + for (int i = 0; i < m->nfd(); i++) + pround(m->fd(i), multiplier, divider); + + for (int i = 0; i < m->nglyphs(); i++) { + pround(m->wd(i), multiplier, divider); + pround(m->lf(i), multiplier, divider); + pround(m->bt(i), multiplier, divider); + pround(m->rt(i), multiplier, divider); + pround(m->tp(i), multiplier, divider); + } + + for (int i = 0; i < m->nkv(); i++) + pround(m->kv(i), multiplier, divider); +} + +static void +apply_kern_precision(Metrics *m, double kern_precision) +{ + if (kern_precision <= 0) + return; + + for (int i = 0; i < m->nkv(); i++) + if (fabs(m->kv(i)) < kern_precision) + m->kv(i) = 0; +} + + +static void +read_file(const char *fn, MetricsFinder *finder) +{ + Filename filename; + FILE *file; + + if (strcmp(fn, "-") == 0) { + filename = Filename("<stdin>"); + file = stdin; + } else { + filename = Filename(fn); + file = filename.open_read(); + } + int save_errno = errno; + + if (!file) { + // look for a font by name + AmfmMetrics *new_amfm = finder->find_amfm(fn, errh); + if (new_amfm) { + set_amfm(new_amfm); + return; + } + if (finder->find_metrics(fn, errh)) + return; + + // check for instance name. don't use InstanceMetricsFinder. + const char *underscore = strchr(fn, '_'); + if (underscore) + new_amfm = finder->find_amfm(PermString(fn, underscore - fn), errh); + if (!new_amfm) + errh->fatal("%s: %s", fn, strerror(save_errno)); + set_amfm(new_amfm); + + int i = 0; + while (underscore[0] == '_' && underscore[1]) { + double x = strtod(underscore + 1, const_cast<char **>(&underscore)); + set_design(i, x); + i++; + } + return; + } + + Slurper slurper(filename, file); + bool is_afm = false; + if (file != stdin) { + char *first_line = slurper.peek_line(); + if (first_line) + is_afm = strncmp(first_line, "StartFontMetrics", 16) == 0; + } + + if (is_afm) { + Metrics *afm = AfmReader::read(slurper, errh); + if (afm) + finder->record(afm); + } else + set_amfm(AmfmReader::read(slurper, finder, errh)); +} + + +static void +usage_error(const char *error_message, ...) +{ + va_list val; + va_start(val, error_message); + if (!error_message) + errh->message("Usage: %s [OPTION | FONT]...", program_name); + else + errh->vxmessage(ErrorHandler::e_error, error_message, val); + errh->message("Type %s --help for more information.", program_name); + exit(1); +} + +static void +usage() +{ + FileErrorHandler uerrh(stdout); + uerrh.message("\ +%<Mmafm%> creates an AFM font metrics file for a multiple master font by\n\ +interpolating at a point you specify and writes it to the standard output.\n\ +\n\ +Usage: %s [OPTION | FONT]...\n\ +\n\ +Each FONT is either an AFM or AMFM file name, or the font name of a multiple\n\ +master font. In the second case, mmafm will find the actual AMFM file using\n\ +the PSRESOURCEPATH environment variable.\n\ +\n\ +General options:\n\ + -o, --output=FILE Write output to FILE.\n\ + -h, --help Print this message and exit.\n\ + -v, --version Print version number and warranty and exit.\n\ +\n\ +Interpolation settings:\n\ + -w, --weight=N Set weight to N.\n\ + -W, --width=N Set width to N.\n\ + -O, --optical-size=N Set optical size to N.\n\ + --style=N Set style axis to N.\n\ + --1=N, --2=N, --3=N, --4=N Set first (second, third, fourth) axis to N.\n\ + -p, --precision=N Allow N digits of fraction (default 3).\n\ + -k, --min-kern=N Remove kerns smaller than N (default 2).\n\ +\n\ +Report bugs to <ekohler@gmail.com>.\n", program_name); +} + + +int +main(int argc, char *argv[]) +{ + MetricsFinder *finder = new CacheMetricsFinder; + + PsresDatabase *psres = new PsresDatabase; + psres->add_psres_path(getenv("PSRESOURCEPATH"), 0, false); + PsresMetricsFinder *psres_finder = new PsresMetricsFinder(psres); + finder->add_finder(psres_finder); + + Clp_Parser *clp = + Clp_NewParser(argc, (const char * const *)argv, sizeof(options) / sizeof(options[0]), options); + program_name = Clp_ProgramName(clp); + + errh = ErrorHandler::static_initialize(new FileErrorHandler(stderr, String(program_name) + ": ")); + + FILE *output_file = 0; + int precision = 3; + double kern_precision = 2.0; + while (1) { + int opt = Clp_Next(clp); + switch (opt) { + + case WEIGHT_OPT: + set_design("Weight", clp->val.d); + break; + + case WIDTH_OPT: + set_design("Width", clp->val.d); + break; + + case OPSIZE_OPT: + set_design("OpticalSize", clp->val.d); + break; + + case STYLE_OPT: + set_design("Style", clp->val.d); + break; + + case N1_OPT: + case N2_OPT: + case N3_OPT: + case N4_OPT: + set_design(opt - N1_OPT, clp->val.d); + break; + + case PRECISION_OPT: + precision = clp->val.i; + break; + + case KERN_PREC_OPT: + kern_precision = clp->val.d; + break; + + case OUTPUT_OPT: + if (output_file) errh->fatal("output file already specified"); + if (strcmp(clp->vstr, "-") == 0) + output_file = stdout; + else { + output_file = fopen(clp->vstr, "wb"); + if (!output_file) + errh->fatal("%s: %s", clp->vstr, strerror(errno)); + } + break; + + case HELP_OPT: + usage(); + exit(0); + break; + + case VERSION_OPT: + printf("mmafm (LCDF typetools) %s\n", VERSION); + printf("Copyright (C) 1997-2013 Eddie Kohler\n\ +This is free software; see the source for copying conditions.\n\ +There is NO warranty, not even for merchantability or fitness for a\n\ +particular purpose.\n"); + exit(0); + break; + + case Clp_NotOption: + read_file(clp->vstr, finder); + break; + + case Clp_Done: + goto done; + + case Clp_BadOption: + usage_error(0); + break; + + } + } + + done: + if (!amfm) usage_error("missing font argument"); + + MultipleMasterSpace *mmspace = amfm->mmspace(); +#if MMAFM_RUN_MMPFB + if (!mmspace->check_intermediate()) { + char *buf = new char[amfm->font_name().length() + 30]; + sprintf(buf, "mmpfb -q --amcp-info '%s'", amfm->font_name().c_str()); + + FILE *f = popen(buf, "r"); + if (f) { + Filename fake("<mmpfb output>"); + Slurper slurpy(fake, f); + AmfmReader::add_amcp_file(slurpy, amfm, errh); + pclose(f); + } + + delete[] buf; + } +#endif + + Vector<double> design = mmspace->default_design_vector(); + for (int i = 0; i < values.size(); i++) + if (ax_names[i]) + mmspace->set_design(design, ax_names[i], values[i], errh); + else + mmspace->set_design(design, ax_nums[i], values[i], errh); + + Vector<double> weight; + if (!mmspace->design_to_weight(design, weight, errh)) { + if (!mmspace->check_intermediate()) { + errh->message("(I can%,t interpolate font programs with intermediate masters on my own."); +#if MMAFM_RUN_MMPFB + errh->message("I tried to run %<mmpfb --amcp-info %s%>, but it didn't work.", amfm->font_name().c_str()); + errh->message("Maybe your PSRESOURCEPATH environment variable is not set?"); +#endif + errh->fatal("See the manual page for more information.)"); + } else + errh->fatal("can%,t create weight vector"); + } + + // Need to check for case when all design coordinates are unspecified. The + // AMFM file contains a default WeightVector, but often NOT a default + // DesignVector; we don't want to generate a file with a FontName like + // `MyriadMM_-9.79797979e97_-9.79797979e97_' because the DesignVector + // components are unknown. + if (!KNOWN(design[0])) + errh->fatal("must specify %s%,s %s coordinate", amfm->font_name().c_str(), + mmspace->axis_type(0).c_str()); + + Metrics *m = amfm->interpolate(design, weight, errh); + if (m) { + + // Add a comment identifying this as interpolated by mmafm + if (MetricsXt *xt = m->find_xt("AFM")) { + AfmMetricsXt *afm_xt = (AfmMetricsXt *)xt; + +#if HAVE_CTIME + time_t cur_time = time(0); + char *time_str = ctime(&cur_time); + int time_len = strlen(time_str) - 1; + char *buf = new char[strlen(VERSION) + time_len + 100]; + sprintf(buf, "Interpolated by mmafm-%s on %.*s.", VERSION, + time_len, time_str); +#else + char *buf = new char[strlen(VERSION) + 100]; + sprintf(buf, "Interpolated by mmafm-%s.", VERSION); +#endif + + afm_xt->opening_comments.push_back(buf); + afm_xt->opening_comments.push_back("Mmafm is free software. See <http://www.lcdf.org/type/>."); + delete[] buf; + } + + // round numbers if necessary + if (precision >= 0) + apply_precision(m, precision); + if (kern_precision > 0) + apply_kern_precision(m, kern_precision); + + // write the output file + if (!output_file) + output_file = stdout; + AfmWriter::write(m, output_file); + + return 0; + } else + return 1; +} |