Example #1
0
// Threshold the rectangle, taking everything except the image buffer pointer
// from the class, using thresholds/hi_values to the output IMAGE.
void ImageThresholder::ThresholdRectToPix(const unsigned char* imagedata,
                                          int bytes_per_pixel,
                                          int bytes_per_line,
                                          const int* thresholds,
                                          const int* hi_values,
                                          Pix** pix) const {
  *pix = pixCreate(rect_width_, rect_height_, 1);
  uinT32* pixdata = pixGetData(*pix);
  int wpl = pixGetWpl(*pix);
  const unsigned char* srcdata = imagedata + rect_top_* bytes_per_line +
                                 rect_left_ * bytes_per_pixel;
  for (int y = 0; y < rect_height_; ++y) {
    const uinT8* linedata = srcdata;
    uinT32* pixline = pixdata + y * wpl;
    for (int x = 0; x < rect_width_; ++x, linedata += bytes_per_pixel) {
      bool white_result = true;
      for (int ch = 0; ch < bytes_per_pixel; ++ch) {
        if (hi_values[ch] >= 0 &&
            (linedata[ch] > thresholds[ch]) == (hi_values[ch] == 0)) {
          white_result = false;
          break;
        }
      }
      if (white_result)
        CLEAR_DATA_BIT(pixline, x);
      else
        SET_DATA_BIT(pixline, x);
    }
    srcdata += bytes_per_line;
  }
}
Example #2
0
/*!
 *  pixSetPixel()
 *
 *      Input:  pix
 *              (x,y) pixel coords
 *              val (value to be inserted)
 *      Return: 0 if OK; 1 on error
 *
 *  Notes:
 *      (1) Warning: the input value is not checked for overflow with respect
 *          the the depth of @pix, and the sign bit (if any) is ignored.
 *          * For d == 1, @val > 0 sets the bit on.
 *          * For d == 2, 4, 8 and 16, @val is masked to the maximum allowable
 *            pixel value, and any (invalid) higher order bits are discarded.
 *      (2) See pixGetPixel() for information on performance.
 */
