cmsgmt.c revision 0
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 0N/A * This code is free software; you can redistribute it and/or modify it 0N/A * under the terms of the GNU General Public License version 2 only, as 0N/A * published by the Free Software Foundation. Sun designates this 0N/A * particular file as subject to the "Classpath" exception as provided 0N/A * by Sun in the LICENSE file that accompanied this code. 0N/A * This code is distributed in the hope that it will be useful, but WITHOUT 0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 0N/A * version 2 for more details (a copy is included in the LICENSE file that 0N/A * accompanied this code). 0N/A * You should have received a copy of the GNU General Public License version 0N/A * 2 along with this work; if not, write to the Free Software Foundation, 0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 0N/A * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 0N/A * CA 95054 USA or visit www.sun.com if you need additional information or 0N/A * have any questions. 0N/A// This file is available under and governed by the GNU General Public 0N/A// License version 2 only, as published by the Free Software Foundation. 0N/A// However, the following notice accompanied the original version of this 0N/A// Copyright (C) 1998-2006 Marti Maria 0N/A// Permission is hereby granted, free of charge, to any person obtaining 0N/A// a copy of this software and associated documentation files (the "Software"), 0N/A// to deal in the Software without restriction, including without limitation 0N/A// the rights to use, copy, modify, merge, publish, distribute, sublicense, 0N/A// and/or sell copies of the Software, and to permit persons to whom the Software 0N/A// is furnished to do so, subject to the following conditions: 0N/A// The above copyright notice and this permission notice shall be included in 0N/A// all copies or substantial portions of the Software. 0N/A// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 0N/A// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 0N/A// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 0N/A// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 0N/A// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 0N/A// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 0N/A// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 0N/AGamut check by default is a catching of 0xFFFF/0xFFFF/0xFFFF PCS values, used 0N/Ainternally by lcms to hold invalid values. Matrix LUT's, operates in a way that 0N/Aunencodeable values are marked as this combination, if PCS is XYZ, this is a very 0N/Ahigh value since encoding is a 1.15 fixed point, something like 1.9997, 1.9997, 1.9997 0N/Anot a very common color after all. Lab PCS is not to be a problem, since L>100 are truely 0N/Aundefined. There is a posibility than ICC comitee defines L>100 as a valid means 0N/Ato use highlights, then it will be lost. 0N/A(1.10 - Actually ICC did it, so this should be checked for full ICC 4.0 support) 0N/A // Only most common spaces 0N/A if (
in ==
0xFFFF)
return 0xFFFFU;
// Marker 0N/A if (
in >
0xFF00)
return 0xFF00U;
// L* = 100.0 0N/A if (
in ==
0xFFFF)
return 0xFFFFU;
// Marker 0N/A// Returns dE on two Lab values 0N/A if (
Lab1 -> a < -
200 ||
Lab1 -> a >
200)
return 65536.;
0N/A if (
Lab1 -> b < -
200 ||
Lab1 -> b >
200)
return 65536.;
0N/A if (
Lab2 -> a < -
200 ||
Lab2 -> a >
200)
return 65536.;
0N/A if (
Lab2 -> b < -
200 ||
Lab2 -> b >
200)
return 65536.;
0N/A// Return the CIE94 Delta E 0N/A// bfd - gets BFD(1:1) difference between Lab1, Lab2 0N/A// cmc - CMC(1:1) difference between Lab1, Lab2 0N/A if (a == 0 && b == 0)
0N/A// dE2000 The weightings KL, KC and KH can be modified to reflect the relative 0N/A// importance of lightness, chroma and hue in different industrial applications 0N/A double G =
0.5 * (
1 -
sqrt(
pow((C +
Cs) /
2 ,
7.0) / (
pow((C +
Cs) /
2,
7.0) +
pow(
25.0,
7.0) ) ));
0N/A// Carefully, clamp on CIELab space. 0N/A // Whole Luma surface to zero 0N/A // Clamp white, DISCARD HIGHLIGHTS. This is done 0N/A // in such way because icc spec doesn't allow the 0N/A // use of L>100 as a highlight means. 0N/A // Check out gamut prism, on a, b faces 0N/A // Falls outside a, b limits. Transports to LCh space, 0N/A // and then do the clipping 0N/A if (
Lab -> a ==
0.0) {
// Is hue exactly 90? 0N/A // atan will not work, so clamp here 0N/A // There are 4 zones 0N/A if ((h >= 0. && h <
45.) ||
0N/A (h >=
315 && h <=
360.)) {
0N/A if (h >=
45. && h <
135)
0N/A if (h >=
135 && h <
225) {
0N/A if (h >=
225 && h <
315) {
0N/A// Several utilities ------------------------------------------------------- 0N/A// Translate from our colorspace to ICC representation 0N/A// v2 L=100 is supposed to be placed on 0xFF00. There is no reasonable 0N/A// number of gridpoints that would make exact match. However, a 0N/A// prelinearization of 258 entries, would map 0xFF00 on entry 257. 0N/A// This is almost what we need, unfortunately, the rest of entries 0N/A// should be scaled by (255*257/256) and this is not exact. 0N/A// An intermediate solution would be to use 257 entries. This does not 0N/A// map 0xFF00 exactly on a node, but so close that the dE induced is 0N/A// negligible. AND the rest of curve is exact. 0N/A // L* uses 257 entries. Entry 256 holds 0xFFFF, so, the effective range 0N/A // is 0..0xFF00. Last entry (257) is also collapsed to 0xFFFF 0N/A for (i=0; i <
256; i++)
0N/A // Repeat last for 0xFFFF 0N/A// Used by gamut & softproofing 0N/A double Thereshold;
// The thereshold after which is considered out of gamut 0N/A// This sampler does compute gamut boundaries by comparing original 0N/A// values with a transform going back and forth. Values above ERR_THERESHOLD 0N/A// of maximum are considered out of gamut. 0N/A // Assume in-gamut by default. 0N/A // Any input space? I can use In[] no matter channels 0N/A // because is just one pixel 0N/A // converts from PCS to colorant. This always 0N/A // does return in-gamut values, 0N/A // Now, do the inverse, from colorant to PCS. 0N/A // Try again, but this time taking Check as input 0N/A // Does the transform returns out-of-gamut? 0N/A Out[0] =
0xFF00;
// Out of gamut! 0N/A // Transport encoded values 0N/A // Take difference of direct value 0N/A // Take difference of converted value 0N/A // if dE1 is small and dE2 is small, value is likely to be in gamut 0N/A // if dE1 is small and dE2 is big, undefined. Assume in gamut 0N/A // dE1 is big and dE2 is small, clearly out of gamut 0N/A // dE1 is big and dE2 is also big, could be due to perceptual mapping 0N/A // so take error ratio 0N/A// Does compute a gamut LUT going back and forth across 0N/A// pcs -> relativ. colorimetric intent -> pcs 0N/A// the dE obtained is then annotated on the LUT. 0N/A// values truely out of gamut, are clipped to dE = 0xFFFE 0N/A// and values changed are supposed to be handled by 0N/A// any gamut remapping, so, are out of gamut as well. 0N/A// **WARNING: This algorithm does assume that gamut 0N/A// remapping algorithms does NOT move in-gamut colors, 0N/A// of course, many perceptual and saturation intents does 0N/A// not work in such way, but relativ. ones should. 0N/A // Safeguard against early abortion 0N/A // The figure of merit. On matrix-shaper profiles, should be almost zero as 0N/A // the conversion is pretty exact. On LUT based profiles, different resolutions 0N/A // of input and output CLUT may result in differences. 0N/A // If input profile specified, create a transform from such profile to Lab 0N/A // Input transform=NULL (Lab) Used to compute the gamut tag 0N/A // This table will take 53 points to give some accurancy, 0N/A // 53 * 53 * 53 * 2 = 291K 0N/A // Does create the forward step 0N/A // Does create the backwards step 0N/A // Restores error handler previous state 0N/A // Go on, try to compute gamut LUT from PCS. 0N/A // This consist on a single channel containing 0N/A // dE when doing a transform back and forth on 0N/A // the colorimetric intent. 0N/A // If no input, then this is a gamut tag operated by Lab, 0N/A // so include pertinent prelinearization 0N/A // Free all needed stuff. 0N/A // And return computed hull 0N/A// This routine does compute the gamut check CLUT. This CLUT goes from whatever 0N/A// input space to the 0 or != 0 gamut check. 0N/A// SoftProofing. Convert from Lab to device, then back to Lab, 0N/A// any gamut remapping is applied 0N/A // From pcs to colorant 0N/A // Now, do the inverse, from colorant to pcs. 0N/A// Does return Softproofing LUT on desired intent 0N/A // LUTs are never abs. colorimetric, is the transform who 0N/A // is responsible of generating white point displacement 0N/A // Safeguard against early abortion 0N/A // Does create the first step 0N/A // Does create the last step 0N/A // Restores error handler previous state 0N/A // This is Lab -> Lab, so 33 point should hold anything 0N/A // Free all needed stuff. 0N/A// Check for monotonicity. 0N/A for (i = n-
2; i >= 0; --i) {
0N/A// Check for endpoints 0N/A// Fixes the gamma balancing of transform. Thanks to Mike Chaney 0N/A// for pointing this subtle bug. 0N/A unsigned int t, i, v;
0N/A // First space is *Lab, use our specialized curves for v2 Lab 0N/A // Do nothing on all but RGB to RGB transforms 0N/A // Check transfer curves 0N/A // Exclude if already linear 0N/A // Exclude if non-monotonic 0N/A // Exclude if weird endpoints 0N/A // Exclude if transfer function is not smooth enough 0N/A // to be modelled as a gamma function, or the gamma is reversed 0N/A// Compute K -> L* relationship. Flags may include black point compensation. In this case, 0N/A// the relationship is assumed from the profile with BPC to a black point zero. 0N/A// Compute Black tone curve on a CMYK -> CMYK transform. This is done by 0N/A// using the proof direction on both profiles to find K->L* relationship 0N/A// then joining both curves. dwFlags may include black point compensation. 0N/A // Make sure CMYK -> CMYK 0N/A // Create individual curves. BPC works also as each K to L* is 0N/A // computed as a BPC to zero black point in case of L* 0N/A // Build the relationship 0N/A // Make sure it is monotonic