blob: 7d8ef2cb28629c0b2e3f2f7cec599a4621bd522d [file] [log] [blame]
/*====================================================================*
- 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.
*====================================================================*/
/*
* ropiplow.c
*
* Low level in-place full height vertical block transfer
*
* void rasteropVipLow()
*
* Low level in-place full width horizontal block transfer
*
* void rasteropHipLow()
* void shiftDataHorizontalLow()
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "allheaders.h"
#define COMBINE_PARTIAL(d, s, m) ( ((d) & ~(m)) | ((s) & (m)) )
static const l_uint32 lmask32[] = {0x0,
0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff};
static const l_uint32 rmask32[] = {0x0,
0x00000001, 0x00000003, 0x00000007, 0x0000000f,
0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff};
/*--------------------------------------------------------------------*
* Low-level Vertical In-place Rasterop *
*--------------------------------------------------------------------*/
/*!
* rasteropVipLow()
*
* Input: data (ptr to image data)
* pixw (width)
* pixh (height)
* depth (depth)
* wpl (wpl)
* x (x val of UL corner of rectangle)
* w (width of rectangle)
* shift (+ shifts data downward in vertical column)
* Return: 0 if OK; 1 on error.
*
* Notes:
* (1) This clears the pixels that are left exposed after the
* translation. You can consider them as pixels that are
* shifted in from outside the image. This can be later
* overridden by the incolor parameter in higher-level functions
* that call this. For example, for images with depth > 1,
* these pixels are cleared to black; to be white they
* must later be SET to white. See, e.g., pixRasteropVip().
* (2) This function scales the width to accommodate any depth,
* performs clipping, and then does the in-place rasterop.
*/
void
rasteropVipLow(l_uint32 *data,
l_int32 pixw,
l_int32 pixh,
l_int32 depth,
l_int32 wpl,
l_int32 x,
l_int32 w,
l_int32 shift)
{
l_int32 fwpartb; /* boolean (1, 0) if first word is partial */
l_int32 fwpart2b; /* boolean (1, 0) if first word is doubly partial */
l_uint32 fwmask; /* mask for first partial word */
l_int32 fwbits; /* first word bits in ovrhang */
l_uint32 *pdfwpart; /* ptr to first partial dest word */
l_uint32 *psfwpart; /* ptr to first partial src word */
l_int32 fwfullb; /* boolean (1, 0) if there exists a full word */
l_int32 nfullw; /* number of full words */
l_uint32 *pdfwfull; /* ptr to first full dest word */
l_uint32 *psfwfull; /* ptr to first full src word */
l_int32 lwpartb; /* boolean (1, 0) if last word is partial */
l_uint32 lwmask; /* mask for last partial word */
l_int32 lwbits; /* last word bits in ovrhang */
l_uint32 *pdlwpart; /* ptr to last partial dest word */
l_uint32 *pslwpart; /* ptr to last partial src word */
l_int32 dirwpl; /* directed wpl (-wpl * sign(shift)) */
l_int32 absshift; /* absolute value of shift; for use in iterator */
l_int32 vlimit; /* vertical limit value for iterations */
l_int32 i, j;
/*--------------------------------------------------------*
* Scale horizontal dimensions by depth *
*--------------------------------------------------------*/
if (depth != 1) {
pixw *= depth;
x *= depth;
w *= depth;
}
/*--------------------------------------------------------*
* Clip horizontally *
*--------------------------------------------------------*/
if (x < 0) {
w += x; /* reduce w */
x = 0; /* clip to x = 0 */
}
if (x >= pixw || w <= 0) /* no part of vertical slice is in the image */
return;
if (x + w > pixw)
w = pixw - x; /* clip to x + w = pixw */
/*--------------------------------------------------------*
* Preliminary calculations *
*--------------------------------------------------------*/
/* is the first word partial? */
if ((x & 31) == 0) { /* if not */
fwpartb = 0;
fwbits = 0;
}
else { /* if so */
fwpartb = 1;
fwbits = 32 - (x & 31);
fwmask = rmask32[fwbits];
if (shift >= 0) { /* go up from bottom */
pdfwpart = data + wpl * (pixh - 1) + (x >> 5);
psfwpart = data + wpl * (pixh - 1 - shift) + (x >> 5);
}
else { /* go down from top */
pdfwpart = data + (x >> 5);
psfwpart = data - wpl * shift + (x >> 5);
}
}
/* is the first word doubly partial? */
if (w >= fwbits) /* if not */
fwpart2b = 0;
else { /* if so */
fwpart2b = 1;
fwmask &= lmask32[32 - fwbits + w];
}
/* is there a full dest word? */
if (fwpart2b == 1) { /* not */
fwfullb = 0;
nfullw = 0;
}
else {
nfullw = (w - fwbits) >> 5;
if (nfullw == 0) /* if not */
fwfullb = 0;
else { /* if so */
fwfullb = 1;
if (fwpartb) {
pdfwfull = pdfwpart + 1;
psfwfull = psfwpart + 1;
}
else {
if (shift >= 0) { /* go up from bottom */
pdfwfull = data + wpl * (pixh - 1) + (x >> 5);
psfwfull = data + wpl * (pixh - 1 - shift) + (x >> 5);
}
else { /* go down from top */
pdfwfull = data + (x >> 5);
psfwfull = data - wpl * shift + (x >> 5);
}
}
}
}
/* is the last word partial? */
lwbits = (x + w) & 31;
if (fwpart2b == 1 || lwbits == 0) /* if not */
lwpartb = 0;
else {
lwpartb = 1;
lwmask = lmask32[lwbits];
if (fwpartb) {
pdlwpart = pdfwpart + 1 + nfullw;
pslwpart = psfwpart + 1 + nfullw;
}
else {
if (shift >= 0) { /* go up from bottom */
pdlwpart = data + wpl * (pixh - 1) + (x >> 5) + nfullw;
pslwpart = data + wpl * (pixh - 1 - shift) + (x >> 5) + nfullw;
}
else { /* go down from top */
pdlwpart = data + (x >> 5) + nfullw;
pslwpart = data - wpl * shift + (x >> 5) + nfullw;
}
}
}
/* determine the direction of flow from the shift
* If the shift >= 0, data flows downard from src
* to dest, starting at the bottom and working up.
* If shift < 0, data flows upward from src to
* dest, starting at the top and working down. */
dirwpl = (shift >= 0) ? -wpl : wpl;
absshift = L_ABS(shift);
vlimit = L_MAX(0, pixh - absshift);
/*--------------------------------------------------------*
* Now we're ready to do the ops *
*--------------------------------------------------------*/
/* Do the first partial word */
if (fwpartb) {
for (i = 0; i < vlimit; i++) {
*pdfwpart = COMBINE_PARTIAL(*pdfwpart, *psfwpart, fwmask);
pdfwpart += dirwpl;
psfwpart += dirwpl;
}
/* Clear the incoming pixels */
for (i = vlimit; i < pixh; i++) {
*pdfwpart = COMBINE_PARTIAL(*pdfwpart, 0x0, fwmask);
pdfwpart += dirwpl;
}
}
/* Do the full words */
if (fwfullb) {
for (i = 0; i < vlimit; i++) {
for (j = 0; j < nfullw; j++)
*(pdfwfull + j) = *(psfwfull + j);
pdfwfull += dirwpl;
psfwfull += dirwpl;
}
/* Clear the incoming pixels */
for (i = vlimit; i < pixh; i++) {
for (j = 0; j < nfullw; j++)
*(pdfwfull + j) = 0x0;
pdfwfull += dirwpl;
}
}
/* Do the last partial word */
if (lwpartb) {
for (i = 0; i < vlimit; i++) {
*pdlwpart = COMBINE_PARTIAL(*pdlwpart, *pslwpart, lwmask);
pdlwpart += dirwpl;
pslwpart += dirwpl;
}
/* Clear the incoming pixels */
for (i = vlimit; i < pixh; i++) {
*pdlwpart = COMBINE_PARTIAL(*pdlwpart, 0x0, lwmask);
pdlwpart += dirwpl;
}
}
return;
}
/*--------------------------------------------------------------------*
* Low-level Horizontal In-place Rasterop *
*--------------------------------------------------------------------*/
/*!
* rasteropHipLow()
*
* Input: data (ptr to image data)
* pixh (height)
* depth (depth)
* wpl (wpl)
* y (y val of UL corner of rectangle)
* h (height of rectangle)
* shift (+ shifts data downward in vertical column)
* Return: 0 if OK; 1 on error.
*
* Notes:
* (1) This clears the pixels that are left exposed after the rasterop.
* Therefore, for Pix with depth > 1, these pixels become black,
* and must be subsequently SET if they are to be white.
* For example, see pixRasteropHip().
* (2) This function performs clipping and calls shiftDataHorizontalLine()
* to do the in-place rasterop on each line.
*/
void
rasteropHipLow(l_uint32 *data,
l_int32 pixh,
l_int32 depth,
l_int32 wpl,
l_int32 y,
l_int32 h,
l_int32 shift)
{
l_int32 i;
l_uint32 *line;
/* clip band if necessary */
if (y < 0) {
h += y; /* reduce h */
y = 0; /* clip to y = 0 */
}
if (h <= 0 || y > pixh) /* no part of horizontal slice is in the image */
return;
if (y + h > pixh)
h = pixh - y; /* clip to y + h = pixh */
for (i = y; i < y + h; i++) {
line = data + i * wpl;
shiftDataHorizontalLow(line, wpl, line, wpl, shift * depth);
}
}
/*!
* shiftDataHorizontalLow()
*
* Input: datad (ptr to beginning of dest line)
* wpld (wpl of dest)
* datas (ptr to beginning of src line)
* wpls (wpl of src)
* shift (horizontal shift of block; >0 is to right)
* Return: void
*
* Notes:
* (1) This can also be used for in-place operation; see, e.g.,
* rasteropHipLow().
* (2) We are clearing the pixels that are shifted in from
* outside the image. This can be overridden by the
* incolor parameter in higher-level functions that call this.
*/
void
shiftDataHorizontalLow(l_uint32 *datad,
l_int32 wpld,
l_uint32 *datas,
l_int32 wpls,
l_int32 shift)
{
l_int32 j, firstdw, wpl, rshift, lshift;
l_uint32 *lined, *lines;
lined = datad;
lines = datas;
if (shift >= 0) { /* src shift to right; data flows to
* right, starting at right edge and
* progressing leftward. */
firstdw = shift / 32;
wpl = L_MIN(wpls, wpld - firstdw);
lined += firstdw + wpl - 1;
lines += wpl - 1;
rshift = shift & 31;
if (rshift == 0) {
for (j = 0; j < wpl; j++)
*lined-- = *lines--;
/* clear out the rest to the left edge */
for (j = 0; j < firstdw; j++)
*lined-- = 0;
}
else {
lshift = 32 - rshift;
for (j = 1; j < wpl; j++) {
*lined-- = *(lines - 1) << lshift | *lines >> rshift;
lines--;
}
*lined = *lines >> rshift; /* partial first */
/* clear out the rest to the left edge */
*lined &= ~lmask32[rshift];
lined--;
for (j = 0; j < firstdw; j++)
*lined-- = 0;
}
}
else { /* src shift to left; data flows to left, starting
* at left edge and progressing rightward. */
firstdw = (-shift) / 32;
wpl = L_MIN(wpls - firstdw, wpld);
lines += firstdw;
lshift = (-shift) & 31;
if (lshift == 0) {
for (j = 0; j < wpl; j++)
*lined++ = *lines++;
/* clear out the rest to the right edge */
for (j = 0; j < firstdw; j++)
*lined++ = 0;
}
else {
rshift = 32 - lshift;
for (j = 1; j < wpl; j++) {
*lined++ = *lines << lshift | *(lines + 1) >> rshift;
lines++;
}
*lined = *lines << lshift; /* partial last */
/* clear out the rest to the right edge */
/* first clear the lshift pixels of this partial word */
*lined &= ~rmask32[lshift];
lined++;
/* then the remaining words to the right edge */
for (j = 0; j < firstdw; j++)
*lined++ = 0;
}
}
return;
}