1726 lines
43 KiB
C
1726 lines
43 KiB
C
/*
|
|
* ttf2pfb.c -- TrueType to PostScript Type 1 Font converter.
|
|
*
|
|
* Author: Chun-Yu Lee <d791013@ce.ntu.edu.tw>
|
|
* Maintainer: Werner Lemberg <wl@gnu.org>
|
|
*
|
|
* The generated output is in a raw Type 1 Font format. An encoder
|
|
* (e.g. t1asm or t1binary) is needed to convert it into PFA or PFB format.
|
|
*
|
|
* This program was adapted from the ntu2cjk package (which was part of the
|
|
* LaTeX2e CJK package (by Werner Lemberg <wl@gnu.org>)).
|
|
*
|
|
*
|
|
* Modified by Joachim H. Kaiser <jhk@cmpnetmail.com> to include real glyph
|
|
* names and other font infos (see PS_Head function).
|
|
* The test programs of the FreeType distribution have been heavily used as
|
|
* templates.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Requirements:
|
|
* - the FreeType library.
|
|
* - t1asm or a similar converter if PFA or PFB format is required.
|
|
* - getafm or a similar program if AFM font metrics are required.
|
|
* - afm2tfm or a similar program if TFM font metrics are required.
|
|
* - for compact fonts: the CJK package for typesetting LaTeX documents.
|
|
* - dvips 5.66 or higher if self-contained PostScript document
|
|
* outputs with partially downloaded fonts are required. Note that
|
|
* the partial download code in dvips is still buggy, causing strange
|
|
* error messages during loading of the created PS fonts.
|
|
* - Ghostscript 3.33 or newer (this is optional).
|
|
*/
|
|
|
|
#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" /* we are in the FreeType package tree */
|
|
|
|
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 /* KS is also called Wansung */
|
|
#define EID_KS 5
|
|
#define PID_JOHAB 3
|
|
#define EID_JOHAB 6
|
|
|
|
/* Set default values */
|
|
#ifndef DEFAULT_PLATFORM_ID
|
|
#define DEFAULT_PLATFORM_ID PID_UNICODE /* MS platform */
|
|
#endif
|
|
|
|
#ifndef DEFAULT_ENCODING_ID
|
|
#define DEFAULT_ENCODING_ID EID_UNICODE
|
|
#endif
|
|
|
|
/* The possible values for the `force_enc' variable. */
|
|
typedef enum enc_type_
|
|
{
|
|
GB = 1, Big5, JIS, KS, Johab, SJIS, X
|
|
} enc_type;
|
|
|
|
/* A variable to enforce a certain font encoding (if > 0). */
|
|
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 /* max # of columns of code range file */
|
|
#define NAMELEN 80 /* max length of name used from LookUp */
|
|
|
|
|
|
/*
|
|
* Flags and globals
|
|
*/
|
|
|
|
int verbose = FALSE; /* messages should be printed or not. */
|
|
int compact = FALSE; /* generate compact font? */
|
|
int keep = FALSE; /* keep output font in case of error? */
|
|
int mapping = FALSE; /* use encoding file as mapping? */
|
|
float fontShift = 0;
|
|
|
|
#ifndef UShort
|
|
typedef unsigned short UShort;
|
|
#endif
|
|
#ifndef UChar
|
|
typedef unsigned char UChar;
|
|
#endif
|
|
|
|
#define TT_Flag_On_Curve 1
|
|
|
|
/* default platform and encoding ID's. */
|
|
int pid = DEFAULT_PLATFORM_ID;
|
|
int eid = DEFAULT_ENCODING_ID;
|
|
|
|
|
|
char* prog; /* program name */
|
|
|
|
|
|
/* for orthogonality with fprintf */
|
|
#define Fputs(_string_) fprintf(out, "%s\n", _string_)
|
|
|
|
|
|
/* Postscript font related defines and functions */
|
|
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)
|
|
|
|
|
|
/*
|
|
* Freetype globals.
|
|
*/
|
|
|
|
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;
|
|
|
|
|
|
/*
|
|
* Data structures defined for encoding vectors
|
|
*/
|
|
|
|
/*
|
|
* A code range file for the encoding vector of a font contains code
|
|
* range pairs, each pair a line. The values for the begin and end of the
|
|
* ranges are separated by ` - '. Note that the spaces before and after the
|
|
* minus sign are significant. The possible syntax is as follows:
|
|
*
|
|
* (Note that code ranges must appear in ascending order.)
|
|
*
|
|
* 1. Absolute range, i.e., the code is at least a two-byte number, e.g.:
|
|
*
|
|
* 0xA140 - 0xA17E
|
|
* 41280 - 41342
|
|
* 0xE00000 - 0xE000FF
|
|
*
|
|
* The first two lines represent the same range.
|
|
*
|
|
* 2. Relative range, i.e., the code is a one-byte number. If the line ends
|
|
* with a colon `:', it designates the high byte(s) range, otherwise the
|
|
* low byte range. If there is no high byte(s) range declared before the low
|
|
* byte range, the last defined high byte(s) range or `0x00 - 0x00:' will be
|
|
* used. e.g.:
|
|
*
|
|
* 0xA1 - 0xFE:
|
|
* 0x40 - 0x7E
|
|
* 0xA1 - 0xFE
|
|
*
|
|
* which is Big-5 Encoding.
|
|
*
|
|
* 3. Single code. Similar to absolute or relative range but the second
|
|
* number of the range is the same as the first number. E.g.:
|
|
*
|
|
* 0xA141 == 0xA141 - 0xA141
|
|
* 0xA1: == 0xA1 - 0xA1:
|
|
* 0xA1 == 0xA1 - 0xA1
|
|
*
|
|
* 4. If the high byte range is declared and there is no low byte range
|
|
* declared consecutively, the assumed low byte range is `0x00 - 0xFF'.
|
|
*
|
|
* 5. Comment line. A line starting with a hash mark `#' followed by any
|
|
* characters up to the end of the line is ignored. Blank lines are also
|
|
* discarded.
|
|
*/
|
|
|
|
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;
|
|
|
|
/* Select encoding vector with respect to pid and eid */
|
|
EncVec* eVecMap[5][10];
|
|
|
|
/* Select encoding vector with respect to force_enc */
|
|
EncVec* eVecMap_force[10];
|
|
|
|
|
|
/*************/
|
|
/* Functions */
|
|
/*************/
|
|
|
|
|
|
void
|
|
mesg(const char *msg, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap, msg);
|
|
vfprintf(stderr, msg, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
|
|
/*
|
|
* Usage.
|
|
*/
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
/*
|
|
* Reallocate a pointer.
|
|
*/
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
/*
|
|
* We have to introduce the `dummy' integer to assure correct handling of
|
|
* the stack. Using `UShort' as the first parameter may fail in case
|
|
* this type is promoted to a different type (as happens e.g. under
|
|
* emx for DOS).
|
|
*/
|
|
|
|
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;
|
|
|
|
/* Big-5 encoding */
|
|
encVec = Alloc_EncVec(1,
|
|
1, 0xA1, 0xFE,
|
|
2, 0x40, 0x7E, 0xA1, 0xFE);
|
|
eVecMap[PID_BIG5][EID_BIG5] = encVec;
|
|
eVecMap_force[Big5] = encVec;
|
|
|
|
/* GB encoding */
|
|
encVec = Alloc_EncVec(2,
|
|
1, 0xA1, 0xF7,
|
|
1, 0xA1, 0xFE);
|
|
eVecMap[PID_GB][EID_GB] = encVec;
|
|
eVecMap_force[GB] = encVec;
|
|
|
|
/* KS encoding */
|
|
encVec = Alloc_EncVec(3,
|
|
1, 0xA1, 0xFE,
|
|
1, 0xA1, 0xFE);
|
|
eVecMap[PID_KS][EID_KS] = encVec;
|
|
eVecMap_force[KS] = encVec;
|
|
|
|
/* Johab encoding */
|
|
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;
|
|
|
|
/* JIS encoding */
|
|
encVec = Alloc_EncVec(5,
|
|
1, 0xA1, 0xF4,
|
|
1, 0xA1, 0xFE);
|
|
eVecMap_force[JIS] = encVec;
|
|
eVecMap_force[X] = encVec; /* will be internally translated to SJIS */
|
|
|
|
/* Unicode encoding */
|
|
encVec = Alloc_EncVec(6,
|
|
1, 0x00, 0xFF,
|
|
1, 0x00, 0xFF);
|
|
eVecMap[PID_UNICODE][EID_UNICODE] = encVec;
|
|
|
|
/* SJIS encoding */
|
|
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;
|
|
}
|
|
|
|
|
|
/*
|
|
* Convert JIS to SJIS encoding.
|
|
*/
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
/*
|
|
* Open TTF file and select cmap.
|
|
*/
|
|
|
|
int
|
|
Init_Font_Engine(char* infile)
|
|
{
|
|
UShort cmapindex, platformID, encodingID, num_cmap;
|
|
|
|
if (verbose)
|
|
printf("Initializing TrueType font engine...\n");
|
|
|
|
/* initialization of the FreeType engine */
|
|
error = TT_Init_FreeType(&engine);
|
|
if (error)
|
|
fatal_error("Couldn't initialize FreeType engine");
|
|
|
|
/* initialization of the post extension */
|
|
error = TT_Init_Post_Extension(engine);
|
|
if (error)
|
|
fatal_error("Couldn't initialize the post extension");
|
|
|
|
/* open the input file */
|
|
error = TT_Open_Face(engine, infile, &face);
|
|
if (error)
|
|
fatal_error("Unable to open input file `%s'", infile);
|
|
|
|
/* load full post table */
|
|
error = TT_Load_PS_Names(face, &post);
|
|
if (error)
|
|
fatal_error("Unable to load post table");
|
|
|
|
/* get face properties */
|
|
TT_Get_Face_Properties(face, &properties);
|
|
|
|
/* Load the instance. */
|
|
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");
|
|
|
|
/* Get the requested cmap. */
|
|
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);
|
|
}
|
|
|
|
/* malloc for glyph data */
|
|
error = TT_Get_CharMap(face, cmapindex, &cmap);
|
|
if (error)
|
|
fatal_error("Cannot load cmap");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* Get font infos: name, version, copyright.
|
|
*/
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
/*
|
|
* Load a glyph's outline and metrics.
|
|
*/
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
/*
|
|
* Get PS name of a glyph.
|
|
*/
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
/*
|
|
* Header of Type 1 font.
|
|
*/
|
|
|
|
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];
|
|
|
|
/* Get the current time with local representation */
|
|
curtime = time(NULL);
|
|
loctime = localtime(&curtime);
|
|
|
|
/* Get font infos: family name, version, notice */
|
|
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("/UnderlineThickness 50 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");
|
|
/* encoding vector */
|
|
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} |-");
|
|
/* Fputs("/password 5839 def"); */
|
|
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);
|
|
}
|
|
|
|
|
|
/*
|
|
* Tail of Type 1 font.
|
|
*/
|
|
|
|
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");
|
|
}
|
|
|
|
|
|
/*
|
|
* Use the `rrcurveto' command on more than one `off' points.
|
|
*/
|
|
|
|
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
|
|
|
|
|
|
/*
|
|
* Construct CharString of a glyph.
|
|
*/
|
|
|
|
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));
|
|
|
|
/* Begin string */
|
|
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
|
|
|
|
/* coordinates are all relative to (0,0) in FreeType */
|
|
fprintf(out, "0 %d hsbw\n", (int)(metrics.advance / 64));
|
|
|
|
/* Initialize ending contour point, relative coordinates */
|
|
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; /* start at least 1 */
|
|
|
|
/*
|
|
* data pts for all contours stored in one array.
|
|
* each round j init at last j + 1
|
|
*/
|
|
|
|
/*
|
|
* start_offpt means start of off points.
|
|
* 0 means no off points in record.
|
|
* N means the position of the off point.
|
|
* end_offpt means the ending off point.
|
|
* lastx, lasty is the last ON point from which Curve and Line
|
|
* shall start.
|
|
*/
|
|
|
|
/*
|
|
* start with j=0. into loop, j=1.
|
|
* if pt[1] off, if start_offpt == 0, toggle start_offpt
|
|
* next j=2. if on, now start_off != 0, run Curveto.
|
|
* if pt[1] on, start_off == 0, will run Lineto.
|
|
*/
|
|
|
|
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
|
|
{ /* On Curve */
|
|
if (start_offpt)
|
|
{
|
|
/*
|
|
* start_offpt stuck at j, end_offpt++.
|
|
* end_offpt - start_offpt gives no of off pts.
|
|
* start_offpt gives start of sequence.
|
|
* why need outline.xCoord[j] outline.yCoord[j]?
|
|
*/
|
|
|
|
PS_Curveto(out,
|
|
outline.points[j].x, outline.points[j].y,
|
|
start_offpt, end_offpt);
|
|
start_offpt = 0;
|
|
|
|
/*
|
|
* also use start_offpt as indicator to save one variable!!
|
|
* after curveto, reset condition.
|
|
*/
|
|
}
|
|
else
|
|
PS_Lineto(outline.points[j].x, outline.points[j].y);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* looks like closepath fst = first, i.e. go back to first
|
|
*/
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
/*
|
|
* Get code ranges of an encoding scheme either from
|
|
* the eVecMap or a code range file.
|
|
*/
|
|
|
|
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];
|
|
|
|
/* parse each code range line */
|
|
while (fgets(buf, buflen, enc) != NULL)
|
|
{
|
|
if (buf[0] != '#' && buf[0] != '\n')
|
|
{
|
|
if (strrchr(buf,':') != NULL)
|
|
{
|
|
/* if there is no high value declared before low value */
|
|
if (lByte != NULL)
|
|
{
|
|
if (cRange == NULL)
|
|
{
|
|
/* default code range `0x00-0x00:' */
|
|
cRange = re_alloc(cRange, ++numCR * sizeof (EVcRange),
|
|
"Get_EncVec");
|
|
cRange->high.start = cRange->high.end = 0;
|
|
}
|
|
/* Assign the last low value */
|
|
(cRange + numCR - 1)->low = lByte;
|
|
(cRange + numCR - 1)->numLowRanges = numLow;
|
|
}
|
|
|
|
/* New high byte range */
|
|
cRange = re_alloc(cRange, ++numCR * sizeof (EVcRange), "Get_EncVec");
|
|
(cRange + numCR - 1)->numLowRanges = numLow = 0;
|
|
lByte = NULL;
|
|
|
|
/* Parse code range */
|
|
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;
|
|
}
|
|
|
|
|
|
/*
|
|
* Match code ranges by a font plane.
|
|
*/
|
|
|
|
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; /* summed # of chars */
|
|
int nChar = (plane-1) * 256; /* the first char code ranges recorded */
|
|
int recording = 0;
|
|
|
|
/* if compact, plane starts from 1 to be */
|
|
/* compatible with the CJK package */
|
|
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 we have made a hit */
|
|
if (planeLow != NULL)
|
|
{ /* if low byte range has not been saved */
|
|
(planeCR + nCR - 1)->low = planeLow;
|
|
(planeCR + nCR - 1)->numLowRanges = nLow;
|
|
planeLow = NULL;
|
|
}
|
|
|
|
/* each new plane starts a EVcRange if */
|
|
/* iChar is still less than nChar */
|
|
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;
|
|
}
|
|
}
|
|
|
|
/* scan each low byte range */
|
|
for (ilow = 0; ilow < (numLow == 0 ? 1 : numLow); ilow++, pLow++)
|
|
{
|
|
int start, end, nLowChar;
|
|
|
|
if (numLow == 0)
|
|
{ /* default range */
|
|
start = 0x0;
|
|
end = 0xff;
|
|
}
|
|
else
|
|
{
|
|
start = pLow->start;
|
|
end = pLow->end;
|
|
}
|
|
nLowChar = end - start + 1;
|
|
if (iChar + nLowChar > nChar)
|
|
{ /* a hit! */
|
|
int bchar = start + nChar - iChar;
|
|
if (planeCR == NULL)
|
|
{
|
|
/* the first time code range is recorded */
|
|
planeCR = re_alloc(planeCR, ++nCR * sizeof (EVcRange),
|
|
"Get_PlaneEV");
|
|
(planeCR + nCR - 1)->high.start = ipl;
|
|
(planeCR + nCR - 1)->high.end = ipl;
|
|
}
|
|
|
|
/* adjust range boundary */
|
|
if (recording == 0)
|
|
start = bchar;
|
|
else
|
|
end = bchar;
|
|
nChar += 0xff;
|
|
|
|
/* recording starts */
|
|
recording++;
|
|
}
|
|
|
|
iChar += nLowChar; /* next range */
|
|
|
|
if (recording)
|
|
{
|
|
/* a new low range */
|
|
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)
|
|
{
|
|
/* beyond recording range */
|
|
(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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* we must finalize the ranges */
|
|
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;
|
|
}
|
|
|
|
|
|
/*
|
|
* The main subroutine for generating Type 1 fonts.
|
|
* One subfont per call.
|
|
*/
|
|
|
|
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;
|
|
}
|
|
|
|
/* Header of Type1 font */
|
|
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;
|
|
}
|
|
|
|
|
|
/*
|
|
* Main: process options, file I/O, etc.
|
|
*/
|
|
|
|
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];
|
|
|
|
/* set up known encoding vectors */
|
|
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')
|
|
{
|
|
/* Set the platform ID. Assumed upper bound is 64 */
|
|
if ((pid = atoi(argv[0])) < 0 || pid > 64)
|
|
/* Check the platform and encoding IDs. */
|
|
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++; /* no octal number */
|
|
sscanf(&argv[0][result], "%i", &plane);
|
|
}
|
|
break;
|
|
case 'e':
|
|
case 'E':
|
|
result = argv[0][2];
|
|
argc--;
|
|
argv++;
|
|
if (result == 'i' || result == 'I')
|
|
{
|
|
/* Set the encoding ID. */
|
|
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': /* Get the TTF file name. */
|
|
case 'T':
|
|
argc--;
|
|
argv++;
|
|
infile = argv[0];
|
|
break;
|
|
case 'o': /* Set the output file name. */
|
|
case 'O':
|
|
argc--;
|
|
argv++;
|
|
outfile = argv[0];
|
|
break;
|
|
case 's': /* shift font bbox up or down */
|
|
case 'S':
|
|
argc--;
|
|
argv++;
|
|
sscanf(argv[0], "%f", &fontShift);
|
|
break;
|
|
#ifdef DEBUG
|
|
case 'd': /* character code for debugging */
|
|
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
|
|
/* Set the input file name. */
|
|
infile = argv[0];
|
|
|
|
argc--;
|
|
argv++;
|
|
}
|
|
|
|
/* Open the output file if specified. */
|
|
if (outfile != NULL)
|
|
/* Attempt to open the output file. */
|
|
if ((out = fopen(outfile, "wt")) == 0)
|
|
{
|
|
fatal("Unable to open the output file `%s'", outfile);
|
|
exit(FAILURE);
|
|
}
|
|
|
|
/* Validate the values passed on the command line. */
|
|
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");
|
|
}
|
|
|
|
/* Initialize font engine */
|
|
if (!Init_Font_Engine(infile))
|
|
{
|
|
if (out != stdout)
|
|
{
|
|
fclose(out);
|
|
if (!keep)
|
|
(void)unlink(outfile);
|
|
}
|
|
exit(FAILURE);
|
|
}
|
|
|
|
/* Generate the disassembled PFB font from the TrueType font */
|
|
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; /* never reached */
|
|
}
|
|
|
|
|
|
/* end of ttf2pfb.c */
|