home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Languages Around the World
/
LanguageWorld.iso
/
psfonts
/
pfm2afm.c
< prev
next >
Wrap
Text File
|
1993-10-29
|
15KB
|
505 lines
/********************************************************************
* *
* Title: pfm2afm - Convert Windows .pfm files to .afm files *
* *
* Author: Ken Borgendale 10/9/91 Version 1.0 *
* *
* Function: *
* Convert a Windows .pfm (Printer Font Metrics) file to a *
* .afm (Adobe Font Metrics) file. The purpose of this is *
* to allow fonts put out for Windows to be used with OS/2. *
* *
* Syntax: *
* pfm2afm infile [outfile] -a *
* *
* Copyright: *
* pfm2afm - Copyright (C) IBM Corp., 1991 *
* *
* This code is released for public use as long as the *
* copyright remains intact. This code is provided asis *
* without any warrenties, express or implied. *
* *
* Notes: *
* 1. Much of the information in the original .afm file is *
* lost when the .pfm file is created, and thus cannot be *
* reconstructed by this utility. This is especially true *
* of data for characters not in the Windows character set. *
* *
* 2. This module is coded to be compiled by the MSC 6.0. *
* For other compilers, be careful of the packing of the *
* PFM structure. *
* *
********************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "pfm2afm.h"
#define BUFSIZE 4096
/*
* Function Prototypes
*/
void help (void);
void parseargs (int argc, uchar * * argv);
void openpfm(void);
void openafm(void);
void putheader(void);
void putchartab(void);
void outchar(int code, ushort width, const uchar * name);
void putkerntab(KERN * kerntab, int kerncnt);
void puttrailer(void);
void outval(int val);
/*
* Global variables
*/
FILE * inf; /* Input file */
FILE * outf; /* Output file */
uchar infname[272]; /* Input file name */
uchar outfname[272]; /* Output file name */
uchar * buffer; /* .pfm read buffer */
PFM * pfm; /* .pfm header */
PSX * psx; /* Metrics extension */
uchar debugflag; /* Debug information flag */
uchar allflag;
uchar isMono; /* Font is mono-spaced */
/*
* Do the function
*/
MAINENT main(int argc, uchar * *argv) {
/* Parse arguments */
parseargs(argc, argv);
/* Open and check input file */
openpfm();
/* Make output file name and open */
openafm();
/* Put out header information */
putheader();
/* Put out character table */
putchartab();
/* Put out kerning table */
if (pfm->kernpairs) {
putkerntab((KERN *)(buffer+pfm->kernpairs+2),
*(ushort *)(buffer+pfm->kernpairs));
}
/* Put out trailer line */
puttrailer();
/* Cleanup */
if (buffer)
free(buffer);
fclose(inf);
fclose(outf);
return 0;
}
/*
* Put out normal help
*/
void help (void) {
puts("\npfm2afm - Convert Windows pfm to afm - Version 1.0\n");
puts("This utility converts Windows pfm files for Adobe type 1 fonts");
puts("to afm files for use on OS/2. This allows fonts created for");
puts("Windows, and shipped without the afm file to be used on OS/2.\n");
puts("pfm2afm infile [outfile] -opts");
puts(" The extension .pfm is added to the infile if it has none.");
puts(" The outfile is defaulted from the input file name.");
puts(" -a = All codepoints in range");
puts("\nNote that pfm files are missing some of the data necessary to");
puts("construct afm files, so the conversion may not be perfect.\n");
puts("Ken Borgendale - kwb@betasvm2.vnet.ibm.com\n");
exit (1);
}
/*
* Parse arguments. This is the full arg treatment, which is sort of
* overkill for one option, but it allows more to be added later.
*/
void parseargs (int argc, uchar * * argv) {
uchar swchar;
int argcnt;
int filecnt;
uchar * argp;
argcnt = 1;
filecnt = 0;
/* Read the arguments and decide what we are doing */
while (argcnt<argc) {
argp = argv[argcnt];
/* Check for switches. Files may not start with - or / */
if (*argp == '-' || *argp == OPTSEP) {
/* Process switches */
swchar = (uchar)tolower(argp[1]);
argp += 2;
switch (swchar) {
case '?':
help(); /* Does not return */
/* All codepoints */
case 'a':
allflag = 0;
break;
/* Debug option */
case 'd':
debugflag = 1;
break;
default:
fputs("Unknown options: ", stderr);
fputs(argp-2, stderr);
fputc('\n', stderr);
}
} else {
if (*argp=='?') {
help(); /* Does not return */
}
switch(++filecnt) {
case 1:
strcpy(infname, argp);
break;
case 2:
strcpy(outfname, argp);
break;
default:
fputs("Extra parameter ignored: ", stderr);
fputs(argp, stderr);
fputc('\n', stderr);
}
}
argcnt++;
}
/* We require the input file name */
if (!filecnt) help();
}
/*
* Open the .pfm file and check it
*/
void openpfm(void) {
uchar * cp;
int len;
/* Check for a file extension */
cp = infname+strlen(infname)-1;
while (cp>=infname && *cp!='.' && *cp!='\\' && *cp!='/' && *cp!=':')
cp--;
if (*cp!='.')
strcat(infname, ".pfm");
/* Open the file */
inf = fopen(infname, "rb");
if (!inf) {
fputs("Unable to open input file - ", stderr);
fputs(infname, stderr);
fputc('\n', stderr);
exit(4);
}
/* Read the file */
buffer = malloc(BUFSIZE);
len = fread(buffer, 1, BUFSIZE, inf);
if (len<256 || len==BUFSIZE) {
fputs("Input file read error - ", stderr);
fputs(infname, stderr);
fputc('\n', stderr);
exit(6);
}
/* Do consistency check */
pfm = (PFM *) buffer;
if (len != (int)pfm->len && /* Check length field matches file length */
pfm->extlen != 30 && /* Check length of PostScript extension */
pfm->fontname>75 && pfm->fontname<512) { /* Font name specified */
fputs("Not a valid Windows type 1 .pfm file - ", stderr);
fputs(infname, stderr);
fputc('\n', stderr);
exit(6);
}
}
/*
* Create the .afm file
*/
void openafm(void) {
uchar * cp;
/* Add .pfm if there is none */
if (!*outfname) {
strcpy(outfname, infname);
cp = outfname+strlen(outfname)-1;
while (cp >= outfname && *cp!='.' && *cp!='\\' && *cp!='/' && *cp!=':')
cp--;
if (*cp=='.') *cp=0;
strcat(outfname, ".afm");
}
/* Open the file */
outf = fopen(outfname, "w");
if (!outf) {
fputs("Unable to open output file - ", stderr);
fputs(outfname, stderr);
fputc('\n', stderr);
exit(5);
}
}
/*
* Put out the header of the .afm file
*/
void putheader(void) {
uchar * cp;
fputs("StartFontMetrics 2.0\n", outf);
if (*pfm->copyright) {
fputs("Comment ", outf);
fputs(pfm->copyright, outf);
fputc('\n', outf);
}
fputs("FontName ", outf);
fputs(buffer+pfm->fontname, outf);
fputs("\nEncodingScheme ", outf);
if (pfm->charset) {
fputs("FontSpecific\n", outf);
} else {
fputs("AdobeStandardEncoding\n", outf);
}
/*
* The .pfm is missing full name, so construct from font name by
* changing the hyphen to a space. This actually works in a lot
* of cases.
*/
fputs("FullName ", outf);
cp = buffer+pfm->fontname;
while (*cp) {
if (*cp=='-') *cp=' ';
fputc(*cp, outf);
cp++;
}
if (pfm->face) {
fputs("\nFamilyName ", outf);
fputs(buffer+pfm->face, outf);
}
fputs("\nWeight ", outf);
if (pfm->weight>475) fputs("Bold", outf);
else if (pfm->weight<325 && pfm->weight)
fputs("Light", outf);
else fputs("Medium", outf);
/*
* The mono flag in the pfm actually indicates whether there is a
* table of font widths, not if they are all the same.
*/
fputs("\nIsFixedPitch ", outf);
if (!(pfm->kind&1) || /* Flag for mono */
pfm->avgwidth == pfm->maxwidth ) { /* Avg width = max width */
fputs("true", outf);
isMono = 1;
} else {
fputs("false", outf);
isMono = 0;
}
/*
* The font bounding box is lost, but try to reconstruct it.
* Much of this is just guess work. The bounding box is required in
* the .afm, but is not used by the PM font installer.
*/
psx = (PSX *)(buffer+pfm->psext);
fputs("\nFontBBox", outf);
if (isMono) outval(-20); /* Just guess at left bounds */
else outval(-100);
outval(-(psx->descender+5)); /* Descender is given as positive value */
outval(pfm->maxwidth+10);
outval(pfm->ascent+5);
/*
* Give other metrics that were kept
*/
fputs("\nCapHeight", outf);
outval((int)psx->capheight);
fputs("\nXHeight", outf);
outval((int)psx->xheight);
fputs("\nDescender", outf);
outval((int)psx->descender);
fputs("\nAscender", outf);
outval((int)psx->ascender);
fputc('\n', outf);
}
/*
* Put out the character tables. According to the .afm spec, the
* characters must be put out sorted in encoding order.
*
* Most Windows .pfm files have the characters in the range 20-ff in
* the Windows code page (819 + quotes).
*/
void putchartab(void) {
int count, i, j;
ushort spwidth;
ushort * ctab;
uchar back[256];
/*
* Compute the count by getting rid of non-existant chars. This
* is complicated by the fact that Windows encodes the .pfm file
* with a space metric for non-existant chars.
*/
memset(back, 0, 256);
count = pfm->lastchar - pfm->firstchar + 1;
spwidth = 0;
/* Compute width of space */
ctab = (ushort *)(buffer+pfm->chartab);
if (pfm->firstchar>=' ' && pfm->lastchar<=' ') {
spwidth = ctab[' '-pfm->firstchar];
}
if (!pfm->charset) {
/*
* Loop thru the chars, deleting those that we presume
* do not really exist.
*/
for (i=pfm->firstchar; i<=(int)pfm->lastchar; i++) {
if (Win2PSStd[i]) {
back[Win2PSStd[i]] = (uchar)i;
} else {
if (!allflag) {
if (*ctab==spwidth) { /* Default width */
if (!(WinClass[i]&1)) {
*ctab = 0;
count--;
}
} else { /* Not default width */
if (!WinClass[i]) {
*ctab = 0;
count--;
}
}
}
}
ctab++;
}
}
/* Put out the header */
fputs("StartCharMetrics", outf);
outval(count);
fputc('\n', outf);
/* Put out all encoded chars */
if (pfm->charset) {
/*
* If the charset is not the Windows standard, just put out
* unnamed entries.
*/
ctab = (ushort *)(buffer+pfm->chartab);
for (i=pfm->firstchar; i<=(int)pfm->lastchar; i++) {
if (*ctab) {
outchar(i, *ctab, NULL);
}
ctab++;
}
} else {
ctab = (ushort *)(buffer+pfm->chartab);
for (i=0; i<256; i++) {
j = back[i];
if (j) {
outchar(i, ctab[j-pfm->firstchar], WinChars[j]);
ctab[j-pfm->firstchar] = 0;
}
}
/* Put out all non-encoded chars */
ctab = (ushort *)(buffer+pfm->chartab);
for (i=pfm->firstchar; i<=(int)pfm->lastchar; i++) {
if (*ctab) {
outchar(-1, *ctab, WinChars[i]);
}
ctab++;
}
}
/* Put out the trailer */
fputs("EndCharMetrics\n", outf);
}
/*
* Output a character entry
*/
void outchar(int code, ushort width, const uchar * name) {
fputs("C ", outf);
outval(code);
fputs(" ; WX ", outf);
outval(width);
if (name) {
fputs(" ; N ", outf);
fputs(name, outf);
}
fputs(" ;\n", outf);
}
/*
* Put out the kerning tables
*/
void putkerntab(KERN * kerntab, int kerncnt) {
int count, i;
KERN * kp;
/* Count non-zero kern pairs */
count = kerncnt;
kp = kerntab;
for (i=0; i<kerncnt; i++) {
if (!kp->kern)
count--;
kp++;
}
/* Put out header */
fputs("StartKernData\nStartKernPairs", outf);
outval(count);
fputc('\n', outf);
/* Put out each non-zero pair */
kp = kerntab;
while (kerncnt) {
if (kp->kern) {
fputs("KPX ", outf);
fputs(WinChars[kp->first], outf);
fputc(' ', outf);
fputs(WinChars[kp->second], outf);
outval((int)kp->kern);
fputc('\n', outf);
}
kp++;
kerncnt--;
}
/* Put out trailer */
fputs("EndKernPairs\nEndKernData\n", outf);
}
/*
* Put out the trailer of the .afm file
*/
void puttrailer(void) {
fputs("EndFontMetrics\n", outf);
}
/*
* Output a decimal value
*/
void outval(int v) {
char chx[16];
itoa(v, chx, 10);
fputc(' ', outf);
fputs(chx, outf);
}