Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
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 *---------------------------------------------------------------------*/
130PIX *
132 BOXA *boxa,
133 l_int32 type,
134 l_int32 thresh,
135 l_int32 rval,
136 l_int32 gval,
137 l_int32 bval)
138{
139l_int32 i, n, ncolors, ngray;
140BOX *box;
141PIX *pixd;
142PIXCMAP *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
229l_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{
238l_int32 i, j, w, h, d, wpl, x1, x2, y1, y2, bw, bh;
239l_int32 nrval, ngval, nbval, aveval;
240l_float32 factor;
241l_uint32 val32;
242l_uint32 *line, *data;
243PIX *pixt;
244PIXCMAP *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.f / 255.f;
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
353PIX *
355 PIX *pixm,
356 l_int32 type,
357 l_int32 thresh,
358 l_int32 rval,
359 l_int32 gval,
360 l_int32 bval)
361{
362l_int32 i, j, w, h, d, wm, hm, wmin, hmin, wpl, wplm;
363l_int32 nrval, ngval, nbval, aveval;
364l_float32 factor;
365l_uint32 val32;
366l_uint32 *line, *data, *linem, *datam;
367PIX *pixd;
368PIXCMAP *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.f / 255.f;
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 *------------------------------------------------------------------*/
476PIX *
478 PIX *pixs,
479 l_uint32 srcval,
480 l_uint32 dstval,
481 l_int32 diff)
482{
483l_int32 val, sval, dval;
484l_int32 rval, gval, bval, rsval, gsval, bsval;
485l_int32 i, j, w, h, d, wpl;
486l_uint32 pixel;
487l_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
561PIX *
563 PIX *pixs,
564 l_uint32 srcval,
565 l_uint32 dstval,
566 l_int32 diff)
567{
568l_int32 i, ncolors, index, found;
569l_int32 rval, gval, bval, rsval, gsval, bsval, rdval, gdval, bdval;
570l_int32 *tab;
571PIX *pixm;
572PIXCMAP *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 *---------------------------------------------------------------------*/
676PIX *
678 PIX *pixs,
679 l_uint32 srcval,
680 l_uint32 dstval)
681{
682l_int32 i, j, w, h, wpl;
683l_int32 rval, gval, bval, rsval, gsval, bsval, rdval, gdval, bdval;
684l_int32 *rtab, *gtab, *btab;
685l_uint32 pixel;
686l_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
769l_ok
771 l_uint32 srcmap,
772 l_uint32 dstmap,
773 l_uint32 *pdcolor)
774{
775l_int32 srval, sgval, sbval, drval, dgval, dbval;
776l_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 *------------------------------------------------------------------*/
852PIX *
854 PIX *pixs,
855 l_uint32 srcval,
856 l_uint32 dstval)
857{
858l_int32 i, j, w, h, wpl;
859l_int32 rval, gval, bval, rsval, gsval, bsval, rdval, gdval, bdval;
860l_int32 *rtab, *gtab, *btab;
861l_uint32 pixel;
862l_uint32 *line, *data;
863PIXCMAP *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
924cleanup:
925 LEPT_FREE(rtab);
926 LEPT_FREE(gtab);
927 LEPT_FREE(btab);
928 return pixd;
929}
930
931
951l_ok
953 l_int32 gval,
954 l_int32 bval,
955 l_uint32 srcval,
956 l_uint32 dstval,
957 l_uint32 *ppixel)
958{
959l_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
1012l_ok
1014 l_int32 gval,
1015 l_int32 bval,
1016 l_float32 fract,
1017 l_uint32 *ppixel)
1018{
1019l_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
1061PIX *
1063 PIX *pixs,
1064 l_uint32 srcval,
1065 l_float32 fract)
1066{
1067l_int32 rval, gval, bval;
1068l_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)
#define SET_DATA_BYTE(pdata, n, val)
#define GET_DATA_BIT(pdata, n)
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
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
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
PIX * pixMapWithInvariantHue(PIX *pixd, PIX *pixs, l_uint32 srcval, l_float32 fract)
pixMapWithInvariantHue()
Definition coloring.c:1062
l_ok pixelLinearMapToTargetColor(l_uint32 scolor, l_uint32 srcmap, l_uint32 dstmap, l_uint32 *pdcolor)
pixelLinearMapToTargetColor()
Definition coloring.c:770
PIX * pixSnapColor(PIX *pixd, PIX *pixs, l_uint32 srcval, l_uint32 dstval, l_int32 diff)
pixSnapColor()
Definition coloring.c:477
PIX * pixLinearMapToTargetColor(PIX *pixd, PIX *pixs, l_uint32 srcval, l_uint32 dstval)
pixLinearMapToTargetColor()
Definition coloring.c:677
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
l_ok pixelFractionalShift(l_int32 rval, l_int32 gval, l_int32 bval, l_float32 fract, l_uint32 *ppixel)
pixelFractionalShift()
Definition coloring.c:1013
@ L_CLONE
Definition pix.h:506
@ L_PAINT_LIGHT
Definition pix.h:556
@ L_PAINT_DARK
Definition pix.h:557