/*! * pixColorGrayRegionsCmap() * * Input: pixs (8 bpp, with colormap) * boxa (of regions in which to apply color) * type (L_PAINT_LIGHT, L_PAINT_DARK) * rval, gval, bval (target color) * Return: 0 if OK, 1 on error * * Notes: * (1) This is an in-place operation. * (2) If type == L_PAINT_LIGHT, it colorizes non-black pixels, * preserving antialiasing. * If type == L_PAINT_DARK, it colorizes non-white pixels, * preserving antialiasing. See pixColorGrayCmap() for details. * (3) This can also be called through pixColorGrayRegions(). * (4) This increases the colormap size by the number of * different gray (non-black or non-white) colors in the * selected regions of pixs. If there is not enough room in * the colormap for this expansion, it returns 1 (error), * and the caller should check the return value. * (5) Because two boxes in the boxa can overlap, pixels that * are colorized in the first box must be excluded in the * second because their value exceeds the size of the map. */ l_int32 pixColorGrayRegionsCmap(PIX *pixs, BOXA *boxa, l_int32 type, l_int32 rval, l_int32 gval, l_int32 bval) { l_int32 i, j, k, w, h, n, nc, x1, y1, x2, y2, bw, bh, wpl; l_int32 val, nval; l_int32 *map; l_uint32 *line, *data; BOX *box; NUMA *na; PIXCMAP *cmap; PROCNAME("pixColorGrayRegionsCmap"); if (!pixs) return ERROR_INT("pixs not defined", procName, 1); if (!boxa) return ERROR_INT("boxa not defined", procName, 1); if ((cmap = pixGetColormap(pixs)) == NULL) return ERROR_INT("no colormap", procName, 1); if (pixGetDepth(pixs) != 8) return ERROR_INT("depth not 8 bpp", procName, 1); if (type != L_PAINT_DARK && type != L_PAINT_LIGHT) return ERROR_INT("invalid type", procName, 1); nc = pixcmapGetCount(cmap); if (addColorizedGrayToCmap(cmap, type, rval, gval, bval, &na)) return ERROR_INT("no room; cmap full", procName, 1); map = numaGetIArray(na); numaDestroy(&na); if (!map) return ERROR_INT("map not made", procName, 1); pixGetDimensions(pixs, &w, &h, NULL); data = pixGetData(pixs); wpl = pixGetWpl(pixs); n = boxaGetCount(boxa); for (k = 0; k < n; k++) { box = boxaGetBox(boxa, k, L_CLONE); boxGetGeometry(box, &x1, &y1, &bw, &bh); x2 = x1 + bw - 1; y2 = y1 + bh - 1; /* Remap gray pixels in the region */ for (i = y1; i <= y2; i++) { if (i < 0 || i >= h) /* clip */ continue; line = data + i * wpl; for (j = x1; j <= x2; j++) { if (j < 0 || j >= w) /* clip */ continue; val = GET_DATA_BYTE(line, j); if (val >= nc) continue; /* from overlapping b.b. */ nval = map[val]; if (nval != 256) SET_DATA_BYTE(line, j, nval); } } boxDestroy(&box); } FREE(map); return 0; }
/*! * pixColorGrayMaskedCmap() * * Input: pixs (8 bpp, with colormap) * pixm (1 bpp mask, through which to apply color) * type (L_PAINT_LIGHT, L_PAINT_DARK) * rval, gval, bval (target color) * Return: 0 if OK, 1 on error * * Notes: * (1) This is an in-place operation. * (2) If type == L_PAINT_LIGHT, it colorizes non-black pixels, * preserving antialiasing. * If type == L_PAINT_DARK, it colorizes non-white pixels, * preserving antialiasing. See pixColorGrayCmap() for details. * (3) This increases the colormap size by the number of * different gray (non-black or non-white) colors in the * input colormap. If there is not enough room in the colormap * for this expansion, it returns 1 (error). */ l_int32 pixColorGrayMaskedCmap(PIX *pixs, PIX *pixm, l_int32 type, l_int32 rval, l_int32 gval, l_int32 bval) { l_int32 i, j, w, h, wm, hm, wmin, hmin, wpl, wplm; l_int32 val, nval; l_int32 *map; l_uint32 *line, *data, *linem, *datam; NUMA *na; PIXCMAP *cmap; PROCNAME("pixColorGrayMaskedCmap"); if (!pixs) return ERROR_INT("pixs not defined", procName, 1); if (!pixm || pixGetDepth(pixm) != 1) return ERROR_INT("pixm undefined or not 1 bpp", procName, 1); if ((cmap = pixGetColormap(pixs)) == NULL) return ERROR_INT("no colormap", procName, 1); if (pixGetDepth(pixs) != 8) return ERROR_INT("depth not 8 bpp", procName, 1); if (type != L_PAINT_DARK && type != L_PAINT_LIGHT) return ERROR_INT("invalid type", procName, 1); if (addColorizedGrayToCmap(cmap, type, rval, gval, bval, &na)) return ERROR_INT("no room; cmap full", procName, 1); map = numaGetIArray(na); numaDestroy(&na); if (!map) return ERROR_INT("map not made", procName, 1); pixGetDimensions(pixs, &w, &h, NULL); pixGetDimensions(pixm, &wm, &hm, NULL); if (wm != w) L_WARNING("wm = %d differs from w = %d\n", procName, wm, w); if (hm != h) L_WARNING("hm = %d differs from h = %d\n", procName, hm, h); wmin = L_MIN(w, wm); hmin = L_MIN(h, hm); data = pixGetData(pixs); wpl = pixGetWpl(pixs); datam = pixGetData(pixm); wplm = pixGetWpl(pixm); /* Remap gray pixels in the region */ for (i = 0; i < hmin; i++) { line = data + i * wpl; linem = datam + i * wplm; for (j = 0; j < wmin; j++) { if (GET_DATA_BIT(linem, j) == 0) continue; val = GET_DATA_BYTE(line, j); nval = map[val]; if (nval != 256) SET_DATA_BYTE(line, j, nval); } } FREE(map); return 0; }
/*! * pixColorGrayCmap() * * Input: pixs (2, 4 or 8 bpp, with colormap) * box (<optional> region to set color; can be NULL) * type (L_PAINT_LIGHT, L_PAINT_DARK) * rval, gval, bval (target color) * Return: 0 if OK, 1 on error * * Notes: * (1) This is an in-place operation. * (2) If type == L_PAINT_LIGHT, it colorizes non-black pixels, * preserving antialiasing. * If type == L_PAINT_DARK, it colorizes non-white pixels, * preserving antialiasing. * (3) If box is NULL, applies function to the entire image; otherwise, * clips the operation to the intersection of the box and pix. * (4) This can also be called through pixColorGray(). * (5) This increases the colormap size by the number of * different gray (non-black or non-white) colors in the * input colormap. If there is not enough room in the colormap * for this expansion, it returns 1 (error), and the caller * should check the return value. If an error is returned * and the cmap is only 2 or 4 bpp, the pix can be converted * to 8 bpp and this function will succeed if run again on * a larger colormap. * (6) Using the darkness of each original pixel in the rect, * it generates a new color (based on the input rgb values). * If type == L_PAINT_LIGHT, the new color is a (generally) * darken-to-black version of the input rgb color, where the * amount of darkening increases with the darkness of the * original pixel color. * If type == L_PAINT_DARK, the new color is a (generally) * faded-to-white version of the input rgb color, where the * amount of fading increases with the brightness of the * original pixel color. */ l_int32 pixColorGrayCmap(PIX *pixs, BOX *box, l_int32 type, l_int32 rval, l_int32 gval, l_int32 bval) { l_int32 i, j, w, h, d, x1, y1, x2, y2, bw, bh, wpl; l_int32 val, nval; l_int32 *map; l_uint32 *line, *data; NUMA *na; PIX *pixt; PIXCMAP *cmap, *cmapc; PROCNAME("pixColorGrayCmap"); if (!pixs) return ERROR_INT("pixs not defined", procName, 1); if ((cmap = pixGetColormap(pixs)) == NULL) return ERROR_INT("no colormap", procName, 1); d = pixGetDepth(pixs); if (d != 2 && d != 4 && d != 8) return ERROR_INT("depth not in {2, 4, 8}", procName, 1); if (type != L_PAINT_DARK && type != L_PAINT_LIGHT) return ERROR_INT("invalid type", procName, 1); /* If 2 bpp or 4 bpp, see if the new colors will fit into * the existing colormap. If not, convert in-place to 8 bpp. */ if (d == 2 || d == 4) { cmapc = pixcmapCopy(cmap); /* experiment with a copy */ if (addColorizedGrayToCmap(cmapc, type, rval, gval, bval, NULL)) { pixt = pixConvertTo8(pixs, 1); pixTransferAllData(pixs, &pixt, 0, 0); } pixcmapDestroy(&cmapc); } /* Find gray colors, add the corresponding new colors, * and set up a mapping table from gray to new. * That table has the value 256 for all colors that are * not to be mapped. */ cmap = pixGetColormap(pixs); if (addColorizedGrayToCmap(cmap, type, rval, gval, bval, &na)) { numaDestroy(&na); return ERROR_INT("no room; cmap full", procName, 1); } map = numaGetIArray(na); /* Determine the region of substitution */ pixGetDimensions(pixs, &w, &h, &d); /* d may be different */ data = pixGetData(pixs); wpl = pixGetWpl(pixs); if (!box) { x1 = y1 = 0; x2 = w; y2 = h; } else { boxGetGeometry(box, &x1, &y1, &bw, &bh); x2 = x1 + bw - 1; y2 = y1 + bh - 1; } /* Remap gray pixels in the region */ for (i = y1; i <= y2; i++) { if (i < 0 || i >= h) /* clip */ continue; line = data + i * wpl; for (j = x1; j <= x2; j++) { if (j < 0 || j >= w) /* clip */ continue; switch (d) { case 2: val = GET_DATA_DIBIT(line, j); nval = map[val]; if (nval != 256) SET_DATA_DIBIT(line, j, nval); break; case 4: val = GET_DATA_QBIT(line, j); nval = map[val]; if (nval != 256) SET_DATA_QBIT(line, j, nval); break; case 8: val = GET_DATA_BYTE(line, j); nval = map[val]; if (nval != 256) SET_DATA_BYTE(line, j, nval); break; } } } FREE(map); numaDestroy(&na); return 0; }