#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include "ttf2tfm.h"
#include "newobj.h"
#include "ttfenc.h"
#include "ligkern.h"
#include "texenc.h"
#include "ttfaux.h"
#include "tfmaux.h"
#include "vplaux.h"
#include "errormsg.h"
#include "filesrch.h"
#include "parse.h"
#include "subfont.h"
char ident[] = "ttf2tfm version 1.3";
char progname[] = "ttf2tfm";
static char makevpl;
static Boolean pedantic;
static Boolean quiet;
static Boolean forceoctal;
static void
handlereencoding(Font *fnt)
{
int i;
ttfinfo *ti;
char *p;
if (fnt->inencname)
{
fnt->inencoding = readencoding(&(fnt->inencname), fnt, True);
for (i = 0; i <= 0xFF; i++)
if (NULL != (ti = fnt->inencptrs[i]))
{
ti->incode = -1;
fnt->inencptrs[i] = NULL;
}
for (i = 0; i <= 0xFF; i++)
{
p = fnt->inencoding->vec[i];
if (p && *p)
{
if ((ti = findadobe(p, fnt->charlist)))
{
if (ti->incode >= 0)
{
warning("Character `%s' encoded twice in input encoding\n"
" (positions %x and %x; the latter is ignored).",
p, ti->incode, i);
fnt->inencoding->vec[i] = ".notdef";
continue;
}
if (ti->charcode >= 0)
{
ti->incode = i;
fnt->inencptrs[i] = ti;
}
}
else
{
warning("Cannot find character `%s'\n"
" specified in input encoding.", p);
}
}
}
fnt->codingscheme = fnt->inencoding->name;
}
if (!quiet)
{
if (fnt->inencname)
printf("\nUsing %s as input encoding.\n", fnt->inencname);
else
{
printf(
"\nUsing the first 256 glyphs in the following input encoding:\n\n");
for (i = 0; i <= 0xFF; i++)
{
if ((ti = fnt->inencptrs[i]))
printf(" 0x%02x %s\n", i, ti->adobename);
}
printf("\n");
}
}
if (fnt->outencname)
fnt->outencoding = readencoding(&(fnt->outencname), fnt, False);
else
fnt->outencoding = readencoding(NULL, fnt, False);
}
static void
assignchars(Font *fnt)
{
register char **p;
register int i, j, k;
register ttfinfo *ti;
int nextfree = 0x80;
for (i = 0, p = fnt->outencoding->vec; i <= 0xFF; i++, p++)
if ((ti = findmappedadobe(*p, fnt->inencptrs)))
{
if (ti->outcode >= 0)
fnt->nextout[i] = ti->outcode;
ti->outcode = i;
fnt->outencptrs[i] = ti;
}
else if (strcmp(*p, ".notdef") != 0)
warning("Cannot map character `%s'\n"
" specified in output encoding.", *p);
if (pedantic)
goto end;
for (i = 0; i <= 0xFF; i++)
if ((ti = fnt->inencptrs[i]) &&
ti->charcode >= 0 && ti->charcode <= 0xFF &&
ti->outcode < 0 && fnt->outencptrs[ti->charcode] == NULL)
{
ti->outcode = ti->charcode;
fnt->outencptrs[ti->charcode] = ti;
}
for (i = 0; i <= 0xFF; i++)
if ((ti = fnt->inencptrs[i]) && ti->outcode < 0)
{
while (fnt->outencptrs[nextfree])
{
nextfree = (nextfree + 1) & 0xFF;
if (nextfree == 0x80)
goto finishup;
}
ti->outcode = nextfree;
fnt->outencptrs[nextfree] = ti;
}
finishup:
for (i = 0; i <= 0xFF; i++)
if ((ti = fnt->inencptrs[i]) && ti->outcode >= 0)
{
k = -1;
while (fnt->nextout[ti->outcode] >= 0)
{
j = fnt->nextout[ti->outcode];
fnt->nextout[ti->outcode] = k;
k = ti->outcode;
ti->outcode = j;
}
fnt->nextout[ti->outcode] = k;
}
end:
if (!quiet)
{
printf("\nUsing the following output encoding:\n\n");
for (i = 0; i <= 0xFF; i++)
{
if ((ti = fnt->outencptrs[i]))
printf(" 0x%02x %s\n", i, ti->adobename);
}
printf("\n");
}
}
#define VERSION "\
Copyright (C) 1997-1999 Frederic Loyer and Werner Lemberg.\n\
There is NO warranty. You may redistribute this software\n\
under the terms of the GNU General Public License\n\
and the Dvips copyright.\n\
\n\
For more information about these matters, see the files\n\
named COPYING and ttf2tfm.c.\n\
\n\
Primary authors of ttf2tfm: F. Loyer and W. Lemberg.\n\
\n\
ttf2tfm is based on afm2tfm from T. Rokicki\n\
and the FreeType project from\n\
David Turner, Robert Wilhelm, and Werner Lemberg.\n\
"
static void
version(void)
{
fputs(ident, stdout);
fprintf(stdout, " (%s)\n", TeX_search_version());
fputs(VERSION, stdout);
exit(0);
}
#define USAGE "\
Convert a TrueType font table to TeX's font metric format.\n\
\n\
-c REAL use REAL for height of small caps made with -V [0.8]\n\
-e REAL widen (extend) characters by a factor of REAL [1.0]\n\
-E INT select INT as the TTF encoding ID [1]\n\
-f INT select INT as the font index in a TTC [0]\n\
-l create 1st/2nd byte ligatures in subfonts\n\
-n use PS names of TrueType font\n\
-N use only PS names and no cmap\n\
-O use octal for all character codes in the vpl file\n\
-p ENCFILE[.enc] read ENCFILE for the TTF->raw TeX mapping\n\
-P INT select INT as the TTF platform ID [3]\n\
-q suppress informational output\n\
-r OLDNAME NEWNAME replace glyph name OLDNAME with NEWNAME\n\
-R RPLFILE[.rpl] read RPLFILE containing glyph replacement names\n\
-s REAL oblique (slant) characters by REAL, usually <<1 [0.0]\n\
-t ENCFILE[.enc] read ENCFILE for the encoding of the vpl file\n\
-T ENCFILE[.enc] equivalent to -p ENCFILE -t ENCFILE\n\
-u output only characters from encodings, nothing extra\n\
-v FILE[.vpl] make a VPL file for conversion to VF\n\
-V SCFILE[.vpl] like -v, but synthesize smallcaps as lowercase\n\
-x rotate subfont glyphs by 90 degrees\n\
-y REAL move rotated glyphs down by a factor of REAL [0.25]\n\
--help print this message and exit\n\
--version print version number and exit\n\
"
static void
usage(void)
{
fputs("Usage: ttf2tfm FILE[.ttf|.ttc] [OPTION]... [FILE[.tfm]]\n", stdout);
fputs(USAGE, stdout);
exit(0);
}
static void
handle_options(int argc, char *argv[], Font *fnt)
{
register int lastext;
register int i;
size_t l;
int arginc;
char *temp;
char c;
char *vpl_name = NULL;
Boolean have_capheight = 0;
Boolean have_sfd = 0;
int sfd_begin, postfix_begin;
int base_name;
stringlist* sl;
for (i = 1; i < argc; i++)
if (argv[i][0] == '-' && argv[i][1] == 'q')
quiet = True;
if (!quiet)
printf("This is %s\n", ident);
#if defined(MSDOS) || defined(OS2) || defined(ATARIST)
fnt->titlebuf = (char *)mymalloc(strlen(progname) + strlen(argv[1]) +
1 + 1);
sprintf(fnt->titlebuf, "%s %s", progname, argv[1]);
#else
fnt->titlebuf = (char *)mymalloc(strlen(argv[0]) + strlen(argv[1]) +
1 + 1);
sprintf(fnt->titlebuf, "%s %s", argv[0], argv[1]);
#endif
fnt->ttfname = newstring(argv[1]);
while (argc > 2 && *argv[2] == '-')
{
arginc = 2;
i = argv[2][1];
switch (i)
{
case 'v':
makevpl = 1;
if (argc <= 3)
oops("Missing parameter for -v option.");
if (vpl_name)
free(vpl_name);
vpl_name = newstring(argv[3]);
handle_extension(&vpl_name, ".vpl");
break;
case 'V':
makevpl = 2;
if (argc <= 3)
oops("Missing parameter for -V option.");
if (vpl_name)
free(vpl_name);
vpl_name = newstring(argv[3]);
handle_extension(&vpl_name, ".vpl");
break;
case 'f':
if (argc <= 3)
oops("Missing parameter for -f option.");
if (sscanf(argv[3], "%lu", &(fnt->fontindex)) == 0)
oops("Invalid font index.");
fnt->fontindexparam = argv[3];
break;
case 'E':
if (argc <= 3)
oops("Missing parameter for -E option.");
if (sscanf(argv[3], "%hu", &(fnt->eid)) == 0)
oops("Invalid encoding ID.");
fnt->eidparam = argv[3];
break;
case 'P':
if (argc <= 3)
oops("Missing parameter for -P option.");
if (sscanf(argv[3], "%hu", &(fnt->pid)) == 0)
oops("Invalid platform ID.");
fnt->pidparam = argv[3];
break;
case 'e':
if (argc <= 3)
oops("Missing parameter for -e option.");
if (sscanf(argv[3], "%f", &(fnt->efactor)) == 0 || fnt->efactor < 0.01)
oops("Bad extension factor.");
fnt->efactorparam = argv[3];
break;
case 'c':
if (argc <= 3)
oops("Missing parameter for -c option.");
have_capheight = True;
if (sscanf(argv[3], "%f", &(fnt->capheight)) == 0)
fnt->capheight = 0;
break;
case 's':
if (argc <= 3)
oops("Missing parameter for -s option.");
if (sscanf(argv[3], "%f", &(fnt->slant)) == 0)
oops("Bad slant parameter.");
fnt->slantparam = argv[3];
break;
case 'p':
if (argc <= 3)
oops("Missing parameter for -p option.");
if (fnt->inencname)
free(fnt->inencname);
fnt->inencname = newstring(argv[3]);
break;
case 'T':
if (argc <= 3)
oops("Missing parameter for -T option.");
if (fnt->inencname)
free(fnt->inencname);
if (fnt->outencname)
free(fnt->outencname);
fnt->inencname = newstring(argv[3]);
fnt->outencname = newstring(argv[3]);
break;
case 't':
if (argc <= 3)
oops("Missing parameter for -T option.");
if (fnt->outencname)
free(fnt->outencname);
fnt->outencname = newstring(argv[3]);
break;
case 'r':
if (argc <= 4)
oops("Not enough parameters for -r option.");
sl = newstringlist();
sl->old_name = newstring(argv[3]);
sl->new_name = newstring(argv[4]);
sl->single_replacement = True;
sl->next = fnt->replacements;
fnt->replacements = sl;
arginc = 3;
break;
case 'R':
if (argc <= 3)
oops("Missing parameter for -R option.");
if (fnt->replacementname)
free(fnt->replacementname);
fnt->replacementname = newstring(argv[3]);
break;
case 'y':
if (argc <= 3)
oops("Missing parameter for -y option.");
if (sscanf(argv[3], "%f", &(fnt->y_offset)) == 0)
oops("Invalid y-offset.");
fnt->y_offsetparam = argv[3];
break;
case 'O':
forceoctal = True;
arginc = 1;
break;
case 'n':
fnt->PSnames = Yes;
arginc = 1;
break;
case 'N':
fnt->PSnames = Only;
arginc = 1;
break;
case 'u':
pedantic = True;
arginc = 1;
break;
case 'q':
quiet = True;
arginc = 1;
break;
case 'l':
fnt->subfont_ligs = True;
arginc = 1;
break;
case 'x':
fnt->rotate = True;
arginc = 1;
break;
default:
if (argc <= 3 || argv[3][0] == '-')
{
warning("Unknown option `%s' will be ignored.\n", argv[2]);
arginc = 1;
}
else
warning("Unknown option `%s %s' will be ignored.\n",
argv[2], argv[3]);
}
for (i = 0; i < arginc; i++)
{
l = strlen(fnt->titlebuf);
fnt->titlebuf = (char *)myrealloc((void *)fnt->titlebuf,
l + strlen(argv[2]) + 1 + 1);
sprintf(fnt->titlebuf + strlen(fnt->titlebuf), " %s", argv[2]);
argv++;
argc--;
}
}
get_replacements(fnt);
if (argc > 3 || (argc == 3 && *argv[2] == '-'))
oops("Need at most two non-option arguments.");
if (argc == 2)
temp = newstring(fnt->ttfname);
else
{
temp = newstring(argv[2]);
l = strlen(fnt->titlebuf);
fnt->titlebuf = (char *)myrealloc((void *)fnt->titlebuf,
l + strlen(argv[2]) + 1 + 1);
sprintf(fnt->titlebuf + strlen(fnt->titlebuf), " %s", argv[2]);
}
handle_sfd(temp, &sfd_begin, &postfix_begin);
if (sfd_begin > -1)
{
have_sfd = True;
i = sfd_begin - 2;
}
else
i = strlen(temp) - 1;
for (; i >= 0; i--)
if (temp[i] == '/' || temp[i] == ':' || temp[i] == '\\')
break;
base_name = i + 1;
if (base_name > 0)
{
c = temp[base_name];
temp[base_name] = '\0';
fnt->tfm_path = newstring(temp);
temp[base_name] = c;
}
if (have_sfd)
{
if (temp[base_name])
fnt->outname = newstring(temp + base_name);
fnt->sfdname = newstring(temp + sfd_begin);
}
else
postfix_begin = base_name;
lastext = -1;
for (i = postfix_begin; temp[i]; i++)
if (temp[i] == '.')
lastext = i;
if (argc == 2 && lastext >= 0)
{
temp[lastext] = '\0';
lastext = -1;
}
if (lastext == -1)
fnt->tfm_ext = newstring(".tfm");
else
{
fnt->tfm_ext = newstring(temp + lastext);
temp[lastext] = '\0';
}
if (have_sfd)
{
if (temp[postfix_begin])
fnt->outname_postfix = newstring(temp + postfix_begin);
}
else
{
if (temp[base_name])
fnt->outname = newstring(temp + base_name);
else
oops("Invalid tfm file name.");
}
if (have_sfd)
{
if (makevpl)
{
warning("Ignoring `-v' and `-V' switches for subfonts.");
makevpl = 0;
}
if (have_capheight)
warning("Ignoring `-c' switch for subfonts.");
if (fnt->inencname || fnt->outencname)
{
warning("Ignoring `-p', `-t', and `-T' switches for subfonts.");
fnt->inencname = NULL;
fnt->outencname = NULL;
}
if (fnt->y_offsetparam && !fnt->rotate)
warning("Ignoring `-y' switch for non-rotated subfonts.");
if (fnt->PSnames)
{
warning("Ignoring `-n' or '-N' switch for subfonts.");
fnt->PSnames = No;
}
init_sfd(fnt, True);
}
else
{
if (have_capheight && fnt->capheight < 0.01)
oops("Bad small caps height.");
if (vpl_name)
if ((fnt->vplout = fopen(vpl_name, "wt")) == NULL)
oops("Cannot open vpl output file.");
if (fnt->subfont_ligs)
{
warning("Ignoring `-l' switch for non-subfont.");
fnt->subfont_ligs = False;
}
if (fnt->rotate)
{
warning("Ignoring `-x' switch for non-subfont.");
fnt->rotate = False;
}
if (fnt->y_offsetparam)
warning("Ignoring `-y' switch for non-subfont.");
}
if (fnt->PSnames == Only)
{
if (fnt->pidparam || fnt->eidparam)
{
warning("Ignoring `-P' and `-E' options if `-N' switch is selected.");
fnt->pidparam = NULL;
fnt->eidparam = NULL;
}
}
if (vpl_name)
free(vpl_name);
free(temp);
}
static void
consttfonts(Font *fnt)
{
if (!quiet)
printf("\n");
if (fnt->outname)
printf("%s", fnt->outname);
if (fnt->sfdname)
printf("@%s@", fnt->sfdname);
if (fnt->outname_postfix)
printf("%s", fnt->outname_postfix);
printf(" %s", fnt->ttfname);
if (fnt->slantparam || fnt->efactorparam ||
fnt->inencname ||
fnt->pidparam || fnt->eidparam ||
fnt->fontindexparam ||
fnt->replacements ||
fnt->replacementname ||
fnt->PSnames ||
fnt->rotate || fnt->y_offsetparam)
{
if (fnt->slantparam)
printf(" Slant=%s", fnt->slantparam);
if (fnt->efactorparam)
printf(" Extend=%s", fnt->efactorparam);
if (fnt->inencname)
printf(" Encoding=%s", fnt->inencname);
if (fnt->pidparam)
printf(" Pid=%s", fnt->pidparam);
if (fnt->eidparam)
printf(" Eid=%s", fnt->eidparam);
if (fnt->fontindexparam)
printf(" Fontindex=%s", fnt->fontindexparam);
if (fnt->PSnames)
printf(" PS=%s", fnt->PSnames == Yes ? "Yes" : "Only");
if (fnt->rotate)
printf(" Rotate=Yes");
if (fnt->y_offsetparam)
printf(" Y-Offset=%s", fnt->y_offsetparam);
if (fnt->replacementname && fnt->inencoding)
printf(" Replacement=%s", fnt->replacementname);
if (fnt->replacements && fnt->inencoding)
{
stringlist *sl;
for (sl = fnt->replacements; sl; sl = sl->next)
if (sl->single_replacement)
printf(" %s=%s", sl->old_name, sl->new_name);
}
}
printf("\n");
}
int
main(int argc, char *argv[])
{
Font font;
ttfinfo *ti;
init_font_structure(&font);
TeX_search_init(argv[0], "ttf2tfm", "TTF2TFM");
if (argc == 1)
{
fputs("ttf2tfm: Need at least one file argument.\n", stderr);
fputs("Try `ttf2tfm --help' for more information.\n", stderr);
exit(1);
}
if (argc == 2)
{
if (strcmp(argv[1], "--help") == 0)
usage();
else if (strcmp(argv[1], "--version") == 0)
version();
}
handle_options(argc, argv, &font);
if (font.sfdname)
{
while (get_sfd(&font))
{
char *temp;
int i, start, end, len;
get_tfm_fullname(&font);
temp = newstring(font.sfdname);
len = strlen(temp);
start = 0;
for (i = len - 1; i >= 0; i--)
if (temp[i] == '/' || temp[i] == ':' || temp[i] == '\\')
{
start = i + 1;
break;
}
end = len;
for (i = len - 1; i >= 0; i--)
if (temp[i] == '.')
{
end = i;
break;
}
temp[end] = '\0';
font.codingscheme = (char *)mymalloc(strlen(temp + start) + 4 + 1);
sprintf(font.codingscheme, "CJK-%s", temp + start);
free(temp);
readttf(&font, quiet, True);
if (font.replacements)
warning("Replacement glyphs will be ignored.");
if (NULL != (ti = findadobe("space", font.charlist)))
font.fontspace = ti->width;
else if (NULL != (ti = findadobe(".c0x20", font.charlist)))
font.fontspace = ti->width;
else
font.fontspace = transform(500, 0, font.efactor, font.slant);
if (buildtfm(&font))
writetfm(&font);
}
close_sfd();
}
else
{
get_tfm_fullname(&font);
readttf(&font, quiet, False);
replace_glyphs(&font);
if (NULL != (ti = findadobe("space", font.charlist)))
font.fontspace = ti->width;
else if (NULL != (ti = findadobe(".c0x20", font.charlist)))
font.fontspace = ti->width;
else
font.fontspace = transform(500, 0, font.efactor, font.slant);
handlereencoding(&font);
buildtfm(&font);
writetfm(&font);
}
if (makevpl)
{
assignchars(&font);
if (makevpl > 1)
upmap(&font);
writevpl(&font, makevpl, forceoctal);
fclose(font.vplout);
}
consttfonts(&font);
exit(0);
return 0;
}