提交 6656a101 编写于 作者: P prr

8078331: Upgrade JDK to use LittleCMS 2.7

Reviewed-by: serb, bae
上级 5e414292
......@@ -353,7 +353,7 @@ static const char* PredefinedSampleID[] = {
"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_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
......
......@@ -298,6 +298,8 @@ cmsBool ComputeAbsoluteIntent(cmsFloat64Number AdaptationState,
{
cmsMAT3 Scale, m1, m2, m3, m4;
// TODO: Follow Marc Mahy's recommendation to check if CHAD is same by using M1*M2 == M2*M1. If so, do nothing.
// Adaptation state
if (AdaptationState == 1.0) {
......@@ -559,7 +561,7 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID,
cmsHPROFILE hProfile;
cmsMAT3 m;
cmsVEC3 off;
cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut, CurrentColorSpace;
cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut = cmsSigLabData, CurrentColorSpace;
cmsProfileClassSignature ClassSig;
cmsUInt32Number i, Intent;
......@@ -661,6 +663,22 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID,
CurrentColorSpace = ColorSpaceOut;
}
// Check for non-negatives clip
if (dwFlags & cmsFLAGS_NONEGATIVES) {
if (ColorSpaceOut == cmsSigGrayData ||
ColorSpaceOut == cmsSigRgbData ||
ColorSpaceOut == cmsSigCmykData) {
cmsStage* clip = _cmsStageClipNegatives(Result->ContextID, cmsChannelsOf(ColorSpaceOut));
if (clip == NULL) goto Error;
if (!cmsPipelineInsertStage(Result, cmsAT_END, clip))
goto Error;
}
}
return Result;
Error:
......@@ -1074,7 +1092,7 @@ cmsPipeline* _cmsLinkProfiles(cmsContext ContextID,
if (TheIntents[i] == INTENT_PERCEPTUAL || TheIntents[i] == INTENT_SATURATION) {
// Force BPC for V4 profiles in perceptual and saturation
if (cmsGetProfileVersion(hProfiles[i]) >= 4.0)
if (cmsGetEncodedICCversion(hProfiles[i]) >= 0x4000000)
BPC[i] = TRUE;
}
}
......
......@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2012 Marti Maria Saguer
// Copyright (c) 1998-2015 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"),
......@@ -54,6 +54,13 @@
#include "lcms2_internal.h"
// This function is here to help applications to prevent mixing lcms versions on header and shared objects.
int CMSEXPORT cmsGetEncodedCMMversion(void)
{
return LCMS_VERSION;
}
// I am so tired about incompatibilities on those functions that here are some replacements
// that hopefully would be fully portable.
......
......@@ -958,7 +958,7 @@ void Eval4Inputs(register const cmsUInt16Number Input[],
Rest = c1 * rx + c2 * ry + c3 * rz;
Tmp1[OutChan] = (cmsUInt16Number) c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest));
Tmp1[OutChan] = (cmsUInt16Number) ( c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)));
}
......@@ -1022,7 +1022,7 @@ void Eval4Inputs(register const cmsUInt16Number Input[],
Rest = c1 * rx + c2 * ry + c3 * rz;
Tmp2[OutChan] = (cmsUInt16Number) c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest));
Tmp2[OutChan] = (cmsUInt16Number) (c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)));
}
......
......@@ -482,6 +482,14 @@ cmsBool CMSEXPORT cmsCloseIOhandler(cmsIOHANDLER* io)
// -------------------------------------------------------------------------------------------------------
cmsIOHANDLER* CMSEXPORT cmsGetProfileIOhandler(cmsHPROFILE hProfile)
{
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*)hProfile;
if (Icc == NULL) return NULL;
return Icc->IOhandler;
}
// Creates an empty structure holding all required parameters
cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID)
{
......@@ -651,25 +659,26 @@ cmsBool CMSEXPORT cmsIsTag(cmsHPROFILE hProfile, cmsTagSignature sig)
return _cmsSearchTag(Icc, sig, FALSE) >= 0;
}
/*
* Enforces that the profile version is per. spec.
* Operates on the big endian bytes from the profile.
* Called before converting to platform endianness.
* Byte 0 is BCD major version, so max 9.
* Byte 1 is 2 BCD digits, one per nibble.
* Reserved bytes 2 & 3 must be 0.
*/
static cmsUInt32Number _validatedVersion(cmsUInt32Number DWord)
// Enforces that the profile version is per. spec.
// Operates on the big endian bytes from the profile.
// Called before converting to platform endianness.
// Byte 0 is BCD major version, so max 9.
// Byte 1 is 2 BCD digits, one per nibble.
// Reserved bytes 2 & 3 must be 0.
static
cmsUInt32Number _validatedVersion(cmsUInt32Number DWord)
{
cmsUInt8Number* pByte = (cmsUInt8Number*)&DWord;
cmsUInt8Number* pByte = (cmsUInt8Number*) &DWord;
cmsUInt8Number temp1;
cmsUInt8Number temp2;
if (*pByte > 0x09) *pByte = (cmsUInt8Number)9;
if (*pByte > 0x09) *pByte = (cmsUInt8Number) 0x09;
temp1 = *(pByte+1) & 0xf0;
temp2 = *(pByte+1) & 0x0f;
if (temp1 > 0x90) temp1 = 0x90;
if (temp2 > 9) temp2 = 0x09;
if (temp2 > 0x09) temp2 = 0x09;
*(pByte+1) = (cmsUInt8Number)(temp1 | temp2);
*(pByte+2) = (cmsUInt8Number)0;
*(pByte+3) = (cmsUInt8Number)0;
......@@ -1167,33 +1176,7 @@ cmsHPROFILE CMSEXPORT cmsOpenProfileFromMem(const void* MemPtr, cmsUInt32Number
return cmsOpenProfileFromMemTHR(NULL, MemPtr, dwSize);
}
static
cmsBool SanityCheck(_cmsICCPROFILE* profile)
{
cmsIOHANDLER* io;
if (!profile) {
return FALSE;
}
io = profile->IOhandler;
if (!io) {
return FALSE;
}
if (!io->Seek ||
!(io->Seek==NULLSeek || io->Seek==MemorySeek || io->Seek==FileSeek))
{
return FALSE;
}
if (!io->Read ||
!(io->Read==NULLRead || io->Read==MemoryRead || io->Read==FileRead))
{
return FALSE;
}
return TRUE;
}
// Dump tag contents. If the profile is being modified, untouched tags are copied from FileOrig
static
......@@ -1225,7 +1208,7 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig)
// 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 (SanityCheck(FileOrig) && Icc -> TagOffsets[i]) {
if (FileOrig != NULL && Icc -> TagOffsets[i]) {
cmsUInt32Number TagSize = FileOrig -> TagSizes[i];
cmsUInt32Number TagOffset = FileOrig -> TagOffsets[i];
......@@ -1874,7 +1857,7 @@ Error:
// 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
// it as cooked without serializing does result into an error. If that is what 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)
{
......@@ -1898,6 +1881,11 @@ cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, cons
Icc ->TagSizes[i] = Size;
_cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
if (Icc->TagPtrs[i] == NULL) {
Icc->TagNames[i] = 0;
return FALSE;
}
return TRUE;
}
......
......@@ -339,8 +339,8 @@ Error:
cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent)
{
cmsTagTypeSignature OriginalType;
cmsTagSignature tag16 = Device2PCS16[Intent];
cmsTagSignature tagFloat = Device2PCSFloat[Intent];
cmsTagSignature tag16;
cmsTagSignature tagFloat;
cmsContext ContextID = cmsGetProfileContextID(hProfile);
// On named color, take the appropiate tag
......@@ -369,6 +369,9 @@ cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent)
// matter other LUT are present and have precedence. Intent = -1 means just this.
if (Intent != -1) {
tag16 = Device2PCS16[Intent];
tagFloat = Device2PCSFloat[Intent];
if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence
// Floating point LUT are always V4, but the encoding range is no
......@@ -611,13 +614,16 @@ Error:
cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent)
{
cmsTagTypeSignature OriginalType;
cmsTagSignature tag16 = PCS2Device16[Intent];
cmsTagSignature tagFloat = PCS2DeviceFloat[Intent];
cmsContext ContextID = cmsGetProfileContextID(hProfile);
cmsTagSignature tag16;
cmsTagSignature tagFloat;
cmsContext ContextID = cmsGetProfileContextID(hProfile);
if (Intent != -1) {
tag16 = PCS2Device16[Intent];
tagFloat = PCS2DeviceFloat[Intent];
if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence
// Floating point LUT are always V4
......@@ -935,7 +941,7 @@ cmsBool _cmsWriteProfileSequence(cmsHPROFILE hProfile, const cmsSEQ* seq)
{
if (!cmsWriteTag(hProfile, cmsSigProfileSequenceDescTag, seq)) return FALSE;
if (cmsGetProfileVersion(hProfile) >= 4.0) {
if (cmsGetEncodedICCversion(hProfile) >= 0x4000000) {
if (!cmsWriteTag(hProfile, cmsSigProfileSequenceIdTag, seq)) return FALSE;
}
......
......@@ -1154,7 +1154,23 @@ cmsStage* _cmsStageNormalizeToXyzFloat(cmsContext ContextID)
return mpe;
}
// Clips values smaller than zero
static
void Clipper(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe)
{
cmsUInt32Number i;
for (i = 0; i < mpe->InputChannels; i++) {
cmsFloat32Number n = In[i];
Out[i] = n < 0 ? 0 : n;
}
}
cmsStage* _cmsStageClipNegatives(cmsContext ContextID, int nChannels)
{
return _cmsStageAllocPlaceholder(ContextID, cmsSigClipNegativesElemType,
nChannels, nChannels, Clipper, NULL, NULL, NULL);
}
// ********************************************************************************
// Type cmsSigXYZ2LabElemType
......
......@@ -543,8 +543,9 @@ cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUIn
v ->nColors = 0;
v ->ContextID = ContextID;
while (v -> Allocated < n)
GrowNamedColorList(v);
while (v -> Allocated < n){
if (!GrowNamedColorList(v)) return NULL;
}
strncpy(v ->Prefix, Prefix, sizeof(v ->Prefix)-1);
strncpy(v ->Suffix, Suffix, sizeof(v ->Suffix)-1);
......@@ -573,8 +574,9 @@ cmsNAMEDCOLORLIST* CMSEXPORT cmsDupNamedColorList(const cmsNAMEDCOLORLIST* v)
if (NewNC == NULL) return NULL;
// For really large tables we need this
while (NewNC ->Allocated < v ->Allocated)
GrowNamedColorList(NewNC);
while (NewNC ->Allocated < v ->Allocated){
if (!GrowNamedColorList(NewNC)) return NULL;
}
memmove(NewNC ->Prefix, v ->Prefix, sizeof(v ->Prefix));
memmove(NewNC ->Suffix, v ->Suffix, sizeof(v ->Suffix));
......
......@@ -192,6 +192,88 @@ cmsBool _Remove2Op(cmsPipeline* Lut, cmsStageSignature Op1, cmsStageSignature Op
return AnyOpt;
}
static
cmsBool CloseEnoughFloat(cmsFloat64Number a, cmsFloat64Number b)
{
return fabs(b - a) < 0.00001f;
}
static
cmsBool isFloatMatrixIdentity(const cmsMAT3* a)
{
cmsMAT3 Identity;
int i, j;
_cmsMAT3identity(&Identity);
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++)
if (!CloseEnoughFloat(a->v[i].n[j], Identity.v[i].n[j])) return FALSE;
return TRUE;
}
// if two adjacent matrices are found, multiply them.
static
cmsBool _MultiplyMatrix(cmsPipeline* Lut)
{
cmsStage** pt1;
cmsStage** pt2;
cmsStage* chain;
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 == cmsSigMatrixElemType && (*pt2)->Implements == cmsSigMatrixElemType) {
// Get both matrices
_cmsStageMatrixData* m1 = (_cmsStageMatrixData*) cmsStageData(*pt1);
_cmsStageMatrixData* m2 = (_cmsStageMatrixData*) cmsStageData(*pt2);
cmsMAT3 res;
// Input offset and output offset should be zero to use this optimization
if (m1->Offset != NULL || m2 ->Offset != NULL ||
cmsStageInputChannels(*pt1) != 3 || cmsStageOutputChannels(*pt1) != 3 ||
cmsStageInputChannels(*pt2) != 3 || cmsStageOutputChannels(*pt2) != 3)
return FALSE;
// Multiply both matrices to get the result
_cmsMAT3per(&res, (cmsMAT3*)m2->Double, (cmsMAT3*)m1->Double);
// Get the next in chain afer the matrices
chain = (*pt2)->Next;
// Remove both matrices
_RemoveElement(pt2);
_RemoveElement(pt1);
// Now what if the result is a plain identity?
if (!isFloatMatrixIdentity(&res)) {
// We can not get rid of full matrix
cmsStage* Multmat = cmsStageAllocMatrix(Lut->ContextID, 3, 3, (const cmsFloat64Number*) &res, NULL);
// Recover the chain
Multmat->Next = chain;
*pt1 = Multmat;
}
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
......@@ -224,6 +306,9 @@ cmsBool PreOptimize(cmsPipeline* Lut)
// Remove float pcs Lab conversions
Opt |= _Remove2Op(Lut, cmsSigXYZ2FloatPCS, cmsSigFloatPCS2XYZ);
// Simplify matrix.
Opt |= _MultiplyMatrix(Lut);
if (Opt) AnyOpt = TRUE;
} while (Opt);
......@@ -280,12 +365,12 @@ static
void* Prelin16dup(cmsContext ContextID, const void* ptr)
{
Prelin16Data* p16 = (Prelin16Data*) ptr;
Prelin16Data* Duped = _cmsDupMem(ContextID, p16, sizeof(Prelin16Data));
Prelin16Data* Duped = (Prelin16Data*) _cmsDupMem(ContextID, p16, sizeof(Prelin16Data));
if (Duped == NULL) return NULL;
Duped ->EvalCurveOut16 = _cmsDupMem(ContextID, p16 ->EvalCurveOut16, p16 ->nOutputs * sizeof(_cmsInterpFn16));
Duped ->ParamsCurveOut16 = _cmsDupMem(ContextID, p16 ->ParamsCurveOut16, p16 ->nOutputs * sizeof(cmsInterpParams* ));
Duped->EvalCurveOut16 = (_cmsInterpFn16*) _cmsDupMem(ContextID, p16->EvalCurveOut16, p16->nOutputs * sizeof(_cmsInterpFn16));
Duped->ParamsCurveOut16 = (cmsInterpParams**)_cmsDupMem(ContextID, p16->ParamsCurveOut16, p16->nOutputs * sizeof(cmsInterpParams*));
return Duped;
}
......@@ -298,7 +383,7 @@ Prelin16Data* PrelinOpt16alloc(cmsContext ContextID,
int nOutputs, cmsToneCurve** Out )
{
int i;
Prelin16Data* p16 = _cmsMallocZero(ContextID, sizeof(Prelin16Data));
Prelin16Data* p16 = (Prelin16Data*)_cmsMallocZero(ContextID, sizeof(Prelin16Data));
if (p16 == NULL) return NULL;
p16 ->nInputs = nInputs;
......@@ -787,7 +872,7 @@ Prelin8Data* PrelinOpt8alloc(cmsContext ContextID, const cmsInterpParams* p, cms
cmsS15Fixed16Number v1, v2, v3;
Prelin8Data* p8;
p8 = _cmsMallocZero(ContextID, sizeof(Prelin8Data));
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,
......@@ -861,7 +946,7 @@ void PrelinEval8(register const cmsUInt16Number Input[],
Prelin8Data* p8 = (Prelin8Data*) D;
register const cmsInterpParams* p = p8 ->p;
int TotalOut = p -> nOutputs;
const cmsUInt16Number* LutTable = p -> Table;
const cmsUInt16Number* LutTable = (const cmsUInt16Number*) p->Table;
r = Input[0] >> 8;
g = Input[1] >> 8;
......@@ -1180,15 +1265,15 @@ void CurvesFree(cmsContext ContextID, void* ptr)
static
void* CurvesDup(cmsContext ContextID, const void* ptr)
{
Curves16Data* Data = _cmsDupMem(ContextID, ptr, sizeof(Curves16Data));
Curves16Data* Data = (Curves16Data*)_cmsDupMem(ContextID, ptr, sizeof(Curves16Data));
int i;
if (Data == NULL) return NULL;
Data ->Curves = _cmsDupMem(ContextID, Data ->Curves, Data ->nCurves * sizeof(cmsUInt16Number*));
Data->Curves = (cmsUInt16Number**) _cmsDupMem(ContextID, Data->Curves, Data->nCurves * sizeof(cmsUInt16Number*));
for (i=0; i < Data -> nCurves; i++) {
Data ->Curves[i] = _cmsDupMem(ContextID, Data ->Curves[i], Data -> nElements * sizeof(cmsUInt16Number));
Data->Curves[i] = (cmsUInt16Number*) _cmsDupMem(ContextID, Data->Curves[i], Data->nElements * sizeof(cmsUInt16Number));
}
return (void*) Data;
......@@ -1201,18 +1286,18 @@ Curves16Data* CurvesAlloc(cmsContext ContextID, int nCurves, int nElements, cmsT
int i, j;
Curves16Data* c16;
c16 = _cmsMallocZero(ContextID, sizeof(Curves16Data));
c16 = (Curves16Data*)_cmsMallocZero(ContextID, sizeof(Curves16Data));
if (c16 == NULL) return NULL;
c16 ->nCurves = nCurves;
c16 ->nElements = nElements;
c16 ->Curves = _cmsCalloc(ContextID, nCurves, sizeof(cmsUInt16Number*));
c16->Curves = (cmsUInt16Number**) _cmsCalloc(ContextID, nCurves, sizeof(cmsUInt16Number*));
if (c16 ->Curves == NULL) return NULL;
for (i=0; i < nCurves; i++) {
c16->Curves[i] = _cmsCalloc(ContextID, nElements, sizeof(cmsUInt16Number));
c16->Curves[i] = (cmsUInt16Number*) _cmsCalloc(ContextID, nElements, sizeof(cmsUInt16Number));
if (c16->Curves[i] == NULL) {
......@@ -1560,49 +1645,83 @@ cmsBool SetMatShaper(cmsPipeline* Dest, cmsToneCurve* Curve1[3], cmsMAT3* Mat, c
}
// 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;
cmsStage* Curve1, *Curve2;
cmsStage* Matrix1, *Matrix2;
cmsMAT3 res;
cmsBool IdentityMat;
cmsPipeline* Dest, *Src;
cmsFloat64Number* Offset;
// Only works on RGB to RGB
if (T_CHANNELS(*InputFormat) != 3 || T_CHANNELS(*OutputFormat) != 3) return FALSE;
// 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;
// Only works on 8 bit input
if (!_cmsFormatterIs8bit(*InputFormat)) return FALSE;
// Seems suitable, proceed
Src = *Lut;
// 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;
// Check for:
//
// shaper-matrix-matrix-shaper
// shaper-matrix-shaper
//
// Both of those constructs are possible (first because abs. colorimetric).
// additionally, In the first case, the input matrix offset should be zero.
// Get both matrices
Data1 = (_cmsStageMatrixData*) cmsStageData(Matrix1);
Data2 = (_cmsStageMatrixData*) cmsStageData(Matrix2);
IdentityMat = FALSE;
if (cmsPipelineCheckAndRetreiveStages(Src, 4,
cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType,
&Curve1, &Matrix1, &Matrix2, &Curve2)) {
// Input offset should be zero
if (Data1 ->Offset != NULL) return FALSE;
// Get both matrices
_cmsStageMatrixData* Data1 = (_cmsStageMatrixData*)cmsStageData(Matrix1);
_cmsStageMatrixData* Data2 = (_cmsStageMatrixData*)cmsStageData(Matrix2);
// Multiply both matrices to get the result
_cmsMAT3per(&res, (cmsMAT3*) Data2 ->Double, (cmsMAT3*) Data1 ->Double);
// Input offset should be zero
if (Data1->Offset != NULL) return FALSE;
// Now the result is in res + Data2 -> Offset. Maybe is a plain identity?
IdentityMat = FALSE;
if (_cmsMAT3isIdentity(&res) && Data2 ->Offset == NULL) {
// Multiply both matrices to get the result
_cmsMAT3per(&res, (cmsMAT3*)Data2->Double, (cmsMAT3*)Data1->Double);
// We can get rid of full matrix
IdentityMat = TRUE;
}
// Only 2nd matrix has offset, or it is zero
Offset = Data2->Offset;
// Now the result is in res + Data2 -> Offset. Maybe is a plain identity?
if (_cmsMAT3isIdentity(&res) && Offset == NULL) {
// We can get rid of full matrix
IdentityMat = TRUE;
}
}
else {
if (cmsPipelineCheckAndRetreiveStages(Src, 3,
cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType,
&Curve1, &Matrix1, &Curve2)) {
_cmsStageMatrixData* Data = (_cmsStageMatrixData*)cmsStageData(Matrix1);
// Copy the matrix to our result
memcpy(&res, Data->Double, sizeof(res));
// Preserve the Odffset (may be NULL as a zero offset)
Offset = Data->Offset;
if (_cmsMAT3isIdentity(&res) && Offset == NULL) {
// We can get rid of full matrix
IdentityMat = TRUE;
}
}
else
return FALSE; // Not optimizeable this time
}
// Allocate an empty LUT
Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels);
......@@ -1612,9 +1731,12 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
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 (!IdentityMat) {
if (!cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageAllocMatrix(Dest->ContextID, 3, 3, (const cmsFloat64Number*)&res, Offset)))
goto Error;
}
if (!cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageDup(Curve2)))
goto Error;
......@@ -1632,7 +1754,7 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
*dwFlags |= cmsFLAGS_NOCACHE;
// Setup the optimizarion routines
SetMatShaper(Dest, mpeC1 ->TheCurves, &res, (cmsVEC3*) Data2 ->Offset, mpeC2->TheCurves, OutputFormat);
SetMatShaper(Dest, mpeC1 ->TheCurves, &res, (cmsVEC3*) Offset, mpeC2->TheCurves, OutputFormat);
}
cmsPipelineFree(Src);
......
......@@ -2438,9 +2438,6 @@ cmsUInt8Number* PackDoubleFrom16(register _cmsTRANSFORM* info,
((cmsFloat64Number*) output)[i + start] = v;
}
if (!ExtraFirst) {
output += Extra * sizeof(cmsFloat64Number);
}
if (Extra == 0 && SwapFirst) {
......@@ -2451,7 +2448,7 @@ cmsUInt8Number* PackDoubleFrom16(register _cmsTRANSFORM* info,
if (T_PLANAR(info -> OutputFormat))
return output + sizeof(cmsFloat64Number);
else
return output + nChan * sizeof(cmsFloat64Number);
return output + (nChan + Extra) * sizeof(cmsFloat64Number);
}
......@@ -2462,50 +2459,47 @@ cmsUInt8Number* PackFloatFrom16(register _cmsTRANSFORM* info,
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;
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;
if (ExtraFirst)
start = Extra;
for (i=0; i < nChan; i++) {
for (i = 0; i < nChan; i++) {
int index = DoSwap ? (nChan - i - 1) : i;
int index = DoSwap ? (nChan - i - 1) : i;
v = (cmsFloat64Number) wOut[index] / maximum;
v = (cmsFloat64Number)wOut[index] / maximum;
if (Reverse)
v = maximum - v;
if (Reverse)
v = maximum - v;
if (Planar)
((cmsFloat32Number*) output)[(i + start ) * Stride]= (cmsFloat32Number) v;
else
((cmsFloat32Number*) output)[i + start] = (cmsFloat32Number) 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) {
if (Extra == 0 && SwapFirst) {
memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat32Number));
*swap1 = (cmsFloat32Number) v;
}
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);
if (T_PLANAR(info->OutputFormat))
return output + sizeof(cmsFloat32Number);
else
return output + (nChan + Extra) * sizeof(cmsFloat32Number);
}
......@@ -2518,50 +2512,47 @@ cmsUInt8Number* PackFloatsFromFloat(_cmsTRANSFORM* info,
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;
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;
if (ExtraFirst)
start = Extra;
for (i=0; i < nChan; i++) {
for (i = 0; i < nChan; i++) {
int index = DoSwap ? (nChan - i - 1) : i;
int index = DoSwap ? (nChan - i - 1) : i;
v = wOut[index] * maximum;
v = wOut[index] * maximum;
if (Reverse)
v = maximum - v;
if (Reverse)
v = maximum - v;
if (Planar)
((cmsFloat32Number*) output)[(i + start)* Stride]= (cmsFloat32Number) v;
else
((cmsFloat32Number*) output)[i + start] = (cmsFloat32Number) 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) {
if (Extra == 0 && SwapFirst) {
memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat32Number));
*swap1 = (cmsFloat32Number) v;
}
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);
if (T_PLANAR(info->OutputFormat))
return output + sizeof(cmsFloat32Number);
else
return output + (nChan + Extra) * sizeof(cmsFloat32Number);
}
static
......@@ -2570,51 +2561,47 @@ cmsUInt8Number* PackDoublesFromFloat(_cmsTRANSFORM* info,
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;
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;
for (i=0; i < nChan; i++) {
if (ExtraFirst)
start = Extra;
int index = DoSwap ? (nChan - i - 1) : i;
for (i = 0; i < nChan; i++) {
v = wOut[index] * maximum;
int index = DoSwap ? (nChan - i - 1) : i;
if (Reverse)
v = maximum - v;
v = wOut[index] * maximum;
if (Planar)
((cmsFloat64Number*) output)[(i + start) * Stride] = v;
else
((cmsFloat64Number*) output)[i + start] = v;
}
if (Reverse)
v = maximum - v;
if (!ExtraFirst) {
output += Extra * sizeof(cmsFloat64Number);
}
if (Planar)
((cmsFloat64Number*)output)[(i + start) * Stride] = v;
else
((cmsFloat64Number*)output)[i + start] = v;
}
if (Extra == 0 && SwapFirst) {
if (Extra == 0 && SwapFirst) {
memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat64Number));
*swap1 = v;
}
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);
if (T_PLANAR(info->OutputFormat))
return output + sizeof(cmsFloat64Number);
else
return output + (nChan + Extra) * sizeof(cmsFloat64Number);
}
......@@ -2850,50 +2837,47 @@ cmsUInt8Number* PackHalfFrom16(register _cmsTRANSFORM* info,
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;
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;
if (ExtraFirst)
start = Extra;
for (i=0; i < nChan; i++) {
for (i = 0; i < nChan; i++) {
int index = DoSwap ? (nChan - i - 1) : i;
int index = DoSwap ? (nChan - i - 1) : i;
v = (cmsFloat32Number) wOut[index] / maximum;
v = (cmsFloat32Number)wOut[index] / maximum;
if (Reverse)
v = maximum - v;
if (Reverse)
v = maximum - v;
if (Planar)
((cmsUInt16Number*) output)[(i + start ) * Stride]= _cmsFloat2Half(v);
else
((cmsUInt16Number*) output)[i + start] = _cmsFloat2Half(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) {
if (Extra == 0 && SwapFirst) {
memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsUInt16Number));
*swap1 = _cmsFloat2Half(v);
}
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);
if (T_PLANAR(info->OutputFormat))
return output + sizeof(cmsUInt16Number);
else
return output + (nChan + Extra) * sizeof(cmsUInt16Number);
}
......@@ -2904,50 +2888,47 @@ cmsUInt8Number* PackHalfFromFloat(_cmsTRANSFORM* info,
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;
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;
if (ExtraFirst)
start = Extra;
for (i=0; i < nChan; i++) {
for (i = 0; i < nChan; i++) {
int index = DoSwap ? (nChan - i - 1) : i;
int index = DoSwap ? (nChan - i - 1) : i;
v = wOut[index] * maximum;
v = wOut[index] * maximum;
if (Reverse)
v = maximum - v;
if (Reverse)
v = maximum - v;
if (Planar)
((cmsUInt16Number*) output)[(i + start)* Stride]= _cmsFloat2Half( v );
else
((cmsUInt16Number*) output)[i + start] = _cmsFloat2Half( 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) {
if (Extra == 0 && SwapFirst) {
memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsUInt16Number));
*swap1 = (cmsUInt16Number) _cmsFloat2Half( v );
}
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);
if (T_PLANAR(info->OutputFormat))
return output + sizeof(cmsUInt16Number);
else
return output + (nChan + Extra)* sizeof(cmsUInt16Number);
}
#endif
......
......@@ -135,6 +135,15 @@ void CMSEXPORT cmsxyY2XYZ(cmsCIEXYZ* Dest, const cmsCIExyY* Source)
Dest -> Z = ((1 - Source -> x - Source -> y) / Source -> y) * Source -> Y;
}
/*
The break point (24/116)^3 = (6/29)^3 is a very small amount of tristimulus
primary (0.008856). Generally, this only happens for
nearly ideal blacks and for some orange / amber colors in transmission mode.
For example, the Z value of the orange turn indicator lamp lens on an
automobile will often be below this value. But the Z does not
contribute to the perceived color directly.
*/
static
cmsFloat64Number f(cmsFloat64Number t)
{
......
......@@ -712,15 +712,21 @@ struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID)
// Internal: get the memory area associanted with each context client
// Returns the block assigned to the specific zone.
// Returns the block assigned to the specific zone. Never return NULL.
void* _cmsContextGetClientChunk(cmsContext ContextID, _cmsMemoryClient mc)
{
struct _cmsContext_struct* ctx;
void *ptr;
if (mc < 0 || mc >= MemoryClientMax) {
cmsSignalError(ContextID, cmsERROR_RANGE, "Bad context client");
return NULL;
if ((int) mc < 0 || mc >= MemoryClientMax) {
cmsSignalError(ContextID, cmsERROR_INTERNAL, "Bad context client -- possible corruption");
// This is catastrophic. Should never reach here
_cmsAssert(0);
// Reverts to global context
return globalContext.chunks[UserPtr];
}
ctx = _cmsGetContext(ContextID);
......@@ -909,7 +915,7 @@ cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData)
}
/*
static
struct _cmsContext_struct* FindPrev(struct _cmsContext_struct* id)
{
......@@ -926,6 +932,7 @@ struct _cmsContext_struct* FindPrev(struct _cmsContext_struct* id)
return NULL; // List is empty or only one element!
}
*/
// Frees any resources associated with the given context,
// and destroys the context placeholder.
......@@ -961,8 +968,8 @@ void CMSEXPORT cmsDeleteContext(cmsContext ContextID)
// Search for previous
for (prev = _cmsContextPoolHead;
prev != NULL;
prev = prev ->Next)
prev != NULL;
prev = prev ->Next)
{
if (prev -> Next == ctx) {
prev -> Next = ctx ->Next;
......
......@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2010 Marti Maria Saguer
// 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"),
......@@ -369,28 +369,7 @@ cmsFloat64Number RootOfLeastSquaresFitQuadraticCurve(int n, cmsFloat64Number x[]
}
/*
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.
......@@ -515,7 +494,6 @@ cmsBool CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROF
// Test for mid range straight (only on relative colorimetric)
NearlyStraightMidrange = TRUE;
MinL = outRamp[0]; MaxL = outRamp[255];
if (Intent == INTENT_RELATIVE_COLORIMETRIC) {
......@@ -531,7 +509,6 @@ cmsBool CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROF
// DestinationBlackPoint shall be the same as initialLab.
// Otherwise, the DestinationBlackPoint shall be determined
// using curve fitting.
if (NearlyStraightMidrange) {
cmsLab2XYZ(NULL, BlackPoint, &InitialLab);
......@@ -543,14 +520,12 @@ cmsBool CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROF
// 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;
......
......@@ -1718,10 +1718,7 @@ cmsBool Write8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsUInt32Number
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;
val = (cmsUInt8Number) FROM_16_TO_8(Tables->TheCurves[i]->Table16[j]);
if (!_cmsWriteUInt8Number(io, val)) return FALSE;
}
......
......@@ -671,7 +671,7 @@ cmsToneCurve* Build_sRGBGamma(cmsContext ContextID)
// Create the ICC virtual profile for sRGB space
cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID)
{
cmsCIExyY D65;
cmsCIExyY D65 = { 0.3127, 0.3290, 1.0 };
cmsCIExyYTRIPLE Rec709Primaries = {
{0.6400, 0.3300, 1.0},
{0.3000, 0.6000, 1.0},
......@@ -680,7 +680,7 @@ cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID)
cmsToneCurve* Gamma22[3];
cmsHPROFILE hsRGB;
cmsWhitePointFromTemp(&D65, 6504);
// cmsWhitePointFromTemp(&D65, 6504);
Gamma22[0] = Gamma22[1] = Gamma22[2] = Build_sRGBGamma(ContextID);
if (Gamma22[0] == NULL) return NULL;
......@@ -708,6 +708,7 @@ typedef struct {
cmsFloat64Number Contrast;
cmsFloat64Number Hue;
cmsFloat64Number Saturation;
cmsBool lAdjustWP;
cmsCIEXYZ WPsrc, WPdest;
} BCHSWADJUSTS, *LPBCHSWADJUSTS;
......@@ -737,9 +738,10 @@ int bchswSampler(register const cmsUInt16Number In[], register cmsUInt16Number O
cmsLCh2Lab(&LabOut, &LChOut);
// Move white point in Lab
cmsLab2XYZ(&bchsw ->WPsrc, &XYZ, &LabOut);
cmsXYZ2Lab(&bchsw ->WPdest, &LabOut, &XYZ);
if (bchsw->lAdjustWP) {
cmsLab2XYZ(&bchsw->WPsrc, &XYZ, &LabOut);
cmsXYZ2Lab(&bchsw->WPdest, &LabOut, &XYZ);
}
// Back to encoded
......@@ -773,18 +775,23 @@ cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID,
bchsw.Contrast = Contrast;
bchsw.Hue = Hue;
bchsw.Saturation = Saturation;
if (TempSrc == TempDest) {
cmsWhitePointFromTemp(&WhitePnt, TempSrc );
cmsxyY2XYZ(&bchsw.WPsrc, &WhitePnt);
bchsw.lAdjustWP = FALSE;
}
else {
bchsw.lAdjustWP = TRUE;
cmsWhitePointFromTemp(&WhitePnt, TempSrc);
cmsxyY2XYZ(&bchsw.WPsrc, &WhitePnt);
cmsWhitePointFromTemp(&WhitePnt, TempDest);
cmsxyY2XYZ(&bchsw.WPdest, &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);
......@@ -1017,12 +1024,14 @@ typedef struct {
} cmsAllowedLUT;
#define cmsSig0 ((cmsTagSignature) 0)
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 }},
{ FALSE, cmsSig0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } },
{ FALSE, cmsSig0, cmsSigLut16Type, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } },
{ FALSE, cmsSig0, cmsSigLut16Type, 2, { cmsSigCurveSetElemType, cmsSigCLutElemType } },
{ TRUE, cmsSig0, 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 }},
......
......@@ -621,46 +621,48 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
_cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID, TransformPlugin);
_cmsTransformCollection* Plugin;
// Allocate needed memory
_cmsTRANSFORM* p = (_cmsTRANSFORM*) _cmsMallocZero(ContextID, sizeof(_cmsTRANSFORM));
if (!p) 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);
// Allocate needed memory
_cmsTRANSFORM* p = (_cmsTRANSFORM*)_cmsMallocZero(ContextID, sizeof(_cmsTRANSFORM));
if (!p) return NULL;
// Store the proposed pipeline
p->Lut = lut;
// Let's see if any plug-in want to do the transform by itself
if (p->Lut != NULL) {
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
_cmsOptimizePipeline(ContextID, &p->Lut, Intent, InputFormat, OutputFormat, dwFlags);
}
// Check whatever this is a true floating point transform
if (_cmsFormatterIsFloat(*InputFormat) && _cmsFormatterIsFloat(*OutputFormat)) {
......
......@@ -52,7 +52,7 @@
//
//---------------------------------------------------------------------------------
//
// Version 2.6
// Version 2.7
//
#ifndef _lcms2_H
......@@ -104,7 +104,7 @@ extern "C" {
#endif
// Version/release
#define LCMS_VERSION 2060
#define LCMS_VERSION 2070
// I will give the chance of redefining basic types for compilers that are not fully C99 compliant
#ifndef CMS_BASIC_TYPES_ALREADY_DEFINED
......@@ -213,27 +213,19 @@ typedef int cmsBool;
# define CMS_USE_BIG_ENDIAN 1
#endif
# ifdef TARGET_CPU_PPC
# if TARGET_CPU_PPC
# define CMS_USE_BIG_ENDIAN 1
# endif
# endif
#if defined(__powerpc__) || defined(__ppc__) || defined(TARGET_CPU_PPC)
# if __powerpc__ || __ppc__ || TARGET_CPU_PPC
# define CMS_USE_BIG_ENDIAN 1
# if defined (__GNUC__) && defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN)
# if __BYTE_ORDER == __LITTLE_ENDIAN
// // Don't use big endian for PowerPC little endian mode
# if defined (__GNUC__) && defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__)
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
// Don't use big endian for PowerPC little endian mode
# undef CMS_USE_BIG_ENDIAN
# endif
# endif
# endif
#endif
// WORDS_BIGENDIAN takes precedence
#if defined(_HOST_BIG_ENDIAN) || defined(__BIG_ENDIAN__) || defined(WORDS_BIGENDIAN)
# define CMS_USE_BIG_ENDIAN 1
#endif
#ifdef macintosh
# ifdef __BIG_ENDIAN__
# define CMS_USE_BIG_ENDIAN 1
......@@ -243,6 +235,12 @@ typedef int cmsBool;
# endif
#endif
// WORDS_BIGENDIAN takes precedence
#if defined(_HOST_BIG_ENDIAN) || defined(__BIG_ENDIAN__) || defined(WORDS_BIGENDIAN)
# define CMS_USE_BIG_ENDIAN 1
#endif
// Calling convention -- this is hardly platform and compiler dependent
#ifdef CMS_IS_WINDOWS_
# if defined(CMS_DLL) || defined(CMS_DLL_BUILD)
......@@ -553,7 +551,8 @@ typedef enum {
cmsSigLab2FloatPCS = 0x64326C20, // 'd2l '
cmsSigFloatPCS2Lab = 0x6C326420, // 'l2d '
cmsSigXYZ2FloatPCS = 0x64327820, // 'd2x '
cmsSigFloatPCS2XYZ = 0x78326420 // 'x2d '
cmsSigFloatPCS2XYZ = 0x78326420, // 'x2d '
cmsSigClipNegativesElemType = 0x636c7020 // 'clp '
} cmsStageSignature;
......@@ -1031,6 +1030,10 @@ typedef struct {
} cmsICCViewingConditions;
// Get LittleCMS version (for shared objects) -----------------------------------------------------------------------------
CMSAPI int CMSEXPORT cmsGetEncodedCMMversion(void);
// Support of non-standard functions --------------------------------------------------------------------------------------
CMSAPI int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2);
......@@ -1509,7 +1512,7 @@ CMSAPI int CMSEXPORT _cmsLCMScolorSpace(cmsColorSpaceSignat
CMSAPI cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace);
// Build a suitable formatter for the colorspace of this profile
// Build a suitable formatter for the colorspace of this profile. nBytes=1 means 8 bits, nBytes=2 means 16 bits.
CMSAPI cmsUInt32Number CMSEXPORT cmsFormatterForColorspaceOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat);
CMSAPI cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat);
......@@ -1538,6 +1541,7 @@ CMSAPI cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID
CMSAPI cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromStream(cmsContext ContextID, FILE* Stream);
CMSAPI cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromMem(cmsContext ContextID, void *Buffer, cmsUInt32Number size, const char* AccessMode);
CMSAPI cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromNULL(cmsContext ContextID);
CMSAPI cmsIOHANDLER* CMSEXPORT cmsGetProfileIOhandler(cmsHPROFILE hProfile);
CMSAPI cmsBool CMSEXPORT cmsCloseIOhandler(cmsIOHANDLER* io);
// MD5 message digest --------------------------------------------------------------------------------------------------
......@@ -1672,6 +1676,10 @@ CMSAPI cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID
#define cmsFLAGS_CLUT_POST_LINEARIZATION 0x0001 // create postlinearization tables if possible
#define cmsFLAGS_CLUT_PRE_LINEARIZATION 0x0010 // create prelinearization tables if possible
// Specific to unbounded mode
#define cmsFLAGS_NONEGATIVES 0x8000 // Prevent negative numbers in floating point transforms
// Fine-tune control over number of gridpoints
#define cmsFLAGS_GRIDPOINTS(n) (((n) & 0xFF) << 16)
......
......@@ -223,11 +223,17 @@ cmsINLINE cmsUInt16Number _cmsQuickSaturateWord(cmsFloat64Number d)
// 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:
// to zero for their defaults. This yields to an initialization macro:
typedef CRITICAL_SECTION _cmsMutex;
#define CMS_MUTEX_INITIALIZER {(void*) -1,-1,0,0,0,0}
#define CMS_MUTEX_INITIALIZER {(PRTL_CRITICAL_SECTION_DEBUG) -1,-1,0,0,0,0}
#ifdef _MSC_VER
# if (_MSC_VER >= 1800)
# pragma warning(disable : 26135)
# endif
#endif
cmsINLINE int _cmsLockPrimitive(_cmsMutex *m)
{
......@@ -313,38 +319,38 @@ typedef int _cmsMutex;
cmsINLINE int _cmsLockPrimitive(_cmsMutex *m)
{
return 0;
cmsUNUSED_PARAMETER(m);
return 0;
}
cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m)
{
return 0;
cmsUNUSED_PARAMETER(m);
return 0;
}
cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m)
{
return 0;
cmsUNUSED_PARAMETER(m);
return 0;
}
cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m)
{
return 0;
cmsUNUSED_PARAMETER(m);
return 0;
}
cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m)
{
return 0;
cmsUNUSED_PARAMETER(m);
return 0;
}
cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m)
{
return 0;
cmsUNUSED_PARAMETER(m);
return 0;
}
#endif
......@@ -852,6 +858,8 @@ cmsStage* _cmsStageNormalizeFromLabFloat(cmsContext ContextID);
cmsStage* _cmsStageNormalizeFromXyzFloat(cmsContext ContextID);
cmsStage* _cmsStageNormalizeToLabFloat(cmsContext ContextID);
cmsStage* _cmsStageNormalizeToXyzFloat(cmsContext ContextID);
cmsStage* _cmsStageClipNegatives(cmsContext ContextID, int nChannels);
// For curve set only
cmsToneCurve** _cmsStageGetPtrToCurveSet(const cmsStage* mpe);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册