diff options
Diffstat (limited to 'dviware/ln03/thomas/ln03fonts.c')
-rw-r--r-- | dviware/ln03/thomas/ln03fonts.c | 1388 |
1 files changed, 1388 insertions, 0 deletions
diff --git a/dviware/ln03/thomas/ln03fonts.c b/dviware/ln03/thomas/ln03fonts.c new file mode 100644 index 0000000000..830b4f35d6 --- /dev/null +++ b/dviware/ln03/thomas/ln03fonts.c @@ -0,0 +1,1388 @@ +/* This file contains those portions of Ln03DVI that create +font loads. It is still being developed... + +Copyright (c) 1983, 1984, 1985, 1986, 1987 by Digital Equipment +Corporation. Author: Flavio Rose, +...!decwrl!dec-rhea!dec-dvinci!rose. + +This version of Ln03DVI is maintained by Matt Thomas. +Please send all bug reports to either: + ...!decwrl!thebay.dec.com!mthomas (UUCP) + mthomas@thebay.dec.com (Internet) + +Development chronology: + +11/28/84: Initial version in PL/I. Finished 11/30/84. + 3/4/85: C translation, a prelude to writing DVI2LN3. + 5/7/85: Finally got around to debugging the C translation! + 6/5/85: Convert to work with Dvi2ln3 -- minor changes. + 6/18/85: Try not to use big input array. + 6/22/85: Cleanup, try to identify longs. +11/12/85: Changed to read PXLs rather than LN03 format files. Old file + called dvi2ln3nft, now renamed to dvi2ln3pxl. +11/15/85: More optimized PXL reading -- use lnf instead of the pxlbuf + when reading rasters. Return just status value from add_txf_..., + use ras_len_added to communicate size. Facilitate error + recovery with copy_ersatz_char. LN03 file reading functionality + woven back in. + 1/16/86: Embarrassing bug, forgot to close the nftf after done with it. + 3/28/86: Conditionalization for Ultrix. + 4/7/86: After moving this to 4.3bsd at MIT, a couple more + fixes to the portability. + 8/6/86: Try to make changes for Apollo. No way to test + them. #ifdef Apollo ... #endif + 11/5/86: Add error message giving PXL extension if no PXL + file can be found. + 2/20/87: Add support for reading of PK files. Reorganize output to be + simpler. Change name to Ln03DVI. + 5/5/87: Misc fixups relating to the CM fonts. COnditionalize some code, etc. + 5/15/87: Fix NFT filename problem (accvio under VMS). cleaup some error + messages. +*/ + +/* INTRODUCTION: When writing an LN03 driver for TeX, it +must be kept in mind that the LN03 has limited font storage +capability. The standard LN03 has just 27k bytes, and two +128k byte RAM cartridges may be added. + +For this reason, when we convert a DVI file to LN03 form, we +build a special font load that has just the glyphs that the +DVI file needs. This allows very complex files, e.g. the +first nine chapters of the Metafontbook, to be printed on +LN03s that have just one extra RAM cartridge. This approach +does, however, consume considerable resources in the VAX to +build those font loads. */ + +/* The following is customary boilerplate. */ + +#ifdef vms +#include stdio +#include errno +#else +#include <stdio.h> +#include <errno.h> +#endif +#include "pk.h" + +/* In VMS we declare external variables to be globalref. +This is not really necessary, just an old habit. */ + +#ifdef vms +#define GLOBAL globaldef +#define EXTERN globalref +#else +#define GLOBAL +#define EXTERN extern +#endif + +/* errno is declared in errno.h under VMS and System V but +not under BSD 4.2. Also we use strchr instead of index so +we conditionalize that too. */ + +#ifdef bsd4_2 + +# define index strchr +extern int errno; + +#endif + + +/* The following symbols are declared compatibly with those +in the file Ln03DVI.c. */ + +#define maxnfonts 31 +#define MAXTEXFONTS 100 +#define FILESPECLEN 252 +#define leftfirst 33 +#define leftlast 126 +#define rightfirst 161 +#define rightlast 254 + +EXTERN FILE *outfile; +EXTERN int lastch[maxnfonts]; +EXTERN unsigned char chw[maxnfonts][256]; + +struct txf { unsigned char chu[256]; int bc, ec; long space, design_size, + scaled_size; int nchs; }; +EXTERN struct txf *txfa[MAXTEXFONTS+1]; +EXTERN long int *font_width[MAXTEXFONTS+1]; + +EXTERN char *font_name[MAXTEXFONTS+1]; +EXTERN double conv, unmag_conv; + +#ifndef vms +char *getenv(); +#endif + +/* The LN03 font load we build is buffered in a fixed-size +area, slightly smaller than the maximum amount of font +memory available on an LN03. [[The code should be changed to +chain fixed-size buffers, so font loads of unlimited size +can be handled, subject only to memory availability. On +systems with limited memory, it may be desirable to use a +disk file instead of this buffer.]] */ + +#define OBUFLEN 2*256*256 +GLOBAL unsigned char lnf[OBUFLEN]; + +/* While constructing the font load, we keep track of the +length of the "character definitions area" in ras_len. We +also have to keep track of the raster size measured in three +different ways, as psize (portrait), lsize (landscape), and +msize (mixed). This is required to fill certain fields in +the font load. */ + +GLOBAL long int ras_len,psize,lsize,msize; + +/* The font load that we construct consists of a number of +LN03 fonts. Each of these contains up to 94 glyphs. They may +be "left fonts", so their glyphs are invoked with codes 33 +through 126; or they may be "right fonts" that respond to +codes 161 through 254. + +The font load that we construct is made up of alternating +left and right fonts (sometimes called "font pairs"). A TeX +font (represented by a txf record) is added to a font pair. +It may be split between the left and right halves of the +pair. + +The variable using_r keeps track of whether we are using a +right font. */ + +GLOBAL char using_r; + +GLOBAL unsigned int nft_first_ch,nft_last_ch,chardir_offset; +GLOBAL int lnf_chardir,ras_beg; +GLOBAL long ras_len_added; + +GLOBAL int pxlf,nftf; +GLOBAL PKFont *pkfont; + +/* The purpose of add_txf_to_lnf is to read the PXL, PK, or LN03 +font file corresponding to TeX font txfno and add its +rasters to the font pair referred to by lnfno. The function +returns 0 if all went well, and various negative numbers to +indicate problems. The number of bytes added to the font +load is returned in the global ras_len_added. */ + +int add_txf_to_lnf(lnfno,txfno) +int lnfno,txfno; +{ + int i,j,k,l,width; + int first_txfc,last_txfc; + char first_txf,last_txf; + + ras_len_added = 0; + + if (txfno < 0 || txfno > MAXTEXFONTS || txfa[txfno] == 0 || + lnfno < 0 || lnfno > maxnfonts) { + fprintf(stderr,"\nLn03DVI internal error, bad txfno or lnfno\n"); + goto error_return; + } + +/* Now, compute first_txfc and last_txfc, the first and last +characters codes to be copied from the TeX font. */ + + first_txfc = -1; last_txfc = -1; + for (i=0; i<256; i++) { + if (txfa[txfno] -> chu[i] != 0) { + if (first_txfc == -1) first_txfc = i; + last_txfc = i; + } + } + if (first_txfc == -1 || last_txfc == -1) return(0); + +/* Tell user what font is being loaded */ + + printf("Font %s:\t",font_name[txfno]); + k = (1500.0*conv*txfa[txfno] -> scaled_size)/ + (unmag_conv*txfa[txfno] -> design_size) + 0.5; + l = ((float)k)/15.0 + 0.5; + if (l != 100) printf("magnified %d%%, ",l); + fflush(stdout); + +/* Now open the file from which we are getting rasters. We +look first for a PK file, the for a PXL file, and finally for a +LN03 format font file (NFT file). */ + + pkfont = NULL; + pxlf = -1; + nftf = -1; + open_pk_file(txfno); + if (pkfont == NULL) open_pxl_file(txfno); + if (pkfont == NULL && pxlf == -1) open_nft_file(txfno); + +/* If neither a PXL file nor a PK file nor an LN03 format +file could be opened, warn the user. The font load will be +filled in with blanks nonetheless. */ + + if (pxlf == -1 && pkfont == NULL && nftf == -1) { + printf("not available, loading blanks, "); + fflush(stdout); + } + +/* Now replace first_txfc and last_txfc by the character +codes into which they are going to be copied. */ + + first_txfc = txfa[txfno] -> chu[first_txfc]; + last_txfc = txfa[txfno] -> chu[last_txfc]; + +/* Determine if this is the first or last TeX font that is +being copied into the current LN03 font pair. */ + + first_txf = (first_txfc == leftfirst); + last_txf = (last_txfc == lastch[lnfno]); + +/* If this is the first TeX font for the current LN03 font +pair, then we have to initialize the LN03 font load buffer. +The initialization routine computes where the rasters begin +in the output buffer, puts in the blanks, etc. */ + + if (first_txf) { + using_r = 0; + initialize_lnf(lnfno); + } + +/* Now go through all the characters in the TeX font and +copy their rasters into the appropriate positions in the +LN03 font pair. When we copy the the last rasters into the +left font, we write the font out and then a comma to +separate it from the next font. [[Fencepost error?]] */ + + for (i=0; i<256; i++) { + if (txfa[txfno] -> chu[i] != 0) { + j = txfa[txfno] -> chu[i]; + if (!using_r && j >= rightfirst) { + write_lnf(); + fprintf(outfile,"\n,"); + using_r = 1; + initialize_lnf(lnfno); + } + if (pxlf != -1) { + k = copy_pxl_char(i,j,lnfno); + if (k != 0) { + close(pxlf); + pxlf = -1; + } + } else if (nftf != -1) { + k = copy_nft_char(i,j,lnfno); + if (k != 0) { + close(nftf); + nftf = -1; + } + } else if (pkfont != NULL) { + k = copy_pk_char(pkfont,i,txfno,j,lnfno); + if (k != 0) { + PKUnloadFont(pkfont); + pkfont = NULL; + } + } + if (pxlf == -1 && pkfont == NULL && nftf == -1) { + width = font_width[txfno][i]*conv+0.5; + k = copy_ersatz_char(j,lnfno,width); + } + } + } + + if (nftf != -1) close(nftf); + if (pxlf != -1) close(pxlf); + if (pkfont != NULL) PKUnloadFont(pkfont); + +/* Type and return the incremental amount of space that the +TeX font being added takes up in the output font load. */ + + ras_len_added += 4*(txfa[txfno] -> nchs); + printf("%d bytes\n",ras_len_added); + +/* If this is the last TeX font being added to this LN03 +font pair, write out the current font (right or left) from +the pair. */ + + if (last_txf) write_lnf(); + + return(0); + +error_return: + return(-1); + +} + +/* A buffer is used to hold the directory part of the PXL file. */ + +#define PXLBUFSIZE 4*517 + +GLOBAL unsigned char pxlbuf[PXLBUFSIZE]; +GLOBAL long pxllen; + +/* The value pxlconv is computed to be the correct +conversion factor from the widths in the PXL file, which are +expressed in units of 2^-20 times the design size, to +pixels. */ + +GLOBAL float pxlconv; + +/* As usual when dealing with TeX files, we have to +rearrange bytes in an overlay to combine them into +longwords. The reason for this is that bytes in TeX files +are combined into longwords the opposite way from how the +VAX combines them. + +Hence, the following overlay and macro: */ + +GLOBAL union lc { unsigned long int ul; + long int l; + unsigned char c[4]; } lcy; + +#ifdef BIG_ENDIAN +#define copy_from_lnf(i) lcy.c[3] = lnf[i]; lcy.c[2] = lnf[i+1]; \ + lcy.c[1] = lnf[i+2]; lcy.c[0] = lnf[i+3] +#define copy_to_lnf(i) lnf[i] = lcy.c[3]; lnf[i+1] = lcy.c[2]; \ + lnf[i+2] = lcy.c[1] ; lnf[i+3] = lcy.c[0] +#define copy_from_pxl(_x) { lcy.c[0] = pxlbuf[_x]; \ + lcy.c[1] = pxlbuf[(_x)+1]; lcy.c[2] = pxlbuf[(_x)+2]; \ + lcy.c[3] = pxlbuf[(_x)+3]; } +#else /* not big endian */ +#define copy_from_lnf(i) lcy.c[0] = lnf[i]; lcy.c[1] = lnf[i+1]; \ + lcy.c[2] = lnf[i+2]; lcy.c[3] = lnf[i+3] +#define copy_to_lnf(i) lnf[i] = lcy.c[0]; lnf[i+1] = lcy.c[1]; \ + lnf[i+2] = lcy.c[2] ; lnf[i+3] = lcy.c[3] +#define copy_from_pxl(_x) { lcy.c[3] = pxlbuf[_x]; \ + lcy.c[2] = pxlbuf[(_x)+1]; lcy.c[1] = pxlbuf[(_x)+2]; \ + lcy.c[0] = pxlbuf[(_x)+3]; } +#endif + + +/* open_pxl_file reads the last 517 longwords of the PXL +file into the pxlbuf. */ + +int open_pxl_file(txfno) +int txfno; +{ + + long i,j; + float two_to_the_20th = 0x100000; + int k,l,jnam,jext,target; + char fullspec[FILESPECLEN]; +#ifndef vms + char *pxldir; +#endif + + find_filename(font_name[txfno],&jnam,&jext); + + fullspec[0] = '\0'; +#ifdef vms + if (jnam == 0) strcpy(fullspec,"TEX$PXLDIR:"); +#else + if (jnam == 0) { +#ifndef Apollo + pxldir = getenv("TEXPXLDIR"); + if (pxldir == NULL) + pxldir = "/usr/lib/tex/pxldir"; +#else + pxldir = "/usr/lib/tex/pxl"; +#endif + strcpy(fullspec,pxldir); + if (fullspec[strlen(fullspec)-1] != '/') + strcat(fullspec,"/"); + } +#endif + strcat(fullspec,font_name[txfno]); + + l = 1000.0 * ( (float) txfa[txfno]->scaled_size / + (float) txfa[txfno]->design_size ) + 0.5; + k = 0.5 + 1.5 * (conv / unmag_conv ) * (float) l ; + + l = strlen(fullspec); + sprintf(&fullspec[l],".%dpxl\0",k); + + pxllen = 0; + pxlf = open(fullspec,0); + if (pxlf == -1) return(1); + printf("loading PXL file %s%s, ",font_name[txfno],&fullspec[l]); + fflush(stdout); + + lseek(pxlf,-517*4,2); + i = read(pxlf,pxlbuf,517*4); + if (i != 517*4) { + if (i < 0) { + fflush(stdout); + perror("error"); + printf("\t\t"); + } else + printf("error: premature EOF (%d)\n\t\t",i); + close(pxlf); + pxlf = -1; + return(1); + } + pxllen = 4*517; + +/* Now that we have read the PXL file, check that it is in +correct format by looking for a trailing ID byte of 1001. */ + + copy_from_pxl(pxllen-4); + if (lcy.ul != 1001) { + printf("error: invalid .PXL id %d\n\t\t",lcy.ul); + close(pxlf); + pxlf = -1; + return(1); + } + +/* If the format is correct, derive a scale factor for the +widths. */ + + copy_from_pxl(pxllen-12); + pxlconv = lcy.ul; + copy_from_pxl(pxllen-16); + pxlconv = (pxlconv/two_to_the_20th)*(lcy.ul/5.0) + *(1.0/(72.27*two_to_the_20th)); +/* printf( "pxlconv=%g, ",pxlconv ); fflush(stdout); /**/ + + return(0); + +} + +GLOBAL unsigned char rev_byte[256] = { + 0,128,64,192,32,160,96,224, + 16,144,80,208,48,176,112,240, + 8,136,72,200,40,168,104,232, + 24,152,88,216,56,184,120,248, + 4,132,68,196,36,164,100,228, + 20,148,84,212,52,180,116,244, + 12,140,76,204,44,172,108,236, + 28,156,92,220,60,188,124,252, + 2,130,66,194,34,162,98,226, + 18,146,82,210,50,178,114,242, + 10,138,74,202,42,170,106,234, + 26,154,90,218,58,186,122,250, + 6,134,70,198,38,166,102,230, + 22,150,86,214,54,182,118,246, + 14,142,78,206,46,174,110,238, + 30,158,94,222,62,190,126,254, + 1,129,65,193,33,161,97,225, + 17,145,81,209,49,177,113,241, + 9,137,73,201,41,169,105,233, + 25,153,89,217,57,185,121,249, + 5,133,69,197,37,165,101,229, + 21,149,85,213,53,181,117,245, + 13,141,77,205,45,173,109,237, + 29,157,93,221,61,189,125,253, + 3,131,67,195,35,163,99,227, + 19,147,83,211,51,179,115,243, + 11,139,75,203,43,171,107,235, + 27,155,91,219,59,187,123,251, + 7,135,71,199,39,167,103,231, + 23,151,87,215,55,183,119,247, + 15,143,79,207,47,175,111,239, + 31,159,95,223,63,191,127,255 + }; + +#define pxl_word(_x) (pxlbuf[_x]*256+pxlbuf[(_x)+1]) +#define signed_pxl_word(_x) ((pxl_word(_x)>0x8000) ? \ + (pxl_word(_x)-0x10000) : pxl_word(_x)) + +/* Copy_pxl_char copies the rasters and character directory +information corresponding to code from in the PXL file, into +the to position of the LN03 font load buffer. */ + +int copy_pxl_char(from,to,lnfno) +unsigned char from,to; +int lnfno; +{ + + unsigned long ds,rs,i,j,def_start; + unsigned int rows,cols,k,l,m,n; + int xoffset, yoffset; + int width; + char all_blank; + +/* Check if the character code from is in the right range +for the PXL file. */ + + if (from > 127) return(1); + +/* Locate the definition and the rasters for from in the PXL +file. */ + + ds = 16*from; + copy_from_pxl(ds+8); + rs = 4*lcy.ul; + cols = pxl_word(ds); rows = pxl_word(ds+2); + +/* If a glyph has no rasters, an "undocumented feature" of +the LN03 seems to cause the glyph to be printed incorrectly. +Because of this, we set the number of rows and columns to 1, +and put in a blank byte (below). */ + + all_blank = ((rows == 0) & (cols == 0)) | rs == 0; + if (all_blank) { + cols = 1; + rows = 1; + } + +/* Compute the width of the glyph in pixels, the xoffset, +and the yoffset. */ + + copy_from_pxl(ds+12); + width = pxlconv*lcy.ul+0.5; + xoffset = signed_pxl_word(ds+4); + yoffset = signed_pxl_word(ds+6); + chw[lnfno][to] = width; + +/* Check that we have enough room left in the LN03 font load +buffer. Fudge factor of 3 added because the read below may +read too much. */ + + def_start = ras_beg+ras_len; + if (def_start+rows*((cols+7)/32)+24+3 > OBUFLEN) { + fprintf(stderr,"no more room in LN03 font load buffer (%ld bytes long)\n", + OBUFLEN); + return(1); + } + +/* Clear the character definition area in the LN03 font load +buffer. */ + + for(i=0; i<24+rows*((cols+7)/8); i++) + lnf[def_start+i] = 0; + +/* Set the fields in the first six longwords of the LN03 +font load character definition. The first assignment sets +the so-called "flag flag", which must be always be set +according to the Common Font File Format. A conversion +factor of 24 is used in converting pixel values, because the +values are supposed to be in centipoints in the LN03 font +load, and if we assume there are 300 pixels in an inch, then +there are 7200 centipoints in an inch. */ + + lnf[def_start+3] = 0x80; + lcy.ul = 24*width; + copy_to_lnf(def_start+4); + lcy.l = -24*xoffset; + copy_to_lnf(def_start+8); + lcy.l = -24*yoffset; + copy_to_lnf(def_start+12); + +/* The rasters are always placed in portrait into the LN03 +font load, with no use of run-length encoding. Thus, the +orient field in the raster format will be 0, and the Type 1 +field is set to 0x81. */ + + lnf[def_start+17] = 0x81; + lnf[def_start+20] = rows%256; + lnf[def_start+21] = rows/256; + lnf[def_start+22] = cols%256; + lnf[def_start+23] = cols/256; + +/* Now we copy the rasters themselves. As we do so, we have +to reverse the bits within each byte. */ + + k = (cols+31)/32; + n = (cols+7)/8; + lseek(pxlf,rs,0); + if (!all_blank) { + for (l=0; l<rows; l++) { + read(pxlf,&lnf[def_start+24+n*l],4*k); + } + for (m=0; m<n*rows; m++) + lnf[def_start+24+m] = rev_byte[lnf[def_start+24+m]]; + } + +/* Set the character locator, increment the LN03 font load +buffer length, and recompute the three sizes. */ + + lcy.l = def_start; + if (to <= leftlast) i = to-leftfirst; else i = to-rightfirst; + copy_to_lnf(lnf_chardir+4*i); + ras_len += 24+rows*n; + ras_len_added += 24+rows*n; + if (ras_len%2 == 1) { + lnf[ras_beg+ras_len] = 0; + ras_len++; + ras_len_added++; + } + + i = rows*((cols+7)/8); + psize += i; + j = ((rows+7)/8)*cols; + lsize += j; + msize += (i > j) ? i : j; + + return(0); +} + +/* Write a blank character of specified width (in pixels) +into LN03 font load buffer. Also, set the chw array. [[This +function is a bit excessive. If we couldn't find a +character's rasters, it would suffice just to leave the +character locator blank.]] */ + +int copy_ersatz_char(to,lnfno,width) +unsigned char to; +int lnfno,width; +{ + + unsigned long ds,rs,i,j,def_start; + unsigned int rows,cols,k,l,m,n; + + cols = 1; + rows = 1; + chw[lnfno][to] = width; + +/* Check that we have enough room left in the LN03 font load +buffer. Return silently if not. */ + + def_start = ras_beg+ras_len; + if (def_start+rows*((cols+7)/32)+24 > OBUFLEN) return(1); + +/* Clear the character definition area in the LN03 font load +buffer. */ + + for(i=0; i<24+rows*((cols+7)/8); i++) + lnf[def_start+i] = 0; + lnf[def_start+3] = 0x80; + lcy.ul = 24*width; + copy_to_lnf(def_start+4); + +/* The rasters are always placed in portrait into the LN03 +font load, with [no use of run-length encoding. Thus, the +orient field in the raster format will be 0, and the Type 1 +field is set to 0x81. */ + + lnf[def_start+17] = 0x81; + lnf[def_start+20] = rows%256; + lnf[def_start+21] = rows/256; + lnf[def_start+22] = cols%256; + lnf[def_start+23] = cols/256; + +/* Set the character locator, increment the LN03 font load +buffer length, and recompute the three sizes. */ + + n = (cols+7)/8; + lcy.l = def_start; + if (to <= leftlast) i = to-leftfirst; else i = to-rightfirst; + copy_to_lnf(lnf_chardir+4*i); + ras_len += 24+rows*n; + ras_len_added += 24+rows*n; + if (ras_len%2 == 1) { + lnf[ras_beg+ras_len] = 0; + ras_len++; + ras_len_added++; + } + + i = rows*((cols+7)/8); + psize += i; + j = ((rows+7)/8)*cols; + lsize += j; + msize += (i > j) ? i : j; + + return(0); +} + +/* The opening part of each NFT file is copied into the +array nfta. Nftlen keeps track of how much of the NFT file +we have read. Nftf is the file descriptor used to do the +reading. */ + +GLOBAL unsigned char nfta[480+1024]; +GLOBAL long nftlen; + +#define copy_from_nft(i) lcy.c[0] = nfta[i]; lcy.c[1] = nfta[i+1]; \ + lcy.c[2] = nfta[i+2]; lcy.c[3] = nfta[i+3] + +/* Open_nft_file opens the NFT file and reads the opening +part into the NFT array. */ + +int open_nft_file(txfno) +int txfno; +{ + int k,l,jnam,jext,target; + char fullspec[FILESPECLEN]; +#ifndef vms + char *ln3dir; +#endif + + find_filename(font_name[txfno],&jnam,&jext); + + fullspec[0] = '\0'; +#ifdef vms + if (jnam == 0) strcpy(fullspec,"TEX$LN03DIR:"); +#else + if (jnam == 0) { +#ifndef Apollo + ln3dir = getenv("TEXLN03DIR"); +#else + ln3dir = "/usr/lib/tex/ln03"; +#endif + strcpy(fullspec,ln3dir); + strcat(fullspec,"/"); + } +#endif + strcat(fullspec,font_name[txfno]); + k = (100.0*conv*txfa[txfno] -> scaled_size)/ + (unmag_conv*txfa[txfno] -> design_size) + 0.5; + l = strlen(fullspec); + if (k == 100) strcat(fullspec,".nft"); + else { + if (k < 1000) sprintf(&fullspec[l],".%03d\0",k); + else sprintf(&fullspec[l],".%d\0",k); + } + + nftlen = 0; + nftf = open(fullspec,0); + if (nftf == -1) return(1); + printf("loading NFT file %s%s, ", font_name[txfno],&fullspec[l]); + fflush(stdout); + + if (read_nft_with_retry(nfta,480) != 0) { + close(nftf); + nftf = -1; + return(1); + } + +/* The NFT file might be random, or it might be a Common +Font File Format file that isn't loadable into an LN03. So, +we make a few checks. + +The second longword must be 'FONT'. */ + + if (nfta[4] != 'F' || nfta[5] != 'O' || nfta[6] != 'N' + || nfta[7] != 'T') { + printf("error: Bad NFT file, lacks FONT.\n\t\t"); + close(nftf); + nftf = -1; + return(1); + } + +/* We also check that there are a full 16 bytes of character +parameters. If there are fewer, we give up: LN03s need all +sixteen, and it's too hard to figure out how to give the +missing ones reasonable values. + +Throughout this program, we define some constants beginning +with fnt__ which define byte offsets into the nft file. +[[The long prefixes of these may cause some trouble if one's +C compiler does not recognize too many significant +characters in identifiers.]] */ + +#define fnt__l_parameters_size 200 + + copy_from_nft(fnt__l_parameters_size); + if (lcy.l != 16) { + printf(" error: bad NFT file, not enough character parameters\n\t\t"); + close(nftf); + nftf = -1; + return(1); + } + +/* Set the variable that tells us the starting location of +the character directory. */ + + chardir_offset = 480; + +/* Figure out what the first and last character codes in the +NFT file are. */ + +#define fnt__l_first_character 164 + + copy_from_nft(fnt__l_first_character); + nft_first_ch = lcy.l; + copy_from_nft(fnt__l_first_character+4); + nft_last_ch = lcy.l; + +/* We must have 0 <= nft_first_ch <= nft_last_ch <= 255, +otherwise we give up on the NFT file. */ + + if (!((0 <= nft_first_ch) && (nft_first_ch <= nft_last_ch) && + (nft_last_ch <= 255))) { + printf(" error: bad NFT file, bad character range.\n\t\t"); + close(nftf); + nftf = -1; + return(1); + } + +/* Now read the character directory into the nfta. */ + + target = chardir_offset+4*(nft_last_ch+1-nft_first_ch); + if (read_nft_with_retry(&nfta[480],target) != 0) { + close(nftf); + nftf = -1; + return(1); + } + return(0); +} + +/* Copy_nft_char copies the character parameters and rasters +corresponding to the from argument out of the NFT file and +into the LN03 font buffer. It also updates the chw +(character width) array. */ + +int copy_nft_char(from,to,lnfno) +unsigned char from,to; +int lnfno; +{ + + int rows,columns,quo; + long i,j,len,def_start,target; + +/* Replace from by the first character code if the NFT file +has no rasters for code from. If this is done, the output +will of course be mangled. The user has already been warned +above, so no further message is needed. */ + + if (from < nft_first_ch) from = nft_first_ch; + if (from > nft_last_ch) from = nft_last_ch; + +/* First we need to determine def_start, the byte offset of +the character definition for code from in the NFT file */ + + copy_from_nft(chardir_offset+(from-nft_first_ch)*4); + def_start = lcy.l; + +/* If the locator is earlier in the file, just give up. Otherwise, assume +it's good, continue and give a vague error message is something goes wrong. +*/ + + if (def_start < nftlen || read_nft_until(def_start) != 0) { + printf(" -- LN03 font file bad, using blanks\n"); + return(1); + } + +/* Read the first 24 bytes of character data. */ + + def_start = ras_beg+ras_len; + if (read_nft_with_retry(&lnf[def_start],nftlen+24) != 0) return(1); + +/* Now we need to check that the rasters are uncompressed. +LN03s can't accept compressed rasters, and this program +isn't clever enough to decompress them. */ + + if (lnf[def_start+17] != 129) { + printf(" -- LN03 font file bad, using blanks\n"); + return(1); + } + +/* Fill in the chw array (which holds character widths). +Centipoint to pixel conversion is necessary (there are 24 +centipoints in a pixel), with rounding (hence the 12). */ + + copy_from_lnf(def_start+4); + chw[lnfno][to] = (lcy.l+12)/24; + +/* NFT files may contain character widths which are not +integral numbers of pixels. It is necessary to round such +values to pixels when copying into the final font load -- if +sent unrounded to the LN03, the widths will be truncated and +positions will be off in the printed output. */ + + lcy.l = 24*chw[lnfno][to]; + copy_to_lnf(def_start+4); + +/* Now we need to compute the size of the rasters, and copy +that number of bytes into the LN03 font buffer. */ + + rows = lnf[def_start+20]+256*lnf[def_start+21]; + columns = lnf[def_start+22]+256*lnf[def_start+23]; + +/* We have to update psize, lsize and msize to fill slots in +the format. */ + + quo = rows/8; + if (rows != quo*8) quo++; + i = quo*columns; + lsize += quo*columns; + quo = columns/8; + if (columns != quo*8) quo++; + psize += quo*rows; + if (i > quo*rows) msize += i; else msize += quo*rows; + +/* Now do the actual copy. We have to ensure that the rasters are +word-aligned in the font load (where one word = 2 bytes, of course). */ + + if (lnf[def_start+16] % 2 == 0) len = quo*rows; else len = i; + if (read_nft_with_retry(&lnf[def_start+24],nftlen+len) != 0) + return(1); + lcy.l = def_start; + if (to <= leftlast) i = to-leftfirst; else i = to-rightfirst; + copy_to_lnf(lnf_chardir+4*i); + ras_len += len+24; + ras_len_added += len+24; + if (ras_len % 2 != 0) { + lnf[ras_beg+ras_len] = 0; + ras_len++; + ras_len_added++; + } + return(0); + +} + +int read_nft_with_retry(where,upto) +long upto; +char *where; +{ + long i,target; + int l; + + i = 0; + while (nftlen < upto) { + target = upto-nftlen; + l = read(nftf,&where[i],target); + if (l <= 0) { + printf(" -- LN03 font file bad, using blanks\n"); + return(1); + } + nftlen += l; + i += l; + } + return(0); +} + +int read_nft_until(pos) +long pos; +{ + char bit_bucket[512]; + int l; + long target; + + while (nftlen < pos) { + target = pos-nftlen; + if (target > 512) target = 512; + l = read(nftf,bit_bucket,target); + if (l <= 0) { + printf(" -- LN03 font file bad, using blanks\n"); + return(1); + } + nftlen += l; + } + return(0); +} + +GLOBAL unsigned char preline[96]; + +/* write_lnf performs the last fixups to the LN03 fnnt buffer and dumps it, +sixelized, into the output file. */ + +int write_lnf (){ + + long i,j,k,rem,quo,ma; + +/* We now have to fix a number of slots: size of file, length of rasters, +final 'FONT', psize, lsize, msize. */ + + lcy.l = ras_beg+ras_len+8; + copy_to_lnf(0); + copy_to_lnf(lcy.l-8); + lnf[lcy.l-4] = 'F'; + lnf[lcy.l-3] = 'O'; + lnf[lcy.l-2] = 'N'; + lnf[lcy.l-1] = 'T'; + +/* Clear out remaining bytes up to 96 more. */ + + j = 96*((lcy.l+95)/96); + for (i=lcy.l; i<j; i++) lnf[i] = 0; + +/* Length of rasters */ + +#define fnt__l_char_definitions_length 156 + + lcy.l = ras_len; + copy_to_lnf(fnt__l_char_definitions_length); + +#define fnt__l_portrait_byte_count 228 +#define fnt__l_landscape_byte_count 232 +#define fnt__l_mixed_byte_count 236 + + lcy.l = psize; + copy_to_lnf(fnt__l_portrait_byte_count); + + lcy.l = lsize; + copy_to_lnf(fnt__l_landscape_byte_count); + + lcy.l = msize; + copy_to_lnf(fnt__l_mixed_byte_count); + +/* Now sixelize and write the contents of LNF. */ + + sixelize_and_write(ras_beg+ras_len+8); + return(0); +} + +int sixelize_and_write(howmuch) +int howmuch; +{ + int quo,i,j; + + quo = howmuch/96; + if (howmuch > quo*96) quo++; + + for (i=0; i<quo; i++) { + for (j=0; j<96; j++) + preline[j] = lnf[96*i+j]; + write_preline(); + } + +} + +int write_preline() { + + char sixel_line[129]; + int i,j,ix,pllen; + unsigned v,w; + + pllen = 96; + ix = 0; + sixel_line[128] = '\0'; + for (i=0; i<128; i++) sixel_line[i] = '?'; + for (i=0; i<pllen; i += 3) { + v = preline[i]; + w = v>>2; + sixel_line[ix] = 63+w; + ix++; + w = (v&3)<<4; + v = preline[i+1]; + w |= v>>4; + sixel_line[ix] = 63+w; + ix++; + w = (v&15)<<2; + v = preline[i+2]; + w |= v>>6; + sixel_line[ix] = 63+w; + ix++; + w = v&63; + sixel_line[ix] = 63+w; + ix++; + } + fprintf(outfile,"\n%s",sixel_line); +} + +/* Initializes the LN03 font buffer. */ + +int initialize_lnf(lnfno) +int lnfno; +{ + int i,j; + +/* The following array holds reasonable values for bytes 0-479 of an LN03 +format font. These bytes were copied from a font load which the LN03 was +known to accept. The font loads generated by this program are initialized +using these values. Some of them are overwritten later, however. */ + + static char good_opening[512] = { + 104,38,0,0,70,79,78,84, + 1,0,0,0,31,0,0,0, + 20,0,0,0,85,48,48,48, + 48,48,48,48,48,50,83,75, + 48,48,71,71,48,48,48,49, + 85,90,90,90,90,48,50,70, + 48,48,48,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 181,7,9,0,11,0,14,0, + 0,0,0,0,104,0,0,0, + 252,0,0,0,124,0,0,0, + 100,1,0,0,120,1,0,0, + 224,1,0,0,4,0,0,0, + 88,3,0,0,0,0,0,0, + 92,3,0,0,48,0,0,0, + 92,3,0,0,0,0,0,0, + 140,3,0,0,212,34,0,0, + 140,3,0,0,33,0,0,0, + 126,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 32,0,0,0,168,0,0,0, + 16,0,0,0,94,0,0,0, + 0,0,0,0,94,0,0,0, + 0,0,0,0,94,0,0,0, + 0,0,0,0,236,25,0,0, + 54,25,0,0,14,27,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,2,0,0,0, + 7,0,0,0,92,3,0,0, + 7,0,0,0,99,3,0,0, + 16,0,0,0,106,3,0,0, + 16,0,0,0,122,3,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 10,0,0,0,244,1,0,0, + 0,0,24,0,16,0,0,0, + 16,0,0,0,1,0,1,0, + 1,0,1,0,0,0,1,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 30,0,0,0,20,0,0,0, + 196,255,255,255,20,0,0,0, + 106,255,255,255,20,0,0,0, + 0,0,1,0,0,0,30,0, + 166,255,255,255,0,0,0,0, + 40,0,0,0,0,0,0,0, + 60,0,0,0,240,0,0,0, + 60,0,0,0,100,0,0,0, + 240,0,0,0,120,0,0,0, + 40,0,0,0,120,0,0,0, + 96,255,255,255,136,255,255,255, + 186,255,255,255,240,0,0,0, + 76,255,255,255,60,0,0,0, + 160,0,0,0,120,0,0,0, + 20,0,0,0,20,0,0,0, + 140,3,0,0,194,3,0,0, + 244,3,0,0,160,4,0,0, + 254,4,0,0,162,5,0,0, + 46,6,0,0,84,6,0,0}; + int pool_beg; + +/* The character directory always begins at position 480 in the Common +Font File Format. */ + + lnf_chardir = 480; + ras_len = 0; + psize = 0; + lsize = 0; + msize = 0; + +/* Copy the good values into the lnf array */ + + for (i=0; i<480; i++) + lnf[i] = good_opening[i]; + +/* Set the last character if necessary */ + +#define fnt__l_first_character 164 + + if (lastch[lnfno] < leftlast && !using_r) + lnf[fnt__l_first_character+4] = lastch[lnfno]; + if (using_r) + lnf[fnt__l_first_character+4] = lastch[lnfno]-rightfirst+ + leftfirst; + +/* Set the character counts */ + +#define fnt__l_infile_locators 204 +#define fnt__l_character_definitions 212 +#define fnt__l_raster_count 220 + + i = lnf[fnt__l_first_character+4]- + lnf[fnt__l_first_character]+1; + ras_beg = lnf_chardir + 4*i + 4 + 48; + lnf[fnt__l_infile_locators] = i; + lnf[fnt__l_character_definitions] = i; + lnf[fnt__l_raster_count] = i; + lnf[ras_beg-52] = lnf[ras_beg-51] = lnf[ras_beg-50] = + lnf[ras_beg-49] = 0; + +/* Set the font file id. This id is a 31-byte string. We make it depend on +the lnfno number, and on whether this is a left or right font. +Specifically, the first seven bytes are U0000nn where nn is lnfno possibly +with a leading zero. The character set part of the ID is 1O if using_r, +otherwise the default from good_opening. */ + +#define fnt__t_font_file_id 20 + + lnf[fnt__t_font_file_id+5] = lnfno/10+'0'; + lnf[fnt__t_font_file_id+6] = lnfno % 10 + '0'; + if (using_r) lnf[fnt__t_font_file_id+20] = 'O'; + +/* We now have to set some fields in the font format that are pointers to +where other fields begin. These pointers depend on the number of glyphs we +are placing in the font file. */ + +#define fnt__a_subset_tables 128 + + lcy.l = lnf_chardir+4*i; + copy_to_lnf(fnt__a_subset_tables); + + lcy.l = lcy.l+4; + copy_to_lnf(fnt__a_subset_tables+8); + copy_to_lnf(fnt__a_subset_tables+16); + + lcy.l = lcy.l+48; + copy_to_lnf(fnt__a_subset_tables+24); + +#define fnt__a_char_definitions 160 + + copy_to_lnf(fnt__a_char_definitions); + +/* Set up the string pool region of the font load (48 bytes). The only +tricky part here is the character set designator at the very beginning of +the pool. Left fonts use one designator, right fonts another. [[More +explanation is needed.]] */ + + pool_beg = ras_beg-48; + + lnf[pool_beg] = '0'; + lnf[pool_beg+1] = using_r ? '<':'B'; + lnf[pool_beg+2] = '\011'; /* ascii tab */ + lnf[pool_beg+3] = 'Z'; + lnf[pool_beg+4] = 'Z'; + lnf[pool_beg+5] = 'Z'; + lnf[pool_beg+6] = 'Z'; + +/* For reasons that are beyond my comprehension, the Common Font File +Format requires us to copy the first seven characters of the font file id +into one piece of the string pool, and the first sixteen into another +place. */ + + for (i=1; i<8; i++) + lnf[pool_beg+7+i-1] = lnf[fnt__t_font_file_id+i-1]; + for (i=1; i<17; i++) + lnf[pool_beg+7+7+i-1] = ' '; + for (i=1; i<17; i++) + lnf[pool_beg+7+7+16+i-1] = lnf[fnt__t_font_file_id+i-1]; + lnf[pool_beg+46] = lnf[pool_beg+47] = 0; + +/* Now make string descriptors point into the string pool. */ + +#define fnt__a_char_set 260 +#define fnt__a_family_id 268 +#define fnt__a_family_name 276 +#define fnt__a_font_id 284 + + lcy.l = pool_beg; + copy_to_lnf(fnt__a_char_set); + lcy.l = pool_beg+7; + copy_to_lnf(fnt__a_family_id); + lcy.l = pool_beg+7+7; + copy_to_lnf(fnt__a_family_name); + lcy.l = pool_beg+7+7+16; + copy_to_lnf(fnt__a_font_id); + +/* Mercifully, all remaining font file slots that we can fill now are +already good as received from good_opening. */ + +} + + +/* There are only two global entry points to this code. here they are: */ + +extern int open_pk_file(); +extern int copy_pk_char(); + +/* We use the following global variables (that were previously defined). */ + +EXTERN PKFont *pkfont; /* in open_pk_file */ +static float pkconv; /* conversion factor */ + +/* This routine opens the PK file. It really is just a jacket for the +routine PKLoadFont We also calculate the conversion factor (pkconv). + +Much of this routine is taken or adapted from open_pxl_file. */ + + +int open_pk_file(txfno) +int txfno; +{ + float two_to_the_20th = 0x100000; + int magnification; + + magnification = 1000.0 * ( (float) txfa[txfno]->scaled_size / + (float) txfa[txfno]->design_size ) + 0.5; + + pkfont = PKLoadFont( font_name[txfno], magnification, 300 ); + if (pkfont == NULL) { + if (errno != ENOENT && errno != ENXIO) + fprintf( stderr, "%s\n\t\t", PKerror ); + return(-1); + } + printf("loading PK file %s, ", PKerror); fflush(stdout); + + pkconv = ( (float) pkfont->design_size * (float) pkfont->magnification ) / + ( 5.0 * 72.27 * two_to_the_20th * two_to_the_20th ); +#ifdef PKDEBUG + printf( "pkconv=%g, ", pkconv ); fflush(stdout); +#endif + return(0); +} + + +/* This routine obtains a glyph from a PK font then copies it to the LN03 +buffer. If the glyph isn't in the font, then we call copy_ersatz_char +to insert a blank character. This routine has greatly adapted and/or +stolen code from copy_pxl_char. */ + +copy_pk_char(fontptr,from,txfno,to,lnfno) +PKFont *fontptr; +unsigned char from,to; +int txfno,lnfno; +{ + PKGlyph *glyphptr; + int i,j, bytes_per_row, def_start = ras_beg + ras_len; + int tfm_width, width; + + glyphptr = PKGetGlyph( fontptr, (int) from ); /* get the glyph */ + + if (glyphptr == NULL) { /* not there? */ + width = font_width[txfno][from]*conv + 0.5; /* insert a */ + return copy_ersatz_char(to,lnfno,width); /* blank */ + } else if (strlen(PKerror) != 0) { /* error? */ + printf("%s\n\t\t",PKerror); /* print it out */ + } + + if (glyphptr->height == 0 || glyphptr->width == 0) { /* kludge for LN03 */ + width = font_width[txfno][from]*conv + 0.5; /* insert a blank */ + return copy_ersatz_char(to,lnfno,width); + } + +/* Copy the rasters to the LN03 buffer. First zero the LN03 glyph header +and the copy the rasters. */ + + bytes_per_row = (glyphptr->width + 7) / 8; + + for (i = 0; i < 24; i++ ) + lnf[def_start+i] = 0; + + for (i = 0; i < glyphptr->height*bytes_per_row; i++ ) + lnf[def_start+i+24] = glyphptr->rasters[i]; + +/* Fill in the header for the LN03 glyph */ + + tfm_width = glyphptr->tfm_width*pkconv + 0.5; + chw[lnfno][to] = glyphptr->h_escapement / 65536; +#ifdef PKDEBUG + if (tfm_width != chw[lnfno][to]) { +#ifdef vms + globalvalue SS$_DEBUG; + LIB$SIGNAL(SS$_DEBUG); +#else + abort(); +#endif + } +#endif + + + lnf[def_start+3] = 0x80; + lcy.ul = 24*chw[lnfno][to]; copy_to_lnf(def_start+4); + lcy.l = -24*glyphptr->h_offset; copy_to_lnf(def_start+8); + lcy.l = -24*glyphptr->v_offset; copy_to_lnf(def_start+12); + + lnf[def_start+17] = 0x81; + lnf[def_start+20] = glyphptr->height%256; + lnf[def_start+21] = glyphptr->height*256; + lnf[def_start+22] = glyphptr->width%256; + lnf[def_start+23] = glyphptr->width*256; + +/* The following is copy directly from copy_pxl_char. I have no idea what +it is really for... */ + + { int i, j; + lcy.l = def_start; + if (to <= leftlast) i = to-leftfirst; else i = to-rightfirst; + copy_to_lnf(lnf_chardir+4*i); + ras_len += 24 + glyphptr->height*bytes_per_row; + ras_len_added += 24 + glyphptr->height*bytes_per_row; + if (ras_len%2 == 1) { + lnf[ras_beg+ras_len] = 0; + ras_len++; + ras_len_added++; + } + + i = glyphptr->height*((glyphptr->width+7)/8); + psize += i; + j = ((glyphptr->height+7)/8)*glyphptr->width; + lsize += j; + msize += (i > j) ? i : j; + } + return(0); +} |