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