Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises.  All rights reserved.
2
 
3
  This software is provided AS-IS with no warranty, either express or
4
  implied.
5
 
6
  This software is distributed under license and may not be copied,
7
  modified or distributed except as expressly authorized under the terms
8
  of the license contained in the file LICENSE in this distribution.
9
 
10
  For more information about licensing, please refer to
11
  http://www.ghostscript.com/licensing/. For information on
12
  commercial licensing, go to http://www.artifex.com/licensing/ or
13
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15
*/
16
 
17
/* $Id: gsbitops.c,v 1.8 2002/10/07 08:28:56 ghostgum Exp $ */
18
/* Bitmap filling, copying, and transforming operations */
19
#include "stdio_.h"
20
#include "memory_.h"
21
#include "gdebug.h"
22
#include "gserror.h"
23
#include "gserrors.h"
24
#include "gstypes.h"
25
#include "gsbittab.h"
26
#include "gxbitops.h"
27
#include "gxcindex.h"
28
 
29
/* ---------------- Bit-oriented operations ---------------- */
30
 
31
/* Define masks for little-endian operation. */
32
/* masks[i] has the first i bits off and the rest on. */
33
#if !arch_is_big_endian
34
const bits16 mono_copy_masks[17] = {
35
    0xffff, 0xff7f, 0xff3f, 0xff1f,
36
    0xff0f, 0xff07, 0xff03, 0xff01,
37
    0xff00, 0x7f00, 0x3f00, 0x1f00,
38
    0x0f00, 0x0700, 0x0300, 0x0100,
39
    0x0000
40
};
41
const bits32 mono_fill_masks[33] = {
42
#define mask(n)\
43
  ((~0xff | (0xff >> (n & 7))) << (n & -8))
44
    mask( 0),mask( 1),mask( 2),mask( 3),mask( 4),mask( 5),mask( 6),mask( 7),
45
    mask( 8),mask( 9),mask(10),mask(11),mask(12),mask(13),mask(14),mask(15),
46
    mask(16),mask(17),mask(18),mask(19),mask(20),mask(21),mask(22),mask(23),
47
    mask(24),mask(25),mask(26),mask(27),mask(28),mask(29),mask(30),mask(31),
48
 
49
#undef mask
50
};
51
#endif
52
 
53
/* Fill a rectangle of bits with an 8x1 pattern. */
54
/* The pattern argument must consist of the pattern in every byte, */
55
/* e.g., if the desired pattern is 0xaa, the pattern argument must */
56
/* have the value 0xaaaa (if ints are short) or 0xaaaaaaaa. */
57
#undef chunk
58
#define chunk mono_fill_chunk
59
#undef mono_masks
60
#define mono_masks mono_fill_masks
61
void
62
bits_fill_rectangle(byte * dest, int dest_bit, uint draster,
63
		    mono_fill_chunk pattern, int width_bits, int height)
