twain3.0/3rdparty/hgOCR/leptonica/rop.c

517 lines
18 KiB
C
Raw Permalink Normal View History

2021-11-20 06:24:33 +00:00
/*====================================================================*
- 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 rop.c
* <pre>
* General rasterop
* l_int32 pixRasterop()
*
* In-place full band translation
* l_int32 pixRasteropVip()
* l_int32 pixRasteropHip()
*
* Full image translation (general and in-place)
* l_int32 pixTranslate()
* l_int32 pixRasteropIP()
*
* Full image rasterop with no translation
* l_int32 pixRasteropFullImage()
* </pre>
*/
#include <string.h>
#include "allheaders.h"
/*--------------------------------------------------------------------*
* General rasterop (basic pix interface) *
*--------------------------------------------------------------------*/
/*!
* \brief pixRasterop()
*
* \param[in] pixd dest pix
* \param[in] dx x val of UL corner of dest rectangle
* \param[in] dy y val of UL corner of dest rectangle
* \param[in] dw width of dest rectangle
* \param[in] dh height of dest rectangle
* \param[in] op op code
* \param[in] pixs src pix
* \param[in] sx x val of UL corner of src rectangle
* \param[in] sy y val of UL corner of src rectangle
* \return 0 if OK; 1 on error.
*
* <pre>
* Notes:
* (1) This has the standard set of 9 args for rasterop.
* This function is your friend; it is worth memorizing!
* (2) If the operation involves only dest, this calls
* rasteropUniLow(). Otherwise, checks depth of the
* src and dest, and if they match, calls rasteropLow().
* (3) For the two-image operation, where both pixs and pixd
* are defined, they are typically different images. However
* there are cases, such as pixSetMirroredBorder(), where
* in-place operations can be done, blitting pixels from
* one part of pixd to another. Consequently, we permit
* such operations. If you use them, be sure that there
* is no overlap between the source and destination rectangles
* in pixd (!)
*
* Background:
* -----------
*
* There are 18 operations, described by the op codes in pix.h.
*
* One, PIX_DST, is a no-op.
*
* Three, PIX_CLR, PIX_SET, and PIX_NOT(PIX_DST) operate only on the dest.
* These are handled by the low-level rasteropUniLow().
*
* The other 14 involve the both the src and the dest, and depend on
* the bit values of either just the src or the bit values of both
* src and dest. They are handled by rasteropLow():
*
* PIX_SRC s
* PIX_NOT(PIX_SRC) ~s
* PIX_SRC | PIX_DST s | d
* PIX_SRC & PIX_DST s & d
* PIX_SRC ^ PIX_DST s ^ d
* PIX_NOT(PIX_SRC) | PIX_DST ~s | d
* PIX_NOT(PIX_SRC) & PIX_DST ~s & d
* PIX_NOT(PIX_SRC) ^ PIX_DST ~s ^ d
* PIX_SRC | PIX_NOT(PIX_DST) s | ~d
* PIX_SRC & PIX_NOT(PIX_DST) s & ~d
* PIX_SRC ^ PIX_NOT(PIX_DST) s ^ ~d
* PIX_NOT(PIX_SRC | PIX_DST) ~(s | d)
* PIX_NOT(PIX_SRC & PIX_DST) ~(s & d)
* PIX_NOT(PIX_SRC ^ PIX_DST) ~(s ^ d)
*
* Each of these is implemented with one of three low-level
* functions, depending on the alignment of the left edge
* of the src and dest rectangles:
* * a fastest implementation if both left edges are
* (32-bit) word aligned
* * a very slightly slower implementation if both left
* edges have the same relative (32-bit) word alignment
* * the general routine that is invoked when
* both left edges have different word alignment
*
* Of the 14 binary rasterops above, only 12 are unique
* logical combinations (out of a possible 16) of src
* and dst bits:
*
* (sd) (11) (10) (01) (00)
* -----------------------------------------------
* s 1 1 0 0
* ~s 0 1 0 1
* s | d 1 1 1 0
* s & d 1 0 0 0
* s ^ d 0 1 1 0
* ~s | d 1 0 1 1
* ~s & d 0 0 1 0
* ~s ^ d 1 0 0 1
* s | ~d 1 1 0 1
* s & ~d 0 1 0 0
* s ^ ~d 1 0 0 1
* ~(s | d) 0 0 0 1
* ~(s & d) 0 1 1 1
* ~(s ^ d) 1 0 0 1
*
* Note that the following three operations are equivalent:
* ~(s ^ d)
* ~s ^ d
* s ^ ~d
* and in the implementation, we call them out with the first form;
* namely, ~(s ^ d).
*
* Of the 16 possible binary combinations of src and dest bits,
* the remaining 4 unique ones are independent of the src bit.
* They depend on either just the dest bit or on neither
* the src nor dest bits:
*
* d 1 0 1 0 (indep. of s)
* ~d 0 1 0 1 (indep. of s)
* CLR 0 0 0 0 (indep. of both s & d)
* SET 1 1 1 1 (indep. of both s & d)
*
* As mentioned above, three of these are implemented by
* rasteropUniLow(), and one is a no-op.
*
* How can these operation codes be represented by bits
* in such a way that when the basic operations are performed
* on the bits the results are unique for unique
* operations, and mimic the logic table given above?
*
* The answer is to choose a particular order of the pairings:
* (sd) (11) (10) (01) (00)
* (which happens to be the same as in the above table)
* and to translate the result into 4-bit representations
* of s and d. For example, the Sun rasterop choice
* (omitting the extra bit for clipping) is
*
* PIX_SRC 0xc
* PIX_DST 0xa
*
* This corresponds to our pairing order given above:
* (sd) (11) (10) (01) (00)
* where for s = 1 we get the bit pattern
* PIX_SRC: 1 1 0 0 (0xc)
* and for d = 1 we get the pattern
* PIX_DST: 1 0 1 0 (0xa)
*
* OK, that's the pairing order that Sun chose. How many different
* ways can we assign bit patterns to PIX_SRC and PIX_DST to get
* the boolean ops to work out? Any of the 4 pairs can be put
* in the first position, any of the remaining 3 pairs can go
* in the second; and one of the remaining 2 pairs can go the the third.
* There is a total of 4*3*2 = 24 ways these pairs can be permuted.
* </pre>
*/
l_ok
pixRasterop(PIX *pixd,
l_int32 dx,
l_int32 dy,
l_int32 dw,
l_int32 dh,
l_int32 op,
PIX *pixs,
l_int32 sx,
l_int32 sy)
{
l_int32 dd;
PROCNAME("pixRasterop");
if (!pixd)
return ERROR_INT("pixd not defined", procName, 1);
if (op == PIX_DST) /* no-op */
return 0;
/* Check if operation is only on dest */
dd = pixGetDepth(pixd);
if (op == PIX_CLR || op == PIX_SET || op == PIX_NOT(PIX_DST)) {
rasteropUniLow(pixGetData(pixd),
pixGetWidth(pixd), pixGetHeight(pixd), dd,
pixGetWpl(pixd),
dx, dy, dw, dh,
op);
return 0;
}
if (!pixs)
return ERROR_INT("pixs not defined", procName, 1);
/* Check depth of src and dest; these must agree */
if (dd != pixGetDepth(pixs))
return ERROR_INT("depths of pixs and pixd differ", procName, 1);
rasteropLow(pixGetData(pixd),
pixGetWidth(pixd), pixGetHeight(pixd), dd,
pixGetWpl(pixd),
dx, dy, dw, dh,
op,
pixGetData(pixs),
pixGetWidth(pixs), pixGetHeight(pixs),
pixGetWpl(pixs),
sx, sy);
return 0;
}
/*--------------------------------------------------------------------*
* In-place full band translation *
*--------------------------------------------------------------------*/
/*!
* \brief pixRasteropVip()
*
* \param[in] pixd in-place
* \param[in] bx left edge of vertical band
* \param[in] bw width of vertical band
* \param[in] vshift vertical shift of band; vshift > 0 is down
* \param[in] incolor L_BRING_IN_WHITE, L_BRING_IN_BLACK
* \return 0 if OK; 1 on error
*
* <pre>
* Notes:
* (1) This rasterop translates a vertical band of the
* image either up or down, bringing in either white
* or black pixels from outside the image.
* (2) The vertical band extends the full height of pixd.
* (3) If a colormap exists, the nearest color to white or black
* is brought in.
* </pre>
*/
l_ok
pixRasteropVip(PIX *pixd,
l_int32 bx,
l_int32 bw,
l_int32 vshift,
l_int32 incolor)
{
l_int32 w, h, d, index, op;
PIX *pixt;
PIXCMAP *cmap;
PROCNAME("pixRasteropVip");
if (!pixd)
return ERROR_INT("pixd not defined", procName, 1);
if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
return ERROR_INT("invalid value for incolor", procName, 1);
if (bw <= 0)
return ERROR_INT("bw must be > 0", procName, 1);
if (vshift == 0)
return 0;
pixGetDimensions(pixd, &w, &h, &d);
rasteropVipLow(pixGetData(pixd), w, h, d, pixGetWpl(pixd), bx, bw, vshift);
cmap = pixGetColormap(pixd);
if (!cmap) {
if ((d == 1 && incolor == L_BRING_IN_BLACK) ||
(d > 1 && incolor == L_BRING_IN_WHITE))
op = PIX_SET;
else
op = PIX_CLR;
/* Set the pixels brought in at top or bottom */
if (vshift > 0)
pixRasterop(pixd, bx, 0, bw, vshift, op, NULL, 0, 0);
else /* vshift < 0 */
pixRasterop(pixd, bx, h + vshift, bw, -vshift, op, NULL, 0, 0);
return 0;
}
/* Get the nearest index and fill with that */
if (incolor == L_BRING_IN_BLACK)
pixcmapGetRankIntensity(cmap, 0.0, &index);
else /* white */
pixcmapGetRankIntensity(cmap, 1.0, &index);
pixt = pixCreate(bw, L_ABS(vshift), d);
pixSetAllArbitrary(pixt, index);
if (vshift > 0)
pixRasterop(pixd, bx, 0, bw, vshift, PIX_SRC, pixt, 0, 0);
else /* vshift < 0 */
pixRasterop(pixd, bx, h + vshift, bw, -vshift, PIX_SRC, pixt, 0, 0);
pixDestroy(&pixt);
return 0;
}
/*!
* \brief pixRasteropHip()
*
* \param[in] pixd in-place operation
* \param[in] by top of horizontal band
* \param[in] bh height of horizontal band
* \param[in] hshift horizontal shift of band; hshift > 0 is to right
* \param[in] incolor L_BRING_IN_WHITE, L_BRING_IN_BLACK
* \return 0 if OK; 1 on error
*
* <pre>
* Notes:
* (1) This rasterop translates a horizontal band of the
* image either left or right, bringing in either white
* or black pixels from outside the image.
* (2) The horizontal band extends the full width of pixd.
* (3) If a colormap exists, the nearest color to white or black
* is brought in.
* </pre>
*/
l_ok
pixRasteropHip(PIX *pixd,
l_int32 by,
l_int32 bh,
l_int32 hshift,
l_int32 incolor)
{
l_int32 w, h, d, index, op;
PIX *pixt;
PIXCMAP *cmap;
PROCNAME("pixRasteropHip");
if (!pixd)
return ERROR_INT("pixd not defined", procName, 1);
if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
return ERROR_INT("invalid value for incolor", procName, 1);
if (bh <= 0)
return ERROR_INT("bh must be > 0", procName, 1);
if (hshift == 0)
return 0;
pixGetDimensions(pixd, &w, &h, &d);
rasteropHipLow(pixGetData(pixd), h, d, pixGetWpl(pixd), by, bh, hshift);
cmap = pixGetColormap(pixd);
if (!cmap) {
if ((d == 1 && incolor == L_BRING_IN_BLACK) ||
(d > 1 && incolor == L_BRING_IN_WHITE))
op = PIX_SET;
else
op = PIX_CLR;
/* Set the pixels brought in at left or right */
if (hshift > 0)
pixRasterop(pixd, 0, by, hshift, bh, op, NULL, 0, 0);
else /* hshift < 0 */
pixRasterop(pixd, w + hshift, by, -hshift, bh, op, NULL, 0, 0);
return 0;
}
/* Get the nearest index and fill with that */
if (incolor == L_BRING_IN_BLACK)
pixcmapGetRankIntensity(cmap, 0.0, &index);
else /* white */
pixcmapGetRankIntensity(cmap, 1.0, &index);
pixt = pixCreate(L_ABS(hshift), bh, d);
pixSetAllArbitrary(pixt, index);
if (hshift > 0)
pixRasterop(pixd, 0, by, hshift, bh, PIX_SRC, pixt, 0, 0);
else /* hshift < 0 */
pixRasterop(pixd, w + hshift, by, -hshift, bh, PIX_SRC, pixt, 0, 0);
pixDestroy(&pixt);
return 0;
}
/*--------------------------------------------------------------------*
* Full image translation (general and in-place) *
*--------------------------------------------------------------------*/
/*!
* \brief pixTranslate()
*
* \param[in] pixd [optional] destination: this can be null,
* equal to pixs, or different from pixs
* \param[in] pixs
* \param[in] hshift horizontal shift; hshift > 0 is to right
* \param[in] vshift vertical shift; vshift > 0 is down
* \param[in] incolor L_BRING_IN_WHITE, L_BRING_IN_BLACK
* \return pixd, or NULL on error.
*
* <pre>
* Notes:
* (1) The general pattern is:
* pixd = pixTranslate(pixd, pixs, ...);
* For clarity, when you know the case, use one of these:
* pixd = pixTranslate(NULL, pixs, ...); // new
* pixTranslate(pixs, pixs, ...); // in-place
* pixTranslate(pixd, pixs, ...); // to existing pixd
* (2) If an existing pixd is not the same size as pixs, the
* image data will be reallocated.
* </pre>
*/
PIX *
pixTranslate(PIX *pixd,
PIX *pixs,
l_int32 hshift,
l_int32 vshift,
l_int32 incolor)
{
PROCNAME("pixTranslate");
if (!pixs)
return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
/* Prepare pixd for in-place operation */
if ((pixd = pixCopy(pixd, pixs)) == NULL)
return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
pixRasteropIP(pixd, hshift, vshift, incolor);
return pixd;
}
/*!
* \brief pixRasteropIP()
*
* \param[in] pixd in-place translation
* \param[in] hshift horizontal shift; hshift > 0 is to right
* \param[in] vshift vertical shift; vshift > 0 is down
* \param[in] incolor L_BRING_IN_WHITE, L_BRING_IN_BLACK
* \return 0 if OK; 1 on error
*/
l_ok
pixRasteropIP(PIX *pixd,
l_int32 hshift,
l_int32 vshift,
l_int32 incolor)
{
l_int32 w, h;
PROCNAME("pixRasteropIP");
if (!pixd)
return ERROR_INT("pixd not defined", procName, 1);
pixGetDimensions(pixd, &w, &h, NULL);
pixRasteropHip(pixd, 0, h, hshift, incolor);
pixRasteropVip(pixd, 0, w, vshift, incolor);
return 0;
}
/*--------------------------------------------------------------------*
* Full image rasterop with no shifts *
*--------------------------------------------------------------------*/
/*!
* \brief pixRasteropFullImage()
*
* \param[in] pixd
* \param[in] pixs
* \param[in] op any of the op-codes
* \return 0 if OK; 1 on error
*
* <pre>
* Notes:
* ~ this is a wrapper for a common 2-image raster operation
* ~ both pixs and pixd must be defined
* ~ the operation is performed with aligned UL corners of pixs and pixd
* ~ the operation clips to the smallest pix; if the width or height
* of pixd is larger than pixs, some pixels in pixd will be unchanged
* </pre>
*/
l_ok
pixRasteropFullImage(PIX *pixd,
PIX *pixs,
l_int32 op)
{
PROCNAME("pixRasteropFullImage");
if (!pixd)
return ERROR_INT("pixd not defined", procName, 1);
if (!pixs)
return ERROR_INT("pixs not defined", procName, 1);
pixRasterop(pixd, 0, 0, pixGetWidth(pixd), pixGetHeight(pixd), op,
pixs, 0, 0);
return 0;
}