jdk/src/share/native/sun/java2d/cmm/lcms/cmscam97.c
changeset 6483 8f9f87a564f6
parent 6390 a6442d6bc38a
parent 6482 0f6a4442b29e
child 6488 404882083757
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam97.c	Wed Jul 05 17:21:58 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,750 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-// This file is available under and governed by the GNU General Public
-// License version 2 only, as published by the Free Software Foundation.
-// However, the following notice accompanied the original version of this
-// file:
-//
-//
-//  Little cms
-//  Copyright (C) 1998-2007 Marti Maria
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the "Software"),
-// to deal in the Software without restriction, including without limitation
-// the rights to use, copy, modify, merge, publish, distribute, sublicense,
-// and/or sell copies of the Software, and to permit persons to whom the Software
-// is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
-// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-
-#include "lcms.h"
-
-
-/*
-typedef struct {
-               double J;
-               double C;
-               double h;
-
-               } cmsJCh, FAR* LPcmsJCh;
-
-
-#define AVG_SURROUND_4     0
-#define AVG_SURROUND       1
-#define DIM_SURROUND       2
-#define DARK_SURROUND      3
-#define CUTSHEET_SURROUND  4
-
-
-typedef struct {
-
-              cmsCIEXYZ whitePoint;
-              double    Yb;
-              double    La;
-              int       surround;
-              double    D_value;
-
-              } cmsViewingConditions, FAR* LPcmsViewingConditions;
-
-
-
-LCMSAPI LCMSHANDLE LCMSEXPORT cmsCIECAM97sInit(LPcmsViewingConditions pVC);
-LCMSAPI void   LCMSEXPORT cmsCIECAM97sDone(LCMSHANDLE hModel);
-LCMSAPI void   LCMSEXPORT cmsCIECAM97sForward(LCMSHANDLE hModel, LPcmsCIEXYZ pIn, LPcmsJCh pOut);
-LCMSAPI void   LCMSEXPORT cmsCIECAM97sReverse(LCMSHANDLE hModel, LPcmsJCh pIn,    LPcmsCIEXYZ pOut);
-
-*/
-
-// ---------- Implementation --------------------------------------------
-
-// #define USE_CIECAM97s2  1
-
-#ifdef USE_CIECAM97s2
-
-#       define NOISE_CONSTANT   3.05
-#else
-#       define NOISE_CONSTANT   2.05
-#endif
-
-
-/*
-  The model input data are the adapting field luminance in cd/m2
-  (normally taken to be 20% of the luminance of white in the adapting field),
-  LA , the relative tristimulus values of the stimulus, XYZ, the relative
-  tristimulus values of white in the same viewing conditions, Xw Yw Zw ,
-  and the relative luminance of the background, Yb . Relative tristimulus
-  values should be expressed on a scale from Y = 0 for a perfect black
-  to Y = 100 for a perfect reflecting diffuser. Additionally, the
-  parameters c, for the impact of surround, Nc , a chromatic induction factor,
-  and F, a factor for degree of adaptation, must be selected according to the
-  guidelines in table
-
-  All CIE tristimulus values are obtained using the CIE 1931
-  Standard Colorimetric Observer (2°).
-
-*/
-
-typedef struct {
-
-    cmsCIEXYZ WP;
-    int surround;
-    int calculate_D;
-
-    double  Yb;         // rel. luminance of background
-
-    cmsCIEXYZ RefWhite;
-
-    double La;    // The adapting field luminance in cd/m2
-
-    double c;     // Impact of surround
-    double Nc;    // Chromatic induction factor
-    double Fll;   // Lightness contrast factor (Removed on rev 2)
-    double F;     // Degree of adaptation
-
-
-    double k;
-    double Fl;
-
-    double Nbb;  // The background and chromatic brightness induction factors.
-    double Ncb;
-    double z;    // base exponential nonlinearity
-    double n;    // background induction factor
-    double D;
-
-    MAT3 MlamRigg;
-    MAT3 MlamRigg_1;
-
-    MAT3 Mhunt;
-    MAT3 Mhunt_1;
-
-    MAT3 Mhunt_x_MlamRigg_1;
-    MAT3 MlamRigg_x_Mhunt_1;
-
-
-    VEC3 RGB_subw;
-    VEC3 RGB_subw_prime;
-
-    double p;
-
-    VEC3 RGB_subwc;
-
-    VEC3 RGB_subaw_prime;
-    double A_subw;
-    double Q_subw;
-
-    } cmsCIECAM97s,FAR *LPcmsCIECAM97s;
-
-
-
-// Free model structure
-
-LCMSAPI void LCMSEXPORT cmsCIECAM97sDone(LCMSHANDLE hModel)
-{
-    LPcmsCIECAM97s lpMod = (LPcmsCIECAM97s) (LPSTR) hModel;
-    if (lpMod) _cmsFree(lpMod);
-}
-
-// Partial discounting for adaptation degree computation
-
-static
-double discount(double d, double chan)
-{
-    return (d * chan + 1 - d);
-}
-
-
-// This routine does model exponential nonlinearity on the short wavelenght
-// sensitive channel. On CIECAM97s rev 2 this has been reverted to linear.
-
-static
-void FwAdaptationDegree(LPcmsCIECAM97s lpMod, LPVEC3 RGBc, LPVEC3 RGB)
-{
-
-
-#ifdef USE_CIECAM97s2
-    RGBc->n[0] = RGB->n[0]* discount(lpMod->D, 100.0/lpMod->RGB_subw.n[0]);
-    RGBc->n[1] = RGB->n[1]* discount(lpMod->D, 100.0/lpMod->RGB_subw.n[1]);
-    RGBc->n[2] = RGB->n[2]* discount(lpMod->D, 100.0/lpMod->RGB_subw.n[2]);
-#else
-
-    RGBc->n[0] = RGB->n[0]* discount(lpMod->D, 1.0/lpMod->RGB_subw.n[0]);
-    RGBc->n[1] = RGB->n[1]* discount(lpMod->D, 1.0/lpMod->RGB_subw.n[1]);
-
-    RGBc->n[2] = pow(fabs(RGB->n[2]), lpMod ->p) * discount(lpMod->D, (1.0/pow(lpMod->RGB_subw.n[2], lpMod->p)));
-
-    // If B happens to be negative, Then Bc is also set to be negative
-
-    if (RGB->n[2] < 0)
-           RGBc->n[2] = -RGBc->n[2];
-#endif
-}
-
-
-static
-void RvAdaptationDegree(LPcmsCIECAM97s lpMod, LPVEC3 RGBc, LPVEC3 RGB)
-{
-
-
-#ifdef USE_CIECAM97s2
-    RGBc->n[0] = RGB->n[0]/discount(lpMod->D, 100.0/lpMod->RGB_subw.n[0]);
-    RGBc->n[1] = RGB->n[1]/discount(lpMod->D, 100.0/lpMod->RGB_subw.n[1]);
-    RGBc->n[2] = RGB->n[2]/discount(lpMod->D, 100.0/lpMod->RGB_subw.n[2]);
-#else
-
-    RGBc->n[0] = RGB->n[0]/discount(lpMod->D, 1.0/lpMod->RGB_subw.n[0]);
-    RGBc->n[1] = RGB->n[1]/discount(lpMod->D, 1.0/lpMod->RGB_subw.n[1]);
-    RGBc->n[2] = pow(fabs(RGB->n[2]), 1.0/lpMod->p)/pow(discount(lpMod->D, 1.0/pow(lpMod->RGB_subw.n[2], lpMod->p)), 1.0/lpMod->p);
-    if (RGB->n[2] < 0)
-           RGBc->n[2] = -RGBc->n[2];
-#endif
-}
-
-
-
-static
-void PostAdaptationConeResponses(LPcmsCIECAM97s lpMod, LPVEC3 RGBa_prime, LPVEC3 RGBprime)
-{
-     if (RGBprime->n[0]>=0.0) {
-
-            RGBa_prime->n[0]=((40.0*pow(lpMod -> Fl * RGBprime->n[0]/100.0, 0.73))/(pow(lpMod -> Fl * RGBprime->n[0]/100.0, 0.73)+2))+1;
-     }
-     else
-     {
-            RGBa_prime->n[0]=((-40.0*pow((-lpMod -> Fl * RGBprime->n[0])/100.0, 0.73))/(pow((-lpMod -> Fl * RGBprime->n[0])/100.0, 0.73)+2))+1;
-     }
-
-     if (RGBprime->n[1]>=0.0)
-     {
-            RGBa_prime->n[1]=((40.0*pow(lpMod -> Fl * RGBprime->n[1]/100.0, 0.73))/(pow(lpMod -> Fl * RGBprime->n[1]/100.0, 0.73)+2))+1;
-     }
-     else
-     {
-            RGBa_prime->n[1]=((-40.0*pow((-lpMod -> Fl * RGBprime->n[1])/100.0, 0.73))/(pow((-lpMod -> Fl * RGBprime->n[1])/100.0, 0.73)+2))+1;
-     }
-
-     if (RGBprime->n[2]>=0.0)
-     {
-            RGBa_prime->n[2]=((40.0*pow(lpMod -> Fl * RGBprime->n[2]/100.0, 0.73))/(pow(lpMod -> Fl * RGBprime->n[2]/100.0, 0.73)+2))+1;
-     }
-     else
-     {
-            RGBa_prime->n[2]=((-40.0*pow((-lpMod -> Fl * RGBprime->n[2])/100.0, 0.73))/(pow((-lpMod -> Fl * RGBprime->n[2])/100.0, 0.73)+2))+1;
-     }
-}
-
-
-// Compute hue quadrature, eccentricity factor, e
-
-static
-void ComputeHueQuadrature(double h, double* H, double* e)
-{
-
-
-#define IRED    0
-#define IYELLOW 1
-#define IGREEN  2
-#define IBLUE   3
-
-      double e_tab[] = {0.8, 0.7, 1.0, 1.2};
-      double H_tab[] = {  0, 100, 200, 300};
-      int p1, p2;
-      double e1, e2, h1, h2;
-
-
-       if (h >= 20.14 && h < 90.0) { // Red
-
-                        p1 = IRED;
-                        p2 = IYELLOW;
-       }
-       else
-       if (h >= 90.0 && h < 164.25) { // Yellow
-
-                        p1 = IYELLOW;
-                        p2 = IGREEN;
-       }
-       else
-       if (h >= 164.25 && h < 237.53) { // Green
-
-                        p1 = IGREEN;
-                        p2 = IBLUE;       }
-       else {                         // Blue
-
-                        p1 = IBLUE;
-                        p2 = IRED;
-       }
-
-       e1 = e_tab[p1]; e2 = e_tab[p2];
-       h1 = H_tab[p1]; h2 = H_tab[p2];
-
-
-
-       *e = e1 + ((e2-e1)*(h-h1)/(h2 - h1));
-       *H = h1 + (100. * (h - h1) / e1) / ((h - h1)/e1 + (h2 - h) / e2);
-
-#undef IRED
-#undef IYELLOW
-#undef IGREEN
-#undef IBLUE
-
-}
-
-
-
-
-
-
-LCMSAPI LCMSHANDLE LCMSEXPORT cmsCIECAM97sInit(LPcmsViewingConditions pVC)
-{
-    LPcmsCIECAM97s lpMod;
-    VEC3 tmp;
-
-    if((lpMod = (LPcmsCIECAM97s) _cmsMalloc(sizeof(cmsCIECAM97s))) == NULL) {
-        return (LCMSHANDLE) NULL;
-    }
-
-
-    lpMod->WP.X = pVC->whitePoint.X;
-    lpMod->WP.Y = pVC->whitePoint.Y;
-    lpMod->WP.Z = pVC->whitePoint.Z;
-
-    lpMod->Yb   = pVC->Yb;
-    lpMod->La   = pVC->La;
-
-    lpMod->surround = pVC->surround;
-
-    lpMod->RefWhite.X = 100.0;
-    lpMod->RefWhite.Y = 100.0;
-    lpMod->RefWhite.Z = 100.0;
-
-#ifdef USE_CIECAM97s2
-
-    VEC3init(&lpMod->MlamRigg.v[0],  0.8562, 0.3372, -0.1934);
-    VEC3init(&lpMod->MlamRigg.v[1], -0.8360, 1.8327,  0.0033);
-    VEC3init(&lpMod->MlamRigg.v[2],  0.0357,-0.0469,  1.0112);
-
-    VEC3init(&lpMod->MlamRigg_1.v[0], 0.9874, -0.1768, 0.1894);
-    VEC3init(&lpMod->MlamRigg_1.v[1], 0.4504,  0.4649, 0.0846);
-    VEC3init(&lpMod->MlamRigg_1.v[2],-0.0139,  0.0278, 0.9861);
-
-#else
-    // Bradford transform: Lam-Rigg cone responses
-    VEC3init(&lpMod->MlamRigg.v[0],  0.8951,  0.2664, -0.1614);
-    VEC3init(&lpMod->MlamRigg.v[1], -0.7502,  1.7135,  0.0367);
-    VEC3init(&lpMod->MlamRigg.v[2],  0.0389, -0.0685,  1.0296);
-
-
-    // Inverse of Lam-Rigg
-    VEC3init(&lpMod->MlamRigg_1.v[0],  0.98699, -0.14705,  0.15996);
-    VEC3init(&lpMod->MlamRigg_1.v[1],  0.43231,  0.51836,  0.04929);
-    VEC3init(&lpMod->MlamRigg_1.v[2], -0.00853,  0.04004,  0.96849);
-
-#endif
-
-    // Hunt-Pointer-Estevez cone responses
-    VEC3init(&lpMod->Mhunt.v[0],   0.38971,  0.68898, -0.07868);
-    VEC3init(&lpMod->Mhunt.v[1],  -0.22981,  1.18340,  0.04641);
-    VEC3init(&lpMod->Mhunt.v[2],   0.0,      0.0,      1.0);
-
-    // Inverse of Hunt-Pointer-Estevez
-    VEC3init(&lpMod->Mhunt_1.v[0],     1.91019, -1.11214, 0.20195);
-    VEC3init(&lpMod->Mhunt_1.v[1],     0.37095,  0.62905, 0.0);
-    VEC3init(&lpMod->Mhunt_1.v[2],     0.0,      0.0,     1.0);
-
-
-    if (pVC->D_value == -1.0)
-          lpMod->calculate_D = 1;
-    else
-    if (pVC->D_value == -2.0)
-           lpMod->calculate_D = 2;
-    else {
-        lpMod->calculate_D = 0;
-        lpMod->D = pVC->D_value;
-    }
-
-   // Table I (revised)
-
-   switch (lpMod->surround) {
-
-    case AVG_SURROUND_4:
-       lpMod->F = 1.0;
-       lpMod->c = 0.69;
-       lpMod->Fll = 0.0;    // Not included on Rev 2
-       lpMod->Nc = 1.0;
-       break;
-    case AVG_SURROUND:
-       lpMod->F = 1.0;
-       lpMod->c = 0.69;
-       lpMod->Fll = 1.0;
-       lpMod->Nc = 1.0;
-       break;
-    case DIM_SURROUND:
-       lpMod->F = 0.99;
-       lpMod->c = 0.59;
-       lpMod->Fll = 1.0;
-       lpMod->Nc = 0.95;
-       break;
-    case DARK_SURROUND:
-       lpMod->F = 0.9;
-       lpMod->c = 0.525;
-       lpMod->Fll = 1.0;
-       lpMod->Nc = 0.8;
-       break;
-    case CUTSHEET_SURROUND:
-       lpMod->F = 0.9;
-       lpMod->c = 0.41;
-       lpMod->Fll = 1.0;
-       lpMod->Nc = 0.8;
-       break;
-    default:
-       lpMod->F = 1.0;
-       lpMod->c = 0.69;
-       lpMod->Fll = 1.0;
-       lpMod->Nc = 1.0;
-       break;
-    }
-
-    lpMod->k = 1 / (5 * lpMod->La  + 1);
-    lpMod->Fl = lpMod->La * pow(lpMod->k, 4) + 0.1*pow(1 - pow(lpMod->k, 4), 2.0) * pow(5*lpMod->La, 1.0/3.0);
-
-    if (lpMod->calculate_D > 0) {
-
-       lpMod->D = lpMod->F * (1 - 1 / (1 + 2*pow(lpMod->La, 0.25) + pow(lpMod->La, 2)/300.0));
-       if (lpMod->calculate_D > 1)
-           lpMod->D = (lpMod->D + 1.0) / 2;
-    }
-
-
-    // RGB_subw = [MlamRigg][WP/YWp]
-#ifdef USE_CIECAM97s2
-    MAT3eval(&lpMod -> RGB_subw, &lpMod -> MlamRigg, &lpMod -> WP);
-#else
-    VEC3divK(&tmp, (LPVEC3) &lpMod -> WP, lpMod->WP.Y);
-    MAT3eval(&lpMod -> RGB_subw, &lpMod -> MlamRigg, &tmp);
-#endif
-
-
-
-    MAT3per(&lpMod -> Mhunt_x_MlamRigg_1,   &lpMod -> Mhunt,   &lpMod->MlamRigg_1  );
-    MAT3per(&lpMod -> MlamRigg_x_Mhunt_1,   &lpMod -> MlamRigg, &lpMod -> Mhunt_1  );
-
-    // p is used on forward model
-    lpMod->p = pow(lpMod->RGB_subw.n[2], 0.0834);
-
-    FwAdaptationDegree(lpMod, &lpMod->RGB_subwc, &lpMod->RGB_subw);
-
-#if USE_CIECAM97s2
-    MAT3eval(&lpMod->RGB_subw_prime, &lpMod->Mhunt_x_MlamRigg_1, &lpMod -> RGB_subwc);
-#else
-    VEC3perK(&tmp, &lpMod -> RGB_subwc, lpMod->WP.Y);
-    MAT3eval(&lpMod->RGB_subw_prime, &lpMod->Mhunt_x_MlamRigg_1, &tmp);
-#endif
-
-    lpMod->n = lpMod-> Yb / lpMod-> WP.Y;
-
-    lpMod->z = 1 + lpMod->Fll * sqrt(lpMod->n);
-    lpMod->Nbb = lpMod->Ncb = 0.725 / pow(lpMod->n, 0.2);
-
-    PostAdaptationConeResponses(lpMod, &lpMod->RGB_subaw_prime, &lpMod->RGB_subw_prime);
-
-    lpMod->A_subw=lpMod->Nbb*(2.0*lpMod->RGB_subaw_prime.n[0]+lpMod->RGB_subaw_prime.n[1]+lpMod->RGB_subaw_prime.n[2]/20.0-NOISE_CONSTANT);
-
-    return (LCMSHANDLE) lpMod;
-}
-
-
-
-
-//
-// The forward model: XYZ -> JCh
-//
-
-LCMSAPI void LCMSEXPORT cmsCIECAM97sForward(LCMSHANDLE hModel, LPcmsCIEXYZ inPtr, LPcmsJCh outPtr)
-{
-
-        LPcmsCIECAM97s lpMod = (LPcmsCIECAM97s) (LPSTR) hModel;
-        double a, b, h, s, H1val, es, A;
-        VEC3 In, RGB, RGBc, RGBprime, RGBa_prime;
-
-        if (inPtr -> Y <= 0.0) {
-
-      outPtr -> J = outPtr -> C = outPtr -> h = 0.0;
-          return;
-        }
-
-       // An initial chromatic adaptation transform is used to go from the source
-       // viewing conditions to corresponding colours under the equal-energy-illuminant
-       // reference viewing conditions. This is handled differently on rev 2
-
-       VEC3init(&In, inPtr -> X, inPtr -> Y, inPtr -> Z);    // 2.1
-
-#ifdef USE_CIECAM97s2
-       // Since the chromatic adaptation transform has been linearized, it
-       // is no longer required to divide the stimulus tristimulus values
-       // by their own Y tristimulus value prior to the chromatic adaptation.
-#else
-       VEC3divK(&In, &In, inPtr -> Y);
-#endif
-
-       MAT3eval(&RGB, &lpMod -> MlamRigg, &In);              // 2.2
-
-       FwAdaptationDegree(lpMod, &RGBc, &RGB);
-
-       // The post-adaptation signals for both the sample and the white are then
-       // transformed from the sharpened cone responses to the Hunt-Pointer-Estevez
-       // cone responses.
-#ifdef USE_CIECAM97s2
-#else
-       VEC3perK(&RGBc, &RGBc, inPtr->Y);
-#endif
-
-       MAT3eval(&RGBprime, &lpMod->Mhunt_x_MlamRigg_1, &RGBc);
-
-       // The post-adaptation cone responses (for both the stimulus and the white)
-       // are then calculated.
-
-       PostAdaptationConeResponses(lpMod, &RGBa_prime, &RGBprime);
-
-       // Preliminary red-green and yellow-blue opponent dimensions are calculated
-
-       a = RGBa_prime.n[0] - (12.0 * RGBa_prime.n[1] / 11.0) + RGBa_prime.n[2]/11.0;
-       b = (RGBa_prime.n[0] + RGBa_prime.n[1] - 2.0 * RGBa_prime.n[2]) / 9.0;
-
-
-       // The CIECAM97s hue angle, h, is then calculated
-       h = (180.0/M_PI)*(atan2(b, a));
-
-
-       while (h < 0)
-              h += 360.0;
-
-       outPtr->h = h;
-
-       // hue quadrature and eccentricity factors, e, are calculated
-
-       ComputeHueQuadrature(h, &H1val, &es);
-
-       // ComputeHueQuadrature(h, &H1val, &h1, &e1, &h2, &e2, &es);
-
-
-      // The achromatic response A
-      A = lpMod->Nbb * (2.0 * RGBa_prime.n[0] + RGBa_prime.n[1] + RGBa_prime.n[2]/20.0 - NOISE_CONSTANT);
-
-      // CIECAM97s Lightness J
-      outPtr -> J = 100.0 * pow(A / lpMod->A_subw, lpMod->c * lpMod->z);
-
-      // CIECAM97s saturation s
-      s =  (50 * hypot (a, b) * 100 * es * (10.0/13.0) * lpMod-> Nc * lpMod->Ncb) / (RGBa_prime.n[0] + RGBa_prime.n[1] + 1.05 * RGBa_prime.n[2]);
-
-      // CIECAM97s Chroma C
-
-#ifdef USE_CIECAM97s2
-      // Eq. 26 has been modified to allow accurate prediction of the Munsell chroma scales.
-      outPtr->C = 0.7487 * pow(s, 0.973) * pow(outPtr->J/100.0, 0.945 * lpMod->n) * (1.64 - pow(0.29, lpMod->n));
-
-#else
-      outPtr->C = 2.44 * pow(s, 0.69) * pow(outPtr->J/100.0, 0.67 * lpMod->n) * (1.64 - pow(0.29, lpMod->n));
-#endif
-}
-
-
-//
-// The reverse model JCh -> XYZ
-//
-
-
-LCMSAPI void LCMSEXPORT cmsCIECAM97sReverse(LCMSHANDLE hModel, LPcmsJCh inPtr, LPcmsCIEXYZ outPtr)
-{
-    LPcmsCIECAM97s lpMod = (LPcmsCIECAM97s) (LPSTR) hModel;
-    double J, C, h, A, H1val, es, s, a, b;
-    double tan_h, sec_h;
-    double R_suba_prime, G_suba_prime, B_suba_prime;
-    double R_prime, G_prime, B_prime;
-    double Y_subc, Y_prime, B_term;
-    VEC3 tmp;
-    VEC3 RGB_prime, RGB_subc_Y;
-    VEC3 Y_over_Y_subc_RGB;
-    VEC3 XYZ_primeprime_over_Y_subc;
-#ifdef USE_CIECAM92s2
-    VEC3 RGBY;
-    VEC3 Out;
-#endif
-
-    J = inPtr->J;
-    h = inPtr->h;
-    C = inPtr->C;
-
-    if (J <= 0) {
-
-        outPtr->X =  0.0;
-        outPtr->Y =  0.0;
-        outPtr->Z =  0.0;
-        return;
-    }
-
-
-
-    // (2) From J Obtain A
-
-    A =  pow(J/100.0, 1/(lpMod->c * lpMod->z)) * lpMod->A_subw;
-
-
-    // (3), (4), (5) Using H Determine h1, h2, e1, e2
-    // e1 and h1 are the values  of e and h for the unique hue having the
-    // nearest lower valur of h and e2 and h2 are the values of e and h for
-    // the unique hue having the nearest higher value of h.
-
-
-    ComputeHueQuadrature(h, &H1val, &es);
-
-    // (7) Calculate s
-
-    s = pow(C / (2.44 * pow(J/100.0, 0.67*lpMod->n) * (1.64 - pow(0.29, lpMod->n))) , (1./0.69));
-
-
-    // (8) Calculate a and b.
-    // NOTE: sqrt(1 + tan^2) == sec(h)
-
-    tan_h = tan ((M_PI/180.)*(h));
-    sec_h = sqrt(1 + tan_h * tan_h);
-
-    if ((h > 90) && (h < 270))
-            sec_h = -sec_h;
-
-    a = s * ( A/lpMod->Nbb + NOISE_CONSTANT) / ( sec_h * 50000.0 * es * lpMod->Nc * lpMod->Ncb/ 13.0 +
-           s * (11.0 / 23.0 + (108.0/23.0) * tan_h));
-
-    b = a * tan_h;
-
-    //(9) Calculate R'a G'a and B'a
-
-    R_suba_prime = (20.0/61.0) * (A/lpMod->Nbb + NOISE_CONSTANT) + (41.0/61.0) * (11.0/23.0) * a + (288.0/61.0) / 23.0 * b;
-    G_suba_prime = (20.0/61.0) * (A/lpMod->Nbb + NOISE_CONSTANT) - (81.0/61.0) * (11.0/23.0) * a - (261.0/61.0) / 23.0 * b;
-    B_suba_prime = (20.0/61.0) * (A/lpMod->Nbb + NOISE_CONSTANT) - (20.0/61.0) * (11.0/23.0) * a - (20.0/61.0) * (315.0/23.0) * b;
-
-    // (10) Calculate R', G' and B'
-
-    if ((R_suba_prime - 1) < 0) {
-
-         R_prime = -100.0 * pow((2.0 - 2.0 * R_suba_prime) /
-                            (39.0 + R_suba_prime), 1.0/0.73);
-    }
-    else
-    {
-         R_prime = 100.0 * pow((2.0 * R_suba_prime - 2.0) /
-                            (41.0 - R_suba_prime), 1.0/0.73);
-    }
-
-    if ((G_suba_prime - 1) < 0)
-    {
-         G_prime = -100.0 * pow((2.0 - 2.0 * G_suba_prime) /
-                            (39.0 + G_suba_prime), 1.0/0.73);
-    }
-    else
-    {
-         G_prime = 100.0 * pow((2.0 * G_suba_prime - 2.0) /
-                            (41.0 - G_suba_prime), 1.0/0.73);
-    }
-
-    if ((B_suba_prime - 1) < 0)
-    {
-         B_prime = -100.0 * pow((2.0 - 2.0 * B_suba_prime) /
-                            (39.0 + B_suba_prime), 1.0/0.73);
-    }
-    else
-    {
-         B_prime = 100.0 * pow((2.0 * B_suba_prime - 2.0) /
-                            (41.0 - B_suba_prime), 1.0/0.73);
-    }
-
-
-    // (11) Calculate RcY, GcY and BcY
-
-    VEC3init(&RGB_prime, R_prime, G_prime, B_prime);
-    VEC3divK(&tmp, &RGB_prime, lpMod -> Fl);
-
-    MAT3eval(&RGB_subc_Y, &lpMod->MlamRigg_x_Mhunt_1, &tmp);
-
-
-
-
-#ifdef USE_CIECAM97s2
-
-       // (12)
-
-
-           RvAdaptationDegree(lpMod, &RGBY, &RGB_subc_Y);
-           MAT3eval(&Out, &lpMod->MlamRigg_1, &RGBY);
-
-           outPtr -> X = Out.n[0];
-           outPtr -> Y = Out.n[1];
-           outPtr -> Z = Out.n[2];
-
-#else
-
-           // (12) Calculate Yc
-
-       Y_subc = 0.43231*RGB_subc_Y.n[0]+0.51836*RGB_subc_Y.n[1]+0.04929*RGB_subc_Y.n[2];
-
-           // (13) Calculate (Y/Yc)R, (Y/Yc)G and (Y/Yc)B
-
-           VEC3divK(&RGB_subc_Y, &RGB_subc_Y, Y_subc);
-           RvAdaptationDegree(lpMod, &Y_over_Y_subc_RGB, &RGB_subc_Y);
-
-           // (14) Calculate Y'
-       Y_prime = 0.43231*(Y_over_Y_subc_RGB.n[0]*Y_subc) + 0.51836*(Y_over_Y_subc_RGB.n[1]*Y_subc) + 0.04929 * (Y_over_Y_subc_RGB.n[2]*Y_subc);
-
-           if (Y_prime < 0 || Y_subc < 0)
-           {
-                // Discard to near black point
-
-                outPtr -> X = 0;
-                outPtr -> Y = 0;
-                outPtr -> Z = 0;
-                return;
-           }
-
-       B_term = pow(Y_prime / Y_subc, (1.0 / lpMod->p) - 1);
-
-          // (15) Calculate X'', Y'' and Z''
-           Y_over_Y_subc_RGB.n[2] /= B_term;
-           MAT3eval(&XYZ_primeprime_over_Y_subc, &lpMod->MlamRigg_1, &Y_over_Y_subc_RGB);
-
-           outPtr->X =  XYZ_primeprime_over_Y_subc.n[0] * Y_subc;
-           outPtr->Y =  XYZ_primeprime_over_Y_subc.n[1] * Y_subc;
-           outPtr->Z =  XYZ_primeprime_over_Y_subc.n[2] * Y_subc;
-#endif
-
-}