mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-17 14:16:10 -06:00
463 lines
16 KiB
C
463 lines
16 KiB
C
/*====================================================================*
|
|
- 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;
|
|
}
|
|
|