cmsgmt.c revision 2693
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
// This file is available under and governed by the GNU General Public
// License version 2 only, as published by the Free Software Foundation.
// However, the following notice accompanied the original version of this
// file:
//
//---------------------------------------------------------------------------------
//
// 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,
// 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.
const cmsUInt32Number Intents[],
const cmsHPROFILE hProfiles[],
const cmsFloat64Number AdaptationStates[],
{
// 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
// The output space
// Create a copy of parameters
for (i=0; i < nProfiles; i++) {
ProfileList[i] = hProfiles[i];
AdaptationList[i] = AdaptationStates[i];
IntentList[i] = Intents[i];
}
// Place Lab identity at chain's end.
// Create the transform
NULL, 0,
dwFlags);
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
const cmsUInt32Number Intents[],
const cmsHPROFILE hProfiles[],
const cmsFloat64Number AdaptationStates[],
{
xform = _cmsChain2Lab(ContextID, nProfiles, TYPE_CMYK_FLT, TYPE_Lab_DBL, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
for (i=0; i < nPoints; i++) {
cmyk[0] = 0;
cmyk[1] = 0;
cmyk[2] = 0;
}
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.
const cmsUInt32Number Intents[],
const cmsHPROFILE hProfiles[],
const cmsFloat64Number AdaptationStates[],
{
// Make sure CMYK -> CMYK
// Make sure last is an output profile
// 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);
dwFlags);
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
// Get rid of components
// Something went wrong...
// Make sure it is monotonic
if (!cmsIsToneCurveMonotonic(KTone)) {
return NULL;
}
return KTone;
}
// Gamut LUT Creation -----------------------------------------------------------------------------------------
// Used by gamut & softproofing
typedef struct {
} 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)
{
// Assume in-gamut by default.
dE1 = 0.;
dE2 = 0;
ErrorRatio = 1.0;
// Convert input to Lab
// converts from PCS to colorant. This always
// does return in-gamut values,
// Now, do the inverse, from colorant to PCS.
// Try again, but this time taking Check as input
// Take difference of direct value
// Take difference of converted value
// if dE1 is small and dE2 is small, value is likely to be in gamut
Out[0] = 0;
else {
// if dE1 is small and dE2 is big, undefined. Assume in gamut
Out[0] = 0;
else
// dE1 is big and dE2 is small, clearly out of gamut
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
if (ErrorRatio > t->Thereshold)
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.
{
int nChannels, nGridpoints;
cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong position of PCS. 1..255 expected, %d found.", nGamutPCSposition);
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)) {
}
else {
}
// Create a copy of parameters
for (i=0; i < nGamutPCSposition; i++) {
ProfileList[i] = hProfiles[i];
AdaptationList[i] = AdaptationStates[i];
IntentList[i] = Intents[i];
}
// Fill Lab identity
BPCList[nGamutPCSposition] = 0;
// 16 bits to Lab double
nGamutPCSposition + 1,
NULL, 0,
// Does create the forward step. Lab double to cmsFloat32Number
// Does create the backwards step
// All ok?
// 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.
}
}
else
// Free all needed stuff.
// And return computed hull
return Gamut;
}
// Total Area Coverage estimation ----------------------------------------------------------------
typedef struct {
// 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)
{
// Evaluate the xform
// All all amounts of ink
// If above maximum, keep track of input values
for (i=0; i < bp ->nOutputChans; i++) {
}
}
return TRUE;
}
// Detect Total area coverage of the profile
{
// TAC only works on output profiles
return 0;
}
// Create a fake formatter for result
// for safety
// Setup a roundtrip on perceptual intent in output profile for TAC estimation
// For L* we only need black and white. For C* we need many points
GridPoints[0] = 6;
}
// Results in %
}
// Carefully, clamp on CIELab space.
{
// Whole Luma surface to zero
if (Lab -> L < 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
double h, slope;
// Falls outside a, b limits. Transports to LCh space,
// and then do the clipping
// atan will not work, so clamp here
return TRUE;
}
h = LCh.h;
// There are 4 zones
if ((h >= 0. && h < 45.) ||
(h >= 315 && h <= 360.)) {
// clip by amax
}
else
if (h >= 45. && h < 135.)
{
// clip by bmax
}
else
if (h >= 135. && h < 225.) {
// clip by amin
}
else
if (h >= 225. && h < 315.) {
// clip by bmin
}
else {
return FALSE;
}
}
return TRUE;
}