406 lines
15 KiB
C
406 lines
15 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these libraries and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/* $XConsortium: ilgraybi.c /main/6 1996/10/30 11:09:02 drk $ */
|
|
/**---------------------------------------------------------------------
|
|
***
|
|
*** (c)Copyright 1991 Hewlett-Packard Co.
|
|
***
|
|
*** RESTRICTED RIGHTS LEGEND
|
|
*** Use, duplication, or disclosure by the U.S. Government is subject to
|
|
*** restrictions as set forth in sub-paragraph (c)(1)(ii) of the Rights in
|
|
*** Technical Data and Computer Software clause in DFARS 252.227-7013.
|
|
*** Hewlett-Packard Company
|
|
*** 3000 Hanover Street
|
|
*** Palo Alto, CA 94304 U.S.A.
|
|
*** Rights for non-DOD U.S. Government Departments and Agencies are as set
|
|
*** forth in FAR 52.227-19(c)(1,2).
|
|
***
|
|
***-------------------------------------------------------------------*/
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "ilint.h"
|
|
#include "ilpipelem.h"
|
|
#include "ilconvert.h"
|
|
#include "ilerrors.h"
|
|
|
|
#ifndef LSB_BIT_ORDER
|
|
# define flip_bits(start,n) /*EMPTY*/
|
|
#else
|
|
extern void flip_bits(ilPtr start, unsigned n);
|
|
|
|
extern void
|
|
flip_bits(ilPtr start,
|
|
unsigned n )
|
|
{
|
|
int i;
|
|
unsigned char c;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
c = *start;
|
|
*start++ = ilBitReverseTable[c];
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* =========================== BITONAL DITHER CODE =============================== */
|
|
|
|
/* Private data for error diffusion to bitonal, inited by Init() function. */
|
|
typedef struct {
|
|
long width; /* width of src/dst images */
|
|
long srcRowBytes; /* bytes/row of src image */
|
|
ilPtr pSrcPixels; /* ptr to start of src pixels */
|
|
long dstRowBytes; /* bytes/row of dst image */
|
|
ilPtr pDstPixels; /* ptr to start of dst pixels */
|
|
ilBool blackIsZero; /* src image: true if 0 is black, else white */
|
|
short *pError1, *pError2; /* ptr to error accumulator buffers */
|
|
} ilBiDiffusionPrivRec, *ilBiDiffusionPrivPtr;
|
|
|
|
|
|
/* Init() function: malloc and zero error accumulator buffers. */
|
|
static ilError ilInitBiDiffusion (
|
|
ilBiDiffusionPrivPtr pPriv,
|
|
ilImageInfo *pSrcImage,
|
|
ilImageInfo *pDstImage
|
|
)
|
|
{
|
|
pPriv->width = pSrcImage->width;
|
|
pPriv->srcRowBytes = pSrcImage->plane[0].nBytesPerRow;
|
|
pPriv->pSrcPixels = pSrcImage->plane[0].pPixels;
|
|
pPriv->dstRowBytes = pDstImage->plane[0].nBytesPerRow;
|
|
pPriv->pDstPixels = pDstImage->plane[0].pPixels;
|
|
pPriv->blackIsZero = pSrcImage->pDes->blackIsZero;
|
|
|
|
/* Create error accumulator buffers, 2 larger than width because the pixels
|
|
above to the left and right are examined.
|
|
*/
|
|
pPriv->pError1 = (short *)IL_MALLOC_ZERO (sizeof (short) * (pPriv->width + 2));
|
|
pPriv->pError2 = (short *)IL_MALLOC_ZERO (sizeof (short) * (pPriv->width + 2));
|
|
if (!pPriv->pError1 || !pPriv->pError2)
|
|
return IL_ERROR_MALLOC;
|
|
|
|
return IL_OK;
|
|
}
|
|
|
|
/* Cleanup() function: dispose error accumulator buffers. */
|
|
static ilError ilCleanupBiDiffusion (
|
|
ilBiDiffusionPrivPtr pPriv
|
|
)
|
|
{
|
|
if (pPriv->pError1)
|
|
IL_FREE (pPriv->pError1);
|
|
if (pPriv->pError2)
|
|
IL_FREE (pPriv->pError2);
|
|
return IL_OK;
|
|
}
|
|
|
|
/* ----------------------- ilDiffuseGrayToBitonal ------------------------- */
|
|
/* Dithers using error diffusion to bitonal.
|
|
Input image: IL_DES_GRAY, IL_FORMAT_BYTE.
|
|
Output image: IL_DES_BITONAL, IL_FORMAT_BIT
|
|
*/
|
|
|
|
/* Execute() function: dither and pack the given # of src lines. */
|
|
static ilError ilExecuteBiDiffusion (
|
|
ilExecuteData *pData,
|
|
long dstLine,
|
|
long *pNLines /* ignored on input */
|
|
)
|
|
{
|
|
#ifdef LSB_BIT_ORDER
|
|
# define SPECIAL_MASK_BIT 0x00000001 /* for LSB bit order */
|
|
# define SHIFT_MASK(m) ((m) <<= 1)
|
|
#else
|
|
# define SPECIAL_MASK_BIT 0x80000000 /* for MSB bit order */
|
|
# define SHIFT_MASK(m) ((m) >>= 1)
|
|
#endif
|
|
ilBiDiffusionPrivPtr pPriv;
|
|
long nLinesM1, nPixelsM1Init, nPixelsM1;
|
|
short *pPrevError, *pError;
|
|
int errorAcc, invert;
|
|
long srcRowBytes, dstRowBytes;
|
|
ilPtr pSrcLine, pDstLine;
|
|
ilPtr pSrc;
|
|
CARD32 mask, *pDst;
|
|
CARD32 outLong;
|
|
|
|
pPriv = (ilBiDiffusionPrivPtr)pData->pPrivate;
|
|
srcRowBytes = pPriv->srcRowBytes;
|
|
pSrcLine = pPriv->pSrcPixels + pData->srcLine * srcRowBytes;
|
|
dstRowBytes = pPriv->dstRowBytes;
|
|
pDstLine = pPriv->pDstPixels + dstLine * dstRowBytes;
|
|
|
|
nLinesM1 = *pNLines;
|
|
if (nLinesM1 <= 0)
|
|
return IL_OK;
|
|
nLinesM1--;
|
|
|
|
nPixelsM1Init = pPriv->width;
|
|
if (nPixelsM1Init <= 0)
|
|
return IL_OK;
|
|
nPixelsM1Init--;
|
|
|
|
/* Set "invert" to 0 if blackIsZero, else to 0xff, and xor each src pixel
|
|
with invert. Thus if 0 is white, the xor turns 0 into 255, 1 into 254, etc.
|
|
*/
|
|
invert = (pPriv->blackIsZero) ? 0 : 0xff;
|
|
|
|
/* Dither: do Floyd-Steinberg dither (error diffusion) requiring src to be
|
|
256 gray levels. True error diffusion would map:
|
|
(srcLevels-1)/(dstLevels-1) = 255/1
|
|
but we will use 256/1 to make muls/divs easy. Use the following:
|
|
1/16 5/16 3/16
|
|
7/16 x
|
|
where the fractions indicate what portion of the error from the surrounding
|
|
pixels should be added to this pixels value (x) to determine dst pixel to
|
|
write at "x".
|
|
*/
|
|
do {
|
|
pSrc = pSrcLine;
|
|
pSrcLine += srcRowBytes;
|
|
pDst = (CARD32 *)pDstLine;
|
|
pDstLine += dstRowBytes;
|
|
|
|
/* Point to error accumulator buffers and switch, so *pError becomes
|
|
*pPrevError for next line. Bump ptrs by 1: prev scan line error is
|
|
examined above to left and right: need zero extra value there to handle
|
|
beginning/end of line.
|
|
*/
|
|
pError = pPriv->pError1;
|
|
pPrevError = pPriv->pError2;
|
|
pPriv->pError1 = pPrevError;
|
|
pPriv->pError2 = pError;
|
|
pError++;
|
|
pPrevError++;
|
|
errorAcc = 0; /* holds error from pixel to the left */
|
|
|
|
mask = SPECIAL_MASK_BIT;
|
|
|
|
outLong = 0;
|
|
nPixelsM1 = nPixelsM1Init;
|
|
do {
|
|
errorAcc *= 7; /* 7 * error to left */
|
|
errorAcc += *(pPrevError - 1); /* 1 * error above left */
|
|
errorAcc += 5 * *pPrevError++; /* 5 * error above */
|
|
errorAcc += 3 * *pPrevError; /* 3 * error above right */
|
|
errorAcc >>= 4; /* /16 */
|
|
errorAcc += *pSrc++ ^ invert; /* + "x"; w/ blackIsZero handled */
|
|
if (errorAcc >= 128) /* output white: don't set out bit */
|
|
errorAcc -= 255; /* sub value of white from errorAcc */
|
|
else /* output black: errorAcc -= 0 */
|
|
outLong |= mask;
|
|
*pError++ = errorAcc; /* store error into buffer */
|
|
if (!(SHIFT_MASK(mask))) {
|
|
flip_bits((ilPtr)&outLong, sizeof(outLong));
|
|
*pDst++ = outLong;
|
|
mask = SPECIAL_MASK_BIT;
|
|
outLong = 0;
|
|
}
|
|
} while (--nPixelsM1 >= 0);
|
|
|
|
if (mask != SPECIAL_MASK_BIT) { /* bits left in outLong; write them */
|
|
flip_bits((ilPtr)&outLong, sizeof(outLong));
|
|
*pDst++ = outLong;
|
|
}
|
|
|
|
} while (--nLinesM1 >= 0);
|
|
|
|
return IL_OK;
|
|
}
|
|
|
|
/* Table exported to ilConvert(), declared in /ilc/ilconvert.h . */
|
|
IL_PRIVATE ilConvertRec _ilDiffuseGrayToBitonal = {
|
|
IL_NPF, /* CheckFormat() */
|
|
IL_STD_FORMAT_BYTE, /* srcFormatCode */
|
|
IL_NPF, /* AddElement() */
|
|
IL_DES_BITONAL, /* pDstDes */
|
|
IL_FORMAT_BIT, /* pDstFormat */
|
|
sizeof (ilBiDiffusionPrivRec), /* nBytesPrivate */
|
|
ilInitBiDiffusion, /* Init() */
|
|
ilCleanupBiDiffusion, /* Cleanup() */
|
|
IL_NPF, /* Destroy() */
|
|
ilExecuteBiDiffusion /* Execute() */
|
|
};
|
|
|
|
|
|
/* =========================== BITONAL THRESHOLD CODE =============================== */
|
|
|
|
/* ----------------------- ilThresholdGrayToBitonal ------------------------- */
|
|
/* Convert gray to bitonal using a user-defined threshold.
|
|
Input image: IL_DES_GRAY, IL_FORMAT_BYTE.
|
|
Output image: IL_DES_BITONAL, IL_FORMAT_BIT
|
|
*/
|
|
|
|
/* Private data for threshold conversion, inited by Init() function. */
|
|
typedef struct {
|
|
CARD32 *pThreshold; /* ptr to threshold for such gray->bi cvts */
|
|
long width; /* width of src/dst images */
|
|
long srcRowBytes; /* bytes/row of src image */
|
|
ilPtr pSrcPixels; /* ptr to start of src pixels */
|
|
long dstRowBytes; /* bytes/row of dst image */
|
|
ilPtr pDstPixels; /* ptr to start of dst pixels */
|
|
ilBool blackIsZero; /* true if 0 is black, else is white */
|
|
} ilThresholdPrivRec, *ilThresholdPrivPtr;
|
|
|
|
/* AddElement function: save copy of pThreshold (pOptionData to ilConvert())
|
|
into private. This ptr is dereferenced every time the pipe is run, allowing
|
|
the caller to change the threshold without reforming the pipe.
|
|
*/
|
|
static ilError ilAddElementThreshold (
|
|
ilThresholdPrivPtr pPriv,
|
|
unsigned short *pPalette, /* not used */
|
|
CARD32 *pThreshold /* pOptionData to ilConvert() */
|
|
)
|
|
{
|
|
pPriv->pThreshold = pThreshold;
|
|
return IL_OK;
|
|
}
|
|
|
|
/* Init() function: init the counter of "y" within private; load image pixel
|
|
address and rowBytes into private for faster reference in Execute().
|
|
*/
|
|
static ilError ilInitThreshold (
|
|
ilThresholdPrivPtr pPriv,
|
|
ilImageInfo *pSrcImage,
|
|
ilImageInfo *pDstImage
|
|
)
|
|
{
|
|
pPriv->width = pSrcImage->width;
|
|
pPriv->srcRowBytes = pSrcImage->plane[0].nBytesPerRow;
|
|
pPriv->pSrcPixels = pSrcImage->plane[0].pPixels;
|
|
pPriv->dstRowBytes = pDstImage->plane[0].nBytesPerRow;
|
|
pPriv->pDstPixels = pDstImage->plane[0].pPixels;
|
|
|
|
pPriv->blackIsZero = pSrcImage->pDes->blackIsZero;
|
|
return IL_OK;
|
|
}
|
|
|
|
/* Execute() function: dither and pack the given # of src lines.
|
|
*/
|
|
static ilError ilExecuteThreshold (
|
|
ilExecuteData *pData,
|
|
long dstLine,
|
|
long *pNLines /* ignored on input */
|
|
)
|
|
{
|
|
#ifdef LSB_BIT_ORDER
|
|
# define SPECIAL_MASK_BIT 0x00000001 /* for LSB bit order */
|
|
# define SHIFT_MASK(m) ((m) <<= 1)
|
|
#else
|
|
# define SPECIAL_MASK_BIT 0x80000000 /* for MSB bit order */
|
|
# define SHIFT_MASK(m) ((m) >>= 1)
|
|
#endif
|
|
ilThresholdPrivPtr pPriv;
|
|
long nLinesM1, nPixelsM1Init;
|
|
long srcRowBytes, dstRowBytes;
|
|
ilPtr pSrcLine, pDstLine;
|
|
long nPixelsM1;
|
|
ilPtr pSrc;
|
|
CARD32 mask, *pDst;
|
|
CARD32 outLong;
|
|
ilByte threshold;
|
|
|
|
pPriv = (ilThresholdPrivPtr)pData->pPrivate;
|
|
threshold = *pPriv->pThreshold;
|
|
srcRowBytes = pPriv->srcRowBytes;
|
|
pSrcLine = pPriv->pSrcPixels + pData->srcLine * srcRowBytes;
|
|
dstRowBytes = pPriv->dstRowBytes;
|
|
pDstLine = pPriv->pDstPixels + dstLine * dstRowBytes;
|
|
|
|
nLinesM1 = *pNLines;
|
|
if (nLinesM1 <= 0)
|
|
return IL_OK;;
|
|
nLinesM1--;
|
|
nPixelsM1Init = pPriv->width;
|
|
if (nPixelsM1Init <= 0)
|
|
return IL_OK;
|
|
nPixelsM1Init--;
|
|
|
|
/* For each pixel, compare to the threshold and output black if
|
|
< threshold (0 = black) or >= threshold (0 = white).
|
|
*/
|
|
do {
|
|
pSrc = pSrcLine;
|
|
pSrcLine += srcRowBytes;
|
|
pDst = (CARD32 *)pDstLine;
|
|
pDstLine += dstRowBytes;
|
|
mask = SPECIAL_MASK_BIT;
|
|
outLong = 0;
|
|
nPixelsM1 = nPixelsM1Init;
|
|
|
|
if (pPriv->blackIsZero) {
|
|
do {
|
|
if (*pSrc++ < threshold)
|
|
outLong |= mask;
|
|
if (! SHIFT_MASK(mask)) {
|
|
flip_bits((ilPtr)&outLong, sizeof(outLong));
|
|
*pDst++ = outLong;
|
|
mask = SPECIAL_MASK_BIT;
|
|
outLong = 0;
|
|
}
|
|
} while (--nPixelsM1 >= 0);
|
|
}
|
|
else {
|
|
do {
|
|
if (*pSrc++ >= threshold)
|
|
outLong |= mask;
|
|
if (! SHIFT_MASK(mask)) {
|
|
flip_bits((ilPtr)&outLong, sizeof(outLong));
|
|
*pDst++ = outLong;
|
|
mask = SPECIAL_MASK_BIT;
|
|
outLong = 0;
|
|
}
|
|
} while (--nPixelsM1 >= 0);
|
|
}
|
|
|
|
/* If mask != left bit on, some bits in outLong; output them. Next line.
|
|
*/
|
|
if (mask != SPECIAL_MASK_BIT) {
|
|
flip_bits((ilPtr)&outLong, sizeof(outLong));
|
|
*pDst++ = outLong;
|
|
}
|
|
|
|
} while (--nLinesM1 >= 0);
|
|
|
|
return IL_OK;
|
|
}
|
|
|
|
/* Table exported to ilConvert(), declared in /ilc/ilconvert.h .
|
|
Convert using a user-supplied threshold.
|
|
Input image: IL_DES_GRAY (either form of blackIsZero), IL_FORMAT_BYTE.
|
|
Output image: IL_DES_BITONAL, IL_FORMAT_BIT
|
|
*/
|
|
IL_PRIVATE ilConvertRec _ilThresholdGrayToBitonal = {
|
|
IL_NPF, /* CheckFormat() */
|
|
IL_STD_FORMAT_BYTE, /* srcFormatCode */
|
|
ilAddElementThreshold, /* AddElement() */
|
|
IL_DES_BITONAL, /* pDstDes */
|
|
IL_FORMAT_BIT, /* pDstFormat */
|
|
sizeof (ilThresholdPrivRec), /* nBytesPrivate */
|
|
ilInitThreshold, /* Init() */
|
|
IL_NPF, /* Cleanup() */
|
|
IL_NPF, /* Destroy() */
|
|
ilExecuteThreshold /* Execute() */
|
|
};
|
|
|