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  *-------------------------------------------------------------*/
124 PIXCMAP *
125 pixcmapCreate(l_int32 depth)
126 {
127 RGBA_QUAD *cta;
128 PIXCMAP *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 
171 PIXCMAP *
172 pixcmapCreateRandom(l_int32 depth,
173  l_int32 hasblack,
174  l_int32 haswhite)
175 {
176 l_int32 ncolors, i;
177 l_int32 red[256], green[256], blue[256];
178 PIXCMAP *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 
217 PIXCMAP *
219  l_int32 nlevels)
220 {
221 l_int32 maxlevels, i, val;
222 PIXCMAP *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 
247 PIXCMAP *
248 pixcmapCopy(const PIXCMAP *cmaps)
249 {
250 l_int32 nbytes, valid;
251 PIXCMAP *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 
278 void
280 {
281 PIXCMAP *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 
316 l_ok
318  PIX *pix,
319  l_int32 *pvalid)
320 {
321 l_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 
413 l_ok
415  l_int32 rval,
416  l_int32 gval,
417  l_int32 bval)
418 {
419 RGBA_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 
451 l_ok
453  l_int32 rval,
454  l_int32 gval,
455  l_int32 bval,
456  l_int32 aval)
457 {
458 RGBA_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 
495 l_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 
544 l_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 
591 l_ok
593  l_int32 rval,
594  l_int32 gval,
595  l_int32 bval,
596  l_int32 *pusable)
597 {
598 l_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 
638 l_ok
640  l_int32 color,
641  l_int32 *pindex)
642 {
643 l_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 
677 l_ok
679  l_int32 setblack,
680  l_int32 setwhite)
681 {
682 l_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 
707 l_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 
724 l_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 
741 l_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 
764 l_ok
766  l_int32 *pmindepth)
767 {
768 l_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 
800 l_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  *-------------------------------------------------------------*/
823 l_ok
825  l_int32 index,
826  l_int32 *prval,
827  l_int32 *pgval,
828  l_int32 *pbval)
829 {
830 RGBA_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 
863 l_ok
865  l_int32 index,
866  l_uint32 *pval32)
867 {
868 l_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 
891 l_ok
893  l_int32 index,
894  l_int32 *prval,
895  l_int32 *pgval,
896  l_int32 *pbval,
897  l_int32 *paval)
898 {
899 RGBA_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 
929 l_ok
931  l_int32 index,
932  l_uint32 *pval32)
933 {
934 l_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 
965 l_ok
967  l_int32 index,
968  l_int32 rval,
969  l_int32 gval,
970  l_int32 bval)
971 {
972 RGBA_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 
1006 l_ok
1008  l_int32 index,
1009  l_int32 aval)
1010 {
1011 RGBA_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 
1035 l_int32
1037  l_int32 rval,
1038  l_int32 gval,
1039  l_int32 bval,
1040  l_int32 *pindex)
1041 {
1042 l_int32 n, i;
1043 RGBA_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 
1074 l_ok
1076  l_int32 *pcolor)
1077 {
1078 l_int32 n, i;
1079 l_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 
1113 l_ok
1115  l_int32 *popaque)
1116 {
1117 l_int32 i, n;
1118 RGBA_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 
1172 l_ok
1174  l_int32 *pntrans,
1175  l_int32 *pmax_trans,
1176  l_int32 *pmin_opaque)
1177 {
1178 l_int32 i, n, ntrans, max_trans, min_opaque, opaque_found;
1179 RGBA_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 
1219 l_ok
1221  l_int32 *pblackwhite)
1222 {
1223 l_int32 val0, val1, hascolor;
1224 RGBA_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 
1260 l_ok
1262  l_int32 *pngray)
1263 {
1264 l_int32 n, i, rval, gval, bval, count;
1265 l_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 
1301 l_ok
1303  l_float32 rankval,
1304  l_int32 *pindex)
1305 {
1306 l_int32 n, i, rval, gval, bval, rankindex;
1307 NUMA *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 
1352 l_ok
1354  l_int32 rval,
1355  l_int32 gval,
1356  l_int32 bval,
1357  l_int32 *pindex)
1358 {
1359 l_int32 i, n, delta, dist, mindist;
1360 RGBA_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 
1410 l_ok
1412  l_int32 val,
1413  l_int32 *pindex)
1414 {
1415 l_int32 i, n, dist, mindist;
1416 RGBA_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 
1463 l_ok
1465  l_int32 index,
1466  l_int32 rval,
1467  l_int32 gval,
1468  l_int32 bval,
1469  l_int32 *pdist)
1470 {
1471 l_int32 n, delta, dist;
1472 RGBA_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 
1519 l_ok
1521  l_int32 select,
1522  l_int32 *pminval,
1523  l_int32 *pmaxval,
1524  l_int32 *pminindex,
1525  l_int32 *pmaxindex)
1526 {
1527 l_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  *-------------------------------------------------------------*/
1613 PIXCMAP *
1614 pixcmapGrayToFalseColor(l_float32 gamma)
1615 {
1616 l_int32 i, rval, gval, bval;
1617 l_int32 *curve;
1618 l_float32 invgamma, x;
1619 PIXCMAP *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 
1677 PIXCMAP *
1678 pixcmapGrayToColor(l_uint32 color)
1679 {
1680 l_int32 i, rval, gval, bval;
1681 PIXCMAP *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 
1709 PIXCMAP *
1711  l_float32 rwt,
1712  l_float32 gwt,
1713  l_float32 bwt)
1714 {
1715 l_int32 i, n, rval, gval, bval, val;
1716 l_float32 sum;
1717 PIXCMAP *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 
1766 PIXCMAP *
1768 {
1769 l_int32 i, n, rval, gval, bval;
1770 PIXCMAP *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 
1801 PIXCMAP *
1803 {
1804 l_int32 i, n, depth, rval, gval, bval;
1805 PIXCMAP *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  *-------------------------------------------------------------*/
1835 PIXCMAP *
1836 pixcmapRead(const char *filename)
1837 {
1838 FILE *fp;
1839 PIXCMAP *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 
1862 PIXCMAP *
1864 {
1865 l_int32 rval, gval, bval, aval, ignore;
1866 l_int32 i, index, ret, depth, ncolors;
1867 PIXCMAP *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 
1904 PIXCMAP *
1905 pixcmapReadMem(const l_uint8 *data,
1906  size_t size)
1907 {
1908 FILE *fp;
1909 PIXCMAP *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 
1932 l_ok
1933 pixcmapWrite(const char *filename,
1934  const PIXCMAP *cmap)
1935 {
1936 l_int32 ret;
1937 FILE *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 
1964 l_ok
1966  const PIXCMAP *cmap)
1967 {
1968 l_int32 *rmap, *gmap, *bmap, *amap;
1969 l_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 
2010 l_ok
2011 pixcmapWriteMem(l_uint8 **pdata,
2012  size_t *psize,
2013  const PIXCMAP *cmap)
2014 {
2015 l_int32 ret;
2016 FILE *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  *----------------------------------------------------------------------*/
2067 l_ok
2069  l_int32 **prmap,
2070  l_int32 **pgmap,
2071  l_int32 **pbmap,
2072  l_int32 **pamap)
2073 {
2074 l_int32 *rmap, *gmap, *bmap, *amap;
2075 l_int32 i, ncolors;
2076 RGBA_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 
2120 l_ok
2122  l_uint32 **ptab,
2123  l_int32 *pncolors)
2124 {
2125 l_int32 i, ncolors, rval, gval, bval, aval;
2126 l_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 
2163 l_ok
2165  l_int32 cpc,
2166  l_int32 *pncolors,
2167  l_uint8 **pdata)
2168 {
2169 l_int32 i, ncolors, rval, gval, bval, aval;
2170 l_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 
2210 PIXCMAP *
2212  l_int32 cpc,
2213  l_int32 ncolors)
2214 {
2215 l_int32 i, d, rval, gval, bval, aval;
2216 PIXCMAP *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 
2271 char *
2272 pixcmapConvertToHex(l_uint8 *data,
2273  l_int32 ncolors)
2274 {
2275 l_int32 i, j, hexbytes;
2276 char *hexdata = NULL;
2277 char 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  *-------------------------------------------------------------*/
2329 l_ok
2331  l_float32 gamma,
2332  l_int32 minval,
2333  l_int32 maxval)
2334 {
2335 l_int32 rval, gval, bval, trval, tgval, tbval, i, ncolors;
2336 NUMA *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 
2384 l_ok
2386  l_float32 factor)
2387 {
2388 l_int32 i, ncolors, rval, gval, bval, trval, tgval, tbval;
2389 NUMA *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 
2436 l_ok
2438  l_float32 fraction)
2439 {
2440 l_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 
2486 l_ok
2488  l_uint32 srcval,
2489  l_uint32 dstval)
2490 {
2491 l_int32 i, ncolors, rval, gval, bval;
2492 l_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
PIXCMAP * pixcmapCreateRandom(l_int32 depth, l_int32 hasblack, l_int32 haswhite)
pixcmapCreateRandom()
Definition: colormap.c:172
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
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
PIXCMAP * pixcmapDeserializeFromMemory(l_uint8 *data, l_int32 cpc, l_int32 ncolors)
pixcmapDeserializeFromMemory()
Definition: colormap.c:2211
l_ok pixcmapSetBlackAndWhite(PIXCMAP *cmap, l_int32 setblack, l_int32 setwhite)
pixcmapSetBlackAndWhite()
Definition: colormap.c:678
PIXCMAP * pixcmapReadStream(FILE *fp)
pixcmapReadStream()
Definition: colormap.c:1863
l_ok pixcmapIsValid(const PIXCMAP *cmap, PIX *pix, l_int32 *pvalid)
pixcmapIsValid()
Definition: colormap.c:317
PIXCMAP * pixcmapConvertTo8(PIXCMAP *cmaps)
pixcmapConvertTo8()
Definition: colormap.c:1802
l_ok pixcmapWriteStream(FILE *fp, const PIXCMAP *cmap)
pixcmapWriteStream()
Definition: colormap.c:1965
PIXCMAP * pixcmapCreate(l_int32 depth)
pixcmapCreate()
Definition: colormap.c:125
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
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
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 * pixcmapGrayToFalseColor(l_float32 gamma)
pixcmapGrayToFalseColor()
Definition: colormap.c:1614
PIXCMAP * pixcmapColorToGray(PIXCMAP *cmaps, l_float32 rwt, l_float32 gwt, l_float32 bwt)
pixcmapColorToGray()
Definition: colormap.c:1710
PIXCMAP * pixcmapConvertTo4(PIXCMAP *cmaps)
pixcmapConvertTo4()
Definition: colormap.c:1767
l_ok pixcmapAddBlackOrWhite(PIXCMAP *cmap, l_int32 color, l_int32 *pindex)
pixcmapAddBlackOrWhite()
Definition: colormap.c:639
l_ok pixcmapAddNearestColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pindex)
pixcmapAddNearestColor()
Definition: colormap.c:545
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
l_int32 pixcmapGetIndex(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pindex)
pixcmapGetIndex()
Definition: colormap.c:1036
char * pixcmapConvertToHex(l_uint8 *data, l_int32 ncolors)
pixcmapConvertToHex()
Definition: colormap.c:2272
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 * pixcmapGrayToColor(l_uint32 color)
pixcmapGrayToColor()
Definition: colormap.c:1678
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
l_ok pixcmapGetRankIntensity(PIXCMAP *cmap, l_float32 rankval, l_int32 *pindex)
pixcmapGetRankIntensity()
Definition: colormap.c:1302
PIXCMAP * pixcmapCreateLinear(l_int32 d, l_int32 nlevels)
pixcmapCreateLinear()
Definition: colormap.c:218
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
l_ok pixcmapToArrays(const PIXCMAP *cmap, l_int32 **prmap, l_int32 **pgmap, l_int32 **pbmap, l_int32 **pamap)
pixcmapToArrays()
Definition: colormap.c:2068
PIXCMAP * pixcmapReadMem(const l_uint8 *data, size_t size)
pixcmapReadMem()
Definition: colormap.c:1905
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 * pixcmapCopy(const PIXCMAP *cmaps)
pixcmapCopy()
Definition: colormap.c:248
l_ok pixcmapAddColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapAddColor()
Definition: colormap.c:414
PIXCMAP * pixcmapRead(const char *filename)
pixcmapRead()
Definition: colormap.c:1836
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 * numaContrastTRC(l_float32 factor)
numaContrastTRC()
Definition: enhance.c:560
NUMA * numaGammaTRC(l_float32 gamma, l_int32 minval, l_int32 maxval)
numaGammaTRC()
Definition: enhance.c:369
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:478
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:194
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 * 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
l_uint8 * l_binaryReadStream(FILE *fp, size_t *pnbytes)
l_binaryReadStream()
Definition: utils2.c:1402
FILE * fopenReadFromMemory(const l_uint8 *data, size_t size)
fopenReadFromMemory()
Definition: utils2.c:2009
FILE * fopenWriteStream(const char *filename, const char *modestring)
fopenWriteStream()
Definition: utils2.c:1975
FILE * fopenWriteWinTempfile(void)
fopenWriteWinTempfile()
Definition: utils2.c:2055
FILE * fopenReadStream(const char *filename)
fopenReadStream()
Definition: utils2.c:1932