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