/* -*-C-*- charpk.h */ /*-->charpk*/ /**********************************************************************/ /******************************* charpk *******************************/ /**********************************************************************/ /* This file departs from all others in the DVIxxx family in that it declares some private functions and globals which are required nowhere else. Only charpk() is called from outside. */ BYTE get_bit(); /* return next bit from file */ BYTE get_nybble(); /* return next 4-bit nybble from file */ UNSIGN16 pk_packed_num(); /* get packed number from file */ BYTE bit_weight; /* weight of current bit in next_byte */ BYTE dyn_f; /* dynamic packing flag */ UNSIGN16 repeat_count; /* how many times to repeat next row */ BYTE next_byte; /* current input byte */ BYTE word_weight; /* weight of current bit in *pword */ /**********************************************************************/ int charpk(c,outfcn) /* return 0 on success, and EOF on failure */ BYTE c; /* current character value */ void (*outfcn)(); /* (possibly NULL) function to output current row */ { INT16 count; /* how many bits of current color left */ UNSIGN16 c_width; /* character width in dots */ UNSIGN16 c_height; /* character height in dots */ BOOLEAN do_output; /* FALSE if outfcn is NULL */ register BYTE flag_byte; /* current file flag byte */ UNSIGN16 h_bit; /* horizontal position in row */ register UNSIGN16 i; /* loop index */ register UNSIGN16 k; /* loop index */ long offset; /* offset into font file */ long p; /* pointer into font file */ UNSIGN32 packet_length; /* packet length */ UNSIGN32* pword; /* pointer into img_row[] */ INT16 rows_left; /* how many rows left */ struct char_entry *tcharptr;/* temporary char_entry pointer */ BYTE turn_on; /* initial black/white flag */ /******************************************************************* This function is called to process a single character description in the PK font file. The character packet is pointed to by fontptr->ch[c].fontrp, and was set by readpk(), which moved past any special commands that precede the packet. The PK raster description is encoded in a complex form, but is guaranteed to step across raster rows from left to right, and down from the top row to bottom row, such that in references to image[n][m], m never decreases in a row, and n never increases in a character. This means that we only require enough memory space to hold one row, provided that outfcn(c,yoff) is called each time a row is completed. This is an important economization for high-resolution output devices -- e.g. a 10pt character at 2400 dots/inch would require about 8Kb for the entire image, but fewer than 25 bytes for a single row. A 72pt character (such as in the aminch font) would need about 430Kb for the image, but only about 200 bytes for a row. The code follows PKtoPX quite closely, particular the latter's sections 37-43 for preamble processing, and sections 44-51 for raster decoding. Access to bit m in the current row is controlled through the macros SETBIT(m) and TESTBIT(m) so we need not be concerned about the details of bit masking. Too bad C does not have a bit data type! The row image is recorded in such a way that bits min_m .. max_m are mapped onto bits 0 .. (max_m - min_m) in img_row[], so that outfcn(c,yoff) should be relieved of any shifting operations. outfcn(c,yoff) is NEVER called if either of hp or wp is <= 0, or if it is NULL. *******************************************************************/ if ((c < FIRSTPXLCHAR) || (LASTPXLCHAR < c)) { (void)warning( "charpk(): Character value out of range for PK font file"); return(EOF); } tcharptr = &(fontptr->ch[c]); if (!VISIBLE(tcharptr)) return(0); /* empty character raster -- nothing to output */ c_width = (UNSIGN16)tcharptr->wp; /* local copies of these to save */ c_height = (UNSIGN16)tcharptr->hp; /* pointer dereferencing in loops */ p = (long)tcharptr->fontrp; /* font file raster pointer */ if (p < 0L) { (void)warning( "charpk(): Requested character not found in PK font file"); return(EOF); } if (FSEEK(fontfp,p,0)) { (void)warning( "charpk(): FSEEK() failure for PK font file character raster"); return(EOF); } /* Since readpk() has already done error checking on the file, and recorded the character metrics, we need not repeat that work, and concentrate instead on getting to the encoded raster description which follows the character packet. */ img_words = (UNSIGN16)(c_width + 31) >> 5; flag_byte = (BYTE)nosignex(fontfp,(BYTE)1); /* get packet flag byte */ dyn_f = flag_byte >> 4; /* dyn_f is high 4 bits from flag_byte */ turn_on = (BYTE)(flag_byte & 0x08); /* turn_on is 8-bit from flag_byte */ flag_byte &= 0x07; /* final flag_byte is low 3 bits */ do_output = (BOOLEAN)(outfcn != (void(*)())NULL); switch(flag_byte) /* flag_byte is in 0..7 */ { case 0: case 1: case 2: case 3: /* short character preamble */ packet_length = (UNSIGN32)flag_byte; packet_length <<= 8; packet_length += (UNSIGN32)nosignex(fontfp,(BYTE)1); packet_length -= 8L; offset = 9L; break; case 4: case 5: case 6: /* extended short character preamble */ packet_length = (UNSIGN32)(flag_byte & 0x03); packet_length <<= 16; packet_length += (UNSIGN32)nosignex(fontfp,(BYTE)2); packet_length -= 13L; offset = 14L; break; case 7: /* long character preamble */ packet_length = (UNSIGN32)nosignex(fontfp,(BYTE)4); packet_length -= 28L; offset = 32L; break; } /* end switch */ if (FSEEK(fontfp,offset,1)) /* position to start of raster data */ { (void)warning( "charpk(): FSEEK() failure for PK font file character raster"); return(EOF); } bit_weight = 0; if (dyn_f == (BYTE)14) /* */ { /* uncompressed character image */ for (i = 0; i < c_height; ++i) { pword = img_row; if (do_output) (void)clrrow(); word_weight = (BYTE)31; for (k = 0; k < c_width; ++k) { if (get_bit()) *pword |= power[word_weight]; if (word_weight) --word_weight; else { ++pword; word_weight = (BYTE)31; } } /* end for (k) */ if (do_output) (void)(*outfcn)(c,i); } /* end for (i) */ } else /* */ { /* run-length encoded character image */ rows_left = (INT16)c_height; h_bit = c_width; repeat_count = 0; word_weight = (BYTE)32; pword = img_row; if (do_output) (void)clrrow(); /* clear img_row[] */ while (rows_left > 0) { count = (INT16)pk_packed_num(); while (count > 0) { if ( (count < (INT16)word_weight) && (count < (INT16)h_bit) ) { if (turn_on) { *pword |= gpower[word_weight]; *pword &= ~gpower[word_weight - count]; } h_bit -= (UNSIGN16)count; word_weight -= (BYTE)count; count = 0; } else if ( (count >= (INT16)h_bit) && (h_bit <= (UNSIGN16)word_weight) ) { if (turn_on) { *pword |= gpower[word_weight]; *pword &= ~gpower[word_weight - h_bit]; } if (do_output) { for (i = 0; i <= repeat_count; (--rows_left, ++i)) (void)(*outfcn)(c,(UNSIGN16)(c_height-rows_left)); } else rows_left -= (INT16)(repeat_count + 1); repeat_count = 0; pword = img_row; if (do_output) (void)clrrow(); word_weight = (BYTE)32; count -= (INT16)h_bit; h_bit = c_width; } else { if (turn_on) *pword |= gpower[word_weight]; pword++; count -= (INT16)word_weight; h_bit -= (UNSIGN16)word_weight; word_weight = (BYTE)32; } } /* end while (count > 0) */ turn_on = (BYTE)(!turn_on); } /* end while (rows_left > 0) */ if ((rows_left > 0) || (h_bit != c_width)) { (void)warning( "charpk(): Bad PK font file--more bits than required"); return(EOF); } } /* end if (run-length encoded image) */ return(0); } /*-->get_bit*/ /**********************************************************************/ /****************************** get_bit *******************************/ /**********************************************************************/ BYTE get_bit() /* return 0, or non-zero (not necessarily 1) */ { register BYTE temp; bit_weight >>= 1; if (bit_weight == 0) /* then must get new byte from font file */ { next_byte = (BYTE)nosignex(fontfp,(BYTE)1); bit_weight = (BYTE)128; } temp = next_byte & bit_weight; next_byte &= ~bit_weight; /* clear the just-read bit */ return (temp); } /*-->get_nybble*/ /**********************************************************************/ /***************************** get_nybble *****************************/ /**********************************************************************/ BYTE get_nybble() { register BYTE temp; if (bit_weight == 0) /* get high nybble */ { next_byte = (BYTE)nosignex(fontfp,(BYTE)1); temp = next_byte >> 4; next_byte &= 0x0f; bit_weight = (BYTE)1; } else /* get low nybble */ { temp = next_byte; /* this has only 4 bits in it */ bit_weight = (BYTE)0; } return(temp); } /*-->pk_packed_num*/ /**********************************************************************/ /*************************** pk_packed_num ****************************/ /**********************************************************************/ UNSIGN16 pk_packed_num() /* return a (non-negative) packed number from the font file */ { /* this function is recursive to one level only */ INT16 i,j; i = (INT16)get_nybble(); if (i == 0) { do { j = (INT16)get_nybble(); ++i; } while (j == 0); while (i > 0) { j <<= 4; j += (INT16)get_nybble(); --i; } return((UNSIGN16)(j - 15 + ((13 - dyn_f) << 4) + dyn_f)); } else if (i <= (INT16)dyn_f) return((UNSIGN16)i); else if (i < 14) return((UNSIGN16)(((i - dyn_f - 1) << 4) + get_nybble() + dyn_f + 1)); else if (i == 14) { repeat_count = pk_packed_num(); return(pk_packed_num()); } else { repeat_count = 1; return(pk_packed_num()); } }