1ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//--------------------------------------------------------------------------------- 2ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 3ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Little Color Management System 4ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Copyright (c) 1998-2014 Marti Maria Saguer 5ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 6ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Permission is hereby granted, free of charge, to any person obtaining 7ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// a copy of this software and associated documentation files (the "Software"), 8ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// to deal in the Software without restriction, including without limitation 9ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// the rights to use, copy, modify, merge, publish, distribute, sublicense, 10ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// and/or sell copies of the Software, and to permit persons to whom the Software 11ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// is furnished to do so, subject to the following conditions: 12ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 13ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// The above copyright notice and this permission notice shall be included in 14ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// all copies or substantial portions of the Software. 15ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 16ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 18ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 24ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//--------------------------------------------------------------------------------- 25ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 26ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 27ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "lcms2_internal.h" 28ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 29ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Virtual (built-in) profiles 30ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ----------------------------------------------------------------------------------- 31ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 32ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 33ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool SetTextTags(cmsHPROFILE hProfile, const wchar_t* Description) 34ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 35ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsMLU *DescriptionMLU, *CopyrightMLU; 36ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsBool rc = FALSE; 37ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsContext ContextID = cmsGetProfileContextID(hProfile); 38ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 39ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov DescriptionMLU = cmsMLUalloc(ContextID, 1); 40ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov CopyrightMLU = cmsMLUalloc(ContextID, 1); 41ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 42ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (DescriptionMLU == NULL || CopyrightMLU == NULL) goto Error; 43ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 44ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsMLUsetWide(DescriptionMLU, "en", "US", Description)) goto Error; 45ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsMLUsetWide(CopyrightMLU, "en", "US", L"No copyright, use freely")) goto Error; 46ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 47ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hProfile, cmsSigProfileDescriptionTag, DescriptionMLU)) goto Error; 48ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hProfile, cmsSigCopyrightTag, CopyrightMLU)) goto Error; 49ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 50ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov rc = TRUE; 51ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 52ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovError: 53ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 54ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (DescriptionMLU) 55ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsMLUfree(DescriptionMLU); 56ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (CopyrightMLU) 57ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsMLUfree(CopyrightMLU); 58ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return rc; 59ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 60ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 61ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 62ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 63ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool SetSeqDescTag(cmsHPROFILE hProfile, const char* Model) 64ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 65ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsBool rc = FALSE; 66ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsContext ContextID = cmsGetProfileContextID(hProfile); 67ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSEQ* Seq = cmsAllocProfileSequenceDescription(ContextID, 1); 68ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 69ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Seq == NULL) return FALSE; 70ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 71ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Seq->seq[0].deviceMfg = (cmsSignature) 0; 72ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Seq->seq[0].deviceModel = (cmsSignature) 0; 73ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 74ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef CMS_DONT_USE_INT64 75ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Seq->seq[0].attributes[0] = 0; 76ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Seq->seq[0].attributes[1] = 0; 77ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#else 78ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Seq->seq[0].attributes = 0; 79ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif 80ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 81ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Seq->seq[0].technology = (cmsTechnologySignature) 0; 82ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 83ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsMLUsetASCII( Seq->seq[0].Manufacturer, cmsNoLanguage, cmsNoCountry, "Little CMS"); 84ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsMLUsetASCII( Seq->seq[0].Model, cmsNoLanguage, cmsNoCountry, Model); 85ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 86ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!_cmsWriteProfileSequence(hProfile, Seq)) goto Error; 87ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 88ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov rc = TRUE; 89ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 90ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovError: 91ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Seq) 92ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFreeProfileSequenceDescription(Seq); 93ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 94ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return rc; 95ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 96ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 97ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 98ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 99ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// This function creates a profile based on White point, primaries and 100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// transfer functions. 101ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHPROFILE CMSEXPORT cmsCreateRGBProfileTHR(cmsContext ContextID, 102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const cmsCIExyY* WhitePoint, 103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const cmsCIExyYTRIPLE* Primaries, 104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsToneCurve* const TransferFunction[3]) 105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsHPROFILE hICC; 107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsMAT3 MColorants; 108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCIEXYZTRIPLE Colorants; 109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCIExyY MaxWhite; 110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsMAT3 CHAD; 111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCIEXYZ WhitePointXYZ; 112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hICC = cmsCreateProfilePlaceholder(ContextID); 114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!hICC) // can't allocate 115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetProfileVersion(hICC, 4.3); 118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetDeviceClass(hICC, cmsSigDisplayClass); 120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetColorSpace(hICC, cmsSigRgbData); 121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetPCS(hICC, cmsSigXYZData); 122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); 124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Implement profile using following tags: 127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // 128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // 1 cmsSigProfileDescriptionTag 129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // 2 cmsSigMediaWhitePointTag 130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // 3 cmsSigRedColorantTag 131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // 4 cmsSigGreenColorantTag 132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // 5 cmsSigBlueColorantTag 133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // 6 cmsSigRedTRCTag 134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // 7 cmsSigGreenTRCTag 135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // 8 cmsSigBlueTRCTag 136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // 9 Chromatic adaptation Tag 137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // This conforms a standard RGB DisplayProfile as says ICC, and then I add (As per addendum II) 138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // 10 cmsSigChromaticityTag 139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!SetTextTags(hICC, L"RGB built-in")) goto Error; 142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (WhitePoint) { 144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hICC, cmsSigMediaWhitePointTag, cmsD50_XYZ())) goto Error; 146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsxyY2XYZ(&WhitePointXYZ, WhitePoint); 148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsAdaptationMatrix(&CHAD, NULL, &WhitePointXYZ, cmsD50_XYZ()); 149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // This is a V4 tag, but many CMM does read and understand it no matter which version 151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hICC, cmsSigChromaticAdaptationTag, (void*) &CHAD)) goto Error; 152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (WhitePoint && Primaries) { 155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov MaxWhite.x = WhitePoint -> x; 157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov MaxWhite.y = WhitePoint -> y; 158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov MaxWhite.Y = 1.0; 159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!_cmsBuildRGB2XYZtransferMatrix(&MColorants, &MaxWhite, Primaries)) goto Error; 161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Colorants.Red.X = MColorants.v[0].n[0]; 163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Colorants.Red.Y = MColorants.v[1].n[0]; 164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Colorants.Red.Z = MColorants.v[2].n[0]; 165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Colorants.Green.X = MColorants.v[0].n[1]; 167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Colorants.Green.Y = MColorants.v[1].n[1]; 168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Colorants.Green.Z = MColorants.v[2].n[1]; 169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Colorants.Blue.X = MColorants.v[0].n[2]; 171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Colorants.Blue.Y = MColorants.v[1].n[2]; 172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Colorants.Blue.Z = MColorants.v[2].n[2]; 173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hICC, cmsSigRedColorantTag, (void*) &Colorants.Red)) goto Error; 175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hICC, cmsSigBlueColorantTag, (void*) &Colorants.Blue)) goto Error; 176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hICC, cmsSigGreenColorantTag, (void*) &Colorants.Green)) goto Error; 177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (TransferFunction) { 181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Tries to minimize space. Thanks to Richard Hughes for this nice idea 183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hICC, cmsSigRedTRCTag, (void*) TransferFunction[0])) goto Error; 184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (TransferFunction[1] == TransferFunction[0]) { 186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsLinkTag (hICC, cmsSigGreenTRCTag, cmsSigRedTRCTag)) goto Error; 188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } else { 190ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hICC, cmsSigGreenTRCTag, (void*) TransferFunction[1])) goto Error; 192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (TransferFunction[2] == TransferFunction[0]) { 195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsLinkTag (hICC, cmsSigBlueTRCTag, cmsSigRedTRCTag)) goto Error; 197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } else { 199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hICC, cmsSigBlueTRCTag, (void*) TransferFunction[2])) goto Error; 201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Primaries) { 205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hICC, cmsSigChromaticityTag, (void*) Primaries)) goto Error; 206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return hICC; 210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 211ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovError: 212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (hICC) 213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCloseProfile(hICC); 214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 217ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHPROFILE CMSEXPORT cmsCreateRGBProfile(const cmsCIExyY* WhitePoint, 218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const cmsCIExyYTRIPLE* Primaries, 219ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsToneCurve* const TransferFunction[3]) 220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return cmsCreateRGBProfileTHR(NULL, WhitePoint, Primaries, TransferFunction); 222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// This function creates a profile based on White point and transfer function. 227ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHPROFILE CMSEXPORT cmsCreateGrayProfileTHR(cmsContext ContextID, 228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const cmsCIExyY* WhitePoint, 229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const cmsToneCurve* TransferFunction) 230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsHPROFILE hICC; 232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCIEXYZ tmp; 233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hICC = cmsCreateProfilePlaceholder(ContextID); 235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!hICC) // can't allocate 236ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetProfileVersion(hICC, 4.3); 239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetDeviceClass(hICC, cmsSigDisplayClass); 241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetColorSpace(hICC, cmsSigGrayData); 242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetPCS(hICC, cmsSigXYZData); 243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); 244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Implement profile using following tags: 247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // 248ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // 1 cmsSigProfileDescriptionTag 249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // 2 cmsSigMediaWhitePointTag 250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // 3 cmsSigGrayTRCTag 251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // This conforms a standard Gray DisplayProfile 253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Fill-in the tags 255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!SetTextTags(hICC, L"gray built-in")) goto Error; 257ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 258ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 259ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (WhitePoint) { 260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 261ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsxyY2XYZ(&tmp, WhitePoint); 262ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) &tmp)) goto Error; 263ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 264ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 265ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (TransferFunction) { 266ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 267ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hICC, cmsSigGrayTRCTag, (void*) TransferFunction)) goto Error; 268ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 269ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 270ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return hICC; 271ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 272ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovError: 273ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (hICC) 274ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCloseProfile(hICC); 275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 276ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 277ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 278ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 279ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 280ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHPROFILE CMSEXPORT cmsCreateGrayProfile(const cmsCIExyY* WhitePoint, 281ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const cmsToneCurve* TransferFunction) 282ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 283ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return cmsCreateGrayProfileTHR(NULL, WhitePoint, TransferFunction); 284ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 285ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 286ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// This is a devicelink operating in the target colorspace with as many transfer functions as components 287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 288ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID, 289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsColorSpaceSignature ColorSpace, 290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsToneCurve* const TransferFunctions[]) 291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 292ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsHPROFILE hICC; 293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipeline* Pipeline; 294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int nChannels; 295ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 296ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hICC = cmsCreateProfilePlaceholder(ContextID); 297ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!hICC) 298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 299ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 300ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetProfileVersion(hICC, 4.3); 301ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 302ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetDeviceClass(hICC, cmsSigLinkClass); 303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetColorSpace(hICC, ColorSpace); 304ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetPCS(hICC, ColorSpace); 305ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 306ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); 307ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 308ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Set up channels 309ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov nChannels = cmsChannelsOf(ColorSpace); 310ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 311ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Creates a Pipeline with prelinearization step only 312ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Pipeline = cmsPipelineAlloc(ContextID, nChannels, nChannels); 313ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Pipeline == NULL) goto Error; 314ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 315ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 316ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Copy tables to Pipeline 317ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineInsertStage(Pipeline, cmsAT_BEGIN, cmsStageAllocToneCurves(ContextID, nChannels, TransferFunctions))) 318ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 319ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 320ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Create tags 321ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!SetTextTags(hICC, L"Linearization built-in")) goto Error; 322ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline)) goto Error; 323ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!SetSeqDescTag(hICC, "Linearization built-in")) goto Error; 324ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 325ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Pipeline is already on virtual profile 326ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineFree(Pipeline); 327ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 328ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Ok, done 329ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return hICC; 330ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 331ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovError: 332ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineFree(Pipeline); 333ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (hICC) 334ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCloseProfile(hICC); 335ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 336ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 337ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 338ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 339ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 340ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLink(cmsColorSpaceSignature ColorSpace, 341ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsToneCurve* const TransferFunctions[]) 342ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 343ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return cmsCreateLinearizationDeviceLinkTHR(NULL, ColorSpace, TransferFunctions); 344ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 345ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 346ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Ink-limiting algorithm 347ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 348ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Sum = C + M + Y + K 349ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// If Sum > InkLimit 350ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Ratio= 1 - (Sum - InkLimit) / (C + M + Y) 351ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// if Ratio <0 352ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Ratio=0 353ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// endif 354ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Else 355ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Ratio=1 356ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// endif 357ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 358ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// C = Ratio * C 359ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// M = Ratio * M 360ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Y = Ratio * Y 361ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// K: Does not change 362ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 363ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 364ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovint InkLimitingSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) 365ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 366ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat64Number InkLimit = *(cmsFloat64Number *) Cargo; 367ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat64Number SumCMY, SumCMYK, Ratio; 368ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 369ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov InkLimit = (InkLimit * 655.35); 370ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 371ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov SumCMY = In[0] + In[1] + In[2]; 372ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov SumCMYK = SumCMY + In[3]; 373ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 374ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (SumCMYK > InkLimit) { 375ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 376ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Ratio = 1 - ((SumCMYK - InkLimit) / SumCMY); 377ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Ratio < 0) 378ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Ratio = 0; 379ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 380ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else Ratio = 1; 381ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 382ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Out[0] = _cmsQuickSaturateWord(In[0] * Ratio); // C 383ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Out[1] = _cmsQuickSaturateWord(In[1] * Ratio); // M 384ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Out[2] = _cmsQuickSaturateWord(In[2] * Ratio); // Y 385ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 386ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Out[3] = In[3]; // K (untouched) 387ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 388ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 389ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 390ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 391ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// This is a devicelink operating in CMYK for ink-limiting 392ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 393ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID, 394ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsColorSpaceSignature ColorSpace, 395ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat64Number Limit) 396ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 397ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsHPROFILE hICC; 398ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipeline* LUT; 399ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* CLUT; 400ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int nChannels; 401ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 402ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (ColorSpace != cmsSigCmykData) { 403ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "InkLimiting: Only CMYK currently supported"); 404ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 405ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 406ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 407ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Limit < 0.0 || Limit > 400) { 408ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 409ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSignalError(ContextID, cmsERROR_RANGE, "InkLimiting: Limit should be between 0..400"); 410ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Limit < 0) Limit = 0; 411ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Limit > 400) Limit = 400; 412ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 413ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 414ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 415ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hICC = cmsCreateProfilePlaceholder(ContextID); 416ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!hICC) // can't allocate 417ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 418ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 419ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetProfileVersion(hICC, 4.3); 420ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 421ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetDeviceClass(hICC, cmsSigLinkClass); 422ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetColorSpace(hICC, ColorSpace); 423ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetPCS(hICC, ColorSpace); 424ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 425ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); 426ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 427ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 428ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Creates a Pipeline with 3D grid only 429ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LUT = cmsPipelineAlloc(ContextID, 4, 4); 430ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (LUT == NULL) goto Error; 431ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 432ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 433ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov nChannels = cmsChannelsOf(ColorSpace); 434ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 435ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov CLUT = cmsStageAllocCLut16bit(ContextID, 17, nChannels, nChannels, NULL); 436ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (CLUT == NULL) goto Error; 437ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 438ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsStageSampleCLut16bit(CLUT, InkLimitingSampler, (void*) &Limit, 0)) goto Error; 439ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 440ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, nChannels)) || 441ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov !cmsPipelineInsertStage(LUT, cmsAT_END, CLUT) || 442ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov !cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, nChannels))) 443ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 444ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 445ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Create tags 446ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!SetTextTags(hICC, L"ink-limiting built-in")) goto Error; 447ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 448ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) LUT)) goto Error; 449ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!SetSeqDescTag(hICC, "ink-limiting built-in")) goto Error; 450ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 451ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // cmsPipeline is already on virtual profile 452ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineFree(LUT); 453ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 454ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Ok, done 455ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return hICC; 456ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 457ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovError: 458ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (LUT != NULL) 459ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineFree(LUT); 460ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 461ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (hICC != NULL) 462ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCloseProfile(hICC); 463ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 464ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 465ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 466ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 467ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLink(cmsColorSpaceSignature ColorSpace, cmsFloat64Number Limit) 468ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 469ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return cmsCreateInkLimitingDeviceLinkTHR(NULL, ColorSpace, Limit); 470ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 471ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 472ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 473ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Creates a fake Lab identity. 474ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHPROFILE CMSEXPORT cmsCreateLab2ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint) 475ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 476ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsHPROFILE hProfile; 477ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipeline* LUT = NULL; 478ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 479ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hProfile = cmsCreateRGBProfileTHR(ContextID, WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL); 480ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (hProfile == NULL) return NULL; 481ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 482ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetProfileVersion(hProfile, 2.1); 483ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 484ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetDeviceClass(hProfile, cmsSigAbstractClass); 485ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetColorSpace(hProfile, cmsSigLabData); 486ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetPCS(hProfile, cmsSigLabData); 487ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 488ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!SetTextTags(hProfile, L"Lab identity built-in")) return NULL; 489ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 490ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // An identity LUT is all we need 491ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LUT = cmsPipelineAlloc(ContextID, 3, 3); 492ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (LUT == NULL) goto Error; 493ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 494ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCLut(ContextID, 3))) 495ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 496ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 497ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error; 498ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineFree(LUT); 499ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 500ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return hProfile; 501ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 502ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovError: 503ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 504ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (LUT != NULL) 505ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineFree(LUT); 506ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 507ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (hProfile != NULL) 508ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCloseProfile(hProfile); 509ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 510ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 511ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 512ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 513ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 514ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHPROFILE CMSEXPORT cmsCreateLab2Profile(const cmsCIExyY* WhitePoint) 515ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 516ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return cmsCreateLab2ProfileTHR(NULL, WhitePoint); 517ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 518ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 519ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 520ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Creates a fake Lab V4 identity. 521ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHPROFILE CMSEXPORT cmsCreateLab4ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint) 522ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 523ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsHPROFILE hProfile; 524ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipeline* LUT = NULL; 525ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 526ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hProfile = cmsCreateRGBProfileTHR(ContextID, WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL); 527ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (hProfile == NULL) return NULL; 528ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 529ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetProfileVersion(hProfile, 4.3); 530ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 531ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetDeviceClass(hProfile, cmsSigAbstractClass); 532ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetColorSpace(hProfile, cmsSigLabData); 533ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetPCS(hProfile, cmsSigLabData); 534ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 535ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!SetTextTags(hProfile, L"Lab identity built-in")) goto Error; 536ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 537ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // An empty LUTs is all we need 538ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LUT = cmsPipelineAlloc(ContextID, 3, 3); 539ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (LUT == NULL) goto Error; 540ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 541ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3))) 542ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 543ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 544ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error; 545ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineFree(LUT); 546ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 547ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return hProfile; 548ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 549ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovError: 550ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 551ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (LUT != NULL) 552ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineFree(LUT); 553ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 554ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (hProfile != NULL) 555ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCloseProfile(hProfile); 556ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 557ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 558ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 559ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 560ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHPROFILE CMSEXPORT cmsCreateLab4Profile(const cmsCIExyY* WhitePoint) 561ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 562ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return cmsCreateLab4ProfileTHR(NULL, WhitePoint); 563ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 564ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 565ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 566ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Creates a fake XYZ identity 567ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHPROFILE CMSEXPORT cmsCreateXYZProfileTHR(cmsContext ContextID) 568ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 569ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsHPROFILE hProfile; 570ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipeline* LUT = NULL; 571ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 572ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hProfile = cmsCreateRGBProfileTHR(ContextID, cmsD50_xyY(), NULL, NULL); 573ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (hProfile == NULL) return NULL; 574ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 575ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetProfileVersion(hProfile, 4.3); 576ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 577ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetDeviceClass(hProfile, cmsSigAbstractClass); 578ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetColorSpace(hProfile, cmsSigXYZData); 579ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetPCS(hProfile, cmsSigXYZData); 580ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 581ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!SetTextTags(hProfile, L"XYZ identity built-in")) goto Error; 582ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 583ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // An identity LUT is all we need 584ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LUT = cmsPipelineAlloc(ContextID, 3, 3); 585ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (LUT == NULL) goto Error; 586ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 587ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3))) 588ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 589ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 590ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error; 591ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineFree(LUT); 592ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 593ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return hProfile; 594ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 595ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovError: 596ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 597ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (LUT != NULL) 598ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineFree(LUT); 599ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 600ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (hProfile != NULL) 601ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCloseProfile(hProfile); 602ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 603ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 604ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 605ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 606ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 607ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHPROFILE CMSEXPORT cmsCreateXYZProfile(void) 608ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 609ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return cmsCreateXYZProfileTHR(NULL); 610ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 611ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 612ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 613ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//sRGB Curves are defined by: 614ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 6154d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann//If R'sRGB,G'sRGB, B'sRGB < 0.04045 616ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 6174d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann// R = R'sRGB / 12.92 6184d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann// G = G'sRGB / 12.92 6194d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann// B = B'sRGB / 12.92 620ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 621ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 6224d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann//else if R'sRGB,G'sRGB, B'sRGB >= 0.04045 623ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 6244d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann// R = ((R'sRGB + 0.055) / 1.055)^2.4 6254d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann// G = ((G'sRGB + 0.055) / 1.055)^2.4 6264d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann// B = ((B'sRGB + 0.055) / 1.055)^2.4 627ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 628ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 629ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsToneCurve* Build_sRGBGamma(cmsContext ContextID) 630ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 631ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat64Number Parameters[5]; 632ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 633ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Parameters[0] = 2.4; 634ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Parameters[1] = 1. / 1.055; 635ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Parameters[2] = 0.055 / 1.055; 636ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Parameters[3] = 1. / 12.92; 637ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Parameters[4] = 0.04045; 638ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 639ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return cmsBuildParametricToneCurve(ContextID, 4, Parameters); 640ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 641ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 642ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Create the ICC virtual profile for sRGB space 643ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHPROFILE CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID) 644ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 645ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCIExyY D65; 646ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCIExyYTRIPLE Rec709Primaries = { 647ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov {0.6400, 0.3300, 1.0}, 648ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov {0.3000, 0.6000, 1.0}, 649ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov {0.1500, 0.0600, 1.0} 650ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov }; 651ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsToneCurve* Gamma22[3]; 652ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsHPROFILE hsRGB; 653ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 654ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsWhitePointFromTemp(&D65, 6504); 655ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Gamma22[0] = Gamma22[1] = Gamma22[2] = Build_sRGBGamma(ContextID); 656ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Gamma22[0] == NULL) return NULL; 657ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 658ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hsRGB = cmsCreateRGBProfileTHR(ContextID, &D65, &Rec709Primaries, Gamma22); 659ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFreeToneCurve(Gamma22[0]); 660ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (hsRGB == NULL) return NULL; 661ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 662ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!SetTextTags(hsRGB, L"sRGB built-in")) { 663ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCloseProfile(hsRGB); 664ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 665ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 666ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 667ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return hsRGB; 668ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 669ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 670ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHPROFILE CMSEXPORT cmsCreate_sRGBProfile(void) 671ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 672ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return cmsCreate_sRGBProfileTHR(NULL); 673ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 674ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 675ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 676ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 677ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovtypedef struct { 678ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat64Number Brightness; 679ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat64Number Contrast; 680ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat64Number Hue; 681ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat64Number Saturation; 682ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCIEXYZ WPsrc, WPdest; 683ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 684ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} BCHSWADJUSTS, *LPBCHSWADJUSTS; 685ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 686ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 687ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 688ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovint bchswSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) 689ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 690ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCIELab LabIn, LabOut; 691ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCIELCh LChIn, LChOut; 692ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCIEXYZ XYZ; 693ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LPBCHSWADJUSTS bchsw = (LPBCHSWADJUSTS) Cargo; 694ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 695ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 696ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsLabEncoded2Float(&LabIn, In); 697ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 698ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 699ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsLab2LCh(&LChIn, &LabIn); 700ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 701ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Do some adjusts on LCh 702ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 703ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LChOut.L = LChIn.L * bchsw ->Contrast + bchsw ->Brightness; 704ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LChOut.C = LChIn.C + bchsw -> Saturation; 705ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LChOut.h = LChIn.h + bchsw -> Hue; 706ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 707ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 708ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsLCh2Lab(&LabOut, &LChOut); 709ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 710ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Move white point in Lab 711ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 712ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsLab2XYZ(&bchsw ->WPsrc, &XYZ, &LabOut); 713ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsXYZ2Lab(&bchsw ->WPdest, &LabOut, &XYZ); 714ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 715ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Back to encoded 716ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 717ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat2LabEncoded(Out, &LabOut); 718ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 719ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 720ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 721ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 722ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 723ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Creates an abstract profile operating in Lab space for Brightness, 724ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// contrast, Saturation and white point displacement 725ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 726ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID, 727ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int nLUTPoints, 728ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat64Number Bright, 729ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat64Number Contrast, 730ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat64Number Hue, 731ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat64Number Saturation, 732ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int TempSrc, 733ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int TempDest) 734ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 735ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsHPROFILE hICC; 736ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipeline* Pipeline; 737ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov BCHSWADJUSTS bchsw; 738ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCIExyY WhitePnt; 739ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* CLUT; 740ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; 741ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i; 742ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 743ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov bchsw.Brightness = Bright; 744ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov bchsw.Contrast = Contrast; 745ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov bchsw.Hue = Hue; 746ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov bchsw.Saturation = Saturation; 747ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 748ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsWhitePointFromTemp(&WhitePnt, TempSrc ); 749ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsxyY2XYZ(&bchsw.WPsrc, &WhitePnt); 750ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 751ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsWhitePointFromTemp(&WhitePnt, TempDest); 752ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsxyY2XYZ(&bchsw.WPdest, &WhitePnt); 753ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 754ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hICC = cmsCreateProfilePlaceholder(ContextID); 755ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!hICC) // can't allocate 756ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 757ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 758ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 759ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetDeviceClass(hICC, cmsSigAbstractClass); 760ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetColorSpace(hICC, cmsSigLabData); 761ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetPCS(hICC, cmsSigLabData); 762ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 763ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); 764ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 765ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Creates a Pipeline with 3D grid only 766ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Pipeline = cmsPipelineAlloc(ContextID, 3, 3); 767ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Pipeline == NULL) { 768ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCloseProfile(hICC); 769ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 770ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 771ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 772ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Dimensions[i] = nLUTPoints; 773ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov CLUT = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 3, 3, NULL); 774ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (CLUT == NULL) return NULL; 775ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 776ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 777ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsStageSampleCLut16bit(CLUT, bchswSampler, (void*) &bchsw, 0)) { 778ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 779ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Shouldn't reach here 780ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 781ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 782ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 783ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT)) { 784ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 785ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 786ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 787ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Create tags 788ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!SetTextTags(hICC, L"BCHS built-in")) return NULL; 789ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 790ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) cmsD50_XYZ()); 791ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 792ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline); 793ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 794ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Pipeline is already on virtual profile 795ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineFree(Pipeline); 796ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 797ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Ok, done 798ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return hICC; 799ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 800ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovError: 801ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineFree(Pipeline); 802ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCloseProfile(hICC); 803ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 804ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 805ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 806ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 807ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovCMSAPI cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfile(int nLUTPoints, 808ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat64Number Bright, 809ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat64Number Contrast, 810ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat64Number Hue, 811ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat64Number Saturation, 812ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int TempSrc, 813ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int TempDest) 814ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 815ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return cmsCreateBCHSWabstractProfileTHR(NULL, nLUTPoints, Bright, Contrast, Hue, Saturation, TempSrc, TempDest); 816ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 817ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 818ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 819ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Creates a fake NULL profile. This profile return 1 channel as always 0. 820ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Is useful only for gamut checking tricks 821ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHPROFILE CMSEXPORT cmsCreateNULLProfileTHR(cmsContext ContextID) 822ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 823ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsHPROFILE hProfile; 824ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipeline* LUT = NULL; 825ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* PostLin; 826ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsToneCurve* EmptyTab; 827ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt16Number Zero[2] = { 0, 0 }; 828ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 829ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hProfile = cmsCreateProfilePlaceholder(ContextID); 830ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!hProfile) // can't allocate 831ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 832ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 833ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetProfileVersion(hProfile, 4.3); 834ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 835ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!SetTextTags(hProfile, L"NULL profile built-in")) goto Error; 836ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 837ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 838ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 839ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetDeviceClass(hProfile, cmsSigOutputClass); 840ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetColorSpace(hProfile, cmsSigGrayData); 841ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetPCS(hProfile, cmsSigLabData); 842ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 843ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // An empty LUTs is all we need 844ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LUT = cmsPipelineAlloc(ContextID, 1, 1); 845ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (LUT == NULL) goto Error; 846ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 847ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov EmptyTab = cmsBuildTabulatedToneCurve16(ContextID, 2, Zero); 848ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PostLin = cmsStageAllocToneCurves(ContextID, 1, &EmptyTab); 849ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFreeToneCurve(EmptyTab); 850ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 851ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineInsertStage(LUT, cmsAT_END, PostLin)) 852ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 853ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 854ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hProfile, cmsSigBToA0Tag, (void*) LUT)) goto Error; 855ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, cmsD50_XYZ())) goto Error; 856ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 857ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineFree(LUT); 858ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return hProfile; 859ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 860ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovError: 861ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 862ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (LUT != NULL) 863ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineFree(LUT); 864ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 865ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (hProfile != NULL) 866ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCloseProfile(hProfile); 867ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 868ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 869ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 870ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 871ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHPROFILE CMSEXPORT cmsCreateNULLProfile(void) 872ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 873ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return cmsCreateNULLProfileTHR(NULL); 874ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 875ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 876ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 877ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 878ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovint IsPCS(cmsColorSpaceSignature ColorSpace) 879ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 880ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return (ColorSpace == cmsSigXYZData || 881ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ColorSpace == cmsSigLabData); 882ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 883ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 884ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 885ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 886ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid FixColorSpaces(cmsHPROFILE hProfile, 887ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsColorSpaceSignature ColorSpace, 888ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsColorSpaceSignature PCS, 889ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number dwFlags) 890ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 891ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (dwFlags & cmsFLAGS_GUESSDEVICECLASS) { 892ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 893ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (IsPCS(ColorSpace) && IsPCS(PCS)) { 894ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 895ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetDeviceClass(hProfile, cmsSigAbstractClass); 896ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetColorSpace(hProfile, ColorSpace); 897ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetPCS(hProfile, PCS); 898ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return; 899ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 900ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 901ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (IsPCS(ColorSpace) && !IsPCS(PCS)) { 902ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 903ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetDeviceClass(hProfile, cmsSigOutputClass); 904ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetPCS(hProfile, ColorSpace); 905ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetColorSpace(hProfile, PCS); 906ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return; 907ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 908ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 909ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (IsPCS(PCS) && !IsPCS(ColorSpace)) { 910ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 911ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetDeviceClass(hProfile, cmsSigInputClass); 912ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetColorSpace(hProfile, ColorSpace); 913ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetPCS(hProfile, PCS); 914ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return; 915ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 916ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 917ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 918ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetDeviceClass(hProfile, cmsSigLinkClass); 919ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetColorSpace(hProfile, ColorSpace); 920ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetPCS(hProfile, PCS); 921ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 922ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 923ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 924ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 925ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// This function creates a named color profile dumping all the contents of transform to a single profile 926ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// In this way, LittleCMS may be used to "group" several named color databases into a single profile. 927ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// It has, however, several minor limitations. PCS is always Lab, which is not very critic since this 928ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// is the normal PCS for named color profiles. 929ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 930ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHPROFILE CreateNamedColorDevicelink(cmsHTRANSFORM xform) 931ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 932ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform; 933ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsHPROFILE hICC = NULL; 934ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i, nColors; 935ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsNAMEDCOLORLIST *nc2 = NULL, *Original = NULL; 936ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 937ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Create an empty placeholder 938ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hICC = cmsCreateProfilePlaceholder(v->ContextID); 939ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (hICC == NULL) return NULL; 940ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 941ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Critical information 942ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetDeviceClass(hICC, cmsSigNamedColorClass); 943ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetColorSpace(hICC, v ->ExitColorSpace); 944ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetPCS(hICC, cmsSigLabData); 945ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 946ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Tag profile with information 947ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!SetTextTags(hICC, L"Named color devicelink")) goto Error; 948ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 949ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Original = cmsGetNamedColorList(xform); 950ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Original == NULL) goto Error; 951ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 952ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov nColors = cmsNamedColorCount(Original); 953ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov nc2 = cmsDupNamedColorList(Original); 954ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (nc2 == NULL) goto Error; 955ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 956ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Colorant count now depends on the output space 957ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov nc2 ->ColorantCount = cmsPipelineOutputChannels(v ->Lut); 958ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 959ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Make sure we have proper formatters 960ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsChangeBuffersFormat(xform, TYPE_NAMED_COLOR_INDEX, 961ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FLOAT_SH(0) | COLORSPACE_SH(_cmsLCMScolorSpace(v ->ExitColorSpace)) 962ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov | BYTES_SH(2) | CHANNELS_SH(cmsChannelsOf(v ->ExitColorSpace))); 963ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 964ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Apply the transfor to colorants. 965ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < nColors; i++) { 966ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsDoTransform(xform, &i, nc2 ->List[i].DeviceColorant, 1); 967ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 968ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 969ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hICC, cmsSigNamedColor2Tag, (void*) nc2)) goto Error; 970ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFreeNamedColorList(nc2); 971ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 972ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return hICC; 973ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 974ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovError: 975ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (hICC != NULL) cmsCloseProfile(hICC); 976ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 977ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 978ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 979ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 980ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// This structure holds information about which MPU can be stored on a profile based on the version 981ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 982ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovtypedef struct { 983ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsBool IsV4; // Is a V4 tag? 984ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsTagSignature RequiredTag; // Set to 0 for both types 985ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsTagTypeSignature LutType; // The LUT type 986ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int nTypes; // Number of types (up to 5) 987ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStageSignature MpeTypes[5]; // 5 is the maximum number 988ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 989ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} cmsAllowedLUT; 990ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 991ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic const cmsAllowedLUT AllowedLUTTypes[] = { 992ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 993ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { FALSE, 0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, 994ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { FALSE, 0, cmsSigLut16Type, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, 995ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { FALSE, 0, cmsSigLut16Type, 2, { cmsSigCurveSetElemType, cmsSigCLutElemType}}, 996ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { TRUE , 0, cmsSigLutAtoBType, 1, { cmsSigCurveSetElemType }}, 997ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType } }, 998ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } }, 999ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 5, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }}, 1000ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 1, { cmsSigCurveSetElemType }}, 1001ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 3, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }}, 1002ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType }}, 1003ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 5, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType }} 1004ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}; 1005ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1006ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define SIZE_OF_ALLOWED_LUT (sizeof(AllowedLUTTypes)/sizeof(cmsAllowedLUT)) 1007ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1008ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Check a single entry 1009ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 1010ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool CheckOne(const cmsAllowedLUT* Tab, const cmsPipeline* Lut) 1011ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1012ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* mpe; 1013ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int n; 1014ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1015ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (n=0, mpe = Lut ->Elements; mpe != NULL; mpe = mpe ->Next, n++) { 1016ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1017ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (n > Tab ->nTypes) return FALSE; 1018ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (cmsStageType(mpe) != Tab ->MpeTypes[n]) return FALSE; 1019ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1020ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1021ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return (n == Tab ->nTypes); 1022ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1023ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1024ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1025ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 1026ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovconst cmsAllowedLUT* FindCombination(const cmsPipeline* Lut, cmsBool IsV4, cmsTagSignature DestinationTag) 1027ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1028ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number n; 1029ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1030ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (n=0; n < SIZE_OF_ALLOWED_LUT; n++) { 1031ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1032ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const cmsAllowedLUT* Tab = AllowedLUTTypes + n; 1033ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1034ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (IsV4 ^ Tab -> IsV4) continue; 1035ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ((Tab ->RequiredTag != 0) && (Tab ->RequiredTag != DestinationTag)) continue; 1036ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1037ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (CheckOne(Tab, Lut)) return Tab; 1038ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1039ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1040ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 1041ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1042ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1043ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1044ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Does convert a transform into a device link profile 1045ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat64Number Version, cmsUInt32Number dwFlags) 1046ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1047ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsHPROFILE hProfile = NULL; 1048ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number FrmIn, FrmOut, ChansIn, ChansOut; 1049ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number ColorSpaceBitsIn, ColorSpaceBitsOut; 1050ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform; 1051ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipeline* LUT = NULL; 1052ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* mpe; 1053ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsContext ContextID = cmsGetTransformContextID(hTransform); 1054ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const cmsAllowedLUT* AllowedLUT; 1055ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsTagSignature DestinationTag; 1056ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsProfileClassSignature deviceClass; 1057ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1058ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsAssert(hTransform != NULL); 1059ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1060ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Get the first mpe to check for named color 1061ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe = cmsPipelineGetPtrToFirstStage(xform ->Lut); 1062ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1063ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Check if is a named color transform 1064ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (mpe != NULL) { 1065ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1066ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (cmsStageType(mpe) == cmsSigNamedColorElemType) { 1067ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return CreateNamedColorDevicelink(hTransform); 1068ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1069ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1070ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1071ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // First thing to do is to get a copy of the transformation 1072ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LUT = cmsPipelineDup(xform ->Lut); 1073ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (LUT == NULL) return NULL; 1074ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1075ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Time to fix the Lab2/Lab4 issue. 1076ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ((xform ->EntryColorSpace == cmsSigLabData) && (Version < 4.0)) { 1077ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1078ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocLabV2ToV4curves(ContextID))) 1079ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 1080ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1081ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1082ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // On the output side too 1083ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ((xform ->ExitColorSpace) == cmsSigLabData && (Version < 4.0)) { 1084ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1085ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocLabV4ToV2(ContextID))) 1086ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 1087ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1088ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1089ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1090ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov hProfile = cmsCreateProfilePlaceholder(ContextID); 1091ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!hProfile) goto Error; // can't allocate 1092ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1093ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetProfileVersion(hProfile, Version); 1094ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1095ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FixColorSpaces(hProfile, xform -> EntryColorSpace, xform -> ExitColorSpace, dwFlags); 1096ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1097ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Optimize the LUT and precalculate a devicelink 1098ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1099ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ChansIn = cmsChannelsOf(xform -> EntryColorSpace); 1100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ChansOut = cmsChannelsOf(xform -> ExitColorSpace); 1101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ColorSpaceBitsIn = _cmsLCMScolorSpace(xform -> EntryColorSpace); 1103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ColorSpaceBitsOut = _cmsLCMScolorSpace(xform -> ExitColorSpace); 1104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FrmIn = COLORSPACE_SH(ColorSpaceBitsIn) | CHANNELS_SH(ChansIn)|BYTES_SH(2); 1106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FrmOut = COLORSPACE_SH(ColorSpaceBitsOut) | CHANNELS_SH(ChansOut)|BYTES_SH(2); 1107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov deviceClass = cmsGetDeviceClass(hProfile); 1109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (deviceClass == cmsSigOutputClass) 1111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov DestinationTag = cmsSigBToA0Tag; 1112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 1113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov DestinationTag = cmsSigAToB0Tag; 1114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Check if the profile/version can store the result 1116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (dwFlags & cmsFLAGS_FORCE_CLUT) 1117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov AllowedLUT = NULL; 1118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 1119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag); 1120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (AllowedLUT == NULL) { 1122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Try to optimize 1124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); 1125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag); 1126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // If no way, then force CLUT that for sure can be written 1130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (AllowedLUT == NULL) { 1131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov dwFlags |= cmsFLAGS_FORCE_CLUT; 1133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); 1134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Put identity curves if needed 1136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (cmsPipelineGetPtrToFirstStage(LUT) ->Type != cmsSigCurveSetElemType) 1137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, ChansIn))) 1138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 1139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (cmsPipelineGetPtrToLastStage(LUT) ->Type != cmsSigCurveSetElemType) 1141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, ChansOut))) 1142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 1143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag); 1145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Somethings is wrong... 1148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (AllowedLUT == NULL) { 1149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 1150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (dwFlags & cmsFLAGS_8BITS_DEVICELINK) 1154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineSetSaveAs8bitsFlag(LUT, TRUE); 1155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Tag profile with information 1157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!SetTextTags(hProfile, L"devicelink")) goto Error; 1158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Store result 1160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hProfile, DestinationTag, LUT)) goto Error; 1161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (xform -> InputColorant != NULL) { 1164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hProfile, cmsSigColorantTableTag, xform->InputColorant)) goto Error; 1165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (xform -> OutputColorant != NULL) { 1168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hProfile, cmsSigColorantTableOutTag, xform->OutputColorant)) goto Error; 1169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ((deviceClass == cmsSigLinkClass) && (xform ->Sequence != NULL)) { 1172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!_cmsWriteProfileSequence(hProfile, xform ->Sequence)) goto Error; 1173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Set the white point 1176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (deviceClass == cmsSigInputClass) { 1177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, &xform ->EntryWhitePoint)) goto Error; 1178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else { 1180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, &xform ->ExitWhitePoint)) goto Error; 1181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Per 7.2.15 in spec 4.3 1185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSetHeaderRenderingIntent(hProfile, xform ->RenderingIntent); 1186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineFree(LUT); 1188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return hProfile; 1189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1190ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovError: 1191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (LUT != NULL) cmsPipelineFree(LUT); 1192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCloseProfile(hProfile); 1193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 1194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1195