You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1597 lines
44 KiB
1597 lines
44 KiB
/* |
|
* Copyright 2008 Department of Mathematical Sciences, New Mexico State University |
|
* |
|
* Permission is hereby granted, free of charge, to any person obtaining a |
|
* copy of this software and associated documentation files (the "Software"), |
|
* to deal in the Software without restriction, including without limitation |
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
|
* and/or sell copies of the Software, and to permit persons to whom the |
|
* Software is furnished to do so, subject to the following conditions: |
|
* |
|
* The above copyright notice and this permission notice shall be included in |
|
* all copies or substantial portions of the Software. |
|
* |
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
* DEPARTMENT OF MATHEMATICAL SCIENCES OR NEW MEXICO STATE UNIVERSITY BE |
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF |
|
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
*/ |
|
|
|
#include <stdio.h> |
|
|
|
#ifdef WIN32 |
|
#include <windows.h> |
|
#else |
|
#include <stdlib.h> |
|
#include <unistd.h> |
|
#endif |
|
|
|
#include <string.h> |
|
|
|
#include <ft2build.h> |
|
#include FT_GLYPH_H |
|
#include FT_SFNT_NAMES_H |
|
#include FT_TRUETYPE_TABLES_H |
|
|
|
/* |
|
* Include the remapping support. |
|
*/ |
|
#include "remap.h" |
|
|
|
/************************************************************************** |
|
* |
|
* Macros. |
|
* |
|
**************************************************************************/ |
|
|
|
/* |
|
* The version of otf2bdf. |
|
*/ |
|
#define OTF2BDF_VERSION "3.0" |
|
|
|
/* |
|
* Set the default values used to generate a BDF font. |
|
*/ |
|
#ifndef DEFAULT_PLATFORM_ID |
|
#define DEFAULT_PLATFORM_ID 3 |
|
#endif |
|
|
|
#ifndef DEFAULT_ENCODING_ID |
|
#define DEFAULT_ENCODING_ID 1 |
|
#endif |
|
|
|
#ifndef DEFAULT_POINT_SIZE |
|
#define DEFAULT_POINT_SIZE 12 |
|
#endif |
|
|
|
#ifndef DEFAULT_RESOLUTION |
|
#define DEFAULT_RESOLUTION 100 |
|
#endif |
|
|
|
/* |
|
* Used as a fallback for XLFD names where the character set/encoding can not |
|
* be determined. |
|
*/ |
|
#ifndef DEFAULT_XLFD_CSET |
|
#define DEFAULT_XLFD_CSET "-FontSpecific-0" |
|
#endif |
|
|
|
/* |
|
* nameID macros for getting strings from the OT font. |
|
*/ |
|
#define BDFOTF_COPYRIGHT_STRING 0 |
|
#define BDFOTF_FAMILY_STRING 1 |
|
#define BDFOTF_SUBFAMILY_STRING 2 |
|
#define BDFOTF_UNIQUEID_STRING 3 |
|
#define BDFOTF_FULLNAME_STRING 4 |
|
#define BDFOTF_VENDOR_STRING 5 |
|
#define BDFOTF_POSTSCRIPT_STRING 6 |
|
#define BDFOTF_TRADEMARK_STRING 7 |
|
|
|
/* |
|
* String names for the string indexes. Used for error messages. |
|
*/ |
|
static char *string_names[] = { |
|
"\"Copyright\"", |
|
"\"Family\"", |
|
"\"SubFamily\"", |
|
"\"Unique ID\"", |
|
"\"Full Name\"", |
|
"\"Vendor\"", |
|
"\"Postscript Name\"", |
|
"\"Trademark\"" |
|
}; |
|
|
|
#if 0 |
|
#define TTF_COPYRIGHT 0 |
|
#define TTF_TYPEFACE 1 |
|
#define TTF_PSNAME 6 |
|
#endif |
|
|
|
#ifndef MAX |
|
#define MAX(h,i) ((h) > (i) ? (h) : (i)) |
|
#endif |
|
|
|
#ifndef MIN |
|
#define MIN(l,o) ((l) < (o) ? (l) : (o)) |
|
#endif |
|
|
|
/************************************************************************** |
|
* |
|
* General globals set from command line. |
|
* |
|
**************************************************************************/ |
|
|
|
/* |
|
* The program name. |
|
*/ |
|
static char *prog; |
|
|
|
/* |
|
* The flag indicating whether messages should be printed or not. |
|
*/ |
|
static int verbose = 0; |
|
|
|
/* |
|
* Flags used when loading glyphs. |
|
*/ |
|
static int load_flags = FT_LOAD_DEFAULT; |
|
|
|
/* |
|
* The default platform and encoding ID's. |
|
*/ |
|
static int pid = DEFAULT_PLATFORM_ID; |
|
static int eid = DEFAULT_ENCODING_ID; |
|
|
|
/* |
|
* Default point size and resolutions. |
|
*/ |
|
static int point_size = DEFAULT_POINT_SIZE; |
|
static int hres = DEFAULT_RESOLUTION; |
|
static int vres = DEFAULT_RESOLUTION; |
|
|
|
/* |
|
* The user supplied foundry name to use in the XLFD name. |
|
*/ |
|
static char *foundry_name = 0; |
|
|
|
/* |
|
* The user supplied typeface name to use in the XLFD name. |
|
*/ |
|
static char *face_name = 0; |
|
|
|
/* |
|
* The user supplied weight name to use in the XLFD name. |
|
*/ |
|
static char *weight_name = 0; |
|
|
|
/* |
|
* The user supplied slant name to use in the XLFD name. |
|
*/ |
|
static char *slant_name = 0; |
|
|
|
/* |
|
* The user supplied width name to use in the XLFD name. |
|
*/ |
|
static char *width_name = 0; |
|
|
|
/* |
|
* The user supplied additional style name to use in the XLFD name. |
|
*/ |
|
static char *style_name = 0; |
|
|
|
/* |
|
* The user supplied spacing (p = proportional, c = character cell, |
|
* m = monospace). |
|
*/ |
|
static int spacing = 0; |
|
|
|
/* |
|
* The dash character to use in the names retrieved from the font. Default is |
|
* the space. |
|
*/ |
|
static int dashchar = ' '; |
|
|
|
/* |
|
* Flag, bitmask, and max code for generating a subset of the glyphs in a font. |
|
*/ |
|
static int do_subset = 0; |
|
static unsigned short maxcode; |
|
static unsigned long subset[2048]; |
|
|
|
/* |
|
* The flag that indicates the remapping table should be used to |
|
* reencode the font. |
|
*/ |
|
static int do_remap = 0; |
|
|
|
/************************************************************************** |
|
* |
|
* Internal globals. |
|
* |
|
**************************************************************************/ |
|
|
|
/* |
|
* Structure used for calculating the font bounding box as the glyphs are |
|
* generated. |
|
*/ |
|
typedef struct { |
|
short minlb; |
|
short maxlb; |
|
short maxrb; |
|
short maxas; |
|
short maxds; |
|
short rbearing; |
|
} bbx_t; |
|
|
|
static bbx_t bbx; |
|
|
|
/* |
|
* The buffer used to transfer the temporary file to the actual output file. |
|
*/ |
|
#define OTF2BDF_IOBUFSIZ 8192 |
|
static char iobuf[OTF2BDF_IOBUFSIZ]; |
|
|
|
/* |
|
* The Units Per Em value used in numerous places. |
|
*/ |
|
static FT_UShort upm; |
|
|
|
/* |
|
* A flag indicating if a CMap was found or not. |
|
*/ |
|
static FT_UShort nocmap; |
|
|
|
/* |
|
* The scaling factor needed to compute the SWIDTH (scalable width) value |
|
* for BDF glyphs. |
|
*/ |
|
static double swscale; |
|
|
|
/************************************************************************** |
|
* |
|
* Platform and encoding table names. |
|
* |
|
**************************************************************************/ |
|
|
|
static char *platform_names[] = { |
|
"Apple Unicode", "Macintosh", "ISO", "Microsoft", "Unknown" |
|
}; |
|
static int nplatform_names = sizeof(platform_names)/sizeof(platform_names[0]); |
|
|
|
/* |
|
* Mac encoding names used when creating the BDF XLFD font name. |
|
*/ |
|
static char *mac_encodings[] = { |
|
"-MacRoman-0", "-MacJapanese-0", "-MacChinese-0", "-MacKorean-0", |
|
"-MacArabic-0", "-MacHebrew-0", "-MacGreek-0", "-MacRussian-0", |
|
"-MacRSymbol-0", "-MacDevanagari-0", "-MacGurmukhi-0", "-MacGujarati-0", |
|
"-MacOriya-0", "-MacBengali-0", "-MacTamil-0", "-MacTelugu-0", |
|
"-MacKannada-0", "-MacMalayalam-0", "-MacSinhalese-0", "-MacBurmese-0", |
|
"-MacKhmer-0", "-MacThai-0", "-MacLaotian-0", "-MacGeorgian-0", |
|
"-MacArmenian-0", "-MacMaldivian-0", "-MacTibetan-0", "-MacMongolian-0", |
|
"-MacGeez-0", "-MacSlavic-0", "-MacVietnamese-0","-MacSindhi-0", |
|
"-MacUninterp-0" |
|
}; |
|
static int nmac_encodings = sizeof(mac_encodings)/sizeof(mac_encodings[0]); |
|
|
|
/* |
|
* ISO encoding names used when creating the BDF XLFD font name. |
|
*/ |
|
static char *iso_encodings[] = { |
|
"-ASCII-0", "-ISO10646-1", "-ISO8859-1" |
|
}; |
|
static int niso_encodings = sizeof(iso_encodings)/sizeof(iso_encodings[0]); |
|
|
|
/* |
|
* Microsoft encoding names used when creating the BDF XLFD font name. |
|
*/ |
|
static char *ms_encodings[] = { |
|
"-Symbol-0", "-ISO10646-1", "-ShiftJIS-0", "-GB2312.1980-0", "-Big5-0", |
|
"-KSC5601.1987-0", "-KSC5601.1992-0" |
|
}; |
|
static int nms_encodings = sizeof(ms_encodings)/sizeof(ms_encodings[0]); |
|
|
|
/* |
|
* The propery names for all the XLFD properties. |
|
*/ |
|
static char *xlfd_props[] = { |
|
"FOUNDRY", |
|
"FAMILY_NAME", |
|
"WEIGHT_NAME", |
|
"SLANT", |
|
"SETWIDTH_NAME", |
|
"ADD_STYLE_NAME", |
|
"PIXEL_SIZE", |
|
"POINT_SIZE", |
|
"RESOLUTION_X", |
|
"RESOLUTION_Y", |
|
"SPACING", |
|
"AVERAGE_WIDTH", |
|
"CHARSET_REGISTRY", |
|
"CHARSET_ENCODING", |
|
}; |
|
|
|
/************************************************************************** |
|
* |
|
* Freetype globals. |
|
* |
|
**************************************************************************/ |
|
|
|
static FT_Library library; |
|
static FT_Face face; |
|
static FT_Size_Metrics imetrics; |
|
static TT_HoriHeader *horizontal; |
|
|
|
/************************************************************************** |
|
* |
|
* Freetype related code. |
|
* |
|
**************************************************************************/ |
|
|
|
/* |
|
* A generic routine to get a name from the OT name table. This routine |
|
* always looks for English language names and checks three possibilities: |
|
* 1. English names with the MS Unicode encoding ID. |
|
* 2. English names with the MS unknown encoding ID. |
|
* 3. English names with the Apple Unicode encoding ID. |
|
* |
|
* The particular name ID mut be provided (e.g. nameID = 0 for copyright |
|
* string, nameID = 6 for Postscript name, nameID = 1 for typeface name. |
|
* |
|
* If the `dash_to_space' flag is non-zero, all dashes (-) in the name will be |
|
* replaced with the character passed. |
|
* |
|
* Returns the number of bytes added. |
|
*/ |
|
static int |
|
otf_get_english_string(FT_Face face, int nameID, int dash_to_space, |
|
char *name, int name_size) |
|
{ |
|
int j, encid; |
|
FT_UInt i, nrec; |
|
FT_SfntName sfntName; |
|
unsigned char *s; |
|
unsigned short slen; |
|
|
|
nrec = FT_Get_Sfnt_Name_Count(face); |
|
|
|
for (encid = 1, j = 0; j < 2; j++, encid--) { |
|
/* |
|
* Locate one of the MS English font names. |
|
*/ |
|
for (i = 0; i < nrec; i++) { |
|
FT_Get_Sfnt_Name(face, i, &sfntName); |
|
if (sfntName.platform_id == 3 && |
|
sfntName.encoding_id == encid && |
|
sfntName.name_id == nameID && |
|
(sfntName.language_id == 0x0409 || |
|
sfntName.language_id == 0x0809 || |
|
sfntName.language_id == 0x0c09 || |
|
sfntName.language_id == 0x1009 || |
|
sfntName.language_id == 0x1409 || |
|
sfntName.language_id == 0x1809)) { |
|
s = sfntName.string; |
|
slen = sfntName.string_len; |
|
break; |
|
} |
|
} |
|
|
|
if (i < nrec) { |
|
if (slen >> 1 >= name_size) { |
|
fprintf(stderr, "%s: warning: %s string longer than buffer. Truncating to %d bytes.\n", prog, string_names[nameID], name_size); |
|
slen = name_size << 1; |
|
} |
|
|
|
/* |
|
* Found one of the MS English font names. The name is by |
|
* definition encoded in Unicode, so copy every second byte into |
|
* the `name' parameter, assuming there is enough space. |
|
*/ |
|
for (i = 1; i < slen; i += 2) { |
|
if (dash_to_space) |
|
*name++ = (s[i] != '-') ? s[i] : ' '; |
|
else if (s[i] == '\r' || s[i] == '\n') { |
|
if (s[i] == '\r' && i + 2 < slen && s[i + 2] == '\n') |
|
i += 2; |
|
*name++ = ' '; |
|
*name++ = ' '; |
|
} else |
|
*name++ = s[i]; |
|
} |
|
*name = 0; |
|
return (slen >> 1); |
|
} |
|
} |
|
|
|
/* |
|
* No MS English name found, attempt to find an Apple Unicode English |
|
* name. |
|
*/ |
|
for (i = 0; i < nrec; i++) { |
|
FT_Get_Sfnt_Name(face, i, &sfntName); |
|
if (sfntName.platform_id == 0 && sfntName.language_id == 0 && |
|
sfntName.name_id == nameID) { |
|
s = sfntName.string; |
|
slen = sfntName.string_len; |
|
break; |
|
} |
|
} |
|
|
|
if (i < nrec) { |
|
if (slen >> 1 >= name_size) { |
|
fprintf(stderr, "%s: warning: %s string longer than buffer. Truncating to %d bytes.\n", prog, string_names[nameID], name_size); |
|
slen = name_size << 1; |
|
} |
|
|
|
/* |
|
* Found the Apple Unicode English name. The name is by definition |
|
* encoded in Unicode, so copy every second byte into the `name' |
|
* parameter, assuming there is enough space. |
|
*/ |
|
for (i = 1; i < slen; i += 2) { |
|
if (dash_to_space) |
|
*name++ = (s[i] != '-') ? s[i] : ' '; |
|
else if (s[i] == '\r' || s[i] == '\n') { |
|
if (s[i] == '\r' && i + 2 < slen && s[i + 2] == '\n') |
|
i += 2; |
|
*name++ = ' '; |
|
*name++ = ' '; |
|
} else |
|
*name++ = s[i]; |
|
} |
|
*name = 0; |
|
return (slen >> 1); |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
/************************************************************************** |
|
* |
|
* Encoding table related functions. |
|
* |
|
**************************************************************************/ |
|
|
|
static char * |
|
platform_name(short pid) |
|
{ |
|
return (pid < nplatform_names) ? |
|
platform_names[pid] : platform_names[nplatform_names - 1]; |
|
} |
|
|
|
static char * |
|
encoding_name(short pid, short eid) |
|
{ |
|
int nnames; |
|
char **names; |
|
|
|
switch (pid) { |
|
case 0: return "-ISO10646-1"; |
|
case 1: |
|
nnames = nmac_encodings; |
|
names = mac_encodings; |
|
break; |
|
case 2: |
|
nnames = niso_encodings; |
|
names = iso_encodings; |
|
break; |
|
case 3: |
|
nnames = nms_encodings; |
|
names = ms_encodings; |
|
break; |
|
default: return "-Unknown-0"; |
|
} |
|
|
|
return (eid < nnames) ? names[eid] : "-Unknown-0"; |
|
} |
|
|
|
static char *spaces = " "; |
|
|
|
static void |
|
print_encoding_table(void) |
|
{ |
|
int ncmaps, i, j; |
|
short pid, eid, lasteid; |
|
char *np, *platform, encoding[64]; |
|
|
|
printf("Encoding tables available in the font:\n\n"); |
|
printf("Platform%.*sEncoding\n", 6, spaces); |
|
printf("-------------------------------------------\n"); |
|
printf("Default%.*sDefault%.*s(-pid %d -eid %d)\n", |
|
7, spaces, 7, spaces, DEFAULT_PLATFORM_ID, DEFAULT_ENCODING_ID); |
|
ncmaps = face->num_charmaps; |
|
for (lasteid = -1, i = 0; i < ncmaps; i++) { |
|
pid = face->charmaps[i]->platform_id; |
|
eid = face->charmaps[i]->encoding_id; |
|
platform = platform_name(pid); |
|
np = encoding_name(pid, eid); |
|
np++; |
|
for (j = 0; j < 63 && *np != '-'; np++, j++) |
|
encoding[j] = *np; |
|
encoding[j] = 0; |
|
/* |
|
* Typecast the result of 14-strlen(). This returns a size_t on |
|
* some platforms and causes a compilation warning. |
|
*/ |
|
printf("%s%.*s%s%.*s(-pid %hd -eid %hd)\n", |
|
platform, (int) (14 - strlen(platform)), spaces, |
|
encoding, (int) (14 - strlen(encoding)), spaces, pid, eid); |
|
} |
|
} |
|
|
|
/************************************************************************** |
|
* |
|
* General code. |
|
* |
|
**************************************************************************/ |
|
|
|
/* |
|
* Create an XLFD name. Assumes there is enough space in the string passed |
|
* to fit a reasonably long XLFD name into, up to the 256 byte maximum. |
|
*/ |
|
static void |
|
make_xlfd_name(char *name, int name_size, FT_Long awidth, int ismono) |
|
{ |
|
FT_Long i; |
|
FT_ULong val; |
|
char *r, *e; |
|
double dr, dp; |
|
TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); |
|
|
|
/* |
|
* Default the foundry name to "FreeType" in honor of the project and |
|
* because the foundry name is too difficult to automatically determine |
|
* from the names in TT fonts. But the user can provide his own. |
|
*/ |
|
if (foundry_name == 0) { |
|
(void) strcpy(name, "-FreeType"); |
|
name += 9; |
|
} else { |
|
*(name++)='-'; |
|
strcpy(name,foundry_name); |
|
name+=strlen(foundry_name); |
|
} |
|
|
|
/* |
|
* Add the typeface name from the font. The fallback default will be |
|
* "Unknown". |
|
*/ |
|
*name++ = '-'; |
|
if (face_name == 0) { |
|
if((i = otf_get_english_string(face, BDFOTF_FAMILY_STRING, dashchar, |
|
name, name_size))) |
|
name += i; |
|
else { |
|
(void) strcpy(name, "Unknown"); |
|
name += 7; |
|
} |
|
} else { |
|
(void) strcpy(name, face_name); |
|
name += strlen(face_name); |
|
} |
|
|
|
/* |
|
* Add the weight name. The default will be "Medium". |
|
*/ |
|
if (weight_name != 0) { |
|
sprintf(name, "-%s", weight_name); |
|
name += strlen(weight_name) + 1; |
|
} else { |
|
if (os2->fsSelection & 0x20) { |
|
(void) strcpy(name, "-Bold"); |
|
name += 5; |
|
} else { |
|
(void) strcpy(name, "-Medium"); |
|
name += 7; |
|
} |
|
} |
|
|
|
/* |
|
* Add the slant name. The default will be 'R'. |
|
*/ |
|
if (slant_name) { |
|
sprintf(name, "-%s", slant_name); |
|
name += strlen(slant_name) + 1; |
|
} else { |
|
*name++ = '-'; |
|
if (os2->fsSelection & 0x01) |
|
*name++ = 'I'; |
|
else |
|
*name++ = 'R'; |
|
} |
|
|
|
/* |
|
* Default the setwidth name to "Normal" but user can specify one. |
|
*/ |
|
if (width_name == 0) { |
|
(void) strcpy(name, "-Normal"); |
|
name += 7; |
|
} else { |
|
*(name++)='-'; |
|
(void) strcpy(name, width_name); |
|
name += strlen(width_name); |
|
} |
|
|
|
/* |
|
* Default the additional style name to NULL but user can specify one. |
|
*/ |
|
*name++ = '-'; |
|
if (style_name != 0) { |
|
(void) strcpy(name, style_name); |
|
name += strlen(style_name); |
|
} |
|
|
|
/* |
|
* Determine the pixel size from the point size and resolution. |
|
*/ |
|
dr = (double) vres; |
|
dp = (double) (point_size * 10); |
|
val = (unsigned long) (((dp * dr) / 722.7) + 0.5); |
|
|
|
/* |
|
* Set the pixel size, point size, and resolution. |
|
*/ |
|
sprintf(name, "-%ld-%d-%d-%d", val, point_size * 10, hres, vres); |
|
name += strlen(name); |
|
|
|
switch (spacing) { |
|
case 'p': case 'P': spacing = 'P'; break; |
|
case 'm': case 'M': spacing = 'M'; break; |
|
case 'c': case 'C': spacing = 'C'; break; |
|
default: spacing = 0; break; |
|
} |
|
|
|
/* |
|
* Set the spacing. |
|
*/ |
|
if (!spacing) |
|
spacing = (ismono) ? 'M' : 'P'; |
|
*name++ = '-'; |
|
*name++ = spacing; |
|
|
|
/* |
|
* Add the average width. |
|
*/ |
|
sprintf(name, "-%ld", awidth); |
|
name += strlen(name); |
|
|
|
/* |
|
* Check to see if the remapping table specified a registry and encoding |
|
* and use those if they both exist. |
|
*/ |
|
otf2bdf_remap_charset(&r, &e); |
|
if (r != 0 && e != 0) { |
|
sprintf(name, "-%s-%s", r, e); |
|
return; |
|
} |
|
|
|
/* |
|
* If the cmap for the platform and encoding id was not found, or the |
|
* platform id is unknown, assume the character set registry and encoding |
|
* are the XLFD default. |
|
*/ |
|
if (nocmap || pid > 3) |
|
(void) strcpy(name, DEFAULT_XLFD_CSET); |
|
else { |
|
/* |
|
* Finally, determine the character set registry and encoding from the |
|
* platform and encoding ID. |
|
*/ |
|
switch (pid) { |
|
case 0: |
|
/* |
|
* Apple Unicode platform, so "-Apple-Unicode" is the default. |
|
*/ |
|
(void) strcpy(name, "-Apple-Unicode"); |
|
break; |
|
case 1: |
|
/* |
|
* Macintosh platform, so choose from the Macintosh encoding |
|
* strings. |
|
*/ |
|
if (eid < 0 || eid >= nmac_encodings) |
|
(void) strcpy(name, DEFAULT_XLFD_CSET); |
|
else |
|
(void) strcpy(name, mac_encodings[eid]); |
|
break; |
|
case 2: |
|
/* |
|
* ISO platform, so choose from the ISO encoding strings. |
|
*/ |
|
if (eid < 0 || eid >= niso_encodings) |
|
(void) strcpy(name, DEFAULT_XLFD_CSET); |
|
else |
|
(void) strcpy(name, iso_encodings[eid]); |
|
break; |
|
case 3: |
|
/* |
|
* Microsoft platform, so choose from the MS encoding strings. |
|
*/ |
|
if (eid < 0 || eid >= nms_encodings) |
|
(void) strcpy(name, DEFAULT_XLFD_CSET); |
|
else |
|
(void) strcpy(name, ms_encodings[eid]); |
|
break; |
|
} |
|
} |
|
} |
|
|
|
static int |
|
generate_font(FILE *out, char *iname, char *oname) |
|
{ |
|
int eof, ismono, i; |
|
FILE *tmp; |
|
FT_Short x, y, dwidth, swidth; |
|
FT_Short y_off, x_off; |
|
FT_Long sx, sy, ex, ey, wd, ht; |
|
FT_Long code, idx, ng, aw; |
|
FT_UShort remapped_code; |
|
unsigned char *bp; |
|
double dw; |
|
char *xp, xlfd[BUFSIZ]; |
|
char *tmpdir, tmpfile[BUFSIZ]; |
|
|
|
imetrics = face->size->metrics; |
|
horizontal = FT_Get_Sfnt_Table(face, ft_sfnt_hhea); |
|
|
|
/* |
|
* Clear the BBX. |
|
*/ |
|
memset((char *) &bbx, 0, sizeof(bbx_t)); |
|
|
|
/* |
|
* Open a temporary file to store the bitmaps in until the exact number |
|
* of bitmaps are known. |
|
*/ |
|
if ((tmpdir = getenv("TMPDIR")) == 0) |
|
tmpdir = "/tmp"; |
|
sprintf(tmpfile, "%s/otf2bdf%ld", tmpdir, (long) getpid()); |
|
if ((tmp = fopen(tmpfile, "w")) == 0) { |
|
fprintf(stderr, "%s: unable to open temporary file '%s'.\n", |
|
prog, tmpfile); |
|
return -1; |
|
} |
|
|
|
/* |
|
* Calculate the scale factor for the SWIDTH field. |
|
*/ |
|
swscale = ((double) vres) * ((double) point_size); |
|
|
|
/* |
|
* Initialize the flag that tracks if the font is monowidth or not and |
|
* initialize the glyph width variable that is used for testing for a |
|
* monowidth font. |
|
*/ |
|
wd = 0xffff; |
|
ismono = 1; |
|
|
|
for (ng = code = 0, eof = 0, aw = 0; eof != EOF && code < 0xffff; code++) { |
|
|
|
/* |
|
* If a remap is indicated, attempt to remap the code. If a remapped |
|
* code is not found, then skip generating the glyph. |
|
*/ |
|
remapped_code = (FT_UShort) code; |
|
if (do_remap && !otf2bdf_remap(&remapped_code)) |
|
continue; |
|
|
|
/* |
|
* If a subset is being generated and the code is greater than the max |
|
* code of the subset, break out of the loop to avoid doing any more |
|
* work. |
|
*/ |
|
if (do_subset && remapped_code > maxcode) |
|
break; |
|
|
|
/* |
|
* If a subset is being generated and the index is not in the subset |
|
* bitmap, just continue. |
|
*/ |
|
if (do_subset && |
|
!(subset[remapped_code >> 5] & (1 << (remapped_code & 31)))) |
|
continue; |
|
|
|
if (nocmap) { |
|
if (code >= face->num_glyphs) |
|
|
|
/* |
|
* At this point, all the glyphs are done. |
|
*/ |
|
break; |
|
idx = code; |
|
} else |
|
idx = FT_Get_Char_Index(face, code); |
|
|
|
/* |
|
* If the glyph could not be loaded for some reason, or a subset is |
|
* being generated and the index is not in the subset bitmap, just |
|
* continue. |
|
*/ |
|
|
|
if (idx <= 0 || FT_Load_Glyph(face, idx, load_flags)) |
|
continue; |
|
|
|
if (FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO)) |
|
continue; |
|
|
|
/* |
|
* Determine the DWIDTH (device width, or advance width in TT terms) |
|
* and the SWIDTH (scalable width) values. |
|
*/ |
|
dwidth = face->glyph->metrics.horiAdvance >> 6; |
|
dw = (double) dwidth; |
|
swidth = (FT_Short) ((dw * 72000.0) / swscale); |
|
|
|
/* |
|
* Determine the actual bounding box of the glyph bitmap. Do not |
|
* forget that the glyph is rendered upside down! |
|
*/ |
|
sx = sy = 0xffff; |
|
ex = ey = 0; |
|
bp = face->glyph->bitmap.buffer; |
|
for (y = 0; y < face->glyph->bitmap.rows; y++) { |
|
for (x = 0; x < face->glyph->bitmap.width; x++) { |
|
if (bp[x >> 3] & (0x80 >> (x & 7))) { |
|
if (x < sx) sx = x; |
|
if (x > ex) ex = x; |
|
if (y < sy) sy = y; |
|
if (y > ey) ey = y; |
|
} |
|
} |
|
bp += face->glyph->bitmap.pitch; |
|
} |
|
|
|
/* |
|
* If the glyph is actually an empty bitmap, set the size to 0 all |
|
* around. |
|
*/ |
|
if (sx == 0xffff && sy == 0xffff && ex == 0 && ey == 0) |
|
sx = ex = sy = ey = 0; |
|
else { |
|
/* |
|
* Adjust the end points. |
|
*/ |
|
ex++; |
|
ey++; |
|
} |
|
|
|
/* |
|
* Increment the number of glyphs generated. |
|
*/ |
|
ng++; |
|
|
|
/* |
|
* Test to see if the font is going to be monowidth or not by |
|
* comparing the current glyph width against the last one. |
|
*/ |
|
if (wd != 0xffff && ismono && (ex - sx) + 1 != wd) |
|
ismono = 0; |
|
|
|
/* |
|
* Adjust the font bounding box. |
|
*/ |
|
wd = ex - sx; |
|
ht = ey - sy; |
|
x_off = sx + face->glyph->bitmap_left; |
|
y_off = sy + face->glyph->bitmap_top - face->glyph->bitmap.rows; |
|
|
|
bbx.maxas = MAX(bbx.maxas, ht + y_off); |
|
bbx.maxds = MAX(bbx.maxds, -y_off); |
|
bbx.rbearing = wd + x_off; |
|
bbx.maxrb = MAX(bbx.maxrb, bbx.rbearing); |
|
bbx.minlb = MIN(bbx.minlb, x_off); |
|
bbx.maxlb = MAX(bbx.maxlb, x_off); |
|
|
|
/* |
|
* Add to the average width accumulator. |
|
*/ |
|
aw += wd; |
|
|
|
/* |
|
* Print the bitmap header. |
|
*/ |
|
fprintf(tmp, "STARTCHAR %04lX\nENCODING %ld\n", code, |
|
(long) remapped_code); |
|
fprintf(tmp, "SWIDTH %hd 0\n", swidth); |
|
fprintf(tmp, "DWIDTH %hd 0\n", dwidth); |
|
fprintf(tmp, "BBX %ld %ld %hd %hd\n", wd, ht, x_off, y_off); |
|
|
|
/* |
|
* Check for an error return here in case the temporary file system |
|
* fills up or the file is deleted while it is being used. |
|
*/ |
|
eof = fprintf(tmp, "BITMAP\n"); |
|
|
|
bp = face->glyph->bitmap.buffer + (sy * face->glyph->bitmap.pitch); |
|
for (y = 0; eof != EOF && y < ey - sy; y++) { |
|
for (idx = 0, x = 0; eof != EOF && x < ex - sx; x++) { |
|
if (x > 0 && (x & 7) == 0) { |
|
/* |
|
* Print the next byte. |
|
*/ |
|
eof = fprintf(tmp, "%02lX", idx & 0xff); |
|
idx = 0; |
|
} |
|
if (bp[(x+sx) >> 3] & (0x80 >> ((x+sx) & 7))) |
|
idx |= (0x80 >> (x & 7)); |
|
} |
|
bp += face->glyph->bitmap.pitch; |
|
if (eof != EOF) |
|
/* |
|
* Because of the structure of the loop, the last byte should |
|
* always be printed. |
|
*/ |
|
fprintf(tmp, "%02lX\n", idx & 0xff); |
|
} |
|
if (eof != EOF) |
|
fprintf(tmp, "ENDCHAR\n"); |
|
} |
|
|
|
fclose(tmp); |
|
|
|
/* |
|
* If a write error occured, delete the temporary file and issue an error |
|
* message. |
|
*/ |
|
if (eof == EOF) { |
|
(void) unlink(tmpfile); |
|
fprintf(stderr, "%s: problem writing to temporary file '%s'.\n", |
|
prog, tmpfile); |
|
return -1; |
|
} |
|
|
|
/* |
|
* If no characters were generated, just unlink the temp file and issue a |
|
* warning. |
|
*/ |
|
if (ng == 0) { |
|
(void) unlink(tmpfile); |
|
fprintf(stderr, "%s: no glyphs generated from '%s'.\n", prog, iname); |
|
return -1; |
|
} |
|
|
|
/* |
|
* Reopen the temporary file so it can be copied to the actual output |
|
* file. |
|
*/ |
|
if ((tmp = fopen(tmpfile, "r")) == 0) { |
|
/* |
|
* Unable to open the file for read, so attempt to delete it and issue |
|
* an error message. |
|
*/ |
|
(void) unlink(tmpfile); |
|
fprintf(stderr, "%s: unable to open temporary file '%s' for read.\n", |
|
prog, tmpfile); |
|
return -1; |
|
} |
|
|
|
/* |
|
* Calculate the average width. |
|
*/ |
|
aw = (FT_Long) ((((double) aw / (double) ng) + 0.5) * 10.0); |
|
|
|
/* |
|
* Generate the XLFD font name. |
|
*/ |
|
make_xlfd_name(xlfd, sizeof(xlfd), aw, ismono); |
|
|
|
/* |
|
* Start writing the font out. |
|
*/ |
|
fprintf(out, "STARTFONT 2.1\n"); |
|
|
|
/* |
|
* Add the vanity comments. |
|
*/ |
|
fprintf(out, "COMMENT\n"); |
|
fprintf(out, "COMMENT Converted from OpenType font \"%s\" by \"%s %s\".\n", |
|
iname, prog, OTF2BDF_VERSION); |
|
fprintf(out, "COMMENT\n"); |
|
|
|
fprintf(out, "FONT %s\n", xlfd); |
|
fprintf(out, "SIZE %d %d %d\n", point_size, hres, vres); |
|
|
|
/* |
|
* Generate the font bounding box. |
|
*/ |
|
fprintf(out, "FONTBOUNDINGBOX %hd %hd %hd %hd\n", |
|
bbx.maxrb - bbx.minlb, bbx.maxas + bbx.maxds, |
|
bbx.minlb, -bbx.maxds); |
|
|
|
/* |
|
* Print the properties. |
|
*/ |
|
fprintf(out, "STARTPROPERTIES %hd\n", 19); |
|
|
|
/* |
|
* Print the font properties from the XLFD name. |
|
*/ |
|
for (i = 0, xp = xlfd; i < 14; i++) { |
|
/* |
|
* Print the XLFD property name. |
|
*/ |
|
fprintf(out, "%s ", xlfd_props[i]); |
|
|
|
/* |
|
* Make sure the ATOM properties are wrapped in double quotes. |
|
*/ |
|
if (i < 6 || i == 10 || i > 11) |
|
putc('"', out); |
|
|
|
/* |
|
* Skip the leading '-' in the XLFD name. |
|
*/ |
|
xp++; |
|
|
|
/* |
|
* Skip until the next '-' or NULL. |
|
*/ |
|
for (; *xp && *xp != '-'; xp++) |
|
putc(*xp, out); |
|
|
|
/* |
|
* Make sure the ATOM properties are wrapped in double quotes. |
|
*/ |
|
if (i < 6 || i == 10 || i > 11) |
|
putc('"', out); |
|
|
|
putc('\n', out); |
|
} |
|
|
|
/* |
|
* Make sure to add the FONT_ASCENT and FONT_DESCENT properties |
|
* because X11 can not live without them. |
|
*/ |
|
fprintf(out, "FONT_ASCENT %hd\nFONT_DESCENT %hd\n", |
|
(horizontal->Ascender * imetrics.y_ppem) / upm, |
|
-((horizontal->Descender * imetrics.y_ppem) / upm)); |
|
|
|
/* |
|
* Get the copyright string from the font. |
|
*/ |
|
(void) otf_get_english_string(face, BDFOTF_COPYRIGHT_STRING, 0, xlfd, |
|
sizeof(xlfd)); |
|
fprintf(out, "COPYRIGHT \"%s\"\n", xlfd); |
|
|
|
/* |
|
* Last, print the two user-defined properties _OTF_FONTFILE and |
|
* _OTF_PSNAME. _OTF_FONTFILE provides a reference to the original OT |
|
* font file which some systems can take advantage of, and _OTF_PSNAME |
|
* provides the Postscript name of the font if it exists. |
|
*/ |
|
(void) otf_get_english_string(face, BDFOTF_POSTSCRIPT_STRING, 0, xlfd, |
|
sizeof(xlfd)); |
|
fprintf(out, "_OTF_FONTFILE \"%s\"\n_OTF_PSNAME \"%s\"\n", iname, xlfd); |
|
|
|
fprintf(out, "ENDPROPERTIES\n"); |
|
|
|
/* |
|
* Print the actual number of glyphs to the output file. |
|
*/ |
|
eof = fprintf(out, "CHARS %ld\n", ng); |
|
|
|
/* |
|
* Copy the temporary file to the output file. |
|
*/ |
|
while (eof != EOF && (ng = fread(iobuf, 1, OTF2BDF_IOBUFSIZ, tmp))) { |
|
if (fwrite(iobuf, 1, ng, out) == 0) |
|
eof = EOF; |
|
} |
|
|
|
/* |
|
* Close the temporary file and delete it. |
|
*/ |
|
fclose(tmp); |
|
(void) unlink(tmpfile); |
|
|
|
/* |
|
* If an error occured when writing to the output file, issue a warning |
|
* and return. |
|
*/ |
|
if (eof == EOF) { |
|
fprintf(stderr, "%s: problem writing to output file '%s'.\n", |
|
prog, oname); |
|
return -1; |
|
} |
|
|
|
/* |
|
* End the font and do memory cleanup on the glyph and raster structures. |
|
*/ |
|
eof = fprintf(out, "ENDFONT\n"); |
|
|
|
return eof; |
|
} |
|
|
|
static int |
|
generate_bdf(FILE *out, char *iname, char *oname) |
|
{ |
|
FT_Long i; |
|
|
|
/* |
|
* Get the requested cmap. |
|
*/ |
|
for (i = 0; i < face->num_charmaps; i++) { |
|
if (face->charmaps[i]->platform_id == pid && |
|
face->charmaps[i]->encoding_id == eid) |
|
break; |
|
} |
|
if (i == face->num_charmaps && pid == 3 && eid == 1) { |
|
/* |
|
* Make a special case when this fails with pid == 3 and eid == 1. |
|
* Change to eid == 0 and try again. This captures the two possible |
|
* cases for MS fonts. Some other method should be used to cycle |
|
* through all the alternatives later. |
|
*/ |
|
for (i = 0; i < face->num_charmaps; i++) { |
|
if (face->charmaps[i]->platform_id == pid && |
|
face->charmaps[i]->encoding_id == 0) |
|
break; |
|
} |
|
if (i < face->num_charmaps) { |
|
pid = 3; |
|
eid = 1; |
|
FT_Set_Charmap(face, face->charmaps[i]); |
|
} else { |
|
/* |
|
* No CMAP was found. |
|
*/ |
|
nocmap = 1; |
|
pid = eid = -1; |
|
} |
|
} else { |
|
FT_Set_Charmap(face, face->charmaps[i]); |
|
nocmap = 0; |
|
} |
|
|
|
if (nocmap && verbose) { |
|
fprintf(stderr, |
|
"%s: no character map for platform %d encoding %d. ", |
|
prog, pid, eid); |
|
fprintf(stderr, "Generating all glyphs.\n"); |
|
} |
|
|
|
/* |
|
* Now go through and generate the glyph bitmaps themselves. |
|
*/ |
|
return generate_font(out, iname, oname); |
|
} |
|
|
|
#define isdig(cc) ((cc) >= '0' && (cc) <= '9') |
|
|
|
/* |
|
* Routine to parse a subset specification supplied on the command line. |
|
* The syntax for this specification is the same as the syntax used for |
|
* the XLFD font names (XLFD documentation, page 9). |
|
* |
|
* Example: |
|
* |
|
* "60 70 80_90" means the glyphs at codes 60, 70, and between 80 and |
|
* 90 inclusive. |
|
*/ |
|
static void |
|
parse_subset(char *s) |
|
{ |
|
long l, r; |
|
|
|
/* |
|
* Make sure to clear the flag and bitmap in case more than one subset is |
|
* specified on the command line. |
|
*/ |
|
maxcode = 0; |
|
do_subset = 0; |
|
(void) memset((char *) subset, 0, sizeof(unsigned long) * 2048); |
|
|
|
while (*s) { |
|
/* |
|
* Collect the next code value. |
|
*/ |
|
for (l = r = 0; *s && isdig(*s); s++) |
|
l = (l * 10) + (*s - '0'); |
|
|
|
/* |
|
* If the next character is an '_', advance and collect the end of the |
|
* specified range. |
|
*/ |
|
if (*s == '_') { |
|
s++; |
|
for (; *s && isdig(*s); s++) |
|
r = (r * 10) + (*s - '0'); |
|
} else |
|
r = l; |
|
|
|
/* |
|
* Add the range just collected to the subset bitmap and set the flag |
|
* that indicates a subset is wanted. |
|
*/ |
|
for (; l <= r; l++) { |
|
do_subset = 1; |
|
subset[l >> 5] |= (1 << (l & 31)); |
|
if (l > maxcode) |
|
maxcode = l; |
|
} |
|
|
|
/* |
|
* Skip all non-digit characters. |
|
*/ |
|
while (*s && !isdig(*s)) |
|
s++; |
|
} |
|
} |
|
|
|
static void |
|
usage(int eval) |
|
{ |
|
printf("Usage: %s [options below] font.ttf\n", prog); |
|
printf("-h\t\tThis message.\n"); |
|
printf("-v\t\tPrint warning messages during conversion.\n"); |
|
printf("-l \"subset\"\tSpecify a subset of glyphs to generate.\n"); |
|
printf("-m mapfile\tGlyph reencoding file.\n"); |
|
printf("-n\t\tTurn off glyph hinting.\n"); |
|
printf("-a\t\tForce auto hinting.\n"); |
|
printf("-et\t\tDisplay the encoding tables available in the font.\n"); |
|
printf("-c c\t\tSet the character spacing (default: from font).\n"); |
|
printf("-f name\t\tSet the foundry name (default: freetype).\n"); |
|
printf("-t name\t\tSet the typeface name (default: from font).\n"); |
|
printf("-w name\t\tSet the weight name (default: Medium).\n"); |
|
printf("-s name\t\tSet the slant name (default: R).\n"); |
|
printf("-k name\t\tSet the width name (default: Normal).\n"); |
|
printf("-d name\t\tSet the additional style name (default: empty).\n"); |
|
printf("-u char\t\tSet the character to replace '-' in names "); |
|
printf("(default: space).\n"); |
|
printf("-pid id\t\tSet the platform ID for encoding (default: %d).\n", |
|
DEFAULT_PLATFORM_ID); |
|
printf("-eid id\t\tSet the encoding ID for encoding (default: %d).\n", |
|
DEFAULT_ENCODING_ID); |
|
printf("-p n\t\tSet the point size (default: %dpt).\n", |
|
DEFAULT_POINT_SIZE); |
|
printf("-r n\t\tSet the horizontal and vertical resolution "); |
|
printf("(default: %ddpi).\n", DEFAULT_RESOLUTION); |
|
printf("-rh n\t\tSet the horizontal resolution "); |
|
printf("(default: %ddpi)\n", DEFAULT_RESOLUTION); |
|
printf("-rv n\t\tSet the vertical resolution "); |
|
printf("(default: %ddpi)\n", DEFAULT_RESOLUTION); |
|
printf("-o outfile\tSet the output filename (default: stdout).\n"); |
|
exit(eval); |
|
} |
|
|
|
int |
|
main(int argc, char *argv[]) |
|
{ |
|
int res, pet; |
|
char *infile, *outfile, *iname, *oname; |
|
FILE *out, *mapin; |
|
|
|
if ((prog = strrchr(argv[0], '/'))) |
|
prog++; |
|
else |
|
prog = argv[0]; |
|
|
|
/* |
|
* Flag indicating whether the encoding tables are supposed to be printed |
|
* or not. |
|
*/ |
|
pet = 0; |
|
|
|
out = stdout; |
|
infile = outfile = 0; |
|
|
|
argc--; |
|
argv++; |
|
|
|
while (argc > 0) { |
|
if (argv[0][0] == '-') { |
|
switch (argv[0][1]) { |
|
case 'v': case 'V': |
|
verbose = 1; |
|
break; |
|
case 'l': case 'L': |
|
argc--; |
|
argv++; |
|
parse_subset(argv[0]); |
|
break; |
|
case 'n': case 'N': |
|
load_flags |= FT_LOAD_NO_HINTING; |
|
break; |
|
case 'a': case 'A': |
|
load_flags |= FT_LOAD_FORCE_AUTOHINT; |
|
break; |
|
case 'c': case 'C': |
|
argc--; |
|
argv++; |
|
spacing = argv[0][0]; |
|
break; |
|
case 't': case 'T': |
|
argc--; |
|
argv++; |
|
face_name = argv[0]; |
|
break; |
|
case 'w': case 'W': |
|
argc--; |
|
argv++; |
|
weight_name = argv[0]; |
|
break; |
|
case 's': case 'S': |
|
argc--; |
|
argv++; |
|
slant_name = argv[0]; |
|
break; |
|
case 'k': case 'K': |
|
argc--; |
|
argv++; |
|
width_name = argv[0]; |
|
break; |
|
case 'd': case 'D': |
|
argc--; |
|
argv++; |
|
style_name = argv[0]; |
|
break; |
|
case 'f': case 'F': |
|
argc--; |
|
argv++; |
|
foundry_name = argv[0]; |
|
break; |
|
case 'u': case 'U': |
|
argc--; |
|
argv++; |
|
dashchar = argv[0][0]; |
|
break; |
|
case 'p': case 'P': |
|
res = argv[0][2]; |
|
argc--; |
|
argv++; |
|
if (res == 'i' || res == 'I') { |
|
/* |
|
* No need to print the encoding tables if the user |
|
* is supplying a platform ID. |
|
*/ |
|
pet = 0; |
|
|
|
/* |
|
* Set the platform ID. |
|
*/ |
|
pid = atoi(argv[0]); |
|
} else |
|
/* |
|
* Set the point size. |
|
*/ |
|
point_size = atoi(argv[0]); |
|
break; |
|
case 'e': case 'E': |
|
if (argv[0][2] == 't' || argv[0][2] == 'T') |
|
pet = 1; |
|
else { |
|
/* |
|
* No need to print the encoding tables if the user |
|
* is supplying a platform ID. |
|
*/ |
|
pet = 0; |
|
|
|
/* |
|
* Set the encoding ID. |
|
*/ |
|
argc--; |
|
argv++; |
|
eid = atoi(argv[0]); |
|
} |
|
break; |
|
case 'r': |
|
/* |
|
* Set the horizontal and vertical resolutions. |
|
*/ |
|
if (argv[0][2] == 'h') |
|
hres = atoi(argv[1]); |
|
else if (argv[0][2] == 'v') |
|
vres = atoi(argv[1]); |
|
else |
|
hres = vres = atoi(argv[1]); |
|
argc--; |
|
argv++; |
|
break; |
|
case 'm': case 'M': |
|
/* |
|
* Try to load a remap table. |
|
*/ |
|
argc--; |
|
argv++; |
|
|
|
/* |
|
* Always reset the `do_remap' variable here in case more than |
|
* one map file appears on the command line. |
|
*/ |
|
do_remap = 0; |
|
if ((mapin = fopen(argv[0], "r")) == 0) |
|
fprintf(stderr, "%s: unable to open the remap table '%s'.\n", |
|
prog, argv[0]); |
|
else { |
|
if (otf2bdf_load_map(mapin) < 0) { |
|
fprintf(stderr, |
|
"%s: problem loading remap table '%s'.\n", |
|
prog, argv[0]); |
|
do_remap = 0; |
|
} else |
|
do_remap = 1; |
|
fclose(mapin); |
|
} |
|
break; |
|
case 'o': case 'O': |
|
/* |
|
* Set the output file name. |
|
*/ |
|
argc--; |
|
argv++; |
|
outfile = argv[0]; |
|
break; |
|
default: |
|
usage(1); |
|
} |
|
} else |
|
/* |
|
* Set the input file name. |
|
*/ |
|
infile = argv[0]; |
|
|
|
argc--; |
|
argv++; |
|
} |
|
|
|
/* |
|
* Validate the values passed on the command line. |
|
*/ |
|
if (infile == 0) { |
|
fprintf(stderr, "%s: no input file provided.\n", prog); |
|
usage(1); |
|
} |
|
/* |
|
* Set the input filename that will be passed to the generator |
|
* routine. |
|
*/ |
|
if ((iname = strrchr(infile, '/'))) |
|
iname++; |
|
else |
|
iname = infile; |
|
|
|
/* |
|
* Check the platform and encoding IDs. |
|
*/ |
|
if (pid < 0 || pid > 255) { |
|
fprintf(stderr, "%s: invalid platform ID '%d'.\n", prog, pid); |
|
exit(1); |
|
} |
|
if (eid < 0 || eid > 65535) { |
|
fprintf(stderr, "%s: invalid encoding ID '%d'.\n", prog, eid); |
|
exit(1); |
|
} |
|
|
|
/* |
|
* Arbitrarily limit the point size to a minimum of 2pt and maximum of |
|
* 256pt. |
|
*/ |
|
if (point_size < 2 || point_size > 256) { |
|
fprintf(stderr, "%s: invalid point size '%dpt'.\n", prog, point_size); |
|
exit(1); |
|
} |
|
|
|
/* |
|
* Arbitrarily limit the resolutions to a minimum of 10dpi and a maximum |
|
* of 1200dpi. |
|
*/ |
|
if (hres < 10 || hres > 1200) { |
|
fprintf(stderr, "%s: invalid horizontal resolution '%ddpi'.\n", |
|
prog, hres); |
|
exit(1); |
|
} |
|
if (vres < 10 || vres > 1200) { |
|
fprintf(stderr, "%s: invalid vertical resolution '%ddpi'.\n", |
|
prog, vres); |
|
exit(1); |
|
} |
|
|
|
/* |
|
* Open the output file if specified. |
|
*/ |
|
if (outfile != 0) { |
|
/* |
|
* Attempt to open the output file. |
|
*/ |
|
if ((out = fopen(outfile, "w")) == 0) { |
|
fprintf(stderr, "%s: unable to open the output file '%s'.\n", |
|
prog, outfile); |
|
exit(1); |
|
} |
|
/* |
|
* Set the output filename to be passed to the generator routine. |
|
*/ |
|
if ((oname = strrchr(outfile, '/'))) |
|
oname++; |
|
else |
|
oname = outfile; |
|
} else |
|
/* |
|
* Set the default output file name to <stdout>. |
|
*/ |
|
oname = "<stdout>"; |
|
|
|
/* |
|
* Intialize Freetype. |
|
*/ |
|
if ((res = FT_Init_FreeType(&library))) { |
|
/* |
|
* Close the output file. |
|
*/ |
|
if (out != stdout) { |
|
fclose(out); |
|
(void) unlink(outfile); |
|
} |
|
fprintf(stderr, "%s[%d]: unable to initialize renderer.\n", |
|
prog, res); |
|
exit(1); |
|
} |
|
|
|
/* |
|
* Open the input file. |
|
*/ |
|
if ((res = FT_New_Face(library, infile, 0, &face))) { |
|
if (out != stdout) { |
|
fclose(out); |
|
(void) unlink(outfile); |
|
} |
|
fprintf(stderr, "%s[%d]: unable to open input file '%s'.\n", |
|
prog, res, infile); |
|
exit(1); |
|
} |
|
|
|
if (pet) |
|
/* |
|
* Simply print the encoding tables and do nothing else. |
|
*/ |
|
print_encoding_table(); |
|
else { |
|
/* |
|
* Set the instance resolution and point size and the relevant |
|
* metrics. |
|
*/ |
|
FT_Set_Char_Size(face, 0, point_size * 64, hres, vres); |
|
|
|
/* |
|
* Set the global units per em value for convenience. |
|
*/ |
|
upm = face->units_per_EM; |
|
|
|
/* |
|
* Generate the BDF font from the TrueType font. |
|
*/ |
|
res = generate_bdf(out, iname, oname); |
|
} |
|
|
|
/* |
|
* Free up the mapping table if one was loaded. |
|
*/ |
|
otf2bdf_free_map(); |
|
|
|
/* |
|
* Close the input and output files. |
|
*/ |
|
(void) FT_Done_Face(face); |
|
if (out != stdout) { |
|
fclose(out); |
|
if (res < 0) |
|
/* |
|
* An error occured when generating the font, so delete the |
|
* output file. |
|
*/ |
|
(void) unlink(outfile); |
|
} |
|
|
|
/* |
|
* Shut down the renderer. |
|
*/ |
|
FT_Done_FreeType(library); |
|
|
|
exit(res); |
|
|
|
return 0; |
|
}
|
|
|