summaryrefslogtreecommitdiff
path: root/Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/mmafm/main.cc
diff options
context:
space:
mode:
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.cc434
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;
+}