diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
new file mode 100644
index 00000000..6a3e435d
--- /dev/null
+++ b/library/CMakeLists.txt
@@ -0,0 +1,16 @@
+# For more information about using CMake with Android Studio, read the
+# documentation: https://d.android.com/studio/projects/add-native-code.html
+
+# Sets the minimum version of CMake required to build the native library.
+
+cmake_minimum_required(VERSION 3.4.1)
+
+# Creates and names a library, sets it as either STATIC
+# or SHARED, and provides the relative paths to its source code.
+# You can define multiple libraries, and CMake builds them for you.
+# Gradle automatically packages shared libraries with your APK.
+
+
+add_subdirectory(src/main/cpp/icc)
+add_subdirectory(src/main/cpp/jpeg)
+add_subdirectory(src/main/cpp/jbig2)
diff --git a/library/build.gradle b/library/build.gradle
index cf32ac47..42d6935a 100644
--- a/library/build.gradle
+++ b/library/build.gradle
@@ -18,6 +18,18 @@ android {
targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION)
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-proguard-rules.txt'
+
+ externalNativeBuild {
+ cmake{
+ abiFilters "armeabi-v7a" ,"arm64-v8a"
+ }
+ }
+ }
+
+ externalNativeBuild {
+ cmake {
+ path "CMakeLists.txt"
+ }
}
buildTypes {
diff --git a/library/src/main/assets/com/tom_roush/pdfbox/resources/icc/ISOcoated_v2_300_bas.icc b/library/src/main/assets/com/tom_roush/pdfbox/resources/icc/ISOcoated_v2_300_bas.icc
new file mode 100644
index 00000000..71faa91f
Binary files /dev/null and b/library/src/main/assets/com/tom_roush/pdfbox/resources/icc/ISOcoated_v2_300_bas.icc differ
diff --git a/library/src/main/cpp/icc/CMakeLists.txt b/library/src/main/cpp/icc/CMakeLists.txt
new file mode 100644
index 00000000..0bdf690f
--- /dev/null
+++ b/library/src/main/cpp/icc/CMakeLists.txt
@@ -0,0 +1,47 @@
+# For more information about using CMake with Android Studio, read the
+# documentation: https://d.android.com/studio/projects/add-native-code.html
+
+# Sets the minimum version of CMake required to build the native library.
+
+cmake_minimum_required(VERSION 3.4.1)
+
+set(TARGET iccUse)
+set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}/
+ # opencv/include
+)
+
+#add_library(libopencv_java4 SHARED IMPORTED)
+#set_target_properties(libopencv_java4 PROPERTIES IMPORTED_LOCATION
+# ${CMAKE_CURRENT_SOURCE_DIR}/opencv/${ANDROID_ABI}/libopencv_java4.so)
+
+
+# Creates and names a library, sets it as either STATIC
+# or SHARED, and provides the relative paths to its source code.
+# You can define multiple libraries, and CMake builds them for you.
+# Gradle automatically packages shared libraries with your APK.
+
+aux_source_directory(${SRC_DIR} DIR_LIB_SOURCE)
+
+add_library(${TARGET} SHARED ${DIR_LIB_SOURCE})
+
+# Searches for a specified prebuilt library and stores the path as a
+# variable. Because CMake includes system libraries in the search path by
+# default, you only need to specify the name of the public NDK library
+# you want to add. CMake verifies that the library exists before
+# completing its build.
+
+target_link_libraries(${TARGET} log android)
+
+# Specifies libraries CMake should link to your target library. You
+# can link multiple libraries, such as libraries you define in this
+# build script, prebuilt third-party libraries, or system libraries.
+
+#if(${ANDROID_ABI} STREQUAL x86 OR ${ANDROID_ABI} STREQUAL x86_64)
+#target_link_libraries(${TARGET} opencv_imgproc opencv_core ippiw ippicv ittnotify tbb cpufeatures)
+#else()
+#target_link_libraries(${TARGET})
+#endif()
+
diff --git a/library/src/main/cpp/icc/IccApplyBPC.cpp b/library/src/main/cpp/icc/IccApplyBPC.cpp
new file mode 100644
index 00000000..9da173e6
--- /dev/null
+++ b/library/src/main/cpp/icc/IccApplyBPC.cpp
@@ -0,0 +1,621 @@
+/** @file
+File: IccApplyBPC.cpp
+
+Contains: Implementation of Black Point Compensation calculations.
+
+Version: V1
+
+Copyright: see ICC Software License
+*/
+
+/*
+* The ICC Software License, Version 0.2
+*
+*
+* Copyright (c) 2003-2015 The International Color Consortium. All rights
+* reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in
+* the documentation and/or other materials provided with the
+* distribution.
+*
+* 3. In the absence of prior written permission, the names "ICC" and "The
+* International Color Consortium" must not be used to imply that the
+* ICC organization endorses or promotes products derived from this
+* software.
+*
+*
+* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR
+* ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+* SUCH DAMAGE.
+* ====================================================================
+*
+* This software consists of voluntary contributions made by many
+* individuals on behalf of the The International Color Consortium.
+*
+*
+* Membership in the ICC is encouraged when this software is used for
+* commercial purposes.
+*
+*
+* For more information on The International Color Consortium, please
+* see .
+*
+*
+*/
+
+//////////////////////////////////////////////////////////////////////
+// HISTORY:
+//
+// -Initial implementation by Rohit Patil 12-10-2008
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "IccApplyBPC.h"
+#include
+
+#define IsSpacePCS(x) ((x)==icSigXYZData || (x)==icSigLabData)
+
+/**
+**************************************************************************
+* Name: CIccApplyBPCHint::GetNewAdjustPCSXform
+*
+* Purpose:
+* Returns a new CIccApplyBPC object. Returned object should be deleted
+* by the caller.
+*
+**************************************************************************
+*/
+IIccAdjustPCSXform* CIccApplyBPCHint::GetNewAdjustPCSXform() const
+{
+ return new CIccApplyBPC();
+}
+
+//////////////////////////////////////////////////////////////////////
+// CIccApplyBPC utility functions
+//////////////////////////////////////////////////////////////////////
+
+// converts lab to pcs
+void CIccApplyBPC::lab2pcs(icFloatNumber* pixel, const CIccProfile* pProfile) const
+{
+ switch (pProfile->m_Header.pcs)
+ {
+ case icSigLabData:
+ icLabToPcs(pixel);
+ break;
+
+ case icSigXYZData:
+ icLabtoXYZ(pixel);
+ icXyzToPcs(pixel);
+ break;
+
+ default:
+ break;
+ }
+}
+
+// converts pcs to lab
+void CIccApplyBPC::pcs2lab(icFloatNumber* pixel, const CIccProfile* pProfile) const
+{
+ switch (pProfile->m_Header.pcs)
+ {
+ case icSigLabData:
+ icLabFromPcs(pixel);
+ break;
+
+ case icSigXYZData:
+ icXyzFromPcs(pixel);
+ icXYZtoLab(pixel);
+ break;
+
+ default:
+ break;
+ }
+}
+
+// calculates sum of product of x^j and y^k polynomials
+icFloatNumber CIccApplyBPC::calcsum(icFloatNumber* x, icFloatNumber* y, int n, int j, int k) const
+{
+ icFloatNumber dSum = 0.0;
+
+ int i;
+ if (j && k) {
+ for (i=0; i2) { // need at least three points to solve three linear equations
+ icFloatNumber s00, s10, s20, s30, s40, s01, s11, s21, denom;
+ s00 = calcsum(x, y, n, 0, 0);
+ s10 = calcsum(x, y, n, 1, 0);
+ s20 = calcsum(x, y, n, 2, 0);
+ s30 = calcsum(x, y, n, 3, 0);
+ s40 = calcsum(x, y, n, 4, 0);
+ s01 = calcsum(x, y, n, 0, 1);
+ s11 = calcsum(x, y, n, 1, 1);
+ s21 = calcsum(x, y, n, 2, 1);
+ denom = (icFloatNumber)(s00*s20*s40 - s10*s10*s40 - s00*s30*s30 + 2.0*s10*s20*s30 - s20*s20*s20);
+ if (fabs(denom)>0.0) {
+ // t and u are the coefficients of the quadratic equation y = tx^2 + ux + c
+ // the three equations with 3 unknowns can be written as
+ // [s40 s30 s20][t] [s21]
+ // [s30 s20 s10][u] = [s11]
+ // [s20 s10 s00][c] [s01]
+ icFloatNumber t = (s01*s10*s30 - s11*s00*s30 - s01*s20*s20 + s11*s10*s20 + s21*s00*s20 - s21*s10*s10)/denom;
+
+ icFloatNumber u = (s11*s00*s40 - s01*s10*s40 + s01*s20*s30 - s21*s00*s30 - s11*s20*s20 + s21*s10*s20)/denom;
+
+ icFloatNumber c = (s01*s20*s40 - s11*s10*s40 - s01*s30*s30 + s11*s20*s30 + s21*s10*s30 - s21*s20*s20)/denom;
+
+ // vertex is (-u + sqrt(u^2 - 4tc))/2t
+ vert = (icFloatNumber)((-1.0 * u + sqrt(u*u - 4*t*c)) / (2.0 * t));
+ }
+ }
+
+ return vert;
+}
+
+/**
+**************************************************************************
+* Name: CIccApplyBPC::CalculateFactors
+*
+* Purpose:
+* This function does the suitable calculations to setup black point
+* compensation.
+*
+* Args:
+* pXform = pointer to the Xform object that calls this function
+*
+* Return:
+* true = all calculations done
+* false = an error occurred
+**************************************************************************
+*/
+bool CIccApplyBPC::CalcFactors(const CIccProfile* pProfile, const CIccXform* pXform, icFloatNumber* Scale, icFloatNumber* Offset) const
+{
+ if (!pProfile || !pXform)
+ return false;
+
+ if (pXform->GetIntent()==icAbsoluteColorimetric) { // black point compensation not supported
+ return false;
+ }
+
+ switch (pProfile->m_Header.deviceClass)
+ { // These profile classes not supported
+ case icSigLinkClass:
+ case icSigAbstractClass:
+ //case icSigColorSpaceClass:
+ case icSigNamedColorClass:
+ return false;
+ default:
+ break;
+ }
+
+ icFloatNumber XYZbp[3]; // storage for black point XYZ
+
+ // calculate the black point
+ if (!calcBlackPoint(pProfile, pXform, XYZbp)) {
+ return false;
+ }
+
+ // calculate the scale and offset
+ if (pXform->IsInput()) { // use PRM black as destination black
+ Scale[0] = (icFloatNumber)((1.0 - icPerceptualRefBlackY)/(1.0 - XYZbp[1]));
+ }
+ else { // use PRM black as source black
+ Scale[0] = (icFloatNumber)((1.0 - XYZbp[1])/(1.0 - icPerceptualRefBlackY));
+ }
+
+ Scale[1] = Scale[0];
+ Scale[2] = Scale[0];
+
+ Offset[0] = (icFloatNumber)((1.0 - Scale[0]) * icPerceptualRefWhiteX);
+ Offset[1] = (icFloatNumber)((1.0 - Scale[1]) * icPerceptualRefWhiteY);
+ Offset[2] = (icFloatNumber)((1.0 - Scale[2]) * icPerceptualRefWhiteZ);
+
+ icXyzToPcs(Offset);
+
+ return true;
+}
+
+/**
+**************************************************************************
+* Name: CIccApplyBPC::calcBlackPoint
+*
+* Purpose:
+* Calculates the black point of a profile
+*
+**************************************************************************
+*/
+bool CIccApplyBPC::calcBlackPoint(const CIccProfile* pProfile, const CIccXform* pXform, icFloatNumber* XYZb) const
+{
+ if (pXform->IsInput()) { // profile used as input/source profile
+ return calcSrcBlackPoint(pProfile, pXform, XYZb);
+ }
+ else { // profile used as output profile
+ return calcDstBlackPoint(pProfile, pXform, XYZb);
+ }
+
+ return true;
+}
+
+/**
+**************************************************************************
+* Name: CIccApplyBPC::calcSrcBlackPoint
+*
+* Purpose:
+* Calculates the black point of a source profile
+*
+**************************************************************************
+*/
+bool CIccApplyBPC::calcSrcBlackPoint(const CIccProfile* pProfile, const CIccXform* pXform, icFloatNumber* XYZb) const
+{
+ icFloatNumber Pixel[16];
+ if ((pProfile->m_Header.colorSpace == icSigCmykData) && (pProfile->m_Header.deviceClass == icSigOutputClass)) {
+
+ // calculate intermediate CMYK
+ XYZb[0] = XYZb[1] = XYZb[2] = 0.0;
+
+ // convert the Lab of 0,0,0 to relevant PCS
+ lab2pcs(XYZb, pProfile);
+
+ //convert the PCS value to CMYK
+ if (!pixelXfm(Pixel, XYZb, pProfile->m_Header.pcs, icPerceptual, pProfile)) {
+ return false;
+ }
+ }
+ else {
+ switch (pProfile->m_Header.colorSpace) {
+ case icSigRgbData:
+ Pixel[0] = 0.0;
+ Pixel[1] = 0.0;
+ Pixel[2] = 0.0;
+ break;
+
+ case icSigGrayData:
+ Pixel[0] = 0.0;
+ break;
+
+ case icSigCmykData:
+ case icSigCmyData:
+ case icSig2colorData:
+ case icSig3colorData:
+ case icSig4colorData:
+ case icSig5colorData:
+ case icSig6colorData:
+ case icSig7colorData:
+ case icSig8colorData:
+ case icSig9colorData:
+ case icSig10colorData:
+ case icSig11colorData:
+ case icSig12colorData:
+ case icSig13colorData:
+ case icSig14colorData:
+ case icSig15colorData:
+ {
+ icUInt32Number nSamples = icGetSpaceSamples(pProfile->m_Header.colorSpace);
+ for (icUInt32Number i=0; im_Header.colorSpace, pXform->GetIntent(), pProfile)) {
+ return false;
+ }
+
+ // convert PCS to Lab
+ pcs2lab(XYZb, pProfile);
+
+ // set a* b* to zero for cmyk profiles
+ if (pProfile->m_Header.colorSpace == icSigCmykData) {
+ XYZb[1] = XYZb[2] = 0.0;
+ }
+
+ // clip L* to 50
+ if (XYZb[0]>50.0) {
+ XYZb[0] = 50.0;
+ }
+
+ // convert Lab to XYZ
+ icLabtoXYZ(XYZb);
+ return true;
+}
+
+/**
+**************************************************************************
+* Name: CIccApplyBPC::calcDstBlackPoint
+*
+* Purpose:
+* Calculates the black point of a destination profile
+*
+**************************************************************************
+*/
+bool CIccApplyBPC::calcDstBlackPoint(const CIccProfile* pProfile, const CIccXform* pXform, icFloatNumber* XYZb) const
+{
+ icRenderingIntent nIntent = pXform->GetIntent();
+ icFloatNumber Pixel[3];
+ icFloatNumber pcsPixel[3];
+
+ // check if the profile is lut based gray, rgb or cmyk
+ if (pProfile->IsTagPresent(icSigBToA0Tag) &&
+ (pProfile->m_Header.colorSpace==icSigGrayData || pProfile->m_Header.colorSpace==icSigRgbData || pProfile->m_Header.colorSpace==icSigCmykData))
+ { // do the complicated and lengthy black point estimation
+
+ // get the black transform
+ CIccCmm* pCmm = getBlackXfm(nIntent, pProfile);
+ if (!pCmm) {
+ return false;
+ }
+
+ // set the initial Lab
+ icFloatNumber iniLab[3] = {0.0, 0.0, 0.0};
+
+ // calculate minL
+ pcsPixel[0] = 0.0;
+ pcsPixel[1] = iniLab[1];
+ pcsPixel[2] = iniLab[2];
+ lab2pcs(pcsPixel, pProfile);
+ if (pCmm->Apply(Pixel, pcsPixel)!=icCmmStatOk) {
+ delete pCmm;
+ return false;
+ }
+ pcs2lab(Pixel, pProfile);
+ icFloatNumber MinL = Pixel[0];
+
+ // calculate MaxL
+ pcsPixel[0] = 100.0;
+ pcsPixel[1] = iniLab[1];
+ pcsPixel[2] = iniLab[2];
+ lab2pcs(pcsPixel, pProfile);
+ if (pCmm->Apply(Pixel, pcsPixel)!=icCmmStatOk) {
+ delete pCmm;
+ return false;
+ }
+ pcs2lab(Pixel, pProfile);
+ icFloatNumber MaxL = Pixel[0];
+
+ // check if quadratic estimation needs to be done
+ bool bStraightMidRange = false;
+
+ // if the intent is relative
+ if (nIntent==icRelativeColorimetric)
+ {
+ // calculate initial Lab as source black point
+ if (!calcSrcBlackPoint(pProfile, pXform, iniLab)) {
+ delete pCmm;
+ return false;
+ }
+
+ // convert the XYZ to lab
+ icXYZtoLab(iniLab);
+
+ // check mid range L* values
+ icFloatNumber lcnt=0.0, roundtripL;
+ bStraightMidRange = true;
+ while (lcnt<100.1)
+ {
+ pcsPixel[0] = icFloatNumber(lcnt);
+ pcsPixel[1] = iniLab[1];
+ pcsPixel[2] = iniLab[2];
+ lab2pcs(pcsPixel, pProfile);
+ if (pCmm->Apply(Pixel, pcsPixel)!=icCmmStatOk) {
+ delete pCmm;
+ return false;
+ }
+ pcs2lab(Pixel, pProfile);
+ roundtripL = Pixel[0];
+
+ if (roundtripL>(MinL + 0.2 * (MaxL - MinL))) {
+ if (fabs(roundtripL - lcnt)>4.0) {
+ bStraightMidRange = false;
+ break;
+ }
+ }
+
+ lcnt += 1.0;
+ }
+ }
+
+ // quadratic estimation is not needed
+ if (bStraightMidRange) { // initial Lab is the destination black point
+ XYZb[0] = iniLab[0];
+ XYZb[1] = iniLab[1];
+ XYZb[2] = iniLab[2];
+ icLabtoXYZ(XYZb);
+ delete pCmm;
+ return true;
+ }
+
+ // find the black point using the least squares error quadratic curve fitting
+
+ // calculate y values
+ icFloatNumber x[101], y[101];
+ icFloatNumber lo=0.03f, hi=0.25f;
+ int i, n;
+ if (nIntent==icRelativeColorimetric) {
+ lo = 0.1f;
+ hi = 0.5f;
+ }
+
+ for (i=0; i<101; i++) {
+ x[i] = icFloatNumber(i);
+ pcsPixel[0] = x[i];
+ pcsPixel[1] = iniLab[1];
+ pcsPixel[2] = iniLab[2];
+ lab2pcs(pcsPixel, pProfile);
+ if (pCmm->Apply(Pixel, pcsPixel)!=icCmmStatOk) {
+ delete pCmm;
+ return false;
+ }
+ pcs2lab(Pixel, pProfile);
+ y[i] = (Pixel[0] - MinL)/(MaxL - MinL);
+ }
+
+ // check for y values in the range and rearrange
+ n = 0;
+ for (i=0; i<101; i++) {
+ if (y[i]>=lo && y[i] PCS round trip transform, always uses relative intent on the device -> pcs transform
+*
+**************************************************************************
+*/
+CIccCmm* CIccApplyBPC::getBlackXfm(icRenderingIntent nIntent, const CIccProfile *pProfile) const
+{
+ // create the cmm object
+ CIccCmm* pCmm = new CIccCmm(pProfile->m_Header.pcs, icSigUnknownData, false);
+ if (!pCmm) return NULL;
+
+ // first create a copy of the profile because the copy will be owned by the cmm
+ CIccProfile* pICC1 = new CIccProfile(*pProfile);
+ if (!pICC1) {
+ delete pCmm;
+ return NULL;
+ }
+
+ // add the xform
+ if (pCmm->AddXform(pICC1, nIntent, icInterpTetrahedral)!=icCmmStatOk) {
+ delete pICC1;
+ delete pCmm;
+ return NULL;
+ }
+
+ // create another copy of the profile because the copy will be owned by the cmm
+ CIccProfile* pICC2 = new CIccProfile(*pProfile);
+ if (!pICC2) {
+ delete pCmm;
+ return NULL;
+ }
+
+ // add the xform
+ if (pCmm->AddXform(pICC2, icRelativeColorimetric, icInterpTetrahedral)!=icCmmStatOk) { // uses the relative intent on the device to Lab side
+ delete pICC2;
+ delete pCmm;
+ return NULL;
+ }
+
+ // get the cmm ready to do transforms
+ if (pCmm->Begin()!=icCmmStatOk) {
+ delete pCmm;
+ return NULL;
+ }
+
+ return pCmm;
+}
diff --git a/library/src/main/cpp/icc/IccApplyBPC.h b/library/src/main/cpp/icc/IccApplyBPC.h
new file mode 100644
index 00000000..6e82a16a
--- /dev/null
+++ b/library/src/main/cpp/icc/IccApplyBPC.h
@@ -0,0 +1,135 @@
+/** @file
+File: IccApplyBPC.h
+
+Contains: Header file for implementation of Black Point Compensation calculations.
+
+Version: V1
+
+Copyright: see ICC Software License
+*/
+
+/*
+* The ICC Software License, Version 0.2
+*
+*
+* Copyright (c) 2003-2015 The International Color Consortium. All rights
+* reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in
+* the documentation and/or other materials provided with the
+* distribution.
+*
+* 3. In the absence of prior written permission, the names "ICC" and "The
+* International Color Consortium" must not be used to imply that the
+* ICC organization endorses or promotes products derived from this
+* software.
+*
+*
+* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR
+* ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+* SUCH DAMAGE.
+* ====================================================================
+*
+* This software consists of voluntary contributions made by many
+* individuals on behalf of the The International Color Consortium.
+*
+*
+* Membership in the ICC is encouraged when this software is used for
+* commercial purposes.
+*
+*
+* For more information on The International Color Consortium, please
+* see .
+*
+*
+*/
+
+//////////////////////////////////////////////////////////////////////
+// HISTORY:
+//
+// -Initial implementation by Rohit Patil 12-8-2008
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(_ICCAPPLYBPC_H)
+#define _ICCAPPLYBPC_H
+
+#include "IccCmm.h"
+
+#ifdef USESAMPLEICCNAMESPACE
+namespace sampleICC {
+#endif
+
+/**
+**************************************************************************
+* Type: Class
+*
+* Purpose:
+* Interface and hint for creating a BPC xform object
+**************************************************************************
+*/
+class ICCPROFLIB_API CIccApplyBPCHint : public CIccCreateAdjustPCSXformHint
+{
+public:
+ virtual const char *GetAdjustPCSType() const { return "CIccApplyBPCHint"; }
+ virtual IIccAdjustPCSXform* GetNewAdjustPCSXform() const;
+};
+
+/**
+ **************************************************************************
+ * Type: Class
+ *
+ * Purpose: This is the hint for applying black point compensation.
+ * Also does the calculations to setup actual application of BPC.
+ *
+ **************************************************************************
+*/
+class ICCPROFLIB_API CIccApplyBPC : public IIccAdjustPCSXform
+{
+public:
+ // virtual IIccAdjustPCSXform functions
+ // does all the calculations for BPC and returns the scale and offset in the arguments passed
+ virtual bool CalcFactors(const CIccProfile* pProfile, const CIccXform* pXfm, icFloatNumber* Scale, icFloatNumber* Offset) const;
+
+private:
+ // utility functions
+ void lab2pcs(icFloatNumber* pixel, const CIccProfile* pProfile) const;
+ void pcs2lab(icFloatNumber* pixel, const CIccProfile* pProfile) const;
+ icFloatNumber calcsum(icFloatNumber* x, icFloatNumber* y, int n, int j, int k) const;
+ icFloatNumber calcQuadraticVertex(icFloatNumber* x, icFloatNumber* y, int n) const;
+
+ // worker functions
+ bool calcBlackPoint(const CIccProfile* pProfile, const CIccXform* pXform, icFloatNumber* XYZb) const;
+ bool calcSrcBlackPoint(const CIccProfile* pProfile, const CIccXform* pXform, icFloatNumber* XYZb) const;
+ bool calcDstBlackPoint(const CIccProfile* pProfile, const CIccXform* pXform, icFloatNumber* XYZb) const;
+
+ bool pixelXfm(icFloatNumber *DstPixel, icFloatNumber *SrcPixel, icColorSpaceSignature SrcSpace,
+ icRenderingIntent nIntent, const CIccProfile *pProfile) const;
+
+ // PCS -> PCS round trip transform, always uses relative intent on the device -> pcs transform
+ CIccCmm* getBlackXfm(icRenderingIntent nIntent, const CIccProfile *pProfile) const;
+};
+
+#ifdef USESAMPLEICCNAMESPACE
+}; //namespace sampleICC
+#endif
+
+#endif // _ICCAPPLYBPC_H
+
diff --git a/library/src/main/cpp/icc/IccCmm.cpp b/library/src/main/cpp/icc/IccCmm.cpp
new file mode 100644
index 00000000..8b639cc9
--- /dev/null
+++ b/library/src/main/cpp/icc/IccCmm.cpp
@@ -0,0 +1,6158 @@
+/** @file
+ File: IccCmm.cpp
+
+ Contains: Implementation of the CIccCmm class.
+
+ Version: V1
+
+ Copyright: � see ICC Software License
+*/
+
+/*
+ * The ICC Software License, Version 0.2
+ *
+ *
+ * Copyright (c) 2003-2015 The International Color Consortium. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. In the absence of prior written permission, the names "ICC" and "The
+ * International Color Consortium" must not be used to imply that the
+ * ICC organization endorses or promotes products derived from this
+ * software.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR
+ * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the The International Color Consortium.
+ *
+ *
+ * Membership in the ICC is encouraged when this software is used for
+ * commercial purposes.
+ *
+ *
+ * For more information on The International Color Consortium, please
+ * see .
+ *
+ *
+ */
+
+//////////////////////////////////////////////////////////////////////
+// HISTORY:
+//
+// -Initial implementation by Max Derhak 5-15-2003
+// -Added support for Monochrome ICC profile apply by Rohit Patil 12-03-2008
+// -Integrated changes for PCS adjustment by George Pawle 12-09-2008
+//
+//////////////////////////////////////////////////////////////////////
+
+#if defined(WIN32) || defined(WIN64)
+#pragma warning( disable: 4786) //disable warning in
+#endif
+
+#include "IccXformFactory.h"
+#include "IccTag.h"
+#include "IccIO.h"
+#include "IccApplyBPC.h"
+#include
+
+#ifdef USESAMPLEICCNAMESPACE
+namespace sampleICC {
+#endif
+
+////
+// Useful Macros
+////
+
+#define IsSpacePCS(x) ((x)==icSigXYZData || (x)==icSigLabData)
+#define IsSpaceCMYK(x) ((x)==icSigCmykData || (x)==icSig4colorData)
+
+#define IsCompatSpace(x, y) ((x)==(y) || (IsSpacePCS(x) && IsSpacePCS(y)) || (IsSpaceCMYK(x) && IsSpaceCMYK(y)))
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+/**
+ **************************************************************************
+ * Class CIccPCS Constructor
+ *
+ * Purpose:
+ * This is a class constructor.
+ *
+ **************************************************************************
+ */
+CIccPCS::CIccPCS()
+{
+ m_bIsV2Lab = false;
+ m_Space = icSigUnknownData;
+}
+
+/**
+**************************************************************************
+* Name: CIccPCS::Reset
+*
+* Purpose:
+* This is called with the initial color space and a bool
+* argument which is true if the PCS is version 2.
+*
+* Args:
+* Startpsace = Starting Colorspace
+* bUseLegacyPCS = legacy PCS flag
+**************************************************************************
+*/
+void CIccPCS::Reset(icColorSpaceSignature StartSpace, bool bUseLegacyPCS)
+{
+ m_bIsV2Lab = IsSpacePCS(StartSpace) && bUseLegacyPCS;
+ m_Space = StartSpace;
+}
+
+/**
+ **************************************************************************
+ * Name: CIccPCS::Check
+ *
+ * Purpose:
+ * This is called before the apply of each profile's xform to adjust the PCS
+ * to the xform's needed PCS.
+ *
+ * Args:
+ * SrcPixel = source pixel data (this may need adjusting),
+ * pXform = the xform that who's Apply function will shortly be called
+ *
+ * Return:
+ * SrcPixel or ptr to adjusted pixel data (we dont want to modify the source data).
+ **************************************************************************
+ */
+const icFloatNumber *CIccPCS::Check(const icFloatNumber *SrcPixel, const CIccXform *pXform)
+{
+ icColorSpaceSignature NextSpace = pXform->GetSrcSpace();
+ bool bIsV2 = pXform->UseLegacyPCS();
+ bool bIsNextV2Lab = bIsV2 && (NextSpace == icSigLabData);
+ const icFloatNumber *rv;
+ bool bNoClip = pXform->NoClipPCS();
+
+ if (m_bIsV2Lab && !bIsNextV2Lab) {
+ Lab2ToLab4(m_Convert, SrcPixel, bNoClip);
+ if (NextSpace==icSigXYZData) {
+ LabToXyz(m_Convert, m_Convert, bNoClip);
+ }
+ rv = m_Convert;
+ }
+ else if (!m_bIsV2Lab && bIsNextV2Lab) {
+ if (m_Space==icSigXYZData) {
+ XyzToLab(m_Convert, SrcPixel, bNoClip);
+ SrcPixel = m_Convert;
+ }
+ Lab4ToLab2(m_Convert, SrcPixel);
+ rv = m_Convert;
+ }
+ else if (m_Space==NextSpace) {
+ rv = SrcPixel;
+ }
+ else if (m_Space==icSigXYZData && NextSpace==icSigLabData) {
+ XyzToLab(m_Convert, SrcPixel, bNoClip);
+ rv = m_Convert;
+ }
+ else if (m_Space==icSigLabData && NextSpace==icSigXYZData) {
+ LabToXyz(m_Convert, SrcPixel, bNoClip);
+ rv = m_Convert;
+ }
+ else {
+ rv = SrcPixel;
+ }
+
+ m_Space = pXform->GetDstSpace();
+ m_bIsV2Lab = bIsV2 && (m_Space == icSigLabData);
+
+ return rv;
+}
+
+/**
+ **************************************************************************
+ * Name: CIccPCS::CheckLast
+ *
+ * Purpose:
+ * Called after all xforms are applied to adjust PCS to final space if needed
+ * Note: space will always be V4.
+ *
+ * Args:
+ * Pixel = Pixel data,
+ * DestSpace = destination color space
+ * bNoClip = indicates whether PCS should be clipped
+ **************************************************************************
+ */
+void CIccPCS::CheckLast(icFloatNumber *Pixel, icColorSpaceSignature DestSpace, bool bNoClip)
+{
+ if (m_bIsV2Lab) {
+ Lab2ToLab4(Pixel, Pixel, bNoClip);
+ if (DestSpace==icSigXYZData) {
+ LabToXyz(Pixel, Pixel, bNoClip);
+ }
+ }
+ else if (m_Space==DestSpace) {
+ return;
+ }
+ else if (m_Space==icSigXYZData) {
+ XyzToLab(Pixel, Pixel, bNoClip);
+ }
+ else if (m_Space==icSigLabData) {
+ LabToXyz(Pixel, Pixel, bNoClip);
+ }
+}
+
+/**
+ **************************************************************************
+ * Name: CIccPCS::UnitClip
+ *
+ * Purpose:
+ * Convert a double to an icUInt16Number with clipping
+ **************************************************************************
+ */
+icFloatNumber CIccPCS::UnitClip(icFloatNumber v)
+{
+ if (v<0)
+ v = 0;
+ if (v>1.0)
+ v = 1.0;
+
+ return v;
+}
+
+/**
+ **************************************************************************
+ * Name: CIccPCS::NegClip
+ *
+ * Purpose:
+ * Convert a double to an icUInt16Number with clipping of negative numbers
+ **************************************************************************
+ */
+icFloatNumber CIccPCS::NegClip(icFloatNumber v)
+{
+ if (v<0)
+ v=0;
+
+ return v;
+}
+
+/**
+ **************************************************************************
+ * Name: CIccPCS::LabToXyz
+ *
+ * Purpose:
+ * Convert Lab to XYZ
+ **************************************************************************
+ */
+void CIccPCS::LabToXyz(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip)
+{
+ icFloatNumber Lab[3];
+
+ memcpy(&Lab,Src,sizeof(Lab));
+
+ icLabFromPcs(Lab);
+
+ icLabtoXYZ(Lab);
+
+ icXyzToPcs(Lab);
+
+ if (!bNoClip) {
+ Dst[0] = UnitClip(Lab[0]);
+ Dst[1] = UnitClip(Lab[1]);
+ Dst[2] = UnitClip(Lab[2]);
+ }
+ else {
+ Dst[0] = Lab[0];
+ Dst[1] = Lab[1];
+ Dst[2] = Lab[2];
+ }
+}
+
+
+/**
+ **************************************************************************
+ * Name: CIccPCS::XyzToLab
+ *
+ * Purpose:
+ * Convert XYZ to Lab
+ **************************************************************************
+ */
+void CIccPCS::XyzToLab(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip)
+{
+ icFloatNumber XYZ[3];
+
+
+ if (!bNoClip) {
+ XYZ[0] = UnitClip(Src[0]);
+ XYZ[1] = UnitClip(Src[1]);
+ XYZ[2] = UnitClip(Src[2]);
+ }
+ else {
+ XYZ[0] = Src[0];
+ XYZ[1] = Src[1];
+ XYZ[2] = Src[2];
+ }
+
+ icXyzFromPcs(XYZ);
+
+ icXYZtoLab(XYZ);
+
+ icLabToPcs(XYZ);
+
+ if (!bNoClip) {
+ Dst[0] = UnitClip(XYZ[0]);
+ Dst[1] = UnitClip(XYZ[1]);
+ Dst[2] = UnitClip(XYZ[2]);
+ }
+ else {
+ Dst[0] = XYZ[0];
+ Dst[1] = XYZ[1];
+ Dst[2] = XYZ[2];
+ }
+}
+
+
+/**
+ **************************************************************************
+ * Name: CIccPCS::Lab2ToXyz
+ *
+ * Purpose:
+ * Convert version 2 Lab to XYZ
+ **************************************************************************
+ */
+void CIccPCS::Lab2ToXyz(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip)
+{
+ Lab2ToLab4(Dst, Src, bNoClip);
+ LabToXyz(Dst, Dst, bNoClip);
+}
+
+
+/**
+ **************************************************************************
+ * Name: CIccPCS::XyzToLab2
+ *
+ * Purpose:
+ * Convert XYZ to version 2 Lab
+ **************************************************************************
+ */
+void CIccPCS::XyzToLab2(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip)
+{
+ XyzToLab(Dst, Src, bNoClip);
+ Lab4ToLab2(Dst, Dst);
+}
+
+
+/**
+ **************************************************************************
+ * Name: CIccPCS::Lab2ToLab4
+ *
+ * Purpose:
+ * Convert version 2 Lab to version 4 Lab
+ **************************************************************************
+ */
+void CIccPCS::Lab2ToLab4(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip)
+{
+ if (bNoClip) {
+ Dst[0] = (icFloatNumber)(Src[0] * 65535.0f / 65280.0f);
+ Dst[1] = (icFloatNumber)(Src[1] * 65535.0f / 65280.0f);
+ Dst[2] = (icFloatNumber)(Src[2] * 65535.0f / 65280.0f);
+ }
+ else {
+ Dst[0] = UnitClip((icFloatNumber)(Src[0] * 65535.0f / 65280.0f));
+ Dst[1] = UnitClip((icFloatNumber)(Src[1] * 65535.0f / 65280.0f));
+ Dst[2] = UnitClip((icFloatNumber)(Src[2] * 65535.0f / 65280.0f));
+ }
+}
+
+/**
+ **************************************************************************
+ * Name: CIccPCS::Lab4ToLab2
+ *
+ * Purpose:
+ * Convert version 4 Lab to version 2 Lab
+ **************************************************************************
+ */
+void CIccPCS::Lab4ToLab2(icFloatNumber *Dst, const icFloatNumber *Src)
+{
+ Dst[0] = (icFloatNumber)(Src[0] * 65280.0f / 65535.0f);
+ Dst[1] = (icFloatNumber)(Src[1] * 65280.0f / 65535.0f);
+ Dst[2] = (icFloatNumber)(Src[2] * 65280.0f / 65535.0f);
+}
+
+/**
+**************************************************************************
+* Name: CIccCreateXformHintManager::CIccCreateXformHintManager
+*
+* Purpose:
+* Destructor
+**************************************************************************
+*/
+CIccCreateXformHintManager::~CIccCreateXformHintManager()
+{
+ if (m_pList) {
+ IIccCreateXformHintList::iterator i;
+
+ for (i=m_pList->begin(); i!=m_pList->end(); i++) {
+ if (i->ptr)
+ delete i->ptr;
+ }
+
+ delete m_pList;
+ }
+}
+
+/**
+**************************************************************************
+* Name: CIccCreateXformHintManager::AddHint
+*
+* Purpose:
+* Adds and owns the passed named hint to it's list.
+*
+* Args:
+* pHint = pointer to the hint object to be added
+*
+* Return:
+* true = hint added to the list
+* false = hint not added
+**************************************************************************
+*/
+bool CIccCreateXformHintManager::AddHint(IIccCreateXformHint* pHint)
+{
+ if (!m_pList) {
+ m_pList = new IIccCreateXformHintList;
+ }
+
+ if (pHint) {
+ if (GetHint(pHint->GetHintType())) {
+ delete pHint;
+ return false;
+ }
+ IIccCreateXformHintPtr Hint;
+ Hint.ptr = pHint;
+ m_pList->push_back(Hint);
+ return true;
+ }
+
+ return false;
+}
+
+/**
+**************************************************************************
+* Name: CIccCreateXformHintManager::DeleteHint
+*
+* Purpose:
+* Deletes the object referenced by the passed named hint pointer
+* and removes it from the list.
+*
+* Args:
+* pHint = pointer to the hint object to be deleted
+*
+* Return:
+* true = hint found and deleted
+* false = hint not found
+**************************************************************************
+*/
+bool CIccCreateXformHintManager::DeleteHint(IIccCreateXformHint* pHint)
+{
+ if (m_pList && pHint) {
+ IIccCreateXformHintList::iterator i;
+ for (i=m_pList->begin(); i!=m_pList->end(); i++) {
+ if (i->ptr) {
+ if (i->ptr == pHint) {
+ delete pHint;
+ pHint = NULL;
+ m_pList->erase(i);
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+/**
+**************************************************************************
+* Name: CIccCreateXformHintManager::GetHint
+*
+* Purpose:
+* Finds and returns a pointer to the named hint.
+*
+* Args:
+* hintName = name of the desired hint
+*
+* Return:
+* Appropriate IIccCreateXformHint pointer
+**************************************************************************
+*/
+IIccCreateXformHint* CIccCreateXformHintManager::GetHint(const char* hintName)
+{
+ IIccCreateXformHint* pHint=NULL;
+
+ if (m_pList) {
+ IIccCreateXformHintList::iterator i;
+ for (i=m_pList->begin(); i!=m_pList->end(); i++) {
+ if (i->ptr) {
+ if (!strcmp(i->ptr->GetHintType(), hintName)) {
+ pHint = i->ptr;
+ break;
+ }
+ }
+ }
+ }
+
+ return pHint;
+}
+
+/**
+ **************************************************************************
+ * Name: CIccXform::CIccXform
+ *
+ * Purpose:
+ * Constructor
+ **************************************************************************
+ */
+CIccXform::CIccXform()
+{
+ m_pProfile = NULL;
+ m_bInput = true;
+ m_nIntent = icUnknownIntent;
+ m_pAdjustPCS = NULL;
+ m_bAdjustPCS = false;
+}
+
+
+/**
+ **************************************************************************
+ * Name: CIccXform::~CIccXform
+ *
+ * Purpose:
+ * Destructor
+ **************************************************************************
+ */
+CIccXform::~CIccXform()
+{
+ if (m_pProfile)
+ delete m_pProfile;
+
+ if (m_pAdjustPCS) {
+ delete m_pAdjustPCS;
+ }
+
+}
+
+
+/**
+ **************************************************************************
+ * Name: CIccXform::Create
+ *
+ * Purpose:
+ * This is a static Creation function that creates derived CIccXform objects and
+ * initializes them.
+ *
+ * Args:
+ * pProfile = pointer to a CIccProfile object that will be owned by the transform. This object will
+ * be destroyed when the returned CIccXform object is destroyed. The means that the CIccProfile
+ * object needs to be allocated on the heap.
+ * bInput = flag to indicate whether to use the input or output side of the profile,
+ * nIntent = the rendering intent to apply to the profile,
+ * nInterp = the interpolation algorithm to use for N-D luts.
+ * nLutType = selection of which transform lut to use
+ * bUseMpeTags = flag to indicate the use MPE flags if available
+ * pHintManager = pointer to object that contains xform creation hints
+ *
+ * Return:
+ * A suitable pXform object
+ **************************************************************************
+ */
+CIccXform *CIccXform::Create(CIccProfile *pProfile, bool bInput/* =true */, icRenderingIntent nIntent/* =icUnknownIntent */,
+ icXformInterp nInterp/* =icInterpLinear */, icXformLutType nLutType/* =icXformLutColor */,
+ bool bUseMpeTags/* =true */, CIccCreateXformHintManager *pHintManager/* =NULL */)
+{
+ CIccXform *rv = NULL;
+ icRenderingIntent nTagIntent = nIntent;
+
+ if (pProfile->m_Header.deviceClass==icSigLinkClass && nIntent==icAbsoluteColorimetric) {
+ nIntent = icPerceptual;
+ }
+
+ if (nTagIntent == icUnknownIntent)
+ nTagIntent = icPerceptual;
+
+ switch (nLutType) {
+ case icXformLutColor:
+ if (bInput) {
+ CIccTag *pTag = NULL;
+ if (bUseMpeTags) {
+ pTag = pProfile->FindTag(icSigDToB0Tag + nTagIntent);
+
+ if (!pTag && nTagIntent ==icAbsoluteColorimetric) {
+ pTag = pProfile->FindTag(icSigDToB1Tag);
+ if (pTag)
+ nTagIntent = icRelativeColorimetric;
+ }
+
+ //Apparently Using DtoB0 is not prescribed here by the ICC Specification
+ //if (!pTag) {
+ // pTag = pProfile->FindTag(icSigDToB0Tag);
+ //}
+
+ //Unsupported elements cause fall back behavior
+ if (pTag && !pTag->IsSupported())
+ pTag = NULL;
+ }
+
+ if (!pTag) {
+ if (nTagIntent == icAbsoluteColorimetric)
+ nTagIntent = icRelativeColorimetric;
+ pTag = pProfile->FindTag(icSigAToB0Tag + nTagIntent);
+ }
+
+ if (!pTag) {
+ pTag = pProfile->FindTag(icSigAToB0Tag);
+ }
+
+ if (!pTag) {
+ if (pProfile->m_Header.colorSpace == icSigRgbData) {
+ rv = CIccXformCreator::CreateXform(icXformTypeMatrixTRC, NULL, pHintManager);
+ }
+ else if (pProfile->m_Header.colorSpace == icSigGrayData) {
+ rv = CIccXformCreator::CreateXform(icXformTypeMonochrome, NULL, pHintManager);
+ }
+ else
+ return NULL;
+ }
+ else if (pTag->GetType()==icSigMultiProcessElementType) {
+ rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager);
+ }
+ else {
+ switch(pProfile->m_Header.colorSpace) {
+ case icSigXYZData:
+ case icSigLabData:
+ case icSigLuvData:
+ case icSigYCbCrData:
+ case icSigYxyData:
+ case icSigRgbData:
+ case icSigHsvData:
+ case icSigHlsData:
+ case icSigCmyData:
+ case icSig3colorData:
+ rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager);
+ break;
+
+ case icSigCmykData:
+ case icSig4colorData:
+ rv = CIccXformCreator::CreateXform(icXformType4DLut, pTag, pHintManager);
+ break;
+
+ default:
+ rv = CIccXformCreator::CreateXform(icXformTypeNDLut, pTag, pHintManager);
+ break;
+ }
+ }
+ }
+ else {
+ CIccTag *pTag = NULL;
+
+ if (bUseMpeTags) {
+ pTag = pProfile->FindTag(icSigBToD0Tag + nTagIntent);
+
+ if (!pTag && nTagIntent ==icAbsoluteColorimetric) {
+ pTag = pProfile->FindTag(icSigBToD1Tag);
+ if (pTag)
+ nTagIntent = icRelativeColorimetric;
+ }
+
+ //Apparently Using BtoD0 is not prescribed here by the ICC Specification
+ //if (!pTag) {
+ // pTag = pProfile->FindTag(icSigBToD0Tag);
+ //}
+
+ //Unsupported elements cause fall back behavior
+ if (pTag && !pTag->IsSupported())
+ pTag = NULL;
+ }
+
+ if (!pTag) {
+ if (nTagIntent == icAbsoluteColorimetric)
+ nTagIntent = icRelativeColorimetric;
+ pTag = pProfile->FindTag(icSigBToA0Tag + nTagIntent);
+ }
+
+ if (!pTag) {
+ pTag = pProfile->FindTag(icSigBToA0Tag);
+ }
+
+ if (!pTag) {
+ if (pProfile->m_Header.colorSpace == icSigRgbData) {
+ rv = CIccXformCreator::CreateXform(icXformTypeMatrixTRC, pTag, pHintManager);
+ }
+ else if (pProfile->m_Header.colorSpace == icSigGrayData) {
+ rv = CIccXformCreator::CreateXform(icXformTypeMonochrome, NULL, pHintManager);
+ }
+ else
+ return NULL;
+ }
+ else if (pTag->GetType()==icSigMultiProcessElementType) {
+ rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager);
+ }
+ else {
+ switch(pProfile->m_Header.pcs) {
+ case icSigXYZData:
+ case icSigLabData:
+ rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ break;
+
+ case icXformLutNamedColor:
+ {
+ CIccTag *pTag = pProfile->FindTag(icSigNamedColor2Tag);
+ if (!pTag)
+ return NULL;
+
+ CIccCreateNamedColorXformHint* pNamedColorHint = new CIccCreateNamedColorXformHint();
+ pNamedColorHint->csPcs = pProfile->m_Header.pcs;
+ pNamedColorHint->csDevice = pProfile->m_Header.colorSpace;
+ if (pHintManager) {
+ pHintManager->AddHint(pNamedColorHint);
+ rv = CIccXformCreator::CreateXform(icXformTypeNamedColor, pTag, pHintManager);
+ pHintManager->DeleteHint(pNamedColorHint);
+ }
+ else {
+ CIccCreateXformHintManager HintManager;
+ HintManager.AddHint(pNamedColorHint);
+ rv = CIccXformCreator::CreateXform(icXformTypeNamedColor, pTag, &HintManager);
+ }
+ }
+ break;
+
+ case icXformLutPreview:
+ {
+ bInput = false;
+ CIccTag *pTag = pProfile->FindTag(icSigPreview0Tag + nTagIntent);
+ if (!pTag) {
+ pTag = pProfile->FindTag(icSigPreview0Tag);
+ }
+ if (!pTag) {
+ return NULL;
+ }
+ else {
+ switch(pProfile->m_Header.pcs) {
+ case icSigXYZData:
+ case icSigLabData:
+ rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager);
+
+ default:
+ break;
+ }
+ }
+ }
+ break;
+
+ case icXformLutGamut:
+ {
+ bInput = false;
+ CIccTag *pTag = pProfile->FindTag(icSigGamutTag);
+ if (!pTag) {
+ return NULL;
+ }
+ else {
+ switch(pProfile->m_Header.pcs) {
+ case icSigXYZData:
+ case icSigLabData:
+ rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager);
+
+ default:
+ break;
+ }
+ }
+ }
+ break;
+ }
+
+ if (rv) {
+ rv->SetParams(pProfile, bInput, nIntent, nInterp, pHintManager);
+ }
+
+ return rv;
+}
+
+/**
+ ******************************************************************************
+ * Name: CIccXform::SetParams
+ *
+ * Purpose:
+ * This is an accessor function to set private values.
+ *
+ * Args:
+ * pProfile = pointer to profile associated with transform
+ * bInput = indicates whether profile is input profile
+ * nIntent = rendering intent to apply to the profile
+ * nInterp = the interpolation algorithm to use for N-D luts
+ ******************************************************************************/
+void CIccXform::SetParams(CIccProfile *pProfile, bool bInput, icRenderingIntent nIntent,
+ icXformInterp nInterp, CIccCreateXformHintManager *pHintManager/* =NULL */)
+{
+ m_pProfile = pProfile;
+ m_bInput = bInput;
+ m_nIntent = nIntent;
+ m_nInterp = nInterp;
+ m_pAdjustPCS = NULL;
+
+ IIccCreateXformHint *pHint=NULL;
+ if (pHintManager && (pHint = pHintManager->GetHint("CIccCreateAdjustPCSXformHint"))){
+ CIccCreateAdjustPCSXformHint *pAdjustPCSHint = (CIccCreateAdjustPCSXformHint*)pHint;
+ m_pAdjustPCS = pAdjustPCSHint->GetNewAdjustPCSXform();
+ }
+}
+
+/**
+ **************************************************************************
+ * Name: CIccXform::Create
+ *
+ * Purpose:
+ * This is a static Creation function that creates derived CIccXform objects and
+ * initializes them.
+ *
+ * Args:
+ * Profile = reference to a CIccProfile object that will be used to create the transform.
+ * A copy of the CIccProfile object will be created and passed to the pointer based Create().
+ * The copied object will be destroyed when the returned CIccXform object is destroyed.
+ * bInput = flag to indicate whether to use the input or output side of the profile,
+ * nIntent = the rendering intent to apply to the profile,
+ * nInterp = the interpolation algorithm to use for N-D luts.
+ * nLutType = selection of which transform lut to use
+ * bUseMpeTags = flag to indicate the use MPE flags if available
+ * pHint = pointer to object passed to CIccXform creation functionality
+ *
+ * Return:
+ * A suitable pXform object
+ **************************************************************************
+ */
+CIccXform *CIccXform::Create(CIccProfile &Profile, bool bInput/* =true */, icRenderingIntent nIntent/* =icUnknownIntent */,
+ icXformInterp nInterp/* =icInterpLinear */, icXformLutType nLutType/* =icXformLutColor */,
+ bool bUseMpeTags/* =true */, CIccCreateXformHintManager *pHintManager/* =NULL */)
+{
+ CIccProfile *pProfile = new CIccProfile(Profile);
+ CIccXform *pXform = Create(pProfile, bInput, nIntent, nInterp, nLutType, bUseMpeTags, pHintManager);
+
+ if (!pXform)
+ delete pProfile;
+
+ return pXform;
+}
+
+
+/**
+ **************************************************************************
+ * Name: CIccXform::Begin
+ *
+ * Purpose:
+ * This function will be called before the xform is applied. Derived objects
+ * should also call this base class function to initialize for Absolute Colorimetric
+ * Intent handling which is performed through the use of the CheckSrcAbs and
+ * CheckDstAbs functions.
+ **************************************************************************
+ */
+icStatusCMM CIccXform::Begin()
+{
+ if (m_nIntent==icAbsoluteColorimetric) {
+ CIccTag *pTag = m_pProfile->FindTag(icSigMediaWhitePointTag);
+
+ if (!pTag || pTag->GetType()!=icSigXYZType)
+ return icCmmStatInvalidProfile;
+
+ CIccTagXYZ *pXyzTag = (CIccTagXYZ*)pTag;
+
+ m_MediaXYZ = (*pXyzTag)[0];
+ }
+
+ // set up for any needed PCS adjustment
+ if (m_nIntent == icAbsoluteColorimetric &&
+ (m_MediaXYZ.X != m_pProfile->m_Header.illuminant.X ||
+ m_MediaXYZ.Y != m_pProfile->m_Header.illuminant.Y ||
+ m_MediaXYZ.Z != m_pProfile->m_Header.illuminant.Z)) {
+
+ icColorSpaceSignature Space = m_pProfile->m_Header.pcs;
+
+ if (IsSpacePCS(Space)) {
+ m_bAdjustPCS = true; // turn ON PCS adjustment
+
+ // scale factors depend upon media white point
+ // set up for input transform
+ m_PCSScale[0] = (icFloatNumber) m_MediaXYZ.X / m_pProfile->m_Header.illuminant.X; // convert to icFloat to avoid precision errors
+ m_PCSScale[1] = (icFloatNumber) m_MediaXYZ.Y / m_pProfile->m_Header.illuminant.Y;
+ m_PCSScale[2] = (icFloatNumber) m_MediaXYZ.Z / m_pProfile->m_Header.illuminant.Z;
+
+ if (!m_bInput) {
+ m_PCSScale[0] = (icFloatNumber) 1.0 / m_PCSScale[0]; // inverse for output transform
+ m_PCSScale[1] = (icFloatNumber) 1.0 / m_PCSScale[1];
+ m_PCSScale[2] = (icFloatNumber) 1.0 / m_PCSScale[2];
+ }
+
+ m_PCSOffset[0] = 0.0;
+ m_PCSOffset[1] = 0.0;
+ m_PCSOffset[2] = 0.0;
+ }
+ }
+ else if (m_nIntent == icPerceptual && (IsVersion2() || !HasPerceptualHandling())) {
+ icColorSpaceSignature Space = m_pProfile->m_Header.pcs;
+
+ if (IsSpacePCS(Space) && m_pProfile->m_Header.deviceClass!=icSigAbstractClass) {
+ m_bAdjustPCS = true; // turn ON PCS adjustment
+
+ // set up for input transform, which needs version 2 black point to version 4
+ m_PCSScale[0] = (icFloatNumber) (1.0 - icPerceptualRefBlackX / icPerceptualRefWhiteX); // scale factors
+ m_PCSScale[1] = (icFloatNumber) (1.0 - icPerceptualRefBlackY / icPerceptualRefWhiteY);
+ m_PCSScale[2] = (icFloatNumber) (1.0 - icPerceptualRefBlackZ / icPerceptualRefWhiteZ);
+
+ m_PCSOffset[0] = (icFloatNumber) (icPerceptualRefBlackX * 32768.0 / 65535.0); // offset factors
+ m_PCSOffset[1] = (icFloatNumber) (icPerceptualRefBlackY * 32768.0 / 65535.0);
+ m_PCSOffset[2] = (icFloatNumber) (icPerceptualRefBlackZ * 32768.0 / 65535.0);
+
+ if (!m_bInput) { // output transform must convert version 4 black point to version 2
+ m_PCSScale[0] = (icFloatNumber) 1.0 / m_PCSScale[0]; // invert scale factors
+ m_PCSScale[1] = (icFloatNumber) 1.0 / m_PCSScale[1];
+ m_PCSScale[2] = (icFloatNumber) 1.0 / m_PCSScale[2];
+
+ m_PCSOffset[0] = - m_PCSOffset[0] * m_PCSScale[0]; // negate offset factors
+ m_PCSOffset[1] = - m_PCSOffset[1] * m_PCSScale[1];
+ m_PCSOffset[2] = - m_PCSOffset[2] * m_PCSScale[2];
+ }
+ }
+ }
+
+
+ if (m_pAdjustPCS) {
+ CIccProfile ProfileCopy(*m_pProfile);
+
+ // need to read in all the tags, so that a copy of the profile can be made
+ if (!ProfileCopy.ReadTags(m_pProfile)) {
+ return icCmmStatInvalidProfile;
+ }
+
+ if (!m_pAdjustPCS->CalcFactors(&ProfileCopy, this, m_PCSScale, m_PCSOffset)) {
+ return icCmmStatIncorrectApply;
+ }
+
+ m_bAdjustPCS = true;
+ delete m_pAdjustPCS;
+ m_pAdjustPCS = NULL;
+ }
+
+ return icCmmStatOk;
+}
+
+/**
+**************************************************************************
+* Name: CIccXform::GetNewApply
+*
+* Purpose:
+* This Factory function allocates data specific for the application of the xform.
+* This allows multiple threads to simultaneously use the same xform.
+**************************************************************************
+*/
+CIccApplyXform *CIccXform::GetNewApply(icStatusCMM &status)
+{
+ CIccApplyXform *rv = new CIccApplyXform(this);
+
+ if (!rv) {
+ status = icCmmStatAllocErr;
+ return NULL;
+ }
+
+ status = icCmmStatOk;
+ return rv;
+}
+
+/**
+ **************************************************************************
+* Name: CIccXform::AdjustPCS
+ *
+ * Purpose:
+* This function will take care of any PCS adjustments
+* needed by the xform (the PCS is always version 4 relative).
+ *
+ * Args:
+* DstPixel = Destination pixel where the result is stored,
+* SrcPixel = Source pixel which is to be applied.
+ *
+ **************************************************************************
+ */
+void CIccXform::AdjustPCS(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const
+{
+ icColorSpaceSignature Space = m_pProfile->m_Header.pcs;
+
+ if (Space==icSigLabData) {
+ if (UseLegacyPCS()) {
+ CIccPCS::Lab2ToXyz(DstPixel, SrcPixel, true);
+ }
+ else {
+ CIccPCS::LabToXyz(DstPixel, SrcPixel, true);
+ }
+ }
+ else {
+ DstPixel[0] = SrcPixel[0];
+ DstPixel[1] = SrcPixel[1];
+ DstPixel[2] = SrcPixel[2];
+ }
+
+ DstPixel[0] = (icFloatNumber)(DstPixel[0] * m_PCSScale[0] + m_PCSOffset[0]);
+ DstPixel[1] = (icFloatNumber)(DstPixel[1] * m_PCSScale[1] + m_PCSOffset[1]);
+ DstPixel[2] = (icFloatNumber)(DstPixel[2] * m_PCSScale[2] + m_PCSOffset[2]);
+
+ if (Space==icSigLabData) {
+ if (UseLegacyPCS()) {
+ CIccPCS::XyzToLab2(DstPixel, DstPixel, true);
+ }
+ else {
+ CIccPCS::XyzToLab(DstPixel, DstPixel, true);
+ }
+ }
+#ifndef SAMPLEICC_NOCLIPLABTOXYZ
+ else {
+ DstPixel[0] = CIccPCS::NegClip(DstPixel[0]);
+ DstPixel[1] = CIccPCS::NegClip(DstPixel[1]);
+ DstPixel[2] = CIccPCS::NegClip(DstPixel[2]);
+ }
+#endif
+}
+
+/**
+ **************************************************************************
+ * Name: CIccXform::CheckSrcAbs
+ *
+ * Purpose:
+ * This function will be called by a derived CIccXform object's Apply() function
+ * BEFORE the actual xform is performed to take care of Absolute to Relative
+ * adjustments needed by the xform (IE the PCS is always version 4 relative).
+ *
+ * Args:
+ * Pixel = src pixel data (will not be modified)
+ *
+ * Return:
+ * returns Pixel or adjusted pixel data.
+ **************************************************************************
+ */
+const icFloatNumber *CIccXform::CheckSrcAbs(CIccApplyXform *pApply, const icFloatNumber *Pixel) const
+{
+ icFloatNumber *pAbsLab = pApply->m_AbsLab;
+ if (m_bAdjustPCS && !m_bInput) {
+ AdjustPCS(pAbsLab, Pixel);
+ return pAbsLab;
+ }
+
+ return Pixel;
+}
+
+/**
+ **************************************************************************
+ * Name: CIccXform::CheckDstAbs
+ *
+ * Purpose:
+ * This function will be called by a derived CIccXform object's Apply() function
+ * AFTER the actual xform is performed to take care of Absolute to Relative
+ * adjustments needed by the xform (IE the PCS is always version 4 relative).
+ *
+ * Args:
+ * Pixel = source pixel data which will be modified
+ *
+ **************************************************************************
+ */
+void CIccXform::CheckDstAbs(icFloatNumber *Pixel) const
+{
+ if (m_bAdjustPCS && m_bInput) {
+ AdjustPCS(Pixel, Pixel);
+ }
+ }
+
+/**
+**************************************************************************
+* Name: CIccXformMatrixTRC::GetSrcSpace
+*
+* Purpose:
+* Return the color space that is input to the transform.
+* If a device space is either XYZ/Lab it is changed to dXYZ/dLab to avoid
+* confusion with PCS encoding of these spaces. Device encoding of XYZ
+* and Lab spaces left to the device.
+**************************************************************************
+*/
+icColorSpaceSignature CIccXform::GetSrcSpace() const
+{
+ icColorSpaceSignature rv;
+ icProfileClassSignature deviceClass = m_pProfile->m_Header.deviceClass;
+
+ if (m_bInput) {
+ rv = m_pProfile->m_Header.colorSpace;
+
+ if (deviceClass != icSigAbstractClass) {
+ //convert signature to device colorspace signature (avoid confusion about encoding).
+ if (rv==icSigXYZData) {
+ rv = icSigDevXYZData;
+ }
+ else if (rv==icSigLabData) {
+ rv = icSigDevLabData;
+ }
+ }
+ }
+ else {
+ rv = m_pProfile->m_Header.pcs;
+ }
+
+ return rv;
+}
+
+/**
+**************************************************************************
+* Name: CIccXformMatrixTRC::GetDstSpace
+*
+* Purpose:
+* Return the color space that is output by the transform.
+* If a device space is either XYZ/Lab it is changed to dXYZ/dLab to avoid
+* confusion with PCS encoding of these spaces. Device encoding of XYZ
+* and Lab spaces left to the device.
+**************************************************************************
+*/
+icColorSpaceSignature CIccXform::GetDstSpace() const
+{
+ icColorSpaceSignature rv;
+ icProfileClassSignature deviceClass = m_pProfile->m_Header.deviceClass;
+
+ if (m_bInput) {
+ rv = m_pProfile->m_Header.pcs;
+ }
+ else {
+ rv = m_pProfile->m_Header.colorSpace;
+
+ //convert signature to device colorspace signature (avoid confusion about encoding).
+ if (deviceClass != icSigAbstractClass) {
+ if (rv==icSigXYZData) {
+ rv = icSigDevXYZData;
+ }
+ else if (rv==icSigLabData) {
+ rv = icSigDevLabData;
+ }
+ }
+ }
+
+ return rv;
+}
+
+/**
+**************************************************************************
+* Name: CIccApplyXform::CIccApplyXform
+*
+* Purpose:
+* Constructor
+**************************************************************************
+*/
+CIccApplyXform::CIccApplyXform(CIccXform *pXform)
+{
+ m_pXform = pXform;
+}
+
+/**
+**************************************************************************
+* Name: CIccApplyXform::CIccApplyXform
+*
+* Purpose:
+* Destructor
+**************************************************************************
+*/
+CIccApplyXform::~CIccApplyXform()
+{
+}
+
+/**
+**************************************************************************
+* Name: CIccXformMonochrome::CIccXformMonochrome
+*
+* Purpose:
+* Constructor
+**************************************************************************
+*/
+CIccXformMonochrome::CIccXformMonochrome()
+{
+ m_Curve = NULL;
+ m_ApplyCurvePtr = NULL;
+ m_bFreeCurve = false;
+}
+
+/**
+**************************************************************************
+* Name: CIccXformMonochrome::~CIccXformMonochrome
+*
+* Purpose:
+* Destructor
+**************************************************************************
+*/
+CIccXformMonochrome::~CIccXformMonochrome()
+{
+ if (m_bFreeCurve && m_Curve) {
+ delete m_Curve;
+ }
+}
+
+/**
+**************************************************************************
+* Name: CIccXformMonochrome::Begin
+*
+* Purpose:
+* Does the initialization of the Xform before Apply() is called.
+* Must be called before Apply().
+*
+**************************************************************************
+*/
+icStatusCMM CIccXformMonochrome::Begin()
+{
+ icStatusCMM status;
+
+ status = CIccXform::Begin();
+ if (status != icCmmStatOk)
+ return status;
+
+ m_ApplyCurvePtr = NULL;
+
+ if (m_bInput) {
+ m_Curve = GetCurve(icSigGrayTRCTag);
+
+ if (!m_Curve) {
+ return icCmmStatProfileMissingTag;
+ }
+ }
+ else {
+ m_Curve = GetInvCurve(icSigGrayTRCTag);
+ m_bFreeCurve = true;
+
+ if (!m_Curve) {
+ return icCmmStatProfileMissingTag;
+ }
+ }
+
+ m_Curve->Begin();
+ if (!m_Curve->IsIdentity()) {
+ m_ApplyCurvePtr = m_Curve;
+ }
+
+ return icCmmStatOk;
+}
+
+/**
+**************************************************************************
+* Name: CIccXformMonochrome::Apply
+*
+* Purpose:
+* Does the actual application of the Xform.
+*
+* Args:
+* pApply = ApplyXform object containing temporary storage used during Apply
+* DstPixel = Destination pixel where the result is stored,
+* SrcPixel = Source pixel which is to be applied.
+**************************************************************************
+*/
+void CIccXformMonochrome::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const
+{
+ icFloatNumber Pixel[3];
+ SrcPixel = CheckSrcAbs(pApply, SrcPixel);
+
+ if (m_bInput) {
+ Pixel[0] = SrcPixel[0];
+
+ if (m_ApplyCurvePtr) {
+ Pixel[0] = m_ApplyCurvePtr->Apply(Pixel[0]);
+ }
+
+ DstPixel[0] = icFloatNumber(icPerceptualRefWhiteX);
+ DstPixel[1] = icFloatNumber(icPerceptualRefWhiteY);
+ DstPixel[2] = icFloatNumber(icPerceptualRefWhiteZ);
+
+ icXyzToPcs(DstPixel);
+
+ if (m_pProfile->m_Header.pcs==icSigLabData) {
+ if (UseLegacyPCS()) {
+ CIccPCS::XyzToLab2(DstPixel, DstPixel, true);
+ }
+ else {
+ CIccPCS::XyzToLab(DstPixel, DstPixel, true);
+ }
+ }
+
+ DstPixel[0] *= Pixel[0];
+ DstPixel[1] *= Pixel[0];
+ DstPixel[2] *= Pixel[0];
+ }
+ else {
+ Pixel[0] = icFloatNumber(icPerceptualRefWhiteX);
+ Pixel[1] = icFloatNumber(icPerceptualRefWhiteY);
+ Pixel[2] = icFloatNumber(icPerceptualRefWhiteZ);
+
+ icXyzToPcs(Pixel);
+
+ if (m_pProfile->m_Header.pcs==icSigLabData) {
+ if (UseLegacyPCS()) {
+ CIccPCS::XyzToLab2(Pixel, Pixel, true);
+ }
+ else {
+ CIccPCS::XyzToLab(Pixel, Pixel, true);
+ }
+ DstPixel[0] = SrcPixel[0]/Pixel[0];
+ }
+ else {
+ DstPixel[0] = SrcPixel[1]/Pixel[1];
+ }
+
+ if (m_ApplyCurvePtr) {
+ DstPixel[0] = m_ApplyCurvePtr->Apply(DstPixel[0]);
+ }
+ }
+
+ CheckDstAbs(DstPixel);
+}
+
+/**
+**************************************************************************
+* Name: CIccXformMonochrome::GetCurve
+*
+* Purpose:
+* Gets the curve having the passed signature, from the profile.
+*
+* Args:
+* sig = signature of the curve to be found
+*
+* Return:
+* Pointer to the curve.
+**************************************************************************
+*/
+CIccCurve *CIccXformMonochrome::GetCurve(icSignature sig) const
+{
+ CIccTag *pTag = m_pProfile->FindTag(sig);
+
+ if (pTag && (pTag->GetType()==icSigCurveType || pTag->GetType()==icSigParametricCurveType)) {
+ return (CIccCurve*)pTag;
+ }
+
+ return NULL;
+}
+
+/**
+**************************************************************************
+* Name: CIccXformMonochrome::GetInvCurve
+*
+* Purpose:
+* Gets the inverted curve having the passed signature, from the profile.
+*
+* Args:
+* sig = signature of the curve to be inverted
+*
+* Return:
+* Pointer to the inverted curve.
+**************************************************************************
+*/
+CIccCurve *CIccXformMonochrome::GetInvCurve(icSignature sig) const
+{
+ CIccCurve *pCurve;
+ CIccTagCurve *pInvCurve;
+
+ if (!(pCurve = GetCurve(sig)))
+ return NULL;
+
+ pCurve->Begin();
+
+ pInvCurve = new CIccTagCurve(2048);
+
+ int i;
+ icFloatNumber x;
+ icFloatNumber *Lut = &(*pInvCurve)[0];
+
+ for (i=0; i<2048; i++) {
+ x=(icFloatNumber)i / 2047;
+
+ Lut[i] = pCurve->Find(x);
+ }
+
+ return pInvCurve;
+}
+
+/**
+**************************************************************************
+* Name: CIccXformMonochrome::ExtractInputCurves
+*
+* Purpose:
+* Gets the input curves. Should be called only after Begin()
+* has been called. Once the curves are extracted, they will
+* not be used by the Apply() function.
+* WARNING: caller owns the curves and must be deleted by the caller.
+*
+* Return:
+* Pointer to the input curves.
+**************************************************************************
+*/
+LPIccCurve* CIccXformMonochrome::ExtractInputCurves()
+{
+ if (m_bInput) {
+ if (m_Curve) {
+ LPIccCurve* Curve = new LPIccCurve[1];
+ Curve[0] = (LPIccCurve)(m_Curve->NewCopy());
+ m_ApplyCurvePtr = NULL;
+ return Curve;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+**************************************************************************
+* Name: CIccXformMonochrome::ExtractOutputCurves
+*
+* Purpose:
+* Gets the output curves. Should be called only after Begin()
+* has been called. Once the curves are extracted, they will
+* not be used by the Apply() function.
+* WARNING: caller owns the curves and must be deleted by the caller.
+*
+* Return:
+* Pointer to the output curves.
+**************************************************************************
+*/
+LPIccCurve* CIccXformMonochrome::ExtractOutputCurves()
+{
+ if (!m_bInput) {
+ if (m_Curve) {
+ LPIccCurve* Curve = new LPIccCurve[1];
+ Curve[0] = (LPIccCurve)(m_Curve->NewCopy());
+ m_ApplyCurvePtr = NULL;
+ return Curve;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ **************************************************************************
+ * Name: CIccXformMatrixTRC::CIccXformMatrixTRC
+ *
+ * Purpose:
+ * Constructor
+ **************************************************************************
+ */
+CIccXformMatrixTRC::CIccXformMatrixTRC()
+{
+ m_Curve[0] = m_Curve[1] = m_Curve[2] = NULL;
+ m_ApplyCurvePtr = NULL;
+ m_bFreeCurve = false;
+}
+
+/**
+ **************************************************************************
+ * Name: CIccXformMatrixTRC::~CIccXformMatrixTRC
+ *
+ * Purpose:
+ * Destructor
+ **************************************************************************
+ */
+CIccXformMatrixTRC::~CIccXformMatrixTRC()
+{
+ if (m_bFreeCurve) {
+ if (m_Curve[0])
+ delete m_Curve[0];
+ if (m_Curve[1])
+ delete m_Curve[1];
+ if (m_Curve[2])
+ delete m_Curve[2];
+ }
+}
+
+/**
+ **************************************************************************
+ * Name: CIccXformMatrixTRC::Begin
+ *
+ * Purpose:
+ * Does the initialization of the Xform before Apply() is called.
+ * Must be called before Apply().
+ *
+ **************************************************************************
+ */
+icStatusCMM CIccXformMatrixTRC::Begin()
+{
+ icStatusCMM status;
+ const CIccTagXYZ *pXYZ;
+
+ status = CIccXform::Begin();
+ if (status != icCmmStatOk)
+ return status;
+
+ pXYZ = GetColumn(icSigRedMatrixColumnTag);
+ if (!pXYZ) {
+ return icCmmStatProfileMissingTag;
+ }
+
+ m_e[0] = icFtoD((*pXYZ)[0].X);
+ m_e[3] = icFtoD((*pXYZ)[0].Y);
+ m_e[6] = icFtoD((*pXYZ)[0].Z);
+
+ pXYZ = GetColumn(icSigGreenMatrixColumnTag);
+ if (!pXYZ) {
+ return icCmmStatProfileMissingTag;
+ }
+
+ m_e[1] = icFtoD((*pXYZ)[0].X);
+ m_e[4] = icFtoD((*pXYZ)[0].Y);
+ m_e[7] = icFtoD((*pXYZ)[0].Z);
+
+ pXYZ = GetColumn(icSigBlueMatrixColumnTag);
+ if (!pXYZ) {
+ return icCmmStatProfileMissingTag;
+ }
+
+ m_e[2] = icFtoD((*pXYZ)[0].X);
+ m_e[5] = icFtoD((*pXYZ)[0].Y);
+ m_e[8] = icFtoD((*pXYZ)[0].Z);
+
+ m_ApplyCurvePtr = NULL;
+
+ if (m_bInput) {
+ m_Curve[0] = GetCurve(icSigRedTRCTag);
+ m_Curve[1] = GetCurve(icSigGreenTRCTag);
+ m_Curve[2] = GetCurve(icSigBlueTRCTag);
+
+ if (!m_Curve[0] || !m_Curve[1] || !m_Curve[2]) {
+ return icCmmStatProfileMissingTag;
+ }
+
+ }
+ else {
+ if (m_pProfile->m_Header.pcs!=icSigXYZData) {
+ return icCmmStatBadSpaceLink;
+ }
+
+ m_Curve[0] = GetInvCurve(icSigRedTRCTag);
+ m_Curve[1] = GetInvCurve(icSigGreenTRCTag);
+ m_Curve[2] = GetInvCurve(icSigBlueTRCTag);
+
+ m_bFreeCurve = true;
+
+ if (!m_Curve[0] || !m_Curve[1] || !m_Curve[2]) {
+ return icCmmStatProfileMissingTag;
+ }
+
+ if (!icMatrixInvert3x3(m_e)) {
+ return icCmmStatInvalidProfile;
+ }
+ }
+
+ m_Curve[0]->Begin();
+ m_Curve[1]->Begin();
+ m_Curve[2]->Begin();
+
+ if (!m_Curve[0]->IsIdentity() || !m_Curve[1]->IsIdentity() || !m_Curve[2]->IsIdentity()) {
+ m_ApplyCurvePtr = m_Curve;
+ }
+
+ return icCmmStatOk;
+}
+
+
+static icFloatNumber XYZScale(icFloatNumber v)
+{
+ v = (icFloatNumber)(v * 32768.0 / 65535.0);
+ return v;
+}
+
+static icFloatNumber XYZDescale(icFloatNumber v)
+{
+ return (icFloatNumber)(v * 65535.0 / 32768.0);
+}
+
+static icFloatNumber RGBClip(icFloatNumber v, CIccCurve *pCurve)
+{
+ if (v<=0)
+ return(pCurve->Apply(0));
+ else if (v>=1.0)
+ return (pCurve->Apply(1.0));
+
+ return pCurve->Apply(v);
+}
+
+/**
+ **************************************************************************
+ * Name: CIccXformMatrixTRC::Apply
+ *
+ * Purpose:
+ * Does the actual application of the Xform.
+ *
+ * Args:
+ * pApply = ApplyXform object containging temporary storage used during Apply
+ * DstPixel = Destination pixel where the result is stored,
+ * SrcPixel = Source pixel which is to be applied.
+ **************************************************************************
+ */
+void CIccXformMatrixTRC::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const
+{
+ icFloatNumber Pixel[3];
+
+ SrcPixel = CheckSrcAbs(pApply, SrcPixel);
+ Pixel[0] = SrcPixel[0];
+ Pixel[1] = SrcPixel[1];
+ Pixel[2] = SrcPixel[2];
+
+ if (m_bInput) {
+
+ double LinR, LinG, LinB;
+ if (m_ApplyCurvePtr) {
+ LinR = m_ApplyCurvePtr[0]->Apply(Pixel[0]);
+ LinG = m_ApplyCurvePtr[1]->Apply(Pixel[1]);
+ LinB = m_ApplyCurvePtr[2]->Apply(Pixel[2]);
+ }
+ else {
+ LinR = Pixel[0];
+ LinG = Pixel[1];
+ LinB = Pixel[2];
+ }
+
+ DstPixel[0] = XYZScale((icFloatNumber)(m_e[0] * LinR + m_e[1] * LinG + m_e[2] * LinB));
+ DstPixel[1] = XYZScale((icFloatNumber)(m_e[3] * LinR + m_e[4] * LinG + m_e[5] * LinB));
+ DstPixel[2] = XYZScale((icFloatNumber)(m_e[6] * LinR + m_e[7] * LinG + m_e[8] * LinB));
+ }
+ else {
+ double X = XYZDescale(Pixel[0]);
+ double Y = XYZDescale(Pixel[1]);
+ double Z = XYZDescale(Pixel[2]);
+
+ if (m_ApplyCurvePtr) {
+ DstPixel[0] = RGBClip((icFloatNumber)(m_e[0] * X + m_e[1] * Y + m_e[2] * Z), m_ApplyCurvePtr[0]);
+ DstPixel[1] = RGBClip((icFloatNumber)(m_e[3] * X + m_e[4] * Y + m_e[5] * Z), m_ApplyCurvePtr[1]);
+ DstPixel[2] = RGBClip((icFloatNumber)(m_e[6] * X + m_e[7] * Y + m_e[8] * Z), m_ApplyCurvePtr[2]);
+ }
+ else {
+ DstPixel[0] = (icFloatNumber)(m_e[0] * X + m_e[1] * Y + m_e[2] * Z);
+ DstPixel[1] = (icFloatNumber)(m_e[3] * X + m_e[4] * Y + m_e[5] * Z);
+ DstPixel[2] = (icFloatNumber)(m_e[6] * X + m_e[7] * Y + m_e[8] * Z);
+ }
+ }
+
+ CheckDstAbs(DstPixel);
+}
+
+/**
+ **************************************************************************
+ * Name: CIccXformMatrixTRC::GetCurve
+ *
+ * Purpose:
+ * Gets the curve having the passed signature, from the profile.
+ *
+ * Args:
+ * sig = signature of the curve to be found
+ *
+ * Return:
+ * Pointer to the curve.
+ **************************************************************************
+ */
+CIccCurve *CIccXformMatrixTRC::GetCurve(icSignature sig) const
+{
+ CIccTag *pTag = m_pProfile->FindTag(sig);
+
+ if (pTag->GetType()==icSigCurveType || pTag->GetType()==icSigParametricCurveType) {
+ return (CIccCurve*)pTag;
+ }
+
+ return NULL;
+}
+
+/**
+ **************************************************************************
+ * Name: CIccXformMatrixTRC::GetColumn
+ *
+ * Purpose:
+ * Gets the XYZ tag from the profile.
+ *
+ * Args:
+ * sig = signature of the XYZ tag to be found.
+ *
+ * Return:
+ * Pointer to the XYZ tag.
+ **************************************************************************
+ */
+CIccTagXYZ *CIccXformMatrixTRC::GetColumn(icSignature sig) const
+{
+ CIccTag *pTag = m_pProfile->FindTag(sig);
+
+ if (!pTag || pTag->GetType()!=icSigXYZType) {
+ return NULL;
+ }
+
+ return (CIccTagXYZ*)pTag;
+}
+
+/**
+ **************************************************************************
+ * Name: CIccXformMatrixTRC::GetInvCurve
+ *
+ * Purpose:
+ * Gets the inverted curve having the passed signature, from the profile.
+ *
+ * Args:
+ * sig = signature of the curve to be inverted
+ *
+ * Return:
+ * Pointer to the inverted curve.
+ **************************************************************************
+ */
+CIccCurve *CIccXformMatrixTRC::GetInvCurve(icSignature sig) const
+{
+ CIccCurve *pCurve;
+ CIccTagCurve *pInvCurve;
+
+ if (!(pCurve = GetCurve(sig)))
+ return NULL;
+
+ pCurve->Begin();
+
+ pInvCurve = new CIccTagCurve(2048);
+
+ int i;
+ icFloatNumber x;
+ icFloatNumber *Lut = &(*pInvCurve)[0];
+
+ for (i=0; i<2048; i++) {
+ x=(icFloatNumber)i / 2047;
+
+ Lut[i] = pCurve->Find(x);
+ }
+
+ return pInvCurve;
+}
+
+/**
+**************************************************************************
+* Name: CIccXformMatrixTRC::ExtractInputCurves
+*
+* Purpose:
+* Gets the input curves. Should be called only after Begin()
+* has been called. Once the curves are extracted, they will
+* not be used by the Apply() function.
+* WARNING: caller owns the curves and must be deleted by the caller.
+*
+* Return:
+* Pointer to the input curves.
+**************************************************************************
+*/
+LPIccCurve* CIccXformMatrixTRC::ExtractInputCurves()
+{
+ if (m_bInput) {
+ if (m_Curve[0]) {
+ LPIccCurve* Curve = new LPIccCurve[3];
+ Curve[0] = (LPIccCurve)(m_Curve[0]->NewCopy());
+ Curve[1] = (LPIccCurve)(m_Curve[1]->NewCopy());
+ Curve[2] = (LPIccCurve)(m_Curve[2]->NewCopy());
+ m_ApplyCurvePtr = NULL;
+ return Curve;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+**************************************************************************
+* Name: CIccXformMatrixTRC::ExtractOutputCurves
+*
+* Purpose:
+* Gets the output curves. Should be called only after Begin()
+* has been called. Once the curves are extracted, they will
+* not be used by the Apply() function.
+* WARNING: caller owns the curves and must be deleted by the caller.
+*
+* Return:
+* Pointer to the output curves.
+**************************************************************************
+*/
+LPIccCurve* CIccXformMatrixTRC::ExtractOutputCurves()
+{
+ if (!m_bInput) {
+ if (m_Curve[0]) {
+ LPIccCurve* Curve = new LPIccCurve[3];
+ Curve[0] = (LPIccCurve)(m_Curve[0]->NewCopy());
+ Curve[1] = (LPIccCurve)(m_Curve[1]->NewCopy());
+ Curve[2] = (LPIccCurve)(m_Curve[2]->NewCopy());
+ m_ApplyCurvePtr = NULL;
+ return Curve;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ **************************************************************************
+ * Name: CIccXform3DLut::CIccXform3DLut
+ *
+ * Purpose:
+ * Constructor
+ *
+ * Args:
+ * pTag = Pointer to the tag of type CIccMBB
+ **************************************************************************
+ */
+CIccXform3DLut::CIccXform3DLut(CIccTag *pTag)
+{
+ if (pTag && pTag->IsMBBType()) {
+ m_pTag = (CIccMBB*)pTag;
+ }
+ else
+ m_pTag = NULL;
+
+ m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL;
+ m_ApplyMatrixPtr = NULL;
+}
+
+/**
+ **************************************************************************
+ * Name: CIccXform3DLut::~CIccXform3DLut
+ *
+ * Purpose:
+ * Destructor
+ **************************************************************************
+ */
+CIccXform3DLut::~CIccXform3DLut()
+{
+}
+
+/**
+ **************************************************************************
+ * Name: CIccXform3DLut::Begin
+ *
+ * Purpose:
+ * Does the initialization of the Xform before Apply() is called.
+ * Must be called before Apply().
+ *
+ **************************************************************************
+ */
+ icStatusCMM CIccXform3DLut::Begin()
+{
+ icStatusCMM status;
+ CIccCurve **Curve;
+ int i;
+
+ status = CIccXform::Begin();
+ if (status != icCmmStatOk)
+ return status;
+
+ if (!m_pTag ||
+ m_pTag->InputChannels()!=3) {
+ return icCmmStatInvalidLut;
+ }
+
+ m_ApplyCurvePtrA = NULL;
+ m_ApplyCurvePtrB = NULL;
+ m_ApplyCurvePtrM = NULL;
+
+ if (m_pTag->m_bInputMatrix) {
+ if (m_pTag->m_CurvesB) {
+ Curve = m_pTag->m_CurvesB;
+
+ Curve[0]->Begin();
+ Curve[1]->Begin();
+ Curve[2]->Begin();
+
+ if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() || !Curve[2]->IsIdentity()) {
+ m_ApplyCurvePtrB = Curve;
+ }
+ }
+
+ if (m_pTag->m_CurvesM) {
+ Curve = m_pTag->m_CurvesM;
+
+ Curve[0]->Begin();
+ Curve[1]->Begin();
+ Curve[2]->Begin();
+
+ if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() || !Curve[2]->IsIdentity()) {
+ m_ApplyCurvePtrM = Curve;
+ }
+ }
+
+ if (m_pTag->m_CLUT) {
+ m_pTag->m_CLUT->Begin();
+ }
+
+ if (m_pTag->m_CurvesA) {
+ Curve = m_pTag->m_CurvesA;
+
+ for (i=0; im_nOutput; i++) {
+ Curve[i]->Begin();
+ }
+
+ for (i=0; im_nOutput; i++) {
+ if (!Curve[i]->IsIdentity()) {
+ m_ApplyCurvePtrA = Curve;
+ break;
+ }
+ }
+ }
+
+ }
+ else {
+ if (m_pTag->m_CurvesA) {
+ Curve = m_pTag->m_CurvesA;
+
+ Curve[0]->Begin();
+ Curve[1]->Begin();
+ Curve[2]->Begin();
+
+ if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() || !Curve[2]->IsIdentity()) {
+ m_ApplyCurvePtrA = Curve;
+ }
+ }
+
+ if (m_pTag->m_CLUT) {
+ m_pTag->m_CLUT->Begin();
+ }
+
+ if (m_pTag->m_CurvesM) {
+ Curve = m_pTag->m_CurvesM;
+
+ for (i=0; im_nOutput; i++) {
+ Curve[i]->Begin();
+ }
+
+ for (i=0; im_nOutput; i++) {
+ if (!Curve[i]->IsIdentity()) {
+ m_ApplyCurvePtrM = Curve;
+ break;
+ }
+ }
+ }
+
+ if (m_pTag->m_CurvesB) {
+ Curve = m_pTag->m_CurvesB;
+
+ for (i=0; im_nOutput; i++) {
+ Curve[i]->Begin();
+ }
+
+ for (i=0; im_nOutput; i++) {
+ if (!Curve[i]->IsIdentity()) {
+ m_ApplyCurvePtrB = Curve;
+ break;
+ }
+ }
+ }
+ }
+
+ m_ApplyMatrixPtr = NULL;
+ if (m_pTag->m_Matrix) {
+ if (m_pTag->m_bInputMatrix) {
+ if (m_pTag->m_nInput!=3) {
+ return icCmmStatInvalidProfile;
+ }
+ }
+ else {
+ if (m_pTag->m_nOutput!=3) {
+ return icCmmStatInvalidProfile;
+ }
+ }
+
+ if (!m_pTag->m_Matrix->IsIdentity()) {
+ m_ApplyMatrixPtr = m_pTag->m_Matrix;
+ }
+ }
+
+ return icCmmStatOk;
+}
+
+/**
+ **************************************************************************
+ * Name: CIccXform3DLut::Apply
+ *
+ * Purpose:
+ * Does the actual application of the Xform.
+ *
+ * Args:
+ * pApply = ApplyXform object containging temporary storage used during Apply
+ * DstPixel = Destination pixel where the result is stored,
+ * SrcPixel = Source pixel which is to be applied.
+ **************************************************************************
+ */
+void CIccXform3DLut::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const
+{
+ icFloatNumber Pixel[16];
+ int i;
+
+ SrcPixel = CheckSrcAbs(pApply, SrcPixel);
+ Pixel[0] = SrcPixel[0];
+ Pixel[1] = SrcPixel[1];
+ Pixel[2] = SrcPixel[2];
+
+ if (m_pTag->m_bInputMatrix) {
+ if (m_ApplyCurvePtrB) {
+ Pixel[0] = m_ApplyCurvePtrB[0]->Apply(Pixel[0]);
+ Pixel[1] = m_ApplyCurvePtrB[1]->Apply(Pixel[1]);
+ Pixel[2] = m_ApplyCurvePtrB[2]->Apply(Pixel[2]);
+ }
+
+ if (m_ApplyMatrixPtr) {
+ m_ApplyMatrixPtr->Apply(Pixel);
+ }
+
+ if (m_ApplyCurvePtrM) {
+ Pixel[0] = m_ApplyCurvePtrM[0]->Apply(Pixel[0]);
+ Pixel[1] = m_ApplyCurvePtrM[1]->Apply(Pixel[1]);
+ Pixel[2] = m_ApplyCurvePtrM[2]->Apply(Pixel[2]);
+ }
+
+ if (m_pTag->m_CLUT) {
+ if (m_nInterp==icInterpLinear)
+ m_pTag->m_CLUT->Interp3d(Pixel, Pixel);
+ else
+ m_pTag->m_CLUT->Interp3dTetra(Pixel, Pixel);
+ }
+
+ if (m_ApplyCurvePtrA) {
+ for (i=0; im_nOutput; i++) {
+ Pixel[i] = m_ApplyCurvePtrA[i]->Apply(Pixel[i]);
+ }
+ }
+
+ }
+ else {
+ if (m_ApplyCurvePtrA) {
+ Pixel[0] = m_ApplyCurvePtrA[0]->Apply(Pixel[0]);
+ Pixel[1] = m_ApplyCurvePtrA[1]->Apply(Pixel[1]);
+ Pixel[2] = m_ApplyCurvePtrA[2]->Apply(Pixel[2]);
+ }
+
+ if (m_pTag->m_CLUT) {
+ if (m_nInterp==icInterpLinear)
+ m_pTag->m_CLUT->Interp3d(Pixel, Pixel);
+ else
+ m_pTag->m_CLUT->Interp3dTetra(Pixel, Pixel);
+ }
+
+ if (m_ApplyCurvePtrM) {
+ for (i=0; im_nOutput; i++) {
+ Pixel[i] = m_ApplyCurvePtrM[i]->Apply(Pixel[i]);
+ }
+ }
+
+ if (m_ApplyMatrixPtr) {
+ m_ApplyMatrixPtr->Apply(Pixel);
+ }
+
+ if (m_ApplyCurvePtrB) {
+ for (i=0; im_nOutput; i++) {
+ Pixel[i] = m_ApplyCurvePtrB[i]->Apply(Pixel[i]);
+ }
+ }
+ }
+
+ for (i=0; im_nOutput; i++) {
+ DstPixel[i] = Pixel[i];
+ }
+
+ CheckDstAbs(DstPixel);
+}
+
+/**
+**************************************************************************
+* Name: CIccXform3DLut::ExtractInputCurves
+*
+* Purpose:
+* Gets the input curves. Should be called only after Begin()
+* has been called. Once the curves are extracted, they will
+* not be used by the Apply() function.
+* WARNING: caller owns the curves and must be deleted by the caller.
+*
+* Return:
+* Pointer to the input curves.
+**************************************************************************
+*/
+LPIccCurve* CIccXform3DLut::ExtractInputCurves()
+{
+ if (m_bInput) {
+ if (m_pTag->m_bInputMatrix) {
+ if (m_pTag->m_CurvesB) {
+ LPIccCurve* Curve = new LPIccCurve[3];
+ Curve[0] = (LPIccCurve)(m_pTag->m_CurvesB[0]->NewCopy());
+ Curve[1] = (LPIccCurve)(m_pTag->m_CurvesB[1]->NewCopy());
+ Curve[2] = (LPIccCurve)(m_pTag->m_CurvesB[2]->NewCopy());
+ m_ApplyCurvePtrB = NULL;
+ return Curve;
+ }
+ }
+ else {
+ if (m_pTag->m_CurvesA) {
+ LPIccCurve* Curve = new LPIccCurve[3];
+ Curve[0] = (LPIccCurve)(m_pTag->m_CurvesA[0]->NewCopy());
+ Curve[1] = (LPIccCurve)(m_pTag->m_CurvesA[1]->NewCopy());
+ Curve[2] = (LPIccCurve)(m_pTag->m_CurvesA[2]->NewCopy());
+ m_ApplyCurvePtrA = NULL;
+ return Curve;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+**************************************************************************
+* Name: CIccXform3DLut::ExtractOutputCurves
+*
+* Purpose:
+* Gets the output curves. Should be called only after Begin()
+* has been called. Once the curves are extracted, they will
+* not be used by the Apply() function.
+* WARNING: caller owns the curves and must be deleted by the caller.
+*
+* Return:
+* Pointer to the output curves.
+**************************************************************************
+*/
+LPIccCurve* CIccXform3DLut::ExtractOutputCurves()
+{
+ if (!m_bInput) {
+ if (m_pTag->m_bInputMatrix) {
+ if (m_pTag->m_CurvesA) {
+ LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput];
+ for (int i=0; im_nOutput; i++) {
+ Curve[i] = (LPIccCurve)(m_pTag->m_CurvesA[i]->NewCopy());
+ }
+ m_ApplyCurvePtrA = NULL;
+ return Curve;
+ }
+ }
+ else {
+ if (m_pTag->m_CurvesB) {
+ LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput];
+ for (int i=0; im_nOutput; i++) {
+ Curve[i] = (LPIccCurve)(m_pTag->m_CurvesB[i]->NewCopy());
+ }
+ m_ApplyCurvePtrB = NULL;
+ return Curve;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ **************************************************************************
+ * Name: CIccXform4DLut::CIccXform4DLut
+ *
+ * Purpose:
+ * Constructor
+ *
+ * Args:
+ * pTag = Pointer to the tag of type CIccMBB
+ **************************************************************************
+ */
+CIccXform4DLut::CIccXform4DLut(CIccTag *pTag)
+{
+ if (pTag && pTag->IsMBBType()) {
+ m_pTag = (CIccMBB*)pTag;
+ }
+ else
+ m_pTag = NULL;
+
+ m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL;
+ m_ApplyMatrixPtr = NULL;
+}
+
+
+/**
+ **************************************************************************
+ * Name: CIccXform4DLut::~CIccXform4DLut
+ *
+ * Purpose:
+ * Destructor
+ **************************************************************************
+ */
+CIccXform4DLut::~CIccXform4DLut()
+{
+}
+
+
+/**
+ **************************************************************************
+ * Name: CIccXform4DLut::Begin
+ *
+ * Purpose:
+ * Does the initialization of the Xform before Apply() is called.
+ * Must be called before Apply().
+ *
+ **************************************************************************
+ */
+icStatusCMM CIccXform4DLut::Begin()
+{
+ icStatusCMM status;
+ CIccCurve **Curve;
+ int i;
+
+ status = CIccXform::Begin();
+ if (status != icCmmStatOk) {
+ return status;
+ }
+
+ if (!m_pTag ||
+ m_pTag->InputChannels()!=4) {
+ return icCmmStatInvalidLut;
+ }
+
+ m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL;
+
+ if (m_pTag->m_bInputMatrix) {
+ if (m_pTag->m_CurvesB) {
+ Curve = m_pTag->m_CurvesB;
+
+ Curve[0]->Begin();
+ Curve[1]->Begin();
+ Curve[2]->Begin();
+ Curve[3]->Begin();
+
+ if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() ||
+ !Curve[2]->IsIdentity() || !Curve[3]->IsIdentity())
+ {
+ m_ApplyCurvePtrB = Curve;
+ }
+ }
+
+ if (m_pTag->m_CLUT) {
+ m_pTag->m_CLUT->Begin();
+ }
+
+ if (m_pTag->m_CurvesA) {
+ Curve = m_pTag->m_CurvesA;
+
+ for (i=0; im_nOutput; i++) {
+ Curve[i]->Begin();
+ }
+
+ for (i=0; im_nOutput; i++) {
+ if (!Curve[i]->IsIdentity()) {
+ m_ApplyCurvePtrA = Curve;
+ break;
+ }
+ }
+ }
+
+ }
+ else {
+ if (m_pTag->m_CurvesA) {
+ Curve = m_pTag->m_CurvesA;
+
+ Curve[0]->Begin();
+ Curve[1]->Begin();
+ Curve[2]->Begin();
+ Curve[3]->Begin();
+
+ if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() ||
+ !Curve[2]->IsIdentity() || !Curve[3]->IsIdentity())
+ {
+ m_ApplyCurvePtrA = Curve;
+ }
+ }
+
+ if (m_pTag->m_CLUT) {
+ m_pTag->m_CLUT->Begin();
+ }
+
+ if (m_pTag->m_CurvesM) {
+ Curve = m_pTag->m_CurvesM;
+
+ for (i=0; im_nOutput; i++) {
+ Curve[i]->Begin();
+ }
+
+ for (i=0; im_nOutput; i++) {
+ if (!Curve[i]->IsIdentity()) {
+ m_ApplyCurvePtrM = Curve;
+ break;
+ }
+ }
+ }
+
+ if (m_pTag->m_CurvesB) {
+ Curve = m_pTag->m_CurvesB;
+
+ for (i=0; im_nOutput; i++) {
+ Curve[i]->Begin();
+ }
+
+ for (i=0; im_nOutput; i++) {
+ if (!Curve[i]->IsIdentity()) {
+ m_ApplyCurvePtrB = Curve;
+ break;
+ }
+ }
+ }
+ }
+
+ m_ApplyMatrixPtr = NULL;
+ if (m_pTag->m_Matrix) {
+ if (m_pTag->m_bInputMatrix) {
+ return icCmmStatInvalidProfile;
+ }
+ else {
+ if (m_pTag->m_nOutput!=3) {
+ return icCmmStatInvalidProfile;
+ }
+ }
+
+ if (!m_pTag->m_Matrix->IsIdentity()) {
+ m_ApplyMatrixPtr = m_pTag->m_Matrix;
+ }
+ }
+
+ return icCmmStatOk;
+}
+
+
+/**
+ **************************************************************************
+ * Name: CIccXform4DLut::Apply
+ *
+ * Purpose:
+ * Does the actual application of the Xform.
+ *
+ * Args:
+ * pApply = ApplyXform object containging temporary storage used during Apply
+ * DstPixel = Destination pixel where the result is stored,
+ * SrcPixel = Source pixel which is to be applied.
+ **************************************************************************
+ */
+void CIccXform4DLut::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const
+{
+ icFloatNumber Pixel[16];
+ int i;
+
+ SrcPixel = CheckSrcAbs(pApply, SrcPixel);
+ Pixel[0] = SrcPixel[0];
+ Pixel[1] = SrcPixel[1];
+ Pixel[2] = SrcPixel[2];
+ Pixel[3] = SrcPixel[3];
+
+ if (m_pTag->m_bInputMatrix) {
+ if (m_ApplyCurvePtrB) {
+ Pixel[0] = m_ApplyCurvePtrB[0]->Apply(Pixel[0]);
+ Pixel[1] = m_ApplyCurvePtrB[1]->Apply(Pixel[1]);
+ Pixel[2] = m_ApplyCurvePtrB[2]->Apply(Pixel[2]);
+ Pixel[3] = m_ApplyCurvePtrB[3]->Apply(Pixel[3]);
+ }
+
+ if (m_pTag->m_CLUT) {
+ m_pTag->m_CLUT->Interp4d(Pixel, Pixel);
+ }
+
+ if (m_ApplyCurvePtrA) {
+ for (i=0; im_nOutput; i++) {
+ Pixel[i] = m_ApplyCurvePtrA[i]->Apply(Pixel[i]);
+ }
+ }
+
+ }
+ else {
+ if (m_ApplyCurvePtrA) {
+ Pixel[0] = m_ApplyCurvePtrA[0]->Apply(Pixel[0]);
+ Pixel[1] = m_ApplyCurvePtrA[1]->Apply(Pixel[1]);
+ Pixel[2] = m_ApplyCurvePtrA[2]->Apply(Pixel[2]);
+ Pixel[3] = m_ApplyCurvePtrA[3]->Apply(Pixel[3]);
+ }
+
+ if (m_pTag->m_CLUT) {
+ m_pTag->m_CLUT->Interp4d(Pixel, Pixel);
+ }
+
+ if (m_ApplyCurvePtrM) {
+ for (i=0; im_nOutput; i++) {
+ Pixel[i] = m_ApplyCurvePtrM[i]->Apply(Pixel[i]);
+ }
+ }
+
+ if (m_ApplyMatrixPtr) {
+ m_ApplyMatrixPtr->Apply(Pixel);
+ }
+
+ if (m_ApplyCurvePtrB) {
+ for (i=0; im_nOutput; i++) {
+ Pixel[i] = m_ApplyCurvePtrB[i]->Apply(Pixel[i]);
+ }
+ }
+ }
+
+ for (i=0; im_nOutput; i++) {
+ DstPixel[i] = Pixel[i];
+ }
+
+ CheckDstAbs(DstPixel);
+}
+
+/**
+**************************************************************************
+* Name: CIccXform4DLut::ExtractInputCurves
+*
+* Purpose:
+* Gets the input curves. Should be called only after Begin()
+* has been called. Once the curves are extracted, they will
+* not be used by the Apply() function.
+* WARNING: caller owns the curves and must be deleted by the caller.
+*
+* Return:
+* Pointer to the input curves.
+**************************************************************************
+*/
+LPIccCurve* CIccXform4DLut::ExtractInputCurves()
+{
+ if (m_bInput) {
+ if (m_pTag->m_bInputMatrix) {
+ if (m_pTag->m_CurvesB) {
+ LPIccCurve* Curve = new LPIccCurve[4];
+ Curve[0] = (LPIccCurve)(m_pTag->m_CurvesB[0]->NewCopy());
+ Curve[1] = (LPIccCurve)(m_pTag->m_CurvesB[1]->NewCopy());
+ Curve[2] = (LPIccCurve)(m_pTag->m_CurvesB[2]->NewCopy());
+ Curve[3] = (LPIccCurve)(m_pTag->m_CurvesB[3]->NewCopy());
+ m_ApplyCurvePtrB = NULL;
+ return Curve;
+ }
+ }
+ else {
+ if (m_pTag->m_CurvesA) {
+ LPIccCurve* Curve = new LPIccCurve[4];
+ Curve[0] = (LPIccCurve)(m_pTag->m_CurvesA[0]->NewCopy());
+ Curve[1] = (LPIccCurve)(m_pTag->m_CurvesA[1]->NewCopy());
+ Curve[2] = (LPIccCurve)(m_pTag->m_CurvesA[2]->NewCopy());
+ Curve[3] = (LPIccCurve)(m_pTag->m_CurvesA[3]->NewCopy());
+ m_ApplyCurvePtrA = NULL;
+ return Curve;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+**************************************************************************
+* Name: CIccXform4DLut::ExtractOutputCurves
+*
+* Purpose:
+* Gets the output curves. Should be called only after Begin()
+* has been called. Once the curves are extracted, they will
+* not be used by the Apply() function.
+* WARNING: caller owns the curves and must be deleted by the caller.
+*
+* Return:
+* Pointer to the output curves.
+**************************************************************************
+*/
+LPIccCurve* CIccXform4DLut::ExtractOutputCurves()
+{
+ if (!m_bInput) {
+ if (m_pTag->m_bInputMatrix) {
+ if (m_pTag->m_CurvesA) {
+ LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput];
+ for (int i=0; im_nOutput; i++) {
+ Curve[i] = (LPIccCurve)(m_pTag->m_CurvesA[i]->NewCopy());
+ }
+ m_ApplyCurvePtrA = NULL;
+ return Curve;
+ }
+ }
+ else {
+ if (m_pTag->m_CurvesB) {
+ LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput];
+ for (int i=0; im_nOutput; i++) {
+ Curve[i] = (LPIccCurve)(m_pTag->m_CurvesB[i]->NewCopy());
+ }
+ m_ApplyCurvePtrB = NULL;
+ return Curve;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+/**
+ **************************************************************************
+ * Name: CIccXformNDLut::CIccXformNDLut
+ *
+ * Purpose:
+ * Constructor
+ *
+ * Args:
+ * pTag = Pointer to the tag of type CIccMBB
+ **************************************************************************
+ */
+CIccXformNDLut::CIccXformNDLut(CIccTag *pTag)
+{
+ if (pTag && pTag->IsMBBType()) {
+ m_pTag = (CIccMBB*)pTag;
+ }
+ else
+ m_pTag = NULL;
+
+ m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL;
+ m_ApplyMatrixPtr = NULL;
+}
+
+
+/**
+ **************************************************************************
+ * Name: CIccXformNDLut::~CIccXformNDLut
+ *
+ * Purpose:
+ * Destructor
+ **************************************************************************
+ */
+CIccXformNDLut::~CIccXformNDLut()
+{
+}
+
+
+/**
+ **************************************************************************
+ * Name: CIccXformNDLut::Begin
+ *
+ * Purpose:
+ * Does the initialization of the Xform before Apply() is called.
+ * Must be called before Apply().
+ *
+ **************************************************************************
+ */
+icStatusCMM CIccXformNDLut::Begin()
+{
+ icStatusCMM status;
+ CIccCurve **Curve;
+ int i;
+
+ status = CIccXform::Begin();
+ if (status != icCmmStatOk) {
+ return status;
+ }
+
+ if (!m_pTag || (m_pTag->InputChannels()>2 && m_pTag->InputChannels()<5)) {
+ return icCmmStatInvalidLut;
+ }
+
+ m_nNumInput = m_pTag->m_nInput;
+
+ m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL;
+
+ if (m_pTag->m_bInputMatrix) {
+ if (m_pTag->m_CurvesB) {
+ Curve = m_pTag->m_CurvesB;
+
+ for (i=0; iBegin();
+
+ for (i=0; iIsIdentity()) {
+ m_ApplyCurvePtrB = Curve;
+ break;
+ }
+ }
+ }
+
+ if (m_pTag->m_CLUT) {
+ m_pTag->m_CLUT->Begin();
+ }
+
+ if (m_pTag->m_CurvesA) {
+ Curve = m_pTag->m_CurvesA;
+
+ for (i=0; im_nOutput; i++) {
+ Curve[i]->Begin();
+ }
+
+ for (i=0; im_nOutput; i++) {
+ if (!Curve[i]->IsIdentity()) {
+ m_ApplyCurvePtrA = Curve;
+ break;
+ }
+ }
+ }
+
+ }
+ else {
+ if (m_pTag->m_CurvesA) {
+ Curve = m_pTag->m_CurvesA;
+
+ for (i=0; iBegin();
+
+ for (i=0; iIsIdentity()) {
+ m_ApplyCurvePtrA = Curve;
+ break;
+ }
+ }
+ }
+
+ if (m_pTag->m_CLUT) {
+ m_pTag->m_CLUT->Begin();
+ }
+
+ if (m_pTag->m_CurvesM) {
+ Curve = m_pTag->m_CurvesM;
+
+ for (i=0; im_nOutput; i++) {
+ Curve[i]->Begin();
+ }
+
+ for (i=0; im_nOutput; i++) {
+ if (!Curve[i]->IsIdentity()) {
+ m_ApplyCurvePtrM = Curve;
+ break;
+ }
+ }
+ }
+
+ if (m_pTag->m_CurvesB) {
+ Curve = m_pTag->m_CurvesB;
+
+ for (i=0; im_nOutput; i++) {
+ Curve[i]->Begin();
+ }
+
+ for (i=0; im_nOutput; i++) {
+ if (!Curve[i]->IsIdentity()) {
+ m_ApplyCurvePtrB = Curve;
+ break;
+ }
+ }
+ }
+ }
+
+ m_ApplyMatrixPtr = NULL;
+ if (m_pTag->m_Matrix) {
+ if (m_pTag->m_bInputMatrix) {
+ return icCmmStatInvalidProfile;
+ }
+ else {
+ if (m_pTag->m_nOutput!=3) {
+ return icCmmStatInvalidProfile;
+ }
+ }
+
+ if (!m_pTag->m_Matrix->IsIdentity()) {
+ m_ApplyMatrixPtr = m_pTag->m_Matrix;
+ }
+ }
+
+ return icCmmStatOk;
+}
+
+
+/**
+ **************************************************************************
+ * Name: CIccXformNDLut::Apply
+ *
+ * Purpose:
+ * Does the actual application of the Xform.
+ *
+ * Args:
+ * pApply = ApplyXform object containging temporary storage used during Apply
+ * DstPixel = Destination pixel where the result is stored,
+ * SrcPixel = Source pixel which is to be applied.
+ **************************************************************************
+ */
+void CIccXformNDLut::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const
+{
+ icFloatNumber Pixel[16];
+ int i;
+
+ SrcPixel = CheckSrcAbs(pApply, SrcPixel);
+ for (i=0; im_bInputMatrix) {
+ if (m_ApplyCurvePtrB) {
+ for (i=0; iApply(Pixel[i]);
+ }
+
+ if (m_pTag->m_CLUT) {
+ switch(m_nNumInput) {
+ case 5:
+ m_pTag->m_CLUT->Interp5d(Pixel, Pixel);
+ break;
+ case 6:
+ m_pTag->m_CLUT->Interp6d(Pixel, Pixel);
+ break;
+ default:
+ m_pTag->m_CLUT->InterpND(Pixel, Pixel);
+ break;
+ }
+ }
+
+ if (m_ApplyCurvePtrA) {
+ for (i=0; im_nOutput; i++) {
+ Pixel[i] = m_ApplyCurvePtrA[i]->Apply(Pixel[i]);
+ }
+ }
+
+ }
+ else {
+ if (m_ApplyCurvePtrA) {
+ for (i=0; iApply(Pixel[i]);
+ }
+
+ if (m_pTag->m_CLUT) {
+ switch(m_nNumInput) {
+ case 5:
+ m_pTag->m_CLUT->Interp5d(Pixel, Pixel);
+ break;
+ case 6:
+ m_pTag->m_CLUT->Interp6d(Pixel, Pixel);
+ break;
+ default:
+ m_pTag->m_CLUT->InterpND(Pixel, Pixel);
+ break;
+ }
+ }
+
+ if (m_ApplyCurvePtrM) {
+ for (i=0; im_nOutput; i++) {
+ Pixel[i] = m_ApplyCurvePtrM[i]->Apply(Pixel[i]);
+ }
+ }
+
+ if (m_ApplyMatrixPtr) {
+ m_ApplyMatrixPtr->Apply(Pixel);
+ }
+
+ if (m_ApplyCurvePtrB) {
+ for (i=0; im_nOutput; i++) {
+ Pixel[i] = m_ApplyCurvePtrB[i]->Apply(Pixel[i]);
+ }
+ }
+ }
+
+ for (i=0; im_nOutput; i++) {
+ DstPixel[i] = Pixel[i];
+ }
+
+ CheckDstAbs(DstPixel);
+}
+
+/**
+**************************************************************************
+* Name: CIccXformNDLut::ExtractInputCurves
+*
+* Purpose:
+* Gets the input curves. Should be called only after Begin()
+* has been called. Once the curves are extracted, they will
+* not be used by the Apply() function.
+* WARNING: caller owns the curves and must be deleted by the caller.
+*
+* Return:
+* Pointer to the input curves.
+**************************************************************************
+*/
+LPIccCurve* CIccXformNDLut::ExtractInputCurves()
+{
+ if (m_bInput) {
+ if (m_pTag->m_bInputMatrix) {
+ if (m_pTag->m_CurvesB) {
+ LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nInput];
+ for (int i=0; im_nInput; i++) {
+ Curve[i] = (LPIccCurve)(m_pTag->m_CurvesB[i]->NewCopy());
+ }
+ m_ApplyCurvePtrB = NULL;
+ return Curve;
+ }
+ }
+ else {
+ if (m_pTag->m_CurvesA) {
+ LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nInput];
+ for (int i=0; im_nInput; i++) {
+ Curve[i] = (LPIccCurve)(m_pTag->m_CurvesA[i]->NewCopy());
+ }
+ m_ApplyCurvePtrA = NULL;
+ return Curve;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+**************************************************************************
+* Name: CIccXformNDLut::ExtractOutputCurves
+*
+* Purpose:
+* Gets the output curves. Should be called only after Begin()
+* has been called. Once the curves are extracted, they will
+* not be used by the Apply() function.
+* WARNING: caller owns the curves and must be deleted by the caller.
+*
+* Return:
+* Pointer to the output curves.
+**************************************************************************
+*/
+LPIccCurve* CIccXformNDLut::ExtractOutputCurves()
+{
+ if (!m_bInput) {
+ if (m_pTag->m_bInputMatrix) {
+ if (m_pTag->m_CurvesA) {
+ LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput];
+ for (int i=0; im_nOutput; i++) {
+ Curve[i] = (LPIccCurve)(m_pTag->m_CurvesA[i]->NewCopy());
+ }
+ m_ApplyCurvePtrA = NULL;
+ return Curve;
+ }
+ }
+ else {
+ if (m_pTag->m_CurvesB) {
+ LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput];
+ for (int i=0; im_nOutput; i++) {
+ Curve[i] = (LPIccCurve)(m_pTag->m_CurvesB[i]->NewCopy());
+ }
+ m_ApplyCurvePtrB = NULL;
+ return Curve;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ **************************************************************************
+ * Name: CIccXformNamedColor::CIccXformNamedColor
+ *
+ * Purpose:
+ * Constructor
+ *
+ * Args:
+ * pTag = Pointer to the tag of type CIccTagNamedColor2,
+ * csPCS = PCS color space,
+ * csDevice = Device color space
+ **************************************************************************
+ */
+CIccXformNamedColor::CIccXformNamedColor(CIccTag *pTag, icColorSpaceSignature csPCS, icColorSpaceSignature csDevice)
+{
+ if (pTag && pTag->GetType()==icSigNamedColor2Type) {
+ m_pTag = (CIccTagNamedColor2*)pTag;
+ m_pTag->SetColorSpaces(csPCS, csDevice);
+ }
+ else
+ m_pTag = NULL;
+
+ m_nSrcSpace = icSigUnknownData;
+ m_nDestSpace = icSigUnknownData;
+}
+
+
+/**
+ **************************************************************************
+ * Name: CIccXformNamedColor::CIccXformNamedColor
+ *
+ * Purpose:
+ * Destructor
+ **************************************************************************
+ */
+CIccXformNamedColor::~CIccXformNamedColor()
+{
+}
+
+/**
+ **************************************************************************
+ * Name: CIccXformNamedColor::Begin
+ *
+ * Purpose:
+ * Does the initialization of the Xform before Apply() is called.
+ * Must be called before Apply().
+ *
+ **************************************************************************
+ */
+icStatusCMM CIccXformNamedColor::Begin()
+{
+ icStatusCMM status;
+
+ status = CIccXform::Begin();
+ if (status != icCmmStatOk)
+ return status;
+
+ if (m_pTag == NULL) {
+ return icCmmStatProfileMissingTag;
+ }
+
+ if (m_nSrcSpace==icSigUnknownData ||
+ m_nDestSpace==icSigUnknownData) {
+ return icCmmStatIncorrectApply;
+ }
+
+ if (m_nSrcSpace != icSigNamedData) {
+ if (m_nDestSpace != icSigNamedData) {
+ m_nApplyInterface = icApplyPixel2Pixel;
+ }
+ else {
+ m_nApplyInterface = icApplyPixel2Named;
+ }
+ }
+ else {
+ if (m_nDestSpace != icSigNamedData) {
+ m_nApplyInterface = icApplyNamed2Pixel;
+ }
+ else {
+ return icCmmStatIncorrectApply;
+ }
+ }
+
+ if (!m_pTag->InitFindCachedPCSColor())
+ return icCmmStatAllocErr;
+
+ return icCmmStatOk;
+}
+
+
+
+/**
+ **************************************************************************
+ * Name: CIccXformNamedColor::Apply
+ *
+ * Purpose:
+ * Does the actual application of the Xform.
+ *
+ * Args:
+ * pApply = ApplyXform object containging temporary storage used during Apply
+ * DstColorName = Destination string where the color name result is stored,
+ * SrcPixel = Source pixel which is to be applied.
+ **************************************************************************
+ */
+icStatusCMM CIccXformNamedColor::Apply(CIccApplyXform* pApply, icChar *DstColorName, const icFloatNumber *SrcPixel) const
+{
+ const CIccTagNamedColor2 *pTag = m_pTag;
+ if (pTag == NULL)
+ return icCmmStatBadXform;
+
+ icFloatNumber DevicePix[16], PCSPix[3];
+ std::string NamedColor;
+ icUInt32Number i, j;
+
+ if (IsSrcPCS()) {
+ SrcPixel = CheckSrcAbs(pApply, SrcPixel);
+ for(i=0; i<3; i++)
+ PCSPix[i] = SrcPixel[i];
+
+ j = pTag->FindCachedPCSColor(PCSPix);
+ pTag->GetColorName(NamedColor, j);
+ }
+ else {
+ for(i=0; iGetDeviceCoords(); i++)
+ DevicePix[i] = SrcPixel[i];
+
+ j = pTag->FindDeviceColor(DevicePix);
+ pTag->GetColorName(NamedColor, j);
+ }
+
+ sprintf(DstColorName, "%s", NamedColor.c_str());
+
+ return icCmmStatOk;
+}
+
+
+/**
+**************************************************************************
+* Name: CIccXformNamedColor::Apply
+*
+* Purpose:
+* Does the actual application of the Xform.
+*
+* Args:
+* pApply = ApplyXform object containging temporary storage used during Apply
+* DstPixel = Destination pixel where the result is stored,
+* SrcColorName = Source color name which is to be applied.
+**************************************************************************
+*/
+icStatusCMM CIccXformNamedColor::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icChar *SrcColorName) const
+{
+ const CIccTagNamedColor2 *pTag = m_pTag;
+
+ if (pTag == NULL)
+ return icCmmStatProfileMissingTag;
+
+ icUInt32Number j;
+
+ if (m_nSrcSpace != icSigNamedData)
+ return icCmmStatBadSpaceLink;
+
+ if (IsDestPCS()) {
+
+ j = pTag->FindColor(SrcColorName);
+ if (j<0)
+ return icCmmStatColorNotFound;
+
+ if (m_nDestSpace == icSigLabData) {
+ memcpy(DstPixel, pTag->GetEntry(j)->pcsCoords, 3*sizeof(icFloatNumber));
+ }
+ else {
+ memcpy(DstPixel, pTag->GetEntry(j)->pcsCoords, 3*sizeof(icFloatNumber));
+ }
+ CheckDstAbs(DstPixel);
+ }
+ else {
+ j = pTag->FindColor(SrcColorName);
+ if (j<0)
+ return icCmmStatColorNotFound;
+ memcpy(DstPixel, pTag->GetEntry(j)->deviceCoords, pTag->GetDeviceCoords()*sizeof(icFloatNumber));
+ }
+
+ return icCmmStatOk;
+}
+
+/**
+ **************************************************************************
+ * Name: CIccXformNamedColor::SetSrcSpace
+ *
+ * Purpose:
+ * Sets the source space of the Xform
+ *
+ * Args:
+ * nSrcSpace = signature of the color space to be set
+ **************************************************************************
+ */
+icStatusCMM CIccXformNamedColor::SetSrcSpace(icColorSpaceSignature nSrcSpace)
+{
+ if (nSrcSpace!=m_pTag->GetPCS())
+ if (nSrcSpace!=m_pTag->GetDeviceSpace())
+ if (nSrcSpace!=icSigNamedData)
+ return icCmmStatBadSpaceLink;
+
+ m_nSrcSpace = nSrcSpace;
+
+ return icCmmStatOk;
+}
+
+/**
+ **************************************************************************
+ * Name: CIccXformNamedColor::SetSrcSpace
+ *
+ * Purpose:
+ * Sets the destination space of the Xform
+ *
+ * Args:
+ * nDestSpace = signature of the color space to be set
+ **************************************************************************
+ */
+icStatusCMM CIccXformNamedColor::SetDestSpace(icColorSpaceSignature nDestSpace)
+{
+ if (m_nSrcSpace == nDestSpace)
+ return icCmmStatBadSpaceLink;
+
+ if (nDestSpace!=m_pTag->GetPCS())
+ if (nDestSpace!=m_pTag->GetDeviceSpace())
+ if (nDestSpace!=icSigNamedData)
+ return icCmmStatBadSpaceLink;
+
+ m_nDestSpace = nDestSpace;
+
+ return icCmmStatOk;
+}
+
+
+/**
+**************************************************************************
+* Name: CIccXformMPE::CIccXformMPE
+*
+* Purpose:
+* Constructor
+**************************************************************************
+*/
+CIccXformMpe::CIccXformMpe(CIccTag *pTag)
+{
+ if (pTag && pTag->GetType()==icSigMultiProcessElementType)
+ m_pTag = (CIccTagMultiProcessElement*)pTag;
+ else
+ m_pTag = NULL;
+
+ m_bUsingAcs = false;
+}
+
+/**
+**************************************************************************
+* Name: CIccXformMPE::~CIccXformMPE
+*
+* Purpose:
+* Destructor
+**************************************************************************
+*/
+CIccXformMpe::~CIccXformMpe()
+{
+}
+
+/**
+**************************************************************************
+* Name: CIccXformMPE::Create
+*
+* Purpose:
+* This is a static Creation function that creates derived CIccXform objects and
+* initializes them.
+*
+* Args:
+* pProfile = pointer to a CIccProfile object that will be owned by the transform. This object will
+* be destroyed when the returned CIccXform object is destroyed. The means that the CIccProfile
+* object needs to be allocated on the heap.
+* bInput = flag to indicate whether to use the input or output side of the profile,
+* nIntent = the rendering intent to apply to the profile,
+* nInterp = the interpolation algorithm to use for N-D luts.
+* nLutType = selection of which transform lut to use
+* pHintManager = hints for creating the xform
+*
+* Return:
+* A suitable pXform object
+**************************************************************************
+*/
+CIccXform *CIccXformMpe::Create(CIccProfile *pProfile, bool bInput/* =true */, icRenderingIntent nIntent/* =icUnknownIntent */,
+ icXformInterp nInterp/* =icInterpLinear */, icXformLutType nLutType/* =icXformLutColor */,
+ CIccCreateXformHintManager *pHintManager/* =NULL */)
+{
+ CIccXform *rv = NULL;
+ icRenderingIntent nTagIntent = nIntent;
+
+ if (nTagIntent == icUnknownIntent)
+ nTagIntent = icPerceptual;
+
+ switch (nLutType) {
+ case icXformLutColor:
+ if (bInput) {
+ CIccTag *pTag = pProfile->FindTag(icSigDToB0Tag + nTagIntent);
+
+ if (!pTag && nTagIntent ==icAbsoluteColorimetric) {
+ pTag = pProfile->FindTag(icSigDToB1Tag);
+ if (pTag)
+ nTagIntent = icRelativeColorimetric;
+ }
+
+ if (!pTag) {
+ pTag = pProfile->FindTag(icSigDToB0Tag);
+ }
+
+ //Unsupported elements cause fall back behavior
+ if (pTag && !pTag->IsSupported())
+ pTag = NULL;
+
+ if (!pTag) {
+ if (nTagIntent == icAbsoluteColorimetric)
+ nTagIntent = icRelativeColorimetric;
+ pTag = pProfile->FindTag(icSigAToB0Tag + nTagIntent);
+ }
+
+ if (!pTag) {
+ pTag = pProfile->FindTag(icSigAToB0Tag);
+ }
+
+ if (!pTag) {
+ if (pProfile->m_Header.colorSpace == icSigRgbData) {
+ rv = new CIccXformMatrixTRC();
+ }
+ else
+ return NULL;
+ }
+ else if (pTag->GetType()==icSigMultiProcessElementType) {
+ rv = new CIccXformMpe(pTag);
+ }
+ else {
+ switch(pProfile->m_Header.colorSpace) {
+ case icSigXYZData:
+ case icSigLabData:
+ case icSigLuvData:
+ case icSigYCbCrData:
+ case icSigYxyData:
+ case icSigRgbData:
+ case icSigHsvData:
+ case icSigHlsData:
+ case icSigCmyData:
+ case icSig3colorData:
+ rv = new CIccXform3DLut(pTag);
+ break;
+
+ case icSigCmykData:
+ case icSig4colorData:
+ rv = new CIccXform4DLut(pTag);
+ break;
+
+ default:
+ rv = new CIccXformNDLut(pTag);
+ break;
+ }
+ }
+ }
+ else {
+ CIccTag *pTag = pProfile->FindTag(icSigBToD0Tag + nTagIntent);
+
+ if (!pTag && nTagIntent ==icAbsoluteColorimetric) {
+ pTag = pProfile->FindTag(icSigBToD1Tag);
+ if (pTag)
+ nTagIntent = icRelativeColorimetric;
+ }
+
+ if (!pTag) {
+ pTag = pProfile->FindTag(icSigBToD0Tag);
+ }
+
+ //Unsupported elements cause fall back behavior
+ if (pTag && !pTag->IsSupported())
+ pTag = NULL;
+
+ if (!pTag) {
+ if (nTagIntent == icAbsoluteColorimetric)
+ nTagIntent = icRelativeColorimetric;
+ pTag = pProfile->FindTag(icSigBToA0Tag + nTagIntent);
+ }
+
+ if (!pTag) {
+ pTag = pProfile->FindTag(icSigBToA0Tag);
+ }
+
+ if (!pTag) {
+ if (pProfile->m_Header.colorSpace == icSigRgbData) {
+ rv = new CIccXformMatrixTRC();
+ }
+ else
+ return NULL;
+ }
+ if (pTag->GetType()==icSigMultiProcessElementType) {
+ rv = new CIccXformMpe(pTag);
+ }
+ else {
+ switch(pProfile->m_Header.pcs) {
+ case icSigXYZData:
+ case icSigLabData:
+ rv = new CIccXform3DLut(pTag);
+
+ default:
+ break;
+ }
+ }
+ }
+ break;
+
+ case icXformLutNamedColor:
+ {
+ CIccTag *pTag = pProfile->FindTag(icSigNamedColor2Tag);
+ if (!pTag)
+ return NULL;
+
+ rv = new CIccXformNamedColor(pTag, pProfile->m_Header.pcs, pProfile->m_Header.colorSpace);
+ }
+ break;
+
+ case icXformLutPreview:
+ {
+ bInput = false;
+ CIccTag *pTag = pProfile->FindTag(icSigPreview0Tag + nTagIntent);
+ if (!pTag) {
+ pTag = pProfile->FindTag(icSigPreview0Tag);
+ }
+ if (!pTag) {
+ return NULL;
+ }
+ else {
+ switch(pProfile->m_Header.pcs) {
+ case icSigXYZData:
+ case icSigLabData:
+ rv = new CIccXform3DLut(pTag);
+
+ default:
+ break;
+ }
+ }
+ }
+ break;
+
+ case icXformLutGamut:
+ {
+ bInput = false;
+ CIccTag *pTag = pProfile->FindTag(icSigGamutTag);
+ if (!pTag) {
+ return NULL;
+ }
+ else {
+ switch(pProfile->m_Header.pcs) {
+ case icSigXYZData:
+ case icSigLabData:
+ rv = new CIccXform3DLut(pTag);
+
+ default:
+ break;
+ }
+ }
+ }
+ break;
+ }
+
+ if (rv) {
+ rv->SetParams(pProfile, bInput, nIntent, nInterp, pHintManager);
+ }
+
+ return rv;
+}
+
+
+/**
+**************************************************************************
+* Name: CIccXformMPE::Begin
+*
+* Purpose:
+* This function will be called before the xform is applied. Derived objects
+* should also call the base class function to initialize for Absolute Colorimetric
+* Intent handling which is performed through the use of the CheckSrcAbs and
+* CheckDstAbs functions.
+**************************************************************************
+*/
+icStatusCMM CIccXformMpe::Begin()
+{
+ icStatusCMM status;
+ status = CIccXform::Begin();
+
+ if (status != icCmmStatOk)
+ return status;
+
+ if (!m_pTag) {
+ return icCmmStatInvalidLut;
+ }
+
+ if (!m_pTag->Begin()) {
+ return icCmmStatInvalidProfile;
+ }
+
+ return icCmmStatOk;
+}
+
+
+/**
+**************************************************************************
+* Name: CIccXformMpe::GetNewApply
+*
+* Purpose:
+* This Factory function allocates data specific for the application of the xform.
+* This allows multiple threads to simultaneously use the same xform.
+**************************************************************************
+*/
+CIccApplyXform *CIccXformMpe::GetNewApply(icStatusCMM &status)
+{
+ if (!m_pTag)
+ return NULL;
+
+ CIccApplyXformMpe *rv= new CIccApplyXformMpe(this);
+
+ if (!rv) {
+ status = icCmmStatAllocErr;
+ return NULL;
+ }
+
+ rv->m_pApply = m_pTag->GetNewApply();
+ if (!rv->m_pApply) {
+ status = icCmmStatAllocErr;
+ delete rv;
+ return NULL;
+ }
+
+ status = icCmmStatOk;
+ return rv;
+}
+
+
+/**
+**************************************************************************
+* Name: CIccXformMPE::Apply
+*
+* Purpose:
+* Does the actual application of the Xform.
+*
+* Args:
+* pApply = ApplyXform object containging temporary storage used during Apply
+* DstPixel = Destination pixel where the result is stored,
+* SrcPixel = Source pixel which is to be applied.
+**************************************************************************
+*/
+void CIccXformMpe::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const
+{
+ const CIccTagMultiProcessElement *pTag = m_pTag;
+
+ if (!m_bInput) { //PCS comming in?
+ if (m_nIntent != icAbsoluteColorimetric) //B2D3 tags don't need abs conversion
+ SrcPixel = CheckSrcAbs(pApply, SrcPixel);
+
+ //Since MPE tags use "real" values for PCS we need to convert from
+ //internal encoding used by IccProfLib
+ icFloatNumber temp[3];
+ switch (GetSrcSpace()) {
+ case icSigXYZData:
+ memcpy(&temp[0], SrcPixel, 3*sizeof(icFloatNumber));
+ icXyzFromPcs(temp);
+ SrcPixel = &temp[0];
+ break;
+
+ case icSigLabData:
+ memcpy(&temp[0], SrcPixel, 3*sizeof(icFloatNumber));
+ icLabFromPcs(temp);
+ SrcPixel = &temp[0];
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ //Note: pApply should be a CIccApplyXformMpe type here
+ CIccApplyXformMpe *pApplyMpe = (CIccApplyXformMpe *)pApply;
+
+ pTag->Apply(pApplyMpe->m_pApply, DstPixel, SrcPixel);
+
+ if (m_bInput) { //PCS going out?
+ //Since MPE tags use "real" values for PCS we need to convert to
+ //internal encoding used by IccProfLib
+ switch(GetDstSpace()) {
+ case icSigXYZData:
+ icXyzToPcs(DstPixel);
+ break;
+
+ case icSigLabData:
+ icLabToPcs(DstPixel);
+ break;
+
+ default:
+ break;
+ }
+
+ if (m_nIntent != icAbsoluteColorimetric) { //D2B3 tags don't need abs conversion
+ CheckDstAbs(DstPixel);
+ }
+ }
+}
+
+/**
+**************************************************************************
+* Name: CIccApplyXformMpe::CIccApplyXformMpe
+*
+* Purpose:
+* Constructor
+**************************************************************************
+*/
+CIccApplyXformMpe::CIccApplyXformMpe(CIccXformMpe *pXform) : CIccApplyXform(pXform)
+{
+}
+
+/**
+**************************************************************************
+* Name: CIccApplyXformMpe::~CIccApplyXformMpe
+*
+* Purpose:
+* Destructor
+**************************************************************************
+*/
+CIccApplyXformMpe::~CIccApplyXformMpe()
+{
+}
+
+
+/**
+**************************************************************************
+* Name: CIccApplyCmm::CIccApplyCmm
+*
+* Purpose:
+* Constructor
+*
+* Args:
+* pCmm = ptr to CMM to apply against
+**************************************************************************
+*/
+CIccApplyCmm::CIccApplyCmm(CIccCmm *pCmm)
+{
+ m_pCmm = pCmm;
+ m_pPCS = m_pCmm->GetPCS();
+
+ m_Xforms = new CIccApplyXformList;
+ m_Xforms->clear();
+}
+
+/**
+**************************************************************************
+* Name: CIccApplyCmm::~CIccApplyCmm
+*
+* Purpose:
+* Destructor
+**************************************************************************
+*/
+CIccApplyCmm::~CIccApplyCmm()
+{
+ if (m_Xforms) {
+ CIccApplyXformList::iterator i;
+
+ for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
+ if (i->ptr)
+ delete i->ptr;
+ }
+
+ delete m_Xforms;
+ }
+
+ if (m_pPCS)
+ delete m_pPCS;
+}
+
+
+/**
+**************************************************************************
+* Name: CIccApplyCmm::Apply
+*
+* Purpose:
+* Does the actual application of the Xforms in the list.
+*
+* Args:
+* DstPixel = Destination pixel where the result is stored,
+* SrcPixel = Source pixel which is to be applied.
+**************************************************************************
+*/
+icStatusCMM CIccApplyCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel)
+{
+ icFloatNumber Pixel[16], *pDst;
+ const icFloatNumber *pSrc;
+ CIccApplyXformList::iterator i;
+ const CIccXform *pLastXform;
+ int j, n = (int)m_Xforms->size();
+ bool bNoClip;
+ if (!n)
+ return icCmmStatBadXform;
+ m_pPCS->Reset(m_pCmm->m_nSrcSpace);
+ pSrc = SrcPixel;
+ pDst = Pixel;
+
+ if (n>1) {
+ for (j=0, i=m_Xforms->begin(); jend(); i++, j++) {
+
+ i->ptr->Apply(pDst, m_pPCS->Check(pSrc, i->ptr->GetXform()));
+ pSrc = pDst;
+ }
+
+ pLastXform = i->ptr->GetXform();
+ i->ptr->Apply(DstPixel, m_pPCS->Check(pSrc, pLastXform));
+ bNoClip = pLastXform->NoClipPCS();
+ }
+ else if (n==1) {
+ i = m_Xforms->begin();
+ pLastXform = i->ptr->GetXform();
+// pri_debug("测试第一步4444");
+ i->ptr->Apply(DstPixel, m_pPCS->Check(SrcPixel, pLastXform));
+// pri_debug("测试第一步3333");
+ bNoClip = pLastXform->NoClipPCS();
+// pri_debug("测试第一步2222");
+ }
+ else {
+ bNoClip = true;
+ }
+
+ m_pPCS->CheckLast(DstPixel, m_pCmm->m_nDestSpace, bNoClip);
+
+ return icCmmStatOk;
+}
+
+/**
+**************************************************************************
+* Name: CIccApplyCmm::Apply
+*
+* Purpose:
+* Does the actual application of the Xforms in the list.
+*
+* Args:
+* DstPixel = Destination pixel where the result is stored,
+* SrcPixel = Source pixel which is to be applied.
+**************************************************************************
+*/
+icStatusCMM CIccApplyCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels)
+{
+ icFloatNumber Pixel[16], *pDst;
+ const icFloatNumber *pSrc;
+ CIccApplyXformList::iterator i;
+ int j, n = (int)m_Xforms->size();
+ icUInt32Number k;
+
+ if (!n)
+ return icCmmStatBadXform;
+
+ for (k=0; kReset(m_pCmm->m_nSrcSpace);
+
+ pSrc = SrcPixel;
+ pDst = Pixel;
+
+ if (n>1) {
+ for (j=0, i=m_Xforms->begin(); jend(); i++, j++) {
+
+ i->ptr->Apply(pDst, m_pPCS->Check(pSrc, i->ptr->GetXform()));
+ pSrc = pDst;
+ }
+
+ i->ptr->Apply(DstPixel, m_pPCS->Check(pSrc, i->ptr->GetXform()));
+ }
+ else if (n==1) {
+ i = m_Xforms->begin();
+ i->ptr->Apply(DstPixel, m_pPCS->Check(SrcPixel, i->ptr->GetXform()));
+ }
+
+ m_pPCS->CheckLast(DstPixel, m_pCmm->m_nDestSpace);
+
+ DstPixel += m_pCmm->GetDestSamples();
+ SrcPixel += m_pCmm->GetSourceSamples();
+ }
+
+ return icCmmStatOk;
+}
+
+void CIccApplyCmm::AppendApplyXform(CIccApplyXform *pApplyXform)
+{
+ CIccApplyXformPtr ptr;
+ ptr.ptr = pApplyXform;
+
+ m_Xforms->push_back(ptr);
+}
+
+/**
+ **************************************************************************
+ * Name: CIccCmm::CIccCmm
+ *
+ * Purpose:
+ * Constructor
+ *
+ * Args:
+ * nSrcSpace = signature of the source color space,
+ * nDestSpace = signature of the destination color space,
+ * bFirstInput = true if the first profile added is an input profile
+ **************************************************************************
+ */
+CIccCmm::CIccCmm(icColorSpaceSignature nSrcSpace /*=icSigUnknownData*/,
+ icColorSpaceSignature nDestSpace /*=icSigUnknownData*/,
+ bool bFirstInput /*=true*/)
+{
+ m_bValid = false;
+
+ m_bLastInput = !bFirstInput;
+ m_nSrcSpace = nSrcSpace;
+ m_nDestSpace = nDestSpace;
+
+ m_nLastSpace = nSrcSpace;
+ m_nLastIntent = icUnknownIntent;
+
+ m_Xforms = new CIccXformList;
+ m_Xforms->clear();
+
+ m_pApply = NULL;
+}
+
+/**
+ **************************************************************************
+ * Name: CIccCmm::~CIccCmm
+ *
+ * Purpose:
+ * Destructor
+ **************************************************************************
+ */
+CIccCmm::~CIccCmm()
+{
+ if (m_Xforms) {
+ CIccXformList::iterator i;
+
+ for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
+ if (i->ptr)
+ delete i->ptr;
+ }
+
+ delete m_Xforms;
+ }
+
+ if (m_pApply)
+ delete m_pApply;
+}
+
+/**
+ **************************************************************************
+ * Name: CIccCmm::AddXform
+ *
+ * Purpose:
+ * Adds a profile at the end of the Xform list
+ *
+ * Args:
+ * szProfilePath = file name of the profile to be added,
+ * nIntent = rendering intent to be used with the profile,
+ * nInterp = type of interpolation to be used with the profile,
+ * nLutType = selection of which transform lut to use
+ * pHintManager = hints for creating the xform
+ *
+ * Return:
+ * icCmmStatOk, if the profile was added to the list succesfully
+ **************************************************************************
+ */
+icStatusCMM CIccCmm::AddXform(const icChar *szProfilePath,
+ icRenderingIntent nIntent /*=icUnknownIntent*/,
+ icXformInterp nInterp /*icXformInterp*/,
+ icXformLutType nLutType /*=icXformLutColor*/,
+ bool bUseMpeTags /*=true*/,
+ CIccCreateXformHintManager *pHintManager /*=NULL*/)
+{
+ CIccProfile *pProfile = OpenIccProfile(szProfilePath);
+
+ if (!pProfile)
+ return icCmmStatCantOpenProfile;
+
+ icStatusCMM rv = AddXform(pProfile, nIntent, nInterp, nLutType, bUseMpeTags, pHintManager);
+
+ if (rv != icCmmStatOk)
+ delete pProfile;
+
+ return rv;
+}
+
+
+/**
+**************************************************************************
+* Name: CIccCmm::AddXform
+*
+* Purpose:
+* Adds a profile at the end of the Xform list
+*
+* Args:
+* pProfileMem = ptr to profile loaded into memory. Note: this memory
+* needs to be available until after the Begin() function is called.
+* nProfileLen = size in bytes of profile loaded into memory
+* nIntent = rendering intent to be used with the profile,
+* nInterp = type of interpolation to be used with the profile,
+* nLutType = selection of which transform lut to use
+* bUseMpeTags = flag to indicate the use MPE flags if available
+* pHintManager = hints for creating the xform
+*
+* Return:
+* icCmmStatOk, if the profile was added to the list succesfully
+**************************************************************************
+*/
+icStatusCMM CIccCmm::AddXform(icUInt8Number *pProfileMem,
+ icUInt32Number nProfileLen,
+ icRenderingIntent nIntent /*=icUnknownIntent*/,
+ icXformInterp nInterp /*icXformInterp*/,
+ icXformLutType nLutType /*=icXformLutColor*/,
+ bool bUseMpeTags /*=true*/,
+ CIccCreateXformHintManager *pHintManager /*=NULL*/)
+{
+ CIccMemIO *pFile = new CIccMemIO;
+
+ if (!pFile || !pFile->Attach(pProfileMem, nProfileLen))
+ return icCmmStatCantOpenProfile;
+
+ CIccProfile *pProfile = new CIccProfile;
+
+ if (!pProfile)
+ return icCmmStatCantOpenProfile;
+
+ if (!pProfile->Attach(pFile)) {
+ delete pFile;
+ delete pProfile;
+ return icCmmStatCantOpenProfile;
+ }
+
+ icStatusCMM rv = AddXform(pProfile, nIntent, nInterp, nLutType, bUseMpeTags, pHintManager);
+
+ if (rv != icCmmStatOk)
+ delete pProfile;
+
+ return rv;
+}
+
+
+/**
+ **************************************************************************
+ * Name: CIccCmm::AddXform
+ *
+ * Purpose:
+ * Adds a profile at the end of the Xform list
+ *
+ * Args:
+ * pProfile = pointer to the CIccProfile object to be added,
+ * nIntent = rendering intent to be used with the profile,
+ * nInterp = type of interpolation to be used with the profile,
+ * nLutType = selection of which transform lut to use
+ * bUseMpeTags = flag to indicate the use MPE flags if available
+ * pHintManager = hints for creating the xform
+ *
+ * Return:
+ * icCmmStatOk, if the profile was added to the list succesfully
+ **************************************************************************
+ */
+icStatusCMM CIccCmm::AddXform(CIccProfile *pProfile,
+ icRenderingIntent nIntent /*=icUnknownIntent*/,
+ icXformInterp nInterp /*=icInterpLinear*/,
+ icXformLutType nLutType /*=icXformLutColor*/,
+ bool bUseMpeTags /*=true*/,
+ CIccCreateXformHintManager *pHintManager /*=NULL*/)
+{
+ icColorSpaceSignature nSrcSpace, nDstSpace;
+ bool bInput = !m_bLastInput;
+
+ if (!pProfile)
+ return icCmmStatInvalidProfile;
+
+ switch (nLutType) {
+ case icXformLutColor:
+ {
+ //Check pProfile if nIntent and input can be found.
+ if (bInput) {
+ nSrcSpace = pProfile->m_Header.colorSpace;
+ nDstSpace = pProfile->m_Header.pcs;
+ }
+ else {
+ if (pProfile->m_Header.deviceClass == icSigLinkClass) {
+ return icCmmStatBadSpaceLink;
+ }
+ nSrcSpace = pProfile->m_Header.pcs;
+ nDstSpace = pProfile->m_Header.colorSpace;
+ if (pProfile->m_Header.deviceClass == icSigAbstractClass) {
+ bInput = true;
+ nIntent = icPerceptual; // Note: icPerceptualIntent = 0
+ }
+ }
+ }
+ break;
+
+ case icXformLutPreview:
+ nSrcSpace = pProfile->m_Header.pcs;
+ nDstSpace = pProfile->m_Header.pcs;
+ bInput = false;
+ break;
+
+ case icXformLutGamut:
+ nSrcSpace = pProfile->m_Header.pcs;
+ nDstSpace = icSigGamutData;
+ bInput = true;
+ break;
+
+ default:
+ return icCmmStatBadLutType;
+ }
+
+ //Make sure colorspaces match with previous xforms
+ if (!m_Xforms->size()) {
+ if (m_nSrcSpace == icSigUnknownData) {
+ m_nLastSpace = nSrcSpace;
+ m_nSrcSpace = nSrcSpace;
+ }
+ else if (!IsCompatSpace(m_nSrcSpace, nSrcSpace)) {
+ return icCmmStatBadSpaceLink;
+ }
+ }
+ else if (!IsCompatSpace(m_nLastSpace, nSrcSpace)) {
+ return icCmmStatBadSpaceLink;
+ }
+
+ if (nSrcSpace==icSigNamedData)
+ return icCmmStatBadSpaceLink;
+
+ //Automatic creation of intent from header/last profile
+ if (nIntent==icUnknownIntent) {
+ if (bInput) {
+ nIntent = (icRenderingIntent)pProfile->m_Header.renderingIntent;
+ }
+ else {
+ nIntent = m_nLastIntent;
+ }
+ if (nIntent == icUnknownIntent)
+ nIntent = icPerceptual;
+ }
+
+ CIccXformPtr Xform;
+
+ Xform.ptr = CIccXform::Create(pProfile, bInput, nIntent, nInterp, nLutType, bUseMpeTags, pHintManager);
+
+ if (!Xform.ptr) {
+ return icCmmStatBadXform;
+ }
+
+ m_nLastSpace = nDstSpace;
+ m_nLastIntent = nIntent;
+ m_bLastInput = bInput;
+
+ m_Xforms->push_back(Xform);
+
+ return icCmmStatOk;
+}
+
+
+/**
+ **************************************************************************
+ * Name: CIccCmm::AddXform
+ *
+ * Purpose:
+ * Adds a profile at the end of the Xform list
+ *
+ * Args:
+ * Profile = reference a CIccProfile object that will be copies and added,
+ * nIntent = rendering intent to be used with the profile,
+ * nInterp = type of interpolation to be used with the profile,
+ * nLutType = selection of which transform lut to use
+ * bUseMpeTags = flag to indicate the use MPE flags if available
+ * pHintManager = hints for creating the xform
+ *
+ * Return:
+ * icCmmStatOk, if the profile was added to the list succesfully
+ **************************************************************************
+ */
+icStatusCMM CIccCmm::AddXform(CIccProfile &Profile,
+ icRenderingIntent nIntent /*=icUnknownIntent*/,
+ icXformInterp nInterp /*=icInterpLinear*/,
+ icXformLutType nLutType /*=icXformLutColor*/,
+ bool bUseMpeTags /*=true*/,
+ CIccCreateXformHintManager *pHintManager /*=NULL*/)
+{
+ CIccProfile *pProfile = new CIccProfile(Profile);
+
+ if (!pProfile)
+ return icCmmStatAllocErr;
+
+ icStatusCMM stat = AddXform(pProfile, nIntent, nInterp, nLutType, bUseMpeTags, pHintManager);
+
+ if (stat != icCmmStatOk)
+ delete pProfile;
+
+ return stat;
+}
+
+/**
+**************************************************************************
+* Name: CIccCmm::GetNewApplyCmm
+*
+* Purpose:
+* Does the initialization of the Xforms before Apply() is called.
+* Must be called before Apply().
+*
+**************************************************************************
+*/
+icStatusCMM CIccCmm::Begin(bool bAllocApplyCmm/*=true*/)
+{
+ if (m_pApply)
+ return icCmmStatOk;
+
+ if (m_nDestSpace==icSigUnknownData) {
+ m_nDestSpace = m_nLastSpace;
+ }
+ else if (!IsCompatSpace(m_nDestSpace, m_nLastSpace)) {
+ return icCmmStatBadSpaceLink;
+ }
+
+ if (m_nSrcSpace==icSigNamedData || m_nDestSpace==icSigNamedData) {
+ return icCmmStatBadSpaceLink;
+ }
+
+ icStatusCMM rv = icCmmStatOk;
+ CIccXformList::iterator i;
+
+ for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
+ rv = i->ptr->Begin();
+
+ if (rv!= icCmmStatOk) {
+ return rv;
+ }
+ }
+
+ if (bAllocApplyCmm) {
+ m_pApply = GetNewApplyCmm(rv);
+ }
+ else
+ rv = icCmmStatOk;
+
+ return rv;
+}
+
+
+/**
+ **************************************************************************
+ * Name: CIccCmm::GetNewApplyCmm
+ *
+ * Purpose:
+ * Allocates an CIccApplyCmm object that does the initialization of the Xforms
+ * that provides an Apply() function.
+ * Multiple CIccApplyCmm objects can be allocated and used in separate threads.
+ *
+ **************************************************************************
+ */
+CIccApplyCmm *CIccCmm::GetNewApplyCmm(icStatusCMM &status)
+{
+ CIccApplyCmm *pApply = new CIccApplyCmm(this);
+
+ if (!pApply) {
+ status = icCmmStatAllocErr;
+ return NULL;
+ }
+
+ CIccXformList::iterator i;
+ CIccApplyXform *pXform;
+
+ for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
+ pXform = i->ptr->GetNewApply(status);
+ if (!pXform || status != icCmmStatOk) {
+ delete pApply;
+ return NULL;
+ }
+ pApply->AppendApplyXform(pXform);
+ }
+
+ m_bValid = true;
+
+ status = icCmmStatOk;
+
+ return pApply;
+}
+
+
+/**
+**************************************************************************
+* Name: CIccCmm::Apply
+*
+* Purpose:
+* Uses the m_pApply object allocated during Begin to Apply the transformations
+* associated with the CMM.
+*
+**************************************************************************
+*/
+icStatusCMM CIccCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel)
+{
+ return m_pApply->Apply(DstPixel, SrcPixel);
+}
+
+
+/**
+**************************************************************************
+* Name: CIccCmm::Apply
+*
+* Purpose:
+* Uses the m_pApply object allocated during Begin to Apply the transformations
+* associated with the CMM.
+*
+**************************************************************************
+*/
+icStatusCMM CIccCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels)
+{
+ return m_pApply->Apply(DstPixel, SrcPixel, nPixels);
+}
+
+
+/**
+**************************************************************************
+* Name: CIccCmm::RemoveAllIO()
+*
+* Purpose:
+* Remove any attachments to CIccIO objects associated with the profiles
+* related to the transforms attached to the CMM.
+* Must be called after Begin().
+*
+* Return:
+* icCmmStatOK - All IO objects removed
+* icCmmStatBadXform - Begin() has not been performed.
+**************************************************************************
+*/
+icStatusCMM CIccCmm::RemoveAllIO()
+{
+ if (!Valid())
+ return icCmmStatBadXform;
+
+ CIccXformList::iterator i;
+
+ for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
+ i->ptr->RemoveIO();
+ }
+
+ return icCmmStatOk;
+}
+
+/**
+ *************************************************************************
+ ** Name: CIccCmm::IsInGamut
+ **
+ ** Purpose:
+ ** Function to check if internal representation of gamut is in gamut. Note
+ ** since gamut table is 8 bit and a color is considered to be in out of gamut
+ ** if the value is not zero. Then we need to check where the 8 bit representation
+ ** of the internal value is not zero.
+ **
+ ** Args:
+ ** pInternal = internal pixel representation of gamut value
+ **
+ ** Return:
+ ** true if in gamut, false if out of gamut
+ **************************************************************************/
+bool CIccCmm::IsInGamut(icFloatNumber *pInternal)
+{
+ if (!((unsigned int)((*pInternal)*255.0)))
+ return true;
+ return false;
+}
+
+
+/**
+ **************************************************************************
+ * Name: CIccCmm::ToInternalEncoding
+ *
+ * Purpose:
+ * Functions for converting to Internal representation of pixel colors.
+ *
+ * Args:
+ * nSpace = color space signature of the data,
+ * nEncode = icFloatColorEncoding type of the data,
+ * pInternal = converted data is stored here,
+ * pData = the data to be converted
+ * bClip = flag to clip to internal range
+ **************************************************************************
+ */
+icStatusCMM CIccCmm::ToInternalEncoding(icColorSpaceSignature nSpace, icFloatColorEncoding nEncode,
+ icFloatNumber *pInternal, const icFloatNumber *pData,
+ bool bClip)
+{
+ int nSamples = icGetSpaceSamples(nSpace);
+ if (!nSamples)
+ return icCmmStatBadColorEncoding;
+
+ icUInt16Number i;
+ icFloatNumber pInput[16];
+ memcpy(pInput, pData, nSamples*sizeof(icFloatNumber));
+ bool bCLRspace = icIsSpaceCLR(nSpace);
+
+ switch(nSpace) {
+
+ case icSigLabData:
+ {
+ switch(nEncode) {
+ case icEncodeValue:
+ {
+ icLabToPcs(pInput);
+ break;
+ }
+ case icEncodeFloat:
+ {
+ break;
+ }
+ case icEncode8Bit:
+ {
+ pInput[0] = icU8toF((icUInt8Number)pInput[0])*100.0f;
+ pInput[1] = icU8toAB((icUInt8Number)pInput[1]);
+ pInput[2] = icU8toAB((icUInt8Number)pInput[2]);
+
+ icLabToPcs(pInput);
+ break;
+ }
+ case icEncode16Bit:
+ {
+ pInput[0] = icU16toF((icUInt16Number)pInput[0]);
+ pInput[1] = icU16toF((icUInt16Number)pInput[1]);
+ pInput[2] = icU16toF((icUInt16Number)pInput[2]);
+ break;
+ }
+ case icEncode16BitV2:
+ {
+ pInput[0] = icU16toF((icUInt16Number)pInput[0]);
+ pInput[1] = icU16toF((icUInt16Number)pInput[1]);
+ pInput[2] = icU16toF((icUInt16Number)pInput[2]);
+
+ CIccPCS::Lab2ToLab4(pInput, pInput);
+ break;
+ }
+ default:
+ return icCmmStatBadColorEncoding;
+ break;
+ }
+ break;
+ }
+
+ case icSigXYZData:
+ {
+ switch(nEncode) {
+ case icEncodeValue:
+ {
+ pInput[0] = (icFloatNumber)pInput[0];
+ pInput[1] = (icFloatNumber)pInput[1];
+ pInput[2] = (icFloatNumber)pInput[2];
+ icXyzToPcs(pInput);
+ break;
+ }
+ case icEncodePercent:
+ {
+ pInput[0] = (icFloatNumber)(pInput[0] / 100.0);
+ pInput[1] = (icFloatNumber)(pInput[1] / 100.0);
+ pInput[2] = (icFloatNumber)(pInput[2] / 100.0);
+ icXyzToPcs(pInput);
+ break;
+ }
+ case icEncodeFloat:
+ {
+ icXyzToPcs(pInput);
+ break;
+ }
+
+ case icEncode16Bit:
+ case icEncode16BitV2:
+ {
+ pInput[0] = icUSFtoD((icU1Fixed15Number)pInput[0]);
+ pInput[1] = icUSFtoD((icU1Fixed15Number)pInput[1]);
+ pInput[2] = icUSFtoD((icU1Fixed15Number)pInput[2]);
+ break;
+ }
+
+ default:
+ return icCmmStatBadColorEncoding;
+ break;
+ }
+ break;
+ }
+
+ case icSigNamedData:
+ return icCmmStatBadColorEncoding;
+
+ default:
+ {
+ switch(nEncode) {
+ case icEncodeValue:
+ {
+ if (!bCLRspace || nSamples<3) {
+ return icCmmStatBadColorEncoding;
+ }
+ icLabToPcs(pInput);
+ break;
+ }
+
+ case icEncodePercent:
+ {
+ if (bClip) {
+ for(i=0; i 1.0) pInput[i] = 1.0;
+ }
+ }
+ else {
+ for(i=0; i 1.0) pInput[i] = 1.0;
+ }
+ }
+ break;
+ }
+
+ case icEncode8Bit:
+ {
+ for(i=0; i 1.0) pInput[i] = 1.0;
+ pInput[i] = (icFloatNumber)(pInput[i]*100.0);
+ }
+ }
+ else {
+ for(i=0; i 1.0) pInput[i] = 1.0;
+ }
+ }
+ break;
+ }
+
+ case icEncode8Bit:
+ {
+ for(i=0; isize();
+}
+
+
+/**
+**************************************************************************
+* Name: CIccCmm::GetFirstXformSource
+*
+* Purpose:
+* Get source colorspace of first transform (similar to m_nSrcSpace with differences in dev colorimetric spaces)
+*
+* Return:
+* colorspace
+**************************************************************************
+*/
+icColorSpaceSignature CIccCmm::GetFirstXformSource()
+{
+ if (!m_Xforms->size())
+ return m_nSrcSpace;
+
+ return m_Xforms->begin()->ptr->GetSrcSpace();
+}
+
+/**
+**************************************************************************
+* Name: CIccCmm::GetNumXforms
+*
+* Purpose:
+* Get source colorspace of last transform (similar to m_nSrcSpace with differences in dev colorimetric spaces)
+*
+* Return:
+* colorspace
+**************************************************************************
+*/
+icColorSpaceSignature CIccCmm::GetLastXformDest()
+{
+ if (!m_Xforms->size())
+ return m_nDestSpace;
+
+ return m_Xforms->rbegin()->ptr->GetDstSpace();
+}
+
+/**
+**************************************************************************
+* Name: CIccApplyCmm::CIccApplyCmm
+*
+* Purpose:
+* Constructor
+*
+* Args:
+* pCmm = ptr to CMM to apply against
+**************************************************************************
+*/
+CIccApplyNamedColorCmm::CIccApplyNamedColorCmm(CIccNamedColorCmm *pCmm) : CIccApplyCmm(pCmm)
+{
+}
+
+
+/**
+**************************************************************************
+* Name: CIccApplyCmm::CIccApplyCmm
+*
+* Purpose:
+* Destructor
+**************************************************************************
+*/
+CIccApplyNamedColorCmm::~CIccApplyNamedColorCmm()
+{
+}
+
+
+/**
+**************************************************************************
+* Name: CIccApplyNamedColorCmm::Apply
+*
+* Purpose:
+* Does the actual application of the Xforms in the list.
+*
+* Args:
+* DstPixel = Destination pixel where the result is stored,
+* SrcPixel = Source pixel which is to be applied.
+**************************************************************************
+*/
+icStatusCMM CIccApplyNamedColorCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel)
+{
+ icFloatNumber Pixel[16], *pDst;
+ const icFloatNumber *pSrc;
+ CIccApplyXformList::iterator i;
+ int j, n = (int)m_Xforms->size();
+ CIccApplyXform *pApply;
+ const CIccXform *pApplyXform;
+ CIccXformNamedColor *pXform;
+
+ if (!n)
+ return icCmmStatBadXform;
+
+ icChar NamedColor[256];
+ icStatusCMM rv;
+
+ m_pPCS->Reset(m_pCmm->GetSourceSpace());
+
+ pSrc = SrcPixel;
+ pDst = Pixel;
+
+ if (n>1) {
+ for (j=0, i=m_Xforms->begin(); jend(); i++, j++) {
+
+ pApply = i->ptr;
+ pApplyXform = pApply->GetXform();
+ if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
+ pXform = (CIccXformNamedColor*)pApplyXform;
+
+ switch(pXform->GetInterface()) {
+ case icApplyPixel2Pixel:
+ pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform));
+ break;
+
+ case icApplyPixel2Named:
+ pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform));
+ break;
+
+ case icApplyNamed2Pixel:
+ if (j==0) {
+ return icCmmStatIncorrectApply;
+ }
+
+ rv = pXform->Apply(pApply, pDst, NamedColor);
+
+ if (rv) {
+ return rv;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ else {
+ pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pApplyXform));
+ }
+ pSrc = pDst;
+ }
+
+ pApply = i->ptr;
+ pApplyXform = pApply->GetXform();
+ if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
+ pXform = (CIccXformNamedColor*)pApplyXform;
+
+ switch(pXform->GetInterface()) {
+ case icApplyPixel2Pixel:
+ pXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pXform));
+ break;
+
+ case icApplyPixel2Named:
+ default:
+ return icCmmStatIncorrectApply;
+ break;
+
+ case icApplyNamed2Pixel:
+ rv = pXform->Apply(pApply, DstPixel, NamedColor);
+ if (rv) {
+ return rv;
+ }
+ break;
+
+ }
+ }
+ else {
+ pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform));
+ }
+
+ }
+ else if (n==1) {
+ i = m_Xforms->begin();
+
+ pApply = i->ptr;
+ pApplyXform = pApply->GetXform();
+ if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
+ return icCmmStatIncorrectApply;
+ }
+
+ pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform));
+ }
+
+ m_pPCS->CheckLast(DstPixel, m_pCmm->GetDestSpace());
+
+ return icCmmStatOk;
+}
+
+
+/**
+**************************************************************************
+* Name: CIccApplyNamedColorCmm::Apply
+*
+* Purpose:
+* Does the actual application of the Xforms in the list.
+*
+* Args:
+* DstPixel = Destination pixel where the result is stored,
+* SrcPixel = Source pixel which is to be applied.
+**************************************************************************
+*/
+icStatusCMM CIccApplyNamedColorCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels)
+{
+ icFloatNumber Pixel[16], *pDst;
+ const icFloatNumber *pSrc;
+ CIccApplyXformList::iterator i;
+ int j, n = (int)m_Xforms->size();
+ CIccApplyXform *pApply;
+ const CIccXform *pApplyXform;
+ CIccXformNamedColor *pXform;
+ icUInt32Number k;
+
+ if (!n)
+ return icCmmStatBadXform;
+
+ icChar NamedColor[256];
+ icStatusCMM rv;
+
+ for (k=0; kReset(m_pCmm->GetSourceSpace());
+
+ pSrc = SrcPixel;
+ pDst = Pixel;
+
+ if (n>1) {
+ for (j=0, i=m_Xforms->begin(); jend(); i++, j++) {
+
+ pApply = i->ptr;
+ pApplyXform = pApply->GetXform();
+ if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
+ pXform = (CIccXformNamedColor*)pApplyXform;
+
+ switch(pXform->GetInterface()) {
+ case icApplyPixel2Pixel:
+ pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform));
+ break;
+
+ case icApplyPixel2Named:
+ pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform));
+ break;
+
+ case icApplyNamed2Pixel:
+ if (j==0) {
+ return icCmmStatIncorrectApply;
+ }
+
+ rv = pXform->Apply(pApply, pDst, NamedColor);
+
+ if (rv) {
+ return rv;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ else {
+ pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pApplyXform));
+ }
+ pSrc = pDst;
+ }
+
+ pApply = i->ptr;
+ pApplyXform = pApply->GetXform();
+ if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
+ pXform = (CIccXformNamedColor*)pApplyXform;
+
+ switch(pXform->GetInterface()) {
+ case icApplyPixel2Pixel:
+ pXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pXform));
+ break;
+
+ case icApplyPixel2Named:
+ default:
+ return icCmmStatIncorrectApply;
+ break;
+
+ case icApplyNamed2Pixel:
+ rv = pXform->Apply(pApply, DstPixel, NamedColor);
+ if (rv) {
+ return rv;
+ }
+ break;
+
+ }
+ }
+ else {
+ pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform));
+ }
+
+ }
+ else if (n==1) {
+ i = m_Xforms->begin();
+
+ pApply = i->ptr;
+ pApplyXform = pApply->GetXform();
+ if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
+ return icCmmStatIncorrectApply;
+ }
+
+ pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform));
+ }
+
+ m_pPCS->CheckLast(DstPixel, m_pCmm->GetDestSpace());
+
+ SrcPixel += m_pCmm->GetSourceSamples();
+ DstPixel += m_pCmm->GetDestSamples();
+ }
+
+ return icCmmStatOk;
+}
+
+
+/**
+**************************************************************************
+* Name: CIccApplyNamedColorCmm::Apply
+*
+* Purpose:
+* Does the actual application of the Xforms in the list.
+*
+* Args:
+* DstColorName = Destination string where the result is stored,
+* SrcPixel = Source pixel which is to be applied.
+**************************************************************************
+*/
+icStatusCMM CIccApplyNamedColorCmm::Apply(icChar* DstColorName, const icFloatNumber *SrcPixel)
+{
+ icFloatNumber Pixel[16], *pDst;
+ const icFloatNumber *pSrc;
+ CIccApplyXformList::iterator i;
+ int j, n = (int)m_Xforms->size();
+ CIccApplyXform *pApply;
+ const CIccXform *pApplyXform;
+ CIccXformNamedColor *pXform;
+
+ if (!n)
+ return icCmmStatBadXform;
+
+ icChar NamedColor[256];
+ icStatusCMM rv;
+
+ m_pPCS->Reset(m_pCmm->GetSourceSpace());
+
+ pSrc = SrcPixel;
+ pDst = Pixel;
+
+ if (n>1) {
+ for (j=0, i=m_Xforms->begin(); jend(); i++, j++) {
+
+ pApply = i->ptr;
+ pApplyXform = pApply->GetXform();
+ if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
+ pXform = (CIccXformNamedColor*)pApplyXform;
+ switch(pXform->GetInterface()) {
+ case icApplyPixel2Pixel:
+ pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform));
+ break;
+
+ case icApplyPixel2Named:
+ pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform));
+ break;
+
+ case icApplyNamed2Pixel:
+ if (j==0) {
+ return icCmmStatIncorrectApply;
+ }
+ rv = pXform->Apply(pApply, pDst, NamedColor);
+ if (rv) {
+ return rv;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ else {
+ pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pApplyXform));
+ }
+ pSrc = pDst;
+ }
+
+ pApply = i->ptr;
+ pApplyXform = pApply->GetXform();
+ if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
+ pXform = (CIccXformNamedColor*)pApplyXform;
+ switch(pXform->GetInterface()) {
+
+ case icApplyPixel2Named:
+ pXform->Apply(pApply, DstColorName, m_pPCS->Check(pSrc, pXform));
+ break;
+
+ case icApplyPixel2Pixel:
+ case icApplyNamed2Pixel:
+ default:
+ return icCmmStatIncorrectApply;
+ break;
+ }
+ }
+ else {
+ return icCmmStatIncorrectApply;
+ }
+
+ }
+ else if (n==1) {
+ i = m_Xforms->begin();
+ pApply = i->ptr;
+ pApplyXform = pApply->GetXform();
+ if (pApplyXform->GetXformType()!=icXformTypeNamedColor) {
+ return icCmmStatIncorrectApply;
+ }
+
+ pXform = (CIccXformNamedColor*)pApplyXform;
+ pXform->Apply(pApply, DstColorName, m_pPCS->Check(pSrc, pXform));
+ }
+
+ return icCmmStatOk;
+}
+
+
+/**
+**************************************************************************
+* Name: CIccApplyNamedColorCmm::Apply
+*
+* Purpose:
+* Does the actual application of the Xforms in the list.
+*
+* Args:
+* DstPixel = Destination pixel where the result is stored,
+* SrcColorName = Source color name which is to be searched.
+**************************************************************************
+*/
+icStatusCMM CIccApplyNamedColorCmm::Apply(icFloatNumber *DstPixel, const icChar *SrcColorName)
+{
+ icFloatNumber Pixel[16], *pDst;
+ const icFloatNumber *pSrc;
+ CIccApplyXformList::iterator i;
+ int j, n = (int)m_Xforms->size();
+ CIccApplyXform *pApply;
+ const CIccXform *pApplyXform;
+ CIccXformNamedColor *pXform;
+
+ if (!n)
+ return icCmmStatBadXform;
+
+ icChar NamedColor[256];
+ icStatusCMM rv;
+
+ i=m_Xforms->begin();
+ pApply = i->ptr;
+ pApplyXform = pApply->GetXform();
+ if (pApplyXform->GetXformType()!=icXformTypeNamedColor)
+ return icCmmStatIncorrectApply;
+
+ pXform = (CIccXformNamedColor*)pApplyXform;
+ m_pPCS->Reset(pXform->GetSrcSpace(), pXform->UseLegacyPCS());
+
+ pDst = Pixel;
+
+ if (n>1) {
+ rv = pXform->Apply(pApply, pDst, SrcColorName);
+ if (rv) {
+ return rv;
+ }
+
+ pSrc = pDst;
+
+ for (j=0, i++; jend(); i++, j++) {
+
+ pApply = i->ptr;
+ pApplyXform = pApply->GetXform();
+ if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
+ CIccXformNamedColor *pXform = (CIccXformNamedColor*)pApplyXform;
+ switch(pXform->GetInterface()) {
+ case icApplyPixel2Pixel:
+ pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform));
+ break;
+
+ case icApplyPixel2Named:
+ pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform));
+ break;
+
+ case icApplyNamed2Pixel:
+ rv = pXform->Apply(pApply, pDst, NamedColor);
+ if (rv) {
+ return rv;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ else {
+ pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pApplyXform));
+ }
+ pSrc = pDst;
+ }
+
+ pApply = i->ptr;
+ pApplyXform = pApply->GetXform();
+ if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
+ pXform = (CIccXformNamedColor*)pApplyXform;
+ switch(pXform->GetInterface()) {
+ case icApplyPixel2Pixel:
+ pXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pXform));
+ break;
+
+ case icApplyPixel2Named:
+ default:
+ return icCmmStatIncorrectApply;
+ break;
+
+ case icApplyNamed2Pixel:
+ rv = pXform->Apply(pApply, DstPixel, NamedColor);
+ if (rv) {
+ return rv;
+ }
+ break;
+
+ }
+ }
+ else {
+ pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform));
+ }
+
+ }
+ else if (n==1) {
+ rv = pXform->Apply(pApply, DstPixel, SrcColorName);
+ if (rv) {
+ return rv;
+ }
+ m_pPCS->Check(DstPixel, pXform);
+ }
+
+ m_pPCS->CheckLast(DstPixel, m_pCmm->GetDestSpace());
+
+ return icCmmStatOk;
+}
+
+/**
+**************************************************************************
+* Name: CIccApplyNamedColorCmm::Apply
+*
+* Purpose:
+* Does the actual application of the Xforms in the list.
+*
+* Args:
+* DstColorName = Destination string where the result is stored,
+* SrcColorName = Source color name which is to be searched.
+**************************************************************************
+*/
+icStatusCMM CIccApplyNamedColorCmm::Apply(icChar *DstColorName, const icChar *SrcColorName)
+{
+ icFloatNumber Pixel[16], *pDst;
+ const icFloatNumber *pSrc;
+ CIccApplyXformList::iterator i;
+ int j, n = (int)m_Xforms->size();
+ icChar NamedColor[256];
+ icStatusCMM rv;
+ CIccApplyXform *pApply;
+ const CIccXform *pApplyXform;
+ CIccXformNamedColor *pXform;
+
+ if (!n)
+ return icCmmStatBadXform;
+
+ i=m_Xforms->begin();
+
+ pApply = i->ptr;
+ pApplyXform = pApply->GetXform();
+ if (pApplyXform->GetXformType()!=icXformTypeNamedColor)
+ return icCmmStatIncorrectApply;
+
+ pXform = (CIccXformNamedColor*)pApplyXform;
+
+ m_pPCS->Reset(pXform->GetSrcSpace(), pXform->UseLegacyPCS());
+
+ pDst = Pixel;
+
+ if (n>1) {
+ rv = pXform->Apply(pApply, pDst, SrcColorName);
+
+ if (rv) {
+ return rv;
+ }
+
+ pSrc = pDst;
+
+ for (j=0, i++; jend(); i++, j++) {
+
+ pApply = i->ptr;
+ pApplyXform = pApply->GetXform();
+ if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
+ pXform = (CIccXformNamedColor*)pApplyXform;
+ switch(pXform->GetInterface()) {
+ case icApplyPixel2Pixel:
+ pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform));
+ break;
+
+
+ case icApplyPixel2Named:
+ pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform));
+ break;
+
+ case icApplyNamed2Pixel:
+ rv = pXform->Apply(pApply, pDst, NamedColor);
+ if (rv) {
+ return rv;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ else {
+ pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform));
+ }
+ pSrc = pDst;
+ }
+
+ pApply = i->ptr;
+ pApplyXform = pApply->GetXform();
+ if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
+ pXform = (CIccXformNamedColor*)pApplyXform;
+ switch(pXform->GetInterface()) {
+ case icApplyPixel2Named:
+ pXform->Apply(pApply, DstColorName, m_pPCS->Check(pSrc, pXform));
+ break;
+
+ case icApplyPixel2Pixel:
+ case icApplyNamed2Pixel:
+ default:
+ return icCmmStatIncorrectApply;
+ break;
+ }
+ }
+ else {
+ return icCmmStatIncorrectApply;
+ }
+
+ }
+ else if (n==1) {
+ return icCmmStatIncorrectApply;
+ }
+
+ return icCmmStatOk;
+}
+
+/**
+ **************************************************************************
+ * Name: CIccNamedColorCmm::CIccNamedColorCmm
+ *
+ * Purpose:
+ * Constructor
+ *
+ * Args:
+ * nSrcSpace = signature of the source color space,
+ * nDestSpace = signature of the destination color space,
+ * bFirstInput = true if the first profile added is an input profile
+ **************************************************************************
+ */
+CIccNamedColorCmm::CIccNamedColorCmm(icColorSpaceSignature nSrcSpace, icColorSpaceSignature nDestSpace,
+ bool bFirstInput) : CIccCmm(nSrcSpace, nDestSpace, bFirstInput)
+{
+ m_nApplyInterface = icApplyPixel2Pixel;
+}
+
+/**
+ **************************************************************************
+ * Name: CIccNamedColorCmm::~CIccNamedColorCmm
+ *
+ * Purpose:
+ * Destructor
+ **************************************************************************
+ */
+CIccNamedColorCmm::~CIccNamedColorCmm()
+{
+}
+
+
+/**
+ **************************************************************************
+ * Name: CIccNamedColorCmm::AddXform
+ *
+ * Purpose:
+ * Adds a profile at the end of the Xform list
+ *
+ * Args:
+ * szProfilePath = file name of the profile to be added,
+ * nIntent = rendering intent to be used with the profile,
+ * nInterp = type of interpolation to be used with the profile
+ * pHintManager = hints for creating the xform
+ *
+ * Return:
+ * icCmmStatOk, if the profile was added to the list succesfully
+ **************************************************************************
+ */
+icStatusCMM CIccNamedColorCmm::AddXform(const icChar *szProfilePath,
+ icRenderingIntent nIntent /*=icUnknownIntent*/,
+ icXformInterp nInterp /*icXformInterp*/,
+ icXformLutType nLutType /*=icXformLutColor*/,
+ bool bUseMpeTags /*=true*/,
+ CIccCreateXformHintManager *pHintManager /*=NULL*/)
+{
+ CIccProfile *pProfile = OpenIccProfile(szProfilePath);
+
+ if (!pProfile)
+ return icCmmStatCantOpenProfile;
+
+ icStatusCMM rv = AddXform(pProfile, nIntent, nInterp, nLutType, bUseMpeTags, pHintManager);
+
+ if (rv != icCmmStatOk)
+ delete pProfile;
+
+ return rv;
+}
+
+/**
+ **************************************************************************
+ * Name: CIccNamedColorCmm::AddXform
+ *
+ * Purpose:
+ * Adds a profile at the end of the Xform list
+ *
+ * Args:
+ * pProfile = pointer to the CIccProfile object to be added,
+ * nIntent = rendering intent to be used with the profile,
+ * nInterp = type of interpolation to be used with the profile
+ * nLutType = type of lut to use from the profile
+ * pHintManager = hints for creating the xform
+ *
+ * Return:
+ * icCmmStatOk, if the profile was added to the list succesfully
+ **************************************************************************
+ */
+icStatusCMM CIccNamedColorCmm::AddXform(CIccProfile *pProfile,
+ icRenderingIntent nIntent /*=icUnknownIntent*/,
+ icXformInterp nInterp /*=icInterpLinear*/,
+ icXformLutType nLutType /*=icXformLutColor*/,
+ bool bUseMpeTags /*=true*/,
+ CIccCreateXformHintManager *pHintManager /*=NULL*/)
+{
+ icColorSpaceSignature nSrcSpace, nDstSpace;
+ CIccXformPtr Xform;
+ bool bInput = !m_bLastInput;
+ icStatusCMM rv;
+
+ Xform.ptr = NULL;
+ switch (nLutType) {
+ //Automatically choose which one
+ case icXformLutColor:
+ case icXformLutNamedColor:
+ {
+ CIccTagNamedColor2 *pTag = (CIccTagNamedColor2*)pProfile->FindTag(icSigNamedColor2Tag);
+
+ if (pTag && (pProfile->m_Header.deviceClass==icSigNamedColorClass || nLutType==icXformLutNamedColor)) {
+ if (bInput) {
+ nSrcSpace = icSigNamedData;
+ }
+ else {
+ nSrcSpace = pProfile->m_Header.pcs;
+ }
+
+ if (!m_Xforms->size()) {
+ if (m_nSrcSpace==icSigUnknownData) {
+ m_nSrcSpace = nSrcSpace;
+ }
+ else {
+ nSrcSpace = m_nSrcSpace;
+ }
+ }
+ else {
+ if (m_nLastSpace==icSigUnknownData) {
+ m_nLastSpace = nSrcSpace;
+ }
+ else {
+ nSrcSpace = m_nLastSpace;
+ }
+ }
+
+ if (nSrcSpace==icSigNamedData) {
+ nDstSpace = pProfile->m_Header.pcs;
+ bInput = true;
+ }
+ else {
+ nDstSpace = icSigNamedData;
+ bInput = false;
+ }
+
+ Xform.ptr = CIccXform::Create(pProfile, bInput, nIntent, nInterp, icXformLutNamedColor, bUseMpeTags, pHintManager);
+ if (!Xform.ptr) {
+ return icCmmStatBadXform;
+ }
+ CIccXformNamedColor *pXform = (CIccXformNamedColor *)Xform.ptr;
+ rv = pXform->SetSrcSpace(nSrcSpace);
+ if (rv)
+ return rv;
+
+ rv = pXform->SetDestSpace(nDstSpace);
+ if (rv)
+ return rv;
+ }
+ else {
+ //It isn't named color so make we will use color lut.
+ nLutType = icXformLutColor;
+
+ //Check pProfile if nIntent and input can be found.
+ if (bInput) {
+ nSrcSpace = pProfile->m_Header.colorSpace;
+ nDstSpace = pProfile->m_Header.pcs;
+ }
+ else {
+ if (pProfile->m_Header.deviceClass == icSigLinkClass) {
+ return icCmmStatBadSpaceLink;
+ }
+ if (pProfile->m_Header.deviceClass == icSigAbstractClass) {
+ bInput = true;
+ nIntent = icPerceptual; // Note: icPerceptualIntent = 0
+ }
+ nSrcSpace = pProfile->m_Header.pcs;
+ nDstSpace = pProfile->m_Header.colorSpace;
+ }
+ }
+ }
+ break;
+
+ case icXformLutPreview:
+ nSrcSpace = pProfile->m_Header.pcs;
+ nDstSpace = pProfile->m_Header.pcs;
+ bInput = false;
+ break;
+
+ case icXformLutGamut:
+ nSrcSpace = pProfile->m_Header.pcs;
+ nDstSpace = icSigGamutData;
+ bInput = true;
+ break;
+
+ default:
+ return icCmmStatBadLutType;
+ }
+
+ //Make sure color spaces match with previous xforms
+ if (!m_Xforms->size()) {
+ if (m_nSrcSpace == icSigUnknownData) {
+ m_nLastSpace = nSrcSpace;
+ m_nSrcSpace = nSrcSpace;
+ }
+ else if (!IsCompatSpace(m_nSrcSpace, nSrcSpace)) {
+ return icCmmStatBadSpaceLink;
+ }
+ }
+ else if (!IsCompatSpace(m_nLastSpace, nSrcSpace)) {
+ return icCmmStatBadSpaceLink;
+ }
+
+ //Automatic creation of intent from header/last profile
+ if (nIntent==icUnknownIntent) {
+ if (bInput) {
+ nIntent = (icRenderingIntent)pProfile->m_Header.renderingIntent;
+ }
+ else {
+ nIntent = m_nLastIntent;
+ }
+ if (nIntent == icUnknownIntent)
+ nIntent = icPerceptual;
+ }
+
+ if (!Xform.ptr)
+ Xform.ptr = CIccXform::Create(pProfile, bInput, nIntent, nInterp, nLutType, bUseMpeTags, pHintManager);
+
+ if (!Xform.ptr) {
+ return icCmmStatBadXform;
+ }
+
+ m_nLastSpace = nDstSpace;
+ m_nLastIntent = nIntent;
+ m_bLastInput = bInput;
+
+ m_Xforms->push_back(Xform);
+
+ return icCmmStatOk;
+}
+
+/**
+ **************************************************************************
+ * Name: CIccNamedColorCmm::Begin
+ *
+ * Purpose:
+ * Does the initialization of the Xforms in the list before Apply() is called.
+ * Must be called before Apply().
+ *
+ **************************************************************************
+ */
+ icStatusCMM CIccNamedColorCmm::Begin(bool bAllocNewApply/* =true */)
+{
+ if (m_nDestSpace==icSigUnknownData) {
+ m_nDestSpace = m_nLastSpace;
+ }
+ else if (!IsCompatSpace(m_nDestSpace, m_nLastSpace)) {
+ return icCmmStatBadSpaceLink;
+ }
+
+ if (m_nSrcSpace != icSigNamedData) {
+ if (m_nDestSpace != icSigNamedData) {
+ m_nApplyInterface = icApplyPixel2Pixel;
+ }
+ else {
+ m_nApplyInterface = icApplyPixel2Named;
+ }
+ }
+ else {
+ if (m_nDestSpace != icSigNamedData) {
+ m_nApplyInterface = icApplyNamed2Pixel;
+ }
+ else {
+ m_nApplyInterface = icApplyNamed2Named;
+ }
+ }
+
+ icStatusCMM rv;
+ CIccXformList::iterator i;
+
+ for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
+ rv = i->ptr->Begin();
+
+ if (rv!= icCmmStatOk) {
+ return rv;
+ }
+ }
+
+ if (bAllocNewApply) {
+ m_pApply = GetNewApplyCmm(rv);
+ }
+ else
+ rv = icCmmStatOk;
+
+ return rv;
+}
+
+ /**
+ **************************************************************************
+ * Name: CIccNamedColorCmm::GetNewApply
+ *
+ * Purpose:
+ * Allocates a CIccApplyCmm object that allows one to call apply from
+ * multiple threads.
+ *
+ **************************************************************************
+ */
+ CIccApplyCmm *CIccNamedColorCmm::GetNewApply(icStatusCMM &status)
+ {
+ CIccApplyCmm *pApply = new CIccApplyNamedColorCmm(this);
+
+ CIccXformList::iterator i;
+
+ for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
+ CIccApplyXform *pXform = i->ptr->GetNewApply(status);
+ if (status != icCmmStatOk || !pXform) {
+ delete pApply;
+ return NULL;
+ }
+ pApply->AppendApplyXform(pXform);
+ }
+
+ m_bValid = true;
+
+ status = icCmmStatOk;
+ return pApply;
+}
+
+
+ /**
+ **************************************************************************
+ * Name: CIccApplyNamedColorCmm::Apply
+ *
+ * Purpose:
+ * Does the actual application of the Xforms in the list.
+ *
+ * Args:
+ * DstColorName = Destination string where the result is stored,
+ * SrcPoxel = Source pixel
+ **************************************************************************
+ */
+icStatusCMM CIccNamedColorCmm::Apply(icChar* DstColorName, const icFloatNumber *SrcPixel)
+{
+ return ((CIccApplyNamedColorCmm*)m_pApply)->Apply(DstColorName, SrcPixel);
+}
+
+
+/**
+**************************************************************************
+* Name: CIccApplyNamedColorCmm::Apply
+*
+* Purpose:
+* Does the actual application of the Xforms in the list.
+*
+* Args:
+* DestPixel = Destination pixel where the result is stored,
+* SrcColorName = Source color name which is to be searched.
+**************************************************************************
+*/
+icStatusCMM CIccNamedColorCmm::Apply(icFloatNumber *DstPixel, const icChar *SrcColorName)
+{
+ return ((CIccApplyNamedColorCmm*)m_pApply)->Apply(DstPixel, SrcColorName);
+}
+
+
+/**
+**************************************************************************
+* Name: CIccApplyNamedColorCmm::Apply
+*
+* Purpose:
+* Does the actual application of the Xforms in the list.
+*
+* Args:
+* DstColorName = Destination string where the result is stored,
+* SrcColorName = Source color name which is to be searched.
+**************************************************************************
+*/
+icStatusCMM CIccNamedColorCmm::Apply(icChar* DstColorName, const icChar *SrcColorName)
+{
+ return ((CIccApplyNamedColorCmm*)m_pApply)->Apply(DstColorName, SrcColorName);
+}
+
+
+/**
+ **************************************************************************
+ * Name: CIccNamedColorCmm::SetLastXformDest
+ *
+ * Purpose:
+ * Sets the destination Color space of the last Xform in the list
+ *
+ * Args:
+ * nDestSpace = signature of the color space to be set
+ **************************************************************************
+ */
+icStatusCMM CIccNamedColorCmm::SetLastXformDest(icColorSpaceSignature nDestSpace)
+{
+ int n = (int)m_Xforms->size();
+ CIccXformPtr *pLastXform;
+
+ if (!n)
+ return icCmmStatBadXform;
+
+ pLastXform = &m_Xforms->back();
+
+ if (pLastXform->ptr->GetXformType()==icXformTypeNamedColor) {
+ CIccXformNamedColor *pXform = (CIccXformNamedColor *)pLastXform->ptr;
+ if (pXform->GetSrcSpace() == icSigNamedData &&
+ nDestSpace == icSigNamedData) {
+ return icCmmStatBadSpaceLink;
+ }
+
+ if (nDestSpace != icSigNamedData &&
+ pXform->GetDstSpace() == icSigNamedData) {
+ return icCmmStatBadSpaceLink;
+ }
+
+ return pXform->SetDestSpace(nDestSpace);
+ }
+
+ return icCmmStatBadXform;
+}
+
+
+/**
+****************************************************************************
+* Name: CIccMruCmm::CIccMruCmm
+*
+* Purpose: private constructor - Use Attach to create CIccMruCmm objects
+*****************************************************************************
+*/
+CIccMruCmm::CIccMruCmm()
+{
+ m_pCmm = NULL;
+}
+
+
+/**
+****************************************************************************
+* Name: CIccMruCmm::~CIccMruCmm
+*
+* Purpose: destructor
+*****************************************************************************
+*/
+CIccMruCmm::~CIccMruCmm()
+{
+ if (m_pCmm)
+ delete m_pCmm;
+}
+
+
+/**
+****************************************************************************
+* Name: CIccMruCmm::Attach
+*
+* Purpose: Create a Cmm decorator object that implements a cache of most
+* recently used pixel transformations.
+*
+* Args:
+* pCmm - pointer to cmm object that we are attaching to.
+* nCacheSize - number of most recently used transformations to cache
+*
+* Return:
+* A CIccMruCmm object that represents a cached form of the pCmm passed in.
+* The pCmm will be owned by the returned object.
+*
+* If this function fails the pCmm object will be deleted.
+*****************************************************************************
+*/
+CIccMruCmm* CIccMruCmm::Attach(CIccCmm *pCmm, icUInt8Number nCacheSize/* =4 */)
+{
+ if (!pCmm || !nCacheSize)
+ return NULL;
+
+ if (!pCmm->Valid()) {
+ delete pCmm;
+ return NULL;
+ }
+
+ CIccMruCmm *rv = new CIccMruCmm();
+
+ rv->m_pCmm = pCmm;
+ rv->m_nCacheSize = nCacheSize;
+
+ rv->m_nSrcSpace = pCmm->GetSourceSpace();
+ rv->m_nDestSpace = pCmm->GetDestSpace();
+ rv->m_nLastSpace = pCmm->GetLastSpace();
+ rv->m_nLastIntent = pCmm->GetLastIntent();
+
+ if (rv->Begin()!=icCmmStatOk) {
+ delete rv;
+ return NULL;
+ }
+
+ return rv;
+}
+
+CIccApplyCmm *CIccMruCmm::GetNewApplyCmm(icStatusCMM &status)
+{
+ CIccApplyMruCmm *rv = new CIccApplyMruCmm(this);
+
+ if (!rv) {
+ status = icCmmStatAllocErr;
+ return NULL;
+ }
+
+ if (!rv->Init(m_pCmm, m_nCacheSize)) {
+ delete rv;
+ status = icCmmStatBad;
+ return NULL;
+ }
+
+ return rv;
+}
+
+
+CIccApplyMruCmm::CIccApplyMruCmm(CIccMruCmm *pCmm) : CIccApplyCmm(pCmm)
+{
+ m_cache = NULL;
+
+ m_pixelData = NULL;
+}
+
+/**
+****************************************************************************
+* Name: CIccApplyMruCmm::~CIccApplyMruCmm
+*
+* Purpose: destructor
+*****************************************************************************
+*/
+CIccApplyMruCmm::~CIccApplyMruCmm()
+{
+ if (m_cache)
+ delete [] m_cache;
+
+ if (m_pixelData)
+ free(m_pixelData);
+}
+
+/**
+****************************************************************************
+* Name: CIccApplyMruCmm::Init
+*
+* Purpose: Initialize the object and set up the cache
+*
+* Args:
+* pCmm - pointer to cmm object that we are attaching to.
+* nCacheSize - number of most recently used transformations to cache
+*
+* Return:
+* true if successful
+*****************************************************************************
+*/
+bool CIccApplyMruCmm::Init(CIccCmm *pCachedCmm, icUInt16Number nCacheSize)
+{
+ m_pCachedCmm = pCachedCmm;
+
+ m_nSrcSamples = m_pCmm->GetSourceSamples();
+ m_nSrcSize = m_nSrcSamples * sizeof(icFloatNumber);
+ m_nDstSize = m_pCmm->GetDestSamples() * sizeof(icFloatNumber);
+
+ m_nTotalSamples = m_nSrcSamples + m_pCmm->GetDestSamples();
+
+ m_nNumPixel = 0;
+ m_nCacheSize = nCacheSize;
+
+ m_pFirst = NULL;
+ m_cache = new CIccMruPixel[nCacheSize];
+
+ if (!m_cache)
+ return false;
+
+ m_pixelData = (icFloatNumber*)malloc(nCacheSize * m_nTotalSamples * sizeof(icFloatNumber));
+
+ if (!m_pixelData)
+ return false;
+
+ return true;
+}
+
+/**
+****************************************************************************
+* Name: CIccMruCmm::Apply
+*
+* Purpose: Apply a transformation to a pixel.
+*
+* Args:
+* DstPixel - Location to store pixel results
+* SrcPixel - Location to get pixel values from
+*
+* Return:
+* icCmmStatOk if successful
+*****************************************************************************
+*/
+icStatusCMM CIccApplyMruCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel)
+{
+ CIccMruPixel *ptr, *prev=NULL, *last=NULL;
+ int i;
+ icFloatNumber *pixel;
+
+ for (ptr = m_pFirst, i=0; ptr; ptr=ptr->pNext, i++) {
+ if (!memcmp(SrcPixel, ptr->pPixelData, m_nSrcSize)) {
+ memcpy(DstPixel, &ptr->pPixelData[m_nSrcSamples], m_nDstSize);
+ return icCmmStatOk;
+ }
+ prev = last;
+ last = ptr;
+ }
+
+ //If we get here SrcPixel is not in the cache
+ if (ipPixelData = pixel;
+
+ if (!last) {
+ m_pFirst = ptr;
+ }
+ else {
+
+ last->pNext = ptr;
+ }
+ }
+ else { //Reuse oldest value and put it at the front of the list
+ prev->pNext = NULL;
+ last->pNext = m_pFirst;
+
+ m_pFirst = last;
+ pixel = last->pPixelData;
+ }
+ icFloatNumber *dest = &pixel[m_nSrcSamples];
+
+ memcpy(pixel, SrcPixel, m_nSrcSize);
+
+ m_pCachedCmm->Apply(dest, pixel);
+
+ memcpy(DstPixel, dest, m_nDstSize);
+
+ return icCmmStatOk;
+}
+
+/**
+****************************************************************************
+* Name: CIccMruCmm::Apply
+*
+* Purpose: Apply a transformation to a pixel.
+*
+* Args:
+* DstPixel - Location to store pixel results
+* SrcPixel - Location to get pixel values from
+* nPixels - number of pixels to convert
+*
+* Return:
+* icCmmStatOk if successful
+*****************************************************************************
+*/
+icStatusCMM CIccApplyMruCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels)
+{
+ CIccMruPixel *ptr, *prev=NULL, *last=NULL;
+ int i;
+ icFloatNumber *pixel, *dest;
+ icUInt32Number k;
+
+ for (k=0; kpNext, i++) {
+ if (!memcmp(SrcPixel, ptr->pPixelData, m_nSrcSize)) {
+ memcpy(DstPixel, &ptr->pPixelData[m_nSrcSamples], m_nDstSize);
+ goto next_k;
+ }
+ prev = last;
+ last = ptr;
+ }
+
+ //If we get here SrcPixel is not in the cache
+ if (ipPixelData = pixel;
+
+ if (!last) {
+ m_pFirst = ptr;
+ }
+ else {
+
+ last->pNext = ptr;
+ }
+ }
+ else { //Reuse oldest value and put it at the front of the list
+ prev->pNext = NULL;
+ last->pNext = m_pFirst;
+
+ m_pFirst = last;
+ pixel = last->pPixelData;
+ }
+ dest = &pixel[m_nSrcSamples];
+
+ memcpy(pixel, SrcPixel, m_nSrcSize);
+
+ m_pCachedCmm->Apply(dest, pixel);
+
+ memcpy(DstPixel, dest, m_nDstSize);
+
+next_k:
+ k++;
+ }
+
+ return icCmmStatOk;
+}
+
+#ifdef USESAMPLEICCNAMESPACE
+} //namespace sampleICC
+#endif
diff --git a/library/src/main/cpp/icc/IccCmm.h b/library/src/main/cpp/icc/IccCmm.h
new file mode 100644
index 00000000..4e450ca0
--- /dev/null
+++ b/library/src/main/cpp/icc/IccCmm.h
@@ -0,0 +1,1141 @@
+/** @file
+ File: IccCmm.h
+
+ Contains: Header file for implementation of the CIccCmm class.
+
+ Version: V1
+
+ Copyright: see ICC Software License
+*/
+
+/*
+ * The ICC Software License, Version 0.2
+ *
+ *
+ * Copyright (c) 2003-2015 The International Color Consortium. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. In the absence of prior written permission, the names "ICC" and "The
+ * International Color Consortium" must not be used to imply that the
+ * ICC organization endorses or promotes products derived from this
+ * software.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR
+ * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the The International Color Consortium.
+ *
+ *
+ * Membership in the ICC is encouraged when this software is used for
+ * commercial purposes.
+ *
+ *
+ * For more information on The International Color Consortium, please
+ * see .
+ *
+ *
+ */
+
+//////////////////////////////////////////////////////////////////////
+// HISTORY:
+//
+// -Initial implementation by Max Derhak 5-15-2003
+// -Added support for Monochrome ICC profile apply by Rohit Patil 12-03-2008
+// -Integrate changes for PCS adjustment by George Pawle 12-09-2008
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(_ICCCMM_H)
+#define _ICCCMM_H
+
+#include "IccProfile.h"
+#include "IccTag.h"
+#include "IccUtil.h"
+#include
+#include
+#include
+
+#ifdef USESAMPLEICCNAMESPACE
+namespace sampleICC {
+#endif
+
+/// CMM return status values
+typedef enum {
+ icCmmStatBad = -1,
+ icCmmStatOk = 0,
+ icCmmStatCantOpenProfile = 1,
+ icCmmStatBadSpaceLink = 2,
+ icCmmStatInvalidProfile = 3,
+ icCmmStatBadXform = 4,
+ icCmmStatInvalidLut = 5,
+ icCmmStatProfileMissingTag = 6,
+ icCmmStatColorNotFound = 7,
+ icCmmStatIncorrectApply = 8,
+ icCmmStatBadColorEncoding = 9,
+ icCmmStatAllocErr = 10,
+ icCmmStatBadLutType = 11,
+} icStatusCMM;
+
+/// CMM Interpolation types
+typedef enum {
+ icInterpLinear = 0,
+ icInterpTetrahedral = 1,
+} icXformInterp;
+
+/// CMM Xform LUT types
+typedef enum {
+ icXformLutColor = 0,
+ icXformLutNamedColor = 1,
+ icXformLutPreview = 2,
+ icXformLutGamut = 3,
+} icXformLutType;
+
+#define icPerceptualRefBlackX 0.00336
+#define icPerceptualRefBlackY 0.0034731
+#define icPerceptualRefBlackZ 0.00287
+
+#define icPerceptualRefWhiteX 0.9642
+#define icPerceptualRefWhiteY 1.0000
+#define icPerceptualRefWhiteZ 0.8249
+
+// CMM Xform types
+typedef enum {
+ icXformTypeMatrixTRC = 0,
+ icXformType3DLut = 1,
+ icXformType4DLut = 2,
+ icXformTypeNDLut = 3,
+ icXformTypeNamedColor = 4, //Creator uses icNamedColorXformHint
+ icXformTypeMpe = 5,
+ icXformTypeMonochrome = 6,
+
+ icXformTypeUnknown = 0x7ffffff,
+} icXformType;
+
+/**
+**************************************************************************
+* Type: Class
+*
+* Purpose:
+* Interface for creation of a named xform hint
+**************************************************************************
+*/
+class ICCPROFLIB_API IIccCreateXformHint
+{
+public:
+ virtual const char *GetHintType() const=0;
+};
+
+/**
+**************************************************************************
+* Type: Class
+*
+* Purpose:
+* Manages the named xform hints
+**************************************************************************
+*/
+class ICCPROFLIB_API CIccCreateXformHintManager
+{
+public:
+ CIccCreateXformHintManager() { m_pList = NULL; }
+ ~CIccCreateXformHintManager();
+
+ /// Adds and owns the passed named hint to it's list
+ bool AddHint(IIccCreateXformHint* pHint);
+
+ /// Deletes the object referenced by the passed named hint pointer and removes it from the list
+ bool DeleteHint(IIccCreateXformHint* pHint);
+
+ /// Finds and returns a pointer to the named hint
+ IIccCreateXformHint* GetHint(const char* hintName);
+
+private:
+ // private hint ptr class
+ class IIccCreateXformHintPtr {
+ public:
+ IIccCreateXformHint* ptr;
+ };
+ typedef std::list IIccCreateXformHintList;
+
+ // private members
+ IIccCreateXformHintList* m_pList;
+};
+
+/**
+**************************************************************************
+* Type: Class
+*
+* Purpose:
+* Hint for creation of a named color xform
+**************************************************************************
+*/
+class ICCPROFLIB_API CIccCreateNamedColorXformHint : public IIccCreateXformHint
+{
+public:
+ virtual const char *GetHintType() const {return "CIccCreateNamedColorXformHint";}
+
+ icColorSpaceSignature csPcs;
+ icColorSpaceSignature csDevice;
+};
+
+/**
+**************************************************************************
+* Type: Class
+*
+* Purpose:
+* Interface for calculating adjust PCS factors
+**************************************************************************
+*/
+class CIccXform;
+class ICCPROFLIB_API IIccAdjustPCSXform
+{
+public:
+ virtual ~IIccAdjustPCSXform() {}
+ virtual bool CalcFactors(const CIccProfile* pProfile, const CIccXform* pXfm, icFloatNumber* Scale, icFloatNumber* Offset) const=0;
+};
+
+/**
+**************************************************************************
+* Type: Class
+*
+* Purpose:
+* Hint for calculating adjust PCS factors
+**************************************************************************
+*/
+class ICCPROFLIB_API CIccCreateAdjustPCSXformHint : public IIccCreateXformHint
+{
+public:
+ virtual const char *GetHintType() const {return "CIccCreateAdjustPCSXformHint";}
+ virtual const char *GetAdjustPCSType() const=0;
+ virtual IIccAdjustPCSXform *GetNewAdjustPCSXform() const=0;
+};
+
+//forward reference to CIccXform used by CIccApplyXform
+class CIccApplyXform;
+
+/**
+ **************************************************************************
+ * Type: Class
+ *
+ * Purpose:
+ * This is the base CMM xform object. A general static creation function,
+ * base behavior, and data are defined. The Create() function will assign
+ * a profile to the class. The CIccProfile object will then be owned by the
+ * xform object and later deleted when the IccXform is deleted.
+ **************************************************************************
+ */
+class ICCPROFLIB_API CIccXform
+{
+public:
+ CIccXform();
+ virtual ~CIccXform();
+
+ virtual icXformType GetXformType() const = 0;
+
+ ///Note: The returned CIccXform will own the profile.
+ static CIccXform *Create(CIccProfile *pProfile, bool bInput=true, icRenderingIntent nIntent=icUnknownIntent,
+ icXformInterp nInterp=icInterpLinear, icXformLutType nLutType=icXformLutColor,
+ bool bUseMpeTags=true, CIccCreateXformHintManager *pHintManager=NULL);
+
+ ///Note: Provide an interface to work profile references. The IccProfile is copied, and the copy's ownership
+ ///is turned over to the Returned CIccXform object.
+ static CIccXform *Create(CIccProfile &pProfile, bool bInput=true, icRenderingIntent nIntent=icUnknownIntent,
+ icXformInterp nInterp=icInterpLinear, icXformLutType nLutType=icXformLutColor,
+ bool bUseMpeTags=true, CIccCreateXformHintManager *pHintManager=NULL);
+
+ virtual icStatusCMM Begin();
+
+ virtual CIccApplyXform *GetNewApply(icStatusCMM &status);
+
+ virtual void Apply(CIccApplyXform *pXform, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const = 0;
+
+ //Detach and remove CIccIO object associated with xform's profile. Must call after Begin()
+ virtual bool RemoveIO() { return m_pProfile->Detach(); }
+
+ ///Returns the source color space of the transform
+ virtual icColorSpaceSignature GetSrcSpace() const;
+
+ ///Returns the destination color space of the transform
+ virtual icColorSpaceSignature GetDstSpace() const;
+
+ ///Checks if version 2 PCS is to be used
+ virtual bool UseLegacyPCS() const { return false; }
+ ///Checks if the profile is version 2
+ virtual bool IsVersion2() const { return !m_pProfile || m_pProfile->m_Header.version < icVersionNumberV4; }
+
+ ///Checks if the profile is to be used as input profile
+ bool IsInput() const { return m_bInput; }
+
+ /// The following function is for Overridden create function
+ void SetParams(CIccProfile *pProfile, bool bInput, icRenderingIntent nIntent, icXformInterp nInterp, CIccCreateXformHintManager *pHintManager=NULL);
+
+ /// Use these functions to extract the input/output curves from the xform
+ virtual LPIccCurve* ExtractInputCurves()=0;
+ virtual LPIccCurve* ExtractOutputCurves()=0;
+
+ virtual bool NoClipPCS() const { return false; }
+
+ /// Returns the profile pointer. Profile is still owned by the Xform.
+ const CIccProfile* GetProfile() const { return m_pProfile; }
+
+ /// Returns the rendering intent being used by the Xform
+ icRenderingIntent GetIntent() const { return m_nIntent; }
+
+protected:
+ //Called by derived classes to initialize Base
+
+ const icFloatNumber *CheckSrcAbs(CIccApplyXform *pApply, const icFloatNumber *Pixel) const;
+ void CheckDstAbs(icFloatNumber *Pixel) const;
+ void AdjustPCS(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const;
+
+ virtual bool HasPerceptualHandling() { return true; }
+
+ CIccProfile *m_pProfile;
+ bool m_bInput;
+ icRenderingIntent m_nIntent;
+ icXYZNumber m_MediaXYZ;
+ icXformInterp m_nInterp;
+
+ // track PCS adjustments
+ IIccAdjustPCSXform* m_pAdjustPCS;
+ bool m_bAdjustPCS;
+ icFloatNumber m_PCSScale[3]; // scale and offset for PCS adjustment in XYZ
+ icFloatNumber m_PCSOffset[3];
+};
+
+/**
+ **************************************************************************
+ * Type: Class
+ *
+ * Purpose: Pointer to the Cmm Xform object
+ **************************************************************************
+ */
+class ICCPROFLIB_API CIccXformPtr {
+public:
+ CIccXform *ptr;
+};
+
+
+/**
+ **************************************************************************
+ * Type: List Class
+ *
+ * Purpose: List of CIccXformPtr which is updated on addition of Xforms
+ **************************************************************************
+ */
+typedef std::list CIccXformList;
+
+
+/**
+**************************************************************************
+* Type: Class
+*
+* Purpose: The Apply Cmm Xform object (Allows xforms to have apply time data)
+**************************************************************************
+*/
+class ICCPROFLIB_API CIccApplyXform
+{
+ friend class CIccXform;
+public:
+ virtual ~CIccApplyXform();
+ virtual icXformType GetXformType() const { return icXformTypeUnknown; }
+
+ void __inline Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) { m_pXform->Apply(this, DstPixel, SrcPixel); }
+
+ const CIccXform *GetXform() { return m_pXform; }
+
+protected:
+ icFloatNumber m_AbsLab[3];
+
+ CIccApplyXform(CIccXform *pXform);
+
+ const CIccXform *m_pXform;
+};
+
+/**
+**************************************************************************
+* Type: Class
+*
+* Purpose: Pointer to the Apply Cmm Xform object
+**************************************************************************
+*/
+class ICCPROFLIB_API CIccApplyXformPtr {
+public:
+ CIccApplyXform *ptr;
+};
+
+
+/**
+**************************************************************************
+* Type: List Class
+*
+* Purpose: List of CIccApplyXformPtr which is updated on addition of Apply Xforms
+**************************************************************************
+*/
+typedef std::list CIccApplyXformList;
+
+/**
+**************************************************************************
+* Type: Class
+*
+* Purpose: This is the general Monochrome Xform (uses a grayTRCTag)
+*
+**************************************************************************
+*/
+class ICCPROFLIB_API CIccXformMonochrome : public CIccXform
+{
+public:
+ CIccXformMonochrome();
+ virtual ~CIccXformMonochrome();
+
+ virtual icXformType GetXformType() const { return icXformTypeMonochrome; }
+
+ virtual icStatusCMM Begin();
+ virtual void Apply(CIccApplyXform *pApplyXform, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const;
+
+ virtual LPIccCurve* ExtractInputCurves();
+ virtual LPIccCurve* ExtractOutputCurves();
+
+protected:
+
+ virtual bool HasPerceptualHandling() { return false; }
+
+ CIccCurve *m_Curve;
+ CIccCurve *GetCurve(icSignature sig) const;
+ CIccCurve *GetInvCurve(icSignature sig) const;
+
+ bool m_bFreeCurve;
+ /// used only when applying the xform
+ LPIccCurve m_ApplyCurvePtr;
+};
+
+/**
+ **************************************************************************
+ * Type: Class
+ *
+ * Purpose: This is the general Matrix-TRC Xform
+ *
+ **************************************************************************
+ */
+class ICCPROFLIB_API CIccXformMatrixTRC : public CIccXform
+{
+public:
+ CIccXformMatrixTRC();
+ virtual ~CIccXformMatrixTRC();
+
+ virtual icXformType GetXformType() const { return icXformTypeMatrixTRC; }
+
+ virtual icStatusCMM Begin();
+ virtual void Apply(CIccApplyXform *pApplyXform, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const;
+
+ virtual LPIccCurve* ExtractInputCurves();
+ virtual LPIccCurve* ExtractOutputCurves();
+
+protected:
+
+ virtual bool HasPerceptualHandling() { return false; }
+
+ icFloatNumber m_e[9];
+ CIccCurve *m_Curve[3];
+ CIccCurve *GetCurve(icSignature sig) const;
+ CIccCurve *GetInvCurve(icSignature sig) const;
+
+ CIccTagXYZ *GetColumn(icSignature sig) const;
+ bool m_bFreeCurve;
+ /// used only when applying the xform
+ const LPIccCurve* m_ApplyCurvePtr;
+};
+
+
+/**
+ **************************************************************************
+ * Type: Class
+ *
+ * Purpose: This is the general 3D-LUT Xform
+ *
+ **************************************************************************
+ */
+class ICCPROFLIB_API CIccXform3DLut : public CIccXform
+{
+public:
+ CIccXform3DLut(CIccTag *pTag);
+ virtual ~CIccXform3DLut();
+
+ virtual icXformType GetXformType() const { return icXformType3DLut; }
+
+ virtual icStatusCMM Begin();
+ virtual void Apply(CIccApplyXform *pApplyXform, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const;
+
+ virtual bool UseLegacyPCS() const { return m_pTag->UseLegacyPCS(); }
+
+ virtual LPIccCurve* ExtractInputCurves();
+ virtual LPIccCurve* ExtractOutputCurves();
+protected:
+
+ const CIccMBB *m_pTag;
+
+ /// Pointers to data in m_pTag, used only for applying the xform
+ const LPIccCurve* m_ApplyCurvePtrA;
+ const LPIccCurve* m_ApplyCurvePtrB;
+ const LPIccCurve* m_ApplyCurvePtrM;
+ const CIccMatrix* m_ApplyMatrixPtr;
+};
+
+
+/**
+ **************************************************************************
+ * Type: Class
+ *
+ * Purpose: This is the general 4D-LUT Xform
+ *
+ **************************************************************************
+ */
+class ICCPROFLIB_API CIccXform4DLut : public CIccXform
+{
+public:
+ CIccXform4DLut(CIccTag *pTag);
+ virtual ~CIccXform4DLut();
+
+ virtual icXformType GetXformType() const { return icXformType4DLut; }
+
+ virtual icStatusCMM Begin();
+ virtual void Apply(CIccApplyXform *pApplyXform, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const;
+
+ virtual bool UseLegacyPCS() const { return m_pTag->UseLegacyPCS(); }
+
+ virtual LPIccCurve* ExtractInputCurves();
+ virtual LPIccCurve* ExtractOutputCurves();
+protected:
+ const CIccMBB *m_pTag;
+
+ /// Pointers to data in m_pTag, used only for applying the xform
+ const LPIccCurve* m_ApplyCurvePtrA;
+ const LPIccCurve* m_ApplyCurvePtrB;
+ const LPIccCurve* m_ApplyCurvePtrM;
+ const CIccMatrix* m_ApplyMatrixPtr;
+};
+
+
+/**
+ **************************************************************************
+ * Type: Class
+ *
+ * Purpose: This is the general ND-LUT Xform
+ *
+ **************************************************************************
+ */
+class ICCPROFLIB_API CIccXformNDLut : public CIccXform
+{
+public:
+ CIccXformNDLut(CIccTag *pTag);
+ virtual ~CIccXformNDLut();
+
+ virtual icXformType GetXformType() const { return icXformTypeNDLut; }
+
+ virtual icStatusCMM Begin();
+ virtual void Apply(CIccApplyXform *pApplyXform, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const;
+
+ virtual bool UseLegacyPCS() const { return m_pTag->UseLegacyPCS(); }
+
+ virtual LPIccCurve* ExtractInputCurves();
+ virtual LPIccCurve* ExtractOutputCurves();
+protected:
+ const CIccMBB *m_pTag;
+ int m_nNumInput;
+
+ /// Pointers to data in m_pTag, used only for applying the xform
+ const LPIccCurve* m_ApplyCurvePtrA;
+ const LPIccCurve* m_ApplyCurvePtrB;
+ const LPIccCurve* m_ApplyCurvePtrM;
+ const CIccMatrix* m_ApplyMatrixPtr;
+};
+
+
+
+/**
+ **************************************************************************
+ * Type: Enum
+ *
+ * Purpose: Defines the interface to be used when applying Named Color
+ * Profiles.
+ *
+ **************************************************************************
+ */
+typedef enum {
+ icApplyPixel2Pixel = 0,
+ icApplyNamed2Pixel = 1,
+ icApplyPixel2Named = 2,
+ icApplyNamed2Named = 3,
+} icApplyInterface;
+
+
+
+/**
+ **************************************************************************
+ * Type: Class
+ *
+ * Purpose: This is the general Xform for Named Color Profiles.
+ *
+ **************************************************************************
+ */
+class ICCPROFLIB_API CIccXformNamedColor : public CIccXform
+{
+public:
+ CIccXformNamedColor(CIccTag *pTag, icColorSpaceSignature csPCS, icColorSpaceSignature csDevice);
+ virtual ~CIccXformNamedColor();
+
+ virtual icXformType GetXformType() const { return icXformTypeNamedColor; }
+
+ virtual icStatusCMM Begin();
+
+ ///Returns the type of interface that will be applied
+ icApplyInterface GetInterface() const {return m_nApplyInterface;}
+
+ virtual void Apply(CIccApplyXform *pApplyXform, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const {}
+
+ icStatusCMM Apply(CIccApplyXform *pApplyXform, icChar *DstColorName, const icFloatNumber *SrcPixel) const;
+ icStatusCMM Apply(CIccApplyXform *pApplyXform, icFloatNumber *DstPixel, const icChar *SrcColorName) const;
+
+ virtual bool UseLegacyPCS() const { return m_pTag->UseLegacyPCS(); }
+
+ icStatusCMM SetSrcSpace(icColorSpaceSignature nSrcSpace);
+ icStatusCMM SetDestSpace(icColorSpaceSignature nDestSpace);
+
+ ///Returns the source color space of the transform
+ icColorSpaceSignature GetSrcSpace() const { return m_nSrcSpace; }
+ ///Returns the destination color space of the transform
+ icColorSpaceSignature GetDstSpace() const { return m_nDestSpace; }
+
+ ///Checks if the source space of the transform is PCS
+ bool IsSrcPCS() const {return m_nSrcSpace == m_pTag->GetPCS();}
+ ///Checks if the destination space of the transform is PCS
+ bool IsDestPCS() const {return m_nDestSpace == m_pTag->GetPCS();}
+
+
+ virtual LPIccCurve* ExtractInputCurves() {return NULL;}
+ virtual LPIccCurve* ExtractOutputCurves() {return NULL;}
+
+protected:
+
+ virtual bool HasPerceptualHandling() { return false; }
+
+ CIccTagNamedColor2 *m_pTag;
+ icApplyInterface m_nApplyInterface;
+ icColorSpaceSignature m_nSrcSpace;
+ icColorSpaceSignature m_nDestSpace;
+};
+
+
+/**
+**************************************************************************
+* Type: Class
+*
+* Purpose: This is the general Xform for Multi Processing Elements.
+*
+**************************************************************************
+*/
+class ICCPROFLIB_API CIccXformMpe : public CIccXform
+{
+public:
+ CIccXformMpe(CIccTag *pTag);
+ virtual ~CIccXformMpe();
+
+ virtual icXformType GetXformType() const { return icXformTypeMpe; }
+
+ ///Note: The returned CIccXform will own the profile.
+ static CIccXform *Create(CIccProfile *pProfile, bool bInput=true, icRenderingIntent nIntent=icUnknownIntent,
+ icXformInterp nInterp=icInterpLinear, icXformLutType nLutType=icXformLutColor, CIccCreateXformHintManager *pHintManager=NULL);
+
+ virtual icStatusCMM Begin();
+
+ virtual CIccApplyXform *GetNewApply(icStatusCMM &status);
+ virtual void Apply(CIccApplyXform *pApplyXform, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const;
+
+ virtual bool UseLegacyPCS() const { return false; }
+ virtual LPIccCurve* ExtractInputCurves() {return NULL;}
+ virtual LPIccCurve* ExtractOutputCurves() {return NULL;}
+
+ virtual bool NoClipPCS() const { return true; }
+
+protected:
+ CIccTagMultiProcessElement *m_pTag;
+ bool m_bUsingAcs;
+};
+
+/**
+**************************************************************************
+* Type: Class
+*
+* Purpose: The Apply general MPE Xform object (Allows xforms to have apply time data)
+**************************************************************************
+*/
+class ICCPROFLIB_API CIccApplyXformMpe : public CIccApplyXform
+{
+ friend class CIccXformMpe;
+public:
+ virtual ~CIccApplyXformMpe();
+ virtual icXformType GetXformType() const { return icXformTypeMpe; }
+
+protected:
+ CIccApplyXformMpe(CIccXformMpe *pXform);
+
+ CIccApplyTagMpe *m_pApply;
+};
+
+/**
+ **************************************************************************
+ * Type: Class
+ *
+ * Purpose: Independant PCS class to do PCS based calculations.
+ * This is a class for managing PCS colorspace transformations. There
+ * are two important categories V2 <-> V4, and Lab <-> XYZ.
+ *
+ **************************************************************************
+ */
+class ICCPROFLIB_API CIccPCS
+{
+public:
+ CIccPCS();
+ virtual ~CIccPCS() {}
+
+ void Reset(icColorSpaceSignature StartSpace, bool bUseLegacyPCS = false);
+
+ virtual const icFloatNumber *Check(const icFloatNumber *SrcPixel, const CIccXform *pXform);
+ void CheckLast(icFloatNumber *SrcPixel, icColorSpaceSignature Space, bool bNoClip=false);
+
+ static void LabToXyz(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip=false);
+ static void XyzToLab(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip=false);
+ static void Lab2ToXyz(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip=false);
+ static void XyzToLab2(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip=false);
+ static icFloatNumber NegClip(icFloatNumber v);
+ static icFloatNumber UnitClip(icFloatNumber v);
+
+ static void Lab2ToLab4(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoclip=false);
+ static void Lab4ToLab2(icFloatNumber *Dst, const icFloatNumber *Src);
+protected:
+
+ bool m_bIsV2Lab;
+ icColorSpaceSignature m_Space;
+
+ icFloatNumber m_Convert[3];
+};
+
+/**
+ **************************************************************************
+ Color data passed to/from the CMM is encoded as floating point numbers ranging from 0.0 to 1.0
+ Often data is encoded using other ranges. The icFloatColorEncoding enum is used by the
+ ToInternalEncoding() and FromInternalEncoding() functions to convert to/from the internal
+ encoding. The valid encoding transforms for the following color space signatures are given
+ below.
+
+ 'CMYK', 'RGB ', 'GRAY', 'CMY ', 'Luv ', 'YCbr', 'Yxy ', 'HSV ', 'HLS ', 'gamt'
+ icEncodePercent: 0.0 <= value <= 100.0
+ icEncodeFloat: 0.0 <= value <= 1.0
+ icEncode8Bit: 0.0 <= value <= 255
+ icEncode16Bit: 0.0 <= value <= 65535
+ icEncode16BitV2: 0.0 <= value <= 65535
+
+ 'XCLR'
+ icEncodeValue: (if X>=3) 0.0 <= L <= 100.0; -128.0 <= a,b <= 127.0 others 0.0 <= value <= 1.0
+ icEncodePercent: 0.0 <= value <= 100.0
+ icEncodeFloat: 0.0 <= value <= 1.0
+ icEncode8Bit: 0.0 <= value <= 255
+ icEncode16Bit: 0.0 <= value <= 65535
+ icEncode16BitV2: 0.0 <= value <= 65535
+
+ 'Lab '
+ icEncodeValue: 0.0 <= L <= 100.0; -128.0 <= a,b <= 127.0
+ icEncodeFloat: 0.0 <= L,a,b <= 1.0 - ICC PCS encoding (See ICC Specification)
+ icEncode8BIt: ICC 8 bit Lab Encoding - See ICC Specification
+ icEncode16Bit: ICC 16 bit V4 Lab Encoding - See ICC Specification
+ icEncode16BitV2: ICC 16 bit V2 Lab Encoding - See ICC Specification
+
+ 'XYZ '
+ icEncodeValue: 0.0 <= X,Y,Z < 1.999969482421875
+ icEncodePercent: 0.0 <= X,Y,Z < 199.9969482421875
+ icEncodeFloat: 0.0 <= L,a,b <= 1.0 - ICC PCS encoding (See ICC Specification
+ icEncode16Bit: ICC 16 bit XYZ Encoding - (icU1Fixed15) See ICC Specification
+ icEncode16BitV2: ICC 16 bit XYZ Encoding - (icU1Fixed15) See ICC Specification
+ **************************************************************************
+*/
+
+typedef enum
+{
+ icEncodeValue=0,
+ icEncodePercent,
+ icEncodeFloat,
+ icEncode8Bit,
+ icEncode16Bit,
+ icEncode16BitV2,
+ icEncodeUnknown,
+} icFloatColorEncoding;
+
+//Forward Reference of CIccCmm for CIccCmmApply
+class CIccCmm;
+
+/**
+**************************************************************************
+* Type: Class
+*
+* Purpose: Defines a class that provides and interface for applying pixel
+* transformations through a CMM. Multiply CIccCmmApply objects can use
+* a single CIccCmm Object.
+*
+**************************************************************************
+*/
+class ICCPROFLIB_API CIccApplyCmm
+{
+ friend class CIccCmm;
+public:
+ virtual ~CIccApplyCmm();
+
+ virtual icStatusCMM Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel);
+
+ //Make sure that when DstPixel==SrcPixel the sizeof DstPixel is less than size of SrcPixel
+ virtual icStatusCMM Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels);
+
+ void AppendApplyXform(CIccApplyXform *pApplyXform);
+
+ CIccCmm *GetCmm() { return m_pCmm; }
+
+protected:
+ CIccApplyCmm(CIccCmm *pCmm);
+
+ CIccApplyXformList *m_Xforms;
+ CIccCmm *m_pCmm;
+
+ CIccPCS *m_pPCS;
+};
+
+/**
+ **************************************************************************
+ * Type: Class
+ *
+ * Purpose: Defines a class that allows one or more profiles to be applied
+ * in order that they are Added.
+ *
+ **************************************************************************
+ */
+class ICCPROFLIB_API CIccCmm
+{
+ friend class CIccApplyCmm;
+public:
+ CIccCmm(icColorSpaceSignature nSrcSpace=icSigUnknownData,
+ icColorSpaceSignature nDestSpace=icSigUnknownData,
+ bool bFirstInput=true);
+ virtual ~CIccCmm();
+
+ virtual CIccPCS *GetPCS() { return new CIccPCS(); }
+
+ ///Must make at least one call to some form of AddXform() before calling Begin()
+ virtual icStatusCMM AddXform(const icChar *szProfilePath, icRenderingIntent nIntent=icUnknownIntent,
+ icXformInterp nInterp=icInterpLinear, icXformLutType nLutType=icXformLutColor,
+ bool bUseMpeTags=true, CIccCreateXformHintManager *pHintManager=NULL);
+ virtual icStatusCMM AddXform(icUInt8Number *pProfileMem, icUInt32Number nProfileLen,
+ icRenderingIntent nIntent=icUnknownIntent, icXformInterp nInterp=icInterpLinear,
+ icXformLutType nLutType=icXformLutColor, bool bUseMpeTags=true,
+ CIccCreateXformHintManager *pHintManager=NULL);
+ virtual icStatusCMM AddXform(CIccProfile *pProfile, icRenderingIntent nIntent=icUnknownIntent,
+ icXformInterp nInterp=icInterpLinear, icXformLutType nLutType=icXformLutColor,
+ bool bUseMpeTags=true, CIccCreateXformHintManager *pHintManager=NULL); //Note: profile will be owned by the CMM
+ virtual icStatusCMM AddXform(CIccProfile &Profile, icRenderingIntent nIntent=icUnknownIntent,
+ icXformInterp nInterp=icInterpLinear, icXformLutType nLutType=icXformLutColor,
+ bool bUseMpeTags=true, CIccCreateXformHintManager *pHintManager=NULL); //Note the profile will be copied
+
+ //The Begin function should be called before Apply or GetNewApplyCmm()
+ virtual icStatusCMM Begin(bool bAllocNewApply=true);
+
+ //Get an additional Apply cmm object to apply pixels with. The Apply object should be deleted by the caller.
+ virtual CIccApplyCmm *GetNewApplyCmm(icStatusCMM &status);
+
+ virtual CIccApplyCmm *GetApply() { return m_pApply; }
+
+ //The following apply functions should only be called if using Begin(true);
+ virtual icStatusCMM Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel);
+ virtual icStatusCMM Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels);
+
+ //Call to Detach and remove all pending IO objects attached to the profiles used by the CMM. Should be called only after Begin()
+ virtual icStatusCMM RemoveAllIO();
+
+ ///Returns the number of profiles/transforms added
+ virtual icUInt32Number GetNumXforms() const;
+
+ ///Returns the source color space
+ icColorSpaceSignature GetSourceSpace() const { return m_nSrcSpace; }
+ ///Returns the destination color space
+ icColorSpaceSignature GetDestSpace() const { return m_nDestSpace; }
+ ///Returns the color space of the last profile added
+ icColorSpaceSignature GetLastSpace() const { return m_nLastSpace; }
+ ///Returns the rendering intent of the last profile added
+ icRenderingIntent GetLastIntent() const { return m_nLastIntent; }
+
+ ///Returns the number of samples in the source color space
+ icUInt16Number GetSourceSamples() const {return (icUInt16Number)icGetSpaceSamples(m_nSrcSpace);}
+ ///Returns the number of samples in the destination color space
+ icUInt16Number GetDestSamples() const {return (icUInt16Number)icGetSpaceSamples(m_nDestSpace);}
+
+ ///Checks if this is a valid CMM object
+ bool Valid() const { return m_bValid; }
+
+ //Function to convert check if Internal representation of 'gamt' color is in gamut.
+ static bool IsInGamut(icFloatNumber *pData);
+
+ ///Functions for converting to Internal representation of pixel colors
+ static icStatusCMM ToInternalEncoding(icColorSpaceSignature nSpace, icFloatColorEncoding nEncode,
+ icFloatNumber *pInternal, const icFloatNumber *pData, bool bClip=true);
+ static icStatusCMM ToInternalEncoding(icColorSpaceSignature nSpace, icFloatNumber *pInternal,
+ const icUInt8Number *pData);
+ static icStatusCMM ToInternalEncoding(icColorSpaceSignature nSpace, icFloatNumber *pInternal,
+ const icUInt16Number *pData);
+ icStatusCMM ToInternalEncoding(icFloatNumber *pInternal, const icUInt8Number *pData) {return ToInternalEncoding(m_nSrcSpace, pInternal, pData);}
+ icStatusCMM ToInternalEncoding(icFloatNumber *pInternal, const icUInt16Number *pData) {return ToInternalEncoding(m_nSrcSpace, pInternal, pData);}
+
+
+ ///Functions for converting from Internal representation of pixel colors
+ static icStatusCMM FromInternalEncoding(icColorSpaceSignature nSpace, icFloatColorEncoding nEncode,
+ icFloatNumber *pData, const icFloatNumber *pInternal, bool bClip=true);
+ static icStatusCMM FromInternalEncoding(icColorSpaceSignature nSpace, icUInt8Number *pData,
+ const icFloatNumber *pInternal);
+ static icStatusCMM FromInternalEncoding(icColorSpaceSignature nSpace, icUInt16Number *pData,
+ const icFloatNumber *pInternal);
+ icStatusCMM FromInternalEncoding(icUInt8Number *pData, icFloatNumber *pInternal) {return FromInternalEncoding(m_nDestSpace, pData, pInternal);}
+ icStatusCMM FromInternalEncoding(icUInt16Number *pData, icFloatNumber *pInternal) {return FromInternalEncoding(m_nDestSpace, pData, pInternal);}
+
+ static const icChar *GetFloatColorEncoding(icFloatColorEncoding val);
+ static icFloatColorEncoding GetFloatColorEncoding(const icChar* val);
+
+ virtual icColorSpaceSignature GetFirstXformSource();
+ virtual icColorSpaceSignature GetLastXformDest();
+
+protected:
+
+ CIccApplyCmm *m_pApply;
+
+ bool m_bValid;
+
+ bool m_bLastInput;
+ icColorSpaceSignature m_nSrcSpace;
+ icColorSpaceSignature m_nDestSpace;
+
+ icColorSpaceSignature m_nLastSpace;
+ icRenderingIntent m_nLastIntent;
+
+ CIccXformList *m_Xforms;
+};
+
+//Forward Class for CIccApplyNamedColorCmm
+class CIccNamedColorCmm;
+/**
+**************************************************************************
+* Type: Class
+*
+* Purpose: Defines a class that provides and interface for applying pixel
+* transformations through a Named Color CMM. Multiply CIccApplyNamedColorCmm
+* objects can refer to a single CIccNamedColorCmm Object.
+*
+**************************************************************************
+*/
+class ICCPROFLIB_API CIccApplyNamedColorCmm : public CIccApplyCmm
+{
+ friend class CIccNamedColorCmm;
+public:
+ virtual ~CIccApplyNamedColorCmm();
+
+ virtual icStatusCMM Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel);
+
+ //Make sure that when DstPixel==SrcPixel the sizeof DstPixel is less than size of SrcPixel
+ virtual icStatusCMM Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels);
+
+ ///Define 4 apply interfaces that are used depending upon the source and destination xforms
+ virtual icStatusCMM Apply(icChar* DstColorName, const icFloatNumber *SrcPixel);
+ virtual icStatusCMM Apply(icFloatNumber *DstPixel, const icChar *SrcColorName);
+ virtual icStatusCMM Apply(icChar* DstColorName, const icChar *SrcColorName);
+
+protected:
+ CIccApplyNamedColorCmm(CIccNamedColorCmm *pCmm);
+};
+
+/**
+ **************************************************************************
+ * Type: Class
+ *
+ * Purpose: A Slower Named Color Profile compatible CMM
+ *
+ **************************************************************************
+ */
+class ICCPROFLIB_API CIccNamedColorCmm : public CIccCmm
+{
+ friend class CIccApplyNamedColorCmm;
+public:
+ ///nSrcSpace cannot be icSigUnknownData if first profile is named color
+ CIccNamedColorCmm(icColorSpaceSignature nSrcSpace=icSigUnknownData,
+ icColorSpaceSignature nDestSpace=icSigUnknownData,
+ bool bFirstInput=true);
+ virtual ~CIccNamedColorCmm();
+
+ ///Must make at least one call to some form of AddXform() before calling Begin()
+ virtual icStatusCMM AddXform(const icChar *szProfilePath, icRenderingIntent nIntent=icUnknownIntent,
+ icXformInterp nInterp=icInterpLinear, icXformLutType nLutType=icXformLutColor,
+ bool bUseMpeTags=true, CIccCreateXformHintManager *pHintManager=NULL);
+ virtual icStatusCMM AddXform(CIccProfile *pProfile, icRenderingIntent nIntent=icUnknownIntent,
+ icXformInterp nInterp=icInterpLinear, icXformLutType nLutType=icXformLutColor,
+ bool buseMpeTags=true, CIccCreateXformHintManager *pHintManager=NULL); //Note: profile will be owned by the CMM
+
+ ///Must be called before calling Apply() or GetNewApply()
+ //The Begin function should be called before Apply or GetNewApplyCmm()
+ virtual icStatusCMM Begin(bool bAllocNewApply=true);
+
+ virtual CIccApplyCmm *GetNewApply(icStatusCMM &status);
+
+
+ //The following apply functions should only be called if using Begin(true);
+ icStatusCMM Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) { return CIccCmm::Apply(DstPixel, SrcPixel); }
+ icStatusCMM Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels) { return CIccCmm::Apply(DstPixel, SrcPixel, nPixels); }
+ virtual icStatusCMM Apply(icFloatNumber *DstPixel, const icChar *SrcColorName);
+ virtual icStatusCMM Apply(icChar* DstColorName, const icFloatNumber *SrcPixel);
+ virtual icStatusCMM Apply(icChar* DstColorName, const icChar *SrcColorName);
+
+ ///Returns the type of interface that will be applied
+ icApplyInterface GetInterface() const {return m_nApplyInterface;}
+
+ icStatusCMM SetLastXformDest(icColorSpaceSignature nDestSpace);
+
+protected:
+ icApplyInterface m_nApplyInterface;
+};
+
+
+class ICCPROFLIB_API CIccMruPixel
+{
+public:
+ CIccMruPixel() { pPixelData = NULL; pNext = NULL; }
+
+ icFloatNumber *pPixelData;
+ CIccMruPixel *pNext;
+};
+
+//Forward Class for CIccApplyNamedColorCmm
+class CIccMruCmm;
+/**
+**************************************************************************
+* Type: Class
+*
+* Purpose: Defines a class that provides and interface for applying pixel
+* transformations through a CMM. Multiply CIccCmmApply objects can use
+* a single CIccCmm Object.
+*
+**************************************************************************
+*/
+class ICCPROFLIB_API CIccApplyMruCmm : public CIccApplyCmm
+{
+ friend class CIccMruCmm;
+public:
+ virtual ~CIccApplyMruCmm();
+
+ virtual icStatusCMM Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel);
+
+ //Make sure that when DstPixel==SrcPixel the sizeof DstPixel is greater than size of SrcPixel
+ virtual icStatusCMM Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels);
+
+protected:
+ CIccApplyMruCmm(CIccMruCmm *pCmm);
+
+ bool Init(CIccCmm *pCachedCmm, icUInt16Number nCacheSize);
+
+ CIccCmm *m_pCachedCmm;
+
+ icUInt16Number m_nCacheSize;
+
+ icFloatNumber *m_pixelData;
+
+ CIccMruPixel *m_pFirst;
+ CIccMruPixel *m_cache;
+
+ icUInt16Number m_nNumPixel;
+
+ icUInt32Number m_nTotalSamples;
+ icUInt32Number m_nSrcSamples;
+
+ icUInt32Number m_nSrcSize;
+ icUInt32Number m_nDstSize;
+
+};
+
+/**
+**************************************************************************
+* Type: Class
+*
+* Purpose: A CMM decorator class that provides limited caching of results
+*
+**************************************************************************
+*/
+class ICCPROFLIB_API CIccMruCmm : public CIccCmm
+{
+ friend class CIccApplyMruCmm;
+private:
+ CIccMruCmm();
+public:
+ virtual ~CIccMruCmm();
+
+ //This is the function used to create a new CIccMruCmm. The pCmm must be valid and its Begin() already called.
+ static CIccMruCmm* Attach(CIccCmm *pCmm, icUInt8Number nCacheSize=6); //The returned object will own pCmm, and pCmm is deleted on failure.
+
+ //override AddXform/Begin functions to return bad status.
+ virtual icStatusCMM AddXform(const icChar *szProfilePath, icRenderingIntent nIntent=icUnknownIntent,
+ icXformInterp nInterp=icInterpLinear, icXformLutType nLutType=icXformLutColor,
+ bool bUseMpeTags=true, CIccCreateXformHintManager *pHintManager=NULL) { return icCmmStatBad; }
+ virtual icStatusCMM AddXform(icUInt8Number *pProfileMem, icUInt32Number nProfileLen,
+ icRenderingIntent nIntent=icUnknownIntent, icXformInterp nInterp=icInterpLinear,
+ icXformLutType nLutType=icXformLutColor, bool bUseMpeTags=true, CIccCreateXformHintManager *pHintManager=NULL) { return icCmmStatBad; }
+ virtual icStatusCMM AddXform(CIccProfile *pProfile, icRenderingIntent nIntent=icUnknownIntent,
+ icXformInterp nInterp=icInterpLinear, icXformLutType nLutType=icXformLutColor,
+ bool bUseMpeTags=true, CIccCreateXformHintManager *pHintManager=NULL) { return icCmmStatBad; }
+ virtual icStatusCMM AddXform(CIccProfile &Profile, icRenderingIntent nIntent=icUnknownIntent,
+ icXformInterp nInterp=icInterpLinear, icXformLutType nLutType=icXformLutColor,
+ bool bUseMpeTags=true, CIccCreateXformHintManager *pHintManager=NULL) { return icCmmStatBad; }
+
+ virtual CIccApplyCmm *GetNewApplyCmm(icStatusCMM &status);
+
+ //Forward calls to attached CMM
+ virtual icStatusCMM RemoveAllIO() { return m_pCmm->RemoveAllIO(); }
+ virtual CIccPCS *GetPCS() { return m_pCmm->GetPCS(); }
+ virtual icUInt32Number GetNumXforms() const { return m_pCmm->GetNumXforms(); }
+
+ virtual icColorSpaceSignature GetFirstXformSource() { return m_pCmm->GetFirstXformSource(); }
+ virtual icColorSpaceSignature GetLastXformDest() { return m_pCmm->GetLastXformDest(); }
+
+protected:
+ CIccCmm *m_pCmm;
+ icUInt16Number m_nCacheSize;
+
+};
+
+#ifdef USESAMPLEICCNAMESPACE
+}; //namespace sampleICC
+#endif
+
+#endif // !defined(_ICCCMM_H)
diff --git a/library/src/main/cpp/icc/IccConvertUTF.cpp b/library/src/main/cpp/icc/IccConvertUTF.cpp
new file mode 100644
index 00000000..f796dafa
--- /dev/null
+++ b/library/src/main/cpp/icc/IccConvertUTF.cpp
@@ -0,0 +1,541 @@
+/*
+* Copyright 2001-2004 Unicode, Inc.
+*
+* Disclaimer
+*
+* This source code is provided as is by Unicode, Inc. No claims are
+* made as to fitness for any particular purpose. No warranties of any
+* kind are expressed or implied. The recipient agrees to determine
+* applicability of information provided. If this file has been
+* purchased on magnetic or optical media from Unicode, Inc., the
+* sole remedy for any claim will be exchange of defective media
+* within 90 days of receipt.
+*
+* Limitations on Rights to Redistribute This Code
+*
+* Unicode, Inc. hereby grants the right to freely use the information
+* supplied in this file in the creation of products supporting the
+* Unicode Standard, and to make copies of this file in any form
+* for internal or external distribution as long as this notice
+* remains attached.
+*/
+
+/* ---------------------------------------------------------------------
+
+Conversions between UTF32, UTF-16, and UTF-8. Source code file.
+Author: Mark E. Davis, 1994.
+Rev History: Rick McGowan, fixes & updates May 2001.
+Sept 2001: fixed const & error conditions per
+mods suggested by S. Parent & A. Lillich.
+June 2002: Tim Dodd added detection and handling of incomplete
+source sequences, enhanced error detection, added casts
+to eliminate compiler warnings.
+July 2003: slight mods to back out aggressive FFFE detection.
+Jan 2004: updated switches in from-UTF8 conversions.
+Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
+
+See the header file "icConvertUTF.h" for complete documentation.
+
+------------------------------------------------------------------------ */
+
+
+#include "IccConvertUTF.h"
+#ifdef CVTUTF_DEBUG
+#include
+#endif
+
+static const int halfShift = 10; /* used for shifting by 10 bits */
+
+static const UTF32 halfBase = 0x0010000UL;
+static const UTF32 halfMask = 0x3FFUL;
+
+#define UNI_SUR_HIGH_START (UTF32)0xD800
+#define UNI_SUR_HIGH_END (UTF32)0xDBFF
+#define UNI_SUR_LOW_START (UTF32)0xDC00
+#define UNI_SUR_LOW_END (UTF32)0xDFFF
+#define false 0
+#define true 1
+
+/* --------------------------------------------------------------------- */
+
+icUtfConversionResult icConvertUTF32toUTF16 (const UTF32** sourceStart, const UTF32* sourceEnd,
+ UTF16** targetStart, UTF16* targetEnd, icUtfConversionFlags flags)
+{
+ icUtfConversionResult result = conversionOK;
+ const UTF32* source = *sourceStart;
+ UTF16* target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch;
+ if (target >= targetEnd) {
+ result = targetExhausted; break;
+ }
+ ch = *source++;
+ if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
+ /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ if (flags == strictConversion) {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ *target++ = (UTF16)ch; /* normal case */
+ }
+ } else if (ch > UNI_MAX_LEGAL_UTF32) {
+ if (flags == strictConversion) {
+ result = sourceIllegal;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ /* target is a character in range 0xFFFF - 0x10FFFF. */
+ if (target + 1 >= targetEnd) {
+ --source; /* Back up source pointer! */
+ result = targetExhausted; break;
+ }
+ ch -= halfBase;
+ *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
+ *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
+ }
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+icUtfConversionResult icConvertUTF16toUTF32 (const UTF16** sourceStart, const UTF16* sourceEnd,
+ UTF32** targetStart, UTF32* targetEnd, icUtfConversionFlags flags)
+{
+ icUtfConversionResult result = conversionOK;
+ const UTF16* source = *sourceStart;
+ UTF32* target = *targetStart;
+ UTF32 ch, ch2;
+ while (source < sourceEnd) {
+ const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
+ ch = *source++;
+ /* If we have a surrogate pair, convert to UTF32 first. */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
+ /* If the 16 bits following the high surrogate are in the source buffer... */
+ if (source < sourceEnd) {
+ ch2 = *source;
+ /* If it's a low surrogate, convert to UTF32. */
+ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
+ ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+ + (ch2 - UNI_SUR_LOW_START) + halfBase;
+ ++source;
+ } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ } else { /* We don't have the 16 bits following the high surrogate. */
+ --source; /* return to the high surrogate */
+ result = sourceExhausted;
+ break;
+ }
+ } else if (flags == strictConversion) {
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ }
+ if (target >= targetEnd) {
+ source = oldSource; /* Back up source pointer! */
+ result = targetExhausted; break;
+ }
+ *target++ = ch;
+ }
+ *sourceStart = source;
+ *targetStart = target;
+#ifdef CVTUTF_DEBUG
+ if (result == sourceIllegal) {
+ fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
+ fflush(stderr);
+ }
+#endif
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+* Index into the table below with the first byte of a UTF-8 sequence to
+* get the number of trailing bytes that are supposed to follow it.
+* Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
+* left as-is for anyone who may want to do such conversion, which was
+* allowed in earlier algorithms.
+*/
+static const char trailingBytesForUTF8[256] = {
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
+};
+
+/*
+* Magic values subtracted from a buffer value during UTF8 conversion.
+* This table contains as many values as there might be trailing bytes
+* in a UTF-8 sequence.
+*/
+static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
+0x03C82080UL, 0xFA082080UL, 0x82082080UL };
+
+/*
+* Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
+* into the first byte, depending on how many bytes follow. There are
+* as many entries in this table as there are UTF-8 sequence types.
+* (I.e., one byte sequence, two byte... etc.). Remember that sequencs
+* for *legal* UTF-8 will be 4 or fewer bytes total.
+*/
+static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+/* --------------------------------------------------------------------- */
+
+/* The interface converts a whole buffer to avoid function-call overhead.
+* Constants have been gathered. Loops & conditionals have been removed as
+* much as possible for efficiency, in favor of drop-through switches.
+* (See "Note A" at the bottom of the file for equivalent code.)
+* If your compiler supports it, the "isLegalUTF8" call can be turned
+* into an inline function.
+*/
+
+/* --------------------------------------------------------------------- */
+
+icUtfConversionResult icConvertUTF16toUTF8 (const UTF16** sourceStart, const UTF16* sourceEnd,
+ UTF8** targetStart, UTF8* targetEnd, icUtfConversionFlags flags)
+{
+ icUtfConversionResult result = conversionOK;
+ const UTF16* source = *sourceStart;
+ UTF8* target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch;
+ unsigned short bytesToWrite = 0;
+ const UTF32 byteMask = 0xBF;
+ const UTF32 byteMark = 0x80;
+ const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
+ ch = *source++;
+ /* If we have a surrogate pair, convert to UTF32 first. */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
+ /* If the 16 bits following the high surrogate are in the source buffer... */
+ if (source < sourceEnd) {
+ UTF32 ch2 = *source;
+ /* If it's a low surrogate, convert to UTF32. */
+ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
+ ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+ + (ch2 - UNI_SUR_LOW_START) + halfBase;
+ ++source;
+ } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ } else { /* We don't have the 16 bits following the high surrogate. */
+ --source; /* return to the high surrogate */
+ result = sourceExhausted;
+ break;
+ }
+ } else if (flags == strictConversion) {
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ }
+ /* Figure out how many bytes the result will require */
+ if (ch < (UTF32)0x80) { bytesToWrite = 1;
+ } else if (ch < (UTF32)0x800) { bytesToWrite = 2;
+ } else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
+ } else if (ch < (UTF32)0x110000) { bytesToWrite = 4;
+ } else { bytesToWrite = 3;
+ ch = UNI_REPLACEMENT_CHAR;
+ }
+
+ target += bytesToWrite;
+ if (target > targetEnd) {
+ source = oldSource; /* Back up source pointer! */
+ target -= bytesToWrite; result = targetExhausted; break;
+ }
+ switch (bytesToWrite) { /* note: everything falls through. */
+ case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
+ }
+ target += bytesToWrite;
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+* Utility routine to tell whether a sequence of bytes is legal UTF-8.
+* This must be called with the length pre-determined by the first byte.
+* If not calling this from ConvertUTF8to*, then the length can be set by:
+* length = trailingBytesForUTF8[*source]+1;
+* and the sequence is illegal right away if there aren't that many bytes
+* available.
+* If presented with a length > 4, this returns false. The Unicode
+* definition of UTF-8 goes up to 4-byte sequences.
+*/
+
+static Boolean isLegalUTF8(const UTF8 *source, int length)
+{
+ UTF8 a;
+ const UTF8 *srcptr = source+length;
+ switch (length) {
+ default: return false;
+ /* Everything else falls through when "true"... */
+ case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
+ case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
+ case 2: if ((a = (*--srcptr)) > 0xBF) return false;
+
+ switch (*source) {
+ /* no fall-through in this inner switch */
+ case 0xE0: if (a < 0xA0) return false; break;
+ case 0xED: if (a > 0x9F) return false; break;
+ case 0xF0: if (a < 0x90) return false; break;
+ case 0xF4: if (a > 0x8F) return false; break;
+ default: if (a < 0x80) return false;
+ }
+
+ case 1: if (*source >= 0x80 && *source < 0xC2) return false;
+ }
+ if (*source > 0xF4) return false;
+ return true;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+* Exported function to return whether a UTF-8 sequence is legal or not.
+* This is not used here; it's just exported.
+*/
+Boolean icIsLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd)
+{
+ int length = trailingBytesForUTF8[*source]+1;
+ if (source+length > sourceEnd) {
+ return false;
+ }
+ return isLegalUTF8(source, length);
+}
+
+/* --------------------------------------------------------------------- */
+
+icUtfConversionResult icConvertUTF8toUTF16 (const UTF8** sourceStart, const UTF8* sourceEnd,
+ UTF16** targetStart, UTF16* targetEnd, icUtfConversionFlags flags)
+{
+ icUtfConversionResult result = conversionOK;
+ const UTF8* source = *sourceStart;
+ UTF16* target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch = 0;
+ unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
+ if (source + extraBytesToRead >= sourceEnd) {
+ result = sourceExhausted; break;
+ }
+ /* Do this check whether lenient or strict */
+ if (! isLegalUTF8(source, extraBytesToRead+1)) {
+ result = sourceIllegal;
+ break;
+ }
+ /*
+ * The cases all fall through. See "Note A" below.
+ */
+ switch (extraBytesToRead) {
+ case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
+ case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
+ case 3: ch += *source++; ch <<= 6;
+ case 2: ch += *source++; ch <<= 6;
+ case 1: ch += *source++; ch <<= 6;
+ case 0: ch += *source++;
+ }
+ ch -= offsetsFromUTF8[extraBytesToRead];
+
+ if (target >= targetEnd) {
+ source -= (extraBytesToRead+1); /* Back up source pointer! */
+ result = targetExhausted; break;
+ }
+ if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ if (flags == strictConversion) {
+ source -= (extraBytesToRead+1); /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ *target++ = (UTF16)ch; /* normal case */
+ }
+ } else if (ch > UNI_MAX_UTF16) {
+ if (flags == strictConversion) {
+ result = sourceIllegal;
+ source -= (extraBytesToRead+1); /* return to the start */
+ break; /* Bail out; shouldn't continue */
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ /* target is a character in range 0xFFFF - 0x10FFFF. */
+ if (target + 1 >= targetEnd) {
+ source -= (extraBytesToRead+1); /* Back up source pointer! */
+ result = targetExhausted; break;
+ }
+ ch -= halfBase;
+ *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
+ *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
+ }
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+icUtfConversionResult icConvertUTF32toUTF8 (const UTF32** sourceStart, const UTF32* sourceEnd,
+ UTF8** targetStart, UTF8* targetEnd, icUtfConversionFlags flags)
+{
+ icUtfConversionResult result = conversionOK;
+ const UTF32* source = *sourceStart;
+ UTF8* target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch;
+ unsigned short bytesToWrite = 0;
+ const UTF32 byteMask = 0xBF;
+ const UTF32 byteMark = 0x80;
+ ch = *source++;
+ if (flags == strictConversion ) {
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ }
+ /*
+ * Figure out how many bytes the result will require. Turn any
+ * illegally large UTF32 things (> Plane 17) into replacement chars.
+ */
+ if (ch < (UTF32)0x80) { bytesToWrite = 1;
+ } else if (ch < (UTF32)0x800) { bytesToWrite = 2;
+ } else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
+ } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4;
+ } else { bytesToWrite = 3;
+ ch = UNI_REPLACEMENT_CHAR;
+ result = sourceIllegal;
+ }
+
+ target += bytesToWrite;
+ if (target > targetEnd) {
+ --source; /* Back up source pointer! */
+ target -= bytesToWrite; result = targetExhausted; break;
+ }
+ switch (bytesToWrite) { /* note: everything falls through. */
+ case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
+ }
+ target += bytesToWrite;
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+icUtfConversionResult icConvertUTF8toUTF32 (const UTF8** sourceStart, const UTF8* sourceEnd,
+ UTF32** targetStart, UTF32* targetEnd, icUtfConversionFlags flags)
+{
+ icUtfConversionResult result = conversionOK;
+ const UTF8* source = *sourceStart;
+ UTF32* target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch = 0;
+ unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
+ if (source + extraBytesToRead >= sourceEnd) {
+ result = sourceExhausted; break;
+ }
+ /* Do this check whether lenient or strict */
+ if (! isLegalUTF8(source, extraBytesToRead+1)) {
+ result = sourceIllegal;
+ break;
+ }
+ /*
+ * The cases all fall through. See "Note A" below.
+ */
+ switch (extraBytesToRead) {
+ case 5: ch += *source++; ch <<= 6;
+ case 4: ch += *source++; ch <<= 6;
+ case 3: ch += *source++; ch <<= 6;
+ case 2: ch += *source++; ch <<= 6;
+ case 1: ch += *source++; ch <<= 6;
+ case 0: ch += *source++;
+ }
+ ch -= offsetsFromUTF8[extraBytesToRead];
+
+ if (target >= targetEnd) {
+ source -= (extraBytesToRead+1); /* Back up the source pointer! */
+ result = targetExhausted; break;
+ }
+ if (ch <= UNI_MAX_LEGAL_UTF32) {
+ /*
+ * UTF-16 surrogate values are illegal in UTF-32, and anything
+ * over Plane 17 (> 0x10FFFF) is illegal.
+ */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ if (flags == strictConversion) {
+ source -= (extraBytesToRead+1); /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ *target++ = ch;
+ }
+ } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
+ result = sourceIllegal;
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* ---------------------------------------------------------------------
+
+Note A.
+The fall-through switches in UTF-8 reading code save a
+temp variable, some decrements & conditionals. The switches
+are equivalent to the following loop:
+{
+int tmpBytesToRead = extraBytesToRead+1;
+do {
+ch += *source++;
+--tmpBytesToRead;
+if (tmpBytesToRead) ch <<= 6;
+} while (tmpBytesToRead > 0);
+}
+In UTF-8 writing code, the switches on "bytesToWrite" are
+similarly unrolled loops.
+
+--------------------------------------------------------------------- */
diff --git a/library/src/main/cpp/icc/IccConvertUTF.h b/library/src/main/cpp/icc/IccConvertUTF.h
new file mode 100644
index 00000000..fcb224b2
--- /dev/null
+++ b/library/src/main/cpp/icc/IccConvertUTF.h
@@ -0,0 +1,158 @@
+/*
+* Copyright 2001-2004 Unicode, Inc.
+*
+* Disclaimer
+*
+* This source code is provided as is by Unicode, Inc. No claims are
+* made as to fitness for any particular purpose. No warranties of any
+* kind are expressed or implied. The recipient agrees to determine
+* applicability of information provided. If this file has been
+* purchased on magnetic or optical media from Unicode, Inc., the
+* sole remedy for any claim will be exchange of defective media
+* within 90 days of receipt.
+*
+* Limitations on Rights to Redistribute This Code
+*
+* Unicode, Inc. hereby grants the right to freely use the information
+* supplied in this file in the creation of products supporting the
+* Unicode Standard, and to make copies of this file in any form
+* for internal or external distribution as long as this notice
+* remains attached.
+*/
+
+/* ---------------------------------------------------------------------
+
+Conversions between UTF32, UTF-16, and UTF-8. Header file.
+
+Several funtions are included here, forming a complete set of
+conversions between the three formats. UTF-7 is not included
+here, but is handled in a separate source file.
+
+Each of these routines takes pointers to input buffers and output
+buffers. The input buffers are const.
+
+Each routine converts the text between *sourceStart and sourceEnd,
+putting the result into the buffer between *targetStart and
+targetEnd. Note: the end pointers are *after* the last item: e.g.
+*(sourceEnd - 1) is the last item.
+
+The return result indicates whether the conversion was successful,
+and if not, whether the problem was in the source or target buffers.
+(Only the first encountered problem is indicated.)
+
+After the conversion, *sourceStart and *targetStart are both
+updated to point to the end of last text successfully converted in
+the respective buffers.
+
+Input parameters:
+sourceStart - pointer to a pointer to the source buffer.
+The contents of this are modified on return so that
+it points at the next thing to be converted.
+targetStart - similarly, pointer to pointer to the target buffer.
+sourceEnd, targetEnd - respectively pointers to the ends of the
+two buffers, for overflow checking only.
+
+These conversion functions take an icUtfConversionFlags argument. When this
+flag is set to strict, both irregular sequences and isolated surrogates
+will cause an error. When the flag is set to lenient, both irregular
+sequences and isolated surrogates are converted.
+
+Whether the flag is strict or lenient, all illegal sequences will cause
+an error return. This includes sequences such as: , ,
+or in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
+must check for illegal sequences.
+
+When the flag is set to lenient, characters over 0x10FFFF are converted
+to the replacement character; otherwise (when the flag is set to strict)
+they constitute an error.
+
+Output parameters:
+The value "sourceIllegal" is returned from some routines if the input
+sequence is malformed. When "sourceIllegal" is returned, the source
+value will point to the illegal value that caused the problem. E.g.,
+in UTF-8 when a sequence is malformed, it points to the start of the
+malformed sequence.
+
+Author: Mark E. Davis, 1994.
+Rev History: Rick McGowan, fixes & updates May 2001.
+Fixes & updates, Sept 2001.
+
+------------------------------------------------------------------------ */
+
+/* ---------------------------------------------------------------------
+July 2009
+- Modified names to avoid possible conflicts - Max Derhak
+- Added IccProfLibConf.h include to use ICCPROFLIB_API with functions
+- Changed typedef of UTF32 to use ICCUINT32
+------------------------------------------------------------------------ */
+
+#include "IccProfLibConf.h"
+
+/* ---------------------------------------------------------------------
+The following 4 definitions are compiler-specific.
+The C standard does not guarantee that wchar_t has at least
+16 bits, so wchar_t is no less portable than unsigned short!
+All should be unsigned values to avoid sign extension during
+bit mask & shift operations.
+------------------------------------------------------------------------ */
+
+typedef ICCUINT32 UTF32; /* at least 32 bits */
+typedef unsigned short UTF16; /* at least 16 bits */
+typedef unsigned char UTF8; /* typically 8 bits */
+typedef unsigned char Boolean; /* 0 or 1 */
+
+/* Some fundamental constants */
+#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
+#define UNI_MAX_BMP (UTF32)0x0000FFFF
+#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
+#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
+#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
+
+typedef enum {
+ conversionOK, /* conversion successful */
+ sourceExhausted, /* partial character in source, but hit end */
+ targetExhausted, /* insuff. room in target for conversion */
+ sourceIllegal /* source sequence is illegal/malformed */
+} icUtfConversionResult;
+
+typedef enum {
+ strictConversion = 0,
+ lenientConversion
+} icUtfConversionFlags;
+
+/* This is for C++ and does no harm in C */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+icUtfConversionResult ICCPROFLIB_API icConvertUTF8toUTF16 (
+ const UTF8** sourceStart, const UTF8* sourceEnd,
+ UTF16** targetStart, UTF16* targetEnd, icUtfConversionFlags flags);
+
+icUtfConversionResult ICCPROFLIB_API icConvertUTF16toUTF8 (
+ const UTF16** sourceStart, const UTF16* sourceEnd,
+ UTF8** targetStart, UTF8* targetEnd, icUtfConversionFlags flags);
+
+icUtfConversionResult ICCPROFLIB_API icConvertUTF8toUTF32 (
+ const UTF8** sourceStart, const UTF8* sourceEnd,
+ UTF32** targetStart, UTF32* targetEnd, icUtfConversionFlags flags);
+
+icUtfConversionResult ICCPROFLIB_API icConvertUTF32toUTF8 (
+ const UTF32** sourceStart, const UTF32* sourceEnd,
+ UTF8** targetStart, UTF8* targetEnd, icUtfConversionFlags flags);
+
+icUtfConversionResult ICCPROFLIB_API icConvertUTF16toUTF32 (
+ const UTF16** sourceStart, const UTF16* sourceEnd,
+ UTF32** targetStart, UTF32* targetEnd, icUtfConversionFlags flags);
+
+icUtfConversionResult ICCPROFLIB_API icConvertUTF32toUTF16 (
+ const UTF32** sourceStart, const UTF32* sourceEnd,
+ UTF16** targetStart, UTF16* targetEnd, icUtfConversionFlags flags);
+
+Boolean ICCPROFLIB_API icIsLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* --------------------------------------------------------------------- */
diff --git a/library/src/main/cpp/icc/IccDefs.h b/library/src/main/cpp/icc/IccDefs.h
new file mode 100644
index 00000000..8212906f
--- /dev/null
+++ b/library/src/main/cpp/icc/IccDefs.h
@@ -0,0 +1,136 @@
+/** @file
+ File: IccDefs.h
+
+ Contains: Access ICC profile definitions and structures including
+ Version 4 extensions
+
+ Copyright: see ICC Software License
+ */
+
+/*
+ * The ICC Software License, Version 0.2
+ *
+ *
+ * Copyright (c) 2003-2015 The International Color Consortium. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. In the absence of prior written permission, the names "ICC" and "The
+ * International Color Consortium" must not be used to imply that the
+ * ICC organization endorses or promotes products derived from this
+ * software.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR
+ * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the The International Color Consortium.
+ *
+ *
+ * Membership in the ICC is encouraged when this software is used for
+ * commercial purposes.
+ *
+ *
+ * For more information on The International Color Consortium, please
+ * see .
+ *
+ *
+ */
+
+#include
+
+/* Header file guard bands */
+#ifndef _ICCDEFS_H
+#define _ICCDEFS_H
+
+#pragma pack(4)
+
+//Get any platform specific prototypes
+#include "IccProfLibConf.h"
+
+#ifdef USESAMPLEICCNAMESPACE
+namespace sampleICC {
+#endif
+
+//Include the standard icProfileHeader definition file
+#include "icProfileHeader.h"
+
+// Define signature for SampleICC's use
+#define icSigSampleICC ((icSignature)0x53494343) /* 'SICC' */
+
+//Definitions used for conversion of fixed floating point numbers
+typedef icUInt16Number icU1Fixed15Number;
+typedef icUInt16Number icU8Fixed8Number;
+
+
+/**
+* Additional convenience color space signatures to distinguish between device
+* encoding and PCS encoding.
+*
+* Device encoding of these color spaces is left to the device to define.
+*/
+#define icSigDevLabData ((icColorSpaceSignature) 0x644C6162) /* 'dLab' */
+#define icSigDevXYZData ((icColorSpaceSignature) 0x6458595A) /* 'dXYZ' */
+
+
+/**
+* All floating point operations/variables in IccProfLib use the icFloatNumber data type.
+* It was found that using float instead of double increased performance. Changing
+* the definition to double will add greater precision at the cost of performance.
+*/
+typedef float icFloatNumber;
+
+/** String formating macros need to match precision of icFloatNumber
+*If precision is double change the "f" below to "lf"
+*/
+#define ICFLOATSFX "f"
+#define ICFLOATFMT "%f"
+
+/* For string operations */
+typedef char icChar;
+#if defined(WIN32) || defined(WIN64)
+typedef wchar_t icWChar;
+#endif
+
+/* Validation Status values */
+typedef enum {
+ icValidateOK, /*Profile is valid and conforms to specification*/
+ icValidateWarning, /*Profile conforms to specification with concerns*/
+ icValidateNonCompliant, /*Profile does not conform to specification, but may still be useable*/
+ icValidateCriticalError, /*Profile does not conform to specification and is not useable*/
+} icValidateStatus;
+
+
+#pragma pack()
+
+#ifdef USESAMPLEICCNAMESPACE
+} //namespace sampleICC
+#endif
+
+#endif /* _ICCDEFS_H */
+
+
+
diff --git a/library/src/main/cpp/icc/IccDemo.cpp b/library/src/main/cpp/icc/IccDemo.cpp
new file mode 100644
index 00000000..0c2d76fb
--- /dev/null
+++ b/library/src/main/cpp/icc/IccDemo.cpp
@@ -0,0 +1,229 @@
+//
+// Created by 钟元杰 on 2022/9/19.
+//
+
+#include "IccCmm.h"
+#include "IccProfile.h"
+#include
+#include
+
+#define TAG "IccCmm_ceshi"
+#define pri_debug(format, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, "[%s:%d]" format, "IccDemo.cpp", __LINE__, ##args)
+
+CIccCmm *cmm = nullptr;
+icFloatNumber Pixels[16];
+
+//from skia pdfDocument
+const icUInt8Number kProfile[] =
+ "\0\0\14\214argl\2 \0\0mntrRGB XYZ \7\336\0\1\0\6\0\26\0\17\0:acspM"
+ "SFT\0\0\0\0IEC sRGB\0\0\0\0\0\0\0\0\0\0\0\0\0\0\366\326\0\1\0\0\0\0"
+ "\323-argl\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\21desc\0\0\1P\0\0\0\231cprt\0"
+ "\0\1\354\0\0\0gdmnd\0\0\2T\0\0\0pdmdd\0\0\2\304\0\0\0\210tech\0\0\3"
+ "L\0\0\0\14vued\0\0\3X\0\0\0gview\0\0\3\300\0\0\0$lumi\0\0\3\344\0\0"
+ "\0\24meas\0\0\3\370\0\0\0$wtpt\0\0\4\34\0\0\0\24bkpt\0\0\0040\0\0\0"
+ "\24rXYZ\0\0\4D\0\0\0\24gXYZ\0\0\4X\0\0\0\24bXYZ\0\0\4l\0\0\0\24rTR"
+ "C\0\0\4\200\0\0\10\14gTRC\0\0\4\200\0\0\10\14bTRC\0\0\4\200\0\0\10"
+ "\14desc\0\0\0\0\0\0\0?sRGB IEC61966-2.1 (Equivalent to www.srgb.co"
+ "m 1998 HP profile)\0\0\0\0\0\0\0\0\0\0\0?sRGB IEC61966-2.1 (Equiva"
+ "lent to www.srgb.com 1998 HP profile)\0\0\0\0\0\0\0\0text\0\0\0\0C"
+ "reated by Graeme W. Gill. Released into the public domain. No Warr"
+ "anty, Use at your own risk.\0\0desc\0\0\0\0\0\0\0\26IEC http://www"
+ ".iec.ch\0\0\0\0\0\0\0\0\0\0\0\26IEC http://www.iec.ch\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0desc\0\0\0\0\0\0\0.IEC 61966-2.1 Default RGB colour sp"
+ "ace - sRGB\0\0\0\0\0\0\0\0\0\0\0.IEC 61966-2.1 Default RGB colour "
+ "space - sRGB\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0sig \0\0\0"
+ "\0CRT desc\0\0\0\0\0\0\0\rIEC61966-2.1\0\0\0\0\0\0\0\0\0\0\0\rIEC6"
+ "1966-2.1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0view\0\0\0\0"
+ "\0\23\244|\0\24_0\0\20\316\2\0\3\355\262\0\4\23\n\0\3\\g\0\0\0\1XY"
+ "Z \0\0\0\0\0L\n=\0P\0\0\0W\36\270meas\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\2\217\0\0\0\2XYZ \0\0\0\0\0\0\363Q\0\1\0\0\0"
+ "\1\26\314XYZ \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0XYZ \0\0\0\0\0\0o\240"
+ "\0\0008\365\0\0\3\220XYZ \0\0\0\0\0\0b\227\0\0\267\207\0\0\30\331X"
+ "YZ \0\0\0\0\0\0$\237\0\0\17\204\0\0\266\304curv\0\0\0\0\0\0\4\0\0\0"
+ "\0\5\0\n\0\17\0\24\0\31\0\36\0#\0(\0-\0002\0007\0;\0@\0E\0J\0O\0T\0"
+ "Y\0^\0c\0h\0m\0r\0w\0|\0\201\0\206\0\213\0\220\0\225\0\232\0\237\0"
+ "\244\0\251\0\256\0\262\0\267\0\274\0\301\0\306\0\313\0\320\0\325\0"
+ "\333\0\340\0\345\0\353\0\360\0\366\0\373\1\1\1\7\1\r\1\23\1\31\1\37"
+ "\1%\1+\0012\0018\1>\1E\1L\1R\1Y\1`\1g\1n\1u\1|\1\203\1\213\1\222\1"
+ "\232\1\241\1\251\1\261\1\271\1\301\1\311\1\321\1\331\1\341\1\351\1"
+ "\362\1\372\2\3\2\14\2\24\2\35\2&\2/\0028\2A\2K\2T\2]\2g\2q\2z\2\204"
+ "\2\216\2\230\2\242\2\254\2\266\2\301\2\313\2\325\2\340\2\353\2\365"
+ "\3\0\3\13\3\26\3!\3-\0038\3C\3O\3Z\3f\3r\3~\3\212\3\226\3\242\3\256"
+ "\3\272\3\307\3\323\3\340\3\354\3\371\4\6\4\23\4 \4-\4;\4H\4U\4c\4q"
+ "\4~\4\214\4\232\4\250\4\266\4\304\4\323\4\341\4\360\4\376\5\r\5\34"
+ "\5+\5:\5I\5X\5g\5w\5\206\5\226\5\246\5\265\5\305\5\325\5\345\5\366"
+ "\6\6\6\26\6'\0067\6H\6Y\6j\6{\6\214\6\235\6\257\6\300\6\321\6\343\6"
+ "\365\7\7\7\31\7+\7=\7O\7a\7t\7\206\7\231\7\254\7\277\7\322\7\345\7"
+ "\370\10\13\10\37\0102\10F\10Z\10n\10\202\10\226\10\252\10\276\10\322"
+ "\10\347\10\373\t\20\t%\t:\tO\td\ty\t\217\t\244\t\272\t\317\t\345\t"
+ "\373\n\21\n'\n=\nT\nj\n\201\n\230\n\256\n\305\n\334\n\363\13\13\13"
+ "\"\0139\13Q\13i\13\200\13\230\13\260\13\310\13\341\13\371\14\22\14"
+ "*\14C\14\\\14u\14\216\14\247\14\300\14\331\14\363\r\r\r&\r@\rZ\rt\r"
+ "\216\r\251\r\303\r\336\r\370\16\23\16.\16I\16d\16\177\16\233\16\266"
+ "\16\322\16\356\17\t\17%\17A\17^\17z\17\226\17\263\17\317\17\354\20"
+ "\t\20&\20C\20a\20~\20\233\20\271\20\327\20\365\21\23\0211\21O\21m\21"
+ "\214\21\252\21\311\21\350\22\7\22&\22E\22d\22\204\22\243\22\303\22"
+ "\343\23\3\23#\23C\23c\23\203\23\244\23\305\23\345\24\6\24'\24I\24j"
+ "\24\213\24\255\24\316\24\360\25\22\0254\25V\25x\25\233\25\275\25\340"
+ "\26\3\26&\26I\26l\26\217\26\262\26\326\26\372\27\35\27A\27e\27\211"
+ "\27\256\27\322\27\367\30\33\30@\30e\30\212\30\257\30\325\30\372\31"
+ " \31E\31k\31\221\31\267\31\335\32\4\32*\32Q\32w\32\236\32\305\32\354"
+ "\33\24\33;\33c\33\212\33\262\33\332\34\2\34*\34R\34{\34\243\34\314"
+ "\34\365\35\36\35G\35p\35\231\35\303\35\354\36\26\36@\36j\36\224\36"
+ "\276\36\351\37\23\37>\37i\37\224\37\277\37\352 \25 A l \230 \304 \360"
+ "!\34!H!u!\241!\316!\373\"'\"U\"\202\"\257\"\335#\n#8#f#\224#\302#\360"
+ "$\37$M$|$\253$\332%\t%8%h%\227%\307%\367&'&W&\207&\267&\350'\30'I'"
+ "z'\253'\334(\r(?(q(\242(\324)\6)8)k)\235)\320*\2*5*h*\233*\317+\2+"
+ "6+i+\235+\321,\5,9,n,\242,\327-\14-A-v-\253-\341.\26.L.\202.\267.\356"
+ "/$/Z/\221/\307/\376050l0\2440\3331\0221J1\2021\2721\3622*2c2\2332\324"
+ "3\r3F3\1773\2703\3614+4e4\2364\3305\0235M5\2075\3025\375676r6\2566"
+ "\3517$7`7\2347\3278\0248P8\2148\3109\0059B9\1779\2749\371:6:t:\262"
+ ":\357;-;k;\252;\350<' >`>\240>\340?!?a"
+ "?\242?\342@#@d@\246@\347A)AjA\254A\356B0BrB\265B\367C:C}C\300D\3DG"
+ "D\212D\316E\22EUE\232E\336F\"FgF\253F\360G5G{G\300H\5HKH\221H\327I"
+ "\35IcI\251I\360J7J}J\304K\14KSK\232K\342L*LrL\272M\2MJM\223M\334N%"
+ "NnN\267O\0OIO\223O\335P'PqP\273Q\6QPQ\233Q\346R1R|R\307S\23S_S\252"
+ "S\366TBT\217T\333U(UuU\302V\17V\\V\251V\367WDW\222W\340X/X}X\313Y\32"
+ "YiY\270Z\7ZVZ\246Z\365[E[\225[\345\\5\\\206\\\326]']x]\311^\32^l^\275"
+ "_\17_a_\263`\5`W`\252`\374aOa\242a\365bIb\234b\360cCc\227c\353d@d\224"
+ "d\351e=e\222e\347f=f\222f\350g=g\223g\351h?h\226h\354iCi\232i\361j"
+ "Hj\237j\367kOk\247k\377lWl\257m\10m`m\271n\22nkn\304o\36oxo\321p+p"
+ "\206p\340q:q\225q\360rKr\246s\1s]s\270t\24tpt\314u(u\205u\341v>v\233"
+ "v\370wVw\263x\21xnx\314y*y\211y\347zFz\245{\4{c{\302|!|\201|\341}A"
+ "}\241~\1~b~\302\177#\177\204\177\345\200G\200\250\201\n\201k\201\315"
+ "\2020\202\222\202\364\203W\203\272\204\35\204\200\204\343\205G\205"
+ "\253\206\16\206r\206\327\207;\207\237\210\4\210i\210\316\2113\211\231"
+ "\211\376\212d\212\312\2130\213\226\213\374\214c\214\312\2151\215\230"
+ "\215\377\216f\216\316\2176\217\236\220\6\220n\220\326\221?\221\250"
+ "\222\21\222z\222\343\223M\223\266\224 \224\212\224\364\225_\225\311"
+ "\2264\226\237\227\n\227u\227\340\230L\230\270\231$\231\220\231\374"
+ "\232h\232\325\233B\233\257\234\34\234\211\234\367\235d\235\322\236"
+ "@\236\256\237\35\237\213\237\372\240i\240\330\241G\241\266\242&\242"
+ "\226\243\6\243v\243\346\244V\244\307\2458\245\251\246\32\246\213\246"
+ "\375\247n\247\340\250R\250\304\2517\251\251\252\34\252\217\253\2\253"
+ "u\253\351\254\\\254\320\255D\255\270\256-\256\241\257\26\257\213\260"
+ "\0\260u\260\352\261`\261\326\262K\262\302\2638\263\256\264%\264\234"
+ "\265\23\265\212\266\1\266y\266\360\267h\267\340\270Y\270\321\271J\271"
+ "\302\272;\272\265\273.\273\247\274!\274\233\275\25\275\217\276\n\276"
+ "\204\276\377\277z\277\365\300p\300\354\301g\301\343\302_\302\333\303"
+ "X\303\324\304Q\304\316\305K\305\310\306F\306\303\307A\307\277\310="
+ "\310\274\311:\311\271\3128\312\267\3136\313\266\3145\314\265\3155\315"
+ "\265\3166\316\266\3177\317\270\3209\320\272\321<\321\276\322?\322\301"
+ "\323D\323\306\324I\324\313\325N\325\321\326U\326\330\327\\\327\340"
+ "\330d\330\350\331l\331\361\332v\332\373\333\200\334\5\334\212\335\20"
+ "\335\226\336\34\336\242\337)\337\257\3406\340\275\341D\341\314\342"
+ "S\342\333\343c\343\353\344s\344\374\345\204\346\r\346\226\347\37\347"
+ "\251\3502\350\274\351F\351\320\352[\352\345\353p\353\373\354\206\355"
+ "\21\355\234\356(\356\264\357@\357\314\360X\360\345\361r\361\377\362"
+ "\214\363\31\363\247\3644\364\302\365P\365\336\366m\366\373\367\212"
+ "\370\31\370\250\3718\371\307\372W\372\347\373w\374\7\374\230\375)\375"
+ "\272\376K\376\334\377m\377\377";
+const size_t kProfileLength = 3212;
+
+extern "C"{
+
+JNIEXPORT jint JNICALL Java_com_xsooy_icc_IccUtils_loadProfile(JNIEnv *env, jobject thiz, jstring path) {
+ delete cmm;
+ cmm = new CIccCmm;
+ if (cmm->GetNumXforms()!=0) {
+ pri_debug("profile已加载");
+ return 1;
+ }
+ const char *nativeString = env->GetStringUTFChars(path, 0);
+ if (cmm->AddXform(nativeString, (icRenderingIntent)0)) {
+ pri_debug("合入失败%s",nativeString);
+// printf("Invalid Profile: %s\n", szSrcProfile);
+ return -1;
+ }
+ pri_debug("合入成功%s",nativeString);
+ if (cmm->Begin() != icCmmStatOk) {
+ pri_debug("合入失败222%s",nativeString);
+// printf("Invalid Profile:\n %s\n %s'\n", szSrcProfile, szDstProfile);
+ return false;
+ }
+ return 0;
+}
+
+icUInt8Number* ConvertJByteaArrayToChars(JNIEnv *env, jbyteArray bytearray)
+{
+ icUInt8Number *chars = NULL;
+ jbyte *bytes;
+ bytes = env->GetByteArrayElements(bytearray, 0);
+ int chars_len = env->GetArrayLength(bytearray);
+ chars = new icUInt8Number[chars_len + 1];
+ memset(chars,0,chars_len + 1);
+ memcpy(chars, bytes, chars_len);
+ chars[chars_len] = 0;
+
+ env->ReleaseByteArrayElements(bytearray, bytes, 0);
+ return chars;
+}
+
+JNIEXPORT jint JNICALL Java_com_xsooy_icc_IccUtils_loadProfileByData(JNIEnv *env, jobject thiz, jbyteArray data) {
+ delete cmm;
+ cmm = new CIccCmm;
+ icUInt8Number *pmsg = ConvertJByteaArrayToChars(env,data);
+ int chars_len = env->GetArrayLength(data);
+ CIccProfile* cIccProfile = OpenIccProfile(pmsg, chars_len);
+ if (cIccProfile==nullptr) {
+ pri_debug("创建IccData失败");
+ return -1;
+ }
+ if (cmm->AddXform(cIccProfile, (icRenderingIntent)0)) {
+ pri_debug("读取IccData失败");
+ return -1;
+ }
+
+ pri_debug("读取输入IccData成功");
+
+ CIccProfile* sRgbProfile = OpenIccProfile(kProfile, kProfileLength);
+ if (cmm->AddXform(sRgbProfile, (icRenderingIntent)0)) {
+ pri_debug("读取sRgb-IccData失败");
+ return -1;
+ }
+
+ pri_debug("读取输入sRgb-IccData成功");
+
+ pri_debug("SourceSpace:%d",cmm->GetSourceSpace());
+ if (cmm->Begin() != icCmmStatOk) {
+ pri_debug("启动Icc失败");
+ return false;
+ }
+ pri_debug("DestSpace:%d",cmm->GetDestSpace());
+ return cmm->GetSourceSpace();
+}
+
+JNIEXPORT jfloat JNICALL Java_com_xsooy_icc_IccUtils_apply(JNIEnv *env, jobject thiz, jfloat pixel) {
+ Pixels[0] = (float) pixel;
+ cmm->Apply(Pixels, Pixels);
+ return Pixels[0];
+}
+
+JNIEXPORT void JNICALL Java_com_xsooy_icc_IccUtils_applyGray(JNIEnv *env, jobject thiz, jfloatArray array,jfloatArray outArray) {
+ jboolean isCopy = JNI_FALSE;
+ jfloat *parray = env->GetFloatArrayElements(array, &isCopy);
+ Pixels[0] = float (parray[0]);
+
+ cmm->Apply(Pixels, Pixels);
+
+ env->SetFloatArrayRegion(outArray,0,3,Pixels);
+}
+
+JNIEXPORT void JNICALL Java_com_xsooy_icc_IccUtils_applyCmyk(JNIEnv *env, jobject thiz, jfloatArray array,jfloatArray outArray) {
+ jboolean isCopy = JNI_FALSE;
+ jfloat *parray = env->GetFloatArrayElements(array, &isCopy);
+ Pixels[0] = float (parray[0]);
+ Pixels[1] = float (parray[1]);
+ Pixels[2] = float (parray[2]);
+ Pixels[3] = float (parray[3]);
+
+ //change data to 'rgb'
+ cmm->Apply(Pixels, Pixels);
+
+ env->SetFloatArrayRegion(outArray,0,3,Pixels);
+}
+
+}
\ No newline at end of file
diff --git a/library/src/main/cpp/icc/IccEval.cpp b/library/src/main/cpp/icc/IccEval.cpp
new file mode 100644
index 00000000..cf8b7afc
--- /dev/null
+++ b/library/src/main/cpp/icc/IccEval.cpp
@@ -0,0 +1,208 @@
+/** @file
+File: IccEval.cpp
+
+Contains: Implementation of the CIccProfile Evaluation utilites.
+
+Version: V1
+
+Copyright: see ICC Software License
+*/
+
+/*
+* The ICC Software License, Version 0.2
+*
+*
+* Copyright (c) 2003-2015 The International Color Consortium. All rights
+* reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in
+* the documentation and/or other materials provided with the
+* distribution.
+*
+* 3. In the absence of prior written permission, the names "ICC" and "The
+* International Color Consortium" must not be used to imply that the
+* ICC organization endorses or promotes products derived from this
+* software.
+*
+*
+* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR
+* ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+* SUCH DAMAGE.
+* ====================================================================
+*
+* This software consists of voluntary contributions made by many
+* individuals on behalf of the The International Color Consortium.
+*
+*
+* Membership in the ICC is encouraged when this software is used for
+* commercial purposes.
+*
+*
+* For more information on The International Color Consortium, please
+* see .
+*
+*
+*/
+
+//////////////////////////////////////////////////////////////////////
+// HISTORY:
+//
+// -Initial implementation by Max Derhak 5-15-2003
+//
+//////////////////////////////////////////////////////////////////////
+
+#include
+#include "IccEval.h"
+#include "IccTag.h"
+
+#ifdef USESAMPLEICCNAMESPACE
+namespace sampleICC {
+#endif
+
+static const icFloatNumber SMALLNUM = (icFloatNumber)0.0001;
+static const icFloatNumber LESSTHANONE = (icFloatNumber)(1.0 - SMALLNUM);
+
+icStatusCMM CIccEvalCompare::EvaluateProfile(CIccProfile *pProfile, icUInt8Number nGran/* =0 */,
+ icRenderingIntent nIntent/* =icUnknownIntent */, icXformInterp nInterp/* =icInterpLinear */,
+ bool buseMpeTags/* =true */)
+{
+ if (!pProfile)
+ {
+ return icCmmStatCantOpenProfile;
+ }
+
+ if (pProfile->m_Header.deviceClass!=icSigInputClass &&
+ pProfile->m_Header.deviceClass!=icSigDisplayClass &&
+ pProfile->m_Header.deviceClass!=icSigOutputClass &&
+ pProfile->m_Header.deviceClass!=icSigColorSpaceClass)
+ {
+ return icCmmStatInvalidProfile;
+ }
+
+ CIccCmm dev2Lab(icSigUnknownData, icSigLabData);
+ CIccCmm Lab2Dev2Lab(icSigLabData, icSigLabData, false);
+
+ icStatusCMM result;
+
+ result = dev2Lab.AddXform(*pProfile, nIntent, nInterp, icXformLutColor, buseMpeTags);
+
+ if (result!=icCmmStatOk) {
+ return result;
+ }
+
+ result = dev2Lab.Begin();
+ if (result != icCmmStatOk) {
+ return result;
+ }
+
+ result = Lab2Dev2Lab.AddXform(*pProfile, nIntent, nInterp, icXformLutColor, buseMpeTags);
+ if (result != icCmmStatOk) {
+ return result;
+ }
+
+ result = Lab2Dev2Lab.AddXform(*pProfile, nIntent, nInterp, icXformLutColor, buseMpeTags);
+ if (result != icCmmStatOk) {
+ return result;
+ }
+
+ result = Lab2Dev2Lab.Begin();
+ if (result != icCmmStatOk) {
+ return result;
+ }
+
+ icFloatNumber sPixel[15];
+ icFloatNumber devPcs[15], roundPcs1[15], roundPcs2[15];
+
+ int ndim = icGetSpaceSamples(pProfile->m_Header.colorSpace);
+ int ndim1 = ndim+1;
+
+ // determine granularity
+ if (!nGran)
+ {
+ CIccTagLutAtoB* pTag = (CIccTagLutAtoB*)pProfile->FindTag(icSigAToB0Tag+(nIntent==icAbsoluteColorimetric ? icRelativeColorimetric : nIntent));
+ if (!pTag || ndim==3)
+ {
+ nGran = 33;
+ }
+ else {
+ CIccCLUT* pClut = pTag->GetCLUT();
+ if (pClut)
+ nGran = pClut->GridPoints()+2;
+ else
+ nGran = 33;
+ }
+ }
+
+ int i, j;
+ icFloatNumber stepsize = (icFloatNumber)(1.0/(icFloatNumber)(nGran-1));
+ icFloatNumber* steps = new icFloatNumber[ndim1];
+ icFloatNumber nstart = 0.0;
+ icFloatNumber nEnd = (icFloatNumber)(1.0+stepsize/2.0);
+ for(j=0; j=0; i--) {
+ if(steps[i]>nEnd) {
+ steps[i] = nstart;
+ steps[i-1] = (steps[i-1]+stepsize);
+ }
+ else break;
+ }
+
+ dev2Lab.Apply(devPcs, sPixel); //Convert device value to pcs from input table
+ Lab2Dev2Lab.Apply(roundPcs1, devPcs); //First round trip gets color into output gamut
+ Lab2Dev2Lab.Apply(roundPcs2, roundPcs1); //Second round trip find reproducibility error
+
+ icLabFromPcs(devPcs);
+ icLabFromPcs(roundPcs1);
+ icLabFromPcs(roundPcs2);
+
+ Compare(sPixel, devPcs, roundPcs1, roundPcs2);
+ }
+
+ delete [] steps;
+
+ return icCmmStatOk;
+}
+
+icStatusCMM CIccEvalCompare::EvaluateProfile(const icChar *szProfilePath, icUInt8Number nGrid/* =0 */, icRenderingIntent nIntent/* =icUnknownIntent */,
+ icXformInterp nInterp/* =icInterpLinear */, bool buseMpeTags/* =true */)
+{
+ CIccProfile *pProfile = ReadIccProfile(szProfilePath);
+
+ if (!pProfile)
+ return icCmmStatCantOpenProfile;
+
+ icStatusCMM result = EvaluateProfile(pProfile, nGrid, nIntent, nInterp, buseMpeTags);
+
+ delete pProfile;
+
+ return result;
+}
+
+#ifdef USESAMPLEICCNAMESPACE
+} //namespace sampleICC
+#endif
diff --git a/library/src/main/cpp/icc/IccEval.h b/library/src/main/cpp/icc/IccEval.h
new file mode 100644
index 00000000..722508ce
--- /dev/null
+++ b/library/src/main/cpp/icc/IccEval.h
@@ -0,0 +1,99 @@
+/** @file
+File: IccEval.h
+
+Contains: Header file for implementation of the CIccProfile Evaluation utilites.
+
+Version: V1
+
+Copyright: see ICC Software License
+*/
+
+/*
+* The ICC Software License, Version 0.2
+*
+*
+* Copyright (c) 2003-2015 The International Color Consortium. All rights
+* reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in
+* the documentation and/or other materials provided with the
+* distribution.
+*
+* 3. In the absence of prior written permission, the names "ICC" and "The
+* International Color Consortium" must not be used to imply that the
+* ICC organization endorses or promotes products derived from this
+* software.
+*
+*
+* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR
+* ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+* SUCH DAMAGE.
+* ====================================================================
+*
+* This software consists of voluntary contributions made by many
+* individuals on behalf of the The International Color Consortium.
+*
+*
+* Membership in the ICC is encouraged when this software is used for
+* commercial purposes.
+*
+*
+* For more information on The International Color Consortium, please
+* see .
+*
+*
+*/
+
+//////////////////////////////////////////////////////////////////////
+// HISTORY:
+//
+// -Initial implementation by Max Derhak 9-25-2007
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(_ICCEVAL_H)
+#define _ICCEVAL_H
+
+#include "IccCmm.h"
+
+#ifdef USESAMPLEICCNAMESPACE
+namespace sampleICC {
+#endif
+
+
+class CIccEvalCompare {
+public:
+ //Create prototype for Compare function that must be implemented by a derived class
+ virtual void Compare(icFloatNumber *pPixel, icFloatNumber *deviceLab, icFloatNumber *destLab1, icFloatNumber *destLab2)=0;
+
+ icStatusCMM ICCPROFLIB_API EvaluateProfile(CIccProfile *pProfile, icUInt8Number nGran=0,
+ icRenderingIntent nIntent=icUnknownIntent, icXformInterp nInterp=icInterpLinear,
+ bool buseMpeTags=true);
+
+ icStatusCMM ICCPROFLIB_API EvaluateProfile(const icChar *szProfilePath, icUInt8Number nGran=0,
+ icRenderingIntent nIntent=icUnknownIntent, icXformInterp nInterp=icInterpLinear,
+ bool buseMpeTags=true);
+};
+
+#ifdef USESAMPLEICCNAMESPACE
+}; //namespace sampleICC
+#endif
+
+#endif // !defined(_ICCCMM_H)
diff --git a/library/src/main/cpp/icc/IccIO.cpp b/library/src/main/cpp/icc/IccIO.cpp
new file mode 100644
index 00000000..1efa9111
--- /dev/null
+++ b/library/src/main/cpp/icc/IccIO.cpp
@@ -0,0 +1,712 @@
+/** @file
+ File: IccIO.cpp
+
+ Contains: Implementation of the CIccIO class.
+
+ Version: V1
+
+ Copyright: see ICC Software License
+*/
+
+/*
+ * The ICC Software License, Version 0.2
+ *
+ *
+ * Copyright (c) 2003-2015 The International Color Consortium. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. In the absence of prior written permission, the names "ICC" and "The
+ * International Color Consortium" must not be used to imply that the
+ * ICC organization endorses or promotes products derived from this
+ * software.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR
+ * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the The International Color Consortium.
+ *
+ *
+ * Membership in the ICC is encouraged when this software is used for
+ * commercial purposes.
+ *
+ *
+ * For more information on The International Color Consortium, please
+ * see .
+ *
+ *
+ */
+
+//////////////////////////////////////////////////////////////////////
+// HISTORY:
+//
+// -Initial implementation by Max Derhak 5-15-2003
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "IccIO.h"
+#include "IccUtil.h"
+#include
+#include
+#include
+
+#ifndef __max
+#define __max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+#ifndef __min
+#define __min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifdef USESAMPLEICCNAMESPACE
+namespace sampleICC {
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Class CIccIO
+//////////////////////////////////////////////////////////////////////
+
+
+icInt32Number CIccIO::ReadLine(void *pBuf8, icInt32Number nNum/*=256*/)
+{
+ icInt32Number n=0;
+ icInt8Number c, *ptr=(icInt8Number*)pBuf8;
+
+ while(n>1;
+ icSwab16Array(pBuf16, nNum);
+
+ return nNum;
+}
+
+icInt32Number CIccIO::Write16(void *pBuf16, icInt32Number nNum)
+{
+#ifndef ICC_BYTE_ORDER_LITTLE_ENDIAN
+ return Write8(pBuf16, nNum<<1)>>1;
+#else
+ icUInt16Number *ptr = (icUInt16Number*)pBuf16;
+ icUInt16Number tmp;
+ icInt32Number i;
+
+ for (i=0; i>2;
+ icSwab32Array(pBuf32, nNum);
+
+ return nNum;
+}
+
+
+icInt32Number CIccIO::Write32(void *pBuf32, icInt32Number nNum)
+{
+#ifndef ICC_BYTE_ORDER_LITTLE_ENDIAN
+ return Write8(pBuf32, nNum<<2)>>2;
+#else
+ icUInt32Number *ptr = (icUInt32Number*)pBuf32;
+ icUInt32Number tmp;
+ icInt32Number i;
+
+ for (i=0; i>3;
+ icSwab64Array(pBuf64, nNum);
+
+ return nNum;
+}
+
+
+icInt32Number CIccIO::Write64(void *pBuf64, icInt32Number nNum)
+{
+#ifndef ICC_BYTE_ORDER_LITTLE_ENDIAN
+ return Write8(pBuf64, nNum<<3)>>3;
+#else
+ icUInt64Number *ptr = (icUInt64Number*)pBuf64;
+ icUInt64Number tmp;
+ icInt32Number i;
+
+ for (i=0; i>2)<<2;
+ if (Seek(nPos + nOffset, icSeekSet)<0)
+ return false;
+ return true;
+}
+
+
+//////////////////////////////////////////////////////////////////////
+// Class CIccFileIO
+//////////////////////////////////////////////////////////////////////
+
+CIccFileIO::CIccFileIO() : CIccIO()
+{
+ m_fFile = NULL;
+}
+
+CIccFileIO::~CIccFileIO()
+{
+ Close();
+}
+
+bool CIccFileIO::Open(const icChar *szFilename, const icChar *szAttr)
+{
+#if defined(WIN32) || defined(WIN64)
+ char myAttr[20];
+
+ if (!strchr(szAttr, 'b')) {
+ myAttr[0] = szAttr[0];
+ myAttr[1] = 'b';
+ strcpy(myAttr+2, szAttr+1);
+ szAttr = myAttr;
+ }
+#endif
+
+ if (m_fFile)
+ fclose(m_fFile);
+
+ m_fFile = fopen(szFilename, szAttr);
+
+ return m_fFile != NULL;
+}
+
+
+#if defined(WIN32) || defined(WIN64)
+bool CIccFileIO::Open(const icWChar *szFilename, const icWChar *szAttr)
+{
+ icWChar myAttr[20];
+
+ if (!wcschr(szAttr, 'b')) {
+ myAttr[0] = szAttr[0];
+ myAttr[1] = 'b';
+ wcscpy(myAttr+2, szAttr+1);
+ szAttr = myAttr;
+ }
+
+ if (m_fFile)
+ fclose(m_fFile);
+
+ m_fFile = _wfopen(szFilename, szAttr);
+
+ return m_fFile != NULL;
+}
+#endif
+
+
+void CIccFileIO::Close()
+{
+ if (m_fFile) {
+ fclose(m_fFile);
+ m_fFile = NULL;
+ }
+}
+
+
+icInt32Number CIccFileIO::Read8(void *pBuf, icInt32Number nNum)
+{
+ if (!m_fFile)
+ return 0;
+
+ return (icInt32Number)fread(pBuf, 1, nNum, m_fFile);
+}
+
+
+icInt32Number CIccFileIO::Write8(void *pBuf, icInt32Number nNum)
+{
+ if (!m_fFile)
+ return 0;
+
+ return (icInt32Number)fwrite(pBuf, 1, nNum, m_fFile);
+}
+
+
+icInt32Number CIccFileIO::GetLength()
+{
+ if (!m_fFile)
+ return 0;
+
+ fflush(m_fFile);
+ icInt32Number current = ftell(m_fFile), end;
+ fseek (m_fFile, 0, SEEK_END);
+ end = ftell(m_fFile);
+ fseek (m_fFile, current, SEEK_SET);
+ return end;
+}
+
+
+icInt32Number CIccFileIO::Seek(icInt32Number nOffset, icSeekVal pos)
+{
+ if (!m_fFile)
+ return -1;
+
+ return !fseek(m_fFile, nOffset, pos) ? ftell(m_fFile) : -1;
+}
+
+
+icInt32Number CIccFileIO::Tell()
+{
+ if (!m_fFile)
+ return -1;
+
+ return ftell(m_fFile);
+}
+
+
+//////////////////////////////////////////////////////////////////////
+// Class CIccMemIO
+//////////////////////////////////////////////////////////////////////
+
+CIccMemIO::CIccMemIO() : CIccIO()
+{
+ m_pData = NULL;
+ m_nSize = 0;
+ m_nAvail = 0;
+ m_nPos = 0;
+
+ m_bFreeData = false;
+}
+
+CIccMemIO::~CIccMemIO()
+{
+ Close();
+}
+
+
+bool CIccMemIO::Alloc(icUInt32Number nSize, bool bWrite)
+{
+ if (m_pData)
+ Close();
+
+ icUInt8Number *pData = (icUInt8Number*)malloc(nSize);
+
+ if (!pData)
+ return false;
+
+ if (!Attach(pData, nSize, bWrite)) {
+ free(pData);
+ return false;
+ }
+
+ m_bFreeData = true;
+
+ return true;
+}
+
+
+bool CIccMemIO::Attach(icUInt8Number *pData, icUInt32Number nSize, bool bWrite)
+{
+ if (!pData)
+ return false;
+
+ if (m_pData)
+ Close();
+
+ m_pData = pData;
+ m_nPos = 0;
+
+ if (bWrite) {
+ m_nAvail = nSize;
+ m_nSize = 0;
+ }
+ else {
+ m_nAvail = m_nSize = nSize;
+ }
+
+ return true;
+}
+
+
+void CIccMemIO::Close()
+{
+ if (m_pData) {
+ if (m_bFreeData) {
+ free(m_pData);
+
+ m_bFreeData = false;
+ }
+ m_pData = NULL;
+ }
+}
+
+
+icInt32Number CIccMemIO::Read8(void *pBuf, icInt32Number nNum)
+{
+ if (!m_pData)
+ return 0;
+
+ nNum = __min((icInt32Number)(m_nSize-m_nPos), nNum);
+
+ memcpy(pBuf, m_pData+m_nPos, nNum);
+ m_nPos += nNum;
+
+ return nNum;
+}
+
+
+icInt32Number CIccMemIO::Write8(void *pBuf, icInt32Number nNum)
+{
+ if (!m_pData)
+ return 0;
+
+ nNum = __min((icInt32Number)(m_nAvail-m_nPos), nNum);
+
+ memcpy(m_pData + m_nPos, pBuf, nNum);
+
+ m_nPos += nNum;
+ if (m_nPos > m_nSize)
+ m_nSize = m_nPos;
+
+ return nNum;
+}
+
+
+icInt32Number CIccMemIO::GetLength()
+{
+ if (!m_pData)
+ return 0;
+
+ return m_nSize;
+}
+
+
+icInt32Number CIccMemIO::Seek(icInt32Number nOffset, icSeekVal pos)
+{
+ if (!m_pData)
+ return -1;
+
+ icInt32Number nPos;
+ switch(pos) {
+ case icSeekSet:
+ nPos = nOffset;
+ break;
+ case icSeekCur:
+ nPos = (icInt32Number)m_nPos + nOffset;
+ break;
+ case icSeekEnd:
+ nPos = (icInt32Number)m_nSize + nOffset;
+ break;
+ default:
+ nPos = 0;
+ break;
+ }
+
+ if (nPos < 0)
+ return -1;
+
+ icUInt32Number uPos = (icUInt32Number)nPos;
+
+ if (uPos > m_nSize && m_nSize != m_nAvail && uPos <=m_nAvail) {
+ memset(m_pData+m_nSize, 0, (icInt32Number)(uPos - m_nSize));
+ m_nSize = uPos;
+ }
+ if (uPos > m_nSize)
+ return -1;
+
+ m_nPos = uPos;
+
+ return nPos;
+}
+
+
+icInt32Number CIccMemIO::Tell()
+{
+ if (!m_pData)
+ return -1;
+
+ return (icInt32Number)m_nPos;
+}
+
+///////////////////////////////
+
+//////////////////////////////////////////////////////////////////////
+// Class CIccNullIO
+//////////////////////////////////////////////////////////////////////
+
+CIccNullIO::CIccNullIO() : CIccIO()
+{
+ m_nSize = 0;
+ m_nPos = 0;
+}
+
+CIccNullIO::~CIccNullIO()
+{
+ Close();
+}
+
+
+void CIccNullIO::Open()
+{
+ m_nPos = 0;
+ m_nSize = 0;
+}
+
+
+void CIccNullIO::Close()
+{
+}
+
+
+icInt32Number CIccNullIO::Read8(void *pBuf, icInt32Number nNum)
+{
+ icInt32Number nLeft = m_nSize - m_nPos;
+ icInt32Number nRead = (nNum <= (icInt32Number)nLeft) ? nNum : nLeft;
+
+ memset(pBuf, 0, nRead);
+ m_nPos += nRead;
+
+ return nRead;
+}
+
+
+icInt32Number CIccNullIO::Write8(void *pBuf, icInt32Number nNum)
+{
+ m_nPos += nNum;
+ if (m_nPos > m_nSize)
+ m_nSize = m_nPos;
+
+ return nNum;
+}
+
+
+icInt32Number CIccNullIO::GetLength()
+{
+ return m_nSize;
+}
+
+
+icInt32Number CIccNullIO::Seek(icInt32Number nOffset, icSeekVal pos)
+{
+ icInt32Number nPos;
+ switch(pos) {
+ case icSeekSet:
+ nPos = nOffset;
+ break;
+ case icSeekCur:
+ nPos = (icInt32Number)m_nPos + nOffset;
+ break;
+ case icSeekEnd:
+ nPos = (icInt32Number)m_nSize + nOffset;
+ break;
+ default:
+ nPos = 0;
+ break;
+ }
+
+ if (nPos < 0)
+ return -1;
+
+ m_nPos = (icUInt32Number)nPos;
+
+ if (m_nPos>m_nSize)
+ m_nSize = m_nPos;
+
+ return nPos;
+}
+
+
+icInt32Number CIccNullIO::Tell()
+{
+ return (icInt32Number)m_nPos;
+}
+
+
+#ifdef USESAMPLEICCNAMESPACE
+} //namespace sampleICC
+#endif
diff --git a/library/src/main/cpp/icc/IccIO.h b/library/src/main/cpp/icc/IccIO.h
new file mode 100644
index 00000000..7ae8b616
--- /dev/null
+++ b/library/src/main/cpp/icc/IccIO.h
@@ -0,0 +1,243 @@
+/** @file
+ File: IccIO.h
+
+ Contains: Implementation of the CIccIO class.
+
+ Version: V1
+
+ Copyright: see ICC Software License
+*/
+
+/*
+ * The ICC Software License, Version 0.2
+ *
+ *
+ * Copyright (c) 2003-2015 The International Color Consortium. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. In the absence of prior written permission, the names "ICC" and "The
+ * International Color Consortium" must not be used to imply that the
+ * ICC organization endorses or promotes products derived from this
+ * software.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR
+ * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the The International Color Consortium.
+ *
+ *
+ * Membership in the ICC is encouraged when this software is used for
+ * commercial purposes.
+ *
+ *
+ * For more information on The International Color Consortium, please
+ * see .
+ *
+ *
+ */
+
+//////////////////////////////////////////////////////////////////////
+// HISTORY:
+//
+// -Initial implementation by Max Derhak 5-15-2003
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(_ICCIO_H)
+#define _ICCIO_H
+
+#include "IccDefs.h"
+#include "stdio.h"
+
+#ifdef USESAMPLEICCNAMESPACE
+namespace sampleICC {
+#endif
+
+///Seek types
+typedef enum {
+ icSeekSet=0, //Seek to an absolute position
+ icSeekCur, //Seek to relative position
+ icSeekEnd, //Seek relative to the ending
+} icSeekVal;
+
+/**
+ **************************************************************************
+ * Type: Class
+ *
+ * Purpose:
+ * This is the base object that handles the IO with an ICC profile.
+ **************************************************************************
+ */
+class ICCPROFLIB_API CIccIO
+{
+public:
+
+ virtual ~CIccIO() {}
+
+ virtual void Close() {}
+
+ virtual icInt32Number Read8(void *pBuf8, icInt32Number nNum=1) { return 0; }
+ virtual icInt32Number Write8(void *pBuf8, icInt32Number nNum=1) { return 0; }
+
+ icInt32Number ReadLine(void *pBuf8, icInt32Number nNum=256);
+
+ icInt32Number Read16(void *pBuf16, icInt32Number nNum=1);
+ icInt32Number Write16(void *pBuf16, icInt32Number nNum=1);
+
+ icInt32Number Read32(void *pBuf32, icInt32Number nNum=1);
+ icInt32Number Write32(void *pBuf32, icInt32Number nNum=1);
+
+ icInt32Number Read64(void *pBuf64, icInt32Number nNum=1);
+ icInt32Number Write64(void *pBuf64, icInt32Number nNum=1);
+
+ icInt32Number Read8Float(void *pBufFloat, icInt32Number nNum=1);
+ icInt32Number Write8Float(void *pBuf16, icInt32Number nNum=1);
+
+ icInt32Number Read16Float(void *pBufFloat, icInt32Number nNum=1);
+ icInt32Number Write16Float(void *pBuf16, icInt32Number nNum=1);
+
+ icInt32Number ReadFloat32Float(void *pBufFloat, icInt32Number nNum=1);
+ icInt32Number WriteFloat32Float(void *pBufFloat, icInt32Number nNum=1);
+
+ virtual icInt32Number GetLength() {return 0;}
+
+ virtual icInt32Number Seek(icInt32Number nOffset, icSeekVal pos) {return -1;}
+ virtual icInt32Number Tell() {return 0;}
+
+ ///Write operation to make sure that filelength is evenly divisible by 4
+ bool Align32();
+
+ ///Operation to make sure read position is evenly divisible by 4
+ bool Sync32(icUInt32Number nOffset=0);
+};
+
+/**
+ **************************************************************************
+ * Type: Class
+ *
+ * Purpose: Handles generic File IO
+ **************************************************************************
+ */
+class ICCPROFLIB_API CIccFileIO : public CIccIO
+{
+public:
+ CIccFileIO();
+ virtual ~CIccFileIO();
+
+ bool Open(const icChar *szFilename, const icChar *szAttr);
+#if defined(WIN32) || defined(WIN64)
+ bool Open(const icWChar *szFilename, const icWChar *szAttr);
+#endif
+ virtual void Close();
+
+ virtual icInt32Number Read8(void *pBuf, icInt32Number nNum=1);
+ virtual icInt32Number Write8(void *pBuf, icInt32Number nNum=1);
+
+ virtual icInt32Number GetLength();
+
+ virtual icInt32Number Seek(icInt32Number nOffset, icSeekVal pos);
+ virtual icInt32Number Tell();
+
+protected:
+ FILE *m_fFile;
+};
+
+/**
+ **************************************************************************
+ * Type: Class
+ *
+ * Purpose: Handles generic memory IO
+ **************************************************************************
+ */
+class ICCPROFLIB_API CIccMemIO : public CIccIO
+{
+public:
+ CIccMemIO();
+ virtual ~CIccMemIO();
+
+ bool Alloc(icUInt32Number nSize, bool bWrite = false);
+
+ bool Attach(icUInt8Number *pData, icUInt32Number nSize, bool bWrite=false);
+ virtual void Close();
+
+ virtual icInt32Number Read8(void *pBuf, icInt32Number nNum=1);
+ virtual icInt32Number Write8(void *pBuf, icInt32Number nNum=1);
+
+ virtual icInt32Number GetLength();
+
+ virtual icInt32Number Seek(icInt32Number nOffset, icSeekVal pos);
+ virtual icInt32Number Tell();
+
+ icUInt8Number *GetData() { return m_pData; }
+
+protected:
+ icUInt8Number *m_pData;
+ icUInt32Number m_nSize;
+ icUInt32Number m_nAvail;
+ icUInt32Number m_nPos;
+
+ bool m_bFreeData;
+};
+
+/**
+ **************************************************************************
+ * Type: Class
+ *
+ * Purpose: Handles simulated File IO
+ **************************************************************************
+ */
+class ICCPROFLIB_API CIccNullIO : public CIccIO
+{
+public:
+ CIccNullIO();
+ virtual ~CIccNullIO();
+
+ //Open resets the file to being zero size
+ void Open();
+ virtual void Close();
+
+
+ virtual icInt32Number Read8(void *pBuf, icInt32Number nNum=1); //Read zero's into buf
+ virtual icInt32Number Write8(void *pBuf, icInt32Number nNum=1);
+
+ virtual icInt32Number GetLength();
+
+ virtual icInt32Number Seek(icInt32Number nOffset, icSeekVal pos);
+ virtual icInt32Number Tell();
+
+protected:
+ icUInt32Number m_nSize;
+ icUInt32Number m_nPos;
+};
+
+
+#ifdef USESAMPLEICCNAMESPACE
+} //namespace sampleICC
+#endif
+
+#endif // !defined(_ICCIO_H)
diff --git a/library/src/main/cpp/icc/IccMpeACS.cpp b/library/src/main/cpp/icc/IccMpeACS.cpp
new file mode 100644
index 00000000..8e4354c3
--- /dev/null
+++ b/library/src/main/cpp/icc/IccMpeACS.cpp
@@ -0,0 +1,491 @@
+/** @file
+ File: IccMpeACS.cpp
+
+ Contains: Implementation of ACS Elements
+
+ Version: V1
+
+ Copyright: see ICC Software License
+*/
+
+/*
+ * The ICC Software License, Version 0.2
+ *
+ *
+ * Copyright (c) 2003-2015 The International Color Consortium. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. In the absence of prior written permission, the names "ICC" and "The
+ * International Color Consortium" must not be used to imply that the
+ * ICC organization endorses or promotes products derived from this
+ * software.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR
+ * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the The International Color Consortium.
+ *
+ *
+ * Membership in the ICC is encouraged when this software is used for
+ * commercial purposes.
+ *
+ *
+ * For more information on The International Color Consortium, please
+ * see .
+ *
+ *
+ */
+
+//////////////////////////////////////////////////////////////////////
+// HISTORY:
+//
+// -Initial implementation by Max Derhak 1-30-2006
+//
+//////////////////////////////////////////////////////////////////////
+
+#if defined(WIN32) || defined(WIN64)
+#pragma warning( disable: 4786) //disable warning in
+#endif
+
+#include
+#include
+#include
+#include
+#include "IccMpeACS.h"
+#include "IccIO.h"
+#include