summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Deutschmann <whissi@gentoo.org>2021-03-30 10:59:39 +0200
committerThomas Deutschmann <whissi@gentoo.org>2021-04-01 00:04:14 +0200
commit5ff1d6955496b3cf9a35042c9ac35db43bc336b1 (patch)
tree6d470f7eb448f59f53e8df1010aec9dad8ce1f72 /leptonica/src/rop.c
parentImport Ghostscript 9.53.1 (diff)
downloadghostscript-gpl-patches-5ff1d6955496b3cf9a35042c9ac35db43bc336b1.tar.gz
ghostscript-gpl-patches-5ff1d6955496b3cf9a35042c9ac35db43bc336b1.tar.bz2
ghostscript-gpl-patches-5ff1d6955496b3cf9a35042c9ac35db43bc336b1.zip
Import Ghostscript 9.54ghostscript-9.54
Signed-off-by: Thomas Deutschmann <whissi@gentoo.org>
Diffstat (limited to 'leptonica/src/rop.c')
-rw-r--r--leptonica/src/rop.c572
1 files changed, 572 insertions, 0 deletions
diff --git a/leptonica/src/rop.c b/leptonica/src/rop.c
new file mode 100644
index 00000000..e7b8939f
--- /dev/null
+++ b/leptonica/src/rop.c
@@ -0,0 +1,572 @@
+/*====================================================================*
+ - 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()
+ *
+ * Checking for invalid crop box
+ * static l_int32 checkRasteropCrop()
+ * </pre>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config_auto.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include "allheaders.h"
+
+static l_int32 checkRasteropCrop(l_int32 pixw, l_int32 pixh, l_int32 dx,
+ l_int32 dy, l_int32 dw, l_int32 dh);
+
+
+/*--------------------------------------------------------------------*
+ * 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 dpw, dph, dpd, spw, sph, spd;
+
+ PROCNAME("pixRasterop");
+
+ if (!pixd)
+ return ERROR_INT("pixd not defined", procName, 1);
+
+ if (op == PIX_DST) /* no-op */
+ return 0;
+
+ pixGetDimensions(pixd, &dpw, &dph, &dpd);
+#if 0
+ if (checkRasteropCrop(dpw, dph, dx, dy, dw, dh)) {
+ L_WARNING("dest crop box out of bounds\n", procName);
+ return 1;
+ }
+#endif
+
+ /* Check if operation is only on dest */
+ if (op == PIX_CLR || op == PIX_SET || op == PIX_NOT(PIX_DST)) {
+ rasteropUniLow(pixGetData(pixd), dpw, dph, dpd, pixGetWpl(pixd),
+ dx, dy, dw, dh, op);
+ return 0;
+ }
+
+ /* Two-image rasterop; the depths must match */
+ if (!pixs)
+ return ERROR_INT("pixs not defined", procName, 1);
+ pixGetDimensions(pixs, &spw, &sph, &spd);
+ if (dpd != spd)
+ return ERROR_INT("depths of pixs and pixd differ", procName, 1);
+#if 0
+ if (checkRasteropCrop(spw, sph, sx, sy, dw, dh)) {
+ L_WARNING("source crop box out of bounds\n", procName);
+ return 1;
+ }
+#endif
+
+ rasteropLow(pixGetData(pixd), dpw, dph, dpd, pixGetWpl(pixd),
+ dx, dy, dw, dh, op,
+ pixGetData(pixs), spw, sph, 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;
+}
+
+
+/*--------------------------------------------------------------------*
+ * Checking for invalid crop box *
+ *--------------------------------------------------------------------*/
+/*!
+ * \brief checkRasteropCrop()
+ *
+ * \param[in] pixw, pixh pix dimensions
+ * \param[in] x, y, w, h crop box parameters
+ * \return 0 if OK, 1 if the crop box does not intersect with the pix.
+ *
+ * <pre>
+ * Notes:
+ * (1) The widths and heights must all be positive, but %x and %y
+ * can take on any value.
+ * (2) This works for checking both the source and dest regions.
+ * (3) This has been used to verify rasteropLow() cropping is correct.
+ * It is not needed for pre-filtering in pixRasterop().
+ * </pre>
+ */
+static l_int32
+checkRasteropCrop(l_int32 pixw,
+ l_int32 pixh,
+ l_int32 x,
+ l_int32 y,
+ l_int32 w,
+ l_int32 h)
+{
+ PROCNAME("checkRasteropCrop");
+
+ if (pixw < 1 || pixh < 1 || w < 1 || h < 1)
+ return ERROR_INT("dimension is <= 0", procName, 1);
+
+ if (x + w <= 0 || y + h <= 0)
+ return ERROR_INT("box to left or above pix", procName, 1);
+
+ if (x >= pixw || y >= pixh)
+ return ERROR_INT("box to right or below pix", procName, 1);
+
+ return 0;
+}