/* * jdcolor.c * * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1997, Thomas G. Lane. * Modified 2011 by Guido Vollbeding. * libjpeg-turbo Modifications: * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB * Copyright (C) 2009, 2011-2012, 2014-2015, 2022, D. R. Commander. * Copyright (C) 2013, Linaro Limited. * For conditions of distribution and use, see the accompanying README.ijg * file. * * This file contains output colorspace conversion routines.
*/
typedefstruct { struct jpeg_color_deconverter pub; /* public fields */
#if BITS_IN_JSAMPLE != 16 /* Private state for YCC->RGB conversion */ int *Cr_r_tab; /* => table for Cr to R conversion */ int *Cb_b_tab; /* => table for Cb to B conversion */
JLONG *Cr_g_tab; /* => table for Cr to G conversion */
JLONG *Cb_g_tab; /* => table for Cb to G conversion */
/* Private state for RGB->Y conversion */
JLONG *rgb_y_tab; /* => table for RGB to Y conversion */ #endif
} my_color_deconverter;
typedef my_color_deconverter *my_cconvert_ptr;
/**************** YCbCr -> RGB conversion: most common case **************/ /**************** RGB -> Y conversion: less 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 * * Y = 0.29900 * R + 0.58700 * G + 0.11400 * B * * where Cb and Cr represent the incoming values less _CENTERJSAMPLE. * (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 samples 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.
*/
/* We allocate one big table for RGB->Y conversion and divide it up into * three parts, instead of doing three alloc_small requests. This lets us * use a single table base address, which can be held in a register in the * inner loops on many machines (more than can hold all three addresses, * anyway).
*/
#define R_Y_OFF 0 /* offset to R => Y section */ #define G_Y_OFF (1 * (_MAXJSAMPLE + 1)) /* offset to G => Y section */ #define B_Y_OFF (2 * (_MAXJSAMPLE + 1)) /* etc. */ #define TABLE_SIZE (3 * (_MAXJSAMPLE + 1))
/* Include inline routines for colorspace extensions */
for (i = 0, x = -_CENTERJSAMPLE; i <= _MAXJSAMPLE; i++, x++) { /* i is the actual input pixel value, in the range 0.._MAXJSAMPLE */ /* The Cb or Cr value we are thinking of is x = i - _CENTERJSAMPLE */ /* Cr=>R value is nearest int to 1.40200 * x */
cconvert->Cr_r_tab[i] = (int)
RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS); /* Cb=>B value is nearest int to 1.77200 * x */
cconvert->Cb_b_tab[i] = (int)
RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS); /* Cr=>G value is scaled-up -0.71414 * x */
cconvert->Cr_g_tab[i] = (-FIX(0.71414)) * x; /* Cb=>G value is scaled-up -0.34414 * x */ /* We also add in ONE_HALF so that need not do it in inner loop */
cconvert->Cb_g_tab[i] = (-FIX(0.34414)) * x + ONE_HALF;
} #else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); #endif
}
/* * Convert some rows of samples to the output colorspace.
*/
METHODDEF(void)
ycc_rgb_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{ switch (cinfo->out_color_space) { case JCS_EXT_RGB:
ycc_extrgb_convert_internal(cinfo, input_buf, input_row, output_buf,
num_rows); break; case JCS_EXT_RGBX: case JCS_EXT_RGBA:
ycc_extrgbx_convert_internal(cinfo, input_buf, input_row, output_buf,
num_rows); break; case JCS_EXT_BGR:
ycc_extbgr_convert_internal(cinfo, input_buf, input_row, output_buf,
num_rows); break; case JCS_EXT_BGRX: case JCS_EXT_BGRA:
ycc_extbgrx_convert_internal(cinfo, input_buf, input_row, output_buf,
num_rows); break; case JCS_EXT_XBGR: case JCS_EXT_ABGR:
ycc_extxbgr_convert_internal(cinfo, input_buf, input_row, output_buf,
num_rows); break; case JCS_EXT_XRGB: case JCS_EXT_ARGB:
ycc_extxrgb_convert_internal(cinfo, input_buf, input_row, output_buf,
num_rows); break; default:
ycc_rgb_convert_internal(cinfo, input_buf, input_row, output_buf,
num_rows); break;
}
}
/**************** Cases other than YCbCr -> RGB **************/
/* * Initialize for RGB->grayscale colorspace conversion.
*/
/* * Color conversion for grayscale: just copy the data. * This also works for YCbCr -> grayscale conversion, in which * we just copy the Y (luminance) component and ignore chrominance.
*/
METHODDEF(void)
gray_rgb_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{ switch (cinfo->out_color_space) { case JCS_EXT_RGB:
gray_extrgb_convert_internal(cinfo, input_buf, input_row, output_buf,
num_rows); break; case JCS_EXT_RGBX: case JCS_EXT_RGBA:
gray_extrgbx_convert_internal(cinfo, input_buf, input_row, output_buf,
num_rows); break; case JCS_EXT_BGR:
gray_extbgr_convert_internal(cinfo, input_buf, input_row, output_buf,
num_rows); break; case JCS_EXT_BGRX: case JCS_EXT_BGRA:
gray_extbgrx_convert_internal(cinfo, input_buf, input_row, output_buf,
num_rows); break; case JCS_EXT_XBGR: case JCS_EXT_ABGR:
gray_extxbgr_convert_internal(cinfo, input_buf, input_row, output_buf,
num_rows); break; case JCS_EXT_XRGB: case JCS_EXT_ARGB:
gray_extxrgb_convert_internal(cinfo, input_buf, input_row, output_buf,
num_rows); break; default:
gray_rgb_convert_internal(cinfo, input_buf, input_row, output_buf,
num_rows); break;
}
}
/* * Convert plain RGB to extended RGB
*/
METHODDEF(void)
rgb_rgb_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{ switch (cinfo->out_color_space) { case JCS_EXT_RGB:
rgb_extrgb_convert_internal(cinfo, input_buf, input_row, output_buf,
num_rows); break; case JCS_EXT_RGBX: case JCS_EXT_RGBA:
rgb_extrgbx_convert_internal(cinfo, input_buf, input_row, output_buf,
num_rows); break; case JCS_EXT_BGR:
rgb_extbgr_convert_internal(cinfo, input_buf, input_row, output_buf,
num_rows); break; case JCS_EXT_BGRX: case JCS_EXT_BGRA:
rgb_extbgrx_convert_internal(cinfo, input_buf, input_row, output_buf,
num_rows); break; case JCS_EXT_XBGR: case JCS_EXT_ABGR:
rgb_extxbgr_convert_internal(cinfo, input_buf, input_row, output_buf,
num_rows); break; case JCS_EXT_XRGB: case JCS_EXT_ARGB:
rgb_extxrgb_convert_internal(cinfo, input_buf, input_row, output_buf,
num_rows); break; default:
rgb_rgb_convert_internal(cinfo, input_buf, input_row, output_buf,
num_rows); break;
}
}
/* * Adobe-style YCCK->CMYK conversion. * We convert YCbCr to R=1-C, G=1-M, and B=1-Y using the same * conversion as above, while passing K (black) unchanged. * We assume build_ycc_rgb_table has been called.
*/
/* Declarations for ordered dithering * * We use a 4x4 ordered dither array packed into 32 bits. This array is * sufficient for dithering RGB888 to RGB565.
*/
/* Make sure num_components agrees with jpeg_color_space */ switch (cinfo->jpeg_color_space) { case JCS_GRAYSCALE: if (cinfo->num_components != 1)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); break;
case JCS_RGB: case JCS_YCbCr: if (cinfo->num_components != 3)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); break;
case JCS_CMYK: case JCS_YCCK: if (cinfo->num_components != 4)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); break;
default: /* JCS_UNKNOWN can be anything */ if (cinfo->num_components < 1)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); break;
}
/* Set out_color_components and conversion method based on requested space. * Also clear the component_needed flags for any unused components, * so that earlier pipeline stages can avoid useless computation. * NOTE: We do not allow any lossy color conversion algorithms in lossless * mode.
*/
switch (cinfo->out_color_space) { case JCS_GRAYSCALE: if (cinfo->master->lossless &&
cinfo->jpeg_color_space != cinfo->out_color_space)
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
cinfo->out_color_components = 1; if (cinfo->jpeg_color_space == JCS_GRAYSCALE ||
cinfo->jpeg_color_space == JCS_YCbCr) {
cconvert->pub._color_convert = grayscale_convert; /* For color->grayscale conversion, only the Y (0) component is needed */ for (ci = 1; ci < cinfo->num_components; ci++)
cinfo->comp_info[ci].component_needed = FALSE;
} elseif (cinfo->jpeg_color_space == JCS_RGB) {
cconvert->pub._color_convert = rgb_gray_convert;
build_rgb_y_table(cinfo);
} else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); break;
case JCS_RGB: case JCS_EXT_RGB: case JCS_EXT_RGBX: case JCS_EXT_BGR: case JCS_EXT_BGRX: case JCS_EXT_XBGR: case JCS_EXT_XRGB: case JCS_EXT_RGBA: case JCS_EXT_BGRA: case JCS_EXT_ABGR: case JCS_EXT_ARGB: if (cinfo->master->lossless && cinfo->jpeg_color_space != JCS_RGB)
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
cinfo->out_color_components = rgb_pixelsize[cinfo->out_color_space]; if (cinfo->jpeg_color_space == JCS_YCbCr) { #ifdef WITH_SIMD if (jsimd_can_ycc_rgb())
cconvert->pub._color_convert = jsimd_ycc_rgb_convert; else #endif
{
cconvert->pub._color_convert = ycc_rgb_convert;
build_ycc_rgb_table(cinfo);
}
} elseif (cinfo->jpeg_color_space == JCS_GRAYSCALE) {
cconvert->pub._color_convert = gray_rgb_convert;
} elseif (cinfo->jpeg_color_space == JCS_RGB) { if (rgb_red[cinfo->out_color_space] == 0 &&
rgb_green[cinfo->out_color_space] == 1 &&
rgb_blue[cinfo->out_color_space] == 2 &&
rgb_pixelsize[cinfo->out_color_space] == 3)
cconvert->pub._color_convert = null_convert; else
cconvert->pub._color_convert = rgb_rgb_convert;
} else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); break;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.