Improvements in CIE Lab conversion code. Start moving YCbCr stuff to the

tif_color.c module.
This commit is contained in:
Andrey Kiselev 2003-12-03 19:54:03 +00:00
parent 77010a7c62
commit 6d52b5d379
3 changed files with 251 additions and 228 deletions

View File

@ -1,4 +1,4 @@
/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_color.c,v 1.1 2003-11-13 19:46:39 dron Exp $ */
/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_color.c,v 1.2 2003-12-03 19:54:03 dron Exp $ */
/*
* Copyright (c) 1988-1997 Sam Leffler
@ -27,7 +27,7 @@
/*
* CIE L*a*b* to CIE XYZ and CIE XYZ to RGB conversion routines are taken
* from the VIPS library (http://www.vips.ecs.soton.ac.uk) with
* the permission of John Cupitt, the author.
* the permission of John Cupitt, the VIPS author.
*/
/*
@ -44,31 +44,31 @@
* reference white tristimuli can be specified.
*/
void
TIFFCIELabToXYZ(uint32 l, int32 a, int32 b, float *X, float *Y, float *Z,
float X0, float Y0, float Z0)
TIFFCIELabToXYZ(TIFFCIELabToRGB *cielab, uint32 l, int32 a, int32 b,
float *X, float *Y, float *Z)
{
float L = (float)l * 100.0 / 255.0;
float cby, tmp;
if( L < 8.856 ) {
*Y = (L * Y0) / 903.292;
cby = 7.787 * (*Y / Y0) + 16.0 / 116.0;
*Y = (L * cielab->Y0) / 903.292;
cby = 7.787 * (*Y / cielab->Y0) + 16.0 / 116.0;
} else {
cby = (L + 16.0) / 116.0;
*Y = Y0 * cby * cby * cby;
*Y = cielab->Y0 * cby * cby * cby;
}
tmp = (double)a / 500.0 + cby;
if( tmp < 0.2069 )
*X = X0 * (tmp - 0.13793) / 7.787;
*X = cielab->X0 * (tmp - 0.13793) / 7.787;
else
*X = X0 * tmp * tmp * tmp;
*X = cielab->X0 * tmp * tmp * tmp;
tmp = cby - (double)b / 200.0;
if( tmp < 0.2069 )
*Z = Z0 * (tmp - 0.13793) / 7.787;
*Z = cielab->Z0 * (tmp - 0.13793) / 7.787;
else
*Z = Z0 * tmp * tmp * tmp;
*Z = cielab->Z0 * tmp * tmp * tmp;
}
/*
@ -116,118 +116,170 @@ TIFFXYZToRGB(TIFFCIELabToRGB *cielab, float X, float Y, float Z,
* the Yr,Yb,Yg <=> r,g,b conversions.
*/
int
TIFFCIELabToRGBInit(TIFFCIELabToRGB** cielab)
TIFFCIELabToRGBInit(TIFFCIELabToRGB* cielab, TIFFDisplay *display,
float X0, float Y0, float Z0)
{
static char module[] = "TIFFCIELabToRGBInit";
int i;
float gamma;
TIFFDisplay sRGB_display = {
{ /* XYZ -> luminance matrix */
{ 3.2410, -1.5374, -0.4986 },
{ -0.9692, 1.8760, 0.0416 },
{ 0.0556, -0.2040, 1.0570 }
},
100, 100, 100, /* Light o/p for reference white */
255, 255, 255, /* Pixel values for ref. white */
1, 1, 1, /* Residual light o/p for black pixel */
2.4, 2.4, 2.4, /* Gamma values for the three guns */
};
cielab->range = 1500;
if (!(*cielab)) {
*cielab = (TIFFCIELabToRGB *)
_TIFFmalloc(sizeof(TIFFCIELabToRGB));
if (*cielab == NULL) {
TIFFError(module,
"No space for CIE L*a*b* control structure");
return -1;
}
(*cielab)->range = 1500;
(*cielab)->display =
(TIFFDisplay *)_TIFFmalloc(sizeof(TIFFDisplay));
if ((*cielab) == NULL) {
cielab->display = (TIFFDisplay *)_TIFFmalloc(sizeof(TIFFDisplay));
if (cielab == NULL) {
TIFFError(module, "No space for display structure");
_TIFFfree(*cielab);
*cielab = 0;
return -1;
}
(*cielab)->Yr2r = (float *)
_TIFFmalloc(((*cielab)->range + 1) * sizeof(float));
if ((*cielab)->Yr2r == NULL) {
cielab->Yr2r = (float *)
_TIFFmalloc((cielab->range + 1) * sizeof(float));
if (cielab->Yr2r == NULL) {
TIFFError(module, "No space for Red conversion array");
_TIFFfree((*cielab)->display);
_TIFFfree(*cielab);
*cielab = 0;
_TIFFfree(cielab->display);
return -1;
}
(*cielab)->Yg2g = (float *)
_TIFFmalloc(((*cielab)->range + 1) * sizeof(float));
if ((*cielab)->Yg2g == NULL) {
cielab->Yg2g = (float *)
_TIFFmalloc((cielab->range + 1) * sizeof(float));
if (cielab->Yg2g == NULL) {
TIFFError(module,
"No space for Green conversion array");
_TIFFfree((*cielab)->Yr2r);
_TIFFfree((*cielab)->display);
_TIFFfree(*cielab);
*cielab = 0;
_TIFFfree(cielab->Yr2r);
_TIFFfree(cielab->display);
return -1;
}
(*cielab)->Yb2b = (float *)
_TIFFmalloc(((*cielab)->range + 1) * sizeof(float));
if ((*cielab)->Yb2b == NULL) {
cielab->Yb2b = (float *)
_TIFFmalloc((cielab->range + 1) * sizeof(float));
if (cielab->Yb2b == NULL) {
TIFFError(module, "No space for Blue conversion array");
_TIFFfree((*cielab)->Yb2b);
_TIFFfree((*cielab)->Yr2r);
_TIFFfree((*cielab)->display);
_TIFFfree(*cielab);
*cielab = 0;
_TIFFfree(cielab->Yb2b);
_TIFFfree(cielab->Yr2r);
_TIFFfree(cielab->display);
return -1;
}
_TIFFmemcpy((*cielab)->display, &sRGB_display,
sizeof(TIFFDisplay));
}
_TIFFmemcpy(cielab->display, display, sizeof(TIFFDisplay));
/* Red */
gamma = 1.0 / (*cielab)->display->d_gammaR ;
(*cielab)->rstep =
((*cielab)->display->d_YCR - (*cielab)->display->d_Y0R)
/ (*cielab)->range;
for(i = 0; i <= (*cielab)->range; i++) {
(*cielab)->Yr2r[i] =
(*cielab)->display->d_Vrwr
* (pow((double)i / (*cielab)->range, gamma));
gamma = 1.0 / cielab->display->d_gammaR ;
cielab->rstep =
(cielab->display->d_YCR - cielab->display->d_Y0R)
/ cielab->range;
for(i = 0; i <= cielab->range; i++) {
cielab->Yr2r[i] = cielab->display->d_Vrwr
* (pow((double)i / cielab->range, gamma));
}
/* Green */
gamma = 1.0 / (*cielab)->display->d_gammaG ;
(*cielab)->gstep =
((*cielab)->display->d_YCR - (*cielab)->display->d_Y0R)
/ (*cielab)->range;
for(i = 0; i <= (*cielab)->range; i++) {
(*cielab)->Yg2g[i] =
(*cielab)->display->d_Vrwg
* (pow((double)i / (*cielab)->range, gamma));
gamma = 1.0 / cielab->display->d_gammaG ;
cielab->gstep =
(cielab->display->d_YCR - cielab->display->d_Y0R)
/ cielab->range;
for(i = 0; i <= cielab->range; i++) {
cielab->Yg2g[i] = cielab->display->d_Vrwg
* (pow((double)i / cielab->range, gamma));
}
/* Blue */
gamma = 1.0 / (*cielab)->display->d_gammaB ;
(*cielab)->bstep =
((*cielab)->display->d_YCR - (*cielab)->display->d_Y0R)
/ (*cielab)->range;
for(i = 0; i <= (*cielab)->range; i++) {
(*cielab)->Yb2b[i] =
(*cielab)->display->d_Vrwb
* (pow((double)i / (*cielab)->range, gamma));
gamma = 1.0 / cielab->display->d_gammaB ;
cielab->bstep =
(cielab->display->d_YCR - cielab->display->d_Y0R)
/ cielab->range;
for(i = 0; i <= cielab->range; i++) {
cielab->Yb2b[i] = cielab->display->d_Vrwb
* (pow((double)i / cielab->range, gamma));
}
/* Init reference white point */
cielab->X0 = X0;
cielab->Y0 = Y0;
cielab->Z0 = Z0;
return 0;
}
/*
* Free TIFFYCbCrToRGB structure.
*/
int
TIFFCIELabToRGBEnd(TIFFCIELabToRGB* cielab)
{
static char module[] = "TIFFCIELabToRGBEnd";
_TIFFfree(cielab->Yr2r);
_TIFFfree(cielab->Yg2g);
_TIFFfree(cielab->Yb2b);
_TIFFfree(cielab->display);
}
#define SHIFT 16
#define FIX(x) ((int32)((x) * (1L<<SHIFT) + 0.5))
#define ONE_HALF ((int32)(1<<(SHIFT-1)))
/*
* 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).
*/
int
TIFFYCbCrToRGBInit(TIFFYCbCrToRGB* ycbcr,
float LumaRed, float LumaGreen, float LumaBlue)
{
TIFFRGBValue* clamptab;
int i;
clamptab = (TIFFRGBValue*)(
(tidata_t) ycbcr+TIFFroundup(sizeof (TIFFYCbCrToRGB), sizeof (long)));
_TIFFmemset(clamptab, 0, 256); /* v < 0 => 0 */
ycbcr->clamptab = (clamptab += 256);
for (i = 0; i < 256; i++)
clamptab[i] = (TIFFRGBValue) i;
_TIFFmemset(clamptab+256, 255, 2*256); /* v > 255 => 255 */
{ float f1 = 2-2*LumaRed; int32 D1 = FIX(f1);
float f2 = LumaRed*f1/LumaGreen; int32 D2 = -FIX(f2);
float f3 = 2-2*LumaBlue; int32 D3 = FIX(f3);
float f4 = LumaBlue*f3/LumaGreen; int32 D4 = -FIX(f4);
int x;
ycbcr->Cr_r_tab = (int*) (clamptab + 3*256);
ycbcr->Cb_b_tab = ycbcr->Cr_r_tab + 256;
ycbcr->Cr_g_tab = (int32*) (ycbcr->Cb_b_tab + 256);
ycbcr->Cb_g_tab = ycbcr->Cr_g_tab + 256;
/*
* 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.
*
* XXX handle ReferenceBlackWhite correctly to calculate
* Cb/Cr values to use in constructing the tables.
*/
for (i = 0, x = -128; i < 256; i++, x++) {
ycbcr->Cr_r_tab[i] = (int)((D1*x + ONE_HALF)>>SHIFT);
ycbcr->Cb_b_tab[i] = (int)((D3*x + ONE_HALF)>>SHIFT);
ycbcr->Cr_g_tab[i] = D2*x;
ycbcr->Cb_g_tab[i] = D4*x + ONE_HALF;
}
}
return 0;
}
#undef SHIFT
#undef ONE_HALF
#undef FIX

View File

@ -1,4 +1,4 @@
/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_getimage.c,v 1.30 2003-12-03 15:40:14 dron Exp $ */
/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_getimage.c,v 1.31 2003-12-03 19:54:03 dron Exp $ */
/*
* Copyright (c) 1991-1997 Sam Leffler
@ -42,9 +42,28 @@ static int pickTileSeparateCase(TIFFRGBAImage*);
static const char photoTag[] = "PhotometricInterpretation";
/*
* Helper constants used in Orientation tag handling
*/
#define FLIP_VERTICALLY 0x01
#define FLIP_HORIZONTALLY 0x02
/*
* Color conversion constants. We will define display types here.
*/
TIFFDisplay display_sRGB = {
{ /* XYZ -> luminance matrix */
{ 3.2410, -1.5374, -0.4986 },
{ -0.9692, 1.8760, 0.0416 },
{ 0.0556, -0.2040, 1.0570 }
},
100, 100, 100, /* Light o/p for reference white */
255, 255, 255, /* Pixel values for ref. white */
1, 1, 1, /* Residual light o/p for black pixel */
2.4, 2.4, 2.4, /* Gamma values for the three guns */
};
/*
* Check the image to see if TIFFReadRGBAImage can deal with it.
* 1/0 is returned according to whether or not the image can
@ -174,10 +193,7 @@ TIFFRGBAImageEnd(TIFFRGBAImage* img)
if (img->ycbcr)
_TIFFfree(img->ycbcr), img->ycbcr = NULL;
if (img->cielab) {
_TIFFfree(img->cielab->Yr2r);
_TIFFfree(img->cielab->Yg2g);
_TIFFfree(img->cielab->Yb2b);
_TIFFfree(img->cielab->display);
TIFFCIELabToRGBEnd(img->cielab);
_TIFFfree(img->cielab), img->cielab = NULL;
}
@ -1540,11 +1556,11 @@ DECLAREContigPutFunc(putcontig8bitCIELab)
fromskew *= 3;
while (h-- > 0) {
for (x = w; x-- > 0;) {
TIFFCIELabToXYZ((u_char)pp[0],
TIFFCIELabToXYZ(img->cielab,
(u_char)pp[0],
(signed char)pp[1],
(signed char)pp[2],
&X, &Y, &Z,
D50_X0, D50_Y0, D50_Z0);
&X, &Y, &Z);
TIFFXYZToRGB(img->cielab, X, Y, Z, &r, &g, &b);
*cp++ = PACK(r, g, b);
pp += 3;
@ -2005,83 +2021,12 @@ DECLAREContigPutFunc(putcontig8bitYCbCr11tile)
#undef YCbCrSetup
#undef YCbCrtoRGB
#define LumaRed coeffs[0]
#define LumaGreen coeffs[1]
#define LumaBlue coeffs[2]
#define SHIFT 16
#define FIX(x) ((int32)((x) * (1L<<SHIFT) + 0.5))
#define ONE_HALF ((int32)(1<<(SHIFT-1)))
/*
* 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).
*/
static void
TIFFYCbCrToRGBInit(TIFFYCbCrToRGB* ycbcr, TIFF* tif)
{
TIFFRGBValue* clamptab;
float* coeffs;
int i;
clamptab = (TIFFRGBValue*)(
(tidata_t) ycbcr+TIFFroundup(sizeof (TIFFYCbCrToRGB), sizeof (long)));
_TIFFmemset(clamptab, 0, 256); /* v < 0 => 0 */
ycbcr->clamptab = (clamptab += 256);
for (i = 0; i < 256; i++)
clamptab[i] = (TIFFRGBValue) i;
_TIFFmemset(clamptab+256, 255, 2*256); /* v > 255 => 255 */
TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRCOEFFICIENTS, &coeffs);
_TIFFmemcpy(ycbcr->coeffs, coeffs, 3*sizeof (float));
{ float f1 = 2-2*LumaRed; int32 D1 = FIX(f1);
float f2 = LumaRed*f1/LumaGreen; int32 D2 = -FIX(f2);
float f3 = 2-2*LumaBlue; int32 D3 = FIX(f3);
float f4 = LumaBlue*f3/LumaGreen; int32 D4 = -FIX(f4);
int x;
ycbcr->Cr_r_tab = (int*) (clamptab + 3*256);
ycbcr->Cb_b_tab = ycbcr->Cr_r_tab + 256;
ycbcr->Cr_g_tab = (int32*) (ycbcr->Cb_b_tab + 256);
ycbcr->Cb_g_tab = ycbcr->Cr_g_tab + 256;
/*
* 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.
*
* XXX handle ReferenceBlackWhite correctly to calculate
* Cb/Cr values to use in constructing the tables.
*/
for (i = 0, x = -128; i < 256; i++, x++) {
ycbcr->Cr_r_tab[i] = (int)((D1*x + ONE_HALF)>>SHIFT);
ycbcr->Cb_b_tab[i] = (int)((D3*x + ONE_HALF)>>SHIFT);
ycbcr->Cr_g_tab[i] = D2*x;
ycbcr->Cb_g_tab[i] = D4*x + ONE_HALF;
}
}
}
#undef SHIFT
#undef ONE_HALF
#undef FIX
#undef LumaBlue
#undef LumaGreen
#undef LumaRed
static tileContigRoutine
initYCbCrConversion(TIFFRGBAImage* img)
{
static char module[] = "initCIELabConversion";
float *coeffs;
uint16 hs, vs;
if (img->ycbcr == NULL) {
@ -2092,18 +2037,17 @@ initYCbCrConversion(TIFFRGBAImage* img)
+ 2*256*sizeof (int32)
);
if (img->ycbcr == NULL) {
TIFFError(TIFFFileName(img->tif),
TIFFError(module,
"No space for YCbCr->RGB conversion state");
return (NULL);
}
TIFFYCbCrToRGBInit(img->ycbcr, img->tif);
} else {
float* coeffs;
}
TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRCOEFFICIENTS, &coeffs);
if (_TIFFmemcmp(coeffs, img->ycbcr->coeffs, 3*sizeof (float)) != 0)
TIFFYCbCrToRGBInit(img->ycbcr, img->tif);
}
if (TIFFYCbCrToRGBInit(img->ycbcr,
coeffs[0], coeffs[1], coeffs[2]) < 0)
return NULL;
/*
* The 6.0 spec says that subsampling must be
* one of 1, 2, or 4, and that vertical subsampling
@ -2120,13 +2064,33 @@ initYCbCrConversion(TIFFRGBAImage* img)
case 0x21: return (putcontig8bitYCbCr21tile);
case 0x11: return (putcontig8bitYCbCr11tile);
}
return (NULL);
}
static tileContigRoutine
initCIELabToRGBConversion(TIFFRGBAImage* img)
initCIELabConversion(TIFFRGBAImage* img)
{
TIFFCIELabToRGBInit(&img->cielab);
static char module[] = "initCIELabConversion";
if (!img->cielab) {
img->cielab = (TIFFCIELabToRGB *)
_TIFFmalloc(sizeof(TIFFCIELabToRGB));
if (!img->cielab) {
TIFFError(module,
"No space for CIE L*a*b*->RGB conversion state.");
return NULL;
}
}
if (TIFFCIELabToRGBInit(img->cielab, &display_sRGB,
D50_X0, D50_Y0, D50_Z0) < 0) {
TIFFError(module,
"Failed to initialize CIE L*a*b*->RGB conversion state.");
_TIFFfree(img->cielab);
return NULL;
}
return putcontig8bitCIELab;
}
@ -2430,7 +2394,7 @@ pickTileContigCase(TIFFRGBAImage* img)
break;
case PHOTOMETRIC_CIELAB:
if (img->bitspersample == 8)
put = initCIELabToRGBConversion(img);
put = initCIELabConversion(img);
break;
}
}

View File

@ -1,4 +1,4 @@
/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tiffio.h,v 1.21 2003-12-03 15:40:14 dron Exp $ */
/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tiffio.h,v 1.22 2003-12-03 19:54:03 dron Exp $ */
/*
* Copyright (c) 1988-1997 Sam Leffler
@ -153,7 +153,8 @@ typedef struct { /* YCbCr->RGB support */
int* Cb_b_tab;
int32* Cr_g_tab;
int32* Cb_g_tab;
float coeffs[3]; /* cached for repeated use */
float coeffs[3]; /* XXX: no longer required. Will
be removed in the future. */
} TIFFYCbCrToRGB;
typedef struct { /* CIE Lab 1976->RGB support */
@ -163,14 +164,20 @@ typedef struct { /* CIE Lab 1976->RGB support */
float* Yg2g; /* Conversion of Yg to g */
float* Yb2b; /* Conversion of Yb to b */
float rstep, gstep, bstep;
float X0, Y0, Z0; /* Reference white point */
} TIFFCIELabToRGB;
extern int TIFFCIELabToRGBInit(TIFFCIELabToRGB**);
extern void TIFFCIELabToXYZ(uint32, int32, int32, float *, float *, float *,
float, float, float);
extern int TIFFCIELabToRGBInit(TIFFCIELabToRGB*, TIFFDisplay *display,
float X0, float Y0, float Z0);
extern int TIFFCIELabToRGBEnd(TIFFCIELabToRGB*);
extern void TIFFCIELabToXYZ(TIFFCIELabToRGB *, uint32, int32, int32,
float *, float *, float *);
extern void TIFFXYZToRGB(TIFFCIELabToRGB *, float, float, float,
uint32 *, uint32 *, uint32 *);
extern int
TIFFYCbCrToRGBInit(TIFFYCbCrToRGB*, float, float, float);
/*
* RGBA-style image support.
*/