home *** CD-ROM | disk | FTP | other *** search
/ Languages Around the World / LanguageWorld.iso / psfonts / pfm2afm.c < prev    next >
Text File  |  1993-10-29  |  15KB  |  505 lines

  1. /********************************************************************
  2.  *                                                                  *
  3.  *  Title:  pfm2afm - Convert Windows .pfm files to .afm files      *
  4.  *                                                                  *
  5.  *  Author: Ken Borgendale   10/9/91  Version 1.0                   *
  6.  *                                                                  *
  7.  *  Function:                                                       *
  8.  *      Convert a Windows .pfm (Printer Font Metrics) file to a     *
  9.  *      .afm (Adobe Font Metrics) file.  The purpose of this is     *
  10.  *      to allow fonts put out for Windows to be used with OS/2.    *
  11.  *                                                                  *
  12.  *  Syntax:                                                         *
  13.  *      pfm2afm  infile  [outfile] -a                               *
  14.  *                                                                  *
  15.  *  Copyright:                                                      *
  16.  *      pfm2afm - Copyright (C) IBM Corp., 1991                     *
  17.  *                                                                  *
  18.  *      This code is released for public use as long as the         *
  19.  *      copyright remains intact.  This code is provided asis       *
  20.  *      without any warrenties, express or implied.                 *
  21.  *                                                                  *
  22.  *  Notes:                                                          *
  23.  *      1. Much of the information in the original .afm file is     *
  24.  *         lost when the .pfm file is created, and thus cannot be   *
  25.  *         reconstructed by this utility.  This is especially true  *
  26.  *         of data for characters not in the Windows character set. *
  27.  *                                                                  *
  28.  *      2. This module is coded to be compiled by the MSC 6.0.      *
  29.  *         For other compilers, be careful of the packing of the    *
  30.  *         PFM structure.                                           *
  31.  *                                                                  *
  32.  ********************************************************************/
  33.  
  34. #include <stdio.h>
  35. #include <string.h>
  36. #include <stdlib.h>
  37. #include "pfm2afm.h"
  38.  
  39. #define BUFSIZE 4096
  40. /*
  41.  *  Function Prototypes
  42.  */
  43. void  help (void);
  44. void  parseargs (int argc, uchar * * argv);
  45. void  openpfm(void);
  46. void  openafm(void);
  47. void  putheader(void);
  48. void  putchartab(void);
  49. void  outchar(int code, ushort width, const uchar * name);
  50. void  putkerntab(KERN * kerntab, int kerncnt);
  51. void  puttrailer(void);
  52. void  outval(int val);
  53.  
  54. /*
  55.  *  Global variables
  56.  */
  57. FILE   * inf;                /* Input file */
  58. FILE   * outf;               /* Output file */
  59. uchar  infname[272];         /* Input file name */
  60. uchar  outfname[272];        /* Output file name */
  61. uchar  * buffer;             /* .pfm read buffer */
  62. PFM    * pfm;                /* .pfm header */
  63. PSX    * psx;                /* Metrics extension */
  64.  
  65. uchar    debugflag;          /* Debug information flag */
  66. uchar    allflag;
  67. uchar    isMono;             /* Font is mono-spaced */
  68.  
  69. /*
  70.  *  Do the function
  71.  */
  72. MAINENT main(int argc, uchar * *argv) {
  73.  
  74.     /* Parse arguments */
  75.     parseargs(argc, argv);
  76.  
  77.     /* Open and check input file */
  78.     openpfm();
  79.  
  80.     /* Make output file name and open */
  81.     openafm();
  82.  
  83.     /* Put out header information */
  84.     putheader();
  85.  
  86.     /* Put out character table */
  87.     putchartab();
  88.  
  89.     /* Put out kerning table */
  90.     if (pfm->kernpairs) {
  91.         putkerntab((KERN *)(buffer+pfm->kernpairs+2),
  92.                    *(ushort *)(buffer+pfm->kernpairs));
  93.     }
  94.  
  95.     /* Put out trailer line */
  96.     puttrailer();
  97.  
  98.     /* Cleanup */
  99.     if (buffer)
  100.         free(buffer);
  101.     fclose(inf);
  102.     fclose(outf);
  103.     return 0;
  104. }
  105.  
  106. /*
  107.  *  Put out normal help
  108.  */
  109. void  help (void) {
  110.     puts("\npfm2afm - Convert Windows pfm to afm - Version 1.0\n");
  111.     puts("This utility converts Windows pfm files for Adobe type 1 fonts");
  112.     puts("to afm files for use on OS/2.  This allows fonts created for");
  113.     puts("Windows, and shipped without the afm file to be used on OS/2.\n");
  114.     puts("pfm2afm  infile  [outfile]  -opts");
  115.     puts("    The extension .pfm is added to the infile if it has none.");
  116.     puts("    The outfile is defaulted from the input file name.");
  117.     puts("    -a = All codepoints in range");
  118.     puts("\nNote that pfm files are missing some of the data necessary to");
  119.     puts("construct afm files, so the conversion may not be perfect.\n");
  120.     puts("Ken Borgendale  -  kwb@betasvm2.vnet.ibm.com\n");
  121.     exit (1);
  122. }
  123.  
  124.  
  125. /*
  126.  *  Parse arguments.  This is the full arg treatment, which is sort of
  127.  *  overkill for one option, but it allows more to be added later.
  128.  */
  129. void  parseargs (int argc, uchar * * argv) {
  130.     uchar  swchar;
  131.     int    argcnt;
  132.     int    filecnt;
  133.     uchar * argp;
  134.  
  135.     argcnt = 1;
  136.     filecnt = 0;
  137.     /* Read the arguments and decide what we are doing */
  138.     while (argcnt<argc) {
  139.         argp = argv[argcnt];
  140.         /* Check for switches.  Files may not start with - or / */
  141.         if (*argp == '-' || *argp == OPTSEP) {
  142.             /* Process switches */
  143.             swchar = (uchar)tolower(argp[1]);
  144.             argp += 2;
  145.             switch (swchar) {
  146.             case '?':
  147.                 help();      /* Does not return */
  148.  
  149.             /* All codepoints */
  150.             case 'a':
  151.                 allflag = 0;
  152.                 break;
  153.  
  154.             /* Debug option */
  155.             case 'd':
  156.                 debugflag = 1;
  157.                 break;
  158.  
  159.             default:
  160.                 fputs("Unknown options: ", stderr);
  161.                 fputs(argp-2, stderr);
  162.                 fputc('\n', stderr);
  163.             }
  164.         } else {
  165.             if (*argp=='?') {
  166.                 help();      /* Does not return */
  167.             }
  168.             switch(++filecnt) {
  169.             case 1:
  170.                 strcpy(infname, argp);
  171.                 break;
  172.             case 2:
  173.                 strcpy(outfname, argp);
  174.                 break;
  175.             default:
  176.                 fputs("Extra parameter ignored: ", stderr);
  177.                 fputs(argp, stderr);
  178.                 fputc('\n', stderr);
  179.             }
  180.         }
  181.         argcnt++;
  182.     }
  183.  
  184.     /* We require the input file name */
  185.     if (!filecnt) help();
  186. }
  187.  
  188.  
  189. /*
  190.  *  Open the .pfm file and check it
  191.  */
  192. void  openpfm(void) {
  193.     uchar   * cp;
  194.     int       len;
  195.  
  196.     /* Check for a file extension */
  197.     cp = infname+strlen(infname)-1;
  198.     while (cp>=infname && *cp!='.' && *cp!='\\' && *cp!='/' && *cp!=':')
  199.        cp--;
  200.     if (*cp!='.')
  201.         strcat(infname, ".pfm");
  202.     /* Open the file */
  203.     inf = fopen(infname, "rb");
  204.     if (!inf) {
  205.         fputs("Unable to open input file - ", stderr);
  206.         fputs(infname, stderr);
  207.         fputc('\n', stderr);
  208.         exit(4);
  209.     }
  210.     /* Read the file */
  211.     buffer = malloc(BUFSIZE);
  212.     len = fread(buffer, 1, BUFSIZE, inf);
  213.     if (len<256 || len==BUFSIZE) {
  214.         fputs("Input file read error - ", stderr);
  215.         fputs(infname, stderr);
  216.         fputc('\n', stderr);
  217.         exit(6);
  218.     }
  219.     /* Do consistency check */
  220.     pfm = (PFM *) buffer;
  221.     if (len != (int)pfm->len &&  /* Check length field matches file length */
  222.         pfm->extlen != 30 &&     /* Check length of PostScript extension   */
  223.         pfm->fontname>75 && pfm->fontname<512) {  /* Font name specified */
  224.         fputs("Not a valid Windows type 1 .pfm file - ", stderr);
  225.         fputs(infname, stderr);
  226.         fputc('\n', stderr);
  227.         exit(6);
  228.     }
  229. }
  230.  
  231. /*
  232.  *  Create the .afm file
  233.  */
  234. void  openafm(void) {
  235.     uchar  * cp;
  236.  
  237.     /* Add .pfm if there is none */
  238.     if (!*outfname) {
  239.         strcpy(outfname, infname);
  240.         cp = outfname+strlen(outfname)-1;
  241.         while (cp >= outfname && *cp!='.' && *cp!='\\' && *cp!='/' && *cp!=':')
  242.            cp--;
  243.         if (*cp=='.') *cp=0;
  244.         strcat(outfname, ".afm");
  245.     }
  246.     /* Open the file */
  247.     outf = fopen(outfname, "w");
  248.     if (!outf) {
  249.         fputs("Unable to open output file - ", stderr);
  250.         fputs(outfname, stderr);
  251.         fputc('\n', stderr);
  252.         exit(5);
  253.     }
  254. }
  255.  
  256. /*
  257.  *  Put out the header of the .afm file
  258.  */
  259. void  putheader(void) {
  260.     uchar * cp;
  261.  
  262.     fputs("StartFontMetrics 2.0\n", outf);
  263.     if (*pfm->copyright) {
  264.         fputs("Comment ", outf);
  265.         fputs(pfm->copyright, outf);
  266.         fputc('\n', outf);
  267.     }
  268.     fputs("FontName ", outf);
  269.     fputs(buffer+pfm->fontname, outf);
  270.     fputs("\nEncodingScheme ", outf);
  271.     if (pfm->charset) {
  272.         fputs("FontSpecific\n", outf);
  273.     } else {
  274.         fputs("AdobeStandardEncoding\n", outf);
  275.     }
  276.     /*
  277.      * The .pfm is missing full name, so construct from font name by
  278.      * changing the hyphen to a space.  This actually works in a lot
  279.      * of cases.
  280.      */
  281.     fputs("FullName ", outf);
  282.     cp = buffer+pfm->fontname;
  283.     while (*cp) {
  284.         if (*cp=='-') *cp=' ';
  285.         fputc(*cp, outf);
  286.         cp++;
  287.     }
  288.     if (pfm->face) {
  289.         fputs("\nFamilyName ", outf);
  290.         fputs(buffer+pfm->face, outf);
  291.     }
  292.  
  293.     fputs("\nWeight ", outf);
  294.     if (pfm->weight>475) fputs("Bold", outf);
  295.     else if (pfm->weight<325 && pfm->weight)
  296.         fputs("Light", outf);
  297.     else fputs("Medium", outf);
  298.  
  299.     /*
  300.      *  The mono flag in the pfm actually indicates whether there is a
  301.      *  table of font widths, not if they are all the same.
  302.      */
  303.     fputs("\nIsFixedPitch ", outf);
  304.     if (!(pfm->kind&1) ||                  /* Flag for mono */
  305.         pfm->avgwidth == pfm->maxwidth ) {  /* Avg width = max width */
  306.         fputs("true", outf);
  307.         isMono = 1;
  308.     } else {
  309.         fputs("false", outf);
  310.         isMono = 0;
  311.     }
  312.  
  313.     /*
  314.      * The font bounding box is lost, but try to reconstruct it.
  315.      * Much of this is just guess work.  The bounding box is required in
  316.      * the .afm, but is not used by the PM font installer.
  317.      */
  318.     psx = (PSX *)(buffer+pfm->psext);
  319.     fputs("\nFontBBox", outf);
  320.     if (isMono) outval(-20);      /* Just guess at left bounds */
  321.     else outval(-100);
  322.     outval(-(psx->descender+5));  /* Descender is given as positive value */
  323.     outval(pfm->maxwidth+10);
  324.     outval(pfm->ascent+5);
  325.  
  326.     /*
  327.      * Give other metrics that were kept
  328.      */
  329.     fputs("\nCapHeight", outf);
  330.     outval((int)psx->capheight);
  331.     fputs("\nXHeight", outf);
  332.     outval((int)psx->xheight);
  333.     fputs("\nDescender", outf);
  334.     outval((int)psx->descender);
  335.     fputs("\nAscender", outf);
  336.     outval((int)psx->ascender);
  337.     fputc('\n', outf);
  338. }
  339.  
  340. /*
  341.  *  Put out the character tables.  According to the .afm spec, the
  342.  *  characters must be put out sorted in encoding order.
  343.  *
  344.  *  Most Windows .pfm files have the characters in the range 20-ff in
  345.  *  the Windows code page (819 + quotes).
  346.  */
  347. void  putchartab(void) {
  348.     int    count, i, j;
  349.     ushort spwidth;
  350.     ushort * ctab;
  351.     uchar  back[256];
  352.  
  353.     /*
  354.      * Compute the count by getting rid of non-existant chars.  This
  355.      * is complicated by the fact that Windows encodes the .pfm file
  356.      * with a space metric for non-existant chars.
  357.      */
  358.     memset(back, 0, 256);
  359.     count = pfm->lastchar - pfm->firstchar + 1;
  360.     spwidth = 0;
  361.     /* Compute width of space */
  362.     ctab = (ushort *)(buffer+pfm->chartab);
  363.     if (pfm->firstchar>=' ' && pfm->lastchar<=' ') {
  364.         spwidth = ctab[' '-pfm->firstchar];
  365.     }
  366.  
  367.     if (!pfm->charset) {
  368.         /*
  369.          *  Loop thru the chars, deleting those that we presume
  370.          *  do not really exist.
  371.          */
  372.         for (i=pfm->firstchar; i<=(int)pfm->lastchar; i++) {
  373.             if (Win2PSStd[i]) {
  374.                 back[Win2PSStd[i]] = (uchar)i;
  375.             } else {
  376.                 if (!allflag) {
  377.                     if (*ctab==spwidth) {   /* Default width */
  378.                         if (!(WinClass[i]&1)) {
  379.                             *ctab = 0;
  380.                             count--;
  381.                         }
  382.                     } else {                /* Not default width */
  383.                         if (!WinClass[i]) {
  384.                             *ctab = 0;
  385.                             count--;
  386.                         }
  387.                     }
  388.                 }
  389.             }
  390.             ctab++;
  391.         }
  392.     }
  393.  
  394.     /* Put out the header */
  395.     fputs("StartCharMetrics", outf);
  396.     outval(count);
  397.     fputc('\n', outf);
  398.  
  399.     /* Put out all encoded chars */
  400.     if (pfm->charset) {
  401.     /*
  402.      * If the charset is not the Windows standard, just put out
  403.      * unnamed entries.
  404.      */
  405.         ctab = (ushort *)(buffer+pfm->chartab);
  406.         for (i=pfm->firstchar; i<=(int)pfm->lastchar; i++) {
  407.             if (*ctab) {
  408.                 outchar(i, *ctab, NULL);
  409.             }
  410.             ctab++;
  411.         }
  412.     } else {
  413.         ctab = (ushort *)(buffer+pfm->chartab);
  414.         for (i=0; i<256; i++) {
  415.             j = back[i];
  416.             if (j) {
  417.                 outchar(i, ctab[j-pfm->firstchar], WinChars[j]);
  418.                 ctab[j-pfm->firstchar] = 0;
  419.             }
  420.         }
  421.         /* Put out all non-encoded chars */
  422.         ctab = (ushort *)(buffer+pfm->chartab);
  423.         for (i=pfm->firstchar; i<=(int)pfm->lastchar; i++) {
  424.             if (*ctab) {
  425.                 outchar(-1, *ctab, WinChars[i]);
  426.             }
  427.             ctab++;
  428.         }
  429.     }
  430.     /* Put out the trailer */
  431.     fputs("EndCharMetrics\n", outf);
  432. }
  433.  
  434. /*
  435.  *  Output a character entry
  436.  */
  437. void  outchar(int code, ushort width, const uchar * name) {
  438.     fputs("C ", outf);
  439.     outval(code);
  440.     fputs(" ; WX ", outf);
  441.     outval(width);
  442.     if (name) {
  443.         fputs(" ; N ", outf);
  444.         fputs(name, outf);
  445.     }
  446.     fputs(" ;\n", outf);
  447. }
  448.  
  449. /*
  450.  *  Put out the kerning tables
  451.  */
  452. void  putkerntab(KERN * kerntab, int kerncnt) {
  453.     int    count, i;
  454.     KERN * kp;
  455.  
  456.     /* Count non-zero kern pairs */
  457.     count = kerncnt;
  458.     kp = kerntab;
  459.     for (i=0; i<kerncnt; i++) {
  460.         if (!kp->kern)
  461.             count--;
  462.         kp++;
  463.     }
  464.  
  465.     /* Put out header */
  466.     fputs("StartKernData\nStartKernPairs", outf);
  467.     outval(count);
  468.     fputc('\n', outf);
  469.  
  470.     /* Put out each non-zero pair */
  471.     kp = kerntab;
  472.     while (kerncnt) {
  473.         if (kp->kern) {
  474.             fputs("KPX ", outf);
  475.             fputs(WinChars[kp->first], outf);
  476.             fputc(' ', outf);
  477.             fputs(WinChars[kp->second], outf);
  478.             outval((int)kp->kern);
  479.             fputc('\n', outf);
  480.         }
  481.         kp++;
  482.         kerncnt--;
  483.     }
  484.  
  485.     /* Put out trailer */
  486.     fputs("EndKernPairs\nEndKernData\n", outf);
  487. }
  488.  
  489. /*
  490.  *  Put out the trailer of the .afm file
  491.  */
  492. void  puttrailer(void) {
  493.     fputs("EndFontMetrics\n", outf);
  494. }
  495.  
  496. /*
  497.  *  Output a decimal value
  498.  */
  499. void outval(int v) {
  500.     char chx[16];
  501.     itoa(v, chx, 10);
  502.     fputc(' ', outf);
  503.     fputs(chx, outf);
  504. }
  505.