Subversion Repositories Scribus

Rev

Blame | Last modification | View Log | RSS feed

//
//  Little cms - profiler construction set
//  Copyright (C) 1998-2001 Marti Maria
//
// THIS SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
// EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
// WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
//
// IN NO EVENT SHALL MARTI MARIA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
// INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
// OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
// LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
// OF THIS SOFTWARE.
//
// This file is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program 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 for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// As a special exception to the GNU General Public License, if you
// distribute this file as part of a program that contains a
// configuration script generated by Autoconf, you may include it under
// the same distribution terms that you use for the rest of that program.
//
// Version 1.09a


#include "lcmsprf.h"


static
void ClampRGB(LPVEC3 RGB)
{
    int i;

    for (i=0; i < 3; i++) {

        if (RGB->n[i] > 1.0)          
                RGB->n[i] = 1.0;
        if (RGB->n[i] < 0)
                RGB->n[i] = 0;
    }
}


static
int RegressionSamplerA2B(register WORD In[], register WORD Out[], register LPVOID Cargo)
{
    cmsCIEXYZ xyz;
    cmsCIELab Lab;  
    VEC3 RGB, RGBlinear, vxyz;
    LPMONITORPROFILERDATA sys = (LPMONITORPROFILERDATA) Cargo;
   
   
        RGB.n[0] = _cmsxSaturate65535To255(In[0]);
        RGB.n[1] = _cmsxSaturate65535To255(In[1]);
        RGB.n[2] = _cmsxSaturate65535To255(In[2]);

        cmsxApplyLinearizationTable(RGB.n, sys->PreLab, RGBlinear.n);
        cmsxApplyLinearizationTable(RGBlinear.n, sys->Prelinearization, RGBlinear.n);
       
        RGBlinear.n[0] /= 255.;
        RGBlinear.n[1] /= 255.;
        RGBlinear.n[2] /= 255.;

        MAT3eval(&vxyz, &sys->PrimariesMatrix, &RGBlinear);
               
                xyz.X = vxyz.n[0];
        xyz.Y = vxyz.n[1];
        xyz.Z = vxyz.n[2];

        cmsxChromaticAdaptationAndNormalization(&sys ->hdr, &xyz, FALSE);
       
       
       // To PCS encoding
       
       cmsXYZ2Lab(NULL, &Lab, &xyz);
       cmsFloat2LabEncoded(Out, &Lab);
       

    return TRUE; // And done witch success
}




static
int RegressionSamplerB2A(register WORD In[], register WORD Out[], register LPVOID Cargo)
{
    cmsCIELab Lab;
    cmsCIEXYZ xyz;
    VEC3 vxyz, RGB;  
    // cmsJCh JCh;
    WORD Lin[3], Llab[3];
    LPMONITORPROFILERDATA sys = (LPMONITORPROFILERDATA) Cargo;
    double L;  


                // Pass L back to 0..0xff00 domain

                L = (double) (In[0] * 65280.0) / 65535.0;
                In[0] =  (WORD) floor(L + .5);


          // To float values
      cmsLabEncoded2Float(&Lab, In);
      cmsLab2XYZ(NULL, &xyz, &Lab);

         
          cmsxChromaticAdaptationAndNormalization(&sys ->hdr, &xyz, TRUE);
          vxyz.n[0] = xyz.X;
          vxyz.n[1] = xyz.Y;
          vxyz.n[2] = xyz.Z;

      MAT3eval(&RGB, &sys-> PrimariesMatrixRev, &vxyz);
     
      // Clamp RGB
      ClampRGB(&RGB);

      // Encode output
      Lin[0] = (WORD) ((double) RGB.n[0] * 65535. + .5);
      Lin[1] = (WORD) ((double) RGB.n[1] * 65535. + .5);
      Lin[2] = (WORD) ((double) RGB.n[2] * 65535. + .5);

      cmsxApplyLinearizationGamma(Lin, sys ->ReverseTables, Llab);
      cmsxApplyLinearizationGamma(Llab, sys ->PreLabRev, Out);

     
    return TRUE; // And done witch success
}


