/* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2005-12-21 * Description : digiKam image editor tool to correct picture * colors using an ICC color profile * * Copyright (C) 2005-2006 by F.J. Cruz * Copyright (C) 2006-2008 by Gilles Caulier * * 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. * * ============================================================ */ // TQt includes. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes. #include #include #include #include #include #include #include #include #include #include #include #include #include #include // LibKDcraw includes. #include #include // Digikam includes. #include "bcgmodifier.h" #include "colorgradientwidget.h" #include "curveswidget.h" #include "ddebug.h" #include "dimg.h" #include "dimgimagefilters.h" #include "editortoolsettings.h" #include "histogramwidget.h" #include "iccpreviewwidget.h" #include "iccprofileinfodlg.h" #include "icctransform.h" #include "imagecurves.h" #include "imagehistogram.h" #include "imageiface.h" #include "imagewidget.h" // Local includes. #include "iccprooftool.h" #include "iccprooftool.moc" using namespace KDcrawIface; using namespace Digikam; namespace DigikamImagesPluginCore { ICCProofTool::ICCProofTool(TQObject* parent) : EditorTool(parent) { setName("colormanagement"); setToolName(i18n("Color Management")); setToolIcon(SmallIcon("colormanagement")); setToolHelp("colormanagement.anchor"); m_destinationPreviewData = 0; m_cmEnabled = true; m_hasICC = false; ImageIface iface(0, 0); m_originalImage = iface.getOriginalImg(); m_embeddedICC = iface.getEmbeddedICCFromOriginalImage(); m_previewWidget = new ImageWidget("colormanagement Tool",0, i18n("

Here you can see the image preview after " "applying a color profile

")); setToolView(m_previewWidget); // ------------------------------------------------------------------- m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| EditorToolSettings::Load| EditorToolSettings::SaveAs| EditorToolSettings::Ok| EditorToolSettings::Cancel); TQGridLayout *gridSettings = new TQGridLayout(m_gboxSettings->plainPage(), 3, 2); TQLabel *label1 = new TQLabel(i18n("Channel: "), m_gboxSettings->plainPage()); label1->setAlignment(TQt::AlignRight | TQt::AlignVCenter); m_channelCB = new TQComboBox(false, m_gboxSettings->plainPage()); m_channelCB->insertItem(i18n("Luminosity")); m_channelCB->insertItem(i18n("Red")); m_channelCB->insertItem(i18n("Green")); m_channelCB->insertItem(i18n("Blue")); TQWhatsThis::add( m_channelCB, i18n("

Select the histogram channel to display here:

" "Luminosity: display the image's luminosity values.

" "Red: display the red channel values.

" "Green: display the green channel values.

" "Blue: display the blue channel values.

")); m_scaleBG = new TQHButtonGroup(m_gboxSettings->plainPage()); m_scaleBG->setExclusive(true); m_scaleBG->setFrameShape(TQFrame::NoFrame); m_scaleBG->setInsideMargin(0); TQWhatsThis::add(m_scaleBG, i18n("

Select the histogram scale here.

" "If the image's maximal values are small, you can use the linear scale.

" "Logarithmic scale can be used when the maximal values are big; " "if it is used, all values (small and large) will be visible on the " "graph.")); TQPushButton *linHistoButton = new TQPushButton(m_scaleBG); TQToolTip::add(linHistoButton, i18n("

Linear")); m_scaleBG->insert(linHistoButton, HistogramWidget::LinScaleHistogram); TDEGlobal::dirs()->addResourceType("histogram-lin", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); TQString directory = TDEGlobal::dirs()->findResourceDir("histogram-lin", "histogram-lin.png"); linHistoButton->setPixmap(TQPixmap(directory + "histogram-lin.png")); linHistoButton->setToggleButton(true); TQPushButton *logHistoButton = new TQPushButton(m_scaleBG); TQToolTip::add(logHistoButton, i18n("

Logarithmic")); m_scaleBG->insert(logHistoButton, HistogramWidget::LogScaleHistogram); TDEGlobal::dirs()->addResourceType("histogram-log", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); directory = TDEGlobal::dirs()->findResourceDir("histogram-log", "histogram-log.png"); logHistoButton->setPixmap(TQPixmap(directory + "histogram-log.png")); logHistoButton->setToggleButton(true); TQHBoxLayout* l1 = new TQHBoxLayout(); l1->addWidget(label1); l1->addWidget(m_channelCB); l1->addStretch(10); l1->addWidget(m_scaleBG); gridSettings->addMultiCellLayout(l1, 0, 0, 0, 2); // ------------------------------------------------------------- TQVBox *histoBox = new TQVBox(m_gboxSettings->plainPage()); m_histogramWidget = new HistogramWidget(256, 140, histoBox, false, true, true); TQWhatsThis::add( m_histogramWidget, i18n("

Here you can see the target preview image histogram " "of the selected image channel. " "This one is updated after setting changes.")); TQLabel *space = new TQLabel(histoBox); space->setFixedHeight(1); m_hGradient = new ColorGradientWidget( ColorGradientWidget::Horizontal, 10, histoBox ); m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); gridSettings->addMultiCellWidget(histoBox, 1, 2, 0, 2); // ------------------------------------------------------------- m_toolBoxWidgets = new TQToolBox(m_gboxSettings->plainPage()); TQWidget *generalOptions = new TQWidget(m_toolBoxWidgets); TQWidget *inProfiles = new TQWidget(m_toolBoxWidgets); TQWidget *spaceProfiles = new TQWidget(m_toolBoxWidgets); TQWidget *proofProfiles = new TQWidget(m_toolBoxWidgets); TQWidget *lightnessadjust = new TQWidget(m_toolBoxWidgets); //---------- "General" Page Setup ---------------------------------- m_toolBoxWidgets->insertItem(GENERALPAGE, generalOptions, SmallIconSet("misc"), i18n("General Settings")); TQWhatsThis::add(generalOptions, i18n("

