diff options
Diffstat (limited to 'Build/source/texk/web2c/pdftexdir/ttf2afm.c')
-rw-r--r-- | Build/source/texk/web2c/pdftexdir/ttf2afm.c | 998 |
1 files changed, 998 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/pdftexdir/ttf2afm.c b/Build/source/texk/web2c/pdftexdir/ttf2afm.c new file mode 100644 index 00000000000..d3aa7051339 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/ttf2afm.c @@ -0,0 +1,998 @@ +/* +Copyright (c) 1996-2005 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/ttf2afm.c#21 $ +*/ + +/* +#include <kpathsea/c-auto.h> +#include <kpathsea/c-fopen.h> +#include <kpathsea/c-limits.h> +#include <kpathsea/c-memstr.h> +#include <kpathsea/c-proto.h> +#include <kpathsea/c-std.h> +#include <kpathsea/c-unistd.h> +#include <kpathsea/c-vararg.h> +#include <kpathsea/getopt.h> +*/ +#include <kpathsea/kpathsea.h> +#include <time.h> +#include <libgen.h> +#include <pdftexdir/ptexmac.h> +#include <pdftexdir/writettf.h> + +static const char perforce_id[] = + "$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/ttf2afm.c#21 $"; + +/* constants used for print_glyph */ +#define AS_NAME 0 +#define AS_INDEX 1 +#define AS_UNICODE 2 + +#define VERSION "1.0" + +#define enc_getchar() xgetc(encfile) +#define enc_eof() feof(encfile) +#define pdftex_fail ttf_fail + +#define print_str(S) if (S != NULL) fprintf(outfile, #S " %s\n", S) +#define print_dimen(N) if (N != 0) fprintf(outfile, #N " %i\n", (int)get_ttf_funit(N)) + +#define get_ttf_funit(n) \ + (n < 0 ? -((-n/upem)*1000 + ((-n%upem)*1000)/upem) :\ + ((n/upem)*1000 + ((n%upem)*1000)/upem)) + +typedef struct _unicode_entry { + TTF_USHORT code; + struct _unicode_entry *next; +} unicode_entry; + +typedef struct { + TTF_ULONG wx; + const char *name; + TTF_USHORT index; + TTF_LONG bbox[4]; + TTF_LONG offset; + char found; + unicode_entry *unicode_list; +} mtx_entry; + +typedef struct _kern_entry { + TTF_FWORD value; + TTF_USHORT adjacent; + struct _kern_entry *next; +} kern_entry; + + +char *FontName = NULL; +char *FullName = NULL; +char *FamilyName = NULL; +char *Notice = NULL; +char *Version = NULL; +char *Weight = NULL; +TTF_LONG ItalicAngle = 0; +TTF_LONG IsFixedPitch = 0; +TTF_LONG FontBBox1 = 0; +TTF_LONG FontBBox2 = 0; +TTF_LONG FontBBox3 = 0; +TTF_LONG FontBBox4 = 0; +TTF_LONG UnderlinePosition = 0; +TTF_LONG UnderlineThickness = 0; +TTF_LONG CapHeight = 0; +TTF_LONG XHeight = 0; +TTF_LONG Ascender = 0; +TTF_LONG Descender = 0; + +char *cur_file_name = NULL; +char *bname = NULL; +FILE *fontfile, *encfile, *outfile = NULL; +char enc_line[ENC_BUF_SIZE]; +int print_glyph = AS_NAME; /* print glyph as names by default*/ +int print_cmap = 0; +int use_ext_enc = 0; /* use external encoding? */ +int select_unicode = 1; /* use the first unicode mapping by default */ +int printing_enc = 0; /* set to 1 while printing encodings */ + + +TTF_USHORT upem; +TTF_USHORT ntabs; +int nhmtx; +int post_format; +int loca_format; +int nglyphs; +int nkernpairs = 0; +int names_count = 0; +char *ps_glyphs_buf = NULL; +dirtab_entry *dir_tab; +mtx_entry *mtx_tab; +kern_entry *kern_tab; +char *enc_names[MAX_CHAR_CODE + 1]; + +cmap_entry *cmap_tab; +TTF_USHORT ncmapsubtabs; +long cmap_offset; + +TTF_USHORT unicode_map[0xFFFF]; + +#include "macnames.c" + +void ttf_fail(char *fmt,...) +{ + va_list args; + va_start(args, fmt); + fprintf(stderr, "\nError: ttf2afm"); + if (cur_file_name) + fprintf(stderr, " (file %s)", cur_file_name); + fprintf(stderr, ": "); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + va_end(args); + exit(-1); +} + +void ttf_warn(char *fmt,...) +{ + va_list args; + va_start(args, fmt); + fprintf(stderr, "\nWarning: ttf2afm"); + if (cur_file_name) + fprintf(stderr, " (file %s)", cur_file_name); + fprintf(stderr, ": "); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + va_end(args); +} + +int xgetc(FILE *stream) +{ + int c = getc(stream); + if (c < 0 && c != EOF) + ttf_fail("getc() failed"); + return c; +} + +long ttf_getnum(int s) +{ + long i = 0; + int c; + while (s > 0) { + if ((c = xgetc(fontfile)) < 0) + ttf_fail("unexpected EOF"); + i = (i << 8) + c; + s--; + } + return i; +} + +dirtab_entry *name_lookup(char *s) +{ + dirtab_entry *p; + for (p = dir_tab; p - dir_tab < ntabs; p++) + if (strncmp(p->tag, s, 4) == 0) + break; + if (p - dir_tab == ntabs) + p = NULL; + return p; +} + +void ttf_seek_tab(char *name, TTF_LONG offset) +{ + dirtab_entry *p = name_lookup(name); + if (p == NULL) + ttf_fail("can't find table `%s'", name); + if (fseek(fontfile, p->offset + offset, SEEK_SET) < 0) + ttf_fail("fseek() failed while reading `%s' table", name); +} + +void ttf_seek_off(char *name, TTF_LONG offset) +{ + if (fseek(fontfile, offset, SEEK_SET) < 0) + ttf_fail("fseek() failed while reading `%s' table", name); +} + +void store_kern_value(TTF_USHORT i, TTF_USHORT j, TTF_FWORD v) +{ + kern_entry *pk; + for (pk = kern_tab + i; pk->next != NULL; pk = pk->next); + pk->next = xtalloc(1, kern_entry); + pk = pk->next; + pk->next = NULL; + pk->adjacent = j; + pk->value = v; +} + +TTF_FWORD get_kern_value(TTF_USHORT i, TTF_USHORT j) +{ + kern_entry *pk; + for (pk = kern_tab + i; pk->next != NULL; pk = pk->next) + if (pk->adjacent == j) + return pk->value; + return 0; +} + +void free_tabs() +{ + int i; + kern_entry *p, *q, *r; + unicode_entry *u, *v; + mtx_entry *pm; + xfree(ps_glyphs_buf); + xfree(dir_tab); + xfree(cmap_tab); + for (pm = mtx_tab; pm - mtx_tab < nglyphs; pm++) + if (pm->unicode_list != NULL) { + for (u = pm->unicode_list; u != NULL; u = v) { + v = u->next; + xfree(u); + } + } + xfree(mtx_tab); + for (i = 0; i <= MAX_CHAR_CODE; i++) + if (enc_names[i] != notdef) + free(enc_names[i]); + if (kern_tab == NULL) + return; + for (p = kern_tab; p - kern_tab < nglyphs; p++) + if (p->next != NULL) { + for (q = p->next; q != NULL; q = r) { + r = q->next; + xfree(q); + } + } + xfree(kern_tab); +} + +void enc_getline() +{ + char *p; + int c; +restart: + if (enc_eof()) + ttf_fail("unexpected end of file"); + p = enc_line; + do { + c = enc_getchar(); + append_char_to_buf(c, p, enc_line, ENC_BUF_SIZE); + } while (c != 10); + append_eol(p, enc_line, ENC_BUF_SIZE); + if (p - enc_line <= 2 || *enc_line == '%') + goto restart; +} + +void read_encoding(char *encname) +{ + char buf[ENC_BUF_SIZE], *q, *r; + int i; + cur_file_name = encname; + if ((encfile = kpse_open_file(encname, kpse_enc_format)) == NULL) + ttf_fail("can't open encoding file for reading"); + enc_getline(); + if (*enc_line != '/' || (r = strchr(enc_line, '[')) == 0) + ttf_fail("invalid encoding vector: name or `[' missing:\n%s", enc_line); + for (i = 0; i <= MAX_CHAR_CODE; i++) + enc_names[i] = (char*) notdef; + if (r[1] == 32) + r += 2; + else + r++; + for (;;) { + while (*r == '/') { + for (q = buf, r++; *r != ' ' && *r != 10 && *r != ']' && *r != '/'; *q++ = *r++); + *q = 0; + if (*r == ' ') + r++; + if (strcmp(buf, notdef) != 0) + enc_names[names_count] = xstrdup(buf); + if (names_count++ > MAX_CHAR_CODE) + ttf_fail("encoding vector contains more than %i names", + (int)(MAX_CHAR_CODE + 1)); + } + if (*r != 10 && *r != '%') + if (strncmp(r, "] def", strlen("] def")) == 0) + goto done; + else + ttf_fail("invalid encoding vector: a name or `] def' expected:\n%s", enc_line); + enc_getline(); + r = enc_line; + } +done: + xfclose(encfile, cur_file_name); + if (names_count != MAX_CHAR_CODE + 1) + ttf_warn("encoding vector contains only %i names (expected %i)", + names_count, MAX_CHAR_CODE + 1); +} + +void append_unicode(long glyph_index, TTF_USHORT code) +{ + mtx_entry *m; + unicode_entry *u, *v; + assert(glyph_index >= 0 && glyph_index < nglyphs); + u = xtalloc(1, unicode_entry), *v; + m = mtx_tab + glyph_index; + u->next = NULL; + u->code = code; + if (m->unicode_list == NULL) + m->unicode_list = u; + else { + for (v = m->unicode_list; v->next != NULL; v = v->next); + v->next = u; + } +} + +void read_cmap() +{ + cmap_entry *e; + seg_entry *seg_tab, *s; + TTF_USHORT *glyphId, format, segCount; + long int n, i, j, k, first_code, length, last_sep, index; + int unicode_map_count = 0; + ttf_seek_tab("cmap", TTF_USHORT_SIZE); /* skip the table vesrion number (=0) */ + ncmapsubtabs = get_ushort(); + cmap_offset = xftell(fontfile, cur_file_name) - 2*TTF_USHORT_SIZE; + cmap_tab = xtalloc(ncmapsubtabs, cmap_entry); + for (e = cmap_tab; e - cmap_tab < ncmapsubtabs; e++) { + e->platform_id = get_ushort(); + e->encoding_id = get_ushort(); + e->offset = get_ulong(); + } + for (i = 0; i < 0xFFFF; ++i) + unicode_map[i] = NOGLYPH_ASSIGNED_YET; + for (e = cmap_tab; e - cmap_tab < ncmapsubtabs; e++) { + ttf_seek_off("cmap", cmap_offset + e->offset); + format = get_ushort(); + if (is_unicode_mapping(e) && format == 4) { + ++unicode_map_count; + if (unicode_map_count == select_unicode) + goto read_unicode_mapping; + } + continue; +read_unicode_mapping: + length = get_ushort(); /* length of subtable */ + get_ushort(); /* skip the version number */ + segCount = get_ushort()/2; + get_ushort(); /* skip searchRange */ + get_ushort(); /* skip entrySelector */ + get_ushort(); /* skip rangeShift */ + seg_tab = xtalloc(segCount, seg_entry); + for (s = seg_tab; s - seg_tab < segCount; s++) + s->endCode = get_ushort(); + get_ushort(); /* skip reversedPad */ + for (s = seg_tab; s - seg_tab < segCount; s++) + s->startCode = get_ushort(); + for (s = seg_tab; s - seg_tab < segCount; s++) + s->idDelta = get_ushort(); + for (s = seg_tab; s - seg_tab < segCount; s++) + s->idRangeOffset = get_ushort(); + length -= 8*TTF_USHORT_SIZE + 4*segCount*TTF_USHORT_SIZE; + n = length/TTF_USHORT_SIZE; /* number of glyphID's */ + glyphId = xtalloc(n, TTF_USHORT); + for (i = 0; i < n; i++) + glyphId[i] = get_ushort(); + for (s = seg_tab; s - seg_tab < segCount; s++) { + for (i = s->startCode; i <= s->endCode; i++) { + if (i == 0xFFFF) + break; + if (s->idRangeOffset != 0xFFFF) { + if (s->idRangeOffset == 0) + index = (s->idDelta + i) & 0xFFFF; + else { + k = (i - s->startCode) + s->idRangeOffset/2 + + (s - seg_tab) - segCount ; + assert(k >= 0 && k < n); + index = glyphId[k]; + if (index != 0) + index = (index + s->idDelta) & 0xFFFF; + } + if (index < 0 || index >= nglyphs) + ttf_fail("cmap: glyph index out of range [0..%i)", nglyphs); + if (unicode_map[i] != NOGLYPH_ASSIGNED_YET) + ttf_fail("cmap: unicode %.4X is mapped to multiple glyphs", i); + if (unicode_map[i] == 0) + ttf_warn("unicode %.4X is mapped to glyph 0", i); + unicode_map[i] = index; + append_unicode(index, i); + } + } + } + xfree(seg_tab); + xfree(glyphId); + break; + } + if (e - cmap_tab == ncmapsubtabs) + ttf_fail("Invalid argument `-m %i': out of range [1..%i]", + select_unicode, unicode_map_count); +} + +void read_font() +{ + long i, j, k, l, n, m, platform_id, encoding_id; + TTF_FWORD kern_value; + char buf[1024], *p; + dirtab_entry *pd; + kern_entry *pk; + mtx_entry *pm; + ttf_skip(TTF_FIXED_SIZE); + ntabs = get_ushort(); + ttf_skip(3*TTF_USHORT_SIZE); + dir_tab = xtalloc(ntabs, dirtab_entry); + for (pd = dir_tab; pd - dir_tab < ntabs; pd++) { + pd->tag[0] = get_char(); + pd->tag[1] = get_char(); + pd->tag[2] = get_char(); + pd->tag[3] = get_char(); + ttf_skip(TTF_ULONG_SIZE); + pd->offset = get_ulong(); + pd->length = get_ulong(); + } + ttf_seek_tab("head", 2*TTF_FIXED_SIZE + 2*TTF_ULONG_SIZE + TTF_USHORT_SIZE); + upem = get_ushort(); + ttf_skip(16); + FontBBox1 = get_fword(); + FontBBox2 = get_fword(); + FontBBox3 = get_fword(); + FontBBox4 = get_fword(); + ttf_skip(TTF_USHORT_SIZE); + ttf_skip(TTF_USHORT_SIZE + TTF_SHORT_SIZE); + loca_format = get_short(); + ttf_seek_tab("maxp", TTF_FIXED_SIZE); + nglyphs = get_ushort(); + mtx_tab = xtalloc(nglyphs + 1, mtx_entry); + for (pm = mtx_tab; pm - mtx_tab < nglyphs + 1; pm++) { + pm->name = NULL; /* notdef */ + pm->found = 0; + pm->unicode_list = NULL; + } + ttf_seek_tab("hhea", TTF_FIXED_SIZE); + Ascender = get_fword(); + Descender = get_fword(); + ttf_skip(TTF_FWORD_SIZE + TTF_UFWORD_SIZE + 3*TTF_FWORD_SIZE + 8*TTF_SHORT_SIZE); + nhmtx = get_ushort(); + ttf_seek_tab("hmtx", 0); + for (pm = mtx_tab; pm - mtx_tab < nhmtx; pm++) { + pm->wx = get_ufword(); + ttf_skip(TTF_FWORD_SIZE); + } + i = pm[-1].wx; + for (; pm - mtx_tab < nglyphs; pm++) + pm->wx = i; + ttf_seek_tab("post", 0); + post_format = get_fixed(); + ItalicAngle = get_fixed(); + UnderlinePosition = get_fword(); + UnderlineThickness = get_fword(); + IsFixedPitch = get_ulong(); + ttf_skip(4*TTF_ULONG_SIZE); + switch (post_format) { + case 0x00010000: + for (pm = mtx_tab; pm - mtx_tab < NMACGLYPHS; pm++) + pm->name = mac_glyph_names[pm - mtx_tab]; + break; + case 0x00020000: + l = get_ushort(); /* some fonts have this value different from nglyphs */ + for (pm = mtx_tab; pm - mtx_tab < l; pm++) + pm->index = get_ushort(); + if ((pd = name_lookup("post")) == NULL) + ttf_fail("can't find table `post'"); + n = pd->length - (xftell(fontfile, cur_file_name) - pd->offset); + ps_glyphs_buf = xtalloc(n + 1, char); + for (m = 0, p = ps_glyphs_buf; p - ps_glyphs_buf < n;) { + for (i = get_byte(); i > 0; i--) + *p++ = get_char(); + *p++ = 0; + m++; + } + for (pm = mtx_tab; pm - mtx_tab < l; pm++) { + if (pm->index < NMACGLYPHS) + pm->name = mac_glyph_names[pm->index]; + else { + k = pm->index - NMACGLYPHS; + if (k < m) { + for (p = ps_glyphs_buf; k > 0; k--) + p = (char *)strend(p) + 1; + pm->name = p; + } + else { + pm->name = NULL; /* index out of valid range, fix name to notdef */ + } + } + } + break; + case 0x00030000: + if (print_glyph == AS_NAME) { + ttf_warn("no names available in `post' table, print glyph names as indices"); + print_glyph = AS_INDEX; + } + break; + default: + ttf_fail("unsupported format (%.8X) of `post' table", post_format); + } + ttf_seek_tab("loca", 0); + for (pm = mtx_tab; pm - mtx_tab < nglyphs + 1; pm++) + pm->offset = (loca_format == 1 ? get_ulong() : get_ushort() << 1); + if ((pd = name_lookup("glyf")) == NULL) + ttf_fail("can't find table `glyf'"); + for (n = pd->offset, pm = mtx_tab; pm - mtx_tab < nglyphs; pm++) { + ttf_seek_off("glyf", n + pm->offset); + ttf_skip(TTF_SHORT_SIZE); + pm->bbox[0] = get_fword(); + pm->bbox[1] = get_fword(); + pm->bbox[2] = get_fword(); + pm->bbox[3] = get_fword(); + } + + ttf_seek_tab("name", 0); + i = ftell(fontfile); + get_ushort(); /* skip Format selector (=0) */ + n = get_ushort(); /* number of name records */ + j = get_ushort() + i; /* start of string storage */ + i += 3*TTF_USHORT_SIZE; /* update the current offset */ + while (n-- > 0) { + ttf_seek_off("name", i); + platform_id = get_ushort(); + encoding_id = get_ushort(); + get_ushort(); /* skip language_id */ + k = get_ushort(); /* name_id */ + l = get_ushort(); /* string length */ + if ((platform_id == 1 && encoding_id == 0) && + (k == 0 || k == 1 || k == 4 || k == 5 || + k == 6)) { + ttf_seek_off("name", j + get_ushort()); + for (p = buf; l-- > 0; p++) + *p = get_char(); + *p++ = 0; + p = xstrdup(buf); + switch (k) { + case 0: Notice = p; break; + case 1: FamilyName = p; break; + case 4: FullName = p; break; + case 5: Version = p; break; + case 6: FontName = p; break; + } + if (Notice != NULL && FamilyName != NULL && + FullName != NULL && FontName != NULL && + Version != NULL) + break; + } + i += 6*TTF_USHORT_SIZE; + } + if ((pd = name_lookup("PCLT")) != NULL) { + ttf_seek_off("PCLT", pd->offset + TTF_FIXED_SIZE + TTF_ULONG_SIZE + TTF_USHORT_SIZE); + XHeight = get_ushort(); + if (XHeight > FontBBox4) { + ttf_warn("XHeight is too big (%i)\n" + "This is likely a font bug, so I discarded this parameter.", + (int)get_ttf_funit(XHeight)); + XHeight = 0; + } + ttf_skip(2*TTF_USHORT_SIZE); + CapHeight = get_ushort(); + if (CapHeight > FontBBox4) { + ttf_warn("CapHeight is too big (%i)\n" + "This is likely a font bug, so I discarded this parameter.", + (int)get_ttf_funit(CapHeight)); + CapHeight = 0; + } + } + if ((pd = name_lookup("OS/2")) != NULL) { + ttf_seek_off("OS/2", pd->offset + TTF_USHORT_SIZE + TTF_SHORT_SIZE); + switch (get_ushort()) { + case 100: Weight = xstrdup("Thin"); break; + case 200: Weight = xstrdup("ExtraLight"); break; + case 300: Weight = xstrdup("Light"); break; + case 400: Weight = xstrdup("Normal"); break; + case 500: Weight = xstrdup("Medium"); break; + case 600: Weight = xstrdup("SemiBold"); break; + case 700: Weight = xstrdup("Bold"); break; + case 800: Weight = xstrdup("ExtraBold"); break; + case 900: Weight = xstrdup("Black"); break; + } + } + read_cmap(); + if ((pd = name_lookup("kern")) == NULL) + return; + kern_tab = xtalloc(nglyphs, kern_entry); + for (pk = kern_tab; pk - kern_tab < nglyphs; pk++) { + pk->next = NULL; + pk->value = 0; + } + ttf_seek_off("kern", pd->offset + TTF_USHORT_SIZE); + for (n = get_ushort(); n > 0; n--) { + ttf_skip(2*TTF_USHORT_SIZE); + k = get_ushort(); + if (!(k & 1) || (k & 2) || (k & 4)) + return; + if (k >> 8 != 0) { + ttf_warn("warning: only format 0 supported of `kern' \ + subtables, others are ignored\n"); + continue; + } + k = get_ushort(); + ttf_skip(3*TTF_USHORT_SIZE); + while (k-- > 0) { + i = get_ushort(); + j = get_ushort(); + kern_value = get_fword(); + if (kern_value != 0) { + store_kern_value(i, j, kern_value); + nkernpairs++; + } + } + } +} + +int null_glyph(const char *s) +{ + return (s == NULL || s == notdef); + /* + strcmp(s, ".null") == 0 || + strcmp(s, ".notdef") == 0 || + strcmp(s, "CR") == 0 || + strcmp(s, "nonmarkingreturn") == 0 + */ +} + +void print_glyph_name(FILE *f, long glyph_index, int convention) +{ + unicode_entry *u; + static char buf[1024]; + const char *n; + assert(glyph_index >= 0 && glyph_index < nglyphs); + n = mtx_tab[glyph_index].name; + if (printing_enc && (n == notdef || glyph_index == 0)) { + fputs(notdef, f); + return; + } + switch (convention) { + case AS_NAME: + if (!null_glyph(n)) + fprintf(f, "%s", mtx_tab[glyph_index].name); + else if (n == notdef && glyph_index == 0) + fputs(notdef, f); + else + fprintf(f, "%s%li", GLYPH_PREFIX_INDEX, glyph_index); + break; + case AS_INDEX: + fprintf(f, "%s%li", GLYPH_PREFIX_INDEX, glyph_index); + break; + case AS_UNICODE: + u = mtx_tab[glyph_index].unicode_list; + if (glyph_index == 0 || u == NULL) + fprintf(f, "%s%li", GLYPH_PREFIX_INDEX, glyph_index); + else { + fprintf(f, "%s%.4X", GLYPH_PREFIX_UNICODE, u->code); + if (u->next != NULL) { + *buf = 0; + for (; u != NULL; u = u->next) { + assert(strlen(buf) + strlen(GLYPH_PREFIX_UNICODE) + 4 < sizeof(buf)); + sprintf(strend(buf), "%s%.4X ", GLYPH_PREFIX_UNICODE, u->code); + } + ttf_warn("glyph %li have multiple encodings: %s", + glyph_index, buf); + } + } + break; + } +} + +void print_char_metric(FILE *f, int charcode, long glyph_index) +{ + assert(glyph_index >= 0 && glyph_index < nglyphs); + fprintf(f, "C %i ; WX %i ; N ", (int) charcode, + (int)get_ttf_funit(mtx_tab[glyph_index].wx)); + print_glyph_name(f, glyph_index, print_glyph); + fprintf(f, " ; B %i %i %i %i ;\n", + (int)get_ttf_funit(mtx_tab[glyph_index].bbox[0]), + (int)get_ttf_funit(mtx_tab[glyph_index].bbox[1]), + (int)get_ttf_funit(mtx_tab[glyph_index].bbox[2]), + (int)get_ttf_funit(mtx_tab[glyph_index].bbox[3])); +} + +void print_afm(char *date, char *fontname) +{ + int i, ncharmetrics; + mtx_entry *pm; + short mtx_index[MAX_CHAR_CODE + 1], *idx; + unsigned int index; + char **pe; + kern_entry *pk, *qk; + unicode_entry *u; + char buf[20]; + fputs("StartFontMetrics 2.0\n", outfile); + fprintf(outfile, "Comment Converted at %s by ttf2afm from font file `%s'\n", date, fontname); + print_str(FontName); + print_str(FullName); + print_str(FamilyName); + print_str(Weight); + fprintf(outfile, "ItalicAngle %i", (int)(ItalicAngle/0x10000)); + if (ItalicAngle%0x10000 > 0) + fprintf(outfile, ".%i", (int)((ItalicAngle%0x10000)*1000)/0x10000); + fputs("\n", outfile); + fprintf(outfile, "IsFixedPitch %s\n", IsFixedPitch ? "true" : "false"); + fprintf(outfile, "FontBBox %i %i %i %i\n", + (int)get_ttf_funit(FontBBox1), + (int)get_ttf_funit(FontBBox2), + (int)get_ttf_funit(FontBBox3), + (int)get_ttf_funit(FontBBox4)); + print_dimen(UnderlinePosition); + print_dimen(UnderlineThickness); + print_str(Version); + print_str(Notice); + fputs("EncodingScheme FontSpecific\n", outfile); + print_dimen(CapHeight); + print_dimen(XHeight); + print_dimen(Ascender); + print_dimen(Descender); + ncharmetrics = nglyphs; + if (use_ext_enc == 0) { /* external encoding vector not given */ + fprintf(outfile, "StartCharMetrics %u\n", ncharmetrics); + for (pm = mtx_tab; pm - mtx_tab < nglyphs; pm++) { + pm->found = 1; + print_char_metric(outfile, -1, pm - mtx_tab); + } + } + else { /* external encoding vector given */ + for (idx = mtx_index; idx - mtx_index <= MAX_CHAR_CODE; *idx++ = 0); + for (pe = enc_names; pe - enc_names < names_count; pe++) { + if (*pe == notdef) + continue; + /* scan form `uniABCD' */ + if (sscanf(*pe, GLYPH_PREFIX_UNICODE "%X", &index) == 1) { + if (unicode_map[index] != NOGLYPH_ASSIGNED_YET) { + pm = mtx_tab + unicode_map[index]; + pm->found = 1; + } + else + ttf_warn("`unicode %s%.4X' is not mapped to any glyph", + GLYPH_PREFIX_UNICODE, index); + continue; + } + /* scan form `index123' */ + if (sscanf(*pe, GLYPH_PREFIX_INDEX "%u", &index) == 1) { + if (index >= nglyphs) + ttf_fail("`%s' out of valid range [0..%i)", + *pe, nglyphs); + pm = mtx_tab + index; + pm->found = 1; + continue; + } + for (pm = mtx_tab; pm - mtx_tab < nglyphs; pm++) + if (pm->name != NULL && strcmp(*pe, pm->name) == 0) + break; + if (pm - mtx_tab < nglyphs) { + mtx_index[pe - enc_names] = pm - mtx_tab; + pm->found = 1; + continue; + } + else + ttf_warn("glyph `%s' not found", *pe); + } + fprintf(outfile, "StartCharMetrics %u\n", ncharmetrics); + for (idx = mtx_index; idx - mtx_index <= MAX_CHAR_CODE; idx++) { + if (*idx != 0 && mtx_tab[*idx].found == 1) + print_char_metric(outfile, idx - mtx_index, *idx); + } + for (pm = mtx_tab; pm - mtx_tab < nglyphs; pm++) { + if (pm->found == 0) + print_char_metric(outfile, -1, pm - mtx_tab); + } + } +end_metrics: + fputs("EndCharMetrics\n", outfile); + if (nkernpairs == 0) + goto end_kerns; + fprintf(outfile, "StartKernData\nStartKernPairs %i\n", nkernpairs); + for (pk = kern_tab; pk - kern_tab < nglyphs; pk++) + for (qk = pk; qk != NULL; qk = qk->next) + if (qk->value != 0) { + fputs("KPX ", outfile); + print_glyph_name(outfile, pk - kern_tab, print_glyph); + fputs(" ", outfile); + print_glyph_name(outfile, qk->adjacent, print_glyph); + fprintf(outfile, " %i\n", get_ttf_funit(qk->value)); + } + fputs("EndKernPairs\nEndKernData\n", outfile); +end_kerns: + fputs("EndFontMetrics\n", outfile); +} + +void print_encoding(char *fontname) +{ + long int i, k, first_code, length, last_sep; + FILE *file; + TTF_USHORT format; + char *enc_name, *end_enc_name; + cmap_entry *e; + const char *n; + printing_enc = 1; + enc_name = xtalloc(strlen(bname) + 20, char); + strcpy(enc_name, bname); + end_enc_name = strend(enc_name); + for (e = cmap_tab; e - cmap_tab < ncmapsubtabs; e++) { + ttf_seek_off("cmap", cmap_offset + e->offset); + format = get_ushort(); + if (format != 0 && format != 4 && format != 6) { + ttf_warn("format %i of encoding subtable unsupported", (int)format); + continue; + } + sprintf(end_enc_name, ".e%i%i", + (int)e->platform_id, (int)e->encoding_id); + if ((file = xfopen(enc_name, FOPEN_W_MODE)) == NULL) + ttf_fail("cannot open file for writing (%s)\n", enc_name); + fprintf(file, "%% Encoding table from font file %s\n", fontname); + fprintf(file, "%% Platform ID %i", (int)e->platform_id); + switch (e->platform_id) { + case 0: fprintf(file, " (Apple Unicode)"); break; + case 1: fprintf(file, " (Macintosh)"); break; + case 2: fprintf(file, " (ISO)"); break; + case 3: fprintf(file, " (Microsoft)"); break; + } + fprintf(file, "\n"); + fprintf(file, "%% Encoding ID %i", (int)e->encoding_id); + if (e->platform_id == 1 && e->encoding_id == 0) + fprintf(file, " (Roman)"); + if (e->platform_id == 3) + switch (e->encoding_id) { + case 0: fprintf(file, " (Symbol)"); break; + case 1: fprintf(file, " (Unicode)"); break; + } + fprintf(file, "\n"); + fprintf(file, "%% Format %i", (int)(format)); + switch (format) { + case 0: fprintf(file, " (byte encoding table)"); break; + case 4: fprintf(file, " (segment mapping to delta values)"); break; + case 6: fprintf(file, " (trimmed table mapping)"); break; + } + fprintf(file, "\n"); + fprintf(file, "/Encoding%i [\n", (int)(e - cmap_tab + 1)); + switch (format) { + case 0: + get_ushort(); /* skip length */ + get_ushort(); /* skip version number */ + for (i = 0; i <= MAX_CHAR_CODE; i++) { + fputs("/", file); + print_glyph_name(file, get_byte(), print_glyph); + fputs("\n", file); + } + break; + case 4: + for (i = 0; i < nglyphs; ++i) { + fprintf(file, "%% Glyph %li -> ", i); + print_glyph_name(file, i, AS_UNICODE); + fputs("\n", file); + } + break; + case 6: + get_ushort(); /* skip table length */ + get_ushort(); /* skip version number */ + first_code = get_ushort(); /* first character code */ + for (i = 0; i < first_code; ++i) + fprintf(file, "/%s\n", notdef); + length = get_ushort(); /* number of character codes */ + for (i = first_code; i < first_code + length; i++) { + k = get_ushort(); + if (i > MAX_CHAR_CODE) + fputs("% ", file); + fputs("/", file); + print_glyph_name(file, k, print_glyph); + fputs("\n", file); + } + for (i = first_code + length; i <= MAX_CHAR_CODE; i++) + fprintf(file, "/%s\n", notdef); + break; + default: + ttf_warn("format %i of encoding subtable unsupported", (int)format); + } + fprintf(file, "] def\n"); + } + xfree(enc_name); +} + +void usage() +{ + cur_file_name = NULL; + fprintf(stderr, + "Usage: ttf2afm [-i|-u|-c|-v] [-e enc] [-o filename] [-m NUM] fontfile\n" + " -i: force printing glyph names in form 'index123'\n" + " -u: force printing glyph names in form 'uniABCD'\n" + " -c: print encoding tables to `basename.e<platformID><encodingID>'\n" + " -v: print version\n" + " -e enc: encode the AFM output using encoding vector from `enc'\n" + " -o filename: write output to file `filename' instead of stdout\n" + " -m NUM: select unicode mapping (default = 1, ie the first)\n" + " fontfile: the TrueType fontfile\n" + "\nPlease send bug reports or feature requests to <pdftex@tug.org>\n" + ); + _exit(-1); +} + +int main(int argc, char **argv) +{ + char date[128], *s; + time_t t = time(&t); + int c; + kpse_set_progname(argv[0]); + kpse_init_prog("ttf2afm", 0, 0, 0) ; + while ((c = getopt(argc, argv, "iucve:o:m:")) != -1) + switch (c) { + case 'i': + print_glyph = AS_INDEX; + break; + case 'u': + print_glyph = AS_UNICODE; + break; + case 'c': + print_cmap = 1; + break; + case 'e': + cur_file_name = optarg; + read_encoding(cur_file_name); + use_ext_enc = 1; + break; + case 'o': + cur_file_name = optarg; + outfile = xfopen(cur_file_name, FOPEN_W_MODE); + if (outfile == NULL) + ttf_fail("cannot open file for writing"); + break; + case 'm': + select_unicode = atoi(optarg); + break; + case 'v': + fprintf(stderr, + "ttf2afm version " VERSION "\n" + "Copyright (C) 1997-2005 Han The Thanh.\n" + "There is NO warranty. Redistribution of this software is\n" + "covered by the terms of both the pdfTeX copyright and\n" + "the GNU General Public License.\n" + "For more information about these matters, see the files\n" + "named COPYING and the pdfTeX source.\n" + "Primary author of ttf2afm: Han The Thanh.\n" + ); + _exit(0); + default: + usage(); + } + if (argc - optind != 1) + usage(); + sprintf(date, "%s\n", ctime(&t)); + *(char *)strchr(date, '\n') = 0; + cur_file_name = argv[optind]; + if (print_cmap) { + bname = strdup(xbasename(cur_file_name)); + if ((s = rindex(bname, '.')) != NULL) + *s = 0; + } + if ((fontfile = kpse_open_file(cur_file_name, kpse_truetype_format)) == NULL) + ttf_fail("can't open font file for reading"); + read_font(); + if (outfile == NULL) + outfile = stdout; + print_afm(date, cur_file_name); + if (print_cmap) + print_encoding(cur_file_name); + xfree(FontName); + xfree(FullName); + xfree(FamilyName); + xfree(Notice); + xfree(Version); + xfree(Weight); + free_tabs(); + xfclose(fontfile, cur_file_name); + return 0; +} |