1 /*====================================================================*
2  -  Copyright (C) 2001 Leptonica.  All rights reserved.
3  -
4  -  Redistribution and use in source and binary forms, with or without
5  -  modification, are permitted provided that the following conditions
6  -  are met:
7  -  1. Redistributions of source code must retain the above copyright
8  -     notice, this list of conditions and the following disclaimer.
9  -  2. Redistributions in binary form must reproduce the above
10  -     copyright notice, this list of conditions and the following
11  -     disclaimer in the documentation and/or other materials
12  -     provided with the distribution.
13  -
14  -  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  -  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  -  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  -  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ANY
18  -  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  -  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  -  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  -  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  -  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23  -  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  -  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *====================================================================*/
26 
27 /*!
28  * \file pix2.c
29  * <pre>
30  *
31  *    This file has these basic operations:
32  *
33  *      (1) Get and set: individual pixels, full image, rectangular region,
34  *          pad pixels, border pixels, and color components for RGB
35  *      (2) Add and remove border pixels
36  *      (3) Endian byte swaps
37  *      (4) Simple method for byte-processing images (instead of words)
38  *
39  *      Pixel poking
40  *           l_int32     pixGetPixel()
41  *           l_int32     pixSetPixel()
42  *           l_int32     pixGetRGBPixel()
43  *           l_int32     pixSetRGBPixel()
44  *           l_int32     pixGetRandomPixel()
45  *           l_int32     pixClearPixel()
46  *           l_int32     pixFlipPixel()
47  *           void        setPixelLow()
48  *
49  *      Find black or white value
50  *           l_int32     pixGetBlackOrWhiteVal()
51  *
52  *      Full image clear/set/set-to-arbitrary-value
53  *           l_int32     pixClearAll()
54  *           l_int32     pixSetAll()
55  *           l_int32     pixSetAllGray()
56  *           l_int32     pixSetAllArbitrary()
57  *           l_int32     pixSetBlackOrWhite()
58  *           l_int32     pixSetComponentArbitrary()
59  *
60  *      Rectangular region clear/set/set-to-arbitrary-value/blend
61  *           l_int32     pixClearInRect()
62  *           l_int32     pixSetInRect()
63  *           l_int32     pixSetInRectArbitrary()
64  *           l_int32     pixBlendInRect()
65  *
66  *      Set pad bits
67  *           l_int32     pixSetPadBits()
68  *           l_int32     pixSetPadBitsBand()
69  *
70  *      Assign border pixels
71  *           l_int32     pixSetOrClearBorder()
72  *           l_int32     pixSetBorderVal()
73  *           l_int32     pixSetBorderRingVal()
74  *           l_int32     pixSetMirroredBorder()
75  *           PIX        *pixCopyBorder()
76  *
77  *      Add and remove border
78  *           PIX        *pixAddBorder()
79  *           PIX        *pixAddBlackOrWhiteBorder()
80  *           PIX        *pixAddBorderGeneral()
81  *           PIX        *pixRemoveBorder()
82  *           PIX        *pixRemoveBorderGeneral()
83  *           PIX        *pixRemoveBorderToSize()
84  *           PIX        *pixAddMirroredBorder()
85  *           PIX        *pixAddRepeatedBorder()
86  *           PIX        *pixAddMixedBorder()
87  *           PIX        *pixAddContinuedBorder()
88  *
89  *      Helper functions using alpha
90  *           l_int32     pixShiftAndTransferAlpha()
91  *           PIX        *pixDisplayLayersRGBA()
92  *
93  *      Color sample setting and extraction
94  *           PIX        *pixCreateRGBImage()
95  *           PIX        *pixGetRGBComponent()
96  *           l_int32     pixSetRGBComponent()
97  *           PIX        *pixGetRGBComponentCmap()
98  *           l_int32     pixCopyRGBComponent()
99  *           l_int32     composeRGBPixel()
100  *           l_int32     composeRGBAPixel()
101  *           void        extractRGBValues()
102  *           void        extractRGBAValues()
103  *           l_int32     extractMinMaxComponent()
104  *           l_int32     pixGetRGBLine()
105  *
106  *      Conversion between big and little endians
107  *           PIX        *pixEndianByteSwapNew()
108  *           l_int32     pixEndianByteSwap()
109  *           l_int32     lineEndianByteSwap()
110  *           PIX        *pixEndianTwoByteSwapNew()
111  *           l_int32     pixEndianTwoByteSwap()
112  *
113  *      Extract raster data as binary string
114  *           l_int32     pixGetRasterData()
115  *
116  *      Test alpha component opaqueness
117  *           l_int32     pixAlphaIsOpaque
118  *
119  *      Setup helpers for 8 bpp byte processing
120  *           l_uint8   **pixSetupByteProcessing()
121  *           l_int32     pixCleanupByteProcessing()
122  *
123  *      Setting parameters for antialias masking with alpha transforms
124  *           void        l_setAlphaMaskBorder()
125  * </pre>
126  */
127 
128 
129 #include <string.h>
130 #include "allheaders.h"
131 
132 static const l_uint32 rmask32[] = {0x0,
133     0x00000001, 0x00000003, 0x00000007, 0x0000000f,
134     0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
135     0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
136     0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
137     0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
138     0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
139     0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
140     0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff};
141 
142     /* This is a global that determines the default 8 bpp alpha mask values
143      * for rings at distance 1 and 2 from the border.  Declare extern
144      * to use.  To change the values, use l_setAlphaMaskBorder(). */
145 LEPT_DLL l_float32  AlphaMaskBorderVals[2] = {0.0, 0.5};
146 
147 
148 #ifndef  NO_CONSOLE_IO
149 #define  DEBUG_SERIALIZE        0
150 #endif  /* ~NO_CONSOLE_IO */
151 
152 
153 /*-------------------------------------------------------------*
154  *                         Pixel poking                        *
155  *-------------------------------------------------------------*/
156 /*!
157  * \brief   pixGetPixel()
158  *
159  * \param[in]    pix
160  * \param[in]    x,y pixel coords
161  * \param[out]   pval pixel value
162  * \return  0 if OK; 1 on error
163  *
164  * <pre>
165  * Notes:
166  *      (1) This returns the value in the data array.  If the pix is
167  *          colormapped, it returns the colormap index, not the rgb value.
168  *      (2) Because of the function overhead and the parameter checking,
169  *          this is much slower than using the GET_DATA_*() macros directly.
170  *          Speed on a 1 Mpixel RGB image, using a 3 GHz machine:
171  *            * pixGet/pixSet: ~25 Mpix/sec
172  *            * GET_DATA/SET_DATA: ~350 MPix/sec
173  *          If speed is important and you're doing random access into
174  *          the pix, use pixGetLinePtrs() and the array access macros.
175  *      (3) If the point is outside the image, this returns an error (1),
176  *          with 0 in %pval.  To avoid spamming output, it fails silently.
177  * </pre>
178  */
179 l_int32
pixGetPixel(PIX * pix,l_int32 x,l_int32 y,l_uint32 * pval)180 pixGetPixel(PIX       *pix,
181             l_int32    x,
182             l_int32    y,
183             l_uint32  *pval)
184 {
185 l_int32    w, h, d, wpl, val;
186 l_uint32  *line, *data;
187 
188     PROCNAME("pixGetPixel");
189 
190     if (!pval)
191         return ERROR_INT("&val not defined", procName, 1);
192     *pval = 0;
193     if (!pix)
194         return ERROR_INT("pix not defined", procName, 1);
195 
196     pixGetDimensions(pix, &w, &h, &d);
197     if (x < 0 || x >= w || y < 0 || y >= h)
198         return 1;
199 
200     wpl = pixGetWpl(pix);
201     data = pixGetData(pix);
202     line = data + y * wpl;
203     switch (d)
204     {
205     case 1:
206         val = GET_DATA_BIT(line, x);
207         break;
208     case 2:
209         val = GET_DATA_DIBIT(line, x);
210         break;
211     case 4:
212         val = GET_DATA_QBIT(line, x);
213         break;
214     case 8:
215         val = GET_DATA_BYTE(line, x);
216         break;
217     case 16:
218         val = GET_DATA_TWO_BYTES(line, x);
219         break;
220     case 32:
221         val = line[x];
222         break;
223     default:
224         return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", procName, 1);
225     }
226 
227     *pval = val;
228     return 0;
229 }
230 
231 
232 /*!
233  * \brief   pixSetPixel()
234  *
235  * \param[in]    pix
236  * \param[in]    x,y pixel coords
237  * \param[in]    val value to be inserted
238  * \return  0 if OK; 1 on error
239  *
240  * <pre>
241  * Notes:
242  *      (1) Warning: the input value is not checked for overflow with respect
243  *          the the depth of %pix, and the sign bit (if any) is ignored.
244  *          * For d == 1, %val > 0 sets the bit on.
245  *          * For d == 2, 4, 8 and 16, %val is masked to the maximum allowable
246  *            pixel value, and any (invalid) higher order bits are discarded.
247  *      (2) See pixGetPixel() for information on performance.
248  * </pre>
249  */
250 l_int32
pixSetPixel(PIX * pix,l_int32 x,l_int32 y,l_uint32 val)251 pixSetPixel(PIX      *pix,
252             l_int32   x,
253             l_int32   y,
254             l_uint32  val)
255 {
256 l_int32    w, h, d, wpl;
257 l_uint32  *line, *data;
258 
259     PROCNAME("pixSetPixel");
260 
261     if (!pix)
262         return ERROR_INT("pix not defined", procName, 1);
263     pixGetDimensions(pix, &w, &h, &d);
264     if (x < 0 || x >= w)
265         return ERROR_INT("x out of bounds", procName, 1);
266     if (y < 0 || y >= h)
267         return ERROR_INT("y out of bounds", procName, 1);
268 
269     data = pixGetData(pix);
270     wpl = pixGetWpl(pix);
271     line = data + y * wpl;
272     switch (d)
273     {
274     case 1:
275         if (val)
276             SET_DATA_BIT(line, x);
277         else
278             CLEAR_DATA_BIT(line, x);
279         break;
280     case 2:
281         SET_DATA_DIBIT(line, x, val);
282         break;
283     case 4:
284         SET_DATA_QBIT(line, x, val);
285         break;
286     case 8:
287         SET_DATA_BYTE(line, x, val);
288         break;
289     case 16:
290         SET_DATA_TWO_BYTES(line, x, val);
291         break;
292     case 32:
293         line[x] = val;
294         break;
295     default:
296         return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", procName, 1);
297     }
298 
299     return 0;
300 }
301 
302 
303 /*!
304  * \brief   pixGetRGBPixel()
305  *
306  * \param[in]    pix 32 bpp rgb, not colormapped
307  * \param[in]    x,y pixel coords
308  * \param[out]   prval [optional] red component
309  * \param[out]   pgval [optional] green component
310  * \param[out]   pbval [optional] blue component
311  * \return  0 if OK; 1 on error
312  */
313 l_int32
pixGetRGBPixel(PIX * pix,l_int32 x,l_int32 y,l_int32 * prval,l_int32 * pgval,l_int32 * pbval)314 pixGetRGBPixel(PIX      *pix,
315                l_int32   x,
316                l_int32   y,
317                l_int32  *prval,
318                l_int32  *pgval,
319                l_int32  *pbval)
320 {
321 l_int32    w, h, d, wpl;
322 l_uint32  *data, *ppixel;
323 
324     PROCNAME("pixGetRGBPixel");
325 
326     if (prval) *prval = 0;
327     if (pgval) *pgval = 0;
328     if (pbval) *pbval = 0;
329     if (!prval && !pgval && !pbval)
330         return ERROR_INT("no output requested", procName, 1);
331     if (!pix)
332         return ERROR_INT("pix not defined", procName, 1);
333     pixGetDimensions(pix, &w, &h, &d);
334     if (d != 32)
335         return ERROR_INT("pix not 32 bpp", procName, 1);
336     if (x < 0 || x >= w)
337         return ERROR_INT("x out of bounds", procName, 1);
338     if (y < 0 || y >= h)
339         return ERROR_INT("y out of bounds", procName, 1);
340 
341     wpl = pixGetWpl(pix);
342     data = pixGetData(pix);
343     ppixel = data + y * wpl + x;
344     if (prval) *prval = GET_DATA_BYTE(ppixel, COLOR_RED);
345     if (pgval) *pgval = GET_DATA_BYTE(ppixel, COLOR_GREEN);
346     if (pbval) *pbval = GET_DATA_BYTE(ppixel, COLOR_BLUE);
347     return 0;
348 }
349 
350 
351 /*!
352  * \brief   pixSetRGBPixel()
353  *
354  * \param[in]    pix 32 bpp rgb
355  * \param[in]    x,y pixel coords
356  * \param[in]    rval red component
357  * \param[in]    gval green component
358  * \param[in]    bval blue component
359  * \return  0 if OK; 1 on error
360  */
361 l_int32
pixSetRGBPixel(PIX * pix,l_int32 x,l_int32 y,l_int32 rval,l_int32 gval,l_int32 bval)362 pixSetRGBPixel(PIX     *pix,
363                l_int32  x,
364                l_int32  y,
365                l_int32  rval,
366                l_int32  gval,
367                l_int32  bval)
368 {
369 l_int32    w, h, d, wpl;
370 l_uint32   pixel;
371 l_uint32  *data, *line;
372 
373     PROCNAME("pixSetRGBPixel");
374 
375     if (!pix)
376         return ERROR_INT("pix not defined", procName, 1);
377     pixGetDimensions(pix, &w, &h, &d);
378     if (d != 32)
379         return ERROR_INT("pix not 32 bpp", procName, 1);
380     if (x < 0 || x >= w)
381         return ERROR_INT("x out of bounds", procName, 1);
382     if (y < 0 || y >= h)
383         return ERROR_INT("y out of bounds", procName, 1);
384 
385     wpl = pixGetWpl(pix);
386     data = pixGetData(pix);
387     line = data + y * wpl;
388     composeRGBPixel(rval, gval, bval, &pixel);
389     *(line + x) = pixel;
390     return 0;
391 }
392 
393 
394 /*!
395  * \brief   pixGetRandomPixel()
396  *
397  * \param[in]    pix any depth; can be colormapped
398  * \param[out]   pval [optional] pixel value
399  * \param[out]   px [optional] x coordinate chosen; can be null
400  * \param[out]   py [optional] y coordinate chosen; can be null
401  * \return  0 if OK; 1 on error
402  *
403  * <pre>
404  * Notes:
405  *      (1) If the pix is colormapped, it returns the rgb value.
406  * </pre>
407  */
408 l_int32
pixGetRandomPixel(PIX * pix,l_uint32 * pval,l_int32 * px,l_int32 * py)409 pixGetRandomPixel(PIX       *pix,
410                   l_uint32  *pval,
411                   l_int32   *px,
412                   l_int32   *py)
413 {
414 l_int32   w, h, x, y, rval, gval, bval;
415 l_uint32  val;
416 PIXCMAP  *cmap;
417 
418     PROCNAME("pixGetRandomPixel");
419 
420     if (pval) *pval = 0;
421     if (px) *px = 0;
422     if (py) *py = 0;
423     if (!pval && !px && !py)
424         return ERROR_INT("no output requested", procName, 1);
425     if (!pix)
426         return ERROR_INT("pix not defined", procName, 1);
427 
428     pixGetDimensions(pix, &w, &h, NULL);
429     x = rand() % w;
430     y = rand() % h;
431     if (px) *px = x;
432     if (py) *py = y;
433     if (pval) {
434         pixGetPixel(pix, x, y, &val);
435         if ((cmap = pixGetColormap(pix)) != NULL) {
436             pixcmapGetColor(cmap, val, &rval, &gval, &bval);
437             composeRGBPixel(rval, gval, bval, pval);
438         } else {
439             *pval = val;
440         }
441     }
442 
443     return 0;
444 }
445 
446 
447 /*!
448  * \brief   pixClearPixel()
449  *
450  * \param[in]    pix
451  * \param[in]    x,y pixel coords
452  * \return  0 if OK; 1 on error.
453  */
454 l_int32
pixClearPixel(PIX * pix,l_int32 x,l_int32 y)455 pixClearPixel(PIX     *pix,
456               l_int32  x,
457               l_int32  y)
458 {
459 l_int32    w, h, d, wpl;
460 l_uint32  *line, *data;
461 
462     PROCNAME("pixClearPixel");
463 
464     if (!pix)
465         return ERROR_INT("pix not defined", procName, 1);
466     pixGetDimensions(pix, &w, &h, &d);
467     if (x < 0 || x >= w)
468         return ERROR_INT("x out of bounds", procName, 1);
469     if (y < 0 || y >= h)
470         return ERROR_INT("y out of bounds", procName, 1);
471 
472     wpl = pixGetWpl(pix);
473     data = pixGetData(pix);
474     line = data + y * wpl;
475     switch (d)
476     {
477     case 1:
478         CLEAR_DATA_BIT(line, x);
479         break;
480     case 2:
481         CLEAR_DATA_DIBIT(line, x);
482         break;
483     case 4:
484         CLEAR_DATA_QBIT(line, x);
485         break;
486     case 8:
487         SET_DATA_BYTE(line, x, 0);
488         break;
489     case 16:
490         SET_DATA_TWO_BYTES(line, x, 0);
491         break;
492     case 32:
493         line[x] = 0;
494         break;
495     default:
496         return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", procName, 1);
497     }
498 
499     return 0;
500 }
501 
502 
503 /*!
504  * \brief   pixFlipPixel()
505  *
506  * \param[in]    pix
507  * \param[in]    x,y pixel coords
508  * \return  0 if OK; 1 on error
509  */
510 l_int32
pixFlipPixel(PIX * pix,l_int32 x,l_int32 y)511 pixFlipPixel(PIX     *pix,
512              l_int32  x,
513              l_int32  y)
514 {
515 l_int32    w, h, d, wpl;
516 l_uint32   val;
517 l_uint32  *line, *data;
518 
519     PROCNAME("pixFlipPixel");
520 
521     if (!pix)
522         return ERROR_INT("pix not defined", procName, 1);
523     pixGetDimensions(pix, &w, &h, &d);
524     if (x < 0 || x >= w)
525         return ERROR_INT("x out of bounds", procName, 1);
526     if (y < 0 || y >= h)
527         return ERROR_INT("y out of bounds", procName, 1);
528 
529     data = pixGetData(pix);
530     wpl = pixGetWpl(pix);
531     line = data + y * wpl;
532     switch (d)
533     {
534     case 1:
535         val = GET_DATA_BIT(line, x);
536         if (val)
537             CLEAR_DATA_BIT(line, x);
538         else
539             SET_DATA_BIT(line, x);
540         break;
541     case 2:
542         val = GET_DATA_DIBIT(line, x);
543         val ^= 0x3;
544         SET_DATA_DIBIT(line, x, val);
545         break;
546     case 4:
547         val = GET_DATA_QBIT(line, x);
548         val ^= 0xf;
549         SET_DATA_QBIT(line, x, val);
550         break;
551     case 8:
552         val = GET_DATA_BYTE(line, x);
553         val ^= 0xff;
554         SET_DATA_BYTE(line, x, val);
555         break;
556     case 16:
557         val = GET_DATA_TWO_BYTES(line, x);
558         val ^= 0xffff;
559         SET_DATA_TWO_BYTES(line, x, val);
560         break;
561     case 32:
562         val = line[x] ^ 0xffffffff;
563         line[x] = val;
564         break;
565     default:
566         return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", procName, 1);
567     }
568 
569     return 0;
570 }
571 
572 
573 /*!
574  * \brief   setPixelLow()
575  *
576  * \param[in]    line ptr to beginning of line,
577  * \param[in]    x pixel location in line
578  * \param[in]    depth bpp
579  * \param[in]    val to be inserted
580  * \return  void
581  *
582  * <pre>
583  * Notes:
584  *      (1) Caution: input variables are not checked!
585  * </pre>
586  */
587 void
setPixelLow(l_uint32 * line,l_int32 x,l_int32 depth,l_uint32 val)588 setPixelLow(l_uint32  *line,
589             l_int32    x,
590             l_int32    depth,
591             l_uint32   val)
592 {
593     switch (depth)
594     {
595     case 1:
596         if (val)
597             SET_DATA_BIT(line, x);
598         else
599             CLEAR_DATA_BIT(line, x);
600         break;
601     case 2:
602         SET_DATA_DIBIT(line, x, val);
603         break;
604     case 4:
605         SET_DATA_QBIT(line, x, val);
606         break;
607     case 8:
608         SET_DATA_BYTE(line, x, val);
609         break;
610     case 16:
611         SET_DATA_TWO_BYTES(line, x, val);
612         break;
613     case 32:
614         line[x] = val;
615         break;
616     default:
617         fprintf(stderr, "illegal depth in setPixelLow()\n");
618     }
619 
620     return;
621 }
622 
623 
624 /*-------------------------------------------------------------*
625  *                     Find black or white value               *
626  *-------------------------------------------------------------*/
627 /*!
628  * \brief   pixGetBlackOrWhiteVal()
629  *
630  * \param[in]    pixs all depths; cmap ok
631  * \param[in]    op L_GET_BLACK_VAL, L_GET_WHITE_VAL
632  * \param[out]   pval pixel value
633  * \return  0 if OK; 1 on error
634  *
635  * <pre>
636  * Notes:
637  *      (1) Side effect.  For a colormapped image, if the requested
638  *          color is not present and there is room to add it in the cmap,
639  *          it is added and the new index is returned.  If there is no room,
640  *          the index of the closest color in intensity is returned.
641  * </pre>
642  */
643 l_int32
pixGetBlackOrWhiteVal(PIX * pixs,l_int32 op,l_uint32 * pval)644 pixGetBlackOrWhiteVal(PIX       *pixs,
645                       l_int32    op,
646                       l_uint32  *pval)
647 {
648 l_int32   d, val;
649 PIXCMAP  *cmap;
650 
651     PROCNAME("pixGetBlackOrWhiteVal");
652 
653     if (!pval)
654         return ERROR_INT("&val not defined", procName, 1);
655     *pval = 0;
656     if (!pixs)
657         return ERROR_INT("pixs not defined", procName, 1);
658     if (op != L_GET_BLACK_VAL && op != L_GET_WHITE_VAL)
659         return ERROR_INT("invalid op", procName, 1);
660 
661     cmap = pixGetColormap(pixs);
662     d = pixGetDepth(pixs);
663     if (!cmap) {
664         if ((d == 1 && op == L_GET_WHITE_VAL) ||
665             (d > 1 && op == L_GET_BLACK_VAL)) {  /* min val */
666             val = 0;
667         } else {  /* max val */
668             val = (d == 32) ? 0xffffff00 : (1 << d) - 1;
669         }
670     } else {  /* handle colormap */
671         if (op == L_GET_BLACK_VAL)
672             pixcmapAddBlackOrWhite(cmap, 0, &val);
673         else  /* L_GET_WHITE_VAL */
674             pixcmapAddBlackOrWhite(cmap, 1, &val);
675     }
676     *pval = val;
677 
678     return 0;
679 }
680 
681 
682 /*-------------------------------------------------------------*
683  *     Full image clear/set/set-to-arbitrary-value/invert      *
684  *-------------------------------------------------------------*/
685 /*!
686  * \brief   pixClearAll()
687  *
688  * \param[in]    pix all depths; use cmapped with caution
689  * \return  0 if OK, 1 on error
690  *
691  * <pre>
692  * Notes:
693  *      (1) Clears all data to 0.  For 1 bpp, this is white; for grayscale
694  *          or color, this is black.
695  *      (2) Caution: for colormapped pix, this sets the color to the first
696  *          one in the colormap.  Be sure that this is the intended color!
697  * </pre>
698  */
699 l_int32
pixClearAll(PIX * pix)700 pixClearAll(PIX  *pix)
701 {
702     PROCNAME("pixClearAll");
703 
704     if (!pix)
705         return ERROR_INT("pix not defined", procName, 1);
706 
707     pixRasterop(pix, 0, 0, pixGetWidth(pix), pixGetHeight(pix),
708                 PIX_CLR, NULL, 0, 0);
709     return 0;
710 }
711 
712 
713 /*!
714  * \brief   pixSetAll()
715  *
716  * \param[in]    pix all depths; use cmapped with caution
717  * \return  0 if OK, 1 on error
718  *
719  * <pre>
720  * Notes:
721  *      (1) Sets all data to 1.  For 1 bpp, this is black; for grayscale
722  *          or color, this is white.
723  *      (2) Caution: for colormapped pix, this sets the pixel value to the
724  *          maximum value supported by the colormap: 2^d - 1.  However, this
725  *          color may not be defined, because the colormap may not be full.
726  * </pre>
727  */
728 l_int32
pixSetAll(PIX * pix)729 pixSetAll(PIX  *pix)
730 {
731 l_int32   n;
732 PIXCMAP  *cmap;
733 
734     PROCNAME("pixSetAll");
735 
736     if (!pix)
737         return ERROR_INT("pix not defined", procName, 1);
738     if ((cmap = pixGetColormap(pix)) != NULL) {
739         n = pixcmapGetCount(cmap);
740         if (n < cmap->nalloc)  /* cmap is not full */
741             return ERROR_INT("cmap entry does not exist", procName, 1);
742     }
743 
744     pixRasterop(pix, 0, 0, pixGetWidth(pix), pixGetHeight(pix),
745                 PIX_SET, NULL, 0, 0);
746     return 0;
747 }
748 
749 
750 /*!
751  * \brief   pixSetAllGray()
752  *
753  * \param[in]    pix all depths, cmap ok
754  * \param[in]    grayval in range 0 ... 255
755  * \return  0 if OK; 1 on error
756  *
757  * <pre>
758  * Notes:
759  *      (1) N.B.  For all images, %grayval == 0 represents black and
760  *          %grayval == 255 represents white.
761  *      (2) For depth < 8, we do our best to approximate the gray level.
762  *          For 1 bpp images, any %grayval < 128 is black; >= 128 is white.
763  *          For 32 bpp images, each r,g,b component is set to %grayval,
764  *          and the alpha component is preserved.
765  *      (3) If pix is colormapped, it adds the gray value, replicated in
766  *          all components, to the colormap if it's not there and there
767  *          is room.  If the colormap is full, it finds the closest color in
768  *          L2 distance of components.  This index is written to all pixels.
769  * </pre>
770  */
771 l_int32
pixSetAllGray(PIX * pix,l_int32 grayval)772 pixSetAllGray(PIX     *pix,
773               l_int32  grayval)
774 {
775 l_int32   d, spp, index;
776 l_uint32  val32;
777 PIX      *alpha;
778 PIXCMAP  *cmap;
779 
780     PROCNAME("pixSetAllGray");
781 
782     if (!pix)
783         return ERROR_INT("pix not defined", procName, 1);
784     if (grayval < 0) {
785         L_WARNING("grayval < 0; setting to 0\n", procName);
786         grayval = 0;
787     } else if (grayval > 255) {
788         L_WARNING("grayval > 255; setting to 255\n", procName);
789         grayval = 255;
790     }
791 
792         /* Handle the colormap case */
793     cmap = pixGetColormap(pix);
794     if (cmap) {
795         pixcmapAddNearestColor(cmap, grayval, grayval, grayval, &index);
796         pixSetAllArbitrary(pix, index);
797         return 0;
798     }
799 
800         /* Non-cmapped */
801     d = pixGetDepth(pix);
802     spp = pixGetSpp(pix);
803     if (d == 1) {
804         if (grayval < 128)  /* black */
805             pixSetAll(pix);
806         else
807             pixClearAll(pix);  /* white */
808     } else if (d < 8) {
809         grayval >>= 8 - d;
810         pixSetAllArbitrary(pix, grayval);
811     } else if (d == 8) {
812         pixSetAllArbitrary(pix, grayval);
813     } else if (d == 16) {
814         grayval |= (grayval << 8);
815         pixSetAllArbitrary(pix, grayval);
816     } else if (d == 32 && spp == 3) {
817         composeRGBPixel(grayval, grayval, grayval, &val32);
818         pixSetAllArbitrary(pix, val32);
819     } else if (d == 32 && spp == 4) {
820         alpha = pixGetRGBComponent(pix, L_ALPHA_CHANNEL);
821         composeRGBPixel(grayval, grayval, grayval, &val32);
822         pixSetAllArbitrary(pix, val32);
823         pixSetRGBComponent(pix, alpha, L_ALPHA_CHANNEL);
824         pixDestroy(&alpha);
825     } else {
826         L_ERROR("invalid depth: %d\n", procName, d);
827         return 1;
828     }
829 
830     return 0;
831 }
832 
833 
834 /*!
835  * \brief   pixSetAllArbitrary()
836  *
837  * \param[in]    pix all depths; use cmapped with caution
838  * \param[in]    val  value to set all pixels
839  * \return  0 if OK; 1 on error
840  *
841  * <pre>
842  * Notes:
843  *      (1) Caution 1!  For colormapped pix, %val is used as an index
844  *          into a colormap.  Be sure that index refers to the intended color.
845  *          If the color is not in the colormap, you should first add it
846  *          and then call this function.
847  *      (2) Caution 2!  For 32 bpp pix, the interpretation of the LSB
848  *          of %val depends on whether spp == 3 (RGB) or spp == 4 (RGBA).
849  *          For RGB, the LSB is ignored in image transformations.
850  *          For RGBA, the LSB is interpreted as the alpha (transparency)
851  *          component; full transparency has alpha == 0x0, whereas
852  *          full opacity has alpha = 0xff.  An RGBA image with full
853  *          opacity behaves like an RGB image.
854  *      (3) As an example of (2), suppose you want to initialize a 32 bpp
855  *          pix with partial opacity, say 0xee337788.  If the pix is 3 spp,
856  *          the 0x88 alpha component will be ignored and may be changed
857  *          in subsequent processing.  However, if the pix is 4 spp, the
858  *          alpha component will be retained and used. The function
859  *          pixCreate(w, h, 32) makes an RGB image by default, and
860  *          pixSetSpp(pix, 4) can be used to promote an RGB image to RGBA.
861  * </pre>
862  */
863 l_int32
pixSetAllArbitrary(PIX * pix,l_uint32 val)864 pixSetAllArbitrary(PIX      *pix,
865                    l_uint32  val)
866 {
867 l_int32    n, i, j, w, h, d, wpl, npix;
868 l_uint32   maxval, wordval;
869 l_uint32  *data, *line;
870 PIXCMAP   *cmap;
871 
872     PROCNAME("pixSetAllArbitrary");
873 
874     if (!pix)
875         return ERROR_INT("pix not defined", procName, 1);
876 
877         /* If colormapped, make sure that val is less than the size
878          * of the cmap array. */
879     if ((cmap = pixGetColormap(pix)) != NULL) {
880         n = pixcmapGetCount(cmap);
881         if (val >= n) {
882             L_WARNING("index not in colormap; using last color\n", procName);
883             val = n - 1;
884         }
885     }
886 
887         /* Make sure val isn't too large for the pixel depth.
888          * If it is too large, set the pixel color to white.  */
889     pixGetDimensions(pix, &w, &h, &d);
890     if (d < 32) {
891         maxval = (1 << d) - 1;
892         if (val > maxval) {
893             L_WARNING("val = %d too large for depth; using maxval = %d\n",
894                       procName, val, maxval);
895             val = maxval;
896         }
897     }
898 
899         /* Set up word to tile with */
900     wordval = 0;
901     npix = 32 / d;    /* number of pixels per 32 bit word */
902     for (j = 0; j < npix; j++)
903         wordval |= (val << (j * d));
904     wpl = pixGetWpl(pix);
905     data = pixGetData(pix);
906     for (i = 0; i < h; i++) {
907         line = data + i * wpl;
908         for (j = 0; j < wpl; j++) {
909             *(line + j) = wordval;
910         }
911     }
912     return 0;
913 }
914 
915 
916 /*!
917  * \brief   pixSetBlackOrWhite()
918  *
919  * \param[in]    pixs all depths; cmap ok
920  * \param[in]    op L_SET_BLACK, L_SET_WHITE
921  * \return  0 if OK; 1 on error
922  *
923  * <pre>
924  * Notes:
925  *      (1) Function for setting all pixels in an image to either black
926  *          or white.
927  *      (2) If pixs is colormapped, it adds black or white to the
928  *          colormap if it's not there and there is room.  If the colormap
929  *          is full, it finds the closest color in intensity.
930  *          This index is written to all pixels.
931  * </pre>
932  */
933 l_int32
pixSetBlackOrWhite(PIX * pixs,l_int32 op)934 pixSetBlackOrWhite(PIX     *pixs,
935                    l_int32  op)
936 {
937 l_int32   d, index;
938 PIXCMAP  *cmap;
939 
940     PROCNAME("pixSetBlackOrWhite");
941 
942     if (!pixs)
943         return ERROR_INT("pix not defined", procName, 1);
944     if (op != L_SET_BLACK && op != L_SET_WHITE)
945         return ERROR_INT("invalid op", procName, 1);
946 
947     cmap = pixGetColormap(pixs);
948     d = pixGetDepth(pixs);
949     if (!cmap) {
950         if ((d == 1 && op == L_SET_BLACK) || (d > 1 && op == L_SET_WHITE))
951             pixSetAll(pixs);
952         else
953             pixClearAll(pixs);
954     } else {  /* handle colormap */
955         if (op == L_SET_BLACK)
956             pixcmapAddBlackOrWhite(cmap, 0, &index);
957         else  /* L_SET_WHITE */
958             pixcmapAddBlackOrWhite(cmap, 1, &index);
959         pixSetAllArbitrary(pixs, index);
960     }
961 
962     return 0;
963 }
964 
965 
966 /*!
967  * \brief   pixSetComponentArbitrary()
968  *
969  * \param[in]    pix 32 bpp
970  * \param[in]    comp COLOR_RED, COLOR_GREEN, COLOR_BLUE, L_ALPHA_CHANNEL
971  * \param[in]    val  value to set this component
972  * \return  0 if OK; 1 on error
973  *
974  * <pre>
975  * Notes:
976  *      (1) For example, this can be used to set the alpha component to opaque:
977  *              pixSetComponentArbitrary(pix, L_ALPHA_CHANNEL, 255)
978  * </pre>
979  */
980 l_int32
pixSetComponentArbitrary(PIX * pix,l_int32 comp,l_int32 val)981 pixSetComponentArbitrary(PIX     *pix,
982                          l_int32  comp,
983                          l_int32  val)
984 {
985 l_int32    i, nwords;
986 l_uint32   mask1, mask2;
987 l_uint32  *data;
988 
989     PROCNAME("pixSetComponentArbitrary");
990 
991     if (!pix || pixGetDepth(pix) != 32)
992         return ERROR_INT("pix not defined or not 32 bpp", procName, 1);
993     if (comp != COLOR_RED && comp != COLOR_GREEN && comp != COLOR_BLUE &&
994         comp != L_ALPHA_CHANNEL)
995         return ERROR_INT("invalid component", procName, 1);
996     if (val < 0 || val > 255)
997         return ERROR_INT("val not in [0 ... 255]", procName, 1);
998 
999     mask1 = ~(255 << (8 * (3 - comp)));
1000     mask2 = val << (8 * (3 - comp));
1001     nwords = pixGetHeight(pix) * pixGetWpl(pix);
1002     data = pixGetData(pix);
1003     for (i = 0; i < nwords; i++) {
1004         data[i] &= mask1;  /* clear out the component */
1005         data[i] |= mask2;  /* insert the new component value */
1006     }
1007 
1008     return 0;
1009 }
1010 
1011 
1012 /*-------------------------------------------------------------*
1013  *     Rectangular region clear/set/set-to-arbitrary-value     *
1014  *-------------------------------------------------------------*/
1015 /*!
1016  * \brief   pixClearInRect()
1017  *
1018  * \param[in]    pix all depths; can be cmapped
1019  * \param[in]    box in which all pixels will be cleared
1020  * \return  0 if OK, 1 on error
1021  *
1022  * <pre>
1023  * Notes:
1024  *      (1) Clears all data in rect to 0.  For 1 bpp, this is white;
1025  *          for grayscale or color, this is black.
1026  *      (2) Caution: for colormapped pix, this sets the color to the first
1027  *          one in the colormap.  Be sure that this is the intended color!
1028  * </pre>
1029  */
1030 l_int32
pixClearInRect(PIX * pix,BOX * box)1031 pixClearInRect(PIX  *pix,
1032                BOX  *box)
1033 {
1034 l_int32  x, y, w, h;
1035 
1036     PROCNAME("pixClearInRect");
1037 
1038     if (!pix)
1039         return ERROR_INT("pix not defined", procName, 1);
1040     if (!box)
1041         return ERROR_INT("box not defined", procName, 1);
1042 
1043     boxGetGeometry(box, &x, &y, &w, &h);
1044     pixRasterop(pix, x, y, w, h, PIX_CLR, NULL, 0, 0);
1045     return 0;
1046 }
1047 
1048 
1049 /*!
1050  * \brief   pixSetInRect()
1051  *
1052  * \param[in]    pix all depths, can be cmapped
1053  * \param[in]    box in which all pixels will be set
1054  * \return  0 if OK, 1 on error
1055  *
1056  * <pre>
1057  * Notes:
1058  *      (1) Sets all data in rect to 1.  For 1 bpp, this is black;
1059  *          for grayscale or color, this is white.
1060  *      (2) Caution: for colormapped pix, this sets the pixel value to the
1061  *          maximum value supported by the colormap: 2^d - 1.  However, this
1062  *          color may not be defined, because the colormap may not be full.
1063  * </pre>
1064  */
1065 l_int32
pixSetInRect(PIX * pix,BOX * box)1066 pixSetInRect(PIX  *pix,
1067              BOX  *box)
1068 {
1069 l_int32   n, x, y, w, h;
1070 PIXCMAP  *cmap;
1071 
1072     PROCNAME("pixSetInRect");
1073 
1074     if (!pix)
1075         return ERROR_INT("pix not defined", procName, 1);
1076     if (!box)
1077         return ERROR_INT("box not defined", procName, 1);
1078     if ((cmap = pixGetColormap(pix)) != NULL) {
1079         n = pixcmapGetCount(cmap);
1080         if (n < cmap->nalloc)  /* cmap is not full */
1081             return ERROR_INT("cmap entry does not exist", procName, 1);
1082     }
1083 
1084     boxGetGeometry(box, &x, &y, &w, &h);
1085     pixRasterop(pix, x, y, w, h, PIX_SET, NULL, 0, 0);
1086     return 0;
1087 }
1088 
1089 
1090 /*!
1091  * \brief   pixSetInRectArbitrary()
1092  *
1093  * \param[in]    pix all depths; can be cmapped
1094  * \param[in]    box in which all pixels will be set to val
1095  * \param[in]    val  value to set all pixels
1096  * \return  0 if OK; 1 on error
1097  *
1098  * <pre>
1099  * Notes:
1100  *      (1) For colormapped pix, be sure the value is the intended
1101  *          one in the colormap.
1102  *      (2) Caution: for colormapped pix, this sets each pixel in the
1103  *          rect to the color at the index equal to val.  Be sure that
1104  *          this index exists in the colormap and that it is the intended one!
1105  * </pre>
1106  */
1107 l_int32
pixSetInRectArbitrary(PIX * pix,BOX * box,l_uint32 val)1108 pixSetInRectArbitrary(PIX      *pix,
1109                       BOX      *box,
1110                       l_uint32  val)
1111 {
1112 l_int32    n, x, y, xstart, xend, ystart, yend, bw, bh, w, h, d, wpl, maxval;
1113 l_uint32  *data, *line;
1114 BOX       *boxc;
1115 PIXCMAP   *cmap;
1116 
1117     PROCNAME("pixSetInRectArbitrary");
1118 
1119     if (!pix)
1120         return ERROR_INT("pix not defined", procName, 1);
1121     if (!box)
1122         return ERROR_INT("box not defined", procName, 1);
1123     pixGetDimensions(pix, &w, &h, &d);
1124     if (d != 1 && d != 2 && d != 4 && d !=8 && d != 16 && d != 32)
1125         return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", procName, 1);
1126     if ((cmap = pixGetColormap(pix)) != NULL) {
1127         n = pixcmapGetCount(cmap);
1128         if (val >= n) {
1129             L_WARNING("index not in colormap; using last color\n", procName);
1130             val = n - 1;
1131         }
1132     }
1133 
1134     maxval = (d == 32) ? 0xffffff00 : (1 << d) - 1;
1135     if (val > maxval) val = maxval;
1136 
1137         /* Handle the simple cases: the min and max values */
1138     if (val == 0) {
1139         pixClearInRect(pix, box);
1140         return 0;
1141     }
1142     if (d == 1 ||
1143         (d == 2 && val == 3) ||
1144         (d == 4 && val == 0xf) ||
1145         (d == 8 && val == 0xff) ||
1146         (d == 16 && val == 0xffff) ||
1147         (d == 32 && ((val ^ 0xffffff00) >> 8 == 0))) {
1148         pixSetInRect(pix, box);
1149         return 0;
1150     }
1151 
1152         /* Find the overlap of box with the input pix */
1153     if ((boxc = boxClipToRectangle(box, w, h)) == NULL)
1154         return ERROR_INT("no overlap of box with image", procName, 1);
1155     boxGetGeometry(boxc, &xstart, &ystart, &bw, &bh);
1156     xend = xstart + bw - 1;
1157     yend = ystart + bh - 1;
1158     boxDestroy(&boxc);
1159 
1160     wpl = pixGetWpl(pix);
1161     data = pixGetData(pix);
1162     for (y = ystart; y <= yend; y++) {
1163         line = data + y * wpl;
1164         for (x = xstart; x <= xend; x++) {
1165             switch(d)
1166             {
1167             case 2:
1168                 SET_DATA_DIBIT(line, x, val);
1169                 break;
1170             case 4:
1171                 SET_DATA_QBIT(line, x, val);
1172                 break;
1173             case 8:
1174                 SET_DATA_BYTE(line, x, val);
1175                 break;
1176             case 16:
1177                 SET_DATA_TWO_BYTES(line, x, val);
1178                 break;
1179             case 32:
1180                 line[x] = val;
1181                 break;
1182             default:
1183                 return ERROR_INT("depth not 2|4|8|16|32 bpp", procName, 1);
1184             }
1185         }
1186     }
1187 
1188     return 0;
1189 }
1190 
1191 
1192 /*!
1193  * \brief   pixBlendInRect()
1194  *
1195  * \param[in]    pixs 32 bpp rgb
1196  * \param[in]    box [optional] in which all pixels will be blended
1197  * \param[in]    val  blend value; 0xrrggbb00
1198  * \param[in]    fract fraction of color to be blended with each pixel in pixs
1199  * \return  0 if OK; 1 on error
1200  *
1201  * <pre>
1202  * Notes:
1203  *      (1) This is an in-place function.  It blends the input color %val
1204  *          with the pixels in pixs in the specified rectangle.
1205  *          If no rectangle is specified, it blends over the entire image.
1206  * </pre>
1207  */
1208 l_int32
pixBlendInRect(PIX * pixs,BOX * box,l_uint32 val,l_float32 fract)1209 pixBlendInRect(PIX       *pixs,
1210                BOX       *box,
1211                l_uint32   val,
1212                l_float32  fract)
1213 {
1214 l_int32    i, j, bx, by, bw, bh, w, h, wpls;
1215 l_int32    prval, pgval, pbval, rval, gval, bval;
1216 l_uint32   val32;
1217 l_uint32  *datas, *lines;
1218 
1219     PROCNAME("pixBlendInRect");
1220 
1221     if (!pixs || pixGetDepth(pixs) != 32)
1222         return ERROR_INT("pixs not defined or not 32 bpp", procName, 1);
1223 
1224     extractRGBValues(val, &rval, &gval, &bval);
1225     pixGetDimensions(pixs, &w, &h, NULL);
1226     datas = pixGetData(pixs);
1227     wpls = pixGetWpl(pixs);
1228     if (!box) {
1229         for (i = 0; i < h; i++) {   /* scan over box */
1230             lines = datas +  i * wpls;
1231             for (j = 0; j < w; j++) {
1232                 val32 = *(lines + j);
1233                 extractRGBValues(val32, &prval, &pgval, &pbval);
1234                 prval = (l_int32)((1. - fract) * prval + fract * rval);
1235                 pgval = (l_int32)((1. - fract) * pgval + fract * gval);
1236                 pbval = (l_int32)((1. - fract) * pbval + fract * bval);
1237                 composeRGBPixel(prval, pgval, pbval, &val32);
1238                 *(lines + j) = val32;
1239             }
1240         }
1241         return 0;
1242     }
1243 
1244     boxGetGeometry(box, &bx, &by, &bw, &bh);
1245     for (i = 0; i < bh; i++) {   /* scan over box */
1246         if (by + i < 0 || by + i >= h) continue;
1247         lines = datas + (by + i) * wpls;
1248         for (j = 0; j < bw; j++) {
1249             if (bx + j < 0 || bx + j >= w) continue;
1250             val32 = *(lines + bx + j);
1251             extractRGBValues(val32, &prval, &pgval, &pbval);
1252             prval = (l_int32)((1. - fract) * prval + fract * rval);
1253             pgval = (l_int32)((1. - fract) * pgval + fract * gval);
1254             pbval = (l_int32)((1. - fract) * pbval + fract * bval);
1255             composeRGBPixel(prval, pgval, pbval, &val32);
1256             *(lines + bx + j) = val32;
1257         }
1258     }
1259     return 0;
1260 }
1261 
1262 
1263 /*-------------------------------------------------------------*
1264  *                         Set pad bits                        *
1265  *-------------------------------------------------------------*/
1266 /*!
1267  * \brief   pixSetPadBits()
1268  *
1269  * \param[in]    pix 1, 2, 4, 8, 16, 32 bpp
1270  * \param[in]    val  0 or 1
1271  * \return  0 if OK; 1 on error
1272  *
1273  * <pre>
1274  * Notes:
1275  *      (1) The pad bits are the bits that expand each scanline to a
1276  *          multiple of 32 bits.  They are usually not used in
1277  *          image processing operations.  When boundary conditions
1278  *          are important, as in seedfill, they must be set properly.
1279  *      (2) This sets the value of the pad bits (if any) in the last
1280  *          32-bit word in each scanline.
1281  *      (3) For 32 bpp pix, there are no pad bits, so this is a no-op.
1282  *      (4) When writing formatted output, such as tiff, png or jpeg,
1283  *          the pad bits have no effect on the raster image that is
1284  *          generated by reading back from the file.  However, in some
1285  *          cases, the compressed file itself will depend on the pad
1286  *          bits.  This is seen, for example, in Windows with 2 and 4 bpp
1287  *          tiff-compressed images that have pad bits on each scanline.
1288  *          It is sometimes convenient to use a golden file with a
1289  *          byte-by-byte check to verify invariance.  Consequently,
1290  *          and because setting the pad bits is cheap, the pad bits are
1291  *          set to 0 before writing these compressed files.
1292  * </pre>
1293  */
1294 l_int32
pixSetPadBits(PIX * pix,l_int32 val)1295 pixSetPadBits(PIX     *pix,
1296               l_int32  val)
1297 {
1298 l_int32    i, w, h, d, wpl, endbits, fullwords;
1299 l_uint32   mask;
1300 l_uint32  *data, *pword;
1301 
1302     PROCNAME("pixSetPadBits");
1303 
1304     if (!pix)
1305         return ERROR_INT("pix not defined", procName, 1);
1306 
1307     pixGetDimensions(pix, &w, &h, &d);
1308     if (d == 32)  /* no padding exists for 32 bpp */
1309         return 0;
1310 
1311     data = pixGetData(pix);
1312     wpl = pixGetWpl(pix);
1313     endbits = 32 - (((l_int64)w * d) % 32);
1314     if (endbits == 32)  /* no partial word */
1315         return 0;
1316     fullwords = (1LL * w * d) / 32;
1317     mask = rmask32[endbits];
1318     if (val == 0)
1319         mask = ~mask;
1320 
1321     for (i = 0; i < h; i++) {
1322         pword = data + i * wpl + fullwords;
1323         if (val == 0) /* clear */
1324             *pword = *pword & mask;
1325         else  /* set */
1326             *pword = *pword | mask;
1327     }
1328 
1329     return 0;
1330 }
1331 
1332 
1333 /*!
1334  * \brief   pixSetPadBitsBand()
1335  *
1336  * \param[in]    pix 1, 2, 4, 8, 16, 32 bpp
1337  * \param[in]    by  starting y value of band
1338  * \param[in]    bh  height of band
1339  * \param[in]    val  0 or 1
1340  * \return  0 if OK; 1 on error
1341  *
1342  * <pre>
1343  * Notes:
1344  *      (1) The pad bits are the bits that expand each scanline to a
1345  *          multiple of 32 bits.  They are usually not used in
1346  *          image processing operations.  When boundary conditions
1347  *          are important, as in seedfill, they must be set properly.
1348  *      (2) This sets the value of the pad bits (if any) in the last
1349  *          32-bit word in each scanline, within the specified
1350  *          band of raster lines.
1351  *      (3) For 32 bpp pix, there are no pad bits, so this is a no-op.
1352  * </pre>
1353  */
1354 l_int32
pixSetPadBitsBand(PIX * pix,l_int32 by,l_int32 bh,l_int32 val)1355 pixSetPadBitsBand(PIX     *pix,
1356                   l_int32  by,
1357                   l_int32  bh,
1358                   l_int32  val)
1359 {
1360 l_int32    i, w, h, d, wpl, endbits, fullwords;
1361 l_uint32   mask;
1362 l_uint32  *data, *pword;
1363 
1364     PROCNAME("pixSetPadBitsBand");
1365 
1366     if (!pix)
1367         return ERROR_INT("pix not defined", procName, 1);
1368 
1369     pixGetDimensions(pix, &w, &h, &d);
1370     if (d == 32)  /* no padding exists for 32 bpp */
1371         return 0;
1372 
1373     if (by < 0)
1374         by = 0;
1375     if (by >= h)
1376         return ERROR_INT("start y not in image", procName, 1);
1377     if (by + bh > h)
1378         bh = h - by;
1379 
1380     data = pixGetData(pix);
1381     wpl = pixGetWpl(pix);
1382     endbits = 32 - (((l_int64)w * d) % 32);
1383     if (endbits == 32)  /* no partial word */
1384         return 0;
1385     fullwords = (l_int64)w * d / 32;
1386 
1387     mask = rmask32[endbits];
1388     if (val == 0)
1389         mask = ~mask;
1390 
1391     for (i = by; i < by + bh; i++) {
1392         pword = data + i * wpl + fullwords;
1393         if (val == 0) /* clear */
1394             *pword = *pword & mask;
1395         else  /* set */
1396             *pword = *pword | mask;
1397     }
1398 
1399     return 0;
1400 }
1401 
1402 
1403 /*-------------------------------------------------------------*
1404  *                       Set border pixels                     *
1405  *-------------------------------------------------------------*/
1406 /*!
1407  * \brief   pixSetOrClearBorder()
1408  *
1409  * \param[in]    pixs all depths
1410  * \param[in]    left, right, top, bot amount to set or clear
1411  * \param[in]    op operation PIX_SET or PIX_CLR
1412  * \return  0 if OK; 1 on error
1413  *
1414  * <pre>
1415  * Notes:
1416  *      (1) The border region is defined to be the region in the
1417  *          image within a specific distance of each edge.  Here, we
1418  *          allow the pixels within a specified distance of each
1419  *          edge to be set independently.  This either sets or
1420  *          clears all pixels in the border region.
1421  *      (2) For binary images, use PIX_SET for black and PIX_CLR for white.
1422  *      (3) For grayscale or color images, use PIX_SET for white
1423  *          and PIX_CLR for black.
1424  * </pre>
1425  */
1426 l_int32
pixSetOrClearBorder(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot,l_int32 op)1427 pixSetOrClearBorder(PIX     *pixs,
1428                     l_int32  left,
1429                     l_int32  right,
1430                     l_int32  top,
1431                     l_int32  bot,
1432                     l_int32  op)
1433 {
1434 l_int32  w, h;
1435 
1436     PROCNAME("pixSetOrClearBorder");
1437 
1438     if (!pixs)
1439         return ERROR_INT("pixs not defined", procName, 1);
1440     if (op != PIX_SET && op != PIX_CLR)
1441         return ERROR_INT("op must be PIX_SET or PIX_CLR", procName, 1);
1442 
1443     pixGetDimensions(pixs, &w, &h, NULL);
1444     pixRasterop(pixs, 0, 0, left, h, op, NULL, 0, 0);
1445     pixRasterop(pixs, w - right, 0, right, h, op, NULL, 0, 0);
1446     pixRasterop(pixs, 0, 0, w, top, op, NULL, 0, 0);
1447     pixRasterop(pixs, 0, h - bot, w, bot, op, NULL, 0, 0);
1448 
1449     return 0;
1450 }
1451 
1452 
1453 /*!
1454  * \brief   pixSetBorderVal()
1455  *
1456  * \param[in]    pixs 8, 16 or 32 bpp
1457  * \param[in]    left, right, top, bot amount to set
1458  * \param[in]    val value to set at each border pixel
1459  * \return  0 if OK; 1 on error
1460  *
1461  * <pre>
1462  * Notes:
1463  *      (1) The border region is defined to be the region in the
1464  *          image within a specific distance of each edge.  Here, we
1465  *          allow the pixels within a specified distance of each
1466  *          edge to be set independently.  This sets the pixels
1467  *          in the border region to the given input value.
1468  *      (2) For efficiency, use pixSetOrClearBorder() if
1469  *          you're setting the border to either black or white.
1470  *      (3) If d != 32, the input value should be masked off
1471  *          to the appropriate number of least significant bits.
1472  *      (4) The code is easily generalized for 2 or 4 bpp.
1473  * </pre>
1474  */
1475 l_int32
pixSetBorderVal(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot,l_uint32 val)1476 pixSetBorderVal(PIX      *pixs,
1477                 l_int32   left,
1478                 l_int32   right,
1479                 l_int32   top,
1480                 l_int32   bot,
1481                 l_uint32  val)
1482 {
1483 l_int32    w, h, d, wpls, i, j, bstart, rstart;
1484 l_uint32  *datas, *lines;
1485 
1486     PROCNAME("pixSetBorderVal");
1487 
1488     if (!pixs)
1489         return ERROR_INT("pixs not defined", procName, 1);
1490     pixGetDimensions(pixs, &w, &h, &d);
1491     if (d != 8 && d != 16 && d != 32)
1492         return ERROR_INT("depth must be 8, 16 or 32 bpp", procName, 1);
1493 
1494     datas = pixGetData(pixs);
1495     wpls = pixGetWpl(pixs);
1496     if (d == 8) {
1497         val &= 0xff;
1498         for (i = 0; i < top; i++) {
1499             lines = datas + i * wpls;
1500             for (j = 0; j < w; j++)
1501                 SET_DATA_BYTE(lines, j, val);
1502         }
1503         rstart = w - right;
1504         bstart = h - bot;
1505         for (i = top; i < bstart; i++) {
1506             lines = datas + i * wpls;
1507             for (j = 0; j < left; j++)
1508                 SET_DATA_BYTE(lines, j, val);
1509             for (j = rstart; j < w; j++)
1510                 SET_DATA_BYTE(lines, j, val);
1511         }
1512         for (i = bstart; i < h; i++) {
1513             lines = datas + i * wpls;
1514             for (j = 0; j < w; j++)
1515                 SET_DATA_BYTE(lines, j, val);
1516         }
1517     } else if (d == 16) {
1518         val &= 0xffff;
1519         for (i = 0; i < top; i++) {
1520             lines = datas + i * wpls;
1521             for (j = 0; j < w; j++)
1522                 SET_DATA_TWO_BYTES(lines, j, val);
1523         }
1524         rstart = w - right;
1525         bstart = h - bot;
1526         for (i = top; i < bstart; i++) {
1527             lines = datas + i * wpls;
1528             for (j = 0; j < left; j++)
1529                 SET_DATA_TWO_BYTES(lines, j, val);
1530             for (j = rstart; j < w; j++)
1531                 SET_DATA_TWO_BYTES(lines, j, val);
1532         }
1533         for (i = bstart; i < h; i++) {
1534             lines = datas + i * wpls;
1535             for (j = 0; j < w; j++)
1536                 SET_DATA_TWO_BYTES(lines, j, val);
1537         }
1538     } else {   /* d == 32 */
1539         for (i = 0; i < top; i++) {
1540             lines = datas + i * wpls;
1541             for (j = 0; j < w; j++)
1542                 *(lines + j) = val;
1543         }
1544         rstart = w - right;
1545         bstart = h - bot;
1546         for (i = top; i < bstart; i++) {
1547             lines = datas + i * wpls;
1548             for (j = 0; j < left; j++)
1549                 *(lines + j) = val;
1550             for (j = rstart; j < w; j++)
1551                 *(lines + j) = val;
1552         }
1553         for (i = bstart; i < h; i++) {
1554             lines = datas + i * wpls;
1555             for (j = 0; j < w; j++)
1556                 *(lines + j) = val;
1557         }
1558     }
1559 
1560     return 0;
1561 }
1562 
1563 
1564 /*!
1565  * \brief   pixSetBorderRingVal()
1566  *
1567  * \param[in]    pixs any depth; cmap OK
1568  * \param[in]    dist distance from outside; must be > 0; first ring is 1
1569  * \param[in]    val value to set at each border pixel
1570  * \return  0 if OK; 1 on error
1571  *
1572  * <pre>
1573  * Notes:
1574  *      (1) The rings are single-pixel-wide rectangular sets of
1575  *          pixels at a given distance from the edge of the pix.
1576  *          This sets all pixels in a given ring to a value.
1577  * </pre>
1578  */
1579 l_int32
pixSetBorderRingVal(PIX * pixs,l_int32 dist,l_uint32 val)1580 pixSetBorderRingVal(PIX      *pixs,
1581                     l_int32   dist,
1582                     l_uint32  val)
1583 {
1584 l_int32  w, h, d, i, j, xend, yend;
1585 
1586     PROCNAME("pixSetBorderRingVal");
1587 
1588     if (!pixs)
1589         return ERROR_INT("pixs not defined", procName, 1);
1590     if (dist < 1)
1591         return ERROR_INT("dist must be > 0", procName, 1);
1592     pixGetDimensions(pixs, &w, &h, &d);
1593     if (w < 2 * dist + 1 || h < 2 * dist + 1)
1594         return ERROR_INT("ring doesn't exist", procName, 1);
1595     if (d < 32 && (val >= (1 << d)))
1596         return ERROR_INT("invalid pixel value", procName, 1);
1597 
1598     xend = w - dist;
1599     yend = h - dist;
1600     for (j = dist - 1; j <= xend; j++)
1601         pixSetPixel(pixs, j, dist - 1, val);
1602     for (j = dist - 1; j <= xend; j++)
1603         pixSetPixel(pixs, j, yend, val);
1604     for (i = dist - 1; i <= yend; i++)
1605         pixSetPixel(pixs, dist - 1, i, val);
1606     for (i = dist - 1; i <= yend; i++)
1607         pixSetPixel(pixs, xend, i, val);
1608 
1609     return 0;
1610 }
1611 
1612 
1613 /*!
1614  * \brief   pixSetMirroredBorder()
1615  *
1616  * \param[in]    pixs all depths; colormap ok
1617  * \param[in]    left, right, top, bot number of pixels to set
1618  * \return  0 if OK, 1 on error
1619  *
1620  * <pre>
1621  * Notes:
1622  *      (1) This applies what is effectively mirror boundary conditions
1623  *          to a border region in the image.  It is in-place.
1624  *      (2) This is useful for setting pixels near the border to a
1625  *          value representative of the near pixels to the interior.
1626  *      (3) The general pixRasterop() is used for an in-place operation here
1627  *          because there is no overlap between the src and dest rectangles.
1628  * </pre>
1629  */
1630 l_int32
pixSetMirroredBorder(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot)1631 pixSetMirroredBorder(PIX     *pixs,
1632                      l_int32  left,
1633                      l_int32  right,
1634                      l_int32  top,
1635                      l_int32  bot)
1636 {
1637 l_int32  i, j, w, h;
1638 
1639     PROCNAME("pixSetMirroredBorder");
1640 
1641     if (!pixs)
1642         return ERROR_INT("pixs not defined", procName, 1);
1643 
1644     pixGetDimensions(pixs, &w, &h, NULL);
1645     for (j = 0; j < left; j++)
1646         pixRasterop(pixs, left - 1 - j, top, 1, h - top - bot, PIX_SRC,
1647                     pixs, left + j, top);
1648     for (j = 0; j < right; j++)
1649         pixRasterop(pixs, w - right + j, top, 1, h - top - bot, PIX_SRC,
1650                     pixs, w - right - 1 - j, top);
1651     for (i = 0; i < top; i++)
1652         pixRasterop(pixs, 0, top - 1 - i, w, 1, PIX_SRC,
1653                     pixs, 0, top + i);
1654     for (i = 0; i < bot; i++)
1655         pixRasterop(pixs, 0, h - bot + i, w, 1, PIX_SRC,
1656                     pixs, 0, h - bot - 1 - i);
1657 
1658     return 0;
1659 }
1660 
1661 
1662 /*!
1663  * \brief   pixCopyBorder()
1664  *
1665  * \param[in]    pixd all depths; colormap ok; can be NULL
1666  * \param[in]    pixs same depth and size as pixd
1667  * \param[in]    left, right, top, bot number of pixels to copy
1668  * \return  pixd, or NULL on error if pixd is not defined
1669  *
1670  * <pre>
1671  * Notes:
1672  *      (1) pixd can be null, but otherwise it must be the same size
1673  *          and depth as pixs.  Always returns pixd.
1674  *      (2) This is useful in situations where by setting a few border
1675  *          pixels we can avoid having to copy all pixels in pixs into
1676  *          pixd as an initialization step for some operation.
1677  *          Nevertheless, for safety, if making a new pixd, all the
1678  *          non-border pixels are initialized to 0.
1679  * </pre>
1680  */
1681 PIX *
pixCopyBorder(PIX * pixd,PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot)1682 pixCopyBorder(PIX     *pixd,
1683               PIX     *pixs,
1684               l_int32  left,
1685               l_int32  right,
1686               l_int32  top,
1687               l_int32  bot)
1688 {
1689 l_int32  w, h;
1690 
1691     PROCNAME("pixCopyBorder");
1692 
1693     if (!pixs)
1694         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
1695 
1696     if (pixd) {
1697         if (pixd == pixs) {
1698             L_WARNING("same: nothing to do\n", procName);
1699             return pixd;
1700         } else if (!pixSizesEqual(pixs, pixd)) {
1701             return (PIX *)ERROR_PTR("pixs and pixd sizes differ",
1702                                     procName, pixd);
1703         }
1704     } else {
1705         if ((pixd = pixCreateTemplate(pixs)) == NULL)
1706             return (PIX *)ERROR_PTR("pixd not made", procName, pixd);
1707     }
1708 
1709     pixGetDimensions(pixs, &w, &h, NULL);
1710     pixRasterop(pixd, 0, 0, left, h, PIX_SRC, pixs, 0, 0);
1711     pixRasterop(pixd, w - right, 0, right, h, PIX_SRC, pixs, w - right, 0);
1712     pixRasterop(pixd, 0, 0, w, top, PIX_SRC, pixs, 0, 0);
1713     pixRasterop(pixd, 0, h - bot, w, bot, PIX_SRC, pixs, 0, h - bot);
1714     return pixd;
1715 }
1716 
1717 
1718 
1719 /*-------------------------------------------------------------*
1720  *                     Add and remove border                   *
1721  *-------------------------------------------------------------*/
1722 /*!
1723  * \brief   pixAddBorder()
1724  *
1725  * \param[in]    pixs all depths; colormap ok
1726  * \param[in]    npix number of pixels to be added to each side
1727  * \param[in]    val  value of added border pixels
1728  * \return  pixd with the added exterior pixels, or NULL on error
1729  *
1730  * <pre>
1731  * Notes:
1732  *      (1) See pixGetBlackOrWhiteVal() for values of black and white pixels.
1733  * </pre>
1734  */
1735 PIX *
pixAddBorder(PIX * pixs,l_int32 npix,l_uint32 val)1736 pixAddBorder(PIX      *pixs,
1737              l_int32   npix,
1738              l_uint32  val)
1739 {
1740     PROCNAME("pixAddBorder");
1741 
1742     if (!pixs)
1743         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1744     if (npix == 0)
1745         return pixClone(pixs);
1746     return pixAddBorderGeneral(pixs, npix, npix, npix, npix, val);
1747 }
1748 
1749 
1750 /*!
1751  * \brief   pixAddBlackOrWhiteBorder()
1752  *
1753  * \param[in]    pixs all depths; colormap ok
1754  * \param[in]    left, right, top, bot  number of pixels added
1755  * \param[in]    op L_GET_BLACK_VAL, L_GET_WHITE_VAL
1756  * \return  pixd with the added exterior pixels, or NULL on error
1757  *
1758  * <pre>
1759  * Notes:
1760  *      (1) See pixGetBlackOrWhiteVal() for possible side effect (adding
1761  *          a color to a colormap).
1762  *      (2) The only complication is that pixs may have a colormap.
1763  *          There are two ways to add the black or white border:
1764  *          (a) As done here (simplest, most efficient)
1765  *          (b) l_int32 ws, hs, d;
1766  *              pixGetDimensions(pixs, &ws, &hs, &d);
1767  *              Pix *pixd = pixCreate(ws + left + right, hs + top + bot, d);
1768  *              PixColormap *cmap = pixGetColormap(pixs);
1769  *              if (cmap != NULL)
1770  *                  pixSetColormap(pixd, pixcmapCopy(cmap));
1771  *              pixSetBlackOrWhite(pixd, L_SET_WHITE);  // uses cmap
1772  *              pixRasterop(pixd, left, top, ws, hs, PIX_SET, pixs, 0, 0);
1773  * </pre>
1774  */
1775 PIX *
pixAddBlackOrWhiteBorder(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot,l_int32 op)1776 pixAddBlackOrWhiteBorder(PIX     *pixs,
1777                          l_int32  left,
1778                          l_int32  right,
1779                          l_int32  top,
1780                          l_int32  bot,
1781                          l_int32  op)
1782 {
1783 l_uint32  val;
1784 
1785     PROCNAME("pixAddBlackOrWhiteBorder");
1786 
1787     if (!pixs)
1788         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1789     if (op != L_GET_BLACK_VAL && op != L_GET_WHITE_VAL)
1790         return (PIX *)ERROR_PTR("invalid op", procName, NULL);
1791 
1792     pixGetBlackOrWhiteVal(pixs, op, &val);
1793     return pixAddBorderGeneral(pixs, left, right, top, bot, val);
1794 }
1795 
1796 
1797 /*!
1798  * \brief   pixAddBorderGeneral()
1799  *
1800  * \param[in]    pixs all depths; colormap ok
1801  * \param[in]    left, right, top, bot  number of pixels added
1802  * \param[in]    val   value of added border pixels
1803  * \return  pixd with the added exterior pixels, or NULL on error
1804  *
1805  * <pre>
1806  * Notes:
1807  *      (1) For binary images:
1808  *             white:  val = 0
1809  *             black:  val = 1
1810  *          For grayscale images:
1811  *             white:  val = 2 ** d - 1
1812  *             black:  val = 0
1813  *          For rgb color images:
1814  *             white:  val = 0xffffff00
1815  *             black:  val = 0
1816  *          For colormapped images, set val to the appropriate colormap index.
1817  *      (2) If the added border is either black or white, you can use
1818  *             pixAddBlackOrWhiteBorder()
1819  *          The black and white values for all images can be found with
1820  *             pixGetBlackOrWhiteVal()
1821  *          which, if pixs is cmapped, may add an entry to the colormap.
1822  *          Alternatively, if pixs has a colormap, you can find the index
1823  *          of the pixel whose intensity is closest to white or black:
1824  *             white: pixcmapGetRankIntensity(cmap, 1.0, &index);
1825  *             black: pixcmapGetRankIntensity(cmap, 0.0, &index);
1826  *          and use that for val.
1827  * </pre>
1828  */
1829 PIX *
pixAddBorderGeneral(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot,l_uint32 val)1830 pixAddBorderGeneral(PIX      *pixs,
1831                     l_int32   left,
1832                     l_int32   right,
1833                     l_int32   top,
1834                     l_int32   bot,
1835                     l_uint32  val)
1836 {
1837 l_int32  ws, hs, wd, hd, d, maxval, op;
1838 PIX     *pixd;
1839 
1840     PROCNAME("pixAddBorderGeneral");
1841 
1842     if (!pixs)
1843         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1844     if (left < 0 || right < 0 || top < 0 || bot < 0)
1845         return (PIX *)ERROR_PTR("negative border added!", procName, NULL);
1846 
1847     pixGetDimensions(pixs, &ws, &hs, &d);
1848     wd = ws + left + right;
1849     hd = hs + top + bot;
1850     if ((pixd = pixCreateNoInit(wd, hd, d)) == NULL)
1851         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1852     pixCopyResolution(pixd, pixs);
1853     pixCopyColormap(pixd, pixs);
1854 
1855         /* Set the new border pixels */
1856     maxval = (d == 32) ? 0xffffff00 : (1 << d) - 1;
1857     op = UNDEF;
1858     if (val == 0)
1859         op = PIX_CLR;
1860     else if (val >= maxval)
1861         op = PIX_SET;
1862     if (op == UNDEF) {
1863         pixSetAllArbitrary(pixd, val);
1864     } else {  /* just set or clear the border pixels */
1865         pixRasterop(pixd, 0, 0, left, hd, op, NULL, 0, 0);
1866         pixRasterop(pixd, wd - right, 0, right, hd, op, NULL, 0, 0);
1867         pixRasterop(pixd, 0, 0, wd, top, op, NULL, 0, 0);
1868         pixRasterop(pixd, 0, hd - bot, wd, bot, op, NULL, 0, 0);
1869     }
1870 
1871         /* Copy pixs into the interior */
1872     pixRasterop(pixd, left, top, ws, hs, PIX_SRC, pixs, 0, 0);
1873     return pixd;
1874 }
1875 
1876 
1877 /*!
1878  * \brief   pixRemoveBorder()
1879  *
1880  * \param[in]    pixs all depths; colormap ok
1881  * \param[in]    npix number to be removed from each of the 4 sides
1882  * \return  pixd with pixels removed around border, or NULL on error
1883  */
1884 PIX *
pixRemoveBorder(PIX * pixs,l_int32 npix)1885 pixRemoveBorder(PIX     *pixs,
1886                 l_int32  npix)
1887 {
1888     PROCNAME("pixRemoveBorder");
1889 
1890     if (!pixs)
1891         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1892     if (npix == 0)
1893         return pixClone(pixs);
1894     return pixRemoveBorderGeneral(pixs, npix, npix, npix, npix);
1895 }
1896 
1897 
1898 /*!
1899  * \brief   pixRemoveBorderGeneral()
1900  *
1901  * \param[in]    pixs all depths; colormap ok
1902  * \param[in]    left, right, top, bot  number of pixels removed
1903  * \return  pixd with pixels removed around border, or NULL on error
1904  */
1905 PIX *
pixRemoveBorderGeneral(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot)1906 pixRemoveBorderGeneral(PIX     *pixs,
1907                        l_int32  left,
1908                        l_int32  right,
1909                        l_int32  top,
1910                        l_int32  bot)
1911 {
1912 l_int32  ws, hs, wd, hd, d;
1913 PIX     *pixd;
1914 
1915     PROCNAME("pixRemoveBorderGeneral");
1916 
1917     if (!pixs)
1918         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1919     if (left < 0 || right < 0 || top < 0 || bot < 0)
1920         return (PIX *)ERROR_PTR("negative border removed!", procName, NULL);
1921 
1922     pixGetDimensions(pixs, &ws, &hs, &d);
1923     wd = ws - left - right;
1924     hd = hs - top - bot;
1925     if (wd <= 0)
1926         return (PIX *)ERROR_PTR("width must be > 0", procName, NULL);
1927     if (hd <= 0)
1928         return (PIX *)ERROR_PTR("height must be > 0", procName, NULL);
1929     if ((pixd = pixCreateNoInit(wd, hd, d)) == NULL)
1930         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1931     pixCopyResolution(pixd, pixs);
1932     pixCopySpp(pixd, pixs);
1933     pixCopyColormap(pixd, pixs);
1934 
1935     pixRasterop(pixd, 0, 0, wd, hd, PIX_SRC, pixs, left, top);
1936     if (pixGetDepth(pixs) == 32 && pixGetSpp(pixs) == 4)
1937         pixShiftAndTransferAlpha(pixd, pixs, -left, -top);
1938     return pixd;
1939 }
1940 
1941 
1942 /*!
1943  * \brief   pixRemoveBorderToSize()
1944  *
1945  * \param[in]    pixs all depths; colormap ok
1946  * \param[in]    wd  target width; use 0 if only removing from height
1947  * \param[in]    hd  target height; use 0 if only removing from width
1948  * \return  pixd with pixels removed around border, or NULL on error
1949  *
1950  * <pre>
1951  * Notes:
1952  *      (1) Removes pixels as evenly as possible from the sides of the
1953  *          image, leaving the central part.
1954  *      (2) Returns clone if no pixels requested removed, or the target
1955  *          sizes are larger than the image.
1956  * </pre>
1957  */
1958 PIX *
pixRemoveBorderToSize(PIX * pixs,l_int32 wd,l_int32 hd)1959 pixRemoveBorderToSize(PIX     *pixs,
1960                       l_int32  wd,
1961                       l_int32  hd)
1962 {
1963 l_int32  w, h, top, bot, left, right, delta;
1964 
1965     PROCNAME("pixRemoveBorderToSize");
1966 
1967     if (!pixs)
1968         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1969 
1970     pixGetDimensions(pixs, &w, &h, NULL);
1971     if ((wd <= 0 || wd >= w) && (hd <= 0 || hd >= h))
1972         return pixClone(pixs);
1973 
1974     left = right = (w - wd) / 2;
1975     delta = w - 2 * left - wd;
1976     right += delta;
1977     top = bot = (h - hd) / 2;
1978     delta = h - hd - 2 * top;
1979     bot += delta;
1980     if (wd <= 0 || wd > w)
1981         left = right = 0;
1982     else if (hd <= 0 || hd > h)
1983         top = bot = 0;
1984 
1985     return pixRemoveBorderGeneral(pixs, left, right, top, bot);
1986 }
1987 
1988 
1989 /*!
1990  * \brief   pixAddMirroredBorder()
1991  *
1992  * \param[in]    pixs all depths; colormap ok
1993  * \param[in]    left, right, top, bot number of pixels added
1994  * \return  pixd, or NULL on error
1995  *
1996  * <pre>
1997  * Notes:
1998  *      (1) This applies what is effectively mirror boundary conditions.
1999  *          For the added border pixels in pixd, the pixels in pixs
2000  *          near the border are mirror-copied into the border region.
2001  *      (2) This is useful for avoiding special operations near
2002  *          boundaries when doing image processing operations
2003  *          such as rank filters and convolution.  In use, one first
2004  *          adds mirrored pixels to each side of the image.  The number
2005  *          of pixels added on each side is half the filter dimension.
2006  *          Then the image processing operations proceed over a
2007  *          region equal to the size of the original image, and
2008  *          write directly into a dest pix of the same size as pixs.
2009  *      (3) The general pixRasterop() is used for an in-place operation here
2010  *          because there is no overlap between the src and dest rectangles.
2011  * </pre>
2012  */
2013 PIX  *
pixAddMirroredBorder(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot)2014 pixAddMirroredBorder(PIX      *pixs,
2015                       l_int32  left,
2016                       l_int32  right,
2017                       l_int32  top,
2018                       l_int32  bot)
2019 {
2020 l_int32  i, j, w, h;
2021 PIX     *pixd;
2022 
2023     PROCNAME("pixAddMirroredBorder");
2024 
2025     if (!pixs)
2026         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2027     pixGetDimensions(pixs, &w, &h, NULL);
2028     if (left > w || right > w || top > h || bot > h)
2029         return (PIX *)ERROR_PTR("border too large", procName, NULL);
2030 
2031         /* Set pixels on left, right, top and bottom, in that order */
2032     pixd = pixAddBorderGeneral(pixs, left, right, top, bot, 0);
2033     for (j = 0; j < left; j++)
2034         pixRasterop(pixd, left - 1 - j, top, 1, h, PIX_SRC,
2035                     pixd, left + j, top);
2036     for (j = 0; j < right; j++)
2037         pixRasterop(pixd, left + w + j, top, 1, h, PIX_SRC,
2038                     pixd, left + w - 1 - j, top);
2039     for (i = 0; i < top; i++)
2040         pixRasterop(pixd, 0, top - 1 - i, left + w + right, 1, PIX_SRC,
2041                     pixd, 0, top + i);
2042     for (i = 0; i < bot; i++)
2043         pixRasterop(pixd, 0, top + h + i, left + w + right, 1, PIX_SRC,
2044                     pixd, 0, top + h - 1 - i);
2045 
2046     return pixd;
2047 }
2048 
2049 
2050 /*!
2051  * \brief   pixAddRepeatedBorder()
2052  *
2053  * \param[in]    pixs all depths; colormap ok
2054  * \param[in]    left, right, top, bot number of pixels added
2055  * \return  pixd, or NULL on error
2056  *
2057  * <pre>
2058  * Notes:
2059  *      (1) This applies a repeated border, as if the central part of
2060  *          the image is tiled over the plane.  So, for example, the
2061  *          pixels in the left border come from the right side of the image.
2062  *      (2) The general pixRasterop() is used for an in-place operation here
2063  *          because there is no overlap between the src and dest rectangles.
2064  * </pre>
2065  */
2066 PIX  *
pixAddRepeatedBorder(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot)2067 pixAddRepeatedBorder(PIX      *pixs,
2068                      l_int32  left,
2069                      l_int32  right,
2070                      l_int32  top,
2071                      l_int32  bot)
2072 {
2073 l_int32  w, h;
2074 PIX     *pixd;
2075 
2076     PROCNAME("pixAddRepeatedBorder");
2077 
2078     if (!pixs)
2079         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2080     pixGetDimensions(pixs, &w, &h, NULL);
2081     if (left > w || right > w || top > h || bot > h)
2082         return (PIX *)ERROR_PTR("border too large", procName, NULL);
2083 
2084     pixd = pixAddBorderGeneral(pixs, left, right, top, bot, 0);
2085 
2086         /* Set pixels on left, right, top and bottom, in that order */
2087     pixRasterop(pixd, 0, top, left, h, PIX_SRC, pixd, w, top);
2088     pixRasterop(pixd, left + w, top, right, h, PIX_SRC, pixd, left, top);
2089     pixRasterop(pixd, 0, 0, left + w + right, top, PIX_SRC, pixd, 0, h);
2090     pixRasterop(pixd, 0, top + h, left + w + right, bot, PIX_SRC, pixd, 0, top);
2091 
2092     return pixd;
2093 }
2094 
2095 
2096 /*!
2097  * \brief   pixAddMixedBorder()
2098  *
2099  * \param[in]    pixs all depths; colormap ok
2100  * \param[in]    left, right, top, bot number of pixels added
2101  * \return  pixd, or NULL on error
2102  *
2103  * <pre>
2104  * Notes:
2105  *      (1) This applies mirrored boundary conditions horizontally
2106  *          and repeated b.c. vertically.
2107  *      (2) It is specifically used for avoiding special operations
2108  *          near boundaries when convolving a hue-saturation histogram
2109  *          with a given window size.  The repeated b.c. are used
2110  *          vertically for hue, and the mirrored b.c. are used
2111  *          horizontally for saturation.  The number of pixels added
2112  *          on each side is approximately (but not quite) half the
2113  *          filter dimension.  The image processing operations can
2114  *          then proceed over a region equal to the size of the original
2115  *          image, and write directly into a dest pix of the same
2116  *          size as pixs.
2117  *      (3) The general pixRasterop() can be used for an in-place
2118  *          operation here because there is no overlap between the
2119  *          src and dest rectangles.
2120  * </pre>
2121  */
2122 PIX  *
pixAddMixedBorder(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot)2123 pixAddMixedBorder(PIX      *pixs,
2124                   l_int32  left,
2125                   l_int32  right,
2126                   l_int32  top,
2127                   l_int32  bot)
2128 {
2129 l_int32  j, w, h;
2130 PIX     *pixd;
2131 
2132     PROCNAME("pixAddMixedBorder");
2133 
2134     if (!pixs)
2135         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2136     pixGetDimensions(pixs, &w, &h, NULL);
2137     if (left > w || right > w || top > h || bot > h)
2138         return (PIX *)ERROR_PTR("border too large", procName, NULL);
2139 
2140         /* Set mirrored pixels on left and right;
2141          * then set repeated pixels on top and bottom. */
2142     pixd = pixAddBorderGeneral(pixs, left, right, top, bot, 0);
2143     for (j = 0; j < left; j++)
2144         pixRasterop(pixd, left - 1 - j, top, 1, h, PIX_SRC,
2145                     pixd, left + j, top);
2146     for (j = 0; j < right; j++)
2147         pixRasterop(pixd, left + w + j, top, 1, h, PIX_SRC,
2148                     pixd, left + w - 1 - j, top);
2149     pixRasterop(pixd, 0, 0, left + w + right, top, PIX_SRC, pixd, 0, h);
2150     pixRasterop(pixd, 0, top + h, left + w + right, bot, PIX_SRC, pixd, 0, top);
2151 
2152     return pixd;
2153 }
2154 
2155 
2156 /*!
2157  * \brief   pixAddContinuedBorder()
2158  *
2159  * \param[in]    pixs
2160  * \param[in]    left, right, top, bot pixels on each side to be added
2161  * \return  pixd, or NULL on error
2162  *
2163  * <pre>
2164  * Notes:
2165  *      (1) This adds pixels on each side whose values are equal to
2166  *          the value on the closest boundary pixel.
2167  * </pre>
2168  */
2169 PIX *
pixAddContinuedBorder(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot)2170 pixAddContinuedBorder(PIX     *pixs,
2171                       l_int32  left,
2172                       l_int32  right,
2173                       l_int32  top,
2174                       l_int32  bot)
2175 {
2176 l_int32  i, j, w, h;
2177 PIX     *pixd;
2178 
2179     PROCNAME("pixAddContinuedBorder");
2180 
2181     if (!pixs)
2182         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2183 
2184     pixd = pixAddBorderGeneral(pixs, left, right, top, bot, 0);
2185     pixGetDimensions(pixs, &w, &h, NULL);
2186     for (j = 0; j < left; j++)
2187         pixRasterop(pixd, j, top, 1, h, PIX_SRC, pixd, left, top);
2188     for (j = 0; j < right; j++)
2189         pixRasterop(pixd, left + w + j, top, 1, h,
2190                     PIX_SRC, pixd, left + w - 1, top);
2191     for (i = 0; i < top; i++)
2192         pixRasterop(pixd, 0, i, left + w + right, 1, PIX_SRC, pixd, 0, top);
2193     for (i = 0; i < bot; i++)
2194         pixRasterop(pixd, 0, top + h + i, left + w + right, 1,
2195                     PIX_SRC, pixd, 0, top + h - 1);
2196 
2197     return pixd;
2198 }
2199 
2200 
2201 /*-------------------------------------------------------------------*
2202  *                     Helper functions using alpha                  *
2203  *-------------------------------------------------------------------*/
2204 /*!
2205  * \brief   pixShiftAndTransferAlpha()
2206  *
2207  * \param[in]    pixd  32 bpp
2208  * \param[in]    pixs  32 bpp
2209  * \param[in]    shiftx, shifty
2210  * \return  0 if OK; 1 on error
2211  */
2212 l_int32
pixShiftAndTransferAlpha(PIX * pixd,PIX * pixs,l_float32 shiftx,l_float32 shifty)2213 pixShiftAndTransferAlpha(PIX       *pixd,
2214                          PIX       *pixs,
2215                          l_float32  shiftx,
2216                          l_float32  shifty)
2217 {
2218 l_int32  w, h;
2219 PIX     *pix1, *pix2;
2220 
2221     PROCNAME("pixShiftAndTransferAlpha");
2222 
2223     if (!pixs || !pixd)
2224         return ERROR_INT("pixs and pixd not both defined", procName, 1);
2225     if (pixGetDepth(pixs) != 32 || pixGetSpp(pixs) != 4)
2226         return ERROR_INT("pixs not 32 bpp and 4 spp", procName, 1);
2227     if (pixGetDepth(pixd) != 32)
2228         return ERROR_INT("pixd not 32 bpp", procName, 1);
2229 
2230     if (shiftx == 0 && shifty == 0) {
2231         pixCopyRGBComponent(pixd, pixs, L_ALPHA_CHANNEL);
2232         return 0;
2233     }
2234 
2235     pix1 = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL);
2236     pixGetDimensions(pixd, &w, &h, NULL);
2237     pix2 = pixCreate(w, h, 8);
2238     pixRasterop(pix2, 0, 0, w, h, PIX_SRC, pix1, -shiftx, -shifty);
2239     pixSetRGBComponent(pixd, pix2, L_ALPHA_CHANNEL);
2240     pixDestroy(&pix1);
2241     pixDestroy(&pix2);
2242     return 0;
2243 }
2244 
2245 
2246 /*!
2247  * \brief   pixDisplayLayersRGBA()
2248  *
2249  * \param[in]    pixs cmap or 32 bpp rgba
2250  * \param[in]    val 32 bit unsigned color to use as background
2251  * \param[in]    maxw max output image width; 0 for no scaling
2252  * \return  pixd showing various image views, or NULL on error
2253  *
2254  * <pre>
2255  * Notes:
2256  *      (1) Use %val == 0xffffff00 for white background.
2257  *      (2) Three views are given:
2258  *           ~ the image with a fully opaque alpha
2259  *           ~ the alpha layer
2260  *           ~ the image as it would appear with a white background.
2261  * </pre>
2262  */
2263 PIX *
pixDisplayLayersRGBA(PIX * pixs,l_uint32 val,l_int32 maxw)2264 pixDisplayLayersRGBA(PIX      *pixs,
2265                      l_uint32  val,
2266                      l_int32   maxw)
2267 {
2268 l_int32    w, width;
2269 l_float32  scalefact;
2270 PIX       *pix1, *pix2, *pixd;
2271 PIXA      *pixa;
2272 PIXCMAP   *cmap;
2273 
2274     PROCNAME("pixDisplayLayersRGBA");
2275 
2276     if (!pixs)
2277         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2278     cmap = pixGetColormap(pixs);
2279     if (!cmap && !(pixGetDepth(pixs) == 32 && pixGetSpp(pixs) == 4))
2280         return (PIX *)ERROR_PTR("pixs not cmap and not 32 bpp rgba",
2281                                 procName, NULL);
2282     if ((w = pixGetWidth(pixs)) == 0)
2283         return (PIX *)ERROR_PTR("pixs width 0 !!", procName, NULL);
2284 
2285     if (cmap)
2286         pix1 = pixRemoveColormap(pixs, REMOVE_CMAP_WITH_ALPHA);
2287     else
2288         pix1 = pixCopy(NULL, pixs);
2289 
2290         /* Scale if necessary so the output width is not larger than maxw */
2291     scalefact = (maxw == 0) ? 1.0 : L_MIN(1.0, (l_float32)(maxw) / w);
2292     width = (l_int32)(scalefact * w);
2293 
2294     pixa = pixaCreate(3);
2295     pixSetSpp(pix1, 3);
2296     pixaAddPix(pixa, pix1, L_INSERT);  /* show the rgb values */
2297     pix1 = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL);
2298     pix2 = pixConvertTo32(pix1);
2299     pixaAddPix(pixa, pix2, L_INSERT);  /* show the alpha channel */
2300     pixDestroy(&pix1);
2301     pix1 = pixAlphaBlendUniform(pixs, (val & 0xffffff00));
2302     pixaAddPix(pixa, pix1, L_INSERT);  /* with %val color bg showing */
2303     pixd = pixaDisplayTiledInRows(pixa, 32, width, scalefact, 0, 25, 2);
2304     pixaDestroy(&pixa);
2305     return pixd;
2306 }
2307 
2308 
2309 /*-------------------------------------------------------------*
2310  *                Color sample setting and extraction          *
2311  *-------------------------------------------------------------*/
2312 /*!
2313  * \brief   pixCreateRGBImage()
2314  *
2315  * \param[in]    pixr 8 bpp red pix
2316  * \param[in]    pixg 8 bpp green pix
2317  * \param[in]    pixb 8 bpp blue pix
2318  * \return  32 bpp pix, interleaved with 4 samples/pixel,
2319  *              or NULL on error
2320  *
2321  * <pre>
2322  * Notes:
2323  *      (1) the 4th byte, sometimes called the "alpha channel",
2324  *          and which is often used for blending between different
2325  *          images, is left with 0 value.
2326  *      (2) see Note (4) in pix.h for details on storage of
2327  *          8-bit samples within each 32-bit word.
2328  *      (3) This implementation, setting the r, g and b components
2329  *          sequentially, is much faster than setting them in parallel
2330  *          by constructing an RGB dest pixel and writing it to dest.
2331  *          The reason is there are many more cache misses when reading
2332  *          from 3 input images simultaneously.
2333  * </pre>
2334  */
2335 PIX *
pixCreateRGBImage(PIX * pixr,PIX * pixg,PIX * pixb)2336 pixCreateRGBImage(PIX  *pixr,
2337                   PIX  *pixg,
2338                   PIX  *pixb)
2339 {
2340 l_int32  wr, wg, wb, hr, hg, hb, dr, dg, db;
2341 PIX     *pixd;
2342 
2343     PROCNAME("pixCreateRGBImage");
2344 
2345     if (!pixr)
2346         return (PIX *)ERROR_PTR("pixr not defined", procName, NULL);
2347     if (!pixg)
2348         return (PIX *)ERROR_PTR("pixg not defined", procName, NULL);
2349     if (!pixb)
2350         return (PIX *)ERROR_PTR("pixb not defined", procName, NULL);
2351     pixGetDimensions(pixr, &wr, &hr, &dr);
2352     pixGetDimensions(pixg, &wg, &hg, &dg);
2353     pixGetDimensions(pixb, &wb, &hb, &db);
2354     if (dr != 8 || dg != 8 || db != 8)
2355         return (PIX *)ERROR_PTR("input pix not all 8 bpp", procName, NULL);
2356     if (wr != wg || wr != wb)
2357         return (PIX *)ERROR_PTR("widths not the same", procName, NULL);
2358     if (hr != hg || hr != hb)
2359         return (PIX *)ERROR_PTR("heights not the same", procName, NULL);
2360 
2361     if ((pixd = pixCreate(wr, hr, 32)) == NULL)
2362         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2363     pixCopyResolution(pixd, pixr);
2364     pixSetRGBComponent(pixd, pixr, COLOR_RED);
2365     pixSetRGBComponent(pixd, pixg, COLOR_GREEN);
2366     pixSetRGBComponent(pixd, pixb, COLOR_BLUE);
2367 
2368     return pixd;
2369 }
2370 
2371 
2372 /*!
2373  * \brief   pixGetRGBComponent()
2374  *
2375  * \param[in]    pixs 32 bpp, or colormapped
2376  * \param[in]    comp one of {COLOR_RED, COLOR_GREEN, COLOR_BLUE,
2377  *                    L_ALPHA_CHANNEL}
2378  * \return  pixd the selected 8 bpp component image of the
2379  *                    input 32 bpp image or NULL on error
2380  *
2381  * <pre>
2382  * Notes:
2383  *      (1) Three calls to this function generate the r, g and b 8 bpp
2384  *          component images.  This is much faster than generating the
2385  *          three images in parallel, by extracting a src pixel and setting
2386  *          the pixels of each component image from it.  The reason is
2387  *          there are many more cache misses when writing to three
2388  *          output images simultaneously.
2389  * </pre>
2390  */
2391 PIX *
pixGetRGBComponent(PIX * pixs,l_int32 comp)2392 pixGetRGBComponent(PIX     *pixs,
2393                    l_int32  comp)
2394 {
2395 l_int32    i, j, w, h, wpls, wpld, val;
2396 l_uint32  *lines, *lined;
2397 l_uint32  *datas, *datad;
2398 PIX       *pixd;
2399 
2400     PROCNAME("pixGetRGBComponent");
2401 
2402     if (!pixs)
2403         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2404     if (pixGetColormap(pixs))
2405         return pixGetRGBComponentCmap(pixs, comp);
2406     if (pixGetDepth(pixs) != 32)
2407         return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
2408     if (comp != COLOR_RED && comp != COLOR_GREEN &&
2409         comp != COLOR_BLUE && comp != L_ALPHA_CHANNEL)
2410         return (PIX *)ERROR_PTR("invalid comp", procName, NULL);
2411 
2412     pixGetDimensions(pixs, &w, &h, NULL);
2413     if ((pixd = pixCreate(w, h, 8)) == NULL)
2414         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2415     pixCopyResolution(pixd, pixs);
2416     wpls = pixGetWpl(pixs);
2417     wpld = pixGetWpl(pixd);
2418     datas = pixGetData(pixs);
2419     datad = pixGetData(pixd);
2420     for (i = 0; i < h; i++) {
2421         lines = datas + i * wpls;
2422         lined = datad + i * wpld;
2423         for (j = 0; j < w; j++) {
2424             val = GET_DATA_BYTE(lines + j, comp);
2425             SET_DATA_BYTE(lined, j, val);
2426         }
2427     }
2428 
2429     return pixd;
2430 }
2431 
2432 
2433 /*!
2434  * \brief   pixSetRGBComponent()
2435  *
2436  * \param[in]    pixd  32 bpp
2437  * \param[in]    pixs  8 bpp
2438  * \param[in]    comp  one of the set: {COLOR_RED, COLOR_GREEN,
2439  *                                      COLOR_BLUE, L_ALPHA_CHANNEL}
2440  * \return  0 if OK; 1 on error
2441  *
2442  * <pre>
2443  * Notes:
2444  *      (1) This places the 8 bpp pixel in pixs into the
2445  *          specified component (properly interleaved) in pixd,
2446  *      (2) The two images are registered to the UL corner; the sizes
2447  *          need not be the same, but a warning is issued if they differ.
2448  * </pre>
2449  */
2450 l_int32
pixSetRGBComponent(PIX * pixd,PIX * pixs,l_int32 comp)2451 pixSetRGBComponent(PIX     *pixd,
2452                    PIX     *pixs,
2453                    l_int32  comp)
2454 {
2455 l_uint8    srcbyte;
2456 l_int32    i, j, w, h, ws, hs, wd, hd;
2457 l_int32    wpls, wpld;
2458 l_uint32  *lines, *lined;
2459 l_uint32  *datas, *datad;
2460 
2461     PROCNAME("pixSetRGBComponent");
2462 
2463     if (!pixd)
2464         return ERROR_INT("pixd not defined", procName, 1);
2465     if (!pixs)
2466         return ERROR_INT("pixs not defined", procName, 1);
2467     if (pixGetDepth(pixd) != 32)
2468         return ERROR_INT("pixd not 32 bpp", procName, 1);
2469     if (pixGetDepth(pixs) != 8)
2470         return ERROR_INT("pixs not 8 bpp", procName, 1);
2471     if (comp != COLOR_RED && comp != COLOR_GREEN &&
2472         comp != COLOR_BLUE && comp != L_ALPHA_CHANNEL)
2473         return ERROR_INT("invalid comp", procName, 1);
2474     pixGetDimensions(pixs, &ws, &hs, NULL);
2475     pixGetDimensions(pixd, &wd, &hd, NULL);
2476     if (ws != wd || hs != hd)
2477         L_WARNING("images sizes not equal\n", procName);
2478     w = L_MIN(ws, wd);
2479     h = L_MIN(hs, hd);
2480     if (comp == L_ALPHA_CHANNEL)
2481         pixSetSpp(pixd, 4);
2482     datas = pixGetData(pixs);
2483     datad = pixGetData(pixd);
2484     wpls = pixGetWpl(pixs);
2485     wpld = pixGetWpl(pixd);
2486     for (i = 0; i < h; i++) {
2487         lines = datas + i * wpls;
2488         lined = datad + i * wpld;
2489         for (j = 0; j < w; j++) {
2490             srcbyte = GET_DATA_BYTE(lines, j);
2491             SET_DATA_BYTE(lined + j, comp, srcbyte);
2492         }
2493     }
2494 
2495     return 0;
2496 }
2497 
2498 
2499 /*!
2500  * \brief   pixGetRGBComponentCmap()
2501  *
2502  * \param[in]    pixs  colormapped
2503  * \param[in]    comp  one of the set: {COLOR_RED, COLOR_GREEN, COLOR_BLUE}
2504  * \return  pixd  the selected 8 bpp component image of the
2505  *                     input cmapped image, or NULL on error
2506  *
2507  * <pre>
2508  * Notes:
2509  *      (1) In leptonica, we do not support alpha in colormaps.
2510  * </pre>
2511  */
2512 PIX *
pixGetRGBComponentCmap(PIX * pixs,l_int32 comp)2513 pixGetRGBComponentCmap(PIX     *pixs,
2514                        l_int32  comp)
2515 {
2516 l_int32     i, j, w, h, val, index;
2517 l_int32     wplc, wpld;
2518 l_uint32   *linec, *lined;
2519 l_uint32   *datac, *datad;
2520 PIX        *pixc, *pixd;
2521 PIXCMAP    *cmap;
2522 RGBA_QUAD  *cta;
2523 
2524     PROCNAME("pixGetRGBComponentCmap");
2525 
2526     if (!pixs)
2527         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2528     if ((cmap = pixGetColormap(pixs)) == NULL)
2529         return (PIX *)ERROR_PTR("pixs not cmapped", procName, NULL);
2530     if (comp == L_ALPHA_CHANNEL)
2531         return (PIX *)ERROR_PTR("alpha in cmaps not supported", procName, NULL);
2532     if (comp != COLOR_RED && comp != COLOR_GREEN && comp != COLOR_BLUE)
2533         return (PIX *)ERROR_PTR("invalid comp", procName, NULL);
2534 
2535         /* If not 8 bpp, make a cmapped 8 bpp pix */
2536     if (pixGetDepth(pixs) == 8)
2537         pixc = pixClone(pixs);
2538     else
2539         pixc = pixConvertTo8(pixs, TRUE);
2540 
2541     pixGetDimensions(pixs, &w, &h, NULL);
2542     if ((pixd = pixCreateNoInit(w, h, 8)) == NULL) {
2543         pixDestroy(&pixc);
2544         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2545     }
2546     pixCopyResolution(pixd, pixs);
2547     wplc = pixGetWpl(pixc);
2548     wpld = pixGetWpl(pixd);
2549     datac = pixGetData(pixc);
2550     datad = pixGetData(pixd);
2551     cta = (RGBA_QUAD *)cmap->array;
2552 
2553     for (i = 0; i < h; i++) {
2554         linec = datac + i * wplc;
2555         lined = datad + i * wpld;
2556         if (comp == COLOR_RED) {
2557             for (j = 0; j < w; j++) {
2558                 index = GET_DATA_BYTE(linec, j);
2559                 val = cta[index].red;
2560                 SET_DATA_BYTE(lined, j, val);
2561             }
2562         } else if (comp == COLOR_GREEN) {
2563             for (j = 0; j < w; j++) {
2564                 index = GET_DATA_BYTE(linec, j);
2565                 val = cta[index].green;
2566                 SET_DATA_BYTE(lined, j, val);
2567             }
2568         } else if (comp == COLOR_BLUE) {
2569             for (j = 0; j < w; j++) {
2570                 index = GET_DATA_BYTE(linec, j);
2571                 val = cta[index].blue;
2572                 SET_DATA_BYTE(lined, j, val);
2573             }
2574         }
2575     }
2576 
2577     pixDestroy(&pixc);
2578     return pixd;
2579 }
2580 
2581 
2582 /*!
2583  * \brief   pixCopyRGBComponent()
2584  *
2585  * \param[in]    pixd 32 bpp
2586  * \param[in]    pixs 32 bpp
2587  * \param[in]    comp one of the set: {COLOR_RED, COLOR_GREEN,
2588  *                                     COLOR_BLUE, L_ALPHA_CHANNEL}
2589  * \return  0 if OK; 1 on error
2590  *
2591  * <pre>
2592  * Notes:
2593  *      (1) The two images are registered to the UL corner.  The sizes
2594  *          are usually the same, and a warning is issued if they differ.
2595  * </pre>
2596  */
2597 l_int32
pixCopyRGBComponent(PIX * pixd,PIX * pixs,l_int32 comp)2598 pixCopyRGBComponent(PIX     *pixd,
2599                     PIX     *pixs,
2600                     l_int32  comp)
2601 {
2602 l_int32    i, j, w, h, ws, hs, wd, hd, val;
2603 l_int32    wpls, wpld;
2604 l_uint32  *lines, *lined;
2605 l_uint32  *datas, *datad;
2606 
2607     PROCNAME("pixCopyRGBComponent");
2608 
2609     if (!pixd && pixGetDepth(pixd) != 32)
2610         return ERROR_INT("pixd not defined or not 32 bpp", procName, 1);
2611     if (!pixs && pixGetDepth(pixs) != 32)
2612         return ERROR_INT("pixs not defined or not 32 bpp", procName, 1);
2613     if (comp != COLOR_RED && comp != COLOR_GREEN &&
2614         comp != COLOR_BLUE && comp != L_ALPHA_CHANNEL)
2615         return ERROR_INT("invalid component", procName, 1);
2616     pixGetDimensions(pixs, &ws, &hs, NULL);
2617     pixGetDimensions(pixd, &wd, &hd, NULL);
2618     if (ws != wd || hs != hd)
2619         L_WARNING("images sizes not equal\n", procName);
2620     w = L_MIN(ws, wd);
2621     h = L_MIN(hs, hd);
2622     if (comp == L_ALPHA_CHANNEL)
2623         pixSetSpp(pixd, 4);
2624     wpls = pixGetWpl(pixs);
2625     wpld = pixGetWpl(pixd);
2626     datas = pixGetData(pixs);
2627     datad = pixGetData(pixd);
2628     for (i = 0; i < h; i++) {
2629         lines = datas + i * wpls;
2630         lined = datad + i * wpld;
2631         for (j = 0; j < w; j++) {
2632             val = GET_DATA_BYTE(lines + j, comp);
2633             SET_DATA_BYTE(lined + j, comp, val);
2634         }
2635     }
2636     return 0;
2637 }
2638 
2639 
2640 /*!
2641  * \brief   composeRGBPixel()
2642  *
2643  * \param[in]    rval, gval, bval
2644  * \param[out]   ppixel  32-bit pixel
2645  * \return  0 if OK; 1 on error
2646  *
2647  * <pre>
2648  * Notes:
2649  *      (1) All channels are 8 bits: the input values must be between
2650  *          0 and 255.  For speed, this is not enforced by masking
2651  *          with 0xff before shifting.
2652  *      (2) A slower implementation uses macros:
2653  *            SET_DATA_BYTE(ppixel, COLOR_RED, rval);
2654  *            SET_DATA_BYTE(ppixel, COLOR_GREEN, gval);
2655  *            SET_DATA_BYTE(ppixel, COLOR_BLUE, bval);
2656  * </pre>
2657  */
2658 l_int32
composeRGBPixel(l_int32 rval,l_int32 gval,l_int32 bval,l_uint32 * ppixel)2659 composeRGBPixel(l_int32    rval,
2660                 l_int32    gval,
2661                 l_int32    bval,
2662                 l_uint32  *ppixel)
2663 {
2664     PROCNAME("composeRGBPixel");
2665 
2666     if (!ppixel)
2667         return ERROR_INT("&pixel not defined", procName, 1);
2668 
2669     *ppixel = (rval << L_RED_SHIFT) | (gval << L_GREEN_SHIFT) |
2670               (bval << L_BLUE_SHIFT);
2671     return 0;
2672 }
2673 
2674 
2675 /*!
2676  * \brief   composeRGBAPixel()
2677  *
2678  * \param[in]    rval, gval, bval, aval
2679  * \param[out]   ppixel  32-bit pixel
2680  * \return  0 if OK; 1 on error
2681  *
2682  * <pre>
2683  * Notes:
2684  *      (1) All channels are 8 bits: the input values must be between
2685  *          0 and 255.  For speed, this is not enforced by masking
2686  *          with 0xff before shifting.
2687  * </pre>
2688  */
2689 l_int32
composeRGBAPixel(l_int32 rval,l_int32 gval,l_int32 bval,l_int32 aval,l_uint32 * ppixel)2690 composeRGBAPixel(l_int32    rval,
2691                  l_int32    gval,
2692                  l_int32    bval,
2693                  l_int32    aval,
2694                  l_uint32  *ppixel)
2695 {
2696     PROCNAME("composeRGBAPixel");
2697 
2698     if (!ppixel)
2699         return ERROR_INT("&pixel not defined", procName, 1);
2700 
2701     *ppixel = (rval << L_RED_SHIFT) | (gval << L_GREEN_SHIFT) |
2702               (bval << L_BLUE_SHIFT) | aval;
2703     return 0;
2704 }
2705 
2706 
2707 /*!
2708  * \brief   extractRGBValues()
2709  *
2710  * \param[in]    pixel 32 bit
2711  * \param[out]   prval [optional] red component
2712  * \param[out]   pgval [optional] green component
2713  * \param[out]   pbval [optional] blue component
2714  * \return  void
2715  *
2716  * <pre>
2717  * Notes:
2718  *      (1) A slower implementation uses macros:
2719  *             *prval = GET_DATA_BYTE(&pixel, COLOR_RED);
2720  *             *pgval = GET_DATA_BYTE(&pixel, COLOR_GREEN);
2721  *             *pbval = GET_DATA_BYTE(&pixel, COLOR_BLUE);
2722  * </pre>
2723  */
2724 void
extractRGBValues(l_uint32 pixel,l_int32 * prval,l_int32 * pgval,l_int32 * pbval)2725 extractRGBValues(l_uint32  pixel,
2726                  l_int32  *prval,
2727                  l_int32  *pgval,
2728                  l_int32  *pbval)
2729 {
2730     if (prval) *prval = (pixel >> L_RED_SHIFT) & 0xff;
2731     if (pgval) *pgval = (pixel >> L_GREEN_SHIFT) & 0xff;
2732     if (pbval) *pbval = (pixel >> L_BLUE_SHIFT) & 0xff;
2733     return;
2734 }
2735 
2736 
2737 /*!
2738  * \brief   extractRGBAValues()
2739  *
2740  * \param[in]    pixel 32 bit
2741  * \param[out]   prval [optional] red component
2742  * \param[out]   pgval [optional] green component
2743  * \param[out]   pbval [optional] blue component
2744  * \param[out]   paval [optional] alpha component
2745  * \return  void
2746  */
2747 void
extractRGBAValues(l_uint32 pixel,l_int32 * prval,l_int32 * pgval,l_int32 * pbval,l_int32 * paval)2748 extractRGBAValues(l_uint32  pixel,
2749                   l_int32  *prval,
2750                   l_int32  *pgval,
2751                   l_int32  *pbval,
2752                   l_int32  *paval)
2753 {
2754     if (prval) *prval = (pixel >> L_RED_SHIFT) & 0xff;
2755     if (pgval) *pgval = (pixel >> L_GREEN_SHIFT) & 0xff;
2756     if (pbval) *pbval = (pixel >> L_BLUE_SHIFT) & 0xff;
2757     if (paval) *paval = (pixel >> L_ALPHA_SHIFT) & 0xff;
2758     return;
2759 }
2760 
2761 
2762 /*!
2763  * \brief   extractMinMaxComponent()
2764  *
2765  * \param[in]    pixel 32 bpp RGB
2766  * \param[in]    type L_CHOOSE_MIN or L_CHOOSE_MAX
2767  * \return  component in range [0 ... 255], or NULL on error
2768  */
2769 l_int32
extractMinMaxComponent(l_uint32 pixel,l_int32 type)2770 extractMinMaxComponent(l_uint32  pixel,
2771                        l_int32   type)
2772 {
2773 l_int32  rval, gval, bval, val;
2774 
2775     extractRGBValues(pixel, &rval, &gval, &bval);
2776     if (type == L_CHOOSE_MIN) {
2777         val = L_MIN(rval, gval);
2778         val = L_MIN(val, bval);
2779     } else {  /* type == L_CHOOSE_MAX */
2780         val = L_MAX(rval, gval);
2781         val = L_MAX(val, bval);
2782     }
2783     return val;
2784 }
2785 
2786 
2787 /*!
2788  * \brief   pixGetRGBLine()
2789  *
2790  * \param[in]    pixs  32 bpp
2791  * \param[in]    row
2792  * \param[in]    bufr  array of red samples; size w bytes
2793  * \param[in]    bufg  array of green samples; size w bytes
2794  * \param[in]    bufb  array of blue samples; size w bytes
2795  * \return  0 if OK; 1 on error
2796  *
2797  * <pre>
2798  * Notes:
2799  *      (1) This puts rgb components from the input line in pixs
2800  *          into the given buffers.
2801  * </pre>
2802  */
2803 l_int32
pixGetRGBLine(PIX * pixs,l_int32 row,l_uint8 * bufr,l_uint8 * bufg,l_uint8 * bufb)2804 pixGetRGBLine(PIX      *pixs,
2805               l_int32   row,
2806               l_uint8  *bufr,
2807               l_uint8  *bufg,
2808               l_uint8  *bufb)
2809 {
2810 l_uint32  *lines;
2811 l_int32    j, w, h;
2812 l_int32    wpls;
2813 
2814     PROCNAME("pixGetRGBLine");
2815 
2816     if (!pixs)
2817         return ERROR_INT("pixs not defined", procName, 1);
2818     if (pixGetDepth(pixs) != 32)
2819         return ERROR_INT("pixs not 32 bpp", procName, 1);
2820     if (!bufr || !bufg || !bufb)
2821         return ERROR_INT("buffer not defined", procName, 1);
2822 
2823     pixGetDimensions(pixs, &w, &h, NULL);
2824     if (row < 0 || row >= h)
2825         return ERROR_INT("row out of bounds", procName, 1);
2826     wpls = pixGetWpl(pixs);
2827     lines = pixGetData(pixs) + row * wpls;
2828 
2829     for (j = 0; j < w; j++) {
2830         bufr[j] = GET_DATA_BYTE(lines + j, COLOR_RED);
2831         bufg[j] = GET_DATA_BYTE(lines + j, COLOR_GREEN);
2832         bufb[j] = GET_DATA_BYTE(lines + j, COLOR_BLUE);
2833     }
2834 
2835     return 0;
2836 }
2837 
2838 
2839 /*-------------------------------------------------------------*
2840  *                    Pixel endian conversion                  *
2841  *-------------------------------------------------------------*/
2842 /*!
2843  * \brief   pixEndianByteSwapNew()
2844  *
2845  * \param[in]    pixs
2846  * \return  pixd, or NULL on error
2847  *
2848  * <pre>
2849  * Notes:
2850  *      (1) This is used to convert the data in a pix to a
2851  *          serialized byte buffer in raster order, and, for RGB,
2852  *          in order RGBA.  This requires flipping bytes within
2853  *          each 32-bit word for little-endian platforms, because the
2854  *          words have a MSB-to-the-left rule, whereas byte raster-order
2855  *          requires the left-most byte in each word to be byte 0.
2856  *          For big-endians, no swap is necessary, so this returns a clone.
2857  *      (2) Unlike pixEndianByteSwap(), which swaps the bytes in-place,
2858  *          this returns a new pix (or a clone).  We provide this
2859  *          because often when serialization is done, the source
2860  *          pix needs to be restored to canonical little-endian order,
2861  *          and this requires a second byte swap.  In such a situation,
2862  *          it is twice as fast to make a new pix in big-endian order,
2863  *          use it, and destroy it.
2864  * </pre>
2865  */
2866 PIX *
pixEndianByteSwapNew(PIX * pixs)2867 pixEndianByteSwapNew(PIX  *pixs)
2868 {
2869 l_uint32  *datas, *datad;
2870 l_int32    i, j, h, wpl;
2871 l_uint32   word;
2872 PIX       *pixd;
2873 
2874     PROCNAME("pixEndianByteSwapNew");
2875 
2876 #ifdef L_BIG_ENDIAN
2877 
2878     return pixClone(pixs);
2879 
2880 #else   /* L_LITTLE_ENDIAN */
2881 
2882     if (!pixs)
2883         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2884 
2885     datas = pixGetData(pixs);
2886     wpl = pixGetWpl(pixs);
2887     h = pixGetHeight(pixs);
2888     pixd = pixCreateTemplate(pixs);
2889     datad = pixGetData(pixd);
2890     for (i = 0; i < h; i++) {
2891         for (j = 0; j < wpl; j++, datas++, datad++) {
2892             word = *datas;
2893             *datad = (word >> 24) |
2894                     ((word >> 8) & 0x0000ff00) |
2895                     ((word << 8) & 0x00ff0000) |
2896                     (word << 24);
2897         }
2898     }
2899 
2900     return pixd;
2901 
2902 #endif   /* L_BIG_ENDIAN */
2903 
2904 }
2905 
2906 
2907 /*!
2908  * \brief   pixEndianByteSwap()
2909  *
2910  * \param[in]    pixs
2911  * \return  0 if OK, 1 on error
2912  *
2913  * <pre>
2914  * Notes:
2915  *      (1) This is used on little-endian platforms to swap
2916  *          the bytes within a word; bytes 0 and 3 are swapped,
2917  *          and bytes 1 and 2 are swapped.
2918  *      (2) This is required for little-endians in situations
2919  *          where we convert from a serialized byte order that is
2920  *          in raster order, as one typically has in file formats,
2921  *          to one with MSB-to-the-left in each 32-bit word, or v.v.
2922  *          See pix.h for a description of the canonical format
2923  *          (MSB-to-the left) that is used for both little-endian
2924  *          and big-endian platforms.   For big-endians, the
2925  *          MSB-to-the-left word order has the bytes in raster
2926  *          order when serialized, so no byte flipping is required.
2927  * </pre>
2928  */
2929 l_int32
pixEndianByteSwap(PIX * pixs)2930 pixEndianByteSwap(PIX  *pixs)
2931 {
2932 l_uint32  *data;
2933 l_int32    i, j, h, wpl;
2934 l_uint32   word;
2935 
2936     PROCNAME("pixEndianByteSwap");
2937 
2938 #ifdef L_BIG_ENDIAN
2939 
2940     return 0;
2941 
2942 #else   /* L_LITTLE_ENDIAN */
2943 
2944     if (!pixs)
2945         return ERROR_INT("pixs not defined", procName, 1);
2946 
2947     data = pixGetData(pixs);
2948     wpl = pixGetWpl(pixs);
2949     h = pixGetHeight(pixs);
2950     for (i = 0; i < h; i++) {
2951         for (j = 0; j < wpl; j++, data++) {
2952             word = *data;
2953             *data = (word >> 24) |
2954                     ((word >> 8) & 0x0000ff00) |
2955                     ((word << 8) & 0x00ff0000) |
2956                     (word << 24);
2957         }
2958     }
2959 
2960     return 0;
2961 
2962 #endif   /* L_BIG_ENDIAN */
2963 
2964 }
2965 
2966 
2967 /*!
2968  * \brief   lineEndianByteSwap()
2969  *
2970  *      Input   datad (dest byte array data, reordered on little-endians)
2971  *              datas (a src line of pix data)
2972  *              wpl (number of 32 bit words in the line)
2973  *      Return: 0 if OK, 1 on error
2974  *
2975  *  Notes:
2976  *      (1) This is used on little-endian platforms to swap
2977  *          the bytes within each word in the line of image data.
2978  *          Bytes 0 <==> 3 and 1 <==> 2 are swapped in the dest
2979  *          byte array data8d, relative to the pix data in datas.
2980  *      (2) The bytes represent 8 bit pixel values.  They are swapped
2981  *          for little endians so that when the dest array (char *)datad
2982  *          is addressed by bytes, the pixels are chosen sequentially
2983  *          from left to right in the image.
2984  */
2985 l_int32
lineEndianByteSwap(l_uint32 * datad,l_uint32 * datas,l_int32 wpl)2986 lineEndianByteSwap(l_uint32  *datad,
2987                    l_uint32  *datas,
2988                    l_int32    wpl)
2989 {
2990 l_int32   j;
2991 l_uint32  word;
2992 
2993     PROCNAME("lineEndianByteSwap");
2994 
2995     if (!datad || !datas)
2996         return ERROR_INT("datad and datas not both defined", procName, 1);
2997 
2998 #ifdef L_BIG_ENDIAN
2999 
3000     memcpy((char *)datad, (char *)datas, 4 * wpl);
3001     return 0;
3002 
3003 #else   /* L_LITTLE_ENDIAN */
3004 
3005     for (j = 0; j < wpl; j++, datas++, datad++) {
3006         word = *datas;
3007         *datad = (word >> 24) |
3008                  ((word >> 8) & 0x0000ff00) |
3009                  ((word << 8) & 0x00ff0000) |
3010                  (word << 24);
3011     }
3012     return 0;
3013 
3014 #endif   /* L_BIG_ENDIAN */
3015 
3016 }
3017 
3018 
3019 /*!
3020  * \brief   pixEndianTwoByteSwapNew()
3021  *
3022  * \param[in]    pixs
3023  * \return  0 if OK, 1 on error
3024  *
3025  * <pre>
3026  * Notes:
3027  *      (1) This is used on little-endian platforms to swap the
3028  *          2-byte entities within a 32-bit word.
3029  *      (2) This is equivalent to a full byte swap, as performed
3030  *          by pixEndianByteSwap(), followed by byte swaps in
3031  *          each of the 16-bit entities separately.
3032  *      (3) Unlike pixEndianTwoByteSwap(), which swaps the shorts in-place,
3033  *          this returns a new pix (or a clone).  We provide this
3034  *          to avoid having to swap twice in situations where the input
3035  *          pix must be restored to canonical little-endian order.
3036  * </pre>
3037  */
3038 PIX *
pixEndianTwoByteSwapNew(PIX * pixs)3039 pixEndianTwoByteSwapNew(PIX  *pixs)
3040 {
3041 l_uint32  *datas, *datad;
3042 l_int32    i, j, h, wpl;
3043 l_uint32   word;
3044 PIX       *pixd;
3045 
3046     PROCNAME("pixEndianTwoByteSwapNew");
3047 
3048 #ifdef L_BIG_ENDIAN
3049 
3050     return pixClone(pixs);
3051 
3052 #else   /* L_LITTLE_ENDIAN */
3053 
3054     if (!pixs)
3055         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3056 
3057     datas = pixGetData(pixs);
3058     wpl = pixGetWpl(pixs);
3059     h = pixGetHeight(pixs);
3060     pixd = pixCreateTemplate(pixs);
3061     datad = pixGetData(pixd);
3062     for (i = 0; i < h; i++) {
3063         for (j = 0; j < wpl; j++, datas++, datad++) {
3064             word = *datas;
3065             *datad = (word << 16) | (word >> 16);
3066         }
3067     }
3068 
3069     return pixd;
3070 
3071 #endif   /* L_BIG_ENDIAN */
3072 
3073 }
3074 
3075 
3076 /*!
3077  * \brief   pixEndianTwoByteSwap()
3078  *
3079  * \param[in]    pixs
3080  * \return  0 if OK, 1 on error
3081  *
3082  * <pre>
3083  * Notes:
3084  *      (1) This is used on little-endian platforms to swap the
3085  *          2-byte entities within a 32-bit word.
3086  *      (2) This is equivalent to a full byte swap, as performed
3087  *          by pixEndianByteSwap(), followed by byte swaps in
3088  *          each of the 16-bit entities separately.
3089  * </pre>
3090  */
3091 l_int32
pixEndianTwoByteSwap(PIX * pixs)3092 pixEndianTwoByteSwap(PIX  *pixs)
3093 {
3094 l_uint32  *data;
3095 l_int32    i, j, h, wpl;
3096 l_uint32   word;
3097 
3098     PROCNAME("pixEndianTwoByteSwap");
3099 
3100 #ifdef L_BIG_ENDIAN
3101 
3102     return 0;
3103 
3104 #else   /* L_LITTLE_ENDIAN */
3105 
3106     if (!pixs)
3107         return ERROR_INT("pixs not defined", procName, 1);
3108 
3109     data = pixGetData(pixs);
3110     wpl = pixGetWpl(pixs);
3111     h = pixGetHeight(pixs);
3112     for (i = 0; i < h; i++) {
3113         for (j = 0; j < wpl; j++, data++) {
3114             word = *data;
3115             *data = (word << 16) | (word >> 16);
3116         }
3117     }
3118 
3119     return 0;
3120 
3121 #endif   /* L_BIG_ENDIAN */
3122 
3123 }
3124 
3125 
3126 /*-------------------------------------------------------------*
3127  *             Extract raster data as binary string            *
3128  *-------------------------------------------------------------*/
3129 /*!
3130  * \brief   pixGetRasterData()
3131  *
3132  * \param[in]    pixs 1, 8, 32 bpp
3133  * \param[out]   pdata raster data in memory
3134  * \param[out]   pnbytes number of bytes in data string
3135  * \return  0 if OK, 1 on error
3136  *
3137  * <pre>
3138  * Notes:
3139  *      (1) This returns the raster data as a byte string, padded to the
3140  *          byte.  For 1 bpp, the first pixel is the MSbit in the first byte.
3141  *          For rgb, the bytes are in (rgb) order.  This is the format
3142  *          required for flate encoding of pixels in a PostScript file.
3143  * </pre>
3144  */
3145 l_int32
pixGetRasterData(PIX * pixs,l_uint8 ** pdata,size_t * pnbytes)3146 pixGetRasterData(PIX       *pixs,
3147                  l_uint8  **pdata,
3148                  size_t    *pnbytes)
3149 {
3150 l_int32    w, h, d, wpl, i, j, rval, gval, bval;
3151 l_int32    databpl;  /* bytes for each raster line in returned data */
3152 l_uint8   *line, *data;  /* packed data in returned array */
3153 l_uint32  *rline, *rdata;  /* data in pix raster */
3154 
3155     PROCNAME("pixGetRasterData");
3156 
3157     if (pdata) *pdata = NULL;
3158     if (pnbytes) *pnbytes = 0;
3159     if (!pdata || !pnbytes)
3160         return ERROR_INT("&data and &nbytes not both defined", procName, 1);
3161     if (!pixs)
3162         return ERROR_INT("pixs not defined", procName, 1);
3163     pixGetDimensions(pixs, &w, &h, &d);
3164     if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
3165         return ERROR_INT("depth not in {1,2,4,8,16,32}", procName, 1);
3166     rdata = pixGetData(pixs);
3167     wpl = pixGetWpl(pixs);
3168     if (d == 1)
3169         databpl = (w + 7) / 8;
3170     else if (d == 2)
3171         databpl = (w + 3) / 4;
3172     else if (d == 4)
3173         databpl = (w + 1) / 2;
3174     else if (d == 8 || d == 16)
3175         databpl = w * (d / 8);
3176     else  /* d == 32 bpp rgb */
3177         databpl = 3 * w;
3178     if ((data = (l_uint8 *)LEPT_CALLOC(databpl * h, sizeof(l_uint8))) == NULL)
3179         return ERROR_INT("data not allocated", procName, 1);
3180     *pdata = data;
3181     *pnbytes = databpl * h;
3182 
3183     for (i = 0; i < h; i++) {
3184          rline = rdata + i * wpl;
3185          line = data + i * databpl;
3186          if (d <= 8) {
3187              for (j = 0; j < databpl; j++)
3188                   line[j] = GET_DATA_BYTE(rline, j);
3189          } else if (d == 16) {
3190              for (j = 0; j < w; j++)
3191                   line[2 * j] = GET_DATA_TWO_BYTES(rline, j);
3192          } else {  /* d == 32 bpp rgb */
3193              for (j = 0; j < w; j++) {
3194                   extractRGBValues(rline[j], &rval, &gval, &bval);
3195                   *(line + 3 * j) = rval;
3196                   *(line + 3 * j + 1) = gval;
3197                   *(line + 3 * j + 2) = bval;
3198              }
3199          }
3200     }
3201 
3202     return 0;
3203 }
3204 
3205 
3206 /*-------------------------------------------------------------*
3207  *                 Test alpha component opaqueness             *
3208  *-------------------------------------------------------------*/
3209 /*!
3210  * \brief   pixAlphaIsOpaque()
3211  *
3212  * \param[in]    pix 32 bpp, spp == 4
3213  * \param[out]   popaque 1 if spp == 4 and all alpha component
3214  *                       values are 255 (opaque); 0 otherwise
3215  * \return  0 if OK, 1 on error
3216  *      Notes:
3217  *          1) On error, opaque is returned as 0 (FALSE).
3218  */
3219 l_int32
pixAlphaIsOpaque(PIX * pix,l_int32 * popaque)3220 pixAlphaIsOpaque(PIX      *pix,
3221                  l_int32  *popaque)
3222 {
3223 l_int32    w, h, wpl, i, j, alpha;
3224 l_uint32  *data, *line;
3225 
3226     PROCNAME("pixAlphaIsOpaque");
3227 
3228     if (!popaque)
3229         return ERROR_INT("&opaque not defined", procName, 1);
3230     *popaque = FALSE;
3231     if (!pix)
3232         return ERROR_INT("&pix not defined", procName, 1);
3233     if (pixGetDepth(pix) != 32)
3234         return ERROR_INT("&pix not 32 bpp", procName, 1);
3235     if (pixGetSpp(pix) != 4)
3236         return ERROR_INT("&pix not 4 spp", procName, 1);
3237 
3238     data = pixGetData(pix);
3239     wpl = pixGetWpl(pix);
3240     pixGetDimensions(pix, &w, &h, NULL);
3241     for (i = 0; i < h; i++) {
3242         line = data + i * wpl;
3243         for (j = 0; j < w; j++) {
3244             alpha = GET_DATA_BYTE(line + j, L_ALPHA_CHANNEL);
3245             if (alpha ^ 0xff)  /* not opaque */
3246                 return 0;
3247         }
3248     }
3249 
3250     *popaque = TRUE;
3251     return 0;
3252 }
3253 
3254 
3255 /*-------------------------------------------------------------*
3256  *             Setup helpers for 8 bpp byte processing         *
3257  *-------------------------------------------------------------*/
3258 /*!
3259  * \brief   pixSetupByteProcessing()
3260  *
3261  * \param[in]    pix 8 bpp, no colormap
3262  * \param[out]   pw [optional] width
3263  * \param[out]   ph [optional] height
3264  * \return  line ptr array, or NULL on error
3265  *
3266  * <pre>
3267  * Notes:
3268  *      (1) This is a simple helper for processing 8 bpp images with
3269  *          direct byte access.  It can swap byte order within each word.
3270  *      (2) After processing, you must call pixCleanupByteProcessing(),
3271  *          which frees the lineptr array and restores byte order.
3272  *      (3) Usage:
3273  *              l_uint8 **lineptrs = pixSetupByteProcessing(pix, &w, &h);
3274  *              for (i = 0; i < h; i++) {
3275  *                  l_uint8 *line = lineptrs[i];
3276  *                  for (j = 0; j < w; j++) {
3277  *                      val = line[j];
3278  *                      ...
3279  *                  }
3280  *              }
3281  *              pixCleanupByteProcessing(pix, lineptrs);
3282  * </pre>
3283  */
3284 l_uint8 **
pixSetupByteProcessing(PIX * pix,l_int32 * pw,l_int32 * ph)3285 pixSetupByteProcessing(PIX      *pix,
3286                        l_int32  *pw,
3287                        l_int32  *ph)
3288 {
3289 l_int32  w, h;
3290 
3291     PROCNAME("pixSetupByteProcessing");
3292 
3293     if (pw) *pw = 0;
3294     if (ph) *ph = 0;
3295     if (!pix || pixGetDepth(pix) != 8)
3296         return (l_uint8 **)ERROR_PTR("pix not defined or not 8 bpp",
3297                                      procName, NULL);
3298     pixGetDimensions(pix, &w, &h, NULL);
3299     if (pw) *pw = w;
3300     if (ph) *ph = h;
3301     if (pixGetColormap(pix))
3302         return (l_uint8 **)ERROR_PTR("pix has colormap", procName, NULL);
3303 
3304     pixEndianByteSwap(pix);
3305     return (l_uint8 **)pixGetLinePtrs(pix, NULL);
3306 }
3307 
3308 
3309 /*!
3310  * \brief   pixCleanupByteProcessing()
3311  *
3312  * \param[in]    pix 8 bpp, no colormap
3313  * \param[in]    lineptrs ptrs to the beginning of each raster line of data
3314  * \return  0 if OK, 1 on error
3315  *
3316  * <pre>
3317  * Notes:
3318  *      (1) This must be called after processing that was initiated
3319  *          by pixSetupByteProcessing() has finished.
3320  * </pre>
3321  */
3322 l_int32
pixCleanupByteProcessing(PIX * pix,l_uint8 ** lineptrs)3323 pixCleanupByteProcessing(PIX      *pix,
3324                          l_uint8 **lineptrs)
3325 {
3326     PROCNAME("pixCleanupByteProcessing");
3327 
3328     if (!pix)
3329         return ERROR_INT("pix not defined", procName, 1);
3330     if (!lineptrs)
3331         return ERROR_INT("lineptrs not defined", procName, 1);
3332 
3333     pixEndianByteSwap(pix);
3334     LEPT_FREE(lineptrs);
3335     return 0;
3336 }
3337 
3338 
3339 /*------------------------------------------------------------------------*
3340  *      Setting parameters for antialias masking with alpha transforms    *
3341  *------------------------------------------------------------------------*/
3342 /*!
3343  * \brief   l_setAlphaMaskBorder()
3344  *
3345  * \param[in]    val1, val2 in [0.0 ... 1.0]
3346  * \return  void
3347  *
3348  * <pre>
3349  * Notes:
3350  *      (1) This sets the opacity values used to generate the two outer
3351  *          boundary rings in the alpha mask associated with geometric
3352  *          transforms such as pixRotateWithAlpha().
3353  *      (2) The default values are val1 = 0.0 (completely transparent
3354  *          in the outermost ring) and val2 = 0.5 (half transparent
3355  *          in the second ring).  When the image is blended, this
3356  *          completely removes the outer ring (shrinking the image by
3357  *          2 in each direction), and alpha-blends with 0.5 the second ring.
3358  *          Using val1 = 0.25 and val2 = 0.75 gives a slightly more
3359  *          blurred border, with no perceptual difference at screen resolution.
3360  *      (3) The actual mask values are found by multiplying these
3361  *          normalized opacity values by 255.
3362  * </pre>
3363  */
3364 void
l_setAlphaMaskBorder(l_float32 val1,l_float32 val2)3365 l_setAlphaMaskBorder(l_float32  val1,
3366                      l_float32  val2)
3367 {
3368     val1 = L_MAX(0.0, L_MIN(1.0, val1));
3369     val2 = L_MAX(0.0, L_MIN(1.0, val2));
3370     AlphaMaskBorderVals[0] = val1;
3371     AlphaMaskBorderVals[1] = val2;
3372 }
3373