BOOL cmsxMonitorProfilerInit(LPMONITORPROFILERDATA sys)
{                                
       

        if (sys == NULL) return FALSE;
        ZeroMemory(sys, sizeof(MONITORPROFILERDATA));

        sys->hdr.DeviceClass = icSigDisplayClass;
        sys->hdr.ColorSpace  = icSigRgbData;
        sys->hdr.PCSType     = PT_Lab;
                sys->hdr.Medium      = MEDIUM_TRANSMISSIVE;
               

        // Default values for generation

        sys -> hdr.lUseCIECAM97s = FALSE;
        sys -> hdr.CLUTPoints = 16;
           
        // Default viewing conditions

        sys -> hdr.device.Yb = 20;
        sys -> hdr.device.La = 20;
        sys -> hdr.device.surround = AVG_SURROUND;
        sys -> hdr.device.D_value  = 1;                         // Complete adaptation


        // Viewing conditions of PCS
                cmsxInitPCSViewingConditions(&sys ->hdr);
             
        strcpy(sys -> hdr.Description,  "unknown monitor");
        strcpy(sys -> hdr.Manufacturer, "little cms profiler construction set");
        strcpy(sys -> hdr.Copyright,   "No copyright, use freely");
        strcpy(sys -> hdr.Model,       "(unknown)");

                sys -> hdr.ProfileVerbosityLevel = 0;

    return TRUE;
}


static
void CreatePrimaryMatrices(LPMONITORPROFILERDATA sys)
{  
    cmsCIExyY White;
    MAT3 tmp;
   

    cmsXYZ2xyY(&White, &sys->hdr.WhitePoint);
    cmsBuildRGB2XYZtransferMatrix(&sys -> PrimariesMatrix, &White, &sys->hdr.Primaries);
   
    CopyMemory(&tmp, &sys -> PrimariesMatrix, sizeof(MAT3));
    MAT3inverse(&tmp, &sys->PrimariesMatrixRev);

}


static
BOOL CreateLUTS(LPMONITORPROFILERDATA sys, LPLUT* A2B, LPLUT* B2A)
{  
    LPLUT AToB0 = cmsAllocLUT();
    LPLUT BToA0 = cmsAllocLUT();
    LPGAMMATABLE LabG;
        cmsCIExyY xyY;

   
        cmsAlloc3DGrid(AToB0, sys->hdr.CLUTPoints, 3, 3);
        cmsAlloc3DGrid(BToA0, sys->hdr.CLUTPoints, 3, 3);

        // cmsAllocLinearTable(AToB0, sys -> Prelinearization, 1);    

        sys->ReverseTables[0] = cmsReverseGamma(4096, sys ->Prelinearization[0]);
        sys->ReverseTables[1] = cmsReverseGamma(4096, sys ->Prelinearization[1]);
        sys->ReverseTables[2] = cmsReverseGamma(4096, sys ->Prelinearization[2]);

        // Prelinearization

        LabG = cmsBuildGamma(4096, 3.0);

        sys -> PreLab[0] = cmsJoinGammaEx(LabG, sys ->Prelinearization[0], 4096);
        sys -> PreLab[1] = cmsJoinGammaEx(LabG, sys ->Prelinearization[1], 4096);
        sys -> PreLab[2] = cmsJoinGammaEx(LabG, sys ->Prelinearization[2], 4096);

        sys -> PreLabRev[0] = cmsJoinGammaEx(sys ->Prelinearization[0], LabG, 4096);
        sys -> PreLabRev[1] = cmsJoinGammaEx(sys ->Prelinearization[1], LabG, 4096);
        sys -> PreLabRev[2] = cmsJoinGammaEx(sys ->Prelinearization[2], LabG, 4096);


        cmsFreeGamma(LabG);

       
        cmsAllocLinearTable(AToB0, sys->PreLabRev, 1);
        cmsAllocLinearTable(BToA0, sys->PreLab,    2);    
       

        // Set CIECAM97s parameters

        sys -> hdr.device.whitePoint.X = sys -> hdr.WhitePoint.X * 100.;
        sys -> hdr.device.whitePoint.Y = sys -> hdr.WhitePoint.Y * 100.;
        sys -> hdr.device.whitePoint.Z = sys -> hdr.WhitePoint.Z * 100.;


                // Normalize White point for CIECAM97s model
                cmsXYZ2xyY(&xyY,  &sys -> hdr.device.whitePoint);
                xyY.Y = 100.;
                cmsxyY2XYZ(&sys -> hdr.device.whitePoint, &xyY);


        sys->hdr.hDevice = cmsCIECAM97sInit(&sys->hdr.device);
        sys->hdr.hPCS    = cmsCIECAM97sInit(&sys->hdr.PCS);


        cmsSample3DGrid(AToB0, RegressionSamplerA2B, sys, 0);
        cmsSample3DGrid(BToA0, RegressionSamplerB2A, sys, 0);

        cmsCIECAM97sDone(sys->hdr.hDevice);
        cmsCIECAM97sDone(sys->hdr.hPCS);

       cmsAddTag(sys->hdr.hProfile, icSigAToB0Tag, AToB0);
       cmsAddTag(sys->hdr.hProfile, icSigBToA0Tag, BToA0);

           // This is the 0xff00 trick to map white at lattice point
           BToA0 ->Matrix.v[0].n[0] = DOUBLE_TO_FIXED((65535.0 / 65280.0));

       *A2B  = AToB0;
       *B2A  = BToA0;
                   
        cmsFreeGammaTriple(sys->ReverseTables);
        cmsFreeGammaTriple(sys->PreLab);
        cmsFreeGammaTriple(sys->PreLabRev);
        return TRUE;
}



