home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Crawly Crypt Collection 2
/
crawlyvol2.bin
/
apps
/
dtp
/
pfm2afm
/
pfm2afm.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-10-27
|
21KB
|
666 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. *
* *
********************************************************************/
#ifndef ATARI
#include <libriaries/dos.h> /* For the return code #defines */
#else
#include <portab.h>
#define VOID void
#define RETURN_OK 0
#define RETURN_WARN 1
#define RETURN_ERROR 2
#define REGISTER
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "pfm2afm.h"
#define BUFSIZE 4096
/*
* Function Prototypes
*/
VOID help (VOID);
VOID parseargs (int, UBYTE **);
VOID openpfm (VOID);
VOID openafm (VOID);
VOID putheader (VOID);
VOID putchartab (VOID);
VOID outchar (int, UWORD, UBYTE *);
VOID putkerntab (KERN *, UWORD);
VOID puttrailer (VOID);
VOID outval (int);
VOID revbyt (UBYTE *, int);
/*
* GLOBAL VARIABLES
*/
FILE *inf; /* INPUT FILE */
FILE *outf; /* OUTPUT FILE */
UBYTE mmsg[256]; /* BUFFER FOR MSGS */
UBYTE infname[272]; /* INPUT FILE NAME */
UBYTE outfname[272]; /* OUTPUT FILE NAME */
UBYTE buffer[BUFSIZE]; /* .PFM READ BUFFER */
PFM pfm; /* .PFM HEADER */
PSX psx; /* METRICS EXTENSION */
UBYTE debugflag; /* DEBUG INFORMATION FLAG */
UBYTE allflag;
UBYTE isMono; /* Font is mono-spaced */
/*
* DO THE FUNCTION
*/
int main(int argc,UBYTE *argv[])
{
UWORD pairs;
/* 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)
{ memcpy(&pairs, buffer+pfm.kernpairs, sizeof(pairs));
revbyt((UBYTE *)&pairs, sizeof(pairs));
putkerntab((KERN *)(buffer+pfm.kernpairs+2), pairs);
}
/* PUT OUT TRAILER LINE */
puttrailer();
return(RETURN_OK);
}
/*
* 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\n");
puts("Note 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");
puts("Ported to Amiga by Kevin Ross - GEnie: K.ROSS12 BIX: kross\n");
exit (RETURN_WARN);
}
/*
* 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 (argc, argv)
int argc;
UBYTE *argv[];
{
UBYTE swchar, *argp;
int argcnt, filecnt;
argcnt = 1;
filecnt = 0;
/* READ THE ARGUMENTS AND DECIDE WHAT WE ARE DOING */
while (argcnt<argc)
{ argp = argv[argcnt];
switch(argp[0])
{
/* PROCESS SWITCHES. FILES MAY NOT START WITH '-' */
case OPTSEP:
swchar = (UBYTE)tolower(argp[1]);
argp += 2;
switch (swchar)
{
/* ALL CODEPOINTS */
case 'a':
allflag = 0;
break;
/* DEBUG OPTION */
case 'd':
debugflag = 1;
break;
default:
fputs("Unknown option: ", stderr);
fputs(argp-2, stderr);
fputc('\n', stderr);
}
break;
case '?':
help(); /* DOES NOT RETURN */
default:
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)
{
UBYTE *cp;
int len;
/* CHECK FOR A FILE EXTENSION */
cp = infname + strlen(infname) - 1;
while (cp >= infname && *cp != '.' && *cp != '/' && *cp != ':')
cp--;
if (*cp != '.')
strcat(infname, ".pfm");
/* OPEN THE FILE */
inf = fopen(infname, "rb");
if (!inf)
{ strcpy(mmsg, "Unable to open input file \"");
strcat(mmsg, infname);
strcat(mmsg, "\"");
perror(mmsg);
exit(RETURN_ERROR);
}
/* READ THE FILE */
len = fread(buffer, 1, BUFSIZE, inf);
if (len < 256 || len == BUFSIZE)
{ strcpy(mmsg, "Input file \"");
strcat(mmsg, infname);
strcat(mmsg, "\" read error");
perror(mmsg);
exit(RETURN_ERROR);
}
/* UNPACK RECORD INTO PFM STRUCT */
cp = buffer;
memcpy(&pfm.vers, cp, sizeof(pfm.vers)); cp += sizeof(pfm.vers);
memcpy(&pfm.len, cp, sizeof(pfm.len)); cp += sizeof(pfm.len);
memcpy(&pfm.copyright, cp, sizeof(pfm.copyright)); cp += sizeof(pfm.copyright);
memcpy(&pfm.type, cp, sizeof(pfm.type)); cp += sizeof(pfm.type);
memcpy(&pfm.points, cp, sizeof(pfm.points)); cp += sizeof(pfm.points);
memcpy(&pfm.verres, cp, sizeof(pfm.verres)); cp += sizeof(pfm.verres);
memcpy(&pfm.horres, cp, sizeof(pfm.horres)); cp += sizeof(pfm.horres);
memcpy(&pfm.ascent, cp, sizeof(pfm.ascent)); cp += sizeof(pfm.ascent);
memcpy(&pfm.intleading,cp, sizeof(pfm.intleading));cp += sizeof(pfm.intleading);
memcpy(&pfm.extleading,cp, sizeof(pfm.extleading));cp += sizeof(pfm.extleading);
memcpy(&pfm.italic, cp, sizeof(pfm.italic)); cp += sizeof(pfm.italic);
memcpy(&pfm.uline, cp, sizeof(pfm.uline)); cp += sizeof(pfm.uline);
memcpy(&pfm.overs, cp, sizeof(pfm.overs)); cp += sizeof(pfm.overs);
memcpy(&pfm.weight, cp, sizeof(pfm.weight)); cp += sizeof(pfm.weight);
memcpy(&pfm.charset, cp, sizeof(pfm.charset)); cp += sizeof(pfm.charset);
memcpy(&pfm.pixwidth, cp, sizeof(pfm.pixwidth)); cp += sizeof(pfm.pixwidth);
memcpy(&pfm.pixheight, cp, sizeof(pfm.pixheight)); cp += sizeof(pfm.pixheight);
memcpy(&pfm.kind, cp, sizeof(pfm.kind)); cp += sizeof(pfm.kind);
memcpy(&pfm.avgwidth, cp, sizeof(pfm.avgwidth)); cp += sizeof(pfm.avgwidth);
memcpy(&pfm.maxwidth, cp, sizeof(pfm.maxwidth)); cp += sizeof(pfm.maxwidth);
memcpy(&pfm.firstchar, cp, sizeof(pfm.firstchar)); cp += sizeof(pfm.firstchar);
memcpy(&pfm.lastchar, cp, sizeof(pfm.lastchar)); cp += sizeof(pfm.lastchar);
memcpy(&pfm.defchar, cp, sizeof(pfm.defchar)); cp += sizeof(pfm.defchar);
memcpy(&pfm.brkchar, cp, sizeof(pfm.brkchar)); cp += sizeof(pfm.brkchar);
memcpy(&pfm.widthby, cp, sizeof(pfm.widthby)); cp += sizeof(pfm.widthby);
memcpy(&pfm.device, cp, sizeof(pfm.device)); cp += sizeof(pfm.device);
memcpy(&pfm.face, cp, sizeof(pfm.face)); cp += sizeof(pfm.face);
memcpy(&pfm.bits, cp, sizeof(pfm.bits)); cp += sizeof(pfm.bits);
memcpy(&pfm.bitoff, cp, sizeof(pfm.bitoff)); cp += sizeof(pfm.bitoff);
memcpy(&pfm.extlen, cp, sizeof(pfm.extlen)); cp += sizeof(pfm.extlen);
memcpy(&pfm.psext, cp, sizeof(pfm.psext)); cp += sizeof(pfm.psext);
memcpy(&pfm.chartab, cp, sizeof(pfm.chartab)); cp += sizeof(pfm.chartab);
cp += sizeof(pfm.res1);
memcpy(&pfm.kernpairs, cp, sizeof(pfm.kernpairs)); cp += sizeof(pfm.kernpairs);
cp += sizeof(pfm.res2);
memcpy(&pfm.fontname, cp, sizeof(pfm.fontname)); cp += sizeof(pfm.fontname);
/*
* Adjust ordering of bytes in binary values
* 68000 orders values MSB to LSB -- 8086 orders values LSB to MSB
*/
revbyt((UBYTE *)&pfm.vers, sizeof(pfm.vers));
revbyt((UBYTE *)&pfm.len, sizeof(pfm.len));
revbyt((UBYTE *)&pfm.type, sizeof(pfm.type));
revbyt((UBYTE *)&pfm.points, sizeof(pfm.points));
revbyt((UBYTE *)&pfm.verres, sizeof(pfm.verres));
revbyt((UBYTE *)&pfm.horres, sizeof(pfm.horres));
revbyt((UBYTE *)&pfm.ascent, sizeof(pfm.ascent));
revbyt((UBYTE *)&pfm.intleading, sizeof(pfm.intleading));
revbyt((UBYTE *)&pfm.extleading, sizeof(pfm.extleading));
revbyt((UBYTE *)&pfm.weight, sizeof(pfm.weight));
revbyt((UBYTE *)&pfm.pixwidth, sizeof(pfm.pixwidth));
revbyt((UBYTE *)&pfm.pixheight, sizeof(pfm.pixheight));
revbyt((UBYTE *)&pfm.avgwidth, sizeof(pfm.avgwidth));
revbyt((UBYTE *)&pfm.maxwidth, sizeof(pfm.maxwidth));
revbyt((UBYTE *)&pfm.widthby, sizeof(pfm.widthby));
revbyt((UBYTE *)&pfm.device, sizeof(pfm.device));
revbyt((UBYTE *)&pfm.face, sizeof(pfm.face));
revbyt((UBYTE *)&pfm.bits, sizeof(pfm.bits));
revbyt((UBYTE *)&pfm.bitoff, sizeof(pfm.bitoff));
revbyt((UBYTE *)&pfm.extlen, sizeof(pfm.extlen));
revbyt((UBYTE *)&pfm.psext, sizeof(pfm.psext));
revbyt((UBYTE *)&pfm.chartab, sizeof(pfm.chartab));
revbyt((UBYTE *)&pfm.kernpairs, sizeof(pfm.kernpairs));
revbyt((UBYTE *)&pfm.fontname, sizeof(pfm.fontname));
/* DO CONSISTENCY CHECK */
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(RETURN_ERROR);
}
}
/*
* CREATE THE .AFM FILE
*/
VOID openafm(VOID)
{
UBYTE *cp;
/* ADD .AFM IF THERE IS NONE */
if (!*outfname)
{ strcpy(outfname, infname);
cp = outfname+strlen(outfname)-1;
while (cp >= outfname && *cp != '.' && *cp != '/' && *cp != ':')
cp--;
if (*cp == '.')
*cp = 0;
strcat(outfname, ".afm");
}
/* OPEN THE FILE */
outf = fopen(outfname, "w");
if (!outf)
{ strcpy(mmsg, "Unable to open output file \"");
strcat(mmsg, outfname);
strcat(mmsg, "\"");
perror(mmsg);
exit(RETURN_ERROR);
}
}
/*
* PUT OUT THE HEADER OF THE .AFM FILE
*/
VOID putheader(VOID)
{
UBYTE * cp;
fputs("StartFontMetrics 2.0\n", outf);
if (pfm.copyright[0])
{ 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.
*/
/* UNPACK RECORD INTO PSX STRUCT */
memcpy(&psx, buffer+pfm.psext, sizeof(psx));
revbyt((UBYTE *)&psx.capheight, sizeof(psx.capheight));
revbyt((UBYTE *)&psx.xheight, sizeof(psx.xheight));
revbyt((UBYTE *)&psx.ascender, sizeof(psx.ascender));
revbyt((UBYTE *)&psx.descender, sizeof(psx.descender));
fputs("\nFontBBox", outf);
if (isMono) /* JUST GUESS AT LEFT BOUNDS */
outval(-20);
else
outval(-100);
/*
* Some .PFMs give the descender as a positive value,
* and others give it as negative...
*/
outval(-(abs(psx.descender)+5));
outval(pfm.maxwidth+10);
outval(pfm.ascent+5);
/*
* GIVE OTHER METRICS THAT WERE KEPT
*/
fputs("\nCapHeight", outf);
outval(psx.capheight);
fputs("\nXHeight", outf);
outval(psx.xheight);
fputs("\nDescender", outf);
outval(-abs(psx.descender));
fputs("\nAscender", outf);
outval(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;
UWORD spwidth;
UWORD * ctab, chartab[256];
UBYTE back[256];
count = pfm.lastchar - pfm.firstchar + 1;
/* UNPACK CHARACTER TABLE INTO CHARTAB */
for (i = 0; i < count; i++)
{ memcpy(&chartab[i], buffer + pfm.chartab + i*sizeof(UWORD),
sizeof(UWORD));
revbyt((UBYTE *)(&chartab[i]), sizeof(UWORD));
}
/*
* 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);
spwidth = 0;
/* COMPUTE WIDTH OF SPACE */
ctab = chartab;
if (pfm.firstchar <= ' ' && pfm.lastchar >= ' ')
spwidth = ctab[' ' - pfm.firstchar];
/*
* Loop thru the chars, deleting those that we presume
* do not really exist.
*/
if (!pfm.charset)
{ for (i = pfm.firstchar; i <= (int)pfm.lastchar; i++)
{ if (Win2PSStd[i])
back[Win2PSStd[i]] = (UBYTE)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);
/*
* If the charset is not the Windows standard, just put out
* unnamed entries.
*/
ctab = chartab;
if (pfm.charset)
{ for (i = pfm.firstchar; i <= (int)pfm.lastchar; i++)
{ if (*ctab)
outchar(i, *ctab, NULL);
ctab++;
}
}
else
{ 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 */
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(code, width, name)
int code;
UWORD width;
UBYTE *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(kerntab, kerncnt)
KERN *kerntab;
UWORD kerncnt;
{
int count, i;
KERN k, *kp;
/* COUNT NON-ZERO KERN PAIRS */
count = kerncnt;
kp = kerntab;
for (i = 0; i < kerncnt; i++)
{ memcpy(&k, kp, 4);
if (!k.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)
{ memcpy(&k, kp, 4);
if (k.kern)
{ revbyt((UBYTE *)&k.kern, sizeof(k.kern));
fputs("KPX ", outf);
fputs(WinChars[k.first], outf);
fputc(' ', outf);
fputs(WinChars[k.second], outf);
outval(k.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(v)
int v;
{
UBYTE chx[16];
/* LATTICE EQUIV. OF itoa() */
stci_d(chx, v);
fputc(' ', outf);
fputs(chx, outf);
}
/*
* REVERSE THE BYTES IN A BINARY VALUE
*/
VOID revbyt (tp,len)
REGISTER UBYTE *tp;
int len;
{
REGISTER UBYTE *hp;
UBYTE ch;
hp = tp + len - 1;
while (tp < hp)
{ ch = *tp;
*tp++ = *hp;
*hp-- = ch;
}
}