static LPLUT Create3x3EmptyLUT(void) { LPLUT AToB0 = cmsAllocLUT(); if (AToB0 == NULL) return NULL; AToB0 -> InputChan = AToB0 -> OutputChan = 3; return AToB0; }
LPLUT LCMSEXPORT cmsDupLUT(LPLUT Orig) { LPLUT NewLUT = cmsAllocLUT(); unsigned int i; CopyMemory(NewLUT, Orig, sizeof(LUT)); for (i=0; i < Orig ->InputChan; i++) NewLUT -> L1[i] = (LPWORD) DupBlockTab((LPVOID) Orig ->L1[i], sizeof(WORD) * Orig ->In16params.nSamples); for (i=0; i < Orig ->OutputChan; i++) NewLUT -> L2[i] = (LPWORD) DupBlockTab((LPVOID) Orig ->L2[i], sizeof(WORD) * Orig ->Out16params.nSamples); NewLUT -> T = (LPWORD) DupBlockTab((LPVOID) Orig ->T, Orig -> Tsize); return NewLUT; }
cmsHPROFILE LCMSEXPORT cmsCreateLinearizationDeviceLink(icColorSpaceSignature ColorSpace, LPGAMMATABLE TransferFunctions[]) { cmsHPROFILE hICC; LPLUT Lut; hICC = _cmsCreateProfilePlaceholder(); if (!hICC) // can't allocate return NULL; cmsSetDeviceClass(hICC, icSigLinkClass); cmsSetColorSpace(hICC, ColorSpace); cmsSetPCS(hICC, ColorSpace); cmsSetRenderingIntent(hICC, INTENT_PERCEPTUAL); // Creates a LUT with prelinearization step only Lut = cmsAllocLUT(); if (Lut == NULL) return NULL; // Set up channels Lut ->InputChan = Lut ->OutputChan = _cmsChannelsOf(ColorSpace); // Copy tables to LUT cmsAllocLinearTable(Lut, TransferFunctions, 1); // Create tags cmsAddTag(hICC, icSigDeviceMfgDescTag, (LPVOID) "(lcms internal)"); cmsAddTag(hICC, icSigProfileDescriptionTag, (LPVOID) "lcms linearization device link"); cmsAddTag(hICC, icSigDeviceModelDescTag, (LPVOID) "linearization built-in"); cmsAddTag(hICC, icSigMediaWhitePointTag, (LPVOID) cmsD50_XYZ()); cmsAddTag(hICC, icSigAToB0Tag, (LPVOID) Lut); // LUT is already on virtual profile cmsFreeLUT(Lut); // Ok, done return hICC; }
cmsHPROFILE LCMSEXPORT cmsCreateNULLProfile(void) { cmsHPROFILE hProfile; LPLUT Lut; LPGAMMATABLE EmptyTab; hProfile = _cmsCreateProfilePlaceholder(); if (!hProfile) // can't allocate return NULL; cmsSetDeviceClass(hProfile, icSigOutputClass); cmsSetColorSpace(hProfile, icSigGrayData); cmsSetPCS(hProfile, icSigLabData); // An empty LUTs is all we need Lut = cmsAllocLUT(); if (Lut == NULL) { cmsCloseProfile(hProfile); return NULL; } Lut -> InputChan = 3; Lut -> OutputChan = 1; EmptyTab = cmsAllocGamma(2); EmptyTab ->GammaTable[0] = 0; EmptyTab ->GammaTable[1] = 0; cmsAllocLinearTable(Lut, &EmptyTab, 2); cmsAddTag(hProfile, icSigBToA0Tag, (LPVOID) Lut); cmsFreeLUT(Lut); cmsFreeGamma(EmptyTab); return hProfile; }
int main(int argc, char *argv[]) { LPLUT AToB0; cmsHPROFILE hProfile; fprintf(stderr, "Creating grayer.icm..."); unlink("grayer.icm"); hProfile = cmsOpenProfileFromFile("grayer.icm", "w"); AToB0 = cmsAllocLUT(); cmsAlloc3DGrid(AToB0, GRID_POINTS, 3, 3); cmsSample3DGrid(AToB0, Forward, NULL, 0); cmsAddTag(hProfile, icSigAToB0Tag, AToB0); cmsSetColorSpace(hProfile, icSigLabData); cmsSetPCS(hProfile, icSigLabData); cmsSetDeviceClass(hProfile, icSigAbstractClass); cmsAddTag(hProfile, icSigProfileDescriptionTag, "Little cms Grayifier"); cmsAddTag(hProfile, icSigCopyrightTag, "Copyright (c) Marti Maria 2003. All rights reserved."); cmsAddTag(hProfile, icSigDeviceMfgDescTag, "Little cms"); cmsAddTag(hProfile, icSigDeviceModelDescTag, "Grayifier abstract profile"); cmsCloseProfile(hProfile); cmsFreeLUT(AToB0); fprintf(stderr, "Done.\n"); return 0; }
// Simplified version of multiprofile transform creator // Flags are removed from arguments. // Gamut checking and named color profiles are not supported. // WARNING: I/O pixel formats should be specified for the created transform later by caller. cmsHTRANSFORM cmmCreateMultiprofileTransform(cmsHPROFILE hProfiles[], int nProfiles, int Intent) { DWORD inFmt, outFmt; cmsHPROFILE hTargetProfile, hProfile; icColorSpaceSignature csIn, csOut; LPLUT Grid = NULL; int nGridPoints, nInChannels, nOutChannels = 3, i = 0; _LPcmsTRANSFORM p; // Resulting transform cmsHTRANSFORM transforms[255]; // Cannot merge more than 255 profiles ZeroMemory(transforms, sizeof(transforms)); if (nProfiles > 255) { return NULL; // Too many profiles } // Check if there are any named color profiles for (i=0; i < nProfiles; i++) { if (cmsGetDeviceClass(hProfiles[i]) == icSigNamedColorClass || cmsGetDeviceClass(hProfiles[i]) == icSigLinkClass) { return NULL; // Unsupported named color and device link profiles } } // Create a placeholder transform with dummy I/O formats to place LUT in it p = (_LPcmsTRANSFORM) cmsCreateTransform(NULL, TYPE_RGB_8, NULL, TYPE_RGB_8, Intent, cmsFLAGS_NULLTRANSFORM); p->EntryColorSpace = cmsGetColorSpace(hProfiles[0]); // Gater information about first input profile hProfile = hProfiles[0]; csIn = cmsGetColorSpace(hProfile); nInChannels = _cmsChannelsOf(csIn); inFmt = BYTES_SH(2) | CHANNELS_SH(nInChannels); // Create a sequence for (i=1; i < nProfiles; i++) { // Gather output parameters hTargetProfile = hProfiles[i]; csOut = cmsGetColorSpace(hTargetProfile); nOutChannels = _cmsChannelsOf(csOut); outFmt = BYTES_SH(2)|CHANNELS_SH(nOutChannels); transforms[i-1] = cmsCreateTransform( hProfile, inFmt, hTargetProfile, outFmt, Intent, cmsFLAGS_NOTPRECALC | cmsFLAGS_NOTCACHE ); if(transforms[i-1] == NULL) CLEANUP_AND_RETURN(NULL); // Incompatible profiles? // Assign output parameters to input hProfile = hTargetProfile; csIn = csOut; nInChannels = nOutChannels; inFmt = outFmt; } p->ExitColorSpace = csOut; transforms[i] = NULL; // End marker p->InputProfile = hProfiles[0]; p->OutputProfile = hProfiles[nProfiles-1]; nGridPoints = _cmsReasonableGridpointsByColorspace(p->EntryColorSpace, 0); nInChannels = _cmsChannelsOf(cmsGetColorSpace(p->InputProfile)); // Create 3DCLUT if (! (Grid = cmsAllocLUT())) CLEANUP_AND_RETURN(NULL); Grid = cmsAlloc3DGrid(Grid, nGridPoints, nInChannels, nOutChannels); _cmsComputePrelinearizationTablesFromXFORM(transforms, nProfiles-1, Grid); // Compute device link on 16-bit basis if (!cmsSample3DGrid(Grid, cmmMultiprofileSampler, (LPVOID) transforms, Grid -> wFlags)) CLEANUP_AND_RETURN(NULL); // Put the new LUT into resulting transform p->DeviceLink = Grid; // Set transform method p->xform = cmmPrecalculatedXformImpl; // Commented out since it is not clear if it is correct or not // Sequential transforms gives same result as multiprofile with this call commented out /* if(Intent != INTENT_ABSOLUTE_COLORIMETRIC) _cmsFixWhiteMisalignment(p); */ // Don't clean LUT Grid = NULL; CLEANUP_AND_RETURN((cmsHTRANSFORM) p); }
cmsHPROFILE LCMSEXPORT f_cmsCreateBCHSWabstractProfile(int nLUTPoints, double Exposure, double Bright, double Contrast, double Hue, double Saturation, LPcmsCIExyY current_wp, LPcmsCIExyY destination_wp, LPGAMMATABLE Tables []) { cmsHPROFILE hICC; LPLUT Lut; BCHSWADJUSTS bchsw; cmsCIExyY WhitePnt; bchsw.Exposure = Exposure; bchsw.Brightness = Bright; bchsw.Contrast = Contrast; bchsw.Hue = Hue; bchsw.Saturation = Saturation; cmsxyY2XYZ(&bchsw.WPsrc, current_wp); cmsxyY2XYZ(&bchsw.WPdest, destination_wp); hICC = _cmsCreateProfilePlaceholder(); if (!hICC) // can't allocate return NULL; cmsSetDeviceClass(hICC, icSigAbstractClass); cmsSetColorSpace(hICC, icSigLabData); cmsSetPCS(hICC, icSigLabData); cmsSetRenderingIntent(hICC, INTENT_PERCEPTUAL); // Creates a LUT with 3D grid only Lut = cmsAllocLUT(); cmsAlloc3DGrid(Lut, nLUTPoints, 3, 3); if (Tables != NULL) cmsAllocLinearTable (Lut, Tables, 1); if (!cmsSample3DGrid(Lut, bchswSampler, (LPVOID) &bchsw, 0)) { // Shouldn't reach here cmsFreeLUT(Lut); cmsCloseProfile(hICC); return NULL; } // Create tags cmsAddTag(hICC, icSigDeviceMfgDescTag, (LPVOID) "(f-spot internal)"); cmsAddTag(hICC, icSigProfileDescriptionTag, (LPVOID) "f-spot BCHSW abstract profile"); cmsAddTag(hICC, icSigDeviceModelDescTag, (LPVOID) "BCHSW built-in"); cmsAddTag(hICC, icSigMediaWhitePointTag, (LPVOID) cmsD50_XYZ()); cmsAddTag(hICC, icSigAToB0Tag, (LPVOID) Lut); // LUT is already on virtual profile cmsFreeLUT(Lut); // Ok, done return hICC; }
cmsHPROFILE LCMSEXPORT cmsCreateInkLimitingDeviceLink(icColorSpaceSignature ColorSpace, double Limit) { cmsHPROFILE hICC; LPLUT Lut; if (ColorSpace != icSigCmykData) { cmsSignalError(LCMS_ERRC_ABORTED, "InkLimiting: Only CMYK currently supported"); return NULL; } if (Limit < 0.0 || Limit > 400) { cmsSignalError(LCMS_ERRC_WARNING, "InkLimiting: Limit should be between 0..400"); if (Limit < 0) Limit = 0; if (Limit > 400) Limit = 400; } hICC = _cmsCreateProfilePlaceholder(); if (!hICC) // can't allocate return NULL; cmsSetDeviceClass(hICC, icSigLinkClass); cmsSetColorSpace(hICC, ColorSpace); cmsSetPCS(hICC, ColorSpace); cmsSetRenderingIntent(hICC, INTENT_PERCEPTUAL); // Creates a LUT with 3D grid only Lut = cmsAllocLUT(); if (Lut == NULL) { cmsCloseProfile(hICC); return NULL; } cmsAlloc3DGrid(Lut, 17, _cmsChannelsOf(ColorSpace), _cmsChannelsOf(ColorSpace)); if (!cmsSample3DGrid(Lut, InkLimitingSampler, (LPVOID) &Limit, 0)) { // Shouldn't reach here cmsFreeLUT(Lut); cmsCloseProfile(hICC); return NULL; } // Create tags cmsAddTag(hICC, icSigDeviceMfgDescTag, (LPVOID) "(lcms internal)"); cmsAddTag(hICC, icSigProfileDescriptionTag, (LPVOID) "lcms ink limiting device link"); cmsAddTag(hICC, icSigDeviceModelDescTag, (LPVOID) "ink limiting built-in"); cmsAddTag(hICC, icSigMediaWhitePointTag, (LPVOID) cmsD50_XYZ()); cmsAddTag(hICC, icSigAToB0Tag, (LPVOID) Lut); // LUT is already on virtual profile cmsFreeLUT(Lut); // Ok, done return hICC; }
LPLUT _cmsComputeSoftProofLUT(cmsHPROFILE hProfile, int nIntent) { cmsHPROFILE hLab; LPLUT SoftProof; DWORD dwFormat; GAMUTCHAIN Chain; int nErrState; LPGAMMATABLE Trans[3]; // LUTs are never abs. colorimetric, is the transform who // is responsible of generating white point displacement if (nIntent == INTENT_ABSOLUTE_COLORIMETRIC) nIntent = INTENT_RELATIVE_COLORIMETRIC; ZeroMemory(&Chain, sizeof(GAMUTCHAIN)); hLab = cmsCreateLabProfile(NULL); // ONLY 4 channels dwFormat = (CHANNELS_SH(4)|BYTES_SH(2)); // Safeguard against early abortion nErrState = cmsErrorAction(LCMS_ERROR_IGNORE); // Does create the first step Chain.hForward = cmsCreateTransform(hLab, TYPE_Lab_16, hProfile, dwFormat, nIntent, cmsFLAGS_NOTPRECALC); // Does create the last step Chain.hReverse = cmsCreateTransform(hProfile, dwFormat, hLab, TYPE_Lab_16, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOTPRECALC); // Restores error handler previous state cmsErrorAction(nErrState); // All ok? if (Chain.hForward && Chain.hReverse) { // This is Lab -> Lab, so 33 point should hold anything SoftProof = cmsAllocLUT(); SoftProof = cmsAlloc3DGrid(SoftProof, 33, 3, 3); CreateLabPrelinearization(Trans); cmsAllocLinearTable(SoftProof, Trans, 1); cmsFreeGammaTriple(Trans); cmsSample3DGrid(SoftProof, SoftProofSampler, (LPVOID) &Chain, SoftProof->wFlags); } else SoftProof = NULL; // Didn't work... // Free all needed stuff. if (Chain.hForward) cmsDeleteTransform(Chain.hForward); if (Chain.hReverse) cmsDeleteTransform(Chain.hReverse); cmsCloseProfile(hLab); return SoftProof; }
static LPLUT ComputeGamutWithInput(cmsHPROFILE hInput, cmsHPROFILE hProfile, int Intent) { cmsHPROFILE hLab; LPLUT Gamut; DWORD dwFormat; GAMUTCHAIN Chain; int nErrState, nChannels, nGridpoints; LPGAMMATABLE Trans[3]; icColorSpaceSignature ColorSpace; ZeroMemory(&Chain, sizeof(GAMUTCHAIN)); hLab = cmsCreateLabProfile(NULL); // Safeguard against early abortion nErrState = cmsErrorAction(LCMS_ERROR_IGNORE); // The figure of merit. On matrix-shaper profiles, should be almost zero as // the conversion is pretty exact. On LUT based profiles, different resolutions // of input and output CLUT may result in differences. if (!cmsIsIntentSupported(hProfile, Intent, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(hProfile, Intent, LCMS_USED_AS_OUTPUT)) Chain.Thereshold = 1.0; else Chain.Thereshold = ERR_THERESHOLD; ColorSpace = cmsGetColorSpace(hProfile); // If input profile specified, create a transform from such profile to Lab if (hInput != NULL) { nChannels = _cmsChannelsOf(ColorSpace); nGridpoints = _cmsReasonableGridpointsByColorspace(ColorSpace, cmsFLAGS_HIGHRESPRECALC); dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2)); Chain.hInput = cmsCreateTransform(hInput, dwFormat, hLab, TYPE_Lab_16, Intent, cmsFLAGS_NOTPRECALC); } else { // Input transform=NULL (Lab) Used to compute the gamut tag // This table will take 53 points to give some accurancy, // 53 * 53 * 53 * 2 = 291K nChannels = 3; // For Lab nGridpoints = 53; Chain.hInput = NULL; dwFormat = (CHANNELS_SH(_cmsChannelsOf(ColorSpace))|BYTES_SH(2)); } // Does create the forward step Chain.hForward = cmsCreateTransform(hLab, TYPE_Lab_16, hProfile, dwFormat, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOTPRECALC); // Does create the backwards step Chain.hReverse = cmsCreateTransform(hProfile, dwFormat, hLab, TYPE_Lab_16, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOTPRECALC); // Restores error handler previous state cmsErrorAction(nErrState); // All ok? if (Chain.hForward && Chain.hReverse) { // Go on, try to compute gamut LUT from PCS. // This consist on a single channel containing // dE when doing a transform back and forth on // the colorimetric intent. Gamut = cmsAllocLUT(); Gamut = cmsAlloc3DGrid(Gamut, nGridpoints, nChannels, 1); // If no input, then this is a gamut tag operated by Lab, // so include pertinent prelinearization if (hInput == NULL) { CreateLabPrelinearization(Trans); cmsAllocLinearTable(Gamut, Trans, 1); cmsFreeGammaTriple(Trans); } cmsSample3DGrid(Gamut, GamutSampler, (LPVOID) &Chain, Gamut ->wFlags); } else Gamut = NULL; // Didn't work... // Free all needed stuff. if (Chain.hInput) cmsDeleteTransform(Chain.hInput); if (Chain.hForward) cmsDeleteTransform(Chain.hForward); if (Chain.hReverse) cmsDeleteTransform(Chain.hReverse); cmsCloseProfile(hLab); // And return computed hull return Gamut; }
static BOOL CreateLUTS(LPMONITORPROFILERDATA sys, LPLUT* A2B, LPLUT* B2A) { LPLUT AToB0 = cmsAllocLUT(); LPLUT BToA0 = cmsAllocLUT(); LPGAMMATABLE LabG; cmsCIExyY xyY; cmsAlloc3DGrid(AToB0, sys->hdr.CLUTPoints, 3, 3); cmsAlloc3DGrid(BToA0, sys->hdr.CLUTPoints, 3, 3); /* cmsAllocLinearTable(AToB0, sys -> Prelinearization, 1); */ sys->ReverseTables[0] = cmsReverseGamma(4096, sys ->Prelinearization[0]); sys->ReverseTables[1] = cmsReverseGamma(4096, sys ->Prelinearization[1]); sys->ReverseTables[2] = cmsReverseGamma(4096, sys ->Prelinearization[2]); /* Prelinearization */ LabG = cmsBuildGamma(4096, 3.0); sys -> PreLab[0] = cmsJoinGammaEx(LabG, sys ->Prelinearization[0], 4096); sys -> PreLab[1] = cmsJoinGammaEx(LabG, sys ->Prelinearization[1], 4096); sys -> PreLab[2] = cmsJoinGammaEx(LabG, sys ->Prelinearization[2], 4096); sys -> PreLabRev[0] = cmsJoinGammaEx(sys ->Prelinearization[0], LabG, 4096); sys -> PreLabRev[1] = cmsJoinGammaEx(sys ->Prelinearization[1], LabG, 4096); sys -> PreLabRev[2] = cmsJoinGammaEx(sys ->Prelinearization[2], LabG, 4096); cmsFreeGamma(LabG); cmsAllocLinearTable(AToB0, sys->PreLabRev, 1); cmsAllocLinearTable(BToA0, sys->PreLab, 2); /* Set CIECAM97s parameters */ sys -> hdr.device.whitePoint.X = sys -> hdr.WhitePoint.X * 100.; sys -> hdr.device.whitePoint.Y = sys -> hdr.WhitePoint.Y * 100.; sys -> hdr.device.whitePoint.Z = sys -> hdr.WhitePoint.Z * 100.; /* Normalize White point for CIECAM97s model */ cmsXYZ2xyY(&xyY, &sys -> hdr.device.whitePoint); xyY.Y = 100.; cmsxyY2XYZ(&sys -> hdr.device.whitePoint, &xyY); sys->hdr.hDevice = cmsCIECAM97sInit(&sys->hdr.device); sys->hdr.hPCS = cmsCIECAM97sInit(&sys->hdr.PCS); cmsSample3DGrid(AToB0, RegressionSamplerA2B, sys, 0); cmsSample3DGrid(BToA0, RegressionSamplerB2A, sys, 0); cmsCIECAM97sDone(sys->hdr.hDevice); cmsCIECAM97sDone(sys->hdr.hPCS); cmsAddTag(sys->hdr.hProfile, icSigAToB0Tag, AToB0); cmsAddTag(sys->hdr.hProfile, icSigBToA0Tag, BToA0); /* This is the 0xff00 trick to map white at lattice point */ BToA0 ->Matrix.v[0].n[0] = DOUBLE_TO_FIXED((65535.0 / 65280.0)); *A2B = AToB0; *B2A = BToA0; cmsFreeGammaTriple(sys->ReverseTables); cmsFreeGammaTriple(sys->PreLab); cmsFreeGammaTriple(sys->PreLabRev); return true; }
int main(int argc, char *argv[]) { LPLUT AToB0, BToA0; LPGAMMATABLE PreLinear[3]; LPGAMMATABLE Lin; CARGO Cargo; cmsHPROFILE hProfile; cmsCIEXYZ wp; fprintf(stderr, "Creating lcmscmy.icm..."); wp.X = 55.6549; wp.Y = 59.0485; wp.Z = 72.5494; cmsXYZ2xyY(&Cus, &wp); InitCargo(&Cargo); hProfile = cmsCreateLabProfile(&Cus); // Create linearization Lin = CreateLinear(); PreLinear[0] = Lin; PreLinear[1] = Lin; PreLinear[2] = Lin; AToB0 = cmsAllocLUT(); BToA0 = cmsAllocLUT(); cmsAlloc3DGrid(AToB0, 33, 3, 3); cmsAlloc3DGrid(BToA0, 33, 3, 3); cmsSample3DGrid(AToB0, Reverse, &Cargo, 0); cmsSample3DGrid(BToA0, Forward, &Cargo, 0); cmsAllocLinearTable(AToB0, PreLinear, 1); cmsAllocLinearTable(BToA0, PreLinear, 2); cmsAddTag(hProfile, icSigAToB0Tag, AToB0); cmsAddTag(hProfile, icSigBToA0Tag, BToA0); cmsSetColorSpace(hProfile, icSigCmyData); cmsAddTag(hProfile, icSigProfileDescriptionTag, "Little cms CMY mixing"); cmsAddTag(hProfile, icSigCopyrightTag, "Copyright (c) Marti Maria, 2002. All rights reserved."); cmsAddTag(hProfile, icSigDeviceMfgDescTag, "Little cms"); cmsAddTag(hProfile, icSigDeviceModelDescTag, "CMY mixing"); _cmsSaveProfile(hProfile, "lcmscmy.icm"); cmsFreeGamma(Lin); cmsFreeLUT(AToB0); cmsFreeLUT(BToA0); cmsCloseProfile(hProfile); FreeCargo(&Cargo); fprintf(stderr, "Done.\n"); return 0; }