LabMnL.c revision 1ab64890
11ab64890Smrg/* $Xorg: LabMnL.c,v 1.3 2000/08/17 19:44:39 cpqbld Exp $ */ 21ab64890Smrg 31ab64890Smrg/* 41ab64890Smrg * Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc. 51ab64890Smrg * All Rights Reserved 61ab64890Smrg * 71ab64890Smrg * This file is a component of an X Window System-specific implementation 81ab64890Smrg * of XCMS based on the TekColor Color Management System. Permission is 91ab64890Smrg * hereby granted to use, copy, modify, sell, and otherwise distribute this 101ab64890Smrg * software and its documentation for any purpose and without fee, provided 111ab64890Smrg * that this copyright, permission, and disclaimer notice is reproduced in 121ab64890Smrg * all copies of this software and in supporting documentation. TekColor 131ab64890Smrg * is a trademark of Tektronix, Inc. 141ab64890Smrg * 151ab64890Smrg * Tektronix makes no representation about the suitability of this software 161ab64890Smrg * for any purpose. It is provided "as is" and with all faults. 171ab64890Smrg * 181ab64890Smrg * TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE, 191ab64890Smrg * INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 201ab64890Smrg * PARTICULAR PURPOSE. IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY 211ab64890Smrg * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER 221ab64890Smrg * RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF 231ab64890Smrg * CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 241ab64890Smrg * CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE. 251ab64890Smrg * 261ab64890Smrg * NAME 271ab64890Smrg * CIELabMnL.c 281ab64890Smrg * 291ab64890Smrg * DESCRIPTION 301ab64890Smrg * Source for the XcmsCIELabQueryMinL() gamut boundary 311ab64890Smrg * querying routine. 321ab64890Smrg * 331ab64890Smrg */ 341ab64890Smrg/* $XFree86: xc/lib/X11/LabMnL.c,v 1.3 2001/01/17 19:41:39 dawes Exp $ */ 351ab64890Smrg 361ab64890Smrg#ifdef HAVE_CONFIG_H 371ab64890Smrg#include <config.h> 381ab64890Smrg#endif 391ab64890Smrg#include "Xlibint.h" 401ab64890Smrg#include "Xcmsint.h" 411ab64890Smrg#include <math.h> 421ab64890Smrg#include "Cv.h" 431ab64890Smrg 441ab64890Smrg/* 451ab64890Smrg * DEFINES 461ab64890Smrg */ 471ab64890Smrg#define MAXBISECTCOUNT 100 481ab64890Smrg#define EPS (XcmsFloat)0.001 491ab64890Smrg#define START_L_STAR (XcmsFloat)40.0 501ab64890Smrg 511ab64890Smrg 521ab64890Smrg/************************************************************************ 531ab64890Smrg * * 541ab64890Smrg * PUBLIC ROUTINES * 551ab64890Smrg * * 561ab64890Smrg ************************************************************************/ 571ab64890Smrg 581ab64890Smrg/* 591ab64890Smrg * NAME 601ab64890Smrg * XcmsCIELabQueryMinL - Compute max Lstar for a hue and chroma 611ab64890Smrg * 621ab64890Smrg * SYNOPSIS 631ab64890Smrg */ 641ab64890SmrgStatus 651ab64890SmrgXcmsCIELabQueryMinL( 661ab64890Smrg XcmsCCC ccc, 671ab64890Smrg XcmsFloat hue_angle, /* hue angle in degrees */ 681ab64890Smrg XcmsFloat chroma, 691ab64890Smrg XcmsColor *pColor_return) 701ab64890Smrg/* 711ab64890Smrg * DESCRIPTION 721ab64890Smrg * Return the maximum Lstar for a specified hue_angle and chroma. 731ab64890Smrg * 741ab64890Smrg * ASSUMPTIONS 751ab64890Smrg * This routine assumes that the white point associated with 761ab64890Smrg * the color specification is the Screen White Point. The 771ab64890Smrg * Screen White Point will also be associated with the 781ab64890Smrg * returned color specification. 791ab64890Smrg * 801ab64890Smrg * RETURNS 811ab64890Smrg * XcmsFailure - Failure 821ab64890Smrg * XcmsSuccess - Succeeded with no modifications 831ab64890Smrg * 841ab64890Smrg */ 851ab64890Smrg{ 861ab64890Smrg XcmsCCCRec myCCC; 871ab64890Smrg XcmsColor max_lc, tmp, prev; 881ab64890Smrg XcmsFloat max_chroma, tmp_chroma; 891ab64890Smrg XcmsFloat hue, nT, nChroma, lastChroma, prevChroma; 901ab64890Smrg XcmsFloat rFactor; 911ab64890Smrg XcmsRGBi rgb_saved; 921ab64890Smrg int nCount, nMaxCount; 931ab64890Smrg 941ab64890Smrg /* 951ab64890Smrg * Check Arguments 961ab64890Smrg */ 971ab64890Smrg if (ccc == NULL || pColor_return == NULL) { 981ab64890Smrg return(XcmsFailure); 991ab64890Smrg } 1001ab64890Smrg 1011ab64890Smrg /* setup the CCC to use for the conversions. */ 1021ab64890Smrg memcpy ((char *) &myCCC, (char *) ccc, sizeof(XcmsCCCRec)); 1031ab64890Smrg myCCC.clientWhitePt.format = XcmsUndefinedFormat; 1041ab64890Smrg myCCC.gamutCompProc = (XcmsCompressionProc) NULL; 1051ab64890Smrg 1061ab64890Smrg while (hue_angle < 0.0) { 1071ab64890Smrg hue_angle += 360.0; 1081ab64890Smrg } 1091ab64890Smrg while (hue_angle >= 360.0) { 1101ab64890Smrg hue_angle -= 360.0; 1111ab64890Smrg } 1121ab64890Smrg 1131ab64890Smrg hue = radians(hue_angle); 1141ab64890Smrg tmp.spec.CIELab.L_star = START_L_STAR; 1151ab64890Smrg tmp.spec.CIELab.a_star = XCMS_CIEASTAROFHUE(hue, chroma); 1161ab64890Smrg tmp.spec.CIELab.b_star = XCMS_CIEBSTAROFHUE(hue, chroma); 1171ab64890Smrg tmp.pixel = pColor_return->pixel; 1181ab64890Smrg tmp.format = XcmsCIELabFormat; 1191ab64890Smrg 1201ab64890Smrg /* Step 1: Obtain the maximum L_star and chroma for this hue. */ 1211ab64890Smrg if (_XcmsCIELabQueryMaxLCRGB(&myCCC, hue, &max_lc, &rgb_saved) 1221ab64890Smrg == XcmsFailure) { 1231ab64890Smrg return(XcmsFailure); 1241ab64890Smrg } 1251ab64890Smrg 1261ab64890Smrg max_chroma = XCMS_CIELAB_PMETRIC_CHROMA(max_lc.spec.CIELab.a_star, 1271ab64890Smrg max_lc.spec.CIELab.b_star); 1281ab64890Smrg 1291ab64890Smrg if (max_chroma <= chroma) { 1301ab64890Smrg /* 1311ab64890Smrg * If the chroma is greater than the chroma for the 1321ab64890Smrg * maximum L/chroma point then the L_star is the 1331ab64890Smrg * the L_star for the maximum L_star/chroma point. 1341ab64890Smrg * This is an error but I return the best approximation I can. 1351ab64890Smrg * Thus the inconsistency. 1361ab64890Smrg */ 1371ab64890Smrg memcpy ((char *) pColor_return, (char *) &max_lc, sizeof (XcmsColor)); 1381ab64890Smrg return(XcmsSuccess); 1391ab64890Smrg } 1401ab64890Smrg 1411ab64890Smrg /* 1421ab64890Smrg * If the chroma is equal to the chroma for the 1431ab64890Smrg * maximum L_star/chroma point then the L_star is the 1441ab64890Smrg * the L_star for the maximum L* and chroma point. 1451ab64890Smrg */ 1461ab64890Smrg /* if (max_chroma == chroma) { 1471ab64890Smrg * memcpy ((char *) pColor_return, (char *) &max_lc, sizeof (XcmsColor)); 1481ab64890Smrg * return(XcmsSuccess); 1491ab64890Smrg * } 1501ab64890Smrg */ 1511ab64890Smrg 1521ab64890Smrg /* must do a bisection here to compute the maximum L* */ 1531ab64890Smrg /* save the structure input so that any elements that */ 1541ab64890Smrg /* are not touched are recopied later in the routine. */ 1551ab64890Smrg nChroma = chroma; 1561ab64890Smrg tmp_chroma = max_chroma; 1571ab64890Smrg lastChroma = -1.0; 1581ab64890Smrg nMaxCount = MAXBISECTCOUNT; 1591ab64890Smrg rFactor = 1.0; 1601ab64890Smrg 1611ab64890Smrg for (nCount = 0; nCount < nMaxCount; nCount++) { 1621ab64890Smrg prevChroma = lastChroma; 1631ab64890Smrg lastChroma = tmp_chroma; 1641ab64890Smrg nT = (nChroma - max_chroma) / max_chroma * rFactor; 1651ab64890Smrg memcpy ((char *)&prev, (char *)&tmp, sizeof(XcmsColor)); 1661ab64890Smrg tmp.spec.RGBi.red = rgb_saved.red + (rgb_saved.red * nT); 1671ab64890Smrg tmp.spec.RGBi.green = rgb_saved.green + (rgb_saved.green * nT); 1681ab64890Smrg tmp.spec.RGBi.blue = rgb_saved.blue + (rgb_saved.blue * nT); 1691ab64890Smrg tmp.format = XcmsRGBiFormat; 1701ab64890Smrg 1711ab64890Smrg /* convert from RGB to CIELab */ 1721ab64890Smrg if (_XcmsConvertColorsWithWhitePt(&myCCC, &tmp, 1731ab64890Smrg ScreenWhitePointOfCCC(&myCCC), 1, XcmsCIELabFormat, 1741ab64890Smrg (Bool *) NULL) == XcmsFailure) { 1751ab64890Smrg return(XcmsFailure); 1761ab64890Smrg } 1771ab64890Smrg 1781ab64890Smrg /* Now check the return against what is expected */ 1791ab64890Smrg tmp_chroma = XCMS_CIELAB_PMETRIC_CHROMA(tmp.spec.CIELab.a_star, 1801ab64890Smrg tmp.spec.CIELab.b_star); 1811ab64890Smrg if (tmp_chroma <= chroma + EPS && tmp_chroma >= chroma - EPS) { 1821ab64890Smrg /* Found It! */ 1831ab64890Smrg memcpy ((char *) pColor_return, (char *) &tmp, sizeof (XcmsColor)); 1841ab64890Smrg return(XcmsSuccess); 1851ab64890Smrg } 1861ab64890Smrg nChroma += chroma - tmp_chroma; 1871ab64890Smrg if (nChroma > max_chroma) { 1881ab64890Smrg nChroma = max_chroma; 1891ab64890Smrg rFactor *= 0.5; /* selective relaxation employed */ 1901ab64890Smrg } else if (nChroma < 0.0) { 1911ab64890Smrg if (XCMS_FABS(lastChroma - chroma) < 1921ab64890Smrg XCMS_FABS(tmp_chroma - chroma)) { 1931ab64890Smrg memcpy ((char *)pColor_return, (char *)&prev, 1941ab64890Smrg sizeof(XcmsColor)); 1951ab64890Smrg } else { 1961ab64890Smrg memcpy ((char *)pColor_return, (char *)&tmp, 1971ab64890Smrg sizeof(XcmsColor)); 1981ab64890Smrg } 1991ab64890Smrg return(XcmsSuccess); 2001ab64890Smrg } else if (tmp_chroma <= prevChroma + EPS && 2011ab64890Smrg tmp_chroma >= prevChroma - EPS) { 2021ab64890Smrg rFactor *= 0.5; /* selective relaxation employed */ 2031ab64890Smrg } 2041ab64890Smrg } 2051ab64890Smrg 2061ab64890Smrg if (nCount >= nMaxCount) { 2071ab64890Smrg if (XCMS_FABS(lastChroma - chroma) < 2081ab64890Smrg XCMS_FABS(tmp_chroma - chroma)) { 2091ab64890Smrg memcpy ((char *)pColor_return, (char *)&prev, 2101ab64890Smrg sizeof(XcmsColor)); 2111ab64890Smrg } else { 2121ab64890Smrg memcpy ((char *)pColor_return, (char *)&tmp, 2131ab64890Smrg sizeof(XcmsColor)); 2141ab64890Smrg } 2151ab64890Smrg } 2161ab64890Smrg memcpy ((char *) pColor_return, (char *) &tmp, sizeof (XcmsColor)); 2171ab64890Smrg return(XcmsSuccess); 2181ab64890Smrg} 219