64
{
65
    uint bit;
66
    chunk right_mask;
67
    int line_count = height;
68
    chunk *ptr;
69
    int last_bit;
70
 
71
#define FOR_EACH_LINE(stat)\
72
	do { stat } while ( inc_ptr(ptr, draster), --line_count )
73
 
74
    dest += (dest_bit >> 3) & -chunk_align_bytes;
75
    ptr = (chunk *) dest;
76
    bit = dest_bit & chunk_align_bit_mask;
77
    last_bit = width_bits + bit - (chunk_bits + 1);
78
 
79
    if (last_bit < 0) {		/* <=1 chunk */
80
	set_mono_thin_mask(right_mask, width_bits, bit);
81
	if (pattern == 0)
82
	    FOR_EACH_LINE(*ptr &= ~right_mask;);
83
	else if (pattern == (mono_fill_chunk)(-1))
84
	    FOR_EACH_LINE(*ptr |= right_mask;);
85
	else
86
	    FOR_EACH_LINE(
87
		*ptr = (*ptr & ~right_mask) | (pattern & right_mask); );
88
    } else {
89
	chunk mask;
90
	int last = last_bit >> chunk_log2_bits;
91
 
92
	set_mono_left_mask(mask, bit);
93
	set_mono_right_mask(right_mask, (last_bit & chunk_bit_mask) + 1);
94
	switch (last) {
95
	    case 0:		/* 2 chunks */
96
		if (pattern == 0)
97
		    FOR_EACH_LINE(*ptr &= ~mask; ptr[1] &= ~right_mask;);
98
		else if (pattern == (mono_fill_chunk)(-1))
99
		    FOR_EACH_LINE(*ptr |= mask; ptr[1] |= right_mask;);
100
		else
101
		    FOR_EACH_LINE(
102
		        *ptr = (*ptr & ~mask) | (pattern & mask);
103
			ptr[1] = (ptr[1] & ~right_mask) | (pattern & right_mask); );
104
		break;
105
	    case 1:		/* 3 chunks */
106
		if (pattern == 0)
107
		    FOR_EACH_LINE( *ptr &= ~mask;
108
				   ptr[1] = 0;
109
				   ptr[2] &= ~right_mask; );
110
		else if (pattern == (mono_fill_chunk)(-1))
111
		    FOR_EACH_LINE( *ptr |= mask;
112
				   ptr[1] = ~(chunk) 0;
113
				   ptr[2] |= right_mask; );
114
		else
115
		    FOR_EACH_LINE( *ptr = (*ptr & ~mask) | (pattern & mask);
116
				    ptr[1] = pattern;
117
				    ptr[2] = (ptr[2] & ~right_mask) | (pattern & right_mask); );
118
		break;
119
	    default:{		/* >3 chunks */
120
		    uint byte_count = (last_bit >> 3) & -chunk_bytes;
121
 
122
		    if (pattern == 0)
123
			FOR_EACH_LINE( *ptr &= ~mask;
124
				       memset(ptr + 1, 0, byte_count);
125
				       ptr[last + 1] &= ~right_mask; );
126
		    else if (pattern == (mono_fill_chunk)(-1))
127
			FOR_EACH_LINE( *ptr |= mask;
128
				       memset(ptr + 1, 0xff, byte_count);
129
				       ptr[last + 1] |= right_mask; );
130
		    else
131
			FOR_EACH_LINE(
132
				*ptr = (*ptr & ~mask) | (pattern & mask);
133
				memset(ptr + 1, (byte) pattern, byte_count);
134
				ptr[last + 1] = (ptr[last + 1] & ~right_mask) |
135
					        (pattern & right_mask); 	);
136
		}
137
	}
138
    }
139
#undef FOR_EACH_LINE
140
}
141
 
142
/*
143
 * Similar to bits_fill_rectangle, but with an additional source mask.
144
 * The src_mask variable is 1 for those bits of the original that are
145
 * to be retained. The mask argument must consist of the requisite value
146
 * in every byte, in the same manner as the pattern.
147
 */
148
void
149
bits_fill_rectangle_masked(byte * dest, int dest_bit, uint draster,
150
		    mono_fill_chunk pattern, mono_fill_chunk src_mask,
151
		    int width_bits, int height)
