/* * 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 #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() */ };