Blame libtiff/tif_color.c

Packit 7838c8
/* $Id: tif_color.c,v 1.24 2017-05-29 10:12:54 erouault Exp $ */
Packit 7838c8
Packit 7838c8
/*
Packit 7838c8
 * Copyright (c) 1988-1997 Sam Leffler
Packit 7838c8
 * Copyright (c) 1991-1997 Silicon Graphics, Inc.
Packit 7838c8
 *
Packit 7838c8
 * Permission to use, copy, modify, distribute, and sell this software and 
Packit 7838c8
 * its documentation for any purpose is hereby granted without fee, provided
Packit 7838c8
 * that (i) the above copyright notices and this permission notice appear in
Packit 7838c8
 * all copies of the software and related documentation, and (ii) the names of
Packit 7838c8
 * Sam Leffler and Silicon Graphics may not be used in any advertising or
Packit 7838c8
 * publicity relating to the software without the specific, prior written
Packit 7838c8
 * permission of Sam Leffler and Silicon Graphics.
Packit 7838c8
 * 
Packit 7838c8
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
Packit 7838c8
 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
Packit 7838c8
 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
Packit 7838c8
 * 
Packit 7838c8
 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
Packit 7838c8
 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
Packit 7838c8
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
Packit 7838c8
 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
Packit 7838c8
 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
Packit 7838c8
 * OF THIS SOFTWARE.
Packit 7838c8
 */
Packit 7838c8
Packit 7838c8
/*
Packit 7838c8
 * CIE L*a*b* to CIE XYZ and CIE XYZ to RGB conversion routines are taken
Packit 7838c8
 * from the VIPS library (http://www.vips.ecs.soton.ac.uk) with
Packit 7838c8
 * the permission of John Cupitt, the VIPS author.
Packit 7838c8
 */
Packit 7838c8
Packit 7838c8
/*
Packit 7838c8
 * TIFF Library.
Packit 7838c8
 *
Packit 7838c8
 * Color space conversion routines.
Packit 7838c8
 */
Packit 7838c8
Packit 7838c8
#include "tiffiop.h"
Packit 7838c8
#include <math.h>
Packit 7838c8
Packit 7838c8
/*
Packit 7838c8
 * Convert color value from the CIE L*a*b* 1976 space to CIE XYZ.
Packit 7838c8
 */
Packit 7838c8
void
Packit 7838c8
TIFFCIELabToXYZ(TIFFCIELabToRGB *cielab, uint32 l, int32 a, int32 b,
Packit 7838c8
		float *X, float *Y, float *Z)
Packit 7838c8
{
Packit 7838c8
	float L = (float)l * 100.0F / 255.0F;
Packit 7838c8
	float cby, tmp;
Packit 7838c8
Packit 7838c8
	if( L < 8.856F ) {
Packit 7838c8
		*Y = (L * cielab->Y0) / 903.292F;
Packit 7838c8
		cby = 7.787F * (*Y / cielab->Y0) + 16.0F / 116.0F;
Packit 7838c8
	} else {
Packit 7838c8
		cby = (L + 16.0F) / 116.0F;
Packit 7838c8
		*Y = cielab->Y0 * cby * cby * cby;
Packit 7838c8
	}
Packit 7838c8
Packit 7838c8
	tmp = (float)a / 500.0F + cby;
Packit 7838c8
	if( tmp < 0.2069F )
Packit 7838c8
		*X = cielab->X0 * (tmp - 0.13793F) / 7.787F;
Packit 7838c8
	else    
Packit 7838c8
		*X = cielab->X0 * tmp * tmp * tmp;
Packit 7838c8
Packit 7838c8
	tmp = cby - (float)b / 200.0F;
Packit 7838c8
	if( tmp < 0.2069F )
Packit 7838c8
		*Z = cielab->Z0 * (tmp - 0.13793F) / 7.787F;
Packit 7838c8
	else    
Packit 7838c8
		*Z = cielab->Z0 * tmp * tmp * tmp;
Packit 7838c8
}
Packit 7838c8
Packit 7838c8
#define RINT(R) ((uint32)((R)>0?((R)+0.5):((R)-0.5)))
Packit 7838c8
/*
Packit 7838c8
 * Convert color value from the XYZ space to RGB.
Packit 7838c8
 */
