• 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  *  colormap.c
18  *
19  *      Colormap creation, copy, destruction, addition
20  *           PIXCMAP    *pixcmapCreate()
21  *           PIXCMAP    *pixcmapCreateRandom()
22  *           PIXCMAP    *pixcmapCreateLinear()
23  *           PIXCMAP    *pixcmapCopy()
24  *           void        pixcmapDestroy()
25  *           l_int32     pixcmapAddColor()
26  *           l_int32     pixcmapAddNewColor()
27  *           l_int32     pixcmapAddBlackOrWhite()
28  *           l_int32     pixcmapSetBlackAndWhite()
29  *           l_int32     pixcmapGetCount()
30  *           l_int32     pixcmapGetDepth()
31  *           l_int32     pixcmapGetMinDepth()
32  *           l_int32     pixcmapGetFreeCount()
33  *           l_int32     pixcmapClear()
34  *
35  *      Colormap random access and test
36  *           l_int32     pixcmapGetColor()
37  *           l_int32     pixcmapResetColor()
38  *           l_int32     pixcmapGetIndex()
39  *           l_int32     pixcmapHasColor()
40  *           l_int32     pixcmapCountGrayColors()
41  *           l_int32     pixcmapGetRankIntensity()
42  *           l_int32     pixcmapGetNearestIndex()
43  *           l_int32     pixcmapGetNearestGrayIndex()
44  *           l_int32     pixcmapGetExtremeValue()
45  *
46  *      Colormap conversion
47  *           PIXCMAP    *pixcmapGrayToColor()
48  *           PIXCMAP    *pixcmapColorToGray()
49  *
50  *      Colormap I/O
51  *           l_int32     pixcmapReadStream()
52  *           l_int32     pixcmapWriteStream()
53  *
54  *      Extract colormap arrays
55  *           l_int32     pixcmapToArrays()
56  *           l_int32     pixcmapToRGBTable()
57  *
58  *      Colormap transforms
59  *           l_int32     pixcmapGammaTRC()
60  *           l_int32     pixcmapContrastTRC()
61  *           l_int32     pixcmapShiftIntensity()
62  *           l_int32     pixcmapConvertRGBToHSV()
63  *           l_int32     pixcmapConvertHSVToRGB()
64  *
65  */
66 
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include "allheaders.h"
71 
72 
73 /*-------------------------------------------------------------*
74  *                Colormap creation and addition               *
75  *-------------------------------------------------------------*/
76 /*!
77  *  pixcmapCreate()
78  *
79  *      Input:  depth (bpp, of pix)
80  *      Return: cmap, or null on error
81  */
82 PIXCMAP *
pixcmapCreate(l_int32 depth)83 pixcmapCreate(l_int32  depth)
84 {
85 RGBA_QUAD  *cta;
86 PIXCMAP    *cmap;
87 
88     PROCNAME("pixcmapCreate");
89 
90     if (depth != 1 && depth != 2 && depth !=4 && depth != 8)
91         return (PIXCMAP *)ERROR_PTR("depth not in {1,2,4,8}", procName, NULL);
92 
93     if ((cmap = (PIXCMAP *)CALLOC(1, sizeof(PIXCMAP))) == NULL)
94         return (PIXCMAP *)ERROR_PTR("cmap not made", procName, NULL);
95     cmap->depth = depth;
96     cmap->nalloc = 1 << depth;
97     if ((cta = (RGBA_QUAD *)CALLOC(cmap->nalloc, sizeof(RGBA_QUAD))) == NULL)
98         return (PIXCMAP *)ERROR_PTR("cta not made", procName, NULL);
99     cmap->array = cta;
100     cmap->n = 0;
101 
102     return cmap;
103 }
104 
105 
106 /*!
107  *  pixcmapCreateRandom()
108  *
109  *      Input:  depth (bpp, of pix; 2, 4 or 8)
110  *              hasblack (1 if the first color is black; 0 if no black)
111  *              haswhite (1 if the last color is white; 0 if no white)
112  *      Return: cmap, or null on error
113  *
114  *  Notes:
115  *      (1) This sets up a colormap with random colors,
116  *          where the first color is optionally black, the last color
117  *          is optionally white, and the remaining colors are
118  *          chosen randomly.
119  *      (2) The number of randomly chosen colors is:
120  *               2^(depth) - haswhite - hasblack
121  *      (3) Because rand() is seeded, it might disrupt otherwise
122  *          deterministic results if also used elsewhere in a program.
123  *      (4) rand() is not threadsafe, and will generate garbage if run
124  *          on multiple threads at once -- though garbage is generally
125  *          what you want from a random number generator!
126  *      (5) Modern rand()s have equal randomness in low and high order
127  *          bits, but older ones don't.  Here, we're just using rand()
128  *          to choose colors for output.
129  */
130 PIXCMAP *
pixcmapCreateRandom(l_int32 depth,l_int32 hasblack,l_int32 haswhite)131 pixcmapCreateRandom(l_int32  depth,
132                     l_int32  hasblack,
133                     l_int32  haswhite)
134 {
135 l_int32   ncolors, i;
136 l_int32   red[256], green[256], blue[256];
137 PIXCMAP  *cmap;
138 
139     PROCNAME("pixcmapCreateRandom");
140 
141     if (depth != 2 && depth != 4 && depth != 8)
142         return (PIXCMAP *)ERROR_PTR("depth not in {2, 4, 8}", procName, NULL);
143     if (hasblack != 0) hasblack = 1;
144     if (haswhite != 0) haswhite = 1;
145 
146     cmap = pixcmapCreate(depth);
147     ncolors = 1 << depth;
148     if (hasblack)  /* first color is optionally black */
149         pixcmapAddColor(cmap, 0, 0, 0);
150     for (i = hasblack; i < ncolors - haswhite; i++) {
151         red[i] = (l_uint32)rand() & 0xff;
152         green[i] = (l_uint32)rand() & 0xff;
153         blue[i] = (l_uint32)rand() & 0xff;
154         pixcmapAddColor(cmap, red[i], green[i], blue[i]);
155     }
156     if (haswhite)  /* last color is optionally white */
157         pixcmapAddColor(cmap, 255, 255, 255);
158 
159     return cmap;
160 }
161 
162 
163 /*!
164  *  pixcmapCreateLinear()
165  *
166  *      Input:  d (depth of pix for this colormap; 1, 2, 4 or 8)
167  *              nlevels (valid in range [2, 2^d])
168  *      Return: cmap, or null on error
169  *
170  *  Notes:
171  *      (1) Colormap has equally spaced gray color values
172  *          from black (0, 0, 0) to white (255, 255, 255).
173  */
174 PIXCMAP *
pixcmapCreateLinear(l_int32 d,l_int32 nlevels)175 pixcmapCreateLinear(l_int32  d,
176                     l_int32  nlevels)
177 {
178 l_int32   maxlevels, i, val;
179 PIXCMAP  *cmap;
180 
181     PROCNAME("pixcmapCreateLinear");
182 
183     if (d != 1 && d != 2 && d !=4 && d != 8)
184         return (PIXCMAP *)ERROR_PTR("d not in {1, 2, 4, 8}", procName, NULL);
185     maxlevels = 1 << d;
186     if (nlevels < 2 || nlevels > maxlevels)
187         return (PIXCMAP *)ERROR_PTR("invalid nlevels", procName, NULL);
188 
189     cmap = pixcmapCreate(d);
190     for (i = 0; i < nlevels; i++) {
191         val = (255 * i) / (nlevels - 1);
192         pixcmapAddColor(cmap, val, val, val);
193     }
194     return cmap;
195 }
196 
197 
198 /*!
199  *  pixcmapCopy()
200  *
201  *      Input:  cmaps
202  *      Return: cmapd, or null on error
203  */
204 PIXCMAP *
pixcmapCopy(PIXCMAP * cmaps)205 pixcmapCopy(PIXCMAP  *cmaps)
206 {
207 l_int32   nbytes;
208 PIXCMAP  *cmapd;
209 
210     PROCNAME("pixcmapCopy");
211 
212     if (!cmaps)
213         return (PIXCMAP *)ERROR_PTR("cmaps not defined", procName, NULL);
214 
215     if ((cmapd = (PIXCMAP *)CALLOC(1, sizeof(PIXCMAP))) == NULL)
216         return (PIXCMAP *)ERROR_PTR("cmapd not made", procName, NULL);
217     nbytes = cmaps->nalloc * sizeof(RGBA_QUAD);
218     if ((cmapd->array = (void *)CALLOC(1, nbytes)) == NULL)
219         return (PIXCMAP *)ERROR_PTR("cmap array not made", procName, NULL);
220     memcpy(cmapd->array, cmaps->array, nbytes);
221     cmapd->n = cmaps->n;
222     cmapd->nalloc = cmaps->nalloc;
223     cmapd->depth = cmaps->depth;
224 
225     return cmapd;
226 }
227 
228 
229 /*!
230  *  pixcmapDestroy()
231  *
232  *      Input:  &cmap (<set to null>)
233  *      Return: void
234  */
235 void
pixcmapDestroy(PIXCMAP ** pcmap)236 pixcmapDestroy(PIXCMAP  **pcmap)
237 {
238 PIXCMAP  *cmap;
239 
240     PROCNAME("pixcmapDestroy");
241 
242     if (pcmap == NULL) {
243         L_WARNING("ptr address is null!", procName);
244         return;
245     }
246 
247     if ((cmap = *pcmap) == NULL)
248         return;
249 
250     FREE(cmap->array);
251     FREE(cmap);
252     *pcmap = NULL;
253 
254     return;
255 }
256 
257 
258 /*!
259  *  pixcmapAddColor()
260  *
261  *      Input:  cmap
262  *              rval, gval, bval (colormap entry to be added; each number
263  *                                is in range [0, ... 255])
264  *      Return: 0 if OK, 1 on error
265  *
266  *  Note: always adds the color if there is room.
267  */
268 l_int32
pixcmapAddColor(PIXCMAP * cmap,l_int32 rval,l_int32 gval,l_int32 bval)269 pixcmapAddColor(PIXCMAP  *cmap,
270                 l_int32   rval,
271                 l_int32   gval,
272                 l_int32   bval)
273 {
274 RGBA_QUAD  *cta;
275 
276     PROCNAME("pixcmapAddColor");
277 
278     if (!cmap)
279         return ERROR_INT("cmap not defined", procName, 1);
280     if (cmap->n >= cmap->nalloc)
281         return ERROR_INT("no free color entries", procName, 1);
282 
283     cta = (RGBA_QUAD *)cmap->array;
284     cta[cmap->n].red = rval;
285     cta[cmap->n].green = gval;
286     cta[cmap->n].blue = bval;
287     cmap->n++;
288 
289     return 0;
290 }
291 
292 
293 /*!
294  *  pixcmapAddNewColor()
295  *
296  *      Input:  cmap
297  *              rval, gval, bval (colormap entry to be added; each number
298  *                                is in range [0, ... 255])
299  *              &index (<return> index of color)
300  *      Return: 0 if OK, 1 on error; 2 if unable to add color
301  *
302  *  Notes:
303  *      (1) This only adds color if not already there.
304  *      (2) This returns the index of the new (or existing) color.
305  *      (3) Returns 2 with a warning if unable to add this color;
306  *          the caller should check the return value.
307  */
308 l_int32
pixcmapAddNewColor(PIXCMAP * cmap,l_int32 rval,l_int32 gval,l_int32 bval,l_int32 * pindex)309 pixcmapAddNewColor(PIXCMAP  *cmap,
310                    l_int32   rval,
311                    l_int32   gval,
312                    l_int32   bval,
313                    l_int32  *pindex)
314 {
315     PROCNAME("pixcmapAddNewColor");
316 
317     if (!pindex)
318         return ERROR_INT("&index not defined", procName, 1);
319     *pindex = 0;
320     if (!cmap)
321         return ERROR_INT("cmap not defined", procName, 1);
322 
323         /* Check if the color is already present. */
324     if (!pixcmapGetIndex(cmap, rval, gval, bval, pindex))  /* found */
325         return 0;
326 
327         /* We need to add the color.  Is there room? */
328     if (cmap->n >= cmap->nalloc) {
329         L_WARNING("no free color entries", procName);
330         return 2;
331     }
332 
333         /* There's room.  Add it. */
334     pixcmapAddColor(cmap, rval, gval, bval);
335     *pindex = pixcmapGetCount(cmap) - 1;
336     return 0;
337 }
338 
339 
340 /*!
341  *  pixcmapAddBlackOrWhite()
342  *
343  *      Input:  cmap
344  *              color (0 for black, 1 for white)
345  *              &index (<optional return> index of color; can be null)
346  *      Return: 0 if OK, 1 on error
347  *
348  *  Notes:
349  *      (1) This only adds color if not already there.
350  *      (2) This sets index to the requested color.
351  *      (3) If there is no room in the colormap, returns the index
352  *          of the closest color.
353  */
354 l_int32
pixcmapAddBlackOrWhite(PIXCMAP * cmap,l_int32 color,l_int32 * pindex)355 pixcmapAddBlackOrWhite(PIXCMAP  *cmap,
356                        l_int32   color,
357                        l_int32  *pindex)
358 {
359 l_int32  index;
360 
361     PROCNAME("pixcmapAddBlackOrWhite");
362 
363     if (pindex) *pindex = 0;
364     if (!cmap)
365         return ERROR_INT("cmap not defined", procName, 1);
366 
367     if (color == 0) {  /* black */
368         if (pixcmapGetFreeCount(cmap) > 0)
369             pixcmapAddNewColor(cmap, 0, 0, 0, &index);
370         else
371             pixcmapGetRankIntensity(cmap, 0.0, &index);
372     }
373     else {  /* white */
374         if (pixcmapGetFreeCount(cmap) > 0)
375             pixcmapAddNewColor(cmap, 255, 255, 255, &index);
376         else
377             pixcmapGetRankIntensity(cmap, 1.0, &index);
378     }
379 
380     if (pindex)
381         *pindex = index;
382     return 0;
383 }
384 
385 
386 /*!
387  *  pixcmapSetBlackAndWhite()
388  *
389  *      Input:  cmap
390  *              setblack (0 for no operation; 1 to set darkest color to black)
391  *              setwhite (0 for no operation; 1 to set lightest color to white)
392  *      Return: 0 if OK, 1 on error
393  */
394 l_int32
pixcmapSetBlackAndWhite(PIXCMAP * cmap,l_int32 setblack,l_int32 setwhite)395 pixcmapSetBlackAndWhite(PIXCMAP  *cmap,
396                         l_int32   setblack,
397                         l_int32   setwhite)
398 {
399 l_int32  index;
400 
401     PROCNAME("pixcmapSetBlackAndWhite");
402 
403     if (!cmap)
404         return ERROR_INT("cmap not defined", procName, 1);
405 
406     if (setblack) {
407         pixcmapGetRankIntensity(cmap, 0.0, &index);
408         pixcmapResetColor(cmap, index, 0, 0, 0);
409     }
410     if (setwhite) {
411         pixcmapGetRankIntensity(cmap, 1.0, &index);
412         pixcmapResetColor(cmap, index, 255, 255, 255);
413     }
414 
415     return 0;
416 }
417 
418 
419 /*!
420  *  pixcmapGetCount()
421  *
422  *      Input:  cmap
423  *      Return: count, or 0 on error
424  */
425 l_int32
pixcmapGetCount(PIXCMAP * cmap)426 pixcmapGetCount(PIXCMAP  *cmap)
427 {
428     PROCNAME("pixcmapGetCount");
429 
430     if (!cmap)
431         return ERROR_INT("cmap not defined", procName, 0);
432 
433     return cmap->n;
434 }
435 
436 
437 /*!
438  *  pixcmapGetFreeCount()
439  *
440  *      Input:  cmap
441  *      Return: free entries, or 0 on error
442  */
443 l_int32
pixcmapGetFreeCount(PIXCMAP * cmap)444 pixcmapGetFreeCount(PIXCMAP  *cmap)
445 {
446     PROCNAME("pixcmapGetFreeCount");
447 
448     if (!cmap)
449         return ERROR_INT("cmap not defined", procName, 0);
450 
451     return (cmap->nalloc - cmap->n);
452 }
453 
454 
455 /*!
456  *  pixcmapGetDepth()
457  *
458  *      Input:  cmap
459  *      Return: depth, or 0 on error
460  */
461 l_int32
pixcmapGetDepth(PIXCMAP * cmap)462 pixcmapGetDepth(PIXCMAP  *cmap)
463 {
464     PROCNAME("pixcmapGetDepth");
465 
466     if (!cmap)
467         return ERROR_INT("cmap not defined", procName, 0);
468 
469     return cmap->depth;
470 }
471 
472 
473 /*!
474  *  pixcmapGetMinDepth()
475  *
476  *      Input:  cmap
477  *              &mindepth (<return> minimum depth to support the colormap)
478  *      Return: 0 if OK, 1 on error
479  *
480  *  Notes:
481  *      (1) On error, &mindepth is returned as 0.
482  */
483 l_int32
pixcmapGetMinDepth(PIXCMAP * cmap,l_int32 * pmindepth)484 pixcmapGetMinDepth(PIXCMAP  *cmap,
485                    l_int32  *pmindepth)
486 {
487 l_int32  ncolors;
488 
489     PROCNAME("pixcmapGetMinDepth");
490 
491     if (!pmindepth)
492         return ERROR_INT("&mindepth not defined", procName, 1);
493     *pmindepth = 0;
494     if (!cmap)
495         return ERROR_INT("cmap not defined", procName, 1);
496 
497     ncolors = pixcmapGetCount(cmap);
498     if (ncolors <= 4)
499         *pmindepth = 2;
500     else if (ncolors <= 16)
501         *pmindepth = 4;
502     else  /* ncolors > 16 */
503         *pmindepth = 8;
504 
505     return 0;
506 }
507 
508 
509 /*!
510  *  pixcmapClear()
511  *
512  *      Input:  cmap
513  *      Return: 0 if OK, 1 on error
514  *
515  *  Note: this removes the colors by setting the count to 0.
516  */
517 l_int32
pixcmapClear(PIXCMAP * cmap)518 pixcmapClear(PIXCMAP  *cmap)
519 {
520     PROCNAME("pixcmapClear");
521 
522     if (!cmap)
523         return ERROR_INT("cmap not defined", procName, 1);
524     cmap->n = 0;
525     return 0;
526 }
527 
528 
529 /*-------------------------------------------------------------*
530  *                      Colormap random access                 *
531  *-------------------------------------------------------------*/
532 /*!
533  *  pixcmapGetColor()
534  *
535  *      Input:  cmap
536  *              index
537  *              &rval, &gval, &bval (<return> each color value in l_int32)
538  *      Return: 0 if OK, 1 if not accessable (caller should check)
539  */
540 l_int32
pixcmapGetColor(PIXCMAP * cmap,l_int32 index,l_int32 * prval,l_int32 * pgval,l_int32 * pbval)541 pixcmapGetColor(PIXCMAP  *cmap,
542                 l_int32   index,
543                 l_int32  *prval,
544                 l_int32  *pgval,
545                 l_int32  *pbval)
546 {
547 RGBA_QUAD  *cta;
548 
549     PROCNAME("pixcmapGetColor");
550 
551     if (!prval || !pgval || !pbval)
552         return ERROR_INT("&rval, &gval, &bval not all defined", procName, 1);
553     *prval = *pgval = *pbval = 0;
554     if (!cmap)
555         return ERROR_INT("cmap not defined", procName, 1);
556     if (index < 0 || index >= cmap->n)
557         return ERROR_INT("index out of bounds", procName, 1);
558 
559     cta = (RGBA_QUAD *)cmap->array;
560     *prval = cta[index].red;
561     *pgval = cta[index].green;
562     *pbval = cta[index].blue;
563 
564     return 0;
565 }
566 
567 
568 /*!
569  *  pixcmapResetColor()
570  *
571  *      Input:  cmap
572  *              index
573  *              rval, gval, bval (colormap entry to be reset; each number
574  *                                is in range [0, ... 255])
575  *      Return: 0 if OK, 1 if not accessable (caller should check)
576  *
577  *  Note: this resets sets the color of an entry that has already
578  *        been set and included in the count of colors
579  */
580 l_int32
pixcmapResetColor(PIXCMAP * cmap,l_int32 index,l_int32 rval,l_int32 gval,l_int32 bval)581 pixcmapResetColor(PIXCMAP  *cmap,
582                   l_int32   index,
583                   l_int32   rval,
584                   l_int32   gval,
585                   l_int32   bval)
586 {
587 RGBA_QUAD  *cta;
588 
589     PROCNAME("pixcmapResetColor");
590 
591     if (!cmap)
592         return ERROR_INT("cmap not defined", procName, 1);
593     if (index < 0 || index >= cmap->n)
594         return ERROR_INT("index out of bounds", procName, 1);
595 
596     cta = (RGBA_QUAD *)cmap->array;
597     cta[index].red = rval;
598     cta[index].green = gval;
599     cta[index].blue = bval;
600 
601     return 0;
602 }
603 
604 
605 /*!
606  *  pixcmapGetIndex()
607  *
608  *      Input:  cmap
609  *              rval, gval, bval (colormap colors to search for; each number
610  *                                is in range [0, ... 255])
611  *              &index (<return>)
612  *      Return: 0 if found, 1 if not found (caller must check)
613  */
614 l_int32
pixcmapGetIndex(PIXCMAP * cmap,l_int32 rval,l_int32 gval,l_int32 bval,l_int32 * pindex)615 pixcmapGetIndex(PIXCMAP  *cmap,
616                 l_int32   rval,
617                 l_int32   gval,
618                 l_int32   bval,
619                 l_int32  *pindex)
620 {
621 l_int32     n, i;
622 RGBA_QUAD  *cta;
623 
624     PROCNAME("pixcmapGetIndex");
625 
626     if (!pindex)
627         return ERROR_INT("&index not defined", procName, 1);
628     *pindex = 0;
629     if (!cmap)
630         return ERROR_INT("cmap not defined", procName, 1);
631     n = pixcmapGetCount(cmap);
632 
633     cta = (RGBA_QUAD *)cmap->array;
634     for (i = 0; i < n; i++) {
635         if (rval == cta[i].red && gval == cta[i].green && bval == cta[i].blue) {
636             *pindex = i;
637             return 0;
638         }
639     }
640 
641     return 1;
642 }
643 
644 
645 /*!
646  *  pixcmapHasColor()
647  *
648  *      Input:  cmap
649  *              &color (<return> TRUE if cmap has color; FALSE otherwise)
650  *      Return: 0 if OK, 1 on error
651  */
652 l_int32
pixcmapHasColor(PIXCMAP * cmap,l_int32 * pcolor)653 pixcmapHasColor(PIXCMAP  *cmap,
654                 l_int32  *pcolor)
655 {
656 l_int32   n, i;
657 l_int32  *rmap, *gmap, *bmap;
658 
659     PROCNAME("pixcmapHasColor");
660 
661     if (!pcolor)
662         return ERROR_INT("&color not defined", procName, 1);
663     *pcolor = FALSE;
664     if (!cmap)
665         return ERROR_INT("cmap not defined", procName, 1);
666 
667     if (pixcmapToArrays(cmap, &rmap, &gmap, &bmap))
668         return ERROR_INT("colormap arrays not made", procName, 1);
669     n = pixcmapGetCount(cmap);
670     for (i = 0; i < n; i++) {
671         if ((rmap[i] != gmap[i]) || (rmap[i] != bmap[i])) {
672             *pcolor = TRUE;
673             break;
674         }
675     }
676 
677     FREE(rmap);
678     FREE(gmap);
679     FREE(bmap);
680     return 0;
681 }
682 
683 
684 /*!
685  *  pixcmapCountGrayColors()
686  *
687  *      Input:  cmap
688  *              &ngray (<return> number of gray colors)
689  *      Return: 0 if OK, 1 on error
690  *
691  *  Notes:
692  *      (1) This counts the unique gray colors, including black and white.
693  */
694 l_int32
pixcmapCountGrayColors(PIXCMAP * cmap,l_int32 * pngray)695 pixcmapCountGrayColors(PIXCMAP  *cmap,
696                        l_int32  *pngray)
697 {
698 l_int32   n, i, rval, gval, bval, count;
699 l_int32  *array;
700 
701     PROCNAME("pixcmapCountGrayColors");
702 
703     if (!pngray)
704         return ERROR_INT("&ngray not defined", procName, 1);
705     *pngray = 0;
706     if (!cmap)
707         return ERROR_INT("cmap not defined", procName, 1);
708 
709     array = (l_int32 *)CALLOC(256, sizeof(l_int32));
710     n = pixcmapGetCount(cmap);
711     count = 0;
712     for (i = 0; i < n; i++) {
713         pixcmapGetColor(cmap, i, &rval, &gval, &bval);
714         if ((rval == gval) && (rval == bval) && (array[rval] == 0)) {
715             array[rval] = 1;
716             count++;
717         }
718     }
719 
720     FREE(array);
721     *pngray = count;
722     return 0;
723 }
724 
725 
726 /*!
727  *  pixcmapGetRankIntensity()
728  *
729  *      Input:  cmap
730  *              rankval (0.0 for darkest, 1.0 for lightest color)
731  *              &index (<return> the index into the colormap that
732  *                      corresponds to the rank intensity color)
733  *      Return: 0 if OK, 1 on error
734  */
735 l_int32
pixcmapGetRankIntensity(PIXCMAP * cmap,l_float32 rankval,l_int32 * pindex)736 pixcmapGetRankIntensity(PIXCMAP    *cmap,
737                         l_float32   rankval,
738                         l_int32    *pindex)
739 {
740 l_int32  n, i, rval, gval, bval, rankindex;
741 NUMA    *na, *nasort;
742 
743     PROCNAME("pixcmapGetRankIntensity");
744 
745     if (!pindex)
746         return ERROR_INT("&index not defined", procName, 1);
747     *pindex = 0;
748     if (!cmap)
749         return ERROR_INT("cmap not defined", procName, 1);
750     if (rankval < 0.0 || rankval > 1.0)
751         return ERROR_INT("rankval not in [0.0 ... 1.0]", procName, 1);
752 
753     n = pixcmapGetCount(cmap);
754     na = numaCreate(n);
755     for (i = 0; i < n; i++) {
756         pixcmapGetColor(cmap, i, &rval, &gval, &bval);
757         numaAddNumber(na, rval + gval + bval);
758     }
759     nasort = numaGetSortIndex(na, L_SORT_INCREASING);
760     rankindex = (l_int32)(rankval * (n - 1) + 0.5);
761     numaGetIValue(nasort, rankindex, pindex);
762 
763     numaDestroy(&na);
764     numaDestroy(&nasort);
765     return 0;
766 }
767 
768 
769 /*!
770  *  pixcmapGetNearestIndex()
771  *
772  *      Input:  cmap
773  *              rval, gval, bval (colormap colors to search for; each number
774  *                                is in range [0, ... 255])
775  *              &index (<return> the index of the nearest color)
776  *      Return: 0 if OK, 1 on error (caller must check)
777  *
778  *  Notes:
779  *      (1) Returns the index of the exact color if possible, otherwise the
780  *          index of the color closest to the target color.
781  *      (2) Nearest color is that which is the least sum-of-squares distance
782  *          from the target color.
783  */
784 l_int32
pixcmapGetNearestIndex(PIXCMAP * cmap,l_int32 rval,l_int32 gval,l_int32 bval,l_int32 * pindex)785 pixcmapGetNearestIndex(PIXCMAP  *cmap,
786                        l_int32   rval,
787                        l_int32   gval,
788                        l_int32   bval,
789                        l_int32  *pindex)
790 {
791 l_int32     i, n, delta, dist, mindist;
792 RGBA_QUAD  *cta;
793 
794     PROCNAME("pixcmapGetNearestIndex");
795 
796     if (!pindex)
797         return ERROR_INT("&index not defined", procName, 1);
798     *pindex = UNDEF;
799     if (!cmap)
800         return ERROR_INT("cmap not defined", procName, 1);
801 
802     if ((cta = (RGBA_QUAD *)cmap->array) == NULL)
803         return ERROR_INT("cta not defined(!)", procName, 1);
804     n = pixcmapGetCount(cmap);
805 
806     mindist = 3 * 255 * 255 + 1;
807     for (i = 0; i < n; i++) {
808         delta = cta[i].red - rval;
809         dist = delta * delta;
810         delta = cta[i].green - gval;
811         dist += delta * delta;
812         delta = cta[i].blue - bval;
813         dist += delta * delta;
814         if (dist < mindist) {
815             *pindex = i;
816             if (dist == 0)
817                 break;
818             mindist = dist;
819         }
820     }
821 
822     return 0;
823 }
824 
825 
826 /*!
827  *  pixcmapGetNearestGrayIndex()
828  *
829  *      Input:  cmap
830  *              val (gray value to search for; in range [0, ... 255])
831  *              &index (<return> the index of the nearest color)
832  *      Return: 0 if OK, 1 on error (caller must check)
833  *
834  *  Notes:
835  *      (1) This should be used on gray colormaps.  It uses only the
836  *          green value of the colormap.
837  *      (2) Returns the index of the exact color if possible, otherwise the
838  *          index of the color closest to the target color.
839  */
840 l_int32
pixcmapGetNearestGrayIndex(PIXCMAP * cmap,l_int32 val,l_int32 * pindex)841 pixcmapGetNearestGrayIndex(PIXCMAP  *cmap,
842                            l_int32   val,
843                            l_int32  *pindex)
844 {
845 l_int32     i, n, dist, mindist;
846 RGBA_QUAD  *cta;
847 
848     PROCNAME("pixcmapGetNearestGrayIndex");
849 
850     if (!pindex)
851         return ERROR_INT("&index not defined", procName, 1);
852     *pindex = 0;
853     if (!cmap)
854         return ERROR_INT("cmap not defined", procName, 1);
855     if (val < 0 || val > 255)
856         return ERROR_INT("val not in [0 ... 255]", procName, 1);
857 
858     if ((cta = (RGBA_QUAD *)cmap->array) == NULL)
859         return ERROR_INT("cta not defined(!)", procName, 1);
860     n = pixcmapGetCount(cmap);
861 
862     mindist = 256;
863     for (i = 0; i < n; i++) {
864         dist = cta[i].green - val;
865         dist = L_ABS(dist);
866         if (dist < mindist) {
867             *pindex = i;
868             if (dist == 0)
869                 break;
870             mindist = dist;
871         }
872     }
873 
874     return 0;
875 }
876 
877 
878 /*!
879  *  pixcmapGetExtremeValue()
880  *
881  *      Input:  cmap
882  *              type (L_CHOOSE_MIN or L_CHOOSE_MAX)
883  *              &rval (<optional return> red component)
884  *              &gval (<optional return> green component)
885  *              &bval (<optional return> blue component)
886  *      Return: 0 if OK, 1 on error
887  *
888  *  Notes:
889  *      (1) Returns for selected components the extreme value
890  *          (either min or max) of the color component that is
891  *          found in the colormap.
892  */
893 l_int32
pixcmapGetExtremeValue(PIXCMAP * cmap,l_int32 type,l_int32 * prval,l_int32 * pgval,l_int32 * pbval)894 pixcmapGetExtremeValue(PIXCMAP  *cmap,
895                        l_int32   type,
896                        l_int32  *prval,
897                        l_int32  *pgval,
898                        l_int32  *pbval)
899 {
900 l_int32  i, n, rval, gval, bval, extrval, extgval, extbval;
901 
902     PROCNAME("pixcmapGetExtremeValue");
903 
904     if (!prval && !pgval && !pbval)
905         return ERROR_INT("no result requested for return", procName, 1);
906     if (prval) *prval = 0;
907     if (pgval) *pgval = 0;
908     if (pbval) *pbval = 0;
909     if (!cmap)
910         return ERROR_INT("cmap not defined", procName, 1);
911     if (type != L_CHOOSE_MIN && type != L_CHOOSE_MAX)
912         return ERROR_INT("invalid type", procName, 1);
913 
914     if (type == L_CHOOSE_MIN) {
915         extrval = 100000;
916         extgval = 100000;
917         extbval = 100000;
918     }
919     else {
920         extrval = 0;
921         extgval = 0;
922         extbval = 0;
923     }
924 
925     n = pixcmapGetCount(cmap);
926     for (i = 0; i < n; i++) {
927         pixcmapGetColor(cmap, i, &rval, &gval, &bval);
928         if ((type == L_CHOOSE_MIN && rval < extrval) ||
929             (type == L_CHOOSE_MAX && rval > extrval))
930             extrval = rval;
931         if ((type == L_CHOOSE_MIN && gval < extgval) ||
932             (type == L_CHOOSE_MAX && gval > extgval))
933             extgval = gval;
934         if ((type == L_CHOOSE_MIN && bval < extbval) ||
935             (type == L_CHOOSE_MAX && bval > extbval))
936             extbval = bval;
937     }
938     if (prval) *prval = extrval;
939     if (pgval) *pgval = extgval;
940     if (pbval) *pbval = extbval;
941     return 0;
942 }
943 
944 
945 /*-------------------------------------------------------------*
946  *                       Colormap conversion                   *
947  *-------------------------------------------------------------*/
948 /*!
949  *  pixcmapGrayToColor()
950  *
951  *      Input:  color
952  *      Return: cmap, or null on error
953  *
954  *  Notes:
955  *      (1) This creates a colormap that maps from gray to
956  *          a specific color.  In the mapping, each component
957  *          is faded to white, depending on the gray value.
958  *      (2) In use, this is simply attached to a grayscale pix
959  *          to give it the input color.
960  */
961 PIXCMAP *
pixcmapGrayToColor(l_uint32 color)962 pixcmapGrayToColor(l_uint32  color)
963 {
964 l_int32   i, rval, gval, bval;
965 PIXCMAP  *cmap;
966 
967     extractRGBValues(color, &rval, &gval, &bval);
968     cmap = pixcmapCreate(8);
969     for (i = 0; i < 256; i++) {
970         pixcmapAddColor(cmap, rval + (i * (255 - rval)) / 255,
971                         gval + (i * (255 - gval)) / 255,
972                         bval + (i * (255 - bval)) / 255);
973     }
974 
975     return cmap;
976 }
977 
978 
979 /*!
980  *  pixcmapColorToGray()
981  *
982  *      Input:  cmap
983  *              rwt, gwt, bwt  (non-negative; these should add to 1.0)
984  *      Return: cmap (gray), or null on error
985  *
986  *  Notes:
987  *      (1) This creates a gray colormap from an arbitrary colormap.
988  *      (2) In use, attach the output gray colormap to the pix
989  *          (or a copy of it) that provided the input colormap.
990  */
991 PIXCMAP *
pixcmapColorToGray(PIXCMAP * cmaps,l_float32 rwt,l_float32 gwt,l_float32 bwt)992 pixcmapColorToGray(PIXCMAP   *cmaps,
993                    l_float32  rwt,
994                    l_float32  gwt,
995                    l_float32  bwt)
996 {
997 l_int32    i, n, rval, gval, bval, val;
998 l_float32  sum;
999 PIXCMAP   *cmapd;
1000 
1001     PROCNAME("pixcmapColorToGray");
1002 
1003     if (!cmaps)
1004         return (PIXCMAP *)ERROR_PTR("cmaps not defined", procName, NULL);
1005     if (rwt < 0.0 || gwt < 0.0 || bwt < 0.0)
1006         return (PIXCMAP *)ERROR_PTR("weights not all >= 0.0", procName, NULL);
1007 
1008         /* Make sure the sum of weights is 1.0; otherwise, you can get
1009          * overflow in the gray value. */
1010     sum = rwt + gwt + bwt;
1011     if (sum == 0.0) {
1012         L_WARNING("all weights zero; setting equal to 1/3", procName);
1013         rwt = gwt = bwt = 0.33333;
1014         sum = 1.0;
1015     }
1016     if (L_ABS(sum - 1.0) > 0.0001) {  /* maintain ratios with sum == 1.0 */
1017         L_WARNING("weights don't sum to 1; maintaining ratios", procName);
1018         rwt = rwt / sum;
1019         gwt = gwt / sum;
1020         bwt = bwt / sum;
1021     }
1022 
1023     cmapd = pixcmapCopy(cmaps);
1024     n = pixcmapGetCount(cmapd);
1025     for (i = 0; i < n; i++) {
1026         pixcmapGetColor(cmapd, i, &rval, &gval, &bval);
1027         val = (l_int32)(rwt * rval + gwt * gval + bwt * bval + 0.5);
1028         pixcmapResetColor(cmapd, i, val, val, val);
1029     }
1030 
1031     return cmapd;
1032 }
1033 
1034 
1035 /*-------------------------------------------------------------*
1036  *                         Colormap I/O                        *
1037  *-------------------------------------------------------------*/
1038 /*!
1039  *  pixcmapReadStream()
1040  *
1041  *      Input:  stream
1042  *      Return: cmap, or null on error
1043  */
1044 PIXCMAP *
pixcmapReadStream(FILE * fp)1045 pixcmapReadStream(FILE  *fp)
1046 {
1047 l_int32   rval, gval, bval;
1048 l_int32   i, index, ret, depth, ncolors;
1049 PIXCMAP  *cmap;
1050 
1051     PROCNAME("pixcmapReadStream");
1052 
1053     if (!fp)
1054         return (PIXCMAP *)ERROR_PTR("stream not defined", procName, NULL);
1055 
1056     ret = fscanf(fp, "\nPixcmap: depth = %d bpp; %d colors\n",
1057                  &depth, &ncolors);
1058     if (ret != 2 ||
1059         (depth != 1 && depth != 2 && depth != 4 && depth != 8) ||
1060         (ncolors < 2 || ncolors > 256))
1061         return (PIXCMAP *)ERROR_PTR("invalid cmap size", procName, NULL);
1062     fscanf(fp, "Color    R-val    G-val    B-val\n");
1063     fscanf(fp, "--------------------------------\n");
1064 
1065     if ((cmap = pixcmapCreate(depth)) == NULL)
1066         return (PIXCMAP *)ERROR_PTR("cmap not made", procName, NULL);
1067     for (i = 0; i < ncolors; i++) {
1068         fscanf(fp, "%3d       %3d      %3d      %3d\n",
1069                 &index, &rval, &gval, &bval);
1070         pixcmapAddColor(cmap, rval, gval, bval);
1071     }
1072 
1073     return cmap;
1074 }
1075 
1076 
1077 /*!
1078  *  pixcmapWriteStream()
1079  *
1080  *      Input:  stream, cmap
1081  *      Return: 0 if OK, 1 on error
1082  */
1083 l_int32
pixcmapWriteStream(FILE * fp,PIXCMAP * cmap)1084 pixcmapWriteStream(FILE     *fp,
1085                    PIXCMAP  *cmap)
1086 {
1087 l_int32  *rmap, *gmap, *bmap;
1088 l_int32   i;
1089 
1090     PROCNAME("pixcmapWriteStream");
1091 
1092     if (!fp)
1093         return ERROR_INT("stream not defined", procName, 1);
1094     if (!cmap)
1095         return ERROR_INT("cmap not defined", procName, 1);
1096 
1097     if (pixcmapToArrays(cmap, &rmap, &gmap, &bmap))
1098         return ERROR_INT("colormap arrays not made", procName, 1);
1099 
1100     fprintf(fp, "\nPixcmap: depth = %d bpp; %d colors\n", cmap->depth, cmap->n);
1101     fprintf(fp, "Color    R-val    G-val    B-val\n");
1102     fprintf(fp, "--------------------------------\n");
1103     for (i = 0; i < cmap->n; i++)
1104         fprintf(fp, "%3d       %3d      %3d      %3d\n",
1105                 i, rmap[i], gmap[i], bmap[i]);
1106     fprintf(fp, "\n");
1107 
1108     FREE(rmap);
1109     FREE(gmap);
1110     FREE(bmap);
1111     return 0;
1112 }
1113 
1114 
1115 /*-------------------------------------------------------------*
1116  *                   Extract colormap arrays                   *
1117  *-------------------------------------------------------------*/
1118 /*!
1119  *  pixcmapToArrays()
1120  *
1121  *      Input:  colormap
1122  *              &rmap, &gmap, &bmap  (<return> colormap arrays)
1123  *      Return: 0 if OK; 1 on error
1124  */
1125 l_int32
pixcmapToArrays(PIXCMAP * cmap,l_int32 ** prmap,l_int32 ** pgmap,l_int32 ** pbmap)1126 pixcmapToArrays(PIXCMAP   *cmap,
1127                 l_int32  **prmap,
1128                 l_int32  **pgmap,
1129                 l_int32  **pbmap)
1130 {
1131 l_int32    *rmap, *gmap, *bmap;
1132 l_int32     i, ncolors;
1133 RGBA_QUAD  *cta;
1134 
1135     PROCNAME("pixcmapToArrays");
1136 
1137     if (!prmap || !pgmap || !pbmap)
1138         return ERROR_INT("&rmap, &gmap, &bmap not all defined", procName, 1);
1139     *prmap = *pgmap = *pbmap = NULL;
1140     if (!cmap)
1141         return ERROR_INT("cmap not defined", procName, 1);
1142 
1143     ncolors = pixcmapGetCount(cmap);
1144     if (((rmap = (l_int32 *)CALLOC(ncolors, sizeof(l_int32))) == NULL) ||
1145         ((gmap = (l_int32 *)CALLOC(ncolors, sizeof(l_int32))) == NULL) ||
1146         ((bmap = (l_int32 *)CALLOC(ncolors, sizeof(l_int32))) == NULL))
1147             return ERROR_INT("calloc fail for *map", procName, 1);
1148     *prmap = rmap;
1149     *pgmap = gmap;
1150     *pbmap = bmap;
1151 
1152     cta = (RGBA_QUAD *)cmap->array;
1153     for (i = 0; i < ncolors; i++) {
1154         rmap[i] = cta[i].red;
1155         gmap[i] = cta[i].green;
1156         bmap[i] = cta[i].blue;
1157     }
1158 
1159     return 0;
1160 }
1161 
1162 
1163 /*!
1164  *  pixcmapToRGBTable()
1165  *
1166  *      Input:  colormap
1167  *              &tab (<return> table of rgba values for the colormap)
1168  *              &ncolors (<optional return> size of table)
1169  *      Return: 0 if OK; 1 on error
1170  */
1171 l_int32
pixcmapToRGBTable(PIXCMAP * cmap,l_uint32 ** ptab,l_int32 * pncolors)1172 pixcmapToRGBTable(PIXCMAP    *cmap,
1173                   l_uint32  **ptab,
1174                   l_int32    *pncolors)
1175 {
1176 l_int32    i, ncolors, rval, gval, bval;
1177 l_uint32  *tab;
1178 
1179     PROCNAME("pixcmapToRGBTable");
1180 
1181     if (!ptab)
1182         return ERROR_INT("&tab not defined", procName, 1);
1183     *ptab = NULL;
1184     if (!cmap)
1185         return ERROR_INT("cmap not defined", procName, 1);
1186 
1187     ncolors = pixcmapGetCount(cmap);
1188     if (pncolors)
1189         *pncolors = ncolors;
1190     if ((tab = (l_uint32 *)CALLOC(ncolors, sizeof(l_uint32))) == NULL)
1191         return ERROR_INT("tab not made", procName, 1);
1192     *ptab = tab;
1193 
1194     for (i = 0; i < ncolors; i++) {
1195         pixcmapGetColor(cmap, i, &rval, &gval, &bval);
1196         composeRGBPixel(rval, gval, bval, &tab[i]);
1197     }
1198 
1199 /*    for (i = 0; i < ncolors; i++)
1200         fprintf(stderr, "Color[%d] = %x\n", i, tab[i]); */
1201 
1202     return 0;
1203 }
1204 
1205 
1206 /*-------------------------------------------------------------*
1207  *                     Colormap transforms                     *
1208  *-------------------------------------------------------------*/
1209 /*!
1210  *  pixcmapGammaTRC()
1211  *
1212  *      Input:  colormap
1213  *              gamma (gamma correction; must be > 0.0)
1214  *              minval  (input value that gives 0 for output; can be < 0)
1215  *              maxval  (input value that gives 255 for output; can be > 255)
1216  *      Return: 0 if OK; 1 on error
1217  *
1218  *  Notes:
1219  *      - in-place transform
1220  *      - see pixGammaTRC() and numaGammaTRC() in enhance.c for
1221  *        description and use of transform
1222  */
1223 l_int32
pixcmapGammaTRC(PIXCMAP * cmap,l_float32 gamma,l_int32 minval,l_int32 maxval)1224 pixcmapGammaTRC(PIXCMAP   *cmap,
1225                 l_float32  gamma,
1226                 l_int32    minval,
1227                 l_int32    maxval)
1228 {
1229 l_int32   rval, gval, bval, trval, tgval, tbval, i, ncolors;
1230 NUMA     *nag;
1231 
1232     PROCNAME("pixcmapGammaTRC");
1233 
1234     if (!cmap)
1235         return ERROR_INT("cmap not defined", procName, 1);
1236     if (gamma <= 0.0) {
1237         L_WARNING("gamma must be > 0.0; setting to 1.0", procName);
1238         gamma = 1.0;
1239     }
1240     if (minval >= maxval)
1241         return ERROR_INT("minval not < maxval", procName, 1);
1242 
1243     if ((nag = numaGammaTRC(gamma, minval, maxval)) == NULL)
1244         return ERROR_INT("nag not made", procName, 1);
1245 
1246     ncolors = pixcmapGetCount(cmap);
1247     for (i = 0; i < ncolors; i++) {
1248         pixcmapGetColor(cmap, i, &rval, &gval, &bval);
1249         numaGetIValue(nag, rval, &trval);
1250         numaGetIValue(nag, gval, &tgval);
1251         numaGetIValue(nag, bval, &tbval);
1252         pixcmapResetColor(cmap, i, trval, tgval, tbval);
1253     }
1254 
1255     numaDestroy(&nag);
1256     return 0;
1257 }
1258 
1259 
1260 /*!
1261  *  pixcmapContrastTRC()
1262  *
1263  *      Input:  colormap
1264  *              factor (generally between 0.0 (no enhancement)
1265  *                      and 1.0, but can be larger than 1.0)
1266  *      Return: 0 if OK; 1 on error
1267  *
1268  *  Notes:
1269  *      - in-place transform
1270  *      - see pixContrastTRC() and numaContrastTRC() in enhance.c for
1271  *        description and use of transform
1272  */
1273 l_int32
pixcmapContrastTRC(PIXCMAP * cmap,l_float32 factor)1274 pixcmapContrastTRC(PIXCMAP   *cmap,
1275                    l_float32  factor)
1276 {
1277 l_int32   i, ncolors, rval, gval, bval, trval, tgval, tbval;
1278 NUMA     *nac;
1279 
1280     PROCNAME("pixcmapContrastTRC");
1281 
1282     if (!cmap)
1283         return ERROR_INT("cmap not defined", procName, 1);
1284     if (factor < 0.0) {
1285         L_WARNING("factor must be >= 0.0; setting to 0.0", procName);
1286         factor = 0.0;
1287     }
1288 
1289     if ((nac = numaContrastTRC(factor)) == NULL)
1290         return ERROR_INT("nac not made", procName, 1);
1291 
1292     ncolors = pixcmapGetCount(cmap);
1293     for (i = 0; i < ncolors; i++) {
1294         pixcmapGetColor(cmap, i, &rval, &gval, &bval);
1295         numaGetIValue(nac, rval, &trval);
1296         numaGetIValue(nac, gval, &tgval);
1297         numaGetIValue(nac, bval, &tbval);
1298         pixcmapResetColor(cmap, i, trval, tgval, tbval);
1299     }
1300 
1301     numaDestroy(&nac);
1302     return 0;
1303 }
1304 
1305 
1306 /*!
1307  *  pixcmapShiftIntensity()
1308  *
1309  *      Input:  colormap
1310  *              fraction (between -1.0 and +1.0)
1311  *      Return: 0 if OK; 1 on error
1312  *
1313  *  Notes:
1314  *      - in-place transform
1315  *      - This does a proportional shift of the intensity for each color.
1316  *      - If fraction < 0.0, it moves all colors towards (0,0,0).
1317  *        This darkens the image.
1318  *      - If fraction > 0.0, it moves all colors towards (255,255,255)
1319  *        This fades the image.
1320  *      - The equivalent transform can be accomplished with pixcmapGammaTRC(),
1321  *        but it is considerably more difficult (see numaGammaTRC()).
1322  */
1323 l_int32
pixcmapShiftIntensity(PIXCMAP * cmap,l_float32 fraction)1324 pixcmapShiftIntensity(PIXCMAP   *cmap,
1325                       l_float32  fraction)
1326 {
1327 l_int32   i, ncolors, rval, gval, bval;
1328 
1329     PROCNAME("pixcmapShiftIntensity");
1330 
1331     if (!cmap)
1332         return ERROR_INT("cmap not defined", procName, 1);
1333     if (fraction < -1.0 || fraction > 1.0)
1334         return ERROR_INT("fraction not in [-1.0, 1.0]", procName, 1);
1335 
1336     ncolors = pixcmapGetCount(cmap);
1337     for (i = 0; i < ncolors; i++) {
1338         pixcmapGetColor(cmap, i, &rval, &gval, &bval);
1339         if (fraction < 0.0)
1340             pixcmapResetColor(cmap, i,
1341                               (l_int32)((1.0 + fraction) * rval),
1342                               (l_int32)((1.0 + fraction) * gval),
1343                               (l_int32)((1.0 + fraction) * bval));
1344         else
1345             pixcmapResetColor(cmap, i,
1346                               rval + (l_int32)(fraction * (255 - rval)),
1347                               gval + (l_int32)(fraction * (255 - gval)),
1348                               bval + (l_int32)(fraction * (255 - bval)));
1349     }
1350 
1351     return 0;
1352 }
1353 
1354 
1355 /*!
1356  *  pixcmapConvertRGBToHSV()
1357  *
1358  *      Input:  colormap
1359  *      Return: 0 if OK; 1 on error
1360  *
1361  *  Notes:
1362  *      - in-place transform
1363  *      - See convertRGBToHSV() for def'n of HSV space.
1364  *      - replaces: r --> h, g --> s, b --> v
1365  */
1366 l_int32
pixcmapConvertRGBToHSV(PIXCMAP * cmap)1367 pixcmapConvertRGBToHSV(PIXCMAP  *cmap)
1368 {
1369 l_int32   i, ncolors, rval, gval, bval, hval, sval, vval;
1370 
1371     PROCNAME("pixcmapConvertRGBToHSV");
1372 
1373     if (!cmap)
1374         return ERROR_INT("cmap not defined", procName, 1);
1375 
1376     ncolors = pixcmapGetCount(cmap);
1377     for (i = 0; i < ncolors; i++) {
1378         pixcmapGetColor(cmap, i, &rval, &gval, &bval);
1379         convertRGBToHSV(rval, gval, bval, &hval, &sval, &vval);
1380         pixcmapResetColor(cmap, i, hval, sval, vval);
1381     }
1382     return 0;
1383 }
1384 
1385 
1386 /*!
1387  *  pixcmapConvertHSVToRGB()
1388  *
1389  *      Input:  colormap
1390  *      Return: 0 if OK; 1 on error
1391  *
1392  *  Notes:
1393  *      - in-place transform
1394  *      - See convertRGBToHSV() for def'n of HSV space.
1395  *      - replaces: h --> r, s --> g, v --> b
1396  */
1397 l_int32
pixcmapConvertHSVToRGB(PIXCMAP * cmap)1398 pixcmapConvertHSVToRGB(PIXCMAP  *cmap)
1399 {
1400 l_int32   i, ncolors, rval, gval, bval, hval, sval, vval;
1401 
1402     PROCNAME("pixcmapConvertHSVToRGB");
1403 
1404     if (!cmap)
1405         return ERROR_INT("cmap not defined", procName, 1);
1406 
1407     ncolors = pixcmapGetCount(cmap);
1408     for (i = 0; i < ncolors; i++) {
1409         pixcmapGetColor(cmap, i, &hval, &sval, &vval);
1410         convertHSVToRGB(hval, sval, vval, &rval, &gval, &bval);
1411         pixcmapResetColor(cmap, i, rval, gval, bval);
1412     }
1413     return 0;
1414 }
1415 
1416