From: Han-Wen Nienhuys Date: Sun, 20 Feb 2005 18:07:11 +0000 (+0000) Subject: add dir X-Git-Tag: release/2.5.14~119 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=7a708a3623602ac8f3561b91dc5cc9c40680a5cd;p=lilypond.git add dir --- diff --git a/ttftool/GNUmakefile b/ttftool/GNUmakefile new file mode 100644 index 0000000000..0c56f8d639 --- /dev/null +++ b/ttftool/GNUmakefile @@ -0,0 +1,19 @@ +# title top level makefile for FlowerLib +# file flower/Makefile + +# should reinstate versioning if shared libs are enabled. + +depth = .. + +NAME = ttftool +MODULE_NAME = ttftool +SUBDIRS = include + +SCRIPTS = +README_FILES = NEWS-1.0 NEWS-1.1.46 README TODO +EXTRA_DIST_FILES= VERSION $(README_FILES) $(SCRIPTS) +STEPMAKE_TEMPLATES=library c po + +include $(depth)/make/stepmake.make + + diff --git a/ttftool/encodings.c b/ttftool/encodings.c new file mode 100644 index 0000000000..e0eff3621a --- /dev/null +++ b/ttftool/encodings.c @@ -0,0 +1,132 @@ +/* Copyright (c) 1997-1998 by Juliusz Chroboczek */ + +#define NULL ((void *)0) + +/* char *macEncoding[]={ */ +/* ".notdef", NULL, NULL, NULL, NULL, NULL, */ +/* NULL, NULL, NULL, NULL, NULL, NULL, */ +/* NULL, NULL, NULL, NULL, NULL, NULL, */ +/* NULL, NULL, NULL, NULL, NULL, NULL, */ +/* NULL, NULL, NULL, NULL, NULL, NULL, */ +/* NULL, NULL, "space", "exclam", "quotedbl", "numbersign", */ +/* "dollar", "percent", "ampersand", "quoteright", "parenleft", */ +/* "parenright", "asterisk", "plus", "comma", "hyphen", "period", */ +/* "slash", "zero", "one", "two", "three", "four", "five", "six", */ +/* "seven", "eight", "nine", "colon", "semicolon", "less", "equal", */ +/* "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", */ +/* "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", */ +/* "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", */ +/* "asciicircum", "underscore", "quoteleft", "a", "b", "c", "d", "e", */ +/* "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", */ +/* "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", */ +/* "tilde", NULL, "Adieresis", "Aring", "Ccedilla", "Eacute", */ +/* "Ntilde", "Odieresis", "Udieresis", "aacute", "agrave", "acircumflex", */ +/* "adieresis", "atilde", "aring", "ccedilla", "eacute", "egrave", */ +/* "ecircumflex", "edieresis", "iacute", "igrave", "icircumflex", */ +/* "idieresis", "ntilde", "oacute", "ograve", "ocircumflex", "odieresis", */ +/* "otilde", "uacute", "ugrave", "ucircumflex", "udieresis", "dagger", */ +/* "degree", "cent", "sterling", "section", "bullet", "paragraph", */ +/* "germandbls", "registered", "copyright", "trademark", "acute", */ +/* "dieresis", "notequal", "AE", "Oslash", "infinity", "plusminus", */ +/* "lessequal", "greaterequal", "yen", "mu", "partialdiff", "Sigma", */ +/* "product", "pi", "integral", "ordfeminine", "ordmasculine", "Omega", */ +/* "ae", "oslash", "questiondown", "exclamdown", "logicalnot", "radical", */ +/* "florin", "approxequal", "Delta", "guillemotleft", "guillemotright", */ +/* "ellipsis", "space", "Agrave", "Atilde", "Otilde", "OE", "oe", */ +/* "endash", "emdash", "quotedblleft", "quotedblright", "quoteleft", */ +/* "quoteright", "divide", "lozenge", "ydieresis", "Ydieresis", */ +/* "fraction", "currency", "guilsinglleft", "guilsinglright", "fi", "fl", */ +/* "daggerdbl", "periodcentered", "quotesinglbase", "quotedblbase", */ +/* "perthousand", "Acircumflex", "Ecircumflex", "Aacute", "Edieresis", */ +/* "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave", "Oacute", */ +/* "Ocircumflex", NULL, "Ograve", "Uacute", "Ucircumflex", "Ugrave", */ +/* "dotlessi", "circumflex", "tilde", "macron", "breve", "dotaccent", */ +/* "ring", "cedilla", "hungarumlaut", "ogonek", "caron"}; */ + +char *macGlyphEncoding[] = { + ".notdef", ".null", "CR", "space", "exclam", "quotedbl", "numbersign", + "dollar", "percent", "ampersand", "quotesingle", "parenleft", + "parenright", "asterisk", "plus", "comma", "hyphen", "period", + "slash", "zero", "one", "two", "three", "four", "five", "six", + "seven", "eight", "nine", "colon", "semicolon", "less", "equal", + "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", + "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", + "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", + "asciicircum", "underscore", "grave", "a", "b", "c", "d", "e", "f", + "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", + "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", + "asciitilde", "Adieresis", "Aring", "Ccedilla", "Eacute", "Ntilde", + "Odieresis", "Udieresis", "aacute", "agrave", "acircumflex", + "adieresis", "atilde", "aring", "ccedilla", "eacute", "egrave", + "ecircumflex", "edieresis", "iacute", "igrave", "icircumflex", + "idieresis", "ntilde", "oacute", "ograve", "ocircumflex", "odieresis", + "otilde", "uacute", "ugrave", "ucircumflex", "udieresis", "dagger", + "degree", "cent", "sterling", "section", "bullet", "paragraph", + "germandbls", "registered", "copyright", "trademark", "acute", + "dieresis", "notequal", "AE", "Oslash", "infinity", "plusinus", + "lessequal", "greaterequal", "yen", "mu1", "partialdiff", "summation", + "product", "pi", "integral", "ordfeminine", "ordmasculine", "Ohm", + "ae", "oslash", "questiondown", "exclamdown", "logicalnot", "radical", + "florin", "approxequal", "increment", "guillemotleft", + "guillemotright", "ellipsis", "nbspace", "Agrave", "Atilde", "Otilde", + "OE", "oe", "endash", "emdash", "quotedblleft", "quotedblright", + "quoteleft", "quoteright", "divide", "lozenge", "ydieresis", + "Ydieresis", "fraction", "currency", "guilsingleft", "guilsingright", + "fi", "fl", "daggerdbl", "periodcentered", "quotesinglbase", + "quotedblbase", "perthousand", "Acircumflex", "Ecircumflex", "Aacute", + "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave", + "Oacute", "Ocircumflex", "applelogo", "Ograve", "Uacute", + "Ucircumflex", "Ugrave", "dotlessi", "circumflex", "tilde", + "overscore", "breve", "dotaccent", "ring", "cedilla", "hungarumlaut", + "ogonek", "caron", "Lslash", "lslash", "Scaron", "scaron", "Zcaron", + "zcaron", "brokenbar", "Eth", "eth", "Yacute", "yacute", "Thorn", + "thorn", "minus", "multiply", "onesuperior", "twosuperior", + "threesuperior", "onehalf", "onequarter", "threequarters", "franc", + "Gbreve", "gbreve", "Idot", "Scedilla", "scedilla", "Cacute", + "cacute", "Ccaron", "ccaron", "dmacron" +}; + +char *adobeStandardEncoding[] = { + ".notdef", NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", + "ampersand", "quoteright", + "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", + "slash", + "zero", "one", "two", "three", "four", "five", "six", "seven", + "eight", "nine", "colon", "semicolon", "less", "equal", "greater", + "question", + "at", "A", "B", "C", "D", "E", "F", "G", + "H", "I", "J", "K", "L", "M", "N", "O", + "P", "Q", "R", "S", "T", "U", "V", "W", + "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", + "underscore", + "quoteleft", "a", "b", "c", "d", "e", "f", "g", + "h", "i", "j", "k", "l", "m", "n", "o", + "p", "q", "r", "s", "t", "u", "v", "w", + "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, "exclamdown", "cent", "sterling", "fraction", "yen", "florin", + "section", + "currency", "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft", + "guilsinglright", "fi", "fl", + NULL, "endash", "dagger", "daggerdbl", "periodcentered", NULL, "paragraph", + "bullet", + "quotesinglbase", "quotedblbase", "quotedblright", "guillemotright", + "ellipsis", "perthousand", NULL, "questiondown", + NULL, "grave", "acute", "circumflex", "tilde", "macron", "breve", + "dotaccent", + "dieresis", NULL, "ring", "cedilla", NULL, "hungarumlaut", "ogonek", + "caron", + "emdash", NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, "AE", NULL, "ordfeminine", NULL, NULL, NULL, NULL, + "Lslash", "Oslash", "OE", "ordmasculine", NULL, NULL, NULL, NULL, + NULL, "ae", NULL, NULL, NULL, "dotlessi", NULL, NULL, + "lslash", "oslash", "oe", "germandbls", NULL, NULL, NULL, NULL +}; diff --git a/ttftool/parse.c b/ttftool/parse.c new file mode 100644 index 0000000000..e519d81ceb --- /dev/null +++ b/ttftool/parse.c @@ -0,0 +1,335 @@ +/* Copyright (c) 1997-1998 by Juliusz Chroboczek */ + +#include +#include +#include +#include +#include "types.h" +#include "proto.h" + +struct TableDirectoryEntry * +readDirectory (int fd, struct OffsetTable *ot) +{ + unsigned n; + int i; + + struct TableDirectoryEntry *td; + surely_read (fd, ot, sizeof (struct OffsetTable)); + FIX_OffsetTable (*ot); + if (verbosity >= 2) + fprintf (stderr, "%d tables\n", ot->numTables); + n = sizeof (struct TableDirectoryEntry) * ot->numTables; + td = mymalloc (n); + surely_read (fd, td, n); + for (i = 0; i < ot->numTables; i++) + FIX_TableDirectoryEntry (td[i]); + return td; +} + +char ** +readNamingTable (int fd) +{ + USHORT format; + USHORT nrecords; + off_t position; + USHORT offset; + int i, index, maxIndex; + struct NameRecord *records; + char *data; + char **strings; + + position = surely_lseek (fd, 0, SEEK_CUR); + + surely_read (fd, &format, sizeof (USHORT)); + FIX_UH (format); + if (format != 0) + error ("Bad TTF file\n"); + surely_read (fd, &nrecords, sizeof (USHORT)); + FIX_UH (nrecords); + surely_read (fd, &offset, sizeof (USHORT)); + FIX_UH (offset); + records = mymalloc (nrecords * sizeof (struct NameRecord)); + surely_read (fd, records, nrecords * sizeof (struct NameRecord)); + + for (i = 0, maxIndex = -1; i < nrecords; i++) + { + FIX_NameRecord (records[i]); + index = records[i].offset + records[i].length; + maxIndex = maxIndex > index ? maxIndex : index; + } + data = mymalloc (maxIndex); + surely_lseek (fd, position + offset, SEEK_SET); + surely_read (fd, data, maxIndex); + + strings = mymalloc (8 * sizeof (char *)); + for (i = 0; i < 8; i++) + strings[i] = NULL; + + for (i = 0; i < nrecords; i++) + { + if (records[i].platformID == 3 && /* Microsoft */ + records[i].encodingID == 1 && /* UGL */ + records[i].languageID == 0x0409 && /* US English */ + records[i].nameID <= 7) + { + strings[records[i].nameID] = mymalloc (records[i].length / 2 + 1); + unistrncpy (strings[records[i].nameID], + data + records[i].offset, records[i].length); + if (verbosity >= 2) + fprintf (stderr, "%d: %s\n", records[i].nameID, + strings[records[i].nameID]); + } + } + free (records); + free (data); + return strings; +} + +int +readMaxpTable (int fd) +{ + struct + { + Fixed version; + USHORT nglyphs; + } data; + surely_read (fd, &data, sizeof (data)); + FIX_Fixed (data.version); + FIX_UH (data.nglyphs); + if (verbosity >= 2) + fprintf (stderr, " version %d.%u\n", + data.version.mantissa, data.version.fraction); + return data.nglyphs; +} + +void +readHeadTable (int fd, struct HeadTable *ht) +{ + surely_read (fd, ht, sizeof (struct HeadTable)); + FIX_HeadTable (*ht); + if (verbosity >= 2) + { + fprintf (stderr, " version %d.%d\n", + ht->version.mantissa, ht->version.fraction); + fprintf (stderr, " font revision %d.%d\n", + ht->fontRevision.mantissa, ht->fontRevision.fraction); + } + if (ht->magicNumber != 0x5F0F3CF5) + error ("Bad magic number in TTF file"); + if (verbosity >= 2) + fprintf (stderr, " %d units per Em\n", ht->unitsPerEm); +} + +int +readPostTable (int fd, int nglyphs, struct PostTable *pt, + struct GlyphName **gt) +{ + USHORT nglyphspost; + USHORT *glyphNameIndex; + struct GlyphName *glyphNames; + char **glyphNamesTemp; + int i, maxIndex; + CHAR c; + + surely_read (fd, pt, sizeof (struct PostTable)); + FIX_PostTable (*pt); + if (verbosity >= 2) + fprintf (stderr, " format type %d.%u\n", + pt->formatType.mantissa, pt->formatType.fraction); + + switch (pt->formatType.mantissa) + { + case 1: + return 1; /* MacGlyphEncoding */ + case 2: + if (pt->formatType.fraction != 0) + error ("Unsupported `post' table format"); + surely_read (fd, &nglyphspost, sizeof (USHORT)); + FIX_UH (nglyphspost); + if (nglyphspost != nglyphs) + error ("Inconsistency between `maxp' and `nglyphs' tables!"); + if (verbosity >= 2) + fprintf (stderr, " %d glyphs\n", nglyphs); + glyphNameIndex = mymalloc (sizeof (USHORT) * nglyphs); + surely_read (fd, glyphNameIndex, sizeof (USHORT) * nglyphs); + glyphNames = mymalloc (sizeof (struct GlyphName) * nglyphs); + for (i = 0, maxIndex = -1; i < nglyphs; i++) + { + FIX_UH (glyphNameIndex[i]); + if (glyphNameIndex[i] < 258) + { + glyphNames[i].type = 0; + glyphNames[i].name.index = glyphNameIndex[i]; + } + else + { + int index; + glyphNames[i].type = 1; + index = glyphNameIndex[i] - 258; + glyphNames[i].name.index = index; + maxIndex = maxIndex > index ? maxIndex : index; + } + } + free (glyphNameIndex); + + i = 0; + glyphNamesTemp = mymalloc (sizeof (char *) * (maxIndex + 1)); + while (i <= maxIndex) + { + surely_read (fd, &c, 1); + glyphNamesTemp[i] = mymalloc (c + 1); + surely_read (fd, glyphNamesTemp[i], c); + glyphNamesTemp[i][c] = '\0'; + if (verbosity >= 3) + fprintf (stderr, " %d: %s\n", i, glyphNamesTemp[i]); + i++; + } + for (i = 0; i < nglyphs; i++) + if (glyphNames[i].type == 1) + glyphNames[i].name.name = glyphNamesTemp[glyphNames[i].name.index]; + free (glyphNamesTemp); + *gt = glyphNames; + return 2; + case 3: + return 3; /* no name table */ + default: + return 0; + } + /*NOTREACHED*/} + +void * +readLocaTable (int fd, int nglyphs, int format) +{ + int i; + switch (format) + { + case 0: + { + USHORT *offsets; + offsets = mymalloc ((nglyphs + 1) * sizeof (USHORT)); + surely_read (fd, offsets, (nglyphs + 1) * sizeof (USHORT)); + for (i = 0; i <= nglyphs; i++) + FIX_UH (offsets[i]); + return offsets; + } + /*NOTREACHED*/ case 1: + { + ULONG *offsets; + offsets = mymalloc ((nglyphs + 1) * sizeof (ULONG)); + surely_read (fd, offsets, (nglyphs + 1) * sizeof (ULONG)); + for (i = 0; i <= nglyphs; i++) + FIX_UL (offsets[i]); + return offsets; + } + /*NOTREACHED*/ default: + error ("Unknown `loca' table format"); + /*NOTREACHED*/} + /*NOTREACHED*/} + +struct Box * +readGlyfTable (int fd, int nglyphs, int format, void *loca) +{ + int i; + struct Box *bbox; + off_t base, offset; + + base = surely_lseek (fd, 0, SEEK_CUR); + + bbox = mymalloc (nglyphs * sizeof (struct Box)); + for (i = 0; i < nglyphs; i++) + { + if (format == 0) + offset = 2 * ((USHORT *) loca)[i]; + else + offset = ((ULONG *) loca)[i]; + surely_lseek (fd, base + offset + sizeof (SHORT), SEEK_SET); + surely_read (fd, bbox + i, sizeof (struct Box)); + FIX_Box (bbox[i]); + } + return bbox; +} + +longHorMetric * +readHmtxTable (int fd, int nummetrics) +{ + longHorMetric *metrics; + int i; + + metrics = mymalloc (nummetrics * sizeof (longHorMetric)); + surely_read (fd, metrics, nummetrics * sizeof (longHorMetric)); + for (i = 0; i < nummetrics; i++) + { + FIX_longHorMetric (metrics[i]); + } + return metrics; +} + +struct HheaTable * +readHheaTable (int fd) +{ + struct HheaTable *hhea; + hhea = mymalloc (sizeof (struct HheaTable)); + surely_read (fd, hhea, sizeof (struct HheaTable)); + FIX_HheaTable (*hhea); + if (verbosity >= 2) + fprintf (stderr, " version %d.%u\n", + hhea->version.mantissa, hhea->version.fraction); + if (hhea->metricDataFormat != 0) + error ("Unknown metric data format"); + return hhea; +} + +int +readKernTable (int fd, int **nkep, struct KernEntry0 ***kep) +{ + struct KernTable kt; + struct KernSubTableHeader ksth; + struct KernSubTable0 kst; + int i, j; + int *nke; + struct KernEntry0 **ke; + + surely_read (fd, &kt, sizeof (struct KernTable)); + FIX_KernTable (kt); + if (verbosity >= 2) + { + fprintf (stderr, " version %d\n", kt.version); + fprintf (stderr, " %d subtables\n", kt.nTables); + } + nke = mymalloc (kt.nTables * sizeof (int)); + ke = mymalloc (kt.nTables * sizeof (struct KernEntry0 *)); + + for (i = 0; i < kt.nTables; i++) + { + surely_read (fd, &ksth, sizeof (struct KernSubTableHeader)); + FIX_KernSubTableHeader (ksth); + if (verbosity >= 2) + fprintf (stderr, " analyzing subtable %d, version %d... ", + i, ksth.version); + if ((ksth.coverage & kernHorizontal) && + !(ksth.coverage & kernMinimum) && + !(ksth.coverage & kernCrossStream) && + (kernFormat (ksth.coverage) == 0)) + { + surely_read (fd, &kst, sizeof (struct KernSubTable0)); + FIX_KernSubTable0 (kst); + if (verbosity >= 2) + fprintf (stderr, "reading %d entries.\n", kst.nPairs); + nke[i] = kst.nPairs; + ke[i] = mymalloc (kst.nPairs * sizeof (struct KernEntry0)); + surely_read (fd, ke[i], kst.nPairs * sizeof (struct KernEntry0)); + for (j = 0; j < kst.nPairs; j++) + FIX_KernEntry0 (ke[i][j]); + } + else + { + if (verbosity >= 2) + fprintf (stderr, "skipping.\n"); + surely_lseek (fd, ksth.length - sizeof (struct KernSubTableHeader), + SEEK_CUR); + } + } + *nkep = nke; + *kep = ke; + return kt.nTables; +} diff --git a/ttftool/ps.c b/ttftool/ps.c new file mode 100644 index 0000000000..ccf4a16b7f --- /dev/null +++ b/ttftool/ps.c @@ -0,0 +1,298 @@ +/* Copyright (c) 1997-1998 by Juliusz Chroboczek */ + +#include +#include +#include +#include +#include "types.h" +#include "proto.h" + +#define CHUNKSIZE 65534 + +#define NAMEOF(i) \ + ((i)==0?\ + ".notdef":\ + ((postType==2)?\ + ((gnt[i].type==0)?\ + (gnt[i].name.index==0?NULL:macGlyphEncoding[gnt[i].name.index]):\ + gnt[i].name.name):\ + ((i)<258?macGlyphEncoding[i]:NULL))) + + +void +printPSFont (FILE * out, struct HeadTable *ht, + char **strings, int nglyphs, int postType, + struct PostTable *pt, struct GlyphName *gnt, int fd) +{ + printPSHeader (out, ht, strings, pt); + printPSData (out, fd); + printPSTrailer (out, nglyphs, postType, gnt); +} + +void +printPSHeader (FILE * out, struct HeadTable *ht, + char **strings, struct PostTable *pt) +{ + fprintf (out, "%%!PS-TrueTypeFont\n"); + if (pt->maxMemType42) + fprintf (out, "%%%%VMUsage: %ld %ld\n", pt->minMemType42, + pt->maxMemType42); + fprintf (out, "%d dict begin\n", 11); + fprintf (out, "/FontName /%s def\n", strings[6] ? strings[6] : "Unknown"); + fprintf (out, "/Encoding StandardEncoding def\n"); + fprintf (out, "/PaintType 0 def\n/FontMatrix [1 0 0 1 0 0] def\n"); + fprintf (out, "/FontBBox [%ld %ld %ld %ld] def\n", + ht->xMin * 1000L / ht->unitsPerEm, + ht->yMin * 1000L / ht->unitsPerEm, + ht->xMax * 1000L / ht->unitsPerEm, + ht->yMax * 1000L / ht->unitsPerEm); + fprintf (out, "/FontType 42 def\n"); + fprintf (out, "/FontInfo 8 dict dup begin\n"); + fprintf (out, "/version (%d.%d) def\n", + ht->fontRevision.mantissa, ht->fontRevision.fraction); + if (strings[0]) + { + fprintf (out, "/Notice ("); + fputpss (strings[0], out); + fprintf (out, ") def\n"); + } + if (strings[4]) + { + fprintf (out, "/FullName ("); + fputpss (strings[4], out); + fprintf (out, ") def\n"); + } + if (strings[1]) + { + fprintf (out, "/FamilyName ("); + fputpss (strings[1], out); + fprintf (out, ") def\n"); + } + fprintf (out, "/isFixedPitch %s def\n", + pt->isFixedPitch ? "true" : "false"); + fprintf (out, "/UnderlinePosition %ld def\n", + pt->underlinePosition * 1000L / ht->unitsPerEm); + fprintf (out, "/UnderlineThickness %ld def\n", + pt->underlineThickness * 1000L / ht->unitsPerEm); + fprintf (out, "end readonly def\n"); +} + +void +printPSData (FILE * out, int fd) +{ + static char xdigits[] = "0123456789ABCDEF"; + + unsigned char *buffer; + int i, j; + + surely_lseek (fd, 0, SEEK_SET); + + buffer = mymalloc (CHUNKSIZE); + + fprintf (out, "/sfnts ["); + for (;;) + { + i = read (fd, buffer, CHUNKSIZE); + if (i == 0) + break; + fprintf (out, "\n<"); + for (j = 0; j < i; j++) + { + if (j != 0 && j % 36 == 0) + putc ('\n', out); + /* fprintf(out,"%02X",(int)buffer[j]) is too slow */ + putc (xdigits[(buffer[j] & 0xF0) >> 4], out); + putc (xdigits[buffer[j] & 0x0F], out); + } + fprintf (out, "00>"); /* Adobe bug? */ + if (i < CHUNKSIZE) + break; + } + fprintf (out, "\n] def\n"); + free (buffer); +} + +void +printPSTrailer (FILE * out, int nglyphs, int postType, struct GlyphName *gnt) +{ + int i, n; + char *name; + + fprintf (out, "/CharStrings %d dict dup begin\n", nglyphs); + switch (postType) + { + case 2: + for (n = i = 0; i < nglyphs; i++) + { + if (n != 0 && n % 4 == 0) + fprintf (out, "\n"); + name = NAMEOF (i); + if (name) + { + fprintf (out, "/%s %d def ", name, i); + n++; + } + } + break; + default: + if (postType != 1) + { + if (verbosity > -2) + fprintf (stderr, + "No glyph name table; assuming MacGlyphEncoding\n"); + } + for (i = 0; i < 258 && i < nglyphs; i++) + { + fprintf (out, "/%s %d def ", macGlyphEncoding[i], i); + if (i != 0 && i % 4 == 0) + fprintf (out, "\n"); + } + break; + } + fprintf (out, "end readonly def\n"); + fprintf (out, "FontName currentdict end definefont pop\n"); +} + +void +printAFM (FILE * afm, struct HeadTable *ht, + char **strings, int nglyphs, int postType, + struct PostTable *pt, struct GlyphName *gnt, + struct Box *bbox, struct HheaTable *hhea, longHorMetric * hmtx, + int nkern, int *nke, struct KernEntry0 **ke) +{ + fprintf (afm, "StartFontMetrics 3.0\n"); + fprintf (afm, "Comment Automatically generated by ttfps -- do not edit\n"); + printAFMHeader (afm, ht, strings, pt); + printAFMMetrics (afm, ht, nglyphs, postType, gnt, bbox, hhea, hmtx); + printAFMKerning (afm, ht, postType, gnt, nkern, nke, ke); + fprintf (afm, "EndFontMetrics\n"); +} + +void +printAFMHeader (FILE * afm, struct HeadTable *ht, + char **strings, struct PostTable *pt) +{ + fprintf (afm, "FontName %s\n", strings[6] ? strings[6] : "Unknown"); + if (strings[4]) + fprintf (afm, "FullName %s\n", strings[4]); + if (strings[1]) + fprintf (afm, "FamilyName %s\n", strings[1]); + fprintf (afm, "IsFixedPitch %s\n", pt->isFixedPitch ? "true" : "false"); + fprintf (afm, "FontBBox %ld %ld %ld %ld\n", + ht->xMin * 1000L / ht->unitsPerEm, + ht->yMin * 1000L / ht->unitsPerEm, + ht->xMax * 1000L / ht->unitsPerEm, + ht->yMax * 1000L / ht->unitsPerEm); + fprintf (afm, "UnderlinePosition %ld\n", + pt->underlinePosition * 1000L / ht->unitsPerEm); + fprintf (afm, "UnderlineThickness %ld\n", + pt->underlineThickness * 1000L / ht->unitsPerEm); + fprintf (afm, "Version %d.%u\n", ht->fontRevision.mantissa, + ht->fontRevision.fraction); + if (strings[0]) + fprintf (afm, "Notice %s\n", strings[0]); + fprintf (afm, "EncodingScheme AdobeStandardEncoding\n"); + /* fprintf(afm,"CapHeight %d\n"); + fprintf(afm,"XHeight %d\n"); + fprintf(afm,"Ascender %d\n"); + fprintf(afm,"Descender %d\n"); */ +} + +void +printAFMMetrics (FILE * afm, struct HeadTable *ht, + int nglyphs, int postType, struct GlyphName *gnt, + struct Box *bbox, + struct HheaTable *hhea, longHorMetric * hmtx) +{ + int i, j; + char *name; + struct hashtable *table; + char *already_done; + + /* Hash all the character names */ + table = make_hashtable (nglyphs / 3 + 1); + for (i = 0; i < nglyphs; i++) + { + name = NAMEOF (i); + if (name) + puthash (table, name, i); + } + + already_done = mycalloc (nglyphs, sizeof (char)); + + fprintf (afm, "StartCharMetrics %d\n", nglyphs); + /* First, print out the encoded glyphs */ + for (i = 0; i < 256; i++) + { + if (adobeStandardEncoding[i]) + { + j = gethash (table, adobeStandardEncoding[i]); + if (j >= 0) + { + printOneAFMMetric (afm, j, i, adobeStandardEncoding[i], + ht, bbox, hhea, hmtx); + already_done[j] = 1; + } + } + } + /* Now, print out the others */ + for (j = 0; j < nglyphs; j++) + { + if (!already_done[j]) + { + name = NAMEOF (j); + printOneAFMMetric (afm, j, -1, name, ht, bbox, hhea, hmtx); + } + } + fprintf (afm, "EndCharMetrics\n"); +} + +void +printOneAFMMetric (FILE * afm, + int index, int code, char *name, + struct HeadTable *ht, + struct Box *bbox, + struct HheaTable *hhea, longHorMetric * hmtx) +{ + if (name) + { + fprintf (afm, "C %d ;", code); + if (hhea && hmtx) + fprintf (afm, " WX %ld ;", + index < hhea->numberOfHMetrics ? + hmtx[index].advanceWidth * 1000L / ht->unitsPerEm : + hmtx[hhea->numberOfHMetrics - + 1].advanceWidth * 1000L / ht->unitsPerEm); + fprintf (afm, " N %s ;", name); + if (bbox) + fprintf (afm, " B %ld %ld %ld %ld ;", + bbox[index].xMin * 1000L / ht->unitsPerEm, + bbox[index].yMin * 1000L / ht->unitsPerEm, + bbox[index].xMax * 1000L / ht->unitsPerEm, + bbox[index].yMax * 1000L / ht->unitsPerEm); + fprintf (afm, "\n"); + } +} + +void +printAFMKerning (FILE * afm, struct HeadTable *ht, + int postType, struct GlyphName *gnt, + int nkern, int *nke, struct KernEntry0 **ke) +{ + int i, j, n; + + for (n = i = 0; i < nkern; i++) + n += nke[i]; + if (n == 0) + return; + + fprintf (afm, "StartKernData\nStartKernPairs %d\n", n); + + for (i = 0; i < nkern; i++) + for (j = 0; j < nke[i]; j++) + fprintf (afm, "KPX %s %s %ld\n", + NAMEOF (ke[i][j].left), + NAMEOF (ke[i][j].right), + ke[i][j].value * 1000L / ht->unitsPerEm); + fprintf (afm, "EndKernPairs\nEndKernData\n"); +} diff --git a/ttftool/ttfps.c b/ttftool/ttfps.c new file mode 100644 index 0000000000..143af5e6a7 --- /dev/null +++ b/ttftool/ttfps.c @@ -0,0 +1,157 @@ +/* Copyright (c) 1997-1998 by Juliusz Chroboczek */ + +#include +#include +#include +#include +#include +#include "types.h" +#include "proto.h" + +static void endianness_test (void); +static void usage (char *); + +int verbosity = 0; + +void +create_type42 (const char *infile, FILE * out) +{ + int fd, i; + FILE *afm = NULL; + struct OffsetTable ot; + struct HeadTable *ht; + struct PostTable *pt; + struct TableDirectoryEntry *td; + void *loca = NULL; + struct HheaTable *hhea = NULL; + struct Box *bbox = NULL; + longHorMetric *hmtx = NULL; + char **strings = NULL; + struct GlyphName *gnt = NULL; + struct KernEntry0 **ke; + int *nke; + int nglyphs, postType, nkern; + off_t headOff = 0, maxpOff = 0, postOff = 0, nameOff = 0, + locaOff = 0, glyfOff = 0, hheaOff = 0, hmtxOff = 0, kernOff = 0; + + extern char *optarg; + extern int optind; + int c; + + endianness_test (); + + if ((fd = open (infile, O_RDONLY)) < 0) + syserror ("Error opening input file"); + + td = readDirectory (fd, &ot); + if (verbosity >= 2) + fprintf (stderr, "True type version %d.%u\n", + ot.version.mantissa, ot.version.fraction); + + for (i = 0; i < ot.numTables; i++) + { + if (verbosity >= 2) + fprintf (stderr, "Found `%c%c%c%c' table\n", + (char) (td[i].tag >> 24), + (char) (td[i].tag >> 16) & 255, + (char) (td[i].tag >> 8) & 255, (char) td[i].tag & 255); + switch (td[i].tag) + { + case MAKE_ULONG ('m', 'a', 'x', 'p'): + maxpOff = td[i].offset; + break; + case MAKE_ULONG ('h', 'e', 'a', 'd'): + headOff = td[i].offset; + break; + case MAKE_ULONG ('p', 'o', 's', 't'): + postOff = td[i].offset; + break; + case MAKE_ULONG ('n', 'a', 'm', 'e'): + nameOff = td[i].offset; + break; + case MAKE_ULONG ('l', 'o', 'c', 'a'): + locaOff = td[i].offset; + break; + case MAKE_ULONG ('g', 'l', 'y', 'f'): + glyfOff = td[i].offset; + break; + case MAKE_ULONG ('h', 'h', 'e', 'a'): + hheaOff = td[i].offset; + break; + case MAKE_ULONG ('h', 'm', 't', 'x'): + hmtxOff = td[i].offset; + break; + case MAKE_ULONG ('k', 'e', 'r', 'n'): + kernOff = td[i].offset; + break; + } + } + if (maxpOff == 0 || headOff == 0 || postOff == 0 || nameOff == 0) + error ("Incomplete TTF file\n"); + + if (verbosity >= 1) + fprintf (stderr, "Processing `maxp' table\n"); + surely_lseek (fd, maxpOff, SEEK_SET); + nglyphs = readMaxpTable (fd); + if (verbosity >= 1) + fprintf (stderr, " %d glyphs\n", nglyphs); + + if (verbosity >= 1) + fprintf (stderr, "Processing `head' table\n"); + surely_lseek (fd, headOff, SEEK_SET); + ht = mymalloc (sizeof (struct HeadTable)); + readHeadTable (fd, ht); + + if (verbosity >= 1) + fprintf (stderr, "Processing `post' table\n"); + surely_lseek (fd, postOff, SEEK_SET); + pt = mymalloc (sizeof (struct PostTable)); + postType = readPostTable (fd, nglyphs, pt, &gnt); + + if (verbosity >= 1) + fprintf (stderr, "Processing `name' table\n"); + surely_lseek (fd, nameOff, SEEK_SET); + strings = readNamingTable (fd); + + if (verbosity >= 1) + fprintf (stderr, "Generating PS file\n"); + printPSFont (out, ht, strings, nglyphs, postType, pt, gnt, fd); + fclose (out); + if (afm) + { + if (verbosity >= 1) + fprintf (stderr, "Generating AFM file\n"); + printAFM (afm, ht, strings, nglyphs, postType, pt, gnt, + bbox, hhea, hmtx, nkern, nke, ke); + fclose (afm); + } + if (verbosity >= 1) + fprintf (stderr, "Done.\n"); + close (fd); +} + + +static void +endianness_test () +{ + union + { + BYTE b[4]; + ULONG l; + } x; + ULONG v; + + x.b[0] = 1; + x.b[1] = 2; + x.b[2] = 3; + x.b[3] = 4; + + v = UL (x.l); + + if (v != (((((1 << 8) + 2) << 8) + 3) << 8) + 4) + { + fprintf (stderr, "Code badly compiled for this architecture\n"); + fprintf (stderr, "Please set SMALLENDIAN and recompile\n"); + exit (2); + } +} diff --git a/ttftool/util.c b/ttftool/util.c new file mode 100644 index 0000000000..45244213a0 --- /dev/null +++ b/ttftool/util.c @@ -0,0 +1,161 @@ +/* Copyright (c) 1997-1998 by Juliusz Chroboczek */ + +#include +#include +#include +#include +#include +#include +#include "types.h" +#include "proto.h" + +void * +mymalloc (size_t size) +{ + void *p; + if ((p = malloc (size)) == NULL) + error ("Unable to allocate memory\n"); + return p; +} + +void * +mycalloc (size_t nelem, size_t elsize) +{ + void *p; + if ((p = calloc (nelem, elsize)) == NULL) + error ("Unable to allocate memory\n"); + return p; +} + +void * +myrealloc (void *ptr, size_t size) +{ + void *p; + if ((p = realloc (ptr, size)) == NULL) + error ("Unable to allocate memory\n"); + return p; +} + +off_t +surely_lseek (int fildes, off_t offset, int whence) +{ + off_t result; + if ((result = lseek (fildes, offset, whence)) < 0) + error ("Bad TTF file"); + return result; +} + +void +error (char *string) +{ + fprintf (stderr, "%s\n", string); + exit (3); + /*NOTREACHED*/} + +void +syserror (char *string) +{ + perror (string); + exit (3); + /*NOTREACHED*/} + +ssize_t +surely_read (int fildes, void *buf, size_t nbyte) +{ + ssize_t n; + if ((n = read (fildes, buf, nbyte)) < nbyte) + error ("Bad TTF file"); + return n; +} + +char * +unistrncpy (char *dst, char *str, size_t length) +{ + int i, j; + + for (i = j = 0; i < length; i += 2) + if (str[i] == 0) + dst[j++] = str[i + 1]; + dst[j] = '\0'; + return dst; +} + +void +fputpss (char *s, FILE * stream) +{ + while (*s) + { + if ((*s & 0200) == 0 && *s >= 040 && *s != '(' && *s != ')') + putc (*s, stream); + else + fprintf (stream, "\\%03o", (unsigned char) *s); + s++; + } +} + +/* Hashtables */ + +unsigned +hash (char *string) +{ + int i; + unsigned u = 0; + for (i = 0; string[i] != '\0'; i++) + u = (u << 2) + string[i]; + return u; +} + +struct hashtable * +make_hashtable (int size) +{ + struct hashtable *t; + + t = mymalloc (sizeof (struct hashtable)); + t->size = size; + t->buckets = mycalloc (size, sizeof (struct hashtable_bucket *)); + + return t; +} + +int +puthash (struct hashtable *t, char *key, int value) +{ + int i; + + i = hash (key) % t->size; + + if (t->buckets[i] == 0) + { + t->buckets[i] = mymalloc (sizeof (struct hashtable_bucket)); + t->buckets[i]->entries = mymalloc (4 * sizeof (struct hashtable_entry)); + t->buckets[i]->size = 4; + t->buckets[i]->nentries = 0; + } + + if (t->buckets[i]->nentries >= t->buckets[i]->size) + { + t->buckets[i]->entries = myrealloc (t->buckets[i]->entries, + t->buckets[i]->size * 2 * + sizeof (struct hashtable_entry)); + t->buckets[i]->size *= 2; + } + + t->buckets[i]->entries[t->buckets[i]->nentries].key = key; + t->buckets[i]->entries[t->buckets[i]->nentries].value = value; + t->buckets[i]->nentries++; + + return value; +} + +int +gethash (struct hashtable *t, char *key) +{ + int i, j; + + i = hash (key) % t->size; + if (t->buckets[i]) + for (j = 0; j < t->buckets[i]->nentries; j++) + if (!strcmp (key, t->buckets[i]->entries[j].key)) + return t->buckets[i]->entries[j].value; + return -1; +}