Here you can set general parameters.

")); TQGridLayout *zeroPageLayout = new TQGridLayout(generalOptions, 5, 1); m_doSoftProofBox = new TQCheckBox(generalOptions); m_doSoftProofBox->setText(i18n("Soft-proofing")); TQWhatsThis::add(m_doSoftProofBox, i18n("

Rendering emulation of the device described " "by the \"Proofing\" profile. Useful to preview the final " "result without rendering to physical medium.

")); m_checkGamutBox = new TQCheckBox(generalOptions); m_checkGamutBox->setText(i18n("Check gamut")); TQWhatsThis::add(m_checkGamutBox, i18n("

You can use this option if you want to show " "the colors that are outside the printer's gamut

")); m_embeddProfileBox = new TQCheckBox(generalOptions); m_embeddProfileBox->setChecked(true); m_embeddProfileBox->setText(i18n("Assign profile")); TQWhatsThis::add(m_embeddProfileBox, i18n("

You can use this option to embed " "the selected workspace color profile into the image.

")); m_BPCBox = new TQCheckBox(generalOptions); m_BPCBox->setText(i18n("Use BPC")); TQWhatsThis::add(m_BPCBox, i18n("

The Black Point Compensation (BPC) feature does work in conjunction " "with Relative Colorimetric Intent. Perceptual intent should make no " "difference, since BPC is always on, and in Absolute Colorimetric " "Intent it is always turned off.

" "

BPC does compensate for a lack of ICC profiles in the dark tone rendering. " "With BPC the dark tones are optimally mapped (no clipping) from original media " "to the destination rendering media, e.g. the combination of paper and ink.

")); TQLabel *intent = new TQLabel(i18n("Rendering Intent:"), generalOptions); m_renderingIntentsCB = new RComboBox(generalOptions); m_renderingIntentsCB->insertItem("Perceptual"); m_renderingIntentsCB->insertItem("Absolute Colorimetric"); m_renderingIntentsCB->insertItem("Relative Colorimetric"); m_renderingIntentsCB->insertItem("Saturation"); m_renderingIntentsCB->setDefaultItem(0); TQWhatsThis::add( m_renderingIntentsCB, i18n("
  • Perceptual intent causes the full gamut " "of the image to be compressed or expanded to fill the gamut of the destination media, " "so that gray balance is preserved but colorimetric accuracy may not be preserved.
    " "In other words, if certain colors in an image fall outside of the range of colors that " "the output device can render, the image intent will cause all the colors in the image " "to be adjusted so that every color in the image falls within the range that can be " "rendered and so that the relationship between colors is preserved as much as possible.
    " "This intent is most suitable for display of photographs and images, and is the default " "intent.
  • " "
  • Absolute Colorimetric intent causes any colors that fall outside the range that the " "output device can render to be adjusted to the closest color that can be rendered, while all " "other colors are left unchanged.
    " "This intent preserves the white point and is most suitable for spot colors (Pantone, " "TruMatch, logo colors, ...).
  • " "
  • Relative Colorimetric intent is defined such that any colors that fall outside the " "range that the output device can render are adjusted to the closest color that can be " "rendered, while all other colors are left unchanged. Proof intent does not preserve " "the white point.
  • " "
  • Saturation intent preserves the saturation of colors in the image at the possible " "expense of hue and lightness.
    " "Implementation of this intent remains somewhat problematic, and the ICC is still working " "on methods to achieve the desired effects.
    " "This intent is most suitable for business graphics such as charts, where it is more " "important that the colors be vivid and contrast well with each other rather than a " "specific color.
")); KURLLabel *lcmsLogoLabel = new KURLLabel(generalOptions); lcmsLogoLabel->setAlignment(AlignTop | AlignRight); lcmsLogoLabel->setText(TQString()); lcmsLogoLabel->setURL("http://www.littlecms.com"); TDEGlobal::dirs()->addResourceType("logo-lcms", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); directory = TDEGlobal::dirs()->findResourceDir("logo-lcms", "logo-lcms.png"); lcmsLogoLabel->setPixmap(TQPixmap(directory + "logo-lcms.png")); TQToolTip::add(lcmsLogoLabel, i18n("Visit Little CMS project website")); zeroPageLayout->addMultiCellWidget(m_doSoftProofBox, 0, 0, 0, 0); zeroPageLayout->addMultiCellWidget(m_checkGamutBox, 1, 1, 0, 0); zeroPageLayout->addMultiCellWidget(m_embeddProfileBox, 2, 2, 0, 0); zeroPageLayout->addMultiCellWidget(lcmsLogoLabel, 0, 2, 1, 1); zeroPageLayout->addMultiCellWidget(m_BPCBox, 3, 3, 0, 0); zeroPageLayout->addMultiCellWidget(intent, 4, 4, 0, 0); zeroPageLayout->addMultiCellWidget(m_renderingIntentsCB, 4, 4, 1, 1); zeroPageLayout->setRowStretch(5, 10); //---------- "Input" Page Setup ---------------------------------- m_toolBoxWidgets->insertItem(INPUTPAGE, inProfiles, SmallIconSet("camera-photo"), i18n("Input Profile")); TQWhatsThis::add(inProfiles, i18n("

Set here all parameters relevant of Input Color " "Profiles.

