|
|
|
/* ============================================================
|
|
|
|
*
|
|
|
|
* This file is a part of digiKam project
|
|
|
|
* http://www.digikam.org
|
|
|
|
*
|
|
|
|
* Date : 2006-06-23
|
|
|
|
* Description : a tab widget to display ICC profile infos
|
|
|
|
*
|
|
|
|
* Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
|
|
|
|
*
|
|
|
|
* This program is free software; 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 2, or (at your option)
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* This program 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 more details.
|
|
|
|
*
|
|
|
|
* ============================================================ */
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
// TQt includes.
|
|
|
|
|
|
|
|
#include <tqlayout.h>
|
|
|
|
#include <tqpushbutton.h>
|
|
|
|
#include <tqwhatsthis.h>
|
|
|
|
#include <tqlabel.h>
|
|
|
|
#include <tqmap.h>
|
|
|
|
#include <tqhbox.h>
|
|
|
|
#include <tqfile.h>
|
|
|
|
#include <tqcombobox.h>
|
|
|
|
#include <tqgroupbox.h>
|
|
|
|
#include <tqmap.h>
|
|
|
|
|
|
|
|
// KDE includes.
|
|
|
|
|
|
|
|
#include <kdialogbase.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kapplication.h>
|
|
|
|
|
|
|
|
// Lcms includes.
|
|
|
|
|
|
|
|
#include LCMS_HEADER
|
|
|
|
#if LCMS_VERSION < 114
|
|
|
|
#define cmsTakeCopyright(profile) "Unknown"
|
|
|
|
#endif // LCMS_VERSION < 114
|
|
|
|
|
|
|
|
// Local includes.
|
|
|
|
|
|
|
|
#include "ddebug.h"
|
|
|
|
#include "metadatalistview.h"
|
|
|
|
#include "cietonguewidget.h"
|
|
|
|
#include "iccprofilewidget.h"
|
|
|
|
#include "iccprofilewidget.moc"
|
|
|
|
|
|
|
|
namespace Digikam
|
|
|
|
{
|
|
|
|
|
|
|
|
static const char* ICCHumanList[] =
|
|
|
|
{
|
|
|
|
"ColorSpace",
|
|
|
|
"Copyright",
|
|
|
|
"DeviceClass",
|
|
|
|
"Name",
|
|
|
|
"Description",
|
|
|
|
"RenderingIntent",
|
|
|
|
"-1"
|
|
|
|
};
|
|
|
|
|
|
|
|
// This entry list is only require for compatibility with MetadataWidget implementation.
|
|
|
|
static const char* ICCEntryList[] =
|
|
|
|
{
|
|
|
|
"Header",
|
|
|
|
"-1"
|
|
|
|
};
|
|
|
|
|
|
|
|
class ICCTagInfo
|
|
|
|
{
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
ICCTagInfo(){}
|
|
|
|
|
|
|
|
ICCTagInfo(const TQString& title, const TQString& description)
|
|
|
|
: m_title(title), m_description(description){}
|
|
|
|
|
|
|
|
TQString title() const { return m_title; }
|
|
|
|
TQString description() const { return m_description; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
TQString m_title;
|
|
|
|
TQString m_description;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef TQMap<TQString, ICCTagInfo> ICCTagInfoMap;
|
|
|
|
|
|
|
|
class ICCProfileWidgetPriv
|
|
|
|
{
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
ICCProfileWidgetPriv()
|
|
|
|
{
|
|
|
|
cieTongue = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQStringList tagsfilter;
|
|
|
|
TQStringList keysFilter;
|
|
|
|
|
|
|
|
CIETongueWidget *cieTongue;
|
|
|
|
|
|
|
|
ICCTagInfoMap iccTagsDescription;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
ICCProfileWidget::ICCProfileWidget(TQWidget* parent, const char* name, int w, int h)
|
|
|
|
: MetadataWidget(parent, name)
|
|
|
|
{
|
|
|
|
cmsErrorAction(LCMS_ERROR_SHOW);
|
|
|
|
|
|
|
|
d = new ICCProfileWidgetPriv;
|
|
|
|
|
|
|
|
// Set the translated ICC tags titles/descriptions list
|
|
|
|
d->iccTagsDescription["Icc.Header.Name"] = ICCTagInfo(i18n("Name"),
|
|
|
|
i18n("The ICC profile product name"));
|
|
|
|
d->iccTagsDescription["Icc.Header.Description"] = ICCTagInfo(i18n("Description"),
|
|
|
|
i18n("The ICC profile product description"));
|
|
|
|
d->iccTagsDescription["Icc.Header.Information"] = ICCTagInfo(i18n("Information"),
|
|
|
|
i18n("Additional ICC profile information"));
|
|
|
|
d->iccTagsDescription["Icc.Header.Manufacturer"] = ICCTagInfo(i18n("Manufacturer"),
|
|
|
|
i18n("Raw information about the ICC profile manufacturer"));
|
|
|
|
d->iccTagsDescription["Icc.Header.Model"] = ICCTagInfo(i18n("Model"),
|
|
|
|
i18n("Raw information about the ICC profile model"));
|
|
|
|
d->iccTagsDescription["Icc.Header.Copyright"] = ICCTagInfo(i18n("Copyright"),
|
|
|
|
i18n("Raw information about the ICC profile copyright"));
|
|
|
|
d->iccTagsDescription["Icc.Header.ProfileID"] = ICCTagInfo(i18n("Profile ID"),
|
|
|
|
i18n("The ICC profile ID number"));
|
|
|
|
d->iccTagsDescription["Icc.Header.ColorSpace"] = ICCTagInfo(i18n("Color Space"),
|
|
|
|
i18n("The color space used by the ICC profile"));
|
|
|
|
d->iccTagsDescription["Icc.Header.ConnectionSpace"] = ICCTagInfo(i18n("Connection Space"),
|
|
|
|
i18n("The connection space used by the ICC profile"));
|
|
|
|
d->iccTagsDescription["Icc.Header.DeviceClass"] = ICCTagInfo(i18n("Device Class"),
|
|
|
|
i18n("The ICC profile device class"));
|
|
|
|
d->iccTagsDescription["Icc.Header.RenderingIntent"] = ICCTagInfo(i18n("Rendering Intent"),
|
|
|
|
i18n("The ICC profile rendering intent"));
|
|
|
|
d->iccTagsDescription["Icc.Header.ProfileVersion"] = ICCTagInfo(i18n("Profile Version"),
|
|
|
|
i18n("The ICC version used to record the profile"));
|
|
|
|
d->iccTagsDescription["Icc.Header.CMMFlags"] = ICCTagInfo(i18n("CMM Flags"),
|
|
|
|
i18n("The ICC profile color management flags"));
|
|
|
|
|
|
|
|
// Set the list of keys and tags filters.
|
|
|
|
for (int i=0 ; TQString(ICCEntryList[i]) != TQString("-1") ; i++)
|
|
|
|
d->keysFilter << ICCEntryList[i];
|
|
|
|
|
|
|
|
for (int i=0 ; TQString(ICCHumanList[i]) != TQString("-1") ; i++)
|
|
|
|
d->tagsfilter << ICCHumanList[i];
|
|
|
|
|
|
|
|
// Add CIE tongue graph to the widget area
|
|
|
|
|
|
|
|
d->cieTongue = new CIETongueWidget(w, h, this);
|
|
|
|
TQWhatsThis::add( d->cieTongue, i18n("<p>This area contains a CIE or chromaticity diagram. "
|
|
|
|
"A CIE diagram is a representation of all the colors "
|
|
|
|
"that a person with normal vision can see. This is represented "
|
|
|
|
"by the colored sail-tqshaped area. In addition you will see a "
|
|
|
|
"triangle that is superimposed on the diagram outlined in white. "
|
|
|
|
"This triangle represents the outer boundaries of the color space "
|
|
|
|
"of the device that is characterized by the inspected profile. "
|
|
|
|
"This is called the device gamut.<p>"
|
|
|
|
"In addition there are black dots and yellow lines on the diagram. "
|
|
|
|
"Each black dot represents one of the measurement points that were "
|
|
|
|
"used to create this profile. The yellow line represents the "
|
|
|
|
"amount that each point is corrected by the profile, and the "
|
|
|
|
"direction of this correction."));
|
|
|
|
|
|
|
|
setUserAreaWidget(d->cieTongue);
|
|
|
|
decodeMetadata();
|
|
|
|
}
|
|
|
|
|
|
|
|
ICCProfileWidget::~ICCProfileWidget()
|
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ICCProfileWidget::setDataLoading()
|
|
|
|
{
|
|
|
|
d->cieTongue->loadingStarted();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ICCProfileWidget::setLoadingFailed()
|
|
|
|
{
|
|
|
|
d->cieTongue->loadingFailed();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString ICCProfileWidget::getMetadataTitle()
|
|
|
|
{
|
|
|
|
return i18n("ICC Color Profile Information");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ICCProfileWidget::loadFromURL(const KURL& url)
|
|
|
|
{
|
|
|
|
setFileName(url.path());
|
|
|
|
|
|
|
|
if (url.isEmpty())
|
|
|
|
{
|
|
|
|
setMetadata();
|
|
|
|
d->cieTongue->setProfileData();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TQFile file(url.path());
|
|
|
|
if ( !file.open(IO_ReadOnly) )
|
|
|
|
{
|
|
|
|
setMetadata();
|
|
|
|
d->cieTongue->setProfileData();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQByteArray iccData(file.size());
|
|
|
|
TQDataStream stream( &file );
|
|
|
|
stream.readRawBytes(iccData.data(), iccData.size());
|
|
|
|
file.close();
|
|
|
|
|
|
|
|
if (iccData.isEmpty())
|
|
|
|
{
|
|
|
|
setMetadata();
|
|
|
|
d->cieTongue->setProfileData();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
setMetadata(iccData);
|
|
|
|
d->cieTongue->setProfileData(iccData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ICCProfileWidget::decodeMetadata()
|
|
|
|
{
|
|
|
|
TQByteArray iccData = getMetadata();
|
|
|
|
if (iccData.isNull())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
d->cieTongue->setProfileData(iccData);
|
|
|
|
|
|
|
|
cmsHPROFILE hProfile = cmsOpenProfileFromMem(iccData.data(), (DWORD)iccData.size());
|
|
|
|
|
|
|
|
if (!hProfile)
|
|
|
|
{
|
|
|
|
DDebug() << "Cannot parse ICC profile tags using LCMS" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
DMetadata::MetaDataMap metaDataMap;
|
|
|
|
|
|
|
|
if ( !TQString(cmsTakeProductName(hProfile)).isEmpty() )
|
|
|
|
metaDataMap.insert("Icc.Header.Name", TQString(cmsTakeProductName(hProfile)).replace("\n", " "));
|
|
|
|
|
|
|
|
if ( !TQString(cmsTakeProductDesc(hProfile)).isEmpty() )
|
|
|
|
metaDataMap.insert("Icc.Header.Description", TQString(cmsTakeProductDesc(hProfile)).replace("\n", " "));
|
|
|
|
|
|
|
|
if ( !TQString(cmsTakeProductInfo(hProfile)).isEmpty() )
|
|
|
|
metaDataMap.insert("Icc.Header.Information", TQString(cmsTakeProductInfo(hProfile)).replace("\n", " "));
|
|
|
|
|
|
|
|
if ( !TQString(cmsTakeManufacturer(hProfile)).isEmpty() )
|
|
|
|
metaDataMap.insert("Icc.Header.Manufacturer", TQString(cmsTakeManufacturer(hProfile)).replace("\n", " "));
|
|
|
|
|
|
|
|
if ( !TQString(cmsTakeModel(hProfile)).isEmpty() )
|
|
|
|
metaDataMap.insert("Icc.Header.Model", TQString(cmsTakeModel(hProfile)).replace("\n", " "));
|
|
|
|
|
|
|
|
if ( !TQString(cmsTakeCopyright(hProfile)).isEmpty() )
|
|
|
|
metaDataMap.insert("Icc.Header.Copyright", TQString(cmsTakeCopyright(hProfile)).replace("\n", " "));
|
|
|
|
|
|
|
|
metaDataMap.insert("Icc.Header.ProfileID", TQString::number((uint)*cmsTakeProfileID(hProfile)));
|
|
|
|
metaDataMap.insert("Icc.Header.ProfileVersion", TQString::number((uint)cmsGetProfileICCversion(hProfile)));
|
|
|
|
metaDataMap.insert("Icc.Header.CMMFlags", TQString::number((uint)cmsTakeHeaderFlags(hProfile)));
|
|
|
|
|
|
|
|
TQString colorSpace;
|
|
|
|
switch (cmsGetColorSpace(hProfile))
|
|
|
|
{
|
|
|
|
case icSigLabData:
|
|
|
|
colorSpace = i18n("Lab");
|
|
|
|
break;
|
|
|
|
case icSigLuvData:
|
|
|
|
colorSpace = i18n("Luv");
|
|
|
|
break;
|
|
|
|
case icSigRgbData:
|
|
|
|
colorSpace = i18n("RGB");
|
|
|
|
break;
|
|
|
|
case icSigGrayData:
|
|
|
|
colorSpace = i18n("GRAY");
|
|
|
|
break;
|
|
|
|
case icSigHsvData:
|
|
|
|
colorSpace = i18n("HSV");
|
|
|
|
break;
|
|
|
|
case icSigHlsData:
|
|
|
|
colorSpace = i18n("HLS");
|
|
|
|
break;
|
|
|
|
case icSigCmykData:
|
|
|
|
colorSpace = i18n("CMYK");
|
|
|
|
break;
|
|
|
|
case icSigCmyData:
|
|
|
|
colorSpace= i18n("CMY");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
colorSpace = i18n("Unknown");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
metaDataMap.insert("Icc.Header.ColorSpace", colorSpace);
|
|
|
|
|
|
|
|
TQString connectionSpace;
|
|
|
|
switch (cmsGetPCS(hProfile))
|
|
|
|
{
|
|
|
|
case icSigLabData:
|
|
|
|
connectionSpace = i18n("Lab");
|
|
|
|
break;
|
|
|
|
case icSigLuvData:
|
|
|
|
connectionSpace = i18n("Luv");
|
|
|
|
break;
|
|
|
|
case icSigRgbData:
|
|
|
|
connectionSpace = i18n("RGB");
|
|
|
|
break;
|
|
|
|
case icSigGrayData:
|
|
|
|
connectionSpace = i18n("GRAY");
|
|
|
|
break;
|
|
|
|
case icSigHsvData:
|
|
|
|
connectionSpace = i18n("HSV");
|
|
|
|
break;
|
|
|
|
case icSigHlsData:
|
|
|
|
connectionSpace = i18n("HLS");
|
|
|
|
break;
|
|
|
|
case icSigCmykData:
|
|
|
|
connectionSpace = i18n("CMYK");
|
|
|
|
break;
|
|
|
|
case icSigCmyData:
|
|
|
|
connectionSpace= i18n("CMY");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
connectionSpace = i18n("Unknown");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
metaDataMap.insert("Icc.Header.ConnectionSpace", connectionSpace);
|
|
|
|
|
|
|
|
TQString device;
|
|
|
|
switch ((int)cmsGetDeviceClass(hProfile))
|
|
|
|
{
|
|
|
|
case icSigInputClass:
|
|
|
|
device = i18n("Input device");
|
|
|
|
break;
|
|
|
|
case icSigDisplayClass:
|
|
|
|
device = i18n("Display device");
|
|
|
|
break;
|
|
|
|
case icSigOutputClass:
|
|
|
|
device = i18n("Output device");
|
|
|
|
break;
|
|
|
|
case icSigColorSpaceClass:
|
|
|
|
device = i18n("Color space");
|
|
|
|
break;
|
|
|
|
case icSigLinkClass:
|
|
|
|
device = i18n("Link device");
|
|
|
|
break;
|
|
|
|
case icSigAbstractClass:
|
|
|
|
device = i18n("Abstract");
|
|
|
|
break;
|
|
|
|
case icSigNamedColorClass:
|
|
|
|
device = i18n("Named color");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
device = i18n("Unknown");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
metaDataMap.insert("Icc.Header.DeviceClass", device);
|
|
|
|
|
|
|
|
TQString intent;
|
|
|
|
switch (cmsTakeRenderingIntent(hProfile))
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
intent = i18n("Perceptual");
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
intent = i18n("Relative Colorimetric");
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
intent = i18n("Saturation");
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
intent = i18n("Absolute Colorimetric");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
intent = i18n("Unknown");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
metaDataMap.insert("Icc.Header.RenderingIntent", intent);
|
|
|
|
|
|
|
|
cmsCloseProfile(hProfile);
|
|
|
|
|
|
|
|
// Update all metadata contents.
|
|
|
|
setMetadataMap(metaDataMap);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ICCProfileWidget::buildView()
|
|
|
|
{
|
|
|
|
if (getMode() == SIMPLE)
|
|
|
|
{
|
|
|
|
setIfdList(getMetadataMap(), d->keysFilter, d->tagsfilter);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
setIfdList(getMetadataMap(), d->keysFilter, TQStringList());
|
|
|
|
}
|
|
|
|
|
|
|
|
MetadataWidget::buildView();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString ICCProfileWidget::getTagTitle(const TQString& key)
|
|
|
|
{
|
|
|
|
ICCTagInfoMap::Iterator it = d->iccTagsDescription.find(key);
|
|
|
|
if (it != d->iccTagsDescription.end())
|
|
|
|
return(it.data().title());
|
|
|
|
|
|
|
|
return key.section('.', 2, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ICCProfileWidget::slotSaveMetadataToFile()
|
|
|
|
{
|
|
|
|
KURL url = saveMetadataToFile(i18n("ICC color profile File to Save"),
|
|
|
|
TQString("*.icc *.icm|"+i18n("ICC Files (*.icc; *.icm)")));
|
|
|
|
storeMetadataToFile(url);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString ICCProfileWidget::getTagDescription(const TQString& key)
|
|
|
|
{
|
|
|
|
ICCTagInfoMap::Iterator it = d->iccTagsDescription.find(key);
|
|
|
|
if (it != d->iccTagsDescription.end())
|
|
|
|
return(it.data().description());
|
|
|
|
|
|
|
|
return key.section('.', 2, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Digikam
|