2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: ilXycbcr.c /main/3 1995/10/23 15:41:23 rswiston $ */
24 /**---------------------------------------------------------------------
26 *** (c)Copyright 1991 Hewlett-Packard Co.
28 *** RESTRICTED RIGHTS LEGEND
29 *** Use, duplication, or disclosure by the U.S. Government is subject to
30 *** restrictions as set forth in sub-paragraph (c)(1)(ii) of the Rights in
31 *** Technical Data and Computer Software clause in DFARS 252.227-7013.
32 *** Hewlett-Packard Company
33 *** 3000 Hanover Street
34 *** Palo Alto, CA 94304 U.S.A.
35 *** Rights for non-DOD U.S. Government Departments and Agencies are as set
36 *** forth in FAR 52.227-19(c)(1,2).
38 ***-------------------------------------------------------------------*/
43 #include "ilpipelem.h"
46 /* Number of bits of Y and Cb/Cr used to dither before a table lookup to
47 convert to a dithered pixel. The number of levels dithered to (nLY/CbCr) is
48 1<<DYCBCR_NBITS_Y/CBCR. The YCbCr->RGB lookup table is "nLY * nLCbCr * nLCbCr"
51 #define DYCBCR_NBITS_Y 6
52 #define DYCBCR_NBITS_CBCR 4
54 /* Tables generated by /il/util/gendithertables.c */
55 static unsigned int _il2x2DitherKernel[4] = {42, 234, 170, 106};
57 /* Private data for YCbCr to dithered pixel filter */
59 unsigned long pixels[1 << (DYCBCR_NBITS_Y + DYCBCR_NBITS_CBCR + DYCBCR_NBITS_CBCR)];
60 } ilDitherYCbCrPrivRec, *ilDitherYCbCrPrivPtr;
63 /* ---------------------- ilFastYCbCrDitherExecute ------------------------ */
64 /* Execute() function: dither from subsampled-by-2 YCbCr to 8 bit pixels.
66 static ilError ilFastYCbCrDitherExecute (
72 ilDitherYCbCrPrivPtr pPriv;
73 ilImagePlaneInfo *pPlane;
74 long nLinesDiv2, halfWidth;
75 long CbRowBytes, CrRowBytes;
76 ilPtr pYLine, pCbLine, pCrLine, pDstLine;
77 unsigned long *pTable;
78 long YRowBytes, dstRowBytes, nPixelsDiv2, CbCr, temp0, temp1;
79 ilPtr pY, pCb, pCr, pDst;
81 /* This filter handles a pipe image of YCbCr subsampled by 2 in Cb/Cr only.
82 The # of lines of Cb/Cr is therefore 1/2 the # of lines of Y.
83 Note: can only handle images with even width/height; checked elsewhere.
85 pPlane = pData->pSrcImage->plane;
86 YRowBytes = pPlane->nBytesPerRow;
87 pYLine = pPlane->pPixels;
89 CbRowBytes = pPlane->nBytesPerRow;
90 pCbLine = pPlane->pPixels;
92 CrRowBytes = pPlane->nBytesPerRow;
93 pCrLine = pPlane->pPixels;
95 pYLine += pData->srcLine * YRowBytes;
96 pCbLine += (pData->srcLine >> 1) * CbRowBytes;
97 pCrLine += (pData->srcLine >> 1) * CrRowBytes;
99 pPlane = pData->pDstImage->plane;
100 dstRowBytes = pPlane->nBytesPerRow;
101 pDstLine = pPlane->pPixels + dstLine * dstRowBytes;
103 pPriv = (ilDitherYCbCrPrivPtr)pData->pPrivate;
104 halfWidth = pData->pSrcImage->width >> 1; /* 1/2 # of lines, pixels per line */
105 nLinesDiv2 = *pNLines >> 1;
106 pTable = pPriv->pixels;
108 /* Do 4 pixels at a time, using 4 Ys for each
109 Cb,Cr pair: get Cb,Cr into upper bits of "CbCr", then add in each Y
110 and use result to index into table that yields 4 dithered pixels:
111 <left><right><below><below right>.
113 while (nLinesDiv2-- > 0) {
115 pYLine += YRowBytes << 1; /* skip 2 lines; read 2 lines each loop */
117 pCbLine += CbRowBytes;
119 pCrLine += CrRowBytes;
121 pDstLine += dstRowBytes << 1; /* skip 2 lines; write 2 lines each loop */
122 nPixelsDiv2 = halfWidth;
123 while (nPixelsDiv2-- > 0) {
126 temp0 >>= (8 - DYCBCR_NBITS_CBCR);
127 CbCr >>= (8 - DYCBCR_NBITS_CBCR);
128 CbCr += temp0 << DYCBCR_NBITS_CBCR;
129 CbCr <<= DYCBCR_NBITS_Y; /* CbCr now in upper bits w/ room for Y */
131 temp0 = pY[YRowBytes]; /* do pixel and pixel below */
133 temp0 = CbCr + (temp0 >> (8-DYCBCR_NBITS_Y));
134 pDst[dstRowBytes] = pTable[temp0] >> 8;
135 temp1 = CbCr + (temp1 >> (8-DYCBCR_NBITS_Y));
136 *pDst++ = pTable[temp1] >> 24;
138 temp0 = pY[YRowBytes]; /* do pixel and pixel below */
140 temp0 = CbCr + (temp0 >> (8-DYCBCR_NBITS_Y));
141 pDst[dstRowBytes] = pTable[temp0];
142 temp1 = CbCr + (temp1 >> (8-DYCBCR_NBITS_Y));
143 *pDst++ = pTable[temp1] >> 16;
150 /* -------------------- ilFastYCbCrDitherDoubleExecute ---------------------- */
151 /* Execute() function: dither and double the given # of src lines.
153 static ilError ilFastYCbCrDitherDoubleExecute (
154 ilExecuteData *pData,
159 ilDitherYCbCrPrivPtr pPriv;
160 ilImagePlaneInfo *pPlane;
161 long nLinesDiv2, halfWidth;
162 long CbRowBytes, CrRowBytes, dstRowBytes;
163 ilPtr pYLine, pCbLine, pCrLine;
164 unsigned long *pTable;
165 long YRowBytes, nPixelsDiv2, CbCr, temp0, temp1;
166 long dstRowShorts, dstRowShortsTimes2, dstRowShortsTimes3;
168 unsigned short *pDst;
169 unsigned short *pDstLine;
171 /* This filter handles a pipe image of YCbCr subsampled by 2 in Cb/Cr only.
172 The # of lines of Cb/Cr is therefore 1/2 the # of lines of Y.
173 Note: can only handle images with even width/height; checked elsewhere.
175 pPlane = pData->pSrcImage->plane;
176 YRowBytes = pPlane->nBytesPerRow;
177 pYLine = pPlane->pPixels;
179 CbRowBytes = pPlane->nBytesPerRow;
180 pCbLine = pPlane->pPixels;
182 CrRowBytes = pPlane->nBytesPerRow;
183 pCrLine = pPlane->pPixels;
184 if (pData->srcLine) {
185 pYLine += pData->srcLine * YRowBytes;
186 pCbLine += (pData->srcLine >> 1) * CbRowBytes;
187 pCrLine += (pData->srcLine >> 1) * CrRowBytes;
190 /* Access dst buffer as shorts */
191 pPlane = pData->pDstImage->plane;
192 dstRowBytes = pPlane->nBytesPerRow;
193 pDstLine = (unsigned short *)(pPlane->pPixels + dstLine * dstRowBytes);
194 dstRowShorts = dstRowBytes >> 1;
195 dstRowShortsTimes2 = dstRowShorts * 2;
196 dstRowShortsTimes3 = dstRowShorts * 3;
198 pPriv = (ilDitherYCbCrPrivPtr)pData->pPrivate;
199 halfWidth = pData->pSrcImage->width >> 1; /* 1/2 # of lines, pixels per line */
200 nLinesDiv2 = *pNLines >> 1;
201 *pNLines <<= 1; /* write 2x # of src lines */
202 pTable = pPriv->pixels;
204 /* Do 4 src pixels at a time, using 4 Ys for each Cb,Cr pair: get Cb,Cr into
205 upper bits of "CbCr", then add in each Y and use result to index into table
206 that yields 4 dithered pixels: <left><right><below><below right>.
207 To double, output those 4 pixels as shown above; 1 src pixel becomes 4 dst.
209 while (nLinesDiv2-- > 0) {
211 pYLine += YRowBytes << 1; /* skip 2 lines; read 2 lines each loop */
213 pCbLine += CbRowBytes;
215 pCrLine += CrRowBytes;
217 pDstLine += dstRowShorts << 2; /* skip 4 lines; write 4 lines each loop */
218 nPixelsDiv2 = halfWidth;
219 while (nPixelsDiv2-- > 0) {
222 temp0 >>= (8 - DYCBCR_NBITS_CBCR);
223 CbCr >>= (8 - DYCBCR_NBITS_CBCR);
224 CbCr += temp0 << DYCBCR_NBITS_CBCR;
225 CbCr <<= DYCBCR_NBITS_Y; /* CbCr now in upper bits w/ room for Y */
227 temp0 = pY[YRowBytes]; /* do pixel and pixel below */
229 temp0 = CbCr + (temp0 >> (8-DYCBCR_NBITS_Y));
230 temp0 = pTable[temp0];
231 pDst[dstRowShortsTimes3] = (unsigned short)temp0;
232 pDst[dstRowShortsTimes2] = (unsigned short)(temp0 >> 16);
233 temp1 = CbCr + (temp1 >> (8-DYCBCR_NBITS_Y));
234 temp1 = pTable[temp1];
235 pDst[dstRowShorts] = (unsigned short)temp1;
236 *pDst++ = (unsigned short)(temp1 >> 16);
238 temp0 = pY[YRowBytes]; /* do pixel and pixel below */
240 temp0 = CbCr + (temp0 >> (8-DYCBCR_NBITS_Y));
241 temp0 = pTable[temp0];
242 pDst[dstRowShortsTimes3] = (unsigned short)temp0;
243 pDst[dstRowShortsTimes2] = (unsigned short)(temp0 >> 16);
244 temp1 = CbCr + (temp1 >> (8-DYCBCR_NBITS_Y));
245 temp1 = pTable[temp1];
246 pDst[dstRowShorts] = (unsigned short)temp1;
247 *pDst++ = (unsigned short)(temp1 >> 16);
256 /* ---------------------------- ilSetupYCbCrDitherTables ----------------------- */
257 /* Setup *pTable as necessary for the YCbCr to RGB (dither) conversion.
259 static void ilSetupYCbCrDitherTables (
265 unsigned long *pTable
268 int nTableEntries, nLevelsY, nLevelsCbCr;
269 int Y, Cb, Cr, refY, refCb, refCr;
270 int R, G, B, pixel, i, temp, kernel;
272 double ditherR, ditherG, ditherB, ditherY, ditherCbCr;
274 #define CVT_TO_RGB { \
275 int tY = Y - pYCbCr->sample[0].refBlack;\
276 int tCb = Cb - pYCbCr->sample[1].refBlack;\
277 int tCr = Cr - pYCbCr->sample[2].refBlack;\
278 R = tCr * (2 - 2 * Lr) + tY;\
279 B = tCb * (2 - 2 * Lb) + tY;\
280 G = (tY - Lb * B - Lr * R) / Lg;\
281 if (R < 0) R = 0; else if (R > 255) R = 255;\
282 if (G < 0) G = 0; else if (G > 255) G = 255;\
283 if (B < 0) B = 0; else if (B > 255) B = 255;\
286 #define YCBCR_DEBUG_TABLE 1
287 #ifdef YCBCR_DEBUG_TABLE
288 /* Set pMapPixels to identity, for debugging */
289 ilByte debugMapPixels[256];
294 for (tmp = 0; tmp < 256; tmp++)
295 debugMapPixels[tmp] = tmp;
296 pMapPixels = debugMapPixels;
300 /* Build the YCbCr to dither-RGB lookup table. The table is indexed by
301 a YCbCr value <Cb><Cr><Y>, where <Y> is "DYCBCR_NBITS_Y" bits
302 in size and <Cb><Cr> are each "DYCBCR_NBITS_CBCR" in size. Indexed that way
303 the table yields either four dithered pixels or a long 24 X pixel.
304 Each table entry is calculated by converting the YCbCr value to
305 its RGB equivalent and either dithering to form 4 pixels or a single
308 nLevelsY = 1 << DYCBCR_NBITS_Y;
309 nLevelsCbCr = 1 << DYCBCR_NBITS_CBCR;
311 Lr = ((double)pYCbCr->lumaRed / (double)10000);
312 Lg = ((double)pYCbCr->lumaGreen / (double)10000);
313 Lb = ((double)pYCbCr->lumaBlue / (double)10000);
315 ditherR = ((1 << nBitsR) - 1) * (double)256 / (double)255;
316 ditherG = ((1 << nBitsG) - 1) * (double)256 / (double)255;
317 ditherB = ((1 << nBitsB) - 1) * (double)256 / (double)255;
319 for (refCb = 0; refCb < nLevelsCbCr; refCb++) {
320 Cb = (255 * refCb) / (nLevelsCbCr - 1);
322 for (refCr = 0; refCr < nLevelsCbCr; refCr++) {
323 Cr = (255 * refCr) / (nLevelsCbCr - 1);
325 for (refY = 0; refY < nLevelsY; refY++) {
326 Y = (255 * refY) / (nLevelsY - 1);
328 /* Store 4 dithered pixels, the result of dithering RGB with
329 a 2x2 kernel. See /ilc/ildither.c for equivalent code.
334 pixel = R >> (8 - nBitsR);
336 pixel |= G >> (8 - nBitsG);
338 pixel |= B >> (8 - nBitsB);
339 pixel = pMapPixels[pixel];
340 *pTable++ = (pixel << 24) | (pixel << 16) | (pixel << 8) | pixel;
345 int halfR = (1 << (7 - nBitsR)) - 1;
346 int halfG = (1 << (7 - nBitsG)) - 1;
347 int halfB = (1 << (7 - nBitsB)) - 1;
348 int maskR = ~((1 << (8 - nBitsR)) - 1);
349 int maskG = ~((1 << (8 - nBitsG)) - 1);
350 int maskB = ~((1 << (8 - nBitsB)) - 1);
352 for (i = 0, pixel = 0; i < 4; i++) {
354 if (temp1 > 255) temp1 = 255; else if (temp1 < 0) temp1 = 0;
355 R += R - (temp1 & maskR);
356 temp = temp1 >> (8 - nBitsR);
359 if (temp1 > 255) temp1 = 255; else if (temp1 < 0) temp1 = 0;
360 G += G - (temp1 & maskG);
362 temp |= temp1 >> (8 - nBitsG);
365 if (temp1 > 255) temp1 = 255; else if (temp1 < 0) temp1 = 0;
366 B += B - (temp1 & maskB);
368 temp |= temp1 >> (8 - nBitsB);
371 pixel |= pMapPixels[temp];
378 R = (double)R * ditherR;
379 G = (double)G * ditherG;
380 B = (double)B * ditherB;
382 for (i = 0, pixel = 0; i < 4; i++) {
383 kernel = _il2x2DitherKernel[i];
384 temp = (R + kernel) >> 8;
386 temp |= (G + kernel) >> 8;
388 temp |= (B + kernel) >> 8;
390 pixel |= pMapPixels[temp];
401 /* ------------------------ _ilFastYCbCrDither ---------------------------- */
402 /* Called by ilConvertForXWrite() to do fast dithered display of YCbCr.
403 The pipe image must be planar, subsampled by 2 in Cb/Cr, 1 in Y.
404 "pMapPixels" points to 256 bytes from the XWC map image, which are folded
405 into the lookup table used for this function.
407 IL_PRIVATE ilBool _ilFastYCbCrDither (
419 ilDitherYCbCrPrivPtr pPriv;
420 ilDstElementData dstData;
421 ilSrcElementData srcData;
423 /* Add a filter to convert subsampled YCbCr to a dithered palette image.
424 Force a single strip; image is at least 2 by 2
426 srcData.consumerImage = (ilObject)NULL;
427 srcData.stripHeight = pInfo->height;
428 srcData.constantStrip = TRUE;
429 srcData.minBufferHeight = 0;
431 dstData.producerObject = (ilObject)NULL;
432 dstData.pDes = IL_DES_GRAY; /* arbitrary; not really used */
433 dstData.pFormat = IL_FORMAT_BYTE;
434 dstData.width = pInfo->width;
435 dstData.height = pInfo->height;
436 dstData.stripHeight = srcData.stripHeight;
440 dstData.stripHeight *= 2;
442 dstData.constantStrip = pInfo->constantStrip;
443 dstData.pPalette = (unsigned short *)NULL;
445 pPriv = (ilDitherYCbCrPrivPtr)ilAddPipeElement (pipe, IL_FILTER,
446 sizeof(ilDitherYCbCrPrivRec), 0, &srcData, &dstData, IL_NPF, IL_NPF, IL_NPF,
447 (doDouble) ? ilFastYCbCrDitherDoubleExecute : ilFastYCbCrDitherExecute, 0);
451 /* Init the table in private */
452 ilSetupYCbCrDitherTables (&pDes->typeInfo.YCbCr, nBitsRed, nBitsGreen, nBitsBlue,
453 pMapPixels, pPriv->pixels);