lib/DtHelp/il: remove register keyword
[oweals/cde.git] / cde / lib / DtHelp / il / ilXycbcr.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
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
22  */
23 /* $XConsortium: ilXycbcr.c /main/3 1995/10/23 15:41:23 rswiston $ */
24 /**---------------------------------------------------------------------
25 ***     
26 ***    (c)Copyright 1991 Hewlett-Packard Co.
27 ***    
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).
37 ***
38 ***-------------------------------------------------------------------*/
39
40 #include "ilint.h"
41 #include "ilXint.h"
42 #include <math.h>
43 #include "ilpipelem.h"
44 #include "ilerrors.h"
45
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"
49         longs in size.
50     */
51 #define DYCBCR_NBITS_Y      6
52 #define DYCBCR_NBITS_CBCR   4
53
54     /*  Tables generated by /il/util/gendithertables.c */
55 static unsigned int _il2x2DitherKernel[4] = {42, 234, 170, 106};
56
57         /*  Private data for YCbCr to dithered pixel filter */
58 typedef struct {
59     unsigned long   pixels[1 << (DYCBCR_NBITS_Y + DYCBCR_NBITS_CBCR + DYCBCR_NBITS_CBCR)];
60     } ilDitherYCbCrPrivRec, *ilDitherYCbCrPrivPtr;
61
62
63         /*  ---------------------- ilFastYCbCrDitherExecute ------------------------ */
64         /*  Execute() function: dither from subsampled-by-2 YCbCr to 8 bit pixels.
65         */
66 static ilError ilFastYCbCrDitherExecute (
67     ilExecuteData          *pData,
68     long                    dstLine,
69     long                   *pNLines
70     )
71 {
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;
80
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.
84         */
85     pPlane = pData->pSrcImage->plane;
86     YRowBytes = pPlane->nBytesPerRow;
87     pYLine = pPlane->pPixels;
88     pPlane++;
89     CbRowBytes = pPlane->nBytesPerRow;
90     pCbLine = pPlane->pPixels;
91     pPlane++;
92     CrRowBytes = pPlane->nBytesPerRow;
93     pCrLine = pPlane->pPixels;
94     if (pData->srcLine) {
95         pYLine  += pData->srcLine * YRowBytes;
96         pCbLine += (pData->srcLine >> 1) * CbRowBytes;
97         pCrLine += (pData->srcLine >> 1) * CrRowBytes;
98         }
99     pPlane = pData->pDstImage->plane;
100     dstRowBytes = pPlane->nBytesPerRow;
101     pDstLine = pPlane->pPixels + dstLine * dstRowBytes;
102
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;
107
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>.
112         */
113     while (nLinesDiv2-- > 0) {
114         pY = pYLine;
115         pYLine += YRowBytes << 1;       /* skip 2 lines; read 2 lines each loop */
116         pCb = pCbLine;
117         pCbLine += CbRowBytes;
118         pCr = pCrLine;
119         pCrLine += CrRowBytes;
120         pDst = pDstLine;
121         pDstLine += dstRowBytes << 1;   /* skip 2 lines; write 2 lines each loop */
122         nPixelsDiv2 = halfWidth;
123         while (nPixelsDiv2-- > 0) {
124             temp0 = *pCb++;
125             CbCr = *pCr++;
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 */
130
131             temp0 = pY[YRowBytes];      /* do pixel and pixel below */
132             temp1 = *pY++;
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;
137
138             temp0 = pY[YRowBytes];      /* do pixel and pixel below */
139             temp1 = *pY++;
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;
144             }
145         }
146
147     return IL_OK;
148 }
149
150         /*  -------------------- ilFastYCbCrDitherDoubleExecute ---------------------- */
151         /*  Execute() function: dither and double the given # of src lines. 
152         */
153 static ilError ilFastYCbCrDitherDoubleExecute (
154     ilExecuteData          *pData,
155     long                    dstLine,
156     long                   *pNLines
157     )
158 {
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;
167 ilPtr              pY, pCb, pCr;
168 unsigned short    *pDst;
169 unsigned short             *pDstLine;
170
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.
174         */
175     pPlane = pData->pSrcImage->plane;
176     YRowBytes = pPlane->nBytesPerRow;
177     pYLine = pPlane->pPixels;
178     pPlane++;
179     CbRowBytes = pPlane->nBytesPerRow;
180     pCbLine = pPlane->pPixels;
181     pPlane++;
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;
188         }
189
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;
197
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;
203
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.
208         */
209     while (nLinesDiv2-- > 0) {
210         pY = pYLine;
211         pYLine += YRowBytes << 1;       /* skip 2 lines; read 2 lines each loop */
212         pCb = pCbLine;
213         pCbLine += CbRowBytes;
214         pCr = pCrLine;
215         pCrLine += CrRowBytes;
216         pDst = pDstLine;
217         pDstLine += dstRowShorts << 2;   /* skip 4 lines; write 4 lines each loop */
218         nPixelsDiv2 = halfWidth;
219         while (nPixelsDiv2-- > 0) {
220             temp0 = *pCb++;
221             CbCr = *pCr++;
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 */
226
227             temp0 = pY[YRowBytes];      /* do pixel and pixel below */
228             temp1 = *pY++;
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);
237
238             temp0 = pY[YRowBytes];      /* do pixel and pixel below */
239             temp1 = *pY++;
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);
248             }
249         }
250
251     return IL_OK;
252 }
253
254
255
256     /*  ---------------------------- ilSetupYCbCrDitherTables ----------------------- */
257     /*  Setup *pTable as necessary for the YCbCr to RGB (dither) conversion.
258     */
259 static void ilSetupYCbCrDitherTables (
260     ilYCbCrInfo   *pYCbCr,
261     int                     nBitsR,
262     int                     nBitsG,
263     int                     nBitsB,
264     ilPtr                   pMapPixels,
265     unsigned long          *pTable
266     )
267 {
268 int                         nTableEntries, nLevelsY, nLevelsCbCr;
269 int                         Y, Cb, Cr, refY, refCb, refCr;
270 int                R, G, B, pixel, i, temp, kernel;
271 double                      Lr, Lg, Lb;
272 double                      ditherR, ditherG, ditherB, ditherY, ditherCbCr;
273
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;\
284                 }
285
286 #define YCBCR_DEBUG_TABLE 1
287 #ifdef YCBCR_DEBUG_TABLE
288         /*  Set pMapPixels to identity, for debugging */
289     ilByte  debugMapPixels[256];
290     int     tmp;
291     int     doDebug = FALSE;
292
293     if (doDebug) {
294         for (tmp = 0; tmp < 256; tmp++)
295             debugMapPixels[tmp] = tmp;
296         pMapPixels = debugMapPixels;
297         }
298 #endif
299
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
306             long X pixel.
307         */
308     nLevelsY = 1 << DYCBCR_NBITS_Y;
309     nLevelsCbCr = 1 << DYCBCR_NBITS_CBCR;
310
311     Lr = ((double)pYCbCr->lumaRed / (double)10000);
312     Lg = ((double)pYCbCr->lumaGreen / (double)10000);
313     Lb = ((double)pYCbCr->lumaBlue / (double)10000);
314
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;
318
319     for (refCb = 0; refCb < nLevelsCbCr; refCb++) {
320         Cb = (255 * refCb) / (nLevelsCbCr - 1);
321
322         for (refCr = 0; refCr < nLevelsCbCr; refCr++) {
323             Cr = (255 * refCr) / (nLevelsCbCr - 1);
324
325             for (refY = 0; refY < nLevelsY; refY++) {
326                 Y = (255 * refY) / (nLevelsY - 1);
327
328                     /*  Store 4 dithered pixels, the result of dithering RGB with
329                         a 2x2 kernel.  See /ilc/ildither.c for equivalent code.
330                     */
331 #define DITHER
332 #ifdef COLORSLAM
333                 CVT_TO_RGB
334                 pixel = R >> (8 - nBitsR);
335                 pixel <<= nBitsG;
336                 pixel |= G >> (8 - nBitsG);
337                 pixel <<= nBitsB;
338                 pixel |= B >> (8 - nBitsB);
339                 pixel = pMapPixels[pixel];
340                 *pTable++ = (pixel << 24) | (pixel << 16) | (pixel << 8) | pixel;
341 #else
342 #ifdef DIFFUSION
343 {
344                 int temp1, temp2;
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);
351                 CVT_TO_RGB
352                 for (i = 0, pixel = 0; i < 4; i++) {
353                     temp1 = R + halfR;
354                     if (temp1 > 255) temp1 = 255; else if (temp1 < 0) temp1 = 0;
355                     R += R - (temp1 & maskR);
356                     temp = temp1 >> (8 - nBitsR);
357
358                     temp1 = G + halfG;
359                     if (temp1 > 255) temp1 = 255; else if (temp1 < 0) temp1 = 0;
360                     G += G - (temp1 & maskG);
361                     temp <<= nBitsG;
362                     temp |= temp1 >> (8 - nBitsG);
363
364                     temp1 = B + halfB;
365                     if (temp1 > 255) temp1 = 255; else if (temp1 < 0) temp1 = 0;
366                     B += B - (temp1 & maskB);
367                     temp <<= nBitsB;
368                     temp |= temp1 >> (8 - nBitsB);
369
370                     pixel <<= 8;
371                     pixel |= pMapPixels[temp];
372                     }
373                 *pTable++ = pixel;
374 }
375 #else
376 #ifdef DITHER
377                 CVT_TO_RGB
378                 R = (double)R * ditherR;
379                 G = (double)G * ditherG;
380                 B = (double)B * ditherB;
381
382                 for (i = 0, pixel = 0; i < 4; i++) {
383                     kernel = _il2x2DitherKernel[i];
384                     temp = (R + kernel) >> 8;
385                     temp <<= nBitsG;
386                     temp |= (G + kernel) >> 8;
387                     temp <<= nBitsB;
388                     temp |= (B + kernel) >> 8;
389                     pixel <<= 8;
390                     pixel |= pMapPixels[temp];
391                     }
392                 *pTable++ = pixel;
393 #endif
394 #endif
395 #endif
396                 }
397             }
398         }
399 }
400
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.
406         */
407 IL_PRIVATE ilBool _ilFastYCbCrDither (
408     ilPipe                  pipe,
409     ilImageDes             *pDes,
410     ilPipeInfo             *pInfo,
411     int                     nBitsRed,
412     int                     nBitsGreen,
413     int                     nBitsBlue,
414     ilBool                  doDouble,
415     ilPtr                   pMapPixels
416     )
417 {
418 ilImageDes                  des;
419 ilDitherYCbCrPrivPtr        pPriv;
420 ilDstElementData            dstData;
421 ilSrcElementData            srcData;
422
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 
425         */
426     srcData.consumerImage = (ilObject)NULL;
427     srcData.stripHeight = pInfo->height;
428     srcData.constantStrip = TRUE;
429     srcData.minBufferHeight = 0;
430
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;
437     if (doDouble) {
438         dstData.width *= 2;
439         dstData.height *= 2;
440         dstData.stripHeight *= 2;
441         }
442     dstData.constantStrip = pInfo->constantStrip;
443     dstData.pPalette = (unsigned short *)NULL;
444
445     pPriv = (ilDitherYCbCrPrivPtr)ilAddPipeElement (pipe, IL_FILTER, 
446             sizeof(ilDitherYCbCrPrivRec), 0, &srcData, &dstData, IL_NPF, IL_NPF, IL_NPF, 
447             (doDouble) ? ilFastYCbCrDitherDoubleExecute : ilFastYCbCrDitherExecute, 0);
448     if (!pPriv)
449         return FALSE;
450
451         /*  Init the table in private */
452     ilSetupYCbCrDitherTables (&pDes->typeInfo.YCbCr, nBitsRed, nBitsGreen, nBitsBlue,
453                               pMapPixels, pPriv->pixels);
454
455     return TRUE;
456 }