roentgen b75cab
.\" $Id: TIFFcolor.3tiff,v 1.4 2009-11-30 12:22:26 fwarmerdam Exp $
roentgen b75cab
.\"
roentgen b75cab
.\" Copyright (c) 2003, Andrey Kiselev <dron@ak4719.spb.edu></dron@ak4719.spb.edu>
roentgen b75cab
.\"
roentgen b75cab
.\" Permission to use, copy, modify, distribute, and sell this software and 
roentgen b75cab
.\" its documentation for any purpose is hereby granted without fee, provided
roentgen b75cab
.\" that (i) the above copyright notices and this permission notice appear in
roentgen b75cab
.\" all copies of the software and related documentation, and (ii) the names of
roentgen b75cab
.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
roentgen b75cab
.\" publicity relating to the software without the specific, prior written
roentgen b75cab
.\" permission of Sam Leffler and Silicon Graphics.
roentgen b75cab
.\" 
roentgen b75cab
.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
roentgen b75cab
.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
roentgen b75cab
.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
roentgen b75cab
.\" 
roentgen b75cab
.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
roentgen b75cab
.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
roentgen b75cab
.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
roentgen b75cab
.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
roentgen b75cab
.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
roentgen b75cab
.\" OF THIS SOFTWARE.
roentgen b75cab
.\"
roentgen b75cab
.if n .po 0
roentgen b75cab
.TH COLOR 3TIFF "December 21, 2003" "libtiff"
roentgen b75cab
.SH NAME
roentgen b75cab
TIFFYCbCrToRGBInit, TIFFYCbCrtoRGB, TIFFCIELabToRGBInit, TIFFCIELabToXYZ,
roentgen b75cab
TIFFXYZToRGB \- color conversion routines.
roentgen b75cab
.SH SYNOPSIS
roentgen b75cab
.B "#include <tiffio.h>"</tiffio.h>
roentgen b75cab
.sp
roentgen b75cab
.BI "int TIFFYCbCrToRGBInit(TIFFYCbCrToRGB *" ycbcr ", float *" luma ", float *"refBlackWhite" );"
roentgen b75cab
.br
roentgen b75cab
.BI "void TIFFYCbCrtoRGB(TIFFYCbCrToRGB *" ycbcr ", uint32 " Y ", int32 " Cb ", int32 " Cr ", uint32 *" R ", uint32 *" G ", uint32 *" B " );"
roentgen b75cab
.sp
roentgen b75cab
.BI "int TIFFCIELabToRGBInit(TIFFCIELabToRGB *" cielab ", const TIFFDisplay *" display ", float *" refWhite ");"
roentgen b75cab
.br
roentgen b75cab
.BI "void TIFFCIELabToXYZ(TIFFCIELabToRGB *" cielab ", uint32 " L ", int32 " a ", int32 " b ", float *" X ", float *" Y ", float *" Z ");"
roentgen b75cab
.br
roentgen b75cab
.BI "void TIFFXYZToRGB(TIFFCIELabToRGB *" cielab ", float " X ", float " Y ", float " Z" , uint32 *" R ", uint32 *" G ", uint32 *" B ");"
roentgen b75cab
.SH DESCRIPTION
roentgen b75cab
TIFF supports several color spaces for images stored in that format. There is
roentgen b75cab
usually a problem of application to handle the data properly and convert
roentgen b75cab
between different colorspaces for displaying and printing purposes. To
roentgen b75cab
simplify this task libtiff implements several color conversion routines
roentgen b75cab
itself. In particular, these routines used in
roentgen b75cab
.B TIFFRGBAImage(3TIFF)
roentgen b75cab
interface.
roentgen b75cab
.PP
roentgen b75cab
.B TIFFYCbCrToRGBInit()
roentgen b75cab
used to initialize
roentgen b75cab
.I YCbCr
roentgen b75cab
to
roentgen b75cab
.I RGB
roentgen b75cab
conversion state. Allocating and freeing of the
roentgen b75cab
.I ycbcr
roentgen b75cab
structure belongs to programmer.
roentgen b75cab
.I TIFFYCbCrToRGB
roentgen b75cab
defined in
roentgen b75cab
.B tiffio.h
roentgen b75cab
as
roentgen b75cab
.PP
roentgen b75cab
.RS
roentgen b75cab
.nf
roentgen b75cab
typedef struct {                /* YCbCr->RGB support */
roentgen b75cab
        TIFFRGBValue* clamptab; /* range clamping table */
roentgen b75cab
        int*	      Cr_r_tab;
roentgen b75cab
        int*	      Cb_b_tab;
roentgen b75cab
        int32*	      Cr_g_tab;
roentgen b75cab
        int32*	      Cb_g_tab;
roentgen b75cab
        int32*        Y_tab;
roentgen b75cab
} TIFFYCbCrToRGB;
roentgen b75cab
.fi
roentgen b75cab
.RE
roentgen b75cab
.PP
roentgen b75cab
.I luma
roentgen b75cab
is a float array of three values representing proportions of the red, green
roentgen b75cab
and blue in luminance, Y (see section 21 of the TIFF 6.0 specification, where
roentgen b75cab
the YCbCr images discussed).
roentgen b75cab
.I TIFFTAG_YCBCRCOEFFICIENTS
roentgen b75cab
holds that values in TIFF file.
roentgen b75cab
.I refBlackWhite
roentgen b75cab
is a float array of 6 values which specifies a pair of headroom and footroom
roentgen b75cab
image data values (codes) for each image component (see section 20 of the
roentgen b75cab
TIFF 6.0 specification where the colorinmetry fields discussed).
roentgen b75cab
.I TIFFTAG_REFERENCEBLACKWHITE
roentgen b75cab
is responsible for storing these values in TIFF file. Following code snippet
roentgen b75cab
should helps to understand the the technique:
roentgen b75cab
.PP
roentgen b75cab
.RS
roentgen b75cab
.nf
roentgen b75cab
float *luma, *refBlackWhite;
roentgen b75cab
uint16 hs, vs;
roentgen b75cab
roentgen b75cab
/* Initialize structures */
roentgen b75cab
ycbcr = (TIFFYCbCrToRGB*)
roentgen b75cab
	_TIFFmalloc(TIFFroundup(sizeof(TIFFYCbCrToRGB), sizeof(long))
roentgen b75cab
        	+ 4*256*sizeof(TIFFRGBValue)
roentgen b75cab
        	+ 2*256*sizeof(int)
roentgen b75cab
        	+ 3*256*sizeof(int32));
