summaryrefslogtreecommitdiff
path: root/dviware/beebe/src/charpk.h
blob: 21a35f5aedbe3b1797f9095e28d54e3868e4f496 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
/* -*-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)	/* <PKtoPX: Get raster by bits> */
    {		/* 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	/* <PKtoPX: Create normally packed raster> */
    {	/* 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());
    }
}