123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456 |
- /*
- * 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: ilXycbcr.c /main/3 1995/10/23 15:41:23 rswiston $ */
- /**---------------------------------------------------------------------
- ***
- *** (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 "ilint.h"
- #include "ilXint.h"
- #include <math.h>
- #include "ilpipelem.h"
- #include "ilerrors.h"
- /* Number of bits of Y and Cb/Cr used to dither before a table lookup to
- convert to a dithered pixel. The number of levels dithered to (nLY/CbCr) is
- 1<<DYCBCR_NBITS_Y/CBCR. The YCbCr->RGB lookup table is "nLY * nLCbCr * nLCbCr"
- longs in size.
- */
- #define DYCBCR_NBITS_Y 6
- #define DYCBCR_NBITS_CBCR 4
- /* Tables generated by /il/util/gendithertables.c */
- static unsigned int _il2x2DitherKernel[4] = {42, 234, 170, 106};
- /* Private data for YCbCr to dithered pixel filter */
- typedef struct {
- unsigned long pixels[1 << (DYCBCR_NBITS_Y + DYCBCR_NBITS_CBCR + DYCBCR_NBITS_CBCR)];
- } ilDitherYCbCrPrivRec, *ilDitherYCbCrPrivPtr;
- /* ---------------------- ilFastYCbCrDitherExecute ------------------------ */
- /* Execute() function: dither from subsampled-by-2 YCbCr to 8 bit pixels.
- */
- static ilError ilFastYCbCrDitherExecute (
- ilExecuteData *pData,
- long dstLine,
- long *pNLines
- )
- {
- ilDitherYCbCrPrivPtr pPriv;
- ilImagePlaneInfo *pPlane;
- long nLinesDiv2, halfWidth;
- long CbRowBytes, CrRowBytes;
- ilPtr pYLine, pCbLine, pCrLine, pDstLine;
- unsigned long *pTable;
- long YRowBytes, dstRowBytes, nPixelsDiv2, CbCr, temp0, temp1;
- ilPtr pY, pCb, pCr, pDst;
- /* This filter handles a pipe image of YCbCr subsampled by 2 in Cb/Cr only.
- The # of lines of Cb/Cr is therefore 1/2 the # of lines of Y.
- Note: can only handle images with even width/height; checked elsewhere.
- */
- pPlane = pData->pSrcImage->plane;
- YRowBytes = pPlane->nBytesPerRow;
- pYLine = pPlane->pPixels;
- pPlane++;
- CbRowBytes = pPlane->nBytesPerRow;
- pCbLine = pPlane->pPixels;
- pPlane++;
- CrRowBytes = pPlane->nBytesPerRow;
- pCrLine = pPlane->pPixels;
- if (pData->srcLine) {
- pYLine += pData->srcLine * YRowBytes;
- pCbLine += (pData->srcLine >> 1) * CbRowBytes;
- pCrLine += (pData->srcLine >> 1) * CrRowBytes;
- }
- pPlane = pData->pDstImage->plane;
- dstRowBytes = pPlane->nBytesPerRow;
- pDstLine = pPlane->pPixels + dstLine * dstRowBytes;
- pPriv = (ilDitherYCbCrPrivPtr)pData->pPrivate;
- halfWidth = pData->pSrcImage->width >> 1; /* 1/2 # of lines, pixels per line */
- nLinesDiv2 = *pNLines >> 1;
- pTable = pPriv->pixels;
- /* Do 4 pixels at a time, using 4 Ys for each
- Cb,Cr pair: get Cb,Cr into upper bits of "CbCr", then add in each Y
- and use result to index into table that yields 4 dithered pixels:
- <left><right><below><below right>.
- */
- while (nLinesDiv2-- > 0) {
- pY = pYLine;
- pYLine += YRowBytes << 1; /* skip 2 lines; read 2 lines each loop */
- pCb = pCbLine;
- pCbLine += CbRowBytes;
- pCr = pCrLine;
- pCrLine += CrRowBytes;
- pDst = pDstLine;
- pDstLine += dstRowBytes << 1; /* skip 2 lines; write 2 lines each loop */
- nPixelsDiv2 = halfWidth;
- while (nPixelsDiv2-- > 0) {
- temp0 = *pCb++;
- CbCr = *pCr++;
- temp0 >>= (8 - DYCBCR_NBITS_CBCR);
- CbCr >>= (8 - DYCBCR_NBITS_CBCR);
- CbCr += temp0 << DYCBCR_NBITS_CBCR;
- CbCr <<= DYCBCR_NBITS_Y; /* CbCr now in upper bits w/ room for Y */
- temp0 = pY[YRowBytes]; /* do pixel and pixel below */
- temp1 = *pY++;
- temp0 = CbCr + (temp0 >> (8-DYCBCR_NBITS_Y));
- pDst[dstRowBytes] = pTable[temp0] >> 8;
- temp1 = CbCr + (temp1 >> (8-DYCBCR_NBITS_Y));
- *pDst++ = pTable[temp1] >> 24;
- temp0 = pY[YRowBytes]; /* do pixel and pixel below */
- temp1 = *pY++;
- temp0 = CbCr + (temp0 >> (8-DYCBCR_NBITS_Y));
- pDst[dstRowBytes] = pTable[temp0];
- temp1 = CbCr + (temp1 >> (8-DYCBCR_NBITS_Y));
- *pDst++ = pTable[temp1] >> 16;
- }
- }
- return IL_OK;
- }
- /* -------------------- ilFastYCbCrDitherDoubleExecute ---------------------- */
- /* Execute() function: dither and double the given # of src lines.
- */
- static ilError ilFastYCbCrDitherDoubleExecute (
- ilExecuteData *pData,
- long dstLine,
- long *pNLines
- )
- {
- ilDitherYCbCrPrivPtr pPriv;
- ilImagePlaneInfo *pPlane;
- long nLinesDiv2, halfWidth;
- long CbRowBytes, CrRowBytes, dstRowBytes;
- ilPtr pYLine, pCbLine, pCrLine;
- unsigned long *pTable;
- long YRowBytes, nPixelsDiv2, CbCr, temp0, temp1;
- long dstRowShorts, dstRowShortsTimes2, dstRowShortsTimes3;
- ilPtr pY, pCb, pCr;
- unsigned short *pDst;
- unsigned short *pDstLine;
- /* This filter handles a pipe image of YCbCr subsampled by 2 in Cb/Cr only.
- The # of lines of Cb/Cr is therefore 1/2 the # of lines of Y.
- Note: can only handle images with even width/height; checked elsewhere.
- */
- pPlane = pData->pSrcImage->plane;
- YRowBytes = pPlane->nBytesPerRow;
- pYLine = pPlane->pPixels;
- pPlane++;
- CbRowBytes = pPlane->nBytesPerRow;
- pCbLine = pPlane->pPixels;
- pPlane++;
- CrRowBytes = pPlane->nBytesPerRow;
- pCrLine = pPlane->pPixels;
- if (pData->srcLine) {
- pYLine += pData->srcLine * YRowBytes;
- pCbLine += (pData->srcLine >> 1) * CbRowBytes;
- pCrLine += (pData->srcLine >> 1) * CrRowBytes;
- }
- /* Access dst buffer as shorts */
- pPlane = pData->pDstImage->plane;
- dstRowBytes = pPlane->nBytesPerRow;
- pDstLine = (unsigned short *)(pPlane->pPixels + dstLine * dstRowBytes);
- dstRowShorts = dstRowBytes >> 1;
- dstRowShortsTimes2 = dstRowShorts * 2;
- dstRowShortsTimes3 = dstRowShorts * 3;
- pPriv = (ilDitherYCbCrPrivPtr)pData->pPrivate;
- halfWidth = pData->pSrcImage->width >> 1; /* 1/2 # of lines, pixels per line */
- nLinesDiv2 = *pNLines >> 1;
- *pNLines <<= 1; /* write 2x # of src lines */
- pTable = pPriv->pixels;
- /* Do 4 src pixels at a time, using 4 Ys for each Cb,Cr pair: get Cb,Cr into
- upper bits of "CbCr", then add in each Y and use result to index into table
- that yields 4 dithered pixels: <left><right><below><below right>.
- To double, output those 4 pixels as shown above; 1 src pixel becomes 4 dst.
- */
- while (nLinesDiv2-- > 0) {
- pY = pYLine;
- pYLine += YRowBytes << 1; /* skip 2 lines; read 2 lines each loop */
- pCb = pCbLine;
- pCbLine += CbRowBytes;
- pCr = pCrLine;
- pCrLine += CrRowBytes;
- pDst = pDstLine;
- pDstLine += dstRowShorts << 2; /* skip 4 lines; write 4 lines each loop */
- nPixelsDiv2 = halfWidth;
- while (nPixelsDiv2-- > 0) {
- temp0 = *pCb++;
- CbCr = *pCr++;
- temp0 >>= (8 - DYCBCR_NBITS_CBCR);
- CbCr >>= (8 - DYCBCR_NBITS_CBCR);
- CbCr += temp0 << DYCBCR_NBITS_CBCR;
- CbCr <<= DYCBCR_NBITS_Y; /* CbCr now in upper bits w/ room for Y */
- temp0 = pY[YRowBytes]; /* do pixel and pixel below */
- temp1 = *pY++;
- temp0 = CbCr + (temp0 >> (8-DYCBCR_NBITS_Y));
- temp0 = pTable[temp0];
- pDst[dstRowShortsTimes3] = (unsigned short)temp0;
- pDst[dstRowShortsTimes2] = (unsigned short)(temp0 >> 16);
- temp1 = CbCr + (temp1 >> (8-DYCBCR_NBITS_Y));
- temp1 = pTable[temp1];
- pDst[dstRowShorts] = (unsigned short)temp1;
- *pDst++ = (unsigned short)(temp1 >> 16);
- temp0 = pY[YRowBytes]; /* do pixel and pixel below */
- temp1 = *pY++;
- temp0 = CbCr + (temp0 >> (8-DYCBCR_NBITS_Y));
- temp0 = pTable[temp0];
- pDst[dstRowShortsTimes3] = (unsigned short)temp0;
- pDst[dstRowShortsTimes2] = (unsigned short)(temp0 >> 16);
- temp1 = CbCr + (temp1 >> (8-DYCBCR_NBITS_Y));
- temp1 = pTable[temp1];
- pDst[dstRowShorts] = (unsigned short)temp1;
- *pDst++ = (unsigned short)(temp1 >> 16);
- }
- }
- return IL_OK;
- }
- /* ---------------------------- ilSetupYCbCrDitherTables ----------------------- */
- /* Setup *pTable as necessary for the YCbCr to RGB (dither) conversion.
- */
- static void ilSetupYCbCrDitherTables (
- ilYCbCrInfo *pYCbCr,
- int nBitsR,
- int nBitsG,
- int nBitsB,
- ilPtr pMapPixels,
- unsigned long *pTable
- )
- {
- int nTableEntries, nLevelsY, nLevelsCbCr;
- int Y, Cb, Cr, refY, refCb, refCr;
- int R, G, B, pixel, i, temp, kernel;
- double Lr, Lg, Lb;
- double ditherR, ditherG, ditherB, ditherY, ditherCbCr;
- #define CVT_TO_RGB { \
- int tY = Y - pYCbCr->sample[0].refBlack;\
- int tCb = Cb - pYCbCr->sample[1].refBlack;\
- int tCr = Cr - pYCbCr->sample[2].refBlack;\
- R = tCr * (2 - 2 * Lr) + tY;\
- B = tCb * (2 - 2 * Lb) + tY;\
- G = (tY - Lb * B - Lr * R) / Lg;\
- if (R < 0) R = 0; else if (R > 255) R = 255;\
- if (G < 0) G = 0; else if (G > 255) G = 255;\
- if (B < 0) B = 0; else if (B > 255) B = 255;\
- }
- #define YCBCR_DEBUG_TABLE 1
- #ifdef YCBCR_DEBUG_TABLE
- /* Set pMapPixels to identity, for debugging */
- ilByte debugMapPixels[256];
- int tmp;
- int doDebug = FALSE;
- if (doDebug) {
- for (tmp = 0; tmp < 256; tmp++)
- debugMapPixels[tmp] = tmp;
- pMapPixels = debugMapPixels;
- }
- #endif
- /* Build the YCbCr to dither-RGB lookup table. The table is indexed by
- a YCbCr value <Cb><Cr><Y>, where <Y> is "DYCBCR_NBITS_Y" bits
- in size and <Cb><Cr> are each "DYCBCR_NBITS_CBCR" in size. Indexed that way
- the table yields either four dithered pixels or a long 24 X pixel.
- Each table entry is calculated by converting the YCbCr value to
- its RGB equivalent and either dithering to form 4 pixels or a single
- long X pixel.
- */
- nLevelsY = 1 << DYCBCR_NBITS_Y;
- nLevelsCbCr = 1 << DYCBCR_NBITS_CBCR;
- Lr = ((double)pYCbCr->lumaRed / (double)10000);
- Lg = ((double)pYCbCr->lumaGreen / (double)10000);
- Lb = ((double)pYCbCr->lumaBlue / (double)10000);
- ditherR = ((1 << nBitsR) - 1) * (double)256 / (double)255;
- ditherG = ((1 << nBitsG) - 1) * (double)256 / (double)255;
- ditherB = ((1 << nBitsB) - 1) * (double)256 / (double)255;
- for (refCb = 0; refCb < nLevelsCbCr; refCb++) {
- Cb = (255 * refCb) / (nLevelsCbCr - 1);
- for (refCr = 0; refCr < nLevelsCbCr; refCr++) {
- Cr = (255 * refCr) / (nLevelsCbCr - 1);
- for (refY = 0; refY < nLevelsY; refY++) {
- Y = (255 * refY) / (nLevelsY - 1);
- /* Store 4 dithered pixels, the result of dithering RGB with
- a 2x2 kernel. See /ilc/ildither.c for equivalent code.
- */
- #define DITHER
- #ifdef COLORSLAM
- CVT_TO_RGB
- pixel = R >> (8 - nBitsR);
- pixel <<= nBitsG;
- pixel |= G >> (8 - nBitsG);
- pixel <<= nBitsB;
- pixel |= B >> (8 - nBitsB);
- pixel = pMapPixels[pixel];
- *pTable++ = (pixel << 24) | (pixel << 16) | (pixel << 8) | pixel;
- #else
- #ifdef DIFFUSION
- {
- int temp1, temp2;
- int halfR = (1 << (7 - nBitsR)) - 1;
- int halfG = (1 << (7 - nBitsG)) - 1;
- int halfB = (1 << (7 - nBitsB)) - 1;
- int maskR = ~((1 << (8 - nBitsR)) - 1);
- int maskG = ~((1 << (8 - nBitsG)) - 1);
- int maskB = ~((1 << (8 - nBitsB)) - 1);
- CVT_TO_RGB
- for (i = 0, pixel = 0; i < 4; i++) {
- temp1 = R + halfR;
- if (temp1 > 255) temp1 = 255; else if (temp1 < 0) temp1 = 0;
- R += R - (temp1 & maskR);
- temp = temp1 >> (8 - nBitsR);
- temp1 = G + halfG;
- if (temp1 > 255) temp1 = 255; else if (temp1 < 0) temp1 = 0;
- G += G - (temp1 & maskG);
- temp <<= nBitsG;
- temp |= temp1 >> (8 - nBitsG);
- temp1 = B + halfB;
- if (temp1 > 255) temp1 = 255; else if (temp1 < 0) temp1 = 0;
- B += B - (temp1 & maskB);
- temp <<= nBitsB;
- temp |= temp1 >> (8 - nBitsB);
- pixel <<= 8;
- pixel |= pMapPixels[temp];
- }
- *pTable++ = pixel;
- }
- #else
- #ifdef DITHER
- CVT_TO_RGB
- R = (double)R * ditherR;
- G = (double)G * ditherG;
- B = (double)B * ditherB;
- for (i = 0, pixel = 0; i < 4; i++) {
- kernel = _il2x2DitherKernel[i];
- temp = (R + kernel) >> 8;
- temp <<= nBitsG;
- temp |= (G + kernel) >> 8;
- temp <<= nBitsB;
- temp |= (B + kernel) >> 8;
- pixel <<= 8;
- pixel |= pMapPixels[temp];
- }
- *pTable++ = pixel;
- #endif
- #endif
- #endif
- }
- }
- }
- }
- /* ------------------------ _ilFastYCbCrDither ---------------------------- */
- /* Called by ilConvertForXWrite() to do fast dithered display of YCbCr.
- The pipe image must be planar, subsampled by 2 in Cb/Cr, 1 in Y.
- "pMapPixels" points to 256 bytes from the XWC map image, which are folded
- into the lookup table used for this function.
- */
- IL_PRIVATE ilBool _ilFastYCbCrDither (
- ilPipe pipe,
- ilImageDes *pDes,
- ilPipeInfo *pInfo,
- int nBitsRed,
- int nBitsGreen,
- int nBitsBlue,
- ilBool doDouble,
- ilPtr pMapPixels
- )
- {
- ilImageDes des;
- ilDitherYCbCrPrivPtr pPriv;
- ilDstElementData dstData;
- ilSrcElementData srcData;
- /* Add a filter to convert subsampled YCbCr to a dithered palette image.
- Force a single strip; image is at least 2 by 2
- */
- srcData.consumerImage = (ilObject)NULL;
- srcData.stripHeight = pInfo->height;
- srcData.constantStrip = TRUE;
- srcData.minBufferHeight = 0;
- dstData.producerObject = (ilObject)NULL;
- dstData.pDes = IL_DES_GRAY; /* arbitrary; not really used */
- dstData.pFormat = IL_FORMAT_BYTE;
- dstData.width = pInfo->width;
- dstData.height = pInfo->height;
- dstData.stripHeight = srcData.stripHeight;
- if (doDouble) {
- dstData.width *= 2;
- dstData.height *= 2;
- dstData.stripHeight *= 2;
- }
- dstData.constantStrip = pInfo->constantStrip;
- dstData.pPalette = (unsigned short *)NULL;
- pPriv = (ilDitherYCbCrPrivPtr)ilAddPipeElement (pipe, IL_FILTER,
- sizeof(ilDitherYCbCrPrivRec), 0, &srcData, &dstData, IL_NPF, IL_NPF, IL_NPF,
- (doDouble) ? ilFastYCbCrDitherDoubleExecute : ilFastYCbCrDitherExecute, 0);
- if (!pPriv)
- return FALSE;
- /* Init the table in private */
- ilSetupYCbCrDitherTables (&pDes->typeInfo.YCbCr, nBitsRed, nBitsGreen, nBitsBlue,
- pMapPixels, pPriv->pixels);
- return TRUE;
- }
|