New color space conversion code: CIE L*a*b* 1976 images now supported by the

TIFFRGBAImage interface. All introduced routines go to new module tif_color.c.
Eventually all color conversion functions should be moved there.
This commit is contained in:
Andrey Kiselev 2003-11-13 19:46:39 +00:00
parent 6b087cb603
commit 474ab9ca0d
4 changed files with 365 additions and 33 deletions

View File

@ -1,4 +1,4 @@
# $Header: /cvs/maptools/cvsroot/libtiff/libtiff/Makefile.in,v 1.24 2003-10-09 08:36:24 dron Exp $
# $Header: /cvs/maptools/cvsroot/libtiff/libtiff/Makefile.in,v 1.25 2003-11-13 19:46:39 dron Exp $
#
# Tag Image File Format Library
#
@ -72,6 +72,7 @@ SRCS = \
tif_close.c \
tif_codec.c \
tif_compress.c \
tif_color.c \
tif_dir.c \
tif_dirinfo.c \
tif_dirread.c \
@ -109,6 +110,7 @@ OBJS = \
tif_close.o \
tif_codec.o \
tif_compress.o \
tif_color.o\
tif_dir.o \
tif_dirinfo.o \
tif_dirread.o \
@ -286,6 +288,8 @@ tif_codec.o: ${SRCDIR}/tif_codec.c
${CC} -c ${CFLAGS} ${SRCDIR}/tif_codec.c
tif_compress.o: ${SRCDIR}/tif_compress.c
${CC} -c ${CFLAGS} ${SRCDIR}/tif_compress.c
tif_color.o: ${SRCDIR}/tif_color.c
${CC} -c ${CFLAGS} ${SRCDIR}/tif_color.c
tif_dir.o: ${SRCDIR}/tif_dir.c
${CC} -c ${CFLAGS} ${SRCDIR}/tif_dir.c
tif_dirinfo.o: ${SRCDIR}/tif_dirinfo.c

233
libtiff/tif_color.c Normal file
View File