")); TQGridLayout *firstPageLayout = new TQGridLayout(inProfiles, 4, 2); m_inProfileBG = new TQButtonGroup(4, TQt::Vertical, inProfiles); m_inProfileBG->setFrameStyle(TQFrame::NoFrame); m_inProfileBG->setInsideMargin(0); m_useEmbeddedProfile = new TQRadioButton(m_inProfileBG); m_useEmbeddedProfile->setText(i18n("Use embedded profile")); m_useSRGBDefaultProfile = new TQRadioButton(m_inProfileBG); m_useSRGBDefaultProfile->setText(i18n("Use builtin sRGB profile")); m_useSRGBDefaultProfile->setChecked(true); m_useInDefaultProfile = new TQRadioButton(m_inProfileBG); m_useInDefaultProfile->setText(i18n("Use default profile")); m_useInSelectedProfile = new TQRadioButton(m_inProfileBG); m_useInSelectedProfile->setText(i18n("Use selected profile")); m_inProfilesPath = new KURLRequester(inProfiles); m_inProfilesPath->setMode(KFile::File|KFile::ExistingOnly); m_inProfilesPath->setFilter("*.icc *.icm|"+i18n("ICC Files (*.icc; *.icm)")); KFileDialog *inProfiles_dialog = m_inProfilesPath->fileDialog(); m_iccInPreviewWidget = new ICCPreviewWidget(inProfiles_dialog); inProfiles_dialog->setPreviewWidget(m_iccInPreviewWidget); TQPushButton *inProfilesInfo = new TQPushButton(i18n("Info..."), inProfiles); TQGroupBox *pictureInfo = new TQGroupBox(2, TQt::Horizontal, i18n("Camera information"), inProfiles); new TQLabel(i18n("Make:"), pictureInfo); KSqueezedTextLabel *make = new KSqueezedTextLabel(0, pictureInfo); new TQLabel(i18n("Model:"), pictureInfo); KSqueezedTextLabel *model = new KSqueezedTextLabel(0, pictureInfo); make->setText(iface.getPhotographInformations().make); model->setText(iface.getPhotographInformations().model); firstPageLayout->addMultiCellWidget(m_inProfileBG, 0, 1, 0, 0); firstPageLayout->addMultiCellWidget(inProfilesInfo, 0, 0, 2, 2); firstPageLayout->addMultiCellWidget(m_inProfilesPath, 2, 2, 0, 2); firstPageLayout->addMultiCellWidget(pictureInfo, 3, 3, 0, 2); firstPageLayout->setColStretch(1, 10); firstPageLayout->setRowStretch(4, 10); //---------- "Workspace" Page Setup --------------------------------- m_toolBoxWidgets->insertItem(WORKSPACEPAGE, spaceProfiles, SmallIconSet("input-tablet"), i18n("Workspace Profile")); TQWhatsThis::add(spaceProfiles, i18n("

Set here all parameters relevant to Color Workspace " "Profiles.

")); TQGridLayout *secondPageLayout = new TQGridLayout(spaceProfiles, 3, 2); m_spaceProfileBG = new TQButtonGroup(2, TQt::Vertical, spaceProfiles); m_spaceProfileBG->setFrameStyle(TQFrame::NoFrame); m_spaceProfileBG->setInsideMargin(0); m_useSpaceDefaultProfile = new TQRadioButton(m_spaceProfileBG); m_useSpaceDefaultProfile->setText(i18n("Use default workspace profile")); m_useSpaceSelectedProfile = new TQRadioButton(m_spaceProfileBG); m_useSpaceSelectedProfile->setText(i18n("Use selected profile")); m_spaceProfilePath = new KURLRequester(spaceProfiles); m_spaceProfilePath->setMode(KFile::File|KFile::ExistingOnly); m_spaceProfilePath->setFilter("*.icc *.icm|"+i18n("ICC Files (*.icc; *.icm)")); KFileDialog *spaceProfiles_dialog = m_spaceProfilePath->fileDialog(); m_iccSpacePreviewWidget = new ICCPreviewWidget(spaceProfiles_dialog); spaceProfiles_dialog->setPreviewWidget(m_iccSpacePreviewWidget); TQPushButton *spaceProfilesInfo = new TQPushButton(i18n("Info..."), spaceProfiles); secondPageLayout->addMultiCellWidget(m_spaceProfileBG, 0, 1, 0, 0); secondPageLayout->addMultiCellWidget(spaceProfilesInfo, 0, 0, 2, 2); secondPageLayout->addMultiCellWidget(m_spaceProfilePath, 2, 2, 0, 2); secondPageLayout->setColStretch(1, 10); secondPageLayout->setRowStretch(3, 10); //---------- "Proofing" Page Setup --------------------------------- m_toolBoxWidgets->insertItem(PROOFINGPAGE, proofProfiles, SmallIconSet("printer"), i18n("Proofing Profile")); TQWhatsThis::add(proofProfiles, i18n("

Set here all parameters relevant to Proofing Color " "Profiles.

")); TQGridLayout *thirdPageLayout = new TQGridLayout(proofProfiles, 3, 2); m_proofProfileBG = new TQButtonGroup(2, TQt::Vertical, proofProfiles); m_proofProfileBG->setFrameStyle(TQFrame::NoFrame); m_proofProfileBG->setInsideMargin(0); m_useProofDefaultProfile = new TQRadioButton(m_proofProfileBG); m_useProofDefaultProfile->setText(i18n("Use default proof profile")); m_useProofSelectedProfile = new TQRadioButton(m_proofProfileBG); m_useProofSelectedProfile->setText(i18n("Use selected profile")); m_proofProfilePath = new KURLRequester(proofProfiles); m_proofProfilePath->setMode(KFile::File|KFile::ExistingOnly); m_proofProfilePath->setFilter("*.icc *.icm|"+i18n("ICC Files (*.icc; *.icm)")); KFileDialog *proofProfiles_dialog = m_proofProfilePath->fileDialog(); m_iccProofPreviewWidget = new ICCPreviewWidget(proofProfiles_dialog); proofProfiles_dialog->setPreviewWidget(m_iccProofPreviewWidget); TQPushButton *proofProfilesInfo = new TQPushButton(i18n("Info..."), proofProfiles); thirdPageLayout->addMultiCellWidget(m_proofProfileBG, 0, 1, 0, 0); thirdPageLayout->addMultiCellWidget(proofProfilesInfo, 0, 0, 2, 2); thirdPageLayout->addMultiCellWidget(m_proofProfilePath, 2, 2, 0, 2); thirdPageLayout->setColStretch(1, 10); thirdPageLayout->setRowStretch(3, 10); //---------- "Lightness" Page Setup ---------------------------------- m_toolBoxWidgets->insertItem(LIGHTNESSPAGE, lightnessadjust, SmallIconSet("blend"), i18n("Lightness Adjustments")); TQWhatsThis::add(lightnessadjust, i18n("

