0,0 → 1,439 |
// |
// Little cms - profiler construction set |
// Copyright (C) 1998-2001 Marti Maria |
// |
// THIS SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, |
// EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY |
// WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. |
// |
// IN NO EVENT SHALL MARTI MARIA BE LIABLE FOR ANY SPECIAL, INCIDENTAL, |
// INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, |
// OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
// WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF |
// LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE |
// OF THIS SOFTWARE. |
// |
// |
// This library is free software; you can redistribute it and/or |
// modify it under the terms of the GNU Lesser General Public |
// License as published by the Free Software Foundation; either |
// version 2 of the License, or (at your option) any later version. |
// |
// This library 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 |
// Lesser General Public License for more details. |
// |
// You should have received a copy of the GNU Lesser General Public |
// License along with this library; if not, write to the Free Software |
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
#include "lcmsprf.h" |
|
|
double cdecl _cmsxSaturate65535To255(double d); |
double cdecl _cmsxSaturate255To65535(double d); |
|
|
void cdecl _cmsxClampXYZ100(LPcmsCIEXYZ xyz); |
|
|
BOOL cdecl cmsxEmbedCharTarget(LPPROFILERCOMMONDATA hdr); |
BOOL cdecl cmsxEmbedMatrixShaper(LPPROFILERCOMMONDATA hdr); |
BOOL cdecl cmsxEmbedTextualInfo(LPPROFILERCOMMONDATA hdr); |
|
// ----------------------------------------------------------------- Implementation |
|
|
// Convert from 0.0..65535.0 to 0.0..255.0 |
|
double _cmsxSaturate65535To255(double d) |
{ |
double v; |
|
v = d / 257.0; |
|
if (v < 0) return 0; |
if (v > 255.0) return 255.0; |
|
return v; |
} |
|
|
double _cmsxSaturate255To65535(double d) |
{ |
double v; |
|
v = d * 257.0; |
|
if (v < 0) return 0; |
if (v > 65535.0) return 65535.0; |
|
return v; |
} |
|
|
|
// Cut off absurd values |
|
void _cmsxClampXYZ100(LPcmsCIEXYZ xyz) |
{ |
|
if (xyz->X > 199.996) |
xyz->X = 199.996; |
|
if (xyz->Y > 199.996) |
xyz->Y = 199.996; |
|
if (xyz->Z > 199.996) |
xyz->Z = 199.996; |
|
if (xyz->Y < 0) |
xyz->Y = 0; |
|
if (xyz->X < 0) |
xyz->X = 0; |
|
if (xyz->Z < 0) |
xyz->Z = 0; |
|
} |
|
static |
int xfilelength(int fd) |
{ |
#ifdef _MSC_VER |
return _filelength(fd); |
#else |
struct stat sb; |
if (fstat(fd, &sb) < 0) |
return(-1); |
return(sb.st_size); |
#endif |
|
|
} |
|
|
BOOL cmsxEmbedCharTarget(LPPROFILERCOMMONDATA hdr) |
{ |
LCMSHANDLE it8 = cmsxIT8Alloc(); |
LPBYTE mem; |
size_t size, readed; |
FILE* f; |
BOOL lFreeOnExit = FALSE; |
|
|
if (!hdr->m.Patches) { |
|
if (!hdr ->ReferenceSheet[0] && !hdr->MeasurementSheet[0]) return FALSE; |
|
if (cmsxPCollBuildMeasurement(&hdr ->m, |
hdr->ReferenceSheet, |
hdr->MeasurementSheet, |
PATCH_HAS_RGB|PATCH_HAS_XYZ) == FALSE) return FALSE; |
lFreeOnExit = TRUE; |
|
} |
|
cmsxIT8SetSheetType(it8,"LCMSEMBED"); |
cmsxIT8SetProperty(it8, "ORIGINATOR", (const char *) "Little cms"); |
cmsxIT8SetProperty(it8, "DESCRIPTOR", (const char *) hdr -> Description); |
cmsxIT8SetProperty(it8, "MANUFACTURER", (const char *) hdr ->Manufacturer); |
|
cmsxPCollSaveToSheet(&hdr->m, it8); |
cmsxIT8SaveToFile(it8, "TMP00.IT8"); |
cmsxIT8Free(it8); |
|
f = fopen("TMP00.IT8", "rb"); |
size = xfilelength(fileno(f)); |
mem = (char*) malloc(size + 1); |
readed = fread(mem, 1, size, f); |
fclose(f); |
|
mem[readed] = 0; |
unlink("TMP00.IT8"); |
|
cmsAddTag(hdr->hProfile, icSigCharTargetTag, mem); |
free(mem); |
|
if (lFreeOnExit) { |
|
cmsxPCollFreeMeasurements(&hdr->m); |
} |
|
return TRUE; |
} |
|
|
static |
BOOL ComputeColorantMatrix(LPcmsCIEXYZTRIPLE Colorants, |
LPcmsCIExyY WhitePoint, |
LPcmsCIExyYTRIPLE Primaries) |
{ |
MAT3 MColorants; |
|
if (!cmsBuildRGB2XYZtransferMatrix(&MColorants, WhitePoint, Primaries)) |
{ |
return FALSE; |
} |
|
|
cmsAdaptMatrixToD50(&MColorants, WhitePoint); |
|
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]; |
|
return TRUE; |
|
} |
|
|
BOOL cmsxEmbedMatrixShaper(LPPROFILERCOMMONDATA hdr) |
{ |
cmsCIEXYZTRIPLE Colorant; |
cmsCIExyY MediaWhite; |
|
cmsXYZ2xyY(&MediaWhite, &hdr ->WhitePoint); |
|
if (ComputeColorantMatrix(&Colorant, &MediaWhite, &hdr ->Primaries)) { |
|
cmsAddTag(hdr ->hProfile, icSigRedColorantTag, &Colorant.Red); |
cmsAddTag(hdr ->hProfile, icSigGreenColorantTag, &Colorant.Green); |
cmsAddTag(hdr ->hProfile, icSigBlueColorantTag, &Colorant.Blue); |
} |
|
cmsAddTag(hdr ->hProfile, icSigRedTRCTag, hdr ->Gamma[0]); |
cmsAddTag(hdr ->hProfile, icSigGreenTRCTag, hdr ->Gamma[1]); |
cmsAddTag(hdr ->hProfile, icSigBlueTRCTag, hdr ->Gamma[2]); |
|
return TRUE; |
} |
|
|
BOOL cmsxEmbedTextualInfo(LPPROFILERCOMMONDATA hdr) |
{ |
if (*hdr ->Description) |
cmsAddTag(hdr ->hProfile, icSigProfileDescriptionTag, hdr ->Description); |
|
if (*hdr ->Copyright) |
cmsAddTag(hdr ->hProfile, icSigCopyrightTag, hdr ->Copyright); |
|
if (*hdr ->Manufacturer) |
cmsAddTag(hdr ->hProfile, icSigDeviceMfgDescTag, hdr ->Manufacturer); |
|
if (*hdr ->Model) |
cmsAddTag(hdr ->hProfile, icSigDeviceModelDescTag, hdr ->Model); |
|
return TRUE; |
} |
|
|
|
void cmsxChromaticAdaptationAndNormalization(LPPROFILERCOMMONDATA hdr, LPcmsCIEXYZ xyz, BOOL lReverse) |
{ |
|
if (hdr->lUseCIECAM97s) { |
|
cmsJCh JCh; |
|
// Let's CIECAM97s to do the adaptation to D50 |
|
xyz->X *= 100.; |
xyz->Y *= 100.; |
xyz->Z *= 100.; |
|
_cmsxClampXYZ100(xyz); |
|
if (lReverse) { |
cmsCIECAM97sForward(hdr->hPCS, xyz, &JCh); |
cmsCIECAM97sReverse(hdr->hDevice, &JCh, xyz); |
} |
else { |
|
cmsCIECAM97sForward(hdr->hDevice, xyz, &JCh); |
cmsCIECAM97sReverse(hdr->hPCS, &JCh, xyz); |
} |
|
_cmsxClampXYZ100(xyz); |
|
xyz -> X /= 100.; |
xyz -> Y /= 100.; |
xyz -> Z /= 100.; |
|
} |
else { |
|
// Else, use Bradford |
|
if (lReverse) { |
cmsAdaptToIlluminant(xyz, cmsD50_XYZ(), &hdr->WhitePoint, xyz); |
} |
else { |
cmsAdaptToIlluminant(xyz, &hdr->WhitePoint, cmsD50_XYZ(), xyz); |
} |
|
} |
|
} |
|
|
void cmsxInitPCSViewingConditions(LPPROFILERCOMMONDATA hdr) |
{ |
|
hdr->PCS.whitePoint.X = cmsD50_XYZ()->X * 100.; |
hdr->PCS.whitePoint.Y = cmsD50_XYZ()->Y * 100.; |
hdr->PCS.whitePoint.Z = cmsD50_XYZ()->Z * 100.; |
|
|
hdr->PCS.Yb = 20; // 20% of surround |
hdr->PCS.La = 20; // Adapting field luminance |
hdr->PCS.surround = AVG_SURROUND; |
hdr->PCS.D_value = 1.0; // Complete adaptation |
|
} |
|
|
// Build gamut hull by geometric means |
void cmsxComputeGamutHull(LPPROFILERCOMMONDATA hdr) |
{ |
int i; |
int x0, y0, z0; |
int Inside, Outside, Boundaries; |
char code; |
|
|
hdr -> hRGBHull = cmsxHullInit(); |
|
// For all valid patches, mark RGB knots as 0 |
for (i=0; i < hdr ->m.nPatches; i++) { |
|
if (hdr ->m.Allowed[i]) { |
|
LPPATCH p = hdr ->m.Patches + i; |
|
|
x0 = (int) floor(p->Colorant.RGB[0] + .5); |
y0 = (int) floor(p->Colorant.RGB[1] + .5); |
z0 = (int) floor(p->Colorant.RGB[2] + .5); |
|
cmsxHullAddPoint(hdr->hRGBHull, x0, y0, z0); |
} |
} |
|
cmsxHullComputeHull(hdr ->hRGBHull); |
|
// #ifdef DEBUG |
cmsxHullDumpVRML(hdr -> hRGBHull, "rgbhull.wrl"); |
// #endif |
|
|
|
// A check |
|
Inside = Outside = Boundaries = 0; |
// For all valid patches, mark RGB knots as 0 |
for (i=0; i < hdr ->m.nPatches; i++) { |
|
if (hdr ->m.Allowed[i]) { |
|
LPPATCH p = hdr ->m.Patches + i; |
|
x0 = (int) floor(p->Colorant.RGB[0] + .5); |
y0 = (int) floor(p->Colorant.RGB[1] + .5); |
z0 = (int) floor(p->Colorant.RGB[2] + .5); |
|
code = cmsxHullCheckpoint(hdr -> hRGBHull, x0, y0, z0); |
|
switch (code) { |
|
case 'i': Inside++; break; |
case 'o': Outside++; break; |
default: Boundaries++; |
} |
|
} |
} |
|
if (hdr ->printf) |
hdr ->printf("Gamut hull: %d inside, %d outside, %d on boundaries", Inside, Outside, Boundaries); |
|
} |
|
BOOL cmsxChoosePCS(LPPROFILERCOMMONDATA hdr) |
{ |
|
double gamma_r, gamma_g, gamma_b; |
cmsCIExyY SourceWhite; |
|
// At first, compute aproximation on matrix-shaper |
if (!cmsxComputeMatrixShaper(hdr ->ReferenceSheet, |
hdr ->MeasurementSheet, |
hdr -> Medium, |
hdr ->Gamma, |
&hdr ->WhitePoint, |
&hdr ->BlackPoint, |
&hdr ->Primaries)) return FALSE; |
|
|
|
cmsXYZ2xyY(&SourceWhite, &hdr ->WhitePoint); |
|
gamma_r = cmsEstimateGamma(hdr ->Gamma[0]); |
gamma_g = cmsEstimateGamma(hdr ->Gamma[1]); |
gamma_b = cmsEstimateGamma(hdr ->Gamma[2]); |
|
|
|
if (gamma_r > 1.8 || gamma_g > 1.8 || gamma_b > 1.8 || |
gamma_r == -1 || gamma_g == -1 || gamma_b == -1) { |
|
hdr ->PCSType = PT_Lab; |
|
if (hdr ->printf) |
hdr ->printf("I have choosen Lab as PCS"); |
|
} |
else { |
|
hdr ->PCSType = PT_XYZ; |
|
if (hdr ->printf) |
hdr ->printf("I have choosen XYZ as PCS"); |
} |
|
|
|
if (hdr ->printf) { |
|
char Buffer[256] = "Infered "; |
|
_cmsIdentifyWhitePoint(Buffer, &hdr ->WhitePoint); |
hdr ->printf("%s", Buffer); |
hdr ->printf("Primaries (x-y): [Red: %2.2f, %2.2f] [Green: %2.2f, %2.2f] [Blue: %2.2f, %2.2f]", |
hdr ->Primaries.Red.x, hdr ->Primaries.Red.y, |
hdr ->Primaries.Green.x, hdr ->Primaries.Green.y, |
hdr ->Primaries.Blue.x, hdr ->Primaries.Blue.y); |
|
if ((gamma_r != -1) && (gamma_g != -1) && (gamma_b != -1)) { |
|
hdr ->printf("Estimated gamma: [Red: %2.2f] [Green: %2.2f] [Blue: %2.2f]", |
gamma_r, gamma_g, gamma_b); |
} |
|
|
} |
|
|
|
return TRUE; |
} |
Property changes: |
Added: svn:eol-style |
## -0,0 +1 ## |
+native |
\ No newline at end of property |
Added: svn:keywords |
## -0,0 +1 ## |
+Author Date Id Revision |
\ No newline at end of property |