Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / lib / DtHelp / il / ilXycbcr.c
1 /* $XConsortium: ilXycbcr.c /main/3 1995/10/23 15:41:23 rswiston $ */
2 /**---------------------------------------------------------------------
3 ***     
4 ***    (c)Copyright 1991 Hewlett-Packard Co.
5 ***    
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).
15 ***
16 ***-------------------------------------------------------------------*/
17
18 #include "ilint.h"
19 #include "ilXint.h"
20 #include <math.h>
21 #include "ilpipelem.h"
22 #include "ilerrors.h"
23
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"
27         longs in size.
28     */
29 #define DYCBCR_NBITS_Y      6
30 #define DYCBCR_NBITS_CBCR   4
31
32     /*  Tables generated by /il/util/gendithertables.c */
33 static unsigned int _il2x2DitherKernel[4] = {42, 234, 170, 106};
34
35         /*  Private data for YCbCr to dithered pixel filter */
36 typedef struct {
37     unsigned long   pixels[1 << (DYCBCR_NBITS_Y + DYCBCR_NBITS_CBCR + DYCBCR_NBITS_CBCR)];
38     } ilDitherYCbCrPrivRec, *ilDitherYCbCrPrivPtr;
39
40
41         /*  ---------------------- ilFastYCbCrDitherExecute ------------------------ */
42         /*  Execute() function: dither from subsampled-by-2 YCbCr to 8 bit pixels.
43         */
44 static ilError ilFastYCbCrDitherExecute (
45     ilExecuteData          *pData,
46     long                    dstLine,
47     long                   *pNLines
48     )
49 {
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;
58
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.
62         */
63     pPlane = pData->pSrcImage->plane;
64     YRowBytes = pPlane->nBytesPerRow;
65     pYLine = pPlane->pPixels;
66     pPlane++;
67     CbRowBytes = pPlane->nBytesPerRow;
68     pCbLine = pPlane->pPixels;
69     pPlane++;
70     CrRowBytes = pPlane->nBytesPerRow;
71     pCrLine = pPlane->pPixels;
72     if (pData->srcLine) {
73         pYLine  += pData->srcLine * YRowBytes;
74         pCbLine += (pData->srcLine >> 1) * CbRowBytes;
75         pCrLine += (pData->srcLine >> 1) * CrRowBytes;
76         }
77     pPlane = pData->pDstImage->plane;
78     dstRowBytes = pPlane->nBytesPerRow;
79     pDstLine = pPlane->pPixels + dstLine * dstRowBytes;
80
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;
85
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>.
90         */
91     while (nLinesDiv2-- > 0) {
92         pY = pYLine;
93         pYLine += YRowBytes << 1;       /* skip 2 lines; read 2 lines each loop */
94         pCb = pCbLine;
95         pCbLine += CbRowBytes;
96         pCr = pCrLine;
97         pCrLine += CrRowBytes;
98         pDst = pDstLine;
99         pDstLine += dstRowBytes << 1;   /* skip 2 lines; write 2 lines each loop */
100         nPixelsDiv2 = halfWidth;
101         while (nPixelsDiv2-- > 0) {
102             temp0 = *pCb++;
103             CbCr = *pCr++;
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 */
108
109             temp0 = pY[YRowBytes];      /* do pixel and pixel below */
110             temp1 = *pY++;
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;
115
116             temp0 = pY[YRowBytes];      /* do pixel and pixel below */
117             temp1 = *pY++;
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;
122             }
123         }
124
125     return IL_OK;
126 }
127
128         /*  -------------------- ilFastYCbCrDitherDoubleExecute ---------------------- */
129         /*  Execute() function: dither and double the given # of src lines. 
130         */
131 static ilError ilFastYCbCrDitherDoubleExecute (
132     ilExecuteData          *pData,
133     long                    dstLine,
134     long                   *pNLines
135     )
136 {
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;
148
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.
152         */
153     pPlane = pData->pSrcImage->plane;
154     YRowBytes = pPlane->nBytesPerRow;
155     pYLine = pPlane->pPixels;
156     pPlane++;
157     CbRowBytes = pPlane->nBytesPerRow;
158     pCbLine = pPlane->pPixels;
159     pPlane++;
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;
166         }
167
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;
175
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;
181
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.
186         */
187     while (nLinesDiv2-- > 0) {
188         pY = pYLine;
189         pYLine += YRowBytes << 1;       /* skip 2 lines; read 2 lines each loop */
190         pCb = pCbLine;
191         pCbLine += CbRowBytes;
192         pCr = pCrLine;
193         pCrLine += CrRowBytes;
194         pDst = pDstLine;
195         pDstLine += dstRowShorts << 2;   /* skip 4 lines; write 4 lines each loop */
196         nPixelsDiv2 = halfWidth;
197         while (nPixelsDiv2-- > 0) {
198             temp0 = *pCb++;
199             CbCr = *pCr++;
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 */
204
205             temp0 = pY[YRowBytes];      /* do pixel and pixel below */
206             temp1 = *pY++;
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);
215
216             temp0 = pY[YRowBytes];      /* do pixel and pixel below */
217             temp1 = *pY++;
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);
226             }
227         }
228
229     return IL_OK;
230 }
231
232
233
234     /*  ---------------------------- ilSetupYCbCrDitherTables ----------------------- */
235     /*  Setup *pTable as necessary for the YCbCr to RGB (dither) conversion.
236     */
237 static void ilSetupYCbCrDitherTables (
238     register ilYCbCrInfo   *pYCbCr,
239     int                     nBitsR,
240     int                     nBitsG,
241     int                     nBitsB,
242     ilPtr                   pMapPixels,
243     unsigned long          *pTable
244     )
245 {
246 int                         nTableEntries, nLevelsY, nLevelsCbCr;
247 int                         Y, Cb, Cr, refY, refCb, refCr;
248 register int                R, G, B, pixel, i, temp, kernel;
249 double                      Lr, Lg, Lb;
250 double                      ditherR, ditherG, ditherB, ditherY, ditherCbCr;
251
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;\
262                 }
263
264 #define YCBCR_DEBUG_TABLE 1
265 #ifdef YCBCR_DEBUG_TABLE
266         /*  Set pMapPixels to identity, for debugging */
267     ilByte  debugMapPixels[256];
268     int     tmp;
269     int     doDebug = FALSE;
270
271     if (doDebug) {
272         for (tmp = 0; tmp < 256; tmp++)
273             debugMapPixels[tmp] = tmp;
274         pMapPixels = debugMapPixels;
275         }
276 #endif
277
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
284             long X pixel.
285         */
286     nLevelsY = 1 << DYCBCR_NBITS_Y;
287     nLevelsCbCr = 1 << DYCBCR_NBITS_CBCR;
288
289     Lr = ((double)pYCbCr->lumaRed / (double)10000);
290     Lg = ((double)pYCbCr->lumaGreen / (double)10000);
291     Lb = ((double)pYCbCr->lumaBlue / (double)10000);
292
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;
296
297     for (refCb = 0; refCb < nLevelsCbCr; refCb++) {
298         Cb = (255 * refCb) / (nLevelsCbCr - 1);
299
300         for (refCr = 0; refCr < nLevelsCbCr; refCr++) {
301             Cr = (255 * refCr) / (nLevelsCbCr - 1);
302
303             for (refY = 0; refY < nLevelsY; refY++) {
304                 Y = (255 * refY) / (nLevelsY - 1);
305
306                     /*  Store 4 dithered pixels, the result of dithering RGB with
307                         a 2x2 kernel.  See /ilc/ildither.c for equivalent code.
308                     */
309 #define DITHER
310 #ifdef COLORSLAM
311                 CVT_TO_RGB
312                 pixel = R >> (8 - nBitsR);
313                 pixel <<= nBitsG;
314                 pixel |= G >> (8 - nBitsG);
315                 pixel <<= nBitsB;
316                 pixel |= B >> (8 - nBitsB);
317                 pixel = pMapPixels[pixel];
318                 *pTable++ = (pixel << 24) | (pixel << 16) | (pixel << 8) | pixel;
319 #else
320 #ifdef DIFFUSION
321 {
322                 int temp1, temp2;
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);
329                 CVT_TO_RGB
330                 for (i = 0, pixel = 0; i < 4; i++) {
331                     temp1 = R + halfR;
332                     if (temp1 > 255) temp1 = 255; else if (temp1 < 0) temp1 = 0;
333                     R += R - (temp1 & maskR);
334                     temp = temp1 >> (8 - nBitsR);
335
336                     temp1 = G + halfG;
337                     if (temp1 > 255) temp1 = 255; else if (temp1 < 0) temp1 = 0;
338                     G += G - (temp1 & maskG);
339                     temp <<= nBitsG;
340                     temp |= temp1 >> (8 - nBitsG);
341
342                     temp1 = B + halfB;
343                     if (temp1 > 255) temp1 = 255; else if (temp1 < 0) temp1 = 0;
344                     B += B - (temp1 & maskB);
345                     temp <<= nBitsB;
346                     temp |= temp1 >> (8 - nBitsB);
347
348                     pixel <<= 8;
349                     pixel |= pMapPixels[temp];
350                     }
351                 *pTable++ = pixel;
352 }
353 #else
354 #ifdef DITHER
355                 CVT_TO_RGB
356                 R = (double)R * ditherR;
357                 G = (double)G * ditherG;
358                 B = (double)B * ditherB;
359
360                 for (i = 0, pixel = 0; i < 4; i++) {
361                     kernel = _il2x2DitherKernel[i];
362                     temp = (R + kernel) >> 8;
363                     temp <<= nBitsG;
364                     temp |= (G + kernel) >> 8;
365                     temp <<= nBitsB;
366                     temp |= (B + kernel) >> 8;
367                     pixel <<= 8;
368                     pixel |= pMapPixels[temp];
369                     }
370                 *pTable++ = pixel;
371 #endif
372 #endif
373 #endif
374                 }
375             }
376         }
377 }
378
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.
384         */
385 IL_PRIVATE ilBool _ilFastYCbCrDither (
386     ilPipe                  pipe,
387     ilImageDes             *pDes,
388     ilPipeInfo             *pInfo,
389     int                     nBitsRed,
390     int                     nBitsGreen,
391     int                     nBitsBlue,
392     ilBool                  doDouble,
393     ilPtr                   pMapPixels
394     )
395 {
396 ilImageDes                  des;
397 ilDitherYCbCrPrivPtr        pPriv;
398 ilDstElementData            dstData;
399 ilSrcElementData            srcData;
400
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 
403         */
404     srcData.consumerImage = (ilObject)NULL;
405     srcData.stripHeight = pInfo->height;
406     srcData.constantStrip = TRUE;
407     srcData.minBufferHeight = 0;
408
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;
415     if (doDouble) {
416         dstData.width *= 2;
417         dstData.height *= 2;
418         dstData.stripHeight *= 2;
419         }
420     dstData.constantStrip = pInfo->constantStrip;
421     dstData.pPalette = (unsigned short *)NULL;
422
423     pPriv = (ilDitherYCbCrPrivPtr)ilAddPipeElement (pipe, IL_FILTER, 
424             sizeof(ilDitherYCbCrPrivRec), 0, &srcData, &dstData, IL_NPF, IL_NPF, IL_NPF, 
425             (doDouble) ? ilFastYCbCrDitherDoubleExecute : ilFastYCbCrDitherExecute, 0);
426     if (!pPriv)
427         return FALSE;
428
429         /*  Init the table in private */
430     ilSetupYCbCrDitherTables (&pDes->typeInfo.YCbCr, nBitsRed, nBitsGreen, nBitsBlue,
431                               pMapPixels, pPriv->pixels);
432
433     return TRUE;
434 }