Leptonica  1.83.1
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 #include "pix_internal.h"
115 
116 /*-------------------------------------------------------------*
117  * Colormap creation and addition *
118  *-------------------------------------------------------------*/
125 PIXCMAP *
126 pixcmapCreate(l_int32 depth)
127 {
128 RGBA_QUAD *cta;
129 PIXCMAP *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 
170 PIXCMAP *
171 pixcmapCreateRandom(l_int32 depth,
172  l_int32 hasblack,
173  l_int32 haswhite)
174 {
175 l_int32 ncolors, i;
176 l_int32 red[256], green[256], blue[256];
177 PIXCMAP *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 
214 PIXCMAP *
216  l_int32 nlevels)
217 {
218 l_int32 maxlevels, i, val;
219 PIXCMAP *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 
242 PIXCMAP *
243 pixcmapCopy(const PIXCMAP *cmaps)
244 {
245 l_int32 nbytes, valid;
246 PIXCMAP *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 
271 void
273 {
274 PIXCMAP *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 
307 l_ok
309  PIX *pix,
310  l_int32 *pvalid)
311 {
312 l_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 
402 l_ok
404  l_int32 rval,
405  l_int32 gval,
406  l_int32 bval)
407 {
408 RGBA_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 
438 l_ok
440  l_int32 rval,
441  l_int32 gval,
442  l_int32 bval,
443  l_int32 aval)
444 {
445 RGBA_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 
480 l_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 
527 l_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 
572 l_ok
574  l_int32 rval,
575  l_int32 gval,
576  l_int32 bval,
577  l_int32 *pusable)
578 {
579 l_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 
617 l_ok
619  l_int32 color,
620  l_int32 *pindex)
621 {
622 l_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 
654 l_ok
656  l_int32 setblack,
657  l_int32 setwhite)
658 {
659 l_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 
682 l_int32
684 {
685  if (!cmap)
686  return ERROR_INT("cmap not defined", __func__, 0);
687  return cmap->n;
688 }
689 
690 
697 l_int32
699 {
700  if (!cmap)
701  return ERROR_INT("cmap not defined", __func__, 0);
702  return (cmap->nalloc - cmap->n);
703 }
704 
705 
712 l_int32
714 {
715  if (!cmap)
716  return ERROR_INT("cmap not defined", __func__, 0);
717  return cmap->depth;
718 }
719 
720 
733 l_ok
735  l_int32 *pmindepth)
736 {
737 l_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 
767 l_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  *-------------------------------------------------------------*/
788 l_ok
790  l_int32 index,
791  l_int32 *prval,
792  l_int32 *pgval,
793  l_int32 *pbval)
794 {
795 RGBA_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 
826 l_ok
828  l_int32 index,
829  l_uint32 *pval32)
830 {
831 l_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 
852 l_ok
854  l_int32 index,
855  l_int32 *prval,
856  l_int32 *pgval,
857  l_int32 *pbval,
858  l_int32 *paval)
859 {
860 RGBA_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 
888 l_ok
890  l_int32 index,
891  l_uint32 *pval32)
892 {
893 l_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 
922 l_ok
924  l_int32 index,
925  l_int32 rval,
926  l_int32 gval,
927  l_int32 bval)
928 {
929 RGBA_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 
961 l_ok
963  l_int32 index,
964  l_int32 aval)
965 {
966 RGBA_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 
988 l_int32
990  l_int32 rval,
991  l_int32 gval,
992  l_int32 bval,
993  l_int32 *pindex)
994 {
995 l_int32 n, i;
996 RGBA_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 
1025 l_ok
1027  l_int32 *pcolor)
1028 {
1029 l_int32 n, i;
1030 l_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 
1062 l_ok
1064  l_int32 *popaque)
1065 {
1066 l_int32 i, n;
1067 RGBA_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 
1119 l_ok
1121  l_int32 *pntrans,
1122  l_int32 *pmax_trans,
1123  l_int32 *pmin_opaque)
1124 {
1125 l_int32 i, n, ntrans, max_trans, min_opaque, opaque_found;
1126 RGBA_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 
1164 l_ok
1166  l_int32 *pblackwhite)
1167 {
1168 l_int32 val0, val1, hascolor;
1169 RGBA_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 
1203 l_ok
1205  l_int32 *pngray)
1206 {
1207 l_int32 n, i, rval, gval, bval, count;
1208 l_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 
1242 l_ok
1244  l_float32 rankval,
1245  l_int32 *pindex)
1246 {
1247 l_int32 n, i, rval, gval, bval, rankindex;
1248 NUMA *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 
1291 l_ok
1293  l_int32 rval,
1294  l_int32 gval,
1295  l_int32 bval,
1296  l_int32 *pindex)
1297 {
1298 l_int32 i, n, delta, dist, mindist;
1299 RGBA_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 
1347 l_ok
1349  l_int32 val,
1350  l_int32 *pindex)
1351 {
1352 l_int32 i, n, dist, mindist;
1353 RGBA_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 
1398 l_ok
1400  l_int32 index,
1401  l_int32 rval,
1402  l_int32 gval,
1403  l_int32 bval,
1404  l_int32 *pdist)
1405 {
1406 l_int32 n, delta, dist;
1407 RGBA_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 
1452 l_ok
1454  l_int32 select,
1455  l_int32 *pminval,
1456  l_int32 *pmaxval,
1457  l_int32 *pminindex,
1458  l_int32 *pmaxindex)
1459 {
1460 l_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  *-------------------------------------------------------------*/
1544 PIXCMAP *
1545 pixcmapGrayToFalseColor(l_float32 gamma)
1546 {
1547 l_int32 i, rval, gval, bval;
1548 l_int32 *curve;
1549 l_float32 invgamma, x;
1550 PIXCMAP *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 
1608 PIXCMAP *
1609 pixcmapGrayToColor(l_uint32 color)
1610 {
1611 l_int32 i, rval, gval, bval;
1612 PIXCMAP *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 
1640 PIXCMAP *
1642  l_float32 rwt,
1643  l_float32 gwt,
1644  l_float32 bwt)
1645 {
1646 l_int32 i, n, rval, gval, bval, val;
1647 l_float32 sum;
1648 PIXCMAP *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.33333;
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 
1695 PIXCMAP *
1697 {
1698 l_int32 i, n, rval, gval, bval;
1699 PIXCMAP *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 
1728 PIXCMAP *
1730 {
1731 l_int32 i, n, depth, rval, gval, bval;
1732 PIXCMAP *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  *-------------------------------------------------------------*/
1760 PIXCMAP *
1761 pixcmapRead(const char *filename)
1762 {
1763 FILE *fp;
1764 PIXCMAP *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("stream not opened", __func__, NULL);
1771  cmap = pixcmapReadStream(fp);
1772  fclose(fp);
1773  if (!cmap)
1774  return (PIXCMAP *)ERROR_PTR("cmap not read", __func__, NULL);
1775  return cmap;
1776 }
1777 
1778 
1785 PIXCMAP *
1787 {
1788 l_int32 rval, gval, bval, aval, ignore;
1789 l_int32 i, index, ret, depth, ncolors;
1790 PIXCMAP *cmap;
1791 
1792  if (!fp)
1793  return (PIXCMAP *)ERROR_PTR("stream not defined", __func__, NULL);
1794 
1795  ret = fscanf(fp, "\nPixcmap: depth = %d bpp; %d colors\n",
1796  &depth, &ncolors);
1797  if (ret != 2 ||
1798  (depth != 1 && depth != 2 && depth != 4 && depth != 8) ||
1799  (ncolors < 2 || ncolors > 256))
1800  return (PIXCMAP *)ERROR_PTR("invalid cmap size", __func__, NULL);
1801  ignore = fscanf(fp, "Color R-val G-val B-val Alpha\n");
1802  ignore = fscanf(fp, "----------------------------------------\n");
1803 
1804  if ((cmap = pixcmapCreate(depth)) == NULL)
1805  return (PIXCMAP *)ERROR_PTR("cmap not made", __func__, NULL);
1806  for (i = 0; i < ncolors; i++) {
1807  if (fscanf(fp, "%3d %3d %3d %3d %3d\n",
1808  &index, &rval, &gval, &bval, &aval) != 5) {
1809  pixcmapDestroy(&cmap);
1810  return (PIXCMAP *)ERROR_PTR("invalid entry", __func__, NULL);
1811  }
1812  pixcmapAddRGBA(cmap, rval, gval, bval, aval);
1813  }
1814  return cmap;
1815 }
1816 
1817 
1825 PIXCMAP *
1826 pixcmapReadMem(const l_uint8 *data,
1827  size_t size)
1828 {
1829 FILE *fp;
1830 PIXCMAP *cmap;
1831 
1832  if (!data)
1833  return (PIXCMAP *)ERROR_PTR("data not defined", __func__, NULL);
1834  if ((fp = fopenReadFromMemory(data, size)) == NULL)
1835  return (PIXCMAP *)ERROR_PTR("stream not opened", __func__, NULL);
1836 
1837  cmap = pixcmapReadStream(fp);
1838  fclose(fp);
1839  if (!cmap) L_ERROR("cmap not read\n", __func__);
1840  return cmap;
1841 }
1842 
1843 
1851 l_ok
1852 pixcmapWrite(const char *filename,
1853  const PIXCMAP *cmap)
1854 {
1855 l_int32 ret;
1856 FILE *fp;
1857 
1858  if (!filename)
1859  return ERROR_INT("filename not defined", __func__, 1);
1860  if (!cmap)
1861  return ERROR_INT("cmap not defined", __func__, 1);
1862 
1863  if ((fp = fopenWriteStream(filename, "w")) == NULL)
1864  return ERROR_INT("stream not opened", __func__, 1);
1865  ret = pixcmapWriteStream(fp, cmap);
1866  fclose(fp);
1867  if (ret)
1868  return ERROR_INT("cmap not written to stream", __func__, 1);
1869  return 0;
1870 }
1871 
1872 
1873 
1881 l_ok
1883  const PIXCMAP *cmap)
1884 {
1885 l_int32 *rmap, *gmap, *bmap, *amap;
1886 l_int32 i;
1887 
1888  if (!fp)
1889  return ERROR_INT("stream not defined", __func__, 1);
1890  if (!cmap)
1891  return ERROR_INT("cmap not defined", __func__, 1);
1892 
1893  if (pixcmapToArrays(cmap, &rmap, &gmap, &bmap, &amap))
1894  return ERROR_INT("colormap arrays not made", __func__, 1);
1895 
1896  fprintf(fp, "\nPixcmap: depth = %d bpp; %d colors\n", cmap->depth, cmap->n);
1897  fprintf(fp, "Color R-val G-val B-val Alpha\n");
1898  fprintf(fp, "----------------------------------------\n");
1899  for (i = 0; i < cmap->n; i++)
1900  fprintf(fp, "%3d %3d %3d %3d %3d\n",
1901  i, rmap[i], gmap[i], bmap[i], amap[i]);
1902  fprintf(fp, "\n");
1903 
1904  LEPT_FREE(rmap);
1905  LEPT_FREE(gmap);
1906  LEPT_FREE(bmap);
1907  LEPT_FREE(amap);
1908  return 0;
1909 }
1910 
1911 
1925 l_ok
1926 pixcmapWriteMem(l_uint8 **pdata,
1927  size_t *psize,
1928  const PIXCMAP *cmap)
1929 {
1930 l_int32 ret;
1931 FILE *fp;
1932 
1933  if (pdata) *pdata = NULL;
1934  if (psize) *psize = 0;
1935  if (!pdata)
1936  return ERROR_INT("&data not defined", __func__, 1);
1937  if (!psize)
1938  return ERROR_INT("&size not defined", __func__, 1);
1939  if (!cmap)
1940  return ERROR_INT("cmap not defined", __func__, 1);
1941 
1942 #if HAVE_FMEMOPEN
1943  if ((fp = open_memstream((char **)pdata, psize)) == NULL)
1944  return ERROR_INT("stream not opened", __func__, 1);
1945  ret = pixcmapWriteStream(fp, cmap);
1946  fputc('\0', fp);
1947  fclose(fp);
1948  *psize = *psize - 1;
1949 #else
1950  L_INFO("work-around: writing to a temp file\n", __func__);
1951  #ifdef _WIN32
1952  if ((fp = fopenWriteWinTempfile()) == NULL)
1953  return ERROR_INT("tmpfile stream not opened", __func__, 1);
1954  #else
1955  if ((fp = tmpfile()) == NULL)
1956  return ERROR_INT("tmpfile stream not opened", __func__, 1);
1957  #endif /* _WIN32 */
1958  ret = pixcmapWriteStream(fp, cmap);
1959  rewind(fp);
1960  *pdata = l_binaryReadStream(fp, psize);
1961  fclose(fp);
1962 #endif /* HAVE_FMEMOPEN */
1963  return ret;
1964 }
1965 
1966 
1967 /*----------------------------------------------------------------------*
1968  * Extract colormap arrays and serialization *
1969  *----------------------------------------------------------------------*/
1980 l_ok
1982  l_int32 **prmap,
1983  l_int32 **pgmap,
1984  l_int32 **pbmap,
1985  l_int32 **pamap)
1986 {
1987 l_int32 *rmap, *gmap, *bmap, *amap;
1988 l_int32 i, ncolors;
1989 RGBA_QUAD *cta;
1990 
1991  if (!prmap || !pgmap || !pbmap)
1992  return ERROR_INT("&rmap, &gmap, &bmap not all defined", __func__, 1);
1993  *prmap = *pgmap = *pbmap = NULL;
1994  if (pamap) *pamap = NULL;
1995  if (!cmap)
1996  return ERROR_INT("cmap not defined", __func__, 1);
1997 
1998  ncolors = pixcmapGetCount(cmap);
1999  rmap = (l_int32 *)LEPT_CALLOC(ncolors, sizeof(l_int32));
2000  gmap = (l_int32 *)LEPT_CALLOC(ncolors, sizeof(l_int32));
2001  bmap = (l_int32 *)LEPT_CALLOC(ncolors, sizeof(l_int32));
2002  *prmap = rmap;
2003  *pgmap = gmap;
2004  *pbmap = bmap;
2005  if (pamap) {
2006  amap = (l_int32 *)LEPT_CALLOC(ncolors, sizeof(l_int32));
2007  *pamap = amap;
2008  }
2009 
2010  cta = (RGBA_QUAD *)cmap->array;
2011  for (i = 0; i < ncolors; i++) {
2012  rmap[i] = cta[i].red;
2013  gmap[i] = cta[i].green;
2014  bmap[i] = cta[i].blue;
2015  if (pamap)
2016  amap[i] = cta[i].alpha;
2017  }
2018 
2019  return 0;
2020 }
2021 
2022 
2031 l_ok
2033  l_uint32 **ptab,
2034  l_int32 *pncolors)
2035 {
2036 l_int32 i, ncolors, rval, gval, bval, aval;
2037 l_uint32 *tab;
2038 
2039  if (!ptab)
2040  return ERROR_INT("&tab not defined", __func__, 1);
2041  *ptab = NULL;
2042  if (!cmap)
2043  return ERROR_INT("cmap not defined", __func__, 1);
2044 
2045  ncolors = pixcmapGetCount(cmap);
2046  if (pncolors) *pncolors = ncolors;
2047  tab = (l_uint32 *)LEPT_CALLOC(ncolors, sizeof(l_uint32));
2048  *ptab = tab;
2049 
2050  for (i = 0; i < ncolors; i++) {
2051  pixcmapGetRGBA(cmap, i, &rval, &gval, &bval, &aval);
2052  composeRGBAPixel(rval, gval, bval, aval, &tab[i]);
2053  }
2054  return 0;
2055 }
2056 
2057 
2072 l_ok
2074  l_int32 cpc,
2075  l_int32 *pncolors,
2076  l_uint8 **pdata)
2077 {
2078 l_int32 i, ncolors, rval, gval, bval, aval;
2079 l_uint8 *data;
2080 
2081  if (!pdata)
2082  return ERROR_INT("&data not defined", __func__, 1);
2083  *pdata = NULL;
2084  if (!pncolors)
2085  return ERROR_INT("&ncolors not defined", __func__, 1);
2086  *pncolors = 0;
2087  if (!cmap)
2088  return ERROR_INT("cmap not defined", __func__, 1);
2089  if (cpc != 3 && cpc != 4)
2090  return ERROR_INT("cpc not 3 or 4", __func__, 1);
2091 
2092  ncolors = pixcmapGetCount(cmap);
2093  *pncolors = ncolors;
2094  data = (l_uint8 *)LEPT_CALLOC((size_t)cpc * ncolors, sizeof(l_uint8));
2095  *pdata = data;
2096 
2097  for (i = 0; i < ncolors; i++) {
2098  pixcmapGetRGBA(cmap, i, &rval, &gval, &bval, &aval);
2099  data[cpc * i] = rval;
2100  data[cpc * i + 1] = gval;
2101  data[cpc * i + 2] = bval;
2102  if (cpc == 4)
2103  data[cpc * i + 3] = aval;
2104  }
2105  return 0;
2106 }
2107 
2108 
2117 PIXCMAP *
2119  l_int32 cpc,
2120  l_int32 ncolors)
2121 {
2122 l_int32 i, d, rval, gval, bval, aval;
2123 PIXCMAP *cmap;
2124 
2125  if (!data)
2126  return (PIXCMAP *)ERROR_PTR("data not defined", __func__, NULL);
2127  if (cpc != 3 && cpc != 4)
2128  return (PIXCMAP *)ERROR_PTR("cpc not 3 or 4", __func__, NULL);
2129  if (ncolors <= 0)
2130  return (PIXCMAP *)ERROR_PTR("no entries", __func__, NULL);
2131  if (ncolors > 256)
2132  return (PIXCMAP *)ERROR_PTR("ncolors > 256", __func__, NULL);
2133 
2134  if (ncolors > 16)
2135  d = 8;
2136  else if (ncolors > 4)
2137  d = 4;
2138  else if (ncolors > 2)
2139  d = 2;
2140  else
2141  d = 1;
2142  cmap = pixcmapCreate(d);
2143  for (i = 0; i < ncolors; i++) {
2144  rval = data[cpc * i];
2145  gval = data[cpc * i + 1];
2146  bval = data[cpc * i + 2];
2147  if (cpc == 4)
2148  aval = data[cpc * i + 3];
2149  else
2150  aval = 255; /* opaque */
2151  pixcmapAddRGBA(cmap, rval, gval, bval, aval);
2152  }
2153 
2154  return cmap;
2155 }
2156 
2157 
2176 char *
2177 pixcmapConvertToHex(l_uint8 *data,
2178  l_int32 ncolors)
2179 {
2180 l_int32 i, j, hexbytes;
2181 char *hexdata = NULL;
2182 char buf[4];
2183 
2184  if (!data)
2185  return (char *)ERROR_PTR("data not defined", __func__, NULL);
2186  if (ncolors < 1)
2187  return (char *)ERROR_PTR("no colors", __func__, NULL);
2188 
2189  hexbytes = 2 + (2 * 3 + 1) * ncolors + 2;
2190  hexdata = (char *)LEPT_CALLOC(hexbytes, sizeof(char));
2191  hexdata[0] = '<';
2192  hexdata[1] = ' ';
2193 
2194  for (i = 0; i < ncolors; i++) {
2195  j = 2 + (2 * 3 + 1) * i;
2196  snprintf(buf, sizeof(buf), "%02x", data[3 * i]);
2197  hexdata[j] = buf[0];
2198  hexdata[j + 1] = buf[1];
2199  snprintf(buf, sizeof(buf), "%02x", data[3 * i + 1]);
2200  hexdata[j + 2] = buf[0];
2201  hexdata[j + 3] = buf[1];
2202  snprintf(buf, sizeof(buf), "%02x", data[3 * i + 2]);
2203  hexdata[j + 4] = buf[0];
2204  hexdata[j + 5] = buf[1];
2205  hexdata[j + 6] = ' ';
2206  }
2207  hexdata[j + 7] = '>';
2208  hexdata[j + 8] = '\0';
2209  return hexdata;
2210 }
2211 
2212 
2213 /*-------------------------------------------------------------*
2214  * Colormap transforms *
2215  *-------------------------------------------------------------*/
2232 l_ok
2234  l_float32 gamma,
2235  l_int32 minval,
2236  l_int32 maxval)
2237 {
2238 l_int32 rval, gval, bval, trval, tgval, tbval, i, ncolors;
2239 NUMA *nag;
2240 
2241  if (!cmap)
2242  return ERROR_INT("cmap not defined", __func__, 1);
2243  if (gamma <= 0.0) {
2244  L_WARNING("gamma must be > 0.0; setting to 1.0\n", __func__);
2245  gamma = 1.0;
2246  }
2247  if (minval >= maxval)
2248  return ERROR_INT("minval not < maxval", __func__, 1);
2249 
2250  if (gamma == 1.0 && minval == 0 && maxval == 255) /* no-op */
2251  return 0;
2252 
2253  if ((nag = numaGammaTRC(gamma, minval, maxval)) == NULL)
2254  return ERROR_INT("nag not made", __func__, 1);
2255 
2256  ncolors = pixcmapGetCount(cmap);
2257  for (i = 0; i < ncolors; i++) {
2258  pixcmapGetColor(cmap, i, &rval, &gval, &bval);
2259  numaGetIValue(nag, rval, &trval);
2260  numaGetIValue(nag, gval, &tgval);
2261  numaGetIValue(nag, bval, &tbval);
2262  pixcmapResetColor(cmap, i, trval, tgval, tbval);
2263  }
2264 
2265  numaDestroy(&nag);
2266  return 0;
2267 }
2268 
2269 
2285 l_ok
2287  l_float32 factor)
2288 {
2289 l_int32 i, ncolors, rval, gval, bval, trval, tgval, tbval;
2290 NUMA *nac;
2291 
2292  if (!cmap)
2293  return ERROR_INT("cmap not defined", __func__, 1);
2294  if (factor < 0.0) {
2295  L_WARNING("factor must be >= 0.0; setting to 0.0\n", __func__);
2296  factor = 0.0;
2297  }
2298 
2299  if ((nac = numaContrastTRC(factor)) == NULL)
2300  return ERROR_INT("nac not made", __func__, 1);
2301 
2302  ncolors = pixcmapGetCount(cmap);
2303  for (i = 0; i < ncolors; i++) {
2304  pixcmapGetColor(cmap, i, &rval, &gval, &bval);
2305  numaGetIValue(nac, rval, &trval);
2306  numaGetIValue(nac, gval, &tgval);
2307  numaGetIValue(nac, bval, &tbval);
2308  pixcmapResetColor(cmap, i, trval, tgval, tbval);
2309  }
2310 
2311  numaDestroy(&nac);
2312  return 0;
2313 }
2314 
2315 
2335 l_ok
2337  l_float32 fraction)
2338 {
2339 l_int32 i, ncolors, rval, gval, bval;
2340 
2341  if (!cmap)
2342  return ERROR_INT("cmap not defined", __func__, 1);
2343  if (fraction < -1.0 || fraction > 1.0)
2344  return ERROR_INT("fraction not in [-1.0, 1.0]", __func__, 1);
2345 
2346  ncolors = pixcmapGetCount(cmap);
2347  for (i = 0; i < ncolors; i++) {
2348  pixcmapGetColor(cmap, i, &rval, &gval, &bval);
2349  if (fraction < 0.0)
2350  pixcmapResetColor(cmap, i,
2351  (l_int32)((1.0 + fraction) * rval),
2352  (l_int32)((1.0 + fraction) * gval),
2353  (l_int32)((1.0 + fraction) * bval));
2354  else
2355  pixcmapResetColor(cmap, i,
2356  rval + (l_int32)(fraction * (255 - rval)),
2357  gval + (l_int32)(fraction * (255 - gval)),
2358  bval + (l_int32)(fraction * (255 - bval)));
2359  }
2360 
2361  return 0;
2362 }
2363 
2364 
2383 l_ok
2385  l_uint32 srcval,
2386  l_uint32 dstval)
2387 {
2388 l_int32 i, ncolors, rval, gval, bval;
2389 l_uint32 newval;
2390 
2391  if (!cmap)
2392  return ERROR_INT("cmap not defined", __func__, 1);
2393 
2394  ncolors = pixcmapGetCount(cmap);
2395  for (i = 0; i < ncolors; i++) {
2396  pixcmapGetColor(cmap, i, &rval, &gval, &bval);
2397  pixelShiftByComponent(rval, gval, bval, srcval, dstval, &newval);
2398  extractRGBValues(newval, &rval, &gval, &bval);
2399  pixcmapResetColor(cmap, i, rval, gval, bval);
2400  }
2401 
2402  return 0;
2403 }
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:952
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
PIXCMAP * pixcmapCreateRandom(l_int32 depth, l_int32 hasblack, l_int32 haswhite)
pixcmapCreateRandom()
Definition: colormap.c:171
l_ok pixcmapContrastTRC(PIXCMAP *cmap, l_float32 factor)
pixcmapContrastTRC()
Definition: colormap.c:2286
l_ok pixcmapHasColor(PIXCMAP *cmap, l_int32 *pcolor)
pixcmapHasColor()
Definition: colormap.c:1026
l_int32 pixcmapGetCount(const PIXCMAP *cmap)
pixcmapGetCount()
Definition: colormap.c:683
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
PIXCMAP * pixcmapDeserializeFromMemory(l_uint8 *data, l_int32 cpc, l_int32 ncolors)
pixcmapDeserializeFromMemory()
Definition: colormap.c:2118
l_ok pixcmapSetBlackAndWhite(PIXCMAP *cmap, l_int32 setblack, l_int32 setwhite)
pixcmapSetBlackAndWhite()
Definition: colormap.c:655
PIXCMAP * pixcmapReadStream(FILE *fp)
pixcmapReadStream()
Definition: colormap.c:1786
l_ok pixcmapIsValid(const PIXCMAP *cmap, PIX *pix, l_int32 *pvalid)
pixcmapIsValid()
Definition: colormap.c:308
PIXCMAP * pixcmapConvertTo8(PIXCMAP *cmaps)
pixcmapConvertTo8()
Definition: colormap.c:1729
l_ok pixcmapWriteStream(FILE *fp, const PIXCMAP *cmap)
pixcmapWriteStream()
Definition: colormap.c:1882
PIXCMAP * pixcmapCreate(l_int32 depth)
pixcmapCreate()
Definition: colormap.c:126
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
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:2073
l_ok pixcmapWrite(const char *filename, const PIXCMAP *cmap)
pixcmapWrite()
Definition: colormap.c:1852
l_ok pixcmapWriteMem(l_uint8 **pdata, size_t *psize, const PIXCMAP *cmap)
pixcmapWriteMem()
Definition: colormap.c:1926
l_ok pixcmapAddRGBA(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 aval)
pixcmapAddRGBA()
Definition: colormap.c:439
PIXCMAP * pixcmapGrayToFalseColor(l_float32 gamma)
pixcmapGrayToFalseColor()
Definition: colormap.c:1545
PIXCMAP * pixcmapColorToGray(PIXCMAP *cmaps, l_float32 rwt, l_float32 gwt, l_float32 bwt)
pixcmapColorToGray()
Definition: colormap.c:1641
PIXCMAP * pixcmapConvertTo4(PIXCMAP *cmaps)
pixcmapConvertTo4()
Definition: colormap.c:1696
l_ok pixcmapAddBlackOrWhite(PIXCMAP *cmap, l_int32 color, l_int32 *pindex)
pixcmapAddBlackOrWhite()
Definition: colormap.c:618
l_ok pixcmapAddNearestColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pindex)
pixcmapAddNearestColor()
Definition: colormap.c:528
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:2233
l_int32 pixcmapGetIndex(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pindex)
pixcmapGetIndex()
Definition: colormap.c:989
char * pixcmapConvertToHex(l_uint8 *data, l_int32 ncolors)
pixcmapConvertToHex()
Definition: colormap.c:2177
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:2336
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 * pixcmapGrayToColor(l_uint32 color)
pixcmapGrayToColor()
Definition: colormap.c:1609
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
l_ok pixcmapGetRankIntensity(PIXCMAP *cmap, l_float32 rankval, l_int32 *pindex)
pixcmapGetRankIntensity()
Definition: colormap.c:1243
PIXCMAP * pixcmapCreateLinear(l_int32 d, l_int32 nlevels)
pixcmapCreateLinear()
Definition: colormap.c:215
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
l_ok pixcmapToArrays(const PIXCMAP *cmap, l_int32 **prmap, l_int32 **pgmap, l_int32 **pbmap, l_int32 **pamap)
pixcmapToArrays()
Definition: colormap.c:1981
PIXCMAP * pixcmapReadMem(const l_uint8 *data, size_t size)
pixcmapReadMem()
Definition: colormap.c:1826
l_ok pixcmapShiftByComponent(PIXCMAP *cmap, l_uint32 srcval, l_uint32 dstval)
pixcmapShiftByComponent()
Definition: colormap.c:2384
l_ok pixcmapIsBlackAndWhite(PIXCMAP *cmap, l_int32 *pblackwhite)
pixcmapIsBlackAndWhite()
Definition: colormap.c:1165
PIXCMAP * pixcmapCopy(const PIXCMAP *cmaps)
pixcmapCopy()
Definition: colormap.c:243
l_ok pixcmapAddColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapAddColor()
Definition: colormap.c:403
PIXCMAP * pixcmapRead(const char *filename)
pixcmapRead()
Definition: colormap.c:1761
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:2032
l_ok pixcmapGetRGBA32(PIXCMAP *cmap, l_int32 index, l_uint32 *pval32)
pixcmapGetRGBA32()
Definition: colormap.c:889
NUMA * numaContrastTRC(l_float32 factor)
numaContrastTRC()
Definition: enhance.c:548
NUMA * numaGammaTRC(l_float32 gamma, l_int32 minval, l_int32 maxval)
numaGammaTRC()
Definition: enhance.c:363
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:460
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:193
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:357
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:720
NUMA * numaGetSortIndex(NUMA *na, l_int32 sortorder)
numaGetSortIndex()
Definition: numafunc1.c:2664
l_ok composeRGBAPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_int32 aval, l_uint32 *ppixel)
composeRGBAPixel()
Definition: pix2.c:2758
void extractRGBValues(l_uint32 pixel, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
extractRGBValues()
Definition: pix2.c:2793
l_ok pixGetMaxColorIndex(PIX *pixs, l_int32 *pmaxindex)
pixGetMaxColorIndex()
Definition: pix4.c:2373
@ 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
void * array
Definition: pix_internal.h:202
l_int32 depth
Definition: pix_internal.h:203
l_int32 nalloc
Definition: pix_internal.h:204
l_uint8 alpha
Definition: pix_internal.h:218
l_uint8 green
Definition: pix_internal.h:216
l_uint8 blue
Definition: pix_internal.h:215
l_uint8 red
Definition: pix_internal.h:217
l_uint8 * l_binaryReadStream(FILE *fp, size_t *pnbytes)
l_binaryReadStream()
Definition: utils2.c:1358
FILE * fopenReadFromMemory(const l_uint8 *data, size_t size)
fopenReadFromMemory()
Definition: utils2.c:1937
FILE * fopenWriteStream(const char *filename, const char *modestring)
fopenWriteStream()
Definition: utils2.c:1905
FILE * fopenWriteWinTempfile(void)
fopenWriteWinTempfile()
Definition: utils2.c:1981
FILE * fopenReadStream(const char *filename)
fopenReadStream()
Definition: utils2.c:1864