• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*====================================================================*
2  -  Copyright (C) 2001 Leptonica.  All rights reserved.
3  -  This software is distributed in the hope that it will be
4  -  useful, but with NO WARRANTY OF ANY KIND.
5  -  No author or distributor accepts responsibility to anyone for the
6  -  consequences of using this software, or for whether it serves any
7  -  particular purpose or works at all, unless he or she says so in
8  -  writing.  Everyone is granted permission to copy, modify and
9  -  redistribute this source code, for commercial or non-commercial
10  -  purposes, with the following restrictions: (1) the origin of this
11  -  source code must not be misrepresented; (2) modified versions must
12  -  be plainly marked as such; and (3) this notice may not be removed
13  -  or altered from any source or modified source distribution.
14  *====================================================================*/
15 
16 /*
17  *  pixconv.c
18  *
19  *      These functions convert between images of different types
20  *      without scaling.
21  *
22  *      Conversion from 8 bpp grayscale to 1, 2, 4 and 8 bpp
23  *           PIX        *pixThreshold8()
24  *
25  *      Conversion from colormap to full color or grayscale
26  *           PIX        *pixRemoveColormap()
27  *
28  *      Add colormap losslessly (8 to 8)
29  *           l_int32     pixAddGrayColormap8()
30  *           PIX        *pixAddMinimalGrayColormap8()
31  *
32  *      Conversion from RGB color to grayscale
33  *           PIX        *pixConvertRGBToLuminance()
34  *           PIX        *pixConvertRGBToGray()
35  *           PIX        *pixConvertRGBToGrayFast()
36  *           PIX        *pixConvertRGBToGrayMinMax()
37  *
38  *      Conversion from grayscale to colormap
39  *           PIX        *pixConvertGrayToColormap()  -- 2, 4, 8 bpp
40  *           PIX        *pixConvertGrayToColormap8()  -- 8 bpp only
41  *
42  *      Colorizing conversion from grayscale to color
43  *           PIX        *pixColorizeGray()  -- 8 bpp or cmapped
44  *
45  *      Conversion from RGB color to colormap
46  *           PIX        *pixConvertRGBToColormap()
47  *
48  *      Quantization for relatively small number of colors in source
49  *           l_int32     pixQuantizeIfFewColors()
50  *
51  *      Conversion from 16 bpp to 8 bpp
52  *           PIX        *pixConvert16To8()
53  *
54  *      Conversion from grayscale to false color
55  *           PIX        *pixConvertGrayToFalseColor()
56  *
57  *      Unpacking conversion from 1 bpp to 2, 4, 8, 16 and 32 bpp
58  *           PIX        *pixUnpackBinary()
59  *           PIX        *pixConvert1To16()
60  *           PIX        *pixConvert1To32()
61  *
62  *      Unpacking conversion from 1 bpp to 2 bpp
63  *           PIX        *pixConvert1To2Cmap()
64  *           PIX        *pixConvert1To2()
65  *
66  *      Unpacking conversion from 1 bpp to 4 bpp
67  *           PIX        *pixConvert1To4Cmap()
68  *           PIX        *pixConvert1To4()
69  *
70  *      Unpacking conversion from 1, 2 and 4 bpp to 8 bpp
71  *           PIX        *pixConvert1To8()
72  *           PIX        *pixConvert2To8()
73  *           PIX        *pixConvert4To8()
74  *
75  *      Unpacking conversion from 8 bpp to 16 bpp
76  *           PIX        *pixConvert8To16()
77  *
78  *      Top-level conversion to 1 bpp
79  *           PIX        *pixConvertTo1()
80  *           PIX        *pixConvertTo1BySampling()
81  *
82  *      Top-level conversion to 8 bpp
83  *           PIX        *pixConvertTo8()
84  *           PIX        *pixConvertTo8BySampling()
85  *
86  *      Top-level conversion to 16 bpp
87  *           PIX        *pixConvertTo16()
88  *
89  *      Top-level conversion to 32 bpp (RGB)
90  *           PIX        *pixConvertTo32()   ***
91  *           PIX        *pixConvertTo32BySampling()   ***
92  *           PIX        *pixConvert8To32()  ***
93  *
94  *      Top-level conversion to 8 or 32 bpp, without colormap
95  *           PIX        *pixConvertTo8Or32
96  *
97  *      Lossless depth conversion (unpacking)
98  *           PIX        *pixConvertLossless()
99  *
100  *      Conversion for printing in PostScript
101  *           PIX        *pixConvertForPSWrap()
102  *
103  *      Colorspace conversion between RGB and HSV
104  *           PIX        *pixConvertRGBToHSV()
105  *           PIX        *pixConvertHSVToRGB()
106  *           l_int32     convertRGBToHSV()
107  *           l_int32     convertHSVToRGB()
108  *           PIX        *pixConvertRGBToHue()
109  *           PIX        *pixConvertRGBToSaturation()
110  *           PIX        *pixConvertRGBToValue()
111  *
112  *
113  *      *** indicates implicit assumption about RGB component ordering
114  */
115 
116 #include <stdio.h>
117 #include <stdlib.h>
118 #include <string.h>
119 #include <math.h>
120 #include "allheaders.h"
121 
122     /* These numbers are ad-hoc, but at least they add up
123        to 1. Unlike, for example, the weighting factor for
124        conversion of RGB to luminance, or more specifically
125        to Y in the YUV colorspace. Those numbers come
126        from the International Telecommunications Union, via ITU-R
127        (and formerly ITU CCIR 601). */
128 static const l_float32  L_RED_WEIGHT =   0.3;
129 static const l_float32  L_GREEN_WEIGHT = 0.5;
130 static const l_float32  L_BLUE_WEIGHT =  0.2;
131 
132 
133 #ifndef  NO_CONSOLE_IO
134 #define DEBUG_CONVERT_TO_COLORMAP  0
135 #define DEBUG_UNROLLING 0
136 #endif   /* ~NO_CONSOLE_IO */
137 
138 
139 /*-------------------------------------------------------------*
140  *     Conversion from 8 bpp grayscale to 1, 2 4 and 8 bpp     *
141  *-------------------------------------------------------------*/
142 /*!
143  *  pixThreshold8()
144  *
145  *      Input:  pix (8 bpp grayscale)
146  *              d (destination depth: 1, 2, 4 or 8)
147  *              nlevels (number of levels to be used for colormap)
148  *              cmapflag (1 if makes colormap; 0 otherwise)
149  *      Return: pixd (thresholded with standard dest thresholds),
150  *              or null on error
151  *
152  *  Notes:
153  *      (1) This uses, by default, equally spaced "target" values
154  *          that depend on the number of levels, with thresholds
155  *          halfway between.  For N levels, with separation (N-1)/255,
156  *          there are N-1 fixed thresholds.
157  *      (2) For 1 bpp destination, the number of levels can only be 2
158  *          and if a cmap is made, black is (0,0,0) and white
159  *          is (255,255,255), which is opposite to the convention
160  *          without a colormap.
161  *      (3) For 1, 2 and 4 bpp, the nlevels arg is used if a colormap
162  *          is made; otherwise, we take the most significant bits
163  *          from the src that will fit in the dest.
164  *      (4) For 8 bpp, the input pixs is quantized to nlevels.  The
165  *          dest quantized with that mapping, either through a colormap
166  *          table or directly with 8 bit values.
167  *      (5) Typically you should not use make a colormap for 1 bpp dest.
168  *      (6) This is not dithering.  Each pixel is treated independently.
169  */
170 PIX *
pixThreshold8(PIX * pixs,l_int32 d,l_int32 nlevels,l_int32 cmapflag)171 pixThreshold8(PIX     *pixs,
172               l_int32  d,
173               l_int32  nlevels,
174               l_int32  cmapflag)
175 {
176 PIX       *pixd;
177 PIXCMAP   *cmap;
178 
179     PROCNAME("pixThreshold8");
180 
181     if (!pixs)
182         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
183     if (pixGetDepth(pixs) != 8)
184         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
185     if (cmapflag && nlevels < 2)
186         return (PIX *)ERROR_PTR("nlevels must be at least 2", procName, NULL);
187 
188     switch (d) {
189     case 1:
190         pixd = pixThresholdToBinary(pixs, 128);
191         if (cmapflag) {
192             cmap = pixcmapCreateLinear(1, 2);
193             pixSetColormap(pixd, cmap);
194         }
195         break;
196     case 2:
197         pixd = pixThresholdTo2bpp(pixs, nlevels, cmapflag);
198         break;
199     case 4:
200         pixd = pixThresholdTo4bpp(pixs, nlevels, cmapflag);
201         break;
202     case 8:
203         pixd = pixThresholdOn8bpp(pixs, nlevels, cmapflag);
204         break;
205     default:
206         return (PIX *)ERROR_PTR("d must be in {1,2,4,8}", procName, NULL);
207     }
208 
209     if (!pixd)
210         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
211     return pixd;
212 }
213 
214 
215 /*-------------------------------------------------------------*
216  *               Conversion from colormapped pix               *
217  *-------------------------------------------------------------*/
218 /*!
219  *  pixRemoveColormap()
220  *
221  *      Input:  pixs (see restrictions below)
222  *              type (REMOVE_CMAP_TO_BINARY,
223  *                    REMOVE_CMAP_TO_GRAYSCALE,
224  *                    REMOVE_CMAP_TO_FULL_COLOR,
225  *                    REMOVE_CMAP_BASED_ON_SRC)
226  *      Return: new pix, or null on error
227  *
228  *  Notes:
229  *      (1) If there is no colormap, a clone is returned.
230  *      (2) Otherwise, the input pixs is restricted to 1, 2, 4 or 8 bpp.
231  *      (3) Use REMOVE_CMAP_TO_BINARY only on 1 bpp pix.
232  *      (4) For grayscale conversion from RGB, use a weighted average
233  *          of RGB values, and always return an 8 bpp pix, regardless
234  *          of whether the input pixs depth is 2, 4 or 8 bpp.
235  */
236 PIX *
pixRemoveColormap(PIX * pixs,l_int32 type)237 pixRemoveColormap(PIX     *pixs,
238                   l_int32  type)
239 {
240 l_int32    sval, rval, gval, bval;
241 l_int32    i, j, k, w, h, d, wpls, wpld, ncolors, count;
242 l_int32    colorfound;
243 l_int32   *rmap, *gmap, *bmap, *graymap;
244 l_uint32  *datas, *lines, *datad, *lined, *lut;
245 l_uint32   sword, dword;
246 PIXCMAP   *cmap;
247 PIX       *pixd;
248 
249     PROCNAME("pixRemoveColormap");
250 
251     if (!pixs)
252         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
253     if ((cmap = pixGetColormap(pixs)) == NULL)
254         return pixClone(pixs);
255 
256     if (type != REMOVE_CMAP_TO_BINARY &&
257         type != REMOVE_CMAP_TO_GRAYSCALE &&
258         type != REMOVE_CMAP_TO_FULL_COLOR &&
259         type != REMOVE_CMAP_BASED_ON_SRC) {
260         L_WARNING("Invalid type; converting based on src", procName);
261         type = REMOVE_CMAP_BASED_ON_SRC;
262     }
263 
264     pixGetDimensions(pixs, &w, &h, &d);
265     if (d != 1 && d != 2 && d != 4 && d != 8)
266         return (PIX *)ERROR_PTR("pixs must be {1,2,4,8} bpp", procName, NULL);
267 
268     if (pixcmapToArrays(cmap, &rmap, &gmap, &bmap))
269         return (PIX *)ERROR_PTR("colormap arrays not made", procName, NULL);
270 
271     if (d != 1 && type == REMOVE_CMAP_TO_BINARY) {
272         L_WARNING("not 1 bpp; can't remove cmap to binary", procName);
273         type = REMOVE_CMAP_BASED_ON_SRC;
274     }
275 
276     if (type == REMOVE_CMAP_BASED_ON_SRC) {
277             /* select output type depending on colormap */
278         pixcmapHasColor(cmap, &colorfound);
279         if (!colorfound) {
280             if (d == 1)
281                 type = REMOVE_CMAP_TO_BINARY;
282             else
283                 type = REMOVE_CMAP_TO_GRAYSCALE;
284         }
285         else
286             type = REMOVE_CMAP_TO_FULL_COLOR;
287     }
288 
289     ncolors = pixcmapGetCount(cmap);
290     datas = pixGetData(pixs);
291     wpls = pixGetWpl(pixs);
292     if (type == REMOVE_CMAP_TO_BINARY) {
293         if ((pixd = pixCopy(NULL, pixs)) == NULL)
294             return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
295         pixcmapGetColor(cmap, 0, &rval, &gval, &bval);
296         if (rval == 0)  /* photometrically inverted from standard */
297             pixInvert(pixd, pixd);
298         pixDestroyColormap(pixd);
299     }
300     else if (type == REMOVE_CMAP_TO_GRAYSCALE) {
301         if ((pixd = pixCreate(w, h, 8)) == NULL)
302             return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
303         pixCopyResolution(pixd, pixs);
304         datad = pixGetData(pixd);
305         wpld = pixGetWpl(pixd);
306         if ((graymap = (l_int32 *)CALLOC(ncolors, sizeof(l_int32))) == NULL)
307             return (PIX *)ERROR_PTR("calloc fail for graymap", procName, NULL);
308         for (i = 0; i < pixcmapGetCount(cmap); i++) {
309             graymap[i] = (rmap[i] + 2 * gmap[i] + bmap[i]) / 4;
310         }
311         for (i = 0; i < h; i++) {
312             lines = datas + i * wpls;
313             lined = datad + i * wpld;
314             switch (d)   /* depth test above; no default permitted */
315             {
316                 case 8:
317                         /* Unrolled 4x */
318                     for (j = 0, count = 0; j + 3 < w; j += 4, count++) {
319                         sword = lines[count];
320                         dword = (graymap[(sword >> 24) & 0xff] << 24) |
321                             (graymap[(sword >> 16) & 0xff] << 16) |
322                             (graymap[(sword >> 8) & 0xff] << 8) |
323                             graymap[sword & 0xff];
324                         lined[count] = dword;
325                     }
326                         /* Cleanup partial word */
327                     for (; j < w; j++) {
328                         sval = GET_DATA_BYTE(lines, j);
329                         gval = graymap[sval];
330                         SET_DATA_BYTE(lined, j, gval);
331                     }
332 #if DEBUG_UNROLLING
333 #define CHECK_VALUE(a, b, c) if (GET_DATA_BYTE(a, b) != c) { \
334     fprintf(stderr, "Error: mismatch at %d, %d vs %d\n", \
335             j, GET_DATA_BYTE(a, b), c); }
336                     for (j = 0; j < w; j++) {
337                         sval = GET_DATA_BYTE(lines, j);
338                         gval = graymap[sval];
339                         CHECK_VALUE(lined, j, gval);
340                     }
341 #endif
342                     break;
343                 case 4:
344                         /* Unrolled 8x */
345                     for (j = 0, count = 0; j + 7 < w; j += 8, count++) {
346                         sword = lines[count];
347                         dword = (graymap[(sword >> 28) & 0xf] << 24) |
348                             (graymap[(sword >> 24) & 0xf] << 16) |
349                             (graymap[(sword >> 20) & 0xf] << 8) |
350                             graymap[(sword >> 16) & 0xf];
351                         lined[2 * count] = dword;
352                         dword = (graymap[(sword >> 12) & 0xf] << 24) |
353                             (graymap[(sword >> 8) & 0xf] << 16) |
354                             (graymap[(sword >> 4) & 0xf] << 8) |
355                             graymap[sword & 0xf];
356                         lined[2 * count + 1] = dword;
357                     }
358                         /* Cleanup partial word */
359                     for (; j < w; j++) {
360                         sval = GET_DATA_QBIT(lines, j);
361                         gval = graymap[sval];
362                         SET_DATA_BYTE(lined, j, gval);
363                     }
364 #if DEBUG_UNROLLING
365                     for (j = 0; j < w; j++) {
366                         sval = GET_DATA_QBIT(lines, j);
367                         gval = graymap[sval];
368                         CHECK_VALUE(lined, j, gval);
369                     }
370 #endif
371                     break;
372                 case 2:
373                         /* Unrolled 16x */
374                     for (j = 0, count = 0; j + 15 < w; j += 16, count++) {
375                         sword = lines[count];
376                         dword = (graymap[(sword >> 30) & 0x3] << 24) |
377                             (graymap[(sword >> 28) & 0x3] << 16) |
378                             (graymap[(sword >> 26) & 0x3] << 8) |
379                             graymap[(sword >> 24) & 0x3];
380                         lined[4 * count] = dword;
381                         dword = (graymap[(sword >> 22) & 0x3] << 24) |
382                             (graymap[(sword >> 20) & 0x3] << 16) |
383                             (graymap[(sword >> 18) & 0x3] << 8) |
384                             graymap[(sword >> 16) & 0x3];
385                         lined[4 * count + 1] = dword;
386                         dword = (graymap[(sword >> 14) & 0x3] << 24) |
387                             (graymap[(sword >> 12) & 0x3] << 16) |
388                             (graymap[(sword >> 10) & 0x3] << 8) |
389                             graymap[(sword >> 8) & 0x3];
390                         lined[4 * count + 2] = dword;
391                         dword = (graymap[(sword >> 6) & 0x3] << 24) |
392                             (graymap[(sword >> 4) & 0x3] << 16) |
393                             (graymap[(sword >> 2) & 0x3] << 8) |
394                             graymap[sword & 0x3];
395                         lined[4 * count + 3] = dword;
396                     }
397                         /* Cleanup partial word */
398                     for (; j < w; j++) {
399                         sval = GET_DATA_DIBIT(lines, j);
400                         gval = graymap[sval];
401                         SET_DATA_BYTE(lined, j, gval);
402                     }
403 #if DEBUG_UNROLLING
404                     for (j = 0; j < w; j++) {
405                         sval = GET_DATA_DIBIT(lines, j);
406                         gval = graymap[sval];
407                         CHECK_VALUE(lined, j, gval);
408                     }
409 #endif
410                     break;
411                 case 1:
412                         /* Unrolled 8x */
413                     for (j = 0, count = 0; j + 31 < w; j += 32, count++) {
414                         sword = lines[count];
415                         for (k = 0; k < 4; k++) {
416                                 /* The top byte is always the relevant one */
417                             dword = (graymap[(sword >> 31) & 0x1] << 24) |
418                                 (graymap[(sword >> 30) & 0x1] << 16) |
419                                 (graymap[(sword >> 29) & 0x1] << 8) |
420                                 graymap[(sword >> 28) & 0x1];
421                             lined[8 * count + 2 * k] = dword;
422                             dword = (graymap[(sword >> 27) & 0x1] << 24) |
423                                 (graymap[(sword >> 26) & 0x1] << 16) |
424                                 (graymap[(sword >> 25) & 0x1] << 8) |
425                                 graymap[(sword >> 24) & 0x1];
426                             lined[8 * count + 2 * k + 1] = dword;
427                             sword <<= 8;  /* Move up the next byte */
428                         }
429                     }
430                         /* Cleanup partial word */
431                     for (; j < w; j++) {
432                         sval = GET_DATA_BIT(lines, j);
433                         gval = graymap[sval];
434                         SET_DATA_BYTE(lined, j, gval);
435                     }
436 #if DEBUG_UNROLLING
437                     for (j = 0; j < w; j++) {
438                         sval = GET_DATA_BIT(lines, j);
439                         gval = graymap[sval];
440                         CHECK_VALUE(lined, j, gval);
441                     }
442 #undef CHECK_VALUE
443 #endif
444                     break;
445                 default:
446                     return NULL;
447             }
448         }
449         if (graymap)
450             FREE(graymap);
451     }
452     else {  /* type == REMOVE_CMAP_TO_FULL_COLOR */
453         if ((pixd = pixCreate(w, h, 32)) == NULL)
454             return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
455         pixCopyResolution(pixd, pixs);
456         datad = pixGetData(pixd);
457         wpld = pixGetWpl(pixd);
458         if ((lut = (l_uint32 *)CALLOC(ncolors, sizeof(l_uint32))) == NULL)
459             return (PIX *)ERROR_PTR("calloc fail for lut", procName, NULL);
460         for (i = 0; i < ncolors; i++)
461             composeRGBPixel(rmap[i], gmap[i], bmap[i], lut + i);
462 
463         for (i = 0; i < h; i++) {
464             lines = datas + i * wpls;
465             lined = datad + i * wpld;
466             for (j = 0; j < w; j++) {
467                 if (d == 8)
468                     sval = GET_DATA_BYTE(lines, j);
469                 else if (d == 4)
470                     sval = GET_DATA_QBIT(lines, j);
471                 else if (d == 2)
472                     sval = GET_DATA_DIBIT(lines, j);
473                 else if (d == 1)
474                     sval = GET_DATA_BIT(lines, j);
475                 else
476                     return NULL;
477                 if (sval >= ncolors)
478                     L_WARNING("pixel value out of bounds", procName);
479                 else
480                     lined[j] = lut[sval];
481             }
482         }
483         FREE(lut);
484     }
485 
486     FREE(rmap);
487     FREE(gmap);
488     FREE(bmap);
489     return pixd;
490 }
491 
492 
493 /*-------------------------------------------------------------*
494  *              Add colormap losslessly (8 to 8)               *
495  *-------------------------------------------------------------*/
496 /*!
497  *  pixAddGrayColormap8()
498  *
499  *      Input:  pixs (8 bpp)
500  *      Return: 0 if OK, 1 on error
501  *
502  *  Notes:
503  *      (1) If pixs has a colormap, this is a no-op.
504  */
505 l_int32
pixAddGrayColormap8(PIX * pixs)506 pixAddGrayColormap8(PIX  *pixs)
507 {
508 PIXCMAP  *cmap;
509 
510     PROCNAME("pixAddGrayColormap8");
511 
512     if (!pixs || pixGetDepth(pixs) != 8)
513         return ERROR_INT("pixs not defined or not 8 bpp", procName, 1);
514     if (pixGetColormap(pixs))
515         return 0;
516 
517     cmap = pixcmapCreateLinear(8, 256);
518     pixSetColormap(pixs, cmap);
519     return 0;
520 }
521 
522 
523 /*!
524  *  pixAddMinimalGrayColormap8()
525  *
526  *      Input:  pixs (8 bpp)
527  *      Return: 0 if OK, 1 on error
528  *
529  *  Notes:
530  *      (1) This generates a colormapped version of the input image
531  *          that has the same number of colormap entries as the
532  *          input image has unique gray levels.
533  */
534 PIX *
pixAddMinimalGrayColormap8(PIX * pixs)535 pixAddMinimalGrayColormap8(PIX  *pixs)
536 {
537 l_int32    ncolors, w, h, i, j, wplt, wpld, index, val;
538 l_int32   *inta, *revmap;
539 l_uint32  *datat, *datad, *linet, *lined;
540 PIX       *pixt, *pixd;
541 PIXCMAP   *cmap;
542 
543     PROCNAME("pixAddMinimalGrayColormap8");
544 
545     if (!pixs || pixGetDepth(pixs) != 8)
546         return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
547 
548         /* Eliminate the easy cases */
549     pixNumColors(pixs, 1, &ncolors);
550     cmap = pixGetColormap(pixs);
551     if (cmap) {
552         if (pixcmapGetCount(cmap) == ncolors)  /* irreducible */
553             return pixCopy(NULL, pixs);
554         else
555             pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
556     }
557     else {
558         if (ncolors == 256) {
559             pixt = pixCopy(NULL, pixs);
560             pixAddGrayColormap8(pixt);
561             return pixt;
562         }
563         pixt = pixClone(pixs);
564     }
565 
566         /* Find the gray levels and make a reverse map */
567     pixGetDimensions(pixt, &w, &h, NULL);
568     datat = pixGetData(pixt);
569     wplt = pixGetWpl(pixt);
570     inta = (l_int32 *)CALLOC(256, sizeof(l_int32));
571     for (i = 0; i < h; i++) {
572         linet = datat + i * wplt;
573         for (j = 0; j < w; j++) {
574             val = GET_DATA_BYTE(linet, j);
575             inta[val] = 1;
576         }
577     }
578     cmap = pixcmapCreate(8);
579     revmap = (l_int32 *)CALLOC(256, sizeof(l_int32));
580     for (i = 0, index = 0; i < 256; i++) {
581         if (inta[i]) {
582             pixcmapAddColor(cmap, i, i, i);
583             revmap[i] = index++;
584         }
585     }
586 
587         /* Set all pixels in pixd to the colormap index */
588     pixd = pixCreateTemplate(pixt);
589     pixSetColormap(pixd, cmap);
590     pixCopyResolution(pixd, pixs);
591     datad = pixGetData(pixd);
592     wpld = pixGetWpl(pixd);
593     for (i = 0; i < h; i++) {
594         linet = datat + i * wplt;
595         lined = datad + i * wpld;
596         for (j = 0; j < w; j++) {
597             val = GET_DATA_BYTE(linet, j);
598             SET_DATA_BYTE(lined, j, revmap[val]);
599         }
600     }
601 
602     pixDestroy(&pixt);
603     FREE(inta);
604     FREE(revmap);
605     return pixd;
606 }
607 
608 
609 /*-------------------------------------------------------------*
610  *            Conversion from RGB color to grayscale           *
611  *-------------------------------------------------------------*/
612 /*!
613  *  pixConvertRGBToLuminance()
614  *
615  *      Input:  pix (32 bpp RGB)
616  *      Return: 8 bpp pix, or null on error
617  *
618  *  Notes:
619  *      (1) Use a standard luminance conversion.
620  */
621 PIX *
pixConvertRGBToLuminance(PIX * pixs)622 pixConvertRGBToLuminance(PIX *pixs)
623 {
624   return pixConvertRGBToGray(pixs, 0.0, 0.0, 0.0);
625 }
626 
627 
628 /*!
629  *  pixConvertRGBToGray()
630  *
631  *      Input:  pix (32 bpp RGB)
632  *              rwt, gwt, bwt  (non-negative; these should add to 1.0,
633  *                              or use 0.0 for default)
634  *      Return: 8 bpp pix, or null on error
635  *
636  *  Notes:
637  *      (1) Use a weighted average of the RGB values.
638  */
639 PIX *
pixConvertRGBToGray(PIX * pixs,l_float32 rwt,l_float32 gwt,l_float32 bwt)640 pixConvertRGBToGray(PIX       *pixs,
641                     l_float32  rwt,
642                     l_float32  gwt,
643                     l_float32  bwt)
644 {
645 l_int32    i, j, w, h, wpls, wpld, rval, gval, bval, val;
646 l_uint32  *datas, *lines, *datad, *lined;
647 l_float32  sum;
648 PIX       *pixd;
649 
650     PROCNAME("pixConvertRGBToGray");
651 
652     if (!pixs)
653         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
654     if (pixGetDepth(pixs) != 32)
655         return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
656     if (rwt < 0.0 || gwt < 0.0 || bwt < 0.0)
657         return (PIX *)ERROR_PTR("weights not all >= 0.0", procName, NULL);
658 
659         /* Make sure the sum of weights is 1.0; otherwise, you can get
660          * overflow in the gray value. */
661     if (rwt == 0.0 && gwt == 0.0 && bwt == 0.0) {
662         rwt = L_RED_WEIGHT;
663         gwt = L_GREEN_WEIGHT;
664         bwt = L_BLUE_WEIGHT;
665     }
666     sum = rwt + gwt + bwt;
667     if (L_ABS(sum - 1.0) > 0.0001) {  /* maintain ratios with sum == 1.0 */
668         L_WARNING("weights don't sum to 1; maintaining ratios", procName);
669         rwt = rwt / sum;
670         gwt = gwt / sum;
671         bwt = bwt / sum;
672     }
673 
674     pixGetDimensions(pixs, &w, &h, NULL);
675     datas = pixGetData(pixs);
676     wpls = pixGetWpl(pixs);
677     if ((pixd = pixCreate(w, h, 8)) == NULL)
678         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
679     pixCopyResolution(pixd, pixs);
680     datad = pixGetData(pixd);
681     wpld = pixGetWpl(pixd);
682 
683     for (i = 0; i < h; i++) {
684         lines = datas + i * wpls;
685         lined = datad + i * wpld;
686         for (j = 0; j < w; j++) {
687             extractRGBValues(lines[j], &rval, &gval, &bval);
688             val = (l_int32)(rwt * rval + gwt * gval + bwt * bval + 0.5);
689             SET_DATA_BYTE(lined, j, val);
690         }
691     }
692 
693     return pixd;
694 }
695 
696 
697 /*!
698  *  pixConvertRGBToGrayFast()
699  *
700  *      Input:  pix (32 bpp RGB)
701  *      Return: 8 bpp pix, or null on error
702  *
703  *  Notes:
704  *      (1) This function should be used if speed of conversion
705  *          is paramount, and the green channel can be used as
706  *          a fair representative of the RGB intensity.  It is
707  *          several times faster than pixConvertRGBToGray().
708  *      (2) To combine RGB to gray conversion with subsampling,
709  *          use pixScaleRGBToGrayFast() instead.
710  */
711 PIX *
pixConvertRGBToGrayFast(PIX * pixs)712 pixConvertRGBToGrayFast(PIX  *pixs)
713 {
714 l_int32    i, j, w, h, wpls, wpld, val;
715 l_uint32  *datas, *lines, *datad, *lined;
716 PIX       *pixd;
717 
718     PROCNAME("pixConvertRGBToGrayFast");
719 
720     if (!pixs)
721         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
722     if (pixGetDepth(pixs) != 32)
723         return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
724 
725     pixGetDimensions(pixs, &w, &h, NULL);
726     datas = pixGetData(pixs);
727     wpls = pixGetWpl(pixs);
728     if ((pixd = pixCreate(w, h, 8)) == NULL)
729         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
730     pixCopyResolution(pixd, pixs);
731     datad = pixGetData(pixd);
732     wpld = pixGetWpl(pixd);
733 
734     for (i = 0; i < h; i++) {
735         lines = datas + i * wpls;
736         lined = datad + i * wpld;
737         for (j = 0; j < w; j++, lines++) {
738             val = ((*lines) >> L_GREEN_SHIFT) & 0xff;
739             SET_DATA_BYTE(lined, j, val);
740         }
741     }
742 
743     return pixd;
744 }
745 
746 
747 /*!
748  *  pixConvertRGBToGrayMinMax()
749  *
750  *      Input:  pix (32 bpp RGB)
751  *              type (L_CHOOSE_MIN or L_CHOOSE_MAX)
752  *      Return: 8 bpp pix, or null on error
753  *
754  *  Notes:
755  *      (1) @type chooses among the 3 color components for each pixel
756  *      (2) This is useful when looking for the maximum deviation
757  *          of a component from either 0 or 255.  For finding the
758  *          deviation of a single component, it is more sensitive
759  *          than using a weighted average.
760  */
761 PIX *
pixConvertRGBToGrayMinMax(PIX * pixs,l_int32 type)762 pixConvertRGBToGrayMinMax(PIX     *pixs,
763                           l_int32  type)
764 {
765 l_int32    i, j, w, h, wpls, wpld, rval, gval, bval, val;
766 l_uint32  *datas, *lines, *datad, *lined;
767 PIX       *pixd;
768 
769     PROCNAME("pixConvertRGBToGrayMinMax");
770 
771     if (!pixs)
772         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
773     if (pixGetDepth(pixs) != 32)
774         return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
775     if (type != L_CHOOSE_MIN && type != L_CHOOSE_MAX)
776         return (PIX *)ERROR_PTR("invalid type", procName, NULL);
777 
778     pixGetDimensions(pixs, &w, &h, NULL);
779     datas = pixGetData(pixs);
780     wpls = pixGetWpl(pixs);
781     if ((pixd = pixCreate(w, h, 8)) == NULL)
782         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
783     pixCopyResolution(pixd, pixs);
784     datad = pixGetData(pixd);
785     wpld = pixGetWpl(pixd);
786 
787     for (i = 0; i < h; i++) {
788         lines = datas + i * wpls;
789         lined = datad + i * wpld;
790         for (j = 0; j < w; j++) {
791             extractRGBValues(lines[j], &rval, &gval, &bval);
792             if (type == L_CHOOSE_MIN) {
793                 val = L_MIN(rval, gval);
794                 val = L_MIN(val, bval);
795             }
796             else {  /* type == L_CHOOSE_MAX */
797                 val = L_MAX(rval, gval);
798                 val = L_MAX(val, bval);
799             }
800             SET_DATA_BYTE(lined, j, val);
801         }
802     }
803 
804     return pixd;
805 }
806 
807 
808 
809 /*---------------------------------------------------------------------------*
810  *                  Conversion from grayscale to colormap                    *
811  *---------------------------------------------------------------------------*/
812 /*!
813  *  pixConvertGrayToColormap()
814  *
815  *      Input:  pixs (2, 4 or 8 bpp grayscale)
816  *      Return: pixd (2, 4 or 8 bpp with colormap), or null on error
817  *
818  *  Notes:
819  *      (1) This is a simple interface for adding a colormap to a
820  *          2, 4 or 8 bpp grayscale image without causing any
821  *          quantization.  There is some similarity to operations
822  *          in grayquant.c, such as pixThresholdOn8bpp(), where
823  *          the emphasis is on quantization with an arbitrary number
824  *          of levels, and a colormap is an option.
825  *      (2) Returns a copy if pixs already has a colormap.
826  *      (3) For 8 bpp src, this is a lossless transformation.
827  *      (4) For 2 and 4 bpp src, this generates a colormap that
828  *          assumes full coverage of the gray space, with equally spaced
829  *          levels: 4 levels for d = 2 and 16 levels for d = 4.
830  *      (5) In all cases, the depth of the dest is the same as the src.
831  */
832 PIX *
pixConvertGrayToColormap(PIX * pixs)833 pixConvertGrayToColormap(PIX  *pixs)
834 {
835 l_int32    d;
836 PIX       *pixd;
837 PIXCMAP   *cmap;
838 
839     PROCNAME("pixConvertGrayToColormap");
840 
841     if (!pixs)
842         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
843     d = pixGetDepth(pixs);
844     if (d != 2 && d != 4 && d != 8)
845         return (PIX *)ERROR_PTR("pixs not 2, 4 or 8 bpp", procName, NULL);
846 
847     if (pixGetColormap(pixs)) {
848         L_WARNING("pixs already has a colormap", procName);
849         return pixCopy(NULL, pixs);
850     }
851 
852     if (d == 8)  /* lossless conversion */
853         return pixConvertGrayToColormap8(pixs, 2);
854 
855         /* Build a cmap with equally spaced target values over the
856          * full 8 bpp range. */
857     pixd = pixCopy(NULL, pixs);
858     cmap = pixcmapCreateLinear(d, 1 << d);
859     pixSetColormap(pixd, cmap);
860     return pixd;
861 }
862 
863 
864 /*!
865  *  pixConvertGrayToColormap8()
866  *
867  *      Input:  pixs (8 bpp grayscale)
868  *              mindepth (of pixd; valid values are 2, 4 and 8)
869  *      Return: pixd (2, 4 or 8 bpp with colormap), or null on error
870  *
871  *  Notes:
872  *      (1) Returns a copy if pixs already has a colormap.
873  *      (2) This is a lossless transformation; there is no quantization.
874  *          We compute the number of different gray values in pixs,
875  *          and construct a colormap that has exactly these values.
876  *      (3) 'mindepth' is the minimum depth of pixd.  If mindepth == 8,
877  *          pixd will always be 8 bpp.  Let the number of different
878  *          gray values in pixs be ngray.  If mindepth == 4, we attempt
879  *          to save pixd as a 4 bpp image, but if ngray > 16,
880  *          pixd must be 8 bpp.  Likewise, if mindepth == 2,
881  *          the depth of pixd will be 2 if ngray <= 4 and 4 if ngray > 4
882  *          but <= 16.
883  */
884 PIX *
pixConvertGrayToColormap8(PIX * pixs,l_int32 mindepth)885 pixConvertGrayToColormap8(PIX     *pixs,
886                           l_int32  mindepth)
887 {
888 l_int32    ncolors, w, h, depth, i, j, wpls, wpld;
889 l_int32    index, num, val, newval;
890 l_int32    array[256];
891 l_uint32  *lines, *lined, *datas, *datad;
892 NUMA      *na;
893 PIX       *pixd;
894 PIXCMAP   *cmap;
895 
896     PROCNAME("pixConvertGrayToColormap8");
897 
898     if (!pixs)
899         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
900     if (pixGetDepth(pixs) != 8)
901         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
902     if (mindepth != 2 && mindepth != 4 && mindepth != 8) {
903         L_WARNING("invalid value of mindepth; setting to 8", procName);
904         mindepth = 8;
905     }
906 
907     if (pixGetColormap(pixs)) {
908         L_WARNING("pixs already has a colormap", procName);
909         return pixCopy(NULL, pixs);
910     }
911 
912     na = pixGetGrayHistogram(pixs, 1);
913     numaGetCountRelativeToZero(na, L_GREATER_THAN_ZERO, &ncolors);
914     if (mindepth == 8 || ncolors > 16)
915         depth = 8;
916     else if (mindepth == 4 || ncolors > 4)
917         depth = 4;
918     else
919         depth = 2;
920 
921     pixGetDimensions(pixs, &w, &h, NULL);
922     pixd = pixCreate(w, h, depth);
923     cmap = pixcmapCreate(depth);
924     pixSetColormap(pixd, cmap);
925     pixCopyResolution(pixd, pixs);
926 
927     index = 0;
928     for (i = 0; i < 256; i++) {
929         numaGetIValue(na, i, &num);
930         if (num > 0) {
931             pixcmapAddColor(cmap, i, i, i);
932             array[i] = index;
933             index++;
934         }
935     }
936 
937     datas = pixGetData(pixs);
938     wpls = pixGetWpl(pixs);
939     datad = pixGetData(pixd);
940     wpld = pixGetWpl(pixd);
941     for (i = 0; i < h; i++) {
942         lines = datas + i * wpls;
943         lined = datad + i * wpld;
944         for (j = 0; j < w; j++) {
945             val = GET_DATA_BYTE(lines, j);
946             newval = array[val];
947             if (depth == 2)
948                 SET_DATA_DIBIT(lined, j, newval);
949             else if (depth == 4)
950                 SET_DATA_QBIT(lined, j, newval);
951             else  /* depth == 8 */
952                 SET_DATA_BYTE(lined, j, newval);
953         }
954     }
955 
956     numaDestroy(&na);
957     return pixd;
958 }
959 
960 
961 /*---------------------------------------------------------------------------*
962  *                Colorizing conversion from grayscale to color              *
963  *---------------------------------------------------------------------------*/
964 /*!
965  *  pixColorizeGray()
966  *
967  *      Input:  pixs (8 bpp gray; 2, 4 or 8 bpp colormapped)
968  *              color (32 bit rgba pixel)
969  *              cmapflag (1 for result to have colormap; 0 for RGB)
970  *      Return: pixd (8 bpp colormapped or 32 bpp rgb), or null on error
971  *
972  *  Notes:
973  *      (1) This applies the specific color to the grayscale image.
974  *      (2) If pixs already has a colormap, it is removed to gray
975  *          before colorizing.
976  */
977 PIX *
pixColorizeGray(PIX * pixs,l_uint32 color,l_int32 cmapflag)978 pixColorizeGray(PIX      *pixs,
979                 l_uint32  color,
980                 l_int32   cmapflag)
981 {
982 l_int32    i, j, w, h, wplt, wpld, val8;
983 l_uint32  *datad, *datat, *lined, *linet, *tab;
984 PIX       *pixt, *pixd;
985 PIXCMAP   *cmap;
986 
987     PROCNAME("pixColorizeGray");
988 
989     if (!pixs)
990         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
991     if (pixGetDepth(pixs) != 8 && !pixGetColormap(pixs))
992         return (PIX *)ERROR_PTR("pixs not 8 bpp or cmapped", procName, NULL);
993 
994     if (pixGetColormap(pixs))
995         pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
996     else
997         pixt = pixClone(pixs);
998 
999     cmap = pixcmapGrayToColor(color);
1000     if (cmapflag) {
1001         pixd = pixCopy(NULL, pixt);
1002         pixSetColormap(pixd, cmap);
1003         pixDestroy(&pixt);
1004         return pixd;
1005     }
1006 
1007         /* Make an RGB pix */
1008     pixcmapToRGBTable(cmap, &tab, NULL);
1009     pixGetDimensions(pixt, &w, &h, NULL);
1010     pixd = pixCreate(w, h, 32);
1011     pixCopyResolution(pixd, pixs);
1012     datad = pixGetData(pixd);
1013     wpld = pixGetWpl(pixd);
1014     datat = pixGetData(pixt);
1015     wplt = pixGetWpl(pixt);
1016     for (i = 0; i < h; i++) {
1017         lined = datad + i * wpld;
1018         linet = datat + i * wplt;
1019         for (j = 0; j < w; j++) {
1020             val8 = GET_DATA_BYTE(linet, j);
1021             lined[j] = tab[val8];
1022         }
1023     }
1024 
1025     pixDestroy(&pixt);
1026     pixcmapDestroy(&cmap);
1027     FREE(tab);
1028     return pixd;
1029 }
1030 
1031 
1032 /*---------------------------------------------------------------------------*
1033  *                    Conversion from RGB color to colormap                  *
1034  *---------------------------------------------------------------------------*/
1035 /*!
1036  *  pixConvertRGBToColormap()
1037  *
1038  *      Input:  pixs (32 bpp rgb)
1039  *              ditherflag (1 to dither, 0 otherwise)
1040  *      Return: pixd (2, 4 or 8 bpp with colormap), or null on error
1041  *
1042  *  Notes:
1043  *      (1) This function has two relatively simple modes of color
1044  *          quantization:
1045  *            (a) If the image is made orthographically and has not more
1046  *                than 256 'colors' at the level 4 octcube leaves,
1047  *                it is quantized nearly exactly.  The ditherflag
1048  *                is ignored.
1049  *            (b) Most natural images have more than 256 different colors;
1050  *                in that case we use adaptive octree quantization,
1051  *                with dithering if requested.
1052  *      (2) If there are not more than 256 occupied level 4 octcubes,
1053  *          the color in the colormap that represents all pixels in
1054  *          one of those octcubes is given by the first pixel that
1055  *          falls into that octcube.
1056  *      (3) If there are more than 256 colors, we use adaptive octree
1057  *          color quantization.
1058  *      (4) Dithering gives better visual results on images where
1059  *          there is a color wash (a slow variation of color), but it
1060  *          is about twice as slow and results in significantly larger
1061  *          files when losslessly compressed (e.g., into png).
1062  */
1063 PIX *
pixConvertRGBToColormap(PIX * pixs,l_int32 ditherflag)1064 pixConvertRGBToColormap(PIX     *pixs,
1065                         l_int32  ditherflag)
1066 {
1067 l_int32  ncolors;
1068 NUMA    *na;
1069 PIX     *pixd;
1070 
1071     PROCNAME("pixConvertRGBToColormap");
1072 
1073     if (!pixs)
1074         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1075     if (pixGetDepth(pixs) != 32)
1076         return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
1077 
1078         /* Get the histogram and count the number of occupied level 4
1079          * leaf octcubes.  We don't yet know if this is the number of
1080          * actual colors, but if it's not, all pixels falling into
1081          * the same leaf octcube will be assigned to the color of the
1082          * first pixel that lands there. */
1083     na = pixOctcubeHistogram(pixs, 4, &ncolors);
1084 
1085         /* If there are too many occupied leaf octcubes to be
1086          * represented directly in a colormap, fall back to octree
1087          * quantization with dithering. */
1088     if (ncolors > 256) {
1089         L_INFO("More than 256 colors; using octree quant with dithering",
1090                procName);
1091         numaDestroy(&na);
1092         return pixOctreeColorQuant(pixs, 240, ditherflag);
1093     }
1094 
1095         /* There are not more than 256 occupied leaf octcubes.
1096          * Quantize to those octcubes. */
1097     pixd = pixFewColorsOctcubeQuant2(pixs, 4, na, ncolors, NULL);
1098     numaDestroy(&na);
1099     return pixd;
1100 }
1101 
1102 
1103 /*---------------------------------------------------------------------------*
1104  *        Quantization for relatively small number of colors in source       *
1105  *---------------------------------------------------------------------------*/
1106 /*!
1107  *  pixQuantizeIfFewColors()
1108  *
1109  *      Input:  pixs (8 bpp gray or 32 bpp rgb)
1110  *              maxcolors (max number of colors allowed to be returned
1111  *                         from pixColorsForQuantization(); use 0 for default)
1112  *              mingraycolors (min number of gray levels that a grayscale
1113  *                             image is quantized to; use 0 for default)
1114  *              octlevel (for octcube quantization: 3 or 4)
1115  *              &pixd (2, 4 or 8 bpp quantized; null if too many colors)
1116  *      Return: 0 if OK, 1 on error or if pixs can't be quantized into
1117  *              a small number of colors.
1118  *
1119  *  Notes:
1120  *      (1) This is a wrapper that tests if the pix can be quantized
1121  *          with good quality using a small number of colors.  If so,
1122  *          it does the quantization, defining a colormap and using
1123  *          pixels whose value is an index into the colormap.
1124  *      (2) If the image has color, it is quantized with 8 bpp pixels.
1125  *          If the image is essentially grayscale, the pixels are
1126  *          either 4 or 8 bpp, depending on the size of the required
1127  *          colormap.
1128  *      (3) @octlevel = 3 works well for most images.  However, for best
1129  *          quality, at a cost of more colors in the colormap, use
1130  *          @octlevel = 4.
1131  *      (4) If the image already has a colormap, it returns a clone.
1132  */
1133 l_int32
pixQuantizeIfFewColors(PIX * pixs,l_int32 maxcolors,l_int32 mingraycolors,l_int32 octlevel,PIX ** ppixd)1134 pixQuantizeIfFewColors(PIX     *pixs,
1135                        l_int32  maxcolors,
1136                        l_int32  mingraycolors,
1137                        l_int32  octlevel,
1138                        PIX    **ppixd)
1139 {
1140 l_int32  d, ncolors, iscolor, graycolors;
1141 PIX     *pixg, *pixd;
1142 
1143     PROCNAME("pixQuantizeIfFewColors");
1144 
1145     if (!ppixd)
1146         return ERROR_INT("&pixd not defined", procName, 1);
1147     *ppixd = NULL;
1148     if (!pixs)
1149         return ERROR_INT("pixs not defined", procName, 1);
1150     d = pixGetDepth(pixs);
1151     if (d != 8 && d != 32)
1152         return ERROR_INT("pixs not defined", procName, 1);
1153     if (pixGetColormap(pixs) != NULL) {
1154         *ppixd = pixClone(pixs);
1155         return 0;
1156     }
1157     if (maxcolors <= 0)
1158         maxcolors = 15;  /* default */
1159     if (maxcolors > 50)
1160         L_WARNING("maxcolors > 50; very large!", procName);
1161     if (mingraycolors <= 0)
1162         mingraycolors = 10;  /* default */
1163     if (mingraycolors > 30)
1164         L_WARNING("mingraycolors > 30; very large!", procName);
1165     if (octlevel != 3 && octlevel != 4) {
1166         L_WARNING("invalid octlevel; setting to 3", procName);
1167         octlevel = 3;
1168     }
1169 
1170         /* Test the number of colors.  For color, the octcube leaves
1171          * are at level 4. */
1172     pixColorsForQuantization(pixs, 0, &ncolors, &iscolor, 0);
1173     if (ncolors > maxcolors)
1174         return ERROR_INT("too many colors", procName, 1);
1175 
1176         /* Quantize!
1177          *  (1) For color:
1178          *      If octlevel == 4, try to quantize to an octree where
1179          *      the octcube leaves are at level 4. If that fails,
1180          *      back off to level 3.
1181          *      If octlevel == 3, quantize to level 3 directly.
1182          *      For level 3, the quality is usually good enough and there
1183          *      is negligible chance of getting more than 256 colors.
1184          *  (2) For grayscale, multiply ncolors by 1.5 for extra quality,
1185          *      but use at least mingraycolors. */
1186     if (iscolor) {
1187         pixd = pixFewColorsOctcubeQuant1(pixs, octlevel);
1188         if (!pixd) {  /* backoff */
1189             pixd = pixFewColorsOctcubeQuant1(pixs, octlevel - 1);
1190             if (octlevel == 3)  /* shouldn't happen */
1191                 L_WARNING("quantized at level 2; low quality", procName);
1192         }
1193     }
1194     else  { /* image is really grayscale */
1195         if (d == 32)
1196             pixg = pixConvertRGBToLuminance(pixs);
1197         else
1198             pixg = pixClone(pixs);
1199         graycolors = L_MAX(mingraycolors, (l_int32)(1.5 * ncolors));
1200         if (graycolors < 16)
1201             pixd = pixThresholdTo4bpp(pixg, graycolors, 1);
1202         else
1203             pixd = pixThresholdOn8bpp(pixg, graycolors, 1);
1204         pixDestroy(&pixg);
1205     }
1206     *ppixd = pixd;
1207 
1208     if (!pixd)
1209         return ERROR_INT("pixd not made", procName, 1);
1210     else
1211         return 0;
1212 }
1213 
1214 
1215 
1216 /*---------------------------------------------------------------------------*
1217  *                    Conversion from 16 bpp to 8 bpp                        *
1218  *---------------------------------------------------------------------------*/
1219 /*!
1220  *  pixConvert16To8()
1221  *
1222  *      Input:  pixs (16 bpp)
1223  *              whichbyte (1 for MSB, 0 for LSB)
1224  *      Return: pixd (8 bpp), or null on error
1225  *
1226  *  Notes:
1227  *      (1) For each dest pixel, use either the MSB or LSB of each src pixel.
1228  */
1229 PIX *
pixConvert16To8(PIX * pixs,l_int32 whichbyte)1230 pixConvert16To8(PIX     *pixs,
1231                 l_int32  whichbyte)
1232 {
1233 l_uint16   dsword;
1234 l_int32    w, h, wpls, wpld, i, j;
1235 l_uint32   sword;
1236 l_uint32  *datas, *datad, *lines, *lined;
1237 PIX       *pixd;
1238 
1239     PROCNAME("pixConvert16To8");
1240 
1241     if (!pixs)
1242         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1243     if (pixGetDepth(pixs) != 16)
1244         return (PIX *)ERROR_PTR("pixs not 16 bpp", procName, NULL);
1245 
1246     pixGetDimensions(pixs, &w, &h, NULL);
1247     if ((pixd = pixCreate(w, h, 8)) == NULL)
1248         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1249     pixCopyResolution(pixd, pixs);
1250     wpls = pixGetWpl(pixs);
1251     datas = pixGetData(pixs);
1252     wpld = pixGetWpl(pixd);
1253     datad = pixGetData(pixd);
1254 
1255         /* Convert 2 pixels at a time */
1256     for (i = 0; i < h; i++) {
1257         lines = datas + i * wpls;
1258         lined = datad + i * wpld;
1259         if (whichbyte == 0) {  /* LSB */
1260             for (j = 0; j < wpls; j++) {
1261                 sword = *(lines + j);
1262                 dsword = ((sword >> 8) & 0xff00) | (sword & 0xff);
1263                 SET_DATA_TWO_BYTES(lined, j, dsword);
1264             }
1265         }
1266         else {  /* MSB */
1267             for (j = 0; j < wpls; j++) {
1268                 sword = *(lines + j);
1269                 dsword = ((sword >> 16) & 0xff00) | ((sword >> 8) & 0xff);
1270                 SET_DATA_TWO_BYTES(lined, j, dsword);
1271             }
1272         }
1273     }
1274 
1275     return pixd;
1276 }
1277 
1278 
1279 
1280 /*---------------------------------------------------------------------------*
1281  *                Conversion from grayscale to false color
1282  *---------------------------------------------------------------------------*/
1283 /*!
1284  *  pixConvertGrayToFalseColor()
1285  *
1286  *      Input:  pixs (8 or 16 bpp grayscale)
1287  *              gamma factor (0.0 or 1.0 for default; > 1.0 for brighter;
1288  *                            2.0 is quite nice)
1289  *      Return: pixd (8 bpp with colormap), or null on error
1290  *
1291  *  Notes:
1292  *      (1) For 8 bpp input, this simply adds a colormap to the input image.
1293  *      (2) For 16 bpp input, it first converts to 8 bpp and then
1294  *          adds the colormap.
1295  *      (3) The colormap is modeled after the Matlab "jet" configuration.
1296  */
1297 PIX *
pixConvertGrayToFalseColor(PIX * pixs,l_float32 gamma)1298 pixConvertGrayToFalseColor(PIX       *pixs,
1299                            l_float32  gamma)
1300 {
1301 l_int32    d, i, rval, bval, gval;
1302 l_int32   *curve;
1303 l_float32  invgamma, x;
1304 PIX       *pixd;
1305 PIXCMAP   *cmap;
1306 
1307     PROCNAME("pixConvertGrayToFalseColor");
1308 
1309     if (!pixs)
1310         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1311     d = pixGetDepth(pixs);
1312     if (d != 8 && d != 16)
1313         return (PIX *)ERROR_PTR("pixs not 8 or 16 bpp", procName, NULL);
1314 
1315     if (d == 16)
1316         pixd = pixConvert16To8(pixs, 1);
1317     else {  /* d == 8 */
1318         if (pixGetColormap(pixs))
1319             pixd = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
1320         else
1321             pixd = pixCopy(NULL, pixs);
1322     }
1323     if (!pixd)
1324         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1325     if ((cmap = pixcmapCreate(8)) == NULL)
1326         return (PIX *)ERROR_PTR("cmap not made", procName, NULL);
1327     pixSetColormap(pixd, cmap);
1328     pixCopyResolution(pixd, pixs);
1329 
1330         /* Generate curve for transition part of color map */
1331     if ((curve = (l_int32 *)CALLOC(64, sizeof(l_int32)))== NULL)
1332         return (PIX *)ERROR_PTR("curve not made", procName, NULL);
1333     if (gamma == 0.0) gamma = 1.0;
1334     invgamma = 1. / gamma;
1335     for (i = 0; i < 64; i++) {
1336         x = (l_float32)i / 64.;
1337         curve[i] = (l_int32)(255. * powf(x, invgamma) + 0.5);
1338     }
1339 
1340     for (i = 0; i < 256; i++) {
1341         if (i < 32) {
1342             rval = 0;
1343             gval = 0;
1344             bval = curve[i + 32];
1345         }
1346         else if (i < 96) {   /* 32 - 95 */
1347             rval = 0;
1348             gval = curve[i - 32];
1349             bval = 255;
1350         }
1351         else if (i < 160) {  /* 96 - 159 */
1352             rval = curve[i - 96];
1353             gval = 255;
1354             bval = curve[159 - i];
1355         }
1356         else if (i < 224) {  /* 160 - 223 */
1357             rval = 255;
1358             gval = curve[223 - i];
1359             bval = 0;
1360         }
1361         else {  /* 224 - 255 */
1362             rval = curve[287 - i];
1363             gval = 0;
1364             bval = 0;
1365         }
1366         pixcmapAddColor(cmap, rval, gval, bval);
1367     }
1368 
1369     FREE(curve);
1370     return pixd;
1371 }
1372 
1373 
1374 /*---------------------------------------------------------------------------*
1375  *         Unpacking conversion from 1 bpp to 2, 4, 8, 16 and 32 bpp         *
1376  *---------------------------------------------------------------------------*/
1377 /*!
1378  *  pixUnpackBinary()
1379  *
1380  *      Input:  pixs (1 bpp)
1381  *              depth (of destination: 2, 4, 8, 16 or 32 bpp)
1382  *              invert (0:  binary 0 --> grayscale 0
1383  *                          binary 1 --> grayscale 0xff...
1384  *                      1:  binary 0 --> grayscale 0xff...
1385  *                          binary 1 --> grayscale 0)
1386  *      Return: pixd (2, 4, 8, 16 or 32 bpp), or null on error
1387  *
1388  *  Notes:
1389  *      (1) This function calls special cases of pixConvert1To*(),
1390  *          for 2, 4, 8, 16 and 32 bpp destinations.
1391  */
1392 PIX *
pixUnpackBinary(PIX * pixs,l_int32 depth,l_int32 invert)1393 pixUnpackBinary(PIX     *pixs,
1394                 l_int32  depth,
1395                 l_int32  invert)
1396 {
1397 PIX  *pixd;
1398 
1399     PROCNAME("pixUnpackBinary");
1400 
1401     if (!pixs)
1402         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1403     if (pixGetDepth(pixs) != 1)
1404         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
1405     if (depth != 2 && depth != 4 && depth != 8 && depth != 16 && depth != 32)
1406         return (PIX *)ERROR_PTR("depth not 2, 4, 8, 16 or 32 bpp",
1407                                 procName, NULL);
1408 
1409     if (depth == 2) {
1410         if (invert == 0)
1411             pixd = pixConvert1To2(NULL, pixs, 0, 3);
1412         else  /* invert bits */
1413             pixd = pixConvert1To2(NULL, pixs, 3, 0);
1414     }
1415     else if (depth == 4) {
1416         if (invert == 0)
1417             pixd = pixConvert1To4(NULL, pixs, 0, 15);
1418         else  /* invert bits */
1419             pixd = pixConvert1To4(NULL, pixs, 15, 0);
1420     }
1421     else if (depth == 8) {
1422         if (invert == 0)
1423             pixd = pixConvert1To8(NULL, pixs, 0, 255);
1424         else  /* invert bits */
1425             pixd = pixConvert1To8(NULL, pixs, 255, 0);
1426     }
1427     else if (depth == 16) {
1428         if (invert == 0)
1429             pixd = pixConvert1To16(NULL, pixs, 0, 0xffff);
1430         else  /* invert bits */
1431             pixd = pixConvert1To16(NULL, pixs, 0xffff, 0);
1432     }
1433     else {
1434         if (invert == 0)
1435             pixd = pixConvert1To32(NULL, pixs, 0, 0xffffffff);
1436         else  /* invert bits */
1437             pixd = pixConvert1To32(NULL, pixs, 0xffffffff, 0);
1438     }
1439 
1440     return pixd;
1441 }
1442 
1443 
1444 /*!
1445  *  pixConvert1To16()
1446  *
1447  *      Input:  pixd (<optional> 16 bpp, can be null)
1448  *              pixs (1 bpp)
1449  *              val0 (16 bit value to be used for 0s in pixs)
1450  *              val1 (16 bit value to be used for 1s in pixs)
1451  *      Return: pixd (16 bpp)
1452  *
1453  *  Notes:
1454  *      (1) If pixd is null, a new pix is made.
1455  *      (2) If pixd is not null, it must be of equal width and height
1456  *          as pixs.  It is always returned.
1457  */
1458 PIX *
pixConvert1To16(PIX * pixd,PIX * pixs,l_uint16 val0,l_uint16 val1)1459 pixConvert1To16(PIX      *pixd,
1460                 PIX      *pixs,
1461                 l_uint16  val0,
1462                 l_uint16  val1)
1463 {
1464 l_int32    w, h, i, j, dibit, ndibits, wpls, wpld;
1465 l_uint16   val[2];
1466 l_uint32   index;
1467 l_uint32  *tab, *datas, *datad, *lines, *lined;
1468 
1469     PROCNAME("pixConvert1To16");
1470 
1471     if (!pixs)
1472         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1473     if (pixGetDepth(pixs) != 1)
1474         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
1475 
1476     w = pixGetWidth(pixs);
1477     h = pixGetHeight(pixs);
1478     if (pixd) {
1479         if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd))
1480             return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd);
1481         if (pixGetDepth(pixd) != 16)
1482             return (PIX *)ERROR_PTR("pixd not 16 bpp", procName, pixd);
1483     }
1484     else {
1485         if ((pixd = pixCreate(w, h, 16)) == NULL)
1486             return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1487     }
1488     pixCopyResolution(pixd, pixs);
1489 
1490         /* Use a table to convert 2 src bits at a time */
1491     if ((tab = (l_uint32 *)CALLOC(4, sizeof(l_uint32))) == NULL)
1492         return (PIX *)ERROR_PTR("tab not made", procName, NULL);
1493     val[0] = val0;
1494     val[1] = val1;
1495     for (index = 0; index < 4; index++) {
1496         tab[index] = (val[(index >> 1) & 1] << 16) | val[index & 1];
1497     }
1498 
1499     datas = pixGetData(pixs);
1500     wpls = pixGetWpl(pixs);
1501     datad = pixGetData(pixd);
1502     wpld = pixGetWpl(pixd);
1503     ndibits = (w + 1) / 2;
1504     for (i = 0; i < h; i++) {
1505         lines = datas + i * wpls;
1506         lined = datad + i * wpld;
1507         for (j = 0; j < ndibits; j++) {
1508             dibit = GET_DATA_DIBIT(lines, j);
1509             lined[j] = tab[dibit];
1510         }
1511     }
1512 
1513     FREE(tab);
1514     return pixd;
1515 }
1516 
1517 
1518 /*!
1519  *  pixConvert1To32()
1520  *
1521  *      Input:  pixd (<optional> 32 bpp, can be null)
1522  *              pixs (1 bpp)
1523  *              val0 (32 bit value to be used for 0s in pixs)
1524  *              val1 (32 bit value to be used for 1s in pixs)
1525  *      Return: pixd (32 bpp)
1526  *
1527  *  Notes:
1528  *      (1) If pixd is null, a new pix is made.
1529  *      (2) If pixd is not null, it must be of equal width and height
1530  *          as pixs.  It is always returned.
1531  */
1532 PIX *
pixConvert1To32(PIX * pixd,PIX * pixs,l_uint32 val0,l_uint32 val1)1533 pixConvert1To32(PIX      *pixd,
1534                 PIX      *pixs,
1535                 l_uint32  val0,
1536                 l_uint32  val1)
1537 {
1538 l_int32    w, h, i, j, wpls, wpld, bit;
1539 l_uint32   val[2];
1540 l_uint32  *datas, *datad, *lines, *lined;
1541 
1542     PROCNAME("pixConvert1To32");
1543 
1544     if (!pixs)
1545         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1546     if (pixGetDepth(pixs) != 1)
1547         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
1548 
1549     pixGetDimensions(pixs, &w, &h, NULL);
1550     if (pixd) {
1551         if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd))
1552             return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd);
1553         if (pixGetDepth(pixd) != 32)
1554             return (PIX *)ERROR_PTR("pixd not 32 bpp", procName, pixd);
1555     }
1556     else {
1557         if ((pixd = pixCreate(w, h, 32)) == NULL)
1558             return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1559     }
1560     pixCopyResolution(pixd, pixs);
1561 
1562     val[0] = val0;
1563     val[1] = val1;
1564     datas = pixGetData(pixs);
1565     wpls = pixGetWpl(pixs);
1566     datad = pixGetData(pixd);
1567     wpld = pixGetWpl(pixd);
1568     for (i = 0; i < h; i++) {
1569         lines = datas + i * wpls;
1570         lined = datad + i * wpld;
1571         for (j = 0; j <w; j++) {
1572             bit = GET_DATA_BIT(lines, j);
1573             lined[j] = val[bit];
1574         }
1575     }
1576 
1577     return pixd;
1578 }
1579 
1580 
1581 /*---------------------------------------------------------------------------*
1582  *                    Conversion from 1 bpp to 2 bpp                         *
1583  *---------------------------------------------------------------------------*/
1584 /*!
1585  *  pixConvert1To2Cmap()
1586  *
1587  *      Input:  pixs (1 bpp)
1588  *      Return: pixd (2 bpp, cmapped)
1589  *
1590  *  Notes:
1591  *      (1) Input 0 is mapped to (255, 255, 255); 1 is mapped to (0, 0, 0)
1592  */
1593 PIX *
pixConvert1To2Cmap(PIX * pixs)1594 pixConvert1To2Cmap(PIX  *pixs)
1595 {
1596 PIX      *pixd;
1597 PIXCMAP  *cmap;
1598 
1599     PROCNAME("pixConvert1To2Cmap");
1600 
1601     if (!pixs)
1602         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1603     if (pixGetDepth(pixs) != 1)
1604         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
1605 
1606     if ((pixd = pixConvert1To2(NULL, pixs, 0, 1)) == NULL)
1607         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1608     cmap = pixcmapCreate(2);
1609     pixcmapAddColor(cmap, 255, 255, 255);
1610     pixcmapAddColor(cmap, 0, 0, 0);
1611     pixSetColormap(pixd, cmap);
1612 
1613     return pixd;
1614 }
1615 
1616 
1617 /*!
1618  *  pixConvert1To2()
1619  *
1620  *      Input:  pixd (<optional> 2 bpp, can be null)
1621  *              pixs (1 bpp)
1622  *              val0 (2 bit value to be used for 0s in pixs)
1623  *              val1 (2 bit value to be used for 1s in pixs)
1624  *      Return: pixd (2 bpp)
1625  *
1626  *  Notes:
1627  *      (1) If pixd is null, a new pix is made.
1628  *      (2) If pixd is not null, it must be of equal width and height
1629  *          as pixs.  It is always returned.
1630  *      (3) A simple unpacking might use val0 = 0 and val1 = 3.
1631  *      (4) If you want a colormapped pixd, use pixConvert1To2Cmap().
1632  */
1633 PIX *
pixConvert1To2(PIX * pixd,PIX * pixs,l_int32 val0,l_int32 val1)1634 pixConvert1To2(PIX     *pixd,
1635                PIX     *pixs,
1636                l_int32  val0,
1637                l_int32  val1)
1638 {
1639 l_int32    w, h, i, j, byteval, nbytes, wpls, wpld;
1640 l_uint8    val[2];
1641 l_uint32   index;
1642 l_uint16  *tab;
1643 l_uint32  *datas, *datad, *lines, *lined;
1644 
1645     PROCNAME("pixConvert1To2");
1646 
1647     if (!pixs)
1648         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
1649     if (pixGetDepth(pixs) != 1)
1650         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
1651 
1652     pixGetDimensions(pixs, &w, &h, NULL);
1653     if (pixd) {
1654         if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd))
1655             return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd);
1656         if (pixGetDepth(pixd) != 2)
1657             return (PIX *)ERROR_PTR("pixd not 2 bpp", procName, pixd);
1658     }
1659     else {
1660         if ((pixd = pixCreate(w, h, 2)) == NULL)
1661             return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1662     }
1663     pixCopyResolution(pixd, pixs);
1664 
1665         /* Use a table to convert 8 src bits to 16 dest bits */
1666     if ((tab = (l_uint16 *)CALLOC(256, sizeof(l_uint16))) == NULL)
1667         return (PIX *)ERROR_PTR("tab not made", procName, NULL);
1668     val[0] = val0;
1669     val[1] = val1;
1670     for (index = 0; index < 256; index++) {
1671         tab[index] = (val[(index >> 7) & 1] << 14) |
1672                      (val[(index >> 6) & 1] << 12) |
1673                      (val[(index >> 5) & 1] << 10) |
1674                      (val[(index >> 4) & 1] << 8) |
1675                      (val[(index >> 3) & 1] << 6) |
1676                      (val[(index >> 2) & 1] << 4) |
1677                      (val[(index >> 1) & 1] << 2) | val[index & 1];
1678     }
1679 
1680     datas = pixGetData(pixs);
1681     wpls = pixGetWpl(pixs);
1682     datad = pixGetData(pixd);
1683     wpld = pixGetWpl(pixd);
1684     nbytes = (w + 7) / 8;
1685     for (i = 0; i < h; i++) {
1686         lines = datas + i * wpls;
1687         lined = datad + i * wpld;
1688         for (j = 0; j < nbytes; j++) {
1689             byteval = GET_DATA_BYTE(lines, j);
1690             SET_DATA_TWO_BYTES(lined, j, tab[byteval]);
1691         }
1692     }
1693 
1694     FREE(tab);
1695     return pixd;
1696 }
1697 
1698 
1699 /*---------------------------------------------------------------------------*
1700  *                    Conversion from 1 bpp to 4 bpp                         *
1701  *---------------------------------------------------------------------------*/
1702 /*!
1703  *  pixConvert1To4Cmap()
1704  *
1705  *      Input:  pixs (1 bpp)
1706  *      Return: pixd (4 bpp, cmapped)
1707  *
1708  *  Notes:
1709  *      (1) Input 0 is mapped to (255, 255, 255); 1 is mapped to (0, 0, 0)
1710  */
1711 PIX *
pixConvert1To4Cmap(PIX * pixs)1712 pixConvert1To4Cmap(PIX  *pixs)
1713 {
1714 PIX      *pixd;
1715 PIXCMAP  *cmap;
1716 
1717     PROCNAME("pixConvert1To4Cmap");
1718 
1719     if (!pixs)
1720         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1721     if (pixGetDepth(pixs) != 1)
1722         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
1723 
1724     if ((pixd = pixConvert1To4(NULL, pixs, 0, 1)) == NULL)
1725         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1726     cmap = pixcmapCreate(4);
1727     pixcmapAddColor(cmap, 255, 255, 255);
1728     pixcmapAddColor(cmap, 0, 0, 0);
1729     pixSetColormap(pixd, cmap);
1730 
1731     return pixd;
1732 }
1733 
1734 
1735 /*!
1736  *  pixConvert1To4()
1737  *
1738  *      Input:  pixd (<optional> 4 bpp, can be null)
1739  *              pixs (1 bpp)
1740  *              val0 (4 bit value to be used for 0s in pixs)
1741  *              val1 (4 bit value to be used for 1s in pixs)
1742  *      Return: pixd (4 bpp)
1743  *
1744  *  Notes:
1745  *      (1) If pixd is null, a new pix is made.
1746  *      (2) If pixd is not null, it must be of equal width and height
1747  *          as pixs.  It is always returned.
1748  *      (3) A simple unpacking might use val0 = 0 and val1 = 15, or v.v.
1749  *      (4) If you want a colormapped pixd, use pixConvert1To4Cmap().
1750  */
1751 PIX *
pixConvert1To4(PIX * pixd,PIX * pixs,l_int32 val0,l_int32 val1)1752 pixConvert1To4(PIX     *pixd,
1753                PIX     *pixs,
1754                l_int32  val0,
1755                l_int32  val1)
1756 {
1757 l_int32    w, h, i, j, byteval, nbytes, wpls, wpld;
1758 l_uint8    val[2];
1759 l_uint32   index;
1760 l_uint32  *tab, *datas, *datad, *lines, *lined;
1761 
1762     PROCNAME("pixConvert1To4");
1763 
1764     if (!pixs)
1765         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
1766     if (pixGetDepth(pixs) != 1)
1767         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
1768 
1769     pixGetDimensions(pixs, &w, &h, NULL);
1770     if (pixd) {
1771         if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd))
1772             return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd);
1773         if (pixGetDepth(pixd) != 4)
1774             return (PIX *)ERROR_PTR("pixd not 4 bpp", procName, pixd);
1775     }
1776     else {
1777         if ((pixd = pixCreate(w, h, 4)) == NULL)
1778             return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1779     }
1780     pixCopyResolution(pixd, pixs);
1781 
1782         /* Use a table to convert 8 src bits to 32 bit dest word */
1783     if ((tab = (l_uint32 *)CALLOC(256, sizeof(l_uint32))) == NULL)
1784         return (PIX *)ERROR_PTR("tab not made", procName, NULL);
1785     val[0] = val0;
1786     val[1] = val1;
1787     for (index = 0; index < 256; index++) {
1788         tab[index] = (val[(index >> 7) & 1] << 28) |
1789                      (val[(index >> 6) & 1] << 24) |
1790                      (val[(index >> 5) & 1] << 20) |
1791                      (val[(index >> 4) & 1] << 16) |
1792                      (val[(index >> 3) & 1] << 12) |
1793                      (val[(index >> 2) & 1] << 8) |
1794                      (val[(index >> 1) & 1] << 4) | val[index & 1];
1795     }
1796 
1797     datas = pixGetData(pixs);
1798     wpls = pixGetWpl(pixs);
1799     datad = pixGetData(pixd);
1800     wpld = pixGetWpl(pixd);
1801     nbytes = (w + 7) / 8;
1802     for (i = 0; i < h; i++) {
1803         lines = datas + i * wpls;
1804         lined = datad + i * wpld;
1805         for (j = 0; j < nbytes; j++) {
1806             byteval = GET_DATA_BYTE(lines, j);
1807             lined[j] = tab[byteval];
1808         }
1809     }
1810 
1811     FREE(tab);
1812     return pixd;
1813 }
1814 
1815 
1816 /*---------------------------------------------------------------------------*
1817  *               Conversion from 1, 2 and 4 bpp to 8 bpp                     *
1818  *---------------------------------------------------------------------------*/
1819 /*!
1820  *  pixConvert1To8()
1821  *
1822  *      Input:  pixd (<optional> 8 bpp, can be null)
1823  *              pixs (1 bpp)
1824  *              val0 (8 bit value to be used for 0s in pixs)
1825  *              val1 (8 bit value to be used for 1s in pixs)
1826  *      Return: pixd (8 bpp)
1827  *
1828  *  Notes:
1829  *      (1) If pixd is null, a new pix is made.
1830  *      (2) If pixd is not null, it must be of equal width and height
1831  *          as pixs.  It is always returned.
1832  *      (3) A simple unpacking might use val0 = 0 and val1 = 255, or v.v.
1833  *      (4) In a typical application where one wants to use a colormap
1834  *          with the dest, you can use val0 = 0, val1 = 1 to make a
1835  *          non-cmapped 8 bpp pix, and then make a colormap and set 0
1836  *          and 1 to the desired colors.  Here is an example:
1837  *             pixd = pixConvert1To8(NULL, pixs, 0, 1);
1838  *             cmap = pixCreate(8);
1839  *             pixcmapAddColor(cmap, 255, 255, 255);
1840  *             pixcmapAddColor(cmap, 0, 0, 0);
1841  *             pixSetColormap(pixd, cmap);
1842  */
1843 PIX *
pixConvert1To8(PIX * pixd,PIX * pixs,l_uint8 val0,l_uint8 val1)1844 pixConvert1To8(PIX     *pixd,
1845                PIX     *pixs,
1846                l_uint8  val0,
1847                l_uint8  val1)
1848 {
1849 l_int32    w, h, i, j, qbit, nqbits, wpls, wpld;
1850 l_uint8    val[2];
1851 l_uint32   index;
1852 l_uint32  *tab, *datas, *datad, *lines, *lined;
1853 
1854     PROCNAME("pixConvert1To8");
1855 
1856     if (!pixs)
1857         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
1858     if (pixGetDepth(pixs) != 1)
1859         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
1860 
1861     pixGetDimensions(pixs, &w, &h, NULL);
1862     if (pixd) {
1863         if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd))
1864             return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd);
1865         if (pixGetDepth(pixd) != 8)
1866             return (PIX *)ERROR_PTR("pixd not 8 bpp", procName, pixd);
1867     }
1868     else {
1869         if ((pixd = pixCreate(w, h, 8)) == NULL)
1870             return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1871     }
1872     pixCopyResolution(pixd, pixs);
1873 
1874         /* Use a table to convert 4 src bits at a time */
1875     if ((tab = (l_uint32 *)CALLOC(16, sizeof(l_uint32))) == NULL)
1876         return (PIX *)ERROR_PTR("tab not made", procName, NULL);
1877     val[0] = val0;
1878     val[1] = val1;
1879     for (index = 0; index < 16; index++) {
1880         tab[index] = (val[(index >> 3) & 1] << 24) |
1881                      (val[(index >> 2) & 1] << 16) |
1882                      (val[(index >> 1) & 1] << 8) | val[index & 1];
1883     }
1884 
1885     datas = pixGetData(pixs);
1886     wpls = pixGetWpl(pixs);
1887     datad = pixGetData(pixd);
1888     wpld = pixGetWpl(pixd);
1889     nqbits = (w + 3) / 4;
1890     for (i = 0; i < h; i++) {
1891         lines = datas + i * wpls;
1892         lined = datad + i * wpld;
1893         for (j = 0; j < nqbits; j++) {
1894             qbit = GET_DATA_QBIT(lines, j);
1895             lined[j] = tab[qbit];
1896         }
1897     }
1898 
1899     FREE(tab);
1900     return pixd;
1901 }
1902 
1903 
1904 /*!
1905  *  pixConvert2To8()
1906  *
1907  *      Input:  pixs (2 bpp)
1908  *              val0 (8 bit value to be used for 00 in pixs)
1909  *              val1 (8 bit value to be used for 01 in pixs)
1910  *              val2 (8 bit value to be used for 10 in pixs)
1911  *              val3 (8 bit value to be used for 11 in pixs)
1912  *              cmapflag (TRUE if pixd is to have a colormap; FALSE otherwise)
1913  *      Return: pixd (8 bpp), or null on error
1914  *
1915  *  Notes:
1916  *      - A simple unpacking might use val0 = 0,
1917  *        val1 = 85 (0x55), val2 = 170 (0xaa), val3 = 255.
1918  *      - If cmapflag is TRUE:
1919  *          - The 8 bpp image is made with a colormap.
1920  *          - If pixs has a colormap, the input values are ignored and
1921  *            the 8 bpp image is made using the colormap
1922  *          - If pixs does not have a colormap, the input values are
1923  *            used to build the colormap.
1924  *      - If cmapflag is FALSE:
1925  *          - The 8 bpp image is made without a colormap.
1926  *          - If pixs has a colormap, the input values are ignored,
1927  *            the colormap is removed, and the values stored in the 8 bpp
1928  *            image are from the colormap.
1929  *          - If pixs does not have a colormap, the input values are
1930  *            used to populate the 8 bpp image.
1931  */
1932 PIX *
pixConvert2To8(PIX * pixs,l_uint8 val0,l_uint8 val1,l_uint8 val2,l_uint8 val3,l_int32 cmapflag)1933 pixConvert2To8(PIX     *pixs,
1934                l_uint8  val0,
1935                l_uint8  val1,
1936                l_uint8  val2,
1937                l_uint8  val3,
1938                l_int32  cmapflag)
1939 {
1940 l_int32    w, h, i, j, nbytes, wpls, wpld, dibit, ncolor;
1941 l_int32    rval, gval, bval, byte;
1942 l_uint8    val[4];
1943 l_uint32   index;
1944 l_uint32  *tab, *datas, *datad, *lines, *lined;
1945 PIX       *pixd;
1946 PIXCMAP   *cmaps, *cmapd;
1947 
1948     PROCNAME("pixConvert2To8");
1949 
1950     if (!pixs)
1951         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1952     if (pixGetDepth(pixs) != 2)
1953         return (PIX *)ERROR_PTR("pixs not 2 bpp", procName, NULL);
1954 
1955     cmaps = pixGetColormap(pixs);
1956     if (cmaps && cmapflag == FALSE)
1957         return pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
1958 
1959     pixGetDimensions(pixs, &w, &h, NULL);
1960     if ((pixd = pixCreate(w, h, 8)) == NULL)
1961         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1962     pixCopyResolution(pixd, pixs);
1963     datas = pixGetData(pixs);
1964     wpls = pixGetWpl(pixs);
1965     datad = pixGetData(pixd);
1966     wpld = pixGetWpl(pixd);
1967 
1968     if (cmapflag == TRUE) {  /* pixd will have a colormap */
1969         cmapd = pixcmapCreate(8);  /* 8 bpp standard cmap */
1970         if (cmaps) {  /* use the existing colormap from pixs */
1971             ncolor = pixcmapGetCount(cmaps);
1972             for (i = 0; i < ncolor; i++) {
1973                 pixcmapGetColor(cmaps, i, &rval, &gval, &bval);
1974                 pixcmapAddColor(cmapd, rval, gval, bval);
1975             }
1976         }
1977         else {  /* make a colormap from the input values */
1978             pixcmapAddColor(cmapd, val0, val0, val0);
1979             pixcmapAddColor(cmapd, val1, val1, val1);
1980             pixcmapAddColor(cmapd, val2, val2, val2);
1981             pixcmapAddColor(cmapd, val3, val3, val3);
1982         }
1983         pixSetColormap(pixd, cmapd);
1984         for (i = 0; i < h; i++) {
1985             lines = datas + i * wpls;
1986             lined = datad + i * wpld;
1987             for (j = 0; j < w; j++) {
1988                 dibit = GET_DATA_DIBIT(lines, j);
1989                 SET_DATA_BYTE(lined, j, dibit);
1990             }
1991         }
1992         return pixd;
1993     }
1994 
1995         /* Last case: no colormap in either pixs or pixd.
1996          * Use input values and build a table to convert 1 src byte
1997          * (4 src pixels) at a time */
1998     if ((tab = (l_uint32 *)CALLOC(256, sizeof(l_uint32))) == NULL)
1999         return (PIX *)ERROR_PTR("tab not made", procName, NULL);
2000     val[0] = val0;
2001     val[1] = val1;
2002     val[2] = val2;
2003     val[3] = val3;
2004     for (index = 0; index < 256; index++) {
2005         tab[index] = (val[(index >> 6) & 3] << 24) |
2006                      (val[(index >> 4) & 3] << 16) |
2007                      (val[(index >> 2) & 3] << 8) | val[index & 3];
2008     }
2009 
2010     nbytes = (w + 3) / 4;
2011     for (i = 0; i < h; i++) {
2012         lines = datas + i * wpls;
2013         lined = datad + i * wpld;
2014         for (j = 0; j < nbytes; j++) {
2015             byte = GET_DATA_BYTE(lines, j);
2016             lined[j] = tab[byte];
2017         }
2018     }
2019 
2020     FREE(tab);
2021     return pixd;
2022 }
2023 
2024 
2025 /*!
2026  *  pixConvert4To8()
2027  *
2028  *      Input:  pixs (4 bpp)
2029  *              cmapflag (TRUE if pixd is to have a colormap; FALSE otherwise)
2030  *      Return: pixd (8 bpp), or null on error
2031  *
2032  *  Notes:
2033  *      - If cmapflag is TRUE:
2034  *          - pixd is made with a colormap.
2035  *          - If pixs has a colormap, it is copied and the colormap
2036  *            index values are placed in pixd.
2037  *          - If pixs does not have a colormap, a colormap with linear
2038  *            trc is built and the pixel values in pixs are placed in
2039  *            pixd as colormap index values.
2040  *      - If cmapflag is FALSE:
2041  *          - pixd is made without a colormap.
2042  *          - If pixs has a colormap, it is removed and the values stored
2043  *            in pixd are from the colormap (converted to gray).
2044  *          - If pixs does not have a colormap, the pixel values in pixs
2045  *            are used, with shift replication, to populate pixd.
2046  */
2047 PIX *
pixConvert4To8(PIX * pixs,l_int32 cmapflag)2048 pixConvert4To8(PIX     *pixs,
2049                l_int32  cmapflag)
2050 {
2051 l_int32    w, h, i, j, wpls, wpld, ncolor;
2052 l_int32    rval, gval, bval, byte, qbit;
2053 l_uint32  *datas, *datad, *lines, *lined;
2054 PIX       *pixd;
2055 PIXCMAP   *cmaps, *cmapd;
2056 
2057     PROCNAME("pixConvert4To8");
2058 
2059     if (!pixs)
2060         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2061     if (pixGetDepth(pixs) != 4)
2062         return (PIX *)ERROR_PTR("pixs not 4 bpp", procName, NULL);
2063 
2064     cmaps = pixGetColormap(pixs);
2065     if (cmaps && cmapflag == FALSE)
2066         return pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
2067 
2068     pixGetDimensions(pixs, &w, &h, NULL);
2069     if ((pixd = pixCreate(w, h, 8)) == NULL)
2070         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2071     pixCopyResolution(pixd, pixs);
2072     datas = pixGetData(pixs);
2073     wpls = pixGetWpl(pixs);
2074     datad = pixGetData(pixd);
2075     wpld = pixGetWpl(pixd);
2076 
2077     if (cmapflag == TRUE) {  /* pixd will have a colormap */
2078         cmapd = pixcmapCreate(8);
2079         if (cmaps) {  /* use the existing colormap from pixs */
2080             ncolor = pixcmapGetCount(cmaps);
2081             for (i = 0; i < ncolor; i++) {
2082                 pixcmapGetColor(cmaps, i, &rval, &gval, &bval);
2083                 pixcmapAddColor(cmapd, rval, gval, bval);
2084             }
2085         }
2086         else {  /* make a colormap with a linear trc */
2087             for (i = 0; i < 16; i++)
2088                 pixcmapAddColor(cmapd, 17 * i, 17 * i, 17 * i);
2089         }
2090         pixSetColormap(pixd, cmapd);
2091         for (i = 0; i < h; i++) {
2092             lines = datas + i * wpls;
2093             lined = datad + i * wpld;
2094             for (j = 0; j < w; j++) {
2095                 qbit = GET_DATA_QBIT(lines, j);
2096                 SET_DATA_BYTE(lined, j, qbit);
2097             }
2098         }
2099         return pixd;
2100     }
2101 
2102         /* Last case: no colormap in either pixs or pixd.
2103          * Replicate the qbit value into 8 bits. */
2104     for (i = 0; i < h; i++) {
2105         lines = datas + i * wpls;
2106         lined = datad + i * wpld;
2107         for (j = 0; j < w; j++) {
2108             qbit = GET_DATA_QBIT(lines, j);
2109             byte = (qbit << 4) | qbit;
2110             SET_DATA_BYTE(lined, j, byte);
2111         }
2112     }
2113     return pixd;
2114 }
2115 
2116 
2117 
2118 /*---------------------------------------------------------------------------*
2119  *               Unpacking conversion from 8 bpp to 16 bpp                   *
2120  *---------------------------------------------------------------------------*/
2121 /*!
2122  *  pixConvert8To16()
2123  *
2124  *      Input:  pixs (8 bpp; colormap removed to gray)
2125  *              leftshift (number of bits: 0 is no shift;
2126  *                         8 replicates in MSB and LSB of dest)
2127  *      Return: pixd (16 bpp), or null on error
2128  *
2129  *  Notes:
2130  *      (1) For left shift of 8, the 8 bit value is replicated in both
2131  *          the MSB and the LSB of the pixels in pixd.  That way, we get
2132  *          proportional mapping, with a correct map from 8 bpp white
2133  *          (0xff) to 16 bpp white (0xffff).
2134  */
2135 PIX *
pixConvert8To16(PIX * pixs,l_int32 leftshift)2136 pixConvert8To16(PIX     *pixs,
2137                 l_int32  leftshift)
2138 {
2139 l_int32    i, j, w, h, d, wplt, wpld, val;
2140 l_uint32  *datat, *datad, *linet, *lined;
2141 PIX       *pixt, *pixd;
2142 
2143     PROCNAME("pixConvert8To16");
2144 
2145     if (!pixs)
2146         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2147     pixGetDimensions(pixs, &w, &h, &d);
2148     if (d != 8)
2149         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
2150     if (leftshift < 0 || leftshift > 8)
2151         return (PIX *)ERROR_PTR("leftshift not in [0 ... 8]", procName, NULL);
2152 
2153     if (pixGetColormap(pixs) != NULL)
2154         pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
2155     else
2156         pixt = pixClone(pixs);
2157 
2158     pixd = pixCreate(w, h, 16);
2159     datat = pixGetData(pixt);
2160     datad = pixGetData(pixd);
2161     wplt = pixGetWpl(pixt);
2162     wpld = pixGetWpl(pixd);
2163     for (i = 0; i < h; i++) {
2164         linet = datat + i * wplt;
2165         lined = datad + i * wpld;
2166         for (j = 0; j < w; j++) {
2167             val = GET_DATA_BYTE(linet, j);
2168             if (leftshift == 8)
2169                 val = val | (val << leftshift);
2170             else
2171                 val <<= leftshift;
2172             SET_DATA_TWO_BYTES(lined, j, val);
2173         }
2174     }
2175 
2176     pixDestroy(&pixt);
2177     return pixd;
2178 }
2179 
2180 
2181 
2182 /*---------------------------------------------------------------------------*
2183  *                     Top-level conversion to 1 bpp                         *
2184  *---------------------------------------------------------------------------*/
2185 /*!
2186  *  pixConvertTo1()
2187  *
2188  *      Input:  pixs (1, 2, 4, 8, 16 or 32 bpp)
2189  *              threshold (for final binarization, relative to 8 bpp)
2190  *      Return: pixd (1 bpp), or null on error
2191  *
2192  *  Notes:
2193  *      (1) This is a top-level function, with simple default values
2194  *          used in pixConvertTo8() if unpacking is necessary.
2195  *      (2) Any existing colormap is removed.
2196  *      (3) If the input image has 1 bpp and no colormap, the operation is
2197  *          lossless and a copy is returned.
2198  */
2199 PIX *
pixConvertTo1(PIX * pixs,l_int32 threshold)2200 pixConvertTo1(PIX     *pixs,
2201               l_int32  threshold)
2202 {
2203 l_int32   d, color0, color1, rval, gval, bval;
2204 PIX      *pixg, *pixd;
2205 PIXCMAP  *cmap;
2206 
2207     PROCNAME("pixConvertTo1");
2208 
2209     if (!pixs)
2210         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2211     d = pixGetDepth(pixs);
2212     if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
2213         return (PIX *)ERROR_PTR("depth not {1,2,4,8,16,32}", procName, NULL);
2214 
2215     cmap = pixGetColormap(pixs);
2216     if (d == 1) {
2217         if (!cmap)
2218             return pixCopy(NULL, pixs);
2219         else {  /* strip the colormap off, and invert if reasonable
2220                    for standard binary photometry.  */
2221             pixcmapGetColor(cmap, 0, &rval, &gval, &bval);
2222             color0 = rval + gval + bval;
2223             pixcmapGetColor(cmap, 1, &rval, &gval, &bval);
2224             color1 = rval + gval + bval;
2225             pixd = pixCopy(NULL, pixs);
2226             pixDestroyColormap(pixd);
2227             if (color1 > color0)
2228                 pixInvert(pixd, pixd);
2229             return pixd;
2230         }
2231     }
2232 
2233         /* For all other depths, use 8 bpp as an intermediary */
2234     pixg = pixConvertTo8(pixs, FALSE);
2235     pixd = pixThresholdToBinary(pixg, threshold);
2236     pixDestroy(&pixg);
2237     return pixd;
2238 }
2239 
2240 
2241 /*!
2242  *  pixConvertTo1BySampling()
2243  *
2244  *      Input:  pixs (1, 2, 4, 8, 16 or 32 bpp)
2245  *              factor (submsampling factor; integer >= 1)
2246  *              threshold (for final binarization, relative to 8 bpp)
2247  *      Return: pixd (1 bpp), or null on error
2248  *
2249  *  Notes:
2250  *      (1) This is a fast, quick/dirty, top-level converter.
2251  *      (2) See pixConvertTo1() for default values.
2252  */
2253 PIX *
pixConvertTo1BySampling(PIX * pixs,l_int32 factor,l_int32 threshold)2254 pixConvertTo1BySampling(PIX     *pixs,
2255                         l_int32  factor,
2256                         l_int32  threshold)
2257 {
2258 l_float32  scalefactor;
2259 PIX       *pixt, *pixd;
2260 
2261     PROCNAME("pixConvertTo1BySampling");
2262 
2263     if (!pixs)
2264         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2265     if (factor < 1)
2266         return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
2267 
2268     scalefactor = 1. / (l_float32)factor;
2269     pixt = pixScaleBySampling(pixs, scalefactor, scalefactor);
2270     pixd = pixConvertTo1(pixt, threshold);
2271 
2272     pixDestroy(&pixt);
2273     return pixd;
2274 }
2275 
2276 
2277 /*---------------------------------------------------------------------------*
2278  *                     Top-level conversion to 8 bpp                         *
2279  *---------------------------------------------------------------------------*/
2280 /*!
2281  *  pixConvertTo8()
2282  *
2283  *      Input:  pixs (1, 2, 4, 8, 16 or 32 bpp)
2284  *              cmapflag (TRUE if pixd is to have a colormap; FALSE otherwise)
2285  *      Return: pixd (8 bpp), or null on error
2286  *
2287  *  Notes:
2288  *      (1) This is a top-level function, with simple default values
2289  *          for unpacking.
2290  *      (2) The result, pixd, is made with a colormap if specified.
2291  *      (3) If d == 8, and cmapflag matches the existence of a cmap
2292  *          in pixs, the operation is lossless and it returns a copy.
2293  *      (4) The default values used are:
2294  *          - 1 bpp: val0 = 255, val1 = 0
2295  *          - 2 bpp: 4 bpp:  even increments over dynamic range
2296  *          - 8 bpp: lossless if cmap matches cmapflag
2297  *          - 16 bpp: use most significant byte
2298  *      (5) If 32 bpp RGB, this is converted to gray.  If you want
2299  *          to do color quantization, you must specify the type
2300  *          explicitly, using the color quantization code.
2301  */
2302 PIX *
pixConvertTo8(PIX * pixs,l_int32 cmapflag)2303 pixConvertTo8(PIX     *pixs,
2304               l_int32  cmapflag)
2305 {
2306 l_int32   d;
2307 PIX      *pixd;
2308 PIXCMAP  *cmap;
2309 
2310     PROCNAME("pixConvertTo8");
2311 
2312     if (!pixs)
2313         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2314     d = pixGetDepth(pixs);
2315     if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
2316         return (PIX *)ERROR_PTR("depth not {1,2,4,8,16,32}", procName, NULL);
2317 
2318     if (d == 1) {
2319         if (!cmapflag)
2320             return pixConvert1To8(NULL, pixs, 255, 0);
2321         else {
2322             pixd = pixConvert1To8(NULL, pixs, 0, 1);
2323             cmap = pixcmapCreate(8);
2324             pixcmapAddColor(cmap, 255, 255, 255);
2325             pixcmapAddColor(cmap, 0, 0, 0);
2326             pixSetColormap(pixd, cmap);
2327             return pixd;
2328         }
2329     }
2330     else if (d == 2)
2331         return pixConvert2To8(pixs, 0, 85, 170, 255, cmapflag);
2332     else if (d == 4)
2333         return pixConvert4To8(pixs, cmapflag);
2334     else if (d == 8) {
2335         cmap = pixGetColormap(pixs);
2336         if ((cmap && cmapflag) || (!cmap && !cmapflag))
2337             return pixCopy(NULL, pixs);
2338         else if (cmap)  /* !cmapflag */
2339             return pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
2340         else {  /* !cmap && cmapflag; add colormap to pixd */
2341             pixd = pixCopy(NULL, pixs);
2342             pixAddGrayColormap8(pixd);
2343             return pixd;
2344         }
2345     }
2346     else if (d == 16) {
2347         pixd = pixConvert16To8(pixs, 1);
2348         if (cmapflag)
2349             pixAddGrayColormap8(pixd);
2350         return pixd;
2351     }
2352     else { /* d == 32 */
2353         pixd = pixConvertRGBToLuminance(pixs);
2354         if (cmapflag)
2355             pixAddGrayColormap8(pixd);
2356         return pixd;
2357     }
2358 }
2359 
2360 
2361 /*!
2362  *  pixConvertTo8BySampling()
2363  *
2364  *      Input:  pixs (1, 2, 4, 8, 16 or 32 bpp)
2365  *              factor (submsampling factor; integer >= 1)
2366  *              cmapflag (TRUE if pixd is to have a colormap; FALSE otherwise)
2367  *      Return: pixd (8 bpp), or null on error
2368  *
2369  *  Notes:
2370  *      (1) This is a fast, quick/dirty, top-level converter.
2371  *      (2) See pixConvertTo8() for default values.
2372  */
2373 PIX *
pixConvertTo8BySampling(PIX * pixs,l_int32 factor,l_int32 cmapflag)2374 pixConvertTo8BySampling(PIX     *pixs,
2375                         l_int32  factor,
2376                         l_int32  cmapflag)
2377 {
2378 l_float32  scalefactor;
2379 PIX       *pixt, *pixd;
2380 
2381     PROCNAME("pixConvertTo8BySampling");
2382 
2383     if (!pixs)
2384         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2385     if (factor < 1)
2386         return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
2387 
2388     scalefactor = 1. / (l_float32)factor;
2389     pixt = pixScaleBySampling(pixs, scalefactor, scalefactor);
2390     pixd = pixConvertTo8(pixt, cmapflag);
2391 
2392     pixDestroy(&pixt);
2393     return pixd;
2394 }
2395 
2396 
2397 /*---------------------------------------------------------------------------*
2398  *                    Top-level conversion to 16 bpp                         *
2399  *---------------------------------------------------------------------------*/
2400 /*!
2401  *  pixConvertTo16()
2402  *
2403  *      Input:  pixs (1, 8 bpp)
2404  *      Return: pixd (16 bpp), or null on error
2405  *
2406  *  Usage: Top-level function, with simple default values for unpacking.
2407  *      1 bpp:  val0 = 0xffff, val1 = 0
2408  *      8 bpp:  replicates the 8 bit value in both the MSB and LSB
2409  *              of the 16 bit pixel.
2410  */
2411 PIX *
pixConvertTo16(PIX * pixs)2412 pixConvertTo16(PIX  *pixs)
2413 {
2414 l_int32  d;
2415 
2416     PROCNAME("pixConvertTo16");
2417 
2418     if (!pixs)
2419         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2420 
2421     d = pixGetDepth(pixs);
2422     if (d == 1)
2423         return pixConvert1To16(NULL, pixs, 0xffff, 0);
2424     else if (d == 8)
2425         return pixConvert8To16(pixs, 8);
2426     else
2427         return (PIX *)ERROR_PTR("src depth not 1 or 8 bpp", procName, NULL);
2428 }
2429 
2430 
2431 
2432 /*---------------------------------------------------------------------------*
2433  *                    Top-level conversion to 32 bpp                         *
2434  *---------------------------------------------------------------------------*/
2435 /*!
2436  *  pixConvertTo32()
2437  *
2438  *      Input:  pixs (1, 2, 4, 8, 16 or 32 bpp)
2439  *      Return: pixd (32 bpp), or null on error
2440  *
2441  *  Usage: Top-level function, with simple default values for unpacking.
2442  *      1 bpp:  val0 = 255, val1 = 0
2443  *              and then replication into R, G and B components
2444  *      2 bpp:  if colormapped, use the colormap values; otherwise,
2445  *              use val0 = 0, val1 = 0x55, val2 = 0xaa, val3 = 255
2446  *              and replicate gray into R, G and B components
2447  *      4 bpp:  if colormapped, use the colormap values; otherwise,
2448  *              replicate 2 nybs into a byte, and then into R,G,B components
2449  *      8 bpp:  if colormapped, use the colormap values; otherwise,
2450  *              replicate gray values into R, G and B components
2451  *      16 bpp:  replicate MSB into R, G and B components
2452  *      32 bpp:  makes a copy
2453  *
2454  *  Notes:
2455  *      (1) Implicit assumption about RGB component ordering.
2456  */
2457 PIX *
pixConvertTo32(PIX * pixs)2458 pixConvertTo32(PIX  *pixs)
2459 {
2460 l_int32  d;
2461 PIX     *pixt, *pixd;
2462 
2463     PROCNAME("pixConvertTo32");
2464 
2465     if (!pixs)
2466         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2467 
2468     d = pixGetDepth(pixs);
2469     if (d == 1)
2470         return pixConvert1To32(NULL, pixs, 0xffffffff, 0);
2471     else if (d == 2) {
2472         pixt = pixConvert2To8(pixs, 0, 85, 170, 255, TRUE);
2473         pixd = pixConvert8To32(pixt);
2474         pixDestroy(&pixt);
2475         return pixd;
2476     }
2477     else if (d == 4) {
2478         pixt = pixConvert4To8(pixs, TRUE);
2479         pixd = pixConvert8To32(pixt);
2480         pixDestroy(&pixt);
2481         return pixd;
2482     }
2483     else if (d == 8)
2484         return pixConvert8To32(pixs);
2485     else if (d == 16) {
2486         pixt = pixConvert16To8(pixs, 1);
2487         pixd = pixConvert8To32(pixt);
2488         pixDestroy(&pixt);
2489         return pixd;
2490     }
2491     else if (d == 32)
2492         return pixCopy(NULL, pixs);
2493     else
2494         return (PIX *)ERROR_PTR("depth not 1, 2, 4, 8, 16, 32 bpp",
2495                                 procName, NULL);
2496 }
2497 
2498 
2499 /*!
2500  *  pixConvertTo32BySampling()
2501  *
2502  *      Input:  pixs (1, 2, 4, 8, 16 or 32 bpp)
2503  *              factor (submsampling factor; integer >= 1)
2504  *      Return: pixd (32 bpp), or null on error
2505  *
2506  *  Notes:
2507  *      (1) This is a fast, quick/dirty, top-level converter.
2508  *      (2) See pixConvertTo32() for default values.
2509  */
2510 PIX *
pixConvertTo32BySampling(PIX * pixs,l_int32 factor)2511 pixConvertTo32BySampling(PIX     *pixs,
2512                          l_int32  factor)
2513 {
2514 l_float32  scalefactor;
2515 PIX       *pixt, *pixd;
2516 
2517     PROCNAME("pixConvertTo32BySampling");
2518 
2519     if (!pixs)
2520         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2521     if (factor < 1)
2522         return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
2523 
2524     scalefactor = 1. / (l_float32)factor;
2525     pixt = pixScaleBySampling(pixs, scalefactor, scalefactor);
2526     pixd = pixConvertTo32(pixt);
2527 
2528     pixDestroy(&pixt);
2529     return pixd;
2530 }
2531 
2532 
2533 /*!
2534  *  pixConvert8To32()
2535  *
2536  *      Input:  pix (8 bpp)
2537  *      Return: 32 bpp rgb pix, or null on error
2538  *
2539  *  Notes:
2540  *      (1) If there is no colormap, replicates the gray value
2541  *          into the 3 MSB of the dest pixel.
2542  *      (2) Implicit assumption about RGB component ordering.
2543  */
2544 PIX *
pixConvert8To32(PIX * pixs)2545 pixConvert8To32(PIX  *pixs)
2546 {
2547 l_int32    i, j, w, h, wpls, wpld, val;
2548 l_uint32  *datas, *datad, *lines, *lined;
2549 l_uint32  *tab;
2550 PIX       *pixd;
2551 
2552     PROCNAME("pixConvert8To32");
2553 
2554     if (!pixs)
2555         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2556     if (pixGetDepth(pixs) != 8)
2557         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
2558 
2559     if (pixGetColormap(pixs))
2560         return pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
2561 
2562         /* Replication table */
2563     if ((tab = (l_uint32 *)CALLOC(256, sizeof(l_uint32))) == NULL)
2564         return (PIX *)ERROR_PTR("tab not made", procName, NULL);
2565     for (i = 0; i < 256; i++)
2566       tab[i] = (i << 24) | (i << 16) | (i << 8);
2567 
2568     pixGetDimensions(pixs, &w, &h, NULL);
2569     datas = pixGetData(pixs);
2570     wpls = pixGetWpl(pixs);
2571     if ((pixd = pixCreate(w, h, 32)) == NULL)
2572         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2573     pixCopyResolution(pixd, pixs);
2574     datad = pixGetData(pixd);
2575     wpld = pixGetWpl(pixd);
2576 
2577     for (i = 0; i < h; i++) {
2578         lines = datas + i * wpls;
2579         lined = datad + i * wpld;
2580         for (j = 0; j < w; j++) {
2581             val = GET_DATA_BYTE(lines, j);
2582             lined[j] = tab[val];
2583         }
2584     }
2585 
2586     FREE(tab);
2587     return pixd;
2588 }
2589 
2590 
2591 /*---------------------------------------------------------------------------*
2592  *           Top-level conversion to 8 or 32 bpp, without colormap           *
2593  *---------------------------------------------------------------------------*/
2594 /*!
2595  *  pixConvertTo8Or32()
2596  *
2597  *      Input:  pixs (1, 2, 4, 8, 16, with or without colormap; or 32 bpp rgb)
2598  *              copyflag (use 0 to return clone if pixs does not need to
2599  *                         be changed; 1 to return a copy in those situations)
2600  *              warnflag (1 to issue warning if colormap is removed; else 0)
2601  *      Return: pixd (8 bpp grayscale or 32 bpp rgb), or null on error
2602  *
2603  *  Notes:
2604  *      (1) If there is a colormap, the colormap is removed to 8 or 32 bpp,
2605  *          depending on whether the colors in the colormap are all gray.
2606  *      (2) If the input is either rgb or 8 bpp without a colormap,
2607  *          this returns either a clone or a copy, depending on @copyflag.
2608  *      (3) Otherwise, the pix is converted to 8 bpp grayscale.
2609  *          In all cases, pixd does not have a colormap.
2610  */
2611 PIX *
pixConvertTo8Or32(PIX * pixs,l_int32 copyflag,l_int32 warnflag)2612 pixConvertTo8Or32(PIX     *pixs,
2613                   l_int32  copyflag,
2614                   l_int32  warnflag)
2615 {
2616 l_int32  d;
2617 PIX     *pixd;
2618 
2619     PROCNAME("pixConvertTo8Or32");
2620 
2621     if (!pixs)
2622         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2623 
2624     d = pixGetDepth(pixs);
2625     if (pixGetColormap(pixs)) {
2626         if (warnflag) L_WARNING("pix has colormap; removing", procName);
2627         pixd = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
2628     }
2629     else if (d == 8 || d == 32) {
2630         if (copyflag == 0)
2631             pixd = pixClone(pixs);
2632         else
2633             pixd = pixCopy(NULL, pixs);
2634     }
2635     else
2636         pixd = pixConvertTo8(pixs, 0);
2637 
2638         /* Sanity check on result */
2639     d = pixGetDepth(pixd);
2640     if (d != 8 && d != 32) {
2641         pixDestroy(&pixd);
2642         return (PIX *)ERROR_PTR("depth not 8 or 32 bpp", procName, NULL);
2643     }
2644 
2645     return pixd;
2646 }
2647 
2648 
2649 /*---------------------------------------------------------------------------*
2650  *                  Lossless depth conversion (unpacking)                    *
2651  *---------------------------------------------------------------------------*/
2652 /*!
2653  *  pixConvertLossless()
2654  *
2655  *      Input:  pixs (1, 2, 4, 8 bpp, not cmapped)
2656  *              d (destination depth: 2, 4 or 8)
2657  *      Return: pixd (2, 4 or 8 bpp), or null on error
2658  *
2659  *  Notes:
2660  *      (1) This is a lossless unpacking (depth-increasing)
2661  *          conversion.  If ds is the depth of pixs, then
2662  *           - if d < ds, returns NULL
2663  *           - if d == ds, returns a copy
2664  *           - if d > ds, does the unpacking conversion
2665  *      (2) If pixs has a colormap, this is an error.
2666  */
2667 PIX *
pixConvertLossless(PIX * pixs,l_int32 d)2668 pixConvertLossless(PIX     *pixs,
2669                    l_int32  d)
2670 {
2671 l_int32    w, h, ds, wpls, wpld, i, j, val;
2672 l_uint32  *datas, *datad, *lines, *lined;
2673 PIX       *pixd;
2674 
2675     PROCNAME("pixConvertLossless");
2676 
2677     if (!pixs)
2678         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2679     if (pixGetColormap(pixs))
2680         return (PIX *)ERROR_PTR("pixs has colormap", procName, NULL);
2681     if (d != 2 && d != 4 && d != 8)
2682         return (PIX *)ERROR_PTR("invalid dest depth", procName, NULL);
2683 
2684     pixGetDimensions(pixs, &w, &h, &ds);
2685     if (d < ds)
2686         return (PIX *)ERROR_PTR("depth > d", procName, NULL);
2687     else if (d == ds)
2688         return pixCopy(NULL, pixs);
2689 
2690     if ((pixd = pixCreate(w, h, d)) == NULL)
2691         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2692     pixCopyResolution(pixd, pixs);
2693 
2694         /* Unpack the bits */
2695     datas = pixGetData(pixs);
2696     wpls = pixGetWpl(pixs);
2697     datad = pixGetData(pixd);
2698     wpld = pixGetWpl(pixd);
2699     for (i = 0; i < h; i++) {
2700         lines = datas + i * wpls;
2701         lined = datad + i * wpld;
2702         switch (ds)
2703         {
2704         case 1:
2705             for (j = 0; j < w; j++) {
2706                 val = GET_DATA_BIT(lines, j);
2707                 if (d == 8)
2708                     SET_DATA_BYTE(lined, j, val);
2709                 else if (d == 4)
2710                     SET_DATA_QBIT(lined, j, val);
2711                 else  /* d == 2 */
2712                     SET_DATA_DIBIT(lined, j, val);
2713             }
2714             break;
2715         case 2:
2716             for (j = 0; j < w; j++) {
2717                 val = GET_DATA_DIBIT(lines, j);
2718                 if (d == 8)
2719                     SET_DATA_BYTE(lined, j, val);
2720                 else  /* d == 4 */
2721                     SET_DATA_QBIT(lined, j, val);
2722             }
2723         case 4:
2724             for (j = 0; j < w; j++) {
2725                 val = GET_DATA_DIBIT(lines, j);
2726                 SET_DATA_BYTE(lined, j, val);
2727             }
2728             break;
2729         }
2730     }
2731 
2732     return pixd;
2733 }
2734 
2735 
2736 /*---------------------------------------------------------------------------*
2737  *                     Conversion for printing in PostScript                 *
2738  *---------------------------------------------------------------------------*/
2739 /*!
2740  *  pixConvertForPSWrap()
2741  *
2742  *      Input:  pixs (1, 2, 4, 8, 16, 32 bpp)
2743  *      Return: pixd (1, 8, or 32 bpp), or null on error
2744  *
2745  *  Notes:
2746  *      (1) For wrapping in PostScript, we convert pixs to
2747  *          1 bpp, 8 bpp (gray) and 32 bpp (RGB color).
2748  *      (2) Colormaps are removed.  For pixs with colormaps, the
2749  *          images are converted to either 8 bpp gray or 32 bpp
2750  *          RGB, depending on whether the colormap has color content.
2751  *      (3) Images without colormaps, that are not 1 bpp or 32 bpp,
2752  *          are converted to 8 bpp gray.
2753  */
2754 PIX *
pixConvertForPSWrap(PIX * pixs)2755 pixConvertForPSWrap(PIX  *pixs)
2756 {
2757 l_int32   d;
2758 PIX      *pixd;
2759 PIXCMAP  *cmap;
2760 
2761     PROCNAME("pixConvertForPSWrap");
2762 
2763     if (!pixs)
2764         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2765 
2766     cmap = pixGetColormap(pixs);
2767     d = pixGetDepth(pixs);
2768     switch (d)
2769     {
2770     case 1:
2771     case 32:
2772         pixd = pixClone(pixs);
2773         break;
2774     case 2:
2775         if (cmap)
2776             pixd = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
2777         else
2778             pixd = pixConvert2To8(pixs, 0, 0x55, 0xaa, 0xff, FALSE);
2779         break;
2780     case 4:
2781         if (cmap)
2782             pixd = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
2783         else
2784             pixd = pixConvert4To8(pixs, FALSE);
2785         break;
2786     case 8:
2787         pixd = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
2788         break;
2789     case 16:
2790         pixd = pixConvert16To8(pixs, 1);
2791         break;
2792     default:
2793         fprintf(stderr, "depth not in {1, 2, 4, 8, 16, 32}");
2794         return NULL;
2795    }
2796 
2797    return pixd;
2798 }
2799 
2800 
2801 /*---------------------------------------------------------------------------*
2802  *                  Colorspace conversion between RGB and HSB                *
2803  *---------------------------------------------------------------------------*/
2804 /*!
2805  *  pixConvertRGBToHSV()
2806  *
2807  *      Input:  pixd (can be NULL; if not NULL, must == pixs)
2808  *              pixs
2809  *      Return: pixd always
2810  *
2811  *  Notes:
2812  *      (1) For pixs = pixd, this is in-place; otherwise pixd must be NULL.
2813  *      (2) The definition of our HSV space is given in convertRGBToHSV().
2814  *      (3) The h, s and v values are stored in the same places as
2815  *          the r, g and b values, respectively.  Here, they are explicitly
2816  *          placed in the 3 MS bytes in the pixel.
2817  *      (4) Normalizing to 1 and considering the r,g,b components,
2818  *          a simple way to understand the HSV space is:
2819  *           - v = max(r,g,b)
2820  *           - s = (max - min) / max
2821  *           - h ~ (mid - min) / (max - min)  [apart from signs and constants]
2822  *      (5) Normalizing to 1, some properties of the HSV space are:
2823  *           - For gray values (r = g = b) along the continuum between
2824  *             black and white:
2825  *                s = 0  (becoming undefined as you approach black)
2826  *                h is undefined everywhere
2827  *           - Where one component is saturated and the others are zero:
2828  *                v = 1
2829  *                s = 1
2830  *                h = 0 (r = max), 1/3 (g = max), 2/3 (b = max)
2831  *           - Where two components are saturated and the other is zero:
2832  *                v = 1
2833  *                s = 1
2834  *                h = 1/2 (if r = 0), 5/6 (if g = 0), 1/6 (if b = 0)
2835  */
2836 PIX *
pixConvertRGBToHSV(PIX * pixd,PIX * pixs)2837 pixConvertRGBToHSV(PIX  *pixd,
2838                    PIX  *pixs)
2839 {
2840 l_int32    w, h, d, wpl, i, j, rval, gval, bval, hval, sval, vval;
2841 l_uint32   pixel;
2842 l_uint32  *line, *data;
2843 PIXCMAP   *cmap;
2844 
2845     PROCNAME("pixConvertRGBToHSV");
2846 
2847     if (!pixs)
2848         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
2849     if (pixd && pixd != pixs)
2850         return (PIX *)ERROR_PTR("pixd defined and not inplace", procName, pixd);
2851 
2852     d = pixGetDepth(pixs);
2853     cmap = pixGetColormap(pixs);
2854     if (!cmap && d != 32)
2855         return (PIX *)ERROR_PTR("not cmapped or rgb", procName, pixd);
2856 
2857     if (!pixd)
2858         pixd = pixCopy(NULL, pixs);
2859 
2860     cmap = pixGetColormap(pixd);
2861     if (cmap) {   /* just convert the colormap */
2862         pixcmapConvertRGBToHSV(cmap);
2863         return pixd;
2864     }
2865 
2866         /* Convert RGB image */
2867     pixGetDimensions(pixd, &w, &h, NULL);
2868     wpl = pixGetWpl(pixd);
2869     data = pixGetData(pixd);
2870     for (i = 0; i < h; i++) {
2871         line = data + i * wpl;
2872         for (j = 0; j < w; j++) {
2873             pixel = line[j];
2874             extractRGBValues(pixel, &rval, &gval, &bval);
2875             convertRGBToHSV(rval, gval, bval, &hval, &sval, &vval);
2876             line[j] = (hval << 24) | (sval << 16) | (vval << 8);
2877         }
2878     }
2879 
2880     return pixd;
2881 }
2882 
2883 
2884 /*!
2885  *  pixConvertHSVToRGB()
2886  *
2887  *      Input:  pixd (can be NULL; if not NULL, must == pixs)
2888  *              pixs
2889  *      Return: pixd always
2890  *
2891  *  Notes:
2892  *      (1) For pixs = pixd, this is in-place; otherwise pixd must be NULL.
2893  *      (2) The user takes responsibility for making sure that pixs is
2894  *          in our HSV space.  The definition of our HSV space is given
2895  *          in convertRGBToHSV().
2896  *      (3) The h, s and v values are stored in the same places as
2897  *          the r, g and b values, respectively.  Here, they are explicitly
2898  *          placed in the 3 MS bytes in the pixel.
2899  */
2900 PIX *
pixConvertHSVToRGB(PIX * pixd,PIX * pixs)2901 pixConvertHSVToRGB(PIX  *pixd,
2902                    PIX  *pixs)
2903 {
2904 l_int32    w, h, d, wpl, i, j, rval, gval, bval, hval, sval, vval;
2905 l_uint32   pixel;
2906 l_uint32  *line, *data;
2907 PIXCMAP   *cmap;
2908 
2909     PROCNAME("pixConvertHSVToRGB");
2910 
2911     if (!pixs)
2912         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
2913     if (pixd && pixd != pixs)
2914         return (PIX *)ERROR_PTR("pixd defined and not inplace", procName, pixd);
2915 
2916     d = pixGetDepth(pixs);
2917     cmap = pixGetColormap(pixs);
2918     if (!cmap && d != 32)
2919         return (PIX *)ERROR_PTR("not cmapped or hsv", procName, pixd);
2920 
2921     if (!pixd)
2922         pixd = pixCopy(NULL, pixs);
2923 
2924     cmap = pixGetColormap(pixd);
2925     if (cmap) {   /* just convert the colormap */
2926         pixcmapConvertHSVToRGB(cmap);
2927         return pixd;
2928     }
2929 
2930         /* Convert HSV image */
2931     pixGetDimensions(pixd, &w, &h, NULL);
2932     wpl = pixGetWpl(pixd);
2933     data = pixGetData(pixd);
2934     for (i = 0; i < h; i++) {
2935         line = data + i * wpl;
2936         for (j = 0; j < w; j++) {
2937             pixel = line[j];
2938             hval = pixel >> 24;
2939             sval = (pixel >> 16) & 0xff;
2940             vval = (pixel >> 8) & 0xff;
2941             convertHSVToRGB(hval, sval, vval, &rval, &gval, &bval);
2942             composeRGBPixel(rval, gval, bval, line + j);
2943         }
2944     }
2945 
2946     return pixd;
2947 }
2948 
2949 
2950 /*!
2951  *  convertRGBToHSV()
2952  *
2953  *      Input:  rval, gval, bval (RGB input)
2954  *              &hval, &sval, &vval (<return> HSV values)
2955  *      Return: 0 if OK, 1 on error
2956  *
2957  *  Notes:
2958  *      (1) The range of returned values is:
2959  *            h [0 ... 239]
2960  *            s [0 ... 255]
2961  *            v [0 ... 255]
2962  *      (2) If r = g = b, the pixel is gray (s = 0), and we define h = 0.
2963  *      (3) h wraps around, so that h = 0 and h = 240 are equivalent
2964  *          in hue space.
2965  *      (4) h has the following correspondence to color:
2966  *            h = 0         magenta
2967  *            h = 40        red
2968  *            h = 80        yellow
2969  *            h = 120       green
2970  *            h = 160       cyan
2971  *            h = 200       blue
2972  */
2973 l_int32
convertRGBToHSV(l_int32 rval,l_int32 gval,l_int32 bval,l_int32 * phval,l_int32 * psval,l_int32 * pvval)2974 convertRGBToHSV(l_int32   rval,
2975                 l_int32   gval,
2976                 l_int32   bval,
2977                 l_int32  *phval,
2978                 l_int32  *psval,
2979                 l_int32  *pvval)
2980 {
2981 l_int32    minrg, maxrg, min, max, delta;
2982 l_float32  h;
2983 
2984     PROCNAME("convertRGBToHSV");
2985 
2986     if (!phval || !psval || !pvval)
2987         return ERROR_INT("&hval, &sval, &vval not all defined", procName, 1);
2988 
2989     minrg = L_MIN(rval, gval);
2990     min = L_MIN(minrg, bval);
2991     maxrg = L_MAX(rval, gval);
2992     max = L_MAX(maxrg, bval);
2993     delta = max - min;
2994 
2995     *pvval = max;
2996     if (delta == 0) {   /* gray; no chroma */
2997         *phval = 0;
2998         *psval = 0;
2999     }
3000     else {
3001         *psval = (l_int32)(255. * (l_float32)delta / (l_float32)max + 0.5);
3002         if (rval == max)  /* between magenta and yellow */
3003             h = (l_float32)(gval - bval) / (l_float32)delta;
3004         else if (gval == max)  /* between yellow and cyan */
3005             h = 2. + (l_float32)(bval - rval) / (l_float32)delta;
3006         else  /* between cyan and magenta */
3007             h = 4. + (l_float32)(rval - gval) / (l_float32)delta;
3008         h *= 40.0;
3009         if (h < 0.0)
3010             h += 240.0;
3011         if (h >= 239.5)
3012             h = 0.0;
3013         *phval = (l_int32)(h + 0.5);
3014     }
3015 
3016     return 0;
3017 }
3018 
3019 
3020 /*!
3021  *  convertHSVToRGB()
3022  *
3023  *      Input:  hval, sval, vval
3024  *              &rval, &gval, &bval (<return> RGB values)
3025  *      Return: 0 if OK, 1 on error
3026  *
3027  *  Notes:
3028  *      (1) See convertRGBToHSV() for valid input range of HSV values
3029  *          and their interpretation in color space.
3030  */
3031 l_int32
convertHSVToRGB(l_int32 hval,l_int32 sval,l_int32 vval,l_int32 * prval,l_int32 * pgval,l_int32 * pbval)3032 convertHSVToRGB(l_int32   hval,
3033                 l_int32   sval,
3034                 l_int32   vval,
3035                 l_int32  *prval,
3036                 l_int32  *pgval,
3037                 l_int32  *pbval)
3038 {
3039 l_int32   i, x, y, z;
3040 l_float32 h, f, s;
3041 
3042     PROCNAME("convertHSVToRGB");
3043 
3044     if (!prval || !pgval || !pbval)
3045         return ERROR_INT("&rval, &gval, &bval not all defined", procName, 1);
3046 
3047     if (sval == 0) {  /* gray */
3048         *prval = vval;
3049         *pgval = vval;
3050         *pbval = vval;
3051     }
3052     else {
3053         if (hval < 0 || hval > 240)
3054             return ERROR_INT("invalid hval", procName, 1);
3055         if (hval == 240)
3056             hval = 0;
3057         h = (l_float32)hval / 40.;
3058         i = (l_int32)h;
3059         f = h - i;
3060         s = (l_float32)sval / 255.;
3061         x = (l_int32)(vval * (1. - s) + 0.5);
3062         y = (l_int32)(vval * (1. - s * f) + 0.5);
3063         z = (l_int32)(vval * (1. - s * (1. - f)) + 0.5);
3064         switch (i)
3065         {
3066         case 0:
3067             *prval = vval;
3068             *pgval = z;
3069             *pbval = x;
3070             break;
3071         case 1:
3072             *prval = y;
3073             *pgval = vval;
3074             *pbval = x;
3075             break;
3076         case 2:
3077             *prval = x;
3078             *pgval = vval;
3079             *pbval = z;
3080             break;
3081         case 3:
3082             *prval = x;
3083             *pgval = y;
3084             *pbval = vval;
3085             break;
3086         case 4:
3087             *prval = z;
3088             *pgval = x;
3089             *pbval = vval;
3090             break;
3091         case 5:
3092             *prval = vval;
3093             *pgval = x;
3094             *pbval = y;
3095             break;
3096         default:  /* none possible */
3097             return 1;
3098         }
3099     }
3100 
3101     return 0;
3102 }
3103 
3104 
3105 /*!
3106  *  pixConvertRGBToHue()
3107  *
3108  *      Input:  pixs (32 bpp RGB or 8 bpp with colormap)
3109  *      Return: pixd (8 bpp hue of HSV), or null on error
3110  *
3111  *  Notes:
3112  *      (1) The conversion to HSV hue is in-lined here.
3113  *      (2) If there is a colormap, it is removed.
3114  *      (3) If you just want the hue component, this does it
3115  *          at about 10 Mpixels/sec/GHz, which is about
3116  *          2x faster than using pixConvertRGBToHSV()
3117  */
3118 PIX *
pixConvertRGBToHue(PIX * pixs)3119 pixConvertRGBToHue(PIX  *pixs)
3120 {
3121 l_int32    w, h, d, wplt, wpld;
3122 l_int32    i, j, rval, gval, bval, hval, minrg, min, maxrg, max, delta;
3123 l_float32  fh;
3124 l_uint32   pixel;
3125 l_uint32  *linet, *lined, *datat, *datad;
3126 PIX       *pixt, *pixd;
3127 
3128     PROCNAME("pixConvertRGBToHue");
3129 
3130     if (!pixs)
3131         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3132 
3133     pixGetDimensions(pixs, &w, &h, &d);
3134     if (d != 32 && !pixGetColormap(pixs))
3135         return (PIX *)ERROR_PTR("not cmapped or rgb", procName, NULL);
3136     pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
3137 
3138         /* Convert RGB image */
3139     pixd = pixCreate(w, h, 8);
3140     pixCopyResolution(pixd, pixs);
3141     wplt = pixGetWpl(pixt);
3142     datat = pixGetData(pixt);
3143     wpld = pixGetWpl(pixd);
3144     datad = pixGetData(pixd);
3145     for (i = 0; i < h; i++) {
3146         linet = datat + i * wplt;
3147         lined = datad + i * wpld;
3148         for (j = 0; j < w; j++) {
3149             pixel = linet[j];
3150             extractRGBValues(pixel, &rval, &gval, &bval);
3151             minrg = L_MIN(rval, gval);
3152             min = L_MIN(minrg, bval);
3153             maxrg = L_MAX(rval, gval);
3154             max = L_MAX(maxrg, bval);
3155             delta = max - min;
3156             if (delta == 0)  /* gray; no chroma */
3157                 hval = 0;
3158             else {
3159                 if (rval == max)  /* between magenta and yellow */
3160                     fh = (l_float32)(gval - bval) / (l_float32)delta;
3161                 else if (gval == max)  /* between yellow and cyan */
3162                     fh = 2. + (l_float32)(bval - rval) / (l_float32)delta;
3163                 else  /* between cyan and magenta */
3164                     fh = 4. + (l_float32)(rval - gval) / (l_float32)delta;
3165                 fh *= 40.0;
3166                 if (fh < 0.0)
3167                     fh += 240.0;
3168                 hval = (l_int32)(fh + 0.5);
3169             }
3170             SET_DATA_BYTE(lined, j, hval);
3171         }
3172     }
3173     pixDestroy(&pixt);
3174 
3175     return pixd;
3176 }
3177 
3178 
3179 
3180 /*!
3181  *  pixConvertRGBToSaturation()
3182  *
3183  *      Input:  pixs (32 bpp RGB or 8 bpp with colormap)
3184  *      Return: pixd (8 bpp sat of HSV), or null on error
3185  *
3186  *  Notes:
3187  *      (1) The conversion to HSV sat is in-lined here.
3188  *      (2) If there is a colormap, it is removed.
3189  *      (3) If you just want the saturation component, this does it
3190  *          at about 12 Mpixels/sec/GHz.
3191  */
3192 PIX *
pixConvertRGBToSaturation(PIX * pixs)3193 pixConvertRGBToSaturation(PIX  *pixs)
3194 {
3195 l_int32    w, h, d, wplt, wpld;
3196 l_int32    i, j, rval, gval, bval, sval, minrg, min, maxrg, max, delta;
3197 l_uint32   pixel;
3198 l_uint32  *linet, *lined, *datat, *datad;
3199 PIX       *pixt, *pixd;
3200 
3201     PROCNAME("pixConvertRGBToSaturation");
3202 
3203     if (!pixs)
3204         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3205 
3206     pixGetDimensions(pixs, &w, &h, &d);
3207     if (d != 32 && !pixGetColormap(pixs))
3208         return (PIX *)ERROR_PTR("not cmapped or rgb", procName, NULL);
3209     pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
3210 
3211         /* Convert RGB image */
3212     pixd = pixCreate(w, h, 8);
3213     pixCopyResolution(pixd, pixs);
3214     wplt = pixGetWpl(pixt);
3215     datat = pixGetData(pixt);
3216     wpld = pixGetWpl(pixd);
3217     datad = pixGetData(pixd);
3218     for (i = 0; i < h; i++) {
3219         linet = datat + i * wplt;
3220         lined = datad + i * wpld;
3221         for (j = 0; j < w; j++) {
3222             pixel = linet[j];
3223             extractRGBValues(pixel, &rval, &gval, &bval);
3224             minrg = L_MIN(rval, gval);
3225             min = L_MIN(minrg, bval);
3226             maxrg = L_MAX(rval, gval);
3227             max = L_MAX(maxrg, bval);
3228             delta = max - min;
3229             if (delta == 0)  /* gray; no chroma */
3230                 sval = 0;
3231             else
3232                 sval = (l_int32)(255. *
3233                                  (l_float32)delta / (l_float32)max + 0.5);
3234             SET_DATA_BYTE(lined, j, sval);
3235         }
3236     }
3237 
3238     pixDestroy(&pixt);
3239     return pixd;
3240 }
3241 
3242 
3243 /*!
3244  *  pixConvertRGBToValue()
3245  *
3246  *      Input:  pixs (32 bpp RGB or 8 bpp with colormap)
3247  *      Return: pixd (8 bpp max component intensity of HSV), or null on error
3248  *
3249  *  Notes:
3250  *      (1) The conversion to HSV sat is in-lined here.
3251  *      (2) If there is a colormap, it is removed.
3252  *      (3) If you just want the value component, this does it
3253  *          at about 35 Mpixels/sec/GHz.
3254  */
3255 PIX *
pixConvertRGBToValue(PIX * pixs)3256 pixConvertRGBToValue(PIX  *pixs)
3257 {
3258 l_int32    w, h, d, wplt, wpld;
3259 l_int32    i, j, rval, gval, bval, maxrg, max;
3260 l_uint32   pixel;
3261 l_uint32  *linet, *lined, *datat, *datad;
3262 PIX       *pixt, *pixd;
3263 
3264     PROCNAME("pixConvertRGBToValue");
3265 
3266     if (!pixs)
3267         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3268 
3269     pixGetDimensions(pixs, &w, &h, &d);
3270     if (d != 32 && !pixGetColormap(pixs))
3271         return (PIX *)ERROR_PTR("not cmapped or rgb", procName, NULL);
3272     pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
3273 
3274         /* Convert RGB image */
3275     pixd = pixCreate(w, h, 8);
3276     pixCopyResolution(pixd, pixs);
3277     wplt = pixGetWpl(pixt);
3278     datat = pixGetData(pixt);
3279     wpld = pixGetWpl(pixd);
3280     datad = pixGetData(pixd);
3281     for (i = 0; i < h; i++) {
3282         linet = datat + i * wplt;
3283         lined = datad + i * wpld;
3284         for (j = 0; j < w; j++) {
3285             pixel = linet[j];
3286             extractRGBValues(pixel, &rval, &gval, &bval);
3287             maxrg = L_MAX(rval, gval);
3288             max = L_MAX(maxrg, bval);
3289             SET_DATA_BYTE(lined, j, max);
3290         }
3291     }
3292 
3293     pixDestroy(&pixt);
3294     return pixd;
3295 }
3296 
3297 
3298 
3299 
3300 
3301