/* License:
 * 
 * This is free software code; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This code is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for details: http://www.gnu.org/licenses/.
 * 
 * Copyright 2014 Elle Stone, 
 * ellestone@ninedegreesbelow.com
 * http://ninedegreesbelow.com
 * */

/* Command line to compile this code:
 * gcc -g -O0 -Wall -o icc-profiles-for-gimp icc-profiles-for-gimp.c -llcms2
 */

#include <lcms2.h>
int main ()
{
/* prints D50X and D50Y values from lcms2.h */
printf("\nD50X, D50Y, D50Z = %1.8f %1.8f %1.8f\n", cmsD50X, cmsD50Y, cmsD50Z);

/* sRGB parametric tone response curve */
/* from Richard Hughes colord cd-create-profile.c
 * cd_util_build_srgb_gamma
	params[0] = 2.4;
	params[1] = 1. / 1.055;
	params[2] = 0.055 / 1.055;
	params[3] = 1. / 12.92;
	params[4] = 0.04045;
}*/
cmsFloat64Number srgb_parameters[5] = 
   { 2.4, 1.0 / 1.055,  0.055 / 1.055, 1.0 / 12.92, 0.04045 }; 
cmsToneCurve *srgb_parametic_curve =
   cmsBuildParametricToneCurve(NULL, 4, srgb_parameters);
cmsToneCurve *srgb_parametric[3] = 
   {srgb_parametic_curve,srgb_parametic_curve,srgb_parametic_curve};

/* perceptually uniform L* (lstar) tone response curve */
/* from Richard Hughes colord cd-create-profile.c
 * cd_util_build_lstar_gamma:
	params[0] = 3.000000;
	params[1] = 0.862076;
	params[2] = 0.137924;
	params[3] = 0.110703;
	params[4] = 0.080002;
}*/
cmsFloat64Number lstar_parameters[5] = 
   { 3.0, 0.862076,  0.137924, 0.110703, 0.080002 }; 
cmsToneCurve *lstar_curve = 
   cmsBuildParametricToneCurve(NULL, 4, lstar_parameters);
cmsToneCurve *lstar[3] = 
   {lstar_curve, lstar_curve, lstar_curve};


/* gamma=1.00, linear gamma, "linear light", etc tone response curve */
cmsToneCurve* gamma100[3];
gamma100[0] = gamma100[1] = gamma100[2] = cmsBuildGamma (NULL, 1.00); 

/* The following true gamma values are not precisely preserved when a V2
 * profile is made. The same problem affects many (all?) V2 profiles available 
 * from various open source and proprietary profile providers. The problem 
 * seems to be hexadecimal rounding during the profile creation process.
 * */

/* gamma=1.80078125 tone response curve */
/* http://www.color.org/chardata/rgb/ROMMRGB.pdf indicates that 
 * the tone response curve for romm isn't a simple gamma curve, but I've
 * never seen a ProPhotoRGB profile that didn't use a simple gamma curve.
 * 
 * All the V2 ProPhoto profiles I've ever examined have 
 * a gamma curve of 1.80078125 rather than 1.80.
 * This is because of hexadecimal rounding.
 * When using gamma=1.80, V2 profiles end up with gamma=1.79688.
 * For this code I used gamma=1.80078125 instead of gamma=1.80.
 * Otherwise V2 and V4 versions of nominally gamma=1.80 profiles 
 * would have different gamma curves.
 * */ 
cmsToneCurve* gamma180[3];
gamma180[0] = gamma180[1] = gamma180[2] = cmsBuildGamma (NULL, 1.80078125); 

/* gamma=2.19921875 tone response curve */
/* per http://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf;
 * ClayRGB uses this value. Based on an old proprietary profile, 
 * it appears to be the correct gamma for WideRGB (WideGamutRGB) as well.
 * It also is what you get when you 
 * try to create a V2 profile with a gamma=2.20 gamma curve. 
 * So perhaps the AdobeRGB1998 and WideGamutRGB specifications 
 * were simply bowing to the inevitable hexadecimal rounding. 
 * Because of hexadecimal rounding errors in V2 profiles, 
 * using gamma = exactly 2.20 will result in V2 and V4 versions 
 * of the same profile having different gamma curves. 
 * Almost all (all?) V2 ICC profiles with nominally gamma=2.20 
 * really have a gamma of 2.19921875, not 2.20.
 * */
cmsToneCurve* gamma220[3];
gamma220[0] = gamma220[1] = gamma220[2] = cmsBuildGamma (NULL, 2.19921875);



/* ************************* WHITE POINTS *************************** */


/* D50 WHITE POINT */

/* cmsCIExyY d50_old_profiles = {0.345699812, 0.358500268, 1.0};
 * D50 white point from actual old V2 D50 profiles */
 
cmsCIExyY d50_rimm_doc_specs = {0.3457, 0.3585, 1.0};
/* http://photo-lovers.org/pdf/color/romm.pdf */

/* Both of the above D50 source white point values produce exactly 
 * the same white point values in the resulting profile */


cmsCIExyY d50_illuminant_profiles  = {0.345702921, 0.358537532, 1.0};
/* D50 profile header illuminant from actual argylLCMS and LCMS profiles */


/* D65 WHITE POINT */

/* cmsCIExyY      d65_old_profiles = {0.312700492, 0.329000939, 1.0};
This white point is found in argyllcms sRGB.icm and ClayRGB1998 profiles.
* It's also found in old V2 proprietary AdobeRGB1998 profiles */ 

cmsCIExyY  d65_srgb_adobe_specs = {0.3127, 0.3290, 1.0};
/* This white point is from the sRGB.icm and AdobeRGB profile specifications */ 

/* Both of the above D65 source white point values produce exactly 
 * the same white point values in the resulting profile */



/* *****************Set up profile variables and values *************** */

cmsHPROFILE profile;
cmsToneCurve* tone_curve[3];
cmsCIExyY whitepoint;
cmsCIExyYTRIPLE primaries;
const char* filename;
cmsMLU *copyright = cmsMLUalloc(NULL, 1);
cmsMLUsetASCII(copyright, "en", "US", "CC0, no warranty, use at your own risk; see http://creativecommons.org/publicdomain/zero/1.0/ for details.");
cmsMLU *manufacturer = cmsMLUalloc(NULL, 1);
cmsMLUsetASCII(manufacturer, "en", "US", "GIMP is the GNU Image Manipulation Program (www.gimp.org)");
cmsMLU *description;



/* ********************** MAKE THE PROFILES ************************* */

/* Make profile: ClayRGB (AdobeRGB), D65, gamma=2.19921875
 * http://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf 
 * 4.2.1 Reference Display White Point
 * The chromaticity coordinates of white displayed on 
 * the reference color monitor shall be x=0.3127, y=0.3290. 
 * . . . [which] correspond to CIE Standard Illuminant D65.
 * */

/* The primaries below are technically correct, but because of hexadecimal rounding
 * these primaries don't make a profile that matches the original.
cmsCIExyYTRIPLE adobe_primaries = {
{0.6400, 0.3300, 1.0},
{0.2100, 0.7100, 1.0},
{0.1500, 0.0600, 1.0}
}; */ 

/* I calculated "prequantized primaries" from the Argyllcms quantized profile.
 * These primaries produce a profile that has the correct adapted primaries. */
cmsCIExyYTRIPLE adobe_primaries_prequantized = {
{0.639996511, 0.329996864, 1.0},
{0.210005295, 0.710004866, 1.0},
{0.149997606, 0.060003644, 1.0}
};
primaries = adobe_primaries_prequantized;
tone_curve[0] = tone_curve[1] = tone_curve[2] = gamma220[0];
whitepoint = d65_srgb_adobe_specs;
profile = cmsCreateRGBProfile ( &whitepoint, &primaries, tone_curve );
cmsWriteTag(profile, cmsSigCopyrightTag, copyright);
cmsWriteTag(profile, cmsSigDeviceMfgDescTag, manufacturer);
cmsSetHeaderRenderingIntent(profile, 1);
cmsSetProfileVersion(profile, 2.1);
description = cmsMLUalloc(NULL, 1);
cmsMLUsetASCII(description, "en", "US", "AdobeRGB1998compatible-gimp-V2.icc (GIMP 2.10.1). The Adobe RGB 1998 color gamut covers a higher percentage of real-world greens than sRGB, but still doesn't include all printable greens, yellows, and cyans. Can be used for 8-bit image editing, with appropriate caution to avoid posterization. This Adobe RGB 1998-compatible icc profile can be applied to DCF R98 camera-generated jpegs.");
cmsWriteTag(profile, cmsSigProfileDescriptionTag, description);
filename = "AdobeRGB1998compatible-gimp-V2.icc";
cmsSaveProfileToFile(profile, filename); 
cmsMLUfree(description);


/* Make profile: sRGB, D65, sRGB-trc
 * http://en.wikipedia.org/wiki/Srgb 
 * */
/* The primaries below are technically correct, but because of hexadecimal rounding
 * these primaries don't make a profile that matches the original.
cmsCIExyYTRIPLE srgb_primaries = {
{0.6400, 0.3300, 1.0},
{0.3000, 0.6000, 1.0},
{0.1500, 0.0600, 1.0}
}; */ 

/* I calculated "prequantized primaries" from the Argyllcms quantized profile.
 * These primaries produce a profile that has the correct adapted primaries. */
cmsCIExyYTRIPLE srgb_primaries_pre_quantized = {
{0.640063875, 0.329971940, 1.0},
{0.299982320, 0.600011332, 1.0},
{0.150010333, 0.060008110, 1.0}
};
tone_curve[0] = tone_curve[1] = tone_curve[2] = srgb_parametric[0];
primaries = srgb_primaries_pre_quantized;
whitepoint = d65_srgb_adobe_specs;
profile = cmsCreateRGBProfile ( &whitepoint, &primaries, tone_curve );
cmsWriteTag(profile, cmsSigCopyrightTag, copyright);
cmsWriteTag(profile, cmsSigDeviceMfgDescTag, manufacturer);
cmsSetHeaderRenderingIntent(profile, 1);
cmsSetProfileVersion(profile, 2.1);
description = cmsMLUalloc(NULL, 1);
cmsMLUsetASCII(description, "en", "US", "sRGB-gimp.icc (GIMP 2.10.1). Hewlett-Packard and Microsoft designed sRGB to match consumer grade CRT color gamuts. sRGB is the standard color space for the world wide web and an excellent color space for editing 8-bit images. This sRGB profile can be applied to DCF R03 camera-generated jpegs.");
cmsWriteTag(profile, cmsSigProfileDescriptionTag, description);
filename = "sRGB-gimp.icc";
cmsSaveProfileToFile(profile, filename);
cmsMLUfree(description);


/* Make profile: Rimm/Romm/Prophoto, D50, gamma=1.80 */
/* Reference Input/Output Medium Metric RGB Color Encodings (RIMM/ROMM RGB)
 * Kevin E. Spaulding, Geoffrey J. Woolfe and Edward J. Giorgianni
 * Eastman Kodak Company, Rochester, New York, U.S.A.
 * Above document is available at http://photo-lovers.org/pdf/color/romm.pdf */
cmsCIExyYTRIPLE rimm_primaries = {
{0.7347, 0.2653, 1.0},
{0.1596, 0.8404, 1.0},
{0.0366, 0.0001, 1.0}
};
primaries = rimm_primaries;
tone_curve[0] = tone_curve[1] = tone_curve[2] = gamma180[0];
whitepoint = d50_rimm_doc_specs;
profile = cmsCreateRGBProfile ( &whitepoint, &primaries, tone_curve );
cmsWriteTag(profile, cmsSigCopyrightTag, copyright);
cmsWriteTag(profile, cmsSigDeviceMfgDescTag, manufacturer);
cmsSetHeaderRenderingIntent(profile, 1);
cmsSetProfileVersion(profile, 2.1);
description = cmsMLUalloc(NULL, 1);
cmsMLUsetASCII(description, "en", "US", "ProPhotoRGB-gimp.icc (GIMP 2.10.1). Kodak designed the Romm (ProPhoto) color gamut to include all printable and most real world colors. It includes some imaginary colors and excludes some of the real world blues and violet blues that can be captured by digital cameras. For high bit depth image editing only.");
cmsWriteTag(profile, cmsSigProfileDescriptionTag, description);
filename = "ProPhotoRGB-gimp.icc";
cmsSaveProfileToFile(profile, filename);
cmsMLUfree(description);


/* Make profile: WidegamutRGB, D50, gamma=2.19921875 */
/* I couldn't find a Widegamut white paper. 
 * Pascale's primary values are closer than the Lindbloom values
 * to the primaries in ald V2 color-balanced Widegamut profiles.
 * Danny Pascale: A review of RGB color spaces
 * http://www.babelcolor.com/download/A%20review%20of%20RGB%20color%20spaces.pdf */
cmsCIExyYTRIPLE widegamut_pascale_primaries = {
{0.7347, 0.2653, 1.0},
{0.1152, 0.8264, 1.0},
{0.1566, 0.0177, 1.0}
};
primaries = widegamut_pascale_primaries;
tone_curve[0] = tone_curve[1] = tone_curve[2] = gamma220[0];
whitepoint = d50_rimm_doc_specs;
profile = cmsCreateRGBProfile ( &whitepoint, &primaries, tone_curve );
cmsWriteTag(profile, cmsSigCopyrightTag, copyright);
cmsWriteTag(profile, cmsSigDeviceMfgDescTag, manufacturer);
cmsSetHeaderRenderingIntent(profile, 1);
cmsSetProfileVersion(profile, 2.1);
description = cmsMLUalloc(NULL, 1);
cmsMLUsetASCII(description, "en", "US", "WideGamutRGB-gimp.icc (GIMP 2.10.1). WideGamutRGB was designed by Adobe to be a wide gamut color space that uses spectral colors as its primaries. For high bit depth image editing only.");
cmsWriteTag(profile, cmsSigProfileDescriptionTag, description);
filename = "WideGamutRGB-gimp.icc";
cmsSaveProfileToFile(profile, filename);
cmsMLUfree(description);


/* Make profile: AllColors, D50, gamma=1.00 */
/* AllColors.icc has a slightly larger color gamut than the ACES color space.
 * It has a D50 white point and a linear gamma TRC. It holds all visible colors.
 * Just like the ACES color space, AllColors also holds a high percentage of imaginary colors.
 * See http://ninedegreesbelow.com/photography/xyz-rgb.html#xyY 
 * for more information about imaginary colors.
 * AllColors primaries for red and blue from http://www.ledtuning.nl/cie.php
 * blue 375nm red 780nm, plus Y intercepts:
 * Color Wavelength (): 375 nm.
 * Spectral Locus coordinates: X:0.17451 Y:0.005182
 * Color Wavelength (): 780 nm.
 * Spectral Locus coordinates: X:0.734690265 Y:0.265309735
 * X1:0.17451 Y1:0.005182
 * X2:0.734690265 Y2:0.265309735
 * X3:0.00Y3:? Solve for Y3:
 * (0.265309735-0.005182)/(0.734690265-0.17451)=0.46436433279205221554=m
 * y=mx+b let x=0; y=b
 * Y1=0.005182=(0.46436433279205221554*0.17451)+b
 * b=0.005182-(0.46436433279205221554*0.17451)=-.07585421971554103213
 *  */
cmsCIExyYTRIPLE allcolors_primaries = 
{
{0.734690265,  0.265309735,  1.0},
{0.000000000,  1.000000000,  1.0},
{0.000000000, -.0758542197,  1.0}
}; 
whitepoint = d50_illuminant_profiles;
primaries = allcolors_primaries;
tone_curve[0] = tone_curve[1] = tone_curve[2] = gamma100[0];
profile = cmsCreateRGBProfile ( &whitepoint, &primaries, tone_curve );
cmsWriteTag(profile, cmsSigCopyrightTag, copyright);
cmsWriteTag(profile, cmsSigDeviceMfgDescTag, manufacturer);
cmsSetHeaderRenderingIntent(profile, 1);
cmsSetProfileVersion(profile, 2.1);
description = cmsMLUalloc(NULL, 1);
cmsMLUsetASCII(description, "en", "US", "AllColorsRGB-gimp-V2-g10.icc (GIMP 2.10.1). This profile has a color gamut that is close to but slightly larger than the ACES color space. For high bit depth image editing only.");
cmsWriteTag(profile, cmsSigProfileDescriptionTag, description);
filename = "AllColorsRGB-Gimp-V2-g10.icc";
cmsSaveProfileToFile(profile, filename);
cmsMLUfree(description);


/* free manufacturer and copyright */
cmsMLUfree(manufacturer);
cmsMLUfree(copyright);

/* make gcc happy by returning an integer from main() */
return 0;
}
