summaryrefslogtreecommitdiffstats
path: root/debian/lcms/lcms-1.19.dfsg2/src/cmscnvrt.c
diff options
context:
space:
mode:
Diffstat (limited to 'debian/lcms/lcms-1.19.dfsg2/src/cmscnvrt.c')
-rwxr-xr-xdebian/lcms/lcms-1.19.dfsg2/src/cmscnvrt.c637
1 files changed, 637 insertions, 0 deletions
diff --git a/debian/lcms/lcms-1.19.dfsg2/src/cmscnvrt.c b/debian/lcms/lcms-1.19.dfsg2/src/cmscnvrt.c
new file mode 100755
index 00000000..7a4b23d4
--- /dev/null
+++ b/debian/lcms/lcms-1.19.dfsg2/src/cmscnvrt.c
@@ -0,0 +1,637 @@
+//
+// Little cms
+// Copyright (C) 1998-2007 Marti Maria
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the Software
+// is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+#include "lcms.h"
+
+
+
+
+/*
+ This module provides conversion stages for handling intents.
+
+The chain of evaluation in a transform is:
+
+ PCS1 PCS2 PCS3 PCS4
+
+|From | |From | |Conversion | |Preview | |Gamut | |Conversion | |To | |To |
+|Input|->|Device|->|Stage 1 |->|handling|->|Checking|->|Stage 2 |->|Device|->|output |
+
+-------- ------- ------------- --------- ---------- ------------- ------- ---------
+
+ AToB0 prew0 gamut BToA0
+Formatting LUT Adjusting LUT LUT Adjusting LUT Formatting
+ Intent Intent 1 intent intent Intent 2 Intent
+
+
+Some of these LUT may be missing
+
+There are two intents involved here, the intent of the transform itself, and the
+intent the proof is being done, if is the case. Since the first intent is to be
+applied to preview, is the proofing intent. The second intent identifies the
+transform intent. Input data of any stage is taked as relative colorimetric
+always.
+
+
+NOTES: V4 states than perceptual & saturation intents between mixed v2 & v4 profiles should
+scale PCS from a black point equal to ZERO in v2 profiles to the reference media black of
+perceptual v4 PCS. Since I found many v2 profiles to be using a perceptual intent with black
+point not zero at all, I'm implementing that as a black point compensation from whatever
+black from perceptal intent to the reference media black for v4 profiles.
+
+*/
+
+
+
+
+int cdecl cmsChooseCnvrt(int Absolute,
+ int Phase1, LPcmsCIEXYZ BlackPointIn,
+ LPcmsCIEXYZ WhitePointIn,
+ LPcmsCIEXYZ IlluminantIn,
+ LPMAT3 ChromaticAdaptationMatrixIn,
+
+ int Phase2, LPcmsCIEXYZ BlackPointOut,
+ LPcmsCIEXYZ WhitePointOut,
+ LPcmsCIEXYZ IlluminantOut,
+ LPMAT3 ChromaticAdaptationMatrixOut,
+
+ int DoBlackPointCompensation,
+ double AdaptationState,
+ _cmsADJFN *fn1,
+ LPWMAT3 wm, LPWVEC3 wof);
+
+
+// -------------------------------------------------------------------------
+
+// D50 - Widely used
+
+LCMSAPI LPcmsCIEXYZ LCMSEXPORT cmsD50_XYZ(void)
+{
+ static cmsCIEXYZ D50XYZ = {D50X, D50Y, D50Z};
+
+ return &D50XYZ;
+}
+
+LCMSAPI LPcmsCIExyY LCMSEXPORT cmsD50_xyY(void)
+{
+ static cmsCIExyY D50xyY;
+ cmsXYZ2xyY(&D50xyY, cmsD50_XYZ());
+
+ return &D50xyY;
+}
+
+
+// ---------------- From LUT to LUT --------------------------
+
+
+// Calculate m, offset Relativ -> Absolute undoing any chromatic
+// adaptation done by the profile.
+
+#ifdef _MSC_VER
+#pragma warning(disable : 4100 4505)
+#endif
+
+
+
+// join scalings to obtain:
+// relative input to absolute and then to relative output
+
+static
+void Rel2RelStepAbsCoefs(double AdaptationState,
+
+ LPcmsCIEXYZ BlackPointIn,
+ LPcmsCIEXYZ WhitePointIn,
+ LPcmsCIEXYZ IlluminantIn,
+ LPMAT3 ChromaticAdaptationMatrixIn,
+
+ LPcmsCIEXYZ BlackPointOut,
+ LPcmsCIEXYZ WhitePointOut,
+ LPcmsCIEXYZ IlluminantOut,
+ LPMAT3 ChromaticAdaptationMatrixOut,
+
+ LPMAT3 m, LPVEC3 of)
+{
+
+ VEC3 WtPtIn, WtPtInAdapted;
+ VEC3 WtPtOut, WtPtOutAdapted;
+ MAT3 Scale, m1, m2, m3;
+
+ VEC3init(&WtPtIn, WhitePointIn->X, WhitePointIn->Y, WhitePointIn->Z);
+ MAT3eval(&WtPtInAdapted, ChromaticAdaptationMatrixIn, &WtPtIn);
+
+ VEC3init(&WtPtOut, WhitePointOut->X, WhitePointOut->Y, WhitePointOut->Z);
+ MAT3eval(&WtPtOutAdapted, ChromaticAdaptationMatrixOut, &WtPtOut);
+
+ VEC3init(&Scale.v[0], WtPtInAdapted.n[0] / WtPtOutAdapted.n[0], 0, 0);
+ VEC3init(&Scale.v[1], 0, WtPtInAdapted.n[1] / WtPtOutAdapted.n[1], 0);
+ VEC3init(&Scale.v[2], 0, 0, WtPtInAdapted.n[2] / WtPtOutAdapted.n[2]);
+
+
+ // Adaptation state
+
+ if (AdaptationState == 1.0) {
+
+ // Observer is fully adapted. Keep chromatic adaptation
+
+ CopyMemory(m, &Scale, sizeof(MAT3));
+
+ }
+ else {
+
+ // Observer is not adapted, undo the chromatic adaptation
+ m1 = *ChromaticAdaptationMatrixIn;
+ MAT3inverse(&m1, &m2);
+
+ MAT3per(&m3, &m2, &Scale);
+ MAT3per(m, &m3, ChromaticAdaptationMatrixOut);
+ }
+
+
+ VEC3init(of, 0.0, 0.0, 0.0);
+
+}
+
+
+// The (in)famous black point compensation. Right now implemented as
+// a linear scaling in XYZ
+
+static
+void ComputeBlackPointCompensationFactors(LPcmsCIEXYZ BlackPointIn,
+ LPcmsCIEXYZ WhitePointIn,
+ LPcmsCIEXYZ IlluminantIn,
+ LPcmsCIEXYZ BlackPointOut,
+ LPcmsCIEXYZ WhitePointOut,
+ LPcmsCIEXYZ IlluminantOut,
+ LPMAT3 m, LPVEC3 of)
+{
+
+
+ cmsCIEXYZ RelativeBlackPointIn, RelativeBlackPointOut;
+ double ax, ay, az, bx, by, bz, tx, ty, tz;
+
+ // At first, convert both black points to relative.
+
+ cmsAdaptToIlluminant(&RelativeBlackPointIn, WhitePointIn, IlluminantIn, BlackPointIn);
+ cmsAdaptToIlluminant(&RelativeBlackPointOut, WhitePointOut, IlluminantOut, BlackPointOut);
+
+ // 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 = RelativeBlackPointIn.X - IlluminantIn ->X;
+ ty = RelativeBlackPointIn.Y - IlluminantIn ->Y;
+ tz = RelativeBlackPointIn.Z - IlluminantIn ->Z;
+
+ ax = (RelativeBlackPointOut.X - IlluminantOut ->X) / tx;
+ ay = (RelativeBlackPointOut.Y - IlluminantOut ->Y) / ty;
+ az = (RelativeBlackPointOut.Z - IlluminantOut ->Z) / tz;
+
+ bx = - IlluminantOut -> X * (RelativeBlackPointOut.X - RelativeBlackPointIn.X) / tx;
+ by = - IlluminantOut -> Y * (RelativeBlackPointOut.Y - RelativeBlackPointIn.Y) / ty;
+ bz = - IlluminantOut -> Z * (RelativeBlackPointOut.Z - RelativeBlackPointIn.Z) / tz;
+
+
+ MAT3identity(m);
+
+ m->v[VX].n[0] = ax;
+ m->v[VY].n[1] = ay;
+ m->v[VZ].n[2] = az;
+
+ VEC3init(of, bx, by, bz);
+
+}
+
+// Return TRUE if both m and of are empy -- "m" being identity and "of" being 0
+
+static
+LCMSBOOL IdentityParameters(LPWMAT3 m, LPWVEC3 of)
+{
+ WVEC3 wv0;
+
+ VEC3initF(&wv0, 0, 0, 0);
+
+ if (!MAT3isIdentity(m, 0.00001)) return FALSE;
+ if (!VEC3equal(of, &wv0, 0.00001)) return FALSE;
+
+ return TRUE;
+}
+
+
+
+
+// ----------------------------------------- Inter PCS conversions
+
+// XYZ to XYZ linear scaling. Aso used on Black point compensation
+
+static
+void XYZ2XYZ(WORD In[], WORD Out[], LPWMAT3 m, LPWVEC3 of)
+{
+
+ WVEC3 a, r;
+
+ a.n[0] = In[0] << 1;
+ a.n[1] = In[1] << 1;
+ a.n[2] = In[2] << 1;
+
+ MAT3evalW(&r, m, &a);
+
+ Out[0] = _cmsClampWord((r.n[VX] + of->n[VX]) >> 1);
+ Out[1] = _cmsClampWord((r.n[VY] + of->n[VY]) >> 1);
+ Out[2] = _cmsClampWord((r.n[VZ] + of->n[VZ]) >> 1);
+}
+
+
+// XYZ to Lab, scaling first
+
+static
+void XYZ2Lab(WORD In[], WORD Out[], LPWMAT3 m, LPWVEC3 of)
+{
+ WORD XYZ[3];
+
+ XYZ2XYZ(In, XYZ, m, of);
+ cmsXYZ2LabEncoded(XYZ, Out);
+}
+
+// Lab to XYZ, then scalling
+
+static
+void Lab2XYZ(WORD In[], WORD Out[], LPWMAT3 m, LPWVEC3 of)
+{
+ WORD XYZ[3];
+
+ cmsLab2XYZEncoded(In, XYZ);
+ XYZ2XYZ(XYZ, Out, m, of);
+}
+
+// Lab to XYZ, scalling and then, back to Lab
+
+static
+void Lab2XYZ2Lab(WORD In[], WORD Out[], LPWMAT3 m, LPWVEC3 of)
+{
+ WORD XYZ[3], XYZ2[3];
+
+ cmsLab2XYZEncoded(In, XYZ);
+ XYZ2XYZ(XYZ, XYZ2, m, of);
+ cmsXYZ2LabEncoded(XYZ2, Out);
+}
+
+// ------------------------------------------------------------------
+
+// Dispatcher for XYZ Relative LUT
+
+static
+int FromXYZRelLUT(int Absolute,
+ LPcmsCIEXYZ BlackPointIn,
+ LPcmsCIEXYZ WhitePointIn,
+ LPcmsCIEXYZ IlluminantIn,
+ LPMAT3 ChromaticAdaptationMatrixIn,
+
+ int Phase2, LPcmsCIEXYZ BlackPointOut,
+ LPcmsCIEXYZ WhitePointOut,
+ LPcmsCIEXYZ IlluminantOut,
+ LPMAT3 ChromaticAdaptationMatrixOut,
+
+ int DoBlackPointCompensation,
+ double AdaptationState,
+ _cmsADJFN *fn1,
+ LPMAT3 m, LPVEC3 of)
+
+{
+ switch (Phase2) {
+
+ // From relative XYZ to Relative XYZ.
+
+ case XYZRel:
+
+ if (Absolute)
+ {
+ // From input relative to absolute, and then
+ // back to output relative
+
+ Rel2RelStepAbsCoefs(AdaptationState,
+ BlackPointIn,
+ WhitePointIn,
+ IlluminantIn,
+ ChromaticAdaptationMatrixIn,
+ BlackPointOut,
+ WhitePointOut,
+ IlluminantOut,
+ ChromaticAdaptationMatrixOut,
+ m, of);
+ *fn1 = XYZ2XYZ;
+
+ }
+ else
+ {
+ // XYZ Relative to XYZ relative, no op required
+ *fn1 = NULL;
+ if (DoBlackPointCompensation) {
+
+ *fn1 = XYZ2XYZ;
+ ComputeBlackPointCompensationFactors(BlackPointIn,
+ WhitePointIn,
+ IlluminantIn,
+ BlackPointOut,
+ WhitePointOut,
+ IlluminantOut,
+ m, of);
+
+ }
+ }
+ break;
+
+
+ // From relative XYZ to Relative Lab
+
+ case LabRel:
+
+ // First pass XYZ to absolute, then to relative and
+ // finally to Lab. I use here D50 for output in order
+ // to prepare the "to Lab" conversion.
+
+ if (Absolute)
+ {
+
+ Rel2RelStepAbsCoefs(AdaptationState,
+ BlackPointIn,
+ WhitePointIn,
+ IlluminantIn,
+ ChromaticAdaptationMatrixIn,
+ BlackPointOut,
+ WhitePointOut,
+ IlluminantOut,
+ ChromaticAdaptationMatrixOut,
+ m, of);
+
+ *fn1 = XYZ2Lab;
+
+ }
+ else
+ {
+ // Just Convert to Lab
+
+ MAT3identity(m);
+ VEC3init(of, 0, 0, 0);
+ *fn1 = XYZ2Lab;
+
+ if (DoBlackPointCompensation) {
+
+ ComputeBlackPointCompensationFactors(BlackPointIn,
+ WhitePointIn,
+ IlluminantIn,
+ BlackPointOut,
+ WhitePointOut,
+ IlluminantOut,
+ m, of);
+ }
+ }
+ break;
+
+
+ default: return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+
+// From Lab Relative type LUT
+
+static
+int FromLabRelLUT(int Absolute,
+ LPcmsCIEXYZ BlackPointIn,
+ LPcmsCIEXYZ WhitePointIn,
+ LPcmsCIEXYZ IlluminantIn,
+ LPMAT3 ChromaticAdaptationMatrixIn,
+
+ int Phase2, LPcmsCIEXYZ BlackPointOut,
+ LPcmsCIEXYZ WhitePointOut,
+ LPcmsCIEXYZ IlluminantOut,
+ LPMAT3 ChromaticAdaptationMatrixOut,
+
+ int DoBlackPointCompensation,
+ double AdaptationState,
+
+ _cmsADJFN *fn1,
+ LPMAT3 m, LPVEC3 of)
+{
+
+ switch (Phase2) {
+
+ // From Lab Relative to XYZ Relative, very usual case
+
+ case XYZRel:
+
+ if (Absolute) { // Absolute intent
+
+ // From lab relative, to XYZ absolute, and then,
+ // back to XYZ relative
+
+ Rel2RelStepAbsCoefs(AdaptationState,
+ BlackPointIn,
+ WhitePointIn,
+ cmsD50_XYZ(),
+ ChromaticAdaptationMatrixIn,
+ BlackPointOut,
+ WhitePointOut,
+ IlluminantOut,
+ ChromaticAdaptationMatrixOut,
+ m, of);
+
+ *fn1 = Lab2XYZ;
+
+ }
+ else
+ {
+ // From Lab relative, to XYZ relative.
+
+ *fn1 = Lab2XYZ;
+ if (DoBlackPointCompensation) {
+
+ ComputeBlackPointCompensationFactors(BlackPointIn,
+ WhitePointIn,
+ IlluminantIn,
+ BlackPointOut,
+ WhitePointOut,
+ IlluminantOut,
+ m, of);
+
+ }
+ }
+ break;
+
+
+
+ case LabRel:
+
+ if (Absolute) {
+
+ // First pass to XYZ using the input illuminant
+ // * InIlluminant / D50, then to absolute. Then
+ // to relative, but for input
+
+ Rel2RelStepAbsCoefs(AdaptationState,
+ BlackPointIn,
+ WhitePointIn, IlluminantIn,
+ ChromaticAdaptationMatrixIn,
+ BlackPointOut,
+ WhitePointOut, cmsD50_XYZ(),
+ ChromaticAdaptationMatrixOut,
+ m, of);
+ *fn1 = Lab2XYZ2Lab;
+ }
+ else
+ { // Lab -> Lab relative don't need any adjust unless
+ // black point compensation
+
+ *fn1 = NULL;
+ if (DoBlackPointCompensation) {
+
+ *fn1 = Lab2XYZ2Lab;
+ ComputeBlackPointCompensationFactors(BlackPointIn,
+ WhitePointIn,
+ IlluminantIn,
+ BlackPointOut,
+ WhitePointOut,
+ IlluminantOut,
+ m, of);
+
+
+ }
+ }
+ break;
+
+
+ default: return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+// This function does calculate the necessary conversion operations
+// needed from transpassing data from a LUT to a LUT. The conversion
+// is modeled as a pointer of function and two coefficients, a and b
+// The function is actually called only if not null pointer is provided,
+// and the two paramaters are passed in. There are several types of
+// conversions, but basically they do a linear scalling and a interchange
+
+
+
+// Main dispatcher
+
+int cmsChooseCnvrt(int Absolute,
+ int Phase1, LPcmsCIEXYZ BlackPointIn,
+ LPcmsCIEXYZ WhitePointIn,
+ LPcmsCIEXYZ IlluminantIn,
+ LPMAT3 ChromaticAdaptationMatrixIn,
+
+ int Phase2, LPcmsCIEXYZ BlackPointOut,
+ LPcmsCIEXYZ WhitePointOut,
+ LPcmsCIEXYZ IlluminantOut,
+ LPMAT3 ChromaticAdaptationMatrixOut,
+
+ int DoBlackPointCompensation,
+ double AdaptationState,
+ _cmsADJFN *fn1,
+ LPWMAT3 wm, LPWVEC3 wof)
+{
+
+ int rc;
+ MAT3 m;
+ VEC3 of;
+
+
+ MAT3identity(&m);
+ VEC3init(&of, 0, 0, 0);
+
+ switch (Phase1) {
+
+ // Input LUT is giving XYZ relative values.
+
+ case XYZRel: rc = FromXYZRelLUT(Absolute,
+ BlackPointIn,
+ WhitePointIn,
+ IlluminantIn,
+ ChromaticAdaptationMatrixIn,
+ Phase2,
+ BlackPointOut,
+ WhitePointOut,
+ IlluminantOut,
+ ChromaticAdaptationMatrixOut,
+ DoBlackPointCompensation,
+ AdaptationState,
+ fn1, &m, &of);
+ break;
+
+
+
+ // Input LUT is giving Lab relative values
+
+ case LabRel: rc = FromLabRelLUT(Absolute,
+ BlackPointIn,
+ WhitePointIn,
+ IlluminantIn,
+ ChromaticAdaptationMatrixIn,
+ Phase2,
+ BlackPointOut,
+ WhitePointOut,
+ IlluminantOut,
+ ChromaticAdaptationMatrixOut,
+ DoBlackPointCompensation,
+ AdaptationState,
+ fn1, &m, &of);
+ break;
+
+
+
+
+ // Unrecognized combination
+
+ default: cmsSignalError(LCMS_ERRC_ABORTED, "(internal) Phase error");
+ return FALSE;
+
+ }
+
+ MAT3toFix(wm, &m);
+ VEC3toFix(wof, &of);
+
+ // Do some optimization -- discard conversion if identity parameters.
+
+ if (*fn1 == XYZ2XYZ || *fn1 == Lab2XYZ2Lab) {
+
+ if (IdentityParameters(wm, wof))
+ *fn1 = NULL;
+ }
+
+
+ return rc;
+}
+
+
+