static cmsHPROFILE OpenProfile(const char* File) { cmsHPROFILE h; if (!File) return cmsCreate_sRGBProfile(); if (stricmp(File, "*Lab") == 0) return cmsCreateLabProfile(NULL); if (stricmp(File, "*XYZ") == 0) return cmsCreateXYZProfile(); if (stricmp(File, "*srgb") == 0) return cmsCreate_sRGBProfile(); if (stricmp(File, "*Gray22") == 0) { LPGAMMATABLE Gamma = cmsBuildGamma(256, 2.2); cmsHPROFILE hProfile = cmsCreateGrayProfile(cmsD50_xyY(), Gamma); cmsFreeGamma(Gamma); return hProfile; } if (stricmp(File, "*Lin2222") == 0) { LPGAMMATABLE Gamma = cmsBuildGamma(256, 2.2); LPGAMMATABLE Gamma4[4]; cmsHPROFILE hProfile; Gamma4[0] = Gamma4[1] = Gamma4[2] = Gamma4[3] = Gamma; hProfile = cmsCreateLinearizationDeviceLink(icSigCmykData, Gamma4); cmsFreeGamma(Gamma); return hProfile; } h = cmsOpenProfileFromFile(File, "r"); if (cmsGetDeviceClass(h) == icSigNamedColorClass) FatalError("ERROR: Cannot make devicelink of named color profiles!"); return h; }
static cmsHPROFILE gimp_color_profile_new_d65_gray_linear_internal (void) { cmsHPROFILE profile; /* white point is D65 from the sRGB specs */ cmsCIExyY whitepoint = { 0.3127, 0.3290, 1.0 }; cmsToneCurve *curve = cmsBuildGamma (NULL, 1.0); profile = cmsCreateGrayProfile (&whitepoint, curve); cmsFreeToneCurve (curve); gimp_color_profile_set_tag (profile, cmsSigProfileDescriptionTag, "GIMP built-in D65 Linear Grayscale"); gimp_color_profile_set_tag (profile, cmsSigDeviceMfgDescTag, "GIMP"); gimp_color_profile_set_tag (profile, cmsSigDeviceModelDescTag, "D65 Linear Grayscale"); gimp_color_profile_set_tag (profile, cmsSigCopyrightTag, "Public Domain"); return profile; }
JNIEXPORT jlong JNICALL Java_com_lightcrafts_utils_LCMS_cmsCreateRGBProfile (JNIEnv *env, jclass clazz, jdoubleArray jWhitePoint, jdoubleArray jPrimaries, jdouble gamma) { double *WhitePoint = (double *) (*env)->GetPrimitiveArrayCritical(env, jWhitePoint, 0); double *Primaries = (double *) (*env)->GetPrimitiveArrayCritical(env, jPrimaries, 0); int i; cmsHPROFILE result; cmsCIExyY w = { WhitePoint[0], WhitePoint[1], WhitePoint[2] }; cmsCIExyYTRIPLE p = { {Primaries[0], Primaries[1], Primaries[2]}, {Primaries[3], Primaries[4], Primaries[5]}, {Primaries[6], Primaries[7], Primaries[8]} }; cmsToneCurve* gammaTable[3]; const int context = 1337; gammaTable[0] = gammaTable[1] = gammaTable[2] = cmsBuildGamma(gamma == 1 ? (cmsContext) &context : 0, gamma); result = cmsCreateRGBProfile(&w, &p, gammaTable); // _cmsSaveProfile( result, "/Stuff/matrixRGB.icc" ); // cmsFreeToneCurve(gammaTable[0]); (*env)->ReleasePrimitiveArrayCritical(env, jWhitePoint, WhitePoint, 0); (*env)->ReleasePrimitiveArrayCritical(env, jPrimaries, Primaries, 0); return (jlong)(intptr_t) result; }
/* This profile corresponds to babl_model ("RGB") */ static cmsHPROFILE create_lcms_linear_rgb_profile (void) { cmsHPROFILE ret; /* white point is D65 from the sRGB specs */ cmsCIExyY whitepoint = {0.3127, 0.3290, 1.0}; /* primaries are ITU‐R BT.709‐5 (xYY), * which are also the primaries from the sRGB specs, * modified to properly account for hexadecimal quantization * during the profile making process. */ cmsCIExyYTRIPLE primaries = { /*R {0.6400, 0.3300, 1.0},*/ /*G {0.3000, 0.6000, 1.0},*/ /*B {0.1500, 0.0600, 1.0} */ /*R*/ {0.639998686, 0.330010138, 1.0}, /*G*/ {0.300003784, 0.600003357, 1.0}, /*B*/ {0.150002046, 0.059997204, 1.0} }; /* linear light */ cmsToneCurve* linear[3]; linear[0] = linear[1] = linear[2] = cmsBuildGamma (NULL, 1.0); /* create the profile, cleanup, and return */ ret = cmsCreateRGBProfile (&whitepoint, &primaries, linear); cmsFreeToneCurve (linear[0]); return ret; }
static cmsHPROFILE OpenProfile(const char* File) { if (!File) return cmsCreate_sRGBProfile(); if (stricmp(File, "*sRGB") == 0) return cmsCreate_sRGBProfile(NULL); if (stricmp(File, "*Lab") == 0) return cmsCreateLabProfile(NULL); if (stricmp(File, "*LabD65") == 0) { cmsCIExyY D65xyY; cmsWhitePointFromTemp(6504, &D65xyY); return cmsCreateLabProfile(&D65xyY); } if (stricmp(File, "*XYZ") == 0) return cmsCreateXYZProfile(); if (stricmp(File, "*Gray22") == 0) { LPGAMMATABLE Gamma = cmsBuildGamma(256, 2.2); cmsHPROFILE hProfile = cmsCreateGrayProfile(cmsD50_xyY(), Gamma); cmsFreeGamma(Gamma); return hProfile; } return cmsOpenProfileFromFile(File, "r"); }
// Create the ICC virtual profile for adobe rgb space cmsHPROFILE dt_colorspaces_create_adobergb_profile(void) { cmsHPROFILE hAdobeRGB; cmsCIEXYZTRIPLE Colorants = { {0.609741, 0.311111, 0.019470}, {0.205276, 0.625671, 0.060867}, {0.149185, 0.063217, 0.744568} }; cmsCIEXYZ black = { 0, 0, 0 }; cmsCIEXYZ D65 = { 0.95045, 1, 1.08905 }; cmsToneCurve* transferFunction; transferFunction = cmsBuildGamma(NULL, 2.2); hAdobeRGB = cmsCreateProfilePlaceholder(0); cmsSetProfileVersion(hAdobeRGB, 2.1); cmsMLU *mlu0 = cmsMLUalloc(NULL, 1); cmsMLUsetASCII(mlu0, "en", "US", "Public Domain"); cmsMLU *mlu1 = cmsMLUalloc(NULL, 1); cmsMLUsetASCII(mlu1, "en", "US", "AdobeRGB"); cmsMLU *mlu2 = cmsMLUalloc(NULL, 1); cmsMLUsetASCII(mlu2, "en", "US", "Darktable"); cmsMLU *mlu3 = cmsMLUalloc(NULL, 1); cmsMLUsetASCII(mlu3, "en", "US", "AdobeRGB"); // this will only be displayed when the embedded profile is read by for example GIMP cmsWriteTag(hAdobeRGB, cmsSigCopyrightTag, mlu0); cmsWriteTag(hAdobeRGB, cmsSigProfileDescriptionTag, mlu1); cmsWriteTag(hAdobeRGB, cmsSigDeviceMfgDescTag, mlu2); cmsWriteTag(hAdobeRGB, cmsSigDeviceModelDescTag, mlu3); cmsMLUfree(mlu0); cmsMLUfree(mlu1); cmsMLUfree(mlu2); cmsMLUfree(mlu3); cmsSetDeviceClass(hAdobeRGB, cmsSigDisplayClass); cmsSetColorSpace(hAdobeRGB, cmsSigRgbData); cmsSetPCS(hAdobeRGB, cmsSigXYZData); cmsWriteTag(hAdobeRGB, cmsSigMediaWhitePointTag, &D65); cmsWriteTag(hAdobeRGB, cmsSigMediaBlackPointTag, &black); cmsWriteTag(hAdobeRGB, cmsSigRedColorantTag, (void*) &Colorants.Red); cmsWriteTag(hAdobeRGB, cmsSigGreenColorantTag, (void*) &Colorants.Green); cmsWriteTag(hAdobeRGB, cmsSigBlueColorantTag, (void*) &Colorants.Blue); cmsWriteTag(hAdobeRGB, cmsSigRedTRCTag, (void*) transferFunction); cmsLinkTag(hAdobeRGB, cmsSigGreenTRCTag, cmsSigRedTRCTag ); cmsLinkTag(hAdobeRGB, cmsSigBlueTRCTag, cmsSigRedTRCTag ); return hAdobeRGB; }
static void CreateLabPrelinearization(LPGAMMATABLE LabTable[]) { int i; LabTable[0] = cmsAllocGamma(257); LabTable[1] = cmsBuildGamma(257, 1.0); LabTable[2] = cmsBuildGamma(257, 1.0); // L* uses 257 entries. Entry 256 holds 0xFFFF, so, the effective range // is 0..0xFF00. Last entry (257) is also collapsed to 0xFFFF // From 0 to 0xFF00 for (i=0; i < 256; i++) LabTable[0]->GammaTable[i] = RGB_8_TO_16(i); // Repeat last for 0xFFFF LabTable[0] ->GammaTable[256] = 0xFFFF; }
QByteArray LcmsColorProfileContainer::createFromChromacities(const KoRGBChromaticities& _chromacities, qreal gamma, QString _profileName) { cmsCIExyYTRIPLE primaries; cmsCIExyY whitePoint; lcmsToPigmentViceVersaStructureCopy(primaries.Red, _chromacities.primaries.Red); lcmsToPigmentViceVersaStructureCopy(primaries.Green, _chromacities.primaries.Green); lcmsToPigmentViceVersaStructureCopy(primaries.Blue, _chromacities.primaries.Blue); lcmsToPigmentViceVersaStructureCopy(whitePoint, _chromacities.whitePoint); cmsToneCurve* gammaTable = cmsBuildGamma(0, gamma); const int numTransferFunctions = 3; cmsToneCurve* transferFunctions[numTransferFunctions]; for (int i = 0; i < numTransferFunctions; ++i) { transferFunctions[i] = gammaTable; } cmsHPROFILE profile = cmsCreateRGBProfile(&whitePoint, &primaries, transferFunctions); QString name = _profileName; if (name.isEmpty()) { name = QString("lcms virtual RGB profile - R(%1, %2) G(%3, %4) B(%5, %6) W(%7, %8) gamma %9") .arg(primaries.Red.x) .arg(primaries.Red.y) .arg(primaries.Green.x) .arg(primaries.Green.y) .arg(primaries.Blue.x) .arg(primaries.Blue.y) .arg(whitePoint.x) .arg(whitePoint.y) .arg(gamma); } // icSigProfileDescriptionTag is the compulsory tag and is the profile name // displayed by other applications. cmsWriteTag(profile, cmsSigProfileDescriptionTag, name.toLatin1().data()); cmsWriteTag(profile, cmsSigDeviceModelDescTag, name.toLatin1().data()); // Clear the default manufacturer's tag that is set to "(lcms internal)" QByteArray ba(""); cmsWriteTag(profile, cmsSigDeviceMfgDescTag, ba.data()); cmsFreeToneCurve(gammaTable); QByteArray profileArray = lcmsProfileToByteArray(profile); cmsCloseProfile(profile); return profileArray; }
static void init(void) { cmsCIEXYZ D65_XYZ = {0.95047, 1.0, 1.08883 }; cmsCIExyY D65; cmsXYZ2xyY(&D65, &D65_XYZ); cmsToneCurve *linear = cmsBuildGamma(NULL, 1.0); cmsToneCurve *linrgb[3] = {linear,linear,linear}; cmsCIExyYTRIPLE primaries = { {0.64, 0.33, 1.0}, {0.30, 0.60, 1.0}, {0.15, 0.06, 1.0} }; cmsFloat64Number P[5] = { 2.4, 1. / 1.055, 0.055 / 1.055, 1. / 12.92, 0.04045 }; cmsToneCurve *srgb = cmsBuildParametricToneCurve(NULL, 4, P); cmsToneCurve *srgbcurve[3] = {srgb,srgb,srgb}; cmsHPROFILE hsRGB = cmsCreateRGBProfile(&D65, &primaries, srgbcurve); cmsHPROFILE hLab = cmsCreateLab4Profile(NULL); cmsHPROFILE hlRGB = cmsCreateRGBProfile(&D65, &primaries, linrgb); cmsHPROFILE hlGray = cmsCreateGrayProfile(cmsD50_xyY(), linear); cmsSetHeaderFlags(hlGray, cmsEmbeddedProfileTrue); cmsSaveProfileToFile(hlGray,"lgray.icc"); cmsSetHeaderFlags(hlRGB, cmsEmbeddedProfileTrue); cmsSaveProfileToFile(hlRGB,"lrgb.icc"); xform_srgb_to_lrgb = cmsCreateTransform(hsRGB, TYPE_RGB_DBL, hlRGB, TYPE_RGB_DBL, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE /* preserve precision */ ); xform_srgb_to_lab = cmsCreateTransform(hsRGB, TYPE_RGB_DBL, hLab, TYPE_Lab_DBL, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE); xform_srgb_to_lgray = cmsCreateTransform(hsRGB, TYPE_RGB_DBL, hlGray, TYPE_GRAY_DBL, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE); cmsCloseProfile(hsRGB); cmsCloseProfile(hlRGB); cmsCloseProfile(hLab); cmsCloseProfile(hlGray); cmsFreeToneCurve(linear); cmsFreeToneCurve(srgb); cmsSetLogErrorHandler(errlog); /* sRGB, RGB, Lab, Gray */ printf("R',G',B',R,G,B,L,a,b,Gray\n"); }
static cmsHPROFILE * gimp_color_profile_new_rgb_adobe_internal (void) { cmsHPROFILE profile; /* white point is D65 from the sRGB specs */ cmsCIExyY whitepoint = { 0.3127, 0.3290, 1.0 }; /* AdobeRGB1998 and sRGB have the same white point. * * The primaries below are technically correct, but because of * hexadecimal rounding these primaries don't make a profile that * matches the original. * * cmsCIExyYTRIPLE primaries = { * { 0.6400, 0.3300, 1.0 }, * { 0.2100, 0.7100, 1.0 }, * { 0.1500, 0.0600, 1.0 } * }; */ cmsCIExyYTRIPLE primaries = { { 0.639996511, 0.329996864, 1.0 }, { 0.210005295, 0.710004866, 1.0 }, { 0.149997606, 0.060003644, 1.0 } }; cmsToneCurve *curve[3]; /* gamma 2.2 */ curve[0] = curve[1] = curve[2] = cmsBuildGamma (NULL, 2.19921875); profile = cmsCreateRGBProfile (&whitepoint, &primaries, curve); cmsFreeToneCurve (curve[0]); gimp_color_profile_set_tag (profile, cmsSigProfileDescriptionTag, "Compatible with Adobe RGB (1998)"); gimp_color_profile_set_tag (profile, cmsSigDeviceMfgDescTag, "GIMP"); gimp_color_profile_set_tag (profile, cmsSigDeviceModelDescTag, "Compatible with Adobe RGB (1998)"); gimp_color_profile_set_tag (profile, cmsSigCopyrightTag, "Public Domain"); return profile; }
static PyObject * pycms_CreateGrayProfile(PyObject *self, PyObject *args) { cmsHPROFILE hProfile; cmsToneCurve *tonecurve; tonecurve = cmsBuildGamma(NULL, 2.2); hProfile = cmsCreateGrayProfile(0, tonecurve); cmsFreeToneCurve(tonecurve); if(hProfile==NULL) { Py_INCREF(Py_None); return Py_None; } return Py_BuildValue("O", PyCObject_FromVoidPtr((void *)hProfile, (void *)cmsCloseProfile)); }
mng_cmsprof mnglcms_createsrgbprofile (void) { cmsCIExyY D65; cmsCIExyYTRIPLE Rec709Primaries = { {0.6400, 0.3300, 1.0}, {0.3000, 0.6000, 1.0}, {0.1500, 0.0600, 1.0} }; LPGAMMATABLE Gamma24[3]; mng_cmsprof hsRGB; cmsWhitePointFromTemp(6504, &D65); Gamma24[0] = Gamma24[1] = Gamma24[2] = cmsBuildGamma(256, 2.4); hsRGB = cmsCreateRGBProfile(&D65, &Rec709Primaries, Gamma24); cmsFreeGamma(Gamma24[0]); return hsRGB; }
static PyObject * pycms_CreateGrayProfile(PyObject *self, PyObject *args) { cmsHPROFILE hProfile; LPGAMMATABLE gamma; cmsErrorAction(LCMS_ERROR_IGNORE); gamma = cmsBuildGamma(256, 2.2); hProfile = cmsCreateGrayProfile(cmsD50_xyY(), gamma); cmsFreeGamma(gamma); if(hProfile==NULL) { Py_INCREF(Py_None); return Py_None; } return Py_BuildValue("O", PyCObject_FromVoidPtr((void *)hProfile, (void *)cmsCloseProfile)); }
static cmsHPROFILE CreateRGBSpace(void) { cmsHPROFILE hProfile; LPGAMMATABLE Gamma3[3]; cmsCIExyYTRIPLE CIEPrimaries = { {0.7355,0.2645 }, {0.2658,0.7243 }, {0.1669,0.0085}}; Gamma3[0] = Gamma3[1] = Gamma3[2] = cmsBuildGamma(4096, 4.5); hProfile = cmsCreateRGBProfile(&Cus, &CIEPrimaries, Gamma3); cmsFreeGamma(Gamma3[0]); return hProfile; }
static cmsHPROFILE gimp_color_profile_new_rgb_srgb_linear_internal (void) { cmsHPROFILE profile; /* white point is D65 from the sRGB specs */ cmsCIExyY whitepoint = { 0.3127, 0.3290, 1.0 }; /* primaries are ITU‐R BT.709‐5 (xYY), which are also the primaries * from the sRGB specs, modified to properly account for hexadecimal * quantization during the profile making process. */ cmsCIExyYTRIPLE primaries = { /* R { 0.6400, 0.3300, 1.0 }, */ /* G { 0.3000, 0.6000, 1.0 }, */ /* B { 0.1500, 0.0600, 1.0 } */ /* R */ { 0.639998686, 0.330010138, 1.0 }, /* G */ { 0.300003784, 0.600003357, 1.0 }, /* B */ { 0.150002046, 0.059997204, 1.0 } }; cmsToneCurve *curve[3]; /* linear light */ curve[0] = curve[1] = curve[2] = cmsBuildGamma (NULL, 1.0); profile = cmsCreateRGBProfile (&whitepoint, &primaries, curve); cmsFreeToneCurve (curve[0]); gimp_color_profile_set_tag (profile, cmsSigProfileDescriptionTag, "GIMP built-in Linear sRGB"); gimp_color_profile_set_tag (profile, cmsSigDeviceMfgDescTag, "GIMP"); gimp_color_profile_set_tag (profile, cmsSigDeviceModelDescTag, "Linear sRGB"); gimp_color_profile_set_tag (profile, cmsSigCopyrightTag, "Public Domain"); return profile; }
PyObject * load_png_fast_progressive (char *filename, PyObject *get_buffer_callback) { // Note: we are not using the method that libpng calls "Reading PNG // files progressively". That method would involve feeding the data // into libpng piece by piece, which is not necessary if we can give // libpng a simple FILE pointer. png_structp png_ptr = NULL; png_infop info_ptr = NULL; PyObject * result = NULL; FILE *fp = NULL; uint32_t width, height; uint32_t rows_left; png_byte color_type; png_byte bit_depth; bool have_alpha; char *cm_processing = NULL; // ICC profile-based colour conversion data. png_charp icc_profile_name = NULL; int icc_compression_type = 0; #if PNG_LIBPNG_VER < 10500 // 1.5.0beta36, according to libpng CHANGES png_charp icc_profile = NULL; #else png_bytep icc_profile = NULL; #endif png_uint_32 icc_proflen = 0; // The sRGB flag has an intent field, which we ignore - // the target gamut is sRGB already. int srgb_intent = 0; // Generic RGB space conversion params. // The assumptions we're making are those of sRGB, // but they'll be overridden by gammas or primaries in the file if used. bool generic_rgb_have_gAMA = false; bool generic_rgb_have_cHRM = false; double generic_rgb_file_gamma = 45455 / PNG_gAMA_scale; double generic_rgb_white_x = 31270 / PNG_cHRM_scale; double generic_rgb_white_y = 32900 / PNG_cHRM_scale; double generic_rgb_red_x = 64000 / PNG_cHRM_scale; double generic_rgb_red_y = 33000 / PNG_cHRM_scale; double generic_rgb_green_x = 30000 / PNG_cHRM_scale; double generic_rgb_green_y = 60000 / PNG_cHRM_scale; double generic_rgb_blue_x = 15000 / PNG_cHRM_scale; double generic_rgb_blue_y = 6000 / PNG_cHRM_scale; // Indicates the case where no CM information was present in the file and we // treated it as sRGB. bool possible_legacy_png = false; // LCMS stuff cmsHPROFILE input_buffer_profile = NULL; cmsHPROFILE nparray_data_profile = cmsCreate_sRGBProfile(); cmsHTRANSFORM input_buffer_to_nparray = NULL; cmsToneCurve *gamma_transfer_func = NULL; cmsUInt32Number input_buffer_format = 0; cmsSetLogErrorHandler(log_lcms2_error); fp = fopen(filename, "rb"); if (!fp) { PyErr_SetFromErrno(PyExc_IOError); //PyErr_Format(PyExc_IOError, "Could not open PNG file for writing: %s", // filename); goto cleanup; } png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, (png_voidp)NULL, png_read_error_callback, NULL); if (!png_ptr) { PyErr_SetString(PyExc_MemoryError, "png_create_write_struct() failed"); goto cleanup; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { PyErr_SetString(PyExc_MemoryError, "png_create_info_struct() failed"); goto cleanup; } if (setjmp(png_jmpbuf(png_ptr))) { goto cleanup; } png_init_io(png_ptr, fp); png_read_info(png_ptr, info_ptr); // If there's an embedded ICC profile, use it in preference to any other // colour management information present. if (png_get_iCCP (png_ptr, info_ptr, &icc_profile_name, &icc_compression_type, &icc_profile, &icc_proflen)) { input_buffer_profile = cmsOpenProfileFromMem(icc_profile, icc_proflen); if (! input_buffer_profile) { PyErr_SetString(PyExc_MemoryError, "cmsOpenProfileFromMem() failed"); goto cleanup; } cm_processing = "iCCP (use embedded colour profile)"; } // Shorthand for sRGB. else if (png_get_sRGB (png_ptr, info_ptr, &srgb_intent)) { input_buffer_profile = cmsCreate_sRGBProfile(); cm_processing = "sRGB (explicit sRGB chunk)"; } else { // We might have generic RGB transformation information in the form of // the chromaticities for R, G and B and a generic gamma curve. if (png_get_cHRM (png_ptr, info_ptr, &generic_rgb_white_x, &generic_rgb_white_y, &generic_rgb_red_x, &generic_rgb_red_y, &generic_rgb_green_x, &generic_rgb_green_y, &generic_rgb_blue_x, &generic_rgb_blue_y)) { generic_rgb_have_cHRM = true; } if (png_get_gAMA(png_ptr, info_ptr, &generic_rgb_file_gamma)) { generic_rgb_have_gAMA = true; } if (generic_rgb_have_gAMA || generic_rgb_have_cHRM) { cmsCIExyYTRIPLE primaries = {{generic_rgb_red_x, generic_rgb_red_y}, {generic_rgb_green_x, generic_rgb_green_y}, {generic_rgb_blue_x, generic_rgb_blue_y}}; cmsCIExyY white_point = {generic_rgb_white_x, generic_rgb_white_y}; gamma_transfer_func = cmsBuildGamma(NULL, 1.0/generic_rgb_file_gamma); cmsToneCurve *transfer_funcs[3] = {gamma_transfer_func, gamma_transfer_func, gamma_transfer_func }; input_buffer_profile = cmsCreateRGBProfile(&white_point, &primaries, transfer_funcs); cm_processing = "cHRM and/or gAMA (generic RGB space)"; } // Possible legacy PNG, or rather one which might have been written with an // old version of MyPaint. Treat as sRGB, but flag the strangeness because // it might be important for PNGs in old OpenRaster files. else { possible_legacy_png = true; input_buffer_profile = cmsCreate_sRGBProfile(); cm_processing = "sRGB (no CM chunks present)"; } } if (png_get_interlace_type (png_ptr, info_ptr) != PNG_INTERLACE_NONE) { PyErr_SetString(PyExc_RuntimeError, "Interlaced PNG files are not supported!"); goto cleanup; } color_type = png_get_color_type(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); have_alpha = color_type & PNG_COLOR_MASK_ALPHA; if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(png_ptr); } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); have_alpha = true; } if (bit_depth < 8) { png_set_packing(png_ptr); } if (!have_alpha) { png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER); } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); } png_read_update_info(png_ptr, info_ptr); // Verify what we have done bit_depth = png_get_bit_depth(png_ptr, info_ptr); if (! (bit_depth == 8 || bit_depth == 16)) { PyErr_SetString(PyExc_RuntimeError, "Failed to convince libpng to convert " "to 8 or 16 bits per channel"); goto cleanup; } if (png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_RGB_ALPHA) { PyErr_SetString(PyExc_RuntimeError, "Failed to convince libpng to convert " "to RGBA (wrong color_type)"); goto cleanup; } if (png_get_channels(png_ptr, info_ptr) != 4) { PyErr_SetString(PyExc_RuntimeError, "Failed to convince libpng to convert " "to RGBA (wrong number of channels)"); goto cleanup; } // PNGs use network byte order, i.e. big-endian in descending order // of bit significance. LittleCMS uses whatever's detected for the compiler. // ref: http://www.w3.org/TR/2003/REC-PNG-20031110/#7Integers-and-byte-order if (bit_depth == 16) { #ifdef CMS_USE_BIG_ENDIAN input_buffer_format = TYPE_RGBA_16; #else input_buffer_format = TYPE_RGBA_16_SE; #endif } else { input_buffer_format = TYPE_RGBA_8; } input_buffer_to_nparray = cmsCreateTransform (input_buffer_profile, input_buffer_format, nparray_data_profile, TYPE_RGBA_8, INTENT_PERCEPTUAL, 0); width = png_get_image_width(png_ptr, info_ptr); height = png_get_image_height(png_ptr, info_ptr); rows_left = height; while (rows_left) { PyObject *pyarr = NULL; uint32_t rows = 0; uint32_t row = 0; const uint8_t input_buf_bytes_per_pixel = (bit_depth==8) ? 4 : 8; const uint32_t input_buf_row_stride = sizeof(png_byte) * width * input_buf_bytes_per_pixel; png_byte *input_buffer = NULL; png_bytep *input_buf_row_pointers = NULL; pyarr = PyObject_CallFunction(get_buffer_callback, "ii", width, height); if (! pyarr) { PyErr_Format(PyExc_RuntimeError, "Get-buffer callback failed"); goto cleanup; } #ifdef HEAVY_DEBUG //assert(PyArray_ISCARRAY(arr)); assert(PyArray_NDIM(pyarr) == 3); assert(PyArray_DIM(pyarr, 1) == width); assert(PyArray_DIM(pyarr, 2) == 4); assert(PyArray_TYPE(pyarr) == NPY_UINT8); assert(PyArray_ISBEHAVED(pyarr)); assert(PyArray_STRIDE(pyarr, 1) == 4*sizeof(uint8_t)); assert(PyArray_STRIDE(pyarr, 2) == sizeof(uint8_t)); #endif rows = PyArray_DIM(pyarr, 0); if (rows > rows_left) { PyErr_Format(PyExc_RuntimeError, "Attempt to read %d rows from the PNG, " "but only %d are left", rows, rows_left); goto cleanup; } input_buffer = (png_byte *) malloc(rows * input_buf_row_stride); input_buf_row_pointers = (png_bytep *)malloc(rows * sizeof(png_bytep)); for (row=0; row<rows; row++) { input_buf_row_pointers[row] = input_buffer + (row * input_buf_row_stride); } png_read_rows(png_ptr, input_buf_row_pointers, NULL, rows); rows_left -= rows; for (row=0; row<rows; row++) { uint8_t *pyarr_row = (uint8_t *)PyArray_DATA(pyarr) + row*PyArray_STRIDE(pyarr, 0); uint8_t *input_row = input_buf_row_pointers[row]; // Really minimal fake colour management. Just remaps to sRGB. cmsDoTransform(input_buffer_to_nparray, input_row, pyarr_row, width); // lcms2 ignores alpha, so copy that verbatim // If it's 8bpc RGBA, use A. // If it's 16bpc RrGgBbAa, use A. for (uint32_t i=0; i<width; ++i) { const uint32_t pyarr_alpha_byte = (i*4) + 3; const uint32_t buf_alpha_byte = (i*input_buf_bytes_per_pixel) + ((bit_depth==8) ? 3 : 6); pyarr_row[pyarr_alpha_byte] = input_row[buf_alpha_byte]; } } free(input_buf_row_pointers); free(input_buffer); Py_DECREF(pyarr); } png_read_end(png_ptr, NULL); result = Py_BuildValue("{s:b,s:i,s:i,s:s}", "possible_legacy_png", possible_legacy_png, "width", width, "height", height, "cm_conversions_applied", cm_processing); cleanup: if (info_ptr) png_destroy_read_struct (&png_ptr, &info_ptr, NULL); // libpng's style is to free internally allocated stuff like the icc // tables in png_destroy_*(). I think. if (fp) fclose(fp); if (input_buffer_profile) cmsCloseProfile(input_buffer_profile); if (nparray_data_profile) cmsCloseProfile(nparray_data_profile); if (input_buffer_to_nparray) cmsDeleteTransform(input_buffer_to_nparray); if (gamma_transfer_func) cmsFreeToneCurve(gamma_transfer_func); return result; }
static BOOL CreateLUTS(LPMONITORPROFILERDATA sys, LPLUT* A2B, LPLUT* B2A) { LPLUT AToB0 = cmsAllocLUT(); LPLUT BToA0 = cmsAllocLUT(); LPGAMMATABLE LabG; cmsCIExyY xyY; cmsAlloc3DGrid(AToB0, sys->hdr.CLUTPoints, 3, 3); cmsAlloc3DGrid(BToA0, sys->hdr.CLUTPoints, 3, 3); /* cmsAllocLinearTable(AToB0, sys -> Prelinearization, 1); */ sys->ReverseTables[0] = cmsReverseGamma(4096, sys ->Prelinearization[0]); sys->ReverseTables[1] = cmsReverseGamma(4096, sys ->Prelinearization[1]); sys->ReverseTables[2] = cmsReverseGamma(4096, sys ->Prelinearization[2]); /* Prelinearization */ LabG = cmsBuildGamma(4096, 3.0); sys -> PreLab[0] = cmsJoinGammaEx(LabG, sys ->Prelinearization[0], 4096); sys -> PreLab[1] = cmsJoinGammaEx(LabG, sys ->Prelinearization[1], 4096); sys -> PreLab[2] = cmsJoinGammaEx(LabG, sys ->Prelinearization[2], 4096); sys -> PreLabRev[0] = cmsJoinGammaEx(sys ->Prelinearization[0], LabG, 4096); sys -> PreLabRev[1] = cmsJoinGammaEx(sys ->Prelinearization[1], LabG, 4096); sys -> PreLabRev[2] = cmsJoinGammaEx(sys ->Prelinearization[2], LabG, 4096); cmsFreeGamma(LabG); cmsAllocLinearTable(AToB0, sys->PreLabRev, 1); cmsAllocLinearTable(BToA0, sys->PreLab, 2); /* Set CIECAM97s parameters */ sys -> hdr.device.whitePoint.X = sys -> hdr.WhitePoint.X * 100.; sys -> hdr.device.whitePoint.Y = sys -> hdr.WhitePoint.Y * 100.; sys -> hdr.device.whitePoint.Z = sys -> hdr.WhitePoint.Z * 100.; /* Normalize White point for CIECAM97s model */ cmsXYZ2xyY(&xyY, &sys -> hdr.device.whitePoint); xyY.Y = 100.; cmsxyY2XYZ(&sys -> hdr.device.whitePoint, &xyY); sys->hdr.hDevice = cmsCIECAM97sInit(&sys->hdr.device); sys->hdr.hPCS = cmsCIECAM97sInit(&sys->hdr.PCS); cmsSample3DGrid(AToB0, RegressionSamplerA2B, sys, 0); cmsSample3DGrid(BToA0, RegressionSamplerB2A, sys, 0); cmsCIECAM97sDone(sys->hdr.hDevice); cmsCIECAM97sDone(sys->hdr.hPCS); cmsAddTag(sys->hdr.hProfile, icSigAToB0Tag, AToB0); cmsAddTag(sys->hdr.hProfile, icSigBToA0Tag, BToA0); /* This is the 0xff00 trick to map white at lattice point */ BToA0 ->Matrix.v[0].n[0] = DOUBLE_TO_FIXED((65535.0 / 65280.0)); *A2B = AToB0; *B2A = BToA0; cmsFreeGammaTriple(sys->ReverseTables); cmsFreeGammaTriple(sys->PreLab); cmsFreeGammaTriple(sys->PreLabRev); return true; }
/** * cd_util_create_standard_space: **/ static gboolean cd_util_create_standard_space (CdUtilPrivate *priv, CdDom *dom, const GNode *root, GError **error) { CdColorYxy yxy; cmsCIExyYTRIPLE primaries; cmsCIExyY white; cmsToneCurve *transfer[3] = { NULL, NULL, NULL}; const gchar *data; const GNode *tmp; gboolean ret; gdouble curve_gamma; /* parse gamma */ tmp = cd_dom_get_node (dom, root, "gamma"); if (tmp == NULL) { ret = FALSE; g_set_error_literal (error, 1, 0, "XML error, expected gamma"); goto out; } data = cd_dom_get_node_data (tmp); if (g_strcmp0 (data, "sRGB") == 0) { transfer[0] = cd_util_build_srgb_gamma (); transfer[1] = transfer[0]; transfer[2] = transfer[0]; } else if (g_strcmp0 (data, "L*") == 0) { transfer[0] = cd_util_build_lstar_gamma (); transfer[1] = transfer[0]; transfer[2] = transfer[0]; } else if (g_strcmp0 (data, "Rec709") == 0) { transfer[0] = cd_util_build_rec709_gamma (); transfer[1] = transfer[0]; transfer[2] = transfer[0]; } else { curve_gamma = cd_dom_get_node_data_as_double (tmp); if (curve_gamma == G_MAXDOUBLE) { ret = FALSE; g_set_error (error, 1, 0, "failed to parse gamma: '%s'", data); goto out; } transfer[0] = cmsBuildGamma (NULL, curve_gamma); transfer[1] = transfer[0]; transfer[2] = transfer[0]; } /* values taken from https://en.wikipedia.org/wiki/Standard_illuminant */ tmp = cd_dom_get_node (dom, root, "whitepoint"); if (tmp == NULL) { ret = FALSE; g_set_error_literal (error, 1, 0, "XML error, expected whitepoint"); goto out; } data = cd_dom_get_node_data (tmp); white.Y = 1.0f; if (g_strcmp0 (data, "C") == 0) { white.x = 0.31006; white.y = 0.31616; } else if (g_strcmp0 (data, "E") == 0) { white.x = 0.33333; white.y = 0.33333; } else if (g_strcmp0 (data, "D50") == 0) { white.x = 0.345703; white.y = 0.358539; } else if (g_strcmp0 (data, "D65") == 0) { cmsWhitePointFromTemp (&white, 6504); } else { ret = FALSE; g_set_error_literal (error, 1, 0, "unknown illuminant, expected C, E, D50 or D65"); goto out; } /* get red primary */ tmp = cd_dom_get_node (dom, root, "primaries/red"); if (tmp == NULL) { ret = FALSE; g_set_error_literal (error, 1, 0, "XML error, expected primaries/red"); goto out; } ret = cd_dom_get_node_yxy (tmp, &yxy); if (!ret) { g_set_error_literal (error, 1, 0, "XML error, invalid primaries/red"); goto out; } primaries.Red.x = yxy.x; primaries.Red.y = yxy.y; primaries.Red.Y = yxy.Y; /* get green primary */ tmp = cd_dom_get_node (dom, root, "primaries/green"); if (tmp == NULL) { ret = FALSE; g_set_error_literal (error, 1, 0, "XML error, expected primaries/green"); goto out; } ret = cd_dom_get_node_yxy (tmp, &yxy); if (!ret) { g_set_error_literal (error, 1, 0, "XML error, invalid primaries/green"); goto out; } primaries.Green.x = yxy.x; primaries.Green.y = yxy.y; primaries.Green.Y = yxy.Y; /* get blue primary */ tmp = cd_dom_get_node (dom, root, "primaries/blue"); if (tmp == NULL) { ret = FALSE; g_set_error_literal (error, 1, 0, "XML error, expected primaries/blue"); goto out; } ret = cd_dom_get_node_yxy (tmp, &yxy); if (!ret) { g_set_error_literal (error, 1, 0, "XML error, invalid primaries/blue"); goto out; } primaries.Blue.x = yxy.x; primaries.Blue.y = yxy.y; primaries.Blue.Y = yxy.Y; /* create profile */ priv->lcms_profile = cmsCreateRGBProfileTHR (cd_icc_get_context (priv->icc), &white, &primaries, transfer); ret = TRUE; out: cmsFreeToneCurve (transfer[0]); return ret; }
// Virtual profiles are handled here. cmsHPROFILE OpenStockProfile(cmsContext ContextID, const char* File) { if (!File) return cmsCreate_sRGBProfileTHR(ContextID); if (cmsstrcasecmp(File, "*Lab2") == 0) return cmsCreateLab2ProfileTHR(ContextID, NULL); if (cmsstrcasecmp(File, "*Lab4") == 0) return cmsCreateLab4ProfileTHR(ContextID, NULL); if (cmsstrcasecmp(File, "*Lab") == 0) return cmsCreateLab4ProfileTHR(ContextID, NULL); if (cmsstrcasecmp(File, "*LabD65") == 0) { cmsCIExyY D65xyY; cmsWhitePointFromTemp( &D65xyY, 6504); return cmsCreateLab4ProfileTHR(ContextID, &D65xyY); } if (cmsstrcasecmp(File, "*XYZ") == 0) return cmsCreateXYZProfileTHR(ContextID); if (cmsstrcasecmp(File, "*Gray22") == 0) { cmsToneCurve* Curve = cmsBuildGamma(ContextID, 2.2); cmsHPROFILE hProfile = cmsCreateGrayProfileTHR(ContextID, cmsD50_xyY(), Curve); cmsFreeToneCurve(Curve); return hProfile; } if (cmsstrcasecmp(File, "*Gray30") == 0) { cmsToneCurve* Curve = cmsBuildGamma(ContextID, 3.0); cmsHPROFILE hProfile = cmsCreateGrayProfileTHR(ContextID, cmsD50_xyY(), Curve); cmsFreeToneCurve(Curve); return hProfile; } if (cmsstrcasecmp(File, "*srgb") == 0) return cmsCreate_sRGBProfileTHR(ContextID); if (cmsstrcasecmp(File, "*null") == 0) return cmsCreateNULLProfileTHR(ContextID); if (cmsstrcasecmp(File, "*Lin2222") == 0) { cmsToneCurve* Gamma = cmsBuildGamma(0, 2.2); cmsToneCurve* Gamma4[4]; cmsHPROFILE hProfile; Gamma4[0] = Gamma4[1] = Gamma4[2] = Gamma4[3] = Gamma; hProfile = cmsCreateLinearizationDeviceLink(cmsSigCmykData, Gamma4); cmsFreeToneCurve(Gamma); return hProfile; } return cmsOpenProfileFromFileTHR(ContextID, File, "r"); }
bool ProfileUtils::createIccProfile(bool isLaptop, const Edid &edid, const QString &filename) { cmsCIExyYTRIPLE chroma; cmsCIExyY white_point; cmsHPROFILE lcms_profile = NULL; cmsToneCurve *transfer_curve[3] = { NULL, NULL, NULL }; bool ret = false; cmsHANDLE dict = NULL; /* ensure the per-user directory exists */ // Create dir path if not available // check if the file doesn't already exist QFileInfo fileInfo(filename); if (fileInfo.exists()) { qCWarning(COLORD) << "EDID ICC Profile already exists" << filename; if (*transfer_curve != NULL) cmsFreeToneCurve(*transfer_curve); return false; } // copy color data from our structures // Red chroma.Red.x = edid.red().x(); chroma.Red.y = edid.red().y(); // Green chroma.Green.x = edid.green().x(); chroma.Green.y = edid.green().y(); // Blue chroma.Blue.x = edid.blue().x(); chroma.Blue.y = edid.blue().y(); // White white_point.x = edid.white().x(); white_point.y = edid.white().y(); white_point.Y = 1.0; // estimate the transfer function for the gamma transfer_curve[0] = transfer_curve[1] = transfer_curve[2] = cmsBuildGamma(NULL, edid.gamma()); // create our generated profile lcms_profile = cmsCreateRGBProfile(&white_point, &chroma, transfer_curve); if (lcms_profile == NULL) { qCWarning(COLORD) << "Failed to create ICC profile on cmsCreateRGBProfile"; if (*transfer_curve != NULL) cmsFreeToneCurve(*transfer_curve); return false; } cmsSetColorSpace(lcms_profile, cmsSigRgbData); cmsSetPCS(lcms_profile, cmsSigXYZData); cmsSetHeaderRenderingIntent(lcms_profile, INTENT_RELATIVE_COLORIMETRIC); cmsSetDeviceClass(lcms_profile, cmsSigDisplayClass); // copyright ret = cmsWriteTagTextAscii(lcms_profile, cmsSigCopyrightTag, "No copyright"); if (!ret) { qCWarning(COLORD) << "Failed to write copyright"; if (*transfer_curve != NULL) cmsFreeToneCurve(*transfer_curve); return false; } // set model QString model; if (isLaptop) { model = DmiUtils::deviceModel(); } else { model = edid.name(); } if (model.isEmpty()) { model = QStringLiteral("Unknown monitor"); } ret = cmsWriteTagTextAscii(lcms_profile, cmsSigDeviceModelDescTag, model); if (!ret) { qCWarning(COLORD) << "Failed to write model"; if (*transfer_curve != NULL) { cmsFreeToneCurve(*transfer_curve); } return false; } // write title ret = cmsWriteTagTextAscii(lcms_profile, cmsSigProfileDescriptionTag, model); if (!ret) { qCWarning(COLORD) << "Failed to write description"; if (*transfer_curve != NULL) cmsFreeToneCurve(*transfer_curve); return false; } // get manufacturer QString vendor; if (isLaptop) { vendor = DmiUtils::deviceVendor(); } else { vendor = edid.vendor(); } if (vendor.isEmpty()) { vendor = QStringLiteral("Unknown vendor"); } ret = cmsWriteTagTextAscii(lcms_profile, cmsSigDeviceMfgDescTag, vendor); if (!ret) { qCWarning(COLORD) << "Failed to write manufacturer"; if (*transfer_curve != NULL) cmsFreeToneCurve(*transfer_curve); return false; } // just create a new dict dict = cmsDictAlloc(NULL); // set the framework creator metadata cmsDictAddEntryAscii(dict, CD_PROFILE_METADATA_CMF_PRODUCT, PACKAGE_NAME); cmsDictAddEntryAscii(dict, CD_PROFILE_METADATA_CMF_BINARY, PACKAGE_NAME); cmsDictAddEntryAscii(dict, CD_PROFILE_METADATA_CMF_VERSION, PACKAGE_VERSION); /* set the data source so we don't ever prompt the user to * recalibrate (as the EDID data won't have changed) */ cmsDictAddEntryAscii(dict, CD_PROFILE_METADATA_DATA_SOURCE, CD_PROFILE_METADATA_DATA_SOURCE_EDID); // set 'ICC meta Tag for Monitor Profiles' data cmsDictAddEntryAscii(dict, "EDID_md5", edid.hash()); if (!model.isEmpty()) cmsDictAddEntryAscii(dict, "EDID_model", model); if (!edid.serial().isEmpty()) { cmsDictAddEntryAscii(dict, "EDID_serial", edid.serial()); } if (!edid.pnpId().isEmpty()) { cmsDictAddEntryAscii(dict, "EDID_mnft", edid.pnpId()); } if (!vendor.isEmpty()) { cmsDictAddEntryAscii(dict, "EDID_manufacturer", vendor); } /* write new tag */ ret = cmsWriteTag(lcms_profile, cmsSigMetaTag, dict); if (!ret) { qCWarning(COLORD) << "Failed to write profile metadata"; if (*transfer_curve != NULL) cmsFreeToneCurve(*transfer_curve); return false; } /* write profile id */ ret = cmsMD5computeID(lcms_profile); if (!ret) { qCWarning(COLORD) << "Failed to write profile id"; if (dict != NULL) cmsDictFree (dict); if (*transfer_curve != NULL) cmsFreeToneCurve(*transfer_curve); return false; } /* save, TODO: get error */ ret = cmsSaveProfileToFile(lcms_profile, filename.toUtf8()); if (dict != NULL) { cmsDictFree (dict); } if (*transfer_curve != NULL) { cmsFreeToneCurve (*transfer_curve); } return ret; }
mng_retcode mng_init_full_cms (mng_datap pData, mng_bool bGlobal, mng_bool bObject, mng_bool bRetrobj) { mng_cmsprof hProf; mng_cmstrans hTrans; mng_imagep pImage = MNG_NULL; mng_imagedatap pBuf = MNG_NULL; #ifdef MNG_SUPPORT_TRACE MNG_TRACE (pData, MNG_FN_INIT_FULL_CMS, MNG_LC_START); #endif if (bObject) /* use object if present ? */ { /* current object ? */ if ((mng_imagep)pData->pCurrentobj) pImage = (mng_imagep)pData->pCurrentobj; else /* if not; use object 0 */ pImage = (mng_imagep)pData->pObjzero; } if (bRetrobj) /* retrieving from an object ? */ pImage = (mng_imagep)pData->pRetrieveobj; if (pImage) /* are we using an object ? */ pBuf = pImage->pImgbuf; /* then address the buffer */ if ((!pBuf) || (!pBuf->bCorrected)) /* is the buffer already corrected ? */ { #ifndef MNG_SKIPCHUNK_iCCP if (((pBuf) && (pBuf->bHasICCP)) || ((bGlobal) && (pData->bHasglobalICCP))) { if (!pData->hProf2) /* output profile not defined ? */ { /* then assume sRGB !! */ pData->hProf2 = mnglcms_createsrgbprofile (); if (!pData->hProf2) /* handle error ? */ MNG_ERRORL (pData, MNG_LCMS_NOHANDLE); } if ((pBuf) && (pBuf->bHasICCP)) /* generate a profile handle */ hProf = cmsOpenProfileFromMem (pBuf->pProfile, pBuf->iProfilesize); else hProf = cmsOpenProfileFromMem (pData->pGlobalProfile, pData->iGlobalProfilesize); pData->hProf1 = hProf; /* save for future use */ if (!hProf) /* handle error ? */ MNG_ERRORL (pData, MNG_LCMS_NOHANDLE); #ifndef MNG_NO_16BIT_SUPPORT if (pData->bIsRGBA16) /* 16-bit intermediates ? */ hTrans = cmsCreateTransform (hProf, TYPE_RGBA_16_SE, pData->hProf2, TYPE_RGBA_16_SE, INTENT_PERCEPTUAL, MNG_CMS_FLAGS); else #endif hTrans = cmsCreateTransform (hProf, TYPE_RGBA_8, pData->hProf2, TYPE_RGBA_8, INTENT_PERCEPTUAL, MNG_CMS_FLAGS); pData->hTrans = hTrans; /* save for future use */ if (!hTrans) /* handle error ? */ MNG_ERRORL (pData, MNG_LCMS_NOTRANS); /* load color-correction routine */ pData->fCorrectrow = (mng_fptr)mng_correct_full_cms; return MNG_NOERROR; /* and done */ } else #endif if (((pBuf) && (pBuf->bHasSRGB)) || ((bGlobal) && (pData->bHasglobalSRGB))) { mng_uint8 iIntent; if (pData->bIssRGB) /* sRGB system ? */ return MNG_NOERROR; /* no conversion required */ if (!pData->hProf3) /* sRGB profile not defined ? */ { /* then create it implicitly !! */ pData->hProf3 = mnglcms_createsrgbprofile (); if (!pData->hProf3) /* handle error ? */ MNG_ERRORL (pData, MNG_LCMS_NOHANDLE); } hProf = pData->hProf3; /* convert from sRGB profile */ if ((pBuf) && (pBuf->bHasSRGB)) /* determine rendering intent */ iIntent = pBuf->iRenderingintent; else iIntent = pData->iGlobalRendintent; if (pData->bIsRGBA16) /* 16-bit intermediates ? */ hTrans = cmsCreateTransform (hProf, TYPE_RGBA_16_SE, pData->hProf2, TYPE_RGBA_16_SE, iIntent, MNG_CMS_FLAGS); else hTrans = cmsCreateTransform (hProf, TYPE_RGBA_8, pData->hProf2, TYPE_RGBA_8, iIntent, MNG_CMS_FLAGS); pData->hTrans = hTrans; /* save for future use */ if (!hTrans) /* handle error ? */ MNG_ERRORL (pData, MNG_LCMS_NOTRANS); /* load color-correction routine */ pData->fCorrectrow = (mng_fptr)mng_correct_full_cms; return MNG_NOERROR; /* and done */ } else if ( (((pBuf) && (pBuf->bHasCHRM)) || ((bGlobal) && (pData->bHasglobalCHRM))) && ( ((pBuf) && (pBuf->bHasGAMA) && (pBuf->iGamma > 0)) || ((bGlobal) && (pData->bHasglobalGAMA) && (pData->iGlobalGamma > 0)) ) ) { mng_CIExyY sWhitepoint; mng_CIExyYTRIPLE sPrimaries; mng_gammatabp pGammatable[3]; mng_float dGamma; if (!pData->hProf2) /* output profile not defined ? */ { /* then assume sRGB !! */ pData->hProf2 = mnglcms_createsrgbprofile (); if (!pData->hProf2) /* handle error ? */ MNG_ERRORL (pData, MNG_LCMS_NOHANDLE); } #ifndef MNG_SKIPCHUNK_cHRM if ((pBuf) && (pBuf->bHasCHRM)) /* local cHRM ? */ { sWhitepoint.x = (mng_float)pBuf->iWhitepointx / 100000; sWhitepoint.y = (mng_float)pBuf->iWhitepointy / 100000; sPrimaries.Red.x = (mng_float)pBuf->iPrimaryredx / 100000; sPrimaries.Red.y = (mng_float)pBuf->iPrimaryredy / 100000; sPrimaries.Green.x = (mng_float)pBuf->iPrimarygreenx / 100000; sPrimaries.Green.y = (mng_float)pBuf->iPrimarygreeny / 100000; sPrimaries.Blue.x = (mng_float)pBuf->iPrimarybluex / 100000; sPrimaries.Blue.y = (mng_float)pBuf->iPrimarybluey / 100000; } else { sWhitepoint.x = (mng_float)pData->iGlobalWhitepointx / 100000; sWhitepoint.y = (mng_float)pData->iGlobalWhitepointy / 100000; sPrimaries.Red.x = (mng_float)pData->iGlobalPrimaryredx / 100000; sPrimaries.Red.y = (mng_float)pData->iGlobalPrimaryredy / 100000; sPrimaries.Green.x = (mng_float)pData->iGlobalPrimarygreenx / 100000; sPrimaries.Green.y = (mng_float)pData->iGlobalPrimarygreeny / 100000; sPrimaries.Blue.x = (mng_float)pData->iGlobalPrimarybluex / 100000; sPrimaries.Blue.y = (mng_float)pData->iGlobalPrimarybluey / 100000; } #endif sWhitepoint.Y = /* Y component is always 1.0 */ sPrimaries.Red.Y = sPrimaries.Green.Y = sPrimaries.Blue.Y = 1.0; if ((pBuf) && (pBuf->bHasGAMA)) /* get the gamma value */ dGamma = (mng_float)pBuf->iGamma / 100000; else dGamma = (mng_float)pData->iGlobalGamma / 100000; dGamma = pData->dViewgamma / dGamma; pGammatable [0] = /* and build the lookup tables */ pGammatable [1] = pGammatable [2] = cmsBuildGamma (256, dGamma); if (!pGammatable [0]) /* enough memory ? */ MNG_ERRORL (pData, MNG_LCMS_NOMEM); /* create the profile */ hProf = cmsCreateRGBProfile (&sWhitepoint, &sPrimaries, pGammatable); cmsFreeGamma (pGammatable [0]); /* free the temporary gamma tables ? */ /* yes! but just the one! */ pData->hProf1 = hProf; /* save for future use */ if (!hProf) /* handle error ? */ MNG_ERRORL (pData, MNG_LCMS_NOHANDLE); if (pData->bIsRGBA16) /* 16-bit intermediates ? */ hTrans = cmsCreateTransform (hProf, TYPE_RGBA_16_SE, pData->hProf2, TYPE_RGBA_16_SE, INTENT_PERCEPTUAL, MNG_CMS_FLAGS); else hTrans = cmsCreateTransform (hProf, TYPE_RGBA_8, pData->hProf2, TYPE_RGBA_8, INTENT_PERCEPTUAL, MNG_CMS_FLAGS); pData->hTrans = hTrans; /* save for future use */ if (!hTrans) /* handle error ? */ MNG_ERRORL (pData, MNG_LCMS_NOTRANS); /* load color-correction routine */ pData->fCorrectrow = (mng_fptr)mng_correct_full_cms; return MNG_NOERROR; /* and done */ } } #ifdef MNG_SUPPORT_TRACE MNG_TRACE (pData, MNG_FN_INIT_FULL_CMS, MNG_LC_END); #endif /* if we get here, we'll only do gamma */ return mng_init_gamma_only (pData, bGlobal, bObject, bRetrobj); }
static GimpColorProfile * gimp_color_profile_new_from_color_profile (GimpColorProfile *profile, gboolean linear) { GimpColorProfile *new_profile; cmsHPROFILE target_profile; GimpMatrix3 matrix = { 0, }; cmsCIEXYZ *whitepoint; cmsToneCurve *curve; const gchar *model; gchar *new_model; g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL); if (gimp_color_profile_is_rgb (profile)) { if (! gimp_color_profile_get_rgb_matrix_colorants (profile, &matrix)) return NULL; } else if (! gimp_color_profile_is_gray (profile)) { return NULL; } whitepoint = cmsReadTag (profile->priv->lcms_profile, cmsSigMediaWhitePointTag); target_profile = cmsCreateProfilePlaceholder (0); cmsSetProfileVersion (target_profile, 4.3); cmsSetDeviceClass (target_profile, cmsSigDisplayClass); cmsSetPCS (target_profile, cmsSigXYZData); cmsWriteTag (target_profile, cmsSigMediaWhitePointTag, whitepoint); if (linear) { /* linear light */ curve = cmsBuildGamma (NULL, 1.00); gimp_color_profile_set_tag (target_profile, cmsSigProfileDescriptionTag, "linear TRC variant generated by GIMP"); } else { cmsFloat64Number srgb_parameters[5] = { 2.4, 1.0 / 1.055, 0.055 / 1.055, 1.0 / 12.92, 0.04045 }; /* sRGB curve */ curve = cmsBuildParametricToneCurve (NULL, 4, srgb_parameters); gimp_color_profile_set_tag (target_profile, cmsSigProfileDescriptionTag, "sRGB TRC variant generated by GIMP"); } if (gimp_color_profile_is_rgb (profile)) { cmsCIEXYZ red; cmsCIEXYZ green; cmsCIEXYZ blue; cmsSetColorSpace (target_profile, cmsSigRgbData); red.X = matrix.coeff[0][0]; red.Y = matrix.coeff[0][1]; red.Z = matrix.coeff[0][2]; green.X = matrix.coeff[1][0]; green.Y = matrix.coeff[1][1]; green.Z = matrix.coeff[1][2]; blue.X = matrix.coeff[2][0]; blue.Y = matrix.coeff[2][1]; blue.Z = matrix.coeff[2][2]; cmsWriteTag (target_profile, cmsSigRedColorantTag, &red); cmsWriteTag (target_profile, cmsSigGreenColorantTag, &green); cmsWriteTag (target_profile, cmsSigBlueColorantTag, &blue); cmsWriteTag (target_profile, cmsSigRedTRCTag, curve); cmsWriteTag (target_profile, cmsSigGreenTRCTag, curve); cmsWriteTag (target_profile, cmsSigBlueTRCTag, curve); } else { cmsSetColorSpace (target_profile, cmsSigGrayData); cmsWriteTag (target_profile, cmsSigGrayTRCTag, curve); } cmsFreeToneCurve (curve); model = gimp_color_profile_get_model (profile); if (model && g_str_has_prefix (model, "Generated from '")) { /* don't add multiple "Generated from 'foo'" */ new_model = g_strdup (model); } else { new_model = g_strdup_printf ("Generated from '%s'", gimp_color_profile_get_description (profile)); } gimp_color_profile_set_tag (target_profile, cmsSigDeviceMfgDescTag, "GIMP"); gimp_color_profile_set_tag (target_profile, cmsSigDeviceModelDescTag, new_model); gimp_color_profile_set_tag (target_profile, cmsSigCopyrightTag, "Public Domain"); g_free (new_model); new_profile = gimp_color_profile_new_from_lcms_profile (target_profile, NULL); cmsCloseProfile (target_profile); return new_profile; }