Back to index

tetex-bin  3.0
ttf2afm.c
Go to the documentation of this file.
00001 /*
00002 Copyright (c) 1996-2005 Han The Thanh, <thanh@pdftex.org>
00003 
00004 This file is part of pdfTeX.
00005 
00006 pdfTeX is free software; you can redistribute it and/or modify
00007 it under the terms of the GNU General Public License as published by
00008 the Free Software Foundation; either version 2 of the License, or
00009 (at your option) any later version.
00010 
00011 pdfTeX is distributed in the hope that it will be useful,
00012 but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 GNU General Public License for more details.
00015 
00016 You should have received a copy of the GNU General Public License
00017 along with pdfTeX; if not, write to the Free Software
00018 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 
00020 $Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/ttf2afm.c#15 $
00021 */
00022 
00023 /*
00024 #include <kpathsea/c-auto.h>
00025 #include <kpathsea/c-fopen.h>
00026 #include <kpathsea/c-limits.h>
00027 #include <kpathsea/c-memstr.h>
00028 #include <kpathsea/c-proto.h>
00029 #include <kpathsea/c-std.h>
00030 #include <kpathsea/c-unistd.h>
00031 #include <kpathsea/c-vararg.h>
00032 #include <kpathsea/getopt.h>
00033 */
00034 #include <kpathsea/kpathsea.h>
00035 #include <time.h>
00036 #include <pdftexdir/ptexmac.h>
00037 #include <pdftexdir/writettf.h>
00038 
00039 static const char perforce_id[] = 
00040     "$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/ttf2afm.c#15 $";
00041 
00042 /* constants used for print_glyph */
00043 #define AS_NAME         0
00044 #define AS_INDEX        1
00045 #define AS_UNICODE      2
00046 
00047 #define VERSION         "1.0"
00048 
00049 #define enc_getchar()   xgetc(encfile)
00050 #define enc_eof()       feof(encfile)
00051 #define pdftex_fail     ttf_fail
00052 
00053 #define print_str(S)    if (S != NULL) fprintf(outfile, #S " %s\n", S)
00054 #define print_dimen(N)  if (N != 0) fprintf(outfile, #N " %i\n", (int)get_ttf_funit(N))
00055 
00056 #define get_ttf_funit(n) \
00057     (n < 0 ? -((-n/upem)*1000 + ((-n%upem)*1000)/upem) :\
00058     ((n/upem)*1000 + ((n%upem)*1000)/upem))
00059 
00060 typedef struct _unicode_entry {
00061     TTF_USHORT code;
00062     struct _unicode_entry *next;
00063 } unicode_entry;
00064 
00065 typedef struct {
00066     TTF_ULONG wx;
00067     const char *name;
00068     TTF_USHORT index;
00069     TTF_LONG bbox[4];
00070     TTF_LONG offset;
00071     char found;
00072     unicode_entry *unicode_list;
00073 } mtx_entry;
00074 
00075 typedef struct _kern_entry {
00076     TTF_FWORD value;
00077     TTF_USHORT adjacent;
00078     struct _kern_entry *next;
00079 } kern_entry;
00080 
00081 
00082 char *FontName = NULL;
00083 char *FullName = NULL;
00084 char *FamilyName = NULL;
00085 char *Notice = NULL;
00086 char *Version = NULL;
00087 char *Weight = NULL;
00088 TTF_LONG ItalicAngle = 0;
00089 TTF_LONG IsFixedPitch = 0;
00090 TTF_LONG FontBBox1 = 0;
00091 TTF_LONG FontBBox2 = 0;
00092 TTF_LONG FontBBox3 = 0;
00093 TTF_LONG FontBBox4 = 0;
00094 TTF_LONG UnderlinePosition = 0;
00095 TTF_LONG UnderlineThickness = 0;
00096 TTF_LONG CapHeight = 0;
00097 TTF_LONG XHeight = 0;
00098 TTF_LONG Ascender = 0;
00099 TTF_LONG Descender = 0;
00100 
00101 char *cur_file_name = NULL;
00102 char *bname = NULL;
00103 FILE *fontfile, *encfile, *outfile = NULL;
00104 char enc_line[ENC_BUF_SIZE];
00105 int print_glyph = AS_NAME;    /* print glyph as names by default*/
00106 int print_cmap = 0;
00107 int use_ext_enc = 0;    /* use external encoding? */
00108 int select_unicode = 1; /* use the first unicode mapping by default */
00109 int printing_enc = 0; /* set to 1 while printing encodings */
00110 
00111 
00112 TTF_USHORT upem;
00113 TTF_USHORT ntabs;
00114 int nhmtx;
00115 int post_format;
00116 int loca_format;
00117 int nglyphs;
00118 int nkernpairs = 0;
00119 int names_count = 0;
00120 char *ps_glyphs_buf = NULL;
00121 dirtab_entry *dir_tab;
00122 mtx_entry *mtx_tab;
00123 kern_entry *kern_tab;
00124 char *enc_names[MAX_CHAR_CODE + 1];
00125 
00126 cmap_entry *cmap_tab;
00127 TTF_USHORT ncmapsubtabs;
00128 long cmap_offset;
00129 
00130 TTF_USHORT unicode_map[0xFFFF];
00131 
00132 #include "macnames.c"
00133 
00134 void ttf_fail(char *fmt,...)
00135 {
00136     va_list args;
00137     va_start(args, fmt);
00138     fprintf(stderr, "\nError: ttf2afm");
00139     if (cur_file_name)
00140         fprintf(stderr, " (file %s)", cur_file_name);
00141     fprintf(stderr, ": ");
00142     vfprintf(stderr, fmt, args);
00143     fprintf(stderr, "\n");
00144     va_end(args);
00145     exit(-1);
00146 }
00147 
00148 void ttf_warn(char *fmt,...)
00149 {
00150     va_list args;
00151     va_start(args, fmt);
00152     fprintf(stderr, "\nWarning: ttf2afm");
00153     if (cur_file_name)
00154         fprintf(stderr, " (file %s)", cur_file_name);
00155     fprintf(stderr, ": ");
00156     vfprintf(stderr, fmt, args);
00157     fprintf(stderr, "\n");
00158     va_end(args);
00159 }
00160 
00161 int xgetc(FILE *stream)
00162 {
00163     int c = getc(stream);
00164     if (c < 0 && c != EOF)
00165         ttf_fail("getc() failed");
00166     return c;
00167 }
00168 
00169 long ttf_getnum(int s)
00170 {
00171     long i = 0;
00172     int c;
00173     while (s > 0) {
00174         if ((c = xgetc(fontfile)) < 0)
00175             ttf_fail("unexpected EOF");
00176         i = (i << 8) + c;
00177         s--;
00178     }
00179     return i;
00180 }
00181 
00182 dirtab_entry *name_lookup(char *s)
00183 {
00184     dirtab_entry *p;
00185     for (p = dir_tab; p - dir_tab < ntabs; p++)
00186         if (strncmp(p->tag, s, 4) == 0)
00187             break;
00188     if (p - dir_tab == ntabs)
00189         p = NULL;
00190     return p;
00191 }
00192 
00193 void ttf_seek_tab(char *name, TTF_LONG offset)
00194 {
00195     dirtab_entry *p = name_lookup(name);
00196     if (p == NULL)
00197         ttf_fail("can't find table `%s'", name);
00198     if (fseek(fontfile, p->offset + offset, SEEK_SET) < 0)
00199         ttf_fail("fseek() failed while reading `%s' table", name);
00200 }
00201 
00202 void ttf_seek_off(char *name, TTF_LONG offset)
00203 {
00204     if (fseek(fontfile, offset, SEEK_SET) < 0)
00205         ttf_fail("fseek() failed while reading `%s' table", name);
00206 }
00207 
00208 void store_kern_value(TTF_USHORT i, TTF_USHORT j, TTF_FWORD v)
00209 {
00210     kern_entry *pk;
00211     for (pk = kern_tab + i; pk->next != NULL; pk = pk->next);
00212     pk->next = xtalloc(1, kern_entry);
00213     pk = pk->next;
00214     pk->next = NULL;
00215     pk->adjacent = j;
00216     pk->value = v;
00217 }
00218 
00219 TTF_FWORD get_kern_value(TTF_USHORT i, TTF_USHORT j)
00220 {
00221     kern_entry *pk;
00222     for (pk = kern_tab + i; pk->next != NULL; pk = pk->next)
00223         if (pk->adjacent == j)
00224             return pk->value;
00225     return 0;
00226 }
00227 
00228 void free_tabs()
00229 {
00230     int i;
00231     kern_entry *p, *q, *r;
00232     unicode_entry *u, *v;
00233     mtx_entry *pm;
00234     xfree(ps_glyphs_buf);
00235     xfree(dir_tab);
00236     xfree(cmap_tab);
00237     for (pm = mtx_tab; pm - mtx_tab < nglyphs; pm++)
00238         if (pm->unicode_list != NULL) {
00239             for (u = pm->unicode_list; u != NULL; u = v) {
00240                 v = u->next;
00241                 xfree(u);
00242             }
00243         }
00244     xfree(mtx_tab);
00245     for (i = 0; i <= MAX_CHAR_CODE; i++)
00246         if (enc_names[i] != notdef)
00247             free(enc_names[i]);
00248     if (kern_tab == NULL)
00249         return;
00250     for (p = kern_tab; p - kern_tab < nglyphs; p++)
00251         if (p->next != NULL) {
00252             for (q = p->next; q != NULL; q = r) {
00253                 r = q->next;
00254                 xfree(q);
00255             }
00256         }
00257     xfree(kern_tab);
00258 }
00259 
00260 void enc_getline()
00261 {
00262     char *p;
00263     int c;
00264 restart:
00265     if (enc_eof())
00266         ttf_fail("unexpected end of file");
00267     p = enc_line;
00268     do {
00269         c = enc_getchar();
00270         append_char_to_buf(c, p, enc_line, ENC_BUF_SIZE);
00271     } while (c != 10);
00272     append_eol(p, enc_line, ENC_BUF_SIZE);
00273     if (p - enc_line <= 2 || *enc_line == '%')
00274         goto restart;
00275 }
00276 
00277 void read_encoding(char *encname)
00278 {
00279     char buf[ENC_BUF_SIZE], *q, *r;
00280     int i;
00281     cur_file_name = encname;
00282     if ((encfile = kpse_open_file(encname, kpse_enc_format)) == NULL)
00283         ttf_fail("can't open encoding file for reading");
00284     enc_getline();
00285     if (*enc_line != '/' || (r = strchr(enc_line, '[')) == 0)
00286         ttf_fail("invalid encoding vector: name or `[' missing:\n%s", enc_line);
00287     for (i = 0; i <= MAX_CHAR_CODE; i++)
00288         enc_names[i] = (char*) notdef;
00289     if (r[1] == 32)
00290         r += 2;
00291     else
00292         r++;
00293     for (;;) {
00294         while (*r == '/') {
00295             for (q = buf, r++; *r != ' ' && *r != 10 && *r != ']' && *r != '/'; *q++ = *r++);
00296             *q = 0;
00297             if (*r == ' ')
00298                 r++;
00299             if (strcmp(buf, notdef) != 0)
00300                 enc_names[names_count] = xstrdup(buf);
00301             if (names_count++ > MAX_CHAR_CODE)
00302                 ttf_fail("encoding vector contains more than %i names",
00303                      (int)(MAX_CHAR_CODE + 1));
00304         }
00305         if (*r != 10 && *r != '%')
00306             if (strncmp(r, "] def", strlen("] def")) == 0)
00307                 goto done;
00308             else
00309                 ttf_fail("invalid encoding vector: a name or `] def' expected:\n%s", enc_line);
00310         enc_getline();
00311         r = enc_line;
00312     }
00313 done:
00314     xfclose(encfile, cur_file_name);
00315     if (names_count != MAX_CHAR_CODE + 1)
00316         ttf_warn("encoding vector contains only %i names (expected %i)", 
00317                  names_count, MAX_CHAR_CODE + 1);
00318 }
00319 
00320 void append_unicode(long glyph_index, TTF_USHORT code)
00321 {
00322     mtx_entry *m;
00323     unicode_entry *u, *v;
00324     assert(glyph_index >= 0 && glyph_index < nglyphs);
00325     u = xtalloc(1, unicode_entry), *v;
00326     m = mtx_tab + glyph_index;
00327     u->next = NULL;
00328     u->code = code;
00329     if (m->unicode_list == NULL)
00330         m->unicode_list = u;
00331     else {
00332         for (v = m->unicode_list; v->next != NULL; v = v->next);
00333         v->next = u;
00334     }
00335 }
00336 
00337 void read_cmap()
00338 {
00339     cmap_entry *e;
00340     seg_entry *seg_tab, *s;
00341     TTF_USHORT *glyphId, format, segCount;
00342     long int n, i, j, k, first_code, length, last_sep, index;
00343     int unicode_map_count = 0;
00344     ttf_seek_tab("cmap", TTF_USHORT_SIZE); /* skip the table vesrion number (=0) */
00345     ncmapsubtabs = get_ushort();
00346     cmap_offset = xftell(fontfile, cur_file_name) - 2*TTF_USHORT_SIZE;
00347     cmap_tab = xtalloc(ncmapsubtabs, cmap_entry);
00348     for (e = cmap_tab; e - cmap_tab < ncmapsubtabs; e++) {
00349         e->platform_id = get_ushort();
00350         e->encoding_id = get_ushort();
00351         e->offset = get_ulong();
00352     }
00353     for (i = 0; i < 0xFFFF; ++i)
00354         unicode_map[i] = NOGLYPH_ASSIGNED_YET;
00355     for (e = cmap_tab; e - cmap_tab < ncmapsubtabs; e++) {
00356         ttf_seek_off("cmap", cmap_offset + e->offset);
00357         format = get_ushort();
00358         if (is_unicode_mapping(e) && format == 4) {
00359             ++unicode_map_count;
00360             if (unicode_map_count == select_unicode)
00361                 goto read_unicode_mapping;
00362         }
00363         continue;
00364 read_unicode_mapping:
00365         length = get_ushort(); /* length of subtable */
00366         get_ushort(); /* skip the version number */
00367         segCount = get_ushort()/2;
00368         get_ushort(); /* skip searchRange */
00369         get_ushort(); /* skip entrySelector */
00370         get_ushort(); /* skip rangeShift */
00371         seg_tab = xtalloc(segCount, seg_entry);
00372         for (s = seg_tab; s - seg_tab < segCount; s++)
00373             s->endCode = get_ushort();
00374         get_ushort(); /* skip reversedPad */
00375         for (s = seg_tab; s - seg_tab < segCount; s++)
00376             s->startCode = get_ushort();
00377         for (s = seg_tab; s - seg_tab < segCount; s++)
00378             s->idDelta = get_ushort();
00379         for (s = seg_tab; s - seg_tab < segCount; s++)
00380             s->idRangeOffset = get_ushort();
00381         length -= 8*TTF_USHORT_SIZE + 4*segCount*TTF_USHORT_SIZE;
00382         n = length/TTF_USHORT_SIZE; /* number of glyphID's */
00383         glyphId = xtalloc(n, TTF_USHORT);
00384         for (i = 0; i < n; i++)
00385             glyphId[i] = get_ushort();
00386         for (s = seg_tab; s - seg_tab < segCount; s++) {
00387             for (i = s->startCode; i <= s->endCode; i++) {
00388                 if (i == 0xFFFF)
00389                     break;
00390                 if (s->idRangeOffset != 0xFFFF) {
00391                     if (s->idRangeOffset == 0)
00392                         index = (s->idDelta + i) & 0xFFFF;
00393                     else {
00394                         k = (i - s->startCode) + s->idRangeOffset/2 + 
00395                             (s - seg_tab) - segCount ;
00396                         assert(k >= 0 && k < n);
00397                         index = glyphId[k];
00398                         if (index != 0)
00399                             index = (index + s->idDelta) & 0xFFFF;
00400                     }
00401                     if (index < 0 || index >= nglyphs)
00402                         ttf_fail("cmap: glyph index out of range [0..%i)", nglyphs);
00403                     if (unicode_map[i] != NOGLYPH_ASSIGNED_YET)
00404                         ttf_fail("cmap: unicode %.4X is mapped to multiple glyphs", i);
00405                     if (unicode_map[i] == 0)
00406                         ttf_warn("unicode %.4X is mapped to glyph 0", i);
00407                     unicode_map[i] = index;
00408                     append_unicode(index, i);
00409                 }
00410             }
00411         }
00412         xfree(seg_tab);
00413         xfree(glyphId);
00414         break;
00415     }
00416     if (e - cmap_tab == ncmapsubtabs)
00417         ttf_fail("Invalid argument `-m %i': out of range [1..%i]",
00418                  select_unicode, unicode_map_count);
00419 }
00420 
00421 void read_font()
00422 {
00423     long i, j, k, l, n, m, platform_id, encoding_id;
00424     TTF_FWORD kern_value;
00425     char buf[1024], *p;
00426     dirtab_entry *pd;
00427     kern_entry *pk;
00428     mtx_entry *pm;
00429     ttf_skip(TTF_FIXED_SIZE);
00430     ntabs = get_ushort();
00431     ttf_skip(3*TTF_USHORT_SIZE);
00432     dir_tab = xtalloc(ntabs, dirtab_entry);
00433     for (pd = dir_tab; pd - dir_tab < ntabs; pd++) {
00434         pd->tag[0] = get_char();
00435         pd->tag[1] = get_char();
00436         pd->tag[2] = get_char();
00437         pd->tag[3] = get_char();
00438         ttf_skip(TTF_ULONG_SIZE);
00439         pd->offset = get_ulong();
00440         pd->length = get_ulong();
00441     }
00442     ttf_seek_tab("head", 2*TTF_FIXED_SIZE + 2*TTF_ULONG_SIZE + TTF_USHORT_SIZE);
00443     upem = get_ushort();
00444     ttf_skip(16);
00445     FontBBox1 = get_fword();
00446     FontBBox2 = get_fword();
00447     FontBBox3 = get_fword();
00448     FontBBox4 = get_fword();
00449     ttf_skip(TTF_USHORT_SIZE);
00450     ttf_skip(TTF_USHORT_SIZE + TTF_SHORT_SIZE);
00451     loca_format = get_short();
00452     ttf_seek_tab("maxp", TTF_FIXED_SIZE);
00453     nglyphs = get_ushort();
00454     mtx_tab = xtalloc(nglyphs + 1, mtx_entry);
00455     for (pm = mtx_tab; pm - mtx_tab < nglyphs + 1; pm++) {
00456         pm->name = NULL; /* notdef */
00457         pm->found = 0;
00458         pm->unicode_list = NULL;
00459     }
00460     ttf_seek_tab("hhea", TTF_FIXED_SIZE);
00461     Ascender = get_fword();
00462     Descender = get_fword();
00463     ttf_skip(TTF_FWORD_SIZE + TTF_UFWORD_SIZE + 3*TTF_FWORD_SIZE + 8*TTF_SHORT_SIZE);
00464     nhmtx = get_ushort();
00465     ttf_seek_tab("hmtx", 0);
00466     for (pm = mtx_tab; pm - mtx_tab < nhmtx; pm++) {
00467         pm->wx = get_ufword();
00468         ttf_skip(TTF_FWORD_SIZE);
00469     }
00470     i = pm[-1].wx;
00471     for (; pm - mtx_tab < nglyphs; pm++)
00472         pm->wx = i;
00473     ttf_seek_tab("post", 0);
00474     post_format = get_fixed();
00475     ItalicAngle = get_fixed();
00476     UnderlinePosition = get_fword();
00477     UnderlineThickness = get_fword();
00478     IsFixedPitch = get_ulong();
00479     ttf_skip(4*TTF_ULONG_SIZE);
00480     switch (post_format) {
00481     case 0x00010000:
00482         for (pm = mtx_tab; pm - mtx_tab < NMACGLYPHS; pm++)
00483             pm->name = mac_glyph_names[pm - mtx_tab];
00484         break;
00485     case 0x00020000:
00486         l = get_ushort(); /* some fonts have this value different from nglyphs */
00487         for (pm = mtx_tab; pm - mtx_tab < l; pm++)
00488             pm->index = get_ushort();
00489         if ((pd = name_lookup("post")) == NULL)
00490             ttf_fail("can't find table `post'");
00491         n = pd->length - (xftell(fontfile, cur_file_name) - pd->offset);
00492         ps_glyphs_buf = xtalloc(n + 1, char);
00493         for (m = 0, p = ps_glyphs_buf; p - ps_glyphs_buf < n;) {
00494             for (i = get_byte(); i > 0; i--)
00495                 *p++ = get_char();
00496             *p++ = 0;
00497             m++;
00498         }
00499         for (pm = mtx_tab; pm - mtx_tab < l; pm++) {
00500             if (pm->index < NMACGLYPHS)
00501                 pm->name = mac_glyph_names[pm->index];
00502             else {
00503                 k = pm->index - NMACGLYPHS;
00504                 if (k < m) {
00505                     for (p = ps_glyphs_buf; k > 0; k--)
00506                         p = (char *)strend(p) + 1;
00507                     pm->name = p;
00508                 }
00509                 else {
00510                     pm->name = NULL; /* index out of valid range, fix name to notdef */
00511                 }
00512             }
00513         }
00514         break;
00515     case 0x00030000:
00516         if (print_glyph == AS_NAME) {
00517             ttf_warn("no names available in `post' table, print glyph names as indices");
00518             print_glyph = AS_INDEX;
00519         }
00520         break;
00521     default:
00522         ttf_fail("unsupported format (%.8X) of `post' table", post_format);
00523     }
00524     ttf_seek_tab("loca", 0);
00525     for (pm = mtx_tab; pm - mtx_tab < nglyphs + 1; pm++)
00526         pm->offset = (loca_format == 1 ? get_ulong() : get_ushort() << 1);
00527     if ((pd = name_lookup("glyf")) == NULL)
00528         ttf_fail("can't find table `glyf'");
00529     for (n = pd->offset, pm = mtx_tab; pm - mtx_tab < nglyphs; pm++) {
00530         ttf_seek_off("glyf", n + pm->offset);
00531         ttf_skip(TTF_SHORT_SIZE);
00532         pm->bbox[0] = get_fword();
00533         pm->bbox[1] = get_fword();
00534         pm->bbox[2] = get_fword();
00535         pm->bbox[3] = get_fword();
00536     }
00537 
00538     ttf_seek_tab("name", 0);
00539     i = ftell(fontfile);
00540     get_ushort();           /* skip Format selector (=0) */
00541     n = get_ushort();       /* number of name records */
00542     j = get_ushort() + i;   /* start of string storage */
00543     i += 3*TTF_USHORT_SIZE; /* update the current offset */
00544     while (n-- > 0) {
00545         ttf_seek_off("name", i);
00546         platform_id = get_ushort();
00547         encoding_id = get_ushort();
00548         get_ushort(); /* skip language_id */
00549         k = get_ushort(); /* name_id */
00550         l = get_ushort(); /* string length */
00551         if ((platform_id == 1 && encoding_id == 0) &&
00552             (k == 0 || k == 1 || k == 4 || k == 5 || 
00553              k == 6)) {
00554             ttf_seek_off("name", j + get_ushort());
00555             for (p = buf; l-- > 0; p++)
00556                 *p = get_char();
00557             *p++ = 0;
00558             p = xstrdup(buf);
00559             switch (k) {
00560             case 0:  Notice = p; break;
00561             case 1:  FamilyName = p; break;
00562             case 4:  FullName = p; break;
00563             case 5:  Version = p; break;
00564             case 6:  FontName = p; break;
00565             }
00566             if (Notice != NULL && FamilyName != NULL && 
00567                 FullName != NULL && FontName != NULL && 
00568                 Version != NULL)
00569                 break;
00570         }
00571         i += 6*TTF_USHORT_SIZE;
00572     }
00573     if ((pd = name_lookup("PCLT")) != NULL) {
00574         ttf_seek_off("PCLT", pd->offset + TTF_FIXED_SIZE + TTF_ULONG_SIZE + TTF_USHORT_SIZE);
00575         XHeight = get_ushort();
00576         if (XHeight > FontBBox3) {
00577             ttf_warn("XHeight is too big (%i)\n"
00578                      "This is likely a font bug, so I discarded this parameter.", 
00579                      (int)get_ttf_funit(XHeight));
00580             XHeight = 0;
00581         }
00582         ttf_skip(2*TTF_USHORT_SIZE);
00583         CapHeight = get_ushort();
00584         if (CapHeight > FontBBox3) {
00585             ttf_warn("CapHeight is too big (%i)\n"
00586                      "This is likely a font bug, so I discarded this parameter.", 
00587                      (int)get_ttf_funit(CapHeight));
00588             CapHeight = 0;
00589         }
00590     }
00591     if ((pd = name_lookup("OS/2")) != NULL) {
00592         ttf_seek_off("OS/2", pd->offset + TTF_USHORT_SIZE + TTF_SHORT_SIZE);
00593         switch (get_ushort()) {
00594         case 100: Weight = xstrdup("Thin"); break;
00595         case 200: Weight = xstrdup("ExtraLight"); break;
00596         case 300: Weight = xstrdup("Light"); break;
00597         case 400: Weight = xstrdup("Normal"); break;
00598         case 500: Weight = xstrdup("Medium"); break;
00599         case 600: Weight = xstrdup("SemiBold"); break;
00600         case 700: Weight = xstrdup("Bold"); break;
00601         case 800: Weight = xstrdup("ExtraBold"); break;
00602         case 900: Weight = xstrdup("Black"); break;
00603         }
00604     }
00605     read_cmap();
00606     if ((pd = name_lookup("kern")) == NULL)
00607         return;
00608     kern_tab = xtalloc(nglyphs, kern_entry);
00609     for (pk = kern_tab; pk - kern_tab < nglyphs; pk++) {
00610         pk->next = NULL;
00611         pk->value = 0;
00612     }
00613     ttf_seek_off("kern", pd->offset + TTF_USHORT_SIZE);
00614     for (n = get_ushort(); n > 0; n--) {
00615         ttf_skip(2*TTF_USHORT_SIZE);
00616         k = get_ushort();
00617         if (!(k & 1) || (k & 2) || (k & 4))
00618             return;
00619         if (k >> 8 != 0) {
00620             ttf_warn("warning: only format 0 supported of `kern' \
00621                  subtables, others are ignored\n");
00622             continue;
00623         }
00624         k = get_ushort();
00625         ttf_skip(3*TTF_USHORT_SIZE);
00626         while (k-- > 0) {
00627             i = get_ushort();
00628             j = get_ushort();
00629             kern_value = get_fword();
00630             if (kern_value != 0) {
00631                 store_kern_value(i, j, kern_value);
00632                 nkernpairs++;
00633             }
00634         }
00635     }
00636 }
00637 
00638 int null_glyph(const char *s)
00639 {
00640     return (s == NULL || s == notdef);
00641     /*
00642         strcmp(s, ".null") == 0 ||
00643         strcmp(s, ".notdef") == 0 ||
00644         strcmp(s, "CR") == 0 ||
00645         strcmp(s, "nonmarkingreturn") == 0
00646     */
00647 }
00648 
00649 void print_glyph_name(FILE *f, long glyph_index, int convention)
00650 {
00651     unicode_entry *u;
00652     static char buf[1024];
00653     const char *n;
00654     assert(glyph_index >= 0 && glyph_index < nglyphs);
00655     n = mtx_tab[glyph_index].name;
00656     if (printing_enc && (n == notdef || glyph_index == 0)) {
00657         fputs(notdef, f);
00658         return;
00659     }
00660     switch (convention) {
00661     case AS_NAME:
00662         if (!null_glyph(n))
00663             fprintf(f, "%s", mtx_tab[glyph_index].name);
00664         else if (n == notdef && glyph_index == 0)
00665             fputs(notdef, f);
00666         else
00667             fprintf(f, "%s%i", GLYPH_PREFIX_INDEX, glyph_index);
00668         break;
00669     case AS_INDEX:
00670         fprintf(f, "%s%i", GLYPH_PREFIX_INDEX, glyph_index);
00671         break;
00672     case AS_UNICODE:
00673         u = mtx_tab[glyph_index].unicode_list;
00674         if (glyph_index == 0 || u == NULL)
00675             fprintf(f, "%s%i", GLYPH_PREFIX_INDEX, glyph_index);
00676         else {
00677             fprintf(f, "%s%.4X", GLYPH_PREFIX_UNICODE, u->code);
00678             if (u->next != NULL) {
00679                 *buf = 0;
00680                 for (; u != NULL; u = u->next) {
00681                     assert(strlen(buf) + strlen(GLYPH_PREFIX_UNICODE) + 4 < sizeof(buf));
00682                     sprintf(strend(buf), "%s%.4X ", GLYPH_PREFIX_UNICODE, u->code);
00683                 }
00684                 ttf_warn("glyph %i have multiple encodings: %s", 
00685                          glyph_index, buf);
00686             }
00687         }
00688         break;
00689     }
00690 }
00691 
00692 void print_char_metric(FILE *f, int charcode, long glyph_index)
00693 {
00694     assert(glyph_index >= 0 && glyph_index < nglyphs);
00695     fprintf(f, "C %i ; WX %i ; N ", (int) charcode, 
00696             (int)get_ttf_funit(mtx_tab[glyph_index].wx));
00697     print_glyph_name(f, glyph_index, print_glyph);
00698     fprintf(f, " ; B %i %i %i %i ;\n", 
00699             (int)get_ttf_funit(mtx_tab[glyph_index].bbox[0]),
00700             (int)get_ttf_funit(mtx_tab[glyph_index].bbox[1]),
00701             (int)get_ttf_funit(mtx_tab[glyph_index].bbox[2]),
00702             (int)get_ttf_funit(mtx_tab[glyph_index].bbox[3]));
00703 }
00704 
00705 void print_afm(char *date, char *fontname)
00706 {
00707     int i, ncharmetrics;
00708     mtx_entry *pm;
00709     short mtx_index[MAX_CHAR_CODE + 1], *idx;
00710     unsigned int index;
00711     char **pe;
00712     kern_entry *pk, *qk;
00713     unicode_entry *u;
00714     char buf[20];
00715     fputs("StartFontMetrics 2.0\n", outfile);
00716     fprintf(outfile, "Comment Converted at %s by ttf2afm from font file `%s'\n", date, fontname);
00717     print_str(FontName);
00718     print_str(FullName);
00719     print_str(FamilyName);
00720     print_str(Weight);
00721     fprintf(outfile, "ItalicAngle %i", (int)(ItalicAngle/0x10000));
00722     if (ItalicAngle%0x10000 > 0)
00723         fprintf(outfile, ".%i", (int)((ItalicAngle%0x10000)*1000)/0x10000);
00724     fputs("\n", outfile);
00725     fprintf(outfile, "IsFixedPitch %s\n", IsFixedPitch ? "true" : "false");
00726     fprintf(outfile, "FontBBox %i %i %i %i\n", 
00727             (int)get_ttf_funit(FontBBox1),
00728             (int)get_ttf_funit(FontBBox2),
00729             (int)get_ttf_funit(FontBBox3),
00730             (int)get_ttf_funit(FontBBox4));
00731     print_dimen(UnderlinePosition);
00732     print_dimen(UnderlineThickness);
00733     print_str(Version);
00734     print_str(Notice);
00735     fputs("EncodingScheme FontSpecific\n", outfile);
00736     print_dimen(CapHeight);
00737     print_dimen(XHeight);
00738     print_dimen(Ascender);
00739     print_dimen(Descender);
00740     ncharmetrics = nglyphs;
00741     if (use_ext_enc == 0) { /* external encoding vector not given */
00742         fprintf(outfile, "StartCharMetrics %u\n", ncharmetrics);
00743         for (pm = mtx_tab; pm - mtx_tab < nglyphs; pm++) {
00744             pm->found = 1;
00745             print_char_metric(outfile, -1, pm - mtx_tab);
00746         }
00747     }
00748     else { /* external encoding vector given */
00749         for (idx = mtx_index; idx - mtx_index <= MAX_CHAR_CODE; *idx++ = 0);
00750         for (pe = enc_names; pe - enc_names < names_count; pe++) {
00751             if (*pe == notdef)
00752                 continue;
00753             /* scan form `uniABCD' */
00754             if (sscanf(*pe, GLYPH_PREFIX_UNICODE "%X", &index) == 1) {
00755                 if (unicode_map[index] != NOGLYPH_ASSIGNED_YET) {
00756                     pm = mtx_tab + unicode_map[index];
00757                     pm->found = 1;
00758                 }
00759                 else
00760                     ttf_warn("`unicode %s%.4X' is not mapped to any glyph", 
00761                              GLYPH_PREFIX_UNICODE, index);
00762                 continue;
00763             }
00764             /* scan form `index123' */
00765             if (sscanf(*pe, GLYPH_PREFIX_INDEX "%u", &index) == 1) {
00766                 if (index >= nglyphs)
00767                     ttf_fail("`%s' out of valid range [0..%i)",
00768                          *pe, nglyphs);
00769                 pm = mtx_tab + index;
00770                 pm->found = 1;
00771                 continue;
00772             }
00773             for (pm = mtx_tab; pm - mtx_tab < nglyphs; pm++)
00774                 if (pm->name != NULL && strcmp(*pe, pm->name) == 0)
00775                     break; 
00776             if (pm - mtx_tab < nglyphs) {
00777                 mtx_index[pe - enc_names] = pm - mtx_tab;
00778                 pm->found = 1;
00779                 continue;
00780             }
00781             else
00782                 ttf_warn("glyph `%s' not found", *pe);
00783         }
00784         fprintf(outfile, "StartCharMetrics %u\n", ncharmetrics);
00785         for (idx = mtx_index; idx - mtx_index <= MAX_CHAR_CODE; idx++) {
00786             if (*idx != 0 && mtx_tab[*idx].found == 1)
00787                 print_char_metric(outfile, idx - mtx_index, *idx);
00788         }
00789         for (pm = mtx_tab; pm - mtx_tab < nglyphs; pm++) {
00790             if (pm->found == 0)
00791                 print_char_metric(outfile, -1, pm - mtx_tab);
00792         }
00793     }
00794 end_metrics:
00795     fputs("EndCharMetrics\n", outfile);
00796     if (nkernpairs == 0)
00797         goto end_kerns;
00798     fprintf(outfile, "StartKernData\nStartKernPairs %i\n", nkernpairs);
00799     for (pk = kern_tab; pk - kern_tab < nglyphs; pk++)
00800         for (qk = pk; qk != NULL; qk = qk->next)
00801             if (qk->value != 0) {
00802                 fputs("KPX ", outfile);
00803                 print_glyph_name(outfile, pk - kern_tab, print_glyph);
00804                 fputs(" ", outfile);
00805                 print_glyph_name(outfile, qk->adjacent, print_glyph);
00806                 fprintf(outfile, " %i\n", get_ttf_funit(qk->value));
00807             }
00808     fputs("EndKernPairs\nEndKernData\n", outfile);
00809 end_kerns:
00810     fputs("EndFontMetrics\n", outfile);
00811 }
00812 
00813 void print_encoding(char *fontname)
00814 {
00815     long int i, k, first_code, length, last_sep;
00816     FILE *file;
00817     TTF_USHORT format;
00818     char *enc_name, *end_enc_name;
00819     cmap_entry *e;
00820     const char *n;
00821     printing_enc = 1;
00822     enc_name = xtalloc(strlen(bname) + 20, char);
00823     strcpy(enc_name, bname);
00824     end_enc_name = strend(enc_name);
00825     for (e = cmap_tab; e - cmap_tab < ncmapsubtabs; e++) {
00826         ttf_seek_off("cmap", cmap_offset + e->offset);
00827         format = get_ushort();
00828         if (format != 0 && format != 4 && format != 6) {
00829             ttf_warn("format %i of encoding subtable unsupported", (int)format);
00830             continue;
00831         }
00832         sprintf(end_enc_name, ".e%i%i", 
00833                 (int)e->platform_id, (int)e->encoding_id);
00834         if ((file = xfopen(enc_name, FOPEN_W_MODE)) == NULL)
00835             ttf_fail("cannot open file for writing (%s)\n", enc_name);
00836         fprintf(file, "%% Encoding table from font file %s\n", fontname);
00837         fprintf(file, "%% Platform ID %i", (int)e->platform_id);
00838         switch (e->platform_id) {
00839         case 0:  fprintf(file, " (Apple Unicode)"); break;
00840         case 1:  fprintf(file, " (Macintosh)"); break;
00841         case 2:  fprintf(file, " (ISO)"); break;
00842         case 3:  fprintf(file, " (Microsoft)"); break;
00843         }
00844         fprintf(file, "\n");
00845         fprintf(file, "%% Encoding ID %i", (int)e->encoding_id);
00846         if (e->platform_id == 1 &&  e->encoding_id == 0)
00847             fprintf(file, " (Roman)");
00848         if (e->platform_id == 3)
00849             switch (e->encoding_id) {
00850             case 0:  fprintf(file, " (Symbol)"); break;
00851             case 1:  fprintf(file, " (Unicode)"); break;
00852             }
00853         fprintf(file, "\n");
00854         fprintf(file, "%% Format %i", (int)(format));
00855         switch (format) {
00856         case 0:  fprintf(file, " (byte encoding table)"); break;
00857         case 4:  fprintf(file, " (segment mapping to delta values)"); break;
00858         case 6:  fprintf(file, " (trimmed table mapping)"); break;
00859         }
00860         fprintf(file, "\n");
00861         fprintf(file, "/Encoding%i [\n", (int)(e - cmap_tab + 1));
00862         switch (format) {
00863         case 0:
00864             get_ushort(); /* skip length */
00865             get_ushort(); /* skip version number */
00866             for (i = 0; i <= MAX_CHAR_CODE; i++) {
00867                 fputs("/", file);
00868                 print_glyph_name(file, get_byte(), print_glyph);
00869                 fputs("\n", file);
00870             }
00871             break;
00872         case 4:
00873             for (i = 0; i < nglyphs; ++i) {
00874                 fprintf(file, "%% Glyph %i -> ", i);
00875                 print_glyph_name(file, i, AS_UNICODE);
00876                 fputs("\n", file);
00877             }
00878             break;
00879         case 6:
00880             get_ushort(); /* skip table length */
00881             get_ushort(); /* skip version number */
00882             first_code = get_ushort(); /* first character code */
00883             for (i = 0; i < first_code; ++i)
00884                 fprintf(file, "/%s\n", notdef);
00885             length = get_ushort(); /* number of character codes */
00886             for (i = first_code; i < first_code + length; i++) {
00887                 k = get_ushort();
00888                 if (i > MAX_CHAR_CODE)
00889                     fputs("% ", file);
00890                 fputs("/", file);
00891                 print_glyph_name(file, k, print_glyph);
00892                 fputs("\n", file);
00893             }
00894             for (i =  first_code + length; i <= MAX_CHAR_CODE; i++)
00895                 fprintf(file, "/%s\n", notdef);
00896             break;
00897         default:
00898             ttf_warn("format %i of encoding subtable unsupported", (int)format);
00899         }
00900         fprintf(file, "] def\n");
00901     }
00902     xfree(enc_name);
00903 }
00904 
00905 void usage()
00906 {
00907     cur_file_name = NULL;
00908     fprintf(stderr,
00909         "Usage: ttf2afm [-i|-u|-c|-v] [-e enc] [-o filename] [-m NUM] fontfile\n"
00910         "    -i:          force printing glyph names in form 'index123'\n"
00911         "    -u:          force printing glyph names in form 'uniABCD'\n"
00912         "    -c:          print encoding tables to `basename.e<platformID><encodingID>'\n"
00913         "    -v:          print version\n"
00914         "    -e enc:      encode the AFM output using encoding vector from `enc'\n"
00915         "    -o filename: write output to file `filename' instead of stdout\n"
00916         "    -m NUM:      select unicode mapping (default = 1, ie the first)\n"
00917         "    fontfile:    the TrueType fontfile\n"
00918         "\nPlease send bug reports or feature requests to <pdftex@tug.org>\n"
00919     );
00920     _exit(-1);
00921 }
00922 
00923 int main(int argc, char **argv)
00924 {
00925     char date[128], *s, *buf = NULL;
00926     time_t t = time(&t);
00927     int c;
00928     kpse_set_progname(argv[0]);
00929     kpse_init_prog("ttf2afm", 0, 0, 0) ;
00930     while ((c = getopt(argc, argv, "iucve:o:m:")) != -1)
00931         switch (c) {
00932         case 'i':
00933             print_glyph = AS_INDEX;
00934             break;
00935         case 'u':
00936             print_glyph = AS_UNICODE;
00937             break;
00938         case 'c':
00939             print_cmap = 1;
00940             break;
00941         case 'e':
00942             cur_file_name = optarg;
00943             read_encoding(cur_file_name);
00944             use_ext_enc = 1;
00945             break;
00946         case 'o':
00947             cur_file_name = optarg;
00948             outfile = xfopen(cur_file_name, FOPEN_W_MODE);
00949             if (outfile == NULL)
00950                 ttf_fail("cannot open file for writing");
00951             break;
00952         case 'm':
00953             select_unicode = atoi(optarg);
00954             break;
00955         case 'v':
00956             fprintf(stderr, 
00957                     "ttf2afm version " VERSION "\n"
00958                     "Copyright (C) 1997-2005 Han The Thanh.\n"
00959                     "There is NO warranty.  Redistribution of this software is\n"
00960                     "covered by the terms of both the pdfTeX copyright and\n"
00961                     "the GNU General Public License.\n"
00962                     "For more information about these matters, see the files\n"
00963                     "named COPYING and the pdfTeX source.\n"
00964                     "Primary author of ttf2afm: Han The Thanh.\n"
00965                    );
00966             _exit(0);
00967         default:
00968             usage();
00969         }
00970     if (argc - optind != 1)
00971         usage();
00972     sprintf(date, "%s\n", ctime(&t));
00973     *(char *)strchr(date, '\n') = 0;
00974     cur_file_name = argv[optind];
00975     if (print_cmap) {
00976         buf = xstrdup(cur_file_name);
00977         bname = xbasename(buf);
00978         if ((s = rindex(bname, '.')) != NULL)
00979             *s = 0;
00980     }
00981     if ((fontfile = kpse_open_file(cur_file_name, kpse_truetype_format)) == NULL)
00982         ttf_fail("can't open font file for reading");
00983     read_font();
00984     if (outfile == NULL)
00985         outfile = stdout;
00986     print_afm(date, cur_file_name);
00987     if (print_cmap)
00988         print_encoding(cur_file_name);
00989     xfree(FontName);
00990     xfree(FullName);
00991     xfree(FamilyName);
00992     xfree(Notice);
00993     xfree(Version);
00994     xfree(Weight);
00995     xfree(buf);
00996     free_tabs();
00997     xfclose(fontfile, cur_file_name);
00998     return 0;
00999 }