home *** CD-ROM | disk | FTP | other *** search
- /********************************************************************
- * *
- * 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 <libraries/dos.h> /* For the return code #defines */
-
- #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(argc, argv)
- 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;
- }
- }
-