Set here all lightness adjustments to the target image.

")); TQGridLayout *fourPageLayout = new TQGridLayout( lightnessadjust, 5, 2); ColorGradientWidget* vGradient = new ColorGradientWidget(ColorGradientWidget::Vertical, 10, lightnessadjust ); vGradient->setColors(TQColor("white"), TQColor("black")); TQLabel *spacev = new TQLabel(lightnessadjust); spacev->setFixedWidth(1); m_curvesWidget = new CurvesWidget(256, 192, m_originalImage->bits(), m_originalImage->width(), m_originalImage->height(), m_originalImage->sixteenBit(), lightnessadjust); TQWhatsThis::add( m_curvesWidget, i18n("

This is the curve adjustment of the image luminosity")); TQLabel *spaceh = new TQLabel(lightnessadjust); spaceh->setFixedHeight(1); ColorGradientWidget *hGradient = new ColorGradientWidget(ColorGradientWidget::Horizontal, 10, lightnessadjust); hGradient->setColors(TQColor("black"), TQColor("white")); m_cInput = new RIntNumInput(lightnessadjust); m_cInput->input()->setLabel(i18n("Contrast:"), AlignLeft | AlignVCenter); m_cInput->setRange(-100, 100, 1); m_cInput->setDefaultValue(0); TQWhatsThis::add( m_cInput, i18n("

Set here the contrast adjustment of the image.")); fourPageLayout->addMultiCellWidget(vGradient, 0, 0, 0, 0); fourPageLayout->addMultiCellWidget(spacev, 0, 0, 1, 1); fourPageLayout->addMultiCellWidget(m_curvesWidget, 0, 0, 2, 2); fourPageLayout->addMultiCellWidget(spaceh, 1, 1, 2, 2); fourPageLayout->addMultiCellWidget(hGradient, 2, 2, 2, 2); fourPageLayout->addMultiCellWidget(m_cInput, 4, 4, 0, 2); // fourPageLayout->setRowSpacing(3); fourPageLayout->setRowStretch(5, 10); // ------------------------------------------------------------- gridSettings->addMultiCellWidget(m_toolBoxWidgets, 3, 3, 0, 2); setToolSettings(m_gboxSettings); m_gboxSettings->enableButton(EditorToolSettings::Ok, false); init(); // ------------------------------------------------------------- connect(lcmsLogoLabel, TQ_SIGNAL(leftClickedURL(const TQString&)), this, TQ_SLOT(processLCMSURL(const TQString&))); connect(m_channelCB, TQ_SIGNAL(activated(int)), this, TQ_SLOT(slotChannelChanged(int))); connect(m_scaleBG, TQ_SIGNAL(released(int)), this, TQ_SLOT(slotScaleChanged(int))); connect(m_curvesWidget, TQ_SIGNAL(signalCurvesChanged()), this, TQ_SLOT(slotTimer())); connect(m_cInput, TQ_SIGNAL(valueChanged (int)), this, TQ_SLOT(slotTimer())); connect(m_renderingIntentsCB, TQ_SIGNAL(activated(int)), this, TQ_SLOT(slotEffect())); //-- Check box options connections ------------------------------------------- connect(m_doSoftProofBox, TQ_SIGNAL(toggled (bool)), this, TQ_SLOT(slotEffect())); connect(m_checkGamutBox, TQ_SIGNAL(toggled (bool)), this, TQ_SLOT(slotEffect())); connect(m_BPCBox, TQ_SIGNAL(toggled (bool)), this, TQ_SLOT(slotEffect())); //-- Button Group ICC profile options connections ---------------------------- connect(m_inProfileBG, TQ_SIGNAL(released (int)), this, TQ_SLOT(slotEffect())); connect(m_spaceProfileBG, TQ_SIGNAL(released (int)), this, TQ_SLOT(slotEffect())); connect(m_proofProfileBG, TQ_SIGNAL(released (int)), this, TQ_SLOT(slotEffect())); //-- url requester ICC profile connections ----------------------------------- connect(m_inProfilesPath, TQ_SIGNAL(urlSelected(const TQString&)), this, TQ_SLOT(slotEffect())); connect(m_spaceProfilePath, TQ_SIGNAL(urlSelected(const TQString&)), this, TQ_SLOT(slotEffect())); connect(m_proofProfilePath, TQ_SIGNAL(urlSelected(const TQString&)), this, TQ_SLOT(slotEffect())); //-- Image preview widget connections ---------------------------- connect(m_previewWidget, TQ_SIGNAL(signalResized()), this, TQ_SLOT(slotEffect())); connect(m_previewWidget, TQ_SIGNAL(spotPositionChangedFromOriginal( const Digikam::DColor &, const TQPoint & )), this, TQ_SLOT(slotSpotColorChanged( const Digikam::DColor & ))); connect(m_previewWidget, TQ_SIGNAL(spotPositionChangedFromTarget( const Digikam::DColor &, const TQPoint & )), this, TQ_SLOT(slotColorSelectedFromTarget( const Digikam::DColor & ))); //-- ICC profile preview connections ----------------------------- connect(inProfilesInfo, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotInICCInfo())); connect(spaceProfilesInfo, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotSpaceICCInfo())); connect(proofProfilesInfo, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotProofICCInfo())); } ICCProofTool::~ICCProofTool() { if (m_destinationPreviewData) delete [] m_destinationPreviewData; } void ICCProofTool::readSettings() { TQString defaultICCPath = TDEGlobalSettings::documentPath(); TDEConfig* config = kapp->config(); // General settings of digiKam Color Management config->setGroup("Color Management"); if (!config->readBoolEntry("EnableCM", false)) { m_cmEnabled = false; slotToggledWidgets(false); } else { m_inPath = config->readPathEntry("InProfileFile"); m_spacePath = config->readPathEntry("WorkProfileFile"); m_proofPath = config->readPathEntry("ProofProfileFile"); if (TQFile::exists(config->readPathEntry("DefaultPath"))) { defaultICCPath = config->readPathEntry("DefaultPath"); } else { TQString message = i18n("The ICC profiles path seems to be invalid. You won't be able to use the \"Default profile\"\ options.

