/* */ /* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 = (unsigned char*) malloc(size + 1); // C->C++ : fixed cast 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 chosen Lab as PCS"); } else { hdr ->PCSType = PT_XYZ; if (hdr ->printf) hdr ->printf("I have chosen 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; }