bool LcmsColorProfileContainer::init() { if (d->profile) cmsCloseProfile(d->profile); d->profile = cmsOpenProfileFromMem((void*)d->data->rawData().constData(), d->data->rawData().size()); #ifndef NDEBUG if (d->data->rawData().size() == 4096) { warnPigment << "Profile has a size of 4096, which is suspicious and indicates a possible misuse of QIODevice::read(int), check your code."; } #endif if (d->profile) { wchar_t buffer[_BUFFER_SIZE_]; d->colorSpaceSignature = cmsGetColorSpace(d->profile); d->deviceClass = cmsGetDeviceClass(d->profile); cmsGetProfileInfo(d->profile, cmsInfoDescription, cmsNoLanguage, cmsNoCountry, buffer, _BUFFER_SIZE_); d->productDescription = QString::fromWCharArray(buffer); d->valid = true; cmsGetProfileInfo(d->profile, cmsInfoModel, cmsNoLanguage, cmsNoCountry, buffer, _BUFFER_SIZE_); d->name = QString::fromWCharArray(buffer); cmsGetProfileInfo(d->profile, cmsInfoManufacturer, cmsNoLanguage, cmsNoCountry, buffer, _BUFFER_SIZE_); d->manufacturer = QString::fromWCharArray(buffer); // Check if the profile can convert (something->this) d->suitableForOutput = cmsIsMatrixShaper(d->profile) || ( cmsIsCLUT(d->profile, INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT) && cmsIsCLUT(d->profile, INTENT_PERCEPTUAL, LCMS_USED_AS_OUTPUT) ); return true; } return false; }
QString readInfo(cmsInfoType info) { GV_RETURN_VALUE_IF_FAIL(mProfile, QString()); wchar_t buffer[1024]; int size = cmsGetProfileInfo(mProfile, info, "en", "US", buffer, 1024); return QString::fromWCharArray(buffer, size); }
QString ScLcms2ColorProfileImpl::productDescription() const { if (m_productDescription.isEmpty()) { if (m_profileHandle) { #ifdef _WIN32 cmsUInt32Number descSize = cmsGetProfileInfo(m_profileHandle, cmsInfoDescription, "en", "US", nullptr, 0); if (descSize > 0) { wchar_t* descData = (wchar_t*) malloc(descSize + sizeof(wchar_t)); descSize = cmsGetProfileInfo(m_profileHandle, cmsInfoDescription, "en", "US", descData, descSize); if (descSize > 0) { uint stringLen = descSize / sizeof(wchar_t); descData[stringLen] = 0; if (sizeof(wchar_t) == sizeof(QChar)) { m_productDescription = QString::fromUtf16((ushort *) descData); } else { m_productDescription = QString::fromUcs4((uint *) descData); } free(descData); } } #else cmsUInt32Number descSize = cmsGetProfileInfoASCII(m_profileHandle, cmsInfoDescription, "en", "US", nullptr, 0); if (descSize > 0) { char* descData = (char*) malloc(descSize + sizeof(char)); descSize = cmsGetProfileInfoASCII(m_profileHandle, cmsInfoDescription, "en", "US", descData, descSize); if (descSize > 0) { m_productDescription = QString(descData); free(descData); } } #endif } } return m_productDescription; }
bool LcmsColorProfileContainer::init() { if (d->profile) { cmsCloseProfile(d->profile); } d->profile = cmsOpenProfileFromMem((void *)d->data->rawData().constData(), d->data->rawData().size()); #ifndef NDEBUG if (d->data->rawData().size() == 4096) { qWarning() << "Profile has a size of 4096, which is suspicious and indicates a possible misuse of QIODevice::read(int), check your code."; } #endif if (d->profile) { wchar_t buffer[_BUFFER_SIZE_]; d->colorSpaceSignature = cmsGetColorSpace(d->profile); d->deviceClass = cmsGetDeviceClass(d->profile); cmsGetProfileInfo(d->profile, cmsInfoDescription, cmsNoLanguage, cmsNoCountry, buffer, _BUFFER_SIZE_); d->name = QString::fromWCharArray(buffer); //apparantly this should give us a localised string??? Not sure about this. cmsGetProfileInfo(d->profile, cmsInfoModel, cmsNoLanguage, cmsNoCountry, buffer, _BUFFER_SIZE_); d->productDescription = QString::fromWCharArray(buffer); cmsGetProfileInfo(d->profile, cmsInfoManufacturer, cmsNoLanguage, cmsNoCountry, buffer, _BUFFER_SIZE_); d->manufacturer = QString::fromWCharArray(buffer); cmsGetProfileInfo(d->profile, cmsInfoCopyright, cmsNoLanguage, cmsNoCountry, buffer, _BUFFER_SIZE_); d->copyright = QString::fromWCharArray(buffer); cmsProfileClassSignature profile_class; profile_class = cmsGetDeviceClass(d->profile); d->valid = (profile_class != cmsSigNamedColorClass); //This is where obtain the whitepoint, and convert it to the actual white point of the profile in the case a Chromatic adaption tag is //present. This is necessary for profiles following the v4 spec. cmsCIEXYZ baseMediaWhitePoint;//dummy to hold copy of mediawhitepoint if this is modified by chromatic adaption. if (cmsIsTag(d->profile, cmsSigMediaWhitePointTag)) { d->mediaWhitePoint = *((cmsCIEXYZ *)cmsReadTag(d->profile, cmsSigMediaWhitePointTag)); baseMediaWhitePoint = d->mediaWhitePoint; cmsXYZ2xyY(&d->whitePoint, &d->mediaWhitePoint); if (cmsIsTag(d->profile, cmsSigChromaticAdaptationTag)) { //the chromatic adaption tag represent a matrix from the actual white point of the profile to D50. cmsCIEXYZ *CAM1 = (cmsCIEXYZ *)cmsReadTag(d->profile, cmsSigChromaticAdaptationTag); //We first put all our data into structures we can manipulate. double d3dummy [3] = {d->mediaWhitePoint.X, d->mediaWhitePoint.Y, d->mediaWhitePoint.Z}; QGenericMatrix<1, 3, double> whitePointMatrix(d3dummy); QTransform invertDummy(CAM1[0].X, CAM1[0].Y, CAM1[0].Z, CAM1[1].X, CAM1[1].Y, CAM1[1].Z, CAM1[2].X, CAM1[2].Y, CAM1[2].Z); //we then abuse QTransform's invert function because it probably does matrix invertion 20 times better than I can program. //if the matrix is uninvertable, invertedDummy will be an identity matrix, which for us means that it won't give any noticeble //effect when we start multiplying. QTransform invertedDummy = invertDummy.inverted(); //we then put the QTransform into a generic 3x3 matrix. double d9dummy [9] = {invertedDummy.m11(), invertedDummy.m12(), invertedDummy.m13(), invertedDummy.m21(), invertedDummy.m22(), invertedDummy.m23(), invertedDummy.m31(), invertedDummy.m32(), invertedDummy.m33() }; QGenericMatrix<3, 3, double> chromaticAdaptionMatrix(d9dummy); //multiplying our inverted adaption matrix with the whitepoint gives us the right whitepoint. QGenericMatrix<1, 3, double> result = chromaticAdaptionMatrix * whitePointMatrix; //and then we pour the matrix into the whitepoint variable. Generic matrix does row/column for indices even though it //uses column/row for initialising. d->mediaWhitePoint.X = result(0, 0); d->mediaWhitePoint.Y = result(1, 0); d->mediaWhitePoint.Z = result(2, 0); cmsXYZ2xyY(&d->whitePoint, &d->mediaWhitePoint); } } //This is for RGB profiles, but it only works for matrix profiles. Need to design it to work with non-matrix profiles. if (cmsIsTag(d->profile, cmsSigRedColorantTag)) { cmsCIEXYZTRIPLE tempColorants; tempColorants.Red = *((cmsCIEXYZ *)cmsReadTag(d->profile, cmsSigRedColorantTag)); tempColorants.Green = *((cmsCIEXYZ *)cmsReadTag(d->profile, cmsSigGreenColorantTag)); tempColorants.Blue = *((cmsCIEXYZ *)cmsReadTag(d->profile, cmsSigBlueColorantTag)); //convert to d65, this is useless. cmsAdaptToIlluminant(&d->colorants.Red, &baseMediaWhitePoint, &d->mediaWhitePoint, &tempColorants.Red); cmsAdaptToIlluminant(&d->colorants.Green, &baseMediaWhitePoint, &d->mediaWhitePoint, &tempColorants.Green); cmsAdaptToIlluminant(&d->colorants.Blue, &baseMediaWhitePoint, &d->mediaWhitePoint, &tempColorants.Blue); //d->colorants = tempColorants; d->hasColorants = true; } else { //qDebug()<<d->name<<": has no colorants"; d->hasColorants = false; } //retrieve TRC. if (cmsIsTag(d->profile, cmsSigRedTRCTag) && cmsIsTag(d->profile, cmsSigBlueTRCTag) && cmsIsTag(d->profile, cmsSigGreenTRCTag)) { d->redTRC = ((cmsToneCurve *)cmsReadTag (d->profile, cmsSigRedTRCTag)); d->greenTRC = ((cmsToneCurve *)cmsReadTag (d->profile, cmsSigGreenTRCTag)); d->blueTRC = ((cmsToneCurve *)cmsReadTag (d->profile, cmsSigBlueTRCTag)); d->redTRCReverse = cmsReverseToneCurve(d->redTRC); d->greenTRCReverse = cmsReverseToneCurve(d->greenTRC); d->blueTRCReverse = cmsReverseToneCurve(d->blueTRC); d->hasTRC = true; } else if (cmsIsTag(d->profile, cmsSigGrayTRCTag)) { d->grayTRC = ((cmsToneCurve *)cmsReadTag (d->profile, cmsSigGrayTRCTag)); d->grayTRCReverse = cmsReverseToneCurve(d->grayTRC); d->hasTRC = true; } else { d->hasTRC = false; } // Check if the profile can convert (something->this) d->suitableForOutput = cmsIsMatrixShaper(d->profile) || (cmsIsCLUT(d->profile, INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT) && cmsIsCLUT(d->profile, INTENT_PERCEPTUAL, LCMS_USED_AS_OUTPUT)); d->version = cmsGetProfileVersion(d->profile); d->defaultIntent = cmsGetHeaderRenderingIntent(d->profile); d->isMatrixShaper = cmsIsMatrixShaper(d->profile); d->isPerceptualCLUT = cmsIsCLUT(d->profile, INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT); d->isSaturationCLUT = cmsIsCLUT(d->profile, INTENT_SATURATION, LCMS_USED_AS_INPUT); d->isAbsoluteCLUT = cmsIsCLUT(d->profile, INTENT_SATURATION, LCMS_USED_AS_INPUT); d->isRelativeCLUT = cmsIsCLUT(d->profile, INTENT_RELATIVE_COLORIMETRIC, LCMS_USED_AS_INPUT); return true; } return false; }
/******************************************************** * IccProfileChangerDialogNew関数 * * ICCプロファイルを選択するダイアログウィジェットを作成 * * 引数 * * parent : 親ウインドウ * * workspace_profile_path : 作業用プロファイルのパス * * 返り値 * * ダイアログ生成用のウィジェット * ********************************************************/ GtkWidget* IccProfileChangerDialogNew(GtkWindow *parent, gchar *workspace_profile_path) { GtkWidget *dialog, *content_area, *box, *radio1, *radio2 = NULL, *radio3, *button; dialog = gtk_dialog_new_with_buttons("Change ICC profile", parent, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_OK, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); gtk_widget_set_size_request(dialog, 400, -1); g_signal_connect(dialog, "response", G_CALLBACK(IccProfileChangerDialogResponse), dialog); content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); gtk_container_set_border_width(GTK_CONTAINER(dialog), 4); radio1 = gtk_radio_button_new_with_label(NULL, "Don't color manage this canvas"); gtk_misc_set_alignment(GTK_MISC(GTK_BIN(radio1)->child), 0, .5); gtk_label_set_width_chars(GTK_LABEL(GTK_BIN(radio1)->child), 64); gtk_label_set_ellipsize(GTK_LABEL(GTK_BIN(radio1)->child), PANGO_ELLIPSIZE_END); gtk_box_pack_start(GTK_BOX(content_area), radio1, FALSE, FALSE, 2); if(workspace_profile_path) { wchar_t *buf; guint32 buf_size; gssize count; gchar *desc = NULL, *label_text; cmsHPROFILE h_profile = cmsOpenProfileFromFile(workspace_profile_path, "rb"); if(h_profile) { buf_size = cmsGetProfileInfo(h_profile, cmsInfoDescription, "ja", "JP", NULL, 0); buf = (wchar_t *)g_malloc(buf_size); cmsGetProfileInfo(h_profile, cmsInfoDescription, "ja", "JP", buf, buf_size); desc = g_convert((gchar *)buf, buf_size, "UTF-8", "UTF-16LE", NULL, &count, NULL); cmsCloseProfile(h_profile); } label_text = g_strdup_printf("Workspace%s%s", desc ? " : " : "", desc ? desc : ""); radio2 = gtk_radio_button_new_with_label_from_widget(radio1, label_text); gtk_misc_set_alignment(GTK_MISC(GTK_BIN(radio2)->child), 0, .5); gtk_label_set_width_chars(GTK_LABEL(GTK_BIN(radio2)->child), 64); gtk_label_set_ellipsize(GTK_LABEL(GTK_BIN(radio2)->child), PANGO_ELLIPSIZE_END); g_object_set_data(G_OBJECT(radio2), "data", g_strdup(workspace_profile_path)); gtk_box_pack_start(GTK_BOX(content_area), radio2, FALSE, FALSE, 2); } radio3 = gtk_radio_button_new_with_label_from_widget(radio1, "Profile : "); button = icc_button_new(); icc_button_set_enable_empty(ICC_BUTTON(button), FALSE); icc_button_set_mask (ICC_BUTTON(button), ICC_BUTTON_CLASS_INPUT | ICC_BUTTON_CLASS_OUTPUT | ICC_BUTTON_CLASS_DISPLAY, ICC_BUTTON_COLORSPACE_XYZ | ICC_BUTTON_COLORSPACE_LAB, ICC_BUTTON_COLORSPACE_RGB); g_object_set_data(G_OBJECT(radio3), "data", icc_button_get_filename(ICC_BUTTON(button))); g_signal_connect(button, "changed", G_CALLBACK(IccProfileChangerDialogProfileChanged), radio3); box = gtk_hbox_new(FALSE, 4); gtk_box_pack_start(GTK_BOX(box), radio3, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(content_area), box, FALSE, FALSE, 2); g_signal_connect(radio1, "toggled", G_CALLBACK(IccProfileChangerDialogSelectionChanged), dialog); g_signal_connect(radio2, "toggled", G_CALLBACK(IccProfileChangerDialogSelectionChanged), dialog); g_signal_connect(radio3, "toggled", G_CALLBACK(IccProfileChangerDialogSelectionChanged), dialog); g_object_set_data(dialog, "radio1", radio1); g_object_set_data(dialog, "radio2", radio2); g_object_set_data(dialog, "radio3", radio3); gtk_widget_show_all(dialog); return dialog; }
QList<ScColorProfileInfo> ScLcms2ColorMgmtEngineImpl::getAvailableProfileInfo(const QString& directory, bool recursive) { QList<ScColorProfileInfo> profileInfos; QDir d(directory, "*", QDir::Name, QDir::Files | QDir::Readable | QDir::Dirs | QDir::NoSymLinks); if ((!d.exists()) || (d.count() == 0)) return profileInfos; QString nam = ""; cmsHPROFILE hIn = NULL; for (uint dc = 0; dc < d.count(); ++dc) { QString file = d[dc]; if (file == "." || file == "..") continue; QFileInfo fi(directory + "/" + file); if (fi.isDir() && !recursive) continue; else if (fi.isDir() && !file.startsWith('.')) { QList<ScColorProfileInfo> profileInfos2 = getAvailableProfileInfo(fi.filePath()+"/", true); profileInfos.append(profileInfos2); continue; } ScColorProfileInfo profileInfo; profileInfo.file = fi.filePath(); QFile f(fi.filePath()); QByteArray bb(40, ' '); if (!f.open(QIODevice::ReadOnly)) { profileInfo.debug = QString("couldn't open %1 as color profile").arg(fi.filePath()); profileInfos.append(profileInfo); continue; } int len = f.read(bb.data(), 40); f.close(); if (len == 40 && bb[36] == 'a' && bb[37] == 'c' && bb[38] == 's' && bb[39] == 'p') { const QByteArray profilePath( QString(directory + "/" + file).toLocal8Bit() ); hIn = cmsOpenProfileFromFile(profilePath.data(), "r"); if (hIn == NULL) continue; #ifdef _WIN32 cmsUInt32Number descSize = cmsGetProfileInfo(hIn, cmsInfoDescription, "en", "US", NULL, 0); if (descSize > 0) { wchar_t* descData = (wchar_t*) malloc(descSize + sizeof(wchar_t)); descSize = cmsGetProfileInfo(hIn, cmsInfoDescription, "en", "US", descData, descSize); if (descSize > 0) { uint stringLen = descSize / sizeof(wchar_t); descData[stringLen] = 0; if (sizeof(wchar_t) == sizeof(QChar)) { profileInfo.description = QString::fromUtf16((ushort *) descData); } else { profileInfo.description = QString::fromUcs4((uint *) descData); } free(descData); } } #else cmsUInt32Number descSize = cmsGetProfileInfoASCII(hIn, cmsInfoDescription, "en", "US", NULL, 0); if (descSize > 0) { char* descData = (char*) malloc(descSize + sizeof(char)); descSize = cmsGetProfileInfoASCII(hIn, cmsInfoDescription, "en", "US", descData, descSize); if (descSize > 0) { profileInfo.description = QString(descData); free(descData); } } #endif if (profileInfo.description.isEmpty()) { cmsCloseProfile(hIn); profileInfo.debug = QString("Color profile %1 is broken : no valid description").arg(fi.filePath()); profileInfos.append(profileInfo); continue; } profileInfo.colorSpace = translateLcmsColorSpaceType( cmsGetColorSpace(hIn) ); profileInfo.deviceClass = translateLcmsProfileClass( cmsGetDeviceClass(hIn) ); profileInfos.append(profileInfo); cmsCloseProfile(hIn); hIn = NULL; } } return profileInfos; }