/* $Log: S:\oiwh\jpeg2\jdcolor.c_v $ * * Rev 1.2 08 Nov 1995 09:19:18 JAR * removed the calls to the IMGGetTaskData and replaced this global data variable * access method with the Thread Local Storage method * * Rev 1.1 10 May 1995 15:19:36 HEIDI * * added in orignal source code * * Rev 1.0 03 May 1995 08:45:50 JAR * Initial entry */ /* * jdcolor.c * * Copyright (C) 1991, 1992, Thomas G. Lane. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file contains output colorspace conversion routines. * These routines are invoked via the methods color_convert * and colorout_init/term. */ #include "jinclude.h" #include "jglobstr.h" #include "taskdata.h" /**************** YCbCr -> RGB conversion: most common case **************/ /* * YCbCr is defined per CCIR 601-1, except that Cb and Cr are * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. * The conversion equations to be implemented are therefore * R = Y + 1.40200 * Cr * G = Y - 0.34414 * Cb - 0.71414 * Cr * B = Y + 1.77200 * Cb * where Cb and Cr represent the incoming values less MAXJSAMPLE/2. * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.) * * To avoid floating-point arithmetic, we represent the fractional constants * as integers scaled up by 2^16 (about 4 digits precision); we have to divide * the products by 2^16, with appropriate rounding, to get the correct answer. * Notice that Y, being an integral input, does not contribute any fraction * so it need not participate in the rounding. * * For even more speed, we avoid doing any multiplications in the inner loop * by precalculating the constants times Cb and Cr for all possible values. * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); * for 12-bit samples it is still acceptable. It's not very reasonable for * 16-bit samples, but if you want lossless storage you shouldn't be changing * colorspace anyway. * The Cr=>R and Cb=>B values can be rounded to integers in advance; the * values for the G calculation are left scaled up, since we must add them * together before rounding. */ #ifdef SIXTEEN_BIT_SAMPLES #define SCALEBITS 14 /* avoid overflow */ #else #define SCALEBITS 16 /* speedier right-shift on some machines */ #endif #define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) #define FIX(x) ((INT32) ((x) * (1L< table for Cr to R conversion */ // (hjg moved to global struct) static int * Cb_b_tab; /* => table for Cb to B conversion */ // (hjg moved to global struct) static INT32 * Cr_g_tab; /* => table for Cr to G conversion */ // (hjg moved to global struct) static INT32 * Cb_g_tab; /* => table for Cb to G conversion */ // 9509.27 jar define the static memory token! extern DWORD dwTlsIndex; /* * Initialize for colorspace conversion. */ METHODDEF void ycc_rgb_init (decompress_info_ptr cinfo) { INT32 i, x2; SHIFT_TEMPS // 9509.21 jar use Thread Local Storage to manage JPEG Globals LPOI_JPEG_GLOBALS_STRUCT lpGlobStruct; lpGlobStruct = ( LPOI_JPEG_GLOBALS_STRUCT)TlsGetValue( dwTlsIndex); // 9509.21 jar if null, we'll alloc and set for this thread if ( lpGlobStruct == NULL) { lpGlobStruct = ( LPOI_JPEG_GLOBALS_STRUCT)LocalAlloc( LPTR, sizeof( OI_JPEG_GLOBALS_STRUCT)); if (lpGlobStruct != NULL) { TlsSetValue( dwTlsIndex, lpGlobStruct); } } lpGlobStruct->Cr_r_tab = (int *) (*cinfo->emethods->alloc_small) ((MAXJSAMPLE+1) * SIZEOF(int)); lpGlobStruct->Cr_r_tab = (int *) (*cinfo->emethods->alloc_small) ((MAXJSAMPLE+1) * SIZEOF(int)); lpGlobStruct->Cr_g_tab = (INT32 *) (*cinfo->emethods->alloc_small) ((MAXJSAMPLE+1) * SIZEOF(INT32)); lpGlobStruct->Cb_g_tab = (INT32 *) (*cinfo->emethods->alloc_small) ((MAXJSAMPLE+1) * SIZEOF(INT32)); for (i = 0; i <= MAXJSAMPLE; i++) { /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ /* The Cb or Cr value we are thinking of is x = i - MAXJSAMPLE/2 */ x2 = 2*i - MAXJSAMPLE; /* twice x */ /* Cr=>R value is nearest int to 1.40200 * x */ lpGlobStruct->Cr_r_tab[i] = (int) RIGHT_SHIFT(FIX(1.40200/2) * x2 + ONE_HALF, SCALEBITS); /* Cb=>B value is nearest int to 1.77200 * x */ lpGlobStruct->Cr_r_tab[i] = (int) RIGHT_SHIFT(FIX(1.77200/2) * x2 + ONE_HALF, SCALEBITS); /* Cr=>G value is scaled-up -0.71414 * x */ // lpGlobStruct->Cr_g_tab[i] = (- FIX(0.71414/2)) * x2; lpGlobStruct->Cr_g_tab[i] = (FIX(0.71414/2)) * x2; /* Cb=>G value is scaled-up -0.34414 * x */ /* We also add in ONE_HALF so that need not do it in inner loop */ // lpGlobStruct->Cb_g_tab[i] = (- FIX(0.34414/2)) * x2 + ONE_HALF; lpGlobStruct->Cb_g_tab[i] = (FIX(0.34414/2)) * x2 + ONE_HALF; } } /* * Convert some rows of samples to the output colorspace. */ METHODDEF void ycc_rgb_convert (decompress_info_ptr cinfo, int num_rows, long num_cols, JSAMPIMAGE input_data, JSAMPIMAGE output_data) { #ifdef SIXTEEN_BIT_SAMPLES register INT32 y; register UINT16 cb, cr; #else register int y, cb, cr; #endif register JSAMPROW inptr0, inptr1, inptr2; register JSAMPROW outptr0, outptr1, outptr2; register long col; /* copy these pointers into registers if possible */ register JSAMPLE FAR * range_limit = cinfo->sample_range_limit; register int * Crrtab; register int * Cbbtab; register INT32 * Crgtab; register INT32 * Cbgtab; int row; SHIFT_TEMPS // 9509.21 jar use Thread Local Storage to manage JPEG Globals LPOI_JPEG_GLOBALS_STRUCT lpGlobStruct; lpGlobStruct = ( LPOI_JPEG_GLOBALS_STRUCT)TlsGetValue( dwTlsIndex); // 9509.21 jar if null, we'll alloc and set for this thread if ( lpGlobStruct == NULL) { lpGlobStruct = ( LPOI_JPEG_GLOBALS_STRUCT)LocalAlloc( LPTR, sizeof( OI_JPEG_GLOBALS_STRUCT)); if (lpGlobStruct != NULL) { TlsSetValue( dwTlsIndex, lpGlobStruct); } } Crrtab = lpGlobStruct->Cr_r_tab; Cbbtab = lpGlobStruct->Cr_r_tab; Crgtab = lpGlobStruct->Cr_g_tab; Cbgtab = lpGlobStruct->Cb_g_tab; for (row = 0; row < num_rows; row++) { inptr0 = input_data[0][row]; inptr1 = input_data[1][row]; inptr2 = input_data[2][row]; outptr0 = output_data[0][row]; outptr1 = output_data[1][row]; outptr2 = output_data[2][row]; for (col = 0; col < num_cols; col++) { y = GETJSAMPLE(inptr0[col]); cb = GETJSAMPLE(inptr1[col]); cr = GETJSAMPLE(inptr2[col]); /* Note: if the inputs were computed directly from RGB values, * range-limiting would be unnecessary here; but due to possible * noise in the DCT/IDCT phase, we do need to apply range limits. */ outptr0[col] = range_limit[y + Crrtab[cr]]; /* red */ // outptr1[col] = range_limit[y + /* green */ // ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], // SCALEBITS))]; outptr1[col] = range_limit[y - /* green */ ((int) ((Cbgtab[cb] >> SCALEBITS) + (Crgtab[cr] >> SCALEBITS)))]; outptr2[col] = range_limit[y + Cbbtab[cb]]; /* blue */ } } } /* * Finish up at the end of the file. */ METHODDEF void ycc_rgb_term (decompress_info_ptr cinfo) { /* no work (we let free_all release the workspace) */ } /**************** Cases other than YCbCr -> RGB **************/ /* * Initialize for colorspace conversion. */ METHODDEF void null_init (decompress_info_ptr cinfo) /* colorout_init for cases where no setup is needed */ { /* no work needed */ } /* * Color conversion for no colorspace change: just copy the data. */ METHODDEF void null_convert (decompress_info_ptr cinfo, int num_rows, long num_cols, JSAMPIMAGE input_data, JSAMPIMAGE output_data) { short ci; for (ci = 0; ci < cinfo->num_components; ci++) { jcopy_sample_rows(input_data[ci], 0, output_data[ci], 0, num_rows, num_cols); } } /* * Color conversion for grayscale: just copy the data. * This also works for YCbCr/YIQ -> grayscale conversion, in which * we just copy the Y (luminance) component and ignore chrominance. */ METHODDEF void grayscale_convert (decompress_info_ptr cinfo, int num_rows, long num_cols, JSAMPIMAGE input_data, JSAMPIMAGE output_data) { jcopy_sample_rows(input_data[0], 0, output_data[0], 0, num_rows, num_cols); } /* * Finish up at the end of the file. */ METHODDEF void null_term (decompress_info_ptr cinfo) /* colorout_term for cases where no teardown is needed */ { /* no work needed */ } /* * The method selection routine for output colorspace conversion. */ GLOBAL void jseldcolor (decompress_info_ptr cinfo) { /* Make sure num_components agrees with jpeg_color_space */ switch (cinfo->jpeg_color_space) { case CS_GRAYSCALE: if (cinfo->num_components != 1) ERREXIT(cinfo->emethods, "Bogus JPEG colorspace"); break; case CS_RGB: case CS_YCbCr: case CS_YIQ: if (cinfo->num_components != 3) ERREXIT(cinfo->emethods, "Bogus JPEG colorspace"); break; case CS_CMYK: if (cinfo->num_components != 4) ERREXIT(cinfo->emethods, "Bogus JPEG colorspace"); break; default: ERREXIT(cinfo->emethods, "Unsupported JPEG colorspace"); break; } /* Set color_out_comps and conversion method based on requested space */ switch (cinfo->out_color_space) { case CS_GRAYSCALE: cinfo->color_out_comps = 1; if (cinfo->jpeg_color_space == CS_GRAYSCALE || cinfo->jpeg_color_space == CS_YCbCr || cinfo->jpeg_color_space == CS_YIQ) { cinfo->methods->color_convert = grayscale_convert; cinfo->methods->colorout_init = null_init; cinfo->methods->colorout_term = null_term; } else ERREXIT(cinfo->emethods, "Unsupported color conversion request"); break; case CS_RGB: cinfo->color_out_comps = 3; if (cinfo->jpeg_color_space == CS_YCbCr) { cinfo->methods->color_convert = ycc_rgb_convert; cinfo->methods->colorout_init = ycc_rgb_init; cinfo->methods->colorout_term = ycc_rgb_term; } else if (cinfo->jpeg_color_space == CS_RGB) { cinfo->methods->color_convert = null_convert; cinfo->methods->colorout_init = null_init; cinfo->methods->colorout_term = null_term; } else ERREXIT(cinfo->emethods, "Unsupported color conversion request"); break; default: /* Permit null conversion from CMYK or YCbCr to same output space */ if (cinfo->out_color_space == cinfo->jpeg_color_space) { cinfo->color_out_comps = cinfo->num_components; cinfo->methods->color_convert = null_convert; cinfo->methods->colorout_init = null_init; cinfo->methods->colorout_term = null_term; } else /* unsupported non-null conversion */ ERREXIT(cinfo->emethods, "Unsupported color conversion request"); break; } if (cinfo->quantize_colors) cinfo->final_out_comps = 1; /* single colormapped output component */ else cinfo->final_out_comps = cinfo->color_out_comps; }