1 /*************************************************************************
2 *
3 * Apache OpenOffice - a multi-platform office productivity suite
4 *
5
6 Derived by beppec56@openoffice.org from various examples
7 in SampleICC library, the original copyright retained.
8
9 Copyright: � see below
10 */
11
12 /*
13 * The ICC Software License, Version 0.1
14 *
15 *
16 * Copyright (c) 2003-2006 The International Color Consortium. All rights
17 * reserved.
18 *
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions
21 * are met:
22 *
23 * 1. Redistributions of source code must retain the above copyright
24 * notice, this list of conditions and the following disclaimer.
25 *
26 * 2. Redistributions in binary form must reproduce the above copyright
27 * notice, this list of conditions and the following disclaimer in
28 * the documentation and/or other materials provided with the
29 * distribution.
30 *
31 * 3. The end-user documentation included with the redistribution,
32 * if any, must include the following acknowledgment:
33 * "This product includes software developed by the
34 * The International Color Consortium (www.color.org)"
35 * Alternately, this acknowledgment may appear in the software itself,
36 * if and wherever such third-party acknowledgments normally appear.
37 *
38 * 4. The names "ICC" and "The International Color Consortium" must
39 * not be used to imply that the ICC organization endorses or
40 * promotes products derived from this software without prior
41 * written permission. For written permission, please see
42 * <http://www.color.org/>.
43 *
44 *
45 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
46 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
47 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
48 * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR
49 * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
51 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
52 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
53 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
54 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
55 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56 * SUCH DAMAGE.
57 * ====================================================================
58 *
59 * This software consists of voluntary contributions made by many
60 * individuals on behalf of the The International Color Consortium.
61 *
62 *
63 * Membership in the ICC is encouraged when this software is used for
64 * commercial purposes.
65 *
66 *
67 * For more information on The International Color Consortium, please
68 * see <http://www.color.org/>.
69 *
70 *
71 */
72
73 #include <math.h>
74 #include <iostream>
75 #include <fstream>
76 using namespace std;
77
78 #include "IccUtil.h"
79 #include "IccProfile.h"
80
81 #include "Vetters.h"
82 #include "CAT.h"
83 #include "CLUT.h"
84
85 const char * const icc_file_name = "sRGB-IEC61966-2.1.icc";
86 const char * const hxx_file_name = "sRGB-IEC61966-2.1.hxx";
87 const char * const this_file_name_and_location =" * icc/source/create_sRGB_profile/create_sRGB_profile.cpp";
88
89 const char* const description = "sRGB IEC61966-2.1";
90 //const char* const devicemanufact = "IEC http://www.iec.ch"; not used, device manufactured by OOo seems funny...
91 const char* const devicemodel = "IEC 61966-2.1 Default RGB colour space - sRGB";
92 const char* const copyright = "Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements; and to You under the Apache License, Version 2.0. ";
93
94 // the creation date is fixed, corresponds to the last time this file has been changed
95 // NOTE: change this date values whenever the data inside the profile are changed.
96 const int data_last_changed_year = 2016;
97 const int data_last_changed_month = 12;
98 const int data_last_day = 24;
99 const int data_last_changed_hour = 43;
100 const int data_last_changed_minute = 00;
101
102 // the following string array it's the standard OOo header format
103 const char * const TheHeader1[] =
104 {
105 "/*************************************************************************",
106 " *",
107 " * Apache OpenOffice - a multi-platform office productivity suite",
108 " *",
109 " * sRGB-IEC61966-2.1.hxx",
110 " *",
111 " * creator: create_sRGB_profile",
112 NULL
113 };
114
115 const char * const TheHeader2[] =
116 {
117 " *",
118 " * Licensed to the Apache Software Foundation (ASF) under one",
119 " * or more contributor license agreements. See the NOTICE file",
120 " * distributed with this work for additional information",
121 " * regarding copyright ownership. The ASF licenses this file",
122 " * to you under the Apache License, Version 2.0 (the",
123 " * \"License\"); you may not use this file except in compliance",
124 " * with the License. You may obtain a copy of the License at",
125 " *",
126 " * http://www.apache.org/licenses/LICENSE-2.0",
127 " *",
128 " * Unless required by applicable law or agreed to in writing,",
129 " * software distributed under the License is distributed on an",
130 " * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY",
131 " * KIND, either express or implied. See the License for the",
132 " * specific language governing permissions and limitations",
133 " * under the License.",
134 " ************************************************************************/",
135 "",
136 "#ifndef INCLUDED_ICC_SRGB_IEC61966_2_1_H",
137 "#define INCLUDED_ICC_SRGB_IEC61966_2_1_H",
138 "",
139 "/***********************************************************************",
140 " * NOTE:",
141 " * this file is automatically generated by running the program",
142 " * obtained building:",
143 this_file_name_and_location,
144 " * contained in module icc",
145 " * modify that program if you need to change something.",
146 " ***********************************************************************/",
147 NULL // last string, a null
148 };
149
150 const char * const TheTail[] =
151 {
152 "#endif /* INCLUDED_ICC_SRGB_IEC61966_2_1_H */",
153 NULL
154 };
155
computeIEC_RGBtoXYZ(icFloatNumber indata)156 icFloatNumber computeIEC_RGBtoXYZ( icFloatNumber indata )
157 {
158 double retval = 0.0;
159 if(indata < 0.04045)
160 retval = indata/12.92;
161 else // apply the other conversion
162 retval = pow( (indata + 0.055)/1.055 , 2.4);
163
164 return retval;
165 }
166
computeIEC_XYZtoRGB(icFloatNumber indata)167 icFloatNumber computeIEC_XYZtoRGB( icFloatNumber indata )
168 {
169 icFloatNumber retval = 0.0;
170 if(indata < 0.0031308)
171 retval = indata*12.92;
172 else // apply the other conversion
173 retval = 1.055*pow( indata , icFloatNumber(1.0/2.4)) - 0.055;
174
175 // cout << retval << endl;
176 return retval;
177 }
178
dumpTag(FILE * outfile,CIccProfile * pIcc,icTagSignature sig)179 void dumpTag(FILE *outfile, CIccProfile *pIcc, icTagSignature sig)
180 {
181 CIccTag *pTag = pIcc->FindTag(sig);
182 char buf[64];
183 CIccInfo Fmt;
184
185 std::string contents;
186
187 if (pTag)
188 {
189 fprintf(outfile, "\nContents of %s tag (%s)\n", Fmt.GetTagSigName(sig), icGetSig(buf, sig));
190 fprintf(outfile,"Type: ");
191
192 if (pTag->IsArrayType()) fprintf(outfile, "Array of ");
193
194 fprintf(outfile, "%s\n", Fmt.GetTagTypeSigName(pTag->GetType()));
195 pTag->Describe(contents);
196 fwrite(contents.c_str(), contents.length(), 1, outfile);
197 }
198 else
199 fprintf(outfile, "Tag (%s) not found in profile\n", icGetSig(buf, sig));
200 }
201
dumpProfile(FILE * outfile,const char * profileName)202 void dumpProfile(FILE *outfile, const char * profileName)
203 {
204 CIccProfile *pIcc;
205 icValidateStatus nStatus;
206
207 pIcc = OpenIccProfile(profileName);
208
209 if (!pIcc)
210 printf("Unable to open '%s'\n", profileName);
211 else
212 {
213 icHeader *pHdr = &pIcc->m_Header;
214 CIccInfo Fmt;
215 char buf[64];
216
217 fprintf(outfile,"Profile: '%s'\n", profileName);
218 if(Fmt.IsProfileIDCalculated(&pHdr->profileID))
219 fprintf(outfile,"Profile ID: %s\n", Fmt.GetProfileID(&pHdr->profileID));
220 else
221 fprintf(outfile,"Profile ID: Profile ID not calculated.\n");
222 fprintf(outfile,"Size: %ld(0x%lx) bytes\n", pHdr->size, pHdr->size);
223
224 fprintf(outfile,"\nHeader\n");
225 fprintf(outfile,"------\n");
226 fprintf(outfile,"Attributes: %s\n", Fmt.GetDeviceAttrName(pHdr->attributes));
227 fprintf(outfile,"Cmm: %s\n", Fmt.GetCmmSigName((icCmmSignature)(pHdr->cmmId)));
228 fprintf(outfile,"Creation Date: %d/%d/%d %02u:%02u:%02u\n",
229 pHdr->date.month, pHdr->date.day, pHdr->date.year,
230 pHdr->date.hours, pHdr->date.minutes, pHdr->date.seconds);
231 fprintf(outfile,"Creator: %s\n", icGetSig(buf, pHdr->creator));
232 fprintf(outfile,"Data Color Space: %s\n", Fmt.GetColorSpaceSigName(pHdr->colorSpace));
233 fprintf(outfile,"Flags %s\n", Fmt.GetProfileFlagsName(pHdr->flags));
234 fprintf(outfile,"PCS Color Space: %s\n", Fmt.GetColorSpaceSigName(pHdr->pcs));
235 fprintf(outfile,"Platform: %s\n", Fmt.GetPlatformSigName(pHdr->platform));
236 fprintf(outfile,"Rendering Intent: %s\n", Fmt.GetRenderingIntentName((icRenderingIntent)(pHdr->renderingIntent)));
237 fprintf(outfile,"Type: %s\n", Fmt.GetProfileClassSigName(pHdr->deviceClass));
238 fprintf(outfile,"Version: %s\n", Fmt.GetVersionName(pHdr->version));
239 fprintf(outfile,"Illuminant: X=%.4lf, Y=%.4lf, Z=%.4lf\n",
240 icFtoD(pHdr->illuminant.X),
241 icFtoD(pHdr->illuminant.Y),
242 icFtoD(pHdr->illuminant.Z));
243
244 fprintf(outfile,"\nProfile Tags\n");
245 fprintf(outfile,"------------\n");
246
247 fprintf(outfile,"%25s ID %8s\t%8s\n", "Tag", "Offset", "Size");
248 fprintf(outfile,"%25s ------ %8s\t%8s\n", "----", "------", "----");
249
250 int n;
251 TagEntryList::iterator i;
252
253 for (n=0, i=pIcc->m_Tags->begin(); i!=pIcc->m_Tags->end(); i++, n++)
254 {
255 fprintf(outfile,"%25s %s %8ld\t%8ld\n", Fmt.GetTagSigName(i->TagInfo.sig),
256 icGetSig(buf, i->TagInfo.sig, false),
257 i->TagInfo.offset, i->TagInfo.size);
258 }
259
260 for (n=0, i=pIcc->m_Tags->begin(); i!=pIcc->m_Tags->end(); i++, n++)
261 dumpTag(outfile, pIcc, i->TagInfo.sig);
262 }
263 delete pIcc;
264 }
265
main(int argc,char * argv[])266 int main(int argc, char* argv[])
267 {
268 const char* myName = path_tail(argv[0]);
269
270 try
271 {
272 const char* const out_file_pathname = icc_file_name;
273
274 CIccProfile profile;
275 profile.InitHeader();
276
277 profile.m_Header.date.year = data_last_changed_year;
278 profile.m_Header.date.month = data_last_changed_month;
279 profile.m_Header.date.day = data_last_day;
280 profile.m_Header.date.hours = data_last_changed_hour;
281 profile.m_Header.date.minutes = data_last_changed_minute;
282 profile.m_Header.date.seconds = 0;
283
284 profile.m_Header.deviceClass = icSigDisplayClass;
285 profile.m_Header.colorSpace = icSigRgbData;
286 profile.m_Header.pcs = icSigXYZData;
287 profile.m_Header.platform = icSigUnkownPlatform;
288 profile.m_Header.attributes = static_cast<icUInt64Number>(icReflective);
289 profile.m_Header.renderingIntent = icPerceptual;
290
291 profile.m_Header.cmmId = 0x6E6F6E65; /* 'none' */
292 profile.m_Header.model = 0x73524742;//sRGB
293
294 profile.m_Header.version=icVersionNumberV2_1;
295
296 // Required tags for a three-component matrix-based display profile, as laid
297 // out by specification ICC.1:1998-09 (clause 6.3) are:
298 //
299 // copyrightTag
300 // profileDescriptionTag
301 // redMatrixColumnTag
302 // greenMatrixColumnTag
303 // blueMatrixColumnTag
304 // redTRCTag
305 // greenTRCTag
306 // blueTRCTag
307 // mediaWhitePointTag
308
309 // the other tags:
310 //
311 // technologyTag
312 // deviceModelTag
313 // deviceMfgDescTag
314 // mediaBlackPointTag
315 // viewingCondDescTag
316 // viewingConditionsTag
317 // luminanceTag
318 // measurementTag
319 //
320 // are optionals, added for completeness
321
322 // the element below are sorted in the same order as
323 // the list above, but the LUT table,
324 // embedded at the end of the profile
325
326 // copyrightTag
327 CIccTagText* copyrightTag = new CIccTagText;
328 copyrightTag->SetText(copyright);
329 profile.AttachTag(icSigCopyrightTag, copyrightTag);
330
331 // profileDescriptionTag
332 CIccTagTextDescription* descriptionTag = new CIccTagTextDescription;
333 descriptionTag->SetText(description);
334 profile.AttachTag(icSigProfileDescriptionTag, descriptionTag);
335
336 CIccTagXYZ* redMatrixColumnTag = new CIccTagXYZ;
337 //values from raccomandation of ICC for sRGB, D50 referenced characterisation data
338 //should be: 0.4361, 0.2225, 0.0139 according to application notes,
339 // the 'X' value below is the one commonly in use on a very
340 // diffused sRGB profile
341 (*redMatrixColumnTag)[0].X = icDtoF(0.4361);
342 (*redMatrixColumnTag)[0].Y = icDtoF(0.2225);
343 (*redMatrixColumnTag)[0].Z = icDtoF(0.0139);
344 profile.AttachTag(icSigRedMatrixColumnTag, redMatrixColumnTag);
345
346 CIccTagXYZ* greenMatrixColumnTag = new CIccTagXYZ;
347 //values from raccomandation of ICC for sRGB, D50 referenced characterisation data
348 (*greenMatrixColumnTag)[0].X = icDtoF(0.3851);
349 (*greenMatrixColumnTag)[0].Y = icDtoF(0.7169);
350 (*greenMatrixColumnTag)[0].Z = icDtoF(0.0971);
351 profile.AttachTag(icSigGreenMatrixColumnTag, greenMatrixColumnTag);
352
353 CIccTagXYZ* blueMatrixColumnTag = new CIccTagXYZ;
354 //values from raccomandation of ICC for sRGB, D50 referenced characterisation data
355 //should be: 0.1431, 0.0606, 0.7139 according to application notes,
356 // the 'Z' value below is the one commonly in use on a very
357 // diffused sRGB profile
358 (*blueMatrixColumnTag)[0].X = icDtoF(0.1431);
359 (*blueMatrixColumnTag)[0].Y = icDtoF(0.0606);
360 (*blueMatrixColumnTag)[0].Z = icDtoF(0.7141);
361 profile.AttachTag(icSigBlueMatrixColumnTag, blueMatrixColumnTag);
362
363 // mediaWhitePointTag
364 CIccTagXYZ* whitePointTag = new CIccTagXYZ;
365 (*whitePointTag)[0].X = icDtoF(0.9505);
366 (*whitePointTag)[0].Y = icDtoF(1.0);
367 (*whitePointTag)[0].Z = icDtoF(1.0891);
368 profile.AttachTag(icSigMediaWhitePointTag, whitePointTag);
369
370 //device signature (technologytag)
371 CIccTagSignature* deviceSign = new CIccTagSignature;
372 deviceSign->SetValue( icSigCRTDisplay );
373 profile.AttachTag( icSigTechnologyTag, deviceSign );
374
375 //device model tag
376 CIccTagTextDescription* deviceModelTag = new CIccTagTextDescription;
377 deviceModelTag->SetText("IEC 61966-2.1 Default RGB colour space - sRGB");
378 profile.AttachTag( icSigDeviceModelDescTag, deviceModelTag);
379
380 // deviceMfgDescTag
381 CIccTagTextDescription* deviceMfgTag = new CIccTagTextDescription;
382 deviceMfgTag->SetText("IEC http://www.iec.ch");
383 profile.AttachTag( icSigDeviceMfgDescTag, deviceMfgTag);
384
385 // mediaBlackPointTag
386 CIccTagXYZ* blackPointTag = new CIccTagXYZ;
387 (*blackPointTag)[0].X =
388 (*blackPointTag)[0].Y =
389 (*blackPointTag)[0].Z = icDtoF(0.0);
390 profile.AttachTag(icSigMediaBlackPointTag, blackPointTag);
391
392 // viewingCondDescTag
393 CIccTagTextDescription* viewingCondDescTag = new CIccTagTextDescription;
394 viewingCondDescTag->SetText("Reference viewing condition according to IEC 61966-2.1");
395 profile.AttachTag( icSigViewingCondDescTag, viewingCondDescTag );
396
397 // viewingConditionsTag
398 CIccTagViewingConditions* viewingConditionsTag = new CIccTagViewingConditions;
399 // Illuminant tristimulus value
400 (*viewingConditionsTag).m_XYZIllum.X = icDtoF(19.6445);
401 (*viewingConditionsTag).m_XYZIllum.Y = icDtoF(20.3718);
402 (*viewingConditionsTag).m_XYZIllum.Z = icDtoF(16.8089);
403 // surround tristimulus value
404 (*viewingConditionsTag).m_XYZSurround.X = icDtoF(3.9289);
405 (*viewingConditionsTag).m_XYZSurround.Y = icDtoF(4.0744);
406 (*viewingConditionsTag).m_XYZSurround.Z = icDtoF(3.3618);
407 (*viewingConditionsTag).m_illumType = icIlluminantD50;
408 profile.AttachTag( icSigViewingConditionsType, viewingConditionsTag );
409
410 // luminanceTag
411 CIccTagXYZ* luminanceTag = new CIccTagXYZ;
412 (*luminanceTag)[0].X = icDtoF(76.0365);
413 (*luminanceTag)[0].Y = icDtoF(80.0);
414 (*luminanceTag)[0].Z = icDtoF(87.1246);
415 profile.AttachTag(icSigLuminanceTag, luminanceTag);
416
417 // measurementTag
418 CIccTagMeasurement* measurementTag = new CIccTagMeasurement;
419 (*measurementTag).m_Data.stdObserver = icStdObs1931TwoDegrees;
420 (*measurementTag).m_Data.backing.X =
421 (*measurementTag).m_Data.backing.Y =
422 (*measurementTag).m_Data.backing.Z = icDtoF(0.0);
423 (*measurementTag).m_Data.geometry = icGeometryUnknown;
424 // the flare is 1%, but the library doesn't seem all right with this
425 // see specification ICC.1:1998-09, clause 6.5.8, table 55 fot the right
426 // format of the data value
427 (*measurementTag).m_Data.flare = static_cast< icMeasurementFlare > ( icDtoUF( 0.01 ) );//means 1%
428 (*measurementTag).m_Data.illuminant = icIlluminantD65;
429 profile.AttachTag(icSigMeasurementTag, measurementTag );
430
431 // compute the LUT curves, they are equal for all three colors
432 // so only one LUT is computed and stored
433 int N = 1024; // number of points in LUTs
434 CIccTagCurve* colorTRCTag = new CIccTagCurve(N);
435 // apply conversion from RGB to XYZ, stepping the RGB value linearly from 0 to 100%
436 // 1024 steps are computed
437 for (int i = 0; i < N; ++i)
438 (*colorTRCTag)[i] = computeIEC_RGBtoXYZ( (icFloatNumber)i/(N-1));
439
440 profile.AttachTag(icSigRedTRCTag, colorTRCTag);
441 profile.AttachTag(icSigGreenTRCTag, colorTRCTag);
442 profile.AttachTag(icSigBlueTRCTag, colorTRCTag);
443
444 //Verify things
445 string validationReport;
446 icValidateStatus validationStatus = profile.Validate(validationReport);
447
448 switch (validationStatus)
449 {
450 case icValidateOK:
451 break;
452
453 case icValidateWarning:
454 clog << "Profile validation warning" << endl
455 << validationReport;
456 break;
457
458 case icValidateNonCompliant:
459 clog << "Profile non compliancy" << endl
460 << validationReport;
461 break;
462
463 case icValidateCriticalError:
464 default:
465 clog << "Profile Error" << endl
466 << validationReport;
467 }
468
469 // Out it goes
470 CIccFileIO out;
471 out.Open(out_file_pathname, "wb+");
472 profile.Write(&out);
473 out.Close();
474
475 FILE *headerfile = fopen(hxx_file_name,"w");
476
477 //print OpenOffice standard file header
478 const char *the_string;
479
480 int idx = 0;
481
482 while((the_string = TheHeader1[idx++]) != NULL )
483 fprintf(headerfile,"%s\n",the_string);
484 // print the creation date (today)
485 // print the date of sRGB ICC profile data
486 fprintf(headerfile," * the date of last change to sRGB ICC profile data is:\n * %4d/%02d/%02d - %02d:%02d\n",
487 data_last_changed_year, data_last_changed_month,
488 data_last_day, data_last_changed_hour,data_last_changed_minute );
489
490 idx = 0;
491
492 while((the_string = TheHeader2[idx++]) != NULL )
493 fprintf(headerfile,"%s\n",the_string);
494
495 {
496 // spit out the data structure (an array of unsigned char)
497 FILE *infile;
498
499 int achar, number = 1;
500
501 infile = fopen(out_file_pathname,"rb");
502
503 fseek(infile,0,SEEK_END);
504 long int thesize= ftell(infile);
505 fseek(infile,0,SEEK_SET);
506
507 fprintf(headerfile,"\nsal_uInt8 nsRGB_ICC_profile[%d]=\n{\n ",thesize);
508
509 do
510 {
511 achar = fgetc(infile);
512 if(achar == EOF)
513 break;
514 fprintf(headerfile,"0x%02x",achar);
515 if(number % 12 == 0)
516 fprintf(headerfile,",\n ");
517 else
518 fprintf(headerfile,", ");
519 number++;
520 } while(achar != EOF );
521 fprintf(headerfile,"\n};\n\n");
522
523 fclose(infile);
524 }
525 // append the file contents, in human readable form, as comment in the header
526 // get the functions from iccDump
527
528 fprintf(headerfile,"/*****************\n\n");
529
530 fprintf(headerfile,"This ICC profile contains the following data:\n\n");
531
532 dumpProfile(headerfile, out_file_pathname );
533
534 fprintf(headerfile,"\n*****************/\n");
535 //now append the tail
536 idx = 0;
537 while((the_string = TheTail[idx++]) != NULL )
538 fprintf(headerfile,"%s\n",the_string);
539
540 fclose(headerfile);
541
542 return EXIT_SUCCESS;
543 }
544 catch (const std::exception& e)
545 {
546 cout << myName << ": error: " << e.what() << endl;
547 return EXIT_FAILURE;
548 }
549 }
550