/* ============================================================ * * 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 * * 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 // TQt includes. #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 // LibKDcraw includes. #include // 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("

Reset all filter parameters to their default values.") ); setButtonWhatsThis( User3, i18n("

Load all filter parameters from settings text file.") ); setButtonWhatsThis( User2, i18n("

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("

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("

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("

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("

Set here the new image height in percent.")); d->preserveRatioBox = new TQCheckBox(i18n("Maintain aspect ratio"), firstPage); TQWhatsThis::add( d->preserveRatioBox, i18n("

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("

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("Note: use Restoration Mode to only scale-up an image to huge size. " "Warning, this process can take a while."), firstPage); d->progressBar = new KProgress(100, firstPage); d->progressBar->setValue(0); TQWhatsThis::add(d->progressBar, i18n("

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, TQT_SLOT(readUserSettings())); // ------------------------------------------------------------- connect(d->cimgLogoLabel, TQT_SIGNAL(leftClickedURL(const TQString&)), this, TQT_SLOT(processCImgURL(const TQString&))); connect(d->wInput, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(slotValuesChanged())); connect(d->hInput, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(slotValuesChanged())); connect(d->wpInput, TQT_SIGNAL(valueChanged(double)), this, TQT_SLOT(slotValuesChanged())); connect(d->hpInput, TQT_SIGNAL(valueChanged(double)), this, TQT_SLOT(slotValuesChanged())); connect(d->useGreycstorationBox, TQT_SIGNAL(toggled(bool)), this, TQT_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(TQT_TQOBJECT(const_cast(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, TQT_TQOBJECT(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