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;
}
Beispiel #2
0
 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;
}
Beispiel #5
0
/********************************************************
* 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;
}