152
{
153
    uint bit;
154
    chunk right_mask;
155
    int line_count = height;
156
    chunk *ptr;
157
    int last_bit;
158
 
159
#define FOR_EACH_LINE(stat)\
160
	do { stat } while ( inc_ptr(ptr, draster), --line_count )
161
 
162
    dest += (dest_bit >> 3) & -chunk_align_bytes;
163
    ptr = (chunk *) dest;
164
    bit = dest_bit & chunk_align_bit_mask;
165
    last_bit = width_bits + bit - (chunk_bits + 1);
166
 
167
    if (last_bit < 0) {		/* <=1 chunk */
168
	set_mono_thin_mask(right_mask, width_bits, bit);
169
	right_mask &= ~src_mask;
170
	if (pattern == 0)
171
	    FOR_EACH_LINE(*ptr &= ~right_mask;);
172
	else if (pattern == (mono_fill_chunk)(-1))
173
	    FOR_EACH_LINE(*ptr |= right_mask;);
174
	else
175
	    FOR_EACH_LINE(
176
		*ptr = (*ptr & ~right_mask) | (pattern & right_mask); );
177
    } else {
178
	chunk mask;
179
	int last = last_bit >> chunk_log2_bits;
180
 
181
	set_mono_left_mask(mask, bit);
182
	set_mono_right_mask(right_mask, (last_bit & chunk_bit_mask) + 1);
183
	mask &= ~src_mask;
184
	right_mask &= ~src_mask;
185
	switch (last) {
186
	    case 0:		/* 2 chunks */
187
		if (pattern == 0)
188
		    FOR_EACH_LINE(*ptr &= ~mask; ptr[1] &= ~right_mask;);
189
		else if (pattern == (mono_fill_chunk)(-1))
190
		    FOR_EACH_LINE(*ptr |= mask; ptr[1] |= right_mask;);
191
		else
192
		    FOR_EACH_LINE(
193
		        *ptr = (*ptr & ~mask) | (pattern & mask);
194
			ptr[1] = (ptr[1] & ~right_mask) | (pattern & right_mask); );
195
		break;
196
	    case 1:		/* 3 chunks */
197
		if (pattern == 0)
198
		    FOR_EACH_LINE( *ptr &= ~mask;
199
				   ptr[1] &= src_mask;
200
				   ptr[2] &= ~right_mask; );
201
		else if (pattern == (mono_fill_chunk)(-1))
202
		    FOR_EACH_LINE( *ptr |= mask;
203
				   ptr[1] |= ~src_mask;
204
				   ptr[2] |= right_mask; );
205
		else
206
		    FOR_EACH_LINE( *ptr = (*ptr & ~mask) | (pattern & mask);
207
				    ptr[1] =(ptr[1] & src_mask) | pattern;
208
				    ptr[2] = (ptr[2] & ~right_mask) | (pattern & right_mask); );
209
		break;
210
	    default:{		/* >3 chunks */
211
                    int     i;
212
 
213
		    if (pattern == 0)
214
			FOR_EACH_LINE( *ptr++ &= ~mask;
215
				       for (i = 0; i < last; i++)
216
					   *ptr++ &= src_mask;
217
				       *ptr &= ~right_mask; );
218
		    else if (pattern == (mono_fill_chunk)(-1))
219
			FOR_EACH_LINE( *ptr++ |= mask;
220
				       for (i = 0; i < last; i++)
221
					   *ptr++ |= ~src_mask;
222
					*ptr |= right_mask; );
223
		    else
224
			FOR_EACH_LINE(
225
			    /* note: we know (pattern & ~src_mask) == pattern */
226
			    *ptr = (*ptr & ~mask) | (pattern & mask);
227
			    ++ptr;
228
			    for (i = 0; i < last; i++, ptr++)
229
                                *ptr = (*ptr & src_mask) | pattern;
230
				*ptr = (*ptr & ~right_mask) | (pattern & right_mask); );
231
		}
232
	}
233
    }
234
#undef FOR_EACH_LINE
235
}
236
 
237
/* Replicate a bitmap horizontally in place. */
238
void
239
bits_replicate_horizontally(byte * data, uint width, uint height,
240
		 uint raster, uint replicated_width, uint replicated_raster)
241
{
242
    /* The current algorithm is extremely inefficient! */
243
    const byte *orig_row = data + (height - 1) * raster;
244
    byte *tile_row = data + (height - 1) * replicated_raster;
245
    uint y;
246
 
247
    if (!(width & 7)) {
248
	uint src_bytes = width >> 3;
249
	uint dest_bytes = replicated_width >> 3;
250
 
251
	for (y = height; y-- > 0;
252
	     orig_row -= raster, tile_row -= replicated_raster
253
	     ) {
254
	    uint move = src_bytes;
255
	    const byte *from = orig_row;
256
	    byte *to = tile_row + dest_bytes - src_bytes;
257
 
258
	    memmove(to, from, move);
259
	    while (to - tile_row >= move) {
260
		from = to;
261
		to -= move;
262
		memmove(to, from, move);
263
		move <<= 1;
264
	    }
265
	    if (to != tile_row)
266
		memmove(tile_row, to, to - tile_row);
267
	}
268
    } else {
269
	/*
270
	 * This algorithm is inefficient, but probably not worth improving.
271
	 */
272
	uint bit_count = width & (uint)(-(int)width);  /* lowest bit: 1, 2, or 4 */
273
	uint left_mask = (0xff00 >> bit_count) & 0xff;
274
 
275
	for (y = height; y-- > 0;
276
	     orig_row -= raster, tile_row -= replicated_raster
277
	     ) {
278
	    uint sx;
279
 
280
	    for (sx = width; sx > 0;) {
281
		uint bits, dx;
282
 
283
		sx -= bit_count;
284
		bits = (orig_row[sx >> 3] << (sx & 7)) & left_mask;
285
		for (dx = sx + replicated_width; dx >= width;) {
286
		    byte *dp;
287
		    int dbit;
288
 
289
		    dx -= width;
290
		    dbit = dx & 7;
291
		    dp = tile_row + (dx >> 3);
292
		    *dp = (*dp & ~(left_mask >> dbit)) | (bits >> dbit);
293
		}
294
	    }
295
	}
296
    }
297
}
298
 
