Leptonica  1.82.0
Image processing and image analysis suite
coloring.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 
94 #ifdef HAVE_CONFIG_H
95 #include <config_auto.h>
96 #endif /* HAVE_CONFIG_H */
97 
98 #include "allheaders.h"
99 
100 /*---------------------------------------------------------------------*
101  * Coloring "gray" pixels *
102  *---------------------------------------------------------------------*/
130 PIX *
132  BOXA *boxa,
133  l_int32 type,
134  l_int32 thresh,
135  l_int32 rval,
136  l_int32 gval,
137  l_int32 bval)
138 {
139 l_int32 i, n, ncolors, ngray;
140 BOX *box;
141 PIX *pixd;
142 PIXCMAP *cmap;
143 
144  PROCNAME("pixColorGrayRegions");
145 
146  if (!pixs || pixGetDepth(pixs) == 1)
147  return (PIX *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL);
148  if (!boxa)
149  return (PIX *)ERROR_PTR("boxa not defined", procName, NULL);
150  if (type != L_PAINT_LIGHT && type != L_PAINT_DARK)
151  return (PIX *)ERROR_PTR("invalid type", procName, NULL);
152 
153  /* If cmapped and there is room in an 8 bpp colormap for
154  * expansion, convert pixs to 8 bpp, and colorize. */
155  cmap = pixGetColormap(pixs);
156  if (cmap) {
157  ncolors = pixcmapGetCount(cmap);
158  pixcmapCountGrayColors(cmap, &ngray);
159  if (ncolors + ngray < 255) {
160  pixd = pixConvertTo8(pixs, 1); /* always new image */
161  pixColorGrayRegionsCmap(pixd, boxa, type, rval, gval, bval);
162  return pixd;
163  }
164  }
165 
166  /* The output will be rgb. Make sure the thresholds are valid */
167  if (type == L_PAINT_LIGHT) { /* thresh should be low */
168  if (thresh >= 255)
169  return (PIX *)ERROR_PTR("thresh must be < 255", procName, NULL);
170  if (thresh > 127)
171  L_WARNING("threshold set very high\n", procName);
172  } else { /* type == L_PAINT_DARK; thresh should be high */
173  if (thresh <= 0)
174  return (PIX *)ERROR_PTR("thresh must be > 0", procName, NULL);
175  if (thresh < 128)
176  L_WARNING("threshold set very low\n", procName);
177  }
178 
179  pixd = pixConvertTo32(pixs); /* always new image */
180  n = boxaGetCount(boxa);
181  for (i = 0; i < n; i++) {
182  box = boxaGetBox(boxa, i, L_CLONE);
183  pixColorGray(pixd, box, type, thresh, rval, gval, bval);
184  boxDestroy(&box);
185  }
186 
187  return pixd;
188 }
189 
190 
231 l_ok
233  BOX *box,
234  l_int32 type,
235  l_int32 thresh,
236  l_int32 rval,
237  l_int32 gval,
238  l_int32 bval)
239 {
240 l_int32 i, j, w, h, d, wpl, x1, x2, y1, y2, bw, bh;
241 l_int32 nrval, ngval, nbval, aveval;
242 l_float32 factor;
243 l_uint32 val32;
244 l_uint32 *line, *data;
245 PIX *pixt;
246 PIXCMAP *cmap;
247 
248  PROCNAME("pixColorGray");
249 
250  if (!pixs)
251  return ERROR_INT("pixs not defined", procName, 1);
252  if (type != L_PAINT_LIGHT && type != L_PAINT_DARK)
253  return ERROR_INT("invalid type", procName, 1);
254 
255  cmap = pixGetColormap(pixs);
256  pixGetDimensions(pixs, &w, &h, &d);
257  if (!cmap && d != 8 && d != 32)
258  return ERROR_INT("pixs not cmapped, 8 bpp or rgb", procName, 1);
259  if (cmap)
260  return pixColorGrayCmap(pixs, box, type, rval, gval, bval);
261 
262  /* rgb or 8 bpp gray image; check the thresh */
263  if (type == L_PAINT_LIGHT) { /* thresh should be low */
264  if (thresh >= 255)
265  return ERROR_INT("thresh must be < 255; else this is a no-op",
266  procName, 1);
267  if (thresh > 127)
268  L_WARNING("threshold set very high\n", procName);
269  } else { /* type == L_PAINT_DARK; thresh should be high */
270  if (thresh <= 0)
271  return ERROR_INT("thresh must be > 0; else this is a no-op",
272  procName, 1);
273  if (thresh < 128)
274  L_WARNING("threshold set very low\n", procName);
275  }
276 
277  /* In-place conversion to 32 bpp if necessary */
278  if (d == 8) {
279  pixt = pixConvertTo32(pixs);
280  pixTransferAllData(pixs, &pixt, 1, 0);
281  }
282 
283  if (!box) {
284  x1 = y1 = 0;
285  x2 = w;
286  y2 = h;
287  } else {
288  boxGetGeometry(box, &x1, &y1, &bw, &bh);
289  x2 = x1 + bw - 1;
290  y2 = y1 + bh - 1;
291  }
292 
293  data = pixGetData(pixs);
294  wpl = pixGetWpl(pixs);
295  factor = 1. / 255.;
296  for (i = y1; i <= y2; i++) {
297  if (i < 0 || i >= h)
298  continue;
299  line = data + i * wpl;
300  for (j = x1; j <= x2; j++) {
301  if (j < 0 || j >= w)
302  continue;
303  val32 = *(line + j);
304  aveval = ((val32 >> 24) + ((val32 >> 16) & 0xff) +
305  ((val32 >> 8) & 0xff)) / 3;
306  if (type == L_PAINT_LIGHT) {
307  if (aveval < thresh) /* skip sufficiently dark pixels */
308  continue;
309  nrval = (l_int32)(rval * aveval * factor);
310  ngval = (l_int32)(gval * aveval * factor);
311  nbval = (l_int32)(bval * aveval * factor);
312  } else { /* type == L_PAINT_DARK */
313  if (aveval > thresh) /* skip sufficiently light pixels */
314  continue;
315  nrval = rval + (l_int32)((255. - rval) * aveval * factor);
316  ngval = gval + (l_int32)((255. - gval) * aveval * factor);
317  nbval = bval + (l_int32)((255. - bval) * aveval * factor);
318  }
319  composeRGBPixel(nrval, ngval, nbval, &val32);
320  *(line + j) = val32;
321  }
322  }
323 
324  return 0;
325 }
326 
327 
357 PIX *
359  PIX *pixm,
360  l_int32 type,
361  l_int32 thresh,
362  l_int32 rval,
363  l_int32 gval,
364  l_int32 bval)
365 {
366 l_int32 i, j, w, h, d, wm, hm, wmin, hmin, wpl, wplm;
367 l_int32 nrval, ngval, nbval, aveval;
368 l_float32 factor;
369 l_uint32 val32;
370 l_uint32 *line, *data, *linem, *datam;
371 PIX *pixd;
372 PIXCMAP *cmap;
373 
374  PROCNAME("pixColorGrayMasked");
375 
376  if (!pixs)
377  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
378  if (!pixm || pixGetDepth(pixm) != 1)
379  return (PIX *)ERROR_PTR("pixm undefined or not 1 bpp", procName, NULL);
380  if (type != L_PAINT_LIGHT && type != L_PAINT_DARK)
381  return (PIX *)ERROR_PTR("invalid type", procName, NULL);
382 
383  cmap = pixGetColormap(pixs);
384  pixGetDimensions(pixs, &w, &h, &d);
385  if (!cmap && d != 8 && d != 32)
386  return (PIX *)ERROR_PTR("pixs not cmapped, 8 bpp gray or 32 bpp",
387  procName, NULL);
388  if (cmap) {
389  pixd = pixCopy(NULL, pixs);
390  pixColorGrayMaskedCmap(pixd, pixm, type, rval, gval, bval);
391  return pixd;
392  }
393 
394  /* rgb or 8 bpp gray image; check the thresh */
395  if (type == L_PAINT_LIGHT) { /* thresh should be low */
396  if (thresh >= 255)
397  return (PIX *)ERROR_PTR(
398  "thresh must be < 255; else this is a no-op", procName, NULL);
399  if (thresh > 127)
400  L_WARNING("threshold set very high\n", procName);
401  } else { /* type == L_PAINT_DARK; thresh should be high */
402  if (thresh <= 0)
403  return (PIX *)ERROR_PTR(
404  "thresh must be > 0; else this is a no-op", procName, NULL);
405  if (thresh < 128)
406  L_WARNING("threshold set very low\n", procName);
407  }
408 
409  pixGetDimensions(pixm, &wm, &hm, NULL);
410  if (wm != w)
411  L_WARNING("wm = %d differs from w = %d\n", procName, wm, w);
412  if (hm != h)
413  L_WARNING("hm = %d differs from h = %d\n", procName, hm, h);
414  wmin = L_MIN(w, wm);
415  hmin = L_MIN(h, hm);
416  if (d == 8)
417  pixd = pixConvertTo32(pixs);
418  else
419  pixd = pixCopy(NULL, pixs);
420 
421  data = pixGetData(pixd);
422  wpl = pixGetWpl(pixd);
423  datam = pixGetData(pixm);
424  wplm = pixGetWpl(pixm);
425  factor = 1. / 255.;
426  for (i = 0; i < hmin; i++) {
427  line = data + i * wpl;
428  linem = datam + i * wplm;
429  for (j = 0; j < wmin; j++) {
430  if (GET_DATA_BIT(linem, j) == 0)
431  continue;
432  val32 = *(line + j);
433  aveval = ((val32 >> 24) + ((val32 >> 16) & 0xff) +
434  ((val32 >> 8) & 0xff)) / 3;
435  if (type == L_PAINT_LIGHT) {
436  if (aveval < thresh) /* skip sufficiently dark pixels */
437  continue;
438  nrval = (l_int32)(rval * aveval * factor);
439  ngval = (l_int32)(gval * aveval * factor);
440  nbval = (l_int32)(bval * aveval * factor);
441  } else { /* type == L_PAINT_DARK */
442  if (aveval > thresh) /* skip sufficiently light pixels */
443  continue;
444  nrval = rval + (l_int32)((255. - rval) * aveval * factor);
445  ngval = gval + (l_int32)((255. - gval) * aveval * factor);
446  nbval = bval + (l_int32)((255. - bval) * aveval * factor);
447  }
448  composeRGBPixel(nrval, ngval, nbval, &val32);
449  *(line + j) = val32;
450  }
451  }
452 
453  return pixd;
454 }
455 
456 
457 /*------------------------------------------------------------------*
458  * Adjusting one or more colors to a target color *
459  *------------------------------------------------------------------*/
482 PIX *
484  PIX *pixs,
485  l_uint32 srcval,
486  l_uint32 dstval,
487  l_int32 diff)
488 {
489 l_int32 val, sval, dval;
490 l_int32 rval, gval, bval, rsval, gsval, bsval;
491 l_int32 i, j, w, h, d, wpl;
492 l_uint32 pixel;
493 l_uint32 *line, *data;
494 
495  PROCNAME("pixSnapColor");
496 
497  if (!pixs)
498  return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
499  if (pixd && (pixd != pixs))
500  return (PIX *)ERROR_PTR("pixd exists, but != pixs", procName, pixd);
501 
502  if (pixGetColormap(pixs))
503  return pixSnapColorCmap(pixd, pixs, srcval, dstval, diff);
504 
505  /* pixs does not have a colormap; it must be 8 bpp gray or
506  * 32 bpp rgb. */
507  if (pixGetDepth(pixs) < 8)
508  return (PIX *)ERROR_PTR("pixs is < 8 bpp", procName, pixd);
509 
510  /* Do the work on pixd */
511  if (!pixd)
512  pixd = pixCopy(NULL, pixs);
513 
514  pixGetDimensions(pixd, &w, &h, &d);
515  data = pixGetData(pixd);
516  wpl = pixGetWpl(pixd);
517  if (d == 8) {
518  sval = srcval & 0xff;
519  dval = dstval & 0xff;
520  for (i = 0; i < h; i++) {
521  line = data + i * wpl;
522  for (j = 0; j < w; j++) {
523  val = GET_DATA_BYTE(line, j);
524  if (L_ABS(val - sval) <= diff)
525  SET_DATA_BYTE(line, j, dval);
526  }
527  }
528  } else { /* d == 32 */
529  extractRGBValues(srcval, &rsval, &gsval, &bsval);
530  for (i = 0; i < h; i++) {
531  line = data + i * wpl;
532  for (j = 0; j < w; j++) {
533  pixel = *(line + j);
534  extractRGBValues(pixel, &rval, &gval, &bval);
535  if ((L_ABS(rval - rsval) <= diff) &&
536  (L_ABS(gval - gsval) <= diff) &&
537  (L_ABS(bval - bsval) <= diff))
538  *(line + j) = dstval; /* replace */
539  }
540  }
541  }
542 
543  return pixd;
544 }
545 
546 
569 PIX *
571  PIX *pixs,
572  l_uint32 srcval,
573  l_uint32 dstval,
574  l_int32 diff)
575 {
576 l_int32 i, ncolors, index, found;
577 l_int32 rval, gval, bval, rsval, gsval, bsval, rdval, gdval, bdval;
578 l_int32 *tab;
579 PIX *pixm;
580 PIXCMAP *cmap;
581 
582  PROCNAME("pixSnapColorCmap");
583 
584  if (!pixs)
585  return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
586  if (!pixGetColormap(pixs))
587  return (PIX *)ERROR_PTR("cmap not found", procName, pixd);
588  if (pixd && (pixd != pixs))
589  return (PIX *)ERROR_PTR("pixd exists, but != pixs", procName, pixd);
590 
591  if (!pixd)
592  pixd = pixCopy(NULL, pixs);
593 
594  /* If no free colors, look for one close to the target
595  * that can be commandeered. */
596  cmap = pixGetColormap(pixd);
597  ncolors = pixcmapGetCount(cmap);
598  extractRGBValues(srcval, &rsval, &gsval, &bsval);
599  extractRGBValues(dstval, &rdval, &gdval, &bdval);
600  found = FALSE;
601  if (pixcmapGetFreeCount(cmap) == 0) {
602  for (i = 0; i < ncolors; i++) {
603  pixcmapGetColor(cmap, i, &rval, &gval, &bval);
604  if ((L_ABS(rval - rsval) <= diff) &&
605  (L_ABS(gval - gsval) <= diff) &&
606  (L_ABS(bval - bsval) <= diff)) {
607  index = i;
608  pixcmapResetColor(cmap, index, rdval, gdval, bdval);
609  found = TRUE;
610  break;
611  }
612  }
613  } else { /* just add the new color */
614  pixcmapAddColor(cmap, rdval, gdval, bdval);
615  ncolors = pixcmapGetCount(cmap);
616  index = ncolors - 1; /* index of new destination color */
617  found = TRUE;
618  }
619 
620  if (!found) {
621  L_INFO("nothing to do\n", procName);
622  return pixd;
623  }
624 
625  /* For each color in cmap that is close enough to srcval,
626  * set the tab value to 1. Then generate a 1 bpp mask with
627  * fg pixels for every pixel in pixd that is close enough
628  * to srcval (i.e., has value 1 in tab). */
629  tab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
630  for (i = 0; i < ncolors; i++) {
631  pixcmapGetColor(cmap, i, &rval, &gval, &bval);
632  if ((L_ABS(rval - rsval) <= diff) &&
633  (L_ABS(gval - gsval) <= diff) &&
634  (L_ABS(bval - bsval) <= diff))
635  tab[i] = 1;
636  }
637  pixm = pixMakeMaskFromLUT(pixd, tab);
638  LEPT_FREE(tab);
639 
640  /* Use the binary mask to set all selected pixels to
641  * the dest color index. */
642  pixSetMasked(pixd, pixm, dstval);
643  pixDestroy(&pixm);
644 
645  /* Remove all unused colors from the colormap. */
646  pixRemoveUnusedColors(pixd);
647 
648  return pixd;
649 }
650 
651 
652 /*---------------------------------------------------------------------*
653  * Piecewise linear color mapping based on a source/target pair *
654  *---------------------------------------------------------------------*/
686 PIX *
688  PIX *pixs,
689  l_uint32 srcval,
690  l_uint32 dstval)
691 {
692 l_int32 i, j, w, h, wpl;
693 l_int32 rval, gval, bval, rsval, gsval, bsval, rdval, gdval, bdval;
694 l_int32 *rtab, *gtab, *btab;
695 l_uint32 pixel;
696 l_uint32 *line, *data;
697 
698  PROCNAME("pixLinearMapToTargetColor");
699 
700  if (!pixs || pixGetDepth(pixs) != 32)
701  return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, pixd);
702  if (pixd && (pixd != pixs))
703  return (PIX *)ERROR_PTR("pixd exists, but != pixs", procName, pixd);
704 
705  /* Do the work on pixd */
706  if (!pixd)
707  pixd = pixCopy(NULL, pixs);
708 
709  extractRGBValues(srcval, &rsval, &gsval, &bsval);
710  extractRGBValues(dstval, &rdval, &gdval, &bdval);
711  rsval = L_MIN(254, L_MAX(1, rsval));
712  gsval = L_MIN(254, L_MAX(1, gsval));
713  bsval = L_MIN(254, L_MAX(1, bsval));
714  rtab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
715  gtab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
716  btab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
717  if (!rtab || !gtab || !btab)
718  return (PIX *)ERROR_PTR("calloc fail for tab", procName, pixd);
719  for (i = 0; i < 256; i++) {
720  if (i <= rsval)
721  rtab[i] = (i * rdval) / rsval;
722  else
723  rtab[i] = rdval + ((255 - rdval) * (i - rsval)) / (255 - rsval);
724  if (i <= gsval)
725  gtab[i] = (i * gdval) / gsval;
726  else
727  gtab[i] = gdval + ((255 - gdval) * (i - gsval)) / (255 - gsval);
728  if (i <= bsval)
729  btab[i] = (i * bdval) / bsval;
730  else
731  btab[i] = bdval + ((255 - bdval) * (i - bsval)) / (255 - bsval);
732  }
733  pixGetDimensions(pixd, &w, &h, NULL);
734  data = pixGetData(pixd);
735  wpl = pixGetWpl(pixd);
736  for (i = 0; i < h; i++) {
737  line = data + i * wpl;
738  for (j = 0; j < w; j++) {
739  pixel = line[j];
740  extractRGBValues(pixel, &rval, &gval, &bval);
741  composeRGBPixel(rtab[rval], gtab[gval], btab[bval], &pixel);
742  line[j] = pixel;
743  }
744  }
745 
746  LEPT_FREE(rtab);
747  LEPT_FREE(gtab);
748  LEPT_FREE(btab);
749  return pixd;
750 }
751 
752 
781 l_ok
783  l_uint32 srcmap,
784  l_uint32 dstmap,
785  l_uint32 *pdcolor)
786 {
787 l_int32 srval, sgval, sbval, drval, dgval, dbval;
788 l_int32 srmap, sgmap, sbmap, drmap, dgmap, dbmap;
789 
790  PROCNAME("pixelLinearMapToTargetColor");
791 
792  if (!pdcolor)
793  return ERROR_INT("&dcolor not defined", procName, 1);
794  *pdcolor = 0;
795 
796  extractRGBValues(scolor, &srval, &sgval, &sbval);
797  extractRGBValues(srcmap, &srmap, &sgmap, &sbmap);
798  extractRGBValues(dstmap, &drmap, &dgmap, &dbmap);
799  srmap = L_MIN(254, L_MAX(1, srmap));
800  sgmap = L_MIN(254, L_MAX(1, sgmap));
801  sbmap = L_MIN(254, L_MAX(1, sbmap));
802 
803  if (srval <= srmap)
804  drval = (srval * drmap) / srmap;
805  else
806  drval = drmap + ((255 - drmap) * (srval - srmap)) / (255 - srmap);
807  if (sgval <= sgmap)
808  dgval = (sgval * dgmap) / sgmap;
809  else
810  dgval = dgmap + ((255 - dgmap) * (sgval - sgmap)) / (255 - sgmap);
811  if (sbval <= sbmap)
812  dbval = (sbval * dbmap) / sbmap;
813  else
814  dbval = dbmap + ((255 - dbmap) * (sbval - sbmap)) / (255 - sbmap);
815 
816  composeRGBPixel(drval, dgval, dbval, pdcolor);
817  return 0;
818 }
819 
820 
821 /*------------------------------------------------------------------*
822  * Fractional shift of RGB towards black or white *
823  *------------------------------------------------------------------*/
866 PIX *
868  PIX *pixs,
869  l_uint32 srcval,
870  l_uint32 dstval)
871 {
872 l_int32 i, j, w, h, wpl;
873 l_int32 rval, gval, bval, rsval, gsval, bsval, rdval, gdval, bdval;
874 l_int32 *rtab, *gtab, *btab;
875 l_uint32 pixel;
876 l_uint32 *line, *data;
877 PIXCMAP *cmap;
878 
879  PROCNAME("pixShiftByComponent");
880 
881  if (!pixs)
882  return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
883  if (pixd && (pixd != pixs))
884  return (PIX *)ERROR_PTR("pixd exists, but != pixs", procName, pixd);
885  if (pixGetDepth(pixs) != 32 && !pixGetColormap(pixs))
886  return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", procName, pixd);
887 
888  /* Do the work on pixd */
889  if (!pixd)
890  pixd = pixCopy(NULL, pixs);
891 
892  /* If colormapped, just modify it */
893  if ((cmap = pixGetColormap(pixd)) != NULL) {
894  pixcmapShiftByComponent(cmap, srcval, dstval);
895  return pixd;
896  }
897 
898  extractRGBValues(srcval, &rsval, &gsval, &bsval);
899  extractRGBValues(dstval, &rdval, &gdval, &bdval);
900  rtab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
901  gtab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
902  btab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
903  if (!rtab || !gtab || !btab) {
904  L_ERROR("calloc fail for tab\n", procName);
905  goto cleanup;
906  }
907  for (i = 0; i < 256; i++) {
908  if (rdval == rsval)
909  rtab[i] = i;
910  else if (rdval < rsval)
911  rtab[i] = (i * rdval) / rsval;
912  else
913  rtab[i] = 255 - (255 - rdval) * (255 - i) / (255 - rsval);
914  if (gdval == gsval)
915  gtab[i] = i;
916  else if (gdval < gsval)
917  gtab[i] = (i * gdval) / gsval;
918  else
919  gtab[i] = 255 - (255 - gdval) * (255 - i) / (255 - gsval);
920  if (bdval == bsval)
921  btab[i] = i;
922  else if (bdval < bsval)
923  btab[i] = (i * bdval) / bsval;
924  else
925  btab[i] = 255 - (255 - bdval) * (255 - i) / (255 - bsval);
926  }
927  pixGetDimensions(pixd, &w, &h, NULL);
928  data = pixGetData(pixd);
929  wpl = pixGetWpl(pixd);
930  for (i = 0; i < h; i++) {
931  line = data + i * wpl;
932  for (j = 0; j < w; j++) {
933  pixel = line[j];
934  extractRGBValues(pixel, &rval, &gval, &bval);
935  composeRGBPixel(rtab[rval], gtab[gval], btab[bval], &pixel);
936  line[j] = pixel;
937  }
938  }
939 
940 cleanup:
941  LEPT_FREE(rtab);
942  LEPT_FREE(gtab);
943  LEPT_FREE(btab);
944  return pixd;
945 }
946 
947 
967 l_ok
969  l_int32 gval,
970  l_int32 bval,
971  l_uint32 srcval,
972  l_uint32 dstval,
973  l_uint32 *ppixel)
974 {
975 l_int32 rsval, rdval, gsval, gdval, bsval, bdval, rs, gs, bs;
976 
977  PROCNAME("pixelShiftByComponent");
978 
979  if (!ppixel)
980  return ERROR_INT("&pixel defined", procName, 1);
981 
982  extractRGBValues(srcval, &rsval, &gsval, &bsval);
983  extractRGBValues(dstval, &rdval, &gdval, &bdval);
984  if (rdval == rsval)
985  rs = rval;
986  else if (rdval < rsval)
987  rs = (rval * rdval) / rsval;
988  else
989  rs = 255 - (255 - rdval) * (255 - rval) / (255 - rsval);
990  if (gdval == gsval)
991  gs = gval;
992  else if (gdval < gsval)
993  gs = (gval * gdval) / gsval;
994  else
995  gs = 255 - (255 - gdval) * (255 - gval) / (255 - gsval);
996  if (bdval == bsval)
997  bs = bval;
998  else if (bdval < bsval)
999  bs = (bval * bdval) / bsval;
1000  else
1001  bs = 255 - (255 - bdval) * (255 - bval) / (255 - bsval);
1002  composeRGBPixel(rs, gs, bs, ppixel);
1003  return 0;
1004 }
1005 
1006 
1030 l_ok
1032  l_int32 gval,
1033  l_int32 bval,
1034  l_float32 fract,
1035  l_uint32 *ppixel)
1036 {
1037 l_int32 nrval, ngval, nbval;
1038 
1039  PROCNAME("pixelFractionalShift");
1040 
1041  if (!ppixel)
1042  return ERROR_INT("&pixel defined", procName, 1);
1043  if (fract < -1.0 || fract > 1.0)
1044  return ERROR_INT("fraction not in [-1 ... +1]", procName, 1);
1045 
1046  nrval = (fract < 0) ? (l_int32)((1.0 + fract) * rval + 0.5) :
1047  rval + (l_int32)(fract * (255 - rval) + 0.5);
1048  ngval = (fract < 0) ? (l_int32)((1.0 + fract) * gval + 0.5) :
1049  gval + (l_int32)(fract * (255 - gval) + 0.5);
1050  nbval = (fract < 0) ? (l_int32)((1.0 + fract) * bval + 0.5) :
1051  bval + (l_int32)(fract * (255 - bval) + 0.5);
1052  composeRGBPixel(nrval, ngval, nbval, ppixel);
1053  return 0;
1054 }
1055 
1056 
1081 PIX *
1083  PIX *pixs,
1084  l_uint32 srcval,
1085  l_float32 fract)
1086 {
1087 l_int32 rval, gval, bval;
1088 l_uint32 dstval;
1089 
1090  PROCNAME("pixMapWithInvariantHue");
1091 
1092  if (!pixs || pixGetDepth(pixs) != 32)
1093  return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, pixd);
1094  if (pixd && (pixd != pixs))
1095  return (PIX *)ERROR_PTR("pixd exists, but != pixs", procName, pixd);
1096  if (fract < -1.0 || fract > 1.0)
1097  return (PIX *)ERROR_PTR("fraction not in [-1 ... +1]", procName, NULL);
1098 
1099  /* Generate the dstval that is %fract toward white from %srcval */
1100  extractRGBValues(srcval, &rval, &gval, &bval);
1101  pixelFractionalShift(rval, gval, bval, fract, &dstval);
1102 
1103  /* Use the (%srcval, dstval) pair to define the linear transform */
1104  return pixLinearMapToTargetColor(pixd, pixs, srcval, dstval);
1105 }
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:198
#define GET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:123
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:282
l_int32 boxaGetCount(BOXA *boxa)
boxaGetCount()
Definition: boxbasic.c:734
l_ok boxGetGeometry(BOX *box, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxGetGeometry()
Definition: boxbasic.c:313
BOX * boxaGetBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetBox()
Definition: boxbasic.c:779
PIX * pixColorGrayRegions(PIX *pixs, BOXA *boxa, l_int32 type, l_int32 thresh, l_int32 rval, l_int32 gval, l_int32 bval)
pixColorGrayRegions()
Definition: coloring.c:131
PIX * pixColorGrayMasked(PIX *pixs, PIX *pixm, l_int32 type, l_int32 thresh, l_int32 rval, l_int32 gval, l_int32 bval)
pixColorGrayMasked()
Definition: coloring.c:358
PIX * pixLinearMapToTargetColor(PIX *pixd, PIX *pixs, l_uint32 srcval, l_uint32 dstval)
pixLinearMapToTargetColor()
Definition: coloring.c:687
PIX * pixSnapColor(PIX *pixd, PIX *pixs, l_uint32 srcval, l_uint32 dstval, l_int32 diff)
pixSnapColor()
Definition: coloring.c:483
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 pixelLinearMapToTargetColor(l_uint32 scolor, l_uint32 srcmap, l_uint32 dstmap, l_uint32 *pdcolor)
pixelLinearMapToTargetColor()
Definition: coloring.c:782
l_ok pixColorGray(PIX *pixs, BOX *box, l_int32 type, l_int32 thresh, l_int32 rval, l_int32 gval, l_int32 bval)
pixColorGray()
Definition: coloring.c:232
PIX * pixSnapColorCmap(PIX *pixd, PIX *pixs, l_uint32 srcval, l_uint32 dstval, l_int32 diff)
pixSnapColorCmap()
Definition: coloring.c:570
PIX * pixShiftByComponent(PIX *pixd, PIX *pixs, l_uint32 srcval, l_uint32 dstval)
pixShiftByComponent()
Definition: coloring.c:867
l_ok pixelFractionalShift(l_int32 rval, l_int32 gval, l_int32 bval, l_float32 fract, l_uint32 *ppixel)
pixelFractionalShift()
Definition: coloring.c:1031
PIX * pixMapWithInvariantHue(PIX *pixd, PIX *pixs, l_uint32 srcval, l_float32 fract)
pixMapWithInvariantHue()
Definition: coloring.c:1082
l_int32 pixcmapGetCount(const PIXCMAP *cmap)
pixcmapGetCount()
Definition: colormap.c:708
l_ok pixcmapResetColor(PIXCMAP *cmap, l_int32 index, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapResetColor()
Definition: colormap.c:966
l_ok pixcmapCountGrayColors(PIXCMAP *cmap, l_int32 *pngray)
pixcmapCountGrayColors()
Definition: colormap.c:1261
l_ok pixcmapGetColor(PIXCMAP *cmap, l_int32 index, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
pixcmapGetColor()
Definition: colormap.c:824
l_int32 pixcmapGetFreeCount(PIXCMAP *cmap)
pixcmapGetFreeCount()
Definition: colormap.c:725
l_ok pixcmapShiftByComponent(PIXCMAP *cmap, l_uint32 srcval, l_uint32 dstval)
pixcmapShiftByComponent()
Definition: colormap.c:2487
l_ok pixcmapAddColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapAddColor()
Definition: colormap.c:414
l_ok pixRemoveUnusedColors(PIX *pixs)
pixRemoveUnusedColors()
Definition: colorquant1.c:3936
l_ok pixColorGrayCmap(PIX *pixs, BOX *box, l_int32 type, l_int32 rval, l_int32 gval, l_int32 bval)
pixColorGrayCmap()
Definition: paintcmap.c:331
l_ok pixColorGrayMaskedCmap(PIX *pixs, PIX *pixm, l_int32 type, l_int32 rval, l_int32 gval, l_int32 bval)
pixColorGrayMaskedCmap()
Definition: paintcmap.c:399
l_ok pixColorGrayRegionsCmap(PIX *pixs, BOXA *boxa, l_int32 type, l_int32 rval, l_int32 gval, l_int32 bval)
pixColorGrayRegionsCmap()
Definition: paintcmap.c:223
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1763
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:621
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1113
PIX * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:705
l_ok pixTransferAllData(PIX *pixd, PIX **ppixs, l_int32 copytext, l_int32 copyformat)
pixTransferAllData()
Definition: pix1.c:902
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2751
void extractRGBValues(l_uint32 pixel, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
extractRGBValues()
Definition: pix2.c:2820
l_ok pixSetMasked(PIX *pixd, PIX *pixm, l_uint32 val)
pixSetMasked()
Definition: pix3.c:163
PIX * pixMakeMaskFromLUT(PIX *pixs, l_int32 *tab)
pixMakeMaskFromLUT()
Definition: pix3.c:1062
@ L_CLONE
Definition: pix.h:713
@ L_PAINT_LIGHT
Definition: pix.h:763
@ L_PAINT_DARK
Definition: pix.h:764
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3133
PIX * pixConvertTo32(PIX *pixs)
pixConvertTo32()
Definition: pixconv.c:3332
Definition: pix.h:481
Definition: pix.h:492
Definition: pix.h:139