@ -0,0 +1,233 @@
/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_color.c,v 1.1 2003-11-13 19:46:39 dron Exp $ */
/*
* Copyright (c) 1988-1997 Sam Leffler
* Copyright (c) 1991-1997 Silicon Graphics, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, provided
* that (i) the above copyright notices and this permission notice appear in
* all copies of the software and related documentation, and (ii) the names of
* Sam Leffler and Silicon Graphics may not be used in any advertising or
* publicity relating to the software without the specific, prior written
* permission of Sam Leffler and Silicon Graphics.
*
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
*
* IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
* ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
* OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
* WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
* LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
/*
* 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.
*/
/*
* TIFF Library.
*
* Color space conversion routines.
*/
#include "tiffiop.h"
#include <math.h>
/*
* Convert color value from the CIE L*a*b* 1976 space to CIE XYZ. Different
* 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)
{
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;
} else {
cby = (L + 16.0) / 116.0;
*Y = Y0 * cby * cby * cby;
}
tmp = (double)a / 500.0 + cby;
if( tmp < 0.2069 )
*X = X0 * (tmp - 0.13793) / 7.787;
else
*X = X0 * tmp * tmp * tmp;
tmp = cby - (double)b / 200.0;
if( tmp < 0.2069 )
*Z = Z0 * (tmp - 0.13793) / 7.787;
else
*Z = Z0 * tmp * tmp * tmp;
}
/*
* Convert color value from the XYZ space to RGB.
*/
void
TIFFXYZToRGB(TIFFCIELabToRGB *cielab, float X, float Y, float Z,
uint32 *r, uint32 *g, uint32 *b)
{
int i;
float Yr, Yg, Yb;
float *matrix = &cielab->display->d_mat[0][0];
/* Multiply through the matrix to get luminosity values. */
Yr = matrix[0] * X + matrix[1] * Y + matrix[2] * Z;
Yg = matrix[3] * X + matrix[4] * Y + matrix[5] * Z;
Yb = matrix[6] * X + matrix[7] * Y + matrix[8] * Z;
/* Clip input */
Yr = TIFFmax( Yr, cielab->display->d_Y0R );
Yg = TIFFmax( Yg, cielab->display->d_Y0G );
Yb = TIFFmax( Yb, cielab->display->d_Y0B );
/* Turn luminosity to colour value. */
i = TIFFmin(cielab->range,
(Yr - cielab->display->d_Y0R) / cielab->rstep);
*r = TIFFrint(cielab->Yr2r[i]);
i = TIFFmin(cielab->range,
(Yg - cielab->display->d_Y0G) / cielab->gstep);
*g = TIFFrint(cielab->Yg2g[i]);
i = TIFFmin(cielab->range,
(Yb - cielab->display->d_Y0B) / cielab->bstep);
*b = TIFFrint(cielab->Yb2b[i]);
/* Clip output. */
*r = TIFFmin( *r, cielab->display->d_Vrwr );
*g = TIFFmin( *g, cielab->display->d_Vrwg );
*b = TIFFmin( *b, cielab->display->d_Vrwb );
}
/*
* Allocate conversion state structures and make look_up tables for
* the Yr,Yb,Yg <=> r,g,b conversions.
*/
int
TIFFCIELabToRGBInit(TIFFCIELabToRGB** cielab)
{
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 */
};
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) {
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) {
TIFFError(module, "No space for Red conversion array");
_TIFFfree((*cielab)->display);
_TIFFfree(*cielab);
*cielab = 0;
return -1;
}
(*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;
return -1;
}
(*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;
return -1;
}
_TIFFmemcpy((*cielab)->display, &sRGB_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));
}
/* 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));
}
/* 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));
}
return 0;
}

View File

@ -1,4 +1,4 @@
/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_getimage.c,v 1.28 2003-10-18 15:42:50 dron Exp $ */
/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_getimage.c,v 1.29 2003-11-13 19:46:39 dron Exp $ */
/*
* Copyright (c) 1991-1997 Sam Leffler
@ -151,6 +151,8 @@ TIFFRGBAImageOK(TIFF* tif, char emsg[1024])
return (0);
}
break;
case PHOTOMETRIC_CIELAB:
break;
default:
sprintf(emsg, "Sorry, can not handle image with %s=%d",
photoTag, photometric);
@ -162,20 +164,27 @@ TIFFRGBAImageOK(TIFF* tif, char emsg[1024])
void
TIFFRGBAImageEnd(TIFFRGBAImage* img)
{
if (img->Map)
_TIFFfree(img->Map), img->Map = NULL;
if (img->BWmap)
_TIFFfree(img->BWmap), img->BWmap = NULL;
if (img->PALmap)
_TIFFfree(img->PALmap), img->PALmap = NULL;
if (img->ycbcr)
_TIFFfree(img->ycbcr), img->ycbcr = NULL;
if (img->Map)
_TIFFfree(img->Map), img->Map = NULL;
if (img->BWmap)
_TIFFfree(img->BWmap), img->BWmap = NULL;
if (img->PALmap)
_TIFFfree(img->PALmap), img->PALmap = NULL;
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);
_TIFFfree(img->cielab), img->cielab = NULL;
}
if( img->redcmap ) {
_TIFFfree( img->redcmap );
_TIFFfree( img->greencmap );
_TIFFfree( img->bluecmap );
}
if( img->redcmap ) {
_TIFFfree( img->redcmap );
_TIFFfree( img->greencmap );
_TIFFfree( img->bluecmap );
}
}
static int
@ -375,6 +384,8 @@ TIFFRGBAImageBegin(TIFFRGBAImage* img, TIFF* tif, int stop, char emsg[1024])
img->photometric = PHOTOMETRIC_RGB; /* little white lie */
img->bitspersample = 8;
break;
case PHOTOMETRIC_CIELAB:
break;
default:
sprintf(emsg, "Sorry, can not handle image with %s=%d",
photoTag, img->photometric);
@ -384,6 +395,7 @@ TIFFRGBAImageBegin(TIFFRGBAImage* img, TIFF* tif, int stop, char emsg[1024])
img->BWmap = NULL;
img->PALmap = NULL;
img->ycbcr = NULL;
img->cielab = NULL;
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &img->width);
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &img->height);
TIFFGetFieldDefaulted(tif, TIFFTAG_ORIENTATION, &img->orientation);
@ -1471,6 +1483,31 @@ DECLARESepPutFunc(putRGBUAseparate16bittile)
}
}
/*
* 8-bit packed CIE L*a*b 1976 samples => RGB
*/
DECLAREContigPutFunc(putcontig8bitCIELab)
{
float X, Y, Z;
uint32 r, g, b;
(void) y;
fromskew *= 3;
while (h-- > 0) {
for (x = w; x-- > 0;) {
TIFFCIELabToXYZ((u_char)pp[0],
(signed char)pp[1],
(signed char)pp[2],
&X, &Y, &Z,
D50_X0, D50_Y0, D50_Z0);
TIFFXYZToRGB(img->cielab, X, Y, Z, &r, &g, &b);
*cp++ = PACK(r, g, b);
pp += 3;
}
cp += toskew;
pp += fromskew;
}
}
/*
* YCbCr -> RGB conversion and packing routines. The colorspace
* conversion algorithm comes from the IJG v5a code; see below
@ -2040,6 +2077,13 @@ initYCbCrConversion(TIFFRGBAImage* img)
return (NULL);
}
static tileContigRoutine
initCIELabToRGBConversion(TIFFRGBAImage* img)
{
TIFFCIELabToRGBInit(&img->cielab);
return putcontig8bitCIELab;
}
/*
* Greyscale images with less than 8 bits/sample are handled
* with a table to avoid lots of shifts and masks. The table
@ -2338,6 +2382,10 @@ pickTileContigCase(TIFFRGBAImage* img)
if (img->bitspersample == 8)
put = initYCbCrConversion(img);
break;
case PHOTOMETRIC_CIELAB:
if (img->bitspersample == 8)
put = initCIELabToRGBConversion(img);
break;
}
}
return ((img->put.contig = put) != 0);
@ -2481,9 +2529,10 @@ TIFFReadRGBATile(TIFF* tif, uint32 col, uint32 row, uint32 * raster)
* Setup the RGBA reader.
*/
if (!TIFFRGBAImageOK(tif, emsg) || !TIFFRGBAImageBegin(&img, tif, 0, emsg)) {
TIFFError(TIFFFileName(tif), emsg);
return( 0 );
if (!TIFFRGBAImageOK(tif, emsg)
|| !TIFFRGBAImageBegin(&img, tif, 0, emsg)) {
TIFFError(TIFFFileName(tif), emsg);
return( 0 );
}
/*
@ -2525,8 +2574,7 @@ TIFFReadRGBATile(TIFF* tif, uint32 col, uint32 row, uint32 * raster)
if( read_xsize == tile_xsize && read_ysize == tile_ysize )
return( ok );
for( i_row = 0; i_row < read_ysize; i_row++ )
{
for( i_row = 0; i_row < read_ysize; i_row++ ) {
memmove( raster + (tile_ysize - i_row - 1) * tile_xsize,
raster + (read_ysize - i_row - 1) * read_xsize,
read_xsize * sizeof(uint32) );
@ -2534,8 +2582,7 @@ TIFFReadRGBATile(TIFF* tif, uint32 col, uint32 row, uint32 * raster)
0, sizeof(uint32) * (tile_xsize - read_xsize) );
}
for( i_row = read_ysize; i_row < tile_ysize; i_row++ )
{
for( i_row = read_ysize; i_row < tile_ysize; i_row++ ) {
_TIFFmemset( raster + (tile_ysize - i_row - 1) * tile_xsize,
0, sizeof(uint32) * tile_xsize );
}

View File

@ -1,4 +1,4 @@
/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tiffio.h,v 1.18 2003-11-07 11:26:38 dron Exp $ */
/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tiffio.h,v 1.19 2003-11-13 19:46:39 dron Exp $ */
/*
* Copyright (c) 1988-1997 Sam Leffler
@ -114,10 +114,66 @@ typedef void* thandle_t; /* client data handle */
#define TIFFPRINT_JPEGACTABLES 0x200 /* JPEG AC tables */
#define TIFFPRINT_JPEGDCTABLES 0x200 /* JPEG DC tables */
/*
* Colour conversion stuff
*/
/* reference white */
#define D65_X0 (95.0470)
#define D65_Y0 (100.0)
#define D65_Z0 (108.8827)
#define D50_X0 (96.4250)
#define D50_Y0 (100.0)
#define D50_Z0 (82.4680)
/* Structure for holding information about a display device. */
typedef unsigned char TIFFRGBValue; /* 8-bit samples */
typedef struct {
float d_mat[3][3]; /* XYZ -> luminance matrix */
float d_YCR; /* Light o/p for reference white */
float d_YCG;
float d_YCB;
int d_Vrwr; /* Pixel values for ref. white */
int d_Vrwg;
int d_Vrwb;
float d_Y0R; /* Residual light for black pixel */
float d_Y0G;
float d_Y0B;
float d_gammaR; /* Gamma values for the three guns */
float d_gammaG;
float d_gammaB;
} TIFFDisplay;
typedef struct { /* YCbCr->RGB support */
TIFFRGBValue* clamptab; /* range clamping table */
int* Cr_r_tab;
int* Cb_b_tab;
int32* Cr_g_tab;
int32* Cb_g_tab;
float coeffs[3]; /* cached for repeated use */
} TIFFYCbCrToRGB;
typedef struct { /* CIE Lab 1976->RGB support */
TIFFDisplay *display;
int range; /* Size of conversion table*/
float* Yr2r; /* Conversion of Yr to r */
float* Yg2g; /* Conversion of Yg to g */
float* Yb2b; /* Conversion of Yb to b */
float rstep, gstep, bstep;
} TIFFCIELabToRGB;
extern int TIFFCIELabToRGBInit(TIFFCIELabToRGB**);
extern void TIFFCIELabToXYZ(uint32, int32, int32, float *, float *, float *,
float, float, float);
extern void TIFFXYZToRGB(TIFFCIELabToRGB *, float, float, float,
uint32 *, uint32 *, uint32 *);
/*
* RGBA-style image support.
*/
typedef unsigned char TIFFRGBValue; /* 8-bit samples */
typedef struct _TIFFRGBAImage TIFFRGBAImage;
/*
* The image reading and conversion routines invoke
@ -138,15 +194,6 @@ typedef void (*tileSeparateRoutine)
/*
* RGBA-reader state.
*/
typedef struct { /* YCbCr->RGB support */
TIFFRGBValue* clamptab; /* range clamping table */
int* Cr_r_tab;
int* Cb_b_tab;
int32* Cr_g_tab;
int32* Cb_g_tab;
float coeffs[3]; /* cached for repeated use */
} TIFFYCbCrToRGB;
struct _TIFFRGBAImage {
TIFF* tif; /* image handle */
int stoponerr; /* stop on read error */
@ -172,6 +219,7 @@ struct _TIFFRGBAImage {
uint32** BWmap; /* black&white map */
uint32** PALmap; /* palette image map */
TIFFYCbCrToRGB* ycbcr; /* YCbCr conversion state */
TIFFCIELabToRGB* cielab; /* CIE L*a*b conversion state */
int row_offset;
int col_offset;