Leptonica  1.83.1
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  if (!pixs || pixGetDepth(pixs) == 1)
145  return (PIX *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL);
146  if (!boxa)
147  return (PIX *)ERROR_PTR("boxa not defined", __func__, NULL);
148  if (type != L_PAINT_LIGHT && type != L_PAINT_DARK)
149  return (PIX *)ERROR_PTR("invalid type", __func__, NULL);
150 
151  /* If cmapped and there is room in an 8 bpp colormap for
152  * expansion, convert pixs to 8 bpp, and colorize. */
153  cmap = pixGetColormap(pixs);
154  if (cmap) {
155  ncolors = pixcmapGetCount(cmap);
156  pixcmapCountGrayColors(cmap, &ngray);
157  if (ncolors + ngray < 255) {
158  pixd = pixConvertTo8(pixs, 1); /* always new image */
159  pixColorGrayRegionsCmap(pixd, boxa, type, rval, gval, bval);
160  return pixd;
161  }
162  }
163 
164  /* The output will be rgb. Make sure the thresholds are valid */
165  if (type == L_PAINT_LIGHT) { /* thresh should be low */
166  if (thresh >= 255)
167  return (PIX *)ERROR_PTR("thresh must be < 255", __func__, NULL);
168  if (thresh > 127)
169  L_WARNING("threshold set very high\n", __func__);
170  } else { /* type == L_PAINT_DARK; thresh should be high */
171  if (thresh <= 0)
172  return (PIX *)ERROR_PTR("thresh must be > 0", __func__, NULL);
173  if (thresh < 128)
174  L_WARNING("threshold set very low\n", __func__);
175  }
176 
177  pixd = pixConvertTo32(pixs); /* always new image */
178  n = boxaGetCount(boxa);
179  for (i = 0; i < n; i++) {
180  box = boxaGetBox(boxa, i, L_CLONE);
181  pixColorGray(pixd, box, type, thresh, rval, gval, bval);
182  boxDestroy(&box);
183  }
184 
185  return pixd;
186 }
187 
188 
229 l_ok
231  BOX *box,
232  l_int32 type,
233  l_int32 thresh,
234  l_int32 rval,
235  l_int32 gval,
236  l_int32 bval)
237 {
238 l_int32 i, j, w, h, d, wpl, x1, x2, y1, y2, bw, bh;
239 l_int32 nrval, ngval, nbval, aveval;
240 l_float32 factor;
241 l_uint32 val32;
242 l_uint32 *line, *data;
243 PIX *pixt;
244 PIXCMAP *cmap;
245 
246  if (!pixs)
247  return ERROR_INT("pixs not defined", __func__, 1);
248  if (type != L_PAINT_LIGHT && type != L_PAINT_DARK)
249  return ERROR_INT("invalid type", __func__, 1);
250 
251  cmap = pixGetColormap(pixs);
252  pixGetDimensions(pixs, &w, &h, &d);
253  if (!cmap && d != 8 && d != 32)
254  return ERROR_INT("pixs not cmapped, 8 bpp or rgb", __func__, 1);
255  if (cmap)
256  return pixColorGrayCmap(pixs, box, type, rval, gval, bval);
257 
258  /* rgb or 8 bpp gray image; check the thresh */
259  if (type == L_PAINT_LIGHT) { /* thresh should be low */
260  if (thresh >= 255)
261  return ERROR_INT("thresh must be < 255; else this is a no-op",
262  __func__, 1);
263  if (thresh > 127)
264  L_WARNING("threshold set very high\n", __func__);
265  } else { /* type == L_PAINT_DARK; thresh should be high */
266  if (thresh <= 0)
267  return ERROR_INT("thresh must be > 0; else this is a no-op",
268  __func__, 1);
269  if (thresh < 128)
270  L_WARNING("threshold set very low\n", __func__);
271  }
272 
273  /* In-place conversion to 32 bpp if necessary */
274  if (d == 8) {
275  pixt = pixConvertTo32(pixs);
276  pixTransferAllData(pixs, &pixt, 1, 0);
277  }
278 
279  if (!box) {
280  x1 = y1 = 0;
281  x2 = w;
282  y2 = h;
283  } else {
284  boxGetGeometry(box, &x1, &y1, &bw, &bh);
285  x2 = x1 + bw - 1;
286  y2 = y1 + bh - 1;
287  }
288 
289  data = pixGetData(pixs);
290  wpl = pixGetWpl(pixs);
291  factor = 1. / 255.;
292  for (i = y1; i <= y2; i++) {
293  if (i < 0 || i >= h)
294  continue;
295  line = data + i * wpl;
296  for (j = x1; j <= x2; j++) {
297  if (j < 0 || j >= w)
298  continue;
299  val32 = *(line + j);
300  aveval = ((val32 >> 24) + ((val32 >> 16) & 0xff) +
301  ((val32 >> 8) & 0xff)) / 3;
302  if (type == L_PAINT_LIGHT) {
303  if (aveval < thresh) /* skip sufficiently dark pixels */
304  continue;
305  nrval = (l_int32)(rval * aveval * factor);
306  ngval = (l_int32)(gval * aveval * factor);
307  nbval = (l_int32)(bval * aveval * factor);
308  } else { /* type == L_PAINT_DARK */
309  if (aveval > thresh) /* skip sufficiently light pixels */
310  continue;
311  nrval = rval + (l_int32)((255. - rval) * aveval * factor);
312  ngval = gval + (l_int32)((255. - gval) * aveval * factor);
313  nbval = bval + (l_int32)((255. - bval) * aveval * factor);
314  }
315  composeRGBPixel(nrval, ngval, nbval, &val32);
316  *(line + j) = val32;
317  }
318  }
319 
320  return 0;
321 }
322 
323 
353 PIX *
355  PIX *pixm,
356  l_int32 type,
357  l_int32 thresh,
358  l_int32 rval,
359  l_int32 gval,
360  l_int32 bval)
361 {
362 l_int32 i, j, w, h, d, wm, hm, wmin, hmin, wpl, wplm;
363 l_int32 nrval, ngval, nbval, aveval;
364 l_float32 factor;
365 l_uint32 val32;
366 l_uint32 *line, *data, *linem, *datam;
367 PIX *pixd;
368 PIXCMAP *cmap;
369 
370  if (!pixs)
371  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
372  if (!pixm || pixGetDepth(pixm) != 1)
373  return (PIX *)ERROR_PTR("pixm undefined or not 1 bpp", __func__, NULL);
374  if (type != L_PAINT_LIGHT && type != L_PAINT_DARK)
375  return (PIX *)ERROR_PTR("invalid type", __func__, NULL);
376 
377  cmap = pixGetColormap(pixs);
378  pixGetDimensions(pixs, &w, &h, &d);
379  if (!cmap && d != 8 && d != 32)
380  return (PIX *)ERROR_PTR("pixs not cmapped, 8 bpp gray or 32 bpp",
381  __func__, NULL);
382  if (cmap) {
383  pixd = pixCopy(NULL, pixs);
384  pixColorGrayMaskedCmap(pixd, pixm, type, rval, gval, bval);
385  return pixd;
386  }
387 
388  /* rgb or 8 bpp gray image; check the thresh */
389  if (type == L_PAINT_LIGHT) { /* thresh should be low */
390  if (thresh >= 255)
391  return (PIX *)ERROR_PTR(
392  "thresh must be < 255; else this is a no-op", __func__, NULL);
393  if (thresh > 127)
394  L_WARNING("threshold set very high\n", __func__);
395  } else { /* type == L_PAINT_DARK; thresh should be high */
396  if (thresh <= 0)
397  return (PIX *)ERROR_PTR(
398  "thresh must be > 0; else this is a no-op", __func__, NULL);
399  if (thresh < 128)
400  L_WARNING("threshold set very low\n", __func__);
401  }
402 
403  pixGetDimensions(pixm, &wm, &hm, NULL);
404  if (wm != w)
405  L_WARNING("wm = %d differs from w = %d\n", __func__, wm, w);
406  if (hm != h)
407  L_WARNING("hm = %d differs from h = %d\n", __func__, hm, h);
408  wmin = L_MIN(w, wm);
409  hmin = L_MIN(h, hm);
410  if (d == 8)
411  pixd = pixConvertTo32(pixs);
412  else
413  pixd = pixCopy(NULL, pixs);
414 
415  data = pixGetData(pixd);
416  wpl = pixGetWpl(pixd);
417  datam = pixGetData(pixm);
418  wplm = pixGetWpl(pixm);
419  factor = 1. / 255.;
420  for (i = 0; i < hmin; i++) {
421  line = data + i * wpl;
422  linem = datam + i * wplm;
423  for (j = 0; j < wmin; j++) {
424  if (GET_DATA_BIT(linem, j) == 0)
425  continue;
426  val32 = *(line + j);
427  aveval = ((val32 >> 24) + ((val32 >> 16) & 0xff) +
428  ((val32 >> 8) & 0xff)) / 3;
429  if (type == L_PAINT_LIGHT) {
430  if (aveval < thresh) /* skip sufficiently dark pixels */
431  continue;
432  nrval = (l_int32)(rval * aveval * factor);
433  ngval = (l_int32)(gval * aveval * factor);
434  nbval = (l_int32)(bval * aveval * factor);
435  } else { /* type == L_PAINT_DARK */
436  if (aveval > thresh) /* skip sufficiently light pixels */
437  continue;
438  nrval = rval + (l_int32)((255. - rval) * aveval * factor);
439  ngval = gval + (l_int32)((255. - gval) * aveval * factor);
440  nbval = bval + (l_int32)((255. - bval) * aveval * factor);
441  }
442  composeRGBPixel(nrval, ngval, nbval, &val32);
443  *(line + j) = val32;
444  }
445  }
446 
447  return pixd;
448 }
449 
450 
451 /*------------------------------------------------------------------*
452  * Adjusting one or more colors to a target color *
453  *------------------------------------------------------------------*/
476 PIX *
478  PIX *pixs,
479  l_uint32 srcval,
480  l_uint32 dstval,
481  l_int32 diff)
482 {
483 l_int32 val, sval, dval;
484 l_int32 rval, gval, bval, rsval, gsval, bsval;
485 l_int32 i, j, w, h, d, wpl;
486 l_uint32 pixel;
487 l_uint32 *line, *data;
488 
489  if (!pixs)
490  return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd);
491  if (pixd && (pixd != pixs))
492  return (PIX *)ERROR_PTR("pixd exists, but != pixs", __func__, pixd);
493 
494  if (pixGetColormap(pixs))
495  return pixSnapColorCmap(pixd, pixs, srcval, dstval, diff);
496 
497  /* pixs does not have a colormap; it must be 8 bpp gray or
498  * 32 bpp rgb. */
499  if (pixGetDepth(pixs) < 8)
500  return (PIX *)ERROR_PTR("pixs is < 8 bpp", __func__, pixd);
501 
502  /* Do the work on pixd */
503  if (!pixd)
504  pixd = pixCopy(NULL, pixs);
505 
506  pixGetDimensions(pixd, &w, &h, &d);
507  data = pixGetData(pixd);
508  wpl = pixGetWpl(pixd);
509  if (d == 8) {
510  sval = srcval & 0xff;
511  dval = dstval & 0xff;
512  for (i = 0; i < h; i++) {
513  line = data + i * wpl;
514  for (j = 0; j < w; j++) {
515  val = GET_DATA_BYTE(line, j);
516  if (L_ABS(val - sval) <= diff)
517  SET_DATA_BYTE(line, j, dval);
518  }
519  }
520  } else { /* d == 32 */
521  extractRGBValues(srcval, &rsval, &gsval, &bsval);
522  for (i = 0; i < h; i++) {
523  line = data + i * wpl;
524  for (j = 0; j < w; j++) {
525  pixel = *(line + j);
526  extractRGBValues(pixel, &rval, &gval, &bval);
527  if ((L_ABS(rval - rsval) <= diff) &&
528  (L_ABS(gval - gsval) <= diff) &&
529  (L_ABS(bval - bsval) <= diff))
530  *(line + j) = dstval; /* replace */
531  }
532  }
533  }
534 
535  return pixd;
536 }
537 
538 
561 PIX *
563  PIX *pixs,
564  l_uint32 srcval,
565  l_uint32 dstval,
566  l_int32 diff)
567 {
568 l_int32 i, ncolors, index, found;
569 l_int32 rval, gval, bval, rsval, gsval, bsval, rdval, gdval, bdval;
570 l_int32 *tab;
571 PIX *pixm;
572 PIXCMAP *cmap;
573 
574  if (!pixs)
575  return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd);
576  if (!pixGetColormap(pixs))
577  return (PIX *)ERROR_PTR("cmap not found", __func__, pixd);
578  if (pixd && (pixd != pixs))
579  return (PIX *)ERROR_PTR("pixd exists, but != pixs", __func__, pixd);
580 
581  if (!pixd)
582  pixd = pixCopy(NULL, pixs);
583 
584  /* If no free colors, look for one close to the target
585  * that can be commandeered. */
586  cmap = pixGetColormap(pixd);
587  ncolors = pixcmapGetCount(cmap);
588  extractRGBValues(srcval, &rsval, &gsval, &bsval);
589  extractRGBValues(dstval, &rdval, &gdval, &bdval);
590  found = FALSE;
591  if (pixcmapGetFreeCount(cmap) == 0) {
592  for (i = 0; i < ncolors; i++) {
593  pixcmapGetColor(cmap, i, &rval, &gval, &bval);
594  if ((L_ABS(rval - rsval) <= diff) &&
595  (L_ABS(gval - gsval) <= diff) &&
596  (L_ABS(bval - bsval) <= diff)) {
597  index = i;
598  pixcmapResetColor(cmap, index, rdval, gdval, bdval);
599  found = TRUE;
600  break;
601  }
602  }
603  } else { /* just add the new color */
604  pixcmapAddColor(cmap, rdval, gdval, bdval);
605  ncolors = pixcmapGetCount(cmap);
606  index = ncolors - 1; /* index of new destination color */
607  found = TRUE;
608  }
609 
610  if (!found) {
611  L_INFO("nothing to do\n", __func__);
612  return pixd;
613  }
614 
615  /* For each color in cmap that is close enough to srcval,
616  * set the tab value to 1. Then generate a 1 bpp mask with
617  * fg pixels for every pixel in pixd that is close enough
618  * to srcval (i.e., has value 1 in tab). */
619  tab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
620  for (i = 0; i < ncolors; i++) {
621  pixcmapGetColor(cmap, i, &rval, &gval, &bval);
622  if ((L_ABS(rval - rsval) <= diff) &&
623  (L_ABS(gval - gsval) <= diff) &&
624  (L_ABS(bval - bsval) <= diff))
625  tab[i] = 1;
626  }
627  pixm = pixMakeMaskFromLUT(pixd, tab);
628  LEPT_FREE(tab);
629 
630  /* Use the binary mask to set all selected pixels to
631  * the dest color index. */
632  pixSetMasked(pixd, pixm, dstval);
633  pixDestroy(&pixm);
634 
635  /* Remove all unused colors from the colormap. */
636  pixRemoveUnusedColors(pixd);
637 
638  return pixd;
639 }
640 
641 
642 /*---------------------------------------------------------------------*
643  * Piecewise linear color mapping based on a source/target pair *
644  *---------------------------------------------------------------------*/
676 PIX *
678  PIX *pixs,
679  l_uint32 srcval,
680  l_uint32 dstval)
681 {
682 l_int32 i, j, w, h, wpl;
683 l_int32 rval, gval, bval, rsval, gsval, bsval, rdval, gdval, bdval;
684 l_int32 *rtab, *gtab, *btab;
685 l_uint32 pixel;
686 l_uint32 *line, *data;
687 
688  if (!pixs || pixGetDepth(pixs) != 32)
689  return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", __func__, pixd);
690  if (pixd && (pixd != pixs))
691  return (PIX *)ERROR_PTR("pixd exists, but != pixs", __func__, pixd);
692 
693  /* Do the work on pixd */
694  if (!pixd)
695  pixd = pixCopy(NULL, pixs);
696 
697  extractRGBValues(srcval, &rsval, &gsval, &bsval);
698  extractRGBValues(dstval, &rdval, &gdval, &bdval);
699  rsval = L_MIN(254, L_MAX(1, rsval));
700  gsval = L_MIN(254, L_MAX(1, gsval));
701  bsval = L_MIN(254, L_MAX(1, bsval));
702  rtab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
703  gtab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
704  btab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
705  if (!rtab || !gtab || !btab)
706  return (PIX *)ERROR_PTR("calloc fail for tab", __func__, pixd);
707  for (i = 0; i < 256; i++) {
708  if (i <= rsval)
709  rtab[i] = (i * rdval) / rsval;
710  else
711  rtab[i] = rdval + ((255 - rdval) * (i - rsval)) / (255 - rsval);
712  if (i <= gsval)
713  gtab[i] = (i * gdval) / gsval;
714  else
715  gtab[i] = gdval + ((255 - gdval) * (i - gsval)) / (255 - gsval);
716  if (i <= bsval)
717  btab[i] = (i * bdval) / bsval;
718  else
719  btab[i] = bdval + ((255 - bdval) * (i - bsval)) / (255 - bsval);
720  }
721  pixGetDimensions(pixd, &w, &h, NULL);
722  data = pixGetData(pixd);
723  wpl = pixGetWpl(pixd);
724  for (i = 0; i < h; i++) {
725  line = data + i * wpl;
726  for (j = 0; j < w; j++) {
727  pixel = line[j];
728  extractRGBValues(pixel, &rval, &gval, &bval);
729  composeRGBPixel(rtab[rval], gtab[gval], btab[bval], &pixel);
730  line[j] = pixel;
731  }
732  }
733 
734  LEPT_FREE(rtab);
735  LEPT_FREE(gtab);
736  LEPT_FREE(btab);
737  return pixd;
738 }
739 
740 
769 l_ok
771  l_uint32 srcmap,
772  l_uint32 dstmap,
773  l_uint32 *pdcolor)
774 {
775 l_int32 srval, sgval, sbval, drval, dgval, dbval;
776 l_int32 srmap, sgmap, sbmap, drmap, dgmap, dbmap;
777 
778  if (!pdcolor)
779  return ERROR_INT("&dcolor not defined", __func__, 1);
780  *pdcolor = 0;
781 
782  extractRGBValues(scolor, &srval, &sgval, &sbval);
783  extractRGBValues(srcmap, &srmap, &sgmap, &sbmap);
784  extractRGBValues(dstmap, &drmap, &dgmap, &dbmap);
785  srmap = L_MIN(254, L_MAX(1, srmap));
786  sgmap = L_MIN(254, L_MAX(1, sgmap));
787  sbmap = L_MIN(254, L_MAX(1, sbmap));
788 
789  if (srval <= srmap)
790  drval = (srval * drmap) / srmap;
791  else
792  drval = drmap + ((255 - drmap) * (srval - srmap)) / (255 - srmap);
793  if (sgval <= sgmap)
794  dgval = (sgval * dgmap) / sgmap;
795  else
796  dgval = dgmap + ((255 - dgmap) * (sgval - sgmap)) / (255 - sgmap);
797  if (sbval <= sbmap)
798  dbval = (sbval * dbmap) / sbmap;
799  else
800  dbval = dbmap + ((255 - dbmap) * (sbval - sbmap)) / (255 - sbmap);
801 
802  composeRGBPixel(drval, dgval, dbval, pdcolor);
803  return 0;
804 }
805 
806 
807 /*------------------------------------------------------------------*
808  * Fractional shift of RGB towards black or white *
809  *------------------------------------------------------------------*/
852 PIX *
854  PIX *pixs,
855  l_uint32 srcval,
856  l_uint32 dstval)
857 {
858 l_int32 i, j, w, h, wpl;
859 l_int32 rval, gval, bval, rsval, gsval, bsval, rdval, gdval, bdval;
860 l_int32 *rtab, *gtab, *btab;
861 l_uint32 pixel;
862 l_uint32 *line, *data;
863 PIXCMAP *cmap;
864 
865  if (!pixs)
866  return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd);
867  if (pixd && (pixd != pixs))
868  return (PIX *)ERROR_PTR("pixd exists, but != pixs", __func__, pixd);
869  if (pixGetDepth(pixs) != 32 && !pixGetColormap(pixs))
870  return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", __func__, pixd);
871 
872  /* Do the work on pixd */
873  if (!pixd)
874  pixd = pixCopy(NULL, pixs);
875 
876  /* If colormapped, just modify it */
877  if ((cmap = pixGetColormap(pixd)) != NULL) {
878  pixcmapShiftByComponent(cmap, srcval, dstval);
879  return pixd;
880  }
881 
882  extractRGBValues(srcval, &rsval, &gsval, &bsval);
883  extractRGBValues(dstval, &rdval, &gdval, &bdval);
884  rtab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
885  gtab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
886  btab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
887  if (!rtab || !gtab || !btab) {
888  L_ERROR("calloc fail for tab\n", __func__);
889  goto cleanup;
890  }
891  for (i = 0; i < 256; i++) {
892  if (rdval == rsval)
893  rtab[i] = i;
894  else if (rdval < rsval)
895  rtab[i] = (i * rdval) / rsval;
896  else
897  rtab[i] = 255 - (255 - rdval) * (255 - i) / (255 - rsval);
898  if (gdval == gsval)
899  gtab[i] = i;
900  else if (gdval < gsval)
901  gtab[i] = (i * gdval) / gsval;
902  else
903  gtab[i] = 255 - (255 - gdval) * (255 - i) / (255 - gsval);
904  if (bdval == bsval)
905  btab[i] = i;
906  else if (bdval < bsval)
907  btab[i] = (i * bdval) / bsval;
908  else
909  btab[i] = 255 - (255 - bdval) * (255 - i) / (255 - bsval);
910  }
911  pixGetDimensions(pixd, &w, &h, NULL);
912  data = pixGetData(pixd);
913  wpl = pixGetWpl(pixd);
914  for (i = 0; i < h; i++) {
915  line = data + i * wpl;
916  for (j = 0; j < w; j++) {
917  pixel = line[j];
918  extractRGBValues(pixel, &rval, &gval, &bval);
919  composeRGBPixel(rtab[rval], gtab[gval], btab[bval], &pixel);
920  line[j] = pixel;
921  }
922  }
923 
924 cleanup:
925  LEPT_FREE(rtab);
926  LEPT_FREE(gtab);
927  LEPT_FREE(btab);
928  return pixd;
929 }
930 
931 
951 l_ok
953  l_int32 gval,
954  l_int32 bval,
955  l_uint32 srcval,
956  l_uint32 dstval,
957  l_uint32 *ppixel)
958 {
959 l_int32 rsval, rdval, gsval, gdval, bsval, bdval, rs, gs, bs;
960 
961  if (!ppixel)
962  return ERROR_INT("&pixel defined", __func__, 1);
963 
964  extractRGBValues(srcval, &rsval, &gsval, &bsval);
965  extractRGBValues(dstval, &rdval, &gdval, &bdval);
966  if (rdval == rsval)
967  rs = rval;
968  else if (rdval < rsval)
969  rs = (rval * rdval) / rsval;
970  else
971  rs = 255 - (255 - rdval) * (255 - rval) / (255 - rsval);
972  if (gdval == gsval)
973  gs = gval;
974  else if (gdval < gsval)
975  gs = (gval * gdval) / gsval;
976  else
977  gs = 255 - (255 - gdval) * (255 - gval) / (255 - gsval);
978  if (bdval == bsval)
979  bs = bval;
980  else if (bdval < bsval)
981  bs = (bval * bdval) / bsval;
982  else
983  bs = 255 - (255 - bdval) * (255 - bval) / (255 - bsval);
984  composeRGBPixel(rs, gs, bs, ppixel);
985  return 0;
986 }
987 
988 
1012 l_ok
1014  l_int32 gval,
1015  l_int32 bval,
1016  l_float32 fract,
1017  l_uint32 *ppixel)
1018 {
1019 l_int32 nrval, ngval, nbval;
1020 
1021  if (!ppixel)
1022  return ERROR_INT("&pixel defined", __func__, 1);
1023  if (fract < -1.0 || fract > 1.0)
1024  return ERROR_INT("fraction not in [-1 ... +1]", __func__, 1);
1025 
1026  nrval = (fract < 0) ? (l_int32)((1.0 + fract) * rval + 0.5) :
1027  rval + (l_int32)(fract * (255 - rval) + 0.5);
1028  ngval = (fract < 0) ? (l_int32)((1.0 + fract) * gval + 0.5) :
1029  gval + (l_int32)(fract * (255 - gval) + 0.5);
1030  nbval = (fract < 0) ? (l_int32)((1.0 + fract) * bval + 0.5) :
1031  bval + (l_int32)(fract * (255 - bval) + 0.5);
1032  composeRGBPixel(nrval, ngval, nbval, ppixel);
1033  return 0;
1034 }
1035 
1036 
1061 PIX *
1063  PIX *pixs,
1064  l_uint32 srcval,
1065  l_float32 fract)
1066 {
1067 l_int32 rval, gval, bval;
1068 l_uint32 dstval;
1069 
1070  if (!pixs || pixGetDepth(pixs) != 32)
1071  return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", __func__, pixd);
1072  if (pixd && (pixd != pixs))
1073  return (PIX *)ERROR_PTR("pixd exists, but != pixs", __func__, pixd);
1074  if (fract < -1.0 || fract > 1.0)
1075  return (PIX *)ERROR_PTR("fraction not in [-1 ... +1]", __func__, NULL);
1076 
1077  /* Generate the dstval that is %fract toward white from %srcval */
1078  extractRGBValues(srcval, &rval, &gval, &bval);
1079  pixelFractionalShift(rval, gval, bval, fract, &dstval);
1080 
1081  /* Use the (%srcval, dstval) pair to define the linear transform */
1082  return pixLinearMapToTargetColor(pixd, pixs, srcval, dstval);
1083 }
#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
l_ok boxGetGeometry(const BOX *box, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxGetGeometry()
Definition: boxbasic.c:301
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:273
l_int32 boxaGetCount(const BOXA *boxa)
boxaGetCount()
Definition: boxbasic.c:661
BOX * boxaGetBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetBox()
Definition: boxbasic.c:702
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:354
PIX * pixLinearMapToTargetColor(PIX *pixd, PIX *pixs, l_uint32 srcval, l_uint32 dstval)
pixLinearMapToTargetColor()
Definition: coloring.c:677
PIX * pixSnapColor(PIX *pixd, PIX *pixs, l_uint32 srcval, l_uint32 dstval, l_int32 diff)
pixSnapColor()
Definition: coloring.c:477
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 pixelLinearMapToTargetColor(l_uint32 scolor, l_uint32 srcmap, l_uint32 dstmap, l_uint32 *pdcolor)
pixelLinearMapToTargetColor()
Definition: coloring.c:770
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:230
PIX * pixSnapColorCmap(PIX *pixd, PIX *pixs, l_uint32 srcval, l_uint32 dstval, l_int32 diff)
pixSnapColorCmap()
Definition: coloring.c:562
PIX * pixShiftByComponent(PIX *pixd, PIX *pixs, l_uint32 srcval, l_uint32 dstval)
pixShiftByComponent()
Definition: coloring.c:853
l_ok pixelFractionalShift(l_int32 rval, l_int32 gval, l_int32 bval, l_float32 fract, l_uint32 *ppixel)
pixelFractionalShift()
Definition: coloring.c:1013
PIX * pixMapWithInvariantHue(PIX *pixd, PIX *pixs, l_uint32 srcval, l_float32 fract)
pixMapWithInvariantHue()
Definition: coloring.c:1062
l_int32 pixcmapGetCount(const PIXCMAP *cmap)
pixcmapGetCount()
Definition: colormap.c:683
l_ok pixcmapResetColor(PIXCMAP *cmap, l_int32 index, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapResetColor()
Definition: colormap.c:923
l_ok pixcmapCountGrayColors(PIXCMAP *cmap, l_int32 *pngray)
pixcmapCountGrayColors()
Definition: colormap.c:1204
l_ok pixcmapGetColor(PIXCMAP *cmap, l_int32 index, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
pixcmapGetColor()
Definition: colormap.c:789
l_int32 pixcmapGetFreeCount(PIXCMAP *cmap)
pixcmapGetFreeCount()
Definition: colormap.c:698
l_ok pixcmapShiftByComponent(PIXCMAP *cmap, l_uint32 srcval, l_uint32 dstval)
pixcmapShiftByComponent()
Definition: colormap.c:2384
l_ok pixcmapAddColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapAddColor()
Definition: colormap.c:403
l_ok pixRemoveUnusedColors(PIX *pixs)
pixRemoveUnusedColors()
Definition: colorquant1.c:3891
l_ok pixColorGrayCmap(PIX *pixs, BOX *box, l_int32 type, l_int32 rval, l_int32 gval, l_int32 bval)
pixColorGrayCmap()
Definition: paintcmap.c:327
l_ok pixColorGrayMaskedCmap(PIX *pixs, PIX *pixm, l_int32 type, l_int32 rval, l_int32 gval, l_int32 bval)
pixColorGrayMaskedCmap()
Definition: paintcmap.c:393
l_ok pixColorGrayRegionsCmap(PIX *pixs, BOXA *boxa, l_int32 type, l_int32 rval, l_int32 gval, l_int32 bval)
pixColorGrayRegionsCmap()
Definition: paintcmap.c:221
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1642
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:608
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1074
PIX * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:689
l_ok pixTransferAllData(PIX *pixd, PIX **ppixs, l_int32 copytext, l_int32 copyformat)
pixTransferAllData()
Definition: pix1.c:879
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2728
void extractRGBValues(l_uint32 pixel, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
extractRGBValues()
Definition: pix2.c:2793
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:1046
@ L_CLONE
Definition: pix.h:506
@ L_PAINT_LIGHT
Definition: pix.h:556
@ L_PAINT_DARK
Definition: pix.h:557
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3055
PIX * pixConvertTo32(PIX *pixs)
pixConvertTo32()
Definition: pixconv.c:3246