Please fix this in the digiKam ICC setup."); slotToggledWidgets( false ); KMessageBox::information(kapp->activeWindow(), message); } } // Plugin settings. config->setGroup("colormanagement Tool"); m_channelCB->setCurrentItem(config->readNumEntry("Histogram Channel", 0)); // Luminosity. m_scaleBG->setButton(config->readNumEntry("Histogram Scale", HistogramWidget::LogScaleHistogram)); m_toolBoxWidgets->setCurrentIndex(config->readNumEntry("Settings Tab", GENERALPAGE)); m_inProfilesPath->setURL(config->readPathEntry("InputProfilePath", defaultICCPath)); m_proofProfilePath->setURL(config->readPathEntry("ProofProfilePath", defaultICCPath)); m_spaceProfilePath->setURL(config->readPathEntry("SpaceProfilePath", defaultICCPath)); m_renderingIntentsCB->setCurrentItem(config->readNumEntry("RenderingIntent", m_renderingIntentsCB->defaultItem())); m_doSoftProofBox->setChecked(config->readBoolEntry("DoSoftProof", false)); m_checkGamutBox->setChecked(config->readBoolEntry("CheckGamut", false)); m_embeddProfileBox->setChecked(config->readBoolEntry("EmbeddProfile", true)); m_BPCBox->setChecked(config->readBoolEntry("BPC", true)); m_inProfileBG->setButton(config->readNumEntry("InputProfileMethod", 0)); m_spaceProfileBG->setButton(config->readNumEntry("SpaceProfileMethod", 0)); m_proofProfileBG->setButton(config->readNumEntry("ProofProfileMethod", 0)); m_cInput->setValue(config->readNumEntry("ContrastAjustment", m_cInput->defaultValue())); for (int i = 0 ; i < 5 ; i++) m_curvesWidget->curves()->curvesChannelReset(i); m_curvesWidget->curves()->setCurveType(m_curvesWidget->m_channelType, ImageCurves::CURVE_SMOOTH); m_curvesWidget->reset(); for (int j = 0 ; j < 17 ; j++) { TQPoint disable(-1, -1); TQPoint p = config->readPointEntry(TQString("CurveAjustmentPoint%1").arg(j), &disable); if (m_originalImage->sixteenBit() && p.x() != -1) { p.setX(p.x()*255); p.setY(p.y()*255); } m_curvesWidget->curves()->setCurvePoint(ImageHistogram::ValueChannel, j, p); } for (int i = 0 ; i < 5 ; i++) m_curvesWidget->curves()->curvesCalculateCurve(i); m_histogramWidget->reset(); slotChannelChanged(m_channelCB->currentItem()); slotScaleChanged(m_scaleBG->selectedId()); } void ICCProofTool::writeSettings() { TDEConfig* config = kapp->config(); config->setGroup("colormanagement Tool"); config->writeEntry("Settings Tab", m_toolBoxWidgets->currentIndex()); config->writeEntry("Histogram Channel", m_channelCB->currentItem()); config->writeEntry("Histogram Scale", m_scaleBG->selectedId()); config->writePathEntry("InputProfilePath", m_inProfilesPath->url()); config->writePathEntry("ProofProfilePath", m_proofProfilePath->url()); config->writePathEntry("SpaceProfilePath", m_spaceProfilePath->url()); config->writeEntry("RenderingIntent", m_renderingIntentsCB->currentItem()); config->writeEntry("DoSoftProof", m_doSoftProofBox->isChecked()); config->writeEntry("CheckGamut", m_checkGamutBox->isChecked()); config->writeEntry("EmbeddProfile", m_embeddProfileBox->isChecked()); config->writeEntry("BPC", m_BPCBox->isChecked()); config->writeEntry("InputProfileMethod", m_inProfileBG->selectedId()); config->writeEntry("SpaceProfileMethod", m_spaceProfileBG->selectedId()); config->writeEntry("ProofProfileMethod", m_proofProfileBG->selectedId()); config->writeEntry("ContrastAjustment", m_cInput->value()); for (int j = 0; j < 17; j++) { TQPoint p = m_curvesWidget->curves()->getCurvePoint(ImageHistogram::ValueChannel, j); if (m_originalImage->sixteenBit() && p.x() != -1) { p.setX(p.x() / 255); p.setY(p.y() / 255); } config->writeEntry(TQString("CurveAjustmentPoint%1").arg(j), p); } m_previewWidget->writeSettings(); config->sync(); } void ICCProofTool::processLCMSURL(const TQString& url) { TDEApplication::kApplication()->invokeBrowser(url); } void ICCProofTool::slotSpotColorChanged(const DColor &color) { m_curvesWidget->setCurveGuide(color); } void ICCProofTool::slotColorSelectedFromTarget( const DColor &color ) { m_histogramWidget->setHistogramGuideByColor(color); } void ICCProofTool::slotChannelChanged( int channel ) { switch (channel) { case LuminosityChannel: m_histogramWidget->m_channelType = HistogramWidget::ValueHistogram; m_hGradient->setColors(TQColor("black"), TQColor("white")); break; case RedChannel: m_histogramWidget->m_channelType = HistogramWidget::RedChannelHistogram; m_hGradient->setColors(TQColor("black"), TQColor("red")); break; case GreenChannel: m_histogramWidget->m_channelType = HistogramWidget::GreenChannelHistogram; m_hGradient->setColors(TQColor("black"), TQColor("green")); break; case BlueChannel: m_histogramWidget->m_channelType = HistogramWidget::BlueChannelHistogram; m_hGradient->setColors(TQColor("black"), TQColor("blue")); break; } m_histogramWidget->repaint(false); } void ICCProofTool::slotScaleChanged(int scale) { m_histogramWidget->m_scaleType = scale; m_histogramWidget->repaint(false); } void ICCProofTool::slotResetSettings() { m_cInput->blockSignals(true); m_renderingIntentsCB->blockSignals(true); m_cInput->slotReset(); m_renderingIntentsCB->slotReset(); for (int i = 0 ; i < 5 ; i++) m_curvesWidget->curves()->curvesChannelReset(i); m_curvesWidget->reset(); m_cInput->blockSignals(false); m_renderingIntentsCB->blockSignals(false); } void ICCProofTool::slotEffect() { kapp->setOverrideCursor(KCursor::waitCursor()); m_gboxSettings->enableButton(EditorToolSettings::Ok, true); m_histogramWidget->stopHistogramComputation(); IccTransform transform; if (m_destinationPreviewData) delete [] m_destinationPreviewData; ImageIface *iface = m_previewWidget->imageIface(); m_destinationPreviewData = iface->getPreviewImage(); int w = iface->previewWidth(); int h = iface->previewHeight(); bool a = iface->previewHasAlpha(); bool sb = iface->previewSixteenBit(); DImg preview(w, h, sb, a, m_destinationPreviewData); TQString tmpInPath = TQString(); TQString tmpProofPath = TQString(); TQString tmpSpacePath = TQString(); bool proofCondition = false; bool spaceCondition = false; //-- Input profile parameters ------------------ if (useDefaultInProfile()) { tmpInPath = m_inPath; } else if (useSelectedInProfile()) { tmpInPath = m_inProfilesPath->url(); TQFileInfo info(tmpInPath); if (!info.exists() || !info.isReadable() || !info.isFile()) { KMessageBox::information(kapp->activeWindow(), i18n("

