1 /*
2  * Copyright (C) 2000, Matias Atria
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 /* Bitmap manipulation routines */
20 
21 #include <config.h>
22 #include <stdlib.h>
23 
24 #include "mdvi.h"
25 #include "color.h"
26 
27 /* bit_masks[n] contains a BmUnit with `n' contiguous bits */
28 
29 static BmUnit bit_masks[] = {
30 	0x0,		0x1,		0x3,		0x7,
31 	0xf,		0x1f,		0x3f,		0x7f,
32 	0xff,
33 #if BITMAP_BYTES > 1
34 			0x1ff,		0x3ff,		0x7ff,
35 	0xfff,		0x1fff,		0x3fff,		0x7fff,
36 	0xffff,
37 #if BITMAP_BYTES > 2
38 			0x1ffff,	0x3ffff,	0x7ffff,
39 	0xfffff,	0x1fffff,	0x3fffff,	0x7fffff,
40 	0xffffff,	0x1ffffff,	0x3ffffff,	0x7ffffff,
41 	0xfffffff,	0x1fffffff,	0x3fffffff,	0x7fffffff,
42 	0xffffffff
43 #endif /* BITMAP_BYTES > 2 */
44 #endif /* BITMAP_BYTES > 1 */
45 };
46 
47 #ifndef NODEBUG
48 #define SHOW_OP_DATA	(DEBUGGING(BITMAP_OPS) && DEBUGGING(BITMAP_DATA))
49 #endif
50 
51 /*
52  * Some useful macros to manipulate bitmap data
53  * SEGMENT(m,n) = bit mask for a segment of `m' contiguous bits
54  * starting at column `n'. These macros assume that
55  *    m + n <= BITMAP_BITS, 0 <= m, n.
56  */
57 #ifdef WORD_BIG_ENDIAN
58 #define SEGMENT(m,n)	(bit_masks[m] << (BITMAP_BITS - (m) - (n)))
59 #else
60 #define SEGMENT(m,n)	(bit_masks[m] << (n))
61 #endif
62 
63 /* sampling and shrinking routines shamelessly stolen from xdvi */
64 
65 static int sample_count[] = {
66 	0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
67 	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
68 	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
69 	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
70 	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
71 	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
72 	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
73 	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
74 	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
75 	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
76 	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
77 	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
78 	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
79 	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
80 	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
81 	4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
82 };
83 
84 /* bit_swap[j] = j with all bits inverted (i.e. msb -> lsb) */
85 static Uchar bit_swap[] = {
86 	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
87 	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
88 	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
89 	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
90 	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
91 	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
92 	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
93 	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
94 	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
95 	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
96 	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
97 	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
98 	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
99 	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
100 	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
101 	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
102 	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
103 	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
104 	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
105 	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
106 	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
107 	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
108 	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
109 	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
110 	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
111 	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
112 	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
113 	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
114 	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
115 	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
116 	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
117 	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
118 };
119 
120 
121 /*
122  * next we have three bitmap functions to convert bitmaps in LSB bit order
123  * with 8, 16 and 32 bits per unit, to our internal format. The differences
124  * are minimal, but writing a generic function to handle all unit sizes is
125  * hopelessly slow.
126  */
127 
bitmap_convert_lsb8(Uchar * bits,int w,int h,int stride)128 BITMAP	*bitmap_convert_lsb8(Uchar *bits, int w, int h, int stride)
129 {
130 	BITMAP	*bm;
131 	int	i;
132 	Uchar	*unit;
133 	register Uchar *curr;
134 	int	bytes;
135 
136 	DEBUG((DBG_BITMAP_OPS, "convert LSB %dx%d@8 -> bitmap\n", w, h));
137 
138 	bm = bitmap_alloc_raw(w, h);
139 
140 	/* this is the number of bytes in the original bitmap */
141 	bytes = ROUND(w, 8);
142 	unit  = (Uchar *)bm->data;
143 	curr = bits;
144 	/* we try to do this as fast as we can */
145 	for(i = 0; i < h; i++) {
146 #ifdef WORD_LITTLE_ENDIAN
147 		memcpy(unit, curr, bytes);
148 		curr += stride;
149 #else
150 		int	j;
151 
152 		for(j = 0; j < bytes; curr++, j++)
153 			unit[j] = bit_swap[*curr];
154 		cur += stride - bytes;
155 #endif
156 		memzero(unit + bytes, bm->stride - bytes);
157 		unit  += bm->stride;
158 	}
159 	if(SHOW_OP_DATA)
160 		bitmap_print(stderr, bm);
161 	return bm;
162 }
163 
bitmap_convert_msb8(Uchar * data,int w,int h,int stride)164 BITMAP	*bitmap_convert_msb8(Uchar *data, int w, int h, int stride)
165 {
166 	BITMAP	*bm;
167 	Uchar	*unit;
168 	Uchar	*curr;
169 	int	i;
170 	int	bytes;
171 
172 	bm = bitmap_alloc(w, h);
173 	bytes = ROUND(w, 8);
174 	unit = (Uchar *)bm->data;
175 	curr = data;
176 	for(i = 0; i < h; i++) {
177 #ifdef WORD_LITTLE_ENDIAN
178 		int	j;
179 
180 		for(j = 0; j < bytes; curr++, j++)
181 			unit[j] = bit_swap[*curr];
182 		curr += stride - bytes;
183 #else
184 		memcpy(unit, curr, bytes);
185 		curr += stride;
186 #endif
187 		memzero(unit + bytes, bm->stride - bytes);
188 		unit += bm->stride;
189 	}
190 	if(SHOW_OP_DATA)
191 		bitmap_print(stderr, bm);
192 	return bm;
193 }
194 
195 
bitmap_copy(BITMAP * bm)196 BITMAP	*bitmap_copy(BITMAP *bm)
197 {
198 	BITMAP	*nb = bitmap_alloc(bm->width, bm->height);
199 
200 	DEBUG((DBG_BITMAP_OPS, "copy %dx%d\n", bm->width, bm->height));
201 	memcpy(nb->data, bm->data, bm->height * bm->stride);
202 	return nb;
203 }
204 
bitmap_alloc(int w,int h)205 BITMAP	*bitmap_alloc(int w, int h)
206 {
207 	BITMAP	*bm;
208 
209 	bm = xalloc(BITMAP);
210 	bm->width = w;
211 	bm->height = h;
212 	bm->stride = BM_BYTES_PER_LINE(bm);
213 	if(h && bm->stride)
214 		bm->data = (BmUnit *)mdvi_calloc(h, bm->stride);
215 	else
216 		bm->data = NULL;
217 
218 	return bm;
219 }
220 
bitmap_alloc_raw(int w,int h)221 BITMAP	*bitmap_alloc_raw(int w, int h)
222 {
223 	BITMAP	*bm;
224 
225 	bm = xalloc(BITMAP);
226 	bm->width = w;
227 	bm->height = h;
228 	bm->stride = BM_BYTES_PER_LINE(bm);
229 	if(h && bm->stride)
230 		bm->data = (BmUnit *)mdvi_malloc(h * bm->stride);
231 	else
232 		bm->data = NULL;
233 
234 	return bm;
235 }
236 
bitmap_destroy(BITMAP * bm)237 void	bitmap_destroy(BITMAP *bm)
238 {
239 	if(bm->data)
240 		free(bm->data);
241 	free(bm);
242 }
243 
bitmap_print(FILE * out,BITMAP * bm)244 void	bitmap_print(FILE *out, BITMAP *bm)
245 {
246 	int	i, j;
247 	BmUnit	*a, mask;
248 	static const char labels[] = {
249 		'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'
250 	};
251 	int	sub;
252 
253 	a = bm->data;
254 	fprintf(out, "    ");
255 	if(bm->width > 10) {
256 		putchar('0');
257 		sub = 0;
258 		for(j = 2; j <= bm->width; j++)
259 			if((j %10) == 0) {
260 				if((j % 100) == 0) {
261 					fprintf(out, "*");
262 					sub += 100;
263 				} else
264 					fprintf(out, "%d", (j - sub)/10);
265 			} else
266 				putc(' ', out);
267 		fprintf(out, "\n    ");
268 	}
269 	for(j = 0; j < bm->width; j++)
270 		putc(labels[j % 10], out);
271 	putchar('\n');
272 	for(i = 0; i < bm->height; i++) {
273 		mask = FIRSTMASK;
274 		a = (BmUnit *)((char *)bm->data + i * bm->stride);
275 		fprintf(out, "%3d ", i+1);
276 		for(j = 0; j < bm->width; j++) {
277 			if(*a & mask)
278 				putc('#', out);
279 			else
280 				putc('.', out);
281 			if(mask == LASTMASK) {
282 				a++;
283 				mask = FIRSTMASK;
284 			} else
285 				NEXTMASK(mask);
286 		}
287 		putchar('\n');
288 	}
289 }
290 
bitmap_set_col(BITMAP * bm,int row,int col,int count,int state)291 void bitmap_set_col(BITMAP *bm, int row, int col, int count, int state)
292 {
293 	BmUnit	*ptr;
294 	BmUnit	mask;
295 
296 	ptr = __bm_unit_ptr(bm, col, row);
297 	mask = FIRSTMASKAT(col);
298 
299 	while(count-- > 0) {
300 		if(state)
301 			*ptr |= mask;
302 		else
303 			*ptr &= ~mask;
304 		/* move to next row */
305 		ptr = bm_offset(ptr, bm->stride);
306 	}
307 }
308 
309 /*
310  * to use this function you should first make sure that
311  * there is room for `count' bits in the scanline
312  *
313  * A general-purpose (but not very efficient) function to paint `n' pixels
314  * on a bitmap, starting at position (x, y) would be:
315  *
316  *    bitmap_paint_bits(__bm_unit_ptr(bitmap, x, y), x % BITMAP_BITS, n)
317  *
318  */
bitmap_paint_bits(BmUnit * ptr,int n,int count)319 void	bitmap_paint_bits(BmUnit *ptr, int n, int count)
320 {
321 	/* paint the head */
322 	if(n + count > BITMAP_BITS) {
323 		*ptr |= SEGMENT(BITMAP_BITS - n, n);
324 		count -= BITMAP_BITS - n;
325 		ptr++;
326 	} else {
327 		*ptr |= SEGMENT(count, n);
328 		return;
329 	}
330 
331 	/* paint the middle */
332 	for(; count >= BITMAP_BITS; count -= BITMAP_BITS)
333 		*ptr++ = bit_masks[BITMAP_BITS];
334 
335 	/* paint the tail */
336 	if(count > 0)
337 		*ptr |= SEGMENT(count, 0);
338 }
339 
340 /*
341  * same as paint_bits but clears pixels instead of painting them. Written
342  * as a separate function for efficiency reasons.
343  */
bitmap_clear_bits(BmUnit * ptr,int n,int count)344 void bitmap_clear_bits(BmUnit *ptr, int n, int count)
345 {
346 	if(n + count > BITMAP_BITS) {
347 		*ptr &= ~SEGMENT(BITMAP_BITS - n, n);
348 		count -= BITMAP_BITS;
349 		ptr++;
350 	} else {
351 		*ptr &= ~SEGMENT(count, n);
352 		return;
353 	}
354 
355 	for(; count >= BITMAP_BITS; count -= BITMAP_BITS)
356 		*ptr++ = 0;
357 
358 	if(count > 0)
359 		*ptr &= ~SEGMENT(count, 0);
360 }
361 
362 /* the general function to paint rows. Still used by the PK reader, but that
363  * will change soon (The GF reader already uses bitmap_paint_bits()).
364  */
bitmap_set_row(BITMAP * bm,int row,int col,int count,int state)365 void	bitmap_set_row(BITMAP *bm, int row, int col, int count, int state)
366 {
367 	BmUnit	*ptr;
368 
369 	ptr = __bm_unit_ptr(bm, col, row);
370 	if(state)
371 		bitmap_paint_bits(ptr, col & (BITMAP_BITS-1), count);
372 	else
373 		bitmap_clear_bits(ptr, col & (BITMAP_BITS-1), count);
374 }
375 
376 /*
377  * Now several `flipping' operations
378  */
379 
bitmap_flip_horizontally(BITMAP * bm)380 void bitmap_flip_horizontally(BITMAP *bm)
381 {
382 	BITMAP	nb;
383 	BmUnit	*fptr, *tptr;
384 	BmUnit	fmask, tmask;
385 	int	w, h;
386 
387 	nb.width = bm->width;
388 	nb.height = bm->height;
389 	nb.stride = bm->stride;
390 	nb.data = mdvi_calloc(bm->height, bm->stride);
391 
392 	fptr = bm->data;
393 	tptr = __bm_unit_ptr(&nb, nb.width-1, 0);
394 	for(h = 0; h < bm->height; h++) {
395 		BmUnit	*fline, *tline;
396 
397 		fline = fptr;
398 		tline = tptr;
399 		fmask = FIRSTMASK;
400 		tmask = FIRSTMASKAT(nb.width-1);
401 		for(w = 0; w < bm->width; w++) {
402 			if(*fline & fmask)
403 				*tline |= tmask;
404 			if(fmask == LASTMASK) {
405 				fmask = FIRSTMASK;
406 				fline++;
407 			} else
408 				NEXTMASK(fmask);
409 			if(tmask == FIRSTMASK) {
410 				tmask = LASTMASK;
411 				tline--;
412 			} else
413 				PREVMASK(tmask);
414 		}
415 		fptr = bm_offset(fptr, bm->stride);
416 		tptr = bm_offset(tptr, bm->stride);
417 	}
418 	DEBUG((DBG_BITMAP_OPS, "flip_horizontally (%d,%d) -> (%d,%d)\n",
419 		bm->width, bm->height, nb.width, nb.height));
420 	mdvi_free(bm->data);
421 	bm->data = nb.data;
422 	if(SHOW_OP_DATA)
423 		bitmap_print(stderr, bm);
424 }
425 
bitmap_flip_vertically(BITMAP * bm)426 void	bitmap_flip_vertically(BITMAP *bm)
427 {
428 	BITMAP	nb;
429 	BmUnit	*fptr, *tptr;
430 	BmUnit	fmask;
431 	int	w, h;
432 
433 	nb.width = bm->width;
434 	nb.height = bm->height;
435 	nb.stride = bm->stride;
436 	nb.data = mdvi_calloc(bm->height, bm->stride);
437 
438 	fptr = bm->data;
439 	tptr = __bm_unit_ptr(&nb, 0, nb.height-1);
440 	for(h = 0; h < bm->height; h++) {
441 		BmUnit	*fline, *tline;
442 
443 		fline = fptr;
444 		tline = tptr;
445 		fmask = FIRSTMASK;
446 		for(w = 0; w < bm->width; w++) {
447 			if(*fline & fmask)
448 				*tline |= fmask;
449 			if(fmask == LASTMASK) {
450 				fmask = FIRSTMASK;
451 				fline++;
452 				tline++;
453 			} else
454 				NEXTMASK(fmask);
455 		}
456 		fptr = bm_offset(fptr, bm->stride);
457 		tptr = (BmUnit *)((char *)tptr - bm->stride);
458 	}
459 	DEBUG((DBG_BITMAP_OPS, "flip_vertically (%d,%d) -> (%d,%d)\n",
460 		bm->width, bm->height, nb.width, nb.height));
461 	mdvi_free(bm->data);
462 	bm->data = nb.data;
463 	if(SHOW_OP_DATA)
464 		bitmap_print(stderr, bm);
465 }
466 
bitmap_flip_diagonally(BITMAP * bm)467 void	bitmap_flip_diagonally(BITMAP *bm)
468 {
469 	BITMAP	nb;
470 	BmUnit	*fptr, *tptr;
471 	BmUnit	fmask, tmask;
472 	int	w, h;
473 
474 	nb.width = bm->width;
475 	nb.height = bm->height;
476 	nb.stride = bm->stride;
477 	nb.data = mdvi_calloc(bm->height, bm->stride);
478 
479 	fptr = bm->data;
480 	tptr = __bm_unit_ptr(&nb, nb.width-1, nb.height-1);
481 	for(h = 0; h < bm->height; h++) {
482 		BmUnit	*fline, *tline;
483 
484 		fline = fptr;
485 		tline = tptr;
486 		fmask = FIRSTMASK;
487 		tmask = FIRSTMASKAT(nb.width-1);
488 		for(w = 0; w < bm->width; w++) {
489 			if(*fline & fmask)
490 				*tline |= tmask;
491 			if(fmask == LASTMASK) {
492 				fmask = FIRSTMASK;
493 				fline++;
494 			} else
495 				NEXTMASK(fmask);
496 			if(tmask == FIRSTMASK) {
497 				tmask = LASTMASK;
498 				tline--;
499 			} else
500 				PREVMASK(tmask);
501 		}
502 		fptr = bm_offset(fptr, bm->stride);
503 		tptr = bm_offset(tptr, -nb.stride);
504 	}
505 	DEBUG((DBG_BITMAP_OPS, "flip_diagonally (%d,%d) -> (%d,%d)\n",
506 		bm->width, bm->height, nb.width, nb.height));
507 	mdvi_free(bm->data);
508 	bm->data = nb.data;
509 	if(SHOW_OP_DATA)
510 		bitmap_print(stderr, bm);
511 }
512 
bitmap_rotate_clockwise(BITMAP * bm)513 void	bitmap_rotate_clockwise(BITMAP *bm)
514 {
515 	BITMAP	nb;
516 	BmUnit	*fptr, *tptr;
517 	BmUnit	fmask, tmask;
518 	int	w, h;
519 
520 	nb.width = bm->height;
521 	nb.height = bm->width;
522 	nb.stride = BM_BYTES_PER_LINE(&nb);
523 	nb.data = mdvi_calloc(nb.height, nb.stride);
524 
525 	fptr = bm->data;
526 	tptr = __bm_unit_ptr(&nb, nb.width - 1, 0);
527 
528 	tmask = FIRSTMASKAT(nb.width-1);
529 	for(h = 0; h < bm->height; h++) {
530 		BmUnit	*fline, *tline;
531 
532 		fmask = FIRSTMASK;
533 		fline = fptr;
534 		tline = tptr;
535 		for(w = 0; w < bm->width; w++) {
536 			if(*fline & fmask)
537 				*tline |= tmask;
538 			if(fmask == LASTMASK) {
539 				fmask = FIRSTMASK;
540 				fline++;
541 			} else
542 				NEXTMASK(fmask);
543 			/* go to next row */
544 			tline = bm_offset(tline, nb.stride);
545 		}
546 		fptr = bm_offset(fptr, bm->stride);
547 		if(tmask == FIRSTMASK) {
548 			tmask = LASTMASK;
549 			tptr--;
550 		} else
551 			PREVMASK(tmask);
552 	}
553 
554 	DEBUG((DBG_BITMAP_OPS, "rotate_clockwise (%d,%d) -> (%d,%d)\n",
555 		bm->width, bm->height, nb.width, nb.height));
556 	mdvi_free(bm->data);
557 	bm->data = nb.data;
558 	bm->width = nb.width;
559 	bm->height = nb.height;
560 	bm->stride = nb.stride;
561 	if(SHOW_OP_DATA)
562 		bitmap_print(stderr, bm);
563 }
564 
bitmap_rotate_counter_clockwise(BITMAP * bm)565 void	bitmap_rotate_counter_clockwise(BITMAP *bm)
566 {
567 	BITMAP	nb;
568 	BmUnit	*fptr, *tptr;
569 	BmUnit	fmask, tmask;
570 	int	w, h;
571 
572 	nb.width = bm->height;
573 	nb.height = bm->width;
574 	nb.stride = BM_BYTES_PER_LINE(&nb);
575 	nb.data = mdvi_calloc(nb.height, nb.stride);
576 
577 	fptr = bm->data;
578 	tptr = __bm_unit_ptr(&nb, 0, nb.height - 1);
579 
580 	tmask = FIRSTMASK;
581 	for(h = 0; h < bm->height; h++) {
582 		BmUnit	*fline, *tline;
583 
584 		fmask = FIRSTMASK;
585 		fline = fptr;
586 		tline = tptr;
587 		for(w = 0; w < bm->width; w++) {
588 			if(*fline & fmask)
589 				*tline |= tmask;
590 			if(fmask == LASTMASK) {
591 				fmask = FIRSTMASK;
592 				fline++;
593 			} else
594 				NEXTMASK(fmask);
595 			/* go to previous row */
596 			tline = bm_offset(tline, -nb.stride);
597 		}
598 		fptr = bm_offset(fptr, bm->stride);
599 		if(tmask == LASTMASK) {
600 			tmask = FIRSTMASK;
601 			tptr++;
602 		} else
603 			NEXTMASK(tmask);
604 	}
605 
606 	DEBUG((DBG_BITMAP_OPS, "rotate_counter_clockwise (%d,%d) -> (%d,%d)\n",
607 		bm->width, bm->height, nb.width, nb.height));
608 	mdvi_free(bm->data);
609 	bm->data = nb.data;
610 	bm->width = nb.width;
611 	bm->height = nb.height;
612 	bm->stride = nb.stride;
613 	if(SHOW_OP_DATA)
614 		bitmap_print(stderr, bm);
615 }
616 
bitmap_flip_rotate_clockwise(BITMAP * bm)617 void	bitmap_flip_rotate_clockwise(BITMAP *bm)
618 {
619 	BITMAP	nb;
620 	BmUnit	*fptr, *tptr;
621 	BmUnit	fmask, tmask;
622 	int	w, h;
623 
624 	nb.width = bm->height;
625 	nb.height = bm->width;
626 	nb.stride = BM_BYTES_PER_LINE(&nb);
627 	nb.data = mdvi_calloc(nb.height, nb.stride);
628 
629 	fptr = bm->data;
630 	tptr = __bm_unit_ptr(&nb, nb.width-1, nb.height-1);
631 
632 	tmask = FIRSTMASKAT(nb.width-1);
633 	for(h = 0; h < bm->height; h++) {
634 		BmUnit	*fline, *tline;
635 
636 		fmask = FIRSTMASK;
637 		fline = fptr;
638 		tline = tptr;
639 		for(w = 0; w < bm->width; w++) {
640 			if(*fline & fmask)
641 				*tline |= tmask;
642 			if(fmask == LASTMASK) {
643 				fmask = FIRSTMASK;
644 				fline++;
645 			} else
646 				NEXTMASK(fmask);
647 			/* go to previous line */
648 			tline = bm_offset(tline, -nb.stride);
649 		}
650 		fptr = bm_offset(fptr, bm->stride);
651 		if(tmask == FIRSTMASK) {
652 			tmask = LASTMASK;
653 			tptr--;
654 		} else
655 			PREVMASK(tmask);
656 	}
657 	DEBUG((DBG_BITMAP_OPS, "flip_rotate_clockwise (%d,%d) -> (%d,%d)\n",
658 		bm->width, bm->height, nb.width, nb.height));
659 	mdvi_free(bm->data);
660 	bm->data = nb.data;
661 	bm->width = nb.width;
662 	bm->height = nb.height;
663 	bm->stride = nb.stride;
664 	if(SHOW_OP_DATA)
665 		bitmap_print(stderr, bm);
666 }
667 
bitmap_flip_rotate_counter_clockwise(BITMAP * bm)668 void	bitmap_flip_rotate_counter_clockwise(BITMAP *bm)
669 {
670 	BITMAP	nb;
671 	BmUnit	*fptr, *tptr;
672 	BmUnit	fmask, tmask;
673 	int	w, h;
674 
675 	nb.width = bm->height;
676 	nb.height = bm->width;
677 	nb.stride = BM_BYTES_PER_LINE(&nb);
678 	nb.data = mdvi_calloc(nb.height, nb.stride);
679 
680 	fptr = bm->data;
681 	tptr = nb.data;
682 	tmask = FIRSTMASK;
683 
684 	for(h = 0; h < bm->height; h++) {
685 		BmUnit	*fline, *tline;
686 
687 		fmask = FIRSTMASK;
688 		fline = fptr;
689 		tline = tptr;
690 		for(w = 0; w < bm->width; w++) {
691 			if(*fline & fmask)
692 				*tline |= tmask;
693 			if(fmask == LASTMASK) {
694 				fmask = FIRSTMASK;
695 				fline++;
696 			} else
697 				NEXTMASK(fmask);
698 			/* go to next line */
699 			tline = bm_offset(tline, nb.stride);
700 		}
701 		fptr = bm_offset(fptr, bm->stride);
702 		if(tmask == LASTMASK) {
703 			tmask = FIRSTMASK;
704 			tptr++;
705 		} else
706 			NEXTMASK(tmask);
707 	}
708 
709 	DEBUG((DBG_BITMAP_OPS, "flip_rotate_counter_clockwise (%d,%d) -> (%d,%d)\n",
710 		bm->width, bm->height, nb.width, nb.height));
711 	mdvi_free(bm->data);
712 	bm->data = nb.data;
713 	bm->width = nb.width;
714 	bm->height = nb.height;
715 	bm->stride = nb.stride;
716 	if(SHOW_OP_DATA)
717 		bitmap_print(stderr, bm);
718 }
719 
720 #if 0
721 void	bitmap_transform(BITMAP *map, DviOrientation orient)
722 {
723 	switch(orient) {
724 		case MDVI_ORIENT_TBLR:
725 			break;
726 		case MDVI_ORIENT_TBRL:
727 			bitmap_flip_horizontally(map);
728 			break;
729 		case MDVI_ORIENT_BTLR:
730 			bitmap_flip_vertically(map);
731 			break;
732 		case MDVI_ORIENT_BTRL:
733 			bitmap_flip_diagonally(map);
734 			break;
735 		case MDVI_ORIENT_RP90:
736 			bitmap_rotate_counter_clockwise(map);
737 			break;
738 		case MDVI_ORIENT_RM90:
739 			bitmap_rotate_clockwise(map);
740 			break;
741 		case MDVI_ORIENT_IRP90:
742 			bitmap_flip_rotate_counter_clockwise(map);
743 			break;
744 		case MDVI_ORIENT_IRM90:
745 			bitmap_flip_rotate_clockwise(map);
746 			break;
747 	}
748 }
749 #endif
750 
751 /*
752  * Count the number of non-zero bits in a box of dimensions w x h, starting
753  * at column `step' in row `data'.
754  *
755  * Shamelessly stolen from xdvi.
756  */
do_sample(BmUnit * data,int stride,int step,int w,int h)757 static int do_sample(BmUnit *data, int stride, int step, int w, int h)
758 {
759 	BmUnit	*ptr, *end, *cp;
760 	int	shift, n;
761 	int	bits_left;
762 	int	wid;
763 
764 	ptr = data + step / BITMAP_BITS;
765 	end = bm_offset(data, h * stride);
766 	shift = FIRSTSHIFTAT(step);
767 	bits_left = w;
768 	n = 0;
769 	while(bits_left) {
770 #ifndef WORD_BIG_ENDIAN
771 		wid = BITMAP_BITS - shift;
772 #else
773 		wid = shift;
774 #endif
775 		if(wid > bits_left)
776 			wid = bits_left;
777 		if(wid > 8)
778 			wid = 8;
779 #ifdef WORD_BIG_ENDIAN
780 		shift -= wid;
781 #endif
782 		for(cp = ptr; cp < end; cp = bm_offset(cp, stride))
783 			n += sample_count[(*cp >> shift) & bit_masks[wid]];
784 #ifndef WORD_BIG_ENDIAN
785 		shift += wid;
786 #endif
787 #ifdef WORD_BIG_ENDIAN
788 		if(shift == 0) {
789 			shift = BITMAP_BITS;
790 			ptr++;
791 		}
792 #else
793 		if(shift == BITMAP_BITS) {
794 			shift = 0;
795 			ptr++;
796 		}
797 #endif
798 		bits_left -= wid;
799 	}
800 	return n;
801 }
802 
mdvi_shrink_box(DviContext * dvi,DviFont * font,DviFontChar * pk,DviGlyph * dest)803 void	mdvi_shrink_box(DviContext *dvi, DviFont *font,
804 	DviFontChar *pk, DviGlyph *dest)
805 {
806 	int	x, y, z;
807 	DviGlyph *glyph;
808 	int	hs, vs;
809 
810 	hs = dvi->params.hshrink;
811 	vs = dvi->params.vshrink;
812 	glyph = &pk->glyph;
813 
814 	x = (int)glyph->x / hs;
815 	if((int)glyph->x - x * hs > 0)
816 		x++;
817 	dest->w = x + ROUND((int)glyph->w - glyph->x, hs);
818 
819 	z = (int)glyph->y + 1;
820 	y = z / vs;
821 	if(z - y * vs <= 0)
822 		y--;
823 	dest->h = y + ROUND((int)glyph->h - z, vs) + 1;
824 	dest->x = x;
825 	dest->y = glyph->y / vs;
826 	dest->data = MDVI_GLYPH_EMPTY;
827 	DEBUG((DBG_BITMAPS, "shrink_box: (%dw,%dh,%dx,%dy) -> (%dw,%dh,%dx,%dy)\n",
828 		glyph->w, glyph->h, glyph->x, glyph->y,
829 		dest->w, dest->h, dest->x, dest->y));
830 }
831 
mdvi_shrink_glyph(DviContext * dvi,DviFont * font,DviFontChar * pk,DviGlyph * dest)832 void	mdvi_shrink_glyph(DviContext *dvi, DviFont *font,
833 	DviFontChar *pk, DviGlyph *dest)
834 {
835 	int	rows_left, rows, init_cols;
836 	int	cols_left, cols;
837 	BmUnit	*old_ptr, *new_ptr;
838 	BITMAP	*oldmap, *newmap;
839 	BmUnit	m, *cp;
840 	DviGlyph *glyph;
841 	int	sample, min_sample;
842 	int	old_stride;
843 	int	new_stride;
844 	int	x, y;
845 	int	w, h;
846 	int	hs, vs;
847 
848 	hs = dvi->params.hshrink;
849 	vs = dvi->params.vshrink;
850 
851 	min_sample = vs * hs * dvi->params.density / 100;
852 
853 	glyph = &pk->glyph;
854 	oldmap = (BITMAP *)glyph->data;
855 
856 	x = (int)glyph->x / hs;
857 	init_cols = (int)glyph->x - x * hs;
858 	if(init_cols <= 0)
859 		init_cols += hs;
860 	else
861 		x++;
862 	w = x + ROUND((int)glyph->w - glyph->x, hs);
863 
864 	cols = (int)glyph->y + 1;
865 	y = cols / vs;
866 	rows = cols - y * vs;
867 	if(rows <= 0) {
868 		rows += vs;
869 		y--;
870 	}
871 	h = y + ROUND((int)glyph->h - cols, vs) + 1;
872 
873 	/* create the new glyph */
874 	newmap = bitmap_alloc(w, h);
875 	dest->data = newmap;
876 	dest->x = x;
877 	dest->y = glyph->y / vs;
878 	dest->w = w;
879 	dest->h = h;
880 
881 	old_ptr = oldmap->data;
882 	old_stride = oldmap->stride;
883 	new_ptr = newmap->data;
884 	new_stride = newmap->stride;
885 	rows_left = glyph->h;
886 
887 	while(rows_left) {
888 		if(rows > rows_left)
889 			rows = rows_left;
890 		cols_left = glyph->w;
891 		m = FIRSTMASK;
892 		cp = new_ptr;
893 		cols = init_cols;
894 		while(cols_left > 0) {
895 			if(cols > cols_left)
896 				cols = cols_left;
897 			sample = do_sample(old_ptr, old_stride,
898 				glyph->w - cols_left, cols, rows);
899 			if(sample >= min_sample)
900 				*cp |= m;
901 			if(m == LASTMASK) {
902 				m = FIRSTMASK;
903 				cp++;
904 			} else
905 				NEXTMASK(m);
906 			cols_left -= cols;
907 			cols = hs;
908 		}
909 		new_ptr = bm_offset(new_ptr, new_stride);
910 		old_ptr = bm_offset(old_ptr, rows * old_stride);
911 		rows_left -= rows;
912 		rows = vs;
913 	}
914 	DEBUG((DBG_BITMAPS, "shrink_glyph: (%dw,%dh,%dx,%dy) -> (%dw,%dh,%dx,%dy)\n",
915 		glyph->w, glyph->h, glyph->x, glyph->y,
916 		dest->w, dest->h, dest->x, dest->y));
917 	if(DEBUGGING(BITMAP_DATA))
918 		bitmap_print(stderr, newmap);
919 }
920 
mdvi_shrink_glyph_grey(DviContext * dvi,DviFont * font,DviFontChar * pk,DviGlyph * dest)921 void	mdvi_shrink_glyph_grey(DviContext *dvi, DviFont *font,
922 	DviFontChar *pk, DviGlyph *dest)
923 {
924 	int	rows_left, rows;
925 	int	cols_left, cols, init_cols;
926 	long	sampleval, samplemax;
927 	BmUnit	*old_ptr;
928 	void	*image;
929 	int	w, h;
930 	int	x, y;
931 	DviGlyph *glyph;
932 	BITMAP 	*map;
933 	Ulong	*pixels;
934 	int	npixels;
935 	Ulong	colortab[2];
936 	int	hs, vs;
937 	DviDevice *dev;
938 
939 	hs = dvi->params.hshrink;
940 	vs = dvi->params.vshrink;
941 	dev = &dvi->device;
942 
943 	glyph = &pk->glyph;
944 	map = (BITMAP *)glyph->data;
945 
946 	x = (int)glyph->x / hs;
947 	init_cols = (int)glyph->x - x * hs;
948 	if(init_cols <= 0)
949 		init_cols += hs;
950 	else
951 		x++;
952 	w = x + ROUND((int)glyph->w - glyph->x, hs);
953 
954 	cols = (int)glyph->y + 1;
955 	y = cols / vs;
956 	rows = cols - y * vs;
957 	if(rows <= 0) {
958 		rows += vs;
959 		y--;
960 	}
961 	h = y + ROUND((int)glyph->h - cols, vs) + 1;
962 	ASSERT(w && h);
963 
964 	/* before touching anything, do this */
965 	image = dev->create_image(dev->device_data, w, h, BITMAP_BITS);
966 	if(image == NULL) {
967 		mdvi_shrink_glyph(dvi, font, pk, dest);
968 		return;
969 	}
970 
971 	/* save these colors */
972 	pk->fg = MDVI_CURRFG(dvi);
973 	pk->bg = MDVI_CURRBG(dvi);
974 
975 	samplemax = vs * hs;
976 	npixels = samplemax + 1;
977 	pixels = get_color_table(&dvi->device, npixels, pk->fg, pk->bg,
978 			dvi->params.gamma, dvi->params.density);
979 	if(pixels == NULL) {
980 		npixels = 2;
981 		colortab[0] = pk->fg;
982 		colortab[1] = pk->bg;
983 		pixels = &colortab[0];
984 	}
985 
986 	/* setup the new glyph */
987 	dest->data = image;
988 	dest->x = x;
989 	dest->y = glyph->y / vs;
990 	dest->w = w;
991 	dest->h = h;
992 
993 	y = 0;
994 	old_ptr = map->data;
995 	rows_left = glyph->h;
996 
997 	while(rows_left && y < h) {
998 		x = 0;
999 		if(rows > rows_left)
1000 			rows = rows_left;
1001 		cols_left = glyph->w;
1002 		cols = init_cols;
1003 		while(cols_left && x < w) {
1004 			if(cols > cols_left)
1005 				cols = cols_left;
1006 			sampleval = do_sample(old_ptr, map->stride,
1007 				glyph->w - cols_left, cols, rows);
1008 			/* scale the sample value by the number of grey levels */
1009 			if(npixels - 1 != samplemax)
1010 				sampleval = ((npixels-1) * sampleval) / samplemax;
1011 			ASSERT(sampleval < npixels);
1012 			dev->put_pixel(image, x, y, pixels[sampleval]);
1013 			cols_left -= cols;
1014 			cols = hs;
1015 			x++;
1016 		}
1017 		for(; x < w; x++)
1018 			dev->put_pixel(image, x, y, pixels[0]);
1019 		old_ptr = bm_offset(old_ptr, rows * map->stride);
1020 		rows_left -= rows;
1021 		rows = vs;
1022 		y++;
1023 	}
1024 
1025 	for(; y < h; y++) {
1026 		for(x = 0; x < w; x++)
1027 			dev->put_pixel(image, x, y, pixels[0]);
1028 	}
1029 
1030         dev->image_done(image);
1031 	DEBUG((DBG_BITMAPS, "shrink_glyph_grey: (%dw,%dh,%dx,%dy) -> (%dw,%dh,%dx,%dy)\n",
1032 		glyph->w, glyph->h, glyph->x, glyph->y,
1033 		dest->w, dest->h, dest->x, dest->y));
1034 }
1035 
1036