LEPTONICA_EXPORT l_int32
pixSetPixel(PIX      *pix,
            l_int32   x,
            l_int32   y,
            l_uint32  val)
{
l_int32    w, h, d, wpl;
l_uint32  *line, *data;

    PROCNAME("pixSetPixel");

    if (!pix)
        return ERROR_INT("pix not defined", procName, 1);

    pixGetDimensions(pix, &w, &h, &d);
    if (x < 0 || x >= w)
        return ERROR_INT("x out of bounds", procName, 1);
    if (y < 0 || y >= h)
        return ERROR_INT("y out of bounds", procName, 1);

    data = pixGetData(pix);
    wpl = pixGetWpl(pix);
    line = data + y * wpl;
    switch (d)
    {
    case 1:
        if (val)
            SET_DATA_BIT(line, x);
        else
            CLEAR_DATA_BIT(line, x);
        break;
    case 2:
        SET_DATA_DIBIT(line, x, val);
        break;
    case 4:
        SET_DATA_QBIT(line, x, val);
        break;
    case 8:
        SET_DATA_BYTE(line, x, val);
        break;
    case 16:
        SET_DATA_TWO_BYTES(line, x, val);
        break;
    case 32:
        line[x] = val;
        break;
    default:
        return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", procName, 1);
    }

    return 0;
}
Example #3
0
// Get a set of bounding boxes of possible horizontal lines in the image.
// The input resolution overrides any resolution set in src_pix.
// The output line_pix contains just all the detected lines.
// The output boxes undergo the transformation (x,y)->(height-y,x) so the
// lines can be found with a vertical line finder afterwards.
// This transformation allows a simple x/y flip to reverse it in tesseract
// coordinates and it is faster to flip the lines than rotate the image.
Boxa* LineFinder::GetHLineBoxes(int resolution, Pix* src_pix, Pix** line_pix) {
#ifdef HAVE_LIBLEPT
  // Remove any parts of 1 inch/kThinLineFraction high or more, by opening
  // away the thin lines and subtracting what's left.
  // This is very generous and will leave in even quite wide lines.
  Pix* pixt1 = pixOpenBrick(NULL, src_pix, 1, resolution / kThinLineFraction);
  pixSubtract(pixt1, src_pix, pixt1);
  // Spread vertically to allow for some skew.
  Pix* pixt2 = pixDilateBrick(NULL, pixt1, 1, 3);
  // Now keep only wide stuff of width at least 1 inch/kMinLineLengthFraction.
  pixOpenBrick(pixt1, pixt2, resolution / kMinLineLengthFraction, 1);
  pixDestroy(&pixt2);
  // Put a single pixel crack in every line at an arbitrary spacing,
  // so they break up and the bounding boxes can be used to get the
  // direction accurately enough without needing outlines.
  int wpl = pixGetWpl(pixt1);
  int width = pixGetWidth(pixt1);
  int height = pixGetHeight(pixt1);
  l_uint32* data = pixGetData(pixt1);
  for (int y = 0; y < height; ++y, data += wpl) {
    for (int x = kCrackSpacing; x < width; x += kCrackSpacing) {
      CLEAR_DATA_BIT(data, x);
    }
  }
  if (textord_tabfind_show_vlines)
    pixWrite("hlines.png", pixt1, IFF_PNG);
  Boxa* boxa = pixConnComp(pixt1, NULL, 8);
  *line_pix = pixt1;

  // Iterate the boxes to flip x and y.
  int nboxes = boxaGetCount(boxa);
  for (int i = 0; i < nboxes; ++i) {
    l_int32 x, y, box_width, box_height;
    boxaGetBoxGeometry(boxa, i, &x, &y, &box_width, &box_height);
    Box* box = boxCreate(height - (y + box_height),
                         width - (x + box_width), box_height, box_width);
    boxaReplaceBox(boxa, i, box);
  }
  return boxa;
#else
  return NULL;
#endif
}
Example #4
0
/*!
 * \brief   pixSeedfill8()
 *
 * \param[in]    pixs 1 bpp
 * \param[in]    stack for holding fillsegs
 * \param[in]    x,y   location of seed pixel
 * \return  0 if OK, 1 on error
 *
 * <pre>
 * Notes:
 *      (1) This is Paul Heckbert's stack-based 8-cc seedfill algorithm.
 *      (2) This operates on the input 1 bpp pix to remove the fg seed
 *          pixel, at (x,y), and all pixels that are 8-connected to it.
 *          The seed pixel at (x,y) must initially be ON.
 *      (3) Reference: see pixSeedFill8BB()
 * </pre>
 */