The selected ICC input profile path seems to be invalid.

" "Please check it.")); return; } } //-- Proof profile parameters ------------------ if (useDefaultProofProfile()) { tmpProofPath = m_proofPath; } else { tmpProofPath = m_proofProfilePath->url(); TQFileInfo info(tmpProofPath); if (!info.exists() || !info.isReadable() || !info.isFile()) { KMessageBox::information(kapp->activeWindow(), i18n("

The selected ICC proof profile path seems to be invalid.

" "Please check it.")); return; } } if (m_doSoftProofBox->isChecked()) proofCondition = tmpProofPath.isEmpty(); //-- Workspace profile parameters -------------- if (useDefaultSpaceProfile()) { tmpSpacePath = m_spacePath; } else { tmpSpacePath = m_spaceProfilePath->url(); TQFileInfo info(tmpSpacePath); if (!info.exists() || !info.isReadable() || !info.isFile()) { KMessageBox::information(kapp->activeWindow(), i18n("

Selected ICC workspace profile path seems to be invalid.

" "Please check it.")); return; } } spaceCondition = tmpSpacePath.isEmpty(); //-- Perform the color transformations ------------------ transform.getTransformType(m_doSoftProofBox->isChecked()); if (m_doSoftProofBox->isChecked()) { if (m_useEmbeddedProfile->isChecked()) { transform.setProfiles(tmpSpacePath, tmpProofPath, true); } else { transform.setProfiles(tmpInPath, tmpSpacePath, tmpProofPath); } } else { if (m_useEmbeddedProfile->isChecked()) { transform.setProfiles(tmpSpacePath); } else { transform.setProfiles(tmpInPath, tmpSpacePath); } } if ( proofCondition || spaceCondition ) { kapp->restoreOverrideCursor(); TQString error = i18n("

Your settings are not sufficient.

" "

To apply a color transform, you need at least two ICC profiles:

" "
  • An \"Input\" profile.
  • " "
  • A \"Workspace\" profile.
" "

If you want to do a \"soft-proof\" transform, in addition to these profiles " "you need a \"Proof\" profile.

"); KMessageBox::information(kapp->activeWindow(), error); m_gboxSettings->enableButton(EditorToolSettings::Ok, false); } else { if (m_useEmbeddedProfile->isChecked()) { transform.apply(preview, m_embeddedICC, m_renderingIntentsCB->currentItem(), useBPC(), m_checkGamutBox->isChecked(), useBuiltinProfile()); } else { TQByteArray fakeProfile = TQByteArray(); transform.apply(preview, fakeProfile, m_renderingIntentsCB->currentItem(), useBPC(), m_checkGamutBox->isChecked(), useBuiltinProfile()); } //-- Calculate and apply the curve on image after transformation ------------- DImg preview2(w, h, sb, a, 0, false); m_curvesWidget->curves()->curvesLutSetup(ImageHistogram::AlphaChannel); m_curvesWidget->curves()->curvesLutProcess(preview.bits(), preview2.bits(), w, h); //-- Adjust contrast --------------------------------------------------------- BCGModifier cmod; cmod.setContrast((double)(m_cInput->value()/100.0) + 1.00); cmod.applyBCG(preview2); iface->putPreviewImage(preview2.bits()); m_previewWidget->updatePreview(); //-- Update histogram -------------------------------------------------------- memcpy(m_destinationPreviewData, preview2.bits(), preview2.numBytes()); m_histogramWidget->updateData(m_destinationPreviewData, w, h, sb, 0, 0, 0, false); kapp->restoreOverrideCursor(); } } void ICCProofTool::finalRendering() { if (!m_doSoftProofBox->isChecked()) { kapp->setOverrideCursor( KCursor::waitCursor() ); ImageIface *iface = m_previewWidget->imageIface(); uchar *data = iface->getOriginalImage(); int w = iface->originalWidth(); int h = iface->originalHeight(); bool a = iface->originalHasAlpha(); bool sb = iface->originalSixteenBit(); if (data) { IccTransform transform; DImg img(w, h, sb, a, data); TQString tmpInPath; TQString tmpProofPath; TQString tmpSpacePath; bool proofCondition; //-- Input profile parameters ------------------ if (useDefaultInProfile()) { tmpInPath = m_inPath; } else if (useSelectedInProfile()) { tmpInPath = m_inProfilesPath->url(); TQFileInfo info(tmpInPath); if (!info.exists() || !info.isReadable() || !info.isFile()) { KMessageBox::information(kapp->activeWindow(), i18n("

