summaryrefslogtreecommitdiffstats
path: root/src/utilities/imageeditor/tools/imageresize.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/utilities/imageeditor/tools/imageresize.cpp')
-rw-r--r--src/utilities/imageeditor/tools/imageresize.cpp650
1 files changed, 650 insertions, 0 deletions
diff --git a/src/utilities/imageeditor/tools/imageresize.cpp b/src/utilities/imageeditor/tools/imageresize.cpp
new file mode 100644
index 00000000..c779b71e
--- /dev/null
+++ b/src/utilities/imageeditor/tools/imageresize.cpp
@@ -0,0 +1,650 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2005-04-07
+ * Description : a tool to resize an image
+ *
+ * Copyright (C) 2005-2009 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.
+ *
+ * ============================================================ */
+
+// C++ includes.
+
+#include <cmath>
+
+// TQt includes.
+
+#include <tqvgroupbox.h>
+#include <tqlabel.h>
+#include <tqpushbutton.h>
+#include <tqtooltip.h>
+#include <tqwhatsthis.h>
+#include <tqlayout.h>
+#include <tqframe.h>
+#include <tqcheckbox.h>
+#include <tqcombobox.h>
+#include <tqtabwidget.h>
+#include <tqtimer.h>
+#include <tqevent.h>
+#include <tqpixmap.h>
+#include <tqbrush.h>
+#include <tqfile.h>
+#include <tqimage.h>
+
+// KDE includes.
+
+#include <kseparator.h>
+#include <kcursor.h>
+#include <kurllabel.h>
+#include <tdelocale.h>
+#include <kiconloader.h>
+#include <tdeapplication.h>
+#include <tdefiledialog.h>
+#include <kstandarddirs.h>
+#include <kprogress.h>
+#include <tdemessagebox.h>
+#include <knuminput.h>
+#include <tdeglobalsettings.h>
+
+// LibKDcraw includes.
+
+#include <libkdcraw/rnuminput.h>
+
+// Digikam includes.
+
+#include "dimg.h"
+#include "ddebug.h"
+#include "imageiface.h"
+#include "dimgthreadedfilter.h"
+#include "greycstorationiface.h"
+#include "greycstorationwidget.h"
+#include "greycstorationsettings.h"
+
+// Local includes.
+
+#include "imageresize.h"
+#include "imageresize.moc"
+
+using namespace KDcrawIface;
+
+namespace Digikam
+{
+
+class ImageResizePriv
+{
+public:
+
+ enum RunningMode
+ {
+ NoneRendering=0,
+ FinalRendering
+ };
+
+ ImageResizePriv()
+ {
+ currentRenderingMode = NoneRendering;
+ parent = 0;
+ preserveRatioBox = 0;
+ useGreycstorationBox = 0;
+ mainTab = 0;
+ wInput = 0;
+ hInput = 0;
+ wpInput = 0;
+ hpInput = 0;
+ progressBar = 0;
+ greycstorationIface = 0;
+ settingsWidget = 0;
+ cimgLogoLabel = 0;
+ restorationTips = 0;
+ }
+
+ int currentRenderingMode;
+ int orgWidth;
+ int orgHeight;
+ int prevW;
+ int prevH;
+
+ double prevWP;
+ double prevHP;
+
+ TQWidget *parent;
+
+ TQLabel *restorationTips;
+
+ TQCheckBox *preserveRatioBox;
+ TQCheckBox *useGreycstorationBox;
+
+ TQTabWidget *mainTab;
+
+ RIntNumInput *wInput;
+ RIntNumInput *hInput;
+
+ RDoubleNumInput *wpInput;
+ RDoubleNumInput *hpInput;
+
+ KProgress *progressBar;
+
+ KURLLabel *cimgLogoLabel;
+
+ GreycstorationIface *greycstorationIface;
+ GreycstorationWidget *settingsWidget;
+};
+
+ImageResize::ImageResize(TQWidget* parent)
+ : KDialogBase(Plain, i18n("Resize Image"),
+ Help|Default|User2|User3|Ok|Cancel, Ok,
+ parent, 0, true, false,
+ TQString(),
+ i18n("&Save As..."),
+ i18n("&Load..."))
+{
+ d = new ImageResizePriv;
+ d->parent = parent;
+ setHelp("resizetool.anchor", "digikam");
+ TQString whatsThis;
+ setButtonWhatsThis( Default, i18n("<p>Reset all filter parameters to their default values.") );
+ setButtonWhatsThis( User3, i18n("<p>Load all filter parameters from settings text file.") );
+ setButtonWhatsThis( User2, i18n("<p>Save all filter parameters to settings text file.") );
+ enableButton(Ok, false);
+
+ ImageIface iface(0, 0);
+ d->orgWidth = iface.originalWidth();
+ d->orgHeight = iface.originalHeight();
+ d->prevW = d->orgWidth;
+ d->prevH = d->orgHeight;
+ d->prevWP = 100.0;
+ d->prevHP = 100.0;
+
+ // -------------------------------------------------------------
+
+ TQVBoxLayout *vlay = new TQVBoxLayout(plainPage(), 0, spacingHint());
+ d->mainTab = new TQTabWidget( plainPage() );
+
+ TQWidget* firstPage = new TQWidget( d->mainTab );
+ TQGridLayout* grid = new TQGridLayout( firstPage, 8, 2, spacingHint());
+ d->mainTab->addTab( firstPage, i18n("New Size") );
+
+ TQLabel *label1 = new TQLabel(i18n("Width:"), firstPage);
+ d->wInput = new RIntNumInput(firstPage);
+ d->wInput->setRange(1, TQMAX(d->orgWidth * 10, 9999), 1);
+ d->wInput->setName("d->wInput");
+ d->wInput->setDefaultValue(d->orgWidth);
+ TQWhatsThis::add( d->wInput, i18n("<p>Set here the new image width in pixels."));
+
+ TQLabel *label2 = new TQLabel(i18n("Height:"), firstPage);
+ d->hInput = new RIntNumInput(firstPage);
+ d->hInput->setRange(1, TQMAX(d->orgHeight * 10, 9999), 1);
+ d->hInput->setName("d->hInput");
+ d->hInput->setDefaultValue(d->orgHeight);
+ TQWhatsThis::add( d->hInput, i18n("<p>Set here the new image height in pixels."));
+
+ TQLabel *label3 = new TQLabel(i18n("Width (%):"), firstPage);
+ d->wpInput = new RDoubleNumInput(firstPage);
+ d->wpInput->setRange(1.0, 999.0, 1.0);
+ d->wpInput->setName("d->wpInput");
+ d->wpInput->setDefaultValue(100.0);
+ TQWhatsThis::add( d->wpInput, i18n("<p>Set here the new image width in percent."));
+
+ TQLabel *label4 = new TQLabel(i18n("Height (%):"), firstPage);
+ d->hpInput = new RDoubleNumInput(firstPage);
+ d->hpInput->setRange(1.0, 999.0, 1.0);
+ d->hpInput->setName("d->hpInput");
+ d->hpInput->setDefaultValue(100.0);
+ TQWhatsThis::add( d->hpInput, i18n("<p>Set here the new image height in percent."));
+
+ d->preserveRatioBox = new TQCheckBox(i18n("Maintain aspect ratio"), firstPage);
+ TQWhatsThis::add( d->preserveRatioBox, i18n("<p>Enable this option to maintain aspect "
+ "ratio with new image sizes."));
+
+ d->cimgLogoLabel = new KURLLabel(firstPage);
+ d->cimgLogoLabel->setText(TQString());
+ d->cimgLogoLabel->setURL("http://cimg.sourceforge.net");
+ TDEGlobal::dirs()->addResourceType("logo-cimg", TDEGlobal::dirs()->kde_default("data") +
+ "digikam/data");
+ TQString directory = TDEGlobal::dirs()->findResourceDir("logo-cimg", "logo-cimg.png");
+ d->cimgLogoLabel->setPixmap( TQPixmap( directory + "logo-cimg.png" ) );
+ TQToolTip::add(d->cimgLogoLabel, i18n("Visit CImg library website"));
+
+ d->useGreycstorationBox = new TQCheckBox(i18n("Restore photograph"), firstPage);
+ TQWhatsThis::add( d->useGreycstorationBox, i18n("<p>Enable this option to restore photograph content. "
+ "This way is usefull to scale-up an image to an huge size. "
+ "Warning: this process can take a while."));
+
+ d->restorationTips = new TQLabel(i18n("<b>Note: use Restoration Mode to only scale-up an image to huge size. "
+ "Warning, this process can take a while.</b>"), firstPage);
+
+ d->progressBar = new KProgress(100, firstPage);
+ d->progressBar->setValue(0);
+ TQWhatsThis::add(d->progressBar, i18n("<p>This shows the current progress when you use Restoration mode."));
+
+ grid->addMultiCellWidget(d->preserveRatioBox, 0, 0, 0, 2);
+ grid->addMultiCellWidget(label1, 1, 1, 0, 0);
+ grid->addMultiCellWidget(d->wInput, 1, 1, 1, 2);
+ grid->addMultiCellWidget(label2, 2, 2, 0, 0);
+ grid->addMultiCellWidget(d->hInput, 2, 2, 1, 2);
+ grid->addMultiCellWidget(label3, 3, 3, 0, 0);
+ grid->addMultiCellWidget(d->wpInput, 3, 3, 1, 2);
+ grid->addMultiCellWidget(label4, 4, 4, 0, 0);
+ grid->addMultiCellWidget(d->hpInput, 4, 4, 1, 2);
+ grid->addMultiCellWidget(new KSeparator(firstPage), 5, 5, 0, 2);
+ grid->addMultiCellWidget(d->cimgLogoLabel, 6, 8, 0, 0);
+ grid->addMultiCellWidget(d->useGreycstorationBox, 6, 6, 1, 2);
+ grid->addMultiCellWidget(d->restorationTips, 7, 7, 1, 2);
+ grid->addMultiCellWidget(d->progressBar, 8, 8, 1, 2);
+ grid->setRowStretch(8, 10);
+
+ // -------------------------------------------------------------
+
+ d->settingsWidget = new GreycstorationWidget(d->mainTab);
+ vlay->addWidget(d->mainTab);
+
+ // -------------------------------------------------------------
+
+ adjustSize();
+ disableResize();
+ TQTimer::singleShot(0, this, TQ_SLOT(readUserSettings()));
+
+ // -------------------------------------------------------------
+
+ connect(d->cimgLogoLabel, TQ_SIGNAL(leftClickedURL(const TQString&)),
+ this, TQ_SLOT(processCImgURL(const TQString&)));
+
+ connect(d->wInput, TQ_SIGNAL(valueChanged(int)),
+ this, TQ_SLOT(slotValuesChanged()));
+
+ connect(d->hInput, TQ_SIGNAL(valueChanged(int)),
+ this, TQ_SLOT(slotValuesChanged()));
+
+ connect(d->wpInput, TQ_SIGNAL(valueChanged(double)),
+ this, TQ_SLOT(slotValuesChanged()));
+
+ connect(d->hpInput, TQ_SIGNAL(valueChanged(double)),
+ this, TQ_SLOT(slotValuesChanged()));
+
+ connect(d->useGreycstorationBox, TQ_SIGNAL(toggled(bool)),
+ this, TQ_SLOT(slotRestorationToggled(bool)) );
+
+ // -------------------------------------------------------------
+
+ Digikam::GreycstorationSettings defaults;
+ defaults.setResizeDefaultSettings();
+ d->settingsWidget->setDefaultSettings(defaults);
+}
+
+ImageResize::~ImageResize()
+{
+ if (d->greycstorationIface)
+ delete d->greycstorationIface;
+
+ delete d;
+}
+
+void ImageResize::slotRestorationToggled(bool b)
+{
+ d->settingsWidget->setEnabled(b);
+ d->progressBar->setEnabled(b);
+ d->cimgLogoLabel->setEnabled(b);
+ enableButton(User2, b);
+ enableButton(User3, b);
+}
+
+void ImageResize::readUserSettings()
+{
+ TDEConfig* config = kapp->config();
+ config->setGroup("resize Tool Dialog");
+
+ GreycstorationSettings settings;
+ GreycstorationSettings defaults;
+ defaults.setResizeDefaultSettings();
+
+ settings.fastApprox = config->readBoolEntry("FastApprox", defaults.fastApprox);
+ settings.interp = config->readNumEntry("Interpolation", defaults.interp);
+ settings.amplitude = config->readDoubleNumEntry("Amplitude", defaults.amplitude);
+ settings.sharpness = config->readDoubleNumEntry("Sharpness", defaults.sharpness);
+ settings.anisotropy = config->readDoubleNumEntry("Anisotropy", defaults.anisotropy);
+ settings.alpha = config->readDoubleNumEntry("Alpha", defaults.alpha);
+ settings.sigma = config->readDoubleNumEntry("Sigma", defaults.sigma);
+ settings.gaussPrec = config->readDoubleNumEntry("GaussPrec", defaults.gaussPrec);
+ settings.dl = config->readDoubleNumEntry("Dl", defaults.dl);
+ settings.da = config->readDoubleNumEntry("Da", defaults.da);
+ settings.nbIter = config->readNumEntry("Iteration", defaults.nbIter);
+ settings.tile = config->readNumEntry("Tile", defaults.tile);
+ settings.btile = config->readNumEntry("BTile", defaults.btile);
+ d->settingsWidget->setSettings(settings);
+
+ d->useGreycstorationBox->setChecked(config->readBoolEntry("RestorePhotograph", false));
+ slotRestorationToggled(d->useGreycstorationBox->isChecked());
+
+ d->preserveRatioBox->blockSignals(true);
+ d->wInput->blockSignals(true);
+ d->hInput->blockSignals(true);
+ d->wpInput->blockSignals(true);
+ d->hpInput->blockSignals(true);
+
+ d->preserveRatioBox->setChecked(true);
+ d->wInput->slotReset();
+ d->hInput->slotReset();
+ d->wpInput->slotReset();
+ d->hpInput->slotReset();
+
+ d->preserveRatioBox->blockSignals(false);
+ d->wInput->blockSignals(false);
+ d->hInput->blockSignals(false);
+ d->wpInput->blockSignals(false);
+ d->hpInput->blockSignals(false);
+}
+
+void ImageResize::writeUserSettings()
+{
+ GreycstorationSettings settings = d->settingsWidget->getSettings();
+ TDEConfig* config = kapp->config();
+ config->setGroup("resize Tool Dialog");
+ config->writeEntry("FastApprox", settings.fastApprox);
+ config->writeEntry("Interpolation", settings.interp);
+ config->writeEntry("Amplitude", settings.amplitude);
+ config->writeEntry("Sharpness", settings.sharpness);
+ config->writeEntry("Anisotropy", settings.anisotropy);
+ config->writeEntry("Alpha", settings.alpha);
+ config->writeEntry("Sigma", settings.sigma);
+ config->writeEntry("GaussPrec", settings.gaussPrec);
+ config->writeEntry("Dl", settings.dl);
+ config->writeEntry("Da", settings.da);
+ config->writeEntry("Iteration", settings.nbIter);
+ config->writeEntry("Tile", settings.tile);
+ config->writeEntry("BTile", settings.btile);
+ config->writeEntry("RestorePhotograph", d->useGreycstorationBox->isChecked());
+ config->sync();
+}
+
+void ImageResize::slotDefault()
+{
+ GreycstorationSettings settings;
+ settings.setResizeDefaultSettings();
+
+ d->settingsWidget->setSettings(settings);
+ d->useGreycstorationBox->setChecked(false);
+ slotRestorationToggled(d->useGreycstorationBox->isChecked());
+
+ d->preserveRatioBox->blockSignals(true);
+ d->wInput->blockSignals(true);
+ d->hInput->blockSignals(true);
+ d->wpInput->blockSignals(true);
+ d->hpInput->blockSignals(true);
+ d->preserveRatioBox->setChecked(true);
+ d->wInput->setValue(d->orgWidth);
+ d->hInput->setValue(d->orgHeight);
+ d->wpInput->setValue(100.0);
+ d->hpInput->setValue(100.0);
+ d->preserveRatioBox->blockSignals(false);
+ d->wInput->blockSignals(false);
+ d->hInput->blockSignals(false);
+ d->wpInput->blockSignals(false);
+ d->hpInput->blockSignals(false);
+}
+
+void ImageResize::slotValuesChanged()
+{
+ enableButton(Ok, true);
+ d->wInput->blockSignals(true);
+ d->hInput->blockSignals(true);
+ d->wpInput->blockSignals(true);
+ d->hpInput->blockSignals(true);
+
+ TQString s(sender()->name());
+
+ if (s == "d->wInput")
+ {
+ double val = d->wInput->value();
+ double wp = val/(double)(d->orgWidth) * 100.0;
+ d->wpInput->setValue(wp);
+
+ if (d->preserveRatioBox->isChecked())
+ {
+ d->hpInput->setValue(wp);
+ int h = (int)(wp*d->orgHeight/100);
+ d->hInput->setValue(h);
+ }
+ }
+ else if (s == "d->hInput")
+ {
+ double val = d->hInput->value();
+ double hp = val/(double)(d->orgHeight) * 100.0;
+ d->hpInput->setValue(hp);
+
+ if (d->preserveRatioBox->isChecked())
+ {
+ d->wpInput->setValue(hp);
+ int w = (int)(hp*d->orgWidth/100);
+ d->wInput->setValue(w);
+ }
+ }
+ else if (s == "d->wpInput")
+ {
+ double val = d->wpInput->value();
+ int w = (int)(val*d->orgWidth/100);
+ d->wInput->setValue(w);
+
+ if (d->preserveRatioBox->isChecked())
+ {
+ d->hpInput->setValue(val);
+ int h = (int)(val*d->orgHeight/100);
+ d->hInput->setValue(h);
+ }
+ }
+ else if (s == "d->hpInput")
+ {
+ double val = d->hpInput->value();
+ int h = (int)(val*d->orgHeight/100);
+ d->hInput->setValue(h);
+
+ if (d->preserveRatioBox->isChecked())
+ {
+ d->wpInput->setValue(val);
+ int w = (int)(val*d->orgWidth/100);
+ d->wInput->setValue(w);
+ }
+ }
+
+ d->prevW = d->wInput->value();
+ d->prevH = d->hInput->value();
+ d->prevWP = d->wpInput->value();
+ d->prevHP = d->hpInput->value();
+
+ d->wInput->blockSignals(false);
+ d->hInput->blockSignals(false);
+ d->wpInput->blockSignals(false);
+ d->hpInput->blockSignals(false);
+}
+
+void ImageResize::slotCancel()
+{
+ if (d->currentRenderingMode != ImageResizePriv::NoneRendering)
+ {
+ d->greycstorationIface->stopComputation();
+ d->parent->unsetCursor();
+ }
+
+ done(Cancel);
+}
+
+void ImageResize::processCImgURL(const TQString& url)
+{
+ TDEApplication::kApplication()->invokeBrowser(url);
+}
+
+void ImageResize::closeEvent(TQCloseEvent *e)
+{
+ if (d->currentRenderingMode != ImageResizePriv::NoneRendering)
+ {
+ d->greycstorationIface->stopComputation();
+ d->parent->unsetCursor();
+ }
+
+ e->accept();
+}
+
+void ImageResize::slotOk()
+{
+ if (d->prevW != d->wInput->value() || d->prevH != d->hInput->value() ||
+ d->prevWP != d->wpInput->value() || d->prevHP != d->hpInput->value())
+ slotValuesChanged();
+
+ d->currentRenderingMode = ImageResizePriv::FinalRendering;
+ d->mainTab->setCurrentPage(0);
+ d->settingsWidget->setEnabled(false);
+ d->preserveRatioBox->setEnabled(false);
+ d->useGreycstorationBox->setEnabled(false);
+ d->wInput->setEnabled(false);
+ d->hInput->setEnabled(false);
+ d->wpInput->setEnabled(false);
+ d->hpInput->setEnabled(false);
+ enableButton(Ok, false);
+ enableButton(Default, false);
+ enableButton(User2, false);
+ enableButton(User3, false);
+
+ d->parent->setCursor( KCursor::waitCursor() );
+ writeUserSettings();
+ ImageIface iface(0, 0);
+ uchar *data = iface.getOriginalImage();
+ DImg image = DImg(iface.originalWidth(), iface.originalHeight(),
+ iface.originalSixteenBit(), iface.originalHasAlpha(), data);
+ delete [] data;
+
+ if (d->useGreycstorationBox->isChecked())
+ {
+ d->progressBar->setValue(0);
+ d->progressBar->setEnabled(true);
+
+ if (d->greycstorationIface)
+ {
+ delete d->greycstorationIface;
+ d->greycstorationIface = 0;
+ }
+
+ d->greycstorationIface = new GreycstorationIface(
+ &image, d->settingsWidget->getSettings(),
+ GreycstorationIface::Resize,
+ d->wInput->value(),
+ d->hInput->value(),
+ 0, this);
+ }
+ else
+ {
+ // See B.K.O #152192: CImg resize() sound like bugous or unadapted
+ // to resize image without good quality.
+
+ image.resize(d->wInput->value(), d->hInput->value());
+ iface.putOriginalImage(i18n("Resize"), image.bits(),
+ image.width(), image.height());
+ d->parent->unsetCursor();
+ accept();
+ }
+}
+
+void ImageResize::customEvent(TQCustomEvent *event)
+{
+ if (!event) return;
+
+ GreycstorationIface::EventData *data = (GreycstorationIface::EventData*) event->data();
+
+ if (!data) return;
+
+ if (data->starting) // Computation in progress !
+ {
+ d->progressBar->setValue(data->progress);
+ }
+ else
+ {
+ if (data->success) // Computation Completed !
+ {
+ switch (d->currentRenderingMode)
+ {
+ case ImageResizePriv::FinalRendering:
+ {
+ DDebug() << "Final resizing completed..." << endl;
+
+ ImageIface iface(0, 0);
+ DImg resizedImage = d->greycstorationIface->getTargetImage();
+
+ iface.putOriginalImage(i18n("Resize"), resizedImage.bits(),
+ resizedImage.width(), resizedImage.height());
+ d->parent->unsetCursor();
+ accept();
+ break;
+ }
+ }
+ }
+ else // Computation Failed !
+ {
+ switch (d->currentRenderingMode)
+ {
+ case ImageResizePriv::FinalRendering:
+ break;
+ }
+ }
+ }
+
+ delete data;
+}
+
+void ImageResize::slotUser3()
+{
+ KURL loadBlowupFile = KFileDialog::getOpenURL(TDEGlobalSettings::documentPath(),
+ TQString( "*" ), this,
+ TQString( i18n("Photograph Resizing Settings File to Load")) );
+ if( loadBlowupFile.isEmpty() )
+ return;
+
+ TQFile file(loadBlowupFile.path());
+
+ if ( file.open(IO_ReadOnly) )
+ {
+ if (!d->settingsWidget->loadSettings(file, TQString("# Photograph Resizing Configuration File")))
+ {
+ KMessageBox::error(this,
+ i18n("\"%1\" is not a Photograph Resizing settings text file.")
+ .arg(loadBlowupFile.fileName()));
+ file.close();
+ return;
+ }
+ }
+ else
+ KMessageBox::error(this, i18n("Cannot load settings from the Photograph Resizing text file."));
+
+ file.close();
+}
+
+void ImageResize::slotUser2()
+{
+ KURL saveBlowupFile = KFileDialog::getSaveURL(TDEGlobalSettings::documentPath(),
+ TQString( "*" ), this,
+ TQString( i18n("Photograph Resizing Settings File to Save")) );
+ if( saveBlowupFile.isEmpty() )
+ return;
+
+ TQFile file(saveBlowupFile.path());
+
+ if ( file.open(IO_WriteOnly) )
+ d->settingsWidget->saveSettings(file, TQString("# Photograph Resizing Configuration File"));
+ else
+ KMessageBox::error(this, i18n("Cannot save settings to the Photograph Resizing text file."));
+
+ file.close();
+}
+
+} // NameSpace Digikam
+