diff options
Diffstat (limited to 'debian/lcms/lcms-1.19.dfsg2/src/cmsvirt.c')
-rwxr-xr-x | debian/lcms/lcms-1.19.dfsg2/src/cmsvirt.c | 899 |
1 files changed, 899 insertions, 0 deletions
diff --git a/debian/lcms/lcms-1.19.dfsg2/src/cmsvirt.c b/debian/lcms/lcms-1.19.dfsg2/src/cmsvirt.c new file mode 100755 index 00000000..10f5bd67 --- /dev/null +++ b/debian/lcms/lcms-1.19.dfsg2/src/cmsvirt.c @@ -0,0 +1,899 @@ +// +// Little cms +// Copyright (C) 1998-2007 Marti Maria +// +// 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, +// and/or sell copies of the Software, and to permit persons to whom the Software +// 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 "lcms.h" + + +// Virtual (built-in) profiles +// ----------------------------------------------------------------------------------- + + +// This function creates a profile based on White point, primaries and +// transfer functions. + + +cmsHPROFILE LCMSEXPORT cmsCreateRGBProfile(LPcmsCIExyY WhitePoint, + LPcmsCIExyYTRIPLE Primaries, + LPGAMMATABLE TransferFunction[3]) +{ + cmsHPROFILE hICC; + cmsCIEXYZ tmp; + MAT3 MColorants; + cmsCIEXYZTRIPLE Colorants; + cmsCIExyY MaxWhite; + + + hICC = _cmsCreateProfilePlaceholder(); + if (!hICC) // can't allocate + return NULL; + + + cmsSetDeviceClass(hICC, icSigDisplayClass); + cmsSetColorSpace(hICC, icSigRgbData); + cmsSetPCS(hICC, icSigXYZData); + cmsSetRenderingIntent(hICC, INTENT_PERCEPTUAL); + + + // Implement profile using following tags: + // + // 1 icSigProfileDescriptionTag + // 2 icSigMediaWhitePointTag + // 3 icSigRedColorantTag + // 4 icSigGreenColorantTag + // 5 icSigBlueColorantTag + // 6 icSigRedTRCTag + // 7 icSigGreenTRCTag + // 8 icSigBlueTRCTag + + // This conforms a standard RGB DisplayProfile as says ICC, and then I add + + // 9 icSigChromaticityTag + + // As addendum II + + + // Fill-in the tags + + cmsAddTag(hICC, icSigDeviceMfgDescTag, (LPVOID) "(lcms internal)"); + cmsAddTag(hICC, icSigProfileDescriptionTag, (LPVOID) "lcms RGB virtual profile"); + cmsAddTag(hICC, icSigDeviceModelDescTag, (LPVOID) "rgb built-in"); + + + if (WhitePoint) { + + cmsxyY2XYZ(&tmp, WhitePoint); + cmsAddTag(hICC, icSigMediaWhitePointTag, (LPVOID) &tmp); + } + + if (WhitePoint && Primaries) { + + MaxWhite.x = WhitePoint -> x; + MaxWhite.y = WhitePoint -> y; + MaxWhite.Y = 1.0; + + if (!cmsBuildRGB2XYZtransferMatrix(&MColorants, &MaxWhite, Primaries)) + { + cmsCloseProfile(hICC); + return NULL; + } + + cmsAdaptMatrixToD50(&MColorants, &MaxWhite); + + 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]; + + cmsAddTag(hICC, icSigRedColorantTag, (LPVOID) &Colorants.Red); + cmsAddTag(hICC, icSigBlueColorantTag, (LPVOID) &Colorants.Blue); + cmsAddTag(hICC, icSigGreenColorantTag, (LPVOID) &Colorants.Green); + } + + + if (TransferFunction) { + + // In case of gamma, we must dup' the table pointer + + cmsAddTag(hICC, icSigRedTRCTag, (LPVOID) TransferFunction[0]); + cmsAddTag(hICC, icSigGreenTRCTag, (LPVOID) TransferFunction[1]); + cmsAddTag(hICC, icSigBlueTRCTag, (LPVOID) TransferFunction[2]); + } + + if (Primaries) { + cmsAddTag(hICC, icSigChromaticityTag, (LPVOID) Primaries); + } + + return hICC; +} + + + +// This function creates a profile based on White point and transfer function. + +cmsHPROFILE LCMSEXPORT cmsCreateGrayProfile(LPcmsCIExyY WhitePoint, + LPGAMMATABLE TransferFunction) +{ + cmsHPROFILE hICC; + cmsCIEXYZ tmp; + + + hICC = _cmsCreateProfilePlaceholder(); + if (!hICC) // can't allocate + return NULL; + + + cmsSetDeviceClass(hICC, icSigDisplayClass); + cmsSetColorSpace(hICC, icSigGrayData); + cmsSetPCS(hICC, icSigXYZData); + cmsSetRenderingIntent(hICC, INTENT_PERCEPTUAL); + + + + // Implement profile using following tags: + // + // 1 icSigProfileDescriptionTag + // 2 icSigMediaWhitePointTag + // 6 icSigGrayTRCTag + + // This conforms a standard Gray DisplayProfile + + // Fill-in the tags + + + cmsAddTag(hICC, icSigDeviceMfgDescTag, (LPVOID) "(lcms internal)"); + cmsAddTag(hICC, icSigProfileDescriptionTag, (LPVOID) "lcms gray virtual profile"); + cmsAddTag(hICC, icSigDeviceModelDescTag, (LPVOID) "gray built-in"); + + + if (WhitePoint) { + + cmsxyY2XYZ(&tmp, WhitePoint); + cmsAddTag(hICC, icSigMediaWhitePointTag, (LPVOID) &tmp); + } + + + if (TransferFunction) { + + // In case of gamma, we must dup' the table pointer + + cmsAddTag(hICC, icSigGrayTRCTag, (LPVOID) TransferFunction); + } + + return hICC; + +} + + +static +int IsPCS(icColorSpaceSignature ColorSpace) +{ + return (ColorSpace == icSigXYZData || + ColorSpace == icSigLabData); +} + +static +void FixColorSpaces(cmsHPROFILE hProfile, + icColorSpaceSignature ColorSpace, + icColorSpaceSignature PCS, + DWORD dwFlags) +{ + + if (dwFlags & cmsFLAGS_GUESSDEVICECLASS) { + + if (IsPCS(ColorSpace) && IsPCS(PCS)) { + + cmsSetDeviceClass(hProfile, icSigAbstractClass); + cmsSetColorSpace(hProfile, ColorSpace); + cmsSetPCS(hProfile, PCS); + return; + } + + if (IsPCS(ColorSpace) && !IsPCS(PCS)) { + + cmsSetDeviceClass(hProfile, icSigOutputClass); + cmsSetPCS(hProfile, ColorSpace); + cmsSetColorSpace(hProfile, PCS); + return; + } + + if (IsPCS(PCS) && !IsPCS(ColorSpace)) { + + cmsSetDeviceClass(hProfile, icSigInputClass); + cmsSetColorSpace(hProfile, ColorSpace); + cmsSetPCS(hProfile, PCS); + return; + } + } + + cmsSetDeviceClass(hProfile, icSigLinkClass); + cmsSetColorSpace(hProfile, ColorSpace); + cmsSetPCS(hProfile, PCS); + +} + + +static +cmsHPROFILE CreateNamedColorDevicelink(cmsHTRANSFORM xform) +{ + _LPcmsTRANSFORM v = (_LPcmsTRANSFORM) xform; + cmsHPROFILE hICC; + cmsCIEXYZ WhitePoint; + int i, nColors; + size_t Size; + LPcmsNAMEDCOLORLIST nc2; + + + hICC = _cmsCreateProfilePlaceholder(); + if (hICC == NULL) return NULL; + + cmsSetRenderingIntent(hICC, v -> Intent); + cmsSetDeviceClass(hICC, icSigNamedColorClass); + cmsSetColorSpace(hICC, v ->ExitColorSpace); + cmsSetPCS(hICC, cmsGetPCS(v ->InputProfile)); + cmsTakeMediaWhitePoint(&WhitePoint, v ->InputProfile); + + cmsAddTag(hICC, icSigMediaWhitePointTag, &WhitePoint); + cmsAddTag(hICC, icSigDeviceMfgDescTag, (LPVOID) "LittleCMS"); + cmsAddTag(hICC, icSigProfileDescriptionTag, (LPVOID) "Named color Device link"); + cmsAddTag(hICC, icSigDeviceModelDescTag, (LPVOID) "Named color Device link"); + + + nColors = cmsNamedColorCount(xform); + nc2 = cmsAllocNamedColorList(nColors); + + Size = sizeof(cmsNAMEDCOLORLIST) + (sizeof(cmsNAMEDCOLOR) * (nColors-1)); + + CopyMemory(nc2, v->NamedColorList, Size); + nc2 ->ColorantCount = _cmsChannelsOf(v ->ExitColorSpace); + + for (i=0; i < nColors; i++) { + cmsDoTransform(xform, &i, nc2 ->List[i].DeviceColorant, 1); + } + + cmsAddTag(hICC, icSigNamedColor2Tag, (void*) nc2); + cmsFreeNamedColorList(nc2); + + return hICC; +} + + +// Does convert a transform into a device link profile + +cmsHPROFILE LCMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, DWORD dwFlags) +{ + cmsHPROFILE hICC; + _LPcmsTRANSFORM v = (_LPcmsTRANSFORM) hTransform; + LPLUT Lut; + LCMSBOOL MustFreeLUT; + LPcmsNAMEDCOLORLIST InputColorant = NULL; + LPcmsNAMEDCOLORLIST OutputColorant = NULL; + + + // Check if is a named color transform + + if (cmsGetDeviceClass(v ->InputProfile) == icSigNamedColorClass) { + + return CreateNamedColorDevicelink(hTransform); + + } + + if (v ->DeviceLink) { + + Lut = v -> DeviceLink; + MustFreeLUT = FALSE; + } + else { + + Lut = _cmsPrecalculateDeviceLink(hTransform, dwFlags); + if (!Lut) return NULL; + MustFreeLUT = TRUE; + } + + hICC = _cmsCreateProfilePlaceholder(); + if (!hICC) { // can't allocate + + if (MustFreeLUT) cmsFreeLUT(Lut); + return NULL; + } + + + FixColorSpaces(hICC, v -> EntryColorSpace, v -> ExitColorSpace, dwFlags); + + cmsSetRenderingIntent(hICC, v -> Intent); + + // Implement devicelink profile using following tags: + // + // 1 icSigProfileDescriptionTag + // 2 icSigMediaWhitePointTag + // 3 icSigAToB0Tag + + + cmsAddTag(hICC, icSigDeviceMfgDescTag, (LPVOID) "LittleCMS"); + cmsAddTag(hICC, icSigProfileDescriptionTag, (LPVOID) "Device link"); + cmsAddTag(hICC, icSigDeviceModelDescTag, (LPVOID) "Device link"); + + + cmsAddTag(hICC, icSigMediaWhitePointTag, (LPVOID) cmsD50_XYZ()); + + if (cmsGetDeviceClass(hICC) == icSigOutputClass) { + + cmsAddTag(hICC, icSigBToA0Tag, (LPVOID) Lut); + } + else + cmsAddTag(hICC, icSigAToB0Tag, (LPVOID) Lut); + + + + // Try to read input and output colorant table + if (cmsIsTag(v ->InputProfile, icSigColorantTableTag)) { + + // Input table can only come in this way. + InputColorant = cmsReadColorantTable(v ->InputProfile, icSigColorantTableTag); + } + + // Output is a little bit more complex. + if (cmsGetDeviceClass(v ->OutputProfile) == icSigLinkClass) { + + // This tag may exist only on devicelink profiles. + if (cmsIsTag(v ->OutputProfile, icSigColorantTableOutTag)) { + + OutputColorant = cmsReadColorantTable(v ->OutputProfile, icSigColorantTableOutTag); + } + + } else { + + if (cmsIsTag(v ->OutputProfile, icSigColorantTableTag)) { + + OutputColorant = cmsReadColorantTable(v ->OutputProfile, icSigColorantTableTag); + } + } + + if (InputColorant) + cmsAddTag(hICC, icSigColorantTableTag, InputColorant); + + if (OutputColorant) + cmsAddTag(hICC, icSigColorantTableOutTag, OutputColorant); + + + + if (MustFreeLUT) cmsFreeLUT(Lut); + if (InputColorant) cmsFreeNamedColorList(InputColorant); + if (OutputColorant) cmsFreeNamedColorList(OutputColorant); + + return hICC; + +} + + +// This is a devicelink operating in the target colorspace with as many transfer +// functions as components + +cmsHPROFILE LCMSEXPORT cmsCreateLinearizationDeviceLink(icColorSpaceSignature ColorSpace, + LPGAMMATABLE TransferFunctions[]) +{ + cmsHPROFILE hICC; + LPLUT Lut; + + + hICC = _cmsCreateProfilePlaceholder(); + if (!hICC) // can't allocate + return NULL; + + + cmsSetDeviceClass(hICC, icSigLinkClass); + cmsSetColorSpace(hICC, ColorSpace); + cmsSetPCS(hICC, ColorSpace); + cmsSetRenderingIntent(hICC, INTENT_PERCEPTUAL); + + + // Creates a LUT with prelinearization step only + Lut = cmsAllocLUT(); + if (Lut == NULL) return NULL; + + // Set up channels + Lut ->InputChan = Lut ->OutputChan = _cmsChannelsOf(ColorSpace); + + // Copy tables to LUT + cmsAllocLinearTable(Lut, TransferFunctions, 1); + + // Create tags + cmsAddTag(hICC, icSigDeviceMfgDescTag, (LPVOID) "(lcms internal)"); + cmsAddTag(hICC, icSigProfileDescriptionTag, (LPVOID) "lcms linearization device link"); + cmsAddTag(hICC, icSigDeviceModelDescTag, (LPVOID) "linearization built-in"); + + cmsAddTag(hICC, icSigMediaWhitePointTag, (LPVOID) cmsD50_XYZ()); + cmsAddTag(hICC, icSigAToB0Tag, (LPVOID) Lut); + + // LUT is already on virtual profile + cmsFreeLUT(Lut); + + // Ok, done + return hICC; +} + + +// Ink-limiting algorithm +// +// Sum = C + M + Y + K +// If Sum > InkLimit +// Ratio= 1 - (Sum - InkLimit) / (C + M + Y) +// if Ratio <0 +// Ratio=0 +// endif +// Else +// Ratio=1 +// endif +// +// C = Ratio * C +// M = Ratio * M +// Y = Ratio * Y +// K: Does not change + +static +int InkLimitingSampler(register WORD In[], register WORD Out[], register LPVOID Cargo) +{ + double InkLimit = *(double *) Cargo; + double SumCMY, SumCMYK, Ratio; + + InkLimit = (InkLimit * 655.35); + + SumCMY = In[0] + In[1] + In[2]; + SumCMYK = SumCMY + In[3]; + + if (SumCMYK > InkLimit) { + + Ratio = 1 - ((SumCMYK - InkLimit) / SumCMY); + if (Ratio < 0) + Ratio = 0; + } + else Ratio = 1; + + Out[0] = (WORD) floor(In[0] * Ratio + 0.5); // C + Out[1] = (WORD) floor(In[1] * Ratio + 0.5); // M + Out[2] = (WORD) floor(In[2] * Ratio + 0.5); // Y + + Out[3] = In[3]; // K (untouched) + + return TRUE; +} + +// This is a devicelink operating in CMYK for ink-limiting + +cmsHPROFILE LCMSEXPORT cmsCreateInkLimitingDeviceLink(icColorSpaceSignature ColorSpace, + double Limit) +{ + cmsHPROFILE hICC; + LPLUT Lut; + + if (ColorSpace != icSigCmykData) { + cmsSignalError(LCMS_ERRC_ABORTED, "InkLimiting: Only CMYK currently supported"); + return NULL; + } + + if (Limit < 0.0 || Limit > 400) { + + cmsSignalError(LCMS_ERRC_WARNING, "InkLimiting: Limit should be between 0..400"); + if (Limit < 0) Limit = 0; + if (Limit > 400) Limit = 400; + + } + + hICC = _cmsCreateProfilePlaceholder(); + if (!hICC) // can't allocate + return NULL; + + + cmsSetDeviceClass(hICC, icSigLinkClass); + cmsSetColorSpace(hICC, ColorSpace); + cmsSetPCS(hICC, ColorSpace); + cmsSetRenderingIntent(hICC, INTENT_PERCEPTUAL); + + + // Creates a LUT with 3D grid only + Lut = cmsAllocLUT(); + if (Lut == NULL) { + cmsCloseProfile(hICC); + return NULL; + } + + + cmsAlloc3DGrid(Lut, 17, _cmsChannelsOf(ColorSpace), + _cmsChannelsOf(ColorSpace)); + + if (!cmsSample3DGrid(Lut, InkLimitingSampler, (LPVOID) &Limit, 0)) { + + // Shouldn't reach here + cmsFreeLUT(Lut); + cmsCloseProfile(hICC); + return NULL; + } + + // Create tags + + cmsAddTag(hICC, icSigDeviceMfgDescTag, (LPVOID) "(lcms internal)"); + cmsAddTag(hICC, icSigProfileDescriptionTag, (LPVOID) "lcms ink limiting device link"); + cmsAddTag(hICC, icSigDeviceModelDescTag, (LPVOID) "ink limiting built-in"); + + cmsAddTag(hICC, icSigMediaWhitePointTag, (LPVOID) cmsD50_XYZ()); + + cmsAddTag(hICC, icSigAToB0Tag, (LPVOID) Lut); + + // LUT is already on virtual profile + cmsFreeLUT(Lut); + + // Ok, done + return hICC; +} + + + +static +LPLUT Create3x3EmptyLUT(void) +{ + LPLUT AToB0 = cmsAllocLUT(); + if (AToB0 == NULL) return NULL; + + AToB0 -> InputChan = AToB0 -> OutputChan = 3; + return AToB0; +} + + + +// Creates a fake Lab identity. +cmsHPROFILE LCMSEXPORT cmsCreateLabProfile(LPcmsCIExyY WhitePoint) +{ + cmsHPROFILE hProfile; + LPLUT Lut; + + hProfile = cmsCreateRGBProfile(WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL); + if (hProfile == NULL) return NULL; + + cmsSetDeviceClass(hProfile, icSigAbstractClass); + cmsSetColorSpace(hProfile, icSigLabData); + cmsSetPCS(hProfile, icSigLabData); + + cmsAddTag(hProfile, icSigDeviceMfgDescTag, (LPVOID) "(lcms internal)"); + cmsAddTag(hProfile, icSigProfileDescriptionTag, (LPVOID) "lcms Lab identity"); + cmsAddTag(hProfile, icSigDeviceModelDescTag, (LPVOID) "Lab built-in"); + + + // An empty LUTs is all we need + Lut = Create3x3EmptyLUT(); + if (Lut == NULL) { + cmsCloseProfile(hProfile); + return NULL; + } + + cmsAddTag(hProfile, icSigAToB0Tag, (LPVOID) Lut); + cmsAddTag(hProfile, icSigBToA0Tag, (LPVOID) Lut); + + cmsFreeLUT(Lut); + + return hProfile; +} + + +// Creates a fake Lab identity. +cmsHPROFILE LCMSEXPORT cmsCreateLab4Profile(LPcmsCIExyY WhitePoint) +{ + cmsHPROFILE hProfile; + LPLUT Lut; + + hProfile = cmsCreateRGBProfile(WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL); + if (hProfile == NULL) return NULL; + + cmsSetProfileICCversion(hProfile, 0x4000000); + + cmsSetDeviceClass(hProfile, icSigAbstractClass); + cmsSetColorSpace(hProfile, icSigLabData); + cmsSetPCS(hProfile, icSigLabData); + + cmsAddTag(hProfile, icSigDeviceMfgDescTag, (LPVOID) "(lcms internal)"); + cmsAddTag(hProfile, icSigProfileDescriptionTag, (LPVOID) "lcms Lab identity v4"); + cmsAddTag(hProfile, icSigDeviceModelDescTag, (LPVOID) "Lab v4 built-in"); + + + // An empty LUTs is all we need + Lut = Create3x3EmptyLUT(); + if (Lut == NULL) { + cmsCloseProfile(hProfile); + return NULL; + } + + Lut -> wFlags |= LUT_V4_INPUT_EMULATE_V2; + cmsAddTag(hProfile, icSigAToB0Tag, (LPVOID) Lut); + + Lut -> wFlags |= LUT_V4_OUTPUT_EMULATE_V2; + cmsAddTag(hProfile, icSigBToA0Tag, (LPVOID) Lut); + + cmsFreeLUT(Lut); + + return hProfile; +} + + + +// Creates a fake XYZ identity +cmsHPROFILE LCMSEXPORT cmsCreateXYZProfile(void) +{ + cmsHPROFILE hProfile; + LPLUT Lut; + + hProfile = cmsCreateRGBProfile(cmsD50_xyY(), NULL, NULL); + if (hProfile == NULL) return NULL; + + cmsSetDeviceClass(hProfile, icSigAbstractClass); + cmsSetColorSpace(hProfile, icSigXYZData); + cmsSetPCS(hProfile, icSigXYZData); + + cmsAddTag(hProfile, icSigDeviceMfgDescTag, (LPVOID) "(lcms internal)"); + cmsAddTag(hProfile, icSigProfileDescriptionTag, (LPVOID) "lcms XYZ identity"); + cmsAddTag(hProfile, icSigDeviceModelDescTag, (LPVOID) "XYZ built-in"); + + // An empty LUTs is all we need + Lut = Create3x3EmptyLUT(); + if (Lut == NULL) { + cmsCloseProfile(hProfile); + return NULL; + } + + cmsAddTag(hProfile, icSigAToB0Tag, (LPVOID) Lut); + cmsAddTag(hProfile, icSigBToA0Tag, (LPVOID) Lut); + cmsAddTag(hProfile, icSigPreview0Tag, (LPVOID) Lut); + + cmsFreeLUT(Lut); + return hProfile; +} + + + +/* + +If R�sRGB,G�sRGB, B�sRGB < 0.04045 + + R = R�sRGB / 12.92 + G = G�sRGB / 12.92 + B = B�sRGB / 12.92 + + + +else if R�sRGB,G�sRGB, B�sRGB >= 0.04045 + + R = ((R�sRGB + 0.055) / 1.055)^2.4 + G = ((G�sRGB + 0.055) / 1.055)^2.4 + B = ((B�sRGB + 0.055) / 1.055)^2.4 + + */ + +static +LPGAMMATABLE Build_sRGBGamma(void) +{ + double Parameters[5]; + + Parameters[0] = 2.4; + Parameters[1] = 1. / 1.055; + Parameters[2] = 0.055 / 1.055; + Parameters[3] = 1. / 12.92; + Parameters[4] = 0.04045; // d + + return cmsBuildParametricGamma(1024, 4, Parameters); +} + +// Create the ICC virtual profile for sRGB space +cmsHPROFILE LCMSEXPORT cmsCreate_sRGBProfile(void) +{ + cmsCIExyY D65; + cmsCIExyYTRIPLE Rec709Primaries = { + {0.6400, 0.3300, 1.0}, + {0.3000, 0.6000, 1.0}, + {0.1500, 0.0600, 1.0} + }; + LPGAMMATABLE Gamma22[3]; + cmsHPROFILE hsRGB; + + cmsWhitePointFromTemp(6504, &D65); + Gamma22[0] = Gamma22[1] = Gamma22[2] = Build_sRGBGamma(); + + hsRGB = cmsCreateRGBProfile(&D65, &Rec709Primaries, Gamma22); + cmsFreeGamma(Gamma22[0]); + if (hsRGB == NULL) return NULL; + + + cmsAddTag(hsRGB, icSigDeviceMfgDescTag, (LPVOID) "(lcms internal)"); + cmsAddTag(hsRGB, icSigDeviceModelDescTag, (LPVOID) "sRGB built-in"); + cmsAddTag(hsRGB, icSigProfileDescriptionTag, (LPVOID) "sRGB built-in"); + + return hsRGB; +} + + + +typedef struct { + double Brightness; + double Contrast; + double Hue; + double Saturation; + cmsCIEXYZ WPsrc, WPdest; + +} BCHSWADJUSTS, *LPBCHSWADJUSTS; + + +static +int bchswSampler(register WORD In[], register WORD Out[], register LPVOID Cargo) +{ + cmsCIELab LabIn, LabOut; + cmsCIELCh LChIn, LChOut; + cmsCIEXYZ XYZ; + LPBCHSWADJUSTS bchsw = (LPBCHSWADJUSTS) Cargo; + + + cmsLabEncoded2Float(&LabIn, In); + + + cmsLab2LCh(&LChIn, &LabIn); + + // Do some adjusts on LCh + + LChOut.L = LChIn.L * bchsw ->Contrast + bchsw ->Brightness; + LChOut.C = LChIn.C + bchsw -> Saturation; + LChOut.h = LChIn.h + bchsw -> Hue; + + + cmsLCh2Lab(&LabOut, &LChOut); + + // Move white point in Lab + + cmsLab2XYZ(&bchsw ->WPsrc, &XYZ, &LabOut); + cmsXYZ2Lab(&bchsw ->WPdest, &LabOut, &XYZ); + + // Back to encoded + + cmsFloat2LabEncoded(Out, &LabOut); + + return TRUE; +} + + +// Creates an abstract profile operating in Lab space for Brightness, +// contrast, Saturation and white point displacement + +cmsHPROFILE LCMSEXPORT cmsCreateBCHSWabstractProfile(int nLUTPoints, + double Bright, + double Contrast, + double Hue, + double Saturation, + int TempSrc, + int TempDest) +{ + cmsHPROFILE hICC; + LPLUT Lut; + BCHSWADJUSTS bchsw; + cmsCIExyY WhitePnt; + + bchsw.Brightness = Bright; + bchsw.Contrast = Contrast; + bchsw.Hue = Hue; + bchsw.Saturation = Saturation; + + cmsWhitePointFromTemp(TempSrc, &WhitePnt); + cmsxyY2XYZ(&bchsw.WPsrc, &WhitePnt); + + cmsWhitePointFromTemp(TempDest, &WhitePnt); + cmsxyY2XYZ(&bchsw.WPdest, &WhitePnt); + + hICC = _cmsCreateProfilePlaceholder(); + if (!hICC) // can't allocate + return NULL; + + + cmsSetDeviceClass(hICC, icSigAbstractClass); + cmsSetColorSpace(hICC, icSigLabData); + cmsSetPCS(hICC, icSigLabData); + + cmsSetRenderingIntent(hICC, INTENT_PERCEPTUAL); + + + // Creates a LUT with 3D grid only + Lut = cmsAllocLUT(); + if (Lut == NULL) { + cmsCloseProfile(hICC); + return NULL; + } + + cmsAlloc3DGrid(Lut, nLUTPoints, 3, 3); + + if (!cmsSample3DGrid(Lut, bchswSampler, (LPVOID) &bchsw, 0)) { + + // Shouldn't reach here + cmsFreeLUT(Lut); + cmsCloseProfile(hICC); + return NULL; + } + + // Create tags + + cmsAddTag(hICC, icSigDeviceMfgDescTag, (LPVOID) "(lcms internal)"); + cmsAddTag(hICC, icSigProfileDescriptionTag, (LPVOID) "lcms BCHSW abstract profile"); + cmsAddTag(hICC, icSigDeviceModelDescTag, (LPVOID) "BCHSW built-in"); + + cmsAddTag(hICC, icSigMediaWhitePointTag, (LPVOID) cmsD50_XYZ()); + + cmsAddTag(hICC, icSigAToB0Tag, (LPVOID) Lut); + + // LUT is already on virtual profile + cmsFreeLUT(Lut); + + // Ok, done + return hICC; + +} + + +// Creates a fake NULL profile. This profile return 1 channel as always 0. +// Is useful only for gamut checking tricks + +cmsHPROFILE LCMSEXPORT cmsCreateNULLProfile(void) +{ + cmsHPROFILE hProfile; + LPLUT Lut; + LPGAMMATABLE EmptyTab; + + hProfile = _cmsCreateProfilePlaceholder(); + if (!hProfile) // can't allocate + return NULL; + + cmsSetDeviceClass(hProfile, icSigOutputClass); + cmsSetColorSpace(hProfile, icSigGrayData); + cmsSetPCS(hProfile, icSigLabData); + + + // An empty LUTs is all we need + Lut = cmsAllocLUT(); + if (Lut == NULL) { + cmsCloseProfile(hProfile); + return NULL; + } + + Lut -> InputChan = 3; + Lut -> OutputChan = 1; + + EmptyTab = cmsAllocGamma(2); + EmptyTab ->GammaTable[0] = 0; + EmptyTab ->GammaTable[1] = 0; + + cmsAllocLinearTable(Lut, &EmptyTab, 2); + + cmsAddTag(hProfile, icSigBToA0Tag, (LPVOID) Lut); + + cmsFreeLUT(Lut); + cmsFreeGamma(EmptyTab); + + return hProfile; +} |