mirror of
https://github.com/Stichting-MINIX-Research-Foundation/xsrc.git
synced 2025-09-10 21:28:49 -04:00
1030 lines
26 KiB
C
1030 lines
26 KiB
C
/* $Xorg: CvCols.c,v 1.3 2000/08/17 19:44:32 cpqbld Exp $ */
|
||
|
||
/*
|
||
* Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc.
|
||
* All Rights Reserved
|
||
*
|
||
* This file is a component of an X Window System-specific implementation
|
||
* of Xcms based on the TekColor Color Management System. Permission is
|
||
* hereby granted to use, copy, modify, sell, and otherwise distribute this
|
||
* software and its documentation for any purpose and without fee, provided
|
||
* that this copyright, permission, and disclaimer notice is reproduced in
|
||
* all copies of this software and in supporting documentation. TekColor
|
||
* is a trademark of Tektronix, Inc.
|
||
*
|
||
* Tektronix makes no representation about the suitability of this software
|
||
* for any purpose. It is provided "as is" and with all faults.
|
||
*
|
||
* TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE,
|
||
* INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||
* PARTICULAR PURPOSE. IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY
|
||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||
* RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF
|
||
* CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||
* CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE.
|
||
*
|
||
*
|
||
* NAME
|
||
* XcmsCvCols.c
|
||
*
|
||
* DESCRIPTION
|
||
* Xcms API routine that converts between the
|
||
* device-independent color spaces.
|
||
*
|
||
*
|
||
*/
|
||
/* $XFree86: xc/lib/X11/CvCols.c,v 1.5 2003/11/03 03:46:26 dawes Exp $ */
|
||
|
||
#include "Xlibint.h"
|
||
#include "Xcmsint.h"
|
||
#include "Cv.h"
|
||
|
||
/*
|
||
* LOCAL DEFINES
|
||
*/
|
||
#define DD_FORMAT 0x01
|
||
#define DI_FORMAT 0x02
|
||
#define MIX_FORMAT 0x04
|
||
#ifndef MAX
|
||
# define MAX(x,y) ((x) > (y) ? (x) : (y))
|
||
#endif
|
||
|
||
|
||
/************************************************************************
|
||
* *
|
||
* PRIVATE ROUTINES *
|
||
* *
|
||
************************************************************************/
|
||
|
||
/*
|
||
* NAME
|
||
* EqualCIEXYZ
|
||
*
|
||
* SYNOPSIS
|
||
*/
|
||
static int
|
||
EqualCIEXYZ(
|
||
XcmsColor *p1, XcmsColor *p2)
|
||
/*
|
||
* DESCRIPTION
|
||
* Compares two XcmsColor structures that are in XcmsCIEXYZFormat
|
||
*
|
||
* RETURNS
|
||
* Returns 1 if equal; 0 otherwise.
|
||
*
|
||
*/
|
||
{
|
||
if (p1->format != XcmsCIEXYZFormat || p2->format != XcmsCIEXYZFormat) {
|
||
return(0);
|
||
}
|
||
if ((p1->spec.CIEXYZ.X != p2->spec.CIEXYZ.X)
|
||
|| (p1->spec.CIEXYZ.Y != p2->spec.CIEXYZ.Y)
|
||
|| (p1->spec.CIEXYZ.Z != p2->spec.CIEXYZ.Z)) {
|
||
return(0);
|
||
}
|
||
return(1);
|
||
}
|
||
|
||
|
||
/*
|
||
* NAME
|
||
* XcmsColorSpace
|
||
*
|
||
* SYNOPSIS
|
||
*/
|
||
static XcmsColorSpace *
|
||
ColorSpaceOfID(
|
||
XcmsCCC ccc,
|
||
XcmsColorFormat id)
|
||
/*
|
||
* DESCRIPTION
|
||
* Returns a pointer to the color space structure
|
||
* (XcmsColorSpace) associated with the specified color space
|
||
* ID.
|
||
*
|
||
* RETURNS
|
||
* Pointer to matching XcmsColorSpace structure if found;
|
||
* otherwise NULL.
|
||
*/
|
||
{
|
||
XcmsColorSpace **papColorSpaces;
|
||
|
||
if (ccc == NULL) {
|
||
return(NULL);
|
||
}
|
||
|
||
/*
|
||
* First try Device-Independent color spaces
|
||
*/
|
||
papColorSpaces = _XcmsDIColorSpaces;
|
||
if (papColorSpaces != NULL) {
|
||
while (*papColorSpaces != NULL) {
|
||
if ((*papColorSpaces)->id == id) {
|
||
return(*papColorSpaces);
|
||
}
|
||
papColorSpaces++;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Next try Device-Dependent color spaces
|
||
*/
|
||
papColorSpaces = ((XcmsFunctionSet *)ccc->pPerScrnInfo->functionSet)->DDColorSpaces;
|
||
if (papColorSpaces != NULL) {
|
||
while (*papColorSpaces != NULL) {
|
||
if ((*papColorSpaces)->id == id) {
|
||
return(*papColorSpaces);
|
||
}
|
||
papColorSpaces++;
|
||
}
|
||
}
|
||
|
||
return(NULL);
|
||
}
|
||
|
||
|
||
/*
|
||
* NAME
|
||
* ValidDIColorSpaceID
|
||
*
|
||
* SYNOPSIS
|
||
*/
|
||
static int
|
||
ValidDIColorSpaceID(
|
||
XcmsColorFormat id)
|
||
/*
|
||
* DESCRIPTION
|
||
* Determines if the specified color space ID is a valid
|
||
* Device-Independent color space in the specified Color
|
||
* Conversion Context.
|
||
*
|
||
* RETURNS
|
||
* Returns zero if not valid; otherwise non-zero.
|
||
*/
|
||
{
|
||
XcmsColorSpace **papRec;
|
||
papRec = _XcmsDIColorSpaces;
|
||
if (papRec != NULL) {
|
||
while (*papRec != NULL) {
|
||
if ((*papRec)->id == id) {
|
||
return(1);
|
||
}
|
||
papRec++;
|
||
}
|
||
}
|
||
return(0);
|
||
}
|
||
|
||
|
||
/*
|
||
* NAME
|
||
* ValidDDColorSpaceID
|
||
*
|
||
* SYNOPSIS
|
||
*/
|
||
static int
|
||
ValidDDColorSpaceID(
|
||
XcmsCCC ccc,
|
||
XcmsColorFormat id)
|
||
/*
|
||
* DESCRIPTION
|
||
* Determines if the specified color space ID is a valid
|
||
* Device-Dependent color space in the specified Color
|
||
* Conversion Context.
|
||
*
|
||
* RETURNS
|
||
* Returns zero if not valid; otherwise non-zero.
|
||
*/
|
||
{
|
||
XcmsColorSpace **papRec;
|
||
|
||
if (ccc->pPerScrnInfo->state != XcmsInitNone) {
|
||
papRec = ((XcmsFunctionSet *)ccc->pPerScrnInfo->functionSet)->DDColorSpaces;
|
||
while (*papRec != NULL) {
|
||
if ((*papRec)->id == id) {
|
||
return(1);
|
||
}
|
||
papRec++;
|
||
}
|
||
}
|
||
return(0);
|
||
}
|
||
|
||
|
||
/*
|
||
* NAME
|
||
* ConvertMixedColors - Convert XcmsColor structures
|
||
*
|
||
* SYNOPSIS
|
||
*/
|
||
static Status
|
||
ConvertMixedColors(
|
||
XcmsCCC ccc,
|
||
XcmsColor *pColors_in_out,
|
||
XcmsColor *pWhitePt,
|
||
unsigned int nColors,
|
||
XcmsColorFormat targetFormat,
|
||
unsigned char format_flag)
|
||
/*
|
||
* DESCRIPTION
|
||
* This routine will only convert the following types of
|
||
* batches:
|
||
* DI to DI
|
||
* DD to DD
|
||
* DD to CIEXYZ
|
||
* In other words, it will not convert the following types of
|
||
* batches:
|
||
* DI to DD
|
||
* DD to DI(not CIEXYZ)
|
||
*
|
||
* format_flag:
|
||
* 0x01 : convert Device-Dependent only specifications to the
|
||
* target format.
|
||
* 0x02 : convert Device-Independent only specifications to the
|
||
* target format.
|
||
* 0x03 : convert all specifications to the target format.
|
||
*
|
||
* RETURNS
|
||
* XcmsFailure if failed,
|
||
* XcmsSuccess if none of the color specifications were
|
||
* compressed in the conversion process
|
||
* XcmsSuccessWithCompression if at least one of the
|
||
* color specifications were compressed in the
|
||
* conversion process.
|
||
*
|
||
*/
|
||
{
|
||
XcmsColor *pColor, *pColors_start;
|
||
XcmsColorFormat format;
|
||
Status retval_tmp;
|
||
Status retval = XcmsSuccess;
|
||
unsigned int iColors;
|
||
unsigned int nBatch;
|
||
|
||
/*
|
||
* Convert array of mixed color specifications in batches of
|
||
* contiguous formats to the target format
|
||
*/
|
||
iColors = 0;
|
||
while (iColors < nColors) {
|
||
/*
|
||
* Find contiguous array of color specifications with the
|
||
* same format
|
||
*/
|
||
pColor = pColors_start = pColors_in_out + iColors;
|
||
format = pColors_start->format;
|
||
nBatch = 0;
|
||
while (iColors < nColors && pColor->format == format) {
|
||
pColor++;
|
||
nBatch++;
|
||
iColors++;
|
||
}
|
||
if (format != targetFormat) {
|
||
/*
|
||
* Need to convert this batch from current format to target format.
|
||
*/
|
||
if (XCMS_DI_ID(format) && (format_flag & DI_FORMAT) &&
|
||
XCMS_DI_ID(targetFormat)) {
|
||
/*
|
||
* DI->DI
|
||
*
|
||
* Format of interest is Device-Independent,
|
||
* This batch contains Device-Independent specifications, and
|
||
* the Target format is Device-Independent.
|
||
*/
|
||
retval_tmp = _XcmsDIConvertColors(ccc, pColors_start, pWhitePt,
|
||
nBatch, targetFormat);
|
||
} else if (XCMS_DD_ID(format) && (format_flag & DD_FORMAT) &&
|
||
(targetFormat == XcmsCIEXYZFormat)) {
|
||
/*
|
||
* DD->CIEXYZ
|
||
*
|
||
* Format of interest is Device-Dependent,
|
||
* This batch contains Device-Dependent specifications, and
|
||
* the Target format is CIEXYZ.
|
||
*
|
||
* Since DD->CIEXYZ we can use NULL instead of pCompressed.
|
||
*/
|
||
if ((ccc->whitePtAdjProc != NULL) && !_XcmsEqualWhitePts(ccc,
|
||
pWhitePt, ScreenWhitePointOfCCC(ccc))) {
|
||
/*
|
||
* Need to call WhiteAdjustProc (Screen White Point to
|
||
* White Point).
|
||
*/
|
||
retval_tmp = (*ccc->whitePtAdjProc)(ccc,
|
||
ScreenWhitePointOfCCC(ccc), pWhitePt,
|
||
XcmsCIEXYZFormat, pColors_start, nBatch,
|
||
(Bool *)NULL);
|
||
} else {
|
||
retval_tmp = _XcmsDDConvertColors(ccc, pColors_start,
|
||
nBatch, XcmsCIEXYZFormat, (Bool *)NULL);
|
||
}
|
||
} else if (XCMS_DD_ID(format) && (format_flag & DD_FORMAT) &&
|
||
XCMS_DD_ID(targetFormat)) {
|
||
/*
|
||
* DD->DD(not CIEXYZ)
|
||
*
|
||
* Format of interest is Device-Dependent,
|
||
* This batch contains Device-Dependent specifications, and
|
||
* the Target format is Device-Dependent and not CIEXYZ.
|
||
*/
|
||
retval_tmp = _XcmsDDConvertColors(ccc, pColors_start, nBatch,
|
||
targetFormat, (Bool *)NULL);
|
||
} else {
|
||
/*
|
||
* This routine is called for the wrong reason.
|
||
*/
|
||
return(XcmsFailure);
|
||
}
|
||
if (retval_tmp == XcmsFailure) {
|
||
return(XcmsFailure);
|
||
}
|
||
retval = MAX(retval, retval_tmp);
|
||
}
|
||
}
|
||
return(retval);
|
||
}
|
||
|
||
|
||
/************************************************************************
|
||
* *
|
||
* API PRIVATE ROUTINES *
|
||
* *
|
||
************************************************************************/
|
||
|
||
/*
|
||
* NAME
|
||
* _XcmsEqualWhitePts
|
||
*
|
||
* SYNOPSIS
|
||
*/
|
||
int
|
||
_XcmsEqualWhitePts(XcmsCCC ccc, XcmsColor *pWhitePt1, XcmsColor *pWhitePt2)
|
||
/*
|
||
* DESCRIPTION
|
||
*
|
||
* RETURNS
|
||
* Returns 0 if not equal; otherwise 1.
|
||
*
|
||
*/
|
||
{
|
||
XcmsColor tmp1, tmp2;
|
||
|
||
memcpy((char *)&tmp1, (char *)pWhitePt1, sizeof(XcmsColor));
|
||
memcpy((char *)&tmp2, (char *)pWhitePt2, sizeof(XcmsColor));
|
||
|
||
if (tmp1.format != XcmsCIEXYZFormat) {
|
||
if (_XcmsDIConvertColors(ccc, &tmp1, (XcmsColor *) NULL, 1,
|
||
XcmsCIEXYZFormat)==0) {
|
||
return(0);
|
||
}
|
||
}
|
||
|
||
if (tmp2.format != XcmsCIEXYZFormat) {
|
||
if (_XcmsDIConvertColors(ccc, &tmp2, (XcmsColor *) NULL, 1,
|
||
XcmsCIEXYZFormat)==0) {
|
||
return(0);
|
||
}
|
||
}
|
||
|
||
return (EqualCIEXYZ(&tmp1, &tmp2));
|
||
}
|
||
|
||
|
||
/*
|
||
* NAME
|
||
* _XcmsDIConvertColors - Convert XcmsColor structures
|
||
*
|
||
* SYNOPSIS
|
||
*/
|
||
Status
|
||
_XcmsDIConvertColors(
|
||
XcmsCCC ccc,
|
||
XcmsColor *pColors_in_out,
|
||
XcmsColor *pWhitePt,
|
||
unsigned int nColors,
|
||
XcmsColorFormat newFormat)
|
||
/*
|
||
* DESCRIPTION
|
||
* Convert XcmsColor structures to another Device-Independent
|
||
* form.
|
||
*
|
||
* Here are some assumptions that this routine makes:
|
||
* 1. The calling routine has already checked if
|
||
* pColors_in_out->format == newFormat, therefore
|
||
* there is no need to check again here.
|
||
* 2. The calling routine has already checked nColors,
|
||
* therefore this routine assumes nColors > 0.
|
||
* 3. The calling routine may want to convert only between
|
||
* CIExyY <-> CIEXYZ <-> CIEuvY
|
||
* therefore, this routine allows pWhitePt to equal NULL.
|
||
*
|
||
*
|
||
* RETURNS
|
||
* XcmsFailure if failed,
|
||
* XcmsSuccess if succeeded.
|
||
*
|
||
*/
|
||
{
|
||
XcmsColorSpace *pFrom, *pTo;
|
||
XcmsDIConversionProc *src_to_CIEXYZ, *src_from_CIEXYZ;
|
||
XcmsDIConversionProc *dest_to_CIEXYZ, *dest_from_CIEXYZ;
|
||
XcmsDIConversionProc *to_CIEXYZ_stop, *from_CIEXYZ_start;
|
||
XcmsDIConversionProc *tmp;
|
||
|
||
/*
|
||
* Allow pWhitePt to equal NULL. This appropriate when converting
|
||
* anywhere between:
|
||
* CIExyY <-> CIEXYZ <-> CIEuvY
|
||
*/
|
||
|
||
if (pColors_in_out == NULL ||
|
||
!ValidDIColorSpaceID(pColors_in_out->format) ||
|
||
!ValidDIColorSpaceID(newFormat)) {
|
||
return(XcmsFailure);
|
||
}
|
||
|
||
/*
|
||
* Get a handle on the function list for the current specification format
|
||
*/
|
||
if ((pFrom = ColorSpaceOfID(ccc, pColors_in_out->format))
|
||
== NULL) {
|
||
return(XcmsFailure);
|
||
}
|
||
|
||
/*
|
||
* Get a handle on the function list for the new specification format
|
||
*/
|
||
if ((pTo = ColorSpaceOfID(ccc, newFormat)) == NULL) {
|
||
return(XcmsFailure);
|
||
}
|
||
|
||
src_to_CIEXYZ = pFrom->to_CIEXYZ;
|
||
src_from_CIEXYZ = pFrom->from_CIEXYZ;
|
||
dest_to_CIEXYZ = pTo->to_CIEXYZ;
|
||
dest_from_CIEXYZ = pTo->from_CIEXYZ;
|
||
|
||
if (pTo->inverse_flag && pFrom->inverse_flag) {
|
||
/*
|
||
* Find common function pointers
|
||
*/
|
||
for (to_CIEXYZ_stop = src_to_CIEXYZ; *to_CIEXYZ_stop; to_CIEXYZ_stop++){
|
||
for (tmp = dest_to_CIEXYZ; *tmp; tmp++) {
|
||
if (*to_CIEXYZ_stop == *tmp) {
|
||
goto Continue;
|
||
}
|
||
}
|
||
}
|
||
|
||
Continue:
|
||
|
||
/*
|
||
* Execute the functions to CIEXYZ, stopping short as necessary
|
||
*/
|
||
while (src_to_CIEXYZ != to_CIEXYZ_stop) {
|
||
if ((*src_to_CIEXYZ++)(ccc, pWhitePt, pColors_in_out,
|
||
nColors) == XcmsFailure) {
|
||
return(XcmsFailure);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Determine where to start on the from_CIEXYZ path.
|
||
*/
|
||
from_CIEXYZ_start = dest_from_CIEXYZ;
|
||
tmp = src_from_CIEXYZ;
|
||
while ((*from_CIEXYZ_start == *tmp) && (*from_CIEXYZ_start != NULL)) {
|
||
from_CIEXYZ_start++;
|
||
tmp++;
|
||
}
|
||
|
||
} else {
|
||
/*
|
||
* The function in at least one of the Color Spaces are not
|
||
* complementary, i.e.,
|
||
* for an i, 0 <= i < n elements
|
||
* from_CIEXYZ[i] is not the inverse of to_CIEXYZ[i]
|
||
*
|
||
* Execute the functions all the way to CIEXYZ
|
||
*/
|
||
while (*src_to_CIEXYZ) {
|
||
if ((*src_to_CIEXYZ++)(ccc, pWhitePt, pColors_in_out,
|
||
nColors) == XcmsFailure) {
|
||
return(XcmsFailure);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Determine where to start on the from_CIEXYZ path.
|
||
*/
|
||
from_CIEXYZ_start = dest_from_CIEXYZ;
|
||
}
|
||
|
||
|
||
/*
|
||
* Execute the functions from CIEXYZ.
|
||
*/
|
||
while (*from_CIEXYZ_start) {
|
||
if ((*from_CIEXYZ_start++)(ccc, pWhitePt, pColors_in_out,
|
||
nColors) == XcmsFailure) {
|
||
return(XcmsFailure);
|
||
}
|
||
}
|
||
|
||
return(XcmsSuccess);
|
||
}
|
||
|
||
|
||
/*
|
||
* NAME
|
||
* _XcmsDDConvertColors - Convert XcmsColor structures
|
||
*
|
||
* SYNOPSIS
|
||
*/
|
||
Status
|
||
_XcmsDDConvertColors(
|
||
XcmsCCC ccc,
|
||
XcmsColor *pColors_in_out,
|
||
unsigned int nColors,
|
||
XcmsColorFormat newFormat,
|
||
Bool *pCompressed)
|
||
/*
|
||
* DESCRIPTION
|
||
* Convert XcmsColor structures:
|
||
*
|
||
* 1. From CIEXYZ to Device-Dependent formats (typically RGB and
|
||
* RGBi),
|
||
* or
|
||
* 2. Between Device-Dependent formats (typically RGB and RGBi).
|
||
*
|
||
* Assumes that these specifications have already been white point
|
||
* adjusted if necessary from Client White Point to Screen
|
||
* White Point. Therefore, the white point now associated
|
||
* with the specifications is the Screen White Point.
|
||
*
|
||
* pCompressed may be NULL. If so this indicates that the
|
||
* calling routine is not interested in knowing exactly which
|
||
* color was compressed, if any.
|
||
*
|
||
*
|
||
* RETURNS
|
||
* XcmsFailure if failed,
|
||
* XcmsSuccess if none of the color specifications were
|
||
* compressed in the conversion process
|
||
* XcmsSuccessWithCompression if at least one of the
|
||
* color specifications were compressed in the
|
||
* conversion process.
|
||
*
|
||
*/
|
||
{
|
||
XcmsColorSpace *pFrom, *pTo;
|
||
XcmsDDConversionProc *src_to_CIEXYZ, *src_from_CIEXYZ;
|
||
XcmsDDConversionProc *dest_to_CIEXYZ, *dest_from_CIEXYZ;
|
||
XcmsDDConversionProc *from_CIEXYZ_start, *to_CIEXYZ_stop;
|
||
XcmsDDConversionProc *tmp;
|
||
int retval;
|
||
int hasCompressed = 0;
|
||
|
||
if (ccc == NULL || pColors_in_out == NULL) {
|
||
return(XcmsFailure);
|
||
}
|
||
|
||
if (nColors == 0 || pColors_in_out->format == newFormat) {
|
||
/* do nothing */
|
||
return(XcmsSuccess);
|
||
}
|
||
|
||
if (((XcmsFunctionSet *)ccc->pPerScrnInfo->functionSet) == NULL) {
|
||
return(XcmsFailure); /* hmm, an internal error? */
|
||
}
|
||
|
||
/*
|
||
* Its ok if pColors_in_out->format == XcmsCIEXYZFormat
|
||
* or
|
||
* if newFormat == XcmsCIEXYZFormat
|
||
*/
|
||
if ( !( ValidDDColorSpaceID(ccc, pColors_in_out->format)
|
||
||
|
||
(pColors_in_out->format == XcmsCIEXYZFormat))
|
||
||
|
||
!(ValidDDColorSpaceID(ccc, newFormat)
|
||
||
|
||
newFormat == XcmsCIEXYZFormat)) {
|
||
return(XcmsFailure);
|
||
}
|
||
|
||
if ((pFrom = ColorSpaceOfID(ccc, pColors_in_out->format)) == NULL){
|
||
return(XcmsFailure);
|
||
}
|
||
|
||
if ((pTo = ColorSpaceOfID(ccc, newFormat)) == NULL) {
|
||
return(XcmsFailure);
|
||
}
|
||
|
||
src_to_CIEXYZ = (XcmsDDConversionProc *)pFrom->to_CIEXYZ;
|
||
src_from_CIEXYZ = (XcmsDDConversionProc *)pFrom->from_CIEXYZ;
|
||
dest_to_CIEXYZ = (XcmsDDConversionProc *)pTo->to_CIEXYZ;
|
||
dest_from_CIEXYZ = (XcmsDDConversionProc *)pTo->from_CIEXYZ;
|
||
|
||
if (pTo->inverse_flag && pFrom->inverse_flag) {
|
||
/*
|
||
* Find common function pointers
|
||
*/
|
||
for (to_CIEXYZ_stop = src_to_CIEXYZ; *to_CIEXYZ_stop; to_CIEXYZ_stop++){
|
||
for (tmp = dest_to_CIEXYZ; *tmp; tmp++) {
|
||
if (*to_CIEXYZ_stop == *tmp) {
|
||
goto Continue;
|
||
}
|
||
}
|
||
}
|
||
Continue:
|
||
|
||
/*
|
||
* Execute the functions
|
||
*/
|
||
while (src_to_CIEXYZ != to_CIEXYZ_stop) {
|
||
retval = (*src_to_CIEXYZ++)(ccc, pColors_in_out, nColors,
|
||
pCompressed);
|
||
if (retval == XcmsFailure) {
|
||
return(XcmsFailure);
|
||
}
|
||
hasCompressed |= (retval == XcmsSuccessWithCompression);
|
||
}
|
||
|
||
/*
|
||
* Determine where to start on the from_CIEXYZ path.
|
||
*/
|
||
from_CIEXYZ_start = dest_from_CIEXYZ;
|
||
tmp = src_from_CIEXYZ;
|
||
while ((*from_CIEXYZ_start == *tmp) && (*from_CIEXYZ_start != NULL)) {
|
||
from_CIEXYZ_start++;
|
||
tmp++;
|
||
}
|
||
|
||
} else {
|
||
/*
|
||
* The function in at least one of the Color Spaces are not
|
||
* complementary, i.e.,
|
||
* for an i, 0 <= i < n elements
|
||
* from_CIEXYZ[i] is not the inverse of to_CIEXYZ[i]
|
||
*
|
||
* Execute the functions all the way to CIEXYZ
|
||
*/
|
||
while (*src_to_CIEXYZ) {
|
||
retval = (*src_to_CIEXYZ++)(ccc, pColors_in_out, nColors,
|
||
pCompressed);
|
||
if (retval == XcmsFailure) {
|
||
return(XcmsFailure);
|
||
}
|
||
hasCompressed |= (retval == XcmsSuccessWithCompression);
|
||
}
|
||
|
||
/*
|
||
* Determine where to start on the from_CIEXYZ path.
|
||
*/
|
||
from_CIEXYZ_start = dest_from_CIEXYZ;
|
||
}
|
||
|
||
while (*from_CIEXYZ_start) {
|
||
retval = (*from_CIEXYZ_start++)(ccc, pColors_in_out, nColors,
|
||
pCompressed);
|
||
if (retval == XcmsFailure) {
|
||
return(XcmsFailure);
|
||
}
|
||
hasCompressed |= (retval == XcmsSuccessWithCompression);
|
||
}
|
||
|
||
return(hasCompressed ? XcmsSuccessWithCompression : XcmsSuccess);
|
||
}
|
||
|
||
|
||
/************************************************************************
|
||
* *
|
||
* PUBLIC ROUTINES *
|
||
* *
|
||
************************************************************************/
|
||
|
||
/*
|
||
* NAME
|
||
* XcmsConvertColors - Convert XcmsColor structures
|
||
*
|
||
* SYNOPSIS
|
||
*/
|
||
Status
|
||
XcmsConvertColors(ccc, pColors_in_out, nColors, targetFormat, pCompressed)
|
||
XcmsCCC ccc;
|
||
XcmsColor *pColors_in_out;
|
||
unsigned int nColors;
|
||
XcmsColorFormat targetFormat;
|
||
Bool *pCompressed;
|
||
/*
|
||
* DESCRIPTION
|
||
* Convert XcmsColor structures to another format
|
||
*
|
||
* RETURNS
|
||
* XcmsFailure if failed,
|
||
* XcmsSuccess if succeeded without gamut compression,
|
||
* XcmsSuccessWithCompression if succeeded with gamut
|
||
* compression.
|
||
*
|
||
*/
|
||
{
|
||
XcmsColor clientWhitePt;
|
||
XcmsColor Color1;
|
||
XcmsColor *pColors_tmp;
|
||
int callWhiteAdjustProc = 0;
|
||
XcmsColorFormat format;
|
||
Status retval;
|
||
unsigned char contents_flag = 0x00;
|
||
unsigned int iColors;
|
||
|
||
if (ccc == NULL || pColors_in_out == NULL ||
|
||
!(ValidDIColorSpaceID(targetFormat) ||
|
||
ValidDDColorSpaceID(ccc, targetFormat))) {
|
||
return(XcmsFailure);
|
||
}
|
||
|
||
/*
|
||
* Check formats in color specification array
|
||
*/
|
||
format = pColors_in_out->format;
|
||
for (pColors_tmp = pColors_in_out, iColors = nColors; iColors; pColors_tmp++, iColors--) {
|
||
if (!(ValidDIColorSpaceID(pColors_tmp->format) ||
|
||
ValidDDColorSpaceID(ccc, pColors_tmp->format))) {
|
||
return(XcmsFailure);
|
||
}
|
||
if (XCMS_DI_ID(pColors_tmp->format)) {
|
||
contents_flag |= DI_FORMAT;
|
||
} else {
|
||
contents_flag |= DD_FORMAT;
|
||
}
|
||
if (pColors_tmp->format != format) {
|
||
contents_flag |= MIX_FORMAT;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Check if we need the Client White Point.
|
||
*/
|
||
if ((contents_flag & DI_FORMAT) || XCMS_DI_ID(targetFormat)) {
|
||
/* To proceed, we need to get the Client White Point */
|
||
memcpy((char *)&clientWhitePt, (char *)&ccc->clientWhitePt,
|
||
sizeof(XcmsColor));
|
||
if (clientWhitePt.format == XcmsUndefinedFormat) {
|
||
/*
|
||
* Client White Point is undefined, therefore set to the Screen
|
||
* White Point.
|
||
* Since Client White Point == Screen White Point, WhiteAdjustProc
|
||
* is not called.
|
||
*/
|
||
memcpy((char *)&clientWhitePt,
|
||
(char *)&ccc->pPerScrnInfo->screenWhitePt,
|
||
sizeof(XcmsColor));
|
||
} else if ((ccc->whitePtAdjProc != NULL) && !_XcmsEqualWhitePts(ccc,
|
||
&clientWhitePt, ScreenWhitePointOfCCC(ccc))) {
|
||
/*
|
||
* Client White Point != Screen White Point, and WhiteAdjustProc
|
||
* is not NULL, therefore, will need to call it when
|
||
* converting between DI and DD specifications.
|
||
*/
|
||
callWhiteAdjustProc = 1;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Make copy of array of color specifications
|
||
*/
|
||
if (nColors > 1) {
|
||
pColors_tmp = (XcmsColor *) Xmalloc(nColors * sizeof(XcmsColor));
|
||
} else {
|
||
pColors_tmp = &Color1;
|
||
}
|
||
memcpy((char *)pColors_tmp, (char *)pColors_in_out,
|
||
nColors * sizeof(XcmsColor));
|
||
|
||
/*
|
||
* zero out pCompressed
|
||
*/
|
||
if (pCompressed) {
|
||
bzero((char *)pCompressed, nColors * sizeof(Bool));
|
||
}
|
||
|
||
if (contents_flag == DD_FORMAT || contents_flag == DI_FORMAT) {
|
||
/*
|
||
* ENTIRE ARRAY IS IN ONE FORMAT.
|
||
*/
|
||
if (XCMS_DI_ID(format) && XCMS_DI_ID(targetFormat)) {
|
||
/*
|
||
* DI-to-DI only conversion
|
||
*/
|
||
retval = _XcmsDIConvertColors(ccc, pColors_tmp,
|
||
&clientWhitePt, nColors, targetFormat);
|
||
} else if (XCMS_DD_ID(format) && XCMS_DD_ID(targetFormat)) {
|
||
/*
|
||
* DD-to-DD only conversion
|
||
* Since DD->DD there will be no compressed thus we can
|
||
* pass NULL instead of pCompressed.
|
||
*/
|
||
retval = _XcmsDDConvertColors(ccc, pColors_tmp, nColors,
|
||
targetFormat, (Bool *)NULL);
|
||
} else {
|
||
/*
|
||
* Otherwise we have:
|
||
* 1. Device-Independent to Device-Dependent Conversion
|
||
* OR
|
||
* 2. Device-Dependent to Device-Independent Conversion
|
||
*
|
||
* We need to go from oldFormat -> CIEXYZ -> targetFormat
|
||
* adjusting for white points as necessary.
|
||
*/
|
||
|
||
if (XCMS_DI_ID(format)) {
|
||
/*
|
||
* 1. Device-Independent to Device-Dependent Conversion
|
||
*/
|
||
if (callWhiteAdjustProc) {
|
||
/*
|
||
* White Point Adjustment
|
||
* Client White Point to Screen White Point
|
||
*/
|
||
retval = (*ccc->whitePtAdjProc)(ccc, &clientWhitePt,
|
||
ScreenWhitePointOfCCC(ccc), targetFormat,
|
||
pColors_tmp, nColors, pCompressed);
|
||
} else {
|
||
if (_XcmsDIConvertColors(ccc, pColors_tmp,
|
||
&clientWhitePt, nColors, XcmsCIEXYZFormat)
|
||
== XcmsFailure) {
|
||
goto Failure;
|
||
}
|
||
retval = _XcmsDDConvertColors(ccc, pColors_tmp, nColors,
|
||
targetFormat, pCompressed);
|
||
}
|
||
} else {
|
||
/*
|
||
* 2. Device-Dependent to Device-Independent Conversion
|
||
*/
|
||
if (callWhiteAdjustProc) {
|
||
/*
|
||
* White Point Adjustment
|
||
* Screen White Point to Client White Point
|
||
*/
|
||
retval = (*ccc->whitePtAdjProc)(ccc,
|
||
ScreenWhitePointOfCCC(ccc), &clientWhitePt,
|
||
targetFormat, pColors_tmp, nColors, pCompressed);
|
||
} else {
|
||
/*
|
||
* Since DD->CIEXYZ, no compression takes place therefore
|
||
* we can pass NULL instead of pCompressed.
|
||
*/
|
||
if (_XcmsDDConvertColors(ccc, pColors_tmp, nColors,
|
||
XcmsCIEXYZFormat, (Bool *)NULL) == XcmsFailure) {
|
||
goto Failure;
|
||
}
|
||
retval = _XcmsDIConvertColors(ccc, pColors_tmp,
|
||
&clientWhitePt, nColors, targetFormat);
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
/*
|
||
* ARRAY HAS MIXED FORMATS.
|
||
*/
|
||
if ((contents_flag == (DI_FORMAT | MIX_FORMAT)) &&
|
||
XCMS_DI_ID(targetFormat)) {
|
||
/*
|
||
* Convert from DI to DI in batches of contiguous formats
|
||
*
|
||
* Because DI->DI, WhiteAdjustProc not called.
|
||
*/
|
||
retval = ConvertMixedColors(ccc, pColors_tmp, &clientWhitePt,
|
||
nColors, targetFormat, (unsigned char)DI_FORMAT);
|
||
} else if ((contents_flag == (DD_FORMAT | MIX_FORMAT)) &&
|
||
XCMS_DD_ID(targetFormat)) {
|
||
/*
|
||
* Convert from DD to DD in batches of contiguous formats
|
||
*
|
||
* Because DD->DD, WhiteAdjustProc not called.
|
||
*/
|
||
retval = ConvertMixedColors(ccc, pColors_tmp,
|
||
(XcmsColor *)NULL, nColors, targetFormat,
|
||
(unsigned char)DD_FORMAT);
|
||
} else if (XCMS_DI_ID(targetFormat)) {
|
||
/*
|
||
* We need to convert from DI-to-DI and DD-to-DI, therefore
|
||
* 1. convert DD specifications to CIEXYZ, then
|
||
* 2. convert all in batches to the target DI format.
|
||
*
|
||
* Note that ConvertMixedColors will call WhiteAdjustProc
|
||
* as necessary.
|
||
*/
|
||
|
||
/*
|
||
* Convert only DD specifications in batches of contiguous formats
|
||
* to CIEXYZ
|
||
*
|
||
* Since DD->CIEXYZ, ConvertMixedColors will apply WhiteAdjustProc
|
||
* if required.
|
||
*/
|
||
retval = ConvertMixedColors(ccc, pColors_tmp, &clientWhitePt,
|
||
nColors, XcmsCIEXYZFormat, (unsigned char)DD_FORMAT);
|
||
|
||
/*
|
||
* Because at this point we may have a mix of DI formats
|
||
* (e.g., CIEXYZ, CIELuv) we must convert the specs to the
|
||
* target DI format in batches of contiguous source formats.
|
||
*/
|
||
retval = ConvertMixedColors(ccc, pColors_tmp, &clientWhitePt,
|
||
nColors, targetFormat, (unsigned char)DI_FORMAT);
|
||
} else {
|
||
/*
|
||
* We need to convert from DI-to-DD and DD-to-DD, therefore
|
||
* 1. convert DI specifications to CIEXYZ, then
|
||
* 2. convert all to the DD target format.
|
||
*
|
||
* This allows white point adjustment and gamut compression
|
||
* to be applied to all the color specifications in one
|
||
* swoop if those functions do in fact modify the entire
|
||
* group of color specifications.
|
||
*/
|
||
|
||
/*
|
||
* Convert in batches to CIEXYZ
|
||
*
|
||
* If DD->CIEXYZ, ConvertMixedColors will apply WhiteAdjustProc
|
||
* if required.
|
||
*/
|
||
if ((retval = ConvertMixedColors(ccc, pColors_tmp, &clientWhitePt,
|
||
nColors, XcmsCIEXYZFormat,
|
||
(unsigned char)(DI_FORMAT | DD_FORMAT))) == XcmsFailure) {
|
||
goto Failure;
|
||
}
|
||
|
||
/*
|
||
* Convert all specifications (now in CIEXYZ format) to
|
||
* the target DD format.
|
||
* Since CIEXYZ->DD, compression MAY take place therefore
|
||
* we must pass pCompressed.
|
||
* Note that WhiteAdjustProc must be used if necessary.
|
||
*/
|
||
if (callWhiteAdjustProc) {
|
||
/*
|
||
* White Point Adjustment
|
||
* Client White Point to Screen White Point
|
||
*/
|
||
retval = (*ccc->whitePtAdjProc)(ccc,
|
||
&clientWhitePt, ScreenWhitePointOfCCC(ccc),
|
||
targetFormat, pColors_tmp, nColors, pCompressed);
|
||
} else {
|
||
retval = _XcmsDDConvertColors(ccc, pColors_tmp, nColors,
|
||
targetFormat, pCompressed);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (retval != XcmsFailure) {
|
||
memcpy((char *)pColors_in_out, (char *)pColors_tmp,
|
||
nColors * sizeof(XcmsColor));
|
||
}
|
||
if (nColors > 1) {
|
||
Xfree((char *)pColors_tmp);
|
||
}
|
||
return(retval);
|
||
|
||
Failure:
|
||
if (nColors > 1) {
|
||
Xfree((char *)pColors_tmp);
|
||
}
|
||
return(XcmsFailure);
|
||
}
|
||
|
||
|
||
/*
|
||
* NAME
|
||
* XcmsRegFormatOfPrefix
|
||
*
|
||
* SYNOPSIS
|
||
*/
|
||
XcmsColorFormat
|
||
_XcmsRegFormatOfPrefix(
|
||
_Xconst char *prefix)
|
||
/*
|
||
* DESCRIPTION
|
||
* Returns a color space ID associated with the specified
|
||
* X Consortium registered color space prefix.
|
||
*
|
||
* RETURNS
|
||
* The color space ID if found;
|
||
* otherwise NULL.
|
||
*/
|
||
{
|
||
XcmsRegColorSpaceEntry *pEntry = _XcmsRegColorSpaces;
|
||
|
||
while (pEntry->prefix != NULL) {
|
||
if (strcmp(prefix, pEntry->prefix) == 0) {
|
||
return(pEntry->id);
|
||
}
|
||
pEntry++;
|
||
}
|
||
return(XcmsUndefinedFormat);
|
||
}
|