299
/* Replicate a bitmap vertically in place. */
300
void
301
bits_replicate_vertically(byte * data, uint height, uint raster,
302
			  uint replicated_height)
303
{
304
    byte *dest = data;
305
    uint h = replicated_height;
306
    uint size = raster * height;
307
 
308
    while (h > height) {
309
	memcpy(dest + size, dest, size);
310
	dest += size;
311
	h -= height;
312
    }
313
}
314
 
315
/* Find the bounding box of a bitmap. */
316
/* Assume bits beyond the width are zero. */
317
void
318
bits_bounding_box(const byte * data, uint height, uint raster,
319
		  gs_int_rect * pbox)
320
{
321
    register const ulong *lp;
322
    static const byte first_1[16] = {
323
	4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0
324
    };
325
    static const byte last_1[16] = {
326
	0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4
327
    };
328
 
329
    /* Count trailing blank rows. */
330
    /* Since the raster is a multiple of sizeof(long), */
331
    /* we don't need to scan by bytes, only by longs. */
332
 
333
    lp = (const ulong *)(data + raster * height);
334
    while ((const byte *)lp > data && !lp[-1])
335
	--lp;
336
    if ((const byte *)lp == data) {
337
	pbox->p.x = pbox->q.x = pbox->p.y = pbox->q.y = 0;
338
	return;
339
    }
340
    pbox->q.y = height = ((const byte *)lp - data + raster - 1) / raster;
341
 
342
    /* Count leading blank rows. */
343
 
344
    lp = (const ulong *)data;
345
    while (!*lp)
346
	++lp;
347
    {
348
	uint n = ((const byte *)lp - data) / raster;
349
 
350
	pbox->p.y = n;
351
	if (n)
352
	    height -= n, data += n * raster;
353
    }
354
 
355
    /* Find the left and right edges. */
356
    /* We know that the first and last rows are non-blank. */
357
 
358
    {
359
	uint raster_longs = raster >> arch_log2_sizeof_long;
360
	uint left = raster_longs - 1, right = 0;
361
	ulong llong = 0, rlong = 0;
362
	const byte *q;
363
	uint h, n;
364
 
365
	for (q = data, h = height; h-- > 0; q += raster) {	/* Work from the left edge by longs. */
366
	    for (lp = (const ulong *)q, n = 0;
367
		 n < left && !*lp; lp++, n++
368
		);
369
	    if (n < left)
370
		left = n, llong = *lp;
371
	    else
372
		llong |= *lp;
373
	    /* Work from the right edge by longs. */
374
	    for (lp = (const ulong *)(q + raster - sizeof(long)),
375
		 n = raster_longs - 1;
376
 
377
		 n > right && !*lp; lp--, n--
378
		);
379
	    if (n > right)
380
		right = n, rlong = *lp;
381
	    else
382
		rlong |= *lp;
383
	}
384
 
385
	/* Do binary subdivision on edge longs.  We assume that */
386
	/* sizeof(long) = 4 or 8. */
387
#if arch_sizeof_long > 8
388
	Error_longs_are_too_large();
389
#endif
390
 
391
#if arch_is_big_endian
392
#  define last_bits(n) ((1L << (n)) - 1)
393
#  define shift_out_last(x,n) ((x) >>= (n))
394
#  define right_justify_last(x,n) DO_NOTHING
395
#else
396
#  define last_bits(n) (-1L << ((arch_sizeof_long * 8) - (n)))
397
#  define shift_out_last(x,n) ((x) <<= (n))
398
#  define right_justify_last(x,n) (x) >>= ((arch_sizeof_long * 8) - (n))
399
#endif
400
 
401
	left <<= arch_log2_sizeof_long + 3;
402
#if arch_sizeof_long == 8
403
	if (llong & ~last_bits(32))
404
	    shift_out_last(llong, 32);
405
	else
406
	    left += 32;
407
#endif
408
	if (llong & ~last_bits(16))
409
	    shift_out_last(llong, 16);
410
	else
411
	    left += 16;
412
	if (llong & ~last_bits(8))
413
	    shift_out_last(llong, 8);
414
	else
415
	    left += 8;
416
	right_justify_last(llong, 8);
417
	if (llong & 0xf0)
418
	    left += first_1[(byte) llong >> 4];
419
	else
420
	    left += first_1[(byte) llong] + 4;
421
 
422
	right <<= arch_log2_sizeof_long + 3;
423
#if arch_sizeof_long == 8
424
	if (!(rlong & last_bits(32)))
425
	    shift_out_last(rlong, 32);
426
	else
427
	    right += 32;
428
#endif
429
	if (!(rlong & last_bits(16)))
430
	    shift_out_last(rlong, 16);
431
	else
432
	    right += 16;
433
	if (!(rlong & last_bits(8)))
434
	    shift_out_last(rlong, 8);
435
	else
436
	    right += 8;
437
	right_justify_last(rlong, 8);
438
	if (!(rlong & 0xf))
439
	    right += last_1[(byte) rlong >> 4];
440
	else
441
	    right += last_1[(uint) rlong & 0xf] + 4;
442
 
443
	pbox->p.x = left;
444
	pbox->q.x = right;
445
    }
446
}
447
 