Selected ICC input profile path seems " "to be invalid.

Please check it.")); return; } } //-- Proof profile parameters ------------------ if (useDefaultProofProfile()) { tmpProofPath = m_proofPath; } else { tmpProofPath = m_proofProfilePath->url(); TQFileInfo info(tmpProofPath); if (!info.exists() || !info.isReadable() || !info.isFile()) { KMessageBox::information(kapp->activeWindow(), i18n("

The selected ICC proof profile path seems " "to be invalid.

Please check it.")); return; } } if (tmpProofPath.isNull()) proofCondition = false; //-- Workspace profile parameters -------------- if (useDefaultSpaceProfile()) { tmpSpacePath = m_spacePath; } else { tmpSpacePath = m_spaceProfilePath->url(); TQFileInfo info(tmpSpacePath); if (!info.exists() || !info.isReadable() || !info.isFile()) { KMessageBox::information(kapp->activeWindow(), i18n("

Selected ICC workspace profile path seems " "to be invalid.

Please check it.")); return; } } //-- Perform the color transformations ------------------ transform.getTransformType(m_doSoftProofBox->isChecked()); if (m_doSoftProofBox->isChecked()) { if (m_useEmbeddedProfile->isChecked()) { transform.setProfiles( tmpSpacePath, tmpProofPath, true ); } else { transform.setProfiles( tmpInPath, tmpSpacePath, tmpProofPath); } } else { if (m_useEmbeddedProfile->isChecked()) { transform.setProfiles( tmpSpacePath ); } else { transform.setProfiles( tmpInPath, tmpSpacePath ); } } if (m_useEmbeddedProfile->isChecked()) { transform.apply(img, m_embeddedICC, m_renderingIntentsCB->currentItem(), useBPC(), m_checkGamutBox->isChecked(), useBuiltinProfile()); } else { TQByteArray fakeProfile = TQByteArray(); transform.apply(img, fakeProfile, m_renderingIntentsCB->currentItem(), useBPC(), m_checkGamutBox->isChecked(), useBuiltinProfile()); } //-- Embed the workspace profile if necessary -------------------------------- if (m_embeddProfileBox->isChecked()) { iface->setEmbeddedICCToOriginalImage(tmpSpacePath); DDebug() << k_funcinfo << TQFile::encodeName(tmpSpacePath) << endl; } //-- Calculate and apply the curve on image after transformation ------------- DImg img2(w, h, sb, a, 0, false); m_curvesWidget->curves()->curvesLutSetup(ImageHistogram::AlphaChannel); m_curvesWidget->curves()->curvesLutProcess(img.bits(), img2.bits(), w, h); //-- Adjust contrast --------------------------------------------------------- BCGModifier cmod; cmod.setContrast((double)(m_cInput->value()/100.0) + 1.00); cmod.applyBCG(img2); iface->putOriginalImage("Color Management", img2.bits()); delete [] data; } kapp->restoreOverrideCursor(); } } void ICCProofTool::slotToggledWidgets( bool t) { m_useInDefaultProfile->setEnabled(t); m_useProofDefaultProfile->setEnabled(t); m_useSpaceDefaultProfile->setEnabled(t); } void ICCProofTool::slotInICCInfo() { if (useEmbeddedProfile()) { getICCInfo(m_embeddedICC); } else if (useBuiltinProfile()) { TQString message = i18n("

You have selected the \"Default builtin sRGB profile\"

"); message.append(i18n("

This profile is built on the fly, so there is no relevant information " "about it.

")); KMessageBox::information(kapp->activeWindow(), message); } else if (useDefaultInProfile()) { getICCInfo(m_inPath); } else if (useSelectedInProfile()) { getICCInfo(m_inProfilesPath->url()); } } void ICCProofTool::slotProofICCInfo() { if (useDefaultProofProfile()) { getICCInfo(m_proofPath); } else { getICCInfo(m_proofProfilePath->url()); } } void ICCProofTool::slotSpaceICCInfo() { if (useDefaultSpaceProfile()) { getICCInfo(m_spacePath); } else { getICCInfo(m_spaceProfilePath->url()); } } void ICCProofTool::getICCInfo(const TQString& profile) { if (profile.isEmpty()) { KMessageBox::error(kapp->activeWindow(), i18n("Sorry, there is no selected profile"), i18n("Profile Error")); return; } ICCProfileInfoDlg infoDlg(kapp->activeWindow(), profile); infoDlg.exec(); } void ICCProofTool::getICCInfo(const TQByteArray& profile) { if (profile.isNull()) { KMessageBox::error(kapp->activeWindow(), i18n("Sorry, it seems there is no embedded profile"), i18n("Profile Error")); return; } ICCProfileInfoDlg infoDlg(kapp->activeWindow(), TQString(), profile); infoDlg.exec(); } void ICCProofTool::slotCMDisabledWarning() { if (!m_cmEnabled) { TQString message = i18n("

