On Wed, 7 Sep 2016 09:24:09 +0200, "Marti Maria" <[email protected]>
wrote:
>
> Here is the cooking recipe:
>
> - Create a CMYK to Lab transform by using your CMYK profile.
> - Measure L* of K at regular points by using this transform. i.e. for (k=0;
> k < 255; k++) transform (0, 0, 0, k) -> Lab; get L and discard a, b;
> - Normalize those point from 0..100 to 0..0xffff and create a sampled tone
> curve. This curve will implement L*(k), and should be monotonic. If not
> monotonic, the CMYK profile is not good and the game is over
> - Reverse the curve by using cmsReverseToneCurveEx. You will end with a
> curve implementing K(L*)
> - Create a constant zero tone curve by using two points set to 0.
> - Build a profile with cmsCreateLinearizationDeviceLink by using the
> reversed curve for L* and two zero curves for a* and *b. Mark this profile
> as Lab as input and 3 channels as output. Probably labeling it as output
> profile would be a good move. The profile has a weir output format (K, 0, 0)
> but this makes things a lot simpler. To do it "well" you would need to use a
> CLUT.
>
> Now you can use this profile as output in a sRGB to KXX transform. You will
> find K in the first output channel. As additional bonus you can use any
> input profile other than sRGB and any color other than R=G=B.
Hi,
Thanks for the detailed response (and excellent library)!
I tried to follow your recipe as well as I could. Could you have a
quick look over the code below? A couple of things:
- I modified a copy of cmsCreateLinearizationDeviceLinkTHR to write
a BToA tag, otherwise creating the sRGB to KXX transform would fail
with an error "Couldn't link the profiles".
- I added a final zero entry in the tone curve table, otherwise the
reversed curve for K(L*) would not be monotonic.
Peter
--------
#include <lcms2.h>
cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR_BToA(cmsContext
ContextID,
cmsColorSpaceSignature ColorSpace,
cmsToneCurve* const
TransferFunctions[])
{
cmsHPROFILE hICC;
cmsPipeline* Pipeline;
int nChannels;
hICC = cmsCreateProfilePlaceholder(ContextID);
if (!hICC)
return NULL;
cmsSetProfileVersion(hICC, 4.3);
cmsSetDeviceClass(hICC, cmsSigLinkClass);
cmsSetColorSpace(hICC, ColorSpace);
cmsSetPCS(hICC, ColorSpace);
cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL);
// Set up channels
nChannels = cmsChannelsOf(ColorSpace);
// Creates a Pipeline with prelinearization step only
Pipeline = cmsPipelineAlloc(ContextID, nChannels, nChannels);
if (Pipeline == NULL) goto Error;
// Copy tables to Pipeline
if (!cmsPipelineInsertStage(Pipeline, cmsAT_BEGIN,
cmsStageAllocToneCurves(ContextID, nChannels, TransferFunctions)))
goto Error;
// Create tags
//if (!SetTextTags(hICC, L"Linearization built-in")) goto Error; //
hack
if (!cmsWriteTag(hICC, cmsSigBToA0Tag, (void*) Pipeline)) goto Error; //
hack
//if (!SetSeqDescTag(hICC, "Linearization built-in")) goto Error; //
hack
// Pipeline is already on virtual profile
cmsPipelineFree(Pipeline);
// Ok, done
return hICC;
Error:
cmsPipelineFree(Pipeline);
if (hICC)
cmsCloseProfile(hICC);
return NULL;
}
void error_handler(cmsContext context, cmsUInt32Number error_code,
const char *text)
{
(void)context;
fprintf(stderr, "error %d: %s\n", error_code, text);
}
int main(int argc, char *argv[])
{
if (argc < 2)
return 1;
cmsContext context = cmsCreateContext(NULL, NULL);
if (!context)
return 1;
cmsSetLogErrorHandlerTHR(context, error_handler);
cmsHPROFILE cmyk_profile = cmsOpenProfileFromFileTHR(context, argv[1], "r");
if (!cmyk_profile)
return 1;
cmsHPROFILE lab_profile = cmsCreateLab2ProfileTHR(context, cmsD50_xyY());
if (!lab_profile)
return 2;
cmsHTRANSFORM cmyk_to_lab_transform = cmsCreateTransformTHR(context,
cmyk_profile, TYPE_CMYK_8,
lab_profile, TYPE_Lab_FLT,
INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_BLACKPOINTCOMPENSATION);
if (!cmyk_to_lab_transform)
return 3;
int k;
cmsUInt8Number cmyk[256 * 4];
cmsFloat32Number lab[256 * 3];
cmsFloat32Number normL[257];
for (k = 0; k < 256; k++) {
cmyk[k*4 + 0] = 0;
cmyk[k*4 + 1] = 0;
cmyk[k*4 + 2] = 0;
cmyk[k*4 + 3] = k;
}
cmsDoTransform(cmyk_to_lab_transform, cmyk, lab, 256);
for (k = 0; k < 256; k++) {
normL[k] = lab[k*3]/100.0;
}
normL[k] = 0.0; // ???
cmsToneCurve *tonecurve = cmsBuildTabulatedToneCurveFloat(context, 257,
normL);
if (!tonecurve)
return 4;
if (!cmsIsToneCurveMonotonic(tonecurve))
return 5;
cmsToneCurve *revtonecurve = cmsReverseToneCurveEx(256, tonecurve);
if (!revtonecurve)
return 6;
if (!cmsIsToneCurveMonotonic(revtonecurve))
return 66;
const cmsFloat32Number zero2[2] = {0.0, 0.0};
cmsToneCurve *zerotonecurve = cmsBuildTabulatedToneCurveFloat(context, 2,
zero2);
if (!zerotonecurve)
return 7;
cmsToneCurve *transferfuncs[3] = {
revtonecurve,
zerotonecurve,
zerotonecurve
};
cmsHPROFILE kxx_profile = cmsCreateLinearizationDeviceLinkTHR_BToA(context,
PT_Lab, transferfuncs);
if (!kxx_profile)
return 8;
cmsSetPCS(kxx_profile, cmsSigLabData);
cmsSetColorSpace(kxx_profile, cmsSigCmyData); // 3 channel output
cmsSetDeviceClass(kxx_profile, cmsSigOutputClass);
// cmsSaveProfileToFile(kxx_profile, "kxx.icc");
cmsHPROFILE srgb_profile = cmsCreate_sRGBProfileTHR(context);
if (!srgb_profile)
return 9;
cmsHTRANSFORM srgb_to_kxx_transform = cmsCreateTransformTHR(context,
srgb_profile, TYPE_RGB_8,
kxx_profile, TYPE_CMY_8, // 3 channel output
INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_BLACKPOINTCOMPENSATION);
if (!srgb_to_kxx_transform)
return 10;
int i;
cmsUInt8Number rgb[256 * 3];
cmsUInt8Number kxx[256 * 3];
for (i = 0; i < 256; i++) {
rgb[i*3 + 0] = i;
rgb[i*3 + 1] = i;
rgb[i*3 + 2] = i;
}
cmsDoTransform(srgb_to_kxx_transform, rgb, kxx, 256);
printf("// to K\n");
for (i = 0; i < 256; i++) {
printf("%3d, ", kxx[i*3]);
if (i%16 == 15)
printf("\n");
if (i == 127)
printf("\n");
}
/* for comparison */
cmsHTRANSFORM srgb_to_cmyk_transform = cmsCreateTransformTHR(context,
srgb_profile, TYPE_RGB_8,
cmyk_profile, TYPE_CMYK_8,
INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_BLACKPOINTCOMPENSATION);
if (!srgb_to_cmyk_transform)
return 11;
cmsDoTransform(srgb_to_cmyk_transform, rgb, cmyk, 256);
printf("\n// to CMYK\n");
for (i = 0; i < 256; i++) {
printf("%3d,%3d,%3d,%3d, ",
cmyk[i*4+0], cmyk[i*4+1], cmyk[i*4+2], cmyk[i*4+3]);
if (i%4 == 3)
printf("\n");
if (i == 127)
printf("\n");
}
return 0;
}
// end
------------------------------------------------------------------------------
_______________________________________________
Lcms-user mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/lcms-user