| /*====================================================================* |
| - Copyright (C) 2001 Leptonica. All rights reserved. |
| - This software is distributed in the hope that it will be |
| - useful, but with NO WARRANTY OF ANY KIND. |
| - No author or distributor accepts responsibility to anyone for the |
| - consequences of using this software, or for whether it serves any |
| - particular purpose or works at all, unless he or she says so in |
| - writing. Everyone is granted permission to copy, modify and |
| - redistribute this source code, for commercial or non-commercial |
| - purposes, with the following restrictions: (1) the origin of this |
| - source code must not be misrepresented; (2) modified versions must |
| - be plainly marked as such; and (3) this notice may not be removed |
| - or altered from any source or modified source distribution. |
| *====================================================================*/ |
| |
| /* |
| * rop.c |
| * |
| * 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() |
| */ |
| |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include "allheaders.h" |
| |
| |
| /*--------------------------------------------------------------------* |
| * General rasterop (basic pix interface) * |
| *--------------------------------------------------------------------*/ |
| /*! |
| * pixRasterop() |
| * |
| * Input: pixd (dest pix) |
| * dx (x val of UL corner of dest rectangle) |
| * dy (y val of UL corner of dest rectangle) |
| * dw (width of dest rectangle) |
| * dh (height of dest rectangle) |
| * op (op code) |
| * pixs (src pix) |
| * sx (x val of UL corner of src rectangle) |
| * sy (y val of UL corner of src rectangle) |
| * Return: 0 if OK; 1 on error. |
| * |
| * 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. |
| */ |
| l_int32 |
| 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 * |
| *--------------------------------------------------------------------*/ |
| /*! |
| * pixRasteropVip() |
| * |
| * Input: pixd (in-place) |
| * x (left edge of vertical band) |
| * w (width of vertical band) |
| * vshift (vertical shift of band; vshift > 0 is down) |
| * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK) |
| * Return: 0 if OK; 1 on error |
| * |
| * 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. |
| */ |
| l_int32 |
| pixRasteropVip(PIX *pixd, |
| l_int32 x, |
| l_int32 w, |
| l_int32 vshift, |
| l_int32 incolor) |
| { |
| l_int32 h, d, op; |
| |
| 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 (vshift == 0) |
| return 0; |
| |
| rasteropVipLow(pixGetData(pixd), |
| pixGetWidth(pixd), pixGetHeight(pixd), |
| pixGetDepth(pixd), pixGetWpl(pixd), |
| x, w, vshift); |
| |
| d = pixGetDepth(pixd); |
| 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, x, 0, w, vshift, op, NULL, 0, 0); |
| else { /* vshift < 0 */ |
| h = pixGetHeight(pixd); |
| pixRasterop(pixd, x, h + vshift, w, -vshift, op, NULL, 0, 0); |
| } |
| |
| return 0; |
| } |
| |
| |
| /*! |
| * pixRasteropHip() |
| * |
| * Input: pixd (in-place operation) |
| * y (top of horizontal band) |
| * h (height of horizontal band) |
| * hshift (horizontal shift of band; hshift > 0 is to right) |
| * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK) |
| * Return: 0 if OK; 1 on error |
| * |
| * 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. |
| */ |
| l_int32 |
| pixRasteropHip(PIX *pixd, |
| l_int32 y, |
| l_int32 h, |
| l_int32 hshift, |
| l_int32 incolor) |
| { |
| l_int32 w, d, op; |
| |
| PROCNAME("pixRasteropHip"); |
| |
| if (!pixd) |
| return ERROR_INT("pixd not defined", procName, 1); |
| |
| if (hshift == 0) |
| return 0; |
| |
| rasteropHipLow(pixGetData(pixd), pixGetHeight(pixd), |
| pixGetDepth(pixd), pixGetWpl(pixd), |
| y, h, hshift); |
| |
| d = pixGetDepth(pixd); |
| 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, y, hshift, h, op, NULL, 0, 0); |
| else { /* hshift < 0 */ |
| w = pixGetWidth(pixd); |
| pixRasterop(pixd, w + hshift, y, -hshift, h, op, NULL, 0, 0); |
| } |
| |
| return 0; |
| } |
| |
| |
| /*--------------------------------------------------------------------* |
| * Full image translation (general and in-place) * |
| *--------------------------------------------------------------------*/ |
| /*! |
| * pixTranslate() |
| * |
| * Input: pixd (<optional> destination: this can be null, |
| * equal to pixs, or different from pixs) |
| * pixs |
| * hshift (horizontal shift; hshift > 0 is to right) |
| * vshift (vertical shift; vshift > 0 is down) |
| * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK) |
| * Return: pixd, or null on error. |
| * |
| * 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. |
| */ |
| 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; |
| } |
| |
| |
| /*! |
| * pixRasteropIP() |
| * |
| * Input: pixd (in-place translation) |
| * hshift (horizontal shift; hshift > 0 is to right) |
| * vshift (vertical shift; vshift > 0 is down) |
| * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK) |
| * Return: 0 if OK; 1 on error |
| */ |
| l_int32 |
| 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); |
| |
| w = pixGetWidth(pixd); |
| h = pixGetHeight(pixd); |
| pixRasteropHip(pixd, 0, h, hshift, incolor); |
| pixRasteropVip(pixd, 0, w, vshift, incolor); |
| |
| return 0; |
| } |
| |
| |
| /*--------------------------------------------------------------------* |
| * Full image rasterop with no shifts * |
| *--------------------------------------------------------------------*/ |
| /*! |
| * pixRasteropFullImage() |
| * |
| * Input: pixd |
| * pixs |
| * op (any of the op-codes) |
| * Return: 0 if OK; 1 on error |
| * |
| * 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 |
| */ |
| l_int32 |
| 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; |
| } |
| |