448
/* Extract a plane from a pixmap. */
449
int
450
bits_extract_plane(const bits_plane_t *dest /*write*/,
451
    const bits_plane_t *source /*read*/, int shift, int width, int height)
452
{
453
    int source_depth = source->depth;
454
    int source_bit = source->x * source_depth;
455
    const byte *source_row = source->data.read + (source_bit >> 3);
456
    int dest_depth = dest->depth;
457
    uint plane_mask = (1 << dest_depth) - 1;
458
    int dest_bit = dest->x * dest_depth;
459
    byte *dest_row = dest->data.write + (dest_bit >> 3);
460
    enum {
461
	EXTRACT_SLOW = 0,
462
	EXTRACT_4_TO_1,
463
	EXTRACT_32_TO_8
464
    } loop_case = EXTRACT_SLOW;
465
    int y;
466
 
467
    source_bit &= 7;
468
    dest_bit &= 7;
469
    /* Check for the fast CMYK cases. */
470
    if (!(source_bit | dest_bit)) {
471
	switch (source_depth) {
472
	case 4:
473
	    loop_case =
474
		(dest_depth == 1 && !(source->raster & 3) &&
475
		 !(source->x & 1) ? EXTRACT_4_TO_1 :
476
		 EXTRACT_SLOW);
477
	    break;
478
	case 32:
479
	    if (dest_depth == 8 && !(shift & 7)) {
480
		loop_case = EXTRACT_32_TO_8;
481
		source_row += 3 - (shift >> 3);
482
	    }
483
	    break;
484
	}
485
    }
486
    for (y = 0; y < height;
487
	 ++y, source_row += source->raster, dest_row += dest->raster
488
	) {
489
	int x;
490
 
491
	switch (loop_case) {
492
	case EXTRACT_4_TO_1: {
493
	    const byte *source = source_row;
494
	    byte *dest = dest_row;
495
 
496
	    /* Do groups of 8 pixels. */
497
	    for (x = width; x >= 8; source += 4, x -= 8) {
498
		bits32 sword =
499
		    (*(const bits32 *)source >> shift) & 0x11111111;
500
 
501
		*dest++ =
502
		    byte_acegbdfh_to_abcdefgh[(
503
#if arch_is_big_endian
504
		    (sword >> 21) | (sword >> 14) | (sword >> 7) | sword
505
#else
506
		    (sword << 3) | (sword >> 6) | (sword >> 15) | (sword >> 24)
507
#endif
508
					) & 0xff];
509
	    }
510
	    if (x) {
511
		/* Do the final 1-7 pixels. */
512
		uint test = 0x10 << shift, store = 0x80;
513
 
514
		do {
515
		    *dest = (*source & test ? *dest | store : *dest & ~store);
516
		    if (test >= 0x10)
517
			test >>= 4;
518
		    else
519
			test <<= 4, ++source;
520
		    store >>= 1;
521
		} while (--x > 0);
522
	    }
523
	    break;
524
	}
525
	case EXTRACT_32_TO_8: {
526
	    const byte *source = source_row;
527
	    byte *dest = dest_row;
528
 
529
	    for (x = width; x > 0; source += 4, --x)
530
		*dest++ = *source;
531
	    break;
532
	}
533
	default: {
534
	    sample_load_declare_setup(sptr, sbit, source_row, source_bit,
535
				      source_depth);
536
	    sample_store_declare_setup(dptr, dbit, dbbyte, dest_row, dest_bit,
537
				       dest_depth);
538
 
539
	    sample_store_preload(dbbyte, dptr, dbit, dest_depth);
540
	    for (x = width; x > 0; --x) {
541
		gx_color_index color;
542
		uint pixel;
543
 
544
		sample_load_next_any(color, sptr, sbit, source_depth);
545
		pixel = (color >> shift) & plane_mask;
546
		sample_store_next8(pixel, dptr, dbit, dest_depth, dbbyte);
547
	    }
548
	    sample_store_flush(dptr, dbit, dest_depth, dbbyte);
549
	}
550
	}
551
    }
552
    return 0;
553
}
554
 
