#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#ifdef TM_IN_SYS_TIME
#include <sys/time.h>
#endif
#include <ctype.h>
#include "freetype.h"
#include "extend/ftxpost.h"
char rcsid[] = "Id: ttf2pfb.c,v 1.13 1999/08/20 13:14:26 werner Exp $";
#define PID_UNICODE 3
#define EID_UNICODE 1
#define PID_SJIS 3
#define EID_SJIS 2
#define PID_GB 3
#define EID_GB 3
#define PID_BIG5 3
#define EID_BIG5 4
#define PID_KS 3
#define EID_KS 5
#define PID_JOHAB 3
#define EID_JOHAB 6
#ifndef DEFAULT_PLATFORM_ID
#define DEFAULT_PLATFORM_ID PID_UNICODE
#endif
#ifndef DEFAULT_ENCODING_ID
#define DEFAULT_ENCODING_ID EID_UNICODE
#endif
typedef enum enc_type_
{
GB = 1, Big5, JIS, KS, Johab, SJIS, X
} enc_type;
enc_type force_enc = 0;
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef FAILURE
#define FAILURE -1
#endif
#define LINELEN 40
#define NAMELEN 80
int verbose = FALSE;
int compact = FALSE;
int keep = FALSE;
int mapping = FALSE;
float fontShift = 0;
#ifndef UShort
typedef unsigned short UShort;
#endif
#ifndef UChar
typedef unsigned char UChar;
#endif
#define TT_Flag_On_Curve 1
int pid = DEFAULT_PLATFORM_ID;
int eid = DEFAULT_ENCODING_ID;
char* prog;
#define Fputs(_string_) fprintf(out, "%s\n", _string_)
TT_F26Dot6 lastpsx, lastpsy;
#define Coord(x) (int)(x)
#define PS_LastPt(x, y) lastpsx = x; lastpsy = y
#define PS_Moveto(x, y) \
fprintf(out, "%d %d rmoveto\n", \
Coord(x - lastpsx), Coord(y - lastpsy)); \
PS_LastPt(x, y)
#define PS_Lineto(x, y) \
fprintf(out, "%d %d rlineto\n", \
Coord(x - lastpsx), Coord(y - lastpsy)); \
PS_LastPt(x, y)
TT_Engine engine;
TT_Face face;
TT_Instance instance;
TT_Glyph glyph;
TT_CharMap cmap;
TT_Error error;
TT_Post post;
TT_Outline outline;
TT_Glyph_Metrics metrics;
TT_Face_Properties properties;
typedef struct _EVHigh
{
UShort start, end;
} EVHigh;
typedef struct _EVLow
{
UChar start, end;
} EVLow;
typedef struct _EVcRange
{
EVHigh high;
UShort numLowRanges;
EVLow* low;
} EVcRange;
typedef struct _EncVec
{
UShort numCodeRanges;
EVcRange* codeRange;
} EncVec;
EncVec* eVecMap[5][10];
EncVec* eVecMap_force[10];
void
mesg(const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
vfprintf(stderr, msg, ap);
va_end(ap);
}
void
Usage(int eval)
{
#ifdef DEBUG
mesg("Usage: %s [-h][-v][-c][-k][-m][-d charcode][-l][-ng][-nc]\n", prog);
#else
mesg("Usage: %s [-h][-v][-c][-k][-m]\n", prog);
#endif
mesg("\t[-pid id] [-eid id] [-force enc] [-enc file]\n");
mesg("\t[-plane pl] [-f fname] [-uid id] [-s shift]\n");
mesg("\t[-o output] [-ttf font.ttf | font.ttf]\n");
mesg("-h\t\tThis message.\n");
mesg("-v\t\tPrint messages during conversion.\n");
mesg("-c\t\tCompact font");
mesg(" (256 chars per font; useful for the CJK package).\n");
mesg("-k\t\tKeep output file in case of error.\n");
mesg("-m\t\tUse encoding file as mapping file.\n");
#ifdef DEBUG
mesg("-d charcode\tDebug CharString for the given character code.\n");
mesg("-l\t\tDisplay point labels.\n");
mesg("-ng\t\tDo not show glyph outline.\n");
mesg("-nc\t\tDo not show control paths.\n");
#endif
mesg("-pid id\t\tSet the platform ID [%d].\n", DEFAULT_PLATFORM_ID);
mesg("-eid id\t\tSet the encoding ID [%d].\n", DEFAULT_ENCODING_ID);
mesg("\t\t(Use a strange pid,eid pair to list all possible pid,eid)\n");
mesg("-force enc\tForce a certain encoding [none].\n");
mesg("\t\t(Possible values are `GB', `JIS', `KS', `SJIS', and `X').\n");
mesg("-enc file\tFile contains code ranges [none].\n");
mesg("-plane pl\tA single font plane [0x0].\n");
mesg("-f fname\tFont name [UNKNOWN].\n");
mesg("-uid id\t\tUnique font ID, for private fonts 4000000-4999999 [4999999].\n");
mesg("-s shift\tY-offset factor [%5.3f].\n", fontShift);
mesg("-o outfile\tSet the output filename [stdout].\n");
mesg("-ttf ttfpath\tThe TTF font pathname.\n");
exit(eval);
}
void
fatal(const char *msg,
...)
{
va_list ap;
va_start(ap, msg);
fprintf(stderr, "%s: ", prog);
vfprintf(stderr, msg, ap);
fprintf(stderr, "\n");
va_end(ap);
exit(FAILURE);
}
void
fatal_error(const char *msg,
...)
{
va_list ap;
va_start(ap, msg);
fprintf(stderr, "%s: Error code 0x%04lx: ", prog, error);
vfprintf(stderr, msg, ap);
fprintf(stderr, "\n");
va_end(ap);
exit(FAILURE);
}
void *
re_alloc(void* ptr,
size_t size,
char* sub)
{
register void* value = realloc(ptr, size);
if (value == NULL)
fatal("%s: Virtual memory exhausted", sub);
return value;
}
EncVec*
Alloc_EncVec(int dummy,
...)
{
va_list vp;
EncVec* encVec = NULL;
EVcRange* cRange = NULL;
EVLow* evLow = NULL;
UShort numCR, numLows;
int i, j;
va_start(vp, dummy);
numCR = va_arg(vp, UShort);
encVec = re_alloc(encVec, 1 * sizeof (EncVec), "Alloc_EncVec");
encVec->numCodeRanges = numCR;
cRange = re_alloc(cRange, numCR * sizeof (EVcRange), "Alloc_EncVec");
for (i = 0; i < numCR; i++)
{
(cRange + i)->high.start = va_arg(vp, UShort);
(cRange + i)->high.end = va_arg(vp, UShort);
(cRange + i)->numLowRanges = numLows = va_arg(vp, UShort);
evLow = NULL;
evLow = re_alloc(evLow, numLows * sizeof (EVLow), "Alloc_EncVec");
for (j = 0; j < numLows; j++)
{
(evLow + j)->start = va_arg(vp, UChar);
(evLow + j)->end = va_arg(vp, UChar);
}
(cRange + i)->low = evLow;
}
encVec->codeRange = cRange;
va_end(vp);
return encVec;
}
void
Known_Encodings(void)
{
EncVec* encVec;
encVec = Alloc_EncVec(1,
1, 0xA1, 0xFE,
2, 0x40, 0x7E, 0xA1, 0xFE);
eVecMap[PID_BIG5][EID_BIG5] = encVec;
eVecMap_force[Big5] = encVec;
encVec = Alloc_EncVec(2,
1, 0xA1, 0xF7,
1, 0xA1, 0xFE);
eVecMap[PID_GB][EID_GB] = encVec;
eVecMap_force[GB] = encVec;
encVec = Alloc_EncVec(3,
1, 0xA1, 0xFE,
1, 0xA1, 0xFE);
eVecMap[PID_KS][EID_KS] = encVec;
eVecMap_force[KS] = encVec;
encVec = Alloc_EncVec(4,
3, 0x84, 0xD3,
2, 0x41, 0x7E,
0x81, 0xFE,
0xD8, 0xDE,
2, 0x31, 0x7E,
0x91, 0xFE,
0xE0, 0xF9,
2, 0x31, 0x7E,
0x91, 0xFE);
eVecMap[PID_JOHAB][EID_JOHAB] = encVec;
eVecMap_force[Johab] = encVec;
encVec = Alloc_EncVec(5,
1, 0xA1, 0xF4,
1, 0xA1, 0xFE);
eVecMap_force[JIS] = encVec;
eVecMap_force[X] = encVec;
encVec = Alloc_EncVec(6,
1, 0x00, 0xFF,
1, 0x00, 0xFF);
eVecMap[PID_UNICODE][EID_UNICODE] = encVec;
encVec = Alloc_EncVec(7,
3, 0x0, 0x0,
1, 0xA1, 0xDF,
0x81, 0x9F,
2, 0x40, 0x7E,
0x80, 0xFC,
0xE0, 0xEF,
2, 0x40, 0x7E,
0x80, 0xFC);
eVecMap[PID_SJIS][EID_SJIS] = encVec;
eVecMap_force[SJIS] = encVec;
}
UShort
JIS_to_SJIS(UShort code)
{
UShort index;
UShort cc0 = (code >> 8) & 0xFF;
UShort cc1 = code & 0xFF;
index = (cc0 - 0xa1) * (0xfe - 0xa1 + 1) + (cc1 - 0xa1);
cc0 = index / ((0x7e - 0x40 + 1) + (0xfc - 0x80 + 1));
cc1 = index % ((0x7e - 0x40 + 1) + (0xfc - 0x80 + 1));
if (cc0 < (0x9f - 0x81 + 1))
cc0 += 0x81;
else
cc0 += 0xe0 - (0x9f - 0x81 + 1);
if (cc1 < (0x7e - 0x40 + 1))
cc1 += 0x40;
else
cc1 += 0x80 - (0x7E - 0x40 + 1);
return (cc0 << 8) + cc1;
}
int
Init_Font_Engine(char* infile)
{
UShort cmapindex, platformID, encodingID, num_cmap;
if (verbose)
printf("Initializing TrueType font engine...\n");
error = TT_Init_FreeType(&engine);
if (error)
fatal_error("Couldn't initialize FreeType engine");
error = TT_Init_Post_Extension(engine);
if (error)
fatal_error("Couldn't initialize the post extension");
error = TT_Open_Face(engine, infile, &face);
if (error)
fatal_error("Unable to open input file `%s'", infile);
error = TT_Load_PS_Names(face, &post);
if (error)
fatal_error("Unable to load post table");
TT_Get_Face_Properties(face, &properties);
error = TT_New_Instance(face, &instance);
if (error)
fatal_error("Couldn't create instance");
error = TT_Set_Instance_Resolutions(instance, 600, 600);
if (error)
fatal_error("Error setting resolutions");
error = TT_Set_Instance_CharSize(instance, 120 * 64);
if (error)
fatal_error("Error setting character size");
error = TT_New_Glyph(face, &glyph);
if (error)
fatal_error("Couldn't create new glyph");
num_cmap = TT_Get_CharMap_Count(face);
for (cmapindex = 0; cmapindex < num_cmap; cmapindex++)
{
TT_Get_CharMap_ID(face, cmapindex, &platformID, &encodingID);
if (platformID == pid && encodingID == eid)
break;
}
if (cmapindex == num_cmap)
{
mesg("Possible platform and encoding ID pairs:");
for (cmapindex = 0; cmapindex < num_cmap; cmapindex++)
{
TT_Get_CharMap_ID(face, cmapindex, &platformID, &encodingID);
mesg(" (%d, %d)", platformID, encodingID);
}
mesg ("\n");
fatal("No character map for given platform %d, encoding %d", pid, eid);
}
error = TT_Get_CharMap(face, cmapindex, &cmap);
if (error)
fatal_error("Cannot load cmap");
return TRUE;
}
char*
LookUp_Name(int index)
{
UShort platform, encoding, language, id;
char* string;
UShort string_len;
UShort i, n;
n = properties.num_Names;
for (i = 0; i < n; i++)
{
TT_Get_Name_ID(face, i, &platform, &encoding, &language, &id);
TT_Get_Name_String(face, i, &string, &string_len);
if (id == index)
break;
}
i = (string_len > NAMELEN) ? NAMELEN : string_len;
string[i] = '\0';
return string;
}
int
LoadTrueTypeChar(int idx)
{
TT_Matrix scale = {(1 << 16) / 64, 0, 0, (1 << 16) / 64};
error = TT_Load_Glyph(instance, glyph, idx, TTLOAD_DEFAULT);
if (error)
fatal_error("Load glyph");
error = TT_Get_Glyph_Outline(glyph, &outline);
if (error)
fatal_error("Get glyph outlines");
TT_Transform_Outline(&outline, &scale);
error = TT_Get_Glyph_Metrics(glyph, &metrics);
if (error)
fatal_error("Get glyph_metrics");
return TRUE;
}
char*
PS_GlyphName(UShort idx,
UShort code)
{
char *glyphname = ".notdef";
static char CJK_glyphname[8];
if (compact)
{
sprintf(CJK_glyphname, "cjk%04X", code);
glyphname = CJK_glyphname;
}
else
{
if (idx)
TT_Get_PS_Name(face, idx, &glyphname);
}
return glyphname;
}
void
PS_Head(FILE *out,
int plane,
EncVec* planeEV,
char* font,
int UID)
{
EVcRange* cRange = planeEV->codeRange;
UShort numCR = planeEV->numCodeRanges;
int cjk = 0, nGlyph = 0, irange;
EVLow* pLow = cRange->low;
UShort nLow = cRange->numLowRanges;
int ipl, ilow, ich;
int idx;
UShort code;
time_t curtime;
struct tm *loctime;
char text[NAMELEN];
char fam_name[NAMELEN];
char* version;
char fullname[NAMELEN];
char copyright[NAMELEN];
curtime = time(NULL);
loctime = localtime(&curtime);
strcpy(fullname, LookUp_Name(6));
strcpy(fam_name, LookUp_Name(1));
strcpy(text, LookUp_Name(5));
version = &text[strcspn(text, "1234567890.")];
version[strspn(version, "1234567890.")] = '\0';
strcpy(copyright, LookUp_Name(0));
fprintf(out, "%%!FontType1-1.0: %s %s\n", font, version);
fprintf(out, "%%%%Creator: %s, ", prog);
fprintf(out, "%s\n", rcsid);
fprintf(out, "%%%%CreationDate: %s", asctime(loctime));
Fputs("%%VMusage: 030000 030000");
Fputs("11 dict begin");
Fputs("/FontInfo 8 dict dup begin");
fprintf(out, "/version (%s) readonly def\n", version);
fprintf(out, "/Copyright (%s) readonly def\n", copyright);
fprintf(out, "/Notice (Plane %d) readonly def\n", plane);
fprintf(out, "/FullName (%s) readonly def\n", fullname);
fprintf(out, "/FamilyName (%s) readonly def\n", fam_name);
Fputs("/Weight (Regular) readonly def");
Fputs("/ItalicAngle 0 def");
Fputs("/isFixedPitch false def");
Fputs("end readonly def");
fprintf(out, "/FontName /%s def\n", font);
Fputs("/PaintType 0 def");
Fputs("/FontType 1 def");
if (fontShift == 0)
Fputs("/FontMatrix [0.001 0 0 0.001 0 0] readonly def");
else
fprintf(out, "/FontMatrix [0.001 0 0 0.001 0 %5.3f] readonly def\n",
fontShift);
Fputs("/Encoding 256 array");
Fputs("0 1 255 {1 index exch /.notdef put} for");
for (irange = 0; irange < numCR; irange++, cRange++)
{
pLow = cRange->low;
nLow = cRange->numLowRanges;
for (ipl = cRange->high.start; ipl <= cRange->high.end; ipl++)
{
if (nLow == 0)
{
nGlyph = 0x100;
for (ich = 0; ich <= 0xff; ich++)
{
code = ipl<<8 | ich;
idx = TT_Char_Index(cmap, code);
fprintf(out, "dup %d /%s put\n", ich, PS_GlyphName(idx, code));
}
}
else
{
for (ilow = 0; ilow < nLow; ilow++, pLow++)
{
if (!compact && !mapping)
cjk = pLow->start;
nGlyph += pLow->end - pLow->start + 1;
for (ich = pLow->start; ich <= pLow->end; ich++, cjk++)
{
code = ipl<<8 | ich;
idx = TT_Char_Index(cmap, code);
fprintf(out, "dup %d /%s put\n", cjk, PS_GlyphName(idx, code));
if (mapping && cjk == 0xFF)
goto done;
}
}
}
}
}
done:
Fputs("readonly def");
Fputs("/FontBBox [0 -300 1000 1000] readonly def");
fprintf(out, "/UniqueID %d def\n",UID);
Fputs("currentdict end");
Fputs("currentfile eexec");
Fputs("dup /Private 8 dict dup begin");
Fputs("/-| { string currentfile exch readstring pop } executeonly def");
Fputs("/|- { noaccess def } executeonly def");
Fputs("/| { noaccess put } executeonly def");
Fputs("/BlueValues [ ] |-");
Fputs("/ForceBold true def");
Fputs("/LanguageGroup 1 def");
Fputs("/RndStemUp false def");
Fputs("/MinFeature{16 16} |-");
fprintf(out, "/UniqueID %d def\n",UID);
Fputs("/Subrs 4 array");
Fputs("dup 0 { 3 0 callothersubr pop pop setcurrentpoint return } |");
Fputs("dup 1 { 0 1 callothersubr return } |");
Fputs("dup 2 { 0 2 callothersubr return } |");
Fputs("dup 3 { return } |");
Fputs("|-");
fprintf(out, "2 index /CharStrings %d dict dup begin\n", nGlyph + 1);
}
void
PS_Tail(FILE *out)
{
Fputs("/.notdef { 0 250 hsbw endchar } |-");
Fputs("end end readonly put noaccess put");
Fputs("dup /FontName get exch definefont pop");
Fputs("mark currentfile closefile");
}
void
PS_Curveto(FILE *out,
TT_F26Dot6 x,
TT_F26Dot6 y,
int s,
int e)
{
int N, i;
TT_F26Dot6 sx[3], sy[3], cx[4], cy[4];
N = e - s + 1;
cx[0] = lastpsx; cy[0] = lastpsy;
if (s == e)
{
cx[1] = (2 * outline.points[s].x + outline.points[s - 1].x) / 3;
cy[1] = (2 * outline.points[s].y + outline.points[s - 1].y) / 3;
cx[2] = (2 * outline.points[s].x + x) / 3;
cy[2] = (2 * outline.points[s].y + y) / 3;
cx[3] = x;
cy[3] = y;
fprintf(out, "%d %d %d %d %d %d rrcurveto\n",
Coord(cx[1] - cx[0]), Coord(cy[1] - cy[0]),
Coord(cx[2] - cx[1]), Coord(cy[2] - cy[1]),
Coord(cx[3] - cx[2]), Coord(cy[3] - cy[2]));
}
else
{
for(i = 0; i < N; i++)
{
sx[0] = (i == 0) ?
outline.points[s - 1].x :
(outline.points[i + s].x + outline.points[i + s - 1].x) / 2;
sy[0] = (i == 0) ?
outline.points[s - 1].y :
(outline.points[i + s].y + outline.points[i + s - 1].y) / 2;
sx[1] = outline.points[s + i].x;
sy[1] = outline.points[s + i].y;
sx[2] = (i == N - 1) ?
x :
(outline.points[s + i].x + outline.points[s + i + 1].x) / 2;
sy[2] = (i == N - 1) ?
y :
(outline.points[s + i].y + outline.points[s + i + 1].y) / 2;
cx[1] = (2 * sx[1] + sx[0]) / 3;
cy[1] = (2 * sy[1] + sy[0]) / 3;
cx[2] = (2 * sx[1] + sx[2]) / 3;
cy[2] = (2 * sy[1] + sy[2]) / 3;
cx[3] = sx[2];
cy[3] = sy[2];
fprintf(out, "%d %d %d %d %d %d rrcurveto\n",
Coord(cx[1] - cx[0]), Coord(cy[1] - cy[0]),
Coord(cx[2] - cx[1]), Coord(cy[2] - cy[1]),
Coord(cx[3] - cx[2]), Coord(cy[3] - cy[2]));
cx[0] = cx[3];
cy[0] = cy[3];
}
}
PS_LastPt(x, y);
}
#ifdef DEBUG
int debug_Char_Code = 0xFFFF;
FILE* tmpout;
int showlabel = FALSE;
int no_glyph = FALSE;
int no_control= FALSE;
#define Fputps(_msg_) fprintf(tmpout, "%s\n", _msg_)
void
tmp_out(FILE* tmpout)
{
int i, j;
Fputps("%!PS");
Fputps("%%% CharString debugging program.");
Fputps("%%% Generated by: ttf2pfb Revision: 1.13 $");
Fputps("%%% plot char-string (pathes defined in /cjkxxxx)");
Fputps("");
Fputps("%%% user-defined parameter");
Fputps("/scalefactor .6 def");
Fputps("%% 0 black, 1 white");
Fputps("/glyph-outline-gray 0 def");
Fputps("/control-point-gray 0.7 def");
Fputps("");
Fputps("%%% calculate shifts and scale factor");
Fputps("currentpagedevice /PageSize get dup");
Fputps("0 get /pagewidth exch def");
Fputps("1 get /pageheight exch def");
Fputps("");
fprintf(tmpout,
"/llx %d.0 def /lly %d.0 def /urx %d.0 def /ury %d.0 def\n",
Coord(metrics.bbox.xMin / 64), Coord(metrics.bbox.yMin / 64),
Coord(metrics.bbox.xMax / 64), Coord(metrics.bbox.yMax / 64));
Fputps("/olwidth urx llx sub def");
Fputps("/olheight ury lly sub def");
Fputps("");
Fputps("/scale scalefactor pagewidth mul olwidth div def");
Fputps("/xshift pagewidth 1 scalefactor sub mul 2 div def");
Fputps("/yshift pageheight olheight scale mul sub 2 div def");
Fputps("");
Fputps("%% save old gray-scale value");
Fputps("/oldgray currentgray def");
Fputps("");
Fputps("%%% for point sequence label");
Fputps("/TimesRoman 8 selectfont");
Fputps("/i++ {i /i i 1 add def} def");
Fputps("/itos {4 string cvs} def");
Fputps("/point {2 copy i++ 3 1 roll 5 3 roll} def");
Fputps("/drawlabel");
Fputps(" {{moveto dup 0 eq {exit}");
Fputps(" {itos show} ifelse} loop pop} def");
Fputps("/nodrawlabel {clear} def");
Fputps("/i 0 def");
Fputps("");
Fputps("%%% for drawing glyph paths, redefine commands used in CharString");
Fputps("%% scaled to proper size");
Fputps("/addr {scale mul 3 -1 roll add 3 1 roll");
Fputps(" scale mul add exch 2 copy} def");
if (no_glyph)
{
Fputps("/rmoveto {addr pop pop point} def");
Fputps("/rlineto {addr pop pop point} def");
Fputps("/rrcurveto {8 4 roll addr 8 -2 roll addr 8 -2 roll addr");
Fputps(" 8 2 roll 6 {pop} repeat point} def");
}
else
{
Fputps("/rmoveto {addr moveto point} def");
Fputps("/rlineto {addr lineto point} def");
Fputps("/rrcurveto {8 4 roll addr 8 -2 roll addr 8 -2 roll addr");
Fputps(" 8 2 roll curveto point} def");
}
Fputps("/hsbw {pop pop");
Fputps(" xshift llx scale mul sub");
Fputps(" yshift lly scale mul sub} def");
Fputps("/endchar {stroke pop pop} def");
Fputps("");
Fputps("%%% for drawing control paths");
Fputps("/T {pop lly sub scale mul yshift add exch");
Fputps(" llx sub scale mul xshift add exch } def");
Fputps("/mt {T 2 copy moveto} def");
if (no_control)
Fputps("/lt {T} def");
else
Fputps("/lt {T 2 copy lineto} def");
Fputps("");
Fputps("1 setlinecap 1 setlinejoin");
Fputps("%%% draw control points and paths");
Fputps("control-point-gray setgray");
for (i = 0, j = 0; i < outline.n_contours; i++)
{
Fputps("");
fprintf(tmpout,
"%d %d %d %d mt\n",
j,
Coord(outline.points[j].x), Coord(outline.points[j].y),
outline.flags[j]);
j++;
for (; j <= outline.contours[i]; j++)
fprintf(tmpout,
"%d %d %d %d lt\n",
j,
Coord(outline.points[j].x), Coord(outline.points[j].y),
outline.flags[j]);
Fputps("closepath");
}
Fputps("stroke");
if (showlabel && !no_control)
Fputps("drawlabel");
else
Fputps("nodrawlabel");
Fputps("");
Fputps("%%% draw glyph outlines");
Fputps("glyph-outline-gray setgray");
Fputps("");
}
#endif
short
PS_CharString(FILE *out,
UShort char_Code)
{
int idx, i, j;
UShort start_offpt, end_offpt = 0, fst;
#if DEBUG
FILE* oldout = out;
int loop = 1;
#endif
if (force_enc == X)
char_Code = JIS_to_SJIS(char_Code);
idx = TT_Char_Index(cmap, char_Code);
if (idx == 0)
return FALSE;
if (!LoadTrueTypeChar(idx))
fatal("Couldn't load character with index %d (code %d)", idx, char_Code);
if (verbose)
printf("0x%04x (%05d): %s\n",
char_Code, idx, PS_GlyphName(idx, char_Code));
fprintf(out, "/%s {\n", PS_GlyphName(idx, char_Code));
#ifdef DEBUG
if (char_Code == debug_Char_Code)
{
tmp_out(tmpout);
out = tmpout;
loop = 0;
}
for (; loop < 2; loop++)
{
#endif
fprintf(out, "0 %d hsbw\n", (int)(metrics.advance / 64));
lastpsx = lastpsy = 0;
for (i = 0, j = 0; i < outline.n_contours; i++)
{
fst = j;
PS_Moveto(outline.points[j].x, outline.points[j].y);
j++;
start_offpt = 0;
for (; j <= outline.contours[i]; j++)
{
if (!(outline.flags[j] & TT_Flag_On_Curve))
{
if (!start_offpt)
start_offpt = end_offpt = j;
else
end_offpt++;
}
else
{
if (start_offpt)
{
PS_Curveto(out,
outline.points[j].x, outline.points[j].y,
start_offpt, end_offpt);
start_offpt = 0;
}
else
PS_Lineto(outline.points[j].x, outline.points[j].y);
}
}
if (start_offpt)
PS_Curveto(out,
outline.points[fst].x, outline.points[fst].y,
start_offpt, end_offpt);
else
Fputs("closepath");
}
Fputs("endchar");
#if DEBUG
out = oldout;
}
if (char_Code == debug_Char_Code)
{
if (showlabel && !no_glyph)
Fputps("drawlabel");
else
Fputps("nodrawlabel");
Fputps("");
Fputps("%%% end of drawing");
Fputps("oldgray setgray");
Fputps("showpage");
fclose(tmpout);
}
#endif
Fputs(" } |-");
return TRUE;
}
EncVec*
Get_EncVec(FILE *enc)
{
EncVec* encVec = NULL;
EVcRange* cRange = NULL;
EVLow* lByte = NULL;
UShort numCR = 0, numLow = 0;
int start, end;
int buflen = LINELEN, numAssigned;
char buf[LINELEN];
if (force_enc != 0)
return eVecMap_force[force_enc];
if (enc == NULL && eVecMap[pid][eid] != NULL)
return eVecMap[pid][eid];
while (fgets(buf, buflen, enc) != NULL)
{
if (buf[0] != '#' && buf[0] != '\n')
{
if (strrchr(buf,':') != NULL)
{
if (lByte != NULL)
{
if (cRange == NULL)
{
cRange = re_alloc(cRange, ++numCR * sizeof (EVcRange),
"Get_EncVec");
cRange->high.start = cRange->high.end = 0;
}
(cRange + numCR - 1)->low = lByte;
(cRange + numCR - 1)->numLowRanges = numLow;
}
cRange = re_alloc(cRange, ++numCR * sizeof (EVcRange), "Get_EncVec");
(cRange + numCR - 1)->numLowRanges = numLow = 0;
lByte = NULL;
numAssigned = sscanf(buf, "%i %*40s %i", &start, &end);
if (numAssigned <= 0 || numAssigned > 2)
{
mesg("%s: Get_EncVec: Invalid high code range.\n", prog);
return NULL;
}
else
{
(cRange + numCR - 1)->high.start = start;
if (numAssigned == 1)
(cRange + numCR - 1)->high.end = start;
else
(cRange + numCR - 1)->high.end = end;
}
}
else
{
lByte = re_alloc(lByte, ++numLow * sizeof (EVLow), "Get_EncVec");
numAssigned = sscanf(buf, "%i %*40s %i", &start, &end);
if (numAssigned <= 0 || numAssigned > 2)
{
mesg("%s: Get_EncVec: Invalid long code range.\n", prog);
return NULL;
}
else
{
(lByte + numLow - 1)->start = start;
if (numAssigned == 1)
(lByte + numLow - 1)->end = start;
else
(lByte + numLow - 1)->end = end;
}
}
}
}
if (cRange == NULL)
{
cRange = re_alloc(cRange, ++numCR * sizeof (EVcRange), "Get_EncVec");
cRange->high.start = cRange->high.end = 0;
cRange->numLowRanges = 0;
}
if (lByte != NULL)
{
(cRange + numCR - 1)->low = lByte;
(cRange + numCR - 1)->numLowRanges = numLow;
}
encVec = re_alloc(encVec, 1 * sizeof (EncVec), "Get_EncVec");
encVec->numCodeRanges = numCR;
encVec->codeRange = cRange;
return encVec;
}
EncVec*
Get_PlaneEV(EncVec* encVec,
int plane)
{
UShort numCR = encVec->numCodeRanges;
EVcRange* cRange = encVec->codeRange;
EncVec* encV = NULL;
EVcRange* planeCR = NULL;
EVLow* planeLow = NULL;
UShort nCR = 0, nLow = 0;
int icr;
if (compact)
{
int iChar = 0;
int nChar = (plane-1) * 256;
int recording = 0;
if (plane < 1 || plane > 99)
fatal("Get_PlaneEV: Given plane out of range");
for (icr = 0; icr < numCR; icr++, cRange++)
{
UShort numLow = cRange->numLowRanges;
int ipl;
for (ipl = cRange->high.start; ipl <= cRange->high.end; ipl++)
{
EVLow* pLow = cRange->low;
int ilow;
if (recording)
{
if (planeLow != NULL)
{
(planeCR + nCR - 1)->low = planeLow;
(planeCR + nCR - 1)->numLowRanges = nLow;
planeLow = NULL;
}
if (iChar <= nChar)
{
planeCR = re_alloc(planeCR, ++nCR * sizeof (EVcRange),
"Get_PlaneEV");
(planeCR + nCR - 1)->high.start =
(planeCR + nCR - 1)->high.end = ipl;
(planeCR + nCR - 1)->numLowRanges = nLow = 0;
}
}
for (ilow = 0; ilow < (numLow == 0 ? 1 : numLow); ilow++, pLow++)
{
int start, end, nLowChar;
if (numLow == 0)
{
start = 0x0;
end = 0xff;
}
else
{
start = pLow->start;
end = pLow->end;
}
nLowChar = end - start + 1;
if (iChar + nLowChar > nChar)
{
int bchar = start + nChar - iChar;
if (planeCR == NULL)
{
planeCR = re_alloc(planeCR, ++nCR * sizeof (EVcRange),
"Get_PlaneEV");
(planeCR + nCR - 1)->high.start = ipl;
(planeCR + nCR - 1)->high.end = ipl;
}
if (recording == 0)
start = bchar;
else
end = bchar;
nChar += 0xff;
recording++;
}
iChar += nLowChar;
if (recording)
{
if (iChar <= nChar)
{
planeLow = re_alloc(planeLow, ++nLow * sizeof (EVLow),
"Get_PlaneEV");
(planeLow + nLow - 1)->start = start;
(planeLow + nLow - 1)->end = end;
}
if (recording > 1 || iChar > nChar)
{
(planeCR + nCR - 1)->numLowRanges = nLow;
(planeCR + nCR - 1)->low = planeLow;
encV = re_alloc(encV, 1 * sizeof (EncVec), "Get_PlaneEV");
encV->numCodeRanges = nCR;
encV->codeRange = planeCR;
return encV;
}
}
}
}
}
if (recording)
{
(planeCR + nCR - 1)->numLowRanges = nLow;
(planeCR + nCR - 1)->low = planeLow;
encV = re_alloc(encV, 1 * sizeof (EncVec), "Get_PlaneEV");
encV->numCodeRanges = nCR;
encV->codeRange = planeCR;
return encV;
}
}
else
{
for (icr = 0; icr < numCR; icr++, cRange++)
{
if (plane >= cRange->high.start && plane <= cRange->high.end)
{
encV = re_alloc(encV, 1 * sizeof (EncVec), "Get_PlaneEV");
planeCR = re_alloc(planeCR, 1 * sizeof (EVcRange), "Get_PlaneEV");
planeCR->high.start = planeCR->high.end = plane;
planeCR->numLowRanges = cRange->numLowRanges;
planeCR->low = cRange->low;
encV->numCodeRanges = 1;
encV->codeRange = planeCR;
return encV;
}
}
}
return NULL;
}
short
Generate_Font(FILE *out,
int plane,
FILE *enc,
char *fname,
int UID)
{
EncVec* encVec = Get_EncVec(enc);
EncVec* planeEncVec;
EVcRange* cRange;
UShort numCR;
UShort code;
int ilow, iplan, ichar, irange;
if (verbose)
printf("Generating fonts...\n\n");
if (encVec == NULL)
return FALSE;
if (mapping)
planeEncVec = encVec;
else
if ((planeEncVec = Get_PlaneEV(encVec, plane)) == NULL)
{
mesg("%s: Can't find encoding vector for the font plane 0x%X.\n",
prog, plane);
return FALSE;
}
PS_Head(out, plane, planeEncVec, fname, UID);
numCR = planeEncVec->numCodeRanges;
cRange = planeEncVec->codeRange;
for (irange = 0; irange < numCR; irange++, cRange++)
{
EVLow* pLow = cRange->low;
UShort nLow = cRange->numLowRanges;
for (iplan = cRange->high.start; iplan <= cRange->high.end; iplan++)
{
if (nLow == 0)
{
for (ichar = 0; ichar <= 0xff; ichar++)
{
code = iplan << 8 | ichar;
PS_CharString(out, code);
}
}
else
{
for (ilow = 0; ilow < nLow; ilow++, pLow++)
{
for (ichar = pLow->start; ichar <= pLow->end; ichar++)
{
code = iplan << 8 | ichar;
PS_CharString(out, code);
}
}
}
}
}
PS_Tail(out);
return TRUE;
}
int
main(int argc,
char *argv[])
{
char *infile, *outfile, *encFile, *fname = "UNKNOWN";
FILE *out, *enc;
int result, plane = 0, UID = 4999999;
if ((prog = strrchr(argv[0], '/')))
prog++;
else
prog = argv[0];
Known_Encodings();
out = stdout;
enc = NULL;
infile = outfile = encFile = NULL;
argc--;
argv++;
while (argc > 0)
{
if (argv[0][0] == '-')
{
switch (argv[0][1])
{
case 'v':
case 'V':
verbose = TRUE;
break;
case 'c':
case 'C':
compact = TRUE;
break;
case 'k':
case 'K':
keep = TRUE;
break;
case 'm':
case 'M':
mapping = TRUE;
break;
case 'p':
case 'P':
result = argv[0][2];
argc--;
argv++;
if (result == 'i' || result == 'I')
{
if ((pid = atoi(argv[0])) < 0 || pid > 64)
fatal("Invalid platform ID %d", pid);
}
else if (result == 'l' || result == 'L')
{
result = 0;
while (argv[0][result] == '0' &&
toupper(argv[0][result + 1]) != 'X')
result++;
sscanf(&argv[0][result], "%i", &plane);
}
break;
case 'e':
case 'E':
result = argv[0][2];
argc--;
argv++;
if (result == 'i' || result == 'I')
{
if ((eid = atoi(argv[0])) < 0 || eid > 64)
fatal("Invalid encoding ID %d", eid);
}
else if (result == 'n' || result == 'N')
encFile = argv[0];
break;
case 'u':
case 'U':
argc--;
argv++;
UID = atoi(argv[0]);
break;
case 'f':
case 'F':
result = argv[0][2];
argc--;
argv++;
if (result == '\0')
fname = argv[0];
else if (result == 'o' || result == 'O')
{
switch (argv[0][0])
{
case 'g':
case 'G':
force_enc = GB;
break;
case 'k':
case 'K':
force_enc = KS;
break;
case 'b':
case 'B':
force_enc = Big5;
break;
case 'j':
case 'J':
result = argv[0][1];
if (result == 'o' || result == 'O')
force_enc = Johab;
else
force_enc = JIS;
break;
case 's':
case 'S':
force_enc = SJIS;
break;
case 'x':
case 'X':
force_enc = X;
}
}
break;
case 't':
case 'T':
argc--;
argv++;
infile = argv[0];
break;
case 'o':
case 'O':
argc--;
argv++;
outfile = argv[0];
break;
case 's':
case 'S':
argc--;
argv++;
sscanf(argv[0], "%f", &fontShift);
break;
#ifdef DEBUG
case 'd':
case 'D':
argc--;
argv++;
sscanf(argv[0], "%i", &debug_Char_Code);
tmpout = fopen("ch-debug.ps", "wt");
mesg("You have specified the character code 0x%04x for debugging.\n",
debug_Char_Code);
mesg("A PostScript program named `ch-debug.ps' will be created.\n");
break;
case 'l':
case 'L':
showlabel = TRUE;
break;
case 'n':
case 'N':
result = argv[0][2];
if (result == 'g' || result == 'G')
no_glyph = TRUE;
else if (result == 'c' || result == 'C')
no_control = TRUE;
break;
#endif
default:
Usage(1);
}
}
else
infile = argv[0];
argc--;
argv++;
}
if (outfile != NULL)
if ((out = fopen(outfile, "wt")) == 0)
{
fatal("Unable to open the output file `%s'", outfile);
exit(FAILURE);
}
if (infile == NULL)
{
mesg("%s: No input TTF file provided\n", prog);
Usage(1);
}
if (encFile != NULL)
{
if ((enc = fopen(encFile, "rt")) == 0)
fatal("No input code range file");
}
if (!Init_Font_Engine(infile))
{
if (out != stdout)
{
fclose(out);
if (!keep)
(void)unlink(outfile);
}
exit(FAILURE);
}
if (Generate_Font(out, plane, enc, fname, UID))
result = 0;
else
result = 2;
if (out != stdout)
{
fclose(out);
if (result != 0)
{
mesg("%s: An error occurred while generating the font", prog);
if (!keep)
(void)unlink(outfile);
}
}
TT_Close_Face(face);
TT_Done_FreeType(engine);
exit(result);
return 0;
}