1 //---------------------------------------------------------------------------------
3 // Little Color Management System
4 // Copyright (c) 1998-2011 Marti Maria Saguer
6 // Permission is hereby granted, free of charge, to any person obtaining
7 // a copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the Software
11 // is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
18 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 //---------------------------------------------------------------------------------
28 // ---------------------------------------------------------------------------------
30 static char* Description
= "Devicelink profile";
31 static char* Copyright
= "No copyright, use freely";
32 static int Intent
= INTENT_PERCEPTUAL
;
33 static char* cOutProf
= "devicelink.icc";
34 static int PrecalcMode
= 1;
35 static int NumOfGridPoints
= 0;
37 static cmsFloat64Number ObserverAdaptationState
= 1.0; // According ICC 4.2 this is the default
39 static cmsBool BlackPointCompensation
= FALSE
;
41 static cmsFloat64Number InkLimit
= 400;
42 static cmsBool lUse8bits
= FALSE
;
43 static cmsBool TagResult
= FALSE
;
44 static cmsBool KeepLinearization
= FALSE
;
45 static cmsFloat64Number Version
= 4.3;
57 fprintf(stderr
, "\nlinkicc: Links profiles into a single devicelink.\n");
59 fprintf(stderr
, "\n");
60 fprintf(stderr
, "usage: linkicc [flags] <profiles>\n\n");
61 fprintf(stderr
, "flags:\n\n");
62 fprintf(stderr
, "%co<profile> - Output devicelink profile. [defaults to 'devicelink.icc']\n", SW
);
64 PrintRenderingIntents();
66 fprintf(stderr
, "%cc<0,1,2> - Precision (0=LowRes, 1=Normal, 2=Hi-res) [defaults to 1]\n", SW
);
67 fprintf(stderr
, "%cn<gridpoints> - Alternate way to set precision, number of CLUT points\n", SW
);
68 fprintf(stderr
, "%cd<description> - description text (quotes can be used)\n", SW
);
69 fprintf(stderr
, "%cy<copyright> - copyright notice (quotes can be used)\n", SW
);
71 fprintf(stderr
, "\n%ck<0..400> - Ink-limiting in %% (CMYK only)\n", SW
);
72 fprintf(stderr
, "%c8 - Creates 8-bit devicelink\n", SW
);
73 fprintf(stderr
, "%cx - Creatively, guess deviceclass of resulting profile.\n", SW
);
74 fprintf(stderr
, "%cb - Black point compensation\n", SW
);
75 fprintf(stderr
, "%ca<0..1> - Observer adaptation state (abs.col. only)\n\n", SW
);
76 fprintf(stderr
, "%cl - Use linearization curves (may affect accuracy)\n", SW
);
77 fprintf(stderr
, "%cr<v.r> - Profile version. (CAUTION: may change the profile implementation)\n", SW
);
78 fprintf(stderr
, "\n");
79 fprintf(stderr
, "Colorspaces must be paired except Lab/XYZ, that can be interchanged.\n\n");
81 fprintf(stderr
, "%ch<0,1,2,3> - More help\n", SW
);
90 fprintf(stderr
, "\nExamples:\n\n"
91 "To create 'devicelink.icm' from a.icc to b.icc:\n"
92 "\tlinkicc a.icc b.icc\n\n"
93 "To create 'out.icc' from sRGB to cmyk.icc:\n"
94 "\tlinkicc -o out.icc *sRGB cmyk.icc\n\n"
95 "To create a sRGB input profile working in Lab:\n"
96 "\tlinkicc -x -o sRGBLab.icc *sRGB *Lab\n\n"
97 "To create a XYZ -> sRGB output profile:\n"
98 "\tlinkicc -x -o sRGBLab.icc *XYZ *sRGB\n\n"
99 "To create a abstract profile doing softproof for cmyk.icc:\n"
100 "\tlinkicc -t1 -x -o softproof.icc *Lab cmyk.icc cmyk.icc *Lab\n\n"
101 "To create a 'grayer' sRGB input profile:\n"
102 "\tlinkicc -x -o grayer.icc *sRGB gray.icc gray.icc *Lab\n\n"
103 "To embed ink limiting into a cmyk output profile:\n"
104 "\tlinkicc -x -o cmyklimited.icc -k 250 cmyk.icc *Lab\n\n");
109 fprintf(stderr
, "This program is intended to be a demo of the little cms\n"
110 "engine. Both lcms and this program are freeware. You can\n"
111 "obtain both in source code at http://www.littlecms.com\n"
112 "For suggestions, comments, bug reports etc. send mail to\n"
113 "info@littlecms.com\n\n");
121 void HandleSwitches(int argc
, char *argv
[])
125 while ((s
= xgetopt(argc
,argv
,"a:A:BbC:c:D:d:h:H:k:K:lLn:N:O:o:r:R:T:t:V:v:xX8y:Y:")) != EOF
) {
132 ObserverAdaptationState
= atof(xoptarg
);
133 if (ObserverAdaptationState
< 0 ||
134 ObserverAdaptationState
> 1.0)
135 FatalError("Adaptation state should be 0..1");
140 BlackPointCompensation
= TRUE
;
145 PrecalcMode
= atoi(xoptarg
);
146 if (PrecalcMode
< 0 || PrecalcMode
> 2) {
147 FatalError("Unknown precalc mode '%d'", PrecalcMode
);
153 // Doing that is correct and safe: Description points to memory allocated in the command line.
154 // same for Copyright and output devicelink.
155 Description
= xoptarg
;
165 InkLimit
= atof(xoptarg
);
166 if (InkLimit
< 0.0 || InkLimit
> 400.0) {
167 FatalError("Ink limit must be 0%%..400%%");
173 case 'L': KeepLinearization
= TRUE
;
178 if (PrecalcMode
!= 1) {
179 FatalError("Precalc mode already specified");
181 NumOfGridPoints
= atoi(xoptarg
);
192 Version
= atof(xoptarg
);
193 if (Version
< 2.0 || Version
> 4.3) {
194 fprintf(stderr
, "WARNING: lcms was not aware of this version, tag types may be wrong!\n");
200 Intent
= atoi(xoptarg
); // Will be validated latter on
205 Verbose
= atoi(xoptarg
);
206 if (Verbose
< 0 || Verbose
> 3) {
207 FatalError("Unknown verbosity level '%d'", Verbose
);
225 case 'X': TagResult
= TRUE
;
232 FatalError("Unknown option - run without args to see valid ones.\n");
237 // Set the copyright and description
239 cmsBool
SetTextTags(cmsHPROFILE hProfile
)
241 cmsMLU
*DescriptionMLU
, *CopyrightMLU
;
243 cmsContext ContextID
= cmsGetProfileContextID(hProfile
);
245 DescriptionMLU
= cmsMLUalloc(ContextID
, 1);
246 CopyrightMLU
= cmsMLUalloc(ContextID
, 1);
248 if (DescriptionMLU
== NULL
|| CopyrightMLU
== NULL
) goto Error
;
250 if (!cmsMLUsetASCII(DescriptionMLU
, "en", "US", Description
)) goto Error
;
251 if (!cmsMLUsetASCII(CopyrightMLU
, "en", "US", Copyright
)) goto Error
;
253 if (!cmsWriteTag(hProfile
, cmsSigProfileDescriptionTag
, DescriptionMLU
)) goto Error
;
254 if (!cmsWriteTag(hProfile
, cmsSigCopyrightTag
, CopyrightMLU
)) goto Error
;
261 cmsMLUfree(DescriptionMLU
);
263 cmsMLUfree(CopyrightMLU
);
269 int main(int argc
, char *argv
[])
272 cmsHPROFILE Profiles
[257];
273 cmsHPROFILE hProfile
;
274 cmsUInt32Number dwFlags
;
275 cmsHTRANSFORM hTransform
= NULL
;
278 fprintf(stderr
, "little cms ICC device link generator - v2.2 [LittleCMS %2.2f]\n", LCMS_VERSION
/ 1000.0);
282 InitUtils("linkicc");
286 HandleSwitches(argc
, argv
);
288 // How many profiles to link?
289 nargs
= (argc
- xoptind
);
294 FatalError("Holy profile! what are you trying to do with so many profiles!?");
299 memset(Profiles
, 0, sizeof(Profiles
));
300 for (i
=0; i
< nargs
; i
++) {
302 Profiles
[i
] = OpenStockProfile(0, argv
[i
+ xoptind
]);
303 if (Profiles
[i
] == NULL
) goto Cleanup
;
306 PrintProfileInformation(Profiles
[i
]);
311 if (InkLimit
!= 400.0) {
312 cmsColorSpaceSignature EndingColorSpace
= cmsGetColorSpace(Profiles
[nargs
-1]);
313 Profiles
[nargs
++] = cmsCreateInkLimitingDeviceLink(EndingColorSpace
, InkLimit
);
317 dwFlags
= cmsFLAGS_KEEP_SEQUENCE
;
318 switch (PrecalcMode
) {
320 case 0: dwFlags
|= cmsFLAGS_LOWRESPRECALC
; break;
321 case 2: dwFlags
|= cmsFLAGS_HIGHRESPRECALC
; break;
323 if (NumOfGridPoints
> 0)
324 dwFlags
|= cmsFLAGS_GRIDPOINTS(NumOfGridPoints
);
329 FatalError("Unknown precalculation mode '%d'", PrecalcMode
);
334 if (BlackPointCompensation
)
335 dwFlags
|= cmsFLAGS_BLACKPOINTCOMPENSATION
;
338 dwFlags
|= cmsFLAGS_GUESSDEVICECLASS
;
340 if (KeepLinearization
)
341 dwFlags
|= cmsFLAGS_CLUT_PRE_LINEARIZATION
|cmsFLAGS_CLUT_POST_LINEARIZATION
;
343 if (lUse8bits
) dwFlags
|= cmsFLAGS_8BITS_DEVICELINK
;
345 cmsSetAdaptationState(ObserverAdaptationState
);
347 // Create the color transform. Specify 0 for the format is safe as the transform
348 // is intended to be used only for the devicelink.
349 hTransform
= cmsCreateMultiprofileTransform(Profiles
, nargs
, 0, 0, Intent
, dwFlags
|cmsFLAGS_NOOPTIMIZE
);
350 if (hTransform
== NULL
) {
351 FatalError("Transform creation failed");
355 hProfile
= cmsTransform2DeviceLink(hTransform
, Version
, dwFlags
);
356 if (hProfile
== NULL
) {
357 FatalError("Devicelink creation failed");
361 SetTextTags(hProfile
);
362 cmsSetHeaderRenderingIntent(hProfile
, Intent
);
364 if (cmsSaveProfileToFile(hProfile
, cOutProf
)) {
367 fprintf(stderr
, "Ok");
370 FatalError("Error saving file!");
372 cmsCloseProfile(hProfile
);
377 if (hTransform
!= NULL
) cmsDeleteTransform(hTransform
);
378 for (i
=0; i
< nargs
; i
++) {
380 if (Profiles
[i
] != NULL
) cmsCloseProfile(Profiles
[i
]);