1 /* $XConsortium: ilycbcr.c /main/5 1996/06/19 12:20:22 ageorge $ */
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 ***-------------------------------------------------------------------*/
18 /* /ilc/ilycbcr.c : Code for handling IL_YCBCR images, including
19 conversions to/from RGB, and subsampling - upsampling is in /ilc/ilupsample.c
22 #include "ilpipelem.h"
23 #include "ilconvert.h"
26 /* ========================== Sub/Upsample Code ================================== */
28 #define NSUBSAMPLES 3 /* hardwired to 3 samples: Y, Cb, Cr */
30 /* Sub/Upsubsample factors as shifts (1=0, 2=1, 4=2) - others not supported. */
32 unsigned int horiz, vert;
33 } ilSubsampleShiftRec, *ilSubsampleShiftPtr;
35 /* Private for sub/upsampling filters. */
37 int nSamples; /* # of samples (components) to process */
38 ilSubsampleShiftRec shift[NSUBSAMPLES]; /* upsample mul as shift value */
39 } ilSubsamplePrivRec, *ilSubsamplePrivPtr;
42 /* ========================== Subsample Code =================================== */
44 /* -------------------------- ilExecuteSubsample ------------------------------- */
45 /* Execute(): subsample as necessary "pPriv->nSamples" planes of the source image.
46 The source image must be planar, byte/pixel.
48 static ilError ilExecuteSubsample (
51 long *pNLines /* ignored on input */
54 register ilSubsamplePrivPtr pPriv;
55 ilImagePlaneInfo *pSrcPlane, *pDstPlane;
57 ilPtr pSrcLine, pDstLine;
59 long srcRowInc, dstRowBytes;
60 long nDstLinesM1, nDstPixelsM1Init;
61 ilSubsampleShiftPtr pShift;
62 register long nDstPixelsM1, srcRowBytes, i;
63 register ilPtr pSrc, pDst;
64 register unsigned int pixel;
66 /* Get width and height of _upsampled_ image; exit if zero. */
67 pPriv = (ilSubsamplePrivPtr)pData->pPrivate;
71 width = pData->pSrcImage->width;
75 /* Loop on samples (components), upsample/translate each plane separately.
76 Note that "srcLine" is shifted - indexing into plane based on vert subsample.
78 for (pSrcPlane = pData->pSrcImage->plane, pDstPlane = pData->pDstImage->plane,
79 pShift = pPriv->shift, nSamples = pPriv->nSamples;
81 pSrcPlane++, pDstPlane++, pShift++) {
83 /* Get # dst lines/pixels across - 1; skip plane if none */
84 nDstLinesM1 = height >> pShift->vert;
88 nDstPixelsM1Init = width >> pShift->horiz;
89 if (nDstPixelsM1Init <= 0)
93 /* Point to src/dst; note dstLine scaled down by vert subsample shift.
94 Set srcRowInc to srcRowBytes scaled up by vertical shift.
96 srcRowBytes = pSrcPlane->nBytesPerRow;
97 pSrcLine = pSrcPlane->pPixels + pData->srcLine * srcRowBytes;
98 srcRowInc = srcRowBytes << pShift->vert;
99 dstRowBytes = pDstPlane->nBytesPerRow;
100 pDstLine = pDstPlane->pPixels + (dstLine >> pShift->vert) * dstRowBytes;
102 switch (pShift->horiz) { /* NOTE: vert shift must be the same! */
104 /* 0 = no subsampling; just copy plane info */
109 bcopy ((char *)pSrc, (char *)pDst, width);
112 } while (--nDstLinesM1 >= 0);
115 /* 1 = 1/4 of pixels (half in each dimension). Take the average of 4
116 pixels: (x,y), (x+1,y), (x,y+1), (x+1,y+1), for each even x,y.
121 pSrcLine += srcRowInc;
123 pDstLine += dstRowBytes;
124 nDstPixelsM1 = nDstPixelsM1Init;
127 pixel += *(pSrc + 1);
128 pixel += *(pSrc + srcRowBytes);
129 pixel += *(pSrc + srcRowBytes + 1);
130 pSrc += 2; /* two pixels to the right */
131 *pDst++ = pixel >> 2; /* store 1/4 sum of 4 pixels */
132 } while (--nDstPixelsM1 >= 0);
133 } while (--nDstLinesM1 >= 0);
136 /* 2 = 1/16 of pixels (1/4 in each dimension). Take the average of 16 pixels,
137 a block below and to the right of (x,y), x,y = multiple of 4.
142 pSrcLine += srcRowInc;
144 pDstLine += dstRowBytes;
145 nDstPixelsM1 = nDstPixelsM1Init;
151 pixel += *(pSrc + 1);
152 pixel += *(pSrc + 2);
153 pixel += *(pSrc + 3);
156 *pDst++ = pixel >> 4; /* store 1/16 sum of 16 pixels */
157 pSrc += -srcRowInc + 4; /* back to top line, 4 to right */
158 } while (--nDstPixelsM1 >= 0);
159 } while (--nDstLinesM1 >= 0);
162 } /* END switch subsample shift */
163 } /* END each plane */
169 /* ---------------------------- ilSubsampleYCbCr ----------------------------- */
170 /* Subsample the pipe image which must be a fully upsampled YCbCr image.
171 pFormat points to the source format; on return, *pFormat is updated
172 to the dst format. *pDes to the _destination_ des, i.e. has subsample values.
174 IL_PRIVATE ilBool _ilSubsampleYCbCr (
178 ilImageFormat *pFormat
181 register ilSubsamplePrivPtr pSubPriv;
182 ilSubsamplePrivRec priv;
183 ilSubsampleShiftRec *pShift;
184 ilYCbCrSampleInfo *pSample;
186 ilDstElementData dstData;
187 ilSrcElementData srcData;
189 /* Only 8 bit planar YCbCr current handled; cvt if not that format. */
190 if ((pFormat->sampleOrder != IL_SAMPLE_PLANES)
191 || (pFormat->nBitsPerSample[0] != 8)
192 || (pFormat->nBitsPerSample[1] != 8)
193 || (pFormat->nBitsPerSample[2] != 8)) {
194 *pFormat = *IL_FORMAT_3BYTE_PLANE;
195 if (!ilConvert (pipe, (ilImageDes *)NULL, pFormat, 0, NULL))
199 /* Determine subsample values: only 1 (no subsampling), 2 (1/4 = 1/2 in each
200 dimension) or 4 (1/16) allowed; same both vertical/horizontal.
202 priv.nSamples = NSUBSAMPLES;
203 pSample = pDes->typeInfo.YCbCr.sample;
205 for (sample = 0; sample < NSUBSAMPLES; sample++, pShift++, pSample++) {
206 if (pSample->subsampleHoriz != pSample->subsampleVert)
207 return ilDeclarePipeInvalid (pipe, IL_ERROR_SUBSAMPLE);
208 switch ((unsigned int)pSample->subsampleHoriz) {
209 case 1: pShift->horiz = 0; break;
210 case 2: pShift->horiz = 1; break;
211 case 4: pShift->horiz = 2; break;
212 default: return ilDeclarePipeInvalid (pipe, IL_ERROR_SUBSAMPLE);
214 pShift->vert = pShift->horiz; /* same subsampling both dimensions */
217 /* Init dstData, add subsample filter. */
218 dstData.producerObject = (ilObject)NULL;
220 dstData.pFormat = pFormat;
221 dstData.width = pInfo->width;
222 dstData.height = pInfo->height;
223 dstData.stripHeight = 0;
224 dstData.constantStrip = FALSE;
225 dstData.pPalette = (unsigned short *)NULL;
227 /* Demand constant strips, a multiple of maximum subsample (4). */
228 srcData.consumerImage = (ilObject)NULL;
229 srcData.stripHeight = 8; /* Arbitrary, but must be multiple of 4 */
230 srcData.constantStrip = TRUE;
231 srcData.minBufferHeight = 0;
233 pSubPriv = (ilSubsamplePrivPtr)ilAddPipeElement (pipe, IL_FILTER,
234 sizeof (ilSubsamplePrivRec), 0, &srcData,
235 &dstData, IL_NPF, IL_NPF, IL_NPF, ilExecuteSubsample, NULL, 0);
238 *pSubPriv = priv; /* copy priv to priv ptr */
244 /* ======================= YCbCr to RGB Code =================================== */
246 /* Lookup tables for YCbCr to RGB conversion. Each table is indexed by Y, Cb or Cr,
247 and contains two values; one the upper short (1st) the other in the lower (2nd);
248 the upper short values are used to compute green.
249 Y G cvt: Y factor = (1 - Lb - Lr)/Lg scale for refBlack/White
250 Cb G cvt: Cb factor = -Lb*(2 - 2*Lb)/Lg Cb scale * (2 - 2 * Lr)
251 Cr G cvt: Cr factor = -Lr*(2 - 2*Lr)/Lg Cr scale * (2 - 2 * Lb)
254 long YTrans[256]; /* values indexed by Y, as above */
255 long CbTrans[256]; /* values indexed by Cb, as above */
256 long CrTrans[256]; /* values indexed by Cr, as above */
257 } ilRGBTransRec, *ilRGBTransPtr;
259 /* Private for RGB to YCbCr filter. */
261 ilRGBTransPtr pTrans; /* ptr to all the translate tables */
262 long y; /* for dither only: current Y */
263 } ilYCbCrToRGBPrivRec, *ilYCbCrToRGBPrivPtr;
265 /* Pointer to "std" translation table: works for "std" YCbCr values -
266 those in IL_DES_YCBCR.
268 static ilRGBTransPtr _ilStdYCbCrTransPtr = (ilRGBTransPtr)NULL;
271 /* --------------------------- ilDestroyTransTable --------------------- */
272 /* Destroy function: used only if pPriv->pTrans points to locally malloc'd
273 translate table, i.e. not using std values and table.
275 static ilError ilDestroyTransTable (
276 ilYCbCrToRGBPrivPtr pPriv
279 IL_FREE (pPriv->pTrans);
283 /* --------------------- ilExecutePlanarYCbCrToRGB ----------------------------- */
284 /* Execute(): convert _planar_ src YCbCr to _pixel_ dst RGB.
285 NOTE: the YCbCr image must have been upsampled, i.e. thru ilExecuteUpsample().
287 static ilError ilExecutePlanarYCbCrToRGB (
288 ilExecuteData *pData,
293 ilPtr pYLine, pCbLine, pCrLine, pDstLine;
294 register ilRGBTransPtr pTrans;
295 register ilPtr pY, pCb, pCr, pDst;
296 register long YTrans, CbTrans, CrTrans, pixel, nPixelsM1;
298 long nPixelsM1Init, nLinesM1;
299 long YRowBytes, CbRowBytes, CrRowBytes, dstRowBytes;
300 ilImagePlaneInfo *pPlane;
303 /* Set nPixels/LinesM1 to # pixels / lines - 1; exit if either 0. */
304 nPixelsM1Init = pData->pSrcImage->width;
305 if (nPixelsM1Init <= 0)
313 /* Point pY/Cb/CrLine to 1st line in src planes; pDstLine to 1st line in dst.
314 Get bytes/row for each of them.
316 pPlane = pData->pSrcImage->plane;
317 YRowBytes = pPlane->nBytesPerRow;
318 pYLine = pPlane->pPixels + pData->srcLine * YRowBytes;
320 CbRowBytes = pPlane->nBytesPerRow;
321 pCbLine = pPlane->pPixels + pData->srcLine * CbRowBytes;
323 CrRowBytes = pPlane->nBytesPerRow;
324 pCrLine = pPlane->pPixels + pData->srcLine * CrRowBytes;
326 pPlane = pData->pDstImage->plane;
327 dstRowBytes = pPlane->nBytesPerRow;
328 pDstLine = pPlane->pPixels + dstLine * dstRowBytes;
330 /* Convert planar YCbCr to pixel RGB. */
331 pTrans = ((ilYCbCrToRGBPrivPtr)pData->pPrivate)->pTrans;
336 pCbLine += CbRowBytes;
338 pCrLine += CrRowBytes;
340 pDstLine += dstRowBytes;
342 nPixelsM1 = nPixelsM1Init;
344 YTrans = pTrans->YTrans[*pY++];
345 CrTrans = pTrans->CrTrans[*pCr++];
347 CbTrans = pTrans->CbTrans[*pCb++];
348 pixel = Y + ((short)CrTrans);
349 if (pixel >> 8) goto plClipR;
350 plRClipped: *pDst++ = pixel; /* store red */
351 pixel = YTrans >> 16;
352 pixel += CbTrans >> 16;
353 pixel += CrTrans >> 16;
354 if (pixel >> 8) goto plClipG;
355 plGClipped: *pDst++ = pixel; /* store green */
356 pixel = Y + ((short)CbTrans);
357 if (pixel >> 8) goto plClipB;
358 plBClipped: *pDst++ = pixel; /* store blue */
359 } while (--nPixelsM1 >= 0);
360 } while (--nLinesM1 >= 0);
364 /* goto point for when R, G or B out of range: clamp pixel and go back and continue.
365 This is done to avoid taking a branch in the most common case: not out of range.
367 plClipR: if (pixel > 255) pixel = 255; else pixel = 0;
369 plClipG: if (pixel > 255) pixel = 255; else pixel = 0;
371 plClipB: if (pixel > 255) pixel = 255; else pixel = 0;
376 /* --------------------- ilExecutePixelYCbCrToRGB ----------------------------- */
377 /* Execute(): convert _pixel_ src YCbCr to _pixel_ dst RGB.
378 NOTE: the YCbCr image must have been upsampled, i.e. thru ilExecuteUpsample().
380 static ilError ilExecutePixelYCbCrToRGB (
381 ilExecuteData *pData,
386 ilPtr pSrcLine, pDstLine;
387 register ilRGBTransPtr pTrans;
388 register ilPtr pSrc, pDst;
389 register long YTrans, CbTrans, CrTrans, pixel, nPixelsM1;
391 long nPixelsM1Init, nLinesM1;
392 long srcRowBytes, dstRowBytes;
393 ilImagePlaneInfo *pPlane;
396 /* Set nPixels/LinesM1 to # pixels / lines - 1; exit if either 0. */
397 nPixelsM1Init = pData->pSrcImage->width;
398 if (nPixelsM1Init <= 0)
406 /* Point pY/Cb/CrLine to 1st line in src planes; pDstLine to 1st line in dst.
407 Get bytes/row for each of them.
409 pPlane = pData->pSrcImage->plane;
410 srcRowBytes = pPlane->nBytesPerRow;
411 pSrcLine = pPlane->pPixels + pData->srcLine * srcRowBytes;
413 pPlane = pData->pDstImage->plane;
414 dstRowBytes = pPlane->nBytesPerRow;
415 pDstLine = pPlane->pPixels + dstLine * dstRowBytes;
417 /* Convert pixel YCbCr to pixel RGB. */
418 pTrans = ((ilYCbCrToRGBPrivPtr)pData->pPrivate)->pTrans;
421 pSrcLine += srcRowBytes;
423 pDstLine += dstRowBytes;
425 nPixelsM1 = nPixelsM1Init;
427 YTrans = pTrans->YTrans[*pSrc++];
428 CbTrans = pTrans->CbTrans[*pSrc++];
430 CrTrans = pTrans->CrTrans[*pSrc++];
431 pixel = Y + ((short)CrTrans);
432 if (pixel >> 8) goto piClipR;
433 piRClipped: *pDst++ = pixel; /* store red */
434 pixel = YTrans >> 16;
435 pixel += CbTrans >> 16;
436 pixel += CrTrans >> 16;
437 if (pixel >> 8) goto piClipG;
438 piGClipped: *pDst++ = pixel; /* store green */
439 pixel = Y + ((short)CbTrans);
440 if (pixel >> 8) goto piClipB;
441 piBClipped: *pDst++ = pixel; /* store blue */
442 } while (--nPixelsM1 >= 0);
443 } while (--nLinesM1 >= 0);
447 /* goto point for when R, G or B out of range: clamp pixel and go back and continue.
448 This is done to avoid taking a branch in the most common case: not out of range.
450 piClipR: if (pixel > 255) pixel = 255; else pixel = 0;
452 piClipG: if (pixel > 255) pixel = 255; else pixel = 0;
454 piClipB: if (pixel > 255) pixel = 255; else pixel = 0;
459 /* ------------------------- ilGetYCbCrConvertTable -------------------------- */
460 /* Returns a pointer to the YCbCr conversion table (ilRGBTransRec); either
461 "_ilStdYCbCrTransPtr" or a ptr to a table that caller must destroy, or
462 null if a malloc error occurs.
464 static ilRGBTransPtr ilGetYCbCrConvertTable (
468 register ilRGBTransPtr pTrans;
469 const ilYCbCrInfo *pYCbCr, *pStdYCbCr;
470 double Lr, Lg, Lb, scaledY;
471 register double factor, gFactor;
472 register int i, refBlack, upper, lower;
479 /* If luma and refBlack/White info same as std IL_DES_YCBCR, then reuse
480 the table at _ilStdYCbCrTransPtr; create it here if does not exist yet.
482 pYCbCr = &pDes->typeInfo.YCbCr;
483 pStdYCbCr = &IL_DES_YCBCR->typeInfo.YCbCr;
484 if ((pYCbCr->sample[0].refBlack == pStdYCbCr->sample[0].refBlack)
485 && (pYCbCr->sample[0].refWhite == pStdYCbCr->sample[0].refWhite)
486 && (pYCbCr->sample[1].refBlack == pStdYCbCr->sample[1].refBlack)
487 && (pYCbCr->sample[1].refWhite == pStdYCbCr->sample[1].refWhite)
488 && (pYCbCr->sample[2].refBlack == pStdYCbCr->sample[2].refBlack)
489 && (pYCbCr->sample[2].refWhite == pStdYCbCr->sample[2].refWhite)
490 && (pYCbCr->lumaRed == pStdYCbCr->lumaRed)
491 && (pYCbCr->lumaGreen == pStdYCbCr->lumaGreen)
492 && (pYCbCr->lumaBlue == pStdYCbCr->lumaBlue)) {
494 pTrans = _ilStdYCbCrTransPtr; /* alloc below if not there yet */
498 pTrans = (ilRGBTransPtr)NULL; /* allocate it below */
501 /* Build translate tables. First, from pg 3 of Appendix O of TIFF spec:
502 R = Cr * (2 - 2 * Lr) + Y
503 B = Cb * (2 - 2 * Lb) + Y
504 G = (Y - Lb * B - Lr * R) / Lg
505 Get green in terms of Cb and Cr:
506 G = (Y - Lb*B - Lr*R) / Lg
507 G = (Y - Lb*(Cb * (2 - 2*Lb) + Y) - Lr*(Cr * (2 - 2*Lr) + Y)) / Lg
508 G = (Y - Lb*Cb*(2 - 2*Lb) - Lb*Y - Lr*Cr*(2 - 2*Lr) - Lr*Y) / Lg
509 G = (Y - Lb*Y - Lr*Y - Cb*Lb*(2 - 2*Lb) - Cr*Lr*(2 - 2*Lr)) / Lg
510 G = (Y * (1 - Lb - Lr) - Cb*Lb*(2 - 2*Lb) - Cr*Lr*(2 - 2*Lr)) / Lg
511 G = Y * (1 - Lb - Lr)/Lg + Cb * -Lb*(2 - 2*Lb)/Lg + Cr * -Lr*(2 - 2*Lr)/Lg
513 if (!pTrans) { /* non-std or std table not build yet */
514 pTrans = (ilRGBTransPtr)IL_MALLOC (sizeof (ilRGBTransRec));
518 /* The Y, Cb and Cr components must be scaled up based on refBlack/White.
519 Factor that scaling in everywhere Y/Cb/Cr are looked up.
520 First get the scale and refBlack for each sample.
522 for (i = 0; i < 3; i++) {
523 sample[i].refBlack = pYCbCr->sample[i].refBlack;
524 sample[i].scale = ((i == 0) ? 255 : 127) /
525 (pYCbCr->sample[i].refWhite - pYCbCr->sample[i].refBlack);
528 /* Calc the Cb/Cr lookup tables, factoring in their scale factors. */
529 Lr = ((double)pYCbCr->lumaRed / (double)10000);
530 Lg = ((double)pYCbCr->lumaGreen / (double)10000);
531 Lb = ((double)pYCbCr->lumaBlue / (double)10000);
533 /* Y translation: lower is scaled Y, upper is value added to get green */
534 gFactor = (1 - Lb - Lr) / Lg;
535 for (i = 0; i < 256; i++) {
536 scaledY = sample[0].scale * i - sample[0].refBlack;
537 upper = scaledY * gFactor + 0.5;
539 pTrans->YTrans[i] = (upper << 16) | (lower & 0xffff);
542 /* Cb: lower is added to Y to get blue, upper added to get green */
543 factor = (2 - 2 * Lb) * sample[1].scale;
544 gFactor = -Lb * (2 - 2 * Lb) / Lg;
545 refBlack = sample[1].refBlack;
546 for (i = 0; i < 256; i++) {
547 upper = (i - refBlack) * gFactor + 0.5;
548 lower = (i - refBlack) * factor + 0.5;
549 pTrans->CbTrans[i] = (upper << 16) | (lower & 0xffff);
552 /* Cr: lower is added to Y to get red, upper added to get green */
553 factor = (2 - 2 * Lr) * sample[2].scale;
554 gFactor = -Lr * (2 - 2 * Lr) / Lg;
555 refBlack = sample[2].refBlack;
556 for (i = 0; i < 256; i++) {
557 upper = (i - refBlack) * gFactor + 0.5;
558 lower = (i - refBlack) * factor + 0.5;
559 pTrans->CrTrans[i] = (upper << 16) | (lower & 0xffff);
562 /* If creating "std" conversion table for first time, set ptr to it */
564 _ilStdYCbCrTransPtr = pTrans;
565 } /* END build table */
571 /* ---------------------------- ilConvertYCbCrToRGB ----------------------------- */
572 /* Convert from source type (pDes->type) == IL_YCBCR to RBB.
573 pFormat points to the source format; on return, *pFormat is updated
574 to the dst format, *pDes to the dst descriptor.
577 IL_PRIVATE ilBool _ilConvertYCbCrToRGB (
581 ilImageFormat *pFormat
584 ilDstElementData dstData;
585 ilError (*executeFunction)(), (*destroyFunction)();
586 ilYCbCrToRGBPrivPtr pPriv;
587 register ilRGBTransPtr pTrans;
589 if ((pFormat->nBitsPerSample[0] != 8)
590 || (pFormat->nBitsPerSample[1] != 8)
591 || (pFormat->nBitsPerSample[2] != 8))
592 return ilDeclarePipeInvalid (pipe, IL_ERROR_NOT_IMPLEMENTED);
594 /* Handle planar/pixel src format with different executeFunction, but in
595 either case output RGB in 3 byte pixel format.
597 if (pFormat->sampleOrder == IL_SAMPLE_PIXELS)
598 executeFunction = ilExecutePixelYCbCrToRGB;
600 executeFunction = ilExecutePlanarYCbCrToRGB;
601 *pFormat = *IL_FORMAT_3BYTE_PIXEL;
604 /* Get translation table or error; destroy it if not the "std" one */
605 pTrans = ilGetYCbCrConvertTable (pDes);
607 return ilDeclarePipeInvalid (pipe, IL_ERROR_MALLOC);
608 destroyFunction = (pTrans == _ilStdYCbCrTransPtr) ? IL_NPF : ilDestroyTransTable;
610 /* Add element to the pipe, init private */
611 dstData.producerObject = (ilObject)NULL;
614 dstData.pFormat = pFormat;
615 dstData.width = pInfo->width;
616 dstData.height = pInfo->height;
617 dstData.stripHeight = 0;
618 dstData.constantStrip = FALSE;
619 dstData.pPalette = (unsigned short *)NULL;
620 pPriv = (ilYCbCrToRGBPrivPtr)ilAddPipeElement (pipe, IL_FILTER,
621 sizeof(ilYCbCrToRGBPrivRec), 0, (ilSrcElementData *)NULL, &dstData,
622 IL_NPF, IL_NPF, destroyFunction, executeFunction, NULL, 0);
624 if (destroyFunction) /* local copy of pTrans; free it */
628 pPriv->pTrans = pTrans;
634 /* ======================= Dither YCbCr Code =================================== */
636 /* Defines for # bits of RGB to dither to. NOTE! however that these are not
637 arbitrary; # bits of red must = # bits of green, because the pre-dither-mul'd
638 value of "Y" is the same for both.
640 #define YCBCR2_NR_BITS 2 /* # of bits of R/G/B to dither to */
641 #define YCBCR2_NG_BITS 3
642 #define YCBCR2_NB_BITS 2
643 #define YCBCR2_MAX_R ((1 << YCBCR2_NR_BITS) - 1) /* max value for R/G/B */
644 #define YCBCR2_MAX_G ((1 << YCBCR2_NG_BITS) - 1)
645 #define YCBCR2_MAX_B ((1 << YCBCR2_NB_BITS) - 1)
647 /* Private for RGB to dithered pixel filter. */
649 ilRGBTransRec trans; /* YCbCr->dither-mul'd values tables */
650 ilPtr pTranslate; /* ptr to ilMap() lookup table pixels */
651 unsigned short *pPalette; /* ptr to palette to destroy or null */
652 long y; /* Init(): current Y within dst image */
653 ilByte translate [256]; /* identity image if no mapImage given */
654 } ilYCbCr2DitherPrivRec, *ilYCbCr2DitherPrivPtr;
656 /* Init() function: init the counter of "y" within private */
657 static ilError ilYCbCr2DitherInit (
658 ilYCbCr2DitherPrivPtr pPriv,
659 ilImageInfo *pSrcImage,
660 ilImageInfo *pDstImage
667 /* Destroy function: destroy pTrans if not std and pPalette if not null */
668 static ilError ilYCbCr2DitherDestroy (
669 ilYCbCr2DitherPrivPtr pPriv
673 IL_FREE (pPriv->pPalette);
678 /* ---------------------- ilYCbCr2DitherExecute ------------------------ */
679 /* Execute() function: dither from subsampled-by-2 YCbCr to 8 bit pixels.
680 Dithering is done to RGB levels of 484 (232 in bits).
682 static ilError ilYCbCr2DitherExecute (
683 ilExecuteData *pData,
688 ilYCbCr2DitherPrivPtr pPriv;
689 ilImagePlaneInfo *pPlane;
690 long nLinesDiv2, halfWidthM1, y;
691 long CbRowBytes, CrRowBytes;
692 ilPtr pYLine, pCbLine, pCrLine, pDstLine;
696 register long YRowBytes, dstRowBytes;
697 register long Y, Cb, Cr, YTrans, CbTrans, CrTrans, comp, pixel;
698 register ilPtr pY, pDst;
699 register ilRGBTransPtr pTrans;
700 register ilPtr pTranslate;
701 register int *pKernel, kernel;
702 #define YCBCR2_KERNEL_SIZE 8 /* size of dither kernel used */
704 /* This filter handles a pipe image of YCbCr subsampled by 2 in Cb/Cr only.
705 The # of lines of Cb/Cr is therefore 1/2 the # of lines of Y.
706 Note: can only handle images with even width/height; checked elsewhere.
708 pPlane = pData->pSrcImage->plane;
709 YRowBytes = pPlane->nBytesPerRow;
710 pYLine = pPlane->pPixels;
712 CbRowBytes = pPlane->nBytesPerRow;
713 pCbLine = pPlane->pPixels;
715 CrRowBytes = pPlane->nBytesPerRow;
716 pCrLine = pPlane->pPixels;
717 if (pData->srcLine) {
718 pYLine += pData->srcLine * YRowBytes;
719 pCbLine += (pData->srcLine >> 1) * CbRowBytes;
720 pCrLine += (pData->srcLine >> 1) * CrRowBytes;
722 pPlane = pData->pDstImage->plane;
723 dstRowBytes = pPlane->nBytesPerRow;
724 pDstLine = pPlane->pPixels + dstLine * dstRowBytes;
726 pPriv = (ilYCbCr2DitherPrivPtr)pData->pPrivate;
727 halfWidthM1 = pData->pSrcImage->width >> 1; /* 1/2 # of pixels - 1 */
728 nLinesDiv2 = *pNLines >> 1;
729 if ((halfWidthM1 <= 0) || (nLinesDiv2 <= 0))
733 pPriv->y += *pNLines;
735 pTrans = &pPriv->trans;
736 pTranslate = pPriv->pTranslate;
738 /* Do 4 pixels at a time, using 4 Ys (below L, L, below R, R) for each Cb,Cr pair.
739 For each Y, do one pixel: get "comp" (RGB) as done in other YCbCr->RGB
740 filters, except that all values are pre-multiplied by what the dither tables
741 would yield if the lookup to _ilMul4/8[] was done. "pixel" is then used as
742 an index into pTranslate table to get pixel to write to dst.
743 See comments in ilGetYCbCrDitherTable() for details.
745 while (nLinesDiv2-- > 0) {
747 pYLine += YRowBytes << 1; /* skip 2 lines; read 2 lines each loop */
749 pCbLine += CbRowBytes;
751 pCrLine += CrRowBytes;
753 pDstLine += dstRowBytes << 1; /* skip 2 lines; write 2 lines each loop */
754 nPixelsDiv2M1 = halfWidthM1;
756 /* Point to even row within kernel based on "y"; point to end of row */
757 pKernel = (int *)&_ilDitherKernel[(y & 6) * YCBCR2_KERNEL_SIZE];
759 pKernelRowEnd = pKernel + 8;
761 /* Dither 4 pixels, using one set of Cb,Cr and 4 Y's. */
763 CrTrans = pTrans->CrTrans[*pCr++];
764 CbTrans = pTrans->CbTrans[*pCb++];
765 Cr = ((short)CrTrans);
767 Cb = ((short)CbTrans);
769 CbTrans += CrTrans; /* add Cb, Cr contributions to green */
772 YTrans = pTrans->YTrans[pY[YRowBytes]];
773 kernel = pKernel[YCBCR2_KERNEL_SIZE];
775 Y += kernel; /* pre-add kernel to Y */
776 pixel = (Y + Cr) >> 8;
777 if (pixel >> YCBCR2_NR_BITS) goto d0ClipR;
778 d0RClipped: comp = ((YTrans >> 16) + CbTrans + kernel) >> 8;
779 if (comp >> YCBCR2_NG_BITS) goto d0ClipG;
780 d0GClipped: pixel = (pixel << YCBCR2_NG_BITS) + comp;
781 comp = (Y + Cb) >> 8;
782 if (comp >> YCBCR2_NB_BITS) goto d0ClipB;
783 d0BClipped: pixel = (pixel << YCBCR2_NB_BITS) + comp;
784 pDst[dstRowBytes] = pTranslate[pixel];
786 /* Do pixel, move pKernel, pY, pDst one to the right */
787 YTrans = pTrans->YTrans[*pY++];
791 pixel = (Y + Cr) >> 8;
792 if (pixel >> YCBCR2_NR_BITS) goto d1ClipR;
793 d1RClipped: comp = ((YTrans >> 16) + CbTrans + kernel) >> 8;
794 if (comp >> YCBCR2_NG_BITS) goto d1ClipG;
795 d1GClipped: pixel = (pixel << YCBCR2_NG_BITS) + comp;
796 comp = (Y + Cb) >> 8;
797 if (comp >> YCBCR2_NB_BITS) goto d1ClipB;
798 d1BClipped: pixel = (pixel << YCBCR2_NB_BITS) + comp;
799 *pDst++ = pTranslate[pixel];
801 /* Same as above two steps for one pixel to the right */
802 YTrans = pTrans->YTrans[pY[YRowBytes]];
803 kernel = pKernel[YCBCR2_KERNEL_SIZE];
805 Y += kernel; /* pre-add kernel to Y */
806 pixel = (Y + Cr) >> 8;
807 if (pixel >> YCBCR2_NR_BITS) goto d2ClipR;
808 d2RClipped: comp = ((YTrans >> 16) + CbTrans + kernel) >> 8;
809 if (comp >> YCBCR2_NG_BITS) goto d2ClipG;
810 d2GClipped: pixel = (pixel << YCBCR2_NG_BITS) + comp;
811 comp = (Y + Cb) >> 8;
812 if (comp >> YCBCR2_NB_BITS) goto d2ClipB;
813 d2BClipped: pixel = (pixel << YCBCR2_NB_BITS) + comp;
814 pDst[dstRowBytes] = pTranslate[pixel];
816 /* Do pixel, move pKernel, pY, pDst one to the right */
817 YTrans = pTrans->YTrans[*pY++];
821 pixel = (Y + Cr) >> 8;
822 if (pixel >> YCBCR2_NR_BITS) goto d3ClipR;
823 d3RClipped: comp = ((YTrans >> 16) + CbTrans + kernel) >> 8;
824 if (comp >> YCBCR2_NG_BITS) goto d3ClipG;
825 d3GClipped: pixel = (pixel << YCBCR2_NG_BITS) + comp;
826 comp = (Y + Cb) >> 8;
827 if (comp >> YCBCR2_NB_BITS) goto d3ClipB;
828 d3BClipped: pixel = (pixel << YCBCR2_NB_BITS) + comp;
829 *pDst++ = pTranslate[pixel];
831 /* If pKernel off end of row, reset back (-8) to beginning of row */
832 if (pKernel >= pKernelRowEnd)
833 pKernel -= YCBCR2_KERNEL_SIZE;
834 } while (--nPixelsDiv2M1 >= 0);
839 /* goto point for when R, G or B out of range: clamp pixel and go back and continue.
840 This is done to avoid taking a branch in the most common case: not out of range.
842 d0ClipR: if (pixel > YCBCR2_MAX_R) pixel = YCBCR2_MAX_R; else pixel = 0;
844 d0ClipG: if (comp > YCBCR2_MAX_G) comp = YCBCR2_MAX_G; else comp = 0;
846 d0ClipB: if (comp > YCBCR2_MAX_B) comp = YCBCR2_MAX_B; else comp = 0;
848 d1ClipR: if (pixel > YCBCR2_MAX_R) pixel = YCBCR2_MAX_R; else pixel = 0;
850 d1ClipG: if (comp > YCBCR2_MAX_G) comp = YCBCR2_MAX_G; else comp = 0;
852 d1ClipB: if (comp > YCBCR2_MAX_B) comp = YCBCR2_MAX_B; else comp = 0;
854 d2ClipR: if (pixel > YCBCR2_MAX_R) pixel = YCBCR2_MAX_R; else pixel = 0;
856 d2ClipG: if (comp > YCBCR2_MAX_G) comp = YCBCR2_MAX_G; else comp = 0;
858 d2ClipB: if (comp > YCBCR2_MAX_B) comp = YCBCR2_MAX_B; else comp = 0;
860 d3ClipR: if (pixel > YCBCR2_MAX_R) pixel = YCBCR2_MAX_R; else pixel = 0;
862 d3ClipG: if (comp > YCBCR2_MAX_G) comp = YCBCR2_MAX_G; else comp = 0;
864 d3ClipB: if (comp > YCBCR2_MAX_B) comp = YCBCR2_MAX_B; else comp = 0;
868 /* ------------------------- ilSetupYCbCrDitherTable -------------------------- */
869 /* Setup the given YCbCr conversion table with values for converting YCbCr->RGB
870 with the dither values pre-multiplied into them.
872 static void ilSetupYCbCrDitherTable (
873 register ilRGBTransPtr pTrans,
878 double Lr, Lg, Lb, scaledY;
879 register double factor, gFactor, rbDither, gDither;
880 register int i, refBlack, upper, lower;
886 /* This function sets up the given translation table, similar to
887 ilGetYCbCrConvertTable(); see that function for more details. The difference
888 is that the multiplications done for dithering (i.e. by table lookup into
889 _ilMul4/8[]) are done into the values stored in the table.
890 For example, red is obtained from Y and Cr by:
891 red = (short)YTrans[Y] + (short)CrTrans[Cr] (1)
892 then red is dithered down to 4 levels by:
893 red = (pMul4[red] + kernel) >> 8; (2)
894 where "pMul4[i]" = i * (nLevels(4) - 1) * 256 / 255"; see /ilc/ildither.c
895 But if the values in the low-order short of YTrans and CrTrans are
896 premultiplied by "(nLevels - 1) * 256 / 255" then the lookup into pMul4[]
897 can be skipped, and step (2) above can be skipped.
899 pYCbCr = &pDes->typeInfo.YCbCr;
901 for (i = 0; i < 3; i++) {
902 sample[i].refBlack = pYCbCr->sample[i].refBlack;
903 sample[i].scale = ((i == 0) ? 255 : 127) /
904 (pYCbCr->sample[i].refWhite - pYCbCr->sample[i].refBlack);
907 /* Calc the Cb/Cr lookup tables, factoring in their scale factors. */
908 Lr = ((double)pYCbCr->lumaRed / (double)10000);
909 Lg = ((double)pYCbCr->lumaGreen / (double)10000);
910 Lb = ((double)pYCbCr->lumaBlue / (double)10000);
912 /* Calc the RGB dither multiply factors; R and B must be the same! */
913 rbDither = ((1 << YCBCR2_NR_BITS) - 1) * 256 / 255;
914 gDither = ((1 << YCBCR2_NG_BITS) - 1) * 256 / 255;
916 /* Y translation: lower is scaled Y, upper is value added to get green */
917 gFactor = (1 - Lb - Lr) / Lg;
918 for (i = 0; i < 256; i++) {
919 scaledY = sample[0].scale * i - sample[0].refBlack;
920 upper = scaledY * gFactor * gDither + 0.5;
921 lower = scaledY * rbDither;
922 pTrans->YTrans[i] = (upper << 16) | (lower & 0xffff);
925 /* Cb: lower is added to Y to get blue, upper added to get green */
926 factor = (2 - 2 * Lb) * sample[1].scale;
927 gFactor = -Lb * (2 - 2 * Lb) / Lg;
928 refBlack = sample[1].refBlack;
929 for (i = 0; i < 256; i++) {
930 upper = (i - refBlack) * gFactor * gDither + 0.5;
931 lower = (i - refBlack) * factor * rbDither + 0.5;
932 pTrans->CbTrans[i] = (upper << 16) | (lower & 0xffff);
935 /* Cr: lower is added to Y to get red, upper added to get green */
936 factor = (2 - 2 * Lr) * sample[2].scale;
937 gFactor = -Lr * (2 - 2 * Lr) / Lg;
938 refBlack = sample[2].refBlack;
939 for (i = 0; i < 256; i++) {
940 upper = (i - refBlack) * gFactor * gDither + 0.5;
941 lower = (i - refBlack) * factor * rbDither + 0.5;
942 pTrans->CrTrans[i] = (upper << 16) | (lower & 0xffff);
948 /* ---------------------------- _ilDitherYCbCr ----------------------------- */
949 /* Does conversions of some forms of YCbCr to dithered IL_PALETTE.
950 Returns "true" if conversion handled, else "false" if not handled or if error.
951 The pipe image must be an uncompressed YCbCr image.
953 IL_PRIVATE ilBool _ilDitherYCbCr (
957 ilImageFormat *pFormat,
959 ilConvertToPaletteInfo *pData
962 ilSrcElementData srcData;
963 ilDstElementData dstData;
965 ilYCbCr2DitherPrivPtr pPriv;
966 unsigned short *pPalette;
969 /* Check for case handled here: 8x8 area dither, levels 484 specified; pipe
970 image is 8 bit/comp YCbCr, subsampled by 2, even width and height.
972 if (((option != IL_CONVERT_TO_PALETTE) && (option != 0))
974 || (pData->method != IL_AREA_DITHER)
975 || (pData->levels[0] != 4)
976 || (pData->levels[1] != 8)
977 || (pData->levels[0] != 4)
978 || (pData->kernelSize != 8)
979 || (pFormat->sampleOrder == IL_SAMPLE_PIXELS)
980 || (pFormat->nBitsPerSample[0] != 8)
981 || (pFormat->nBitsPerSample[1] != 8)
982 || (pFormat->nBitsPerSample[2] != 8)
983 || (pDes->typeInfo.YCbCr.sample[0].subsampleHoriz != 1)
984 || (pDes->typeInfo.YCbCr.sample[0].subsampleVert != 1)
985 || (pDes->typeInfo.YCbCr.sample[1].subsampleHoriz != 2)
986 || (pDes->typeInfo.YCbCr.sample[1].subsampleVert != 2)
987 || (pDes->typeInfo.YCbCr.sample[2].subsampleHoriz != 2)
988 || (pDes->typeInfo.YCbCr.sample[2].subsampleVert != 2)
989 || ((pInfo->width | pInfo->height) & 1)) { /* width or height odd */
990 pipe->context->error = 0; /* can't handle; not an error */
994 /* If mapImage given, validate it and point to its pixels. If not given,
995 pTranslate becomes null and will point to "identity" mapImage below.
997 pTranslate = (ilPtr)NULL;
998 if (pData->mapImage) {
1000 if (!ilQueryClientImage (pData->mapImage, &pInfo, 0)
1001 || (pInfo->width != 256) || (pInfo->height != 1)
1002 || (pInfo->pDes->compression != IL_UNCOMPRESSED)
1003 || (pInfo->pDes->nSamplesPerPixel != 1)
1004 || (pInfo->pFormat->nBitsPerSample[0] != 8))
1005 return ilDeclarePipeInvalid (pipe, IL_ERROR_MAP_IMAGE);
1006 pTranslate = pInfo->plane[0].pPixels;
1009 /* alloc pPalette unless not palette dst; init with ramp if not choosing */
1010 pPalette = (unsigned short *)NULL;
1011 if (pData->dstType == IL_PALETTE) {
1012 register int red, green, blue;
1013 register int redLevel, greenLevel, blueLevel;
1014 register unsigned short *pPal;
1016 pPalette = (unsigned short *)IL_MALLOC_ZERO (3 * 256 * sizeof(unsigned short));
1018 return ilDeclarePipeInvalid (pipe, IL_ERROR_MALLOC);
1020 for (red = 0; red < pData->levels[0]; red++) {
1021 redLevel = 65535 * red / (pData->levels[0] - 1);
1022 for (green = 0; green < pData->levels[1]; green++) {
1023 greenLevel = 65535 * green / (pData->levels[1] - 1);
1024 for (blue = 0; blue < pData->levels[2]; blue++) {
1025 blueLevel = 65535 * blue / (pData->levels[2] - 1);
1026 pPal [0] = redLevel;
1027 pPal [256] = greenLevel;
1028 pPal [512] = blueLevel;
1035 /* Add element to the pipe, init private. Accept strips as they are;
1036 presumably they will be even # lines because image is subsampled.
1038 srcData.consumerImage = (ilObject)NULL;
1039 srcData.stripHeight = pInfo->stripHeight;
1040 srcData.constantStrip = FALSE;
1041 srcData.minBufferHeight = 0;
1043 dstData.producerObject = (ilObject)NULL;
1045 des.type = pData->dstType;
1046 if (des.type == IL_PALETTE) {
1047 des.flags = IL_DITHERED_PALETTE;
1048 des.typeInfo.palette.levels[0] = pData->levels[0];
1049 des.typeInfo.palette.levels[1] = pData->levels[1];
1050 des.typeInfo.palette.levels[2] = pData->levels[2];
1052 dstData.pDes = &des;
1053 dstData.pFormat = IL_FORMAT_BYTE;
1054 dstData.width = pInfo->width;
1055 dstData.height = pInfo->height;
1056 dstData.stripHeight = 0;
1057 dstData.constantStrip = FALSE;
1058 dstData.pPalette = pPalette;
1060 pPriv = (ilYCbCr2DitherPrivPtr)ilAddPipeElement (pipe, IL_FILTER,
1061 sizeof(ilYCbCr2DitherPrivRec), 0, &srcData, &dstData,
1062 ilYCbCr2DitherInit, IL_NPF, ilYCbCr2DitherDestroy, ilYCbCr2DitherExecute, NULL, 0);
1064 if (pPriv->pPalette)
1065 IL_FREE (pPriv->pPalette);
1069 /* Init pPriv; point pTranslate to identity image if no mapImage given */
1071 pPriv->pTranslate = pTranslate;
1074 pPriv->pTranslate = pPriv->translate;
1075 for (i = 0; i < 256; i++)
1076 pPriv->translate[i] = i;
1078 pPriv->pPalette = pPalette;
1080 /* Init tables for YCbCr->RGB conversion plus dithering */
1081 ilSetupYCbCrDitherTable (&pPriv->trans, pDes);
1083 /* Update pipe info and return */
1084 ilGetPipeInfo (pipe, FALSE, pInfo, pDes, pFormat);
1090 /* ======================= RGB To YCbCr Code =================================== */
1092 /* # of bits of fixed point precision for interim values during conversion */
1095 /* Private for RGB to YCbCr filter. For each component to be calculated (Y/Cb/Cr),
1096 a table indexed by the src component (R/G/B) which gives the contribution
1097 for that src component, in fixed point: <32-PR2Y bits>.<PR2Y bits>
1100 long YR[256], YG[256], YB[256]; /* component lookup tables */
1101 long CbR[256], CbG[256], CbB[256];
1102 long CrR[256], CrG[256], CrB[256];
1103 long YRefBlack, CbRefBlack, CrRefBlack; /* component reference black */
1104 } ilRGBToYCbCrPrivRec, *ilRGBToYCbCrPrivPtr;
1106 /* Macro to do floor/ceiling of given value: makes it 0..255.
1107 Shift right by 8; if not zero, is < 0 or > 255; handle those cases.
1109 #define BYTE_RANGE(_pixel) { \
1110 if (_pixel & ~0xff) \
1111 if ((_pixel) < 0) _pixel = 0; \
1112 else _pixel = 255; \
1116 /* ----------------------- ilExecuteRGBToYCbCr -------------------------------- */
1117 /* Execute(): convert _pixel_ src RGB to _planar_ dst YCbCr.
1119 static ilError ilExecuteRGBToYCbCr (
1120 ilExecuteData *pData,
1125 register ilRGBToYCbCrPrivPtr pPriv;
1126 ilPtr pSrcLine, pYLine, pCbLine, pCrLine;
1127 register ilPtr pSrc, pY, pCb, pCr;
1128 register long nPixelsM1;
1129 register long YRefBlack, CbRefBlack, CrRefBlack;
1130 long nPixelsM1Init, nLinesM1;
1131 long YRowBytes, CbRowBytes, CrRowBytes, srcRowBytes;
1132 ilImagePlaneInfo *pPlane;
1133 register long R, G, B, pixel;
1136 /* Set nPixels/LinesM1 to # pixels / lines - 1; exit if either 0. */
1137 pPriv = (ilRGBToYCbCrPrivPtr)pData->pPrivate;
1138 nPixelsM1Init = pData->pSrcImage->width;
1139 if (nPixelsM1Init <= 0)
1142 nLinesM1 = *pNLines;
1147 /* Point pSrcLine to first line of src RGB (pixel-order) data; point
1148 pY/Cb/CrLine to 1st line in dst YCbCr (planar-order) data planes.
1149 Get bytes/row for each of them.
1151 pPlane = pData->pSrcImage->plane;
1152 srcRowBytes = pPlane->nBytesPerRow;
1153 pSrcLine = pPlane->pPixels + pData->srcLine * srcRowBytes;
1155 pPlane = pData->pDstImage->plane;
1156 YRowBytes = pPlane->nBytesPerRow;
1157 pYLine = pPlane->pPixels + dstLine * YRowBytes;
1159 CbRowBytes = pPlane->nBytesPerRow;
1160 pCbLine = pPlane->pPixels + dstLine * CbRowBytes;
1162 CrRowBytes = pPlane->nBytesPerRow;
1163 pCrLine = pPlane->pPixels + dstLine * CrRowBytes;
1165 /* Load component refBlack values, plus 1/2 shift (precision) amt for rounding
1166 into values, shifted up so it can be added before right shift.
1168 YRefBlack = (pPriv->YRefBlack << PR2Y) + (1 << (PR2Y - 1));
1169 CbRefBlack = (pPriv->CbRefBlack << PR2Y) + (1 << (PR2Y - 1));
1170 CrRefBlack = (pPriv->CrRefBlack << PR2Y) + (1 << (PR2Y - 1));
1172 /* Convert pixel RGB to planar YCbCr. */
1175 pSrcLine += srcRowBytes;
1177 pYLine += YRowBytes;
1179 pCbLine += CbRowBytes;
1181 pCrLine += CrRowBytes;
1183 nPixelsM1 = nPixelsM1Init;
1189 pixel = (pPriv->YR[R] + pPriv->YG[G] + pPriv->YB[B] + YRefBlack) >> PR2Y;
1190 if (pixel >> 8) goto YClip;
1191 YClipped: *pY++ = pixel;
1193 pixel = (pPriv->CbR[R] + pPriv->CbG[G] + pPriv->CbB[B] + CbRefBlack) >> PR2Y;
1194 if (pixel >> 8) goto CbClip;
1195 CbClipped: *pCb++ = pixel;
1197 pixel = (pPriv->CrR[R] + pPriv->CrG[G] + pPriv->CrB[B] + CrRefBlack) >> PR2Y;
1198 if (pixel >> 8) goto CrClip;
1199 CrClipped: *pCr++ = pixel;
1201 } while (--nPixelsM1 >= 0);
1202 } while (--nLinesM1 >= 0);
1206 /* goto point for when Y/Cb/Cr out of range: clamp pixel and go back and continue.
1207 This is done to avoid taking a branch in the most common case: not out of range.
1209 YClip: if (pixel > 255) pixel = 255; else pixel = 0;
1211 CbClip: if (pixel > 255) pixel = 255; else pixel = 0;
1213 CrClip: if (pixel > 255) pixel = 255; else pixel = 0;
1217 /* ---------------------------- ilConvertRGBToYCbCr ----------------------------- */
1218 /* Convert from source type (pDes->type) == RGB to YCbCr.
1219 pFormat points to the source format; on return, *pFormat is updated
1220 to the dst format. pNewDes points to the dst dest; *pDes to the src (pipe) des;
1221 on return it is updated to the new descriptor.
1223 IL_PRIVATE ilBool _ilConvertRGBToYCbCr (
1226 register ilImageDes *pDes,
1227 register const ilImageDes *pNewDes,
1228 ilImageFormat *pFormat
1231 register ilRGBToYCbCrPrivPtr pPriv;
1232 register ilYCbCrInfo *pYCbCr;
1233 ilDstElementData dstData;
1234 double Lr, Lg, Lb, range;
1240 /* Get format = planar order, 8 bits / pixel, or error */
1241 if ((pFormat->nBitsPerSample[0] != 8)
1242 || (pFormat->nBitsPerSample[1] != 8)
1243 || (pFormat->nBitsPerSample[2] != 8)
1244 || (pFormat->sampleOrder != IL_SAMPLE_PIXELS)) {
1245 if (!ilConvert (pipe, (ilImageDes *)NULL, IL_FORMAT_3BYTE_PIXEL, 0, NULL))
1249 /* Add filter to write 3 planar YCbCr format image. Update pDes: std YCbCr but
1250 with caller's sample refBlack/White and lumaRed/Green/Blue.
1252 *pDes = *IL_DES_YCBCR;
1253 pDes->typeInfo.YCbCr.sample[0].refBlack = pNewDes->typeInfo.YCbCr.sample[0].refBlack;
1254 pDes->typeInfo.YCbCr.sample[0].refWhite = pNewDes->typeInfo.YCbCr.sample[0].refWhite;
1255 pDes->typeInfo.YCbCr.sample[1].refBlack = pNewDes->typeInfo.YCbCr.sample[1].refBlack;
1256 pDes->typeInfo.YCbCr.sample[1].refWhite = pNewDes->typeInfo.YCbCr.sample[1].refWhite;
1257 pDes->typeInfo.YCbCr.sample[2].refBlack = pNewDes->typeInfo.YCbCr.sample[2].refBlack;
1258 pDes->typeInfo.YCbCr.sample[2].refWhite = pNewDes->typeInfo.YCbCr.sample[2].refWhite;
1259 pDes->typeInfo.YCbCr.lumaRed = pNewDes->typeInfo.YCbCr.lumaRed;
1260 pDes->typeInfo.YCbCr.lumaGreen = pNewDes->typeInfo.YCbCr.lumaGreen;
1261 pDes->typeInfo.YCbCr.lumaBlue = pNewDes->typeInfo.YCbCr.lumaBlue;
1263 *pFormat = *IL_FORMAT_3BYTE_PLANE;
1264 dstData.producerObject = (ilObject)NULL;
1265 dstData.pDes = pDes;
1266 dstData.pFormat = pFormat;
1267 dstData.width = pInfo->width;
1268 dstData.height = pInfo->height;
1269 dstData.stripHeight = 0;
1270 dstData.constantStrip = FALSE;
1271 dstData.pPalette = (unsigned short *)NULL;
1272 pPriv = (ilRGBToYCbCrPrivPtr)ilAddPipeElement (pipe, IL_FILTER,
1273 sizeof(ilRGBToYCbCrPrivRec), 0, (ilSrcElementData *)NULL, &dstData,
1274 IL_NPF, IL_NPF, IL_NPF, ilExecuteRGBToYCbCr, NULL, 0);
1278 /* See Appendix O pg 3 of TIFF spec. Use fixed point (16.16) for
1279 floating point values.
1280 Y = Lr*R + Lg*G + Lb*B
1281 Cb = (B - Y) / (2-2*Lb)
1282 = (B - Lr*R - Lg*G - Lb*B) / (2-2*Lb)
1283 = R * -Lr/(2-2*Lb) + G * -Lg/(2-2*Lb) + B * (1-Lb)/(2-2*Lb)
1284 Cr = (R - Y) / (2-2*Lr)
1285 = (R - Lr*R - Lg*G - Lb*B) / (2-2*Lr)
1286 = R * (1-Lr)/(2-2*Lr) + G * -Lg/(2-2*Lr) + B * -Lb/(2-2*Lr)
1287 In each case, the scale up to account for the scaling range is done
1288 by multiplying the scaling range into each RGB factor. The refBlack is
1289 then added (not shown above). Each of the values multiplied times R/G/B
1290 is called "Y/Cb/Cr|R/G/B".
1292 pYCbCr = &pDes->typeInfo.YCbCr;
1293 Lr = (double)pYCbCr->lumaRed / 10000;
1294 Lg = (double)pYCbCr->lumaGreen / 10000;
1295 Lb = (double)pYCbCr->lumaBlue / 10000;
1297 /* Y R/G/B multiples, plus refBlack. */
1298 range = (1 << PR2Y) * (double)(pYCbCr->sample[0].refWhite - pYCbCr->sample[0].refBlack) / 255;
1299 YR = range * Lr + 0.5;
1300 YG = range * Lg + 0.5;
1301 YB = range * Lb + 0.5;
1302 pPriv->YRefBlack = pYCbCr->sample[0].refBlack;
1304 /* Cb and Cr multiples, refBlack. Note coding range for Cb/Cr == 127. */
1305 range = (1 << PR2Y) * (double)(pYCbCr->sample[1].refWhite - pYCbCr->sample[1].refBlack) / 127;
1306 CbR = range * -Lr/(2-2*Lb) + 0.5;
1307 CbG = range * -Lg/(2-2*Lb) + 0.5;
1308 CbB = range * (1-Lb)/(2-2*Lb) + 0.5;
1309 pPriv->CbRefBlack = pYCbCr->sample[1].refBlack;
1311 range = (1 << PR2Y) * (double)(pYCbCr->sample[2].refWhite - pYCbCr->sample[2].refBlack) / 127;
1312 CrR = range * (1-Lr)/(2-2*Lr) + 0.5;
1313 CrG = range * -Lg/(2-2*Lr) + 0.5;
1314 CrB = range * -Lb/(2-2*Lr) + 0.5;
1315 pPriv->CrRefBlack = pYCbCr->sample[2].refBlack;
1317 /* Build lookup table which is the result of multiplying the above by 0..255,
1318 i.e. the source RGB values. Using this lookup table is equivalent to multiply
1319 but a whole lot faster.
1321 for (i = 0; i < 256; i++) {
1322 pPriv->YR[i] = YR * i;
1323 pPriv->YG[i] = YG * i;
1324 pPriv->YB[i] = YB * i;
1325 pPriv->CbR[i] = CbR * i;
1326 pPriv->CbG[i] = CbG * i;
1327 pPriv->CbB[i] = CbB * i;
1328 pPriv->CrR[i] = CrR * i;
1329 pPriv->CrG[i] = CrG * i;
1330 pPriv->CrB[i] = CrB * i;