1 /************************************************************************* 2 * 3 * OpenOffice.org - 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 = "The Contents of this file are made available subject to the terms of GNU Lesser General Public License version 3"; 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 = 2007; 97 const int data_last_changed_month = 12; 98 const int data_last_day = 12; 99 const int data_last_changed_hour = 18; 100 const int data_last_changed_minute = 32; 101 102 // the following string array it's the standard OOo header format 103 const char * const TheHeader1[] = 104 { 105 "/*************************************************************************", 106 " *", 107 " * OpenOffice.org - 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 " * This file is part of OpenOffice.org.", 119 " *", 120 " * OpenOffice.org is free software: you can redistribute it and/or modify", 121 " * it under the terms of the GNU Lesser General Public License version 3", 122 " * only, as published by the Free Software Foundation.", 123 " *", 124 " * OpenOffice.org is distributed in the hope that it will be useful,", 125 " * but WITHOUT ANY WARRANTY; without even the implied warranty of", 126 " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", 127 " * GNU Lesser General Public License version 3 for more details", 128 " * (a copy is included in the LICENSE file that accompanied this code).", 129 " *", 130 " * You should have received a copy of the GNU Lesser General Public License", 131 " * version 3 along with OpenOffice.org. If not, see", 132 " * <http://www.openoffice.org/license.html>", 133 " * for a copy of the LGPLv3 License.", 134 " *", 135 " ************************************************************************/", 136 "", 137 "#ifndef INCLUDED_ICC_SRGB_IEC61966_2_1_H", 138 "#define INCLUDED_ICC_SRGB_IEC61966_2_1_H", 139 "", 140 "/***********************************************************************", 141 " * NOTE:", 142 " * this file is automatically generated by running the program", 143 " * obtained building:", 144 this_file_name_and_location, 145 " * contained in module icc", 146 " * modify that program if you need to change something.", 147 " ***********************************************************************/", 148 NULL // last string, a null 149 }; 150 151 const char * const TheTail[] = 152 { 153 "#endif /* INCLUDED_ICC_SRGB_IEC61966_2_1_H */", 154 NULL 155 }; 156 157 icFloatNumber computeIEC_RGBtoXYZ( icFloatNumber indata ) 158 { 159 double retval = 0.0; 160 if(indata < 0.04045) 161 retval = indata/12.92; 162 else // apply the other conversion 163 retval = pow( (indata + 0.055)/1.055 , 2.4); 164 165 return retval; 166 } 167 168 icFloatNumber computeIEC_XYZtoRGB( icFloatNumber indata ) 169 { 170 icFloatNumber retval = 0.0; 171 if(indata < 0.0031308) 172 retval = indata*12.92; 173 else // apply the other conversion 174 retval = 1.055*pow( indata , icFloatNumber(1.0/2.4)) - 0.055; 175 176 // cout << retval << endl; 177 return retval; 178 } 179 180 void dumpTag(FILE *outfile, CIccProfile *pIcc, icTagSignature sig) 181 { 182 CIccTag *pTag = pIcc->FindTag(sig); 183 char buf[64]; 184 CIccInfo Fmt; 185 186 std::string contents; 187 188 if (pTag) 189 { 190 fprintf(outfile, "\nContents of %s tag (%s)\n", Fmt.GetTagSigName(sig), icGetSig(buf, sig)); 191 fprintf(outfile,"Type: "); 192 193 if (pTag->IsArrayType()) fprintf(outfile, "Array of "); 194 195 fprintf(outfile, "%s\n", Fmt.GetTagTypeSigName(pTag->GetType())); 196 pTag->Describe(contents); 197 fwrite(contents.c_str(), contents.length(), 1, outfile); 198 } 199 else 200 fprintf(outfile, "Tag (%s) not found in profile\n", icGetSig(buf, sig)); 201 } 202 203 void dumpProfile(FILE *outfile, const char * profileName) 204 { 205 CIccProfile *pIcc; 206 std::string sReport; 207 icValidateStatus nStatus; 208 209 pIcc = OpenIccProfile(profileName); 210 211 if (!pIcc) 212 printf("Unable to open '%s'\n", profileName); 213 else 214 { 215 icHeader *pHdr = &pIcc->m_Header; 216 CIccInfo Fmt; 217 char buf[64]; 218 219 fprintf(outfile,"Profile: '%s'\n", profileName); 220 if(Fmt.IsProfileIDCalculated(&pHdr->profileID)) 221 fprintf(outfile,"Profile ID: %s\n", Fmt.GetProfileID(&pHdr->profileID)); 222 else 223 fprintf(outfile,"Profile ID: Profile ID not calculated.\n"); 224 fprintf(outfile,"Size: %ld(0x%lx) bytes\n", pHdr->size, pHdr->size); 225 226 fprintf(outfile,"\nHeader\n"); 227 fprintf(outfile,"------\n"); 228 fprintf(outfile,"Attributes: %s\n", Fmt.GetDeviceAttrName(pHdr->attributes)); 229 fprintf(outfile,"Cmm: %s\n", Fmt.GetCmmSigName((icCmmSignature)(pHdr->cmmId))); 230 fprintf(outfile,"Creation Date: %d/%d/%d %02u:%02u:%02u\n", 231 pHdr->date.month, pHdr->date.day, pHdr->date.year, 232 pHdr->date.hours, pHdr->date.minutes, pHdr->date.seconds); 233 fprintf(outfile,"Creator: %s\n", icGetSig(buf, pHdr->creator)); 234 fprintf(outfile,"Data Color Space: %s\n", Fmt.GetColorSpaceSigName(pHdr->colorSpace)); 235 fprintf(outfile,"Flags %s\n", Fmt.GetProfileFlagsName(pHdr->flags)); 236 fprintf(outfile,"PCS Color Space: %s\n", Fmt.GetColorSpaceSigName(pHdr->pcs)); 237 fprintf(outfile,"Platform: %s\n", Fmt.GetPlatformSigName(pHdr->platform)); 238 fprintf(outfile,"Rendering Intent: %s\n", Fmt.GetRenderingIntentName((icRenderingIntent)(pHdr->renderingIntent))); 239 fprintf(outfile,"Type: %s\n", Fmt.GetProfileClassSigName(pHdr->deviceClass)); 240 fprintf(outfile,"Version: %s\n", Fmt.GetVersionName(pHdr->version)); 241 fprintf(outfile,"Illuminant: X=%.4lf, Y=%.4lf, Z=%.4lf\n", 242 icFtoD(pHdr->illuminant.X), 243 icFtoD(pHdr->illuminant.Y), 244 icFtoD(pHdr->illuminant.Z)); 245 246 fprintf(outfile,"\nProfile Tags\n"); 247 fprintf(outfile,"------------\n"); 248 249 fprintf(outfile,"%25s ID %8s\t%8s\n", "Tag", "Offset", "Size"); 250 fprintf(outfile,"%25s ------ %8s\t%8s\n", "----", "------", "----"); 251 252 int n; 253 TagEntryList::iterator i; 254 255 for (n=0, i=pIcc->m_Tags->begin(); i!=pIcc->m_Tags->end(); i++, n++) 256 { 257 fprintf(outfile,"%25s %s %8ld\t%8ld\n", Fmt.GetTagSigName(i->TagInfo.sig), 258 icGetSig(buf, i->TagInfo.sig, false), 259 i->TagInfo.offset, i->TagInfo.size); 260 } 261 262 for (n=0, i=pIcc->m_Tags->begin(); i!=pIcc->m_Tags->end(); i++, n++) 263 dumpTag(outfile, pIcc, i->TagInfo.sig); 264 } 265 delete pIcc; 266 } 267 268 int main(int argc, char* argv[]) 269 { 270 const char* myName = path_tail(argv[0]); 271 272 try 273 { 274 const char* const out_file_pathname = icc_file_name; 275 276 CIccProfile profile; 277 profile.InitHeader(); 278 279 profile.m_Header.date.year = data_last_changed_year; 280 profile.m_Header.date.month = data_last_changed_month; 281 profile.m_Header.date.day = data_last_day; 282 profile.m_Header.date.hours = data_last_changed_hour; 283 profile.m_Header.date.minutes = data_last_changed_minute; 284 profile.m_Header.date.seconds = 0; 285 286 profile.m_Header.deviceClass = icSigDisplayClass; 287 profile.m_Header.colorSpace = icSigRgbData; 288 profile.m_Header.pcs = icSigXYZData; 289 profile.m_Header.platform = icSigUnkownPlatform; 290 profile.m_Header.attributes = static_cast<icUInt64Number>(icReflective); 291 profile.m_Header.renderingIntent = icPerceptual; 292 293 profile.m_Header.cmmId = 0x6E6F6E65; /* 'none' */ 294 profile.m_Header.model = 0x73524742;//sRGB 295 296 profile.m_Header.version=icVersionNumberV2_1; 297 298 // Required tags for a three-component matrix-based display profile, as laid 299 // out by specification ICC.1:1998-09 (clause 6.3) are: 300 // 301 // copyrightTag 302 // profileDescriptionTag 303 // redMatrixColumnTag 304 // greenMatrixColumnTag 305 // blueMatrixColumnTag 306 // redTRCTag 307 // greenTRCTag 308 // blueTRCTag 309 // mediaWhitePointTag 310 311 // the other tags: 312 // 313 // technologyTag 314 // deviceModelTag 315 // deviceMfgDescTag 316 // mediaBlackPointTag 317 // viewingCondDescTag 318 // viewingConditionsTag 319 // luminanceTag 320 // measurementTag 321 // 322 // are optionals, added for completeness 323 324 // the element below are sorted in the same order as 325 // the list above, but the LUT table, 326 // embedded at the end of the profile 327 328 // copyrightTag 329 CIccTagText* copyrightTag = new CIccTagText; 330 copyrightTag->SetText(copyright); 331 profile.AttachTag(icSigCopyrightTag, copyrightTag); 332 333 // profileDescriptionTag 334 CIccTagTextDescription* descriptionTag = new CIccTagTextDescription; 335 descriptionTag->SetText(description); 336 profile.AttachTag(icSigProfileDescriptionTag, descriptionTag); 337 338 CIccTagXYZ* redMatrixColumnTag = new CIccTagXYZ; 339 //values from raccomandation of ICC for sRGB, D50 referenced characterisation data 340 //should be: 0.4361, 0.2225, 0.0139 according to application notes, 341 // the 'X' value below is the one commonly in use on a very 342 // diffused sRGB profile 343 (*redMatrixColumnTag)[0].X = icDtoF(0.4361); 344 (*redMatrixColumnTag)[0].Y = icDtoF(0.2225); 345 (*redMatrixColumnTag)[0].Z = icDtoF(0.0139); 346 profile.AttachTag(icSigRedMatrixColumnTag, redMatrixColumnTag); 347 348 CIccTagXYZ* greenMatrixColumnTag = new CIccTagXYZ; 349 //values from raccomandation of ICC for sRGB, D50 referenced characterisation data 350 (*greenMatrixColumnTag)[0].X = icDtoF(0.3851); 351 (*greenMatrixColumnTag)[0].Y = icDtoF(0.7169); 352 (*greenMatrixColumnTag)[0].Z = icDtoF(0.0971); 353 profile.AttachTag(icSigGreenMatrixColumnTag, greenMatrixColumnTag); 354 355 CIccTagXYZ* blueMatrixColumnTag = new CIccTagXYZ; 356 //values from raccomandation of ICC for sRGB, D50 referenced characterisation data 357 //should be: 0.1431, 0.0606, 0.7139 according to application notes, 358 // the 'Z' value below is the one commonly in use on a very 359 // diffused sRGB profile 360 (*blueMatrixColumnTag)[0].X = icDtoF(0.1431); 361 (*blueMatrixColumnTag)[0].Y = icDtoF(0.0606); 362 (*blueMatrixColumnTag)[0].Z = icDtoF(0.7141); 363 profile.AttachTag(icSigBlueMatrixColumnTag, blueMatrixColumnTag); 364 365 // mediaWhitePointTag 366 CIccTagXYZ* whitePointTag = new CIccTagXYZ; 367 (*whitePointTag)[0].X = icDtoF(0.9505); 368 (*whitePointTag)[0].Y = icDtoF(1.0); 369 (*whitePointTag)[0].Z = icDtoF(1.0891); 370 profile.AttachTag(icSigMediaWhitePointTag, whitePointTag); 371 372 //device signature (technologytag) 373 CIccTagSignature* deviceSign = new CIccTagSignature; 374 deviceSign->SetValue( icSigCRTDisplay ); 375 profile.AttachTag( icSigTechnologyTag, deviceSign ); 376 377 //device model tag 378 CIccTagTextDescription* deviceModelTag = new CIccTagTextDescription; 379 deviceModelTag->SetText("IEC 61966-2.1 Default RGB colour space - sRGB"); 380 profile.AttachTag( icSigDeviceModelDescTag, deviceModelTag); 381 382 // deviceMfgDescTag 383 CIccTagTextDescription* deviceMfgTag = new CIccTagTextDescription; 384 deviceMfgTag->SetText("IEC http://www.iec.ch"); 385 profile.AttachTag( icSigDeviceMfgDescTag, deviceMfgTag); 386 387 // mediaBlackPointTag 388 CIccTagXYZ* blackPointTag = new CIccTagXYZ; 389 (*blackPointTag)[0].X = 390 (*blackPointTag)[0].Y = 391 (*blackPointTag)[0].Z = icDtoF(0.0); 392 profile.AttachTag(icSigMediaBlackPointTag, blackPointTag); 393 394 // viewingCondDescTag 395 CIccTagTextDescription* viewingCondDescTag = new CIccTagTextDescription; 396 viewingCondDescTag->SetText("Reference viewing condition according to IEC 61966-2.1"); 397 profile.AttachTag( icSigViewingCondDescTag, viewingCondDescTag ); 398 399 // viewingConditionsTag 400 CIccTagViewingConditions* viewingConditionsTag = new CIccTagViewingConditions; 401 // Illuminant tristimulus value 402 (*viewingConditionsTag).m_XYZIllum.X = icDtoF(19.6445); 403 (*viewingConditionsTag).m_XYZIllum.Y = icDtoF(20.3718); 404 (*viewingConditionsTag).m_XYZIllum.Z = icDtoF(16.8089); 405 // surround tristimulus value 406 (*viewingConditionsTag).m_XYZSurround.X = icDtoF(3.9289); 407 (*viewingConditionsTag).m_XYZSurround.Y = icDtoF(4.0744); 408 (*viewingConditionsTag).m_XYZSurround.Z = icDtoF(3.3618); 409 (*viewingConditionsTag).m_illumType = icIlluminantD50; 410 profile.AttachTag( icSigViewingConditionsType, viewingConditionsTag ); 411 412 // luminanceTag 413 CIccTagXYZ* luminanceTag = new CIccTagXYZ; 414 (*luminanceTag)[0].X = icDtoF(76.0365); 415 (*luminanceTag)[0].Y = icDtoF(80.0); 416 (*luminanceTag)[0].Z = icDtoF(87.1246); 417 profile.AttachTag(icSigLuminanceTag, luminanceTag); 418 419 // measurementTag 420 CIccTagMeasurement* measurementTag = new CIccTagMeasurement; 421 (*measurementTag).m_Data.stdObserver = icStdObs1931TwoDegrees; 422 (*measurementTag).m_Data.backing.X = 423 (*measurementTag).m_Data.backing.Y = 424 (*measurementTag).m_Data.backing.Z = icDtoF(0.0); 425 (*measurementTag).m_Data.geometry = icGeometryUnknown; 426 // the flare is 1%, but the library doesn't seem all right with this 427 // see specification ICC.1:1998-09, clause 6.5.8, table 55 fot the right 428 // format of the data value 429 (*measurementTag).m_Data.flare = static_cast< icMeasurementFlare > ( icDtoUF( 0.01 ) );//means 1% 430 (*measurementTag).m_Data.illuminant = icIlluminantD65; 431 profile.AttachTag(icSigMeasurementTag, measurementTag ); 432 433 // compute the LUT curves, they are equal for all three colors 434 // so only one LUT is computed and stored 435 int N = 1024; // number of points in LUTs 436 CIccTagCurve* colorTRCTag = new CIccTagCurve(N); 437 // apply conversion from RGB to XYZ, stepping the RGB value linearly from 0 to 100% 438 // 1024 steps are computed 439 for (int i = 0; i < N; ++i) 440 (*colorTRCTag)[i] = computeIEC_RGBtoXYZ( (icFloatNumber)i/(N-1)); 441 442 profile.AttachTag(icSigRedTRCTag, colorTRCTag); 443 profile.AttachTag(icSigGreenTRCTag, colorTRCTag); 444 profile.AttachTag(icSigBlueTRCTag, colorTRCTag); 445 446 //Verify things 447 string validationReport; 448 icValidateStatus validationStatus = profile.Validate(validationReport); 449 450 switch (validationStatus) 451 { 452 case icValidateOK: 453 break; 454 455 case icValidateWarning: 456 clog << "Profile validation warning" << endl 457 << validationReport; 458 break; 459 460 case icValidateNonCompliant: 461 clog << "Profile non compliancy" << endl 462 << validationReport; 463 break; 464 465 case icValidateCriticalError: 466 default: 467 clog << "Profile Error" << endl 468 << validationReport; 469 } 470 471 // Out it goes 472 CIccFileIO out; 473 out.Open(out_file_pathname, "wb+"); 474 profile.Write(&out); 475 out.Close(); 476 477 FILE *headerfile = fopen(hxx_file_name,"w"); 478 479 //print OpenOffice standard file header 480 const char *the_string; 481 482 int idx = 0; 483 484 while((the_string = TheHeader1[idx++]) != NULL ) 485 fprintf(headerfile,"%s\n",the_string); 486 // print the creation date (today) 487 // print the date of sRGB ICC profile data 488 fprintf(headerfile," * the date of last change to sRGB ICC profile data is:\n * %4d/%02d/%02d - %02d:%02d\n", 489 data_last_changed_year, data_last_changed_month, 490 data_last_day, data_last_changed_hour,data_last_changed_minute ); 491 492 idx = 0; 493 494 while((the_string = TheHeader2[idx++]) != NULL ) 495 fprintf(headerfile,"%s\n",the_string); 496 497 { 498 // spit out the data structure (an array of unsigned char) 499 FILE *infile; 500 501 int achar, number = 1; 502 503 infile = fopen(out_file_pathname,"rb"); 504 505 fseek(infile,0,SEEK_END); 506 long int thesize= ftell(infile); 507 fseek(infile,0,SEEK_SET); 508 509 fprintf(headerfile,"\nsal_uInt8 nsRGB_ICC_profile[%d]=\n{\n ",thesize); 510 511 do 512 { 513 achar = fgetc(infile); 514 if(achar == EOF) 515 break; 516 fprintf(headerfile,"0x%02x",achar); 517 if(number % 12 == 0) 518 fprintf(headerfile,",\n "); 519 else 520 fprintf(headerfile,", "); 521 number++; 522 } while(achar != EOF ); 523 fprintf(headerfile,"\n};\n\n"); 524 525 fclose(infile); 526 } 527 // append the file contents, in human readable form, as comment in the header 528 // get the functions from iccDump 529 530 fprintf(headerfile,"/*****************\n\n"); 531 532 fprintf(headerfile,"This ICC profile contains the following data:\n\n"); 533 534 dumpProfile(headerfile, out_file_pathname ); 535 536 fprintf(headerfile,"\n*****************/\n"); 537 //now append the tail 538 idx = 0; 539 while((the_string = TheTail[idx++]) != NULL ) 540 fprintf(headerfile,"%s\n",the_string); 541 542 fclose(headerfile); 543 544 return EXIT_SUCCESS; 545 } 546 catch (const std::exception& e) 547 { 548 cout << myName << ": error: " << e.what() << endl; 549 return EXIT_FAILURE; 550 } 551 } 552