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