• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*====================================================================*
2  -  Copyright (C) 2001 Leptonica.  All rights reserved.
3  -  This software is distributed in the hope that it will be
4  -  useful, but with NO WARRANTY OF ANY KIND.
5  -  No author or distributor accepts responsibility to anyone for the
6  -  consequences of using this software, or for whether it serves any
7  -  particular purpose or works at all, unless he or she says so in
8  -  writing.  Everyone is granted permission to copy, modify and
9  -  redistribute this source code, for commercial or non-commercial
10  -  purposes, with the following restrictions: (1) the origin of this
11  -  source code must not be misrepresented; (2) modified versions must
12  -  be plainly marked as such; and (3) this notice may not be removed
13  -  or altered from any source or modified source distribution.
14  *====================================================================*/
15 
16 /*
17  *  pix2.c
18  *
19  *    This file has these basic operations:
20  *
21  *      (1) Get and set: individual pixels, full image, rectangular region,
22  *          pad pixels, border pixels, and color components for RGB
23  *      (2) Add and remove border pixels
24  *      (3) Endian byte swaps
25  *
26  *      Pixel poking
27  *           l_int32     pixGetPixel()
28  *           l_int32     pixSetPixel()
29  *           l_int32     pixGetRGBPixel()
30  *           l_int32     pixSetRGBPixel()
31  *           l_int32     pixGetRandomPixel()
32  *           l_int32     pixClearPixel()
33  *           l_int32     pixFlipPixel()
34  *           void        setPixelLow()
35  *
36  *      Full image clear/set/set-to-arbitrary-value
37  *           l_int32     pixClearAll()
38  *           l_int32     pixSetAll()
39  *           l_int32     pixSetAllArbitrary()
40  *           l_int32     pixSetBlackOrWhite()
41  *
42  *      Rectangular region clear/set/set-to-arbitrary-value/blend
43  *           l_int32     pixClearInRect()
44  *           l_int32     pixSetInRect()
45  *           l_int32     pixSetInRectArbitrary()
46  *           l_int32     pixBlendInRect()
47  *
48  *      Set pad bits
49  *           l_int32     pixSetPadBits()
50  *           l_int32     pixSetPadBitsBand()
51  *
52  *      Assign border pixels
53  *           l_int32     pixSetOrClearBorder()
54  *           l_int32     pixSetBorderVal()
55  *           l_int32     pixSetMirroredBorder()
56  *           PIX        *pixCopyBorder()
57  *
58  *      Add and remove border
59  *           PIX        *pixAddBorder()
60  *           PIX        *pixAddBorderGeneral()
61  *           PIX        *pixRemoveBorder()
62  *           PIX        *pixRemoveBorderGeneral()
63  *           PIX        *pixAddMirroredBorder()
64  *           PIX        *pixAddRepeatedBorder()
65  *           PIX        *pixAddMixedBorder()
66  *
67  *      Color sample setting and extraction
68  *           PIX        *pixCreateRGBImage()
69  *           PIX        *pixGetRGBComponent()
70  *           l_int32     pixSetRGBComponent()
71  *           PIX        *pixGetRGBComponentCmap()
72  *           l_int32     composeRGBPixel()
73  *           void        extractRGBValues()
74  *           l_int32     pixGetRGBLine()
75  *
76  *      Conversion between big and little endians
77  *           PIX        *pixEndianByteSwapNew()
78  *           l_int32     pixEndianByteSwap()
79  *           l_int32     lineEndianByteSwap()
80  *           PIX        *pixEndianTwoByteSwapNew()
81  *           l_int32     pixEndianTwoByteSwap()
82  *
83  *      *** indicates implicit assumption about RGB component ordering
84  */
85 
86 
87 #include <stdio.h>
88 #include <stdlib.h>
89 #include <string.h>
90 #include "allheaders.h"
91 
92 static const l_uint32 rmask32[] = {0x0,
93     0x00000001, 0x00000003, 0x00000007, 0x0000000f,
94     0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
95     0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
96     0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
97     0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
98     0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
99     0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
100     0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff};
101 
102 
103 
104 /*-------------------------------------------------------------*
105  *                         Pixel poking                        *
106  *-------------------------------------------------------------*/
107 /*!
108  *  pixGetPixel()
109  *
110  *      Input:  pix
111  *              (x,y) pixel coords
112  *              &val (<return> pixel value)
113  *      Return: 0 if OK; 1 on error
114  *
115  *  Notes:
116  *      (1) This returns the value in the data array.  If the pix is
117  *          colormapped, it returns the colormap index, not the rgb value.
118  */
119 l_int32
pixGetPixel(PIX * pix,l_int32 x,l_int32 y,l_uint32 * pval)120 pixGetPixel(PIX       *pix,
121             l_int32    x,
122             l_int32    y,
123             l_uint32  *pval)
124 {
125 l_int32    w, h, d, wpl, val;
126 l_uint32  *line, *data;
127 
128     PROCNAME("pixGetPixel");
129 
130     if (!pval)
131         return ERROR_INT("pval not defined", procName, 1);
132     *pval = 0;
133     if (!pix)
134         return ERROR_INT("pix not defined", procName, 1);
135 
136     pixGetDimensions(pix, &w, &h, &d);
137     if (x < 0 || x >= w)
138         return ERROR_INT("x out of bounds", procName, 1);
139     if (y < 0 || y >= h)
140         return ERROR_INT("y out of bounds", procName, 1);
141 
142     wpl = pixGetWpl(pix);
143     data = pixGetData(pix);
144     line = data + y * wpl;
145     switch (d)
146     {
147     case 1:
148         val = GET_DATA_BIT(line, x);
149         break;
150     case 2:
151         val = GET_DATA_DIBIT(line, x);
152         break;
153     case 4:
154         val = GET_DATA_QBIT(line, x);
155         break;
156     case 8:
157         val = GET_DATA_BYTE(line, x);
158         break;
159     case 16:
160         val = GET_DATA_TWO_BYTES(line, x);
161         break;
162     case 32:
163         val = line[x];
164         break;
165     default:
166         return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", procName, 1);
167     }
168 
169     *pval = val;
170     return 0;
171 }
172 
173 
174 /*!
175  *  pixSetPixel()
176  *
177  *      Input:  pix
178  *              (x,y) pixel coords
179  *              val (value to be inserted)
180  *      Return: 0 if OK; 1 on error
181  *
182  *  Note: the input value is not checked for overflow, and
183  *        the sign bit (if any) is ignored.
184  */
185 l_int32
pixSetPixel(PIX * pix,l_int32 x,l_int32 y,l_uint32 val)186 pixSetPixel(PIX      *pix,
187             l_int32   x,
188             l_int32   y,
189             l_uint32  val)
190 {
191 l_int32    w, h, d, wpl;
192 l_uint32  *line, *data;
193 
194     PROCNAME("pixSetPixel");
195 
196     if (!pix)
197         return ERROR_INT("pix not defined", procName, 1);
198 
199     pixGetDimensions(pix, &w, &h, &d);
200     if (x < 0 || x >= w)
201         return ERROR_INT("x out of bounds", procName, 1);
202     if (y < 0 || y >= h)
203         return ERROR_INT("y out of bounds", procName, 1);
204 
205     data = pixGetData(pix);
206     wpl = pixGetWpl(pix);
207     line = data + y * wpl;
208     switch (d)
209     {
210     case 1:
211         if (val)
212             SET_DATA_BIT(line, x);
213         else
214             CLEAR_DATA_BIT(line, x);
215         break;
216     case 2:
217         SET_DATA_DIBIT(line, x, val);
218         break;
219     case 4:
220         SET_DATA_QBIT(line, x, val);
221         break;
222     case 8:
223         SET_DATA_BYTE(line, x, val);
224         break;
225     case 16:
226         SET_DATA_TWO_BYTES(line, x, val);
227         break;
228     case 32:
229         line[x] = val;
230         break;
231     default:
232         return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", procName, 1);
233     }
234 
235     return 0;
236 }
237 
238 
239 /*!
240  *  pixGetRGBPixel()
241  *
242  *      Input:  pix (32 bpp rgb, not colormapped)
243  *              (x,y) pixel coords
244  *              &rval (<optional return> red component)
245  *              &gval (<optional return> green component)
246  *              &bval (<optional return> blue component)
247  *      Return: 0 if OK; 1 on error
248  */
249 l_int32
pixGetRGBPixel(PIX * pix,l_int32 x,l_int32 y,l_int32 * prval,l_int32 * pgval,l_int32 * pbval)250 pixGetRGBPixel(PIX      *pix,
251                l_int32   x,
252                l_int32   y,
253                l_int32  *prval,
254                l_int32  *pgval,
255                l_int32  *pbval)
256 {
257 l_int32    w, h, d, wpl;
258 l_uint32  *data, *ppixel;
259 
260     PROCNAME("pixGetRGBPixel");
261 
262     if (!pix)
263         return ERROR_INT("pix not defined", procName, 1);
264     pixGetDimensions(pix, &w, &h, &d);
265     if (d != 32)
266         return ERROR_INT("pix not 32 bpp", procName, 1);
267     if (x < 0 || x >= w)
268         return ERROR_INT("x out of bounds", procName, 1);
269     if (y < 0 || y >= h)
270         return ERROR_INT("y out of bounds", procName, 1);
271 
272     wpl = pixGetWpl(pix);
273     data = pixGetData(pix);
274     ppixel = data + y * wpl + x;
275     if (prval) *prval = GET_DATA_BYTE(ppixel, COLOR_RED);
276     if (pgval) *pgval = GET_DATA_BYTE(ppixel, COLOR_GREEN);
277     if (pbval) *pbval = GET_DATA_BYTE(ppixel, COLOR_BLUE);
278     return 0;
279 }
280 
281 
282 /*!
283  *  pixSetRGBPixel()
284  *
285  *      Input:  pix (32 bpp rgb)
286  *              (x,y) pixel coords
287  *              rval (red component)
288  *              gval (green component)
289  *              bval (blue component)
290  *      Return: 0 if OK; 1 on error
291  */
292 l_int32
pixSetRGBPixel(PIX * pix,l_int32 x,l_int32 y,l_int32 rval,l_int32 gval,l_int32 bval)293 pixSetRGBPixel(PIX     *pix,
294                l_int32  x,
295                l_int32  y,
296                l_int32  rval,
297                l_int32  gval,
298                l_int32  bval)
299 {
300 l_int32    w, h, d, wpl;
301 l_uint32   pixel;
302 l_uint32  *data, *line;
303 
304     PROCNAME("pixSetRGBPixel");
305 
306     if (!pix)
307         return ERROR_INT("pix not defined", procName, 1);
308     pixGetDimensions(pix, &w, &h, &d);
309     if (d != 32)
310         return ERROR_INT("pix not 32 bpp", procName, 1);
311     if (x < 0 || x >= w)
312         return ERROR_INT("x out of bounds", procName, 1);
313     if (y < 0 || y >= h)
314         return ERROR_INT("y out of bounds", procName, 1);
315 
316     wpl = pixGetWpl(pix);
317     data = pixGetData(pix);
318     line = data + y * wpl;
319     composeRGBPixel(rval, gval, bval, &pixel);
320     *(line + x) = pixel;
321     return 0;
322 }
323 
324 
325 /*!
326  *  pixGetRandomPixel()
327  *
328  *      Input:  pix (any depth; can be colormapped)
329  *              &val (<return> pixel value)
330  *              &x (<optional return> x coordinate chosen; can be null)
331  *              &y (<optional return> y coordinate chosen; can be null)
332  *      Return: 0 if OK; 1 on error
333  *
334  *  Notes:
335  *      (1) If the pix is colormapped, it returns the rgb value.
336  */
337 l_int32
pixGetRandomPixel(PIX * pix,l_uint32 * pval,l_int32 * px,l_int32 * py)338 pixGetRandomPixel(PIX       *pix,
339                   l_uint32  *pval,
340                   l_int32   *px,
341                   l_int32   *py)
342 {
343 l_int32   w, h, x, y, rval, gval, bval;
344 l_uint32  val;
345 PIXCMAP  *cmap;
346 
347     PROCNAME("pixGetRandomPixel");
348 
349     if (!pval)
350         return ERROR_INT("pval not defined", procName, 1);
351     *pval = 0;
352     if (!pix)
353         return ERROR_INT("pix not defined", procName, 1);
354 
355     pixGetDimensions(pix, &w, &h, NULL);
356     x = rand() % w;
357     y = rand() % h;
358     if (px) *px = x;
359     if (py) *py = y;
360     pixGetPixel(pix, x, y, &val);
361     if ((cmap = pixGetColormap(pix)) != NULL) {
362         pixcmapGetColor(cmap, val, &rval, &gval, &bval);
363         composeRGBPixel(rval, gval, bval, pval);
364     }
365     else
366         *pval = val;
367 
368     return 0;
369 }
370 
371 
372 /*!
373  *  pixClearPixel()
374  *
375  *      Input:  pix
376  *              (x,y) pixel coords
377  *      Return: 0 if OK; 1 on error.
378  */
379 l_int32
pixClearPixel(PIX * pix,l_int32 x,l_int32 y)380 pixClearPixel(PIX     *pix,
381               l_int32  x,
382               l_int32  y)
383 {
384 l_int32    w, h, d, wpl;
385 l_uint32  *line, *data;
386 
387     PROCNAME("pixClearPixel");
388 
389     if (!pix)
390         return ERROR_INT("pix not defined", procName, 1);
391 
392     pixGetDimensions(pix, &w, &h, &d);
393     if (x < 0 || x >= w)
394         return ERROR_INT("x out of bounds", procName, 1);
395     if (y < 0 || y >= h)
396         return ERROR_INT("y out of bounds", procName, 1);
397 
398     wpl = pixGetWpl(pix);
399     data = pixGetData(pix);
400     line = data + y * wpl;
401     switch (d)
402     {
403     case 1:
404         CLEAR_DATA_BIT(line, x);
405         break;
406     case 2:
407         CLEAR_DATA_DIBIT(line, x);
408         break;
409     case 4:
410         CLEAR_DATA_QBIT(line, x);
411         break;
412     case 8:
413         SET_DATA_BYTE(line, x, 0);
414         break;
415     case 16:
416         SET_DATA_TWO_BYTES(line, x, 0);
417         break;
418     case 32:
419         line[x] = 0;
420         break;
421     default:
422         return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", procName, 1);
423     }
424 
425     return 0;
426 }
427 
428 
429 /*!
430  *  pixFlipPixel()
431  *
432  *      Input:  pix
433  *              (x,y) pixel coords
434  *      Return: 0 if OK; 1 on error
435  */
436 l_int32
pixFlipPixel(PIX * pix,l_int32 x,l_int32 y)437 pixFlipPixel(PIX     *pix,
438              l_int32  x,
439              l_int32  y)
440 {
441 l_int32    w, h, d, wpl;
442 l_uint32   val;
443 l_uint32  *line, *data;
444 
445     PROCNAME("pixFlipPixel");
446 
447     if (!pix)
448         return ERROR_INT("pix not defined", procName, 1);
449 
450     pixGetDimensions(pix, &w, &h, &d);
451     if (x < 0 || x >= w)
452         return ERROR_INT("x out of bounds", procName, 1);
453     if (y < 0 || y >= h)
454         return ERROR_INT("y out of bounds", procName, 1);
455 
456     data = pixGetData(pix);
457     wpl = pixGetWpl(pix);
458     line = data + y * wpl;
459     switch (d)
460     {
461     case 1:
462         val = GET_DATA_BIT(line, x);
463         if (val)
464             CLEAR_DATA_BIT(line, x);
465         else
466             SET_DATA_BIT(line, x);
467         break;
468     case 2:
469         val = GET_DATA_DIBIT(line, x);
470         val ^= 0x3;
471         SET_DATA_DIBIT(line, x, val);
472         break;
473     case 4:
474         val = GET_DATA_QBIT(line, x);
475         val ^= 0xf;
476         SET_DATA_QBIT(line, x, val);
477         break;
478     case 8:
479         val = GET_DATA_BYTE(line, x);
480         val ^= 0xff;
481         SET_DATA_BYTE(line, x, val);
482         break;
483     case 16:
484         val = GET_DATA_TWO_BYTES(line, x);
485         val ^= 0xffff;
486         SET_DATA_TWO_BYTES(line, x, val);
487         break;
488     case 32:
489         val = line[x] ^ 0xffffffff;
490         line[x] = val;
491         break;
492     default:
493         return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", procName, 1);
494     }
495 
496     return 0;
497 }
498 
499 
500 /*!
501  *  setPixelLow()
502  *
503  *      Input:  line (ptr to beginning of line),
504  *              x (pixel location in line)
505  *              depth (bpp)
506  *              val (to be inserted)
507  *      Return: void
508  *
509  *  Notes:
510  *      (1) Caution: input variables are not checked!
511  */
512 void
setPixelLow(l_uint32 * line,l_int32 x,l_int32 depth,l_uint32 val)513 setPixelLow(l_uint32  *line,
514             l_int32    x,
515             l_int32    depth,
516             l_uint32   val)
517 {
518     switch (depth)
519     {
520     case 1:
521         if (val)
522             SET_DATA_BIT(line, x);
523         else
524             CLEAR_DATA_BIT(line, x);
525         break;
526     case 2:
527         SET_DATA_DIBIT(line, x, val);
528         break;
529     case 4:
530         SET_DATA_QBIT(line, x, val);
531         break;
532     case 8:
533         SET_DATA_BYTE(line, x, val);
534         break;
535     case 16:
536         SET_DATA_TWO_BYTES(line, x, val);
537         break;
538     case 32:
539         line[x] = val;
540         break;
541     default:
542         fprintf(stderr, "illegal depth in setPixelLow()\n");
543     }
544 
545     return;
546 }
547 
548 
549 /*-------------------------------------------------------------*
550  *     Full image clear/set/set-to-arbitrary-value/invert      *
551  *-------------------------------------------------------------*/
552 /*!
553  *  pixClearAll()
554  *
555  *      Input:  pix (all depths; use cmapped with caution)
556  *      Return: 0 if OK, 1 on error
557  *
558  *  Notes:
559  *      (1) Clears all data to 0.  For 1 bpp, this is white; for grayscale
560  *          or color, this is black.
561  *      (2) Caution: for colormapped pix, this sets the color to the first
562  *          one in the colormap.  Be sure that this is the intended color!
563  */
564 l_int32
pixClearAll(PIX * pix)565 pixClearAll(PIX  *pix)
566 {
567     PROCNAME("pixClearAll");
568 
569     if (!pix)
570         return ERROR_INT("pix not defined", procName, 1);
571 
572     pixRasterop(pix, 0, 0, pixGetWidth(pix), pixGetHeight(pix),
573                 PIX_CLR, NULL, 0, 0);
574     return 0;
575 }
576 
577 
578 /*!
579  *  pixSetAll()
580  *
581  *      Input:  pix (all depths; use cmapped with caution)
582  *      Return: 0 if OK, 1 on error
583  *
584  *  Notes:
585  *      (1) Sets all data to 1.  For 1 bpp, this is black; for grayscale
586  *          or color, this is white.
587  *      (2) Caution: for colormapped pix, this sets the pixel value to the
588  *          maximum value supported by the colormap: 2^d - 1.  However, this
589  *          color may not be defined, because the colormap may not be full.
590  */
591 l_int32
pixSetAll(PIX * pix)592 pixSetAll(PIX  *pix)
593 {
594 l_int32   n;
595 PIXCMAP  *cmap;
596 
597     PROCNAME("pixSetAll");
598 
599     if (!pix)
600         return ERROR_INT("pix not defined", procName, 1);
601     if ((cmap = pixGetColormap(pix)) != NULL) {
602         n = pixcmapGetCount(cmap);
603         if (n < cmap->nalloc)  /* cmap is not full */
604             return ERROR_INT("cmap entry does not exist", procName, 1);
605     }
606 
607     pixRasterop(pix, 0, 0, pixGetWidth(pix), pixGetHeight(pix),
608                 PIX_SET, NULL, 0, 0);
609     return 0;
610 }
611 
612 
613 /*!
614  *  pixSetAllArbitrary()
615  *
616  *      Input:  pix (all depths; use cmapped with caution)
617  *              val  (value to set all pixels)
618  *      Return: 0 if OK; 1 on error
619  *
620  *  Notes:
621  *      (1) For colormapped pix, be sure the value is the intended
622  *          one in the colormap.
623  *      (2) Caution: for colormapped pix, this sets each pixel to the
624  *          color at the index equal to val.  Be sure that this index
625  *          exists in the colormap and that it is the intended one!
626  */
627 l_int32
pixSetAllArbitrary(PIX * pix,l_uint32 val)628 pixSetAllArbitrary(PIX      *pix,
629                    l_uint32  val)
630 {
631 l_int32    n, i, j, w, h, d, wpl, npix;
632 l_uint32   maxval, wordval;
633 l_uint32  *data, *line;
634 PIXCMAP   *cmap;
635 
636     PROCNAME("pixSetAllArbitrary");
637 
638     if (!pix)
639         return ERROR_INT("pix not defined", procName, 1);
640     if ((cmap = pixGetColormap(pix)) != NULL) {
641         n = pixcmapGetCount(cmap);
642         if (val < 0) {
643             L_WARNING("index not in colormap; using first color", procName);
644             val = 0;
645         }
646         else if (val >= n) {
647             L_WARNING("index not in colormap; using last color", procName);
648             val = n - 1;
649         }
650     }
651 
652     pixGetDimensions(pix, &w, &h, &d);
653     if (d == 32)
654         maxval = 0xffffffff;
655     else
656         maxval = (1 << d) - 1;
657     if (val < 0) {
658         L_WARNING("invalid pixel value; set to 0", procName);
659         val = 0;
660     }
661     if (val > maxval) {
662         L_WARNING_INT("invalid pixel val; set to maxval = %d",
663                       procName, maxval);
664         val = maxval;
665     }
666 
667         /* Set up word to tile with */
668     wordval = 0;
669     npix = 32 / d;    /* number of pixels per 32 bit word */
670     for (j = 0; j < npix; j++)
671         wordval |= (val << (j * d));
672 
673     wpl = pixGetWpl(pix);
674     data = pixGetData(pix);
675     for (i = 0; i < h; i++) {
676         line = data + i * wpl;
677         for (j = 0; j < wpl; j++) {
678             *(line + j) = wordval;
679         }
680     }
681 
682     return 0;
683 }
684 
685 
686 /*!
687  *  pixSetBlackOrWhite()
688  *
689  *      Input:  pixs (all depths; cmap ok)
690  *              incolor (L_BRING_IN_BLACK or L_BRING_IN_WHITE)
691  *      Return: 0 if OK; 1 on error
692  *
693  *  Notes:
694  *      (1) Function for setting all pixels in an image to either black
695  *          or white.
696  *      (2) If pixs is colormapped, it adds black or white to the
697  *          colormap if it's not there and there is room.  If the colormap
698  *          is full, it finds the closest color in intensity.
699  *          This index is written to all pixels.
700  */
701 l_int32
pixSetBlackOrWhite(PIX * pixs,l_int32 incolor)702 pixSetBlackOrWhite(PIX     *pixs,
703                    l_int32  incolor)
704 {
705 l_int32   d, index;
706 PIXCMAP  *cmap;
707 
708     PROCNAME("pixSetBlackOrWhite");
709 
710     if (!pixs)
711         return ERROR_INT("pix not defined", procName, 1);
712     if (incolor != L_BRING_IN_BLACK && incolor != L_BRING_IN_WHITE)
713         return ERROR_INT("invalid incolor", procName, 1);
714 
715     cmap = pixGetColormap(pixs);
716     d = pixGetDepth(pixs);
717     if (!cmap) {
718         if ((d == 1 && incolor == L_BRING_IN_BLACK) ||
719             (d > 1 && incolor == L_BRING_IN_WHITE))
720             pixSetAll(pixs);
721         else
722             pixClearAll(pixs);
723     }
724     else {  /* handle colormap */
725         if (incolor == L_BRING_IN_BLACK)
726             pixcmapAddBlackOrWhite(cmap, 0, &index);
727         else  /* L_BRING_IN_WHITE */
728             pixcmapAddBlackOrWhite(cmap, 1, &index);
729         pixSetAllArbitrary(pixs, index);
730     }
731 
732     return 0;
733 }
734 
735 
736 /*-------------------------------------------------------------*
737  *     Rectangular region clear/set/set-to-arbitrary-value     *
738  *-------------------------------------------------------------*/
739 /*!
740  *  pixClearInRect()
741  *
742  *      Input:  pix (all depths; can be cmapped)
743  *              box (in which all pixels will be cleared)
744  *      Return: 0 if OK, 1 on error
745  *
746  *  Notes:
747  *      (1) Clears all data in rect to 0.  For 1 bpp, this is white;
748  *          for grayscale or color, this is black.
749  *      (2) Caution: for colormapped pix, this sets the color to the first
750  *          one in the colormap.  Be sure that this is the intended color!
751  */
752 l_int32
pixClearInRect(PIX * pix,BOX * box)753 pixClearInRect(PIX  *pix,
754                BOX  *box)
755 {
756 l_int32  x, y, w, h;
757 
758     PROCNAME("pixClearInRect");
759 
760     if (!pix)
761         return ERROR_INT("pix not defined", procName, 1);
762     if (!box)
763         return ERROR_INT("box not defined", procName, 1);
764 
765     boxGetGeometry(box, &x, &y, &w, &h);
766     pixRasterop(pix, x, y, w, h, PIX_CLR, NULL, 0, 0);
767     return 0;
768 }
769 
770 
771 /*!
772  *  pixSetInRect()
773  *
774  *      Input:  pix (all depths, can be cmapped)
775  *              box (in which all pixels will be set)
776  *      Return: 0 if OK, 1 on error
777  *
778  *  Notes:
779  *      (1) Sets all data in rect to 1.  For 1 bpp, this is black;
780  *          for grayscale or color, this is white.
781  *      (2) Caution: for colormapped pix, this sets the pixel value to the
782  *          maximum value supported by the colormap: 2^d - 1.  However, this
783  *          color may not be defined, because the colormap may not be full.
784  */
785 l_int32
pixSetInRect(PIX * pix,BOX * box)786 pixSetInRect(PIX  *pix,
787              BOX  *box)
788 {
789 l_int32   n, x, y, w, h;
790 PIXCMAP  *cmap;
791 
792     PROCNAME("pixSetInRect");
793 
794     if (!pix)
795         return ERROR_INT("pix not defined", procName, 1);
796     if (!box)
797         return ERROR_INT("box not defined", procName, 1);
798     if ((cmap = pixGetColormap(pix)) != NULL) {
799         n = pixcmapGetCount(cmap);
800         if (n < cmap->nalloc)  /* cmap is not full */
801             return ERROR_INT("cmap entry does not exist", procName, 1);
802     }
803 
804     boxGetGeometry(box, &x, &y, &w, &h);
805     pixRasterop(pix, x, y, w, h, PIX_SET, NULL, 0, 0);
806     return 0;
807 }
808 
809 
810 /*!
811  *  pixSetInRectArbitrary()
812  *
813  *      Input:  pix (all depths; can be cmapped)
814  *              box (in which all pixels will be set to val)
815  *              val  (value to set all pixels)
816  *      Return: 0 if OK; 1 on error
817  *
818  *  Notes:
819  *      (1) For colormapped pix, be sure the value is the intended
820  *          one in the colormap.
821  *      (2) Caution: for colormapped pix, this sets each pixel in the
822  *          rect to the color at the index equal to val.  Be sure that
823  *          this index exists in the colormap and that it is the intended one!
824  */
825 l_int32
pixSetInRectArbitrary(PIX * pix,BOX * box,l_uint32 val)826 pixSetInRectArbitrary(PIX      *pix,
827                       BOX      *box,
828                       l_uint32  val)
829 {
830 l_int32    n, x, y, xstart, xend, ystart, yend, bw, bh, w, h, d, wpl, maxval;
831 l_uint32  *data, *line;
832 BOX       *boxc;
833 PIXCMAP   *cmap;
834 
835     PROCNAME("pixSetInRectArbitrary");
836 
837     if (!pix)
838         return ERROR_INT("pix not defined", procName, 1);
839     if (!box)
840         return ERROR_INT("box not defined", procName, 1);
841     pixGetDimensions(pix, &w, &h, &d);
842     if (d != 1 && d != 2 && d != 4 && d !=8 && d != 16 && d != 32)
843         return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", procName, 1);
844     if ((cmap = pixGetColormap(pix)) != NULL) {
845         n = pixcmapGetCount(cmap);
846         if (val < 0) {
847             L_WARNING("index not in colormap; using first color", procName);
848             val = 0;
849         }
850         else if (val >= n) {
851             L_WARNING("index not in colormap; using last color", procName);
852             val = n - 1;
853         }
854     }
855 
856     if (d == 32)
857         maxval = 0xffffffff;
858     else
859         maxval = (1 << d) - 1;
860     if (val < 0) {
861         L_WARNING("invalid pixel value; set to 0", procName);
862         val = 0;
863     }
864     if (val > maxval) {
865         L_WARNING_INT("invalid pixel val; set to maxval = %d",
866                       procName, maxval);
867         val = maxval;
868     }
869 
870         /* Handle the simple cases: the min and max values */
871     if (val == 0) {
872         pixClearInRect(pix, box);
873         return 0;
874     }
875     if (d == 1 ||
876         (d == 2 && val == 3) ||
877         (d == 4 && val == 0xf) ||
878         (d == 8 && val == 0xff) ||
879         (d == 16 && val == 0xffff) ||
880         (d == 32 && ((val ^ 0xffffff00) >> 8 == 0))) {
881         pixSetInRect(pix, box);
882         return 0;
883     }
884 
885         /* Find the overlap of box with the input pix */
886     if ((boxc = boxClipToRectangle(box, w, h)) == NULL)
887         return ERROR_INT("no overlap of box with image", procName, 1);
888     boxGetGeometry(boxc, &xstart, &ystart, &bw, &bh);
889     xend = xstart + bw - 1;
890     yend = ystart + bh - 1;
891     boxDestroy(&boxc);
892 
893     wpl = pixGetWpl(pix);
894     data = pixGetData(pix);
895     for (y = ystart; y <= yend; y++) {
896         line = data + y * wpl;
897         for (x = xstart; x <= xend; x++) {
898             switch(d)
899             {
900             case 2:
901                 SET_DATA_DIBIT(line, x, val);
902                 break;
903             case 4:
904                 SET_DATA_QBIT(line, x, val);
905                 break;
906             case 8:
907                 SET_DATA_BYTE(line, x, val);
908                 break;
909             case 16:
910                 SET_DATA_TWO_BYTES(line, x, val);
911                 break;
912             case 32:
913                 line[x] = val;
914                 break;
915             default:
916                 return ERROR_INT("depth not 2|4|8|16|32 bpp", procName, 1);
917             }
918         }
919     }
920 
921     return 0;
922 }
923 
924 
925 /*!
926  *  pixBlendInRect()
927  *
928  *      Input:  pixs (32 bpp rgb)
929  *              box (in which all pixels will be blended)
930  *              val  (blend value; 0xrrggbb00)
931  *              fract (fraction of color to be blended with each pixel in pixs)
932  *      Return: 0 if OK; 1 on error
933  *
934  *  Notes:
935  *      (1) This is an in-place function.  It blends the input color @val
936  *          with the pixels in pixs in the specified rectangle.
937  */
938 l_int32
pixBlendInRect(PIX * pixs,BOX * box,l_uint32 val,l_float32 fract)939 pixBlendInRect(PIX       *pixs,
940                BOX       *box,
941                l_uint32   val,
942                l_float32  fract)
943 {
944 l_int32    i, j, bx, by, bw, bh, w, h, wpls;
945 l_int32    prval, pgval, pbval, rval, gval, bval;
946 l_uint32   val32;
947 l_uint32  *datas, *lines;
948 
949     PROCNAME("pixBlendInRect");
950 
951     if (!pixs || pixGetDepth(pixs) != 32)
952         return ERROR_INT("pixs not defined or not 32 bpp", procName, 1);
953     if (!box)
954         return ERROR_INT("box not defined", procName, 1);
955 
956     boxGetGeometry(box, &bx, &by, &bw, &bh);
957     pixGetDimensions(pixs, &w, &h, NULL);
958     datas = pixGetData(pixs);
959     wpls = pixGetWpl(pixs);
960     extractRGBValues(val, &rval, &gval, &bval);
961     for (i = 0; i < bh; i++) {   /* scan over box */
962         if (by + i < 0 || by + i >= h) continue;
963         lines = datas + (by + i) * wpls;
964         for (j = 0; j < bw; j++) {
965             if (bx + j < 0 || bx + j >= w) continue;
966             val32 = *(lines + bx + j);
967             extractRGBValues(val32, &prval, &pgval, &pbval);
968             prval = (l_int32)((1. - fract) * prval + fract * rval);
969             pgval = (l_int32)((1. - fract) * pgval + fract * gval);
970             pbval = (l_int32)((1. - fract) * pbval + fract * bval);
971             composeRGBPixel(prval, pgval, pbval, &val32);
972             *(lines + bx + j) = val32;
973         }
974     }
975 
976     return 0;
977 }
978 
979 
980 /*-------------------------------------------------------------*
981  *                         Set pad bits                        *
982  *-------------------------------------------------------------*/
983 /*!
984  *  pixSetPadBits()
985  *
986  *      Input:  pix (1, 2, 4, 8, 16, 32 bpp)
987  *              val  (0 or 1)
988  *      Return: 0 if OK; 1 on error
989  *
990  *  Notes:
991  *      (1) The pad bits are the bits that expand each scanline to a
992  *          multiple of 32 bits.  They are usually not used in
993  *          image processing operations.  When boundary conditions
994  *          are important, as in seedfill, they must be set properly.
995  *      (2) This sets the value of the pad bits (if any) in the last
996  *          32-bit word in each scanline.
997  *      (3) For 32 bpp pix, there are no pad bits, so this is a no-op.
998  */
999 l_int32
pixSetPadBits(PIX * pix,l_int32 val)1000 pixSetPadBits(PIX     *pix,
1001               l_int32  val)
1002 {
1003 l_int32    i, w, h, d, wpl, endbits, fullwords;
1004 l_uint32   mask;
1005 l_uint32  *data, *pword;
1006 
1007     PROCNAME("pixSetPadBits");
1008 
1009     if (!pix)
1010         return ERROR_INT("pix not defined", procName, 1);
1011 
1012     pixGetDimensions(pix, &w, &h, &d);
1013     if (d == 32)  /* no padding exists for 32 bpp */
1014         return 0;
1015 
1016     data = pixGetData(pix);
1017     wpl = pixGetWpl(pix);
1018     endbits = 32 - ((w * d) % 32);
1019     if (endbits == 32)  /* no partial word */
1020         return 0;
1021     fullwords = w * d / 32;
1022 
1023     mask = rmask32[endbits];
1024     if (val == 0)
1025         mask = ~mask;
1026 
1027     for (i = 0; i < h; i++) {
1028         pword = data + i * wpl + fullwords;
1029         if (val == 0) /* clear */
1030             *pword = *pword & mask;
1031         else  /* set */
1032             *pword = *pword | mask;
1033     }
1034 
1035     return 0;
1036 }
1037 
1038 
1039 /*!
1040  *  pixSetPadBitsBand()
1041  *
1042  *      Input:  pix (1, 2, 4, 8, 16, 32 bpp)
1043  *              by  (starting y value of band)
1044  *              bh  (height of band)
1045  *              val  (0 or 1)
1046  *      Return: 0 if OK; 1 on error
1047  *
1048  *  Notes:
1049  *      (1) The pad bits are the bits that expand each scanline to a
1050  *          multiple of 32 bits.  They are usually not used in
1051  *          image processing operations.  When boundary conditions
1052  *          are important, as in seedfill, they must be set properly.
1053  *      (2) This sets the value of the pad bits (if any) in the last
1054  *          32-bit word in each scanline, within the specified
1055  *          band of raster lines.
1056  *      (3) For 32 bpp pix, there are no pad bits, so this is a no-op.
1057  */
1058 l_int32
pixSetPadBitsBand(PIX * pix,l_int32 by,l_int32 bh,l_int32 val)1059 pixSetPadBitsBand(PIX     *pix,
1060                   l_int32  by,
1061                   l_int32  bh,
1062                   l_int32  val)
1063 {
1064 l_int32    i, w, h, d, wpl, endbits, fullwords;
1065 l_uint32   mask;
1066 l_uint32  *data, *pword;
1067 
1068     PROCNAME("pixSetPadBitsBand");
1069 
1070     if (!pix)
1071         return ERROR_INT("pix not defined", procName, 1);
1072 
1073     pixGetDimensions(pix, &w, &h, &d);
1074     if (d == 32)  /* no padding exists for 32 bpp */
1075         return 0;
1076 
1077     if (by < 0)
1078         by = 0;
1079     if (by >= h)
1080         return ERROR_INT("start y not in image", procName, 1);
1081     if (by + bh > h)
1082         bh = h - by;
1083 
1084     data = pixGetData(pix);
1085     wpl = pixGetWpl(pix);
1086     endbits = 32 - ((w * d) % 32);
1087     if (endbits == 32)  /* no partial word */
1088         return 0;
1089     fullwords = w * d / 32;
1090 
1091     mask = rmask32[endbits];
1092     if (val == 0)
1093         mask = ~mask;
1094 
1095     for (i = by; i < by + bh; i++) {
1096         pword = data + i * wpl + fullwords;
1097         if (val == 0) /* clear */
1098             *pword = *pword & mask;
1099         else  /* set */
1100             *pword = *pword | mask;
1101     }
1102 
1103     return 0;
1104 }
1105 
1106 
1107 /*-------------------------------------------------------------*
1108  *                       Set border pixels                     *
1109  *-------------------------------------------------------------*/
1110 /*!
1111  *  pixSetOrClearBorder()
1112  *
1113  *      Input:  pixs (all depths)
1114  *              left, right, top, bot (amount to set or clear)
1115  *              operation (PIX_SET or PIX_CLR)
1116  *      Return: 0 if OK; 1 on error
1117  *
1118  *  Notes:
1119  *      (1) The border region is defined to be the region in the
1120  *          image within a specific distance of each edge.  Here, we
1121  *          allow the pixels within a specified distance of each
1122  *          edge to be set independently.  This either sets or
1123  *          clears all pixels in the border region.
1124  *      (2) For binary images, use PIX_SET for black and PIX_CLR for white.
1125  *      (3) For grayscale or color images, use PIX_SET for white
1126  *          and PIX_CLR for black.
1127  */
1128 l_int32
pixSetOrClearBorder(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot,l_int32 op)1129 pixSetOrClearBorder(PIX     *pixs,
1130                     l_int32  left,
1131                     l_int32  right,
1132                     l_int32  top,
1133                     l_int32  bot,
1134                     l_int32  op)
1135 {
1136 l_int32  w, h;
1137 
1138     PROCNAME("pixSetOrClearBorder");
1139 
1140     if (!pixs)
1141         return ERROR_INT("pixs not defined", procName, 1);
1142     if (op != PIX_SET && op != PIX_CLR)
1143         return ERROR_INT("op must be PIX_SET or PIX_CLR", procName, 1);
1144 
1145     pixGetDimensions(pixs, &w, &h, NULL);
1146     pixRasterop(pixs, 0, 0, left, h, op, NULL, 0, 0);
1147     pixRasterop(pixs, w - right, 0, right, h, op, NULL, 0, 0);
1148     pixRasterop(pixs, 0, 0, w, top, op, NULL, 0, 0);
1149     pixRasterop(pixs, 0, h - bot, w, bot, op, NULL, 0, 0);
1150 
1151     return 0;
1152 }
1153 
1154 
1155 /*!
1156  *  pixSetBorderVal()
1157  *
1158  *      Input:  pixs (8, 16 or 32 bpp)
1159  *              left, right, top, bot (amount to set)
1160  *              val (value to set at each border pixel)
1161  *      Return: 0 if OK; 1 on error
1162  *
1163  *  Notes:
1164  *      (1) The border region is defined to be the region in the
1165  *          image within a specific distance of each edge.  Here, we
1166  *          allow the pixels within a specified distance of each
1167  *          edge to be set independently.  This sets the pixels
1168  *          in the border region to the given input value.
1169  *      (2) For efficiency, use pixSetOrClearBorder() if
1170  *          you're setting the border to either black or white.
1171  *      (3) If d != 32, the input value should be masked off
1172  *          to the appropriate number of least significant bits.
1173  *      (4) The code is easily generalized for 2 or 4 bpp.
1174  */
1175 l_int32
pixSetBorderVal(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot,l_uint32 val)1176 pixSetBorderVal(PIX      *pixs,
1177                 l_int32   left,
1178                 l_int32   right,
1179                 l_int32   top,
1180                 l_int32   bot,
1181                 l_uint32  val)
1182 {
1183 l_int32    w, h, d, wpls, i, j, bstart, rstart;
1184 l_uint32  *datas, *lines;
1185 
1186     PROCNAME("pixSetBorderVal");
1187 
1188     if (!pixs)
1189         return ERROR_INT("pixs not defined", procName, 1);
1190     pixGetDimensions(pixs, &w, &h, &d);
1191     if (d != 8 && d != 16 && d != 32)
1192         return ERROR_INT("depth must be 8, 16 or 32 bpp", procName, 1);
1193 
1194     datas = pixGetData(pixs);
1195     wpls = pixGetWpl(pixs);
1196     if (d == 8) {
1197         val &= 0xff;
1198         for (i = 0; i < top; i++) {
1199             lines = datas + i * wpls;
1200             for (j = 0; j < w; j++)
1201                 SET_DATA_BYTE(lines, j, val);
1202         }
1203         rstart = w - right;
1204         bstart = h - bot;
1205         for (i = top; i < bstart; i++) {
1206             lines = datas + i * wpls;
1207             for (j = 0; j < left; j++)
1208                 SET_DATA_BYTE(lines, j, val);
1209             for (j = rstart; j < w; j++)
1210                 SET_DATA_BYTE(lines, j, val);
1211         }
1212         for (i = bstart; i < h; i++) {
1213             lines = datas + i * wpls;
1214             for (j = 0; j < w; j++)
1215                 SET_DATA_BYTE(lines, j, val);
1216         }
1217     }
1218     else if (d == 16) {
1219         val &= 0xffff;
1220         for (i = 0; i < top; i++) {
1221             lines = datas + i * wpls;
1222             for (j = 0; j < w; j++)
1223                 SET_DATA_TWO_BYTES(lines, j, val);
1224         }
1225         rstart = w - right;
1226         bstart = h - bot;
1227         for (i = top; i < bstart; i++) {
1228             lines = datas + i * wpls;
1229             for (j = 0; j < left; j++)
1230                 SET_DATA_TWO_BYTES(lines, j, val);
1231             for (j = rstart; j < w; j++)
1232                 SET_DATA_TWO_BYTES(lines, j, val);
1233         }
1234         for (i = bstart; i < h; i++) {
1235             lines = datas + i * wpls;
1236             for (j = 0; j < w; j++)
1237                 SET_DATA_TWO_BYTES(lines, j, val);
1238         }
1239     }
1240     else {   /* d == 32 */
1241         for (i = 0; i < top; i++) {
1242             lines = datas + i * wpls;
1243             for (j = 0; j < w; j++)
1244                 *(lines + j) = val;
1245         }
1246         rstart = w - right;
1247         bstart = h - bot;
1248         for (i = top; i < bstart; i++) {
1249             lines = datas + i * wpls;
1250             for (j = 0; j < left; j++)
1251                 *(lines + j) = val;
1252             for (j = rstart; j < w; j++)
1253                 *(lines + j) = val;
1254         }
1255         for (i = bstart; i < h; i++) {
1256             lines = datas + i * wpls;
1257             for (j = 0; j < w; j++)
1258                 *(lines + j) = val;
1259         }
1260     }
1261 
1262     return 0;
1263 }
1264 
1265 
1266 /*!
1267  *  pixSetMirroredBorder()
1268  *
1269  *      Input:  pixs (all depths; colormap ok)
1270  *              left, right, top, bot (number of pixels to set)
1271  *      Return: 0 if OK, 1 on error
1272  *
1273  *  Notes:
1274  *      (1) This applies what is effectively mirror boundary conditions
1275  *          to a border region in the image.  It is in-place.
1276  *      (2) This is useful for setting pixels near the border to a
1277  *          value representative of the near pixels to the interior.
1278  *      (3) The general pixRasterop() is used for an in-place operation here
1279  *          because there is no overlap between the src and dest rectangles.
1280  */
1281 l_int32
pixSetMirroredBorder(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot)1282 pixSetMirroredBorder(PIX     *pixs,
1283                      l_int32  left,
1284                      l_int32  right,
1285                      l_int32  top,
1286                      l_int32  bot)
1287 {
1288 l_int32  i, j, w, h;
1289 
1290     PROCNAME("pixSetMirroredBorder");
1291 
1292     if (!pixs)
1293         return ERROR_INT("pixs not defined", procName, 1);
1294 
1295     pixGetDimensions(pixs, &w, &h, NULL);
1296     for (j = 0; j < left; j++)
1297         pixRasterop(pixs, left - 1 - j, top, 1, h - top - bot, PIX_SRC,
1298                     pixs, left + j, top);
1299     for (j = 0; j < right; j++)
1300         pixRasterop(pixs, w - right + j, top, 1, h - top - bot, PIX_SRC,
1301                     pixs, w - right - 1 - j, top);
1302     for (i = 0; i < top; i++)
1303         pixRasterop(pixs, 0, top - 1 - i, w, 1, PIX_SRC,
1304                     pixs, 0, top + i);
1305     for (i = 0; i < bot; i++)
1306         pixRasterop(pixs, 0, h - bot + i, w, 1, PIX_SRC,
1307                     pixs, 0, h - bot - 1 - i);
1308 
1309     return 0;
1310 }
1311 
1312 
1313 /*!
1314  *  pixCopyBorder()
1315  *
1316  *      Input:  pixd (all depths; colormap ok; can be NULL)
1317  *              pixs (same depth and size as pixd)
1318  *              left, right, top, bot (number of pixels to copy)
1319  *      Return: pixd, or null on error if pixd is not defined
1320  *
1321  *  Notes:
1322  *      (1) pixd can be null, but otherwise it must be the same size
1323  *          and depth as pixs.  Always returns pixd.
1324  *      (1) This is useful in situations where by setting a few border
1325  *          pixels we can avoid having to copy all pixels in pixs into
1326  *          pixd as an initialization step for some operation.
1327  */
1328 PIX *
pixCopyBorder(PIX * pixd,PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot)1329 pixCopyBorder(PIX     *pixd,
1330               PIX     *pixs,
1331               l_int32  left,
1332               l_int32  right,
1333               l_int32  top,
1334               l_int32  bot)
1335 {
1336 l_int32  w, h;
1337 
1338     PROCNAME("pixCopyBorder");
1339 
1340     if (!pixs)
1341         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
1342 
1343     if (pixd) {
1344         if (pixd == pixs) {
1345             L_WARNING("same: nothing to do", procName);
1346             return pixd;
1347         }
1348         else if (!pixSizesEqual(pixs, pixd))
1349             return (PIX *)ERROR_PTR("pixs and pixd sizes differ",
1350                                     procName, pixd);
1351     }
1352     else {
1353         if ((pixd = pixCreateTemplateNoInit(pixs)) == NULL)
1354             return (PIX *)ERROR_PTR("pixd not made", procName, pixd);
1355     }
1356 
1357     pixGetDimensions(pixs, &w, &h, NULL);
1358     pixRasterop(pixd, 0, 0, left, h, PIX_SRC, pixs, 0, 0);
1359     pixRasterop(pixd, w - right, 0, right, h, PIX_SRC, pixs, w - right, 0);
1360     pixRasterop(pixd, 0, 0, w, top, PIX_SRC, pixs, 0, 0);
1361     pixRasterop(pixd, 0, h - bot, w, bot, PIX_SRC, pixs, 0, h - bot);
1362 
1363     return pixd;
1364 }
1365 
1366 
1367 
1368 /*-------------------------------------------------------------*
1369  *                     Add and remove border                   *
1370  *-------------------------------------------------------------*/
1371 /*!
1372  *  pixAddBorder()
1373  *
1374  *      Input:  pixs (all depths; colormap ok)
1375  *              npix (number of pixels to be added to each side)
1376  *              val  (value of added border pixels)
1377  *      Return: pixd (with the input pixs centered), or null on error
1378  *
1379  *  Notes:
1380  *      (1) See pixAddBorderGeneral() for values of white & black pixels.
1381  */
1382 PIX *
pixAddBorder(PIX * pixs,l_int32 npix,l_uint32 val)1383 pixAddBorder(PIX      *pixs,
1384              l_int32   npix,
1385              l_uint32  val)
1386 {
1387     PROCNAME("pixAddBorder");
1388 
1389     if (!pixs)
1390         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1391     if (npix == 0)
1392         return pixClone(pixs);
1393     return pixAddBorderGeneral(pixs, npix, npix, npix, npix, val);
1394 }
1395 
1396 
1397 /*!
1398  *  pixAddBorderGeneral()
1399  *
1400  *      Input:  pixs (all depths; colormap ok)
1401  *              left, right, top, bot  (number of pixels added)
1402  *              val   (value of added border pixels)
1403  *      Return: pixd (with the input pixs inserted), or null on error
1404  *
1405  *  Notes:
1406  *      (1) For binary images:
1407  *             white:  val = 0
1408  *             black:  val = 1
1409  *      (2) For grayscale images:
1410  *             white:  val = 2 ** d - 1
1411  *             black:  val = 0
1412  *      (3) For rgb color images:
1413  *             white:  val = 0xffffff00
1414  *             black:  val = 0
1415  */
1416 PIX *
pixAddBorderGeneral(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot,l_uint32 val)1417 pixAddBorderGeneral(PIX      *pixs,
1418                     l_int32   left,
1419                     l_int32   right,
1420                     l_int32   top,
1421                     l_int32   bot,
1422                     l_uint32  val)
1423 {
1424 l_int32  ws, hs, wd, hd, d, op;
1425 PIX     *pixd;
1426 
1427     PROCNAME("pixAddBorderGeneral");
1428 
1429     if (!pixs)
1430         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1431     if (left < 0 || right < 0 || top < 0 || bot < 0)
1432         return (PIX *)ERROR_PTR("negative border added!", procName, NULL);
1433 
1434     pixGetDimensions(pixs, &ws, &hs, &d);
1435     wd = ws + left + right;
1436     hd = hs + top + bot;
1437     if ((pixd = pixCreateNoInit(wd, hd, d)) == NULL)
1438         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1439     pixCopyResolution(pixd, pixs);
1440     pixCopyColormap(pixd, pixs);
1441 
1442         /* Set the new border pixels */
1443     op = UNDEF;
1444     if (val == 0)
1445         op = PIX_CLR;
1446     else if ((d == 1 && val == 1) || (d == 2 && val == 3) ||
1447              (d == 4 && val == 0xf) || (d == 8 && val == 0xff) ||
1448              (d == 32 && (val >> 8) == 0xffffff))
1449         op = PIX_SET;
1450     if (op == UNDEF)
1451         pixSetAllArbitrary(pixd, val);   /* a little extra writing ! */
1452     else {
1453         pixRasterop(pixd, 0, 0, left, hd, op, NULL, 0, 0);
1454         pixRasterop(pixd, wd - right, 0, right, hd, op, NULL, 0, 0);
1455         pixRasterop(pixd, 0, 0, wd, top, op, NULL, 0, 0);
1456         pixRasterop(pixd, 0, hd - bot, wd, bot, op, NULL, 0, 0);
1457     }
1458 
1459         /* Copy pixs into the interior */
1460     pixRasterop(pixd, left, top, ws, hs, PIX_SRC, pixs, 0, 0);
1461     return pixd;
1462 }
1463 
1464 
1465 /*!
1466  *  pixRemoveBorder()
1467  *
1468  *      Input:  pixs (all depths; colormap ok)
1469  *              npix (number to be removed from each of the 4 sides)
1470  *      Return: pixd (with pixels removed around border), or null on error
1471  */
1472 PIX *
pixRemoveBorder(PIX * pixs,l_int32 npix)1473 pixRemoveBorder(PIX     *pixs,
1474                 l_int32  npix)
1475 {
1476     PROCNAME("pixRemoveBorder");
1477 
1478     if (!pixs)
1479         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1480     if (npix == 0)
1481         return pixClone(pixs);
1482     return pixRemoveBorderGeneral(pixs, npix, npix, npix, npix);
1483 }
1484 
1485 
1486 /*!
1487  *  pixRemoveBorderGeneral()
1488  *
1489  *      Input:  pixs (all depths; colormap ok)
1490  *              left, right, top, bot  (number of pixels added)
1491  *      Return: pixd (with pixels removed around border), or null on error
1492  */
1493 PIX *
pixRemoveBorderGeneral(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot)1494 pixRemoveBorderGeneral(PIX     *pixs,
1495                        l_int32  left,
1496                        l_int32  right,
1497                        l_int32  top,
1498                        l_int32  bot)
1499 {
1500 l_int32  ws, hs, wd, hd, d;
1501 PIX     *pixd;
1502 
1503     PROCNAME("pixRemoveBorderGeneral");
1504 
1505     if (!pixs)
1506         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1507     if (left < 0 || right < 0 || top < 0 || bot < 0)
1508         return (PIX *)ERROR_PTR("negative border removed!", procName, NULL);
1509 
1510     pixGetDimensions(pixs, &ws, &hs, &d);
1511     wd = ws - left - right;
1512     hd = hs - top - bot;
1513     if (wd <= 0)
1514         return (PIX *)ERROR_PTR("width must be > 0", procName, NULL);
1515     if (hd <= 0)
1516         return (PIX *)ERROR_PTR("height must be > 0", procName, NULL);
1517     if ((pixd = pixCreateNoInit(wd, hd, d)) == NULL)
1518         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1519     pixCopyResolution(pixd, pixs);
1520     pixCopyColormap(pixd, pixs);
1521 
1522     pixRasterop(pixd, 0, 0, wd, hd, PIX_SRC, pixs, left, top);
1523     return pixd;
1524 }
1525 
1526 
1527 /*!
1528  *  pixAddMirroredBorder()
1529  *
1530  *      Input:  pixs (all depths; colormap ok)
1531  *              left, right, top, bot (number of pixels added)
1532  *      Return: pixd, or null on error
1533  *
1534  *  Notes:
1535  *      (1) This applies what is effectively mirror boundary conditions.
1536  *          For the added border pixels in pixd, the pixels in pixs
1537  *          near the border are mirror-copied into the border region.
1538  *      (2) This is useful for avoiding special operations near
1539  *          boundaries when doing image processing operations
1540  *          such as rank filters and convolution.  In use, one first
1541  *          adds mirrored pixels to each side of the image.  The number
1542  *          of pixels added on each side is half the filter dimension.
1543  *          Then the image processing operations proceed over a
1544  *          region equal to the size of the original image, and
1545  *          write directly into a dest pix of the same size as pixs.
1546  *      (3) The general pixRasterop() is used for an in-place operation here
1547  *          because there is no overlap between the src and dest rectangles.
1548  */
1549 PIX  *
pixAddMirroredBorder(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot)1550 pixAddMirroredBorder(PIX      *pixs,
1551                       l_int32  left,
1552                       l_int32  right,
1553                       l_int32  top,
1554                       l_int32  bot)
1555 {
1556 l_int32  i, j, w, h;
1557 PIX     *pixd;
1558 
1559     PROCNAME("pixAddMirroredBorder");
1560 
1561     if (!pixs)
1562         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1563     pixGetDimensions(pixs, &w, &h, NULL);
1564     if (left > w || right > w || top > h || bot > h)
1565         return (PIX *)ERROR_PTR("border too large", procName, NULL);
1566 
1567         /* Set pixels on left, right, top and bottom, in that order */
1568     pixd = pixAddBorderGeneral(pixs, left, right, top, bot, 0);
1569     for (j = 0; j < left; j++)
1570         pixRasterop(pixd, left - 1 - j, top, 1, h, PIX_SRC,
1571                     pixd, left + j, top);
1572     for (j = 0; j < right; j++)
1573         pixRasterop(pixd, left + w + j, top, 1, h, PIX_SRC,
1574                     pixd, left + w - 1 - j, top);
1575     for (i = 0; i < top; i++)
1576         pixRasterop(pixd, 0, top - 1 - i, left + w + right, 1, PIX_SRC,
1577                     pixd, 0, top + i);
1578     for (i = 0; i < bot; i++)
1579         pixRasterop(pixd, 0, top + h + i, left + w + right, 1, PIX_SRC,
1580                     pixd, 0, top + h - 1 - i);
1581 
1582     return pixd;
1583 }
1584 
1585 /*!
1586  *  pixAddRepeatedBorder()
1587  *
1588  *      Input:  pixs (all depths; colormap ok)
1589  *              left, right, top, bot (number of pixels added)
1590  *      Return: pixd, or null on error
1591  *
1592  *  Notes:
1593  *      (1) This applies a repeated border, as if the central part of
1594  *          the image is tiled over the plane.  So, for example, the
1595  *          pixels in the left border come from the right side of the image.
1596  *      (2) The general pixRasterop() is used for an in-place operation here
1597  *          because there is no overlap between the src and dest rectangles.
1598  */
1599 PIX  *
pixAddRepeatedBorder(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot)1600 pixAddRepeatedBorder(PIX      *pixs,
1601                      l_int32  left,
1602                      l_int32  right,
1603                      l_int32  top,
1604                      l_int32  bot)
1605 {
1606 l_int32  w, h;
1607 PIX     *pixd;
1608 
1609     PROCNAME("pixAddRepeatedBorder");
1610 
1611     if (!pixs)
1612         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1613     pixGetDimensions(pixs, &w, &h, NULL);
1614     if (left > w || right > w || top > h || bot > h)
1615         return (PIX *)ERROR_PTR("border too large", procName, NULL);
1616 
1617     pixd = pixAddBorderGeneral(pixs, left, right, top, bot, 0);
1618 
1619         /* Set pixels on left, right, top and bottom, in that order */
1620     pixRasterop(pixd, 0, top, left, h, PIX_SRC, pixd, w, top);
1621     pixRasterop(pixd, left + w, top, right, h, PIX_SRC, pixd, left, top);
1622     pixRasterop(pixd, 0, 0, left + w + right, top, PIX_SRC, pixd, 0, h);
1623     pixRasterop(pixd, 0, top + h, left + w + right, bot, PIX_SRC, pixd, 0, top);
1624 
1625     return pixd;
1626 }
1627 
1628 
1629 /*!
1630  *  pixAddMixedBorder()
1631  *
1632  *      Input:  pixs (all depths; colormap ok)
1633  *              left, right, top, bot (number of pixels added)
1634  *      Return: pixd, or null on error
1635  *
1636  *  Notes:
1637  *      (1) This applies mirrored boundary conditions horizontally
1638  *          and repeated b.c. vertically.
1639  *      (2) It is specifically used for avoiding special operations
1640  *          near boundaries when convolving a hue-saturation histogram
1641  *          with a given window size.  The repeated b.c. are used
1642  *          vertically for hue, and the mirrored b.c. are used
1643  *          horizontally for saturation.  The number of pixels added
1644  *          on each side is approximately (but not quite) half the
1645  *          filter dimension.  The image processing operations can
1646  *          then proceed over a region equal to the size of the original
1647  *          image, and write directly into a dest pix of the same
1648  *          size as pixs.
1649  *      (3) The general pixRasterop() can be used for an in-place
1650  *          operation here because there is no overlap between the
1651  *          src and dest rectangles.
1652  */
1653 PIX  *
pixAddMixedBorder(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot)1654 pixAddMixedBorder(PIX      *pixs,
1655                   l_int32  left,
1656                   l_int32  right,
1657                   l_int32  top,
1658                   l_int32  bot)
1659 {
1660 l_int32  j, w, h;
1661 PIX     *pixd;
1662 
1663     PROCNAME("pixAddMixedBorder");
1664 
1665     if (!pixs)
1666         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1667     pixGetDimensions(pixs, &w, &h, NULL);
1668     if (left > w || right > w || top > h || bot > h)
1669         return (PIX *)ERROR_PTR("border too large", procName, NULL);
1670 
1671         /* Set mirrored pixels on left and right;
1672          * then set repeated pixels on top and bottom. */
1673     pixd = pixAddBorderGeneral(pixs, left, right, top, bot, 0);
1674     for (j = 0; j < left; j++)
1675         pixRasterop(pixd, left - 1 - j, top, 1, h, PIX_SRC,
1676                     pixd, left + j, top);
1677     for (j = 0; j < right; j++)
1678         pixRasterop(pixd, left + w + j, top, 1, h, PIX_SRC,
1679                     pixd, left + w - 1 - j, top);
1680     pixRasterop(pixd, 0, 0, left + w + right, top, PIX_SRC, pixd, 0, h);
1681     pixRasterop(pixd, 0, top + h, left + w + right, bot, PIX_SRC, pixd, 0, top);
1682 
1683     return pixd;
1684 }
1685 
1686 
1687 
1688 /*-------------------------------------------------------------*
1689  *                Color sample setting and extraction          *
1690  *-------------------------------------------------------------*/
1691 /*!
1692  *  pixCreateRGBImage()
1693  *
1694  *      Input:  8 bpp red pix
1695  *              8 bpp green pix
1696  *              8 bpp blue pix
1697  *      Return: 32 bpp pix, interleaved with 4 samples/pixel,
1698  *              or null on error
1699  *
1700  *  Notes:
1701  *      (1) the 4th byte, sometimes called the "alpha channel",
1702  *          and which is often used for blending between different
1703  *          images, is left with 0 value.
1704  *      (2) see Note (4) in pix.h for details on storage of
1705  *          8-bit samples within each 32-bit word.
1706  *      (3) This implementation, setting the r, g and b components
1707  *          sequentially, is much faster than setting them in parallel
1708  *          by constructing an RGB dest pixel and writing it to dest.
1709  *          The reason is there are many more cache misses when reading
1710  *          from 3 input images simultaneously.
1711  */
1712 PIX *
pixCreateRGBImage(PIX * pixr,PIX * pixg,PIX * pixb)1713 pixCreateRGBImage(PIX  *pixr,
1714                   PIX  *pixg,
1715                   PIX  *pixb)
1716 {
1717 l_int32  wr, wg, wb, hr, hg, hb, dr, dg, db;
1718 PIX     *pixd;
1719 
1720     PROCNAME("pixCreateRGBImage");
1721 
1722     if (!pixr)
1723         return (PIX *)ERROR_PTR("pixr not defined", procName, NULL);
1724     if (!pixg)
1725         return (PIX *)ERROR_PTR("pixg not defined", procName, NULL);
1726     if (!pixb)
1727         return (PIX *)ERROR_PTR("pixb not defined", procName, NULL);
1728     pixGetDimensions(pixr, &wr, &hr, &dr);
1729     pixGetDimensions(pixg, &wg, &hg, &dg);
1730     pixGetDimensions(pixb, &wb, &hb, &db);
1731     if (dr != 8 || dg != 8 || db != 8)
1732         return (PIX *)ERROR_PTR("input pix not all 8 bpp", procName, NULL);
1733     if (wr != wg || wr != wb)
1734         return (PIX *)ERROR_PTR("widths not the same", procName, NULL);
1735     if (hr != hg || hr != hb)
1736         return (PIX *)ERROR_PTR("heights not the same", procName, NULL);
1737 
1738     if ((pixd = pixCreate(wr, hr, 32)) == NULL)
1739         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1740     pixCopyResolution(pixd, pixr);
1741     pixSetRGBComponent(pixd, pixr, COLOR_RED);
1742     pixSetRGBComponent(pixd, pixg, COLOR_GREEN);
1743     pixSetRGBComponent(pixd, pixb, COLOR_BLUE);
1744 
1745     return pixd;
1746 }
1747 
1748 
1749 /*!
1750  *  pixGetRGBComponent()
1751  *
1752  *      Input:  pixs  (32 bpp)
1753  *              color  (one of {COLOR_RED, COLOR_GREEN, COLOR_BLUE,
1754  *                      L_ALPHA_CHANNEL})
1755  *      Return: pixd, the selected 8 bpp component image of the
1756  *              input 32 bpp image, or null on error
1757  *
1758  *  Notes:
1759  *      (1) The alpha channel (in the 4th byte of each RGB pixel)
1760  *          is not used in leptonica.
1761  *      (2) Three calls to this function generate the three 8 bpp component
1762  *          images.  This is much faster than generating the three
1763  *          images in parallel, by extracting a src pixel and setting
1764  *          the pixels of each component image from it.  The reason is
1765  *          there are many more cache misses when writing to three
1766  *          output images simultaneously.
1767  */
1768 PIX *
pixGetRGBComponent(PIX * pixs,l_int32 color)1769 pixGetRGBComponent(PIX     *pixs,
1770                    l_int32  color)
1771 {
1772 l_uint8    srcbyte;
1773 l_uint32  *lines, *lined;
1774 l_uint32  *datas, *datad;
1775 l_int32    i, j, w, h;
1776 l_int32    wpls, wpld;
1777 PIX           *pixd;
1778 
1779     PROCNAME("pixGetRGBComponent");
1780 
1781     if (!pixs)
1782         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1783     if (pixGetDepth(pixs) != 32)
1784         return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
1785     if (color != COLOR_RED && color != COLOR_GREEN &&
1786         color != COLOR_BLUE && color != L_ALPHA_CHANNEL)
1787         return (PIX *)ERROR_PTR("invalid color", procName, NULL);
1788 
1789     pixGetDimensions(pixs, &w, &h, NULL);
1790     if ((pixd = pixCreate(w, h, 8)) == NULL)
1791         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1792     pixCopyResolution(pixd, pixs);
1793     wpls = pixGetWpl(pixs);
1794     wpld = pixGetWpl(pixd);
1795     datas = pixGetData(pixs);
1796     datad = pixGetData(pixd);
1797 
1798     for (i = 0; i < h; i++) {
1799         lines = datas + i * wpls;
1800         lined = datad + i * wpld;
1801         for (j = 0; j < w; j++) {
1802             srcbyte = GET_DATA_BYTE(lines + j, color);
1803             SET_DATA_BYTE(lined, j, srcbyte);
1804         }
1805     }
1806 
1807     return pixd;
1808 }
1809 
1810 
1811 /*!
1812  *  pixSetRGBComponent()
1813  *
1814  *      Input:  pixd  (32 bpp)
1815  *              pixs  (8 bpp)
1816  *              color  (one of {COLOR_RED, COLOR_GREEN, COLOR_BLUE,
1817  *                      L_ALPHA_CHANNEL})
1818  *      Return: 0 if OK; 1 on error
1819  *
1820  *  Notes:
1821  *      (1) This places the 8 bpp pixel in pixs into the
1822  *          specified color component (properly interleaved) in pixd.
1823  *      (2) The alpha channel component is not used in leptonica.
1824  */
1825 l_int32
pixSetRGBComponent(PIX * pixd,PIX * pixs,l_int32 color)1826 pixSetRGBComponent(PIX     *pixd,
1827                    PIX     *pixs,
1828                    l_int32  color)
1829 {
1830 l_uint8    srcbyte;
1831 l_int32    i, j, w, h;
1832 l_int32    wpls, wpld;
1833 l_uint32  *lines, *lined;
1834 l_uint32  *datas, *datad;
1835 
1836     PROCNAME("pixSetRGBComponent");
1837 
1838     if (!pixd)
1839         return ERROR_INT("pixd not defined", procName, 1);
1840     if (!pixs)
1841         return ERROR_INT("pixs not defined", procName, 1);
1842 
1843     if (pixGetDepth(pixd) != 32)
1844         return ERROR_INT("pixd not 32 bpp", procName, 1);
1845     if (pixGetDepth(pixs) != 8)
1846         return ERROR_INT("pixs not 8 bpp", procName, 1);
1847     if (color != COLOR_RED && color != COLOR_GREEN &&
1848         color != COLOR_BLUE && color != L_ALPHA_CHANNEL)
1849         return ERROR_INT("invalid color", procName, 1);
1850     pixGetDimensions(pixs, &w, &h, NULL);
1851     if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd))
1852         return ERROR_INT("sizes not commensurate", procName, 1);
1853 
1854     datas = pixGetData(pixs);
1855     datad = pixGetData(pixd);
1856     wpls = pixGetWpl(pixs);
1857     wpld = pixGetWpl(pixd);
1858     for (i = 0; i < h; i++) {
1859         lines = datas + i * wpls;
1860         lined = datad + i * wpld;
1861         for (j = 0; j < w; j++) {
1862             srcbyte = GET_DATA_BYTE(lines, j);
1863             SET_DATA_BYTE(lined + j, color, srcbyte);
1864         }
1865     }
1866 
1867     return 0;
1868 }
1869 
1870 
1871 /*!
1872  *  pixGetRGBComponentCmap()
1873  *
1874  *      Input:  pixs  (colormapped)
1875  *              color  (one of {COLOR_RED, COLOR_GREEN, COLOR_BLUE})
1876  *      Return: pixd  (the selected 8 bpp component image of the
1877  *                     input cmapped image), or null on error
1878  */
1879 PIX *
pixGetRGBComponentCmap(PIX * pixs,l_int32 color)1880 pixGetRGBComponentCmap(PIX     *pixs,
1881                        l_int32  color)
1882 {
1883 l_int32     i, j, w, h, val, index;
1884 l_int32     wplc, wpld;
1885 l_uint32   *linec, *lined;
1886 l_uint32   *datac, *datad;
1887 PIX        *pixc, *pixd;
1888 PIXCMAP    *cmap;
1889 RGBA_QUAD  *cta;
1890 
1891     PROCNAME("pixGetRGBComponentCmap");
1892 
1893     if (!pixs)
1894         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1895     if ((cmap = pixGetColormap(pixs)) == NULL)
1896         return (PIX *)ERROR_PTR("pixs not cmapped", procName, NULL);
1897     if (color != COLOR_RED && color != COLOR_GREEN &&
1898         color != COLOR_BLUE)
1899         return (PIX *)ERROR_PTR("invalid color", procName, NULL);
1900 
1901         /* If not 8 bpp, make a cmapped 8 bpp pix */
1902     if (pixGetDepth(pixs) == 8)
1903         pixc = pixClone(pixs);
1904     else
1905         pixc = pixConvertTo8(pixs, TRUE);
1906 
1907     pixGetDimensions(pixs, &w, &h, NULL);
1908     if ((pixd = pixCreateNoInit(w, h, 8)) == NULL)
1909         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1910     pixCopyResolution(pixd, pixs);
1911     wplc = pixGetWpl(pixc);
1912     wpld = pixGetWpl(pixd);
1913     datac = pixGetData(pixc);
1914     datad = pixGetData(pixd);
1915     cta = (RGBA_QUAD *)cmap->array;
1916 
1917     for (i = 0; i < h; i++) {
1918         linec = datac + i * wplc;
1919         lined = datad + i * wpld;
1920         if (color == COLOR_RED) {
1921             for (j = 0; j < w; j++) {
1922                 index = GET_DATA_BYTE(linec, j);
1923                 val = cta[index].red;
1924                 SET_DATA_BYTE(lined, j, val);
1925             }
1926         }
1927         else if (color == COLOR_GREEN) {
1928             for (j = 0; j < w; j++) {
1929                 index = GET_DATA_BYTE(linec, j);
1930                 val = cta[index].green;
1931                 SET_DATA_BYTE(lined, j, val);
1932             }
1933         }
1934         else if (color == COLOR_BLUE) {
1935             for (j = 0; j < w; j++) {
1936                 index = GET_DATA_BYTE(linec, j);
1937                 val = cta[index].green;
1938                 SET_DATA_BYTE(lined, j, val);
1939             }
1940         }
1941     }
1942 
1943     pixDestroy(&pixc);
1944     return pixd;
1945 }
1946 
1947 
1948 /*!
1949  *  composeRGBPixel()
1950  *
1951  *      Input:  rval, gval, bval
1952  *              &rgbpixel  (<return> 32-bit pixel)
1953  *      Return: 0 if OK; 1 on error
1954  *
1955  *  Notes:
1956  *      (1) A slower implementation uses macros:
1957  *            SET_DATA_BYTE(ppixel, COLOR_RED, rval);
1958  *            SET_DATA_BYTE(ppixel, COLOR_GREEN, gval);
1959  *            SET_DATA_BYTE(ppixel, COLOR_BLUE, bval);
1960  */
1961 l_int32
composeRGBPixel(l_int32 rval,l_int32 gval,l_int32 bval,l_uint32 * ppixel)1962 composeRGBPixel(l_int32    rval,
1963                 l_int32    gval,
1964                 l_int32    bval,
1965                 l_uint32  *ppixel)
1966 {
1967     PROCNAME("composeRGBPixel");
1968 
1969     if (!ppixel)
1970         return ERROR_INT("&pixel not defined", procName, 1);
1971 
1972     *ppixel = (rval << L_RED_SHIFT) | (gval << L_GREEN_SHIFT) |
1973               (bval << L_BLUE_SHIFT);
1974     return 0;
1975 }
1976 
1977 
1978 /*!
1979  *  extractRGBValues()
1980  *
1981  *      Input:  pixel (32 bit)
1982  *              &rval (<optional return> red component)
1983  *              &gval (<optional return> green component)
1984  *              &bval (<optional return> blue component)
1985  *      Return: void
1986  *
1987  *  Notes:
1988  *      (1) A slower implementation uses macros:
1989  *             *prval = GET_DATA_BYTE(&pixel, COLOR_RED);
1990  *             *pgval = GET_DATA_BYTE(&pixel, COLOR_GREEN);
1991  *             *pbval = GET_DATA_BYTE(&pixel, COLOR_BLUE);
1992  */
1993 void
extractRGBValues(l_uint32 pixel,l_int32 * prval,l_int32 * pgval,l_int32 * pbval)1994 extractRGBValues(l_uint32  pixel,
1995                  l_int32  *prval,
1996                  l_int32  *pgval,
1997                  l_int32  *pbval)
1998 {
1999     if (prval) *prval = (pixel >> L_RED_SHIFT) & 0xff;
2000     if (pgval) *pgval = (pixel >> L_GREEN_SHIFT) & 0xff;
2001     if (pbval) *pbval = (pixel >> L_BLUE_SHIFT) & 0xff;
2002     return;
2003 }
2004 
2005 
2006 /*!
2007  *  pixGetRGBLine()
2008  *
2009  *      Input:  pixs  (32 bpp)
2010  *              row
2011  *              bufr  (array of red samples; size w bytes)
2012  *              bufg  (array of green samples; size w bytes)
2013  *              bufb  (array of blue samples; size w bytes)
2014  *      Return: 0 if OK; 1 on error
2015  *
2016  *  Notes:
2017  *      (1) This puts rgb components from the input line in pixs
2018  *          into the given buffers.
2019  */
2020 l_int32
pixGetRGBLine(PIX * pixs,l_int32 row,l_uint8 * bufr,l_uint8 * bufg,l_uint8 * bufb)2021 pixGetRGBLine(PIX      *pixs,
2022               l_int32   row,
2023               l_uint8  *bufr,
2024               l_uint8  *bufg,
2025               l_uint8  *bufb)
2026 {
2027 l_uint32  *lines;
2028 l_int32    j, w, h;
2029 l_int32    wpls;
2030 
2031     PROCNAME("pixGetRGBLine");
2032 
2033     if (!pixs)
2034         return ERROR_INT("pixs not defined", procName, 1);
2035     if (pixGetDepth(pixs) != 32)
2036         return ERROR_INT("pixs not 32 bpp", procName, 1);
2037     if (!bufr || !bufg || !bufb)
2038         return ERROR_INT("buffer not defined", procName, 1);
2039 
2040     pixGetDimensions(pixs, &w, &h, NULL);
2041     if (row < 0 || row >= h)
2042         return ERROR_INT("row out of bounds", procName, 1);
2043     wpls = pixGetWpl(pixs);
2044     lines = pixGetData(pixs) + row * wpls;
2045 
2046     for (j = 0; j < w; j++) {
2047         bufr[j] = GET_DATA_BYTE(lines + j, COLOR_RED);
2048         bufg[j] = GET_DATA_BYTE(lines + j, COLOR_GREEN);
2049         bufb[j] = GET_DATA_BYTE(lines + j, COLOR_BLUE);
2050     }
2051 
2052     return 0;
2053 }
2054 
2055 
2056 /*-------------------------------------------------------------*
2057  *                    Pixel endian conversion                  *
2058  *-------------------------------------------------------------*/
2059 /*!
2060  *  pixEndianByteSwapNew()
2061  *
2062  *      Input:  pixs
2063  *      Return: pixd, or null on error
2064  *
2065  *  Notes:
2066  *      (1) This is used to convert the data in a pix to a
2067  *          serialized byte buffer in raster order, and, for RGB,
2068  *          in order RGBA.  This requires flipping bytes within
2069  *          each 32-bit word for little-endian platforms, because the
2070  *          words have a MSB-to-the-left rule, whereas byte raster-order
2071  *          requires the left-most byte in each word to be byte 0.
2072  *          For big-endians, no swap is necessary, so this returns a clone.
2073  *      (2) Unlike pixEndianByteSwap(), which swaps the bytes in-place,
2074  *          this returns a new pix (or a clone).  We provide this
2075  *          because often when serialization is done, the source
2076  *          pix needs to be restored to canonical little-endian order,
2077  *          and this requires a second byte swap.  In such a situation,
2078  *          it is twice as fast to make a new pix in big-endian order,
2079  *          use it, and destroy it.
2080  */
2081 PIX *
pixEndianByteSwapNew(PIX * pixs)2082 pixEndianByteSwapNew(PIX  *pixs)
2083 {
2084 l_uint32  *datas, *datad;
2085 l_int32    i, j, h, wpl;
2086 l_uint32   word;
2087 PIX       *pixd;
2088 
2089     PROCNAME("pixEndianByteSwapNew");
2090 
2091 #ifdef L_BIG_ENDIAN
2092 
2093     return pixClone(pixs);
2094 
2095 #else   /* L_LITTLE_ENDIAN */
2096 
2097     if (!pixs)
2098         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2099 
2100     datas = pixGetData(pixs);
2101     wpl = pixGetWpl(pixs);
2102     h = pixGetHeight(pixs);
2103     pixd = pixCreateTemplate(pixs);
2104     datad = pixGetData(pixd);
2105     for (i = 0; i < h; i++) {
2106         for (j = 0; j < wpl; j++, datas++, datad++) {
2107             word = *datas;
2108             *datad = (word >> 24) |
2109                     ((word >> 8) & 0x0000ff00) |
2110                     ((word << 8) & 0x00ff0000) |
2111                     (word << 24);
2112         }
2113     }
2114 
2115     return pixd;
2116 
2117 #endif   /* L_BIG_ENDIAN */
2118 
2119 }
2120 
2121 
2122 /*!
2123  *  pixEndianByteSwap()
2124  *
2125  *      Input:  pixs
2126  *      Return: 0 if OK, 1 on error
2127  *
2128  *  Notes:
2129  *      (1) This is used on little-endian platforms to swap
2130  *          the bytes within a word; bytes 0 and 3 are swapped,
2131  *          and bytes 1 and 2 are swapped.
2132  *      (2) This is required for little-endians in situations
2133  *          where we convert from a serialized byte order that is
2134  *          in raster order, as one typically has in file formats,
2135  *          to one with MSB-to-the-left in each 32-bit word, or v.v.
2136  *          See pix.h for a description of the canonical format
2137  *          (MSB-to-the left) that is used for both little-endian
2138  *          and big-endian platforms.   For big-endians, the
2139  *          MSB-to-the-left word order has the bytes in raster
2140  *          order when serialized, so no byte flipping is required.
2141  */
2142 l_int32
pixEndianByteSwap(PIX * pixs)2143 pixEndianByteSwap(PIX  *pixs)
2144 {
2145 l_uint32  *data;
2146 l_int32    i, j, h, wpl;
2147 l_uint32   word;
2148 
2149     PROCNAME("pixEndianByteSwap");
2150 
2151 #ifdef L_BIG_ENDIAN
2152 
2153     return 0;
2154 
2155 #else   /* L_LITTLE_ENDIAN */
2156 
2157     if (!pixs)
2158         return ERROR_INT("pixs not defined", procName, 1);
2159 
2160     data = pixGetData(pixs);
2161     wpl = pixGetWpl(pixs);
2162     h = pixGetHeight(pixs);
2163     for (i = 0; i < h; i++) {
2164         for (j = 0; j < wpl; j++, data++) {
2165             word = *data;
2166             *data = (word >> 24) |
2167                     ((word >> 8) & 0x0000ff00) |
2168                     ((word << 8) & 0x00ff0000) |
2169                     (word << 24);
2170         }
2171     }
2172 
2173     return 0;
2174 
2175 #endif   /* L_BIG_ENDIAN */
2176 
2177 }
2178 
2179 
2180 /*!
2181  *  lineEndianByteSwap()
2182  *
2183  *      Input   datad (dest byte array data, reordered on little-endians)
2184  *              datas (a src line of pix data)
2185  *              wpl (number of 32 bit words in the line)
2186  *      Return: 0 if OK, 1 on error
2187  *
2188  *  Notes:
2189  *      (1) This is used on little-endian platforms to swap
2190  *          the bytes within each word in the line of image data.
2191  *          Bytes 0 <==> 3 and 1 <==> 2 are swapped in the dest
2192  *          byte array data8d, relative to the pix data in datas.
2193  *      (2) The bytes represent 8 bit pixel values.  They are swapped
2194  *          for little endians so that when the dest array (char *)datad
2195  *          is addressed by bytes, the pixels are chosen sequentially
2196  *          from left to right in the image.
2197  */
2198 l_int32
lineEndianByteSwap(l_uint32 * datad,l_uint32 * datas,l_int32 wpl)2199 lineEndianByteSwap(l_uint32  *datad,
2200                    l_uint32  *datas,
2201                    l_int32    wpl)
2202 {
2203 l_int32   j;
2204 l_uint32  word;
2205 
2206     PROCNAME("lineEndianByteSwap");
2207 
2208     if (!datad || !datas)
2209         return ERROR_INT("datad and datas not both defined", procName, 1);
2210 
2211 #ifdef L_BIG_ENDIAN
2212 
2213     memcpy((char *)datad, (char *)datas, 4 * wpl);
2214     return 0;
2215 
2216 #else   /* L_LITTLE_ENDIAN */
2217 
2218     for (j = 0; j < wpl; j++, datas++, datad++) {
2219         word = *datas;
2220         *datad = (word >> 24) |
2221                  ((word >> 8) & 0x0000ff00) |
2222                  ((word << 8) & 0x00ff0000) |
2223                  (word << 24);
2224     }
2225     return 0;
2226 
2227 #endif   /* L_BIG_ENDIAN */
2228 
2229 }
2230 
2231 
2232 /*!
2233  *  pixEndianTwoByteSwapNew()
2234  *
2235  *      Input:  pixs
2236  *      Return: 0 if OK, 1 on error
2237  *
2238  *  Notes:
2239  *      (1) This is used on little-endian platforms to swap the
2240  *          2-byte entities within a 32-bit word.
2241  *      (2) This is equivalent to a full byte swap, as performed
2242  *          by pixEndianByteSwap(), followed by byte swaps in
2243  *          each of the 16-bit entities separately.
2244  *      (3) Unlike pixEndianTwoByteSwap(), which swaps the shorts in-place,
2245  *          this returns a new pix (or a clone).  We provide this
2246  *          to avoid having to swap twice in situations where the input
2247  *          pix must be restored to canonical little-endian order.
2248  */
2249 PIX *
pixEndianTwoByteSwapNew(PIX * pixs)2250 pixEndianTwoByteSwapNew(PIX  *pixs)
2251 {
2252 l_uint32  *datas, *datad;
2253 l_int32    i, j, h, wpl;
2254 l_uint32   word;
2255 PIX       *pixd;
2256 
2257     PROCNAME("pixEndianTwoByteSwapNew");
2258 
2259 #ifdef L_BIG_ENDIAN
2260 
2261     return pixClone(pixs);
2262 
2263 #else   /* L_LITTLE_ENDIAN */
2264 
2265     if (!pixs)
2266         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2267 
2268     datas = pixGetData(pixs);
2269     wpl = pixGetWpl(pixs);
2270     h = pixGetHeight(pixs);
2271     pixd = pixCreateTemplate(pixs);
2272     datad = pixGetData(pixd);
2273     for (i = 0; i < h; i++) {
2274         for (j = 0; j < wpl; j++, datas++, datad++) {
2275             word = *datas;
2276             *datad = (word << 16) | (word >> 16);
2277         }
2278     }
2279 
2280     return pixd;
2281 
2282 #endif   /* L_BIG_ENDIAN */
2283 
2284 }
2285 
2286 
2287 /*!
2288  *  pixEndianTwoByteSwap()
2289  *
2290  *      Input:  pixs
2291  *      Return: 0 if OK, 1 on error
2292  *
2293  *  Notes:
2294  *      (1) This is used on little-endian platforms to swap the
2295  *          2-byte entities within a 32-bit word.
2296  *      (2) This is equivalent to a full byte swap, as performed
2297  *          by pixEndianByteSwap(), followed by byte swaps in
2298  *          each of the 16-bit entities separately.
2299  */
2300 l_int32
pixEndianTwoByteSwap(PIX * pixs)2301 pixEndianTwoByteSwap(PIX  *pixs)
2302 {
2303 l_uint32  *data;
2304 l_int32    i, j, h, wpl;
2305 l_uint32   word;
2306 
2307     PROCNAME("pixEndianTwoByteSwap");
2308 
2309 #ifdef L_BIG_ENDIAN
2310 
2311     return 0;
2312 
2313 #else   /* L_LITTLE_ENDIAN */
2314 
2315     if (!pixs)
2316         return ERROR_INT("pixs not defined", procName, 1);
2317 
2318     data = pixGetData(pixs);
2319     wpl = pixGetWpl(pixs);
2320     h = pixGetHeight(pixs);
2321     for (i = 0; i < h; i++) {
2322         for (j = 0; j < wpl; j++, data++) {
2323             word = *data;
2324             *data = (word << 16) | (word >> 16);
2325         }
2326     }
2327 
2328     return 0;
2329 
2330 #endif   /* L_BIG_ENDIAN */
2331 
2332 }
2333 
2334 
2335