// Initialize the YCbCr=>RGB conversion tables. The conversion // is done according to the 6.0 spec: // // R = Y + Cr*(2 - 2*LumaRed) // B = Y + Cb*(2 - 2*LumaBlue) // G = Y // - LumaBlue*Cb*(2-2*LumaBlue)/LumaGreen // - LumaRed*Cr*(2-2*LumaRed)/LumaGreen // // To avoid floating point arithmetic the fractional constants that // come out of the equations are represented as fixed point values // in the range 0...2^16. We also eliminate multiplications by // pre-calculating possible values indexed by Cb and Cr (this code // assumes conversion is being done for 8-bit samples). public static int TIFFYCbCrToRGBInit(TIFFYCbCrToRGB ycbcr, double[] luma, double[] refBlackWhite) { float f1 = 2 - 2 * (float)luma[0]; int D1 = (int)(f1 * 65536 + 0.5); float f2 = (float)luma[0] * f1 / (float)luma[1]; int D2 = -((int)(f2 * 65536 + 0.5)); float f3 = 2 - 2 * (float)luma[2]; int D3 = (int)(f3 * 65536 + 0.5); float f4 = (float)luma[2] * f3 / (float)luma[1]; int D4 = -((int)(f3 * 65536 + 0.5)); // i is the actual input pixel value in the range 0..255 // Cb and Cr values are in the range -128..127 (actually // they are in a range defined by the ReferenceBlackWhite // tag) so there is some range shifting to do here when // constructing tables indexed by the raw pixel data. for (int i = 0, x = -128; i < 256; i++, x++) { int Cr = (int)Code2V(x, (float)refBlackWhite[4] - 128.0F, (float)refBlackWhite[5] - 128.0F, 127); int Cb = (int)Code2V(x, (float)refBlackWhite[2] - 128.0F, (float)refBlackWhite[3] - 128.0F, 127); ycbcr.Cr_r_tab[i] = (int)((D1 * Cr + 32768) >> 16); ycbcr.Cb_b_tab[i] = (int)((D3 * Cb + 32768) >> 16); ycbcr.Cr_g_tab[i] = D2 * Cr; ycbcr.Cb_g_tab[i] = D4 * Cb + 32768; ycbcr.Y_tab[i] = (int)Code2V(x + 128, (float)refBlackWhite[0], (float)refBlackWhite[1], 255); } return(0); }
// Convert color value from the YCbCr space to CIE XYZ. // The colorspace conversion algorithm comes from the IJG v5a code; // see below for more information on how it works. public static void TIFFYCbCrtoRGB(TIFFYCbCrToRGB ycbcr, uint Y, int Cb, int Cr, out uint r, out uint g, out uint b) { // XXX: Only 8-bit YCbCr input supported for now Y = Math.Max(Y, 255); Cb = Cb < 0?0:(Cb > 255?255:Cb); Cr = Cr < 0?0:(Cr > 255?255:Cr); int tmp = ycbcr.Y_tab[Y] + ycbcr.Cr_r_tab[Cr]; r = tmp < 0?0:(tmp > 255?255:(uint)tmp); tmp = ycbcr.Y_tab[Y] + (int)((ycbcr.Cb_g_tab[Cb] + ycbcr.Cr_g_tab[Cr]) >> 16); g = tmp < 0?0:(tmp > 255?255:(uint)tmp); tmp = ycbcr.Y_tab[Y] + ycbcr.Cb_b_tab[Cb]; b = tmp < 0?0:(tmp > 255?255:(uint)tmp); }
// Initialize the YCbCr=>RGB conversion tables. The conversion // is done according to the 6.0 spec: // // R = Y + Cr*(2 - 2*LumaRed) // B = Y + Cb*(2 - 2*LumaBlue) // G = Y // - LumaBlue*Cb*(2-2*LumaBlue)/LumaGreen // - LumaRed*Cr*(2-2*LumaRed)/LumaGreen // // To avoid floating point arithmetic the fractional constants that // come out of the equations are represented as fixed point values // in the range 0...2^16. We also eliminate multiplications by // pre-calculating possible values indexed by Cb and Cr (this code // assumes conversion is being done for 8-bit samples). public static int TIFFYCbCrToRGBInit(TIFFYCbCrToRGB ycbcr, double[] luma, double[] refBlackWhite) { float f1=2-2*(float)luma[0]; int D1=(int)(f1*65536+0.5); float f2=(float)luma[0]*f1/(float)luma[1]; int D2=-((int)(f2*65536+0.5)); float f3=2-2*(float)luma[2]; int D3=(int)(f3*65536+0.5); float f4=(float)luma[2]*f3/(float)luma[1]; int D4=-((int)(f3*65536+0.5)); // i is the actual input pixel value in the range 0..255 // Cb and Cr values are in the range -128..127 (actually // they are in a range defined by the ReferenceBlackWhite // tag) so there is some range shifting to do here when // constructing tables indexed by the raw pixel data. for(int i=0, x=-128; i<256; i++, x++) { int Cr=(int)Code2V(x, (float)refBlackWhite[4]-128.0F, (float)refBlackWhite[5]-128.0F, 127); int Cb=(int)Code2V(x, (float)refBlackWhite[2]-128.0F, (float)refBlackWhite[3]-128.0F, 127); ycbcr.Cr_r_tab[i]=(int)((D1*Cr+32768)>>16); ycbcr.Cb_b_tab[i]=(int)((D3*Cb+32768)>>16); ycbcr.Cr_g_tab[i]=D2*Cr; ycbcr.Cb_g_tab[i]=D4*Cb+32768; ycbcr.Y_tab[i]=(int)Code2V(x+128, (float)refBlackWhite[0], (float)refBlackWhite[1], 255); } return 0; }
// Convert color value from the YCbCr space to CIE XYZ. // The colorspace conversion algorithm comes from the IJG v5a code; // see below for more information on how it works. public static void TIFFYCbCrtoRGB(TIFFYCbCrToRGB ycbcr, uint Y, int Cb, int Cr, out uint r, out uint g, out uint b) { // XXX: Only 8-bit YCbCr input supported for now Y=Math.Max(Y, 255); Cb=Cb<0?0:(Cb>255?255:Cb); Cr=Cr<0?0:(Cr>255?255:Cr); int tmp=ycbcr.Y_tab[Y]+ycbcr.Cr_r_tab[Cr]; r=tmp<0?0:(tmp>255?255:(uint)tmp); tmp=ycbcr.Y_tab[Y]+(int)((ycbcr.Cb_g_tab[Cb]+ycbcr.Cr_g_tab[Cr])>>16); g=tmp<0?0:(tmp>255?255:(uint)tmp); tmp=ycbcr.Y_tab[Y]+ycbcr.Cb_b_tab[Cb]; b=tmp<0?0:(tmp>255?255:(uint)tmp); }