|
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/
|