1 //---------------------------------------------------------------------------------
2 //
3 //  Little Color Management System
4 //  Copyright (c) 1998-2017 Marti Maria Saguer
5 //
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:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
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.
23 //
24 //---------------------------------------------------------------------------------
25 //
26 
27 #include "utils.h"
28 
29 
30 int Verbose = 0;
31 
32 static char ProgramName[256] = "";
33 
FatalError(const char * frm,...)34 void FatalError(const char *frm, ...)
35 {
36     va_list args;
37 
38     va_start(args, frm);
39     fprintf(stderr, "[%s fatal error]: ", ProgramName);
40     vfprintf(stderr, frm, args);
41     fprintf(stderr, "\n");
42     va_end(args);
43 
44     exit(1);
45 }
46 
47 // Show errors to the end user (unless quiet option)
48 static
MyErrorLogHandler(cmsContext ContextID,cmsUInt32Number ErrorCode,const char * Text)49 void MyErrorLogHandler(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text)
50 {
51     if (Verbose >= 0)
52         fprintf(stderr, "[%s]: %s\n", ProgramName, Text);
53 
54     UTILS_UNUSED_PARAMETER(ErrorCode);
55     UTILS_UNUSED_PARAMETER(ContextID);
56 }
57 
58 
InitUtils(cmsContext ContextID,const char * PName)59 void InitUtils(cmsContext ContextID, const char* PName)
60 {
61       strncpy(ProgramName, PName, sizeof(ProgramName));
62       ProgramName[sizeof(ProgramName)-1] = 0;
63 
64       cmsSetLogErrorHandler(ContextID, MyErrorLogHandler);
65 }
66 
67 
68 // Virtual profiles are handled here.
OpenStockProfile(cmsContext ContextID,const char * File)69 cmsHPROFILE OpenStockProfile(cmsContext ContextID, const char* File)
70 {
71        if (!File)
72             return cmsCreate_sRGBProfile(ContextID);
73 
74        if (cmsstrcasecmp(File, "*Lab2") == 0)
75                 return cmsCreateLab2Profile(ContextID, NULL);
76 
77        if (cmsstrcasecmp(File, "*Lab4") == 0)
78                 return cmsCreateLab4Profile(ContextID, NULL);
79 
80        if (cmsstrcasecmp(File, "*Lab") == 0)
81                 return cmsCreateLab4Profile(ContextID, NULL);
82 
83        if (cmsstrcasecmp(File, "*LabD65") == 0) {
84 
85            cmsCIExyY D65xyY;
86 
87            cmsWhitePointFromTemp(ContextID,  &D65xyY, 6504);
88            return cmsCreateLab4Profile(ContextID, &D65xyY);
89        }
90 
91        if (cmsstrcasecmp(File, "*XYZ") == 0)
92                 return cmsCreateXYZProfile(ContextID);
93 
94        if (cmsstrcasecmp(File, "*Gray22") == 0) {
95 
96            cmsToneCurve* Curve = cmsBuildGamma(ContextID, 2.2);
97            cmsHPROFILE hProfile = cmsCreateGrayProfile(ContextID, cmsD50_xyY(ContextID), Curve);
98            cmsFreeToneCurve(ContextID, Curve);
99            return hProfile;
100        }
101 
102         if (cmsstrcasecmp(File, "*Gray30") == 0) {
103 
104            cmsToneCurve* Curve = cmsBuildGamma(ContextID, 3.0);
105            cmsHPROFILE hProfile = cmsCreateGrayProfile(ContextID, cmsD50_xyY(ContextID), Curve);
106            cmsFreeToneCurve(ContextID, Curve);
107            return hProfile;
108        }
109 
110        if (cmsstrcasecmp(File, "*srgb") == 0)
111                 return cmsCreate_sRGBProfile(ContextID);
112 
113        if (cmsstrcasecmp(File, "*null") == 0)
114                 return cmsCreateNULLProfile(ContextID);
115 
116 
117        if (cmsstrcasecmp(File, "*Lin2222") == 0) {
118 
119             cmsToneCurve*  Gamma = cmsBuildGamma(0, 2.2);
120             cmsToneCurve*  Gamma4[4];
121             cmsHPROFILE hProfile;
122 
123             Gamma4[0] = Gamma4[1] = Gamma4[2] = Gamma4[3] = Gamma;
124             hProfile = cmsCreateLinearizationDeviceLink(ContextID, cmsSigCmykData, Gamma4);
125             cmsFreeToneCurve(ContextID, Gamma);
126             return hProfile;
127        }
128 
129 
130         return cmsOpenProfileFromFile(ContextID, File, "r");
131 }
132 
133 // Help on available built-ins
PrintBuiltins(void)134 void PrintBuiltins(void)
135 {
136      fprintf(stderr, "\nBuilt-in profiles:\n\n");
137      fprintf(stderr, "\t*Lab2  -- D50-based v2 CIEL*a*b\n"
138                      "\t*Lab4  -- D50-based v4 CIEL*a*b\n"
139                      "\t*Lab   -- D50-based v4 CIEL*a*b\n"
140                      "\t*XYZ   -- CIE XYZ (PCS)\n"
141                      "\t*sRGB  -- sRGB color space\n"
142                      "\t*Gray22 - Monochrome of Gamma 2.2\n"
143                      "\t*Gray30 - Monochrome of Gamma 3.0\n"
144                      "\t*null   - Monochrome black for all input\n"
145                      "\t*Lin2222- CMYK linearization of gamma 2.2 on each channel\n");
146 }
147 
148 
149 // Auxiliary for printing information on profile
150 static
PrintInfo(cmsContext ContextID,cmsHPROFILE h,cmsInfoType Info)151 void PrintInfo(cmsContext ContextID, cmsHPROFILE h, cmsInfoType Info)
152 {
153     char* text;
154     int len;
155 
156     len = cmsGetProfileInfoASCII(ContextID, h, Info, "en", "US", NULL, 0);
157     if (len == 0) return;
158 
159     text = (char*) malloc(len * sizeof(char));
160     if (text == NULL) return;
161 
162     cmsGetProfileInfoASCII(ContextID, h, Info, "en", "US", text, len);
163 
164     if (strlen(text) > 0)
165         printf("%s\n", text);
166 
167     free(text);
168 }
169 
170 
171 
172 // Displays the colorant table
173 static
PrintColorantTable(cmsContext ContextID,cmsHPROFILE hInput,cmsTagSignature Sig,const char * Title)174 void PrintColorantTable(cmsContext ContextID, cmsHPROFILE hInput, cmsTagSignature Sig, const char* Title)
175 {
176     cmsNAMEDCOLORLIST* list;
177     int i, n;
178 
179     if (cmsIsTag(ContextID, hInput, Sig)) {
180 
181         printf("%s:\n", Title);
182 
183         list = (cmsNAMEDCOLORLIST*) cmsReadTag(ContextID, hInput, Sig);
184         if (list == NULL) {
185             printf("(Unavailable)\n");
186             return;
187         }
188 
189         n = cmsNamedColorCount(ContextID, list);
190         for (i=0; i < n; i++) {
191 
192             char Name[cmsMAX_PATH];
193 
194             cmsNamedColorInfo(ContextID, list, i, Name, NULL, NULL, NULL, NULL);
195             printf("\t%s\n", Name);
196         }
197 
198         printf("\n");
199     }
200 
201 }
202 
203 
PrintProfileInformation(cmsContext ContextID,cmsHPROFILE hInput)204 void PrintProfileInformation(cmsContext ContextID, cmsHPROFILE hInput)
205 {
206     if (hInput == NULL) {
207 			fprintf(stderr, "*Wrong or corrupted profile*\n");
208             return;
209     }
210 
211     PrintInfo(ContextID, hInput, cmsInfoDescription);
212     PrintInfo(ContextID, hInput, cmsInfoManufacturer);
213     PrintInfo(ContextID, hInput, cmsInfoModel);
214     PrintInfo(ContextID, hInput, cmsInfoCopyright);
215 
216     if (Verbose > 2) {
217 
218         PrintColorantTable(ContextID, hInput, cmsSigColorantTableTag,    "Input colorant table");
219         PrintColorantTable(ContextID, hInput, cmsSigColorantTableOutTag, "Input colorant out table");
220     }
221 
222     printf("\n");
223 }
224 
225 // -----------------------------------------------------------------------------
226 
227 
PrintRenderingIntents(cmsContext ContextID)228 void PrintRenderingIntents(cmsContext ContextID)
229 {
230     cmsUInt32Number Codes[200];
231     char* Descriptions[200];
232     cmsUInt32Number n, i;
233 
234     fprintf(stderr, "%ct<n> rendering intent:\n\n", SW);
235 
236     n = cmsGetSupportedIntents(ContextID, 200, Codes, Descriptions);
237 
238     for (i=0; i < n; i++) {
239         fprintf(stderr, "\t%u - %s\n", Codes[i], Descriptions[i]);
240     }
241     fprintf(stderr, "\n");
242 }
243 
244 
245 
246 // ------------------------------------------------------------------------------
247 
SaveMemoryBlock(const cmsUInt8Number * Buffer,cmsUInt32Number dwLen,const char * Filename)248 cmsBool SaveMemoryBlock(const cmsUInt8Number* Buffer, cmsUInt32Number dwLen, const char* Filename)
249 {
250     FILE* out = fopen(Filename, "wb");
251     if (out == NULL) {
252         FatalError("Cannot create '%s'", Filename);
253         return FALSE;
254     }
255 
256     if (fwrite(Buffer, 1, dwLen, out) != dwLen) {
257         FatalError("Cannot write %ld bytes to %s", dwLen, Filename);
258         return FALSE;
259     }
260 
261     if (fclose(out) != 0) {
262         FatalError("Error flushing file '%s'", Filename);
263         return FALSE;
264     }
265 
266     return TRUE;
267 }
268 
269 // ------------------------------------------------------------------------------
270 
271 // Return a pixel type on depending on the number of channels
PixelTypeFromChanCount(int ColorChannels)272 int PixelTypeFromChanCount(int ColorChannels)
273 {
274     switch (ColorChannels) {
275 
276         case 1: return PT_GRAY;
277         case 2: return PT_MCH2;
278         case 3: return PT_MCH3;
279         case 4: return PT_CMYK;
280         case 5: return PT_MCH5;
281         case 6: return PT_MCH6;
282         case 7: return PT_MCH7;
283         case 8: return PT_MCH8;
284         case 9: return PT_MCH9;
285         case 10: return PT_MCH10;
286         case 11: return PT_MCH11;
287         case 12: return PT_MCH12;
288         case 13: return PT_MCH13;
289         case 14: return PT_MCH14;
290         case 15: return PT_MCH15;
291 
292         default:
293 
294             FatalError("What a weird separation of %d channels?!?!", ColorChannels);
295             return -1;
296     }
297 }
298 
299 
300 // ------------------------------------------------------------------------------
301 
302 // Return number of channels of pixel type
ChanCountFromPixelType(int ColorChannels)303 int ChanCountFromPixelType(int ColorChannels)
304 {
305     switch (ColorChannels) {
306 
307       case PT_GRAY: return 1;
308 
309       case PT_RGB:
310       case PT_CMY:
311       case PT_Lab:
312       case PT_YUV:
313       case PT_YCbCr: return 3;
314 
315       case PT_CMYK: return 4 ;
316       case PT_MCH2: return 2 ;
317       case PT_MCH3: return 3 ;
318       case PT_MCH4: return 4 ;
319       case PT_MCH5: return 5 ;
320       case PT_MCH6: return 6 ;
321       case PT_MCH7: return 7 ;
322       case PT_MCH8: return 8 ;
323       case PT_MCH9: return 9 ;
324       case PT_MCH10: return 10;
325       case PT_MCH11: return 11;
326       case PT_MCH12: return 12;
327       case PT_MCH13: return 12;
328       case PT_MCH14: return 14;
329       case PT_MCH15: return 15;
330 
331       default:
332 
333           FatalError("Unsupported color space of %d channels", ColorChannels);
334           return -1;
335     }
336 }
337