1 /* $XConsortium: ilXycbcr.c /main/3 1995/10/23 15:41:23 rswiston $ */
2 /**---------------------------------------------------------------------
4 *** (c)Copyright 1991 Hewlett-Packard Co.
6 *** RESTRICTED RIGHTS LEGEND
7 *** Use, duplication, or disclosure by the U.S. Government is subject to
8 *** restrictions as set forth in sub-paragraph (c)(1)(ii) of the Rights in
9 *** Technical Data and Computer Software clause in DFARS 252.227-7013.
10 *** Hewlett-Packard Company
11 *** 3000 Hanover Street
12 *** Palo Alto, CA 94304 U.S.A.
13 *** Rights for non-DOD U.S. Government Departments and Agencies are as set
14 *** forth in FAR 52.227-19(c)(1,2).
16 ***-------------------------------------------------------------------*/
21 #include "ilpipelem.h"
24 /* Number of bits of Y and Cb/Cr used to dither before a table lookup to
25 convert to a dithered pixel. The number of levels dithered to (nLY/CbCr) is
26 1<<DYCBCR_NBITS_Y/CBCR. The YCbCr->RGB lookup table is "nLY * nLCbCr * nLCbCr"
29 #define DYCBCR_NBITS_Y 6
30 #define DYCBCR_NBITS_CBCR 4
32 /* Tables generated by /il/util/gendithertables.c */
33 static unsigned int _il2x2DitherKernel[4] = {42, 234, 170, 106};
35 /* Private data for YCbCr to dithered pixel filter */
37 unsigned long pixels[1 << (DYCBCR_NBITS_Y + DYCBCR_NBITS_CBCR + DYCBCR_NBITS_CBCR)];
38 } ilDitherYCbCrPrivRec, *ilDitherYCbCrPrivPtr;
41 /* ---------------------- ilFastYCbCrDitherExecute ------------------------ */
42 /* Execute() function: dither from subsampled-by-2 YCbCr to 8 bit pixels.
44 static ilError ilFastYCbCrDitherExecute (
50 ilDitherYCbCrPrivPtr pPriv;
51 ilImagePlaneInfo *pPlane;
52 long nLinesDiv2, halfWidth;
53 long CbRowBytes, CrRowBytes;
54 ilPtr pYLine, pCbLine, pCrLine, pDstLine;
55 register unsigned long *pTable;
56 register long YRowBytes, dstRowBytes, nPixelsDiv2, CbCr, temp0, temp1;
57 register ilPtr pY, pCb, pCr, pDst;
59 /* This filter handles a pipe image of YCbCr subsampled by 2 in Cb/Cr only.
60 The # of lines of Cb/Cr is therefore 1/2 the # of lines of Y.
61 Note: can only handle images with even width/height; checked elsewhere.
63 pPlane = pData->pSrcImage->plane;
64 YRowBytes = pPlane->nBytesPerRow;
65 pYLine = pPlane->pPixels;
67 CbRowBytes = pPlane->nBytesPerRow;
68 pCbLine = pPlane->pPixels;
70 CrRowBytes = pPlane->nBytesPerRow;
71 pCrLine = pPlane->pPixels;
73 pYLine += pData->srcLine * YRowBytes;
74 pCbLine += (pData->srcLine >> 1) * CbRowBytes;
75 pCrLine += (pData->srcLine >> 1) * CrRowBytes;
77 pPlane = pData->pDstImage->plane;
78 dstRowBytes = pPlane->nBytesPerRow;
79 pDstLine = pPlane->pPixels + dstLine * dstRowBytes;
81 pPriv = (ilDitherYCbCrPrivPtr)pData->pPrivate;
82 halfWidth = pData->pSrcImage->width >> 1; /* 1/2 # of lines, pixels per line */
83 nLinesDiv2 = *pNLines >> 1;
84 pTable = pPriv->pixels;
86 /* Do 4 pixels at a time, using 4 Ys for each
87 Cb,Cr pair: get Cb,Cr into upper bits of "CbCr", then add in each Y
88 and use result to index into table that yields 4 dithered pixels:
89 <left><right><below><below right>.
91 while (nLinesDiv2-- > 0) {
93 pYLine += YRowBytes << 1; /* skip 2 lines; read 2 lines each loop */
95 pCbLine += CbRowBytes;
97 pCrLine += CrRowBytes;
99 pDstLine += dstRowBytes << 1; /* skip 2 lines; write 2 lines each loop */
100 nPixelsDiv2 = halfWidth;
101 while (nPixelsDiv2-- > 0) {
104 temp0 >>= (8 - DYCBCR_NBITS_CBCR);
105 CbCr >>= (8 - DYCBCR_NBITS_CBCR);
106 CbCr += temp0 << DYCBCR_NBITS_CBCR;
107 CbCr <<= DYCBCR_NBITS_Y; /* CbCr now in upper bits w/ room for Y */
109 temp0 = pY[YRowBytes]; /* do pixel and pixel below */
111 temp0 = CbCr + (temp0 >> (8-DYCBCR_NBITS_Y));
112 pDst[dstRowBytes] = pTable[temp0] >> 8;
113 temp1 = CbCr + (temp1 >> (8-DYCBCR_NBITS_Y));
114 *pDst++ = pTable[temp1] >> 24;
116 temp0 = pY[YRowBytes]; /* do pixel and pixel below */
118 temp0 = CbCr + (temp0 >> (8-DYCBCR_NBITS_Y));
119 pDst[dstRowBytes] = pTable[temp0];
120 temp1 = CbCr + (temp1 >> (8-DYCBCR_NBITS_Y));
121 *pDst++ = pTable[temp1] >> 16;
128 /* -------------------- ilFastYCbCrDitherDoubleExecute ---------------------- */
129 /* Execute() function: dither and double the given # of src lines.
131 static ilError ilFastYCbCrDitherDoubleExecute (
132 ilExecuteData *pData,
137 ilDitherYCbCrPrivPtr pPriv;
138 ilImagePlaneInfo *pPlane;
139 long nLinesDiv2, halfWidth;
140 long CbRowBytes, CrRowBytes, dstRowBytes;
141 ilPtr pYLine, pCbLine, pCrLine;
142 register unsigned long *pTable;
143 register long YRowBytes, nPixelsDiv2, CbCr, temp0, temp1;
144 register long dstRowShorts, dstRowShortsTimes2, dstRowShortsTimes3;
145 register ilPtr pY, pCb, pCr;
146 register unsigned short *pDst;
147 unsigned short *pDstLine;
149 /* This filter handles a pipe image of YCbCr subsampled by 2 in Cb/Cr only.
150 The # of lines of Cb/Cr is therefore 1/2 the # of lines of Y.
151 Note: can only handle images with even width/height; checked elsewhere.
153 pPlane = pData->pSrcImage->plane;
154 YRowBytes = pPlane->nBytesPerRow;
155 pYLine = pPlane->pPixels;
157 CbRowBytes = pPlane->nBytesPerRow;
158 pCbLine = pPlane->pPixels;
160 CrRowBytes = pPlane->nBytesPerRow;
161 pCrLine = pPlane->pPixels;
162 if (pData->srcLine) {
163 pYLine += pData->srcLine * YRowBytes;
164 pCbLine += (pData->srcLine >> 1) * CbRowBytes;
165 pCrLine += (pData->srcLine >> 1) * CrRowBytes;
168 /* Access dst buffer as shorts */
169 pPlane = pData->pDstImage->plane;
170 dstRowBytes = pPlane->nBytesPerRow;
171 pDstLine = (unsigned short *)(pPlane->pPixels + dstLine * dstRowBytes);
172 dstRowShorts = dstRowBytes >> 1;
173 dstRowShortsTimes2 = dstRowShorts * 2;
174 dstRowShortsTimes3 = dstRowShorts * 3;
176 pPriv = (ilDitherYCbCrPrivPtr)pData->pPrivate;
177 halfWidth = pData->pSrcImage->width >> 1; /* 1/2 # of lines, pixels per line */
178 nLinesDiv2 = *pNLines >> 1;
179 *pNLines <<= 1; /* write 2x # of src lines */
180 pTable = pPriv->pixels;
182 /* Do 4 src pixels at a time, using 4 Ys for each Cb,Cr pair: get Cb,Cr into
183 upper bits of "CbCr", then add in each Y and use result to index into table
184 that yields 4 dithered pixels: <left><right><below><below right>.
185 To double, output those 4 pixels as shown above; 1 src pixel becomes 4 dst.
187 while (nLinesDiv2-- > 0) {
189 pYLine += YRowBytes << 1; /* skip 2 lines; read 2 lines each loop */
191 pCbLine += CbRowBytes;
193 pCrLine += CrRowBytes;
195 pDstLine += dstRowShorts << 2; /* skip 4 lines; write 4 lines each loop */
196 nPixelsDiv2 = halfWidth;
197 while (nPixelsDiv2-- > 0) {
200 temp0 >>= (8 - DYCBCR_NBITS_CBCR);
201 CbCr >>= (8 - DYCBCR_NBITS_CBCR);
202 CbCr += temp0 << DYCBCR_NBITS_CBCR;
203 CbCr <<= DYCBCR_NBITS_Y; /* CbCr now in upper bits w/ room for Y */
205 temp0 = pY[YRowBytes]; /* do pixel and pixel below */
207 temp0 = CbCr + (temp0 >> (8-DYCBCR_NBITS_Y));
208 temp0 = pTable[temp0];
209 pDst[dstRowShortsTimes3] = (unsigned short)temp0;
210 pDst[dstRowShortsTimes2] = (unsigned short)(temp0 >> 16);
211 temp1 = CbCr + (temp1 >> (8-DYCBCR_NBITS_Y));
212 temp1 = pTable[temp1];
213 pDst[dstRowShorts] = (unsigned short)temp1;
214 *pDst++ = (unsigned short)(temp1 >> 16);
216 temp0 = pY[YRowBytes]; /* do pixel and pixel below */
218 temp0 = CbCr + (temp0 >> (8-DYCBCR_NBITS_Y));
219 temp0 = pTable[temp0];
220 pDst[dstRowShortsTimes3] = (unsigned short)temp0;
221 pDst[dstRowShortsTimes2] = (unsigned short)(temp0 >> 16);
222 temp1 = CbCr + (temp1 >> (8-DYCBCR_NBITS_Y));
223 temp1 = pTable[temp1];
224 pDst[dstRowShorts] = (unsigned short)temp1;
225 *pDst++ = (unsigned short)(temp1 >> 16);
234 /* ---------------------------- ilSetupYCbCrDitherTables ----------------------- */
235 /* Setup *pTable as necessary for the YCbCr to RGB (dither) conversion.
237 static void ilSetupYCbCrDitherTables (
238 register ilYCbCrInfo *pYCbCr,
243 unsigned long *pTable
246 int nTableEntries, nLevelsY, nLevelsCbCr;
247 int Y, Cb, Cr, refY, refCb, refCr;
248 register int R, G, B, pixel, i, temp, kernel;
250 double ditherR, ditherG, ditherB, ditherY, ditherCbCr;
252 #define CVT_TO_RGB { \
253 int tY = Y - pYCbCr->sample[0].refBlack;\
254 int tCb = Cb - pYCbCr->sample[1].refBlack;\
255 int tCr = Cr - pYCbCr->sample[2].refBlack;\
256 R = tCr * (2 - 2 * Lr) + tY;\
257 B = tCb * (2 - 2 * Lb) + tY;\
258 G = (tY - Lb * B - Lr * R) / Lg;\
259 if (R < 0) R = 0; else if (R > 255) R = 255;\
260 if (G < 0) G = 0; else if (G > 255) G = 255;\
261 if (B < 0) B = 0; else if (B > 255) B = 255;\
264 #define YCBCR_DEBUG_TABLE 1
265 #ifdef YCBCR_DEBUG_TABLE
266 /* Set pMapPixels to identity, for debugging */
267 ilByte debugMapPixels[256];
272 for (tmp = 0; tmp < 256; tmp++)
273 debugMapPixels[tmp] = tmp;
274 pMapPixels = debugMapPixels;
278 /* Build the YCbCr to dither-RGB lookup table. The table is indexed by
279 a YCbCr value <Cb><Cr><Y>, where <Y> is "DYCBCR_NBITS_Y" bits
280 in size and <Cb><Cr> are each "DYCBCR_NBITS_CBCR" in size. Indexed that way
281 the table yields either four dithered pixels or a long 24 X pixel.
282 Each table entry is calculated by converting the YCbCr value to
283 its RGB equivalent and either dithering to form 4 pixels or a single
286 nLevelsY = 1 << DYCBCR_NBITS_Y;
287 nLevelsCbCr = 1 << DYCBCR_NBITS_CBCR;
289 Lr = ((double)pYCbCr->lumaRed / (double)10000);
290 Lg = ((double)pYCbCr->lumaGreen / (double)10000);
291 Lb = ((double)pYCbCr->lumaBlue / (double)10000);
293 ditherR = ((1 << nBitsR) - 1) * (double)256 / (double)255;
294 ditherG = ((1 << nBitsG) - 1) * (double)256 / (double)255;
295 ditherB = ((1 << nBitsB) - 1) * (double)256 / (double)255;
297 for (refCb = 0; refCb < nLevelsCbCr; refCb++) {
298 Cb = (255 * refCb) / (nLevelsCbCr - 1);
300 for (refCr = 0; refCr < nLevelsCbCr; refCr++) {
301 Cr = (255 * refCr) / (nLevelsCbCr - 1);
303 for (refY = 0; refY < nLevelsY; refY++) {
304 Y = (255 * refY) / (nLevelsY - 1);
306 /* Store 4 dithered pixels, the result of dithering RGB with
307 a 2x2 kernel. See /ilc/ildither.c for equivalent code.
312 pixel = R >> (8 - nBitsR);
314 pixel |= G >> (8 - nBitsG);
316 pixel |= B >> (8 - nBitsB);
317 pixel = pMapPixels[pixel];
318 *pTable++ = (pixel << 24) | (pixel << 16) | (pixel << 8) | pixel;
323 int halfR = (1 << (7 - nBitsR)) - 1;
324 int halfG = (1 << (7 - nBitsG)) - 1;
325 int halfB = (1 << (7 - nBitsB)) - 1;
326 int maskR = ~((1 << (8 - nBitsR)) - 1);
327 int maskG = ~((1 << (8 - nBitsG)) - 1);
328 int maskB = ~((1 << (8 - nBitsB)) - 1);
330 for (i = 0, pixel = 0; i < 4; i++) {
332 if (temp1 > 255) temp1 = 255; else if (temp1 < 0) temp1 = 0;
333 R += R - (temp1 & maskR);
334 temp = temp1 >> (8 - nBitsR);
337 if (temp1 > 255) temp1 = 255; else if (temp1 < 0) temp1 = 0;
338 G += G - (temp1 & maskG);
340 temp |= temp1 >> (8 - nBitsG);
343 if (temp1 > 255) temp1 = 255; else if (temp1 < 0) temp1 = 0;
344 B += B - (temp1 & maskB);
346 temp |= temp1 >> (8 - nBitsB);
349 pixel |= pMapPixels[temp];
356 R = (double)R * ditherR;
357 G = (double)G * ditherG;
358 B = (double)B * ditherB;
360 for (i = 0, pixel = 0; i < 4; i++) {
361 kernel = _il2x2DitherKernel[i];
362 temp = (R + kernel) >> 8;
364 temp |= (G + kernel) >> 8;
366 temp |= (B + kernel) >> 8;
368 pixel |= pMapPixels[temp];
379 /* ------------------------ _ilFastYCbCrDither ---------------------------- */
380 /* Called by ilConvertForXWrite() to do fast dithered display of YCbCr.
381 The pipe image must be planar, subsampled by 2 in Cb/Cr, 1 in Y.
382 "pMapPixels" points to 256 bytes from the XWC map image, which are folded
383 into the lookup table used for this function.
385 IL_PRIVATE ilBool _ilFastYCbCrDither (
397 ilDitherYCbCrPrivPtr pPriv;
398 ilDstElementData dstData;
399 ilSrcElementData srcData;
401 /* Add a filter to convert subsampled YCbCr to a dithered palette image.
402 Force a single strip; image is at least 2 by 2
404 srcData.consumerImage = (ilObject)NULL;
405 srcData.stripHeight = pInfo->height;
406 srcData.constantStrip = TRUE;
407 srcData.minBufferHeight = 0;
409 dstData.producerObject = (ilObject)NULL;
410 dstData.pDes = IL_DES_GRAY; /* arbitrary; not really used */
411 dstData.pFormat = IL_FORMAT_BYTE;
412 dstData.width = pInfo->width;
413 dstData.height = pInfo->height;
414 dstData.stripHeight = srcData.stripHeight;
418 dstData.stripHeight *= 2;
420 dstData.constantStrip = pInfo->constantStrip;
421 dstData.pPalette = (unsigned short *)NULL;
423 pPriv = (ilDitherYCbCrPrivPtr)ilAddPipeElement (pipe, IL_FILTER,
424 sizeof(ilDitherYCbCrPrivRec), 0, &srcData, &dstData, IL_NPF, IL_NPF, IL_NPF,
425 (doDouble) ? ilFastYCbCrDitherDoubleExecute : ilFastYCbCrDitherExecute, 0);
429 /* Init the table in private */
430 ilSetupYCbCrDitherTables (&pDes->typeInfo.YCbCr, nBitsRed, nBitsGreen, nBitsBlue,
431 pMapPixels, pPriv->pixels);