Leptonica 1.84.1
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 image pixel values do not exceed the
373 * max indexing into the colormap array. */
374 if (pix) {
375 pixGetMaxColorIndex(pix, &maxindex);
376 if (maxindex >= cmap->n) {
377 L_ERROR("(max index = %d) >= (num colors = %d)\n", __func__,
378 maxindex, cmap->n);
379 return 1;
380 }
381 }
382
383 *pvalid = 1;
384 return 0;
385}
386
387
402l_ok
404 l_int32 rval,
405 l_int32 gval,
406 l_int32 bval)
407{
408RGBA_QUAD *cta;
409
410 if (!cmap)
411 return ERROR_INT("cmap not defined", __func__, 1);
412 if (cmap->n >= cmap->nalloc)
413 return ERROR_INT("no free color entries", __func__, 1);
414
415 cta = (RGBA_QUAD *)cmap->array;
416 cta[cmap->n].red = rval;
417 cta[cmap->n].green = gval;
418 cta[cmap->n].blue = bval;
419 cta[cmap->n].alpha = 255;
420 cmap->n++;
421 return 0;
422}
423
424
438l_ok
440 l_int32 rval,
441 l_int32 gval,
442 l_int32 bval,
443 l_int32 aval)
444{
445RGBA_QUAD *cta;
446
447 if (!cmap)
448 return ERROR_INT("cmap not defined", __func__, 1);
449 if (cmap->n >= cmap->nalloc)
450 return ERROR_INT("no free color entries", __func__, 1);
451
452 cta = (RGBA_QUAD *)cmap->array;
453 cta[cmap->n].red = rval;
454 cta[cmap->n].green = gval;
455 cta[cmap->n].blue = bval;
456 cta[cmap->n].alpha = aval;
457 cmap->n++;
458 return 0;
459}
460
461
480l_ok
482 l_int32 rval,
483 l_int32 gval,
484 l_int32 bval,
485 l_int32 *pindex)
486{
487 if (!pindex)
488 return ERROR_INT("&index not defined", __func__, 1);
489 *pindex = 0;
490 if (!cmap)
491 return ERROR_INT("cmap not defined", __func__, 1);
492
493 /* Check if the color is already present. */
494 if (!pixcmapGetIndex(cmap, rval, gval, bval, pindex)) /* found */
495 return 0;
496
497 /* We need to add the color. Is there room? */
498 if (cmap->n >= cmap->nalloc) {
499 L_WARNING("no free color entries\n", __func__);
500 return 2;
501 }
502
503 /* There's room. Add it. */
504 pixcmapAddColor(cmap, rval, gval, bval);
505 *pindex = pixcmapGetCount(cmap) - 1;
506 return 0;
507}
508
509
527l_ok
529 l_int32 rval,
530 l_int32 gval,
531 l_int32 bval,
532 l_int32 *pindex)
533{
534 if (!pindex)
535 return ERROR_INT("&index not defined", __func__, 1);
536 *pindex = 0;
537 if (!cmap)
538 return ERROR_INT("cmap not defined", __func__, 1);
539
540 /* Check if the color is already present. */
541 if (!pixcmapGetIndex(cmap, rval, gval, bval, pindex)) /* found */
542 return 0;
543
544 /* We need to add the color. Is there room? */
545 if (cmap->n < cmap->nalloc) {
546 pixcmapAddColor(cmap, rval, gval, bval);
547 *pindex = pixcmapGetCount(cmap) - 1;
548 return 0;
549 }
550
551 /* There's no room. Return the index of the nearest color */
552 pixcmapGetNearestIndex(cmap, rval, gval, bval, pindex);
553 return 0;
554}
555
556
572l_ok
574 l_int32 rval,
575 l_int32 gval,
576 l_int32 bval,
577 l_int32 *pusable)
578{
579l_int32 index;
580
581 if (!pusable)
582 return ERROR_INT("&usable not defined", __func__, 1);
583 *pusable = 0;
584 if (!cmap)
585 return ERROR_INT("cmap not defined", __func__, 1);
586
587 /* Is there room to add it? */
588 if (cmap->n < cmap->nalloc) {
589 *pusable = 1;
590 return 0;
591 }
592
593 /* No room; check if the color is already present. */
594 if (!pixcmapGetIndex(cmap, rval, gval, bval, &index)) /* found */
595 *pusable = 1;
596 return 0;
597}
598
599
617l_ok
619 l_int32 color,
620 l_int32 *pindex)
621{
622l_int32 index;
623
624 if (pindex) *pindex = 0;
625 if (!cmap)
626 return ERROR_INT("cmap not defined", __func__, 1);
627
628 if (color == 0) { /* black */
629 if (pixcmapGetFreeCount(cmap) > 0)
630 pixcmapAddNewColor(cmap, 0, 0, 0, &index);
631 else
632 pixcmapGetRankIntensity(cmap, 0.0, &index);
633 } else { /* white */
634 if (pixcmapGetFreeCount(cmap) > 0)
635 pixcmapAddNewColor(cmap, 255, 255, 255, &index);
636 else
637 pixcmapGetRankIntensity(cmap, 1.0, &index);
638 }
639
640 if (pindex)
641 *pindex = index;
642 return 0;
643}
644
645
654l_ok
656 l_int32 setblack,
657 l_int32 setwhite)
658{
659l_int32 index;
660
661 if (!cmap)
662 return ERROR_INT("cmap not defined", __func__, 1);
663
664 if (setblack) {
665 pixcmapGetRankIntensity(cmap, 0.0, &index);
666 pixcmapResetColor(cmap, index, 0, 0, 0);
667 }
668 if (setwhite) {
669 pixcmapGetRankIntensity(cmap, 1.0, &index);
670 pixcmapResetColor(cmap, index, 255, 255, 255);
671 }
672 return 0;
673}
674
675
682l_int32
684{
685 if (!cmap)
686 return ERROR_INT("cmap not defined", __func__, 0);
687 return cmap->n;
688}
689
690
697l_int32
699{
700 if (!cmap)
701 return ERROR_INT("cmap not defined", __func__, 0);
702 return (cmap->nalloc - cmap->n);
703}
704
705
712l_int32
714{
715 if (!cmap)
716 return ERROR_INT("cmap not defined", __func__, 0);
717 return cmap->depth;
718}
719
720
733l_ok
735 l_int32 *pmindepth)
736{
737l_int32 ncolors;
738
739 if (!pmindepth)
740 return ERROR_INT("&mindepth not defined", __func__, 1);
741 *pmindepth = 0;
742 if (!cmap)
743 return ERROR_INT("cmap not defined", __func__, 1);
744
745 ncolors = pixcmapGetCount(cmap);
746 if (ncolors <= 4)
747 *pmindepth = 2;
748 else if (ncolors <= 16)
749 *pmindepth = 4;
750 else /* ncolors > 16 */
751 *pmindepth = 8;
752 return 0;
753}
754
755
767l_ok
769{
770 if (!cmap)
771 return ERROR_INT("cmap not defined", __func__, 1);
772 cmap->n = 0;
773 return 0;
774}
775
776
777/*-------------------------------------------------------------*
778 * Colormap random access *
779 *-------------------------------------------------------------*/
788l_ok
790 l_int32 index,
791 l_int32 *prval,
792 l_int32 *pgval,
793 l_int32 *pbval)
794{
795RGBA_QUAD *cta;
796
797 if (!prval || !pgval || !pbval)
798 return ERROR_INT("&rval, &gval, &bval not all defined", __func__, 1);
799 *prval = *pgval = *pbval = 0;
800 if (!cmap)
801 return ERROR_INT("cmap not defined", __func__, 1);
802 if (index < 0 || index >= cmap->n)
803 return ERROR_INT("index out of bounds", __func__, 1);
804
805 cta = (RGBA_QUAD *)cmap->array;
806 *prval = cta[index].red;
807 *pgval = cta[index].green;
808 *pbval = cta[index].blue;
809 return 0;
810}
811
812
826l_ok
828 l_int32 index,
829 l_uint32 *pval32)
830{
831l_int32 rval, gval, bval;
832
833 if (!pval32)
834 return ERROR_INT("&val32 not defined", __func__, 1);
835 *pval32 = 0;
836
837 if (pixcmapGetColor(cmap, index, &rval, &gval, &bval) != 0)
838 return ERROR_INT("rgb values not found", __func__, 1);
839 composeRGBAPixel(rval, gval, bval, 255, pval32);
840 return 0;
841}
842
843
852l_ok
854 l_int32 index,
855 l_int32 *prval,
856 l_int32 *pgval,
857 l_int32 *pbval,
858 l_int32 *paval)
859{
860RGBA_QUAD *cta;
861
862 if (!prval || !pgval || !pbval || !paval)
863 return ERROR_INT("&rval, &gval, &bval, &aval not all defined",
864 __func__, 1);
865 *prval = *pgval = *pbval = *paval = 0;
866 if (!cmap)
867 return ERROR_INT("cmap not defined", __func__, 1);
868 if (index < 0 || index >= cmap->n)
869 return ERROR_INT("index out of bounds", __func__, 1);
870
871 cta = (RGBA_QUAD *)cmap->array;
872 *prval = cta[index].red;
873 *pgval = cta[index].green;
874 *pbval = cta[index].blue;
875 *paval = cta[index].alpha;
876 return 0;
877}
878
879
888l_ok
890 l_int32 index,
891 l_uint32 *pval32)
892{
893l_int32 rval, gval, bval, aval;
894
895 if (!pval32)
896 return ERROR_INT("&val32 not defined", __func__, 1);
897 *pval32 = 0;
898
899 if (pixcmapGetRGBA(cmap, index, &rval, &gval, &bval, &aval) != 0)
900 return ERROR_INT("rgba values not found", __func__, 1);
901 composeRGBAPixel(rval, gval, bval, aval, pval32);
902 return 0;
903}
904
905
922l_ok
924 l_int32 index,
925 l_int32 rval,
926 l_int32 gval,
927 l_int32 bval)
928{
929RGBA_QUAD *cta;
930
931 if (!cmap)
932 return ERROR_INT("cmap not defined", __func__, 1);
933 if (index < 0 || index >= cmap->n)
934 return ERROR_INT("index out of bounds", __func__, 1);
935
936 cta = (RGBA_QUAD *)cmap->array;
937 cta[index].red = rval;
938 cta[index].green = gval;
939 cta[index].blue = bval;
940 cta[index].alpha = 255;
941 return 0;
942}
943
944
961l_ok
963 l_int32 index,
964 l_int32 aval)
965{
966RGBA_QUAD *cta;
967
968 if (!cmap)
969 return ERROR_INT("cmap not defined", __func__, 1);
970 if (index < 0 || index >= cmap->n)
971 return ERROR_INT("index out of bounds", __func__, 1);
972
973 cta = (RGBA_QUAD *)cmap->array;
974 cta[index].alpha = aval;
975 return 0;
976}
977
978
988l_int32
990 l_int32 rval,
991 l_int32 gval,
992 l_int32 bval,
993 l_int32 *pindex)
994{
995l_int32 n, i;
996RGBA_QUAD *cta;
997
998 if (!pindex)
999 return ERROR_INT("&index not defined", __func__, 1);
1000 *pindex = 0;
1001 if (!cmap)
1002 return ERROR_INT("cmap not defined", __func__, 1);
1003 n = pixcmapGetCount(cmap);
1004
1005 cta = (RGBA_QUAD *)cmap->array;
1006 for (i = 0; i < n; i++) {
1007 if (rval == cta[i].red &&
1008 gval == cta[i].green &&
1009 bval == cta[i].blue) {
1010 *pindex = i;
1011 return 0;
1012 }
1013 }
1014 return 1;
1015}
1016
1017
1025l_ok
1027 l_int32 *pcolor)
1028{
1029l_int32 n, i;
1030l_int32 *rmap, *gmap, *bmap;
1031
1032 if (!pcolor)
1033 return ERROR_INT("&color not defined", __func__, 1);
1034 *pcolor = FALSE;
1035 if (!cmap)
1036 return ERROR_INT("cmap not defined", __func__, 1);
1037
1038 if (pixcmapToArrays(cmap, &rmap, &gmap, &bmap, NULL))
1039 return ERROR_INT("colormap arrays not made", __func__, 1);
1040 n = pixcmapGetCount(cmap);
1041 for (i = 0; i < n; i++) {
1042 if ((rmap[i] != gmap[i]) || (rmap[i] != bmap[i])) {
1043 *pcolor = TRUE;
1044 break;
1045 }
1046 }
1047
1048 LEPT_FREE(rmap);
1049 LEPT_FREE(gmap);
1050 LEPT_FREE(bmap);
1051 return 0;
1052}
1053
1054
1062l_ok
1064 l_int32 *popaque)
1065{
1066l_int32 i, n;
1067RGBA_QUAD *cta;
1068
1069 if (!popaque)
1070 return ERROR_INT("&opaque not defined", __func__, 1);
1071 *popaque = TRUE;
1072 if (!cmap)
1073 return ERROR_INT("cmap not defined", __func__, 1);
1074
1075 n = pixcmapGetCount(cmap);
1076 cta = (RGBA_QUAD *)cmap->array;
1077 for (i = 0; i < n; i++) {
1078 if (cta[i].alpha != 255) {
1079 *popaque = FALSE;
1080 break;
1081 }
1082 }
1083 return 0;
1084}
1085
1086
1119l_ok
1121 l_int32 *pntrans,
1122 l_int32 *pmax_trans,
1123 l_int32 *pmin_opaque)
1124{
1125l_int32 i, n, ntrans, max_trans, min_opaque, opaque_found;
1126RGBA_QUAD *cta;
1127
1128 if (pntrans) *pntrans = 0;
1129 if (pmax_trans) *pmax_trans = -1;
1130 if (pmin_opaque) *pmin_opaque = 256;
1131 if (!cmap)
1132 return ERROR_INT("cmap not defined", __func__, 1);
1133
1134 n = pixcmapGetCount(cmap);
1135 ntrans = 0;
1136 max_trans = -1;
1137 min_opaque = n;
1138 cta = (RGBA_QUAD *)cmap->array;
1139 opaque_found = FALSE;
1140 for (i = 0; i < n; i++) {
1141 if (cta[i].alpha != 255) {
1142 ntrans++;
1143 max_trans = i;
1144 } else if (opaque_found == FALSE) {
1145 opaque_found = TRUE;
1146 min_opaque = i;
1147 }
1148 }
1149 if (pntrans) *pntrans = ntrans;
1150 if (pmax_trans) *pmax_trans = max_trans;
1151 if (pmin_opaque) *pmin_opaque = min_opaque;
1152 return 0;
1153}
1154
1155
1164l_ok
1166 l_int32 *pblackwhite)
1167{
1168l_int32 val0, val1, hascolor;
1169RGBA_QUAD *cta;
1170
1171 if (!pblackwhite)
1172 return ERROR_INT("&blackwhite not defined", __func__, 1);
1173 *pblackwhite = FALSE;
1174 if (!cmap)
1175 return ERROR_INT("cmap not defined", __func__, 1);
1176 if (pixcmapGetCount(cmap) != 2)
1177 return 0;
1178
1179 pixcmapHasColor(cmap, &hascolor);
1180 if (hascolor) return 0;
1181
1182 cta = (RGBA_QUAD *)cmap->array;
1183 val0 = cta[0].red;
1184 val1 = cta[1].red;
1185 if ((val0 == 0 && val1 == 255) || (val0 == 255 && val1 == 0))
1186 *pblackwhite = TRUE;
1187 return 0;
1188}
1189
1190
1203l_ok
1205 l_int32 *pngray)
1206{
1207l_int32 n, i, rval, gval, bval, count;
1208l_int32 *array;
1209
1210 if (!pngray)
1211 return ERROR_INT("&ngray not defined", __func__, 1);
1212 *pngray = 0;
1213 if (!cmap)
1214 return ERROR_INT("cmap not defined", __func__, 1);
1215
1216 array = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
1217 n = pixcmapGetCount(cmap);
1218 count = 0;
1219 for (i = 0; i < n; i++) {
1220 pixcmapGetColor(cmap, i, &rval, &gval, &bval);
1221 if ((rval == gval) && (rval == bval) && (array[rval] == 0)) {
1222 array[rval] = 1;
1223 count++;
1224 }
1225 }
1226
1227 LEPT_FREE(array);
1228 *pngray = count;
1229 return 0;
1230}
1231
1232
1242l_ok
1244 l_float32 rankval,
1245 l_int32 *pindex)
1246{
1247l_int32 n, i, rval, gval, bval, rankindex;
1248NUMA *na, *nasort;
1249
1250 if (!pindex)
1251 return ERROR_INT("&index not defined", __func__, 1);
1252 *pindex = 0;
1253 if (!cmap)
1254 return ERROR_INT("cmap not defined", __func__, 1);
1255 if (rankval < 0.0 || rankval > 1.0)
1256 return ERROR_INT("rankval not in [0.0 ... 1.0]", __func__, 1);
1257
1258 n = pixcmapGetCount(cmap);
1259 na = numaCreate(n);
1260 for (i = 0; i < n; i++) {
1261 pixcmapGetColor(cmap, i, &rval, &gval, &bval);
1262 numaAddNumber(na, rval + gval + bval);
1263 }
1264 nasort = numaGetSortIndex(na, L_SORT_INCREASING);
1265 rankindex = (l_int32)(rankval * (n - 1) + 0.5);
1266 numaGetIValue(nasort, rankindex, pindex);
1267
1268 numaDestroy(&na);
1269 numaDestroy(&nasort);
1270 return 0;
1271}
1272
1273
1291l_ok
1293 l_int32 rval,
1294 l_int32 gval,
1295 l_int32 bval,
1296 l_int32 *pindex)
1297{
1298l_int32 i, n, delta, dist, mindist;
1299RGBA_QUAD *cta;
1300
1301 if (!pindex)
1302 return ERROR_INT("&index not defined", __func__, 1);
1303 *pindex = UNDEF;
1304 if (!cmap)
1305 return ERROR_INT("cmap not defined", __func__, 1);
1306
1307 if ((cta = (RGBA_QUAD *)cmap->array) == NULL)
1308 return ERROR_INT("cta not defined(!)", __func__, 1);
1309 n = pixcmapGetCount(cmap);
1310
1311 mindist = 3 * 255 * 255 + 1;
1312 for (i = 0; i < n; i++) {
1313 delta = cta[i].red - rval;
1314 dist = delta * delta;
1315 delta = cta[i].green - gval;
1316 dist += delta * delta;
1317 delta = cta[i].blue - bval;
1318 dist += delta * delta;
1319 if (dist < mindist) {
1320 *pindex = i;
1321 if (dist == 0)
1322 break;
1323 mindist = dist;
1324 }
1325 }
1326
1327 return 0;
1328}
1329
1330
1347l_ok
1349 l_int32 val,
1350 l_int32 *pindex)
1351{
1352l_int32 i, n, dist, mindist;
1353RGBA_QUAD *cta;
1354
1355 if (!pindex)
1356 return ERROR_INT("&index not defined", __func__, 1);
1357 *pindex = 0;
1358 if (!cmap)
1359 return ERROR_INT("cmap not defined", __func__, 1);
1360 if (val < 0 || val > 255)
1361 return ERROR_INT("val not in [0 ... 255]", __func__, 1);
1362
1363 if ((cta = (RGBA_QUAD *)cmap->array) == NULL)
1364 return ERROR_INT("cta not defined(!)", __func__, 1);
1365 n = pixcmapGetCount(cmap);
1366
1367 mindist = 256;
1368 for (i = 0; i < n; i++) {
1369 dist = cta[i].green - val;
1370 dist = L_ABS(dist);
1371 if (dist < mindist) {
1372 *pindex = i;
1373 if (dist == 0)
1374 break;
1375 mindist = dist;
1376 }
1377 }
1378
1379 return 0;
1380}
1381
1382
1398l_ok
1400 l_int32 index,
1401 l_int32 rval,
1402 l_int32 gval,
1403 l_int32 bval,
1404 l_int32 *pdist)
1405{
1406l_int32 n, delta, dist;
1407RGBA_QUAD *cta;
1408
1409 if (!pdist)
1410 return ERROR_INT("&dist not defined", __func__, 1);
1411 *pdist = UNDEF;
1412 if (!cmap)
1413 return ERROR_INT("cmap not defined", __func__, 1);
1414 n = pixcmapGetCount(cmap);
1415 if (index >= n)
1416 return ERROR_INT("invalid index", __func__, 1);
1417
1418 if ((cta = (RGBA_QUAD *)cmap->array) == NULL)
1419 return ERROR_INT("cta not defined(!)", __func__, 1);
1420
1421 delta = cta[index].red - rval;
1422 dist = delta * delta;
1423 delta = cta[index].green - gval;
1424 dist += delta * delta;
1425 delta = cta[index].blue - bval;
1426 dist += delta * delta;
1427 *pdist = dist;
1428
1429 return 0;
1430}
1431
1432
1452l_ok
1454 l_int32 select,
1455 l_int32 *pminval,
1456 l_int32 *pmaxval,
1457 l_int32 *pminindex,
1458 l_int32 *pmaxindex)
1459{
1460l_int32 i, n, imin, imax, minval, maxval, rval, gval, bval, aveval;
1461
1462 if (pminval) *pminval = UNDEF;
1463 if (pmaxval) *pmaxval = UNDEF;
1464 if (pminindex) *pminindex = UNDEF;
1465 if (pmaxindex) *pmaxindex = UNDEF;
1466 if (!pminval && !pmaxval && !pminindex && !pmaxindex)
1467 return ERROR_INT("no result requested", __func__, 1);
1468 if (!cmap)
1469 return ERROR_INT("cmap not defined", __func__, 1);
1470
1471 imin = UNDEF;
1472 imax = UNDEF;
1473 minval = 100000;
1474 maxval = -1;
1475 n = pixcmapGetCount(cmap);
1476 for (i = 0; i < n; i++) {
1477 pixcmapGetColor(cmap, i, &rval, &gval, &bval);
1478 if (select == L_SELECT_RED) {
1479 if (rval < minval) {
1480 minval = rval;
1481 imin = i;
1482 }
1483 if (rval > maxval) {
1484 maxval = rval;
1485 imax = i;
1486 }
1487 } else if (select == L_SELECT_GREEN) {
1488 if (gval < minval) {
1489 minval = gval;
1490 imin = i;
1491 }
1492 if (gval > maxval) {
1493 maxval = gval;
1494 imax = i;
1495 }
1496 } else if (select == L_SELECT_BLUE) {
1497 if (bval < minval) {
1498 minval = bval;
1499 imin = i;
1500 }
1501 if (bval > maxval) {
1502 maxval = bval;
1503 imax = i;
1504 }
1505 } else if (select == L_SELECT_AVERAGE) {
1506 aveval = (rval + gval + bval) / 3;
1507 if (aveval < minval) {
1508 minval = aveval;
1509 imin = i;
1510 }
1511 if (aveval > maxval) {
1512 maxval = aveval;
1513 imax = i;
1514 }
1515 } else {
1516 return ERROR_INT("invalid selection", __func__, 1);
1517 }
1518 }
1519
1520 if (pminval) *pminval = minval;
1521 if (pmaxval) *pmaxval = maxval;
1522 if (pminindex) *pminindex = imin;
1523 if (pmaxindex) *pmaxindex = imax;
1524 return 0;
1525}
1526
1527
1528/*-------------------------------------------------------------*
1529 * Colormap conversion *
1530 *-------------------------------------------------------------*/
1544PIXCMAP *
1546{
1547l_int32 i, rval, gval, bval;
1548l_int32 *curve;
1549l_float32 invgamma, x;
1550PIXCMAP *cmap;
1551
1552 if (gamma <= 0.0) gamma = 1.0;
1553
1554 /* Generate curve for transition part of color map */
1555 curve = (l_int32 *)LEPT_CALLOC(64, sizeof(l_int32));
1556 invgamma = 1. / gamma;
1557 for (i = 0; i < 64; i++) {
1558 x = (l_float32)i / 64.;
1559 curve[i] = (l_int32)(255. * powf(x, invgamma) + 0.5);
1560 }
1561
1562 cmap = pixcmapCreate(8);
1563 for (i = 0; i < 256; i++) {
1564 if (i < 32) {
1565 rval = 0;
1566 gval = 0;
1567 bval = curve[i + 32];
1568 } else if (i < 96) { /* 32 - 95 */
1569 rval = 0;
1570 gval = curve[i - 32];
1571 bval = 255;
1572 } else if (i < 160) { /* 96 - 159 */
1573 rval = curve[i - 96];
1574 gval = 255;
1575 bval = curve[159 - i];
1576 } else if (i < 224) { /* 160 - 223 */
1577 rval = 255;
1578 gval = curve[223 - i];
1579 bval = 0;
1580 } else { /* 224 - 255 */
1581 rval = curve[287 - i];
1582 gval = 0;
1583 bval = 0;
1584 }
1585 pixcmapAddColor(cmap, rval, gval, bval);
1586 }
1587
1588 LEPT_FREE(curve);
1589 return cmap;
1590}
1591
1592
1608PIXCMAP *
1609pixcmapGrayToColor(l_uint32 color)
1610{
1611l_int32 i, rval, gval, bval;
1612PIXCMAP *cmap;
1613
1614 extractRGBValues(color, &rval, &gval, &bval);
1615 cmap = pixcmapCreate(8);
1616 for (i = 0; i < 256; i++) {
1617 pixcmapAddColor(cmap, rval + (i * (255 - rval)) / 255,
1618 gval + (i * (255 - gval)) / 255,
1619 bval + (i * (255 - bval)) / 255);
1620 }
1621
1622 return cmap;
1623}
1624
1625
1640PIXCMAP *
1642 l_float32 rwt,
1643 l_float32 gwt,
1644 l_float32 bwt)
1645{
1646l_int32 i, n, rval, gval, bval, val;
1647l_float32 sum;
1648PIXCMAP *cmapd;
1649
1650 if (!cmaps)
1651 return (PIXCMAP *)ERROR_PTR("cmaps not defined", __func__, NULL);
1652 if (rwt < 0.0 || gwt < 0.0 || bwt < 0.0)
1653 return (PIXCMAP *)ERROR_PTR("weights not all >= 0.0", __func__, NULL);
1654
1655 /* Make sure the sum of weights is 1.0; otherwise, you can get
1656 * overflow in the gray value. */
1657 sum = rwt + gwt + bwt;
1658 if (sum == 0.0) {
1659 L_WARNING("all weights zero; setting equal to 1/3\n", __func__);
1660 rwt = gwt = bwt = 0.33333f;
1661 sum = 1.0;
1662 }
1663 if (L_ABS(sum - 1.0) > 0.0001) { /* maintain ratios with sum == 1.0 */
1664 L_WARNING("weights don't sum to 1; maintaining ratios\n", __func__);
1665 rwt = rwt / sum;
1666 gwt = gwt / sum;
1667 bwt = bwt / sum;
1668 }
1669
1670 if ((cmapd = pixcmapCopy(cmaps)) == NULL)
1671 return (PIXCMAP *)ERROR_PTR("cmapd not made", __func__, NULL);
1672 n = pixcmapGetCount(cmapd);
1673 for (i = 0; i < n; i++) {
1674 pixcmapGetColor(cmapd, i, &rval, &gval, &bval);
1675 val = (l_int32)(rwt * rval + gwt * gval + bwt * bval + 0.5);
1676 pixcmapResetColor(cmapd, i, val, val, val);
1677 }
1678
1679 return cmapd;
1680}
1681
1682
1695PIXCMAP *
1697{
1698l_int32 i, n, rval, gval, bval;
1699PIXCMAP *cmapd;
1700
1701 if (!cmaps)
1702 return (PIXCMAP *)ERROR_PTR("cmaps not defined", __func__, NULL);
1703 if (pixcmapGetDepth(cmaps) != 2)
1704 return (PIXCMAP *)ERROR_PTR("cmaps not for 2 bpp pix", __func__, NULL);
1705
1706 cmapd = pixcmapCreate(4);
1707 n = pixcmapGetCount(cmaps);
1708 for (i = 0; i < n; i++) {
1709 pixcmapGetColor(cmaps, i, &rval, &gval, &bval);
1710 pixcmapAddColor(cmapd, rval, gval, bval);
1711 }
1712 return cmapd;
1713}
1714
1715
1728PIXCMAP *
1730{
1731l_int32 i, n, depth, rval, gval, bval;
1732PIXCMAP *cmapd;
1733
1734 if (!cmaps)
1735 return (PIXCMAP *)ERROR_PTR("cmaps not defined", __func__, NULL);
1736 depth = pixcmapGetDepth(cmaps);
1737 if (depth == 8) return pixcmapCopy(cmaps);
1738 if (depth != 2 && depth != 4)
1739 return (PIXCMAP *)ERROR_PTR("cmaps not 2 or 4 bpp", __func__, NULL);
1740
1741 cmapd = pixcmapCreate(8);
1742 n = pixcmapGetCount(cmaps);
1743 for (i = 0; i < n; i++) {
1744 pixcmapGetColor(cmaps, i, &rval, &gval, &bval);
1745 pixcmapAddColor(cmapd, rval, gval, bval);
1746 }
1747 return cmapd;
1748}
1749
1750
1751/*-------------------------------------------------------------*
1752 * Colormap I/O *
1753 *-------------------------------------------------------------*/
1760PIXCMAP *
1761pixcmapRead(const char *filename)
1762{
1763FILE *fp;
1764PIXCMAP *cmap;
1765
1766 if (!filename)
1767 return (PIXCMAP *)ERROR_PTR("filename not defined", __func__, NULL);
1768
1769 if ((fp = fopenReadStream(filename)) == NULL)
1770 return (PIXCMAP *)ERROR_PTR_1("stream not opened",
1771 filename, __func__, NULL);
1772 cmap = pixcmapReadStream(fp);
1773 fclose(fp);
1774 if (!cmap)
1775 return (PIXCMAP *)ERROR_PTR_1("cmap not read",
1776 filename, __func__, NULL);
1777 return cmap;
1778}
1779
1780
1787PIXCMAP *
1789{
1790l_int32 rval, gval, bval, aval, ignore;
1791l_int32 i, index, ret, depth, ncolors;
1792PIXCMAP *cmap;
1793
1794 if (!fp)
1795 return (PIXCMAP *)ERROR_PTR("stream not defined", __func__, NULL);
1796
1797 ret = fscanf(fp, "\nPixcmap: depth = %d bpp; %d colors\n",
1798 &depth, &ncolors);
1799 if (ret != 2 ||
1800 (depth != 1 && depth != 2 && depth != 4 && depth != 8) ||
1801 (ncolors < 2 || ncolors > 256))
1802 return (PIXCMAP *)ERROR_PTR("invalid cmap size", __func__, NULL);
1803 ignore = fscanf(fp, "Color R-val G-val B-val Alpha\n");
1804 ignore = fscanf(fp, "----------------------------------------\n");
1805
1806 if ((cmap = pixcmapCreate(depth)) == NULL)
1807 return (PIXCMAP *)ERROR_PTR("cmap not made", __func__, NULL);
1808 for (i = 0; i < ncolors; i++) {
1809 if (fscanf(fp, "%3d %3d %3d %3d %3d\n",
1810 &index, &rval, &gval, &bval, &aval) != 5) {
1811 pixcmapDestroy(&cmap);
1812 return (PIXCMAP *)ERROR_PTR("invalid entry", __func__, NULL);
1813 }
1814 pixcmapAddRGBA(cmap, rval, gval, bval, aval);
1815 }
1816 return cmap;
1817}
1818
1819
1827PIXCMAP *
1828pixcmapReadMem(const l_uint8 *data,
1829 size_t size)
1830{
1831FILE *fp;
1832PIXCMAP *cmap;
1833
1834 if (!data)
1835 return (PIXCMAP *)ERROR_PTR("data not defined", __func__, NULL);
1836 if ((fp = fopenReadFromMemory(data, size)) == NULL)
1837 return (PIXCMAP *)ERROR_PTR("stream not opened", __func__, NULL);
1838
1839 cmap = pixcmapReadStream(fp);
1840 fclose(fp);
1841 if (!cmap) L_ERROR("cmap not read\n", __func__);
1842 return cmap;
1843}
1844
1845
1853l_ok
1854pixcmapWrite(const char *filename,
1855 const PIXCMAP *cmap)
1856{
1857l_int32 ret;
1858FILE *fp;
1859
1860 if (!filename)
1861 return ERROR_INT("filename not defined", __func__, 1);
1862 if (!cmap)
1863 return ERROR_INT("cmap not defined", __func__, 1);
1864
1865 if ((fp = fopenWriteStream(filename, "w")) == NULL)
1866 return ERROR_INT_1("stream not opened", filename, __func__, 1);
1867 ret = pixcmapWriteStream(fp, cmap);
1868 fclose(fp);
1869 if (ret)
1870 return ERROR_INT_1("cmap not written to stream", filename, __func__, 1);
1871 return 0;
1872}
1873
1874
1875
1883l_ok
1885 const PIXCMAP *cmap)
1886{
1887l_int32 *rmap, *gmap, *bmap, *amap;
1888l_int32 i;
1889
1890 if (!fp)
1891 return ERROR_INT("stream not defined", __func__, 1);
1892 if (!cmap)
1893 return ERROR_INT("cmap not defined", __func__, 1);
1894
1895 if (pixcmapToArrays(cmap, &rmap, &gmap, &bmap, &amap))
1896 return ERROR_INT("colormap arrays not made", __func__, 1);
1897
1898 fprintf(fp, "\nPixcmap: depth = %d bpp; %d colors\n", cmap->depth, cmap->n);
1899 fprintf(fp, "Color R-val G-val B-val Alpha\n");
1900 fprintf(fp, "----------------------------------------\n");
1901 for (i = 0; i < cmap->n; i++)
1902 fprintf(fp, "%3d %3d %3d %3d %3d\n",
1903 i, rmap[i], gmap[i], bmap[i], amap[i]);
1904 fprintf(fp, "\n");
1905
1906 LEPT_FREE(rmap);
1907 LEPT_FREE(gmap);
1908 LEPT_FREE(bmap);
1909 LEPT_FREE(amap);
1910 return 0;
1911}
1912
1913
1927l_ok
1928pixcmapWriteMem(l_uint8 **pdata,
1929 size_t *psize,
1930 const PIXCMAP *cmap)
1931{
1932l_int32 ret;
1933FILE *fp;
1934
1935 if (pdata) *pdata = NULL;
1936 if (psize) *psize = 0;
1937 if (!pdata)
1938 return ERROR_INT("&data not defined", __func__, 1);
1939 if (!psize)
1940 return ERROR_INT("&size not defined", __func__, 1);
1941 if (!cmap)
1942 return ERROR_INT("cmap not defined", __func__, 1);
1943
1944#if HAVE_FMEMOPEN
1945 if ((fp = open_memstream((char **)pdata, psize)) == NULL)
1946 return ERROR_INT("stream not opened", __func__, 1);
1947 ret = pixcmapWriteStream(fp, cmap);
1948 fputc('\0', fp);
1949 fclose(fp);
1950 *psize = *psize - 1;
1951#else
1952 L_INFO("no fmemopen API --> work-around: write to temp file\n", __func__);
1953 #ifdef _WIN32
1954 if ((fp = fopenWriteWinTempfile()) == NULL)
1955 return ERROR_INT("tmpfile stream not opened", __func__, 1);
1956 #else
1957 if ((fp = tmpfile()) == NULL)
1958 return ERROR_INT("tmpfile stream not opened", __func__, 1);
1959 #endif /* _WIN32 */
1960 ret = pixcmapWriteStream(fp, cmap);
1961 rewind(fp);
1962 *pdata = l_binaryReadStream(fp, psize);
1963 fclose(fp);
1964#endif /* HAVE_FMEMOPEN */
1965 return ret;
1966}
1967
1968
1969/*----------------------------------------------------------------------*
1970 * Extract colormap arrays and serialization *
1971 *----------------------------------------------------------------------*/
1982l_ok
1984 l_int32 **prmap,
1985 l_int32 **pgmap,
1986 l_int32 **pbmap,
1987 l_int32 **pamap)
1988{
1989l_int32 *rmap, *gmap, *bmap, *amap = NULL;
1990l_int32 i, ncolors;
1991RGBA_QUAD *cta;
1992
1993 if (!prmap || !pgmap || !pbmap)
1994 return ERROR_INT("&rmap, &gmap, &bmap not all defined", __func__, 1);
1995 *prmap = *pgmap = *pbmap = NULL;
1996 if (pamap) *pamap = NULL;
1997 if (!cmap)
1998 return ERROR_INT("cmap not defined", __func__, 1);
1999
2000 ncolors = pixcmapGetCount(cmap);
2001 rmap = (l_int32 *)LEPT_CALLOC(ncolors, sizeof(l_int32));
2002 gmap = (l_int32 *)LEPT_CALLOC(ncolors, sizeof(l_int32));
2003 bmap = (l_int32 *)LEPT_CALLOC(ncolors, sizeof(l_int32));
2004 *prmap = rmap;
2005 *pgmap = gmap;
2006 *pbmap = bmap;
2007 if (pamap) {
2008 amap = (l_int32 *)LEPT_CALLOC(ncolors, sizeof(l_int32));
2009 *pamap = amap;
2010 }
2011
2012 cta = (RGBA_QUAD *)cmap->array;
2013 for (i = 0; i < ncolors; i++) {
2014 rmap[i] = cta[i].red;
2015 gmap[i] = cta[i].green;
2016 bmap[i] = cta[i].blue;
2017 if (pamap)
2018 amap[i] = cta[i].alpha;
2019 }
2020
2021 return 0;
2022}
2023
2024
2033l_ok
2035 l_uint32 **ptab,
2036 l_int32 *pncolors)
2037{
2038l_int32 i, ncolors, rval, gval, bval, aval;
2039l_uint32 *tab;
2040
2041 if (!ptab)
2042 return ERROR_INT("&tab not defined", __func__, 1);
2043 *ptab = NULL;
2044 if (!cmap)
2045 return ERROR_INT("cmap not defined", __func__, 1);
2046
2047 ncolors = pixcmapGetCount(cmap);
2048 if (pncolors) *pncolors = ncolors;
2049 tab = (l_uint32 *)LEPT_CALLOC(ncolors, sizeof(l_uint32));
2050 *ptab = tab;
2051
2052 for (i = 0; i < ncolors; i++) {
2053 pixcmapGetRGBA(cmap, i, &rval, &gval, &bval, &aval);
2054 composeRGBAPixel(rval, gval, bval, aval, &tab[i]);
2055 }
2056 return 0;
2057}
2058
2059
2074l_ok
2076 l_int32 cpc,
2077 l_int32 *pncolors,
2078 l_uint8 **pdata)
2079{
2080l_int32 i, ncolors, rval, gval, bval, aval;
2081l_uint8 *data;
2082
2083 if (!pdata)
2084 return ERROR_INT("&data not defined", __func__, 1);
2085 *pdata = NULL;
2086 if (!pncolors)
2087 return ERROR_INT("&ncolors not defined", __func__, 1);
2088 *pncolors = 0;
2089 if (!cmap)
2090 return ERROR_INT("cmap not defined", __func__, 1);
2091 if (cpc != 3 && cpc != 4)
2092 return ERROR_INT("cpc not 3 or 4", __func__, 1);
2093
2094 ncolors = pixcmapGetCount(cmap);
2095 *pncolors = ncolors;
2096 data = (l_uint8 *)LEPT_CALLOC((size_t)cpc * ncolors, sizeof(l_uint8));
2097 *pdata = data;
2098
2099 for (i = 0; i < ncolors; i++) {
2100 pixcmapGetRGBA(cmap, i, &rval, &gval, &bval, &aval);
2101 data[cpc * i] = rval;
2102 data[cpc * i + 1] = gval;
2103 data[cpc * i + 2] = bval;
2104 if (cpc == 4)
2105 data[cpc * i + 3] = aval;
2106 }
2107 return 0;
2108}
2109
2110
2119PIXCMAP *
2121 l_int32 cpc,
2122 l_int32 ncolors)
2123{
2124l_int32 i, d, rval, gval, bval, aval;
2125PIXCMAP *cmap;
2126
2127 if (!data)
2128 return (PIXCMAP *)ERROR_PTR("data not defined", __func__, NULL);
2129 if (cpc != 3 && cpc != 4)
2130 return (PIXCMAP *)ERROR_PTR("cpc not 3 or 4", __func__, NULL);
2131 if (ncolors <= 0)
2132 return (PIXCMAP *)ERROR_PTR("no entries", __func__, NULL);
2133 if (ncolors > 256)
2134 return (PIXCMAP *)ERROR_PTR("ncolors > 256", __func__, NULL);
2135
2136 if (ncolors > 16)
2137 d = 8;
2138 else if (ncolors > 4)
2139 d = 4;
2140 else if (ncolors > 2)
2141 d = 2;
2142 else
2143 d = 1;
2144 cmap = pixcmapCreate(d);
2145 for (i = 0; i < ncolors; i++) {
2146 rval = data[cpc * i];
2147 gval = data[cpc * i + 1];
2148 bval = data[cpc * i + 2];
2149 if (cpc == 4)
2150 aval = data[cpc * i + 3];
2151 else
2152 aval = 255; /* opaque */
2153 pixcmapAddRGBA(cmap, rval, gval, bval, aval);
2154 }
2155
2156 return cmap;
2157}
2158
2159
2178char *
2180 l_int32 ncolors)
2181{
2182l_int32 i, j, hexbytes;
2183char *hexdata = NULL;
2184char buf[4];
2185
2186 if (!data)
2187 return (char *)ERROR_PTR("data not defined", __func__, NULL);
2188 if (ncolors < 1)
2189 return (char *)ERROR_PTR("no colors", __func__, NULL);
2190
2191 hexbytes = 2 + (2 * 3 + 1) * ncolors + 2;
2192 hexdata = (char *)LEPT_CALLOC(hexbytes, sizeof(char));
2193 hexdata[0] = '<';
2194 hexdata[1] = ' ';
2195
2196 for (i = 0; i < ncolors; i++) {
2197 j = 2 + (2 * 3 + 1) * i;
2198 snprintf(buf, sizeof(buf), "%02x", data[3 * i]);
2199 hexdata[j] = buf[0];
2200 hexdata[j + 1] = buf[1];
2201 snprintf(buf, sizeof(buf), "%02x", data[3 * i + 1]);
2202 hexdata[j + 2] = buf[0];
2203 hexdata[j + 3] = buf[1];
2204 snprintf(buf, sizeof(buf), "%02x", data[3 * i + 2]);
2205 hexdata[j + 4] = buf[0];
2206 hexdata[j + 5] = buf[1];
2207 hexdata[j + 6] = ' ';
2208 }
2209 hexdata[j + 7] = '>';
2210 hexdata[j + 8] = '\0';
2211 return hexdata;
2212}
2213
2214
2215/*-------------------------------------------------------------*
2216 * Colormap transforms *
2217 *-------------------------------------------------------------*/
2234l_ok
2236 l_float32 gamma,
2237 l_int32 minval,
2238 l_int32 maxval)
2239{
2240l_int32 rval, gval, bval, trval, tgval, tbval, i, ncolors;
2241NUMA *nag;
2242
2243 if (!cmap)
2244 return ERROR_INT("cmap not defined", __func__, 1);
2245 if (gamma <= 0.0) {
2246 L_WARNING("gamma must be > 0.0; setting to 1.0\n", __func__);
2247 gamma = 1.0;
2248 }
2249 if (minval >= maxval)
2250 return ERROR_INT("minval not < maxval", __func__, 1);
2251
2252 if (gamma == 1.0 && minval == 0 && maxval == 255) /* no-op */
2253 return 0;
2254
2255 if ((nag = numaGammaTRC(gamma, minval, maxval)) == NULL)
2256 return ERROR_INT("nag not made", __func__, 1);
2257
2258 ncolors = pixcmapGetCount(cmap);
2259 for (i = 0; i < ncolors; i++) {
2260 pixcmapGetColor(cmap, i, &rval, &gval, &bval);
2261 numaGetIValue(nag, rval, &trval);
2262 numaGetIValue(nag, gval, &tgval);
2263 numaGetIValue(nag, bval, &tbval);
2264 pixcmapResetColor(cmap, i, trval, tgval, tbval);
2265 }
2266
2267 numaDestroy(&nag);
2268 return 0;
2269}
2270
2271
2287l_ok
2289 l_float32 factor)
2290{
2291l_int32 i, ncolors, rval, gval, bval, trval, tgval, tbval;
2292NUMA *nac;
2293
2294 if (!cmap)
2295 return ERROR_INT("cmap not defined", __func__, 1);
2296 if (factor < 0.0) {
2297 L_WARNING("factor must be >= 0.0; setting to 0.0\n", __func__);
2298 factor = 0.0;
2299 }
2300
2301 if ((nac = numaContrastTRC(factor)) == NULL)
2302 return ERROR_INT("nac not made", __func__, 1);
2303
2304 ncolors = pixcmapGetCount(cmap);
2305 for (i = 0; i < ncolors; i++) {
2306 pixcmapGetColor(cmap, i, &rval, &gval, &bval);
2307 numaGetIValue(nac, rval, &trval);
2308 numaGetIValue(nac, gval, &tgval);
2309 numaGetIValue(nac, bval, &tbval);
2310 pixcmapResetColor(cmap, i, trval, tgval, tbval);
2311 }
2312
2313 numaDestroy(&nac);
2314 return 0;
2315}
2316
2317
2337l_ok
2339 l_float32 fraction)
2340{
2341l_int32 i, ncolors, rval, gval, bval;
2342
2343 if (!cmap)
2344 return ERROR_INT("cmap not defined", __func__, 1);
2345 if (fraction < -1.0 || fraction > 1.0)
2346 return ERROR_INT("fraction not in [-1.0, 1.0]", __func__, 1);
2347
2348 ncolors = pixcmapGetCount(cmap);
2349 for (i = 0; i < ncolors; i++) {
2350 pixcmapGetColor(cmap, i, &rval, &gval, &bval);
2351 if (fraction < 0.0)
2352 pixcmapResetColor(cmap, i,
2353 (l_int32)((1.0 + fraction) * rval),
2354 (l_int32)((1.0 + fraction) * gval),
2355 (l_int32)((1.0 + fraction) * bval));
2356 else
2357 pixcmapResetColor(cmap, i,
2358 rval + (l_int32)(fraction * (255 - rval)),
2359 gval + (l_int32)(fraction * (255 - gval)),
2360 bval + (l_int32)(fraction * (255 - bval)));
2361 }
2362
2363 return 0;
2364}
2365
2366
2385l_ok
2387 l_uint32 srcval,
2388 l_uint32 dstval)
2389{
2390l_int32 i, ncolors, rval, gval, bval;
2391l_uint32 newval;
2392
2393 if (!cmap)
2394 return ERROR_INT("cmap not defined", __func__, 1);
2395
2396 ncolors = pixcmapGetCount(cmap);
2397 for (i = 0; i < ncolors; i++) {
2398 pixcmapGetColor(cmap, i, &rval, &gval, &bval);
2399 pixelShiftByComponent(rval, gval, bval, srcval, dstval, &newval);
2400 extractRGBValues(newval, &rval, &gval, &bval);
2401 pixcmapResetColor(cmap, i, rval, gval, bval);
2402 }
2403
2404 return 0;
2405}
l_ok pixcmapSetAlpha(PIXCMAP *cmap, l_int32 index, l_int32 aval)
pixcmapSetAlpha()
Definition colormap.c:962
void pixcmapDestroy(PIXCMAP **pcmap)
pixcmapDestroy()
Definition colormap.c:272
l_ok pixcmapContrastTRC(PIXCMAP *cmap, l_float32 factor)
pixcmapContrastTRC()
Definition colormap.c:2288
l_ok pixcmapHasColor(PIXCMAP *cmap, l_int32 *pcolor)
pixcmapHasColor()
Definition colormap.c:1026
l_int32 pixcmapGetCount(const PIXCMAP *cmap)
pixcmapGetCount()
Definition colormap.c:683
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:1399
l_ok pixcmapSetBlackAndWhite(PIXCMAP *cmap, l_int32 setblack, l_int32 setwhite)
pixcmapSetBlackAndWhite()
Definition colormap.c:655
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:1884
l_ok pixcmapAddNewColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pindex)
pixcmapAddNewColor()
Definition colormap.c:481
l_ok pixcmapGetNearestIndex(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pindex)
pixcmapGetNearestIndex()
Definition colormap.c:1292
PIXCMAP * pixcmapGrayToColor(l_uint32 color)
pixcmapGrayToColor()
Definition colormap.c:1609
l_ok pixcmapGetColor32(PIXCMAP *cmap, l_int32 index, l_uint32 *pval32)
pixcmapGetColor32()
Definition colormap.c:827
l_ok pixcmapSerializeToMemory(PIXCMAP *cmap, l_int32 cpc, l_int32 *pncolors, l_uint8 **pdata)
pixcmapSerializeToMemory()
Definition colormap.c:2075
l_ok pixcmapWrite(const char *filename, const PIXCMAP *cmap)
pixcmapWrite()
Definition colormap.c:1854
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:1928
l_ok pixcmapAddRGBA(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 aval)
pixcmapAddRGBA()
Definition colormap.c:439
PIXCMAP * pixcmapDeserializeFromMemory(l_uint8 *data, l_int32 cpc, l_int32 ncolors)
pixcmapDeserializeFromMemory()
Definition colormap.c:2120
l_ok pixcmapAddBlackOrWhite(PIXCMAP *cmap, l_int32 color, l_int32 *pindex)
pixcmapAddBlackOrWhite()
Definition colormap.c:618
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:528
PIXCMAP * pixcmapColorToGray(PIXCMAP *cmaps, l_float32 rwt, l_float32 gwt, l_float32 bwt)
pixcmapColorToGray()
Definition colormap.c:1641
l_ok pixcmapResetColor(PIXCMAP *cmap, l_int32 index, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapResetColor()
Definition colormap.c:923
l_ok pixcmapGammaTRC(PIXCMAP *cmap, l_float32 gamma, l_int32 minval, l_int32 maxval)
pixcmapGammaTRC()
Definition colormap.c:2235
PIXCMAP * pixcmapConvertTo4(PIXCMAP *cmaps)
pixcmapConvertTo4()
Definition colormap.c:1696
l_int32 pixcmapGetIndex(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pindex)
pixcmapGetIndex()
Definition colormap.c:989
PIXCMAP * pixcmapReadStream(FILE *fp)
pixcmapReadStream()
Definition colormap.c:1788
l_ok pixcmapCountGrayColors(PIXCMAP *cmap, l_int32 *pngray)
pixcmapCountGrayColors()
Definition colormap.c:1204
l_int32 pixcmapGetDepth(PIXCMAP *cmap)
pixcmapGetDepth()
Definition colormap.c:713
l_ok pixcmapNonOpaqueColorsInfo(PIXCMAP *cmap, l_int32 *pntrans, l_int32 *pmax_trans, l_int32 *pmin_opaque)
pixcmapNonOpaqueColorsInfo()
Definition colormap.c:1120
l_ok pixcmapUsableColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pusable)
pixcmapUsableColor()
Definition colormap.c:573
l_ok pixcmapShiftIntensity(PIXCMAP *cmap, l_float32 fraction)
pixcmapShiftIntensity()
Definition colormap.c:2338
l_ok pixcmapGetColor(PIXCMAP *cmap, l_int32 index, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
pixcmapGetColor()
Definition colormap.c:789
l_ok pixcmapIsOpaque(PIXCMAP *cmap, l_int32 *popaque)
pixcmapIsOpaque()
Definition colormap.c:1063
l_ok pixcmapGetMinDepth(PIXCMAP *cmap, l_int32 *pmindepth)
pixcmapGetMinDepth()
Definition colormap.c:734
PIXCMAP * pixcmapGrayToFalseColor(l_float32 gamma)
pixcmapGrayToFalseColor()
Definition colormap.c:1545
l_int32 pixcmapGetFreeCount(PIXCMAP *cmap)
pixcmapGetFreeCount()
Definition colormap.c:698
l_ok pixcmapGetRangeValues(PIXCMAP *cmap, l_int32 select, l_int32 *pminval, l_int32 *pmaxval, l_int32 *pminindex, l_int32 *pmaxindex)
pixcmapGetRangeValues()
Definition colormap.c:1453
l_ok pixcmapClear(PIXCMAP *cmap)
pixcmapClear()
Definition colormap.c:768
char * pixcmapConvertToHex(l_uint8 *data, l_int32 ncolors)
pixcmapConvertToHex()
Definition colormap.c:2179
l_ok pixcmapGetRankIntensity(PIXCMAP *cmap, l_float32 rankval, l_int32 *pindex)
pixcmapGetRankIntensity()
Definition colormap.c:1243
PIXCMAP * pixcmapReadMem(const l_uint8 *data, size_t size)
pixcmapReadMem()
Definition colormap.c:1828
l_ok pixcmapGetRGBA(PIXCMAP *cmap, l_int32 index, l_int32 *prval, l_int32 *pgval, l_int32 *pbval, l_int32 *paval)
pixcmapGetRGBA()
Definition colormap.c:853
PIXCMAP * pixcmapConvertTo8(PIXCMAP *cmaps)
pixcmapConvertTo8()
Definition colormap.c:1729
l_ok pixcmapToArrays(const PIXCMAP *cmap, l_int32 **prmap, l_int32 **pgmap, l_int32 **pbmap, l_int32 **pamap)
pixcmapToArrays()
Definition colormap.c:1983
l_ok pixcmapShiftByComponent(PIXCMAP *cmap, l_uint32 srcval, l_uint32 dstval)
pixcmapShiftByComponent()
Definition colormap.c:2386
l_ok pixcmapIsBlackAndWhite(PIXCMAP *cmap, l_int32 *pblackwhite)
pixcmapIsBlackAndWhite()
Definition colormap.c:1165
PIXCMAP * pixcmapRead(const char *filename)
pixcmapRead()
Definition colormap.c:1761
l_ok pixcmapAddColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapAddColor()
Definition colormap.c:403
l_ok pixcmapGetNearestGrayIndex(PIXCMAP *cmap, l_int32 val, l_int32 *pindex)
pixcmapGetNearestGrayIndex()
Definition colormap.c:1348
l_ok pixcmapToRGBTable(PIXCMAP *cmap, l_uint32 **ptab, l_int32 *pncolors)
pixcmapToRGBTable()
Definition colormap.c:2034
l_ok pixcmapGetRGBA32(PIXCMAP *cmap, l_int32 index, l_uint32 *pval32)
pixcmapGetRGBA32()
Definition colormap.c:889
@ 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