Luv.c revision 1ab64890
1/* $Xorg: Luv.c,v 1.3 2000/08/17 19:44:41 cpqbld Exp $ */
2
3/*
4 * Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc.
5 * 	All Rights Reserved
6 *
7 * This file is a component of an X Window System-specific implementation
8 * of XCMS based on the TekColor Color Management System.  Permission is
9 * hereby granted to use, copy, modify, sell, and otherwise distribute this
10 * software and its documentation for any purpose and without fee, provided
11 * that this copyright, permission, and disclaimer notice is reproduced in
12 * all copies of this software and in supporting documentation.  TekColor
13 * is a trademark of Tektronix, Inc.
14 *
15 * Tektronix makes no representation about the suitability of this software
16 * for any purpose.  It is provided "as is" and with all faults.
17 *
18 * TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE,
19 * INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE.  IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY
21 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
22 * RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF
23 * CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
24 * CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE.
25 *
26 *
27 *	NAME
28 *		CIELuv.c
29 *
30 *	DESCRIPTION
31 *		This file contains routines that support the CIE L*u*v*
32 *		color space to include conversions to and from the CIE
33 *		XYZ space.
34 *
35 *	DOCUMENTATION
36 *		"TekColor Color Management System, System Implementor's Manual"
37 *		and
38 *		Fred W. Billmeyer & Max Saltzman, "Principles of Color
39 *		Technology", John Wily & Sons, Inc, 1981.
40 */
41/* $XFree86: xc/lib/X11/Luv.c,v 1.3 2001/01/17 19:41:39 dawes Exp $ */
42
43#ifdef HAVE_CONFIG_H
44#include <config.h>
45#endif
46#include <X11/Xos.h>
47#include "Xlibint.h"
48#include "Xcmsint.h"
49#include "Cv.h"
50
51#include <stdio.h> /* sscanf */
52
53
54/*
55 *	FORWARD DECLARATIONS
56 */
57
58static int CIELuv_ParseString(register char *spec, XcmsColor *pColor);
59static Status XcmsCIELuv_ValidSpec(XcmsColor *pColor);
60
61/*
62 *	DEFINES
63 *		Internal definitions that need NOT be exported to any package
64 *		or program using this package.
65 */
66#ifdef DBL_EPSILON
67#  define XMY_DBL_EPSILON DBL_EPSILON
68#else
69#  define XMY_DBL_EPSILON 0.00001
70#endif
71
72
73/*
74 *	LOCAL VARIABLES
75 */
76
77    /*
78     * NULL terminated list of functions applied to get from CIELuv to CIEXYZ
79     */
80static XcmsConversionProc Fl_CIELuv_to_CIEXYZ[] = {
81    XcmsCIELuvToCIEuvY,
82    XcmsCIEuvYToCIEXYZ,
83    NULL
84};
85
86    /*
87     * NULL terminated list of functions applied to get from CIEXYZ to CIELuv
88     */
89static XcmsConversionProc Fl_CIEXYZ_to_CIELuv[] = {
90    XcmsCIEXYZToCIEuvY,
91    XcmsCIEuvYToCIELuv,
92    NULL
93};
94
95/*
96 *	GLOBALS
97 */
98
99    /*
100     * CIE Luv Color Space
101     */
102XcmsColorSpace	XcmsCIELuvColorSpace =
103    {
104	_XcmsCIELuv_prefix,	/* prefix */
105	XcmsCIELuvFormat,		/* id */
106	CIELuv_ParseString,	/* parseString */
107	Fl_CIELuv_to_CIEXYZ,	/* to_CIEXYZ */
108	Fl_CIEXYZ_to_CIELuv,	/* from_CIEXYZ */
109	1
110    };
111
112
113/************************************************************************
114 *									*
115 *			 PRIVATE ROUTINES				*
116 *									*
117 ************************************************************************/
118
119/*
120 *	NAME
121 *		CIELuv_ParseString
122 *
123 *	SYNOPSIS
124 */
125static int
126CIELuv_ParseString(
127    register char *spec,
128    XcmsColor *pColor)
129/*
130 *	DESCRIPTION
131 *		This routines takes a string and attempts to convert
132 *		it into a XcmsColor structure with XcmsCIELuvFormat.
133 *		The assumed CIELuv string syntax is:
134 *		    CIELuv:<L>/<u>/<v>
135 *		Where L, u, and v are in string input format for floats
136 *		consisting of:
137 *		    a. an optional sign
138 *		    b. a string of numbers possibly containing a decimal point,
139 *		    c. an optional exponent field containing an 'E' or 'e'
140 *			followed by a possibly signed integer string.
141 *
142 *	RETURNS
143 *		0 if failed, non-zero otherwise.
144 */
145{
146    int n;
147    char *pchar;
148
149    if ((pchar = strchr(spec, ':')) == NULL) {
150	return(XcmsFailure);
151    }
152    n = (int)(pchar - spec);
153
154    /*
155     * Check for proper prefix.
156     */
157    if (strncmp(spec, _XcmsCIELuv_prefix, n) != 0) {
158	return(XcmsFailure);
159    }
160
161    /*
162     * Attempt to parse the value portion.
163     */
164    if (sscanf(spec + n + 1, "%lf/%lf/%lf",
165	    &pColor->spec.CIELuv.L_star,
166	    &pColor->spec.CIELuv.u_star,
167	    &pColor->spec.CIELuv.v_star) != 3) {
168        char *s; /* Maybe failed due to locale */
169        int f;
170        if ((s = strdup(spec))) {
171            for (f = 0; s[f]; ++f)
172                if (s[f] == '.')
173                    s[f] = ',';
174                else if (s[f] == ',')
175                    s[f] = '.';
176	    if (sscanf(s + n + 1, "%lf/%lf/%lf",
177		       &pColor->spec.CIELuv.L_star,
178		       &pColor->spec.CIELuv.u_star,
179		       &pColor->spec.CIELuv.v_star) != 3) {
180                free(s);
181                return(XcmsFailure);
182            }
183            free(s);
184        } else
185	return(XcmsFailure);
186    }
187    pColor->format = XcmsCIELuvFormat;
188    pColor->pixel = 0;
189    return(XcmsCIELuv_ValidSpec(pColor));
190}
191
192
193/************************************************************************
194 *									*
195 *			 PUBLIC ROUTINES				*
196 *									*
197 ************************************************************************/
198
199/*
200 *	NAME
201 *		XcmsCIELuv_ValidSpec
202 *
203 *	SYNOPSIS
204 */
205static Status
206XcmsCIELuv_ValidSpec(
207    XcmsColor *pColor)
208/*
209 *	DESCRIPTION
210 *		Checks if color specification valid for CIE L*u*v*.
211 *
212 *	RETURNS
213 *		XcmsFailure if invalid,
214 *		XcmsSuccess if valid.
215 *
216 */
217{
218    if (pColor->format != XcmsCIELuvFormat
219	    ||
220	    (pColor->spec.CIELuv.L_star < 0.0 - XMY_DBL_EPSILON)
221	    ||
222	    (pColor->spec.CIELuv.L_star > 100.0 + XMY_DBL_EPSILON)) {
223	return(XcmsFailure);
224    }
225    return(XcmsSuccess);
226}
227
228
229/*
230 *	NAME
231 *		XcmsCIELuvToCIEuvY - convert CIELuv to CIEuvY
232 *
233 *	SYNOPSIS
234 */
235Status
236XcmsCIELuvToCIEuvY(
237    XcmsCCC ccc,
238    XcmsColor *pLuv_WhitePt,
239    XcmsColor *pColors_in_out,
240    unsigned int nColors)
241/*
242 *	DESCRIPTION
243 *		Converts color specifications in an array of XcmsColor
244 *		structures from CIELuv format to CIEuvY format.
245 *
246 *	RETURNS
247 *		XcmsFailure if failed,
248 *		XcmsSuccess if succeeded.
249 *
250 */
251{
252    XcmsColor	*pColor = pColors_in_out;
253    XcmsColor	whitePt;
254    XcmsCIEuvY	uvY_return;
255    XcmsFloat	tmpVal;
256    register int i;
257
258    /*
259     * Check arguments
260     */
261    if (pLuv_WhitePt == NULL || pColors_in_out == NULL) {
262	return(XcmsFailure);
263    }
264
265    /*
266     * Make sure white point is in CIEuvY form
267     */
268    if (pLuv_WhitePt->format != XcmsCIEuvYFormat) {
269	/* Make copy of the white point because we're going to modify it */
270	memcpy((char *)&whitePt, (char *)pLuv_WhitePt, sizeof(XcmsColor));
271	if (!_XcmsDIConvertColors(ccc, &whitePt, (XcmsColor *)NULL,
272		1, XcmsCIEuvYFormat)) {
273	    return(XcmsFailure);
274	}
275	pLuv_WhitePt = &whitePt;
276    }
277    /* Make sure it is a white point, i.e., Y == 1.0 */
278    if (pLuv_WhitePt->spec.CIEuvY.Y != 1.0) {
279	return(XcmsFailure);
280    }
281
282    /*
283     * Now convert each XcmsColor structure to CIEXYZ form
284     */
285    for (i = 0; i < nColors; i++, pColor++) {
286
287	/* Make sure original format is CIELuv and is valid */
288	if (!XcmsCIELuv_ValidSpec(pColor)) {
289	    return(XcmsFailure);
290	}
291
292	if (pColor->spec.CIELuv.L_star < 7.99953624) {
293	    uvY_return.Y = pColor->spec.CIELuv.L_star / 903.29;
294	} else {
295	    tmpVal = (pColor->spec.CIELuv.L_star + 16.0) / 116.0;
296	    uvY_return.Y = tmpVal * tmpVal * tmpVal; /* tmpVal ** 3 */
297	}
298
299
300
301	if (pColor->spec.CIELuv.L_star == 0.0) {
302	    uvY_return.u_prime = pLuv_WhitePt->spec.CIEuvY.u_prime;
303	    uvY_return.v_prime = pLuv_WhitePt->spec.CIEuvY.v_prime;
304	} else {
305	    tmpVal = 13.0 * (pColor->spec.CIELuv.L_star / 100.0);
306	    uvY_return.u_prime = pColor->spec.CIELuv.u_star/tmpVal +
307			    pLuv_WhitePt->spec.CIEuvY.u_prime;
308	    uvY_return.v_prime = pColor->spec.CIELuv.v_star/tmpVal +
309			    pLuv_WhitePt->spec.CIEuvY.v_prime;
310	}
311	/* Copy result to pColor */
312	memcpy((char *)&pColor->spec, (char *)&uvY_return, sizeof(XcmsCIEuvY));
313
314	/* Identify that the format is now CIEuvY */
315	pColor->format = XcmsCIEuvYFormat;
316    }
317    return(XcmsSuccess);
318}
319
320
321/*
322 *	NAME
323 *		XcmsCIEuvYToCIELuv - convert CIEuvY to CIELuv
324 *
325 *	SYNOPSIS
326 */
327Status
328XcmsCIEuvYToCIELuv(
329    XcmsCCC ccc,
330    XcmsColor *pLuv_WhitePt,
331    XcmsColor *pColors_in_out,
332    unsigned int nColors)
333/*
334 *	DESCRIPTION
335 *		Converts color specifications in an array of XcmsColor
336 *		structures from CIEuvY format to CIELab format.
337 *
338 *	RETURNS
339 *		XcmsFailure if failed,
340 *		XcmsSuccess if succeeded.
341 *
342 */
343{
344    XcmsColor	*pColor = pColors_in_out;
345    XcmsColor	whitePt;
346    XcmsCIELuv	Luv_return;
347    XcmsFloat	tmpVal;
348    register int i;
349
350    /*
351     * Check arguments
352     */
353    if (pLuv_WhitePt == NULL || pColors_in_out == NULL) {
354	return(XcmsFailure);
355    }
356
357    /*
358     * Make sure white point is in CIEuvY form
359     */
360    if (pLuv_WhitePt->format != XcmsCIEuvYFormat) {
361	/* Make copy of the white point because we're going to modify it */
362	memcpy((char *)&whitePt, (char *)pLuv_WhitePt, sizeof(XcmsColor));
363	if (!_XcmsDIConvertColors(ccc, &whitePt,
364		(XcmsColor *)NULL, 1, XcmsCIEuvYFormat)) {
365	    return(XcmsFailure);
366	}
367	pLuv_WhitePt = &whitePt;
368    }
369    /* Make sure it is a white point, i.e., Y == 1.0 */
370    if (pLuv_WhitePt->spec.CIEuvY.Y != 1.0) {
371	return(XcmsFailure);
372    }
373
374    /*
375     * Now convert each XcmsColor structure to CIEXYZ form
376     */
377    for (i = 0; i < nColors; i++, pColor++) {
378
379	if (!_XcmsCIEuvY_ValidSpec(pColor)) {
380	    return(XcmsFailure);
381	}
382
383	/* Now convert the uvY to Luv */
384	Luv_return.L_star =
385	    (pColor->spec.CIEuvY.Y < 0.008856)
386	    ?
387	    (pColor->spec.CIEuvY.Y * 903.29)
388	    :
389	    ((XcmsFloat)(XCMS_CUBEROOT(pColor->spec.CIEuvY.Y) * 116.0) - 16.0);
390	tmpVal = 13.0 * (Luv_return.L_star / 100.0);
391	Luv_return.u_star = tmpVal *
392	   (pColor->spec.CIEuvY.u_prime - pLuv_WhitePt->spec.CIEuvY.u_prime);
393	Luv_return.v_star = tmpVal *
394	   (pColor->spec.CIEuvY.v_prime - pLuv_WhitePt->spec.CIEuvY.v_prime);
395
396	/* Copy result to pColor */
397	memcpy((char *)&pColor->spec, (char *)&Luv_return, sizeof(XcmsCIELuv));
398
399	/* Identify that the format is now CIEuvY */
400	pColor->format = XcmsCIELuvFormat;
401    }
402    return(XcmsSuccess);
403}
404