555
/* Expand a plane into a pixmap. */
556
int
557
bits_expand_plane(const bits_plane_t *dest /*write*/,
558
    const bits_plane_t *source /*read*/, int shift, int width, int height)
559
{
560
    /*
561
     * Eventually we will optimize this just like bits_extract_plane.
562
     */
563
    int source_depth = source->depth;
564
    int source_bit = source->x * source_depth;
565
    const byte *source_row = source->data.read + (source_bit >> 3);
566
    int dest_depth = dest->depth;
567
    int dest_bit = dest->x * dest_depth;
568
    byte *dest_row = dest->data.write + (dest_bit >> 3);
569
    enum {
570
	EXPAND_SLOW = 0,
571
	EXPAND_1_TO_4,
572
	EXPAND_8_TO_32
573
    } loop_case = EXPAND_SLOW;
574
    int y;
575
 
576
    source_bit &= 7;
577
    /* Check for the fast CMYK cases. */
578
    if (!(source_bit || (dest_bit & 31) || (dest->raster & 3))) {
579
	switch (dest_depth) {
580
	case 4:
581
	    if (source_depth == 1)
582
		loop_case = EXPAND_1_TO_4;
583
	    break;
584
	case 32:
585
	    if (source_depth == 8 && !(shift & 7))
586
		loop_case = EXPAND_8_TO_32;
587
	    break;
588
	}
589
    }
590
    dest_bit &= 7;
591
    switch (loop_case) {
592
 
593
    case EXPAND_8_TO_32: {
594
#if arch_is_big_endian
595
#  define word_shift (shift)
596
#else
597
	int word_shift = 24 - shift;
598
#endif
599
	for (y = 0; y < height;
600
	     ++y, source_row += source->raster, dest_row += dest->raster
601
	     ) {
602
	    int x;
603
	    const byte *source = source_row;
604
	    bits32 *dest = (bits32 *)dest_row;
605
 
606
	    for (x = width; x > 0; --x)
607
		*dest++ = (bits32)(*source++) << word_shift;
608
	}
609
#undef word_shift
610
    }
611
	break;
612
 
613
    case EXPAND_1_TO_4:
614
    default:
615
	for (y = 0; y < height;
616
	     ++y, source_row += source->raster, dest_row += dest->raster
617
	     ) {
618
	    int x;
619
	    sample_load_declare_setup(sptr, sbit, source_row, source_bit,
620
				      source_depth);
621
	    sample_store_declare_setup(dptr, dbit, dbbyte, dest_row, dest_bit,
622
				       dest_depth);
623
 
624
	    sample_store_preload(dbbyte, dptr, dbit, dest_depth);
625
	    for (x = width; x > 0; --x) {
626
		uint color;
627
		gx_color_index pixel;
628
 
629
		sample_load_next8(color, sptr, sbit, source_depth);
630
		pixel = color << shift;
631
		sample_store_next_any(pixel, dptr, dbit, dest_depth, dbbyte);
632
	    }
633
	    sample_store_flush(dptr, dbit, dest_depth, dbbyte);
634
	}
635
	break;
636
 
637
    }
638
    return 0;
639
}
640
 
641
/* ---------------- Byte-oriented operations ---------------- */
642
 
643
/* Fill a rectangle of bytes. */
644
void
645
bytes_fill_rectangle(byte * dest, uint raster,
646
		     byte value, int width_bytes, int height)
647
{
648
    while (height-- > 0) {
649
	memset(dest, value, width_bytes);
650
	dest += raster;
651
    }
652
}
653
 
654
/* Copy a rectangle of bytes. */
655
void
656
bytes_copy_rectangle(byte * dest, uint dest_raster,
657
	     const byte * src, uint src_raster, int width_bytes, int height)
658
{
659
    while (height-- > 0) {
660
	memcpy(dest, src, width_bytes);
661
	src += src_raster;
662
	dest += dest_raster;
663
    }
664
}