l_int32
pixSeedfill8(PIX      *pixs,
             L_STACK  *stack,
             l_int32   x,
             l_int32   y)
{
    l_int32    w, h, xstart, wpl, x1, x2, dy;
    l_int32    xmax, ymax;
    l_uint32  *data, *line;

    PROCNAME("pixSeedfill8");

    if (!pixs || pixGetDepth(pixs) != 1)
        return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
    if (!stack)
        return ERROR_INT("stack not defined", procName, 1);
    if (!stack->auxstack)
        stack->auxstack = lstackCreate(0);

    pixGetDimensions(pixs, &w, &h, NULL);
    xmax = w - 1;
    ymax = h - 1;
    data = pixGetData(pixs);
    wpl = pixGetWpl(pixs);
    line = data + y * wpl;

    /* Check pix value of seed; must be ON */
    if (x < 0 || x > xmax || y < 0 || y > ymax || (GET_DATA_BIT(line, x) == 0))
        return 0;

    /* Init stack to seed */
    pushFillseg(stack, x, x, y, 1, ymax);
    pushFillseg(stack, x, x, y + 1, -1, ymax);

    while (lstackGetCount(stack) > 0) {
        /* Pop segment off stack and fill a neighboring scan line */
        popFillseg(stack, &x1, &x2, &y, &dy);
        line = data + y * wpl;

        /* A segment of scanline y - dy for x1 <= x <= x2 was
         * previously filled.  We now explore adjacent pixels
         * in scan line y.  There are three regions: to the
         * left of x1, between x1 and x2, and to the right of x2.
         * These regions are handled differently.  Leaks are
         * possible expansions beyond the previous segment and
         * going back in the -dy direction.  These can happen
         * for x < x1 and for x > x2.  Any "leak" segments
         * are plugged with a push in the -dy (opposite) direction.
         * And any segments found anywhere are always extended
         * in the +dy direction.  */
        for (x = x1 - 1; x >= 0 && (GET_DATA_BIT(line, x) == 1); x--)
            CLEAR_DATA_BIT(line,x);
        if (x >= x1 - 1)  /* pix at x1 - 1 was off and was not cleared */
            goto skip;
        xstart = x + 1;
        if (xstart < x1)   /* leak on left? */
            pushFillseg(stack, xstart, x1 - 1, y, -dy, ymax);

        x = x1;
        do {
            for (; x <= xmax && (GET_DATA_BIT(line, x) == 1); x++)
                CLEAR_DATA_BIT(line, x);
            pushFillseg(stack, xstart, x - 1, y, dy, ymax);
            if (x > x2)   /* leak on right? */
                pushFillseg(stack, x2 + 1, x - 1, y, -dy, ymax);
skip:
            for (x++; x <= x2 + 1 &&
                    x <= xmax &&
                    (GET_DATA_BIT(line, x) == 0); x++)
                ;
            xstart = x;
        } while (x <= x2 + 1 && x <= xmax);
    }

    return 0;
}
Example #5
0
/*!
 * \brief   pixSeedfill8BB()
 *
 * \param[in]    pixs 1 bpp
 * \param[in]    stack for holding fillsegs
 * \param[in]    x,y   location of seed pixel
 * \return  box or NULL on error.
 *
 * <pre>
 * Notes:
 *      (1) This is Paul Heckbert's stack-based 8-cc seedfill algorithm.
 *      (2) This operates on the input 1 bpp pix to remove the fg seed
 *          pixel, at (x,y), and all pixels that are 8-connected to it.
 *          The seed pixel at (x,y) must initially be ON.
 *      (3) Returns the bounding box of the erased 8-cc component.
 *      (4) Reference: see Paul Heckbert's stack-based seed fill algorithm
 *          in "Graphic Gems", ed. Andrew Glassner, Academic
 *          Press, 1990.  The algorithm description is given
 *          on pp. 275-277; working C code is on pp. 721-722.)
 *          The code here follows Heckbert's closely, except
 *          the leak checks are changed for 8 connectivity.
 *          See comments on pixSeedfill4BB() for more details.
 * </pre>
 */
