Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
colormap.c
Go to the documentation of this file.
1/*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 -
4 - Redistribution and use in source and binary forms, with or without
5 - modification, are permitted provided that the following conditions
6 - are met:
7 - 1. Redistributions of source code must retain the above copyright
8 - notice, this list of conditions and the following disclaimer.
9 - 2. Redistributions in binary form must reproduce the above
10 - copyright notice, this list of conditions and the following
11 - disclaimer in the documentation and/or other materials
12 - provided with the distribution.
13 -
14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *====================================================================*/
26
107#ifdef HAVE_CONFIG_H
108#include <config_auto.h>
109#endif /* HAVE_CONFIG_H */
110
111#include <math.h>
112#include <string.h>
113#include "allheaders.h"
114#include "pix_internal.h"
115
116/*-------------------------------------------------------------*
117 * Colormap creation and addition *
118 *-------------------------------------------------------------*/
125PIXCMAP *
126pixcmapCreate(l_int32 depth)
127{
128RGBA_QUAD *cta;
129PIXCMAP *cmap;
130
131 if (depth != 1 && depth != 2 && depth !=4 && depth != 8)
132 return (PIXCMAP *)ERROR_PTR("depth not in {1,2,4,8}", __func__, NULL);
133
134 cmap = (PIXCMAP *)LEPT_CALLOC(1, sizeof(PIXCMAP));
135 cmap->depth = depth;
136 cmap->nalloc = 1 << depth;
137 cta = (RGBA_QUAD *)LEPT_CALLOC(cmap->nalloc, sizeof(RGBA_QUAD));
138 cmap->array = cta;
139 cmap->n = 0;
140 return cmap;
141}
142
143
170PIXCMAP *
172 l_int32 hasblack,
173 l_int32 haswhite)
174{
175l_int32 ncolors, i;
176l_int32 red[256], green[256], blue[256];
177PIXCMAP *cmap;
178
179 if (depth != 2 && depth != 4 && depth != 8)
180 return (PIXCMAP *)ERROR_PTR("depth not in {2, 4, 8}", __func__, NULL);
181 if (hasblack != 0) hasblack = 1;
182 if (haswhite != 0) haswhite = 1;
183
184 cmap = pixcmapCreate(depth);
185 ncolors = 1 << depth;
186 if (hasblack) /* first color is optionally black */
187 pixcmapAddColor(cmap, 0, 0, 0);
188 for (i = hasblack; i < ncolors - haswhite; i++) {
189 red[i] = (l_uint32)rand() & 0xff;
190 green[i] = (l_uint32)rand() & 0xff;
191 blue[i] = (l_uint32)rand() & 0xff;
192 pixcmapAddColor(cmap, red[i], green[i], blue[i]);
193 }
194 if (haswhite) /* last color is optionally white */
195 pixcmapAddColor(cmap, 255, 255, 255);
196
197 return cmap;
198}
199
200
214PIXCMAP *
216 l_int32 nlevels)
217{
218l_int32 maxlevels, i, val;
219PIXCMAP *cmap;
220
221 if (d != 1 && d != 2 && d !=4 && d != 8)
222 return (PIXCMAP *)ERROR_PTR("d not in {1, 2, 4, 8}", __func__, NULL);
223 maxlevels = 1 << d;
224 if (nlevels < 2 || nlevels > maxlevels)
225 return (PIXCMAP *)ERROR_PTR("invalid nlevels", __func__, NULL);
226
227 cmap = pixcmapCreate(d);
228 for (i = 0; i < nlevels; i++) {
229 val = (255 * i) / (nlevels - 1);
230 pixcmapAddColor(cmap, val, val, val);
231 }
232 return cmap;
233}
234
235
242PIXCMAP *
243pixcmapCopy(const PIXCMAP *cmaps)
244{
245l_int32 nbytes, valid;
246PIXCMAP *cmapd;
247
248 if (!cmaps)
249 return (PIXCMAP *)ERROR_PTR("cmaps not defined", __func__, NULL);
250 pixcmapIsValid(cmaps, NULL, &valid);
251 if (!valid)
252 return (PIXCMAP *)ERROR_PTR("invalid cmap", __func__, NULL);
253
254 cmapd = (PIXCMAP *)LEPT_CALLOC(1, sizeof(PIXCMAP));
255 nbytes = cmaps->nalloc * sizeof(RGBA_QUAD);
256 cmapd->array = (void *)LEPT_CALLOC(1, nbytes);
257 memcpy(cmapd->array, cmaps->array, cmaps->n * sizeof(RGBA_QUAD));
258 cmapd->n = cmaps->n;
259 cmapd->nalloc = cmaps->nalloc;
260 cmapd->depth = cmaps->depth;
261 return cmapd;
262}
263
264
271void
273{
274PIXCMAP *cmap;
275
276 if (pcmap == NULL) {
277 L_WARNING("ptr address is null!\n", __func__);
278 return;
279 }
280
281 if ((cmap = *pcmap) == NULL)
282 return;
283
284 LEPT_FREE(cmap->array);
285 LEPT_FREE(cmap);
286 *pcmap = NULL;
287}
288
307l_ok
309 PIX *pix,
310 l_int32 *pvalid)
311{
312l_int32 d, depth, nalloc, maxindex, maxcolors;
313
314 if (!pvalid)
315 return ERROR_INT("&valid not defined", __func__, 1);
316 *pvalid = 0;
317 if (!cmap)
318 return ERROR_INT("cmap not defined", __func__, 1);
319 if (!cmap->array)
320 return ERROR_INT("cmap array not defined", __func__, 1);
321 d = cmap->depth;
322 if (d != 1 && d != 2 && d != 4 && d != 8) {
323 L_ERROR("invalid cmap depth: %d\n", __func__, d);
324 return 1;
325 }
326 nalloc = cmap->nalloc;
327 if (nalloc != (1 << d)) {
328 L_ERROR("invalid cmap nalloc = %d; d = %d\n", __func__, nalloc, d);
329 return 1;
330 }
331 if (cmap->n < 0 || cmap->n > nalloc) {
332 L_ERROR("invalid cmap n: %d; nalloc = %d\n", __func__, cmap->n, nalloc);
333 return 1;
334 }
335
336 /* If a pix is given, it must have a depth no larger than 8 */
337 if (pix) {
338 depth = pixGetDepth(pix);
339 if (depth > 8) {
340 L_ERROR("pix depth %d > 8\n", __func__, depth);
341 return 1;
342 }
343 maxcolors = 1 << depth;
344 }
345
346 /* To prevent indexing overflow into the cmap, the pix depth
347 * must not exceed the cmap depth. Do not require depth equality,
348 * because some functions such as median cut quantizers allow
349 * the cmap depth to be bigger than the pix depth. */
350 if (pix && (depth > d)) {
351 L_ERROR("(pix depth = %d) > (cmap depth = %d)\n", __func__, depth, d);
352 return 1;
353 }
354 if (pix && cmap->n < 1) {
355 L_ERROR("cmap array is empty; invalid with any pix\n", __func__);
356 return 1;
357 }
358
359 /* Do not let the colormap have more colors than the pixels
360 * can address. The png encoder considers this to be an
361 * "invalid palette length". For example, for 1 bpp, the
362 * colormap may have a depth > 1, but it must not have more
363 * than 2 colors. */
364 if (pix && (cmap->n > maxcolors)) {
365 L_ERROR("cmap entries = %d > max colors for pix = %d\n", __func__,
366 cmap->n, maxcolors);
367 return 1;
368 }
369
370 /* Where the colormap or the pix may have been corrupted, and
371 * in particular when reading or writing image files, it should
372 * be verified that the largest colormap index value in the image
373 * is less than the number of entries in the colormap array. */
374 if (pix) {
375 pixGetMaxColorIndex(pix, &maxindex);
376 if (maxindex >= cmap->n) {
377 L_ERROR("(max index in image = %d) >= "
378 "(number entries in colormap = %d)\n", __func__,
379 maxindex, cmap->n);
380 return 1;
381 }
382 }
383
384 *pvalid = 1;
385 return 0;
386}
387
388
403l_ok
405 l_int32 rval,
406 l_int32 gval,
407 l_int32 bval)
408{
409RGBA_QUAD *cta;
410
411 if (!cmap)
412 return ERROR_INT("cmap not defined", __func__, 1);
413 if (cmap->n >= cmap->nalloc)
414 return ERROR_INT("no free color entries", __func__, 1);
415
416 cta = (RGBA_QUAD *)cmap->array;
417 cta[cmap->n].red = rval;
418 cta[cmap->n].green = gval;
419 cta[cmap->n].blue = bval;
420 cta[cmap->n].alpha = 255;
421 cmap->n++;
422 return 0;
423}
424
425
439l_ok
441 l_int32 rval,
442 l_int32 gval,
443 l_int32 bval,
444 l_int32 aval)
445{
446RGBA_QUAD *cta;
447
448 if (!cmap)
449 return ERROR_INT("cmap not defined", __func__, 1);
450 if (cmap->n >= cmap->nalloc)
451 return ERROR_INT("no free color entries", __func__, 1);
452
453 cta = (RGBA_QUAD *)cmap->array;
454 cta[cmap->n].red = rval;
455 cta[cmap->n].green = gval;
456 cta[cmap->n].blue = bval;
457 cta[cmap->n].alpha = aval;
458 cmap->n++;
459 return 0;
460}
461
462
481l_ok
483 l_int32 rval,
484 l_int32 gval,
485 l_int32 bval,
486 l_int32 *pindex)
487{
488 if (!pindex)
489 return ERROR_INT("&index not defined", __func__, 1);
490 *pindex = 0;
491 if (!cmap)
492 return ERROR_INT("cmap not defined", __func__, 1);
493
494 /* Check if the color is already present. */
495 if (!pixcmapGetIndex(cmap, rval, gval, bval, pindex)) /* found */
496 return 0;
497
498 /* We need to add the color. Is there room? */
499 if (cmap->n >= cmap->nalloc) {
500 L_WARNING("no free color entries\n", __func__);
501 return 2;
502 }
503
504 /* There's room. Add it. */
505 pixcmapAddColor(cmap, rval, gval, bval);
506 *pindex = pixcmapGetCount(cmap) - 1;
507 return 0;
508}
509
510
528l_ok
530 l_int32 rval,
531 l_int32 gval,
532 l_int32 bval,
533 l_int32 *pindex)
534{
535 if (!pindex)
536 return ERROR_INT("&index not defined", __func__, 1);
537 *pindex = 0;
538 if (!cmap)
539 return ERROR_INT("cmap not defined", __func__, 1);
540
541 /* Check if the color is already present. */
542 if (!pixcmapGetIndex(cmap, rval, gval, bval, pindex)) /* found */
543 return 0;
544
545 /* We need to add the color. Is there room? */
546 if (cmap->n < cmap->nalloc) {
547 pixcmapAddColor(cmap, rval, gval, bval);
548 *pindex = pixcmapGetCount(cmap) - 1;
549 return 0;
550 }
551
552 /* There's no room. Return the index of the nearest color */
553 pixcmapGetNearestIndex(cmap, rval, gval, bval, pindex);
554 return 0;
555}
556
557
573l_ok
575 l_int32 rval,
576 l_int32 gval,
577 l_int32 bval,
578 l_int32 *pusable)
579{
580l_int32 index;
581
582 if (!pusable)
583 return ERROR_INT("&usable not defined", __func__, 1);
584 *pusable = 0;
585 if (!cmap)
586 return ERROR_INT("cmap not defined", __func__, 1);
587
588 /* Is there room to add it? */
589 if (cmap->n < cmap->nalloc) {
590 *pusable = 1;
591 return 0;
592 }
593
594 /* No room; check if the color is already present. */
595 if (!pixcmapGetIndex(cmap, rval, gval, bval, &index)) /* found */
596 *pusable = 1;
597 return 0;
598}
599
600
618l_ok
620 l_int32 color,
621 l_int32 *pindex)
622{
623l_int32 index;
624
625 if (pindex) *pindex = 0;
626 if (!cmap)
627 return ERROR_INT("cmap not defined", __func__, 1);
628
629 if (color == 0) { /* black */
630 if (pixcmapGetFreeCount(cmap) > 0)
631 pixcmapAddNewColor(cmap, 0, 0, 0, &index);
632 else
633 pixcmapGetRankIntensity(cmap, 0.0, &index);
634 } else { /* white */
635 if (pixcmapGetFreeCount(cmap) > 0)
636 pixcmapAddNewColor(cmap, 255, 255, 255, &index);
637 else
638 pixcmapGetRankIntensity(cmap, 1.0, &index);
639 }
640
641 if (pindex)
642 *pindex = index;
643 return 0;
644}
645
646
655l_ok
657 l_int32 setblack,
658 l_int32 setwhite)
659{
660l_int32 index;
661
662 if (!cmap)
663 return ERROR_INT("cmap not defined", __func__, 1);
664
665 if (setblack) {
666 pixcmapGetRankIntensity(cmap, 0.0, &index);
667 pixcmapResetColor(cmap, index, 0, 0, 0);
668 }
669 if (setwhite) {
670 pixcmapGetRankIntensity(cmap, 1.0, &index);
671 pixcmapResetColor(cmap, index, 255, 255, 255);
672 }
673 return 0;
674}
675
676
683l_int32
685{
686 if (!cmap)
687 return ERROR_INT("cmap not defined", __func__, 0);
688 return cmap->n;
689}
690
691
698l_int32
700{
701 if (!cmap)
702 return ERROR_INT("cmap not defined", __func__, 0);
703 return (cmap->nalloc - cmap->n);
704}
705
706
713l_int32
715{
716 if (!cmap)
717 return ERROR_INT("cmap not defined", __func__, 0);
718 return cmap->depth;
719}
720
721
734l_ok
736 l_int32 *pmindepth)
737{
738l_int32 ncolors;
739
740 if (!pmindepth)
741 return ERROR_INT("&mindepth not defined", __func__, 1);
742 *pmindepth = 0;
743 if (!cmap)
744 return ERROR_INT("cmap not defined", __func__, 1);
745
746 ncolors = pixcmapGetCount(cmap);
747 if (ncolors <= 4)
748 *pmindepth = 2;
749 else if (ncolors <= 16)
750 *pmindepth = 4;
751 else /* ncolors > 16 */
752 *pmindepth = 8;
753 return 0;
754}
755
756
768l_ok
770{
771 if (!cmap)
772 return ERROR_INT("cmap not defined", __func__, 1);
773 cmap->n = 0;
774 return 0;
775}
776
777
778/*-------------------------------------------------------------*
779 * Colormap random access *
780 *-------------------------------------------------------------*/
789l_ok
791 l_int32 index,
792 l_int32 *prval,
793 l_int32 *pgval,
794 l_int32 *pbval)
795{
796RGBA_QUAD *cta;
797
798 if (!prval || !pgval || !pbval)
799 return ERROR_INT("&rval, &gval, &bval not all defined", __func__, 1);
800 *prval = *pgval = *pbval = 0;
801 if (!cmap)
802 return ERROR_INT("cmap not defined", __func__, 1);
803 if (index < 0 || index >= cmap->n)
804 return ERROR_INT("index out of bounds", __func__, 1);
805
806 cta = (RGBA_QUAD *)cmap->array;
807 *prval = cta[index].red;
808 *pgval = cta[index].green;
809 *pbval = cta[index].blue;
810 return 0;
811}
812
813
827l_ok
829 l_int32 index,
830 l_uint32 *pval32)
831{
832l_int32 rval, gval, bval;
833
834 if (!pval32)
835 return ERROR_INT("&val32 not defined", __func__, 1);
836 *pval32 = 0;
837
838 if (pixcmapGetColor(cmap, index, &rval, &gval, &bval) != 0)
839 return ERROR_INT("rgb values not found", __func__, 1);
840 composeRGBAPixel(rval, gval, bval, 255, pval32);
841 return 0;
842}
843
844
853l_ok
855 l_int32 index,
856 l_int32 *prval,
857 l_int32 *pgval,
858 l_int32 *pbval,
859 l_int32 *paval)
860{
861RGBA_QUAD *cta;
862
863 if (!prval || !pgval || !pbval || !paval)
864 return ERROR_INT("&rval, &gval, &bval, &aval not all defined",
865 __func__, 1);
866 *prval = *pgval = *pbval = *paval = 0;
867 if (!cmap)
868 return ERROR_INT("cmap not defined", __func__, 1);
869 if (index < 0 || index >= cmap->n)
870 return ERROR_INT("index out of bounds", __func__, 1);
871
872 cta = (RGBA_QUAD *)cmap->array;
873 *prval = cta[index].red;
874 *pgval = cta[index].green;
875 *pbval = cta[index].blue;
876 *paval = cta[index].alpha;
877 return 0;
878}
879
880
889l_ok
891 l_int32 index,
892 l_uint32 *pval32)
893{
894l_int32 rval, gval, bval, aval;
895
896 if (!pval32)
897 return ERROR_INT("&val32 not defined", __func__, 1);
898 *pval32 = 0;
899
900 if (pixcmapGetRGBA(cmap, index, &rval, &gval, &bval, &aval) != 0)
901 return ERROR_INT("rgba values not found", __func__, 1);
902 composeRGBAPixel(rval, gval, bval, aval, pval32);
903 return 0;
904}
905
906
923l_ok
925 l_int32 index,
926 l_int32 rval,
927 l_int32 gval,
928 l_int32 bval)
929{
930RGBA_QUAD *cta;
931
932 if (!cmap)
933 return ERROR_INT("cmap not defined", __func__, 1);
934 if (index < 0 || index >= cmap->n)
935 return ERROR_INT("index out of bounds", __func__, 1);
936
937 cta = (RGBA_QUAD *)cmap->array;
938 cta[index].red = rval;
939 cta[index].green = gval;
940 cta[index].blue = bval;
941 cta[index].alpha = 255;
942 return 0;
943}
944
945
962l_ok
964 l_int32 index,
965 l_int32 aval)
966{
967RGBA_QUAD *cta;
968
969 if (!cmap)
970 return ERROR_INT("cmap not defined", __func__, 1);
971 if (index < 0 || index >= cmap->n)
972 return ERROR_INT("index out of bounds", __func__, 1);
973
974 cta = (RGBA_QUAD *)cmap->array;
975 cta[index].alpha = aval;
976 return 0;
977}
978
979
989l_int32
991 l_int32 rval,
992 l_int32 gval,
993 l_int32 bval,
994 l_int32 *pindex)
995{
996l_int32 n, i;
997RGBA_QUAD *cta;
998
999 if (!pindex)
1000 return ERROR_INT("&index not defined", __func__, 1);
1001 *pindex = 0;
1002 if (!cmap)
1003 return ERROR_INT("cmap not defined", __func__, 1);
1004 n = pixcmapGetCount(cmap);
1005
1006 cta = (RGBA_QUAD *)cmap->array;
1007 for (i = 0; i < n; i++) {
1008 if (rval == cta[i].red &&
1009 gval == cta[i].green &&
1010 bval == cta[i].blue) {
1011 *pindex = i;
1012 return 0;
1013 }
1014 }
1015 return 1;
1016}
1017
1018
1026l_ok
1028 l_int32 *pcolor)
1029{
1030l_int32 n, i;
1031l_int32 *rmap, *gmap, *bmap;
1032
1033 if (!pcolor)
1034 return ERROR_INT("&color not defined", __func__, 1);
1035 *pcolor = FALSE;
1036 if (!cmap)
1037 return ERROR_INT("cmap not defined", __func__, 1);
1038
1039 if (pixcmapToArrays(cmap, &rmap, &gmap, &bmap, NULL))
1040 return ERROR_INT("colormap arrays not made", __func__, 1);
1041 n = pixcmapGetCount(cmap);
1042 for (i = 0; i < n; i++) {
1043 if ((rmap[i] != gmap[i]) || (rmap[i] != bmap[i])) {
1044 *pcolor = TRUE;
1045 break;
1046 }
1047 }
1048
1049 LEPT_FREE(rmap);
1050 LEPT_FREE(gmap);
1051 LEPT_FREE(bmap);
1052 return 0;
1053}
1054
1055
1063l_ok
1065 l_int32 *popaque)
1066{
1067l_int32 i, n;
1068RGBA_QUAD *cta;
1069
1070 if (!popaque)
1071 return ERROR_INT("&opaque not defined", __func__, 1);
1072 *popaque = TRUE;
1073 if (!cmap)
1074 return ERROR_INT("cmap not defined", __func__, 1);
1075
1076 n = pixcmapGetCount(cmap);
1077 cta = (RGBA_QUAD *)cmap->array;
1078 for (i = 0; i < n; i++) {
1079 if (cta[i].alpha != 255) {
1080 *popaque = FALSE;
1081 break;
1082 }
1083 }
1084 return 0;
1085}
1086
1087
1120l_ok
1122 l_int32 *pntrans,
1123 l_int32 *pmax_trans,
1124 l_int32 *pmin_opaque)
1125{
1126l_int32 i, n, ntrans, max_trans, min_opaque, opaque_found;
1127RGBA_QUAD *cta;
1128
1129 if (pntrans) *pntrans = 0;
1130 if (pmax_trans) *pmax_trans = -1;
1131 if (pmin_opaque) *pmin_opaque = 256;
1132 if (!cmap)
1133 return ERROR_INT("cmap not defined", __func__, 1);
1134
1135 n = pixcmapGetCount(cmap);
1136 ntrans = 0;
1137 max_trans = -1;
1138 min_opaque = n;
1139 cta = (RGBA_QUAD *)cmap->array;
1140 opaque_found = FALSE;
1141 for (i = 0; i < n; i++) {
1142 if (cta[i].alpha != 255) {
1143 ntrans++;
1144 max_trans = i;
1145 } else if (opaque_found == FALSE) {
1146 opaque_found = TRUE;
1147 min_opaque = i;
1148 }
1149 }
1150 if (pntrans) *pntrans = ntrans;
1151 if (pmax_trans) *pmax_trans = max_trans;
1152 if (pmin_opaque) *pmin_opaque = min_opaque;
1153 return 0;
1154}
1155
1156
1165l_ok
1167 l_int32 *pblackwhite)
1168{
1169l_int32 val0, val1, hascolor;
1170RGBA_QUAD *cta;
1171
1172 if (!pblackwhite)
1173 return ERROR_INT("&blackwhite not defined", __func__, 1);
1174 *pblackwhite = FALSE;
1175 if (!cmap)
1176 return ERROR_INT("cmap not defined", __func__, 1);
1177 if (pixcmapGetCount(cmap) != 2)
1178 return 0;
1179
1180 pixcmapHasColor(cmap, &hascolor);
1181 if (hascolor) return 0;
1182
1183 cta = (RGBA_QUAD *)cmap->array;
1184 val0 = cta[0].red;
1185 val1 = cta[1].red;
1186 if ((val0 == 0 && val1 == 255) || (val0 == 255 && val1 == 0))
1187 *pblackwhite = TRUE;
1188 return 0;
1189}
1190
1191
1204l_ok
1206 l_int32 *pngray)
1207{
1208l_int32 n, i, rval, gval, bval, count;
1209l_int32 *array;
1210
1211 if (!pngray)
1212 return ERROR_INT("&ngray not defined", __func__, 1);
1213 *pngray = 0;
1214 if (!cmap)
1215 return ERROR_INT("cmap not defined", __func__, 1);
1216
1217 array = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
1218 n = pixcmapGetCount(cmap);
1219 count = 0;
1220 for (i = 0; i < n; i++) {
1221 pixcmapGetColor(cmap, i, &rval, &gval, &bval);
1222 if ((rval == gval) && (rval == bval) && (array[rval] == 0)) {
1223 array[rval] = 1;
1224 count++;
1225 }
1226 }
1227
1228 LEPT_FREE(array);
1229 *pngray = count;
1230 return 0;
1231}
1232
1233
1243l_ok
1245 l_float32 rankval,
1246 l_int32 *pindex)
1247{
1248l_int32 n, i, rval, gval, bval, rankindex;
1249NUMA *na, *nasort;
1250
1251 if (!pindex)
1252 return ERROR_INT("&index not defined", __func__, 1);
1253 *pindex = 0;
1254 if (!cmap)
1255 return ERROR_INT("cmap not defined", __func__, 1);
1256 if (rankval < 0.0 || rankval > 1.0)
1257 return ERROR_INT("rankval not in [0.0 ... 1.0]", __func__, 1);
1258
1259 n = pixcmapGetCount(cmap);
1260 na = numaCreate(n);
1261 for (i = 0; i < n; i++) {
1262 pixcmapGetColor(cmap, i, &rval, &gval, &bval);
1263 numaAddNumber(na, rval + gval + bval);
1264 }
1265 nasort = numaGetSortIndex(na, L_SORT_INCREASING);
1266 rankindex = (l_int32)(rankval * (n - 1) + 0.5);
1267 numaGetIValue(nasort, rankindex, pindex);
1268
1269 numaDestroy(&na);
1270 numaDestroy(&nasort);
1271 return 0;
1272}
1273
1274
1292l_ok
1294 l_int32 rval,
1295 l_int32 gval,
1296 l_int32 bval,
1297 l_int32 *pindex)
1298{
1299l_int32 i, n, delta, dist, mindist;
1300RGBA_QUAD *cta;
1301
1302 if (!pindex)
1303 return ERROR_INT("&index not defined", __func__, 1);
1304 *pindex = UNDEF;
1305 if (!cmap)
1306 return ERROR_INT("cmap not defined", __func__, 1);
1307
1308 if ((cta = (RGBA_QUAD *)cmap->array) == NULL)
1309 return ERROR_INT("cta not defined(!)", __func__, 1);
1310 n = pixcmapGetCount(cmap);
1311
1312 mindist = 3 * 255 * 255 + 1;
1313 for (i = 0; i < n; i++) {
1314 delta = cta[i].red - rval;
1315 dist = delta * delta;
1316 delta = cta[i].green - gval;
1317 dist += delta * delta;
1318 delta = cta[i].blue - bval;
1319 dist += delta * delta;
1320 if (dist < mindist) {
1321 *pindex = i;
1322 if (dist == 0)
1323 break;
1324 mindist = dist;
1325 }
1326 }
1327
1328 return 0;
1329}
1330
1331
1348l_ok
1350 l_int32 val,
1351 l_int32 *pindex)
1352{
1353l_int32 i, n, dist, mindist;
1354RGBA_QUAD *cta;
1355
1356 if (!pindex)
1357 return ERROR_INT("&index not defined", __func__, 1);
1358 *pindex = 0;
1359 if (!cmap)
1360 return ERROR_INT("cmap not defined", __func__, 1);
1361 if (val < 0 || val > 255)
1362 return ERROR_INT("val not in [0 ... 255]", __func__, 1);
1363
1364 if ((cta = (RGBA_QUAD *)cmap->array) == NULL)
1365 return ERROR_INT("cta not defined(!)", __func__, 1);
1366 n = pixcmapGetCount(cmap);
1367
1368 mindist = 256;
1369 for (i = 0; i < n; i++) {
1370 dist = cta[i].green - val;
1371 dist = L_ABS(dist);
1372 if (dist < mindist) {
1373 *pindex = i;
1374 if (dist == 0)
1375 break;
1376 mindist = dist;
1377 }
1378 }
1379
1380 return 0;
1381}
1382
1383
1399l_ok
1401 l_int32 index,
1402 l_int32 rval,
1403 l_int32 gval,
1404 l_int32 bval,
1405 l_int32 *pdist)
1406{
1407l_int32 n, delta, dist;
1408RGBA_QUAD *cta;
1409
1410 if (!pdist)
1411 return ERROR_INT("&dist not defined", __func__, 1);
1412 *pdist = UNDEF;
1413 if (!cmap)
1414 return ERROR_INT("cmap not defined", __func__, 1);
1415 n = pixcmapGetCount(cmap);
1416 if (index >= n)
1417 return ERROR_INT("invalid index", __func__, 1);
1418
1419 if ((cta = (RGBA_QUAD *)cmap->array) == NULL)
1420 return ERROR_INT("cta not defined(!)", __func__, 1);
1421
1422 delta = cta[index].red - rval;
1423 dist = delta * delta;
1424 delta = cta[index].green - gval;
1425 dist += delta * delta;
1426 delta = cta[index].blue - bval;
1427 dist += delta * delta;
1428 *pdist = dist;
1429
1430 return 0;
1431}
1432
1433
1453l_ok
1455 l_int32 select,
1456 l_int32 *pminval,
1457 l_int32 *pmaxval,
1458 l_int32 *pminindex,
1459 l_int32 *pmaxindex)
1460{
1461l_int32 i, n, imin, imax, minval, maxval, rval, gval, bval, aveval;
1462
1463 if (pminval) *pminval = UNDEF;
1464 if (pmaxval) *pmaxval = UNDEF;
1465 if (pminindex) *pminindex = UNDEF;
1466 if (pmaxindex) *pmaxindex = UNDEF;
1467 if (!pminval && !pmaxval && !pminindex && !pmaxindex)
1468 return ERROR_INT("no result requested", __func__, 1);
1469 if (!cmap)
1470 return ERROR_INT("cmap not defined", __func__, 1);
1471
1472 imin = UNDEF;
1473 imax = UNDEF;
1474 minval = 100000;
1475 maxval = -1;
1476 n = pixcmapGetCount(cmap);
1477 for (i = 0; i < n; i++) {
1478 pixcmapGetColor(cmap, i, &rval, &gval, &bval);
1479 if (select == L_SELECT_RED) {
1480 if (rval < minval) {
1481 minval = rval;
1482 imin = i;
1483 }
1484 if (rval > maxval) {
1485 maxval = rval;
1486 imax = i;
1487 }
1488 } else if (select == L_SELECT_GREEN) {
1489 if (gval < minval) {
1490 minval = gval;
1491 imin = i;
1492 }
1493 if (gval > maxval) {
1494 maxval = gval;
1495 imax = i;
1496 }
1497 } else if (select == L_SELECT_BLUE) {
1498 if (bval < minval) {
1499 minval = bval;
1500 imin = i;
1501 }
1502 if (bval > maxval) {
1503 maxval = bval;
1504 imax = i;
1505 }
1506 } else if (select == L_SELECT_AVERAGE) {
1507 aveval = (rval + gval + bval) / 3;
1508 if (aveval < minval) {
1509 minval = aveval;
1510 imin = i;
1511 }
1512 if (aveval > maxval) {
1513 maxval = aveval;
1514 imax = i;
1515 }
1516 } else {
1517 return ERROR_INT("invalid selection", __func__, 1);
1518 }
1519 }
1520
1521 if (pminval) *pminval = minval;
1522 if (pmaxval) *pmaxval = maxval;
1523 if (pminindex) *pminindex = imin;
1524 if (pmaxindex) *pmaxindex = imax;
1525 return 0;
1526}
1527
1528
1529/*-------------------------------------------------------------*
1530 * Colormap conversion *
1531 *-------------------------------------------------------------*/
1545PIXCMAP *
1547{
1548l_int32 i, rval, gval, bval;
1549l_int32 *curve;
1550l_float32 invgamma, x;
1551PIXCMAP *cmap;
1552
1553 if (gamma <= 0.0) gamma = 1.0;
1554
1555 /* Generate curve for transition part of color map */
1556 curve = (l_int32 *)LEPT_CALLOC(64, sizeof(l_int32));
1557 invgamma = 1. / gamma;
1558 for (i = 0; i < 64; i++) {
1559 x = (l_float32)i / 64.;
1560 curve[i] = (l_int32)(255. * powf(x, invgamma) + 0.5);
1561 }
1562
1563 cmap = pixcmapCreate(8);
1564 for (i = 0; i < 256; i++) {
1565 if (i < 32) {
1566 rval = 0;
1567 gval = 0;
1568 bval = curve[i + 32];
1569 } else if (i < 96) { /* 32 - 95 */
1570 rval = 0;
1571 gval = curve[i - 32];
1572 bval = 255;
1573 } else if (i < 160) { /* 96 - 159 */
1574 rval = curve[i - 96];
1575 gval = 255;
1576 bval = curve[159 - i];
1577 } else if (i < 224) { /* 160 - 223 */
1578 rval = 255;
1579 gval = curve[223 - i];
1580 bval = 0;
1581 } else { /* 224 - 255 */
1582 rval = curve[287 - i];
1583 gval = 0;
1584 bval = 0;
1585 }
1586 pixcmapAddColor(cmap, rval, gval, bval);
1587 }
1588
1589 LEPT_FREE(curve);
1590 return cmap;
1591}
1592
1593
1609PIXCMAP *
1610pixcmapGrayToColor(l_uint32 color)
1611{
1612l_int32 i, rval, gval, bval;
1613PIXCMAP *cmap;
1614
1615 extractRGBValues(color, &rval, &gval, &bval);
1616 cmap = pixcmapCreate(8);
1617 for (i = 0; i < 256; i++) {
1618 pixcmapAddColor(cmap, rval + (i * (255 - rval)) / 255,
1619 gval + (i * (255 - gval)) / 255,
1620 bval + (i * (255 - bval)) / 255);
1621 }
1622
1623 return cmap;
1624}
1625
1626
1641PIXCMAP *
1643 l_float32 rwt,
1644 l_float32 gwt,
1645 l_float32 bwt)
1646{
1647l_int32 i, n, rval, gval, bval, val;
1648l_float32 sum;
1649PIXCMAP *cmapd;
1650
1651 if (!cmaps)
1652 return (PIXCMAP *)ERROR_PTR("cmaps not defined", __func__, NULL);
1653 if (rwt < 0.0 || gwt < 0.0 || bwt < 0.0)
1654 return (PIXCMAP *)ERROR_PTR("weights not all >= 0.0", __func__, NULL);
1655
1656 /* Make sure the sum of weights is 1.0; otherwise, you can get
1657 * overflow in the gray value. */
1658 sum = rwt + gwt + bwt;
1659 if (sum == 0.0) {
1660 L_WARNING("all weights zero; setting equal to 1/3\n", __func__);
1661 rwt = gwt = bwt = 0.33333f;
1662 sum = 1.0;
1663 }
1664 if (L_ABS(sum - 1.0) > 0.0001) { /* maintain ratios with sum == 1.0 */
1665 L_WARNING("weights don't sum to 1; maintaining ratios\n", __func__);
1666 rwt = rwt / sum;
1667 gwt = gwt / sum;
1668 bwt = bwt / sum;
1669 }
1670
1671 if ((cmapd = pixcmapCopy(cmaps)) == NULL)
1672 return (PIXCMAP *)ERROR_PTR("cmapd not made", __func__, NULL);
1673 n = pixcmapGetCount(cmapd);
1674 for (i = 0; i < n; i++) {
1675 pixcmapGetColor(cmapd, i, &rval, &gval, &bval);
1676 val = (l_int32)(rwt * rval + gwt * gval + bwt * bval + 0.5);
1677 pixcmapResetColor(cmapd, i, val, val, val);
1678 }
1679
1680 return cmapd;
1681}
1682
1683
1696PIXCMAP *
1698{
1699l_int32 i, n, rval, gval, bval;
1700PIXCMAP *cmapd;
1701
1702 if (!cmaps)
1703 return (PIXCMAP *)ERROR_PTR("cmaps not defined", __func__, NULL);
1704 if (pixcmapGetDepth(cmaps) != 2)
1705 return (PIXCMAP *)ERROR_PTR("cmaps not for 2 bpp pix", __func__, NULL);
1706
1707 cmapd = pixcmapCreate(4);
1708 n = pixcmapGetCount(cmaps);
1709 for (i = 0; i < n; i++) {
1710 pixcmapGetColor(cmaps, i, &rval, &gval, &bval);
1711 pixcmapAddColor(cmapd, rval, gval, bval);
1712 }
1713 return cmapd;
1714}
1715
1716
1729PIXCMAP *
1731{
1732l_int32 i, n, depth, rval, gval, bval;
1733PIXCMAP *cmapd;
1734
1735 if (!cmaps)
1736 return (PIXCMAP *)ERROR_PTR("cmaps not defined", __func__, NULL);
1737 depth = pixcmapGetDepth(cmaps);
1738 if (depth == 8) return pixcmapCopy(cmaps);
1739 if (depth != 2 && depth != 4)
1740 return (PIXCMAP *)ERROR_PTR("cmaps not 2 or 4 bpp", __func__, NULL);
1741
1742 cmapd = pixcmapCreate(8);
1743 n = pixcmapGetCount(cmaps);
1744 for (i = 0; i < n; i++) {
1745 pixcmapGetColor(cmaps, i, &rval, &gval, &bval);
1746 pixcmapAddColor(cmapd, rval, gval, bval);
1747 }
1748 return cmapd;
1749}
1750
1751
1752/*-------------------------------------------------------------*
1753 * Colormap I/O *
1754 *-------------------------------------------------------------*/
1761PIXCMAP *
1762pixcmapRead(const char *filename)
1763{
1764FILE *fp;
1765PIXCMAP *cmap;
1766
1767 if (!filename)
1768 return (PIXCMAP *)ERROR_PTR("filename not defined", __func__, NULL);
1769
1770 if ((fp = fopenReadStream(filename)) == NULL)
1771 return (PIXCMAP *)ERROR_PTR_1("stream not opened",
1772 filename, __func__, NULL);
1773 cmap = pixcmapReadStream(fp);
1774 fclose(fp);
1775 if (!cmap)
1776 return (PIXCMAP *)ERROR_PTR_1("cmap not read",
1777 filename, __func__, NULL);
1778 return cmap;
1779}
1780
1781
1788PIXCMAP *
1790{
1791l_int32 rval, gval, bval, aval, ignore;
1792l_int32 i, index, ret, depth, ncolors;
1793PIXCMAP *cmap;
1794
1795 if (!fp)
1796 return (PIXCMAP *)ERROR_PTR("stream not defined", __func__, NULL);
1797
1798 ret = fscanf(fp, "\nPixcmap: depth = %d bpp; %d colors\n",
1799 &depth, &ncolors);
1800 if (ret != 2 ||
1801 (depth != 1 && depth != 2 && depth != 4 && depth != 8) ||
1802 (ncolors < 2 || ncolors > 256))
1803 return (PIXCMAP *)ERROR_PTR("invalid cmap size", __func__, NULL);
1804 ignore = fscanf(fp, "Color R-val G-val B-val Alpha\n");
1805 ignore = fscanf(fp, "----------------------------------------\n");
1806
1807 if ((cmap = pixcmapCreate(depth)) == NULL)
1808 return (PIXCMAP *)ERROR_PTR("cmap not made", __func__, NULL);
1809 for (i = 0; i < ncolors; i++) {
1810 if (fscanf(fp, "%3d %3d %3d %3d %3d\n",
1811 &index, &rval, &gval, &bval, &aval) != 5) {
1812 pixcmapDestroy(&cmap);
1813 return (PIXCMAP *)ERROR_PTR("invalid entry", __func__, NULL);
1814 }
1815 pixcmapAddRGBA(cmap, rval, gval, bval, aval);
1816 }
1817 return cmap;
1818}
1819
1820
1828PIXCMAP *
1829pixcmapReadMem(const l_uint8 *data,
1830 size_t size)
1831{
1832FILE *fp;
1833PIXCMAP *cmap;
1834
1835 if (!data)
1836 return (PIXCMAP *)ERROR_PTR("data not defined", __func__, NULL);
1837 if ((fp = fopenReadFromMemory(data, size)) == NULL)
1838 return (PIXCMAP *)ERROR_PTR("stream not opened", __func__, NULL);
1839
1840 cmap = pixcmapReadStream(fp);
1841 fclose(fp);
1842 if (!cmap) L_ERROR("cmap not read\n", __func__);
1843 return cmap;
1844}
1845
1846
1854l_ok
1855pixcmapWrite(const char *filename,
1856 const PIXCMAP *cmap)
1857{
1858l_int32 ret;
1859FILE *fp;
1860
1861 if (!filename)
1862 return ERROR_INT("filename not defined", __func__, 1);
1863 if (!cmap)
1864 return ERROR_INT("cmap not defined", __func__, 1);
1865
1866 if ((fp = fopenWriteStream(filename, "w")) == NULL)
1867 return ERROR_INT_1("stream not opened", filename, __func__, 1);
1868 ret = pixcmapWriteStream(fp, cmap);
1869 fclose(fp);
1870 if (ret)
1871 return ERROR_INT_1("cmap not written to stream", filename, __func__, 1);
1872 return 0;
1873}
1874
1875
1876
1884l_ok
1886 const PIXCMAP *cmap)
1887{
1888l_int32 *rmap, *gmap, *bmap, *amap;
1889l_int32 i;
1890
1891 if (!fp)
1892 return ERROR_INT("stream not defined", __func__, 1);
1893 if (!cmap)
1894 return ERROR_INT("cmap not defined", __func__, 1);
1895
1896 if (pixcmapToArrays(cmap, &rmap, &gmap, &bmap, &amap))
1897 return ERROR_INT("colormap arrays not made", __func__, 1);
1898
1899 fprintf(fp, "\nPixcmap: depth = %d bpp; %d colors\n", cmap->depth, cmap->n);
1900 fprintf(fp, "Color R-val G-val B-val Alpha\n");
1901 fprintf(fp, "----------------------------------------\n");
1902 for (i = 0; i < cmap->n; i++)
1903 fprintf(fp, "%3d %3d %3d %3d %3d\n",
1904 i, rmap[i], gmap[i], bmap[i], amap[i]);
1905 fprintf(fp, "\n");
1906
1907 LEPT_FREE(rmap);
1908 LEPT_FREE(gmap);
1909 LEPT_FREE(bmap);
1910 LEPT_FREE(amap);
1911 return 0;
1912}
1913
1914
1928l_ok
1929pixcmapWriteMem(l_uint8 **pdata,
1930 size_t *psize,
1931 const PIXCMAP *cmap)
1932{
1933l_int32 ret;
1934FILE *fp;
1935
1936 if (pdata) *pdata = NULL;
1937 if (psize) *psize = 0;
1938 if (!pdata)
1939 return ERROR_INT("&data not defined", __func__, 1);
1940 if (!psize)
1941 return ERROR_INT("&size not defined", __func__, 1);
1942 if (!cmap)
1943 return ERROR_INT("cmap not defined", __func__, 1);
1944
1945#if HAVE_FMEMOPEN
1946 if ((fp = open_memstream((char **)pdata, psize)) == NULL)
1947 return ERROR_INT("stream not opened", __func__, 1);
1948 ret = pixcmapWriteStream(fp, cmap);
1949 fputc('\0', fp);
1950 fclose(fp);
1951 if (*psize > 0) *psize = *psize - 1;
1952#else
1953 L_INFO("no fmemopen API --> work-around: write to temp file\n", __func__);
1954 #ifdef _WIN32
1955 if ((fp = fopenWriteWinTempfile()) == NULL)
1956 return ERROR_INT("tmpfile stream not opened", __func__, 1);
1957 #else
1958 if ((fp = tmpfile()) == NULL)
1959 return ERROR_INT("tmpfile stream not opened", __func__, 1);
1960 #endif /* _WIN32 */
1961 ret = pixcmapWriteStream(fp, cmap);
1962 rewind(fp);
1963 *pdata = l_binaryReadStream(fp, psize);
1964 fclose(fp);
1965#endif /* HAVE_FMEMOPEN */
1966 return ret;
1967}
1968
1969
1970/*----------------------------------------------------------------------*
1971 * Extract colormap arrays and serialization *
1972 *----------------------------------------------------------------------*/
1983l_ok
1985 l_int32 **prmap,
1986 l_int32 **pgmap,
1987 l_int32 **pbmap,
1988 l_int32 **pamap)
1989{
1990l_int32 *rmap, *gmap, *bmap, *amap = NULL;
1991l_int32 i, ncolors;
1992RGBA_QUAD *cta;
1993
1994 if (!prmap || !pgmap || !pbmap)
1995 return ERROR_INT("&rmap, &gmap, &bmap not all defined", __func__, 1);
1996 *prmap = *pgmap = *pbmap = NULL;
1997 if (pamap) *pamap = NULL;
1998 if (!cmap)
1999 return ERROR_INT("cmap not defined", __func__, 1);
2000
2001 ncolors = pixcmapGetCount(cmap);
2002 rmap = (l_int32 *)LEPT_CALLOC(ncolors, sizeof(l_int32));
2003 gmap = (l_int32 *)LEPT_CALLOC(ncolors, sizeof(l_int32));
2004 bmap = (l_int32 *)LEPT_CALLOC(ncolors, sizeof(l_int32));
2005 *prmap = rmap;
2006 *pgmap = gmap;
2007 *pbmap = bmap;
2008 if (pamap) {
2009 amap = (l_int32 *)LEPT_CALLOC(ncolors, sizeof(l_int32));
2010 *pamap = amap;
2011 }
2012
2013 cta = (RGBA_QUAD *)cmap->array;
2014 for (i = 0; i < ncolors; i++) {
2015 rmap[i] = cta[i].red;
2016 gmap[i] = cta[i].green;
2017 bmap[i] = cta[i].blue;
2018 if (pamap)
2019 amap[i] = cta[i].alpha;
2020 }
2021
2022 return 0;
2023}
2024
2025
2034l_ok
2036 l_uint32 **ptab,
2037 l_int32 *pncolors)
2038{
2039l_int32 i, ncolors, rval, gval, bval, aval;
2040l_uint32 *tab;
2041
2042 if (!ptab)
2043 return ERROR_INT("&tab not defined", __func__, 1);
2044 *ptab = NULL;
2045 if (!cmap)
2046 return ERROR_INT("cmap not defined", __func__, 1);
2047
2048 ncolors = pixcmapGetCount(cmap);
2049 if (pncolors) *pncolors = ncolors;
2050 tab = (l_uint32 *)LEPT_CALLOC(ncolors, sizeof(l_uint32));
2051 *ptab = tab;
2052
2053 for (i = 0; i < ncolors; i++) {
2054 pixcmapGetRGBA(cmap, i, &rval, &gval, &bval, &aval);
2055 composeRGBAPixel(rval, gval, bval, aval, &tab[i]);
2056 }
2057 return 0;
2058}
2059
2060
2075l_ok
2077 l_int32 cpc,
2078 l_int32 *pncolors,
2079 l_uint8 **pdata)
2080{
2081l_int32 i, ncolors, rval, gval, bval, aval;
2082l_uint8 *data;
2083
2084 if (!pdata)
2085 return ERROR_INT("&data not defined", __func__, 1);
2086 *pdata = NULL;
2087 if (!pncolors)
2088 return ERROR_INT("&ncolors not defined", __func__, 1);
2089 *pncolors = 0;
2090 if (!cmap)
2091 return ERROR_INT("cmap not defined", __func__, 1);
2092 if (cpc != 3 && cpc != 4)
2093 return ERROR_INT("cpc not 3 or 4", __func__, 1);
2094
2095 ncolors = pixcmapGetCount(cmap);
2096 *pncolors = ncolors;
2097 data = (l_uint8 *)LEPT_CALLOC((size_t)cpc * ncolors, sizeof(l_uint8));
2098 *pdata = data;
2099
2100 for (i = 0; i < ncolors; i++) {
2101 pixcmapGetRGBA(cmap, i, &rval, &gval, &bval, &aval);
2102 data[cpc * i] = rval;
2103 data[cpc * i + 1] = gval;
2104 data[cpc * i + 2] = bval;
2105 if (cpc == 4)
2106 data[cpc * i + 3] = aval;
2107 }
2108 return 0;
2109}
2110
2111
2120PIXCMAP *
2122 l_int32 cpc,
2123 l_int32 ncolors)
2124{
2125l_int32 i, d, rval, gval, bval, aval;
2126PIXCMAP *cmap;
2127
2128 if (!data)
2129 return (PIXCMAP *)ERROR_PTR("data not defined", __func__, NULL);
2130 if (cpc != 3 && cpc != 4)
2131 return (PIXCMAP *)ERROR_PTR("cpc not 3 or 4", __func__, NULL);
2132 if (ncolors <= 0)
2133 return (PIXCMAP *)ERROR_PTR("no entries", __func__, NULL);
2134 if (ncolors > 256)
2135 return (PIXCMAP *)ERROR_PTR("ncolors > 256", __func__, NULL);
2136
2137 if (ncolors > 16)
2138 d = 8;
2139 else if (ncolors > 4)
2140 d = 4;
2141 else if (ncolors > 2)
2142 d = 2;
2143 else
2144 d = 1;
2145 cmap = pixcmapCreate(d);
2146 for (i = 0; i < ncolors; i++) {
2147 rval = data[cpc * i];
2148 gval = data[cpc * i + 1];
2149 bval = data[cpc * i + 2];
2150 if (cpc == 4)
2151 aval = data[cpc * i + 3];
2152 else
2153 aval = 255; /* opaque */
2154 pixcmapAddRGBA(cmap, rval, gval, bval, aval);
2155 }
2156
2157 return cmap;
2158}
2159
2160
2179char *
2181 l_int32 ncolors)
2182{
2183l_int32 i, j, hexbytes;
2184char *hexdata = NULL;
2185char buf[4];
2186
2187 if (!data)
2188 return (char *)ERROR_PTR("data not defined", __func__, NULL);
2189 if (ncolors < 1)
2190 return (char *)ERROR_PTR("no colors", __func__, NULL);
2191
2192 hexbytes = 2 + (2 * 3 + 1) * ncolors + 2;
2193 hexdata = (char *)LEPT_CALLOC(hexbytes, sizeof(char));
2194 hexdata[0] = '<';
2195 hexdata[1] = ' ';
2196
2197 for (i = 0; i < ncolors; i++) {
2198 j = 2 + (2 * 3 + 1) * i;
2199 snprintf(buf, sizeof(buf), "%02x", data[3 * i]);
2200 hexdata[j] = buf[0];
2201 hexdata[j + 1] = buf[1];
2202 snprintf(buf, sizeof(buf), "%02x", data[3 * i + 1]);
2203 hexdata[j + 2] = buf[0];
2204 hexdata[j + 3] = buf[1];
2205 snprintf(buf, sizeof(buf), "%02x", data[3 * i + 2]);
2206 hexdata[j + 4] = buf[0];
2207 hexdata[j + 5] = buf[1];
2208 hexdata[j + 6] = ' ';
2209 }
2210 hexdata[j + 7] = '>';
2211 hexdata[j + 8] = '\0';
2212 return hexdata;
2213}
2214
2215
2216/*-------------------------------------------------------------*
2217 * Colormap transforms *
2218 *-------------------------------------------------------------*/
2235l_ok
2237 l_float32 gamma,
2238 l_int32 minval,
2239 l_int32 maxval)
2240{
2241l_int32 rval, gval, bval, trval, tgval, tbval, i, ncolors;
2242NUMA *nag;
2243
2244 if (!cmap)
2245 return ERROR_INT("cmap not defined", __func__, 1);
2246 if (gamma <= 0.0) {
2247 L_WARNING("gamma must be > 0.0; setting to 1.0\n", __func__);
2248 gamma = 1.0;
2249 }
2250 if (minval >= maxval)
2251 return ERROR_INT("minval not < maxval", __func__, 1);
2252
2253 if (gamma == 1.0 && minval == 0 && maxval == 255) /* no-op */
2254 return 0;
2255
2256 if ((nag = numaGammaTRC(gamma, minval, maxval)) == NULL)
2257 return ERROR_INT("nag not made", __func__, 1);
2258
2259 ncolors = pixcmapGetCount(cmap);
2260 for (i = 0; i < ncolors; i++) {
2261 pixcmapGetColor(cmap, i, &rval, &gval, &bval);
2262 numaGetIValue(nag, rval, &trval);
2263 numaGetIValue(nag, gval, &tgval);
2264 numaGetIValue(nag, bval, &tbval);
2265 pixcmapResetColor(cmap, i, trval, tgval, tbval);
2266 }
2267
2268 numaDestroy(&nag);
2269 return 0;
2270}
2271
2272
2288l_ok
2290 l_float32 factor)
2291{
2292l_int32 i, ncolors, rval, gval, bval, trval, tgval, tbval;
2293NUMA *nac;
2294
2295 if (!cmap)
2296 return ERROR_INT("cmap not defined", __func__, 1);
2297 if (factor < 0.0) {
2298 L_WARNING("factor must be >= 0.0; setting to 0.0\n", __func__);
2299 factor = 0.0;
2300 }
2301
2302 if ((nac = numaContrastTRC(factor)) == NULL)
2303 return ERROR_INT("nac not made", __func__, 1);
2304
2305 ncolors = pixcmapGetCount(cmap);
2306 for (i = 0; i < ncolors; i++) {
2307 pixcmapGetColor(cmap, i, &rval, &gval, &bval);
2308 numaGetIValue(nac, rval, &trval);
2309 numaGetIValue(nac, gval, &tgval);
2310 numaGetIValue(nac, bval, &tbval);
2311 pixcmapResetColor(cmap, i, trval, tgval, tbval);
2312 }
2313
2314 numaDestroy(&nac);
2315 return 0;
2316}
2317
2318
2338l_ok
2340 l_float32 fraction)
2341{
2342l_int32 i, ncolors, rval, gval, bval;
2343
2344 if (!cmap)
2345 return ERROR_INT("cmap not defined", __func__, 1);
2346 if (fraction < -1.0 || fraction > 1.0)
2347 return ERROR_INT("fraction not in [-1.0, 1.0]", __func__, 1);
2348
2349 ncolors = pixcmapGetCount(cmap);
2350 for (i = 0; i < ncolors; i++) {
2351 pixcmapGetColor(cmap, i, &rval, &gval, &bval);
2352 if (fraction < 0.0)
2353 pixcmapResetColor(cmap, i,
2354 (l_int32)((1.0 + fraction) * rval),
2355 (l_int32)((1.0 + fraction) * gval),
2356 (l_int32)((1.0 + fraction) * bval));
2357 else
2358 pixcmapResetColor(cmap, i,
2359 rval + (l_int32)(fraction * (255 - rval)),
2360 gval + (l_int32)(fraction * (255 - gval)),
2361 bval + (l_int32)(fraction * (255 - bval)));
2362 }
2363
2364 return 0;
2365}
2366
2367
2386l_ok
2388 l_uint32 srcval,
2389 l_uint32 dstval)
2390{
2391l_int32 i, ncolors, rval, gval, bval;
2392l_uint32 newval;
2393
2394 if (!cmap)
2395 return ERROR_INT("cmap not defined", __func__, 1);
2396
2397 ncolors = pixcmapGetCount(cmap);
2398 for (i = 0; i < ncolors; i++) {
2399 pixcmapGetColor(cmap, i, &rval, &gval, &bval);
2400 pixelShiftByComponent(rval, gval, bval, srcval, dstval, &newval);
2401 extractRGBValues(newval, &rval, &gval, &bval);
2402 pixcmapResetColor(cmap, i, rval, gval, bval);
2403 }
2404
2405 return 0;
2406}
l_ok pixcmapSetAlpha(PIXCMAP *cmap, l_int32 index, l_int32 aval)
pixcmapSetAlpha()
Definition colormap.c:963
void pixcmapDestroy(PIXCMAP **pcmap)
pixcmapDestroy()
Definition colormap.c:272
l_ok pixcmapContrastTRC(PIXCMAP *cmap, l_float32 factor)
pixcmapContrastTRC()
Definition colormap.c:2289
l_ok pixcmapHasColor(PIXCMAP *cmap, l_int32 *pcolor)
pixcmapHasColor()
Definition colormap.c:1027
l_int32 pixcmapGetCount(const PIXCMAP *cmap)
pixcmapGetCount()
Definition colormap.c:684
PIXCMAP * pixcmapCreateRandom(l_int32 depth, l_int32 hasblack, l_int32 haswhite)
pixcmapCreateRandom()
Definition colormap.c:171
l_ok pixcmapGetDistanceToColor(PIXCMAP *cmap, l_int32 index, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pdist)
pixcmapGetDistanceToColor()
Definition colormap.c:1400
l_ok pixcmapSetBlackAndWhite(PIXCMAP *cmap, l_int32 setblack, l_int32 setwhite)
pixcmapSetBlackAndWhite()
Definition colormap.c:656
l_ok pixcmapIsValid(const PIXCMAP *cmap, PIX *pix, l_int32 *pvalid)
pixcmapIsValid()
Definition colormap.c:308
PIXCMAP * pixcmapCopy(const PIXCMAP *cmaps)
pixcmapCopy()
Definition colormap.c:243
l_ok pixcmapWriteStream(FILE *fp, const PIXCMAP *cmap)
pixcmapWriteStream()
Definition colormap.c:1885
l_ok pixcmapAddNewColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pindex)
pixcmapAddNewColor()
Definition colormap.c:482
l_ok pixcmapGetNearestIndex(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pindex)
pixcmapGetNearestIndex()
Definition colormap.c:1293
PIXCMAP * pixcmapGrayToColor(l_uint32 color)
pixcmapGrayToColor()
Definition colormap.c:1610
l_ok pixcmapGetColor32(PIXCMAP *cmap, l_int32 index, l_uint32 *pval32)
pixcmapGetColor32()
Definition colormap.c:828
l_ok pixcmapSerializeToMemory(PIXCMAP *cmap, l_int32 cpc, l_int32 *pncolors, l_uint8 **pdata)
pixcmapSerializeToMemory()
Definition colormap.c:2076
l_ok pixcmapWrite(const char *filename, const PIXCMAP *cmap)
pixcmapWrite()
Definition colormap.c:1855
PIXCMAP * pixcmapCreate(l_int32 depth)
pixcmapCreate()
Definition colormap.c:126
l_ok pixcmapWriteMem(l_uint8 **pdata, size_t *psize, const PIXCMAP *cmap)
pixcmapWriteMem()
Definition colormap.c:1929
l_ok pixcmapAddRGBA(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 aval)
pixcmapAddRGBA()
Definition colormap.c:440
PIXCMAP * pixcmapDeserializeFromMemory(l_uint8 *data, l_int32 cpc, l_int32 ncolors)
pixcmapDeserializeFromMemory()
Definition colormap.c:2121
l_ok pixcmapAddBlackOrWhite(PIXCMAP *cmap, l_int32 color, l_int32 *pindex)
pixcmapAddBlackOrWhite()
Definition colormap.c:619
PIXCMAP * pixcmapCreateLinear(l_int32 d, l_int32 nlevels)
pixcmapCreateLinear()
Definition colormap.c:215
l_ok pixcmapAddNearestColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pindex)
pixcmapAddNearestColor()
Definition colormap.c:529
PIXCMAP * pixcmapColorToGray(PIXCMAP *cmaps, l_float32 rwt, l_float32 gwt, l_float32 bwt)
pixcmapColorToGray()
Definition colormap.c:1642
l_ok pixcmapResetColor(PIXCMAP *cmap, l_int32 index, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapResetColor()
Definition colormap.c:924
l_ok pixcmapGammaTRC(PIXCMAP *cmap, l_float32 gamma, l_int32 minval, l_int32 maxval)
pixcmapGammaTRC()
Definition colormap.c:2236
PIXCMAP * pixcmapConvertTo4(PIXCMAP *cmaps)
pixcmapConvertTo4()
Definition colormap.c:1697
l_int32 pixcmapGetIndex(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pindex)
pixcmapGetIndex()
Definition colormap.c:990
PIXCMAP * pixcmapReadStream(FILE *fp)
pixcmapReadStream()
Definition colormap.c:1789
l_ok pixcmapCountGrayColors(PIXCMAP *cmap, l_int32 *pngray)
pixcmapCountGrayColors()
Definition colormap.c:1205
l_int32 pixcmapGetDepth(PIXCMAP *cmap)
pixcmapGetDepth()
Definition colormap.c:714
l_ok pixcmapNonOpaqueColorsInfo(PIXCMAP *cmap, l_int32 *pntrans, l_int32 *pmax_trans, l_int32 *pmin_opaque)
pixcmapNonOpaqueColorsInfo()
Definition colormap.c:1121
l_ok pixcmapUsableColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pusable)
pixcmapUsableColor()
Definition colormap.c:574
l_ok pixcmapShiftIntensity(PIXCMAP *cmap, l_float32 fraction)
pixcmapShiftIntensity()
Definition colormap.c:2339
l_ok pixcmapGetColor(PIXCMAP *cmap, l_int32 index, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
pixcmapGetColor()
Definition colormap.c:790
l_ok pixcmapIsOpaque(PIXCMAP *cmap, l_int32 *popaque)
pixcmapIsOpaque()
Definition colormap.c:1064
l_ok pixcmapGetMinDepth(PIXCMAP *cmap, l_int32 *pmindepth)
pixcmapGetMinDepth()
Definition colormap.c:735
PIXCMAP * pixcmapGrayToFalseColor(l_float32 gamma)
pixcmapGrayToFalseColor()
Definition colormap.c:1546
l_int32 pixcmapGetFreeCount(PIXCMAP *cmap)
pixcmapGetFreeCount()
Definition colormap.c:699
l_ok pixcmapGetRangeValues(PIXCMAP *cmap, l_int32 select, l_int32 *pminval, l_int32 *pmaxval, l_int32 *pminindex, l_int32 *pmaxindex)
pixcmapGetRangeValues()
Definition colormap.c:1454
l_ok pixcmapClear(PIXCMAP *cmap)
pixcmapClear()
Definition colormap.c:769
char * pixcmapConvertToHex(l_uint8 *data, l_int32 ncolors)
pixcmapConvertToHex()
Definition colormap.c:2180
l_ok pixcmapGetRankIntensity(PIXCMAP *cmap, l_float32 rankval, l_int32 *pindex)
pixcmapGetRankIntensity()
Definition colormap.c:1244
PIXCMAP * pixcmapReadMem(const l_uint8 *data, size_t size)
pixcmapReadMem()
Definition colormap.c:1829
l_ok pixcmapGetRGBA(PIXCMAP *cmap, l_int32 index, l_int32 *prval, l_int32 *pgval, l_int32 *pbval, l_int32 *paval)
pixcmapGetRGBA()
Definition colormap.c:854
PIXCMAP * pixcmapConvertTo8(PIXCMAP *cmaps)
pixcmapConvertTo8()
Definition colormap.c:1730
l_ok pixcmapToArrays(const PIXCMAP *cmap, l_int32 **prmap, l_int32 **pgmap, l_int32 **pbmap, l_int32 **pamap)
pixcmapToArrays()
Definition colormap.c:1984
l_ok pixcmapShiftByComponent(PIXCMAP *cmap, l_uint32 srcval, l_uint32 dstval)
pixcmapShiftByComponent()
Definition colormap.c:2387
l_ok pixcmapIsBlackAndWhite(PIXCMAP *cmap, l_int32 *pblackwhite)
pixcmapIsBlackAndWhite()
Definition colormap.c:1166
PIXCMAP * pixcmapRead(const char *filename)
pixcmapRead()
Definition colormap.c:1762
l_ok pixcmapAddColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapAddColor()
Definition colormap.c:404
l_ok pixcmapGetNearestGrayIndex(PIXCMAP *cmap, l_int32 val, l_int32 *pindex)
pixcmapGetNearestGrayIndex()
Definition colormap.c:1349
l_ok pixcmapToRGBTable(PIXCMAP *cmap, l_uint32 **ptab, l_int32 *pncolors)
pixcmapToRGBTable()
Definition colormap.c:2035
l_ok pixcmapGetRGBA32(PIXCMAP *cmap, l_int32 index, l_uint32 *pval32)
pixcmapGetRGBA32()
Definition colormap.c:890
@ L_SELECT_GREEN
Definition pix.h:616
@ L_SELECT_BLUE
Definition pix.h:617
@ L_SELECT_AVERAGE
Definition pix.h:620
@ L_SELECT_RED
Definition pix.h:615
@ L_SORT_INCREASING
Definition pix.h:522
struct RGBA_Quad RGBA_QUAD
Definition pix.h:237
l_int32 depth
l_int32 nalloc
l_uint8 alpha
l_uint8 green
l_uint8 blue
l_uint8 red