You have not enabled Color Management in the digiKam preferences.

"); message.append(i18n("

\"Use of default profile\" options will be disabled now.

")); KMessageBox::information(kapp->activeWindow(), message); slotToggledWidgets(false); } } //-- General Tab --------------------------- bool ICCProofTool::useBPC() { return m_BPCBox->isChecked(); } bool ICCProofTool::doProof() { return m_doSoftProofBox->isChecked(); } bool ICCProofTool::checkGamut() { return m_checkGamutBox->isChecked(); } bool ICCProofTool::embedProfile() { return m_embeddProfileBox->isChecked(); } //-- Input Tab --------------------------- bool ICCProofTool::useEmbeddedProfile() { return m_useEmbeddedProfile->isChecked(); } bool ICCProofTool::useBuiltinProfile() { return m_useSRGBDefaultProfile->isChecked(); } bool ICCProofTool::useDefaultInProfile() { return m_useInDefaultProfile->isChecked(); } bool ICCProofTool::useSelectedInProfile() { return m_useInSelectedProfile->isChecked(); } //-- Workspace Tab --------------------------- bool ICCProofTool::useDefaultSpaceProfile() { return m_useSpaceDefaultProfile->isChecked(); } //-- Proofing Tab --------------------------- bool ICCProofTool::useDefaultProofProfile() { return m_useProofDefaultProfile->isChecked(); } //-- Load all settings from file -------------------------------------- void ICCProofTool::slotLoadSettings() { KURL loadColorManagementFile = KFileDialog::getOpenURL(TDEGlobalSettings::documentPath(), TQString("*"), kapp->activeWindow(), TQString(i18n("Color Management Settings File to Load"))); if (loadColorManagementFile.isEmpty()) return; TQFile file(loadColorManagementFile.path()); if (file.open(IO_ReadOnly)) { TQTextStream stream(&file); if (stream.readLine() != "# Color Management Configuration File") { KMessageBox::error(kapp->activeWindow(), i18n("\"%1\" is not a Color Management settings text file.") .arg(loadColorManagementFile.fileName())); file.close(); return; } blockSignals(true); m_renderingIntentsCB->setCurrentItem(stream.readLine().toInt()); m_doSoftProofBox->setChecked((bool) (stream.readLine().toUInt())); m_checkGamutBox->setChecked((bool) (stream.readLine().toUInt())); m_embeddProfileBox->setChecked((bool) (stream.readLine().toUInt())); m_BPCBox->setChecked((bool) (stream.readLine().toUInt())); m_inProfileBG->setButton(stream.readLine().toInt()); m_spaceProfileBG->setButton(stream.readLine().toInt()); m_proofProfileBG->setButton(stream.readLine().toInt()); m_inProfilesPath->setURL(stream.readLine()); m_proofProfilePath->setURL(stream.readLine()); m_spaceProfilePath->setURL(stream.readLine()); m_cInput->setValue(stream.readLine().toInt()); for (int i = 0 ; i < 5 ; i++) m_curvesWidget->curves()->curvesChannelReset(i); m_curvesWidget->curves()->setCurveType(m_curvesWidget->m_channelType, ImageCurves::CURVE_SMOOTH); m_curvesWidget->reset(); for (int j = 0; j < 17; j++) { TQPoint disable(-1, -1); TQPoint p; p.setX(stream.readLine().toInt()); p.setY(stream.readLine().toInt()); if (m_originalImage->sixteenBit() && p != disable) { p.setX(p.x() * 255); p.setY(p.y() * 255); } m_curvesWidget->curves()->setCurvePoint(ImageHistogram::ValueChannel, j, p); } blockSignals(false); for (int i = 0 ; i < 5 ; i++) m_curvesWidget->curves()->curvesCalculateCurve(i); m_histogramWidget->reset(); slotEffect(); } else KMessageBox::error(kapp->activeWindow(), i18n("Cannot load settings from the Color Management text file.")); file.close(); } //-- Save all settings to file --------------------------------------- void ICCProofTool::slotSaveAsSettings() { KURL saveColorManagementFile = KFileDialog::getSaveURL(TDEGlobalSettings::documentPath(), TQString( "*" ), kapp->activeWindow(), TQString(i18n("Color Management Settings File to Save"))); if (saveColorManagementFile.isEmpty()) return; TQFile file(saveColorManagementFile.path()); if (file.open(IO_WriteOnly)) { TQTextStream stream(&file); stream << "# Color Management Configuration File\n"; stream << m_renderingIntentsCB->currentItem() << "\n"; stream << m_doSoftProofBox->isChecked() << "\n"; stream << m_checkGamutBox->isChecked() << "\n"; stream << m_embeddProfileBox->isChecked() << "\n"; stream << m_BPCBox->isChecked() << "\n"; stream << m_inProfileBG->selectedId() << "\n"; stream << m_spaceProfileBG->selectedId() << "\n"; stream << m_proofProfileBG->selectedId() << "\n"; stream << m_inProfilesPath->url() << "\n"; stream << m_proofProfilePath->url() << "\n"; stream << m_spaceProfilePath->url() << "\n"; stream << m_cInput->value() << "\n"; for (int j = 0; j < 17; j++) { TQPoint p = m_curvesWidget->curves()->getCurvePoint(ImageHistogram::ValueChannel, j); if (m_originalImage->sixteenBit()) { p.setX(p.x() / 255); p.setY(p.y() / 255); } stream << p.x() << "\n"; stream << p.y() << "\n"; } } else KMessageBox::error(kapp->activeWindow(), i18n("Cannot save settings to the Color Management text file.")); file.close(); } } // NameSpace DigikamImagesPluginCore