uvY.c revision 61b2299d
1/* $Xorg: uvY.c,v 1.3 2000/08/17 19:45:23 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 *		CIEuvy.c
29 *
30 *	DESCRIPTION
31 *		This file contains routines that support the CIE u'v'Y
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 */
38/* $XFree86: xc/lib/X11/uvY.c,v 1.3 2001/01/17 19:41:57 dawes Exp $ */
39
40#ifdef HAVE_CONFIG_H
41#include <config.h>
42#endif
43#include <X11/Xos.h>
44#include "Xlibint.h"
45#include "Xcmsint.h"
46#include "Cv.h"
47
48#include <stdio.h>
49
50/*
51 *	FORWARD DECLARATIONS
52 */
53static int CIEuvY_ParseString(register char *spec, XcmsColor *pColor);
54
55/*
56 *	DEFINES
57 *		Internal definitions that need NOT be exported to any package
58 *		or program using this package.
59 */
60#ifdef DBL_EPSILON
61#  define XMY_DBL_EPSILON DBL_EPSILON
62#else
63#  define XMY_DBL_EPSILON 0.00001
64#endif
65
66
67/*
68 *	LOCAL VARIABLES
69 */
70
71    /*
72     * NULL terminated list of functions applied to get from CIEuvY to CIEXYZ
73     */
74static XcmsConversionProc Fl_CIEuvY_to_CIEXYZ[] = {
75    XcmsCIEuvYToCIEXYZ,
76    NULL
77};
78
79    /*
80     * NULL terminated list of functions applied to get from CIEXYZ to CIEuvY
81     */
82static XcmsConversionProc Fl_CIEXYZ_to_CIEuvY[] = {
83    XcmsCIEXYZToCIEuvY,
84    NULL
85};
86
87
88/*
89 *	GLOBALS
90 */
91
92    /*
93     * CIE uvY Color Space
94     */
95XcmsColorSpace	XcmsCIEuvYColorSpace =
96    {
97	_XcmsCIEuvY_prefix,		/* prefix */
98	XcmsCIEuvYFormat,		/* id */
99	CIEuvY_ParseString,	/* parseString */
100	Fl_CIEuvY_to_CIEXYZ,	/* to_CIEXYZ */
101	Fl_CIEXYZ_to_CIEuvY,	/* from_CIEXYZ */
102	1
103    };
104
105
106
107/************************************************************************
108 *									*
109 *			 PRIVATE ROUTINES				*
110 *									*
111 ************************************************************************/
112
113/*
114 *	NAME
115 *		CIEuvY_ParseString
116 *
117 *	SYNOPSIS
118 */
119static int
120CIEuvY_ParseString(
121    register char *spec,
122    XcmsColor *pColor)
123/*
124 *	DESCRIPTION
125 *		This routines takes a string and attempts to convert
126 *		it into a XcmsColor structure with XcmsCIEuvYFormat.
127 *		The assumed CIEuvY string syntax is:
128 *		    CIEuvY:<u>/<v>/<Y>
129 *		Where u, v, and Y are in string input format for floats
130 *		consisting of:
131 *		    a. an optional sign
132 *		    b. a string of numbers possibly containing a decimal point,
133 *		    c. an optional exponent field containing an 'E' or 'e'
134 *			followed by a possibly signed integer string.
135 *
136 *	RETURNS
137 *		0 if failed, non-zero otherwise.
138 */
139{
140    int n;
141    char *pchar;
142
143    if ((pchar = strchr(spec, ':')) == NULL) {
144	return(XcmsFailure);
145    }
146    n = (int)(pchar - spec);
147
148    /*
149     * Check for proper prefix.
150     */
151    if (strncmp(spec, _XcmsCIEuvY_prefix, n) != 0) {
152	return(XcmsFailure);
153    }
154
155    /*
156     * Attempt to parse the value portion.
157     */
158    if (sscanf(spec + n + 1, "%lf/%lf/%lf",
159	    &pColor->spec.CIEuvY.u_prime,
160	    &pColor->spec.CIEuvY.v_prime,
161	    &pColor->spec.CIEuvY.Y) != 3) {
162        char *s; /* Maybe failed due to locale */
163        int f;
164        if ((s = strdup(spec))) {
165            for (f = 0; s[f]; ++f)
166                if (s[f] == '.')
167                    s[f] = ',';
168                else if (s[f] == ',')
169                    s[f] = '.';
170	    if (sscanf(s + n + 1, "%lf/%lf/%lf",
171		       &pColor->spec.CIEuvY.u_prime,
172		       &pColor->spec.CIEuvY.v_prime,
173		       &pColor->spec.CIEuvY.Y) != 3) {
174                free(s);
175                return(XcmsFailure);
176            }
177            free(s);
178        } else
179	    return(XcmsFailure);
180    }
181    pColor->format = XcmsCIEuvYFormat;
182    pColor->pixel = 0;
183    return(_XcmsCIEuvY_ValidSpec(pColor));
184}
185
186
187/************************************************************************
188 *									*
189 *			 PUBLIC ROUTINES				*
190 *									*
191 ************************************************************************/
192
193/*
194 *	NAME
195 *		XcmsCIEuvY_ValidSpec
196 *
197 *	SYNOPSIS
198 */
199Status
200_XcmsCIEuvY_ValidSpec(
201    XcmsColor *pColor)
202/*
203 *	DESCRIPTION
204 *		Checks if color specification valid for CIE u'v'Y.
205 *
206 *	RETURNS
207 *		XcmsFailure if invalid,
208 *		XcmsSuccess if valid.
209 *
210 */
211{
212    if (pColor->format != XcmsCIEuvYFormat
213	    ||
214	    (pColor->spec.CIEuvY.Y < 0.0 - XMY_DBL_EPSILON)
215	    ||
216	    (pColor->spec.CIEuvY.Y > 1.0 + XMY_DBL_EPSILON)) {
217	return(XcmsFailure);
218    }
219    return(XcmsSuccess);
220}
221
222
223/*
224 *	NAME
225 *		XcmsCIEuvYToCIEXYZ - convert CIEuvY to CIEXYZ
226 *
227 *	SYNOPSIS
228 */
229Status
230XcmsCIEuvYToCIEXYZ(
231    XcmsCCC ccc,
232    XcmsColor *puvY_WhitePt,
233    XcmsColor *pColors_in_out,
234    unsigned int nColors)
235/*
236 *	DESCRIPTION
237 *		Converts color specifications in an array of XcmsColor
238 *		structures from CIEuvY format to CIEXYZ format.
239 *
240 *	RETURNS
241 *		XcmsFailure if failed,
242 *		XcmsSuccess if succeeded.
243 *
244 */
245{
246    XcmsCIEXYZ XYZ_return;
247    XcmsColor whitePt;
248    int i;
249    XcmsColor *pColor = pColors_in_out;
250    XcmsFloat div, x, y, z, Y;
251
252    /*
253     * Check arguments
254     *	Postpone checking puvY_WhitePt until it is actually needed
255     *	otherwise converting between XYZ and uvY will fail.
256     */
257    if (pColors_in_out == NULL) {
258	return(XcmsFailure);
259    }
260
261
262    /*
263     * Now convert each XcmsColor structure to CIEXYZ form
264     */
265    for (i = 0; i < nColors; i++, pColor++) {
266
267	/* Make sure original format is CIEuvY */
268	if (!_XcmsCIEuvY_ValidSpec(pColor)) {
269	    return(XcmsFailure);
270	}
271
272	/*
273	 * Convert to CIEXYZ
274	 */
275
276	Y = pColor->spec.CIEuvY.Y;
277
278	/* Convert color u'v' to xyz space */
279	div = (6.0 * pColor->spec.CIEuvY.u_prime) - (16.0 * pColor->spec.CIEuvY.v_prime) + 12.0;
280	if (div == 0.0) {
281	    /* use white point since div == 0 */
282	    if (puvY_WhitePt == NULL ) {
283		return(XcmsFailure);
284	    }
285	    /*
286	     * Make sure white point is in CIEuvY form
287	     */
288	    if (puvY_WhitePt->format != XcmsCIEuvYFormat) {
289		/* Make copy of the white point because we're going to modify it */
290		memcpy((char *)&whitePt, (char *)puvY_WhitePt, sizeof(XcmsColor));
291		if (!_XcmsDIConvertColors(ccc, &whitePt, (XcmsColor *)NULL, 1,
292			XcmsCIEuvYFormat)) {
293		    return(XcmsFailure);
294		}
295		puvY_WhitePt = &whitePt;
296	    }
297	    /* Make sure it is a white point, i.e., Y == 1.0 */
298	    if (puvY_WhitePt->spec.CIEuvY.Y != 1.0) {
299		return(XcmsFailure);
300	    }
301	    div = (6.0 * puvY_WhitePt->spec.CIEuvY.u_prime) -
302		    (16.0 * puvY_WhitePt->spec.CIEuvY.v_prime) + 12.0;
303	    if (div == 0) {
304		/* internal error */
305		return(XcmsFailure);
306	    }
307	    x = 9.0 * puvY_WhitePt->spec.CIEuvY.u_prime / div;
308	    y = 4.0 * puvY_WhitePt->spec.CIEuvY.v_prime / div;
309	} else {
310	    x = 9.0 * pColor->spec.CIEuvY.u_prime / div;
311	    y = 4.0 * pColor->spec.CIEuvY.v_prime / div;
312	}
313	z = 1.0 - x - y;
314
315	/* Convert from xyz to XYZ */
316	/* Conversion uses color normalized lightness based on Y */
317	if (y != 0.0) {
318	    XYZ_return.X = x * Y / y;
319	} else {
320	    XYZ_return.X = x;
321	}
322	XYZ_return.Y = Y;
323	if (y != 0.0) {
324	    XYZ_return.Z = z * Y / y;
325	} else {
326	    XYZ_return.Z = z;
327	}
328
329	memcpy((char *)&pColor->spec.CIEXYZ, (char *)&XYZ_return, sizeof(XcmsCIEXYZ));
330	/* Identify that format is now CIEXYZ */
331	pColor->format = XcmsCIEXYZFormat;
332    }
333
334    return(XcmsSuccess);
335}
336
337
338/*
339 *	NAME
340 *		XcmsCIEXYZToCIEuvY - convert CIEXYZ to CIEuvY
341 *
342 *	SYNOPSIS
343 */
344Status
345XcmsCIEXYZToCIEuvY(
346    XcmsCCC ccc,
347    XcmsColor *puvY_WhitePt,
348    XcmsColor *pColors_in_out,
349    unsigned int nColors)
350/*
351 *	DESCRIPTION
352 *		Converts color specifications in an array of XcmsColor
353 *		structures from CIEXYZ format to CIEuvY format.
354 *
355 *	RETURNS
356 *		XcmsFailure if failed,
357 *		XcmsSuccess if succeeded.
358 *
359 */
360{
361    XcmsCIEuvY uvY_return;
362    XcmsColor whitePt;
363    int i;
364    XcmsColor *pColor = pColors_in_out;
365    XcmsFloat div;
366
367    /*
368     * Check arguments
369     *	Postpone checking puvY_WhitePt until it is actually needed
370     *	otherwise converting between XYZ and uvY will fail.
371     */
372    if (pColors_in_out == NULL) {
373	return(XcmsFailure);
374    }
375
376    /*
377     * Now convert each XcmsColor structure to CIEuvY form
378     */
379    for (i = 0; i < nColors; i++, pColor++) {
380
381	/* Make sure original format is CIEXYZ */
382	if (!_XcmsCIEXYZ_ValidSpec(pColor)) {
383	    return(XcmsFailure);
384	}
385
386	/* Convert to CIEuvY */
387	div = pColor->spec.CIEXYZ.X + (15.0 * pColor->spec.CIEXYZ.Y) +
388		(3.0 * pColor->spec.CIEXYZ.Z);
389	if (div == 0.0) {
390	    /* Use white point since div == 0.0 */
391	    if (puvY_WhitePt == NULL ) {
392		return(XcmsFailure);
393	    }
394	    /*
395	     * Make sure white point is in CIEuvY form
396	     */
397	    if (puvY_WhitePt->format != XcmsCIEuvYFormat) {
398		/* Make copy of the white point because we're going to modify it */
399		memcpy((char *)&whitePt, (char *)puvY_WhitePt, sizeof(XcmsColor));
400		if (!_XcmsDIConvertColors(ccc, &whitePt, (XcmsColor *)NULL, 1,
401			XcmsCIEuvYFormat)) {
402		    return(XcmsFailure);
403		}
404		puvY_WhitePt = &whitePt;
405	    }
406	    /* Make sure it is a white point, i.e., Y == 1.0 */
407	    if (puvY_WhitePt->spec.CIEuvY.Y != 1.0) {
408		return(XcmsFailure);
409	    }
410	    uvY_return.Y = pColor->spec.CIEXYZ.Y;
411	    uvY_return.u_prime = puvY_WhitePt->spec.CIEuvY.u_prime;
412	    uvY_return.v_prime = puvY_WhitePt->spec.CIEuvY.v_prime;
413	} else {
414	    uvY_return.u_prime = 4.0 * pColor->spec.CIEXYZ.X / div;
415	    uvY_return.v_prime = 9.0 * pColor->spec.CIEXYZ.Y / div;
416	    uvY_return.Y = pColor->spec.CIEXYZ.Y;
417	}
418
419	memcpy((char *)&pColor->spec.CIEuvY, (char *)&uvY_return, sizeof(XcmsCIEuvY));
420	/* Identify that format is now CIEuvY */
421	pColor->format = XcmsCIEuvYFormat;
422    }
423
424    return(XcmsSuccess);
425}
426