Leptonica 1.82.0
Image processing and image analysis suite
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
115/*-------------------------------------------------------------*
116 * Colormap creation and addition *
117 *-------------------------------------------------------------*/
124PIXCMAP *
125pixcmapCreate(l_int32 depth)
126{
127RGBA_QUAD *cta;
128PIXCMAP *cmap;
129
130 PROCNAME("pixcmapCreate");
131
132 if (depth != 1 && depth != 2 && depth !=4 && depth != 8)
133 return (PIXCMAP *)ERROR_PTR("depth not in {1,2,4,8}", procName, NULL);
134
135 cmap = (PIXCMAP *)LEPT_CALLOC(1, sizeof(PIXCMAP));
136 cmap->depth = depth;
137 cmap->nalloc = 1 << depth;
138 cta = (RGBA_QUAD *)LEPT_CALLOC(cmap->nalloc, sizeof(RGBA_QUAD));
139 cmap->array = cta;
140 cmap->n = 0;
141 return cmap;
142}
143
144
171PIXCMAP *
173 l_int32 hasblack,
174 l_int32 haswhite)
175{
176l_int32 ncolors, i;
177l_int32 red[256], green[256], blue[256];
178PIXCMAP *cmap;
179
180 PROCNAME("pixcmapCreateRandom");
181
182 if (depth != 2 && depth != 4 && depth != 8)
183 return (PIXCMAP *)ERROR_PTR("depth not in {2, 4, 8}", procName, NULL);
184 if (hasblack != 0) hasblack = 1;
185 if (haswhite != 0) haswhite = 1;
186
187 cmap = pixcmapCreate(depth);
188 ncolors = 1 << depth;
189 if (hasblack) /* first color is optionally black */
190 pixcmapAddColor(cmap, 0, 0, 0);
191 for (i = hasblack; i < ncolors - haswhite; i++) {
192 red[i] = (l_uint32)rand() & 0xff;
193 green[i] = (l_uint32)rand() & 0xff;
194 blue[i] = (l_uint32)rand() & 0xff;
195 pixcmapAddColor(cmap, red[i], green[i], blue[i]);
196 }
197 if (haswhite) /* last color is optionally white */
198 pixcmapAddColor(cmap, 255, 255, 255);
199
200 return cmap;
201}
202
203
217PIXCMAP *
219 l_int32 nlevels)
220{
221l_int32 maxlevels, i, val;
222PIXCMAP *cmap;
223
224 PROCNAME("pixcmapCreateLinear");
225
226 if (d != 1 && d != 2 && d !=4 && d != 8)
227 return (PIXCMAP *)ERROR_PTR("d not in {1, 2, 4, 8}", procName, NULL);
228 maxlevels = 1 << d;
229 if (nlevels < 2 || nlevels > maxlevels)
230 return (PIXCMAP *)ERROR_PTR("invalid nlevels", procName, NULL);
231
232 cmap = pixcmapCreate(d);
233 for (i = 0; i < nlevels; i++) {
234 val = (255 * i) / (nlevels - 1);
235 pixcmapAddColor(cmap, val, val, val);
236 }
237 return cmap;
238}
239
240
247PIXCMAP *
248pixcmapCopy(const PIXCMAP *cmaps)
249{
250l_int32 nbytes, valid;
251PIXCMAP *cmapd;
252
253 PROCNAME("pixcmapCopy");
254
255 if (!cmaps)
256 return (PIXCMAP *)ERROR_PTR("cmaps not defined", procName, NULL);
257 pixcmapIsValid(cmaps, NULL, &valid);
258 if (!valid)
259 return (PIXCMAP *)ERROR_PTR("invalid cmap", procName, NULL);
260
261 cmapd = (PIXCMAP *)LEPT_CALLOC(1, sizeof(PIXCMAP));
262 nbytes = cmaps->nalloc * sizeof(RGBA_QUAD);
263 cmapd->array = (void *)LEPT_CALLOC(1, nbytes);
264 memcpy(cmapd->array, cmaps->array, cmaps->n * sizeof(RGBA_QUAD));
265 cmapd->n = cmaps->n;
266 cmapd->nalloc = cmaps->nalloc;
267 cmapd->depth = cmaps->depth;
268 return cmapd;
269}
270
271
278void
280{
281PIXCMAP *cmap;
282
283 PROCNAME("pixcmapDestroy");
284
285 if (pcmap == NULL) {
286 L_WARNING("ptr address is null!\n", procName);
287 return;
288 }
289
290 if ((cmap = *pcmap) == NULL)
291 return;
292
293 LEPT_FREE(cmap->array);
294 LEPT_FREE(cmap);
295 *pcmap = NULL;
296}
297
316l_ok
318 PIX *pix,
319 l_int32 *pvalid)
320{
321l_int32 d, depth, nalloc, maxindex, maxcolors;
322
323 PROCNAME("pixcmapIsValid");
324
325 if (!pvalid)
326 return ERROR_INT("&valid not defined", procName, 1);
327 *pvalid = 0;
328 if (!cmap)
329 return ERROR_INT("cmap not defined", procName, 1);
330 if (!cmap->array)
331 return ERROR_INT("cmap array not defined", procName, 1);
332 d = cmap->depth;
333 if (d != 1 && d != 2 && d != 4 && d != 8) {
334 L_ERROR("invalid cmap depth: %d\n", procName, d);
335 return 1;
336 }
337 nalloc = cmap->nalloc;
338 if (nalloc != (1 << d)) {
339 L_ERROR("invalid cmap nalloc = %d; d = %d\n", procName, nalloc, d);
340 return 1;
341 }
342 if (cmap->n < 0 || cmap->n > nalloc) {
343 L_ERROR("invalid cmap n: %d; nalloc = %d\n", procName, cmap->n, nalloc);
344 return 1;
345 }
346
347 /* If a pix is given, it must have a depth no larger than 8 */
348 if (pix) {
349 depth = pixGetDepth(pix);
350 if (depth > 8) {
351 L_ERROR("pix depth %d > 8\n", procName, depth);
352 return 1;
353 }
354 maxcolors = 1 << depth;
355 }
356
357 /* To prevent indexing overflow into the cmap, the pix depth
358 * must not exceed the cmap depth. Do not require depth equality,
359 * because some functions such as median cut quantizers allow
360 * the cmap depth to be bigger than the pix depth. */
361 if (pix && (depth > d)) {
362 L_ERROR("(pix depth = %d) > (cmap depth = %d)\n", procName, depth, d);
363 return 1;
364 }
365 if (pix && cmap->n < 1) {
366 L_ERROR("cmap array is empty; invalid with any pix\n", procName);
367 return 1;
368 }
369
370 /* Do not let the colormap have more colors than the pixels
371 * can address. The png encoder considers this to be an
372 * "invalid palette length". For example, for 1 bpp, the
373 * colormap may have a depth > 1, but it must not have more
374 * than 2 colors. */
375 if (pix && (cmap->n > maxcolors)) {
376 L_ERROR("cmap entries = %d > max colors for pix = %d\n", procName,
377 cmap->n, maxcolors);
378 return 1;
379 }
380
381 /* Where the colormap or the pix may have been corrupted, and
382 * in particular when reading or writing image files, it should
383 * be verified that the image pixel values do not exceed the
384 * max indexing into the colormap array. */
385 if (pix) {
386 pixGetMaxColorIndex(pix, &maxindex);
387 if (maxindex >= cmap->n) {
388 L_ERROR("(max index = %d) >= (num colors = %d)\n", procName,
389 maxindex, cmap->n);
390 return 1;
391 }
392 }
393
394 *pvalid = 1;
395 return 0;
396}
397
398
413l_ok
415 l_int32 rval,
416 l_int32 gval,
417 l_int32 bval)
418{
419RGBA_QUAD *cta;
420
421 PROCNAME("pixcmapAddColor");
422
423 if (!cmap)
424 return ERROR_INT("cmap not defined", procName, 1);
425 if (cmap->n >= cmap->nalloc)
426 return ERROR_INT("no free color entries", procName, 1);
427
428 cta = (RGBA_QUAD *)cmap->array;
429 cta[cmap->n].red = rval;
430 cta[cmap->n].green = gval;
431 cta[cmap->n].blue = bval;
432 cta[cmap->n].alpha = 255;
433 cmap->n++;
434 return 0;
435}
436
437
451l_ok
453 l_int32 rval,
454 l_int32 gval,
455 l_int32 bval,
456 l_int32 aval)
457{
458RGBA_QUAD *cta;
459
460 PROCNAME("pixcmapAddRGBA");
461
462 if (!cmap)
463 return ERROR_INT("cmap not defined", procName, 1);
464 if (cmap->n >= cmap->nalloc)
465 return ERROR_INT("no free color entries", procName, 1);
466
467 cta = (RGBA_QUAD *)cmap->array;
468 cta[cmap->n].red = rval;
469 cta[cmap->n].green = gval;
470 cta[cmap->n].blue = bval;
471 cta[cmap->n].alpha = aval;
472 cmap->n++;
473 return 0;
474}
475
476
495l_ok
497 l_int32 rval,
498 l_int32 gval,
499 l_int32 bval,
500 l_int32 *pindex)
501{
502 PROCNAME("pixcmapAddNewColor");
503
504 if (!pindex)
505 return ERROR_INT("&index not defined", procName, 1);
506 *pindex = 0;
507 if (!cmap)
508 return ERROR_INT("cmap not defined", procName, 1);
509
510 /* Check if the color is already present. */
511 if (!pixcmapGetIndex(cmap, rval, gval, bval, pindex)) /* found */
512 return 0;
513
514 /* We need to add the color. Is there room? */
515 if (cmap->n >= cmap->nalloc) {
516 L_WARNING("no free color entries\n", procName);
517 return 2;
518 }
519
520 /* There's room. Add it. */
521 pixcmapAddColor(cmap, rval, gval, bval);
522 *pindex = pixcmapGetCount(cmap) - 1;
523 return 0;
524}
525
526
544l_ok
546 l_int32 rval,
547 l_int32 gval,
548 l_int32 bval,
549 l_int32 *pindex)
550{
551 PROCNAME("pixcmapAddNearestColor");
552
553 if (!pindex)
554 return ERROR_INT("&index not defined", procName, 1);
555 *pindex = 0;
556 if (!cmap)
557 return ERROR_INT("cmap not defined", procName, 1);
558
559 /* Check if the color is already present. */
560 if (!pixcmapGetIndex(cmap, rval, gval, bval, pindex)) /* found */
561 return 0;
562
563 /* We need to add the color. Is there room? */
564 if (cmap->n < cmap->nalloc) {
565 pixcmapAddColor(cmap, rval, gval, bval);
566 *pindex = pixcmapGetCount(cmap) - 1;
567 return 0;
568 }
569
570 /* There's no room. Return the index of the nearest color */
571 pixcmapGetNearestIndex(cmap, rval, gval, bval, pindex);
572 return 0;
573}
574
575
591l_ok
593 l_int32 rval,
594 l_int32 gval,
595 l_int32 bval,
596 l_int32 *pusable)
597{
598l_int32 index;
599
600 PROCNAME("pixcmapUsableColor");
601
602 if (!pusable)
603 return ERROR_INT("&usable not defined", procName, 1);
604 *pusable = 0;
605 if (!cmap)
606 return ERROR_INT("cmap not defined", procName, 1);
607
608 /* Is there room to add it? */
609 if (cmap->n < cmap->nalloc) {
610 *pusable = 1;
611 return 0;
612 }
613
614 /* No room; check if the color is already present. */
615 if (!pixcmapGetIndex(cmap, rval, gval, bval, &index)) /* found */
616 *pusable = 1;
617 return 0;
618}
619
620
638l_ok
640 l_int32 color,
641 l_int32 *pindex)
642{
643l_int32 index;
644
645 PROCNAME("pixcmapAddBlackOrWhite");
646
647 if (pindex) *pindex = 0;
648 if (!cmap)
649 return ERROR_INT("cmap not defined", procName, 1);
650
651 if (color == 0) { /* black */
652 if (pixcmapGetFreeCount(cmap) > 0)
653 pixcmapAddNewColor(cmap, 0, 0, 0, &index);
654 else
655 pixcmapGetRankIntensity(cmap, 0.0, &index);
656 } else { /* white */
657 if (pixcmapGetFreeCount(cmap) > 0)
658 pixcmapAddNewColor(cmap, 255, 255, 255, &index);
659 else
660 pixcmapGetRankIntensity(cmap, 1.0, &index);
661 }
662
663 if (pindex)
664 *pindex = index;
665 return 0;
666}
667
668
677l_ok
679 l_int32 setblack,
680 l_int32 setwhite)
681{
682l_int32 index;
683
684 PROCNAME("pixcmapSetBlackAndWhite");
685
686 if (!cmap)
687 return ERROR_INT("cmap not defined", procName, 1);
688
689 if (setblack) {
690 pixcmapGetRankIntensity(cmap, 0.0, &index);
691 pixcmapResetColor(cmap, index, 0, 0, 0);
692 }
693 if (setwhite) {
694 pixcmapGetRankIntensity(cmap, 1.0, &index);
695 pixcmapResetColor(cmap, index, 255, 255, 255);
696 }
697 return 0;
698}
699
700
707l_int32
709{
710 PROCNAME("pixcmapGetCount");
711
712 if (!cmap)
713 return ERROR_INT("cmap not defined", procName, 0);
714 return cmap->n;
715}
716
717
724l_int32
726{
727 PROCNAME("pixcmapGetFreeCount");
728
729 if (!cmap)
730 return ERROR_INT("cmap not defined", procName, 0);
731 return (cmap->nalloc - cmap->n);
732}
733
734
741l_int32
743{
744 PROCNAME("pixcmapGetDepth");
745
746 if (!cmap)
747 return ERROR_INT("cmap not defined", procName, 0);
748 return cmap->depth;
749}
750
751
764l_ok
766 l_int32 *pmindepth)
767{
768l_int32 ncolors;
769
770 PROCNAME("pixcmapGetMinDepth");
771
772 if (!pmindepth)
773 return ERROR_INT("&mindepth not defined", procName, 1);
774 *pmindepth = 0;
775 if (!cmap)
776 return ERROR_INT("cmap not defined", procName, 1);
777
778 ncolors = pixcmapGetCount(cmap);
779 if (ncolors <= 4)
780 *pmindepth = 2;
781 else if (ncolors <= 16)
782 *pmindepth = 4;
783 else /* ncolors > 16 */
784 *pmindepth = 8;
785 return 0;
786}
787
788
800l_ok
802{
803 PROCNAME("pixcmapClear");
804
805 if (!cmap)
806 return ERROR_INT("cmap not defined", procName, 1);
807 cmap->n = 0;
808 return 0;
809}
810
811
812/*-------------------------------------------------------------*
813 * Colormap random access *
814 *-------------------------------------------------------------*/
823l_ok
825 l_int32 index,
826 l_int32 *prval,
827 l_int32 *pgval,
828 l_int32 *pbval)
829{
830RGBA_QUAD *cta;
831
832 PROCNAME("pixcmapGetColor");
833
834 if (!prval || !pgval || !pbval)
835 return ERROR_INT("&rval, &gval, &bval not all defined", procName, 1);
836 *prval = *pgval = *pbval = 0;
837 if (!cmap)
838 return ERROR_INT("cmap not defined", procName, 1);
839 if (index < 0 || index >= cmap->n)
840 return ERROR_INT("index out of bounds", procName, 1);
841
842 cta = (RGBA_QUAD *)cmap->array;
843 *prval = cta[index].red;
844 *pgval = cta[index].green;
845 *pbval = cta[index].blue;
846 return 0;
847}
848
849
863l_ok
865 l_int32 index,
866 l_uint32 *pval32)
867{
868l_int32 rval, gval, bval;
869
870 PROCNAME("pixcmapGetColor32");
871
872 if (!pval32)
873 return ERROR_INT("&val32 not defined", procName, 1);
874 *pval32 = 0;
875
876 if (pixcmapGetColor(cmap, index, &rval, &gval, &bval) != 0)
877 return ERROR_INT("rgb values not found", procName, 1);
878 composeRGBAPixel(rval, gval, bval, 255, pval32);
879 return 0;
880}
881
882
891l_ok
893 l_int32 index,
894 l_int32 *prval,
895 l_int32 *pgval,
896 l_int32 *pbval,
897 l_int32 *paval)
898{
899RGBA_QUAD *cta;
900
901 PROCNAME("pixcmapGetRGBA");
902
903 if (!prval || !pgval || !pbval || !paval)
904 return ERROR_INT("&rval, &gval, &bval, &aval not all defined",
905 procName, 1);
906 *prval = *pgval = *pbval = *paval = 0;
907 if (!cmap)
908 return ERROR_INT("cmap not defined", procName, 1);
909 if (index < 0 || index >= cmap->n)
910 return ERROR_INT("index out of bounds", procName, 1);
911
912 cta = (RGBA_QUAD *)cmap->array;
913 *prval = cta[index].red;
914 *pgval = cta[index].green;
915 *pbval = cta[index].blue;
916 *paval = cta[index].alpha;
917 return 0;
918}
919
920
929l_ok
931 l_int32 index,
932 l_uint32 *pval32)
933{
934l_int32 rval, gval, bval, aval;
935
936 PROCNAME("pixcmapGetRGBA32");
937
938 if (!pval32)
939 return ERROR_INT("&val32 not defined", procName, 1);
940 *pval32 = 0;
941
942 if (pixcmapGetRGBA(cmap, index, &rval, &gval, &bval, &aval) != 0)
943 return ERROR_INT("rgba values not found", procName, 1);
944 composeRGBAPixel(rval, gval, bval, aval, pval32);
945 return 0;
946}
947
948
965l_ok
967 l_int32 index,
968 l_int32 rval,
969 l_int32 gval,
970 l_int32 bval)
971{
972RGBA_QUAD *cta;
973
974 PROCNAME("pixcmapResetColor");
975
976 if (!cmap)
977 return ERROR_INT("cmap not defined", procName, 1);
978 if (index < 0 || index >= cmap->n)
979 return ERROR_INT("index out of bounds", procName, 1);
980
981 cta = (RGBA_QUAD *)cmap->array;
982 cta[index].red = rval;
983 cta[index].green = gval;
984 cta[index].blue = bval;
985 cta[index].alpha = 255;
986 return 0;
987}
988
989
1006l_ok
1008 l_int32 index,
1009 l_int32 aval)
1010{
1011RGBA_QUAD *cta;
1012
1013 PROCNAME("pixcmapSetAlpha");
1014
1015 if (!cmap)
1016 return ERROR_INT("cmap not defined", procName, 1);
1017 if (index < 0 || index >= cmap->n)
1018 return ERROR_INT("index out of bounds", procName, 1);
1019
1020 cta = (RGBA_QUAD *)cmap->array;
1021 cta[index].alpha = aval;
1022 return 0;
1023}
1024
1025
1035l_int32
1037 l_int32 rval,
1038 l_int32 gval,
1039 l_int32 bval,
1040 l_int32 *pindex)
1041{
1042l_int32 n, i;
1043RGBA_QUAD *cta;
1044
1045 PROCNAME("pixcmapGetIndex");
1046
1047 if (!pindex)
1048 return ERROR_INT("&index not defined", procName, 1);
1049 *pindex = 0;
1050 if (!cmap)
1051 return ERROR_INT("cmap not defined", procName, 1);
1052 n = pixcmapGetCount(cmap);
1053
1054 cta = (RGBA_QUAD *)cmap->array;
1055 for (i = 0; i < n; i++) {
1056 if (rval == cta[i].red &&
1057 gval == cta[i].green &&
1058 bval == cta[i].blue) {
1059 *pindex = i;
1060 return 0;
1061 }
1062 }
1063 return 1;
1064}
1065
1066
1074l_ok
1076 l_int32 *pcolor)
1077{
1078l_int32 n, i;
1079l_int32 *rmap, *gmap, *bmap;
1080
1081 PROCNAME("pixcmapHasColor");
1082
1083 if (!pcolor)
1084 return ERROR_INT("&color not defined", procName, 1);
1085 *pcolor = FALSE;
1086 if (!cmap)
1087 return ERROR_INT("cmap not defined", procName, 1);
1088
1089 if (pixcmapToArrays(cmap, &rmap, &gmap, &bmap, NULL))
1090 return ERROR_INT("colormap arrays not made", procName, 1);
1091 n = pixcmapGetCount(cmap);
1092 for (i = 0; i < n; i++) {
1093 if ((rmap[i] != gmap[i]) || (rmap[i] != bmap[i])) {
1094 *pcolor = TRUE;
1095 break;
1096 }
1097 }
1098
1099 LEPT_FREE(rmap);
1100 LEPT_FREE(gmap);
1101 LEPT_FREE(bmap);
1102 return 0;
1103}
1104
1105
1113l_ok
1115 l_int32 *popaque)
1116{
1117l_int32 i, n;
1118RGBA_QUAD *cta;
1119
1120 PROCNAME("pixcmapIsOpaque");
1121
1122 if (!popaque)
1123 return ERROR_INT("&opaque not defined", procName, 1);
1124 *popaque = TRUE;
1125 if (!cmap)
1126 return ERROR_INT("cmap not defined", procName, 1);
1127
1128 n = pixcmapGetCount(cmap);
1129 cta = (RGBA_QUAD *)cmap->array;
1130 for (i = 0; i < n; i++) {
1131 if (cta[i].alpha != 255) {
1132 *popaque = FALSE;
1133 break;
1134 }
1135 }
1136 return 0;
1137}
1138
1139
1172l_ok
1174 l_int32 *pntrans,
1175 l_int32 *pmax_trans,
1176 l_int32 *pmin_opaque)
1177{
1178l_int32 i, n, ntrans, max_trans, min_opaque, opaque_found;
1179RGBA_QUAD *cta;
1180
1181 PROCNAME("pixcmapCountNonOpaqueColors");
1182
1183 if (pntrans) *pntrans = 0;
1184 if (pmax_trans) *pmax_trans = -1;
1185 if (pmin_opaque) *pmin_opaque = 256;
1186 if (!cmap)
1187 return ERROR_INT("cmap not defined", procName, 1);
1188
1189 n = pixcmapGetCount(cmap);
1190 ntrans = 0;
1191 max_trans = -1;
1192 min_opaque = n;
1193 cta = (RGBA_QUAD *)cmap->array;
1194 opaque_found = FALSE;
1195 for (i = 0; i < n; i++) {
1196 if (cta[i].alpha != 255) {
1197 ntrans++;
1198 max_trans = i;
1199 } else if (opaque_found == FALSE) {
1200 opaque_found = TRUE;
1201 min_opaque = i;
1202 }
1203 }
1204 if (pntrans) *pntrans = ntrans;
1205 if (pmax_trans) *pmax_trans = max_trans;
1206 if (pmin_opaque) *pmin_opaque = min_opaque;
1207 return 0;
1208}
1209
1210
1219l_ok
1221 l_int32 *pblackwhite)
1222{
1223l_int32 val0, val1, hascolor;
1224RGBA_QUAD *cta;
1225
1226 PROCNAME("pixcmapIsBlackAndWhite");
1227
1228 if (!pblackwhite)
1229 return ERROR_INT("&blackwhite not defined", procName, 1);
1230 *pblackwhite = FALSE;
1231 if (!cmap)
1232 return ERROR_INT("cmap not defined", procName, 1);
1233 if (pixcmapGetCount(cmap) != 2)
1234 return 0;
1235
1236 pixcmapHasColor(cmap, &hascolor);
1237 if (hascolor) return 0;
1238
1239 cta = (RGBA_QUAD *)cmap->array;
1240 val0 = cta[0].red;
1241 val1 = cta[1].red;
1242 if ((val0 == 0 && val1 == 255) || (val0 == 255 && val1 == 0))
1243 *pblackwhite = TRUE;
1244 return 0;
1245}
1246
1247
1260l_ok
1262 l_int32 *pngray)
1263{
1264l_int32 n, i, rval, gval, bval, count;
1265l_int32 *array;
1266
1267 PROCNAME("pixcmapCountGrayColors");
1268
1269 if (!pngray)
1270 return ERROR_INT("&ngray not defined", procName, 1);
1271 *pngray = 0;
1272 if (!cmap)
1273 return ERROR_INT("cmap not defined", procName, 1);
1274
1275 array = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
1276 n = pixcmapGetCount(cmap);
1277 count = 0;
1278 for (i = 0; i < n; i++) {
1279 pixcmapGetColor(cmap, i, &rval, &gval, &bval);
1280 if ((rval == gval) && (rval == bval) && (array[rval] == 0)) {
1281 array[rval] = 1;
1282 count++;
1283 }
1284 }
1285
1286 LEPT_FREE(array);
1287 *pngray = count;
1288 return 0;
1289}
1290
1291
1301l_ok
1303 l_float32 rankval,
1304 l_int32 *pindex)
1305{
1306l_int32 n, i, rval, gval, bval, rankindex;
1307NUMA *na, *nasort;
1308
1309 PROCNAME("pixcmapGetRankIntensity");
1310
1311 if (!pindex)
1312 return ERROR_INT("&index not defined", procName, 1);
1313 *pindex = 0;
1314 if (!cmap)
1315 return ERROR_INT("cmap not defined", procName, 1);
1316 if (rankval < 0.0 || rankval > 1.0)
1317 return ERROR_INT("rankval not in [0.0 ... 1.0]", procName, 1);
1318
1319 n = pixcmapGetCount(cmap);
1320 na = numaCreate(n);
1321 for (i = 0; i < n; i++) {
1322 pixcmapGetColor(cmap, i, &rval, &gval, &bval);
1323 numaAddNumber(na, rval + gval + bval);
1324 }
1325 nasort = numaGetSortIndex(na, L_SORT_INCREASING);
1326 rankindex = (l_int32)(rankval * (n - 1) + 0.5);
1327 numaGetIValue(nasort, rankindex, pindex);
1328
1329 numaDestroy(&na);
1330 numaDestroy(&nasort);
1331 return 0;
1332}
1333
1334
1352l_ok
1354 l_int32 rval,
1355 l_int32 gval,
1356 l_int32 bval,
1357 l_int32 *pindex)
1358{
1359l_int32 i, n, delta, dist, mindist;
1360RGBA_QUAD *cta;
1361
1362 PROCNAME("pixcmapGetNearestIndex");
1363
1364 if (!pindex)
1365 return ERROR_INT("&index not defined", procName, 1);
1366 *pindex = UNDEF;
1367 if (!cmap)
1368 return ERROR_INT("cmap not defined", procName, 1);
1369
1370 if ((cta = (RGBA_QUAD *)cmap->array) == NULL)
1371 return ERROR_INT("cta not defined(!)", procName, 1);
1372 n = pixcmapGetCount(cmap);
1373
1374 mindist = 3 * 255 * 255 + 1;
1375 for (i = 0; i < n; i++) {
1376 delta = cta[i].red - rval;
1377 dist = delta * delta;
1378 delta = cta[i].green - gval;
1379 dist += delta * delta;
1380 delta = cta[i].blue - bval;
1381 dist += delta * delta;
1382 if (dist < mindist) {
1383 *pindex = i;
1384 if (dist == 0)
1385 break;
1386 mindist = dist;
1387 }
1388 }
1389
1390 return 0;
1391}
1392
1393
1410l_ok
1412 l_int32 val,
1413 l_int32 *pindex)
1414{
1415l_int32 i, n, dist, mindist;
1416RGBA_QUAD *cta;
1417
1418 PROCNAME("pixcmapGetNearestGrayIndex");
1419
1420 if (!pindex)
1421 return ERROR_INT("&index not defined", procName, 1);
1422 *pindex = 0;
1423 if (!cmap)
1424 return ERROR_INT("cmap not defined", procName, 1);
1425 if (val < 0 || val > 255)
1426 return ERROR_INT("val not in [0 ... 255]", procName, 1);
1427
1428 if ((cta = (RGBA_QUAD *)cmap->array) == NULL)
1429 return ERROR_INT("cta not defined(!)", procName, 1);
1430 n = pixcmapGetCount(cmap);
1431
1432 mindist = 256;
1433 for (i = 0; i < n; i++) {
1434 dist = cta[i].green - val;
1435 dist = L_ABS(dist);
1436 if (dist < mindist) {
1437 *pindex = i;
1438 if (dist == 0)
1439 break;
1440 mindist = dist;
1441 }
1442 }
1443
1444 return 0;
1445}
1446
1447
1463l_ok
1465 l_int32 index,
1466 l_int32 rval,
1467 l_int32 gval,
1468 l_int32 bval,
1469 l_int32 *pdist)
1470{
1471l_int32 n, delta, dist;
1472RGBA_QUAD *cta;
1473
1474 PROCNAME("pixcmapGetDistanceToColor");
1475
1476 if (!pdist)
1477 return ERROR_INT("&dist not defined", procName, 1);
1478 *pdist = UNDEF;
1479 if (!cmap)
1480 return ERROR_INT("cmap not defined", procName, 1);
1481 n = pixcmapGetCount(cmap);
1482 if (index >= n)
1483 return ERROR_INT("invalid index", procName, 1);
1484
1485 if ((cta = (RGBA_QUAD *)cmap->array) == NULL)
1486 return ERROR_INT("cta not defined(!)", procName, 1);
1487
1488 delta = cta[index].red - rval;
1489 dist = delta * delta;
1490 delta = cta[index].green - gval;
1491 dist += delta * delta;
1492 delta = cta[index].blue - bval;
1493 dist += delta * delta;
1494 *pdist = dist;
1495
1496 return 0;
1497}
1498
1499
1519l_ok
1521 l_int32 select,
1522 l_int32 *pminval,
1523 l_int32 *pmaxval,
1524 l_int32 *pminindex,
1525 l_int32 *pmaxindex)
1526{
1527l_int32 i, n, imin, imax, minval, maxval, rval, gval, bval, aveval;
1528
1529 PROCNAME("pixcmapGetRangeValues");
1530
1531 if (pminval) *pminval = UNDEF;
1532 if (pmaxval) *pmaxval = UNDEF;
1533 if (pminindex) *pminindex = UNDEF;
1534 if (pmaxindex) *pmaxindex = UNDEF;
1535 if (!pminval && !pmaxval && !pminindex && !pmaxindex)
1536 return ERROR_INT("no result requested", procName, 1);
1537 if (!cmap)
1538 return ERROR_INT("cmap not defined", procName, 1);
1539
1540 imin = UNDEF;
1541 imax = UNDEF;
1542 minval = 100000;
1543 maxval = -1;
1544 n = pixcmapGetCount(cmap);
1545 for (i = 0; i < n; i++) {
1546 pixcmapGetColor(cmap, i, &rval, &gval, &bval);
1547 if (select == L_SELECT_RED) {
1548 if (rval < minval) {
1549 minval = rval;
1550 imin = i;
1551 }
1552 if (rval > maxval) {
1553 maxval = rval;
1554 imax = i;
1555 }
1556 } else if (select == L_SELECT_GREEN) {
1557 if (gval < minval) {
1558 minval = gval;
1559 imin = i;
1560 }
1561 if (gval > maxval) {
1562 maxval = gval;
1563 imax = i;
1564 }
1565 } else if (select == L_SELECT_BLUE) {
1566 if (bval < minval) {
1567 minval = bval;
1568 imin = i;
1569 }
1570 if (bval > maxval) {
1571 maxval = bval;
1572 imax = i;
1573 }
1574 } else if (select == L_SELECT_AVERAGE) {
1575 aveval = (rval + gval + bval) / 3;
1576 if (aveval < minval) {
1577 minval = aveval;
1578 imin = i;
1579 }
1580 if (aveval > maxval) {
1581 maxval = aveval;
1582 imax = i;
1583 }
1584 } else {
1585 return ERROR_INT("invalid selection", procName, 1);
1586 }
1587 }
1588
1589 if (pminval) *pminval = minval;
1590 if (pmaxval) *pmaxval = maxval;
1591 if (pminindex) *pminindex = imin;
1592 if (pmaxindex) *pmaxindex = imax;
1593 return 0;
1594}
1595
1596
1597/*-------------------------------------------------------------*
1598 * Colormap conversion *
1599 *-------------------------------------------------------------*/
1613PIXCMAP *
1615{
1616l_int32 i, rval, gval, bval;
1617l_int32 *curve;
1618l_float32 invgamma, x;
1619PIXCMAP *cmap;
1620
1621 if (gamma <= 0.0) gamma = 1.0;
1622
1623 /* Generate curve for transition part of color map */
1624 curve = (l_int32 *)LEPT_CALLOC(64, sizeof(l_int32));
1625 invgamma = 1. / gamma;
1626 for (i = 0; i < 64; i++) {
1627 x = (l_float32)i / 64.;
1628 curve[i] = (l_int32)(255. * powf(x, invgamma) + 0.5);
1629 }
1630
1631 cmap = pixcmapCreate(8);
1632 for (i = 0; i < 256; i++) {
1633 if (i < 32) {
1634 rval = 0;
1635 gval = 0;
1636 bval = curve[i + 32];
1637 } else if (i < 96) { /* 32 - 95 */
1638 rval = 0;
1639 gval = curve[i - 32];
1640 bval = 255;
1641 } else if (i < 160) { /* 96 - 159 */
1642 rval = curve[i - 96];
1643 gval = 255;
1644 bval = curve[159 - i];
1645 } else if (i < 224) { /* 160 - 223 */
1646 rval = 255;
1647 gval = curve[223 - i];
1648 bval = 0;
1649 } else { /* 224 - 255 */
1650 rval = curve[287 - i];
1651 gval = 0;
1652 bval = 0;
1653 }
1654 pixcmapAddColor(cmap, rval, gval, bval);
1655 }
1656
1657 LEPT_FREE(curve);
1658 return cmap;
1659}
1660
1661
1677PIXCMAP *
1678pixcmapGrayToColor(l_uint32 color)
1679{
1680l_int32 i, rval, gval, bval;
1681PIXCMAP *cmap;
1682
1683 extractRGBValues(color, &rval, &gval, &bval);
1684 cmap = pixcmapCreate(8);
1685 for (i = 0; i < 256; i++) {
1686 pixcmapAddColor(cmap, rval + (i * (255 - rval)) / 255,
1687 gval + (i * (255 - gval)) / 255,
1688 bval + (i * (255 - bval)) / 255);
1689 }
1690
1691 return cmap;
1692}
1693
1694
1709PIXCMAP *
1711 l_float32 rwt,
1712 l_float32 gwt,
1713 l_float32 bwt)
1714{
1715l_int32 i, n, rval, gval, bval, val;
1716l_float32 sum;
1717PIXCMAP *cmapd;
1718
1719 PROCNAME("pixcmapColorToGray");
1720
1721 if (!cmaps)
1722 return (PIXCMAP *)ERROR_PTR("cmaps not defined", procName, NULL);
1723 if (rwt < 0.0 || gwt < 0.0 || bwt < 0.0)
1724 return (PIXCMAP *)ERROR_PTR("weights not all >= 0.0", procName, NULL);
1725
1726 /* Make sure the sum of weights is 1.0; otherwise, you can get
1727 * overflow in the gray value. */
1728 sum = rwt + gwt + bwt;
1729 if (sum == 0.0) {
1730 L_WARNING("all weights zero; setting equal to 1/3\n", procName);
1731 rwt = gwt = bwt = 0.33333;
1732 sum = 1.0;
1733 }
1734 if (L_ABS(sum - 1.0) > 0.0001) { /* maintain ratios with sum == 1.0 */
1735 L_WARNING("weights don't sum to 1; maintaining ratios\n", procName);
1736 rwt = rwt / sum;
1737 gwt = gwt / sum;
1738 bwt = bwt / sum;
1739 }
1740
1741 if ((cmapd = pixcmapCopy(cmaps)) == NULL)
1742 return (PIXCMAP *)ERROR_PTR("cmapd not made", procName, NULL);
1743 n = pixcmapGetCount(cmapd);
1744 for (i = 0; i < n; i++) {
1745 pixcmapGetColor(cmapd, i, &rval, &gval, &bval);
1746 val = (l_int32)(rwt * rval + gwt * gval + bwt * bval + 0.5);
1747 pixcmapResetColor(cmapd, i, val, val, val);
1748 }
1749
1750 return cmapd;
1751}
1752
1753
1766PIXCMAP *
1768{
1769l_int32 i, n, rval, gval, bval;
1770PIXCMAP *cmapd;
1771
1772 PROCNAME("pixcmapConvertTo4");
1773
1774 if (!cmaps)
1775 return (PIXCMAP *)ERROR_PTR("cmaps not defined", procName, NULL);
1776 if (pixcmapGetDepth(cmaps) != 2)
1777 return (PIXCMAP *)ERROR_PTR("cmaps not for 2 bpp pix", procName, NULL);
1778
1779 cmapd = pixcmapCreate(4);
1780 n = pixcmapGetCount(cmaps);
1781 for (i = 0; i < n; i++) {
1782 pixcmapGetColor(cmaps, i, &rval, &gval, &bval);
1783 pixcmapAddColor(cmapd, rval, gval, bval);
1784 }
1785 return cmapd;
1786}
1787
1788
1801PIXCMAP *
1803{
1804l_int32 i, n, depth, rval, gval, bval;
1805PIXCMAP *cmapd;
1806
1807 PROCNAME("pixcmapConvertTo8");
1808
1809 if (!cmaps)
1810 return (PIXCMAP *)ERROR_PTR("cmaps not defined", procName, NULL);
1811 depth = pixcmapGetDepth(cmaps);
1812 if (depth == 8) return pixcmapCopy(cmaps);
1813 if (depth != 2 && depth != 4)
1814 return (PIXCMAP *)ERROR_PTR("cmaps not 2 or 4 bpp", procName, NULL);
1815
1816 cmapd = pixcmapCreate(8);
1817 n = pixcmapGetCount(cmaps);
1818 for (i = 0; i < n; i++) {
1819 pixcmapGetColor(cmaps, i, &rval, &gval, &bval);
1820 pixcmapAddColor(cmapd, rval, gval, bval);
1821 }
1822 return cmapd;
1823}
1824
1825
1826/*-------------------------------------------------------------*
1827 * Colormap I/O *
1828 *-------------------------------------------------------------*/
1835PIXCMAP *
1836pixcmapRead(const char *filename)
1837{
1838FILE *fp;
1839PIXCMAP *cmap;
1840
1841 PROCNAME("pixcmapRead");
1842
1843 if (!filename)
1844 return (PIXCMAP *)ERROR_PTR("filename not defined", procName, NULL);
1845
1846 if ((fp = fopenReadStream(filename)) == NULL)
1847 return (PIXCMAP *)ERROR_PTR("stream not opened", procName, NULL);
1848 cmap = pixcmapReadStream(fp);
1849 fclose(fp);
1850 if (!cmap)
1851 return (PIXCMAP *)ERROR_PTR("cmap not read", procName, NULL);
1852 return cmap;
1853}
1854
1855
1862PIXCMAP *
1864{
1865l_int32 rval, gval, bval, aval, ignore;
1866l_int32 i, index, ret, depth, ncolors;
1867PIXCMAP *cmap;
1868
1869 PROCNAME("pixcmapReadStream");
1870
1871 if (!fp)
1872 return (PIXCMAP *)ERROR_PTR("stream not defined", procName, NULL);
1873
1874 ret = fscanf(fp, "\nPixcmap: depth = %d bpp; %d colors\n",
1875 &depth, &ncolors);
1876 if (ret != 2 ||
1877 (depth != 1 && depth != 2 && depth != 4 && depth != 8) ||
1878 (ncolors < 2 || ncolors > 256))
1879 return (PIXCMAP *)ERROR_PTR("invalid cmap size", procName, NULL);
1880 ignore = fscanf(fp, "Color R-val G-val B-val Alpha\n");
1881 ignore = fscanf(fp, "----------------------------------------\n");
1882
1883 if ((cmap = pixcmapCreate(depth)) == NULL)
1884 return (PIXCMAP *)ERROR_PTR("cmap not made", procName, NULL);
1885 for (i = 0; i < ncolors; i++) {
1886 if (fscanf(fp, "%3d %3d %3d %3d %3d\n",
1887 &index, &rval, &gval, &bval, &aval) != 5) {
1888 pixcmapDestroy(&cmap);
1889 return (PIXCMAP *)ERROR_PTR("invalid entry", procName, NULL);
1890 }
1891 pixcmapAddRGBA(cmap, rval, gval, bval, aval);
1892 }
1893 return cmap;
1894}
1895
1896
1904PIXCMAP *
1905pixcmapReadMem(const l_uint8 *data,
1906 size_t size)
1907{
1908FILE *fp;
1909PIXCMAP *cmap;
1910
1911 PROCNAME("pixcmapReadMem");
1912
1913 if (!data)
1914 return (PIXCMAP *)ERROR_PTR("data not defined", procName, NULL);
1915 if ((fp = fopenReadFromMemory(data, size)) == NULL)
1916 return (PIXCMAP *)ERROR_PTR("stream not opened", procName, NULL);
1917
1918 cmap = pixcmapReadStream(fp);
1919 fclose(fp);
1920 if (!cmap) L_ERROR("cmap not read\n", procName);
1921 return cmap;
1922}
1923
1924
1932l_ok
1933pixcmapWrite(const char *filename,
1934 const PIXCMAP *cmap)
1935{
1936l_int32 ret;
1937FILE *fp;
1938
1939 PROCNAME("pixcmapWrite");
1940
1941 if (!filename)
1942 return ERROR_INT("filename not defined", procName, 1);
1943 if (!cmap)
1944 return ERROR_INT("cmap not defined", procName, 1);
1945
1946 if ((fp = fopenWriteStream(filename, "w")) == NULL)
1947 return ERROR_INT("stream not opened", procName, 1);
1948 ret = pixcmapWriteStream(fp, cmap);
1949 fclose(fp);
1950 if (ret)
1951 return ERROR_INT("cmap not written to stream", procName, 1);
1952 return 0;
1953}
1954
1955
1956
1964l_ok
1966 const PIXCMAP *cmap)
1967{
1968l_int32 *rmap, *gmap, *bmap, *amap;
1969l_int32 i;
1970
1971 PROCNAME("pixcmapWriteStream");
1972
1973 if (!fp)
1974 return ERROR_INT("stream not defined", procName, 1);
1975 if (!cmap)
1976 return ERROR_INT("cmap not defined", procName, 1);
1977
1978 if (pixcmapToArrays(cmap, &rmap, &gmap, &bmap, &amap))
1979 return ERROR_INT("colormap arrays not made", procName, 1);
1980
1981 fprintf(fp, "\nPixcmap: depth = %d bpp; %d colors\n", cmap->depth, cmap->n);
1982 fprintf(fp, "Color R-val G-val B-val Alpha\n");
1983 fprintf(fp, "----------------------------------------\n");
1984 for (i = 0; i < cmap->n; i++)
1985 fprintf(fp, "%3d %3d %3d %3d %3d\n",
1986 i, rmap[i], gmap[i], bmap[i], amap[i]);
1987 fprintf(fp, "\n");
1988
1989 LEPT_FREE(rmap);
1990 LEPT_FREE(gmap);
1991 LEPT_FREE(bmap);
1992 LEPT_FREE(amap);
1993 return 0;
1994}
1995
1996
2010l_ok
2011pixcmapWriteMem(l_uint8 **pdata,
2012 size_t *psize,
2013 const PIXCMAP *cmap)
2014{
2015l_int32 ret;
2016FILE *fp;
2017
2018 PROCNAME("pixcmapWriteMem");
2019
2020 if (pdata) *pdata = NULL;
2021 if (psize) *psize = 0;
2022 if (!pdata)
2023 return ERROR_INT("&data not defined", procName, 1);
2024 if (!psize)
2025 return ERROR_INT("&size not defined", procName, 1);
2026 if (!cmap)
2027 return ERROR_INT("cmap not defined", procName, 1);
2028
2029#if HAVE_FMEMOPEN
2030 if ((fp = open_memstream((char **)pdata, psize)) == NULL)
2031 return ERROR_INT("stream not opened", procName, 1);
2032 ret = pixcmapWriteStream(fp, cmap);
2033 fputc('\0', fp);
2034 fclose(fp);
2035 *psize = *psize - 1;
2036#else
2037 L_INFO("work-around: writing to a temp file\n", procName);
2038 #ifdef _WIN32
2039 if ((fp = fopenWriteWinTempfile()) == NULL)
2040 return ERROR_INT("tmpfile stream not opened", procName, 1);
2041 #else
2042 if ((fp = tmpfile()) == NULL)
2043 return ERROR_INT("tmpfile stream not opened", procName, 1);
2044 #endif /* _WIN32 */
2045 ret = pixcmapWriteStream(fp, cmap);
2046 rewind(fp);
2047 *pdata = l_binaryReadStream(fp, psize);
2048 fclose(fp);
2049#endif /* HAVE_FMEMOPEN */
2050 return ret;
2051}
2052
2053
2054/*----------------------------------------------------------------------*
2055 * Extract colormap arrays and serialization *
2056 *----------------------------------------------------------------------*/
2067l_ok
2069 l_int32 **prmap,
2070 l_int32 **pgmap,
2071 l_int32 **pbmap,
2072 l_int32 **pamap)
2073{
2074l_int32 *rmap, *gmap, *bmap, *amap;
2075l_int32 i, ncolors;
2076RGBA_QUAD *cta;
2077
2078 PROCNAME("pixcmapToArrays");
2079
2080 if (!prmap || !pgmap || !pbmap)
2081 return ERROR_INT("&rmap, &gmap, &bmap not all defined", procName, 1);
2082 *prmap = *pgmap = *pbmap = NULL;
2083 if (pamap) *pamap = NULL;
2084 if (!cmap)
2085 return ERROR_INT("cmap not defined", procName, 1);
2086
2087 ncolors = pixcmapGetCount(cmap);
2088 rmap = (l_int32 *)LEPT_CALLOC(ncolors, sizeof(l_int32));
2089 gmap = (l_int32 *)LEPT_CALLOC(ncolors, sizeof(l_int32));
2090 bmap = (l_int32 *)LEPT_CALLOC(ncolors, sizeof(l_int32));
2091 *prmap = rmap;
2092 *pgmap = gmap;
2093 *pbmap = bmap;
2094 if (pamap) {
2095 amap = (l_int32 *)LEPT_CALLOC(ncolors, sizeof(l_int32));
2096 *pamap = amap;
2097 }
2098
2099 cta = (RGBA_QUAD *)cmap->array;
2100 for (i = 0; i < ncolors; i++) {
2101 rmap[i] = cta[i].red;
2102 gmap[i] = cta[i].green;
2103 bmap[i] = cta[i].blue;
2104 if (pamap)
2105 amap[i] = cta[i].alpha;
2106 }
2107
2108 return 0;
2109}
2110
2111
2120l_ok
2122 l_uint32 **ptab,
2123 l_int32 *pncolors)
2124{
2125l_int32 i, ncolors, rval, gval, bval, aval;
2126l_uint32 *tab;
2127
2128 PROCNAME("pixcmapToRGBTable");
2129
2130 if (!ptab)
2131 return ERROR_INT("&tab not defined", procName, 1);
2132 *ptab = NULL;
2133 if (!cmap)
2134 return ERROR_INT("cmap not defined", procName, 1);
2135
2136 ncolors = pixcmapGetCount(cmap);
2137 if (pncolors) *pncolors = ncolors;
2138 tab = (l_uint32 *)LEPT_CALLOC(ncolors, sizeof(l_uint32));
2139 *ptab = tab;
2140
2141 for (i = 0; i < ncolors; i++) {
2142 pixcmapGetRGBA(cmap, i, &rval, &gval, &bval, &aval);
2143 composeRGBAPixel(rval, gval, bval, aval, &tab[i]);
2144 }
2145 return 0;
2146}
2147
2148
2163l_ok
2165 l_int32 cpc,
2166 l_int32 *pncolors,
2167 l_uint8 **pdata)
2168{
2169l_int32 i, ncolors, rval, gval, bval, aval;
2170l_uint8 *data;
2171
2172 PROCNAME("pixcmapSerializeToMemory");
2173
2174 if (!pdata)
2175 return ERROR_INT("&data not defined", procName, 1);
2176 *pdata = NULL;
2177 if (!pncolors)
2178 return ERROR_INT("&ncolors not defined", procName, 1);
2179 *pncolors = 0;
2180 if (!cmap)
2181 return ERROR_INT("cmap not defined", procName, 1);
2182 if (cpc != 3 && cpc != 4)
2183 return ERROR_INT("cpc not 3 or 4", procName, 1);
2184
2185 ncolors = pixcmapGetCount(cmap);
2186 *pncolors = ncolors;
2187 data = (l_uint8 *)LEPT_CALLOC((size_t)cpc * ncolors, sizeof(l_uint8));
2188 *pdata = data;
2189
2190 for (i = 0; i < ncolors; i++) {
2191 pixcmapGetRGBA(cmap, i, &rval, &gval, &bval, &aval);
2192 data[cpc * i] = rval;
2193 data[cpc * i + 1] = gval;
2194 data[cpc * i + 2] = bval;
2195 if (cpc == 4)
2196 data[cpc * i + 3] = aval;
2197 }
2198 return 0;
2199}
2200
2201
2210PIXCMAP *
2212 l_int32 cpc,
2213 l_int32 ncolors)
2214{
2215l_int32 i, d, rval, gval, bval, aval;
2216PIXCMAP *cmap;
2217
2218 PROCNAME("pixcmapDeserializeFromMemory");
2219
2220 if (!data)
2221 return (PIXCMAP *)ERROR_PTR("data not defined", procName, NULL);
2222 if (cpc != 3 && cpc != 4)
2223 return (PIXCMAP *)ERROR_PTR("cpc not 3 or 4", procName, NULL);
2224 if (ncolors <= 0)
2225 return (PIXCMAP *)ERROR_PTR("no entries", procName, NULL);
2226 if (ncolors > 256)
2227 return (PIXCMAP *)ERROR_PTR("ncolors > 256", procName, NULL);
2228
2229 if (ncolors > 16)
2230 d = 8;
2231 else if (ncolors > 4)
2232 d = 4;
2233 else if (ncolors > 2)
2234 d = 2;
2235 else
2236 d = 1;
2237 cmap = pixcmapCreate(d);
2238 for (i = 0; i < ncolors; i++) {
2239 rval = data[cpc * i];
2240 gval = data[cpc * i + 1];
2241 bval = data[cpc * i + 2];
2242 if (cpc == 4)
2243 aval = data[cpc * i + 3];
2244 else
2245 aval = 255; /* opaque */
2246 pixcmapAddRGBA(cmap, rval, gval, bval, aval);
2247 }
2248
2249 return cmap;
2250}
2251
2252
2271char *
2273 l_int32 ncolors)
2274{
2275l_int32 i, j, hexbytes;
2276char *hexdata = NULL;
2277char buf[4];
2278
2279 PROCNAME("pixcmapConvertToHex");
2280
2281 if (!data)
2282 return (char *)ERROR_PTR("data not defined", procName, NULL);
2283 if (ncolors < 1)
2284 return (char *)ERROR_PTR("no colors", procName, NULL);
2285
2286 hexbytes = 2 + (2 * 3 + 1) * ncolors + 2;
2287 hexdata = (char *)LEPT_CALLOC(hexbytes, sizeof(char));
2288 hexdata[0] = '<';
2289 hexdata[1] = ' ';
2290
2291 for (i = 0; i < ncolors; i++) {
2292 j = 2 + (2 * 3 + 1) * i;
2293 snprintf(buf, sizeof(buf), "%02x", data[3 * i]);
2294 hexdata[j] = buf[0];
2295 hexdata[j + 1] = buf[1];
2296 snprintf(buf, sizeof(buf), "%02x", data[3 * i + 1]);
2297 hexdata[j + 2] = buf[0];
2298 hexdata[j + 3] = buf[1];
2299 snprintf(buf, sizeof(buf), "%02x", data[3 * i + 2]);
2300 hexdata[j + 4] = buf[0];
2301 hexdata[j + 5] = buf[1];
2302 hexdata[j + 6] = ' ';
2303 }
2304 hexdata[j + 7] = '>';
2305 hexdata[j + 8] = '\0';
2306 return hexdata;
2307}
2308
2309
2310/*-------------------------------------------------------------*
2311 * Colormap transforms *
2312 *-------------------------------------------------------------*/
2329l_ok
2331 l_float32 gamma,
2332 l_int32 minval,
2333 l_int32 maxval)
2334{
2335l_int32 rval, gval, bval, trval, tgval, tbval, i, ncolors;
2336NUMA *nag;
2337
2338 PROCNAME("pixcmapGammaTRC");
2339
2340 if (!cmap)
2341 return ERROR_INT("cmap not defined", procName, 1);
2342 if (gamma <= 0.0) {
2343 L_WARNING("gamma must be > 0.0; setting to 1.0\n", procName);
2344 gamma = 1.0;
2345 }
2346 if (minval >= maxval)
2347 return ERROR_INT("minval not < maxval", procName, 1);
2348
2349 if (gamma == 1.0 && minval == 0 && maxval == 255) /* no-op */
2350 return 0;
2351
2352 if ((nag = numaGammaTRC(gamma, minval, maxval)) == NULL)
2353 return ERROR_INT("nag not made", procName, 1);
2354
2355 ncolors = pixcmapGetCount(cmap);
2356 for (i = 0; i < ncolors; i++) {
2357 pixcmapGetColor(cmap, i, &rval, &gval, &bval);
2358 numaGetIValue(nag, rval, &trval);
2359 numaGetIValue(nag, gval, &tgval);
2360 numaGetIValue(nag, bval, &tbval);
2361 pixcmapResetColor(cmap, i, trval, tgval, tbval);
2362 }
2363
2364 numaDestroy(&nag);
2365 return 0;
2366}
2367
2368
2384l_ok
2386 l_float32 factor)
2387{
2388l_int32 i, ncolors, rval, gval, bval, trval, tgval, tbval;
2389NUMA *nac;
2390
2391 PROCNAME("pixcmapContrastTRC");
2392
2393 if (!cmap)
2394 return ERROR_INT("cmap not defined", procName, 1);
2395 if (factor < 0.0) {
2396 L_WARNING("factor must be >= 0.0; setting to 0.0\n", procName);
2397 factor = 0.0;
2398 }
2399
2400 if ((nac = numaContrastTRC(factor)) == NULL)
2401 return ERROR_INT("nac not made", procName, 1);
2402
2403 ncolors = pixcmapGetCount(cmap);
2404 for (i = 0; i < ncolors; i++) {
2405 pixcmapGetColor(cmap, i, &rval, &gval, &bval);
2406 numaGetIValue(nac, rval, &trval);
2407 numaGetIValue(nac, gval, &tgval);
2408 numaGetIValue(nac, bval, &tbval);
2409 pixcmapResetColor(cmap, i, trval, tgval, tbval);
2410 }
2411
2412 numaDestroy(&nac);
2413 return 0;
2414}
2415
2416
2436l_ok
2438 l_float32 fraction)
2439{
2440l_int32 i, ncolors, rval, gval, bval;
2441
2442 PROCNAME("pixcmapShiftIntensity");
2443
2444 if (!cmap)
2445 return ERROR_INT("cmap not defined", procName, 1);
2446 if (fraction < -1.0 || fraction > 1.0)
2447 return ERROR_INT("fraction not in [-1.0, 1.0]", procName, 1);
2448
2449 ncolors = pixcmapGetCount(cmap);
2450 for (i = 0; i < ncolors; i++) {
2451 pixcmapGetColor(cmap, i, &rval, &gval, &bval);
2452 if (fraction < 0.0)
2453 pixcmapResetColor(cmap, i,
2454 (l_int32)((1.0 + fraction) * rval),
2455 (l_int32)((1.0 + fraction) * gval),
2456 (l_int32)((1.0 + fraction) * bval));
2457 else
2458 pixcmapResetColor(cmap, i,
2459 rval + (l_int32)(fraction * (255 - rval)),
2460 gval + (l_int32)(fraction * (255 - gval)),
2461 bval + (l_int32)(fraction * (255 - bval)));
2462 }
2463
2464 return 0;
2465}
2466
2467
2486l_ok
2488 l_uint32 srcval,
2489 l_uint32 dstval)
2490{
2491l_int32 i, ncolors, rval, gval, bval;
2492l_uint32 newval;
2493
2494 PROCNAME("pixcmapShiftByComponent");
2495
2496 if (!cmap)
2497 return ERROR_INT("cmap not defined", procName, 1);
2498
2499 ncolors = pixcmapGetCount(cmap);
2500 for (i = 0; i < ncolors; i++) {
2501 pixcmapGetColor(cmap, i, &rval, &gval, &bval);
2502 pixelShiftByComponent(rval, gval, bval, srcval, dstval, &newval);
2503 extractRGBValues(newval, &rval, &gval, &bval);
2504 pixcmapResetColor(cmap, i, rval, gval, bval);
2505 }
2506
2507 return 0;
2508}
l_ok pixelShiftByComponent(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 srcval, l_uint32 dstval, l_uint32 *ppixel)
pixelShiftByComponent()
Definition: coloring.c:968
l_ok pixcmapSetAlpha(PIXCMAP *cmap, l_int32 index, l_int32 aval)
pixcmapSetAlpha()
Definition: colormap.c:1007
void pixcmapDestroy(PIXCMAP **pcmap)
pixcmapDestroy()
Definition: colormap.c:279
l_ok pixcmapContrastTRC(PIXCMAP *cmap, l_float32 factor)
pixcmapContrastTRC()
Definition: colormap.c:2385
l_ok pixcmapHasColor(PIXCMAP *cmap, l_int32 *pcolor)
pixcmapHasColor()
Definition: colormap.c:1075
l_int32 pixcmapGetCount(const PIXCMAP *cmap)
pixcmapGetCount()
Definition: colormap.c:708
PIXCMAP * pixcmapCreateRandom(l_int32 depth, l_int32 hasblack, l_int32 haswhite)
pixcmapCreateRandom()
Definition: colormap.c:172
l_ok pixcmapGetDistanceToColor(PIXCMAP *cmap, l_int32 index, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pdist)
pixcmapGetDistanceToColor()
Definition: colormap.c:1464
l_ok pixcmapSetBlackAndWhite(PIXCMAP *cmap, l_int32 setblack, l_int32 setwhite)
pixcmapSetBlackAndWhite()
Definition: colormap.c:678
l_ok pixcmapIsValid(const PIXCMAP *cmap, PIX *pix, l_int32 *pvalid)
pixcmapIsValid()
Definition: colormap.c:317
PIXCMAP * pixcmapCopy(const PIXCMAP *cmaps)
pixcmapCopy()
Definition: colormap.c:248
l_ok pixcmapWriteStream(FILE *fp, const PIXCMAP *cmap)
pixcmapWriteStream()
Definition: colormap.c:1965
l_ok pixcmapAddNewColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pindex)
pixcmapAddNewColor()
Definition: colormap.c:496
l_ok pixcmapGetNearestIndex(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pindex)
pixcmapGetNearestIndex()
Definition: colormap.c:1353
PIXCMAP * pixcmapGrayToColor(l_uint32 color)
pixcmapGrayToColor()
Definition: colormap.c:1678
l_ok pixcmapGetColor32(PIXCMAP *cmap, l_int32 index, l_uint32 *pval32)
pixcmapGetColor32()
Definition: colormap.c:864
l_ok pixcmapSerializeToMemory(PIXCMAP *cmap, l_int32 cpc, l_int32 *pncolors, l_uint8 **pdata)
pixcmapSerializeToMemory()
Definition: colormap.c:2164
l_ok pixcmapWrite(const char *filename, const PIXCMAP *cmap)
pixcmapWrite()
Definition: colormap.c:1933
PIXCMAP * pixcmapCreate(l_int32 depth)
pixcmapCreate()
Definition: colormap.c:125
l_ok pixcmapWriteMem(l_uint8 **pdata, size_t *psize, const PIXCMAP *cmap)
pixcmapWriteMem()
Definition: colormap.c:2011
l_ok pixcmapAddRGBA(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 aval)
pixcmapAddRGBA()
Definition: colormap.c:452
PIXCMAP * pixcmapDeserializeFromMemory(l_uint8 *data, l_int32 cpc, l_int32 ncolors)
pixcmapDeserializeFromMemory()
Definition: colormap.c:2211
l_ok pixcmapAddBlackOrWhite(PIXCMAP *cmap, l_int32 color, l_int32 *pindex)
pixcmapAddBlackOrWhite()
Definition: colormap.c:639
PIXCMAP * pixcmapCreateLinear(l_int32 d, l_int32 nlevels)
pixcmapCreateLinear()
Definition: colormap.c:218
l_ok pixcmapAddNearestColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pindex)
pixcmapAddNearestColor()
Definition: colormap.c:545
PIXCMAP * pixcmapColorToGray(PIXCMAP *cmaps, l_float32 rwt, l_float32 gwt, l_float32 bwt)
pixcmapColorToGray()
Definition: colormap.c:1710
l_ok pixcmapResetColor(PIXCMAP *cmap, l_int32 index, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapResetColor()
Definition: colormap.c:966
l_ok pixcmapGammaTRC(PIXCMAP *cmap, l_float32 gamma, l_int32 minval, l_int32 maxval)
pixcmapGammaTRC()
Definition: colormap.c:2330
PIXCMAP * pixcmapConvertTo4(PIXCMAP *cmaps)
pixcmapConvertTo4()
Definition: colormap.c:1767
l_int32 pixcmapGetIndex(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pindex)
pixcmapGetIndex()
Definition: colormap.c:1036
PIXCMAP * pixcmapReadStream(FILE *fp)
pixcmapReadStream()
Definition: colormap.c:1863
l_ok pixcmapCountGrayColors(PIXCMAP *cmap, l_int32 *pngray)
pixcmapCountGrayColors()
Definition: colormap.c:1261
l_int32 pixcmapGetDepth(PIXCMAP *cmap)
pixcmapGetDepth()
Definition: colormap.c:742
l_ok pixcmapNonOpaqueColorsInfo(PIXCMAP *cmap, l_int32 *pntrans, l_int32 *pmax_trans, l_int32 *pmin_opaque)
pixcmapNonOpaqueColorsInfo()
Definition: colormap.c:1173
l_ok pixcmapUsableColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pusable)
pixcmapUsableColor()
Definition: colormap.c:592
l_ok pixcmapShiftIntensity(PIXCMAP *cmap, l_float32 fraction)
pixcmapShiftIntensity()
Definition: colormap.c:2437
l_ok pixcmapGetColor(PIXCMAP *cmap, l_int32 index, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
pixcmapGetColor()
Definition: colormap.c:824
l_ok pixcmapIsOpaque(PIXCMAP *cmap, l_int32 *popaque)
pixcmapIsOpaque()
Definition: colormap.c:1114
l_ok pixcmapGetMinDepth(PIXCMAP *cmap, l_int32 *pmindepth)
pixcmapGetMinDepth()
Definition: colormap.c:765
PIXCMAP * pixcmapGrayToFalseColor(l_float32 gamma)
pixcmapGrayToFalseColor()
Definition: colormap.c:1614
l_int32 pixcmapGetFreeCount(PIXCMAP *cmap)
pixcmapGetFreeCount()
Definition: colormap.c:725
l_ok pixcmapGetRangeValues(PIXCMAP *cmap, l_int32 select, l_int32 *pminval, l_int32 *pmaxval, l_int32 *pminindex, l_int32 *pmaxindex)
pixcmapGetRangeValues()
Definition: colormap.c:1520
l_ok pixcmapClear(PIXCMAP *cmap)
pixcmapClear()
Definition: colormap.c:801
char * pixcmapConvertToHex(l_uint8 *data, l_int32 ncolors)
pixcmapConvertToHex()
Definition: colormap.c:2272
l_ok pixcmapGetRankIntensity(PIXCMAP *cmap, l_float32 rankval, l_int32 *pindex)
pixcmapGetRankIntensity()
Definition: colormap.c:1302
PIXCMAP * pixcmapReadMem(const l_uint8 *data, size_t size)
pixcmapReadMem()
Definition: colormap.c:1905
l_ok pixcmapGetRGBA(PIXCMAP *cmap, l_int32 index, l_int32 *prval, l_int32 *pgval, l_int32 *pbval, l_int32 *paval)
pixcmapGetRGBA()
Definition: colormap.c:892
PIXCMAP * pixcmapConvertTo8(PIXCMAP *cmaps)
pixcmapConvertTo8()
Definition: colormap.c:1802
l_ok pixcmapToArrays(const PIXCMAP *cmap, l_int32 **prmap, l_int32 **pgmap, l_int32 **pbmap, l_int32 **pamap)
pixcmapToArrays()
Definition: colormap.c:2068
l_ok pixcmapShiftByComponent(PIXCMAP *cmap, l_uint32 srcval, l_uint32 dstval)
pixcmapShiftByComponent()
Definition: colormap.c:2487
l_ok pixcmapIsBlackAndWhite(PIXCMAP *cmap, l_int32 *pblackwhite)
pixcmapIsBlackAndWhite()
Definition: colormap.c:1220
PIXCMAP * pixcmapRead(const char *filename)
pixcmapRead()
Definition: colormap.c:1836
l_ok pixcmapAddColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapAddColor()
Definition: colormap.c:414
l_ok pixcmapGetNearestGrayIndex(PIXCMAP *cmap, l_int32 val, l_int32 *pindex)
pixcmapGetNearestGrayIndex()
Definition: colormap.c:1411
l_ok pixcmapToRGBTable(PIXCMAP *cmap, l_uint32 **ptab, l_int32 *pncolors)
pixcmapToRGBTable()
Definition: colormap.c:2121
l_ok pixcmapGetRGBA32(PIXCMAP *cmap, l_int32 index, l_uint32 *pval32)
pixcmapGetRGBA32()
Definition: colormap.c:930
NUMA * numaGammaTRC(l_float32 gamma, l_int32 minval, l_int32 maxval)
numaGammaTRC()
Definition: enhance.c:369
NUMA * numaContrastTRC(l_float32 factor)
numaContrastTRC()
Definition: enhance.c:560
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:478
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:366
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:754
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:194
NUMA * numaGetSortIndex(NUMA *na, l_int32 sortorder)
numaGetSortIndex()
Definition: numafunc1.c:2751
l_ok composeRGBAPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_int32 aval, l_uint32 *ppixel)
composeRGBAPixel()
Definition: pix2.c:2783
void extractRGBValues(l_uint32 pixel, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
extractRGBValues()
Definition: pix2.c:2820
l_ok pixGetMaxColorIndex(PIX *pixs, l_int32 *pmaxindex)
pixGetMaxColorIndex()
Definition: pix4.c:2427
@ L_SELECT_GREEN
Definition: pix.h:823
@ L_SELECT_BLUE
Definition: pix.h:824
@ L_SELECT_AVERAGE
Definition: pix.h:827
@ L_SELECT_RED
Definition: pix.h:822
@ L_SORT_INCREASING
Definition: pix.h:729
Definition: array.h:71
void * array
Definition: pix.h:161
l_int32 n
Definition: pix.h:164
l_int32 depth
Definition: pix.h:162
l_int32 nalloc
Definition: pix.h:163
Definition: pix.h:139
Definition: pix.h:174
l_uint8 alpha
Definition: pix.h:178
l_uint8 green
Definition: pix.h:176
l_uint8 blue
Definition: pix.h:175
l_uint8 red
Definition: pix.h:177
FILE * fopenWriteWinTempfile(void)
fopenWriteWinTempfile()
Definition: utils2.c:2055
FILE * fopenWriteStream(const char *filename, const char *modestring)
fopenWriteStream()
Definition: utils2.c:1975
FILE * fopenReadFromMemory(const l_uint8 *data, size_t size)
fopenReadFromMemory()
Definition: utils2.c:2009
FILE * fopenReadStream(const char *filename)
fopenReadStream()
Definition: utils2.c:1932
l_uint8 * l_binaryReadStream(FILE *fp, size_t *pnbytes)
l_binaryReadStream()
Definition: utils2.c:1402