roentgen b75cab
if (ycbcr == NULL) {
roentgen b75cab
        TIFFError("YCbCr->RGB",
roentgen b75cab
		"No space for YCbCr->RGB conversion state");
roentgen b75cab
        exit(0);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRCOEFFICIENTS, &luma);
roentgen b75cab
TIFFGetFieldDefaulted(tif, TIFFTAG_REFERENCEBLACKWHITE, &refBlackWhite);
roentgen b75cab
if (TIFFYCbCrToRGBInit(ycbcr, luma, refBlackWhite) < 0)
roentgen b75cab
	exit(0);
roentgen b75cab
roentgen b75cab
/* Start conversion */
roentgen b75cab
uint32 r, g, b;
roentgen b75cab
uint32 Y;
roentgen b75cab
int32 Cb, Cr;
roentgen b75cab
roentgen b75cab
for each pixel in image
roentgen b75cab
	TIFFYCbCrtoRGB(img->ycbcr, Y, Cb, Cr, &r, &g, &b);
roentgen b75cab
roentgen b75cab
/* Free state structure */
roentgen b75cab
_TIFFfree(ycbcr);
roentgen b75cab
.fi
roentgen b75cab
.RE
roentgen b75cab
.PP
roentgen b75cab
roentgen b75cab
.PP
roentgen b75cab
.B TIFFCIELabToRGBInit()
roentgen b75cab
initializes the
roentgen b75cab
.I CIE L*a*b* 1976
roentgen b75cab
to
roentgen b75cab
.I RGB
roentgen b75cab
conversion state.
roentgen b75cab
.B TIFFCIELabToRGB
roentgen b75cab
defined as
roentgen b75cab
.PP
roentgen b75cab
.RS
roentgen b75cab
.nf
roentgen b75cab
#define CIELABTORGB_TABLE_RANGE 1500
roentgen b75cab
roentgen b75cab
typedef struct {		     /* CIE Lab 1976->RGB support */
roentgen b75cab
	int	range;		     /* Size of conversion table */
roentgen b75cab
	float	rstep, gstep, bstep;
roentgen b75cab
	float	X0, Y0, Z0;	     /* Reference white point */
roentgen b75cab
	TIFFDisplay display;
roentgen b75cab
	float	Yr2r[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yr to r */
roentgen b75cab
	float	Yg2g[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yg to g */
roentgen b75cab
	float	Yb2b[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yb to b */
roentgen b75cab
} TIFFCIELabToRGB;
roentgen b75cab
.fi
roentgen b75cab
.RE
roentgen b75cab
.PP
roentgen b75cab
.I display
roentgen b75cab
is a display device description, declared as
roentgen b75cab
.PP
roentgen b75cab
.RS
roentgen b75cab
.nf
roentgen b75cab
typedef struct {
roentgen b75cab
	float d_mat[3][3]; /* XYZ -> luminance matrix */
roentgen b75cab
	float d_YCR;       /* Light o/p for reference white */
roentgen b75cab
	float d_YCG;
roentgen b75cab
	float d_YCB;
roentgen b75cab
	uint32 d_Vrwr;     /* Pixel values for ref. white */
roentgen b75cab
	uint32 d_Vrwg;
roentgen b75cab
	uint32 d_Vrwb;
roentgen b75cab
	float d_Y0R;       /* Residual light for black pixel */
roentgen b75cab
	float d_Y0G;
roentgen b75cab
	float d_Y0B;
roentgen b75cab
	float d_gammaR;    /* Gamma values for the three guns */
roentgen b75cab
	float d_gammaG;
roentgen b75cab
	float d_gammaB;
roentgen b75cab
} TIFFDisplay;
roentgen b75cab
.fi
roentgen b75cab
.RE
roentgen b75cab
.PP
roentgen b75cab
For example, the one can use sRGB device, which has the following parameters:
roentgen b75cab
.PP
roentgen b75cab
.RS
roentgen b75cab
.nf
roentgen b75cab
TIFFDisplay display_sRGB = {
roentgen b75cab
	{       /* XYZ -> luminance matrix */
roentgen b75cab
		{  3.2410F, -1.5374F, -0.4986F },
roentgen b75cab
		{  -0.9692F, 1.8760F, 0.0416F },
roentgen b75cab
		{  0.0556F, -0.2040F, 1.0570F }
roentgen b75cab
	},	
roentgen b75cab
	100.0F, 100.0F, 100.0F, /* Light o/p for reference white */
roentgen b75cab
	255, 255, 255,      /* Pixel values for ref. white */
roentgen b75cab
	1.0F, 1.0F, 1.0F,   /* Residual light o/p for black pixel */
roentgen b75cab
	2.4F, 2.4F, 2.4F,   /* Gamma values for the three guns */
roentgen b75cab
};
roentgen b75cab
.fi
roentgen b75cab
.RE
roentgen b75cab
.PP
roentgen b75cab
.I refWhite
roentgen b75cab
is a color temperature of the reference white. The
roentgen b75cab
.I TIFFTAG_WHITEPOINT
roentgen b75cab
contains the chromaticity of the white point of the image from where the
roentgen b75cab
reference white can be calculated using following formulae:
roentgen b75cab
.PP
roentgen b75cab
.RS
roentgen b75cab
refWhite_Y = 100.0
roentgen b75cab
.br
roentgen b75cab
refWhite_X = whitePoint_x / whitePoint_y * refWhite_Y
roentgen b75cab
.br
roentgen b75cab
refWhite_Z = (1.0 - whitePoint_x - whitePoint_y) / whitePoint_y * refWhite_X
roentgen b75cab
.br
roentgen b75cab
.RE
roentgen b75cab
.PP
roentgen b75cab
The conversion itself performed in two steps: at the first one we will convert
roentgen b75cab
.I CIE L*a*b* 1976
roentgen b75cab
to
roentgen b75cab
.I CIE XYZ
roentgen b75cab
using
roentgen b75cab
.B TIFFCIELabToXYZ()
roentgen b75cab
routine, and at the second step we will convert
roentgen b75cab
.I CIE XYZ
roentgen b75cab
to
roentgen b75cab
.I RGB
roentgen b75cab
using
roentgen b75cab
.B TIFFXYZToRGB().
roentgen b75cab
Look at the code sample below:
roentgen b75cab
.PP
roentgen b75cab
.RS
roentgen b75cab
.nf
roentgen b75cab
float   *whitePoint;
roentgen b75cab
float   refWhite[3];
roentgen b75cab
roentgen b75cab
/* Initialize structures */
roentgen b75cab
img->cielab = (TIFFCIELabToRGB *)
roentgen b75cab
	_TIFFmalloc(sizeof(TIFFCIELabToRGB));
roentgen b75cab
if (!cielab) {
roentgen b75cab
	TIFFError("CIE L*a*b*->RGB",
roentgen b75cab
		"No space for CIE L*a*b*->RGB conversion state.");
roentgen b75cab
	exit(0);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
TIFFGetFieldDefaulted(tif, TIFFTAG_WHITEPOINT, &whitePoint);
roentgen b75cab
refWhite[1] = 100.0F;
roentgen b75cab
refWhite[0] = whitePoint[0] / whitePoint[1] * refWhite[1];
roentgen b75cab
refWhite[2] = (1.0F - whitePoint[0] - whitePoint[1])
roentgen b75cab
	      / whitePoint[1] * refWhite[1];
roentgen b75cab
if (TIFFCIELabToRGBInit(cielab, &display_sRGB, refWhite) < 0) {
roentgen b75cab
	TIFFError("CIE L*a*b*->RGB",
roentgen b75cab
		"Failed to initialize CIE L*a*b*->RGB conversion state.");
roentgen b75cab
	_TIFFfree(cielab);
roentgen b75cab
	exit(0);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
/* Now we can start to convert */
roentgen b75cab
uint32 r, g, b;
roentgen b75cab
uint32 L;
roentgen b75cab
int32 a, b;
roentgen b75cab
float X, Y, Z;
roentgen b75cab
roentgen b75cab
for each pixel in image
roentgen b75cab
	TIFFCIELabToXYZ(cielab, L, a, b, &X, &Y, &Z);
roentgen b75cab
	TIFFXYZToRGB(cielab, X, Y, Z, &r, &g, &b);
roentgen b75cab
roentgen b75cab
/* Don't forget to free the state structure */
roentgen b75cab
_TIFFfree(cielab);
roentgen b75cab
.fi
roentgen b75cab
.RE
roentgen b75cab
.PP
roentgen b75cab
.SH "SEE ALSO"
roentgen b75cab
.BR TIFFRGBAImage (3TIFF)
roentgen b75cab
.BR libtiff (3TIFF),
roentgen b75cab
.PP
roentgen b75cab
Libtiff library home page:
roentgen b75cab
.BR http://www.remotesensing.org/libtiff/