BOOL cmsxMonitorProfilerDo(LPMONITORPROFILERDATA sys)
{
                 
    cmsCIExyY White;
    LPLUT AToB0, BToA0;

        AToB0 = BToA0 = NULL;

        if (!*sys -> hdr.OutputProfileFile)
                return FALSE;

     
        if (sys->hdr.ReferenceSheet[0] || sys->hdr.MeasurementSheet[0]) {

                if (sys->hdr.printf) {
           
                    sys->hdr.printf("Loading sheets...");

                    if (sys->hdr.ReferenceSheet[0])
                        sys->hdr.printf("Reference sheet: %s", sys->hdr.ReferenceSheet);
                    if (sys->hdr.MeasurementSheet[0])
                        sys->hdr.printf("Measurement sheet: %s", sys->hdr.MeasurementSheet);
                }


                if (!cmsxComputeMatrixShaper(sys -> hdr.ReferenceSheet,                                
                                             sys -> hdr.MeasurementSheet,  
                                                                                         MEDIUM_TRANSMISSIVE,                                      
                                             sys -> Prelinearization,
                                             &sys -> hdr.WhitePoint,
                                             &sys -> hdr.BlackPoint,
                                             &sys -> hdr.Primaries)) return FALSE;

                                if (sys->hdr.printf) {

                                        char Buffer[1024];
                                        _cmsIdentifyWhitePoint(Buffer, &sys ->hdr.WhitePoint);
                                        sys->hdr.printf("%s", Buffer);

                                        sys->hdr.printf("Primaries: R:%1.2g, %1.2g  G:%1.2g, %1.2g  B:%1.2g, %1.2g",
                                                        sys->hdr.Primaries.Red.x,sys->hdr.Primaries.Red.y,
                                                        sys->hdr.Primaries.Green.x, sys->hdr.Primaries.Green.y,
                                                        sys->hdr.Primaries.Blue.x, sys->hdr.Primaries.Blue.y);
                                }

        }
       
       
        CreatePrimaryMatrices(sys);

       
        cmsXYZ2xyY(&White, &sys->hdr.WhitePoint);
       
        sys->hdr.hProfile = cmsCreateRGBProfile(&White,
                                                &sys-> hdr.Primaries,
                                                sys -> Prelinearization);
     
        cmsSetDeviceClass(sys->hdr.hProfile, sys->hdr.DeviceClass);

                if (sys -> hdr.lUseCIECAM97s)
                        sys->hdr.PCSType = PT_Lab;
                else
                        sys->hdr.PCSType = PT_XYZ;
       
        cmsSetPCS(sys->hdr.hProfile,  _cmsICCcolorSpace(sys->hdr.PCSType));
               
        if (sys -> hdr.lUseCIECAM97s)
                        CreateLUTS(sys, &AToB0, &BToA0);


                cmsxEmbedTextualInfo(&sys ->hdr);
       
        cmsAddTag(sys->hdr.hProfile, icSigMediaWhitePointTag,  &sys->hdr.WhitePoint);
        cmsAddTag(sys->hdr.hProfile, icSigMediaBlackPointTag, &sys->hdr.BlackPoint);


                if (sys->hdr.ProfileVerbosityLevel >= 2) {
                                                                       
                        cmsxEmbedCharTarget(&sys ->hdr);       
                }


        _cmsSaveProfile(sys->hdr.hProfile, sys->hdr.OutputProfileFile);
        cmsCloseProfile(sys->hdr.hProfile);
        sys->hdr.hProfile = NULL;      
               

        if (AToB0) cmsFreeLUT(AToB0);
        if (BToA0) cmsFreeLUT(BToA0);

        if (sys ->Prelinearization[0])
            cmsFreeGammaTriple(sys -> Prelinearization);          
                     
    return TRUE;
}