BOX *
pixSeedfill8BB(PIX      *pixs,
               L_STACK  *stack,
               l_int32   x,
               l_int32   y)
{
    l_int32    w, h, xstart, wpl, x1, x2, dy;
    l_int32    xmax, ymax;
    l_int32    minx, maxx, miny, maxy;  /* for bounding box of this c.c. */
    l_uint32  *data, *line;
    BOX       *box;

    PROCNAME("pixSeedfill8BB");

    if (!pixs || pixGetDepth(pixs) != 1)
        return (BOX *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL);
    if (!stack)
        return (BOX *)ERROR_PTR("stack not defined", procName, NULL);
    if (!stack->auxstack)
        stack->auxstack = lstackCreate(0);

    pixGetDimensions(pixs, &w, &h, NULL);
    xmax = w - 1;
    ymax = h - 1;
    data = pixGetData(pixs);
    wpl = pixGetWpl(pixs);
    line = data + y * wpl;

    /* Check pix value of seed; must be ON */
    if (x < 0 || x > xmax || y < 0 || y > ymax || (GET_DATA_BIT(line, x) == 0))
        return NULL;

    /* Init stack to seed:
     * Must first init b.b. values to prevent valgrind from complaining;
     * then init b.b. boundaries correctly to seed.  */
    minx = miny = 100000;
    maxx = maxy = 0;
    pushFillsegBB(stack, x, x, y, 1, ymax, &minx, &maxx, &miny, &maxy);
    pushFillsegBB(stack, x, x, y + 1, -1, ymax, &minx, &maxx, &miny, &maxy);
    minx = maxx = x;
    miny = maxy = y;

    while (lstackGetCount(stack) > 0) {
        /* Pop segment off stack and fill a neighboring scan line */
        popFillseg(stack, &x1, &x2, &y, &dy);
        line = data + y * wpl;

        /* A segment of scanline y - dy for x1 <= x <= x2 was
         * previously filled.  We now explore adjacent pixels
         * in scan line y.  There are three regions: to the
         * left of x1, between x1 and x2, and to the right of x2.
         * These regions are handled differently.  Leaks are
         * possible expansions beyond the previous segment and
         * going back in the -dy direction.  These can happen
         * for x < x1 and for x > x2.  Any "leak" segments
         * are plugged with a push in the -dy (opposite) direction.
         * And any segments found anywhere are always extended
         * in the +dy direction.  */
        for (x = x1 - 1; x >= 0 && (GET_DATA_BIT(line, x) == 1); x--)
            CLEAR_DATA_BIT(line,x);
        if (x >= x1 - 1)  /* pix at x1 - 1 was off and was not cleared */
            goto skip;
        xstart = x + 1;
        if (xstart < x1)   /* leak on left? */
            pushFillsegBB(stack, xstart, x1 - 1, y, -dy,
                          ymax, &minx, &maxx, &miny, &maxy);

        x = x1;
        do {
            for (; x <= xmax && (GET_DATA_BIT(line, x) == 1); x++)
                CLEAR_DATA_BIT(line, x);
            pushFillsegBB(stack, xstart, x - 1, y, dy,
                          ymax, &minx, &maxx, &miny, &maxy);
            if (x > x2)   /* leak on right? */
                pushFillsegBB(stack, x2 + 1, x - 1, y, -dy,
                              ymax, &minx, &maxx, &miny, &maxy);
skip:
            for (x++; x <= x2 + 1 &&
                    x <= xmax &&
                    (GET_DATA_BIT(line, x) == 0); x++)
                ;
            xstart = x;
        } while (x <= x2 + 1 && x <= xmax);
    }

    if ((box = boxCreate(minx, miny, maxx - minx + 1, maxy - miny + 1))
            == NULL)
        return (BOX *)ERROR_PTR("box not made", procName, NULL);
    return box;
}
/*!
 *  pixSetSelectCmap()
 *
 *      Input:  pixs (1, 2, 4 or 8 bpp, with colormap)
 *              box (<optional> region to set color; can be NULL)
 *              sindex (colormap index of pixels to be changed)
 *              rval, gval, bval (new color to paint)
 *      Return: 0 if OK, 1 on error
 *
 *  Note:
 *      (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 DC 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.
 */
l_int32
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;
}
/*!
 *  pixSetSelectMaskedCmap()
 *
 *      Input:  pixs (2, 4 or 8 bpp, with colormap)
 *              pixm (<optional> 1 bpp mask; no-op if NULL)
 *              x, y (UL corner of mask relative to pixs)
 *              sindex (colormap index of pixels in pixs to be changed)
 *              rval, gval, bval (new color to substitute)
 *      Return: 0 if OK, 1 on error
 *
 *  Note:
 *      (1) This is an in-place operation.
 *      (2) This paints through the fg of pixm and replaces all pixels
 *          in pixs that have a particular 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.
 */
l_int32
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 */
    w = pixGetWidth(pixs);
    h = pixGetHeight(pixs);
    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 1:
                    val = GET_DATA_BIT(lines, x + j);
                    if (val == sindex) {
                        if (index == 0)
                            CLEAR_DATA_BIT(lines, x + j);
                        else
                            SET_DATA_BIT(lines, x + j);
                    }
                    break;
                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;
}
Example #8
0
/*!
 *  pixRotateBySampling()
 *
 *      Input:  pixs (1, 2, 4, 8, 16, 32 bpp rgb; can be cmapped)
 *              xcen (x value of center of rotation)
 *              ycen (y value of center of rotation)
 *              angle (radians; clockwise is positive)
 *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK)
 *      Return: pixd, or null on error
 *
 *  Notes:
 *      (1) For very small rotations, just return a clone.
 *      (2) Rotation brings either white or black pixels in
 *          from outside the image.
 *      (3) Colormaps are retained.
 */
