diff options
Diffstat (limited to 'third_party/lcms2-2.6/src')
26 files changed, 0 insertions, 34524 deletions
diff --git a/third_party/lcms2-2.6/src/cmscam02.c b/third_party/lcms2-2.6/src/cmscam02.c deleted file mode 100644 index 9d874aa205..0000000000 --- a/third_party/lcms2-2.6/src/cmscam02.c +++ /dev/null @@ -1,486 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- -// - -#include "lcms2_internal.h" - -// CIECAM 02 appearance model. Many thanks to Jordi Vilar for the debugging. - -// ---------- Implementation -------------------------------------------- - -typedef struct { - - cmsFloat64Number XYZ[3]; - cmsFloat64Number RGB[3]; - cmsFloat64Number RGBc[3]; - cmsFloat64Number RGBp[3]; - cmsFloat64Number RGBpa[3]; - cmsFloat64Number a, b, h, e, H, A, J, Q, s, t, C, M; - cmsFloat64Number abC[2]; - cmsFloat64Number abs[2]; - cmsFloat64Number abM[2]; - -} CAM02COLOR; - -typedef struct { - - CAM02COLOR adoptedWhite; - cmsFloat64Number LA, Yb; - cmsFloat64Number F, c, Nc; - cmsUInt32Number surround; - cmsFloat64Number n, Nbb, Ncb, z, FL, D; - - cmsContext ContextID; - -} cmsCIECAM02; - - -static -cmsFloat64Number compute_n(cmsCIECAM02* pMod) -{ - return (pMod -> Yb / pMod -> adoptedWhite.XYZ[1]); -} - -static -cmsFloat64Number compute_z(cmsCIECAM02* pMod) -{ - return (1.48 + pow(pMod -> n, 0.5)); -} - -static -cmsFloat64Number computeNbb(cmsCIECAM02* pMod) -{ - return (0.725 * pow((1.0 / pMod -> n), 0.2)); -} - -static -cmsFloat64Number computeFL(cmsCIECAM02* pMod) -{ - cmsFloat64Number k, FL; - - k = 1.0 / ((5.0 * pMod->LA) + 1.0); - FL = 0.2 * pow(k, 4.0) * (5.0 * pMod->LA) + 0.1 * - (pow((1.0 - pow(k, 4.0)), 2.0)) * - (pow((5.0 * pMod->LA), (1.0 / 3.0))); - - return FL; -} - -static -cmsFloat64Number computeD(cmsCIECAM02* pMod) -{ - cmsFloat64Number D; - - D = pMod->F - (1.0/3.6)*(exp(((-pMod ->LA-42) / 92.0))); - - return D; -} - - -static -CAM02COLOR XYZtoCAT02(CAM02COLOR clr) -{ - clr.RGB[0] = (clr.XYZ[0] * 0.7328) + (clr.XYZ[1] * 0.4296) + (clr.XYZ[2] * -0.1624); - clr.RGB[1] = (clr.XYZ[0] * -0.7036) + (clr.XYZ[1] * 1.6975) + (clr.XYZ[2] * 0.0061); - clr.RGB[2] = (clr.XYZ[0] * 0.0030) + (clr.XYZ[1] * 0.0136) + (clr.XYZ[2] * 0.9834); - - return clr; -} - -static -CAM02COLOR ChromaticAdaptation(CAM02COLOR clr, cmsCIECAM02* pMod) -{ - cmsUInt32Number i; - - for (i = 0; i < 3; i++) { - clr.RGBc[i] = ((pMod -> adoptedWhite.XYZ[1] * - (pMod->D / pMod -> adoptedWhite.RGB[i])) + - (1.0 - pMod->D)) * clr.RGB[i]; - } - - return clr; -} - - -static -CAM02COLOR CAT02toHPE(CAM02COLOR clr) -{ - cmsFloat64Number M[9]; - - M[0] =(( 0.38971 * 1.096124) + (0.68898 * 0.454369) + (-0.07868 * -0.009628)); - M[1] =(( 0.38971 * -0.278869) + (0.68898 * 0.473533) + (-0.07868 * -0.005698)); - M[2] =(( 0.38971 * 0.182745) + (0.68898 * 0.072098) + (-0.07868 * 1.015326)); - M[3] =((-0.22981 * 1.096124) + (1.18340 * 0.454369) + ( 0.04641 * -0.009628)); - M[4] =((-0.22981 * -0.278869) + (1.18340 * 0.473533) + ( 0.04641 * -0.005698)); - M[5] =((-0.22981 * 0.182745) + (1.18340 * 0.072098) + ( 0.04641 * 1.015326)); - M[6] =(-0.009628); - M[7] =(-0.005698); - M[8] =( 1.015326); - - clr.RGBp[0] = (clr.RGBc[0] * M[0]) + (clr.RGBc[1] * M[1]) + (clr.RGBc[2] * M[2]); - clr.RGBp[1] = (clr.RGBc[0] * M[3]) + (clr.RGBc[1] * M[4]) + (clr.RGBc[2] * M[5]); - clr.RGBp[2] = (clr.RGBc[0] * M[6]) + (clr.RGBc[1] * M[7]) + (clr.RGBc[2] * M[8]); - - return clr; -} - -static -CAM02COLOR NonlinearCompression(CAM02COLOR clr, cmsCIECAM02* pMod) -{ - cmsUInt32Number i; - cmsFloat64Number temp; - - for (i = 0; i < 3; i++) { - if (clr.RGBp[i] < 0) { - - temp = pow((-1.0 * pMod->FL * clr.RGBp[i] / 100.0), 0.42); - clr.RGBpa[i] = (-1.0 * 400.0 * temp) / (temp + 27.13) + 0.1; - } - else { - temp = pow((pMod->FL * clr.RGBp[i] / 100.0), 0.42); - clr.RGBpa[i] = (400.0 * temp) / (temp + 27.13) + 0.1; - } - } - - clr.A = (((2.0 * clr.RGBpa[0]) + clr.RGBpa[1] + - (clr.RGBpa[2] / 20.0)) - 0.305) * pMod->Nbb; - - return clr; -} - -static -CAM02COLOR ComputeCorrelates(CAM02COLOR clr, cmsCIECAM02* pMod) -{ - cmsFloat64Number a, b, temp, e, t, r2d, d2r; - - a = clr.RGBpa[0] - (12.0 * clr.RGBpa[1] / 11.0) + (clr.RGBpa[2] / 11.0); - b = (clr.RGBpa[0] + clr.RGBpa[1] - (2.0 * clr.RGBpa[2])) / 9.0; - - r2d = (180.0 / 3.141592654); - if (a == 0) { - if (b == 0) clr.h = 0; - else if (b > 0) clr.h = 90; - else clr.h = 270; - } - else if (a > 0) { - temp = b / a; - if (b > 0) clr.h = (r2d * atan(temp)); - else if (b == 0) clr.h = 0; - else clr.h = (r2d * atan(temp)) + 360; - } - else { - temp = b / a; - clr.h = (r2d * atan(temp)) + 180; - } - - d2r = (3.141592654 / 180.0); - e = ((12500.0 / 13.0) * pMod->Nc * pMod->Ncb) * - (cos((clr.h * d2r + 2.0)) + 3.8); - - if (clr.h < 20.14) { - temp = ((clr.h + 122.47)/1.2) + ((20.14 - clr.h)/0.8); - clr.H = 300 + (100*((clr.h + 122.47)/1.2)) / temp; - } - else if (clr.h < 90.0) { - temp = ((clr.h - 20.14)/0.8) + ((90.00 - clr.h)/0.7); - clr.H = (100*((clr.h - 20.14)/0.8)) / temp; - } - else if (clr.h < 164.25) { - temp = ((clr.h - 90.00)/0.7) + ((164.25 - clr.h)/1.0); - clr.H = 100 + ((100*((clr.h - 90.00)/0.7)) / temp); - } - else if (clr.h < 237.53) { - temp = ((clr.h - 164.25)/1.0) + ((237.53 - clr.h)/1.2); - clr.H = 200 + ((100*((clr.h - 164.25)/1.0)) / temp); - } - else { - temp = ((clr.h - 237.53)/1.2) + ((360 - clr.h + 20.14)/0.8); - clr.H = 300 + ((100*((clr.h - 237.53)/1.2)) / temp); - } - - clr.J = 100.0 * pow((clr.A / pMod->adoptedWhite.A), - (pMod->c * pMod->z)); - - clr.Q = (4.0 / pMod->c) * pow((clr.J / 100.0), 0.5) * - (pMod->adoptedWhite.A + 4.0) * pow(pMod->FL, 0.25); - - t = (e * pow(((a * a) + (b * b)), 0.5)) / - (clr.RGBpa[0] + clr.RGBpa[1] + - ((21.0 / 20.0) * clr.RGBpa[2])); - - clr.C = pow(t, 0.9) * pow((clr.J / 100.0), 0.5) * - pow((1.64 - pow(0.29, pMod->n)), 0.73); - - clr.M = clr.C * pow(pMod->FL, 0.25); - clr.s = 100.0 * pow((clr.M / clr.Q), 0.5); - - return clr; -} - - -static -CAM02COLOR InverseCorrelates(CAM02COLOR clr, cmsCIECAM02* pMod) -{ - - cmsFloat64Number t, e, p1, p2, p3, p4, p5, hr, d2r; - d2r = 3.141592654 / 180.0; - - t = pow( (clr.C / (pow((clr.J / 100.0), 0.5) * - (pow((1.64 - pow(0.29, pMod->n)), 0.73)))), - (1.0 / 0.9) ); - e = ((12500.0 / 13.0) * pMod->Nc * pMod->Ncb) * - (cos((clr.h * d2r + 2.0)) + 3.8); - - clr.A = pMod->adoptedWhite.A * pow( - (clr.J / 100.0), - (1.0 / (pMod->c * pMod->z))); - - p1 = e / t; - p2 = (clr.A / pMod->Nbb) + 0.305; - p3 = 21.0 / 20.0; - - hr = clr.h * d2r; - - if (fabs(sin(hr)) >= fabs(cos(hr))) { - p4 = p1 / sin(hr); - clr.b = (p2 * (2.0 + p3) * (460.0 / 1403.0)) / - (p4 + (2.0 + p3) * (220.0 / 1403.0) * - (cos(hr) / sin(hr)) - (27.0 / 1403.0) + - p3 * (6300.0 / 1403.0)); - clr.a = clr.b * (cos(hr) / sin(hr)); - } - else { - p5 = p1 / cos(hr); - clr.a = (p2 * (2.0 + p3) * (460.0 / 1403.0)) / - (p5 + (2.0 + p3) * (220.0 / 1403.0) - - ((27.0 / 1403.0) - p3 * (6300.0 / 1403.0)) * - (sin(hr) / cos(hr))); - clr.b = clr.a * (sin(hr) / cos(hr)); - } - - clr.RGBpa[0] = ((460.0 / 1403.0) * p2) + - ((451.0 / 1403.0) * clr.a) + - ((288.0 / 1403.0) * clr.b); - clr.RGBpa[1] = ((460.0 / 1403.0) * p2) - - ((891.0 / 1403.0) * clr.a) - - ((261.0 / 1403.0) * clr.b); - clr.RGBpa[2] = ((460.0 / 1403.0) * p2) - - ((220.0 / 1403.0) * clr.a) - - ((6300.0 / 1403.0) * clr.b); - - return clr; -} - -static -CAM02COLOR InverseNonlinearity(CAM02COLOR clr, cmsCIECAM02* pMod) -{ - cmsUInt32Number i; - cmsFloat64Number c1; - - for (i = 0; i < 3; i++) { - if ((clr.RGBpa[i] - 0.1) < 0) c1 = -1; - else c1 = 1; - clr.RGBp[i] = c1 * (100.0 / pMod->FL) * - pow(((27.13 * fabs(clr.RGBpa[i] - 0.1)) / - (400.0 - fabs(clr.RGBpa[i] - 0.1))), - (1.0 / 0.42)); - } - - return clr; -} - -static -CAM02COLOR HPEtoCAT02(CAM02COLOR clr) -{ - cmsFloat64Number M[9]; - - M[0] = (( 0.7328 * 1.910197) + (0.4296 * 0.370950)); - M[1] = (( 0.7328 * -1.112124) + (0.4296 * 0.629054)); - M[2] = (( 0.7328 * 0.201908) + (0.4296 * 0.000008) - 0.1624); - M[3] = ((-0.7036 * 1.910197) + (1.6975 * 0.370950)); - M[4] = ((-0.7036 * -1.112124) + (1.6975 * 0.629054)); - M[5] = ((-0.7036 * 0.201908) + (1.6975 * 0.000008) + 0.0061); - M[6] = (( 0.0030 * 1.910197) + (0.0136 * 0.370950)); - M[7] = (( 0.0030 * -1.112124) + (0.0136 * 0.629054)); - M[8] = (( 0.0030 * 0.201908) + (0.0136 * 0.000008) + 0.9834);; - - clr.RGBc[0] = (clr.RGBp[0] * M[0]) + (clr.RGBp[1] * M[1]) + (clr.RGBp[2] * M[2]); - clr.RGBc[1] = (clr.RGBp[0] * M[3]) + (clr.RGBp[1] * M[4]) + (clr.RGBp[2] * M[5]); - clr.RGBc[2] = (clr.RGBp[0] * M[6]) + (clr.RGBp[1] * M[7]) + (clr.RGBp[2] * M[8]); - return clr; -} - - -static -CAM02COLOR InverseChromaticAdaptation(CAM02COLOR clr, cmsCIECAM02* pMod) -{ - cmsUInt32Number i; - for (i = 0; i < 3; i++) { - clr.RGB[i] = clr.RGBc[i] / - ((pMod->adoptedWhite.XYZ[1] * pMod->D / pMod->adoptedWhite.RGB[i]) + 1.0 - pMod->D); - } - return clr; -} - - -static -CAM02COLOR CAT02toXYZ(CAM02COLOR clr) -{ - clr.XYZ[0] = (clr.RGB[0] * 1.096124) + (clr.RGB[1] * -0.278869) + (clr.RGB[2] * 0.182745); - clr.XYZ[1] = (clr.RGB[0] * 0.454369) + (clr.RGB[1] * 0.473533) + (clr.RGB[2] * 0.072098); - clr.XYZ[2] = (clr.RGB[0] * -0.009628) + (clr.RGB[1] * -0.005698) + (clr.RGB[2] * 1.015326); - - return clr; -} - - -cmsHANDLE CMSEXPORT cmsCIECAM02Init(cmsContext ContextID, const cmsViewingConditions* pVC) -{ - cmsCIECAM02* lpMod; - - _cmsAssert(pVC != NULL); - - if((lpMod = (cmsCIECAM02*) _cmsMallocZero(ContextID, sizeof(cmsCIECAM02))) == NULL) { - return NULL; - } - - lpMod ->ContextID = ContextID; - - lpMod ->adoptedWhite.XYZ[0] = pVC ->whitePoint.X; - lpMod ->adoptedWhite.XYZ[1] = pVC ->whitePoint.Y; - lpMod ->adoptedWhite.XYZ[2] = pVC ->whitePoint.Z; - - lpMod -> LA = pVC ->La; - lpMod -> Yb = pVC ->Yb; - lpMod -> D = pVC ->D_value; - lpMod -> surround = pVC ->surround; - - switch (lpMod -> surround) { - - - case CUTSHEET_SURROUND: - lpMod->F = 0.8; - lpMod->c = 0.41; - lpMod->Nc = 0.8; - break; - - case DARK_SURROUND: - lpMod -> F = 0.8; - lpMod -> c = 0.525; - lpMod -> Nc = 0.8; - break; - - case DIM_SURROUND: - lpMod -> F = 0.9; - lpMod -> c = 0.59; - lpMod -> Nc = 0.95; - break; - - default: - // Average surround - lpMod -> F = 1.0; - lpMod -> c = 0.69; - lpMod -> Nc = 1.0; - } - - lpMod -> n = compute_n(lpMod); - lpMod -> z = compute_z(lpMod); - lpMod -> Nbb = computeNbb(lpMod); - lpMod -> FL = computeFL(lpMod); - - if (lpMod -> D == D_CALCULATE) { - lpMod -> D = computeD(lpMod); - } - - lpMod -> Ncb = lpMod -> Nbb; - - lpMod -> adoptedWhite = XYZtoCAT02(lpMod -> adoptedWhite); - lpMod -> adoptedWhite = ChromaticAdaptation(lpMod -> adoptedWhite, lpMod); - lpMod -> adoptedWhite = CAT02toHPE(lpMod -> adoptedWhite); - lpMod -> adoptedWhite = NonlinearCompression(lpMod -> adoptedWhite, lpMod); - - return (cmsHANDLE) lpMod; - -} - -void CMSEXPORT cmsCIECAM02Done(cmsHANDLE hModel) -{ - cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel; - - if (lpMod) _cmsFree(lpMod ->ContextID, lpMod); -} - - -void CMSEXPORT cmsCIECAM02Forward(cmsHANDLE hModel, const cmsCIEXYZ* pIn, cmsJCh* pOut) -{ - CAM02COLOR clr; - cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel; - - _cmsAssert(lpMod != NULL); - _cmsAssert(pIn != NULL); - _cmsAssert(pOut != NULL); - - memset(&clr, 0, sizeof(clr)); - - clr.XYZ[0] = pIn ->X; - clr.XYZ[1] = pIn ->Y; - clr.XYZ[2] = pIn ->Z; - - clr = XYZtoCAT02(clr); - clr = ChromaticAdaptation(clr, lpMod); - clr = CAT02toHPE(clr); - clr = NonlinearCompression(clr, lpMod); - clr = ComputeCorrelates(clr, lpMod); - - pOut ->J = clr.J; - pOut ->C = clr.C; - pOut ->h = clr.h; -} - -void CMSEXPORT cmsCIECAM02Reverse(cmsHANDLE hModel, const cmsJCh* pIn, cmsCIEXYZ* pOut) -{ - CAM02COLOR clr; - cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel; - - _cmsAssert(lpMod != NULL); - _cmsAssert(pIn != NULL); - _cmsAssert(pOut != NULL); - - memset(&clr, 0, sizeof(clr)); - - clr.J = pIn -> J; - clr.C = pIn -> C; - clr.h = pIn -> h; - - clr = InverseCorrelates(clr, lpMod); - clr = InverseNonlinearity(clr, lpMod); - clr = HPEtoCAT02(clr); - clr = InverseChromaticAdaptation(clr, lpMod); - clr = CAT02toXYZ(clr); - - pOut ->X = clr.XYZ[0]; - pOut ->Y = clr.XYZ[1]; - pOut ->Z = clr.XYZ[2]; -} diff --git a/third_party/lcms2-2.6/src/cmscgats.c b/third_party/lcms2-2.6/src/cmscgats.c deleted file mode 100644 index cce4cedbad..0000000000 --- a/third_party/lcms2-2.6/src/cmscgats.c +++ /dev/null @@ -1,2776 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- -// - -#include "lcms2_internal.h" - - -// IT8.7 / CGATS.17-200x handling ----------------------------------------------------------------------------- - - -#define MAXID 128 // Max length of identifier -#define MAXSTR 1024 // Max length of string -#define MAXTABLES 255 // Max Number of tables in a single stream -#define MAXINCLUDE 20 // Max number of nested includes - -#define DEFAULT_DBL_FORMAT "%.10g" // Double formatting - -#ifdef CMS_IS_WINDOWS_ -//sunliang.liu modified 2010426 for wince error -# ifndef _WIN32_WCE -# include <io.h> -# endif -# define DIR_CHAR '\\' -#else -# define DIR_CHAR '/' -#endif - - -// Symbols -typedef enum { - - SNONE, - SINUM, // Integer - SDNUM, // Real - SIDENT, // Identifier - SSTRING, // string - SCOMMENT, // comment - SEOLN, // End of line - SEOF, // End of stream - SSYNERROR, // Syntax error found on stream - - // Keywords - - SBEGIN_DATA, - SBEGIN_DATA_FORMAT, - SEND_DATA, - SEND_DATA_FORMAT, - SKEYWORD, - SDATA_FORMAT_ID, - SINCLUDE - - } SYMBOL; - - -// How to write the value -typedef enum { - - WRITE_UNCOOKED, - WRITE_STRINGIFY, - WRITE_HEXADECIMAL, - WRITE_BINARY, - WRITE_PAIR - - } WRITEMODE; - -// Linked list of variable names -typedef struct _KeyVal { - - struct _KeyVal* Next; - char* Keyword; // Name of variable - struct _KeyVal* NextSubkey; // If key is a dictionary, points to the next item - char* Subkey; // If key is a dictionary, points to the subkey name - char* Value; // Points to value - WRITEMODE WriteAs; // How to write the value - - } KEYVALUE; - - -// Linked list of memory chunks (Memory sink) -typedef struct _OwnedMem { - - struct _OwnedMem* Next; - void * Ptr; // Point to value - - } OWNEDMEM; - -// Suballocator -typedef struct _SubAllocator { - - cmsUInt8Number* Block; - cmsUInt32Number BlockSize; - cmsUInt32Number Used; - - } SUBALLOCATOR; - -// Table. Each individual table can hold properties and rows & cols -typedef struct _Table { - - char SheetType[MAXSTR]; // The first row of the IT8 (the type) - - int nSamples, nPatches; // Cols, Rows - int SampleID; // Pos of ID - - KEYVALUE* HeaderList; // The properties - - char** DataFormat; // The binary stream descriptor - char** Data; // The binary stream - - } TABLE; - -// File stream being parsed -typedef struct _FileContext { - char FileName[cmsMAX_PATH]; // File name if being readed from file - FILE* Stream; // File stream or NULL if holded in memory - } FILECTX; - -// This struct hold all information about an open IT8 handler. -typedef struct { - - - cmsUInt32Number TablesCount; // How many tables in this stream - cmsUInt32Number nTable; // The actual table - - TABLE Tab[MAXTABLES]; - - // Memory management - OWNEDMEM* MemorySink; // The storage backend - SUBALLOCATOR Allocator; // String suballocator -- just to keep it fast - - // Parser state machine - SYMBOL sy; // Current symbol - int ch; // Current character - - cmsInt32Number inum; // integer value - cmsFloat64Number dnum; // real value - - char id[MAXID]; // identifier - char str[MAXSTR]; // string - - // Allowed keywords & datasets. They have visibility on whole stream - KEYVALUE* ValidKeywords; - KEYVALUE* ValidSampleID; - - char* Source; // Points to loc. being parsed - cmsInt32Number lineno; // line counter for error reporting - - FILECTX* FileStack[MAXINCLUDE]; // Stack of files being parsed - cmsInt32Number IncludeSP; // Include Stack Pointer - - char* MemoryBlock; // The stream if holded in memory - - char DoubleFormatter[MAXID];// Printf-like 'cmsFloat64Number' formatter - - cmsContext ContextID; // The threading context - - } cmsIT8; - - -// The stream for save operations -typedef struct { - - FILE* stream; // For save-to-file behaviour - - cmsUInt8Number* Base; - cmsUInt8Number* Ptr; // For save-to-mem behaviour - cmsUInt32Number Used; - cmsUInt32Number Max; - - } SAVESTREAM; - - -// ------------------------------------------------------ cmsIT8 parsing routines - - -// A keyword -typedef struct { - - const char *id; - SYMBOL sy; - - } KEYWORD; - -// The keyword->symbol translation table. Sorting is required. -static const KEYWORD TabKeys[] = { - - {"$INCLUDE", SINCLUDE}, // This is an extension! - {".INCLUDE", SINCLUDE}, // This is an extension! - - {"BEGIN_DATA", SBEGIN_DATA }, - {"BEGIN_DATA_FORMAT", SBEGIN_DATA_FORMAT }, - {"DATA_FORMAT_IDENTIFIER", SDATA_FORMAT_ID}, - {"END_DATA", SEND_DATA}, - {"END_DATA_FORMAT", SEND_DATA_FORMAT}, - {"KEYWORD", SKEYWORD} - }; - -#define NUMKEYS (sizeof(TabKeys)/sizeof(KEYWORD)) - -// Predefined properties - -// A property -typedef struct { - const char *id; // The identifier - WRITEMODE as; // How is supposed to be written - } PROPERTY; - -static PROPERTY PredefinedProperties[] = { - - {"NUMBER_OF_FIELDS", WRITE_UNCOOKED}, // Required - NUMBER OF FIELDS - {"NUMBER_OF_SETS", WRITE_UNCOOKED}, // Required - NUMBER OF SETS - {"ORIGINATOR", WRITE_STRINGIFY}, // Required - Identifies the specific system, organization or individual that created the data file. - {"FILE_DESCRIPTOR", WRITE_STRINGIFY}, // Required - Describes the purpose or contents of the data file. - {"CREATED", WRITE_STRINGIFY}, // Required - Indicates date of creation of the data file. - {"DESCRIPTOR", WRITE_STRINGIFY}, // Required - Describes the purpose or contents of the data file. - {"DIFFUSE_GEOMETRY", WRITE_STRINGIFY}, // The diffuse geometry used. Allowed values are "sphere" or "opal". - {"MANUFACTURER", WRITE_STRINGIFY}, - {"MANUFACTURE", WRITE_STRINGIFY}, // Some broken Fuji targets does store this value - {"PROD_DATE", WRITE_STRINGIFY}, // Identifies year and month of production of the target in the form yyyy:mm. - {"SERIAL", WRITE_STRINGIFY}, // Uniquely identifies individual physical target. - - {"MATERIAL", WRITE_STRINGIFY}, // Identifies the material on which the target was produced using a code - // uniquely identifying th e material. This is intend ed to be used for IT8.7 - // physical targets only (i.e . IT8.7/1 a nd IT8.7/2). - - {"INSTRUMENTATION", WRITE_STRINGIFY}, // Used to report the specific instrumentation used (manufacturer and - // model number) to generate the data reported. This data will often - // provide more information about the particular data collected than an - // extensive list of specific details. This is particularly important for - // spectral data or data derived from spectrophotometry. - - {"MEASUREMENT_SOURCE", WRITE_STRINGIFY}, // Illumination used for spectral measurements. This data helps provide - // a guide to the potential for issues of paper fluorescence, etc. - - {"PRINT_CONDITIONS", WRITE_STRINGIFY}, // Used to define the characteristics of the printed sheet being reported. - // Where standard conditions have been defined (e.g., SWOP at nominal) - // named conditions may suffice. Otherwise, detailed information is - // needed. - - {"SAMPLE_BACKING", WRITE_STRINGIFY}, // Identifies the backing material used behind the sample during - // measurement. Allowed values are "black" "white" or "na". - - {"CHISQ_DOF", WRITE_STRINGIFY}, // Degrees of freedom associated with the Chi squared statistic - - // below properties are new in recent specs: - - {"MEASUREMENT_GEOMETRY", WRITE_STRINGIFY}, // The type of measurement, either reflection or transmission, should be indicated - // along with details of the geometry and the aperture size and shape. For example, - // for transmission measurements it is important to identify 0/diffuse, diffuse/0, - // opal or integrating sphere, etc. For reflection it is important to identify 0/45, - // 45/0, sphere (specular included or excluded), etc. - - {"FILTER", WRITE_STRINGIFY}, // Identifies the use of physical filter(s) during measurement. Typically used to - // denote the use of filters such as none, D65, Red, Green or Blue. - - {"POLARIZATION", WRITE_STRINGIFY}, // Identifies the use of a physical polarization filter during measurement. Allowed - // values are "yes" "white" "none" or "na" - - {"WEIGHTING_FUNCTION", WRITE_PAIR}, // Indicates such functions as: the CIE standard observer functions used in the - // calculation of various data parameters (2 degree and 10 degree), CIE standard - // illuminant functions used in the calculation of various data parameters (e.g., D50, - // D65, etc.), density status response, etc. If used there shall be at least one - // name-value pair following the WEIGHTING_FUNCTION tag/keyword. The first attribute - // in the set shall be {"name" and shall identify the particular parameter used. - // The second shall be {"value" and shall provide the value associated with that name. - // For ASCII data, a string containing the Name and Value attribute pairs shall follow - // the weighting function keyword. A semi-colon separates attribute pairs from each - // other and within the attribute the name and value are separated by a comma. - - {"COMPUTATIONAL_PARAMETER", WRITE_PAIR}, // Parameter that is used in computing a value from measured data. Name is the name - // of the calculation, parameter is the name of the parameter used in the calculation - // and value is the value of the parameter. - - {"TARGET_TYPE", WRITE_STRINGIFY}, // The type of target being measured, e.g. IT8.7/1, IT8.7/3, user defined, etc. - - {"COLORANT", WRITE_STRINGIFY}, // Identifies the colorant(s) used in creating the target. - - {"TABLE_DESCRIPTOR", WRITE_STRINGIFY}, // Describes the purpose or contents of a data table. - - {"TABLE_NAME", WRITE_STRINGIFY} // Provides a short name for a data table. -}; - -#define NUMPREDEFINEDPROPS (sizeof(PredefinedProperties)/sizeof(PROPERTY)) - - -// Predefined sample types on dataset -static const char* PredefinedSampleID[] = { - "SAMPLE_ID", // Identifies sample that data represents - "STRING", // Identifies label, or other non-machine readable value. - // Value must begin and end with a " symbol - - "CMYK_C", // Cyan component of CMYK data expressed as a percentage - "CMYK_M", // Magenta component of CMYK data expressed as a percentage - "CMYK_Y", // Yellow component of CMYK data expressed as a percentage - "CMYK_K", // Black component of CMYK data expressed as a percentage - "D_RED", // Red filter density - "D_GREEN", // Green filter density - "D_BLUE", // Blue filter density - "D_VIS", // Visual filter density - "D_MAJOR_FILTER", // Major filter d ensity - "RGB_R", // Red component of RGB data - "RGB_G", // Green component of RGB data - "RGB_B", // Blue com ponent of RGB data - "SPECTRAL_NM", // Wavelength of measurement expressed in nanometers - "SPECTRAL_PCT", // Percentage reflectance/transmittance - "SPECTRAL_DEC", // Reflectance/transmittance - "XYZ_X", // X component of tristimulus data - "XYZ_Y", // Y component of tristimulus data - "XYZ_Z", // Z component of tristimulus data - "XYY_X" // x component of chromaticity data - "XYY_Y", // y component of chromaticity data - "XYY_CAPY", // Y component of tristimulus data - "LAB_L", // L* component of Lab data - "LAB_A", // a* component of Lab data - "LAB_B", // b* component of Lab data - "LAB_C", // C*ab component of Lab data - "LAB_H", // hab component of Lab data - "LAB_DE", // CIE dE - "LAB_DE_94", // CIE dE using CIE 94 - "LAB_DE_CMC", // dE using CMC - "LAB_DE_2000", // CIE dE using CIE DE 2000 - "MEAN_DE", // Mean Delta E (LAB_DE) of samples compared to batch average - // (Used for data files for ANSI IT8.7/1 and IT8.7/2 targets) - "STDEV_X", // Standard deviation of X (tristimulus data) - "STDEV_Y", // Standard deviation of Y (tristimulus data) - "STDEV_Z", // Standard deviation of Z (tristimulus data) - "STDEV_L", // Standard deviation of L* - "STDEV_A", // Standard deviation of a* - "STDEV_B", // Standard deviation of b* - "STDEV_DE", // Standard deviation of CIE dE - "CHI_SQD_PAR"}; // The average of the standard deviations of L*, a* and b*. It is - // used to derive an estimate of the chi-squared parameter which is - // recommended as the predictor of the variability of dE - -#define NUMPREDEFINEDSAMPLEID (sizeof(PredefinedSampleID)/sizeof(char *)) - -//Forward declaration of some internal functions -static void* AllocChunk(cmsIT8* it8, cmsUInt32Number size); - -// Checks whatever c is a separator -static -cmsBool isseparator(int c) -{ - return (c == ' ') || (c == '\t') ; -} - -// Checks whatever c is a valid identifier char -static -cmsBool ismiddle(int c) -{ - return (!isseparator(c) && (c != '#') && (c !='\"') && (c != '\'') && (c > 32) && (c < 127)); -} - -// Checks whatsever c is a valid identifier middle char. -static -cmsBool isidchar(int c) -{ - return isalnum(c) || ismiddle(c); -} - -// Checks whatsever c is a valid identifier first char. -static -cmsBool isfirstidchar(int c) -{ - return !isdigit(c) && ismiddle(c); -} - -// Guess whether the supplied path looks like an absolute path -static -cmsBool isabsolutepath(const char *path) -{ - char ThreeChars[4]; - - if(path == NULL) - return FALSE; - if (path[0] == 0) - return FALSE; - - strncpy(ThreeChars, path, 3); - ThreeChars[3] = 0; - - if(ThreeChars[0] == DIR_CHAR) - return TRUE; - -#ifdef CMS_IS_WINDOWS_ - if (isalpha((int) ThreeChars[0]) && ThreeChars[1] == ':') - return TRUE; -#endif - return FALSE; -} - - -// Makes a file path based on a given reference path -// NOTE: this function doesn't check if the path exists or even if it's legal -static -cmsBool BuildAbsolutePath(const char *relPath, const char *basePath, char *buffer, cmsUInt32Number MaxLen) -{ - char *tail; - cmsUInt32Number len; - - // Already absolute? - if (isabsolutepath(relPath)) { - - strncpy(buffer, relPath, MaxLen); - buffer[MaxLen-1] = 0; - return TRUE; - } - - // No, search for last - strncpy(buffer, basePath, MaxLen); - buffer[MaxLen-1] = 0; - - tail = strrchr(buffer, DIR_CHAR); - if (tail == NULL) return FALSE; // Is not absolute and has no separators?? - - len = (cmsUInt32Number) (tail - buffer); - if (len >= MaxLen) return FALSE; - - // No need to assure zero terminator over here - strncpy(tail + 1, relPath, MaxLen - len); - - return TRUE; -} - - -// Make sure no exploit is being even tried -static -const char* NoMeta(const char* str) -{ - if (strchr(str, '%') != NULL) - return "**** CORRUPTED FORMAT STRING ***"; - - return str; -} - -// Syntax error -static -cmsBool SynError(cmsIT8* it8, const char *Txt, ...) -{ - char Buffer[256], ErrMsg[1024]; - va_list args; - - va_start(args, Txt); - vsnprintf(Buffer, 255, Txt, args); - Buffer[255] = 0; - va_end(args); - - snprintf(ErrMsg, 1023, "%s: Line %d, %s", it8->FileStack[it8 ->IncludeSP]->FileName, it8->lineno, Buffer); - ErrMsg[1023] = 0; - it8->sy = SSYNERROR; - cmsSignalError(it8 ->ContextID, cmsERROR_CORRUPTION_DETECTED, "%s", ErrMsg); - return FALSE; -} - -// Check if current symbol is same as specified. issue an error else. -static -cmsBool Check(cmsIT8* it8, SYMBOL sy, const char* Err) -{ - if (it8 -> sy != sy) - return SynError(it8, NoMeta(Err)); - return TRUE; -} - -// Read Next character from stream -static -void NextCh(cmsIT8* it8) -{ - if (it8 -> FileStack[it8 ->IncludeSP]->Stream) { - - it8 ->ch = fgetc(it8 ->FileStack[it8 ->IncludeSP]->Stream); - - if (feof(it8 -> FileStack[it8 ->IncludeSP]->Stream)) { - - if (it8 ->IncludeSP > 0) { - - fclose(it8 ->FileStack[it8->IncludeSP--]->Stream); - it8 -> ch = ' '; // Whitespace to be ignored - - } else - it8 ->ch = 0; // EOF - } - } - else { - it8->ch = *it8->Source; - if (it8->ch) it8->Source++; - } -} - - -// Try to see if current identifier is a keyword, if so return the referred symbol -static -SYMBOL BinSrchKey(const char *id) -{ - int l = 1; - int r = NUMKEYS; - int x, res; - - while (r >= l) - { - x = (l+r)/2; - res = cmsstrcasecmp(id, TabKeys[x-1].id); - if (res == 0) return TabKeys[x-1].sy; - if (res < 0) r = x - 1; - else l = x + 1; - } - - return SNONE; -} - - -// 10 ^n -static -cmsFloat64Number xpow10(int n) -{ - return pow(10, (cmsFloat64Number) n); -} - - -// Reads a Real number, tries to follow from integer number -static -void ReadReal(cmsIT8* it8, int inum) -{ - it8->dnum = (cmsFloat64Number) inum; - - while (isdigit(it8->ch)) { - - it8->dnum = it8->dnum * 10.0 + (it8->ch - '0'); - NextCh(it8); - } - - if (it8->ch == '.') { // Decimal point - - cmsFloat64Number frac = 0.0; // fraction - int prec = 0; // precision - - NextCh(it8); // Eats dec. point - - while (isdigit(it8->ch)) { - - frac = frac * 10.0 + (it8->ch - '0'); - prec++; - NextCh(it8); - } - - it8->dnum = it8->dnum + (frac / xpow10(prec)); - } - - // Exponent, example 34.00E+20 - if (toupper(it8->ch) == 'E') { - - cmsInt32Number e; - cmsInt32Number sgn; - - NextCh(it8); sgn = 1; - - if (it8->ch == '-') { - - sgn = -1; NextCh(it8); - } - else - if (it8->ch == '+') { - - sgn = +1; - NextCh(it8); - } - - e = 0; - while (isdigit(it8->ch)) { - - if ((cmsFloat64Number) e * 10L < (cmsFloat64Number) +2147483647.0) - e = e * 10 + (it8->ch - '0'); - - NextCh(it8); - } - - e = sgn*e; - it8 -> dnum = it8 -> dnum * xpow10(e); - } -} - -// Parses a float number -// This can not call directly atof because it uses locale dependant -// parsing, while CCMX files always use . as decimal separator -static -cmsFloat64Number ParseFloatNumber(const char *Buffer) -{ - cmsFloat64Number dnum = 0.0; - int sign = 1; - - // keep safe - if (Buffer == NULL) return 0.0; - - if (*Buffer == '-' || *Buffer == '+') { - - sign = (*Buffer == '-') ? -1 : 1; - Buffer++; - } - - - while (*Buffer && isdigit((int) *Buffer)) { - - dnum = dnum * 10.0 + (*Buffer - '0'); - if (*Buffer) Buffer++; - } - - if (*Buffer == '.') { - - cmsFloat64Number frac = 0.0; // fraction - int prec = 0; // precission - - if (*Buffer) Buffer++; - - while (*Buffer && isdigit((int) *Buffer)) { - - frac = frac * 10.0 + (*Buffer - '0'); - prec++; - if (*Buffer) Buffer++; - } - - dnum = dnum + (frac / xpow10(prec)); - } - - // Exponent, example 34.00E+20 - if (*Buffer && toupper(*Buffer) == 'E') { - - int e; - int sgn; - - if (*Buffer) Buffer++; - sgn = 1; - - if (*Buffer == '-') { - - sgn = -1; - if (*Buffer) Buffer++; - } - else - if (*Buffer == '+') { - - sgn = +1; - if (*Buffer) Buffer++; - } - - e = 0; - while (*Buffer && isdigit((int) *Buffer)) { - - if ((cmsFloat64Number) e * 10L < INT_MAX) - e = e * 10 + (*Buffer - '0'); - - if (*Buffer) Buffer++; - } - - e = sgn*e; - dnum = dnum * xpow10(e); - } - - return sign * dnum; -} - - -// Reads next symbol -static -void InSymbol(cmsIT8* it8) -{ - register char *idptr; - register int k; - SYMBOL key; - int sng; - - do { - - while (isseparator(it8->ch)) - NextCh(it8); - - if (isfirstidchar(it8->ch)) { // Identifier - - k = 0; - idptr = it8->id; - - do { - - if (++k < MAXID) *idptr++ = (char) it8->ch; - - NextCh(it8); - - } while (isidchar(it8->ch)); - - *idptr = '\0'; - - - key = BinSrchKey(it8->id); - if (key == SNONE) it8->sy = SIDENT; - else it8->sy = key; - - } - else // Is a number? - if (isdigit(it8->ch) || it8->ch == '.' || it8->ch == '-' || it8->ch == '+') - { - int sign = 1; - - if (it8->ch == '-') { - sign = -1; - NextCh(it8); - } - - it8->inum = 0; - it8->sy = SINUM; - - if (it8->ch == '0') { // 0xnnnn (Hexa) or 0bnnnn (Binary) - - NextCh(it8); - if (toupper(it8->ch) == 'X') { - - int j; - - NextCh(it8); - while (isxdigit(it8->ch)) - { - it8->ch = toupper(it8->ch); - if (it8->ch >= 'A' && it8->ch <= 'F') j = it8->ch -'A'+10; - else j = it8->ch - '0'; - - if ((long) it8->inum * 16L > (long) INT_MAX) - { - SynError(it8, "Invalid hexadecimal number"); - return; - } - - it8->inum = it8->inum * 16 + j; - NextCh(it8); - } - return; - } - - if (toupper(it8->ch) == 'B') { // Binary - - int j; - - NextCh(it8); - while (it8->ch == '0' || it8->ch == '1') - { - j = it8->ch - '0'; - - if ((long) it8->inum * 2L > (long) INT_MAX) - { - SynError(it8, "Invalid binary number"); - return; - } - - it8->inum = it8->inum * 2 + j; - NextCh(it8); - } - return; - } - } - - - while (isdigit(it8->ch)) { - - if ((cmsFloat64Number) it8->inum * 10L > (cmsFloat64Number) +2147483647.0) { - ReadReal(it8, it8->inum); - it8->sy = SDNUM; - it8->dnum *= sign; - return; - } - - it8->inum = it8->inum * 10 + (it8->ch - '0'); - NextCh(it8); - } - - if (it8->ch == '.') { - - ReadReal(it8, it8->inum); - it8->sy = SDNUM; - it8->dnum *= sign; - return; - } - - it8 -> inum *= sign; - - // Special case. Numbers followed by letters are taken as identifiers - - if (isidchar(it8 ->ch)) { - - if (it8 ->sy == SINUM) { - - sprintf(it8->id, "%d", it8->inum); - } - else { - - sprintf(it8->id, it8 ->DoubleFormatter, it8->dnum); - } - - k = (int) strlen(it8 ->id); - idptr = it8 ->id + k; - do { - - if (++k < MAXID) *idptr++ = (char) it8->ch; - - NextCh(it8); - - } while (isidchar(it8->ch)); - - *idptr = '\0'; - it8->sy = SIDENT; - } - return; - - } - else - switch ((int) it8->ch) { - - // EOF marker -- ignore it - case '\x1a': - NextCh(it8); - break; - - // Eof stream markers - case 0: - case -1: - it8->sy = SEOF; - break; - - - // Next line - case '\r': - NextCh(it8); - if (it8 ->ch == '\n') - NextCh(it8); - it8->sy = SEOLN; - it8->lineno++; - break; - - case '\n': - NextCh(it8); - it8->sy = SEOLN; - it8->lineno++; - break; - - // Comment - case '#': - NextCh(it8); - while (it8->ch && it8->ch != '\n' && it8->ch != '\r') - NextCh(it8); - - it8->sy = SCOMMENT; - break; - - // String. - case '\'': - case '\"': - idptr = it8->str; - sng = it8->ch; - k = 0; - NextCh(it8); - - while (k < MAXSTR && it8->ch != sng) { - - if (it8->ch == '\n'|| it8->ch == '\r') k = MAXSTR+1; - else { - *idptr++ = (char) it8->ch; - NextCh(it8); - k++; - } - } - - it8->sy = SSTRING; - *idptr = '\0'; - NextCh(it8); - break; - - - default: - SynError(it8, "Unrecognized character: 0x%x", it8 ->ch); - return; - } - - } while (it8->sy == SCOMMENT); - - // Handle the include special token - - if (it8 -> sy == SINCLUDE) { - - FILECTX* FileNest; - - if(it8 -> IncludeSP >= (MAXINCLUDE-1)) { - - SynError(it8, "Too many recursion levels"); - return; - } - - InSymbol(it8); - if (!Check(it8, SSTRING, "Filename expected")) return; - - FileNest = it8 -> FileStack[it8 -> IncludeSP + 1]; - if(FileNest == NULL) { - - FileNest = it8 ->FileStack[it8 -> IncludeSP + 1] = (FILECTX*)AllocChunk(it8, sizeof(FILECTX)); - //if(FileNest == NULL) - // TODO: how to manage out-of-memory conditions? - } - - if (BuildAbsolutePath(it8->str, - it8->FileStack[it8->IncludeSP]->FileName, - FileNest->FileName, cmsMAX_PATH-1) == FALSE) { - SynError(it8, "File path too long"); - return; - } - - FileNest->Stream = fopen(FileNest->FileName, "rt"); - if (FileNest->Stream == NULL) { - - SynError(it8, "File %s not found", FileNest->FileName); - return; - } - it8->IncludeSP++; - - it8 ->ch = ' '; - InSymbol(it8); - } - -} - -// Checks end of line separator -static -cmsBool CheckEOLN(cmsIT8* it8) -{ - if (!Check(it8, SEOLN, "Expected separator")) return FALSE; - while (it8 -> sy == SEOLN) - InSymbol(it8); - return TRUE; - -} - -// Skip a symbol - -static -void Skip(cmsIT8* it8, SYMBOL sy) -{ - if (it8->sy == sy && it8->sy != SEOF) - InSymbol(it8); -} - - -// Skip multiple EOLN -static -void SkipEOLN(cmsIT8* it8) -{ - while (it8->sy == SEOLN) { - InSymbol(it8); - } -} - - -// Returns a string holding current value -static -cmsBool GetVal(cmsIT8* it8, char* Buffer, cmsUInt32Number max, const char* ErrorTitle) -{ - switch (it8->sy) { - - case SEOLN: // Empty value - Buffer[0]=0; - break; - case SIDENT: strncpy(Buffer, it8->id, max); - Buffer[max-1]=0; - break; - case SINUM: snprintf(Buffer, max, "%d", it8 -> inum); break; - case SDNUM: snprintf(Buffer, max, it8->DoubleFormatter, it8 -> dnum); break; - case SSTRING: strncpy(Buffer, it8->str, max); - Buffer[max-1] = 0; - break; - - - default: - return SynError(it8, "%s", ErrorTitle); - } - - Buffer[max] = 0; - return TRUE; -} - -// ---------------------------------------------------------- Table - -static -TABLE* GetTable(cmsIT8* it8) -{ - if ((it8 -> nTable >= it8 ->TablesCount)) { - - SynError(it8, "Table %d out of sequence", it8 -> nTable); - return it8 -> Tab; - } - - return it8 ->Tab + it8 ->nTable; -} - -// ---------------------------------------------------------- Memory management - - -// Frees an allocator and owned memory -void CMSEXPORT cmsIT8Free(cmsHANDLE hIT8) -{ - cmsIT8* it8 = (cmsIT8*) hIT8; - - if (it8 == NULL) - return; - - if (it8->MemorySink) { - - OWNEDMEM* p; - OWNEDMEM* n; - - for (p = it8->MemorySink; p != NULL; p = n) { - - n = p->Next; - if (p->Ptr) _cmsFree(it8 ->ContextID, p->Ptr); - _cmsFree(it8 ->ContextID, p); - } - } - - if (it8->MemoryBlock) - _cmsFree(it8 ->ContextID, it8->MemoryBlock); - - _cmsFree(it8 ->ContextID, it8); -} - - -// Allocates a chunk of data, keep linked list -static -void* AllocBigBlock(cmsIT8* it8, cmsUInt32Number size) -{ - OWNEDMEM* ptr1; - void* ptr = _cmsMallocZero(it8->ContextID, size); - - if (ptr != NULL) { - - ptr1 = (OWNEDMEM*) _cmsMallocZero(it8 ->ContextID, sizeof(OWNEDMEM)); - - if (ptr1 == NULL) { - - _cmsFree(it8 ->ContextID, ptr); - return NULL; - } - - ptr1-> Ptr = ptr; - ptr1-> Next = it8 -> MemorySink; - it8 -> MemorySink = ptr1; - } - - return ptr; -} - - -// Suballocator. -static -void* AllocChunk(cmsIT8* it8, cmsUInt32Number size) -{ - cmsUInt32Number Free = it8 ->Allocator.BlockSize - it8 ->Allocator.Used; - cmsUInt8Number* ptr; - - size = _cmsALIGNMEM(size); - - if (size > Free) { - - if (it8 -> Allocator.BlockSize == 0) - - it8 -> Allocator.BlockSize = 20*1024; - else - it8 ->Allocator.BlockSize *= 2; - - if (it8 ->Allocator.BlockSize < size) - it8 ->Allocator.BlockSize = size; - - it8 ->Allocator.Used = 0; - it8 ->Allocator.Block = (cmsUInt8Number*) AllocBigBlock(it8, it8 ->Allocator.BlockSize); - } - - ptr = it8 ->Allocator.Block + it8 ->Allocator.Used; - it8 ->Allocator.Used += size; - - return (void*) ptr; - -} - - -// Allocates a string -static -char *AllocString(cmsIT8* it8, const char* str) -{ - cmsUInt32Number Size = (cmsUInt32Number) strlen(str)+1; - char *ptr; - - - ptr = (char *) AllocChunk(it8, Size); - if (ptr) strncpy (ptr, str, Size-1); - - return ptr; -} - -// Searches through linked list - -static -cmsBool IsAvailableOnList(KEYVALUE* p, const char* Key, const char* Subkey, KEYVALUE** LastPtr) -{ - if (LastPtr) *LastPtr = p; - - for (; p != NULL; p = p->Next) { - - if (LastPtr) *LastPtr = p; - - if (*Key != '#') { // Comments are ignored - - if (cmsstrcasecmp(Key, p->Keyword) == 0) - break; - } - } - - if (p == NULL) - return FALSE; - - if (Subkey == 0) - return TRUE; - - for (; p != NULL; p = p->NextSubkey) { - - if (p ->Subkey == NULL) continue; - - if (LastPtr) *LastPtr = p; - - if (cmsstrcasecmp(Subkey, p->Subkey) == 0) - return TRUE; - } - - return FALSE; -} - - - -// Add a property into a linked list -static -KEYVALUE* AddToList(cmsIT8* it8, KEYVALUE** Head, const char *Key, const char *Subkey, const char* xValue, WRITEMODE WriteAs) -{ - KEYVALUE* p; - KEYVALUE* last; - - - // Check if property is already in list - - if (IsAvailableOnList(*Head, Key, Subkey, &p)) { - - // This may work for editing properties - - // return SynError(it8, "duplicate key <%s>", Key); - } - else { - - last = p; - - // Allocate the container - p = (KEYVALUE*) AllocChunk(it8, sizeof(KEYVALUE)); - if (p == NULL) - { - SynError(it8, "AddToList: out of memory"); - return NULL; - } - - // Store name and value - p->Keyword = AllocString(it8, Key); - p->Subkey = (Subkey == NULL) ? NULL : AllocString(it8, Subkey); - - // Keep the container in our list - if (*Head == NULL) { - *Head = p; - } - else - { - if (Subkey != NULL && last != NULL) { - - last->NextSubkey = p; - - // If Subkey is not null, then last is the last property with the same key, - // but not necessarily is the last property in the list, so we need to move - // to the actual list end - while (last->Next != NULL) - last = last->Next; - } - - if (last != NULL) last->Next = p; - } - - p->Next = NULL; - p->NextSubkey = NULL; - } - - p->WriteAs = WriteAs; - - if (xValue != NULL) { - - p->Value = AllocString(it8, xValue); - } - else { - p->Value = NULL; - } - - return p; -} - -static -KEYVALUE* AddAvailableProperty(cmsIT8* it8, const char* Key, WRITEMODE as) -{ - return AddToList(it8, &it8->ValidKeywords, Key, NULL, NULL, as); -} - - -static -KEYVALUE* AddAvailableSampleID(cmsIT8* it8, const char* Key) -{ - return AddToList(it8, &it8->ValidSampleID, Key, NULL, NULL, WRITE_UNCOOKED); -} - - -static -void AllocTable(cmsIT8* it8) -{ - TABLE* t; - - t = it8 ->Tab + it8 ->TablesCount; - - t->HeaderList = NULL; - t->DataFormat = NULL; - t->Data = NULL; - - it8 ->TablesCount++; -} - - -cmsInt32Number CMSEXPORT cmsIT8SetTable(cmsHANDLE IT8, cmsUInt32Number nTable) -{ - cmsIT8* it8 = (cmsIT8*) IT8; - - if (nTable >= it8 ->TablesCount) { - - if (nTable == it8 ->TablesCount) { - - AllocTable(it8); - } - else { - SynError(it8, "Table %d is out of sequence", nTable); - return -1; - } - } - - it8 ->nTable = nTable; - - return (cmsInt32Number) nTable; -} - - - -// Init an empty container -cmsHANDLE CMSEXPORT cmsIT8Alloc(cmsContext ContextID) -{ - cmsIT8* it8; - cmsUInt32Number i; - - it8 = (cmsIT8*) _cmsMallocZero(ContextID, sizeof(cmsIT8)); - if (it8 == NULL) return NULL; - - AllocTable(it8); - - it8->MemoryBlock = NULL; - it8->MemorySink = NULL; - - it8 ->nTable = 0; - - it8->ContextID = ContextID; - it8->Allocator.Used = 0; - it8->Allocator.Block = NULL; - it8->Allocator.BlockSize = 0; - - it8->ValidKeywords = NULL; - it8->ValidSampleID = NULL; - - it8 -> sy = SNONE; - it8 -> ch = ' '; - it8 -> Source = NULL; - it8 -> inum = 0; - it8 -> dnum = 0.0; - - it8->FileStack[0] = (FILECTX*)AllocChunk(it8, sizeof(FILECTX)); - it8->IncludeSP = 0; - it8 -> lineno = 1; - - strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT); - cmsIT8SetSheetType((cmsHANDLE) it8, "CGATS.17"); - - // Initialize predefined properties & data - - for (i=0; i < NUMPREDEFINEDPROPS; i++) - AddAvailableProperty(it8, PredefinedProperties[i].id, PredefinedProperties[i].as); - - for (i=0; i < NUMPREDEFINEDSAMPLEID; i++) - AddAvailableSampleID(it8, PredefinedSampleID[i]); - - - return (cmsHANDLE) it8; -} - - -const char* CMSEXPORT cmsIT8GetSheetType(cmsHANDLE hIT8) -{ - return GetTable((cmsIT8*) hIT8)->SheetType; -} - -cmsBool CMSEXPORT cmsIT8SetSheetType(cmsHANDLE hIT8, const char* Type) -{ - TABLE* t = GetTable((cmsIT8*) hIT8); - - strncpy(t ->SheetType, Type, MAXSTR-1); - t ->SheetType[MAXSTR-1] = 0; - return TRUE; -} - -cmsBool CMSEXPORT cmsIT8SetComment(cmsHANDLE hIT8, const char* Val) -{ - cmsIT8* it8 = (cmsIT8*) hIT8; - - if (!Val) return FALSE; - if (!*Val) return FALSE; - - return AddToList(it8, &GetTable(it8)->HeaderList, "# ", NULL, Val, WRITE_UNCOOKED) != NULL; -} - -// Sets a property -cmsBool CMSEXPORT cmsIT8SetPropertyStr(cmsHANDLE hIT8, const char* Key, const char *Val) -{ - cmsIT8* it8 = (cmsIT8*) hIT8; - - if (!Val) return FALSE; - if (!*Val) return FALSE; - - return AddToList(it8, &GetTable(it8)->HeaderList, Key, NULL, Val, WRITE_STRINGIFY) != NULL; -} - -cmsBool CMSEXPORT cmsIT8SetPropertyDbl(cmsHANDLE hIT8, const char* cProp, cmsFloat64Number Val) -{ - cmsIT8* it8 = (cmsIT8*) hIT8; - char Buffer[1024]; - - sprintf(Buffer, it8->DoubleFormatter, Val); - - return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_UNCOOKED) != NULL; -} - -cmsBool CMSEXPORT cmsIT8SetPropertyHex(cmsHANDLE hIT8, const char* cProp, cmsUInt32Number Val) -{ - cmsIT8* it8 = (cmsIT8*) hIT8; - char Buffer[1024]; - - sprintf(Buffer, "%u", Val); - - return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_HEXADECIMAL) != NULL; -} - -cmsBool CMSEXPORT cmsIT8SetPropertyUncooked(cmsHANDLE hIT8, const char* Key, const char* Buffer) -{ - cmsIT8* it8 = (cmsIT8*) hIT8; - - return AddToList(it8, &GetTable(it8)->HeaderList, Key, NULL, Buffer, WRITE_UNCOOKED) != NULL; -} - -cmsBool CMSEXPORT cmsIT8SetPropertyMulti(cmsHANDLE hIT8, const char* Key, const char* SubKey, const char *Buffer) -{ - cmsIT8* it8 = (cmsIT8*) hIT8; - - return AddToList(it8, &GetTable(it8)->HeaderList, Key, SubKey, Buffer, WRITE_PAIR) != NULL; -} - -// Gets a property -const char* CMSEXPORT cmsIT8GetProperty(cmsHANDLE hIT8, const char* Key) -{ - cmsIT8* it8 = (cmsIT8*) hIT8; - KEYVALUE* p; - - if (IsAvailableOnList(GetTable(it8) -> HeaderList, Key, NULL, &p)) - { - return p -> Value; - } - return NULL; -} - - -cmsFloat64Number CMSEXPORT cmsIT8GetPropertyDbl(cmsHANDLE hIT8, const char* cProp) -{ - const char *v = cmsIT8GetProperty(hIT8, cProp); - - if (v == NULL) return 0.0; - - return ParseFloatNumber(v); -} - -const char* CMSEXPORT cmsIT8GetPropertyMulti(cmsHANDLE hIT8, const char* Key, const char *SubKey) -{ - cmsIT8* it8 = (cmsIT8*) hIT8; - KEYVALUE* p; - - if (IsAvailableOnList(GetTable(it8) -> HeaderList, Key, SubKey, &p)) { - return p -> Value; - } - return NULL; -} - -// ----------------------------------------------------------------- Datasets - - -static -void AllocateDataFormat(cmsIT8* it8) -{ - TABLE* t = GetTable(it8); - - if (t -> DataFormat) return; // Already allocated - - t -> nSamples = (int) cmsIT8GetPropertyDbl(it8, "NUMBER_OF_FIELDS"); - - if (t -> nSamples <= 0) { - - SynError(it8, "AllocateDataFormat: Unknown NUMBER_OF_FIELDS"); - t -> nSamples = 10; - } - - t -> DataFormat = (char**) AllocChunk (it8, ((cmsUInt32Number) t->nSamples + 1) * sizeof(char *)); - if (t->DataFormat == NULL) { - - SynError(it8, "AllocateDataFormat: Unable to allocate dataFormat array"); - } - -} - -static -const char *GetDataFormat(cmsIT8* it8, int n) -{ - TABLE* t = GetTable(it8); - - if (t->DataFormat) - return t->DataFormat[n]; - - return NULL; -} - -static -cmsBool SetDataFormat(cmsIT8* it8, int n, const char *label) -{ - TABLE* t = GetTable(it8); - - if (!t->DataFormat) - AllocateDataFormat(it8); - - if (n > t -> nSamples) { - SynError(it8, "More than NUMBER_OF_FIELDS fields."); - return FALSE; - } - - if (t->DataFormat) { - t->DataFormat[n] = AllocString(it8, label); - } - - return TRUE; -} - - -cmsBool CMSEXPORT cmsIT8SetDataFormat(cmsHANDLE h, int n, const char *Sample) -{ - cmsIT8* it8 = (cmsIT8*) h; - return SetDataFormat(it8, n, Sample); -} - -static -void AllocateDataSet(cmsIT8* it8) -{ - TABLE* t = GetTable(it8); - - if (t -> Data) return; // Already allocated - - t-> nSamples = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS")); - t-> nPatches = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS")); - - t-> Data = (char**)AllocChunk (it8, ((cmsUInt32Number) t->nSamples + 1) * ((cmsUInt32Number) t->nPatches + 1) *sizeof (char*)); - if (t->Data == NULL) { - - SynError(it8, "AllocateDataSet: Unable to allocate data array"); - } - -} - -static -char* GetData(cmsIT8* it8, int nSet, int nField) -{ - TABLE* t = GetTable(it8); - int nSamples = t -> nSamples; - int nPatches = t -> nPatches; - - if (nSet >= nPatches || nField >= nSamples) - return NULL; - - if (!t->Data) return NULL; - return t->Data [nSet * nSamples + nField]; -} - -static -cmsBool SetData(cmsIT8* it8, int nSet, int nField, const char *Val) -{ - TABLE* t = GetTable(it8); - - if (!t->Data) - AllocateDataSet(it8); - - if (!t->Data) return FALSE; - - if (nSet > t -> nPatches || nSet < 0) { - - return SynError(it8, "Patch %d out of range, there are %d patches", nSet, t -> nPatches); - } - - if (nField > t ->nSamples || nField < 0) { - return SynError(it8, "Sample %d out of range, there are %d samples", nField, t ->nSamples); - - } - - t->Data [nSet * t -> nSamples + nField] = AllocString(it8, Val); - return TRUE; -} - - -// --------------------------------------------------------------- File I/O - - -// Writes a string to file -static -void WriteStr(SAVESTREAM* f, const char *str) -{ - cmsUInt32Number len; - - if (str == NULL) - str = " "; - - // Length to write - len = (cmsUInt32Number) strlen(str); - f ->Used += len; - - - if (f ->stream) { // Should I write it to a file? - - if (fwrite(str, 1, len, f->stream) != len) { - cmsSignalError(0, cmsERROR_WRITE, "Write to file error in CGATS parser"); - return; - } - - } - else { // Or to a memory block? - - if (f ->Base) { // Am I just counting the bytes? - - if (f ->Used > f ->Max) { - - cmsSignalError(0, cmsERROR_WRITE, "Write to memory overflows in CGATS parser"); - return; - } - - memmove(f ->Ptr, str, len); - f->Ptr += len; - } - - } -} - - -// Write formatted - -static -void Writef(SAVESTREAM* f, const char* frm, ...) -{ - char Buffer[4096]; - va_list args; - - va_start(args, frm); - vsnprintf(Buffer, 4095, frm, args); - Buffer[4095] = 0; - WriteStr(f, Buffer); - va_end(args); - -} - -// Writes full header -static -void WriteHeader(cmsIT8* it8, SAVESTREAM* fp) -{ - KEYVALUE* p; - TABLE* t = GetTable(it8); - - // Writes the type - WriteStr(fp, t->SheetType); - WriteStr(fp, "\n"); - - for (p = t->HeaderList; (p != NULL); p = p->Next) - { - if (*p ->Keyword == '#') { - - char* Pt; - - WriteStr(fp, "#\n# "); - for (Pt = p ->Value; *Pt; Pt++) { - - - Writef(fp, "%c", *Pt); - - if (*Pt == '\n') { - WriteStr(fp, "# "); - } - } - - WriteStr(fp, "\n#\n"); - continue; - } - - - if (!IsAvailableOnList(it8-> ValidKeywords, p->Keyword, NULL, NULL)) { - -#ifdef CMS_STRICT_CGATS - WriteStr(fp, "KEYWORD\t\""); - WriteStr(fp, p->Keyword); - WriteStr(fp, "\"\n"); -#endif - - AddAvailableProperty(it8, p->Keyword, WRITE_UNCOOKED); - } - - WriteStr(fp, p->Keyword); - if (p->Value) { - - switch (p ->WriteAs) { - - case WRITE_UNCOOKED: - Writef(fp, "\t%s", p ->Value); - break; - - case WRITE_STRINGIFY: - Writef(fp, "\t\"%s\"", p->Value ); - break; - - case WRITE_HEXADECIMAL: - Writef(fp, "\t0x%X", atoi(p ->Value)); - break; - - case WRITE_BINARY: - Writef(fp, "\t0x%B", atoi(p ->Value)); - break; - - case WRITE_PAIR: - Writef(fp, "\t\"%s,%s\"", p->Subkey, p->Value); - break; - - default: SynError(it8, "Unknown write mode %d", p ->WriteAs); - return; - } - } - - WriteStr (fp, "\n"); - } - -} - - -// Writes the data format -static -void WriteDataFormat(SAVESTREAM* fp, cmsIT8* it8) -{ - int i, nSamples; - TABLE* t = GetTable(it8); - - if (!t -> DataFormat) return; - - WriteStr(fp, "BEGIN_DATA_FORMAT\n"); - WriteStr(fp, " "); - nSamples = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS")); - - for (i = 0; i < nSamples; i++) { - - WriteStr(fp, t->DataFormat[i]); - WriteStr(fp, ((i == (nSamples-1)) ? "\n" : "\t")); - } - - WriteStr (fp, "END_DATA_FORMAT\n"); -} - - -// Writes data array -static -void WriteData(SAVESTREAM* fp, cmsIT8* it8) -{ - int i, j; - TABLE* t = GetTable(it8); - - if (!t->Data) return; - - WriteStr (fp, "BEGIN_DATA\n"); - - t->nPatches = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS")); - - for (i = 0; i < t-> nPatches; i++) { - - WriteStr(fp, " "); - - for (j = 0; j < t->nSamples; j++) { - - char *ptr = t->Data[i*t->nSamples+j]; - - if (ptr == NULL) WriteStr(fp, "\"\""); - else { - // If value contains whitespace, enclose within quote - - if (strchr(ptr, ' ') != NULL) { - - WriteStr(fp, "\""); - WriteStr(fp, ptr); - WriteStr(fp, "\""); - } - else - WriteStr(fp, ptr); - } - - WriteStr(fp, ((j == (t->nSamples-1)) ? "\n" : "\t")); - } - } - WriteStr (fp, "END_DATA\n"); -} - - - -// Saves whole file -cmsBool CMSEXPORT cmsIT8SaveToFile(cmsHANDLE hIT8, const char* cFileName) -{ - SAVESTREAM sd; - cmsUInt32Number i; - cmsIT8* it8 = (cmsIT8*) hIT8; - - memset(&sd, 0, sizeof(sd)); - - sd.stream = fopen(cFileName, "wt"); - if (!sd.stream) return FALSE; - - for (i=0; i < it8 ->TablesCount; i++) { - - cmsIT8SetTable(hIT8, i); - WriteHeader(it8, &sd); - WriteDataFormat(&sd, it8); - WriteData(&sd, it8); - } - - if (fclose(sd.stream) != 0) return FALSE; - - return TRUE; -} - - -// Saves to memory -cmsBool CMSEXPORT cmsIT8SaveToMem(cmsHANDLE hIT8, void *MemPtr, cmsUInt32Number* BytesNeeded) -{ - SAVESTREAM sd; - cmsUInt32Number i; - cmsIT8* it8 = (cmsIT8*) hIT8; - - memset(&sd, 0, sizeof(sd)); - - sd.stream = NULL; - sd.Base = (cmsUInt8Number*) MemPtr; - sd.Ptr = sd.Base; - - sd.Used = 0; - - if (sd.Base) - sd.Max = *BytesNeeded; // Write to memory? - else - sd.Max = 0; // Just counting the needed bytes - - for (i=0; i < it8 ->TablesCount; i++) { - - cmsIT8SetTable(hIT8, i); - WriteHeader(it8, &sd); - WriteDataFormat(&sd, it8); - WriteData(&sd, it8); - } - - sd.Used++; // The \0 at the very end - - if (sd.Base) - *sd.Ptr = 0; - - *BytesNeeded = sd.Used; - - return TRUE; -} - - -// -------------------------------------------------------------- Higer level parsing - -static -cmsBool DataFormatSection(cmsIT8* it8) -{ - int iField = 0; - TABLE* t = GetTable(it8); - - InSymbol(it8); // Eats "BEGIN_DATA_FORMAT" - CheckEOLN(it8); - - while (it8->sy != SEND_DATA_FORMAT && - it8->sy != SEOLN && - it8->sy != SEOF && - it8->sy != SSYNERROR) { - - if (it8->sy != SIDENT) { - - return SynError(it8, "Sample type expected"); - } - - if (!SetDataFormat(it8, iField, it8->id)) return FALSE; - iField++; - - InSymbol(it8); - SkipEOLN(it8); - } - - SkipEOLN(it8); - Skip(it8, SEND_DATA_FORMAT); - SkipEOLN(it8); - - if (iField != t ->nSamples) { - SynError(it8, "Count mismatch. NUMBER_OF_FIELDS was %d, found %d\n", t ->nSamples, iField); - - - } - - return TRUE; -} - - - -static -cmsBool DataSection (cmsIT8* it8) -{ - int iField = 0; - int iSet = 0; - char Buffer[256]; - TABLE* t = GetTable(it8); - - InSymbol(it8); // Eats "BEGIN_DATA" - CheckEOLN(it8); - - if (!t->Data) - AllocateDataSet(it8); - - while (it8->sy != SEND_DATA && it8->sy != SEOF) - { - if (iField >= t -> nSamples) { - iField = 0; - iSet++; - - } - - if (it8->sy != SEND_DATA && it8->sy != SEOF) { - - if (!GetVal(it8, Buffer, 255, "Sample data expected")) - return FALSE; - - if (!SetData(it8, iSet, iField, Buffer)) - return FALSE; - - iField++; - - InSymbol(it8); - SkipEOLN(it8); - } - } - - SkipEOLN(it8); - Skip(it8, SEND_DATA); - SkipEOLN(it8); - - // Check for data completion. - - if ((iSet+1) != t -> nPatches) - return SynError(it8, "Count mismatch. NUMBER_OF_SETS was %d, found %d\n", t ->nPatches, iSet+1); - - return TRUE; -} - - - - -static -cmsBool HeaderSection(cmsIT8* it8) -{ - char VarName[MAXID]; - char Buffer[MAXSTR]; - KEYVALUE* Key; - - while (it8->sy != SEOF && - it8->sy != SSYNERROR && - it8->sy != SBEGIN_DATA_FORMAT && - it8->sy != SBEGIN_DATA) { - - - switch (it8 -> sy) { - - case SKEYWORD: - InSymbol(it8); - if (!GetVal(it8, Buffer, MAXSTR-1, "Keyword expected")) return FALSE; - if (!AddAvailableProperty(it8, Buffer, WRITE_UNCOOKED)) return FALSE; - InSymbol(it8); - break; - - - case SDATA_FORMAT_ID: - InSymbol(it8); - if (!GetVal(it8, Buffer, MAXSTR-1, "Keyword expected")) return FALSE; - if (!AddAvailableSampleID(it8, Buffer)) return FALSE; - InSymbol(it8); - break; - - - case SIDENT: - strncpy(VarName, it8->id, MAXID-1); - VarName[MAXID-1] = 0; - - if (!IsAvailableOnList(it8-> ValidKeywords, VarName, NULL, &Key)) { - -#ifdef CMS_STRICT_CGATS - return SynError(it8, "Undefined keyword '%s'", VarName); -#else - Key = AddAvailableProperty(it8, VarName, WRITE_UNCOOKED); - if (Key == NULL) return FALSE; -#endif - } - - InSymbol(it8); - if (!GetVal(it8, Buffer, MAXSTR-1, "Property data expected")) return FALSE; - - if(Key->WriteAs != WRITE_PAIR) { - AddToList(it8, &GetTable(it8)->HeaderList, VarName, NULL, Buffer, - (it8->sy == SSTRING) ? WRITE_STRINGIFY : WRITE_UNCOOKED); - } - else { - const char *Subkey; - char *Nextkey; - if (it8->sy != SSTRING) - return SynError(it8, "Invalid value '%s' for property '%s'.", Buffer, VarName); - - // chop the string as a list of "subkey, value" pairs, using ';' as a separator - for (Subkey = Buffer; Subkey != NULL; Subkey = Nextkey) - { - char *Value, *temp; - - // identify token pair boundary - Nextkey = (char*) strchr(Subkey, ';'); - if(Nextkey) - *Nextkey++ = '\0'; - - // for each pair, split the subkey and the value - Value = (char*) strrchr(Subkey, ','); - if(Value == NULL) - return SynError(it8, "Invalid value for property '%s'.", VarName); - - // gobble the spaces before the coma, and the coma itself - temp = Value++; - do *temp-- = '\0'; while(temp >= Subkey && *temp == ' '); - - // gobble any space at the right - temp = Value + strlen(Value) - 1; - while(*temp == ' ') *temp-- = '\0'; - - // trim the strings from the left - Subkey += strspn(Subkey, " "); - Value += strspn(Value, " "); - - if(Subkey[0] == 0 || Value[0] == 0) - return SynError(it8, "Invalid value for property '%s'.", VarName); - AddToList(it8, &GetTable(it8)->HeaderList, VarName, Subkey, Value, WRITE_PAIR); - } - } - - InSymbol(it8); - break; - - - case SEOLN: break; - - default: - return SynError(it8, "expected keyword or identifier"); - } - - SkipEOLN(it8); - } - - return TRUE; - -} - - -static -void ReadType(cmsIT8* it8, char* SheetTypePtr) -{ - // First line is a very special case. - - while (isseparator(it8->ch)) - NextCh(it8); - - while (it8->ch != '\r' && it8 ->ch != '\n' && it8->ch != '\t' && it8 -> ch != -1) { - - *SheetTypePtr++= (char) it8 ->ch; - NextCh(it8); - } - - *SheetTypePtr = 0; -} - - -static -cmsBool ParseIT8(cmsIT8* it8, cmsBool nosheet) -{ - char* SheetTypePtr = it8 ->Tab[0].SheetType; - - if (nosheet == 0) { - ReadType(it8, SheetTypePtr); - } - - InSymbol(it8); - - SkipEOLN(it8); - - while (it8-> sy != SEOF && - it8-> sy != SSYNERROR) { - - switch (it8 -> sy) { - - case SBEGIN_DATA_FORMAT: - if (!DataFormatSection(it8)) return FALSE; - break; - - case SBEGIN_DATA: - - if (!DataSection(it8)) return FALSE; - - if (it8 -> sy != SEOF) { - - AllocTable(it8); - it8 ->nTable = it8 ->TablesCount - 1; - - // Read sheet type if present. We only support identifier and string. - // <ident> <eoln> is a type string - // anything else, is not a type string - if (nosheet == 0) { - - if (it8 ->sy == SIDENT) { - - // May be a type sheet or may be a prop value statement. We cannot use insymbol in - // this special case... - while (isseparator(it8->ch)) - NextCh(it8); - - // If a newline is found, then this is a type string - if (it8 ->ch == '\n' || it8->ch == '\r') { - - cmsIT8SetSheetType(it8, it8 ->id); - InSymbol(it8); - } - else - { - // It is not. Just continue - cmsIT8SetSheetType(it8, ""); - } - } - else - // Validate quoted strings - if (it8 ->sy == SSTRING) { - cmsIT8SetSheetType(it8, it8 ->str); - InSymbol(it8); - } - } - - } - break; - - case SEOLN: - SkipEOLN(it8); - break; - - default: - if (!HeaderSection(it8)) return FALSE; - } - - } - - return (it8 -> sy != SSYNERROR); -} - - - -// Init usefull pointers - -static -void CookPointers(cmsIT8* it8) -{ - int idField, i; - char* Fld; - cmsUInt32Number j; - cmsUInt32Number nOldTable = it8 ->nTable; - - for (j=0; j < it8 ->TablesCount; j++) { - - TABLE* t = it8 ->Tab + j; - - t -> SampleID = 0; - it8 ->nTable = j; - - for (idField = 0; idField < t -> nSamples; idField++) - { - if (t ->DataFormat == NULL){ - SynError(it8, "Undefined DATA_FORMAT"); - return; - } - - Fld = t->DataFormat[idField]; - if (!Fld) continue; - - - if (cmsstrcasecmp(Fld, "SAMPLE_ID") == 0) { - - t -> SampleID = idField; - - for (i=0; i < t -> nPatches; i++) { - - char *Data = GetData(it8, i, idField); - if (Data) { - char Buffer[256]; - - strncpy(Buffer, Data, 255); - Buffer[255] = 0; - - if (strlen(Buffer) <= strlen(Data)) - strcpy(Data, Buffer); - else - SetData(it8, i, idField, Buffer); - - } - } - - } - - // "LABEL" is an extension. It keeps references to forward tables - - if ((cmsstrcasecmp(Fld, "LABEL") == 0) || Fld[0] == '$' ) { - - // Search for table references... - for (i=0; i < t -> nPatches; i++) { - - char *Label = GetData(it8, i, idField); - - if (Label) { - - cmsUInt32Number k; - - // This is the label, search for a table containing - // this property - - for (k=0; k < it8 ->TablesCount; k++) { - - TABLE* Table = it8 ->Tab + k; - KEYVALUE* p; - - if (IsAvailableOnList(Table->HeaderList, Label, NULL, &p)) { - - // Available, keep type and table - char Buffer[256]; - - char *Type = p ->Value; - int nTable = (int) k; - - snprintf(Buffer, 255, "%s %d %s", Label, nTable, Type ); - - SetData(it8, i, idField, Buffer); - } - } - - - } - - } - - - } - - } - } - - it8 ->nTable = nOldTable; -} - -// Try to infere if the file is a CGATS/IT8 file at all. Read first line -// that should be something like some printable characters plus a \n -// returns 0 if this is not like a CGATS, or an integer otherwise. This integer is the number of words in first line? -static -int IsMyBlock(cmsUInt8Number* Buffer, int n) -{ - int words = 1, space = 0, quot = 0; - int i; - - if (n < 10) return 0; // Too small - - if (n > 132) - n = 132; - - for (i = 1; i < n; i++) { - - switch(Buffer[i]) - { - case '\n': - case '\r': - return ((quot == 1) || (words > 2)) ? 0 : words; - case '\t': - case ' ': - if(!quot && !space) - space = 1; - break; - case '\"': - quot = !quot; - break; - default: - if (Buffer[i] < 32) return 0; - if (Buffer[i] > 127) return 0; - words += space; - space = 0; - break; - } - } - - return 0; -} - - -static -cmsBool IsMyFile(const char* FileName) -{ - FILE *fp; - cmsUInt32Number Size; - cmsUInt8Number Ptr[133]; - - fp = fopen(FileName, "rt"); - if (!fp) { - cmsSignalError(0, cmsERROR_FILE, "File '%s' not found", FileName); - return FALSE; - } - - Size = (cmsUInt32Number) fread(Ptr, 1, 132, fp); - - if (fclose(fp) != 0) - return FALSE; - - Ptr[Size] = '\0'; - - return IsMyBlock(Ptr, Size); -} - -// ---------------------------------------------------------- Exported routines - - -cmsHANDLE CMSEXPORT cmsIT8LoadFromMem(cmsContext ContextID, void *Ptr, cmsUInt32Number len) -{ - cmsHANDLE hIT8; - cmsIT8* it8; - int type; - - _cmsAssert(Ptr != NULL); - _cmsAssert(len != 0); - - type = IsMyBlock((cmsUInt8Number*)Ptr, len); - if (type == 0) return NULL; - - hIT8 = cmsIT8Alloc(ContextID); - if (!hIT8) return NULL; - - it8 = (cmsIT8*) hIT8; - it8 ->MemoryBlock = (char*) _cmsMalloc(ContextID, len + 1); - - strncpy(it8 ->MemoryBlock, (const char*) Ptr, len); - it8 ->MemoryBlock[len] = 0; - - strncpy(it8->FileStack[0]->FileName, "", cmsMAX_PATH-1); - it8-> Source = it8 -> MemoryBlock; - - if (!ParseIT8(it8, type-1)) { - - cmsIT8Free(hIT8); - return FALSE; - } - - CookPointers(it8); - it8 ->nTable = 0; - - _cmsFree(ContextID, it8->MemoryBlock); - it8 -> MemoryBlock = NULL; - - return hIT8; - - -} - - -cmsHANDLE CMSEXPORT cmsIT8LoadFromFile(cmsContext ContextID, const char* cFileName) -{ - - cmsHANDLE hIT8; - cmsIT8* it8; - int type; - - _cmsAssert(cFileName != NULL); - - type = IsMyFile(cFileName); - if (type == 0) return NULL; - - hIT8 = cmsIT8Alloc(ContextID); - it8 = (cmsIT8*) hIT8; - if (!hIT8) return NULL; - - - it8 ->FileStack[0]->Stream = fopen(cFileName, "rt"); - - if (!it8 ->FileStack[0]->Stream) { - cmsIT8Free(hIT8); - return NULL; - } - - - strncpy(it8->FileStack[0]->FileName, cFileName, cmsMAX_PATH-1); - it8->FileStack[0]->FileName[cmsMAX_PATH-1] = 0; - - if (!ParseIT8(it8, type-1)) { - - fclose(it8 ->FileStack[0]->Stream); - cmsIT8Free(hIT8); - return NULL; - } - - CookPointers(it8); - it8 ->nTable = 0; - - if (fclose(it8 ->FileStack[0]->Stream)!= 0) { - cmsIT8Free(hIT8); - return NULL; - } - - return hIT8; - -} - -int CMSEXPORT cmsIT8EnumDataFormat(cmsHANDLE hIT8, char ***SampleNames) -{ - cmsIT8* it8 = (cmsIT8*) hIT8; - TABLE* t; - - _cmsAssert(hIT8 != NULL); - - t = GetTable(it8); - - if (SampleNames) - *SampleNames = t -> DataFormat; - return t -> nSamples; -} - - -cmsUInt32Number CMSEXPORT cmsIT8EnumProperties(cmsHANDLE hIT8, char ***PropertyNames) -{ - cmsIT8* it8 = (cmsIT8*) hIT8; - KEYVALUE* p; - cmsUInt32Number n; - char **Props; - TABLE* t; - - _cmsAssert(hIT8 != NULL); - - t = GetTable(it8); - - // Pass#1 - count properties - - n = 0; - for (p = t -> HeaderList; p != NULL; p = p->Next) { - n++; - } - - - Props = (char **) AllocChunk(it8, sizeof(char *) * n); - - // Pass#2 - Fill pointers - n = 0; - for (p = t -> HeaderList; p != NULL; p = p->Next) { - Props[n++] = p -> Keyword; - } - - *PropertyNames = Props; - return n; -} - -cmsUInt32Number CMSEXPORT cmsIT8EnumPropertyMulti(cmsHANDLE hIT8, const char* cProp, const char ***SubpropertyNames) -{ - cmsIT8* it8 = (cmsIT8*) hIT8; - KEYVALUE *p, *tmp; - cmsUInt32Number n; - const char **Props; - TABLE* t; - - _cmsAssert(hIT8 != NULL); - - - t = GetTable(it8); - - if(!IsAvailableOnList(t->HeaderList, cProp, NULL, &p)) { - *SubpropertyNames = 0; - return 0; - } - - // Pass#1 - count properties - - n = 0; - for (tmp = p; tmp != NULL; tmp = tmp->NextSubkey) { - if(tmp->Subkey != NULL) - n++; - } - - - Props = (const char **) AllocChunk(it8, sizeof(char *) * n); - - // Pass#2 - Fill pointers - n = 0; - for (tmp = p; tmp != NULL; tmp = tmp->NextSubkey) { - if(tmp->Subkey != NULL) - Props[n++] = p ->Subkey; - } - - *SubpropertyNames = Props; - return n; -} - -static -int LocatePatch(cmsIT8* it8, const char* cPatch) -{ - int i; - const char *data; - TABLE* t = GetTable(it8); - - for (i=0; i < t-> nPatches; i++) { - - data = GetData(it8, i, t->SampleID); - - if (data != NULL) { - - if (cmsstrcasecmp(data, cPatch) == 0) - return i; - } - } - - // SynError(it8, "Couldn't find patch '%s'\n", cPatch); - return -1; -} - - -static -int LocateEmptyPatch(cmsIT8* it8) -{ - int i; - const char *data; - TABLE* t = GetTable(it8); - - for (i=0; i < t-> nPatches; i++) { - - data = GetData(it8, i, t->SampleID); - - if (data == NULL) - return i; - - } - - return -1; -} - -static -int LocateSample(cmsIT8* it8, const char* cSample) -{ - int i; - const char *fld; - TABLE* t = GetTable(it8); - - for (i=0; i < t->nSamples; i++) { - - fld = GetDataFormat(it8, i); - if (cmsstrcasecmp(fld, cSample) == 0) - return i; - } - - return -1; - -} - - -int CMSEXPORT cmsIT8FindDataFormat(cmsHANDLE hIT8, const char* cSample) -{ - cmsIT8* it8 = (cmsIT8*) hIT8; - - _cmsAssert(hIT8 != NULL); - - return LocateSample(it8, cSample); -} - - - -const char* CMSEXPORT cmsIT8GetDataRowCol(cmsHANDLE hIT8, int row, int col) -{ - cmsIT8* it8 = (cmsIT8*) hIT8; - - _cmsAssert(hIT8 != NULL); - - return GetData(it8, row, col); -} - - -cmsFloat64Number CMSEXPORT cmsIT8GetDataRowColDbl(cmsHANDLE hIT8, int row, int col) -{ - const char* Buffer; - - Buffer = cmsIT8GetDataRowCol(hIT8, row, col); - - if (Buffer == NULL) return 0.0; - - return ParseFloatNumber(Buffer); -} - - -cmsBool CMSEXPORT cmsIT8SetDataRowCol(cmsHANDLE hIT8, int row, int col, const char* Val) -{ - cmsIT8* it8 = (cmsIT8*) hIT8; - - _cmsAssert(hIT8 != NULL); - - return SetData(it8, row, col, Val); -} - - -cmsBool CMSEXPORT cmsIT8SetDataRowColDbl(cmsHANDLE hIT8, int row, int col, cmsFloat64Number Val) -{ - cmsIT8* it8 = (cmsIT8*) hIT8; - char Buff[256]; - - _cmsAssert(hIT8 != NULL); - - sprintf(Buff, it8->DoubleFormatter, Val); - - return SetData(it8, row, col, Buff); -} - - - -const char* CMSEXPORT cmsIT8GetData(cmsHANDLE hIT8, const char* cPatch, const char* cSample) -{ - cmsIT8* it8 = (cmsIT8*) hIT8; - int iField, iSet; - - _cmsAssert(hIT8 != NULL); - - iField = LocateSample(it8, cSample); - if (iField < 0) { - return NULL; - } - - iSet = LocatePatch(it8, cPatch); - if (iSet < 0) { - return NULL; - } - - return GetData(it8, iSet, iField); -} - - -cmsFloat64Number CMSEXPORT cmsIT8GetDataDbl(cmsHANDLE it8, const char* cPatch, const char* cSample) -{ - const char* Buffer; - - Buffer = cmsIT8GetData(it8, cPatch, cSample); - - return ParseFloatNumber(Buffer); -} - - - -cmsBool CMSEXPORT cmsIT8SetData(cmsHANDLE hIT8, const char* cPatch, const char* cSample, const char *Val) -{ - cmsIT8* it8 = (cmsIT8*) hIT8; - int iField, iSet; - TABLE* t; - - _cmsAssert(hIT8 != NULL); - - t = GetTable(it8); - - iField = LocateSample(it8, cSample); - - if (iField < 0) - return FALSE; - - if (t-> nPatches == 0) { - - AllocateDataFormat(it8); - AllocateDataSet(it8); - CookPointers(it8); - } - - if (cmsstrcasecmp(cSample, "SAMPLE_ID") == 0) { - - iSet = LocateEmptyPatch(it8); - if (iSet < 0) { - return SynError(it8, "Couldn't add more patches '%s'\n", cPatch); - } - - iField = t -> SampleID; - } - else { - iSet = LocatePatch(it8, cPatch); - if (iSet < 0) { - return FALSE; - } - } - - return SetData(it8, iSet, iField, Val); -} - - -cmsBool CMSEXPORT cmsIT8SetDataDbl(cmsHANDLE hIT8, const char* cPatch, - const char* cSample, - cmsFloat64Number Val) -{ - cmsIT8* it8 = (cmsIT8*) hIT8; - char Buff[256]; - - _cmsAssert(hIT8 != NULL); - - snprintf(Buff, 255, it8->DoubleFormatter, Val); - return cmsIT8SetData(hIT8, cPatch, cSample, Buff); -} - -// Buffer should get MAXSTR at least - -const char* CMSEXPORT cmsIT8GetPatchName(cmsHANDLE hIT8, int nPatch, char* buffer) -{ - cmsIT8* it8 = (cmsIT8*) hIT8; - TABLE* t; - char* Data; - - _cmsAssert(hIT8 != NULL); - - t = GetTable(it8); - Data = GetData(it8, nPatch, t->SampleID); - - if (!Data) return NULL; - if (!buffer) return Data; - - strncpy(buffer, Data, MAXSTR-1); - buffer[MAXSTR-1] = 0; - return buffer; -} - -int CMSEXPORT cmsIT8GetPatchByName(cmsHANDLE hIT8, const char *cPatch) -{ - _cmsAssert(hIT8 != NULL); - - return LocatePatch((cmsIT8*)hIT8, cPatch); -} - -cmsUInt32Number CMSEXPORT cmsIT8TableCount(cmsHANDLE hIT8) -{ - cmsIT8* it8 = (cmsIT8*) hIT8; - - _cmsAssert(hIT8 != NULL); - - return it8 ->TablesCount; -} - -// This handles the "LABEL" extension. -// Label, nTable, Type - -int CMSEXPORT cmsIT8SetTableByLabel(cmsHANDLE hIT8, const char* cSet, const char* cField, const char* ExpectedType) -{ - const char* cLabelFld; - char Type[256], Label[256]; - int nTable; - - _cmsAssert(hIT8 != NULL); - - if (cField != NULL && *cField == 0) - cField = "LABEL"; - - if (cField == NULL) - cField = "LABEL"; - - cLabelFld = cmsIT8GetData(hIT8, cSet, cField); - if (!cLabelFld) return -1; - - if (sscanf(cLabelFld, "%255s %d %255s", Label, &nTable, Type) != 3) - return -1; - - if (ExpectedType != NULL && *ExpectedType == 0) - ExpectedType = NULL; - - if (ExpectedType) { - - if (cmsstrcasecmp(Type, ExpectedType) != 0) return -1; - } - - return cmsIT8SetTable(hIT8, nTable); -} - - -cmsBool CMSEXPORT cmsIT8SetIndexColumn(cmsHANDLE hIT8, const char* cSample) -{ - cmsIT8* it8 = (cmsIT8*) hIT8; - int pos; - - _cmsAssert(hIT8 != NULL); - - pos = LocateSample(it8, cSample); - if(pos == -1) - return FALSE; - - it8->Tab[it8->nTable].SampleID = pos; - return TRUE; -} - - -void CMSEXPORT cmsIT8DefineDblFormat(cmsHANDLE hIT8, const char* Formatter) -{ - cmsIT8* it8 = (cmsIT8*) hIT8; - - _cmsAssert(hIT8 != NULL); - - if (Formatter == NULL) - strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT); - else - strncpy(it8->DoubleFormatter, Formatter, sizeof(it8->DoubleFormatter)); - - it8 ->DoubleFormatter[sizeof(it8 ->DoubleFormatter)-1] = 0; -} diff --git a/third_party/lcms2-2.6/src/cmscnvrt.c b/third_party/lcms2-2.6/src/cmscnvrt.c deleted file mode 100644 index 1a93e83f90..0000000000 --- a/third_party/lcms2-2.6/src/cmscnvrt.c +++ /dev/null @@ -1,1142 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- -// - -#include "lcms2_internal.h" - - -// Link several profiles to obtain a single LUT modelling the whole color transform. Intents, Black point -// compensation and Adaptation parameters may vary across profiles. BPC and Adaptation refers to the PCS -// after the profile. I.e, BPC[0] refers to connexion between profile(0) and profile(1) -cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, - cmsUInt32Number nProfiles, - cmsUInt32Number Intents[], - cmsHPROFILE hProfiles[], - cmsBool BPC[], - cmsFloat64Number AdaptationStates[], - cmsUInt32Number dwFlags); - -//--------------------------------------------------------------------------------- - -// This is the default routine for ICC-style intents. A user may decide to override it by using a plugin. -// Supported intents are perceptual, relative colorimetric, saturation and ICC-absolute colorimetric -static -cmsPipeline* DefaultICCintents(cmsContext ContextID, - cmsUInt32Number nProfiles, - cmsUInt32Number Intents[], - cmsHPROFILE hProfiles[], - cmsBool BPC[], - cmsFloat64Number AdaptationStates[], - cmsUInt32Number dwFlags); - -//--------------------------------------------------------------------------------- - -// This is the entry for black-preserving K-only intents, which are non-ICC. Last profile have to be a output profile -// to do the trick (no devicelinks allowed at that position) -static -cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, - cmsUInt32Number nProfiles, - cmsUInt32Number Intents[], - cmsHPROFILE hProfiles[], - cmsBool BPC[], - cmsFloat64Number AdaptationStates[], - cmsUInt32Number dwFlags); - -//--------------------------------------------------------------------------------- - -// This is the entry for black-plane preserving, which are non-ICC. Again, Last profile have to be a output profile -// to do the trick (no devicelinks allowed at that position) -static -cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, - cmsUInt32Number nProfiles, - cmsUInt32Number Intents[], - cmsHPROFILE hProfiles[], - cmsBool BPC[], - cmsFloat64Number AdaptationStates[], - cmsUInt32Number dwFlags); - -//--------------------------------------------------------------------------------- - - -// This is a structure holding implementations for all supported intents. -typedef struct _cms_intents_list { - - cmsUInt32Number Intent; - char Description[256]; - cmsIntentFn Link; - struct _cms_intents_list* Next; - -} cmsIntentsList; - - -// Built-in intents -static cmsIntentsList DefaultIntents[] = { - - { INTENT_PERCEPTUAL, "Perceptual", DefaultICCintents, &DefaultIntents[1] }, - { INTENT_RELATIVE_COLORIMETRIC, "Relative colorimetric", DefaultICCintents, &DefaultIntents[2] }, - { INTENT_SATURATION, "Saturation", DefaultICCintents, &DefaultIntents[3] }, - { INTENT_ABSOLUTE_COLORIMETRIC, "Absolute colorimetric", DefaultICCintents, &DefaultIntents[4] }, - { INTENT_PRESERVE_K_ONLY_PERCEPTUAL, "Perceptual preserving black ink", BlackPreservingKOnlyIntents, &DefaultIntents[5] }, - { INTENT_PRESERVE_K_ONLY_RELATIVE_COLORIMETRIC, "Relative colorimetric preserving black ink", BlackPreservingKOnlyIntents, &DefaultIntents[6] }, - { INTENT_PRESERVE_K_ONLY_SATURATION, "Saturation preserving black ink", BlackPreservingKOnlyIntents, &DefaultIntents[7] }, - { INTENT_PRESERVE_K_PLANE_PERCEPTUAL, "Perceptual preserving black plane", BlackPreservingKPlaneIntents, &DefaultIntents[8] }, - { INTENT_PRESERVE_K_PLANE_RELATIVE_COLORIMETRIC,"Relative colorimetric preserving black plane", BlackPreservingKPlaneIntents, &DefaultIntents[9] }, - { INTENT_PRESERVE_K_PLANE_SATURATION, "Saturation preserving black plane", BlackPreservingKPlaneIntents, NULL } -}; - - -// A pointer to the begining of the list -_cmsIntentsPluginChunkType _cmsIntentsPluginChunk = { NULL }; - -// Duplicates the zone of memory used by the plug-in in the new context -static -void DupPluginIntentsList(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src) -{ - _cmsIntentsPluginChunkType newHead = { NULL }; - cmsIntentsList* entry; - cmsIntentsList* Anterior = NULL; - _cmsIntentsPluginChunkType* head = (_cmsIntentsPluginChunkType*) src->chunks[IntentPlugin]; - - // Walk the list copying all nodes - for (entry = head->Intents; - entry != NULL; - entry = entry ->Next) { - - cmsIntentsList *newEntry = ( cmsIntentsList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(cmsIntentsList)); - - if (newEntry == NULL) - return; - - // We want to keep the linked list order, so this is a little bit tricky - newEntry -> Next = NULL; - if (Anterior) - Anterior -> Next = newEntry; - - Anterior = newEntry; - - if (newHead.Intents == NULL) - newHead.Intents = newEntry; - } - - ctx ->chunks[IntentPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsIntentsPluginChunkType)); -} - -void _cmsAllocIntentsPluginChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src) -{ - if (src != NULL) { - - // Copy all linked list - DupPluginIntentsList(ctx, src); - } - else { - static _cmsIntentsPluginChunkType IntentsPluginChunkType = { NULL }; - ctx ->chunks[IntentPlugin] = _cmsSubAllocDup(ctx ->MemPool, &IntentsPluginChunkType, sizeof(_cmsIntentsPluginChunkType)); - } -} - - -// Search the list for a suitable intent. Returns NULL if not found -static -cmsIntentsList* SearchIntent(cmsContext ContextID, cmsUInt32Number Intent) -{ - _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(ContextID, IntentPlugin); - cmsIntentsList* pt; - - for (pt = ctx -> Intents; pt != NULL; pt = pt -> Next) - if (pt ->Intent == Intent) return pt; - - for (pt = DefaultIntents; pt != NULL; pt = pt -> Next) - if (pt ->Intent == Intent) return pt; - - return NULL; -} - -// Black point compensation. Implemented as a linear scaling in XYZ. Black points -// should come relative to the white point. Fills an matrix/offset element m -// which is organized as a 4x4 matrix. -static -void ComputeBlackPointCompensation(const cmsCIEXYZ* BlackPointIn, - const cmsCIEXYZ* BlackPointOut, - cmsMAT3* m, cmsVEC3* off) -{ - cmsFloat64Number ax, ay, az, bx, by, bz, tx, ty, tz; - - // Now we need to compute a matrix plus an offset m and of such of - // [m]*bpin + off = bpout - // [m]*D50 + off = D50 - // - // This is a linear scaling in the form ax+b, where - // a = (bpout - D50) / (bpin - D50) - // b = - D50* (bpout - bpin) / (bpin - D50) - - tx = BlackPointIn->X - cmsD50_XYZ()->X; - ty = BlackPointIn->Y - cmsD50_XYZ()->Y; - tz = BlackPointIn->Z - cmsD50_XYZ()->Z; - - ax = (BlackPointOut->X - cmsD50_XYZ()->X) / tx; - ay = (BlackPointOut->Y - cmsD50_XYZ()->Y) / ty; - az = (BlackPointOut->Z - cmsD50_XYZ()->Z) / tz; - - bx = - cmsD50_XYZ()-> X * (BlackPointOut->X - BlackPointIn->X) / tx; - by = - cmsD50_XYZ()-> Y * (BlackPointOut->Y - BlackPointIn->Y) / ty; - bz = - cmsD50_XYZ()-> Z * (BlackPointOut->Z - BlackPointIn->Z) / tz; - - _cmsVEC3init(&m ->v[0], ax, 0, 0); - _cmsVEC3init(&m ->v[1], 0, ay, 0); - _cmsVEC3init(&m ->v[2], 0, 0, az); - _cmsVEC3init(off, bx, by, bz); - -} - - -// Approximate a blackbody illuminant based on CHAD information -static -cmsFloat64Number CHAD2Temp(const cmsMAT3* Chad) -{ - // Convert D50 across inverse CHAD to get the absolute white point - cmsVEC3 d, s; - cmsCIEXYZ Dest; - cmsCIExyY DestChromaticity; - cmsFloat64Number TempK; - cmsMAT3 m1, m2; - - m1 = *Chad; - if (!_cmsMAT3inverse(&m1, &m2)) return FALSE; - - s.n[VX] = cmsD50_XYZ() -> X; - s.n[VY] = cmsD50_XYZ() -> Y; - s.n[VZ] = cmsD50_XYZ() -> Z; - - _cmsMAT3eval(&d, &m2, &s); - - Dest.X = d.n[VX]; - Dest.Y = d.n[VY]; - Dest.Z = d.n[VZ]; - - cmsXYZ2xyY(&DestChromaticity, &Dest); - - if (!cmsTempFromWhitePoint(&TempK, &DestChromaticity)) - return -1.0; - - return TempK; -} - -// Compute a CHAD based on a given temperature -static - void Temp2CHAD(cmsMAT3* Chad, cmsFloat64Number Temp) -{ - cmsCIEXYZ White; - cmsCIExyY ChromaticityOfWhite; - - cmsWhitePointFromTemp(&ChromaticityOfWhite, Temp); - cmsxyY2XYZ(&White, &ChromaticityOfWhite); - _cmsAdaptationMatrix(Chad, NULL, &White, cmsD50_XYZ()); -} - -// Join scalings to obtain relative input to absolute and then to relative output. -// Result is stored in a 3x3 matrix -static -cmsBool ComputeAbsoluteIntent(cmsFloat64Number AdaptationState, - const cmsCIEXYZ* WhitePointIn, - const cmsMAT3* ChromaticAdaptationMatrixIn, - const cmsCIEXYZ* WhitePointOut, - const cmsMAT3* ChromaticAdaptationMatrixOut, - cmsMAT3* m) -{ - cmsMAT3 Scale, m1, m2, m3, m4; - - // Adaptation state - if (AdaptationState == 1.0) { - - // Observer is fully adapted. Keep chromatic adaptation. - // That is the standard V4 behaviour - _cmsVEC3init(&m->v[0], WhitePointIn->X / WhitePointOut->X, 0, 0); - _cmsVEC3init(&m->v[1], 0, WhitePointIn->Y / WhitePointOut->Y, 0); - _cmsVEC3init(&m->v[2], 0, 0, WhitePointIn->Z / WhitePointOut->Z); - - } - else { - - // Incomplete adaptation. This is an advanced feature. - _cmsVEC3init(&Scale.v[0], WhitePointIn->X / WhitePointOut->X, 0, 0); - _cmsVEC3init(&Scale.v[1], 0, WhitePointIn->Y / WhitePointOut->Y, 0); - _cmsVEC3init(&Scale.v[2], 0, 0, WhitePointIn->Z / WhitePointOut->Z); - - - if (AdaptationState == 0.0) { - - m1 = *ChromaticAdaptationMatrixOut; - _cmsMAT3per(&m2, &m1, &Scale); - // m2 holds CHAD from output white to D50 times abs. col. scaling - - // Observer is not adapted, undo the chromatic adaptation - _cmsMAT3per(m, &m2, ChromaticAdaptationMatrixOut); - - m3 = *ChromaticAdaptationMatrixIn; - if (!_cmsMAT3inverse(&m3, &m4)) return FALSE; - _cmsMAT3per(m, &m2, &m4); - - } else { - - cmsMAT3 MixedCHAD; - cmsFloat64Number TempSrc, TempDest, Temp; - - m1 = *ChromaticAdaptationMatrixIn; - if (!_cmsMAT3inverse(&m1, &m2)) return FALSE; - _cmsMAT3per(&m3, &m2, &Scale); - // m3 holds CHAD from input white to D50 times abs. col. scaling - - TempSrc = CHAD2Temp(ChromaticAdaptationMatrixIn); - TempDest = CHAD2Temp(ChromaticAdaptationMatrixOut); - - if (TempSrc < 0.0 || TempDest < 0.0) return FALSE; // Something went wrong - - if (_cmsMAT3isIdentity(&Scale) && fabs(TempSrc - TempDest) < 0.01) { - - _cmsMAT3identity(m); - return TRUE; - } - - Temp = (1.0 - AdaptationState) * TempDest + AdaptationState * TempSrc; - - // Get a CHAD from whatever output temperature to D50. This replaces output CHAD - Temp2CHAD(&MixedCHAD, Temp); - - _cmsMAT3per(m, &m3, &MixedCHAD); - } - - } - return TRUE; - -} - -// Just to see if m matrix should be applied -static -cmsBool IsEmptyLayer(cmsMAT3* m, cmsVEC3* off) -{ - cmsFloat64Number diff = 0; - cmsMAT3 Ident; - int i; - - if (m == NULL && off == NULL) return TRUE; // NULL is allowed as an empty layer - if (m == NULL && off != NULL) return FALSE; // This is an internal error - - _cmsMAT3identity(&Ident); - - for (i=0; i < 3*3; i++) - diff += fabs(((cmsFloat64Number*)m)[i] - ((cmsFloat64Number*)&Ident)[i]); - - for (i=0; i < 3; i++) - diff += fabs(((cmsFloat64Number*)off)[i]); - - - return (diff < 0.002); -} - - -// Compute the conversion layer -static -cmsBool ComputeConversion(int i, cmsHPROFILE hProfiles[], - cmsUInt32Number Intent, - cmsBool BPC, - cmsFloat64Number AdaptationState, - cmsMAT3* m, cmsVEC3* off) -{ - - int k; - - // m and off are set to identity and this is detected latter on - _cmsMAT3identity(m); - _cmsVEC3init(off, 0, 0, 0); - - // If intent is abs. colorimetric, - if (Intent == INTENT_ABSOLUTE_COLORIMETRIC) { - - cmsCIEXYZ WhitePointIn, WhitePointOut; - cmsMAT3 ChromaticAdaptationMatrixIn, ChromaticAdaptationMatrixOut; - - _cmsReadMediaWhitePoint(&WhitePointIn, hProfiles[i-1]); - _cmsReadCHAD(&ChromaticAdaptationMatrixIn, hProfiles[i-1]); - - _cmsReadMediaWhitePoint(&WhitePointOut, hProfiles[i]); - _cmsReadCHAD(&ChromaticAdaptationMatrixOut, hProfiles[i]); - - if (!ComputeAbsoluteIntent(AdaptationState, - &WhitePointIn, &ChromaticAdaptationMatrixIn, - &WhitePointOut, &ChromaticAdaptationMatrixOut, m)) return FALSE; - - } - else { - // Rest of intents may apply BPC. - - if (BPC) { - - cmsCIEXYZ BlackPointIn, BlackPointOut; - - cmsDetectBlackPoint(&BlackPointIn, hProfiles[i-1], Intent, 0); - cmsDetectDestinationBlackPoint(&BlackPointOut, hProfiles[i], Intent, 0); - - // If black points are equal, then do nothing - if (BlackPointIn.X != BlackPointOut.X || - BlackPointIn.Y != BlackPointOut.Y || - BlackPointIn.Z != BlackPointOut.Z) - ComputeBlackPointCompensation(&BlackPointIn, &BlackPointOut, m, off); - } - } - - // Offset should be adjusted because the encoding. We encode XYZ normalized to 0..1.0, - // to do that, we divide by MAX_ENCODEABLE_XZY. The conversion stage goes XYZ -> XYZ so - // we have first to convert from encoded to XYZ and then convert back to encoded. - // y = Mx + Off - // x = x'c - // y = M x'c + Off - // y = y'c; y' = y / c - // y' = (Mx'c + Off) /c = Mx' + (Off / c) - - for (k=0; k < 3; k++) { - off ->n[k] /= MAX_ENCODEABLE_XYZ; - } - - return TRUE; -} - - -// Add a conversion stage if needed. If a matrix/offset m is given, it applies to XYZ space -static -cmsBool AddConversion(cmsPipeline* Result, cmsColorSpaceSignature InPCS, cmsColorSpaceSignature OutPCS, cmsMAT3* m, cmsVEC3* off) -{ - cmsFloat64Number* m_as_dbl = (cmsFloat64Number*) m; - cmsFloat64Number* off_as_dbl = (cmsFloat64Number*) off; - - // Handle PCS mismatches. A specialized stage is added to the LUT in such case - switch (InPCS) { - - case cmsSigXYZData: // Input profile operates in XYZ - - switch (OutPCS) { - - case cmsSigXYZData: // XYZ -> XYZ - if (!IsEmptyLayer(m, off) && - !cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl))) - return FALSE; - break; - - case cmsSigLabData: // XYZ -> Lab - if (!IsEmptyLayer(m, off) && - !cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl))) - return FALSE; - if (!cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID))) - return FALSE; - break; - - default: - return FALSE; // Colorspace mismatch - } - break; - - case cmsSigLabData: // Input profile operates in Lab - - switch (OutPCS) { - - case cmsSigXYZData: // Lab -> XYZ - - if (!cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID))) - return FALSE; - if (!IsEmptyLayer(m, off) && - !cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl))) - return FALSE; - break; - - case cmsSigLabData: // Lab -> Lab - - if (!IsEmptyLayer(m, off)) { - if (!cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID)) || - !cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)) || - !cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID))) - return FALSE; - } - break; - - default: - return FALSE; // Mismatch - } - break; - - // On colorspaces other than PCS, check for same space - default: - if (InPCS != OutPCS) return FALSE; - break; - } - - return TRUE; -} - - -// Is a given space compatible with another? -static -cmsBool ColorSpaceIsCompatible(cmsColorSpaceSignature a, cmsColorSpaceSignature b) -{ - // If they are same, they are compatible. - if (a == b) return TRUE; - - // Check for MCH4 substitution of CMYK - if ((a == cmsSig4colorData) && (b == cmsSigCmykData)) return TRUE; - if ((a == cmsSigCmykData) && (b == cmsSig4colorData)) return TRUE; - - // Check for XYZ/Lab. Those spaces are interchangeable as they can be computed one from other. - if ((a == cmsSigXYZData) && (b == cmsSigLabData)) return TRUE; - if ((a == cmsSigLabData) && (b == cmsSigXYZData)) return TRUE; - - return FALSE; -} - - -// Default handler for ICC-style intents -static -cmsPipeline* DefaultICCintents(cmsContext ContextID, - cmsUInt32Number nProfiles, - cmsUInt32Number TheIntents[], - cmsHPROFILE hProfiles[], - cmsBool BPC[], - cmsFloat64Number AdaptationStates[], - cmsUInt32Number dwFlags) -{ - cmsPipeline* Lut = NULL; - cmsPipeline* Result; - cmsHPROFILE hProfile; - cmsMAT3 m; - cmsVEC3 off; - cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut, CurrentColorSpace; - cmsProfileClassSignature ClassSig; - cmsUInt32Number i, Intent; - - // For safety - if (nProfiles == 0) return NULL; - - // Allocate an empty LUT for holding the result. 0 as channel count means 'undefined' - Result = cmsPipelineAlloc(ContextID, 0, 0); - if (Result == NULL) return NULL; - - CurrentColorSpace = cmsGetColorSpace(hProfiles[0]); - - for (i=0; i < nProfiles; i++) { - - cmsBool lIsDeviceLink, lIsInput; - - hProfile = hProfiles[i]; - ClassSig = cmsGetDeviceClass(hProfile); - lIsDeviceLink = (ClassSig == cmsSigLinkClass || ClassSig == cmsSigAbstractClass ); - - // First profile is used as input unless devicelink or abstract - if ((i == 0) && !lIsDeviceLink) { - lIsInput = TRUE; - } - else { - // Else use profile in the input direction if current space is not PCS - lIsInput = (CurrentColorSpace != cmsSigXYZData) && - (CurrentColorSpace != cmsSigLabData); - } - - Intent = TheIntents[i]; - - if (lIsInput || lIsDeviceLink) { - - ColorSpaceIn = cmsGetColorSpace(hProfile); - ColorSpaceOut = cmsGetPCS(hProfile); - } - else { - - ColorSpaceIn = cmsGetPCS(hProfile); - ColorSpaceOut = cmsGetColorSpace(hProfile); - } - - if (!ColorSpaceIsCompatible(ColorSpaceIn, CurrentColorSpace)) { - - cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "ColorSpace mismatch"); - goto Error; - } - - // If devicelink is found, then no custom intent is allowed and we can - // read the LUT to be applied. Settings don't apply here. - if (lIsDeviceLink || ((ClassSig == cmsSigNamedColorClass) && (nProfiles == 1))) { - - // Get the involved LUT from the profile - Lut = _cmsReadDevicelinkLUT(hProfile, Intent); - if (Lut == NULL) goto Error; - - // What about abstract profiles? - if (ClassSig == cmsSigAbstractClass && i > 0) { - if (!ComputeConversion(i, hProfiles, Intent, BPC[i], AdaptationStates[i], &m, &off)) goto Error; - } - else { - _cmsMAT3identity(&m); - _cmsVEC3init(&off, 0, 0, 0); - } - - - if (!AddConversion(Result, CurrentColorSpace, ColorSpaceIn, &m, &off)) goto Error; - - } - else { - - if (lIsInput) { - // Input direction means non-pcs connection, so proceed like devicelinks - Lut = _cmsReadInputLUT(hProfile, Intent); - if (Lut == NULL) goto Error; - } - else { - - // Output direction means PCS connection. Intent may apply here - Lut = _cmsReadOutputLUT(hProfile, Intent); - if (Lut == NULL) goto Error; - - - if (!ComputeConversion(i, hProfiles, Intent, BPC[i], AdaptationStates[i], &m, &off)) goto Error; - if (!AddConversion(Result, CurrentColorSpace, ColorSpaceIn, &m, &off)) goto Error; - - } - } - - // Concatenate to the output LUT - if (!cmsPipelineCat(Result, Lut)) - goto Error; - - cmsPipelineFree(Lut); - Lut = NULL; - - // Update current space - CurrentColorSpace = ColorSpaceOut; - } - - return Result; - -Error: - - if (Lut != NULL) cmsPipelineFree(Lut); - if (Result != NULL) cmsPipelineFree(Result); - return NULL; - - cmsUNUSED_PARAMETER(dwFlags); -} - - -// Wrapper for DLL calling convention -cmsPipeline* CMSEXPORT _cmsDefaultICCintents(cmsContext ContextID, - cmsUInt32Number nProfiles, - cmsUInt32Number TheIntents[], - cmsHPROFILE hProfiles[], - cmsBool BPC[], - cmsFloat64Number AdaptationStates[], - cmsUInt32Number dwFlags) -{ - return DefaultICCintents(ContextID, nProfiles, TheIntents, hProfiles, BPC, AdaptationStates, dwFlags); -} - -// Black preserving intents --------------------------------------------------------------------------------------------- - -// Translate black-preserving intents to ICC ones -static -int TranslateNonICCIntents(int Intent) -{ - switch (Intent) { - case INTENT_PRESERVE_K_ONLY_PERCEPTUAL: - case INTENT_PRESERVE_K_PLANE_PERCEPTUAL: - return INTENT_PERCEPTUAL; - - case INTENT_PRESERVE_K_ONLY_RELATIVE_COLORIMETRIC: - case INTENT_PRESERVE_K_PLANE_RELATIVE_COLORIMETRIC: - return INTENT_RELATIVE_COLORIMETRIC; - - case INTENT_PRESERVE_K_ONLY_SATURATION: - case INTENT_PRESERVE_K_PLANE_SATURATION: - return INTENT_SATURATION; - - default: return Intent; - } -} - -// Sampler for Black-only preserving CMYK->CMYK transforms - -typedef struct { - cmsPipeline* cmyk2cmyk; // The original transform - cmsToneCurve* KTone; // Black-to-black tone curve - -} GrayOnlyParams; - - -// Preserve black only if that is the only ink used -static -int BlackPreservingGrayOnlySampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) -{ - GrayOnlyParams* bp = (GrayOnlyParams*) Cargo; - - // If going across black only, keep black only - if (In[0] == 0 && In[1] == 0 && In[2] == 0) { - - // TAC does not apply because it is black ink! - Out[0] = Out[1] = Out[2] = 0; - Out[3] = cmsEvalToneCurve16(bp->KTone, In[3]); - return TRUE; - } - - // Keep normal transform for other colors - bp ->cmyk2cmyk ->Eval16Fn(In, Out, bp ->cmyk2cmyk->Data); - return TRUE; -} - -// This is the entry for black-preserving K-only intents, which are non-ICC -static -cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, - cmsUInt32Number nProfiles, - cmsUInt32Number TheIntents[], - cmsHPROFILE hProfiles[], - cmsBool BPC[], - cmsFloat64Number AdaptationStates[], - cmsUInt32Number dwFlags) -{ - GrayOnlyParams bp; - cmsPipeline* Result; - cmsUInt32Number ICCIntents[256]; - cmsStage* CLUT; - cmsUInt32Number i, nGridPoints; - - - // Sanity check - if (nProfiles < 1 || nProfiles > 255) return NULL; - - // Translate black-preserving intents to ICC ones - for (i=0; i < nProfiles; i++) - ICCIntents[i] = TranslateNonICCIntents(TheIntents[i]); - - // Check for non-cmyk profiles - if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData || - cmsGetColorSpace(hProfiles[nProfiles-1]) != cmsSigCmykData) - return DefaultICCintents(ContextID, nProfiles, ICCIntents, hProfiles, BPC, AdaptationStates, dwFlags); - - memset(&bp, 0, sizeof(bp)); - - // Allocate an empty LUT for holding the result - Result = cmsPipelineAlloc(ContextID, 4, 4); - if (Result == NULL) return NULL; - - // Create a LUT holding normal ICC transform - bp.cmyk2cmyk = DefaultICCintents(ContextID, - nProfiles, - ICCIntents, - hProfiles, - BPC, - AdaptationStates, - dwFlags); - - if (bp.cmyk2cmyk == NULL) goto Error; - - // Now, compute the tone curve - bp.KTone = _cmsBuildKToneCurve(ContextID, - 4096, - nProfiles, - ICCIntents, - hProfiles, - BPC, - AdaptationStates, - dwFlags); - - if (bp.KTone == NULL) goto Error; - - - // How many gridpoints are we going to use? - nGridPoints = _cmsReasonableGridpointsByColorspace(cmsSigCmykData, dwFlags); - - // Create the CLUT. 16 bits - CLUT = cmsStageAllocCLut16bit(ContextID, nGridPoints, 4, 4, NULL); - if (CLUT == NULL) goto Error; - - // This is the one and only MPE in this LUT - if (!cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT)) - goto Error; - - // Sample it. We cannot afford pre/post linearization this time. - if (!cmsStageSampleCLut16bit(CLUT, BlackPreservingGrayOnlySampler, (void*) &bp, 0)) - goto Error; - - // Get rid of xform and tone curve - cmsPipelineFree(bp.cmyk2cmyk); - cmsFreeToneCurve(bp.KTone); - - return Result; - -Error: - - if (bp.cmyk2cmyk != NULL) cmsPipelineFree(bp.cmyk2cmyk); - if (bp.KTone != NULL) cmsFreeToneCurve(bp.KTone); - if (Result != NULL) cmsPipelineFree(Result); - return NULL; - -} - -// K Plane-preserving CMYK to CMYK ------------------------------------------------------------------------------------ - -typedef struct { - - cmsPipeline* cmyk2cmyk; // The original transform - cmsHTRANSFORM hProofOutput; // Output CMYK to Lab (last profile) - cmsHTRANSFORM cmyk2Lab; // The input chain - cmsToneCurve* KTone; // Black-to-black tone curve - cmsPipeline* LabK2cmyk; // The output profile - cmsFloat64Number MaxError; - - cmsHTRANSFORM hRoundTrip; - cmsFloat64Number MaxTAC; - - -} PreserveKPlaneParams; - - -// The CLUT will be stored at 16 bits, but calculations are performed at cmsFloat32Number precision -static -int BlackPreservingSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) -{ - int i; - cmsFloat32Number Inf[4], Outf[4]; - cmsFloat32Number LabK[4]; - cmsFloat64Number SumCMY, SumCMYK, Error, Ratio; - cmsCIELab ColorimetricLab, BlackPreservingLab; - PreserveKPlaneParams* bp = (PreserveKPlaneParams*) Cargo; - - // Convert from 16 bits to floating point - for (i=0; i < 4; i++) - Inf[i] = (cmsFloat32Number) (In[i] / 65535.0); - - // Get the K across Tone curve - LabK[3] = cmsEvalToneCurveFloat(bp ->KTone, Inf[3]); - - // If going across black only, keep black only - if (In[0] == 0 && In[1] == 0 && In[2] == 0) { - - Out[0] = Out[1] = Out[2] = 0; - Out[3] = _cmsQuickSaturateWord(LabK[3] * 65535.0); - return TRUE; - } - - // Try the original transform, - cmsPipelineEvalFloat( Inf, Outf, bp ->cmyk2cmyk); - - // Store a copy of the floating point result into 16-bit - for (i=0; i < 4; i++) - Out[i] = _cmsQuickSaturateWord(Outf[i] * 65535.0); - - // Maybe K is already ok (mostly on K=0) - if ( fabs(Outf[3] - LabK[3]) < (3.0 / 65535.0) ) { - return TRUE; - } - - // K differ, mesure and keep Lab measurement for further usage - // this is done in relative colorimetric intent - cmsDoTransform(bp->hProofOutput, Out, &ColorimetricLab, 1); - - // Is not black only and the transform doesn't keep black. - // Obtain the Lab of output CMYK. After that we have Lab + K - cmsDoTransform(bp ->cmyk2Lab, Outf, LabK, 1); - - // Obtain the corresponding CMY using reverse interpolation - // (K is fixed in LabK[3]) - if (!cmsPipelineEvalReverseFloat(LabK, Outf, Outf, bp ->LabK2cmyk)) { - - // Cannot find a suitable value, so use colorimetric xform - // which is already stored in Out[] - return TRUE; - } - - // Make sure to pass thru K (which now is fixed) - Outf[3] = LabK[3]; - - // Apply TAC if needed - SumCMY = Outf[0] + Outf[1] + Outf[2]; - SumCMYK = SumCMY + Outf[3]; - - if (SumCMYK > bp ->MaxTAC) { - - Ratio = 1 - ((SumCMYK - bp->MaxTAC) / SumCMY); - if (Ratio < 0) - Ratio = 0; - } - else - Ratio = 1.0; - - Out[0] = _cmsQuickSaturateWord(Outf[0] * Ratio * 65535.0); // C - Out[1] = _cmsQuickSaturateWord(Outf[1] * Ratio * 65535.0); // M - Out[2] = _cmsQuickSaturateWord(Outf[2] * Ratio * 65535.0); // Y - Out[3] = _cmsQuickSaturateWord(Outf[3] * 65535.0); - - // Estimate the error (this goes 16 bits to Lab DBL) - cmsDoTransform(bp->hProofOutput, Out, &BlackPreservingLab, 1); - Error = cmsDeltaE(&ColorimetricLab, &BlackPreservingLab); - if (Error > bp -> MaxError) - bp->MaxError = Error; - - return TRUE; -} - -// This is the entry for black-plane preserving, which are non-ICC -static -cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, - cmsUInt32Number nProfiles, - cmsUInt32Number TheIntents[], - cmsHPROFILE hProfiles[], - cmsBool BPC[], - cmsFloat64Number AdaptationStates[], - cmsUInt32Number dwFlags) -{ - PreserveKPlaneParams bp; - cmsPipeline* Result = NULL; - cmsUInt32Number ICCIntents[256]; - cmsStage* CLUT; - cmsUInt32Number i, nGridPoints; - cmsHPROFILE hLab; - - // Sanity check - if (nProfiles < 1 || nProfiles > 255) return NULL; - - // Translate black-preserving intents to ICC ones - for (i=0; i < nProfiles; i++) - ICCIntents[i] = TranslateNonICCIntents(TheIntents[i]); - - // Check for non-cmyk profiles - if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData || - !(cmsGetColorSpace(hProfiles[nProfiles-1]) == cmsSigCmykData || - cmsGetDeviceClass(hProfiles[nProfiles-1]) == cmsSigOutputClass)) - return DefaultICCintents(ContextID, nProfiles, ICCIntents, hProfiles, BPC, AdaptationStates, dwFlags); - - // Allocate an empty LUT for holding the result - Result = cmsPipelineAlloc(ContextID, 4, 4); - if (Result == NULL) return NULL; - - - memset(&bp, 0, sizeof(bp)); - - // We need the input LUT of the last profile, assuming this one is responsible of - // black generation. This LUT will be seached in inverse order. - bp.LabK2cmyk = _cmsReadInputLUT(hProfiles[nProfiles-1], INTENT_RELATIVE_COLORIMETRIC); - if (bp.LabK2cmyk == NULL) goto Cleanup; - - // Get total area coverage (in 0..1 domain) - bp.MaxTAC = cmsDetectTAC(hProfiles[nProfiles-1]) / 100.0; - if (bp.MaxTAC <= 0) goto Cleanup; - - - // Create a LUT holding normal ICC transform - bp.cmyk2cmyk = DefaultICCintents(ContextID, - nProfiles, - ICCIntents, - hProfiles, - BPC, - AdaptationStates, - dwFlags); - if (bp.cmyk2cmyk == NULL) goto Cleanup; - - // Now the tone curve - bp.KTone = _cmsBuildKToneCurve(ContextID, 4096, nProfiles, - ICCIntents, - hProfiles, - BPC, - AdaptationStates, - dwFlags); - if (bp.KTone == NULL) goto Cleanup; - - // To measure the output, Last profile to Lab - hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); - bp.hProofOutput = cmsCreateTransformTHR(ContextID, hProfiles[nProfiles-1], - CHANNELS_SH(4)|BYTES_SH(2), hLab, TYPE_Lab_DBL, - INTENT_RELATIVE_COLORIMETRIC, - cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE); - if ( bp.hProofOutput == NULL) goto Cleanup; - - // Same as anterior, but lab in the 0..1 range - bp.cmyk2Lab = cmsCreateTransformTHR(ContextID, hProfiles[nProfiles-1], - FLOAT_SH(1)|CHANNELS_SH(4)|BYTES_SH(4), hLab, - FLOAT_SH(1)|CHANNELS_SH(3)|BYTES_SH(4), - INTENT_RELATIVE_COLORIMETRIC, - cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE); - if (bp.cmyk2Lab == NULL) goto Cleanup; - cmsCloseProfile(hLab); - - // Error estimation (for debug only) - bp.MaxError = 0; - - // How many gridpoints are we going to use? - nGridPoints = _cmsReasonableGridpointsByColorspace(cmsSigCmykData, dwFlags); - - - CLUT = cmsStageAllocCLut16bit(ContextID, nGridPoints, 4, 4, NULL); - if (CLUT == NULL) goto Cleanup; - - if (!cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT)) - goto Cleanup; - - cmsStageSampleCLut16bit(CLUT, BlackPreservingSampler, (void*) &bp, 0); - -Cleanup: - - if (bp.cmyk2cmyk) cmsPipelineFree(bp.cmyk2cmyk); - if (bp.cmyk2Lab) cmsDeleteTransform(bp.cmyk2Lab); - if (bp.hProofOutput) cmsDeleteTransform(bp.hProofOutput); - - if (bp.KTone) cmsFreeToneCurve(bp.KTone); - if (bp.LabK2cmyk) cmsPipelineFree(bp.LabK2cmyk); - - return Result; -} - -// Link routines ------------------------------------------------------------------------------------------------------ - -// Chain several profiles into a single LUT. It just checks the parameters and then calls the handler -// for the first intent in chain. The handler may be user-defined. Is up to the handler to deal with the -// rest of intents in chain. A maximum of 255 profiles at time are supported, which is pretty reasonable. -cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, - cmsUInt32Number nProfiles, - cmsUInt32Number TheIntents[], - cmsHPROFILE hProfiles[], - cmsBool BPC[], - cmsFloat64Number AdaptationStates[], - cmsUInt32Number dwFlags) -{ - cmsUInt32Number i; - cmsIntentsList* Intent; - - // Make sure a reasonable number of profiles is provided - if (nProfiles <= 0 || nProfiles > 255) { - cmsSignalError(ContextID, cmsERROR_RANGE, "Couldn't link '%d' profiles", nProfiles); - return NULL; - } - - for (i=0; i < nProfiles; i++) { - - // Check if black point is really needed or allowed. Note that - // following Adobe's document: - // BPC does not apply to devicelink profiles, nor to abs colorimetric, - // and applies always on V4 perceptual and saturation. - - if (TheIntents[i] == INTENT_ABSOLUTE_COLORIMETRIC) - BPC[i] = FALSE; - - if (TheIntents[i] == INTENT_PERCEPTUAL || TheIntents[i] == INTENT_SATURATION) { - - // Force BPC for V4 profiles in perceptual and saturation - if (cmsGetProfileVersion(hProfiles[i]) >= 4.0) - BPC[i] = TRUE; - } - } - - // Search for a handler. The first intent in the chain defines the handler. That would - // prevent using multiple custom intents in a multiintent chain, but the behaviour of - // this case would present some issues if the custom intent tries to do things like - // preserve primaries. This solution is not perfect, but works well on most cases. - - Intent = SearchIntent(ContextID, TheIntents[0]); - if (Intent == NULL) { - cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported intent '%d'", TheIntents[0]); - return NULL; - } - - // Call the handler - return Intent ->Link(ContextID, nProfiles, TheIntents, hProfiles, BPC, AdaptationStates, dwFlags); -} - -// ------------------------------------------------------------------------------------------------- - -// Get information about available intents. nMax is the maximum space for the supplied "Codes" -// and "Descriptions" the function returns the total number of intents, which may be greater -// than nMax, although the matrices are not populated beyond this level. -cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions) -{ - _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(ContextID, IntentPlugin); - cmsIntentsList* pt; - cmsUInt32Number nIntents; - - - for (nIntents=0, pt = ctx->Intents; pt != NULL; pt = pt -> Next) - { - if (nIntents < nMax) { - if (Codes != NULL) - Codes[nIntents] = pt ->Intent; - - if (Descriptions != NULL) - Descriptions[nIntents] = pt ->Description; - } - - nIntents++; - } - - for (nIntents=0, pt = DefaultIntents; pt != NULL; pt = pt -> Next) - { - if (nIntents < nMax) { - if (Codes != NULL) - Codes[nIntents] = pt ->Intent; - - if (Descriptions != NULL) - Descriptions[nIntents] = pt ->Description; - } - - nIntents++; - } - return nIntents; -} - -cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions) -{ - return cmsGetSupportedIntentsTHR(NULL, nMax, Codes, Descriptions); -} - -// The plug-in registration. User can add new intents or override default routines -cmsBool _cmsRegisterRenderingIntentPlugin(cmsContext id, cmsPluginBase* Data) -{ - _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(id, IntentPlugin); - cmsPluginRenderingIntent* Plugin = (cmsPluginRenderingIntent*) Data; - cmsIntentsList* fl; - - // Do we have to reset the custom intents? - if (Data == NULL) { - - ctx->Intents = NULL; - return TRUE; - } - - fl = (cmsIntentsList*) _cmsPluginMalloc(id, sizeof(cmsIntentsList)); - if (fl == NULL) return FALSE; - - - fl ->Intent = Plugin ->Intent; - strncpy(fl ->Description, Plugin ->Description, sizeof(fl ->Description)-1); - fl ->Description[sizeof(fl ->Description)-1] = 0; - - fl ->Link = Plugin ->Link; - - fl ->Next = ctx ->Intents; - ctx ->Intents = fl; - - return TRUE; -} - diff --git a/third_party/lcms2-2.6/src/cmserr.c b/third_party/lcms2-2.6/src/cmserr.c deleted file mode 100644 index f9adc3824a..0000000000 --- a/third_party/lcms2-2.6/src/cmserr.c +++ /dev/null @@ -1,707 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- - -#include "lcms2_internal.h" - -// I am so tired about incompatibilities on those functions that here are some replacements -// that hopefully would be fully portable. - -// compare two strings ignoring case -int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2) -{ - register const unsigned char *us1 = (const unsigned char *)s1, - *us2 = (const unsigned char *)s2; - - while (toupper(*us1) == toupper(*us2++)) - if (*us1++ == '\0') - return 0; - - return (toupper(*us1) - toupper(*--us2)); -} - -// long int because C99 specifies ftell in such way (7.19.9.2) -long int CMSEXPORT cmsfilelength(FILE* f) -{ - long int p , n; - - p = ftell(f); // register current file position - - if (fseek(f, 0, SEEK_END) != 0) { - return -1; - } - - n = ftell(f); - fseek(f, p, SEEK_SET); // file position restored - - return n; -} - -#if 0 -// Memory handling ------------------------------------------------------------------ -// -// This is the interface to low-level memory management routines. By default a simple -// wrapping to malloc/free/realloc is provided, although there is a limit on the max -// amount of memoy that can be reclaimed. This is mostly as a safety feature to prevent -// bogus or evil code to allocate huge blocks that otherwise lcms would never need. - -#define MAX_MEMORY_FOR_ALLOC ((cmsUInt32Number)(1024U*1024U*512U)) - -// User may override this behaviour by using a memory plug-in, which basically replaces -// the default memory management functions. In this case, no check is performed and it -// is up to the plug-in writter to keep in the safe side. There are only three functions -// required to be implemented: malloc, realloc and free, although the user may want to -// replace the optional mallocZero, calloc and dup as well. - -cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plugin); - -// ********************************************************************************* - -// This is the default memory allocation function. It does a very coarse -// check of amout of memory, just to prevent exploits -static -void* _cmsMallocDefaultFn(cmsContext ContextID, cmsUInt32Number size) -{ - if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never allow over maximum - - return (void*) malloc(size); - - cmsUNUSED_PARAMETER(ContextID); -} - -// Generic allocate & zero -static -void* _cmsMallocZeroDefaultFn(cmsContext ContextID, cmsUInt32Number size) -{ - void *pt = _cmsMalloc(ContextID, size); - if (pt == NULL) return NULL; - - memset(pt, 0, size); - return pt; -} - - -// The default free function. The only check proformed is against NULL pointers -static -void _cmsFreeDefaultFn(cmsContext ContextID, void *Ptr) -{ - // free(NULL) is defined a no-op by C99, therefore it is safe to - // avoid the check, but it is here just in case... - - if (Ptr) free(Ptr); - - cmsUNUSED_PARAMETER(ContextID); -} - -// The default realloc function. Again it checks for exploits. If Ptr is NULL, -// realloc behaves the same way as malloc and allocates a new block of size bytes. -static -void* _cmsReallocDefaultFn(cmsContext ContextID, void* Ptr, cmsUInt32Number size) -{ - - if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never realloc over 512Mb - - return realloc(Ptr, size); - - cmsUNUSED_PARAMETER(ContextID); -} - - -// The default calloc function. Allocates an array of num elements, each one of size bytes -// all memory is initialized to zero. -static -void* _cmsCallocDefaultFn(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size) -{ - cmsUInt32Number Total = num * size; - - // Preserve calloc behaviour - if (Total == 0) return NULL; - - // Safe check for overflow. - if (num >= UINT_MAX / size) return NULL; - - // Check for overflow - if (Total < num || Total < size) { - return NULL; - } - - if (Total > MAX_MEMORY_FOR_ALLOC) return NULL; // Never alloc over 512Mb - - return _cmsMallocZero(ContextID, Total); -} - -// Generic block duplication -static -void* _cmsDupDefaultFn(cmsContext ContextID, const void* Org, cmsUInt32Number size) -{ - void* mem; - - if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never dup over 512Mb - - mem = _cmsMalloc(ContextID, size); - - if (mem != NULL && Org != NULL) - memmove(mem, Org, size); - - return mem; -} - - -// Pointers to memory manager functions in Context0 -_cmsMemPluginChunkType _cmsMemPluginChunk = { _cmsMallocDefaultFn, _cmsMallocZeroDefaultFn, _cmsFreeDefaultFn, - _cmsReallocDefaultFn, _cmsCallocDefaultFn, _cmsDupDefaultFn - }; - - -// Reset and duplicate memory manager -void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src) -{ - _cmsAssert(ctx != NULL); - - if (src != NULL) { - - // Duplicate - ctx ->chunks[MemPlugin] = _cmsSubAllocDup(ctx ->MemPool, src ->chunks[MemPlugin], sizeof(_cmsMemPluginChunkType)); - } - else { - - // To reset it, we use the default allocators, which cannot be overriden - ctx ->chunks[MemPlugin] = &ctx ->DefaultMemoryManager; - } -} - -// Auxiliar to fill memory management functions from plugin (or context 0 defaults) -void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkType* ptr) -{ - if (Plugin == NULL) { - - memcpy(ptr, &_cmsMemPluginChunk, sizeof(_cmsMemPluginChunk)); - } - else { - - ptr ->MallocPtr = Plugin -> MallocPtr; - ptr ->FreePtr = Plugin -> FreePtr; - ptr ->ReallocPtr = Plugin -> ReallocPtr; - - // Make sure we revert to defaults - ptr ->MallocZeroPtr= _cmsMallocZeroDefaultFn; - ptr ->CallocPtr = _cmsCallocDefaultFn; - ptr ->DupPtr = _cmsDupDefaultFn; - - if (Plugin ->MallocZeroPtr != NULL) ptr ->MallocZeroPtr = Plugin -> MallocZeroPtr; - if (Plugin ->CallocPtr != NULL) ptr ->CallocPtr = Plugin -> CallocPtr; - if (Plugin ->DupPtr != NULL) ptr ->DupPtr = Plugin -> DupPtr; - - } -} - - -// Plug-in replacement entry -cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase *Data) -{ - cmsPluginMemHandler* Plugin = (cmsPluginMemHandler*) Data; - _cmsMemPluginChunkType* ptr; - - // NULL forces to reset to defaults. In this special case, the defaults are stored in the context structure. - // Remaining plug-ins does NOT have any copy in the context structure, but this is somehow special as the - // context internal data should be malloce'd by using those functions. - if (Data == NULL) { - - struct _cmsContext_struct* ctx = ( struct _cmsContext_struct*) ContextID; - - // Return to the default allocators - if (ContextID != NULL) { - ctx->chunks[MemPlugin] = (void*) &ctx->DefaultMemoryManager; - } - return TRUE; - } - - // Check for required callbacks - if (Plugin -> MallocPtr == NULL || - Plugin -> FreePtr == NULL || - Plugin -> ReallocPtr == NULL) return FALSE; - - // Set replacement functions - ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); - if (ptr == NULL) - return FALSE; - - _cmsInstallAllocFunctions(Plugin, ptr); - return TRUE; -} -#else -#include "core/fxcrt/fx_memory.h" -#include "core/fxcrt/fx_system.h" - -cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plugin) -{ - return TRUE; -} - -// Generic allocate -void* CMSEXPORT _cmsMalloc(cmsContext ContextID, cmsUInt32Number size) -{ - return FXMEM_DefaultAlloc(size, 1); -} - -// Generic allocate & zero -void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size) -{ - void* p = FXMEM_DefaultAlloc(size, 1); - if (p) memset(p, 0, size); - return p; -} - -// Generic calloc -void* CMSEXPORT _cmsCalloc(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size) -{ - cmsUInt32Number total = num * size; - if (total == 0 || total / size != num || total >= 512 * 1024 * 1024) - return NULL; - - return _cmsMallocZero(ContextID, num * size); -} - -// Generic reallocate -void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number size) -{ - return FXMEM_DefaultRealloc(Ptr, size, 1); -} - -// Generic free memory -void CMSEXPORT _cmsFree(cmsContext ContextID, void* Ptr) -{ - if (Ptr != NULL) FXMEM_DefaultFree(Ptr, 0); -} - -// Generic block duplication -void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size) -{ - void* p = FXMEM_DefaultAlloc(size, 1); - memmove(p, Org, size); - return p; -} - -_cmsMemPluginChunkType _cmsMemPluginChunk = {_cmsMalloc, _cmsMallocZero, _cmsFree, - _cmsRealloc, _cmsCalloc, _cmsDupMem - }; - -void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src) -{ - _cmsAssert(ctx != NULL); - - if (src != NULL) { - - // Duplicate - ctx ->chunks[MemPlugin] = _cmsSubAllocDup(ctx ->MemPool, src ->chunks[MemPlugin], sizeof(_cmsMemPluginChunkType)); - } - else { - - // To reset it, we use the default allocators, which cannot be overriden - ctx ->chunks[MemPlugin] = &ctx ->DefaultMemoryManager; - } -} - -void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkType* ptr) -{ - if (Plugin == NULL) { - - memcpy(ptr, &_cmsMemPluginChunk, sizeof(_cmsMemPluginChunk)); - } - else { - - ptr ->MallocPtr = Plugin -> MallocPtr; - ptr ->FreePtr = Plugin -> FreePtr; - ptr ->ReallocPtr = Plugin -> ReallocPtr; - - // Make sure we revert to defaults - ptr ->MallocZeroPtr= _cmsMallocZero; - ptr ->CallocPtr = _cmsCalloc; - ptr ->DupPtr = _cmsDupMem; - - if (Plugin ->MallocZeroPtr != NULL) ptr ->MallocZeroPtr = Plugin -> MallocZeroPtr; - if (Plugin ->CallocPtr != NULL) ptr ->CallocPtr = Plugin -> CallocPtr; - if (Plugin ->DupPtr != NULL) ptr ->DupPtr = Plugin -> DupPtr; - - } -} -#endif - -// ******************************************************************************************** - -// Sub allocation takes care of many pointers of small size. The memory allocated in -// this way have be freed at once. Next function allocates a single chunk for linked list -// I prefer this method over realloc due to the big inpact on xput realloc may have if -// memory is being swapped to disk. This approach is safer (although that may not be true on all platforms) -static -_cmsSubAllocator_chunk* _cmsCreateSubAllocChunk(cmsContext ContextID, cmsUInt32Number Initial) -{ - _cmsSubAllocator_chunk* chunk; - - // 20K by default - if (Initial == 0) - Initial = 20*1024; - - // Create the container - chunk = (_cmsSubAllocator_chunk*) _cmsMallocZero(ContextID, sizeof(_cmsSubAllocator_chunk)); - if (chunk == NULL) return NULL; - - // Initialize values - chunk ->Block = (cmsUInt8Number*) _cmsMalloc(ContextID, Initial); - if (chunk ->Block == NULL) { - - // Something went wrong - _cmsFree(ContextID, chunk); - return NULL; - } - - chunk ->BlockSize = Initial; - chunk ->Used = 0; - chunk ->next = NULL; - - return chunk; -} - -// The suballocated is nothing but a pointer to the first element in the list. We also keep -// the thread ID in this structure. -_cmsSubAllocator* _cmsCreateSubAlloc(cmsContext ContextID, cmsUInt32Number Initial) -{ - _cmsSubAllocator* sub; - - // Create the container - sub = (_cmsSubAllocator*) _cmsMallocZero(ContextID, sizeof(_cmsSubAllocator)); - if (sub == NULL) return NULL; - - sub ->ContextID = ContextID; - - sub ->h = _cmsCreateSubAllocChunk(ContextID, Initial); - if (sub ->h == NULL) { - _cmsFree(ContextID, sub); - return NULL; - } - - return sub; -} - - -// Get rid of whole linked list -void _cmsSubAllocDestroy(_cmsSubAllocator* sub) -{ - _cmsSubAllocator_chunk *chunk, *n; - - for (chunk = sub ->h; chunk != NULL; chunk = n) { - - n = chunk->next; - if (chunk->Block != NULL) _cmsFree(sub ->ContextID, chunk->Block); - _cmsFree(sub ->ContextID, chunk); - } - - // Free the header - _cmsFree(sub ->ContextID, sub); -} - - -// Get a pointer to small memory block. -void* _cmsSubAlloc(_cmsSubAllocator* sub, cmsUInt32Number size) -{ - cmsUInt32Number Free = sub -> h ->BlockSize - sub -> h -> Used; - cmsUInt8Number* ptr; - - size = _cmsALIGNMEM(size); - - // Check for memory. If there is no room, allocate a new chunk of double memory size. - if (size > Free) { - - _cmsSubAllocator_chunk* chunk; - cmsUInt32Number newSize; - - newSize = sub -> h ->BlockSize * 2; - if (newSize < size) newSize = size; - - chunk = _cmsCreateSubAllocChunk(sub -> ContextID, newSize); - if (chunk == NULL) return NULL; - - // Link list - chunk ->next = sub ->h; - sub ->h = chunk; - - } - - ptr = sub -> h ->Block + sub -> h ->Used; - sub -> h -> Used += size; - - return (void*) ptr; -} - -// Duplicate in pool -void* _cmsSubAllocDup(_cmsSubAllocator* s, const void *ptr, cmsUInt32Number size) -{ - void *NewPtr; - - // Dup of null pointer is also NULL - if (ptr == NULL) - return NULL; - - NewPtr = _cmsSubAlloc(s, size); - - if (ptr != NULL && NewPtr != NULL) { - memcpy(NewPtr, ptr, size); - } - - return NewPtr; -} - - - -// Error logging ****************************************************************** - -// There is no error handling at all. When a funtion fails, it returns proper value. -// For example, all create functions does return NULL on failure. Other return FALSE -// It may be interesting, for the developer, to know why the function is failing. -// for that reason, lcms2 does offer a logging function. This function does recive -// a ENGLISH string with some clues on what is going wrong. You can show this -// info to the end user, or just create some sort of log. -// The logging function should NOT terminate the program, as this obviously can leave -// resources. It is the programmer's responsability to check each function return code -// to make sure it didn't fail. - -// Error messages are limited to MAX_ERROR_MESSAGE_LEN - -#define MAX_ERROR_MESSAGE_LEN 1024 - -// --------------------------------------------------------------------------------------------------------- - -// This is our default log error -static void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text); - -// Context0 storage, which is global -_cmsLogErrorChunkType _cmsLogErrorChunk = { DefaultLogErrorHandlerFunction }; - -// Allocates and inits error logger container for a given context. If src is NULL, only initializes the value -// to the default. Otherwise, it duplicates the value. The interface is standard across all context clients -void _cmsAllocLogErrorChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src) -{ - static _cmsLogErrorChunkType LogErrorChunk = { DefaultLogErrorHandlerFunction }; - void* from; - - if (src != NULL) { - from = src ->chunks[Logger]; - } - else { - from = &LogErrorChunk; - } - - ctx ->chunks[Logger] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsLogErrorChunkType)); -} - -// The default error logger does nothing. -static -void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text) -{ - // fprintf(stderr, "[lcms]: %s\n", Text); - // fflush(stderr); - - cmsUNUSED_PARAMETER(ContextID); - cmsUNUSED_PARAMETER(ErrorCode); - cmsUNUSED_PARAMETER(Text); -} - -// Change log error, context based -void CMSEXPORT cmsSetLogErrorHandlerTHR(cmsContext ContextID, cmsLogErrorHandlerFunction Fn) -{ - _cmsLogErrorChunkType* lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger); - - if (lhg != NULL) { - - if (Fn == NULL) - lhg -> LogErrorHandler = DefaultLogErrorHandlerFunction; - else - lhg -> LogErrorHandler = Fn; - } -} - -// Change log error, legacy -void CMSEXPORT cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn) -{ - cmsSetLogErrorHandlerTHR(NULL, Fn); -} - -// Log an error -// ErrorText is a text holding an english description of error. -void CMSEXPORT cmsSignalError(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *ErrorText, ...) -{ - va_list args; - char Buffer[MAX_ERROR_MESSAGE_LEN]; - _cmsLogErrorChunkType* lhg; - - - va_start(args, ErrorText); - vsnprintf(Buffer, MAX_ERROR_MESSAGE_LEN-1, ErrorText, args); - va_end(args); - - // Check for the context, if specified go there. If not, go for the global - lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger); - if (lhg ->LogErrorHandler) { - lhg ->LogErrorHandler(ContextID, ErrorCode, Buffer); - } -} - -// Utility function to print signatures -void _cmsTagSignature2String(char String[5], cmsTagSignature sig) -{ - cmsUInt32Number be; - - // Convert to big endian - be = _cmsAdjustEndianess32((cmsUInt32Number) sig); - - // Move chars - memmove(String, &be, 4); - - // Make sure of terminator - String[4] = 0; -} - -//-------------------------------------------------------------------------------------------------- - - -static -void* defMtxCreate(cmsContext id) -{ - _cmsMutex* ptr_mutex = (_cmsMutex*) _cmsMalloc(id, sizeof(_cmsMutex)); - _cmsInitMutexPrimitive(ptr_mutex); - return (void*) ptr_mutex; -} - -static -void defMtxDestroy(cmsContext id, void* mtx) -{ - _cmsDestroyMutexPrimitive((_cmsMutex *) mtx); - _cmsFree(id, mtx); -} - -static -cmsBool defMtxLock(cmsContext id, void* mtx) -{ - cmsUNUSED_PARAMETER(id); - return _cmsLockPrimitive((_cmsMutex *) mtx) == 0; -} - -static -void defMtxUnlock(cmsContext id, void* mtx) -{ - cmsUNUSED_PARAMETER(id); - _cmsUnlockPrimitive((_cmsMutex *) mtx); -} - - - -// Pointers to memory manager functions in Context0 -_cmsMutexPluginChunkType _cmsMutexPluginChunk = { defMtxCreate, defMtxDestroy, defMtxLock, defMtxUnlock }; - -// Allocate and init mutex container. -void _cmsAllocMutexPluginChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src) -{ - static _cmsMutexPluginChunkType MutexChunk = {defMtxCreate, defMtxDestroy, defMtxLock, defMtxUnlock }; - void* from; - - if (src != NULL) { - from = src ->chunks[MutexPlugin]; - } - else { - from = &MutexChunk; - } - - ctx ->chunks[MutexPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsMutexPluginChunkType)); -} - -// Register new ways to transform -cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Data) -{ - cmsPluginMutex* Plugin = (cmsPluginMutex*) Data; - _cmsMutexPluginChunkType* ctx = ( _cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); - - if (Data == NULL) { - - // No lock routines - ctx->CreateMutexPtr = NULL; - ctx->DestroyMutexPtr = NULL; - ctx->LockMutexPtr = NULL; - ctx ->UnlockMutexPtr = NULL; - return TRUE; - } - - // Factory callback is required - if (Plugin ->CreateMutexPtr == NULL || Plugin ->DestroyMutexPtr == NULL || - Plugin ->LockMutexPtr == NULL || Plugin ->UnlockMutexPtr == NULL) return FALSE; - - - ctx->CreateMutexPtr = Plugin->CreateMutexPtr; - ctx->DestroyMutexPtr = Plugin ->DestroyMutexPtr; - ctx ->LockMutexPtr = Plugin ->LockMutexPtr; - ctx ->UnlockMutexPtr = Plugin ->UnlockMutexPtr; - - // All is ok - return TRUE; -} - -// Generic Mutex fns -void* CMSEXPORT _cmsCreateMutex(cmsContext ContextID) -{ - _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); - - if (ptr ->CreateMutexPtr == NULL) return NULL; - - return ptr ->CreateMutexPtr(ContextID); -} - -void CMSEXPORT _cmsDestroyMutex(cmsContext ContextID, void* mtx) -{ - _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); - - if (ptr ->DestroyMutexPtr != NULL) { - - ptr ->DestroyMutexPtr(ContextID, mtx); - } -} - -cmsBool CMSEXPORT _cmsLockMutex(cmsContext ContextID, void* mtx) -{ - _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); - - if (ptr ->LockMutexPtr == NULL) return TRUE; - - return ptr ->LockMutexPtr(ContextID, mtx); -} - -void CMSEXPORT _cmsUnlockMutex(cmsContext ContextID, void* mtx) -{ - _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); - - if (ptr ->UnlockMutexPtr != NULL) { - - ptr ->UnlockMutexPtr(ContextID, mtx); - } -} diff --git a/third_party/lcms2-2.6/src/cmsgamma.c b/third_party/lcms2-2.6/src/cmsgamma.c deleted file mode 100644 index 97aeb7cc16..0000000000 --- a/third_party/lcms2-2.6/src/cmsgamma.c +++ /dev/null @@ -1,1298 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2013 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- -// - -#include "lcms2_internal.h" - -// Tone curves are powerful constructs that can contain curves specified in diverse ways. -// The curve is stored in segments, where each segment can be sampled or specified by parameters. -// a 16.bit simplification of the *whole* curve is kept for optimization purposes. For float operation, -// each segment is evaluated separately. Plug-ins may be used to define new parametric schemes, -// each plug-in may define up to MAX_TYPES_IN_LCMS_PLUGIN functions types. For defining a function, -// the plug-in should provide the type id, how many parameters each type has, and a pointer to -// a procedure that evaluates the function. In the case of reverse evaluation, the evaluator will -// be called with the type id as a negative value, and a sampled version of the reversed curve -// will be built. - -// ----------------------------------------------------------------- Implementation -// Maxim number of nodes -#define MAX_NODES_IN_CURVE 4097 -#define MINUS_INF (-1E22F) -#define PLUS_INF (+1E22F) - -// The list of supported parametric curves -typedef struct _cmsParametricCurvesCollection_st { - - int nFunctions; // Number of supported functions in this chunk - int FunctionTypes[MAX_TYPES_IN_LCMS_PLUGIN]; // The identification types - int ParameterCount[MAX_TYPES_IN_LCMS_PLUGIN]; // Number of parameters for each function - cmsParametricCurveEvaluator Evaluator; // The evaluator - - struct _cmsParametricCurvesCollection_st* Next; // Next in list - -} _cmsParametricCurvesCollection; - -// This is the default (built-in) evaluator -static cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Number Params[], cmsFloat64Number R); - -// The built-in list -static _cmsParametricCurvesCollection DefaultCurves = { - 9, // # of curve types - { 1, 2, 3, 4, 5, 6, 7, 8, 108 }, // Parametric curve ID - { 1, 3, 4, 5, 7, 4, 5, 5, 1 }, // Parameters by type - DefaultEvalParametricFn, // Evaluator - NULL // Next in chain -}; - -// Duplicates the zone of memory used by the plug-in in the new context -static -void DupPluginCurvesList(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src) -{ - _cmsCurvesPluginChunkType newHead = { NULL }; - _cmsParametricCurvesCollection* entry; - _cmsParametricCurvesCollection* Anterior = NULL; - _cmsCurvesPluginChunkType* head = (_cmsCurvesPluginChunkType*) src->chunks[CurvesPlugin]; - - _cmsAssert(head != NULL); - - // Walk the list copying all nodes - for (entry = head->ParametricCurves; - entry != NULL; - entry = entry ->Next) { - - _cmsParametricCurvesCollection *newEntry = ( _cmsParametricCurvesCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsParametricCurvesCollection)); - - if (newEntry == NULL) - return; - - // We want to keep the linked list order, so this is a little bit tricky - newEntry -> Next = NULL; - if (Anterior) - Anterior -> Next = newEntry; - - Anterior = newEntry; - - if (newHead.ParametricCurves == NULL) - newHead.ParametricCurves = newEntry; - } - - ctx ->chunks[CurvesPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsCurvesPluginChunkType)); -} - -// The allocator have to follow the chain -void _cmsAllocCurvesPluginChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src) -{ - _cmsAssert(ctx != NULL); - - if (src != NULL) { - - // Copy all linked list - DupPluginCurvesList(ctx, src); - } - else { - static _cmsCurvesPluginChunkType CurvesPluginChunk = { NULL }; - ctx ->chunks[CurvesPlugin] = _cmsSubAllocDup(ctx ->MemPool, &CurvesPluginChunk, sizeof(_cmsCurvesPluginChunkType)); - } -} - - -// The linked list head -_cmsCurvesPluginChunkType _cmsCurvesPluginChunk = { NULL }; - -// As a way to install new parametric curves -cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext ContextID, cmsPluginBase* Data) -{ - _cmsCurvesPluginChunkType* ctx = ( _cmsCurvesPluginChunkType*) _cmsContextGetClientChunk(ContextID, CurvesPlugin); - cmsPluginParametricCurves* Plugin = (cmsPluginParametricCurves*) Data; - _cmsParametricCurvesCollection* fl; - - if (Data == NULL) { - - ctx -> ParametricCurves = NULL; - return TRUE; - } - - fl = (_cmsParametricCurvesCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsParametricCurvesCollection)); - if (fl == NULL) return FALSE; - - // Copy the parameters - fl ->Evaluator = Plugin ->Evaluator; - fl ->nFunctions = Plugin ->nFunctions; - - // Make sure no mem overwrites - if (fl ->nFunctions > MAX_TYPES_IN_LCMS_PLUGIN) - fl ->nFunctions = MAX_TYPES_IN_LCMS_PLUGIN; - - // Copy the data - memmove(fl->FunctionTypes, Plugin ->FunctionTypes, fl->nFunctions * sizeof(cmsUInt32Number)); - memmove(fl->ParameterCount, Plugin ->ParameterCount, fl->nFunctions * sizeof(cmsUInt32Number)); - - // Keep linked list - fl ->Next = ctx->ParametricCurves; - ctx->ParametricCurves = fl; - - // All is ok - return TRUE; -} - - -// Search in type list, return position or -1 if not found -static -int IsInSet(int Type, _cmsParametricCurvesCollection* c) -{ - int i; - - for (i=0; i < c ->nFunctions; i++) - if (abs(Type) == c ->FunctionTypes[i]) return i; - - return -1; -} - - -// Search for the collection which contains a specific type -static -_cmsParametricCurvesCollection *GetParametricCurveByType(cmsContext ContextID, int Type, int* index) -{ - _cmsParametricCurvesCollection* c; - int Position; - _cmsCurvesPluginChunkType* ctx = ( _cmsCurvesPluginChunkType*) _cmsContextGetClientChunk(ContextID, CurvesPlugin); - - for (c = ctx->ParametricCurves; c != NULL; c = c ->Next) { - - Position = IsInSet(Type, c); - - if (Position != -1) { - if (index != NULL) - *index = Position; - return c; - } - } - // If none found, revert for defaults - for (c = &DefaultCurves; c != NULL; c = c ->Next) { - - Position = IsInSet(Type, c); - - if (Position != -1) { - if (index != NULL) - *index = Position; - return c; - } - } - - return NULL; -} - -// Low level allocate, which takes care of memory details. nEntries may be zero, and in this case -// no optimation curve is computed. nSegments may also be zero in the inverse case, where only the -// optimization curve is given. Both features simultaneously is an error -static -cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsInt32Number nEntries, - cmsInt32Number nSegments, const cmsCurveSegment* Segments, - const cmsUInt16Number* Values) -{ - cmsToneCurve* p; - int i; - - // We allow huge tables, which are then restricted for smoothing operations - if (nEntries > 65530 || nEntries < 0) { - cmsSignalError(ContextID, cmsERROR_RANGE, "Couldn't create tone curve of more than 65530 entries"); - return NULL; - } - - if (nEntries <= 0 && nSegments <= 0) { - cmsSignalError(ContextID, cmsERROR_RANGE, "Couldn't create tone curve with zero segments and no table"); - return NULL; - } - - // Allocate all required pointers, etc. - p = (cmsToneCurve*) _cmsMallocZero(ContextID, sizeof(cmsToneCurve)); - if (!p) return NULL; - - // In this case, there are no segments - if (nSegments <= 0) { - p ->Segments = NULL; - p ->Evals = NULL; - } - else { - p ->Segments = (cmsCurveSegment*) _cmsCalloc(ContextID, nSegments, sizeof(cmsCurveSegment)); - if (p ->Segments == NULL) goto Error; - - p ->Evals = (cmsParametricCurveEvaluator*) _cmsCalloc(ContextID, nSegments, sizeof(cmsParametricCurveEvaluator)); - if (p ->Evals == NULL) goto Error; - } - - p -> nSegments = nSegments; - - // This 16-bit table contains a limited precision representation of the whole curve and is kept for - // increasing xput on certain operations. - if (nEntries <= 0) { - p ->Table16 = NULL; - } - else { - p ->Table16 = (cmsUInt16Number*) _cmsCalloc(ContextID, nEntries, sizeof(cmsUInt16Number)); - if (p ->Table16 == NULL) goto Error; - } - - p -> nEntries = nEntries; - - // Initialize members if requested - if (Values != NULL && (nEntries > 0)) { - - for (i=0; i < nEntries; i++) - p ->Table16[i] = Values[i]; - } - - // Initialize the segments stuff. The evaluator for each segment is located and a pointer to it - // is placed in advance to maximize performance. - if (Segments != NULL && (nSegments > 0)) { - - _cmsParametricCurvesCollection *c; - - p ->SegInterp = (cmsInterpParams**) _cmsCalloc(ContextID, nSegments, sizeof(cmsInterpParams*)); - if (p ->SegInterp == NULL) goto Error; - - for (i=0; i< nSegments; i++) { - - // Type 0 is a special marker for table-based curves - if (Segments[i].Type == 0) - p ->SegInterp[i] = _cmsComputeInterpParams(ContextID, Segments[i].nGridPoints, 1, 1, NULL, CMS_LERP_FLAGS_FLOAT); - - memmove(&p ->Segments[i], &Segments[i], sizeof(cmsCurveSegment)); - - if (Segments[i].Type == 0 && Segments[i].SampledPoints != NULL) - p ->Segments[i].SampledPoints = (cmsFloat32Number*) _cmsDupMem(ContextID, Segments[i].SampledPoints, sizeof(cmsFloat32Number) * Segments[i].nGridPoints); - else - p ->Segments[i].SampledPoints = NULL; - - - c = GetParametricCurveByType(ContextID, Segments[i].Type, NULL); - if (c != NULL) - p ->Evals[i] = c ->Evaluator; - } - } - - p ->InterpParams = _cmsComputeInterpParams(ContextID, p ->nEntries, 1, 1, p->Table16, CMS_LERP_FLAGS_16BITS); - if (p->InterpParams != NULL) - return p; - -Error: - if (p -> Segments) _cmsFree(ContextID, p ->Segments); - if (p -> Evals) _cmsFree(ContextID, p -> Evals); - if (p ->Table16) _cmsFree(ContextID, p ->Table16); - _cmsFree(ContextID, p); - return NULL; -} - - -// Parametric Fn using floating point -static -cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Number Params[], cmsFloat64Number R) -{ - cmsFloat64Number e, Val, disc; - - switch (Type) { - - // X = Y ^ Gamma - case 1: - if (R < 0) { - - if (fabs(Params[0] - 1.0) < MATRIX_DET_TOLERANCE) - Val = R; - else - Val = 0; - } - else - Val = pow(R, Params[0]); - break; - - // Type 1 Reversed: X = Y ^1/gamma - case -1: - if (R < 0) { - - if (fabs(Params[0] - 1.0) < MATRIX_DET_TOLERANCE) - Val = R; - else - Val = 0; - } - else - Val = pow(R, 1/Params[0]); - break; - - // CIE 122-1966 - // Y = (aX + b)^Gamma | X >= -b/a - // Y = 0 | else - case 2: - disc = -Params[2] / Params[1]; - - if (R >= disc ) { - - e = Params[1]*R + Params[2]; - - if (e > 0) - Val = pow(e, Params[0]); - else - Val = 0; - } - else - Val = 0; - break; - - // Type 2 Reversed - // X = (Y ^1/g - b) / a - case -2: - if (R < 0) - Val = 0; - else - Val = (pow(R, 1.0/Params[0]) - Params[2]) / Params[1]; - - if (Val < 0) - Val = 0; - break; - - - // IEC 61966-3 - // Y = (aX + b)^Gamma | X <= -b/a - // Y = c | else - case 3: - disc = -Params[2] / Params[1]; - if (disc < 0) - disc = 0; - - if (R >= disc) { - - e = Params[1]*R + Params[2]; - - if (e > 0) - Val = pow(e, Params[0]) + Params[3]; - else - Val = 0; - } - else - Val = Params[3]; - break; - - - // Type 3 reversed - // X=((Y-c)^1/g - b)/a | (Y>=c) - // X=-b/a | (Y<c) - case -3: - if (R >= Params[3]) { - - e = R - Params[3]; - - if (e > 0) - Val = (pow(e, 1/Params[0]) - Params[2]) / Params[1]; - else - Val = 0; - } - else { - Val = -Params[2] / Params[1]; - } - break; - - - // IEC 61966-2.1 (sRGB) - // Y = (aX + b)^Gamma | X >= d - // Y = cX | X < d - case 4: - if (R >= Params[4]) { - - e = Params[1]*R + Params[2]; - - if (e > 0) - Val = pow(e, Params[0]); - else - Val = 0; - } - else - Val = R * Params[3]; - break; - - // Type 4 reversed - // X=((Y^1/g-b)/a) | Y >= (ad+b)^g - // X=Y/c | Y< (ad+b)^g - case -4: - e = Params[1] * Params[4] + Params[2]; - if (e < 0) - disc = 0; - else - disc = pow(e, Params[0]); - - if (R >= disc) { - - Val = (pow(R, 1.0/Params[0]) - Params[2]) / Params[1]; - } - else { - Val = R / Params[3]; - } - break; - - - // Y = (aX + b)^Gamma + e | X >= d - // Y = cX + f | X < d - case 5: - if (R >= Params[4]) { - - e = Params[1]*R + Params[2]; - - if (e > 0) - Val = pow(e, Params[0]) + Params[5]; - else - Val = Params[5]; - } - else - Val = R*Params[3] + Params[6]; - break; - - - // Reversed type 5 - // X=((Y-e)1/g-b)/a | Y >=(ad+b)^g+e), cd+f - // X=(Y-f)/c | else - case -5: - - disc = Params[3] * Params[4] + Params[6]; - if (R >= disc) { - - e = R - Params[5]; - if (e < 0) - Val = 0; - else - Val = (pow(e, 1.0/Params[0]) - Params[2]) / Params[1]; - } - else { - Val = (R - Params[6]) / Params[3]; - } - break; - - - // Types 6,7,8 comes from segmented curves as described in ICCSpecRevision_02_11_06_Float.pdf - // Type 6 is basically identical to type 5 without d - - // Y = (a * X + b) ^ Gamma + c - case 6: - e = Params[1]*R + Params[2]; - - if (e < 0) - Val = Params[3]; - else - Val = pow(e, Params[0]) + Params[3]; - break; - - // ((Y - c) ^1/Gamma - b) / a - case -6: - e = R - Params[3]; - if (e < 0) - Val = 0; - else - Val = (pow(e, 1.0/Params[0]) - Params[2]) / Params[1]; - break; - - - // Y = a * log (b * X^Gamma + c) + d - case 7: - - e = Params[2] * pow(R, Params[0]) + Params[3]; - if (e <= 0) - Val = Params[4]; - else - Val = Params[1]*log10(e) + Params[4]; - break; - - // (Y - d) / a = log(b * X ^Gamma + c) - // pow(10, (Y-d) / a) = b * X ^Gamma + c - // pow((pow(10, (Y-d) / a) - c) / b, 1/g) = X - case -7: - Val = pow((pow(10.0, (R-Params[4]) / Params[1]) - Params[3]) / Params[2], 1.0 / Params[0]); - break; - - - //Y = a * b^(c*X+d) + e - case 8: - Val = (Params[0] * pow(Params[1], Params[2] * R + Params[3]) + Params[4]); - break; - - - // Y = (log((y-e) / a) / log(b) - d ) / c - // a=0, b=1, c=2, d=3, e=4, - case -8: - - disc = R - Params[4]; - if (disc < 0) Val = 0; - else - Val = (log(disc / Params[0]) / log(Params[1]) - Params[3]) / Params[2]; - break; - - // S-Shaped: (1 - (1-x)^1/g)^1/g - case 108: - Val = pow(1.0 - pow(1 - R, 1/Params[0]), 1/Params[0]); - break; - - // y = (1 - (1-x)^1/g)^1/g - // y^g = (1 - (1-x)^1/g) - // 1 - y^g = (1-x)^1/g - // (1 - y^g)^g = 1 - x - // 1 - (1 - y^g)^g - case -108: - Val = 1 - pow(1 - pow(R, Params[0]), Params[0]); - break; - - default: - // Unsupported parametric curve. Should never reach here - return 0; - } - - return Val; -} - -// Evaluate a segmented funtion for a single value. Return -1 if no valid segment found . -// If fn type is 0, perform an interpolation on the table -static -cmsFloat64Number EvalSegmentedFn(const cmsToneCurve *g, cmsFloat64Number R) -{ - int i; - - for (i = g ->nSegments-1; i >= 0 ; --i) { - - // Check for domain - if ((R > g ->Segments[i].x0) && (R <= g ->Segments[i].x1)) { - - // Type == 0 means segment is sampled - if (g ->Segments[i].Type == 0) { - - cmsFloat32Number R1 = (cmsFloat32Number) (R - g ->Segments[i].x0) / (g ->Segments[i].x1 - g ->Segments[i].x0); - cmsFloat32Number Out; - - // Setup the table (TODO: clean that) - g ->SegInterp[i]-> Table = g ->Segments[i].SampledPoints; - - g ->SegInterp[i] -> Interpolation.LerpFloat(&R1, &Out, g ->SegInterp[i]); - - return Out; - } - else - return g ->Evals[i](g->Segments[i].Type, g ->Segments[i].Params, R); - } - } - - return MINUS_INF; -} - -// Access to estimated low-res table -cmsUInt32Number CMSEXPORT cmsGetToneCurveEstimatedTableEntries(const cmsToneCurve* t) -{ - _cmsAssert(t != NULL); - return t ->nEntries; -} - -const cmsUInt16Number* CMSEXPORT cmsGetToneCurveEstimatedTable(const cmsToneCurve* t) -{ - _cmsAssert(t != NULL); - return t ->Table16; -} - - -// Create an empty gamma curve, by using tables. This specifies only the limited-precision part, and leaves the -// floating point description empty. -cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurve16(cmsContext ContextID, cmsInt32Number nEntries, const cmsUInt16Number Values[]) -{ - return AllocateToneCurveStruct(ContextID, nEntries, 0, NULL, Values); -} - -static -int EntriesByGamma(cmsFloat64Number Gamma) -{ - if (fabs(Gamma - 1.0) < 0.001) return 2; - return 4096; -} - - -// Create a segmented gamma, fill the table -cmsToneCurve* CMSEXPORT cmsBuildSegmentedToneCurve(cmsContext ContextID, - cmsInt32Number nSegments, const cmsCurveSegment Segments[]) -{ - int i; - cmsFloat64Number R, Val; - cmsToneCurve* g; - int nGridPoints = 4096; - - _cmsAssert(Segments != NULL); - - // Optimizatin for identity curves. - if (nSegments == 1 && Segments[0].Type == 1) { - - nGridPoints = EntriesByGamma(Segments[0].Params[0]); - } - - g = AllocateToneCurveStruct(ContextID, nGridPoints, nSegments, Segments, NULL); - if (g == NULL) return NULL; - - // Once we have the floating point version, we can approximate a 16 bit table of 4096 entries - // for performance reasons. This table would normally not be used except on 8/16 bits transforms. - for (i=0; i < nGridPoints; i++) { - - R = (cmsFloat64Number) i / (nGridPoints-1); - - Val = EvalSegmentedFn(g, R); - - // Round and saturate - g ->Table16[i] = _cmsQuickSaturateWord(Val * 65535.0); - } - - return g; -} - -// Use a segmented curve to store the floating point table -cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurveFloat(cmsContext ContextID, cmsUInt32Number nEntries, const cmsFloat32Number values[]) -{ - cmsCurveSegment Seg[3]; - - // A segmented tone curve should have function segments in the first and last positions - // Initialize segmented curve part up to 0 to constant value = samples[0] - Seg[0].x0 = MINUS_INF; - Seg[0].x1 = 0; - Seg[0].Type = 6; - - Seg[0].Params[0] = 1; - Seg[0].Params[1] = 0; - Seg[0].Params[2] = 0; - Seg[0].Params[3] = values[0]; - Seg[0].Params[4] = 0; - - // From zero to 1 - Seg[1].x0 = 0; - Seg[1].x1 = 1.0; - Seg[1].Type = 0; - - Seg[1].nGridPoints = nEntries; - Seg[1].SampledPoints = (cmsFloat32Number*) values; - - // Final segment is constant = lastsample - Seg[2].x0 = 1.0; - Seg[2].x1 = PLUS_INF; - Seg[2].Type = 6; - - Seg[2].Params[0] = 1; - Seg[2].Params[1] = 0; - Seg[2].Params[2] = 0; - Seg[2].Params[3] = values[nEntries-1]; - Seg[2].Params[4] = 0; - - - return cmsBuildSegmentedToneCurve(ContextID, 3, Seg); -} - -// Parametric curves -// -// Parameters goes as: Curve, a, b, c, d, e, f -// Type is the ICC type +1 -// if type is negative, then the curve is analyticaly inverted -cmsToneCurve* CMSEXPORT cmsBuildParametricToneCurve(cmsContext ContextID, cmsInt32Number Type, const cmsFloat64Number Params[]) -{ - cmsCurveSegment Seg0; - int Pos = 0; - cmsUInt32Number size; - _cmsParametricCurvesCollection* c = GetParametricCurveByType(ContextID, Type, &Pos); - - _cmsAssert(Params != NULL); - - if (c == NULL) { - cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Invalid parametric curve type %d", Type); - return NULL; - } - - memset(&Seg0, 0, sizeof(Seg0)); - - Seg0.x0 = MINUS_INF; - Seg0.x1 = PLUS_INF; - Seg0.Type = Type; - - size = c->ParameterCount[Pos] * sizeof(cmsFloat64Number); - memmove(Seg0.Params, Params, size); - - return cmsBuildSegmentedToneCurve(ContextID, 1, &Seg0); -} - - - -// Build a gamma table based on gamma constant -cmsToneCurve* CMSEXPORT cmsBuildGamma(cmsContext ContextID, cmsFloat64Number Gamma) -{ - return cmsBuildParametricToneCurve(ContextID, 1, &Gamma); -} - - -// Free all memory taken by the gamma curve -void CMSEXPORT cmsFreeToneCurve(cmsToneCurve* Curve) -{ - cmsContext ContextID; - - // added by Xiaochuan Liu - // Curve->InterpParams may be null - if (Curve == NULL || Curve->InterpParams == NULL) return; - - ContextID = Curve ->InterpParams->ContextID; - - _cmsFreeInterpParams(Curve ->InterpParams); - Curve ->InterpParams = NULL; - - if (Curve -> Table16) - { - _cmsFree(ContextID, Curve ->Table16); - Curve ->Table16 = NULL; - } - - if (Curve ->Segments) { - - cmsUInt32Number i; - - for (i=0; i < Curve ->nSegments; i++) { - - if (Curve ->Segments[i].SampledPoints) { - _cmsFree(ContextID, Curve ->Segments[i].SampledPoints); - Curve ->Segments[i].SampledPoints = NULL; - } - - if (Curve ->SegInterp[i] != 0) - { - _cmsFreeInterpParams(Curve->SegInterp[i]); - Curve->SegInterp[i] = NULL; - } - } - - _cmsFree(ContextID, Curve ->Segments); - Curve ->Segments = NULL; - _cmsFree(ContextID, Curve ->SegInterp); - Curve ->SegInterp = NULL; - } - - if (Curve -> Evals) - { - _cmsFree(ContextID, Curve -> Evals); - Curve -> Evals = NULL; - } - - if (Curve) - { - _cmsFree(ContextID, Curve); - Curve = NULL; - } -} - -// Utility function, free 3 gamma tables -void CMSEXPORT cmsFreeToneCurveTriple(cmsToneCurve* Curve[3]) -{ - - _cmsAssert(Curve != NULL); - - if (Curve[0] != NULL) cmsFreeToneCurve(Curve[0]); - if (Curve[1] != NULL) cmsFreeToneCurve(Curve[1]); - if (Curve[2] != NULL) cmsFreeToneCurve(Curve[2]); - - Curve[0] = Curve[1] = Curve[2] = NULL; -} - - -// Duplicate a gamma table -cmsToneCurve* CMSEXPORT cmsDupToneCurve(const cmsToneCurve* In) -{ - // Xiaochuan Liu - // fix openpdf bug(mantis id:0055683, google id:360198) - // the function CurveSetElemTypeFree in cmslut.c also needs to check pointer - if (In == NULL || In ->InterpParams == NULL || In ->Segments == NULL || In ->Table16 == NULL) return NULL; - - return AllocateToneCurveStruct(In ->InterpParams ->ContextID, In ->nEntries, In ->nSegments, In ->Segments, In ->Table16); -} - -// Joins two curves for X and Y. Curves should be monotonic. -// We want to get -// -// y = Y^-1(X(t)) -// -cmsToneCurve* CMSEXPORT cmsJoinToneCurve(cmsContext ContextID, - const cmsToneCurve* X, - const cmsToneCurve* Y, cmsUInt32Number nResultingPoints) -{ - cmsToneCurve* out = NULL; - cmsToneCurve* Yreversed = NULL; - cmsFloat32Number t, x; - cmsFloat32Number* Res = NULL; - cmsUInt32Number i; - - - _cmsAssert(X != NULL); - _cmsAssert(Y != NULL); - - Yreversed = cmsReverseToneCurveEx(nResultingPoints, Y); - if (Yreversed == NULL) goto Error; - - Res = (cmsFloat32Number*) _cmsCalloc(ContextID, nResultingPoints, sizeof(cmsFloat32Number)); - if (Res == NULL) goto Error; - - //Iterate - for (i=0; i < nResultingPoints; i++) { - - t = (cmsFloat32Number) i / (nResultingPoints-1); - x = cmsEvalToneCurveFloat(X, t); - Res[i] = cmsEvalToneCurveFloat(Yreversed, x); - } - - // Allocate space for output - out = cmsBuildTabulatedToneCurveFloat(ContextID, nResultingPoints, Res); - -Error: - - if (Res != NULL) _cmsFree(ContextID, Res); - if (Yreversed != NULL) cmsFreeToneCurve(Yreversed); - - return out; -} - - - -// Get the surrounding nodes. This is tricky on non-monotonic tables -static -int GetInterval(cmsFloat64Number In, const cmsUInt16Number LutTable[], const struct _cms_interp_struc* p) -{ - int i; - int y0, y1; - - // A 1 point table is not allowed - if (p -> Domain[0] < 1) return -1; - - // Let's see if ascending or descending. - if (LutTable[0] < LutTable[p ->Domain[0]]) { - - // Table is overall ascending - for (i=p->Domain[0]-1; i >=0; --i) { - - y0 = LutTable[i]; - y1 = LutTable[i+1]; - - if (y0 <= y1) { // Increasing - if (In >= y0 && In <= y1) return i; - } - else - if (y1 < y0) { // Decreasing - if (In >= y1 && In <= y0) return i; - } - } - } - else { - // Table is overall descending - for (i=0; i < (int) p -> Domain[0]; i++) { - - y0 = LutTable[i]; - y1 = LutTable[i+1]; - - if (y0 <= y1) { // Increasing - if (In >= y0 && In <= y1) return i; - } - else - if (y1 < y0) { // Decreasing - if (In >= y1 && In <= y0) return i; - } - } - } - - return -1; -} - -// Reverse a gamma table -cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsInt32Number nResultSamples, const cmsToneCurve* InCurve) -{ - cmsToneCurve *out; - cmsFloat64Number a = 0, b = 0, y, x1, y1, x2, y2; - int i, j; - int Ascending; - - _cmsAssert(InCurve != NULL); - - // Try to reverse it analytically whatever possible - - if (InCurve ->nSegments == 1 && InCurve ->Segments[0].Type > 0 && - /* InCurve -> Segments[0].Type <= 5 */ - GetParametricCurveByType(InCurve ->InterpParams->ContextID, InCurve ->Segments[0].Type, NULL) != NULL) { - - return cmsBuildParametricToneCurve(InCurve ->InterpParams->ContextID, - -(InCurve -> Segments[0].Type), - InCurve -> Segments[0].Params); - } - - // Nope, reverse the table. - out = cmsBuildTabulatedToneCurve16(InCurve ->InterpParams->ContextID, nResultSamples, NULL); - if (out == NULL) - return NULL; - - // We want to know if this is an ascending or descending table - Ascending = !cmsIsToneCurveDescending(InCurve); - - // Iterate across Y axis - for (i=0; i < nResultSamples; i++) { - - y = (cmsFloat64Number) i * 65535.0 / (nResultSamples - 1); - - // Find interval in which y is within. - j = GetInterval(y, InCurve->Table16, InCurve->InterpParams); - if (j >= 0) { - - - // Get limits of interval - x1 = InCurve ->Table16[j]; - x2 = InCurve ->Table16[j+1]; - - y1 = (cmsFloat64Number) (j * 65535.0) / (InCurve ->nEntries - 1); - y2 = (cmsFloat64Number) ((j+1) * 65535.0 ) / (InCurve ->nEntries - 1); - - // If collapsed, then use any - if (x1 == x2) { - - out ->Table16[i] = _cmsQuickSaturateWord(Ascending ? y2 : y1); - continue; - - } else { - - // Interpolate - a = (y2 - y1) / (x2 - x1); - b = y2 - a * x2; - } - } - - out ->Table16[i] = _cmsQuickSaturateWord(a* y + b); - } - - - return out; -} - -// Reverse a gamma table -cmsToneCurve* CMSEXPORT cmsReverseToneCurve(const cmsToneCurve* InGamma) -{ - _cmsAssert(InGamma != NULL); - - return cmsReverseToneCurveEx(4096, InGamma); -} - -// From: Eilers, P.H.C. (1994) Smoothing and interpolation with finite -// differences. in: Graphic Gems IV, Heckbert, P.S. (ed.), Academic press. -// -// Smoothing and interpolation with second differences. -// -// Input: weights (w), data (y): vector from 1 to m. -// Input: smoothing parameter (lambda), length (m). -// Output: smoothed vector (z): vector from 1 to m. - -static -cmsBool smooth2(cmsContext ContextID, cmsFloat32Number w[], cmsFloat32Number y[], cmsFloat32Number z[], cmsFloat32Number lambda, int m) -{ - int i, i1, i2; - cmsFloat32Number *c, *d, *e; - cmsBool st; - - - c = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number)); - d = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number)); - e = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number)); - - if (c != NULL && d != NULL && e != NULL) { - - - d[1] = w[1] + lambda; - c[1] = -2 * lambda / d[1]; - e[1] = lambda /d[1]; - z[1] = w[1] * y[1]; - d[2] = w[2] + 5 * lambda - d[1] * c[1] * c[1]; - c[2] = (-4 * lambda - d[1] * c[1] * e[1]) / d[2]; - e[2] = lambda / d[2]; - z[2] = w[2] * y[2] - c[1] * z[1]; - - for (i = 3; i < m - 1; i++) { - i1 = i - 1; i2 = i - 2; - d[i]= w[i] + 6 * lambda - c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2]; - c[i] = (-4 * lambda -d[i1] * c[i1] * e[i1])/ d[i]; - e[i] = lambda / d[i]; - z[i] = w[i] * y[i] - c[i1] * z[i1] - e[i2] * z[i2]; - } - - i1 = m - 2; i2 = m - 3; - - d[m - 1] = w[m - 1] + 5 * lambda -c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2]; - c[m - 1] = (-2 * lambda - d[i1] * c[i1] * e[i1]) / d[m - 1]; - z[m - 1] = w[m - 1] * y[m - 1] - c[i1] * z[i1] - e[i2] * z[i2]; - i1 = m - 1; i2 = m - 2; - - d[m] = w[m] + lambda - c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2]; - z[m] = (w[m] * y[m] - c[i1] * z[i1] - e[i2] * z[i2]) / d[m]; - z[m - 1] = z[m - 1] / d[m - 1] - c[m - 1] * z[m]; - - for (i = m - 2; 1<= i; i--) - z[i] = z[i] / d[i] - c[i] * z[i + 1] - e[i] * z[i + 2]; - - st = TRUE; - } - else st = FALSE; - - if (c != NULL) _cmsFree(ContextID, c); - if (d != NULL) _cmsFree(ContextID, d); - if (e != NULL) _cmsFree(ContextID, e); - - return st; -} - -// Smooths a curve sampled at regular intervals. -cmsBool CMSEXPORT cmsSmoothToneCurve(cmsToneCurve* Tab, cmsFloat64Number lambda) -{ - cmsFloat32Number w[MAX_NODES_IN_CURVE], y[MAX_NODES_IN_CURVE], z[MAX_NODES_IN_CURVE]; - int i, nItems, Zeros, Poles; - - if (Tab == NULL) return FALSE; - - if (cmsIsToneCurveLinear(Tab)) return TRUE; // Nothing to do - - nItems = Tab -> nEntries; - - if (nItems >= MAX_NODES_IN_CURVE) { - cmsSignalError(Tab ->InterpParams->ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: too many points."); - return FALSE; - } - - memset(w, 0, nItems * sizeof(cmsFloat32Number)); - memset(y, 0, nItems * sizeof(cmsFloat32Number)); - memset(z, 0, nItems * sizeof(cmsFloat32Number)); - - for (i=0; i < nItems; i++) - { - y[i+1] = (cmsFloat32Number) Tab -> Table16[i]; - w[i+1] = 1.0; - } - - if (!smooth2(Tab ->InterpParams->ContextID, w, y, z, (cmsFloat32Number) lambda, nItems)) return FALSE; - - // Do some reality - checking... - Zeros = Poles = 0; - for (i=nItems; i > 1; --i) { - - if (z[i] == 0.) Zeros++; - if (z[i] >= 65535.) Poles++; - if (z[i] < z[i-1]) { - cmsSignalError(Tab ->InterpParams->ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Non-Monotonic."); - return FALSE; - } - } - - if (Zeros > (nItems / 3)) { - cmsSignalError(Tab ->InterpParams->ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Degenerated, mostly zeros."); - return FALSE; - } - if (Poles > (nItems / 3)) { - cmsSignalError(Tab ->InterpParams->ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Degenerated, mostly poles."); - return FALSE; - } - - // Seems ok - for (i=0; i < nItems; i++) { - - // Clamp to cmsUInt16Number - Tab -> Table16[i] = _cmsQuickSaturateWord(z[i+1]); - } - - return TRUE; -} - -// Is a table linear? Do not use parametric since we cannot guarantee some weird parameters resulting -// in a linear table. This way assures it is linear in 12 bits, which should be enought in most cases. -cmsBool CMSEXPORT cmsIsToneCurveLinear(const cmsToneCurve* Curve) -{ - cmsUInt32Number i; - int diff; - - _cmsAssert(Curve != NULL); - - for (i=0; i < Curve ->nEntries; i++) { - - diff = abs((int) Curve->Table16[i] - (int) _cmsQuantizeVal(i, Curve ->nEntries)); - if (diff > 0x0f) - return FALSE; - } - - return TRUE; -} - -// Same, but for monotonicity -cmsBool CMSEXPORT cmsIsToneCurveMonotonic(const cmsToneCurve* t) -{ - int n; - int i, last; - cmsBool lDescending; - - _cmsAssert(t != NULL); - - // Degenerated curves are monotonic? Ok, let's pass them - n = t ->nEntries; - if (n < 2) return TRUE; - - // Curve direction - lDescending = cmsIsToneCurveDescending(t); - - if (lDescending) { - - last = t ->Table16[0]; - - for (i = 1; i < n; i++) { - - if (t ->Table16[i] - last > 2) // We allow some ripple - return FALSE; - else - last = t ->Table16[i]; - - } - } - else { - - last = t ->Table16[n-1]; - - for (i = n-2; i >= 0; --i) { - - if (t ->Table16[i] - last > 2) - return FALSE; - else - last = t ->Table16[i]; - - } - } - - return TRUE; -} - -// Same, but for descending tables -cmsBool CMSEXPORT cmsIsToneCurveDescending(const cmsToneCurve* t) -{ - _cmsAssert(t != NULL); - - return t ->Table16[0] > t ->Table16[t ->nEntries-1]; -} - - -// Another info fn: is out gamma table multisegment? -cmsBool CMSEXPORT cmsIsToneCurveMultisegment(const cmsToneCurve* t) -{ - _cmsAssert(t != NULL); - - return t -> nSegments > 1; -} - -cmsInt32Number CMSEXPORT cmsGetToneCurveParametricType(const cmsToneCurve* t) -{ - _cmsAssert(t != NULL); - - if (t -> nSegments != 1) return 0; - return t ->Segments[0].Type; -} - -// We need accuracy this time -cmsFloat32Number CMSEXPORT cmsEvalToneCurveFloat(const cmsToneCurve* Curve, cmsFloat32Number v) -{ - _cmsAssert(Curve != NULL); - - // Check for 16 bits table. If so, this is a limited-precision tone curve - if (Curve ->nSegments == 0) { - - cmsUInt16Number In, Out; - - In = (cmsUInt16Number) _cmsQuickSaturateWord(v * 65535.0); - Out = cmsEvalToneCurve16(Curve, In); - - return (cmsFloat32Number) (Out / 65535.0); - } - - return (cmsFloat32Number) EvalSegmentedFn(Curve, v); -} - -// We need xput over here -cmsUInt16Number CMSEXPORT cmsEvalToneCurve16(const cmsToneCurve* Curve, cmsUInt16Number v) -{ - cmsUInt16Number out; - - _cmsAssert(Curve != NULL); - - Curve ->InterpParams ->Interpolation.Lerp16(&v, &out, Curve ->InterpParams); - return out; -} - - -// Least squares fitting. -// A mathematical procedure for finding the best-fitting curve to a given set of points by -// minimizing the sum of the squares of the offsets ("the residuals") of the points from the curve. -// The sum of the squares of the offsets is used instead of the offset absolute values because -// this allows the residuals to be treated as a continuous differentiable quantity. -// -// y = f(x) = x ^ g -// -// R = (yi - (xi^g)) -// R2 = (yi - (xi^g))2 -// SUM R2 = SUM (yi - (xi^g))2 -// -// dR2/dg = -2 SUM x^g log(x)(y - x^g) -// solving for dR2/dg = 0 -// -// g = 1/n * SUM(log(y) / log(x)) - -cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Number Precision) -{ - cmsFloat64Number gamma, sum, sum2; - cmsFloat64Number n, x, y, Std; - cmsUInt32Number i; - - _cmsAssert(t != NULL); - - sum = sum2 = n = 0; - - // Excluding endpoints - for (i=1; i < (MAX_NODES_IN_CURVE-1); i++) { - - x = (cmsFloat64Number) i / (MAX_NODES_IN_CURVE-1); - y = (cmsFloat64Number) cmsEvalToneCurveFloat(t, (cmsFloat32Number) x); - - // Avoid 7% on lower part to prevent - // artifacts due to linear ramps - - if (y > 0. && y < 1. && x > 0.07) { - - gamma = log(y) / log(x); - sum += gamma; - sum2 += gamma * gamma; - n++; - } - } - - // Take a look on SD to see if gamma isn't exponential at all - Std = sqrt((n * sum2 - sum * sum) / (n*(n-1))); - - if (Std > Precision) - return -1.0; - - return (sum / n); // The mean -} diff --git a/third_party/lcms2-2.6/src/cmsgmt.c b/third_party/lcms2-2.6/src/cmsgmt.c deleted file mode 100644 index 1103363a78..0000000000 --- a/third_party/lcms2-2.6/src/cmsgmt.c +++ /dev/null @@ -1,590 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- -// - -#include "lcms2_internal.h" - - -// Auxiliar: append a Lab identity after the given sequence of profiles -// and return the transform. Lab profile is closed, rest of profiles are kept open. -cmsHTRANSFORM _cmsChain2Lab(cmsContext ContextID, - cmsUInt32Number nProfiles, - cmsUInt32Number InputFormat, - cmsUInt32Number OutputFormat, - const cmsUInt32Number Intents[], - const cmsHPROFILE hProfiles[], - const cmsBool BPC[], - const cmsFloat64Number AdaptationStates[], - cmsUInt32Number dwFlags) -{ - cmsHTRANSFORM xform; - cmsHPROFILE hLab; - cmsHPROFILE ProfileList[256]; - cmsBool BPCList[256]; - cmsFloat64Number AdaptationList[256]; - cmsUInt32Number IntentList[256]; - cmsUInt32Number i; - - // This is a rather big number and there is no need of dynamic memory - // since we are adding a profile, 254 + 1 = 255 and this is the limit - if (nProfiles > 254) return NULL; - - // The output space - hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); - if (hLab == NULL) return NULL; - - // Create a copy of parameters - for (i=0; i < nProfiles; i++) { - - ProfileList[i] = hProfiles[i]; - BPCList[i] = BPC[i]; - AdaptationList[i] = AdaptationStates[i]; - IntentList[i] = Intents[i]; - } - - // Place Lab identity at chain's end. - ProfileList[nProfiles] = hLab; - BPCList[nProfiles] = 0; - AdaptationList[nProfiles] = 1.0; - IntentList[nProfiles] = INTENT_RELATIVE_COLORIMETRIC; - - // Create the transform - xform = cmsCreateExtendedTransform(ContextID, nProfiles + 1, ProfileList, - BPCList, - IntentList, - AdaptationList, - NULL, 0, - InputFormat, - OutputFormat, - dwFlags); - - cmsCloseProfile(hLab); - - return xform; -} - - -// Compute K -> L* relationship. Flags may include black point compensation. In this case, -// the relationship is assumed from the profile with BPC to a black point zero. -static -cmsToneCurve* ComputeKToLstar(cmsContext ContextID, - cmsUInt32Number nPoints, - cmsUInt32Number nProfiles, - const cmsUInt32Number Intents[], - const cmsHPROFILE hProfiles[], - const cmsBool BPC[], - const cmsFloat64Number AdaptationStates[], - cmsUInt32Number dwFlags) -{ - cmsToneCurve* out = NULL; - cmsUInt32Number i; - cmsHTRANSFORM xform; - cmsCIELab Lab; - cmsFloat32Number cmyk[4]; - cmsFloat32Number* SampledPoints; - - xform = _cmsChain2Lab(ContextID, nProfiles, TYPE_CMYK_FLT, TYPE_Lab_DBL, Intents, hProfiles, BPC, AdaptationStates, dwFlags); - if (xform == NULL) return NULL; - - SampledPoints = (cmsFloat32Number*) _cmsCalloc(ContextID, nPoints, sizeof(cmsFloat32Number)); - if (SampledPoints == NULL) goto Error; - - for (i=0; i < nPoints; i++) { - - cmyk[0] = 0; - cmyk[1] = 0; - cmyk[2] = 0; - cmyk[3] = (cmsFloat32Number) ((i * 100.0) / (nPoints-1)); - - cmsDoTransform(xform, cmyk, &Lab, 1); - SampledPoints[i]= (cmsFloat32Number) (1.0 - Lab.L / 100.0); // Negate K for easier operation - } - - out = cmsBuildTabulatedToneCurveFloat(ContextID, nPoints, SampledPoints); - -Error: - - cmsDeleteTransform(xform); - if (SampledPoints) _cmsFree(ContextID, SampledPoints); - - return out; -} - - -// Compute Black tone curve on a CMYK -> CMYK transform. This is done by -// using the proof direction on both profiles to find K->L* relationship -// then joining both curves. dwFlags may include black point compensation. -cmsToneCurve* _cmsBuildKToneCurve(cmsContext ContextID, - cmsUInt32Number nPoints, - cmsUInt32Number nProfiles, - const cmsUInt32Number Intents[], - const cmsHPROFILE hProfiles[], - const cmsBool BPC[], - const cmsFloat64Number AdaptationStates[], - cmsUInt32Number dwFlags) -{ - cmsToneCurve *in, *out, *KTone; - - // Make sure CMYK -> CMYK - if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData || - cmsGetColorSpace(hProfiles[nProfiles-1])!= cmsSigCmykData) return NULL; - - - // Make sure last is an output profile - if (cmsGetDeviceClass(hProfiles[nProfiles - 1]) != cmsSigOutputClass) return NULL; - - // Create individual curves. BPC works also as each K to L* is - // computed as a BPC to zero black point in case of L* - in = ComputeKToLstar(ContextID, nPoints, nProfiles - 1, Intents, hProfiles, BPC, AdaptationStates, dwFlags); - if (in == NULL) return NULL; - - out = ComputeKToLstar(ContextID, nPoints, 1, - Intents + (nProfiles - 1), - &hProfiles [nProfiles - 1], - BPC + (nProfiles - 1), - AdaptationStates + (nProfiles - 1), - dwFlags); - if (out == NULL) { - cmsFreeToneCurve(in); - return NULL; - } - - // Build the relationship. This effectively limits the maximum accuracy to 16 bits, but - // since this is used on black-preserving LUTs, we are not loosing accuracy in any case - KTone = cmsJoinToneCurve(ContextID, in, out, nPoints); - - // Get rid of components - cmsFreeToneCurve(in); cmsFreeToneCurve(out); - - // Something went wrong... - if (KTone == NULL) return NULL; - - // Make sure it is monotonic - if (!cmsIsToneCurveMonotonic(KTone)) { - cmsFreeToneCurve(KTone); - return NULL; - } - - return KTone; -} - - -// Gamut LUT Creation ----------------------------------------------------------------------------------------- - -// Used by gamut & softproofing - -typedef struct { - - cmsHTRANSFORM hInput; // From whatever input color space. 16 bits to DBL - cmsHTRANSFORM hForward, hReverse; // Transforms going from Lab to colorant and back - cmsFloat64Number Thereshold; // The thereshold after which is considered out of gamut - - } GAMUTCHAIN; - -// This sampler does compute gamut boundaries by comparing original -// values with a transform going back and forth. Values above ERR_THERESHOLD -// of maximum are considered out of gamut. - -#define ERR_THERESHOLD 5 - - -static -int GamutSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) -{ - GAMUTCHAIN* t = (GAMUTCHAIN* ) Cargo; - cmsCIELab LabIn1, LabOut1; - cmsCIELab LabIn2, LabOut2; - cmsUInt16Number Proof[cmsMAXCHANNELS], Proof2[cmsMAXCHANNELS]; - cmsFloat64Number dE1, dE2, ErrorRatio; - - // Assume in-gamut by default. - ErrorRatio = 1.0; - - // Convert input to Lab - cmsDoTransform(t -> hInput, In, &LabIn1, 1); - - // converts from PCS to colorant. This always - // does return in-gamut values, - cmsDoTransform(t -> hForward, &LabIn1, Proof, 1); - - // Now, do the inverse, from colorant to PCS. - cmsDoTransform(t -> hReverse, Proof, &LabOut1, 1); - - memmove(&LabIn2, &LabOut1, sizeof(cmsCIELab)); - - // Try again, but this time taking Check as input - cmsDoTransform(t -> hForward, &LabOut1, Proof2, 1); - cmsDoTransform(t -> hReverse, Proof2, &LabOut2, 1); - - // Take difference of direct value - dE1 = cmsDeltaE(&LabIn1, &LabOut1); - - // Take difference of converted value - dE2 = cmsDeltaE(&LabIn2, &LabOut2); - - - // if dE1 is small and dE2 is small, value is likely to be in gamut - if (dE1 < t->Thereshold && dE2 < t->Thereshold) - Out[0] = 0; - else { - - // if dE1 is small and dE2 is big, undefined. Assume in gamut - if (dE1 < t->Thereshold && dE2 > t->Thereshold) - Out[0] = 0; - else - // dE1 is big and dE2 is small, clearly out of gamut - if (dE1 > t->Thereshold && dE2 < t->Thereshold) - Out[0] = (cmsUInt16Number) _cmsQuickFloor((dE1 - t->Thereshold) + .5); - else { - - // dE1 is big and dE2 is also big, could be due to perceptual mapping - // so take error ratio - if (dE2 == 0.0) - ErrorRatio = dE1; - else - ErrorRatio = dE1 / dE2; - - if (ErrorRatio > t->Thereshold) - Out[0] = (cmsUInt16Number) _cmsQuickFloor((ErrorRatio - t->Thereshold) + .5); - else - Out[0] = 0; - } - } - - - return TRUE; -} - -// Does compute a gamut LUT going back and forth across pcs -> relativ. colorimetric intent -> pcs -// the dE obtained is then annotated on the LUT. Values truely out of gamut are clipped to dE = 0xFFFE -// and values changed are supposed to be handled by any gamut remapping, so, are out of gamut as well. -// -// **WARNING: This algorithm does assume that gamut remapping algorithms does NOT move in-gamut colors, -// of course, many perceptual and saturation intents does not work in such way, but relativ. ones should. - -cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID, - cmsHPROFILE hProfiles[], - cmsBool BPC[], - cmsUInt32Number Intents[], - cmsFloat64Number AdaptationStates[], - cmsUInt32Number nGamutPCSposition, - cmsHPROFILE hGamut) -{ - cmsHPROFILE hLab; - cmsPipeline* Gamut; - cmsStage* CLUT; - cmsUInt32Number dwFormat; - GAMUTCHAIN Chain; - int nChannels, nGridpoints; - cmsColorSpaceSignature ColorSpace; - cmsUInt32Number i; - cmsHPROFILE ProfileList[256]; - cmsBool BPCList[256]; - cmsFloat64Number AdaptationList[256]; - cmsUInt32Number IntentList[256]; - - memset(&Chain, 0, sizeof(GAMUTCHAIN)); - - - if (nGamutPCSposition <= 0 || nGamutPCSposition > 255) { - cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong position of PCS. 1..255 expected, %d found.", nGamutPCSposition); - return NULL; - } - - hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); - if (hLab == NULL) return NULL; - - - // The figure of merit. On matrix-shaper profiles, should be almost zero as - // the conversion is pretty exact. On LUT based profiles, different resolutions - // of input and output CLUT may result in differences. - - if (cmsIsMatrixShaper(hGamut)) { - - Chain.Thereshold = 1.0; - } - else { - Chain.Thereshold = ERR_THERESHOLD; - } - - - // Create a copy of parameters - for (i=0; i < nGamutPCSposition; i++) { - ProfileList[i] = hProfiles[i]; - BPCList[i] = BPC[i]; - AdaptationList[i] = AdaptationStates[i]; - IntentList[i] = Intents[i]; - } - - // Fill Lab identity - ProfileList[nGamutPCSposition] = hLab; - BPCList[nGamutPCSposition] = 0; - AdaptationList[nGamutPCSposition] = 1.0; - IntentList[nGamutPCSposition] = INTENT_RELATIVE_COLORIMETRIC; - - - ColorSpace = cmsGetColorSpace(hGamut); - - nChannels = cmsChannelsOf(ColorSpace); - nGridpoints = _cmsReasonableGridpointsByColorspace(ColorSpace, cmsFLAGS_HIGHRESPRECALC); - dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2)); - - // 16 bits to Lab double - Chain.hInput = cmsCreateExtendedTransform(ContextID, - nGamutPCSposition + 1, - ProfileList, - BPCList, - IntentList, - AdaptationList, - NULL, 0, - dwFormat, TYPE_Lab_DBL, - cmsFLAGS_NOCACHE); - - - // Does create the forward step. Lab double to device - dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2)); - Chain.hForward = cmsCreateTransformTHR(ContextID, - hLab, TYPE_Lab_DBL, - hGamut, dwFormat, - INTENT_RELATIVE_COLORIMETRIC, - cmsFLAGS_NOCACHE); - - // Does create the backwards step - Chain.hReverse = cmsCreateTransformTHR(ContextID, hGamut, dwFormat, - hLab, TYPE_Lab_DBL, - INTENT_RELATIVE_COLORIMETRIC, - cmsFLAGS_NOCACHE); - - - // All ok? - if (Chain.hInput && Chain.hForward && Chain.hReverse) { - - // Go on, try to compute gamut LUT from PCS. This consist on a single channel containing - // dE when doing a transform back and forth on the colorimetric intent. - - Gamut = cmsPipelineAlloc(ContextID, 3, 1); - if (Gamut != NULL) { - - CLUT = cmsStageAllocCLut16bit(ContextID, nGridpoints, nChannels, 1, NULL); - if (!cmsPipelineInsertStage(Gamut, cmsAT_BEGIN, CLUT)) { - cmsPipelineFree(Gamut); - Gamut = NULL; - } - else { - cmsStageSampleCLut16bit(CLUT, GamutSampler, (void*) &Chain, 0); - } - } - } - else - Gamut = NULL; // Didn't work... - - // Free all needed stuff. - if (Chain.hInput) cmsDeleteTransform(Chain.hInput); - if (Chain.hForward) cmsDeleteTransform(Chain.hForward); - if (Chain.hReverse) cmsDeleteTransform(Chain.hReverse); - if (hLab) cmsCloseProfile(hLab); - - // And return computed hull - return Gamut; -} - -// Total Area Coverage estimation ---------------------------------------------------------------- - -typedef struct { - cmsUInt32Number nOutputChans; - cmsHTRANSFORM hRoundTrip; - cmsFloat32Number MaxTAC; - cmsFloat32Number MaxInput[cmsMAXCHANNELS]; - -} cmsTACestimator; - - -// This callback just accounts the maximum ink dropped in the given node. It does not populate any -// memory, as the destination table is NULL. Its only purpose it to know the global maximum. -static -int EstimateTAC(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void * Cargo) -{ - cmsTACestimator* bp = (cmsTACestimator*) Cargo; - cmsFloat32Number RoundTrip[cmsMAXCHANNELS]; - cmsUInt32Number i; - cmsFloat32Number Sum; - - - // Evaluate the xform - cmsDoTransform(bp->hRoundTrip, In, RoundTrip, 1); - - // All all amounts of ink - for (Sum=0, i=0; i < bp ->nOutputChans; i++) - Sum += RoundTrip[i]; - - // If above maximum, keep track of input values - if (Sum > bp ->MaxTAC) { - - bp ->MaxTAC = Sum; - - for (i=0; i < bp ->nOutputChans; i++) { - bp ->MaxInput[i] = In[i]; - } - } - - return TRUE; - - cmsUNUSED_PARAMETER(Out); -} - - -// Detect Total area coverage of the profile -cmsFloat64Number CMSEXPORT cmsDetectTAC(cmsHPROFILE hProfile) -{ - cmsTACestimator bp; - cmsUInt32Number dwFormatter; - cmsUInt32Number GridPoints[MAX_INPUT_DIMENSIONS]; - cmsHPROFILE hLab; - cmsContext ContextID = cmsGetProfileContextID(hProfile); - - // TAC only works on output profiles - if (cmsGetDeviceClass(hProfile) != cmsSigOutputClass) { - return 0; - } - - // Create a fake formatter for result - dwFormatter = cmsFormatterForColorspaceOfProfile(hProfile, 4, TRUE); - - bp.nOutputChans = T_CHANNELS(dwFormatter); - bp.MaxTAC = 0; // Initial TAC is 0 - - // for safety - if (bp.nOutputChans >= cmsMAXCHANNELS) return 0; - - hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); - if (hLab == NULL) return 0; - // Setup a roundtrip on perceptual intent in output profile for TAC estimation - bp.hRoundTrip = cmsCreateTransformTHR(ContextID, hLab, TYPE_Lab_16, - hProfile, dwFormatter, INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE); - - cmsCloseProfile(hLab); - if (bp.hRoundTrip == NULL) return 0; - - // For L* we only need black and white. For C* we need many points - GridPoints[0] = 6; - GridPoints[1] = 74; - GridPoints[2] = 74; - - - if (!cmsSliceSpace16(3, GridPoints, EstimateTAC, &bp)) { - bp.MaxTAC = 0; - } - - cmsDeleteTransform(bp.hRoundTrip); - - // Results in % - return bp.MaxTAC; -} - - -// Carefully, clamp on CIELab space. - -cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab, - double amax, double amin, - double bmax, double bmin) -{ - - // Whole Luma surface to zero - - if (Lab -> L < 0) { - - Lab-> L = Lab->a = Lab-> b = 0.0; - return FALSE; - } - - // Clamp white, DISCARD HIGHLIGHTS. This is done - // in such way because icc spec doesn't allow the - // use of L>100 as a highlight means. - - if (Lab->L > 100) - Lab -> L = 100; - - // Check out gamut prism, on a, b faces - - if (Lab -> a < amin || Lab->a > amax|| - Lab -> b < bmin || Lab->b > bmax) { - - cmsCIELCh LCh; - double h, slope; - - // Falls outside a, b limits. Transports to LCh space, - // and then do the clipping - - - if (Lab -> a == 0.0) { // Is hue exactly 90? - - // atan will not work, so clamp here - Lab -> b = Lab->b < 0 ? bmin : bmax; - return TRUE; - } - - cmsLab2LCh(&LCh, Lab); - - slope = Lab -> b / Lab -> a; - h = LCh.h; - - // There are 4 zones - - if ((h >= 0. && h < 45.) || - (h >= 315 && h <= 360.)) { - - // clip by amax - Lab -> a = amax; - Lab -> b = amax * slope; - } - else - if (h >= 45. && h < 135.) - { - // clip by bmax - Lab -> b = bmax; - Lab -> a = bmax / slope; - } - else - if (h >= 135. && h < 225.) { - // clip by amin - Lab -> a = amin; - Lab -> b = amin * slope; - - } - else - if (h >= 225. && h < 315.) { - // clip by bmin - Lab -> b = bmin; - Lab -> a = bmin / slope; - } - else { - cmsSignalError(0, cmsERROR_RANGE, "Invalid angle"); - return FALSE; - } - - } - - return TRUE; -} diff --git a/third_party/lcms2-2.6/src/cmshalf.c b/third_party/lcms2-2.6/src/cmshalf.c deleted file mode 100644 index f038b57b4c..0000000000 --- a/third_party/lcms2-2.6/src/cmshalf.c +++ /dev/null @@ -1,534 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- - -#include "lcms2_internal.h" - -#ifndef CMS_NO_HALF_SUPPORT - -// This code is inspired in the paper "Fast Half Float Conversions" -// by Jeroen van der Zijp - -static cmsUInt32Number Mantissa[2048] = { - -0x00000000, 0x33800000, 0x34000000, 0x34400000, 0x34800000, 0x34a00000, -0x34c00000, 0x34e00000, 0x35000000, 0x35100000, 0x35200000, 0x35300000, -0x35400000, 0x35500000, 0x35600000, 0x35700000, 0x35800000, 0x35880000, -0x35900000, 0x35980000, 0x35a00000, 0x35a80000, 0x35b00000, 0x35b80000, -0x35c00000, 0x35c80000, 0x35d00000, 0x35d80000, 0x35e00000, 0x35e80000, -0x35f00000, 0x35f80000, 0x36000000, 0x36040000, 0x36080000, 0x360c0000, -0x36100000, 0x36140000, 0x36180000, 0x361c0000, 0x36200000, 0x36240000, -0x36280000, 0x362c0000, 0x36300000, 0x36340000, 0x36380000, 0x363c0000, -0x36400000, 0x36440000, 0x36480000, 0x364c0000, 0x36500000, 0x36540000, -0x36580000, 0x365c0000, 0x36600000, 0x36640000, 0x36680000, 0x366c0000, -0x36700000, 0x36740000, 0x36780000, 0x367c0000, 0x36800000, 0x36820000, -0x36840000, 0x36860000, 0x36880000, 0x368a0000, 0x368c0000, 0x368e0000, -0x36900000, 0x36920000, 0x36940000, 0x36960000, 0x36980000, 0x369a0000, -0x369c0000, 0x369e0000, 0x36a00000, 0x36a20000, 0x36a40000, 0x36a60000, -0x36a80000, 0x36aa0000, 0x36ac0000, 0x36ae0000, 0x36b00000, 0x36b20000, -0x36b40000, 0x36b60000, 0x36b80000, 0x36ba0000, 0x36bc0000, 0x36be0000, -0x36c00000, 0x36c20000, 0x36c40000, 0x36c60000, 0x36c80000, 0x36ca0000, -0x36cc0000, 0x36ce0000, 0x36d00000, 0x36d20000, 0x36d40000, 0x36d60000, -0x36d80000, 0x36da0000, 0x36dc0000, 0x36de0000, 0x36e00000, 0x36e20000, -0x36e40000, 0x36e60000, 0x36e80000, 0x36ea0000, 0x36ec0000, 0x36ee0000, -0x36f00000, 0x36f20000, 0x36f40000, 0x36f60000, 0x36f80000, 0x36fa0000, -0x36fc0000, 0x36fe0000, 0x37000000, 0x37010000, 0x37020000, 0x37030000, -0x37040000, 0x37050000, 0x37060000, 0x37070000, 0x37080000, 0x37090000, -0x370a0000, 0x370b0000, 0x370c0000, 0x370d0000, 0x370e0000, 0x370f0000, -0x37100000, 0x37110000, 0x37120000, 0x37130000, 0x37140000, 0x37150000, -0x37160000, 0x37170000, 0x37180000, 0x37190000, 0x371a0000, 0x371b0000, -0x371c0000, 0x371d0000, 0x371e0000, 0x371f0000, 0x37200000, 0x37210000, -0x37220000, 0x37230000, 0x37240000, 0x37250000, 0x37260000, 0x37270000, -0x37280000, 0x37290000, 0x372a0000, 0x372b0000, 0x372c0000, 0x372d0000, -0x372e0000, 0x372f0000, 0x37300000, 0x37310000, 0x37320000, 0x37330000, -0x37340000, 0x37350000, 0x37360000, 0x37370000, 0x37380000, 0x37390000, -0x373a0000, 0x373b0000, 0x373c0000, 0x373d0000, 0x373e0000, 0x373f0000, -0x37400000, 0x37410000, 0x37420000, 0x37430000, 0x37440000, 0x37450000, -0x37460000, 0x37470000, 0x37480000, 0x37490000, 0x374a0000, 0x374b0000, -0x374c0000, 0x374d0000, 0x374e0000, 0x374f0000, 0x37500000, 0x37510000, -0x37520000, 0x37530000, 0x37540000, 0x37550000, 0x37560000, 0x37570000, -0x37580000, 0x37590000, 0x375a0000, 0x375b0000, 0x375c0000, 0x375d0000, -0x375e0000, 0x375f0000, 0x37600000, 0x37610000, 0x37620000, 0x37630000, -0x37640000, 0x37650000, 0x37660000, 0x37670000, 0x37680000, 0x37690000, -0x376a0000, 0x376b0000, 0x376c0000, 0x376d0000, 0x376e0000, 0x376f0000, -0x37700000, 0x37710000, 0x37720000, 0x37730000, 0x37740000, 0x37750000, -0x37760000, 0x37770000, 0x37780000, 0x37790000, 0x377a0000, 0x377b0000, -0x377c0000, 0x377d0000, 0x377e0000, 0x377f0000, 0x37800000, 0x37808000, -0x37810000, 0x37818000, 0x37820000, 0x37828000, 0x37830000, 0x37838000, -0x37840000, 0x37848000, 0x37850000, 0x37858000, 0x37860000, 0x37868000, -0x37870000, 0x37878000, 0x37880000, 0x37888000, 0x37890000, 0x37898000, -0x378a0000, 0x378a8000, 0x378b0000, 0x378b8000, 0x378c0000, 0x378c8000, -0x378d0000, 0x378d8000, 0x378e0000, 0x378e8000, 0x378f0000, 0x378f8000, -0x37900000, 0x37908000, 0x37910000, 0x37918000, 0x37920000, 0x37928000, -0x37930000, 0x37938000, 0x37940000, 0x37948000, 0x37950000, 0x37958000, -0x37960000, 0x37968000, 0x37970000, 0x37978000, 0x37980000, 0x37988000, -0x37990000, 0x37998000, 0x379a0000, 0x379a8000, 0x379b0000, 0x379b8000, -0x379c0000, 0x379c8000, 0x379d0000, 0x379d8000, 0x379e0000, 0x379e8000, -0x379f0000, 0x379f8000, 0x37a00000, 0x37a08000, 0x37a10000, 0x37a18000, -0x37a20000, 0x37a28000, 0x37a30000, 0x37a38000, 0x37a40000, 0x37a48000, -0x37a50000, 0x37a58000, 0x37a60000, 0x37a68000, 0x37a70000, 0x37a78000, -0x37a80000, 0x37a88000, 0x37a90000, 0x37a98000, 0x37aa0000, 0x37aa8000, -0x37ab0000, 0x37ab8000, 0x37ac0000, 0x37ac8000, 0x37ad0000, 0x37ad8000, -0x37ae0000, 0x37ae8000, 0x37af0000, 0x37af8000, 0x37b00000, 0x37b08000, -0x37b10000, 0x37b18000, 0x37b20000, 0x37b28000, 0x37b30000, 0x37b38000, -0x37b40000, 0x37b48000, 0x37b50000, 0x37b58000, 0x37b60000, 0x37b68000, -0x37b70000, 0x37b78000, 0x37b80000, 0x37b88000, 0x37b90000, 0x37b98000, -0x37ba0000, 0x37ba8000, 0x37bb0000, 0x37bb8000, 0x37bc0000, 0x37bc8000, -0x37bd0000, 0x37bd8000, 0x37be0000, 0x37be8000, 0x37bf0000, 0x37bf8000, -0x37c00000, 0x37c08000, 0x37c10000, 0x37c18000, 0x37c20000, 0x37c28000, -0x37c30000, 0x37c38000, 0x37c40000, 0x37c48000, 0x37c50000, 0x37c58000, -0x37c60000, 0x37c68000, 0x37c70000, 0x37c78000, 0x37c80000, 0x37c88000, -0x37c90000, 0x37c98000, 0x37ca0000, 0x37ca8000, 0x37cb0000, 0x37cb8000, -0x37cc0000, 0x37cc8000, 0x37cd0000, 0x37cd8000, 0x37ce0000, 0x37ce8000, -0x37cf0000, 0x37cf8000, 0x37d00000, 0x37d08000, 0x37d10000, 0x37d18000, -0x37d20000, 0x37d28000, 0x37d30000, 0x37d38000, 0x37d40000, 0x37d48000, -0x37d50000, 0x37d58000, 0x37d60000, 0x37d68000, 0x37d70000, 0x37d78000, -0x37d80000, 0x37d88000, 0x37d90000, 0x37d98000, 0x37da0000, 0x37da8000, -0x37db0000, 0x37db8000, 0x37dc0000, 0x37dc8000, 0x37dd0000, 0x37dd8000, -0x37de0000, 0x37de8000, 0x37df0000, 0x37df8000, 0x37e00000, 0x37e08000, -0x37e10000, 0x37e18000, 0x37e20000, 0x37e28000, 0x37e30000, 0x37e38000, -0x37e40000, 0x37e48000, 0x37e50000, 0x37e58000, 0x37e60000, 0x37e68000, -0x37e70000, 0x37e78000, 0x37e80000, 0x37e88000, 0x37e90000, 0x37e98000, -0x37ea0000, 0x37ea8000, 0x37eb0000, 0x37eb8000, 0x37ec0000, 0x37ec8000, -0x37ed0000, 0x37ed8000, 0x37ee0000, 0x37ee8000, 0x37ef0000, 0x37ef8000, -0x37f00000, 0x37f08000, 0x37f10000, 0x37f18000, 0x37f20000, 0x37f28000, -0x37f30000, 0x37f38000, 0x37f40000, 0x37f48000, 0x37f50000, 0x37f58000, -0x37f60000, 0x37f68000, 0x37f70000, 0x37f78000, 0x37f80000, 0x37f88000, -0x37f90000, 0x37f98000, 0x37fa0000, 0x37fa8000, 0x37fb0000, 0x37fb8000, -0x37fc0000, 0x37fc8000, 0x37fd0000, 0x37fd8000, 0x37fe0000, 0x37fe8000, -0x37ff0000, 0x37ff8000, 0x38000000, 0x38004000, 0x38008000, 0x3800c000, -0x38010000, 0x38014000, 0x38018000, 0x3801c000, 0x38020000, 0x38024000, -0x38028000, 0x3802c000, 0x38030000, 0x38034000, 0x38038000, 0x3803c000, -0x38040000, 0x38044000, 0x38048000, 0x3804c000, 0x38050000, 0x38054000, -0x38058000, 0x3805c000, 0x38060000, 0x38064000, 0x38068000, 0x3806c000, -0x38070000, 0x38074000, 0x38078000, 0x3807c000, 0x38080000, 0x38084000, -0x38088000, 0x3808c000, 0x38090000, 0x38094000, 0x38098000, 0x3809c000, -0x380a0000, 0x380a4000, 0x380a8000, 0x380ac000, 0x380b0000, 0x380b4000, -0x380b8000, 0x380bc000, 0x380c0000, 0x380c4000, 0x380c8000, 0x380cc000, -0x380d0000, 0x380d4000, 0x380d8000, 0x380dc000, 0x380e0000, 0x380e4000, -0x380e8000, 0x380ec000, 0x380f0000, 0x380f4000, 0x380f8000, 0x380fc000, -0x38100000, 0x38104000, 0x38108000, 0x3810c000, 0x38110000, 0x38114000, -0x38118000, 0x3811c000, 0x38120000, 0x38124000, 0x38128000, 0x3812c000, -0x38130000, 0x38134000, 0x38138000, 0x3813c000, 0x38140000, 0x38144000, -0x38148000, 0x3814c000, 0x38150000, 0x38154000, 0x38158000, 0x3815c000, -0x38160000, 0x38164000, 0x38168000, 0x3816c000, 0x38170000, 0x38174000, -0x38178000, 0x3817c000, 0x38180000, 0x38184000, 0x38188000, 0x3818c000, -0x38190000, 0x38194000, 0x38198000, 0x3819c000, 0x381a0000, 0x381a4000, -0x381a8000, 0x381ac000, 0x381b0000, 0x381b4000, 0x381b8000, 0x381bc000, -0x381c0000, 0x381c4000, 0x381c8000, 0x381cc000, 0x381d0000, 0x381d4000, -0x381d8000, 0x381dc000, 0x381e0000, 0x381e4000, 0x381e8000, 0x381ec000, -0x381f0000, 0x381f4000, 0x381f8000, 0x381fc000, 0x38200000, 0x38204000, -0x38208000, 0x3820c000, 0x38210000, 0x38214000, 0x38218000, 0x3821c000, -0x38220000, 0x38224000, 0x38228000, 0x3822c000, 0x38230000, 0x38234000, -0x38238000, 0x3823c000, 0x38240000, 0x38244000, 0x38248000, 0x3824c000, -0x38250000, 0x38254000, 0x38258000, 0x3825c000, 0x38260000, 0x38264000, -0x38268000, 0x3826c000, 0x38270000, 0x38274000, 0x38278000, 0x3827c000, -0x38280000, 0x38284000, 0x38288000, 0x3828c000, 0x38290000, 0x38294000, -0x38298000, 0x3829c000, 0x382a0000, 0x382a4000, 0x382a8000, 0x382ac000, -0x382b0000, 0x382b4000, 0x382b8000, 0x382bc000, 0x382c0000, 0x382c4000, -0x382c8000, 0x382cc000, 0x382d0000, 0x382d4000, 0x382d8000, 0x382dc000, -0x382e0000, 0x382e4000, 0x382e8000, 0x382ec000, 0x382f0000, 0x382f4000, -0x382f8000, 0x382fc000, 0x38300000, 0x38304000, 0x38308000, 0x3830c000, -0x38310000, 0x38314000, 0x38318000, 0x3831c000, 0x38320000, 0x38324000, -0x38328000, 0x3832c000, 0x38330000, 0x38334000, 0x38338000, 0x3833c000, -0x38340000, 0x38344000, 0x38348000, 0x3834c000, 0x38350000, 0x38354000, -0x38358000, 0x3835c000, 0x38360000, 0x38364000, 0x38368000, 0x3836c000, -0x38370000, 0x38374000, 0x38378000, 0x3837c000, 0x38380000, 0x38384000, -0x38388000, 0x3838c000, 0x38390000, 0x38394000, 0x38398000, 0x3839c000, -0x383a0000, 0x383a4000, 0x383a8000, 0x383ac000, 0x383b0000, 0x383b4000, -0x383b8000, 0x383bc000, 0x383c0000, 0x383c4000, 0x383c8000, 0x383cc000, -0x383d0000, 0x383d4000, 0x383d8000, 0x383dc000, 0x383e0000, 0x383e4000, -0x383e8000, 0x383ec000, 0x383f0000, 0x383f4000, 0x383f8000, 0x383fc000, -0x38400000, 0x38404000, 0x38408000, 0x3840c000, 0x38410000, 0x38414000, -0x38418000, 0x3841c000, 0x38420000, 0x38424000, 0x38428000, 0x3842c000, -0x38430000, 0x38434000, 0x38438000, 0x3843c000, 0x38440000, 0x38444000, -0x38448000, 0x3844c000, 0x38450000, 0x38454000, 0x38458000, 0x3845c000, -0x38460000, 0x38464000, 0x38468000, 0x3846c000, 0x38470000, 0x38474000, -0x38478000, 0x3847c000, 0x38480000, 0x38484000, 0x38488000, 0x3848c000, -0x38490000, 0x38494000, 0x38498000, 0x3849c000, 0x384a0000, 0x384a4000, -0x384a8000, 0x384ac000, 0x384b0000, 0x384b4000, 0x384b8000, 0x384bc000, -0x384c0000, 0x384c4000, 0x384c8000, 0x384cc000, 0x384d0000, 0x384d4000, -0x384d8000, 0x384dc000, 0x384e0000, 0x384e4000, 0x384e8000, 0x384ec000, -0x384f0000, 0x384f4000, 0x384f8000, 0x384fc000, 0x38500000, 0x38504000, -0x38508000, 0x3850c000, 0x38510000, 0x38514000, 0x38518000, 0x3851c000, -0x38520000, 0x38524000, 0x38528000, 0x3852c000, 0x38530000, 0x38534000, -0x38538000, 0x3853c000, 0x38540000, 0x38544000, 0x38548000, 0x3854c000, -0x38550000, 0x38554000, 0x38558000, 0x3855c000, 0x38560000, 0x38564000, -0x38568000, 0x3856c000, 0x38570000, 0x38574000, 0x38578000, 0x3857c000, -0x38580000, 0x38584000, 0x38588000, 0x3858c000, 0x38590000, 0x38594000, -0x38598000, 0x3859c000, 0x385a0000, 0x385a4000, 0x385a8000, 0x385ac000, -0x385b0000, 0x385b4000, 0x385b8000, 0x385bc000, 0x385c0000, 0x385c4000, -0x385c8000, 0x385cc000, 0x385d0000, 0x385d4000, 0x385d8000, 0x385dc000, -0x385e0000, 0x385e4000, 0x385e8000, 0x385ec000, 0x385f0000, 0x385f4000, -0x385f8000, 0x385fc000, 0x38600000, 0x38604000, 0x38608000, 0x3860c000, -0x38610000, 0x38614000, 0x38618000, 0x3861c000, 0x38620000, 0x38624000, -0x38628000, 0x3862c000, 0x38630000, 0x38634000, 0x38638000, 0x3863c000, -0x38640000, 0x38644000, 0x38648000, 0x3864c000, 0x38650000, 0x38654000, -0x38658000, 0x3865c000, 0x38660000, 0x38664000, 0x38668000, 0x3866c000, -0x38670000, 0x38674000, 0x38678000, 0x3867c000, 0x38680000, 0x38684000, -0x38688000, 0x3868c000, 0x38690000, 0x38694000, 0x38698000, 0x3869c000, -0x386a0000, 0x386a4000, 0x386a8000, 0x386ac000, 0x386b0000, 0x386b4000, -0x386b8000, 0x386bc000, 0x386c0000, 0x386c4000, 0x386c8000, 0x386cc000, -0x386d0000, 0x386d4000, 0x386d8000, 0x386dc000, 0x386e0000, 0x386e4000, -0x386e8000, 0x386ec000, 0x386f0000, 0x386f4000, 0x386f8000, 0x386fc000, -0x38700000, 0x38704000, 0x38708000, 0x3870c000, 0x38710000, 0x38714000, -0x38718000, 0x3871c000, 0x38720000, 0x38724000, 0x38728000, 0x3872c000, -0x38730000, 0x38734000, 0x38738000, 0x3873c000, 0x38740000, 0x38744000, -0x38748000, 0x3874c000, 0x38750000, 0x38754000, 0x38758000, 0x3875c000, -0x38760000, 0x38764000, 0x38768000, 0x3876c000, 0x38770000, 0x38774000, -0x38778000, 0x3877c000, 0x38780000, 0x38784000, 0x38788000, 0x3878c000, -0x38790000, 0x38794000, 0x38798000, 0x3879c000, 0x387a0000, 0x387a4000, -0x387a8000, 0x387ac000, 0x387b0000, 0x387b4000, 0x387b8000, 0x387bc000, -0x387c0000, 0x387c4000, 0x387c8000, 0x387cc000, 0x387d0000, 0x387d4000, -0x387d8000, 0x387dc000, 0x387e0000, 0x387e4000, 0x387e8000, 0x387ec000, -0x387f0000, 0x387f4000, 0x387f8000, 0x387fc000, 0x38000000, 0x38002000, -0x38004000, 0x38006000, 0x38008000, 0x3800a000, 0x3800c000, 0x3800e000, -0x38010000, 0x38012000, 0x38014000, 0x38016000, 0x38018000, 0x3801a000, -0x3801c000, 0x3801e000, 0x38020000, 0x38022000, 0x38024000, 0x38026000, -0x38028000, 0x3802a000, 0x3802c000, 0x3802e000, 0x38030000, 0x38032000, -0x38034000, 0x38036000, 0x38038000, 0x3803a000, 0x3803c000, 0x3803e000, -0x38040000, 0x38042000, 0x38044000, 0x38046000, 0x38048000, 0x3804a000, -0x3804c000, 0x3804e000, 0x38050000, 0x38052000, 0x38054000, 0x38056000, -0x38058000, 0x3805a000, 0x3805c000, 0x3805e000, 0x38060000, 0x38062000, -0x38064000, 0x38066000, 0x38068000, 0x3806a000, 0x3806c000, 0x3806e000, -0x38070000, 0x38072000, 0x38074000, 0x38076000, 0x38078000, 0x3807a000, -0x3807c000, 0x3807e000, 0x38080000, 0x38082000, 0x38084000, 0x38086000, -0x38088000, 0x3808a000, 0x3808c000, 0x3808e000, 0x38090000, 0x38092000, -0x38094000, 0x38096000, 0x38098000, 0x3809a000, 0x3809c000, 0x3809e000, -0x380a0000, 0x380a2000, 0x380a4000, 0x380a6000, 0x380a8000, 0x380aa000, -0x380ac000, 0x380ae000, 0x380b0000, 0x380b2000, 0x380b4000, 0x380b6000, -0x380b8000, 0x380ba000, 0x380bc000, 0x380be000, 0x380c0000, 0x380c2000, -0x380c4000, 0x380c6000, 0x380c8000, 0x380ca000, 0x380cc000, 0x380ce000, -0x380d0000, 0x380d2000, 0x380d4000, 0x380d6000, 0x380d8000, 0x380da000, -0x380dc000, 0x380de000, 0x380e0000, 0x380e2000, 0x380e4000, 0x380e6000, -0x380e8000, 0x380ea000, 0x380ec000, 0x380ee000, 0x380f0000, 0x380f2000, -0x380f4000, 0x380f6000, 0x380f8000, 0x380fa000, 0x380fc000, 0x380fe000, -0x38100000, 0x38102000, 0x38104000, 0x38106000, 0x38108000, 0x3810a000, -0x3810c000, 0x3810e000, 0x38110000, 0x38112000, 0x38114000, 0x38116000, -0x38118000, 0x3811a000, 0x3811c000, 0x3811e000, 0x38120000, 0x38122000, -0x38124000, 0x38126000, 0x38128000, 0x3812a000, 0x3812c000, 0x3812e000, -0x38130000, 0x38132000, 0x38134000, 0x38136000, 0x38138000, 0x3813a000, -0x3813c000, 0x3813e000, 0x38140000, 0x38142000, 0x38144000, 0x38146000, -0x38148000, 0x3814a000, 0x3814c000, 0x3814e000, 0x38150000, 0x38152000, -0x38154000, 0x38156000, 0x38158000, 0x3815a000, 0x3815c000, 0x3815e000, -0x38160000, 0x38162000, 0x38164000, 0x38166000, 0x38168000, 0x3816a000, -0x3816c000, 0x3816e000, 0x38170000, 0x38172000, 0x38174000, 0x38176000, -0x38178000, 0x3817a000, 0x3817c000, 0x3817e000, 0x38180000, 0x38182000, -0x38184000, 0x38186000, 0x38188000, 0x3818a000, 0x3818c000, 0x3818e000, -0x38190000, 0x38192000, 0x38194000, 0x38196000, 0x38198000, 0x3819a000, -0x3819c000, 0x3819e000, 0x381a0000, 0x381a2000, 0x381a4000, 0x381a6000, -0x381a8000, 0x381aa000, 0x381ac000, 0x381ae000, 0x381b0000, 0x381b2000, -0x381b4000, 0x381b6000, 0x381b8000, 0x381ba000, 0x381bc000, 0x381be000, -0x381c0000, 0x381c2000, 0x381c4000, 0x381c6000, 0x381c8000, 0x381ca000, -0x381cc000, 0x381ce000, 0x381d0000, 0x381d2000, 0x381d4000, 0x381d6000, -0x381d8000, 0x381da000, 0x381dc000, 0x381de000, 0x381e0000, 0x381e2000, -0x381e4000, 0x381e6000, 0x381e8000, 0x381ea000, 0x381ec000, 0x381ee000, -0x381f0000, 0x381f2000, 0x381f4000, 0x381f6000, 0x381f8000, 0x381fa000, -0x381fc000, 0x381fe000, 0x38200000, 0x38202000, 0x38204000, 0x38206000, -0x38208000, 0x3820a000, 0x3820c000, 0x3820e000, 0x38210000, 0x38212000, -0x38214000, 0x38216000, 0x38218000, 0x3821a000, 0x3821c000, 0x3821e000, -0x38220000, 0x38222000, 0x38224000, 0x38226000, 0x38228000, 0x3822a000, -0x3822c000, 0x3822e000, 0x38230000, 0x38232000, 0x38234000, 0x38236000, -0x38238000, 0x3823a000, 0x3823c000, 0x3823e000, 0x38240000, 0x38242000, -0x38244000, 0x38246000, 0x38248000, 0x3824a000, 0x3824c000, 0x3824e000, -0x38250000, 0x38252000, 0x38254000, 0x38256000, 0x38258000, 0x3825a000, -0x3825c000, 0x3825e000, 0x38260000, 0x38262000, 0x38264000, 0x38266000, -0x38268000, 0x3826a000, 0x3826c000, 0x3826e000, 0x38270000, 0x38272000, -0x38274000, 0x38276000, 0x38278000, 0x3827a000, 0x3827c000, 0x3827e000, -0x38280000, 0x38282000, 0x38284000, 0x38286000, 0x38288000, 0x3828a000, -0x3828c000, 0x3828e000, 0x38290000, 0x38292000, 0x38294000, 0x38296000, -0x38298000, 0x3829a000, 0x3829c000, 0x3829e000, 0x382a0000, 0x382a2000, -0x382a4000, 0x382a6000, 0x382a8000, 0x382aa000, 0x382ac000, 0x382ae000, -0x382b0000, 0x382b2000, 0x382b4000, 0x382b6000, 0x382b8000, 0x382ba000, -0x382bc000, 0x382be000, 0x382c0000, 0x382c2000, 0x382c4000, 0x382c6000, -0x382c8000, 0x382ca000, 0x382cc000, 0x382ce000, 0x382d0000, 0x382d2000, -0x382d4000, 0x382d6000, 0x382d8000, 0x382da000, 0x382dc000, 0x382de000, -0x382e0000, 0x382e2000, 0x382e4000, 0x382e6000, 0x382e8000, 0x382ea000, -0x382ec000, 0x382ee000, 0x382f0000, 0x382f2000, 0x382f4000, 0x382f6000, -0x382f8000, 0x382fa000, 0x382fc000, 0x382fe000, 0x38300000, 0x38302000, -0x38304000, 0x38306000, 0x38308000, 0x3830a000, 0x3830c000, 0x3830e000, -0x38310000, 0x38312000, 0x38314000, 0x38316000, 0x38318000, 0x3831a000, -0x3831c000, 0x3831e000, 0x38320000, 0x38322000, 0x38324000, 0x38326000, -0x38328000, 0x3832a000, 0x3832c000, 0x3832e000, 0x38330000, 0x38332000, -0x38334000, 0x38336000, 0x38338000, 0x3833a000, 0x3833c000, 0x3833e000, -0x38340000, 0x38342000, 0x38344000, 0x38346000, 0x38348000, 0x3834a000, -0x3834c000, 0x3834e000, 0x38350000, 0x38352000, 0x38354000, 0x38356000, -0x38358000, 0x3835a000, 0x3835c000, 0x3835e000, 0x38360000, 0x38362000, -0x38364000, 0x38366000, 0x38368000, 0x3836a000, 0x3836c000, 0x3836e000, -0x38370000, 0x38372000, 0x38374000, 0x38376000, 0x38378000, 0x3837a000, -0x3837c000, 0x3837e000, 0x38380000, 0x38382000, 0x38384000, 0x38386000, -0x38388000, 0x3838a000, 0x3838c000, 0x3838e000, 0x38390000, 0x38392000, -0x38394000, 0x38396000, 0x38398000, 0x3839a000, 0x3839c000, 0x3839e000, -0x383a0000, 0x383a2000, 0x383a4000, 0x383a6000, 0x383a8000, 0x383aa000, -0x383ac000, 0x383ae000, 0x383b0000, 0x383b2000, 0x383b4000, 0x383b6000, -0x383b8000, 0x383ba000, 0x383bc000, 0x383be000, 0x383c0000, 0x383c2000, -0x383c4000, 0x383c6000, 0x383c8000, 0x383ca000, 0x383cc000, 0x383ce000, -0x383d0000, 0x383d2000, 0x383d4000, 0x383d6000, 0x383d8000, 0x383da000, -0x383dc000, 0x383de000, 0x383e0000, 0x383e2000, 0x383e4000, 0x383e6000, -0x383e8000, 0x383ea000, 0x383ec000, 0x383ee000, 0x383f0000, 0x383f2000, -0x383f4000, 0x383f6000, 0x383f8000, 0x383fa000, 0x383fc000, 0x383fe000, -0x38400000, 0x38402000, 0x38404000, 0x38406000, 0x38408000, 0x3840a000, -0x3840c000, 0x3840e000, 0x38410000, 0x38412000, 0x38414000, 0x38416000, -0x38418000, 0x3841a000, 0x3841c000, 0x3841e000, 0x38420000, 0x38422000, -0x38424000, 0x38426000, 0x38428000, 0x3842a000, 0x3842c000, 0x3842e000, -0x38430000, 0x38432000, 0x38434000, 0x38436000, 0x38438000, 0x3843a000, -0x3843c000, 0x3843e000, 0x38440000, 0x38442000, 0x38444000, 0x38446000, -0x38448000, 0x3844a000, 0x3844c000, 0x3844e000, 0x38450000, 0x38452000, -0x38454000, 0x38456000, 0x38458000, 0x3845a000, 0x3845c000, 0x3845e000, -0x38460000, 0x38462000, 0x38464000, 0x38466000, 0x38468000, 0x3846a000, -0x3846c000, 0x3846e000, 0x38470000, 0x38472000, 0x38474000, 0x38476000, -0x38478000, 0x3847a000, 0x3847c000, 0x3847e000, 0x38480000, 0x38482000, -0x38484000, 0x38486000, 0x38488000, 0x3848a000, 0x3848c000, 0x3848e000, -0x38490000, 0x38492000, 0x38494000, 0x38496000, 0x38498000, 0x3849a000, -0x3849c000, 0x3849e000, 0x384a0000, 0x384a2000, 0x384a4000, 0x384a6000, -0x384a8000, 0x384aa000, 0x384ac000, 0x384ae000, 0x384b0000, 0x384b2000, -0x384b4000, 0x384b6000, 0x384b8000, 0x384ba000, 0x384bc000, 0x384be000, -0x384c0000, 0x384c2000, 0x384c4000, 0x384c6000, 0x384c8000, 0x384ca000, -0x384cc000, 0x384ce000, 0x384d0000, 0x384d2000, 0x384d4000, 0x384d6000, -0x384d8000, 0x384da000, 0x384dc000, 0x384de000, 0x384e0000, 0x384e2000, -0x384e4000, 0x384e6000, 0x384e8000, 0x384ea000, 0x384ec000, 0x384ee000, -0x384f0000, 0x384f2000, 0x384f4000, 0x384f6000, 0x384f8000, 0x384fa000, -0x384fc000, 0x384fe000, 0x38500000, 0x38502000, 0x38504000, 0x38506000, -0x38508000, 0x3850a000, 0x3850c000, 0x3850e000, 0x38510000, 0x38512000, -0x38514000, 0x38516000, 0x38518000, 0x3851a000, 0x3851c000, 0x3851e000, -0x38520000, 0x38522000, 0x38524000, 0x38526000, 0x38528000, 0x3852a000, -0x3852c000, 0x3852e000, 0x38530000, 0x38532000, 0x38534000, 0x38536000, -0x38538000, 0x3853a000, 0x3853c000, 0x3853e000, 0x38540000, 0x38542000, -0x38544000, 0x38546000, 0x38548000, 0x3854a000, 0x3854c000, 0x3854e000, -0x38550000, 0x38552000, 0x38554000, 0x38556000, 0x38558000, 0x3855a000, -0x3855c000, 0x3855e000, 0x38560000, 0x38562000, 0x38564000, 0x38566000, -0x38568000, 0x3856a000, 0x3856c000, 0x3856e000, 0x38570000, 0x38572000, -0x38574000, 0x38576000, 0x38578000, 0x3857a000, 0x3857c000, 0x3857e000, -0x38580000, 0x38582000, 0x38584000, 0x38586000, 0x38588000, 0x3858a000, -0x3858c000, 0x3858e000, 0x38590000, 0x38592000, 0x38594000, 0x38596000, -0x38598000, 0x3859a000, 0x3859c000, 0x3859e000, 0x385a0000, 0x385a2000, -0x385a4000, 0x385a6000, 0x385a8000, 0x385aa000, 0x385ac000, 0x385ae000, -0x385b0000, 0x385b2000, 0x385b4000, 0x385b6000, 0x385b8000, 0x385ba000, -0x385bc000, 0x385be000, 0x385c0000, 0x385c2000, 0x385c4000, 0x385c6000, -0x385c8000, 0x385ca000, 0x385cc000, 0x385ce000, 0x385d0000, 0x385d2000, -0x385d4000, 0x385d6000, 0x385d8000, 0x385da000, 0x385dc000, 0x385de000, -0x385e0000, 0x385e2000, 0x385e4000, 0x385e6000, 0x385e8000, 0x385ea000, -0x385ec000, 0x385ee000, 0x385f0000, 0x385f2000, 0x385f4000, 0x385f6000, -0x385f8000, 0x385fa000, 0x385fc000, 0x385fe000, 0x38600000, 0x38602000, -0x38604000, 0x38606000, 0x38608000, 0x3860a000, 0x3860c000, 0x3860e000, -0x38610000, 0x38612000, 0x38614000, 0x38616000, 0x38618000, 0x3861a000, -0x3861c000, 0x3861e000, 0x38620000, 0x38622000, 0x38624000, 0x38626000, -0x38628000, 0x3862a000, 0x3862c000, 0x3862e000, 0x38630000, 0x38632000, -0x38634000, 0x38636000, 0x38638000, 0x3863a000, 0x3863c000, 0x3863e000, -0x38640000, 0x38642000, 0x38644000, 0x38646000, 0x38648000, 0x3864a000, -0x3864c000, 0x3864e000, 0x38650000, 0x38652000, 0x38654000, 0x38656000, -0x38658000, 0x3865a000, 0x3865c000, 0x3865e000, 0x38660000, 0x38662000, -0x38664000, 0x38666000, 0x38668000, 0x3866a000, 0x3866c000, 0x3866e000, -0x38670000, 0x38672000, 0x38674000, 0x38676000, 0x38678000, 0x3867a000, -0x3867c000, 0x3867e000, 0x38680000, 0x38682000, 0x38684000, 0x38686000, -0x38688000, 0x3868a000, 0x3868c000, 0x3868e000, 0x38690000, 0x38692000, -0x38694000, 0x38696000, 0x38698000, 0x3869a000, 0x3869c000, 0x3869e000, -0x386a0000, 0x386a2000, 0x386a4000, 0x386a6000, 0x386a8000, 0x386aa000, -0x386ac000, 0x386ae000, 0x386b0000, 0x386b2000, 0x386b4000, 0x386b6000, -0x386b8000, 0x386ba000, 0x386bc000, 0x386be000, 0x386c0000, 0x386c2000, -0x386c4000, 0x386c6000, 0x386c8000, 0x386ca000, 0x386cc000, 0x386ce000, -0x386d0000, 0x386d2000, 0x386d4000, 0x386d6000, 0x386d8000, 0x386da000, -0x386dc000, 0x386de000, 0x386e0000, 0x386e2000, 0x386e4000, 0x386e6000, -0x386e8000, 0x386ea000, 0x386ec000, 0x386ee000, 0x386f0000, 0x386f2000, -0x386f4000, 0x386f6000, 0x386f8000, 0x386fa000, 0x386fc000, 0x386fe000, -0x38700000, 0x38702000, 0x38704000, 0x38706000, 0x38708000, 0x3870a000, -0x3870c000, 0x3870e000, 0x38710000, 0x38712000, 0x38714000, 0x38716000, -0x38718000, 0x3871a000, 0x3871c000, 0x3871e000, 0x38720000, 0x38722000, -0x38724000, 0x38726000, 0x38728000, 0x3872a000, 0x3872c000, 0x3872e000, -0x38730000, 0x38732000, 0x38734000, 0x38736000, 0x38738000, 0x3873a000, -0x3873c000, 0x3873e000, 0x38740000, 0x38742000, 0x38744000, 0x38746000, -0x38748000, 0x3874a000, 0x3874c000, 0x3874e000, 0x38750000, 0x38752000, -0x38754000, 0x38756000, 0x38758000, 0x3875a000, 0x3875c000, 0x3875e000, -0x38760000, 0x38762000, 0x38764000, 0x38766000, 0x38768000, 0x3876a000, -0x3876c000, 0x3876e000, 0x38770000, 0x38772000, 0x38774000, 0x38776000, -0x38778000, 0x3877a000, 0x3877c000, 0x3877e000, 0x38780000, 0x38782000, -0x38784000, 0x38786000, 0x38788000, 0x3878a000, 0x3878c000, 0x3878e000, -0x38790000, 0x38792000, 0x38794000, 0x38796000, 0x38798000, 0x3879a000, -0x3879c000, 0x3879e000, 0x387a0000, 0x387a2000, 0x387a4000, 0x387a6000, -0x387a8000, 0x387aa000, 0x387ac000, 0x387ae000, 0x387b0000, 0x387b2000, -0x387b4000, 0x387b6000, 0x387b8000, 0x387ba000, 0x387bc000, 0x387be000, -0x387c0000, 0x387c2000, 0x387c4000, 0x387c6000, 0x387c8000, 0x387ca000, -0x387cc000, 0x387ce000, 0x387d0000, 0x387d2000, 0x387d4000, 0x387d6000, -0x387d8000, 0x387da000, 0x387dc000, 0x387de000, 0x387e0000, 0x387e2000, -0x387e4000, 0x387e6000, 0x387e8000, 0x387ea000, 0x387ec000, 0x387ee000, -0x387f0000, 0x387f2000, 0x387f4000, 0x387f6000, 0x387f8000, 0x387fa000, -0x387fc000, 0x387fe000 -}; - -static cmsUInt16Number Offset[64] = { -0x0000, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, -0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, -0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, -0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, -0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, -0x0400, 0x0400, 0x0000, 0x0400, 0x0400, 0x0400, -0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, -0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, -0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, -0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, -0x0400, 0x0400, 0x0400, 0x0400 -}; - -static cmsUInt32Number Exponent[64] = { -0x00000000, 0x00800000, 0x01000000, 0x01800000, 0x02000000, 0x02800000, -0x03000000, 0x03800000, 0x04000000, 0x04800000, 0x05000000, 0x05800000, -0x06000000, 0x06800000, 0x07000000, 0x07800000, 0x08000000, 0x08800000, -0x09000000, 0x09800000, 0x0a000000, 0x0a800000, 0x0b000000, 0x0b800000, -0x0c000000, 0x0c800000, 0x0d000000, 0x0d800000, 0x0e000000, 0x0e800000, -0x0f000000, 0x47800000, 0x80000000, 0x80800000, 0x81000000, 0x81800000, -0x82000000, 0x82800000, 0x83000000, 0x83800000, 0x84000000, 0x84800000, -0x85000000, 0x85800000, 0x86000000, 0x86800000, 0x87000000, 0x87800000, -0x88000000, 0x88800000, 0x89000000, 0x89800000, 0x8a000000, 0x8a800000, -0x8b000000, 0x8b800000, 0x8c000000, 0x8c800000, 0x8d000000, 0x8d800000, -0x8e000000, 0x8e800000, 0x8f000000, 0xc7800000 -}; - -static cmsUInt16Number Base[512] = { -0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, -0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, -0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, -0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, -0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, -0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, -0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, -0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, -0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, -0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, -0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, -0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x0c00, 0x1000, 0x1400, 0x1800, 0x1c00, -0x2000, 0x2400, 0x2800, 0x2c00, 0x3000, 0x3400, 0x3800, 0x3c00, 0x4000, 0x4400, -0x4800, 0x4c00, 0x5000, 0x5400, 0x5800, 0x5c00, 0x6000, 0x6400, 0x6800, 0x6c00, -0x7000, 0x7400, 0x7800, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, -0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, -0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, -0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, -0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, -0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, -0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, -0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, -0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, -0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, -0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, -0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x8000, 0x8000, 0x8000, 0x8000, -0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, -0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, -0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, -0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, -0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, -0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, -0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, -0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, -0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, -0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8001, -0x8002, 0x8004, 0x8008, 0x8010, 0x8020, 0x8040, 0x8080, 0x8100, 0x8200, 0x8400, -0x8800, 0x8c00, 0x9000, 0x9400, 0x9800, 0x9c00, 0xa000, 0xa400, 0xa800, 0xac00, -0xb000, 0xb400, 0xb800, 0xbc00, 0xc000, 0xc400, 0xc800, 0xcc00, 0xd000, 0xd400, -0xd800, 0xdc00, 0xe000, 0xe400, 0xe800, 0xec00, 0xf000, 0xf400, 0xf800, 0xfc00, -0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, -0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, -0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, -0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, -0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, -0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, -0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, -0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, -0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, -0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, -0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, -0xfc00, 0xfc00 -}; - -static cmsUInt8Number Shift[512] = { -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x17, -0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, -0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, -0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0d, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, -0x12, 0x11, 0x10, 0x0f, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, -0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, -0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x0d -}; - -cmsFloat32Number _cmsHalf2Float(cmsUInt16Number h) -{ - union { - cmsFloat32Number flt; - cmsUInt32Number num; - } out; - - int n = h >> 10; - - out.num = Mantissa[ (h & 0x3ff) + Offset[ n ] ] + Exponent[ n ]; - return out.flt; -} - -cmsUInt16Number _cmsFloat2Half(cmsFloat32Number flt) -{ - union { - cmsFloat32Number flt; - cmsUInt32Number num; - } in; - - cmsUInt32Number n, j; - - in.flt = flt; - n = in.num; - j = (n >> 23) & 0x1ff; - - return (cmsUInt16Number) ((cmsUInt32Number) Base[ j ] + (( n & 0x007fffff) >> Shift[ j ])); -} - -#endif diff --git a/third_party/lcms2-2.6/src/cmsintrp.c b/third_party/lcms2-2.6/src/cmsintrp.c deleted file mode 100644 index 14c68563ca..0000000000 --- a/third_party/lcms2-2.6/src/cmsintrp.c +++ /dev/null @@ -1,1506 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- -// - -#include "lcms2_internal.h" - -// This module incorporates several interpolation routines, for 1 to 8 channels on input and -// up to 65535 channels on output. The user may change those by using the interpolation plug-in - -// Interpolation routines by default -static cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags); - -// This is the default factory -_cmsInterpPluginChunkType _cmsInterpPluginChunk = { NULL }; - -// The interpolation plug-in memory chunk allocator/dup -void _cmsAllocInterpPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src) -{ - void* from; - - _cmsAssert(ctx != NULL); - - if (src != NULL) { - from = src ->chunks[InterpPlugin]; - } - else { - static _cmsInterpPluginChunkType InterpPluginChunk = { NULL }; - - from = &InterpPluginChunk; - } - - _cmsAssert(from != NULL); - ctx ->chunks[InterpPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsInterpPluginChunkType)); -} - - -// Main plug-in entry -cmsBool _cmsRegisterInterpPlugin(cmsContext ContextID, cmsPluginBase* Data) -{ - cmsPluginInterpolation* Plugin = (cmsPluginInterpolation*) Data; - _cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin); - - if (Data == NULL) { - - ptr ->Interpolators = NULL; - return TRUE; - } - - // Set replacement functions - ptr ->Interpolators = Plugin ->InterpolatorsFactory; - return TRUE; -} - - -// Set the interpolation method -cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p) -{ - _cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin); - - p ->Interpolation.Lerp16 = NULL; - - // Invoke factory, possibly in the Plug-in - if (ptr ->Interpolators != NULL) - p ->Interpolation = ptr->Interpolators(p -> nInputs, p ->nOutputs, p ->dwFlags); - - // If unsupported by the plug-in, go for the LittleCMS default. - // If happens only if an extern plug-in is being used - if (p ->Interpolation.Lerp16 == NULL) - p ->Interpolation = DefaultInterpolatorsFactory(p ->nInputs, p ->nOutputs, p ->dwFlags); - - // Check for valid interpolator (we just check one member of the union) - if (p ->Interpolation.Lerp16 == NULL) { - return FALSE; - } - - return TRUE; -} - - -// This function precalculates as many parameters as possible to speed up the interpolation. -cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID, - const cmsUInt32Number nSamples[], - int InputChan, int OutputChan, - const void *Table, - cmsUInt32Number dwFlags) -{ - cmsInterpParams* p; - int i; - - // Check for maximum inputs - if (InputChan > MAX_INPUT_DIMENSIONS) { - cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", InputChan, MAX_INPUT_DIMENSIONS); - return NULL; - } - - // Creates an empty object - p = (cmsInterpParams*) _cmsMallocZero(ContextID, sizeof(cmsInterpParams)); - if (p == NULL) return NULL; - - // Keep original parameters - p -> dwFlags = dwFlags; - p -> nInputs = InputChan; - p -> nOutputs = OutputChan; - p ->Table = Table; - p ->ContextID = ContextID; - - // Fill samples per input direction and domain (which is number of nodes minus one) - for (i=0; i < InputChan; i++) { - - p -> nSamples[i] = nSamples[i]; - p -> Domain[i] = nSamples[i] - 1; - } - - // Compute factors to apply to each component to index the grid array - p -> opta[0] = p -> nOutputs; - for (i=1; i < InputChan; i++) - p ->opta[i] = p ->opta[i-1] * nSamples[InputChan-i]; - - - if (!_cmsSetInterpolationRoutine(ContextID, p)) { - cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported interpolation (%d->%d channels)", InputChan, OutputChan); - _cmsFree(ContextID, p); - return NULL; - } - - // All seems ok - return p; -} - - -// This one is a wrapper on the anterior, but assuming all directions have same number of nodes -cmsInterpParams* _cmsComputeInterpParams(cmsContext ContextID, int nSamples, int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags) -{ - int i; - cmsUInt32Number Samples[MAX_INPUT_DIMENSIONS]; - - // Fill the auxiliar array - for (i=0; i < MAX_INPUT_DIMENSIONS; i++) - Samples[i] = nSamples; - - // Call the extended function - return _cmsComputeInterpParamsEx(ContextID, Samples, InputChan, OutputChan, Table, dwFlags); -} - - -// Free all associated memory -void _cmsFreeInterpParams(cmsInterpParams* p) -{ - if (p != NULL) _cmsFree(p ->ContextID, p); -} - - -// Inline fixed point interpolation -cmsINLINE cmsUInt16Number LinearInterp(cmsS15Fixed16Number a, cmsS15Fixed16Number l, cmsS15Fixed16Number h) -{ - cmsUInt32Number dif = (cmsUInt32Number) (h - l) * a + 0x8000; - dif = (dif >> 16) + l; - return (cmsUInt16Number) (dif); -} - - -// Linear interpolation (Fixed-point optimized) -static -void LinLerp1D(register const cmsUInt16Number Value[], - register cmsUInt16Number Output[], - register const cmsInterpParams* p) -{ - cmsUInt16Number y1, y0; - int cell0, rest; - int val3; - const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table; - - // if last value... - if (Value[0] == 0xffff) { - - Output[0] = LutTable[p -> Domain[0]]; - return; - } - - val3 = p -> Domain[0] * Value[0]; - val3 = _cmsToFixedDomain(val3); // To fixed 15.16 - - cell0 = FIXED_TO_INT(val3); // Cell is 16 MSB bits - rest = FIXED_REST_TO_INT(val3); // Rest is 16 LSB bits - - y0 = LutTable[cell0]; - y1 = LutTable[cell0+1]; - - - Output[0] = LinearInterp(rest, y0, y1); -} - -// To prevent out of bounds indexing -cmsINLINE cmsFloat32Number fclamp(cmsFloat32Number v) -{ - return ((v < 0.0f) || isnan(v)) ? 0.0f : (v > 1.0f ? 1.0f : v); -} - -// Floating-point version of 1D interpolation -static -void LinLerp1Dfloat(const cmsFloat32Number Value[], - cmsFloat32Number Output[], - const cmsInterpParams* p) -{ - cmsFloat32Number y1, y0; - cmsFloat32Number val2, rest; - int cell0, cell1; - const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table; - - val2 = fclamp(Value[0]); - - // if last value... - if (val2 == 1.0) { - Output[0] = LutTable[p -> Domain[0]]; - return; - } - - val2 *= p -> Domain[0]; - - cell0 = (int) floor(val2); - cell1 = (int) ceil(val2); - - // Rest is 16 LSB bits - rest = val2 - cell0; - - y0 = LutTable[cell0] ; - y1 = LutTable[cell1] ; - - Output[0] = y0 + (y1 - y0) * rest; -} - - - -// Eval gray LUT having only one input channel -static -void Eval1Input(register const cmsUInt16Number Input[], - register cmsUInt16Number Output[], - register const cmsInterpParams* p16) -{ - cmsS15Fixed16Number fk; - cmsS15Fixed16Number k0, k1, rk, K0, K1; - int v; - cmsUInt32Number OutChan; - const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; - - v = Input[0] * p16 -> Domain[0]; - fk = _cmsToFixedDomain(v); - - k0 = FIXED_TO_INT(fk); - rk = (cmsUInt16Number) FIXED_REST_TO_INT(fk); - - k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0); - - K0 = p16 -> opta[0] * k0; - K1 = p16 -> opta[0] * k1; - - for (OutChan=0; OutChan < p16->nOutputs; OutChan++) { - - Output[OutChan] = LinearInterp(rk, LutTable[K0+OutChan], LutTable[K1+OutChan]); - } -} - - - -// Eval gray LUT having only one input channel -static -void Eval1InputFloat(const cmsFloat32Number Value[], - cmsFloat32Number Output[], - const cmsInterpParams* p) -{ - cmsFloat32Number y1, y0; - cmsFloat32Number val2, rest; - int cell0, cell1; - cmsUInt32Number OutChan; - const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table; - - val2 = fclamp(Value[0]); - - // if last value... - if (val2 == 1.0) { - Output[0] = LutTable[p -> Domain[0]]; - return; - } - - val2 *= p -> Domain[0]; - - cell0 = (int) floor(val2); - cell1 = (int) ceil(val2); - - // Rest is 16 LSB bits - rest = val2 - cell0; - - cell0 *= p -> opta[0]; - cell1 *= p -> opta[0]; - - for (OutChan=0; OutChan < p->nOutputs; OutChan++) { - - y0 = LutTable[cell0 + OutChan] ; - y1 = LutTable[cell1 + OutChan] ; - - Output[OutChan] = y0 + (y1 - y0) * rest; - } -} - -// Bilinear interpolation (16 bits) - cmsFloat32Number version -static -void BilinearInterpFloat(const cmsFloat32Number Input[], - cmsFloat32Number Output[], - const cmsInterpParams* p) - -{ -# define LERP(a,l,h) (cmsFloat32Number) ((l)+(((h)-(l))*(a))) -# define DENS(i,j) (LutTable[(i)+(j)+OutChan]) - - const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table; - cmsFloat32Number px, py; - int x0, y0, - X0, Y0, X1, Y1; - int TotalOut, OutChan; - cmsFloat32Number fx, fy, - d00, d01, d10, d11, - dx0, dx1, - dxy; - - TotalOut = p -> nOutputs; - px = fclamp(Input[0]) * p->Domain[0]; - py = fclamp(Input[1]) * p->Domain[1]; - - x0 = (int) _cmsQuickFloor(px); fx = px - (cmsFloat32Number) x0; - y0 = (int) _cmsQuickFloor(py); fy = py - (cmsFloat32Number) y0; - - X0 = p -> opta[1] * x0; - X1 = X0 + (Input[0] >= 1.0 ? 0 : p->opta[1]); - - Y0 = p -> opta[0] * y0; - Y1 = Y0 + (Input[1] >= 1.0 ? 0 : p->opta[0]); - - for (OutChan = 0; OutChan < TotalOut; OutChan++) { - - d00 = DENS(X0, Y0); - d01 = DENS(X0, Y1); - d10 = DENS(X1, Y0); - d11 = DENS(X1, Y1); - - dx0 = LERP(fx, d00, d10); - dx1 = LERP(fx, d01, d11); - - dxy = LERP(fy, dx0, dx1); - - Output[OutChan] = dxy; - } - - -# undef LERP -# undef DENS -} - -// Bilinear interpolation (16 bits) - optimized version -static -void BilinearInterp16(register const cmsUInt16Number Input[], - register cmsUInt16Number Output[], - register const cmsInterpParams* p) - -{ -#define DENS(i,j) (LutTable[(i)+(j)+OutChan]) -#define LERP(a,l,h) (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a))) - - const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table; - int OutChan, TotalOut; - cmsS15Fixed16Number fx, fy; - register int rx, ry; - int x0, y0; - register int X0, X1, Y0, Y1; - int d00, d01, d10, d11, - dx0, dx1, - dxy; - - TotalOut = p -> nOutputs; - - fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]); - x0 = FIXED_TO_INT(fx); - rx = FIXED_REST_TO_INT(fx); // Rest in 0..1.0 domain - - - fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]); - y0 = FIXED_TO_INT(fy); - ry = FIXED_REST_TO_INT(fy); - - - X0 = p -> opta[1] * x0; - X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[1]); - - Y0 = p -> opta[0] * y0; - Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[0]); - - for (OutChan = 0; OutChan < TotalOut; OutChan++) { - - d00 = DENS(X0, Y0); - d01 = DENS(X0, Y1); - d10 = DENS(X1, Y0); - d11 = DENS(X1, Y1); - - dx0 = LERP(rx, d00, d10); - dx1 = LERP(rx, d01, d11); - - dxy = LERP(ry, dx0, dx1); - - Output[OutChan] = (cmsUInt16Number) dxy; - } - - -# undef LERP -# undef DENS -} - - -// Trilinear interpolation (16 bits) - cmsFloat32Number version -static -void TrilinearInterpFloat(const cmsFloat32Number Input[], - cmsFloat32Number Output[], - const cmsInterpParams* p) - -{ -# define LERP(a,l,h) (cmsFloat32Number) ((l)+(((h)-(l))*(a))) -# define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) - - const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table; - cmsFloat32Number px, py, pz; - int x0, y0, z0, - X0, Y0, Z0, X1, Y1, Z1; - int TotalOut, OutChan; - cmsFloat32Number fx, fy, fz, - d000, d001, d010, d011, - d100, d101, d110, d111, - dx00, dx01, dx10, dx11, - dxy0, dxy1, dxyz; - - TotalOut = p -> nOutputs; - - // We need some clipping here - px = fclamp(Input[0]) * p->Domain[0]; - py = fclamp(Input[1]) * p->Domain[1]; - pz = fclamp(Input[2]) * p->Domain[2]; - - x0 = (int) _cmsQuickFloor(px); fx = px - (cmsFloat32Number) x0; - y0 = (int) _cmsQuickFloor(py); fy = py - (cmsFloat32Number) y0; - z0 = (int) _cmsQuickFloor(pz); fz = pz - (cmsFloat32Number) z0; - - X0 = p -> opta[2] * x0; - X1 = X0 + (Input[0] >= 1.0 ? 0 : p->opta[2]); - - Y0 = p -> opta[1] * y0; - Y1 = Y0 + (Input[1] >= 1.0 ? 0 : p->opta[1]); - - Z0 = p -> opta[0] * z0; - Z1 = Z0 + (Input[2] >= 1.0 ? 0 : p->opta[0]); - - for (OutChan = 0; OutChan < TotalOut; OutChan++) { - - d000 = DENS(X0, Y0, Z0); - d001 = DENS(X0, Y0, Z1); - d010 = DENS(X0, Y1, Z0); - d011 = DENS(X0, Y1, Z1); - - d100 = DENS(X1, Y0, Z0); - d101 = DENS(X1, Y0, Z1); - d110 = DENS(X1, Y1, Z0); - d111 = DENS(X1, Y1, Z1); - - - dx00 = LERP(fx, d000, d100); - dx01 = LERP(fx, d001, d101); - dx10 = LERP(fx, d010, d110); - dx11 = LERP(fx, d011, d111); - - dxy0 = LERP(fy, dx00, dx10); - dxy1 = LERP(fy, dx01, dx11); - - dxyz = LERP(fz, dxy0, dxy1); - - Output[OutChan] = dxyz; - } - - -# undef LERP -# undef DENS -} - -// Trilinear interpolation (16 bits) - optimized version -static -void TrilinearInterp16(register const cmsUInt16Number Input[], - register cmsUInt16Number Output[], - register const cmsInterpParams* p) - -{ -#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) -#define LERP(a,l,h) (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a))) - - const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table; - int OutChan, TotalOut; - cmsS15Fixed16Number fx, fy, fz; - register int rx, ry, rz; - int x0, y0, z0; - register int X0, X1, Y0, Y1, Z0, Z1; - int d000, d001, d010, d011, - d100, d101, d110, d111, - dx00, dx01, dx10, dx11, - dxy0, dxy1, dxyz; - - TotalOut = p -> nOutputs; - - fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]); - x0 = FIXED_TO_INT(fx); - rx = FIXED_REST_TO_INT(fx); // Rest in 0..1.0 domain - - - fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]); - y0 = FIXED_TO_INT(fy); - ry = FIXED_REST_TO_INT(fy); - - fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]); - z0 = FIXED_TO_INT(fz); - rz = FIXED_REST_TO_INT(fz); - - - X0 = p -> opta[2] * x0; - X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[2]); - - Y0 = p -> opta[1] * y0; - Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[1]); - - Z0 = p -> opta[0] * z0; - Z1 = Z0 + (Input[2] == 0xFFFFU ? 0 : p->opta[0]); - - for (OutChan = 0; OutChan < TotalOut; OutChan++) { - - d000 = DENS(X0, Y0, Z0); - d001 = DENS(X0, Y0, Z1); - d010 = DENS(X0, Y1, Z0); - d011 = DENS(X0, Y1, Z1); - - d100 = DENS(X1, Y0, Z0); - d101 = DENS(X1, Y0, Z1); - d110 = DENS(X1, Y1, Z0); - d111 = DENS(X1, Y1, Z1); - - - dx00 = LERP(rx, d000, d100); - dx01 = LERP(rx, d001, d101); - dx10 = LERP(rx, d010, d110); - dx11 = LERP(rx, d011, d111); - - dxy0 = LERP(ry, dx00, dx10); - dxy1 = LERP(ry, dx01, dx11); - - dxyz = LERP(rz, dxy0, dxy1); - - Output[OutChan] = (cmsUInt16Number) dxyz; - } - - -# undef LERP -# undef DENS -} - - -// Tetrahedral interpolation, using Sakamoto algorithm. -#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) -static -void TetrahedralInterpFloat(const cmsFloat32Number Input[], - cmsFloat32Number Output[], - const cmsInterpParams* p) -{ - const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; - cmsFloat32Number px, py, pz; - int x0, y0, z0, - X0, Y0, Z0, X1, Y1, Z1; - cmsFloat32Number rx, ry, rz; - cmsFloat32Number c0, c1=0, c2=0, c3=0; - int OutChan, TotalOut; - - TotalOut = p -> nOutputs; - - // We need some clipping here - px = fclamp(Input[0]) * p->Domain[0]; - py = fclamp(Input[1]) * p->Domain[1]; - pz = fclamp(Input[2]) * p->Domain[2]; - - x0 = (int) _cmsQuickFloor(px); rx = (px - (cmsFloat32Number) x0); - y0 = (int) _cmsQuickFloor(py); ry = (py - (cmsFloat32Number) y0); - z0 = (int) _cmsQuickFloor(pz); rz = (pz - (cmsFloat32Number) z0); - - - X0 = p -> opta[2] * x0; - X1 = X0 + (Input[0] >= 1.0 ? 0 : p->opta[2]); - - Y0 = p -> opta[1] * y0; - Y1 = Y0 + (Input[1] >= 1.0 ? 0 : p->opta[1]); - - Z0 = p -> opta[0] * z0; - Z1 = Z0 + (Input[2] >= 1.0 ? 0 : p->opta[0]); - - for (OutChan=0; OutChan < TotalOut; OutChan++) { - - // These are the 6 Tetrahedral - - c0 = DENS(X0, Y0, Z0); - - if (rx >= ry && ry >= rz) { - - c1 = DENS(X1, Y0, Z0) - c0; - c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0); - c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); - - } - else - if (rx >= rz && rz >= ry) { - - c1 = DENS(X1, Y0, Z0) - c0; - c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); - c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0); - - } - else - if (rz >= rx && rx >= ry) { - - c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1); - c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); - c3 = DENS(X0, Y0, Z1) - c0; - - } - else - if (ry >= rx && rx >= rz) { - - c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0); - c2 = DENS(X0, Y1, Z0) - c0; - c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); - - } - else - if (ry >= rz && rz >= rx) { - - c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); - c2 = DENS(X0, Y1, Z0) - c0; - c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0); - - } - else - if (rz >= ry && ry >= rx) { - - c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); - c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1); - c3 = DENS(X0, Y0, Z1) - c0; - - } - else { - c1 = c2 = c3 = 0; - } - - Output[OutChan] = c0 + c1 * rx + c2 * ry + c3 * rz; - } - -} - -#undef DENS - - - - -static -void TetrahedralInterp16(register const cmsUInt16Number Input[], - register cmsUInt16Number Output[], - register const cmsInterpParams* p) -{ - const cmsUInt16Number* LutTable = (cmsUInt16Number*) p -> Table; - cmsS15Fixed16Number fx, fy, fz; - cmsS15Fixed16Number rx, ry, rz; - int x0, y0, z0; - cmsS15Fixed16Number c0, c1, c2, c3, Rest; - cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1; - cmsUInt32Number TotalOut = p -> nOutputs; - - fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]); - fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]); - fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]); - - x0 = FIXED_TO_INT(fx); - y0 = FIXED_TO_INT(fy); - z0 = FIXED_TO_INT(fz); - - rx = FIXED_REST_TO_INT(fx); - ry = FIXED_REST_TO_INT(fy); - rz = FIXED_REST_TO_INT(fz); - - X0 = p -> opta[2] * x0; - X1 = (Input[0] == 0xFFFFU ? 0 : p->opta[2]); - - Y0 = p -> opta[1] * y0; - Y1 = (Input[1] == 0xFFFFU ? 0 : p->opta[1]); - - Z0 = p -> opta[0] * z0; - Z1 = (Input[2] == 0xFFFFU ? 0 : p->opta[0]); - - LutTable = &LutTable[X0+Y0+Z0]; - - // Output should be computed as x = ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)) - // which expands as: x = (Rest + ((Rest+0x7fff)/0xFFFF) + 0x8000)>>16 - // This can be replaced by: t = Rest+0x8001, x = (t + (t>>16))>>16 - // at the cost of being off by one at 7fff and 17ffe. - - if (rx >= ry) { - if (ry >= rz) { - Y1 += X1; - Z1 += Y1; - for (; TotalOut; TotalOut--) { - c1 = LutTable[X1]; - c2 = LutTable[Y1]; - c3 = LutTable[Z1]; - c0 = *LutTable++; - c3 -= c2; - c2 -= c1; - c1 -= c0; - Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; - *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16); - } - } else if (rz >= rx) { - X1 += Z1; - Y1 += X1; - for (; TotalOut; TotalOut--) { - c1 = LutTable[X1]; - c2 = LutTable[Y1]; - c3 = LutTable[Z1]; - c0 = *LutTable++; - c2 -= c1; - c1 -= c3; - c3 -= c0; - Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; - *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16); - } - } else { - Z1 += X1; - Y1 += Z1; - for (; TotalOut; TotalOut--) { - c1 = LutTable[X1]; - c2 = LutTable[Y1]; - c3 = LutTable[Z1]; - c0 = *LutTable++; - c2 -= c3; - c3 -= c1; - c1 -= c0; - Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; - *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16); - } - } - } else { - if (rx >= rz) { - X1 += Y1; - Z1 += X1; - for (; TotalOut; TotalOut--) { - c1 = LutTable[X1]; - c2 = LutTable[Y1]; - c3 = LutTable[Z1]; - c0 = *LutTable++; - c3 -= c1; - c1 -= c2; - c2 -= c0; - Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; - *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16); - } - } else if (ry >= rz) { - Z1 += Y1; - X1 += Z1; - for (; TotalOut; TotalOut--) { - c1 = LutTable[X1]; - c2 = LutTable[Y1]; - c3 = LutTable[Z1]; - c0 = *LutTable++; - c1 -= c3; - c3 -= c2; - c2 -= c0; - Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; - *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16); - } - } else { - Y1 += Z1; - X1 += Y1; - for (; TotalOut; TotalOut--) { - c1 = LutTable[X1]; - c2 = LutTable[Y1]; - c3 = LutTable[Z1]; - c0 = *LutTable++; - c1 -= c2; - c2 -= c3; - c3 -= c0; - Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; - *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16); - } - } - } -} - - -#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) -static -void Eval4Inputs(register const cmsUInt16Number Input[], - register cmsUInt16Number Output[], - register const cmsInterpParams* p16) -{ - const cmsUInt16Number* LutTable; - cmsS15Fixed16Number fk; - cmsS15Fixed16Number k0, rk; - int K0, K1; - cmsS15Fixed16Number fx, fy, fz; - cmsS15Fixed16Number rx, ry, rz; - int x0, y0, z0; - cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1; - cmsUInt32Number i; - cmsS15Fixed16Number c0, c1, c2, c3, Rest; - cmsUInt32Number OutChan; - cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; - - - fk = _cmsToFixedDomain((int) Input[0] * p16 -> Domain[0]); - fx = _cmsToFixedDomain((int) Input[1] * p16 -> Domain[1]); - fy = _cmsToFixedDomain((int) Input[2] * p16 -> Domain[2]); - fz = _cmsToFixedDomain((int) Input[3] * p16 -> Domain[3]); - - k0 = FIXED_TO_INT(fk); - x0 = FIXED_TO_INT(fx); - y0 = FIXED_TO_INT(fy); - z0 = FIXED_TO_INT(fz); - - rk = FIXED_REST_TO_INT(fk); - rx = FIXED_REST_TO_INT(fx); - ry = FIXED_REST_TO_INT(fy); - rz = FIXED_REST_TO_INT(fz); - - K0 = p16 -> opta[3] * k0; - K1 = K0 + (Input[0] == 0xFFFFU ? 0 : p16->opta[3]); - - X0 = p16 -> opta[2] * x0; - X1 = X0 + (Input[1] == 0xFFFFU ? 0 : p16->opta[2]); - - Y0 = p16 -> opta[1] * y0; - Y1 = Y0 + (Input[2] == 0xFFFFU ? 0 : p16->opta[1]); - - Z0 = p16 -> opta[0] * z0; - Z1 = Z0 + (Input[3] == 0xFFFFU ? 0 : p16->opta[0]); - - LutTable = (cmsUInt16Number*) p16 -> Table; - LutTable += K0; - - for (OutChan=0; OutChan < p16 -> nOutputs; OutChan++) { - - c0 = DENS(X0, Y0, Z0); - - if (rx >= ry && ry >= rz) { - - c1 = DENS(X1, Y0, Z0) - c0; - c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0); - c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); - - } - else - if (rx >= rz && rz >= ry) { - - c1 = DENS(X1, Y0, Z0) - c0; - c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); - c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0); - - } - else - if (rz >= rx && rx >= ry) { - - c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1); - c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); - c3 = DENS(X0, Y0, Z1) - c0; - - } - else - if (ry >= rx && rx >= rz) { - - c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0); - c2 = DENS(X0, Y1, Z0) - c0; - c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); - - } - else - if (ry >= rz && rz >= rx) { - - c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); - c2 = DENS(X0, Y1, Z0) - c0; - c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0); - - } - else - if (rz >= ry && ry >= rx) { - - c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); - c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1); - c3 = DENS(X0, Y0, Z1) - c0; - - } - else { - c1 = c2 = c3 = 0; - } - - Rest = c1 * rx + c2 * ry + c3 * rz; - - Tmp1[OutChan] = (cmsUInt16Number) c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)); - } - - - LutTable = (cmsUInt16Number*) p16 -> Table; - LutTable += K1; - - for (OutChan=0; OutChan < p16 -> nOutputs; OutChan++) { - - c0 = DENS(X0, Y0, Z0); - - if (rx >= ry && ry >= rz) { - - c1 = DENS(X1, Y0, Z0) - c0; - c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0); - c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); - - } - else - if (rx >= rz && rz >= ry) { - - c1 = DENS(X1, Y0, Z0) - c0; - c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); - c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0); - - } - else - if (rz >= rx && rx >= ry) { - - c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1); - c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); - c3 = DENS(X0, Y0, Z1) - c0; - - } - else - if (ry >= rx && rx >= rz) { - - c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0); - c2 = DENS(X0, Y1, Z0) - c0; - c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); - - } - else - if (ry >= rz && rz >= rx) { - - c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); - c2 = DENS(X0, Y1, Z0) - c0; - c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0); - - } - else - if (rz >= ry && ry >= rx) { - - c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); - c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1); - c3 = DENS(X0, Y0, Z1) - c0; - - } - else { - c1 = c2 = c3 = 0; - } - - Rest = c1 * rx + c2 * ry + c3 * rz; - - Tmp2[OutChan] = (cmsUInt16Number) c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)); - } - - - - for (i=0; i < p16 -> nOutputs; i++) { - Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]); - } -} -#undef DENS - - -// For more that 3 inputs (i.e., CMYK) -// evaluate two 3-dimensional interpolations and then linearly interpolate between them. - - -static -void Eval4InputsFloat(const cmsFloat32Number Input[], - cmsFloat32Number Output[], - const cmsInterpParams* p) -{ - const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; - cmsFloat32Number rest; - cmsFloat32Number pk; - int k0, K0, K1; - const cmsFloat32Number* T; - cmsUInt32Number i; - cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; - cmsInterpParams p1; - - pk = fclamp(Input[0]) * p->Domain[0]; - k0 = _cmsQuickFloor(pk); - rest = pk - (cmsFloat32Number) k0; - - K0 = p -> opta[3] * k0; - K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[3]); - - p1 = *p; - memmove(&p1.Domain[0], &p ->Domain[1], 3*sizeof(cmsUInt32Number)); - - T = LutTable + K0; - p1.Table = T; - - TetrahedralInterpFloat(Input + 1, Tmp1, &p1); - - T = LutTable + K1; - p1.Table = T; - TetrahedralInterpFloat(Input + 1, Tmp2, &p1); - - for (i=0; i < p -> nOutputs; i++) - { - cmsFloat32Number y0 = Tmp1[i]; - cmsFloat32Number y1 = Tmp2[i]; - - Output[i] = y0 + (y1 - y0) * rest; - } -} - - -static -void Eval5Inputs(register const cmsUInt16Number Input[], - register cmsUInt16Number Output[], - - register const cmsInterpParams* p16) -{ - const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; - cmsS15Fixed16Number fk; - cmsS15Fixed16Number k0, rk; - int K0, K1; - const cmsUInt16Number* T; - cmsUInt32Number i; - cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; - cmsInterpParams p1; - - - fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]); - k0 = FIXED_TO_INT(fk); - rk = FIXED_REST_TO_INT(fk); - - K0 = p16 -> opta[4] * k0; - K1 = p16 -> opta[4] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0)); - - p1 = *p16; - memmove(&p1.Domain[0], &p16 ->Domain[1], 4*sizeof(cmsUInt32Number)); - - T = LutTable + K0; - p1.Table = T; - - Eval4Inputs(Input + 1, Tmp1, &p1); - - T = LutTable + K1; - p1.Table = T; - - Eval4Inputs(Input + 1, Tmp2, &p1); - - for (i=0; i < p16 -> nOutputs; i++) { - - Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]); - } - -} - - -static -void Eval5InputsFloat(const cmsFloat32Number Input[], - cmsFloat32Number Output[], - const cmsInterpParams* p) -{ - const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; - cmsFloat32Number rest; - cmsFloat32Number pk; - int k0, K0, K1; - const cmsFloat32Number* T; - cmsUInt32Number i; - cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; - cmsInterpParams p1; - - pk = fclamp(Input[0]) * p->Domain[0]; - k0 = _cmsQuickFloor(pk); - rest = pk - (cmsFloat32Number) k0; - - K0 = p -> opta[4] * k0; - K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[4]); - - p1 = *p; - memmove(&p1.Domain[0], &p ->Domain[1], 4*sizeof(cmsUInt32Number)); - - T = LutTable + K0; - p1.Table = T; - - Eval4InputsFloat(Input + 1, Tmp1, &p1); - - T = LutTable + K1; - p1.Table = T; - - Eval4InputsFloat(Input + 1, Tmp2, &p1); - - for (i=0; i < p -> nOutputs; i++) { - - cmsFloat32Number y0 = Tmp1[i]; - cmsFloat32Number y1 = Tmp2[i]; - - Output[i] = y0 + (y1 - y0) * rest; - } -} - - - -static -void Eval6Inputs(register const cmsUInt16Number Input[], - register cmsUInt16Number Output[], - register const cmsInterpParams* p16) -{ - const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; - cmsS15Fixed16Number fk; - cmsS15Fixed16Number k0, rk; - int K0, K1; - const cmsUInt16Number* T; - cmsUInt32Number i; - cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; - cmsInterpParams p1; - - fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]); - k0 = FIXED_TO_INT(fk); - rk = FIXED_REST_TO_INT(fk); - - K0 = p16 -> opta[5] * k0; - K1 = p16 -> opta[5] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0)); - - p1 = *p16; - memmove(&p1.Domain[0], &p16 ->Domain[1], 5*sizeof(cmsUInt32Number)); - - T = LutTable + K0; - p1.Table = T; - - Eval5Inputs(Input + 1, Tmp1, &p1); - - T = LutTable + K1; - p1.Table = T; - - Eval5Inputs(Input + 1, Tmp2, &p1); - - for (i=0; i < p16 -> nOutputs; i++) { - - Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]); - } - -} - - -static -void Eval6InputsFloat(const cmsFloat32Number Input[], - cmsFloat32Number Output[], - const cmsInterpParams* p) -{ - const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; - cmsFloat32Number rest; - cmsFloat32Number pk; - int k0, K0, K1; - const cmsFloat32Number* T; - cmsUInt32Number i; - cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; - cmsInterpParams p1; - - pk = fclamp(Input[0]) * p->Domain[0]; - k0 = _cmsQuickFloor(pk); - rest = pk - (cmsFloat32Number) k0; - - K0 = p -> opta[5] * k0; - K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[5]); - - p1 = *p; - memmove(&p1.Domain[0], &p ->Domain[1], 5*sizeof(cmsUInt32Number)); - - T = LutTable + K0; - p1.Table = T; - - Eval5InputsFloat(Input + 1, Tmp1, &p1); - - T = LutTable + K1; - p1.Table = T; - - Eval5InputsFloat(Input + 1, Tmp2, &p1); - - for (i=0; i < p -> nOutputs; i++) { - - cmsFloat32Number y0 = Tmp1[i]; - cmsFloat32Number y1 = Tmp2[i]; - - Output[i] = y0 + (y1 - y0) * rest; - } -} - - -static -void Eval7Inputs(register const cmsUInt16Number Input[], - register cmsUInt16Number Output[], - register const cmsInterpParams* p16) -{ - const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; - cmsS15Fixed16Number fk; - cmsS15Fixed16Number k0, rk; - int K0, K1; - const cmsUInt16Number* T; - cmsUInt32Number i; - cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; - cmsInterpParams p1; - - - fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]); - k0 = FIXED_TO_INT(fk); - rk = FIXED_REST_TO_INT(fk); - - K0 = p16 -> opta[6] * k0; - K1 = p16 -> opta[6] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0)); - - p1 = *p16; - memmove(&p1.Domain[0], &p16 ->Domain[1], 6*sizeof(cmsUInt32Number)); - - T = LutTable + K0; - p1.Table = T; - - Eval6Inputs(Input + 1, Tmp1, &p1); - - T = LutTable + K1; - p1.Table = T; - - Eval6Inputs(Input + 1, Tmp2, &p1); - - for (i=0; i < p16 -> nOutputs; i++) { - Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]); - } -} - - -static -void Eval7InputsFloat(const cmsFloat32Number Input[], - cmsFloat32Number Output[], - const cmsInterpParams* p) -{ - const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; - cmsFloat32Number rest; - cmsFloat32Number pk; - int k0, K0, K1; - const cmsFloat32Number* T; - cmsUInt32Number i; - cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; - cmsInterpParams p1; - - pk = fclamp(Input[0]) * p->Domain[0]; - k0 = _cmsQuickFloor(pk); - rest = pk - (cmsFloat32Number) k0; - - K0 = p -> opta[6] * k0; - K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[6]); - - p1 = *p; - memmove(&p1.Domain[0], &p ->Domain[1], 6*sizeof(cmsUInt32Number)); - - T = LutTable + K0; - p1.Table = T; - - Eval6InputsFloat(Input + 1, Tmp1, &p1); - - T = LutTable + K1; - p1.Table = T; - - Eval6InputsFloat(Input + 1, Tmp2, &p1); - - - for (i=0; i < p -> nOutputs; i++) { - - cmsFloat32Number y0 = Tmp1[i]; - cmsFloat32Number y1 = Tmp2[i]; - - Output[i] = y0 + (y1 - y0) * rest; - - } -} - -static -void Eval8Inputs(register const cmsUInt16Number Input[], - register cmsUInt16Number Output[], - register const cmsInterpParams* p16) -{ - const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; - cmsS15Fixed16Number fk; - cmsS15Fixed16Number k0, rk; - int K0, K1; - const cmsUInt16Number* T; - cmsUInt32Number i; - cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; - cmsInterpParams p1; - - fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]); - k0 = FIXED_TO_INT(fk); - rk = FIXED_REST_TO_INT(fk); - - K0 = p16 -> opta[7] * k0; - K1 = p16 -> opta[7] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0)); - - p1 = *p16; - memmove(&p1.Domain[0], &p16 ->Domain[1], 7*sizeof(cmsUInt32Number)); - - T = LutTable + K0; - p1.Table = T; - - Eval7Inputs(Input + 1, Tmp1, &p1); - - T = LutTable + K1; - p1.Table = T; - Eval7Inputs(Input + 1, Tmp2, &p1); - - for (i=0; i < p16 -> nOutputs; i++) { - Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]); - } -} - - - -static -void Eval8InputsFloat(const cmsFloat32Number Input[], - cmsFloat32Number Output[], - const cmsInterpParams* p) -{ - const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; - cmsFloat32Number rest; - cmsFloat32Number pk; - int k0, K0, K1; - const cmsFloat32Number* T; - cmsUInt32Number i; - cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; - cmsInterpParams p1; - - pk = fclamp(Input[0]) * p->Domain[0]; - k0 = _cmsQuickFloor(pk); - rest = pk - (cmsFloat32Number) k0; - - K0 = p -> opta[7] * k0; - K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[7]); - - p1 = *p; - memmove(&p1.Domain[0], &p ->Domain[1], 7*sizeof(cmsUInt32Number)); - - T = LutTable + K0; - p1.Table = T; - - Eval7InputsFloat(Input + 1, Tmp1, &p1); - - T = LutTable + K1; - p1.Table = T; - - Eval7InputsFloat(Input + 1, Tmp2, &p1); - - - for (i=0; i < p -> nOutputs; i++) { - - cmsFloat32Number y0 = Tmp1[i]; - cmsFloat32Number y1 = Tmp2[i]; - - Output[i] = y0 + (y1 - y0) * rest; - } -} - -// The default factory -static -cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags) -{ - - cmsInterpFunction Interpolation; - cmsBool IsFloat = (dwFlags & CMS_LERP_FLAGS_FLOAT); - cmsBool IsTrilinear = (dwFlags & CMS_LERP_FLAGS_TRILINEAR); - - memset(&Interpolation, 0, sizeof(Interpolation)); - - // Safety check - if (nInputChannels >= 4 && nOutputChannels >= MAX_STAGE_CHANNELS) - return Interpolation; - - switch (nInputChannels) { - - case 1: // Gray LUT / linear - - if (nOutputChannels == 1) { - - if (IsFloat) - Interpolation.LerpFloat = LinLerp1Dfloat; - else - Interpolation.Lerp16 = LinLerp1D; - - } - else { - - if (IsFloat) - Interpolation.LerpFloat = Eval1InputFloat; - else - Interpolation.Lerp16 = Eval1Input; - } - break; - - case 2: // Duotone - if (IsFloat) - Interpolation.LerpFloat = BilinearInterpFloat; - else - Interpolation.Lerp16 = BilinearInterp16; - break; - - case 3: // RGB et al - - if (IsTrilinear) { - - if (IsFloat) - Interpolation.LerpFloat = TrilinearInterpFloat; - else - Interpolation.Lerp16 = TrilinearInterp16; - } - else { - - if (IsFloat) - Interpolation.LerpFloat = TetrahedralInterpFloat; - else { - - Interpolation.Lerp16 = TetrahedralInterp16; - } - } - break; - - case 4: // CMYK lut - - if (IsFloat) - Interpolation.LerpFloat = Eval4InputsFloat; - else - Interpolation.Lerp16 = Eval4Inputs; - break; - - case 5: // 5 Inks - if (IsFloat) - Interpolation.LerpFloat = Eval5InputsFloat; - else - Interpolation.Lerp16 = Eval5Inputs; - break; - - case 6: // 6 Inks - if (IsFloat) - Interpolation.LerpFloat = Eval6InputsFloat; - else - Interpolation.Lerp16 = Eval6Inputs; - break; - - case 7: // 7 inks - if (IsFloat) - Interpolation.LerpFloat = Eval7InputsFloat; - else - Interpolation.Lerp16 = Eval7Inputs; - break; - - case 8: // 8 inks - if (IsFloat) - Interpolation.LerpFloat = Eval8InputsFloat; - else - Interpolation.Lerp16 = Eval8Inputs; - break; - - break; - - default: - Interpolation.Lerp16 = NULL; - } - - return Interpolation; -} diff --git a/third_party/lcms2-2.6/src/cmsio0.c b/third_party/lcms2-2.6/src/cmsio0.c deleted file mode 100644 index 3ed730a92a..0000000000 --- a/third_party/lcms2-2.6/src/cmsio0.c +++ /dev/null @@ -1,1895 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- -// -#include "lcms2_internal.h" - -// Generic I/O, tag dictionary management, profile struct - -// IOhandlers are abstractions used by littleCMS to read from whatever file, stream, -// memory block or any storage. Each IOhandler provides implementations for read, -// write, seek and tell functions. LittleCMS code deals with IO across those objects. -// In this way, is easier to add support for new storage media. - -// NULL stream, for taking care of used space ------------------------------------- - -// NULL IOhandler basically does nothing but keep track on how many bytes have been -// written. This is handy when creating profiles, where the file size is needed in the -// header. Then, whole profile is serialized across NULL IOhandler and a second pass -// writes the bytes to the pertinent IOhandler. - -typedef struct { - cmsUInt32Number Pointer; // Points to current location -} FILENULL; - -static -cmsUInt32Number NULLRead(cmsIOHANDLER* iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count) -{ - FILENULL* ResData = (FILENULL*) iohandler ->stream; - - cmsUInt32Number len = size * count; - ResData -> Pointer += len; - return count; - - cmsUNUSED_PARAMETER(Buffer); -} - -static -cmsBool NULLSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset) -{ - FILENULL* ResData = (FILENULL*) iohandler ->stream; - - ResData ->Pointer = offset; - return TRUE; -} - -static -cmsUInt32Number NULLTell(cmsIOHANDLER* iohandler) -{ - FILENULL* ResData = (FILENULL*) iohandler ->stream; - return ResData -> Pointer; -} - -static -cmsBool NULLWrite(cmsIOHANDLER* iohandler, cmsUInt32Number size, const void *Ptr) -{ - FILENULL* ResData = (FILENULL*) iohandler ->stream; - - ResData ->Pointer += size; - if (ResData ->Pointer > iohandler->UsedSpace) - iohandler->UsedSpace = ResData ->Pointer; - - return TRUE; - - cmsUNUSED_PARAMETER(Ptr); -} - -static -cmsBool NULLClose(cmsIOHANDLER* iohandler) -{ - FILENULL* ResData = (FILENULL*) iohandler ->stream; - - _cmsFree(iohandler ->ContextID, ResData); - _cmsFree(iohandler ->ContextID, iohandler); - return TRUE; -} - -// The NULL IOhandler creator -cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromNULL(cmsContext ContextID) -{ - struct _cms_io_handler* iohandler = NULL; - FILENULL* fm = NULL; - - iohandler = (struct _cms_io_handler*) _cmsMallocZero(ContextID, sizeof(struct _cms_io_handler)); - if (iohandler == NULL) return NULL; - - fm = (FILENULL*) _cmsMallocZero(ContextID, sizeof(FILENULL)); - if (fm == NULL) goto Error; - - fm ->Pointer = 0; - - iohandler ->ContextID = ContextID; - iohandler ->stream = (void*) fm; - iohandler ->UsedSpace = 0; - iohandler ->ReportedSize = 0; - iohandler ->PhysicalFile[0] = 0; - - iohandler ->Read = NULLRead; - iohandler ->Seek = NULLSeek; - iohandler ->Close = NULLClose; - iohandler ->Tell = NULLTell; - iohandler ->Write = NULLWrite; - - return iohandler; - -Error: - if (iohandler) _cmsFree(ContextID, iohandler); - return NULL; - -} - - -// Memory-based stream -------------------------------------------------------------- - -// Those functions implements an iohandler which takes a block of memory as storage medium. - -typedef struct { - cmsUInt8Number* Block; // Points to allocated memory - cmsUInt32Number Size; // Size of allocated memory - cmsUInt32Number Pointer; // Points to current location - int FreeBlockOnClose; // As title - -} FILEMEM; - -static -cmsUInt32Number MemoryRead(struct _cms_io_handler* iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count) -{ - FILEMEM* ResData = (FILEMEM*) iohandler ->stream; - cmsUInt8Number* Ptr; - cmsUInt32Number len = size * count; - - if (ResData -> Pointer + len > ResData -> Size){ - - len = (ResData -> Size - ResData -> Pointer); - cmsSignalError(iohandler ->ContextID, cmsERROR_READ, "Read from memory error. Got %d bytes, block should be of %d bytes", len, count * size); - return 0; - } - - Ptr = ResData -> Block; - Ptr += ResData -> Pointer; - memmove(Buffer, Ptr, len); - ResData -> Pointer += len; - - return count; -} - -// SEEK_CUR is assumed -static -cmsBool MemorySeek(struct _cms_io_handler* iohandler, cmsUInt32Number offset) -{ - FILEMEM* ResData = (FILEMEM*) iohandler ->stream; - - if (offset > ResData ->Size) { - cmsSignalError(iohandler ->ContextID, cmsERROR_SEEK, "Too few data; probably corrupted profile"); - return FALSE; - } - - ResData ->Pointer = offset; - return TRUE; -} - -// Tell for memory -static -cmsUInt32Number MemoryTell(struct _cms_io_handler* iohandler) -{ - FILEMEM* ResData = (FILEMEM*) iohandler ->stream; - - if (ResData == NULL) return 0; - return ResData -> Pointer; -} - - -// Writes data to memory, also keeps used space for further reference. -static -cmsBool MemoryWrite(struct _cms_io_handler* iohandler, cmsUInt32Number size, const void *Ptr) -{ - FILEMEM* ResData = (FILEMEM*) iohandler ->stream; - - if (ResData == NULL) return FALSE; // Housekeeping - - // Check for available space. Clip. - if (ResData->Pointer + size > ResData->Size) { - size = ResData ->Size - ResData->Pointer; - } - - if (size == 0) return TRUE; // Write zero bytes is ok, but does nothing - - memmove(ResData ->Block + ResData ->Pointer, Ptr, size); - ResData ->Pointer += size; - - if (ResData ->Pointer > iohandler->UsedSpace) - iohandler->UsedSpace = ResData ->Pointer; - - return TRUE; -} - - -static -cmsBool MemoryClose(struct _cms_io_handler* iohandler) -{ - FILEMEM* ResData = (FILEMEM*) iohandler ->stream; - - if (ResData ->FreeBlockOnClose) { - - if (ResData ->Block) _cmsFree(iohandler ->ContextID, ResData ->Block); - } - - _cmsFree(iohandler ->ContextID, ResData); - _cmsFree(iohandler ->ContextID, iohandler); - - return TRUE; -} - -// Create a iohandler for memory block. AccessMode=='r' assumes the iohandler is going to read, and makes -// a copy of the memory block for letting user to free the memory after invoking open profile. In write -// mode ("w"), Buffere points to the begin of memory block to be written. -cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromMem(cmsContext ContextID, void *Buffer, cmsUInt32Number size, const char* AccessMode) -{ - cmsIOHANDLER* iohandler = NULL; - FILEMEM* fm = NULL; - - _cmsAssert(AccessMode != NULL); - - iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER)); - if (iohandler == NULL) return NULL; - - switch (*AccessMode) { - - case 'r': - fm = (FILEMEM*) _cmsMallocZero(ContextID, sizeof(FILEMEM)); - if (fm == NULL) goto Error; - - if (Buffer == NULL) { - cmsSignalError(ContextID, cmsERROR_READ, "Couldn't read profile from NULL pointer"); - goto Error; - } - - fm ->Block = (cmsUInt8Number*) _cmsMalloc(ContextID, size); - if (fm ->Block == NULL) { - - _cmsFree(ContextID, fm); - _cmsFree(ContextID, iohandler); - cmsSignalError(ContextID, cmsERROR_READ, "Couldn't allocate %ld bytes for profile", size); - return NULL; - } - - - memmove(fm->Block, Buffer, size); - fm ->FreeBlockOnClose = TRUE; - fm ->Size = size; - fm ->Pointer = 0; - iohandler -> ReportedSize = size; - break; - - case 'w': - fm = (FILEMEM*) _cmsMallocZero(ContextID, sizeof(FILEMEM)); - if (fm == NULL) goto Error; - - fm ->Block = (cmsUInt8Number*) Buffer; - fm ->FreeBlockOnClose = FALSE; - fm ->Size = size; - fm ->Pointer = 0; - iohandler -> ReportedSize = 0; - break; - - default: - cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown access mode '%c'", *AccessMode); - return NULL; - } - - iohandler ->ContextID = ContextID; - iohandler ->stream = (void*) fm; - iohandler ->UsedSpace = 0; - iohandler ->PhysicalFile[0] = 0; - - iohandler ->Read = MemoryRead; - iohandler ->Seek = MemorySeek; - iohandler ->Close = MemoryClose; - iohandler ->Tell = MemoryTell; - iohandler ->Write = MemoryWrite; - - return iohandler; - -Error: - if (fm) _cmsFree(ContextID, fm); - if (iohandler) _cmsFree(ContextID, iohandler); - return NULL; -} - -// File-based stream ------------------------------------------------------- - -// Read count elements of size bytes each. Return number of elements read -static -cmsUInt32Number FileRead(cmsIOHANDLER* iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count) -{ - cmsUInt32Number nReaded = (cmsUInt32Number) fread(Buffer, size, count, (FILE*) iohandler->stream); - - if (nReaded != count) { - cmsSignalError(iohandler ->ContextID, cmsERROR_FILE, "Read error. Got %d bytes, block should be of %d bytes", nReaded * size, count * size); - return 0; - } - - return nReaded; -} - -// Postion file pointer in the file -static -cmsBool FileSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset) -{ - if (fseek((FILE*) iohandler ->stream, (long) offset, SEEK_SET) != 0) { - - cmsSignalError(iohandler ->ContextID, cmsERROR_FILE, "Seek error; probably corrupted file"); - return FALSE; - } - - return TRUE; -} - -// Returns file pointer position -static -cmsUInt32Number FileTell(cmsIOHANDLER* iohandler) -{ - return (cmsUInt32Number) ftell((FILE*)iohandler ->stream); -} - -// Writes data to stream, also keeps used space for further reference. Returns TRUE on success, FALSE on error -static -cmsBool FileWrite(cmsIOHANDLER* iohandler, cmsUInt32Number size, const void* Buffer) -{ - if (size == 0) return TRUE; // We allow to write 0 bytes, but nothing is written - - iohandler->UsedSpace += size; - return (fwrite(Buffer, size, 1, (FILE*) iohandler->stream) == 1); -} - -// Closes the file -static -cmsBool FileClose(cmsIOHANDLER* iohandler) -{ - if (fclose((FILE*) iohandler ->stream) != 0) return FALSE; - _cmsFree(iohandler ->ContextID, iohandler); - return TRUE; -} - -// Create a iohandler for disk based files. -cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const char* FileName, const char* AccessMode) -{ - cmsIOHANDLER* iohandler = NULL; - FILE* fm = NULL; - - _cmsAssert(FileName != NULL); - _cmsAssert(AccessMode != NULL); - - iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER)); - if (iohandler == NULL) return NULL; - - switch (*AccessMode) { - - case 'r': - fm = fopen(FileName, "rb"); - if (fm == NULL) { - _cmsFree(ContextID, iohandler); - cmsSignalError(ContextID, cmsERROR_FILE, "File '%s' not found", FileName); - return NULL; - } - iohandler -> ReportedSize = (cmsUInt32Number) cmsfilelength(fm); - break; - - case 'w': - fm = fopen(FileName, "wb"); - if (fm == NULL) { - _cmsFree(ContextID, iohandler); - cmsSignalError(ContextID, cmsERROR_FILE, "Couldn't create '%s'", FileName); - return NULL; - } - iohandler -> ReportedSize = 0; - break; - - default: - _cmsFree(ContextID, iohandler); - cmsSignalError(ContextID, cmsERROR_FILE, "Unknown access mode '%c'", *AccessMode); - return NULL; - } - - iohandler ->ContextID = ContextID; - iohandler ->stream = (void*) fm; - iohandler ->UsedSpace = 0; - - // Keep track of the original file - strncpy(iohandler -> PhysicalFile, FileName, sizeof(iohandler -> PhysicalFile)-1); - iohandler -> PhysicalFile[sizeof(iohandler -> PhysicalFile)-1] = 0; - - iohandler ->Read = FileRead; - iohandler ->Seek = FileSeek; - iohandler ->Close = FileClose; - iohandler ->Tell = FileTell; - iohandler ->Write = FileWrite; - - return iohandler; -} - -// Create a iohandler for stream based files -cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromStream(cmsContext ContextID, FILE* Stream) -{ - cmsIOHANDLER* iohandler = NULL; - - iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER)); - if (iohandler == NULL) return NULL; - - iohandler -> ContextID = ContextID; - iohandler -> stream = (void*) Stream; - iohandler -> UsedSpace = 0; - iohandler -> ReportedSize = (cmsUInt32Number) cmsfilelength(Stream); - iohandler -> PhysicalFile[0] = 0; - - iohandler ->Read = FileRead; - iohandler ->Seek = FileSeek; - iohandler ->Close = FileClose; - iohandler ->Tell = FileTell; - iohandler ->Write = FileWrite; - - return iohandler; -} - - - -// Close an open IO handler -cmsBool CMSEXPORT cmsCloseIOhandler(cmsIOHANDLER* io) -{ - return io -> Close(io); -} - -// ------------------------------------------------------------------------------------------------------- - -#ifdef _WIN32_WCE -time_t wceex_time(time_t *timer); -struct tm * wceex_gmtime(const time_t *timer); - -#define time wceex_time -#define gmtime wceex_gmtime -#endif - -// Creates an empty structure holding all required parameters -cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID) -{ - time_t now = time(NULL); - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) _cmsMallocZero(ContextID, sizeof(_cmsICCPROFILE)); - if (Icc == NULL) return NULL; - - Icc ->ContextID = ContextID; - - // Set it to empty - Icc -> TagCount = 0; - - // Set default version - Icc ->Version = 0x02100000; - - // Set creation date/time - memmove(&Icc ->Created, gmtime(&now), sizeof(Icc ->Created)); - - // Create a mutex if the user provided proper plugin. NULL otherwise - Icc ->UsrMutex = _cmsCreateMutex(ContextID); - - // Return the handle - return (cmsHPROFILE) Icc; -} - -cmsContext CMSEXPORT cmsGetProfileContextID(cmsHPROFILE hProfile) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - - if (Icc == NULL) return NULL; - return Icc -> ContextID; -} - - -// Return the number of tags -cmsInt32Number CMSEXPORT cmsGetTagCount(cmsHPROFILE hProfile) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - if (Icc == NULL) return -1; - - return Icc->TagCount; -} - -// Return the tag signature of a given tag number -cmsTagSignature CMSEXPORT cmsGetTagSignature(cmsHPROFILE hProfile, cmsUInt32Number n) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - - if (n > Icc->TagCount) return (cmsTagSignature) 0; // Mark as not available - if (n >= MAX_TABLE_TAG) return (cmsTagSignature) 0; // As double check - - return Icc ->TagNames[n]; -} - - -static -int SearchOneTag(_cmsICCPROFILE* Profile, cmsTagSignature sig) -{ - cmsUInt32Number i; - - for (i=0; i < Profile -> TagCount; i++) { - - if (sig == Profile -> TagNames[i]) - return i; - } - - return -1; -} - -// Search for a specific tag in tag dictionary. Returns position or -1 if tag not found. -// If followlinks is turned on, then the position of the linked tag is returned -int _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks) -{ - int n; - cmsTagSignature LinkedSig; - - do { - - // Search for given tag in ICC profile directory - n = SearchOneTag(Icc, sig); - if (n < 0) - return -1; // Not found - - if (!lFollowLinks) - return n; // Found, don't follow links - - // Is this a linked tag? - LinkedSig = Icc ->TagLinked[n]; - - // Yes, follow link - if (LinkedSig != (cmsTagSignature) 0) { - // fix bug mantis id#0055942 - // assume that TRCTag and ColorantTag can't be linked. - // Xiaochuan Liu 2014-04-23 - if ((sig == cmsSigRedTRCTag || sig == cmsSigGreenTRCTag || sig == cmsSigBlueTRCTag) && - (LinkedSig == cmsSigRedColorantTag || LinkedSig == cmsSigGreenColorantTag || LinkedSig == cmsSigBlueColorantTag)) - { - return n; - } - sig = LinkedSig; - } - - } while (LinkedSig != (cmsTagSignature) 0); - - return n; -} - -// Deletes a tag entry - -static -void _cmsDeleteTagByPos(_cmsICCPROFILE* Icc, int i) -{ - _cmsAssert(Icc != NULL); - _cmsAssert(i >= 0); - - - if (Icc -> TagPtrs[i] != NULL) { - - // Free previous version - if (Icc ->TagSaveAsRaw[i]) { - _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]); - } - else { - cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i]; - - if (TypeHandler != NULL) { - - cmsTagTypeHandler LocalTypeHandler = *TypeHandler; - LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameter - LocalTypeHandler.ICCVersion = Icc ->Version; - LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]); - Icc ->TagPtrs[i] = NULL; - } - } - - } -} - - -// Creates a new tag entry -static -cmsBool _cmsNewTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, int* NewPos) -{ - int i; - - // Search for the tag - i = _cmsSearchTag(Icc, sig, FALSE); - if (i >= 0) { - - // Already exists? delete it - _cmsDeleteTagByPos(Icc, i); - *NewPos = i; - } - else { - - // No, make a new one - - if (Icc -> TagCount >= MAX_TABLE_TAG) { - cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG); - return FALSE; - } - - *NewPos = Icc ->TagCount; - Icc -> TagCount++; - } - - return TRUE; -} - - -// Check existance -cmsBool CMSEXPORT cmsIsTag(cmsHPROFILE hProfile, cmsTagSignature sig) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) (void*) hProfile; - return _cmsSearchTag(Icc, sig, FALSE) >= 0; -} - - -// Read profile header and validate it -cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) -{ - cmsTagEntry Tag; - cmsICCHeader Header; - cmsUInt32Number i, j; - cmsUInt32Number HeaderSize; - cmsIOHANDLER* io = Icc ->IOhandler; - cmsUInt32Number TagCount; - - - // Read the header - if (io -> Read(io, &Header, sizeof(cmsICCHeader), 1) != 1) { - return FALSE; - } - - // Validate file as an ICC profile - if (_cmsAdjustEndianess32(Header.magic) != cmsMagicNumber) { - cmsSignalError(Icc ->ContextID, cmsERROR_BAD_SIGNATURE, "not an ICC profile, invalid signature"); - return FALSE; - } - - // Adjust endianess of the used parameters - Icc -> DeviceClass = (cmsProfileClassSignature) _cmsAdjustEndianess32(Header.deviceClass); - Icc -> ColorSpace = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Header.colorSpace); - Icc -> PCS = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Header.pcs); - - Icc -> RenderingIntent = _cmsAdjustEndianess32(Header.renderingIntent); - Icc -> flags = _cmsAdjustEndianess32(Header.flags); - Icc -> manufacturer = _cmsAdjustEndianess32(Header.manufacturer); - Icc -> model = _cmsAdjustEndianess32(Header.model); - Icc -> creator = _cmsAdjustEndianess32(Header.creator); - - _cmsAdjustEndianess64(&Icc -> attributes, &Header.attributes); - Icc -> Version = _cmsAdjustEndianess32(Header.version); - - // Get size as reported in header - HeaderSize = _cmsAdjustEndianess32(Header.size); - - // Make sure HeaderSize is lower than profile size - if (HeaderSize >= Icc ->IOhandler ->ReportedSize) - HeaderSize = Icc ->IOhandler ->ReportedSize; - - - // Get creation date/time - _cmsDecodeDateTimeNumber(&Header.date, &Icc ->Created); - - // The profile ID are 32 raw bytes - memmove(Icc ->ProfileID.ID32, Header.profileID.ID32, 16); - - - // Read tag directory - if (!_cmsReadUInt32Number(io, &TagCount)) return FALSE; - if (TagCount > MAX_TABLE_TAG) { - - cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", TagCount); - return FALSE; - } - - - // Read tag directory - Icc -> TagCount = 0; - for (i=0; i < TagCount; i++) { - - if (!_cmsReadUInt32Number(io, (cmsUInt32Number *) &Tag.sig)) return FALSE; - if (!_cmsReadUInt32Number(io, &Tag.offset)) return FALSE; - if (!_cmsReadUInt32Number(io, &Tag.size)) return FALSE; - - // Perform some sanity check. Offset + size should fall inside file. - if (Tag.offset + Tag.size > HeaderSize || - Tag.offset + Tag.size < Tag.offset) - continue; - - Icc -> TagNames[Icc ->TagCount] = Tag.sig; - Icc -> TagOffsets[Icc ->TagCount] = Tag.offset; - Icc -> TagSizes[Icc ->TagCount] = Tag.size; - - // Search for links - for (j=0; j < Icc ->TagCount; j++) { - - if ((Icc ->TagOffsets[j] == Tag.offset) && - (Icc ->TagSizes[j] == Tag.size) && - (Icc ->TagNames[j] == Tag.sig)) { - - Icc ->TagLinked[Icc ->TagCount] = Icc ->TagNames[j]; - } - - } - - Icc ->TagCount++; - } - - return TRUE; -} - -// Saves profile header -cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace) -{ - cmsICCHeader Header; - cmsUInt32Number i; - cmsTagEntry Tag; - cmsInt32Number Count = 0; - - Header.size = _cmsAdjustEndianess32(UsedSpace); - Header.cmmId = _cmsAdjustEndianess32(lcmsSignature); - Header.version = _cmsAdjustEndianess32(Icc ->Version); - - Header.deviceClass = (cmsProfileClassSignature) _cmsAdjustEndianess32(Icc -> DeviceClass); - Header.colorSpace = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Icc -> ColorSpace); - Header.pcs = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Icc -> PCS); - - // NOTE: in v4 Timestamp must be in UTC rather than in local time - _cmsEncodeDateTimeNumber(&Header.date, &Icc ->Created); - - Header.magic = _cmsAdjustEndianess32(cmsMagicNumber); - -#ifdef CMS_IS_WINDOWS_ - Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMicrosoft); -#else - Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMacintosh); -#endif - - Header.flags = _cmsAdjustEndianess32(Icc -> flags); - Header.manufacturer = _cmsAdjustEndianess32(Icc -> manufacturer); - Header.model = _cmsAdjustEndianess32(Icc -> model); - - _cmsAdjustEndianess64(&Header.attributes, &Icc -> attributes); - - // Rendering intent in the header (for embedded profiles) - Header.renderingIntent = _cmsAdjustEndianess32(Icc -> RenderingIntent); - - // Illuminant is always D50 - Header.illuminant.X = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(cmsD50_XYZ()->X)); - Header.illuminant.Y = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(cmsD50_XYZ()->Y)); - Header.illuminant.Z = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(cmsD50_XYZ()->Z)); - - // Created by LittleCMS (that's me!) - Header.creator = _cmsAdjustEndianess32(lcmsSignature); - - memset(&Header.reserved, 0, sizeof(Header.reserved)); - - // Set profile ID. Endianess is always big endian - memmove(&Header.profileID, &Icc ->ProfileID, 16); - - // Dump the header - if (!Icc -> IOhandler->Write(Icc->IOhandler, sizeof(cmsICCHeader), &Header)) return FALSE; - - // Saves Tag directory - - // Get true count - for (i=0; i < Icc -> TagCount; i++) { - if (Icc ->TagNames[i] != 0) - Count++; - } - - // Store number of tags - if (!_cmsWriteUInt32Number(Icc ->IOhandler, Count)) return FALSE; - - for (i=0; i < Icc -> TagCount; i++) { - - if (Icc ->TagNames[i] == 0) continue; // It is just a placeholder - - Tag.sig = (cmsTagSignature) _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagNames[i]); - Tag.offset = _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagOffsets[i]); - Tag.size = _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagSizes[i]); - - if (!Icc ->IOhandler -> Write(Icc-> IOhandler, sizeof(cmsTagEntry), &Tag)) return FALSE; - } - - return TRUE; -} - -// ----------------------------------------------------------------------- Set/Get several struct members - - -cmsUInt32Number CMSEXPORT cmsGetHeaderRenderingIntent(cmsHPROFILE hProfile) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - return Icc -> RenderingIntent; -} - -void CMSEXPORT cmsSetHeaderRenderingIntent(cmsHPROFILE hProfile, cmsUInt32Number RenderingIntent) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - Icc -> RenderingIntent = RenderingIntent; -} - -cmsUInt32Number CMSEXPORT cmsGetHeaderFlags(cmsHPROFILE hProfile) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - return (cmsUInt32Number) Icc -> flags; -} - -void CMSEXPORT cmsSetHeaderFlags(cmsHPROFILE hProfile, cmsUInt32Number Flags) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - Icc -> flags = (cmsUInt32Number) Flags; -} - -cmsUInt32Number CMSEXPORT cmsGetHeaderManufacturer(cmsHPROFILE hProfile) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - return Icc ->manufacturer; -} - -void CMSEXPORT cmsSetHeaderManufacturer(cmsHPROFILE hProfile, cmsUInt32Number manufacturer) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - Icc -> manufacturer = manufacturer; -} - -cmsUInt32Number CMSEXPORT cmsGetHeaderCreator(cmsHPROFILE hProfile) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - return Icc ->creator; -} - -cmsUInt32Number CMSEXPORT cmsGetHeaderModel(cmsHPROFILE hProfile) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - return Icc ->model; -} - -void CMSEXPORT cmsSetHeaderModel(cmsHPROFILE hProfile, cmsUInt32Number model) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - Icc -> model = model; -} - -void CMSEXPORT cmsGetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number* Flags) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - memmove(Flags, &Icc -> attributes, sizeof(cmsUInt64Number)); -} - -void CMSEXPORT cmsSetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number Flags) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - memmove(&Icc -> attributes, &Flags, sizeof(cmsUInt64Number)); -} - -void CMSEXPORT cmsGetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* ProfileID) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - memmove(ProfileID, Icc ->ProfileID.ID8, 16); -} - -void CMSEXPORT cmsSetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* ProfileID) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - memmove(&Icc -> ProfileID, ProfileID, 16); -} - -cmsBool CMSEXPORT cmsGetHeaderCreationDateTime(cmsHPROFILE hProfile, struct tm *Dest) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - memmove(Dest, &Icc ->Created, sizeof(struct tm)); - return TRUE; -} - -cmsColorSpaceSignature CMSEXPORT cmsGetPCS(cmsHPROFILE hProfile) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - return Icc -> PCS; -} - -void CMSEXPORT cmsSetPCS(cmsHPROFILE hProfile, cmsColorSpaceSignature pcs) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - Icc -> PCS = pcs; -} - -cmsColorSpaceSignature CMSEXPORT cmsGetColorSpace(cmsHPROFILE hProfile) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - return Icc -> ColorSpace; -} - -void CMSEXPORT cmsSetColorSpace(cmsHPROFILE hProfile, cmsColorSpaceSignature sig) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - Icc -> ColorSpace = sig; -} - -cmsProfileClassSignature CMSEXPORT cmsGetDeviceClass(cmsHPROFILE hProfile) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - return Icc -> DeviceClass; -} - -void CMSEXPORT cmsSetDeviceClass(cmsHPROFILE hProfile, cmsProfileClassSignature sig) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - Icc -> DeviceClass = sig; -} - -cmsUInt32Number CMSEXPORT cmsGetEncodedICCversion(cmsHPROFILE hProfile) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - return Icc -> Version; -} - -void CMSEXPORT cmsSetEncodedICCversion(cmsHPROFILE hProfile, cmsUInt32Number Version) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - Icc -> Version = Version; -} - -// Get an hexadecimal number with same digits as v -static -cmsUInt32Number BaseToBase(cmsUInt32Number in, int BaseIn, int BaseOut) -{ - char Buff[100]; - int i, len; - cmsUInt32Number out; - - for (len=0; in > 0 && len < 100; len++) { - - Buff[len] = (char) (in % BaseIn); - in /= BaseIn; - } - - for (i=len-1, out=0; i >= 0; --i) { - out = out * BaseOut + Buff[i]; - } - - return out; -} - -void CMSEXPORT cmsSetProfileVersion(cmsHPROFILE hProfile, cmsFloat64Number Version) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - - // 4.2 -> 0x4200000 - - Icc -> Version = BaseToBase((cmsUInt32Number) floor(Version * 100.0 + 0.5), 10, 16) << 16; -} - -cmsFloat64Number CMSEXPORT cmsGetProfileVersion(cmsHPROFILE hProfile) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - cmsUInt32Number n = Icc -> Version >> 16; - - return BaseToBase(n, 16, 10) / 100.0; -} -// -------------------------------------------------------------------------------------------------------------- - - -// Create profile from IOhandler -cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandlerTHR(cmsContext ContextID, cmsIOHANDLER* io) -{ - _cmsICCPROFILE* NewIcc; - cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID); - - if (hEmpty == NULL) return NULL; - - NewIcc = (_cmsICCPROFILE*) hEmpty; - - NewIcc ->IOhandler = io; - if (!_cmsReadHeader(NewIcc)) goto Error; - return hEmpty; - -Error: - cmsCloseProfile(hEmpty); - return NULL; -} - -// Create profile from IOhandler -cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandler2THR(cmsContext ContextID, cmsIOHANDLER* io, cmsBool write) -{ - _cmsICCPROFILE* NewIcc; - cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID); - - if (hEmpty == NULL) return NULL; - - NewIcc = (_cmsICCPROFILE*) hEmpty; - - NewIcc ->IOhandler = io; - if (write) { - - NewIcc -> IsWrite = TRUE; - return hEmpty; - } - - if (!_cmsReadHeader(NewIcc)) goto Error; - return hEmpty; - -Error: - cmsCloseProfile(hEmpty); - return NULL; -} - - -// Create profile from disk file -cmsHPROFILE CMSEXPORT cmsOpenProfileFromFileTHR(cmsContext ContextID, const char *lpFileName, const char *sAccess) -{ - _cmsICCPROFILE* NewIcc; - cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID); - - if (hEmpty == NULL) return NULL; - - NewIcc = (_cmsICCPROFILE*) hEmpty; - - NewIcc ->IOhandler = cmsOpenIOhandlerFromFile(ContextID, lpFileName, sAccess); - if (NewIcc ->IOhandler == NULL) goto Error; - - if (*sAccess == 'W' || *sAccess == 'w') { - - NewIcc -> IsWrite = TRUE; - - return hEmpty; - } - - if (!_cmsReadHeader(NewIcc)) goto Error; - return hEmpty; - -Error: - cmsCloseProfile(hEmpty); - return NULL; -} - - -cmsHPROFILE CMSEXPORT cmsOpenProfileFromFile(const char *ICCProfile, const char *sAccess) -{ - return cmsOpenProfileFromFileTHR(NULL, ICCProfile, sAccess); -} - - -cmsHPROFILE CMSEXPORT cmsOpenProfileFromStreamTHR(cmsContext ContextID, FILE* ICCProfile, const char *sAccess) -{ - _cmsICCPROFILE* NewIcc; - cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID); - - if (hEmpty == NULL) return NULL; - - NewIcc = (_cmsICCPROFILE*) hEmpty; - - NewIcc ->IOhandler = cmsOpenIOhandlerFromStream(ContextID, ICCProfile); - if (NewIcc ->IOhandler == NULL) goto Error; - - if (*sAccess == 'w') { - - NewIcc -> IsWrite = TRUE; - return hEmpty; - } - - if (!_cmsReadHeader(NewIcc)) goto Error; - return hEmpty; - -Error: - cmsCloseProfile(hEmpty); - return NULL; - -} - -cmsHPROFILE CMSEXPORT cmsOpenProfileFromStream(FILE* ICCProfile, const char *sAccess) -{ - return cmsOpenProfileFromStreamTHR(NULL, ICCProfile, sAccess); -} - - -// Open from memory block -cmsHPROFILE CMSEXPORT cmsOpenProfileFromMemTHR(cmsContext ContextID, const void* MemPtr, cmsUInt32Number dwSize) -{ - _cmsICCPROFILE* NewIcc; - cmsHPROFILE hEmpty; - - hEmpty = cmsCreateProfilePlaceholder(ContextID); - if (hEmpty == NULL) return NULL; - - NewIcc = (_cmsICCPROFILE*) hEmpty; - - // Ok, in this case const void* is casted to void* just because open IO handler - // shares read and writting modes. Don't abuse this feature! - NewIcc ->IOhandler = cmsOpenIOhandlerFromMem(ContextID, (void*) MemPtr, dwSize, "r"); - if (NewIcc ->IOhandler == NULL) goto Error; - - if (!_cmsReadHeader(NewIcc)) goto Error; - - return hEmpty; - -Error: - cmsCloseProfile(hEmpty); - return NULL; -} - -cmsHPROFILE CMSEXPORT cmsOpenProfileFromMem(const void* MemPtr, cmsUInt32Number dwSize) -{ - return cmsOpenProfileFromMemTHR(NULL, MemPtr, dwSize); -} - - - -// Dump tag contents. If the profile is being modified, untouched tags are copied from FileOrig -static -cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig) -{ - cmsUInt8Number* Data; - cmsUInt32Number i; - cmsUInt32Number Begin; - cmsIOHANDLER* io = Icc ->IOhandler; - cmsTagDescriptor* TagDescriptor; - cmsTagTypeSignature TypeBase; - cmsTagTypeSignature Type; - cmsTagTypeHandler* TypeHandler; - cmsFloat64Number Version = cmsGetProfileVersion((cmsHPROFILE) Icc); - cmsTagTypeHandler LocalTypeHandler; - - for (i=0; i < Icc -> TagCount; i++) { - - if (Icc ->TagNames[i] == 0) continue; - - // Linked tags are not written - if (Icc ->TagLinked[i] != (cmsTagSignature) 0) continue; - - Icc -> TagOffsets[i] = Begin = io ->UsedSpace; - - Data = (cmsUInt8Number*) Icc -> TagPtrs[i]; - - if (!Data) { - - // Reach here if we are copying a tag from a disk-based ICC profile which has not been modified by user. - // In this case a blind copy of the block data is performed - if (FileOrig != NULL && Icc -> TagOffsets[i]) { - - cmsUInt32Number TagSize = FileOrig -> TagSizes[i]; - cmsUInt32Number TagOffset = FileOrig -> TagOffsets[i]; - void* Mem; - - if (!FileOrig ->IOhandler->Seek(FileOrig ->IOhandler, TagOffset)) return FALSE; - - Mem = _cmsMalloc(Icc ->ContextID, TagSize); - if (Mem == NULL) return FALSE; - - if (FileOrig ->IOhandler->Read(FileOrig->IOhandler, Mem, TagSize, 1) != 1) return FALSE; - if (!io ->Write(io, TagSize, Mem)) return FALSE; - _cmsFree(Icc ->ContextID, Mem); - - Icc -> TagSizes[i] = (io ->UsedSpace - Begin); - - - // Align to 32 bit boundary. - if (! _cmsWriteAlignment(io)) - return FALSE; - } - - continue; - } - - - // Should this tag be saved as RAW? If so, tagsizes should be specified in advance (no further cooking is done) - if (Icc ->TagSaveAsRaw[i]) { - - if (io -> Write(io, Icc ->TagSizes[i], Data) != 1) return FALSE; - } - else { - - // Search for support on this tag - TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, Icc -> TagNames[i]); - if (TagDescriptor == NULL) continue; // Unsupported, ignore it - - if (TagDescriptor ->DecideType != NULL) { - - Type = TagDescriptor ->DecideType(Version, Data); - } - else { - - Type = TagDescriptor ->SupportedTypes[0]; - } - - TypeHandler = _cmsGetTagTypeHandler(Icc->ContextID, Type); - - if (TypeHandler == NULL) { - cmsSignalError(Icc ->ContextID, cmsERROR_INTERNAL, "(Internal) no handler for tag %x", Icc -> TagNames[i]); - continue; - } - - TypeBase = TypeHandler ->Signature; - if (!_cmsWriteTypeBase(io, TypeBase)) - return FALSE; - - LocalTypeHandler = *TypeHandler; - LocalTypeHandler.ContextID = Icc ->ContextID; - LocalTypeHandler.ICCVersion = Icc ->Version; - if (!LocalTypeHandler.WritePtr(&LocalTypeHandler, io, Data, TagDescriptor ->ElemCount)) { - - char String[5]; - - _cmsTagSignature2String(String, (cmsTagSignature) TypeBase); - cmsSignalError(Icc ->ContextID, cmsERROR_WRITE, "Couldn't write type '%s'", String); - return FALSE; - } - } - - - Icc -> TagSizes[i] = (io ->UsedSpace - Begin); - - // Align to 32 bit boundary. - if (! _cmsWriteAlignment(io)) - return FALSE; - } - - - return TRUE; -} - - -// Fill the offset and size fields for all linked tags -static -cmsBool SetLinks( _cmsICCPROFILE* Icc) -{ - cmsUInt32Number i; - - for (i=0; i < Icc -> TagCount; i++) { - - cmsTagSignature lnk = Icc ->TagLinked[i]; - if (lnk != (cmsTagSignature) 0) { - - int j = _cmsSearchTag(Icc, lnk, FALSE); - if (j >= 0) { - - Icc ->TagOffsets[i] = Icc ->TagOffsets[j]; - Icc ->TagSizes[i] = Icc ->TagSizes[j]; - } - - } - } - - return TRUE; -} - -// Low-level save to IOHANDLER. It returns the number of bytes used to -// store the profile, or zero on error. io may be NULL and in this case -// no data is written--only sizes are calculated -cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOHANDLER* io) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - _cmsICCPROFILE Keep; - cmsIOHANDLER* PrevIO = NULL; - cmsUInt32Number UsedSpace; - cmsContext ContextID; - - _cmsAssert(hProfile != NULL); - - memmove(&Keep, Icc, sizeof(_cmsICCPROFILE)); - - ContextID = cmsGetProfileContextID(hProfile); - PrevIO = Icc ->IOhandler = cmsOpenIOhandlerFromNULL(ContextID); - if (PrevIO == NULL) return 0; - - // Pass #1 does compute offsets - - if (!_cmsWriteHeader(Icc, 0)) goto Error; - if (!SaveTags(Icc, &Keep)) goto Error; - - UsedSpace = PrevIO ->UsedSpace; - - // Pass #2 does save to iohandler - - if (io != NULL) { - - Icc ->IOhandler = io; - if (!SetLinks(Icc)) goto Error; - if (!_cmsWriteHeader(Icc, UsedSpace)) goto Error; - if (!SaveTags(Icc, &Keep)) goto Error; - } - - memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); - if (!cmsCloseIOhandler(PrevIO)) return 0; - - return UsedSpace; - - -Error: - cmsCloseIOhandler(PrevIO); - memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); - return 0; -} - -#ifdef _WIN32_WCE -int wceex_unlink(const char *filename); -#ifndef remove -# define remove wceex_unlink -#endif -#endif - -// Low-level save to disk. -cmsBool CMSEXPORT cmsSaveProfileToFile(cmsHPROFILE hProfile, const char* FileName) -{ - cmsContext ContextID = cmsGetProfileContextID(hProfile); - cmsIOHANDLER* io = cmsOpenIOhandlerFromFile(ContextID, FileName, "w"); - cmsBool rc; - - if (io == NULL) return FALSE; - - rc = (cmsSaveProfileToIOhandler(hProfile, io) != 0); - rc &= cmsCloseIOhandler(io); - - if (rc == FALSE) { // remove() is C99 per 7.19.4.1 - remove(FileName); // We have to IGNORE return value in this case - } - return rc; -} - -// Same as anterior, but for streams -cmsBool CMSEXPORT cmsSaveProfileToStream(cmsHPROFILE hProfile, FILE* Stream) -{ - cmsBool rc; - cmsContext ContextID = cmsGetProfileContextID(hProfile); - cmsIOHANDLER* io = cmsOpenIOhandlerFromStream(ContextID, Stream); - - if (io == NULL) return FALSE; - - rc = (cmsSaveProfileToIOhandler(hProfile, io) != 0); - rc &= cmsCloseIOhandler(io); - - return rc; -} - - -// Same as anterior, but for memory blocks. In this case, a NULL as MemPtr means calculate needed space only -cmsBool CMSEXPORT cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, cmsUInt32Number* BytesNeeded) -{ - cmsBool rc; - cmsIOHANDLER* io; - cmsContext ContextID = cmsGetProfileContextID(hProfile); - - _cmsAssert(BytesNeeded != NULL); - - // Should we just calculate the needed space? - if (MemPtr == NULL) { - - *BytesNeeded = cmsSaveProfileToIOhandler(hProfile, NULL); - return (*BytesNeeded == 0) ? FALSE : TRUE; - } - - // That is a real write operation - io = cmsOpenIOhandlerFromMem(ContextID, MemPtr, *BytesNeeded, "w"); - if (io == NULL) return FALSE; - - rc = (cmsSaveProfileToIOhandler(hProfile, io) != 0); - rc &= cmsCloseIOhandler(io); - - return rc; -} - - - -// Closes a profile freeing any involved resources -cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - cmsBool rc = TRUE; - cmsUInt32Number i; - - if (!Icc) return FALSE; - - // Was open in write mode? - if (Icc ->IsWrite) { - - Icc ->IsWrite = FALSE; // Assure no further writting - rc &= cmsSaveProfileToFile(hProfile, Icc ->IOhandler->PhysicalFile); - } - - for (i=0; i < Icc -> TagCount; i++) { - - if (Icc -> TagPtrs[i]) { - - cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i]; - - if (TypeHandler != NULL) { - cmsTagTypeHandler LocalTypeHandler = *TypeHandler; - - LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameters - LocalTypeHandler.ICCVersion = Icc ->Version; - LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]); - } - else - _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]); - } - } - - if (Icc ->IOhandler != NULL) { - rc &= cmsCloseIOhandler(Icc->IOhandler); - } - - _cmsDestroyMutex(Icc->ContextID, Icc->UsrMutex); - - _cmsFree(Icc ->ContextID, Icc); // Free placeholder memory - - return rc; -} - - -// ------------------------------------------------------------------------------------------------------------------- - - -// Returns TRUE if a given tag is supported by a plug-in -static -cmsBool IsTypeSupported(cmsTagDescriptor* TagDescriptor, cmsTagTypeSignature Type) -{ - cmsUInt32Number i, nMaxTypes; - - nMaxTypes = TagDescriptor->nSupportedTypes; - if (nMaxTypes >= MAX_TYPES_IN_LCMS_PLUGIN) - nMaxTypes = MAX_TYPES_IN_LCMS_PLUGIN; - - for (i=0; i < nMaxTypes; i++) { - if (Type == TagDescriptor ->SupportedTypes[i]) return TRUE; - } - - return FALSE; -} - - -// That's the main read function -void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - cmsIOHANDLER* io = Icc ->IOhandler; - cmsTagTypeHandler* TypeHandler; - cmsTagTypeHandler LocalTypeHandler; - cmsTagDescriptor* TagDescriptor; - cmsTagTypeSignature BaseType; - cmsUInt32Number Offset, TagSize; - cmsUInt32Number ElemCount; - int n; - - if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return NULL; - - n = _cmsSearchTag(Icc, sig, TRUE); - if (n < 0) goto Error; // Not found, return NULL - - - // If the element is already in memory, return the pointer - if (Icc -> TagPtrs[n]) { - - if (Icc->TagTypeHandlers[n] == NULL) goto Error; - - // Sanity check - BaseType = Icc->TagTypeHandlers[n]->Signature; - if (BaseType == 0) goto Error; - - TagDescriptor = _cmsGetTagDescriptor(Icc->ContextID, sig); - if (TagDescriptor == NULL) goto Error; - - if (!IsTypeSupported(TagDescriptor, BaseType)) goto Error; - - if (Icc ->TagSaveAsRaw[n]) goto Error; // We don't support read raw tags as cooked - - _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); - return Icc -> TagPtrs[n]; - } - - // We need to read it. Get the offset and size to the file - Offset = Icc -> TagOffsets[n]; - TagSize = Icc -> TagSizes[n]; - - // Seek to its location - if (!io -> Seek(io, Offset)) - goto Error; - - // Search for support on this tag - TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig); - if (TagDescriptor == NULL) { - - char String[5]; - - _cmsTagSignature2String(String, sig); - - // An unknown element was found. - cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown tag type '%s' found.", String); - goto Error; // Unsupported. - } - - // if supported, get type and check if in list - BaseType = _cmsReadTypeBase(io); - if (BaseType == 0) goto Error; - - if (!IsTypeSupported(TagDescriptor, BaseType)) goto Error; - - TagSize -= 8; // Alredy read by the type base logic - - // Get type handler - TypeHandler = _cmsGetTagTypeHandler(Icc ->ContextID, BaseType); - if (TypeHandler == NULL) goto Error; - LocalTypeHandler = *TypeHandler; - - - // Read the tag - Icc -> TagTypeHandlers[n] = TypeHandler; - - LocalTypeHandler.ContextID = Icc ->ContextID; - LocalTypeHandler.ICCVersion = Icc ->Version; - Icc -> TagPtrs[n] = LocalTypeHandler.ReadPtr(&LocalTypeHandler, io, &ElemCount, TagSize); - - // The tag type is supported, but something wrong happend and we cannot read the tag. - // let know the user about this (although it is just a warning) - if (Icc -> TagPtrs[n] == NULL) { - - char String[5]; - - _cmsTagSignature2String(String, sig); - cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Corrupted tag '%s'", String); - goto Error; - } - - // This is a weird error that may be a symptom of something more serious, the number of - // stored item is actually less than the number of required elements. - if (ElemCount < TagDescriptor ->ElemCount) { - - char String[5]; - - _cmsTagSignature2String(String, sig); - cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "'%s' Inconsistent number of items: expected %d, got %d", - String, TagDescriptor ->ElemCount, ElemCount); - } - - - // Return the data - _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); - return Icc -> TagPtrs[n]; - - - // Return error and unlock tha data -Error: - _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); - return NULL; -} - - -// Get true type of data -cmsTagTypeSignature _cmsGetTagTrueType(cmsHPROFILE hProfile, cmsTagSignature sig) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - cmsTagTypeHandler* TypeHandler; - int n; - - // Search for given tag in ICC profile directory - n = _cmsSearchTag(Icc, sig, TRUE); - if (n < 0) return (cmsTagTypeSignature) 0; // Not found, return NULL - - // Get the handler. The true type is there - TypeHandler = Icc -> TagTypeHandlers[n]; - return TypeHandler ->Signature; -} - - -// Write a single tag. This just keeps track of the tak into a list of "to be written". If the tag is already -// in that list, the previous version is deleted. -cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - cmsTagTypeHandler* TypeHandler = NULL; - cmsTagTypeHandler LocalTypeHandler; - cmsTagDescriptor* TagDescriptor = NULL; - cmsTagTypeSignature Type; - int i; - cmsFloat64Number Version; - char TypeString[5], SigString[5]; - - if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return FALSE; - - // To delete tags. - if (data == NULL) { - - // Delete the tag - i = _cmsSearchTag(Icc, sig, FALSE); - if (i >= 0) { - - // Use zero as a mark of deleted - _cmsDeleteTagByPos(Icc, i); - Icc ->TagNames[i] = (cmsTagSignature) 0; - _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); - return TRUE; - } - // Didn't find the tag - goto Error; - } - - if (!_cmsNewTag(Icc, sig, &i)) goto Error; - - // This is not raw - Icc ->TagSaveAsRaw[i] = FALSE; - - // This is not a link - Icc ->TagLinked[i] = (cmsTagSignature) 0; - - // Get information about the TAG. - TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig); - if (TagDescriptor == NULL){ - cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag '%x'", sig); - goto Error; - } - - - // Now we need to know which type to use. It depends on the version. - Version = cmsGetProfileVersion(hProfile); - - if (TagDescriptor ->DecideType != NULL) { - - // Let the tag descriptor to decide the type base on depending on - // the data. This is useful for example on parametric curves, where - // curves specified by a table cannot be saved as parametric and needs - // to be casted to single v2-curves, even on v4 profiles. - - Type = TagDescriptor ->DecideType(Version, data); - } - else { - - Type = TagDescriptor ->SupportedTypes[0]; - } - - // Does the tag support this type? - if (!IsTypeSupported(TagDescriptor, Type)) { - - _cmsTagSignature2String(TypeString, (cmsTagSignature) Type); - _cmsTagSignature2String(SigString, sig); - - cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString); - goto Error; - } - - // Does we have a handler for this type? - TypeHandler = _cmsGetTagTypeHandler(Icc->ContextID, Type); - if (TypeHandler == NULL) { - - _cmsTagSignature2String(TypeString, (cmsTagSignature) Type); - _cmsTagSignature2String(SigString, sig); - - cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString); - goto Error; // Should never happen - } - - - // Fill fields on icc structure - Icc ->TagTypeHandlers[i] = TypeHandler; - Icc ->TagNames[i] = sig; - Icc ->TagSizes[i] = 0; - Icc ->TagOffsets[i] = 0; - - LocalTypeHandler = *TypeHandler; - LocalTypeHandler.ContextID = Icc ->ContextID; - LocalTypeHandler.ICCVersion = Icc ->Version; - Icc ->TagPtrs[i] = LocalTypeHandler.DupPtr(&LocalTypeHandler, data, TagDescriptor ->ElemCount); - - if (Icc ->TagPtrs[i] == NULL) { - - _cmsTagSignature2String(TypeString, (cmsTagSignature) Type); - _cmsTagSignature2String(SigString, sig); - cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Malformed struct in type '%s' for tag '%s'", TypeString, SigString); - - goto Error; - } - - _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); - return TRUE; - -Error: - _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); - return FALSE; - -} - -// Read and write raw data. The only way those function would work and keep consistence with normal read and write -// is to do an additional step of serialization. That means, readRaw would issue a normal read and then convert the obtained -// data to raw bytes by using the "write" serialization logic. And vice-versa. I know this may end in situations where -// raw data written does not exactly correspond with the raw data proposed to cmsWriteRaw data, but this approach allows -// to write a tag as raw data and the read it as handled. - -cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, void* data, cmsUInt32Number BufferSize) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - void *Object; - int i; - cmsIOHANDLER* MemIO; - cmsTagTypeHandler* TypeHandler = NULL; - cmsTagTypeHandler LocalTypeHandler; - cmsTagDescriptor* TagDescriptor = NULL; - cmsUInt32Number rc; - cmsUInt32Number Offset, TagSize; - - if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0; - - // Search for given tag in ICC profile directory - i = _cmsSearchTag(Icc, sig, TRUE); - if (i < 0) goto Error; // Not found, - - // It is already read? - if (Icc -> TagPtrs[i] == NULL) { - - // No yet, get original position - Offset = Icc ->TagOffsets[i]; - TagSize = Icc ->TagSizes[i]; - - // read the data directly, don't keep copy - if (data != NULL) { - - if (BufferSize < TagSize) - TagSize = BufferSize; - - if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) goto Error; - if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) goto Error; - - _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); - return TagSize; - } - - _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); - return Icc ->TagSizes[i]; - } - - // The data has been already read, or written. But wait!, maybe the user choosed to save as - // raw data. In this case, return the raw data directly - if (Icc ->TagSaveAsRaw[i]) { - - if (data != NULL) { - - TagSize = Icc ->TagSizes[i]; - if (BufferSize < TagSize) - TagSize = BufferSize; - - memmove(data, Icc ->TagPtrs[i], TagSize); - - _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); - return TagSize; - } - - _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); - return Icc ->TagSizes[i]; - } - - // Already readed, or previously set by cmsWriteTag(). We need to serialize that - // data to raw in order to maintain consistency. - - _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); - Object = cmsReadTag(hProfile, sig); - if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0; - - if (Object == NULL) goto Error; - - // Now we need to serialize to a memory block: just use a memory iohandler - - if (data == NULL) { - MemIO = cmsOpenIOhandlerFromNULL(cmsGetProfileContextID(hProfile)); - } else{ - MemIO = cmsOpenIOhandlerFromMem(cmsGetProfileContextID(hProfile), data, BufferSize, "w"); - } - if (MemIO == NULL) goto Error; - - // Obtain type handling for the tag - TypeHandler = Icc ->TagTypeHandlers[i]; - TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig); - if (TagDescriptor == NULL) { - cmsCloseIOhandler(MemIO); - goto Error; - } - - if (TypeHandler == NULL) goto Error; - - // Serialize - LocalTypeHandler = *TypeHandler; - LocalTypeHandler.ContextID = Icc ->ContextID; - LocalTypeHandler.ICCVersion = Icc ->Version; - - if (!_cmsWriteTypeBase(MemIO, TypeHandler ->Signature)) { - cmsCloseIOhandler(MemIO); - goto Error; - } - - if (!LocalTypeHandler.WritePtr(&LocalTypeHandler, MemIO, Object, TagDescriptor ->ElemCount)) { - cmsCloseIOhandler(MemIO); - goto Error; - } - - // Get Size and close - rc = MemIO ->Tell(MemIO); - cmsCloseIOhandler(MemIO); // Ignore return code this time - - _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); - return rc; - -Error: - _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); - return 0; -} - -// Similar to the anterior. This function allows to write directly to the ICC profile any data, without -// checking anything. As a rule, mixing Raw with cooked doesn't work, so writting a tag as raw and then reading -// it as cooked without serializing does result into an error. If that is wha you want, you will need to dump -// the profile to memry or disk and then reopen it. -cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data, cmsUInt32Number Size) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - int i; - - if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0; - - if (!_cmsNewTag(Icc, sig, &i)) { - _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); - return FALSE; - } - - // Mark the tag as being written as RAW - Icc ->TagSaveAsRaw[i] = TRUE; - Icc ->TagNames[i] = sig; - Icc ->TagLinked[i] = (cmsTagSignature) 0; - - // Keep a copy of the block - Icc ->TagPtrs[i] = _cmsDupMem(Icc ->ContextID, data, Size); - Icc ->TagSizes[i] = Size; - - _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); - return TRUE; -} - -// Using this function you can collapse several tag entries to the same block in the profile -cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSignature dest) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - int i; - - if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return FALSE; - - if (!_cmsNewTag(Icc, sig, &i)) { - _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); - return FALSE; - } - - // Keep necessary information - Icc ->TagSaveAsRaw[i] = FALSE; - Icc ->TagNames[i] = sig; - Icc ->TagLinked[i] = dest; - - Icc ->TagPtrs[i] = NULL; - Icc ->TagSizes[i] = 0; - Icc ->TagOffsets[i] = 0; - - _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); - return TRUE; -} - - -// Returns the tag linked to sig, in the case two tags are sharing same resource -cmsTagSignature CMSEXPORT cmsTagLinkedTo(cmsHPROFILE hProfile, cmsTagSignature sig) -{ - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - int i; - - // Search for given tag in ICC profile directory - i = _cmsSearchTag(Icc, sig, FALSE); - if (i < 0) return (cmsTagSignature) 0; // Not found, return 0 - - return Icc -> TagLinked[i]; -} diff --git a/third_party/lcms2-2.6/src/cmsio1.c b/third_party/lcms2-2.6/src/cmsio1.c deleted file mode 100644 index 778aa2b4fc..0000000000 --- a/third_party/lcms2-2.6/src/cmsio1.c +++ /dev/null @@ -1,1020 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- -// - -#include "lcms2_internal.h" - -// Read tags using low-level functions, provides necessary glue code to adapt versions, etc. - -// LUT tags -static const cmsTagSignature Device2PCS16[] = {cmsSigAToB0Tag, // Perceptual - cmsSigAToB1Tag, // Relative colorimetric - cmsSigAToB2Tag, // Saturation - cmsSigAToB1Tag }; // Absolute colorimetric - -static const cmsTagSignature Device2PCSFloat[] = {cmsSigDToB0Tag, // Perceptual - cmsSigDToB1Tag, // Relative colorimetric - cmsSigDToB2Tag, // Saturation - cmsSigDToB3Tag }; // Absolute colorimetric - -static const cmsTagSignature PCS2Device16[] = {cmsSigBToA0Tag, // Perceptual - cmsSigBToA1Tag, // Relative colorimetric - cmsSigBToA2Tag, // Saturation - cmsSigBToA1Tag }; // Absolute colorimetric - -static const cmsTagSignature PCS2DeviceFloat[] = {cmsSigBToD0Tag, // Perceptual - cmsSigBToD1Tag, // Relative colorimetric - cmsSigBToD2Tag, // Saturation - cmsSigBToD3Tag }; // Absolute colorimetric - - -// Factors to convert from 1.15 fixed point to 0..1.0 range and vice-versa -#define InpAdj (1.0/MAX_ENCODEABLE_XYZ) // (65536.0/(65535.0*2.0)) -#define OutpAdj (MAX_ENCODEABLE_XYZ) // ((2.0*65535.0)/65536.0) - -// Several resources for gray conversions. -static const cmsFloat64Number GrayInputMatrix[] = { (InpAdj*cmsD50X), (InpAdj*cmsD50Y), (InpAdj*cmsD50Z) }; -static const cmsFloat64Number OneToThreeInputMatrix[] = { 1, 1, 1 }; -static const cmsFloat64Number PickYMatrix[] = { 0, (OutpAdj*cmsD50Y), 0 }; -static const cmsFloat64Number PickLstarMatrix[] = { 1, 0, 0 }; - -// Get a media white point fixing some issues found in certain old profiles -cmsBool _cmsReadMediaWhitePoint(cmsCIEXYZ* Dest, cmsHPROFILE hProfile) -{ - cmsCIEXYZ* Tag; - - _cmsAssert(Dest != NULL); - - Tag = (cmsCIEXYZ*) cmsReadTag(hProfile, cmsSigMediaWhitePointTag); - - // If no wp, take D50 - if (Tag == NULL) { - *Dest = *cmsD50_XYZ(); - return TRUE; - } - - // V2 display profiles should give D50 - if (cmsGetEncodedICCversion(hProfile) < 0x4000000) { - - if (cmsGetDeviceClass(hProfile) == cmsSigDisplayClass) { - *Dest = *cmsD50_XYZ(); - return TRUE; - } - } - - // All seems ok - *Dest = *Tag; - return TRUE; -} - - -// Chromatic adaptation matrix. Fix some issues as well -cmsBool _cmsReadCHAD(cmsMAT3* Dest, cmsHPROFILE hProfile) -{ - cmsMAT3* Tag; - - _cmsAssert(Dest != NULL); - - Tag = (cmsMAT3*) cmsReadTag(hProfile, cmsSigChromaticAdaptationTag); - - if (Tag != NULL) { - *Dest = *Tag; - return TRUE; - } - - // No CHAD available, default it to identity - _cmsMAT3identity(Dest); - - // V2 display profiles should give D50 - if (cmsGetEncodedICCversion(hProfile) < 0x4000000) { - - if (cmsGetDeviceClass(hProfile) == cmsSigDisplayClass) { - - cmsCIEXYZ* White = (cmsCIEXYZ*) cmsReadTag(hProfile, cmsSigMediaWhitePointTag); - - if (White == NULL) { - - _cmsMAT3identity(Dest); - return TRUE; - } - - return _cmsAdaptationMatrix(Dest, NULL, White, cmsD50_XYZ()); - } - } - - return TRUE; -} - - -// Auxiliar, read colorants as a MAT3 structure. Used by any function that needs a matrix-shaper -static -cmsBool ReadICCMatrixRGB2XYZ(cmsMAT3* r, cmsHPROFILE hProfile) -{ - cmsCIEXYZ *PtrRed, *PtrGreen, *PtrBlue; - - _cmsAssert(r != NULL); - - PtrRed = (cmsCIEXYZ *) cmsReadTag(hProfile, cmsSigRedColorantTag); - PtrGreen = (cmsCIEXYZ *) cmsReadTag(hProfile, cmsSigGreenColorantTag); - PtrBlue = (cmsCIEXYZ *) cmsReadTag(hProfile, cmsSigBlueColorantTag); - - if (PtrRed == NULL || PtrGreen == NULL || PtrBlue == NULL) - return FALSE; - - _cmsVEC3init(&r -> v[0], PtrRed -> X, PtrGreen -> X, PtrBlue -> X); - _cmsVEC3init(&r -> v[1], PtrRed -> Y, PtrGreen -> Y, PtrBlue -> Y); - _cmsVEC3init(&r -> v[2], PtrRed -> Z, PtrGreen -> Z, PtrBlue -> Z); - - return TRUE; -} - - -// Gray input pipeline -static -cmsPipeline* BuildGrayInputMatrixPipeline(cmsHPROFILE hProfile) -{ - cmsToneCurve *GrayTRC; - cmsPipeline* Lut; - cmsContext ContextID = cmsGetProfileContextID(hProfile); - - GrayTRC = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGrayTRCTag); - if (GrayTRC == NULL) return NULL; - - Lut = cmsPipelineAlloc(ContextID, 1, 3); - if (Lut == NULL) - goto Error; - - if (cmsGetPCS(hProfile) == cmsSigLabData) { - - // In this case we implement the profile as an identity matrix plus 3 tone curves - cmsUInt16Number Zero[2] = { 0x8080, 0x8080 }; - cmsToneCurve* EmptyTab; - cmsToneCurve* LabCurves[3]; - - EmptyTab = cmsBuildTabulatedToneCurve16(ContextID, 2, Zero); - - if (EmptyTab == NULL) - goto Error; - - LabCurves[0] = GrayTRC; - LabCurves[1] = EmptyTab; - LabCurves[2] = EmptyTab; - - if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 1, OneToThreeInputMatrix, NULL)) || - !cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, LabCurves))) { - cmsFreeToneCurve(EmptyTab); - goto Error; - } - - cmsFreeToneCurve(EmptyTab); - - } - else { - - if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 1, &GrayTRC)) || - !cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 1, GrayInputMatrix, NULL))) - goto Error; - } - - return Lut; - -Error: - // memory pointed by GrayTRC is not a new malloc memory, so don't free it here, - // memory pointed by GrayTRC will be freed when hProfile is closed. - // test file :0047776_Pocket Medicine_ The Massachusetts General Hospital Handbook of Internal Medicine-2.pdf - // Xiaochuan Liu, 20140421 - //cmsFreeToneCurve(GrayTRC); - cmsPipelineFree(Lut); - return NULL; -} - -// RGB Matrix shaper -static -cmsPipeline* BuildRGBInputMatrixShaper(cmsHPROFILE hProfile) -{ - cmsPipeline* Lut; - cmsMAT3 Mat; - cmsToneCurve *Shapes[3]; - cmsContext ContextID = cmsGetProfileContextID(hProfile); - int i, j; - - if (!ReadICCMatrixRGB2XYZ(&Mat, hProfile)) return NULL; - - // XYZ PCS in encoded in 1.15 format, and the matrix output comes in 0..0xffff range, so - // we need to adjust the output by a factor of (0x10000/0xffff) to put data in - // a 1.16 range, and then a >> 1 to obtain 1.15. The total factor is (65536.0)/(65535.0*2) - - for (i=0; i < 3; i++) - for (j=0; j < 3; j++) - Mat.v[i].n[j] *= InpAdj; - - - Shapes[0] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigRedTRCTag); - Shapes[1] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGreenTRCTag); - Shapes[2] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigBlueTRCTag); - - if (!Shapes[0] || !Shapes[1] || !Shapes[2]) - return NULL; - - Lut = cmsPipelineAlloc(ContextID, 3, 3); - if (Lut != NULL) { - - if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, Shapes)) || - !cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Mat, NULL))) - goto Error; - - // Note that it is certainly possible a single profile would have a LUT based - // tag for output working in lab and a matrix-shaper for the fallback cases. - // This is not allowed by the spec, but this code is tolerant to those cases - if (cmsGetPCS(hProfile) == cmsSigLabData) { - - if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocXYZ2Lab(ContextID))) - goto Error; - } - - } - - return Lut; - -Error: - cmsPipelineFree(Lut); - return NULL; -} - - - -// Read the DToAX tag, adjusting the encoding of Lab or XYZ if neded -static -cmsPipeline* _cmsReadFloatInputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat) -{ - cmsContext ContextID = cmsGetProfileContextID(hProfile); - cmsPipeline* Lut = cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat)); - cmsColorSpaceSignature spc = cmsGetColorSpace(hProfile); - cmsColorSpaceSignature PCS = cmsGetPCS(hProfile); - - if (Lut == NULL) return NULL; - - // input and output of transform are in lcms 0..1 encoding. If XYZ or Lab spaces are used, - // these need to be normalized into the appropriate ranges (Lab = 100,0,0, XYZ=1.0,1.0,1.0) - if ( spc == cmsSigLabData) - { - if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID))) - goto Error; - } - else if (spc == cmsSigXYZData) - { - if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID))) - goto Error; - } - - if ( PCS == cmsSigLabData) - { - if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID))) - goto Error; - } - else if( PCS == cmsSigXYZData) - { - if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID))) - goto Error; - } - - return Lut; - -Error: - cmsPipelineFree(Lut); - return NULL; -} - - -// Read and create a BRAND NEW MPE LUT from a given profile. All stuff dependent of version, etc -// is adjusted here in order to create a LUT that takes care of all those details. -// We add intent = -1 as a way to read matrix shaper always, no matter of other LUT -cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent) -{ - cmsTagTypeSignature OriginalType; - cmsTagSignature tag16 = Device2PCS16[Intent]; - cmsTagSignature tagFloat = Device2PCSFloat[Intent]; - cmsContext ContextID = cmsGetProfileContextID(hProfile); - - // On named color, take the appropiate tag - if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) { - - cmsPipeline* Lut; - cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) cmsReadTag(hProfile, cmsSigNamedColor2Tag); - - if (nc == NULL) return NULL; - - Lut = cmsPipelineAlloc(ContextID, 0, 0); - if (Lut == NULL) { - cmsFreeNamedColorList(nc); - return NULL; - } - - if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocNamedColor(nc, TRUE)) || - !cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) { - cmsPipelineFree(Lut); - return NULL; - } - return Lut; - } - - // This is an attempt to reuse this funtion to retrieve the matrix-shaper as pipeline no - // matter other LUT are present and have precedence. Intent = -1 means just this. - if (Intent != -1) { - - if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence - - // Floating point LUT are always V4, but the encoding range is no - // longer 0..1.0, so we need to add an stage depending on the color space - return _cmsReadFloatInputTag(hProfile, tagFloat); - } - - // Revert to perceptual if no tag is found - if (!cmsIsTag(hProfile, tag16)) { - tag16 = Device2PCS16[0]; - } - - if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table? - - // Check profile version and LUT type. Do the necessary adjustments if needed - - // First read the tag - cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16); - if (Lut == NULL) return NULL; - - // After reading it, we have now info about the original type - OriginalType = _cmsGetTagTrueType(hProfile, tag16); - - // The profile owns the Lut, so we need to copy it - Lut = cmsPipelineDup(Lut); - - // We need to adjust data only for Lab16 on output - if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData) - return Lut; - - // If the input is Lab, add also a conversion at the begin - if (cmsGetColorSpace(hProfile) == cmsSigLabData && - !cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID))) - goto Error; - - // Add a matrix for conversion V2 to V4 Lab PCS - if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) - goto Error; - - return Lut; -Error: - cmsPipelineFree(Lut); - return NULL; - } - } - - // Lut was not found, try to create a matrix-shaper - - // Check if this is a grayscale profile. - if (cmsGetColorSpace(hProfile) == cmsSigGrayData) { - - // if so, build appropiate conversion tables. - // The tables are the PCS iluminant, scaled across GrayTRC - return BuildGrayInputMatrixPipeline(hProfile); - } - - // Not gray, create a normal matrix-shaper - return BuildRGBInputMatrixShaper(hProfile); -} - -// --------------------------------------------------------------------------------------------------------------- - -// Gray output pipeline. -// XYZ -> Gray or Lab -> Gray. Since we only know the GrayTRC, we need to do some assumptions. Gray component will be -// given by Y on XYZ PCS and by L* on Lab PCS, Both across inverse TRC curve. -// The complete pipeline on XYZ is Matrix[3:1] -> Tone curve and in Lab Matrix[3:1] -> Tone Curve as well. - -static -cmsPipeline* BuildGrayOutputPipeline(cmsHPROFILE hProfile) -{ - cmsToneCurve *GrayTRC, *RevGrayTRC; - cmsPipeline* Lut; - cmsContext ContextID = cmsGetProfileContextID(hProfile); - - GrayTRC = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGrayTRCTag); - if (GrayTRC == NULL) return NULL; - - RevGrayTRC = cmsReverseToneCurve(GrayTRC); - if (RevGrayTRC == NULL) return NULL; - - Lut = cmsPipelineAlloc(ContextID, 3, 1); - if (Lut == NULL) { - cmsFreeToneCurve(RevGrayTRC); - return NULL; - } - - if (cmsGetPCS(hProfile) == cmsSigLabData) { - - if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickLstarMatrix, NULL))) - goto Error; - } - else { - if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickYMatrix, NULL))) - goto Error; - } - - if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 1, &RevGrayTRC))) - goto Error; - - cmsFreeToneCurve(RevGrayTRC); - return Lut; - -Error: - cmsFreeToneCurve(RevGrayTRC); - cmsPipelineFree(Lut); - return NULL; -} - - -static -cmsPipeline* BuildRGBOutputMatrixShaper(cmsHPROFILE hProfile) -{ - cmsPipeline* Lut; - cmsToneCurve *Shapes[3], *InvShapes[3]; - cmsMAT3 Mat, Inv; - int i, j; - cmsContext ContextID = cmsGetProfileContextID(hProfile); - - if (!ReadICCMatrixRGB2XYZ(&Mat, hProfile)) - return NULL; - - if (!_cmsMAT3inverse(&Mat, &Inv)) - return NULL; - - // XYZ PCS in encoded in 1.15 format, and the matrix input should come in 0..0xffff range, so - // we need to adjust the input by a << 1 to obtain a 1.16 fixed and then by a factor of - // (0xffff/0x10000) to put data in 0..0xffff range. Total factor is (2.0*65535.0)/65536.0; - - for (i=0; i < 3; i++) - for (j=0; j < 3; j++) - Inv.v[i].n[j] *= OutpAdj; - - Shapes[0] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigRedTRCTag); - Shapes[1] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGreenTRCTag); - Shapes[2] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigBlueTRCTag); - - if (!Shapes[0] || !Shapes[1] || !Shapes[2]) - return NULL; - - InvShapes[0] = cmsReverseToneCurve(Shapes[0]); - InvShapes[1] = cmsReverseToneCurve(Shapes[1]); - InvShapes[2] = cmsReverseToneCurve(Shapes[2]); - - if (!InvShapes[0] || !InvShapes[1] || !InvShapes[2]) { - return NULL; - } - - Lut = cmsPipelineAlloc(ContextID, 3, 3); - if (Lut != NULL) { - - // Note that it is certainly possible a single profile would have a LUT based - // tag for output working in lab and a matrix-shaper for the fallback cases. - // This is not allowed by the spec, but this code is tolerant to those cases - if (cmsGetPCS(hProfile) == cmsSigLabData) { - - if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLab2XYZ(ContextID))) - goto Error; - } - - if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Inv, NULL)) || - !cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, InvShapes))) - goto Error; - } - - cmsFreeToneCurveTriple(InvShapes); - return Lut; -Error: - cmsFreeToneCurveTriple(InvShapes); - cmsPipelineFree(Lut); - return NULL; -} - - -// Change CLUT interpolation to trilinear -static -void ChangeInterpolationToTrilinear(cmsPipeline* Lut) -{ - cmsStage* Stage; - - for (Stage = cmsPipelineGetPtrToFirstStage(Lut); - Stage != NULL; - Stage = cmsStageNext(Stage)) { - - if (cmsStageType(Stage) == cmsSigCLutElemType) { - - _cmsStageCLutData* CLUT = (_cmsStageCLutData*) Stage ->Data; - - CLUT ->Params->dwFlags |= CMS_LERP_FLAGS_TRILINEAR; - _cmsSetInterpolationRoutine(Lut->ContextID, CLUT ->Params); - } - } -} - - -// Read the DToAX tag, adjusting the encoding of Lab or XYZ if neded -static -cmsPipeline* _cmsReadFloatOutputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat) -{ - cmsContext ContextID = cmsGetProfileContextID(hProfile); - cmsPipeline* Lut = cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat)); - cmsColorSpaceSignature PCS = cmsGetPCS(hProfile); - cmsColorSpaceSignature dataSpace = cmsGetColorSpace(hProfile); - - if (Lut == NULL) return NULL; - - // If PCS is Lab or XYZ, the floating point tag is accepting data in the space encoding, - // and since the formatter has already accomodated to 0..1.0, we should undo this change - if ( PCS == cmsSigLabData) - { - if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID))) - goto Error; - } - else - if (PCS == cmsSigXYZData) - { - if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID))) - goto Error; - } - - // the output can be Lab or XYZ, in which case normalisation is needed on the end of the pipeline - if ( dataSpace == cmsSigLabData) - { - if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID))) - goto Error; - } - else if (dataSpace == cmsSigXYZData) - { - if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID))) - goto Error; - } - - return Lut; - -Error: - cmsPipelineFree(Lut); - return NULL; -} - -// Create an output MPE LUT from agiven profile. Version mismatches are handled here -cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent) -{ - cmsTagTypeSignature OriginalType; - cmsTagSignature tag16 = PCS2Device16[Intent]; - cmsTagSignature tagFloat = PCS2DeviceFloat[Intent]; - cmsContext ContextID = cmsGetProfileContextID(hProfile); - - - if (Intent != -1) { - - if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence - - // Floating point LUT are always V4 - return _cmsReadFloatOutputTag(hProfile, tagFloat); - } - - // Revert to perceptual if no tag is found - if (!cmsIsTag(hProfile, tag16)) { - tag16 = PCS2Device16[0]; - } - - if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table? - - // Check profile version and LUT type. Do the necessary adjustments if needed - - // First read the tag - cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16); - if (Lut == NULL) return NULL; - - // After reading it, we have info about the original type - OriginalType = _cmsGetTagTrueType(hProfile, tag16); - - // The profile owns the Lut, so we need to copy it - Lut = cmsPipelineDup(Lut); - if (Lut == NULL) return NULL; - - // Now it is time for a controversial stuff. I found that for 3D LUTS using - // Lab used as indexer space, trilinear interpolation should be used - if (cmsGetPCS(hProfile) == cmsSigLabData) - ChangeInterpolationToTrilinear(Lut); - - // We need to adjust data only for Lab and Lut16 type - if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData) - return Lut; - - // Add a matrix for conversion V4 to V2 Lab PCS - if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID))) - goto Error; - - // If the output is Lab, add also a conversion at the end - if (cmsGetColorSpace(hProfile) == cmsSigLabData) - if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) - goto Error; - - return Lut; -Error: - cmsPipelineFree(Lut); - return NULL; - } - } - - // Lut not found, try to create a matrix-shaper - - // Check if this is a grayscale profile. - if (cmsGetColorSpace(hProfile) == cmsSigGrayData) { - - // if so, build appropiate conversion tables. - // The tables are the PCS iluminant, scaled across GrayTRC - return BuildGrayOutputPipeline(hProfile); - } - - // Not gray, create a normal matrix-shaper, which only operates in XYZ space - return BuildRGBOutputMatrixShaper(hProfile); -} - -// --------------------------------------------------------------------------------------------------------------- - -// Read the AToD0 tag, adjusting the encoding of Lab or XYZ if neded -static -cmsPipeline* _cmsReadFloatDevicelinkTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat) -{ - cmsContext ContextID = cmsGetProfileContextID(hProfile); - cmsPipeline* Lut = cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat)); - cmsColorSpaceSignature PCS = cmsGetPCS(hProfile); - cmsColorSpaceSignature spc = cmsGetColorSpace(hProfile); - - if (Lut == NULL) return NULL; - - if (spc == cmsSigLabData) - { - if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID))) - goto Error; - } - else - if (spc == cmsSigXYZData) - { - if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID))) - goto Error; - } - - if (PCS == cmsSigLabData) - { - if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID))) - goto Error; - } - else - if (PCS == cmsSigXYZData) - { - if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID))) - goto Error; - } - - return Lut; -Error: - cmsPipelineFree(Lut); - return NULL; -} - -// This one includes abstract profiles as well. Matrix-shaper cannot be obtained on that device class. The -// tag name here may default to AToB0 -cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent) -{ - cmsPipeline* Lut; - cmsTagTypeSignature OriginalType; - cmsTagSignature tag16 = Device2PCS16[Intent]; - cmsTagSignature tagFloat = Device2PCSFloat[Intent]; - cmsContext ContextID = cmsGetProfileContextID(hProfile); - - - // On named color, take the appropiate tag - if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) { - - cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) cmsReadTag(hProfile, cmsSigNamedColor2Tag); - - if (nc == NULL) return NULL; - - Lut = cmsPipelineAlloc(ContextID, 0, 0); - if (Lut == NULL) - goto Error; - - if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocNamedColor(nc, FALSE))) - goto Error; - - if (cmsGetColorSpace(hProfile) == cmsSigLabData) - if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) - goto Error; - - return Lut; -Error: - cmsPipelineFree(Lut); - cmsFreeNamedColorList(nc); - return NULL; - } - - if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence - - // Floating point LUT are always V - return _cmsReadFloatDevicelinkTag(hProfile, tagFloat); - } - - tagFloat = Device2PCSFloat[0]; - if (cmsIsTag(hProfile, tagFloat)) { - - return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat)); - } - - if (!cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table? - - tag16 = Device2PCS16[0]; - if (!cmsIsTag(hProfile, tag16)) return NULL; - } - - // Check profile version and LUT type. Do the necessary adjustments if needed - - // Read the tag - Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16); - if (Lut == NULL) return NULL; - - // The profile owns the Lut, so we need to copy it - Lut = cmsPipelineDup(Lut); - if (Lut == NULL) return NULL; - - // Now it is time for a controversial stuff. I found that for 3D LUTS using - // Lab used as indexer space, trilinear interpolation should be used - if (cmsGetPCS(hProfile) == cmsSigLabData) - ChangeInterpolationToTrilinear(Lut); - - // After reading it, we have info about the original type - OriginalType = _cmsGetTagTrueType(hProfile, tag16); - - // We need to adjust data for Lab16 on output - if (OriginalType != cmsSigLut16Type) return Lut; - - // Here it is possible to get Lab on both sides - - if (cmsGetColorSpace(hProfile) == cmsSigLabData) { - if(!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID))) - goto Error2; - } - - if (cmsGetPCS(hProfile) == cmsSigLabData) { - if(!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) - goto Error2; - } - - return Lut; - -Error2: - cmsPipelineFree(Lut); - return NULL; -} - -// --------------------------------------------------------------------------------------------------------------- - -// Returns TRUE if the profile is implemented as matrix-shaper -cmsBool CMSEXPORT cmsIsMatrixShaper(cmsHPROFILE hProfile) -{ - switch (cmsGetColorSpace(hProfile)) { - - case cmsSigGrayData: - - return cmsIsTag(hProfile, cmsSigGrayTRCTag); - - case cmsSigRgbData: - - return (cmsIsTag(hProfile, cmsSigRedColorantTag) && - cmsIsTag(hProfile, cmsSigGreenColorantTag) && - cmsIsTag(hProfile, cmsSigBlueColorantTag) && - cmsIsTag(hProfile, cmsSigRedTRCTag) && - cmsIsTag(hProfile, cmsSigGreenTRCTag) && - cmsIsTag(hProfile, cmsSigBlueTRCTag)); - - default: - - return FALSE; - } -} - -// Returns TRUE if the intent is implemented as CLUT -cmsBool CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number UsedDirection) -{ - const cmsTagSignature* TagTable; - - // For devicelinks, the supported intent is that one stated in the header - if (cmsGetDeviceClass(hProfile) == cmsSigLinkClass) { - return (cmsGetHeaderRenderingIntent(hProfile) == Intent); - } - - switch (UsedDirection) { - - case LCMS_USED_AS_INPUT: TagTable = Device2PCS16; break; - case LCMS_USED_AS_OUTPUT:TagTable = PCS2Device16; break; - - // For proofing, we need rel. colorimetric in output. Let's do some recursion - case LCMS_USED_AS_PROOF: - return cmsIsIntentSupported(hProfile, Intent, LCMS_USED_AS_INPUT) && - cmsIsIntentSupported(hProfile, INTENT_RELATIVE_COLORIMETRIC, LCMS_USED_AS_OUTPUT); - - default: - cmsSignalError(cmsGetProfileContextID(hProfile), cmsERROR_RANGE, "Unexpected direction (%d)", UsedDirection); - return FALSE; - } - - return cmsIsTag(hProfile, TagTable[Intent]); - -} - - -// Return info about supported intents -cmsBool CMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, - cmsUInt32Number Intent, cmsUInt32Number UsedDirection) -{ - - if (cmsIsCLUT(hProfile, Intent, UsedDirection)) return TRUE; - - // Is there any matrix-shaper? If so, the intent is supported. This is a bit odd, since V2 matrix shaper - // does not fully support relative colorimetric because they cannot deal with non-zero black points, but - // many profiles claims that, and this is certainly not true for V4 profiles. Lets answer "yes" no matter - // the accuracy would be less than optimal in rel.col and v2 case. - - return cmsIsMatrixShaper(hProfile); -} - - -// --------------------------------------------------------------------------------------------------------------- - -// Read both, profile sequence description and profile sequence id if present. Then combine both to -// create qa unique structure holding both. Shame on ICC to store things in such complicated way. -cmsSEQ* _cmsReadProfileSequence(cmsHPROFILE hProfile) -{ - cmsSEQ* ProfileSeq; - cmsSEQ* ProfileId; - cmsSEQ* NewSeq; - cmsUInt32Number i; - - // Take profile sequence description first - ProfileSeq = (cmsSEQ*) cmsReadTag(hProfile, cmsSigProfileSequenceDescTag); - - // Take profile sequence ID - ProfileId = (cmsSEQ*) cmsReadTag(hProfile, cmsSigProfileSequenceIdTag); - - if (ProfileSeq == NULL && ProfileId == NULL) return NULL; - - if (ProfileSeq == NULL) return cmsDupProfileSequenceDescription(ProfileId); - if (ProfileId == NULL) return cmsDupProfileSequenceDescription(ProfileSeq); - - // We have to mix both together. For that they must agree - if (ProfileSeq ->n != ProfileId ->n) return cmsDupProfileSequenceDescription(ProfileSeq); - - NewSeq = cmsDupProfileSequenceDescription(ProfileSeq); - - // Ok, proceed to the mixing - if (NewSeq != NULL) { - for (i=0; i < ProfileSeq ->n; i++) { - - memmove(&NewSeq ->seq[i].ProfileID, &ProfileId ->seq[i].ProfileID, sizeof(cmsProfileID)); - NewSeq ->seq[i].Description = cmsMLUdup(ProfileId ->seq[i].Description); - } - } - return NewSeq; -} - -// Dump the contents of profile sequence in both tags (if v4 available) -cmsBool _cmsWriteProfileSequence(cmsHPROFILE hProfile, const cmsSEQ* seq) -{ - if (!cmsWriteTag(hProfile, cmsSigProfileSequenceDescTag, seq)) return FALSE; - - if (cmsGetProfileVersion(hProfile) >= 4.0) { - - if (!cmsWriteTag(hProfile, cmsSigProfileSequenceIdTag, seq)) return FALSE; - } - - return TRUE; -} - - -// Auxiliar, read and duplicate a MLU if found. -static -cmsMLU* GetMLUFromProfile(cmsHPROFILE h, cmsTagSignature sig) -{ - cmsMLU* mlu = (cmsMLU*) cmsReadTag(h, sig); - if (mlu == NULL) return NULL; - - return cmsMLUdup(mlu); -} - -// Create a sequence description out of an array of profiles -cmsSEQ* _cmsCompileProfileSequence(cmsContext ContextID, cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[]) -{ - cmsUInt32Number i; - cmsSEQ* seq = cmsAllocProfileSequenceDescription(ContextID, nProfiles); - - if (seq == NULL) return NULL; - - for (i=0; i < nProfiles; i++) { - - cmsPSEQDESC* ps = &seq ->seq[i]; - cmsHPROFILE h = hProfiles[i]; - cmsTechnologySignature* techpt; - - cmsGetHeaderAttributes(h, &ps ->attributes); - cmsGetHeaderProfileID(h, ps ->ProfileID.ID8); - ps ->deviceMfg = cmsGetHeaderManufacturer(h); - ps ->deviceModel = cmsGetHeaderModel(h); - - techpt = (cmsTechnologySignature*) cmsReadTag(h, cmsSigTechnologyTag); - if (techpt == NULL) - ps ->technology = (cmsTechnologySignature) 0; - else - ps ->technology = *techpt; - - ps ->Manufacturer = GetMLUFromProfile(h, cmsSigDeviceMfgDescTag); - ps ->Model = GetMLUFromProfile(h, cmsSigDeviceModelDescTag); - ps ->Description = GetMLUFromProfile(h, cmsSigProfileDescriptionTag); - - } - - return seq; -} - -// ------------------------------------------------------------------------------------------------------------------- - - -static -const cmsMLU* GetInfo(cmsHPROFILE hProfile, cmsInfoType Info) -{ - cmsTagSignature sig; - - switch (Info) { - - case cmsInfoDescription: - sig = cmsSigProfileDescriptionTag; - break; - - case cmsInfoManufacturer: - sig = cmsSigDeviceMfgDescTag; - break; - - case cmsInfoModel: - sig = cmsSigDeviceModelDescTag; - break; - - case cmsInfoCopyright: - sig = cmsSigCopyrightTag; - break; - - default: return NULL; - } - - - return (cmsMLU*) cmsReadTag(hProfile, sig); -} - - - -cmsUInt32Number CMSEXPORT cmsGetProfileInfo(cmsHPROFILE hProfile, cmsInfoType Info, - const char LanguageCode[3], const char CountryCode[3], - wchar_t* Buffer, cmsUInt32Number BufferSize) -{ - const cmsMLU* mlu = GetInfo(hProfile, Info); - if (mlu == NULL) return 0; - - return cmsMLUgetWide(mlu, LanguageCode, CountryCode, Buffer, BufferSize); -} - - -cmsUInt32Number CMSEXPORT cmsGetProfileInfoASCII(cmsHPROFILE hProfile, cmsInfoType Info, - const char LanguageCode[3], const char CountryCode[3], - char* Buffer, cmsUInt32Number BufferSize) -{ - const cmsMLU* mlu = GetInfo(hProfile, Info); - if (mlu == NULL) return 0; - - return cmsMLUgetASCII(mlu, LanguageCode, CountryCode, Buffer, BufferSize); -} diff --git a/third_party/lcms2-2.6/src/cmslut.c b/third_party/lcms2-2.6/src/cmslut.c deleted file mode 100644 index 19d43361f0..0000000000 --- a/third_party/lcms2-2.6/src/cmslut.c +++ /dev/null @@ -1,1820 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- -// - -#include "lcms2_internal.h" - - -// Allocates an empty multi profile element -cmsStage* CMSEXPORT _cmsStageAllocPlaceholder(cmsContext ContextID, - cmsStageSignature Type, - cmsUInt32Number InputChannels, - cmsUInt32Number OutputChannels, - _cmsStageEvalFn EvalPtr, - _cmsStageDupElemFn DupElemPtr, - _cmsStageFreeElemFn FreePtr, - void* Data) -{ - cmsStage* ph = (cmsStage*) _cmsMallocZero(ContextID, sizeof(cmsStage)); - - if (ph == NULL) return NULL; - - - ph ->ContextID = ContextID; - - ph ->Type = Type; - ph ->Implements = Type; // By default, no clue on what is implementing - - ph ->InputChannels = InputChannels; - ph ->OutputChannels = OutputChannels; - ph ->EvalPtr = EvalPtr; - ph ->DupElemPtr = DupElemPtr; - ph ->FreePtr = FreePtr; - ph ->Data = Data; - - return ph; -} - - -static -void EvaluateIdentity(const cmsFloat32Number In[], - cmsFloat32Number Out[], - const cmsStage *mpe) -{ - memmove(Out, In, mpe ->InputChannels * sizeof(cmsFloat32Number)); -} - - -cmsStage* CMSEXPORT cmsStageAllocIdentity(cmsContext ContextID, cmsUInt32Number nChannels) -{ - return _cmsStageAllocPlaceholder(ContextID, - cmsSigIdentityElemType, - nChannels, nChannels, - EvaluateIdentity, - NULL, - NULL, - NULL); - } - -// Conversion functions. From floating point to 16 bits -static -void FromFloatTo16(const cmsFloat32Number In[], cmsUInt16Number Out[], cmsUInt32Number n) -{ - cmsUInt32Number i; - - for (i=0; i < n; i++) { - Out[i] = _cmsQuickSaturateWord(In[i] * 65535.0); - } -} - -// From 16 bits to floating point -static -void From16ToFloat(const cmsUInt16Number In[], cmsFloat32Number Out[], cmsUInt32Number n) -{ - cmsUInt32Number i; - - for (i=0; i < n; i++) { - Out[i] = (cmsFloat32Number) In[i] / 65535.0F; - } -} - - -// This function is quite useful to analyze the structure of a LUT and retrieve the MPE elements -// that conform the LUT. It should be called with the LUT, the number of expected elements and -// then a list of expected types followed with a list of cmsFloat64Number pointers to MPE elements. If -// the function founds a match with current pipeline, it fills the pointers and returns TRUE -// if not, returns FALSE without touching anything. Setting pointers to NULL does bypass -// the storage process. -cmsBool CMSEXPORT cmsPipelineCheckAndRetreiveStages(const cmsPipeline* Lut, cmsUInt32Number n, ...) -{ - va_list args; - cmsUInt32Number i; - cmsStage* mpe; - cmsStageSignature Type; - void** ElemPtr; - - // Make sure same number of elements - if (cmsPipelineStageCount(Lut) != n) return FALSE; - - va_start(args, n); - - // Iterate across asked types - mpe = Lut ->Elements; - for (i=0; i < n; i++) { - - // Get asked type - Type = (cmsStageSignature)va_arg(args, cmsStageSignature); - if (mpe ->Type != Type) { - - va_end(args); // Mismatch. We are done. - return FALSE; - } - mpe = mpe ->Next; - } - - // Found a combination, fill pointers if not NULL - mpe = Lut ->Elements; - for (i=0; i < n; i++) { - - ElemPtr = va_arg(args, void**); - if (ElemPtr != NULL) - *ElemPtr = mpe; - - mpe = mpe ->Next; - } - - va_end(args); - return TRUE; -} - -// Below there are implementations for several types of elements. Each type may be implemented by a -// evaluation function, a duplication function, a function to free resources and a constructor. - -// ************************************************************************************************* -// Type cmsSigCurveSetElemType (curves) -// ************************************************************************************************* - -cmsToneCurve** _cmsStageGetPtrToCurveSet(const cmsStage* mpe) -{ - _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) mpe ->Data; - - return Data ->TheCurves; -} - -static -void EvaluateCurves(const cmsFloat32Number In[], - cmsFloat32Number Out[], - const cmsStage *mpe) -{ - _cmsStageToneCurvesData* Data; - cmsUInt32Number i; - - _cmsAssert(mpe != NULL); - - Data = (_cmsStageToneCurvesData*) mpe ->Data; - if (Data == NULL) return; - - if (Data ->TheCurves == NULL) return; - - for (i=0; i < Data ->nCurves; i++) { - Out[i] = cmsEvalToneCurveFloat(Data ->TheCurves[i], In[i]); - } -} - -static -void CurveSetElemTypeFree(cmsStage* mpe) -{ - _cmsStageToneCurvesData* Data; - cmsUInt32Number i; - - _cmsAssert(mpe != NULL); - - Data = (_cmsStageToneCurvesData*) mpe ->Data; - if (Data == NULL) return; - - if (Data ->TheCurves != NULL) { - for (i=0; i < Data ->nCurves; i++) { - if (Data ->TheCurves[i] != NULL) - cmsFreeToneCurve(Data ->TheCurves[i]); - } - } - _cmsFree(mpe ->ContextID, Data ->TheCurves); - _cmsFree(mpe ->ContextID, Data); -} - - -static -void* CurveSetDup(cmsStage* mpe) -{ - _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) mpe ->Data; - _cmsStageToneCurvesData* NewElem; - cmsUInt32Number i; - - NewElem = (_cmsStageToneCurvesData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageToneCurvesData)); - if (NewElem == NULL) return NULL; - - NewElem ->nCurves = Data ->nCurves; - NewElem ->TheCurves = (cmsToneCurve**) _cmsCalloc(mpe ->ContextID, NewElem ->nCurves, sizeof(cmsToneCurve*)); - - if (NewElem ->TheCurves == NULL) goto Error; - - for (i=0; i < NewElem ->nCurves; i++) { - - // Duplicate each curve. It may fail. - NewElem ->TheCurves[i] = cmsDupToneCurve(Data ->TheCurves[i]); - if (NewElem ->TheCurves[i] == NULL) goto Error; - - - } - return (void*) NewElem; - -Error: - - if (NewElem ->TheCurves != NULL) { - for (i=0; i < NewElem ->nCurves; i++) { - if (NewElem ->TheCurves[i]) - cmsFreeToneCurve(NewElem ->TheCurves[i]); - } - } - _cmsFree(mpe ->ContextID, NewElem ->TheCurves); - _cmsFree(mpe ->ContextID, NewElem); - return NULL; -} - - -// Curves == NULL forces identity curves -cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Number nChannels, cmsToneCurve* const Curves[]) -{ - cmsUInt32Number i; - _cmsStageToneCurvesData* NewElem; - cmsStage* NewMPE; - - - NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCurveSetElemType, nChannels, nChannels, - EvaluateCurves, CurveSetDup, CurveSetElemTypeFree, NULL ); - if (NewMPE == NULL) return NULL; - - NewElem = (_cmsStageToneCurvesData*) _cmsMallocZero(ContextID, sizeof(_cmsStageToneCurvesData)); - if (NewElem == NULL) { - cmsStageFree(NewMPE); - return NULL; - } - - NewMPE ->Data = (void*) NewElem; - - NewElem ->nCurves = nChannels; - NewElem ->TheCurves = (cmsToneCurve**) _cmsCalloc(ContextID, nChannels, sizeof(cmsToneCurve*)); - if (NewElem ->TheCurves == NULL) { - cmsStageFree(NewMPE); - return NULL; - } - - for (i=0; i < nChannels; i++) { - - if (Curves == NULL) { - NewElem ->TheCurves[i] = cmsBuildGamma(ContextID, 1.0); - } - else { - NewElem ->TheCurves[i] = cmsDupToneCurve(Curves[i]); - } - - if (NewElem ->TheCurves[i] == NULL) { - cmsStageFree(NewMPE); - return NULL; - } - - } - - return NewMPE; -} - - -// Create a bunch of identity curves -cmsStage* _cmsStageAllocIdentityCurves(cmsContext ContextID, int nChannels) -{ - cmsStage* mpe = cmsStageAllocToneCurves(ContextID, nChannels, NULL); - - if (mpe == NULL) return NULL; - mpe ->Implements = cmsSigIdentityElemType; - return mpe; -} - - -// ************************************************************************************************* -// Type cmsSigMatrixElemType (Matrices) -// ************************************************************************************************* - - -// Special care should be taken here because precision loss. A temporary cmsFloat64Number buffer is being used -static -void EvaluateMatrix(const cmsFloat32Number In[], - cmsFloat32Number Out[], - const cmsStage *mpe) -{ - cmsUInt32Number i, j; - _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data; - cmsFloat64Number Tmp; - - // Input is already in 0..1.0 notation - for (i=0; i < mpe ->OutputChannels; i++) { - - Tmp = 0; - for (j=0; j < mpe->InputChannels; j++) { - Tmp += In[j] * Data->Double[i*mpe->InputChannels + j]; - } - - if (Data ->Offset != NULL) - Tmp += Data->Offset[i]; - - Out[i] = (cmsFloat32Number) Tmp; - } - - - // Output in 0..1.0 domain -} - - -// Duplicate a yet-existing matrix element -static -void* MatrixElemDup(cmsStage* mpe) -{ - _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data; - _cmsStageMatrixData* NewElem; - cmsUInt32Number sz; - - NewElem = (_cmsStageMatrixData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageMatrixData)); - if (NewElem == NULL) return NULL; - - sz = mpe ->InputChannels * mpe ->OutputChannels; - - NewElem ->Double = (cmsFloat64Number*) _cmsDupMem(mpe ->ContextID, Data ->Double, sz * sizeof(cmsFloat64Number)) ; - - if (Data ->Offset) - NewElem ->Offset = (cmsFloat64Number*) _cmsDupMem(mpe ->ContextID, - Data ->Offset, mpe -> OutputChannels * sizeof(cmsFloat64Number)) ; - - return (void*) NewElem; -} - - -static -void MatrixElemTypeFree(cmsStage* mpe) -{ - _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data; - if (Data == NULL) - return; - if (Data ->Double) - _cmsFree(mpe ->ContextID, Data ->Double); - - if (Data ->Offset) - _cmsFree(mpe ->ContextID, Data ->Offset); - - _cmsFree(mpe ->ContextID, mpe ->Data); -} - - - -cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number Rows, cmsUInt32Number Cols, - const cmsFloat64Number* Matrix, const cmsFloat64Number* Offset) -{ - cmsUInt32Number i, n; - _cmsStageMatrixData* NewElem; - cmsStage* NewMPE; - - n = Rows * Cols; - - // Check for overflow - if (n == 0) return NULL; - if (n >= UINT_MAX / Cols) return NULL; - if (n >= UINT_MAX / Rows) return NULL; - if (n < Rows || n < Cols) return NULL; - - NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigMatrixElemType, Cols, Rows, - EvaluateMatrix, MatrixElemDup, MatrixElemTypeFree, NULL ); - if (NewMPE == NULL) return NULL; - - - NewElem = (_cmsStageMatrixData*) _cmsMallocZero(ContextID, sizeof(_cmsStageMatrixData)); - if (NewElem == NULL) return NULL; - - - NewElem ->Double = (cmsFloat64Number*) _cmsCalloc(ContextID, n, sizeof(cmsFloat64Number)); - - if (NewElem->Double == NULL) { - MatrixElemTypeFree(NewMPE); - return NULL; - } - - for (i=0; i < n; i++) { - NewElem ->Double[i] = Matrix[i]; - } - - - if (Offset != NULL) { - - NewElem ->Offset = (cmsFloat64Number*) _cmsCalloc(ContextID, Rows, sizeof(cmsFloat64Number)); - if (NewElem->Offset == NULL) { - MatrixElemTypeFree(NewMPE); - return NULL; - } - - for (i=0; i < Rows; i++) { - NewElem ->Offset[i] = Offset[i]; - } - - } - - NewMPE ->Data = (void*) NewElem; - return NewMPE; -} - - -// ************************************************************************************************* -// Type cmsSigCLutElemType -// ************************************************************************************************* - - -// Evaluate in true floating point -static -void EvaluateCLUTfloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) -{ - _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; - - Data -> Params ->Interpolation.LerpFloat(In, Out, Data->Params); -} - - -// Convert to 16 bits, evaluate, and back to floating point -static -void EvaluateCLUTfloatIn16(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) -{ - _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; - cmsUInt16Number In16[MAX_STAGE_CHANNELS], Out16[MAX_STAGE_CHANNELS]; - - _cmsAssert(mpe ->InputChannels <= MAX_STAGE_CHANNELS); - _cmsAssert(mpe ->OutputChannels <= MAX_STAGE_CHANNELS); - - FromFloatTo16(In, In16, mpe ->InputChannels); - Data -> Params ->Interpolation.Lerp16(In16, Out16, Data->Params); - From16ToFloat(Out16, Out, mpe ->OutputChannels); -} - - -// Given an hypercube of b dimensions, with Dims[] number of nodes by dimension, calculate the total amount of nodes -static -cmsUInt32Number CubeSize(const cmsUInt32Number Dims[], cmsUInt32Number b) -{ - cmsUInt32Number rv, dim; - - _cmsAssert(Dims != NULL); - - for (rv = 1; b > 0; b--) { - - dim = Dims[b-1]; - if (dim == 0) return 0; // Error - - rv *= dim; - - // Check for overflow - if (rv > UINT_MAX / dim) return 0; - } - - return rv; -} - -static -void* CLUTElemDup(cmsStage* mpe) -{ - _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; - _cmsStageCLutData* NewElem; - - - NewElem = (_cmsStageCLutData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageCLutData)); - if (NewElem == NULL) return NULL; - - NewElem ->nEntries = Data ->nEntries; - NewElem ->HasFloatValues = Data ->HasFloatValues; - - if (Data ->Tab.T) { - - if (Data ->HasFloatValues) { - NewElem ->Tab.TFloat = (cmsFloat32Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.TFloat, Data ->nEntries * sizeof (cmsFloat32Number)); - if (NewElem ->Tab.TFloat == NULL) - goto Error; - } else { - NewElem ->Tab.T = (cmsUInt16Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.T, Data ->nEntries * sizeof (cmsUInt16Number)); - if (NewElem ->Tab.TFloat == NULL) - goto Error; - } - } - - NewElem ->Params = _cmsComputeInterpParamsEx(mpe ->ContextID, - Data ->Params ->nSamples, - Data ->Params ->nInputs, - Data ->Params ->nOutputs, - NewElem ->Tab.T, - Data ->Params ->dwFlags); - if (NewElem->Params != NULL) - return (void*) NewElem; - Error: - if (NewElem->Tab.T) - // This works for both types - _cmsFree(mpe ->ContextID, NewElem -> Tab.T); - _cmsFree(mpe ->ContextID, NewElem); - return NULL; -} - - -static -void CLutElemTypeFree(cmsStage* mpe) -{ - - _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; - - // Already empty - if (Data == NULL) return; - - // This works for both types - if (Data -> Tab.T) - _cmsFree(mpe ->ContextID, Data -> Tab.T); - - _cmsFreeInterpParams(Data ->Params); - _cmsFree(mpe ->ContextID, mpe ->Data); -} - - -// Allocates a 16-bit multidimensional CLUT. This is evaluated at 16-bit precision. Table may have different -// granularity on each dimension. -cmsStage* CMSEXPORT cmsStageAllocCLut16bitGranular(cmsContext ContextID, - const cmsUInt32Number clutPoints[], - cmsUInt32Number inputChan, - cmsUInt32Number outputChan, - const cmsUInt16Number* Table) -{ - cmsUInt32Number i, n; - _cmsStageCLutData* NewElem; - cmsStage* NewMPE; - - _cmsAssert(clutPoints != NULL); - - if (inputChan > MAX_INPUT_DIMENSIONS) { - cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", inputChan, MAX_INPUT_DIMENSIONS); - return NULL; - } - - NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCLutElemType, inputChan, outputChan, - EvaluateCLUTfloatIn16, CLUTElemDup, CLutElemTypeFree, NULL ); - - if (NewMPE == NULL) return NULL; - - NewElem = (_cmsStageCLutData*) _cmsMallocZero(ContextID, sizeof(_cmsStageCLutData)); - if (NewElem == NULL) { - cmsStageFree(NewMPE); - return NULL; - } - - NewMPE ->Data = (void*) NewElem; - - NewElem -> nEntries = n = outputChan * CubeSize(clutPoints, inputChan); - NewElem -> HasFloatValues = FALSE; - - if (n == 0) { - cmsStageFree(NewMPE); - return NULL; - } - - - NewElem ->Tab.T = (cmsUInt16Number*) _cmsCalloc(ContextID, n, sizeof(cmsUInt16Number)); - if (NewElem ->Tab.T == NULL) { - cmsStageFree(NewMPE); - return NULL; - } - - if (Table != NULL) { - for (i=0; i < n; i++) { - NewElem ->Tab.T[i] = Table[i]; - } - } - - NewElem ->Params = _cmsComputeInterpParamsEx(ContextID, clutPoints, inputChan, outputChan, NewElem ->Tab.T, CMS_LERP_FLAGS_16BITS); - if (NewElem ->Params == NULL) { - cmsStageFree(NewMPE); - return NULL; - } - - return NewMPE; -} - -cmsStage* CMSEXPORT cmsStageAllocCLut16bit(cmsContext ContextID, - cmsUInt32Number nGridPoints, - cmsUInt32Number inputChan, - cmsUInt32Number outputChan, - const cmsUInt16Number* Table) -{ - cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; - int i; - - // Our resulting LUT would be same gridpoints on all dimensions - for (i=0; i < MAX_INPUT_DIMENSIONS; i++) - Dimensions[i] = nGridPoints; - - return cmsStageAllocCLut16bitGranular(ContextID, Dimensions, inputChan, outputChan, Table); -} - - -cmsStage* CMSEXPORT cmsStageAllocCLutFloat(cmsContext ContextID, - cmsUInt32Number nGridPoints, - cmsUInt32Number inputChan, - cmsUInt32Number outputChan, - const cmsFloat32Number* Table) -{ - cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; - int i; - - // Our resulting LUT would be same gridpoints on all dimensions - for (i=0; i < MAX_INPUT_DIMENSIONS; i++) - Dimensions[i] = nGridPoints; - - return cmsStageAllocCLutFloatGranular(ContextID, Dimensions, inputChan, outputChan, Table); -} - - - -cmsStage* CMSEXPORT cmsStageAllocCLutFloatGranular(cmsContext ContextID, const cmsUInt32Number clutPoints[], cmsUInt32Number inputChan, cmsUInt32Number outputChan, const cmsFloat32Number* Table) -{ - cmsUInt32Number i, n; - _cmsStageCLutData* NewElem; - cmsStage* NewMPE; - - _cmsAssert(clutPoints != NULL); - - if (inputChan > MAX_INPUT_DIMENSIONS) { - cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", inputChan, MAX_INPUT_DIMENSIONS); - return NULL; - } - - NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCLutElemType, inputChan, outputChan, - EvaluateCLUTfloat, CLUTElemDup, CLutElemTypeFree, NULL); - if (NewMPE == NULL) return NULL; - - - NewElem = (_cmsStageCLutData*) _cmsMallocZero(ContextID, sizeof(_cmsStageCLutData)); - if (NewElem == NULL) { - cmsStageFree(NewMPE); - return NULL; - } - - NewMPE ->Data = (void*) NewElem; - - // There is a potential integer overflow on conputing n and nEntries. - NewElem -> nEntries = n = outputChan * CubeSize(clutPoints, inputChan); - NewElem -> HasFloatValues = TRUE; - - if (n == 0) { - cmsStageFree(NewMPE); - return NULL; - } - - NewElem ->Tab.TFloat = (cmsFloat32Number*) _cmsCalloc(ContextID, n, sizeof(cmsFloat32Number)); - if (NewElem ->Tab.TFloat == NULL) { - cmsStageFree(NewMPE); - return NULL; - } - - if (Table != NULL) { - for (i=0; i < n; i++) { - NewElem ->Tab.TFloat[i] = Table[i]; - } - } - - NewElem ->Params = _cmsComputeInterpParamsEx(ContextID, clutPoints, inputChan, outputChan, NewElem ->Tab.TFloat, CMS_LERP_FLAGS_FLOAT); - if (NewElem ->Params == NULL) { - cmsStageFree(NewMPE); - return NULL; - } - - return NewMPE; -} - - -static -int IdentitySampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void * Cargo) -{ - int nChan = *(int*) Cargo; - int i; - - for (i=0; i < nChan; i++) - Out[i] = In[i]; - - return 1; -} - -// Creates an MPE that just copies input to output -cmsStage* _cmsStageAllocIdentityCLut(cmsContext ContextID, int nChan) -{ - cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; - cmsStage* mpe ; - int i; - - for (i=0; i < MAX_INPUT_DIMENSIONS; i++) - Dimensions[i] = 2; - - mpe = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, nChan, nChan, NULL); - if (mpe == NULL) return NULL; - - if (!cmsStageSampleCLut16bit(mpe, IdentitySampler, &nChan, 0)) { - cmsStageFree(mpe); - return NULL; - } - - mpe ->Implements = cmsSigIdentityElemType; - return mpe; -} - - - -// Quantize a value 0 <= i < MaxSamples to 0..0xffff -cmsUInt16Number _cmsQuantizeVal(cmsFloat64Number i, int MaxSamples) -{ - cmsFloat64Number x; - - x = ((cmsFloat64Number) i * 65535.) / (cmsFloat64Number) (MaxSamples - 1); - return _cmsQuickSaturateWord(x); -} - - -// This routine does a sweep on whole input space, and calls its callback -// function on knots. returns TRUE if all ok, FALSE otherwise. -cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, void * Cargo, cmsUInt32Number dwFlags) -{ - int i, t, nTotalPoints, index, rest; - int nInputs, nOutputs; - cmsUInt32Number* nSamples; - cmsUInt16Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS]; - _cmsStageCLutData* clut; - - if (mpe == NULL) return FALSE; - - clut = (_cmsStageCLutData*) mpe->Data; - - if (clut == NULL) return FALSE; - - nSamples = clut->Params ->nSamples; - nInputs = clut->Params ->nInputs; - nOutputs = clut->Params ->nOutputs; - - if (nInputs <= 0) return FALSE; - if (nOutputs <= 0) return FALSE; - if (nInputs > MAX_INPUT_DIMENSIONS) return FALSE; - if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE; - - nTotalPoints = CubeSize(nSamples, nInputs); - if (nTotalPoints == 0) return FALSE; - - index = 0; - for (i = 0; i < nTotalPoints; i++) { - - rest = i; - for (t = nInputs-1; t >=0; --t) { - - cmsUInt32Number Colorant = rest % nSamples[t]; - - rest /= nSamples[t]; - - In[t] = _cmsQuantizeVal(Colorant, nSamples[t]); - } - - if (clut ->Tab.T != NULL) { - for (t=0; t < nOutputs; t++) - Out[t] = clut->Tab.T[index + t]; - } - - if (!Sampler(In, Out, Cargo)) - return FALSE; - - if (!(dwFlags & SAMPLER_INSPECT)) { - - if (clut ->Tab.T != NULL) { - for (t=0; t < nOutputs; t++) - clut->Tab.T[index + t] = Out[t]; - } - } - - index += nOutputs; - } - - return TRUE; -} - -// Same as anterior, but for floting point -cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler, void * Cargo, cmsUInt32Number dwFlags) -{ - int i, t, nTotalPoints, index, rest; - int nInputs, nOutputs; - cmsUInt32Number* nSamples; - cmsFloat32Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS]; - _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data; - - nSamples = clut->Params ->nSamples; - nInputs = clut->Params ->nInputs; - nOutputs = clut->Params ->nOutputs; - - if (nInputs <= 0) return FALSE; - if (nOutputs <= 0) return FALSE; - if (nInputs > MAX_INPUT_DIMENSIONS) return FALSE; - if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE; - - nTotalPoints = CubeSize(nSamples, nInputs); - if (nTotalPoints == 0) return FALSE; - - index = 0; - for (i = 0; i < nTotalPoints; i++) { - - rest = i; - for (t = nInputs-1; t >=0; --t) { - - cmsUInt32Number Colorant = rest % nSamples[t]; - - rest /= nSamples[t]; - - In[t] = (cmsFloat32Number) (_cmsQuantizeVal(Colorant, nSamples[t]) / 65535.0); - } - - if (clut ->Tab.TFloat != NULL) { - for (t=0; t < nOutputs; t++) - Out[t] = clut->Tab.TFloat[index + t]; - } - - if (!Sampler(In, Out, Cargo)) - return FALSE; - - if (!(dwFlags & SAMPLER_INSPECT)) { - - if (clut ->Tab.TFloat != NULL) { - for (t=0; t < nOutputs; t++) - clut->Tab.TFloat[index + t] = Out[t]; - } - } - - index += nOutputs; - } - - return TRUE; -} - - - -// This routine does a sweep on whole input space, and calls its callback -// function on knots. returns TRUE if all ok, FALSE otherwise. -cmsBool CMSEXPORT cmsSliceSpace16(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[], - cmsSAMPLER16 Sampler, void * Cargo) -{ - int i, t, nTotalPoints, rest; - cmsUInt16Number In[cmsMAXCHANNELS]; - - if (nInputs >= cmsMAXCHANNELS) return FALSE; - - nTotalPoints = CubeSize(clutPoints, nInputs); - if (nTotalPoints == 0) return FALSE; - - for (i = 0; i < nTotalPoints; i++) { - - rest = i; - for (t = nInputs-1; t >=0; --t) { - - cmsUInt32Number Colorant = rest % clutPoints[t]; - - rest /= clutPoints[t]; - In[t] = _cmsQuantizeVal(Colorant, clutPoints[t]); - - } - - if (!Sampler(In, NULL, Cargo)) - return FALSE; - } - - return TRUE; -} - -cmsInt32Number CMSEXPORT cmsSliceSpaceFloat(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[], - cmsSAMPLERFLOAT Sampler, void * Cargo) -{ - int i, t, nTotalPoints, rest; - cmsFloat32Number In[cmsMAXCHANNELS]; - - if (nInputs >= cmsMAXCHANNELS) return FALSE; - - nTotalPoints = CubeSize(clutPoints, nInputs); - if (nTotalPoints == 0) return FALSE; - - for (i = 0; i < nTotalPoints; i++) { - - rest = i; - for (t = nInputs-1; t >=0; --t) { - - cmsUInt32Number Colorant = rest % clutPoints[t]; - - rest /= clutPoints[t]; - In[t] = (cmsFloat32Number) (_cmsQuantizeVal(Colorant, clutPoints[t]) / 65535.0); - - } - - if (!Sampler(In, NULL, Cargo)) - return FALSE; - } - - return TRUE; -} - -// ******************************************************************************** -// Type cmsSigLab2XYZElemType -// ******************************************************************************** - - -static -void EvaluateLab2XYZ(const cmsFloat32Number In[], - cmsFloat32Number Out[], - const cmsStage *mpe) -{ - cmsCIELab Lab; - cmsCIEXYZ XYZ; - const cmsFloat64Number XYZadj = MAX_ENCODEABLE_XYZ; - - // V4 rules - Lab.L = In[0] * 100.0; - Lab.a = In[1] * 255.0 - 128.0; - Lab.b = In[2] * 255.0 - 128.0; - - cmsLab2XYZ(NULL, &XYZ, &Lab); - - // From XYZ, range 0..19997 to 0..1.0, note that 1.99997 comes from 0xffff - // encoded as 1.15 fixed point, so 1 + (32767.0 / 32768.0) - - Out[0] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.X / XYZadj); - Out[1] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Y / XYZadj); - Out[2] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Z / XYZadj); - return; - - cmsUNUSED_PARAMETER(mpe); -} - - -// No dup or free routines needed, as the structure has no pointers in it. -cmsStage* _cmsStageAllocLab2XYZ(cmsContext ContextID) -{ - return _cmsStageAllocPlaceholder(ContextID, cmsSigLab2XYZElemType, 3, 3, EvaluateLab2XYZ, NULL, NULL, NULL); -} - -// ******************************************************************************** - -// v2 L=100 is supposed to be placed on 0xFF00. There is no reasonable -// number of gridpoints that would make exact match. However, a prelinearization -// of 258 entries, would map 0xFF00 exactly on entry 257, and this is good to avoid scum dot. -// Almost all what we need but unfortunately, the rest of entries should be scaled by -// (255*257/256) and this is not exact. - -cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID) -{ - cmsStage* mpe; - cmsToneCurve* LabTable[3]; - int i, j; - - LabTable[0] = cmsBuildTabulatedToneCurve16(ContextID, 258, NULL); - LabTable[1] = cmsBuildTabulatedToneCurve16(ContextID, 258, NULL); - LabTable[2] = cmsBuildTabulatedToneCurve16(ContextID, 258, NULL); - - for (j=0; j < 3; j++) { - - if (LabTable[j] == NULL) { - cmsFreeToneCurveTriple(LabTable); - return NULL; - } - - // We need to map * (0xffff / 0xff00), thats same as (257 / 256) - // So we can use 258-entry tables to do the trick (i / 257) * (255 * 257) * (257 / 256); - for (i=0; i < 257; i++) { - - LabTable[j]->Table16[i] = (cmsUInt16Number) ((i * 0xffff + 0x80) >> 8); - } - - LabTable[j] ->Table16[257] = 0xffff; - } - - mpe = cmsStageAllocToneCurves(ContextID, 3, LabTable); - cmsFreeToneCurveTriple(LabTable); - - if (mpe == NULL) return NULL; - mpe ->Implements = cmsSigLabV2toV4; - return mpe; -} - -// ******************************************************************************** - -// Matrix-based conversion, which is more accurate, but slower and cannot properly be saved in devicelink profiles -cmsStage* _cmsStageAllocLabV2ToV4(cmsContext ContextID) -{ - static const cmsFloat64Number V2ToV4[] = { 65535.0/65280.0, 0, 0, - 0, 65535.0/65280.0, 0, - 0, 0, 65535.0/65280.0 - }; - - cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, V2ToV4, NULL); - - if (mpe == NULL) return mpe; - mpe ->Implements = cmsSigLabV2toV4; - return mpe; -} - - -// Reverse direction -cmsStage* _cmsStageAllocLabV4ToV2(cmsContext ContextID) -{ - static const cmsFloat64Number V4ToV2[] = { 65280.0/65535.0, 0, 0, - 0, 65280.0/65535.0, 0, - 0, 0, 65280.0/65535.0 - }; - - cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, V4ToV2, NULL); - - if (mpe == NULL) return mpe; - mpe ->Implements = cmsSigLabV4toV2; - return mpe; -} - - -// To Lab to float. Note that the MPE gives numbers in normal Lab range -// and we need 0..1.0 range for the formatters -// L* : 0...100 => 0...1.0 (L* / 100) -// ab* : -128..+127 to 0..1 ((ab* + 128) / 255) - -cmsStage* _cmsStageNormalizeFromLabFloat(cmsContext ContextID) -{ - static const cmsFloat64Number a1[] = { - 1.0/100.0, 0, 0, - 0, 1.0/255.0, 0, - 0, 0, 1.0/255.0 - }; - - static const cmsFloat64Number o1[] = { - 0, - 128.0/255.0, - 128.0/255.0 - }; - - cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, o1); - - if (mpe == NULL) return mpe; - mpe ->Implements = cmsSigLab2FloatPCS; - return mpe; -} - -// Fom XYZ to floating point PCS -cmsStage* _cmsStageNormalizeFromXyzFloat(cmsContext ContextID) -{ -#define n (32768.0/65535.0) - static const cmsFloat64Number a1[] = { - n, 0, 0, - 0, n, 0, - 0, 0, n - }; -#undef n - - cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, NULL); - - if (mpe == NULL) return mpe; - mpe ->Implements = cmsSigXYZ2FloatPCS; - return mpe; -} - -cmsStage* _cmsStageNormalizeToLabFloat(cmsContext ContextID) -{ - static const cmsFloat64Number a1[] = { - 100.0, 0, 0, - 0, 255.0, 0, - 0, 0, 255.0 - }; - - static const cmsFloat64Number o1[] = { - 0, - -128.0, - -128.0 - }; - - cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, o1); - if (mpe == NULL) return mpe; - mpe ->Implements = cmsSigFloatPCS2Lab; - return mpe; -} - -cmsStage* _cmsStageNormalizeToXyzFloat(cmsContext ContextID) -{ -#define n (65535.0/32768.0) - - static const cmsFloat64Number a1[] = { - n, 0, 0, - 0, n, 0, - 0, 0, n - }; -#undef n - - cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, NULL); - if (mpe == NULL) return mpe; - mpe ->Implements = cmsSigFloatPCS2XYZ; - return mpe; -} - - - -// ******************************************************************************** -// Type cmsSigXYZ2LabElemType -// ******************************************************************************** - -static -void EvaluateXYZ2Lab(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) -{ - cmsCIELab Lab; - cmsCIEXYZ XYZ; - const cmsFloat64Number XYZadj = MAX_ENCODEABLE_XYZ; - - // From 0..1.0 to XYZ - - XYZ.X = In[0] * XYZadj; - XYZ.Y = In[1] * XYZadj; - XYZ.Z = In[2] * XYZadj; - - cmsXYZ2Lab(NULL, &Lab, &XYZ); - - // From V4 Lab to 0..1.0 - - Out[0] = (cmsFloat32Number) (Lab.L / 100.0); - Out[1] = (cmsFloat32Number) ((Lab.a + 128.0) / 255.0); - Out[2] = (cmsFloat32Number) ((Lab.b + 128.0) / 255.0); - return; - - cmsUNUSED_PARAMETER(mpe); -} - -cmsStage* _cmsStageAllocXYZ2Lab(cmsContext ContextID) -{ - return _cmsStageAllocPlaceholder(ContextID, cmsSigXYZ2LabElemType, 3, 3, EvaluateXYZ2Lab, NULL, NULL, NULL); - -} - -// ******************************************************************************** - -// For v4, S-Shaped curves are placed in a/b axis to increase resolution near gray - -cmsStage* _cmsStageAllocLabPrelin(cmsContext ContextID) -{ - cmsToneCurve* LabTable[3]; - cmsFloat64Number Params[1] = {2.4} ; - - LabTable[0] = cmsBuildGamma(ContextID, 1.0); - LabTable[1] = cmsBuildParametricToneCurve(ContextID, 108, Params); - LabTable[2] = cmsBuildParametricToneCurve(ContextID, 108, Params); - - return cmsStageAllocToneCurves(ContextID, 3, LabTable); -} - - -// Free a single MPE -void CMSEXPORT cmsStageFree(cmsStage* mpe) -{ - if (mpe ->FreePtr) - mpe ->FreePtr(mpe); - - _cmsFree(mpe ->ContextID, mpe); -} - - -cmsUInt32Number CMSEXPORT cmsStageInputChannels(const cmsStage* mpe) -{ - return mpe ->InputChannels; -} - -cmsUInt32Number CMSEXPORT cmsStageOutputChannels(const cmsStage* mpe) -{ - return mpe ->OutputChannels; -} - -cmsStageSignature CMSEXPORT cmsStageType(const cmsStage* mpe) -{ - return mpe -> Type; -} - -void* CMSEXPORT cmsStageData(const cmsStage* mpe) -{ - return mpe -> Data; -} - -cmsStage* CMSEXPORT cmsStageNext(const cmsStage* mpe) -{ - return mpe -> Next; -} - - -// Duplicates an MPE -cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe) -{ - cmsStage* NewMPE; - - if (mpe == NULL) return NULL; - NewMPE = _cmsStageAllocPlaceholder(mpe ->ContextID, - mpe ->Type, - mpe ->InputChannels, - mpe ->OutputChannels, - mpe ->EvalPtr, - mpe ->DupElemPtr, - mpe ->FreePtr, - NULL); - if (NewMPE == NULL) return NULL; - - NewMPE ->Implements = mpe ->Implements; - - if (mpe ->DupElemPtr) { - - NewMPE ->Data = mpe ->DupElemPtr(mpe); - - if (NewMPE->Data == NULL) { - - cmsStageFree(NewMPE); - return NULL; - } - - } else { - - NewMPE ->Data = NULL; - } - - return NewMPE; -} - - -// *********************************************************************************************************** - -// This function sets up the channel count -static -cmsBool BlessLUT(cmsPipeline* lut) -{ - // We can set the input/ouput channels only if we have elements. - if (lut ->Elements != NULL) { - - cmsStage* prev; - cmsStage* next; - cmsStage* First; - cmsStage* Last; - - First = cmsPipelineGetPtrToFirstStage(lut); - Last = cmsPipelineGetPtrToLastStage(lut); - - if (First == NULL || Last == NULL) return FALSE; - - lut->InputChannels = First->InputChannels; - lut->OutputChannels = Last->OutputChannels; - - // Check chain consistency - prev = First; - next = prev->Next; - - while (next != NULL) - { - if (next->InputChannels != prev->OutputChannels) - return FALSE; - - next = next->Next; - prev = prev->Next; - } - } - return TRUE; -} - - -// Default to evaluate the LUT on 16 bit-basis. Precision is retained. -static -void _LUTeval16(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register const void* D) -{ - cmsPipeline* lut = (cmsPipeline*) D; - cmsStage *mpe; - cmsFloat32Number Storage[2][MAX_STAGE_CHANNELS] = {0.0f}; - int Phase = 0, NextPhase; - - From16ToFloat(In, &Storage[Phase][0], lut ->InputChannels); - - for (mpe = lut ->Elements; - mpe != NULL; - mpe = mpe ->Next) { - - NextPhase = Phase ^ 1; - mpe ->EvalPtr(&Storage[Phase][0], &Storage[NextPhase][0], mpe); - Phase = NextPhase; - } - - - FromFloatTo16(&Storage[Phase][0], Out, lut ->OutputChannels); -} - - - -// Does evaluate the LUT on cmsFloat32Number-basis. -static -void _LUTevalFloat(register const cmsFloat32Number In[], register cmsFloat32Number Out[], const void* D) -{ - cmsPipeline* lut = (cmsPipeline*) D; - cmsStage *mpe; - cmsFloat32Number Storage[2][MAX_STAGE_CHANNELS] = {0.0f}; - int Phase = 0, NextPhase; - - memmove(&Storage[Phase][0], In, lut ->InputChannels * sizeof(cmsFloat32Number)); - - for (mpe = lut ->Elements; - mpe != NULL; - mpe = mpe ->Next) { - - NextPhase = Phase ^ 1; - mpe ->EvalPtr(&Storage[Phase][0], &Storage[NextPhase][0], mpe); - Phase = NextPhase; - } - - memmove(Out, &Storage[Phase][0], lut ->OutputChannels * sizeof(cmsFloat32Number)); -} - - - - -// LUT Creation & Destruction - -cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number InputChannels, cmsUInt32Number OutputChannels) -{ - cmsPipeline* NewLUT; - - // A value of zero in channels is allowed as placeholder - if (InputChannels >= cmsMAXCHANNELS || - OutputChannels >= cmsMAXCHANNELS) return NULL; - - NewLUT = (cmsPipeline*) _cmsMallocZero(ContextID, sizeof(cmsPipeline)); - if (NewLUT == NULL) return NULL; - - - NewLUT -> InputChannels = InputChannels; - NewLUT -> OutputChannels = OutputChannels; - - NewLUT ->Eval16Fn = _LUTeval16; - NewLUT ->EvalFloatFn = _LUTevalFloat; - NewLUT ->DupDataFn = NULL; - NewLUT ->FreeDataFn = NULL; - NewLUT ->Data = NewLUT; - NewLUT ->ContextID = ContextID; - - if (!BlessLUT(NewLUT)) - { - _cmsFree(ContextID, NewLUT); - return NULL; - } - - return NewLUT; -} - -cmsContext CMSEXPORT cmsGetPipelineContextID(const cmsPipeline* lut) -{ - _cmsAssert(lut != NULL); - return lut ->ContextID; -} - -cmsUInt32Number CMSEXPORT cmsPipelineInputChannels(const cmsPipeline* lut) -{ - _cmsAssert(lut != NULL); - return lut ->InputChannels; -} - -cmsUInt32Number CMSEXPORT cmsPipelineOutputChannels(const cmsPipeline* lut) -{ - _cmsAssert(lut != NULL); - return lut ->OutputChannels; -} - -// Free a profile elements LUT -void CMSEXPORT cmsPipelineFree(cmsPipeline* lut) -{ - cmsStage *mpe, *Next; - - if (lut == NULL) return; - - for (mpe = lut ->Elements; - mpe != NULL; - mpe = Next) { - - Next = mpe ->Next; - cmsStageFree(mpe); - } - - if (lut ->FreeDataFn) lut ->FreeDataFn(lut ->ContextID, lut ->Data); - - _cmsFree(lut ->ContextID, lut); -} - - -// Default to evaluate the LUT on 16 bit-basis. -void CMSEXPORT cmsPipelineEval16(const cmsUInt16Number In[], cmsUInt16Number Out[], const cmsPipeline* lut) -{ - _cmsAssert(lut != NULL); - lut ->Eval16Fn(In, Out, lut->Data); -} - - -// Does evaluate the LUT on cmsFloat32Number-basis. -void CMSEXPORT cmsPipelineEvalFloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsPipeline* lut) -{ - _cmsAssert(lut != NULL); - lut ->EvalFloatFn(In, Out, lut); -} - - - -// Duplicates a LUT -cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut) -{ - cmsPipeline* NewLUT; - cmsStage *NewMPE, *Anterior = NULL, *mpe; - cmsBool First = TRUE; - - if (lut == NULL) return NULL; - - NewLUT = cmsPipelineAlloc(lut ->ContextID, lut ->InputChannels, lut ->OutputChannels); - if (NewLUT == NULL) return NULL; - - for (mpe = lut ->Elements; - mpe != NULL; - mpe = mpe ->Next) { - - NewMPE = cmsStageDup(mpe); - - if (NewMPE == NULL) { - cmsPipelineFree(NewLUT); - return NULL; - } - - if (First) { - NewLUT ->Elements = NewMPE; - First = FALSE; - } - else { - Anterior ->Next = NewMPE; - } - - Anterior = NewMPE; - } - - NewLUT ->Eval16Fn = lut ->Eval16Fn; - NewLUT ->EvalFloatFn = lut ->EvalFloatFn; - NewLUT ->DupDataFn = lut ->DupDataFn; - NewLUT ->FreeDataFn = lut ->FreeDataFn; - - if (NewLUT ->DupDataFn != NULL) - NewLUT ->Data = NewLUT ->DupDataFn(lut ->ContextID, lut->Data); - - - NewLUT ->SaveAs8Bits = lut ->SaveAs8Bits; - - if (!BlessLUT(NewLUT)) - { - _cmsFree(lut->ContextID, NewLUT); - return NULL; - } - - return NewLUT; -} - - -int CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe) -{ - cmsStage* Anterior = NULL, *pt; - - if (lut == NULL || mpe == NULL) - return FALSE; - - switch (loc) { - - case cmsAT_BEGIN: - mpe ->Next = lut ->Elements; - lut ->Elements = mpe; - break; - - case cmsAT_END: - - if (lut ->Elements == NULL) - lut ->Elements = mpe; - else { - - for (pt = lut ->Elements; - pt != NULL; - pt = pt -> Next) Anterior = pt; - - Anterior ->Next = mpe; - mpe ->Next = NULL; - } - break; - default:; - return FALSE; - } - - return BlessLUT(lut); -} - -// Unlink an element and return the pointer to it -void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage** mpe) -{ - cmsStage *Anterior, *pt, *Last; - cmsStage *Unlinked = NULL; - - - // If empty LUT, there is nothing to remove - if (lut ->Elements == NULL) { - if (mpe) *mpe = NULL; - return; - } - - // On depending on the strategy... - switch (loc) { - - case cmsAT_BEGIN: - { - cmsStage* elem = lut ->Elements; - - lut ->Elements = elem -> Next; - elem ->Next = NULL; - Unlinked = elem; - - } - break; - - case cmsAT_END: - Anterior = Last = NULL; - for (pt = lut ->Elements; - pt != NULL; - pt = pt -> Next) { - Anterior = Last; - Last = pt; - } - - Unlinked = Last; // Next already points to NULL - - // Truncate the chain - if (Anterior) - Anterior ->Next = NULL; - else - lut ->Elements = NULL; - break; - default:; - } - - if (mpe) - *mpe = Unlinked; - else - cmsStageFree(Unlinked); - - // May fail, but we ignore it - BlessLUT(lut); -} - - -// Concatenate two LUT into a new single one -cmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2) -{ - cmsStage* mpe; - - // If both LUTS does not have elements, we need to inherit - // the number of channels - if (l1 ->Elements == NULL && l2 ->Elements == NULL) { - l1 ->InputChannels = l2 ->InputChannels; - l1 ->OutputChannels = l2 ->OutputChannels; - } - - // Cat second - for (mpe = l2 ->Elements; - mpe != NULL; - mpe = mpe ->Next) { - - // We have to dup each element - if (!cmsPipelineInsertStage(l1, cmsAT_END, cmsStageDup(mpe))) - return FALSE; - } - - return BlessLUT(l1); -} - - -cmsBool CMSEXPORT cmsPipelineSetSaveAs8bitsFlag(cmsPipeline* lut, cmsBool On) -{ - cmsBool Anterior = lut ->SaveAs8Bits; - - lut ->SaveAs8Bits = On; - return Anterior; -} - - -cmsStage* CMSEXPORT cmsPipelineGetPtrToFirstStage(const cmsPipeline* lut) -{ - return lut ->Elements; -} - -cmsStage* CMSEXPORT cmsPipelineGetPtrToLastStage(const cmsPipeline* lut) -{ - cmsStage *mpe, *Anterior = NULL; - - for (mpe = lut ->Elements; mpe != NULL; mpe = mpe ->Next) - Anterior = mpe; - - return Anterior; -} - -cmsUInt32Number CMSEXPORT cmsPipelineStageCount(const cmsPipeline* lut) -{ - cmsStage *mpe; - cmsUInt32Number n; - - for (n=0, mpe = lut ->Elements; mpe != NULL; mpe = mpe ->Next) - n++; - - return n; -} - -// This function may be used to set the optional evaluator and a block of private data. If private data is being used, an optional -// duplicator and free functions should also be specified in order to duplicate the LUT construct. Use NULL to inhibit such functionality. -void CMSEXPORT _cmsPipelineSetOptimizationParameters(cmsPipeline* Lut, - _cmsOPTeval16Fn Eval16, - void* PrivateData, - _cmsFreeUserDataFn FreePrivateDataFn, - _cmsDupUserDataFn DupPrivateDataFn) -{ - - Lut ->Eval16Fn = Eval16; - Lut ->DupDataFn = DupPrivateDataFn; - Lut ->FreeDataFn = FreePrivateDataFn; - Lut ->Data = PrivateData; -} - - -// ----------------------------------------------------------- Reverse interpolation -// Here's how it goes. The derivative Df(x) of the function f is the linear -// transformation that best approximates f near the point x. It can be represented -// by a matrix A whose entries are the partial derivatives of the components of f -// with respect to all the coordinates. This is know as the Jacobian -// -// The best linear approximation to f is given by the matrix equation: -// -// y-y0 = A (x-x0) -// -// So, if x0 is a good "guess" for the zero of f, then solving for the zero of this -// linear approximation will give a "better guess" for the zero of f. Thus let y=0, -// and since y0=f(x0) one can solve the above equation for x. This leads to the -// Newton's method formula: -// -// xn+1 = xn - A-1 f(xn) -// -// where xn+1 denotes the (n+1)-st guess, obtained from the n-th guess xn in the -// fashion described above. Iterating this will give better and better approximations -// if you have a "good enough" initial guess. - - -#define JACOBIAN_EPSILON 0.001f -#define INVERSION_MAX_ITERATIONS 30 - -// Increment with reflexion on boundary -static -void IncDelta(cmsFloat32Number *Val) -{ - if (*Val < (1.0 - JACOBIAN_EPSILON)) - - *Val += JACOBIAN_EPSILON; - - else - *Val -= JACOBIAN_EPSILON; - -} - - - -// Euclidean distance between two vectors of n elements each one -static -cmsFloat32Number EuclideanDistance(cmsFloat32Number a[], cmsFloat32Number b[], int n) -{ - cmsFloat32Number sum = 0; - int i; - - for (i=0; i < n; i++) { - cmsFloat32Number dif = b[i] - a[i]; - sum += dif * dif; - } - - return sqrtf(sum); -} - - -// Evaluate a LUT in reverse direction. It only searches on 3->3 LUT. Uses Newton method -// -// x1 <- x - [J(x)]^-1 * f(x) -// -// lut: The LUT on where to do the search -// Target: LabK, 3 values of Lab plus destination K which is fixed -// Result: The obtained CMYK -// Hint: Location where begin the search - -cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], - cmsFloat32Number Result[], - cmsFloat32Number Hint[], - const cmsPipeline* lut) -{ - cmsUInt32Number i, j; - cmsFloat64Number error, LastError = 1E20; - cmsFloat32Number fx[4], x[4], xd[4], fxd[4]; - cmsVEC3 tmp, tmp2; - cmsMAT3 Jacobian; - - // Only 3->3 and 4->3 are supported - if (lut ->InputChannels != 3 && lut ->InputChannels != 4) return FALSE; - if (lut ->OutputChannels != 3) return FALSE; - - // Take the hint as starting point if specified - if (Hint == NULL) { - - // Begin at any point, we choose 1/3 of CMY axis - x[0] = x[1] = x[2] = 0.3f; - } - else { - - // Only copy 3 channels from hint... - for (j=0; j < 3; j++) - x[j] = Hint[j]; - } - - // If Lut is 4-dimensions, then grab target[3], which is fixed - if (lut ->InputChannels == 4) { - x[3] = Target[3]; - } - else x[3] = 0; // To keep lint happy - - - // Iterate - for (i = 0; i < INVERSION_MAX_ITERATIONS; i++) { - - // Get beginning fx - cmsPipelineEvalFloat(x, fx, lut); - - // Compute error - error = EuclideanDistance(fx, Target, 3); - - // If not convergent, return last safe value - if (error >= LastError) - break; - - // Keep latest values - LastError = error; - for (j=0; j < lut ->InputChannels; j++) - Result[j] = x[j]; - - // Found an exact match? - if (error <= 0) - break; - - // Obtain slope (the Jacobian) - for (j = 0; j < 3; j++) { - - xd[0] = x[0]; - xd[1] = x[1]; - xd[2] = x[2]; - xd[3] = x[3]; // Keep fixed channel - - IncDelta(&xd[j]); - - cmsPipelineEvalFloat(xd, fxd, lut); - - Jacobian.v[0].n[j] = ((fxd[0] - fx[0]) / JACOBIAN_EPSILON); - Jacobian.v[1].n[j] = ((fxd[1] - fx[1]) / JACOBIAN_EPSILON); - Jacobian.v[2].n[j] = ((fxd[2] - fx[2]) / JACOBIAN_EPSILON); - } - - // Solve system - tmp2.n[0] = fx[0] - Target[0]; - tmp2.n[1] = fx[1] - Target[1]; - tmp2.n[2] = fx[2] - Target[2]; - - if (!_cmsMAT3solve(&tmp, &Jacobian, &tmp2)) - return FALSE; - - // Move our guess - x[0] -= (cmsFloat32Number) tmp.n[0]; - x[1] -= (cmsFloat32Number) tmp.n[1]; - x[2] -= (cmsFloat32Number) tmp.n[2]; - - // Some clipping.... - for (j=0; j < 3; j++) { - if (x[j] < 0) x[j] = 0; - else - if (x[j] > 1.0) x[j] = 1.0; - } - } - - return TRUE; -} diff --git a/third_party/lcms2-2.6/src/cmsmd5.c b/third_party/lcms2-2.6/src/cmsmd5.c deleted file mode 100644 index a4758ff662..0000000000 --- a/third_party/lcms2-2.6/src/cmsmd5.c +++ /dev/null @@ -1,343 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- - -#include "lcms2_internal.h" - -#ifdef CMS_USE_BIG_ENDIAN - -static -void byteReverse(cmsUInt8Number * buf, cmsUInt32Number longs) -{ - do { - - cmsUInt32Number t = _cmsAdjustEndianess32(*(cmsUInt32Number *) buf); - *(cmsUInt32Number *) buf = t; - buf += sizeof(cmsUInt32Number); - - } while (--longs); - -} - -#else -#define byteReverse(buf, len) -#endif - - -typedef struct { - - cmsUInt32Number buf[4]; - cmsUInt32Number bits[2]; - cmsUInt8Number in[64]; - cmsContext ContextID; - -} _cmsMD5; - -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -#define STEP(f, w, x, y, z, data, s) \ - ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) - - -static -void MD5_Transform(cmsUInt32Number buf[4], cmsUInt32Number in[16]) - -{ - register cmsUInt32Number a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); - STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); - STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); - STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); - STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); - STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); - STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); - STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); - STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); - STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); - STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); - STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); - STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); - STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); - STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); - STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); - - STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); - STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); - STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); - STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); - STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); - STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); - STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); - STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); - STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); - STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); - STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); - STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); - STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); - STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); - STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); - STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); - - STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); - STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); - STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); - STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); - STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); - STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); - STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); - STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); - STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); - STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); - STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); - STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); - STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); - STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); - STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); - STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); - - STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); - STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); - STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); - STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); - STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); - STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); - STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); - STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); - STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); - STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); - STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); - STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); - STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); - STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); - STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); - STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} - - -// Create a MD5 object -static -cmsHANDLE MD5alloc(cmsContext ContextID) -{ - _cmsMD5* ctx = (_cmsMD5*) _cmsMallocZero(ContextID, sizeof(_cmsMD5)); - if (ctx == NULL) return NULL; - - ctx ->ContextID = ContextID; - - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; - - ctx->bits[0] = 0; - ctx->bits[1] = 0; - - return (cmsHANDLE) ctx; -} - - -static -void MD5add(cmsHANDLE Handle, cmsUInt8Number* buf, cmsUInt32Number len) -{ - _cmsMD5* ctx = (_cmsMD5*) Handle; - cmsUInt32Number t; - - t = ctx->bits[0]; - if ((ctx->bits[0] = t + (len << 3)) < t) - ctx->bits[1]++; - - ctx->bits[1] += len >> 29; - - t = (t >> 3) & 0x3f; - - if (t) { - - cmsUInt8Number *p = (cmsUInt8Number *) ctx->in + t; - - t = 64 - t; - if (len < t) { - memmove(p, buf, len); - return; - } - - memmove(p, buf, t); - byteReverse(ctx->in, 16); - - MD5_Transform(ctx->buf, (cmsUInt32Number *) ctx->in); - buf += t; - len -= t; - } - - while (len >= 64) { - memmove(ctx->in, buf, 64); - byteReverse(ctx->in, 16); - MD5_Transform(ctx->buf, (cmsUInt32Number *) ctx->in); - buf += 64; - len -= 64; - } - - memmove(ctx->in, buf, len); -} - -// Destroy the object and return the checksum -static -void MD5finish(cmsProfileID* ProfileID, cmsHANDLE Handle) -{ - _cmsMD5* ctx = (_cmsMD5*) Handle; - cmsUInt32Number count; - cmsUInt8Number *p; - - count = (ctx->bits[0] >> 3) & 0x3F; - - p = ctx->in + count; - *p++ = 0x80; - - count = 64 - 1 - count; - - if (count < 8) { - - memset(p, 0, count); - byteReverse(ctx->in, 16); - MD5_Transform(ctx->buf, (cmsUInt32Number *) ctx->in); - - memset(ctx->in, 0, 56); - } else { - memset(p, 0, count - 8); - } - byteReverse(ctx->in, 14); - - ((cmsUInt32Number *) ctx->in)[14] = ctx->bits[0]; - ((cmsUInt32Number *) ctx->in)[15] = ctx->bits[1]; - - MD5_Transform(ctx->buf, (cmsUInt32Number *) ctx->in); - - byteReverse((cmsUInt8Number *) ctx->buf, 4); - memmove(ProfileID ->ID8, ctx->buf, 16); - - _cmsFree(ctx ->ContextID, ctx); -} - - - -// Assuming io points to an ICC profile, compute and store MD5 checksum -// In the header, rendering intentent, attributes and ID should be set to zero -// before computing MD5 checksum (per 6.1.13 in ICC spec) - -cmsBool CMSEXPORT cmsMD5computeID(cmsHPROFILE hProfile) -{ - cmsContext ContextID; - cmsUInt32Number BytesNeeded; - cmsUInt8Number* Mem = NULL; - cmsHANDLE MD5 = NULL; - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - _cmsICCPROFILE Keep; - - _cmsAssert(hProfile != NULL); - - ContextID = cmsGetProfileContextID(hProfile); - - // Save a copy of the profile header - memmove(&Keep, Icc, sizeof(_cmsICCPROFILE)); - - // Set RI, attributes and ID - memset(&Icc ->attributes, 0, sizeof(Icc ->attributes)); - Icc ->RenderingIntent = 0; - memset(&Icc ->ProfileID, 0, sizeof(Icc ->ProfileID)); - - // Compute needed storage - if (!cmsSaveProfileToMem(hProfile, NULL, &BytesNeeded)) goto Error; - - // Allocate memory - Mem = (cmsUInt8Number*) _cmsMalloc(ContextID, BytesNeeded); - if (Mem == NULL) goto Error; - - // Save to temporary storage - if (!cmsSaveProfileToMem(hProfile, Mem, &BytesNeeded)) goto Error; - - // Create MD5 object - MD5 = MD5alloc(ContextID); - if (MD5 == NULL) goto Error; - - // Add all bytes - MD5add(MD5, Mem, BytesNeeded); - - // Temp storage is no longer needed - _cmsFree(ContextID, Mem); - - // Restore header - memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); - - // And store the ID - MD5finish(&Icc ->ProfileID, MD5); - return TRUE; - -Error: - - // Free resources as something went wrong - // "MD5" cannot be other than NULL here, so no need to free it - if (Mem != NULL) _cmsFree(ContextID, Mem); - memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); - return FALSE; -} - -cmsBool CMSEXPORT cmsMD5computeIDExt(const void* buf, unsigned long size, unsigned char ProfileID[16]) -{ - cmsHANDLE MD5; - cmsUInt8Number* Mem; - - if (buf == NULL) - return FALSE; - MD5 = NULL; - Mem = (cmsUInt8Number*)_cmsMalloc(NULL,size); - memmove(Mem,buf,size); - // Create MD5 object - MD5 = MD5alloc(NULL); - if (MD5 == NULL) goto Error; - - // Add all bytes - MD5add(MD5, Mem, size); - - // Temp storage is no longer needed - _cmsFree(NULL, Mem); - - // And store the ID - MD5finish((cmsProfileID*)ProfileID, MD5); - return TRUE; -Error: - if (MD5 != NULL) _cmsFree(NULL, MD5); - return FALSE; -} diff --git a/third_party/lcms2-2.6/src/cmsmtrx.c b/third_party/lcms2-2.6/src/cmsmtrx.c deleted file mode 100644 index fb7b91caf1..0000000000 --- a/third_party/lcms2-2.6/src/cmsmtrx.c +++ /dev/null @@ -1,175 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- -// - -#include "lcms2_internal.h" - - -#define DSWAP(x, y) {cmsFloat64Number tmp = (x); (x)=(y); (y)=tmp;} - - -// Initiate a vector -void CMSEXPORT _cmsVEC3init(cmsVEC3* r, cmsFloat64Number x, cmsFloat64Number y, cmsFloat64Number z) -{ - r -> n[VX] = x; - r -> n[VY] = y; - r -> n[VZ] = z; -} - -// Vector substraction -void CMSEXPORT _cmsVEC3minus(cmsVEC3* r, const cmsVEC3* a, const cmsVEC3* b) -{ - r -> n[VX] = a -> n[VX] - b -> n[VX]; - r -> n[VY] = a -> n[VY] - b -> n[VY]; - r -> n[VZ] = a -> n[VZ] - b -> n[VZ]; -} - -// Vector cross product -void CMSEXPORT _cmsVEC3cross(cmsVEC3* r, const cmsVEC3* u, const cmsVEC3* v) -{ - r ->n[VX] = u->n[VY] * v->n[VZ] - v->n[VY] * u->n[VZ]; - r ->n[VY] = u->n[VZ] * v->n[VX] - v->n[VZ] * u->n[VX]; - r ->n[VZ] = u->n[VX] * v->n[VY] - v->n[VX] * u->n[VY]; -} - -// Vector dot product -cmsFloat64Number CMSEXPORT _cmsVEC3dot(const cmsVEC3* u, const cmsVEC3* v) -{ - return u->n[VX] * v->n[VX] + u->n[VY] * v->n[VY] + u->n[VZ] * v->n[VZ]; -} - -// Euclidean length -cmsFloat64Number CMSEXPORT _cmsVEC3length(const cmsVEC3* a) -{ - return sqrt(a ->n[VX] * a ->n[VX] + - a ->n[VY] * a ->n[VY] + - a ->n[VZ] * a ->n[VZ]); -} - -// Euclidean distance -cmsFloat64Number CMSEXPORT _cmsVEC3distance(const cmsVEC3* a, const cmsVEC3* b) -{ - cmsFloat64Number d1 = a ->n[VX] - b ->n[VX]; - cmsFloat64Number d2 = a ->n[VY] - b ->n[VY]; - cmsFloat64Number d3 = a ->n[VZ] - b ->n[VZ]; - - return sqrt(d1*d1 + d2*d2 + d3*d3); -} - - - -// 3x3 Identity -void CMSEXPORT _cmsMAT3identity(cmsMAT3* a) -{ - _cmsVEC3init(&a-> v[0], 1.0, 0.0, 0.0); - _cmsVEC3init(&a-> v[1], 0.0, 1.0, 0.0); - _cmsVEC3init(&a-> v[2], 0.0, 0.0, 1.0); -} - -static -cmsBool CloseEnough(cmsFloat64Number a, cmsFloat64Number b) -{ - return fabs(b - a) < (1.0 / 65535.0); -} - - -cmsBool CMSEXPORT _cmsMAT3isIdentity(const cmsMAT3* a) -{ - cmsMAT3 Identity; - int i, j; - - _cmsMAT3identity(&Identity); - - for (i=0; i < 3; i++) - for (j=0; j < 3; j++) - if (!CloseEnough(a ->v[i].n[j], Identity.v[i].n[j])) return FALSE; - - return TRUE; -} - - -// Multiply two matrices -void CMSEXPORT _cmsMAT3per(cmsMAT3* r, const cmsMAT3* a, const cmsMAT3* b) -{ -#define ROWCOL(i, j) \ - a->v[i].n[0]*b->v[0].n[j] + a->v[i].n[1]*b->v[1].n[j] + a->v[i].n[2]*b->v[2].n[j] - - _cmsVEC3init(&r-> v[0], ROWCOL(0,0), ROWCOL(0,1), ROWCOL(0,2)); - _cmsVEC3init(&r-> v[1], ROWCOL(1,0), ROWCOL(1,1), ROWCOL(1,2)); - _cmsVEC3init(&r-> v[2], ROWCOL(2,0), ROWCOL(2,1), ROWCOL(2,2)); - -#undef ROWCOL //(i, j) -} - - - -// Inverse of a matrix b = a^(-1) -cmsBool CMSEXPORT _cmsMAT3inverse(const cmsMAT3* a, cmsMAT3* b) -{ - cmsFloat64Number det, c0, c1, c2; - - c0 = a -> v[1].n[1]*a -> v[2].n[2] - a -> v[1].n[2]*a -> v[2].n[1]; - c1 = -a -> v[1].n[0]*a -> v[2].n[2] + a -> v[1].n[2]*a -> v[2].n[0]; - c2 = a -> v[1].n[0]*a -> v[2].n[1] - a -> v[1].n[1]*a -> v[2].n[0]; - - det = a -> v[0].n[0]*c0 + a -> v[0].n[1]*c1 + a -> v[0].n[2]*c2; - - if (fabs(det) < MATRIX_DET_TOLERANCE) return FALSE; // singular matrix; can't invert - - b -> v[0].n[0] = c0/det; - b -> v[0].n[1] = (a -> v[0].n[2]*a -> v[2].n[1] - a -> v[0].n[1]*a -> v[2].n[2])/det; - b -> v[0].n[2] = (a -> v[0].n[1]*a -> v[1].n[2] - a -> v[0].n[2]*a -> v[1].n[1])/det; - b -> v[1].n[0] = c1/det; - b -> v[1].n[1] = (a -> v[0].n[0]*a -> v[2].n[2] - a -> v[0].n[2]*a -> v[2].n[0])/det; - b -> v[1].n[2] = (a -> v[0].n[2]*a -> v[1].n[0] - a -> v[0].n[0]*a -> v[1].n[2])/det; - b -> v[2].n[0] = c2/det; - b -> v[2].n[1] = (a -> v[0].n[1]*a -> v[2].n[0] - a -> v[0].n[0]*a -> v[2].n[1])/det; - b -> v[2].n[2] = (a -> v[0].n[0]*a -> v[1].n[1] - a -> v[0].n[1]*a -> v[1].n[0])/det; - - return TRUE; -} - - -// Solve a system in the form Ax = b -cmsBool CMSEXPORT _cmsMAT3solve(cmsVEC3* x, cmsMAT3* a, cmsVEC3* b) -{ - cmsMAT3 m, a_1; - - memmove(&m, a, sizeof(cmsMAT3)); - - if (!_cmsMAT3inverse(&m, &a_1)) return FALSE; // Singular matrix - - _cmsMAT3eval(x, &a_1, b); - return TRUE; -} - -// Evaluate a vector across a matrix -void CMSEXPORT _cmsMAT3eval(cmsVEC3* r, const cmsMAT3* a, const cmsVEC3* v) -{ - r->n[VX] = a->v[0].n[VX]*v->n[VX] + a->v[0].n[VY]*v->n[VY] + a->v[0].n[VZ]*v->n[VZ]; - r->n[VY] = a->v[1].n[VX]*v->n[VX] + a->v[1].n[VY]*v->n[VY] + a->v[1].n[VZ]*v->n[VZ]; - r->n[VZ] = a->v[2].n[VX]*v->n[VX] + a->v[2].n[VY]*v->n[VY] + a->v[2].n[VZ]*v->n[VZ]; -} - diff --git a/third_party/lcms2-2.6/src/cmsnamed.c b/third_party/lcms2-2.6/src/cmsnamed.c deleted file mode 100644 index ef1eb3089e..0000000000 --- a/third_party/lcms2-2.6/src/cmsnamed.c +++ /dev/null @@ -1,937 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- -// - -#include "lcms2_internal.h" - -// Multilocalized unicode objects. That is an attempt to encapsulate i18n. - - -// Allocates an empty multi localizad unicode object -cmsMLU* CMSEXPORT cmsMLUalloc(cmsContext ContextID, cmsUInt32Number nItems) -{ - cmsMLU* mlu; - - // nItems should be positive if given - if (nItems <= 0) nItems = 2; - - // Create the container - mlu = (cmsMLU*) _cmsMallocZero(ContextID, sizeof(cmsMLU)); - if (mlu == NULL) return NULL; - - mlu ->ContextID = ContextID; - - // Create entry array - mlu ->Entries = (_cmsMLUentry*) _cmsCalloc(ContextID, nItems, sizeof(_cmsMLUentry)); - if (mlu ->Entries == NULL) { - _cmsFree(ContextID, mlu); - return NULL; - } - - // Ok, keep indexes up to date - mlu ->AllocatedEntries = nItems; - mlu ->UsedEntries = 0; - - return mlu; -} - - -// Grows a mempool table for a MLU. Each time this function is called, mempool size is multiplied times two. -static -cmsBool GrowMLUpool(cmsMLU* mlu) -{ - cmsUInt32Number size; - void *NewPtr; - - // Sanity check - if (mlu == NULL) return FALSE; - - if (mlu ->PoolSize == 0) - size = 256; - else - size = mlu ->PoolSize * 2; - - // Check for overflow - if (size < mlu ->PoolSize) return FALSE; - - // Reallocate the pool - NewPtr = _cmsRealloc(mlu ->ContextID, mlu ->MemPool, size); - if (NewPtr == NULL) return FALSE; - - - mlu ->MemPool = NewPtr; - mlu ->PoolSize = size; - - return TRUE; -} - - -// Grows a entry table for a MLU. Each time this function is called, table size is multiplied times two. -static -cmsBool GrowMLUtable(cmsMLU* mlu) -{ - int AllocatedEntries; - _cmsMLUentry *NewPtr; - - // Sanity check - if (mlu == NULL) return FALSE; - - AllocatedEntries = mlu ->AllocatedEntries * 2; - - // Check for overflow - if (AllocatedEntries / 2 != mlu ->AllocatedEntries) return FALSE; - - // Reallocate the memory - NewPtr = (_cmsMLUentry*)_cmsRealloc(mlu ->ContextID, mlu ->Entries, AllocatedEntries*sizeof(_cmsMLUentry)); - if (NewPtr == NULL) return FALSE; - - mlu ->Entries = NewPtr; - mlu ->AllocatedEntries = AllocatedEntries; - - return TRUE; -} - - -// Search for a specific entry in the structure. Language and Country are used. -static -int SearchMLUEntry(cmsMLU* mlu, cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode) -{ - int i; - - // Sanity check - if (mlu == NULL) return -1; - - // Iterate whole table - for (i=0; i < mlu ->UsedEntries; i++) { - - if (mlu ->Entries[i].Country == CountryCode && - mlu ->Entries[i].Language == LanguageCode) return i; - } - - // Not found - return -1; -} - -// Add a block of characters to the intended MLU. Language and country are specified. -// Only one entry for Language/country pair is allowed. -static -cmsBool AddMLUBlock(cmsMLU* mlu, cmsUInt32Number size, const wchar_t *Block, - cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode) -{ - cmsUInt32Number Offset; - cmsUInt8Number* Ptr; - - // Sanity check - if (mlu == NULL) return FALSE; - - // Is there any room available? - if (mlu ->UsedEntries >= mlu ->AllocatedEntries) { - if (!GrowMLUtable(mlu)) return FALSE; - } - - // Only one ASCII string - if (SearchMLUEntry(mlu, LanguageCode, CountryCode) >= 0) return FALSE; // Only one is allowed! - - // Check for size - while ((mlu ->PoolSize - mlu ->PoolUsed) < size) { - - if (!GrowMLUpool(mlu)) return FALSE; - } - - Offset = mlu ->PoolUsed; - - Ptr = (cmsUInt8Number*) mlu ->MemPool; - if (Ptr == NULL) return FALSE; - - // Set the entry - memmove(Ptr + Offset, Block, size); - mlu ->PoolUsed += size; - - mlu ->Entries[mlu ->UsedEntries].StrW = Offset; - mlu ->Entries[mlu ->UsedEntries].Len = size; - mlu ->Entries[mlu ->UsedEntries].Country = CountryCode; - mlu ->Entries[mlu ->UsedEntries].Language = LanguageCode; - mlu ->UsedEntries++; - - return TRUE; -} - - -// Add an ASCII entry. -cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* ASCIIString) -{ - cmsUInt32Number i, len = (cmsUInt32Number) strlen(ASCIIString)+1; - wchar_t* WStr; - cmsBool rc; - cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode); - cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode); - - if (mlu == NULL) return FALSE; - - WStr = (wchar_t*) _cmsCalloc(mlu ->ContextID, len, sizeof(wchar_t)); - if (WStr == NULL) return FALSE; - - for (i=0; i < len; i++) - WStr[i] = (wchar_t) ASCIIString[i]; - - rc = AddMLUBlock(mlu, len * sizeof(wchar_t), WStr, Lang, Cntry); - - _cmsFree(mlu ->ContextID, WStr); - return rc; - -} - -// We don't need any wcs support library -static -cmsUInt32Number mywcslen(const wchar_t *s) -{ - const wchar_t *p; - - p = s; - while (*p) - p++; - - return (cmsUInt32Number)(p - s); -} - - -// Add a wide entry -cmsBool CMSEXPORT cmsMLUsetWide(cmsMLU* mlu, const char Language[3], const char Country[3], const wchar_t* WideString) -{ - cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) Language); - cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) Country); - cmsUInt32Number len; - - if (mlu == NULL) return FALSE; - if (WideString == NULL) return FALSE; - - len = (cmsUInt32Number) (mywcslen(WideString) + 1) * sizeof(wchar_t); - return AddMLUBlock(mlu, len, WideString, Lang, Cntry); -} - -// Duplicating a MLU is as easy as copying all members -cmsMLU* CMSEXPORT cmsMLUdup(const cmsMLU* mlu) -{ - cmsMLU* NewMlu = NULL; - - // Duplicating a NULL obtains a NULL - if (mlu == NULL) return NULL; - - NewMlu = cmsMLUalloc(mlu ->ContextID, mlu ->UsedEntries); - if (NewMlu == NULL) return NULL; - - // Should never happen - if (NewMlu ->AllocatedEntries < mlu ->UsedEntries) - goto Error; - - // Sanitize... - if (NewMlu ->Entries == NULL || mlu ->Entries == NULL) goto Error; - - memmove(NewMlu ->Entries, mlu ->Entries, mlu ->UsedEntries * sizeof(_cmsMLUentry)); - NewMlu ->UsedEntries = mlu ->UsedEntries; - - // The MLU may be empty - if (mlu ->PoolUsed == 0) { - NewMlu ->MemPool = NULL; - } - else { - // It is not empty - NewMlu ->MemPool = _cmsMalloc(mlu ->ContextID, mlu ->PoolUsed); - if (NewMlu ->MemPool == NULL) goto Error; - } - - NewMlu ->PoolSize = mlu ->PoolUsed; - - if (NewMlu ->MemPool == NULL || mlu ->MemPool == NULL) goto Error; - - memmove(NewMlu ->MemPool, mlu->MemPool, mlu ->PoolUsed); - NewMlu ->PoolUsed = mlu ->PoolUsed; - - return NewMlu; - -Error: - - if (NewMlu != NULL) cmsMLUfree(NewMlu); - return NULL; -} - -// Free any used memory -void CMSEXPORT cmsMLUfree(cmsMLU* mlu) -{ - if (mlu) { - - if (mlu -> Entries) _cmsFree(mlu ->ContextID, mlu->Entries); - if (mlu -> MemPool) _cmsFree(mlu ->ContextID, mlu->MemPool); - - _cmsFree(mlu ->ContextID, mlu); - } -} - - -// The algorithm first searches for an exact match of country and language, if not found it uses -// the Language. If none is found, first entry is used instead. -static -const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu, - cmsUInt32Number *len, - cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode, - cmsUInt16Number* UsedLanguageCode, cmsUInt16Number* UsedCountryCode) -{ - int i; - int Best = -1; - _cmsMLUentry* v; - - if (mlu == NULL) return NULL; - - if (mlu -> AllocatedEntries <= 0) return NULL; - - for (i=0; i < mlu ->UsedEntries; i++) { - - v = mlu ->Entries + i; - - if (v -> Language == LanguageCode) { - - if (Best == -1) Best = i; - - if (v -> Country == CountryCode) { - - if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language; - if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country; - - if (len != NULL) *len = v ->Len; - - return (wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v -> StrW); // Found exact match - } - } - } - - // No string found. Return First one - if (Best == -1) - Best = 0; - - v = mlu ->Entries + Best; - - if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language; - if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country; - - if (len != NULL) *len = v ->Len; - - return(wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v ->StrW); -} - - -// Obtain an ASCII representation of the wide string. Setting buffer to NULL returns the len -cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu, - const char LanguageCode[3], const char CountryCode[3], - char* Buffer, cmsUInt32Number BufferSize) -{ - const wchar_t *Wide; - cmsUInt32Number StrLen = 0; - cmsUInt32Number ASCIIlen, i; - - cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode); - cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode); - - // Sanitize - if (mlu == NULL) return 0; - - // Get WideChar - Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL); - if (Wide == NULL) return 0; - - ASCIIlen = StrLen / sizeof(wchar_t); - - // Maybe we want only to know the len? - if (Buffer == NULL) return ASCIIlen + 1; // Note the zero at the end - - // No buffer size means no data - if (BufferSize <= 0) return 0; - - // Some clipping may be required - if (BufferSize < ASCIIlen + 1) - ASCIIlen = BufferSize - 1; - - // Precess each character - for (i=0; i < ASCIIlen; i++) { - - if (Wide[i] == 0) - Buffer[i] = 0; - else - Buffer[i] = (char) Wide[i]; - } - - // We put a termination "\0" - Buffer[ASCIIlen] = 0; - return ASCIIlen + 1; -} - -// Obtain a wide representation of the MLU, on depending on current locale settings -cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu, - const char LanguageCode[3], const char CountryCode[3], - wchar_t* Buffer, cmsUInt32Number BufferSize) -{ - const wchar_t *Wide; - cmsUInt32Number StrLen = 0; - - cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode); - cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode); - - // Sanitize - if (mlu == NULL) return 0; - - Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL); - if (Wide == NULL) return 0; - - // Maybe we want only to know the len? - if (Buffer == NULL) return StrLen + sizeof(wchar_t); - - // No buffer size means no data - if (BufferSize <= 0) return 0; - - // Some clipping may be required - if (BufferSize < StrLen + sizeof(wchar_t)) - StrLen = BufferSize - + sizeof(wchar_t); - - memmove(Buffer, Wide, StrLen); - Buffer[StrLen / sizeof(wchar_t)] = 0; - - return StrLen + sizeof(wchar_t); -} - - -// Get also the language and country -CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu, - const char LanguageCode[3], const char CountryCode[3], - char ObtainedLanguage[3], char ObtainedCountry[3]) -{ - const wchar_t *Wide; - - cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode); - cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode); - cmsUInt16Number ObtLang, ObtCode; - - // Sanitize - if (mlu == NULL) return FALSE; - - Wide = _cmsMLUgetWide(mlu, NULL, Lang, Cntry, &ObtLang, &ObtCode); - if (Wide == NULL) return FALSE; - - // Get used language and code - *(cmsUInt16Number *)ObtainedLanguage = _cmsAdjustEndianess16(ObtLang); - *(cmsUInt16Number *)ObtainedCountry = _cmsAdjustEndianess16(ObtCode); - - ObtainedLanguage[2] = ObtainedCountry[2] = 0; - return TRUE; -} - - - -// Get the number of translations in the MLU object -cmsUInt32Number CMSEXPORT cmsMLUtranslationsCount(const cmsMLU* mlu) -{ - if (mlu == NULL) return 0; - return mlu->UsedEntries; -} - -// Get the language and country codes for a specific MLU index -cmsBool CMSEXPORT cmsMLUtranslationsCodes(const cmsMLU* mlu, - cmsUInt32Number idx, - char LanguageCode[3], - char CountryCode[3]) -{ - _cmsMLUentry *entry; - - if (mlu == NULL) return FALSE; - - if (idx >= (cmsUInt32Number) mlu->UsedEntries) return FALSE; - - entry = &mlu->Entries[idx]; - - *(cmsUInt16Number *)LanguageCode = _cmsAdjustEndianess16(entry->Language); - *(cmsUInt16Number *)CountryCode = _cmsAdjustEndianess16(entry->Country); - - return TRUE; -} - - -// Named color lists -------------------------------------------------------------------------------------------- - -// Grow the list to keep at least NumElements -static -cmsBool GrowNamedColorList(cmsNAMEDCOLORLIST* v) -{ - cmsUInt32Number size; - _cmsNAMEDCOLOR * NewPtr; - - if (v == NULL) return FALSE; - - if (v ->Allocated == 0) - size = 64; // Initial guess - else - size = v ->Allocated * 2; - - // Keep a maximum color lists can grow, 100K entries seems reasonable - if (size > 1024*100) return FALSE; - - NewPtr = (_cmsNAMEDCOLOR*) _cmsRealloc(v ->ContextID, v ->List, size * sizeof(_cmsNAMEDCOLOR)); - if (NewPtr == NULL) - return FALSE; - - v ->List = NewPtr; - v ->Allocated = size; - return TRUE; -} - -// Allocate a list for n elements -cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUInt32Number n, cmsUInt32Number ColorantCount, const char* Prefix, const char* Suffix) -{ - cmsNAMEDCOLORLIST* v = (cmsNAMEDCOLORLIST*) _cmsMallocZero(ContextID, sizeof(cmsNAMEDCOLORLIST)); - - if (v == NULL) return NULL; - - v ->List = NULL; - v ->nColors = 0; - v ->ContextID = ContextID; - - while (v -> Allocated < n) { - if (!GrowNamedColorList(v)) { - cmsFreeNamedColorList(v); - return NULL; - } - } - - strncpy(v ->Prefix, Prefix, sizeof(v ->Prefix)-1); - strncpy(v ->Suffix, Suffix, sizeof(v ->Suffix)-1); - v->Prefix[32] = v->Suffix[32] = 0; - - v -> ColorantCount = ColorantCount; - - return v; -} - -// Free a list -void CMSEXPORT cmsFreeNamedColorList(cmsNAMEDCOLORLIST* v) -{ - if (v == NULL) return; - if (v ->List) _cmsFree(v ->ContextID, v ->List); - _cmsFree(v ->ContextID, v); -} - -cmsNAMEDCOLORLIST* CMSEXPORT cmsDupNamedColorList(const cmsNAMEDCOLORLIST* v) -{ - cmsNAMEDCOLORLIST* NewNC; - - if (v == NULL) return NULL; - - NewNC= cmsAllocNamedColorList(v ->ContextID, v -> nColors, v ->ColorantCount, v ->Prefix, v ->Suffix); - if (NewNC == NULL) return NULL; - - // For really large tables we need this - while (NewNC ->Allocated < v ->Allocated) { - if (!GrowNamedColorList(NewNC)) { - cmsFreeNamedColorList(NewNC); - return NULL; - } - } - - memmove(NewNC ->Prefix, v ->Prefix, sizeof(v ->Prefix)); - memmove(NewNC ->Suffix, v ->Suffix, sizeof(v ->Suffix)); - NewNC ->ColorantCount = v ->ColorantCount; - memmove(NewNC->List, v ->List, v->nColors * sizeof(_cmsNAMEDCOLOR)); - NewNC ->nColors = v ->nColors; - return NewNC; -} - - -// Append a color to a list. List pointer may change if reallocated -cmsBool CMSEXPORT cmsAppendNamedColor(cmsNAMEDCOLORLIST* NamedColorList, - const char* Name, - cmsUInt16Number PCS[3], cmsUInt16Number Colorant[cmsMAXCHANNELS]) -{ - cmsUInt32Number i; - - if (NamedColorList == NULL) return FALSE; - - if (NamedColorList ->nColors + 1 > NamedColorList ->Allocated) { - if (!GrowNamedColorList(NamedColorList)) return FALSE; - } - - for (i=0; i < NamedColorList ->ColorantCount; i++) - NamedColorList ->List[NamedColorList ->nColors].DeviceColorant[i] = Colorant == NULL? 0 : Colorant[i]; - - for (i=0; i < 3; i++) - NamedColorList ->List[NamedColorList ->nColors].PCS[i] = PCS == NULL ? 0 : PCS[i]; - - if (Name != NULL) { - - strncpy(NamedColorList ->List[NamedColorList ->nColors].Name, Name, cmsMAX_PATH-1); - NamedColorList ->List[NamedColorList ->nColors].Name[cmsMAX_PATH-1] = 0; - - } - else - NamedColorList ->List[NamedColorList ->nColors].Name[0] = 0; - - - NamedColorList ->nColors++; - return TRUE; -} - -// Returns number of elements -cmsUInt32Number CMSEXPORT cmsNamedColorCount(const cmsNAMEDCOLORLIST* NamedColorList) -{ - if (NamedColorList == NULL) return 0; - return NamedColorList ->nColors; -} - -// Info aboout a given color -cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cmsUInt32Number nColor, - char* Name, - char* Prefix, - char* Suffix, - cmsUInt16Number* PCS, - cmsUInt16Number* Colorant) -{ - if (NamedColorList == NULL) return FALSE; - - if (nColor >= cmsNamedColorCount(NamedColorList)) return FALSE; - - if (Name) strcpy(Name, NamedColorList->List[nColor].Name); - if (Prefix) strcpy(Prefix, NamedColorList->Prefix); - if (Suffix) strcpy(Suffix, NamedColorList->Suffix); - if (PCS) - memmove(PCS, NamedColorList ->List[nColor].PCS, 3*sizeof(cmsUInt16Number)); - - if (Colorant) - memmove(Colorant, NamedColorList ->List[nColor].DeviceColorant, - sizeof(cmsUInt16Number) * NamedColorList ->ColorantCount); - - - return TRUE; -} - -// Search for a given color name (no prefix or suffix) -cmsInt32Number CMSEXPORT cmsNamedColorIndex(const cmsNAMEDCOLORLIST* NamedColorList, const char* Name) -{ - int i, n; - - if (NamedColorList == NULL) return -1; - n = cmsNamedColorCount(NamedColorList); - for (i=0; i < n; i++) { - if (cmsstrcasecmp(Name, NamedColorList->List[i].Name) == 0) - return i; - } - - return -1; -} - -// MPE support ----------------------------------------------------------------------------------------------------------------- - -static -void FreeNamedColorList(cmsStage* mpe) -{ - cmsNAMEDCOLORLIST* List = (cmsNAMEDCOLORLIST*) mpe ->Data; - cmsFreeNamedColorList(List); -} - -static -void* DupNamedColorList(cmsStage* mpe) -{ - cmsNAMEDCOLORLIST* List = (cmsNAMEDCOLORLIST*) mpe ->Data; - return cmsDupNamedColorList(List); -} - -static -void EvalNamedColorPCS(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) -{ - cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) mpe ->Data; - cmsUInt16Number index = (cmsUInt16Number) _cmsQuickSaturateWord(In[0] * 65535.0); - - if (index >= NamedColorList-> nColors) { - cmsSignalError(NamedColorList ->ContextID, cmsERROR_RANGE, "Color %d out of range; ignored", index); - } - else { - - // Named color always uses Lab - Out[0] = (cmsFloat32Number) (NamedColorList->List[index].PCS[0] / 65535.0); - Out[1] = (cmsFloat32Number) (NamedColorList->List[index].PCS[1] / 65535.0); - Out[2] = (cmsFloat32Number) (NamedColorList->List[index].PCS[2] / 65535.0); - } -} - -static -void EvalNamedColor(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) -{ - cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) mpe ->Data; - cmsUInt16Number index = (cmsUInt16Number) _cmsQuickSaturateWord(In[0] * 65535.0); - cmsUInt32Number j; - - if (index >= NamedColorList-> nColors) { - cmsSignalError(NamedColorList ->ContextID, cmsERROR_RANGE, "Color %d out of range; ignored", index); - } - else { - for (j=0; j < NamedColorList ->ColorantCount; j++) - Out[j] = (cmsFloat32Number) (NamedColorList->List[index].DeviceColorant[j] / 65535.0); - } -} - - -// Named color lookup element -cmsStage* _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList, cmsBool UsePCS) -{ - return _cmsStageAllocPlaceholder(NamedColorList ->ContextID, - cmsSigNamedColorElemType, - 1, UsePCS ? 3 : NamedColorList ->ColorantCount, - UsePCS ? EvalNamedColorPCS : EvalNamedColor, - DupNamedColorList, - FreeNamedColorList, - cmsDupNamedColorList(NamedColorList)); - -} - - -// Retrieve the named color list from a transform. Should be first element in the LUT -cmsNAMEDCOLORLIST* CMSEXPORT cmsGetNamedColorList(cmsHTRANSFORM xform) -{ - _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform; - cmsStage* mpe = v ->Lut->Elements; - - if (mpe ->Type != cmsSigNamedColorElemType) return NULL; - return (cmsNAMEDCOLORLIST*) mpe ->Data; -} - - -// Profile sequence description routines ------------------------------------------------------------------------------------- - -cmsSEQ* CMSEXPORT cmsAllocProfileSequenceDescription(cmsContext ContextID, cmsUInt32Number n) -{ - cmsSEQ* Seq; - cmsUInt32Number i; - - if (n == 0) return NULL; - - // In a absolutely arbitrary way, I hereby decide to allow a maxim of 255 profiles linked - // in a devicelink. It makes not sense anyway and may be used for exploits, so let's close the door! - if (n > 255) return NULL; - - Seq = (cmsSEQ*) _cmsMallocZero(ContextID, sizeof(cmsSEQ)); - if (Seq == NULL) return NULL; - - Seq -> ContextID = ContextID; - Seq -> seq = (cmsPSEQDESC*) _cmsCalloc(ContextID, n, sizeof(cmsPSEQDESC)); - Seq -> n = n; - - if (Seq -> seq == NULL) { - _cmsFree(ContextID, Seq); - return NULL; - } - - for (i=0; i < n; i++) { - Seq -> seq[i].Manufacturer = NULL; - Seq -> seq[i].Model = NULL; - Seq -> seq[i].Description = NULL; - } - - return Seq; -} - -void CMSEXPORT cmsFreeProfileSequenceDescription(cmsSEQ* pseq) -{ - cmsUInt32Number i; - - for (i=0; i < pseq ->n; i++) { - if (pseq ->seq[i].Manufacturer != NULL) cmsMLUfree(pseq ->seq[i].Manufacturer); - if (pseq ->seq[i].Model != NULL) cmsMLUfree(pseq ->seq[i].Model); - if (pseq ->seq[i].Description != NULL) cmsMLUfree(pseq ->seq[i].Description); - } - - if (pseq ->seq != NULL) _cmsFree(pseq ->ContextID, pseq ->seq); - _cmsFree(pseq -> ContextID, pseq); -} - -cmsSEQ* CMSEXPORT cmsDupProfileSequenceDescription(const cmsSEQ* pseq) -{ - cmsSEQ *NewSeq; - cmsUInt32Number i; - - if (pseq == NULL) - return NULL; - - NewSeq = (cmsSEQ*) _cmsMalloc(pseq -> ContextID, sizeof(cmsSEQ)); - if (NewSeq == NULL) return NULL; - - - NewSeq -> seq = (cmsPSEQDESC*) _cmsCalloc(pseq ->ContextID, pseq ->n, sizeof(cmsPSEQDESC)); - if (NewSeq ->seq == NULL) goto Error; - - NewSeq -> ContextID = pseq ->ContextID; - NewSeq -> n = pseq ->n; - - for (i=0; i < pseq->n; i++) { - - memmove(&NewSeq ->seq[i].attributes, &pseq ->seq[i].attributes, sizeof(cmsUInt64Number)); - - NewSeq ->seq[i].deviceMfg = pseq ->seq[i].deviceMfg; - NewSeq ->seq[i].deviceModel = pseq ->seq[i].deviceModel; - memmove(&NewSeq ->seq[i].ProfileID, &pseq ->seq[i].ProfileID, sizeof(cmsProfileID)); - NewSeq ->seq[i].technology = pseq ->seq[i].technology; - - NewSeq ->seq[i].Manufacturer = cmsMLUdup(pseq ->seq[i].Manufacturer); - NewSeq ->seq[i].Model = cmsMLUdup(pseq ->seq[i].Model); - NewSeq ->seq[i].Description = cmsMLUdup(pseq ->seq[i].Description); - - } - - return NewSeq; - -Error: - - cmsFreeProfileSequenceDescription(NewSeq); - return NULL; -} - -// Dictionaries -------------------------------------------------------------------------------------------------------- - -// Dictionaries are just very simple linked lists - - -typedef struct _cmsDICT_struct { - cmsDICTentry* head; - cmsContext ContextID; -} _cmsDICT; - - -// Allocate an empty dictionary -cmsHANDLE CMSEXPORT cmsDictAlloc(cmsContext ContextID) -{ - _cmsDICT* dict = (_cmsDICT*) _cmsMallocZero(ContextID, sizeof(_cmsDICT)); - if (dict == NULL) return NULL; - - dict ->ContextID = ContextID; - return (cmsHANDLE) dict; - -} - -// Dispose resources -void CMSEXPORT cmsDictFree(cmsHANDLE hDict) -{ - _cmsDICT* dict = (_cmsDICT*) hDict; - cmsDICTentry *entry, *next; - - _cmsAssert(dict != NULL); - - // Walk the list freeing all nodes - entry = dict ->head; - while (entry != NULL) { - - if (entry ->DisplayName != NULL) cmsMLUfree(entry ->DisplayName); - if (entry ->DisplayValue != NULL) cmsMLUfree(entry ->DisplayValue); - if (entry ->Name != NULL) _cmsFree(dict ->ContextID, entry -> Name); - if (entry ->Value != NULL) _cmsFree(dict ->ContextID, entry -> Value); - - // Don't fall in the habitual trap... - next = entry ->Next; - _cmsFree(dict ->ContextID, entry); - - entry = next; - } - - _cmsFree(dict ->ContextID, dict); -} - - -// Duplicate a wide char string -static -wchar_t* DupWcs(cmsContext ContextID, const wchar_t* ptr) -{ - if (ptr == NULL) return NULL; - return (wchar_t*) _cmsDupMem(ContextID, ptr, (mywcslen(ptr) + 1) * sizeof(wchar_t)); -} - -// Add a new entry to the linked list -cmsBool CMSEXPORT cmsDictAddEntry(cmsHANDLE hDict, const wchar_t* Name, const wchar_t* Value, const cmsMLU *DisplayName, const cmsMLU *DisplayValue) -{ - _cmsDICT* dict = (_cmsDICT*) hDict; - cmsDICTentry *entry; - - _cmsAssert(dict != NULL); - _cmsAssert(Name != NULL); - - entry = (cmsDICTentry*) _cmsMallocZero(dict ->ContextID, sizeof(cmsDICTentry)); - if (entry == NULL) return FALSE; - - entry ->DisplayName = cmsMLUdup(DisplayName); - entry ->DisplayValue = cmsMLUdup(DisplayValue); - entry ->Name = DupWcs(dict ->ContextID, Name); - entry ->Value = DupWcs(dict ->ContextID, Value); - - entry ->Next = dict ->head; - dict ->head = entry; - - return TRUE; -} - - -// Duplicates an existing dictionary -cmsHANDLE CMSEXPORT cmsDictDup(cmsHANDLE hDict) -{ - _cmsDICT* old_dict = (_cmsDICT*) hDict; - cmsHANDLE hNew; - cmsDICTentry *entry; - - _cmsAssert(old_dict != NULL); - - hNew = cmsDictAlloc(old_dict ->ContextID); - if (hNew == NULL) return NULL; - - // Walk the list freeing all nodes - entry = old_dict ->head; - while (entry != NULL) { - - if (!cmsDictAddEntry(hNew, entry ->Name, entry ->Value, entry ->DisplayName, entry ->DisplayValue)) { - - cmsDictFree(hNew); - return NULL; - } - - entry = entry -> Next; - } - - return hNew; -} - -// Get a pointer to the linked list -const cmsDICTentry* CMSEXPORT cmsDictGetEntryList(cmsHANDLE hDict) -{ - _cmsDICT* dict = (_cmsDICT*) hDict; - - if (dict == NULL) return NULL; - return dict ->head; -} - -// Helper For external languages -const cmsDICTentry* CMSEXPORT cmsDictNextEntry(const cmsDICTentry* e) -{ - if (e == NULL) return NULL; - return e ->Next; -} diff --git a/third_party/lcms2-2.6/src/cmsopt.c b/third_party/lcms2-2.6/src/cmsopt.c deleted file mode 100644 index 76de01554c..0000000000 --- a/third_party/lcms2-2.6/src/cmsopt.c +++ /dev/null @@ -1,1811 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2011 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- -// - -#include "lcms2_internal.h" - - -//---------------------------------------------------------------------------------- - -// Optimization for 8 bits, Shaper-CLUT (3 inputs only) -typedef struct { - - cmsContext ContextID; - - const cmsInterpParams* p; // Tetrahedrical interpolation parameters. This is a not-owned pointer. - - cmsUInt16Number rx[256], ry[256], rz[256]; - cmsUInt32Number X0[256], Y0[256], Z0[256]; // Precomputed nodes and offsets for 8-bit input data - - -} Prelin8Data; - - -// Generic optimization for 16 bits Shaper-CLUT-Shaper (any inputs) -typedef struct { - - cmsContext ContextID; - - // Number of channels - int nInputs; - int nOutputs; - - _cmsInterpFn16 EvalCurveIn16[MAX_INPUT_DIMENSIONS]; // The maximum number of input channels is known in advance - cmsInterpParams* ParamsCurveIn16[MAX_INPUT_DIMENSIONS]; - - _cmsInterpFn16 EvalCLUT; // The evaluator for 3D grid - const cmsInterpParams* CLUTparams; // (not-owned pointer) - - - _cmsInterpFn16* EvalCurveOut16; // Points to an array of curve evaluators in 16 bits (not-owned pointer) - cmsInterpParams** ParamsCurveOut16; // Points to an array of references to interpolation params (not-owned pointer) - - -} Prelin16Data; - - -// Optimization for matrix-shaper in 8 bits. Numbers are operated in n.14 signed, tables are stored in 1.14 fixed - -typedef cmsInt32Number cmsS1Fixed14Number; // Note that this may hold more than 16 bits! - -#define DOUBLE_TO_1FIXED14(x) ((cmsS1Fixed14Number) floor((x) * 16384.0 + 0.5)) - -typedef struct { - - cmsContext ContextID; - - cmsS1Fixed14Number Shaper1R[256]; // from 0..255 to 1.14 (0.0...1.0) - cmsS1Fixed14Number Shaper1G[256]; - cmsS1Fixed14Number Shaper1B[256]; - - cmsS1Fixed14Number Mat[3][3]; // n.14 to n.14 (needs a saturation after that) - cmsS1Fixed14Number Off[3]; - - cmsUInt16Number Shaper2R[16385]; // 1.14 to 0..255 - cmsUInt16Number Shaper2G[16385]; - cmsUInt16Number Shaper2B[16385]; - -} MatShaper8Data; - -// Curves, optimization is shared between 8 and 16 bits -typedef struct { - - cmsContext ContextID; - - int nCurves; // Number of curves - int nElements; // Elements in curves - cmsUInt16Number** Curves; // Points to a dynamically allocated array - -} Curves16Data; - - -// Simple optimizations ---------------------------------------------------------------------------------------------------------- - - -// Remove an element in linked chain -static -void _RemoveElement(cmsStage** head) -{ - cmsStage* mpe = *head; - cmsStage* next = mpe ->Next; - *head = next; - cmsStageFree(mpe); -} - -// Remove all identities in chain. Note that pt actually is a double pointer to the element that holds the pointer. -static -cmsBool _Remove1Op(cmsPipeline* Lut, cmsStageSignature UnaryOp) -{ - cmsStage** pt = &Lut ->Elements; - cmsBool AnyOpt = FALSE; - - while (*pt != NULL) { - - if ((*pt) ->Implements == UnaryOp) { - _RemoveElement(pt); - AnyOpt = TRUE; - } - else - pt = &((*pt) -> Next); - } - - return AnyOpt; -} - -// Same, but only if two adjacent elements are found -static -cmsBool _Remove2Op(cmsPipeline* Lut, cmsStageSignature Op1, cmsStageSignature Op2) -{ - cmsStage** pt1; - cmsStage** pt2; - cmsBool AnyOpt = FALSE; - - pt1 = &Lut ->Elements; - if (*pt1 == NULL) return AnyOpt; - - while (*pt1 != NULL) { - - pt2 = &((*pt1) -> Next); - if (*pt2 == NULL) return AnyOpt; - - if ((*pt1) ->Implements == Op1 && (*pt2) ->Implements == Op2) { - _RemoveElement(pt2); - _RemoveElement(pt1); - AnyOpt = TRUE; - } - else - pt1 = &((*pt1) -> Next); - } - - return AnyOpt; -} - -// Preoptimize just gets rif of no-ops coming paired. Conversion from v2 to v4 followed -// by a v4 to v2 and vice-versa. The elements are then discarded. -static -cmsBool PreOptimize(cmsPipeline* Lut) -{ - cmsBool AnyOpt = FALSE, Opt; - - do { - - Opt = FALSE; - - // Remove all identities - Opt |= _Remove1Op(Lut, cmsSigIdentityElemType); - - // Remove XYZ2Lab followed by Lab2XYZ - Opt |= _Remove2Op(Lut, cmsSigXYZ2LabElemType, cmsSigLab2XYZElemType); - - // Remove Lab2XYZ followed by XYZ2Lab - Opt |= _Remove2Op(Lut, cmsSigLab2XYZElemType, cmsSigXYZ2LabElemType); - - // Remove V4 to V2 followed by V2 to V4 - Opt |= _Remove2Op(Lut, cmsSigLabV4toV2, cmsSigLabV2toV4); - - // Remove V2 to V4 followed by V4 to V2 - Opt |= _Remove2Op(Lut, cmsSigLabV2toV4, cmsSigLabV4toV2); - - // Remove float pcs Lab conversions - Opt |= _Remove2Op(Lut, cmsSigLab2FloatPCS, cmsSigFloatPCS2Lab); - - // Remove float pcs Lab conversions - Opt |= _Remove2Op(Lut, cmsSigXYZ2FloatPCS, cmsSigFloatPCS2XYZ); - - if (Opt) AnyOpt = TRUE; - - } while (Opt); - - return AnyOpt; -} - -static -void Eval16nop1D(register const cmsUInt16Number Input[], - register cmsUInt16Number Output[], - register const struct _cms_interp_struc* p) -{ - Output[0] = Input[0]; - - cmsUNUSED_PARAMETER(p); -} - -static -void PrelinEval16(register const cmsUInt16Number Input[], - register cmsUInt16Number Output[], - register const void* D) -{ - Prelin16Data* p16 = (Prelin16Data*) D; - cmsUInt16Number StageABC[MAX_INPUT_DIMENSIONS]; - cmsUInt16Number StageDEF[cmsMAXCHANNELS]; - int i; - - for (i=0; i < p16 ->nInputs; i++) { - - p16 ->EvalCurveIn16[i](&Input[i], &StageABC[i], p16 ->ParamsCurveIn16[i]); - } - - p16 ->EvalCLUT(StageABC, StageDEF, p16 ->CLUTparams); - - for (i=0; i < p16 ->nOutputs; i++) { - - p16 ->EvalCurveOut16[i](&StageDEF[i], &Output[i], p16 ->ParamsCurveOut16[i]); - } -} - - -static -void PrelinOpt16free(cmsContext ContextID, void* ptr) -{ - Prelin16Data* p16 = (Prelin16Data*) ptr; - - _cmsFree(ContextID, p16 ->EvalCurveOut16); - _cmsFree(ContextID, p16 ->ParamsCurveOut16); - - _cmsFree(ContextID, p16); -} - -static -void* Prelin16dup(cmsContext ContextID, const void* ptr) -{ - Prelin16Data* p16 = (Prelin16Data*) ptr; - Prelin16Data* Duped = _cmsDupMem(ContextID, p16, sizeof(Prelin16Data)); - - if (Duped == NULL) return NULL; - - Duped ->EvalCurveOut16 = (_cmsInterpFn16*)_cmsDupMem(ContextID, p16 ->EvalCurveOut16, p16 ->nOutputs * sizeof(_cmsInterpFn16)); - Duped ->ParamsCurveOut16 = (cmsInterpParams**)_cmsDupMem(ContextID, p16 ->ParamsCurveOut16, p16 ->nOutputs * sizeof(cmsInterpParams* )); - - return Duped; -} - - -static -Prelin16Data* PrelinOpt16alloc(cmsContext ContextID, - const cmsInterpParams* ColorMap, - int nInputs, cmsToneCurve** In, - int nOutputs, cmsToneCurve** Out ) -{ - int i; - Prelin16Data* p16 = _cmsMallocZero(ContextID, sizeof(Prelin16Data)); - if (p16 == NULL) return NULL; - - p16 ->nInputs = nInputs; - p16 -> nOutputs = nOutputs; - - - for (i=0; i < nInputs; i++) { - - if (In == NULL) { - p16 -> ParamsCurveIn16[i] = NULL; - p16 -> EvalCurveIn16[i] = Eval16nop1D; - - } - else { - p16 -> ParamsCurveIn16[i] = In[i] ->InterpParams; - p16 -> EvalCurveIn16[i] = p16 ->ParamsCurveIn16[i]->Interpolation.Lerp16; - } - } - - p16 ->CLUTparams = ColorMap; - p16 ->EvalCLUT = ColorMap ->Interpolation.Lerp16; - - - p16 -> EvalCurveOut16 = (_cmsInterpFn16*) _cmsCalloc(ContextID, nOutputs, sizeof(_cmsInterpFn16)); - p16 -> ParamsCurveOut16 = (cmsInterpParams**) _cmsCalloc(ContextID, nOutputs, sizeof(cmsInterpParams* )); - - for (i=0; i < nOutputs; i++) { - - if (Out == NULL) { - p16 ->ParamsCurveOut16[i] = NULL; - p16 -> EvalCurveOut16[i] = Eval16nop1D; - } - else { - - p16 ->ParamsCurveOut16[i] = Out[i] ->InterpParams; - p16 -> EvalCurveOut16[i] = p16 ->ParamsCurveOut16[i]->Interpolation.Lerp16; - } - } - - return p16; -} - - - -// Resampling --------------------------------------------------------------------------------- - -#define PRELINEARIZATION_POINTS 4096 - -// Sampler implemented by another LUT. This is a clean way to precalculate the devicelink 3D CLUT for -// almost any transform. We use floating point precision and then convert from floating point to 16 bits. -static -int XFormSampler16(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) -{ - cmsPipeline* Lut = (cmsPipeline*) Cargo; - cmsFloat32Number InFloat[cmsMAXCHANNELS], OutFloat[cmsMAXCHANNELS]; - cmsUInt32Number i; - - _cmsAssert(Lut -> InputChannels < cmsMAXCHANNELS); - _cmsAssert(Lut -> OutputChannels < cmsMAXCHANNELS); - - // From 16 bit to floating point - for (i=0; i < Lut ->InputChannels; i++) - InFloat[i] = (cmsFloat32Number) (In[i] / 65535.0); - - // Evaluate in floating point - cmsPipelineEvalFloat(InFloat, OutFloat, Lut); - - // Back to 16 bits representation - for (i=0; i < Lut ->OutputChannels; i++) - Out[i] = _cmsQuickSaturateWord(OutFloat[i] * 65535.0); - - // Always succeed - return TRUE; -} - -// Try to see if the curves of a given MPE are linear -static -cmsBool AllCurvesAreLinear(cmsStage* mpe) -{ - cmsToneCurve** Curves; - cmsUInt32Number i, n; - - Curves = _cmsStageGetPtrToCurveSet(mpe); - if (Curves == NULL) return FALSE; - - n = cmsStageOutputChannels(mpe); - - for (i=0; i < n; i++) { - if (!cmsIsToneCurveLinear(Curves[i])) return FALSE; - } - - return TRUE; -} - -// This function replaces a specific node placed in "At" by the "Value" numbers. Its purpose -// is to fix scum dot on broken profiles/transforms. Works on 1, 3 and 4 channels -static -cmsBool PatchLUT(cmsStage* CLUT, cmsUInt16Number At[], cmsUInt16Number Value[], - int nChannelsOut, int nChannelsIn) -{ - _cmsStageCLutData* Grid = (_cmsStageCLutData*) CLUT ->Data; - cmsInterpParams* p16 = Grid ->Params; - cmsFloat64Number px, py, pz, pw; - int x0, y0, z0, w0; - int i, index; - - if (CLUT -> Type != cmsSigCLutElemType) { - cmsSignalError(CLUT->ContextID, cmsERROR_INTERNAL, "(internal) Attempt to PatchLUT on non-lut stage"); - return FALSE; - } - - if (nChannelsIn != 1 && nChannelsIn != 3 && nChannelsIn != 4) { - cmsSignalError(CLUT->ContextID, cmsERROR_INTERNAL, "(internal) %d Channels are not supported on PatchLUT", nChannelsIn); - return FALSE; - } - if (nChannelsIn == 4) { - - px = ((cmsFloat64Number) At[0] * (p16->Domain[0])) / 65535.0; - py = ((cmsFloat64Number) At[1] * (p16->Domain[1])) / 65535.0; - pz = ((cmsFloat64Number) At[2] * (p16->Domain[2])) / 65535.0; - pw = ((cmsFloat64Number) At[3] * (p16->Domain[3])) / 65535.0; - - x0 = (int) floor(px); - y0 = (int) floor(py); - z0 = (int) floor(pz); - w0 = (int) floor(pw); - - if (((px - x0) != 0) || - ((py - y0) != 0) || - ((pz - z0) != 0) || - ((pw - w0) != 0)) return FALSE; // Not on exact node - - index = p16 -> opta[3] * x0 + - p16 -> opta[2] * y0 + - p16 -> opta[1] * z0 + - p16 -> opta[0] * w0; - } - else - if (nChannelsIn == 3) { - - px = ((cmsFloat64Number) At[0] * (p16->Domain[0])) / 65535.0; - py = ((cmsFloat64Number) At[1] * (p16->Domain[1])) / 65535.0; - pz = ((cmsFloat64Number) At[2] * (p16->Domain[2])) / 65535.0; - - x0 = (int) floor(px); - y0 = (int) floor(py); - z0 = (int) floor(pz); - - if (((px - x0) != 0) || - ((py - y0) != 0) || - ((pz - z0) != 0)) return FALSE; // Not on exact node - - index = p16 -> opta[2] * x0 + - p16 -> opta[1] * y0 + - p16 -> opta[0] * z0; - } - else - if (nChannelsIn == 1) { - - px = ((cmsFloat64Number) At[0] * (p16->Domain[0])) / 65535.0; - - x0 = (int) floor(px); - - if (((px - x0) != 0)) return FALSE; // Not on exact node - - index = p16 -> opta[0] * x0; - } - else { - cmsSignalError(CLUT->ContextID, cmsERROR_INTERNAL, "(internal) %d Channels are not supported on PatchLUT", nChannelsIn); - return FALSE; - } - - for (i=0; i < nChannelsOut; i++) - Grid -> Tab.T[index + i] = Value[i]; - - return TRUE; -} - -// Auxiliar, to see if two values are equal or very different -static -cmsBool WhitesAreEqual(int n, cmsUInt16Number White1[], cmsUInt16Number White2[] ) -{ - int i; - - for (i=0; i < n; i++) { - - if (abs(White1[i] - White2[i]) > 0xf000) return TRUE; // Values are so extremly different that the fixup should be avoided - if (White1[i] != White2[i]) return FALSE; - } - return TRUE; -} - - -// Locate the node for the white point and fix it to pure white in order to avoid scum dot. -static -cmsBool FixWhiteMisalignment(cmsPipeline* Lut, cmsColorSpaceSignature EntryColorSpace, cmsColorSpaceSignature ExitColorSpace) -{ - cmsUInt16Number *WhitePointIn, *WhitePointOut; - cmsUInt16Number WhiteIn[cmsMAXCHANNELS], WhiteOut[cmsMAXCHANNELS], ObtainedOut[cmsMAXCHANNELS]; - cmsUInt32Number i, nOuts, nIns; - cmsStage *PreLin = NULL, *CLUT = NULL, *PostLin = NULL; - - if (!_cmsEndPointsBySpace(EntryColorSpace, - &WhitePointIn, NULL, &nIns)) return FALSE; - - if (!_cmsEndPointsBySpace(ExitColorSpace, - &WhitePointOut, NULL, &nOuts)) return FALSE; - - // It needs to be fixed? - if (Lut ->InputChannels != nIns) return FALSE; - if (Lut ->OutputChannels != nOuts) return FALSE; - - cmsPipelineEval16(WhitePointIn, ObtainedOut, Lut); - - if (WhitesAreEqual(nOuts, WhitePointOut, ObtainedOut)) return TRUE; // whites already match - - // Check if the LUT comes as Prelin, CLUT or Postlin. We allow all combinations - if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &PreLin, &CLUT, &PostLin)) - if (!cmsPipelineCheckAndRetreiveStages(Lut, 2, cmsSigCurveSetElemType, cmsSigCLutElemType, &PreLin, &CLUT)) - if (!cmsPipelineCheckAndRetreiveStages(Lut, 2, cmsSigCLutElemType, cmsSigCurveSetElemType, &CLUT, &PostLin)) - if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCLutElemType, &CLUT)) - return FALSE; - - // We need to interpolate white points of both, pre and post curves - if (PreLin) { - - cmsToneCurve** Curves = _cmsStageGetPtrToCurveSet(PreLin); - - for (i=0; i < nIns; i++) { - WhiteIn[i] = cmsEvalToneCurve16(Curves[i], WhitePointIn[i]); - } - } - else { - for (i=0; i < nIns; i++) - WhiteIn[i] = WhitePointIn[i]; - } - - // If any post-linearization, we need to find how is represented white before the curve, do - // a reverse interpolation in this case. - if (PostLin) { - - cmsToneCurve** Curves = _cmsStageGetPtrToCurveSet(PostLin); - - for (i=0; i < nOuts; i++) { - - cmsToneCurve* InversePostLin = cmsReverseToneCurve(Curves[i]); - if (InversePostLin == NULL) { - WhiteOut[i] = WhitePointOut[i]; - - } else { - - WhiteOut[i] = cmsEvalToneCurve16(InversePostLin, WhitePointOut[i]); - cmsFreeToneCurve(InversePostLin); - } - } - } - else { - for (i=0; i < nOuts; i++) - WhiteOut[i] = WhitePointOut[i]; - } - - // Ok, proceed with patching. May fail and we don't care if it fails - PatchLUT(CLUT, WhiteIn, WhiteOut, nOuts, nIns); - - return TRUE; -} - -// ----------------------------------------------------------------------------------------------------------------------------------------------- -// This function creates simple LUT from complex ones. The generated LUT has an optional set of -// prelinearization curves, a CLUT of nGridPoints and optional postlinearization tables. -// These curves have to exist in the original LUT in order to be used in the simplified output. -// Caller may also use the flags to allow this feature. -// LUTS with all curves will be simplified to a single curve. Parametric curves are lost. -// This function should be used on 16-bits LUTS only, as floating point losses precision when simplified -// ----------------------------------------------------------------------------------------------------------------------------------------------- - -static -cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) -{ - cmsPipeline* Src = NULL; - cmsPipeline* Dest = NULL; - cmsStage* mpe; - cmsStage* CLUT; - cmsStage *KeepPreLin = NULL, *KeepPostLin = NULL; - int nGridPoints; - cmsColorSpaceSignature ColorSpace, OutputColorSpace; - cmsStage *NewPreLin = NULL; - cmsStage *NewPostLin = NULL; - _cmsStageCLutData* DataCLUT; - cmsToneCurve** DataSetIn; - cmsToneCurve** DataSetOut; - Prelin16Data* p16; - - // This is a loosy optimization! does not apply in floating-point cases - if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) return FALSE; - - ColorSpace = _cmsICCcolorSpace(T_COLORSPACE(*InputFormat)); - OutputColorSpace = _cmsICCcolorSpace(T_COLORSPACE(*OutputFormat)); - nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags); - - // For empty LUTs, 2 points are enough - if (cmsPipelineStageCount(*Lut) == 0) - nGridPoints = 2; - - Src = *Lut; - - // Named color pipelines cannot be optimized either - for (mpe = cmsPipelineGetPtrToFirstStage(Src); - mpe != NULL; - mpe = cmsStageNext(mpe)) { - if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE; - } - - // Allocate an empty LUT - Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels); - if (!Dest) return FALSE; - - // Prelinearization tables are kept unless indicated by flags - if (*dwFlags & cmsFLAGS_CLUT_PRE_LINEARIZATION) { - - // Get a pointer to the prelinearization element - cmsStage* PreLin = cmsPipelineGetPtrToFirstStage(Src); - - // Check if suitable - if (PreLin ->Type == cmsSigCurveSetElemType) { - - // Maybe this is a linear tram, so we can avoid the whole stuff - if (!AllCurvesAreLinear(PreLin)) { - - // All seems ok, proceed. - NewPreLin = cmsStageDup(PreLin); - if(!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, NewPreLin)) - goto Error; - - // Remove prelinearization. Since we have duplicated the curve - // in destination LUT, the sampling shoud be applied after this stage. - cmsPipelineUnlinkStage(Src, cmsAT_BEGIN, &KeepPreLin); - } - } - } - - // Allocate the CLUT - CLUT = cmsStageAllocCLut16bit(Src ->ContextID, nGridPoints, Src ->InputChannels, Src->OutputChannels, NULL); - if (CLUT == NULL) goto Error; - - // Add the CLUT to the destination LUT - if (!cmsPipelineInsertStage(Dest, cmsAT_END, CLUT)) { - goto Error; - } - - // Postlinearization tables are kept unless indicated by flags - if (*dwFlags & cmsFLAGS_CLUT_POST_LINEARIZATION) { - - // Get a pointer to the postlinearization if present - cmsStage* PostLin = cmsPipelineGetPtrToLastStage(Src); - - // Check if suitable - if (cmsStageType(PostLin) == cmsSigCurveSetElemType) { - - // Maybe this is a linear tram, so we can avoid the whole stuff - if (!AllCurvesAreLinear(PostLin)) { - - // All seems ok, proceed. - NewPostLin = cmsStageDup(PostLin); - if (!cmsPipelineInsertStage(Dest, cmsAT_END, NewPostLin)) - goto Error; - - // In destination LUT, the sampling shoud be applied after this stage. - cmsPipelineUnlinkStage(Src, cmsAT_END, &KeepPostLin); - } - } - } - - // Now its time to do the sampling. We have to ignore pre/post linearization - // The source LUT whithout pre/post curves is passed as parameter. - if (!cmsStageSampleCLut16bit(CLUT, XFormSampler16, (void*) Src, 0)) { -Error: - // Ops, something went wrong, Restore stages - if (KeepPreLin != NULL) { - if (!cmsPipelineInsertStage(Src, cmsAT_BEGIN, KeepPreLin)) { - _cmsAssert(0); // This never happens - } - } - if (KeepPostLin != NULL) { - if (!cmsPipelineInsertStage(Src, cmsAT_END, KeepPostLin)) { - _cmsAssert(0); // This never happens - } - } - cmsPipelineFree(Dest); - return FALSE; - } - - // Done. - - if (KeepPreLin != NULL) cmsStageFree(KeepPreLin); - if (KeepPostLin != NULL) cmsStageFree(KeepPostLin); - cmsPipelineFree(Src); - - DataCLUT = (_cmsStageCLutData*) CLUT ->Data; - - if (NewPreLin == NULL) DataSetIn = NULL; - else DataSetIn = ((_cmsStageToneCurvesData*) NewPreLin ->Data) ->TheCurves; - - if (NewPostLin == NULL) DataSetOut = NULL; - else DataSetOut = ((_cmsStageToneCurvesData*) NewPostLin ->Data) ->TheCurves; - - - if (DataSetIn == NULL && DataSetOut == NULL) { - - _cmsPipelineSetOptimizationParameters(Dest, (_cmsOPTeval16Fn) DataCLUT->Params->Interpolation.Lerp16, DataCLUT->Params, NULL, NULL); - } - else { - - p16 = PrelinOpt16alloc(Dest ->ContextID, - DataCLUT ->Params, - Dest ->InputChannels, - DataSetIn, - Dest ->OutputChannels, - DataSetOut); - - _cmsPipelineSetOptimizationParameters(Dest, PrelinEval16, (void*) p16, PrelinOpt16free, Prelin16dup); - } - - - // Don't fix white on absolute colorimetric - if (Intent == INTENT_ABSOLUTE_COLORIMETRIC) - *dwFlags |= cmsFLAGS_NOWHITEONWHITEFIXUP; - - if (!(*dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP)) { - - FixWhiteMisalignment(Dest, ColorSpace, OutputColorSpace); - } - - *Lut = Dest; - return TRUE; - - cmsUNUSED_PARAMETER(Intent); -} - - -// ----------------------------------------------------------------------------------------------------------------------------------------------- -// Fixes the gamma balancing of transform. This is described in my paper "Prelinearization Stages on -// Color-Management Application-Specific Integrated Circuits (ASICs)" presented at NIP24. It only works -// for RGB transforms. See the paper for more details -// ----------------------------------------------------------------------------------------------------------------------------------------------- - - -// Normalize endpoints by slope limiting max and min. This assures endpoints as well. -// Descending curves are handled as well. -static -void SlopeLimiting(cmsToneCurve* g) -{ - int BeginVal, EndVal; - int AtBegin = (int) floor((cmsFloat64Number) g ->nEntries * 0.02 + 0.5); // Cutoff at 2% - int AtEnd = g ->nEntries - AtBegin - 1; // And 98% - cmsFloat64Number Val, Slope, beta; - int i; - - if (cmsIsToneCurveDescending(g)) { - BeginVal = 0xffff; EndVal = 0; - } - else { - BeginVal = 0; EndVal = 0xffff; - } - - // Compute slope and offset for begin of curve - Val = g ->Table16[AtBegin]; - Slope = (Val - BeginVal) / AtBegin; - beta = Val - Slope * AtBegin; - - for (i=0; i < AtBegin; i++) - g ->Table16[i] = _cmsQuickSaturateWord(i * Slope + beta); - - // Compute slope and offset for the end - Val = g ->Table16[AtEnd]; - Slope = (EndVal - Val) / AtBegin; // AtBegin holds the X interval, which is same in both cases - beta = Val - Slope * AtEnd; - - for (i = AtEnd; i < (int) g ->nEntries; i++) - g ->Table16[i] = _cmsQuickSaturateWord(i * Slope + beta); -} - - -// Precomputes tables for 8-bit on input devicelink. -static -Prelin8Data* PrelinOpt8alloc(cmsContext ContextID, const cmsInterpParams* p, cmsToneCurve* G[3]) -{ - int i; - cmsUInt16Number Input[3]; - cmsS15Fixed16Number v1, v2, v3; - Prelin8Data* p8; - - p8 = (Prelin8Data*)_cmsMallocZero(ContextID, sizeof(Prelin8Data)); - if (p8 == NULL) return NULL; - - // Since this only works for 8 bit input, values comes always as x * 257, - // we can safely take msb byte (x << 8 + x) - - for (i=0; i < 256; i++) { - - if (G != NULL) { - - // Get 16-bit representation - Input[0] = cmsEvalToneCurve16(G[0], FROM_8_TO_16(i)); - Input[1] = cmsEvalToneCurve16(G[1], FROM_8_TO_16(i)); - Input[2] = cmsEvalToneCurve16(G[2], FROM_8_TO_16(i)); - } - else { - Input[0] = FROM_8_TO_16(i); - Input[1] = FROM_8_TO_16(i); - Input[2] = FROM_8_TO_16(i); - } - - - // Move to 0..1.0 in fixed domain - v1 = _cmsToFixedDomain(Input[0] * p -> Domain[0]); - v2 = _cmsToFixedDomain(Input[1] * p -> Domain[1]); - v3 = _cmsToFixedDomain(Input[2] * p -> Domain[2]); - - // Store the precalculated table of nodes - p8 ->X0[i] = (p->opta[2] * FIXED_TO_INT(v1)); - p8 ->Y0[i] = (p->opta[1] * FIXED_TO_INT(v2)); - p8 ->Z0[i] = (p->opta[0] * FIXED_TO_INT(v3)); - - // Store the precalculated table of offsets - p8 ->rx[i] = (cmsUInt16Number) FIXED_REST_TO_INT(v1); - p8 ->ry[i] = (cmsUInt16Number) FIXED_REST_TO_INT(v2); - p8 ->rz[i] = (cmsUInt16Number) FIXED_REST_TO_INT(v3); - } - - p8 ->ContextID = ContextID; - p8 ->p = p; - - return p8; -} - -static -void Prelin8free(cmsContext ContextID, void* ptr) -{ - _cmsFree(ContextID, ptr); -} - -static -void* Prelin8dup(cmsContext ContextID, const void* ptr) -{ - return _cmsDupMem(ContextID, ptr, sizeof(Prelin8Data)); -} - - - -// A optimized interpolation for 8-bit input. -#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) -static -void PrelinEval8(register const cmsUInt16Number Input[], - register cmsUInt16Number Output[], - register const void* D) -{ - - cmsUInt8Number r, g, b; - cmsS15Fixed16Number rx, ry, rz; - cmsS15Fixed16Number c0, c1, c2, c3, Rest; - int OutChan; - register cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1; - Prelin8Data* p8 = (Prelin8Data*) D; - register const cmsInterpParams* p = p8 ->p; - int TotalOut = p -> nOutputs; - const cmsUInt16Number* LutTable = (const cmsUInt16Number*)p -> Table; - - r = Input[0] >> 8; - g = Input[1] >> 8; - b = Input[2] >> 8; - - X0 = X1 = p8->X0[r]; - Y0 = Y1 = p8->Y0[g]; - Z0 = Z1 = p8->Z0[b]; - - rx = p8 ->rx[r]; - ry = p8 ->ry[g]; - rz = p8 ->rz[b]; - - X1 = X0 + ((rx == 0) ? 0 : p ->opta[2]); - Y1 = Y0 + ((ry == 0) ? 0 : p ->opta[1]); - Z1 = Z0 + ((rz == 0) ? 0 : p ->opta[0]); - - - // These are the 6 Tetrahedral - for (OutChan=0; OutChan < TotalOut; OutChan++) { - - c0 = DENS(X0, Y0, Z0); - - if (rx >= ry && ry >= rz) - { - c1 = DENS(X1, Y0, Z0) - c0; - c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0); - c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); - } - else - if (rx >= rz && rz >= ry) - { - c1 = DENS(X1, Y0, Z0) - c0; - c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); - c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0); - } - else - if (rz >= rx && rx >= ry) - { - c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1); - c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); - c3 = DENS(X0, Y0, Z1) - c0; - } - else - if (ry >= rx && rx >= rz) - { - c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0); - c2 = DENS(X0, Y1, Z0) - c0; - c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); - } - else - if (ry >= rz && rz >= rx) - { - c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); - c2 = DENS(X0, Y1, Z0) - c0; - c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0); - } - else - if (rz >= ry && ry >= rx) - { - c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); - c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1); - c3 = DENS(X0, Y0, Z1) - c0; - } - else { - c1 = c2 = c3 = 0; - } - - - Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; - Output[OutChan] = (cmsUInt16Number)c0 + ((Rest + (Rest>>16))>>16); - - } -} - -#undef DENS - - -// Curves that contain wide empty areas are not optimizeable -static -cmsBool IsDegenerated(const cmsToneCurve* g) -{ - int i, Zeros = 0, Poles = 0; - int nEntries = g ->nEntries; - - for (i=0; i < nEntries; i++) { - - if (g ->Table16[i] == 0x0000) Zeros++; - if (g ->Table16[i] == 0xffff) Poles++; - } - - if (Zeros == 1 && Poles == 1) return FALSE; // For linear tables - if (Zeros > (nEntries / 4)) return TRUE; // Degenerated, mostly zeros - if (Poles > (nEntries / 4)) return TRUE; // Degenerated, mostly poles - - return FALSE; -} - -// -------------------------------------------------------------------------------------------------------------- -// We need xput over here - -static -cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) -{ - cmsPipeline* OriginalLut; - int nGridPoints; - cmsToneCurve *Trans[cmsMAXCHANNELS], *TransReverse[cmsMAXCHANNELS]; - cmsUInt32Number t, i; - cmsFloat32Number v, In[cmsMAXCHANNELS], Out[cmsMAXCHANNELS]; - cmsBool lIsSuitable, lIsLinear; - cmsPipeline* OptimizedLUT = NULL, *LutPlusCurves = NULL; - cmsStage* OptimizedCLUTmpe; - cmsColorSpaceSignature ColorSpace, OutputColorSpace; - cmsStage* OptimizedPrelinMpe; - cmsStage* mpe; - cmsToneCurve** OptimizedPrelinCurves; - _cmsStageCLutData* OptimizedPrelinCLUT; - - - // This is a loosy optimization! does not apply in floating-point cases - if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) return FALSE; - - // Only on RGB - if (T_COLORSPACE(*InputFormat) != PT_RGB) return FALSE; - if (T_COLORSPACE(*OutputFormat) != PT_RGB) return FALSE; - - - // On 16 bits, user has to specify the feature - if (!_cmsFormatterIs8bit(*InputFormat)) { - if (!(*dwFlags & cmsFLAGS_CLUT_PRE_LINEARIZATION)) return FALSE; - } - - OriginalLut = *Lut; - - // Named color pipelines cannot be optimized either - for (mpe = cmsPipelineGetPtrToFirstStage(OriginalLut); - mpe != NULL; - mpe = cmsStageNext(mpe)) { - if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE; - } - - ColorSpace = _cmsICCcolorSpace(T_COLORSPACE(*InputFormat)); - OutputColorSpace = _cmsICCcolorSpace(T_COLORSPACE(*OutputFormat)); - nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags); - - // Empty gamma containers - memset(Trans, 0, sizeof(Trans)); - memset(TransReverse, 0, sizeof(TransReverse)); - - for (t = 0; t < OriginalLut ->InputChannels; t++) { - Trans[t] = cmsBuildTabulatedToneCurve16(OriginalLut ->ContextID, PRELINEARIZATION_POINTS, NULL); - if (Trans[t] == NULL) goto Error; - } - - // Populate the curves - for (i=0; i < PRELINEARIZATION_POINTS; i++) { - - v = (cmsFloat32Number) ((cmsFloat64Number) i / (PRELINEARIZATION_POINTS - 1)); - - // Feed input with a gray ramp - for (t=0; t < OriginalLut ->InputChannels; t++) - In[t] = v; - - // Evaluate the gray value - cmsPipelineEvalFloat(In, Out, OriginalLut); - - // Store result in curve - for (t=0; t < OriginalLut ->InputChannels; t++) - Trans[t] ->Table16[i] = _cmsQuickSaturateWord(Out[t] * 65535.0); - } - - // Slope-limit the obtained curves - for (t = 0; t < OriginalLut ->InputChannels; t++) - SlopeLimiting(Trans[t]); - - // Check for validity - lIsSuitable = TRUE; - lIsLinear = TRUE; - for (t=0; (lIsSuitable && (t < OriginalLut ->InputChannels)); t++) { - - // Exclude if already linear - if (!cmsIsToneCurveLinear(Trans[t])) - lIsLinear = FALSE; - - // Exclude if non-monotonic - if (!cmsIsToneCurveMonotonic(Trans[t])) - lIsSuitable = FALSE; - - if (IsDegenerated(Trans[t])) - lIsSuitable = FALSE; - } - - // If it is not suitable, just quit - if (!lIsSuitable) goto Error; - - // Invert curves if possible - for (t = 0; t < OriginalLut ->InputChannels; t++) { - TransReverse[t] = cmsReverseToneCurveEx(PRELINEARIZATION_POINTS, Trans[t]); - if (TransReverse[t] == NULL) goto Error; - } - - // Now inset the reversed curves at the begin of transform - LutPlusCurves = cmsPipelineDup(OriginalLut); - if (LutPlusCurves == NULL) goto Error; - - if (!cmsPipelineInsertStage(LutPlusCurves, cmsAT_BEGIN, cmsStageAllocToneCurves(OriginalLut ->ContextID, OriginalLut ->InputChannels, TransReverse))) - goto Error; - - // Create the result LUT - OptimizedLUT = cmsPipelineAlloc(OriginalLut ->ContextID, OriginalLut ->InputChannels, OriginalLut ->OutputChannels); - if (OptimizedLUT == NULL) goto Error; - - OptimizedPrelinMpe = cmsStageAllocToneCurves(OriginalLut ->ContextID, OriginalLut ->InputChannels, Trans); - - // Create and insert the curves at the beginning - if (!cmsPipelineInsertStage(OptimizedLUT, cmsAT_BEGIN, OptimizedPrelinMpe)) - goto Error; - - // Allocate the CLUT for result - OptimizedCLUTmpe = cmsStageAllocCLut16bit(OriginalLut ->ContextID, nGridPoints, OriginalLut ->InputChannels, OriginalLut ->OutputChannels, NULL); - - // Add the CLUT to the destination LUT - if (!cmsPipelineInsertStage(OptimizedLUT, cmsAT_END, OptimizedCLUTmpe)) - goto Error; - - // Resample the LUT - if (!cmsStageSampleCLut16bit(OptimizedCLUTmpe, XFormSampler16, (void*) LutPlusCurves, 0)) goto Error; - - // Free resources - for (t = 0; t < OriginalLut ->InputChannels; t++) { - - if (Trans[t]) cmsFreeToneCurve(Trans[t]); - if (TransReverse[t]) cmsFreeToneCurve(TransReverse[t]); - } - - cmsPipelineFree(LutPlusCurves); - - - OptimizedPrelinCurves = _cmsStageGetPtrToCurveSet(OptimizedPrelinMpe); - OptimizedPrelinCLUT = (_cmsStageCLutData*) OptimizedCLUTmpe ->Data; - - // Set the evaluator if 8-bit - if (_cmsFormatterIs8bit(*InputFormat)) { - - Prelin8Data* p8 = PrelinOpt8alloc(OptimizedLUT ->ContextID, - OptimizedPrelinCLUT ->Params, - OptimizedPrelinCurves); - if (p8 == NULL) return FALSE; - - _cmsPipelineSetOptimizationParameters(OptimizedLUT, PrelinEval8, (void*) p8, Prelin8free, Prelin8dup); - - } - else - { - Prelin16Data* p16 = PrelinOpt16alloc(OptimizedLUT ->ContextID, - OptimizedPrelinCLUT ->Params, - 3, OptimizedPrelinCurves, 3, NULL); - if (p16 == NULL) return FALSE; - - _cmsPipelineSetOptimizationParameters(OptimizedLUT, PrelinEval16, (void*) p16, PrelinOpt16free, Prelin16dup); - - } - - // Don't fix white on absolute colorimetric - if (Intent == INTENT_ABSOLUTE_COLORIMETRIC) - *dwFlags |= cmsFLAGS_NOWHITEONWHITEFIXUP; - - if (!(*dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP)) { - - if (!FixWhiteMisalignment(OptimizedLUT, ColorSpace, OutputColorSpace)) { - - return FALSE; - } - } - - // And return the obtained LUT - - cmsPipelineFree(OriginalLut); - *Lut = OptimizedLUT; - return TRUE; - -Error: - - for (t = 0; t < OriginalLut ->InputChannels; t++) { - - if (Trans[t]) cmsFreeToneCurve(Trans[t]); - if (TransReverse[t]) cmsFreeToneCurve(TransReverse[t]); - } - - if (LutPlusCurves != NULL) cmsPipelineFree(LutPlusCurves); - if (OptimizedLUT != NULL) cmsPipelineFree(OptimizedLUT); - - return FALSE; - - cmsUNUSED_PARAMETER(Intent); -} - - -// Curves optimizer ------------------------------------------------------------------------------------------------------------------ - -static -void CurvesFree(cmsContext ContextID, void* ptr) -{ - Curves16Data* Data = (Curves16Data*) ptr; - int i; - - for (i=0; i < Data -> nCurves; i++) { - - _cmsFree(ContextID, Data ->Curves[i]); - } - - _cmsFree(ContextID, Data ->Curves); - _cmsFree(ContextID, ptr); -} - -static -void* CurvesDup(cmsContext ContextID, const void* ptr) -{ - Curves16Data* Data = (Curves16Data*)_cmsDupMem(ContextID, ptr, sizeof(Curves16Data)); - int i; - - if (Data == NULL) return NULL; - - Data ->Curves = (cmsUInt16Number**)_cmsDupMem(ContextID, Data ->Curves, Data ->nCurves * sizeof(cmsUInt16Number*)); - - for (i=0; i < Data -> nCurves; i++) { - Data ->Curves[i] = (cmsUInt16Number*)_cmsDupMem(ContextID, Data ->Curves[i], Data -> nElements * sizeof(cmsUInt16Number)); - } - - return (void*) Data; -} - -// Precomputes tables for 8-bit on input devicelink. -static -Curves16Data* CurvesAlloc(cmsContext ContextID, int nCurves, int nElements, cmsToneCurve** G) -{ - int i, j; - Curves16Data* c16; - - c16 = (Curves16Data*)_cmsMallocZero(ContextID, sizeof(Curves16Data)); - if (c16 == NULL) return NULL; - - c16 ->nCurves = nCurves; - c16 ->nElements = nElements; - - c16 ->Curves = (cmsUInt16Number**)_cmsCalloc(ContextID, nCurves, sizeof(cmsUInt16Number*)); - if (c16 ->Curves == NULL) return NULL; - - for (i=0; i < nCurves; i++) { - - c16->Curves[i] = (cmsUInt16Number*)_cmsCalloc(ContextID, nElements, sizeof(cmsUInt16Number)); - - if (c16->Curves[i] == NULL) { - - for (j=0; j < i; j++) { - _cmsFree(ContextID, c16->Curves[j]); - } - _cmsFree(ContextID, c16->Curves); - _cmsFree(ContextID, c16); - return NULL; - } - - if (nElements == 256) { - - for (j=0; j < nElements; j++) { - - c16 ->Curves[i][j] = cmsEvalToneCurve16(G[i], FROM_8_TO_16(j)); - } - } - else { - - for (j=0; j < nElements; j++) { - c16 ->Curves[i][j] = cmsEvalToneCurve16(G[i], (cmsUInt16Number) j); - } - } - } - - return c16; -} - -static -void FastEvaluateCurves8(register const cmsUInt16Number In[], - register cmsUInt16Number Out[], - register const void* D) -{ - Curves16Data* Data = (Curves16Data*) D; - cmsUInt8Number x; - int i; - - for (i=0; i < Data ->nCurves; i++) { - - x = (In[i] >> 8); - Out[i] = Data -> Curves[i][x]; - } -} - - -static -void FastEvaluateCurves16(register const cmsUInt16Number In[], - register cmsUInt16Number Out[], - register const void* D) -{ - Curves16Data* Data = (Curves16Data*) D; - int i; - - for (i=0; i < Data ->nCurves; i++) { - Out[i] = Data -> Curves[i][In[i]]; - } -} - - -static -void FastIdentity16(register const cmsUInt16Number In[], - register cmsUInt16Number Out[], - register const void* D) -{ - cmsPipeline* Lut = (cmsPipeline*) D; - cmsUInt32Number i; - - for (i=0; i < Lut ->InputChannels; i++) { - Out[i] = In[i]; - } -} - - -// If the target LUT holds only curves, the optimization procedure is to join all those -// curves together. That only works on curves and does not work on matrices. -static -cmsBool OptimizeByJoiningCurves(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) -{ - cmsToneCurve** GammaTables = NULL; - cmsFloat32Number InFloat[cmsMAXCHANNELS], OutFloat[cmsMAXCHANNELS]; - cmsUInt32Number i, j; - cmsPipeline* Src = *Lut; - cmsPipeline* Dest = NULL; - cmsStage* mpe; - cmsStage* ObtainedCurves = NULL; - - - // This is a loosy optimization! does not apply in floating-point cases - if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) return FALSE; - - // Only curves in this LUT? - for (mpe = cmsPipelineGetPtrToFirstStage(Src); - mpe != NULL; - mpe = cmsStageNext(mpe)) { - if (cmsStageType(mpe) != cmsSigCurveSetElemType) return FALSE; - } - - // Allocate an empty LUT - Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels); - if (Dest == NULL) return FALSE; - - // Create target curves - GammaTables = (cmsToneCurve**) _cmsCalloc(Src ->ContextID, Src ->InputChannels, sizeof(cmsToneCurve*)); - if (GammaTables == NULL) goto Error; - - for (i=0; i < Src ->InputChannels; i++) { - GammaTables[i] = cmsBuildTabulatedToneCurve16(Src ->ContextID, PRELINEARIZATION_POINTS, NULL); - if (GammaTables[i] == NULL) goto Error; - } - - // Compute 16 bit result by using floating point - for (i=0; i < PRELINEARIZATION_POINTS; i++) { - - for (j=0; j < Src ->InputChannels; j++) - InFloat[j] = (cmsFloat32Number) ((cmsFloat64Number) i / (PRELINEARIZATION_POINTS - 1)); - - cmsPipelineEvalFloat(InFloat, OutFloat, Src); - - for (j=0; j < Src ->InputChannels; j++) - GammaTables[j] -> Table16[i] = _cmsQuickSaturateWord(OutFloat[j] * 65535.0); - } - - ObtainedCurves = cmsStageAllocToneCurves(Src ->ContextID, Src ->InputChannels, GammaTables); - if (ObtainedCurves == NULL) goto Error; - - for (i=0; i < Src ->InputChannels; i++) { - cmsFreeToneCurve(GammaTables[i]); - GammaTables[i] = NULL; - } - - if (GammaTables != NULL) _cmsFree(Src ->ContextID, GammaTables); - - // Maybe the curves are linear at the end - if (!AllCurvesAreLinear(ObtainedCurves)) { - - if (!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, ObtainedCurves)) - goto Error; - - // If the curves are to be applied in 8 bits, we can save memory - if (_cmsFormatterIs8bit(*InputFormat)) { - - _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) ObtainedCurves ->Data; - Curves16Data* c16 = CurvesAlloc(Dest ->ContextID, Data ->nCurves, 256, Data ->TheCurves); - - if (c16 == NULL) goto Error; - *dwFlags |= cmsFLAGS_NOCACHE; - _cmsPipelineSetOptimizationParameters(Dest, FastEvaluateCurves8, c16, CurvesFree, CurvesDup); - - } - else { - - _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) cmsStageData(ObtainedCurves); - Curves16Data* c16 = CurvesAlloc(Dest ->ContextID, Data ->nCurves, 65536, Data ->TheCurves); - - if (c16 == NULL) goto Error; - *dwFlags |= cmsFLAGS_NOCACHE; - _cmsPipelineSetOptimizationParameters(Dest, FastEvaluateCurves16, c16, CurvesFree, CurvesDup); - } - } - else { - - // LUT optimizes to nothing. Set the identity LUT - cmsStageFree(ObtainedCurves); - - if (!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageAllocIdentity(Dest ->ContextID, Src ->InputChannels))) - goto Error; - - *dwFlags |= cmsFLAGS_NOCACHE; - _cmsPipelineSetOptimizationParameters(Dest, FastIdentity16, (void*) Dest, NULL, NULL); - } - - // We are done. - cmsPipelineFree(Src); - *Lut = Dest; - return TRUE; - -Error: - - if (ObtainedCurves != NULL) cmsStageFree(ObtainedCurves); - if (GammaTables != NULL) { - for (i=0; i < Src ->InputChannels; i++) { - if (GammaTables[i] != NULL) cmsFreeToneCurve(GammaTables[i]); - } - - _cmsFree(Src ->ContextID, GammaTables); - } - - if (Dest != NULL) cmsPipelineFree(Dest); - return FALSE; - - cmsUNUSED_PARAMETER(Intent); - cmsUNUSED_PARAMETER(InputFormat); - cmsUNUSED_PARAMETER(OutputFormat); - cmsUNUSED_PARAMETER(dwFlags); -} - -// ------------------------------------------------------------------------------------------------------------------------------------- -// LUT is Shaper - Matrix - Matrix - Shaper, which is very frequent when combining two matrix-shaper profiles - - -static -void FreeMatShaper(cmsContext ContextID, void* Data) -{ - if (Data != NULL) _cmsFree(ContextID, Data); -} - -static -void* DupMatShaper(cmsContext ContextID, const void* Data) -{ - return _cmsDupMem(ContextID, Data, sizeof(MatShaper8Data)); -} - - -// A fast matrix-shaper evaluator for 8 bits. This is a bit ticky since I'm using 1.14 signed fixed point -// to accomplish some performance. Actually it takes 256x3 16 bits tables and 16385 x 3 tables of 8 bits, -// in total about 50K, and the performance boost is huge! -static -void MatShaperEval16(register const cmsUInt16Number In[], - register cmsUInt16Number Out[], - register const void* D) -{ - MatShaper8Data* p = (MatShaper8Data*) D; - cmsS1Fixed14Number l1, l2, l3, r, g, b; - cmsUInt32Number ri, gi, bi; - - // In this case (and only in this case!) we can use this simplification since - // In[] is assured to come from a 8 bit number. (a << 8 | a) - ri = In[0] & 0xFF; - gi = In[1] & 0xFF; - bi = In[2] & 0xFF; - - // Across first shaper, which also converts to 1.14 fixed point - r = p->Shaper1R[ri]; - g = p->Shaper1G[gi]; - b = p->Shaper1B[bi]; - - // Evaluate the matrix in 1.14 fixed point - l1 = (p->Mat[0][0] * r + p->Mat[0][1] * g + p->Mat[0][2] * b + p->Off[0] + 0x2000) >> 14; - l2 = (p->Mat[1][0] * r + p->Mat[1][1] * g + p->Mat[1][2] * b + p->Off[1] + 0x2000) >> 14; - l3 = (p->Mat[2][0] * r + p->Mat[2][1] * g + p->Mat[2][2] * b + p->Off[2] + 0x2000) >> 14; - - // Now we have to clip to 0..1.0 range - ri = (l1 < 0) ? 0 : ((l1 > 16384) ? 16384 : l1); - gi = (l2 < 0) ? 0 : ((l2 > 16384) ? 16384 : l2); - bi = (l3 < 0) ? 0 : ((l3 > 16384) ? 16384 : l3); - - // And across second shaper, - Out[0] = p->Shaper2R[ri]; - Out[1] = p->Shaper2G[gi]; - Out[2] = p->Shaper2B[bi]; - -} - -// This table converts from 8 bits to 1.14 after applying the curve -static -cmsBool FillFirstShaper(cmsS1Fixed14Number* Table, cmsToneCurve* Curve) -{ - int i; - cmsFloat32Number R, y; - - for (i=0; i < 256; i++) { - - R = (cmsFloat32Number) (i / 255.0); - y = cmsEvalToneCurveFloat(Curve, R); - if (isinf(y)) - return FALSE; - - Table[i] = DOUBLE_TO_1FIXED14(y); - } - return TRUE; -} - -// This table converts form 1.14 (being 0x4000 the last entry) to 8 bits after applying the curve -static -cmsBool FillSecondShaper(cmsUInt16Number* Table, cmsToneCurve* Curve, cmsBool Is8BitsOutput) -{ - int i; - cmsFloat32Number R, Val; - - for (i=0; i < 16385; i++) { - - R = (cmsFloat32Number) (i / 16384.0); - Val = cmsEvalToneCurveFloat(Curve, R); // Val comes 0..1.0 - if (isinf(Val)) - return FALSE; - - if (Is8BitsOutput) { - - // If 8 bits output, we can optimize further by computing the / 257 part. - // first we compute the resulting byte and then we store the byte times - // 257. This quantization allows to round very quick by doing a >> 8, but - // since the low byte is always equal to msb, we can do a & 0xff and this works! - cmsUInt16Number w = _cmsQuickSaturateWord(Val * 65535.0); - cmsUInt8Number b = FROM_16_TO_8(w); - - Table[i] = FROM_8_TO_16(b); - } - else Table[i] = _cmsQuickSaturateWord(Val * 65535.0); - } - return TRUE; -} - -// Compute the matrix-shaper structure -static -cmsBool SetMatShaper(cmsPipeline* Dest, cmsToneCurve* Curve1[3], cmsMAT3* Mat, cmsVEC3* Off, cmsToneCurve* Curve2[3], cmsUInt32Number* OutputFormat) -{ - MatShaper8Data* p; - int i, j; - cmsBool Is8Bits = _cmsFormatterIs8bit(*OutputFormat); - - // Allocate a big chuck of memory to store precomputed tables - p = (MatShaper8Data*) _cmsMalloc(Dest ->ContextID, sizeof(MatShaper8Data)); - if (p == NULL) return FALSE; - - p -> ContextID = Dest -> ContextID; - - // Precompute tables - if (!FillFirstShaper(p ->Shaper1R, Curve1[0])) - goto Error; - if (!FillFirstShaper(p ->Shaper1G, Curve1[1])) - goto Error; - if (!FillFirstShaper(p ->Shaper1B, Curve1[2])) - goto Error; - - if (!FillSecondShaper(p ->Shaper2R, Curve2[0], Is8Bits)) - goto Error; - if (!FillSecondShaper(p ->Shaper2G, Curve2[1], Is8Bits)) - goto Error; - if (!FillSecondShaper(p ->Shaper2B, Curve2[2], Is8Bits)) - goto Error; - - // Convert matrix to nFixed14. Note that those values may take more than 16 bits as - for (i=0; i < 3; i++) { - for (j=0; j < 3; j++) { - p ->Mat[i][j] = DOUBLE_TO_1FIXED14(Mat->v[i].n[j]); - } - } - - for (i=0; i < 3; i++) { - - if (Off == NULL) { - p ->Off[i] = 0; - } - else { - p ->Off[i] = DOUBLE_TO_1FIXED14(Off->n[i]); - } - } - - // Mark as optimized for faster formatter - if (Is8Bits) - *OutputFormat |= OPTIMIZED_SH(1); - - // Fill function pointers - _cmsPipelineSetOptimizationParameters(Dest, MatShaperEval16, (void*) p, FreeMatShaper, DupMatShaper); - return TRUE; -Error: - _cmsFree(Dest->ContextID, p); - return FALSE; -} - -// 8 bits on input allows matrix-shaper boot up to 25 Mpixels per second on RGB. That's fast! -// TODO: Allow a third matrix for abs. colorimetric -static -cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) -{ - cmsStage* Curve1, *Curve2; - cmsStage* Matrix1, *Matrix2; - _cmsStageMatrixData* Data1; - _cmsStageMatrixData* Data2; - cmsMAT3 res; - cmsBool IdentityMat; - cmsPipeline* Dest, *Src; - - // Only works on RGB to RGB - if (T_CHANNELS(*InputFormat) != 3 || T_CHANNELS(*OutputFormat) != 3) return FALSE; - - // Only works on 8 bit input - if (!_cmsFormatterIs8bit(*InputFormat)) return FALSE; - - // Seems suitable, proceed - Src = *Lut; - - // Check for shaper-matrix-matrix-shaper structure, that is what this optimizer stands for - if (!cmsPipelineCheckAndRetreiveStages(Src, 4, - cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, - &Curve1, &Matrix1, &Matrix2, &Curve2)) return FALSE; - - // Get both matrices - Data1 = (_cmsStageMatrixData*) cmsStageData(Matrix1); - Data2 = (_cmsStageMatrixData*) cmsStageData(Matrix2); - - // Input offset should be zero - if (Data1 ->Offset != NULL) return FALSE; - - // Multiply both matrices to get the result - _cmsMAT3per(&res, (cmsMAT3*) Data2 ->Double, (cmsMAT3*) Data1 ->Double); - - // Now the result is in res + Data2 -> Offset. Maybe is a plain identity? - IdentityMat = FALSE; - if (_cmsMAT3isIdentity(&res) && Data2 ->Offset == NULL) { - - // We can get rid of full matrix - IdentityMat = TRUE; - } - - // Allocate an empty LUT - Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels); - if (!Dest) return FALSE; - - // Assamble the new LUT - if (!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageDup(Curve1))) - goto Error; - - if (!IdentityMat) - if (!cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageAllocMatrix(Dest ->ContextID, 3, 3, (const cmsFloat64Number*) &res, Data2 ->Offset))) - goto Error; - if (!cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageDup(Curve2))) - goto Error; - - // If identity on matrix, we can further optimize the curves, so call the join curves routine - if (IdentityMat) { - - OptimizeByJoiningCurves(&Dest, Intent, InputFormat, OutputFormat, dwFlags); - } - else { - _cmsStageToneCurvesData* mpeC1 = (_cmsStageToneCurvesData*) cmsStageData(Curve1); - _cmsStageToneCurvesData* mpeC2 = (_cmsStageToneCurvesData*) cmsStageData(Curve2); - - // In this particular optimization, cach?does not help as it takes more time to deal with - // the cach?that with the pixel handling - *dwFlags |= cmsFLAGS_NOCACHE; - - // Setup the optimizarion routines - if (!SetMatShaper(Dest, mpeC1 ->TheCurves, &res, (cmsVEC3*) Data2 ->Offset, mpeC2->TheCurves, OutputFormat)) - goto Error; - } - - cmsPipelineFree(Src); - *Lut = Dest; - return TRUE; -Error: - // Leave Src unchanged - cmsPipelineFree(Dest); - return FALSE; -} - - -// ------------------------------------------------------------------------------------------------------------------------------------- -// Optimization plug-ins - -// List of optimizations -typedef struct _cmsOptimizationCollection_st { - - _cmsOPToptimizeFn OptimizePtr; - - struct _cmsOptimizationCollection_st *Next; - -} _cmsOptimizationCollection; - - -// The built-in list. We currently implement 4 types of optimizations. Joining of curves, matrix-shaper, linearization and resampling -static _cmsOptimizationCollection DefaultOptimization[] = { - - { OptimizeByJoiningCurves, &DefaultOptimization[1] }, - { OptimizeMatrixShaper, &DefaultOptimization[2] }, - { OptimizeByComputingLinearization, &DefaultOptimization[3] }, - { OptimizeByResampling, NULL } -}; - -// The linked list head -_cmsOptimizationPluginChunkType _cmsOptimizationPluginChunk = { NULL }; - - -// Duplicates the zone of memory used by the plug-in in the new context -static -void DupPluginOptimizationList(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src) -{ - _cmsOptimizationPluginChunkType newHead = { NULL }; - _cmsOptimizationCollection* entry; - _cmsOptimizationCollection* Anterior = NULL; - _cmsOptimizationPluginChunkType* head = (_cmsOptimizationPluginChunkType*) src->chunks[OptimizationPlugin]; - - _cmsAssert(ctx != NULL); - _cmsAssert(head != NULL); - - // Walk the list copying all nodes - for (entry = head->OptimizationCollection; - entry != NULL; - entry = entry ->Next) { - - _cmsOptimizationCollection *newEntry = ( _cmsOptimizationCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsOptimizationCollection)); - - if (newEntry == NULL) - return; - - // We want to keep the linked list order, so this is a little bit tricky - newEntry -> Next = NULL; - if (Anterior) - Anterior -> Next = newEntry; - - Anterior = newEntry; - - if (newHead.OptimizationCollection == NULL) - newHead.OptimizationCollection = newEntry; - } - - ctx ->chunks[OptimizationPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsOptimizationPluginChunkType)); -} - -void _cmsAllocOptimizationPluginChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src) -{ - if (src != NULL) { - - // Copy all linked list - DupPluginOptimizationList(ctx, src); - } - else { - static _cmsOptimizationPluginChunkType OptimizationPluginChunkType = { NULL }; - ctx ->chunks[OptimizationPlugin] = _cmsSubAllocDup(ctx ->MemPool, &OptimizationPluginChunkType, sizeof(_cmsOptimizationPluginChunkType)); - } -} - - -// Register new ways to optimize -cmsBool _cmsRegisterOptimizationPlugin(cmsContext ContextID, cmsPluginBase* Data) -{ - cmsPluginOptimization* Plugin = (cmsPluginOptimization*) Data; - _cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin); - _cmsOptimizationCollection* fl; - - if (Data == NULL) { - - ctx->OptimizationCollection = NULL; - return TRUE; - } - - // Optimizer callback is required - if (Plugin ->OptimizePtr == NULL) return FALSE; - - fl = (_cmsOptimizationCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsOptimizationCollection)); - if (fl == NULL) return FALSE; - - // Copy the parameters - fl ->OptimizePtr = Plugin ->OptimizePtr; - - // Keep linked list - fl ->Next = ctx->OptimizationCollection; - - // Set the head - ctx ->OptimizationCollection = fl; - - // All is ok - return TRUE; -} - -// The entry point for LUT optimization -cmsBool _cmsOptimizePipeline(cmsContext ContextID, - cmsPipeline** PtrLut, - int Intent, - cmsUInt32Number* InputFormat, - cmsUInt32Number* OutputFormat, - cmsUInt32Number* dwFlags) -{ - _cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin); - _cmsOptimizationCollection* Opts; - cmsBool AnySuccess = FALSE; - - // A CLUT is being asked, so force this specific optimization - if (*dwFlags & cmsFLAGS_FORCE_CLUT) { - - PreOptimize(*PtrLut); - return OptimizeByResampling(PtrLut, Intent, InputFormat, OutputFormat, dwFlags); - } - - // Anything to optimize? - if ((*PtrLut) ->Elements == NULL) { - _cmsPipelineSetOptimizationParameters(*PtrLut, FastIdentity16, (void*) *PtrLut, NULL, NULL); - return TRUE; - } - - // Try to get rid of identities and trivial conversions. - AnySuccess = PreOptimize(*PtrLut); - - // After removal do we end with an identity? - if ((*PtrLut) ->Elements == NULL) { - _cmsPipelineSetOptimizationParameters(*PtrLut, FastIdentity16, (void*) *PtrLut, NULL, NULL); - return TRUE; - } - - // Do not optimize, keep all precision - if (*dwFlags & cmsFLAGS_NOOPTIMIZE) - return FALSE; - - // Try plug-in optimizations - for (Opts = ctx->OptimizationCollection; - Opts != NULL; - Opts = Opts ->Next) { - - // If one schema succeeded, we are done - if (Opts ->OptimizePtr(PtrLut, Intent, InputFormat, OutputFormat, dwFlags)) { - - return TRUE; // Optimized! - } - } - - // Try built-in optimizations - for (Opts = DefaultOptimization; - Opts != NULL; - Opts = Opts ->Next) { - - if (Opts ->OptimizePtr(PtrLut, Intent, InputFormat, OutputFormat, dwFlags)) { - - return TRUE; - } - } - - // Only simple optimizations succeeded - return AnySuccess; -} diff --git a/third_party/lcms2-2.6/src/cmspack.c b/third_party/lcms2-2.6/src/cmspack.c deleted file mode 100644 index 9323b53ec5..0000000000 --- a/third_party/lcms2-2.6/src/cmspack.c +++ /dev/null @@ -1,3369 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- -// -#include "lcms2_internal.h" - -// This module handles all formats supported by lcms. There are two flavors, 16 bits and -// floating point. Floating point is supported only in a subset, those formats holding -// cmsFloat32Number (4 bytes per component) and double (marked as 0 bytes per component -// as special case) - -// --------------------------------------------------------------------------- - - -// This macro return words stored as big endian -#define CHANGE_ENDIAN(w) (cmsUInt16Number) ((cmsUInt16Number) ((w)<<8)|((w)>>8)) - -// These macros handles reversing (negative) -#define REVERSE_FLAVOR_8(x) ((cmsUInt8Number) (0xff-(x))) -#define REVERSE_FLAVOR_16(x) ((cmsUInt16Number)(0xffff-(x))) - -// * 0xffff / 0xff00 = (255 * 257) / (255 * 256) = 257 / 256 -cmsINLINE cmsUInt16Number FomLabV2ToLabV4(cmsUInt16Number x) -{ - int a = (x << 8 | x) >> 8; // * 257 / 256 - if ( a > 0xffff) return 0xffff; - return (cmsUInt16Number) a; -} - -// * 0xf00 / 0xffff = * 256 / 257 -cmsINLINE cmsUInt16Number FomLabV4ToLabV2(cmsUInt16Number x) -{ - return (cmsUInt16Number) (((x << 8) + 0x80) / 257); -} - - -typedef struct { - cmsUInt32Number Type; - cmsUInt32Number Mask; - cmsFormatter16 Frm; - -} cmsFormatters16; - -typedef struct { - cmsUInt32Number Type; - cmsUInt32Number Mask; - cmsFormatterFloat Frm; - -} cmsFormattersFloat; - - -#define ANYSPACE COLORSPACE_SH(31) -#define ANYCHANNELS CHANNELS_SH(15) -#define ANYEXTRA EXTRA_SH(7) -#define ANYPLANAR PLANAR_SH(1) -#define ANYENDIAN ENDIAN16_SH(1) -#define ANYSWAP DOSWAP_SH(1) -#define ANYSWAPFIRST SWAPFIRST_SH(1) -#define ANYFLAVOR FLAVOR_SH(1) - - -// Supress waning about info never being used - -#ifdef _MSC_VER -#pragma warning(disable : 4100) -#endif - -// Unpacking routines (16 bits) ---------------------------------------------------------------------------------------- - - -// Does almost everything but is slow -static -cmsUInt8Number* UnrollChunkyBytes(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - int nChan = T_CHANNELS(info -> InputFormat); - int DoSwap = T_DOSWAP(info ->InputFormat); - int Reverse = T_FLAVOR(info ->InputFormat); - int SwapFirst = T_SWAPFIRST(info -> InputFormat); - int Extra = T_EXTRA(info -> InputFormat); - int ExtraFirst = DoSwap ^ SwapFirst; - cmsUInt16Number v; - int i; - - if (ExtraFirst) { - accum += Extra; - } - - for (i=0; i < nChan; i++) { - int index = DoSwap ? (nChan - i - 1) : i; - - v = FROM_8_TO_16(*accum); - v = Reverse ? REVERSE_FLAVOR_16(v) : v; - wIn[index] = v; - accum++; - } - - if (!ExtraFirst) { - accum += Extra; - } - - if (Extra == 0 && SwapFirst) { - cmsUInt16Number tmp = wIn[0]; - - memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number)); - wIn[nChan-1] = tmp; - } - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); - -} - -// Extra channels are just ignored because come in the next planes -static -cmsUInt8Number* UnrollPlanarBytes(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - int nChan = T_CHANNELS(info -> InputFormat); - int DoSwap = T_DOSWAP(info ->InputFormat); - int SwapFirst = T_SWAPFIRST(info ->InputFormat); - int Reverse = T_FLAVOR(info ->InputFormat); - int i; - cmsUInt8Number* Init = accum; - - if (DoSwap ^ SwapFirst) { - accum += T_EXTRA(info -> InputFormat) * Stride; - } - - for (i=0; i < nChan; i++) { - - int index = DoSwap ? (nChan - i - 1) : i; - cmsUInt16Number v = FROM_8_TO_16(*accum); - - wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v; - accum += Stride; - } - - return (Init + 1); -} - -// Special cases, provided for performance -static -cmsUInt8Number* Unroll4Bytes(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[0] = FROM_8_TO_16(*accum); accum++; // C - wIn[1] = FROM_8_TO_16(*accum); accum++; // M - wIn[2] = FROM_8_TO_16(*accum); accum++; // Y - wIn[3] = FROM_8_TO_16(*accum); accum++; // K - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Unroll4BytesReverse(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[0] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // C - wIn[1] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // M - wIn[2] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // Y - wIn[3] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // K - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Unroll4BytesSwapFirst(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[3] = FROM_8_TO_16(*accum); accum++; // K - wIn[0] = FROM_8_TO_16(*accum); accum++; // C - wIn[1] = FROM_8_TO_16(*accum); accum++; // M - wIn[2] = FROM_8_TO_16(*accum); accum++; // Y - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -// KYMC -static -cmsUInt8Number* Unroll4BytesSwap(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[3] = FROM_8_TO_16(*accum); accum++; // K - wIn[2] = FROM_8_TO_16(*accum); accum++; // Y - wIn[1] = FROM_8_TO_16(*accum); accum++; // M - wIn[0] = FROM_8_TO_16(*accum); accum++; // C - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Unroll4BytesSwapSwapFirst(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[2] = FROM_8_TO_16(*accum); accum++; // K - wIn[1] = FROM_8_TO_16(*accum); accum++; // Y - wIn[0] = FROM_8_TO_16(*accum); accum++; // M - wIn[3] = FROM_8_TO_16(*accum); accum++; // C - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Unroll3Bytes(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[0] = FROM_8_TO_16(*accum); accum++; // R - wIn[1] = FROM_8_TO_16(*accum); accum++; // G - wIn[2] = FROM_8_TO_16(*accum); accum++; // B - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Unroll3BytesSkip1Swap(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - accum++; // A - wIn[2] = FROM_8_TO_16(*accum); accum++; // B - wIn[1] = FROM_8_TO_16(*accum); accum++; // G - wIn[0] = FROM_8_TO_16(*accum); accum++; // R - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Unroll3BytesSkip1SwapSwapFirst(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[2] = FROM_8_TO_16(*accum); accum++; // B - wIn[1] = FROM_8_TO_16(*accum); accum++; // G - wIn[0] = FROM_8_TO_16(*accum); accum++; // R - accum++; // A - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Unroll3BytesSkip1SwapFirst(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - accum++; // A - wIn[0] = FROM_8_TO_16(*accum); accum++; // R - wIn[1] = FROM_8_TO_16(*accum); accum++; // G - wIn[2] = FROM_8_TO_16(*accum); accum++; // B - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - - -// BRG -static -cmsUInt8Number* Unroll3BytesSwap(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[2] = FROM_8_TO_16(*accum); accum++; // B - wIn[1] = FROM_8_TO_16(*accum); accum++; // G - wIn[0] = FROM_8_TO_16(*accum); accum++; // R - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* UnrollLabV2_8(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[0] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // L - wIn[1] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // a - wIn[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // b - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* UnrollALabV2_8(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - accum++; // A - wIn[0] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // L - wIn[1] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // a - wIn[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // b - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* UnrollLabV2_16(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[0] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2; // L - wIn[1] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2; // a - wIn[2] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2; // b - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -// for duplex -static -cmsUInt8Number* Unroll2Bytes(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[0] = FROM_8_TO_16(*accum); accum++; // ch1 - wIn[1] = FROM_8_TO_16(*accum); accum++; // ch2 - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - - - - -// Monochrome duplicates L into RGB for null-transforms -static -cmsUInt8Number* Unroll1Byte(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++; // L - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - - -static -cmsUInt8Number* Unroll1ByteSkip1(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++; // L - accum += 1; - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Unroll1ByteSkip2(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++; // L - accum += 2; - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Unroll1ByteReversed(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[0] = wIn[1] = wIn[2] = REVERSE_FLAVOR_16(FROM_8_TO_16(*accum)); accum++; // L - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - - -static -cmsUInt8Number* UnrollAnyWords(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - int nChan = T_CHANNELS(info -> InputFormat); - int SwapEndian = T_ENDIAN16(info -> InputFormat); - int DoSwap = T_DOSWAP(info ->InputFormat); - int Reverse = T_FLAVOR(info ->InputFormat); - int SwapFirst = T_SWAPFIRST(info -> InputFormat); - int Extra = T_EXTRA(info -> InputFormat); - int ExtraFirst = DoSwap ^ SwapFirst; - int i; - - if (ExtraFirst) { - accum += Extra * sizeof(cmsUInt16Number); - } - - for (i=0; i < nChan; i++) { - - int index = DoSwap ? (nChan - i - 1) : i; - cmsUInt16Number v = *(cmsUInt16Number*) accum; - - if (SwapEndian) - v = CHANGE_ENDIAN(v); - - wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v; - - accum += sizeof(cmsUInt16Number); - } - - if (!ExtraFirst) { - accum += Extra * sizeof(cmsUInt16Number); - } - - if (Extra == 0 && SwapFirst) { - - cmsUInt16Number tmp = wIn[0]; - - memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number)); - wIn[nChan-1] = tmp; - } - - return accum; - - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* UnrollPlanarWords(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - int nChan = T_CHANNELS(info -> InputFormat); - int DoSwap= T_DOSWAP(info ->InputFormat); - int Reverse= T_FLAVOR(info ->InputFormat); - int SwapEndian = T_ENDIAN16(info -> InputFormat); - int i; - cmsUInt8Number* Init = accum; - - if (DoSwap) { - accum += T_EXTRA(info -> InputFormat) * Stride * sizeof(cmsUInt16Number); - } - - for (i=0; i < nChan; i++) { - - int index = DoSwap ? (nChan - i - 1) : i; - cmsUInt16Number v = *(cmsUInt16Number*) accum; - - if (SwapEndian) - v = CHANGE_ENDIAN(v); - - wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v; - - accum += Stride * sizeof(cmsUInt16Number); - } - - return (Init + sizeof(cmsUInt16Number)); -} - - -static -cmsUInt8Number* Unroll4Words(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C - wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M - wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y - wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // K - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Unroll4WordsReverse(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[0] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // C - wIn[1] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // M - wIn[2] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // Y - wIn[3] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // K - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Unroll4WordsSwapFirst(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // K - wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C - wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M - wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -// KYMC -static -cmsUInt8Number* Unroll4WordsSwap(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // K - wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y - wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M - wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Unroll4WordsSwapSwapFirst(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // K - wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // Y - wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // M - wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // C - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Unroll3Words(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C R - wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M G - wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y B - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Unroll3WordsSwap(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // C R - wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M G - wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // Y B - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Unroll3WordsSkip1Swap(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - accum += 2; // A - wIn[2] = *(cmsUInt16Number*) accum; accum += 2; // R - wIn[1] = *(cmsUInt16Number*) accum; accum += 2; // G - wIn[0] = *(cmsUInt16Number*) accum; accum += 2; // B - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Unroll3WordsSkip1SwapFirst(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - accum += 2; // A - wIn[0] = *(cmsUInt16Number*) accum; accum += 2; // R - wIn[1] = *(cmsUInt16Number*) accum; accum += 2; // G - wIn[2] = *(cmsUInt16Number*) accum; accum += 2; // B - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Unroll1Word(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // L - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Unroll1WordReversed(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[0] = wIn[1] = wIn[2] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Unroll1WordSkip3(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum; - - accum += 8; - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Unroll2Words(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[0] = *(cmsUInt16Number*) accum; accum += 2; // ch1 - wIn[1] = *(cmsUInt16Number*) accum; accum += 2; // ch2 - - return accum; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - - -// This is a conversion of Lab double to 16 bits -static -cmsUInt8Number* UnrollLabDoubleTo16(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - if (T_PLANAR(info -> InputFormat)) { - - cmsFloat64Number* Pt = (cmsFloat64Number*) accum; - - cmsCIELab Lab; - - Lab.L = Pt[0]; - Lab.a = Pt[Stride]; - Lab.b = Pt[Stride*2]; - - cmsFloat2LabEncoded(wIn, &Lab); - return accum + sizeof(cmsFloat64Number); - } - else { - - cmsFloat2LabEncoded(wIn, (cmsCIELab*) accum); - accum += sizeof(cmsCIELab) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat64Number); - return accum; - } -} - - -// This is a conversion of Lab float to 16 bits -static -cmsUInt8Number* UnrollLabFloatTo16(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - cmsCIELab Lab; - - if (T_PLANAR(info -> InputFormat)) { - - cmsFloat32Number* Pt = (cmsFloat32Number*) accum; - - - Lab.L = Pt[0]; - Lab.a = Pt[Stride]; - Lab.b = Pt[Stride*2]; - - cmsFloat2LabEncoded(wIn, &Lab); - return accum + sizeof(cmsFloat32Number); - } - else { - - Lab.L = ((cmsFloat32Number*) accum)[0]; - Lab.a = ((cmsFloat32Number*) accum)[1]; - Lab.b = ((cmsFloat32Number*) accum)[2]; - - cmsFloat2LabEncoded(wIn, &Lab); - accum += (3 + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat32Number); - return accum; - } -} - -// This is a conversion of XYZ double to 16 bits -static -cmsUInt8Number* UnrollXYZDoubleTo16(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - if (T_PLANAR(info -> InputFormat)) { - - cmsFloat64Number* Pt = (cmsFloat64Number*) accum; - cmsCIEXYZ XYZ; - - XYZ.X = Pt[0]; - XYZ.Y = Pt[Stride]; - XYZ.Z = Pt[Stride*2]; - cmsFloat2XYZEncoded(wIn, &XYZ); - - return accum + sizeof(cmsFloat64Number); - - } - - else { - cmsFloat2XYZEncoded(wIn, (cmsCIEXYZ*) accum); - accum += sizeof(cmsCIEXYZ) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat64Number); - - return accum; - } -} - -// This is a conversion of XYZ float to 16 bits -static -cmsUInt8Number* UnrollXYZFloatTo16(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - if (T_PLANAR(info -> InputFormat)) { - - cmsFloat32Number* Pt = (cmsFloat32Number*) accum; - cmsCIEXYZ XYZ; - - XYZ.X = Pt[0]; - XYZ.Y = Pt[Stride]; - XYZ.Z = Pt[Stride*2]; - cmsFloat2XYZEncoded(wIn, &XYZ); - - return accum + sizeof(cmsFloat32Number); - - } - - else { - cmsFloat32Number* Pt = (cmsFloat32Number*) accum; - cmsCIEXYZ XYZ; - - XYZ.X = Pt[0]; - XYZ.Y = Pt[1]; - XYZ.Z = Pt[2]; - cmsFloat2XYZEncoded(wIn, &XYZ); - - accum += 3 * sizeof(cmsFloat32Number) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat32Number); - - return accum; - } -} - -// Check if space is marked as ink -cmsINLINE cmsBool IsInkSpace(cmsUInt32Number Type) -{ - switch (T_COLORSPACE(Type)) { - - case PT_CMY: - case PT_CMYK: - case PT_MCH5: - case PT_MCH6: - case PT_MCH7: - case PT_MCH8: - case PT_MCH9: - case PT_MCH10: - case PT_MCH11: - case PT_MCH12: - case PT_MCH13: - case PT_MCH14: - case PT_MCH15: return TRUE; - - default: return FALSE; - } -} - -// Inks does come in percentage, remaining cases are between 0..1.0, again to 16 bits -static -cmsUInt8Number* UnrollDoubleTo16(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - - int nChan = T_CHANNELS(info -> InputFormat); - int DoSwap = T_DOSWAP(info ->InputFormat); - int Reverse = T_FLAVOR(info ->InputFormat); - int SwapFirst = T_SWAPFIRST(info -> InputFormat); - int Extra = T_EXTRA(info -> InputFormat); - int ExtraFirst = DoSwap ^ SwapFirst; - int Planar = T_PLANAR(info -> InputFormat); - cmsFloat64Number v; - cmsUInt16Number vi; - int i, start = 0; - cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0; - - - if (ExtraFirst) - start = Extra; - - for (i=0; i < nChan; i++) { - - int index = DoSwap ? (nChan - i - 1) : i; - - if (Planar) - v = (cmsFloat32Number) ((cmsFloat64Number*) accum)[(i + start) * Stride]; - else - v = (cmsFloat32Number) ((cmsFloat64Number*) accum)[i + start]; - - vi = _cmsQuickSaturateWord(v * maximum); - - if (Reverse) - vi = REVERSE_FLAVOR_16(vi); - - wIn[index] = vi; - } - - - if (Extra == 0 && SwapFirst) { - cmsUInt16Number tmp = wIn[0]; - - memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number)); - wIn[nChan-1] = tmp; - } - - if (T_PLANAR(info -> InputFormat)) - return accum + sizeof(cmsFloat64Number); - else - return accum + (nChan + Extra) * sizeof(cmsFloat64Number); -} - - - -static -cmsUInt8Number* UnrollFloatTo16(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - - int nChan = T_CHANNELS(info -> InputFormat); - int DoSwap = T_DOSWAP(info ->InputFormat); - int Reverse = T_FLAVOR(info ->InputFormat); - int SwapFirst = T_SWAPFIRST(info -> InputFormat); - int Extra = T_EXTRA(info -> InputFormat); - int ExtraFirst = DoSwap ^ SwapFirst; - int Planar = T_PLANAR(info -> InputFormat); - cmsFloat32Number v; - cmsUInt16Number vi; - int i, start = 0; - cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0; - - - if (ExtraFirst) - start = Extra; - - for (i=0; i < nChan; i++) { - - int index = DoSwap ? (nChan - i - 1) : i; - - if (Planar) - v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[(i + start) * Stride]; - else - v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[i + start]; - - vi = _cmsQuickSaturateWord(v * maximum); - - if (Reverse) - vi = REVERSE_FLAVOR_16(vi); - - wIn[index] = vi; - } - - - if (Extra == 0 && SwapFirst) { - cmsUInt16Number tmp = wIn[0]; - - memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number)); - wIn[nChan-1] = tmp; - } - - if (T_PLANAR(info -> InputFormat)) - return accum + sizeof(cmsFloat32Number); - else - return accum + (nChan + Extra) * sizeof(cmsFloat32Number); -} - - - - -// For 1 channel, we need to duplicate data (it comes in 0..1.0 range) -static -cmsUInt8Number* UnrollDouble1Chan(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - cmsFloat64Number* Inks = (cmsFloat64Number*) accum; - - wIn[0] = wIn[1] = wIn[2] = _cmsQuickSaturateWord(Inks[0] * 65535.0); - - return accum + sizeof(cmsFloat64Number); - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -//------------------------------------------------------------------------------------------------------------------- - -// For anything going from cmsFloat32Number -static -cmsUInt8Number* UnrollFloatsToFloat(_cmsTRANSFORM* info, - cmsFloat32Number wIn[], - cmsUInt8Number* accum, - cmsUInt32Number Stride) -{ - - int nChan = T_CHANNELS(info -> InputFormat); - int DoSwap = T_DOSWAP(info ->InputFormat); - int Reverse = T_FLAVOR(info ->InputFormat); - int SwapFirst = T_SWAPFIRST(info -> InputFormat); - int Extra = T_EXTRA(info -> InputFormat); - int ExtraFirst = DoSwap ^ SwapFirst; - int Planar = T_PLANAR(info -> InputFormat); - cmsFloat32Number v; - int i, start = 0; - cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 100.0F : 1.0F; - - - if (ExtraFirst) - start = Extra; - - for (i=0; i < nChan; i++) { - - int index = DoSwap ? (nChan - i - 1) : i; - - if (Planar) - v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[(i + start) * Stride]; - else - v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[i + start]; - - v /= maximum; - - wIn[index] = Reverse ? 1 - v : v; - } - - - if (Extra == 0 && SwapFirst) { - cmsFloat32Number tmp = wIn[0]; - - memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsFloat32Number)); - wIn[nChan-1] = tmp; - } - - if (T_PLANAR(info -> InputFormat)) - return accum + sizeof(cmsFloat32Number); - else - return accum + (nChan + Extra) * sizeof(cmsFloat32Number); -} - -// For anything going from double - -static -cmsUInt8Number* UnrollDoublesToFloat(_cmsTRANSFORM* info, - cmsFloat32Number wIn[], - cmsUInt8Number* accum, - cmsUInt32Number Stride) -{ - - int nChan = T_CHANNELS(info -> InputFormat); - int DoSwap = T_DOSWAP(info ->InputFormat); - int Reverse = T_FLAVOR(info ->InputFormat); - int SwapFirst = T_SWAPFIRST(info -> InputFormat); - int Extra = T_EXTRA(info -> InputFormat); - int ExtraFirst = DoSwap ^ SwapFirst; - int Planar = T_PLANAR(info -> InputFormat); - cmsFloat64Number v; - int i, start = 0; - cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 100.0 : 1.0; - - - if (ExtraFirst) - start = Extra; - - for (i=0; i < nChan; i++) { - - int index = DoSwap ? (nChan - i - 1) : i; - - if (Planar) - v = (cmsFloat64Number) ((cmsFloat64Number*) accum)[(i + start) * Stride]; - else - v = (cmsFloat64Number) ((cmsFloat64Number*) accum)[i + start]; - - v /= maximum; - - wIn[index] = (cmsFloat32Number) (Reverse ? 1.0 - v : v); - } - - - if (Extra == 0 && SwapFirst) { - cmsFloat32Number tmp = wIn[0]; - - memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsFloat32Number)); - wIn[nChan-1] = tmp; - } - - if (T_PLANAR(info -> InputFormat)) - return accum + sizeof(cmsFloat64Number); - else - return accum + (nChan + Extra) * sizeof(cmsFloat64Number); -} - - - -// From Lab double to cmsFloat32Number -static -cmsUInt8Number* UnrollLabDoubleToFloat(_cmsTRANSFORM* info, - cmsFloat32Number wIn[], - cmsUInt8Number* accum, - cmsUInt32Number Stride) -{ - cmsFloat64Number* Pt = (cmsFloat64Number*) accum; - - if (T_PLANAR(info -> InputFormat)) { - - wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1 - wIn[1] = (cmsFloat32Number) ((Pt[Stride] + 128) / 255.0); // form -128..+127 to 0..1 - wIn[2] = (cmsFloat32Number) ((Pt[Stride*2] + 128) / 255.0); - - return accum + sizeof(cmsFloat64Number); - } - else { - - wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1 - wIn[1] = (cmsFloat32Number) ((Pt[1] + 128) / 255.0); // form -128..+127 to 0..1 - wIn[2] = (cmsFloat32Number) ((Pt[2] + 128) / 255.0); - - accum += sizeof(cmsFloat64Number)*(3 + T_EXTRA(info ->InputFormat)); - return accum; - } -} - -// From Lab double to cmsFloat32Number -static -cmsUInt8Number* UnrollLabFloatToFloat(_cmsTRANSFORM* info, - cmsFloat32Number wIn[], - cmsUInt8Number* accum, - cmsUInt32Number Stride) -{ - cmsFloat32Number* Pt = (cmsFloat32Number*) accum; - - if (T_PLANAR(info -> InputFormat)) { - - wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1 - wIn[1] = (cmsFloat32Number) ((Pt[Stride] + 128) / 255.0); // form -128..+127 to 0..1 - wIn[2] = (cmsFloat32Number) ((Pt[Stride*2] + 128) / 255.0); - - return accum + sizeof(cmsFloat32Number); - } - else { - - wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1 - wIn[1] = (cmsFloat32Number) ((Pt[1] + 128) / 255.0); // form -128..+127 to 0..1 - wIn[2] = (cmsFloat32Number) ((Pt[2] + 128) / 255.0); - - accum += sizeof(cmsFloat32Number)*(3 + T_EXTRA(info ->InputFormat)); - return accum; - } -} - - - -// 1.15 fixed point, that means maximum value is MAX_ENCODEABLE_XYZ (0xFFFF) -static -cmsUInt8Number* UnrollXYZDoubleToFloat(_cmsTRANSFORM* info, - cmsFloat32Number wIn[], - cmsUInt8Number* accum, - cmsUInt32Number Stride) -{ - cmsFloat64Number* Pt = (cmsFloat64Number*) accum; - - if (T_PLANAR(info -> InputFormat)) { - - wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ); - wIn[1] = (cmsFloat32Number) (Pt[Stride] / MAX_ENCODEABLE_XYZ); - wIn[2] = (cmsFloat32Number) (Pt[Stride*2] / MAX_ENCODEABLE_XYZ); - - return accum + sizeof(cmsFloat64Number); - } - else { - - wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ); - wIn[1] = (cmsFloat32Number) (Pt[1] / MAX_ENCODEABLE_XYZ); - wIn[2] = (cmsFloat32Number) (Pt[2] / MAX_ENCODEABLE_XYZ); - - accum += sizeof(cmsFloat64Number)*(3 + T_EXTRA(info ->InputFormat)); - return accum; - } -} - -static -cmsUInt8Number* UnrollXYZFloatToFloat(_cmsTRANSFORM* info, - cmsFloat32Number wIn[], - cmsUInt8Number* accum, - cmsUInt32Number Stride) -{ - cmsFloat32Number* Pt = (cmsFloat32Number*) accum; - - if (T_PLANAR(info -> InputFormat)) { - - wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ); - wIn[1] = (cmsFloat32Number) (Pt[Stride] / MAX_ENCODEABLE_XYZ); - wIn[2] = (cmsFloat32Number) (Pt[Stride*2] / MAX_ENCODEABLE_XYZ); - - return accum + sizeof(cmsFloat32Number); - } - else { - - wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ); - wIn[1] = (cmsFloat32Number) (Pt[1] / MAX_ENCODEABLE_XYZ); - wIn[2] = (cmsFloat32Number) (Pt[2] / MAX_ENCODEABLE_XYZ); - - accum += sizeof(cmsFloat32Number)*(3 + T_EXTRA(info ->InputFormat)); - return accum; - } -} - - - -// Packing routines ----------------------------------------------------------------------------------------------------------- - - -// Generic chunky for byte - -static -cmsUInt8Number* PackAnyBytes(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - int nChan = T_CHANNELS(info -> OutputFormat); - int DoSwap = T_DOSWAP(info ->OutputFormat); - int Reverse = T_FLAVOR(info ->OutputFormat); - int Extra = T_EXTRA(info -> OutputFormat); - int SwapFirst = T_SWAPFIRST(info -> OutputFormat); - int ExtraFirst = DoSwap ^ SwapFirst; - cmsUInt8Number* swap1; - cmsUInt8Number v = 0; - int i; - - swap1 = output; - - if (ExtraFirst) { - output += Extra; - } - - for (i=0; i < nChan; i++) { - - int index = DoSwap ? (nChan - i - 1) : i; - - v = FROM_16_TO_8(wOut[index]); - - if (Reverse) - v = REVERSE_FLAVOR_8(v); - - *output++ = v; - } - - if (!ExtraFirst) { - output += Extra; - } - - if (Extra == 0 && SwapFirst) { - - memmove(swap1 + 1, swap1, nChan-1); - *swap1 = v; - } - - - return output; - - cmsUNUSED_PARAMETER(Stride); -} - - - -static -cmsUInt8Number* PackAnyWords(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - int nChan = T_CHANNELS(info -> OutputFormat); - int SwapEndian = T_ENDIAN16(info -> InputFormat); - int DoSwap = T_DOSWAP(info ->OutputFormat); - int Reverse = T_FLAVOR(info ->OutputFormat); - int Extra = T_EXTRA(info -> OutputFormat); - int SwapFirst = T_SWAPFIRST(info -> OutputFormat); - int ExtraFirst = DoSwap ^ SwapFirst; - cmsUInt16Number* swap1; - cmsUInt16Number v = 0; - int i; - - swap1 = (cmsUInt16Number*) output; - - if (ExtraFirst) { - output += Extra * sizeof(cmsUInt16Number); - } - - for (i=0; i < nChan; i++) { - - int index = DoSwap ? (nChan - i - 1) : i; - - v = wOut[index]; - - if (SwapEndian) - v = CHANGE_ENDIAN(v); - - if (Reverse) - v = REVERSE_FLAVOR_16(v); - - *(cmsUInt16Number*) output = v; - - output += sizeof(cmsUInt16Number); - } - - if (!ExtraFirst) { - output += Extra * sizeof(cmsUInt16Number); - } - - if (Extra == 0 && SwapFirst) { - - memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsUInt16Number)); - *swap1 = v; - } - - - return output; - - cmsUNUSED_PARAMETER(Stride); -} - - -static -cmsUInt8Number* PackPlanarBytes(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - int nChan = T_CHANNELS(info -> OutputFormat); - int DoSwap = T_DOSWAP(info ->OutputFormat); - int SwapFirst = T_SWAPFIRST(info ->OutputFormat); - int Reverse = T_FLAVOR(info ->OutputFormat); - int i; - cmsUInt8Number* Init = output; - - - if (DoSwap ^ SwapFirst) { - output += T_EXTRA(info -> OutputFormat) * Stride; - } - - - for (i=0; i < nChan; i++) { - - int index = DoSwap ? (nChan - i - 1) : i; - cmsUInt8Number v = FROM_16_TO_8(wOut[index]); - - *(cmsUInt8Number*) output = (cmsUInt8Number) (Reverse ? REVERSE_FLAVOR_8(v) : v); - output += Stride; - } - - return (Init + 1); - - cmsUNUSED_PARAMETER(Stride); -} - - -static -cmsUInt8Number* PackPlanarWords(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - int nChan = T_CHANNELS(info -> OutputFormat); - int DoSwap = T_DOSWAP(info ->OutputFormat); - int Reverse= T_FLAVOR(info ->OutputFormat); - int SwapEndian = T_ENDIAN16(info -> OutputFormat); - int i; - cmsUInt8Number* Init = output; - cmsUInt16Number v; - - if (DoSwap) { - output += T_EXTRA(info -> OutputFormat) * Stride * sizeof(cmsUInt16Number); - } - - for (i=0; i < nChan; i++) { - - int index = DoSwap ? (nChan - i - 1) : i; - - v = wOut[index]; - - if (SwapEndian) - v = CHANGE_ENDIAN(v); - - if (Reverse) - v = REVERSE_FLAVOR_16(v); - - *(cmsUInt16Number*) output = v; - output += (Stride * sizeof(cmsUInt16Number)); - } - - return (Init + sizeof(cmsUInt16Number)); -} - -// CMYKcm (unrolled for speed) - -static -cmsUInt8Number* Pack6Bytes(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *output++ = FROM_16_TO_8(wOut[0]); - *output++ = FROM_16_TO_8(wOut[1]); - *output++ = FROM_16_TO_8(wOut[2]); - *output++ = FROM_16_TO_8(wOut[3]); - *output++ = FROM_16_TO_8(wOut[4]); - *output++ = FROM_16_TO_8(wOut[5]); - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -// KCMYcm - -static -cmsUInt8Number* Pack6BytesSwap(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *output++ = FROM_16_TO_8(wOut[5]); - *output++ = FROM_16_TO_8(wOut[4]); - *output++ = FROM_16_TO_8(wOut[3]); - *output++ = FROM_16_TO_8(wOut[2]); - *output++ = FROM_16_TO_8(wOut[1]); - *output++ = FROM_16_TO_8(wOut[0]); - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -// CMYKcm -static -cmsUInt8Number* Pack6Words(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *(cmsUInt16Number*) output = wOut[0]; - output+= 2; - *(cmsUInt16Number*) output = wOut[1]; - output+= 2; - *(cmsUInt16Number*) output = wOut[2]; - output+= 2; - *(cmsUInt16Number*) output = wOut[3]; - output+= 2; - *(cmsUInt16Number*) output = wOut[4]; - output+= 2; - *(cmsUInt16Number*) output = wOut[5]; - output+= 2; - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -// KCMYcm -static -cmsUInt8Number* Pack6WordsSwap(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *(cmsUInt16Number*) output = wOut[5]; - output+= 2; - *(cmsUInt16Number*) output = wOut[4]; - output+= 2; - *(cmsUInt16Number*) output = wOut[3]; - output+= 2; - *(cmsUInt16Number*) output = wOut[2]; - output+= 2; - *(cmsUInt16Number*) output = wOut[1]; - output+= 2; - *(cmsUInt16Number*) output = wOut[0]; - output+= 2; - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - - -static -cmsUInt8Number* Pack4Bytes(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *output++ = FROM_16_TO_8(wOut[0]); - *output++ = FROM_16_TO_8(wOut[1]); - *output++ = FROM_16_TO_8(wOut[2]); - *output++ = FROM_16_TO_8(wOut[3]); - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Pack4BytesReverse(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[0])); - *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[1])); - *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[2])); - *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[3])); - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - - -static -cmsUInt8Number* Pack4BytesSwapFirst(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *output++ = FROM_16_TO_8(wOut[3]); - *output++ = FROM_16_TO_8(wOut[0]); - *output++ = FROM_16_TO_8(wOut[1]); - *output++ = FROM_16_TO_8(wOut[2]); - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -// ABGR -static -cmsUInt8Number* Pack4BytesSwap(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *output++ = FROM_16_TO_8(wOut[3]); - *output++ = FROM_16_TO_8(wOut[2]); - *output++ = FROM_16_TO_8(wOut[1]); - *output++ = FROM_16_TO_8(wOut[0]); - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Pack4BytesSwapSwapFirst(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *output++ = FROM_16_TO_8(wOut[2]); - *output++ = FROM_16_TO_8(wOut[1]); - *output++ = FROM_16_TO_8(wOut[0]); - *output++ = FROM_16_TO_8(wOut[3]); - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Pack4Words(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *(cmsUInt16Number*) output = wOut[0]; - output+= 2; - *(cmsUInt16Number*) output = wOut[1]; - output+= 2; - *(cmsUInt16Number*) output = wOut[2]; - output+= 2; - *(cmsUInt16Number*) output = wOut[3]; - output+= 2; - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Pack4WordsReverse(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[0]); - output+= 2; - *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[1]); - output+= 2; - *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[2]); - output+= 2; - *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[3]); - output+= 2; - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -// ABGR -static -cmsUInt8Number* Pack4WordsSwap(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *(cmsUInt16Number*) output = wOut[3]; - output+= 2; - *(cmsUInt16Number*) output = wOut[2]; - output+= 2; - *(cmsUInt16Number*) output = wOut[1]; - output+= 2; - *(cmsUInt16Number*) output = wOut[0]; - output+= 2; - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -// CMYK -static -cmsUInt8Number* Pack4WordsBigEndian(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[0]); - output+= 2; - *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[1]); - output+= 2; - *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[2]); - output+= 2; - *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[3]); - output+= 2; - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - - -static -cmsUInt8Number* PackLabV2_8(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[0])); - *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[1])); - *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[2])); - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* PackALabV2_8(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - output++; - *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[0])); - *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[1])); - *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[2])); - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* PackLabV2_16(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *(cmsUInt16Number*) output = FomLabV4ToLabV2(wOut[0]); - output += 2; - *(cmsUInt16Number*) output = FomLabV4ToLabV2(wOut[1]); - output += 2; - *(cmsUInt16Number*) output = FomLabV4ToLabV2(wOut[2]); - output += 2; - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Pack3Bytes(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *output++ = FROM_16_TO_8(wOut[0]); - *output++ = FROM_16_TO_8(wOut[1]); - *output++ = FROM_16_TO_8(wOut[2]); - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Pack3BytesOptimized(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *output++ = (wOut[0] & 0xFF); - *output++ = (wOut[1] & 0xFF); - *output++ = (wOut[2] & 0xFF); - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Pack3BytesSwap(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *output++ = FROM_16_TO_8(wOut[2]); - *output++ = FROM_16_TO_8(wOut[1]); - *output++ = FROM_16_TO_8(wOut[0]); - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Pack3BytesSwapOptimized(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *output++ = (wOut[2] & 0xFF); - *output++ = (wOut[1] & 0xFF); - *output++ = (wOut[0] & 0xFF); - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - - -static -cmsUInt8Number* Pack3Words(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *(cmsUInt16Number*) output = wOut[0]; - output+= 2; - *(cmsUInt16Number*) output = wOut[1]; - output+= 2; - *(cmsUInt16Number*) output = wOut[2]; - output+= 2; - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Pack3WordsSwap(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *(cmsUInt16Number*) output = wOut[2]; - output+= 2; - *(cmsUInt16Number*) output = wOut[1]; - output+= 2; - *(cmsUInt16Number*) output = wOut[0]; - output+= 2; - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Pack3WordsBigEndian(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[0]); - output+= 2; - *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[1]); - output+= 2; - *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[2]); - output+= 2; - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Pack3BytesAndSkip1(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *output++ = FROM_16_TO_8(wOut[0]); - *output++ = FROM_16_TO_8(wOut[1]); - *output++ = FROM_16_TO_8(wOut[2]); - output++; - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Pack3BytesAndSkip1Optimized(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *output++ = (wOut[0] & 0xFF); - *output++ = (wOut[1] & 0xFF); - *output++ = (wOut[2] & 0xFF); - output++; - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - - -static -cmsUInt8Number* Pack3BytesAndSkip1SwapFirst(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - output++; - *output++ = FROM_16_TO_8(wOut[0]); - *output++ = FROM_16_TO_8(wOut[1]); - *output++ = FROM_16_TO_8(wOut[2]); - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Pack3BytesAndSkip1SwapFirstOptimized(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - output++; - *output++ = (wOut[0] & 0xFF); - *output++ = (wOut[1] & 0xFF); - *output++ = (wOut[2] & 0xFF); - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Pack3BytesAndSkip1Swap(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - output++; - *output++ = FROM_16_TO_8(wOut[2]); - *output++ = FROM_16_TO_8(wOut[1]); - *output++ = FROM_16_TO_8(wOut[0]); - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Pack3BytesAndSkip1SwapOptimized(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - output++; - *output++ = (wOut[2] & 0xFF); - *output++ = (wOut[1] & 0xFF); - *output++ = (wOut[0] & 0xFF); - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - - -static -cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirst(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *output++ = FROM_16_TO_8(wOut[2]); - *output++ = FROM_16_TO_8(wOut[1]); - *output++ = FROM_16_TO_8(wOut[0]); - output++; - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirstOptimized(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *output++ = (wOut[2] & 0xFF); - *output++ = (wOut[1] & 0xFF); - *output++ = (wOut[0] & 0xFF); - output++; - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Pack3WordsAndSkip1(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *(cmsUInt16Number*) output = wOut[0]; - output+= 2; - *(cmsUInt16Number*) output = wOut[1]; - output+= 2; - *(cmsUInt16Number*) output = wOut[2]; - output+= 2; - output+= 2; - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Pack3WordsAndSkip1Swap(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - output+= 2; - *(cmsUInt16Number*) output = wOut[2]; - output+= 2; - *(cmsUInt16Number*) output = wOut[1]; - output+= 2; - *(cmsUInt16Number*) output = wOut[0]; - output+= 2; - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - - -static -cmsUInt8Number* Pack3WordsAndSkip1SwapFirst(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - output+= 2; - *(cmsUInt16Number*) output = wOut[0]; - output+= 2; - *(cmsUInt16Number*) output = wOut[1]; - output+= 2; - *(cmsUInt16Number*) output = wOut[2]; - output+= 2; - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - - -static -cmsUInt8Number* Pack3WordsAndSkip1SwapSwapFirst(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *(cmsUInt16Number*) output = wOut[2]; - output+= 2; - *(cmsUInt16Number*) output = wOut[1]; - output+= 2; - *(cmsUInt16Number*) output = wOut[0]; - output+= 2; - output+= 2; - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - - - -static -cmsUInt8Number* Pack1Byte(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *output++ = FROM_16_TO_8(wOut[0]); - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - - -static -cmsUInt8Number* Pack1ByteReversed(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *output++ = FROM_16_TO_8(REVERSE_FLAVOR_16(wOut[0])); - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - - -static -cmsUInt8Number* Pack1ByteSkip1(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *output++ = FROM_16_TO_8(wOut[0]); - output++; - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - - -static -cmsUInt8Number* Pack1ByteSkip1SwapFirst(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - output++; - *output++ = FROM_16_TO_8(wOut[0]); - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Pack1Word(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *(cmsUInt16Number*) output = wOut[0]; - output+= 2; - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - - -static -cmsUInt8Number* Pack1WordReversed(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[0]); - output+= 2; - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Pack1WordBigEndian(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[0]); - output+= 2; - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - - -static -cmsUInt8Number* Pack1WordSkip1(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - *(cmsUInt16Number*) output = wOut[0]; - output+= 4; - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - -static -cmsUInt8Number* Pack1WordSkip1SwapFirst(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - output += 2; - *(cmsUInt16Number*) output = wOut[0]; - output+= 2; - - return output; - - cmsUNUSED_PARAMETER(info); - cmsUNUSED_PARAMETER(Stride); -} - - -// Unencoded Float values -- don't try optimize speed -static -cmsUInt8Number* PackLabDoubleFrom16(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - - if (T_PLANAR(info -> OutputFormat)) { - - cmsCIELab Lab; - cmsFloat64Number* Out = (cmsFloat64Number*) output; - cmsLabEncoded2Float(&Lab, wOut); - - Out[0] = Lab.L; - Out[Stride] = Lab.a; - Out[Stride*2] = Lab.b; - - return output + sizeof(cmsFloat64Number); - } - else { - - cmsLabEncoded2Float((cmsCIELab*) output, wOut); - return output + (sizeof(cmsCIELab) + T_EXTRA(info ->OutputFormat) * sizeof(cmsFloat64Number)); - } -} - - -static -cmsUInt8Number* PackLabFloatFrom16(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - cmsCIELab Lab; - cmsLabEncoded2Float(&Lab, wOut); - - if (T_PLANAR(info -> OutputFormat)) { - - cmsFloat32Number* Out = (cmsFloat32Number*) output; - - Out[0] = (cmsFloat32Number)Lab.L; - Out[Stride] = (cmsFloat32Number)Lab.a; - Out[Stride*2] = (cmsFloat32Number)Lab.b; - - return output + sizeof(cmsFloat32Number); - } - else { - - ((cmsFloat32Number*) output)[0] = (cmsFloat32Number) Lab.L; - ((cmsFloat32Number*) output)[1] = (cmsFloat32Number) Lab.a; - ((cmsFloat32Number*) output)[2] = (cmsFloat32Number) Lab.b; - - return output + (3 + T_EXTRA(info ->OutputFormat)) * sizeof(cmsFloat32Number); - } -} - -static -cmsUInt8Number* PackXYZDoubleFrom16(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - if (T_PLANAR(Info -> OutputFormat)) { - - cmsCIEXYZ XYZ; - cmsFloat64Number* Out = (cmsFloat64Number*) output; - cmsXYZEncoded2Float(&XYZ, wOut); - - Out[0] = XYZ.X; - Out[Stride] = XYZ.Y; - Out[Stride*2] = XYZ.Z; - - return output + sizeof(cmsFloat64Number); - - } - else { - - cmsXYZEncoded2Float((cmsCIEXYZ*) output, wOut); - - return output + (sizeof(cmsCIEXYZ) + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number)); - } -} - -static -cmsUInt8Number* PackXYZFloatFrom16(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - if (T_PLANAR(Info -> OutputFormat)) { - - cmsCIEXYZ XYZ; - cmsFloat32Number* Out = (cmsFloat32Number*) output; - cmsXYZEncoded2Float(&XYZ, wOut); - - Out[0] = (cmsFloat32Number) XYZ.X; - Out[Stride] = (cmsFloat32Number) XYZ.Y; - Out[Stride*2] = (cmsFloat32Number) XYZ.Z; - - return output + sizeof(cmsFloat32Number); - - } - else { - - cmsCIEXYZ XYZ; - cmsFloat32Number* Out = (cmsFloat32Number*) output; - cmsXYZEncoded2Float(&XYZ, wOut); - - Out[0] = (cmsFloat32Number) XYZ.X; - Out[1] = (cmsFloat32Number) XYZ.Y; - Out[2] = (cmsFloat32Number) XYZ.Z; - - return output + (3 * sizeof(cmsFloat32Number) + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number)); - } -} - -static -cmsUInt8Number* PackDoubleFrom16(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - int nChan = T_CHANNELS(info -> OutputFormat); - int DoSwap = T_DOSWAP(info ->OutputFormat); - int Reverse = T_FLAVOR(info ->OutputFormat); - int Extra = T_EXTRA(info -> OutputFormat); - int SwapFirst = T_SWAPFIRST(info -> OutputFormat); - int Planar = T_PLANAR(info -> OutputFormat); - int ExtraFirst = DoSwap ^ SwapFirst; - cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 655.35 : 65535.0; - cmsFloat64Number v = 0; - cmsFloat64Number* swap1 = (cmsFloat64Number*) output; - int i, start = 0; - - if (ExtraFirst) - start = Extra; - - for (i=0; i < nChan; i++) { - - int index = DoSwap ? (nChan - i - 1) : i; - - v = (cmsFloat64Number) wOut[index] / maximum; - - if (Reverse) - v = maximum - v; - - if (Planar) - ((cmsFloat64Number*) output)[(i + start) * Stride]= v; - else - ((cmsFloat64Number*) output)[i + start] = v; - } - - if (!ExtraFirst) { - output += Extra * sizeof(cmsFloat64Number); - } - - if (Extra == 0 && SwapFirst) { - - memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat64Number)); - *swap1 = v; - } - - if (T_PLANAR(info -> OutputFormat)) - return output + sizeof(cmsFloat64Number); - else - return output + nChan * sizeof(cmsFloat64Number); - -} - - -static -cmsUInt8Number* PackFloatFrom16(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - int nChan = T_CHANNELS(info -> OutputFormat); - int DoSwap = T_DOSWAP(info ->OutputFormat); - int Reverse = T_FLAVOR(info ->OutputFormat); - int Extra = T_EXTRA(info -> OutputFormat); - int SwapFirst = T_SWAPFIRST(info -> OutputFormat); - int Planar = T_PLANAR(info -> OutputFormat); - int ExtraFirst = DoSwap ^ SwapFirst; - cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 655.35 : 65535.0; - cmsFloat64Number v = 0; - cmsFloat32Number* swap1 = (cmsFloat32Number*) output; - int i, start = 0; - - if (ExtraFirst) - start = Extra; - - for (i=0; i < nChan; i++) { - - int index = DoSwap ? (nChan - i - 1) : i; - - v = (cmsFloat64Number) wOut[index] / maximum; - - if (Reverse) - v = maximum - v; - - if (Planar) - ((cmsFloat32Number*) output)[(i + start ) * Stride]= (cmsFloat32Number) v; - else - ((cmsFloat32Number*) output)[i + start] = (cmsFloat32Number) v; - } - - if (!ExtraFirst) { - output += Extra * sizeof(cmsFloat32Number); - } - - if (Extra == 0 && SwapFirst) { - - memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat32Number)); - *swap1 = (cmsFloat32Number) v; - } - - if (T_PLANAR(info -> OutputFormat)) - return output + sizeof(cmsFloat32Number); - else - return output + nChan * sizeof(cmsFloat32Number); -} - - - -// -------------------------------------------------------------------------------------------------------- - -static -cmsUInt8Number* PackFloatsFromFloat(_cmsTRANSFORM* info, - cmsFloat32Number wOut[], - cmsUInt8Number* output, - cmsUInt32Number Stride) -{ - int nChan = T_CHANNELS(info -> OutputFormat); - int DoSwap = T_DOSWAP(info ->OutputFormat); - int Reverse = T_FLAVOR(info ->OutputFormat); - int Extra = T_EXTRA(info -> OutputFormat); - int SwapFirst = T_SWAPFIRST(info -> OutputFormat); - int Planar = T_PLANAR(info -> OutputFormat); - int ExtraFirst = DoSwap ^ SwapFirst; - cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0; - cmsFloat32Number* swap1 = (cmsFloat32Number*) output; - cmsFloat64Number v = 0; - int i, start = 0; - - if (ExtraFirst) - start = Extra; - - for (i=0; i < nChan; i++) { - - int index = DoSwap ? (nChan - i - 1) : i; - - v = wOut[index] * maximum; - - if (Reverse) - v = maximum - v; - - if (Planar) - ((cmsFloat32Number*) output)[(i + start)* Stride]= (cmsFloat32Number) v; - else - ((cmsFloat32Number*) output)[i + start] = (cmsFloat32Number) v; - } - - if (!ExtraFirst) { - output += Extra * sizeof(cmsFloat32Number); - } - - if (Extra == 0 && SwapFirst) { - - memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat32Number)); - *swap1 = (cmsFloat32Number) v; - } - - if (T_PLANAR(info -> OutputFormat)) - return output + sizeof(cmsFloat32Number); - else - return output + nChan * sizeof(cmsFloat32Number); -} - -static -cmsUInt8Number* PackDoublesFromFloat(_cmsTRANSFORM* info, - cmsFloat32Number wOut[], - cmsUInt8Number* output, - cmsUInt32Number Stride) -{ - int nChan = T_CHANNELS(info -> OutputFormat); - int DoSwap = T_DOSWAP(info ->OutputFormat); - int Reverse = T_FLAVOR(info ->OutputFormat); - int Extra = T_EXTRA(info -> OutputFormat); - int SwapFirst = T_SWAPFIRST(info -> OutputFormat); - int Planar = T_PLANAR(info -> OutputFormat); - int ExtraFirst = DoSwap ^ SwapFirst; - cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0; - cmsFloat64Number v = 0; - cmsFloat64Number* swap1 = (cmsFloat64Number*) output; - int i, start = 0; - - if (ExtraFirst) - start = Extra; - - for (i=0; i < nChan; i++) { - - int index = DoSwap ? (nChan - i - 1) : i; - - v = wOut[index] * maximum; - - if (Reverse) - v = maximum - v; - - if (Planar) - ((cmsFloat64Number*) output)[(i + start) * Stride] = v; - else - ((cmsFloat64Number*) output)[i + start] = v; - } - - if (!ExtraFirst) { - output += Extra * sizeof(cmsFloat64Number); - } - - if (Extra == 0 && SwapFirst) { - - memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat64Number)); - *swap1 = v; - } - - - if (T_PLANAR(info -> OutputFormat)) - return output + sizeof(cmsFloat64Number); - else - return output + nChan * sizeof(cmsFloat64Number); - -} - - - - - -static -cmsUInt8Number* PackLabFloatFromFloat(_cmsTRANSFORM* Info, - cmsFloat32Number wOut[], - cmsUInt8Number* output, - cmsUInt32Number Stride) -{ - cmsFloat32Number* Out = (cmsFloat32Number*) output; - - if (T_PLANAR(Info -> OutputFormat)) { - - Out[0] = (cmsFloat32Number) (wOut[0] * 100.0); - Out[Stride] = (cmsFloat32Number) (wOut[1] * 255.0 - 128.0); - Out[Stride*2] = (cmsFloat32Number) (wOut[2] * 255.0 - 128.0); - - return output + sizeof(cmsFloat32Number); - } - else { - - Out[0] = (cmsFloat32Number) (wOut[0] * 100.0); - Out[1] = (cmsFloat32Number) (wOut[1] * 255.0 - 128.0); - Out[2] = (cmsFloat32Number) (wOut[2] * 255.0 - 128.0); - - return output + (sizeof(cmsFloat32Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number)); - } - -} - - -static -cmsUInt8Number* PackLabDoubleFromFloat(_cmsTRANSFORM* Info, - cmsFloat32Number wOut[], - cmsUInt8Number* output, - cmsUInt32Number Stride) -{ - cmsFloat64Number* Out = (cmsFloat64Number*) output; - - if (T_PLANAR(Info -> OutputFormat)) { - - Out[0] = (cmsFloat64Number) (wOut[0] * 100.0); - Out[Stride] = (cmsFloat64Number) (wOut[1] * 255.0 - 128.0); - Out[Stride*2] = (cmsFloat64Number) (wOut[2] * 255.0 - 128.0); - - return output + sizeof(cmsFloat64Number); - } - else { - - Out[0] = (cmsFloat64Number) (wOut[0] * 100.0); - Out[1] = (cmsFloat64Number) (wOut[1] * 255.0 - 128.0); - Out[2] = (cmsFloat64Number) (wOut[2] * 255.0 - 128.0); - - return output + (sizeof(cmsFloat64Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number)); - } - -} - - -// From 0..1 range to 0..MAX_ENCODEABLE_XYZ -static -cmsUInt8Number* PackXYZFloatFromFloat(_cmsTRANSFORM* Info, - cmsFloat32Number wOut[], - cmsUInt8Number* output, - cmsUInt32Number Stride) -{ - cmsFloat32Number* Out = (cmsFloat32Number*) output; - - if (T_PLANAR(Info -> OutputFormat)) { - - Out[0] = (cmsFloat32Number) (wOut[0] * MAX_ENCODEABLE_XYZ); - Out[Stride] = (cmsFloat32Number) (wOut[1] * MAX_ENCODEABLE_XYZ); - Out[Stride*2] = (cmsFloat32Number) (wOut[2] * MAX_ENCODEABLE_XYZ); - - return output + sizeof(cmsFloat32Number); - } - else { - - Out[0] = (cmsFloat32Number) (wOut[0] * MAX_ENCODEABLE_XYZ); - Out[1] = (cmsFloat32Number) (wOut[1] * MAX_ENCODEABLE_XYZ); - Out[2] = (cmsFloat32Number) (wOut[2] * MAX_ENCODEABLE_XYZ); - - return output + (sizeof(cmsFloat32Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number)); - } - -} - -// Same, but convert to double -static -cmsUInt8Number* PackXYZDoubleFromFloat(_cmsTRANSFORM* Info, - cmsFloat32Number wOut[], - cmsUInt8Number* output, - cmsUInt32Number Stride) -{ - cmsFloat64Number* Out = (cmsFloat64Number*) output; - - if (T_PLANAR(Info -> OutputFormat)) { - - Out[0] = (cmsFloat64Number) (wOut[0] * MAX_ENCODEABLE_XYZ); - Out[Stride] = (cmsFloat64Number) (wOut[1] * MAX_ENCODEABLE_XYZ); - Out[Stride*2] = (cmsFloat64Number) (wOut[2] * MAX_ENCODEABLE_XYZ); - - return output + sizeof(cmsFloat64Number); - } - else { - - Out[0] = (cmsFloat64Number) (wOut[0] * MAX_ENCODEABLE_XYZ); - Out[1] = (cmsFloat64Number) (wOut[1] * MAX_ENCODEABLE_XYZ); - Out[2] = (cmsFloat64Number) (wOut[2] * MAX_ENCODEABLE_XYZ); - - return output + (sizeof(cmsFloat64Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number)); - } - -} - - -// ---------------------------------------------------------------------------------------------------------------- - -#ifndef CMS_NO_HALF_SUPPORT - -// Decodes an stream of half floats to wIn[] described by input format - -static -cmsUInt8Number* UnrollHalfTo16(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - - int nChan = T_CHANNELS(info -> InputFormat); - int DoSwap = T_DOSWAP(info ->InputFormat); - int Reverse = T_FLAVOR(info ->InputFormat); - int SwapFirst = T_SWAPFIRST(info -> InputFormat); - int Extra = T_EXTRA(info -> InputFormat); - int ExtraFirst = DoSwap ^ SwapFirst; - int Planar = T_PLANAR(info -> InputFormat); - cmsFloat32Number v; - int i, start = 0; - cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 655.35F : 65535.0F; - - - if (ExtraFirst) - start = Extra; - - for (i=0; i < nChan; i++) { - - int index = DoSwap ? (nChan - i - 1) : i; - - if (Planar) - v = _cmsHalf2Float ( ((cmsUInt16Number*) accum)[(i + start) * Stride] ); - else - v = _cmsHalf2Float ( ((cmsUInt16Number*) accum)[i + start] ) ; - - if (Reverse) v = maximum - v; - - wIn[index] = _cmsQuickSaturateWord(v * maximum); - } - - - if (Extra == 0 && SwapFirst) { - cmsUInt16Number tmp = wIn[0]; - - memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number)); - wIn[nChan-1] = tmp; - } - - if (T_PLANAR(info -> InputFormat)) - return accum + sizeof(cmsUInt16Number); - else - return accum + (nChan + Extra) * sizeof(cmsUInt16Number); -} - -// Decodes an stream of half floats to wIn[] described by input format - -static -cmsUInt8Number* UnrollHalfToFloat(_cmsTRANSFORM* info, - cmsFloat32Number wIn[], - cmsUInt8Number* accum, - cmsUInt32Number Stride) -{ - - int nChan = T_CHANNELS(info -> InputFormat); - int DoSwap = T_DOSWAP(info ->InputFormat); - int Reverse = T_FLAVOR(info ->InputFormat); - int SwapFirst = T_SWAPFIRST(info -> InputFormat); - int Extra = T_EXTRA(info -> InputFormat); - int ExtraFirst = DoSwap ^ SwapFirst; - int Planar = T_PLANAR(info -> InputFormat); - cmsFloat32Number v; - int i, start = 0; - cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 100.0F : 1.0F; - - - if (ExtraFirst) - start = Extra; - - for (i=0; i < nChan; i++) { - - int index = DoSwap ? (nChan - i - 1) : i; - - if (Planar) - v = _cmsHalf2Float ( ((cmsUInt16Number*) accum)[(i + start) * Stride] ); - else - v = _cmsHalf2Float ( ((cmsUInt16Number*) accum)[i + start] ) ; - - v /= maximum; - - wIn[index] = Reverse ? 1 - v : v; - } - - - if (Extra == 0 && SwapFirst) { - cmsFloat32Number tmp = wIn[0]; - - memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsFloat32Number)); - wIn[nChan-1] = tmp; - } - - if (T_PLANAR(info -> InputFormat)) - return accum + sizeof(cmsUInt16Number); - else - return accum + (nChan + Extra) * sizeof(cmsUInt16Number); -} - - -static -cmsUInt8Number* PackHalfFrom16(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - int nChan = T_CHANNELS(info -> OutputFormat); - int DoSwap = T_DOSWAP(info ->OutputFormat); - int Reverse = T_FLAVOR(info ->OutputFormat); - int Extra = T_EXTRA(info -> OutputFormat); - int SwapFirst = T_SWAPFIRST(info -> OutputFormat); - int Planar = T_PLANAR(info -> OutputFormat); - int ExtraFirst = DoSwap ^ SwapFirst; - cmsFloat32Number maximum = IsInkSpace(info ->OutputFormat) ? 655.35F : 65535.0F; - cmsFloat32Number v = 0; - cmsUInt16Number* swap1 = (cmsUInt16Number*) output; - int i, start = 0; - - if (ExtraFirst) - start = Extra; - - for (i=0; i < nChan; i++) { - - int index = DoSwap ? (nChan - i - 1) : i; - - v = (cmsFloat32Number) wOut[index] / maximum; - - if (Reverse) - v = maximum - v; - - if (Planar) - ((cmsUInt16Number*) output)[(i + start ) * Stride]= _cmsFloat2Half(v); - else - ((cmsUInt16Number*) output)[i + start] = _cmsFloat2Half(v); - } - - if (!ExtraFirst) { - output += Extra * sizeof(cmsUInt16Number); - } - - if (Extra == 0 && SwapFirst) { - - memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsUInt16Number)); - *swap1 = _cmsFloat2Half(v); - } - - if (T_PLANAR(info -> OutputFormat)) - return output + sizeof(cmsUInt16Number); - else - return output + nChan * sizeof(cmsUInt16Number); -} - - - -static -cmsUInt8Number* PackHalfFromFloat(_cmsTRANSFORM* info, - cmsFloat32Number wOut[], - cmsUInt8Number* output, - cmsUInt32Number Stride) -{ - int nChan = T_CHANNELS(info -> OutputFormat); - int DoSwap = T_DOSWAP(info ->OutputFormat); - int Reverse = T_FLAVOR(info ->OutputFormat); - int Extra = T_EXTRA(info -> OutputFormat); - int SwapFirst = T_SWAPFIRST(info -> OutputFormat); - int Planar = T_PLANAR(info -> OutputFormat); - int ExtraFirst = DoSwap ^ SwapFirst; - cmsFloat32Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0F : 1.0F; - cmsUInt16Number* swap1 = (cmsUInt16Number*) output; - cmsFloat32Number v = 0; - int i, start = 0; - - if (ExtraFirst) - start = Extra; - - for (i=0; i < nChan; i++) { - - int index = DoSwap ? (nChan - i - 1) : i; - - v = wOut[index] * maximum; - - if (Reverse) - v = maximum - v; - - if (Planar) - ((cmsUInt16Number*) output)[(i + start)* Stride]= _cmsFloat2Half( v ); - else - ((cmsUInt16Number*) output)[i + start] = _cmsFloat2Half( v ); - } - - if (!ExtraFirst) { - output += Extra * sizeof(cmsUInt16Number); - } - - if (Extra == 0 && SwapFirst) { - - memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsUInt16Number)); - *swap1 = (cmsUInt16Number) _cmsFloat2Half( v ); - } - - if (T_PLANAR(info -> OutputFormat)) - return output + sizeof(cmsUInt16Number); - else - return output + nChan * sizeof(cmsUInt16Number); -} - -#endif - -// ---------------------------------------------------------------------------------------------------------------- - - -static cmsFormatters16 InputFormatters16[] = { - - // Type Mask Function - // ---------------------------- ------------------------------------ ---------------------------- - { TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, UnrollLabDoubleTo16}, - { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, UnrollXYZDoubleTo16}, - { TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, UnrollLabFloatTo16}, - { TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, UnrollXYZFloatTo16}, - { TYPE_GRAY_DBL, 0, UnrollDouble1Chan}, - { FLOAT_SH(1)|BYTES_SH(0), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR| - ANYSWAP|ANYEXTRA|ANYSPACE, UnrollDoubleTo16}, - { FLOAT_SH(1)|BYTES_SH(4), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR| - ANYSWAP|ANYEXTRA|ANYSPACE, UnrollFloatTo16}, -#ifndef CMS_NO_HALF_SUPPORT - { FLOAT_SH(1)|BYTES_SH(2), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR| - ANYEXTRA|ANYSWAP|ANYSPACE, UnrollHalfTo16}, -#endif - - { CHANNELS_SH(1)|BYTES_SH(1), ANYSPACE, Unroll1Byte}, - { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1), ANYSPACE, Unroll1ByteSkip1}, - { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(2), ANYSPACE, Unroll1ByteSkip2}, - { CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Unroll1ByteReversed}, - { COLORSPACE_SH(PT_MCH2)|CHANNELS_SH(2)|BYTES_SH(1), 0, Unroll2Bytes}, - - { TYPE_LabV2_8, 0, UnrollLabV2_8 }, - { TYPE_ALabV2_8, 0, UnrollALabV2_8 }, - { TYPE_LabV2_16, 0, UnrollLabV2_16 }, - - { CHANNELS_SH(3)|BYTES_SH(1), ANYSPACE, Unroll3Bytes}, - { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll3BytesSwap}, - { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll3BytesSkip1Swap}, - { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll3BytesSkip1SwapFirst}, - - { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), - ANYSPACE, Unroll3BytesSkip1SwapSwapFirst}, - - { CHANNELS_SH(4)|BYTES_SH(1), ANYSPACE, Unroll4Bytes}, - { CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Unroll4BytesReverse}, - { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4BytesSwapFirst}, - { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll4BytesSwap}, - { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4BytesSwapSwapFirst}, - - { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST| - ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarBytes}, - - { BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP| - ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollChunkyBytes}, - - { CHANNELS_SH(1)|BYTES_SH(2), ANYSPACE, Unroll1Word}, - { CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1), ANYSPACE, Unroll1WordReversed}, - { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(3), ANYSPACE, Unroll1WordSkip3}, - - { CHANNELS_SH(2)|BYTES_SH(2), ANYSPACE, Unroll2Words}, - { CHANNELS_SH(3)|BYTES_SH(2), ANYSPACE, Unroll3Words}, - { CHANNELS_SH(4)|BYTES_SH(2), ANYSPACE, Unroll4Words}, - - { CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Unroll3WordsSwap}, - { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll3WordsSkip1SwapFirst}, - { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll3WordsSkip1Swap}, - { CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1), ANYSPACE, Unroll4WordsReverse}, - { CHANNELS_SH(4)|BYTES_SH(2)|SWAPFIRST_SH(1), ANYSPACE, Unroll4WordsSwapFirst}, - { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Unroll4WordsSwap}, - { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4WordsSwapSwapFirst}, - - - { BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarWords}, - { BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollAnyWords}, -}; - - - -static cmsFormattersFloat InputFormattersFloat[] = { - - // Type Mask Function - // ---------------------------- ------------------------------------ ---------------------------- - { TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, UnrollLabDoubleToFloat}, - { TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, UnrollLabFloatToFloat}, - - { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, UnrollXYZDoubleToFloat}, - { TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, UnrollXYZFloatToFloat}, - - { FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA| - ANYCHANNELS|ANYSPACE, UnrollFloatsToFloat}, - - { FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA| - ANYCHANNELS|ANYSPACE, UnrollDoublesToFloat}, -#ifndef CMS_NO_HALF_SUPPORT - { FLOAT_SH(1)|BYTES_SH(2), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA| - ANYCHANNELS|ANYSPACE, UnrollHalfToFloat}, -#endif -}; - - -// Bit fields set to one in the mask are not compared -static -cmsFormatter _cmsGetStockInputFormatter(cmsUInt32Number dwInput, cmsUInt32Number dwFlags) -{ - cmsUInt32Number i; - cmsFormatter fr; - - switch (dwFlags) { - - case CMS_PACK_FLAGS_16BITS: { - for (i=0; i < sizeof(InputFormatters16) / sizeof(cmsFormatters16); i++) { - cmsFormatters16* f = InputFormatters16 + i; - - if ((dwInput & ~f ->Mask) == f ->Type) { - fr.Fmt16 = f ->Frm; - return fr; - } - } - } - break; - - case CMS_PACK_FLAGS_FLOAT: { - for (i=0; i < sizeof(InputFormattersFloat) / sizeof(cmsFormattersFloat); i++) { - cmsFormattersFloat* f = InputFormattersFloat + i; - - if ((dwInput & ~f ->Mask) == f ->Type) { - fr.FmtFloat = f ->Frm; - return fr; - } - } - } - break; - - default:; - - } - - fr.Fmt16 = NULL; - return fr; -} - -static cmsFormatters16 OutputFormatters16[] = { - // Type Mask Function - // ---------------------------- ------------------------------------ ---------------------------- - - { TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, PackLabDoubleFrom16}, - { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, PackXYZDoubleFrom16}, - - { TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, PackLabFloatFrom16}, - { TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, PackXYZFloatFrom16}, - - { FLOAT_SH(1)|BYTES_SH(0), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP| - ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, PackDoubleFrom16}, - { FLOAT_SH(1)|BYTES_SH(4), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP| - ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, PackFloatFrom16}, -#ifndef CMS_NO_HALF_SUPPORT - { FLOAT_SH(1)|BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP| - ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, PackHalfFrom16}, -#endif - - { CHANNELS_SH(1)|BYTES_SH(1), ANYSPACE, Pack1Byte}, - { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1), ANYSPACE, Pack1ByteSkip1}, - { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack1ByteSkip1SwapFirst}, - - { CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Pack1ByteReversed}, - - { TYPE_LabV2_8, 0, PackLabV2_8 }, - { TYPE_ALabV2_8, 0, PackALabV2_8 }, - { TYPE_LabV2_16, 0, PackLabV2_16 }, - - { CHANNELS_SH(3)|BYTES_SH(1)|OPTIMIZED_SH(1), ANYSPACE, Pack3BytesOptimized}, - { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|OPTIMIZED_SH(1), ANYSPACE, Pack3BytesAndSkip1Optimized}, - { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1)|OPTIMIZED_SH(1), - ANYSPACE, Pack3BytesAndSkip1SwapFirstOptimized}, - { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|OPTIMIZED_SH(1), - ANYSPACE, Pack3BytesAndSkip1SwapSwapFirstOptimized}, - { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|EXTRA_SH(1)|OPTIMIZED_SH(1), - ANYSPACE, Pack3BytesAndSkip1SwapOptimized}, - { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|OPTIMIZED_SH(1), ANYSPACE, Pack3BytesSwapOptimized}, - - - - { CHANNELS_SH(3)|BYTES_SH(1), ANYSPACE, Pack3Bytes}, - { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1), ANYSPACE, Pack3BytesAndSkip1}, - { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack3BytesAndSkip1SwapFirst}, - { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), - ANYSPACE, Pack3BytesAndSkip1SwapSwapFirst}, - { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|EXTRA_SH(1), ANYSPACE, Pack3BytesAndSkip1Swap}, - { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack3BytesSwap}, - { CHANNELS_SH(6)|BYTES_SH(1), ANYSPACE, Pack6Bytes}, - { CHANNELS_SH(6)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack6BytesSwap}, - { CHANNELS_SH(4)|BYTES_SH(1), ANYSPACE, Pack4Bytes}, - { CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Pack4BytesReverse}, - { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack4BytesSwapFirst}, - { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack4BytesSwap}, - { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack4BytesSwapSwapFirst}, - - { BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyBytes}, - { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarBytes}, - - { CHANNELS_SH(1)|BYTES_SH(2), ANYSPACE, Pack1Word}, - { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(1), ANYSPACE, Pack1WordSkip1}, - { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack1WordSkip1SwapFirst}, - { CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1), ANYSPACE, Pack1WordReversed}, - { CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1), ANYSPACE, Pack1WordBigEndian}, - { CHANNELS_SH(3)|BYTES_SH(2), ANYSPACE, Pack3Words}, - { CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Pack3WordsSwap}, - { CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1), ANYSPACE, Pack3WordsBigEndian}, - { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1), ANYSPACE, Pack3WordsAndSkip1}, - { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack3WordsAndSkip1Swap}, - { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack3WordsAndSkip1SwapFirst}, - - { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), - ANYSPACE, Pack3WordsAndSkip1SwapSwapFirst}, - - { CHANNELS_SH(4)|BYTES_SH(2), ANYSPACE, Pack4Words}, - { CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1), ANYSPACE, Pack4WordsReverse}, - { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Pack4WordsSwap}, - { CHANNELS_SH(4)|BYTES_SH(2)|ENDIAN16_SH(1), ANYSPACE, Pack4WordsBigEndian}, - - { CHANNELS_SH(6)|BYTES_SH(2), ANYSPACE, Pack6Words}, - { CHANNELS_SH(6)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Pack6WordsSwap}, - - { BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYENDIAN|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarWords}, - { BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyWords} - -}; - - -static cmsFormattersFloat OutputFormattersFloat[] = { - // Type Mask Function - // ---------------------------- --------------------------------------------------- ---------------------------- - { TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, PackLabFloatFromFloat}, - { TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, PackXYZFloatFromFloat}, - - { TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, PackLabDoubleFromFloat}, - { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, PackXYZDoubleFromFloat}, - - { FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR| - ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackFloatsFromFloat }, - { FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR| - ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackDoublesFromFloat }, -#ifndef CMS_NO_HALF_SUPPORT - { FLOAT_SH(1)|BYTES_SH(2), - ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackHalfFromFloat }, -#endif - - - -}; - - -// Bit fields set to one in the mask are not compared -static -cmsFormatter _cmsGetStockOutputFormatter(cmsUInt32Number dwInput, cmsUInt32Number dwFlags) -{ - cmsUInt32Number i; - cmsFormatter fr; - - - switch (dwFlags) - { - - case CMS_PACK_FLAGS_16BITS: { - - for (i=0; i < sizeof(OutputFormatters16) / sizeof(cmsFormatters16); i++) { - cmsFormatters16* f = OutputFormatters16 + i; - - if ((dwInput & ~f ->Mask) == f ->Type) { - fr.Fmt16 = f ->Frm; - return fr; - } - } - } - break; - - case CMS_PACK_FLAGS_FLOAT: { - - for (i=0; i < sizeof(OutputFormattersFloat) / sizeof(cmsFormattersFloat); i++) { - cmsFormattersFloat* f = OutputFormattersFloat + i; - - if ((dwInput & ~f ->Mask) == f ->Type) { - fr.FmtFloat = f ->Frm; - return fr; - } - } - } - break; - - default:; - - } - - fr.Fmt16 = NULL; - return fr; -} - - -typedef struct _cms_formatters_factory_list { - - cmsFormatterFactory Factory; - struct _cms_formatters_factory_list *Next; - -} cmsFormattersFactoryList; - -_cmsFormattersPluginChunkType _cmsFormattersPluginChunk = { NULL }; - - -// Duplicates the zone of memory used by the plug-in in the new context -static -void DupFormatterFactoryList(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src) -{ - _cmsFormattersPluginChunkType newHead = { NULL }; - cmsFormattersFactoryList* entry; - cmsFormattersFactoryList* Anterior = NULL; - _cmsFormattersPluginChunkType* head = (_cmsFormattersPluginChunkType*) src->chunks[FormattersPlugin]; - - _cmsAssert(head != NULL); - - // Walk the list copying all nodes - for (entry = head->FactoryList; - entry != NULL; - entry = entry ->Next) { - - cmsFormattersFactoryList *newEntry = ( cmsFormattersFactoryList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(cmsFormattersFactoryList)); - - if (newEntry == NULL) - return; - - // We want to keep the linked list order, so this is a little bit tricky - newEntry -> Next = NULL; - if (Anterior) - Anterior -> Next = newEntry; - - Anterior = newEntry; - - if (newHead.FactoryList == NULL) - newHead.FactoryList = newEntry; - } - - ctx ->chunks[FormattersPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsFormattersPluginChunkType)); -} - -// The interpolation plug-in memory chunk allocator/dup -void _cmsAllocFormattersPluginChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src) -{ - _cmsAssert(ctx != NULL); - - if (src != NULL) { - - // Duplicate the LIST - DupFormatterFactoryList(ctx, src); - } - else { - static _cmsFormattersPluginChunkType FormattersPluginChunk = { NULL }; - ctx ->chunks[FormattersPlugin] = _cmsSubAllocDup(ctx ->MemPool, &FormattersPluginChunk, sizeof(_cmsFormattersPluginChunkType)); - } -} - - - -// Formatters management -cmsBool _cmsRegisterFormattersPlugin(cmsContext ContextID, cmsPluginBase* Data) -{ - _cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin); - cmsPluginFormatters* Plugin = (cmsPluginFormatters*) Data; - cmsFormattersFactoryList* fl ; - - // Reset to built-in defaults - if (Data == NULL) { - - ctx ->FactoryList = NULL; - return TRUE; - } - - fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(ContextID, sizeof(cmsFormattersFactoryList)); - if (fl == NULL) return FALSE; - - fl ->Factory = Plugin ->FormattersFactory; - - fl ->Next = ctx -> FactoryList; - ctx ->FactoryList = fl; - - return TRUE; -} - -cmsFormatter _cmsGetFormatter(cmsContext ContextID, - cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 - cmsFormatterDirection Dir, - cmsUInt32Number dwFlags) -{ - _cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin); - cmsFormattersFactoryList* f; - - for (f =ctx->FactoryList; f != NULL; f = f ->Next) { - - cmsFormatter fn = f ->Factory(Type, Dir, dwFlags); - if (fn.Fmt16 != NULL) return fn; - } - - // Revert to default - if (Dir == cmsFormatterInput) - return _cmsGetStockInputFormatter(Type, dwFlags); - else - return _cmsGetStockOutputFormatter(Type, dwFlags); -} - - -// Return whatever given formatter refers to float values -cmsBool _cmsFormatterIsFloat(cmsUInt32Number Type) -{ - return T_FLOAT(Type) ? TRUE : FALSE; -} - -// Return whatever given formatter refers to 8 bits -cmsBool _cmsFormatterIs8bit(cmsUInt32Number Type) -{ - int Bytes = T_BYTES(Type); - - return (Bytes == 1); -} - -// Build a suitable formatter for the colorspace of this profile -cmsUInt32Number CMSEXPORT cmsFormatterForColorspaceOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat) -{ - - cmsColorSpaceSignature ColorSpace = cmsGetColorSpace(hProfile); - cmsUInt32Number ColorSpaceBits = _cmsLCMScolorSpace(ColorSpace); - cmsUInt32Number nOutputChans = cmsChannelsOf(ColorSpace); - cmsUInt32Number Float = lIsFloat ? 1 : 0; - - // Create a fake formatter for result - return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans); -} - -// Build a suitable formatter for the colorspace of this profile -cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat) -{ - - cmsColorSpaceSignature ColorSpace = cmsGetPCS(hProfile); - int ColorSpaceBits = _cmsLCMScolorSpace(ColorSpace); - cmsUInt32Number nOutputChans = cmsChannelsOf(ColorSpace); - cmsUInt32Number Float = lIsFloat ? 1 : 0; - - // Create a fake formatter for result - return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans); -} diff --git a/third_party/lcms2-2.6/src/cmspcs.c b/third_party/lcms2-2.6/src/cmspcs.c deleted file mode 100644 index 102cd7d21e..0000000000 --- a/third_party/lcms2-2.6/src/cmspcs.c +++ /dev/null @@ -1,931 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- -// - -#include "lcms2_internal.h" - -// inter PCS conversions XYZ <-> CIE L* a* b* -/* - - - CIE 15:2004 CIELab is defined as: - - L* = 116*f(Y/Yn) - 16 0 <= L* <= 100 - a* = 500*[f(X/Xn) - f(Y/Yn)] - b* = 200*[f(Y/Yn) - f(Z/Zn)] - - and - - f(t) = t^(1/3) 1 >= t > (24/116)^3 - (841/108)*t + (16/116) 0 <= t <= (24/116)^3 - - - Reverse transform is: - - X = Xn*[a* / 500 + (L* + 16) / 116] ^ 3 if (X/Xn) > (24/116) - = Xn*(a* / 500 + L* / 116) / 7.787 if (X/Xn) <= (24/116) - - - - PCS in Lab2 is encoded as: - - 8 bit Lab PCS: - - L* 0..100 into a 0..ff byte. - a* t + 128 range is -128.0 +127.0 - b* - - 16 bit Lab PCS: - - L* 0..100 into a 0..ff00 word. - a* t + 128 range is -128.0 +127.9961 - b* - - - -Interchange Space Component Actual Range Encoded Range -CIE XYZ X 0 -> 1.99997 0x0000 -> 0xffff -CIE XYZ Y 0 -> 1.99997 0x0000 -> 0xffff -CIE XYZ Z 0 -> 1.99997 0x0000 -> 0xffff - -Version 2,3 ------------ - -CIELAB (16 bit) L* 0 -> 100.0 0x0000 -> 0xff00 -CIELAB (16 bit) a* -128.0 -> +127.996 0x0000 -> 0x8000 -> 0xffff -CIELAB (16 bit) b* -128.0 -> +127.996 0x0000 -> 0x8000 -> 0xffff - - -Version 4 ---------- - -CIELAB (16 bit) L* 0 -> 100.0 0x0000 -> 0xffff -CIELAB (16 bit) a* -128.0 -> +127 0x0000 -> 0x8080 -> 0xffff -CIELAB (16 bit) b* -128.0 -> +127 0x0000 -> 0x8080 -> 0xffff - -*/ - -// Conversions -void CMSEXPORT cmsXYZ2xyY(cmsCIExyY* Dest, const cmsCIEXYZ* Source) -{ - cmsFloat64Number ISum; - - ISum = 1./(Source -> X + Source -> Y + Source -> Z); - - Dest -> x = (Source -> X) * ISum; - Dest -> y = (Source -> Y) * ISum; - Dest -> Y = Source -> Y; -} - -void CMSEXPORT cmsxyY2XYZ(cmsCIEXYZ* Dest, const cmsCIExyY* Source) -{ - Dest -> X = (Source -> x / Source -> y) * Source -> Y; - Dest -> Y = Source -> Y; - Dest -> Z = ((1 - Source -> x - Source -> y) / Source -> y) * Source -> Y; -} - -static -cmsFloat64Number f(cmsFloat64Number t) -{ - const cmsFloat64Number Limit = (24.0/116.0) * (24.0/116.0) * (24.0/116.0); - - if (t <= Limit) - return (841.0/108.0) * t + (16.0/116.0); - else - return pow(t, 1.0/3.0); -} - -static -cmsFloat64Number f_1(cmsFloat64Number t) -{ - const cmsFloat64Number Limit = (24.0/116.0); - - if (t <= Limit) { - return (108.0/841.0) * (t - (16.0/116.0)); - } - - return t * t * t; -} - - -// Standard XYZ to Lab. it can handle negative XZY numbers in some cases -void CMSEXPORT cmsXYZ2Lab(const cmsCIEXYZ* WhitePoint, cmsCIELab* Lab, const cmsCIEXYZ* xyz) -{ - cmsFloat64Number fx, fy, fz; - - if (WhitePoint == NULL) - WhitePoint = cmsD50_XYZ(); - - fx = f(xyz->X / WhitePoint->X); - fy = f(xyz->Y / WhitePoint->Y); - fz = f(xyz->Z / WhitePoint->Z); - - Lab->L = 116.0*fy - 16.0; - Lab->a = 500.0*(fx - fy); - Lab->b = 200.0*(fy - fz); -} - - -// Standard XYZ to Lab. It can return negative XYZ in some cases -void CMSEXPORT cmsLab2XYZ(const cmsCIEXYZ* WhitePoint, cmsCIEXYZ* xyz, const cmsCIELab* Lab) -{ - cmsFloat64Number x, y, z; - - if (WhitePoint == NULL) - WhitePoint = cmsD50_XYZ(); - - y = (Lab-> L + 16.0) / 116.0; - x = y + 0.002 * Lab -> a; - z = y - 0.005 * Lab -> b; - - xyz -> X = f_1(x) * WhitePoint -> X; - xyz -> Y = f_1(y) * WhitePoint -> Y; - xyz -> Z = f_1(z) * WhitePoint -> Z; - -} - -static -cmsFloat64Number L2float2(cmsUInt16Number v) -{ - return (cmsFloat64Number) v / 652.800; -} - -// the a/b part -static -cmsFloat64Number ab2float2(cmsUInt16Number v) -{ - return ((cmsFloat64Number) v / 256.0) - 128.0; -} - -static -cmsUInt16Number L2Fix2(cmsFloat64Number L) -{ - return _cmsQuickSaturateWord(L * 652.8); -} - -static -cmsUInt16Number ab2Fix2(cmsFloat64Number ab) -{ - return _cmsQuickSaturateWord((ab + 128.0) * 256.0); -} - - -static -cmsFloat64Number L2float4(cmsUInt16Number v) -{ - return (cmsFloat64Number) v / 655.35; -} - -// the a/b part -static -cmsFloat64Number ab2float4(cmsUInt16Number v) -{ - return ((cmsFloat64Number) v / 257.0) - 128.0; -} - - -void CMSEXPORT cmsLabEncoded2FloatV2(cmsCIELab* Lab, const cmsUInt16Number wLab[3]) -{ - Lab->L = L2float2(wLab[0]); - Lab->a = ab2float2(wLab[1]); - Lab->b = ab2float2(wLab[2]); -} - - -void CMSEXPORT cmsLabEncoded2Float(cmsCIELab* Lab, const cmsUInt16Number wLab[3]) -{ - Lab->L = L2float4(wLab[0]); - Lab->a = ab2float4(wLab[1]); - Lab->b = ab2float4(wLab[2]); -} - -static -cmsFloat64Number Clamp_L_doubleV2(cmsFloat64Number L) -{ - const cmsFloat64Number L_max = (cmsFloat64Number) (0xFFFF * 100.0) / 0xFF00; - - if (L < 0) L = 0; - if (L > L_max) L = L_max; - - return L; -} - - -static -cmsFloat64Number Clamp_ab_doubleV2(cmsFloat64Number ab) -{ - if (ab < MIN_ENCODEABLE_ab2) ab = MIN_ENCODEABLE_ab2; - if (ab > MAX_ENCODEABLE_ab2) ab = MAX_ENCODEABLE_ab2; - - return ab; -} - -void CMSEXPORT cmsFloat2LabEncodedV2(cmsUInt16Number wLab[3], const cmsCIELab* fLab) -{ - cmsCIELab Lab; - - Lab.L = Clamp_L_doubleV2(fLab ->L); - Lab.a = Clamp_ab_doubleV2(fLab ->a); - Lab.b = Clamp_ab_doubleV2(fLab ->b); - - wLab[0] = L2Fix2(Lab.L); - wLab[1] = ab2Fix2(Lab.a); - wLab[2] = ab2Fix2(Lab.b); -} - - -static -cmsFloat64Number Clamp_L_doubleV4(cmsFloat64Number L) -{ - if (L < 0) L = 0; - if (L > 100.0) L = 100.0; - - return L; -} - -static -cmsFloat64Number Clamp_ab_doubleV4(cmsFloat64Number ab) -{ - if (ab < MIN_ENCODEABLE_ab4) ab = MIN_ENCODEABLE_ab4; - if (ab > MAX_ENCODEABLE_ab4) ab = MAX_ENCODEABLE_ab4; - - return ab; -} - -static -cmsUInt16Number L2Fix4(cmsFloat64Number L) -{ - return _cmsQuickSaturateWord(L * 655.35); -} - -static -cmsUInt16Number ab2Fix4(cmsFloat64Number ab) -{ - return _cmsQuickSaturateWord((ab + 128.0) * 257.0); -} - -void CMSEXPORT cmsFloat2LabEncoded(cmsUInt16Number wLab[3], const cmsCIELab* fLab) -{ - cmsCIELab Lab; - - Lab.L = Clamp_L_doubleV4(fLab ->L); - Lab.a = Clamp_ab_doubleV4(fLab ->a); - Lab.b = Clamp_ab_doubleV4(fLab ->b); - - wLab[0] = L2Fix4(Lab.L); - wLab[1] = ab2Fix4(Lab.a); - wLab[2] = ab2Fix4(Lab.b); -} - -// Auxiliar: convert to Radians -static -cmsFloat64Number RADIANS(cmsFloat64Number deg) -{ - return (deg * M_PI) / 180.; -} - - -// Auxiliar: atan2 but operating in degrees and returning 0 if a==b==0 -static -cmsFloat64Number atan2deg(cmsFloat64Number a, cmsFloat64Number b) -{ - cmsFloat64Number h; - - if (a == 0 && b == 0) - h = 0; - else - h = atan2(a, b); - - h *= (180. / M_PI); - - while (h > 360.) - h -= 360.; - - while ( h < 0) - h += 360.; - - return h; -} - - -// Auxiliar: Square -static -cmsFloat64Number Sqr(cmsFloat64Number v) -{ - return v * v; -} -// From cylindrical coordinates. No check is performed, then negative values are allowed -void CMSEXPORT cmsLab2LCh(cmsCIELCh* LCh, const cmsCIELab* Lab) -{ - LCh -> L = Lab -> L; - LCh -> C = pow(Sqr(Lab ->a) + Sqr(Lab ->b), 0.5); - LCh -> h = atan2deg(Lab ->b, Lab ->a); -} - - -// To cylindrical coordinates. No check is performed, then negative values are allowed -void CMSEXPORT cmsLCh2Lab(cmsCIELab* Lab, const cmsCIELCh* LCh) -{ - cmsFloat64Number h = (LCh -> h * M_PI) / 180.0; - - Lab -> L = LCh -> L; - Lab -> a = LCh -> C * cos(h); - Lab -> b = LCh -> C * sin(h); -} - -// In XYZ All 3 components are encoded using 1.15 fixed point -static -cmsUInt16Number XYZ2Fix(cmsFloat64Number d) -{ - return _cmsQuickSaturateWord(d * 32768.0); -} - -void CMSEXPORT cmsFloat2XYZEncoded(cmsUInt16Number XYZ[3], const cmsCIEXYZ* fXYZ) -{ - cmsCIEXYZ xyz; - - xyz.X = fXYZ -> X; - xyz.Y = fXYZ -> Y; - xyz.Z = fXYZ -> Z; - - // Clamp to encodeable values. - if (xyz.Y <= 0) { - - xyz.X = 0; - xyz.Y = 0; - xyz.Z = 0; - } - - if (xyz.X > MAX_ENCODEABLE_XYZ) - xyz.X = MAX_ENCODEABLE_XYZ; - - if (xyz.X < 0) - xyz.X = 0; - - if (xyz.Y > MAX_ENCODEABLE_XYZ) - xyz.Y = MAX_ENCODEABLE_XYZ; - - if (xyz.Y < 0) - xyz.Y = 0; - - if (xyz.Z > MAX_ENCODEABLE_XYZ) - xyz.Z = MAX_ENCODEABLE_XYZ; - - if (xyz.Z < 0) - xyz.Z = 0; - - - XYZ[0] = XYZ2Fix(xyz.X); - XYZ[1] = XYZ2Fix(xyz.Y); - XYZ[2] = XYZ2Fix(xyz.Z); -} - - -// To convert from Fixed 1.15 point to cmsFloat64Number -static -cmsFloat64Number XYZ2float(cmsUInt16Number v) -{ - cmsS15Fixed16Number fix32; - - // From 1.15 to 15.16 - fix32 = v << 1; - - // From fixed 15.16 to cmsFloat64Number - return _cms15Fixed16toDouble(fix32); -} - - -void CMSEXPORT cmsXYZEncoded2Float(cmsCIEXYZ* fXYZ, const cmsUInt16Number XYZ[3]) -{ - fXYZ -> X = XYZ2float(XYZ[0]); - fXYZ -> Y = XYZ2float(XYZ[1]); - fXYZ -> Z = XYZ2float(XYZ[2]); -} - - -// Returns dE on two Lab values -cmsFloat64Number CMSEXPORT cmsDeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2) -{ - cmsFloat64Number dL, da, db; - - dL = fabs(Lab1 -> L - Lab2 -> L); - da = fabs(Lab1 -> a - Lab2 -> a); - db = fabs(Lab1 -> b - Lab2 -> b); - - return pow(Sqr(dL) + Sqr(da) + Sqr(db), 0.5); -} - - -// Return the CIE94 Delta E -cmsFloat64Number CMSEXPORT cmsCIE94DeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2) -{ - cmsCIELCh LCh1, LCh2; - cmsFloat64Number dE, dL, dC, dh, dhsq; - cmsFloat64Number c12, sc, sh; - - dL = fabs(Lab1 ->L - Lab2 ->L); - - cmsLab2LCh(&LCh1, Lab1); - cmsLab2LCh(&LCh2, Lab2); - - dC = fabs(LCh1.C - LCh2.C); - dE = cmsDeltaE(Lab1, Lab2); - - dhsq = Sqr(dE) - Sqr(dL) - Sqr(dC); - if (dhsq < 0) - dh = 0; - else - dh = pow(dhsq, 0.5); - - c12 = sqrt(LCh1.C * LCh2.C); - - sc = 1.0 + (0.048 * c12); - sh = 1.0 + (0.014 * c12); - - return sqrt(Sqr(dL) + Sqr(dC) / Sqr(sc) + Sqr(dh) / Sqr(sh)); -} - - -// Auxiliary -static -cmsFloat64Number ComputeLBFD(const cmsCIELab* Lab) -{ - cmsFloat64Number yt; - - if (Lab->L > 7.996969) - yt = (Sqr((Lab->L+16)/116)*((Lab->L+16)/116))*100; - else - yt = 100 * (Lab->L / 903.3); - - return (54.6 * (M_LOG10E * (log(yt + 1.5))) - 9.6); -} - - - -// bfd - gets BFD(1:1) difference between Lab1, Lab2 -cmsFloat64Number CMSEXPORT cmsBFDdeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2) -{ - cmsFloat64Number lbfd1,lbfd2,AveC,Aveh,dE,deltaL, - deltaC,deltah,dc,t,g,dh,rh,rc,rt,bfd; - cmsCIELCh LCh1, LCh2; - - - lbfd1 = ComputeLBFD(Lab1); - lbfd2 = ComputeLBFD(Lab2); - deltaL = lbfd2 - lbfd1; - - cmsLab2LCh(&LCh1, Lab1); - cmsLab2LCh(&LCh2, Lab2); - - deltaC = LCh2.C - LCh1.C; - AveC = (LCh1.C+LCh2.C)/2; - Aveh = (LCh1.h+LCh2.h)/2; - - dE = cmsDeltaE(Lab1, Lab2); - - if (Sqr(dE)>(Sqr(Lab2->L-Lab1->L)+Sqr(deltaC))) - deltah = sqrt(Sqr(dE)-Sqr(Lab2->L-Lab1->L)-Sqr(deltaC)); - else - deltah =0; - - - dc = 0.035 * AveC / (1 + 0.00365 * AveC)+0.521; - g = sqrt(Sqr(Sqr(AveC))/(Sqr(Sqr(AveC))+14000)); - t = 0.627+(0.055*cos((Aveh-254)/(180/M_PI))- - 0.040*cos((2*Aveh-136)/(180/M_PI))+ - 0.070*cos((3*Aveh-31)/(180/M_PI))+ - 0.049*cos((4*Aveh+114)/(180/M_PI))- - 0.015*cos((5*Aveh-103)/(180/M_PI))); - - dh = dc*(g*t+1-g); - rh = -0.260*cos((Aveh-308)/(180/M_PI))- - 0.379*cos((2*Aveh-160)/(180/M_PI))- - 0.636*cos((3*Aveh+254)/(180/M_PI))+ - 0.226*cos((4*Aveh+140)/(180/M_PI))- - 0.194*cos((5*Aveh+280)/(180/M_PI)); - - rc = sqrt((AveC*AveC*AveC*AveC*AveC*AveC)/((AveC*AveC*AveC*AveC*AveC*AveC)+70000000)); - rt = rh*rc; - - bfd = sqrt(Sqr(deltaL)+Sqr(deltaC/dc)+Sqr(deltah/dh)+(rt*(deltaC/dc)*(deltah/dh))); - - return bfd; -} - - -// cmc - CMC(l:c) difference between Lab1, Lab2 -cmsFloat64Number CMSEXPORT cmsCMCdeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2, cmsFloat64Number l, cmsFloat64Number c) -{ - cmsFloat64Number dE,dL,dC,dh,sl,sc,sh,t,f,cmc; - cmsCIELCh LCh1, LCh2; - - if (Lab1 ->L == 0 && Lab2 ->L == 0) return 0; - - cmsLab2LCh(&LCh1, Lab1); - cmsLab2LCh(&LCh2, Lab2); - - - dL = Lab2->L-Lab1->L; - dC = LCh2.C-LCh1.C; - - dE = cmsDeltaE(Lab1, Lab2); - - if (Sqr(dE)>(Sqr(dL)+Sqr(dC))) - dh = sqrt(Sqr(dE)-Sqr(dL)-Sqr(dC)); - else - dh =0; - - if ((LCh1.h > 164) && (LCh1.h < 345)) - t = 0.56 + fabs(0.2 * cos(((LCh1.h + 168)/(180/M_PI)))); - else - t = 0.36 + fabs(0.4 * cos(((LCh1.h + 35 )/(180/M_PI)))); - - sc = 0.0638 * LCh1.C / (1 + 0.0131 * LCh1.C) + 0.638; - sl = 0.040975 * Lab1->L /(1 + 0.01765 * Lab1->L); - - if (Lab1->L<16) - sl = 0.511; - - f = sqrt((LCh1.C * LCh1.C * LCh1.C * LCh1.C)/((LCh1.C * LCh1.C * LCh1.C * LCh1.C)+1900)); - sh = sc*(t*f+1-f); - cmc = sqrt(Sqr(dL/(l*sl))+Sqr(dC/(c*sc))+Sqr(dh/sh)); - - return cmc; -} - -// dE2000 The weightings KL, KC and KH can be modified to reflect the relative -// importance of lightness, chroma and hue in different industrial applications -cmsFloat64Number CMSEXPORT cmsCIE2000DeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2, - cmsFloat64Number Kl, cmsFloat64Number Kc, cmsFloat64Number Kh) -{ - cmsFloat64Number L1 = Lab1->L; - cmsFloat64Number a1 = Lab1->a; - cmsFloat64Number b1 = Lab1->b; - cmsFloat64Number C = sqrt( Sqr(a1) + Sqr(b1) ); - - cmsFloat64Number Ls = Lab2 ->L; - cmsFloat64Number as = Lab2 ->a; - cmsFloat64Number bs = Lab2 ->b; - cmsFloat64Number Cs = sqrt( Sqr(as) + Sqr(bs) ); - - cmsFloat64Number G = 0.5 * ( 1 - sqrt(pow((C + Cs) / 2 , 7.0) / (pow((C + Cs) / 2, 7.0) + pow(25.0, 7.0) ) )); - - cmsFloat64Number a_p = (1 + G ) * a1; - cmsFloat64Number b_p = b1; - cmsFloat64Number C_p = sqrt( Sqr(a_p) + Sqr(b_p)); - cmsFloat64Number h_p = atan2deg(b_p, a_p); - - - cmsFloat64Number a_ps = (1 + G) * as; - cmsFloat64Number b_ps = bs; - cmsFloat64Number C_ps = sqrt(Sqr(a_ps) + Sqr(b_ps)); - cmsFloat64Number h_ps = atan2deg(b_ps, a_ps); - - cmsFloat64Number meanC_p =(C_p + C_ps) / 2; - - cmsFloat64Number hps_plus_hp = h_ps + h_p; - cmsFloat64Number hps_minus_hp = h_ps - h_p; - - cmsFloat64Number meanh_p = fabs(hps_minus_hp) <= 180.000001 ? (hps_plus_hp)/2 : - (hps_plus_hp) < 360 ? (hps_plus_hp + 360)/2 : - (hps_plus_hp - 360)/2; - - cmsFloat64Number delta_h = (hps_minus_hp) <= -180.000001 ? (hps_minus_hp + 360) : - (hps_minus_hp) > 180 ? (hps_minus_hp - 360) : - (hps_minus_hp); - cmsFloat64Number delta_L = (Ls - L1); - cmsFloat64Number delta_C = (C_ps - C_p ); - - - cmsFloat64Number delta_H =2 * sqrt(C_ps*C_p) * sin(RADIANS(delta_h) / 2); - - cmsFloat64Number T = 1 - 0.17 * cos(RADIANS(meanh_p-30)) - + 0.24 * cos(RADIANS(2*meanh_p)) - + 0.32 * cos(RADIANS(3*meanh_p + 6)) - - 0.2 * cos(RADIANS(4*meanh_p - 63)); - - cmsFloat64Number Sl = 1 + (0.015 * Sqr((Ls + L1) /2- 50) )/ sqrt(20 + Sqr( (Ls+L1)/2 - 50) ); - - cmsFloat64Number Sc = 1 + 0.045 * (C_p + C_ps)/2; - cmsFloat64Number Sh = 1 + 0.015 * ((C_ps + C_p)/2) * T; - - cmsFloat64Number delta_ro = 30 * exp( -Sqr(((meanh_p - 275 ) / 25))); - - cmsFloat64Number Rc = 2 * sqrt(( pow(meanC_p, 7.0) )/( pow(meanC_p, 7.0) + pow(25.0, 7.0))); - - cmsFloat64Number Rt = -sin(2 * RADIANS(delta_ro)) * Rc; - - cmsFloat64Number deltaE00 = sqrt( Sqr(delta_L /(Sl * Kl)) + - Sqr(delta_C/(Sc * Kc)) + - Sqr(delta_H/(Sh * Kh)) + - Rt*(delta_C/(Sc * Kc)) * (delta_H / (Sh * Kh))); - - return deltaE00; -} - -// This function returns a number of gridpoints to be used as LUT table. It assumes same number -// of gripdpoints in all dimensions. Flags may override the choice. -int _cmsReasonableGridpointsByColorspace(cmsColorSpaceSignature Colorspace, cmsUInt32Number dwFlags) -{ - int nChannels; - - // Already specified? - if (dwFlags & 0x00FF0000) { - // Yes, grab'em - return (dwFlags >> 16) & 0xFF; - } - - nChannels = cmsChannelsOf(Colorspace); - - // HighResPrecalc is maximum resolution - if (dwFlags & cmsFLAGS_HIGHRESPRECALC) { - - if (nChannels > 4) - return 7; // 7 for Hifi - - if (nChannels == 4) // 23 for CMYK - return 23; - - return 49; // 49 for RGB and others - } - - - // LowResPrecal is lower resolution - if (dwFlags & cmsFLAGS_LOWRESPRECALC) { - - if (nChannels > 4) - return 6; // 6 for more than 4 channels - - if (nChannels == 1) - return 33; // For monochrome - - return 17; // 17 for remaining - } - - // Default values - if (nChannels > 4) - return 7; // 7 for Hifi - - if (nChannels == 4) - return 17; // 17 for CMYK - - return 33; // 33 for RGB -} - - -cmsBool _cmsEndPointsBySpace(cmsColorSpaceSignature Space, - cmsUInt16Number **White, - cmsUInt16Number **Black, - cmsUInt32Number *nOutputs) -{ - // Only most common spaces - - static cmsUInt16Number RGBblack[4] = { 0, 0, 0 }; - static cmsUInt16Number RGBwhite[4] = { 0xffff, 0xffff, 0xffff }; - static cmsUInt16Number CMYKblack[4] = { 0xffff, 0xffff, 0xffff, 0xffff }; // 400% of ink - static cmsUInt16Number CMYKwhite[4] = { 0, 0, 0, 0 }; - static cmsUInt16Number LABblack[4] = { 0, 0x8080, 0x8080 }; // V4 Lab encoding - static cmsUInt16Number LABwhite[4] = { 0xFFFF, 0x8080, 0x8080 }; - static cmsUInt16Number CMYblack[4] = { 0xffff, 0xffff, 0xffff }; - static cmsUInt16Number CMYwhite[4] = { 0, 0, 0 }; - static cmsUInt16Number Grayblack[4] = { 0 }; - static cmsUInt16Number GrayWhite[4] = { 0xffff }; - - switch (Space) { - - case cmsSigGrayData: if (White) *White = GrayWhite; - if (Black) *Black = Grayblack; - if (nOutputs) *nOutputs = 1; - return TRUE; - - case cmsSigRgbData: if (White) *White = RGBwhite; - if (Black) *Black = RGBblack; - if (nOutputs) *nOutputs = 3; - return TRUE; - - case cmsSigLabData: if (White) *White = LABwhite; - if (Black) *Black = LABblack; - if (nOutputs) *nOutputs = 3; - return TRUE; - - case cmsSigCmykData: if (White) *White = CMYKwhite; - if (Black) *Black = CMYKblack; - if (nOutputs) *nOutputs = 4; - return TRUE; - - case cmsSigCmyData: if (White) *White = CMYwhite; - if (Black) *Black = CMYblack; - if (nOutputs) *nOutputs = 3; - return TRUE; - - default:; - } - - return FALSE; -} - - - -// Several utilities ------------------------------------------------------- - -// Translate from our colorspace to ICC representation - -cmsColorSpaceSignature CMSEXPORT _cmsICCcolorSpace(int OurNotation) -{ - switch (OurNotation) { - - case 1: - case PT_GRAY: return cmsSigGrayData; - - case 2: - case PT_RGB: return cmsSigRgbData; - - case PT_CMY: return cmsSigCmyData; - case PT_CMYK: return cmsSigCmykData; - case PT_YCbCr:return cmsSigYCbCrData; - case PT_YUV: return cmsSigLuvData; - case PT_XYZ: return cmsSigXYZData; - - case PT_LabV2: - case PT_Lab: return cmsSigLabData; - - case PT_YUVK: return cmsSigLuvKData; - case PT_HSV: return cmsSigHsvData; - case PT_HLS: return cmsSigHlsData; - case PT_Yxy: return cmsSigYxyData; - - case PT_MCH1: return cmsSigMCH1Data; - case PT_MCH2: return cmsSigMCH2Data; - case PT_MCH3: return cmsSigMCH3Data; - case PT_MCH4: return cmsSigMCH4Data; - case PT_MCH5: return cmsSigMCH5Data; - case PT_MCH6: return cmsSigMCH6Data; - case PT_MCH7: return cmsSigMCH7Data; - case PT_MCH8: return cmsSigMCH8Data; - - case PT_MCH9: return cmsSigMCH9Data; - case PT_MCH10: return cmsSigMCHAData; - case PT_MCH11: return cmsSigMCHBData; - case PT_MCH12: return cmsSigMCHCData; - case PT_MCH13: return cmsSigMCHDData; - case PT_MCH14: return cmsSigMCHEData; - case PT_MCH15: return cmsSigMCHFData; - - default: return (cmsColorSpaceSignature) (-1); - } -} - - -int CMSEXPORT _cmsLCMScolorSpace(cmsColorSpaceSignature ProfileSpace) -{ - switch (ProfileSpace) { - - case cmsSigGrayData: return PT_GRAY; - case cmsSigRgbData: return PT_RGB; - case cmsSigCmyData: return PT_CMY; - case cmsSigCmykData: return PT_CMYK; - case cmsSigYCbCrData:return PT_YCbCr; - case cmsSigLuvData: return PT_YUV; - case cmsSigXYZData: return PT_XYZ; - case cmsSigLabData: return PT_Lab; - case cmsSigLuvKData: return PT_YUVK; - case cmsSigHsvData: return PT_HSV; - case cmsSigHlsData: return PT_HLS; - case cmsSigYxyData: return PT_Yxy; - - case cmsSig1colorData: - case cmsSigMCH1Data: return PT_MCH1; - - case cmsSig2colorData: - case cmsSigMCH2Data: return PT_MCH2; - - case cmsSig3colorData: - case cmsSigMCH3Data: return PT_MCH3; - - case cmsSig4colorData: - case cmsSigMCH4Data: return PT_MCH4; - - case cmsSig5colorData: - case cmsSigMCH5Data: return PT_MCH5; - - case cmsSig6colorData: - case cmsSigMCH6Data: return PT_MCH6; - - case cmsSigMCH7Data: - case cmsSig7colorData:return PT_MCH7; - - case cmsSigMCH8Data: - case cmsSig8colorData:return PT_MCH8; - - case cmsSigMCH9Data: - case cmsSig9colorData:return PT_MCH9; - - case cmsSigMCHAData: - case cmsSig10colorData:return PT_MCH10; - - case cmsSigMCHBData: - case cmsSig11colorData:return PT_MCH11; - - case cmsSigMCHCData: - case cmsSig12colorData:return PT_MCH12; - - case cmsSigMCHDData: - case cmsSig13colorData:return PT_MCH13; - - case cmsSigMCHEData: - case cmsSig14colorData:return PT_MCH14; - - case cmsSigMCHFData: - case cmsSig15colorData:return PT_MCH15; - - default: return (cmsColorSpaceSignature) (-1); - } -} - - -cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace) -{ - switch (ColorSpace) { - - case cmsSigMCH1Data: - case cmsSig1colorData: - case cmsSigGrayData: return 1; - - case cmsSigMCH2Data: - case cmsSig2colorData: return 2; - - case cmsSigXYZData: - case cmsSigLabData: - case cmsSigLuvData: - case cmsSigYCbCrData: - case cmsSigYxyData: - case cmsSigRgbData: - case cmsSigHsvData: - case cmsSigHlsData: - case cmsSigCmyData: - case cmsSigMCH3Data: - case cmsSig3colorData: return 3; - - case cmsSigLuvKData: - case cmsSigCmykData: - case cmsSigMCH4Data: - case cmsSig4colorData: return 4; - - case cmsSigMCH5Data: - case cmsSig5colorData: return 5; - - case cmsSigMCH6Data: - case cmsSig6colorData: return 6; - - case cmsSigMCH7Data: - case cmsSig7colorData: return 7; - - case cmsSigMCH8Data: - case cmsSig8colorData: return 8; - - case cmsSigMCH9Data: - case cmsSig9colorData: return 9; - - case cmsSigMCHAData: - case cmsSig10colorData: return 10; - - case cmsSigMCHBData: - case cmsSig11colorData: return 11; - - case cmsSigMCHCData: - case cmsSig12colorData: return 12; - - case cmsSigMCHDData: - case cmsSig13colorData: return 13; - - case cmsSigMCHEData: - case cmsSig14colorData: return 14; - - case cmsSigMCHFData: - case cmsSig15colorData: return 15; - - default: return 3; - } -} diff --git a/third_party/lcms2-2.6/src/cmsplugin.c b/third_party/lcms2-2.6/src/cmsplugin.c deleted file mode 100644 index 42c4002b55..0000000000 --- a/third_party/lcms2-2.6/src/cmsplugin.c +++ /dev/null @@ -1,959 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- -// - -#include "lcms2_internal.h" - - -// ---------------------------------------------------------------------------------- -// Encoding & Decoding support functions -// ---------------------------------------------------------------------------------- - -// Little-Endian to Big-Endian - -// Adjust a word value after being readed/ before being written from/to an ICC profile -cmsUInt16Number CMSEXPORT _cmsAdjustEndianess16(cmsUInt16Number Word) -{ -#ifndef CMS_USE_BIG_ENDIAN - - cmsUInt8Number* pByte = (cmsUInt8Number*) &Word; - cmsUInt8Number tmp; - - tmp = pByte[0]; - pByte[0] = pByte[1]; - pByte[1] = tmp; -#endif - - return Word; -} - - -// Transports to properly encoded values - note that icc profiles does use big endian notation. - -// 1 2 3 4 -// 4 3 2 1 - -cmsUInt32Number CMSEXPORT _cmsAdjustEndianess32(cmsUInt32Number DWord) -{ -#ifndef CMS_USE_BIG_ENDIAN - - cmsUInt8Number* pByte = (cmsUInt8Number*) &DWord; - cmsUInt8Number temp1; - cmsUInt8Number temp2; - - temp1 = *pByte++; - temp2 = *pByte++; - *(pByte-1) = *pByte; - *pByte++ = temp2; - *(pByte-3) = *pByte; - *pByte = temp1; -#endif - return DWord; -} - -// 1 2 3 4 5 6 7 8 -// 8 7 6 5 4 3 2 1 - -void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number* QWord) -{ - -#ifndef CMS_USE_BIG_ENDIAN - - cmsUInt8Number* pIn = (cmsUInt8Number*) QWord; - cmsUInt8Number* pOut = (cmsUInt8Number*) Result; - - _cmsAssert(Result != NULL); - - pOut[7] = pIn[0]; - pOut[6] = pIn[1]; - pOut[5] = pIn[2]; - pOut[4] = pIn[3]; - pOut[3] = pIn[4]; - pOut[2] = pIn[5]; - pOut[1] = pIn[6]; - pOut[0] = pIn[7]; - -#else - _cmsAssert(Result != NULL); - -# ifdef CMS_DONT_USE_INT64 - (*Result)[0] = QWord[0]; - (*Result)[1] = QWord[1]; -# else - *Result = *QWord; -# endif -#endif -} - -// Auxiliar -- read 8, 16 and 32-bit numbers -cmsBool CMSEXPORT _cmsReadUInt8Number(cmsIOHANDLER* io, cmsUInt8Number* n) -{ - cmsUInt8Number tmp; - - _cmsAssert(io != NULL); - - if (io -> Read(io, &tmp, sizeof(cmsUInt8Number), 1) != 1) - return FALSE; - - if (n != NULL) *n = tmp; - return TRUE; -} - -cmsBool CMSEXPORT _cmsReadUInt16Number(cmsIOHANDLER* io, cmsUInt16Number* n) -{ - cmsUInt16Number tmp; - - _cmsAssert(io != NULL); - - if (io -> Read(io, &tmp, sizeof(cmsUInt16Number), 1) != 1) - return FALSE; - - if (n != NULL) *n = _cmsAdjustEndianess16(tmp); - return TRUE; -} - -cmsBool CMSEXPORT _cmsReadUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, cmsUInt16Number* Array) -{ - cmsUInt32Number i; - - _cmsAssert(io != NULL); - - for (i=0; i < n; i++) { - - if (Array != NULL) { - if (!_cmsReadUInt16Number(io, Array + i)) return FALSE; - } - else { - if (!_cmsReadUInt16Number(io, NULL)) return FALSE; - } - - } - return TRUE; -} - -cmsBool CMSEXPORT _cmsReadUInt32Number(cmsIOHANDLER* io, cmsUInt32Number* n) -{ - cmsUInt32Number tmp; - - _cmsAssert(io != NULL); - - if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1) - return FALSE; - - if (n != NULL) *n = _cmsAdjustEndianess32(tmp); - return TRUE; -} - -cmsBool CMSEXPORT _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n) -{ - cmsUInt32Number tmp; - - _cmsAssert(io != NULL); - - if (io -> Read(io, &tmp, sizeof(cmsFloat32Number), 1) != 1) - return FALSE; - - if (n != NULL) { - - tmp = _cmsAdjustEndianess32(tmp); - *n = *(cmsFloat32Number*) &tmp; - if (isnan(*n)) - return FALSE; - } - - // fpclassify() required by C99 - return (fpclassify(*n) == FP_ZERO) || (fpclassify(*n) == FP_NORMAL); -} - - -cmsBool CMSEXPORT _cmsReadUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n) -{ - cmsUInt64Number tmp; - - _cmsAssert(io != NULL); - - if (io -> Read(io, &tmp, sizeof(cmsUInt64Number), 1) != 1) - return FALSE; - - if (n != NULL) _cmsAdjustEndianess64(n, &tmp); - return TRUE; -} - - -cmsBool CMSEXPORT _cmsRead15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number* n) -{ - cmsUInt32Number tmp; - - _cmsAssert(io != NULL); - - if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1) - return FALSE; - - if (n != NULL) { - *n = _cms15Fixed16toDouble(_cmsAdjustEndianess32(tmp)); - } - - return TRUE; -} - - -// Jun-21-2000: Some profiles (those that comes with W2K) comes -// with the media white (media black?) x 100. Add a sanity check - -static -void NormalizeXYZ(cmsCIEXYZ* Dest) -{ - while (Dest -> X > 2. && - Dest -> Y > 2. && - Dest -> Z > 2.) { - - Dest -> X /= 10.; - Dest -> Y /= 10.; - Dest -> Z /= 10.; - } -} - -cmsBool CMSEXPORT _cmsReadXYZNumber(cmsIOHANDLER* io, cmsCIEXYZ* XYZ) -{ - cmsEncodedXYZNumber xyz; - - _cmsAssert(io != NULL); - - if (io ->Read(io, &xyz, sizeof(cmsEncodedXYZNumber), 1) != 1) return FALSE; - - if (XYZ != NULL) { - - XYZ->X = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.X)); - XYZ->Y = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Y)); - XYZ->Z = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Z)); - - NormalizeXYZ(XYZ); - } - return TRUE; -} - -cmsBool CMSEXPORT _cmsWriteUInt8Number(cmsIOHANDLER* io, cmsUInt8Number n) -{ - _cmsAssert(io != NULL); - - if (io -> Write(io, sizeof(cmsUInt8Number), &n) != 1) - return FALSE; - - return TRUE; -} - -cmsBool CMSEXPORT _cmsWriteUInt16Number(cmsIOHANDLER* io, cmsUInt16Number n) -{ - cmsUInt16Number tmp; - - _cmsAssert(io != NULL); - - tmp = _cmsAdjustEndianess16(n); - if (io -> Write(io, sizeof(cmsUInt16Number), &tmp) != 1) - return FALSE; - - return TRUE; -} - -cmsBool CMSEXPORT _cmsWriteUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, const cmsUInt16Number* Array) -{ - cmsUInt32Number i; - - _cmsAssert(io != NULL); - _cmsAssert(Array != NULL); - - for (i=0; i < n; i++) { - if (!_cmsWriteUInt16Number(io, Array[i])) return FALSE; - } - - return TRUE; -} - -cmsBool CMSEXPORT _cmsWriteUInt32Number(cmsIOHANDLER* io, cmsUInt32Number n) -{ - cmsUInt32Number tmp; - - _cmsAssert(io != NULL); - - tmp = _cmsAdjustEndianess32(n); - if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1) - return FALSE; - - return TRUE; -} - - -cmsBool CMSEXPORT _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n) -{ - cmsUInt32Number tmp; - - _cmsAssert(io != NULL); - - tmp = *(cmsUInt32Number*) &n; - tmp = _cmsAdjustEndianess32(tmp); - if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1) - return FALSE; - - return TRUE; -} - -cmsBool CMSEXPORT _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n) -{ - cmsUInt64Number tmp; - - _cmsAssert(io != NULL); - - _cmsAdjustEndianess64(&tmp, n); - if (io -> Write(io, sizeof(cmsUInt64Number), &tmp) != 1) - return FALSE; - - return TRUE; -} - -cmsBool CMSEXPORT _cmsWrite15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number n) -{ - cmsUInt32Number tmp; - - _cmsAssert(io != NULL); - - tmp = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(n)); - if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1) - return FALSE; - - return TRUE; -} - -cmsBool CMSEXPORT _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ) -{ - cmsEncodedXYZNumber xyz; - - _cmsAssert(io != NULL); - _cmsAssert(XYZ != NULL); - - xyz.X = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->X)); - xyz.Y = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->Y)); - xyz.Z = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->Z)); - - return io -> Write(io, sizeof(cmsEncodedXYZNumber), &xyz); -} - -// from Fixed point 8.8 to double -cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8) -{ - cmsUInt8Number msb, lsb; - - lsb = (cmsUInt8Number) (fixed8 & 0xff); - msb = (cmsUInt8Number) (((cmsUInt16Number) fixed8 >> 8) & 0xff); - - return (cmsFloat64Number) ((cmsFloat64Number) msb + ((cmsFloat64Number) lsb / 256.0)); -} - -cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val) -{ - cmsS15Fixed16Number GammaFixed32 = _cmsDoubleTo15Fixed16(val); - return (cmsUInt16Number) ((GammaFixed32 >> 8) & 0xFFFF); -} - -// from Fixed point 15.16 to double -cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32) -{ - cmsFloat64Number floater, sign, mid; - int Whole, FracPart; - - sign = (fix32 < 0 ? -1 : 1); - fix32 = abs(fix32); - - Whole = (cmsUInt16Number)(fix32 >> 16) & 0xffff; - FracPart = (cmsUInt16Number)(fix32 & 0xffff); - - mid = (cmsFloat64Number) FracPart / 65536.0; - floater = (cmsFloat64Number) Whole + mid; - - return sign * floater; -} - -// from double to Fixed point 15.16 -cmsS15Fixed16Number CMSEXPORT _cmsDoubleTo15Fixed16(cmsFloat64Number v) -{ - return ((cmsS15Fixed16Number) floor((v)*65536.0 + 0.5)); -} - -// Date/Time functions - -void CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeNumber *Source, struct tm *Dest) -{ - - _cmsAssert(Dest != NULL); - _cmsAssert(Source != NULL); - - Dest->tm_sec = _cmsAdjustEndianess16(Source->seconds); - Dest->tm_min = _cmsAdjustEndianess16(Source->minutes); - Dest->tm_hour = _cmsAdjustEndianess16(Source->hours); - Dest->tm_mday = _cmsAdjustEndianess16(Source->day); - Dest->tm_mon = _cmsAdjustEndianess16(Source->month) - 1; - Dest->tm_year = _cmsAdjustEndianess16(Source->year) - 1900; - Dest->tm_wday = -1; - Dest->tm_yday = -1; - Dest->tm_isdst = 0; -} - -void CMSEXPORT _cmsEncodeDateTimeNumber(cmsDateTimeNumber *Dest, const struct tm *Source) -{ - _cmsAssert(Dest != NULL); - _cmsAssert(Source != NULL); - - Dest->seconds = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_sec); - Dest->minutes = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_min); - Dest->hours = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_hour); - Dest->day = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_mday); - Dest->month = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_mon + 1)); - Dest->year = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_year + 1900)); -} - -// Read base and return type base -cmsTagTypeSignature CMSEXPORT _cmsReadTypeBase(cmsIOHANDLER* io) -{ - _cmsTagBase Base; - - _cmsAssert(io != NULL); - - if (io -> Read(io, &Base, sizeof(_cmsTagBase), 1) != 1) - return (cmsTagTypeSignature) 0; - - return (cmsTagTypeSignature) _cmsAdjustEndianess32(Base.sig); -} - -// Setup base marker -cmsBool CMSEXPORT _cmsWriteTypeBase(cmsIOHANDLER* io, cmsTagTypeSignature sig) -{ - _cmsTagBase Base; - - _cmsAssert(io != NULL); - - Base.sig = (cmsTagTypeSignature) _cmsAdjustEndianess32(sig); - memset(&Base.reserved, 0, sizeof(Base.reserved)); - return io -> Write(io, sizeof(_cmsTagBase), &Base); -} - -cmsBool CMSEXPORT _cmsReadAlignment(cmsIOHANDLER* io) -{ - cmsUInt8Number Buffer[4]; - cmsUInt32Number NextAligned, At; - cmsUInt32Number BytesToNextAlignedPos; - - _cmsAssert(io != NULL); - - At = io -> Tell(io); - NextAligned = _cmsALIGNLONG(At); - BytesToNextAlignedPos = NextAligned - At; - if (BytesToNextAlignedPos == 0) return TRUE; - if (BytesToNextAlignedPos > 4) return FALSE; - - return (io ->Read(io, Buffer, BytesToNextAlignedPos, 1) == 1); -} - -cmsBool CMSEXPORT _cmsWriteAlignment(cmsIOHANDLER* io) -{ - cmsUInt8Number Buffer[4]; - cmsUInt32Number NextAligned, At; - cmsUInt32Number BytesToNextAlignedPos; - - _cmsAssert(io != NULL); - - At = io -> Tell(io); - NextAligned = _cmsALIGNLONG(At); - BytesToNextAlignedPos = NextAligned - At; - if (BytesToNextAlignedPos == 0) return TRUE; - if (BytesToNextAlignedPos > 4) return FALSE; - - memset(Buffer, 0, BytesToNextAlignedPos); - return io -> Write(io, BytesToNextAlignedPos, Buffer); -} - - -// To deal with text streams. 2K at most -cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...) -{ - va_list args; - int len; - cmsUInt8Number Buffer[2048]; - cmsBool rc; - - _cmsAssert(io != NULL); - _cmsAssert(frm != NULL); - - va_start(args, frm); - - len = vsnprintf((char*) Buffer, 2047, frm, args); - if (len < 0) return FALSE; // Truncated, which is a fatal error for us - - rc = io ->Write(io, len, Buffer); - - va_end(args); - - return rc; -} - - -// Plugin memory management ------------------------------------------------------------------------------------------------- - -// Specialized malloc for plug-ins, that is freed upon exit. -void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size) -{ - struct _cmsContext_struct* ctx = _cmsGetContext(ContextID); - - if (ctx ->MemPool == NULL) { - - if (ContextID == NULL) { - - ctx->MemPool = _cmsCreateSubAlloc(0, 2*1024); - } - else { - cmsSignalError(ContextID, cmsERROR_CORRUPTION_DETECTED, "NULL memory pool on context"); - return NULL; - } - } - - return _cmsSubAlloc(ctx->MemPool, size); -} - - -// Main plug-in dispatcher -cmsBool CMSEXPORT cmsPlugin(void* Plug_in) -{ - return cmsPluginTHR(NULL, Plug_in); -} - -cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in) -{ - cmsPluginBase* Plugin; - - for (Plugin = (cmsPluginBase*) Plug_in; - Plugin != NULL; - Plugin = Plugin -> Next) { - - if (Plugin -> Magic != cmsPluginMagicNumber) { - cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin"); - return FALSE; - } - - if (Plugin ->ExpectedVersion > LCMS_VERSION) { - cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d", - Plugin ->ExpectedVersion, LCMS_VERSION); - return FALSE; - } - - switch (Plugin -> Type) { - - case cmsPluginMemHandlerSig: - if (!_cmsRegisterMemHandlerPlugin(id, Plugin)) return FALSE; - break; - - case cmsPluginInterpolationSig: - if (!_cmsRegisterInterpPlugin(id, Plugin)) return FALSE; - break; - - case cmsPluginTagTypeSig: - if (!_cmsRegisterTagTypePlugin(id, Plugin)) return FALSE; - break; - - case cmsPluginTagSig: - if (!_cmsRegisterTagPlugin(id, Plugin)) return FALSE; - break; - - case cmsPluginFormattersSig: - if (!_cmsRegisterFormattersPlugin(id, Plugin)) return FALSE; - break; - - case cmsPluginRenderingIntentSig: - if (!_cmsRegisterRenderingIntentPlugin(id, Plugin)) return FALSE; - break; - - case cmsPluginParametricCurveSig: - if (!_cmsRegisterParametricCurvesPlugin(id, Plugin)) return FALSE; - break; - - case cmsPluginMultiProcessElementSig: - if (!_cmsRegisterMultiProcessElementPlugin(id, Plugin)) return FALSE; - break; - - case cmsPluginOptimizationSig: - if (!_cmsRegisterOptimizationPlugin(id, Plugin)) return FALSE; - break; - - case cmsPluginTransformSig: - if (!_cmsRegisterTransformPlugin(id, Plugin)) return FALSE; - break; - - case cmsPluginMutexSig: - if (!_cmsRegisterMutexPlugin(id, Plugin)) return FALSE; - break; - - default: - cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type); - return FALSE; - } - } - - // Keep a reference to the plug-in - return TRUE; -} - - -// Revert all plug-ins to default -void CMSEXPORT cmsUnregisterPlugins(void) -{ - cmsUnregisterPluginsTHR(NULL); -} - - -// The Global storage for system context. This is the one and only global variable -// pointers structure. All global vars are referenced here. -static struct _cmsContext_struct globalContext = { - - NULL, // Not in the linked list - NULL, // No suballocator - { - NULL, // UserPtr, - &_cmsLogErrorChunk, // Logger, - &_cmsAlarmCodesChunk, // AlarmCodes, - &_cmsAdaptationStateChunk, // AdaptationState, - &_cmsMemPluginChunk, // MemPlugin, - &_cmsInterpPluginChunk, // InterpPlugin, - &_cmsCurvesPluginChunk, // CurvesPlugin, - &_cmsFormattersPluginChunk, // FormattersPlugin, - &_cmsTagTypePluginChunk, // TagTypePlugin, - &_cmsTagPluginChunk, // TagPlugin, - &_cmsIntentsPluginChunk, // IntentPlugin, - &_cmsMPETypePluginChunk, // MPEPlugin, - &_cmsOptimizationPluginChunk, // OptimizationPlugin, - &_cmsTransformPluginChunk, // TransformPlugin, - &_cmsMutexPluginChunk // MutexPlugin - }, - - { NULL, NULL, NULL, NULL, NULL, NULL } // The default memory allocator is not used for context 0 -}; - - -// The context pool (linked list head) -static _cmsMutex _cmsContextPoolHeadMutex = CMS_MUTEX_INITIALIZER; -static struct _cmsContext_struct* _cmsContextPoolHead = NULL; - -// Internal, get associated pointer, with guessing. Never returns NULL. -struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID) -{ - struct _cmsContext_struct* id = (struct _cmsContext_struct*) ContextID; - struct _cmsContext_struct* ctx; - - - // On 0, use global settings - if (id == NULL) - return &globalContext; - - // Search - for (ctx = _cmsContextPoolHead; - ctx != NULL; - ctx = ctx ->Next) { - - // Found it? - if (id == ctx) - return ctx; // New-style context, - } - - return &globalContext; -} - - -// Internal: get the memory area associanted with each context client -// Returns the block assigned to the specific zone. -void* _cmsContextGetClientChunk(cmsContext ContextID, _cmsMemoryClient mc) -{ - struct _cmsContext_struct* ctx; - void *ptr; - - if (mc >= MemoryClientMax) { - cmsSignalError(ContextID, cmsERROR_RANGE, "Bad context client"); - return NULL; - } - - ctx = _cmsGetContext(ContextID); - ptr = ctx ->chunks[mc]; - - if (ptr != NULL) - return ptr; - - // A null ptr means no special settings for that context, and this - // reverts to Context0 globals - return globalContext.chunks[mc]; -} - - -// This function returns the given context its default pristine state, -// as no plug-ins were declared. There is no way to unregister a single -// plug-in, as a single call to cmsPluginTHR() function may register -// many different plug-ins simultaneously, then there is no way to -// identify which plug-in to unregister. -void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID) -{ - _cmsRegisterMemHandlerPlugin(ContextID, NULL); - _cmsRegisterInterpPlugin(ContextID, NULL); - _cmsRegisterTagTypePlugin(ContextID, NULL); - _cmsRegisterTagPlugin(ContextID, NULL); - _cmsRegisterFormattersPlugin(ContextID, NULL); - _cmsRegisterRenderingIntentPlugin(ContextID, NULL); - _cmsRegisterParametricCurvesPlugin(ContextID, NULL); - _cmsRegisterMultiProcessElementPlugin(ContextID, NULL); - _cmsRegisterOptimizationPlugin(ContextID, NULL); - _cmsRegisterTransformPlugin(ContextID, NULL); - _cmsRegisterMutexPlugin(ContextID, NULL); -} - - -// Returns the memory manager plug-in, if any, from the Plug-in bundle -static -cmsPluginMemHandler* _cmsFindMemoryPlugin(void* PluginBundle) -{ - cmsPluginBase* Plugin; - - for (Plugin = (cmsPluginBase*) PluginBundle; - Plugin != NULL; - Plugin = Plugin -> Next) { - - if (Plugin -> Magic == cmsPluginMagicNumber && - Plugin -> ExpectedVersion <= LCMS_VERSION && - Plugin -> Type == cmsPluginMemHandlerSig) { - - // Found! - return (cmsPluginMemHandler*) Plugin; - } - } - - // Nope, revert to defaults - return NULL; -} - - -// Creates a new context with optional associated plug-ins. Caller may also specify an optional pointer to user-defined -// data that will be forwarded to plug-ins and logger. -cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData) -{ - struct _cmsContext_struct* ctx; - struct _cmsContext_struct fakeContext; - - _cmsInstallAllocFunctions(_cmsFindMemoryPlugin(Plugin), &fakeContext.DefaultMemoryManager); - - fakeContext.chunks[UserPtr] = UserData; - fakeContext.chunks[MemPlugin] = &fakeContext.DefaultMemoryManager; - - // Create the context structure. - ctx = (struct _cmsContext_struct*) _cmsMalloc(&fakeContext, sizeof(struct _cmsContext_struct)); - if (ctx == NULL) - return NULL; // Something very wrong happened! - - // Init the structure and the memory manager - memset(ctx, 0, sizeof(struct _cmsContext_struct)); - - // Keep memory manager - memcpy(&ctx->DefaultMemoryManager, &fakeContext.DefaultMemoryManager, sizeof(_cmsMemPluginChunk)); - - // Maintain the linked list (with proper locking) - _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); - ctx ->Next = _cmsContextPoolHead; - _cmsContextPoolHead = ctx; - _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); - - ctx ->chunks[UserPtr] = UserData; - ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager; - - // Now we can allocate the pool by using default memory manager - ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*)); // default size about 32 pointers - if (ctx ->MemPool == NULL) { - - cmsDeleteContext(ctx); - return NULL; - } - - _cmsAllocLogErrorChunk(ctx, NULL); - _cmsAllocAlarmCodesChunk(ctx, NULL); - _cmsAllocAdaptationStateChunk(ctx, NULL); - _cmsAllocMemPluginChunk(ctx, NULL); - _cmsAllocInterpPluginChunk(ctx, NULL); - _cmsAllocCurvesPluginChunk(ctx, NULL); - _cmsAllocFormattersPluginChunk(ctx, NULL); - _cmsAllocTagTypePluginChunk(ctx, NULL); - _cmsAllocMPETypePluginChunk(ctx, NULL); - _cmsAllocTagPluginChunk(ctx, NULL); - _cmsAllocIntentsPluginChunk(ctx, NULL); - _cmsAllocOptimizationPluginChunk(ctx, NULL); - _cmsAllocTransformPluginChunk(ctx, NULL); - _cmsAllocMutexPluginChunk(ctx, NULL); - - // Setup the plug-ins - if (!cmsPluginTHR(ctx, Plugin)) { - - cmsDeleteContext(ctx); - return NULL; - } - - return (cmsContext) ctx; -} - -// Duplicates a context with all associated plug-ins. -// Caller may specify an optional pointer to user-defined -// data that will be forwarded to plug-ins and logger. -cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData) -{ - int i; - struct _cmsContext_struct* ctx; - const struct _cmsContext_struct* src = _cmsGetContext(ContextID); - - void* userData = (NewUserData != NULL) ? NewUserData : src -> chunks[UserPtr]; - - - ctx = (struct _cmsContext_struct*) _cmsMalloc(ContextID, sizeof(struct _cmsContext_struct)); - if (ctx == NULL) - return NULL; // Something very wrong happened - - // Setup default memory allocators - memcpy(&ctx->DefaultMemoryManager, &src->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager)); - - // Maintain the linked list - _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); - ctx ->Next = _cmsContextPoolHead; - _cmsContextPoolHead = ctx; - _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); - - ctx ->chunks[UserPtr] = userData; - ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager; - - ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*)); - if (ctx ->MemPool == NULL) { - - cmsDeleteContext(ctx); - return NULL; - } - - // Allocate all required chunks. - _cmsAllocLogErrorChunk(ctx, src); - _cmsAllocAlarmCodesChunk(ctx, src); - _cmsAllocAdaptationStateChunk(ctx, src); - _cmsAllocMemPluginChunk(ctx, src); - _cmsAllocInterpPluginChunk(ctx, src); - _cmsAllocCurvesPluginChunk(ctx, src); - _cmsAllocFormattersPluginChunk(ctx, src); - _cmsAllocTagTypePluginChunk(ctx, src); - _cmsAllocMPETypePluginChunk(ctx, src); - _cmsAllocTagPluginChunk(ctx, src); - _cmsAllocIntentsPluginChunk(ctx, src); - _cmsAllocOptimizationPluginChunk(ctx, src); - _cmsAllocTransformPluginChunk(ctx, src); - _cmsAllocMutexPluginChunk(ctx, src); - - // Make sure no one failed - for (i=Logger; i < MemoryClientMax; i++) { - - if (src ->chunks[i] == NULL) { - cmsDeleteContext((cmsContext) ctx); - return NULL; - } - } - - return (cmsContext) ctx; -} - - - -static -struct _cmsContext_struct* FindPrev(struct _cmsContext_struct* id) -{ - struct _cmsContext_struct* prev; - - // Search for previous - for (prev = _cmsContextPoolHead; - prev != NULL; - prev = prev ->Next) - { - if (prev ->Next == id) - return prev; - } - - return NULL; // List is empty or only one element! -} - -// Frees any resources associated with the given context, -// and destroys the context placeholder. -// The ContextID can no longer be used in any THR operation. -void CMSEXPORT cmsDeleteContext(cmsContext ContextID) -{ - if (ContextID != NULL) { - - struct _cmsContext_struct* ctx = (struct _cmsContext_struct*) ContextID; - struct _cmsContext_struct fakeContext; - struct _cmsContext_struct* prev; - - memcpy(&fakeContext.DefaultMemoryManager, &ctx->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager)); - - fakeContext.chunks[UserPtr] = ctx ->chunks[UserPtr]; - fakeContext.chunks[MemPlugin] = &fakeContext.DefaultMemoryManager; - - // Get rid of plugins - cmsUnregisterPluginsTHR(ContextID); - - // Since all memory is allocated in the private pool, all what we need to do is destroy the pool - if (ctx -> MemPool != NULL) - _cmsSubAllocDestroy(ctx ->MemPool); - ctx -> MemPool = NULL; - - // Maintain list - _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); - if (_cmsContextPoolHead == ctx) { - - _cmsContextPoolHead = ctx->Next; - } - else { - - // Search for previous - for (prev = _cmsContextPoolHead; - prev != NULL; - prev = prev ->Next) - { - if (prev -> Next == ctx) { - prev -> Next = ctx ->Next; - break; - } - } - } - _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); - - // free the memory block itself - _cmsFree(&fakeContext, ctx); - } -} - -// Returns the user data associated to the given ContextID, or NULL if no user data was attached on context creation -void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID) -{ - return _cmsContextGetClientChunk(ContextID, UserPtr); -} diff --git a/third_party/lcms2-2.6/src/cmsps2.c b/third_party/lcms2-2.6/src/cmsps2.c deleted file mode 100644 index 224b44b542..0000000000 --- a/third_party/lcms2-2.6/src/cmsps2.c +++ /dev/null @@ -1,1597 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2011 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- -// - -#include "lcms2_internal.h" - -// PostScript ColorRenderingDictionary and ColorSpaceArray - - -#define MAXPSCOLS 60 // Columns on tables - -/* - Implementation - -------------- - - PostScript does use XYZ as its internal PCS. But since PostScript - interpolation tables are limited to 8 bits, I use Lab as a way to - improve the accuracy, favoring perceptual results. So, for the creation - of each CRD, CSA the profiles are converted to Lab via a device - link between profile -> Lab or Lab -> profile. The PS code necessary to - convert Lab <-> XYZ is also included. - - - - Color Space Arrays (CSA) - ================================================================================== - - In order to obtain precision, code chooses between three ways to implement - the device -> XYZ transform. These cases identifies monochrome profiles (often - implemented as a set of curves), matrix-shaper and Pipeline-based. - - Monochrome - ----------- - - This is implemented as /CIEBasedA CSA. The prelinearization curve is - placed into /DecodeA section, and matrix equals to D50. Since here is - no interpolation tables, I do the conversion directly to XYZ - - NOTE: CLUT-based monochrome profiles are NOT supported. So, cmsFLAGS_MATRIXINPUT - flag is forced on such profiles. - - [ /CIEBasedA - << - /DecodeA { transfer function } bind - /MatrixA [D50] - /RangeLMN [ 0.0 cmsD50X 0.0 cmsD50Y 0.0 cmsD50Z ] - /WhitePoint [D50] - /BlackPoint [BP] - /RenderingIntent (intent) - >> - ] - - On simpler profiles, the PCS is already XYZ, so no conversion is required. - - - Matrix-shaper based - ------------------- - - This is implemented both with /CIEBasedABC or /CIEBasedDEF on dependig - of profile implementation. Since here there are no interpolation tables, I do - the conversion directly to XYZ - - - - [ /CIEBasedABC - << - /DecodeABC [ {transfer1} {transfer2} {transfer3} ] - /MatrixABC [Matrix] - /RangeLMN [ 0.0 cmsD50X 0.0 cmsD50Y 0.0 cmsD50Z ] - /DecodeLMN [ { / 2} dup dup ] - /WhitePoint [D50] - /BlackPoint [BP] - /RenderingIntent (intent) - >> - ] - - - CLUT based - ---------- - - Lab is used in such cases. - - [ /CIEBasedDEF - << - /DecodeDEF [ <prelinearization> ] - /Table [ p p p [<...>]] - /RangeABC [ 0 1 0 1 0 1] - /DecodeABC[ <postlinearization> ] - /RangeLMN [ -0.236 1.254 0 1 -0.635 1.640 ] - % -128/500 1+127/500 0 1 -127/200 1+128/200 - /MatrixABC [ 1 1 1 1 0 0 0 0 -1] - /WhitePoint [D50] - /BlackPoint [BP] - /RenderingIntent (intent) - ] - - - Color Rendering Dictionaries (CRD) - ================================== - These are always implemented as CLUT, and always are using Lab. Since CRD are expected to - be used as resources, the code adds the definition as well. - - << - /ColorRenderingType 1 - /WhitePoint [ D50 ] - /BlackPoint [BP] - /MatrixPQR [ Bradford ] - /RangePQR [-0.125 1.375 -0.125 1.375 -0.125 1.375 ] - /TransformPQR [ - {4 index 3 get div 2 index 3 get mul exch pop exch pop exch pop exch pop } bind - {4 index 4 get div 2 index 4 get mul exch pop exch pop exch pop exch pop } bind - {4 index 5 get div 2 index 5 get mul exch pop exch pop exch pop exch pop } bind - ] - /MatrixABC <...> - /EncodeABC <...> - /RangeABC <.. used for XYZ -> Lab> - /EncodeLMN - /RenderTable [ p p p [<...>]] - - /RenderingIntent (Perceptual) - >> - /Current exch /ColorRendering defineresource pop - - - The following stages are used to convert from XYZ to Lab - -------------------------------------------------------- - - Input is given at LMN stage on X, Y, Z - - Encode LMN gives us f(X/Xn), f(Y/Yn), f(Z/Zn) - - /EncodeLMN [ - - { 0.964200 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind - { 1.000000 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind - { 0.824900 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind - - ] - - - MatrixABC is used to compute f(Y/Yn), f(X/Xn) - f(Y/Yn), f(Y/Yn) - f(Z/Zn) - - | 0 1 0| - | 1 -1 0| - | 0 1 -1| - - /MatrixABC [ 0 1 0 1 -1 1 0 0 -1 ] - - EncodeABC finally gives Lab values. - - /EncodeABC [ - { 116 mul 16 sub 100 div } bind - { 500 mul 128 add 255 div } bind - { 200 mul 128 add 255 div } bind - ] - - The following stages are used to convert Lab to XYZ - ---------------------------------------------------- - - /RangeABC [ 0 1 0 1 0 1] - /DecodeABC [ { 100 mul 16 add 116 div } bind - { 255 mul 128 sub 500 div } bind - { 255 mul 128 sub 200 div } bind - ] - - /MatrixABC [ 1 1 1 1 0 0 0 0 -1] - /DecodeLMN [ - {dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.964200 mul} bind - {dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse } bind - {dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.824900 mul} bind - ] - - -*/ - -/* - - PostScript algorithms discussion. - ========================================================================================================= - - 1D interpolation algorithm - - - 1D interpolation (float) - ------------------------ - - val2 = Domain * Value; - - cell0 = (int) floor(val2); - cell1 = (int) ceil(val2); - - rest = val2 - cell0; - - y0 = LutTable[cell0] ; - y1 = LutTable[cell1] ; - - y = y0 + (y1 - y0) * rest; - - - - PostScript code Stack - ================================================ - - { % v - <check 0..1.0> - [array] % v tab - dup % v tab tab - length 1 sub % v tab dom - - 3 -1 roll % tab dom v - - mul % tab val2 - dup % tab val2 val2 - dup % tab val2 val2 val2 - floor cvi % tab val2 val2 cell0 - exch % tab val2 cell0 val2 - ceiling cvi % tab val2 cell0 cell1 - - 3 index % tab val2 cell0 cell1 tab - exch % tab val2 cell0 tab cell1 - get % tab val2 cell0 y1 - - 4 -1 roll % val2 cell0 y1 tab - 3 -1 roll % val2 y1 tab cell0 - get % val2 y1 y0 - - dup % val2 y1 y0 y0 - 3 1 roll % val2 y0 y1 y0 - - sub % val2 y0 (y1-y0) - 3 -1 roll % y0 (y1-y0) val2 - dup % y0 (y1-y0) val2 val2 - floor cvi % y0 (y1-y0) val2 floor(val2) - sub % y0 (y1-y0) rest - mul % y0 t1 - add % y - 65535 div % result - - } bind - - -*/ - - -// This struct holds the memory block currently being write -typedef struct { - _cmsStageCLutData* Pipeline; - cmsIOHANDLER* m; - - int FirstComponent; - int SecondComponent; - - const char* PreMaj; - const char* PostMaj; - const char* PreMin; - const char* PostMin; - - int FixWhite; // Force mapping of pure white - - cmsColorSpaceSignature ColorSpace; // ColorSpace of profile - - -} cmsPsSamplerCargo; - -static int _cmsPSActualColumn = 0; - - -// Convert to byte -static -cmsUInt8Number Word2Byte(cmsUInt16Number w) -{ - return (cmsUInt8Number) floor((cmsFloat64Number) w / 257.0 + 0.5); -} - - -// Convert to byte (using ICC2 notation) -/* -static -cmsUInt8Number L2Byte(cmsUInt16Number w) -{ - int ww = w + 0x0080; - - if (ww > 0xFFFF) return 0xFF; - - return (cmsUInt8Number) ((cmsUInt16Number) (ww >> 8) & 0xFF); -} -*/ - -// Write a cooked byte - -static -void WriteByte(cmsIOHANDLER* m, cmsUInt8Number b) -{ - _cmsIOPrintf(m, "%02x", b); - _cmsPSActualColumn += 2; - - if (_cmsPSActualColumn > MAXPSCOLS) { - - _cmsIOPrintf(m, "\n"); - _cmsPSActualColumn = 0; - } -} - -// ----------------------------------------------------------------- PostScript generation - - -// Removes offending Carriage returns -static -char* RemoveCR(const char* txt) -{ - static char Buffer[2048]; - char* pt; - - strncpy(Buffer, txt, 2047); - Buffer[2047] = 0; - for (pt = Buffer; *pt; pt++) - if (*pt == '\n' || *pt == '\r') *pt = ' '; - - return Buffer; - -} - -static -void EmitHeader(cmsIOHANDLER* m, const char* Title, cmsHPROFILE hProfile) -{ - time_t timer; - cmsMLU *Description, *Copyright; - char DescASCII[256], CopyrightASCII[256]; - - time(&timer); - - Description = (cmsMLU*) cmsReadTag(hProfile, cmsSigProfileDescriptionTag); - Copyright = (cmsMLU*) cmsReadTag(hProfile, cmsSigCopyrightTag); - - DescASCII[0] = DescASCII[255] = 0; - CopyrightASCII[0] = CopyrightASCII[255] = 0; - - if (Description != NULL) cmsMLUgetASCII(Description, cmsNoLanguage, cmsNoCountry, DescASCII, 255); - if (Copyright != NULL) cmsMLUgetASCII(Copyright, cmsNoLanguage, cmsNoCountry, CopyrightASCII, 255); - - _cmsIOPrintf(m, "%%!PS-Adobe-3.0\n"); - _cmsIOPrintf(m, "%%\n"); - _cmsIOPrintf(m, "%% %s\n", Title); - _cmsIOPrintf(m, "%% Source: %s\n", RemoveCR(DescASCII)); - _cmsIOPrintf(m, "%% %s\n", RemoveCR(CopyrightASCII)); - _cmsIOPrintf(m, "%% Created: %s", ctime(&timer)); // ctime appends a \n!!! - _cmsIOPrintf(m, "%%\n"); - _cmsIOPrintf(m, "%%%%BeginResource\n"); - -} - - -// Emits White & Black point. White point is always D50, Black point is the device -// Black point adapted to D50. - -static -void EmitWhiteBlackD50(cmsIOHANDLER* m, cmsCIEXYZ* BlackPoint) -{ - - _cmsIOPrintf(m, "/BlackPoint [%f %f %f]\n", BlackPoint -> X, - BlackPoint -> Y, - BlackPoint -> Z); - - _cmsIOPrintf(m, "/WhitePoint [%f %f %f]\n", cmsD50_XYZ()->X, - cmsD50_XYZ()->Y, - cmsD50_XYZ()->Z); -} - - -static -void EmitRangeCheck(cmsIOHANDLER* m) -{ - _cmsIOPrintf(m, "dup 0.0 lt { pop 0.0 } if " - "dup 1.0 gt { pop 1.0 } if "); - -} - -// Does write the intent - -static -void EmitIntent(cmsIOHANDLER* m, int RenderingIntent) -{ - const char *intent; - - switch (RenderingIntent) { - - case INTENT_PERCEPTUAL: intent = "Perceptual"; break; - case INTENT_RELATIVE_COLORIMETRIC: intent = "RelativeColorimetric"; break; - case INTENT_ABSOLUTE_COLORIMETRIC: intent = "AbsoluteColorimetric"; break; - case INTENT_SATURATION: intent = "Saturation"; break; - - default: intent = "Undefined"; break; - } - - _cmsIOPrintf(m, "/RenderingIntent (%s)\n", intent ); -} - -// -// Convert L* to Y -// -// Y = Yn*[ (L* + 16) / 116] ^ 3 if (L*) >= 6 / 29 -// = Yn*( L* / 116) / 7.787 if (L*) < 6 / 29 -// - -/* -static -void EmitL2Y(cmsIOHANDLER* m) -{ - _cmsIOPrintf(m, - "{ " - "100 mul 16 add 116 div " // (L * 100 + 16) / 116 - "dup 6 29 div ge " // >= 6 / 29 ? - "{ dup dup mul mul } " // yes, ^3 and done - "{ 4 29 div sub 108 841 div mul } " // no, slope limiting - "ifelse } bind "); -} -*/ - - -// Lab -> XYZ, see the discussion above - -static -void EmitLab2XYZ(cmsIOHANDLER* m) -{ - _cmsIOPrintf(m, "/RangeABC [ 0 1 0 1 0 1]\n"); - _cmsIOPrintf(m, "/DecodeABC [\n"); - _cmsIOPrintf(m, "{100 mul 16 add 116 div } bind\n"); - _cmsIOPrintf(m, "{255 mul 128 sub 500 div } bind\n"); - _cmsIOPrintf(m, "{255 mul 128 sub 200 div } bind\n"); - _cmsIOPrintf(m, "]\n"); - _cmsIOPrintf(m, "/MatrixABC [ 1 1 1 1 0 0 0 0 -1]\n"); - _cmsIOPrintf(m, "/RangeLMN [ -0.236 1.254 0 1 -0.635 1.640 ]\n"); - _cmsIOPrintf(m, "/DecodeLMN [\n"); - _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.964200 mul} bind\n"); - _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse } bind\n"); - _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.824900 mul} bind\n"); - _cmsIOPrintf(m, "]\n"); -} - - - -// Outputs a table of words. It does use 16 bits - -static -void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table) -{ - cmsUInt32Number i; - cmsFloat64Number gamma; - - if (Table == NULL) return; // Error - - if (Table ->nEntries <= 0) return; // Empty table - - // Suppress whole if identity - if (cmsIsToneCurveLinear(Table)) return; - - // Check if is really an exponential. If so, emit "exp" - gamma = cmsEstimateGamma(Table, 0.001); - if (gamma > 0) { - _cmsIOPrintf(m, "{ %g exp } bind ", gamma); - return; - } - - _cmsIOPrintf(m, "{ "); - - // Bounds check - EmitRangeCheck(m); - - // Emit intepolation code - - // PostScript code Stack - // =============== ======================== - // v - _cmsIOPrintf(m, " ["); - - for (i=0; i < Table->nEntries; i++) { - _cmsIOPrintf(m, "%d ", Table->Table16[i]); - } - - _cmsIOPrintf(m, "] "); // v tab - - _cmsIOPrintf(m, "dup "); // v tab tab - _cmsIOPrintf(m, "length 1 sub "); // v tab dom - _cmsIOPrintf(m, "3 -1 roll "); // tab dom v - _cmsIOPrintf(m, "mul "); // tab val2 - _cmsIOPrintf(m, "dup "); // tab val2 val2 - _cmsIOPrintf(m, "dup "); // tab val2 val2 val2 - _cmsIOPrintf(m, "floor cvi "); // tab val2 val2 cell0 - _cmsIOPrintf(m, "exch "); // tab val2 cell0 val2 - _cmsIOPrintf(m, "ceiling cvi "); // tab val2 cell0 cell1 - _cmsIOPrintf(m, "3 index "); // tab val2 cell0 cell1 tab - _cmsIOPrintf(m, "exch "); // tab val2 cell0 tab cell1 - _cmsIOPrintf(m, "get "); // tab val2 cell0 y1 - _cmsIOPrintf(m, "4 -1 roll "); // val2 cell0 y1 tab - _cmsIOPrintf(m, "3 -1 roll "); // val2 y1 tab cell0 - _cmsIOPrintf(m, "get "); // val2 y1 y0 - _cmsIOPrintf(m, "dup "); // val2 y1 y0 y0 - _cmsIOPrintf(m, "3 1 roll "); // val2 y0 y1 y0 - _cmsIOPrintf(m, "sub "); // val2 y0 (y1-y0) - _cmsIOPrintf(m, "3 -1 roll "); // y0 (y1-y0) val2 - _cmsIOPrintf(m, "dup "); // y0 (y1-y0) val2 val2 - _cmsIOPrintf(m, "floor cvi "); // y0 (y1-y0) val2 floor(val2) - _cmsIOPrintf(m, "sub "); // y0 (y1-y0) rest - _cmsIOPrintf(m, "mul "); // y0 t1 - _cmsIOPrintf(m, "add "); // y - _cmsIOPrintf(m, "65535 div "); // result - - _cmsIOPrintf(m, " } bind "); -} - - -// Compare gamma table - -static -cmsBool GammaTableEquals(cmsUInt16Number* g1, cmsUInt16Number* g2, int nEntries) -{ - return memcmp(g1, g2, nEntries* sizeof(cmsUInt16Number)) == 0; -} - - -// Does write a set of gamma curves - -static -void EmitNGamma(cmsIOHANDLER* m, int n, cmsToneCurve* g[]) -{ - int i; - - for( i=0; i < n; i++ ) - { - if (g[i] == NULL) return; // Error - - if (i > 0 && GammaTableEquals(g[i-1]->Table16, g[i]->Table16, g[i]->nEntries)) { - - _cmsIOPrintf(m, "dup "); - } - else { - Emit1Gamma(m, g[i]); - } - } - -} - - - - - -// Following code dumps a LUT onto memory stream - - -// This is the sampler. Intended to work in SAMPLER_INSPECT mode, -// that is, the callback will be called for each knot with -// -// In[] The grid location coordinates, normalized to 0..ffff -// Out[] The Pipeline values, normalized to 0..ffff -// -// Returning a value other than 0 does terminate the sampling process -// -// Each row contains Pipeline values for all but first component. So, I -// detect row changing by keeping a copy of last value of first -// component. -1 is used to mark begining of whole block. - -static -int OutputValueSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) -{ - cmsPsSamplerCargo* sc = (cmsPsSamplerCargo*) Cargo; - cmsUInt32Number i; - - - if (sc -> FixWhite) { - - if (In[0] == 0xFFFF) { // Only in L* = 100, ab = [-8..8] - - if ((In[1] >= 0x7800 && In[1] <= 0x8800) && - (In[2] >= 0x7800 && In[2] <= 0x8800)) { - - cmsUInt16Number* Black; - cmsUInt16Number* White; - cmsUInt32Number nOutputs; - - if (!_cmsEndPointsBySpace(sc ->ColorSpace, &White, &Black, &nOutputs)) - return 0; - - for (i=0; i < nOutputs; i++) - Out[i] = White[i]; - } - - - } - } - - - // Hadle the parenthesis on rows - - if (In[0] != sc ->FirstComponent) { - - if (sc ->FirstComponent != -1) { - - _cmsIOPrintf(sc ->m, sc ->PostMin); - sc ->SecondComponent = -1; - _cmsIOPrintf(sc ->m, sc ->PostMaj); - } - - // Begin block - _cmsPSActualColumn = 0; - - _cmsIOPrintf(sc ->m, sc ->PreMaj); - sc ->FirstComponent = In[0]; - } - - - if (In[1] != sc ->SecondComponent) { - - if (sc ->SecondComponent != -1) { - - _cmsIOPrintf(sc ->m, sc ->PostMin); - } - - _cmsIOPrintf(sc ->m, sc ->PreMin); - sc ->SecondComponent = In[1]; - } - - // Dump table. - - for (i=0; i < sc -> Pipeline ->Params->nOutputs; i++) { - - cmsUInt16Number wWordOut = Out[i]; - cmsUInt8Number wByteOut; // Value as byte - - - // We always deal with Lab4 - - wByteOut = Word2Byte(wWordOut); - WriteByte(sc -> m, wByteOut); - } - - return 1; -} - -// Writes a Pipeline on memstream. Could be 8 or 16 bits based - -static -void WriteCLUT(cmsIOHANDLER* m, cmsStage* mpe, const char* PreMaj, - const char* PostMaj, - const char* PreMin, - const char* PostMin, - int FixWhite, - cmsColorSpaceSignature ColorSpace) -{ - cmsUInt32Number i; - cmsPsSamplerCargo sc; - - sc.FirstComponent = -1; - sc.SecondComponent = -1; - sc.Pipeline = (_cmsStageCLutData *) mpe ->Data; - sc.m = m; - sc.PreMaj = PreMaj; - sc.PostMaj= PostMaj; - - sc.PreMin = PreMin; - sc.PostMin = PostMin; - sc.FixWhite = FixWhite; - sc.ColorSpace = ColorSpace; - - _cmsIOPrintf(m, "["); - - for (i=0; i < sc.Pipeline->Params->nInputs; i++) - _cmsIOPrintf(m, " %d ", sc.Pipeline->Params->nSamples[i]); - - _cmsIOPrintf(m, " [\n"); - - cmsStageSampleCLut16bit(mpe, OutputValueSampler, (void*) &sc, SAMPLER_INSPECT); - - _cmsIOPrintf(m, PostMin); - _cmsIOPrintf(m, PostMaj); - _cmsIOPrintf(m, "] "); - -} - - -// Dumps CIEBasedA Color Space Array - -static -int EmitCIEBasedA(cmsIOHANDLER* m, cmsToneCurve* Curve, cmsCIEXYZ* BlackPoint) -{ - - _cmsIOPrintf(m, "[ /CIEBasedA\n"); - _cmsIOPrintf(m, " <<\n"); - - _cmsIOPrintf(m, "/DecodeA "); - - Emit1Gamma(m, Curve); - - _cmsIOPrintf(m, " \n"); - - _cmsIOPrintf(m, "/MatrixA [ 0.9642 1.0000 0.8249 ]\n"); - _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n"); - - EmitWhiteBlackD50(m, BlackPoint); - EmitIntent(m, INTENT_PERCEPTUAL); - - _cmsIOPrintf(m, ">>\n"); - _cmsIOPrintf(m, "]\n"); - - return 1; -} - - -// Dumps CIEBasedABC Color Space Array - -static -int EmitCIEBasedABC(cmsIOHANDLER* m, cmsFloat64Number* Matrix, cmsToneCurve** CurveSet, cmsCIEXYZ* BlackPoint) -{ - int i; - - _cmsIOPrintf(m, "[ /CIEBasedABC\n"); - _cmsIOPrintf(m, "<<\n"); - _cmsIOPrintf(m, "/DecodeABC [ "); - - EmitNGamma(m, 3, CurveSet); - - _cmsIOPrintf(m, "]\n"); - - _cmsIOPrintf(m, "/MatrixABC [ " ); - - for( i=0; i < 3; i++ ) { - - _cmsIOPrintf(m, "%.6f %.6f %.6f ", Matrix[i + 3*0], - Matrix[i + 3*1], - Matrix[i + 3*2]); - } - - - _cmsIOPrintf(m, "]\n"); - - _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n"); - - EmitWhiteBlackD50(m, BlackPoint); - EmitIntent(m, INTENT_PERCEPTUAL); - - _cmsIOPrintf(m, ">>\n"); - _cmsIOPrintf(m, "]\n"); - - - return 1; -} - - -static -int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, int Intent, cmsCIEXYZ* BlackPoint) -{ - const char* PreMaj; - const char* PostMaj; - const char* PreMin, *PostMin; - cmsStage* mpe; - - mpe = Pipeline ->Elements; - - switch (cmsStageInputChannels(mpe)) { - case 3: - - _cmsIOPrintf(m, "[ /CIEBasedDEF\n"); - PreMaj ="<"; - PostMaj= ">\n"; - PreMin = PostMin = ""; - break; - case 4: - _cmsIOPrintf(m, "[ /CIEBasedDEFG\n"); - PreMaj = "["; - PostMaj = "]\n"; - PreMin = "<"; - PostMin = ">\n"; - break; - default: - return 0; - - } - - _cmsIOPrintf(m, "<<\n"); - - if (cmsStageType(mpe) == cmsSigCurveSetElemType) { - - _cmsIOPrintf(m, "/DecodeDEF [ "); - EmitNGamma(m, cmsStageOutputChannels(mpe), _cmsStageGetPtrToCurveSet(mpe)); - _cmsIOPrintf(m, "]\n"); - - mpe = mpe ->Next; - } - - if (cmsStageType(mpe) == cmsSigCLutElemType) { - - _cmsIOPrintf(m, "/Table "); - WriteCLUT(m, mpe, PreMaj, PostMaj, PreMin, PostMin, FALSE, (cmsColorSpaceSignature) 0); - _cmsIOPrintf(m, "]\n"); - } - - EmitLab2XYZ(m); - EmitWhiteBlackD50(m, BlackPoint); - EmitIntent(m, Intent); - - _cmsIOPrintf(m, " >>\n"); - _cmsIOPrintf(m, "]\n"); - - return 1; -} - -// Generates a curve from a gray profile - -static - cmsToneCurve* ExtractGray2Y(cmsContext ContextID, cmsHPROFILE hProfile, int Intent) -{ - cmsToneCurve* Out = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL); - cmsHPROFILE hXYZ = cmsCreateXYZProfile(); - cmsHTRANSFORM xform = cmsCreateTransformTHR(ContextID, hProfile, TYPE_GRAY_8, hXYZ, TYPE_XYZ_DBL, Intent, cmsFLAGS_NOOPTIMIZE); - int i; - - if (Out != NULL) { - for (i=0; i < 256; i++) { - - cmsUInt8Number Gray = (cmsUInt8Number) i; - cmsCIEXYZ XYZ; - - cmsDoTransform(xform, &Gray, &XYZ, 1); - - Out ->Table16[i] =_cmsQuickSaturateWord(XYZ.Y * 65535.0); - } - } - - cmsDeleteTransform(xform); - cmsCloseProfile(hXYZ); - return Out; -} - - - -// Because PostScript has only 8 bits in /Table, we should use -// a more perceptually uniform space... I do choose Lab. - -static -int WriteInputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Number dwFlags) -{ - cmsHPROFILE hLab; - cmsHTRANSFORM xform; - cmsUInt32Number nChannels; - cmsUInt32Number InputFormat; - int rc; - cmsHPROFILE Profiles[2]; - cmsCIEXYZ BlackPointAdaptedToD50; - - // Does create a device-link based transform. - // The DeviceLink is next dumped as working CSA. - - InputFormat = cmsFormatterForColorspaceOfProfile(hProfile, 2, FALSE); - nChannels = T_CHANNELS(InputFormat); - - - cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, 0); - - // Adjust output to Lab4 - hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL); - - Profiles[0] = hProfile; - Profiles[1] = hLab; - - xform = cmsCreateMultiprofileTransform(Profiles, 2, InputFormat, TYPE_Lab_DBL, Intent, 0); - cmsCloseProfile(hLab); - - if (xform == NULL) { - - cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Profile -> Lab"); - return 0; - } - - // Only 1, 3 and 4 channels are allowed - - switch (nChannels) { - - case 1: { - cmsToneCurve* Gray2Y = ExtractGray2Y(m ->ContextID, hProfile, Intent); - EmitCIEBasedA(m, Gray2Y, &BlackPointAdaptedToD50); - cmsFreeToneCurve(Gray2Y); - } - break; - - case 3: - case 4: { - cmsUInt32Number OutFrm = TYPE_Lab_16; - cmsPipeline* DeviceLink; - _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform; - - DeviceLink = cmsPipelineDup(v ->Lut); - if (DeviceLink == NULL) return 0; - - dwFlags |= cmsFLAGS_FORCE_CLUT; - _cmsOptimizePipeline(m->ContextID, &DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags); - - rc = EmitCIEBasedDEF(m, DeviceLink, Intent, &BlackPointAdaptedToD50); - cmsPipelineFree(DeviceLink); - if (rc == 0) return 0; - } - break; - - default: - - cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Only 3, 4 channels supported for CSA. This profile has %d channels.", nChannels); - return 0; - } - - - cmsDeleteTransform(xform); - - return 1; -} - -static -cmsFloat64Number* GetPtrToMatrix(const cmsStage* mpe) -{ - _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data; - - return Data -> Double; -} - - -// Does create CSA based on matrix-shaper. Allowed types are gray and RGB based - -static -int WriteInputMatrixShaper(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsStage* Matrix, cmsStage* Shaper) -{ - cmsColorSpaceSignature ColorSpace; - int rc; - cmsCIEXYZ BlackPointAdaptedToD50; - - ColorSpace = cmsGetColorSpace(hProfile); - - cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0); - - if (ColorSpace == cmsSigGrayData) { - - cmsToneCurve** ShaperCurve = _cmsStageGetPtrToCurveSet(Shaper); - rc = EmitCIEBasedA(m, ShaperCurve[0], &BlackPointAdaptedToD50); - - } - else - if (ColorSpace == cmsSigRgbData) { - - cmsMAT3 Mat; - int i, j; - - memmove(&Mat, GetPtrToMatrix(Matrix), sizeof(Mat)); - - for (i=0; i < 3; i++) - for (j=0; j < 3; j++) - Mat.v[i].n[j] *= MAX_ENCODEABLE_XYZ; - - rc = EmitCIEBasedABC(m, (cmsFloat64Number *) &Mat, - _cmsStageGetPtrToCurveSet(Shaper), - &BlackPointAdaptedToD50); - } - else { - - cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Profile is not suitable for CSA. Unsupported colorspace."); - return 0; - } - - return rc; -} - - - -// Creates a PostScript color list from a named profile data. -// This is a HP extension, and it works in Lab instead of XYZ - -static -int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent) -{ - cmsHTRANSFORM xform; - cmsHPROFILE hLab; - int i, nColors; - char ColorName[32]; - cmsNAMEDCOLORLIST* NamedColorList; - - hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL); - xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, hLab, TYPE_Lab_DBL, Intent, 0); - if (xform == NULL) return 0; - - NamedColorList = cmsGetNamedColorList(xform); - if (NamedColorList == NULL) return 0; - - _cmsIOPrintf(m, "<<\n"); - _cmsIOPrintf(m, "(colorlistcomment) (%s)\n", "Named color CSA"); - _cmsIOPrintf(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n"); - _cmsIOPrintf(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n"); - - nColors = cmsNamedColorCount(NamedColorList); - - - for (i=0; i < nColors; i++) { - - cmsUInt16Number In[1]; - cmsCIELab Lab; - - In[0] = (cmsUInt16Number) i; - - if (!cmsNamedColorInfo(NamedColorList, i, ColorName, NULL, NULL, NULL, NULL)) - continue; - - cmsDoTransform(xform, In, &Lab, 1); - _cmsIOPrintf(m, " (%s) [ %.3f %.3f %.3f ]\n", ColorName, Lab.L, Lab.a, Lab.b); - } - - - - _cmsIOPrintf(m, ">>\n"); - - cmsDeleteTransform(xform); - cmsCloseProfile(hLab); - return 1; -} - - -// Does create a Color Space Array on XYZ colorspace for PostScript usage -static -cmsUInt32Number GenerateCSA(cmsContext ContextID, - cmsHPROFILE hProfile, - cmsUInt32Number Intent, - cmsUInt32Number dwFlags, - cmsIOHANDLER* mem) -{ - cmsUInt32Number dwBytesUsed; - cmsPipeline* lut = NULL; - cmsStage* Matrix, *Shaper; - - - // Is a named color profile? - if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) { - - if (!WriteNamedColorCSA(mem, hProfile, Intent)) goto Error; - } - else { - - - // Any profile class are allowed (including devicelink), but - // output (PCS) colorspace must be XYZ or Lab - cmsColorSpaceSignature ColorSpace = cmsGetPCS(hProfile); - - if (ColorSpace != cmsSigXYZData && - ColorSpace != cmsSigLabData) { - - cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Invalid output color space"); - goto Error; - } - - - // Read the lut with all necessary conversion stages - lut = _cmsReadInputLUT(hProfile, Intent); - if (lut == NULL) goto Error; - - - // Tone curves + matrix can be implemented without any LUT - if (cmsPipelineCheckAndRetreiveStages(lut, 2, cmsSigCurveSetElemType, cmsSigMatrixElemType, &Shaper, &Matrix)) { - - if (!WriteInputMatrixShaper(mem, hProfile, Matrix, Shaper)) goto Error; - - } - else { - // We need a LUT for the rest - if (!WriteInputLUT(mem, hProfile, Intent, dwFlags)) goto Error; - } - } - - - // Done, keep memory usage - dwBytesUsed = mem ->UsedSpace; - - // Get rid of LUT - if (lut != NULL) cmsPipelineFree(lut); - - // Finally, return used byte count - return dwBytesUsed; - -Error: - if (lut != NULL) cmsPipelineFree(lut); - return 0; -} - -// ------------------------------------------------------ Color Rendering Dictionary (CRD) - - - -/* - - Black point compensation plus chromatic adaptation: - - Step 1 - Chromatic adaptation - ============================= - - WPout - X = ------- PQR - Wpin - - Step 2 - Black point compensation - ================================= - - (WPout - BPout)*X - WPout*(BPin - BPout) - out = --------------------------------------- - WPout - BPin - - - Algorithm discussion - ==================== - - TransformPQR(WPin, BPin, WPout, BPout, PQR) - - Wpin,etc= { Xws Yws Zws Pws Qws Rws } - - - Algorithm Stack 0...n - =========================================================== - PQR BPout WPout BPin WPin - 4 index 3 get WPin PQR BPout WPout BPin WPin - div (PQR/WPin) BPout WPout BPin WPin - 2 index 3 get WPout (PQR/WPin) BPout WPout BPin WPin - mult WPout*(PQR/WPin) BPout WPout BPin WPin - - 2 index 3 get WPout WPout*(PQR/WPin) BPout WPout BPin WPin - 2 index 3 get BPout WPout WPout*(PQR/WPin) BPout WPout BPin WPin - sub (WPout-BPout) WPout*(PQR/WPin) BPout WPout BPin WPin - mult (WPout-BPout)* WPout*(PQR/WPin) BPout WPout BPin WPin - - 2 index 3 get WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin - 4 index 3 get BPin WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin - 3 index 3 get BPout BPin WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin - - sub (BPin-BPout) WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin - mult (BPin-BPout)*WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin - sub (BPout-WPout)* WPout*(PQR/WPin)-(BPin-BPout)*WPout BPout WPout BPin WPin - - 3 index 3 get BPin (BPout-WPout)* WPout*(PQR/WPin)-(BPin-BPout)*WPout BPout WPout BPin WPin - 3 index 3 get WPout BPin (BPout-WPout)* WPout*(PQR/WPin)-(BPin-BPout)*WPout BPout WPout BPin WPin - exch - sub (WPout-BPin) (BPout-WPout)* WPout*(PQR/WPin)-(BPin-BPout)*WPout BPout WPout BPin WPin - div - - exch pop - exch pop - exch pop - exch pop - -*/ - - -static -void EmitPQRStage(cmsIOHANDLER* m, cmsHPROFILE hProfile, int DoBPC, int lIsAbsolute) -{ - - - if (lIsAbsolute) { - - // For absolute colorimetric intent, encode back to relative - // and generate a relative Pipeline - - // Relative encoding is obtained across XYZpcs*(D50/WhitePoint) - - cmsCIEXYZ White; - - _cmsReadMediaWhitePoint(&White, hProfile); - - _cmsIOPrintf(m,"/MatrixPQR [1 0 0 0 1 0 0 0 1 ]\n"); - _cmsIOPrintf(m,"/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ]\n"); - - _cmsIOPrintf(m, "%% Absolute colorimetric -- encode to relative to maximize LUT usage\n" - "/TransformPQR [\n" - "{0.9642 mul %g div exch pop exch pop exch pop exch pop} bind\n" - "{1.0000 mul %g div exch pop exch pop exch pop exch pop} bind\n" - "{0.8249 mul %g div exch pop exch pop exch pop exch pop} bind\n]\n", - White.X, White.Y, White.Z); - return; - } - - - _cmsIOPrintf(m,"%% Bradford Cone Space\n" - "/MatrixPQR [0.8951 -0.7502 0.0389 0.2664 1.7135 -0.0685 -0.1614 0.0367 1.0296 ] \n"); - - _cmsIOPrintf(m, "/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ]\n"); - - - // No BPC - - if (!DoBPC) { - - _cmsIOPrintf(m, "%% VonKries-like transform in Bradford Cone Space\n" - "/TransformPQR [\n" - "{exch pop exch 3 get mul exch pop exch 3 get div} bind\n" - "{exch pop exch 4 get mul exch pop exch 4 get div} bind\n" - "{exch pop exch 5 get mul exch pop exch 5 get div} bind\n]\n"); - } else { - - // BPC - - _cmsIOPrintf(m, "%% VonKries-like transform in Bradford Cone Space plus BPC\n" - "/TransformPQR [\n"); - - _cmsIOPrintf(m, "{4 index 3 get div 2 index 3 get mul " - "2 index 3 get 2 index 3 get sub mul " - "2 index 3 get 4 index 3 get 3 index 3 get sub mul sub " - "3 index 3 get 3 index 3 get exch sub div " - "exch pop exch pop exch pop exch pop } bind\n"); - - _cmsIOPrintf(m, "{4 index 4 get div 2 index 4 get mul " - "2 index 4 get 2 index 4 get sub mul " - "2 index 4 get 4 index 4 get 3 index 4 get sub mul sub " - "3 index 4 get 3 index 4 get exch sub div " - "exch pop exch pop exch pop exch pop } bind\n"); - - _cmsIOPrintf(m, "{4 index 5 get div 2 index 5 get mul " - "2 index 5 get 2 index 5 get sub mul " - "2 index 5 get 4 index 5 get 3 index 5 get sub mul sub " - "3 index 5 get 3 index 5 get exch sub div " - "exch pop exch pop exch pop exch pop } bind\n]\n"); - - } - - -} - - -static -void EmitXYZ2Lab(cmsIOHANDLER* m) -{ - _cmsIOPrintf(m, "/RangeLMN [ -0.635 2.0 0 2 -0.635 2.0 ]\n"); - _cmsIOPrintf(m, "/EncodeLMN [\n"); - _cmsIOPrintf(m, "{ 0.964200 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n"); - _cmsIOPrintf(m, "{ 1.000000 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n"); - _cmsIOPrintf(m, "{ 0.824900 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n"); - _cmsIOPrintf(m, "]\n"); - _cmsIOPrintf(m, "/MatrixABC [ 0 1 0 1 -1 1 0 0 -1 ]\n"); - _cmsIOPrintf(m, "/EncodeABC [\n"); - - - _cmsIOPrintf(m, "{ 116 mul 16 sub 100 div } bind\n"); - _cmsIOPrintf(m, "{ 500 mul 128 add 256 div } bind\n"); - _cmsIOPrintf(m, "{ 200 mul 128 add 256 div } bind\n"); - - - _cmsIOPrintf(m, "]\n"); - - -} - -// Due to impedance mismatch between XYZ and almost all RGB and CMYK spaces -// I choose to dump LUTS in Lab instead of XYZ. There is still a lot of wasted -// space on 3D CLUT, but since space seems not to be a problem here, 33 points -// would give a reasonable accurancy. Note also that CRD tables must operate in -// 8 bits. - -static -int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Number dwFlags) -{ - cmsHPROFILE hLab; - cmsHTRANSFORM xform; - int i, nChannels; - cmsUInt32Number OutputFormat; - _cmsTRANSFORM* v; - cmsPipeline* DeviceLink; - cmsHPROFILE Profiles[3]; - cmsCIEXYZ BlackPointAdaptedToD50; - cmsBool lDoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION); - cmsBool lFixWhite = !(dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP); - cmsUInt32Number InFrm = TYPE_Lab_16; - int RelativeEncodingIntent; - cmsColorSpaceSignature ColorSpace; - - - hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL); - if (hLab == NULL) return 0; - - OutputFormat = cmsFormatterForColorspaceOfProfile(hProfile, 2, FALSE); - nChannels = T_CHANNELS(OutputFormat); - - ColorSpace = cmsGetColorSpace(hProfile); - - // For absolute colorimetric, the LUT is encoded as relative in order to preserve precision. - - RelativeEncodingIntent = Intent; - if (RelativeEncodingIntent == INTENT_ABSOLUTE_COLORIMETRIC) - RelativeEncodingIntent = INTENT_RELATIVE_COLORIMETRIC; - - - // Use V4 Lab always - Profiles[0] = hLab; - Profiles[1] = hProfile; - - xform = cmsCreateMultiprofileTransformTHR(m ->ContextID, - Profiles, 2, TYPE_Lab_DBL, - OutputFormat, RelativeEncodingIntent, 0); - cmsCloseProfile(hLab); - - if (xform == NULL) { - - cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Lab -> Profile in CRD creation"); - return 0; - } - - // Get a copy of the internal devicelink - v = (_cmsTRANSFORM*) xform; - DeviceLink = cmsPipelineDup(v ->Lut); - if (DeviceLink == NULL) return 0; - - - // We need a CLUT - dwFlags |= cmsFLAGS_FORCE_CLUT; - _cmsOptimizePipeline(m->ContextID, &DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags); - - _cmsIOPrintf(m, "<<\n"); - _cmsIOPrintf(m, "/ColorRenderingType 1\n"); - - - cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, 0); - - // Emit headers, etc. - EmitWhiteBlackD50(m, &BlackPointAdaptedToD50); - EmitPQRStage(m, hProfile, lDoBPC, Intent == INTENT_ABSOLUTE_COLORIMETRIC); - EmitXYZ2Lab(m); - - - // FIXUP: map Lab (100, 0, 0) to perfect white, because the particular encoding for Lab - // does map a=b=0 not falling into any specific node. Since range a,b goes -128..127, - // zero is slightly moved towards right, so assure next node (in L=100 slice) is mapped to - // zero. This would sacrifice a bit of highlights, but failure to do so would cause - // scum dot. Ouch. - - if (Intent == INTENT_ABSOLUTE_COLORIMETRIC) - lFixWhite = FALSE; - - _cmsIOPrintf(m, "/RenderTable "); - - - WriteCLUT(m, cmsPipelineGetPtrToFirstStage(DeviceLink), "<", ">\n", "", "", lFixWhite, ColorSpace); - - _cmsIOPrintf(m, " %d {} bind ", nChannels); - - for (i=1; i < nChannels; i++) - _cmsIOPrintf(m, "dup "); - - _cmsIOPrintf(m, "]\n"); - - - EmitIntent(m, Intent); - - _cmsIOPrintf(m, ">>\n"); - - if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) { - - _cmsIOPrintf(m, "/Current exch /ColorRendering defineresource pop\n"); - } - - cmsPipelineFree(DeviceLink); - cmsDeleteTransform(xform); - - return 1; -} - - -// Builds a ASCII string containing colorant list in 0..1.0 range -static -void BuildColorantList(char *Colorant, int nColorant, cmsUInt16Number Out[]) -{ - char Buff[32]; - int j; - - Colorant[0] = 0; - if (nColorant > cmsMAXCHANNELS) - nColorant = cmsMAXCHANNELS; - - for (j=0; j < nColorant; j++) { - - sprintf(Buff, "%.3f", Out[j] / 65535.0); - strcat(Colorant, Buff); - if (j < nColorant -1) - strcat(Colorant, " "); - - } -} - - -// Creates a PostScript color list from a named profile data. -// This is a HP extension. - -static -int WriteNamedColorCRD(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent, cmsUInt32Number dwFlags) -{ - cmsHTRANSFORM xform; - int i, nColors, nColorant; - cmsUInt32Number OutputFormat; - char ColorName[32]; - char Colorant[128]; - cmsNAMEDCOLORLIST* NamedColorList; - - - OutputFormat = cmsFormatterForColorspaceOfProfile(hNamedColor, 2, FALSE); - nColorant = T_CHANNELS(OutputFormat); - - - xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, NULL, OutputFormat, Intent, dwFlags); - if (xform == NULL) return 0; - - - NamedColorList = cmsGetNamedColorList(xform); - if (NamedColorList == NULL) return 0; - - _cmsIOPrintf(m, "<<\n"); - _cmsIOPrintf(m, "(colorlistcomment) (%s) \n", "Named profile"); - _cmsIOPrintf(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n"); - _cmsIOPrintf(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n"); - - nColors = cmsNamedColorCount(NamedColorList); - - for (i=0; i < nColors; i++) { - - cmsUInt16Number In[1]; - cmsUInt16Number Out[cmsMAXCHANNELS]; - - In[0] = (cmsUInt16Number) i; - - if (!cmsNamedColorInfo(NamedColorList, i, ColorName, NULL, NULL, NULL, NULL)) - continue; - - cmsDoTransform(xform, In, Out, 1); - BuildColorantList(Colorant, nColorant, Out); - _cmsIOPrintf(m, " (%s) [ %s ]\n", ColorName, Colorant); - } - - _cmsIOPrintf(m, " >>"); - - if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) { - - _cmsIOPrintf(m, " /Current exch /HPSpotTable defineresource pop\n"); - } - - cmsDeleteTransform(xform); - return 1; -} - - - -// This one does create a Color Rendering Dictionary. -// CRD are always LUT-Based, no matter if profile is -// implemented as matrix-shaper. - -static -cmsUInt32Number GenerateCRD(cmsContext ContextID, - cmsHPROFILE hProfile, - cmsUInt32Number Intent, cmsUInt32Number dwFlags, - cmsIOHANDLER* mem) -{ - cmsUInt32Number dwBytesUsed; - - if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) { - - EmitHeader(mem, "Color Rendering Dictionary (CRD)", hProfile); - } - - - // Is a named color profile? - if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) { - - if (!WriteNamedColorCRD(mem, hProfile, Intent, dwFlags)) { - return 0; - } - } - else { - - // CRD are always implemented as LUT - - if (!WriteOutputLUT(mem, hProfile, Intent, dwFlags)) { - return 0; - } - } - - if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) { - - _cmsIOPrintf(mem, "%%%%EndResource\n"); - _cmsIOPrintf(mem, "\n%% CRD End\n"); - } - - // Done, keep memory usage - dwBytesUsed = mem ->UsedSpace; - - // Finally, return used byte count - return dwBytesUsed; - - cmsUNUSED_PARAMETER(ContextID); -} - - - - -cmsUInt32Number CMSEXPORT cmsGetPostScriptColorResource(cmsContext ContextID, - cmsPSResourceType Type, - cmsHPROFILE hProfile, - cmsUInt32Number Intent, - cmsUInt32Number dwFlags, - cmsIOHANDLER* io) -{ - cmsUInt32Number rc; - - - switch (Type) { - - case cmsPS_RESOURCE_CSA: - rc = GenerateCSA(ContextID, hProfile, Intent, dwFlags, io); - break; - - default: - case cmsPS_RESOURCE_CRD: - rc = GenerateCRD(ContextID, hProfile, Intent, dwFlags, io); - break; - } - - return rc; -} - - - -cmsUInt32Number CMSEXPORT cmsGetPostScriptCRD(cmsContext ContextID, - cmsHPROFILE hProfile, - cmsUInt32Number Intent, cmsUInt32Number dwFlags, - void* Buffer, cmsUInt32Number dwBufferLen) -{ - cmsIOHANDLER* mem; - cmsUInt32Number dwBytesUsed; - - // Set up the serialization engine - if (Buffer == NULL) - mem = cmsOpenIOhandlerFromNULL(ContextID); - else - mem = cmsOpenIOhandlerFromMem(ContextID, Buffer, dwBufferLen, "w"); - - if (!mem) return 0; - - dwBytesUsed = cmsGetPostScriptColorResource(ContextID, cmsPS_RESOURCE_CRD, hProfile, Intent, dwFlags, mem); - - // Get rid of memory stream - cmsCloseIOhandler(mem); - - return dwBytesUsed; -} - - - -// Does create a Color Space Array on XYZ colorspace for PostScript usage -cmsUInt32Number CMSEXPORT cmsGetPostScriptCSA(cmsContext ContextID, - cmsHPROFILE hProfile, - cmsUInt32Number Intent, - cmsUInt32Number dwFlags, - void* Buffer, - cmsUInt32Number dwBufferLen) -{ - cmsIOHANDLER* mem; - cmsUInt32Number dwBytesUsed; - - if (Buffer == NULL) - mem = cmsOpenIOhandlerFromNULL(ContextID); - else - mem = cmsOpenIOhandlerFromMem(ContextID, Buffer, dwBufferLen, "w"); - - if (!mem) return 0; - - dwBytesUsed = cmsGetPostScriptColorResource(ContextID, cmsPS_RESOURCE_CSA, hProfile, Intent, dwFlags, mem); - - // Get rid of memory stream - cmsCloseIOhandler(mem); - - return dwBytesUsed; - -} diff --git a/third_party/lcms2-2.6/src/cmssamp.c b/third_party/lcms2-2.6/src/cmssamp.c deleted file mode 100644 index 70e469161f..0000000000 --- a/third_party/lcms2-2.6/src/cmssamp.c +++ /dev/null @@ -1,572 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- -// - -#include "lcms2_internal.h" - - -#define cmsmin(a, b) (((a) < (b)) ? (a) : (b)) -#define cmsmax(a, b) (((a) > (b)) ? (a) : (b)) - -// This file contains routines for resampling and LUT optimization, black point detection -// and black preservation. - -// Black point detection ------------------------------------------------------------------------- - - -// PCS -> PCS round trip transform, always uses relative intent on the device -> pcs -static -cmsHTRANSFORM CreateRoundtripXForm(cmsHPROFILE hProfile, cmsUInt32Number nIntent) -{ - cmsContext ContextID = cmsGetProfileContextID(hProfile); - cmsHPROFILE hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); - cmsHTRANSFORM xform; - cmsBool BPC[4] = { FALSE, FALSE, FALSE, FALSE }; - cmsFloat64Number States[4] = { 1.0, 1.0, 1.0, 1.0 }; - cmsHPROFILE hProfiles[4]; - cmsUInt32Number Intents[4]; - - hProfiles[0] = hLab; hProfiles[1] = hProfile; hProfiles[2] = hProfile; hProfiles[3] = hLab; - Intents[0] = INTENT_RELATIVE_COLORIMETRIC; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = INTENT_RELATIVE_COLORIMETRIC; - - xform = cmsCreateExtendedTransform(ContextID, 4, hProfiles, BPC, Intents, - States, NULL, 0, TYPE_Lab_DBL, TYPE_Lab_DBL, cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE); - - cmsCloseProfile(hLab); - return xform; -} - -// Use darker colorants to obtain black point. This works in the relative colorimetric intent and -// assumes more ink results in darker colors. No ink limit is assumed. -static -cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput, - cmsUInt32Number Intent, - cmsCIEXYZ* BlackPoint, - cmsUInt32Number dwFlags) -{ - cmsUInt16Number *Black; - cmsHTRANSFORM xform; - cmsColorSpaceSignature Space; - cmsUInt32Number nChannels; - cmsUInt32Number dwFormat; - cmsHPROFILE hLab; - cmsCIELab Lab; - cmsCIEXYZ BlackXYZ; - cmsContext ContextID = cmsGetProfileContextID(hInput); - - // If the profile does not support input direction, assume Black point 0 - if (!cmsIsIntentSupported(hInput, Intent, LCMS_USED_AS_INPUT)) { - - BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; - return FALSE; - } - - // Create a formatter which has n channels and floating point - dwFormat = cmsFormatterForColorspaceOfProfile(hInput, 2, FALSE); - - // Try to get black by using black colorant - Space = cmsGetColorSpace(hInput); - - // This function returns darker colorant in 16 bits for several spaces - if (!_cmsEndPointsBySpace(Space, NULL, &Black, &nChannels)) { - - BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; - return FALSE; - } - - if (nChannels != T_CHANNELS(dwFormat)) { - BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; - return FALSE; - } - - // Lab will be used as the output space, but lab2 will avoid recursion - hLab = cmsCreateLab2ProfileTHR(ContextID, NULL); - if (hLab == NULL) { - BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; - return FALSE; - } - - // Create the transform - xform = cmsCreateTransformTHR(ContextID, hInput, dwFormat, - hLab, TYPE_Lab_DBL, Intent, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE); - cmsCloseProfile(hLab); - - if (xform == NULL) { - - // Something went wrong. Get rid of open resources and return zero as black - BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; - return FALSE; - } - - // Convert black to Lab - cmsDoTransform(xform, Black, &Lab, 1); - - // Force it to be neutral, clip to max. L* of 50 - Lab.a = Lab.b = 0; - if (Lab.L > 50) Lab.L = 50; - - // Free the resources - cmsDeleteTransform(xform); - - // Convert from Lab (which is now clipped) to XYZ. - cmsLab2XYZ(NULL, &BlackXYZ, &Lab); - - if (BlackPoint != NULL) - *BlackPoint = BlackXYZ; - - return TRUE; - - cmsUNUSED_PARAMETER(dwFlags); -} - -// Get a black point of output CMYK profile, discounting any ink-limiting embedded -// in the profile. For doing that, we use perceptual intent in input direction: -// Lab (0, 0, 0) -> [Perceptual] Profile -> CMYK -> [Rel. colorimetric] Profile -> Lab -static -cmsBool BlackPointUsingPerceptualBlack(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile) -{ - cmsHTRANSFORM hRoundTrip; - cmsCIELab LabIn, LabOut; - cmsCIEXYZ BlackXYZ; - - // Is the intent supported by the profile? - if (!cmsIsIntentSupported(hProfile, INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT)) { - - BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; - return TRUE; - } - - hRoundTrip = CreateRoundtripXForm(hProfile, INTENT_PERCEPTUAL); - if (hRoundTrip == NULL) { - BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; - return FALSE; - } - - LabIn.L = LabIn.a = LabIn.b = 0; - cmsDoTransform(hRoundTrip, &LabIn, &LabOut, 1); - - // Clip Lab to reasonable limits - if (LabOut.L > 50) LabOut.L = 50; - LabOut.a = LabOut.b = 0; - - cmsDeleteTransform(hRoundTrip); - - // Convert it to XYZ - cmsLab2XYZ(NULL, &BlackXYZ, &LabOut); - - if (BlackPoint != NULL) - *BlackPoint = BlackXYZ; - - return TRUE; -} - -// This function shouldn't exist at all -- there is such quantity of broken -// profiles on black point tag, that we must somehow fix chromaticity to -// avoid huge tint when doing Black point compensation. This function does -// just that. There is a special flag for using black point tag, but turned -// off by default because it is bogus on most profiles. The detection algorithm -// involves to turn BP to neutral and to use only L component. -cmsBool CMSEXPORT cmsDetectBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags) -{ - cmsProfileClassSignature devClass; - - // Make sure the device class is adequate - devClass = cmsGetDeviceClass(hProfile); - if (devClass == cmsSigLinkClass || - devClass == cmsSigAbstractClass || - devClass == cmsSigNamedColorClass) { - BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; - return FALSE; - } - - // Make sure intent is adequate - if (Intent != INTENT_PERCEPTUAL && - Intent != INTENT_RELATIVE_COLORIMETRIC && - Intent != INTENT_SATURATION) { - BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; - return FALSE; - } - - // v4 + perceptual & saturation intents does have its own black point, and it is - // well specified enough to use it. Black point tag is deprecated in V4. - if ((cmsGetEncodedICCversion(hProfile) >= 0x4000000) && - (Intent == INTENT_PERCEPTUAL || Intent == INTENT_SATURATION)) { - - // Matrix shaper share MRC & perceptual intents - if (cmsIsMatrixShaper(hProfile)) - return BlackPointAsDarkerColorant(hProfile, INTENT_RELATIVE_COLORIMETRIC, BlackPoint, 0); - - // Get Perceptual black out of v4 profiles. That is fixed for perceptual & saturation intents - BlackPoint -> X = cmsPERCEPTUAL_BLACK_X; - BlackPoint -> Y = cmsPERCEPTUAL_BLACK_Y; - BlackPoint -> Z = cmsPERCEPTUAL_BLACK_Z; - - return TRUE; - } - - -#ifdef CMS_USE_PROFILE_BLACK_POINT_TAG - - // v2, v4 rel/abs colorimetric - if (cmsIsTag(hProfile, cmsSigMediaBlackPointTag) && - Intent == INTENT_RELATIVE_COLORIMETRIC) { - - cmsCIEXYZ *BlackPtr, BlackXYZ, UntrustedBlackPoint, TrustedBlackPoint, MediaWhite; - cmsCIELab Lab; - - // If black point is specified, then use it, - - BlackPtr = cmsReadTag(hProfile, cmsSigMediaBlackPointTag); - if (BlackPtr != NULL) { - - BlackXYZ = *BlackPtr; - _cmsReadMediaWhitePoint(&MediaWhite, hProfile); - - // Black point is absolute XYZ, so adapt to D50 to get PCS value - cmsAdaptToIlluminant(&UntrustedBlackPoint, &MediaWhite, cmsD50_XYZ(), &BlackXYZ); - - // Force a=b=0 to get rid of any chroma - cmsXYZ2Lab(NULL, &Lab, &UntrustedBlackPoint); - Lab.a = Lab.b = 0; - if (Lab.L > 50) Lab.L = 50; // Clip to L* <= 50 - cmsLab2XYZ(NULL, &TrustedBlackPoint, &Lab); - - if (BlackPoint != NULL) - *BlackPoint = TrustedBlackPoint; - - return TRUE; - } - } -#endif - - // That is about v2 profiles. - - // If output profile, discount ink-limiting and that's all - if (Intent == INTENT_RELATIVE_COLORIMETRIC && - (cmsGetDeviceClass(hProfile) == cmsSigOutputClass) && - (cmsGetColorSpace(hProfile) == cmsSigCmykData)) - return BlackPointUsingPerceptualBlack(BlackPoint, hProfile); - - // Nope, compute BP using current intent. - return BlackPointAsDarkerColorant(hProfile, Intent, BlackPoint, dwFlags); -} - - - -// --------------------------------------------------------------------------------------------------------- - -// Least Squares Fit of a Quadratic Curve to Data -// http://www.personal.psu.edu/jhm/f90/lectures/lsq2.html - -static -cmsFloat64Number RootOfLeastSquaresFitQuadraticCurve(int n, cmsFloat64Number x[], cmsFloat64Number y[]) -{ - double sum_x = 0, sum_x2 = 0, sum_x3 = 0, sum_x4 = 0; - double sum_y = 0, sum_yx = 0, sum_yx2 = 0; - double d, a, b, c; - int i; - cmsMAT3 m; - cmsVEC3 v, res; - - if (n < 4) return 0; - - for (i=0; i < n; i++) { - - double xn = x[i]; - double yn = y[i]; - - sum_x += xn; - sum_x2 += xn*xn; - sum_x3 += xn*xn*xn; - sum_x4 += xn*xn*xn*xn; - - sum_y += yn; - sum_yx += yn*xn; - sum_yx2 += yn*xn*xn; - } - - _cmsVEC3init(&m.v[0], n, sum_x, sum_x2); - _cmsVEC3init(&m.v[1], sum_x, sum_x2, sum_x3); - _cmsVEC3init(&m.v[2], sum_x2, sum_x3, sum_x4); - - _cmsVEC3init(&v, sum_y, sum_yx, sum_yx2); - - if (!_cmsMAT3solve(&res, &m, &v)) return 0; - - - a = res.n[2]; - b = res.n[1]; - c = res.n[0]; - - if (fabs(a) < 1.0E-10) { - - return cmsmin(0, cmsmax(50, -c/b )); - } - else { - - d = b*b - 4.0 * a * c; - if (d <= 0) { - return 0; - } - else { - - double rt = (-b + sqrt(d)) / (2.0 * a); - - return cmsmax(0, cmsmin(50, rt)); - } - } - -} - -/* -static -cmsBool IsMonotonic(int n, const cmsFloat64Number Table[]) -{ - int i; - cmsFloat64Number last; - - last = Table[n-1]; - - for (i = n-2; i >= 0; --i) { - - if (Table[i] > last) - - return FALSE; - else - last = Table[i]; - - } - - return TRUE; -} -*/ - -// Calculates the black point of a destination profile. -// This algorithm comes from the Adobe paper disclosing its black point compensation method. -cmsBool CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags) -{ - cmsColorSpaceSignature ColorSpace; - cmsHTRANSFORM hRoundTrip = NULL; - cmsCIELab InitialLab, destLab, Lab; - cmsFloat64Number inRamp[256], outRamp[256]; - cmsFloat64Number MinL, MaxL; - cmsBool NearlyStraightMidrange = TRUE; - cmsFloat64Number yRamp[256]; - cmsFloat64Number x[256], y[256]; - cmsFloat64Number lo, hi; - int n, l; - cmsProfileClassSignature devClass; - - // Make sure the device class is adequate - devClass = cmsGetDeviceClass(hProfile); - if (devClass == cmsSigLinkClass || - devClass == cmsSigAbstractClass || - devClass == cmsSigNamedColorClass) { - BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; - return FALSE; - } - - // Make sure intent is adequate - if (Intent != INTENT_PERCEPTUAL && - Intent != INTENT_RELATIVE_COLORIMETRIC && - Intent != INTENT_SATURATION) { - BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; - return FALSE; - } - - - // v4 + perceptual & saturation intents does have its own black point, and it is - // well specified enough to use it. Black point tag is deprecated in V4. - if ((cmsGetEncodedICCversion(hProfile) >= 0x4000000) && - (Intent == INTENT_PERCEPTUAL || Intent == INTENT_SATURATION)) { - - // Matrix shaper share MRC & perceptual intents - if (cmsIsMatrixShaper(hProfile)) - return BlackPointAsDarkerColorant(hProfile, INTENT_RELATIVE_COLORIMETRIC, BlackPoint, 0); - - // Get Perceptual black out of v4 profiles. That is fixed for perceptual & saturation intents - BlackPoint -> X = cmsPERCEPTUAL_BLACK_X; - BlackPoint -> Y = cmsPERCEPTUAL_BLACK_Y; - BlackPoint -> Z = cmsPERCEPTUAL_BLACK_Z; - return TRUE; - } - - - // Check if the profile is lut based and gray, rgb or cmyk (7.2 in Adobe's document) - ColorSpace = cmsGetColorSpace(hProfile); - if (!cmsIsCLUT(hProfile, Intent, LCMS_USED_AS_OUTPUT ) || - (ColorSpace != cmsSigGrayData && - ColorSpace != cmsSigRgbData && - ColorSpace != cmsSigCmykData)) { - - // In this case, handle as input case - return cmsDetectBlackPoint(BlackPoint, hProfile, Intent, dwFlags); - } - - // It is one of the valid cases!, use Adobe algorithm - - - // Set a first guess, that should work on good profiles. - if (Intent == INTENT_RELATIVE_COLORIMETRIC) { - - cmsCIEXYZ IniXYZ; - - // calculate initial Lab as source black point - if (!cmsDetectBlackPoint(&IniXYZ, hProfile, Intent, dwFlags)) { - return FALSE; - } - - // convert the XYZ to lab - cmsXYZ2Lab(NULL, &InitialLab, &IniXYZ); - - } else { - - // set the initial Lab to zero, that should be the black point for perceptual and saturation - InitialLab.L = 0; - InitialLab.a = 0; - InitialLab.b = 0; - } - - - // Step 2 - // ====== - - // Create a roundtrip. Define a Transform BT for all x in L*a*b* - hRoundTrip = CreateRoundtripXForm(hProfile, Intent); - if (hRoundTrip == NULL) return FALSE; - - // Compute ramps - - for (l=0; l < 256; l++) { - - Lab.L = (cmsFloat64Number) (l * 100.0) / 255.0; - Lab.a = cmsmin(50, cmsmax(-50, InitialLab.a)); - Lab.b = cmsmin(50, cmsmax(-50, InitialLab.b)); - - cmsDoTransform(hRoundTrip, &Lab, &destLab, 1); - - inRamp[l] = Lab.L; - outRamp[l] = destLab.L; - } - - // Make monotonic - for (l = 254; l > 0; --l) { - outRamp[l] = cmsmin(outRamp[l], outRamp[l+1]); - } - - // Check - if (! (outRamp[0] < outRamp[255])) { - - cmsDeleteTransform(hRoundTrip); - BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; - return FALSE; - } - - - // Test for mid range straight (only on relative colorimetric) - - NearlyStraightMidrange = TRUE; - MinL = outRamp[0]; MaxL = outRamp[255]; - if (Intent == INTENT_RELATIVE_COLORIMETRIC) { - - for (l=0; l < 256; l++) { - - if (! ((inRamp[l] <= MinL + 0.2 * (MaxL - MinL) ) || - (fabs(inRamp[l] - outRamp[l]) < 4.0 ))) - NearlyStraightMidrange = FALSE; - } - - // If the mid range is straight (as determined above) then the - // DestinationBlackPoint shall be the same as initialLab. - // Otherwise, the DestinationBlackPoint shall be determined - // using curve fitting. - - if (NearlyStraightMidrange) { - - cmsLab2XYZ(NULL, BlackPoint, &InitialLab); - cmsDeleteTransform(hRoundTrip); - return TRUE; - } - } - - - // curve fitting: The round-trip curve normally looks like a nearly constant section at the black point, - // with a corner and a nearly straight line to the white point. - - for (l=0; l < 256; l++) { - - yRamp[l] = (outRamp[l] - MinL) / (MaxL - MinL); - } - - // find the black point using the least squares error quadratic curve fitting - - if (Intent == INTENT_RELATIVE_COLORIMETRIC) { - lo = 0.1; - hi = 0.5; - } - else { - - // Perceptual and saturation - lo = 0.03; - hi = 0.25; - } - - // Capture shadow points for the fitting. - n = 0; - for (l=0; l < 256; l++) { - - cmsFloat64Number ff = yRamp[l]; - - if (ff >= lo && ff < hi) { - x[n] = inRamp[l]; - y[n] = yRamp[l]; - n++; - } - } - - - // No suitable points - if (n < 3 ) { - cmsDeleteTransform(hRoundTrip); - BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; - return FALSE; - } - - - // fit and get the vertex of quadratic curve - Lab.L = RootOfLeastSquaresFitQuadraticCurve(n, x, y); - - if (Lab.L < 0.0) { // clip to zero L* if the vertex is negative - Lab.L = 0; - } - - Lab.a = InitialLab.a; - Lab.b = InitialLab.b; - - cmsLab2XYZ(NULL, BlackPoint, &Lab); - - cmsDeleteTransform(hRoundTrip); - return TRUE; -} diff --git a/third_party/lcms2-2.6/src/cmssm.c b/third_party/lcms2-2.6/src/cmssm.c deleted file mode 100644 index 5836e15506..0000000000 --- a/third_party/lcms2-2.6/src/cmssm.c +++ /dev/null @@ -1,734 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2011 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- -// - -#include "lcms2_internal.h" - - -// ------------------------------------------------------------------------ - -// Gamut boundary description by using Jan Morovic's Segment maxima method -// Many thanks to Jan for allowing me to use his algorithm. - -// r = C* -// alpha = Hab -// theta = L* - -#define SECTORS 16 // number of divisions in alpha and theta - -// Spherical coordinates -typedef struct { - - cmsFloat64Number r; - cmsFloat64Number alpha; - cmsFloat64Number theta; - -} cmsSpherical; - -typedef enum { - GP_EMPTY, - GP_SPECIFIED, - GP_MODELED - - } GDBPointType; - - -typedef struct { - - GDBPointType Type; - cmsSpherical p; // Keep also alpha & theta of maximum - -} cmsGDBPoint; - - -typedef struct { - - cmsContext ContextID; - cmsGDBPoint Gamut[SECTORS][SECTORS]; - -} cmsGDB; - - -// A line using the parametric form -// P = a + t*u -typedef struct { - - cmsVEC3 a; - cmsVEC3 u; - -} cmsLine; - - -// A plane using the parametric form -// Q = b + r*v + s*w -typedef struct { - - cmsVEC3 b; - cmsVEC3 v; - cmsVEC3 w; - -} cmsPlane; - - - -// -------------------------------------------------------------------------------------------- - -// ATAN2() which always returns degree positive numbers - -static -cmsFloat64Number _cmsAtan2(cmsFloat64Number y, cmsFloat64Number x) -{ - cmsFloat64Number a; - - // Deal with undefined case - if (x == 0.0 && y == 0.0) return 0; - - a = (atan2(y, x) * 180.0) / M_PI; - - while (a < 0) { - a += 360; - } - - return a; -} - -// Convert to spherical coordinates -static -void ToSpherical(cmsSpherical* sp, const cmsVEC3* v) -{ - - cmsFloat64Number L, a, b; - - L = v ->n[VX]; - a = v ->n[VY]; - b = v ->n[VZ]; - - sp ->r = sqrt( L*L + a*a + b*b ); - - if (sp ->r == 0) { - sp ->alpha = sp ->theta = 0; - return; - } - - sp ->alpha = _cmsAtan2(a, b); - sp ->theta = _cmsAtan2(sqrt(a*a + b*b), L); -} - - -// Convert to cartesian from spherical -static -void ToCartesian(cmsVEC3* v, const cmsSpherical* sp) -{ - cmsFloat64Number sin_alpha; - cmsFloat64Number cos_alpha; - cmsFloat64Number sin_theta; - cmsFloat64Number cos_theta; - cmsFloat64Number L, a, b; - - sin_alpha = sin((M_PI * sp ->alpha) / 180.0); - cos_alpha = cos((M_PI * sp ->alpha) / 180.0); - sin_theta = sin((M_PI * sp ->theta) / 180.0); - cos_theta = cos((M_PI * sp ->theta) / 180.0); - - a = sp ->r * sin_theta * sin_alpha; - b = sp ->r * sin_theta * cos_alpha; - L = sp ->r * cos_theta; - - v ->n[VX] = L; - v ->n[VY] = a; - v ->n[VZ] = b; -} - - -// Quantize sector of a spherical coordinate. Saturate 360, 180 to last sector -// The limits are the centers of each sector, so -static -void QuantizeToSector(const cmsSpherical* sp, int* alpha, int* theta) -{ - *alpha = (int) floor(((sp->alpha * (SECTORS)) / 360.0) ); - *theta = (int) floor(((sp->theta * (SECTORS)) / 180.0) ); - - if (*alpha >= SECTORS) - *alpha = SECTORS-1; - if (*theta >= SECTORS) - *theta = SECTORS-1; -} - - -// Line determined by 2 points -static -void LineOf2Points(cmsLine* line, cmsVEC3* a, cmsVEC3* b) -{ - - _cmsVEC3init(&line ->a, a ->n[VX], a ->n[VY], a ->n[VZ]); - _cmsVEC3init(&line ->u, b ->n[VX] - a ->n[VX], - b ->n[VY] - a ->n[VY], - b ->n[VZ] - a ->n[VZ]); -} - - -// Evaluate parametric line -static -void GetPointOfLine(cmsVEC3* p, const cmsLine* line, cmsFloat64Number t) -{ - p ->n[VX] = line ->a.n[VX] + t * line->u.n[VX]; - p ->n[VY] = line ->a.n[VY] + t * line->u.n[VY]; - p ->n[VZ] = line ->a.n[VZ] + t * line->u.n[VZ]; -} - - - -/* - Closest point in sector line1 to sector line2 (both are defined as 0 <=t <= 1) - http://softsurfer.com/Archive/algorithm_0106/algorithm_0106.htm - - Copyright 2001, softSurfer (www.softsurfer.com) - This code may be freely used and modified for any purpose - providing that this copyright notice is included with it. - SoftSurfer makes no warranty for this code, and cannot be held - liable for any real or imagined damage resulting from its use. - Users of this code must verify correctness for their application. - -*/ - -static -cmsBool ClosestLineToLine(cmsVEC3* r, const cmsLine* line1, const cmsLine* line2) -{ - cmsFloat64Number a, b, c, d, e, D; - cmsFloat64Number sc, sN, sD; - cmsFloat64Number tc, tN, tD; - cmsVEC3 w0; - - _cmsVEC3minus(&w0, &line1 ->a, &line2 ->a); - - a = _cmsVEC3dot(&line1 ->u, &line1 ->u); - b = _cmsVEC3dot(&line1 ->u, &line2 ->u); - c = _cmsVEC3dot(&line2 ->u, &line2 ->u); - d = _cmsVEC3dot(&line1 ->u, &w0); - e = _cmsVEC3dot(&line2 ->u, &w0); - - D = a*c - b * b; // Denominator - sD = tD = D; // default sD = D >= 0 - - if (D < MATRIX_DET_TOLERANCE) { // the lines are almost parallel - - sN = 0.0; // force using point P0 on segment S1 - sD = 1.0; // to prevent possible division by 0.0 later - tN = e; - tD = c; - } - else { // get the closest points on the infinite lines - - sN = (b*e - c*d); - tN = (a*e - b*d); - - if (sN < 0.0) { // sc < 0 => the s=0 edge is visible - - sN = 0.0; - tN = e; - tD = c; - } - else if (sN > sD) { // sc > 1 => the s=1 edge is visible - sN = sD; - tN = e + b; - tD = c; - } - } - - if (tN < 0.0) { // tc < 0 => the t=0 edge is visible - - tN = 0.0; - // recompute sc for this edge - if (-d < 0.0) - sN = 0.0; - else if (-d > a) - sN = sD; - else { - sN = -d; - sD = a; - } - } - else if (tN > tD) { // tc > 1 => the t=1 edge is visible - - tN = tD; - - // recompute sc for this edge - if ((-d + b) < 0.0) - sN = 0; - else if ((-d + b) > a) - sN = sD; - else { - sN = (-d + b); - sD = a; - } - } - // finally do the division to get sc and tc - sc = (fabs(sN) < MATRIX_DET_TOLERANCE ? 0.0 : sN / sD); - tc = (fabs(tN) < MATRIX_DET_TOLERANCE ? 0.0 : tN / tD); - - GetPointOfLine(r, line1, sc); - return TRUE; -} - - - -// ------------------------------------------------------------------ Wrapper - - -// Allocate & free structure -cmsHANDLE CMSEXPORT cmsGBDAlloc(cmsContext ContextID) -{ - cmsGDB* gbd = (cmsGDB*) _cmsMallocZero(ContextID, sizeof(cmsGDB)); - if (gbd == NULL) return NULL; - - gbd -> ContextID = ContextID; - - return (cmsHANDLE) gbd; -} - - -void CMSEXPORT cmsGBDFree(cmsHANDLE hGBD) -{ - cmsGDB* gbd = (cmsGDB*) hGBD; - if (hGBD != NULL) - _cmsFree(gbd->ContextID, (void*) gbd); -} - - -// Auxiliar to retrieve a pointer to the segmentr containing the Lab value -static -cmsGDBPoint* GetPoint(cmsGDB* gbd, const cmsCIELab* Lab, cmsSpherical* sp) -{ - cmsVEC3 v; - int alpha, theta; - - // Housekeeping - _cmsAssert(gbd != NULL); - _cmsAssert(Lab != NULL); - _cmsAssert(sp != NULL); - - // Center L* by substracting half of its domain, that's 50 - _cmsVEC3init(&v, Lab ->L - 50.0, Lab ->a, Lab ->b); - - // Convert to spherical coordinates - ToSpherical(sp, &v); - - if (sp ->r < 0 || sp ->alpha < 0 || sp->theta < 0) { - cmsSignalError(gbd ->ContextID, cmsERROR_RANGE, "spherical value out of range"); - return NULL; - } - - // On which sector it falls? - QuantizeToSector(sp, &alpha, &theta); - - if (alpha < 0 || theta < 0 || alpha >= SECTORS || theta >= SECTORS) { - cmsSignalError(gbd ->ContextID, cmsERROR_RANGE, " quadrant out of range"); - return NULL; - } - - // Get pointer to the sector - return &gbd ->Gamut[theta][alpha]; -} - -// Add a point to gamut descriptor. Point to add is in Lab color space. -// GBD is centered on a=b=0 and L*=50 -cmsBool CMSEXPORT cmsGDBAddPoint(cmsHANDLE hGBD, const cmsCIELab* Lab) -{ - cmsGDB* gbd = (cmsGDB*) hGBD; - cmsGDBPoint* ptr; - cmsSpherical sp; - - - // Get pointer to the sector - ptr = GetPoint(gbd, Lab, &sp); - if (ptr == NULL) return FALSE; - - // If no samples at this sector, add it - if (ptr ->Type == GP_EMPTY) { - - ptr -> Type = GP_SPECIFIED; - ptr -> p = sp; - } - else { - - - // Substitute only if radius is greater - if (sp.r > ptr -> p.r) { - - ptr -> Type = GP_SPECIFIED; - ptr -> p = sp; - } - } - - return TRUE; -} - -// Check if a given point falls inside gamut -cmsBool CMSEXPORT cmsGDBCheckPoint(cmsHANDLE hGBD, const cmsCIELab* Lab) -{ - cmsGDB* gbd = (cmsGDB*) hGBD; - cmsGDBPoint* ptr; - cmsSpherical sp; - - // Get pointer to the sector - ptr = GetPoint(gbd, Lab, &sp); - if (ptr == NULL) return FALSE; - - // If no samples at this sector, return no data - if (ptr ->Type == GP_EMPTY) return FALSE; - - // In gamut only if radius is greater - - return (sp.r <= ptr -> p.r); -} - -// ----------------------------------------------------------------------------------------------------------------------- - -// Find near sectors. The list of sectors found is returned on Close[]. -// The function returns the number of sectors as well. - -// 24 9 10 11 12 -// 23 8 1 2 13 -// 22 7 * 3 14 -// 21 6 5 4 15 -// 20 19 18 17 16 -// -// Those are the relative movements -// {-2,-2}, {-1, -2}, {0, -2}, {+1, -2}, {+2, -2}, -// {-2,-1}, {-1, -1}, {0, -1}, {+1, -1}, {+2, -1}, -// {-2, 0}, {-1, 0}, {0, 0}, {+1, 0}, {+2, 0}, -// {-2,+1}, {-1, +1}, {0, +1}, {+1, +1}, {+2, +1}, -// {-2,+2}, {-1, +2}, {0, +2}, {+1, +2}, {+2, +2}}; - - -static -const struct _spiral { - - int AdvX, AdvY; - - } Spiral[] = { {0, -1}, {+1, -1}, {+1, 0}, {+1, +1}, {0, +1}, {-1, +1}, - {-1, 0}, {-1, -1}, {-1, -2}, {0, -2}, {+1, -2}, {+2, -2}, - {+2, -1}, {+2, 0}, {+2, +1}, {+2, +2}, {+1, +2}, {0, +2}, - {-1, +2}, {-2, +2}, {-2, +1}, {-2, 0}, {-2, -1}, {-2, -2} }; - -#define NSTEPS (sizeof(Spiral) / sizeof(struct _spiral)) - -static -int FindNearSectors(cmsGDB* gbd, int alpha, int theta, cmsGDBPoint* Close[]) -{ - int nSectors = 0; - int a, t; - cmsUInt32Number i; - cmsGDBPoint* pt; - - for (i=0; i < NSTEPS; i++) { - - a = alpha + Spiral[i].AdvX; - t = theta + Spiral[i].AdvY; - - // Cycle at the end - a %= SECTORS; - t %= SECTORS; - - // Cycle at the begin - if (a < 0) a = SECTORS + a; - if (t < 0) t = SECTORS + t; - - pt = &gbd ->Gamut[t][a]; - - if (pt -> Type != GP_EMPTY) { - - Close[nSectors++] = pt; - } - } - - return nSectors; -} - - -// Interpolate a missing sector. Method identifies whatever this is top, bottom or mid -static -cmsBool InterpolateMissingSector(cmsGDB* gbd, int alpha, int theta) -{ - cmsSpherical sp; - cmsVEC3 Lab; - cmsVEC3 Centre; - cmsLine ray; - int nCloseSectors; - cmsGDBPoint* Close[NSTEPS + 1]; - cmsSpherical closel, templ; - cmsLine edge; - int k, m; - - // Is that point already specified? - if (gbd ->Gamut[theta][alpha].Type != GP_EMPTY) return TRUE; - - // Fill close points - nCloseSectors = FindNearSectors(gbd, alpha, theta, Close); - - - // Find a central point on the sector - sp.alpha = (cmsFloat64Number) ((alpha + 0.5) * 360.0) / (SECTORS); - sp.theta = (cmsFloat64Number) ((theta + 0.5) * 180.0) / (SECTORS); - sp.r = 50.0; - - // Convert to Cartesian - ToCartesian(&Lab, &sp); - - // Create a ray line from centre to this point - _cmsVEC3init(&Centre, 50.0, 0, 0); - LineOf2Points(&ray, &Lab, &Centre); - - // For all close sectors - closel.r = 0.0; - closel.alpha = 0; - closel.theta = 0; - - for (k=0; k < nCloseSectors; k++) { - - for(m = k+1; m < nCloseSectors; m++) { - - cmsVEC3 temp, a1, a2; - - // A line from sector to sector - ToCartesian(&a1, &Close[k]->p); - ToCartesian(&a2, &Close[m]->p); - - LineOf2Points(&edge, &a1, &a2); - - // Find a line - ClosestLineToLine(&temp, &ray, &edge); - - // Convert to spherical - ToSpherical(&templ, &temp); - - - if ( templ.r > closel.r && - templ.theta >= (theta*180.0/SECTORS) && - templ.theta <= ((theta+1)*180.0/SECTORS) && - templ.alpha >= (alpha*360.0/SECTORS) && - templ.alpha <= ((alpha+1)*360.0/SECTORS)) { - - closel = templ; - } - } - } - - gbd ->Gamut[theta][alpha].p = closel; - gbd ->Gamut[theta][alpha].Type = GP_MODELED; - - return TRUE; - -} - - -// Interpolate missing parts. The algorithm fist computes slices at -// theta=0 and theta=Max. -cmsBool CMSEXPORT cmsGDBCompute(cmsHANDLE hGBD, cmsUInt32Number dwFlags) -{ - int alpha, theta; - cmsGDB* gbd = (cmsGDB*) hGBD; - - _cmsAssert(hGBD != NULL); - - // Interpolate black - for (alpha = 0; alpha < SECTORS; alpha++) { - - if (!InterpolateMissingSector(gbd, alpha, 0)) return FALSE; - } - - // Interpolate white - for (alpha = 0; alpha < SECTORS; alpha++) { - - if (!InterpolateMissingSector(gbd, alpha, SECTORS-1)) return FALSE; - } - - - // Interpolate Mid - for (theta = 1; theta < SECTORS; theta++) { - for (alpha = 0; alpha < SECTORS; alpha++) { - - if (!InterpolateMissingSector(gbd, alpha, theta)) return FALSE; - } - } - - // Done - return TRUE; - - cmsUNUSED_PARAMETER(dwFlags); -} - - - - -// -------------------------------------------------------------------------------------------------------- - -// Great for debug, but not suitable for real use - -#if 0 -cmsBool cmsGBDdumpVRML(cmsHANDLE hGBD, const char* fname) -{ - FILE* fp; - int i, j; - cmsGDB* gbd = (cmsGDB*) hGBD; - cmsGDBPoint* pt; - - fp = fopen (fname, "wt"); - if (fp == NULL) - return FALSE; - - fprintf (fp, "#VRML V2.0 utf8\n"); - - // set the viewing orientation and distance - fprintf (fp, "DEF CamTest Group {\n"); - fprintf (fp, "\tchildren [\n"); - fprintf (fp, "\t\tDEF Cameras Group {\n"); - fprintf (fp, "\t\t\tchildren [\n"); - fprintf (fp, "\t\t\t\tDEF DefaultView Viewpoint {\n"); - fprintf (fp, "\t\t\t\t\tposition 0 0 340\n"); - fprintf (fp, "\t\t\t\t\torientation 0 0 1 0\n"); - fprintf (fp, "\t\t\t\t\tdescription \"default view\"\n"); - fprintf (fp, "\t\t\t\t}\n"); - fprintf (fp, "\t\t\t]\n"); - fprintf (fp, "\t\t},\n"); - fprintf (fp, "\t]\n"); - fprintf (fp, "}\n"); - - // Output the background stuff - fprintf (fp, "Background {\n"); - fprintf (fp, "\tskyColor [\n"); - fprintf (fp, "\t\t.5 .5 .5\n"); - fprintf (fp, "\t]\n"); - fprintf (fp, "}\n"); - - // Output the shape stuff - fprintf (fp, "Transform {\n"); - fprintf (fp, "\tscale .3 .3 .3\n"); - fprintf (fp, "\tchildren [\n"); - - // Draw the axes as a shape: - fprintf (fp, "\t\tShape {\n"); - fprintf (fp, "\t\t\tappearance Appearance {\n"); - fprintf (fp, "\t\t\t\tmaterial Material {\n"); - fprintf (fp, "\t\t\t\t\tdiffuseColor 0 0.8 0\n"); - fprintf (fp, "\t\t\t\t\temissiveColor 1.0 1.0 1.0\n"); - fprintf (fp, "\t\t\t\t\tshininess 0.8\n"); - fprintf (fp, "\t\t\t\t}\n"); - fprintf (fp, "\t\t\t}\n"); - fprintf (fp, "\t\t\tgeometry IndexedLineSet {\n"); - fprintf (fp, "\t\t\t\tcoord Coordinate {\n"); - fprintf (fp, "\t\t\t\t\tpoint [\n"); - fprintf (fp, "\t\t\t\t\t0.0 0.0 0.0,\n"); - fprintf (fp, "\t\t\t\t\t%f 0.0 0.0,\n", 255.0); - fprintf (fp, "\t\t\t\t\t0.0 %f 0.0,\n", 255.0); - fprintf (fp, "\t\t\t\t\t0.0 0.0 %f]\n", 255.0); - fprintf (fp, "\t\t\t\t}\n"); - fprintf (fp, "\t\t\t\tcoordIndex [\n"); - fprintf (fp, "\t\t\t\t\t0, 1, -1\n"); - fprintf (fp, "\t\t\t\t\t0, 2, -1\n"); - fprintf (fp, "\t\t\t\t\t0, 3, -1]\n"); - fprintf (fp, "\t\t\t}\n"); - fprintf (fp, "\t\t}\n"); - - - fprintf (fp, "\t\tShape {\n"); - fprintf (fp, "\t\t\tappearance Appearance {\n"); - fprintf (fp, "\t\t\t\tmaterial Material {\n"); - fprintf (fp, "\t\t\t\t\tdiffuseColor 0 0.8 0\n"); - fprintf (fp, "\t\t\t\t\temissiveColor 1 1 1\n"); - fprintf (fp, "\t\t\t\t\tshininess 0.8\n"); - fprintf (fp, "\t\t\t\t}\n"); - fprintf (fp, "\t\t\t}\n"); - fprintf (fp, "\t\t\tgeometry PointSet {\n"); - - // fill in the points here - fprintf (fp, "\t\t\t\tcoord Coordinate {\n"); - fprintf (fp, "\t\t\t\t\tpoint [\n"); - - // We need to transverse all gamut hull. - for (i=0; i < SECTORS; i++) - for (j=0; j < SECTORS; j++) { - - cmsVEC3 v; - - pt = &gbd ->Gamut[i][j]; - ToCartesian(&v, &pt ->p); - - fprintf (fp, "\t\t\t\t\t%g %g %g", v.n[0]+50, v.n[1], v.n[2]); - - if ((j == SECTORS - 1) && (i == SECTORS - 1)) - fprintf (fp, "]\n"); - else - fprintf (fp, ",\n"); - - } - - fprintf (fp, "\t\t\t\t}\n"); - - - - // fill in the face colors - fprintf (fp, "\t\t\t\tcolor Color {\n"); - fprintf (fp, "\t\t\t\t\tcolor [\n"); - - for (i=0; i < SECTORS; i++) - for (j=0; j < SECTORS; j++) { - - cmsVEC3 v; - - pt = &gbd ->Gamut[i][j]; - - - ToCartesian(&v, &pt ->p); - - - if (pt ->Type == GP_EMPTY) - fprintf (fp, "\t\t\t\t\t%g %g %g", 0.0, 0.0, 0.0); - else - if (pt ->Type == GP_MODELED) - fprintf (fp, "\t\t\t\t\t%g %g %g", 1.0, .5, .5); - else { - fprintf (fp, "\t\t\t\t\t%g %g %g", 1.0, 1.0, 1.0); - - } - - if ((j == SECTORS - 1) && (i == SECTORS - 1)) - fprintf (fp, "]\n"); - else - fprintf (fp, ",\n"); - } - fprintf (fp, "\t\t\t}\n"); - - - fprintf (fp, "\t\t\t}\n"); - fprintf (fp, "\t\t}\n"); - fprintf (fp, "\t]\n"); - fprintf (fp, "}\n"); - - fclose (fp); - - return TRUE; -} -#endif diff --git a/third_party/lcms2-2.6/src/cmstypes.c b/third_party/lcms2-2.6/src/cmstypes.c deleted file mode 100644 index 29806fb194..0000000000 --- a/third_party/lcms2-2.6/src/cmstypes.c +++ /dev/null @@ -1,5610 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2014 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- -// - -#include "lcms2_internal.h" - -// Tag Serialization ----------------------------------------------------------------------------- -// This file implements every single tag and tag type as described in the ICC spec. Some types -// have been deprecated, like ncl and Data. There is no implementation for those types as there -// are no profiles holding them. The programmer can also extend this list by defining his own types -// by using the appropiate plug-in. There are three types of plug ins regarding that. First type -// allows to define new tags using any existing type. Next plug-in type allows to define new types -// and the third one is very specific: allows to extend the number of elements in the multiprocessing -// elements special type. -//-------------------------------------------------------------------------------------------------- - -// Some broken types -#define cmsCorbisBrokenXYZtype ((cmsTagTypeSignature) 0x17A505B8) -#define cmsMonacoBrokenCurveType ((cmsTagTypeSignature) 0x9478ee00) - -// This is the linked list that keeps track of the defined types -typedef struct _cmsTagTypeLinkedList_st { - - cmsTagTypeHandler Handler; - struct _cmsTagTypeLinkedList_st* Next; - -} _cmsTagTypeLinkedList; - -// Some macros to define callbacks. -#define READ_FN(x) Type_##x##_Read -#define WRITE_FN(x) Type_##x##_Write -#define FREE_FN(x) Type_##x##_Free -#define DUP_FN(x) Type_##x##_Dup - -// Helper macro to define a handler. Callbacks do have a fixed naming convention. -#define TYPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), DUP_FN(x), FREE_FN(x), NULL, 0 } - -// Helper macro to define a MPE handler. Callbacks do have a fixed naming convention -#define TYPE_MPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), GenericMPEdup, GenericMPEfree, NULL, 0 } - -// Register a new type handler. This routine is shared between normal types and MPE. LinkedList points to the optional list head -static -cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsMemoryClient pos) -{ - cmsPluginTagType* Plugin = (cmsPluginTagType*) Data; - _cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(id, pos); - _cmsTagTypeLinkedList *pt; - - // Calling the function with NULL as plug-in would unregister the plug in. - if (Data == NULL) { - - // There is no need to set free the memory, as pool is destroyed as a whole. - ctx ->TagTypes = NULL; - return TRUE; - } - - // Registering happens in plug-in memory pool. - pt = (_cmsTagTypeLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagTypeLinkedList)); - if (pt == NULL) return FALSE; - - pt ->Handler = Plugin ->Handler; - pt ->Next = ctx ->TagTypes; - - ctx ->TagTypes = pt; - - return TRUE; -} - -// Return handler for a given type or NULL if not found. Shared between normal types and MPE. It first tries the additons -// made by plug-ins and then the built-in defaults. -static -cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* PluginLinkedList, _cmsTagTypeLinkedList* DefaultLinkedList) -{ - _cmsTagTypeLinkedList* pt; - - for (pt = PluginLinkedList; - pt != NULL; - pt = pt ->Next) { - - if (sig == pt -> Handler.Signature) return &pt ->Handler; - } - - for (pt = DefaultLinkedList; - pt != NULL; - pt = pt ->Next) { - - if (sig == pt -> Handler.Signature) return &pt ->Handler; - } - - return NULL; -} - - -// Auxiliar to convert UTF-32 to UTF-16 in some cases -static -cmsBool _cmsWriteWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, const wchar_t* Array) -{ - cmsUInt32Number i; - - _cmsAssert(io != NULL); - _cmsAssert(!(Array == NULL && n > 0)); - - for (i=0; i < n; i++) { - if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Array[i])) return FALSE; - } - - return TRUE; -} - -// Auxiliar to read an array of wchar_t -static -cmsBool _cmsReadWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, wchar_t* Array) -{ - cmsUInt32Number i; - cmsUInt16Number tmp; - - _cmsAssert(io != NULL); - - for (i=0; i < n; i++) { - - if (Array != NULL) { - - if (!_cmsReadUInt16Number(io, &tmp)) return FALSE; - Array[i] = (wchar_t) tmp; - } - else { - if (!_cmsReadUInt16Number(io, NULL)) return FALSE; - } - - } - return TRUE; -} - -// To deal with position tables -typedef cmsBool (* PositionTableEntryFn)(struct _cms_typehandler_struct* self, - cmsIOHANDLER* io, - void* Cargo, - cmsUInt32Number n, - cmsUInt32Number SizeOfTag); - -// Helper function to deal with position tables as decribed in ICC spec 4.3 -// A table of n elements is readed, where first comes n records containing offsets and sizes and -// then a block containing the data itself. This allows to reuse same data in more than one entry -static -cmsBool ReadPositionTable(struct _cms_typehandler_struct* self, - cmsIOHANDLER* io, - cmsUInt32Number Count, - cmsUInt32Number BaseOffset, - void *Cargo, - PositionTableEntryFn ElementFn) -{ - cmsUInt32Number i; - cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL; - cmsUInt32Number currentPosition; - - currentPosition = io->Tell(io); - // Verify there is enough space left to read two cmsUInt32Number items for Count items. - if (((io->ReportedSize - currentPosition) / (2 * sizeof(cmsUInt32Number))) < Count) - return FALSE; - - // Let's take the offsets to each element - ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number)); - if (ElementOffsets == NULL) goto Error; - - ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number)); - if (ElementSizes == NULL) goto Error; - - for (i=0; i < Count; i++) { - - if (!_cmsReadUInt32Number(io, &ElementOffsets[i])) goto Error; - if (!_cmsReadUInt32Number(io, &ElementSizes[i])) goto Error; - - ElementOffsets[i] += BaseOffset; - } - - // Seek to each element and read it - for (i=0; i < Count; i++) { - - if (!io -> Seek(io, ElementOffsets[i])) goto Error; - - // This is the reader callback - if (!ElementFn(self, io, Cargo, i, ElementSizes[i])) goto Error; - } - - // Success - if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets); - if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes); - return TRUE; - -Error: - if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets); - if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes); - return FALSE; -} - -// Same as anterior, but for write position tables -static -cmsBool WritePositionTable(struct _cms_typehandler_struct* self, - cmsIOHANDLER* io, - cmsUInt32Number SizeOfTag, - cmsUInt32Number Count, - cmsUInt32Number BaseOffset, - void *Cargo, - PositionTableEntryFn ElementFn) -{ - cmsUInt32Number i; - cmsUInt32Number DirectoryPos, CurrentPos, Before; - cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL; - - // Create table - ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number)); - if (ElementOffsets == NULL) goto Error; - - ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number)); - if (ElementSizes == NULL) goto Error; - - // Keep starting position of curve offsets - DirectoryPos = io ->Tell(io); - - // Write a fake directory to be filled latter on - for (i=0; i < Count; i++) { - - if (!_cmsWriteUInt32Number(io, 0)) goto Error; // Offset - if (!_cmsWriteUInt32Number(io, 0)) goto Error; // size - } - - // Write each element. Keep track of the size as well. - for (i=0; i < Count; i++) { - - Before = io ->Tell(io); - ElementOffsets[i] = Before - BaseOffset; - - // Callback to write... - if (!ElementFn(self, io, Cargo, i, SizeOfTag)) goto Error; - - // Now the size - ElementSizes[i] = io ->Tell(io) - Before; - } - - // Write the directory - CurrentPos = io ->Tell(io); - if (!io ->Seek(io, DirectoryPos)) goto Error; - - for (i=0; i < Count; i++) { - if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error; - if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error; - } - - if (!io ->Seek(io, CurrentPos)) goto Error; - - if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets); - if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes); - return TRUE; - -Error: - if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets); - if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes); - return FALSE; -} - - -// ******************************************************************************** -// Type XYZ. Only one value is allowed -// ******************************************************************************** - -//The XYZType contains an array of three encoded values for the XYZ tristimulus -//values. Tristimulus values must be non-negative. The signed encoding allows for -//implementation optimizations by minimizing the number of fixed formats. - - -static -void *Type_XYZ_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsCIEXYZ* xyz; - - *nItems = 0; - xyz = (cmsCIEXYZ*) _cmsMallocZero(self ->ContextID, sizeof(cmsCIEXYZ)); - if (xyz == NULL) return NULL; - - if (!_cmsReadXYZNumber(io, xyz)) { - _cmsFree(self ->ContextID, xyz); - return NULL; - } - - *nItems = 1; - return (void*) xyz; - - cmsUNUSED_PARAMETER(SizeOfTag); -} - -static -cmsBool Type_XYZ_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - return _cmsWriteXYZNumber(io, (cmsCIEXYZ*) Ptr); - - cmsUNUSED_PARAMETER(nItems); - cmsUNUSED_PARAMETER(self); -} - -static -void* Type_XYZ_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIEXYZ)); - - cmsUNUSED_PARAMETER(n); -} - -static -void Type_XYZ_Free(struct _cms_typehandler_struct* self, void *Ptr) -{ - _cmsFree(self ->ContextID, Ptr); -} - - -static -cmsTagTypeSignature DecideXYZtype(cmsFloat64Number ICCVersion, const void *Data) -{ - return cmsSigXYZType; - - cmsUNUSED_PARAMETER(ICCVersion); - cmsUNUSED_PARAMETER(Data); -} - - -// ******************************************************************************** -// Type chromaticity. Only one value is allowed -// ******************************************************************************** -// The chromaticity tag type provides basic chromaticity data and type of -// phosphors or colorants of a monitor to applications and utilities. - -static -void *Type_Chromaticity_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsCIExyYTRIPLE* chrm; - cmsUInt16Number nChans, Table; - - *nItems = 0; - chrm = (cmsCIExyYTRIPLE*) _cmsMallocZero(self ->ContextID, sizeof(cmsCIExyYTRIPLE)); - if (chrm == NULL) return NULL; - - if (!_cmsReadUInt16Number(io, &nChans)) goto Error; - - // Let's recover from a bug introduced in early versions of lcms1 - if (nChans == 0 && SizeOfTag == 32) { - - if (!_cmsReadUInt16Number(io, NULL)) goto Error; - if (!_cmsReadUInt16Number(io, &nChans)) goto Error; - } - - if (nChans != 3) goto Error; - - if (!_cmsReadUInt16Number(io, &Table)) goto Error; - - if (!_cmsRead15Fixed16Number(io, &chrm ->Red.x)) goto Error; - if (!_cmsRead15Fixed16Number(io, &chrm ->Red.y)) goto Error; - - chrm ->Red.Y = 1.0; - - if (!_cmsRead15Fixed16Number(io, &chrm ->Green.x)) goto Error; - if (!_cmsRead15Fixed16Number(io, &chrm ->Green.y)) goto Error; - - chrm ->Green.Y = 1.0; - - if (!_cmsRead15Fixed16Number(io, &chrm ->Blue.x)) goto Error; - if (!_cmsRead15Fixed16Number(io, &chrm ->Blue.y)) goto Error; - - chrm ->Blue.Y = 1.0; - - *nItems = 1; - return (void*) chrm; - -Error: - _cmsFree(self ->ContextID, (void*) chrm); - return NULL; - - cmsUNUSED_PARAMETER(SizeOfTag); -} - -static -cmsBool SaveOneChromaticity(cmsFloat64Number x, cmsFloat64Number y, cmsIOHANDLER* io) -{ - if (!_cmsWriteUInt32Number(io, _cmsDoubleTo15Fixed16(x))) return FALSE; - if (!_cmsWriteUInt32Number(io, _cmsDoubleTo15Fixed16(y))) return FALSE; - - return TRUE; -} - -static -cmsBool Type_Chromaticity_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsCIExyYTRIPLE* chrm = (cmsCIExyYTRIPLE*) Ptr; - - if (!_cmsWriteUInt16Number(io, 3)) return FALSE; // nChannels - if (!_cmsWriteUInt16Number(io, 0)) return FALSE; // Table - - if (!SaveOneChromaticity(chrm -> Red.x, chrm -> Red.y, io)) return FALSE; - if (!SaveOneChromaticity(chrm -> Green.x, chrm -> Green.y, io)) return FALSE; - if (!SaveOneChromaticity(chrm -> Blue.x, chrm -> Blue.y, io)) return FALSE; - - return TRUE; - - cmsUNUSED_PARAMETER(nItems); - cmsUNUSED_PARAMETER(self); -} - -static -void* Type_Chromaticity_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIExyYTRIPLE)); - - cmsUNUSED_PARAMETER(n); -} - -static -void Type_Chromaticity_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - _cmsFree(self ->ContextID, Ptr); -} - - -// ******************************************************************************** -// Type cmsSigColorantOrderType -// ******************************************************************************** - -// This is an optional tag which specifies the laydown order in which colorants will -// be printed on an n-colorant device. The laydown order may be the same as the -// channel generation order listed in the colorantTableTag or the channel order of a -// colour space such as CMYK, in which case this tag is not needed. When this is not -// the case (for example, ink-towers sometimes use the order KCMY), this tag may be -// used to specify the laydown order of the colorants. - - -static -void *Type_ColorantOrderType_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsUInt8Number* ColorantOrder; - cmsUInt32Number Count; - - *nItems = 0; - if (!_cmsReadUInt32Number(io, &Count)) return NULL; - if (Count > cmsMAXCHANNELS) return NULL; - - ColorantOrder = (cmsUInt8Number*) _cmsCalloc(self ->ContextID, cmsMAXCHANNELS, sizeof(cmsUInt8Number)); - if (ColorantOrder == NULL) return NULL; - - // We use FF as end marker - memset(ColorantOrder, 0xFF, cmsMAXCHANNELS * sizeof(cmsUInt8Number)); - - if (io ->Read(io, ColorantOrder, sizeof(cmsUInt8Number), Count) != Count) { - - _cmsFree(self ->ContextID, (void*) ColorantOrder); - return NULL; - } - - *nItems = 1; - return (void*) ColorantOrder; - - cmsUNUSED_PARAMETER(SizeOfTag); -} - -static -cmsBool Type_ColorantOrderType_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsUInt8Number* ColorantOrder = (cmsUInt8Number*) Ptr; - cmsUInt32Number i, sz, Count; - - // Get the length - for (Count=i=0; i < cmsMAXCHANNELS; i++) { - if (ColorantOrder[i] != 0xFF) Count++; - } - - if (!_cmsWriteUInt32Number(io, Count)) return FALSE; - - sz = Count * sizeof(cmsUInt8Number); - if (!io -> Write(io, sz, ColorantOrder)) return FALSE; - - return TRUE; - - cmsUNUSED_PARAMETER(nItems); - cmsUNUSED_PARAMETER(self); -} - -static -void* Type_ColorantOrderType_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - return _cmsDupMem(self ->ContextID, Ptr, cmsMAXCHANNELS * sizeof(cmsUInt8Number)); - - cmsUNUSED_PARAMETER(n); -} - - -static -void Type_ColorantOrderType_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - _cmsFree(self ->ContextID, Ptr); -} - -// ******************************************************************************** -// Type cmsSigS15Fixed16ArrayType -// ******************************************************************************** -// This type represents an array of generic 4-byte/32-bit fixed point quantity. -// The number of values is determined from the size of the tag. - -static -void *Type_S15Fixed16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsFloat64Number* array_double; - cmsUInt32Number i, n; - - *nItems = 0; - n = SizeOfTag / sizeof(cmsUInt32Number); - array_double = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, n, sizeof(cmsFloat64Number)); - if (array_double == NULL) return NULL; - - for (i=0; i < n; i++) { - - if (!_cmsRead15Fixed16Number(io, &array_double[i])) { - - _cmsFree(self ->ContextID, array_double); - return NULL; - } - } - - *nItems = n; - return (void*) array_double; -} - -static -cmsBool Type_S15Fixed16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsFloat64Number* Value = (cmsFloat64Number*) Ptr; - cmsUInt32Number i; - - for (i=0; i < nItems; i++) { - - if (!_cmsWrite15Fixed16Number(io, Value[i])) return FALSE; - } - - return TRUE; - - cmsUNUSED_PARAMETER(self); -} - -static -void* Type_S15Fixed16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsFloat64Number)); -} - - -static -void Type_S15Fixed16_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - _cmsFree(self ->ContextID, Ptr); -} - -// ******************************************************************************** -// Type cmsSigU16Fixed16ArrayType -// ******************************************************************************** -// This type represents an array of generic 4-byte/32-bit quantity. -// The number of values is determined from the size of the tag. - - -static -void *Type_U16Fixed16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsFloat64Number* array_double; - cmsUInt32Number v; - cmsUInt32Number i, n; - - *nItems = 0; - n = SizeOfTag / sizeof(cmsUInt32Number); - array_double = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, n, sizeof(cmsFloat64Number)); - if (array_double == NULL) return NULL; - - for (i=0; i < n; i++) { - - if (!_cmsReadUInt32Number(io, &v)) { - _cmsFree(self ->ContextID, (void*) array_double); - return NULL; - } - - // Convert to cmsFloat64Number - array_double[i] = (cmsFloat64Number) (v / 65536.0); - } - - *nItems = n; - return (void*) array_double; -} - -static -cmsBool Type_U16Fixed16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsFloat64Number* Value = (cmsFloat64Number*) Ptr; - cmsUInt32Number i; - - for (i=0; i < nItems; i++) { - - cmsUInt32Number v = (cmsUInt32Number) floor(Value[i]*65536.0 + 0.5); - - if (!_cmsWriteUInt32Number(io, v)) return FALSE; - } - - return TRUE; - - cmsUNUSED_PARAMETER(self); -} - - -static -void* Type_U16Fixed16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsFloat64Number)); -} - -static -void Type_U16Fixed16_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - _cmsFree(self ->ContextID, Ptr); -} - -// ******************************************************************************** -// Type cmsSigSignatureType -// ******************************************************************************** -// -// The signatureType contains a four-byte sequence, Sequences of less than four -// characters are padded at the end with spaces, 20h. -// Typically this type is used for registered tags that can be displayed on many -// development systems as a sequence of four characters. - -static -void *Type_Signature_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsSignature* SigPtr = (cmsSignature*) _cmsMalloc(self ->ContextID, sizeof(cmsSignature)); - if (SigPtr == NULL) return NULL; - - if (!_cmsReadUInt32Number(io, SigPtr)) return NULL; - *nItems = 1; - - return SigPtr; - - cmsUNUSED_PARAMETER(SizeOfTag); -} - -static -cmsBool Type_Signature_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsSignature* SigPtr = (cmsSignature*) Ptr; - - return _cmsWriteUInt32Number(io, *SigPtr); - - cmsUNUSED_PARAMETER(nItems); - cmsUNUSED_PARAMETER(self); -} - -static -void* Type_Signature_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsSignature)); -} - -static -void Type_Signature_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - _cmsFree(self ->ContextID, Ptr); -} - - -// ******************************************************************************** -// Type cmsSigTextType -// ******************************************************************************** -// -// The textType is a simple text structure that contains a 7-bit ASCII text string. -// The length of the string is obtained by subtracting 8 from the element size portion -// of the tag itself. This string must be terminated with a 00h byte. - -static -void *Type_Text_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - char* Text = NULL; - cmsMLU* mlu = NULL; - - // Create a container - mlu = cmsMLUalloc(self ->ContextID, 1); - if (mlu == NULL) return NULL; - - *nItems = 0; - - // We need to store the "\0" at the end, so +1 - if (SizeOfTag == UINT_MAX) goto Error; - - Text = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1); - if (Text == NULL) goto Error; - - if (io -> Read(io, Text, sizeof(char), SizeOfTag) != SizeOfTag) goto Error; - - // Make sure text is properly ended - Text[SizeOfTag] = 0; - *nItems = 1; - - // Keep the result - if (!cmsMLUsetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text)) goto Error; - - _cmsFree(self ->ContextID, Text); - return (void*) mlu; - -Error: - if (mlu != NULL) - cmsMLUfree(mlu); - if (Text != NULL) - _cmsFree(self ->ContextID, Text); - - return NULL; -} - -// The conversion implies to choose a language. So, we choose the actual language. -static -cmsBool Type_Text_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsMLU* mlu = (cmsMLU*) Ptr; - cmsUInt32Number size; - cmsBool rc; - char* Text; - - // Get the size of the string. Note there is an extra "\0" at the end - size = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0); - if (size == 0) return FALSE; // Cannot be zero! - - // Create memory - Text = (char*) _cmsMalloc(self ->ContextID, size); - if (Text == NULL) return FALSE; - - cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, size); - - // Write it, including separator - rc = io ->Write(io, size, Text); - - _cmsFree(self ->ContextID, Text); - return rc; - - cmsUNUSED_PARAMETER(nItems); -} - -static -void* Type_Text_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - return (void*) cmsMLUdup((cmsMLU*) Ptr); - - cmsUNUSED_PARAMETER(n); - cmsUNUSED_PARAMETER(self); -} - - -static -void Type_Text_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - cmsMLU* mlu = (cmsMLU*) Ptr; - cmsMLUfree(mlu); - return; - - cmsUNUSED_PARAMETER(self); -} - -static -cmsTagTypeSignature DecideTextType(cmsFloat64Number ICCVersion, const void *Data) -{ - if (ICCVersion >= 4.0) - return cmsSigMultiLocalizedUnicodeType; - - return cmsSigTextType; - - cmsUNUSED_PARAMETER(Data); -} - - -// ******************************************************************************** -// Type cmsSigDataType -// ******************************************************************************** - -// General purpose data type -static -void *Type_Data_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsICCData* BinData; - cmsUInt32Number LenOfData; - - *nItems = 0; - - if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; - - LenOfData = SizeOfTag - sizeof(cmsUInt32Number); - if (LenOfData > INT_MAX) return NULL; - - BinData = (cmsICCData*) _cmsMalloc(self ->ContextID, sizeof(cmsICCData) + LenOfData - 1); - if (BinData == NULL) return NULL; - - BinData ->len = LenOfData; - if (!_cmsReadUInt32Number(io, &BinData->flag)) { - _cmsFree(self ->ContextID, BinData); - return NULL; - } - - if (io -> Read(io, BinData ->data, sizeof(cmsUInt8Number), LenOfData) != LenOfData) { - - _cmsFree(self ->ContextID, BinData); - return NULL; - } - - *nItems = 1; - - return (void*) BinData; -} - - -static -cmsBool Type_Data_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsICCData* BinData = (cmsICCData*) Ptr; - - if (!_cmsWriteUInt32Number(io, BinData ->flag)) return FALSE; - - return io ->Write(io, BinData ->len, BinData ->data); - - cmsUNUSED_PARAMETER(nItems); - cmsUNUSED_PARAMETER(self); -} - - -static -void* Type_Data_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - cmsICCData* BinData = (cmsICCData*) Ptr; - - return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsICCData) + BinData ->len - 1); - - cmsUNUSED_PARAMETER(n); -} - -static -void Type_Data_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - _cmsFree(self ->ContextID, Ptr); -} - -// ******************************************************************************** -// Type cmsSigTextDescriptionType -// ******************************************************************************** - -static -void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - char* Text = NULL; - cmsMLU* mlu = NULL; - cmsUInt32Number AsciiCount; - cmsUInt32Number i, UnicodeCode, UnicodeCount; - cmsUInt16Number ScriptCodeCode, Dummy; - cmsUInt8Number ScriptCodeCount; - - *nItems = 0; - - // One dword should be there - if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; - - // Read len of ASCII - if (!_cmsReadUInt32Number(io, &AsciiCount)) return NULL; - SizeOfTag -= sizeof(cmsUInt32Number); - - // Check for size - if (SizeOfTag < AsciiCount) return NULL; - - // All seems Ok, allocate the container - mlu = cmsMLUalloc(self ->ContextID, 1); - if (mlu == NULL) return NULL; - - // As many memory as size of tag - Text = (char*) _cmsMalloc(self ->ContextID, AsciiCount + 1); - if (Text == NULL) goto Error; - - // Read it - if (io ->Read(io, Text, sizeof(char), AsciiCount) != AsciiCount) goto Error; - SizeOfTag -= AsciiCount; - - // Make sure there is a terminator - Text[AsciiCount] = 0; - - // Set the MLU entry. From here we can be tolerant to wrong types - if (!cmsMLUsetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text)) goto Error; - _cmsFree(self ->ContextID, (void*) Text); - Text = NULL; - - // Skip Unicode code - if (SizeOfTag < 2* sizeof(cmsUInt32Number)) goto Done; - if (!_cmsReadUInt32Number(io, &UnicodeCode)) goto Done; - if (!_cmsReadUInt32Number(io, &UnicodeCount)) goto Done; - SizeOfTag -= 2* sizeof(cmsUInt32Number); - - if (SizeOfTag < UnicodeCount*sizeof(cmsUInt16Number)) goto Done; - - for (i=0; i < UnicodeCount; i++) { - if (!io ->Read(io, &Dummy, sizeof(cmsUInt16Number), 1)) goto Done; - } - SizeOfTag -= UnicodeCount*sizeof(cmsUInt16Number); - - // Skip ScriptCode code if present. Some buggy profiles does have less - // data that stricttly required. We need to skip it as this type may come - // embedded in other types. - - if (SizeOfTag >= sizeof(cmsUInt16Number) + sizeof(cmsUInt8Number) + 67) { - - if (!_cmsReadUInt16Number(io, &ScriptCodeCode)) goto Done; - if (!_cmsReadUInt8Number(io, &ScriptCodeCount)) goto Done; - - // Skip rest of tag - for (i=0; i < 67; i++) { - if (!io ->Read(io, &Dummy, sizeof(cmsUInt8Number), 1)) goto Error; - } - } - -Done: - - *nItems = 1; - return mlu; - -Error: - if (Text) _cmsFree(self ->ContextID, (void*) Text); - if (mlu) cmsMLUfree(mlu); - return NULL; -} - - -// This tag can come IN UNALIGNED SIZE. In order to prevent issues, we force zeros on description to align it -static -cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsMLU* mlu = (cmsMLU*) Ptr; - char *Text = NULL; - wchar_t *Wide = NULL; - cmsUInt32Number len, len_aligned, len_filler_alignment; - cmsBool rc = FALSE; - char Filler[68]; - - // Used below for writting zeroes - memset(Filler, 0, sizeof(Filler)); - - // Get the len of string - len = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0); - - // From ICC3.4: It has been found that textDescriptionType can contain misaligned data - //(see clause 4.1 for the definition of 'aligned'. Because the Unicode language - // code and Unicode count immediately follow the ASCII description, their - // alignment is not correct if the ASCII count is not a multiple of four. The - // ScriptCode code is misaligned when the ASCII count is odd. Profile reading and - // writing software must be written carefully in order to handle these alignment - // problems. - - // Compute an aligned size - len_aligned = _cmsALIGNLONG(len); - len_filler_alignment = len_aligned - len; - - // Null strings - if (len <= 0) { - - Text = (char*) _cmsDupMem(self ->ContextID, "", sizeof(char)); - Wide = (wchar_t*) _cmsDupMem(self ->ContextID, L"", sizeof(wchar_t)); - } - else { - // Create independent buffers - Text = (char*) _cmsCalloc(self ->ContextID, len, sizeof(char)); - if (Text == NULL) goto Error; - - Wide = (wchar_t*) _cmsCalloc(self ->ContextID, len, sizeof(wchar_t)); - if (Wide == NULL) goto Error; - - // Get both representations. - cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, len * sizeof(char)); - cmsMLUgetWide(mlu, cmsNoLanguage, cmsNoCountry, Wide, len * sizeof(wchar_t)); - } - - // * cmsUInt32Number count; * Description length - // * cmsInt8Number desc[count] * NULL terminated ascii string - // * cmsUInt32Number ucLangCode; * UniCode language code - // * cmsUInt32Number ucCount; * UniCode description length - // * cmsInt16Number ucDesc[ucCount];* The UniCode description - // * cmsUInt16Number scCode; * ScriptCode code - // * cmsUInt8Number scCount; * ScriptCode count - // * cmsInt8Number scDesc[67]; * ScriptCode Description - - if (!_cmsWriteUInt32Number(io, len_aligned)) goto Error; - if (!io ->Write(io, len, Text)) goto Error; - if (!io ->Write(io, len_filler_alignment, Filler)) goto Error; - - if (!_cmsWriteUInt32Number(io, 0)) goto Error; // ucLanguageCode - - // This part is tricky: we need an aligned tag size, and the ScriptCode part - // takes 70 bytes, so we need 2 extra bytes to do the alignment - - if (!_cmsWriteUInt32Number(io, len_aligned+1)) goto Error; - - // Note that in some compilers sizeof(cmsUInt16Number) != sizeof(wchar_t) - if (!_cmsWriteWCharArray(io, len, Wide)) goto Error; - if (!_cmsWriteUInt16Array(io, len_filler_alignment+1, (cmsUInt16Number*) Filler)) goto Error; - - // ScriptCode Code & count (unused) - if (!_cmsWriteUInt16Number(io, 0)) goto Error; - if (!_cmsWriteUInt8Number(io, 0)) goto Error; - - if (!io ->Write(io, 67, Filler)) goto Error; - - rc = TRUE; - -Error: - if (Text) _cmsFree(self ->ContextID, Text); - if (Wide) _cmsFree(self ->ContextID, Wide); - - return rc; - - cmsUNUSED_PARAMETER(nItems); -} - - -static -void* Type_Text_Description_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - return (void*) cmsMLUdup((cmsMLU*) Ptr); - - cmsUNUSED_PARAMETER(n); - cmsUNUSED_PARAMETER(self); -} - -static -void Type_Text_Description_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - cmsMLU* mlu = (cmsMLU*) Ptr; - - cmsMLUfree(mlu); - return; - - cmsUNUSED_PARAMETER(self); -} - - -static -cmsTagTypeSignature DecideTextDescType(cmsFloat64Number ICCVersion, const void *Data) -{ - if (ICCVersion >= 4.0) - return cmsSigMultiLocalizedUnicodeType; - - return cmsSigTextDescriptionType; - - cmsUNUSED_PARAMETER(Data); -} - - -// ******************************************************************************** -// Type cmsSigCurveType -// ******************************************************************************** - -static -void *Type_Curve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsUInt32Number Count; - cmsToneCurve* NewGamma; - - *nItems = 0; - if (!_cmsReadUInt32Number(io, &Count)) return NULL; - - switch (Count) { - - case 0: // Linear. - { - cmsFloat64Number SingleGamma = 1.0; - - NewGamma = cmsBuildParametricToneCurve(self ->ContextID, 1, &SingleGamma); - if (!NewGamma) return NULL; - *nItems = 1; - return NewGamma; - } - - case 1: // Specified as the exponent of gamma function - { - cmsUInt16Number SingleGammaFixed; - cmsFloat64Number SingleGamma; - - if (!_cmsReadUInt16Number(io, &SingleGammaFixed)) return NULL; - SingleGamma = _cms8Fixed8toDouble(SingleGammaFixed); - - *nItems = 1; - return cmsBuildParametricToneCurve(self ->ContextID, 1, &SingleGamma); - } - - default: // Curve - - if (Count > 0x7FFF) - return NULL; // This is to prevent bad guys for doing bad things - - NewGamma = cmsBuildTabulatedToneCurve16(self ->ContextID, Count, NULL); - if (!NewGamma) return NULL; - - if (!_cmsReadUInt16Array(io, Count, NewGamma -> Table16)) { - cmsFreeToneCurve(NewGamma); - return NULL; - } - - *nItems = 1; - return NewGamma; - } - - cmsUNUSED_PARAMETER(SizeOfTag); -} - - -static -cmsBool Type_Curve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsToneCurve* Curve = (cmsToneCurve*) Ptr; - - if (Curve ->nSegments == 1 && Curve ->Segments[0].Type == 1) { - - // Single gamma, preserve number - cmsUInt16Number SingleGammaFixed = _cmsDoubleTo8Fixed8(Curve ->Segments[0].Params[0]); - - if (!_cmsWriteUInt32Number(io, 1)) return FALSE; - if (!_cmsWriteUInt16Number(io, SingleGammaFixed)) return FALSE; - return TRUE; - - } - - if (!_cmsWriteUInt32Number(io, Curve ->nEntries)) return FALSE; - return _cmsWriteUInt16Array(io, Curve ->nEntries, Curve ->Table16); - - cmsUNUSED_PARAMETER(nItems); - cmsUNUSED_PARAMETER(self); -} - - -static -void* Type_Curve_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - return (void*) cmsDupToneCurve((cmsToneCurve*) Ptr); - - cmsUNUSED_PARAMETER(n); - cmsUNUSED_PARAMETER(self); -} - -static -void Type_Curve_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - cmsToneCurve* gamma = (cmsToneCurve*) Ptr; - - cmsFreeToneCurve(gamma); - return; - - cmsUNUSED_PARAMETER(self); -} - - -// ******************************************************************************** -// Type cmsSigParametricCurveType -// ******************************************************************************** - - -// Decide which curve type to use on writting -static -cmsTagTypeSignature DecideCurveType(cmsFloat64Number ICCVersion, const void *Data) -{ - cmsToneCurve* Curve = (cmsToneCurve*) Data; - - if (ICCVersion < 4.0) return cmsSigCurveType; - if (Curve ->nSegments != 1) return cmsSigCurveType; // Only 1-segment curves can be saved as parametric - if (Curve ->Segments[0].Type < 0) return cmsSigCurveType; // Only non-inverted curves - if (Curve ->Segments[0].Type > 5) return cmsSigCurveType; // Only ICC parametric curves - - return cmsSigParametricCurveType; -} - -static -void *Type_ParametricCurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - static const int ParamsByType[] = { 1, 3, 4, 5, 7 }; - cmsFloat64Number Params[10]; - cmsUInt16Number Type; - int i, n; - cmsToneCurve* NewGamma; - - if (!_cmsReadUInt16Number(io, &Type)) return NULL; - if (!_cmsReadUInt16Number(io, NULL)) return NULL; // Reserved - - if (Type > 4) { - - cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown parametric curve type '%d'", Type); - return NULL; - } - - memset(Params, 0, sizeof(Params)); - n = ParamsByType[Type]; - - for (i=0; i < n; i++) { - - if (!_cmsRead15Fixed16Number(io, &Params[i])) return NULL; - } - - NewGamma = cmsBuildParametricToneCurve(self ->ContextID, Type+1, Params); - - *nItems = 1; - return NewGamma; - - cmsUNUSED_PARAMETER(SizeOfTag); -} - - -static -cmsBool Type_ParametricCurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsToneCurve* Curve = (cmsToneCurve*) Ptr; - int i, nParams, typen; - static const int ParamsByType[] = { 0, 1, 3, 4, 5, 7 }; - - typen = Curve -> Segments[0].Type; - - if (Curve ->nSegments > 1 || typen < 1) { - - cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Multisegment or Inverted parametric curves cannot be written"); - return FALSE; - } - - if (typen > 5) { - cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported parametric curve"); - return FALSE; - } - - nParams = ParamsByType[typen]; - - if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) (Curve ->Segments[0].Type - 1))) return FALSE; - if (!_cmsWriteUInt16Number(io, 0)) return FALSE; // Reserved - - for (i=0; i < nParams; i++) { - - if (!_cmsWrite15Fixed16Number(io, Curve -> Segments[0].Params[i])) return FALSE; - } - - return TRUE; - - cmsUNUSED_PARAMETER(nItems); -} - -static -void* Type_ParametricCurve_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - return (void*) cmsDupToneCurve((cmsToneCurve*) Ptr); - - cmsUNUSED_PARAMETER(n); - cmsUNUSED_PARAMETER(self); -} - -static -void Type_ParametricCurve_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - cmsToneCurve* gamma = (cmsToneCurve*) Ptr; - - cmsFreeToneCurve(gamma); - return; - - cmsUNUSED_PARAMETER(self); -} - - -// ******************************************************************************** -// Type cmsSigDateTimeType -// ******************************************************************************** - -// A 12-byte value representation of the time and date, where the byte usage is assigned -// as specified in table 1. The actual values are encoded as 16-bit unsigned integers -// (uInt16Number - see 5.1.6). -// -// All the dateTimeNumber values in a profile shall be in Coordinated Universal Time -// (UTC, also known as GMT or ZULU Time). Profile writers are required to convert local -// time to UTC when setting these values. Programmes that display these values may show -// the dateTimeNumber as UTC, show the equivalent local time (at current locale), or -// display both UTC and local versions of the dateTimeNumber. - -static -void *Type_DateTime_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsDateTimeNumber timestamp; - struct tm * NewDateTime; - - *nItems = 0; - NewDateTime = (struct tm*) _cmsMalloc(self ->ContextID, sizeof(struct tm)); - if (NewDateTime == NULL) return NULL; - - if (io->Read(io, ×tamp, sizeof(cmsDateTimeNumber), 1) != 1) return NULL; - - _cmsDecodeDateTimeNumber(×tamp, NewDateTime); - - *nItems = 1; - return NewDateTime; - - cmsUNUSED_PARAMETER(SizeOfTag); -} - - -static -cmsBool Type_DateTime_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - struct tm * DateTime = (struct tm*) Ptr; - cmsDateTimeNumber timestamp; - - _cmsEncodeDateTimeNumber(×tamp, DateTime); - if (!io ->Write(io, sizeof(cmsDateTimeNumber), ×tamp)) return FALSE; - - return TRUE; - - cmsUNUSED_PARAMETER(nItems); - cmsUNUSED_PARAMETER(self); -} - -static -void* Type_DateTime_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - return _cmsDupMem(self ->ContextID, Ptr, sizeof(struct tm)); - - cmsUNUSED_PARAMETER(n); -} - -static -void Type_DateTime_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - _cmsFree(self ->ContextID, Ptr); -} - - - -// ******************************************************************************** -// Type icMeasurementType -// ******************************************************************************** - -/* -The measurementType information refers only to the internal profile data and is -meant to provide profile makers an alternative to the default measurement -specifications. -*/ - -static -void *Type_Measurement_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsICCMeasurementConditions mc; - - - memset(&mc, 0, sizeof(mc)); - - if (!_cmsReadUInt32Number(io, &mc.Observer)) return NULL; - if (!_cmsReadXYZNumber(io, &mc.Backing)) return NULL; - if (!_cmsReadUInt32Number(io, &mc.Geometry)) return NULL; - if (!_cmsRead15Fixed16Number(io, &mc.Flare)) return NULL; - if (!_cmsReadUInt32Number(io, &mc.IlluminantType)) return NULL; - - *nItems = 1; - return _cmsDupMem(self ->ContextID, &mc, sizeof(cmsICCMeasurementConditions)); - - cmsUNUSED_PARAMETER(SizeOfTag); -} - - -static -cmsBool Type_Measurement_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsICCMeasurementConditions* mc =(cmsICCMeasurementConditions*) Ptr; - - if (!_cmsWriteUInt32Number(io, mc->Observer)) return FALSE; - if (!_cmsWriteXYZNumber(io, &mc->Backing)) return FALSE; - if (!_cmsWriteUInt32Number(io, mc->Geometry)) return FALSE; - if (!_cmsWrite15Fixed16Number(io, mc->Flare)) return FALSE; - if (!_cmsWriteUInt32Number(io, mc->IlluminantType)) return FALSE; - - return TRUE; - - cmsUNUSED_PARAMETER(nItems); - cmsUNUSED_PARAMETER(self); -} - -static -void* Type_Measurement_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsICCMeasurementConditions)); - - cmsUNUSED_PARAMETER(n); -} - -static -void Type_Measurement_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - _cmsFree(self ->ContextID, Ptr); -} - - -// ******************************************************************************** -// Type cmsSigMultiLocalizedUnicodeType -// ******************************************************************************** -// -// Do NOT trust SizeOfTag as there is an issue on the definition of profileSequenceDescTag. See the TechNote from -// Max Derhak and Rohit Patil about this: basically the size of the string table should be guessed and cannot be -// taken from the size of tag if this tag is embedded as part of bigger structures (profileSequenceDescTag, for instance) -// - -static -void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsMLU* mlu; - cmsUInt32Number Count, RecLen, NumOfWchar; - cmsUInt32Number SizeOfHeader; - cmsUInt32Number Len, Offset; - cmsUInt32Number i; - wchar_t* Block; - cmsUInt32Number BeginOfThisString, EndOfThisString, LargestPosition; - - *nItems = 0; - if (!_cmsReadUInt32Number(io, &Count)) return NULL; - if (!_cmsReadUInt32Number(io, &RecLen)) return NULL; - - if (RecLen != 12) { - - cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "multiLocalizedUnicodeType of len != 12 is not supported."); - return NULL; - } - - mlu = cmsMLUalloc(self ->ContextID, Count); - if (mlu == NULL) return NULL; - - mlu ->UsedEntries = Count; - - SizeOfHeader = 12 * Count + sizeof(_cmsTagBase); - LargestPosition = 0; - - for (i=0; i < Count; i++) { - - if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Language)) goto Error; - if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Country)) goto Error; - - // Now deal with Len and offset. - if (!_cmsReadUInt32Number(io, &Len)) goto Error; - if (!_cmsReadUInt32Number(io, &Offset)) goto Error; - - // Check for overflow - if (Offset < (SizeOfHeader + 8)) goto Error; - - // True begin of the string - BeginOfThisString = Offset - SizeOfHeader - 8; - - // Ajust to wchar_t elements - mlu ->Entries[i].Len = (Len * sizeof(wchar_t)) / sizeof(cmsUInt16Number); - mlu ->Entries[i].StrW = (BeginOfThisString * sizeof(wchar_t)) / sizeof(cmsUInt16Number); - - // To guess maximum size, add offset + len - EndOfThisString = BeginOfThisString + Len; - if (EndOfThisString > LargestPosition) - LargestPosition = EndOfThisString; - } - - // Now read the remaining of tag and fill all strings. Substract the directory - SizeOfTag = (LargestPosition * sizeof(wchar_t)) / sizeof(cmsUInt16Number); - if (SizeOfTag == 0) - { - Block = NULL; - NumOfWchar = 0; - - } - else - { - Block = (wchar_t*) _cmsMalloc(self ->ContextID, SizeOfTag); - if (Block == NULL) goto Error; - NumOfWchar = SizeOfTag / sizeof(wchar_t); - if (!_cmsReadWCharArray(io, NumOfWchar, Block)) goto Error; - } - - mlu ->MemPool = Block; - mlu ->PoolSize = SizeOfTag; - mlu ->PoolUsed = SizeOfTag; - - *nItems = 1; - return (void*) mlu; - -Error: - if (mlu) cmsMLUfree(mlu); - return NULL; -} - -static -cmsBool Type_MLU_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsMLU* mlu =(cmsMLU*) Ptr; - cmsUInt32Number HeaderSize; - cmsUInt32Number Len, Offset; - int i; - - if (Ptr == NULL) { - - // Empty placeholder - if (!_cmsWriteUInt32Number(io, 0)) return FALSE; - if (!_cmsWriteUInt32Number(io, 12)) return FALSE; - return TRUE; - } - - if (!_cmsWriteUInt32Number(io, mlu ->UsedEntries)) return FALSE; - if (!_cmsWriteUInt32Number(io, 12)) return FALSE; - - HeaderSize = 12 * mlu ->UsedEntries + sizeof(_cmsTagBase); - - for (i=0; i < mlu ->UsedEntries; i++) { - - Len = mlu ->Entries[i].Len; - Offset = mlu ->Entries[i].StrW; - - Len = (Len * sizeof(cmsUInt16Number)) / sizeof(wchar_t); - Offset = (Offset * sizeof(cmsUInt16Number)) / sizeof(wchar_t) + HeaderSize + 8; - - if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Language)) return FALSE; - if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Country)) return FALSE; - if (!_cmsWriteUInt32Number(io, Len)) return FALSE; - if (!_cmsWriteUInt32Number(io, Offset)) return FALSE; - } - - if (!_cmsWriteWCharArray(io, mlu ->PoolUsed / sizeof(wchar_t), (wchar_t*) mlu ->MemPool)) return FALSE; - - return TRUE; - - cmsUNUSED_PARAMETER(nItems); - cmsUNUSED_PARAMETER(self); -} - - -static -void* Type_MLU_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - return (void*) cmsMLUdup((cmsMLU*) Ptr); - - cmsUNUSED_PARAMETER(n); - cmsUNUSED_PARAMETER(self); -} - -static -void Type_MLU_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - cmsMLUfree((cmsMLU*) Ptr); - return; - - cmsUNUSED_PARAMETER(self); -} - - -// ******************************************************************************** -// Type cmsSigLut8Type -// ******************************************************************************** - -// Decide which LUT type to use on writting -static -cmsTagTypeSignature DecideLUTtypeA2B(cmsFloat64Number ICCVersion, const void *Data) -{ - cmsPipeline* Lut = (cmsPipeline*) Data; - - if (ICCVersion < 4.0) { - if (Lut ->SaveAs8Bits) return cmsSigLut8Type; - return cmsSigLut16Type; - } - else { - return cmsSigLutAtoBType; - } -} - -static -cmsTagTypeSignature DecideLUTtypeB2A(cmsFloat64Number ICCVersion, const void *Data) -{ - cmsPipeline* Lut = (cmsPipeline*) Data; - - if (ICCVersion < 4.0) { - if (Lut ->SaveAs8Bits) return cmsSigLut8Type; - return cmsSigLut16Type; - } - else { - return cmsSigLutBtoAType; - } -} - -/* -This structure represents a colour transform using tables of 8-bit precision. -This type contains four processing elements: a 3 by 3 matrix (which shall be -the identity matrix unless the input colour space is XYZ), a set of one dimensional -input tables, a multidimensional lookup table, and a set of one dimensional output -tables. Data is processed using these elements via the following sequence: -(matrix) -> (1d input tables) -> (multidimensional lookup table - CLUT) -> (1d output tables) - -Byte Position Field Length (bytes) Content Encoded as... -8 1 Number of Input Channels (i) uInt8Number -9 1 Number of Output Channels (o) uInt8Number -10 1 Number of CLUT grid points (identical for each side) (g) uInt8Number -11 1 Reserved for padding (fill with 00h) - -12..15 4 Encoded e00 parameter s15Fixed16Number -*/ - - -// Read 8 bit tables as gamma functions -static -cmsBool Read8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels) -{ - cmsUInt8Number* Temp = NULL; - int i, j; - cmsToneCurve* Tables[cmsMAXCHANNELS]; - - if (nChannels > cmsMAXCHANNELS) return FALSE; - if (nChannels <= 0) return FALSE; - - memset(Tables, 0, sizeof(Tables)); - - Temp = (cmsUInt8Number*) _cmsMalloc(ContextID, 256); - if (Temp == NULL) return FALSE; - - for (i=0; i < nChannels; i++) { - Tables[i] = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL); - if (Tables[i] == NULL) goto Error; - } - - for (i=0; i < nChannels; i++) { - - if (io ->Read(io, Temp, 256, 1) != 1) goto Error; - - for (j=0; j < 256; j++) - Tables[i]->Table16[j] = (cmsUInt16Number) FROM_8_TO_16(Temp[j]); - } - - _cmsFree(ContextID, Temp); - Temp = NULL; - - if (!cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, nChannels, Tables))) - goto Error; - - for (i=0; i < nChannels; i++) - cmsFreeToneCurve(Tables[i]); - - return TRUE; - -Error: - for (i=0; i < nChannels; i++) { - if (Tables[i]) cmsFreeToneCurve(Tables[i]); - } - - if (Temp) _cmsFree(ContextID, Temp); - return FALSE; -} - - -static -cmsBool Write8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsUInt32Number n, _cmsStageToneCurvesData* Tables) -{ - int j; - cmsUInt32Number i; - cmsUInt8Number val; - - for (i=0; i < n; i++) { - - if (Tables) { - - // Usual case of identity curves - if ((Tables ->TheCurves[i]->nEntries == 2) && - (Tables->TheCurves[i]->Table16[0] == 0) && - (Tables->TheCurves[i]->Table16[1] == 65535)) { - - for (j=0; j < 256; j++) { - if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) j)) return FALSE; - } - } - else - if (Tables ->TheCurves[i]->nEntries != 256) { - cmsSignalError(ContextID, cmsERROR_RANGE, "LUT8 needs 256 entries on prelinearization"); - return FALSE; - } - else - for (j=0; j < 256; j++) { - - if (Tables != NULL) - val = (cmsUInt8Number) FROM_16_TO_8(Tables->TheCurves[i]->Table16[j]); - else - val = (cmsUInt8Number) j; - - if (!_cmsWriteUInt8Number(io, val)) return FALSE; - } - } - } - return TRUE; -} - - -// Check overflow -static -cmsUInt32Number uipow(cmsUInt32Number n, cmsUInt32Number a, cmsUInt32Number b) -{ - cmsUInt32Number rv = 1, rc; - - if (a == 0) return 0; - if (n == 0) return 0; - - for (; b > 0; b--) { - - rv *= a; - - // Check for overflow - if (rv > UINT_MAX / a) return (cmsUInt32Number) -1; - - } - - rc = rv * n; - - if (rv != rc / n) return (cmsUInt32Number) -1; - return rc; -} - - -// That will create a MPE LUT with Matrix, pre tables, CLUT and post tables. -// 8 bit lut may be scaled easely to v4 PCS, but we need also to properly adjust -// PCS on BToAxx tags and AtoB if abstract. We need to fix input direction. - -static -void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsUInt8Number InputChannels, OutputChannels, CLUTpoints; - cmsUInt8Number* Temp = NULL; - cmsPipeline* NewLUT = NULL; - cmsUInt32Number nTabSize, i; - cmsFloat64Number Matrix[3*3]; - - *nItems = 0; - - if (!_cmsReadUInt8Number(io, &InputChannels)) goto Error; - if (!_cmsReadUInt8Number(io, &OutputChannels)) goto Error; - if (!_cmsReadUInt8Number(io, &CLUTpoints)) goto Error; - - if (CLUTpoints == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least - - // Padding - if (!_cmsReadUInt8Number(io, NULL)) goto Error; - - // Do some checking - if (InputChannels == 0 || InputChannels > cmsMAXCHANNELS) goto Error; - if (OutputChannels == 0 || OutputChannels > cmsMAXCHANNELS) goto Error; - - // Allocates an empty Pipeline - NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels); - if (NewLUT == NULL) goto Error; - - // Read the Matrix - if (!_cmsRead15Fixed16Number(io, &Matrix[0])) goto Error; - if (!_cmsRead15Fixed16Number(io, &Matrix[1])) goto Error; - if (!_cmsRead15Fixed16Number(io, &Matrix[2])) goto Error; - if (!_cmsRead15Fixed16Number(io, &Matrix[3])) goto Error; - if (!_cmsRead15Fixed16Number(io, &Matrix[4])) goto Error; - if (!_cmsRead15Fixed16Number(io, &Matrix[5])) goto Error; - if (!_cmsRead15Fixed16Number(io, &Matrix[6])) goto Error; - if (!_cmsRead15Fixed16Number(io, &Matrix[7])) goto Error; - if (!_cmsRead15Fixed16Number(io, &Matrix[8])) goto Error; - - - // Only operates if not identity... - if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) { - - if (!cmsPipelineInsertStage(NewLUT, cmsAT_BEGIN, cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL))) - goto Error; - } - - // Get input tables - if (!Read8bitTables(self ->ContextID, io, NewLUT, InputChannels)) goto Error; - - // Get 3D CLUT. Check the overflow.... - nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels); - if (nTabSize == (cmsUInt32Number) -1) goto Error; - if (nTabSize > 0) { - - cmsUInt16Number *PtrW, *T; - - PtrW = T = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number)); - if (T == NULL) goto Error; - - Temp = (cmsUInt8Number*) _cmsMalloc(self ->ContextID, nTabSize); - if (Temp == NULL) { - _cmsFree(self ->ContextID, T); - goto Error; - } - - if (io ->Read(io, Temp, nTabSize, 1) != 1) { - _cmsFree(self ->ContextID, T); - _cmsFree(self ->ContextID, Temp); - goto Error; - } - - for (i = 0; i < nTabSize; i++) { - - *PtrW++ = FROM_8_TO_16(Temp[i]); - } - _cmsFree(self ->ContextID, Temp); - Temp = NULL; - - if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T))) - goto Error; - _cmsFree(self ->ContextID, T); - } - - - // Get output tables - if (!Read8bitTables(self ->ContextID, io, NewLUT, OutputChannels)) goto Error; - - *nItems = 1; - return NewLUT; - -Error: - if (NewLUT != NULL) cmsPipelineFree(NewLUT); - return NULL; - - cmsUNUSED_PARAMETER(SizeOfTag); -} - -// We only allow a specific MPE structure: Matrix plus prelin, plus clut, plus post-lin. -static -cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsUInt32Number j, nTabSize; - cmsUInt8Number val; - cmsPipeline* NewLUT = (cmsPipeline*) Ptr; - cmsStage* mpe; - _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL; - _cmsStageMatrixData* MatMPE = NULL; - _cmsStageCLutData* clut = NULL; - int clutPoints; - - // Disassemble the LUT into components. - mpe = NewLUT -> Elements; - if (mpe ->Type == cmsSigMatrixElemType) { - - MatMPE = (_cmsStageMatrixData*) mpe ->Data; - mpe = mpe -> Next; - } - - if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) { - PreMPE = (_cmsStageToneCurvesData*) mpe ->Data; - mpe = mpe -> Next; - } - - if (mpe != NULL && mpe ->Type == cmsSigCLutElemType) { - clut = (_cmsStageCLutData*) mpe -> Data; - mpe = mpe ->Next; - } - - if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) { - PostMPE = (_cmsStageToneCurvesData*) mpe ->Data; - mpe = mpe -> Next; - } - - // That should be all - if (mpe != NULL) { - cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT8"); - return FALSE; - } - - - if (clut == NULL) - clutPoints = 0; - else - clutPoints = clut->Params->nSamples[0]; - - if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->InputChannels)) return FALSE; - if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->OutputChannels)) return FALSE; - if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE; - if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding - - - if (MatMPE != NULL) { - - if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[0])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[1])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[2])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[3])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[4])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[5])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[6])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[7])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[8])) return FALSE; - - } - else { - - if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; - if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; - if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; - if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; - if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; - if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; - if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; - if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; - if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; - } - - // The prelinearization table - if (!Write8bitTables(self ->ContextID, io, NewLUT ->InputChannels, PreMPE)) return FALSE; - - nTabSize = uipow(NewLUT->OutputChannels, clutPoints, NewLUT ->InputChannels); - if (nTabSize == (cmsUInt32Number) -1) return FALSE; - if (nTabSize > 0) { - - // The 3D CLUT. - if (clut != NULL) { - - for (j=0; j < nTabSize; j++) { - - val = (cmsUInt8Number) FROM_16_TO_8(clut ->Tab.T[j]); - if (!_cmsWriteUInt8Number(io, val)) return FALSE; - } - } - } - - // The postlinearization table - if (!Write8bitTables(self ->ContextID, io, NewLUT ->OutputChannels, PostMPE)) return FALSE; - - return TRUE; - - cmsUNUSED_PARAMETER(nItems); -} - - -static -void* Type_LUT8_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - return (void*) cmsPipelineDup((cmsPipeline*) Ptr); - - cmsUNUSED_PARAMETER(n); - cmsUNUSED_PARAMETER(self); -} - -static -void Type_LUT8_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - cmsPipelineFree((cmsPipeline*) Ptr); - return; - - cmsUNUSED_PARAMETER(self); -} - -// ******************************************************************************** -// Type cmsSigLut16Type -// ******************************************************************************** - -// Read 16 bit tables as gamma functions -static -cmsBool Read16bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels, int nEntries) -{ - int i; - cmsToneCurve* Tables[cmsMAXCHANNELS]; - - // Maybe an empty table? (this is a lcms extension) - if (nEntries <= 0) return TRUE; - - // Check for malicious profiles - if (nEntries < 2) return FALSE; - if (nChannels > cmsMAXCHANNELS) return FALSE; - - // Init table to zero - memset(Tables, 0, sizeof(Tables)); - - for (i=0; i < nChannels; i++) { - - Tables[i] = cmsBuildTabulatedToneCurve16(ContextID, nEntries, NULL); - if (Tables[i] == NULL) goto Error; - - if (!_cmsReadUInt16Array(io, nEntries, Tables[i]->Table16)) goto Error; - } - - - // Add the table (which may certainly be an identity, but this is up to the optimizer, not the reading code) - if (!cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, nChannels, Tables))) - goto Error; - - for (i=0; i < nChannels; i++) - cmsFreeToneCurve(Tables[i]); - - return TRUE; - -Error: - for (i=0; i < nChannels; i++) { - if (Tables[i]) cmsFreeToneCurve(Tables[i]); - } - - return FALSE; -} - -static -cmsBool Write16bitTables(cmsContext ContextID, cmsIOHANDLER* io, _cmsStageToneCurvesData* Tables) -{ - int j; - cmsUInt32Number i; - cmsUInt16Number val; - int nEntries; - - _cmsAssert(Tables != NULL); - - nEntries = Tables->TheCurves[0]->nEntries; - - for (i=0; i < Tables ->nCurves; i++) { - - for (j=0; j < nEntries; j++) { - - val = Tables->TheCurves[i]->Table16[j]; - if (!_cmsWriteUInt16Number(io, val)) return FALSE; - } - } - return TRUE; - - cmsUNUSED_PARAMETER(ContextID); -} - -static -void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsUInt8Number InputChannels, OutputChannels, CLUTpoints; - cmsPipeline* NewLUT = NULL; - cmsUInt32Number nTabSize; - cmsFloat64Number Matrix[3*3]; - cmsUInt16Number InputEntries, OutputEntries; - - *nItems = 0; - - if (!_cmsReadUInt8Number(io, &InputChannels)) return NULL; - if (!_cmsReadUInt8Number(io, &OutputChannels)) return NULL; - if (!_cmsReadUInt8Number(io, &CLUTpoints)) return NULL; // 255 maximum - - // Padding - if (!_cmsReadUInt8Number(io, NULL)) return NULL; - - // Do some checking - if (InputChannels == 0 || InputChannels > cmsMAXCHANNELS) goto Error; - if (OutputChannels == 0 || OutputChannels > cmsMAXCHANNELS) goto Error; - - // Allocates an empty LUT - NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels); - if (NewLUT == NULL) goto Error; - - // Read the Matrix - if (!_cmsRead15Fixed16Number(io, &Matrix[0])) goto Error; - if (!_cmsRead15Fixed16Number(io, &Matrix[1])) goto Error; - if (!_cmsRead15Fixed16Number(io, &Matrix[2])) goto Error; - if (!_cmsRead15Fixed16Number(io, &Matrix[3])) goto Error; - if (!_cmsRead15Fixed16Number(io, &Matrix[4])) goto Error; - if (!_cmsRead15Fixed16Number(io, &Matrix[5])) goto Error; - if (!_cmsRead15Fixed16Number(io, &Matrix[6])) goto Error; - if (!_cmsRead15Fixed16Number(io, &Matrix[7])) goto Error; - if (!_cmsRead15Fixed16Number(io, &Matrix[8])) goto Error; - - - // Only operates on 3 channels - if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) { - - if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL))) - goto Error; - } - - if (!_cmsReadUInt16Number(io, &InputEntries)) goto Error; - if (!_cmsReadUInt16Number(io, &OutputEntries)) goto Error; - - if (InputEntries > 0x7FFF || OutputEntries > 0x7FFF) goto Error; - if (CLUTpoints == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least - - // Get input tables - if (!Read16bitTables(self ->ContextID, io, NewLUT, InputChannels, InputEntries)) goto Error; - - // Get 3D CLUT - nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels); - if (nTabSize == (cmsUInt32Number) -1) goto Error; - if (nTabSize > 0) { - - cmsUInt16Number *T; - - T = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number)); - if (T == NULL) goto Error; - - if (!_cmsReadUInt16Array(io, nTabSize, T)) { - _cmsFree(self ->ContextID, T); - goto Error; - } - - if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T))) { - _cmsFree(self ->ContextID, T); - goto Error; - } - _cmsFree(self ->ContextID, T); - } - - - // Get output tables - if (!Read16bitTables(self ->ContextID, io, NewLUT, OutputChannels, OutputEntries)) goto Error; - - *nItems = 1; - return NewLUT; - -Error: - if (NewLUT != NULL) cmsPipelineFree(NewLUT); - return NULL; - - cmsUNUSED_PARAMETER(SizeOfTag); -} - -// We only allow some specific MPE structures: Matrix plus prelin, plus clut, plus post-lin. -// Some empty defaults are created for missing parts - -static -cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsUInt32Number nTabSize; - cmsPipeline* NewLUT = (cmsPipeline*) Ptr; - cmsStage* mpe; - _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL; - _cmsStageMatrixData* MatMPE = NULL; - _cmsStageCLutData* clut = NULL; - int i, InputChannels, OutputChannels, clutPoints; - - // Disassemble the LUT into components. - mpe = NewLUT -> Elements; - if (mpe != NULL && mpe ->Type == cmsSigMatrixElemType) { - - MatMPE = (_cmsStageMatrixData*) mpe ->Data; - mpe = mpe -> Next; - } - - - if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) { - PreMPE = (_cmsStageToneCurvesData*) mpe ->Data; - mpe = mpe -> Next; - } - - if (mpe != NULL && mpe ->Type == cmsSigCLutElemType) { - clut = (_cmsStageCLutData*) mpe -> Data; - mpe = mpe ->Next; - } - - if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) { - PostMPE = (_cmsStageToneCurvesData*) mpe ->Data; - mpe = mpe -> Next; - } - - // That should be all - if (mpe != NULL) { - cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT16"); - return FALSE; - } - - InputChannels = cmsPipelineInputChannels(NewLUT); - OutputChannels = cmsPipelineOutputChannels(NewLUT); - - if (clut == NULL) - clutPoints = 0; - else - clutPoints = clut->Params->nSamples[0]; - - if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) InputChannels)) return FALSE; - if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) OutputChannels)) return FALSE; - if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE; - if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding - - - if (MatMPE != NULL) { - - if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[0])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[1])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[2])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[3])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[4])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[5])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[6])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[7])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[8])) return FALSE; - } - else { - - if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; - if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; - if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; - if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; - if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; - if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; - if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; - if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; - if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; - } - - - if (PreMPE != NULL) { - if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PreMPE ->TheCurves[0]->nEntries)) return FALSE; - } else { - if (!_cmsWriteUInt16Number(io, 2)) return FALSE; - } - - if (PostMPE != NULL) { - if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PostMPE ->TheCurves[0]->nEntries)) return FALSE; - } else { - if (!_cmsWriteUInt16Number(io, 2)) return FALSE; - - } - - // The prelinearization table - - if (PreMPE != NULL) { - if (!Write16bitTables(self ->ContextID, io, PreMPE)) return FALSE; - } - else { - for (i=0; i < InputChannels; i++) { - - if (!_cmsWriteUInt16Number(io, 0)) return FALSE; - if (!_cmsWriteUInt16Number(io, 0xffff)) return FALSE; - } - } - - nTabSize = uipow(OutputChannels, clutPoints, InputChannels); - if (nTabSize == (cmsUInt32Number) -1) return FALSE; - if (nTabSize > 0) { - // The 3D CLUT. - if (clut != NULL) { - if (!_cmsWriteUInt16Array(io, nTabSize, clut->Tab.T)) return FALSE; - } - } - - // The postlinearization table - if (PostMPE != NULL) { - if (!Write16bitTables(self ->ContextID, io, PostMPE)) return FALSE; - } - else { - for (i=0; i < OutputChannels; i++) { - - if (!_cmsWriteUInt16Number(io, 0)) return FALSE; - if (!_cmsWriteUInt16Number(io, 0xffff)) return FALSE; - } - } - - return TRUE; - - cmsUNUSED_PARAMETER(nItems); -} - -static -void* Type_LUT16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - return (void*) cmsPipelineDup((cmsPipeline*) Ptr); - - cmsUNUSED_PARAMETER(n); - cmsUNUSED_PARAMETER(self); -} - -static -void Type_LUT16_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - cmsPipelineFree((cmsPipeline*) Ptr); - return; - - cmsUNUSED_PARAMETER(self); -} - - -// ******************************************************************************** -// Type cmsSigLutAToBType -// ******************************************************************************** - - -// V4 stuff. Read matrix for LutAtoB and LutBtoA - -static -cmsStage* ReadMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset) -{ - cmsFloat64Number dMat[3*3]; - cmsFloat64Number dOff[3]; - cmsStage* Mat; - - // Go to address - if (!io -> Seek(io, Offset)) return NULL; - - // Read the Matrix - if (!_cmsRead15Fixed16Number(io, &dMat[0])) return NULL; - if (!_cmsRead15Fixed16Number(io, &dMat[1])) return NULL; - if (!_cmsRead15Fixed16Number(io, &dMat[2])) return NULL; - if (!_cmsRead15Fixed16Number(io, &dMat[3])) return NULL; - if (!_cmsRead15Fixed16Number(io, &dMat[4])) return NULL; - if (!_cmsRead15Fixed16Number(io, &dMat[5])) return NULL; - if (!_cmsRead15Fixed16Number(io, &dMat[6])) return NULL; - if (!_cmsRead15Fixed16Number(io, &dMat[7])) return NULL; - if (!_cmsRead15Fixed16Number(io, &dMat[8])) return NULL; - - if (!_cmsRead15Fixed16Number(io, &dOff[0])) return NULL; - if (!_cmsRead15Fixed16Number(io, &dOff[1])) return NULL; - if (!_cmsRead15Fixed16Number(io, &dOff[2])) return NULL; - - Mat = cmsStageAllocMatrix(self ->ContextID, 3, 3, dMat, dOff); - - return Mat; -} - - - - -// V4 stuff. Read CLUT part for LutAtoB and LutBtoA - -static -cmsStage* ReadCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, int InputChannels, int OutputChannels) -{ - cmsUInt8Number gridPoints8[cmsMAXCHANNELS]; // Number of grid points in each dimension. - cmsUInt32Number GridPoints[cmsMAXCHANNELS], i; - cmsUInt8Number Precision; - cmsStage* CLUT; - _cmsStageCLutData* Data; - - if (!io -> Seek(io, Offset)) return NULL; - if (io -> Read(io, gridPoints8, cmsMAXCHANNELS, 1) != 1) return NULL; - - - for (i=0; i < cmsMAXCHANNELS; i++) { - - if (gridPoints8[i] == 1) return NULL; // Impossible value, 0 for no CLUT and then 2 at least - GridPoints[i] = gridPoints8[i]; - } - - if (!_cmsReadUInt8Number(io, &Precision)) return NULL; - - if (!_cmsReadUInt8Number(io, NULL)) return NULL; - if (!_cmsReadUInt8Number(io, NULL)) return NULL; - if (!_cmsReadUInt8Number(io, NULL)) return NULL; - - CLUT = cmsStageAllocCLut16bitGranular(self ->ContextID, GridPoints, InputChannels, OutputChannels, NULL); - if (CLUT == NULL) return NULL; - - Data = (_cmsStageCLutData*) CLUT ->Data; - - // Precision can be 1 or 2 bytes - if (Precision == 1) { - - cmsUInt8Number v; - - for (i=0; i < Data ->nEntries; i++) { - - if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) { - cmsStageFree(CLUT); - return NULL; - } - Data ->Tab.T[i] = FROM_8_TO_16(v); - } - - } - else - if (Precision == 2) { - - if (!_cmsReadUInt16Array(io, Data->nEntries, Data ->Tab.T)) { - cmsStageFree(CLUT); - return NULL; - } - } - else { - cmsStageFree(CLUT); - cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision); - return NULL; - } - - return CLUT; -} - -static -cmsToneCurve* ReadEmbeddedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io) -{ - cmsTagTypeSignature BaseType; - cmsUInt32Number nItems; - - BaseType = _cmsReadTypeBase(io); - switch (BaseType) { - - case cmsSigCurveType: - return (cmsToneCurve*) Type_Curve_Read(self, io, &nItems, 0); - - case cmsSigParametricCurveType: - return (cmsToneCurve*) Type_ParametricCurve_Read(self, io, &nItems, 0); - - default: - { - char String[5]; - - _cmsTagSignature2String(String, (cmsTagSignature) BaseType); - cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String); - } - return NULL; - } -} - - -// Read a set of curves from specific offset -static -cmsStage* ReadSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, cmsUInt32Number nCurves) -{ - cmsToneCurve* Curves[cmsMAXCHANNELS]; - cmsUInt32Number i; - cmsStage* Lin = NULL; - - if (nCurves > cmsMAXCHANNELS) return FALSE; - - if (!io -> Seek(io, Offset)) return FALSE; - - for (i=0; i < nCurves; i++) - Curves[i] = NULL; - - for (i=0; i < nCurves; i++) { - - Curves[i] = ReadEmbeddedCurve(self, io); - if (Curves[i] == NULL) goto Error; - if (!_cmsReadAlignment(io)) goto Error; - - } - - Lin = cmsStageAllocToneCurves(self ->ContextID, nCurves, Curves); - -Error: - for (i=0; i < nCurves; i++) - cmsFreeToneCurve(Curves[i]); - - return Lin; -} - - -// LutAtoB type - -// This structure represents a colour transform. The type contains up to five processing -// elements which are stored in the AtoBTag tag in the following order: a set of one -// dimensional curves, a 3 by 3 matrix with offset terms, a set of one dimensional curves, -// a multidimensional lookup table, and a set of one dimensional output curves. -// Data are processed using these elements via the following sequence: -// -//("A" curves) -> (multidimensional lookup table - CLUT) -> ("M" curves) -> (matrix) -> ("B" curves). -// -/* -It is possible to use any or all of these processing elements. At least one processing element -must be included.Only the following combinations are allowed: - -B -M - Matrix - B -A - CLUT - B -A - CLUT - M - Matrix - B - -*/ - -static -void* Type_LUTA2B_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsUInt32Number BaseOffset; - cmsUInt8Number inputChan; // Number of input channels - cmsUInt8Number outputChan; // Number of output channels - cmsUInt32Number offsetB; // Offset to first "B" curve - cmsUInt32Number offsetMat; // Offset to matrix - cmsUInt32Number offsetM; // Offset to first "M" curve - cmsUInt32Number offsetC; // Offset to CLUT - cmsUInt32Number offsetA; // Offset to first "A" curve - cmsPipeline* NewLUT = NULL; - - - BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); - - if (!_cmsReadUInt8Number(io, &inputChan)) return NULL; - if (!_cmsReadUInt8Number(io, &outputChan)) return NULL; - - if (!_cmsReadUInt16Number(io, NULL)) return NULL; - - if (!_cmsReadUInt32Number(io, &offsetB)) return NULL; - if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL; - if (!_cmsReadUInt32Number(io, &offsetM)) return NULL; - if (!_cmsReadUInt32Number(io, &offsetC)) return NULL; - if (!_cmsReadUInt32Number(io, &offsetA)) return NULL; - - if (inputChan == 0 || inputChan >= cmsMAXCHANNELS) return NULL; - if (outputChan == 0 || outputChan >= cmsMAXCHANNELS) return NULL; - - // Allocates an empty LUT - NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan); - if (NewLUT == NULL) return NULL; - - if (offsetA!= 0) { - if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, inputChan))) - goto Error; - } - - if (offsetC != 0) { - if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan))) - goto Error; - } - - if (offsetM != 0) { - if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, outputChan))) - goto Error; - } - - if (offsetMat != 0) { - if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat))) - goto Error; - } - - if (offsetB != 0) { - if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, outputChan))) - goto Error; - } - - *nItems = 1; - return NewLUT; -Error: - cmsPipelineFree(NewLUT); - return NULL; - - cmsUNUSED_PARAMETER(SizeOfTag); -} - -// Write a set of curves -static -cmsBool WriteMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsStage* mpe) -{ - _cmsStageMatrixData* m = (_cmsStageMatrixData*) mpe -> Data; - - // Write the Matrix - if (!_cmsWrite15Fixed16Number(io, m -> Double[0])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, m -> Double[1])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, m -> Double[2])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, m -> Double[3])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, m -> Double[4])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, m -> Double[5])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, m -> Double[6])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, m -> Double[7])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, m -> Double[8])) return FALSE; - - if (m ->Offset != NULL) { - - if (!_cmsWrite15Fixed16Number(io, m -> Offset[0])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, m -> Offset[1])) return FALSE; - if (!_cmsWrite15Fixed16Number(io, m -> Offset[2])) return FALSE; - } - else { - if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; - if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; - if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; - - } - - - return TRUE; - - cmsUNUSED_PARAMETER(self); -} - - -// Write a set of curves -static -cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsTagTypeSignature Type, cmsStage* mpe) -{ - cmsUInt32Number i, n; - cmsTagTypeSignature CurrentType; - cmsToneCurve** Curves; - - - n = cmsStageOutputChannels(mpe); - Curves = _cmsStageGetPtrToCurveSet(mpe); - - for (i=0; i < n; i++) { - - // If this is a table-based curve, use curve type even on V4 - CurrentType = Type; - - if ((Curves[i] ->nSegments == 0)|| - ((Curves[i]->nSegments == 2) && (Curves[i] ->Segments[1].Type == 0)) ) - CurrentType = cmsSigCurveType; - else - if (Curves[i] ->Segments[0].Type < 0) - CurrentType = cmsSigCurveType; - - if (!_cmsWriteTypeBase(io, CurrentType)) return FALSE; - - switch (CurrentType) { - - case cmsSigCurveType: - if (!Type_Curve_Write(self, io, Curves[i], 1)) return FALSE; - break; - - case cmsSigParametricCurveType: - if (!Type_ParametricCurve_Write(self, io, Curves[i], 1)) return FALSE; - break; - - default: - { - char String[5]; - - _cmsTagSignature2String(String, (cmsTagSignature) Type); - cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String); - } - return FALSE; - } - - if (!_cmsWriteAlignment(io)) return FALSE; - } - - - return TRUE; -} - - -static -cmsBool WriteCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt8Number Precision, cmsStage* mpe) -{ - cmsUInt8Number gridPoints[cmsMAXCHANNELS]; // Number of grid points in each dimension. - cmsUInt32Number i; - _cmsStageCLutData* CLUT = ( _cmsStageCLutData*) mpe -> Data; - - if (CLUT ->HasFloatValues) { - cmsSignalError(self ->ContextID, cmsERROR_NOT_SUITABLE, "Cannot save floating point data, CLUT are 8 or 16 bit only"); - return FALSE; - } - - memset(gridPoints, 0, sizeof(gridPoints)); - for (i=0; i < (cmsUInt32Number) CLUT ->Params ->nInputs; i++) - gridPoints[i] = (cmsUInt8Number) CLUT ->Params ->nSamples[i]; - - if (!io -> Write(io, cmsMAXCHANNELS*sizeof(cmsUInt8Number), gridPoints)) return FALSE; - - if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) Precision)) return FALSE; - if (!_cmsWriteUInt8Number(io, 0)) return FALSE; - if (!_cmsWriteUInt8Number(io, 0)) return FALSE; - if (!_cmsWriteUInt8Number(io, 0)) return FALSE; - - // Precision can be 1 or 2 bytes - if (Precision == 1) { - - for (i=0; i < CLUT->nEntries; i++) { - - if (!_cmsWriteUInt8Number(io, FROM_16_TO_8(CLUT->Tab.T[i]))) return FALSE; - } - } - else - if (Precision == 2) { - - if (!_cmsWriteUInt16Array(io, CLUT->nEntries, CLUT ->Tab.T)) return FALSE; - } - else { - cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision); - return FALSE; - } - - if (!_cmsWriteAlignment(io)) return FALSE; - - return TRUE; -} - - - - -static -cmsBool Type_LUTA2B_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsPipeline* Lut = (cmsPipeline*) Ptr; - int inputChan, outputChan; - cmsStage *A = NULL, *B = NULL, *M = NULL; - cmsStage * Matrix = NULL; - cmsStage * CLUT = NULL; - cmsUInt32Number offsetB = 0, offsetMat = 0, offsetM = 0, offsetC = 0, offsetA = 0; - cmsUInt32Number BaseOffset, DirectoryPos, CurrentPos; - - // Get the base for all offsets - BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); - - if (Lut ->Elements != NULL) - if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCurveSetElemType, &B)) - if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &M, &Matrix, &B)) - if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &A, &CLUT, &B)) - if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, - cmsSigMatrixElemType, cmsSigCurveSetElemType, &A, &CLUT, &M, &Matrix, &B)) { - - cmsSignalError(self->ContextID, cmsERROR_NOT_SUITABLE, "LUT is not suitable to be saved as LutAToB"); - return FALSE; - } - - // Get input, output channels - inputChan = cmsPipelineInputChannels(Lut); - outputChan = cmsPipelineOutputChannels(Lut); - - // Write channel count - if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) inputChan)) return FALSE; - if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) outputChan)) return FALSE; - if (!_cmsWriteUInt16Number(io, 0)) return FALSE; - - // Keep directory to be filled latter - DirectoryPos = io ->Tell(io); - - // Write the directory - if (!_cmsWriteUInt32Number(io, 0)) return FALSE; - if (!_cmsWriteUInt32Number(io, 0)) return FALSE; - if (!_cmsWriteUInt32Number(io, 0)) return FALSE; - if (!_cmsWriteUInt32Number(io, 0)) return FALSE; - if (!_cmsWriteUInt32Number(io, 0)) return FALSE; - - if (A != NULL) { - - offsetA = io ->Tell(io) - BaseOffset; - if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, A)) return FALSE; - } - - if (CLUT != NULL) { - offsetC = io ->Tell(io) - BaseOffset; - if (!WriteCLUT(self, io, Lut ->SaveAs8Bits ? 1 : 2, CLUT)) return FALSE; - - } - if (M != NULL) { - - offsetM = io ->Tell(io) - BaseOffset; - if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, M)) return FALSE; - } - - if (Matrix != NULL) { - offsetMat = io ->Tell(io) - BaseOffset; - if (!WriteMatrix(self, io, Matrix)) return FALSE; - } - - if (B != NULL) { - - offsetB = io ->Tell(io) - BaseOffset; - if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE; - } - - CurrentPos = io ->Tell(io); - - if (!io ->Seek(io, DirectoryPos)) return FALSE; - - if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE; - if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE; - if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE; - if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE; - if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE; - - if (!io ->Seek(io, CurrentPos)) return FALSE; - - return TRUE; - - cmsUNUSED_PARAMETER(nItems); -} - - -static -void* Type_LUTA2B_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - return (void*) cmsPipelineDup((cmsPipeline*) Ptr); - - cmsUNUSED_PARAMETER(n); - cmsUNUSED_PARAMETER(self); -} - -static -void Type_LUTA2B_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - cmsPipelineFree((cmsPipeline*) Ptr); - return; - - cmsUNUSED_PARAMETER(self); -} - - -// LutBToA type - -static -void* Type_LUTB2A_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsUInt8Number inputChan; // Number of input channels - cmsUInt8Number outputChan; // Number of output channels - cmsUInt32Number BaseOffset; // Actual position in file - cmsUInt32Number offsetB; // Offset to first "B" curve - cmsUInt32Number offsetMat; // Offset to matrix - cmsUInt32Number offsetM; // Offset to first "M" curve - cmsUInt32Number offsetC; // Offset to CLUT - cmsUInt32Number offsetA; // Offset to first "A" curve - cmsPipeline* NewLUT = NULL; - - - BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); - - if (!_cmsReadUInt8Number(io, &inputChan)) return NULL; - if (!_cmsReadUInt8Number(io, &outputChan)) return NULL; - - if (inputChan == 0 || inputChan >= cmsMAXCHANNELS) return NULL; - if (outputChan == 0 || outputChan >= cmsMAXCHANNELS) return NULL; - - // Padding - if (!_cmsReadUInt16Number(io, NULL)) return NULL; - - if (!_cmsReadUInt32Number(io, &offsetB)) return NULL; - if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL; - if (!_cmsReadUInt32Number(io, &offsetM)) return NULL; - if (!_cmsReadUInt32Number(io, &offsetC)) return NULL; - if (!_cmsReadUInt32Number(io, &offsetA)) return NULL; - - // Allocates an empty LUT - NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan); - if (NewLUT == NULL) return NULL; - - if (offsetB != 0) { - if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, inputChan))) - goto Error; - } - - if (offsetMat != 0) { - if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat))) - goto Error; - } - - if (offsetM != 0) { - if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, inputChan))) - goto Error; - } - - if (offsetC != 0) { - if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan))) - goto Error; - } - - if (offsetA!= 0) { - if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, outputChan))) - goto Error; - } - - *nItems = 1; - return NewLUT; -Error: - cmsPipelineFree(NewLUT); - return NULL; - - cmsUNUSED_PARAMETER(SizeOfTag); -} - - -/* -B -B - Matrix - M -B - CLUT - A -B - Matrix - M - CLUT - A -*/ - -static -cmsBool Type_LUTB2A_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsPipeline* Lut = (cmsPipeline*) Ptr; - int inputChan, outputChan; - cmsStage *A = NULL, *B = NULL, *M = NULL; - cmsStage *Matrix = NULL; - cmsStage *CLUT = NULL; - cmsUInt32Number offsetB = 0, offsetMat = 0, offsetM = 0, offsetC = 0, offsetA = 0; - cmsUInt32Number BaseOffset, DirectoryPos, CurrentPos; - - - BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); - - if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCurveSetElemType, &B)) - if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &B, &Matrix, &M)) - if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &CLUT, &A)) - if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, - cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &Matrix, &M, &CLUT, &A)) { - cmsSignalError(self->ContextID, cmsERROR_NOT_SUITABLE, "LUT is not suitable to be saved as LutBToA"); - return FALSE; - } - - inputChan = cmsPipelineInputChannels(Lut); - outputChan = cmsPipelineOutputChannels(Lut); - - if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) inputChan)) return FALSE; - if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) outputChan)) return FALSE; - if (!_cmsWriteUInt16Number(io, 0)) return FALSE; - - DirectoryPos = io ->Tell(io); - - if (!_cmsWriteUInt32Number(io, 0)) return FALSE; - if (!_cmsWriteUInt32Number(io, 0)) return FALSE; - if (!_cmsWriteUInt32Number(io, 0)) return FALSE; - if (!_cmsWriteUInt32Number(io, 0)) return FALSE; - if (!_cmsWriteUInt32Number(io, 0)) return FALSE; - - if (A != NULL) { - - offsetA = io ->Tell(io) - BaseOffset; - if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, A)) return FALSE; - } - - if (CLUT != NULL) { - offsetC = io ->Tell(io) - BaseOffset; - if (!WriteCLUT(self, io, Lut ->SaveAs8Bits ? 1 : 2, CLUT)) return FALSE; - - } - if (M != NULL) { - - offsetM = io ->Tell(io) - BaseOffset; - if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, M)) return FALSE; - } - - if (Matrix != NULL) { - offsetMat = io ->Tell(io) - BaseOffset; - if (!WriteMatrix(self, io, Matrix)) return FALSE; - } - - if (B != NULL) { - - offsetB = io ->Tell(io) - BaseOffset; - if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE; - } - - CurrentPos = io ->Tell(io); - - if (!io ->Seek(io, DirectoryPos)) return FALSE; - - if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE; - if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE; - if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE; - if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE; - if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE; - - if (!io ->Seek(io, CurrentPos)) return FALSE; - - return TRUE; - - cmsUNUSED_PARAMETER(nItems); -} - - - -static -void* Type_LUTB2A_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - return (void*) cmsPipelineDup((cmsPipeline*) Ptr); - - cmsUNUSED_PARAMETER(n); - cmsUNUSED_PARAMETER(self); -} - -static -void Type_LUTB2A_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - cmsPipelineFree((cmsPipeline*) Ptr); - return; - - cmsUNUSED_PARAMETER(self); -} - - - -// ******************************************************************************** -// Type cmsSigColorantTableType -// ******************************************************************************** -/* -The purpose of this tag is to identify the colorants used in the profile by a -unique name and set of XYZ or L*a*b* values to give the colorant an unambiguous -value. The first colorant listed is the colorant of the first device channel of -a lut tag. The second colorant listed is the colorant of the second device channel -of a lut tag, and so on. -*/ - -static -void *Type_ColorantTable_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsUInt32Number i, Count; - cmsNAMEDCOLORLIST* List; - char Name[33]; - cmsUInt16Number PCS[3]; - - - if (!_cmsReadUInt32Number(io, &Count)) return NULL; - - if (Count > cmsMAXCHANNELS) { - cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many colorants '%d'", Count); - return NULL; - } - - List = cmsAllocNamedColorList(self ->ContextID, Count, 0, "", ""); - for (i=0; i < Count; i++) { - - if (io ->Read(io, Name, 32, 1) != 1) goto Error; - Name[32] = 0; - - if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error; - - if (!cmsAppendNamedColor(List, Name, PCS, NULL)) goto Error; - - } - - *nItems = 1; - return List; - -Error: - *nItems = 0; - cmsFreeNamedColorList(List); - return NULL; - - cmsUNUSED_PARAMETER(SizeOfTag); -} - - - -// Saves a colorant table. It is using the named color structure for simplicity sake -static -cmsBool Type_ColorantTable_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr; - int i, nColors; - - nColors = cmsNamedColorCount(NamedColorList); - - if (!_cmsWriteUInt32Number(io, nColors)) return FALSE; - - for (i=0; i < nColors; i++) { - - char root[33]; - cmsUInt16Number PCS[3]; - - if (!cmsNamedColorInfo(NamedColorList, i, root, NULL, NULL, PCS, NULL)) return 0; - root[32] = 0; - - if (!io ->Write(io, 32, root)) return FALSE; - if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE; - } - - return TRUE; - - cmsUNUSED_PARAMETER(nItems); - cmsUNUSED_PARAMETER(self); -} - - -static -void* Type_ColorantTable_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) -{ - cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr; - return (void*) cmsDupNamedColorList(nc); - - cmsUNUSED_PARAMETER(n); - cmsUNUSED_PARAMETER(self); -} - - -static -void Type_ColorantTable_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr); - return; - - cmsUNUSED_PARAMETER(self); -} - - -// ******************************************************************************** -// Type cmsSigNamedColor2Type -// ******************************************************************************** -// -//The namedColor2Type is a count value and array of structures that provide color -//coordinates for 7-bit ASCII color names. For each named color, a PCS and optional -//device representation of the color are given. Both representations are 16-bit values. -//The device representation corresponds to the header's 'color space of data' field. -//This representation should be consistent with the 'number of device components' -//field in the namedColor2Type. If this field is 0, device coordinates are not provided. -//The PCS representation corresponds to the header's PCS field. The PCS representation -//is always provided. Color names are fixed-length, 32-byte fields including null -//termination. In order to maintain maximum portability, it is strongly recommended -//that special characters of the 7-bit ASCII set not be used. - -static -void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - - cmsUInt32Number vendorFlag; // Bottom 16 bits for ICC use - cmsUInt32Number count; // Count of named colors - cmsUInt32Number nDeviceCoords; // Num of device coordinates - char prefix[32]; // Prefix for each color name - char suffix[32]; // Suffix for each color name - cmsNAMEDCOLORLIST* v; - cmsUInt32Number i; - - - *nItems = 0; - if (!_cmsReadUInt32Number(io, &vendorFlag)) return NULL; - if (!_cmsReadUInt32Number(io, &count)) return NULL; - if (!_cmsReadUInt32Number(io, &nDeviceCoords)) return NULL; - - if (io -> Read(io, prefix, 32, 1) != 1) return NULL; - if (io -> Read(io, suffix, 32, 1) != 1) return NULL; - - prefix[31] = suffix[31] = 0; - - v = cmsAllocNamedColorList(self ->ContextID, count, nDeviceCoords, prefix, suffix); - if (v == NULL) { - cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many named colors '%d'", count); - return NULL; - } - - if (nDeviceCoords > cmsMAXCHANNELS) { - cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many device coordinates '%d'", nDeviceCoords); - goto Error; - } - for (i=0; i < count; i++) { - - cmsUInt16Number PCS[3]; - cmsUInt16Number Colorant[cmsMAXCHANNELS]; - char Root[33]; - - memset(Colorant, 0, sizeof(Colorant)); - if (io -> Read(io, Root, 32, 1) != 1) goto Error; - Root[32] = 0; - if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error; - if (!_cmsReadUInt16Array(io, nDeviceCoords, Colorant)) goto Error; - - if (!cmsAppendNamedColor(v, Root, PCS, Colorant)) goto Error; - } - - *nItems = 1; - return (void*) v ; - -Error: - cmsFreeNamedColorList(v); - return NULL; - - cmsUNUSED_PARAMETER(SizeOfTag); -} - - -// Saves a named color list into a named color profile -static -cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr; - char prefix[32]; // Prefix for each color name - char suffix[32]; // Suffix for each color name - int i, nColors; - - nColors = cmsNamedColorCount(NamedColorList); - - if (!_cmsWriteUInt32Number(io, 0)) return FALSE; - if (!_cmsWriteUInt32Number(io, nColors)) return FALSE; - if (!_cmsWriteUInt32Number(io, NamedColorList ->ColorantCount)) return FALSE; - - strncpy(prefix, (const char*) NamedColorList->Prefix, 32); - strncpy(suffix, (const char*) NamedColorList->Suffix, 32); - - suffix[31] = prefix[31] = 0; - - if (!io ->Write(io, 32, prefix)) return FALSE; - if (!io ->Write(io, 32, suffix)) return FALSE; - - for (i=0; i < nColors; i++) { - - cmsUInt16Number PCS[3]; - cmsUInt16Number Colorant[cmsMAXCHANNELS]; - char Root[33]; - - if (!cmsNamedColorInfo(NamedColorList, i, Root, NULL, NULL, PCS, Colorant)) return 0; - if (!io ->Write(io, 32 , Root)) return FALSE; - if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE; - if (!_cmsWriteUInt16Array(io, NamedColorList ->ColorantCount, Colorant)) return FALSE; - } - - return TRUE; - - cmsUNUSED_PARAMETER(nItems); - cmsUNUSED_PARAMETER(self); -} - -static -void* Type_NamedColor_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) -{ - cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr; - - return (void*) cmsDupNamedColorList(nc); - - cmsUNUSED_PARAMETER(n); - cmsUNUSED_PARAMETER(self); -} - - -static -void Type_NamedColor_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr); - return; - - cmsUNUSED_PARAMETER(self); -} - - -// ******************************************************************************** -// Type cmsSigProfileSequenceDescType -// ******************************************************************************** - -// This type is an array of structures, each of which contains information from the -// header fields and tags from the original profiles which were combined to create -// the final profile. The order of the structures is the order in which the profiles -// were combined and includes a structure for the final profile. This provides a -// description of the profile sequence from source to destination, -// typically used with the DeviceLink profile. - -static -cmsBool ReadEmbeddedText(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU** mlu, cmsUInt32Number SizeOfTag) -{ - cmsTagTypeSignature BaseType; - cmsUInt32Number nItems; - - BaseType = _cmsReadTypeBase(io); - - switch (BaseType) { - - case cmsSigTextType: - if (*mlu) cmsMLUfree(*mlu); - *mlu = (cmsMLU*)Type_Text_Read(self, io, &nItems, SizeOfTag); - return (*mlu != NULL); - - case cmsSigTextDescriptionType: - if (*mlu) cmsMLUfree(*mlu); - *mlu = (cmsMLU*) Type_Text_Description_Read(self, io, &nItems, SizeOfTag); - return (*mlu != NULL); - - /* - TBD: Size is needed for MLU, and we have no idea on which is the available size - */ - - case cmsSigMultiLocalizedUnicodeType: - if (*mlu) cmsMLUfree(*mlu); - *mlu = (cmsMLU*) Type_MLU_Read(self, io, &nItems, SizeOfTag); - return (*mlu != NULL); - - default: return FALSE; - } -} - - -static -void *Type_ProfileSequenceDesc_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsSEQ* OutSeq; - cmsUInt32Number i, Count; - - *nItems = 0; - - if (!_cmsReadUInt32Number(io, &Count)) return NULL; - - if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; - SizeOfTag -= sizeof(cmsUInt32Number); - - - OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count); - if (OutSeq == NULL) return NULL; - - OutSeq ->n = Count; - - // Get structures as well - - for (i=0; i < Count; i++) { - - cmsPSEQDESC* sec = &OutSeq -> seq[i]; - - if (!_cmsReadUInt32Number(io, &sec ->deviceMfg)) goto Error; - if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error; - SizeOfTag -= sizeof(cmsUInt32Number); - - if (!_cmsReadUInt32Number(io, &sec ->deviceModel)) goto Error; - if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error; - SizeOfTag -= sizeof(cmsUInt32Number); - - if (!_cmsReadUInt64Number(io, &sec ->attributes)) goto Error; - if (SizeOfTag < sizeof(cmsUInt64Number)) goto Error; - SizeOfTag -= sizeof(cmsUInt64Number); - - if (!_cmsReadUInt32Number(io, (cmsUInt32Number *)&sec ->technology)) goto Error; - if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error; - SizeOfTag -= sizeof(cmsUInt32Number); - - if (!ReadEmbeddedText(self, io, &sec ->Manufacturer, SizeOfTag)) goto Error; - if (!ReadEmbeddedText(self, io, &sec ->Model, SizeOfTag)) goto Error; - } - - *nItems = 1; - return OutSeq; - -Error: - cmsFreeProfileSequenceDescription(OutSeq); - return NULL; -} - - -// Aux--Embed a text description type. It can be of type text description or multilocalized unicode -// and it depends of the version number passed on cmsTagDescriptor structure instead of stack -static -cmsBool SaveDescription(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* Text) -{ - if (self ->ICCVersion < 0x4000000) { - - if (!_cmsWriteTypeBase(io, cmsSigTextDescriptionType)) return FALSE; - return Type_Text_Description_Write(self, io, Text, 1); - } - else { - if (!_cmsWriteTypeBase(io, cmsSigMultiLocalizedUnicodeType)) return FALSE; - return Type_MLU_Write(self, io, Text, 1); - } -} - - -static -cmsBool Type_ProfileSequenceDesc_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsSEQ* Seq = (cmsSEQ*) Ptr; - cmsUInt32Number i; - - if (!_cmsWriteUInt32Number(io, Seq->n)) return FALSE; - - for (i=0; i < Seq ->n; i++) { - - cmsPSEQDESC* sec = &Seq -> seq[i]; - - if (!_cmsWriteUInt32Number(io, sec ->deviceMfg)) return FALSE; - if (!_cmsWriteUInt32Number(io, sec ->deviceModel)) return FALSE; - if (!_cmsWriteUInt64Number(io, &sec ->attributes)) return FALSE; - if (!_cmsWriteUInt32Number(io, sec ->technology)) return FALSE; - - if (!SaveDescription(self, io, sec ->Manufacturer)) return FALSE; - if (!SaveDescription(self, io, sec ->Model)) return FALSE; - } - - return TRUE; - - cmsUNUSED_PARAMETER(nItems); -} - - -static -void* Type_ProfileSequenceDesc_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) -{ - return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr); - - cmsUNUSED_PARAMETER(n); - cmsUNUSED_PARAMETER(self); -} - -static -void Type_ProfileSequenceDesc_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr); - return; - - cmsUNUSED_PARAMETER(self); -} - - -// ******************************************************************************** -// Type cmsSigProfileSequenceIdType -// ******************************************************************************** -/* -In certain workflows using ICC Device Link Profiles, it is necessary to identify the -original profiles that were combined to create the Device Link Profile. -This type is an array of structures, each of which contains information for -identification of a profile used in a sequence -*/ - - -static -cmsBool ReadSeqID(struct _cms_typehandler_struct* self, - cmsIOHANDLER* io, - void* Cargo, - cmsUInt32Number n, - cmsUInt32Number SizeOfTag) -{ - cmsSEQ* OutSeq = (cmsSEQ*) Cargo; - cmsPSEQDESC* seq = &OutSeq ->seq[n]; - - if (io -> Read(io, seq ->ProfileID.ID8, 16, 1) != 1) return FALSE; - if (!ReadEmbeddedText(self, io, &seq ->Description, SizeOfTag)) return FALSE; - - return TRUE; -} - - - -static -void *Type_ProfileSequenceId_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsSEQ* OutSeq; - cmsUInt32Number Count; - cmsUInt32Number BaseOffset; - - *nItems = 0; - - // Get actual position as a basis for element offsets - BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); - - // Get table count - if (!_cmsReadUInt32Number(io, &Count)) return NULL; - SizeOfTag -= sizeof(cmsUInt32Number); - - // Allocate an empty structure - OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count); - if (OutSeq == NULL) return NULL; - - - // Read the position table - if (!ReadPositionTable(self, io, Count, BaseOffset, OutSeq, ReadSeqID)) { - - cmsFreeProfileSequenceDescription(OutSeq); - return NULL; - } - - // Success - *nItems = 1; - return OutSeq; - -} - - -static -cmsBool WriteSeqID(struct _cms_typehandler_struct* self, - cmsIOHANDLER* io, - void* Cargo, - cmsUInt32Number n, - cmsUInt32Number SizeOfTag) -{ - cmsSEQ* Seq = (cmsSEQ*) Cargo; - - if (!io ->Write(io, 16, Seq ->seq[n].ProfileID.ID8)) return FALSE; - - // Store here the MLU - if (!SaveDescription(self, io, Seq ->seq[n].Description)) return FALSE; - - return TRUE; - - cmsUNUSED_PARAMETER(SizeOfTag); -} - -static -cmsBool Type_ProfileSequenceId_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsSEQ* Seq = (cmsSEQ*) Ptr; - cmsUInt32Number BaseOffset; - - // Keep the base offset - BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); - - // This is the table count - if (!_cmsWriteUInt32Number(io, Seq ->n)) return FALSE; - - // This is the position table and content - if (!WritePositionTable(self, io, 0, Seq ->n, BaseOffset, Seq, WriteSeqID)) return FALSE; - - return TRUE; - - cmsUNUSED_PARAMETER(nItems); -} - -static -void* Type_ProfileSequenceId_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) -{ - return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr); - - cmsUNUSED_PARAMETER(n); - cmsUNUSED_PARAMETER(self); -} - -static -void Type_ProfileSequenceId_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr); - return; - - cmsUNUSED_PARAMETER(self); -} - - -// ******************************************************************************** -// Type cmsSigUcrBgType -// ******************************************************************************** -/* -This type contains curves representing the under color removal and black -generation and a text string which is a general description of the method used -for the ucr/bg. -*/ - -static -void *Type_UcrBg_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsUcrBg* n = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg)); - cmsUInt32Number CountUcr, CountBg; - char* ASCIIString; - - *nItems = 0; - if (n == NULL) return NULL; - - // First curve is Under color removal - if (!_cmsReadUInt32Number(io, &CountUcr)) return NULL; - if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; - SizeOfTag -= sizeof(cmsUInt32Number); - - n ->Ucr = cmsBuildTabulatedToneCurve16(self ->ContextID, CountUcr, NULL); - if (n ->Ucr == NULL) return NULL; - - if (!_cmsReadUInt16Array(io, CountUcr, n ->Ucr->Table16)) return NULL; - if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; - SizeOfTag -= CountUcr * sizeof(cmsUInt16Number); - - // Second curve is Black generation - if (!_cmsReadUInt32Number(io, &CountBg)) return NULL; - if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; - SizeOfTag -= sizeof(cmsUInt32Number); - - n ->Bg = cmsBuildTabulatedToneCurve16(self ->ContextID, CountBg, NULL); - if (n ->Bg == NULL) return NULL; - if (!_cmsReadUInt16Array(io, CountBg, n ->Bg->Table16)) return NULL; - if (SizeOfTag < CountBg * sizeof(cmsUInt16Number)) return NULL; - SizeOfTag -= CountBg * sizeof(cmsUInt16Number); - if (SizeOfTag == UINT_MAX) return NULL; - - // Now comes the text. The length is specified by the tag size - n ->Desc = cmsMLUalloc(self ->ContextID, 1); - if (n ->Desc == NULL) return NULL; - - ASCIIString = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1); - if (io ->Read(io, ASCIIString, sizeof(char), SizeOfTag) != SizeOfTag) return NULL; - ASCIIString[SizeOfTag] = 0; - cmsMLUsetASCII(n ->Desc, cmsNoLanguage, cmsNoCountry, ASCIIString); - _cmsFree(self ->ContextID, ASCIIString); - - *nItems = 1; - return (void*) n; -} - -static -cmsBool Type_UcrBg_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsUcrBg* Value = (cmsUcrBg*) Ptr; - cmsUInt32Number TextSize; - char* Text; - - // First curve is Under color removal - if (!_cmsWriteUInt32Number(io, Value ->Ucr ->nEntries)) return FALSE; - if (!_cmsWriteUInt16Array(io, Value ->Ucr ->nEntries, Value ->Ucr ->Table16)) return FALSE; - - // Then black generation - if (!_cmsWriteUInt32Number(io, Value ->Bg ->nEntries)) return FALSE; - if (!_cmsWriteUInt16Array(io, Value ->Bg ->nEntries, Value ->Bg ->Table16)) return FALSE; - - // Now comes the text. The length is specified by the tag size - TextSize = cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, NULL, 0); - Text = (char*) _cmsMalloc(self ->ContextID, TextSize); - if (cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, Text, TextSize) != TextSize) return FALSE; - - if (!io ->Write(io, TextSize, Text)) return FALSE; - _cmsFree(self ->ContextID, Text); - - return TRUE; - - cmsUNUSED_PARAMETER(nItems); -} - -static -void* Type_UcrBg_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - cmsUcrBg* Src = (cmsUcrBg*) Ptr; - cmsUcrBg* NewUcrBg = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg)); - - if (NewUcrBg == NULL) return NULL; - - NewUcrBg ->Bg = cmsDupToneCurve(Src ->Bg); - NewUcrBg ->Ucr = cmsDupToneCurve(Src ->Ucr); - NewUcrBg ->Desc = cmsMLUdup(Src ->Desc); - - return (void*) NewUcrBg; - - cmsUNUSED_PARAMETER(n); -} - -static -void Type_UcrBg_Free(struct _cms_typehandler_struct* self, void *Ptr) -{ - cmsUcrBg* Src = (cmsUcrBg*) Ptr; - - if (Src ->Ucr) cmsFreeToneCurve(Src ->Ucr); - if (Src ->Bg) cmsFreeToneCurve(Src ->Bg); - if (Src ->Desc) cmsMLUfree(Src ->Desc); - - _cmsFree(self ->ContextID, Ptr); -} - -// ******************************************************************************** -// Type cmsSigCrdInfoType -// ******************************************************************************** - -/* -This type contains the PostScript product name to which this profile corresponds -and the names of the companion CRDs. Recall that a single profile can generate -multiple CRDs. It is implemented as a MLU being the language code "PS" and then -country varies for each element: - - nm: PostScript product name - #0: Rendering intent 0 CRD name - #1: Rendering intent 1 CRD name - #2: Rendering intent 2 CRD name - #3: Rendering intent 3 CRD name -*/ - - - -// Auxiliar, read an string specified as count + string -static -cmsBool ReadCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, cmsUInt32Number* SizeOfTag, const char* Section) -{ - cmsUInt32Number Count; - char* Text; - - if (*SizeOfTag < sizeof(cmsUInt32Number)) return FALSE; - - if (!_cmsReadUInt32Number(io, &Count)) return FALSE; - - if (Count > UINT_MAX - sizeof(cmsUInt32Number)) return FALSE; - if (*SizeOfTag < Count + sizeof(cmsUInt32Number)) return FALSE; - - Text = (char*) _cmsMalloc(self ->ContextID, Count+1); - if (Text == NULL) return FALSE; - - if (io ->Read(io, Text, sizeof(cmsUInt8Number), Count) != Count) { - _cmsFree(self ->ContextID, Text); - return FALSE; - } - - Text[Count] = 0; - - cmsMLUsetASCII(mlu, "PS", Section, Text); - _cmsFree(self ->ContextID, Text); - - *SizeOfTag -= (Count + sizeof(cmsUInt32Number)); - return TRUE; -} - -static -cmsBool WriteCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, const char* Section) -{ - cmsUInt32Number TextSize; - char* Text; - - TextSize = cmsMLUgetASCII(mlu, "PS", Section, NULL, 0); - Text = (char*) _cmsMalloc(self ->ContextID, TextSize); - - if (!_cmsWriteUInt32Number(io, TextSize)) return FALSE; - - if (cmsMLUgetASCII(mlu, "PS", Section, Text, TextSize) == 0) return FALSE; - - if (!io ->Write(io, TextSize, Text)) return FALSE; - _cmsFree(self ->ContextID, Text); - - return TRUE; -} - -static -void *Type_CrdInfo_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsMLU* mlu = cmsMLUalloc(self ->ContextID, 5); - - *nItems = 0; - if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "nm")) goto Error; - if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#0")) goto Error; - if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#1")) goto Error; - if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#2")) goto Error; - if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#3")) goto Error; - - *nItems = 1; - return (void*) mlu; - -Error: - cmsMLUfree(mlu); - return NULL; - -} - -static -cmsBool Type_CrdInfo_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - - cmsMLU* mlu = (cmsMLU*) Ptr; - - if (!WriteCountAndSting(self, io, mlu, "nm")) goto Error; - if (!WriteCountAndSting(self, io, mlu, "#0")) goto Error; - if (!WriteCountAndSting(self, io, mlu, "#1")) goto Error; - if (!WriteCountAndSting(self, io, mlu, "#2")) goto Error; - if (!WriteCountAndSting(self, io, mlu, "#3")) goto Error; - - return TRUE; - -Error: - return FALSE; - - cmsUNUSED_PARAMETER(nItems); -} - - -static -void* Type_CrdInfo_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - return (void*) cmsMLUdup((cmsMLU*) Ptr); - - cmsUNUSED_PARAMETER(n); - cmsUNUSED_PARAMETER(self); -} - -static -void Type_CrdInfo_Free(struct _cms_typehandler_struct* self, void *Ptr) -{ - cmsMLUfree((cmsMLU*) Ptr); - return; - - cmsUNUSED_PARAMETER(self); -} - -// ******************************************************************************** -// Type cmsSigScreeningType -// ******************************************************************************** -// -//The screeningType describes various screening parameters including screen -//frequency, screening angle, and spot shape. - -static -void *Type_Screening_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsScreening* sc = NULL; - cmsUInt32Number i; - - sc = (cmsScreening*) _cmsMallocZero(self ->ContextID, sizeof(cmsScreening)); - if (sc == NULL) return NULL; - - *nItems = 0; - - if (!_cmsReadUInt32Number(io, &sc ->Flag)) goto Error; - if (!_cmsReadUInt32Number(io, &sc ->nChannels)) goto Error; - - if (sc ->nChannels > cmsMAXCHANNELS - 1) - sc ->nChannels = cmsMAXCHANNELS - 1; - - for (i=0; i < sc ->nChannels; i++) { - - if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].Frequency)) goto Error; - if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].ScreenAngle)) goto Error; - if (!_cmsReadUInt32Number(io, &sc ->Channels[i].SpotShape)) goto Error; - } - - - *nItems = 1; - - return (void*) sc; - -Error: - if (sc != NULL) - _cmsFree(self ->ContextID, sc); - - return NULL; - - cmsUNUSED_PARAMETER(SizeOfTag); -} - - -static -cmsBool Type_Screening_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsScreening* sc = (cmsScreening* ) Ptr; - cmsUInt32Number i; - - if (!_cmsWriteUInt32Number(io, sc ->Flag)) return FALSE; - if (!_cmsWriteUInt32Number(io, sc ->nChannels)) return FALSE; - - for (i=0; i < sc ->nChannels; i++) { - - if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].Frequency)) return FALSE; - if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].ScreenAngle)) return FALSE; - if (!_cmsWriteUInt32Number(io, sc ->Channels[i].SpotShape)) return FALSE; - } - - return TRUE; - - cmsUNUSED_PARAMETER(nItems); - cmsUNUSED_PARAMETER(self); -} - - -static -void* Type_Screening_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening)); - - cmsUNUSED_PARAMETER(n); -} - - -static -void Type_Screening_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - _cmsFree(self ->ContextID, Ptr); -} - -// ******************************************************************************** -// Type cmsSigViewingConditionsType -// ******************************************************************************** -// -//This type represents a set of viewing condition parameters including: -//CIE 'absolute'illuminant white point tristimulus values and CIE 'absolute' -//surround tristimulus values. - -static -void *Type_ViewingConditions_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsICCViewingConditions* vc = NULL; - - vc = (cmsICCViewingConditions*) _cmsMallocZero(self ->ContextID, sizeof(cmsICCViewingConditions)); - if (vc == NULL) return NULL; - - *nItems = 0; - - if (!_cmsReadXYZNumber(io, &vc ->IlluminantXYZ)) goto Error; - if (!_cmsReadXYZNumber(io, &vc ->SurroundXYZ)) goto Error; - if (!_cmsReadUInt32Number(io, &vc ->IlluminantType)) goto Error; - - *nItems = 1; - - return (void*) vc; - -Error: - if (vc != NULL) - _cmsFree(self ->ContextID, vc); - - return NULL; - - cmsUNUSED_PARAMETER(SizeOfTag); -} - - -static -cmsBool Type_ViewingConditions_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsICCViewingConditions* sc = (cmsICCViewingConditions* ) Ptr; - - if (!_cmsWriteXYZNumber(io, &sc ->IlluminantXYZ)) return FALSE; - if (!_cmsWriteXYZNumber(io, &sc ->SurroundXYZ)) return FALSE; - if (!_cmsWriteUInt32Number(io, sc ->IlluminantType)) return FALSE; - - return TRUE; - - cmsUNUSED_PARAMETER(nItems); - cmsUNUSED_PARAMETER(self); -} - - -static -void* Type_ViewingConditions_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening)); - - cmsUNUSED_PARAMETER(n); -} - - -static -void Type_ViewingConditions_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - _cmsFree(self ->ContextID, Ptr); -} - - -// ******************************************************************************** -// Type cmsSigMultiProcessElementType -// ******************************************************************************** - - -static -void* GenericMPEdup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - return (void*) cmsStageDup((cmsStage*) Ptr); - - cmsUNUSED_PARAMETER(n); - cmsUNUSED_PARAMETER(self); -} - -static -void GenericMPEfree(struct _cms_typehandler_struct* self, void *Ptr) -{ - cmsStageFree((cmsStage*) Ptr); - return; - - cmsUNUSED_PARAMETER(self); -} - -// Each curve is stored in one or more curve segments, with break-points specified between curve segments. -// The first curve segment always starts at -Infinity, and the last curve segment always ends at +Infinity. The -// first and last curve segments shall be specified in terms of a formula, whereas the other segments shall be -// specified either in terms of a formula, or by a sampled curve. - - -// Read an embedded segmented curve -static -cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io) -{ - cmsCurveSegSignature ElementSig; - cmsUInt32Number i, j; - cmsUInt16Number nSegments; - cmsCurveSegment* Segments; - cmsToneCurve* Curve; - cmsFloat32Number PrevBreak = -1E22F; // - infinite - - // Take signature and channels for each element. - if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return NULL; - - // That should be a segmented curve - if (ElementSig != cmsSigSegmentedCurve) return NULL; - - if (!_cmsReadUInt32Number(io, NULL)) return NULL; - if (!_cmsReadUInt16Number(io, &nSegments)) return NULL; - if (!_cmsReadUInt16Number(io, NULL)) return NULL; - - if (nSegments < 1) return NULL; - Segments = (cmsCurveSegment*) _cmsCalloc(self ->ContextID, nSegments, sizeof(cmsCurveSegment)); - if (Segments == NULL) return NULL; - - // Read breakpoints - for (i=0; i < (cmsUInt32Number) nSegments - 1; i++) { - - Segments[i].x0 = PrevBreak; - if (!_cmsReadFloat32Number(io, &Segments[i].x1)) goto Error; - PrevBreak = Segments[i].x1; - } - - Segments[nSegments-1].x0 = PrevBreak; - Segments[nSegments-1].x1 = 1E22F; // A big cmsFloat32Number number - - // Read segments - for (i=0; i < nSegments; i++) { - - if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) goto Error; - if (!_cmsReadUInt32Number(io, NULL)) goto Error; - - switch (ElementSig) { - - case cmsSigFormulaCurveSeg: { - - cmsUInt16Number Type; - cmsUInt32Number ParamsByType[] = {4, 5, 5 }; - - if (!_cmsReadUInt16Number(io, &Type)) goto Error; - if (!_cmsReadUInt16Number(io, NULL)) goto Error; - - Segments[i].Type = Type + 6; - if (Type > 2) goto Error; - - for (j=0; j < ParamsByType[Type]; j++) { - - cmsFloat32Number f; - if (!_cmsReadFloat32Number(io, &f)) goto Error; - Segments[i].Params[j] = f; - } - } - break; - - - case cmsSigSampledCurveSeg: { - cmsUInt32Number Count; - - if (!_cmsReadUInt32Number(io, &Count)) goto Error; - - Segments[i].nGridPoints = Count; - Segments[i].SampledPoints = (cmsFloat32Number*) _cmsCalloc(self ->ContextID, Count, sizeof(cmsFloat32Number)); - if (Segments[i].SampledPoints == NULL) goto Error; - - for (j=0; j < Count; j++) { - if (!_cmsReadFloat32Number(io, &Segments[i].SampledPoints[j])) goto Error; - } - } - break; - - default: - { - char String[5]; - - _cmsTagSignature2String(String, (cmsTagSignature) ElementSig); - cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve element type '%s' found.", String); - } - goto Error; - - } - } - - Curve = cmsBuildSegmentedToneCurve(self ->ContextID, nSegments, Segments); - - for (i=0; i < nSegments; i++) { - if (Segments[i].SampledPoints) _cmsFree(self ->ContextID, Segments[i].SampledPoints); - } - _cmsFree(self ->ContextID, Segments); - return Curve; - -Error: - if (Segments) { - for (i=0; i < nSegments; i++) { - if (Segments[i].SampledPoints) _cmsFree(self ->ContextID, Segments[i].SampledPoints); - } - _cmsFree(self ->ContextID, Segments); - } - return NULL; -} - - -static -cmsBool ReadMPECurve(struct _cms_typehandler_struct* self, - cmsIOHANDLER* io, - void* Cargo, - cmsUInt32Number n, - cmsUInt32Number SizeOfTag) -{ - cmsToneCurve** GammaTables = ( cmsToneCurve**) Cargo; - - GammaTables[n] = ReadSegmentedCurve(self, io); - return (GammaTables[n] != NULL); - - cmsUNUSED_PARAMETER(SizeOfTag); -} - -static -void *Type_MPEcurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsStage* mpe = NULL; - cmsUInt16Number InputChans, OutputChans; - cmsUInt32Number i, BaseOffset; - cmsToneCurve** GammaTables; - - *nItems = 0; - - // Get actual position as a basis for element offsets - BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); - - if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; - if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; - - if (InputChans != OutputChans) return NULL; - - GammaTables = (cmsToneCurve**) _cmsCalloc(self ->ContextID, InputChans, sizeof(cmsToneCurve*)); - if (GammaTables == NULL) return NULL; - - if (ReadPositionTable(self, io, InputChans, BaseOffset, GammaTables, ReadMPECurve)) { - - mpe = cmsStageAllocToneCurves(self ->ContextID, InputChans, GammaTables); - } - else { - mpe = NULL; - } - - for (i=0; i < InputChans; i++) { - if (GammaTables[i]) cmsFreeToneCurve(GammaTables[i]); - } - - _cmsFree(self ->ContextID, GammaTables); - *nItems = (mpe != NULL) ? 1 : 0; - return mpe; - - cmsUNUSED_PARAMETER(SizeOfTag); -} - - -// Write a single segmented curve. NO CHECK IS PERFORMED ON VALIDITY -static -cmsBool WriteSegmentedCurve(cmsIOHANDLER* io, cmsToneCurve* g) -{ - cmsUInt32Number i, j; - cmsCurveSegment* Segments = g ->Segments; - cmsUInt32Number nSegments = g ->nSegments; - - if (!_cmsWriteUInt32Number(io, cmsSigSegmentedCurve)) goto Error; - if (!_cmsWriteUInt32Number(io, 0)) goto Error; - if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) nSegments)) goto Error; - if (!_cmsWriteUInt16Number(io, 0)) goto Error; - - // Write the break-points - for (i=0; i < nSegments - 1; i++) { - if (!_cmsWriteFloat32Number(io, Segments[i].x1)) goto Error; - } - - // Write the segments - for (i=0; i < g ->nSegments; i++) { - - cmsCurveSegment* ActualSeg = Segments + i; - - if (ActualSeg -> Type == 0) { - - // This is a sampled curve - if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigSampledCurveSeg)) goto Error; - if (!_cmsWriteUInt32Number(io, 0)) goto Error; - if (!_cmsWriteUInt32Number(io, ActualSeg -> nGridPoints)) goto Error; - - for (j=0; j < g ->Segments[i].nGridPoints; j++) { - if (!_cmsWriteFloat32Number(io, ActualSeg -> SampledPoints[j])) goto Error; - } - - } - else { - int Type; - cmsUInt32Number ParamsByType[] = { 4, 5, 5 }; - - // This is a formula-based - if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigFormulaCurveSeg)) goto Error; - if (!_cmsWriteUInt32Number(io, 0)) goto Error; - - // We only allow 1, 2 and 3 as types - Type = ActualSeg ->Type - 6; - if (Type > 2 || Type < 0) goto Error; - - if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Type)) goto Error; - if (!_cmsWriteUInt16Number(io, 0)) goto Error; - - for (j=0; j < ParamsByType[Type]; j++) { - if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) ActualSeg ->Params[j])) goto Error; - } - } - - // It seems there is no need to align. Code is here, and for safety commented out - // if (!_cmsWriteAlignment(io)) goto Error; - } - - return TRUE; - -Error: - return FALSE; -} - - -static -cmsBool WriteMPECurve(struct _cms_typehandler_struct* self, - cmsIOHANDLER* io, - void* Cargo, - cmsUInt32Number n, - cmsUInt32Number SizeOfTag) -{ - _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) Cargo; - - return WriteSegmentedCurve(io, Curves ->TheCurves[n]); - - cmsUNUSED_PARAMETER(SizeOfTag); - cmsUNUSED_PARAMETER(self); -} - -// Write a curve, checking first for validity -static -cmsBool Type_MPEcurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsUInt32Number BaseOffset; - cmsStage* mpe = (cmsStage*) Ptr; - _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) mpe ->Data; - - BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); - - // Write the header. Since those are curves, input and output channels are same - if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE; - if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE; - - if (!WritePositionTable(self, io, 0, - mpe ->InputChannels, BaseOffset, Curves, WriteMPECurve)) return FALSE; - - - return TRUE; - - cmsUNUSED_PARAMETER(nItems); -} - - - -// The matrix is organized as an array of PxQ+Q elements, where P is the number of input channels to the -// matrix, and Q is the number of output channels. The matrix elements are each float32Numbers. The array -// is organized as follows: -// array = [e11, e12, ? e1P, e21, e22, ? e2P, ? eQ1, eQ2, ? eQP, e1, e2, ? eQ] - -static -void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsStage* mpe; - cmsUInt16Number InputChans, OutputChans; - cmsUInt32Number nElems, i; - cmsFloat64Number* Matrix; - cmsFloat64Number* Offsets; - - if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; - if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; - - - // Input and output chans may be ANY (up to 0xffff), - // but we choose to limit to 16 channels for now - if (InputChans >= cmsMAXCHANNELS) return NULL; - if (OutputChans >= cmsMAXCHANNELS) return NULL; - - nElems = InputChans * OutputChans; - - Matrix = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, nElems, sizeof(cmsFloat64Number)); - if (Matrix == NULL) return NULL; - - Offsets = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, OutputChans, sizeof(cmsFloat64Number)); - if (Offsets == NULL) { - - _cmsFree(self ->ContextID, Matrix); - return NULL; - } - - for (i=0; i < nElems; i++) { - - cmsFloat32Number v; - - if (!_cmsReadFloat32Number(io, &v)) { - _cmsFree(self ->ContextID, Matrix); - _cmsFree(self ->ContextID, Offsets); - return NULL; - } - Matrix[i] = v; - } - - - for (i=0; i < OutputChans; i++) { - - cmsFloat32Number v; - - if (!_cmsReadFloat32Number(io, &v)) { - _cmsFree(self ->ContextID, Matrix); - _cmsFree(self ->ContextID, Offsets); - return NULL; - } - Offsets[i] = v; - } - - - mpe = cmsStageAllocMatrix(self ->ContextID, OutputChans, InputChans, Matrix, Offsets); - _cmsFree(self ->ContextID, Matrix); - _cmsFree(self ->ContextID, Offsets); - - *nItems = 1; - - return mpe; - - cmsUNUSED_PARAMETER(SizeOfTag); -} - -static -cmsBool Type_MPEmatrix_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsUInt32Number i, nElems; - cmsStage* mpe = (cmsStage*) Ptr; - _cmsStageMatrixData* Matrix = (_cmsStageMatrixData*) mpe ->Data; - - if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE; - if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE; - - nElems = mpe ->InputChannels * mpe ->OutputChannels; - - for (i=0; i < nElems; i++) { - if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Double[i])) return FALSE; - } - - - for (i=0; i < mpe ->OutputChannels; i++) { - - if (Matrix ->Offset == NULL) { - - if (!_cmsWriteFloat32Number(io, 0)) return FALSE; - } - else { - if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Offset[i])) return FALSE; - } - } - - return TRUE; - - cmsUNUSED_PARAMETER(nItems); - cmsUNUSED_PARAMETER(self); -} - - - -static -void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsStage* mpe = NULL; - cmsUInt16Number InputChans, OutputChans; - cmsUInt8Number Dimensions8[16]; - cmsUInt32Number i, nMaxGrids, GridPoints[MAX_INPUT_DIMENSIONS]; - _cmsStageCLutData* clut; - - if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; - if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; - - if (InputChans == 0) goto Error; - if (OutputChans == 0) goto Error; - - if (io ->Read(io, Dimensions8, sizeof(cmsUInt8Number), 16) != 16) - goto Error; - - // Copy MAX_INPUT_DIMENSIONS at most. Expand to cmsUInt32Number - nMaxGrids = InputChans > MAX_INPUT_DIMENSIONS ? MAX_INPUT_DIMENSIONS : InputChans; - - for (i = 0; i < nMaxGrids; i++) { - if (Dimensions8[i] == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least - GridPoints[i] = (cmsUInt32Number)Dimensions8[i]; - } - - // Allocate the true CLUT - mpe = cmsStageAllocCLutFloatGranular(self ->ContextID, GridPoints, InputChans, OutputChans, NULL); - if (mpe == NULL) goto Error; - - // Read the data - clut = (_cmsStageCLutData*) mpe ->Data; - for (i=0; i < clut ->nEntries; i++) { - - if (!_cmsReadFloat32Number(io, &clut ->Tab.TFloat[i])) goto Error; - } - - *nItems = 1; - return mpe; - -Error: - *nItems = 0; - if (mpe != NULL) cmsStageFree(mpe); - return NULL; - - cmsUNUSED_PARAMETER(SizeOfTag); -} - -// Write a CLUT in floating point -static -cmsBool Type_MPEclut_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsUInt8Number Dimensions8[16]; - cmsUInt32Number i; - cmsStage* mpe = (cmsStage*) Ptr; - _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe ->Data; - - // Check for maximum number of channels - if (mpe -> InputChannels > 15) return FALSE; - - // Only floats are supported in MPE - if (clut ->HasFloatValues == FALSE) return FALSE; - - if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE; - if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE; - - memset(Dimensions8, 0, sizeof(Dimensions8)); - - for (i=0; i < mpe ->InputChannels; i++) - Dimensions8[i] = (cmsUInt8Number) clut ->Params ->nSamples[i]; - - if (!io ->Write(io, 16, Dimensions8)) return FALSE; - - for (i=0; i < clut ->nEntries; i++) { - - if (!_cmsWriteFloat32Number(io, clut ->Tab.TFloat[i])) return FALSE; - } - - return TRUE; - - cmsUNUSED_PARAMETER(nItems); - cmsUNUSED_PARAMETER(self); -} - - - -// This is the list of built-in MPE types -static _cmsTagTypeLinkedList SupportedMPEtypes[] = { - -{{ (cmsTagTypeSignature) cmsSigBAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[1] }, // Ignore those elements for now -{{ (cmsTagTypeSignature) cmsSigEAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[2] }, // (That's what the spec says) - -{TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCurveSetElemType, MPEcurve), &SupportedMPEtypes[3] }, -{TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigMatrixElemType, MPEmatrix), &SupportedMPEtypes[4] }, -{TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCLutElemType, MPEclut), NULL }, -}; - -_cmsTagTypePluginChunkType _cmsMPETypePluginChunk = { NULL }; - -static -cmsBool ReadMPEElem(struct _cms_typehandler_struct* self, - cmsIOHANDLER* io, - void* Cargo, - cmsUInt32Number n, - cmsUInt32Number SizeOfTag) -{ - cmsStageSignature ElementSig; - cmsTagTypeHandler* TypeHandler; - cmsUInt32Number nItems; - cmsPipeline *NewLUT = (cmsPipeline *) Cargo; - _cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin); - - - // Take signature and channels for each element. - if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return FALSE; - - // The reserved placeholder - if (!_cmsReadUInt32Number(io, NULL)) return FALSE; - - // Read diverse MPE types - TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk ->TagTypes, SupportedMPEtypes); - if (TypeHandler == NULL) { - - char String[5]; - - _cmsTagSignature2String(String, (cmsTagSignature) ElementSig); - - // An unknown element was found. - cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown MPE type '%s' found.", String); - return FALSE; - } - - // If no read method, just ignore the element (valid for cmsSigBAcsElemType and cmsSigEAcsElemType) - // Read the MPE. No size is given - if (TypeHandler ->ReadPtr != NULL) { - - // This is a real element which should be read and processed - if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, (cmsStage*) TypeHandler ->ReadPtr(self, io, &nItems, SizeOfTag))) - return FALSE; - } - - return TRUE; - - cmsUNUSED_PARAMETER(SizeOfTag); - cmsUNUSED_PARAMETER(n); -} - - -// This is the main dispatcher for MPE -static -void *Type_MPE_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsUInt16Number InputChans, OutputChans; - cmsUInt32Number ElementCount; - cmsPipeline *NewLUT = NULL; - cmsUInt32Number BaseOffset; - - // Get actual position as a basis for element offsets - BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); - - // Read channels and element count - if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; - if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; - - if (InputChans == 0 || InputChans >= cmsMAXCHANNELS) return NULL; - if (OutputChans == 0 || OutputChans >= cmsMAXCHANNELS) return NULL; - - // Allocates an empty LUT - NewLUT = cmsPipelineAlloc(self ->ContextID, InputChans, OutputChans); - if (NewLUT == NULL) return NULL; - - if (!_cmsReadUInt32Number(io, &ElementCount)) goto Error; - if (!ReadPositionTable(self, io, ElementCount, BaseOffset, NewLUT, ReadMPEElem)) goto Error; - - // Success - *nItems = 1; - return NewLUT; - - // Error -Error: - if (NewLUT != NULL) cmsPipelineFree(NewLUT); - *nItems = 0; - return NULL; - - cmsUNUSED_PARAMETER(SizeOfTag); -} - - - -// This one is a liitle bit more complex, so we don't use position tables this time. -static -cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsUInt32Number i, BaseOffset, DirectoryPos, CurrentPos; - int inputChan, outputChan; - cmsUInt32Number ElemCount; - cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL, Before; - cmsStageSignature ElementSig; - cmsPipeline* Lut = (cmsPipeline*) Ptr; - cmsStage* Elem = Lut ->Elements; - cmsTagTypeHandler* TypeHandler; - _cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin); - - BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); - - inputChan = cmsPipelineInputChannels(Lut); - outputChan = cmsPipelineOutputChannels(Lut); - ElemCount = cmsPipelineStageCount(Lut); - - ElementOffsets = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number)); - if (ElementOffsets == NULL) goto Error; - - ElementSizes = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number)); - if (ElementSizes == NULL) goto Error; - - // Write the head - if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) inputChan)) goto Error; - if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) outputChan)) goto Error; - if (!_cmsWriteUInt32Number(io, (cmsUInt16Number) ElemCount)) goto Error; - - DirectoryPos = io ->Tell(io); - - // Write a fake directory to be filled latter on - for (i=0; i < ElemCount; i++) { - if (!_cmsWriteUInt32Number(io, 0)) goto Error; // Offset - if (!_cmsWriteUInt32Number(io, 0)) goto Error; // size - } - - // Write each single tag. Keep track of the size as well. - for (i=0; i < ElemCount; i++) { - - ElementOffsets[i] = io ->Tell(io) - BaseOffset; - - ElementSig = Elem ->Type; - - TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk->TagTypes, SupportedMPEtypes); - if (TypeHandler == NULL) { - - char String[5]; - - _cmsTagSignature2String(String, (cmsTagSignature) ElementSig); - - // An unknow element was found. - cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Found unknown MPE type '%s'", String); - goto Error; - } - - if (!_cmsWriteUInt32Number(io, ElementSig)) goto Error; - if (!_cmsWriteUInt32Number(io, 0)) goto Error; - Before = io ->Tell(io); - if (!TypeHandler ->WritePtr(self, io, Elem, 1)) goto Error; - if (!_cmsWriteAlignment(io)) goto Error; - - ElementSizes[i] = io ->Tell(io) - Before; - - Elem = Elem ->Next; - } - - // Write the directory - CurrentPos = io ->Tell(io); - - if (!io ->Seek(io, DirectoryPos)) goto Error; - - for (i=0; i < ElemCount; i++) { - if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error; - if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error; - } - - if (!io ->Seek(io, CurrentPos)) goto Error; - - if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets); - if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes); - return TRUE; - -Error: - if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets); - if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes); - return FALSE; - - cmsUNUSED_PARAMETER(nItems); -} - - -static -void* Type_MPE_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - return (void*) cmsPipelineDup((cmsPipeline*) Ptr); - - cmsUNUSED_PARAMETER(n); - cmsUNUSED_PARAMETER(self); -} - -static -void Type_MPE_Free(struct _cms_typehandler_struct* self, void *Ptr) -{ - cmsPipelineFree((cmsPipeline*) Ptr); - return; - - cmsUNUSED_PARAMETER(self); -} - - -// ******************************************************************************** -// Type cmsSigVcgtType -// ******************************************************************************** - - -#define cmsVideoCardGammaTableType 0 -#define cmsVideoCardGammaFormulaType 1 - -// Used internally -typedef struct { - double Gamma; - double Min; - double Max; -} _cmsVCGTGAMMA; - - -static -void *Type_vcgt_Read(struct _cms_typehandler_struct* self, - cmsIOHANDLER* io, - cmsUInt32Number* nItems, - cmsUInt32Number SizeOfTag) -{ - cmsUInt32Number TagType, n, i; - cmsToneCurve** Curves; - - *nItems = 0; - - // Read tag type - if (!_cmsReadUInt32Number(io, &TagType)) return NULL; - - // Allocate space for the array - Curves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*)); - if (Curves == NULL) return NULL; - - // There are two possible flavors - switch (TagType) { - - // Gamma is stored as a table - case cmsVideoCardGammaTableType: - { - cmsUInt16Number nChannels, nElems, nBytes; - - // Check channel count, which should be 3 (we don't support monochrome this time) - if (!_cmsReadUInt16Number(io, &nChannels)) goto Error; - - if (nChannels != 3) { - cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported number of channels for VCGT '%d'", nChannels); - goto Error; - } - - // Get Table element count and bytes per element - if (!_cmsReadUInt16Number(io, &nElems)) goto Error; - if (!_cmsReadUInt16Number(io, &nBytes)) goto Error; - - // Adobe's quirk fixup. Fixing broken profiles... - if (nElems == 256 && nBytes == 1 && SizeOfTag == 1576) - nBytes = 2; - - - // Populate tone curves - for (n=0; n < 3; n++) { - - Curves[n] = cmsBuildTabulatedToneCurve16(self ->ContextID, nElems, NULL); - if (Curves[n] == NULL) goto Error; - - // On depending on byte depth - switch (nBytes) { - - // One byte, 0..255 - case 1: - for (i=0; i < nElems; i++) { - - cmsUInt8Number v; - - if (!_cmsReadUInt8Number(io, &v)) goto Error; - Curves[n] ->Table16[i] = FROM_8_TO_16(v); - } - break; - - // One word 0..65535 - case 2: - if (!_cmsReadUInt16Array(io, nElems, Curves[n]->Table16)) goto Error; - break; - - // Unsupported - default: - cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported bit depth for VCGT '%d'", nBytes * 8); - goto Error; - } - } // For all 3 channels - } - break; - - // In this case, gamma is stored as a formula - case cmsVideoCardGammaFormulaType: - { - _cmsVCGTGAMMA Colorant[3]; - - // Populate tone curves - for (n=0; n < 3; n++) { - - double Params[10]; - - if (!_cmsRead15Fixed16Number(io, &Colorant[n].Gamma)) goto Error; - if (!_cmsRead15Fixed16Number(io, &Colorant[n].Min)) goto Error; - if (!_cmsRead15Fixed16Number(io, &Colorant[n].Max)) goto Error; - - // Parametric curve type 5 is: - // Y = (aX + b)^Gamma + e | X >= d - // Y = cX + f | X < d - - // vcgt formula is: - // Y = (Max ?Min) * (X ^ Gamma) + Min - - // So, the translation is - // a = (Max ?Min) ^ ( 1 / Gamma) - // e = Min - // b=c=d=f=0 - - Params[0] = Colorant[n].Gamma; - Params[1] = pow((Colorant[n].Max - Colorant[n].Min), (1.0 / Colorant[n].Gamma)); - Params[2] = 0; - Params[3] = 0; - Params[4] = 0; - Params[5] = Colorant[n].Min; - Params[6] = 0; - - Curves[n] = cmsBuildParametricToneCurve(self ->ContextID, 5, Params); - if (Curves[n] == NULL) goto Error; - } - } - break; - - // Unsupported - default: - cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag type for VCGT '%d'", TagType); - goto Error; - } - - *nItems = 1; - return (void*) Curves; - -// Regret, free all resources -Error: - - cmsFreeToneCurveTriple(Curves); - _cmsFree(self ->ContextID, Curves); - return NULL; - - cmsUNUSED_PARAMETER(SizeOfTag); -} - - -// We don't support all flavors, only 16bits tables and formula -static -cmsBool Type_vcgt_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsToneCurve** Curves = (cmsToneCurve**) Ptr; - cmsUInt32Number i, j; - - if (cmsGetToneCurveParametricType(Curves[0]) == 5 && - cmsGetToneCurveParametricType(Curves[1]) == 5 && - cmsGetToneCurveParametricType(Curves[2]) == 5) { - - if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaFormulaType)) return FALSE; - - // Save parameters - for (i=0; i < 3; i++) { - - _cmsVCGTGAMMA v; - - v.Gamma = Curves[i] ->Segments[0].Params[0]; - v.Min = Curves[i] ->Segments[0].Params[5]; - v.Max = pow(Curves[i] ->Segments[0].Params[1], v.Gamma) + v.Min; - - if (!_cmsWrite15Fixed16Number(io, v.Gamma)) return FALSE; - if (!_cmsWrite15Fixed16Number(io, v.Min)) return FALSE; - if (!_cmsWrite15Fixed16Number(io, v.Max)) return FALSE; - } - } - - else { - - // Always store as a table of 256 words - if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaTableType)) return FALSE; - if (!_cmsWriteUInt16Number(io, 3)) return FALSE; - if (!_cmsWriteUInt16Number(io, 256)) return FALSE; - if (!_cmsWriteUInt16Number(io, 2)) return FALSE; - - for (i=0; i < 3; i++) { - for (j=0; j < 256; j++) { - - cmsFloat32Number v = cmsEvalToneCurveFloat(Curves[i], (cmsFloat32Number) (j / 255.0)); - cmsUInt16Number n = _cmsQuickSaturateWord(v * 65535.0); - - if (!_cmsWriteUInt16Number(io, n)) return FALSE; - } - } - } - - return TRUE; - - cmsUNUSED_PARAMETER(self); - cmsUNUSED_PARAMETER(nItems); -} - -static -void* Type_vcgt_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - cmsToneCurve** OldCurves = (cmsToneCurve**) Ptr; - cmsToneCurve** NewCurves; - - NewCurves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*)); - if (NewCurves == NULL) return NULL; - - NewCurves[0] = cmsDupToneCurve(OldCurves[0]); - NewCurves[1] = cmsDupToneCurve(OldCurves[1]); - NewCurves[2] = cmsDupToneCurve(OldCurves[2]); - - return (void*) NewCurves; - - cmsUNUSED_PARAMETER(n); -} - - -static -void Type_vcgt_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - cmsFreeToneCurveTriple((cmsToneCurve**) Ptr); - _cmsFree(self ->ContextID, Ptr); -} - - -// ******************************************************************************** -// Type cmsSigDictType -// ******************************************************************************** - -// Single column of the table can point to wchar or MLUC elements. Holds arrays of data -typedef struct { - cmsContext ContextID; - cmsUInt32Number *Offsets; - cmsUInt32Number *Sizes; -} _cmsDICelem; - -typedef struct { - _cmsDICelem Name, Value, DisplayName, DisplayValue; - -} _cmsDICarray; - -// Allocate an empty array element -static -cmsBool AllocElem(cmsContext ContextID, _cmsDICelem* e, cmsUInt32Number Count) -{ - e->Offsets = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number)); - if (e->Offsets == NULL) return FALSE; - - e->Sizes = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number)); - if (e->Sizes == NULL) { - - _cmsFree(ContextID, e -> Offsets); - return FALSE; - } - - e ->ContextID = ContextID; - return TRUE; -} - -// Free an array element -static -void FreeElem(_cmsDICelem* e) -{ - if (e ->Offsets != NULL) _cmsFree(e -> ContextID, e -> Offsets); - if (e ->Sizes != NULL) _cmsFree(e -> ContextID, e -> Sizes); - e->Offsets = e ->Sizes = NULL; -} - -// Get rid of whole array -static -void FreeArray( _cmsDICarray* a) -{ - if (a ->Name.Offsets != NULL) FreeElem(&a->Name); - if (a ->Value.Offsets != NULL) FreeElem(&a ->Value); - if (a ->DisplayName.Offsets != NULL) FreeElem(&a->DisplayName); - if (a ->DisplayValue.Offsets != NULL) FreeElem(&a ->DisplayValue); -} - - -// Allocate whole array -static -cmsBool AllocArray(cmsContext ContextID, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length) -{ - // Empty values - memset(a, 0, sizeof(_cmsDICarray)); - - // On depending on record size, create column arrays - if (!AllocElem(ContextID, &a ->Name, Count)) goto Error; - if (!AllocElem(ContextID, &a ->Value, Count)) goto Error; - - if (Length > 16) { - if (!AllocElem(ContextID, &a -> DisplayName, Count)) goto Error; - - } - if (Length > 24) { - if (!AllocElem(ContextID, &a ->DisplayValue, Count)) goto Error; - } - return TRUE; - -Error: - FreeArray(a); - return FALSE; -} - -// Read one element -static -cmsBool ReadOneElem(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, cmsUInt32Number BaseOffset) -{ - if (!_cmsReadUInt32Number(io, &e->Offsets[i])) return FALSE; - if (!_cmsReadUInt32Number(io, &e ->Sizes[i])) return FALSE; - - // An offset of zero has special meaning and shal be preserved - if (e ->Offsets[i] > 0) - e ->Offsets[i] += BaseOffset; - return TRUE; -} - - -static -cmsBool ReadOffsetArray(cmsIOHANDLER* io, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length, cmsUInt32Number BaseOffset) -{ - cmsUInt32Number i; - - // Read column arrays - for (i=0; i < Count; i++) { - - if (!ReadOneElem(io, &a -> Name, i, BaseOffset)) return FALSE; - if (!ReadOneElem(io, &a -> Value, i, BaseOffset)) return FALSE; - - if (Length > 16) { - - if (!ReadOneElem(io, &a ->DisplayName, i, BaseOffset)) return FALSE; - - } - - if (Length > 24) { - - if (!ReadOneElem(io, & a -> DisplayValue, i, BaseOffset)) return FALSE; - } - } - return TRUE; -} - - -// Write one element -static -cmsBool WriteOneElem(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i) -{ - if (!_cmsWriteUInt32Number(io, e->Offsets[i])) return FALSE; - if (!_cmsWriteUInt32Number(io, e ->Sizes[i])) return FALSE; - - return TRUE; -} - -static -cmsBool WriteOffsetArray(cmsIOHANDLER* io, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length) -{ - cmsUInt32Number i; - - for (i=0; i < Count; i++) { - - if (!WriteOneElem(io, &a -> Name, i)) return FALSE; - if (!WriteOneElem(io, &a -> Value, i)) return FALSE; - - if (Length > 16) { - - if (!WriteOneElem(io, &a -> DisplayName, i)) return FALSE; - } - - if (Length > 24) { - - if (!WriteOneElem(io, &a -> DisplayValue, i)) return FALSE; - } - } - - return TRUE; -} - -static -cmsBool ReadOneWChar(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, wchar_t ** wcstr) -{ - - cmsUInt32Number nChars; - - // Special case for undefined strings (see ICC Votable - // Proposal Submission, Dictionary Type and Metadata TAG Definition) - if (e -> Offsets[i] == 0) { - - *wcstr = NULL; - return TRUE; - } - - if (!io -> Seek(io, e -> Offsets[i])) return FALSE; - - nChars = e ->Sizes[i] / sizeof(cmsUInt16Number); - - - *wcstr = (wchar_t*) _cmsMallocZero(e ->ContextID, (nChars + 1) * sizeof(wchar_t)); - if (*wcstr == NULL) return FALSE; - - if (!_cmsReadWCharArray(io, nChars, *wcstr)) { - _cmsFree(e ->ContextID, *wcstr); - return FALSE; - } - - // End of string marker - (*wcstr)[nChars] = 0; - return TRUE; -} - -static -cmsUInt32Number mywcslen(const wchar_t *s) -{ - const wchar_t *p; - - p = s; - while (*p) - p++; - - return (cmsUInt32Number)(p - s); -} - -static -cmsBool WriteOneWChar(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, const wchar_t * wcstr, cmsUInt32Number BaseOffset) -{ - cmsUInt32Number Before = io ->Tell(io); - cmsUInt32Number n; - - e ->Offsets[i] = Before - BaseOffset; - - if (wcstr == NULL) { - e ->Sizes[i] = 0; - e ->Offsets[i] = 0; - return TRUE; - } - - n = mywcslen(wcstr); - if (!_cmsWriteWCharArray(io, n, wcstr)) return FALSE; - - e ->Sizes[i] = io ->Tell(io) - Before; - return TRUE; -} - -static -cmsBool ReadOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, cmsMLU** mlu) -{ - cmsUInt32Number nItems = 0; - - // A way to get null MLUCs - if (e -> Offsets[i] == 0 || e ->Sizes[i] == 0) { - - *mlu = NULL; - return TRUE; - } - - if (!io -> Seek(io, e -> Offsets[i])) return FALSE; - - *mlu = (cmsMLU*) Type_MLU_Read(self, io, &nItems, e ->Sizes[i]); - return *mlu != NULL; -} - -static -cmsBool WriteOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, const cmsMLU* mlu, cmsUInt32Number BaseOffset) -{ - cmsUInt32Number Before; - - // Special case for undefined strings (see ICC Votable - // Proposal Submission, Dictionary Type and Metadata TAG Definition) - if (mlu == NULL) { - e ->Sizes[i] = 0; - e ->Offsets[i] = 0; - return TRUE; - } - - Before = io ->Tell(io); - e ->Offsets[i] = Before - BaseOffset; - - if (!Type_MLU_Write(self, io, (void*) mlu, 1)) return FALSE; - - e ->Sizes[i] = io ->Tell(io) - Before; - return TRUE; -} - - -static -void *Type_Dictionary_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ - cmsHANDLE hDict; - cmsUInt32Number i, Count, Length; - cmsUInt32Number BaseOffset; - _cmsDICarray a; - wchar_t *NameWCS = NULL, *ValueWCS = NULL; - cmsMLU *DisplayNameMLU = NULL, *DisplayValueMLU=NULL; - cmsBool rc; - - *nItems = 0; - - // Get actual position as a basis for element offsets - BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); - - // Get name-value record count - if (!_cmsReadUInt32Number(io, &Count)) return NULL; - SizeOfTag -= sizeof(cmsUInt32Number); - - // Get rec length - if (!_cmsReadUInt32Number(io, &Length)) return NULL; - SizeOfTag -= sizeof(cmsUInt32Number); - - // Check for valid lengths - if (Length != 16 && Length != 24 && Length != 32) { - cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown record length in dictionary '%d'", Length); - return NULL; - } - - // Creates an empty dictionary - hDict = cmsDictAlloc(self -> ContextID); - if (hDict == NULL) return NULL; - - // On depending on record size, create column arrays - if (!AllocArray(self -> ContextID, &a, Count, Length)) goto Error; - - // Read column arrays - if (!ReadOffsetArray(io, &a, Count, Length, BaseOffset)) goto Error; - - // Seek to each element and read it - for (i=0; i < Count; i++) { - - if (!ReadOneWChar(io, &a.Name, i, &NameWCS)) goto Error; - if (!ReadOneWChar(io, &a.Value, i, &ValueWCS)) goto Error; - - if (Length > 16) { - if (!ReadOneMLUC(self, io, &a.DisplayName, i, &DisplayNameMLU)) goto Error; - } - - if (Length > 24) { - if (!ReadOneMLUC(self, io, &a.DisplayValue, i, &DisplayValueMLU)) goto Error; - } - - if (NameWCS == NULL || ValueWCS == NULL) { - - cmsSignalError(self->ContextID, cmsERROR_CORRUPTION_DETECTED, "Bad dictionary Name/Value"); - rc = FALSE; - } - else { - - rc = cmsDictAddEntry(hDict, NameWCS, ValueWCS, DisplayNameMLU, DisplayValueMLU); - } - - if (NameWCS != NULL) _cmsFree(self ->ContextID, NameWCS); - if (ValueWCS != NULL) _cmsFree(self ->ContextID, ValueWCS); - if (DisplayNameMLU != NULL) cmsMLUfree(DisplayNameMLU); - if (DisplayValueMLU != NULL) cmsMLUfree(DisplayValueMLU); - - if (!rc) goto Error; - } - - FreeArray(&a); - *nItems = 1; - return (void*) hDict; - -Error: - FreeArray(&a); - cmsDictFree(hDict); - return NULL; -} - - -static -cmsBool Type_Dictionary_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ - cmsHANDLE hDict = (cmsHANDLE) Ptr; - const cmsDICTentry* p; - cmsBool AnyName, AnyValue; - cmsUInt32Number i, Count, Length; - cmsUInt32Number DirectoryPos, CurrentPos, BaseOffset; - _cmsDICarray a; - - if (hDict == NULL) return FALSE; - - BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); - - // Let's inspect the dictionary - Count = 0; AnyName = FALSE; AnyValue = FALSE; - for (p = cmsDictGetEntryList(hDict); p != NULL; p = cmsDictNextEntry(p)) { - - if (p ->DisplayName != NULL) AnyName = TRUE; - if (p ->DisplayValue != NULL) AnyValue = TRUE; - Count++; - } - - Length = 16; - if (AnyName) Length += 8; - if (AnyValue) Length += 8; - - if (!_cmsWriteUInt32Number(io, Count)) return FALSE; - if (!_cmsWriteUInt32Number(io, Length)) return FALSE; - - // Keep starting position of offsets table - DirectoryPos = io ->Tell(io); - - // Allocate offsets array - if (!AllocArray(self ->ContextID, &a, Count, Length)) goto Error; - - // Write a fake directory to be filled latter on - if (!WriteOffsetArray(io, &a, Count, Length)) goto Error; - - // Write each element. Keep track of the size as well. - p = cmsDictGetEntryList(hDict); - for (i=0; i < Count; i++) { - - if (!WriteOneWChar(io, &a.Name, i, p ->Name, BaseOffset)) goto Error; - if (!WriteOneWChar(io, &a.Value, i, p ->Value, BaseOffset)) goto Error; - - if (p ->DisplayName != NULL) { - if (!WriteOneMLUC(self, io, &a.DisplayName, i, p ->DisplayName, BaseOffset)) goto Error; - } - - if (p ->DisplayValue != NULL) { - if (!WriteOneMLUC(self, io, &a.DisplayValue, i, p ->DisplayValue, BaseOffset)) goto Error; - } - - p = cmsDictNextEntry(p); - } - - // Write the directory - CurrentPos = io ->Tell(io); - if (!io ->Seek(io, DirectoryPos)) goto Error; - - if (!WriteOffsetArray(io, &a, Count, Length)) goto Error; - - if (!io ->Seek(io, CurrentPos)) goto Error; - - FreeArray(&a); - return TRUE; - -Error: - FreeArray(&a); - return FALSE; - - cmsUNUSED_PARAMETER(nItems); -} - - -static -void* Type_Dictionary_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) -{ - return (void*) cmsDictDup((cmsHANDLE) Ptr); - - cmsUNUSED_PARAMETER(n); - cmsUNUSED_PARAMETER(self); -} - - -static -void Type_Dictionary_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ - cmsDictFree((cmsHANDLE) Ptr); - cmsUNUSED_PARAMETER(self); -} - - -// ******************************************************************************** -// Type support main routines -// ******************************************************************************** - - -// This is the list of built-in types -static _cmsTagTypeLinkedList SupportedTagTypes[] = { - -{TYPE_HANDLER(cmsSigChromaticityType, Chromaticity), &SupportedTagTypes[1] }, -{TYPE_HANDLER(cmsSigColorantOrderType, ColorantOrderType), &SupportedTagTypes[2] }, -{TYPE_HANDLER(cmsSigS15Fixed16ArrayType, S15Fixed16), &SupportedTagTypes[3] }, -{TYPE_HANDLER(cmsSigU16Fixed16ArrayType, U16Fixed16), &SupportedTagTypes[4] }, -{TYPE_HANDLER(cmsSigTextType, Text), &SupportedTagTypes[5] }, -{TYPE_HANDLER(cmsSigTextDescriptionType, Text_Description), &SupportedTagTypes[6] }, -{TYPE_HANDLER(cmsSigCurveType, Curve), &SupportedTagTypes[7] }, -{TYPE_HANDLER(cmsSigParametricCurveType, ParametricCurve), &SupportedTagTypes[8] }, -{TYPE_HANDLER(cmsSigDateTimeType, DateTime), &SupportedTagTypes[9] }, -{TYPE_HANDLER(cmsSigLut8Type, LUT8), &SupportedTagTypes[10] }, -{TYPE_HANDLER(cmsSigLut16Type, LUT16), &SupportedTagTypes[11] }, -{TYPE_HANDLER(cmsSigColorantTableType, ColorantTable), &SupportedTagTypes[12] }, -{TYPE_HANDLER(cmsSigNamedColor2Type, NamedColor), &SupportedTagTypes[13] }, -{TYPE_HANDLER(cmsSigMultiLocalizedUnicodeType, MLU), &SupportedTagTypes[14] }, -{TYPE_HANDLER(cmsSigProfileSequenceDescType, ProfileSequenceDesc), &SupportedTagTypes[15] }, -{TYPE_HANDLER(cmsSigSignatureType, Signature), &SupportedTagTypes[16] }, -{TYPE_HANDLER(cmsSigMeasurementType, Measurement), &SupportedTagTypes[17] }, -{TYPE_HANDLER(cmsSigDataType, Data), &SupportedTagTypes[18] }, -{TYPE_HANDLER(cmsSigLutAtoBType, LUTA2B), &SupportedTagTypes[19] }, -{TYPE_HANDLER(cmsSigLutBtoAType, LUTB2A), &SupportedTagTypes[20] }, -{TYPE_HANDLER(cmsSigUcrBgType, UcrBg), &SupportedTagTypes[21] }, -{TYPE_HANDLER(cmsSigCrdInfoType, CrdInfo), &SupportedTagTypes[22] }, -{TYPE_HANDLER(cmsSigMultiProcessElementType, MPE), &SupportedTagTypes[23] }, -{TYPE_HANDLER(cmsSigScreeningType, Screening), &SupportedTagTypes[24] }, -{TYPE_HANDLER(cmsSigViewingConditionsType, ViewingConditions), &SupportedTagTypes[25] }, -{TYPE_HANDLER(cmsSigXYZType, XYZ), &SupportedTagTypes[26] }, -{TYPE_HANDLER(cmsCorbisBrokenXYZtype, XYZ), &SupportedTagTypes[27] }, -{TYPE_HANDLER(cmsMonacoBrokenCurveType, Curve), &SupportedTagTypes[28] }, -{TYPE_HANDLER(cmsSigProfileSequenceIdType, ProfileSequenceId), &SupportedTagTypes[29] }, -{TYPE_HANDLER(cmsSigDictType, Dictionary), &SupportedTagTypes[30] }, -{TYPE_HANDLER(cmsSigVcgtType, vcgt), NULL } -}; - - -_cmsTagTypePluginChunkType _cmsTagTypePluginChunk = { NULL }; - - - -// Duplicates the zone of memory used by the plug-in in the new context -static -void DupTagTypeList(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src, - int loc) -{ - _cmsTagTypePluginChunkType newHead = { NULL }; - _cmsTagTypeLinkedList* entry; - _cmsTagTypeLinkedList* Anterior = NULL; - _cmsTagTypePluginChunkType* head = (_cmsTagTypePluginChunkType*) src->chunks[loc]; - - // Walk the list copying all nodes - for (entry = head->TagTypes; - entry != NULL; - entry = entry ->Next) { - - _cmsTagTypeLinkedList *newEntry = ( _cmsTagTypeLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagTypeLinkedList)); - - if (newEntry == NULL) - return; - - // We want to keep the linked list order, so this is a little bit tricky - newEntry -> Next = NULL; - if (Anterior) - Anterior -> Next = newEntry; - - Anterior = newEntry; - - if (newHead.TagTypes == NULL) - newHead.TagTypes = newEntry; - } - - ctx ->chunks[loc] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagTypePluginChunkType)); -} - - -void _cmsAllocTagTypePluginChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src) -{ - if (src != NULL) { - - // Duplicate the LIST - DupTagTypeList(ctx, src, TagTypePlugin); - } - else { - static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL }; - ctx ->chunks[TagTypePlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType)); - } -} - -void _cmsAllocMPETypePluginChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src) -{ - if (src != NULL) { - - // Duplicate the LIST - DupTagTypeList(ctx, src, MPEPlugin); - } - else { - static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL }; - ctx ->chunks[MPEPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType)); - } - -} - - -// Both kind of plug-ins share same structure -cmsBool _cmsRegisterTagTypePlugin(cmsContext id, cmsPluginBase* Data) -{ - return RegisterTypesPlugin(id, Data, TagTypePlugin); -} - -cmsBool _cmsRegisterMultiProcessElementPlugin(cmsContext id, cmsPluginBase* Data) -{ - return RegisterTypesPlugin(id, Data,MPEPlugin); -} - - -// Wrapper for tag types -cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsContext ContextID, cmsTagTypeSignature sig) -{ - _cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(ContextID, TagTypePlugin); - - return GetHandler(sig, ctx->TagTypes, SupportedTagTypes); -} - -// ******************************************************************************** -// Tag support main routines -// ******************************************************************************** - -typedef struct _cmsTagLinkedList_st { - - cmsTagSignature Signature; - cmsTagDescriptor Descriptor; - struct _cmsTagLinkedList_st* Next; - -} _cmsTagLinkedList; - -// This is the list of built-in tags -static _cmsTagLinkedList SupportedTags[] = { - - { cmsSigAToB0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[1]}, - { cmsSigAToB1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[2]}, - { cmsSigAToB2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[3]}, - { cmsSigBToA0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[4]}, - { cmsSigBToA1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[5]}, - { cmsSigBToA2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[6]}, - - // Allow corbis and its broken XYZ type - { cmsSigRedColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[7]}, - { cmsSigGreenColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[8]}, - { cmsSigBlueColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[9]}, - - { cmsSigRedTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[10]}, - { cmsSigGreenTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[11]}, - { cmsSigBlueTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[12]}, - - { cmsSigCalibrationDateTimeTag, { 1, 1, { cmsSigDateTimeType }, NULL}, &SupportedTags[13]}, - { cmsSigCharTargetTag, { 1, 1, { cmsSigTextType }, NULL}, &SupportedTags[14]}, - - { cmsSigChromaticAdaptationTag, { 9, 1, { cmsSigS15Fixed16ArrayType }, NULL}, &SupportedTags[15]}, - { cmsSigChromaticityTag, { 1, 1, { cmsSigChromaticityType }, NULL}, &SupportedTags[16]}, - { cmsSigColorantOrderTag, { 1, 1, { cmsSigColorantOrderType }, NULL}, &SupportedTags[17]}, - { cmsSigColorantTableTag, { 1, 1, { cmsSigColorantTableType }, NULL}, &SupportedTags[18]}, - { cmsSigColorantTableOutTag, { 1, 1, { cmsSigColorantTableType }, NULL}, &SupportedTags[19]}, - - { cmsSigCopyrightTag, { 1, 3, { cmsSigTextType, cmsSigMultiLocalizedUnicodeType, cmsSigTextDescriptionType}, DecideTextType}, &SupportedTags[20]}, - { cmsSigDateTimeTag, { 1, 1, { cmsSigDateTimeType }, NULL}, &SupportedTags[21]}, - - { cmsSigDeviceMfgDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[22]}, - { cmsSigDeviceModelDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[23]}, - - { cmsSigGamutTag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[24]}, - - { cmsSigGrayTRCTag, { 1, 2, { cmsSigCurveType, cmsSigParametricCurveType }, DecideCurveType}, &SupportedTags[25]}, - { cmsSigLuminanceTag, { 1, 1, { cmsSigXYZType }, NULL}, &SupportedTags[26]}, - - { cmsSigMediaBlackPointTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, NULL}, &SupportedTags[27]}, - { cmsSigMediaWhitePointTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, NULL}, &SupportedTags[28]}, - - { cmsSigNamedColor2Tag, { 1, 1, { cmsSigNamedColor2Type }, NULL}, &SupportedTags[29]}, - - { cmsSigPreview0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[30]}, - { cmsSigPreview1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[31]}, - { cmsSigPreview2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[32]}, - - { cmsSigProfileDescriptionTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[33]}, - { cmsSigProfileSequenceDescTag, { 1, 1, { cmsSigProfileSequenceDescType }, NULL}, &SupportedTags[34]}, - { cmsSigTechnologyTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[35]}, - - { cmsSigColorimetricIntentImageStateTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[36]}, - { cmsSigPerceptualRenderingIntentGamutTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[37]}, - { cmsSigSaturationRenderingIntentGamutTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[38]}, - - { cmsSigMeasurementTag, { 1, 1, { cmsSigMeasurementType }, NULL}, &SupportedTags[39]}, - - { cmsSigPs2CRD0Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[40]}, - { cmsSigPs2CRD1Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[41]}, - { cmsSigPs2CRD2Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[42]}, - { cmsSigPs2CRD3Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[43]}, - { cmsSigPs2CSATag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[44]}, - { cmsSigPs2RenderingIntentTag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[45]}, - - { cmsSigViewingCondDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[46]}, - - { cmsSigUcrBgTag, { 1, 1, { cmsSigUcrBgType}, NULL}, &SupportedTags[47]}, - { cmsSigCrdInfoTag, { 1, 1, { cmsSigCrdInfoType}, NULL}, &SupportedTags[48]}, - - { cmsSigDToB0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[49]}, - { cmsSigDToB1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[50]}, - { cmsSigDToB2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[51]}, - { cmsSigDToB3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[52]}, - { cmsSigBToD0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[53]}, - { cmsSigBToD1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[54]}, - { cmsSigBToD2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[55]}, - { cmsSigBToD3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[56]}, - - { cmsSigScreeningDescTag, { 1, 1, { cmsSigTextDescriptionType }, NULL}, &SupportedTags[57]}, - { cmsSigViewingConditionsTag, { 1, 1, { cmsSigViewingConditionsType }, NULL}, &SupportedTags[58]}, - - { cmsSigScreeningTag, { 1, 1, { cmsSigScreeningType}, NULL }, &SupportedTags[59]}, - { cmsSigVcgtTag, { 1, 1, { cmsSigVcgtType}, NULL }, &SupportedTags[60]}, - { cmsSigMetaTag, { 1, 1, { cmsSigDictType}, NULL }, &SupportedTags[61]}, - { cmsSigProfileSequenceIdTag, { 1, 1, { cmsSigProfileSequenceIdType}, NULL }, &SupportedTags[62]}, - { cmsSigProfileDescriptionMLTag,{ 1, 1, { cmsSigMultiLocalizedUnicodeType}, NULL}, NULL} - - -}; - -/* - Not supported Why - ======================= ========================================= - cmsSigOutputResponseTag ==> WARNING, POSSIBLE PATENT ON THIS SUBJECT! - cmsSigNamedColorTag ==> Deprecated - cmsSigDataTag ==> Ancient, unused - cmsSigDeviceSettingsTag ==> Deprecated, useless -*/ - - -_cmsTagPluginChunkType _cmsTagPluginChunk = { NULL }; - - -// Duplicates the zone of memory used by the plug-in in the new context -static -void DupTagList(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src) -{ - _cmsTagPluginChunkType newHead = { NULL }; - _cmsTagLinkedList* entry; - _cmsTagLinkedList* Anterior = NULL; - _cmsTagPluginChunkType* head = (_cmsTagPluginChunkType*) src->chunks[TagPlugin]; - - // Walk the list copying all nodes - for (entry = head->Tag; - entry != NULL; - entry = entry ->Next) { - - _cmsTagLinkedList *newEntry = ( _cmsTagLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagLinkedList)); - - if (newEntry == NULL) - return; - - // We want to keep the linked list order, so this is a little bit tricky - newEntry -> Next = NULL; - if (Anterior) - Anterior -> Next = newEntry; - - Anterior = newEntry; - - if (newHead.Tag == NULL) - newHead.Tag = newEntry; - } - - ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagPluginChunkType)); -} - -void _cmsAllocTagPluginChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src) -{ - if (src != NULL) { - - DupTagList(ctx, src); - } - else { - static _cmsTagPluginChunkType TagPluginChunk = { NULL }; - ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagPluginChunk, sizeof(_cmsTagPluginChunkType)); - } - -} - -cmsBool _cmsRegisterTagPlugin(cmsContext id, cmsPluginBase* Data) -{ - cmsPluginTag* Plugin = (cmsPluginTag*) Data; - _cmsTagLinkedList *pt; - _cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(id, TagPlugin); - - if (Data == NULL) { - - TagPluginChunk->Tag = NULL; - return TRUE; - } - - pt = (_cmsTagLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagLinkedList)); - if (pt == NULL) return FALSE; - - pt ->Signature = Plugin ->Signature; - pt ->Descriptor = Plugin ->Descriptor; - pt ->Next = TagPluginChunk ->Tag; - - TagPluginChunk ->Tag = pt; - - return TRUE; -} - -// Return a descriptor for a given tag or NULL -cmsTagDescriptor* _cmsGetTagDescriptor(cmsContext ContextID, cmsTagSignature sig) -{ - _cmsTagLinkedList* pt; - _cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(ContextID, TagPlugin); - - for (pt = TagPluginChunk->Tag; - pt != NULL; - pt = pt ->Next) { - - if (sig == pt -> Signature) return &pt ->Descriptor; - } - - for (pt = SupportedTags; - pt != NULL; - pt = pt ->Next) { - - if (sig == pt -> Signature) return &pt ->Descriptor; - } - - return NULL; -} diff --git a/third_party/lcms2-2.6/src/cmsvirt.c b/third_party/lcms2-2.6/src/cmsvirt.c deleted file mode 100644 index d19ace1651..0000000000 --- a/third_party/lcms2-2.6/src/cmsvirt.c +++ /dev/null @@ -1,1194 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2014 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- -// - -#include "lcms2_internal.h" - -// Virtual (built-in) profiles -// ----------------------------------------------------------------------------------- - -static -cmsBool SetTextTags(cmsHPROFILE hProfile, const wchar_t* Description) -{ - cmsMLU *DescriptionMLU, *CopyrightMLU; - cmsBool rc = FALSE; - cmsContext ContextID = cmsGetProfileContextID(hProfile); - - DescriptionMLU = cmsMLUalloc(ContextID, 1); - CopyrightMLU = cmsMLUalloc(ContextID, 1); - - if (DescriptionMLU == NULL || CopyrightMLU == NULL) goto Error; - - if (!cmsMLUsetWide(DescriptionMLU, "en", "US", Description)) goto Error; - if (!cmsMLUsetWide(CopyrightMLU, "en", "US", L"No copyright, use freely")) goto Error; - - if (!cmsWriteTag(hProfile, cmsSigProfileDescriptionTag, DescriptionMLU)) goto Error; - if (!cmsWriteTag(hProfile, cmsSigCopyrightTag, CopyrightMLU)) goto Error; - - rc = TRUE; - -Error: - - if (DescriptionMLU) - cmsMLUfree(DescriptionMLU); - if (CopyrightMLU) - cmsMLUfree(CopyrightMLU); - return rc; -} - - -static -cmsBool SetSeqDescTag(cmsHPROFILE hProfile, const char* Model) -{ - cmsBool rc = FALSE; - cmsContext ContextID = cmsGetProfileContextID(hProfile); - cmsSEQ* Seq = cmsAllocProfileSequenceDescription(ContextID, 1); - - if (Seq == NULL) return FALSE; - - Seq->seq[0].deviceMfg = (cmsSignature) 0; - Seq->seq[0].deviceModel = (cmsSignature) 0; - -#ifdef CMS_DONT_USE_INT64 - Seq->seq[0].attributes[0] = 0; - Seq->seq[0].attributes[1] = 0; -#else - Seq->seq[0].attributes = 0; -#endif - - Seq->seq[0].technology = (cmsTechnologySignature) 0; - - cmsMLUsetASCII( Seq->seq[0].Manufacturer, cmsNoLanguage, cmsNoCountry, "Little CMS"); - cmsMLUsetASCII( Seq->seq[0].Model, cmsNoLanguage, cmsNoCountry, Model); - - if (!_cmsWriteProfileSequence(hProfile, Seq)) goto Error; - - rc = TRUE; - -Error: - if (Seq) - cmsFreeProfileSequenceDescription(Seq); - - return rc; -} - - - -// This function creates a profile based on White point, primaries and -// transfer functions. -cmsHPROFILE CMSEXPORT cmsCreateRGBProfileTHR(cmsContext ContextID, - const cmsCIExyY* WhitePoint, - const cmsCIExyYTRIPLE* Primaries, - cmsToneCurve* const TransferFunction[3]) -{ - cmsHPROFILE hICC; - cmsMAT3 MColorants; - cmsCIEXYZTRIPLE Colorants; - cmsCIExyY MaxWhite; - cmsMAT3 CHAD; - cmsCIEXYZ WhitePointXYZ; - - hICC = cmsCreateProfilePlaceholder(ContextID); - if (!hICC) // can't allocate - return NULL; - - cmsSetProfileVersion(hICC, 4.3); - - cmsSetDeviceClass(hICC, cmsSigDisplayClass); - cmsSetColorSpace(hICC, cmsSigRgbData); - cmsSetPCS(hICC, cmsSigXYZData); - - cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); - - - // Implement profile using following tags: - // - // 1 cmsSigProfileDescriptionTag - // 2 cmsSigMediaWhitePointTag - // 3 cmsSigRedColorantTag - // 4 cmsSigGreenColorantTag - // 5 cmsSigBlueColorantTag - // 6 cmsSigRedTRCTag - // 7 cmsSigGreenTRCTag - // 8 cmsSigBlueTRCTag - // 9 Chromatic adaptation Tag - // This conforms a standard RGB DisplayProfile as says ICC, and then I add (As per addendum II) - // 10 cmsSigChromaticityTag - - - if (!SetTextTags(hICC, L"RGB built-in")) goto Error; - - if (WhitePoint) { - - if (!cmsWriteTag(hICC, cmsSigMediaWhitePointTag, cmsD50_XYZ())) goto Error; - - cmsxyY2XYZ(&WhitePointXYZ, WhitePoint); - _cmsAdaptationMatrix(&CHAD, NULL, &WhitePointXYZ, cmsD50_XYZ()); - - // This is a V4 tag, but many CMM does read and understand it no matter which version - if (!cmsWriteTag(hICC, cmsSigChromaticAdaptationTag, (void*) &CHAD)) goto Error; - } - - if (WhitePoint && Primaries) { - - MaxWhite.x = WhitePoint -> x; - MaxWhite.y = WhitePoint -> y; - MaxWhite.Y = 1.0; - - if (!_cmsBuildRGB2XYZtransferMatrix(&MColorants, &MaxWhite, Primaries)) goto Error; - - Colorants.Red.X = MColorants.v[0].n[0]; - Colorants.Red.Y = MColorants.v[1].n[0]; - Colorants.Red.Z = MColorants.v[2].n[0]; - - Colorants.Green.X = MColorants.v[0].n[1]; - Colorants.Green.Y = MColorants.v[1].n[1]; - Colorants.Green.Z = MColorants.v[2].n[1]; - - Colorants.Blue.X = MColorants.v[0].n[2]; - Colorants.Blue.Y = MColorants.v[1].n[2]; - Colorants.Blue.Z = MColorants.v[2].n[2]; - - if (!cmsWriteTag(hICC, cmsSigRedColorantTag, (void*) &Colorants.Red)) goto Error; - if (!cmsWriteTag(hICC, cmsSigBlueColorantTag, (void*) &Colorants.Blue)) goto Error; - if (!cmsWriteTag(hICC, cmsSigGreenColorantTag, (void*) &Colorants.Green)) goto Error; - } - - - if (TransferFunction) { - - // Tries to minimize space. Thanks to Richard Hughes for this nice idea - if (!cmsWriteTag(hICC, cmsSigRedTRCTag, (void*) TransferFunction[0])) goto Error; - - if (TransferFunction[1] == TransferFunction[0]) { - - if (!cmsLinkTag (hICC, cmsSigGreenTRCTag, cmsSigRedTRCTag)) goto Error; - - } else { - - if (!cmsWriteTag(hICC, cmsSigGreenTRCTag, (void*) TransferFunction[1])) goto Error; - } - - if (TransferFunction[2] == TransferFunction[0]) { - - if (!cmsLinkTag (hICC, cmsSigBlueTRCTag, cmsSigRedTRCTag)) goto Error; - - } else { - - if (!cmsWriteTag(hICC, cmsSigBlueTRCTag, (void*) TransferFunction[2])) goto Error; - } - } - - if (Primaries) { - if (!cmsWriteTag(hICC, cmsSigChromaticityTag, (void*) Primaries)) goto Error; - } - - - return hICC; - -Error: - if (hICC) - cmsCloseProfile(hICC); - return NULL; -} - -cmsHPROFILE CMSEXPORT cmsCreateRGBProfile(const cmsCIExyY* WhitePoint, - const cmsCIExyYTRIPLE* Primaries, - cmsToneCurve* const TransferFunction[3]) -{ - return cmsCreateRGBProfileTHR(NULL, WhitePoint, Primaries, TransferFunction); -} - - - -// This function creates a profile based on White point and transfer function. -cmsHPROFILE CMSEXPORT cmsCreateGrayProfileTHR(cmsContext ContextID, - const cmsCIExyY* WhitePoint, - const cmsToneCurve* TransferFunction) -{ - cmsHPROFILE hICC; - cmsCIEXYZ tmp; - - hICC = cmsCreateProfilePlaceholder(ContextID); - if (!hICC) // can't allocate - return NULL; - - cmsSetProfileVersion(hICC, 4.3); - - cmsSetDeviceClass(hICC, cmsSigDisplayClass); - cmsSetColorSpace(hICC, cmsSigGrayData); - cmsSetPCS(hICC, cmsSigXYZData); - cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); - - - // Implement profile using following tags: - // - // 1 cmsSigProfileDescriptionTag - // 2 cmsSigMediaWhitePointTag - // 3 cmsSigGrayTRCTag - - // This conforms a standard Gray DisplayProfile - - // Fill-in the tags - - if (!SetTextTags(hICC, L"gray built-in")) goto Error; - - - if (WhitePoint) { - - cmsxyY2XYZ(&tmp, WhitePoint); - if (!cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) &tmp)) goto Error; - } - - if (TransferFunction) { - - if (!cmsWriteTag(hICC, cmsSigGrayTRCTag, (void*) TransferFunction)) goto Error; - } - - return hICC; - -Error: - if (hICC) - cmsCloseProfile(hICC); - return NULL; -} - - - -cmsHPROFILE CMSEXPORT cmsCreateGrayProfile(const cmsCIExyY* WhitePoint, - const cmsToneCurve* TransferFunction) -{ - return cmsCreateGrayProfileTHR(NULL, WhitePoint, TransferFunction); -} - -// This is a devicelink operating in the target colorspace with as many transfer functions as components - -cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID, - cmsColorSpaceSignature ColorSpace, - cmsToneCurve* const TransferFunctions[]) -{ - cmsHPROFILE hICC; - cmsPipeline* Pipeline; - int nChannels; - - hICC = cmsCreateProfilePlaceholder(ContextID); - if (!hICC) - return NULL; - - cmsSetProfileVersion(hICC, 4.3); - - cmsSetDeviceClass(hICC, cmsSigLinkClass); - cmsSetColorSpace(hICC, ColorSpace); - cmsSetPCS(hICC, ColorSpace); - - cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); - - // Set up channels - nChannels = cmsChannelsOf(ColorSpace); - - // Creates a Pipeline with prelinearization step only - Pipeline = cmsPipelineAlloc(ContextID, nChannels, nChannels); - if (Pipeline == NULL) goto Error; - - - // Copy tables to Pipeline - if (!cmsPipelineInsertStage(Pipeline, cmsAT_BEGIN, cmsStageAllocToneCurves(ContextID, nChannels, TransferFunctions))) - goto Error; - - // Create tags - if (!SetTextTags(hICC, L"Linearization built-in")) goto Error; - if (!cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline)) goto Error; - if (!SetSeqDescTag(hICC, "Linearization built-in")) goto Error; - - // Pipeline is already on virtual profile - cmsPipelineFree(Pipeline); - - // Ok, done - return hICC; - -Error: - cmsPipelineFree(Pipeline); - if (hICC) - cmsCloseProfile(hICC); - - - return NULL; -} - -cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLink(cmsColorSpaceSignature ColorSpace, - cmsToneCurve* const TransferFunctions[]) -{ - return cmsCreateLinearizationDeviceLinkTHR(NULL, ColorSpace, TransferFunctions); -} - -// Ink-limiting algorithm -// -// Sum = C + M + Y + K -// If Sum > InkLimit -// Ratio= 1 - (Sum - InkLimit) / (C + M + Y) -// if Ratio <0 -// Ratio=0 -// endif -// Else -// Ratio=1 -// endif -// -// C = Ratio * C -// M = Ratio * M -// Y = Ratio * Y -// K: Does not change - -static -int InkLimitingSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) -{ - cmsFloat64Number InkLimit = *(cmsFloat64Number *) Cargo; - cmsFloat64Number SumCMY, SumCMYK, Ratio; - - InkLimit = (InkLimit * 655.35); - - SumCMY = In[0] + In[1] + In[2]; - SumCMYK = SumCMY + In[3]; - - if (SumCMYK > InkLimit) { - - Ratio = 1 - ((SumCMYK - InkLimit) / SumCMY); - if (Ratio < 0) - Ratio = 0; - } - else Ratio = 1; - - Out[0] = _cmsQuickSaturateWord(In[0] * Ratio); // C - Out[1] = _cmsQuickSaturateWord(In[1] * Ratio); // M - Out[2] = _cmsQuickSaturateWord(In[2] * Ratio); // Y - - Out[3] = In[3]; // K (untouched) - - return TRUE; -} - -// This is a devicelink operating in CMYK for ink-limiting - -cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID, - cmsColorSpaceSignature ColorSpace, - cmsFloat64Number Limit) -{ - cmsHPROFILE hICC; - cmsPipeline* LUT; - cmsStage* CLUT; - int nChannels; - - if (ColorSpace != cmsSigCmykData) { - cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "InkLimiting: Only CMYK currently supported"); - return NULL; - } - - if (Limit < 0.0 || Limit > 400) { - - cmsSignalError(ContextID, cmsERROR_RANGE, "InkLimiting: Limit should be between 0..400"); - if (Limit < 0) Limit = 0; - if (Limit > 400) Limit = 400; - - } - - hICC = cmsCreateProfilePlaceholder(ContextID); - if (!hICC) // can't allocate - return NULL; - - cmsSetProfileVersion(hICC, 4.3); - - cmsSetDeviceClass(hICC, cmsSigLinkClass); - cmsSetColorSpace(hICC, ColorSpace); - cmsSetPCS(hICC, ColorSpace); - - cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); - - - // Creates a Pipeline with 3D grid only - LUT = cmsPipelineAlloc(ContextID, 4, 4); - if (LUT == NULL) goto Error; - - - nChannels = cmsChannelsOf(ColorSpace); - - CLUT = cmsStageAllocCLut16bit(ContextID, 17, nChannels, nChannels, NULL); - if (CLUT == NULL) goto Error; - - if (!cmsStageSampleCLut16bit(CLUT, InkLimitingSampler, (void*) &Limit, 0)) goto Error; - - if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, nChannels)) || - !cmsPipelineInsertStage(LUT, cmsAT_END, CLUT) || - !cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, nChannels))) - goto Error; - - // Create tags - if (!SetTextTags(hICC, L"ink-limiting built-in")) goto Error; - - if (!cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) LUT)) goto Error; - if (!SetSeqDescTag(hICC, "ink-limiting built-in")) goto Error; - - // cmsPipeline is already on virtual profile - cmsPipelineFree(LUT); - - // Ok, done - return hICC; - -Error: - if (LUT != NULL) - cmsPipelineFree(LUT); - - if (hICC != NULL) - cmsCloseProfile(hICC); - - return NULL; -} - -cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLink(cmsColorSpaceSignature ColorSpace, cmsFloat64Number Limit) -{ - return cmsCreateInkLimitingDeviceLinkTHR(NULL, ColorSpace, Limit); -} - - -// Creates a fake Lab identity. -cmsHPROFILE CMSEXPORT cmsCreateLab2ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint) -{ - cmsHPROFILE hProfile; - cmsPipeline* LUT = NULL; - - hProfile = cmsCreateRGBProfileTHR(ContextID, WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL); - if (hProfile == NULL) return NULL; - - cmsSetProfileVersion(hProfile, 2.1); - - cmsSetDeviceClass(hProfile, cmsSigAbstractClass); - cmsSetColorSpace(hProfile, cmsSigLabData); - cmsSetPCS(hProfile, cmsSigLabData); - - if (!SetTextTags(hProfile, L"Lab identity built-in")) return NULL; - - // An identity LUT is all we need - LUT = cmsPipelineAlloc(ContextID, 3, 3); - if (LUT == NULL) goto Error; - - if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCLut(ContextID, 3))) - goto Error; - - if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error; - cmsPipelineFree(LUT); - - return hProfile; - -Error: - - if (LUT != NULL) - cmsPipelineFree(LUT); - - if (hProfile != NULL) - cmsCloseProfile(hProfile); - - return NULL; -} - - -cmsHPROFILE CMSEXPORT cmsCreateLab2Profile(const cmsCIExyY* WhitePoint) -{ - return cmsCreateLab2ProfileTHR(NULL, WhitePoint); -} - - -// Creates a fake Lab V4 identity. -cmsHPROFILE CMSEXPORT cmsCreateLab4ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint) -{ - cmsHPROFILE hProfile; - cmsPipeline* LUT = NULL; - - hProfile = cmsCreateRGBProfileTHR(ContextID, WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL); - if (hProfile == NULL) return NULL; - - cmsSetProfileVersion(hProfile, 4.3); - - cmsSetDeviceClass(hProfile, cmsSigAbstractClass); - cmsSetColorSpace(hProfile, cmsSigLabData); - cmsSetPCS(hProfile, cmsSigLabData); - - if (!SetTextTags(hProfile, L"Lab identity built-in")) goto Error; - - // An empty LUTs is all we need - LUT = cmsPipelineAlloc(ContextID, 3, 3); - if (LUT == NULL) goto Error; - - if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3))) - goto Error; - - if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error; - cmsPipelineFree(LUT); - - return hProfile; - -Error: - - if (LUT != NULL) - cmsPipelineFree(LUT); - - if (hProfile != NULL) - cmsCloseProfile(hProfile); - - return NULL; -} - -cmsHPROFILE CMSEXPORT cmsCreateLab4Profile(const cmsCIExyY* WhitePoint) -{ - return cmsCreateLab4ProfileTHR(NULL, WhitePoint); -} - - -// Creates a fake XYZ identity -cmsHPROFILE CMSEXPORT cmsCreateXYZProfileTHR(cmsContext ContextID) -{ - cmsHPROFILE hProfile; - cmsPipeline* LUT = NULL; - - hProfile = cmsCreateRGBProfileTHR(ContextID, cmsD50_xyY(), NULL, NULL); - if (hProfile == NULL) return NULL; - - cmsSetProfileVersion(hProfile, 4.3); - - cmsSetDeviceClass(hProfile, cmsSigAbstractClass); - cmsSetColorSpace(hProfile, cmsSigXYZData); - cmsSetPCS(hProfile, cmsSigXYZData); - - if (!SetTextTags(hProfile, L"XYZ identity built-in")) goto Error; - - // An identity LUT is all we need - LUT = cmsPipelineAlloc(ContextID, 3, 3); - if (LUT == NULL) goto Error; - - if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3))) - goto Error; - - if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error; - cmsPipelineFree(LUT); - - return hProfile; - -Error: - - if (LUT != NULL) - cmsPipelineFree(LUT); - - if (hProfile != NULL) - cmsCloseProfile(hProfile); - - return NULL; -} - - -cmsHPROFILE CMSEXPORT cmsCreateXYZProfile(void) -{ - return cmsCreateXYZProfileTHR(NULL); -} - - -//sRGB Curves are defined by: -// -//If R'sRGB,G'sRGB, B'sRGB < 0.04045 -// -// R = R'sRGB / 12.92 -// G = G'sRGB / 12.92 -// B = B'sRGB / 12.92 -// -// -//else if R'sRGB,G'sRGB, B'sRGB >= 0.04045 -// -// R = ((R'sRGB + 0.055) / 1.055)^2.4 -// G = ((G'sRGB + 0.055) / 1.055)^2.4 -// B = ((B'sRGB + 0.055) / 1.055)^2.4 - -static -cmsToneCurve* Build_sRGBGamma(cmsContext ContextID) -{ - cmsFloat64Number Parameters[5]; - - Parameters[0] = 2.4; - Parameters[1] = 1. / 1.055; - Parameters[2] = 0.055 / 1.055; - Parameters[3] = 1. / 12.92; - Parameters[4] = 0.04045; - - return cmsBuildParametricToneCurve(ContextID, 4, Parameters); -} - -// Create the ICC virtual profile for sRGB space -cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID) -{ - cmsCIExyY D65; - cmsCIExyYTRIPLE Rec709Primaries = { - {0.6400, 0.3300, 1.0}, - {0.3000, 0.6000, 1.0}, - {0.1500, 0.0600, 1.0} - }; - cmsToneCurve* Gamma22[3]; - cmsHPROFILE hsRGB; - - cmsWhitePointFromTemp(&D65, 6504); - Gamma22[0] = Gamma22[1] = Gamma22[2] = Build_sRGBGamma(ContextID); - if (Gamma22[0] == NULL) return NULL; - - hsRGB = cmsCreateRGBProfileTHR(ContextID, &D65, &Rec709Primaries, Gamma22); - cmsFreeToneCurve(Gamma22[0]); - if (hsRGB == NULL) return NULL; - - if (!SetTextTags(hsRGB, L"sRGB built-in")) { - cmsCloseProfile(hsRGB); - return NULL; - } - - return hsRGB; -} - -cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfile(void) -{ - return cmsCreate_sRGBProfileTHR(NULL); -} - - - -typedef struct { - cmsFloat64Number Brightness; - cmsFloat64Number Contrast; - cmsFloat64Number Hue; - cmsFloat64Number Saturation; - cmsCIEXYZ WPsrc, WPdest; - -} BCHSWADJUSTS, *LPBCHSWADJUSTS; - - -static -int bchswSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) -{ - cmsCIELab LabIn, LabOut; - cmsCIELCh LChIn, LChOut; - cmsCIEXYZ XYZ; - LPBCHSWADJUSTS bchsw = (LPBCHSWADJUSTS) Cargo; - - - cmsLabEncoded2Float(&LabIn, In); - - - cmsLab2LCh(&LChIn, &LabIn); - - // Do some adjusts on LCh - - LChOut.L = LChIn.L * bchsw ->Contrast + bchsw ->Brightness; - LChOut.C = LChIn.C + bchsw -> Saturation; - LChOut.h = LChIn.h + bchsw -> Hue; - - - cmsLCh2Lab(&LabOut, &LChOut); - - // Move white point in Lab - - cmsLab2XYZ(&bchsw ->WPsrc, &XYZ, &LabOut); - cmsXYZ2Lab(&bchsw ->WPdest, &LabOut, &XYZ); - - // Back to encoded - - cmsFloat2LabEncoded(Out, &LabOut); - - return TRUE; -} - - -// Creates an abstract profile operating in Lab space for Brightness, -// contrast, Saturation and white point displacement - -cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID, - int nLUTPoints, - cmsFloat64Number Bright, - cmsFloat64Number Contrast, - cmsFloat64Number Hue, - cmsFloat64Number Saturation, - int TempSrc, - int TempDest) -{ - cmsHPROFILE hICC; - cmsPipeline* Pipeline; - BCHSWADJUSTS bchsw; - cmsCIExyY WhitePnt; - cmsStage* CLUT; - cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; - int i; - - bchsw.Brightness = Bright; - bchsw.Contrast = Contrast; - bchsw.Hue = Hue; - bchsw.Saturation = Saturation; - - cmsWhitePointFromTemp(&WhitePnt, TempSrc ); - cmsxyY2XYZ(&bchsw.WPsrc, &WhitePnt); - - cmsWhitePointFromTemp(&WhitePnt, TempDest); - cmsxyY2XYZ(&bchsw.WPdest, &WhitePnt); - - hICC = cmsCreateProfilePlaceholder(ContextID); - if (!hICC) // can't allocate - return NULL; - - - cmsSetDeviceClass(hICC, cmsSigAbstractClass); - cmsSetColorSpace(hICC, cmsSigLabData); - cmsSetPCS(hICC, cmsSigLabData); - - cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); - - // Creates a Pipeline with 3D grid only - Pipeline = cmsPipelineAlloc(ContextID, 3, 3); - if (Pipeline == NULL) { - cmsCloseProfile(hICC); - return NULL; - } - - for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Dimensions[i] = nLUTPoints; - CLUT = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 3, 3, NULL); - if (CLUT == NULL) return NULL; - - - if (!cmsStageSampleCLut16bit(CLUT, bchswSampler, (void*) &bchsw, 0)) { - - // Shouldn't reach here - goto Error; - } - - if (!cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT)) { - goto Error; - } - - // Create tags - if (!SetTextTags(hICC, L"BCHS built-in")) return NULL; - - cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) cmsD50_XYZ()); - - cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline); - - // Pipeline is already on virtual profile - cmsPipelineFree(Pipeline); - - // Ok, done - return hICC; - -Error: - cmsPipelineFree(Pipeline); - cmsCloseProfile(hICC); - return NULL; -} - - -CMSAPI cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfile(int nLUTPoints, - cmsFloat64Number Bright, - cmsFloat64Number Contrast, - cmsFloat64Number Hue, - cmsFloat64Number Saturation, - int TempSrc, - int TempDest) -{ - return cmsCreateBCHSWabstractProfileTHR(NULL, nLUTPoints, Bright, Contrast, Hue, Saturation, TempSrc, TempDest); -} - - -// Creates a fake NULL profile. This profile return 1 channel as always 0. -// Is useful only for gamut checking tricks -cmsHPROFILE CMSEXPORT cmsCreateNULLProfileTHR(cmsContext ContextID) -{ - cmsHPROFILE hProfile; - cmsPipeline* LUT = NULL; - cmsStage* PostLin; - cmsToneCurve* EmptyTab; - cmsUInt16Number Zero[2] = { 0, 0 }; - - hProfile = cmsCreateProfilePlaceholder(ContextID); - if (!hProfile) // can't allocate - return NULL; - - cmsSetProfileVersion(hProfile, 4.3); - - if (!SetTextTags(hProfile, L"NULL profile built-in")) goto Error; - - - - cmsSetDeviceClass(hProfile, cmsSigOutputClass); - cmsSetColorSpace(hProfile, cmsSigGrayData); - cmsSetPCS(hProfile, cmsSigLabData); - - // An empty LUTs is all we need - LUT = cmsPipelineAlloc(ContextID, 1, 1); - if (LUT == NULL) goto Error; - - EmptyTab = cmsBuildTabulatedToneCurve16(ContextID, 2, Zero); - PostLin = cmsStageAllocToneCurves(ContextID, 1, &EmptyTab); - cmsFreeToneCurve(EmptyTab); - - if (!cmsPipelineInsertStage(LUT, cmsAT_END, PostLin)) - goto Error; - - if (!cmsWriteTag(hProfile, cmsSigBToA0Tag, (void*) LUT)) goto Error; - if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, cmsD50_XYZ())) goto Error; - - cmsPipelineFree(LUT); - return hProfile; - -Error: - - if (LUT != NULL) - cmsPipelineFree(LUT); - - if (hProfile != NULL) - cmsCloseProfile(hProfile); - - return NULL; -} - -cmsHPROFILE CMSEXPORT cmsCreateNULLProfile(void) -{ - return cmsCreateNULLProfileTHR(NULL); -} - - -static -int IsPCS(cmsColorSpaceSignature ColorSpace) -{ - return (ColorSpace == cmsSigXYZData || - ColorSpace == cmsSigLabData); -} - - -static -void FixColorSpaces(cmsHPROFILE hProfile, - cmsColorSpaceSignature ColorSpace, - cmsColorSpaceSignature PCS, - cmsUInt32Number dwFlags) -{ - if (dwFlags & cmsFLAGS_GUESSDEVICECLASS) { - - if (IsPCS(ColorSpace) && IsPCS(PCS)) { - - cmsSetDeviceClass(hProfile, cmsSigAbstractClass); - cmsSetColorSpace(hProfile, ColorSpace); - cmsSetPCS(hProfile, PCS); - return; - } - - if (IsPCS(ColorSpace) && !IsPCS(PCS)) { - - cmsSetDeviceClass(hProfile, cmsSigOutputClass); - cmsSetPCS(hProfile, ColorSpace); - cmsSetColorSpace(hProfile, PCS); - return; - } - - if (IsPCS(PCS) && !IsPCS(ColorSpace)) { - - cmsSetDeviceClass(hProfile, cmsSigInputClass); - cmsSetColorSpace(hProfile, ColorSpace); - cmsSetPCS(hProfile, PCS); - return; - } - } - - cmsSetDeviceClass(hProfile, cmsSigLinkClass); - cmsSetColorSpace(hProfile, ColorSpace); - cmsSetPCS(hProfile, PCS); -} - - - -// This function creates a named color profile dumping all the contents of transform to a single profile -// In this way, LittleCMS may be used to "group" several named color databases into a single profile. -// It has, however, several minor limitations. PCS is always Lab, which is not very critic since this -// is the normal PCS for named color profiles. -static -cmsHPROFILE CreateNamedColorDevicelink(cmsHTRANSFORM xform) -{ - _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform; - cmsHPROFILE hICC = NULL; - int i, nColors; - cmsNAMEDCOLORLIST *nc2 = NULL, *Original = NULL; - - // Create an empty placeholder - hICC = cmsCreateProfilePlaceholder(v->ContextID); - if (hICC == NULL) return NULL; - - // Critical information - cmsSetDeviceClass(hICC, cmsSigNamedColorClass); - cmsSetColorSpace(hICC, v ->ExitColorSpace); - cmsSetPCS(hICC, cmsSigLabData); - - // Tag profile with information - if (!SetTextTags(hICC, L"Named color devicelink")) goto Error; - - Original = cmsGetNamedColorList(xform); - if (Original == NULL) goto Error; - - nColors = cmsNamedColorCount(Original); - nc2 = cmsDupNamedColorList(Original); - if (nc2 == NULL) goto Error; - - // Colorant count now depends on the output space - nc2 ->ColorantCount = cmsPipelineOutputChannels(v ->Lut); - - // Make sure we have proper formatters - cmsChangeBuffersFormat(xform, TYPE_NAMED_COLOR_INDEX, - FLOAT_SH(0) | COLORSPACE_SH(_cmsLCMScolorSpace(v ->ExitColorSpace)) - | BYTES_SH(2) | CHANNELS_SH(cmsChannelsOf(v ->ExitColorSpace))); - - // Apply the transfor to colorants. - for (i=0; i < nColors; i++) { - cmsDoTransform(xform, &i, nc2 ->List[i].DeviceColorant, 1); - } - - if (!cmsWriteTag(hICC, cmsSigNamedColor2Tag, (void*) nc2)) goto Error; - cmsFreeNamedColorList(nc2); - - return hICC; - -Error: - if (hICC != NULL) cmsCloseProfile(hICC); - return NULL; -} - - -// This structure holds information about which MPU can be stored on a profile based on the version - -typedef struct { - cmsBool IsV4; // Is a V4 tag? - cmsTagSignature RequiredTag; // Set to 0 for both types - cmsTagTypeSignature LutType; // The LUT type - int nTypes; // Number of types (up to 5) - cmsStageSignature MpeTypes[5]; // 5 is the maximum number - -} cmsAllowedLUT; - -static const cmsAllowedLUT AllowedLUTTypes[] = { - - { FALSE, 0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, - { FALSE, 0, cmsSigLut16Type, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, - { FALSE, 0, cmsSigLut16Type, 2, { cmsSigCurveSetElemType, cmsSigCLutElemType}}, - { TRUE , 0, cmsSigLutAtoBType, 1, { cmsSigCurveSetElemType }}, - { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType } }, - { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } }, - { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 5, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }}, - { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 1, { cmsSigCurveSetElemType }}, - { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 3, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }}, - { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType }}, - { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 5, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType }} -}; - -#define SIZE_OF_ALLOWED_LUT (sizeof(AllowedLUTTypes)/sizeof(cmsAllowedLUT)) - -// Check a single entry -static -cmsBool CheckOne(const cmsAllowedLUT* Tab, const cmsPipeline* Lut) -{ - cmsStage* mpe; - int n; - - for (n=0, mpe = Lut ->Elements; mpe != NULL; mpe = mpe ->Next, n++) { - - if (n > Tab ->nTypes) return FALSE; - if (cmsStageType(mpe) != Tab ->MpeTypes[n]) return FALSE; - } - - return (n == Tab ->nTypes); -} - - -static -const cmsAllowedLUT* FindCombination(const cmsPipeline* Lut, cmsBool IsV4, cmsTagSignature DestinationTag) -{ - cmsUInt32Number n; - - for (n=0; n < SIZE_OF_ALLOWED_LUT; n++) { - - const cmsAllowedLUT* Tab = AllowedLUTTypes + n; - - if (IsV4 ^ Tab -> IsV4) continue; - if ((Tab ->RequiredTag != 0) && (Tab ->RequiredTag != DestinationTag)) continue; - - if (CheckOne(Tab, Lut)) return Tab; - } - - return NULL; -} - - -// Does convert a transform into a device link profile -cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat64Number Version, cmsUInt32Number dwFlags) -{ - cmsHPROFILE hProfile = NULL; - cmsUInt32Number FrmIn, FrmOut, ChansIn, ChansOut; - cmsUInt32Number ColorSpaceBitsIn, ColorSpaceBitsOut; - _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform; - cmsPipeline* LUT = NULL; - cmsStage* mpe; - cmsContext ContextID = cmsGetTransformContextID(hTransform); - const cmsAllowedLUT* AllowedLUT; - cmsTagSignature DestinationTag; - cmsProfileClassSignature deviceClass; - - _cmsAssert(hTransform != NULL); - - // Get the first mpe to check for named color - mpe = cmsPipelineGetPtrToFirstStage(xform ->Lut); - - // Check if is a named color transform - if (mpe != NULL) { - - if (cmsStageType(mpe) == cmsSigNamedColorElemType) { - return CreateNamedColorDevicelink(hTransform); - } - } - - // First thing to do is to get a copy of the transformation - LUT = cmsPipelineDup(xform ->Lut); - if (LUT == NULL) return NULL; - - // Time to fix the Lab2/Lab4 issue. - if ((xform ->EntryColorSpace == cmsSigLabData) && (Version < 4.0)) { - - if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocLabV2ToV4curves(ContextID))) - goto Error; - } - - // On the output side too - if ((xform ->ExitColorSpace) == cmsSigLabData && (Version < 4.0)) { - - if (!cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocLabV4ToV2(ContextID))) - goto Error; - } - - - hProfile = cmsCreateProfilePlaceholder(ContextID); - if (!hProfile) goto Error; // can't allocate - - cmsSetProfileVersion(hProfile, Version); - - FixColorSpaces(hProfile, xform -> EntryColorSpace, xform -> ExitColorSpace, dwFlags); - - // Optimize the LUT and precalculate a devicelink - - ChansIn = cmsChannelsOf(xform -> EntryColorSpace); - ChansOut = cmsChannelsOf(xform -> ExitColorSpace); - - ColorSpaceBitsIn = _cmsLCMScolorSpace(xform -> EntryColorSpace); - ColorSpaceBitsOut = _cmsLCMScolorSpace(xform -> ExitColorSpace); - - FrmIn = COLORSPACE_SH(ColorSpaceBitsIn) | CHANNELS_SH(ChansIn)|BYTES_SH(2); - FrmOut = COLORSPACE_SH(ColorSpaceBitsOut) | CHANNELS_SH(ChansOut)|BYTES_SH(2); - - deviceClass = cmsGetDeviceClass(hProfile); - - if (deviceClass == cmsSigOutputClass) - DestinationTag = cmsSigBToA0Tag; - else - DestinationTag = cmsSigAToB0Tag; - - // Check if the profile/version can store the result - if (dwFlags & cmsFLAGS_FORCE_CLUT) - AllowedLUT = NULL; - else - AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag); - - if (AllowedLUT == NULL) { - - // Try to optimize - _cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); - AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag); - - } - - // If no way, then force CLUT that for sure can be written - if (AllowedLUT == NULL) { - - dwFlags |= cmsFLAGS_FORCE_CLUT; - _cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); - - // Put identity curves if needed - if (cmsPipelineGetPtrToFirstStage(LUT) ->Type != cmsSigCurveSetElemType) - if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, ChansIn))) - goto Error; - - if (cmsPipelineGetPtrToLastStage(LUT) ->Type != cmsSigCurveSetElemType) - if (!cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, ChansOut))) - goto Error; - - AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag); - } - - // Somethings is wrong... - if (AllowedLUT == NULL) { - goto Error; - } - - - if (dwFlags & cmsFLAGS_8BITS_DEVICELINK) - cmsPipelineSetSaveAs8bitsFlag(LUT, TRUE); - - // Tag profile with information - if (!SetTextTags(hProfile, L"devicelink")) goto Error; - - // Store result - if (!cmsWriteTag(hProfile, DestinationTag, LUT)) goto Error; - - - if (xform -> InputColorant != NULL) { - if (!cmsWriteTag(hProfile, cmsSigColorantTableTag, xform->InputColorant)) goto Error; - } - - if (xform -> OutputColorant != NULL) { - if (!cmsWriteTag(hProfile, cmsSigColorantTableOutTag, xform->OutputColorant)) goto Error; - } - - if ((deviceClass == cmsSigLinkClass) && (xform ->Sequence != NULL)) { - if (!_cmsWriteProfileSequence(hProfile, xform ->Sequence)) goto Error; - } - - // Set the white point - if (deviceClass == cmsSigInputClass) { - if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, &xform ->EntryWhitePoint)) goto Error; - } - else { - if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, &xform ->ExitWhitePoint)) goto Error; - } - - - // Per 7.2.15 in spec 4.3 - cmsSetHeaderRenderingIntent(hProfile, xform ->RenderingIntent); - - cmsPipelineFree(LUT); - return hProfile; - -Error: - if (LUT != NULL) cmsPipelineFree(LUT); - cmsCloseProfile(hProfile); - return NULL; -} diff --git a/third_party/lcms2-2.6/src/cmswtpnt.c b/third_party/lcms2-2.6/src/cmswtpnt.c deleted file mode 100644 index 903fdd7497..0000000000 --- a/third_party/lcms2-2.6/src/cmswtpnt.c +++ /dev/null @@ -1,349 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2014 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- -// - -#include "lcms2_internal.h" - - -// D50 - Widely used -const cmsCIEXYZ* CMSEXPORT cmsD50_XYZ(void) -{ - static cmsCIEXYZ D50XYZ = {cmsD50X, cmsD50Y, cmsD50Z}; - - return &D50XYZ; -} - -const cmsCIExyY* CMSEXPORT cmsD50_xyY(void) -{ - static cmsCIExyY D50xyY; - - cmsXYZ2xyY(&D50xyY, cmsD50_XYZ()); - - return &D50xyY; -} - -// Obtains WhitePoint from Temperature -cmsBool CMSEXPORT cmsWhitePointFromTemp(cmsCIExyY* WhitePoint, cmsFloat64Number TempK) -{ - cmsFloat64Number x, y; - cmsFloat64Number T, T2, T3; - // cmsFloat64Number M1, M2; - - _cmsAssert(WhitePoint != NULL); - - T = TempK; - T2 = T*T; // Square - T3 = T2*T; // Cube - - // For correlated color temperature (T) between 4000K and 7000K: - - if (T >= 4000. && T <= 7000.) - { - x = -4.6070*(1E9/T3) + 2.9678*(1E6/T2) + 0.09911*(1E3/T) + 0.244063; - } - else - // or for correlated color temperature (T) between 7000K and 25000K: - - if (T > 7000.0 && T <= 25000.0) - { - x = -2.0064*(1E9/T3) + 1.9018*(1E6/T2) + 0.24748*(1E3/T) + 0.237040; - } - else { - cmsSignalError(0, cmsERROR_RANGE, "cmsWhitePointFromTemp: invalid temp"); - return FALSE; - } - - // Obtain y(x) - - y = -3.000*(x*x) + 2.870*x - 0.275; - - // wave factors (not used, but here for futures extensions) - - // M1 = (-1.3515 - 1.7703*x + 5.9114 *y)/(0.0241 + 0.2562*x - 0.7341*y); - // M2 = (0.0300 - 31.4424*x + 30.0717*y)/(0.0241 + 0.2562*x - 0.7341*y); - - WhitePoint -> x = x; - WhitePoint -> y = y; - WhitePoint -> Y = 1.0; - - return TRUE; -} - - - -typedef struct { - - cmsFloat64Number mirek; // temp (in microreciprocal kelvin) - cmsFloat64Number ut; // u coord of intersection w/ blackbody locus - cmsFloat64Number vt; // v coord of intersection w/ blackbody locus - cmsFloat64Number tt; // slope of ISOTEMPERATURE. line - - } ISOTEMPERATURE; - -static ISOTEMPERATURE isotempdata[] = { -// {Mirek, Ut, Vt, Tt } - {0, 0.18006, 0.26352, -0.24341}, - {10, 0.18066, 0.26589, -0.25479}, - {20, 0.18133, 0.26846, -0.26876}, - {30, 0.18208, 0.27119, -0.28539}, - {40, 0.18293, 0.27407, -0.30470}, - {50, 0.18388, 0.27709, -0.32675}, - {60, 0.18494, 0.28021, -0.35156}, - {70, 0.18611, 0.28342, -0.37915}, - {80, 0.18740, 0.28668, -0.40955}, - {90, 0.18880, 0.28997, -0.44278}, - {100, 0.19032, 0.29326, -0.47888}, - {125, 0.19462, 0.30141, -0.58204}, - {150, 0.19962, 0.30921, -0.70471}, - {175, 0.20525, 0.31647, -0.84901}, - {200, 0.21142, 0.32312, -1.0182 }, - {225, 0.21807, 0.32909, -1.2168 }, - {250, 0.22511, 0.33439, -1.4512 }, - {275, 0.23247, 0.33904, -1.7298 }, - {300, 0.24010, 0.34308, -2.0637 }, - {325, 0.24702, 0.34655, -2.4681 }, - {350, 0.25591, 0.34951, -2.9641 }, - {375, 0.26400, 0.35200, -3.5814 }, - {400, 0.27218, 0.35407, -4.3633 }, - {425, 0.28039, 0.35577, -5.3762 }, - {450, 0.28863, 0.35714, -6.7262 }, - {475, 0.29685, 0.35823, -8.5955 }, - {500, 0.30505, 0.35907, -11.324 }, - {525, 0.31320, 0.35968, -15.628 }, - {550, 0.32129, 0.36011, -23.325 }, - {575, 0.32931, 0.36038, -40.770 }, - {600, 0.33724, 0.36051, -116.45 } -}; - -#define NISO sizeof(isotempdata)/sizeof(ISOTEMPERATURE) - - -// Robertson's method -cmsBool CMSEXPORT cmsTempFromWhitePoint(cmsFloat64Number* TempK, const cmsCIExyY* WhitePoint) -{ - cmsUInt32Number j; - cmsFloat64Number us,vs; - cmsFloat64Number uj,vj,tj,di,dj,mi,mj; - cmsFloat64Number xs, ys; - - _cmsAssert(WhitePoint != NULL); - _cmsAssert(TempK != NULL); - - di = mi = 0; - xs = WhitePoint -> x; - ys = WhitePoint -> y; - - // convert (x,y) to CIE 1960 (u,WhitePoint) - - us = (2*xs) / (-xs + 6*ys + 1.5); - vs = (3*ys) / (-xs + 6*ys + 1.5); - - - for (j=0; j < NISO; j++) { - - uj = isotempdata[j].ut; - vj = isotempdata[j].vt; - tj = isotempdata[j].tt; - mj = isotempdata[j].mirek; - - dj = ((vs - vj) - tj * (us - uj)) / sqrt(1.0 + tj * tj); - - if ((j != 0) && (di/dj < 0.0)) { - - // Found a match - *TempK = 1000000.0 / (mi + (di / (di - dj)) * (mj - mi)); - return TRUE; - } - - di = dj; - mi = mj; - } - - // Not found - return FALSE; -} - - -// Compute chromatic adaptation matrix using Chad as cone matrix - -static -cmsBool ComputeChromaticAdaptation(cmsMAT3* Conversion, - const cmsCIEXYZ* SourceWhitePoint, - const cmsCIEXYZ* DestWhitePoint, - const cmsMAT3* Chad) - -{ - - cmsMAT3 Chad_Inv; - cmsVEC3 ConeSourceXYZ, ConeSourceRGB; - cmsVEC3 ConeDestXYZ, ConeDestRGB; - cmsMAT3 Cone, Tmp; - - - Tmp = *Chad; - if (!_cmsMAT3inverse(&Tmp, &Chad_Inv)) return FALSE; - - _cmsVEC3init(&ConeSourceXYZ, SourceWhitePoint -> X, - SourceWhitePoint -> Y, - SourceWhitePoint -> Z); - - _cmsVEC3init(&ConeDestXYZ, DestWhitePoint -> X, - DestWhitePoint -> Y, - DestWhitePoint -> Z); - - _cmsMAT3eval(&ConeSourceRGB, Chad, &ConeSourceXYZ); - _cmsMAT3eval(&ConeDestRGB, Chad, &ConeDestXYZ); - - // Build matrix - _cmsVEC3init(&Cone.v[0], ConeDestRGB.n[0]/ConeSourceRGB.n[0], 0.0, 0.0); - _cmsVEC3init(&Cone.v[1], 0.0, ConeDestRGB.n[1]/ConeSourceRGB.n[1], 0.0); - _cmsVEC3init(&Cone.v[2], 0.0, 0.0, ConeDestRGB.n[2]/ConeSourceRGB.n[2]); - - - // Normalize - _cmsMAT3per(&Tmp, &Cone, Chad); - _cmsMAT3per(Conversion, &Chad_Inv, &Tmp); - - return TRUE; -} - -// Returns the final chrmatic adaptation from illuminant FromIll to Illuminant ToIll -// The cone matrix can be specified in ConeMatrix. If NULL, Bradford is assumed -cmsBool _cmsAdaptationMatrix(cmsMAT3* r, const cmsMAT3* ConeMatrix, const cmsCIEXYZ* FromIll, const cmsCIEXYZ* ToIll) -{ - cmsMAT3 LamRigg = {{ // Bradford matrix - {{ 0.8951, 0.2664, -0.1614 }}, - {{ -0.7502, 1.7135, 0.0367 }}, - {{ 0.0389, -0.0685, 1.0296 }} - }}; - - if (ConeMatrix == NULL) - ConeMatrix = &LamRigg; - - return ComputeChromaticAdaptation(r, FromIll, ToIll, ConeMatrix); -} - -// Same as anterior, but assuming D50 destination. White point is given in xyY -static -cmsBool _cmsAdaptMatrixToD50(cmsMAT3* r, const cmsCIExyY* SourceWhitePt) -{ - cmsCIEXYZ Dn; - cmsMAT3 Bradford; - cmsMAT3 Tmp; - - cmsxyY2XYZ(&Dn, SourceWhitePt); - - if (!_cmsAdaptationMatrix(&Bradford, NULL, &Dn, cmsD50_XYZ())) return FALSE; - - Tmp = *r; - _cmsMAT3per(r, &Bradford, &Tmp); - - return TRUE; -} - -// Build a White point, primary chromas transfer matrix from RGB to CIE XYZ -// This is just an approximation, I am not handling all the non-linear -// aspects of the RGB to XYZ process, and assumming that the gamma correction -// has transitive property in the tranformation chain. -// -// the alghoritm: -// -// - First I build the absolute conversion matrix using -// primaries in XYZ. This matrix is next inverted -// - Then I eval the source white point across this matrix -// obtaining the coeficients of the transformation -// - Then, I apply these coeficients to the original matrix -// -cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePt, const cmsCIExyYTRIPLE* Primrs) -{ - cmsVEC3 WhitePoint, Coef; - cmsMAT3 Result, Primaries; - cmsFloat64Number xn, yn; - cmsFloat64Number xr, yr; - cmsFloat64Number xg, yg; - cmsFloat64Number xb, yb; - - xn = WhitePt -> x; - yn = WhitePt -> y; - xr = Primrs -> Red.x; - yr = Primrs -> Red.y; - xg = Primrs -> Green.x; - yg = Primrs -> Green.y; - xb = Primrs -> Blue.x; - yb = Primrs -> Blue.y; - - // Build Primaries matrix - _cmsVEC3init(&Primaries.v[0], xr, xg, xb); - _cmsVEC3init(&Primaries.v[1], yr, yg, yb); - _cmsVEC3init(&Primaries.v[2], (1-xr-yr), (1-xg-yg), (1-xb-yb)); - - - // Result = Primaries ^ (-1) inverse matrix - if (!_cmsMAT3inverse(&Primaries, &Result)) - return FALSE; - - - _cmsVEC3init(&WhitePoint, xn/yn, 1.0, (1.0-xn-yn)/yn); - - // Across inverse primaries ... - _cmsMAT3eval(&Coef, &Result, &WhitePoint); - - // Give us the Coefs, then I build transformation matrix - _cmsVEC3init(&r -> v[0], Coef.n[VX]*xr, Coef.n[VY]*xg, Coef.n[VZ]*xb); - _cmsVEC3init(&r -> v[1], Coef.n[VX]*yr, Coef.n[VY]*yg, Coef.n[VZ]*yb); - _cmsVEC3init(&r -> v[2], Coef.n[VX]*(1.0-xr-yr), Coef.n[VY]*(1.0-xg-yg), Coef.n[VZ]*(1.0-xb-yb)); - - - return _cmsAdaptMatrixToD50(r, WhitePt); - -} - - -// Adapts a color to a given illuminant. Original color is expected to have -// a SourceWhitePt white point. -cmsBool CMSEXPORT cmsAdaptToIlluminant(cmsCIEXYZ* Result, - const cmsCIEXYZ* SourceWhitePt, - const cmsCIEXYZ* Illuminant, - const cmsCIEXYZ* Value) -{ - cmsMAT3 Bradford; - cmsVEC3 In, Out; - - _cmsAssert(Result != NULL); - _cmsAssert(SourceWhitePt != NULL); - _cmsAssert(Illuminant != NULL); - _cmsAssert(Value != NULL); - - if (!_cmsAdaptationMatrix(&Bradford, NULL, SourceWhitePt, Illuminant)) return FALSE; - - _cmsVEC3init(&In, Value -> X, Value -> Y, Value -> Z); - _cmsMAT3eval(&Out, &Bradford, &In); - - Result -> X = Out.n[0]; - Result -> Y = Out.n[1]; - Result -> Z = Out.n[2]; - - return TRUE; -} diff --git a/third_party/lcms2-2.6/src/cmsxform.c b/third_party/lcms2-2.6/src/cmsxform.c deleted file mode 100644 index dffe6b2fb7..0000000000 --- a/third_party/lcms2-2.6/src/cmsxform.c +++ /dev/null @@ -1,1137 +0,0 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2014 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- -// - -#include "lcms2_internal.h" - -// Transformations stuff -// ----------------------------------------------------------------------- - -#define DEFAULT_OBSERVER_ADAPTATION_STATE 1.0 - -// The Context0 observer adaptation state. -_cmsAdaptationStateChunkType _cmsAdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE }; - -// Init and duplicate observer adaptation state -void _cmsAllocAdaptationStateChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src) -{ - static _cmsAdaptationStateChunkType AdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE }; - void* from; - - if (src != NULL) { - from = src ->chunks[AdaptationStateContext]; - } - else { - from = &AdaptationStateChunk; - } - - ctx ->chunks[AdaptationStateContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAdaptationStateChunkType)); -} - - -// Sets adaptation state for absolute colorimetric intent in the given context. Adaptation state applies on all -// but cmsCreateExtendedTransformTHR(). Little CMS can handle incomplete adaptation states. -cmsFloat64Number CMSEXPORT cmsSetAdaptationStateTHR(cmsContext ContextID, cmsFloat64Number d) -{ - cmsFloat64Number prev; - _cmsAdaptationStateChunkType* ptr = (_cmsAdaptationStateChunkType*) _cmsContextGetClientChunk(ContextID, AdaptationStateContext); - - // Get previous value for return - prev = ptr ->AdaptationState; - - // Set the value if d is positive or zero - if (d >= 0.0) { - - ptr ->AdaptationState = d; - } - - // Always return previous value - return prev; -} - - -// The adaptation state may be defaulted by this function. If you don't like it, use the extended transform routine -cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d) -{ - return cmsSetAdaptationStateTHR(NULL, d); -} - -// ----------------------------------------------------------------------- - -// Alarm codes for 16-bit transformations, because the fixed range of containers there are -// no values left to mark out of gamut. - -#define DEFAULT_ALARM_CODES_VALUE {0x7F00, 0x7F00, 0x7F00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - -_cmsAlarmCodesChunkType _cmsAlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE }; - -// Sets the codes used to mark out-out-gamut on Proofing transforms for a given context. Values are meant to be -// encoded in 16 bits. -void CMSEXPORT cmsSetAlarmCodesTHR(cmsContext ContextID, const cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS]) -{ - _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext); - - _cmsAssert(ContextAlarmCodes != NULL); // Can't happen - - memcpy(ContextAlarmCodes->AlarmCodes, AlarmCodesP, sizeof(ContextAlarmCodes->AlarmCodes)); -} - -// Gets the current codes used to mark out-out-gamut on Proofing transforms for the given context. -// Values are meant to be encoded in 16 bits. -void CMSEXPORT cmsGetAlarmCodesTHR(cmsContext ContextID, cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS]) -{ - _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext); - - _cmsAssert(ContextAlarmCodes != NULL); // Can't happen - - memcpy(AlarmCodesP, ContextAlarmCodes->AlarmCodes, sizeof(ContextAlarmCodes->AlarmCodes)); -} - -void CMSEXPORT cmsSetAlarmCodes(const cmsUInt16Number NewAlarm[cmsMAXCHANNELS]) -{ - _cmsAssert(NewAlarm != NULL); - - cmsSetAlarmCodesTHR(NULL, NewAlarm); -} - -void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number OldAlarm[cmsMAXCHANNELS]) -{ - _cmsAssert(OldAlarm != NULL); - cmsGetAlarmCodesTHR(NULL, OldAlarm); -} - - -// Init and duplicate alarm codes -void _cmsAllocAlarmCodesChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src) -{ - static _cmsAlarmCodesChunkType AlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE }; - void* from; - - if (src != NULL) { - from = src ->chunks[AlarmCodesContext]; - } - else { - from = &AlarmCodesChunk; - } - - ctx ->chunks[AlarmCodesContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAlarmCodesChunkType)); -} - -// ----------------------------------------------------------------------- - -// Get rid of transform resources -void CMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform) -{ - _cmsTRANSFORM* p = (_cmsTRANSFORM*) hTransform; - - _cmsAssert(p != NULL); - - if (p -> GamutCheck) - cmsPipelineFree(p -> GamutCheck); - - if (p -> Lut) - cmsPipelineFree(p -> Lut); - - if (p ->InputColorant) - cmsFreeNamedColorList(p ->InputColorant); - - if (p -> OutputColorant) - cmsFreeNamedColorList(p ->OutputColorant); - - if (p ->Sequence) - cmsFreeProfileSequenceDescription(p ->Sequence); - - if (p ->UserData) - p ->FreeUserData(p ->ContextID, p ->UserData); - - _cmsFree(p ->ContextID, (void *) p); -} - -// Apply transform. -void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform, - const void* InputBuffer, - void* OutputBuffer, - cmsUInt32Number Size) - -{ - _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform; - - p -> xform(p, InputBuffer, OutputBuffer, Size, Size); -} - - -// Apply transform. -void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform, - const void* InputBuffer, - void* OutputBuffer, - cmsUInt32Number Size, cmsUInt32Number Stride) - -{ - _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform; - - p -> xform(p, InputBuffer, OutputBuffer, Size, Stride); -} - - -// Transform routines ---------------------------------------------------------------------------------------------------------- - -// Float xform converts floats. Since there are no performance issues, one routine does all job, including gamut check. -// Note that because extended range, we can use a -1.0 value for out of gamut in this case. -static -void FloatXFORM(_cmsTRANSFORM* p, - const void* in, - void* out, cmsUInt32Number Size, cmsUInt32Number Stride) -{ - cmsUInt8Number* accum; - cmsUInt8Number* output; - cmsFloat32Number fIn[cmsMAXCHANNELS], fOut[cmsMAXCHANNELS]; - cmsFloat32Number OutOfGamut; - cmsUInt32Number i, j; - - accum = (cmsUInt8Number*) in; - output = (cmsUInt8Number*) out; - - for (i=0; i < Size; i++) { - - accum = p -> FromInputFloat(p, fIn, accum, Stride); - - // Any gamut chack to do? - if (p ->GamutCheck != NULL) { - - // Evaluate gamut marker. - cmsPipelineEvalFloat( fIn, &OutOfGamut, p ->GamutCheck); - - // Is current color out of gamut? - if (OutOfGamut > 0.0) { - - // Certainly, out of gamut - for (j=0; j < cmsMAXCHANNELS; j++) - fOut[j] = -1.0; - - } - else { - // No, proceed normally - cmsPipelineEvalFloat(fIn, fOut, p -> Lut); - } - } - else { - - // No gamut check at all - cmsPipelineEvalFloat(fIn, fOut, p -> Lut); - } - - // Back to asked representation - output = p -> ToOutputFloat(p, fOut, output, Stride); - } -} - - -static -void NullFloatXFORM(_cmsTRANSFORM* p, - const void* in, - void* out, - cmsUInt32Number Size, - cmsUInt32Number Stride) -{ - cmsUInt8Number* accum; - cmsUInt8Number* output; - cmsFloat32Number fIn[cmsMAXCHANNELS]; - cmsUInt32Number i, n; - - accum = (cmsUInt8Number*) in; - output = (cmsUInt8Number*) out; - n = Size; - - for (i=0; i < n; i++) { - - accum = p -> FromInputFloat(p, fIn, accum, Stride); - output = p -> ToOutputFloat(p, fIn, output, Stride); - } -} - -// 16 bit precision ----------------------------------------------------------------------------------------------------------- - -// Null transformation, only applies formatters. No cach?static -void NullXFORM(_cmsTRANSFORM* p, - const void* in, - void* out, cmsUInt32Number Size, - cmsUInt32Number Stride) -{ - cmsUInt8Number* accum; - cmsUInt8Number* output; - cmsUInt16Number wIn[cmsMAXCHANNELS]; - cmsUInt32Number i, n; - - accum = (cmsUInt8Number*) in; - output = (cmsUInt8Number*) out; - n = Size; // Buffer len - - for (i=0; i < n; i++) { - - accum = p -> FromInput(p, wIn, accum, Stride); - output = p -> ToOutput(p, wIn, output, Stride); - } -} - - -// No gamut check, no cache, 16 bits -static -void PrecalculatedXFORM(_cmsTRANSFORM* p, - const void* in, - void* out, cmsUInt32Number Size, cmsUInt32Number Stride) -{ - register cmsUInt8Number* accum; - register cmsUInt8Number* output; - cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS]; - cmsUInt32Number i, n; - - accum = (cmsUInt8Number*) in; - output = (cmsUInt8Number*) out; - n = Size; - - for (i=0; i < n; i++) { - - accum = p -> FromInput(p, wIn, accum, Stride); - p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data); - output = p -> ToOutput(p, wOut, output, Stride); - } -} - - -// Auxiliar: Handle precalculated gamut check. The retrieval of context may be alittle bit slow, but this function is not critical. -static -void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p, - const cmsUInt16Number wIn[], - cmsUInt16Number wOut[]) -{ - cmsUInt16Number wOutOfGamut; - - p ->GamutCheck ->Eval16Fn(wIn, &wOutOfGamut, p ->GamutCheck ->Data); - if (wOutOfGamut >= 1) { - - cmsUInt16Number i; - _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(p->ContextID, AlarmCodesContext); - - for (i=0; i < p ->Lut->OutputChannels; i++) { - - wOut[i] = ContextAlarmCodes ->AlarmCodes[i]; - } - } - else - p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data); -} - -// Gamut check, No cach? 16 bits. -static -void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p, - const void* in, - void* out, cmsUInt32Number Size, cmsUInt32Number Stride) -{ - cmsUInt8Number* accum; - cmsUInt8Number* output; - cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS]; - cmsUInt32Number i, n; - - accum = (cmsUInt8Number*) in; - output = (cmsUInt8Number*) out; - n = Size; // Buffer len - - for (i=0; i < n; i++) { - - accum = p -> FromInput(p, wIn, accum, Stride); - TransformOnePixelWithGamutCheck(p, wIn, wOut); - output = p -> ToOutput(p, wOut, output, Stride); - } -} - - -// No gamut check, Cach? 16 bits, -static -void CachedXFORM(_cmsTRANSFORM* p, - const void* in, - void* out, cmsUInt32Number Size, cmsUInt32Number Stride) -{ - cmsUInt8Number* accum; - cmsUInt8Number* output; - cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS]; - cmsUInt32Number i, n; - _cmsCACHE Cache; - - accum = (cmsUInt8Number*) in; - output = (cmsUInt8Number*) out; - n = Size; // Buffer len - - // Empty buffers for quick memcmp - memset(wIn, 0, sizeof(wIn)); - memset(wOut, 0, sizeof(wOut)); - - // Get copy of zero cache - memcpy(&Cache, &p ->Cache, sizeof(Cache)); - - for (i=0; i < n; i++) { - - accum = p -> FromInput(p, wIn, accum, Stride); - - if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) { - - memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut)); - } - else { - - p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data); - - memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn)); - memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut)); - } - - output = p -> ToOutput(p, wOut, output, Stride); - } - -} - - -// All those nice features together -static -void CachedXFORMGamutCheck(_cmsTRANSFORM* p, - const void* in, - void* out, cmsUInt32Number Size, cmsUInt32Number Stride) -{ - cmsUInt8Number* accum; - cmsUInt8Number* output; - cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS]; - cmsUInt32Number i, n; - _cmsCACHE Cache; - - accum = (cmsUInt8Number*) in; - output = (cmsUInt8Number*) out; - n = Size; // Buffer len - - // Empty buffers for quick memcmp - memset(wIn, 0, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); - memset(wOut, 0, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); - - // Get copy of zero cache - memcpy(&Cache, &p ->Cache, sizeof(Cache)); - - for (i=0; i < n; i++) { - - accum = p -> FromInput(p, wIn, accum, Stride); - - if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) { - memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut)); - } - else { - TransformOnePixelWithGamutCheck(p, wIn, wOut); - memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn)); - memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut)); - } - - output = p -> ToOutput(p, wOut, output, Stride); - } - -} - -// ------------------------------------------------------------------------------------------------------------- - -// List of used-defined transform factories -typedef struct _cmsTransformCollection_st { - - _cmsTransformFactory Factory; - struct _cmsTransformCollection_st *Next; - -} _cmsTransformCollection; - -// The linked list head -_cmsTransformPluginChunkType _cmsTransformPluginChunk = { NULL }; - - -// Duplicates the zone of memory used by the plug-in in the new context -static -void DupPluginTransformList(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src) -{ - _cmsTransformPluginChunkType newHead = { NULL }; - _cmsTransformCollection* entry; - _cmsTransformCollection* Anterior = NULL; - _cmsTransformPluginChunkType* head = (_cmsTransformPluginChunkType*) src->chunks[TransformPlugin]; - - // Walk the list copying all nodes - for (entry = head->TransformCollection; - entry != NULL; - entry = entry ->Next) { - - _cmsTransformCollection *newEntry = ( _cmsTransformCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTransformCollection)); - - if (newEntry == NULL) - return; - - // We want to keep the linked list order, so this is a little bit tricky - newEntry -> Next = NULL; - if (Anterior) - Anterior -> Next = newEntry; - - Anterior = newEntry; - - if (newHead.TransformCollection == NULL) - newHead.TransformCollection = newEntry; - } - - ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTransformPluginChunkType)); -} - -void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src) -{ - if (src != NULL) { - - // Copy all linked list - DupPluginTransformList(ctx, src); - } - else { - static _cmsTransformPluginChunkType TransformPluginChunkType = { NULL }; - ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TransformPluginChunkType, sizeof(_cmsTransformPluginChunkType)); - } -} - - - -// Register new ways to transform -cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Data) -{ - cmsPluginTransform* Plugin = (cmsPluginTransform*) Data; - _cmsTransformCollection* fl; - _cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID,TransformPlugin); - - if (Data == NULL) { - - // Free the chain. Memory is safely freed at exit - ctx->TransformCollection = NULL; - return TRUE; - } - - // Factory callback is required - if (Plugin ->Factory == NULL) return FALSE; - - - fl = (_cmsTransformCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsTransformCollection)); - if (fl == NULL) return FALSE; - - // Copy the parameters - fl ->Factory = Plugin ->Factory; - - // Keep linked list - fl ->Next = ctx->TransformCollection; - ctx->TransformCollection = fl; - - // All is ok - return TRUE; -} - - -void CMSEXPORT _cmsSetTransformUserData(struct _cmstransform_struct *CMMcargo, void* ptr, _cmsFreeUserDataFn FreePrivateDataFn) -{ - _cmsAssert(CMMcargo != NULL); - CMMcargo ->UserData = ptr; - CMMcargo ->FreeUserData = FreePrivateDataFn; -} - -// returns the pointer defined by the plug-in to store private data -void * CMSEXPORT _cmsGetTransformUserData(struct _cmstransform_struct *CMMcargo) -{ - _cmsAssert(CMMcargo != NULL); - return CMMcargo ->UserData; -} - -// returns the current formatters -void CMSEXPORT _cmsGetTransformFormatters16(struct _cmstransform_struct *CMMcargo, cmsFormatter16* FromInput, cmsFormatter16* ToOutput) -{ - _cmsAssert(CMMcargo != NULL); - if (FromInput) *FromInput = CMMcargo ->FromInput; - if (ToOutput) *ToOutput = CMMcargo ->ToOutput; -} - -void CMSEXPORT _cmsGetTransformFormattersFloat(struct _cmstransform_struct *CMMcargo, cmsFormatterFloat* FromInput, cmsFormatterFloat* ToOutput) -{ - _cmsAssert(CMMcargo != NULL); - if (FromInput) *FromInput = CMMcargo ->FromInputFloat; - if (ToOutput) *ToOutput = CMMcargo ->ToOutputFloat; -} - - -// Allocate transform struct and set it to defaults. Ask the optimization plug-in about if those formats are proper -// for separated transforms. If this is the case, -static -_cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, - cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) -{ - _cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID, TransformPlugin); - _cmsTransformCollection* Plugin; - - // Allocate needed memory - _cmsTRANSFORM* p = (_cmsTRANSFORM*) _cmsMallocZero(ContextID, sizeof(_cmsTRANSFORM)); - if (!p) { - cmsPipelineFree(lut); - return NULL; - } - - // Store the proposed pipeline - p ->Lut = lut; - - // Let's see if any plug-in want to do the transform by itself - for (Plugin = ctx ->TransformCollection; - Plugin != NULL; - Plugin = Plugin ->Next) { - - if (Plugin ->Factory(&p->xform, &p->UserData, &p ->FreeUserData, &p ->Lut, InputFormat, OutputFormat, dwFlags)) { - - // Last plugin in the declaration order takes control. We just keep - // the original parameters as a logging. - // Note that cmsFLAGS_CAN_CHANGE_FORMATTER is not set, so by default - // an optimized transform is not reusable. The plug-in can, however, change - // the flags and make it suitable. - - p ->ContextID = ContextID; - p ->InputFormat = *InputFormat; - p ->OutputFormat = *OutputFormat; - p ->dwOriginalFlags = *dwFlags; - - // Fill the formatters just in case the optimized routine is interested. - // No error is thrown if the formatter doesn't exist. It is up to the optimization - // factory to decide what to do in those cases. - p ->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; - p ->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; - p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; - p ->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat; - - return p; - } - } - - // Not suitable for the transform plug-in, let's check the pipeline plug-in - if (p ->Lut != NULL) - _cmsOptimizePipeline(ContextID, &p->Lut, Intent, InputFormat, OutputFormat, dwFlags); - - // Check whatever this is a true floating point transform - if (_cmsFormatterIsFloat(*InputFormat) && _cmsFormatterIsFloat(*OutputFormat)) { - - // Get formatter function always return a valid union, but the contents of this union may be NULL. - p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; - p ->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat; - *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER; - - if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) { - - cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format"); - cmsDeleteTransform(p); - return NULL; - } - - if (*dwFlags & cmsFLAGS_NULLTRANSFORM) { - - p ->xform = NullFloatXFORM; - } - else { - // Float transforms don't use cach? always are non-NULL - p ->xform = FloatXFORM; - } - - } - else { - - if (*InputFormat == 0 && *OutputFormat == 0) { - p ->FromInput = p ->ToOutput = NULL; - *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER; - } - else { - - int BytesPerPixelInput; - - p ->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; - p ->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; - - if (p ->FromInput == NULL || p ->ToOutput == NULL) { - - cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format"); - cmsDeleteTransform(p); - return NULL; - } - - BytesPerPixelInput = T_BYTES(p ->InputFormat); - if (BytesPerPixelInput == 0 || BytesPerPixelInput >= 2) - *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER; - - } - - if (*dwFlags & cmsFLAGS_NULLTRANSFORM) { - - p ->xform = NullXFORM; - } - else { - if (*dwFlags & cmsFLAGS_NOCACHE) { - - if (*dwFlags & cmsFLAGS_GAMUTCHECK) - p ->xform = PrecalculatedXFORMGamutCheck; // Gamut check, no cach? - else - p ->xform = PrecalculatedXFORM; // No cach? no gamut check - } - else { - - if (*dwFlags & cmsFLAGS_GAMUTCHECK) - p ->xform = CachedXFORMGamutCheck; // Gamut check, cach? - else - p ->xform = CachedXFORM; // No gamut check, cach? - } - } - } - - p ->InputFormat = *InputFormat; - p ->OutputFormat = *OutputFormat; - p ->dwOriginalFlags = *dwFlags; - p ->ContextID = ContextID; - p ->UserData = NULL; - return p; -} - -static -cmsBool GetXFormColorSpaces(int nProfiles, cmsHPROFILE hProfiles[], cmsColorSpaceSignature* Input, cmsColorSpaceSignature* Output) -{ - cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut; - cmsColorSpaceSignature PostColorSpace; - int i; - - if (nProfiles <= 0) return FALSE; - if (hProfiles[0] == NULL) return FALSE; - - *Input = PostColorSpace = cmsGetColorSpace(hProfiles[0]); - - for (i=0; i < nProfiles; i++) { - - cmsProfileClassSignature cls; - cmsHPROFILE hProfile = hProfiles[i]; - - int lIsInput = (PostColorSpace != cmsSigXYZData) && - (PostColorSpace != cmsSigLabData); - - if (hProfile == NULL) return FALSE; - - cls = cmsGetDeviceClass(hProfile); - - if (cls == cmsSigNamedColorClass) { - - ColorSpaceIn = cmsSig1colorData; - ColorSpaceOut = (nProfiles > 1) ? cmsGetPCS(hProfile) : cmsGetColorSpace(hProfile); - } - else - if (lIsInput || (cls == cmsSigLinkClass)) { - - ColorSpaceIn = cmsGetColorSpace(hProfile); - ColorSpaceOut = cmsGetPCS(hProfile); - } - else - { - ColorSpaceIn = cmsGetPCS(hProfile); - ColorSpaceOut = cmsGetColorSpace(hProfile); - } - - if (i==0) - *Input = ColorSpaceIn; - - PostColorSpace = ColorSpaceOut; - } - - *Output = PostColorSpace; - - return TRUE; -} - -// Check colorspace -static -cmsBool IsProperColorSpace(cmsColorSpaceSignature Check, cmsUInt32Number dwFormat) -{ - int Space1 = T_COLORSPACE(dwFormat); - int Space2 = _cmsLCMScolorSpace(Check); - - if (Space1 == PT_ANY) return TRUE; - if (Space1 == Space2) return TRUE; - - if (Space1 == PT_LabV2 && Space2 == PT_Lab) return TRUE; - if (Space1 == PT_Lab && Space2 == PT_LabV2) return TRUE; - - return FALSE; -} - -// ---------------------------------------------------------------------------------------------------------------- - -static -void SetWhitePoint(cmsCIEXYZ* wtPt, const cmsCIEXYZ* src) -{ - if (src == NULL) { - wtPt ->X = cmsD50X; - wtPt ->Y = cmsD50Y; - wtPt ->Z = cmsD50Z; - } - else { - wtPt ->X = src->X; - wtPt ->Y = src->Y; - wtPt ->Z = src->Z; - } - -} - -// New to lcms 2.0 -- have all parameters available. -cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID, - cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[], - cmsBool BPC[], - cmsUInt32Number Intents[], - cmsFloat64Number AdaptationStates[], - cmsHPROFILE hGamutProfile, - cmsUInt32Number nGamutPCSposition, - cmsUInt32Number InputFormat, - cmsUInt32Number OutputFormat, - cmsUInt32Number dwFlags) -{ - _cmsTRANSFORM* xform; - cmsColorSpaceSignature EntryColorSpace; - cmsColorSpaceSignature ExitColorSpace; - cmsPipeline* Lut; - cmsUInt32Number LastIntent = Intents[nProfiles-1]; - - // If it is a fake transform - if (dwFlags & cmsFLAGS_NULLTRANSFORM) - { - return AllocEmptyTransform(ContextID, NULL, INTENT_PERCEPTUAL, &InputFormat, &OutputFormat, &dwFlags); - } - - // If gamut check is requested, make sure we have a gamut profile - if (dwFlags & cmsFLAGS_GAMUTCHECK) { - if (hGamutProfile == NULL) dwFlags &= ~cmsFLAGS_GAMUTCHECK; - } - - // On floating point transforms, inhibit cache - if (_cmsFormatterIsFloat(InputFormat) || _cmsFormatterIsFloat(OutputFormat)) - dwFlags |= cmsFLAGS_NOCACHE; - - // Mark entry/exit spaces - if (!GetXFormColorSpaces(nProfiles, hProfiles, &EntryColorSpace, &ExitColorSpace)) { - cmsSignalError(ContextID, cmsERROR_NULL, "NULL input profiles on transform"); - return NULL; - } - - // Check if proper colorspaces - if (!IsProperColorSpace(EntryColorSpace, InputFormat)) { - cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong input color space on transform"); - return NULL; - } - - if (!IsProperColorSpace(ExitColorSpace, OutputFormat)) { - cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong output color space on transform"); - return NULL; - } - - // Create a pipeline with all transformations - Lut = _cmsLinkProfiles(ContextID, nProfiles, Intents, hProfiles, BPC, AdaptationStates, dwFlags); - if (Lut == NULL) { - cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Couldn't link the profiles"); - return NULL; - } - - // Check channel count - if ((cmsChannelsOf(EntryColorSpace) != cmsPipelineInputChannels(Lut)) || - (cmsChannelsOf(ExitColorSpace) != cmsPipelineOutputChannels(Lut))) { - cmsPipelineFree(Lut); - cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Channel count doesn't match. Profile is corrupted"); - return NULL; - } - - - // All seems ok - xform = AllocEmptyTransform(ContextID, Lut, LastIntent, &InputFormat, &OutputFormat, &dwFlags); - if (xform == NULL) { - return NULL; - } - - // Keep values - xform ->EntryColorSpace = EntryColorSpace; - xform ->ExitColorSpace = ExitColorSpace; - xform ->RenderingIntent = Intents[nProfiles-1]; - - // Take white points - SetWhitePoint(&xform->EntryWhitePoint, (cmsCIEXYZ*) cmsReadTag(hProfiles[0], cmsSigMediaWhitePointTag)); - SetWhitePoint(&xform->ExitWhitePoint, (cmsCIEXYZ*) cmsReadTag(hProfiles[nProfiles-1], cmsSigMediaWhitePointTag)); - - - // Create a gamut check LUT if requested - if (hGamutProfile != NULL && (dwFlags & cmsFLAGS_GAMUTCHECK)) - xform ->GamutCheck = _cmsCreateGamutCheckPipeline(ContextID, hProfiles, - BPC, Intents, - AdaptationStates, - nGamutPCSposition, - hGamutProfile); - - - // Try to read input and output colorant table - if (cmsIsTag(hProfiles[0], cmsSigColorantTableTag)) { - - // Input table can only come in this way. - xform ->InputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[0], cmsSigColorantTableTag)); - } - - // Output is a little bit more complex. - if (cmsGetDeviceClass(hProfiles[nProfiles-1]) == cmsSigLinkClass) { - - // This tag may exist only on devicelink profiles. - if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag)) { - - // It may be NULL if error - xform ->OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag)); - } - - } else { - - if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableTag)) { - - xform -> OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableTag)); - } - } - - // Store the sequence of profiles - if (dwFlags & cmsFLAGS_KEEP_SEQUENCE) { - xform ->Sequence = _cmsCompileProfileSequence(ContextID, nProfiles, hProfiles); - } - else - xform ->Sequence = NULL; - - // If this is a cached transform, init first value, which is zero (16 bits only) - if (!(dwFlags & cmsFLAGS_NOCACHE)) { - - memset(&xform ->Cache.CacheIn, 0, sizeof(xform ->Cache.CacheIn)); - - if (xform ->GamutCheck != NULL) { - TransformOnePixelWithGamutCheck(xform, xform ->Cache.CacheIn, xform->Cache.CacheOut); - } - else { - - xform ->Lut ->Eval16Fn(xform ->Cache.CacheIn, xform->Cache.CacheOut, xform -> Lut->Data); - } - - } - - return (cmsHTRANSFORM) xform; -} - -// Multiprofile transforms: Gamut check is not available here, as it is unclear from which profile the gamut comes. -cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransformTHR(cmsContext ContextID, - cmsHPROFILE hProfiles[], - cmsUInt32Number nProfiles, - cmsUInt32Number InputFormat, - cmsUInt32Number OutputFormat, - cmsUInt32Number Intent, - cmsUInt32Number dwFlags) -{ - cmsUInt32Number i; - cmsBool BPC[256]; - cmsUInt32Number Intents[256]; - cmsFloat64Number AdaptationStates[256]; - - if (nProfiles <= 0 || nProfiles > 255) { - cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong number of profiles. 1..255 expected, %d found.", nProfiles); - return NULL; - } - - for (i=0; i < nProfiles; i++) { - BPC[i] = dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION ? TRUE : FALSE; - Intents[i] = Intent; - AdaptationStates[i] = cmsSetAdaptationStateTHR(ContextID, -1); - } - - - return cmsCreateExtendedTransform(ContextID, nProfiles, hProfiles, BPC, Intents, AdaptationStates, NULL, 0, InputFormat, OutputFormat, dwFlags); -} - - - -cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[], - cmsUInt32Number nProfiles, - cmsUInt32Number InputFormat, - cmsUInt32Number OutputFormat, - cmsUInt32Number Intent, - cmsUInt32Number dwFlags) -{ - - if (nProfiles <= 0 || nProfiles > 255) { - cmsSignalError(NULL, cmsERROR_RANGE, "Wrong number of profiles. 1..255 expected, %d found.", nProfiles); - return NULL; - } - - return cmsCreateMultiprofileTransformTHR(cmsGetProfileContextID(hProfiles[0]), - hProfiles, - nProfiles, - InputFormat, - OutputFormat, - Intent, - dwFlags); -} - -cmsHTRANSFORM CMSEXPORT cmsCreateTransformTHR(cmsContext ContextID, - cmsHPROFILE Input, - cmsUInt32Number InputFormat, - cmsHPROFILE Output, - cmsUInt32Number OutputFormat, - cmsUInt32Number Intent, - cmsUInt32Number dwFlags) -{ - - cmsHPROFILE hArray[2]; - - hArray[0] = Input; - hArray[1] = Output; - - return cmsCreateMultiprofileTransformTHR(ContextID, hArray, Output == NULL ? 1 : 2, InputFormat, OutputFormat, Intent, dwFlags); -} - -CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateTransform(cmsHPROFILE Input, - cmsUInt32Number InputFormat, - cmsHPROFILE Output, - cmsUInt32Number OutputFormat, - cmsUInt32Number Intent, - cmsUInt32Number dwFlags) -{ - return cmsCreateTransformTHR(cmsGetProfileContextID(Input), Input, InputFormat, Output, OutputFormat, Intent, dwFlags); -} - - -cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransformTHR(cmsContext ContextID, - cmsHPROFILE InputProfile, - cmsUInt32Number InputFormat, - cmsHPROFILE OutputProfile, - cmsUInt32Number OutputFormat, - cmsHPROFILE ProofingProfile, - cmsUInt32Number nIntent, - cmsUInt32Number ProofingIntent, - cmsUInt32Number dwFlags) -{ - cmsHPROFILE hArray[4]; - cmsUInt32Number Intents[4]; - cmsBool BPC[4]; - cmsFloat64Number Adaptation[4]; - cmsBool DoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION) ? TRUE : FALSE; - - - hArray[0] = InputProfile; hArray[1] = ProofingProfile; hArray[2] = ProofingProfile; hArray[3] = OutputProfile; - Intents[0] = nIntent; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = ProofingIntent; - BPC[0] = DoBPC; BPC[1] = DoBPC; BPC[2] = 0; BPC[3] = 0; - - Adaptation[0] = Adaptation[1] = Adaptation[2] = Adaptation[3] = cmsSetAdaptationStateTHR(ContextID, -1); - - if (!(dwFlags & (cmsFLAGS_SOFTPROOFING|cmsFLAGS_GAMUTCHECK))) - return cmsCreateTransformTHR(ContextID, InputProfile, InputFormat, OutputProfile, OutputFormat, nIntent, dwFlags); - - return cmsCreateExtendedTransform(ContextID, 4, hArray, BPC, Intents, Adaptation, - ProofingProfile, 1, InputFormat, OutputFormat, dwFlags); - -} - - -cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile, - cmsUInt32Number InputFormat, - cmsHPROFILE OutputProfile, - cmsUInt32Number OutputFormat, - cmsHPROFILE ProofingProfile, - cmsUInt32Number nIntent, - cmsUInt32Number ProofingIntent, - cmsUInt32Number dwFlags) -{ - return cmsCreateProofingTransformTHR(cmsGetProfileContextID(InputProfile), - InputProfile, - InputFormat, - OutputProfile, - OutputFormat, - ProofingProfile, - nIntent, - ProofingIntent, - dwFlags); -} - - -// Grab the ContextID from an open transform. Returns NULL if a NULL transform is passed -cmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform) -{ - _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform; - - if (xform == NULL) return NULL; - return xform -> ContextID; -} - -// Grab the input/output formats -cmsUInt32Number CMSEXPORT cmsGetTransformInputFormat(cmsHTRANSFORM hTransform) -{ - _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform; - - if (xform == NULL) return 0; - return xform->InputFormat; -} - -cmsUInt32Number CMSEXPORT cmsGetTransformOutputFormat(cmsHTRANSFORM hTransform) -{ - _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform; - - if (xform == NULL) return 0; - return xform->OutputFormat; -} - -// For backwards compatibility -cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform, - cmsUInt32Number InputFormat, - cmsUInt32Number OutputFormat) -{ - - _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform; - cmsFormatter16 FromInput, ToOutput; - - - // We only can afford to change formatters if previous transform is at least 16 bits - if (!(xform ->dwOriginalFlags & cmsFLAGS_CAN_CHANGE_FORMATTER)) { - - cmsSignalError(xform ->ContextID, cmsERROR_NOT_SUITABLE, "cmsChangeBuffersFormat works only on transforms created originally with at least 16 bits of precision"); - return FALSE; - } - - FromInput = _cmsGetFormatter(xform->ContextID, InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; - ToOutput = _cmsGetFormatter(xform->ContextID, OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; - - if (FromInput == NULL || ToOutput == NULL) { - - cmsSignalError(xform -> ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format"); - return FALSE; - } - - xform ->InputFormat = InputFormat; - xform ->OutputFormat = OutputFormat; - xform ->FromInput = FromInput; - xform ->ToOutput = ToOutput; - return TRUE; -} diff --git a/third_party/lcms2-2.6/src/lcms2_internal.h b/third_party/lcms2-2.6/src/lcms2_internal.h deleted file mode 100644 index cc76d488d0..0000000000 --- a/third_party/lcms2-2.6/src/lcms2_internal.h +++ /dev/null @@ -1,1032 +0,0 @@ -//<<<+++OPENSOURCE -//<<<+++OPENSOURCE_MUST_BEGIN COMMENT==TRUE -// -// Little Color Management System -// Copyright (c) 1998-2014 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- -// - -#ifndef _lcms_internal_H - -// Include plug-in foundation -#ifndef _lcms_plugin_H -#include "third_party/lcms2-2.6/include/lcms2_plugin.h" -#endif - -// ctype is part of C99 as per 7.1.2 -#include <ctype.h> - -// assert macro is part of C99 as per 7.2 -#include <assert.h> - -// Some needed constants -#ifndef M_PI -# define M_PI 3.14159265358979323846 -#endif - -#ifndef M_LOG10E -# define M_LOG10E 0.434294481903251827651 -#endif - -// BorlandC 5.5, VC2003 are broken on that -#if defined(__BORLANDC__) || (_MSC_VER < 1400) // 1400 == VC++ 8.0 -#define sinf(x) (float)sin((float)x) -#define sqrtf(x) (float)sqrt((float)x) -#endif - - -// Alignment of ICC file format uses 4 bytes (cmsUInt32Number) -#define _cmsALIGNLONG(x) (((x)+(sizeof(cmsUInt32Number)-1)) & ~(sizeof(cmsUInt32Number)-1)) - -// Alignment to memory pointer -#define _cmsALIGNMEM(x) (((x)+(sizeof(void *) - 1)) & ~(sizeof(void *) - 1)) - -// Maximum encodeable values in floating point -#define MAX_ENCODEABLE_XYZ (1.0 + 32767.0/32768.0) -#define MIN_ENCODEABLE_ab2 (-128.0) -#define MAX_ENCODEABLE_ab2 ((65535.0/256.0) - 128.0) -#define MIN_ENCODEABLE_ab4 (-128.0) -#define MAX_ENCODEABLE_ab4 (127.0) - -// Maximum of channels for internal pipeline evaluation -#define MAX_STAGE_CHANNELS 128 - -// Unused parameter warning supression -#define cmsUNUSED_PARAMETER(x) ((void)x) - -// The specification for "inline" is section 6.7.4 of the C99 standard (ISO/IEC 9899:1999). -// unfortunately VisualC++ does not conform that -#if defined(_MSC_VER) || defined(__BORLANDC__) -# define cmsINLINE __inline -#else -# define cmsINLINE static inline -#endif - -// Other replacement functions -#ifdef _MSC_VER -# ifndef snprintf -# define snprintf _snprintf -# endif -# ifndef vsnprintf -# define vsnprintf _vsnprintf -# endif -#endif - - -// A fast way to convert from/to 16 <-> 8 bits -#define FROM_8_TO_16(rgb) (cmsUInt16Number) ((((cmsUInt16Number) (rgb)) << 8)|(rgb)) -#define FROM_16_TO_8(rgb) (cmsUInt8Number) ((((cmsUInt32Number)(rgb) * 65281U + 8388608U) >> 24) & 0xFFU) - -// Code analysis is broken on asserts -#ifdef _MSC_VER -# if (_MSC_VER >= 1500) -# define _cmsAssert(a) { assert((a)); __analysis_assume((a)); } -# else -# define _cmsAssert(a) assert((a)) -# endif -#else -# define _cmsAssert(a) assert((a)) -#endif - -//--------------------------------------------------------------------------------- - -// Determinant lower than that are assumed zero (used on matrix invert) -#define MATRIX_DET_TOLERANCE 0.0001 - -//--------------------------------------------------------------------------------- - -// Fixed point -#define FIXED_TO_INT(x) ((x)>>16) -#define FIXED_REST_TO_INT(x) ((x)&0xFFFFU) -#define ROUND_FIXED_TO_INT(x) (((x)+0x8000)>>16) - -cmsINLINE cmsS15Fixed16Number _cmsToFixedDomain(int a) { return a + ((a + 0x7fff) / 0xffff); } -cmsINLINE int _cmsFromFixedDomain(cmsS15Fixed16Number a) { return a - ((a + 0x7fff) >> 16); } - -// ----------------------------------------------------------------------------------------------------------- - -// Fast floor conversion logic. Thanks to Sree Kotay and Stuart Nixon -// note than this only works in the range ..-32767...+32767 because -// mantissa is interpreted as 15.16 fixed point. -// The union is to avoid pointer aliasing overoptimization. -cmsINLINE int _cmsQuickFloor(cmsFloat64Number val) -{ -#ifdef CMS_DONT_USE_FAST_FLOOR - return (int) floor(val); -#else - const cmsFloat64Number _lcms_double2fixmagic = 68719476736.0 * 1.5; // 2^36 * 1.5, (52-16=36) uses limited precision to floor - union { - cmsFloat64Number val; - int halves[2]; - } temp; - - temp.val = val + _lcms_double2fixmagic; - -#ifdef CMS_USE_BIG_ENDIAN - return temp.halves[1] >> 16; -#else - return temp.halves[0] >> 16; -#endif -#endif -} - -// Fast floor restricted to 0..65535.0 -cmsINLINE cmsUInt16Number _cmsQuickFloorWord(cmsFloat64Number d) -{ - return (cmsUInt16Number) _cmsQuickFloor(d - 32767.0) + 32767U; -} - -// Floor to word, taking care of saturation -cmsINLINE cmsUInt16Number _cmsQuickSaturateWord(cmsFloat64Number d) -{ - d += 0.5; - if (d <= 0) return 0; - if (d >= 65535.0) return 0xffff; - - return _cmsQuickFloorWord(d); -} - - -// Pthread support -------------------------------------------------------------------- -#ifndef CMS_NO_PTHREADS - -// This is the threading support. Unfortunately, it has to be platform-dependent because -// windows does not support pthreads. - -#ifdef CMS_IS_WINDOWS_ - -#define WIN32_LEAN_AND_MEAN 1 -#include <windows.h> - - -// From: http://locklessinc.com/articles/pthreads_on_windows/ -// The pthreads API has an initialization macro that has no correspondence to anything in -// the windows API. By investigating the internal definition of the critical section type, -// one may work out how to initialize one without calling InitializeCriticalSection(). -// The trick here is that InitializeCriticalSection() is not allowed to fail. It tries -// to allocate a critical section debug object, but if no memory is available, it sets -// the pointer to a specific value. (One would expect that value to be NULL, but it is -// actually (void *)-1 for some reason.) Thus we can use this special value for that -// pointer, and the critical section code will work. - -// The other important part of the critical section type to initialize is the number -// of waiters. This controls whether or not the mutex is locked. Fortunately, this -// part of the critical section is unlikely to change. Apparently, many programs -// already test critical sections to see if they are locked using this value, so -// Microsoft felt that it was necessary to keep it set at -1 for an unlocked critical -// section, even when they changed the underlying algorithm to be more scalable. -// The final parts of the critical section object are unimportant, and can be set -// to zero for their defaults. This yields an initialization macro: - -typedef CRITICAL_SECTION _cmsMutex; - -#define CMS_MUTEX_INITIALIZER {(void*) -1,-1,0,0,0,0} - -cmsINLINE int _cmsLockPrimitive(_cmsMutex *m) -{ - EnterCriticalSection(m); - return 0; -} - -cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m) -{ - LeaveCriticalSection(m); - return 0; -} - -cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m) -{ - InitializeCriticalSection(m); - return 0; -} - -cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m) -{ - DeleteCriticalSection(m); - return 0; -} - -cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m) -{ - EnterCriticalSection(m); - return 0; -} - -cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m) -{ - LeaveCriticalSection(m); - return 0; -} - -#else - -// Rest of the wide world -#include <pthread.h> - -#define CMS_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER -typedef pthread_mutex_t _cmsMutex; - - -cmsINLINE int _cmsLockPrimitive(_cmsMutex *m) -{ - return pthread_mutex_lock(m); -} - -cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m) -{ - return pthread_mutex_unlock(m); -} - -cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m) -{ - return pthread_mutex_init(m, NULL); -} - -cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m) -{ - return pthread_mutex_destroy(m); -} - -cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m) -{ - return pthread_mutex_lock(m); -} - -cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m) -{ - return pthread_mutex_unlock(m); -} - -#endif -#else - -#define CMS_MUTEX_INITIALIZER 0 -typedef int _cmsMutex; - - -cmsINLINE int _cmsLockPrimitive(_cmsMutex *m) -{ - return 0; - cmsUNUSED_PARAMETER(m); -} - -cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m) -{ - return 0; - cmsUNUSED_PARAMETER(m); -} - -cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m) -{ - return 0; - cmsUNUSED_PARAMETER(m); -} - -cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m) -{ - return 0; - cmsUNUSED_PARAMETER(m); -} - -cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m) -{ - return 0; - cmsUNUSED_PARAMETER(m); -} - -cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m) -{ - return 0; - cmsUNUSED_PARAMETER(m); -} -#endif - -// Plug-In registration --------------------------------------------------------------- - -// Specialized function for plug-in memory management. No pairing free() since whole pool is freed at once. -void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size); - -// Memory management -cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plugin); - -// Interpolation -cmsBool _cmsRegisterInterpPlugin(cmsContext ContextID, cmsPluginBase* Plugin); - -// Parametric curves -cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext ContextID, cmsPluginBase* Plugin); - -// Formatters management -cmsBool _cmsRegisterFormattersPlugin(cmsContext ContextID, cmsPluginBase* Plugin); - -// Tag type management -cmsBool _cmsRegisterTagTypePlugin(cmsContext ContextID, cmsPluginBase* Plugin); - -// Tag management -cmsBool _cmsRegisterTagPlugin(cmsContext ContextID, cmsPluginBase* Plugin); - -// Intent management -cmsBool _cmsRegisterRenderingIntentPlugin(cmsContext ContextID, cmsPluginBase* Plugin); - -// Multi Process elements -cmsBool _cmsRegisterMultiProcessElementPlugin(cmsContext ContextID, cmsPluginBase* Plugin); - -// Optimization -cmsBool _cmsRegisterOptimizationPlugin(cmsContext ContextID, cmsPluginBase* Plugin); - -// Transform -cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Plugin); - -// Mutex -cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Plugin); - -// --------------------------------------------------------------------------------------------------------- - -// Suballocators. -typedef struct _cmsSubAllocator_chunk_st { - - cmsUInt8Number* Block; - cmsUInt32Number BlockSize; - cmsUInt32Number Used; - - struct _cmsSubAllocator_chunk_st* next; - -} _cmsSubAllocator_chunk; - - -typedef struct { - - cmsContext ContextID; - _cmsSubAllocator_chunk* h; - -} _cmsSubAllocator; - - -_cmsSubAllocator* _cmsCreateSubAlloc(cmsContext ContextID, cmsUInt32Number Initial); -void _cmsSubAllocDestroy(_cmsSubAllocator* s); -void* _cmsSubAlloc(_cmsSubAllocator* s, cmsUInt32Number size); -void* _cmsSubAllocDup(_cmsSubAllocator* s, const void *ptr, cmsUInt32Number size); - -// ---------------------------------------------------------------------------------- - -// The context clients. -typedef enum { - - UserPtr, // User-defined pointer - Logger, - AlarmCodesContext, - AdaptationStateContext, - MemPlugin, - InterpPlugin, - CurvesPlugin, - FormattersPlugin, - TagTypePlugin, - TagPlugin, - IntentPlugin, - MPEPlugin, - OptimizationPlugin, - TransformPlugin, - MutexPlugin, - - // Last in list - MemoryClientMax - -} _cmsMemoryClient; - - -// Container for memory management plug-in. -typedef struct { - - _cmsMallocFnPtrType MallocPtr; - _cmsMalloZerocFnPtrType MallocZeroPtr; - _cmsFreeFnPtrType FreePtr; - _cmsReallocFnPtrType ReallocPtr; - _cmsCallocFnPtrType CallocPtr; - _cmsDupFnPtrType DupPtr; - -} _cmsMemPluginChunkType; - -// Copy memory management function pointers from plug-in to chunk, taking care of missing routines -void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkType* ptr); - -// Internal structure for context -struct _cmsContext_struct { - - struct _cmsContext_struct* Next; // Points to next context in the new style - _cmsSubAllocator* MemPool; // The memory pool that stores context data - - void* chunks[MemoryClientMax]; // array of pointers to client chunks. Memory itself is hold in the suballocator. - // If NULL, then it reverts to global Context0 - - _cmsMemPluginChunkType DefaultMemoryManager; // The allocators used for creating the context itself. Cannot be overriden -}; - -// Returns a pointer to a valid context structure, including the global one if id is zero. -// Verifies the magic number. -struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID); - -// Returns the block assigned to the specific zone. -void* _cmsContextGetClientChunk(cmsContext id, _cmsMemoryClient mc); - - -// Chunks of context memory by plug-in client ------------------------------------------------------- - -// Those structures encapsulates all variables needed by the several context clients (mostly plug-ins) - -// Container for error logger -- not a plug-in -typedef struct { - - cmsLogErrorHandlerFunction LogErrorHandler; // Set to NULL for Context0 fallback - -} _cmsLogErrorChunkType; - -// The global Context0 storage for error logger -extern _cmsLogErrorChunkType _cmsLogErrorChunk; - -// Allocate and init error logger container. -void _cmsAllocLogErrorChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src); - -// Container for alarm codes -- not a plug-in -typedef struct { - - cmsUInt16Number AlarmCodes[cmsMAXCHANNELS]; - -} _cmsAlarmCodesChunkType; - -// The global Context0 storage for alarm codes -extern _cmsAlarmCodesChunkType _cmsAlarmCodesChunk; - -// Allocate and init alarm codes container. -void _cmsAllocAlarmCodesChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src); - -// Container for adaptation state -- not a plug-in -typedef struct { - - cmsFloat64Number AdaptationState; - -} _cmsAdaptationStateChunkType; - -// The global Context0 storage for adaptation state -extern _cmsAdaptationStateChunkType _cmsAdaptationStateChunk; - -// Allocate and init adaptation state container. -void _cmsAllocAdaptationStateChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src); - - -// The global Context0 storage for memory management -extern _cmsMemPluginChunkType _cmsMemPluginChunk; - -// Allocate and init memory management container. -void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src); - -// Container for interpolation plug-in -typedef struct { - - cmsInterpFnFactory Interpolators; - -} _cmsInterpPluginChunkType; - -// The global Context0 storage for interpolation plug-in -extern _cmsInterpPluginChunkType _cmsInterpPluginChunk; - -// Allocate and init interpolation container. -void _cmsAllocInterpPluginChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src); - -// Container for parametric curves plug-in -typedef struct { - - struct _cmsParametricCurvesCollection_st* ParametricCurves; - -} _cmsCurvesPluginChunkType; - -// The global Context0 storage for tone curves plug-in -extern _cmsCurvesPluginChunkType _cmsCurvesPluginChunk; - -// Allocate and init parametric curves container. -void _cmsAllocCurvesPluginChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src); - -// Container for formatters plug-in -typedef struct { - - struct _cms_formatters_factory_list* FactoryList; - -} _cmsFormattersPluginChunkType; - -// The global Context0 storage for formatters plug-in -extern _cmsFormattersPluginChunkType _cmsFormattersPluginChunk; - -// Allocate and init formatters container. -void _cmsAllocFormattersPluginChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src); - -// This chunk type is shared by TagType plug-in and MPE Plug-in -typedef struct { - - struct _cmsTagTypeLinkedList_st* TagTypes; - -} _cmsTagTypePluginChunkType; - - -// The global Context0 storage for tag types plug-in -extern _cmsTagTypePluginChunkType _cmsTagTypePluginChunk; - - -// The global Context0 storage for mult process elements plug-in -extern _cmsTagTypePluginChunkType _cmsMPETypePluginChunk; - -// Allocate and init Tag types container. -void _cmsAllocTagTypePluginChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src); -// Allocate and init MPE container. -void _cmsAllocMPETypePluginChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src); -// Container for tag plug-in -typedef struct { - - struct _cmsTagLinkedList_st* Tag; - -} _cmsTagPluginChunkType; - - -// The global Context0 storage for tag plug-in -extern _cmsTagPluginChunkType _cmsTagPluginChunk; - -// Allocate and init Tag container. -void _cmsAllocTagPluginChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src); - -// Container for intents plug-in -typedef struct { - - struct _cms_intents_list* Intents; - -} _cmsIntentsPluginChunkType; - - -// The global Context0 storage for intents plug-in -extern _cmsIntentsPluginChunkType _cmsIntentsPluginChunk; - -// Allocate and init intents container. -void _cmsAllocIntentsPluginChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src); - -// Container for optimization plug-in -typedef struct { - - struct _cmsOptimizationCollection_st* OptimizationCollection; - -} _cmsOptimizationPluginChunkType; - - -// The global Context0 storage for optimizers plug-in -extern _cmsOptimizationPluginChunkType _cmsOptimizationPluginChunk; - -// Allocate and init optimizers container. -void _cmsAllocOptimizationPluginChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src); - -// Container for transform plug-in -typedef struct { - - struct _cmsTransformCollection_st* TransformCollection; - -} _cmsTransformPluginChunkType; - -// The global Context0 storage for full-transform replacement plug-in -extern _cmsTransformPluginChunkType _cmsTransformPluginChunk; - -// Allocate and init transform container. -void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src); - -// Container for mutex plug-in -typedef struct { - - _cmsCreateMutexFnPtrType CreateMutexPtr; - _cmsDestroyMutexFnPtrType DestroyMutexPtr; - _cmsLockMutexFnPtrType LockMutexPtr; - _cmsUnlockMutexFnPtrType UnlockMutexPtr; - -} _cmsMutexPluginChunkType; - -// The global Context0 storage for mutex plug-in -extern _cmsMutexPluginChunkType _cmsMutexPluginChunk; - -// Allocate and init mutex container. -void _cmsAllocMutexPluginChunk(struct _cmsContext_struct* ctx, - const struct _cmsContext_struct* src); - -// ---------------------------------------------------------------------------------- -// MLU internal representation -typedef struct { - - cmsUInt16Number Language; - cmsUInt16Number Country; - - cmsUInt32Number StrW; // Offset to current unicode string - cmsUInt32Number Len; // Length in bytes - -} _cmsMLUentry; - -struct _cms_MLU_struct { - - cmsContext ContextID; - - // The directory - int AllocatedEntries; - int UsedEntries; - _cmsMLUentry* Entries; // Array of pointers to strings allocated in MemPool - - // The Pool - cmsUInt32Number PoolSize; // The maximum allocated size - cmsUInt32Number PoolUsed; // The used size - void* MemPool; // Pointer to begin of memory pool -}; - -// Named color list internal representation -typedef struct { - - char Name[cmsMAX_PATH]; - cmsUInt16Number PCS[3]; - cmsUInt16Number DeviceColorant[cmsMAXCHANNELS]; - -} _cmsNAMEDCOLOR; - -struct _cms_NAMEDCOLORLIST_struct { - - cmsUInt32Number nColors; - cmsUInt32Number Allocated; - cmsUInt32Number ColorantCount; - - char Prefix[33]; // Prefix and suffix are defined to be 32 characters at most - char Suffix[33]; - - _cmsNAMEDCOLOR* List; - - cmsContext ContextID; -}; - - -// ---------------------------------------------------------------------------------- - -// This is the internal struct holding profile details. - -// Maximum supported tags in a profile -#define MAX_TABLE_TAG 100 - -typedef struct _cms_iccprofile_struct { - - // I/O handler - cmsIOHANDLER* IOhandler; - - // The thread ID - cmsContext ContextID; - - // Creation time - struct tm Created; - - // Only most important items found in ICC profiles - cmsUInt32Number Version; - cmsProfileClassSignature DeviceClass; - cmsColorSpaceSignature ColorSpace; - cmsColorSpaceSignature PCS; - cmsUInt32Number RenderingIntent; - - cmsUInt32Number flags; - cmsUInt32Number manufacturer, model; - cmsUInt64Number attributes; - cmsUInt32Number creator; - - cmsProfileID ProfileID; - - // Dictionary - cmsUInt32Number TagCount; - cmsTagSignature TagNames[MAX_TABLE_TAG]; - cmsTagSignature TagLinked[MAX_TABLE_TAG]; // The tag to wich is linked (0=none) - cmsUInt32Number TagSizes[MAX_TABLE_TAG]; // Size on disk - cmsUInt32Number TagOffsets[MAX_TABLE_TAG]; - cmsBool TagSaveAsRaw[MAX_TABLE_TAG]; // True to write uncooked - void * TagPtrs[MAX_TABLE_TAG]; - cmsTagTypeHandler* TagTypeHandlers[MAX_TABLE_TAG]; // Same structure may be serialized on different types - // depending on profile version, so we keep track of the - // type handler for each tag in the list. - // Special - cmsBool IsWrite; - - // Keep a mutex for cmsReadTag -- Note that this only works if the user includes a mutex plugin - void * UsrMutex; - -} _cmsICCPROFILE; - -// IO helpers for profiles -cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc); -cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace); -int _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks); - -// Tag types -cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsContext ContextID, cmsTagTypeSignature sig); -cmsTagTypeSignature _cmsGetTagTrueType(cmsHPROFILE hProfile, cmsTagSignature sig); -cmsTagDescriptor* _cmsGetTagDescriptor(cmsContext ContextID, cmsTagSignature sig); - -// Error logging --------------------------------------------------------------------------------------------------------- - -void _cmsTagSignature2String(char String[5], cmsTagSignature sig); - -// Interpolation --------------------------------------------------------------------------------------------------------- - -cmsInterpParams* _cmsComputeInterpParams(cmsContext ContextID, int nSamples, int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags); -cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID, const cmsUInt32Number nSamples[], int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags); -void _cmsFreeInterpParams(cmsInterpParams* p); -cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p); - -// Curves ---------------------------------------------------------------------------------------------------------------- - -// This struct holds information about a segment, plus a pointer to the function that implements the evaluation. -// In the case of table-based, Eval pointer is set to NULL - -// The gamma function main structure -struct _cms_curve_struct { - - cmsInterpParams* InterpParams; // Private optimizations for interpolation - - cmsUInt32Number nSegments; // Number of segments in the curve. Zero for a 16-bit based tables - cmsCurveSegment* Segments; // The segments - cmsInterpParams** SegInterp; // Array of private optimizations for interpolation in table-based segments - - cmsParametricCurveEvaluator* Evals; // Evaluators (one per segment) - - // 16 bit Table-based representation follows - cmsUInt32Number nEntries; // Number of table elements - cmsUInt16Number* Table16; // The table itself. -}; - - -// Pipelines & Stages --------------------------------------------------------------------------------------------- - -// A single stage -struct _cmsStage_struct { - - cmsContext ContextID; - - cmsStageSignature Type; // Identifies the stage - cmsStageSignature Implements; // Identifies the *function* of the stage (for optimizations) - - cmsUInt32Number InputChannels; // Input channels -- for optimization purposes - cmsUInt32Number OutputChannels; // Output channels -- for optimization purposes - - _cmsStageEvalFn EvalPtr; // Points to fn that evaluates the stage (always in floating point) - _cmsStageDupElemFn DupElemPtr; // Points to a fn that duplicates the *data* of the stage - _cmsStageFreeElemFn FreePtr; // Points to a fn that sets the *data* of the stage free - - // A generic pointer to whatever memory needed by the stage - void* Data; - - // Maintains linked list (used internally) - struct _cmsStage_struct* Next; -}; - - -// Special Stages (cannot be saved) -cmsStage* _cmsStageAllocLab2XYZ(cmsContext ContextID); -cmsStage* _cmsStageAllocXYZ2Lab(cmsContext ContextID); -cmsStage* _cmsStageAllocLabPrelin(cmsContext ContextID); -cmsStage* _cmsStageAllocLabV2ToV4(cmsContext ContextID); -cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID); -cmsStage* _cmsStageAllocLabV4ToV2(cmsContext ContextID); -cmsStage* _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList, cmsBool UsePCS); -cmsStage* _cmsStageAllocIdentityCurves(cmsContext ContextID, int nChannels); -cmsStage* _cmsStageAllocIdentityCLut(cmsContext ContextID, int nChan); -cmsStage* _cmsStageNormalizeFromLabFloat(cmsContext ContextID); -cmsStage* _cmsStageNormalizeFromXyzFloat(cmsContext ContextID); -cmsStage* _cmsStageNormalizeToLabFloat(cmsContext ContextID); -cmsStage* _cmsStageNormalizeToXyzFloat(cmsContext ContextID); - -// For curve set only -cmsToneCurve** _cmsStageGetPtrToCurveSet(const cmsStage* mpe); - - -// Pipeline Evaluator (in floating point) -typedef void (* _cmsPipelineEvalFloatFn)(const cmsFloat32Number In[], - cmsFloat32Number Out[], - const void* Data); - -struct _cmsPipeline_struct { - - cmsStage* Elements; // Points to elements chain - cmsUInt32Number InputChannels, OutputChannels; - - // Data & evaluators - void *Data; - - _cmsOPTeval16Fn Eval16Fn; - _cmsPipelineEvalFloatFn EvalFloatFn; - _cmsFreeUserDataFn FreeDataFn; - _cmsDupUserDataFn DupDataFn; - - cmsContext ContextID; // Environment - - cmsBool SaveAs8Bits; // Implementation-specific: save as 8 bits if possible -}; - -// LUT reading & creation ------------------------------------------------------------------------------------------- - -// Read tags using low-level function, provide necessary glue code to adapt versions, etc. All those return a brand new copy -// of the LUTS, since ownership of original is up to the profile. The user should free allocated resources. - -cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent); -cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent); -cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent); - -// Special values -cmsBool _cmsReadMediaWhitePoint(cmsCIEXYZ* Dest, cmsHPROFILE hProfile); -cmsBool _cmsReadCHAD(cmsMAT3* Dest, cmsHPROFILE hProfile); - -// Profile linker -------------------------------------------------------------------------------------------------- - -cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, - cmsUInt32Number nProfiles, - cmsUInt32Number TheIntents[], - cmsHPROFILE hProfiles[], - cmsBool BPC[], - cmsFloat64Number AdaptationStates[], - cmsUInt32Number dwFlags); - -// Sequence -------------------------------------------------------------------------------------------------------- - -cmsSEQ* _cmsReadProfileSequence(cmsHPROFILE hProfile); -cmsBool _cmsWriteProfileSequence(cmsHPROFILE hProfile, const cmsSEQ* seq); -cmsSEQ* _cmsCompileProfileSequence(cmsContext ContextID, cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[]); - - -// LUT optimization ------------------------------------------------------------------------------------------------ - -cmsUInt16Number _cmsQuantizeVal(cmsFloat64Number i, int MaxSamples); -int _cmsReasonableGridpointsByColorspace(cmsColorSpaceSignature Colorspace, cmsUInt32Number dwFlags); - -cmsBool _cmsEndPointsBySpace(cmsColorSpaceSignature Space, - cmsUInt16Number **White, - cmsUInt16Number **Black, - cmsUInt32Number *nOutputs); - -cmsBool _cmsOptimizePipeline(cmsContext ContextID, - cmsPipeline** Lut, - int Intent, - cmsUInt32Number* InputFormat, - cmsUInt32Number* OutputFormat, - cmsUInt32Number* dwFlags ); - - -// Hi level LUT building ---------------------------------------------------------------------------------------------- - -cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID, - cmsHPROFILE hProfiles[], - cmsBool BPC[], - cmsUInt32Number Intents[], - cmsFloat64Number AdaptationStates[], - cmsUInt32Number nGamutPCSposition, - cmsHPROFILE hGamut); - - -// Formatters ------------------------------------------------------------------------------------------------------------ - -#define cmsFLAGS_CAN_CHANGE_FORMATTER 0x02000000 // Allow change buffer format - -cmsBool _cmsFormatterIsFloat(cmsUInt32Number Type); -cmsBool _cmsFormatterIs8bit(cmsUInt32Number Type); - -cmsFormatter _cmsGetFormatter(cmsContext ContextID, - cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 - cmsFormatterDirection Dir, - cmsUInt32Number dwFlags); - - -#ifndef CMS_NO_HALF_SUPPORT - -// Half float -cmsFloat32Number _cmsHalf2Float(cmsUInt16Number h); -cmsUInt16Number _cmsFloat2Half(cmsFloat32Number flt); - -#endif - -// Transform logic ------------------------------------------------------------------------------------------------------ - -struct _cmstransform_struct; - -typedef struct { - - // 1-pixel cache (16 bits only) - cmsUInt16Number CacheIn[cmsMAXCHANNELS]; - cmsUInt16Number CacheOut[cmsMAXCHANNELS]; - -} _cmsCACHE; - - - -// Transformation -typedef struct _cmstransform_struct { - - cmsUInt32Number InputFormat, OutputFormat; // Keep formats for further reference - - // Points to transform code - _cmsTransformFn xform; - - // Formatters, cannot be embedded into LUT because cache - cmsFormatter16 FromInput; - cmsFormatter16 ToOutput; - - cmsFormatterFloat FromInputFloat; - cmsFormatterFloat ToOutputFloat; - - // 1-pixel cache seed for zero as input (16 bits, read only) - _cmsCACHE Cache; - - // A Pipeline holding the full (optimized) transform - cmsPipeline* Lut; - - // A Pipeline holding the gamut check. It goes from the input space to bilevel - cmsPipeline* GamutCheck; - - // Colorant tables - cmsNAMEDCOLORLIST* InputColorant; // Input Colorant table - cmsNAMEDCOLORLIST* OutputColorant; // Colorant table (for n chans > CMYK) - - // Informational only - cmsColorSpaceSignature EntryColorSpace; - cmsColorSpaceSignature ExitColorSpace; - - // White points (informative only) - cmsCIEXYZ EntryWhitePoint; - cmsCIEXYZ ExitWhitePoint; - - // Profiles used to create the transform - cmsSEQ* Sequence; - - cmsUInt32Number dwOriginalFlags; - cmsFloat64Number AdaptationState; - - // The intent of this transform. That is usually the last intent in the profilechain, but may differ - cmsUInt32Number RenderingIntent; - - // An id that uniquely identifies the running context. May be null. - cmsContext ContextID; - - // A user-defined pointer that can be used to store data for transform plug-ins - void* UserData; - _cmsFreeUserDataFn FreeUserData; - -} _cmsTRANSFORM; - -// -------------------------------------------------------------------------------------------------- - -cmsHTRANSFORM _cmsChain2Lab(cmsContext ContextID, - cmsUInt32Number nProfiles, - cmsUInt32Number InputFormat, - cmsUInt32Number OutputFormat, - const cmsUInt32Number Intents[], - const cmsHPROFILE hProfiles[], - const cmsBool BPC[], - const cmsFloat64Number AdaptationStates[], - cmsUInt32Number dwFlags); - - -cmsToneCurve* _cmsBuildKToneCurve(cmsContext ContextID, - cmsUInt32Number nPoints, - cmsUInt32Number nProfiles, - const cmsUInt32Number Intents[], - const cmsHPROFILE hProfiles[], - const cmsBool BPC[], - const cmsFloat64Number AdaptationStates[], - cmsUInt32Number dwFlags); - -cmsBool _cmsAdaptationMatrix(cmsMAT3* r, const cmsMAT3* ConeMatrix, const cmsCIEXYZ* FromIll, const cmsCIEXYZ* ToIll); - -cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePoint, const cmsCIExyYTRIPLE* Primaries); - - -#define _lcms_internal_H -#endif -//<<<+++OPENSOURCE_MUST_END |