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