PIX *
pixRotateBySampling(PIX *pixs,
                    l_int32 xcen,
                    l_int32 ycen,
                    l_float32 angle,
                    l_int32 incolor) {
    l_int32 w, h, d, i, j, x, y, xdif, ydif, wm1, hm1, wpld;
    l_uint32 val;
    l_float32 sina, cosa;
    l_uint32 *datad, *lined;
    void **lines;
    PIX *pixd;

    PROCNAME("pixRotateBySampling");

    if (!pixs)
        return (PIX *) ERROR_PTR("pixs not defined", procName, NULL);
    if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
        return (PIX *) ERROR_PTR("invalid incolor", procName, NULL);
    pixGetDimensions(pixs, &w, &h, &d);
    if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
        return (PIX *) ERROR_PTR("invalid depth", procName, NULL);

    if (L_ABS(angle) < MIN_ANGLE_TO_ROTATE)
        return pixClone(pixs);

    if ((pixd = pixCreateTemplateNoInit(pixs)) == NULL)
        return (PIX *) ERROR_PTR("pixd not made", procName, NULL);
    pixSetBlackOrWhite(pixd, incolor);

    sina = sin(angle);
    cosa = cos(angle);
    datad = pixGetData(pixd);
    wpld = pixGetWpl(pixd);
    wm1 = w - 1;
    hm1 = h - 1;
    lines = pixGetLinePtrs(pixs, NULL);

    /* Treat 1 bpp case specially */
    if (d == 1) {
        for (i = 0; i < h; i++) {  /* scan over pixd */
            lined = datad + i * wpld;
            ydif = ycen - i;
            for (j = 0; j < w; j++) {
                xdif = xcen - j;
                x = xcen + (l_int32)(-xdif * cosa - ydif * sina);
                if (x < 0 || x > wm1) continue;
                y = ycen + (l_int32)(-ydif * cosa + xdif * sina);
                if (y < 0 || y > hm1) continue;
                if (incolor == L_BRING_IN_WHITE) {
                    if (GET_DATA_BIT(lines[y], x))
                        SET_DATA_BIT(lined, j);
                } else {
                    if (!GET_DATA_BIT(lines[y], x))
                        CLEAR_DATA_BIT(lined, j);
                }
            }
        }
        FREE(lines);
        return pixd;
    }

    for (i = 0; i < h; i++) {  /* scan over pixd */
        lined = datad + i * wpld;
        ydif = ycen - i;
        for (j = 0; j < w; j++) {
            xdif = xcen - j;
            x = xcen + (l_int32)(-xdif * cosa - ydif * sina);
            if (x < 0 || x > wm1) continue;
            y = ycen + (l_int32)(-ydif * cosa + xdif * sina);
            if (y < 0 || y > hm1) continue;
            switch (d) {
                case 8:
                    val = GET_DATA_BYTE(lines[y], x);
                    SET_DATA_BYTE(lined, j, val);
                    break;
                case 32:
                    val = GET_DATA_FOUR_BYTES(lines[y], x);
                    SET_DATA_FOUR_BYTES(lined, j, val);
                    break;
                case 2:
                    val = GET_DATA_DIBIT(lines[y], x);
                    SET_DATA_DIBIT(lined, j, val);
                    break;
                case 4:
                    val = GET_DATA_QBIT(lines[y], x);
                    SET_DATA_QBIT(lined, j, val);
                    break;
                case 16:
                    val = GET_DATA_TWO_BYTES(lines[y], x);
                    SET_DATA_TWO_BYTES(lined, j, val);
                    break;
                default:
                    return (PIX *) ERROR_PTR("invalid depth", procName, NULL);
            }
        }
    }

    FREE(lines);
    return pixd;
}