diff options
Diffstat (limited to 'leptonica/src/paintcmap.c')
-rw-r--r-- | leptonica/src/paintcmap.c | 765 |
1 files changed, 765 insertions, 0 deletions
diff --git a/leptonica/src/paintcmap.c b/leptonica/src/paintcmap.c new file mode 100644 index 00000000..b0f27982 --- /dev/null +++ b/leptonica/src/paintcmap.c @@ -0,0 +1,765 @@ +/*====================================================================* + - Copyright (C) 2001 Leptonica. All rights reserved. + - + - Redistribution and use in source and binary forms, with or without + - modification, are permitted provided that the following conditions + - are met: + - 1. Redistributions of source code must retain the above copyright + - notice, this list of conditions and the following disclaimer. + - 2. Redistributions in binary form must reproduce the above + - copyright notice, this list of conditions and the following + - disclaimer in the documentation and/or other materials + - provided with the distribution. + - + - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY + - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *====================================================================*/ + +/*! + * \file paintcmap.c + * <pre> + * + * These in-place functions paint onto colormap images. + * + * Repaint selected pixels in region + * l_int32 pixSetSelectCmap() + * + * Repaint non-white pixels in region + * l_int32 pixColorGrayRegionsCmap() + * l_int32 pixColorGrayCmap() + * l_int32 pixColorGrayMaskedCmap() + * l_int32 addColorizedGrayToCmap() + * + * Repaint selected pixels through mask + * l_int32 pixSetSelectMaskedCmap() + * + * Repaint all pixels through mask + * l_int32 pixSetMaskedCmap() + * + * + * The 'set select' functions condition the setting on a specific + * pixel value (i.e., index into the colormap) of the underyling + * Pix that is being modified. The same conditioning is used in + * pixBlendCmap(). + * + * The pixColorGrayCmap() function sets all truly gray (r = g = b) pixels, + * with the exception of either black or white pixels, to a new color. + * + * The pixSetSelectMaskedCmap() function conditions pixel painting + * on both a specific pixel value and location within the fg mask. + * By contrast, pixSetMaskedCmap() sets all pixels under the + * mask foreground, without considering the initial pixel values. + * </pre> + */ + +#ifdef HAVE_CONFIG_H +#include <config_auto.h> +#endif /* HAVE_CONFIG_H */ + +#include <string.h> +#include "allheaders.h" + +/*-------------------------------------------------------------* + * Repaint selected pixels in region * + *-------------------------------------------------------------*/ +/*! + * \brief pixSetSelectCmap() + * + * \param[in] pixs 1, 2, 4 or 8 bpp, with colormap + * \param[in] box [optional] region to set color; can be NULL + * \param[in] sindex colormap index of pixels to be changed + * \param[in] rval, gval, bval new color to paint + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * (1) This is an in-place operation. + * (2) It sets all pixels in region that have the color specified + * by the colormap index %sindex to the new color. + * (3) %sindex must be in the existing colormap; otherwise an + * error is returned. + * (4) If the new color exists in the colormap, it is used; + * otherwise, it is added to the colormap. If it cannot be + * added because the colormap is full, an error is returned. + * (5) If %box is NULL, applies function to the entire image; otherwise, + * clips the operation to the intersection of the box and pix. + * (6) An example of use would be to set to a specific color all + * the light (background) pixels within a certain region of + * a 3-level 2 bpp image, while leaving light pixels outside + * this region unchanged. + * </pre> + */ +l_ok +pixSetSelectCmap(PIX *pixs, + BOX *box, + l_int32 sindex, + l_int32 rval, + l_int32 gval, + l_int32 bval) +{ +l_int32 i, j, w, h, d, n, x1, y1, x2, y2, bw, bh, val, wpls; +l_int32 index; /* of new color to be set */ +l_uint32 *lines, *datas; +PIXCMAP *cmap; + + PROCNAME("pixSetSelectCmap"); + + 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 != 1 && d != 2 && d != 4 && d != 8) + return ERROR_INT("depth not in {1,2,4,8}", procName, 1); + + /* Add new color if necessary; get index of this color in cmap */ + n = pixcmapGetCount(cmap); + if (sindex >= n) + return ERROR_INT("sindex too large; no cmap entry", procName, 1); + if (pixcmapGetIndex(cmap, rval, gval, bval, &index)) { /* not found */ + if (pixcmapAddColor(cmap, rval, gval, bval)) + return ERROR_INT("error adding cmap entry", procName, 1); + else + index = n; /* we've added one color */ + } + + /* Determine the region of substitution */ + pixGetDimensions(pixs, &w, &h, NULL); + if (!box) { + x1 = y1 = 0; + x2 = w; + y2 = h; + } else { + boxGetGeometry(box, &x1, &y1, &bw, &bh); + x2 = x1 + bw - 1; + y2 = y1 + bh - 1; + } + + /* Replace pixel value sindex by index in the region */ + datas = pixGetData(pixs); + wpls = pixGetWpl(pixs); + for (i = y1; i <= y2; i++) { + if (i < 0 || i >= h) /* clip */ + continue; + lines = datas + i * wpls; + for (j = x1; j <= x2; j++) { + if (j < 0 || j >= w) /* clip */ + continue; + switch (d) { + case 1: + val = GET_DATA_BIT(lines, j); + if (val == sindex) { + if (index == 0) + CLEAR_DATA_BIT(lines, j); + else + SET_DATA_BIT(lines, j); + } + break; + case 2: + val = GET_DATA_DIBIT(lines, j); + if (val == sindex) + SET_DATA_DIBIT(lines, j, index); + break; + case 4: + val = GET_DATA_QBIT(lines, j); + if (val == sindex) + SET_DATA_QBIT(lines, j, index); + break; + case 8: + val = GET_DATA_BYTE(lines, j); + if (val == sindex) + SET_DATA_BYTE(lines, j, index); + break; + default: + return ERROR_INT("depth not in {1,2,4,8}", procName, 1); + } + } + } + + return 0; +} + + +/*-------------------------------------------------------------* + * Repaint gray pixels in region * + *-------------------------------------------------------------*/ +/*! + * \brief pixColorGrayRegionsCmap() + * + * \param[in] pixs 8 bpp, with colormap + * \param[in] boxa of regions in which to apply color + * \param[in] type L_PAINT_LIGHT, L_PAINT_DARK + * \param[in] rval, gval, bval target color + * \return 0 if OK, 1 on error + * + * <pre> + * 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 %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. + * </pre> + */ +l_ok +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); + } + + LEPT_FREE(map); + return 0; +} + + +/*! + * \brief pixColorGrayCmap() + * + * \param[in] pixs 2, 4 or 8 bpp, with colormap + * \param[in] box [optional] region to set color; can be NULL + * \param[in] type L_PAINT_LIGHT, L_PAINT_DARK + * \param[in] rval, gval, bval target color + * \return 0 if OK, 1 on error + * + * <pre> + * 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) %box gives the region to apply color; if NULL, this + * colorizes the entire image. + * (4) If the cmap is only 2 or 4 bpp, pixs is converted in-place + * to an 8 bpp cmap. A 1 bpp cmap is not a valid input pix. + * (5) This can also be called through pixColorGray(). + * (6) This operation 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. + * (7) 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. + * </pre> + */ +l_ok +pixColorGrayCmap(PIX *pixs, + BOX *box, + l_int32 type, + l_int32 rval, + l_int32 gval, + l_int32 bval) +{ +l_int32 w, h, d, ret; +PIX *pixt; +BOXA *boxa; +PIXCMAP *cmap; + + PROCNAME("pixColorGrayCmap"); + + if (!pixs) + return ERROR_INT("pixs not defined", procName, 1); + if ((cmap = pixGetColormap(pixs)) == NULL) + return ERROR_INT("no colormap", procName, 1); + pixGetDimensions(pixs, &w, &h, &d); + 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, convert in-place to 8 bpp. */ + if (d == 2 || d == 4) { + pixt = pixConvertTo8(pixs, 1); + pixTransferAllData(pixs, &pixt, 0, 0); + } + + /* If box == NULL, color the entire image */ + boxa = boxaCreate(1); + if (box) { + boxaAddBox(boxa, box, L_COPY); + } else { + box = boxCreate(0, 0, w, h); + boxaAddBox(boxa, box, L_INSERT); + } + ret = pixColorGrayRegionsCmap(pixs, boxa, type, rval, gval, bval); + + boxaDestroy(&boxa); + return ret; +} + + +/*! + * \brief pixColorGrayMaskedCmap() + * + * \param[in] pixs 8 bpp, with colormap + * \param[in] pixm 1 bpp mask, through which to apply color + * \param[in] type L_PAINT_LIGHT, L_PAINT_DARK + * \param[in] rval, gval, bval target color + * \return 0 if OK, 1 on error + * + * <pre> + * 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). + * </pre> + */ +l_ok +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); + } + } + + LEPT_FREE(map); + return 0; +} + + +/*! + * \brief addColorizedGrayToCmap() + * + * \param[in] cmap from 2 or 4 bpp pix + * \param[in] type L_PAINT_LIGHT, L_PAINT_DARK + * \param[in] rval, gval, bval target color + * \param[out] pna [optional] table for mapping new cmap entries + * \return 0 if OK; 1 on error; 2 if new colors will not fit in cmap. + * + * <pre> + * Notes: + * (1) If %type == L_PAINT_LIGHT, it colorizes non-black pixels, + * preserving antialiasing. + * If %type == L_PAINT_DARK, it colorizes non-white pixels, + * preserving antialiasing. + * (2) 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 (treated as a warning); + * the caller should check the return value. + * (3) This can be used to determine if the new colors will fit in + * the cmap, using null for &na. Returns 0 if they fit; 2 if + * they don't fit. + * (4) The mapping table contains, for each gray color found, the + * index of the corresponding colorized pixel. Non-gray + * pixels are assigned the invalid index 256. + * (5) See pixColorGrayCmap() for usage. + * </pre> + */ +l_ok +addColorizedGrayToCmap(PIXCMAP *cmap, + l_int32 type, + l_int32 rval, + l_int32 gval, + l_int32 bval, + NUMA **pna) +{ +l_int32 i, n, erval, egval, ebval, nrval, ngval, nbval, newindex; +NUMA *na; + + PROCNAME("addColorizedGrayToCmap"); + + if (pna) *pna = NULL; + if (!cmap) + return ERROR_INT("cmap not defined", procName, 1); + if (type != L_PAINT_DARK && type != L_PAINT_LIGHT) + return ERROR_INT("invalid type", procName, 1); + + n = pixcmapGetCount(cmap); + na = numaCreate(n); + for (i = 0; i < n; i++) { + pixcmapGetColor(cmap, i, &erval, &egval, &ebval); + if (type == L_PAINT_LIGHT) { + if (erval == egval && erval == ebval && erval != 0) { + nrval = (l_int32)(rval * (l_float32)erval / 255.); + ngval = (l_int32)(gval * (l_float32)egval / 255.); + nbval = (l_int32)(bval * (l_float32)ebval / 255.); + if (pixcmapAddNewColor(cmap, nrval, ngval, nbval, &newindex)) { + numaDestroy(&na); + L_WARNING("no room; colormap full\n", procName); + return 2; + } + numaAddNumber(na, newindex); + } else { + numaAddNumber(na, 256); /* invalid number; not gray */ + } + } else { /* L_PAINT_DARK */ + if (erval == egval && erval == ebval && erval != 255) { + nrval = rval + + (l_int32)((255. - rval) * (l_float32)erval / 255.); + ngval = gval + + (l_int32)((255. - gval) * (l_float32)egval / 255.); + nbval = bval + + (l_int32)((255. - bval) * (l_float32)ebval / 255.); + if (pixcmapAddNewColor(cmap, nrval, ngval, nbval, &newindex)) { + numaDestroy(&na); + L_WARNING("no room; colormap full\n", procName); + return 2; + } + numaAddNumber(na, newindex); + } else { + numaAddNumber(na, 256); /* invalid number; not gray */ + } + } + } + + if (pna) + *pna = na; + else + numaDestroy(&na); + return 0; +} + + +/*-------------------------------------------------------------* + * Repaint selected pixels through mask * + *-------------------------------------------------------------*/ +/*! + * \brief pixSetSelectMaskedCmap() + * + * \param[in] pixs 2, 4 or 8 bpp, with colormap + * \param[in] pixm [optional] 1 bpp mask; no-op if NULL + * \param[in] x, y UL corner of mask relative to pixs + * \param[in] sindex cmap index of pixels in pixs to be changed + * \param[in] rval, gval, bval new color to substitute + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * (1) This is an in-place operation. + * (2) This paints through the fg of pixm and replaces all pixels + * in pixs that have the value %sindex with the new color. + * (3) If pixm == NULL, a warning is given. + * (4) %sindex must be in the existing colormap; otherwise an + * error is returned. + * (5) If the new color exists in the colormap, it is used; + * otherwise, it is added to the colormap. If the colormap + * is full, an error is returned. + * </pre> + */ +l_ok +pixSetSelectMaskedCmap(PIX *pixs, + PIX *pixm, + l_int32 x, + l_int32 y, + l_int32 sindex, + l_int32 rval, + l_int32 gval, + l_int32 bval) +{ +l_int32 i, j, w, h, d, n, wm, hm, wpls, wplm, val; +l_int32 index; /* of new color to be set */ +l_uint32 *lines, *linem, *datas, *datam; +PIXCMAP *cmap; + + PROCNAME("pixSetSelectMaskedCmap"); + + if (!pixs) + return ERROR_INT("pixs not defined", procName, 1); + if ((cmap = pixGetColormap(pixs)) == NULL) + return ERROR_INT("no colormap", procName, 1); + if (!pixm) { + L_WARNING("no mask; nothing to do\n", procName); + return 0; + } + + d = pixGetDepth(pixs); + if (d != 2 && d != 4 && d != 8) + return ERROR_INT("depth not in {2, 4, 8}", procName, 1); + + /* add new color if necessary; get index of this color in cmap */ + n = pixcmapGetCount(cmap); + if (sindex >= n) + return ERROR_INT("sindex too large; no cmap entry", procName, 1); + if (pixcmapGetIndex(cmap, rval, gval, bval, &index)) { /* not found */ + if (pixcmapAddColor(cmap, rval, gval, bval)) + return ERROR_INT("error adding cmap entry", procName, 1); + else + index = n; /* we've added one color */ + } + + /* replace pixel value sindex by index when fg pixel in pixmc + * overlays it */ + pixGetDimensions(pixs, &w, &h, NULL); + datas = pixGetData(pixs); + wpls = pixGetWpl(pixs); + wm = pixGetWidth(pixm); + hm = pixGetHeight(pixm); + datam = pixGetData(pixm); + wplm = pixGetWpl(pixm); + for (i = 0; i < hm; i++) { + if (i + y < 0 || i + y >= h) continue; + lines = datas + (y + i) * wpls; + linem = datam + i * wplm; + for (j = 0; j < wm; j++) { + if (j + x < 0 || j + x >= w) continue; + if (GET_DATA_BIT(linem, j)) { + switch (d) { + case 2: + val = GET_DATA_DIBIT(lines, x + j); + if (val == sindex) + SET_DATA_DIBIT(lines, x + j, index); + break; + case 4: + val = GET_DATA_QBIT(lines, x + j); + if (val == sindex) + SET_DATA_QBIT(lines, x + j, index); + break; + case 8: + val = GET_DATA_BYTE(lines, x + j); + if (val == sindex) + SET_DATA_BYTE(lines, x + j, index); + break; + default: + return ERROR_INT("depth not in {1,2,4,8}", procName, 1); + } + } + } + } + + return 0; +} + + +/*-------------------------------------------------------------* + * Repaint all pixels through mask * + *-------------------------------------------------------------*/ +/*! + * \brief pixSetMaskedCmap() + * + * \param[in] pixs 2, 4 or 8 bpp, colormapped + * \param[in] pixm [optional] 1 bpp mask; no-op if NULL + * \param[in] x, y origin of pixm relative to pixs; + * can be negative + * \param[in] rval, gval, bval new color to set at each masked pixel + * \return 0 if OK; 1 on error + * + * <pre> + * Notes: + * (1) This is an in-place operation. + * (2) It paints a single color through the mask (as a stencil). + * (3) The mask origin is placed at (%x,%y) on %pixs, and the + * operation is clipped to the intersection of the mask and pixs. + * (4) If %pixm == NULL, a warning is given. + * (5) Typically, %pixm is a small binary mask located somewhere + * on the larger %pixs. + * (6) If the color is in the colormap, it is used. Otherwise, + * it is added if possible; an error is returned if the + * colormap is already full. + * </pre> + */ +l_ok +pixSetMaskedCmap(PIX *pixs, + PIX *pixm, + l_int32 x, + l_int32 y, + l_int32 rval, + l_int32 gval, + l_int32 bval) +{ +l_int32 w, h, d, wpl, wm, hm, wplm; +l_int32 i, j, index; +l_uint32 *data, *datam, *line, *linem; +PIXCMAP *cmap; + + PROCNAME("pixSetMaskedCmap"); + + if (!pixs) + return ERROR_INT("pixs not defined", procName, 1); + if ((cmap = pixGetColormap(pixs)) == NULL) + return ERROR_INT("no colormap in pixs", procName, 1); + if (!pixm) { + L_WARNING("no mask; nothing to do\n", procName); + return 0; + } + d = pixGetDepth(pixs); + if (d != 2 && d != 4 && d != 8) + return ERROR_INT("depth not in {2,4,8}", procName, 1); + if (pixGetDepth(pixm) != 1) + return ERROR_INT("pixm not 1 bpp", procName, 1); + + /* Add new color if necessary; store in 'index' */ + if (pixcmapGetIndex(cmap, rval, gval, bval, &index)) { /* not found */ + if (pixcmapAddColor(cmap, rval, gval, bval)) + return ERROR_INT("no room in cmap", procName, 1); + index = pixcmapGetCount(cmap) - 1; + } + + pixGetDimensions(pixs, &w, &h, NULL); + wpl = pixGetWpl(pixs); + data = pixGetData(pixs); + pixGetDimensions(pixm, &wm, &hm, NULL); + wplm = pixGetWpl(pixm); + datam = pixGetData(pixm); + for (i = 0; i < hm; i++) { + if (i + y < 0 || i + y >= h) continue; + line = data + (i + y) * wpl; + linem = datam + i * wplm; + for (j = 0; j < wm; j++) { + if (j + x < 0 || j + x >= w) continue; + if (GET_DATA_BIT(linem, j)) { /* paint color */ + switch (d) { + case 2: + SET_DATA_DIBIT(line, j + x, index); + break; + case 4: + SET_DATA_QBIT(line, j + x, index); + break; + case 8: + SET_DATA_BYTE(line, j + x, index); + break; + default: + return ERROR_INT("depth not in {2,4,8}", procName, 1); + } + } + } + } + + return 0; +} |