%! % POSTSCRIPT PFA TO PFB FONT FILE CONVERTER % ========================================= % by Don Lancaster v1.3 9 Mar 97 % Copyright c. 1997 by Don Lancaster and Synergetics, Box 809, % Thatcher AZ, 85552 (520) 428-4073. synergetics@tinaja.com % All commercial rights and all electronic media rights *fully* % reserved. Linking welcome. Reposting is expressly forbidden. % Further support on www.tinaja.com % Consulting services available via don@tinaja.com % ==================================== % WARNING: Preliminary code. Use at your own risk. % Report all problems to don@tinaja.com % ==================================== % The PostScript general purpose computing language is ideal for % disk-based font and format coversions. This example takes PC-based % hex-ascii .PFA font files and converts them to binary .PFB files. % .PFA files are normally used for serial and other comm apps that % are not eight bit clean. .PFB files are normally used internally % and where a clean 8 bit comm channel is available. More details % on these file formats appear in Adobe Technical note #5040 on % Supporting Downloadable PostScript Language Fonts. % This utility may be used with GhostScript or with a PostScript % printer having an internal hard drive. But it is easiest to use % by routing it to Acrobat distiller 3.0 or higher. First view this % utility with an editor or word processor, changing the filenames % as needed. Distiller will then do the format conversion for you. % A "normal" .PFA file consisting of ASCII text up to "eexec" is % assumed, followed by lines of Hex characters ending in at least % one line of zeros, followed by ending ASCII text. % A .PFB file recognizes three different types of data blocks. Each % type has a six byte id and length header. Type I is ordinary ASCII % text, which is passed on as is. Type II is binary, which gets % converted to HEX-ASCII pairs of suitable line lenghts. Type III is % an end of file marker. % .PFA Files are written with carriage returns only. To convert to % cr-lf pairs on a PC, bring the .PFA file up in Netscape, copy it to % the clipboard, then paste it to Wordpad. Then resave. % Note that any existing .PFB file with target filename is deleted. % Note also that an "empty file" error is normal and expected. Because % distiller is being tricked into PostScript computing, rather than % generating a .PDF file. % Three scratch strings are used to ease debugging of problem files. % Only one is really required for tighter code. % defaults. Be sure to use "\\" when you mean "\" in the filename!!! /pfafilename (c:\\Windows\\Desktop\\atrump\\Glunk___.PFA) def % source /pfbfilename (c:\\Windows\\Desktop\\atrump\\Glunk___.PFB) def % target /scratch1 (c:\\Windows\\Desktop\\atrump\\Scratch1.txt) def % work file /scratch2 (c:\\Windows\\Desktop\\atrump\\Scratch2.txt) def % work file /scratch3 (c:\\Windows\\Desktop\\atrump\\Scratch3.txt) def % work file % /fillscratchflies does a three step conversion of the .pfa file... /fillscratchfiles { /oktogo false def {source 1000 string readline { dup (currentfile eexec)search {pop pop pop scratch1 exch writestring scratch1 (\r) writestring /oktogo true store exit} {pop scratch1 exch writestring scratch1 (\n) writestring }ifelse } {0 errormessage exit}ifelse % error if no eexec } loop oktogo {fillscratchfile2} if % continue if possible } def % /fillscratchfile2 continues by reading and converting hex lines to % binary. It exits normally by finding a line that starts with at % least six zeros... /fillscratchfile2 { /oktogo false store { source 1000 string readline { dup (00000000000000) search {pop pop pop % test for all zeros line /oktogo true store exit} % a line of mostly zeros found {pop /ASCIIHexDecode filter dup % normal line - not all zeros 500 string readstring pop scratch2 exch writestring pop } ifelse % zeros test pa } % valid readline { 1 errormessage /oktogo false store exit} % got to end of file ifelse % found or did not find ending ASCII text. } loop oktogo {fillscratchfile3}if % continue if possible } def % /fillscratchfile3 reads and passes on ending ascii rows of % zeros and cleartomark... /fillscratchfile3 { scratch3 (\n) writestring % write cr scratch3 exch writestring % write row of zeros {source 1000 string readstring {scratch3 exch writestring} {scratch3 exch writestring exit } ifelse } loop scratch3 (\n) writestring % end with newline mergescratchfiles } def % /mergesscratchfiles calculates the binary format headers and combines % files scratch1 (initial ascii), scratch2 (binary), and scratch3 (end % zeros and cleartomark) into a composite .PFB file... /mergescratchfiles { (gotto mergescratchfiles ) == flush % begin first ascii portion... scratch1 closefile % apparently cannot measure status of open file? scratch1filename status % find bytes written to scratch1 pop pop pop exch pop % extract bytes written 0 exch % convert to base 256 dup 65536 idiv exch 65536 mod dup 256 idiv exch 256 mod target 128 write % header 128 marker target 1 write % 1 = Ascii mode 4{target exch write} repeat % four length bytes mod256 scratch1filename (r) file /scratch1 exch store % reopen scratch file {scratch1 1000 string readstring % copy scratch1 after new header {target exch writestring} {target exch writestring exit} ifelse } loop % begin binary portion... scratch2 closefile % apparently cannot measure status of open file? scratch2filename status % find bytes written to scratch2 pop pop pop exch pop % extract bytes written 0 exch % convert to base 256 dup 65536 idiv exch 65536 mod dup 256 idiv exch 256 mod target 128 write % header 128 marker target 2 write % 2 = binary mode 4{target exch write} repeat % four length bytes mod256 scratch2filename (r) file /scratch2 exch store % reopen scratch file {scratch2 1000 string readstring % copy scratch2 after new header {target exch writestring} {target exch writestring exit} ifelse } loop % begin final ascii portion... scratch3 closefile % apparently cannot measure status of open file? scratch3filename status % find bytes written to scratch2 pop pop pop exch pop % extract bytes written 0 exch % convert to base 256 dup 65536 idiv exch 65536 mod dup 256 idiv exch 256 mod target 128 write % header 128 marker target 1 write % 1 = ascii mode 4{target exch write} repeat % four length bytes mod256 scratch3filename (r) file /scratch3 exch store % reopen scratch file {scratch3 1000 string readstring % copy scratch2 after new header {target exch writestring} {target exch writestring exit} ifelse } loop % write eof marker target 128 write % .PFB end of file marker target 3 write } def % This is the actual conversion loop. It reads and rewrites one ASCII % line at a time until "eexec" is found, writing to scratchfile1. It % then reads one binary line at a time and converts to hex, writing to % scratchfile2. Whenever a line of all zeros is found, text switches % to ASCII and writes to scratchfile3. Headers based on filelength and % type are created for the three scratchfiles and merged into final .PFB /convertpfa2pfb { save /pfasnap exch store mark % save state pfbfilename status % erase old .pfb file {pop pop pop pop pfbfilename deletefile} if scratch1 status % erase old scratch file {pop pop pop pop scratch1filename deletefile} if scratch2 status % erase old scratch file {pop pop pop pop scratch2filename deletefile} if scratch3 status % erase old scratch file {pop pop pop pop scratch3filename deletefile} if pfafilename (r) file /source exch store % open read file pfbfilename (w) file /target exch store % open write file scratch1filename (w+) file /scratch1 exch store % open scratch file scratch2filename (w+) file /scratch2 exch store % open scratch file scratch3filename (w+) file /scratch3 exch store % open scratch file fillscratchfiles % build temp files source closefile % close open files target closefile scratch1 closefile scratch2 closefile scratch3 closefile cleartomark pfasnap restore % restore state } def %%%%%%%%%%%%%%%%%%% USE EXAMPLE %%%%%%%%%%%%%%%%%%%% % IMPORTANT: Enter "\\" any time you mean "\" in the filename!!! /pfafilename (c:\\Windows\\Desktop\\atrump\\Tmr_____.PFA) def % source /pfbfilename (c:\\Windows\\Desktop\\atrump\\Tmr_____.PFB) def % target /scratch1filename (c:\\Windows\\Desktop\\atrump\\scratch1.txt) def % scratch /scratch2filename (c:\\Windows\\Desktop\\atrump\\scratch2.txt) def % scratch /scratch3filename (c:\\Windows\\Desktop\\atrump\\scratch3.txt) def % scratch convertpfa2pfb % do conversion % quit % uncomment quit if distiller 3.0 not used.