Packit 7838c8
void
Packit 7838c8
TIFFXYZToRGB(TIFFCIELabToRGB *cielab, float X, float Y, float Z,
Packit 7838c8
	     uint32 *r, uint32 *g, uint32 *b)
Packit 7838c8
{
Packit 7838c8
	int i;
Packit 7838c8
	float Yr, Yg, Yb;
Packit 7838c8
	float *matrix = &cielab->display.d_mat[0][0];
Packit 7838c8
Packit 7838c8
	/* Multiply through the matrix to get luminosity values. */
Packit 7838c8
	Yr =  matrix[0] * X + matrix[1] * Y + matrix[2] * Z;
Packit 7838c8
	Yg =  matrix[3] * X + matrix[4] * Y + matrix[5] * Z;
Packit 7838c8
	Yb =  matrix[6] * X + matrix[7] * Y + matrix[8] * Z;
Packit 7838c8
Packit 7838c8
	/* Clip input */
Packit 7838c8
	Yr = TIFFmax(Yr, cielab->display.d_Y0R);
Packit 7838c8
	Yg = TIFFmax(Yg, cielab->display.d_Y0G);
Packit 7838c8
	Yb = TIFFmax(Yb, cielab->display.d_Y0B);
Packit 7838c8
Packit 7838c8
	/* Avoid overflow in case of wrong input values */
Packit 7838c8
	Yr = TIFFmin(Yr, cielab->display.d_YCR);
Packit 7838c8
	Yg = TIFFmin(Yg, cielab->display.d_YCG);
Packit 7838c8
	Yb = TIFFmin(Yb, cielab->display.d_YCB);
Packit 7838c8
Packit 7838c8
	/* Turn luminosity to colour value. */
Packit 7838c8
	i = (int)((Yr - cielab->display.d_Y0R) / cielab->rstep);
Packit 7838c8
	i = TIFFmin(cielab->range, i);
Packit 7838c8
	*r = RINT(cielab->Yr2r[i]);
Packit 7838c8
Packit 7838c8
	i = (int)((Yg - cielab->display.d_Y0G) / cielab->gstep);
Packit 7838c8
	i = TIFFmin(cielab->range, i);
Packit 7838c8
	*g = RINT(cielab->Yg2g[i]);
Packit 7838c8
Packit 7838c8
	i = (int)((Yb - cielab->display.d_Y0B) / cielab->bstep);
Packit 7838c8
	i = TIFFmin(cielab->range, i);
Packit 7838c8
	*b = RINT(cielab->Yb2b[i]);
Packit 7838c8
Packit 7838c8
	/* Clip output. */
Packit 7838c8
	*r = TIFFmin(*r, cielab->display.d_Vrwr);
Packit 7838c8
	*g = TIFFmin(*g, cielab->display.d_Vrwg);
Packit 7838c8
	*b = TIFFmin(*b, cielab->display.d_Vrwb);
Packit 7838c8
}
Packit 7838c8
#undef RINT
Packit 7838c8
Packit 7838c8
/* 
Packit 7838c8
 * Allocate conversion state structures and make look_up tables for
Packit 7838c8
 * the Yr,Yb,Yg <=> r,g,b conversions.
Packit 7838c8
 */
Packit 7838c8
int
Packit 7838c8
TIFFCIELabToRGBInit(TIFFCIELabToRGB* cielab,
Packit 7838c8
		    const TIFFDisplay *display, float *refWhite)
