| /*====================================================================* |
| - 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; |
| } |
| |