Packit 7838c8
{
Packit 7838c8
	int i;
Packit 7838c8
	double dfGamma;
Packit 7838c8
Packit 7838c8
	cielab->range = CIELABTORGB_TABLE_RANGE;
Packit 7838c8
Packit 7838c8
	_TIFFmemcpy(&cielab->display, display, sizeof(TIFFDisplay));
Packit 7838c8
Packit 7838c8
	/* Red */
Packit 7838c8
	dfGamma = 1.0 / cielab->display.d_gammaR ;
Packit 7838c8
	cielab->rstep =
Packit 7838c8
		(cielab->display.d_YCR - cielab->display.d_Y0R)	/ cielab->range;
Packit 7838c8
	for(i = 0; i <= cielab->range; i++) {
Packit 7838c8
		cielab->Yr2r[i] = cielab->display.d_Vrwr
Packit 7838c8
		    * ((float)pow((double)i / cielab->range, dfGamma));
Packit 7838c8
	}
Packit 7838c8
Packit 7838c8
	/* Green */
Packit 7838c8
	dfGamma = 1.0 / cielab->display.d_gammaG ;
Packit 7838c8
	cielab->gstep =
Packit 7838c8
	    (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range;
Packit 7838c8
	for(i = 0; i <= cielab->range; i++) {
Packit 7838c8
		cielab->Yg2g[i] = cielab->display.d_Vrwg
Packit 7838c8
		    * ((float)pow((double)i / cielab->range, dfGamma));
Packit 7838c8
	}
Packit 7838c8
Packit 7838c8
	/* Blue */
Packit 7838c8
	dfGamma = 1.0 / cielab->display.d_gammaB ;
Packit 7838c8
	cielab->bstep =
Packit 7838c8
	    (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range;
Packit 7838c8
	for(i = 0; i <= cielab->range; i++) {
Packit 7838c8
		cielab->Yb2b[i] = cielab->display.d_Vrwb
Packit 7838c8
		    * ((float)pow((double)i / cielab->range, dfGamma));
Packit 7838c8
	}
Packit 7838c8
Packit 7838c8
	/* Init reference white point */
Packit 7838c8
	cielab->X0 = refWhite[0];
Packit 7838c8
	cielab->Y0 = refWhite[1];
Packit 7838c8
	cielab->Z0 = refWhite[2];
Packit 7838c8
Packit 7838c8
	return 0;
Packit 7838c8
}
Packit 7838c8
Packit 7838c8
/* 
Packit 7838c8
 * Convert color value from the YCbCr space to CIE XYZ.
Packit 7838c8
 * The colorspace conversion algorithm comes from the IJG v5a code;
Packit 7838c8
 * see below for more information on how it works.
Packit 7838c8
 */
Packit 7838c8
#define	SHIFT			16
Packit 7838c8
#define	FIX(x)			((int32)((x) * (1L<
Packit 7838c8
#define	ONE_HALF		((int32)(1<<(SHIFT-1)))
Packit 7838c8
#define	Code2V(c, RB, RW, CR)	((((c)-(int32)(RB))*(float)(CR))/(float)(((RW)-(RB)!=0) ? ((RW)-(RB)) : 1))
Packit 7838c8
#define	CLAMP(f,min,max)	((f)<(min)?(min):(f)>(max)?(max):(f))
Packit 7838c8
#define HICLAMP(f,max)		((f)>(max)?(max):(f))
Packit 7838c8
Packit 7838c8
void
Packit 7838c8
TIFFYCbCrtoRGB(TIFFYCbCrToRGB *ycbcr, uint32 Y, int32 Cb, int32 Cr,
Packit 7838c8
	       uint32 *r, uint32 *g, uint32 *b)
Packit 7838c8
{
Packit 7838c8
	int32 i;
Packit 7838c8
Packit 7838c8
	/* XXX: Only 8-bit YCbCr input supported for now */
Packit 7838c8
	Y = HICLAMP(Y, 255);
Packit 7838c8
	Cb = CLAMP(Cb, 0, 255);
Packit 7838c8
	Cr = CLAMP(Cr, 0, 255);
Packit 7838c8
Packit 7838c8
	i = ycbcr->Y_tab[Y] + ycbcr->Cr_r_tab[Cr];
Packit 7838c8
	*r = CLAMP(i, 0, 255);
Packit 7838c8
	i = ycbcr->Y_tab[Y]
Packit 7838c8
	    + (int)((ycbcr->Cb_g_tab[Cb] + ycbcr->Cr_g_tab[Cr]) >> SHIFT);
Packit 7838c8
	*g = CLAMP(i, 0, 255);
Packit 7838c8
	i = ycbcr->Y_tab[Y] + ycbcr->Cb_b_tab[Cb];
Packit 7838c8
	*b = CLAMP(i, 0, 255);
Packit 7838c8
}
Packit 7838c8
Packit 7838c8
/* Clamp function for sanitization purposes. Normally clamping should not */
Packit 7838c8
/* occur for well behaved chroma and refBlackWhite coefficients */
Packit 7838c8
static float CLAMPw(float v, float vmin, float vmax)
Packit 7838c8
{
Packit 7838c8
    if( v < vmin )
Packit 7838c8
    {
Packit 7838c8
        /* printf("%f clamped to %f\n", v, vmin); */
Packit 7838c8
        return vmin;
Packit 7838c8
    }
Packit 7838c8
    if( v > vmax )
Packit 7838c8
    {
Packit 7838c8
        /* printf("%f clamped to %f\n", v, vmax); */
Packit 7838c8
        return vmax;
Packit 7838c8
    }
Packit 7838c8
    return v;
Packit 7838c8
}
Packit 7838c8
Packit 7838c8
/*
Packit 7838c8
 * Initialize the YCbCr->RGB conversion tables.  The conversion
Packit 7838c8
 * is done according to the 6.0 spec:
Packit 7838c8
 *
Packit 7838c8
 *    R = Y + Cr*(2 - 2*LumaRed)
Packit 7838c8
 *    B = Y + Cb*(2 - 2*LumaBlue)
Packit 7838c8
 *    G =   Y
Packit 7838c8
 *        - LumaBlue*Cb*(2-2*LumaBlue)/LumaGreen
Packit 7838c8
 *        - LumaRed*Cr*(2-2*LumaRed)/LumaGreen
Packit 7838c8
 *
Packit 7838c8
 * To avoid floating point arithmetic the fractional constants that
Packit 7838c8
 * come out of the equations are represented as fixed point values
Packit 7838c8
 * in the range 0...2^16.  We also eliminate multiplications by
Packit 7838c8
 * pre-calculating possible values indexed by Cb and Cr (this code
Packit 7838c8
 * assumes conversion is being done for 8-bit samples).
Packit 7838c8
 */
Packit 7838c8
int
Packit 7838c8
TIFFYCbCrToRGBInit(TIFFYCbCrToRGB* ycbcr, float *luma, float *refBlackWhite)
Packit 7838c8
{
Packit 7838c8
    TIFFRGBValue* clamptab;
Packit 7838c8
    int i;
Packit 7838c8
    
Packit 7838c8
#define LumaRed	    luma[0]
Packit 7838c8
#define LumaGreen   luma[1]
Packit 7838c8
#define LumaBlue    luma[2]
Packit 7838c8
Packit 7838c8
    clamptab = (TIFFRGBValue*)(
Packit 7838c8
	(uint8*) ycbcr+TIFFroundup_32(sizeof (TIFFYCbCrToRGB), sizeof (long)));  
Packit 7838c8
    _TIFFmemset(clamptab, 0, 256);		/* v < 0 => 0 */
Packit 7838c8
    ycbcr->clamptab = (clamptab += 256);
Packit 7838c8
    for (i = 0; i < 256; i++)
Packit 7838c8
	clamptab[i] = (TIFFRGBValue) i;
Packit 7838c8
    _TIFFmemset(clamptab+256, 255, 2*256);	/* v > 255 => 255 */
Packit 7838c8
    ycbcr->Cr_r_tab = (int*) (clamptab + 3*256);
Packit 7838c8
    ycbcr->Cb_b_tab = ycbcr->Cr_r_tab + 256;
Packit 7838c8
    ycbcr->Cr_g_tab = (int32*) (ycbcr->Cb_b_tab + 256);
Packit 7838c8
    ycbcr->Cb_g_tab = ycbcr->Cr_g_tab + 256;
Packit 7838c8
    ycbcr->Y_tab = ycbcr->Cb_g_tab + 256;
Packit 7838c8
Packit 7838c8
    { float f1 = 2-2*LumaRed;		int32 D1 = FIX(CLAMP(f1,0.0F,2.0F));
Packit 7838c8
      float f2 = LumaRed*f1/LumaGreen;	int32 D2 = -FIX(CLAMP(f2,0.0F,2.0F));
Packit 7838c8
      float f3 = 2-2*LumaBlue;		int32 D3 = FIX(CLAMP(f3,0.0F,2.0F));
Packit 7838c8
      float f4 = LumaBlue*f3/LumaGreen;	int32 D4 = -FIX(CLAMP(f4,0.0F,2.0F));
Packit 7838c8
      int x;
Packit 7838c8
Packit 7838c8
#undef LumaBlue
Packit 7838c8
#undef LumaGreen
Packit 7838c8
#undef LumaRed
Packit 7838c8
      
Packit 7838c8
      /*
Packit 7838c8
       * i is the actual input pixel value in the range 0..255
Packit 7838c8
       * Cb and Cr values are in the range -128..127 (actually
Packit 7838c8
       * they are in a range defined by the ReferenceBlackWhite
Packit 7838c8
       * tag) so there is some range shifting to do here when
Packit 7838c8
       * constructing tables indexed by the raw pixel data.
Packit 7838c8
       */
Packit 7838c8
      for (i = 0, x = -128; i < 256; i++, x++) {
Packit 7838c8
	    int32 Cr = (int32)CLAMPw(Code2V(x, refBlackWhite[4] - 128.0F,
Packit 7838c8
			    refBlackWhite[5] - 128.0F, 127),
Packit 7838c8
                            -128.0F * 32, 128.0F * 32);
Packit 7838c8
	    int32 Cb = (int32)CLAMPw(Code2V(x, refBlackWhite[2] - 128.0F,
Packit 7838c8
			    refBlackWhite[3] - 128.0F, 127),
Packit 7838c8
                            -128.0F * 32, 128.0F * 32);
Packit 7838c8
Packit 7838c8
	    ycbcr->Cr_r_tab[i] = (int32)((D1*Cr + ONE_HALF)>>SHIFT);
Packit 7838c8
	    ycbcr->Cb_b_tab[i] = (int32)((D3*Cb + ONE_HALF)>>SHIFT);
Packit 7838c8
	    ycbcr->Cr_g_tab[i] = D2*Cr;
Packit 7838c8
	    ycbcr->Cb_g_tab[i] = D4*Cb + ONE_HALF;
Packit 7838c8
	    ycbcr->Y_tab[i] =
Packit 7838c8
		    (int32)CLAMPw(Code2V(x + 128, refBlackWhite[0], refBlackWhite[1], 255),
Packit 7838c8
                                  -128.0F * 32, 128.0F * 32);
Packit 7838c8
      }
Packit 7838c8
    }
Packit 7838c8
Packit 7838c8
    return 0;
Packit 7838c8
}
Packit 7838c8
#undef	HICLAMP
Packit 7838c8
#undef	CLAMP
Packit 7838c8
#undef	Code2V
Packit 7838c8
#undef	SHIFT
Packit 7838c8
#undef	ONE_HALF
Packit 7838c8
#undef	FIX
Packit 7838c8
Packit 7838c8
/* vim: set ts=8 sts=8 sw=8 noet: */
Packit 7838c8
/*
Packit 7838c8
 * Local Variables:
Packit 7838c8
 * mode: c
Packit 7838c8
 * c-basic-offset: 8
Packit 7838c8
 * fill-column: 78
Packit 7838c8
 * End:
Packit 7838c8
 */