diff options
Diffstat (limited to 'src/imageplugins')
425 files changed, 75937 insertions, 0 deletions
diff --git a/src/imageplugins/Makefile.am b/src/imageplugins/Makefile.am new file mode 100644 index 00000000..3e04b062 --- /dev/null +++ b/src/imageplugins/Makefile.am @@ -0,0 +1,5 @@ +SUBDIRS = coreplugin adjustcurves adjustlevels antivignetting blurfx border \ + channelmixer charcoal colorfx distortionfx emboss filmgrain \ + freerotation hotpixels infrared inpainting inserttext lensdistortion \ + noisereduction oilpaint perspective raindrop restoration sheartool \ + superimpose texture whitebalance diff --git a/src/imageplugins/adjustcurves/Makefile.am b/src/imageplugins/adjustcurves/Makefile.am new file mode 100644 index 00000000..f798a7af --- /dev/null +++ b/src/imageplugins/adjustcurves/Makefile.am @@ -0,0 +1,33 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_adjustcurves_la_SOURCES = imageplugin_adjustcurves.cpp \ + adjustcurvestool.cpp + +digikamimageplugin_adjustcurves_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_adjustcurves_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_adjustcurves.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_adjustcurves.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_adjustcurves_ui.rc diff --git a/src/imageplugins/adjustcurves/adjustcurves.cpp b/src/imageplugins/adjustcurves/adjustcurves.cpp new file mode 100644 index 00000000..ace9c9b3 --- /dev/null +++ b/src/imageplugins/adjustcurves/adjustcurves.cpp @@ -0,0 +1,677 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-01 + * Description : image histogram adjust curves. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// C++ includes. + +#include <cmath> + +// TQt includes. + +#include <tqlayout.h> +#include <tqcolor.h> +#include <tqgroupbox.h> +#include <tqhgroupbox.h> +#include <tqvgroupbox.h> +#include <tqlabel.h> +#include <tqpainter.h> +#include <tqcombobox.h> +#include <tqspinbox.h> +#include <tqwhatsthis.h> +#include <tqtooltip.h> +#include <tqpushbutton.h> +#include <tqlayout.h> +#include <tqframe.h> +#include <tqtimer.h> +#include <tqhbuttongroup.h> +#include <tqpixmap.h> + +// KDE includes. + +#include <tdeconfig.h> +#include <kcursor.h> +#include <tdelocale.h> +#include <knuminput.h> +#include <tdemessagebox.h> +#include <tdeselect.h> +#include <tdefiledialog.h> +#include <tdeglobalsettings.h> +#include <tdeaboutdata.h> +#include <khelpmenu.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <tdepopupmenu.h> +#include <kstandarddirs.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "imagehistogram.h" +#include "imagecurves.h" +#include "histogramwidget.h" +#include "curveswidget.h" +#include "colorgradientwidget.h" +#include "dimgimagefilters.h" +#include "adjustcurves.h" +#include "adjustcurves.moc" + +namespace DigikamAdjustCurvesImagesPlugin +{ + +AdjustCurveDialog::AdjustCurveDialog(TQWidget* parent) + : Digikam::ImageDlgBase(parent, i18n("Adjust Color Curves"), "adjustcurves", true, false) +{ + m_destinationPreviewData = 0L; + + Digikam::ImageIface iface(0, 0); + uchar *data = iface.getOriginalImage(); + int w = iface.originalWidth(); + int h = iface.originalHeight(); + bool sixteenBit = iface.originalSixteenBit(); + bool hasAlpha = iface.originalHasAlpha(); + m_originalImage = Digikam::DImg(w, h, sixteenBit, hasAlpha ,data); + delete [] data; + + m_histoSegments = m_originalImage.sixteenBit() ? 65535 : 255; + m_curves = new Digikam::ImageCurves(m_originalImage.sixteenBit()); + + // About data and help button. + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Adjust Color Curves"), + digikam_version, + I18N_NOOP("An image-histogram-curves adjustment plugin for digiKam."), + TDEAboutData::License_GPL, + "(c) 2004-2008, Gilles Caulier", + 0, + "http://www.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + setAboutData(about); + + // ------------------------------------------------------------- + + m_previewWidget = new Digikam::ImageWidget("adjustcurves Tool Dialog", plainPage(), + i18n("<p>This is the image's curve-adjustments preview. " + "You can pick a spot on the image " + "to see the corresponding level in the histogram.")); + setPreviewAreaWidget(m_previewWidget); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(plainPage()); + TQGridLayout* grid = new TQGridLayout( gboxSettings, 5, 5, spacingHint()); + + TQLabel *label1 = new TQLabel(i18n("Channel:"), gboxSettings); + label1->setAlignment ( TQt::AlignRight | TQt::AlignVCenter ); + m_channelCB = new TQComboBox( false, gboxSettings ); + m_channelCB->insertItem( i18n("Luminosity") ); + m_channelCB->insertItem( i18n("Red") ); + m_channelCB->insertItem( i18n("Green") ); + m_channelCB->insertItem( i18n("Blue") ); + m_channelCB->insertItem( i18n("Alpha") ); + m_channelCB->setCurrentText( i18n("Luminosity") ); + TQWhatsThis::add( m_channelCB, i18n("<p>Select the histogram channel to display here:<p>" + "<b>Luminosity</b>: display the image's luminosity values.<p>" + "<b>Red</b>: display the red image-channel values.<p>" + "<b>Green</b>: display the green image-channel values.<p>" + "<b>Blue</b>: display the blue image-channel values.<p>" + "<b>Alpha</b>: display the alpha image-channel values. " + "This channel corresponds to the transparency value and " + "is supported by some image formats, such as PNG or TIF.")); + + m_scaleBG = new TQHButtonGroup(gboxSettings); + TQWhatsThis::add( m_scaleBG, i18n("<p>Select the histogram scale here.<p>" + "If the image's maximal counts are small, you can use the linear scale.<p>" + "Logarithmic scale can be used when the maximal counts 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( "<p>Linear" ) ); + m_scaleBG->insert(linHistoButton, Digikam::CurvesWidget::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( "<p>Logarithmic" ) ); + m_scaleBG->insert(logHistoButton, Digikam::CurvesWidget::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); + + m_scaleBG->setExclusive(true); + m_scaleBG->setButton(Digikam::CurvesWidget::LogScaleHistogram); + m_scaleBG->setFrameShape(TQFrame::NoFrame); + m_scaleBG->setInsideMargin( 0 ); + + TQHBoxLayout* l1 = new TQHBoxLayout(); + l1->addStretch(10); + l1->addWidget(m_scaleBG); + + grid->addMultiCellWidget(label1, 0, 0, 1, 1); + grid->addMultiCellWidget(m_channelCB, 0, 0, 2, 2); + grid->addMultiCellLayout(l1, 0, 0, 4, 5); + + // ------------------------------------------------------------- + + TQWidget *curveBox = new TQWidget(gboxSettings); + TQGridLayout* gl = new TQGridLayout(curveBox, 4, 2, 0); + + m_histogramWidget = new Digikam::HistogramWidget(256, 140, curveBox, false, true, true); + TQWhatsThis::add( m_histogramWidget, i18n("<p>Here you can see the target preview image histogram drawing " + "of the selected image channel. This one is re-computed at any " + "curves settings changes.")); + + m_vGradient = new Digikam::ColorGradientWidget( Digikam::ColorGradientWidget::Vertical, 10, curveBox ); + m_vGradient->setColors( TQColor( "white" ), TQColor( "black" ) ); + + TQLabel *spacev = new TQLabel(curveBox); + spacev->setFixedWidth(1); + + m_curvesWidget = new Digikam::CurvesWidget(256, 256, m_originalImage.bits(), m_originalImage.width(), + m_originalImage.height(), m_originalImage.sixteenBit(), + m_curves, curveBox); + TQWhatsThis::add( m_curvesWidget, i18n("<p>This is the curve drawing of the selected channel from " + "original image")); + + TQLabel *spaceh = new TQLabel(curveBox); + spaceh->setFixedHeight(1); + + m_hGradient = new Digikam::ColorGradientWidget( Digikam::ColorGradientWidget::Horizontal, 10, curveBox ); + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + + gl->addMultiCellWidget(m_histogramWidget, 0, 0, 2, 2); + gl->addMultiCellWidget(m_vGradient, 2, 2, 0, 0); + gl->addMultiCellWidget(spacev, 2, 2, 1, 1); + gl->addMultiCellWidget(m_curvesWidget, 2, 2, 2, 2); + gl->addMultiCellWidget(spaceh, 3, 3, 2, 2); + gl->addMultiCellWidget(m_hGradient, 4, 4, 2, 2); + gl->setRowSpacing(1, spacingHint()); + + grid->addMultiCellWidget(curveBox, 2, 3, 0, 5); + + // ------------------------------------------------------------- + + m_curveType = new TQHButtonGroup(gboxSettings); + m_curveFree = new TQPushButton(m_curveType); + m_curveType->insert(m_curveFree, FreeDrawing); + TDEGlobal::dirs()->addResourceType("curvefree", TDEGlobal::dirs()->kde_default("data") + + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("curvefree", "curvefree.png"); + m_curveFree->setPixmap( TQPixmap( directory + "curvefree.png" ) ); + m_curveFree->setToggleButton(true); + TQToolTip::add( m_curveFree, i18n( "Curve free mode" ) ); + TQWhatsThis::add( m_curveFree, i18n("<p>With this button, you can draw your curve free-hand with the mouse.")); + m_curveSmooth = new TQPushButton(m_curveType); + m_curveType->insert(m_curveSmooth, SmoothDrawing); + TDEGlobal::dirs()->addResourceType("curvemooth", TDEGlobal::dirs()->kde_default("data") + + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("curvemooth", "curvemooth.png"); + m_curveSmooth->setPixmap( TQPixmap( directory + "curvemooth.png" ) ); + m_curveSmooth->setToggleButton(true); + TQToolTip::add( m_curveSmooth, i18n( "Curve smooth mode" ) ); + TQWhatsThis::add( m_curveSmooth, i18n("<p>With this button, you constrains the curve type to a smooth line with tension.")); + m_curveType->setExclusive(true); + m_curveType->setButton(SmoothDrawing); + m_curveType->setFrameShape(TQFrame::NoFrame); + + // ------------------------------------------------------------- + + m_pickerColorButtonGroup = new TQHButtonGroup(gboxSettings); + m_pickBlack = new TQPushButton(m_pickerColorButtonGroup); + m_pickerColorButtonGroup->insert(m_pickBlack, BlackTonal); + TDEGlobal::dirs()->addResourceType("color-picker-black", TDEGlobal::dirs()->kde_default("data") + + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("color-picker-black", "color-picker-black.png"); + m_pickBlack->setPixmap( TQPixmap( directory + "color-picker-black.png" ) ); + m_pickBlack->setToggleButton(true); + TQToolTip::add( m_pickBlack, i18n( "All channels shadow tone color picker" ) ); + TQWhatsThis::add( m_pickBlack, i18n("<p>With this button, you can pick the color from original image used to set <b>Shadow Tone</b> " + "smooth curves point on Red, Green, Blue, and Luminosity channels.")); + m_pickGray = new TQPushButton(m_pickerColorButtonGroup); + m_pickerColorButtonGroup->insert(m_pickGray, GrayTonal); + TDEGlobal::dirs()->addResourceType("color-picker-grey", TDEGlobal::dirs()->kde_default("data") + + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("color-picker-grey", "color-picker-grey.png"); + m_pickGray->setPixmap( TQPixmap( directory + "color-picker-grey.png" ) ); + m_pickGray->setToggleButton(true); + TQToolTip::add( m_pickGray, i18n( "All channels middle tone color picker" ) ); + TQWhatsThis::add( m_pickGray, i18n("<p>With this button, you can pick the color from original image used to set <b>Middle Tone</b> " + "smooth curves point on Red, Green, Blue, and Luminosity channels.")); + m_pickWhite = new TQPushButton(m_pickerColorButtonGroup); + m_pickerColorButtonGroup->insert(m_pickWhite, WhiteTonal); + TDEGlobal::dirs()->addResourceType("color-picker-white", TDEGlobal::dirs()->kde_default("data") + + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("color-picker-white", "color-picker-white.png"); + m_pickWhite->setPixmap( TQPixmap( directory + "color-picker-white.png" ) ); + m_pickWhite->setToggleButton(true); + TQToolTip::add( m_pickWhite, i18n( "All channels highlight tone color picker" ) ); + TQWhatsThis::add( m_pickWhite, i18n("<p>With this button, you can pick the color from original image used to set <b>Highlight Tone</b> " + "smooth curves point on Red, Green, Blue, and Luminosity channels.")); + m_pickerColorButtonGroup->setExclusive(true); + m_pickerColorButtonGroup->setFrameShape(TQFrame::NoFrame); + + // ------------------------------------------------------------- + + m_resetButton = new TQPushButton(i18n("&Reset"), gboxSettings); + m_resetButton->setPixmap( SmallIcon("reload_page", 18) ); + TQToolTip::add( m_resetButton, i18n( "Reset current channel curves' values." ) ); + TQWhatsThis::add( m_resetButton, i18n("<p>If you press this button, all curves' values " + "from the current selected channel " + "will be reset to the default values.")); + + TQHBoxLayout* l3 = new TQHBoxLayout(); + l3->addWidget(m_curveType); + l3->addWidget(m_pickerColorButtonGroup); + l3->addWidget(m_resetButton); + l3->addStretch(10); + + grid->addMultiCellLayout(l3, 4, 4, 1, 5); + + // ------------------------------------------------------------- + + + grid->setRowStretch(5, 10); + setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + connect(m_curvesWidget, TQ_SIGNAL(signalCurvesChanged()), + this, TQ_SLOT(slotTimer())); + + 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 & ))); + + connect(m_previewWidget, TQ_SIGNAL(signalResized()), + this, TQ_SLOT(slotEffect())); + + // ------------------------------------------------------------- + // ComboBox slots. + + 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_curveType, TQ_SIGNAL(clicked(int)), + this, TQ_SLOT(slotCurveTypeChanged(int))); + + // ------------------------------------------------------------- + // Bouttons slots. + + connect(m_resetButton, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotResetCurrentChannel())); + + connect(m_pickerColorButtonGroup, TQ_SIGNAL(released(int)), + this, TQ_SLOT(slotPickerColorButtonActived())); +} + +AdjustCurveDialog::~AdjustCurveDialog() +{ + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + delete m_histogramWidget; + delete m_curvesWidget; + delete m_previewWidget; + delete m_curves; +} + +void AdjustCurveDialog::slotPickerColorButtonActived() +{ + // Save previous rendering mode and toggle to original image. + m_currentPreviewMode = m_previewWidget->getRenderingPreviewMode(); + m_previewWidget->setRenderingPreviewMode(Digikam::ImageGuideWidget::PreviewOriginalImage); +} + +void AdjustCurveDialog::slotSpotColorChanged(const Digikam::DColor &color) +{ + Digikam::DColor sc = color; + + if ( m_pickBlack->isOn() ) + { + // Black tonal curves point. + m_curves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, 1, + TQPoint(TQMAX(TQMAX(sc.red(), sc.green()), sc.blue()), 42*m_histoSegments/256)); + m_curves->setCurvePoint(Digikam::ImageHistogram::RedChannel, 1, TQPoint(sc.red(), 42*m_histoSegments/256)); + m_curves->setCurvePoint(Digikam::ImageHistogram::GreenChannel, 1, TQPoint(sc.green(), 42*m_histoSegments/256)); + m_curves->setCurvePoint(Digikam::ImageHistogram::BlueChannel, 1, TQPoint(sc.blue(), 42*m_histoSegments/256)); + m_pickBlack->setOn(false); + } + else if ( m_pickGray->isOn() ) + { + // Gray tonal curves point. + m_curves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, 8, + TQPoint(TQMAX(TQMAX(sc.red(), sc.green()), sc.blue()), 128*m_histoSegments/256)); + m_curves->setCurvePoint(Digikam::ImageHistogram::RedChannel, 8, TQPoint(sc.red(), 128*m_histoSegments/256)); + m_curves->setCurvePoint(Digikam::ImageHistogram::GreenChannel, 8, TQPoint(sc.green(), 128*m_histoSegments/256)); + m_curves->setCurvePoint(Digikam::ImageHistogram::BlueChannel, 8, TQPoint(sc.blue(), 128*m_histoSegments/256)); + m_pickGray->setOn(false); + } + else if ( m_pickWhite->isOn() ) + { + // White tonal curves point. + m_curves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, 15, + TQPoint(TQMAX(TQMAX(sc.red(), sc.green()), sc.blue()), 213*m_histoSegments/256)); + m_curves->setCurvePoint(Digikam::ImageHistogram::RedChannel, 15, TQPoint(sc.red(), 213*m_histoSegments/256)); + m_curves->setCurvePoint(Digikam::ImageHistogram::GreenChannel, 15, TQPoint(sc.green(), 213*m_histoSegments/256)); + m_curves->setCurvePoint(Digikam::ImageHistogram::BlueChannel, 15, TQPoint(sc.blue(), 213*m_histoSegments/256)); + m_pickWhite->setOn(false); + } + else + { + m_curvesWidget->setCurveGuide(color); + return; + } + + // Calculate Red, green, blue curves. + + for (int i = Digikam::ImageHistogram::ValueChannel ; i <= Digikam::ImageHistogram::BlueChannel ; i++) + m_curves->curvesCalculateCurve(i); + + m_curvesWidget->repaint(false); + + // restore previous rendering mode. + m_previewWidget->setRenderingPreviewMode(m_currentPreviewMode); + + slotEffect(); +} + +void AdjustCurveDialog::slotColorSelectedFromTarget( const Digikam::DColor &color ) +{ + m_histogramWidget->setHistogramGuideByColor(color); +} + +void AdjustCurveDialog::slotResetCurrentChannel() +{ + m_curves->curvesChannelReset(m_channelCB->currentItem()); + + m_curvesWidget->reset(); + slotEffect(); + m_histogramWidget->reset(); +} + +void AdjustCurveDialog::slotEffect() +{ + Digikam::ImageIface* iface = m_previewWidget->imageIface(); + uchar *orgData = iface->getPreviewImage(); + int w = iface->previewWidth(); + int h = iface->previewHeight(); + bool sb = iface->previewSixteenBit(); + + // Create the new empty destination image data space. + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + m_destinationPreviewData = new uchar[w*h*(sb ? 8 : 4)]; + + // Calculate the LUT to apply on the image. + m_curves->curvesLutSetup(Digikam::ImageHistogram::AlphaChannel); + + // Apply the lut to the image. + m_curves->curvesLutProcess(orgData, m_destinationPreviewData, w, h); + + iface->putPreviewImage(m_destinationPreviewData); + m_previewWidget->updatePreview(); + + // Update histogram. + m_histogramWidget->updateData(m_destinationPreviewData, w, h, sb, 0, 0, 0, false); + delete [] orgData; +} + +void AdjustCurveDialog::finalRendering() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + Digikam::ImageIface* iface = m_previewWidget->imageIface(); + uchar *orgData = iface->getOriginalImage(); + int w = iface->originalWidth(); + int h = iface->originalHeight(); + bool sb = iface->originalSixteenBit(); + + // Create the new empty destination image data space. + uchar* desData = new uchar[w*h*(sb ? 8 : 4)]; + + // Calculate the LUT to apply on the image. + m_curves->curvesLutSetup(Digikam::ImageHistogram::AlphaChannel); + + // Apply the lut to the image. + m_curves->curvesLutProcess(orgData, desData, w, h); + + iface->putOriginalImage(i18n("Adjust Curve"), desData); + kapp->restoreOverrideCursor(); + + delete [] orgData; + delete [] desData; + accept(); +} + +void AdjustCurveDialog::slotChannelChanged(int channel) +{ + switch(channel) + { + case LuminosityChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::ValueHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + m_curvesWidget->m_channelType = Digikam::CurvesWidget::ValueHistogram; + m_vGradient->setColors( TQColor( "white" ), TQColor( "black" ) ); + break; + + case RedChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::RedChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "red" ) ); + m_curvesWidget->m_channelType = Digikam::CurvesWidget::RedChannelHistogram; + m_vGradient->setColors( TQColor( "red" ), TQColor( "black" ) ); + break; + + case GreenChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::GreenChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "green" ) ); + m_curvesWidget->m_channelType = Digikam::CurvesWidget::GreenChannelHistogram; + m_vGradient->setColors( TQColor( "green" ), TQColor( "black" ) ); + break; + + case BlueChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::BlueChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "blue" ) ); + m_curvesWidget->m_channelType = Digikam::CurvesWidget::BlueChannelHistogram; + m_vGradient->setColors( TQColor( "blue" ), TQColor( "black" ) ); + break; + + case AlphaChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::AlphaChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + m_curvesWidget->m_channelType = Digikam::CurvesWidget::AlphaChannelHistogram; + m_vGradient->setColors( TQColor( "white" ), TQColor( "black" ) ); + break; + } + + m_curveType->setButton(m_curves->getCurveType(channel)); + + m_curvesWidget->repaint(false); + m_histogramWidget->repaint(false); +} + +void AdjustCurveDialog::slotScaleChanged(int scale) +{ + m_curvesWidget->m_scaleType = scale; + m_histogramWidget->m_scaleType = scale; + m_histogramWidget->repaint(false); + m_curvesWidget->repaint(false); +} + +void AdjustCurveDialog::slotCurveTypeChanged(int type) +{ + switch(type) + { + case SmoothDrawing: + { + m_curves->setCurveType(m_curvesWidget->m_channelType, Digikam::ImageCurves::CURVE_SMOOTH); + m_pickerColorButtonGroup->setEnabled(true); + break; + } + + case FreeDrawing: + { + m_curves->setCurveType(m_curvesWidget->m_channelType, Digikam::ImageCurves::CURVE_FREE); + m_pickerColorButtonGroup->setEnabled(false); + break; + } + } + + m_curvesWidget->curveTypeChanged(); +} + +void AdjustCurveDialog::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("adjustcurves Tool Dialog"); + + m_channelCB->setCurrentItem(config->readNumEntry("Histogram Channel", 0)); // Luminosity. + m_scaleBG->setButton(config->readNumEntry("Histogram Scale", Digikam::HistogramWidget::LogScaleHistogram)); + + m_curvesWidget->reset(); + + for (int i = 0 ; i < 5 ; i++) + { + m_curves->curvesChannelReset(i); + m_curves->setCurveType(i, (Digikam::ImageCurves::CurveType)config->readNumEntry(TQString("CurveTypeChannel%1").arg(i), + Digikam::ImageCurves::CURVE_SMOOTH)); + + for (int j = 0 ; j < 17 ; j++) + { + TQPoint disable(-1, -1); + TQPoint p = config->readPointEntry(TQString("CurveAjustmentChannel%1Point%2").arg(i).arg(j), &disable); + + if (m_originalImage.sixteenBit() && p.x() != -1) + { + p.setX(p.x()*255); + p.setY(p.y()*255); + } + + m_curves->setCurvePoint(i, j, p); + } + + m_curves->curvesCalculateCurve(i); + } + + slotChannelChanged(m_channelCB->currentItem()); + slotScaleChanged(m_scaleBG->selectedId()); +} + +void AdjustCurveDialog::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("adjustcurves Tool Dialog"); + config->writeEntry("Histogram Channel", m_channelCB->currentItem()); + config->writeEntry("Histogram Scale", m_scaleBG->selectedId()); + + for (int i = 0 ; i < 5 ; i++) + { + config->writeEntry(TQString("CurveTypeChannel%1").arg(i), m_curves->getCurveType(i)); + + for (int j = 0 ; j < 17 ; j++) + { + TQPoint p = m_curves->getCurvePoint(i, j); + + if (m_originalImage.sixteenBit() && p.x() != -1) + { + p.setX(p.x()/255); + p.setY(p.y()/255); + } + + config->writeEntry(TQString("CurveAjustmentChannel%1Point%2").arg(i).arg(j), p); + } + } + + config->sync(); +} + +void AdjustCurveDialog::resetValues() +{ + for (int channel = 0 ; channel < 5 ; channel++) + m_curves->curvesChannelReset(channel); + + m_curvesWidget->reset(); + m_histogramWidget->reset(); +} + +// Load all settings. +void AdjustCurveDialog::slotUser3() +{ + KURL loadCurvesFile; + + loadCurvesFile = KFileDialog::getOpenURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), this, + TQString( i18n("Select Gimp Curves File to Load")) ); + if( loadCurvesFile.isEmpty() ) + return; + + if ( m_curves->loadCurvesFromGimpCurvesFile( loadCurvesFile ) == false ) + { + KMessageBox::error(this, i18n("Cannot load from the Gimp curves text file.")); + return; + } + + // Refresh the current curves config. + slotChannelChanged(m_channelCB->currentItem()); + slotEffect(); +} + +// Save all settings. +void AdjustCurveDialog::slotUser2() +{ + KURL saveCurvesFile; + + saveCurvesFile = KFileDialog::getSaveURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), this, + TQString( i18n("Gimp Curves File to Save")) ); + if( saveCurvesFile.isEmpty() ) + return; + + if ( m_curves->saveCurvesToGimpCurvesFile( saveCurvesFile ) == false ) + { + KMessageBox::error(this, i18n("Cannot save to the Gimp curves text file.")); + return; + } + + // Refresh the current curves config. + slotChannelChanged(m_channelCB->currentItem()); +} + +} // NameSpace DigikamAdjustCurvesImagesPlugin + diff --git a/src/imageplugins/adjustcurves/adjustcurves.h b/src/imageplugins/adjustcurves/adjustcurves.h new file mode 100644 index 00000000..f4cad2f2 --- /dev/null +++ b/src/imageplugins/adjustcurves/adjustcurves.h @@ -0,0 +1,143 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-01 + * Description : image histogram adjust curves. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef ADJUSTCURVES_H +#define ADJUSTCURVES_H + +// Digikam includes. + +#include "imagedlgbase.h" +#include "dimg.h" + +// Local includes. + +class TQComboBox; +class TQPushButton; +class TQHButtonGroup; + +namespace Digikam +{ +class CurvesWidget; +class HistogramWidget; +class ColorGradientWidget; +class ImageWidget; +class ImageCurves; +} + +namespace DigikamAdjustCurvesImagesPlugin +{ + +class AdjustCurveDialog : public Digikam::ImageDlgBase +{ + TQ_OBJECT + + +public: + + AdjustCurveDialog(TQWidget *parent); + ~AdjustCurveDialog(); + +private: + + void readUserSettings(); + void writeUserSettings(); + void resetValues(); + void finalRendering(); + +private slots: + + void slotUser2(); + void slotUser3(); + void slotEffect(); + void slotResetCurrentChannel(); + void slotChannelChanged(int channel); + void slotScaleChanged(int scale); + void slotCurveTypeChanged(int type); + void slotSpotColorChanged(const Digikam::DColor &color); + void slotColorSelectedFromTarget(const Digikam::DColor &color); + void slotPickerColorButtonActived(); + +private: + + enum ColorPicker + { + BlackTonal=0, + GrayTonal, + WhiteTonal + }; + + enum ColorChannel + { + LuminosityChannel=0, + RedChannel, + GreenChannel, + BlueChannel, + AlphaChannel + }; + + enum CurvesDrawingType + { + SmoothDrawing=0, + FreeDrawing + }; + + enum HistogramScale + { + Linear=0, + Logarithmic + }; + + uchar *m_destinationPreviewData; + + int m_histoSegments; + int m_currentPreviewMode; + + TQComboBox *m_channelCB; + + TQPushButton *m_resetButton; + TQPushButton *m_pickBlack; + TQPushButton *m_pickGray; + TQPushButton *m_pickWhite; + TQPushButton *m_curveFree; + TQPushButton *m_curveSmooth; + + TQHButtonGroup *m_pickerColorButtonGroup; + TQHButtonGroup *m_scaleBG; + TQHButtonGroup *m_curveType; + + Digikam::CurvesWidget *m_curvesWidget; + + Digikam::HistogramWidget *m_histogramWidget; + + Digikam::ColorGradientWidget *m_hGradient; + Digikam::ColorGradientWidget *m_vGradient; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::ImageCurves *m_curves; + Digikam::DImg m_originalImage; +}; + +} // NameSpace DigikamAdjustCurvesImagesPlugin + +#endif /* ADJUSTCURVES_H */ diff --git a/src/imageplugins/adjustcurves/adjustcurvestool.cpp b/src/imageplugins/adjustcurves/adjustcurvestool.cpp new file mode 100644 index 00000000..7bfd00f7 --- /dev/null +++ b/src/imageplugins/adjustcurves/adjustcurvestool.cpp @@ -0,0 +1,659 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-01 + * Description : image histogram adjust curves. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// C++ includes. + +#include <cmath> + +// TQt includes. + +#include <tqlayout.h> +#include <tqcolor.h> +#include <tqgroupbox.h> +#include <tqhgroupbox.h> +#include <tqvgroupbox.h> +#include <tqlabel.h> +#include <tqpainter.h> +#include <tqcombobox.h> +#include <tqspinbox.h> +#include <tqwhatsthis.h> +#include <tqtooltip.h> +#include <tqpushbutton.h> +#include <tqlayout.h> +#include <tqframe.h> +#include <tqtimer.h> +#include <tqhbuttongroup.h> +#include <tqpixmap.h> + +// KDE includes. + +#include <tdeconfig.h> +#include <kcursor.h> +#include <tdelocale.h> +#include <knuminput.h> +#include <tdemessagebox.h> +#include <tdeselect.h> +#include <tdefiledialog.h> +#include <tdeglobalsettings.h> +#include <tdeaboutdata.h> +#include <khelpmenu.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <tdepopupmenu.h> +#include <kstandarddirs.h> +#include <kpushbutton.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "imagehistogram.h" +#include "imagecurves.h" +#include "editortoolsettings.h" +#include "histogramwidget.h" +#include "curveswidget.h" +#include "colorgradientwidget.h" +#include "dimgimagefilters.h" +#include "adjustcurvestool.h" +#include "adjustcurvestool.moc" + +using namespace Digikam; + +namespace DigikamAdjustCurvesImagesPlugin +{ + +AdjustCurvesTool::AdjustCurvesTool(TQObject* parent) + : EditorTool(parent) +{ + m_destinationPreviewData = 0; + + ImageIface iface(0, 0); + m_originalImage = iface.getOriginalImg(); + + m_histoSegments = m_originalImage->sixteenBit() ? 65535 : 255; + + setName("adjustcurves"); + setToolName(i18n("Adjust Curves")); + setToolIcon(SmallIcon("adjustcurves")); + + // ------------------------------------------------------------- + + m_previewWidget = new ImageWidget("adjustcurves Tool", 0, + i18n("<p>This is the image's curve-adjustments preview. " + "You can pick a spot on the image " + "to see the corresponding level in the histogram.")); + setToolView(m_previewWidget); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Load| + EditorToolSettings::SaveAs| + EditorToolSettings::Ok| + EditorToolSettings::Cancel); + + TQGridLayout* grid = new TQGridLayout(m_gboxSettings->plainPage(), 5, 5); + + 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") ); + m_channelCB->insertItem( i18n("Alpha") ); + m_channelCB->setCurrentText( i18n("Luminosity") ); + TQWhatsThis::add( m_channelCB, i18n("<p>Select the histogram channel to display here:<p>" + "<b>Luminosity</b>: display the image's luminosity values.<p>" + "<b>Red</b>: display the red image-channel values.<p>" + "<b>Green</b>: display the green image-channel values.<p>" + "<b>Blue</b>: display the blue image-channel values.<p>" + "<b>Alpha</b>: display the alpha image-channel values. " + "This channel corresponds to the transparency value and " + "is supported by some image formats, such as PNG or TIF.")); + + m_scaleBG = new TQHButtonGroup(m_gboxSettings->plainPage()); + TQWhatsThis::add( m_scaleBG, i18n("<p>Select the histogram scale here.<p>" + "If the image's maximal counts are small, you can use the linear scale.<p>" + "Logarithmic scale can be used when the maximal counts 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( "<p>Linear" ) ); + m_scaleBG->insert(linHistoButton, CurvesWidget::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( "<p>Logarithmic" ) ); + m_scaleBG->insert(logHistoButton, CurvesWidget::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); + + m_scaleBG->setExclusive(true); + m_scaleBG->setButton(CurvesWidget::LogScaleHistogram); + m_scaleBG->setFrameShape(TQFrame::NoFrame); + m_scaleBG->setInsideMargin(0); + + TQHBoxLayout* l1 = new TQHBoxLayout(); + l1->addWidget(label1); + l1->addWidget(m_channelCB); + l1->addStretch(10); + l1->addWidget(m_scaleBG); + + // ------------------------------------------------------------- + + TQWidget *curveBox = new TQWidget(m_gboxSettings->plainPage()); + TQGridLayout* gl = new TQGridLayout(curveBox, 4, 2, 0); + + m_histogramWidget = new HistogramWidget(256, 140, curveBox, false, true, true); + TQWhatsThis::add( m_histogramWidget, i18n("<p>Here you can see the target preview image histogram drawing " + "of the selected image channel. This one is re-computed at any " + "curves settings changes.")); + + m_vGradient = new ColorGradientWidget( ColorGradientWidget::Vertical, 10, curveBox ); + m_vGradient->setColors( TQColor( "white" ), TQColor( "black" ) ); + + TQLabel *spacev = new TQLabel(curveBox); + spacev->setFixedWidth(1); + + m_curvesWidget = new CurvesWidget(256, 256, m_originalImage->bits(), m_originalImage->width(), + m_originalImage->height(), m_originalImage->sixteenBit(), + curveBox); + TQWhatsThis::add( m_curvesWidget, i18n("<p>This is the curve drawing of the selected channel from " + "original image")); + + TQLabel *spaceh = new TQLabel(curveBox); + spaceh->setFixedHeight(1); + + m_hGradient = new ColorGradientWidget( ColorGradientWidget::Horizontal, 10, curveBox ); + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + + gl->addMultiCellWidget(m_histogramWidget, 0, 0, 2, 2); + gl->addMultiCellWidget(m_vGradient, 2, 2, 0, 0); + gl->addMultiCellWidget(spacev, 2, 2, 1, 1); + gl->addMultiCellWidget(m_curvesWidget, 2, 2, 2, 2); + gl->addMultiCellWidget(spaceh, 3, 3, 2, 2); + gl->addMultiCellWidget(m_hGradient, 4, 4, 2, 2); + gl->setRowSpacing(1, m_gboxSettings->spacingHint()); + + // ------------------------------------------------------------- + + m_curveType = new TQHButtonGroup(m_gboxSettings->plainPage()); + m_curveFree = new TQPushButton(m_curveType); + m_curveType->insert(m_curveFree, FreeDrawing); + TDEGlobal::dirs()->addResourceType("curvefree", TDEGlobal::dirs()->kde_default("data") + + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("curvefree", "curvefree.png"); + m_curveFree->setPixmap( TQPixmap( directory + "curvefree.png" ) ); + m_curveFree->setToggleButton(true); + TQToolTip::add( m_curveFree, i18n( "Curve free mode" ) ); + TQWhatsThis::add( m_curveFree, i18n("<p>With this button, you can draw your curve free-hand with the mouse.")); + m_curveSmooth = new TQPushButton(m_curveType); + m_curveType->insert(m_curveSmooth, SmoothDrawing); + TDEGlobal::dirs()->addResourceType("curvemooth", TDEGlobal::dirs()->kde_default("data") + + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("curvemooth", "curvemooth.png"); + m_curveSmooth->setPixmap( TQPixmap( directory + "curvemooth.png" ) ); + m_curveSmooth->setToggleButton(true); + TQToolTip::add( m_curveSmooth, i18n( "Curve smooth mode" ) ); + TQWhatsThis::add( m_curveSmooth, i18n("<p>With this button, you constrains the curve type to a smooth line with tension.")); + m_curveType->setExclusive(true); + m_curveType->setButton(SmoothDrawing); + m_curveType->setFrameShape(TQFrame::NoFrame); + + // ------------------------------------------------------------- + + m_pickerColorButtonGroup = new TQHButtonGroup(m_gboxSettings->plainPage()); + m_pickBlack = new TQPushButton(m_pickerColorButtonGroup); + m_pickerColorButtonGroup->insert(m_pickBlack, BlackTonal); + TDEGlobal::dirs()->addResourceType("color-picker-black", TDEGlobal::dirs()->kde_default("data") + + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("color-picker-black", "color-picker-black.png"); + m_pickBlack->setPixmap( TQPixmap( directory + "color-picker-black.png" ) ); + m_pickBlack->setToggleButton(true); + TQToolTip::add( m_pickBlack, i18n( "All channels shadow tone color picker" ) ); + TQWhatsThis::add( m_pickBlack, i18n("<p>With this button, you can pick the color from original image used to set <b>Shadow Tone</b> " + "smooth curves point on Red, Green, Blue, and Luminosity channels.")); + m_pickGray = new TQPushButton(m_pickerColorButtonGroup); + m_pickerColorButtonGroup->insert(m_pickGray, GrayTonal); + TDEGlobal::dirs()->addResourceType("color-picker-grey", TDEGlobal::dirs()->kde_default("data") + + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("color-picker-grey", "color-picker-grey.png"); + m_pickGray->setPixmap( TQPixmap( directory + "color-picker-grey.png" ) ); + m_pickGray->setToggleButton(true); + TQToolTip::add( m_pickGray, i18n( "All channels middle tone color picker" ) ); + TQWhatsThis::add( m_pickGray, i18n("<p>With this button, you can pick the color from original image used to set <b>Middle Tone</b> " + "smooth curves point on Red, Green, Blue, and Luminosity channels.")); + m_pickWhite = new TQPushButton(m_pickerColorButtonGroup); + m_pickerColorButtonGroup->insert(m_pickWhite, WhiteTonal); + TDEGlobal::dirs()->addResourceType("color-picker-white", TDEGlobal::dirs()->kde_default("data") + + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("color-picker-white", "color-picker-white.png"); + m_pickWhite->setPixmap( TQPixmap( directory + "color-picker-white.png" ) ); + m_pickWhite->setToggleButton(true); + TQToolTip::add( m_pickWhite, i18n( "All channels highlight tone color picker" ) ); + TQWhatsThis::add( m_pickWhite, i18n("<p>With this button, you can pick the color from original image used to set <b>Highlight Tone</b> " + "smooth curves point on Red, Green, Blue, and Luminosity channels.")); + m_pickerColorButtonGroup->setExclusive(true); + m_pickerColorButtonGroup->setFrameShape(TQFrame::NoFrame); + + // ------------------------------------------------------------- + + m_resetButton = new TQPushButton(i18n("&Reset"), m_gboxSettings->plainPage()); + m_resetButton->setPixmap( SmallIcon("reload_page", 18) ); + TQToolTip::add( m_resetButton, i18n( "Reset current channel curves' values." ) ); + TQWhatsThis::add( m_resetButton, i18n("<p>If you press this button, all curves' values " + "from the current selected channel " + "will be reset to the default values.")); + + TQHBoxLayout* l3 = new TQHBoxLayout(); + l3->addWidget(m_curveType); + l3->addWidget(m_pickerColorButtonGroup); + l3->addWidget(m_resetButton); + l3->addStretch(10); + + grid->addMultiCellLayout(l1, 0, 0, 1, 5); + grid->addMultiCellWidget(curveBox, 1, 3, 0, 5); + grid->addMultiCellLayout(l3, 4, 4, 1, 5); + grid->setMargin(0); + grid->setSpacing(m_gboxSettings->spacingHint()); + grid->setRowStretch(5, 10); + + setToolSettings(m_gboxSettings); + init(); + + // ------------------------------------------------------------- + + connect(m_curvesWidget, TQ_SIGNAL(signalCurvesChanged()), + this, TQ_SLOT(slotTimer())); + + 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&))); + + connect(m_previewWidget, TQ_SIGNAL(signalResized()), + this, TQ_SLOT(slotEffect())); + + // ------------------------------------------------------------- + // ComboBox slots. + + 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_curveType, TQ_SIGNAL(clicked(int)), + this, TQ_SLOT(slotCurveTypeChanged(int))); + + // ------------------------------------------------------------- + // Buttons slots. + + connect(m_resetButton, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotResetCurrentChannel())); + + connect(m_pickerColorButtonGroup, TQ_SIGNAL(released(int)), + this, TQ_SLOT(slotPickerColorButtonActived())); +} + +AdjustCurvesTool::~AdjustCurvesTool() +{ + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; +} + +void AdjustCurvesTool::slotPickerColorButtonActived() +{ + // Save previous rendering mode and toggle to original image. + m_currentPreviewMode = m_previewWidget->getRenderingPreviewMode(); + m_previewWidget->setRenderingPreviewMode(ImageGuideWidget::PreviewOriginalImage); +} + +void AdjustCurvesTool::slotSpotColorChanged(const DColor &color) +{ + DColor sc = color; + + if ( m_pickBlack->isOn() ) + { + // Black tonal curves point. + m_curvesWidget->curves()->setCurvePoint(ImageHistogram::ValueChannel, 1, + TQPoint(TQMAX(TQMAX(sc.red(), sc.green()), sc.blue()), 42*m_histoSegments/256)); + m_curvesWidget->curves()->setCurvePoint(ImageHistogram::RedChannel, 1, TQPoint(sc.red(), 42*m_histoSegments/256)); + m_curvesWidget->curves()->setCurvePoint(ImageHistogram::GreenChannel, 1, TQPoint(sc.green(), 42*m_histoSegments/256)); + m_curvesWidget->curves()->setCurvePoint(ImageHistogram::BlueChannel, 1, TQPoint(sc.blue(), 42*m_histoSegments/256)); + m_pickBlack->setOn(false); + } + else if ( m_pickGray->isOn() ) + { + // Gray tonal curves point. + m_curvesWidget->curves()->setCurvePoint(ImageHistogram::ValueChannel, 8, + TQPoint(TQMAX(TQMAX(sc.red(), sc.green()), sc.blue()), 128*m_histoSegments/256)); + m_curvesWidget->curves()->setCurvePoint(ImageHistogram::RedChannel, 8, TQPoint(sc.red(), 128*m_histoSegments/256)); + m_curvesWidget->curves()->setCurvePoint(ImageHistogram::GreenChannel, 8, TQPoint(sc.green(), 128*m_histoSegments/256)); + m_curvesWidget->curves()->setCurvePoint(ImageHistogram::BlueChannel, 8, TQPoint(sc.blue(), 128*m_histoSegments/256)); + m_pickGray->setOn(false); + } + else if ( m_pickWhite->isOn() ) + { + // White tonal curves point. + m_curvesWidget->curves()->setCurvePoint(ImageHistogram::ValueChannel, 15, + TQPoint(TQMAX(TQMAX(sc.red(), sc.green()), sc.blue()), 213*m_histoSegments/256)); + m_curvesWidget->curves()->setCurvePoint(ImageHistogram::RedChannel, 15, TQPoint(sc.red(), 213*m_histoSegments/256)); + m_curvesWidget->curves()->setCurvePoint(ImageHistogram::GreenChannel, 15, TQPoint(sc.green(), 213*m_histoSegments/256)); + m_curvesWidget->curves()->setCurvePoint(ImageHistogram::BlueChannel, 15, TQPoint(sc.blue(), 213*m_histoSegments/256)); + m_pickWhite->setOn(false); + } + else + { + m_curvesWidget->setCurveGuide(color); + return; + } + + // Calculate Red, green, blue curves. + + for (int i = ImageHistogram::ValueChannel ; i <= ImageHistogram::BlueChannel ; i++) + m_curvesWidget->curves()->curvesCalculateCurve(i); + + m_curvesWidget->repaint(false); + + // restore previous rendering mode. + m_previewWidget->setRenderingPreviewMode(m_currentPreviewMode); + + slotEffect(); +} + +void AdjustCurvesTool::slotColorSelectedFromTarget( const DColor &color ) +{ + m_histogramWidget->setHistogramGuideByColor(color); +} + +void AdjustCurvesTool::slotResetCurrentChannel() +{ + m_curvesWidget->curves()->curvesChannelReset(m_channelCB->currentItem()); + + m_curvesWidget->repaint(); + slotEffect(); + m_histogramWidget->reset(); +} + +void AdjustCurvesTool::slotEffect() +{ + ImageIface* iface = m_previewWidget->imageIface(); + uchar *orgData = iface->getPreviewImage(); + int w = iface->previewWidth(); + int h = iface->previewHeight(); + bool sb = iface->previewSixteenBit(); + + // Create the new empty destination image data space. + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + m_destinationPreviewData = new uchar[w*h*(sb ? 8 : 4)]; + + // Calculate the LUT to apply on the image. + m_curvesWidget->curves()->curvesLutSetup(ImageHistogram::AlphaChannel); + + // Apply the lut to the image. + m_curvesWidget->curves()->curvesLutProcess(orgData, m_destinationPreviewData, w, h); + + iface->putPreviewImage(m_destinationPreviewData); + m_previewWidget->updatePreview(); + + // Update histogram. + m_histogramWidget->updateData(m_destinationPreviewData, w, h, sb, 0, 0, 0, false); + delete [] orgData; +} + +void AdjustCurvesTool::finalRendering() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + ImageIface* iface = m_previewWidget->imageIface(); + uchar *orgData = iface->getOriginalImage(); + int w = iface->originalWidth(); + int h = iface->originalHeight(); + bool sb = iface->originalSixteenBit(); + + // Create the new empty destination image data space. + uchar* desData = new uchar[w*h*(sb ? 8 : 4)]; + + // Calculate the LUT to apply on the image. + m_curvesWidget->curves()->curvesLutSetup(ImageHistogram::AlphaChannel); + + // Apply the lut to the image. + m_curvesWidget->curves()->curvesLutProcess(orgData, desData, w, h); + + iface->putOriginalImage(i18n("Adjust Curves"), desData); + kapp->restoreOverrideCursor(); + + delete [] orgData; + delete [] desData; +} + +void AdjustCurvesTool::slotChannelChanged(int channel) +{ + switch(channel) + { + case LuminosityChannel: + m_histogramWidget->m_channelType = HistogramWidget::ValueHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + m_curvesWidget->m_channelType = CurvesWidget::ValueHistogram; + m_vGradient->setColors( TQColor( "white" ), TQColor( "black" ) ); + break; + + case RedChannel: + m_histogramWidget->m_channelType = HistogramWidget::RedChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "red" ) ); + m_curvesWidget->m_channelType = CurvesWidget::RedChannelHistogram; + m_vGradient->setColors( TQColor( "red" ), TQColor( "black" ) ); + break; + + case GreenChannel: + m_histogramWidget->m_channelType = HistogramWidget::GreenChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "green" ) ); + m_curvesWidget->m_channelType = CurvesWidget::GreenChannelHistogram; + m_vGradient->setColors( TQColor( "green" ), TQColor( "black" ) ); + break; + + case BlueChannel: + m_histogramWidget->m_channelType = HistogramWidget::BlueChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "blue" ) ); + m_curvesWidget->m_channelType = CurvesWidget::BlueChannelHistogram; + m_vGradient->setColors( TQColor( "blue" ), TQColor( "black" ) ); + break; + + case AlphaChannel: + m_histogramWidget->m_channelType = HistogramWidget::AlphaChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + m_curvesWidget->m_channelType = CurvesWidget::AlphaChannelHistogram; + m_vGradient->setColors( TQColor( "white" ), TQColor( "black" ) ); + break; + } + + m_curveType->setButton(m_curvesWidget->curves()->getCurveType(channel)); + + m_curvesWidget->repaint(false); + m_histogramWidget->repaint(false); +} + +void AdjustCurvesTool::slotScaleChanged(int scale) +{ + m_curvesWidget->m_scaleType = scale; + m_histogramWidget->m_scaleType = scale; + m_histogramWidget->repaint(false); + m_curvesWidget->repaint(false); +} + +void AdjustCurvesTool::slotCurveTypeChanged(int type) +{ + switch(type) + { + case SmoothDrawing: + { + m_curvesWidget->curves()->setCurveType(m_curvesWidget->m_channelType, ImageCurves::CURVE_SMOOTH); + m_pickerColorButtonGroup->setEnabled(true); + break; + } + + case FreeDrawing: + { + m_curvesWidget->curves()->setCurveType(m_curvesWidget->m_channelType, ImageCurves::CURVE_FREE); + m_pickerColorButtonGroup->setEnabled(false); + break; + } + } + + m_curvesWidget->curveTypeChanged(); +} + +void AdjustCurvesTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("adjustcurves Tool"); + + m_channelCB->setCurrentItem(config->readNumEntry("Histogram Channel", 0)); // Luminosity. + m_scaleBG->setButton(config->readNumEntry("Histogram Scale", HistogramWidget::LogScaleHistogram)); + + m_curvesWidget->reset(); + + for (int i = 0 ; i < 5 ; i++) + { + m_curvesWidget->curves()->curvesChannelReset(i); + m_curvesWidget->curves()->setCurveType(i, (ImageCurves::CurveType)config->readNumEntry(TQString("CurveTypeChannel%1").arg(i), + ImageCurves::CURVE_SMOOTH)); + + for (int j = 0 ; j < 17 ; j++) + { + TQPoint disable(-1, -1); + TQPoint p = config->readPointEntry(TQString("CurveAjustmentChannel%1Point%2").arg(i).arg(j), &disable); + + if (m_originalImage->sixteenBit() && p.x() != -1) + { + p.setX(p.x()*255); + p.setY(p.y()*255); + } + + m_curvesWidget->curves()->setCurvePoint(i, j, p); + } + + m_curvesWidget->curves()->curvesCalculateCurve(i); + } + + m_histogramWidget->reset(); + slotChannelChanged(m_channelCB->currentItem()); + slotScaleChanged(m_scaleBG->selectedId()); + slotEffect(); +} + +void AdjustCurvesTool::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("adjustcurves Tool"); + config->writeEntry("Histogram Channel", m_channelCB->currentItem()); + config->writeEntry("Histogram Scale", m_scaleBG->selectedId()); + + for (int i = 0 ; i < 5 ; i++) + { + config->writeEntry(TQString("CurveTypeChannel%1").arg(i), m_curvesWidget->curves()->getCurveType(i)); + + for (int j = 0 ; j < 17 ; j++) + { + TQPoint p = m_curvesWidget->curves()->getCurvePoint(i, j); + + if (m_originalImage->sixteenBit() && p.x() != -1) + { + p.setX(p.x()/255); + p.setY(p.y()/255); + } + + config->writeEntry(TQString("CurveAjustmentChannel%1Point%2").arg(i).arg(j), p); + } + } + + m_previewWidget->writeSettings(); + config->sync(); +} + +void AdjustCurvesTool::slotResetSettings() +{ + for (int channel = 0 ; channel < 5 ; channel++) + m_curvesWidget->curves()->curvesChannelReset(channel); + + m_curvesWidget->reset(); + slotEffect(); + m_histogramWidget->reset(); +} + +void AdjustCurvesTool::slotLoadSettings() +{ + KURL loadCurvesFile; + + loadCurvesFile = KFileDialog::getOpenURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), kapp->activeWindow(), + TQString( i18n("Select Gimp Curves File to Load")) ); + if( loadCurvesFile.isEmpty() ) + return; + + if ( m_curvesWidget->curves()->loadCurvesFromGimpCurvesFile( loadCurvesFile ) == false ) + { + KMessageBox::error(kapp->activeWindow(), i18n("Cannot load from the Gimp curves text file.")); + return; + } + + // Refresh the current curves config. + slotChannelChanged(m_channelCB->currentItem()); + slotEffect(); +} + +void AdjustCurvesTool::slotSaveAsSettings() +{ + KURL saveCurvesFile; + + saveCurvesFile = KFileDialog::getSaveURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), kapp->activeWindow(), + TQString( i18n("Gimp Curves File to Save")) ); + if( saveCurvesFile.isEmpty() ) + return; + + if ( m_curvesWidget->curves()->saveCurvesToGimpCurvesFile( saveCurvesFile ) == false ) + { + KMessageBox::error(kapp->activeWindow(), i18n("Cannot save to the Gimp curves text file.")); + return; + } + + // Refresh the current curves config. + slotChannelChanged(m_channelCB->currentItem()); +} + +} // NameSpace DigikamAdjustCurvesImagesPlugin diff --git a/src/imageplugins/adjustcurves/adjustcurvestool.h b/src/imageplugins/adjustcurves/adjustcurvestool.h new file mode 100644 index 00000000..4a380530 --- /dev/null +++ b/src/imageplugins/adjustcurves/adjustcurvestool.h @@ -0,0 +1,145 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-01 + * Description : image histogram adjust curves. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef ADJUSTCURVESTOOL_H +#define ADJUSTCURVESTOOL_H + +// Digikam includes. + +#include "editortool.h" + +// Local includes. + +class TQComboBox; +class TQPushButton; +class TQHButtonGroup; + +namespace Digikam +{ +class CurvesWidget; +class HistogramWidget; +class ColorGradientWidget; +class EditorToolSettings; +class ImageWidget; +class DImg; +class DColor; +} + +namespace DigikamAdjustCurvesImagesPlugin +{ + +class AdjustCurvesTool : public Digikam::EditorTool +{ + TQ_OBJECT + + +public: + + AdjustCurvesTool(TQObject *parent); + ~AdjustCurvesTool(); + +private: + + void readSettings(); + void writeSettings(); + void finalRendering(); + +private slots: + + void slotSaveAsSettings(); + void slotLoadSettings(); + void slotEffect(); + void slotResetSettings(); + void slotResetCurrentChannel(); + void slotChannelChanged(int channel); + void slotScaleChanged(int scale); + void slotCurveTypeChanged(int type); + void slotSpotColorChanged(const Digikam::DColor& color); + void slotColorSelectedFromTarget(const Digikam::DColor& color); + void slotPickerColorButtonActived(); + +private: + + enum ColorPicker + { + BlackTonal=0, + GrayTonal, + WhiteTonal + }; + + enum ColorChannel + { + LuminosityChannel=0, + RedChannel, + GreenChannel, + BlueChannel, + AlphaChannel + }; + + enum CurvesDrawingType + { + SmoothDrawing=0, + FreeDrawing + }; + + enum HistogramScale + { + Linear=0, + Logarithmic + }; + + uchar *m_destinationPreviewData; + + int m_histoSegments; + int m_currentPreviewMode; + + TQComboBox *m_channelCB; + + TQPushButton *m_resetButton; + TQPushButton *m_pickBlack; + TQPushButton *m_pickGray; + TQPushButton *m_pickWhite; + TQPushButton *m_curveFree; + TQPushButton *m_curveSmooth; + + TQHButtonGroup *m_pickerColorButtonGroup; + TQHButtonGroup *m_scaleBG; + TQHButtonGroup *m_curveType; + + Digikam::CurvesWidget *m_curvesWidget; + + Digikam::HistogramWidget *m_histogramWidget; + + Digikam::ColorGradientWidget *m_hGradient; + Digikam::ColorGradientWidget *m_vGradient; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; + + Digikam::DImg *m_originalImage; +}; + +} // NameSpace DigikamAdjustCurvesImagesPlugin + +#endif /* ADJUSTCURVESTOOL_H */ diff --git a/src/imageplugins/adjustcurves/digikamimageplugin_adjustcurves.desktop b/src/imageplugins/adjustcurves/digikamimageplugin_adjustcurves.desktop new file mode 100644 index 00000000..377c2a33 --- /dev/null +++ b/src/imageplugins/adjustcurves/digikamimageplugin_adjustcurves.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Name=ImagePlugin_AdjustCurves +Name[bg]=Приставка за снимки - Настройка на кривите +Name[da]=Billedplugin_Kurvejustering +Name[el]=ΠρόσθετοΕικόνας_ΠροσαρμογήΚαμπύλων +Name[fi]=TasonsäätöKäyrä +Name[hr]=Podešavanje krivulja +Name[it]=PluginImmagini_RegolaCurve +Name[nl]=Afbeeldingsplugin_CurvesAanpassen +Name[sr]=Подешавање кривих +Name[sr@Latn]=Podešavanje krivih +Name[sv]=Insticksprogram för justering av kurvor +Name[tr]=ResimEklentisi_EğriAyarla +Name[xx]=xxImagePlugin_AdjustCurvesxx +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 + +Comment=Image histogram adjust curves plugin for digiKam +Comment[bg]=Приставка на digiKam за настройка кривите на хистограмите на снимки +Comment[ca]=Connector pel digiKam d'ajust de les corbes de l'histograma d'imatges +Comment[da]=Plugin til histogramkurvejustering i Digikam +Comment[de]=digiKam-Modul zur Justierung der Farbkurven +Comment[el]=Πρόσθετο προσαρμογής των καμπύλων του ιστογράμματος εικόνας για το digiKam +Comment[es]=Histograma de imágenes, plugin de ajuste de curvas para digiKam +Comment[et]=DigiKami pildi histogrammi kõverate kohendamise plugin +Comment[fa]=وصلۀ منحنیهای تنظیم سابقهنمای تصویر برای digiKam +Comment[fi]=Muokkaa värikanavien raja-arvoja +Comment[fr]=Module externe pour ajuster les courbes de l'histogramme dans digiKam +Comment[gl]=Un plugin de digiKam para o axuste das curvas do histograma da imaxe +Comment[hr]=digiKam dodatak za histogramsko podešavanje krivulja +Comment[is]=Íforrit fyrir digiKam sem breytir ferlum (curves) í stuðlariti myndar +Comment[it]=Plugin di regolazione delle curve degli istogrammi delle immagini per digiKam +Comment[ja]=digiKam カーブ補正プラグイン +Comment[nds]=digiKam-Moduul för't Topassen vun Histogramm-Klöörbagens +Comment[nl]=Digikam-plugin voor curvesaanpassing van afbeeldingshistogram +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਚਿੱਤਰ ਹਿਸਟੋਗਰਾਮ ਅਨੁਕੂਲ ਚਾਪ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam dostosowująca krzywe i histogram dla obrazu +Comment[pt]=Um 'plugin' do digiKam de ajuste de curvas do histograma da imagem +Comment[pt_BR]=Plugin de ajuste de curvas do histograma da imagem +Comment[ru]=Модуль digiKam подстройки кривых гистограммы изображения +Comment[sk]=digiKam plugin histogramu kriviek úprav obrázku +Comment[sr]=digiKam-ов прикључак за подешавање кривих хистограма слике +Comment[sr@Latn]=digiKam-ov priključak za podešavanje krivih histograma slike +Comment[sv]=Digikam insticksprogram för justering av kurvor i bildhistogram +Comment[tr]=digiKam için resim histogram eğrileri ayarlama eklentisi +Comment[uk]=Втулок коригування кривих гістограми зображень для digiKam +Comment[vi]=Phần bổ sung biểu đồ tần xuất điều chỉnh đường cong ảnh cho digiKam +Comment[xx]=xxImage histogram adjust curves plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_adjustcurves +author=Caulier Gilles, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/adjustcurves/digikamimageplugin_adjustcurves_ui.rc b/src/imageplugins/adjustcurves/digikamimageplugin_adjustcurves_ui.rc new file mode 100644 index 00000000..c87c2c1e --- /dev/null +++ b/src/imageplugins/adjustcurves/digikamimageplugin_adjustcurves_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="5" name="digikamimageplugin_adjustcurves" > + + <MenuBar> + + <Menu name="Color" ><text>&Color</text> + <Action name="imageplugin_adjustcurves" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action name="imageplugin_adjustcurves" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/adjustcurves/imageplugin_adjustcurves.cpp b/src/imageplugins/adjustcurves/imageplugin_adjustcurves.cpp new file mode 100644 index 00000000..11b6e53f --- /dev/null +++ b/src/imageplugins/adjustcurves/imageplugin_adjustcurves.cpp @@ -0,0 +1,70 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-01 + * Description : image histogram adjust curves. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> + +// Local includes. + +#include "ddebug.h" +#include "adjustcurvestool.h" +#include "imageplugin_adjustcurves.h" +#include "imageplugin_adjustcurves.moc" + +using namespace DigikamAdjustCurvesImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY( digikamimageplugin_adjustcurves, + KGenericFactory<ImagePlugin_AdjustCurves>("digikamimageplugin_adjustcurves")); + +ImagePlugin_AdjustCurves::ImagePlugin_AdjustCurves(TQObject *parent, const char*, const TQStringList&) + : Digikam::ImagePlugin(parent, "ImagePlugin_AdjustCurves") +{ + m_curvesAction = new TDEAction(i18n("Curves Adjust..."), "adjustcurves", + CTRL+SHIFT+Key_M, // NOTE: Photoshop 7 use CTRL+M (but it's used in KDE to toogle menu bar). + this, TQ_SLOT(slotCurvesAdjust()), + actionCollection(), "imageplugin_adjustcurves"); + + setXMLFile("digikamimageplugin_adjustcurves_ui.rc"); + + DDebug() << "ImagePlugin_AdjustCurves plugin loaded" << endl; +} + +ImagePlugin_AdjustCurves::~ImagePlugin_AdjustCurves() +{ +} + +void ImagePlugin_AdjustCurves::setEnabledActions(bool enable) +{ + m_curvesAction->setEnabled(enable); +} + +void ImagePlugin_AdjustCurves::slotCurvesAdjust() +{ + AdjustCurvesTool *curves = new AdjustCurvesTool(this); + loadTool(curves); +} diff --git a/src/imageplugins/adjustcurves/imageplugin_adjustcurves.h b/src/imageplugins/adjustcurves/imageplugin_adjustcurves.h new file mode 100644 index 00000000..f8e43578 --- /dev/null +++ b/src/imageplugins/adjustcurves/imageplugin_adjustcurves.h @@ -0,0 +1,56 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-01 + * Description : image histogram adjust curves. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_ADJUSTCURVES_H +#define IMAGEPLUGIN_ADJUSTCURVES_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_AdjustCurves : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_AdjustCurves(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_AdjustCurves(); + + void setEnabledActions(bool enable); + +private slots: + + void slotCurvesAdjust(); + +private: + + TDEAction *m_curvesAction; +}; + +#endif /* IMAGEPLUGIN_ADJUSTCURVES_H */ diff --git a/src/imageplugins/adjustlevels/Makefile.am b/src/imageplugins/adjustlevels/Makefile.am new file mode 100644 index 00000000..2b04f4cc --- /dev/null +++ b/src/imageplugins/adjustlevels/Makefile.am @@ -0,0 +1,34 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_adjustlevels_la_SOURCES = imageplugin_adjustlevels.cpp \ + adjustlevelstool.cpp + +digikamimageplugin_adjustlevels_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_adjustlevels_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_adjustlevels.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_adjustlevels.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_adjustlevels_ui.rc + diff --git a/src/imageplugins/adjustlevels/adjustlevels.cpp b/src/imageplugins/adjustlevels/adjustlevels.cpp new file mode 100644 index 00000000..72d5e46b --- /dev/null +++ b/src/imageplugins/adjustlevels/adjustlevels.cpp @@ -0,0 +1,913 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-20 + * Description : image histogram adjust levels. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// C++ includes. + +#include <cmath> + +// TQt includes. + +#include <tqlayout.h> +#include <tqcolor.h> +#include <tqgroupbox.h> +#include <tqhgroupbox.h> +#include <tqvgroupbox.h> +#include <tqlabel.h> +#include <tqpainter.h> +#include <tqcombobox.h> +#include <tqspinbox.h> +#include <tqwhatsthis.h> +#include <tqtooltip.h> +#include <tqpushbutton.h> +#include <tqlayout.h> +#include <tqframe.h> +#include <tqtimer.h> +#include <tqhbuttongroup.h> +#include <tqpixmap.h> + +// KDE includes. + +#include <tdeconfig.h> +#include <kcursor.h> +#include <tdelocale.h> +#include <knuminput.h> +#include <tdemessagebox.h> +#include <tdeselect.h> +#include <tdefiledialog.h> +#include <tdeglobalsettings.h> +#include <tdeaboutdata.h> +#include <khelpmenu.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <tdepopupmenu.h> +#include <kstandarddirs.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "imagehistogram.h" +#include "imagelevels.h" +#include "histogramwidget.h" +#include "dimgimagefilters.h" +#include "adjustlevels.h" +#include "adjustlevels.moc" + +namespace DigikamAdjustLevelsImagesPlugin +{ + +AdjustLevelDialog::AdjustLevelDialog(TQWidget* parent) + : Digikam::ImageDlgBase(parent, i18n("Adjust Color Levels"), + "adjustlevels", true, false) +{ + m_destinationPreviewData = 0L; + + Digikam::ImageIface iface(0, 0); + uchar *data = iface.getOriginalImage(); + int w = iface.originalWidth(); + int h = iface.originalHeight(); + bool sixteenBit = iface.originalSixteenBit(); + bool hasAlpha = iface.originalHasAlpha(); + m_originalImage = Digikam::DImg(w, h, sixteenBit, hasAlpha ,data); + delete [] data; + + m_histoSegments = m_originalImage.sixteenBit() ? 65535 : 255; + m_levels = new Digikam::ImageLevels(m_originalImage.sixteenBit()); + + // About data and help button. + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Adjust Color Levels"), + digikam_version, + I18N_NOOP("An image-histogram-levels adjustment plugin for digiKam."), + TDEAboutData::License_GPL, + "(c) 2004-2008, Gilles Caulier", + 0, + "http://www.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + setAboutData(about); + + // ------------------------------------------------------------- + + m_previewWidget = new Digikam::ImageWidget("adjustlevels Tool Dialog", plainPage(), + i18n("<p>Here you can see the image's " + "level-adjustments preview. You can pick a spot on the image " + "to see the corresponding level in the histogram.")); + setPreviewAreaWidget(m_previewWidget); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(plainPage()); + TQGridLayout* grid = new TQGridLayout(gboxSettings, 16, 8, spacingHint(), 0); + + TQLabel *label1 = new TQLabel(i18n("Channel:"), gboxSettings); + label1->setAlignment ( TQt::AlignRight | TQt::AlignVCenter ); + m_channelCB = new TQComboBox( false, gboxSettings ); + m_channelCB->insertItem( i18n("Luminosity") ); + m_channelCB->insertItem( i18n("Red") ); + m_channelCB->insertItem( i18n("Green") ); + m_channelCB->insertItem( i18n("Blue") ); + m_channelCB->insertItem( i18n("Alpha") ); + m_channelCB->setCurrentText( i18n("Luminosity") ); + TQWhatsThis::add( m_channelCB, i18n("<p>Here select the histogram channel to display:<p>" + "<b>Luminosity</b>: display the image's luminosity values.<p>" + "<b>Red</b>: display the red image-channel values.<p>" + "<b>Green</b>: display the green image-channel values.<p>" + "<b>Blue</b>: display the blue image-channel values.<p>" + "<b>Alpha</b>: display the alpha image-channel values. " + "This channel corresponds to the transparency value and " + "is supported by some image formats, such as PNG or TIF.")); + + m_scaleBG = new TQHButtonGroup(gboxSettings); + m_scaleBG->setExclusive(true); + m_scaleBG->setFrameShape(TQFrame::NoFrame); + m_scaleBG->setInsideMargin( 0 ); + TQWhatsThis::add( m_scaleBG, i18n("<p>Here select the histogram scale.<p>" + "If the image's maximal counts are small, you can use the linear scale.<p>" + "The Logarithmic scale can be used when the maximal counts 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( "<p>Linear" ) ); + m_scaleBG->insert(linHistoButton, Digikam::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( "<p>Logarithmic" ) ); + m_scaleBG->insert(logHistoButton, Digikam::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); + + // ------------------------------------------------------------- + + m_histogramWidget = new Digikam::HistogramWidget(256, 140, gboxSettings, false, true, true); + TQWhatsThis::add( m_histogramWidget, i18n("<p>Here you can see the target preview image histogram drawing of the " + "selected image channel. This one is re-computed at any levels " + "settings changes.")); + + m_levelsHistogramWidget = new Digikam::HistogramWidget(256, 140, m_originalImage.bits(), m_originalImage.width(), + m_originalImage.height(), m_originalImage.sixteenBit(), gboxSettings, false); + TQWhatsThis::add( m_levelsHistogramWidget, i18n("<p>This is the histogram drawing of the selected channel " + "from original image")); + + // ------------------------------------------------------------- + + m_hGradientMinInput = new KGradientSelector( TDESelector::Horizontal, gboxSettings ); + m_hGradientMinInput->setFixedHeight( 20 ); + m_hGradientMinInput->setMinValue(0); + m_hGradientMinInput->setMaxValue(m_histoSegments); + TQWhatsThis::add( m_hGradientMinInput, i18n("<p>Select the minimal intensity input value of the histogram.")); + TQToolTip::add( m_hGradientMinInput, i18n( "Minimal intensity input." ) ); + m_hGradientMinInput->setColors( TQColor( "black" ), TQColor( "white" ) ); + m_hGradientMinInput->installEventFilter(this); + + m_hGradientMaxInput = new KGradientSelector( TDESelector::Horizontal, gboxSettings ); + m_hGradientMaxInput->setFixedHeight( 20 ); + m_hGradientMaxInput->setMinValue(0); + m_hGradientMaxInput->setMaxValue(m_histoSegments); + TQWhatsThis::add( m_hGradientMaxInput, i18n("<p>Select the maximal intensity input value of the histogram.")); + TQToolTip::add( m_hGradientMaxInput, i18n( "Maximal intensity input." ) ); + m_hGradientMaxInput->setColors( TQColor( "black" ), TQColor( "white" ) ); + m_hGradientMaxInput->installEventFilter(this); + + m_minInput = new TQSpinBox(0, m_histoSegments, 1, gboxSettings); + m_minInput->setValue(0); + TQWhatsThis::add( m_minInput, i18n("<p>Select the minimal intensity input value of the histogram.")); + TQToolTip::add( m_minInput, i18n( "Minimal intensity input." ) ); + + m_gammaInput = new KDoubleNumInput(gboxSettings); + m_gammaInput->setPrecision(2); + m_gammaInput->setRange(0.1, 3.0, 0.01); + m_gammaInput->setValue(1.0); + TQToolTip::add( m_gammaInput, i18n( "Gamma input value." ) ); + TQWhatsThis::add( m_gammaInput, i18n("<p>Select the gamma input value.")); + + m_maxInput = new TQSpinBox(0, m_histoSegments, 1, gboxSettings); + m_maxInput->setValue(m_histoSegments); + TQToolTip::add( m_maxInput, i18n( "Maximal intensity input." ) ); + TQWhatsThis::add( m_maxInput, i18n("<p>Select the maximal intensity input value of the histogram.")); + + m_hGradientMinOutput = new KGradientSelector( TDESelector::Horizontal, gboxSettings ); + m_hGradientMinOutput->setColors( TQColor( "black" ), TQColor( "white" ) ); + TQWhatsThis::add( m_hGradientMinOutput, i18n("<p>Select the minimal intensity output value of the histogram.")); + TQToolTip::add( m_hGradientMinOutput, i18n( "Minimal intensity output." ) ); + m_hGradientMinOutput->setFixedHeight( 20 ); + m_hGradientMinOutput->setMinValue(0); + m_hGradientMinOutput->setMaxValue(m_histoSegments); + m_hGradientMinOutput->installEventFilter(this); + + m_hGradientMaxOutput = new KGradientSelector( TDESelector::Horizontal, gboxSettings ); + m_hGradientMaxOutput->setColors( TQColor( "black" ), TQColor( "white" ) ); + TQWhatsThis::add( m_hGradientMaxOutput, i18n("<p>Select the maximal intensity output value of the histogram.")); + TQToolTip::add( m_hGradientMaxOutput, i18n( "Maximal intensity output." ) ); + m_hGradientMaxOutput->setFixedHeight( 20 ); + m_hGradientMaxOutput->setMinValue(0); + m_hGradientMaxOutput->setMaxValue(m_histoSegments); + m_hGradientMaxOutput->installEventFilter(this); + + m_minOutput = new TQSpinBox(0, m_histoSegments, 1, gboxSettings); + m_minOutput->setValue(0); + TQToolTip::add( m_minOutput, i18n( "Minimal intensity output." ) ); + TQWhatsThis::add( m_minOutput, i18n("<p>Select the minimal intensity output value of the histogram.")); + + m_maxOutput = new TQSpinBox(0, m_histoSegments, 1, gboxSettings); + m_maxOutput->setValue(m_histoSegments); + TQToolTip::add( m_maxOutput, i18n( "Maximal intensity output." ) ); + TQWhatsThis::add( m_maxOutput, i18n("<p>Select the maximal intensity output value of the histogram.")); + + // ------------------------------------------------------------- + + m_pickerColorButtonGroup = new TQHButtonGroup(gboxSettings); + m_pickBlack = new TQPushButton(m_pickerColorButtonGroup); + m_pickerColorButtonGroup->insert(m_pickBlack, BlackTonal); + TDEGlobal::dirs()->addResourceType("color-picker-black", TDEGlobal::dirs()->kde_default("data") + + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("color-picker-black", "color-picker-black.png"); + m_pickBlack->setPixmap( TQPixmap( directory + "color-picker-black.png" ) ); + m_pickBlack->setToggleButton(true); + TQToolTip::add( m_pickBlack, i18n( "All channels shadow tone color picker" ) ); + TQWhatsThis::add( m_pickBlack, i18n("<p>With this button, you can pick the color from original image used to set <b>Shadow Tone</b> " + "levels input on Red, Green, Blue, and Luminosity channels.")); + m_pickGray = new TQPushButton(m_pickerColorButtonGroup); + m_pickerColorButtonGroup->insert(m_pickGray, GrayTonal); + TDEGlobal::dirs()->addResourceType("color-picker-gray", TDEGlobal::dirs()->kde_default("data") + + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("color-picker-gray", "color-picker-gray.png"); + m_pickGray->setPixmap( TQPixmap( directory + "color-picker-gray.png" ) ); + m_pickGray->setToggleButton(true); + TQToolTip::add( m_pickGray, i18n( "All channels middle tone color picker" ) ); + TQWhatsThis::add( m_pickGray, i18n("<p>With this button, you can pick the color from original image used to set <b>Middle Tone</b> " + "levels input on Red, Green, Blue, and Luminosity channels.")); + m_pickWhite = new TQPushButton(m_pickerColorButtonGroup); + m_pickerColorButtonGroup->insert(m_pickWhite, WhiteTonal); + TDEGlobal::dirs()->addResourceType("color-picker-white", TDEGlobal::dirs()->kde_default("data") + + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("color-picker-white", "color-picker-white.png"); + m_pickWhite->setPixmap( TQPixmap( directory + "color-picker-white.png" ) ); + m_pickWhite->setToggleButton(true); + TQToolTip::add( m_pickWhite, i18n( "All channels highlight tone color picker" ) ); + TQWhatsThis::add( m_pickWhite, i18n("<p>With this button, you can pick the color from original image used to set <b>Highlight Tone</b> " + "levels input on Red, Green, Blue, and Luminosity channels.")); + m_pickerColorButtonGroup->setExclusive(true); + m_pickerColorButtonGroup->setFrameShape(TQFrame::NoFrame); + + m_autoButton = new TQPushButton(gboxSettings); + m_autoButton->setPixmap(kapp->iconLoader()->loadIcon("system-run", (TDEIcon::Group)TDEIcon::Toolbar)); TQToolTip::add( m_autoButton, i18n( "Adjust all levels automatically." ) ); + TQWhatsThis::add( m_autoButton, i18n("<p>If you press this button, all channel levels will be adjusted " + "automatically.")); + + m_resetButton = new TQPushButton(i18n("&Reset"), gboxSettings); + m_resetButton->setPixmap(kapp->iconLoader()->loadIcon("reload_page", (TDEIcon::Group)TDEIcon::Toolbar)); + TQToolTip::add( m_resetButton, i18n( "Reset current channel levels' values." ) ); + TQWhatsThis::add( m_resetButton, i18n("<p>If you press this button, all levels' values " + "from the current selected channel " + "will be reset to the default values.")); + + TQLabel *space = new TQLabel(gboxSettings); + space->setFixedWidth(spacingHint()); + + TQHBoxLayout* l3 = new TQHBoxLayout(); + l3->addWidget(m_pickerColorButtonGroup); + l3->addWidget(m_autoButton); + l3->addWidget(space); + l3->addWidget(m_resetButton); + l3->addStretch(10); + + // ------------------------------------------------------------- + + grid->addMultiCellLayout(l1, 0, 0, 0, 6); + grid->setRowSpacing(1, spacingHint()); + grid->addMultiCellWidget(m_histogramWidget, 2, 2, 1, 5); + grid->setRowSpacing(3, spacingHint()); + grid->addMultiCellWidget(m_levelsHistogramWidget, 4, 4, 1, 5); + grid->addMultiCellWidget(m_hGradientMinInput, 5, 5, 0, 6); + grid->addMultiCellWidget(m_minInput, 5, 5, 8, 8); + grid->setRowSpacing(6, spacingHint()); + grid->addMultiCellWidget(m_hGradientMaxInput, 7, 7, 0, 6); + grid->addMultiCellWidget(m_maxInput, 7, 7, 8, 8); + grid->setRowSpacing(8, spacingHint()); + grid->addMultiCellWidget(m_gammaInput, 9, 9, 0, 8); + grid->setRowSpacing(10, spacingHint()); + grid->addMultiCellWidget(m_hGradientMinOutput, 11, 11, 0, 6); + grid->addMultiCellWidget(m_minOutput, 11, 11, 8, 8); + grid->setRowSpacing(12, spacingHint()); + grid->addMultiCellWidget(m_hGradientMaxOutput, 13, 13, 0, 6); + grid->addMultiCellWidget(m_maxOutput, 13, 13, 8, 8); + grid->setRowSpacing(14, spacingHint()); + grid->addMultiCellLayout(l3, 15, 15, 0, 8); + grid->setRowStretch(16, 10); + grid->setColStretch(2, 10); + grid->setColSpacing(0, 5); + grid->setColSpacing(6, 5); + grid->setColSpacing(7, spacingHint()); + + setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + // Channels and scale selection slots. + + 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_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 & ))); + + connect(m_previewWidget, TQ_SIGNAL(signalResized()), + this, TQ_SLOT(slotEffect())); + + // ------------------------------------------------------------- + // Color sliders and spinbox slots. + + connect(m_hGradientMinInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotAdjustMinInputSpinBox(int))); + + connect(m_minInput, TQ_SIGNAL(valueChanged (int)), + this, TQ_SLOT(slotAdjustSliders())); + + connect(m_gammaInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotGammaInputchanged(double))); + + connect(m_hGradientMaxInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotAdjustMaxInputSpinBox(int))); + + connect(m_maxInput, TQ_SIGNAL(valueChanged (int)), + this, TQ_SLOT(slotAdjustSliders())); + + connect(m_hGradientMinOutput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotAdjustMinOutputSpinBox(int))); + + connect(m_minOutput, TQ_SIGNAL(valueChanged (int)), + this, TQ_SLOT(slotAdjustSliders())); + + connect(m_hGradientMaxOutput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotAdjustMaxOutputSpinBox(int))); + + connect(m_maxOutput, TQ_SIGNAL(valueChanged (int)), + this, TQ_SLOT(slotAdjustSliders())); + + // ------------------------------------------------------------- + // Bouttons slots. + + connect(m_autoButton, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotAutoLevels())); + + connect(m_resetButton, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotResetCurrentChannel())); + + connect(m_pickerColorButtonGroup, TQ_SIGNAL(released(int)), + this, TQ_SLOT(slotPickerColorButtonActived())); + +} + +AdjustLevelDialog::~AdjustLevelDialog() +{ + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + delete m_histogramWidget; + delete m_levelsHistogramWidget; + delete m_levels; +} + +void AdjustLevelDialog::slotPickerColorButtonActived() +{ + // Save previous rendering mode and toggle to original image. + m_currentPreviewMode = m_previewWidget->getRenderingPreviewMode(); + m_previewWidget->setRenderingPreviewMode(Digikam::ImageGuideWidget::PreviewOriginalImage); +} + +void AdjustLevelDialog::slotSpotColorChanged(const Digikam::DColor &color) +{ + if ( m_pickBlack->isOn() ) + { + // Black tonal levels point. + m_levels->levelsBlackToneAdjustByColors(m_channelCB->currentItem(), color); + m_pickBlack->setOn(false); + } + else if ( m_pickGray->isOn() ) + { + // Gray tonal levels point. + m_levels->levelsGrayToneAdjustByColors(m_channelCB->currentItem(), color); + m_pickGray->setOn(false); + } + else if ( m_pickWhite->isOn() ) + { + // White tonal levels point. + m_levels->levelsWhiteToneAdjustByColors(m_channelCB->currentItem(), color); + m_pickWhite->setOn(false); + } + else + { + m_levelsHistogramWidget->setHistogramGuideByColor(color); + return; + } + + // Refresh the current levels config. + slotChannelChanged(m_channelCB->currentItem()); + + // restore previous rendering mode. + m_previewWidget->setRenderingPreviewMode(m_currentPreviewMode); + + slotEffect(); +} + +void AdjustLevelDialog::slotColorSelectedFromTarget( const Digikam::DColor &color ) +{ + m_histogramWidget->setHistogramGuideByColor(color); +} + +void AdjustLevelDialog::slotGammaInputchanged(double val) +{ + blockSignals(true); + m_levels->setLevelGammaValue(m_channelCB->currentItem(), val); + blockSignals(false); + slotTimer(); +} + +void AdjustLevelDialog::slotAdjustMinInputSpinBox(int val) +{ + blockSignals(true); + + if ( val < m_hGradientMaxInput->value() ) + val = m_hGradientMaxInput->value(); + + m_minInput->setValue(m_histoSegments - val); + m_hGradientMinInput->setValue( val ); + m_levels->setLevelLowInputValue(m_channelCB->currentItem(), m_histoSegments - val); + blockSignals(false); + slotTimer(); +} + +void AdjustLevelDialog::slotAdjustMaxInputSpinBox(int val) +{ + blockSignals(true); + + if ( val > m_hGradientMinInput->value() ) + val = m_hGradientMinInput->value(); + + m_maxInput->setValue(m_histoSegments - val); + m_hGradientMaxInput->setValue( val ); + m_levels->setLevelHighInputValue(m_channelCB->currentItem(), m_histoSegments - val); + blockSignals(false); + slotTimer(); +} + +void AdjustLevelDialog::slotAdjustMinOutputSpinBox(int val) +{ + blockSignals(true); + + if ( val < m_hGradientMaxOutput->value() ) + val = m_hGradientMaxOutput->value(); + + m_minOutput->setValue(m_histoSegments - val); + m_hGradientMinOutput->setValue( val ); + m_levels->setLevelLowOutputValue(m_channelCB->currentItem(), m_histoSegments - val); + blockSignals(false); + slotTimer(); +} + +void AdjustLevelDialog::slotAdjustMaxOutputSpinBox(int val) +{ + blockSignals(true); + + if ( val > m_hGradientMinOutput->value() ) + val = m_hGradientMinOutput->value(); + + m_maxOutput->setValue(m_histoSegments - val); + m_hGradientMaxOutput->setValue( val ); + m_levels->setLevelHighOutputValue(m_channelCB->currentItem(), m_histoSegments - val); + blockSignals(false); + slotTimer(); +} + +void AdjustLevelDialog::slotAdjustSliders() +{ + adjustSliders(m_minInput->value(), m_gammaInput->value(), + m_maxInput->value(), m_minOutput->value(), + m_maxOutput->value()); +} + +void AdjustLevelDialog::adjustSliders(int minIn, double gamIn, int maxIn, int minOut, int maxOut) +{ + m_hGradientMinInput->setValue(m_histoSegments - minIn); + m_hGradientMaxInput->setValue(m_histoSegments - maxIn); + m_gammaInput->setValue(gamIn); + m_hGradientMinOutput->setValue(m_histoSegments - minOut); + m_hGradientMaxOutput->setValue(m_histoSegments - maxOut); +} + +void AdjustLevelDialog::slotResetCurrentChannel() +{ + m_levels->levelsChannelReset(m_channelCB->currentItem()); + + // Refresh the current levels config. + slotChannelChanged(m_channelCB->currentItem()); + m_levelsHistogramWidget->reset(); + + slotEffect(); + m_histogramWidget->reset(); +} + +void AdjustLevelDialog::slotAutoLevels() +{ + // Calculate Auto levels. + m_levels->levelsAuto(m_levelsHistogramWidget->m_imageHistogram); + + // Refresh the current levels config. + slotChannelChanged(m_channelCB->currentItem()); + + slotEffect(); +} + +void AdjustLevelDialog::slotEffect() +{ + Digikam::ImageIface* iface = m_previewWidget->imageIface(); + uchar *orgData = iface->getPreviewImage(); + int w = iface->previewWidth(); + int h = iface->previewHeight(); + bool sb = iface->previewSixteenBit(); + + // Create the new empty destination image data space. + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + m_destinationPreviewData = new uchar[w*h*(sb ? 8 : 4)]; + + // Calculate the LUT to apply on the image. + m_levels->levelsLutSetup(Digikam::ImageHistogram::AlphaChannel); + + // Apply the lut to the image. + m_levels->levelsLutProcess(orgData, m_destinationPreviewData, w, h); + + iface->putPreviewImage(m_destinationPreviewData); + m_previewWidget->updatePreview(); + + // Update histogram. + m_histogramWidget->updateData(m_destinationPreviewData, w, h, sb, 0, 0, 0, false); + + delete [] orgData; +} + +void AdjustLevelDialog::finalRendering() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + Digikam::ImageIface* iface = m_previewWidget->imageIface(); + uchar *orgData = iface->getOriginalImage(); + int w = iface->originalWidth(); + int h = iface->originalHeight(); + bool sb = iface->originalSixteenBit(); + + // Create the new empty destination image data space. + uchar* desData = new uchar[w*h*(sb ? 8 : 4)]; + + // Calculate the LUT to apply on the image. + m_levels->levelsLutSetup(Digikam::ImageHistogram::AlphaChannel); + + // Apply the lut to the image. + m_levels->levelsLutProcess(orgData, desData, w, h); + + iface->putOriginalImage(i18n("Adjust Level"), desData); + kapp->restoreOverrideCursor(); + + delete [] orgData; + delete [] desData; + accept(); +} + +void AdjustLevelDialog::slotChannelChanged(int channel) +{ + switch(channel) + { + case LuminosityChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::ValueHistogram; + m_levelsHistogramWidget->m_channelType = Digikam::HistogramWidget::ValueHistogram; + m_hGradientMinInput->setColors( TQColor( "black" ), TQColor( "white" ) ); + m_hGradientMaxInput->setColors( TQColor( "black" ), TQColor( "white" ) ); + m_hGradientMinOutput->setColors( TQColor( "black" ), TQColor( "white" ) ); + m_hGradientMaxOutput->setColors( TQColor( "black" ), TQColor( "white" ) ); + break; + + case RedChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::RedChannelHistogram; + m_levelsHistogramWidget->m_channelType = Digikam::HistogramWidget::RedChannelHistogram; + m_hGradientMinInput->setColors( TQColor( "black" ), TQColor( "red" ) ); + m_hGradientMaxInput->setColors( TQColor( "black" ), TQColor( "red" ) ); + m_hGradientMinOutput->setColors( TQColor( "black" ), TQColor( "red" ) ); + m_hGradientMaxOutput->setColors( TQColor( "black" ), TQColor( "red" ) ); + break; + + case GreenChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::GreenChannelHistogram; + m_levelsHistogramWidget->m_channelType = Digikam::HistogramWidget::GreenChannelHistogram; + m_hGradientMinInput->setColors( TQColor( "black" ), TQColor( "green" ) ); + m_hGradientMaxInput->setColors( TQColor( "black" ), TQColor( "green" ) ); + m_hGradientMinOutput->setColors( TQColor( "black" ), TQColor( "green" ) ); + m_hGradientMaxOutput->setColors( TQColor( "black" ), TQColor( "green" ) ); + break; + + case BlueChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::BlueChannelHistogram; + m_levelsHistogramWidget->m_channelType = Digikam::HistogramWidget::BlueChannelHistogram; + m_hGradientMinInput->setColors( TQColor( "black" ), TQColor( "blue" ) ); + m_hGradientMaxInput->setColors( TQColor( "black" ), TQColor( "blue" ) ); + m_hGradientMinOutput->setColors( TQColor( "black" ), TQColor( "blue" ) ); + m_hGradientMaxOutput->setColors( TQColor( "black" ), TQColor( "blue" ) ); + break; + + case AlphaChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::AlphaChannelHistogram; + m_levelsHistogramWidget->m_channelType = Digikam::HistogramWidget::AlphaChannelHistogram; + m_hGradientMinInput->setColors( TQColor( "black" ), TQColor( "white" ) ); + m_hGradientMaxInput->setColors( TQColor( "black" ), TQColor( "white" ) ); + m_hGradientMinOutput->setColors( TQColor( "black" ), TQColor( "white" ) ); + m_hGradientMaxOutput->setColors( TQColor( "black" ), TQColor( "white" ) ); + break; + } + + adjustSliders(m_levels->getLevelLowInputValue(channel), + m_levels->getLevelGammaValue(channel), + m_levels->getLevelHighInputValue(channel), + m_levels->getLevelLowOutputValue(channel), + m_levels->getLevelHighOutputValue(channel)); + + m_levelsHistogramWidget->repaint(false); + m_histogramWidget->repaint(false); +} + +void AdjustLevelDialog::slotScaleChanged(int scale) +{ + m_levelsHistogramWidget->m_scaleType = scale; + m_histogramWidget->m_scaleType = scale; + m_histogramWidget->repaint(false); + m_levelsHistogramWidget->repaint(false); +} + +void AdjustLevelDialog::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("adjustlevels Tool Dialog"); + + m_channelCB->setCurrentItem(config->readNumEntry("Histogram Channel", 0)); // Luminosity. + m_scaleBG->setButton(config->readNumEntry("Histogram Scale", Digikam::HistogramWidget::LogScaleHistogram)); + + for (int i = 0 ; i < 5 ; i++) + { + bool sb = m_originalImage.sixteenBit(); + int max = sb ? 65535 : 255; + double gamma = config->readDoubleNumEntry(TQString("GammaChannel%1").arg(i), 1.0); + int lowInput = config->readNumEntry(TQString("LowInputChannel%1").arg(i), 0); + int lowOutput = config->readNumEntry(TQString("LowOutputChannel%1").arg(i), 0); + int highInput = config->readNumEntry(TQString("HighInputChannel%1").arg(i), max); + int highOutput = config->readNumEntry(TQString("HighOutputChannel%1").arg(i), max); + + m_levels->setLevelGammaValue(i, gamma); + m_levels->setLevelLowInputValue(i, sb ? lowInput*255 : lowInput); + m_levels->setLevelHighInputValue(i, sb ? highInput*255 : highInput); + m_levels->setLevelLowOutputValue(i, sb ? lowOutput*255 : lowOutput); + m_levels->setLevelHighOutputValue(i, sb ? highOutput*255 : highOutput); + } + + m_levelsHistogramWidget->reset(); + m_histogramWidget->reset(); + slotChannelChanged(m_channelCB->currentItem()); + slotScaleChanged(m_scaleBG->selectedId()); + + // This is mandatory here to set spinbox values because slot connections + // can be not set completely at plugin startup. + m_minInput->setValue(m_levels->getLevelLowInputValue(m_channelCB->currentItem())); + m_minOutput->setValue(m_levels->getLevelLowOutputValue(m_channelCB->currentItem())); + m_maxInput->setValue(m_levels->getLevelHighInputValue(m_channelCB->currentItem())); + m_maxOutput->setValue(m_levels->getLevelHighOutputValue(m_channelCB->currentItem())); +} + +void AdjustLevelDialog::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("adjustlevels Tool Dialog"); + config->writeEntry("Histogram Channel", m_channelCB->currentItem()); + config->writeEntry("Histogram Scale", m_scaleBG->selectedId()); + + for (int i = 0 ; i < 5 ; i++) + { + bool sb = m_originalImage.sixteenBit(); + double gamma = m_levels->getLevelGammaValue(i); + int lowInput = m_levels->getLevelLowInputValue(i); + int lowOutput = m_levels->getLevelLowOutputValue(i); + int highInput = m_levels->getLevelHighInputValue(i); + int highOutput = m_levels->getLevelHighOutputValue(i); + + config->writeEntry(TQString("GammaChannel%1").arg(i), gamma); + config->writeEntry(TQString("LowInputChannel%1").arg(i), sb ? lowInput/255 : lowInput); + config->writeEntry(TQString("LowOutputChannel%1").arg(i), sb ? lowOutput/255 : lowOutput); + config->writeEntry(TQString("HighInputChannel%1").arg(i), sb ? highInput/255 : highInput); + config->writeEntry(TQString("HighOutputChannel%1").arg(i), sb ? highOutput/255 : highOutput); + } + + config->sync(); +} + +void AdjustLevelDialog::resetValues() +{ + for (int channel = 0 ; channel < 5 ; ++channel) + m_levels->levelsChannelReset(channel); + + // Refresh the current levels config. + slotChannelChanged(m_channelCB->currentItem()); + m_levelsHistogramWidget->reset(); + m_histogramWidget->reset(); +} + +// Load all settings. +void AdjustLevelDialog::slotUser3() +{ + KURL loadLevelsFile; + + loadLevelsFile = KFileDialog::getOpenURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), this, + TQString( i18n("Select Gimp Levels File to Load")) ); + if( loadLevelsFile.isEmpty() ) + return; + + if ( m_levels->loadLevelsFromGimpLevelsFile( loadLevelsFile ) == false ) + { + KMessageBox::error(this, i18n("Cannot load from the Gimp levels text file.")); + return; + } + + // Refresh the current levels config. + slotChannelChanged(m_channelCB->currentItem()); +} + +// Save all settings. +void AdjustLevelDialog::slotUser2() +{ + KURL saveLevelsFile; + + saveLevelsFile = KFileDialog::getSaveURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), this, + TQString( i18n("Gimp Levels File to Save")) ); + if( saveLevelsFile.isEmpty() ) + return; + + if ( m_levels->saveLevelsToGimpLevelsFile( saveLevelsFile ) == false ) + { + KMessageBox::error(this, i18n("Cannot save to the Gimp levels text file.")); + return; + } + + // Refresh the current levels config. + slotChannelChanged(m_channelCB->currentItem()); +} + +// See B.K.O #146636: use event filter with all level slider to display a +// guide over level histogram. +bool AdjustLevelDialog::eventFilter(TQObject *obj, TQEvent *ev) +{ + if ( obj == m_hGradientMinInput ) + { + if ( ev->type() == TQEvent::MouseButtonPress) + { + connect(m_minInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotShowHistogramGuide(int))); + + return false; + } + if ( ev->type() == TQEvent::MouseButtonRelease) + { + disconnect(m_minInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotShowHistogramGuide(int))); + + m_levelsHistogramWidget->reset(); + return false; + } + else + { + return false; + } + } + if ( obj == m_hGradientMaxInput ) + { + if ( ev->type() == TQEvent::MouseButtonPress) + { + connect(m_maxInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotShowHistogramGuide(int))); + + return false; + } + if ( ev->type() == TQEvent::MouseButtonRelease) + { + disconnect(m_maxInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotShowHistogramGuide(int))); + + m_levelsHistogramWidget->reset(); + return false; + } + else + { + return false; + } + } + if ( obj == m_hGradientMinOutput ) + { + if ( ev->type() == TQEvent::MouseButtonPress) + { + connect(m_minOutput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotShowHistogramGuide(int))); + + return false; + } + if ( ev->type() == TQEvent::MouseButtonRelease) + { + disconnect(m_minOutput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotShowHistogramGuide(int))); + + m_levelsHistogramWidget->reset(); + return false; + } + else + { + return false; + } + } + if ( obj == m_hGradientMaxOutput ) + { + if ( ev->type() == TQEvent::MouseButtonPress) + { + connect(m_maxOutput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotShowHistogramGuide(int))); + + return false; + } + if ( ev->type() == TQEvent::MouseButtonRelease) + { + disconnect(m_maxOutput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotShowHistogramGuide(int))); + + m_levelsHistogramWidget->reset(); + return false; + } + else + { + return false; + } + } + else + { + // pass the event on to the parent class + return KDialogBase::eventFilter(obj, ev); + } +} + +void AdjustLevelDialog::slotShowHistogramGuide(int v) +{ + Digikam::DColor color(v, v, v, v, m_originalImage.sixteenBit()); + m_levelsHistogramWidget->setHistogramGuideByColor(color); +} + +} // NameSpace DigikamAdjustLevelsImagesPlugin diff --git a/src/imageplugins/adjustlevels/adjustlevels.h b/src/imageplugins/adjustlevels/adjustlevels.h new file mode 100644 index 00000000..1b1ad9be --- /dev/null +++ b/src/imageplugins/adjustlevels/adjustlevels.h @@ -0,0 +1,153 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-20 + * Description : image histogram adjust levels. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef ADJUSTLEVELS_H +#define ADJUSTLEVELS_H + +// Digikam includes. + +#include "imagedlgbase.h" +#include "dimg.h" + +class TQComboBox; +class TQSpinBox; +class TQPushButton; +class TQHButtonGroup; + +class KDoubleSpinBox; +class KGradientSelector; +class KDoubleNumInput; + +namespace Digikam +{ +class HistogramWidget; +class ImageWidget; +class ImageLevels; +} + +namespace DigikamAdjustLevelsImagesPlugin +{ + +class AdjustLevelDialog : public Digikam::ImageDlgBase +{ + TQ_OBJECT + + +public: + + AdjustLevelDialog(TQWidget *parent); + ~AdjustLevelDialog(); + +private: + + void readUserSettings(); + void writeUserSettings(); + void resetValues(); + void finalRendering(); + void adjustSliders(int minIn, double gamIn, int maxIn, int minOut, int maxOut); + bool eventFilter(TQObject *o, TQEvent *e); + +private slots: + + void slotUser2(); + void slotUser3(); + void slotEffect(); + void slotResetCurrentChannel(); + void slotAutoLevels(); + void slotChannelChanged(int channel); + void slotScaleChanged(int scale); + void slotAdjustSliders(); + void slotGammaInputchanged(double val); + void slotAdjustMinInputSpinBox(int val); + void slotAdjustMaxInputSpinBox(int val); + void slotAdjustMinOutputSpinBox(int val); + void slotAdjustMaxOutputSpinBox(int val); + void slotSpotColorChanged(const Digikam::DColor &color); + void slotColorSelectedFromTarget(const Digikam::DColor &color); + void slotPickerColorButtonActived(); + void slotShowHistogramGuide(int v); + +private: + + enum HistogramScale + { + Linear=0, + Logarithmic + }; + + enum ColorChannel + { + LuminosityChannel=0, + RedChannel, + GreenChannel, + BlueChannel, + AlphaChannel + }; + + enum ColorPicker + { + BlackTonal=0, + GrayTonal, + WhiteTonal + }; + + uchar *m_destinationPreviewData; + + int m_histoSegments; + int m_currentPreviewMode; + + TQComboBox *m_channelCB; + + TQSpinBox *m_minInput; + TQSpinBox *m_maxInput; + TQSpinBox *m_minOutput; + TQSpinBox *m_maxOutput; + + TQPushButton *m_autoButton; + TQPushButton *m_resetButton; + TQPushButton *m_pickBlack; + TQPushButton *m_pickGray; + TQPushButton *m_pickWhite; + + TQHButtonGroup *m_pickerColorButtonGroup; + TQHButtonGroup *m_scaleBG; + + KDoubleNumInput *m_gammaInput; + + KGradientSelector *m_hGradientMinInput; + KGradientSelector *m_hGradientMaxInput; + KGradientSelector *m_hGradientMinOutput; + KGradientSelector *m_hGradientMaxOutput; + + Digikam::HistogramWidget *m_levelsHistogramWidget; + Digikam::HistogramWidget *m_histogramWidget; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::ImageLevels *m_levels; + Digikam::DImg m_originalImage; +}; + +} // NameSpace DigikamAdjustLevelsImagesPlugin + +#endif /* ADJUSTLEVELS_H */ diff --git a/src/imageplugins/adjustlevels/adjustlevelstool.cpp b/src/imageplugins/adjustlevels/adjustlevelstool.cpp new file mode 100644 index 00000000..28066774 --- /dev/null +++ b/src/imageplugins/adjustlevels/adjustlevelstool.cpp @@ -0,0 +1,901 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-20 + * Description : image histogram adjust levels. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// C++ includes. + +#include <cmath> + +// TQt includes. + +#include <tqcolor.h> +#include <tqcombobox.h> +#include <tqframe.h> +#include <tqgroupbox.h> +#include <tqhbuttongroup.h> +#include <tqhgroupbox.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqlayout.h> +#include <tqpainter.h> +#include <tqpixmap.h> +#include <tqpushbutton.h> +#include <tqtimer.h> +#include <tqtooltip.h> +#include <tqvgroupbox.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <tdefiledialog.h> +#include <tdeglobalsettings.h> +#include <khelpmenu.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <tdepopupmenu.h> +#include <tdeselect.h> +#include <kstandarddirs.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "dimg.h" +#include "editortoolsettings.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "imagehistogram.h" +#include "imagelevels.h" +#include "histogramwidget.h" +#include "dimgimagefilters.h" +#include "adjustlevelstool.h" +#include "adjustlevelstool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamAdjustLevelsImagesPlugin +{ + +AdjustLevelsTool::AdjustLevelsTool(TQObject* parent) + : EditorTool(parent) +{ + m_destinationPreviewData = 0; + + ImageIface iface(0, 0); + m_originalImage = iface.getOriginalImg(); + + m_histoSegments = m_originalImage->sixteenBit() ? 65535 : 255; + m_levels = new ImageLevels(m_originalImage->sixteenBit()); + + setName("adjustlevels"); + setToolName(i18n("Adjust Levels")); + setToolIcon(SmallIcon("adjustlevels")); + + // ------------------------------------------------------------- + + m_previewWidget = new ImageWidget("adjustlevels Tool", 0, + i18n("<p>Here you can see the image's " + "level-adjustments preview. You can pick a spot on the image " + "to see the corresponding level in the histogram.")); + setToolView(m_previewWidget); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Load| + EditorToolSettings::SaveAs| + EditorToolSettings::Ok| + EditorToolSettings::Cancel); + + TQGridLayout* grid = new TQGridLayout(m_gboxSettings->plainPage(), 20, 6); + + 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") ); + m_channelCB->insertItem( i18n("Alpha") ); + m_channelCB->setCurrentText( i18n("Luminosity") ); + TQWhatsThis::add( m_channelCB, i18n("<p>Here select the histogram channel to display:<p>" + "<b>Luminosity</b>: display the image's luminosity values.<p>" + "<b>Red</b>: display the red image-channel values.<p>" + "<b>Green</b>: display the green image-channel values.<p>" + "<b>Blue</b>: display the blue image-channel values.<p>" + "<b>Alpha</b>: display the alpha image-channel values. " + "This channel corresponds to the transparency value and " + "is supported by some image formats, such as PNG or TIF.")); + + 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("<p>Here select the histogram scale.<p>" + "If the image's maximal counts are small, you can use the linear scale.<p>" + "The Logarithmic scale can be used when the maximal counts 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( "<p>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( "<p>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); + + // ------------------------------------------------------------- + + m_histogramWidget = new HistogramWidget(256, 140, m_gboxSettings->plainPage(), false, true, true); + TQWhatsThis::add( m_histogramWidget, i18n("<p>Here you can see the target preview image histogram drawing of the " + "selected image channel. This one is re-computed at any levels " + "settings changes.")); + + m_levelsHistogramWidget = new HistogramWidget(256, 140, m_originalImage->bits(), m_originalImage->width(), + m_originalImage->height(), m_originalImage->sixteenBit(), m_gboxSettings, false); + TQWhatsThis::add( m_levelsHistogramWidget, i18n("<p>This is the histogram drawing of the selected channel " + "from original image")); + + // ------------------------------------------------------------- + + m_hGradientMinInput = new KGradientSelector( TDESelector::Horizontal, m_gboxSettings->plainPage() ); + m_hGradientMinInput->setFixedHeight( 20 ); + m_hGradientMinInput->setMinValue(0); + m_hGradientMinInput->setMaxValue(m_histoSegments); + TQWhatsThis::add( m_hGradientMinInput, i18n("<p>Select the minimal intensity input value of the histogram.")); + TQToolTip::add( m_hGradientMinInput, i18n( "Minimal intensity input." ) ); + m_hGradientMinInput->setColors( TQColor( "black" ), TQColor( "white" ) ); + m_hGradientMinInput->installEventFilter(this); + + m_hGradientMaxInput = new KGradientSelector( TDESelector::Horizontal, m_gboxSettings->plainPage() ); + m_hGradientMaxInput->setFixedHeight( 20 ); + m_hGradientMaxInput->setMinValue(0); + m_hGradientMaxInput->setMaxValue(m_histoSegments); + TQWhatsThis::add( m_hGradientMaxInput, i18n("<p>Select the maximal intensity input value of the histogram.")); + TQToolTip::add( m_hGradientMaxInput, i18n( "Maximal intensity input." ) ); + m_hGradientMaxInput->setColors( TQColor( "black" ), TQColor( "white" ) ); + m_hGradientMaxInput->installEventFilter(this); + + m_minInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_minInput->input()->setRange(0, m_histoSegments, 1, false); + m_minInput->setDefaultValue(0); + TQWhatsThis::add( m_minInput, i18n("<p>Select the minimal intensity input value of the histogram.")); + TQToolTip::add( m_minInput, i18n( "Minimal intensity input." ) ); + + m_gammaInput = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_gammaInput->setPrecision(2); + m_gammaInput->setRange(0.1, 3.0, 0.01, true); + m_gammaInput->setDefaultValue(1.0); + TQToolTip::add( m_gammaInput, i18n( "Gamma input value." ) ); + TQWhatsThis::add( m_gammaInput, i18n("<p>Select the gamma input value.")); + + m_maxInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_maxInput->input()->setRange(0, m_histoSegments, 1, false); + m_maxInput->setDefaultValue(m_histoSegments); + TQToolTip::add( m_maxInput, i18n( "Maximal intensity input." ) ); + TQWhatsThis::add( m_maxInput, i18n("<p>Select the maximal intensity input value of the histogram.")); + + m_hGradientMinOutput = new KGradientSelector( TDESelector::Horizontal, m_gboxSettings->plainPage() ); + m_hGradientMinOutput->setColors( TQColor( "black" ), TQColor( "white" ) ); + TQWhatsThis::add( m_hGradientMinOutput, i18n("<p>Select the minimal intensity output value of the histogram.")); + TQToolTip::add( m_hGradientMinOutput, i18n( "Minimal intensity output." ) ); + m_hGradientMinOutput->setFixedHeight( 20 ); + m_hGradientMinOutput->setMinValue(0); + m_hGradientMinOutput->setMaxValue(m_histoSegments); + m_hGradientMinOutput->installEventFilter(this); + + m_hGradientMaxOutput = new KGradientSelector( TDESelector::Horizontal, m_gboxSettings->plainPage() ); + m_hGradientMaxOutput->setColors( TQColor( "black" ), TQColor( "white" ) ); + TQWhatsThis::add( m_hGradientMaxOutput, i18n("<p>Select the maximal intensity output value of the histogram.")); + TQToolTip::add( m_hGradientMaxOutput, i18n( "Maximal intensity output." ) ); + m_hGradientMaxOutput->setFixedHeight( 20 ); + m_hGradientMaxOutput->setMinValue(0); + m_hGradientMaxOutput->setMaxValue(m_histoSegments); + m_hGradientMaxOutput->installEventFilter(this); + + m_minOutput = new RIntNumInput(m_gboxSettings->plainPage()); + m_minOutput->input()->setRange(0, m_histoSegments, 1, false); + m_minOutput->setDefaultValue(0); + TQToolTip::add( m_minOutput, i18n( "Minimal intensity output." ) ); + TQWhatsThis::add( m_minOutput, i18n("<p>Select the minimal intensity output value of the histogram.")); + + m_maxOutput = new RIntNumInput(m_gboxSettings->plainPage()); + m_maxOutput->input()->setRange(0, m_histoSegments, 1, false); + m_maxOutput->setDefaultValue(m_histoSegments); + TQToolTip::add( m_maxOutput, i18n( "Maximal intensity output." ) ); + TQWhatsThis::add( m_maxOutput, i18n("<p>Select the maximal intensity output value of the histogram.")); + + // ------------------------------------------------------------- + + m_pickerColorButtonGroup = new TQHButtonGroup(m_gboxSettings->plainPage()); + m_pickBlack = new TQPushButton(m_pickerColorButtonGroup); + m_pickerColorButtonGroup->insert(m_pickBlack, BlackTonal); + TDEGlobal::dirs()->addResourceType("color-picker-black", TDEGlobal::dirs()->kde_default("data") + + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("color-picker-black", "color-picker-black.png"); + m_pickBlack->setPixmap( TQPixmap( directory + "color-picker-black.png" ) ); + m_pickBlack->setToggleButton(true); + TQToolTip::add( m_pickBlack, i18n( "All channels shadow tone color picker" ) ); + TQWhatsThis::add( m_pickBlack, i18n("<p>With this button, you can pick the color from original image used to set <b>Shadow Tone</b> " + "levels input on Red, Green, Blue, and Luminosity channels.")); + m_pickGray = new TQPushButton(m_pickerColorButtonGroup); + m_pickerColorButtonGroup->insert(m_pickGray, GrayTonal); + TDEGlobal::dirs()->addResourceType("color-picker-gray", TDEGlobal::dirs()->kde_default("data") + + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("color-picker-grey", "color-picker-grey.png"); + m_pickGray->setPixmap( TQPixmap( directory + "color-picker-grey.png" ) ); + m_pickGray->setToggleButton(true); + TQToolTip::add( m_pickGray, i18n( "All channels middle tone color picker" ) ); + TQWhatsThis::add( m_pickGray, i18n("<p>With this button, you can pick the color from original image used to set <b>Middle Tone</b> " + "levels input on Red, Green, Blue, and Luminosity channels.")); + m_pickWhite = new TQPushButton(m_pickerColorButtonGroup); + m_pickerColorButtonGroup->insert(m_pickWhite, WhiteTonal); + TDEGlobal::dirs()->addResourceType("color-picker-white", TDEGlobal::dirs()->kde_default("data") + + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("color-picker-white", "color-picker-white.png"); + m_pickWhite->setPixmap( TQPixmap( directory + "color-picker-white.png" ) ); + m_pickWhite->setToggleButton(true); + TQToolTip::add( m_pickWhite, i18n( "All channels highlight tone color picker" ) ); + TQWhatsThis::add( m_pickWhite, i18n("<p>With this button, you can pick the color from original image used to set <b>Highlight Tone</b> " + "levels input on Red, Green, Blue, and Luminosity channels.")); + m_pickerColorButtonGroup->setExclusive(true); + m_pickerColorButtonGroup->setFrameShape(TQFrame::NoFrame); + + m_autoButton = new TQPushButton(m_gboxSettings->plainPage()); + m_autoButton->setPixmap(kapp->iconLoader()->loadIcon("system-run", (TDEIcon::Group)TDEIcon::Toolbar)); TQToolTip::add( m_autoButton, i18n( "Adjust all levels automatically." ) ); + TQWhatsThis::add( m_autoButton, i18n("<p>If you press this button, all channel levels will be adjusted " + "automatically.")); + + m_resetButton = new TQPushButton(i18n("&Reset"), m_gboxSettings->plainPage()); + m_resetButton->setPixmap(kapp->iconLoader()->loadIcon("reload_page", (TDEIcon::Group)TDEIcon::Toolbar)); + TQToolTip::add( m_resetButton, i18n( "Reset current channel levels' values." ) ); + TQWhatsThis::add( m_resetButton, i18n("<p>If you press this button, all levels' values " + "from the current selected channel " + "will be reset to the default values.")); + + TQLabel *space = new TQLabel(m_gboxSettings->plainPage()); + space->setFixedWidth(m_gboxSettings->spacingHint()); + + TQHBoxLayout* l3 = new TQHBoxLayout(); + l3->addWidget(m_pickerColorButtonGroup); + l3->addWidget(m_autoButton); + l3->addWidget(space); + l3->addWidget(m_resetButton); + l3->addStretch(10); + + // ------------------------------------------------------------- + + grid->addMultiCellLayout(l1, 0, 0, 0, 6); + grid->addMultiCellWidget(m_histogramWidget, 2, 2, 1, 5); + grid->addMultiCellWidget(m_levelsHistogramWidget, 4, 4, 1, 5); + grid->addMultiCellWidget(m_hGradientMinInput, 5, 5, 0, 6); + grid->addMultiCellWidget(m_hGradientMaxInput, 7, 7, 0, 6); + grid->addMultiCellWidget(m_minInput, 9, 9, 1, 1); + grid->addMultiCellWidget(m_maxInput, 9, 9, 5, 5); + grid->addMultiCellWidget(m_gammaInput, 11, 11, 0, 6); + grid->addMultiCellWidget(m_hGradientMinOutput, 13, 13, 0, 6); + grid->addMultiCellWidget(m_hGradientMaxOutput, 15, 15, 0, 6); + grid->addMultiCellWidget(m_minOutput, 17, 17, 1, 1); + grid->addMultiCellWidget(m_maxOutput, 17, 17, 5, 5); + grid->addMultiCellLayout(l3, 19, 19, 0, 6); + grid->setRowStretch(20, 10); + grid->setColStretch(3, 10); + grid->setMargin(0); + grid->setSpacing(5); + + setToolSettings(m_gboxSettings); + init(); + + // ------------------------------------------------------------- + // Channels and scale selection slots. + + 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_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&))); + + connect(m_previewWidget, TQ_SIGNAL(signalResized()), + this, TQ_SLOT(slotEffect())); + + // ------------------------------------------------------------- + // Color sliders and spinbox slots. + + connect(m_hGradientMinInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotAdjustMinInputSpinBox(int))); + + connect(m_minInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotAdjustSliders())); + + connect(m_gammaInput, TQ_SIGNAL(valueChanged(double)), + this, TQ_SLOT(slotGammaInputchanged(double))); + + connect(m_hGradientMaxInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotAdjustMaxInputSpinBox(int))); + + connect(m_maxInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotAdjustSliders())); + + connect(m_hGradientMinOutput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotAdjustMinOutputSpinBox(int))); + + connect(m_minOutput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotAdjustSliders())); + + connect(m_hGradientMaxOutput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotAdjustMaxOutputSpinBox(int))); + + connect(m_maxOutput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotAdjustSliders())); + + // ------------------------------------------------------------- + // Bouttons slots. + + connect(m_autoButton, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotAutoLevels())); + + connect(m_resetButton, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotResetCurrentChannel())); + + connect(m_pickerColorButtonGroup, TQ_SIGNAL(released(int)), + this, TQ_SLOT(slotPickerColorButtonActived())); +} + +AdjustLevelsTool::~AdjustLevelsTool() +{ + delete [] m_destinationPreviewData; + delete m_levels; +} + +void AdjustLevelsTool::slotPickerColorButtonActived() +{ + // Save previous rendering mode and toggle to original image. + m_currentPreviewMode = m_previewWidget->getRenderingPreviewMode(); + m_previewWidget->setRenderingPreviewMode(ImageGuideWidget::PreviewOriginalImage); +} + +void AdjustLevelsTool::slotSpotColorChanged(const DColor& color) +{ + if ( m_pickBlack->isOn() ) + { + // Black tonal levels point. + m_levels->levelsBlackToneAdjustByColors(m_channelCB->currentItem(), color); + m_pickBlack->setOn(false); + } + else if ( m_pickGray->isOn() ) + { + // Gray tonal levels point. + m_levels->levelsGrayToneAdjustByColors(m_channelCB->currentItem(), color); + m_pickGray->setOn(false); + } + else if ( m_pickWhite->isOn() ) + { + // White tonal levels point. + m_levels->levelsWhiteToneAdjustByColors(m_channelCB->currentItem(), color); + m_pickWhite->setOn(false); + } + else + { + m_levelsHistogramWidget->setHistogramGuideByColor(color); + return; + } + + // Refresh the current levels config. + slotChannelChanged(m_channelCB->currentItem()); + + // restore previous rendering mode. + m_previewWidget->setRenderingPreviewMode(m_currentPreviewMode); + + slotEffect(); +} + +void AdjustLevelsTool::slotColorSelectedFromTarget(const DColor& color) +{ + m_histogramWidget->setHistogramGuideByColor(color); +} + +void AdjustLevelsTool::slotGammaInputchanged(double val) +{ + blockSignals(true); + m_levels->setLevelGammaValue(m_channelCB->currentItem(), val); + blockSignals(false); + slotTimer(); +} + +void AdjustLevelsTool::slotAdjustMinInputSpinBox(int val) +{ + blockSignals(true); + + if ( val < m_hGradientMaxInput->value() ) + val = m_hGradientMaxInput->value(); + + m_minInput->setValue(m_histoSegments - val); + m_hGradientMinInput->setValue( val ); + m_levels->setLevelLowInputValue(m_channelCB->currentItem(), m_histoSegments - val); + blockSignals(false); + slotTimer(); +} + +void AdjustLevelsTool::slotAdjustMaxInputSpinBox(int val) +{ + blockSignals(true); + + if ( val > m_hGradientMinInput->value() ) + val = m_hGradientMinInput->value(); + + m_maxInput->setValue(m_histoSegments - val); + m_hGradientMaxInput->setValue( val ); + m_levels->setLevelHighInputValue(m_channelCB->currentItem(), m_histoSegments - val); + blockSignals(false); + slotTimer(); +} + +void AdjustLevelsTool::slotAdjustMinOutputSpinBox(int val) +{ + blockSignals(true); + + if ( val < m_hGradientMaxOutput->value() ) + val = m_hGradientMaxOutput->value(); + + m_minOutput->setValue(m_histoSegments - val); + m_hGradientMinOutput->setValue( val ); + m_levels->setLevelLowOutputValue(m_channelCB->currentItem(), m_histoSegments - val); + blockSignals(false); + slotTimer(); +} + +void AdjustLevelsTool::slotAdjustMaxOutputSpinBox(int val) +{ + blockSignals(true); + + if ( val > m_hGradientMinOutput->value() ) + val = m_hGradientMinOutput->value(); + + m_maxOutput->setValue(m_histoSegments - val); + m_hGradientMaxOutput->setValue( val ); + m_levels->setLevelHighOutputValue(m_channelCB->currentItem(), m_histoSegments - val); + blockSignals(false); + slotTimer(); +} + +void AdjustLevelsTool::slotAdjustSliders() +{ + adjustSliders(m_minInput->value(), m_gammaInput->value(), + m_maxInput->value(), m_minOutput->value(), + m_maxOutput->value()); +} + +void AdjustLevelsTool::adjustSliders(int minIn, double gamIn, int maxIn, int minOut, int maxOut) +{ + m_hGradientMinInput->setValue(m_histoSegments - minIn); + m_hGradientMaxInput->setValue(m_histoSegments - maxIn); + m_gammaInput->setValue(gamIn); + m_hGradientMinOutput->setValue(m_histoSegments - minOut); + m_hGradientMaxOutput->setValue(m_histoSegments - maxOut); +} + +void AdjustLevelsTool::slotResetCurrentChannel() +{ + m_levels->levelsChannelReset(m_channelCB->currentItem()); + + // Refresh the current levels config. + slotChannelChanged(m_channelCB->currentItem()); + m_levelsHistogramWidget->reset(); + + slotEffect(); + m_histogramWidget->reset(); +} + +void AdjustLevelsTool::slotAutoLevels() +{ + // Calculate Auto levels. + m_levels->levelsAuto(m_levelsHistogramWidget->m_imageHistogram); + + // Refresh the current levels config. + slotChannelChanged(m_channelCB->currentItem()); + + slotEffect(); +} + +void AdjustLevelsTool::slotEffect() +{ + ImageIface* iface = m_previewWidget->imageIface(); + uchar *orgData = iface->getPreviewImage(); + int w = iface->previewWidth(); + int h = iface->previewHeight(); + bool sb = iface->previewSixteenBit(); + + // Create the new empty destination image data space. + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + m_destinationPreviewData = new uchar[w*h*(sb ? 8 : 4)]; + + // Calculate the LUT to apply on the image. + m_levels->levelsLutSetup(ImageHistogram::AlphaChannel); + + // Apply the lut to the image. + m_levels->levelsLutProcess(orgData, m_destinationPreviewData, w, h); + + iface->putPreviewImage(m_destinationPreviewData); + m_previewWidget->updatePreview(); + + // Update histogram. + m_histogramWidget->updateData(m_destinationPreviewData, w, h, sb, 0, 0, 0, false); + + delete [] orgData; +} + +void AdjustLevelsTool::finalRendering() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + ImageIface* iface = m_previewWidget->imageIface(); + uchar *orgData = iface->getOriginalImage(); + int w = iface->originalWidth(); + int h = iface->originalHeight(); + bool sb = iface->originalSixteenBit(); + + // Create the new empty destination image data space. + uchar* desData = new uchar[w*h*(sb ? 8 : 4)]; + + // Calculate the LUT to apply on the image. + m_levels->levelsLutSetup(ImageHistogram::AlphaChannel); + + // Apply the lut to the image. + m_levels->levelsLutProcess(orgData, desData, w, h); + + iface->putOriginalImage(i18n("Adjust Level"), desData); + kapp->restoreOverrideCursor(); + + delete [] orgData; + delete [] desData; +} + +void AdjustLevelsTool::slotChannelChanged(int channel) +{ + switch(channel) + { + case LuminosityChannel: + m_histogramWidget->m_channelType = HistogramWidget::ValueHistogram; + m_levelsHistogramWidget->m_channelType = HistogramWidget::ValueHistogram; + m_hGradientMinInput->setColors( TQColor( "black" ), TQColor( "white" ) ); + m_hGradientMaxInput->setColors( TQColor( "black" ), TQColor( "white" ) ); + m_hGradientMinOutput->setColors( TQColor( "black" ), TQColor( "white" ) ); + m_hGradientMaxOutput->setColors( TQColor( "black" ), TQColor( "white" ) ); + break; + + case RedChannel: + m_histogramWidget->m_channelType = HistogramWidget::RedChannelHistogram; + m_levelsHistogramWidget->m_channelType = HistogramWidget::RedChannelHistogram; + m_hGradientMinInput->setColors( TQColor( "black" ), TQColor( "red" ) ); + m_hGradientMaxInput->setColors( TQColor( "black" ), TQColor( "red" ) ); + m_hGradientMinOutput->setColors( TQColor( "black" ), TQColor( "red" ) ); + m_hGradientMaxOutput->setColors( TQColor( "black" ), TQColor( "red" ) ); + break; + + case GreenChannel: + m_histogramWidget->m_channelType = HistogramWidget::GreenChannelHistogram; + m_levelsHistogramWidget->m_channelType = HistogramWidget::GreenChannelHistogram; + m_hGradientMinInput->setColors( TQColor( "black" ), TQColor( "green" ) ); + m_hGradientMaxInput->setColors( TQColor( "black" ), TQColor( "green" ) ); + m_hGradientMinOutput->setColors( TQColor( "black" ), TQColor( "green" ) ); + m_hGradientMaxOutput->setColors( TQColor( "black" ), TQColor( "green" ) ); + break; + + case BlueChannel: + m_histogramWidget->m_channelType = HistogramWidget::BlueChannelHistogram; + m_levelsHistogramWidget->m_channelType = HistogramWidget::BlueChannelHistogram; + m_hGradientMinInput->setColors( TQColor( "black" ), TQColor( "blue" ) ); + m_hGradientMaxInput->setColors( TQColor( "black" ), TQColor( "blue" ) ); + m_hGradientMinOutput->setColors( TQColor( "black" ), TQColor( "blue" ) ); + m_hGradientMaxOutput->setColors( TQColor( "black" ), TQColor( "blue" ) ); + break; + + case AlphaChannel: + m_histogramWidget->m_channelType = HistogramWidget::AlphaChannelHistogram; + m_levelsHistogramWidget->m_channelType = HistogramWidget::AlphaChannelHistogram; + m_hGradientMinInput->setColors( TQColor( "black" ), TQColor( "white" ) ); + m_hGradientMaxInput->setColors( TQColor( "black" ), TQColor( "white" ) ); + m_hGradientMinOutput->setColors( TQColor( "black" ), TQColor( "white" ) ); + m_hGradientMaxOutput->setColors( TQColor( "black" ), TQColor( "white" ) ); + break; + } + + adjustSliders(m_levels->getLevelLowInputValue(channel), + m_levels->getLevelGammaValue(channel), + m_levels->getLevelHighInputValue(channel), + m_levels->getLevelLowOutputValue(channel), + m_levels->getLevelHighOutputValue(channel)); + + m_levelsHistogramWidget->repaint(false); + m_histogramWidget->repaint(false); +} + +void AdjustLevelsTool::slotScaleChanged(int scale) +{ + m_levelsHistogramWidget->m_scaleType = scale; + m_histogramWidget->m_scaleType = scale; + m_histogramWidget->repaint(false); + m_levelsHistogramWidget->repaint(false); +} + +void AdjustLevelsTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("adjustlevels Tool"); + + m_channelCB->setCurrentItem(config->readNumEntry("Histogram Channel", 0)); // Luminosity. + m_scaleBG->setButton(config->readNumEntry("Histogram Scale", HistogramWidget::LogScaleHistogram)); + + for (int i = 0 ; i < 5 ; i++) + { + bool sb = m_originalImage->sixteenBit(); + int max = sb ? 65535 : 255; + double gamma = config->readDoubleNumEntry(TQString("GammaChannel%1").arg(i), 1.0); + int lowInput = config->readNumEntry(TQString("LowInputChannel%1").arg(i), 0); + int lowOutput = config->readNumEntry(TQString("LowOutputChannel%1").arg(i), 0); + int highInput = config->readNumEntry(TQString("HighInputChannel%1").arg(i), max); + int highOutput = config->readNumEntry(TQString("HighOutputChannel%1").arg(i), max); + + m_levels->setLevelGammaValue(i, gamma); + m_levels->setLevelLowInputValue(i, sb ? lowInput*255 : lowInput); + m_levels->setLevelHighInputValue(i, sb ? highInput*255 : highInput); + m_levels->setLevelLowOutputValue(i, sb ? lowOutput*255 : lowOutput); + m_levels->setLevelHighOutputValue(i, sb ? highOutput*255 : highOutput); + } + + m_levelsHistogramWidget->reset(); + m_histogramWidget->reset(); + slotChannelChanged(m_channelCB->currentItem()); + slotScaleChanged(m_scaleBG->selectedId()); + + // This is mandatory here to set spinbox values because slot connections + // can be not set completely at plugin startup. + m_minInput->setValue(m_levels->getLevelLowInputValue(m_channelCB->currentItem())); + m_minOutput->setValue(m_levels->getLevelLowOutputValue(m_channelCB->currentItem())); + m_maxInput->setValue(m_levels->getLevelHighInputValue(m_channelCB->currentItem())); + m_maxOutput->setValue(m_levels->getLevelHighOutputValue(m_channelCB->currentItem())); +} + +void AdjustLevelsTool::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("adjustlevels Tool"); + config->writeEntry("Histogram Channel", m_channelCB->currentItem()); + config->writeEntry("Histogram Scale", m_scaleBG->selectedId()); + + for (int i = 0 ; i < 5 ; i++) + { + bool sb = m_originalImage->sixteenBit(); + double gamma = m_levels->getLevelGammaValue(i); + int lowInput = m_levels->getLevelLowInputValue(i); + int lowOutput = m_levels->getLevelLowOutputValue(i); + int highInput = m_levels->getLevelHighInputValue(i); + int highOutput = m_levels->getLevelHighOutputValue(i); + + config->writeEntry(TQString("GammaChannel%1").arg(i), gamma); + config->writeEntry(TQString("LowInputChannel%1").arg(i), sb ? lowInput/255 : lowInput); + config->writeEntry(TQString("LowOutputChannel%1").arg(i), sb ? lowOutput/255 : lowOutput); + config->writeEntry(TQString("HighInputChannel%1").arg(i), sb ? highInput/255 : highInput); + config->writeEntry(TQString("HighOutputChannel%1").arg(i), sb ? highOutput/255 : highOutput); + } + + m_previewWidget->writeSettings(); + config->sync(); +} + +void AdjustLevelsTool::slotResetSettings() +{ + for (int channel = 0 ; channel < 5 ; ++channel) + m_levels->levelsChannelReset(channel); + + // Refresh the current levels config. + slotChannelChanged(m_channelCB->currentItem()); + m_levelsHistogramWidget->reset(); + slotEffect(); + m_histogramWidget->reset(); +} + +void AdjustLevelsTool::slotLoadSettings() +{ + KURL loadLevelsFile; + + loadLevelsFile = KFileDialog::getOpenURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), kapp->activeWindow(), + TQString( i18n("Select Gimp Levels File to Load")) ); + if( loadLevelsFile.isEmpty() ) + return; + + if ( m_levels->loadLevelsFromGimpLevelsFile( loadLevelsFile ) == false ) + { + KMessageBox::error(kapp->activeWindow(), i18n("Cannot load from the Gimp levels text file.")); + return; + } + + // Refresh the current levels config. + slotChannelChanged(m_channelCB->currentItem()); +} + +void AdjustLevelsTool::slotSaveAsSettings() +{ + KURL saveLevelsFile; + + saveLevelsFile = KFileDialog::getSaveURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), kapp->activeWindow(), + TQString( i18n("Gimp Levels File to Save")) ); + if( saveLevelsFile.isEmpty() ) + return; + + if ( m_levels->saveLevelsToGimpLevelsFile( saveLevelsFile ) == false ) + { + KMessageBox::error(kapp->activeWindow(), i18n("Cannot save to the Gimp levels text file.")); + return; + } + + // Refresh the current levels config. + slotChannelChanged(m_channelCB->currentItem()); +} + +// See B.K.O #146636: use event filter with all level slider to display a +// guide over level histogram. +bool AdjustLevelsTool::eventFilter(TQObject *obj, TQEvent *ev) +{ + if ( obj == m_hGradientMinInput ) + { + if ( ev->type() == TQEvent::MouseButtonPress) + { + connect(m_minInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotShowInputHistogramGuide(int))); + + return false; + } + if ( ev->type() == TQEvent::MouseButtonRelease) + { + disconnect(m_minInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotShowInputHistogramGuide(int))); + + m_levelsHistogramWidget->reset(); + return false; + } + else + { + return false; + } + } + if ( obj == m_hGradientMaxInput ) + { + if ( ev->type() == TQEvent::MouseButtonPress) + { + connect(m_maxInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotShowInputHistogramGuide(int))); + + return false; + } + if ( ev->type() == TQEvent::MouseButtonRelease) + { + disconnect(m_maxInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotShowInputHistogramGuide(int))); + + m_levelsHistogramWidget->reset(); + return false; + } + else + { + return false; + } + } + if ( obj == m_hGradientMinOutput ) + { + if ( ev->type() == TQEvent::MouseButtonPress) + { + connect(m_minOutput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotShowOutputHistogramGuide(int))); + + return false; + } + if ( ev->type() == TQEvent::MouseButtonRelease) + { + disconnect(m_minOutput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotShowOutputHistogramGuide(int))); + + m_histogramWidget->reset(); + return false; + } + else + { + return false; + } + } + if ( obj == m_hGradientMaxOutput ) + { + if ( ev->type() == TQEvent::MouseButtonPress) + { + connect(m_maxOutput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotShowOutputHistogramGuide(int))); + + return false; + } + if ( ev->type() == TQEvent::MouseButtonRelease) + { + disconnect(m_maxOutput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotShowOutputHistogramGuide(int))); + + m_histogramWidget->reset(); + return false; + } + else + { + return false; + } + } + else + { + // pass the event on to the parent class + return EditorTool::eventFilter(obj, ev); + } +} + +void AdjustLevelsTool::slotShowInputHistogramGuide(int v) +{ + DColor color(v, v, v, v, m_originalImage->sixteenBit()); + m_levelsHistogramWidget->setHistogramGuideByColor(color); +} + +void AdjustLevelsTool::slotShowOutputHistogramGuide(int v) +{ + DColor color(v, v, v, v, m_originalImage->sixteenBit()); + m_histogramWidget->setHistogramGuideByColor(color); +} + +} // NameSpace DigikamAdjustLevelsImagesPlugin diff --git a/src/imageplugins/adjustlevels/adjustlevelstool.h b/src/imageplugins/adjustlevels/adjustlevelstool.h new file mode 100644 index 00000000..9fdadf91 --- /dev/null +++ b/src/imageplugins/adjustlevels/adjustlevelstool.h @@ -0,0 +1,160 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-20 + * Description : image histogram adjust levels. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef ADJUSTLEVELSTOOL_H +#define ADJUSTLEVELSTOOL_H + +// Digikam includes. + +#include "editortool.h" + +class TQComboBox; +class TQPushButton; +class TQHButtonGroup; + +class KGradientSelector; + +namespace KDcrawIface +{ +class RDoubleNumInput; +class RIntNumInput; +} + +namespace Digikam +{ +class HistogramWidget; +class ImageWidget; +class ImageLevels; +class DImg; +class DColor; +} + +namespace DigikamAdjustLevelsImagesPlugin +{ + +class AdjustLevelsTool : public Digikam::EditorTool +{ + TQ_OBJECT + + +public: + + AdjustLevelsTool(TQObject *parent); + ~AdjustLevelsTool(); + +private: + + void readSettings(); + void writeSettings(); + void finalRendering(); + void adjustSliders(int minIn, double gamIn, int maxIn, int minOut, int maxOut); + bool eventFilter(TQObject *o, TQEvent *e); + +private slots: + + void slotLoadSettings(); + void slotSaveAsSettings(); + void slotEffect(); + void slotResetSettings(); + void slotResetCurrentChannel(); + void slotAutoLevels(); + void slotChannelChanged(int channel); + void slotScaleChanged(int scale); + void slotAdjustSliders(); + void slotGammaInputchanged(double val); + void slotAdjustMinInputSpinBox(int val); + void slotAdjustMaxInputSpinBox(int val); + void slotAdjustMinOutputSpinBox(int val); + void slotAdjustMaxOutputSpinBox(int val); + void slotSpotColorChanged(const Digikam::DColor& color); + void slotColorSelectedFromTarget(const Digikam::DColor& color); + void slotPickerColorButtonActived(); + void slotShowInputHistogramGuide(int v); + void slotShowOutputHistogramGuide(int v); + +private: + + enum HistogramScale + { + Linear=0, + Logarithmic + }; + + enum ColorChannel + { + LuminosityChannel=0, + RedChannel, + GreenChannel, + BlueChannel, + AlphaChannel + }; + + enum ColorPicker + { + BlackTonal=0, + GrayTonal, + WhiteTonal + }; + + uchar *m_destinationPreviewData; + + int m_histoSegments; + int m_currentPreviewMode; + + TQComboBox *m_channelCB; + + TQPushButton *m_autoButton; + TQPushButton *m_resetButton; + TQPushButton *m_pickBlack; + TQPushButton *m_pickGray; + TQPushButton *m_pickWhite; + + TQHButtonGroup *m_pickerColorButtonGroup; + TQHButtonGroup *m_scaleBG; + + KGradientSelector *m_hGradientMinInput; + KGradientSelector *m_hGradientMaxInput; + KGradientSelector *m_hGradientMinOutput; + KGradientSelector *m_hGradientMaxOutput; + + KDcrawIface::RDoubleNumInput *m_gammaInput; + + KDcrawIface::RIntNumInput *m_minInput; + KDcrawIface::RIntNumInput *m_maxInput; + KDcrawIface::RIntNumInput *m_minOutput; + KDcrawIface::RIntNumInput *m_maxOutput; + + Digikam::HistogramWidget *m_levelsHistogramWidget; + Digikam::HistogramWidget *m_histogramWidget; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; + + Digikam::ImageLevels *m_levels; + Digikam::DImg *m_originalImage; +}; + +} // NameSpace DigikamAdjustLevelsImagesPlugin + +#endif /* ADJUSTLEVELSTOOL_H */ diff --git a/src/imageplugins/adjustlevels/digikamimageplugin_adjustlevels.desktop b/src/imageplugins/adjustlevels/digikamimageplugin_adjustlevels.desktop new file mode 100644 index 00000000..b601ebbf --- /dev/null +++ b/src/imageplugins/adjustlevels/digikamimageplugin_adjustlevels.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Name=ImagePlugin_AdjustLevels +Name[bg]=Приставка за снимки - Настройка на нивата +Name[da]=Billedplugin_Niveaujustering +Name[el]=ΠρόσθετοΕικόνας_ΠροσαρμογήΕπιπέδων +Name[fi]=TasonsäätöHistogrammi +Name[hr]=Podešavanje razina +Name[it]=PluginImmagini_RegolaLivelli +Name[nl]=Afbeeldingsplugin_NiveausAanpassen +Name[sr]=Подешавање нивоа +Name[sr@Latn]=Podešavanje nivoa +Name[sv]=Insticksprogram för nivåjustering +Name[tr]=ResimEklentisi_DüzeyAyarla +Name[xx]=xxImagePlugin_AdjustLevelsxx +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 + +Comment=Image histogram adjust levels plugin for digiKam +Comment[bg]=Приставка на digiKam за настройка нивата на хистограмите на снимки +Comment[ca]=Connector pel digiKam d'ajust dels nivells de l'histograma d'imatges +Comment[da]=Plugin til niveaujustering i Digikam +Comment[de]=digiKam-Modul zur Justierung der Bildhistogrammwerte +Comment[el]=Πρόσθετο προσαρμογής των επιπέδων του ιστογράμματος εικόνας για το digiKam +Comment[es]=Plugin de digiKam para ajustar los niveles de color de una imagen +Comment[et]=DigiKami pildi histogrammi tasemete kohendamise plugin +Comment[fa]=وصلۀ سطوح تنظیم سابقهنمای تصویر برای digiKam +Comment[fi]=Muokkaa värikanavien raja-arvoja +Comment[fr]=Module externe pour ajuster les niveaux de l'histogramme dans digiKam +Comment[gl]=Un plugin de digiKam para axustar os níveis do histograma +Comment[hr]=digiKam dodatak za histogramsko podešavanje razina +Comment[is]=Íforrit fyrir digiKam sem breytir tíðnidreifingu (levels) í stuðlariti myndar +Comment[it]=Plugin di regolazione dei livelli degli istogrammi delle immagini per digiKam +Comment[ja]=digiKam レベル補正プラグイン +Comment[nds]=digiKam-Moduul för't Topassen vun Klöörkanaal-Toonrebeden +Comment[nl]=Digikam-plugin voor niveauaanpassing van afbeeldingshistogram +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਚਿੱਤਰ ਹਿਸਟੋਗਰਾਮ ਅਨੁਕੂਲ ਪੱਧਰ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam dostosowująca poziomy histogramu +Comment[pt]=Um 'plugin' do digiKam para ajustar os níveis do histograma do digiKam +Comment[pt_BR]=Plugin de ajuste de níveis do histograma da imagem +Comment[ru]=Модуль digiKam подстройки уровней гистограммы изображения +Comment[sk]=digiKam plugin histogramu úrovní obrázku +Comment[sr]=digiKam-ов прикључак за подешавање нивоа хистограма слика +Comment[sr@Latn]=digiKam-ov priključak za podešavanje nivoa histograma slika +Comment[sv]=Digikam insticksprogram för justering av nivåer i bildhistogram +Comment[tr]=digiKam için resim histogram düzeyleri ayarlama eklentisi +Comment[uk]=Втулок коригування рівнів гістограми зображень для digiKam +Comment[vi]=Phần bổ sung biểu đồ tần xuất điều chỉnh lớp ảnh cho digiKam +Comment[xx]=xxImage histogram adjust levels plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_adjustlevels +author=Caulier Gilles, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/adjustlevels/digikamimageplugin_adjustlevels_ui.rc b/src/imageplugins/adjustlevels/digikamimageplugin_adjustlevels_ui.rc new file mode 100644 index 00000000..8036e124 --- /dev/null +++ b/src/imageplugins/adjustlevels/digikamimageplugin_adjustlevels_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="5" name="digikamimageplugin_adjustlevels" > + + <MenuBar> + + <Menu name="Color" ><text>&Color</text> + <Action name="imageplugin_adjustlevels" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action name="imageplugin_adjustlevels" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/adjustlevels/imageplugin_adjustlevels.cpp b/src/imageplugins/adjustlevels/imageplugin_adjustlevels.cpp new file mode 100644 index 00000000..0f9dcb9e --- /dev/null +++ b/src/imageplugins/adjustlevels/imageplugin_adjustlevels.cpp @@ -0,0 +1,71 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-06-04 + * Description : image histogram adjust levels. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> + +// Local includes. + +#include "ddebug.h" +#include "adjustlevelstool.h" +#include "imageplugin_adjustlevels.h" +#include "imageplugin_adjustlevels.moc" + +using namespace DigikamAdjustLevelsImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_adjustlevels, + KGenericFactory<ImagePlugin_AdjustLevels>("digikamimageplugin_adjustlevels")) + +ImagePlugin_AdjustLevels::ImagePlugin_AdjustLevels(TQObject *parent, const char*, + const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_AdjustLevels") +{ + m_levelsAction = new TDEAction(i18n("Levels Adjust..."), "adjustlevels", + CTRL+Key_L, // NOTE: Photoshop 7 use CTRL+L. + this, TQ_SLOT(slotLevelsAdjust()), + actionCollection(), "imageplugin_adjustlevels"); + + setXMLFile("digikamimageplugin_adjustlevels_ui.rc"); + + DDebug() << "ImagePlugin_AdjustLevels plugin loaded" << endl; +} + +ImagePlugin_AdjustLevels::~ImagePlugin_AdjustLevels() +{ +} + +void ImagePlugin_AdjustLevels::setEnabledActions(bool enable) +{ + m_levelsAction->setEnabled(enable); +} + +void ImagePlugin_AdjustLevels::slotLevelsAdjust() +{ + AdjustLevelsTool *levels = new AdjustLevelsTool(this); + loadTool(levels); +} diff --git a/src/imageplugins/adjustlevels/imageplugin_adjustlevels.h b/src/imageplugins/adjustlevels/imageplugin_adjustlevels.h new file mode 100644 index 00000000..16af4f32 --- /dev/null +++ b/src/imageplugins/adjustlevels/imageplugin_adjustlevels.h @@ -0,0 +1,56 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-06-04 + * Description : image histogram adjust levels. + * + * Copyright (C) 2004-2007 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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_ADJUSTLEVELS_H +#define IMAGEPLUGIN_ADJUSTLEVELS_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_AdjustLevels : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_AdjustLevels(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_AdjustLevels(); + + void setEnabledActions(bool enable); + +private slots: + + void slotLevelsAdjust(); + +private: + + TDEAction *m_levelsAction; +}; + +#endif /* IMAGEPLUGIN_ADJUSTLEVELS_H */ diff --git a/src/imageplugins/antivignetting/Makefile.am b/src/imageplugins/antivignetting/Makefile.am new file mode 100644 index 00000000..54539672 --- /dev/null +++ b/src/imageplugins/antivignetting/Makefile.am @@ -0,0 +1,34 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_antivignetting_la_SOURCES = imageplugin_antivignetting.cpp \ + antivignettingtool.cpp antivignetting.cpp + +digikamimageplugin_antivignetting_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_antivignetting_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_antivignetting.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_antivignetting.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_antivignetting_ui.rc + diff --git a/src/imageplugins/antivignetting/antivignetting.cpp b/src/imageplugins/antivignetting/antivignetting.cpp new file mode 100644 index 00000000..dec0a9ea --- /dev/null +++ b/src/imageplugins/antivignetting/antivignetting.cpp @@ -0,0 +1,149 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : Antivignetting threaded image filter. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * Original AntiVignetting algorithm copyrighted 2003 by + * John Walker from 'pnmctrfilt' implementation. See + * http://www.fourmilab.ch/netpbm/pnmctrfilt for more + * information. + * + * 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> +#include <cstdlib> + +// Local includes. + +#include "dimg.h" +#include "dimgimagefilters.h" +#include "antivignetting.h" + +namespace DigikamAntiVignettingImagesPlugin +{ + +AntiVignetting::AntiVignetting(Digikam::DImg *orgImage, TQObject *parent, double density, + double power, double radius, int xshift, int yshift, bool normalize) + : Digikam::DImgThreadedFilter(orgImage, parent, "AntiVignetting") +{ + m_density = density; + m_power = power; + m_radius = radius; + m_xshift = xshift; + m_yshift = yshift; + m_normalize = normalize; + + initFilter(); +} + +// This method is inspired from John Walker 'pnmctrfilt' algorithm code. + +void AntiVignetting::filterImage(void) +{ + int progress; + int col, row, xd, td, yd, p; + int i, xsize, ysize, diagonal, erad, xctr, yctr; + double *ldens; + + uchar* NewBits = m_destImage.bits(); + uchar* data = m_orgImage.bits(); + + unsigned short* NewBits16 = (unsigned short*)m_destImage.bits(); + unsigned short* data16 = (unsigned short*)m_orgImage.bits(); + + int Width = m_orgImage.width(); + int Height = m_orgImage.height(); + + // Determine the radius of the filter. This is the half diagonal + // measure of the image multiplied by the command line radius factor. + + xsize = (Height + 1) / 2; + ysize = (Width + 1) / 2; + erad = (int)((sqrt((xsize * xsize) + (ysize * ysize)) + 0.5) * m_radius); + + // Build the in-memory table which maps distance from the + // center of the image (as adjusted by the X and Y offset, + // if any) to the density of the filter at this remove. This + // table needs to be as large as the diagonal from the + // (possibly offset) center to the most distant corner + // of the image. + + xsize = ((Height + 1) / 2) + abs(m_xshift); + ysize = ((Width + 1) / 2) + abs(m_yshift); + diagonal = ((int) (sqrt((xsize * xsize) + (ysize * ysize)) + 0.5)) + 1; + + ldens = new double[diagonal]; + + for (i = 0 ; !m_cancel && (i < diagonal) ; i++) + { + if ( i >= erad ) + ldens[i] = 1; + else + ldens[i] = (1.0 + (m_density - 1) * pow(1.0 - (((double) i) / (erad - 1)), m_power)); + } + + xctr = ((Height + 1) / 2) + m_xshift; + yctr = ((Width + 1) / 2) + m_yshift; + + for (row = 0 ; !m_cancel && (row < Width) ; row++) + { + yd = abs(yctr - row); + + for (col = 0 ; !m_cancel && (col < Height) ; col++) + { + p = (col * Width + row)*4; + + xd = abs(xctr - col); + td = (int) (sqrt((xd * xd) + (yd * yd)) + 0.5); + + if (!m_orgImage.sixteenBit()) // 8 bits image + { + NewBits[ p ] = (uchar)(data[ p ] / ldens[td]); + NewBits[p+1] = (uchar)(data[p+1] / ldens[td]); + NewBits[p+2] = (uchar)(data[p+2] / ldens[td]); + NewBits[p+3] = data[p+3]; + } + else // 16 bits image. + { + NewBits16[ p ] = (unsigned short)(data16[ p ] / ldens[td]); + NewBits16[p+1] = (unsigned short)(data16[p+1] / ldens[td]); + NewBits16[p+2] = (unsigned short)(data16[p+2] / ldens[td]); + NewBits16[p+3] = data16[p+3]; + } + } + + // Update the progress bar in dialog. + progress = (int)(((double)row * 100.0) / Width); + if (progress%5 == 0) + postProgress( progress ); + } + + // Normalize colors for a best rendering. + if (m_normalize) + { + Digikam::DImgImageFilters filters; + filters.normalizeImage(m_destImage.bits(), Width, Height, m_destImage.sixteenBit()); + } + + delete [] ldens; +} + +} // NameSpace DigikamAntiVignettingImagesPlugin diff --git a/src/imageplugins/antivignetting/antivignetting.h b/src/imageplugins/antivignetting/antivignetting.h new file mode 100644 index 00000000..f5311da0 --- /dev/null +++ b/src/imageplugins/antivignetting/antivignetting.h @@ -0,0 +1,62 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : Antivignetting threaded image filter. + * + * Copyright (C) 2005-2007 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. + * + * ============================================================ */ + +#ifndef ANTIVIGNETTING_H +#define ANTIVIGNETTING_H + +// Digikam includes. + +#include "dimgthreadedfilter.h" + +namespace DigikamAntiVignettingImagesPlugin +{ + +class AntiVignetting : public Digikam::DImgThreadedFilter +{ + +public: + + AntiVignetting(Digikam::DImg *orgImage, TQObject *parent=0, double density=2.0, + double power=1.0, double radius=1.0, int xshift=0, int yshift=0, bool normalize=true); + + ~AntiVignetting(){}; + +private: + + virtual void filterImage(void); + +private: + + bool m_normalize; + + int m_xshift; + int m_yshift; + + double m_density; + double m_power; + double m_radius; +}; + +} // NameSpace DigikamAntiVignettingImagesPlugin + +#endif /* ANTIVIGNETTING_H */ diff --git a/src/imageplugins/antivignetting/antivignettingtool.cpp b/src/imageplugins/antivignetting/antivignettingtool.cpp new file mode 100644 index 00000000..d8f211c7 --- /dev/null +++ b/src/imageplugins/antivignetting/antivignettingtool.cpp @@ -0,0 +1,378 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-25 + * Description : a digiKam image plugin to reduce + * vignetting on an image. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqlabel.h> +#include <tqwhatsthis.h> +#include <tqlayout.h> +#include <tqimage.h> +#include <tqpixmap.h> +#include <tqpainter.h> +#include <tqpen.h> +#include <tqtabwidget.h> + +// KDE includes. + +#include <tdeconfig.h> +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <kstandarddirs.h> +#include <kseparator.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "bcgmodifier.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "editortoolsettings.h" +#include "dimgimagefilters.h" +#include "antivignetting.h" +#include "antivignettingtool.h" +#include "antivignettingtool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamAntiVignettingImagesPlugin +{ + +AntiVignettingTool::AntiVignettingTool(TQObject* parent) + : EditorToolThreaded(parent) +{ + setName("antivignettings"); + setToolName(i18n("Vignetting Correction")); + setToolIcon(SmallIcon("antivignetting")); + + m_previewWidget = new ImageWidget("antivignetting Tool", 0, TQString(), + false, ImageGuideWidget::HVGuideMode, false); + + setToolView(m_previewWidget); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel); + TQGridLayout* grid = new TQGridLayout(m_gboxSettings->plainPage(), 14, 2); + + m_maskPreviewLabel = new TQLabel( m_gboxSettings->plainPage() ); + m_maskPreviewLabel->setAlignment ( TQt::AlignHCenter | TQt::AlignVCenter ); + TQWhatsThis::add( m_maskPreviewLabel, i18n("<p>You can see here a thumbnail preview of the anti-vignetting " + "mask applied to the image.") ); + + // ------------------------------------------------------------- + + TQLabel *label1 = new TQLabel(i18n("Density:"), m_gboxSettings->plainPage()); + + m_densityInput = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_densityInput->setPrecision(1); + m_densityInput->setRange(1.0, 20.0, 0.1); + m_densityInput->setDefaultValue(2.0); + TQWhatsThis::add( m_densityInput, i18n("<p>This value controls the degree of intensity attenuation by the filter " + "at its point of maximum density.")); + + // ------------------------------------------------------------- + + TQLabel *label2 = new TQLabel(i18n("Power:"), m_gboxSettings->plainPage()); + + m_powerInput = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_powerInput->setPrecision(1); + m_powerInput->setRange(0.1, 2.0, 0.1); + m_powerInput->setDefaultValue(1.0); + TQWhatsThis::add( m_powerInput, i18n("<p>This value is used as the exponent controlling the fall-off in density " + "from the center of the filter to the periphery.")); + + // ------------------------------------------------------------- + + TQLabel *label3 = new TQLabel(i18n("Radius:"), m_gboxSettings->plainPage()); + + m_radiusInput = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_radiusInput->setPrecision(1); + m_radiusInput->setRange(-100.0, 100.0, 0.1); + m_radiusInput->setDefaultValue(1.0); + TQWhatsThis::add( m_radiusInput, i18n("<p>This value is the radius of the center filter. It is a multiple of the " + "half-diagonal measure of the image, at which the density of the filter falls " + "to zero.")); + + KSeparator *line = new KSeparator(Horizontal, m_gboxSettings->plainPage()); + + // ------------------------------------------------------------- + + TQLabel *label4 = new TQLabel(i18n("Brightness:"), m_gboxSettings->plainPage()); + + m_brightnessInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_brightnessInput->setRange(0, 100, 1); + m_brightnessInput->setDefaultValue(0); + TQWhatsThis::add( m_brightnessInput, i18n("<p>Set here the brightness re-adjustment of the target image.")); + + // ------------------------------------------------------------- + + TQLabel *label5 = new TQLabel(i18n("Contrast:"), m_gboxSettings->plainPage()); + + m_contrastInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_contrastInput->setRange(0, 100, 1); + m_contrastInput->setDefaultValue(0); + TQWhatsThis::add( m_contrastInput, i18n("<p>Set here the contrast re-adjustment of the target image.")); + + // ------------------------------------------------------------- + + TQLabel *label6 = new TQLabel(i18n("Gamma:"), m_gboxSettings->plainPage()); + + m_gammaInput = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_gammaInput->setPrecision(2); + m_gammaInput->setRange(0.1, 3.0, 0.01); + m_gammaInput->setDefaultValue(1.0); + TQWhatsThis::add( m_gammaInput, i18n("<p>Set here the gamma re-adjustment of the target image.")); + + grid->addMultiCellWidget(m_maskPreviewLabel, 0, 0, 0, 2); + grid->addMultiCellWidget(label1, 1, 1, 0, 2); + grid->addMultiCellWidget(m_densityInput, 2, 2, 0, 2); + grid->addMultiCellWidget(label2, 3, 3, 0, 2); + grid->addMultiCellWidget(m_powerInput, 4, 4, 0, 2); + grid->addMultiCellWidget(label3, 5, 5, 0, 2); + grid->addMultiCellWidget(m_radiusInput, 6, 6, 0, 2); + grid->addMultiCellWidget(line, 7, 7, 0, 2); + grid->addMultiCellWidget(label4, 8, 8, 0, 2); + grid->addMultiCellWidget(m_brightnessInput, 9, 9, 0, 2); + grid->addMultiCellWidget(label5, 10, 10, 0, 2); + grid->addMultiCellWidget(m_contrastInput, 11, 11, 0, 2); + grid->addMultiCellWidget(label6, 12, 12, 0, 2); + grid->addMultiCellWidget(m_gammaInput, 13, 13, 0, 2); + grid->setRowStretch(14, 10); + grid->setMargin(m_gboxSettings->spacingHint()); + grid->setSpacing(m_gboxSettings->spacingHint()); + + setToolSettings(m_gboxSettings); + init(); + + // ------------------------------------------------------------- + + connect(m_densityInput, TQ_SIGNAL(valueChanged(double)), + this, TQ_SLOT(slotTimer())); + + connect(m_powerInput, TQ_SIGNAL(valueChanged(double)), + this, TQ_SLOT(slotTimer())); + + connect(m_radiusInput, TQ_SIGNAL(valueChanged(double)), + this, TQ_SLOT(slotTimer())); + + connect(m_brightnessInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_contrastInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_gammaInput, TQ_SIGNAL(valueChanged(double)), + this, TQ_SLOT(slotTimer())); +} + +AntiVignettingTool::~AntiVignettingTool() +{ +} + +void AntiVignettingTool::renderingFinished() +{ + m_densityInput->setEnabled(true); + m_powerInput->setEnabled(true); + m_radiusInput->setEnabled(true); + m_brightnessInput->setEnabled(true); + m_contrastInput->setEnabled(true); + m_gammaInput->setEnabled(true); +} + +void AntiVignettingTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("antivignettings Tool"); + + m_densityInput->blockSignals(true); + m_powerInput->blockSignals(true); + m_radiusInput->blockSignals(true); + m_brightnessInput->blockSignals(true); + m_contrastInput->blockSignals(true); + m_gammaInput->blockSignals(true); + + m_densityInput->setValue(config->readDoubleNumEntry("DensityAjustment", m_densityInput->defaultValue())); + m_powerInput->setValue(config->readDoubleNumEntry("PowerAjustment", m_powerInput->defaultValue())); + m_radiusInput->setValue(config->readDoubleNumEntry("RadiusAjustment", m_radiusInput->defaultValue())); + m_brightnessInput->setValue(config->readNumEntry("BrightnessAjustment", m_brightnessInput->defaultValue())); + m_contrastInput->setValue(config->readNumEntry("ContrastAjustment", m_contrastInput->defaultValue())); + m_gammaInput->setValue(config->readDoubleNumEntry("GammaAjustment", m_gammaInput->defaultValue())); + + m_densityInput->blockSignals(false); + m_powerInput->blockSignals(false); + m_radiusInput->blockSignals(false); + m_brightnessInput->blockSignals(false); + m_contrastInput->blockSignals(false); + m_gammaInput->blockSignals(false); + + slotEffect(); +} + +void AntiVignettingTool::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("antivignettings Tool"); + config->writeEntry("DensityAjustment", m_densityInput->value()); + config->writeEntry("PowerAjustment", m_powerInput->value()); + config->writeEntry("RadiusAjustment", m_radiusInput->value()); + config->writeEntry("BrightnessAjustment", m_brightnessInput->value()); + config->writeEntry("ContrastAjustment", m_contrastInput->value()); + config->writeEntry("GammaAjustment", m_gammaInput->value()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void AntiVignettingTool::slotResetSettings() +{ + m_densityInput->blockSignals(true); + m_powerInput->blockSignals(true); + m_radiusInput->blockSignals(true); + m_brightnessInput->blockSignals(true); + m_contrastInput->blockSignals(true); + m_gammaInput->blockSignals(true); + + m_densityInput->slotReset(); + m_powerInput->slotReset(); + m_radiusInput->slotReset(); + m_brightnessInput->slotReset(); + m_contrastInput->slotReset(); + m_gammaInput->slotReset(); + + m_densityInput->blockSignals(false); + m_powerInput->blockSignals(false); + m_radiusInput->blockSignals(false); + m_brightnessInput->blockSignals(false); + m_contrastInput->blockSignals(false); + m_gammaInput->blockSignals(false); +} + +void AntiVignettingTool::prepareEffect() +{ + m_densityInput->setEnabled(false); + m_powerInput->setEnabled(false); + m_radiusInput->setEnabled(false); + m_brightnessInput->setEnabled(false); + m_contrastInput->setEnabled(false); + m_gammaInput->setEnabled(false); + + double d = m_densityInput->value(); + double p = m_powerInput->value(); + double r = m_radiusInput->value(); + + ImageIface* iface = m_previewWidget->imageIface(); + uchar *data = iface->getOriginalImage(); + int orgWidth = iface->originalWidth(); + int orgHeight = iface->originalHeight(); + TQSize ps(orgWidth, orgHeight); + ps.scale( TQSize(120, 120), TQSize::ScaleMin ); + + // Calc mask preview. + DImg preview(ps.width(), ps.height(), false); + memset(preview.bits(), 255, preview.numBytes()); + AntiVignetting maskPreview(&preview, 0L, d, p, r, 0, 0, false); + TQPixmap pix = maskPreview.getTargetImage().convertToPixmap(); + TQPainter pt(&pix); + pt.setPen( TQPen(TQt::black, 1) ); + pt.drawRect( 0, 0, pix.width(), pix.height() ); + pt.end(); + m_maskPreviewLabel->setPixmap( pix ); + + DImg orgImage(orgWidth, orgHeight, iface->originalSixteenBit(), + iface->originalHasAlpha(), data); + delete [] data; + + setFilter(dynamic_cast<DImgThreadedFilter*>(new AntiVignetting(&orgImage, this, d, p, r, 0, 0, true))); +} + +void AntiVignettingTool::prepareFinal() +{ + m_densityInput->setEnabled(false); + m_powerInput->setEnabled(false); + m_radiusInput->setEnabled(false); + m_brightnessInput->setEnabled(false); + m_contrastInput->setEnabled(false); + m_gammaInput->setEnabled(false); + + double d = m_densityInput->value(); + double p = m_powerInput->value(); + double r = m_radiusInput->value(); + + ImageIface iface(0, 0); + + uchar *data = iface.getOriginalImage(); + DImg orgImage(iface.originalWidth(), iface.originalHeight(), iface.originalSixteenBit(), + iface.originalHasAlpha(), data); + delete [] data; + + setFilter(dynamic_cast<DImgThreadedFilter*>(new AntiVignetting(&orgImage, this, d, p, r, 0, 0, true))); +} + +void AntiVignettingTool::putPreviewData(void) +{ + ImageIface* iface = m_previewWidget->imageIface(); + DImg imDest = filter()->getTargetImage(); + + // Adjust Image BCG. + + double b = (double)(m_brightnessInput->value() / 100.0); + double c = (double)(m_contrastInput->value() / 100.0) + (double)(1.00); + double g = m_gammaInput->value(); + + BCGModifier cmod; + cmod.setGamma(g); + cmod.setBrightness(b); + cmod.setContrast(c); + cmod.applyBCG(imDest); + + iface->putPreviewImage((imDest.smoothScale(iface->previewWidth(), + iface->previewHeight())).bits()); + m_previewWidget->updatePreview(); +} + +void AntiVignettingTool::putFinalData(void) +{ + ImageIface iface(0, 0); + + iface.putOriginalImage(i18n("Vignetting Correction"), + filter()->getTargetImage().bits()); + + double b = (double)(m_brightnessInput->value() / 100.0); + double c = (double)(m_contrastInput->value() / 100.0) + (double)(1.00); + double g = m_gammaInput->value(); + + // Adjust Image BCG. + iface.setOriginalBCG(b, c, g); +} + +} // NameSpace DigikamAntiVignettingImagesPlugin diff --git a/src/imageplugins/antivignetting/antivignettingtool.h b/src/imageplugins/antivignetting/antivignettingtool.h new file mode 100644 index 00000000..467a19da --- /dev/null +++ b/src/imageplugins/antivignetting/antivignettingtool.h @@ -0,0 +1,92 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : a digiKam image plugin to reduce + * vignetting on an image. + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +#ifndef ANTIVIGNETTINGTOOL_H +#define ANTIVIGNETTINGTOOL_H + +// Digikam includes. + +#include "editortool.h" + +class TQLabel; + +namespace KDcrawIface +{ +class RIntNumInput; +class RDoubleNumInput; +} + +namespace Digikam +{ +class EditorToolSettings; +class ImageWidget; +} + +namespace DigikamAntiVignettingImagesPlugin +{ + +class AntiVignettingTool : public Digikam::EditorToolThreaded +{ + TQ_OBJECT + + +public: + + AntiVignettingTool(TQObject *parent); + ~AntiVignettingTool(); + +private slots: + + void slotResetSettings(); + +private: + + void writeSettings(); + void readSettings(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + TQLabel *m_maskPreviewLabel; + + KDcrawIface::RIntNumInput *m_brightnessInput; + KDcrawIface::RIntNumInput *m_contrastInput; + + KDcrawIface::RDoubleNumInput *m_gammaInput; + KDcrawIface::RDoubleNumInput *m_densityInput; + KDcrawIface::RDoubleNumInput *m_powerInput; + KDcrawIface::RDoubleNumInput *m_radiusInput; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamAntiVignettingImagesPlugin + +#endif /* ANTIVIGNETTINGTOOL_H */ diff --git a/src/imageplugins/antivignetting/digikamimageplugin_antivignetting.desktop b/src/imageplugins/antivignetting/digikamimageplugin_antivignetting.desktop new file mode 100644 index 00000000..f70a4752 --- /dev/null +++ b/src/imageplugins/antivignetting/digikamimageplugin_antivignetting.desktop @@ -0,0 +1,50 @@ +[Desktop Entry] +Name=ImagePlugin_AntiVignetting +Name[bg]=Приставка за снимки - Премахване на винетиране +Name[da]=Billedplugin_Anti-vignettering +Name[el]=ΠρόσθετοΕικόνας_Αντισκίασης +Name[fi]=ReunatummentumienPoisto +Name[hr]=Uklanjanje vinjeta +Name[it]=PluginImmagini_Antivignettatura +Name[nl]=Afbeeldingsplugin_Antivignetting +Name[sr]=Девињетизација +Name[sr@Latn]=Devinjetizacija +Name[sv]=Insticksprogram för antivinjettering +Name[tr]=ResimEklentisi_KenarKararmalarınıDüzelt +Name[xx]=xxImagePlugin_AntiVignettingxx +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=Anti Vignetting image effect plugin for digiKam +Comment[bg]=Приставка на digiKam за намаляване на винетирането на снимки +Comment[ca]=Connector pel digiKam d'efecte anti-vinyetatge +Comment[da]=Anti-vignetteringsplugin for Digikam +Comment[de]=digiKam-Modul zur Reduzierung von Vignettierung im Bild +Comment[el]=Πρόσθετο εφέ αντισκίασης εικόνας για το digiKam +Comment[es]=Un plugin para digiKam para eliminar efectos tipo "Vignetting" +Comment[et]=DigiKami pildi vinjeti kohendamise plugin +Comment[fa]=وصلۀ جلوۀ تصویر ضد عکس برای digiKam +Comment[fi]=Keskialueen portaaton tummennus +Comment[gl]=Un plugin de digiKam para efeitos antiviñeta de imaxe +Comment[hr]=digiKam dodatak za efekt protiv vinjeta +Comment[is]=Íforrit fyrir digiKam sem minnkar linsuskyggingu í hornum +Comment[it]=Plugin per l'effetto delle immagini di antivignettatura per digiKam +Comment[ja]=digiKam 口径食補正プラグイン +Comment[nds]=digiKam-Bildeffektmoduul gegen Randschaddens +Comment[nl]=Digikam-plugin voor anti-vignetting +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਐਂਟੀ ਵੀਜਨਿੰਟ ਚਿੱਤਰ ਪਰਭਾਵ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam usuwająca efekt winietowania +Comment[pt]=Um 'plugin' do digiKam para efeitos anti-vinheta de imagem +Comment[pt_BR]=Plugin de efeito anti-Vignetting para o digiKam +Comment[ru]=Модуль эффекта анти-виньетирования изображения для digiKam +Comment[sk]=Plugin korekcie vignetácie obrázku pre digiKam +Comment[sr]=digiKam-ов прикључак за ефекат девињетизације +Comment[sr@Latn]=digiKam-ov priključak za efekat devinjetizacije +Comment[sv]=Digikam insticksprogram för antivinjetteringsbildeffekt +Comment[tr]=digiKam için kenar kararmalarını düzeltme eklentisi +Comment[uk]=Втулок противіньєткового ефекту зображень для digiKam +Comment[vi]=Phần bổ sung hiệu ứng chống làm mờ nét ảnh cho digiKam +Comment[xx]=xxAnti Vignetting image effect plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_antivignetting +author=Gilles Caulier, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/antivignetting/digikamimageplugin_antivignetting_ui.rc b/src/imageplugins/antivignetting/digikamimageplugin_antivignetting_ui.rc new file mode 100644 index 00000000..7a54a1f3 --- /dev/null +++ b/src/imageplugins/antivignetting/digikamimageplugin_antivignetting_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="5" name="digikamimageplugin_antivignetting" > + + <MenuBar> + + <Menu name="Enhance" ><text>Enh&ance</text> + <Action name="imageplugin_antivignetting" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action name="imageplugin_antivignetting" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/antivignetting/imageeffect_antivignetting.cpp b/src/imageplugins/antivignetting/imageeffect_antivignetting.cpp new file mode 100644 index 00000000..7d7a00c6 --- /dev/null +++ b/src/imageplugins/antivignetting/imageeffect_antivignetting.cpp @@ -0,0 +1,380 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-25 + * Description : a digiKam image plugin to reduce + * vignetting on an image. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqlabel.h> +#include <tqwhatsthis.h> +#include <tqlayout.h> +#include <tqimage.h> +#include <tqpixmap.h> +#include <tqpainter.h> +#include <tqpen.h> +#include <tqtabwidget.h> + +// KDE includes. + +#include <tdeconfig.h> +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <kstandarddirs.h> +#include <knuminput.h> +#include <kseparator.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "bcgmodifier.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "dimgimagefilters.h" +#include "antivignetting.h" +#include "imageeffect_antivignetting.h" +#include "imageeffect_antivignetting.moc" + +namespace DigikamAntiVignettingImagesPlugin +{ + +ImageEffect_AntiVignetting::ImageEffect_AntiVignetting(TQWidget* parent) + : Digikam::ImageGuideDlg(parent, i18n("Vignetting Correction"), + "antivignettings", false, true, false, + Digikam::ImageGuideWidget::HVGuideMode, 0, true) +{ + TQString whatsThis; + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Vignetting Correction"), + digikam_version, + I18N_NOOP("A digiKam image plugin to reduce image vignetting."), + TDEAboutData::License_GPL, + "(c) 2004-2008, Gilles Caulier", + 0, + "http://www.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + about->addAuthor("John Walker", I18N_NOOP("Anti Vignetting algorithm"), 0, + "http://www.fourmilab.ch/netpbm/pnmctrfilt"); + + setAboutData(about); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(plainPage()); + TQGridLayout* gridSettings = new TQGridLayout( gboxSettings, 13, 2, spacingHint()); + + m_maskPreviewLabel = new TQLabel( gboxSettings ); + m_maskPreviewLabel->setAlignment ( TQt::AlignHCenter | TQt::AlignVCenter ); + TQWhatsThis::add( m_maskPreviewLabel, i18n("<p>You can see here a thumbnail preview of the anti-vignetting " + "mask applied to the image.") ); + gridSettings->addMultiCellWidget(m_maskPreviewLabel, 0, 0, 0, 2); + + // ------------------------------------------------------------- + + TQLabel *label1 = new TQLabel(i18n("Density:"), gboxSettings); + + m_densityInput = new KDoubleNumInput(gboxSettings); + m_densityInput->setPrecision(1); + m_densityInput->setRange(1.0, 20.0, 0.1, true); + TQWhatsThis::add( m_densityInput, i18n("<p>This value controls the degree of intensity attenuation by the filter " + "at its point of maximum density.")); + + gridSettings->addMultiCellWidget(label1, 1, 1, 0, 2); + gridSettings->addMultiCellWidget(m_densityInput, 2, 2, 0, 2); + + // ------------------------------------------------------------- + + TQLabel *label2 = new TQLabel(i18n("Power:"), gboxSettings); + + m_powerInput = new KDoubleNumInput(gboxSettings); + m_powerInput->setPrecision(1); + m_powerInput->setRange(0.1, 2.0, 0.1, true); + TQWhatsThis::add( m_powerInput, i18n("<p>This value is used as the exponent controlling the fall-off in density " + "from the center of the filter to the periphery.")); + + gridSettings->addMultiCellWidget(label2, 3, 3, 0, 2); + gridSettings->addMultiCellWidget(m_powerInput, 4, 4, 0, 2); + + // ------------------------------------------------------------- + + TQLabel *label3 = new TQLabel(i18n("Radius:"), gboxSettings); + + m_radiusInput = new KDoubleNumInput(gboxSettings); + m_radiusInput->setPrecision(1); + m_radiusInput->setRange(-100.0, 100.0, 0.1, true); + TQWhatsThis::add( m_radiusInput, i18n("<p>This value is the radius of the center filter. It is a multiple of the " + "half-diagonal measure of the image, at which the density of the filter falls " + "to zero.")); + + gridSettings->addMultiCellWidget(label3, 5, 5, 0, 2); + gridSettings->addMultiCellWidget(m_radiusInput, 6, 6, 0, 2); + + KSeparator *line = new KSeparator(Horizontal, gboxSettings); + gridSettings->addMultiCellWidget(line, 7, 7, 0, 2); + + // ------------------------------------------------------------- + + TQLabel *label4 = new TQLabel(i18n("Brightness:"), gboxSettings); + + m_brightnessInput = new KIntNumInput(gboxSettings); + m_brightnessInput->setRange(0, 100, 1, true); + TQWhatsThis::add( m_brightnessInput, i18n("<p>Set here the brightness re-adjustment of the target image.")); + + gridSettings->addMultiCellWidget(label4, 8, 8, 0, 2); + gridSettings->addMultiCellWidget(m_brightnessInput, 9, 9, 0, 2); + + // ------------------------------------------------------------- + + TQLabel *label5 = new TQLabel(i18n("Contrast:"), gboxSettings); + + m_contrastInput = new KIntNumInput(gboxSettings); + m_contrastInput->setRange(0, 100, 1, true); + TQWhatsThis::add( m_contrastInput, i18n("<p>Set here the contrast re-adjustment of the target image.")); + + gridSettings->addMultiCellWidget(label5, 10, 10, 0, 2); + gridSettings->addMultiCellWidget(m_contrastInput, 11, 11, 0, 2); + + // ------------------------------------------------------------- + + TQLabel *label6 = new TQLabel(i18n("Gamma:"), gboxSettings); + + m_gammaInput = new KDoubleNumInput(gboxSettings); + m_gammaInput->setPrecision(2); + m_gammaInput->setRange(0.1, 3.0, 0.01, true); + m_gammaInput->setValue(1.0); + TQWhatsThis::add( m_gammaInput, i18n("<p>Set here the gamma re-adjustment of the target image.")); + + gridSettings->addMultiCellWidget(label6, 12, 12, 0, 2); + gridSettings->addMultiCellWidget(m_gammaInput, 13, 13, 0, 2); + + setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + connect(m_densityInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_powerInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_radiusInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_brightnessInput, TQ_SIGNAL(valueChanged (int)), + this, TQ_SLOT(slotTimer())); + + connect(m_contrastInput, TQ_SIGNAL(valueChanged (int)), + this, TQ_SLOT(slotTimer())); + + connect(m_gammaInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); +} + +ImageEffect_AntiVignetting::~ImageEffect_AntiVignetting() +{ +} + +void ImageEffect_AntiVignetting::renderingFinished() +{ + m_densityInput->setEnabled(true); + m_powerInput->setEnabled(true); + m_radiusInput->setEnabled(true); + m_brightnessInput->setEnabled(true); + m_contrastInput->setEnabled(true); + m_gammaInput->setEnabled(true); +} + +void ImageEffect_AntiVignetting::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("antivignettings Tool Dialog"); + + m_densityInput->blockSignals(true); + m_powerInput->blockSignals(true); + m_radiusInput->blockSignals(true); + m_brightnessInput->blockSignals(true); + m_contrastInput->blockSignals(true); + m_gammaInput->blockSignals(true); + + m_densityInput->setValue(config->readDoubleNumEntry("DensityAjustment", 2.0)); + m_powerInput->setValue(config->readDoubleNumEntry("PowerAjustment", 1.0)); + m_radiusInput->setValue(config->readDoubleNumEntry("RadiusAjustment", 1.0)); + m_brightnessInput->setValue(config->readNumEntry("BrightnessAjustment", 0)); + m_contrastInput->setValue(config->readNumEntry("ContrastAjustment", 0)); + m_gammaInput->setValue(config->readDoubleNumEntry("GammaAjustment", 1.0)); + + m_densityInput->blockSignals(false); + m_powerInput->blockSignals(false); + m_radiusInput->blockSignals(false); + m_brightnessInput->blockSignals(false); + m_contrastInput->blockSignals(false); + m_gammaInput->blockSignals(false); + + slotEffect(); +} + +void ImageEffect_AntiVignetting::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("antivignettings Tool Dialog"); + config->writeEntry("DensityAjustment", m_densityInput->value()); + config->writeEntry("PowerAjustment", m_powerInput->value()); + config->writeEntry("RadiusAjustment", m_radiusInput->value()); + config->writeEntry("BrightnessAjustment", m_brightnessInput->value()); + config->writeEntry("ContrastAjustment", m_contrastInput->value()); + config->writeEntry("GammaAjustment", m_gammaInput->value()); + config->sync(); +} + +void ImageEffect_AntiVignetting::resetValues() +{ + m_densityInput->blockSignals(true); + m_powerInput->blockSignals(true); + m_radiusInput->blockSignals(true); + m_brightnessInput->blockSignals(true); + m_contrastInput->blockSignals(true); + m_gammaInput->blockSignals(true); + + m_densityInput->setValue(2.0); + m_powerInput->setValue(1.0); + m_radiusInput->setValue(1.0); + m_brightnessInput->setValue(0); + m_contrastInput->setValue(0); + m_gammaInput->setValue(1.0); + + m_densityInput->blockSignals(false); + m_powerInput->blockSignals(false); + m_radiusInput->blockSignals(false); + m_brightnessInput->blockSignals(false); + m_contrastInput->blockSignals(false); + m_gammaInput->blockSignals(false); +} + +void ImageEffect_AntiVignetting::prepareEffect() +{ + m_densityInput->setEnabled(false); + m_powerInput->setEnabled(false); + m_radiusInput->setEnabled(false); + m_brightnessInput->setEnabled(false); + m_contrastInput->setEnabled(false); + m_gammaInput->setEnabled(false); + + double d = m_densityInput->value(); + double p = m_powerInput->value(); + double r = m_radiusInput->value(); + + Digikam::ImageIface* iface = m_imagePreviewWidget->imageIface(); + uchar *data = iface->getOriginalImage(); + int orgWidth = iface->originalWidth(); + int orgHeight = iface->originalHeight(); + TQSize ps(orgWidth, orgHeight); + ps.scale( TQSize(120, 120), TQSize::ScaleMin ); + + // Calc mask preview. + Digikam::DImg preview(ps.width(), ps.height(), false); + memset(preview.bits(), 255, preview.numBytes()); + AntiVignetting maskPreview(&preview, 0L, d, p, r, 0, 0, false); + TQPixmap pix = maskPreview.getTargetImage().convertToPixmap(); + TQPainter pt(&pix); + pt.setPen( TQPen(TQt::black, 1) ); + pt.drawRect( 0, 0, pix.width(), pix.height() ); + pt.end(); + m_maskPreviewLabel->setPixmap( pix ); + + Digikam::DImg orgImage(orgWidth, orgHeight, iface->originalSixteenBit(), + iface->originalHasAlpha(), data); + delete [] data; + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new AntiVignetting(&orgImage, this, d, p, r, 0, 0, true)); +} + +void ImageEffect_AntiVignetting::prepareFinal() +{ + m_densityInput->setEnabled(false); + m_powerInput->setEnabled(false); + m_radiusInput->setEnabled(false); + m_brightnessInput->setEnabled(false); + m_contrastInput->setEnabled(false); + m_gammaInput->setEnabled(false); + + double d = m_densityInput->value(); + double p = m_powerInput->value(); + double r = m_radiusInput->value(); + + Digikam::ImageIface iface(0, 0); + + uchar *data = iface.getOriginalImage(); + Digikam::DImg orgImage(iface.originalWidth(), iface.originalHeight(), iface.originalSixteenBit(), + iface.originalHasAlpha(), data); + delete [] data; + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new AntiVignetting(&orgImage, this, d, p, r, 0, 0, true)); +} + +void ImageEffect_AntiVignetting::putPreviewData(void) +{ + Digikam::ImageIface* iface = m_imagePreviewWidget->imageIface(); + + Digikam::DImg imDest = m_threadedFilter->getTargetImage(); + + // Adjust Image BCG. + + double b = (double)(m_brightnessInput->value() / 100.0); + double c = (double)(m_contrastInput->value() / 100.0) + (double)(1.00); + double g = m_gammaInput->value(); + + Digikam::BCGModifier cmod; + cmod.setGamma(g); + cmod.setBrightness(b); + cmod.setContrast(c); + cmod.applyBCG(imDest); + + iface->putPreviewImage((imDest.smoothScale(iface->previewWidth(), + iface->previewHeight())).bits()); + m_imagePreviewWidget->updatePreview(); +} + +void ImageEffect_AntiVignetting::putFinalData(void) +{ + Digikam::ImageIface iface(0, 0); + + iface.putOriginalImage(i18n("Vignetting Correction"), + m_threadedFilter->getTargetImage().bits()); + + double b = (double)(m_brightnessInput->value() / 100.0); + double c = (double)(m_contrastInput->value() / 100.0) + (double)(1.00); + double g = m_gammaInput->value(); + + // Adjust Image BCG. + iface.setOriginalBCG(b, c, g); +} + +} // NameSpace DigikamAntiVignettingImagesPlugin + diff --git a/src/imageplugins/antivignetting/imageeffect_antivignetting.h b/src/imageplugins/antivignetting/imageeffect_antivignetting.h new file mode 100644 index 00000000..3ee6f158 --- /dev/null +++ b/src/imageplugins/antivignetting/imageeffect_antivignetting.h @@ -0,0 +1,79 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : a digiKam image plugin to reduce + * vignetting on an image. + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_ANTIVIGNETTING_H +#define IMAGEEFFECT_ANTIVIGNETTING_H + +// Digikam includes. + +#include "imageguidedlg.h" + +class TQLabel; + +class KIntNumInput; +class KDoubleNumInput; + +namespace DigikamAntiVignettingImagesPlugin +{ + +class ImageEffect_AntiVignetting : public Digikam::ImageGuideDlg +{ + TQ_OBJECT + + +public: + + ImageEffect_AntiVignetting(TQWidget *parent); + ~ImageEffect_AntiVignetting(); + +private slots: + + void readUserSettings(); + +private: + + void writeUserSettings(); + void resetValues(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + TQLabel *m_maskPreviewLabel; + + KIntNumInput *m_brightnessInput; + KIntNumInput *m_contrastInput; + + KDoubleNumInput *m_gammaInput; + KDoubleNumInput *m_densityInput; + KDoubleNumInput *m_powerInput; + KDoubleNumInput *m_radiusInput; +}; + +} // NameSpace DigikamAntiVignettingImagesPlugin + +#endif /* IMAGEEFFECT_ANTIVIGNETTING_H */ diff --git a/src/imageplugins/antivignetting/imageplugin_antivignetting.cpp b/src/imageplugins/antivignetting/imageplugin_antivignetting.cpp new file mode 100644 index 00000000..239d9842 --- /dev/null +++ b/src/imageplugins/antivignetting/imageplugin_antivignetting.cpp @@ -0,0 +1,70 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-25 + * Description : a digiKam image plugin to reduce + * vignetting on an image. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> + +// Local includes. + +#include "ddebug.h" +#include "antivignettingtool.h" +#include "imageplugin_antivignetting.h" +#include "imageplugin_antivignetting.moc" + +using namespace DigikamAntiVignettingImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_antivignetting, + KGenericFactory<ImagePlugin_AntiVignetting>("digikamimageplugin_antivignetting")); + +ImagePlugin_AntiVignetting::ImagePlugin_AntiVignetting(TQObject *parent, const char*, const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_AntiVignetting") +{ + m_antivignettingAction = new TDEAction(i18n("Vignetting Correction..."), "antivignetting", 0, + this, TQ_SLOT(slotAntiVignetting()), + actionCollection(), "imageplugin_antivignetting"); + + setXMLFile("digikamimageplugin_antivignetting_ui.rc"); + + DDebug() << "ImagePlugin_AntiVignetting plugin loaded" << endl; +} + +ImagePlugin_AntiVignetting::~ImagePlugin_AntiVignetting() +{ +} + +void ImagePlugin_AntiVignetting::setEnabledActions(bool enable) +{ + m_antivignettingAction->setEnabled(enable); +} + +void ImagePlugin_AntiVignetting::slotAntiVignetting() +{ + AntiVignettingTool *tool = new AntiVignettingTool(this); + loadTool(tool); +} diff --git a/src/imageplugins/antivignetting/imageplugin_antivignetting.h b/src/imageplugins/antivignetting/imageplugin_antivignetting.h new file mode 100644 index 00000000..d8d4eedd --- /dev/null +++ b/src/imageplugins/antivignetting/imageplugin_antivignetting.h @@ -0,0 +1,57 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-25 + * Description : a digiKam image plugin to reduce + * vignetting on an image. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_ANTIVIGNETTING_H +#define IMAGEPLUGIN_ANTIVIGNETTING_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_AntiVignetting : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_AntiVignetting(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_AntiVignetting(); + + void setEnabledActions(bool enable); + +private slots: + + void slotAntiVignetting(); + +private: + + TDEAction *m_antivignettingAction; +}; + +#endif /* IMAGEPLUGIN_ANTIVIGNETTING_H */ diff --git a/src/imageplugins/blurfx/Makefile.am b/src/imageplugins/blurfx/Makefile.am new file mode 100644 index 00000000..51a78977 --- /dev/null +++ b/src/imageplugins/blurfx/Makefile.am @@ -0,0 +1,34 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_blurfx_la_SOURCES = imageplugin_blurfx.cpp \ + blurfxtool.cpp blurfx.cpp + +digikamimageplugin_blurfx_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_blurfx_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_blurfx.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_blurfx.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_blurfx_ui.rc + diff --git a/src/imageplugins/blurfx/blurfx.cpp b/src/imageplugins/blurfx/blurfx.cpp new file mode 100644 index 00000000..ec5ff30e --- /dev/null +++ b/src/imageplugins/blurfx/blurfx.cpp @@ -0,0 +1,1445 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : Blur FX threaded image filter. + * + * Copyright 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * Original Blur algorithms copyrighted 2004 by + * Pieter Z. Voloshyn <pieter dot voloshyn 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. + * + * ============================================================ */ + +// Represents 1 +#define ANGLE_RATIO 0.017453292519943295769236907685 + +// C++ includes. + +#include <cmath> +#include <cstdlib> +#include <cstring> + +// TQt includes. + +#include <tqdatetime.h> + +// Local includes. + +#include "dimg.h" +#include "dimggaussianblur.h" +#include "blurfx.h" + +namespace DigikamBlurFXImagesPlugin +{ + +BlurFX::BlurFX(Digikam::DImg *orgImage, TQObject *parent, int blurFXType, int distance, int level) + : Digikam::DImgThreadedFilter(orgImage, parent, "BlurFX") +{ + m_blurFXType = blurFXType; + m_distance = distance; + m_level = level; + + initFilter(); +} + +void BlurFX::filterImage(void) +{ + int w = m_orgImage.width(); + int h = m_orgImage.height(); + + switch (m_blurFXType) + { + case ZoomBlur: + zoomBlur(&m_orgImage, &m_destImage, w/2, h/2, m_distance); + break; + + case RadialBlur: + radialBlur(&m_orgImage, &m_destImage, w/2, h/2, m_distance); + break; + + case FarBlur: + farBlur(&m_orgImage, &m_destImage, m_distance); + break; + + case MotionBlur: + motionBlur(&m_orgImage, &m_destImage, m_distance, (double)m_level); + break; + + case SoftenerBlur: + softenerBlur(&m_orgImage, &m_destImage); + break; + + case ShakeBlur: + shakeBlur(&m_orgImage, &m_destImage, m_distance); + break; + + case FocusBlur: + focusBlur(&m_orgImage, &m_destImage, w/2, h/2, m_distance, m_level*10); + break; + + case SmartBlur: + smartBlur(&m_orgImage, &m_destImage, m_distance, m_level); + break; + + case FrostGlass: + frostGlass(&m_orgImage, &m_destImage, m_distance); + break; + + case Mosaic: + mosaic(&m_orgImage, &m_destImage, m_distance, m_distance); + break; + } +} + +/* Function to apply the ZoomBlur effect backported from ImageProcessing version 2 + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * X, Y => Center of zoom in the image + * Distance => Distance value + * pArea => Preview area. + * + * Theory => Here we have a effect similar to RadialBlur mode Zoom from + * Photoshop. The theory is very similar to RadialBlur, but has one + * difference. Instead we use pixels with the same radius and + * near angles, we take pixels with the same angle but near radius + * This radius is always from the center to out of the image, we + * calc a proportional radius from the center. + */ +void BlurFX::zoomBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, int X, int Y, int Distance, TQRect pArea) +{ + if (Distance <= 1) return; + int progress; + + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pResBits = destImage->bits(); + + // We working on full image. + int xMin = 0; + int xMax = Width; + int yMin = 0; + int yMax = Height; + + // If we working in preview mode, else we using the preview area. + if ( pArea.isValid() ) + { + xMin = pArea.x(); + xMax = pArea.x() + pArea.width(); + yMin = pArea.y(); + yMax = pArea.y() + pArea.height(); + } + + int h, w, nh, nw, r; + int sumR, sumG, sumB, nCount; + double lfRadius, lfNewRadius, lfRadMax, lfAngle; + + Digikam::DColor color; + int offset; + + lfRadMax = sqrt (Height * Height + Width * Width); + + // number of added pixels + nCount = 0; + + // we have reached the main loop + for (h = yMin; !m_cancel && (h < yMax); h++) + { + for (w = xMin; !m_cancel && (w < xMax); w++) + { + // ...we enter this loop to sum the bits + + // we initialize the variables + sumR = sumG = sumB = nCount = 0; + + nw = X - w; + nh = Y - h; + + lfRadius = sqrt (nw * nw + nh * nh); + lfAngle = atan2 ((double)nh, (double)nw); + lfNewRadius = (lfRadius * Distance) / lfRadMax; + + for (r = 0; !m_cancel && (r <= lfNewRadius); r++) + { + // we need to calc the positions + nw = (int)(X - (lfRadius - r) * cos (lfAngle)); + nh = (int)(Y - (lfRadius - r) * sin (lfAngle)); + + if (IsInside(Width, Height, nw, nh)) + { + // read color + offset = GetOffset(Width, nw, nh, bytesDepth); + color.setColor(data + offset, sixteenBit); + + // we sum the bits + sumR += color.red(); + sumG += color.green(); + sumB += color.blue(); + nCount++; + } + } + + if (nCount == 0) nCount = 1; + + // calculate pointer + offset = GetOffset(Width, w, h, bytesDepth); + // read color to preserve alpha + color.setColor(data + offset, sixteenBit); + + // now, we have to calc the arithmetic average + color.setRed (sumR / nCount); + color.setGreen(sumG / nCount); + color.setBlue (sumB / nCount); + + // write color to destination + color.setPixel(pResBits + offset); + } + + // Update the progress bar in dialog. + progress = (int) (((double)(h - yMin) * 100.0) / (yMax - yMin)); + + if (progress%5 == 0) + postProgress(progress); + } +} + +/* Function to apply the radialBlur effect backported from ImageProcessing version 2 + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * X, Y => Center of radial in the image + * Distance => Distance value + * pArea => Preview area. + * + * Theory => Similar to RadialBlur from Photoshop, its an amazing effect + * Very easy to understand but a little hard to implement. + * We have all the image and find the center pixel. Now, we analize + * all the pixels and calc the radius from the center and find the + * angle. After this, we sum this pixel with others with the same + * radius, but different angles. Here I'm using degrees angles. + */ +void BlurFX::radialBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, int X, int Y, int Distance, TQRect pArea) +{ + if (Distance <= 1) return; + int progress; + + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pResBits = destImage->bits(); + + // We working on full image. + int xMin = 0; + int xMax = Width; + int yMin = 0; + int yMax = Height; + + // If we working in preview mode, else we using the preview area. + if ( pArea.isValid() ) + { + xMin = pArea.x(); + xMax = pArea.x() + pArea.width(); + yMin = pArea.y(); + yMax = pArea.y() + pArea.height(); + } + + int sumR, sumG, sumB, nw, nh; + double Radius, Angle, AngleRad; + + Digikam::DColor color; + int offset; + + double *nMultArray = new double[Distance * 2 + 1]; + + for (int i = -Distance; i <= Distance; i++) + nMultArray[i + Distance] = i * ANGLE_RATIO; + + // number of added pixels + int nCount = 0; + + // we have reached the main loop + + for (int h = yMin; !m_cancel && (h < yMax); h++) + { + for (int w = xMin; !m_cancel && (w < xMax); w++) + { + // ...we enter this loop to sum the bits + + // we initialize the variables + sumR = sumG = sumB = nCount = 0; + + nw = X - w; + nh = Y - h; + + Radius = sqrt (nw * nw + nh * nh); + AngleRad = atan2 ((double)nh, (double)nw); + + for (int a = -Distance; !m_cancel && (a <= Distance); a++) + { + Angle = AngleRad + nMultArray[a + Distance]; + // we need to calc the positions + nw = (int)(X - Radius * cos (Angle)); + nh = (int)(Y - Radius * sin (Angle)); + + if (IsInside(Width, Height, nw, nh)) + { + // read color + offset = GetOffset(Width, nw, nh, bytesDepth); + color.setColor(data + offset, sixteenBit); + + // we sum the bits + sumR += color.red(); + sumG += color.green(); + sumB += color.blue(); + nCount++; + } + } + + if (nCount == 0) nCount = 1; + + // calculate pointer + offset = GetOffset(Width, w, h, bytesDepth); + // read color to preserve alpha + color.setColor(data + offset, sixteenBit); + + // now, we have to calc the arithmetic average + color.setRed (sumR / nCount); + color.setGreen(sumG / nCount); + color.setBlue (sumB / nCount); + + // write color to destination + color.setPixel(pResBits + offset); + } + + // Update the progress bar in dialog. + progress = (int) (((double)(h - yMin) * 100.0) / (yMax - yMin)); + + if (progress%5 == 0) + postProgress(progress); + } + + delete [] nMultArray; +} + +/* Function to apply the focusBlur effect backported from ImageProcessing version 2 + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * BlurRadius => Radius of blurred image. + * BlendRadius => Radius of blending effect. + * bInversed => If true, invert focus effect. + * pArea => Preview area. + * + */ +void BlurFX::focusBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, + int X, int Y, int BlurRadius, int BlendRadius, + bool bInversed, TQRect pArea) +{ + int progress; + + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pResBits = destImage->bits(); + + // We working on full image. + int xMin = 0; + int xMax = Width; + int yMin = 0; + int yMax = Height; + + // If we working in preview mode, else we using the preview area. + if ( pArea.isValid() ) + { + xMin = pArea.x(); + xMax = pArea.x() + pArea.width(); + yMin = pArea.y(); + yMax = pArea.y() + pArea.height(); + } + + if (pArea.isValid()) + { + //UNTESTED (unused) + + // We do not have access to the loop of the Gaussian blur, + // so we have to cut the image that we run the effect on. + int xMinBlur = xMin - BlurRadius; + int xMaxBlur = xMax + BlurRadius; + int yMinBlur = yMin - BlurRadius; + int yMaxBlur = yMax + BlurRadius; + Digikam::DImg areaImage = orgImage->copy(xMinBlur, yMaxBlur, xMaxBlur - xMinBlur, yMaxBlur - yMinBlur); + + Digikam::DImgGaussianBlur(this, *orgImage, *destImage, 10, 75, BlurRadius); + + // I am unsure about differences of 1 pixel + destImage->bitBltImage(&areaImage, xMinBlur, yMinBlur); + destImage->bitBltImage(orgImage, 0, 0, Width, yMinBlur, 0, 0); + destImage->bitBltImage(orgImage, 0, yMinBlur, xMinBlur, yMaxBlur - yMinBlur, 0, yMinBlur); + destImage->bitBltImage(orgImage, xMaxBlur + 1, yMinBlur, Width - xMaxBlur - 1, yMaxBlur - yMinBlur, yMaxBlur, yMinBlur); + destImage->bitBltImage(orgImage, 0, yMaxBlur + 1, Width, Height - yMaxBlur - 1, 0, yMaxBlur); + + postProgress(80); + } + else + { + // copy bits for blurring + memcpy(pResBits, data, orgImage->numBytes()); + + // Gaussian blur using the BlurRadius parameter. + Digikam::DImgGaussianBlur(this, *orgImage, *destImage, 10, 80, BlurRadius); + } + + // Blending results. + + int nBlendFactor; + double lfRadius; + int offset; + + Digikam::DColor colorOrgImage, colorBlurredImage; + int alpha; + uchar *ptr; + + // get composer for default blending + Digikam::DColorComposer *composer = Digikam::DColorComposer::getComposer(Digikam::DColorComposer::PorterDuffNone); + + int nh = 0, nw = 0; + + for (int h = yMin; !m_cancel && (h < yMax); h++) + { + nh = Y - h; + + for (int w = xMin; !m_cancel && (w < xMax); w++) + { + nw = X - w; + + lfRadius = sqrt (nh * nh + nw * nw); + + if (sixteenBit) + nBlendFactor = LimitValues16 ((int)(65535.0 * lfRadius / (double)BlendRadius)); + else + nBlendFactor = LimitValues8 ((int)(255.0 * lfRadius / (double)BlendRadius)); + + // Read color values + offset = GetOffset(Width, w, h, bytesDepth); + ptr = pResBits + offset; + colorOrgImage.setColor(data + offset, sixteenBit); + colorBlurredImage.setColor(ptr, sixteenBit); + + // Preserve alpha + alpha = colorOrgImage.alpha(); + + // In normal mode, the image is focused in the middle + // and less focused towards the border. + // In inversed mode, the image is more focused towards the edge + // and less focused in the middle. + // This is achieved by swapping src and dest while blending. + if (bInversed) + { + // set blending alpha value as src alpha. Original value is stored above. + colorOrgImage.setAlpha(nBlendFactor); + // compose colors, writing to dest - colorBlurredImage + composer->compose(colorBlurredImage, colorOrgImage); + // restore alpha + colorBlurredImage.setAlpha(alpha); + // write color to destination + colorBlurredImage.setPixel(ptr); + } + else + { + // set blending alpha value as src alpha. Original value is stored above. + colorBlurredImage.setAlpha(nBlendFactor); + // compose colors, writing to dest - colorOrgImage + composer->compose(colorOrgImage, colorBlurredImage); + // restore alpha + colorOrgImage.setAlpha(alpha); + // write color to destination + colorOrgImage.setPixel(ptr); + } + } + + // Update the progress bar in dialog. + progress = (int) (80.0 + ((double)(h - yMin) * 20.0) / (yMax - yMin)); + + if (progress%5 == 0) + postProgress(progress); + } + + delete composer; +} + +/* Function to apply the farBlur effect backported from ImageProcessing version 2 + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Distance => Distance value + * + * Theory => This is an interesting effect, the blur is applied in that + * way: (the value "1" means pixel to be used in a blur calc, ok?) + * e.g. With distance = 2 + * |1|1|1|1|1| + * |1|0|0|0|1| + * |1|0|C|0|1| + * |1|0|0|0|1| + * |1|1|1|1|1| + * We sum all the pixels with value = 1 and apply at the pixel with* + * the position "C". + */ +void BlurFX::farBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Distance) +{ + if (Distance < 1) return; + + // we need to create our kernel + // e.g. distance = 3, so kernel={3 1 1 2 1 1 3} + + int *nKern = new int[Distance * 2 + 1]; + + for (int i = 0; i < Distance * 2 + 1; i++) + { + // the first element is 3 + if (i == 0) + nKern[i] = 2; + // the center element is 2 + else if (i == Distance) + nKern[i] = 3; + // the last element is 3 + else if (i == Distance * 2) + nKern[i] = 3; + // all other elements will be 1 + else + nKern[i] = 1; + } + + // now, we apply a convolution with kernel + MakeConvolution(orgImage, destImage, Distance, nKern); + + // we must delete to free memory + delete [] nKern; +} + +/* Function to apply the SmartBlur effect + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Radius => blur matrix radius. + * Strenght => Color strenght. + * + * Theory => Similar to SmartBlur from Photoshop, this function has the + * same engine as Blur function, but, in a matrix with n + * dimentions, we take only colors that pass by sensibility filter + * The result is a clean image, not totally blurred, but a image + * with correction between pixels. + */ + +void BlurFX::smartBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Radius, int Strength) +{ + if (Radius <= 0) return; + + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pResBits = destImage->bits(); + + int progress; + int sumR, sumG, sumB, nCount, w, h, a; + + int StrengthRange = Strength; + if (sixteenBit) + StrengthRange = (StrengthRange + 1) * 256 - 1; + + Digikam::DColor color, radiusColor, radiusColorBlur; + int offset, loopOffset; + + uchar* pBlur = new uchar[orgImage->numBytes()]; + + // We need to copy our bits to blur bits + + memcpy (pBlur, data, orgImage->numBytes()); + + // we have reached the main loop + + for (h = 0; !m_cancel && (h < Height); h++) + { + for (w = 0; !m_cancel && (w < Width); w++) + { + // we initialize the variables + sumR = sumG = sumB = nCount = 0; + + // read color + offset = GetOffset(Width, w, h, bytesDepth); + color.setColor(data + offset, sixteenBit); + + // ...we enter this loop to sum the bits + for (a = -Radius; !m_cancel && (a <= Radius); a++) + { + // verify if is inside the rect + if (IsInside( Width, Height, w + a, h)) + { + // read color + loopOffset = GetOffset(Width, w+a, h, bytesDepth); + radiusColor.setColor(data + loopOffset, sixteenBit); + + // now, we have to check if is inside the sensibility filter + if (IsColorInsideTheRange (color.red(), color.green(), color.blue(), + radiusColor.red(), radiusColor.green(), radiusColor.blue(), + StrengthRange)) + { + // finally we sum the bits + sumR += radiusColor.red(); + sumG += radiusColor.green(); + sumB += radiusColor.blue(); + } + else + { + // finally we sum the bits + sumR += color.red(); + sumG += color.green(); + sumB += color.blue(); + } + + // increment counter + nCount++; + } + } + + // now, we have to calc the arithmetic average + color.setRed (sumR / nCount); + color.setGreen(sumG / nCount); + color.setBlue (sumB / nCount); + + // write color to destination + color.setPixel(pBlur + offset); + } + + // Update the progress bar in dialog. + progress = (int) (((double)h * 50.0) / Height); + + if (progress%5 == 0) + postProgress(progress); + } + + // we have reached the second part of main loop + + for (w = 0; !m_cancel && (w < Width); w++) + { + for (h = 0;!m_cancel && ( h < Height); h++) + { + // we initialize the variables + sumR = sumG = sumB = nCount = 0; + + // read color + offset = GetOffset(Width, w, h, bytesDepth); + color.setColor(data + offset, sixteenBit); + + // ...we enter this loop to sum the bits + for (a = -Radius; !m_cancel && (a <= Radius); a++) + { + // verify if is inside the rect + if (IsInside( Width, Height, w, h + a)) + { + // read color + loopOffset = GetOffset(Width, w, h+a, bytesDepth); + radiusColor.setColor(data + loopOffset, sixteenBit); + + // now, we have to check if is inside the sensibility filter + if (IsColorInsideTheRange (color.red(), color.green(), color.blue(), + radiusColor.red(), radiusColor.green(), radiusColor.blue(), + StrengthRange)) + { + radiusColorBlur.setColor(pBlur + loopOffset, sixteenBit); + // finally we sum the bits + sumR += radiusColorBlur.red(); + sumG += radiusColorBlur.green(); + sumB += radiusColorBlur.blue(); + } + else + { + // finally we sum the bits + sumR += color.red(); + sumG += color.green(); + sumB += color.blue(); + } + + // increment counter + nCount++; + } + } + + // now, we have to calc the arithmetic average + color.setRed (sumR / nCount); + color.setGreen(sumG / nCount); + color.setBlue (sumB / nCount); + + // write color to destination + color.setPixel(pResBits + offset); + } + + // Update the progress bar in dialog. + progress = (int) (50.0 + ((double)w * 50.0) / Width); + + if (progress%5 == 0) + postProgress(progress); + } + + // now, we must free memory + delete [] pBlur; +} + +/* Function to apply the motionBlur effect backported from ImageProcessing version 2 + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Distance => Distance value + * Angle => Angle direction (degrees) + * + * Theory => Similar to MotionBlur from Photoshop, the engine is very + * simple to undertand, we take a pixel (duh!), with the angle we + * will taking near pixels. After this we blur (add and do a + * division). + */ +void BlurFX::motionBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Distance, double Angle) +{ + if (Distance == 0) return; + int progress; + + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pResBits = destImage->bits(); + + Digikam::DColor color; + int offset; + + // we try to avoid division by 0 (zero) + if (Angle == 0.0) Angle = 360.0; + + int sumR, sumG, sumB, nCount, nw, nh; + double nAngX, nAngY; + + // we initialize cos and sin for a best performance + nAngX = cos ((2.0 * M_PI) / (360.0 / Angle)); + nAngY = sin ((2.0 * M_PI) / (360.0 / Angle)); + + // total of bits to be taken is given by this formula + nCount = Distance * 2 + 1; + + // we will alloc size and calc the possible results + int *lpXArray = new int[nCount]; + int *lpYArray = new int[nCount]; + + for (int i = 0; i < nCount; i++) + { + lpXArray[i] = lround( (double)(i - Distance) * nAngX); + lpYArray[i] = lround( (double)(i - Distance) * nAngY); + } + + // we have reached the main loop + + for (int h = 0; !m_cancel && (h < Height); h++) + { + for (int w = 0; !m_cancel && (w < Width); w++) + { + // we initialize the variables + sumR = sumG = sumB = 0; + + // ...we enter this loop to sum the bits + for (int a = -Distance; !m_cancel && (a <= Distance); a++) + { + // we need to calc the positions + nw = w + lpXArray[a + Distance]; + nh = h + lpYArray[a + Distance]; + + offset = GetOffsetAdjusted(Width, Height, nw, nh, bytesDepth); + color.setColor(data + offset, sixteenBit); + + // we sum the bits + sumR += color.red(); + sumG += color.green(); + sumB += color.blue(); + } + + if (nCount == 0) nCount = 1; + + // calculate pointer + offset = GetOffset(Width, w, h, bytesDepth); + // read color to preserve alpha + color.setColor(data + offset, sixteenBit); + + // now, we have to calc the arithmetic average + color.setRed (sumR / nCount); + color.setGreen(sumG / nCount); + color.setBlue (sumB / nCount); + + // write color to destination + color.setPixel(pResBits + offset); + } + + // Update the progress bar in dialog. + progress = (int) (((double)h * 100.0) / Height); + + if (progress%5 == 0) + postProgress(progress); + } + + delete [] lpXArray; + delete [] lpYArray; +} + +/* Function to apply the softenerBlur effect + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * + * Theory => An interesting blur-like function. In dark tones we apply a + * blur with 3x3 dimentions, in light tones, we apply a blur with + * 5x5 dimentions. Easy, hun? + */ +void BlurFX::softenerBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage) +{ + int progress; + + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pResBits = destImage->bits(); + + int SomaR = 0, SomaG = 0, SomaB = 0; + int Gray; + + Digikam::DColor color, colorSoma; + int offset, offsetSoma; + + int grayLimit = sixteenBit ? 32767 : 127; + + for (int h = 0; !m_cancel && (h < Height); h++) + { + for (int w = 0; !m_cancel && (w < Width); w++) + { + SomaR = SomaG = SomaB = 0; + + offset = GetOffset(Width, w, h, bytesDepth); + color.setColor(data + offset, sixteenBit); + + Gray = (color.red() + color.green() + color.blue()) / 3; + + if (Gray > grayLimit) + { + // 7x7 + for (int a = -3; !m_cancel && (a <= 3); a++) + { + for (int b = -3; !m_cancel && (b <= 3); b++) + { + if ((h + a < 0) || (w + b < 0)) + offsetSoma = offset; + else + offsetSoma = GetOffset(Width, (w + Lim_Max (w, b, Width)), + (h + Lim_Max (h, a, Height)), bytesDepth); + colorSoma.setColor(data + offsetSoma, sixteenBit); + + SomaR += colorSoma.red(); + SomaG += colorSoma.green(); + SomaB += colorSoma.blue(); + } + } + + // 7*7 = 49 + color.setRed (SomaR / 49); + color.setGreen(SomaG / 49); + color.setBlue (SomaB / 49); + color.setPixel(pResBits + offset); + } + else + { + // 3x3 + for (int a = -1; !m_cancel && (a <= 1); a++) + { + for (int b = -1; !m_cancel && (b <= 1); b++) + { + if ((h + a < 0) || (w + b < 0)) + offsetSoma = offset; + else + offsetSoma = GetOffset(Width, (w + Lim_Max (w, b, Width)), + (h + Lim_Max (h, a, Height)), bytesDepth); + colorSoma.setColor(data + offsetSoma, sixteenBit); + + SomaR += colorSoma.red(); + SomaG += colorSoma.green(); + SomaB += colorSoma.blue(); + } + } + + // 3*3 = 9 + color.setRed (SomaR / 9); + color.setGreen(SomaG / 9); + color.setBlue (SomaB / 9); + color.setPixel(pResBits + offset); + } + } + + // Update the progress bar in dialog. + progress = (int) (((double)h * 100.0) / Height); + + if (progress%5 == 0) + postProgress(progress); + } +} + +/* Function to apply the shake blur effect + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Distance => Distance between layers (from origin) + * + * Theory => Similar to Fragment effect from Photoshop. We create 4 layers + * each one has the same distance from the origin, but have + * different positions (top, button, left and right), with these 4 + * layers, we join all the pixels. + */ +void BlurFX::shakeBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Distance) +{ + int progress; + + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pResBits = destImage->bits(); + + Digikam::DColor color, colorLayer, color1, color2, color3, color4; + int offset, offsetLayer; + + int numBytes = orgImage->numBytes(); + uchar* Layer1 = new uchar[numBytes]; + uchar* Layer2 = new uchar[numBytes]; + uchar* Layer3 = new uchar[numBytes]; + uchar* Layer4 = new uchar[numBytes]; + + int h, w, nw, nh; + + for (h = 0; !m_cancel && (h < Height); h++) + { + for (w = 0; !m_cancel && (w < Width); w++) + { + offsetLayer = GetOffset(Width, w, h, bytesDepth); + + nh = (h + Distance >= Height) ? Height - 1 : h + Distance; + offset = GetOffset(Width, w, nh, bytesDepth); + color.setColor(data + offset, sixteenBit); + color.setPixel(Layer1 + offsetLayer); + + nh = (h - Distance < 0) ? 0 : h - Distance; + offset = GetOffset(Width, w, nh, bytesDepth); + color.setColor(data + offset, sixteenBit); + color.setPixel(Layer2 + offsetLayer); + + nw = (w + Distance >= Width) ? Width - 1 : w + Distance; + offset = GetOffset(Width, nw, h, bytesDepth); + color.setColor(data + offset, sixteenBit); + color.setPixel(Layer3 + offsetLayer); + + nw = (w - Distance < 0) ? 0 : w - Distance; + offset = GetOffset(Width, nw, h, bytesDepth); + color.setColor(data + offset, sixteenBit); + color.setPixel(Layer4 + offsetLayer); + } + + // Update the progress bar in dialog. + progress = (int) (((double)h * 50.0) / Height); + + if (progress%5 == 0) + postProgress(progress); + } + + for (int h = 0; !m_cancel && (h < Height); h++) + { + for (int w = 0; !m_cancel && (w < Width); w++) + { + offset = GetOffset(Width, w, h, bytesDepth); + // read original data to preserve alpha + color.setColor(data + offset, sixteenBit); + // read colors from all four layers + color1.setColor(Layer1 + offset, sixteenBit); + color2.setColor(Layer2 + offset, sixteenBit); + color3.setColor(Layer3 + offset, sixteenBit); + color4.setColor(Layer4 + offset, sixteenBit); + + // set color components of resulting color + color.setRed ( (color1.red() + color2.red() + color3.red() + color4.red()) / 4 ); + color.setGreen( (color1.green() + color2.green() + color3.green() + color4.green()) / 4 ); + color.setBlue ( (color1.blue() + color2.blue() + color3.blue() + color4.blue()) / 4 ); + + color.setPixel(pResBits + offset); + } + + // Update the progress bar in dialog. + progress = (int) (50.0 + ((double)h * 50.0) / Height); + + if (progress%5 == 0) + postProgress(progress); + } + + delete [] Layer1; + delete [] Layer2; + delete [] Layer3; + delete [] Layer4; +} + +/* Function to apply the frostGlass effect + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Frost => Frost value + * + * Theory => Similar to Diffuse effect, but the random byte is defined + * in a matrix. Diffuse uses a random diagonal byte. + */ +void BlurFX::frostGlass(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Frost) +{ + int progress; + + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pResBits = destImage->bits(); + + Frost = (Frost < 1) ? 1 : (Frost > 10) ? 10 : Frost; + + int h, w; + + Digikam::DColor color; + int offset; + + // Randomize. + + TQDateTime dt = TQDateTime::currentDateTime(); + TQDateTime Y2000( TQDate(2000, 1, 1), TQTime(0, 0, 0) ); + uint seed = dt.secsTo(Y2000); + + int range = sixteenBit ? 65535 : 255; + + // it is a huge optimizsation to allocate these here once + uchar *IntensityCount = new uchar[range + 1]; + uint *AverageColorR = new uint[range + 1]; + uint *AverageColorG = new uint[range + 1]; + uint *AverageColorB = new uint[range + 1]; + + for (h = 0; !m_cancel && (h < Height); h++) + { + for (w = 0; !m_cancel && (w < Width); w++) + { + offset = GetOffset(Width, w, h, bytesDepth); + // read color to preserve alpha + color.setColor(data + offset, sixteenBit); + + // get random color from surrounding of w|h + color = RandomColor (data, Width, Height, sixteenBit, bytesDepth, + w, h, Frost, color.alpha(), &seed, range, IntensityCount, + AverageColorR, AverageColorG, AverageColorB); + + // write color to destination + color.setPixel(pResBits + offset); + } + + // Update the progress bar in dialog. + progress = (int) (((double)h * 100.0) / Height); + + if (progress%5 == 0) + postProgress(progress); + } + + delete [] IntensityCount; + delete [] AverageColorR; + delete [] AverageColorG; + delete [] AverageColorB; +} + +/* Function to apply the mosaic effect backported from ImageProcessing version 2 + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Size => Size of mosaic . + * + * Theory => Ok, you can find some mosaic effects on PSC, but this one + * has a great feature, if you see a mosaic in other code you will + * see that the corner pixel doesn't change. The explanation is + * simple, the color of the mosaic is the same as the first pixel + * get. Here, the color of the mosaic is the same as the mosaic + * center pixel. + * Now the function scan the rows from the top (like photoshop). + */ +void BlurFX::mosaic(Digikam::DImg *orgImage, Digikam::DImg *destImage, int SizeW, int SizeH) +{ + int progress; + + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pResBits = destImage->bits(); + + // we need to check for valid values + if (SizeW < 1) SizeW = 1; + if (SizeH < 1) SizeH = 1; + if ((SizeW == 1) && (SizeH == 1)) return; + + Digikam::DColor color; + int offsetCenter, offset; + + // this loop will never look for transparent colors + + for (int h = 0; !m_cancel && (h < Height); h += SizeH) + { + for (int w = 0; !m_cancel && (w < Width); w += SizeW) + { + // we have to find the center pixel for mosaic's rectangle + + offsetCenter = GetOffsetAdjusted(Width, Height, w + (SizeW / 2), h + (SizeH / 2), bytesDepth); + color.setColor(data + offsetCenter, sixteenBit); + + // now, we fill the mosaic's rectangle with the center pixel color + + for (int subw = w; !m_cancel && (subw <= w + SizeW); subw++) + { + for (int subh = h; !m_cancel && (subh <= h + SizeH); subh++) + { + // if is inside... + if (IsInside(Width, Height, subw, subh)) + { + // set color + offset = GetOffset(Width, subw, subh, bytesDepth); + color.setPixel(pResBits + offset); + } + } + } + } + + // Update the progress bar in dialog. + progress = (int) (((double)h * 100.0) / Height); + + if (progress%5 == 0) + postProgress(progress); + } +} + +/* Function to get a color in a matriz with a determined size + * + * Bits => Bits array + * Width => Image width + * Height => Image height + * X => Position horizontal + * Y => Position vertical + * Radius => The radius of the matrix to be created + * + * Theory => This function takes from a distinct matrix a random color + */ +Digikam::DColor BlurFX::RandomColor(uchar *Bits, int Width, int Height, bool sixteenBit, int bytesDepth, + int X, int Y, int Radius, + int alpha, uint *randomSeed, int range, uchar *IntensityCount, + uint *AverageColorR, uint *AverageColorG, uint *AverageColorB) +{ + Digikam::DColor color; + int offset; + + int w, h, counter = 0; + + int I; + + // For 16 bit we have a problem here because this takes 255 times longer, + // and the algorithm is really slow for 16 bit, but I think this cannot be avoided. + memset(IntensityCount, 0, range ); + memset(AverageColorR, 0, range ); + memset(AverageColorG, 0, range ); + memset(AverageColorB, 0, range ); + + for (w = X - Radius; !m_cancel && (w <= X + Radius); w++) + { + for (h = Y - Radius; !m_cancel && (h <= Y + Radius); h++) + { + if ((w >= 0) && (w < Width) && (h >= 0) && (h < Height)) + { + offset = GetOffset(Width, w, h, bytesDepth); + color.setColor(Bits + offset, sixteenBit); + I = GetIntensity (color.red(), color.green(), color.blue()); + IntensityCount[I]++; + counter++; + + if (IntensityCount[I] == 1) + { + AverageColorR[I] = color.red(); + AverageColorG[I] = color.green(); + AverageColorB[I] = color.blue(); + } + else + { + AverageColorR[I] += color.red(); + AverageColorG[I] += color.green(); + AverageColorB[I] += color.blue(); + } + } + } + } + + // check for m_cancel here before entering the do loop (will crash with SIGFPE otherwise) + if (m_cancel) + return Digikam::DColor(0, 0, 0, 0, sixteenBit); + + int RandNumber, count, Index, ErrorCount = 0; + int J; + + do + { + RandNumber = abs( (int)((rand_r(randomSeed) + 1) * ((double)counter / (1 + (double) RAND_MAX))) ); + count = 0; + Index = 0; + + do + { + count += IntensityCount[Index]; + Index++; + } + while (count < RandNumber && !m_cancel); + + J = Index - 1; + ErrorCount++; + } + while ((IntensityCount[J] == 0) && (ErrorCount <= counter) && !m_cancel); + + if (m_cancel) + return Digikam::DColor(0, 0, 0, 0, sixteenBit); + + + color.setSixteenBit(sixteenBit); + color.setAlpha(alpha); + + if (ErrorCount >= counter) + { + color.setRed (AverageColorR[J] / counter); + color.setGreen(AverageColorG[J] / counter); + color.setBlue (AverageColorB[J] / counter); + } + else + { + color.setRed (AverageColorR[J] / IntensityCount[J]); + color.setGreen(AverageColorG[J] / IntensityCount[J]); + color.setBlue (AverageColorB[J] / IntensityCount[J]); + } + + return color; +} + +/* Function to simple convolve a unique pixel with a determined radius + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Radius => kernel radius, e.g. rad=1, so array will be 3X3 + * Kernel => kernel array to apply. + * + * Theory => I've worked hard here, but I think this is a very smart + * way to convolve an array, its very hard to explain how I reach + * this, but the trick here its to store the sum used by the + * previous pixel, so we sum with the other pixels that wasn't get + */ +void BlurFX::MakeConvolution (Digikam::DImg *orgImage, Digikam::DImg *destImage, int Radius, int Kernel[]) +{ + if (Radius <= 0) return; + + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pOutBits = destImage->bits(); + + int progress; + int n, h, w; + + int nSumR, nSumG, nSumB, nCount; + int nKernelWidth = Radius * 2 + 1; + int range = sixteenBit ? 65536 : 256; + Digikam::DColor color; + int offset; + + uchar* pBlur = new uchar[orgImage->numBytes()]; + + // We need to copy our bits to blur bits + + memcpy (pBlur, data, orgImage->numBytes()); + + // We need to alloc a 2d array to help us to store the values + + int** arrMult = Alloc2DArray (nKernelWidth, range); + + for (int i = 0; i < nKernelWidth; i++) + for (int j = 0; j < range; j++) + arrMult[i][j] = j * Kernel[i]; + + // Now, we enter in the main loop + + for (h = 0; !m_cancel && (h < Height); h++) + { + for (w = 0; !m_cancel && (w < Width); w++) + { + // initialize the variables + nSumR = nSumG = nSumB = nCount = 0; + + // first of all, we need to blur the horizontal lines + + for (n = -Radius; !m_cancel && (n <= Radius); n++) + { + // if is inside... + if (IsInside (Width, Height, w + n, h)) + { + // read color from orgImage + offset = GetOffset(Width, w+n, h, bytesDepth); + color.setColor(data + offset, sixteenBit); + + // finally, we sum the pixels using a method similar to assigntables + nSumR += arrMult[n + Radius][color.red()]; + nSumG += arrMult[n + Radius][color.green()]; + nSumB += arrMult[n + Radius][color.blue()]; + + // we need to add the kernel value to the counter + nCount += Kernel[n + Radius]; + } + } + + if (nCount == 0) nCount = 1; + + // calculate pointer + offset = GetOffset(Width, w, h, bytesDepth); + // read color from orgImage to preserve alpha + color.setColor(data + offset, sixteenBit); + + // now, we have to calc the arithmetic average + if (sixteenBit) + { + color.setRed (LimitValues16(nSumR / nCount)); + color.setGreen(LimitValues16(nSumG / nCount)); + color.setBlue (LimitValues16(nSumB / nCount)); + } + else + { + color.setRed (LimitValues8(nSumR / nCount)); + color.setGreen(LimitValues8(nSumG / nCount)); + color.setBlue (LimitValues8(nSumB / nCount)); + } + + // write color to blur bits + color.setPixel(pBlur + offset); + } + + // Update the progress bar in dialog. + progress = (int) (((double)h * 50.0) / Height); + + if (progress%5 == 0) + postProgress(progress); + } + + // We enter in the second main loop + for (w = 0; !m_cancel && (w < Width); w++) + { + for (h = 0; !m_cancel && (h < Height); h++) + { + // initialize the variables + nSumR = nSumG = nSumB = nCount = 0; + + // first of all, we need to blur the vertical lines + for (n = -Radius; !m_cancel && (n <= Radius); n++) + { + // if is inside... + if (IsInside(Width, Height, w, h + n)) + { + // read color from blur bits + offset = GetOffset(Width, w, h+n, bytesDepth); + color.setColor(pBlur + offset, sixteenBit); + + // finally, we sum the pixels using a method similar to assigntables + nSumR += arrMult[n + Radius][color.red()]; + nSumG += arrMult[n + Radius][color.green()]; + nSumB += arrMult[n + Radius][color.blue()]; + + // we need to add the kernel value to the counter + nCount += Kernel[n + Radius]; + } + } + + if (nCount == 0) nCount = 1; + + // calculate pointer + offset = GetOffset(Width, w, h, bytesDepth); + // read color from orgImage to preserve alpha + color.setColor(data + offset, sixteenBit); + + // now, we have to calc the arithmetic average + if (sixteenBit) + { + color.setRed (LimitValues16(nSumR / nCount)); + color.setGreen(LimitValues16(nSumG / nCount)); + color.setBlue (LimitValues16(nSumB / nCount)); + } + else + { + color.setRed (LimitValues8(nSumR / nCount)); + color.setGreen(LimitValues8(nSumG / nCount)); + color.setBlue (LimitValues8(nSumB / nCount)); + } + + // write color to destination + color.setPixel(pOutBits + offset); + } + + // Update the progress bar in dialog. + progress = (int) (50.0 + ((double)w * 50.0) / Width); + + if (progress%5 == 0) + postProgress(progress); + } + + // now, we must free memory + Free2DArray (arrMult, nKernelWidth); + delete [] pBlur; +} + +} // NameSpace DigikamBlurFXImagesPlugin diff --git a/src/imageplugins/blurfx/blurfx.h b/src/imageplugins/blurfx/blurfx.h new file mode 100644 index 00000000..4a4397b4 --- /dev/null +++ b/src/imageplugins/blurfx/blurfx.h @@ -0,0 +1,191 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : Blur FX threaded image filter. + * + * Copyright 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * Original Blur algorithms copyrighted 2004 by + * Pieter Z. Voloshyn <pieter dot voloshyn 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. + * + * ============================================================ */ + +#ifndef BLURFX_H +#define BLURFX_H + +// Digikam includes. + +#include "dimgthreadedfilter.h" + +namespace DigikamBlurFXImagesPlugin +{ + +class BlurFX : public Digikam::DImgThreadedFilter +{ + +public: + + BlurFX(Digikam::DImg *orgImage, TQObject *parent=0, int blurFXType=ZoomBlur, + int distance=100, int level=45); + + ~BlurFX(){}; + +public: + + enum BlurFXTypes + { + ZoomBlur=0, + RadialBlur, + FarBlur, + MotionBlur, + SoftenerBlur, + ShakeBlur, + FocusBlur, + SmartBlur, + FrostGlass, + Mosaic + }; + +private: // BlurFX filter data. + + int m_blurFXType; + int m_distance; + int m_level; + +private: // BlurFX filter methods. + + virtual void filterImage(void); + + // Backported from ImageProcessing version 1 + void softenerBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage); + void shakeBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Distance); + void frostGlass(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Frost); + + // Backported from ImageProcessing version 2 + void zoomBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, + int X, int Y, int Distance, TQRect pArea=TQRect()); + void radialBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, + int X, int Y, int Distance, TQRect pArea=TQRect()); + void focusBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, + int X, int Y, int BlurRadius, int BlendRadius, + bool bInversed=false, TQRect pArea=TQRect()); + void farBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Distance); + void motionBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Distance, double Angle=0.0); + void smartBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Radius, int Strenght); + void mosaic(Digikam::DImg *orgImage, Digikam::DImg *destImage, int SizeW, int SizeH); + +private: // Internal filter methods. + + void MakeConvolution(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Radius, int Kernel[]); + + Digikam::DColor RandomColor(uchar *Bits, int Width, int Height, bool sixteenBit, int bytesDepth, + int X, int Y, int Radius, + int alpha, uint *randomSeed, int range, uchar *IntensityCount, + uint *AverageColorR, uint *AverageColorG, uint *AverageColorB); + + // Return the limit defined the max and min values. + inline int Lim_Max(int Now, int Up, int Max) + { + --Max; + while (Now > Max - Up) --Up; + return (Up); + }; + + // Return the luminance (Y) component of YIQ color model. + inline int GetIntensity (int R, int G, int B) + { + return (int)(R * 0.3 + G * 0.59 + B * 0.11); + }; + + // function to allocate a 2d array + inline int** Alloc2DArray (int Columns, int Rows) + { + // First, we declare our future 2d array to be returned + int** lpcArray = NULL; + + // Now, we alloc the main pointer with Columns + lpcArray = new int*[Columns]; + + for (int i = 0; i < Columns; i++) + lpcArray[i] = new int[Rows]; + + return (lpcArray); + } + + // Function to deallocates the 2d array previously created + inline void Free2DArray (int** lpcArray, int Columns) + { + // loop to dealocate the columns + for (int i = 0; i < Columns; i++) + delete [] lpcArray[i]; + + // now, we delete the main pointer + delete [] lpcArray; + } + + inline bool IsInside (int Width, int Height, int X, int Y) + { + bool bIsWOk = ((X < 0) ? false : (X >= Width ) ? false : true); + bool bIsHOk = ((Y < 0) ? false : (Y >= Height) ? false : true); + return (bIsWOk && bIsHOk); + }; + + inline uchar LimitValues8(int ColorValue) + { + if (ColorValue > 255) ColorValue = 255; + if (ColorValue < 0) ColorValue = 0; + return ((uchar) ColorValue); + }; + + + inline int LimitValues16(int ColorValue) + { + if (ColorValue > 65535) ColorValue = 65535; + if (ColorValue < 0) ColorValue = 0; + return ColorValue; + }; + + inline int GetOffset(int Width, int X, int Y, int bytesDepth) + { + return (Y * Width * bytesDepth) + (X * bytesDepth); + }; + + inline int GetOffsetAdjusted(int Width, int Height, int X, int Y, int bytesDepth) + { + X = (X < 0) ? 0 : ((X >= Width ) ? (Width - 1) : X); + Y = (Y < 0) ? 0 : ((Y >= Height) ? (Height - 1) : Y); + return GetOffset(Width, X, Y, bytesDepth); + }; + + inline bool IsColorInsideTheRange (int cR, int cG, int cB, + int nR, int nG, int nB, + int Range) + { + if ((nR >= cR - Range) && (nR <= cR + Range)) + if ((nG >= cG - Range) && (nG <= cG + Range)) + if ((nB >= cB - Range) && (nB <= cB + Range)) + return (true); + + return (false); + }; + +}; + +} // NameSpace DigikamBlurFXImagesPlugin + +#endif /* BLURFX_H */ diff --git a/src/imageplugins/blurfx/blurfxtool.cpp b/src/imageplugins/blurfx/blurfxtool.cpp new file mode 100644 index 00000000..2998dbde --- /dev/null +++ b/src/imageplugins/blurfx/blurfxtool.cpp @@ -0,0 +1,402 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-09 + * Description : a plugin to apply Blur FX to images + * + * Copyright 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <tqdatetime.h> +#include <tqimage.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqslider.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <tdelocale.h> +#include <kiconloader.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> +#include <libkdcraw/rcombobox.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "imageiface.h" +#include "imagepanelwidget.h" +#include "editortoolsettings.h" +#include "blurfx.h" +#include "blurfxtool.h" +#include "blurfxtool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamBlurFXImagesPlugin +{ + +BlurFXTool::BlurFXTool(TQObject* parent) + : EditorToolThreaded(parent) +{ + setName("blurfx"); + setToolName(i18n("Blur FX")); + setToolIcon(SmallIcon("blurfx")); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel| + EditorToolSettings::Try, + EditorToolSettings::PanIcon); + TQGridLayout* grid = new TQGridLayout( m_gboxSettings->plainPage(), 6, 1); + + m_effectTypeLabel = new TQLabel(i18n("Type:"), m_gboxSettings->plainPage()); + + m_effectType = new RComboBox(m_gboxSettings->plainPage()); + m_effectType->insertItem(i18n("Zoom Blur")); + m_effectType->insertItem(i18n("Radial Blur")); + m_effectType->insertItem(i18n("Far Blur")); + m_effectType->insertItem(i18n("Motion Blur")); + m_effectType->insertItem(i18n("Softener Blur")); + m_effectType->insertItem(i18n("Skake Blur")); + m_effectType->insertItem(i18n("Focus Blur")); + m_effectType->insertItem(i18n("Smart Blur")); + m_effectType->insertItem(i18n("Frost Glass")); + m_effectType->insertItem(i18n("Mosaic")); + m_effectType->setDefaultItem(BlurFX::ZoomBlur); + TQWhatsThis::add( m_effectType, i18n("<p>Select the blurring effect to apply to the image.<p>" + "<b>Zoom Blur</b>: blurs the image along radial lines starting from " + "a specified center point. This simulates the blur of a zooming camera.<p>" + "<b>Radial Blur</b>: blurs the image by rotating the pixels around " + "the specified center point. This simulates the blur of a rotating camera.<p>" + "<b>Far Blur</b>: blurs the image by using far pixels. This simulates the blur " + "of an unfocalized camera lens.<p>" + "<b>Motion Blur</b>: blurs the image by moving the pixels horizontally. " + "This simulates the blur of a linear moving camera.<p>" + "<b>Softener Blur</b>: blurs the image softly in dark tones and hardly in light " + "tones. This gives images a dreamy and glossy soft focus effect. It's ideal " + "for creating romantic portraits, glamour photographs, or giving images a warm " + "and subtle glow.<p>" + "<b>Skake Blur</b>: blurs the image by skaking randomly the pixels. " + "This simulates the blur of a random moving camera.<p>" + "<b>Focus Blur</b>: blurs the image corners to reproduce the astigmatism distortion " + "of a lens.<p>" + "<b>Smart Blur</b>: finds the edges of color in your image and blurs them without " + "muddying the rest of the image.<p>" + "<b>Frost Glass</b>: blurs the image by randomly disperse light coming through " + "a frosted glass.<p>" + "<b>Mosaic</b>: divides the photograph into rectangular cells and then " + "recreates it by filling those cells with average pixel value.")); + + m_distanceLabel = new TQLabel(i18n("Distance:"), m_gboxSettings->plainPage()); + m_distanceInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_distanceInput->setRange(0, 100, 1); + m_distanceInput->setDefaultValue(3); + TQWhatsThis::add( m_distanceInput, i18n("<p>Set here the blur distance in pixels.")); + + m_levelLabel = new TQLabel(i18n("Level:"), m_gboxSettings->plainPage()); + m_levelInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_levelInput->setRange(0, 360, 1); + m_levelInput->setDefaultValue(128); + TQWhatsThis::add( m_levelInput, i18n("<p>This value controls the level to use with the current effect.")); + + grid->addMultiCellWidget(m_effectTypeLabel, 0, 0, 0, 1); + grid->addMultiCellWidget(m_effectType, 1, 1, 0, 1); + grid->addMultiCellWidget(m_distanceLabel, 2, 2, 0, 1); + grid->addMultiCellWidget(m_distanceInput, 3, 3, 0, 1); + grid->addMultiCellWidget(m_levelLabel, 4, 4, 0, 1); + grid->addMultiCellWidget(m_levelInput, 5, 5, 0, 1); + grid->setRowStretch(6, 10); + grid->setMargin(m_gboxSettings->spacingHint()); + grid->setSpacing(m_gboxSettings->spacingHint()); + + setToolSettings(m_gboxSettings); + + // ------------------------------------------------------------- + + m_previewWidget = new ImagePanelWidget(470, 350, "blurfx Tool", m_gboxSettings->panIconView()); + + setToolView(m_previewWidget); + init(); + + // ------------------------------------------------------------- + + connect(m_effectType, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotEffectTypeChanged(int))); + + connect(m_distanceInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_levelInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); +} + +BlurFXTool::~BlurFXTool() +{ +} + +void BlurFXTool::renderingFinished(void) +{ + + m_effectTypeLabel->setEnabled(true); + m_effectType->setEnabled(true); + m_distanceInput->setEnabled(true); + m_distanceLabel->setEnabled(true); + + switch (m_effectType->currentItem()) + { + case BlurFX::ZoomBlur: + case BlurFX::RadialBlur: + case BlurFX::FarBlur: + case BlurFX::ShakeBlur: + case BlurFX::FrostGlass: + case BlurFX::Mosaic: + break; + + case BlurFX::MotionBlur: + case BlurFX::FocusBlur: + case BlurFX::SmartBlur: + m_levelInput->setEnabled(true); + m_levelLabel->setEnabled(true); + break; + + case BlurFX::SoftenerBlur: + m_distanceInput->setEnabled(false); + m_distanceLabel->setEnabled(false); + break; + } +} + +void BlurFXTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("blurfx Tool"); + m_effectType->blockSignals(true); + m_distanceInput->blockSignals(true); + m_levelInput->blockSignals(true); + + m_effectType->setCurrentItem(config->readNumEntry("EffectType", m_effectType->defaultItem())); + m_distanceInput->setValue(config->readNumEntry("DistanceAjustment", m_distanceInput->defaultValue())); + m_levelInput->setValue(config->readNumEntry("LevelAjustment", m_levelInput->defaultValue())); + + m_effectType->blockSignals(false); + m_distanceInput->blockSignals(false); + m_levelInput->blockSignals(false); +} + +void BlurFXTool::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("blurfx Tool"); + config->writeEntry("EffectType", m_effectType->currentItem()); + config->writeEntry("DistanceAjustment", m_distanceInput->value()); + config->writeEntry("LevelAjustment", m_levelInput->value()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void BlurFXTool::slotResetSettings() +{ + m_effectType->blockSignals(true); + m_distanceInput->blockSignals(true); + m_levelInput->blockSignals(true); + + m_effectType->slotReset(); + m_distanceInput->slotReset(); + m_levelInput->slotReset(); + + m_effectType->blockSignals(false); + m_distanceInput->blockSignals(false); + m_levelInput->blockSignals(false); + + slotEffectTypeChanged(m_effectType->defaultItem()); +} + +void BlurFXTool::slotEffectTypeChanged(int type) +{ + m_distanceInput->setEnabled(true); + m_distanceLabel->setEnabled(true); + + m_distanceInput->blockSignals(true); + m_levelInput->blockSignals(true); + + m_distanceInput->setRange(0, 200, 1); + m_distanceInput->setValue(100); + m_levelInput->setRange(0, 360, 1); + m_levelInput->setValue(45); + + m_levelInput->setEnabled(false); + m_levelLabel->setEnabled(false); + + switch (type) + { + case BlurFX::ZoomBlur: + break; + + case BlurFX::RadialBlur: + case BlurFX::FrostGlass: + m_distanceInput->setRange(0, 10, 1); + m_distanceInput->setValue(3); + break; + + case BlurFX::FarBlur: + m_distanceInput->setRange(0, 20, 1); + m_distanceInput->input()->setMaxValue(20); + m_distanceInput->setValue(10); + break; + + case BlurFX::MotionBlur: + case BlurFX::FocusBlur: + m_distanceInput->setRange(0, 100, 1); + m_distanceInput->setValue(20); + m_levelInput->setEnabled(true); + m_levelLabel->setEnabled(true); + break; + + case BlurFX::SoftenerBlur: + m_distanceInput->setEnabled(false); + m_distanceLabel->setEnabled(false); + break; + + case BlurFX::ShakeBlur: + m_distanceInput->setRange(0, 100, 1); + m_distanceInput->setValue(20); + break; + + case BlurFX::SmartBlur: + m_distanceInput->setRange(0, 20, 1); + m_distanceInput->setValue(3); + m_levelInput->setEnabled(true); + m_levelLabel->setEnabled(true); + m_levelInput->setRange(0, 255, 1); + m_levelInput->setValue(128); + break; + + case BlurFX::Mosaic: + m_distanceInput->setRange(0, 50, 1); + m_distanceInput->setValue(3); + break; + } + + m_distanceInput->blockSignals(false); + m_levelInput->blockSignals(false); + + slotEffect(); +} + +void BlurFXTool::prepareEffect() +{ + m_effectTypeLabel->setEnabled(false); + m_effectType->setEnabled(false); + m_distanceInput->setEnabled(false); + m_distanceLabel->setEnabled(false); + m_levelInput->setEnabled(false); + m_levelLabel->setEnabled(false); + + DImg image; + + switch (m_effectType->currentItem()) + { + case BlurFX::ZoomBlur: + case BlurFX::RadialBlur: + case BlurFX::FocusBlur: + { + ImageIface iface(0, 0); + image = *iface.getOriginalImg(); + break; + } + + case BlurFX::FarBlur: + case BlurFX::MotionBlur: + case BlurFX::SoftenerBlur: + case BlurFX::ShakeBlur: + case BlurFX::SmartBlur: + case BlurFX::FrostGlass: + case BlurFX::Mosaic: + image = m_previewWidget->getOriginalRegionImage(); + break; + } + + int t = m_effectType->currentItem(); + int d = m_distanceInput->value(); + int l = m_levelInput->value(); + + setFilter(dynamic_cast<DImgThreadedFilter*>(new BlurFX(&image, this, t, d, l))); +} + +void BlurFXTool::prepareFinal() +{ + m_effectTypeLabel->setEnabled(false); + m_effectType->setEnabled(false); + m_distanceInput->setEnabled(false); + m_distanceLabel->setEnabled(false); + m_levelInput->setEnabled(false); + m_levelLabel->setEnabled(false); + + int t = m_effectType->currentItem(); + int d = m_distanceInput->value(); + int l = m_levelInput->value(); + + ImageIface iface(0, 0); + setFilter(dynamic_cast<DImgThreadedFilter *>(new BlurFX(iface.getOriginalImg(), this, t, d, l))); +} + +void BlurFXTool::putPreviewData() +{ + switch (m_effectType->currentItem()) + { + case BlurFX::ZoomBlur: + case BlurFX::RadialBlur: + case BlurFX::FocusBlur: + { + TQRect pRect = m_previewWidget->getOriginalImageRegionToRender(); + DImg destImg = filter()->getTargetImage().copy(pRect); + m_previewWidget->setPreviewImage(destImg); + break; + } + case BlurFX::FarBlur: + case BlurFX::MotionBlur: + case BlurFX::SoftenerBlur: + case BlurFX::ShakeBlur: + case BlurFX::SmartBlur: + case BlurFX::FrostGlass: + case BlurFX::Mosaic: + m_previewWidget->setPreviewImage(filter()->getTargetImage()); + break; + } +} + +void BlurFXTool::putFinalData() +{ + ImageIface iface(0, 0); + iface.putOriginalImage(i18n("Blur Effects"), filter()->getTargetImage().bits()); +} + +} // NameSpace DigikamBlurFXImagesPlugin diff --git a/src/imageplugins/blurfx/blurfxtool.h b/src/imageplugins/blurfx/blurfxtool.h new file mode 100644 index 00000000..9726e65d --- /dev/null +++ b/src/imageplugins/blurfx/blurfxtool.h @@ -0,0 +1,93 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-09 + * Description : a plugin to apply Blur FX to images + * + * Copyright 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef BLURFXTOOL_H +#define BLURFXTOOL_H + +// Digikam includes. + +#include "editortool.h" + +class TQLabel; + +namespace KDcrawIface +{ +class RIntNumInput; +class RComboBox; +} + +namespace Digikam +{ +class EditorToolSettings; +class ImagePanelWidget; +} + +namespace DigikamBlurFXImagesPlugin +{ + +class BlurFXTool : public Digikam::EditorToolThreaded +{ + TQ_OBJECT + + +public: + + BlurFXTool(TQObject *parent); + ~BlurFXTool(); + +private slots: + + void slotEffectTypeChanged(int type); + void slotResetSettings(); + +private: + + void readSettings(); + void writeSettings(); + void prepareEffect(); + void prepareFinal(); + void abortPreview(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + TQLabel *m_effectTypeLabel; + TQLabel *m_distanceLabel; + TQLabel *m_levelLabel; + + KDcrawIface::RComboBox *m_effectType; + + KDcrawIface::RIntNumInput *m_distanceInput; + KDcrawIface::RIntNumInput *m_levelInput; + + Digikam::ImagePanelWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamBlurFXImagesPlugin + +#endif /* BLURFXTOOL_H */ diff --git a/src/imageplugins/blurfx/digikamimageplugin_blurfx.desktop b/src/imageplugins/blurfx/digikamimageplugin_blurfx.desktop new file mode 100644 index 00000000..e7968a80 --- /dev/null +++ b/src/imageplugins/blurfx/digikamimageplugin_blurfx.desktop @@ -0,0 +1,49 @@ +[Desktop Entry] +Name=ImagePlugin_BlurFX +Name[bg]=Приставка за снимки - Ефекти за замъгляване +Name[el]=ΠρόσθετοΕικόνας_ΕφέΘολώματος +Name[fi]=Sumennus +Name[hr]=Zamućenje +Name[it]=PluginImmagini_EffettiDiSfocatura +Name[nl]=Afbeeldingsplugin_Vervaageffect +Name[sr]=Ефекти замућења +Name[sr@Latn]=Efekti zamućenja +Name[sv]=Insticksprogram för oskärpeeffekt +Name[tr]=ResimEklentisi_Bulanıklaştır +Name[xx]=xxImagePlugin_BlurFXxx +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=Blur special effects plugin for digiKam +Comment[bg]=Приставка на digiKam с ефекти за замъгляване на снимки +Comment[ca]=Connector pel digiKam d'efectes especials de difuminat +Comment[da]=Digikam plugin med specialeffekter for udviskning +Comment[de]=digiKam-Modul zum Erzeugen von speziellen Unschärfe-Effekten +Comment[el]=Πρόσθετο ειδικών εφέ θολώματος για το digiKam +Comment[es]=Plugin para digiKam con efectos especiales de difusión +Comment[et]=DigiKami spetsiaalsete hägustamisefektide plugin +Comment[fa]=وصلۀ جلوههای ویژۀ محو برای digiKam +Comment[fi]=Sumennustehosteita +Comment[gl]=Un plugin de digiKam para efeitos especiais de borrón +Comment[hr]=digiKam dodatak za efekt zamućenja +Comment[is]=Íforrit fyrir digiKam sem mýkir eða afskerpir myndir +Comment[it]=Plugin degli effetti speciali di sfocatura per digiKam +Comment[ja]=digiKam ぼかし特殊効果プラグイン +Comment[nds]=digiKam-Moduul för't Opstellen vun Weekteek-Effekten +Comment[nl]=Digikam-plugin voor vervaageffect +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਬਲੱਰ (ਧੁੰਧਲਾਪਨ) ਖਾਸ ਪਰਭਾਵ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka specjalnych efektów rozmycia do programu digiKam +Comment[pt]=Um 'plugin' do digiKam para efeitos especiais de borrão +Comment[pt_BR]=Plugin de efeitos especiais de desfocalização +Comment[ru]=Модуль специальных эффектов размытия для digiKam +Comment[sk]=digiKam plugin pre špeciálne efekty rozmazania +Comment[sr]=Прикључак ефеката замућења за digiKam +Comment[sr@Latn]=Priključak efekata zamućenja za digiKam +Comment[sv]=Digikam insticksprogram med specialeffekter för oskärpa +Comment[tr]=digiKam için bulanıklaştırma eklentisi +Comment[uk]=Втулок спеціальних ефектів розмивання для digiKam +Comment[vi]=Phần bổ sung hiệu ứng che mờ cho digiKam +Comment[xx]=xxBlur special effects plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_blurfx +author=Gilles Caulier, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/blurfx/digikamimageplugin_blurfx_ui.rc b/src/imageplugins/blurfx/digikamimageplugin_blurfx_ui.rc new file mode 100644 index 00000000..085b4c68 --- /dev/null +++ b/src/imageplugins/blurfx/digikamimageplugin_blurfx_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="5" name="digikamimageplugin_blurfx" > + + <MenuBar> + + <Menu name="Filters" ><text>F&ilters</text> + <Action name="imageplugin_blurfx" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action shortcut="" name="imageplugin_blurfx" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/blurfx/imageeffect_blurfx.cpp b/src/imageplugins/blurfx/imageeffect_blurfx.cpp new file mode 100644 index 00000000..62bcd525 --- /dev/null +++ b/src/imageplugins/blurfx/imageeffect_blurfx.cpp @@ -0,0 +1,388 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-09 + * Description : a plugin to apply Blur FX to images + * + * Copyright 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <tqlabel.h> +#include <tqwhatsthis.h> +#include <tqlayout.h> +#include <tqslider.h> +#include <tqimage.h> +#include <tqcombobox.h> +#include <tqdatetime.h> + +// KDE includes. + +#include <tdeconfig.h> +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <knuminput.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "blurfx.h" +#include "imageeffect_blurfx.h" +#include "imageeffect_blurfx.moc" + +namespace DigikamBlurFXImagesPlugin +{ + +ImageEffect_BlurFX::ImageEffect_BlurFX(TQWidget* parent) + : Digikam::CtrlPanelDlg(parent, i18n("Apply Blurring Special Effect to Photograph"), + "blurfx", false, false, true, + Digikam::ImagePannelWidget::SeparateViewAll) +{ + TQString whatsThis; + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Blur Effects"), + digikam_version, + I18N_NOOP("A digiKam image plugin to apply blurring special effect " + "to an image."), + TDEAboutData::License_GPL, + "(c) 2005, Gilles Caulier\n" + "(c) 2006-2008, Gilles Caulier and Marcel Wiesweg", + 0, + "http://www.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + about->addAuthor("Pieter Z. Voloshyn", I18N_NOOP("Blurring algorithms"), + "pieter dot voloshyn at gmail dot com"); + + about->addAuthor("Marcel Wiesweg", I18N_NOOP("Developer"), + "marcel dot wiesweg at gmx dot de"); + + setAboutData(about); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(m_imagePreviewWidget); + TQGridLayout* gridSettings = new TQGridLayout( gboxSettings, 5, 1, 0, spacingHint()); + + m_effectTypeLabel = new TQLabel(i18n("Type:"), gboxSettings); + + m_effectType = new TQComboBox( false, gboxSettings ); + m_effectType->insertItem( i18n("Zoom Blur") ); + m_effectType->insertItem( i18n("Radial Blur") ); + m_effectType->insertItem( i18n("Far Blur") ); + m_effectType->insertItem( i18n("Motion Blur") ); + m_effectType->insertItem( i18n("Softener Blur") ); + m_effectType->insertItem( i18n("Skake Blur") ); + m_effectType->insertItem( i18n("Focus Blur") ); + m_effectType->insertItem( i18n("Smart Blur") ); + m_effectType->insertItem( i18n("Frost Glass") ); + m_effectType->insertItem( i18n("Mosaic") ); + TQWhatsThis::add( m_effectType, i18n("<p>Select the blurring effect to apply to the image.<p>" + "<b>Zoom Blur</b>: blurs the image along radial lines starting from " + "a specified center point. This simulates the blur of a zooming camera.<p>" + "<b>Radial Blur</b>: blurs the image by rotating the pixels around " + "the specified center point. This simulates the blur of a rotating camera.<p>" + "<b>Far Blur</b>: blurs the image by using far pixels. This simulates the blur " + "of an unfocalized camera lens.<p>" + "<b>Motion Blur</b>: blurs the image by moving the pixels horizontally. " + "This simulates the blur of a linear moving camera.<p>" + "<b>Softener Blur</b>: blurs the image softly in dark tones and hardly in light " + "tones. This gives images a dreamy and glossy soft focus effect. It's ideal " + "for creating romantic portraits, glamour photographs, or giving images a warm " + "and subtle glow.<p>" + "<b>Skake Blur</b>: blurs the image by skaking randomly the pixels. " + "This simulates the blur of a random moving camera.<p>" + "<b>Focus Blur</b>: blurs the image corners to reproduce the astigmatism distortion " + "of a lens.<p>" + "<b>Smart Blur</b>: finds the edges of color in your image and blurs them without " + "muddying the rest of the image.<p>" + "<b>Frost Glass</b>: blurs the image by randomly disperse light coming through " + "a frosted glass.<p>" + "<b>Mosaic</b>: divides the photograph into rectangular cells and then " + "recreates it by filling those cells with average pixel value.")); + gridSettings->addMultiCellWidget(m_effectTypeLabel, 0, 0, 0, 1); + gridSettings->addMultiCellWidget(m_effectType, 1, 1, 0, 1); + + m_distanceLabel = new TQLabel(i18n("Distance:"), gboxSettings); + m_distanceInput = new KIntNumInput(gboxSettings); + m_distanceInput->setRange(0, 100, 1, true); + TQWhatsThis::add( m_distanceInput, i18n("<p>Set here the blur distance in pixels.")); + + gridSettings->addMultiCellWidget(m_distanceLabel, 2, 2, 0, 1); + gridSettings->addMultiCellWidget(m_distanceInput, 3, 3, 0, 1); + + m_levelLabel = new TQLabel(i18n("Level:"), gboxSettings); + m_levelInput = new KIntNumInput(gboxSettings); + m_levelInput->setRange(0, 360, 1, true); + TQWhatsThis::add( m_levelInput, i18n("<p>This value controls the level to use with the current effect.")); + + gridSettings->addMultiCellWidget(m_levelLabel, 4, 4, 0, 1); + gridSettings->addMultiCellWidget(m_levelInput, 5, 5, 0, 1); + + m_imagePreviewWidget->setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + connect(m_effectType, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotEffectTypeChanged(int))); + + connect(m_distanceInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_levelInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); +} + +ImageEffect_BlurFX::~ImageEffect_BlurFX() +{ +} + +void ImageEffect_BlurFX::renderingFinished(void) +{ + + m_effectTypeLabel->setEnabled(true); + m_effectType->setEnabled(true); + m_distanceInput->setEnabled(true); + m_distanceLabel->setEnabled(true); + + switch (m_effectType->currentItem()) + { + case BlurFX::ZoomBlur: + case BlurFX::RadialBlur: + case BlurFX::FarBlur: + case BlurFX::ShakeBlur: + case BlurFX::FrostGlass: + case BlurFX::Mosaic: + break; + + case BlurFX::MotionBlur: + case BlurFX::FocusBlur: + case BlurFX::SmartBlur: + m_levelInput->setEnabled(true); + m_levelLabel->setEnabled(true); + break; + + case BlurFX::SoftenerBlur: + m_distanceInput->setEnabled(false); + m_distanceLabel->setEnabled(false); + break; + } +} + +void ImageEffect_BlurFX::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("blurfx Tool Dialog"); + m_effectType->blockSignals(true); + m_distanceInput->blockSignals(true); + m_levelInput->blockSignals(true); + m_effectType->setCurrentItem(config->readNumEntry("EffectType", BlurFX::ZoomBlur)); + m_distanceInput->setValue(config->readNumEntry("DistanceAjustment", 3)); + m_levelInput->setValue(config->readNumEntry("LevelAjustment", 128)); + m_effectType->blockSignals(false); + m_distanceInput->blockSignals(false); + m_levelInput->blockSignals(false); +} + +void ImageEffect_BlurFX::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("blurfx Tool Dialog"); + config->writeEntry("EffectType", m_effectType->currentItem()); + config->writeEntry("DistanceAjustment", m_distanceInput->value()); + config->writeEntry("LevelAjustment", m_levelInput->value()); + config->sync(); +} + +void ImageEffect_BlurFX::resetValues() +{ + m_effectType->setCurrentItem(BlurFX::ZoomBlur); + slotEffectTypeChanged(BlurFX::ZoomBlur); +} + +void ImageEffect_BlurFX::slotEffectTypeChanged(int type) +{ + m_distanceInput->setEnabled(true); + m_distanceLabel->setEnabled(true); + + m_distanceInput->blockSignals(true); + m_levelInput->blockSignals(true); + m_distanceInput->setRange(0, 200, 1, true); + m_distanceInput->setValue(100); + m_levelInput->setRange(0, 360, 1, true); + m_levelInput->setValue(45); + + m_levelInput->setEnabled(false); + m_levelLabel->setEnabled(false); + + switch (type) + { + case BlurFX::ZoomBlur: + break; + + case BlurFX::RadialBlur: + case BlurFX::FrostGlass: + m_distanceInput->setRange(0, 10, 1, true); + m_distanceInput->setValue(3); + break; + + case BlurFX::FarBlur: + m_distanceInput->setRange(0, 20, 1, true); + m_distanceInput->setMaxValue(20); + m_distanceInput->setValue(10); + break; + + case BlurFX::MotionBlur: + case BlurFX::FocusBlur: + m_distanceInput->setRange(0, 100, 1, true); + m_distanceInput->setValue(20); + m_levelInput->setEnabled(true); + m_levelLabel->setEnabled(true); + break; + + case BlurFX::SoftenerBlur: + m_distanceInput->setEnabled(false); + m_distanceLabel->setEnabled(false); + break; + + case BlurFX::ShakeBlur: + m_distanceInput->setRange(0, 100, 1, true); + m_distanceInput->setValue(20); + break; + + case BlurFX::SmartBlur: + m_distanceInput->setRange(0, 20, 1, true); + m_distanceInput->setValue(3); + m_levelInput->setEnabled(true); + m_levelLabel->setEnabled(true); + m_levelInput->setRange(0, 255, 1, true); + m_levelInput->setValue(128); + break; + + case BlurFX::Mosaic: + m_distanceInput->setRange(0, 50, 1, true); + m_distanceInput->setValue(3); + break; + } + + m_distanceInput->blockSignals(false); + m_levelInput->blockSignals(false); + + slotEffect(); +} + +void ImageEffect_BlurFX::prepareEffect() +{ + m_effectTypeLabel->setEnabled(false); + m_effectType->setEnabled(false); + m_distanceInput->setEnabled(false); + m_distanceLabel->setEnabled(false); + m_levelInput->setEnabled(false); + m_levelLabel->setEnabled(false); + + Digikam::DImg image; + + switch (m_effectType->currentItem()) + { + case BlurFX::ZoomBlur: + case BlurFX::RadialBlur: + case BlurFX::FocusBlur: + { + Digikam::ImageIface iface(0, 0); + image = *iface.getOriginalImg(); + break; + } + + case BlurFX::FarBlur: + case BlurFX::MotionBlur: + case BlurFX::SoftenerBlur: + case BlurFX::ShakeBlur: + case BlurFX::SmartBlur: + case BlurFX::FrostGlass: + case BlurFX::Mosaic: + image = m_imagePreviewWidget->getOriginalRegionImage(); + break; + } + + int t = m_effectType->currentItem(); + int d = m_distanceInput->value(); + int l = m_levelInput->value(); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>(new BlurFX(&image, this, t, d, l)); +} + +void ImageEffect_BlurFX::prepareFinal() +{ + m_effectTypeLabel->setEnabled(false); + m_effectType->setEnabled(false); + m_distanceInput->setEnabled(false); + m_distanceLabel->setEnabled(false); + m_levelInput->setEnabled(false); + m_levelLabel->setEnabled(false); + + int t = m_effectType->currentItem(); + int d = m_distanceInput->value(); + int l = m_levelInput->value(); + + Digikam::ImageIface iface(0, 0); + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>(new BlurFX(iface.getOriginalImg(), this, t, d, l)); +} + +void ImageEffect_BlurFX::putPreviewData(void) +{ + switch (m_effectType->currentItem()) + { + case BlurFX::ZoomBlur: + case BlurFX::RadialBlur: + case BlurFX::FocusBlur: + { + TQRect pRect = m_imagePreviewWidget->getOriginalImageRegionToRender(); + Digikam::DImg destImg = m_threadedFilter->getTargetImage().copy(pRect); + m_imagePreviewWidget->setPreviewImage(destImg); + break; + } + case BlurFX::FarBlur: + case BlurFX::MotionBlur: + case BlurFX::SoftenerBlur: + case BlurFX::ShakeBlur: + case BlurFX::SmartBlur: + case BlurFX::FrostGlass: + case BlurFX::Mosaic: + m_imagePreviewWidget->setPreviewImage(m_threadedFilter->getTargetImage()); + break; + } +} + +void ImageEffect_BlurFX::putFinalData(void) +{ + Digikam::ImageIface iface(0, 0); + + iface.putOriginalImage(i18n("Blur Effects"), + m_threadedFilter->getTargetImage().bits()); +} + +} // NameSpace DigikamBlurFXImagesPlugin + diff --git a/src/imageplugins/blurfx/imageeffect_blurfx.h b/src/imageplugins/blurfx/imageeffect_blurfx.h new file mode 100644 index 00000000..e2517d4f --- /dev/null +++ b/src/imageplugins/blurfx/imageeffect_blurfx.h @@ -0,0 +1,80 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-09 + * Description : a plugin to apply Blur FX to images + * + * Copyright 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_BLURFX_H +#define IMAGEEFFECT_BLURFX_H + +// Digikam includes. + +#include "ctrlpaneldlg.h" + +class TQComboBox; +class TQLabel; + +class KIntNumInput; + +namespace DigikamBlurFXImagesPlugin +{ + +class ImageEffect_BlurFX : public Digikam::CtrlPanelDlg +{ + TQ_OBJECT + + +public: + + ImageEffect_BlurFX(TQWidget *parent); + ~ImageEffect_BlurFX(); + +private slots: + + void slotEffectTypeChanged(int type); + void readUserSettings(); + +private: + + void writeUserSettings(); + void resetValues(); + void prepareEffect(); + void prepareFinal(); + void abortPreview(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + TQComboBox *m_effectType; + + TQLabel *m_effectTypeLabel; + TQLabel *m_distanceLabel; + TQLabel *m_levelLabel; + + KIntNumInput *m_distanceInput; + KIntNumInput *m_levelInput; +}; + +} // NameSpace DigikamBlurFXImagesPlugin + +#endif /* IMAGEEFFECT_BLURFX_H */ diff --git a/src/imageplugins/blurfx/imageplugin_blurfx.cpp b/src/imageplugins/blurfx/imageplugin_blurfx.cpp new file mode 100644 index 00000000..3bbd05e0 --- /dev/null +++ b/src/imageplugins/blurfx/imageplugin_blurfx.cpp @@ -0,0 +1,70 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-09 + * Description : a plugin to apply Blur FX to images + * + * Copyright 2005-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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> +#include <tdeapplication.h> + +// Local includes. + +#include "ddebug.h" +#include "blurfxtool.h" +#include "imageplugin_blurfx.h" +#include "imageplugin_blurfx.moc" + +using namespace DigikamBlurFXImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_blurfx, + KGenericFactory<ImagePlugin_BlurFX>("digikamimageplugin_blurfx")); + +ImagePlugin_BlurFX::ImagePlugin_BlurFX(TQObject *parent, const char*, const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_BlurFX") +{ + m_blurfxAction = new TDEAction(i18n("Blur Effects..."), "blurfx", 0, + this, TQ_SLOT(slotBlurFX()), + actionCollection(), "imageplugin_blurfx"); + + setXMLFile( "digikamimageplugin_blurfx_ui.rc" ); + + DDebug() << "ImagePlugin_BlurFX plugin loaded" << endl; +} + +ImagePlugin_BlurFX::~ImagePlugin_BlurFX() +{ +} + +void ImagePlugin_BlurFX::setEnabledActions(bool enable) +{ + m_blurfxAction->setEnabled(enable); +} + +void ImagePlugin_BlurFX::slotBlurFX() +{ + BlurFXTool *tool = new BlurFXTool(this); + loadTool(tool); +} diff --git a/src/imageplugins/blurfx/imageplugin_blurfx.h b/src/imageplugins/blurfx/imageplugin_blurfx.h new file mode 100644 index 00000000..13df6534 --- /dev/null +++ b/src/imageplugins/blurfx/imageplugin_blurfx.h @@ -0,0 +1,56 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-09 + * Description : a plugin to apply Blur FX to images + * + * Copyright 2005-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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_BLURFX_H +#define IMAGEPLUGIN_BLURFX_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_BlurFX : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_BlurFX(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_BlurFX(); + + void setEnabledActions(bool enable); + +private slots: + + void slotBlurFX(); + +private: + + TDEAction *m_blurfxAction; +}; + +#endif /* IMAGEPLUGIN_BLURFX_H */ diff --git a/src/imageplugins/border/Makefile.am b/src/imageplugins/border/Makefile.am new file mode 100644 index 00000000..385acfab --- /dev/null +++ b/src/imageplugins/border/Makefile.am @@ -0,0 +1,34 @@ +METASOURCES = AUTO +SUBDIRS = patterns + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_border_la_SOURCES = imageplugin_border.cpp \ + bordertool.cpp border.cpp + +digikamimageplugin_border_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_border_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_border.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_border.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_border_ui.rc diff --git a/src/imageplugins/border/border.cpp b/src/imageplugins/border/border.cpp new file mode 100644 index 00000000..00726f58 --- /dev/null +++ b/src/imageplugins/border/border.cpp @@ -0,0 +1,393 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : border threaded image filter. + * + * Copyright 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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> +#include <cstdlib> + +// TQt includes. + +#include <tqpoint.h> +#include <tqregion.h> +#include <tqpointarray.h> + +// Local includes. + +#include "dimg.h" +#include "ddebug.h" +#include "border.h" + +namespace DigikamBorderImagesPlugin +{ + +Border::Border(Digikam::DImg *image, TQObject *parent, int orgWidth, int orgHeight, + TQString borderPath, int borderType, float borderPercent, + Digikam::DColor solidColor, + Digikam::DColor niepceBorderColor, + Digikam::DColor niepceLineColor, + Digikam::DColor bevelUpperLeftColor, + Digikam::DColor bevelLowerRightColor, + Digikam::DColor decorativeFirstColor, + Digikam::DColor decorativeSecondColor) + : Digikam::DImgThreadedFilter(image, parent, "Border") +{ + m_orgWidth = orgWidth; + m_orgHeight = orgHeight; + m_orgRatio = (float)m_orgWidth / (float)m_orgHeight; + m_borderType = borderType; + m_borderPath = borderPath; + int size = (image->width() > image->height()) ? image->height() : image->width(); + m_borderMainWidth = (int)(size * borderPercent); + m_border2ndWidth = (int)(size * 0.005); + + // Clamp internal border with to 1 pixel to be visible with small image. + if (m_border2ndWidth < 1) m_border2ndWidth = 1; + + m_solidColor = solidColor; + m_niepceBorderColor = niepceBorderColor; + m_niepceLineColor = niepceLineColor; + m_bevelUpperLeftColor = bevelUpperLeftColor; + m_bevelLowerRightColor = bevelLowerRightColor; + m_decorativeFirstColor = decorativeFirstColor; + m_decorativeSecondColor = decorativeSecondColor; + + m_preserveAspectRatio = true; + + initFilter(); +} + +Border::Border(Digikam::DImg *orgImage, TQObject *parent, int orgWidth, int orgHeight, + TQString borderPath, int borderType, + int borderWidth1, int borderWidth2, int borderWidth3, int borderWidth4, + Digikam::DColor solidColor, + Digikam::DColor niepceBorderColor, + Digikam::DColor niepceLineColor, + Digikam::DColor bevelUpperLeftColor, + Digikam::DColor bevelLowerRightColor, + Digikam::DColor decorativeFirstColor, + Digikam::DColor decorativeSecondColor) + : Digikam::DImgThreadedFilter(orgImage, parent, "Border") +{ + m_orgWidth = orgWidth; + m_orgHeight = orgHeight; + + m_borderType = borderType; + m_borderWidth1 = borderWidth1; + m_borderWidth2 = borderWidth2; + m_borderWidth3 = borderWidth3; + m_borderWidth4 = borderWidth4; + + m_solidColor = solidColor; + m_niepceBorderColor = niepceBorderColor; + m_niepceLineColor = niepceLineColor; + m_bevelUpperLeftColor = bevelUpperLeftColor; + m_bevelLowerRightColor = bevelLowerRightColor; + m_decorativeFirstColor = decorativeFirstColor; + m_decorativeSecondColor = decorativeSecondColor; + + m_borderPath = borderPath; + + m_preserveAspectRatio = false; + + initFilter(); +} + +void Border::filterImage(void) +{ + switch (m_borderType) + { + case SolidBorder: + if (m_preserveAspectRatio) + solid(m_orgImage, m_destImage, m_solidColor, m_borderMainWidth); + else + solid2(m_orgImage, m_destImage, m_solidColor, m_borderWidth1); + break; + + case NiepceBorder: + if (m_preserveAspectRatio) + niepce(m_orgImage, m_destImage, m_niepceBorderColor, m_borderMainWidth, + m_niepceLineColor, m_border2ndWidth); + else + niepce2(m_orgImage, m_destImage, m_niepceBorderColor, m_borderWidth1, + m_niepceLineColor, m_borderWidth4); + break; + + case BeveledBorder: + if (m_preserveAspectRatio) + bevel(m_orgImage, m_destImage, m_bevelUpperLeftColor, + m_bevelLowerRightColor, m_borderMainWidth); + else + bevel2(m_orgImage, m_destImage, m_bevelUpperLeftColor, + m_bevelLowerRightColor, m_borderWidth1); + break; + + case PineBorder: + case WoodBorder: + case PaperBorder: + case ParqueBorder: + case IceBorder: + case LeafBorder: + case MarbleBorder: + case RainBorder: + case CratersBorder: + case DriedBorder: + case PinkBorder: + case StoneBorder: + case ChalkBorder: + case GraniteBorder: + case RockBorder: + case WallBorder: + if (m_preserveAspectRatio) + pattern(m_orgImage, m_destImage, m_borderMainWidth, + m_decorativeFirstColor, m_decorativeSecondColor, + m_border2ndWidth, m_border2ndWidth); + else + pattern2(m_orgImage, m_destImage, m_borderWidth1, + m_decorativeFirstColor, m_decorativeSecondColor, + m_borderWidth2, m_borderWidth2); + break; + } +} + +// -- Methods to preserve aspect ratio of image ------------------------------------------ + +void Border::solid(Digikam::DImg &src, Digikam::DImg &dest, const Digikam::DColor &fg, int borderWidth) +{ + if (m_orgWidth > m_orgHeight) + { + int height = src.height() + borderWidth*2; + dest = Digikam::DImg((int)(height*m_orgRatio), height, src.sixteenBit(), src.hasAlpha()); + dest.fill(fg); + dest.bitBltImage(&src, (dest.width()-src.width())/2, borderWidth); + } + else + { + int width = src.width() + borderWidth*2; + dest = Digikam::DImg(width, (int)(width/m_orgRatio), src.sixteenBit(), src.hasAlpha()); + dest.fill(fg); + dest.bitBltImage(&src, borderWidth, (dest.height()-src.height())/2); + } +} + +void Border::niepce(Digikam::DImg &src, Digikam::DImg &dest, const Digikam::DColor &fg, + int borderWidth, const Digikam::DColor &bg, int lineWidth) +{ + Digikam::DImg tmp; + solid(src, tmp, bg, lineWidth); + solid(tmp, dest, fg, borderWidth); +} + +void Border::bevel(Digikam::DImg &src, Digikam::DImg &dest, const Digikam::DColor &topColor, + const Digikam::DColor &btmColor, int borderWidth) +{ + int width, height; + + if (m_orgWidth > m_orgHeight) + { + height = src.height() + borderWidth*2; + width = (int)(height*m_orgRatio); + } + else + { + width = src.width() + borderWidth*2; + height = (int)(width/m_orgRatio); + } + + dest = Digikam::DImg(width, height, src.sixteenBit(), src.hasAlpha()); + dest.fill(topColor); + + TQPointArray btTriangle(3); + btTriangle.setPoint(0, width, 0); + btTriangle.setPoint(1, 0, height); + btTriangle.setPoint(2, width, height); + TQRegion btRegion(btTriangle); + + for(int x=0 ; x < width ; x++) + { + for(int y=0 ; y < height ; y++) + { + if (btRegion.contains(TQPoint(x, y))) + dest.setPixelColor(x, y, btmColor); + } + } + + if (m_orgWidth > m_orgHeight) + { + dest.bitBltImage(&src, (dest.width()-src.width())/2, borderWidth); + } + else + { + dest.bitBltImage(&src, borderWidth, (dest.height()-src.height())/2); + } +} + +void Border::pattern(Digikam::DImg &src, Digikam::DImg &dest, int borderWidth, + const Digikam::DColor &firstColor, const Digikam::DColor &secondColor, + int firstWidth, int secondWidth) +{ + // Original image with the first solid border around. + Digikam::DImg tmp; + solid(src, tmp, firstColor, firstWidth); + + // Border tiled image using pattern with second solid border around. + int width, height; + + if (m_orgWidth > m_orgHeight) + { + height = tmp.height() + borderWidth*2; + width = (int)(height*m_orgRatio); + } + else + { + width = tmp.width() + borderWidth*2; + height = (int)(width/m_orgRatio); + } + + Digikam::DImg tmp2(width, height, tmp.sixteenBit(), tmp.hasAlpha()); + DDebug() << "Border File:" << m_borderPath << endl; + Digikam::DImg border(m_borderPath); + if ( border.isNull() ) + return; + + border.convertToDepthOfImage(&tmp2); + + for (int x = 0 ; x < width ; x+=border.width()) + for (int y = 0 ; y < height ; y+=border.height()) + tmp2.bitBltImage(&border, x, y); + + solid(tmp2, dest, secondColor, secondWidth); + + // Merge both images to one. + if (m_orgWidth > m_orgHeight) + { + dest.bitBltImage(&tmp, (dest.width()-tmp.width())/2, borderWidth); + } + else + { + dest.bitBltImage(&tmp, borderWidth, (dest.height()-tmp.height())/2); + } +} + +// -- Methods to not-preserve aspect ratio of image ------------------------------------------ + + +void Border::solid2(Digikam::DImg &src, Digikam::DImg &dest, const Digikam::DColor &fg, int borderWidth) +{ + dest = Digikam::DImg(src.width() + borderWidth*2, src.height() + borderWidth*2, + src.sixteenBit(), src.hasAlpha()); + dest.fill(fg); + dest.bitBltImage(&src, borderWidth, borderWidth); +} + +void Border::niepce2(Digikam::DImg &src, Digikam::DImg &dest, const Digikam::DColor &fg, int borderWidth, + const Digikam::DColor &bg, int lineWidth) +{ + Digikam::DImg tmp; + solid2(src, tmp, bg, lineWidth); + solid2(tmp, dest, fg, borderWidth); +} + +void Border::bevel2(Digikam::DImg &src, Digikam::DImg &dest, const Digikam::DColor &topColor, + const Digikam::DColor &btmColor, int borderWidth) +{ + int x, y; + int wc; + + dest = Digikam::DImg(src.width() + borderWidth*2, + src.height() + borderWidth*2, + src.sixteenBit(), src.hasAlpha()); + + // top + + for(y=0, wc = (int)dest.width()-1; y < borderWidth; ++y, --wc) + { + for(x=0; x < wc; ++x) + dest.setPixelColor(x, y, topColor); + + for(;x < (int)dest.width(); ++x) + dest.setPixelColor(x, y, btmColor); + } + + // left and right + + for(; y < (int)dest.height()-borderWidth; ++y) + { + for(x=0; x < borderWidth; ++x) + dest.setPixelColor(x, y, topColor); + + for(x = (int)dest.width()-1; x > (int)dest.width()-borderWidth-1; --x) + dest.setPixelColor(x, y, btmColor); + } + + // bottom + + for(wc = borderWidth; y < (int)dest.height(); ++y, --wc) + { + for(x=0; x < wc; ++x) + dest.setPixelColor(x, y, topColor); + + for(; x < (int)dest.width(); ++x) + dest.setPixelColor(x, y, btmColor); + } + + dest.bitBltImage(&src, borderWidth, borderWidth); +} + +void Border::pattern2(Digikam::DImg &src, Digikam::DImg &dest, int borderWidth, + const Digikam::DColor &firstColor, const Digikam::DColor &secondColor, + int firstWidth, int secondWidth) +{ + // Border tile. + + int w = m_orgWidth + borderWidth*2; + int h = m_orgHeight + borderWidth*2; + + DDebug() << "Border File:" << m_borderPath << endl; + Digikam::DImg border(m_borderPath); + if ( border.isNull() ) + return; + + Digikam::DImg borderImg(w, h, src.sixteenBit(), src.hasAlpha()); + border.convertToDepthOfImage(&borderImg); + + for (int x = 0 ; x < w ; x+=border.width()) + for (int y = 0 ; y < h ; y+=border.height()) + borderImg.bitBltImage(&border, x, y); + + // First line around the pattern tile. + Digikam::DImg tmp = borderImg.smoothScale(src.width() + borderWidth*2, + src.height() + borderWidth*2 ); + + solid2(tmp, dest, firstColor, firstWidth); + + // Second line around original image. + tmp.reset(); + solid2(src, tmp, secondColor, secondWidth); + + // Copy original image. + dest.bitBltImage(&tmp, borderWidth, borderWidth); +} + +} // NameSpace DigikamBorderImagesPlugin diff --git a/src/imageplugins/border/border.h b/src/imageplugins/border/border.h new file mode 100644 index 00000000..b213e27a --- /dev/null +++ b/src/imageplugins/border/border.h @@ -0,0 +1,151 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : border threaded image filter. + * + * Copyright 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef BORDER_H +#define BORDER_H + +// TQt includes. + +#include <tqstring.h> +#include <tqcolor.h> +#include <tqimage.h> + +// Digikam includes. + +#include "dimgthreadedfilter.h" + +namespace DigikamBorderImagesPlugin +{ + +class Border : public Digikam::DImgThreadedFilter +{ + +public: + + enum BorderTypes + { + SolidBorder=0, + NiepceBorder, + BeveledBorder, + PineBorder, + WoodBorder, + PaperBorder, + ParqueBorder, + IceBorder, + LeafBorder, + MarbleBorder, + RainBorder, + CratersBorder, + DriedBorder, + PinkBorder, + StoneBorder, + ChalkBorder, + GraniteBorder, + RockBorder, + WallBorder + }; + +public: + + /** Constructor using settings to preserve aspect ratio of image. */ + Border(Digikam::DImg *orgImage, TQObject *parent=0, int orgWidth=0, int orgHeight=0, + TQString borderPath=TQString(), int borderType=SolidBorder, float borderPercent=0.1, + Digikam::DColor solidColor = Digikam::DColor(), + Digikam::DColor niepceBorderColor = Digikam::DColor(), + Digikam::DColor niepceLineColor = Digikam::DColor(), + Digikam::DColor bevelUpperLeftColor = Digikam::DColor(), + Digikam::DColor bevelLowerRightColor = Digikam::DColor(), + Digikam::DColor decorativeFirstColor = Digikam::DColor(), + Digikam::DColor decorativeSecondColor = Digikam::DColor()); + + /** Constructor using settings to not-preserve aspect ratio of image. */ + Border(Digikam::DImg *orgImage, TQObject *parent=0, int orgWidth=0, int orgHeight=0, + TQString borderPath=TQString(), int borderType=SolidBorder, + int borderWidth1=100, int borderWidth2=20, int borderWidth3=20, int borderWidth4=10, + Digikam::DColor solidColor = Digikam::DColor(), + Digikam::DColor niepceBorderColor = Digikam::DColor(), + Digikam::DColor niepceLineColor = Digikam::DColor(), + Digikam::DColor bevelUpperLeftColor = Digikam::DColor(), + Digikam::DColor bevelLowerRightColor = Digikam::DColor(), + Digikam::DColor decorativeFirstColor = Digikam::DColor(), + Digikam::DColor decorativeSecondColor = Digikam::DColor()); + + ~Border(){}; + +private: + + virtual void filterImage(void); + + + /** Methods to preserve aspect ratio of image. */ + void solid(Digikam::DImg &src, Digikam::DImg &dest, const Digikam::DColor &fg, int borderWidth); + void niepce(Digikam::DImg &src, Digikam::DImg &dest, const Digikam::DColor &fg, int borderWidth, + const Digikam::DColor &bg, int lineWidth); + void bevel(Digikam::DImg &src, Digikam::DImg &dest, const Digikam::DColor &topColor, + const Digikam::DColor &btmColor, int borderWidth); + void pattern(Digikam::DImg &src, Digikam::DImg &dest, int borderWidth, const Digikam::DColor &firstColor, + const Digikam::DColor &secondColor, int firstWidth, int secondWidth); + + /** Methods to not-preserve aspect ratio of image. */ + void solid2(Digikam::DImg &src, Digikam::DImg &dest, const Digikam::DColor &fg, int borderWidth); + void niepce2(Digikam::DImg &src, Digikam::DImg &dest, const Digikam::DColor &fg, int borderWidth, + const Digikam::DColor &bg, int lineWidth); + void bevel2(Digikam::DImg &src, Digikam::DImg &dest, const Digikam::DColor &topColor, + const Digikam::DColor &btmColor, int borderWidth); + void pattern2(Digikam::DImg &src, Digikam::DImg &dest, int borderWidth, const Digikam::DColor &firstColor, + const Digikam::DColor &secondColor, int firstWidth, int secondWidth); + +private: + + bool m_preserveAspectRatio; + + int m_orgWidth; + int m_orgHeight; + + int m_borderType; + + int m_borderWidth1; + int m_borderWidth2; + int m_borderWidth3; + int m_borderWidth4; + + int m_borderMainWidth; + int m_border2ndWidth; + + float m_orgRatio; + + TQString m_borderPath; + + Digikam::DColor m_solidColor; + Digikam::DColor m_niepceBorderColor; + Digikam::DColor m_niepceLineColor; + Digikam::DColor m_bevelUpperLeftColor; + Digikam::DColor m_bevelLowerRightColor; + Digikam::DColor m_decorativeFirstColor; + Digikam::DColor m_decorativeSecondColor; +}; + +} // NameSpace DigikamBorderImagesPlugin + +#endif /* BORDER_H */ diff --git a/src/imageplugins/border/bordertool.cpp b/src/imageplugins/border/bordertool.cpp new file mode 100644 index 00000000..160f5b0a --- /dev/null +++ b/src/imageplugins/border/bordertool.cpp @@ -0,0 +1,668 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-20 + * Description : a digiKam image plugin to add a border + * around an image. + * + * Copyright 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <tqcheckbox.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <kcolorbutton.h> +#include <tdeconfig.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <kseparator.h> +#include <kstandarddirs.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> +#include <libkdcraw/rcombobox.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "editortoolsettings.h" +#include "border.h" +#include "bordertool.h" +#include "bordertool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamBorderImagesPlugin +{ + +BorderTool::BorderTool(TQObject* parent) + : EditorToolThreaded(parent) +{ + setName("border"); + setToolName(i18n("Add Border")); + setToolIcon(SmallIcon("bordertool")); + + m_previewWidget = new ImageWidget("bordertool Tool", 0, TQString(), + false, ImageGuideWidget::HVGuideMode, false); + + setToolView(m_previewWidget); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel); + TQGridLayout* grid = new TQGridLayout(m_gboxSettings->plainPage(), 11, 2); + + TQLabel *label1 = new TQLabel(i18n("Type:"), m_gboxSettings->plainPage()); + + m_borderType = new RComboBox(m_gboxSettings->plainPage()); + m_borderType->insertItem( i18n("Solid") ); + // Niepce is Real name. This is the first guy in the world to have built a camera. + m_borderType->insertItem( "Niepce" ); + m_borderType->insertItem( i18n("Beveled") ); + m_borderType->insertItem( i18n("Decorative Pine") ); + m_borderType->insertItem( i18n("Decorative Wood") ); + m_borderType->insertItem( i18n("Decorative Paper") ); + m_borderType->insertItem( i18n("Decorative Parquet") ); + m_borderType->insertItem( i18n("Decorative Ice") ); + m_borderType->insertItem( i18n("Decorative Leaf") ); + m_borderType->insertItem( i18n("Decorative Marble") ); + m_borderType->insertItem( i18n("Decorative Rain") ); + m_borderType->insertItem( i18n("Decorative Craters") ); + m_borderType->insertItem( i18n("Decorative Dried") ); + m_borderType->insertItem( i18n("Decorative Pink") ); + m_borderType->insertItem( i18n("Decorative Stone") ); + m_borderType->insertItem( i18n("Decorative Chalk") ); + m_borderType->insertItem( i18n("Decorative Granite") ); + m_borderType->insertItem( i18n("Decorative Rock") ); + m_borderType->insertItem( i18n("Decorative Wall") ); + m_borderType->setDefaultItem(Border::SolidBorder); + TQWhatsThis::add( m_borderType, i18n("<p>Select the border type to add around the image.")); + + KSeparator *line1 = new KSeparator(Horizontal, m_gboxSettings->plainPage()); + + // ------------------------------------------------------------------- + + m_preserveAspectRatio = new TQCheckBox(m_gboxSettings->plainPage()); + m_preserveAspectRatio->setText(i18n("Preserve Aspect Ratio")); + TQWhatsThis::add(m_preserveAspectRatio, i18n("Enable this option if you want to preserve the aspect " + "ratio of the image. If enabled, the border width will be " + "in percent of the image size, else the border width will " + "in pixels.")); + + m_labelBorderPercent = new TQLabel(i18n("Width (%):"), m_gboxSettings->plainPage()); + m_borderPercent = new RIntNumInput(m_gboxSettings->plainPage()); + m_borderPercent->setRange(1, 50, 1); + m_borderPercent->setDefaultValue(10); + TQWhatsThis::add(m_borderPercent, i18n("<p>Set here the border width in percent of the image size.")); + + m_labelBorderWidth = new TQLabel(i18n("Width (pixels):"), m_gboxSettings->plainPage()); + m_borderWidth = new RIntNumInput(m_gboxSettings->plainPage()); + m_borderWidth->setDefaultValue(100); + TQWhatsThis::add(m_borderWidth, i18n("<p>Set here the border width in pixels to add around the image.")); + + ImageIface iface(0, 0); + int w = iface.originalWidth(); + int h = iface.originalHeight(); + + if (w > h) + m_borderWidth->setRange(1, h/2, 1); + else + m_borderWidth->setRange(1, w/2, 1); + + KSeparator *line2 = new KSeparator(Horizontal, m_gboxSettings->plainPage()); + + // ------------------------------------------------------------------- + + m_labelForeground = new TQLabel(m_gboxSettings->plainPage()); + m_firstColorButton = new KColorButton( TQColor( 192, 192, 192 ), m_gboxSettings->plainPage() ); + m_labelBackground = new TQLabel(m_gboxSettings->plainPage()); + m_secondColorButton = new KColorButton( TQColor( 128, 128, 128 ), m_gboxSettings->plainPage() ); + + // ------------------------------------------------------------------- + + grid->addMultiCellWidget(label1, 0, 0, 0, 2); + grid->addMultiCellWidget(m_borderType, 1, 1, 0, 2); + grid->addMultiCellWidget(line1, 2, 2, 0, 2); + grid->addMultiCellWidget(m_preserveAspectRatio, 3, 3, 0, 2); + grid->addMultiCellWidget(m_labelBorderPercent, 4, 4, 0, 2); + grid->addMultiCellWidget(m_borderPercent, 5, 5, 0, 2); + grid->addMultiCellWidget(m_labelBorderWidth, 6, 6, 0, 2); + grid->addMultiCellWidget(m_borderWidth, 7, 7, 0, 2); + grid->addMultiCellWidget(line2, 8, 8, 0, 2); + grid->addMultiCellWidget(m_labelForeground, 9, 9, 0, 0); + grid->addMultiCellWidget(m_firstColorButton, 9, 9, 1, 2); + grid->addMultiCellWidget(m_labelBackground, 10, 10, 0, 0); + grid->addMultiCellWidget(m_secondColorButton, 10, 10, 1, 2); + grid->setRowStretch(11, 10); + grid->setMargin(m_gboxSettings->spacingHint()); + grid->setSpacing(m_gboxSettings->spacingHint()); + + setToolSettings(m_gboxSettings); + init(); + + // ------------------------------------------------------------- + + connect(m_preserveAspectRatio, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotPreserveAspectRatioToggled(bool))); + + connect(m_borderType, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotBorderTypeChanged(int))); + + connect(m_borderPercent, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_borderWidth, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_firstColorButton, TQ_SIGNAL(changed(const TQColor &)), + this, TQ_SLOT(slotColorForegroundChanged(const TQColor &))); + + connect(m_secondColorButton, TQ_SIGNAL(changed(const TQColor &)), + this, TQ_SLOT(slotColorBackgroundChanged(const TQColor &))); +} + +BorderTool::~BorderTool() +{ +} + +void BorderTool::readSettings() +{ + m_borderType->blockSignals(true); + m_borderPercent->blockSignals(true); + m_borderWidth->blockSignals(true); + m_firstColorButton->blockSignals(true); + m_secondColorButton->blockSignals(true); + m_preserveAspectRatio->blockSignals(true); + + TDEConfig *config = kapp->config(); + config->setGroup("border Tool"); + + m_borderType->setCurrentItem(config->readNumEntry("Border Type", m_borderType->defaultItem())); + m_borderPercent->setValue(config->readNumEntry("Border Percent", m_borderPercent->defaultValue())); + m_borderWidth->setValue(config->readNumEntry("Border Width", m_borderWidth->defaultValue())); + m_preserveAspectRatio->setChecked(config->readBoolEntry("Preserve Aspect Ratio", true)); + + TQColor black(0, 0, 0); + TQColor white(255, 255, 255); + TQColor gray1(192, 192, 192); + TQColor gray2(128, 128, 128); + + m_solidColor = config->readColorEntry("Solid Color", &black); + m_niepceBorderColor = config->readColorEntry("Niepce Border Color", &white); + m_niepceLineColor = config->readColorEntry("Niepce Line Color", &black); + m_bevelUpperLeftColor = config->readColorEntry("Bevel Upper Left Color", &gray1); + m_bevelLowerRightColor = config->readColorEntry("Bevel Lower Right Color", &gray2); + m_decorativeFirstColor = config->readColorEntry("Decorative First Color", &black); + m_decorativeSecondColor = config->readColorEntry("Decorative Second Color", &black); + + m_borderType->blockSignals(false); + m_borderPercent->blockSignals(false); + m_borderWidth->blockSignals(false); + m_firstColorButton->blockSignals(false); + m_secondColorButton->blockSignals(false); + m_preserveAspectRatio->blockSignals(false); + + slotBorderTypeChanged(m_borderType->currentItem()); +} + +void BorderTool::writeSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("border Tool"); + + config->writeEntry("Border Type", m_borderType->currentItem()); + config->writeEntry("Border Percent", m_borderPercent->value()); + config->writeEntry("Border Width", m_borderWidth->value()); + config->writeEntry("Preserve Aspect Ratio", m_preserveAspectRatio->isChecked()); + + config->writeEntry("Solid Color", m_solidColor); + config->writeEntry("Niepce Border Color", m_niepceBorderColor); + config->writeEntry("Niepce Line Color", m_niepceLineColor); + config->writeEntry("Bevel Upper Left Color", m_bevelUpperLeftColor); + config->writeEntry("Bevel Lower Right Color", m_bevelLowerRightColor); + config->writeEntry("Decorative First Color", m_decorativeFirstColor); + config->writeEntry("Decorative Second Color", m_decorativeSecondColor); + + m_previewWidget->writeSettings(); + + config->sync(); +} + +void BorderTool::slotResetSettings() +{ + m_borderType->blockSignals(true); + m_borderPercent->blockSignals(true); + m_borderWidth->blockSignals(true); + m_firstColorButton->blockSignals(true); + m_secondColorButton->blockSignals(true); + m_preserveAspectRatio->blockSignals(true); + + m_borderType->slotReset(); + m_borderPercent->slotReset(); + m_borderWidth->slotReset(); + m_preserveAspectRatio->setChecked(true); + + m_solidColor = TQColor(0, 0, 0); + m_niepceBorderColor = TQColor(255, 255, 255); + m_niepceLineColor = TQColor(0, 0, 0); + m_bevelUpperLeftColor = TQColor(192, 192, 192); + m_bevelLowerRightColor = TQColor(128, 128, 128); + m_decorativeFirstColor = TQColor(0, 0, 0); + m_decorativeSecondColor = TQColor(0, 0, 0); + + m_borderType->blockSignals(false); + m_borderPercent->blockSignals(false); + m_borderWidth->blockSignals(false); + m_firstColorButton->blockSignals(false); + m_secondColorButton->blockSignals(false); + m_preserveAspectRatio->blockSignals(false); + + slotBorderTypeChanged(Border::SolidBorder); +} + +void BorderTool::renderingFinished() +{ + m_preserveAspectRatio->setEnabled(true); + m_borderType->setEnabled(true); + m_borderPercent->setEnabled(true); + m_borderWidth->setEnabled(true); + m_firstColorButton->setEnabled(true); + m_secondColorButton->setEnabled(true); + toggleBorderSlider(m_preserveAspectRatio->isChecked()); +} + +void BorderTool::slotColorForegroundChanged(const TQColor &color) +{ + switch (m_borderType->currentItem()) + { + case Border::SolidBorder: + m_solidColor = color; + break; + + case Border::NiepceBorder: + m_niepceBorderColor = color; + break; + + case Border::BeveledBorder: + m_bevelUpperLeftColor = color; + break; + + case Border::PineBorder: + case Border::WoodBorder: + case Border::PaperBorder: + case Border::ParqueBorder: + case Border::IceBorder: + case Border::LeafBorder: + case Border::MarbleBorder: + case Border::RainBorder: + case Border::CratersBorder: + case Border::DriedBorder: + case Border::PinkBorder: + case Border::StoneBorder: + case Border::ChalkBorder: + case Border::GraniteBorder: + case Border::RockBorder: + case Border::WallBorder: + m_decorativeFirstColor = color; + break; + } + + slotEffect(); +} + +void BorderTool::slotColorBackgroundChanged(const TQColor &color) +{ + switch (m_borderType->currentItem()) + { + case Border::SolidBorder: + m_solidColor = color; + break; + + case Border::NiepceBorder: + m_niepceLineColor = color; + break; + + case Border::BeveledBorder: + m_bevelLowerRightColor = color; + break; + + case Border::PineBorder: + case Border::WoodBorder: + case Border::PaperBorder: + case Border::ParqueBorder: + case Border::IceBorder: + case Border::LeafBorder: + case Border::MarbleBorder: + case Border::RainBorder: + case Border::CratersBorder: + case Border::DriedBorder: + case Border::PinkBorder: + case Border::StoneBorder: + case Border::ChalkBorder: + case Border::GraniteBorder: + case Border::RockBorder: + case Border::WallBorder: + m_decorativeSecondColor = color; + break; + } + + slotEffect(); +} + +void BorderTool::slotBorderTypeChanged(int borderType) +{ + m_labelForeground->setText(i18n("First:")); + m_labelBackground->setText(i18n("Second:")); + TQWhatsThis::add( m_firstColorButton, i18n("<p>Set here the foreground color of the border.")); + TQWhatsThis::add( m_secondColorButton, i18n("<p>Set here the Background color of the border.")); + m_firstColorButton->setEnabled(true); + m_secondColorButton->setEnabled(true); + m_labelForeground->setEnabled(true); + m_labelBackground->setEnabled(true); + m_borderPercent->setEnabled(true); + + switch (borderType) + { + case Border::SolidBorder: + m_firstColorButton->setColor( m_solidColor ); + m_secondColorButton->setEnabled(false); + m_labelBackground->setEnabled(false); + break; + + case Border::NiepceBorder: + TQWhatsThis::add( m_firstColorButton, i18n("<p>Set here the color of the main border.")); + TQWhatsThis::add( m_secondColorButton, i18n("<p>Set here the color of the line.")); + m_firstColorButton->setColor( m_niepceBorderColor ); + m_secondColorButton->setColor( m_niepceLineColor ); + break; + + case Border::BeveledBorder: + TQWhatsThis::add( m_firstColorButton, i18n("<p>Set here the color of the upper left area.")); + TQWhatsThis::add( m_secondColorButton, i18n("<p>Set here the color of the lower right area.")); + m_firstColorButton->setColor( m_bevelUpperLeftColor ); + m_secondColorButton->setColor( m_bevelLowerRightColor ); + break; + + case Border::PineBorder: + case Border::WoodBorder: + case Border::PaperBorder: + case Border::ParqueBorder: + case Border::IceBorder: + case Border::LeafBorder: + case Border::MarbleBorder: + case Border::RainBorder: + case Border::CratersBorder: + case Border::DriedBorder: + case Border::PinkBorder: + case Border::StoneBorder: + case Border::ChalkBorder: + case Border::GraniteBorder: + case Border::RockBorder: + case Border::WallBorder: + TQWhatsThis::add( m_firstColorButton, i18n("<p>Set here the color of the first line.")); + TQWhatsThis::add( m_secondColorButton, i18n("<p>Set here the color of the second line.")); + m_firstColorButton->setColor( m_decorativeFirstColor ); + m_secondColorButton->setColor( m_decorativeSecondColor ); + break; + } + + slotEffect(); +} + +void BorderTool::prepareEffect() +{ + m_borderType->setEnabled(false); + m_borderPercent->setEnabled(false); + m_borderWidth->setEnabled(false); + m_firstColorButton->setEnabled(false); + m_secondColorButton->setEnabled(false); + m_preserveAspectRatio->setEnabled(false); + + ImageIface* iface = m_previewWidget->imageIface(); + int orgWidth = iface->originalWidth(); + int orgHeight = iface->originalHeight(); + int w = iface->previewWidth(); + int h = iface->previewHeight(); + bool sixteenBit = iface->previewSixteenBit(); + uchar *data = iface->getPreviewImage(); + DImg previewImage(w, h, sixteenBit, + iface->previewHasAlpha(), data); + delete [] data; + + int borderType = m_borderType->currentItem(); + float ratio = (float)w/(float)orgWidth; + int borderWidth = (int)((float)m_borderWidth->value()*ratio); + TQString border = getBorderPath( m_borderType->currentItem() ); + + if (m_preserveAspectRatio->isChecked()) + { + setFilter(dynamic_cast<DImgThreadedFilter*>( + new Border(&previewImage, this, orgWidth, orgHeight, + border, borderType, m_borderPercent->value()/100.0, + DColor(m_solidColor, sixteenBit), + DColor(m_niepceBorderColor, sixteenBit), + DColor(m_niepceLineColor, sixteenBit), + DColor(m_bevelUpperLeftColor, sixteenBit), + DColor(m_bevelLowerRightColor, sixteenBit), + DColor(m_decorativeFirstColor, sixteenBit), + DColor(m_decorativeSecondColor, sixteenBit)))); + } + else + { + setFilter(dynamic_cast<DImgThreadedFilter*>( + new Border(&previewImage, this, orgWidth, orgHeight, + border, borderType, borderWidth, + (int)(20.0*ratio), (int)(20.0*ratio), 3, + DColor(m_solidColor, sixteenBit), + DColor(m_niepceBorderColor, sixteenBit), + DColor(m_niepceLineColor, sixteenBit), + DColor(m_bevelUpperLeftColor, sixteenBit), + DColor(m_bevelLowerRightColor, sixteenBit), + DColor(m_decorativeFirstColor, sixteenBit), + DColor(m_decorativeSecondColor, sixteenBit)))); + } +} + +void BorderTool::prepareFinal() +{ + m_borderType->setEnabled(false); + m_borderPercent->setEnabled(false); + m_borderWidth->setEnabled(false); + m_firstColorButton->setEnabled(false); + m_secondColorButton->setEnabled(false); + + int borderType = m_borderType->currentItem(); + int borderWidth = m_borderWidth->value(); + float borderRatio = m_borderPercent->value()/100.0; + TQString border = getBorderPath( m_borderType->currentItem() ); + + ImageIface iface(0, 0); + int orgWidth = iface.originalWidth(); + int orgHeight = iface.originalHeight(); + bool sixteenBit = iface.previewSixteenBit(); + uchar *data = iface.getOriginalImage(); + DImg orgImage(orgWidth, orgHeight, sixteenBit, + iface.originalHasAlpha(), data); + delete [] data; + + if (m_preserveAspectRatio->isChecked()) + { + setFilter(dynamic_cast<DImgThreadedFilter*>( + new Border(&orgImage, this, orgWidth, orgHeight, + border, borderType, borderRatio, + DColor(m_solidColor, sixteenBit), + DColor(m_niepceBorderColor, sixteenBit), + DColor(m_niepceLineColor, sixteenBit), + DColor(m_bevelUpperLeftColor, sixteenBit), + DColor(m_bevelLowerRightColor, sixteenBit), + DColor(m_decorativeFirstColor, sixteenBit), + DColor(m_decorativeSecondColor, sixteenBit)))); + } + else + { + setFilter(dynamic_cast<DImgThreadedFilter*>( + new Border(&orgImage, this, orgWidth, orgHeight, + border, borderType, borderWidth, 15, 15, 10, + DColor(m_solidColor, sixteenBit), + DColor(m_niepceBorderColor, sixteenBit), + DColor(m_niepceLineColor, sixteenBit), + DColor(m_bevelUpperLeftColor, sixteenBit), + DColor(m_bevelLowerRightColor, sixteenBit), + DColor(m_decorativeFirstColor, sixteenBit), + DColor(m_decorativeSecondColor, sixteenBit)))); + } +} + +void BorderTool::putPreviewData() +{ + ImageIface* iface = m_previewWidget->imageIface(); + int w = iface->previewWidth(); + int h = iface->previewHeight(); + + DImg imTemp = filter()->getTargetImage().smoothScale(w, h, TQSize::ScaleMin); + DImg imDest( w, h, filter()->getTargetImage().sixteenBit(), + filter()->getTargetImage().hasAlpha() ); + + imDest.fill( DColor(m_previewWidget->paletteBackgroundColor().rgb(), + filter()->getTargetImage().sixteenBit()) ); + + imDest.bitBltImage(&imTemp, (w-imTemp.width())/2, (h-imTemp.height())/2); + + iface->putPreviewImage(imDest.bits()); + m_previewWidget->updatePreview(); +} + +void BorderTool::putFinalData() +{ + ImageIface iface(0, 0); + + DImg targetImage = filter()->getTargetImage(); + iface.putOriginalImage(i18n("Add Border"), + targetImage.bits(), + targetImage.width(), targetImage.height()); +} + +TQString BorderTool::getBorderPath(int border) +{ + TQString pattern; + + switch (border) + { + case Border::PineBorder: + pattern = "pine-pattern"; + break; + + case Border::WoodBorder: + pattern = "wood-pattern"; + break; + + case Border::PaperBorder: + pattern = "paper-pattern"; + break; + + case Border::ParqueBorder: + pattern = "parque-pattern"; + break; + + case Border::IceBorder: + pattern = "ice-pattern"; + break; + + case Border::LeafBorder: + pattern = "leaf-pattern"; + break; + + case Border::MarbleBorder: + pattern = "marble-pattern"; + break; + + case Border::RainBorder: + pattern = "rain-pattern"; + break; + + case Border::CratersBorder: + pattern = "craters-pattern"; + break; + + case Border::DriedBorder: + pattern = "dried-pattern"; + break; + + case Border::PinkBorder: + pattern = "pink-pattern"; + break; + + case Border::StoneBorder: + pattern = "stone-pattern"; + break; + + case Border::ChalkBorder: + pattern = "chalk-pattern"; + break; + + case Border::GraniteBorder: + pattern = "granit-pattern"; + break; + + case Border::RockBorder: + pattern = "rock-pattern"; + break; + + case Border::WallBorder: + pattern = "wall-pattern"; + break; + + default: + return TQString(); + } + + TDEGlobal::dirs()->addResourceType(pattern.ascii(), TDEGlobal::dirs()->kde_default("data") + + "digikam/data"); + return (TDEGlobal::dirs()->findResourceDir(pattern.ascii(), pattern + ".png") + pattern + ".png" ); +} + +void BorderTool::slotPreserveAspectRatioToggled(bool b) +{ + toggleBorderSlider(b); + slotTimer(); +} + +void BorderTool::toggleBorderSlider(bool b) +{ + m_borderPercent->setEnabled(b); + m_borderWidth->setEnabled(!b); + m_labelBorderPercent->setEnabled(b); + m_labelBorderWidth->setEnabled(!b); +} + +} // NameSpace DigikamBorderImagesPlugin diff --git a/src/imageplugins/border/bordertool.h b/src/imageplugins/border/bordertool.h new file mode 100644 index 00000000..a8ec5ccf --- /dev/null +++ b/src/imageplugins/border/bordertool.h @@ -0,0 +1,123 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-20 + * Description : a digiKam image plugin to add a border + * around an image. + * + * Copyright 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef BORDERTOOL_H +#define BORDERTOOL_H + +// TQt includes. + +#include <tqstring.h> + +// Digikam includes. + +#include "editortool.h" + +class TQLabel; +class TQCheckBox; +class TQColor; + +class KColorButton; + +namespace KDcrawIface +{ +class RIntNumInput; +class RComboBox; +} + +namespace Digikam +{ +class EditorToolSettings; +class ImageWidget; +} + +namespace DigikamBorderImagesPlugin +{ + +class BorderTool : public Digikam::EditorToolThreaded +{ + TQ_OBJECT + + +public: + + BorderTool(TQObject *parent); + ~BorderTool(); + +private: + + TQString getBorderPath(int border); + +private slots: + + void slotPreserveAspectRatioToggled(bool); + void slotBorderTypeChanged(int borderType); + void slotColorForegroundChanged(const TQColor &color); + void slotColorBackgroundChanged(const TQColor &color); + void slotResetSettings(); + +private: + + void writeSettings(); + void readSettings(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + void toggleBorderSlider(bool b); + +private: + + TQLabel *m_labelBorderPercent; + TQLabel *m_labelBorderWidth; + TQLabel *m_labelForeground; + TQLabel *m_labelBackground; + + TQCheckBox *m_preserveAspectRatio; + + TQColor m_solidColor; + TQColor m_niepceBorderColor; + TQColor m_niepceLineColor; + TQColor m_bevelUpperLeftColor; + TQColor m_bevelLowerRightColor; + TQColor m_decorativeFirstColor; + TQColor m_decorativeSecondColor; + + KDcrawIface::RComboBox *m_borderType; + + KDcrawIface::RIntNumInput *m_borderPercent; + KDcrawIface::RIntNumInput *m_borderWidth; + + KColorButton *m_firstColorButton; + KColorButton *m_secondColorButton; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamBorderImagesPlugin + +#endif /* BORDERTOOL_H */ diff --git a/src/imageplugins/border/digikamimageplugin_border.desktop b/src/imageplugins/border/digikamimageplugin_border.desktop new file mode 100644 index 00000000..45f32a7e --- /dev/null +++ b/src/imageplugins/border/digikamimageplugin_border.desktop @@ -0,0 +1,50 @@ +[Desktop Entry] +Name=ImagePlugin_Border +Name[bg]=Приставка за снимки - �амки +Name[da]=Billedplugin_Indramning +Name[el]=ΠρόσθετοΕικόνας_Περίγραμμα +Name[fi]=Reunus +Name[hr]=Obrub +Name[it]=PluginImmagini_Bordo +Name[nl]=Afbeeldingsplugin_Rand +Name[sr]=Оквир +Name[sr@Latn]=Okvir +Name[sv]=Insticksprogram för bildkanter +Name[tr]=ResimEklentisi_Çerçeve +Name[xx]=xxImagePlugin_Borderxx +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=Add border to image plugin for digiKam +Comment[bg]=Приставка на digiKam за добавяне на рамки на снимки +Comment[ca]=Connector pel digiKam per afegir una vora a la imatge +Comment[da]=Plugin til indramning af billeder i Digikam +Comment[de]=digiKam-Modul zum Hinzufügen eines Rahmens zu einem Bild +Comment[el]=Πρόσθετο προσθήκης περιγράμματος σε εικόνα για το digiKam +Comment[es]=Plugin de digiKam para añadir bordes a la imagen +Comment[et]=DigiKami pildile raami lisamise plugin +Comment[fa]=افزودن لبه به وصلۀ تصویر برای digiKam +Comment[fi]=Lisää kuvaan reunuksen +Comment[gl]=Un plugin de digiKam para engadir un contorno á imaxe +Comment[hr]=digiKam dodatak za dodavanje obruba +Comment[is]=Íforrit fyrir digiKam sem gerir ramma á myndir +Comment[it]=Plugin per l'aggiunta di bordi a un'immagire per digiKam +Comment[ja]=digikam 画像装飾プラグイン +Comment[nds]=digiKam-Moduul för't Tofögen vun Ränners rund en Bild +Comment[nl]=Digikam-plugin voor het toevoegen van randen +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਹਾਸ਼ੀਆ ਜੋੜਨ ਲਈ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam dodająca ramkę do obrazu +Comment[pt]=Um 'plugin' do digiKam para adicionar um contorno à imagem +Comment[pt_BR]=Plugin de adicionar borda na imagem +Comment[ru]=Модуль digiKam наложения рамки на изображение +Comment[sk]=digiKam plugin pridávajúci okraj obrázku +Comment[sr]=Прикључак за digiKam који додаје оквир на слику +Comment[sr@Latn]=Priključak za digiKam koji dodaje okvir na sliku +Comment[sv]=Digikam insticksprogram för tillägg av kanter +Comment[tr]=digiKam için resme çerçeve eklenme eklentisi +Comment[uk]=Втулок digiKam для додавання рамки навколо зображення +Comment[vi]=Phần bổ sung thêm viền trên ảnh cho digiKam +Comment[xx]=xxAdd border to image plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_border +author=Gilles Caulier, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/border/digikamimageplugin_border_ui.rc b/src/imageplugins/border/digikamimageplugin_border_ui.rc new file mode 100644 index 00000000..8cce0581 --- /dev/null +++ b/src/imageplugins/border/digikamimageplugin_border_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="6" name="digikamimageplugin_border" > + + <MenuBar> + + <Menu name="Decorate" ><text>&Decorate</text> + <Action name="imageplugin_border" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action name="imageplugin_border" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/border/imageeffect_border.cpp b/src/imageplugins/border/imageeffect_border.cpp new file mode 100644 index 00000000..9f3dd6c3 --- /dev/null +++ b/src/imageplugins/border/imageeffect_border.cpp @@ -0,0 +1,667 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-20 + * Description : a digiKam image plugin to add a border + * around an image. + * + * Copyright 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <tqlabel.h> +#include <tqwhatsthis.h> +#include <tqlayout.h> +#include <tqcombobox.h> +#include <tqcheckbox.h> + +// KDE includes. + +#include <kseparator.h> +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <kstandarddirs.h> +#include <tdeconfig.h> +#include <knuminput.h> +#include <kcolorbutton.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "border.h" +#include "imageeffect_border.h" +#include "imageeffect_border.moc" + +namespace DigikamBorderImagesPlugin +{ + +ImageEffect_Border::ImageEffect_Border(TQWidget* parent) + : Digikam::ImageGuideDlg(parent, i18n("Add Border Around Photograph"), + "border", false, false, false, + Digikam::ImageGuideWidget::HVGuideMode) +{ + // No need Abort button action. + showButton(User1, false); + + TQString whatsThis; + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Add Border"), + digikam_version, + I18N_NOOP("A digiKam image plugin to add a border around an image."), + TDEAboutData::License_GPL, + "(c) 2005, Gilles Caulier\n" + "(c) 2006-2008, Gilles Caulier and Marcel Wiesweg", + 0, + "http://www.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + about->addAuthor("Marcel Wiesweg", I18N_NOOP("Developer"), + "marcel dot wiesweg at gmx dot de"); + + setAboutData(about); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(plainPage()); + TQGridLayout* gridSettings = new TQGridLayout(gboxSettings, 10, 2, spacingHint()); + + TQLabel *label1 = new TQLabel(i18n("Type:"), gboxSettings); + + m_borderType = new TQComboBox( false, gboxSettings ); + m_borderType->insertItem( i18n("Solid") ); + // Niepce is Real name. This is the first guy in the world to have built a camera. + m_borderType->insertItem( "Niepce" ); + m_borderType->insertItem( i18n("Beveled") ); + m_borderType->insertItem( i18n("Decorative Pine") ); + m_borderType->insertItem( i18n("Decorative Wood") ); + m_borderType->insertItem( i18n("Decorative Paper") ); + m_borderType->insertItem( i18n("Decorative Parquet") ); + m_borderType->insertItem( i18n("Decorative Ice") ); + m_borderType->insertItem( i18n("Decorative Leaf") ); + m_borderType->insertItem( i18n("Decorative Marble") ); + m_borderType->insertItem( i18n("Decorative Rain") ); + m_borderType->insertItem( i18n("Decorative Craters") ); + m_borderType->insertItem( i18n("Decorative Dried") ); + m_borderType->insertItem( i18n("Decorative Pink") ); + m_borderType->insertItem( i18n("Decorative Stone") ); + m_borderType->insertItem( i18n("Decorative Chalk") ); + m_borderType->insertItem( i18n("Decorative Granite") ); + m_borderType->insertItem( i18n("Decorative Rock") ); + m_borderType->insertItem( i18n("Decorative Wall") ); + TQWhatsThis::add( m_borderType, i18n("<p>Select the border type to add around the image.")); + + KSeparator *line1 = new KSeparator(Horizontal, gboxSettings); + + // ------------------------------------------------------------------- + + m_preserveAspectRatio = new TQCheckBox(gboxSettings); + m_preserveAspectRatio->setText(i18n("Preserve Aspect Ratio")); + TQWhatsThis::add(m_preserveAspectRatio, i18n("Enable this option if you want to preserve the aspect " + "ratio of the image. If enabled, the border width will be " + "in percent of the image size, else the border width will " + "in pixels.")); + + m_labelBorderPercent = new TQLabel(i18n("Width (%):"), gboxSettings); + m_borderPercent = new KIntNumInput(gboxSettings); + m_borderPercent->setRange(1, 50, 1, true); + TQWhatsThis::add(m_borderPercent, i18n("<p>Set here the border width in percent of the image size.")); + + m_labelBorderWidth = new TQLabel(i18n("Width (pixels):"), gboxSettings); + m_borderWidth = new KIntNumInput(gboxSettings); + TQWhatsThis::add(m_borderWidth, i18n("<p>Set here the border width in pixels to add around the image.")); + + Digikam::ImageIface iface(0, 0); + int w = iface.originalWidth(); + int h = iface.originalHeight(); + + if (w > h) + m_borderWidth->setRange(1, h/2, 1, true); + else + m_borderWidth->setRange(1, w/2, 1, true); + + KSeparator *line2 = new KSeparator(Horizontal, gboxSettings); + + // ------------------------------------------------------------------- + + m_labelForeground = new TQLabel(gboxSettings); + m_firstColorButton = new KColorButton( TQColor( 192, 192, 192 ), gboxSettings ); + m_labelBackground = new TQLabel(gboxSettings); + m_secondColorButton = new KColorButton( TQColor( 128, 128, 128 ), gboxSettings ); + + // ------------------------------------------------------------------- + + gridSettings->addMultiCellWidget(label1, 0, 0, 0, 2); + gridSettings->addMultiCellWidget(m_borderType, 1, 1, 0, 2); + gridSettings->addMultiCellWidget(line1, 2, 2, 0, 2); + gridSettings->addMultiCellWidget(m_preserveAspectRatio, 3, 3, 0, 2); + gridSettings->addMultiCellWidget(m_labelBorderPercent, 4, 4, 0, 2); + gridSettings->addMultiCellWidget(m_borderPercent, 5, 5, 0, 2); + gridSettings->addMultiCellWidget(m_labelBorderWidth, 6, 6, 0, 2); + gridSettings->addMultiCellWidget(m_borderWidth, 7, 7, 0, 2); + gridSettings->addMultiCellWidget(line2, 8, 8, 0, 2); + gridSettings->addMultiCellWidget(m_labelForeground, 9, 9, 0, 0); + gridSettings->addMultiCellWidget(m_firstColorButton, 9, 9, 1, 2); + gridSettings->addMultiCellWidget(m_labelBackground, 10, 10, 0, 0); + gridSettings->addMultiCellWidget(m_secondColorButton, 10, 10, 1, 2); + + setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + connect(m_preserveAspectRatio, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotPreserveAspectRatioToggled(bool))); + + connect(m_borderType, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotBorderTypeChanged(int))); + + connect(m_borderPercent, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_borderWidth, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_firstColorButton, TQ_SIGNAL(changed(const TQColor &)), + this, TQ_SLOT(slotColorForegroundChanged(const TQColor &))); + + connect(m_secondColorButton, TQ_SIGNAL(changed(const TQColor &)), + this, TQ_SLOT(slotColorBackgroundChanged(const TQColor &))); +} + +ImageEffect_Border::~ImageEffect_Border() +{ +} + +void ImageEffect_Border::readUserSettings(void) +{ + m_borderType->blockSignals(true); + m_borderPercent->blockSignals(true); + m_borderWidth->blockSignals(true); + m_firstColorButton->blockSignals(true); + m_secondColorButton->blockSignals(true); + m_preserveAspectRatio->blockSignals(true); + + TDEConfig *config = kapp->config(); + config->setGroup("border Tool Dialog"); + + m_borderType->setCurrentItem(config->readNumEntry("Border Type", Border::SolidBorder)); + m_borderPercent->setValue(config->readNumEntry("Border Percent", 10) ); + m_borderWidth->setValue(config->readNumEntry("Border Width", 100) ); + m_preserveAspectRatio->setChecked(config->readBoolEntry("Preserve Aspect Ratio", true) ); + + TQColor black(0, 0, 0); + TQColor white(255, 255, 255); + TQColor gray1(192, 192, 192); + TQColor gray2(128, 128, 128); + + m_solidColor = config->readColorEntry("Solid Color", &black); + m_niepceBorderColor = config->readColorEntry("Niepce Border Color", &white); + m_niepceLineColor = config->readColorEntry("Niepce Line Color", &black); + m_bevelUpperLeftColor = config->readColorEntry("Bevel Upper Left Color", &gray1); + m_bevelLowerRightColor = config->readColorEntry("Bevel Lower Right Color", &gray2); + m_decorativeFirstColor = config->readColorEntry("Decorative First Color", &black); + m_decorativeSecondColor = config->readColorEntry("Decorative Second Color", &black); + + m_borderType->blockSignals(false); + m_borderPercent->blockSignals(false); + m_borderWidth->blockSignals(false); + m_firstColorButton->blockSignals(false); + m_secondColorButton->blockSignals(false); + m_preserveAspectRatio->blockSignals(false); + + slotBorderTypeChanged(m_borderType->currentItem()); +} + +void ImageEffect_Border::writeUserSettings(void) +{ + TDEConfig *config = kapp->config(); + config->setGroup("border Tool Dialog"); + + config->writeEntry("Border Type", m_borderType->currentItem()); + config->writeEntry("Border Percent", m_borderPercent->value()); + config->writeEntry("Border Width", m_borderWidth->value()); + config->writeEntry("Preserve Aspect Ratio", m_preserveAspectRatio->isChecked()); + + config->writeEntry("Solid Color", m_solidColor); + config->writeEntry("Niepce Border Color", m_niepceBorderColor); + config->writeEntry("Niepce Line Color", m_niepceLineColor); + config->writeEntry("Bevel Upper Left Color", m_bevelUpperLeftColor); + config->writeEntry("Bevel Lower Right Color", m_bevelLowerRightColor); + config->writeEntry("Decorative First Color", m_decorativeFirstColor); + config->writeEntry("Decorative Second Color", m_decorativeSecondColor); + + config->sync(); +} + +void ImageEffect_Border::resetValues() +{ + m_borderType->blockSignals(true); + m_borderPercent->blockSignals(true); + m_borderWidth->blockSignals(true); + m_firstColorButton->blockSignals(true); + m_secondColorButton->blockSignals(true); + m_preserveAspectRatio->blockSignals(true); + + m_borderType->setCurrentItem(Border::SolidBorder); + m_borderPercent->setValue(10); + m_borderWidth->setValue(100); + m_preserveAspectRatio->setChecked(true); + + m_solidColor = TQColor(0, 0, 0); + m_niepceBorderColor = TQColor(255, 255, 255); + m_niepceLineColor = TQColor(0, 0, 0); + m_bevelUpperLeftColor = TQColor(192, 192, 192); + m_bevelLowerRightColor = TQColor(128, 128, 128); + m_decorativeFirstColor = TQColor(0, 0, 0); + m_decorativeSecondColor = TQColor(0, 0, 0); + + m_borderType->blockSignals(false); + m_borderPercent->blockSignals(false); + m_borderWidth->blockSignals(false); + m_firstColorButton->blockSignals(false); + m_secondColorButton->blockSignals(false); + m_preserveAspectRatio->blockSignals(false); + + slotBorderTypeChanged(Border::SolidBorder); +} + +void ImageEffect_Border::renderingFinished() +{ + m_preserveAspectRatio->setEnabled(true); + m_borderType->setEnabled(true); + m_borderPercent->setEnabled(true); + m_borderWidth->setEnabled(true); + m_firstColorButton->setEnabled(true); + m_secondColorButton->setEnabled(true); + toggleBorderSlider(m_preserveAspectRatio->isChecked()); +} + +void ImageEffect_Border::slotColorForegroundChanged(const TQColor &color) +{ + switch (m_borderType->currentItem()) + { + case Border::SolidBorder: + m_solidColor = color; + break; + + case Border::NiepceBorder: + m_niepceBorderColor = color; + break; + + case Border::BeveledBorder: + m_bevelUpperLeftColor = color; + break; + + case Border::PineBorder: + case Border::WoodBorder: + case Border::PaperBorder: + case Border::ParqueBorder: + case Border::IceBorder: + case Border::LeafBorder: + case Border::MarbleBorder: + case Border::RainBorder: + case Border::CratersBorder: + case Border::DriedBorder: + case Border::PinkBorder: + case Border::StoneBorder: + case Border::ChalkBorder: + case Border::GraniteBorder: + case Border::RockBorder: + case Border::WallBorder: + m_decorativeFirstColor = color; + break; + } + + slotEffect(); +} + +void ImageEffect_Border::slotColorBackgroundChanged(const TQColor &color) +{ + switch (m_borderType->currentItem()) + { + case Border::SolidBorder: + m_solidColor = color; + break; + + case Border::NiepceBorder: + m_niepceLineColor = color; + break; + + case Border::BeveledBorder: + m_bevelLowerRightColor = color; + break; + + case Border::PineBorder: + case Border::WoodBorder: + case Border::PaperBorder: + case Border::ParqueBorder: + case Border::IceBorder: + case Border::LeafBorder: + case Border::MarbleBorder: + case Border::RainBorder: + case Border::CratersBorder: + case Border::DriedBorder: + case Border::PinkBorder: + case Border::StoneBorder: + case Border::ChalkBorder: + case Border::GraniteBorder: + case Border::RockBorder: + case Border::WallBorder: + m_decorativeSecondColor = color; + break; + } + + slotEffect(); +} + +void ImageEffect_Border::slotBorderTypeChanged(int borderType) +{ + m_labelForeground->setText(i18n("First:")); + m_labelBackground->setText(i18n("Second:")); + TQWhatsThis::add( m_firstColorButton, i18n("<p>Set here the foreground color of the border.")); + TQWhatsThis::add( m_secondColorButton, i18n("<p>Set here the Background color of the border.")); + m_firstColorButton->setEnabled(true); + m_secondColorButton->setEnabled(true); + m_labelForeground->setEnabled(true); + m_labelBackground->setEnabled(true); + m_borderPercent->setEnabled(true); + + switch (borderType) + { + case Border::SolidBorder: + m_firstColorButton->setColor( m_solidColor ); + m_secondColorButton->setEnabled(false); + m_labelBackground->setEnabled(false); + break; + + case Border::NiepceBorder: + TQWhatsThis::add( m_firstColorButton, i18n("<p>Set here the color of the main border.")); + TQWhatsThis::add( m_secondColorButton, i18n("<p>Set here the color of the line.")); + m_firstColorButton->setColor( m_niepceBorderColor ); + m_secondColorButton->setColor( m_niepceLineColor ); + break; + + case Border::BeveledBorder: + TQWhatsThis::add( m_firstColorButton, i18n("<p>Set here the color of the upper left area.")); + TQWhatsThis::add( m_secondColorButton, i18n("<p>Set here the color of the lower right area.")); + m_firstColorButton->setColor( m_bevelUpperLeftColor ); + m_secondColorButton->setColor( m_bevelLowerRightColor ); + break; + + case Border::PineBorder: + case Border::WoodBorder: + case Border::PaperBorder: + case Border::ParqueBorder: + case Border::IceBorder: + case Border::LeafBorder: + case Border::MarbleBorder: + case Border::RainBorder: + case Border::CratersBorder: + case Border::DriedBorder: + case Border::PinkBorder: + case Border::StoneBorder: + case Border::ChalkBorder: + case Border::GraniteBorder: + case Border::RockBorder: + case Border::WallBorder: + TQWhatsThis::add( m_firstColorButton, i18n("<p>Set here the color of the first line.")); + TQWhatsThis::add( m_secondColorButton, i18n("<p>Set here the color of the second line.")); + m_firstColorButton->setColor( m_decorativeFirstColor ); + m_secondColorButton->setColor( m_decorativeSecondColor ); + break; + } + + slotEffect(); +} + +void ImageEffect_Border::prepareEffect() +{ + m_borderType->setEnabled(false); + m_borderPercent->setEnabled(false); + m_borderWidth->setEnabled(false); + m_firstColorButton->setEnabled(false); + m_secondColorButton->setEnabled(false); + m_preserveAspectRatio->setEnabled(false); + + Digikam::ImageIface* iface = m_imagePreviewWidget->imageIface(); + int orgWidth = iface->originalWidth(); + int orgHeight = iface->originalHeight(); + int w = iface->previewWidth(); + int h = iface->previewHeight(); + bool sixteenBit = iface->previewSixteenBit(); + uchar *data = iface->getPreviewImage(); + Digikam::DImg previewImage(w, h, sixteenBit, + iface->previewHasAlpha(), data); + delete [] data; + + int borderType = m_borderType->currentItem(); + float ratio = (float)w/(float)orgWidth; + int borderWidth = (int)((float)m_borderWidth->value()*ratio); + TQString border = getBorderPath( m_borderType->currentItem() ); + + if (m_preserveAspectRatio->isChecked()) + { + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new Border(&previewImage, this, orgWidth, orgHeight, + border, borderType, m_borderPercent->value()/100.0, + Digikam::DColor(m_solidColor, sixteenBit), + Digikam::DColor(m_niepceBorderColor, sixteenBit), + Digikam::DColor(m_niepceLineColor, sixteenBit), + Digikam::DColor(m_bevelUpperLeftColor, sixteenBit), + Digikam::DColor(m_bevelLowerRightColor, sixteenBit), + Digikam::DColor(m_decorativeFirstColor, sixteenBit), + Digikam::DColor(m_decorativeSecondColor, sixteenBit)) ); + } + else + { + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new Border(&previewImage, this, orgWidth, orgHeight, + border, borderType, borderWidth, + (int)(20.0*ratio), (int)(20.0*ratio), 3, + Digikam::DColor(m_solidColor, sixteenBit), + Digikam::DColor(m_niepceBorderColor, sixteenBit), + Digikam::DColor(m_niepceLineColor, sixteenBit), + Digikam::DColor(m_bevelUpperLeftColor, sixteenBit), + Digikam::DColor(m_bevelLowerRightColor, sixteenBit), + Digikam::DColor(m_decorativeFirstColor, sixteenBit), + Digikam::DColor(m_decorativeSecondColor, sixteenBit)) ); + } +} + +void ImageEffect_Border::prepareFinal() +{ + m_borderType->setEnabled(false); + m_borderPercent->setEnabled(false); + m_borderWidth->setEnabled(false); + m_firstColorButton->setEnabled(false); + m_secondColorButton->setEnabled(false); + + int borderType = m_borderType->currentItem(); + int borderWidth = m_borderWidth->value(); + float borderRatio = m_borderPercent->value()/100.0; + TQString border = getBorderPath( m_borderType->currentItem() ); + + Digikam::ImageIface iface(0, 0); + int orgWidth = iface.originalWidth(); + int orgHeight = iface.originalHeight(); + bool sixteenBit = iface.previewSixteenBit(); + uchar *data = iface.getOriginalImage(); + Digikam::DImg orgImage(orgWidth, orgHeight, sixteenBit, + iface.originalHasAlpha(), data); + delete [] data; + + if (m_preserveAspectRatio->isChecked()) + { + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new Border(&orgImage, this, orgWidth, orgHeight, + border, borderType, borderRatio, + Digikam::DColor(m_solidColor, sixteenBit), + Digikam::DColor(m_niepceBorderColor, sixteenBit), + Digikam::DColor(m_niepceLineColor, sixteenBit), + Digikam::DColor(m_bevelUpperLeftColor, sixteenBit), + Digikam::DColor(m_bevelLowerRightColor, sixteenBit), + Digikam::DColor(m_decorativeFirstColor, sixteenBit), + Digikam::DColor(m_decorativeSecondColor, sixteenBit)) ); + } + else + { + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new Border(&orgImage, this, orgWidth, orgHeight, + border, borderType, borderWidth, 15, 15, 10, + Digikam::DColor(m_solidColor, sixteenBit), + Digikam::DColor(m_niepceBorderColor, sixteenBit), + Digikam::DColor(m_niepceLineColor, sixteenBit), + Digikam::DColor(m_bevelUpperLeftColor, sixteenBit), + Digikam::DColor(m_bevelLowerRightColor, sixteenBit), + Digikam::DColor(m_decorativeFirstColor, sixteenBit), + Digikam::DColor(m_decorativeSecondColor, sixteenBit)) ); + } +} + +void ImageEffect_Border::putPreviewData(void) +{ + Digikam::ImageIface* iface = m_imagePreviewWidget->imageIface(); + int w = iface->previewWidth(); + int h = iface->previewHeight(); + + Digikam::DImg imTemp = m_threadedFilter->getTargetImage().smoothScale(w, h, TQSize::ScaleMin); + Digikam::DImg imDest( w, h, m_threadedFilter->getTargetImage().sixteenBit(), + m_threadedFilter->getTargetImage().hasAlpha() ); + + imDest.fill( Digikam::DColor(paletteBackgroundColor().rgb(), + m_threadedFilter->getTargetImage().sixteenBit()) ); + + imDest.bitBltImage(&imTemp, (w-imTemp.width())/2, (h-imTemp.height())/2); + + iface->putPreviewImage(imDest.bits()); + m_imagePreviewWidget->updatePreview(); +} + +void ImageEffect_Border::putFinalData(void) +{ + Digikam::ImageIface iface(0, 0); + + Digikam::DImg targetImage = m_threadedFilter->getTargetImage(); + iface.putOriginalImage(i18n("Add Border"), + targetImage.bits(), + targetImage.width(), targetImage.height()); +} + +TQString ImageEffect_Border::getBorderPath(int border) +{ + TQString pattern; + + switch (border) + { + case Border::PineBorder: + pattern = "pine-pattern"; + break; + + case Border::WoodBorder: + pattern = "wood-pattern"; + break; + + case Border::PaperBorder: + pattern = "paper-pattern"; + break; + + case Border::ParqueBorder: + pattern = "parque-pattern"; + break; + + case Border::IceBorder: + pattern = "ice-pattern"; + break; + + case Border::LeafBorder: + pattern = "leaf-pattern"; + break; + + case Border::MarbleBorder: + pattern = "marble-pattern"; + break; + + case Border::RainBorder: + pattern = "rain-pattern"; + break; + + case Border::CratersBorder: + pattern = "craters-pattern"; + break; + + case Border::DriedBorder: + pattern = "dried-pattern"; + break; + + case Border::PinkBorder: + pattern = "pink-pattern"; + break; + + case Border::StoneBorder: + pattern = "stone-pattern"; + break; + + case Border::ChalkBorder: + pattern = "chalk-pattern"; + break; + + case Border::GraniteBorder: + pattern = "granit-pattern"; + break; + + case Border::RockBorder: + pattern = "rock-pattern"; + break; + + case Border::WallBorder: + pattern = "wall-pattern"; + break; + + default: + return TQString(); + } + + TDEGlobal::dirs()->addResourceType(pattern.ascii(), TDEGlobal::dirs()->kde_default("data") + + "digikam/data"); + return (TDEGlobal::dirs()->findResourceDir(pattern.ascii(), pattern + ".png") + pattern + ".png" ); +} + +void ImageEffect_Border::slotPreserveAspectRatioToggled(bool b) +{ + toggleBorderSlider(b); + slotTimer(); +} + +void ImageEffect_Border::toggleBorderSlider(bool b) +{ + m_borderPercent->setEnabled(b); + m_borderWidth->setEnabled(!b); + m_labelBorderPercent->setEnabled(b); + m_labelBorderWidth->setEnabled(!b); +} + +} // NameSpace DigikamBorderImagesPlugin + diff --git a/src/imageplugins/border/imageeffect_border.h b/src/imageplugins/border/imageeffect_border.h new file mode 100644 index 00000000..787a76a0 --- /dev/null +++ b/src/imageplugins/border/imageeffect_border.h @@ -0,0 +1,109 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-20 + * Description : a digiKam image plugin to add a border + * around an image. + * + * Copyright 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_BORDER_H +#define IMAGEEFFECT_BORDER_H + +// TQt includes. + +#include <tqstring.h> + +// Digikam includes. + +#include "imageguidedlg.h" + +class TQComboBox; +class TQLabel; +class TQCheckBox; +class TQColor; + +class KIntNumInput; +class KColorButton; + +namespace DigikamBorderImagesPlugin +{ + +class ImageEffect_Border : public Digikam::ImageGuideDlg +{ + TQ_OBJECT + + +public: + + ImageEffect_Border(TQWidget *parent); + ~ImageEffect_Border(); + +private: + + TQString getBorderPath(int border); + +private slots: + + void slotPreserveAspectRatioToggled(bool); + void slotBorderTypeChanged(int borderType); + void slotColorForegroundChanged(const TQColor &color); + void slotColorBackgroundChanged(const TQColor &color); + void readUserSettings(); + +private: + + void writeUserSettings(); + void resetValues(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + void toggleBorderSlider(bool b); + +private: + + TQLabel *m_labelBorderPercent; + TQLabel *m_labelBorderWidth; + TQLabel *m_labelForeground; + TQLabel *m_labelBackground; + + TQComboBox *m_borderType; + + TQCheckBox *m_preserveAspectRatio; + + TQColor m_solidColor; + TQColor m_niepceBorderColor; + TQColor m_niepceLineColor; + TQColor m_bevelUpperLeftColor; + TQColor m_bevelLowerRightColor; + TQColor m_decorativeFirstColor; + TQColor m_decorativeSecondColor; + + KIntNumInput *m_borderPercent; + KIntNumInput *m_borderWidth; + + KColorButton *m_firstColorButton; + KColorButton *m_secondColorButton; +}; + +} // NameSpace DigikamBorderImagesPlugin + +#endif /* IMAGEEFFECT_BORDER_H */ diff --git a/src/imageplugins/border/imageplugin_border.cpp b/src/imageplugins/border/imageplugin_border.cpp new file mode 100644 index 00000000..f0c5a236 --- /dev/null +++ b/src/imageplugins/border/imageplugin_border.cpp @@ -0,0 +1,71 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-20 + * Description : a digiKam image plugin to add a border + * around an image. + * + * Copyright 2005-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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> + +// Local includes. + +#include "ddebug.h" +#include "bordertool.h" +#include "imageplugin_border.h" +#include "imageplugin_border.moc" + +using namespace DigikamBorderImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_border, + KGenericFactory<ImagePlugin_Border>("digikamimageplugin_border")); + +ImagePlugin_Border::ImagePlugin_Border(TQObject *parent, const char*, const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_Border") +{ + m_borderAction = new TDEAction(i18n("Add Border..."), "bordertool", + 0, + this, TQ_SLOT(slotBorder()), + actionCollection(), "imageplugin_border"); + + setXMLFile("digikamimageplugin_border_ui.rc"); + + DDebug() << "ImagePlugin_Border plugin loaded" << endl; +} + +ImagePlugin_Border::~ImagePlugin_Border() +{ +} + +void ImagePlugin_Border::setEnabledActions(bool enable) +{ + m_borderAction->setEnabled(enable); +} + +void ImagePlugin_Border::slotBorder() +{ + BorderTool *tool = new BorderTool(this); + loadTool(tool); +} diff --git a/src/imageplugins/border/imageplugin_border.h b/src/imageplugins/border/imageplugin_border.h new file mode 100644 index 00000000..e5b3d959 --- /dev/null +++ b/src/imageplugins/border/imageplugin_border.h @@ -0,0 +1,57 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-20 + * Description : a digiKam image plugin to add a border + * around an image. + * + * Copyright 2005-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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_BORDER_H +#define IMAGEPLUGIN_BORDER_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_Border : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_Border(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_Border(); + + void setEnabledActions(bool enable); + +private slots: + + void slotBorder(); + +private: + + TDEAction *m_borderAction; +}; + +#endif /* IMAGEPLUGIN_BORDER_H */ diff --git a/src/imageplugins/border/patterns/Makefile.am b/src/imageplugins/border/patterns/Makefile.am new file mode 100644 index 00000000..31bb4b2d --- /dev/null +++ b/src/imageplugins/border/patterns/Makefile.am @@ -0,0 +1,5 @@ +borderpicsdir = $(kde_datadir)/digikam/data +borderpics_DATA = pine-pattern.png wood-pattern.png paper-pattern.png parque-pattern.png \ + ice-pattern.png leaf-pattern.png marble-pattern.png rain-pattern.png \ + craters-pattern.png dried-pattern.png pink-pattern.png stone-pattern.png \ + chalk-pattern.png granit-pattern.png rock-pattern.png wall-pattern.png diff --git a/src/imageplugins/border/patterns/chalk-pattern.png b/src/imageplugins/border/patterns/chalk-pattern.png Binary files differnew file mode 100644 index 00000000..31c34f62 --- /dev/null +++ b/src/imageplugins/border/patterns/chalk-pattern.png diff --git a/src/imageplugins/border/patterns/craters-pattern.png b/src/imageplugins/border/patterns/craters-pattern.png Binary files differnew file mode 100644 index 00000000..fe8fe792 --- /dev/null +++ b/src/imageplugins/border/patterns/craters-pattern.png diff --git a/src/imageplugins/border/patterns/dried-pattern.png b/src/imageplugins/border/patterns/dried-pattern.png Binary files differnew file mode 100644 index 00000000..fca948ff --- /dev/null +++ b/src/imageplugins/border/patterns/dried-pattern.png diff --git a/src/imageplugins/border/patterns/granit-pattern.png b/src/imageplugins/border/patterns/granit-pattern.png Binary files differnew file mode 100644 index 00000000..eccbb354 --- /dev/null +++ b/src/imageplugins/border/patterns/granit-pattern.png diff --git a/src/imageplugins/border/patterns/ice-pattern.png b/src/imageplugins/border/patterns/ice-pattern.png Binary files differnew file mode 100644 index 00000000..30a67265 --- /dev/null +++ b/src/imageplugins/border/patterns/ice-pattern.png diff --git a/src/imageplugins/border/patterns/leaf-pattern.png b/src/imageplugins/border/patterns/leaf-pattern.png Binary files differnew file mode 100644 index 00000000..b602fceb --- /dev/null +++ b/src/imageplugins/border/patterns/leaf-pattern.png diff --git a/src/imageplugins/border/patterns/marble-pattern.png b/src/imageplugins/border/patterns/marble-pattern.png Binary files differnew file mode 100644 index 00000000..6346bf1f --- /dev/null +++ b/src/imageplugins/border/patterns/marble-pattern.png diff --git a/src/imageplugins/border/patterns/paper-pattern.png b/src/imageplugins/border/patterns/paper-pattern.png Binary files differnew file mode 100644 index 00000000..43da3b2f --- /dev/null +++ b/src/imageplugins/border/patterns/paper-pattern.png diff --git a/src/imageplugins/border/patterns/parque-pattern.png b/src/imageplugins/border/patterns/parque-pattern.png Binary files differnew file mode 100644 index 00000000..2aa5e96f --- /dev/null +++ b/src/imageplugins/border/patterns/parque-pattern.png diff --git a/src/imageplugins/border/patterns/pine-pattern.png b/src/imageplugins/border/patterns/pine-pattern.png Binary files differnew file mode 100644 index 00000000..4ae7a687 --- /dev/null +++ b/src/imageplugins/border/patterns/pine-pattern.png diff --git a/src/imageplugins/border/patterns/pink-pattern.png b/src/imageplugins/border/patterns/pink-pattern.png Binary files differnew file mode 100644 index 00000000..d0649c85 --- /dev/null +++ b/src/imageplugins/border/patterns/pink-pattern.png diff --git a/src/imageplugins/border/patterns/rain-pattern.png b/src/imageplugins/border/patterns/rain-pattern.png Binary files differnew file mode 100644 index 00000000..a282c442 --- /dev/null +++ b/src/imageplugins/border/patterns/rain-pattern.png diff --git a/src/imageplugins/border/patterns/rock-pattern.png b/src/imageplugins/border/patterns/rock-pattern.png Binary files differnew file mode 100644 index 00000000..04dc8b0e --- /dev/null +++ b/src/imageplugins/border/patterns/rock-pattern.png diff --git a/src/imageplugins/border/patterns/stone-pattern.png b/src/imageplugins/border/patterns/stone-pattern.png Binary files differnew file mode 100644 index 00000000..98da7c2c --- /dev/null +++ b/src/imageplugins/border/patterns/stone-pattern.png diff --git a/src/imageplugins/border/patterns/wall-pattern.png b/src/imageplugins/border/patterns/wall-pattern.png Binary files differnew file mode 100644 index 00000000..3c101597 --- /dev/null +++ b/src/imageplugins/border/patterns/wall-pattern.png diff --git a/src/imageplugins/border/patterns/wood-pattern.png b/src/imageplugins/border/patterns/wood-pattern.png Binary files differnew file mode 100644 index 00000000..bfe4c724 --- /dev/null +++ b/src/imageplugins/border/patterns/wood-pattern.png diff --git a/src/imageplugins/channelmixer/Makefile.am b/src/imageplugins/channelmixer/Makefile.am new file mode 100644 index 00000000..61eaab34 --- /dev/null +++ b/src/imageplugins/channelmixer/Makefile.am @@ -0,0 +1,34 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_channelmixer_la_SOURCES = imageplugin_channelmixer.cpp \ + channelmixertool.cpp + +digikamimageplugin_channelmixer_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_channelmixer_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_channelmixer.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_channelmixer.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_channelmixer_ui.rc + diff --git a/src/imageplugins/channelmixer/channelmixer.cpp b/src/imageplugins/channelmixer/channelmixer.cpp new file mode 100644 index 00000000..849cc1e8 --- /dev/null +++ b/src/imageplugins/channelmixer/channelmixer.cpp @@ -0,0 +1,784 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-26 + * Description : image channels mixer. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * Load and save mixer gains methods inspired from + * Gimp 2.2.3 and copyrighted 2002 by Martin Guldahl + * <mguldahl at xmission 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 <cstdio> +#include <cmath> +#include <cstring> +#include <cstdlib> +#include <cerrno> + +// TQt includes. + +#include <tqcolor.h> +#include <tqgroupbox.h> +#include <tqhgroupbox.h> +#include <tqvgroupbox.h> +#include <tqhbuttongroup.h> +#include <tqlabel.h> +#include <tqpainter.h> +#include <tqcombobox.h> +#include <tqspinbox.h> +#include <tqvbox.h> +#include <tqwhatsthis.h> +#include <tqpushbutton.h> +#include <tqlayout.h> +#include <tqframe.h> +#include <tqtimer.h> +#include <tqcheckbox.h> +#include <tqfile.h> +#include <tqtooltip.h> + +// KDE includes. + +#include <tdeconfig.h> +#include <kcursor.h> +#include <tdelocale.h> +#include <knuminput.h> +#include <tdemessagebox.h> +#include <tdeselect.h> +#include <tdefiledialog.h> +#include <tdeglobalsettings.h> +#include <tdeaboutdata.h> +#include <khelpmenu.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <tdepopupmenu.h> +#include <kstandarddirs.h> + +// Local includes. + +#include "version.h" +#include "dimg.h" +#include "ddebug.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "imagehistogram.h" +#include "histogramwidget.h" +#include "colorgradientwidget.h" +#include "dimgimagefilters.h" +#include "channelmixer.h" +#include "channelmixer.moc" + +namespace DigikamChannelMixerImagesPlugin +{ + +ChannelMixerDialog::ChannelMixerDialog(TQWidget* parent) + : Digikam::ImageDlgBase(parent, i18n("Color Channel Mixer"), + "channelmixer", true, false) +{ + m_destinationPreviewData = 0L; + + // About data and help button. + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Color Channel Mixer"), + digikam_version, + I18N_NOOP("An image color channel mixer plugin for digiKam."), + TDEAboutData::License_GPL, + "(c) 2005-2008, Gilles Caulier", + 0, + "http://www.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + setAboutData(about); + + // ------------------------------------------------------------- + + m_previewWidget = new Digikam::ImageWidget("channelmixer Tool Dialog", plainPage(), + i18n("<p>You can see here the image's color channels' " + "gains adjustments preview. You can pick color on image " + "to see the color level corresponding on histogram.")); + setPreviewAreaWidget(m_previewWidget); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(plainPage()); + TQGridLayout* grid = new TQGridLayout( gboxSettings, 9, 4, spacingHint()); + + TQLabel *label1 = new TQLabel(i18n("Channel:"), gboxSettings); + label1->setAlignment ( TQt::AlignRight | TQt::AlignVCenter ); + m_channelCB = new TQComboBox( false, gboxSettings ); + m_channelCB->insertItem( i18n("Red") ); + m_channelCB->insertItem( i18n("Green") ); + m_channelCB->insertItem( i18n("Blue") ); + m_channelCB->setCurrentText( i18n("Red") ); + TQWhatsThis::add( m_channelCB, i18n("<p>Select the color channel to mix here:<p>" + "<b>Red</b>: display the red image-channel values.<p>" + "<b>Green</b>: display the green image-channel values.<p>" + "<b>Blue</b>: display the blue image-channel values.<p>")); + + m_scaleBG = new TQHButtonGroup(gboxSettings); + m_scaleBG->setExclusive(true); + m_scaleBG->setFrameShape(TQFrame::NoFrame); + m_scaleBG->setInsideMargin( 0 ); + TQWhatsThis::add( m_scaleBG, i18n("<p>Select the histogram scale here.<p>" + "If the image's maximal counts are small, you can use the linear scale.<p>" + "Logarithmic scale can be used when the maximal counts 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( "<p>Linear" ) ); + m_scaleBG->insert(linHistoButton, Digikam::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( "<p>Logarithmic" ) ); + m_scaleBG->insert(logHistoButton, Digikam::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); + + grid->addMultiCellLayout(l1, 0, 0, 0, 4); + + // ------------------------------------------------------------- + + TQVBox *histoBox = new TQVBox(gboxSettings); + m_histogramWidget = new Digikam::HistogramWidget(256, 140, histoBox, false, true, true); + TQWhatsThis::add( m_histogramWidget, i18n("<p>Here you can see the target preview image histogram drawing " + "of the selected image channel. This one is re-computed at any " + "mixer settings changes.")); + TQLabel *space = new TQLabel(histoBox); + space->setFixedHeight(1); + m_hGradient = new Digikam::ColorGradientWidget( Digikam::ColorGradientWidget::Horizontal, 10, histoBox ); + m_hGradient->setColors( TQColor( "black" ), TQColor( "red" ) ); + + grid->addMultiCellWidget(histoBox, 1, 2, 0, 4); + + // ------------------------------------------------------------- + + TQLabel *redLabel = new TQLabel(i18n("Red:"), gboxSettings); + m_redGain = new KDoubleNumInput(gboxSettings); + m_redGain->setPrecision(0); + m_redGain->setRange(-200.0, 200.0, 1, true); + TQWhatsThis::add( m_redGain, i18n("<p>Select the red color gain in percent for the current channel here.")); + + TQLabel *blueLabel = new TQLabel(i18n("Blue:"), gboxSettings); + m_greenGain = new KDoubleNumInput(gboxSettings); + m_greenGain->setPrecision(0); + m_greenGain->setRange(-200.0, 200.0, 1, true); + TQWhatsThis::add( m_greenGain, i18n("<p>Select the green color gain in percent for the current channel here.")); + + TQLabel *greenLabel = new TQLabel(i18n("Green:"), gboxSettings); + m_blueGain = new KDoubleNumInput(gboxSettings); + m_blueGain->setPrecision(0); + m_blueGain->setRange(-200.0, 200.0, 1, true); + TQWhatsThis::add( m_blueGain, i18n("<p>Select the blue color gain in percent for the current channel here.")); + + m_resetButton = new TQPushButton(i18n("&Reset"), gboxSettings); + TQWhatsThis::add( m_resetButton, i18n("Reset color channels' gains settings from the currently selected channel.")); + + grid->addMultiCellWidget(redLabel, 3, 3, 0, 0); + grid->addMultiCellWidget(greenLabel, 4, 4, 0, 0); + grid->addMultiCellWidget(blueLabel, 5, 5, 0, 0); + grid->addMultiCellWidget(m_redGain, 3, 3, 1, 4); + grid->addMultiCellWidget(m_greenGain, 4, 4, 1, 4); + grid->addMultiCellWidget(m_blueGain, 5, 5, 1, 4); + grid->addMultiCellWidget(m_resetButton, 6, 6, 0, 1); + + // ------------------------------------------------------------- + + m_monochrome = new TQCheckBox( i18n("Monochrome"), gboxSettings); + TQWhatsThis::add( m_monochrome, i18n("<p>Enable this option if you want the image rendered in monochrome mode. " + "In this mode, the histogram will display only luminosity values.")); + + m_preserveLuminosity = new TQCheckBox( i18n("Preserve luminosity"), gboxSettings); + TQWhatsThis::add( m_preserveLuminosity, i18n("<p>Enable this option is you want preserve the image luminosity.")); + + grid->addMultiCellWidget(m_monochrome, 7, 7, 0, 4); + grid->addMultiCellWidget(m_preserveLuminosity, 8, 8, 0, 4); + grid->setRowStretch(9, 10); + + setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + // Channels and scale selection slots. + + 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_previewWidget, TQ_SIGNAL(spotPositionChangedFromTarget( const Digikam::DColor &, const TQPoint & )), + this, TQ_SLOT(slotColorSelectedFromTarget( const Digikam::DColor & ))); + + connect(m_previewWidget, TQ_SIGNAL(signalResized()), + this, TQ_SLOT(slotEffect())); + + // ------------------------------------------------------------- + // Gains settings slots. + + connect(m_redGain, TQ_SIGNAL(valueChanged(double)), + this, TQ_SLOT(slotGainsChanged())); + + connect(m_greenGain, TQ_SIGNAL(valueChanged(double)), + this, TQ_SLOT(slotGainsChanged())); + + connect(m_blueGain, TQ_SIGNAL(valueChanged(double)), + this, TQ_SLOT(slotGainsChanged())); + + connect(m_preserveLuminosity, TQ_SIGNAL(toggled (bool)), + this, TQ_SLOT(slotEffect())); + + connect(m_monochrome, TQ_SIGNAL(toggled (bool)), + this, TQ_SLOT(slotMonochromeActived(bool))); + + // ------------------------------------------------------------- + // Bouttons slots. + + connect(m_resetButton, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotResetCurrentChannel())); +} + +ChannelMixerDialog::~ChannelMixerDialog() +{ + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + delete m_histogramWidget; +} + +void ChannelMixerDialog::slotResetCurrentChannel() +{ + switch( m_channelCB->currentItem() ) + { + case GreenChannelGains: // Green. + m_greenRedGain = 0.0; + m_greenGreenGain = 1.0; + m_greenBlueGain = 0.0; + break; + + case BlueChannelGains: // Blue. + m_blueRedGain = 0.0; + m_blueGreenGain = 0.0; + m_blueBlueGain = 1.0; + break; + + default: // Red or monochrome. + if ( m_monochrome->isChecked() ) + { + m_blackRedGain = 1.0; + m_blackGreenGain = 0.0; + m_blackBlueGain = 0.0; + } + else + { + m_redRedGain = 1.0; + m_redGreenGain = 0.0; + m_redBlueGain = 0.0; + } + break; + } + + adjustSliders(); + slotEffect(); + m_histogramWidget->reset(); +} + +void ChannelMixerDialog::slotColorSelectedFromTarget( const Digikam::DColor &color ) +{ + m_histogramWidget->setHistogramGuideByColor(color); +} + +void ChannelMixerDialog::slotGainsChanged() +{ + switch( m_channelCB->currentItem() ) + { + case GreenChannelGains: // Green. + m_greenRedGain = m_redGain->value() / 100.0; + m_greenGreenGain = m_greenGain->value() / 100.0; + m_greenBlueGain = m_blueGain->value() / 100.0; + break; + + case BlueChannelGains: // Blue. + m_blueRedGain = m_redGain->value() / 100.0; + m_blueGreenGain = m_greenGain->value() / 100.0; + m_blueBlueGain = m_blueGain->value() / 100.0; + break; + + default: // Red or monochrome. + if ( m_monochrome->isChecked() ) + { + m_blackRedGain = m_redGain->value() / 100.0; + m_blackGreenGain = m_greenGain->value() / 100.0; + m_blackBlueGain = m_blueGain->value() / 100.0; + } + else + { + m_redRedGain = m_redGain->value() / 100.0; + m_redGreenGain = m_greenGain->value() / 100.0; + m_redBlueGain = m_blueGain->value() / 100.0; + } + break; + } + + slotTimer(); +} + +void ChannelMixerDialog::adjustSliders(void) +{ + m_redGain->blockSignals(true); + m_greenGain->blockSignals(true); + m_blueGain->blockSignals(true); + + switch( m_channelCB->currentItem() ) + { + case GreenChannelGains: // Green. + m_redGain->setValue(m_greenRedGain * 100.0); + m_greenGain->setValue(m_greenGreenGain * 100.0); + m_blueGain->setValue(m_greenBlueGain * 100.0); + break; + + case BlueChannelGains: // Blue. + m_redGain->setValue(m_blueRedGain * 100.0); + m_greenGain->setValue(m_blueGreenGain * 100.0); + m_blueGain->setValue(m_blueBlueGain * 100.0); + break; + + default: // Red or monochrome. + if ( m_monochrome->isChecked() ) + { + m_redGain->setValue(m_blackRedGain * 100.0); + m_greenGain->setValue(m_blackGreenGain * 100.0); + m_blueGain->setValue(m_blackBlueGain * 100.0); + } + else + { + m_redGain->setValue(m_redRedGain * 100.0); + m_greenGain->setValue(m_redGreenGain * 100.0); + m_blueGain->setValue(m_redBlueGain * 100.0); + } + break; + } + + m_redGain->blockSignals(false); + m_greenGain->blockSignals(false); + m_blueGain->blockSignals(false); +} + +void ChannelMixerDialog::slotMonochromeActived(bool mono) +{ + m_channelCB->setEnabled(!mono); + m_channelCB->setCurrentItem(RedChannelGains); // Red for monochrome. + slotChannelChanged(RedChannelGains); // Monochrome => display luminosity histogram value. +} + +void ChannelMixerDialog::slotEffect() +{ + Digikam::ImageIface* iface = m_previewWidget->imageIface(); + uchar *data = iface->getPreviewImage(); + int w = iface->previewWidth(); + int h = iface->previewHeight(); + bool sb = iface->previewSixteenBit(); + + // Create the new empty destination image data space. + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + m_destinationPreviewData = new uchar[w*h*(sb ? 8 : 4)]; + Digikam::DImgImageFilters filter; + + if (m_monochrome->isChecked()) + { + filter.channelMixerImage(data, w, h, sb, // Image data. + m_preserveLuminosity->isChecked(), // Preserve luminosity. + m_monochrome->isChecked(), // Monochrome. + m_blackRedGain, m_blackGreenGain, m_blackBlueGain, // Red channel gains. + 0.0, 1.0, 0.0, // Green channel gains (not used). + 0.0, 0.0, 1.0); // Blue channel gains (not used). + } + else + { + filter.channelMixerImage(data, w, h, sb, // Image data. + m_preserveLuminosity->isChecked(), // Preserve luminosity. + m_monochrome->isChecked(), // Monochrome. + m_redRedGain, m_redGreenGain, m_redBlueGain, // Red channel gains. + m_greenRedGain, m_greenGreenGain, m_greenBlueGain, // Green channel gains. + m_blueRedGain, m_blueGreenGain, m_blueBlueGain); // Blue channel gains. + } + + iface->putPreviewImage(data); + m_previewWidget->updatePreview(); + + // Update histogram. + memcpy (m_destinationPreviewData, data, w*h*(sb ? 8 : 4)); + m_histogramWidget->updateData(m_destinationPreviewData, w, h, sb, 0, 0, 0, false); + delete [] data; +} + +void ChannelMixerDialog::finalRendering() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + Digikam::ImageIface* iface = m_previewWidget->imageIface(); + uchar *data = iface->getOriginalImage(); + int w = iface->originalWidth(); + int h = iface->originalHeight(); + bool sb = iface->originalSixteenBit(); + + Digikam::DImgImageFilters filter; + + if (m_monochrome->isChecked()) + { + filter.channelMixerImage(data, w, h, sb, // Image data. + m_preserveLuminosity->isChecked(), // Preserve luminosity. + m_monochrome->isChecked(), // Monochrome. + m_blackRedGain, m_blackGreenGain, m_blackBlueGain, // Red channel gains. + 0.0, 1.0, 0.0, // Green channel gains (not used). + 0.0, 0.0, 1.0); // Blue channel gains (not used). + } + else + { + filter.channelMixerImage(data, w, h, sb, // Image data. + m_preserveLuminosity->isChecked(), // Preserve luminosity. + m_monochrome->isChecked(), // Monochrome. + m_redRedGain, m_redGreenGain, m_redBlueGain, // Red channel gains. + m_greenRedGain, m_greenGreenGain, m_greenBlueGain, // Green channel gains. + m_blueRedGain, m_blueGreenGain, m_blueBlueGain); // Blue channel gains. + } + + iface->putOriginalImage(i18n("Channel Mixer"), data); + delete [] data; + kapp->restoreOverrideCursor(); + accept(); +} + +void ChannelMixerDialog::slotChannelChanged(int channel) +{ + switch(channel) + { + case GreenChannelGains: // Green. + m_histogramWidget->m_channelType = Digikam::HistogramWidget::GreenChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "green" ) ); + break; + + case BlueChannelGains: // Blue. + m_histogramWidget->m_channelType = Digikam::HistogramWidget::BlueChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "blue" ) ); + break; + + default: // Red or monochrome. + if ( m_monochrome->isChecked() ) + { + m_histogramWidget->m_channelType = Digikam::HistogramWidget::ValueHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + } + else + { + m_histogramWidget->m_channelType = Digikam::HistogramWidget::RedChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "red" ) ); + } + break; + } + + m_histogramWidget->repaint(false); + adjustSliders(); + slotEffect(); +} + +void ChannelMixerDialog::slotScaleChanged(int scale) +{ + m_histogramWidget->m_scaleType = scale; + m_histogramWidget->repaint(false); +} + +void ChannelMixerDialog::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("channelmixer Tool Dialog"); + + m_channelCB->setCurrentItem(config->readNumEntry("Histogram Channel", 0)); // Luminosity. + m_scaleBG->setButton(config->readNumEntry("Histogram Scale", Digikam::HistogramWidget::LogScaleHistogram)); + + m_monochrome->setChecked(config->readBoolEntry("Monochrome", false)); + m_preserveLuminosity->setChecked(config->readNumEntry("PreserveLuminosity", false)); + + m_redRedGain = config->readDoubleNumEntry("RedRedGain", 1.0); + m_redGreenGain = config->readDoubleNumEntry("RedGreenGain", 0.0); + m_redBlueGain = config->readDoubleNumEntry("RedBlueGain", 0.0); + + m_greenRedGain = config->readDoubleNumEntry("GreenRedGain", 0.0); + m_greenGreenGain = config->readDoubleNumEntry("GreenGreenGain", 1.0); + m_greenBlueGain = config->readDoubleNumEntry("GreenBlueGain", 0.0); + + m_blueRedGain = config->readDoubleNumEntry("BlueRedGain", 0.0); + m_blueGreenGain = config->readDoubleNumEntry("BlueGreenGain", 0.0); + m_blueBlueGain = config->readDoubleNumEntry("BlueBlueGain", 1.0); + + m_blackRedGain = config->readDoubleNumEntry("BlackRedGain", 1.0); + m_blackGreenGain = config->readDoubleNumEntry("BlackGreenGain", 0.0); + m_blackBlueGain = config->readDoubleNumEntry("BlackBlueGain", 0.0); + + adjustSliders(); + m_histogramWidget->reset(); + + slotChannelChanged(m_channelCB->currentItem()); + slotScaleChanged(m_scaleBG->selectedId()); +} + +void ChannelMixerDialog::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("channelmixer Tool Dialog"); + config->writeEntry("Histogram Channel", m_channelCB->currentItem()); + config->writeEntry("Histogram Scale", m_scaleBG->selectedId()); + + config->writeEntry("Monochrome", m_monochrome->isChecked()); + config->writeEntry("PreserveLuminosity", m_preserveLuminosity->isChecked()); + + config->writeEntry("RedRedGain", m_redRedGain); + config->writeEntry("RedGreenGain", m_redGreenGain); + config->writeEntry("RedBlueGain", m_redBlueGain); + + config->writeEntry("GreenRedGain", m_greenRedGain); + config->writeEntry("GreenGreenGain", m_greenGreenGain); + config->writeEntry("GreenBlueGain", m_greenBlueGain); + + config->writeEntry("BlueRedGain", m_blueRedGain); + config->writeEntry("BlueGreenGain", m_blueGreenGain); + config->writeEntry("BlueBlueGain", m_blueBlueGain); + + config->writeEntry("BlackRedGain", m_blackRedGain); + config->writeEntry("BlackGreenGain", m_blackGreenGain); + config->writeEntry("BlackBlueGain", m_blackBlueGain); + + config->sync(); +} + +void ChannelMixerDialog::resetValues() +{ + m_monochrome->blockSignals(true); + m_preserveLuminosity->blockSignals(true); + + m_redRedGain = 1.0; + m_redGreenGain = 0.0; + m_redBlueGain = 0.0; + + m_greenRedGain = 0.0; + m_greenGreenGain = 1.0; + m_greenBlueGain = 0.0; + + m_blueRedGain = 0.0; + m_blueGreenGain = 0.0; + m_blueBlueGain = 1.0; + + m_blackRedGain = 1.0; + m_blackGreenGain = 0.0; + m_blackBlueGain = 0.0; + + adjustSliders(); + + m_monochrome->blockSignals(false); + m_preserveLuminosity->blockSignals(false); + m_channelCB->setEnabled(true); + + m_histogramWidget->reset(); + + slotChannelChanged(RedChannelGains); +} + +// Load all gains. +void ChannelMixerDialog::slotUser3() +{ + KURL loadGainsFileUrl; + FILE *fp = 0L; + int currentOutputChannel; + bool monochrome; + + loadGainsFileUrl = KFileDialog::getOpenURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), this, + TQString( i18n("Select Gimp Gains Mixer File to Load")) ); + if( loadGainsFileUrl.isEmpty() ) + return; + + fp = fopen(TQFile::encodeName(loadGainsFileUrl.path()), "r"); + + if ( fp ) + { + char buf1[1024]; + char buf2[1024]; + char buf3[1024]; + + buf1[0] = '\0'; + + fgets(buf1, 1023, fp); + + fscanf (fp, "%*s %s", buf1); + + // Get the current output channel in dialog. + + if (strcmp (buf1, "RED") == 0) + currentOutputChannel = RedChannelGains; + else if (strcmp (buf1, "GREEN") == 0) + currentOutputChannel = GreenChannelGains; + else if (strcmp (buf1, "BLUE") == 0) + currentOutputChannel = BlueChannelGains; + + fscanf (fp, "%*s %s", buf1); // preview flag, preserved for compatibility + + fscanf (fp, "%*s %s", buf1); + + if (strcmp (buf1, "true") == 0) + monochrome = true; + else + monochrome = false; + + fscanf (fp, "%*s %s", buf1); + + if (strcmp (buf1, "true") == 0) + m_preserveLuminosity->setChecked(true); + else + m_preserveLuminosity->setChecked(false); + + fscanf (fp, "%*s %s %s %s", buf1, buf2, buf3); + m_redRedGain = atof(buf1); + m_redGreenGain = atof(buf2); + m_redBlueGain = atof(buf3); + + fscanf (fp, "%*s %s %s %s", buf1, buf2, buf3); + m_greenRedGain = atof(buf1); + m_greenGreenGain = atof(buf2); + m_greenBlueGain = atof(buf3); + + fscanf (fp, "%*s %s %s %s", buf1, buf2, buf3); + m_blueRedGain = atof(buf1); + m_blueGreenGain = atof(buf2); + m_blueBlueGain = atof(buf3); + + fscanf (fp, "%*s %s %s %s", buf1, buf2, buf3); + m_blackRedGain = atof(buf1); + m_blackGreenGain = atof(buf2); + m_blackBlueGain = atof(buf3); + + fclose(fp); + + // Refresh settings. + m_monochrome->setChecked(monochrome); + m_channelCB->setCurrentItem(currentOutputChannel); + slotChannelChanged(currentOutputChannel); + } + else + { + KMessageBox::error(this, i18n("Cannot load settings from the Gains Mixer text file.")); + return; + } +} + +// Save all gains. +void ChannelMixerDialog::slotUser2() +{ + KURL saveGainsFileUrl; + FILE *fp = 0L; + + saveGainsFileUrl = KFileDialog::getSaveURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), this, + TQString( i18n("Gimp Gains Mixer File to Save")) ); + if( saveGainsFileUrl.isEmpty() ) + return; + + fp = fopen(TQFile::encodeName(saveGainsFileUrl.path()), "w"); + + if ( fp ) + { + const char *str = 0L; + char buf1[256]; + char buf2[256]; + char buf3[256]; + + switch ( m_channelCB->currentItem() ) + { + case RedChannelGains: + str = "RED"; + break; + case GreenChannelGains: + str = "GREEN"; + break; + case BlueChannelGains: + str = "BLUE"; + break; + default: + DWarning() << "Unknown Color channel gains" << endl; + break; + } + + fprintf (fp, "# Channel Mixer Configuration File\n"); + + fprintf (fp, "CHANNEL: %s\n", str); + fprintf (fp, "PREVIEW: %s\n", "true"); // preserved for compatibility + fprintf (fp, "MONOCHROME: %s\n", + m_monochrome->isChecked() ? "true" : "false"); + fprintf (fp, "PRESERVE_LUMINOSITY: %s\n", + m_preserveLuminosity->isChecked() ? "true" : "false"); + + sprintf (buf1, "%5.3f", m_redRedGain); + sprintf (buf2, "%5.3f", m_redGreenGain); + sprintf (buf3, "%5.3f", m_redBlueGain); + fprintf (fp, "RED: %s %s %s\n", buf1, buf2,buf3); + + sprintf (buf1, "%5.3f", m_greenRedGain); + sprintf (buf2, "%5.3f", m_greenGreenGain); + sprintf (buf3, "%5.3f", m_greenBlueGain); + fprintf (fp, "GREEN: %s %s %s\n", buf1, buf2,buf3); + + sprintf (buf1, "%5.3f", m_blueRedGain); + sprintf (buf2, "%5.3f", m_blueGreenGain); + sprintf (buf3, "%5.3f", m_blueBlueGain); + fprintf (fp, "BLUE: %s %s %s\n", buf1, buf2,buf3); + + sprintf (buf1, "%5.3f", m_blackRedGain); + sprintf (buf2, "%5.3f", m_blackGreenGain); + sprintf (buf3, "%5.3f", m_blackBlueGain); + fprintf (fp, "BLACK: %s %s %s\n", buf1, buf2,buf3); + + fclose (fp); + } + else + { + KMessageBox::error(this, i18n("Cannot save settings to the Gains Mixer text file.")); + return; + } +} + +} // NameSpace DigikamChannelMixerImagesPlugin + diff --git a/src/imageplugins/channelmixer/channelmixer.h b/src/imageplugins/channelmixer/channelmixer.h new file mode 100644 index 00000000..9b4396d0 --- /dev/null +++ b/src/imageplugins/channelmixer/channelmixer.h @@ -0,0 +1,133 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-26 + * Description : image channels mixer. + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +#ifndef CHANNELMIXER_H +#define CHANNELMIXER_H + +// Digikam includes. + +#include "imagedlgbase.h" + +class TQCheckBox; +class TQComboBox; +class TQPushButton; +class TQHButtonGroup; + +class KDoubleNumInput; + +namespace Digikam +{ +class HistogramWidget; +class ColorGradientWidget; +class ImageWidget; +class DColor; +} + +namespace DigikamChannelMixerImagesPlugin +{ + +class ChannelMixerDialog : public Digikam::ImageDlgBase +{ + TQ_OBJECT + + +public: + + ChannelMixerDialog(TQWidget *parent); + ~ChannelMixerDialog(); + +private: + + void readUserSettings(); + void writeUserSettings(); + void resetValues(); + void finalRendering(); + void adjustSliders(); + +private slots: + + void slotUser2(); + void slotUser3(); + void slotResetCurrentChannel(); + void slotEffect(); + void slotChannelChanged(int channel); + void slotScaleChanged(int scale); + void slotGainsChanged(); + void slotMonochromeActived(bool mono); + void slotColorSelectedFromTarget(const Digikam::DColor &color); + +private: + + enum ColorChannelGains + { + RedChannelGains=0, + GreenChannelGains, + BlueChannelGains + }; + + enum HistogramScale + { + Linear=0, + Logarithmic + }; + +private: + + uchar *m_destinationPreviewData; + + double m_redRedGain; + double m_redGreenGain; + double m_redBlueGain; + double m_greenRedGain; + double m_greenGreenGain; + double m_greenBlueGain; + double m_blueRedGain; + double m_blueGreenGain; + double m_blueBlueGain; + double m_blackRedGain; + double m_blackGreenGain; + double m_blackBlueGain; + + TQComboBox *m_channelCB; + + TQHButtonGroup *m_scaleBG; + + KDoubleNumInput *m_redGain; + KDoubleNumInput *m_greenGain; + KDoubleNumInput *m_blueGain; + + TQPushButton *m_resetButton; + + TQCheckBox *m_preserveLuminosity; + TQCheckBox *m_monochrome; + + Digikam::ColorGradientWidget *m_hGradient; + + Digikam::HistogramWidget *m_histogramWidget; + + Digikam::ImageWidget *m_previewWidget; +}; + +} // NameSpace DigikamChannelMixerImagesPlugin + +#endif /* CHANNELMIXER_H */ diff --git a/src/imageplugins/channelmixer/channelmixertool.cpp b/src/imageplugins/channelmixer/channelmixertool.cpp new file mode 100644 index 00000000..c8215178 --- /dev/null +++ b/src/imageplugins/channelmixer/channelmixertool.cpp @@ -0,0 +1,774 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-26 + * Description : image channels mixer. + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +// C++ includes. + +#include <cstdio> +#include <cmath> +#include <cstring> +#include <cstdlib> +#include <cerrno> + +// TQt includes. + +#include <tqcheckbox.h> +#include <tqcolor.h> +#include <tqcombobox.h> +#include <tqfile.h> +#include <tqframe.h> +#include <tqgroupbox.h> +#include <tqhbuttongroup.h> +#include <tqhgroupbox.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqpainter.h> +#include <tqpushbutton.h> +#include <tqspinbox.h> +#include <tqtimer.h> +#include <tqtooltip.h> +#include <tqvbox.h> +#include <tqvgroupbox.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeconfig.h> +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <kcursor.h> +#include <tdefiledialog.h> +#include <tdeglobalsettings.h> +#include <khelpmenu.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <tdepopupmenu.h> +#include <tdeselect.h> +#include <kstandarddirs.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> + +// Local includes. + +#include "daboutdata.h" +#include "dimg.h" +#include "ddebug.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "imagehistogram.h" +#include "histogramwidget.h" +#include "colorgradientwidget.h" +#include "dimgimagefilters.h" +#include "editortoolsettings.h" +#include "channelmixertool.h" +#include "channelmixertool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamChannelMixerImagesPlugin +{ + +ChannelMixerTool::ChannelMixerTool(TQObject* parent) + : EditorTool(parent) +{ + m_destinationPreviewData = 0; + + setName("channelmixer"); + setToolName(i18n("Channel Mixer")); + setToolIcon(SmallIcon("channelmixer")); + + // ------------------------------------------------------------- + + m_previewWidget = new ImageWidget("channelmixer Tool", 0, + i18n("<p>You can see here the image's color channels' " + "gains adjustments preview. You can pick color on image " + "to see the color level corresponding on histogram.")); + setToolView(m_previewWidget); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Load| + EditorToolSettings::SaveAs| + EditorToolSettings::Ok| + EditorToolSettings::Cancel); + TQGridLayout* grid = new TQGridLayout(m_gboxSettings->plainPage(), 9, 4); + + 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("Red") ); + m_channelCB->insertItem( i18n("Green") ); + m_channelCB->insertItem( i18n("Blue") ); + m_channelCB->setCurrentText( i18n("Red") ); + TQWhatsThis::add( m_channelCB, i18n("<p>Select the color channel to mix here:<p>" + "<b>Red</b>: display the red image-channel values.<p>" + "<b>Green</b>: display the green image-channel values.<p>" + "<b>Blue</b>: display the blue image-channel values.<p>")); + + 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("<p>Select the histogram scale here.<p>" + "If the image's maximal counts are small, you can use the linear scale.<p>" + "Logarithmic scale can be used when the maximal counts 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( "<p>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( "<p>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); + + // ------------------------------------------------------------- + + TQVBox *histoBox = new TQVBox(m_gboxSettings->plainPage()); + m_histogramWidget = new HistogramWidget(256, 140, histoBox, false, true, true); + TQWhatsThis::add( m_histogramWidget, i18n("<p>Here you can see the target preview image histogram drawing " + "of the selected image channel. This one is re-computed at any " + "mixer settings changes.")); + TQLabel *space = new TQLabel(histoBox); + space->setFixedHeight(1); + m_hGradient = new ColorGradientWidget( ColorGradientWidget::Horizontal, 10, histoBox ); + m_hGradient->setColors( TQColor( "black" ), TQColor( "red" ) ); + + // ------------------------------------------------------------- + + TQLabel *redLabel = new TQLabel(i18n("Red:"), m_gboxSettings->plainPage()); + m_redGain = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_redGain->setPrecision(0); + m_redGain->setRange(-200.0, 200.0, 1); + m_redGain->setDefaultValue(0); + TQWhatsThis::add( m_redGain, i18n("<p>Select the red color gain in percent for the current channel here.")); + + TQLabel *blueLabel = new TQLabel(i18n("Blue:"), m_gboxSettings->plainPage()); + m_greenGain = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_greenGain->setPrecision(0); + m_greenGain->setRange(-200.0, 200.0, 1); + m_greenGain->setDefaultValue(0); + TQWhatsThis::add( m_greenGain, i18n("<p>Select the green color gain in percent for the current channel here.")); + + TQLabel *greenLabel = new TQLabel(i18n("Green:"), m_gboxSettings->plainPage()); + m_blueGain = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_blueGain->setPrecision(0); + m_blueGain->setRange(-200.0, 200.0, 1); + m_blueGain->setDefaultValue(0); + TQWhatsThis::add( m_blueGain, i18n("<p>Select the blue color gain in percent for the current channel here.")); + + m_resetButton = new TQPushButton(i18n("&Reset"), m_gboxSettings->plainPage()); + TQWhatsThis::add( m_resetButton, i18n("Reset color channels' gains settings from the currently selected channel.")); + + // ------------------------------------------------------------- + + m_monochrome = new TQCheckBox( i18n("Monochrome"), m_gboxSettings->plainPage()); + TQWhatsThis::add( m_monochrome, i18n("<p>Enable this option if you want the image rendered in monochrome mode. " + "In this mode, the histogram will display only luminosity values.")); + + m_preserveLuminosity = new TQCheckBox( i18n("Preserve luminosity"), m_gboxSettings->plainPage()); + TQWhatsThis::add( m_preserveLuminosity, i18n("<p>Enable this option is you want preserve the image luminosity.")); + + grid->addMultiCellLayout(l1, 0, 0, 0, 4); + grid->addMultiCellWidget(histoBox, 1, 2, 0, 4); + grid->addMultiCellWidget(redLabel, 3, 3, 0, 0); + grid->addMultiCellWidget(greenLabel, 4, 4, 0, 0); + grid->addMultiCellWidget(blueLabel, 5, 5, 0, 0); + grid->addMultiCellWidget(m_redGain, 3, 3, 1, 4); + grid->addMultiCellWidget(m_greenGain, 4, 4, 1, 4); + grid->addMultiCellWidget(m_blueGain, 5, 5, 1, 4); + grid->addMultiCellWidget(m_resetButton, 6, 6, 0, 1); + grid->addMultiCellWidget(m_monochrome, 7, 7, 0, 4); + grid->addMultiCellWidget(m_preserveLuminosity, 8, 8, 0, 4); + grid->setRowStretch(9, 10); + grid->setMargin(m_gboxSettings->spacingHint()); + grid->setSpacing(m_gboxSettings->spacingHint()); + + setToolSettings(m_gboxSettings); + init(); + + // ------------------------------------------------------------- + // Channels and scale selection slots. + + 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_previewWidget, TQ_SIGNAL(spotPositionChangedFromTarget(const Digikam::DColor&, const TQPoint&)), + this, TQ_SLOT(slotColorSelectedFromTarget(const Digikam::DColor&))); + + connect(m_previewWidget, TQ_SIGNAL(signalResized()), + this, TQ_SLOT(slotEffect())); + + // ------------------------------------------------------------- + // Gains settings slots. + + connect(m_redGain, TQ_SIGNAL(valueChanged(double)), + this, TQ_SLOT(slotGainsChanged())); + + connect(m_greenGain, TQ_SIGNAL(valueChanged(double)), + this, TQ_SLOT(slotGainsChanged())); + + connect(m_blueGain, TQ_SIGNAL(valueChanged(double)), + this, TQ_SLOT(slotGainsChanged())); + + connect(m_preserveLuminosity, TQ_SIGNAL(toggled (bool)), + this, TQ_SLOT(slotEffect())); + + connect(m_monochrome, TQ_SIGNAL(toggled (bool)), + this, TQ_SLOT(slotMonochromeActived(bool))); + + // ------------------------------------------------------------- + // Bouttons slots. + + connect(m_resetButton, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotResetCurrentChannel())); +} + +ChannelMixerTool::~ChannelMixerTool() +{ + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; +} + +void ChannelMixerTool::slotResetCurrentChannel() +{ + switch( m_channelCB->currentItem() ) + { + case GreenChannelGains: // Green. + m_greenRedGain = 0.0; + m_greenGreenGain = 1.0; + m_greenBlueGain = 0.0; + break; + + case BlueChannelGains: // Blue. + m_blueRedGain = 0.0; + m_blueGreenGain = 0.0; + m_blueBlueGain = 1.0; + break; + + default: // Red or monochrome. + if ( m_monochrome->isChecked() ) + { + m_blackRedGain = 1.0; + m_blackGreenGain = 0.0; + m_blackBlueGain = 0.0; + } + else + { + m_redRedGain = 1.0; + m_redGreenGain = 0.0; + m_redBlueGain = 0.0; + } + break; + } + + adjustSliders(); + slotEffect(); + m_histogramWidget->reset(); +} + +void ChannelMixerTool::slotColorSelectedFromTarget(const DColor& color) +{ + m_histogramWidget->setHistogramGuideByColor(color); +} + +void ChannelMixerTool::slotGainsChanged() +{ + switch( m_channelCB->currentItem() ) + { + case GreenChannelGains: // Green. + m_greenRedGain = m_redGain->value() / 100.0; + m_greenGreenGain = m_greenGain->value() / 100.0; + m_greenBlueGain = m_blueGain->value() / 100.0; + break; + + case BlueChannelGains: // Blue. + m_blueRedGain = m_redGain->value() / 100.0; + m_blueGreenGain = m_greenGain->value() / 100.0; + m_blueBlueGain = m_blueGain->value() / 100.0; + break; + + default: // Red or monochrome. + if ( m_monochrome->isChecked() ) + { + m_blackRedGain = m_redGain->value() / 100.0; + m_blackGreenGain = m_greenGain->value() / 100.0; + m_blackBlueGain = m_blueGain->value() / 100.0; + } + else + { + m_redRedGain = m_redGain->value() / 100.0; + m_redGreenGain = m_greenGain->value() / 100.0; + m_redBlueGain = m_blueGain->value() / 100.0; + } + break; + } + + slotTimer(); +} + +void ChannelMixerTool::adjustSliders() +{ + m_redGain->blockSignals(true); + m_greenGain->blockSignals(true); + m_blueGain->blockSignals(true); + + switch( m_channelCB->currentItem() ) + { + case GreenChannelGains: // Green. + m_redGain->setValue(m_greenRedGain * 100.0); + m_greenGain->setValue(m_greenGreenGain * 100.0); + m_blueGain->setValue(m_greenBlueGain * 100.0); + break; + + case BlueChannelGains: // Blue. + m_redGain->setValue(m_blueRedGain * 100.0); + m_greenGain->setValue(m_blueGreenGain * 100.0); + m_blueGain->setValue(m_blueBlueGain * 100.0); + break; + + default: // Red or monochrome. + if ( m_monochrome->isChecked() ) + { + m_redGain->setValue(m_blackRedGain * 100.0); + m_greenGain->setValue(m_blackGreenGain * 100.0); + m_blueGain->setValue(m_blackBlueGain * 100.0); + } + else + { + m_redGain->setValue(m_redRedGain * 100.0); + m_greenGain->setValue(m_redGreenGain * 100.0); + m_blueGain->setValue(m_redBlueGain * 100.0); + } + break; + } + + m_redGain->blockSignals(false); + m_greenGain->blockSignals(false); + m_blueGain->blockSignals(false); +} + +void ChannelMixerTool::slotMonochromeActived(bool mono) +{ + m_channelCB->setEnabled(!mono); + m_channelCB->setCurrentItem(RedChannelGains); // Red for monochrome. + slotChannelChanged(RedChannelGains); // Monochrome => display luminosity histogram value. +} + +void ChannelMixerTool::slotEffect() +{ + ImageIface* iface = m_previewWidget->imageIface(); + uchar *data = iface->getPreviewImage(); + int w = iface->previewWidth(); + int h = iface->previewHeight(); + bool sb = iface->previewSixteenBit(); + + // Create the new empty destination image data space. + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + m_destinationPreviewData = new uchar[w*h*(sb ? 8 : 4)]; + DImgImageFilters filter; + + if (m_monochrome->isChecked()) + { + filter.channelMixerImage(data, w, h, sb, // Image data. + m_preserveLuminosity->isChecked(), // Preserve luminosity. + m_monochrome->isChecked(), // Monochrome. + m_blackRedGain, m_blackGreenGain, m_blackBlueGain, // Red channel gains. + 0.0, 1.0, 0.0, // Green channel gains (not used). + 0.0, 0.0, 1.0); // Blue channel gains (not used). + } + else + { + filter.channelMixerImage(data, w, h, sb, // Image data. + m_preserveLuminosity->isChecked(), // Preserve luminosity. + m_monochrome->isChecked(), // Monochrome. + m_redRedGain, m_redGreenGain, m_redBlueGain, // Red channel gains. + m_greenRedGain, m_greenGreenGain, m_greenBlueGain, // Green channel gains. + m_blueRedGain, m_blueGreenGain, m_blueBlueGain); // Blue channel gains. + } + + iface->putPreviewImage(data); + m_previewWidget->updatePreview(); + + // Update histogram. + memcpy (m_destinationPreviewData, data, w*h*(sb ? 8 : 4)); + m_histogramWidget->updateData(m_destinationPreviewData, w, h, sb, 0, 0, 0, false); + delete [] data; +} + +void ChannelMixerTool::finalRendering() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + ImageIface* iface = m_previewWidget->imageIface(); + uchar *data = iface->getOriginalImage(); + int w = iface->originalWidth(); + int h = iface->originalHeight(); + bool sb = iface->originalSixteenBit(); + + DImgImageFilters filter; + + if (m_monochrome->isChecked()) + { + filter.channelMixerImage(data, w, h, sb, // Image data. + m_preserveLuminosity->isChecked(), // Preserve luminosity. + m_monochrome->isChecked(), // Monochrome. + m_blackRedGain, m_blackGreenGain, m_blackBlueGain, // Red channel gains. + 0.0, 1.0, 0.0, // Green channel gains (not used). + 0.0, 0.0, 1.0); // Blue channel gains (not used). + } + else + { + filter.channelMixerImage(data, w, h, sb, // Image data. + m_preserveLuminosity->isChecked(), // Preserve luminosity. + m_monochrome->isChecked(), // Monochrome. + m_redRedGain, m_redGreenGain, m_redBlueGain, // Red channel gains. + m_greenRedGain, m_greenGreenGain, m_greenBlueGain, // Green channel gains. + m_blueRedGain, m_blueGreenGain, m_blueBlueGain); // Blue channel gains. + } + + iface->putOriginalImage(i18n("Channel Mixer"), data); + delete [] data; + kapp->restoreOverrideCursor(); +} + +void ChannelMixerTool::slotChannelChanged(int channel) +{ + switch(channel) + { + case GreenChannelGains: // Green. + m_histogramWidget->m_channelType = HistogramWidget::GreenChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "green" ) ); + break; + + case BlueChannelGains: // Blue. + m_histogramWidget->m_channelType = HistogramWidget::BlueChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "blue" ) ); + break; + + default: // Red or monochrome. + if ( m_monochrome->isChecked() ) + { + m_histogramWidget->m_channelType = HistogramWidget::ValueHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + } + else + { + m_histogramWidget->m_channelType = HistogramWidget::RedChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "red" ) ); + } + break; + } + + m_histogramWidget->repaint(false); + adjustSliders(); + slotEffect(); +} + +void ChannelMixerTool::slotScaleChanged(int scale) +{ + m_histogramWidget->m_scaleType = scale; + m_histogramWidget->repaint(false); +} + +void ChannelMixerTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("channelmixer Tool"); + + m_channelCB->setCurrentItem(config->readNumEntry("Histogram Channel", 0)); // Luminosity. + m_scaleBG->setButton(config->readNumEntry("Histogram Scale", HistogramWidget::LogScaleHistogram)); + + m_monochrome->setChecked(config->readBoolEntry("Monochrome", false)); + m_preserveLuminosity->setChecked(config->readNumEntry("PreserveLuminosity", false)); + + m_redRedGain = config->readDoubleNumEntry("RedRedGain", 1.0); + m_redGreenGain = config->readDoubleNumEntry("RedGreenGain", 0.0); + m_redBlueGain = config->readDoubleNumEntry("RedBlueGain", 0.0); + + m_greenRedGain = config->readDoubleNumEntry("GreenRedGain", 0.0); + m_greenGreenGain = config->readDoubleNumEntry("GreenGreenGain", 1.0); + m_greenBlueGain = config->readDoubleNumEntry("GreenBlueGain", 0.0); + + m_blueRedGain = config->readDoubleNumEntry("BlueRedGain", 0.0); + m_blueGreenGain = config->readDoubleNumEntry("BlueGreenGain", 0.0); + m_blueBlueGain = config->readDoubleNumEntry("BlueBlueGain", 1.0); + + m_blackRedGain = config->readDoubleNumEntry("BlackRedGain", 1.0); + m_blackGreenGain = config->readDoubleNumEntry("BlackGreenGain", 0.0); + m_blackBlueGain = config->readDoubleNumEntry("BlackBlueGain", 0.0); + + adjustSliders(); + m_histogramWidget->reset(); + slotChannelChanged(m_channelCB->currentItem()); + slotScaleChanged(m_scaleBG->selectedId()); +} + +void ChannelMixerTool::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("channelmixer Tool"); + config->writeEntry("Histogram Channel", m_channelCB->currentItem()); + config->writeEntry("Histogram Scale", m_scaleBG->selectedId()); + + config->writeEntry("Monochrome", m_monochrome->isChecked()); + config->writeEntry("PreserveLuminosity", m_preserveLuminosity->isChecked()); + + config->writeEntry("RedRedGain", m_redRedGain); + config->writeEntry("RedGreenGain", m_redGreenGain); + config->writeEntry("RedBlueGain", m_redBlueGain); + + config->writeEntry("GreenRedGain", m_greenRedGain); + config->writeEntry("GreenGreenGain", m_greenGreenGain); + config->writeEntry("GreenBlueGain", m_greenBlueGain); + + config->writeEntry("BlueRedGain", m_blueRedGain); + config->writeEntry("BlueGreenGain", m_blueGreenGain); + config->writeEntry("BlueBlueGain", m_blueBlueGain); + + config->writeEntry("BlackRedGain", m_blackRedGain); + config->writeEntry("BlackGreenGain", m_blackGreenGain); + config->writeEntry("BlackBlueGain", m_blackBlueGain); + + m_previewWidget->writeSettings(); + + config->sync(); +} + +void ChannelMixerTool::slotResetSettings() +{ + m_monochrome->blockSignals(true); + m_preserveLuminosity->blockSignals(true); + + m_redRedGain = 1.0; + m_redGreenGain = 0.0; + m_redBlueGain = 0.0; + + m_greenRedGain = 0.0; + m_greenGreenGain = 1.0; + m_greenBlueGain = 0.0; + + m_blueRedGain = 0.0; + m_blueGreenGain = 0.0; + m_blueBlueGain = 1.0; + + m_blackRedGain = 1.0; + m_blackGreenGain = 0.0; + m_blackBlueGain = 0.0; + + adjustSliders(); + + m_monochrome->blockSignals(false); + m_preserveLuminosity->blockSignals(false); + m_channelCB->setEnabled(true); + + m_histogramWidget->reset(); + + slotChannelChanged(RedChannelGains); +} + +void ChannelMixerTool::slotLoadSettings() +{ + KURL loadGainsFileUrl; + FILE *fp = 0L; + int currentOutputChannel; + bool monochrome; + + loadGainsFileUrl = KFileDialog::getOpenURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), kapp->activeWindow(), + TQString( i18n("Select Gimp Gains Mixer File to Load")) ); + if( loadGainsFileUrl.isEmpty() ) + return; + + fp = fopen(TQFile::encodeName(loadGainsFileUrl.path()), "r"); + + if ( fp ) + { + char buf1[1024]; + char buf2[1024]; + char buf3[1024]; + + buf1[0] = '\0'; + + fgets(buf1, 1023, fp); + + fscanf (fp, "%*s %s", buf1); + + // Get the current output channel in dialog. + + if (strcmp (buf1, "RED") == 0) + currentOutputChannel = RedChannelGains; + else if (strcmp (buf1, "GREEN") == 0) + currentOutputChannel = GreenChannelGains; + else if (strcmp (buf1, "BLUE") == 0) + currentOutputChannel = BlueChannelGains; + + fscanf (fp, "%*s %s", buf1); // preview flag, preserved for compatibility + + fscanf (fp, "%*s %s", buf1); + + if (strcmp (buf1, "true") == 0) + monochrome = true; + else + monochrome = false; + + fscanf (fp, "%*s %s", buf1); + + if (strcmp (buf1, "true") == 0) + m_preserveLuminosity->setChecked(true); + else + m_preserveLuminosity->setChecked(false); + + fscanf (fp, "%*s %s %s %s", buf1, buf2, buf3); + m_redRedGain = atof(buf1); + m_redGreenGain = atof(buf2); + m_redBlueGain = atof(buf3); + + fscanf (fp, "%*s %s %s %s", buf1, buf2, buf3); + m_greenRedGain = atof(buf1); + m_greenGreenGain = atof(buf2); + m_greenBlueGain = atof(buf3); + + fscanf (fp, "%*s %s %s %s", buf1, buf2, buf3); + m_blueRedGain = atof(buf1); + m_blueGreenGain = atof(buf2); + m_blueBlueGain = atof(buf3); + + fscanf (fp, "%*s %s %s %s", buf1, buf2, buf3); + m_blackRedGain = atof(buf1); + m_blackGreenGain = atof(buf2); + m_blackBlueGain = atof(buf3); + + fclose(fp); + + // Refresh settings. + m_monochrome->setChecked(monochrome); + m_channelCB->setCurrentItem(currentOutputChannel); + slotChannelChanged(currentOutputChannel); + } + else + { + KMessageBox::error(kapp->activeWindow(), i18n("Cannot load settings from the Gains Mixer text file.")); + return; + } +} + +void ChannelMixerTool::slotSaveAsSettings() +{ + KURL saveGainsFileUrl; + FILE *fp = 0L; + + saveGainsFileUrl = KFileDialog::getSaveURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), kapp->activeWindow(), + TQString( i18n("Gimp Gains Mixer File to Save")) ); + if( saveGainsFileUrl.isEmpty() ) + return; + + fp = fopen(TQFile::encodeName(saveGainsFileUrl.path()), "w"); + + if ( fp ) + { + const char *str = 0L; + char buf1[256]; + char buf2[256]; + char buf3[256]; + + switch ( m_channelCB->currentItem() ) + { + case RedChannelGains: + str = "RED"; + break; + case GreenChannelGains: + str = "GREEN"; + break; + case BlueChannelGains: + str = "BLUE"; + break; + default: + DWarning() << "Unknown Color channel gains" << endl; + break; + } + + fprintf (fp, "# Channel Mixer Configuration File\n"); + + fprintf (fp, "CHANNEL: %s\n", str); + fprintf (fp, "PREVIEW: %s\n", "true"); // preserved for compatibility + fprintf (fp, "MONOCHROME: %s\n", + m_monochrome->isChecked() ? "true" : "false"); + fprintf (fp, "PRESERVE_LUMINOSITY: %s\n", + m_preserveLuminosity->isChecked() ? "true" : "false"); + + sprintf (buf1, "%5.3f", m_redRedGain); + sprintf (buf2, "%5.3f", m_redGreenGain); + sprintf (buf3, "%5.3f", m_redBlueGain); + fprintf (fp, "RED: %s %s %s\n", buf1, buf2,buf3); + + sprintf (buf1, "%5.3f", m_greenRedGain); + sprintf (buf2, "%5.3f", m_greenGreenGain); + sprintf (buf3, "%5.3f", m_greenBlueGain); + fprintf (fp, "GREEN: %s %s %s\n", buf1, buf2,buf3); + + sprintf (buf1, "%5.3f", m_blueRedGain); + sprintf (buf2, "%5.3f", m_blueGreenGain); + sprintf (buf3, "%5.3f", m_blueBlueGain); + fprintf (fp, "BLUE: %s %s %s\n", buf1, buf2,buf3); + + sprintf (buf1, "%5.3f", m_blackRedGain); + sprintf (buf2, "%5.3f", m_blackGreenGain); + sprintf (buf3, "%5.3f", m_blackBlueGain); + fprintf (fp, "BLACK: %s %s %s\n", buf1, buf2,buf3); + + fclose (fp); + } + else + { + KMessageBox::error(kapp->activeWindow(), i18n("Cannot save settings to the Gains Mixer text file.")); + return; + } +} + +} // NameSpace DigikamChannelMixerImagesPlugin diff --git a/src/imageplugins/channelmixer/channelmixertool.h b/src/imageplugins/channelmixer/channelmixertool.h new file mode 100644 index 00000000..c15a30cd --- /dev/null +++ b/src/imageplugins/channelmixer/channelmixertool.h @@ -0,0 +1,138 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-26 + * Description : image channels mixer. + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +#ifndef CHANNELMIXERTOOL_H +#define CHANNELMIXERTOOL_H + +// Digikam includes. + +#include "editortool.h" + +class TQCheckBox; +class TQComboBox; +class TQPushButton; +class TQHButtonGroup; + +namespace KDcrawIface +{ +class RDoubleNumInput; +} + +namespace Digikam +{ +class HistogramWidget; +class ColorGradientWidget; +class ImageWidget; +class DColor; +} + +namespace DigikamChannelMixerImagesPlugin +{ + +class ChannelMixerTool : public Digikam::EditorTool +{ + TQ_OBJECT + + +public: + + ChannelMixerTool(TQObject *parent); + ~ChannelMixerTool(); + +private: + + void readSettings(); + void writeSettings(); + void finalRendering(); + void adjustSliders(); + +private slots: + + void slotLoadSettings(); + void slotSaveAsSettings(); + void slotResetCurrentChannel(); + void slotEffect(); + void slotResetSettings(); + void slotChannelChanged(int channel); + void slotScaleChanged(int scale); + void slotGainsChanged(); + void slotMonochromeActived(bool mono); + void slotColorSelectedFromTarget(const Digikam::DColor &color); + +private: + + enum ColorChannelGains + { + RedChannelGains=0, + GreenChannelGains, + BlueChannelGains + }; + + enum HistogramScale + { + Linear=0, + Logarithmic + }; + +private: + + uchar *m_destinationPreviewData; + + double m_redRedGain; + double m_redGreenGain; + double m_redBlueGain; + double m_greenRedGain; + double m_greenGreenGain; + double m_greenBlueGain; + double m_blueRedGain; + double m_blueGreenGain; + double m_blueBlueGain; + double m_blackRedGain; + double m_blackGreenGain; + double m_blackBlueGain; + + TQComboBox *m_channelCB; + + TQHButtonGroup *m_scaleBG; + + KDcrawIface::RDoubleNumInput *m_redGain; + KDcrawIface::RDoubleNumInput *m_greenGain; + KDcrawIface::RDoubleNumInput *m_blueGain; + + TQPushButton *m_resetButton; + + TQCheckBox *m_preserveLuminosity; + TQCheckBox *m_monochrome; + + Digikam::ColorGradientWidget *m_hGradient; + + Digikam::HistogramWidget *m_histogramWidget; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamChannelMixerImagesPlugin + +#endif /* CHANNELMIXERTOOL_H */ diff --git a/src/imageplugins/channelmixer/digikamimageplugin_channelmixer.desktop b/src/imageplugins/channelmixer/digikamimageplugin_channelmixer.desktop new file mode 100644 index 00000000..a855fffe --- /dev/null +++ b/src/imageplugins/channelmixer/digikamimageplugin_channelmixer.desktop @@ -0,0 +1,51 @@ +[Desktop Entry] +Name=ImagePlugin_ChannelMixer +Name[bg]=Приставка за снимки - Смесител на канали +Name[el]=ΠρόσθετοΕικόνας_ΑνάμειξηΚαναλιών +Name[fi]=KanavatasapainonSäätö +Name[hr]=Miješanje kanala +Name[it]=PluginImmagini_MixerDeiCanali +Name[nl]=Afbeeldingsplugin_Kanaalmixer +Name[sr]=Миксета канала +Name[sr@Latn]=Mikseta kanala +Name[sv]=Insticksprogram för kanalblandning +Name[tr]=ResimEklentisi_KanalKarıştırıcı +Name[xx]=xxImagePlugin_ChannelMixerxx +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 + +Comment=Image color channels mixer plugin for digiKam +Comment[bg]=Приставка на digiKam със смесител на цветови канали +Comment[ca]=Connector pel digiKam per mesclar els canals de color de la imatge +Comment[da]=Digikam plugin til at blande billedfarvekanaler +Comment[de]=digiKam-Modul zum Mischen von Farbkanälen eines Bildes +Comment[el]=Πρόσθετο μείκτη καναλιών χρώματος εικόνας για το digiKam +Comment[en_GB]=Image colour channels mixer plugin for digiKam +Comment[es]=Plugin para digiKam para la mezcla de los canales de color de imagen +Comment[et]=DigiKami pildi värvikanalite mikseri plugin +Comment[fa]=وصلۀ مخلوطکن مجراهای رنگ تصویر برای digiKam +Comment[fi]=Värikanavien sekoitussuhteiden muokkain +Comment[gl]=Un plugin de digiKam para misturar os canais de cores +Comment[hr]=digiKam dodatak za miješanje kanala boja +Comment[is]=Íforrit fyrir digiKam sem blandar litrásum mynda +Comment[it]=Plugin di mixer dei canali dei colori per digiKam +Comment[ja]=digiKam カラーチャンネルミキサープラグイン +Comment[nds]=digiKam-Mischermoduul för de Bild-Klöörkanaals +Comment[nl]=Digikam-plugin voor kanaalmixer +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਚਿੱਤਰ ਰੰਗ ਚੈਨਲ ਮਿਕਸਰ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam mieszająca kanały kolorów +Comment[pt]=Um 'plugin' do digiKam para misturar os canais de cores +Comment[pt_BR]=Plugin do mixer de canais de cor da imagem +Comment[ru]=Модуль микширования цветовых каналов для digiKam +Comment[sk]=digiKam plugin pre miešanie farebných kanálov obrázku +Comment[sr]=Прикључак миксете канала боја за digiKam +Comment[sr@Latn]=Priključak miksete kanala boja za digiKam +Comment[sv]=Digikam insticksprogram för att blanda bildfärgkanaler +Comment[tr]=digiKam için resim kanalları karıştıcı eklentisi +Comment[uk]=Втулок змішування каналів кольорів для digiKam +Comment[vi]=Phần bổ sung hoà kênh màu ảnh cho digiKam +Comment[xx]=xxImage color channels mixer plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_channelmixer +author=Caulier Gilles, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/channelmixer/digikamimageplugin_channelmixer_ui.rc b/src/imageplugins/channelmixer/digikamimageplugin_channelmixer_ui.rc new file mode 100644 index 00000000..1a004c96 --- /dev/null +++ b/src/imageplugins/channelmixer/digikamimageplugin_channelmixer_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="5" name="digikamimageplugin_channelmixer" > + + <MenuBar> + + <Menu name="Color"><text>&Color</text> + <Action name="imageplugin_channelmixer" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action name="imageplugin_channelmixer" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/channelmixer/imageplugin_channelmixer.cpp b/src/imageplugins/channelmixer/imageplugin_channelmixer.cpp new file mode 100644 index 00000000..19fe21a9 --- /dev/null +++ b/src/imageplugins/channelmixer/imageplugin_channelmixer.cpp @@ -0,0 +1,71 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-26 + * Description : image channels mixer. + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> + +// Local includes. + +#include "ddebug.h" +#include "channelmixertool.h" +#include "imageplugin_channelmixer.h" +#include "imageplugin_channelmixer.moc" + +using namespace DigikamChannelMixerImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_channelmixer, + KGenericFactory<ImagePlugin_ChannelMixer>("digikamimageplugin_channelmixer")) + +ImagePlugin_ChannelMixer::ImagePlugin_ChannelMixer(TQObject *parent, const char*, + const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_ChannelMixer") +{ + m_channelMixerAction = new TDEAction(i18n("Channel Mixer..."), "channelmixer", + CTRL+Key_H, + this, TQ_SLOT(slotChannelMixer()), + actionCollection(), "imageplugin_channelmixer"); + + setXMLFile("digikamimageplugin_channelmixer_ui.rc"); + + DDebug() << "ImagePlugin_ChannelMixer plugin loaded" << endl; +} + +ImagePlugin_ChannelMixer::~ImagePlugin_ChannelMixer() +{ +} + +void ImagePlugin_ChannelMixer::setEnabledActions(bool enable) +{ + m_channelMixerAction->setEnabled(enable); +} + +void ImagePlugin_ChannelMixer::slotChannelMixer() +{ + ChannelMixerTool *cm = new ChannelMixerTool(this); + loadTool(cm); +} diff --git a/src/imageplugins/channelmixer/imageplugin_channelmixer.h b/src/imageplugins/channelmixer/imageplugin_channelmixer.h new file mode 100644 index 00000000..444006ab --- /dev/null +++ b/src/imageplugins/channelmixer/imageplugin_channelmixer.h @@ -0,0 +1,56 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-26 + * Description : image channels mixer. + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_CHANNELMIXER_H +#define IMAGEPLUGIN_CHANNELMIXER_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_ChannelMixer : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_ChannelMixer(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_ChannelMixer(); + + void setEnabledActions(bool enable); + +private slots: + + void slotChannelMixer(); + +private: + + TDEAction *m_channelMixerAction; +}; + +#endif /* IMAGEPLUGIN_CHANNELMIXER_H */ diff --git a/src/imageplugins/charcoal/Makefile.am b/src/imageplugins/charcoal/Makefile.am new file mode 100644 index 00000000..3d851deb --- /dev/null +++ b/src/imageplugins/charcoal/Makefile.am @@ -0,0 +1,34 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_charcoal_la_SOURCES = imageplugin_charcoal.cpp \ + charcoaltool.cpp charcoal.cpp + +digikamimageplugin_charcoal_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_charcoal_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_charcoal.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_charcoal.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_charcoal_ui.rc + diff --git a/src/imageplugins/charcoal/charcoal.cpp b/src/imageplugins/charcoal/charcoal.cpp new file mode 100644 index 00000000..a4c54a3c --- /dev/null +++ b/src/imageplugins/charcoal/charcoal.cpp @@ -0,0 +1,249 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : Charcoal threaded image filter. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * Original Charcoal algorithm copyright 2002 + * by Daniel M. Duley <mosfet@kde.org> from KImageEffect API. + * + * 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. + * + * ============================================================ */ + +#define SQ2PI 2.50662827463100024161235523934010416269302368164062 +#define Epsilon 1.0e-12 + +// C++ includes. + +#include <cmath> + +// Local includes. + +#include "ddebug.h" +#include "dimg.h" +#include "dimggaussianblur.h" +#include "dimgimagefilters.h" +#include "charcoal.h" + +namespace DigikamCharcoalImagesPlugin +{ + +Charcoal::Charcoal(Digikam::DImg *orgImage, TQObject *parent, double pencil, double smooth) + : Digikam::DImgThreadedFilter(orgImage, parent, "Charcoal") +{ + m_pencil = pencil; + m_smooth = smooth; + + initFilter(); +} + +void Charcoal::filterImage(void) +{ + if (m_orgImage.isNull()) + { + DWarning() << k_funcinfo << "No image data available!" + << endl; + return; + } + + if (m_pencil <= 0.0) + { + m_destImage = m_orgImage; + return; + } + + // -- Applying Edge effect ----------------------------------------------- + + long i=0; + int kernelWidth = getOptimalKernelWidth(m_pencil, m_smooth); + + if((int)m_orgImage.width() < kernelWidth) + { + DWarning() << k_funcinfo << "Image is smaller than radius!" + << endl; + return; + } + + double *kernel = new double[kernelWidth*kernelWidth]; + + if(!kernel) + { + DWarning() << k_funcinfo << "Unable to allocate memory!" + << endl; + return; + } + + for(i = 0 ; i < (kernelWidth*kernelWidth) ; i++) + kernel[i]=(-1.0); + + kernel[i/2]=kernelWidth*kernelWidth-1.0; + convolveImage(kernelWidth, kernel); + delete [] kernel; + + // -- Applying Gaussian blur effect --------------------------------------- + + Digikam::DImgGaussianBlur(this, m_destImage, m_destImage, 50, 60, (int)(m_smooth/10.0)); + + if (m_cancel) + return; + + // -- Applying strech contrast color effect ------------------------------- + + Digikam::DImgImageFilters().stretchContrastImage(m_destImage.bits(), m_destImage.width(), + m_destImage.height(), m_destImage.sixteenBit()); + postProgress( 70 ); + if (m_cancel) + return; + + // -- Inverting image color ----------------------------------------------- + + Digikam::DImgImageFilters().invertImage(m_destImage.bits(), m_destImage.width(), + m_destImage.height(), m_destImage.sixteenBit()); + postProgress( 80 ); + if (m_cancel) + return; + + // -- Convert to neutral black & white ------------------------------------ + + Digikam::DImgImageFilters().channelMixerImage( + m_destImage.bits(), m_destImage.width(), + m_destImage.height(), m_destImage.sixteenBit(), // Image data. + true, // Preserve luminosity. + true, // Monochrome. + 0.3, 0.59 , 0.11, // Red channel gains. + 0.0, 1.0, 0.0, // Green channel gains (not used). + 0.0, 0.0, 1.0); // Blue channel gains (not used). + postProgress( 90 ); + if (m_cancel) + return; +} + +bool Charcoal::convolveImage(const unsigned int order, const double *kernel) +{ + uint x, y; + int mx, my, sx, sy, mcx, mcy, progress; + long kernelWidth, i; + double red, green, blue, alpha, normalize=0.0; + double *k=0; + Digikam::DColor color; + + kernelWidth = order; + + if((kernelWidth % 2) == 0) + { + DWarning() << k_funcinfo << "Kernel width must be an odd number!" + << endl; + return(false); + } + + double *normal_kernel = new double[kernelWidth*kernelWidth]; + + if(!normal_kernel) + { + DWarning() << k_funcinfo << "Unable to allocate memory!" + << endl; + return(false); + } + + for(i=0 ; i < (kernelWidth*kernelWidth) ; i++) + normalize += kernel[i]; + + if(fabs(normalize) <= Epsilon) + normalize=1.0; + + normalize = 1.0/normalize; + + for(i=0 ; i < (kernelWidth*kernelWidth) ; i++) + normal_kernel[i] = normalize*kernel[i]; + + double maxClamp = m_destImage.sixteenBit() ? 16777215.0 : 65535.0; + + for(y=0 ; !m_cancel && (y < m_destImage.height()) ; y++) + { + sy = y-(kernelWidth/2); + + for(x=0 ; !m_cancel && (x < m_destImage.width()) ; x++) + { + k = normal_kernel; + red = green = blue = alpha = 0; + sy = y-(kernelWidth/2); + + for(mcy=0 ; !m_cancel && (mcy < kernelWidth) ; mcy++, sy++) + { + my = sy < 0 ? 0 : sy > (int)m_destImage.height()-1 ? m_destImage.height()-1 : sy; + sx = x+(-kernelWidth/2); + + for(mcx=0 ; !m_cancel && (mcx < kernelWidth) ; mcx++, sx++) + { + mx = sx < 0 ? 0 : sx > (int)m_destImage.width()-1 ? m_destImage.width()-1 : sx; + color = m_orgImage.getPixelColor(mx, my); + red += (*k)*(color.red() * 257.0); + green += (*k)*(color.green() * 257.0); + blue += (*k)*(color.blue() * 257.0); + alpha += (*k)*(color.alpha() * 257.0); + k++; + } + } + + red = red < 0.0 ? 0.0 : red > maxClamp ? maxClamp : red+0.5; + green = green < 0.0 ? 0.0 : green > maxClamp ? maxClamp : green+0.5; + blue = blue < 0.0 ? 0.0 : blue > maxClamp ? maxClamp : blue+0.5; + alpha = alpha < 0.0 ? 0.0 : alpha > maxClamp ? maxClamp : alpha+0.5; + + m_destImage.setPixelColor(x, y, Digikam::DColor((int)(red / 257UL), (int)(green / 257UL), + (int)(blue / 257UL), (int)(alpha / 257UL), + m_destImage.sixteenBit())); + } + + progress = (int)(((double)y * 50.0) / m_destImage.height()); + if ( progress%5 == 0 ) + postProgress( progress ); + } + + delete [] normal_kernel; + return(true); +} + +int Charcoal::getOptimalKernelWidth(double radius, double sigma) +{ + double normalize, value; + long kernelWidth; + long u; + + if(radius > 0.0) + return((int)(2.0*ceil(radius)+1.0)); + + for(kernelWidth=5; ;) + { + normalize=0.0; + + for(u=(-kernelWidth/2) ; u <= (kernelWidth/2) ; u++) + normalize += exp(-((double) u*u)/(2.0*sigma*sigma))/(SQ2PI*sigma); + + u = kernelWidth/2; + value = exp(-((double) u*u)/(2.0*sigma*sigma))/(SQ2PI*sigma)/normalize; + + if((long)(65535*value) <= 0) + break; + + kernelWidth+=2; + } + + return((int)kernelWidth-2); +} + +} // NameSpace DigikamCharcoalImagesPlugin diff --git a/src/imageplugins/charcoal/charcoal.h b/src/imageplugins/charcoal/charcoal.h new file mode 100644 index 00000000..2088ccc4 --- /dev/null +++ b/src/imageplugins/charcoal/charcoal.h @@ -0,0 +1,56 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : Charcoal threaded image filter. + * + * Copyright (C) 2005-2007 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. + * + * ============================================================ */ + +#ifndef CHARCOAL_H +#define CHARCOAL_H + +// Digikam includes. + +#include "dimgthreadedfilter.h" + +namespace DigikamCharcoalImagesPlugin +{ + +class Charcoal : public Digikam::DImgThreadedFilter +{ + +public: + + Charcoal(Digikam::DImg *orgImage, TQObject *parent=0, double pencil=5.0, double smooth=10.0); + ~Charcoal(){}; + +private: + + void filterImage(void); + bool convolveImage(const unsigned int order, const double *kernel); + int getOptimalKernelWidth(double radius, double sigma); + +private: + + double m_pencil; + double m_smooth; +}; + +} // NameSpace DigikamCharcoalImagesPlugin + +#endif /* CHARCOAL_H */ diff --git a/src/imageplugins/charcoal/charcoaltool.cpp b/src/imageplugins/charcoal/charcoaltool.cpp new file mode 100644 index 00000000..75ee22df --- /dev/null +++ b/src/imageplugins/charcoal/charcoaltool.cpp @@ -0,0 +1,202 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-26 + * Description : a digikam image editor plugin to + * simulate charcoal drawing. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqlabel.h> +#include <tqwhatsthis.h> +#include <tqlayout.h> + +// KDE includes. + +#include <tdeconfig.h> +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <kstandarddirs.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "imagepanelwidget.h" +#include "editortoolsettings.h" +#include "charcoal.h" +#include "charcoaltool.h" +#include "charcoaltool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamCharcoalImagesPlugin +{ + +CharcoalTool::CharcoalTool(TQObject* parent) + : EditorToolThreaded(parent) +{ + setName("charcoal"); + setToolName(i18n("Charcoal")); + setToolIcon(SmallIcon("charcoaltool")); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel| + EditorToolSettings::Try, + EditorToolSettings::PanIcon); + TQGridLayout* grid = new TQGridLayout( m_gboxSettings->plainPage(), 4, 1); + TQLabel *label1 = new TQLabel(i18n("Pencil size:"), m_gboxSettings->plainPage()); + + m_pencilInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_pencilInput->setRange(1, 100, 1); + m_pencilInput->setDefaultValue(5); + TQWhatsThis::add( m_pencilInput, i18n("<p>Set here the charcoal pencil size used to simulate the drawing.")); + + // ------------------------------------------------------------- + + TQLabel *label2 = new TQLabel(i18n("Smooth:"), m_gboxSettings->plainPage()); + + m_smoothInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_smoothInput->setRange(1, 100, 1); + m_smoothInput->setDefaultValue(10); + TQWhatsThis::add( m_smoothInput, i18n("<p>This value controls the smoothing effect of the pencil " + "under the canvas.")); + + grid->addMultiCellWidget(label1, 0, 0, 0, 1); + grid->addMultiCellWidget(m_pencilInput, 1, 1, 0, 1); + grid->addMultiCellWidget(label2, 2, 2, 0, 1); + grid->addMultiCellWidget(m_smoothInput, 3, 3, 0, 1); + grid->setRowStretch(4, 10); + grid->setMargin(m_gboxSettings->spacingHint()); + grid->setSpacing(m_gboxSettings->spacingHint()); + + setToolSettings(m_gboxSettings); + + // ------------------------------------------------------------- + + m_previewWidget = new ImagePanelWidget(470, 350, "charcoal Tool", m_gboxSettings->panIconView()); + + setToolView(m_previewWidget); + init(); + + // ------------------------------------------------------------- + + connect(m_pencilInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_smoothInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); +} + +CharcoalTool::~CharcoalTool() +{ +} + +void CharcoalTool::renderingFinished() +{ + m_pencilInput->setEnabled(true); + m_smoothInput->setEnabled(true); +} + +void CharcoalTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("charcoal Tool"); + m_pencilInput->blockSignals(true); + m_smoothInput->blockSignals(true); + + m_pencilInput->setValue(config->readNumEntry("PencilAjustment", m_pencilInput->defaultValue())); + m_smoothInput->setValue(config->readNumEntry("SmoothAjustment", m_smoothInput->defaultValue())); + + m_pencilInput->blockSignals(false); + m_smoothInput->blockSignals(false); +} + +void CharcoalTool::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("charcoal Tool"); + config->writeEntry("PencilAjustment", m_pencilInput->value()); + config->writeEntry("SmoothAjustment", m_smoothInput->value()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void CharcoalTool::slotResetSettings() +{ + m_pencilInput->blockSignals(true); + m_smoothInput->blockSignals(true); + + m_pencilInput->slotReset(); + m_smoothInput->slotReset(); + + m_pencilInput->blockSignals(false); + m_smoothInput->blockSignals(false); +} + +void CharcoalTool::prepareEffect() +{ + m_pencilInput->setEnabled(false); + m_smoothInput->setEnabled(false); + + double pencil = (double)m_pencilInput->value()/10.0; + double smooth = (double)m_smoothInput->value(); + + DImg image = m_previewWidget->getOriginalRegionImage(); + + setFilter(dynamic_cast<DImgThreadedFilter*>(new Charcoal(&image, this, pencil, smooth))); +} + +void CharcoalTool::prepareFinal() +{ + m_pencilInput->setEnabled(false); + m_smoothInput->setEnabled(false); + + double pencil = (double)m_pencilInput->value()/10.0; + double smooth = (double)m_smoothInput->value(); + + ImageIface iface(0, 0); + setFilter(dynamic_cast<DImgThreadedFilter*>(new Charcoal(iface.getOriginalImg(), this, pencil, smooth))); +} + +void CharcoalTool::putPreviewData() +{ + m_previewWidget->setPreviewImage(filter()->getTargetImage()); +} + +void CharcoalTool::putFinalData() +{ + ImageIface iface(0, 0); + iface.putOriginalImage(i18n("Charcoal"), filter()->getTargetImage().bits()); +} + +} // NameSpace DigikamCharcoalImagesPlugin diff --git a/src/imageplugins/charcoal/charcoaltool.h b/src/imageplugins/charcoal/charcoaltool.h new file mode 100644 index 00000000..5833dd06 --- /dev/null +++ b/src/imageplugins/charcoal/charcoaltool.h @@ -0,0 +1,82 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-26 + * Description : a digikam image editor plugin to + * simulate charcoal drawing. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef CHARCOALTOOL_H +#define CHARCOALTOOL_H + +// Local includes. + +#include "editortool.h" + +namespace KDcrawIface +{ +class RIntNumInput; +} + +namespace Digikam +{ +class EditorToolSettings; +class ImagePanelWidget; +} + +namespace DigikamCharcoalImagesPlugin +{ + +class CharcoalTool : public Digikam::EditorToolThreaded +{ + TQ_OBJECT + + +public: + + CharcoalTool(TQObject* parent); + ~CharcoalTool(); + +private slots: + + void slotResetSettings(); + +private: + + void readSettings(); + void writeSettings(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + KDcrawIface::RIntNumInput *m_pencilInput; + KDcrawIface::RIntNumInput *m_smoothInput; + + Digikam::ImagePanelWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamCharcoalImagesPlugin + +#endif /* CHARCOALTOOL_H */ diff --git a/src/imageplugins/charcoal/digikamimageplugin_charcoal.desktop b/src/imageplugins/charcoal/digikamimageplugin_charcoal.desktop new file mode 100644 index 00000000..e8957bbf --- /dev/null +++ b/src/imageplugins/charcoal/digikamimageplugin_charcoal.desktop @@ -0,0 +1,50 @@ +[Desktop Entry] +Name=ImagePlugin_Charcoal +Name[bg]=Приставка за снимки - Въглен +Name[da]=Billedplugin_Kultegning +Name[el]=ΠρόσθετοΕικόνας_Κάρβουνο +Name[fi]=Hiilipiirros +Name[hr]=Crtež ugljenom +Name[it]=PluginImmagini_Carboncino +Name[nl]=Afbeeldingsplugin_Houtskool +Name[sr]=Угљен +Name[sr@Latn]=Ugljen +Name[sv]=Insticksprogram för kolteckning +Name[tr]=ResimEklentisi_Karakalem +Name[xx]=xxImagePlugin_Charcoalxx +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=Charcoal drawing image effect plugin for digiKam +Comment[bg]=Приставка на digiKam за наподобяване на рисуване с въглен върху снимки +Comment[ca]=Connector pel digiKam d'efecte d'imatge de dibuix al carbonet +Comment[da]=Plugin til kultegningseffekt på billeder i Digikam +Comment[de]=digiKam-Modul zum Erzeugen eines Kohlezeichnung-Effekts +Comment[el]=Πρόσθετο εφέ σχεδίασης με κάρβουνο για το digiKam +Comment[es]=Plugin para digiKam con efectos de dibujo a carboncillo +Comment[et]=DigiKami söejoonistuse pildiefektiplugin +Comment[fa]=وصلۀ جلوۀ تصویر ترسیم Charcoal برای digiKam +Comment[fi]=Jäljittelee hiiliviivapiirrosta +Comment[gl]=Un plugin de digiKam para o efeito de imaxe debuxada ao carbón +Comment[hr]=digiKam dodatak za efekt crtanja ugljenom +Comment[is]=Íforrit fyrir digiKam sem líkir eftir viðarkolateikningu +Comment[it]=Plugin di effetto di disegno dell'immagine con carboncino per digiKam +Comment[ja]=digiKam 木炭画効果プラグイン +Comment[nds]=digiKam-Moduul för Kahlteken-Effekten +Comment[nl]=Digikam-plugin voor houtskooltekeningen +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਚਾਰਕੋਲ ਡਰਾਇੰਗ ਚਿੱਤਰ ਪਰਭਾਵ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam imitująca szkice węglem +Comment[pt]=Um 'plugin' do digiKam para o efeito de imagem de desenho a carvão +Comment[pt_BR]=Plugin de efeito de carvão para o digiKam +Comment[ru]=Модуль изображения картинки углем для digiKam +Comment[sk]=digiKam plugin pre efekt kreslenia kriedou +Comment[sr]=Прикључак ефекта цртежа угљеном за digiKam +Comment[sr@Latn]=Priključak efekta crteža ugljenom za digiKam +Comment[sv]=Digikam insticksprogram för kolteckningsbildeffekt +Comment[tr]=digiKam için karakalem resim etkisi eklentisi +Comment[uk]=Втулок створення ефекту малювання вугільним олівцем для digiKam +Comment[vi]=Phần bổ sung hiệu ứng vẽ ảnh than gỗ cho digiKam +Comment[xx]=xxCharcoal drawing image effect plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_charcoal +author=Gilles Caulier, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/charcoal/digikamimageplugin_charcoal_ui.rc b/src/imageplugins/charcoal/digikamimageplugin_charcoal_ui.rc new file mode 100644 index 00000000..92ab4752 --- /dev/null +++ b/src/imageplugins/charcoal/digikamimageplugin_charcoal_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="6" name="digikamimageplugin_charcoal" > + + <MenuBar> + + <Menu name="Filters" ><text>F&ilters</text> + <Action name="imageplugin_charcoal" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action shortcut="" name="imageplugin_charcoal" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/charcoal/imageeffect_charcoal.cpp b/src/imageplugins/charcoal/imageeffect_charcoal.cpp new file mode 100644 index 00000000..67a0269d --- /dev/null +++ b/src/imageplugins/charcoal/imageeffect_charcoal.cpp @@ -0,0 +1,193 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-26 + * Description : a digikam image editor plugin to + * simulate charcoal drawing. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqlabel.h> +#include <tqwhatsthis.h> +#include <tqlayout.h> + +// KDE includes. + +#include <tdeconfig.h> +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <knuminput.h> +#include <kstandarddirs.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "charcoal.h" +#include "imageeffect_charcoal.h" +#include "imageeffect_charcoal.moc" + +namespace DigikamCharcoalImagesPlugin +{ + +ImageEffect_Charcoal::ImageEffect_Charcoal(TQWidget* parent) + : Digikam::CtrlPanelDlg(parent, i18n("Charcoal Drawing"), + "charcoal", false, false, true, + Digikam::ImagePannelWidget::SeparateViewAll) +{ + TQString whatsThis; + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Charcoal Drawing"), + digikam_version, + I18N_NOOP("A digiKam charcoal drawing image effect plugin."), + TDEAboutData::License_GPL, + "(c) 2004-2008, Gilles Caulier", + 0, + "http://www.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + setAboutData(about); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(m_imagePreviewWidget); + TQGridLayout* gridSettings = new TQGridLayout( gboxSettings, 3, 1, 0, spacingHint()); + TQLabel *label1 = new TQLabel(i18n("Pencil size:"), gboxSettings); + + m_pencilInput = new KIntNumInput(gboxSettings); + m_pencilInput->setRange(1, 100, 1, true); + m_pencilInput->setValue(5); + TQWhatsThis::add( m_pencilInput, i18n("<p>Set here the charcoal pencil size used to simulate the drawing.")); + + gridSettings->addMultiCellWidget(label1, 0, 0, 0, 1); + gridSettings->addMultiCellWidget(m_pencilInput, 1, 1, 0, 1); + + // ------------------------------------------------------------- + + TQLabel *label2 = new TQLabel(i18n("Smooth:"), gboxSettings); + + m_smoothInput = new KIntNumInput(gboxSettings); + m_smoothInput->setRange(1, 100, 1, true); + m_smoothInput->setValue(10); + TQWhatsThis::add( m_smoothInput, i18n("<p>This value controls the smoothing effect of the pencil " + "under the canvas.")); + + gridSettings->addMultiCellWidget(label2, 2, 2, 0, 1); + gridSettings->addMultiCellWidget(m_smoothInput, 3, 3, 0, 1); + + m_imagePreviewWidget->setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + connect(m_pencilInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_smoothInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); +} + +ImageEffect_Charcoal::~ImageEffect_Charcoal() +{ +} + +void ImageEffect_Charcoal::renderingFinished() +{ + m_pencilInput->setEnabled(true); + m_smoothInput->setEnabled(true); +} + +void ImageEffect_Charcoal::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("charcoal Tool Dialog"); + m_pencilInput->blockSignals(true); + m_smoothInput->blockSignals(true); + m_pencilInput->setValue(config->readNumEntry("PencilAjustment", 5)); + m_smoothInput->setValue(config->readNumEntry("SmoothAjustment", 10)); + m_pencilInput->blockSignals(false); + m_smoothInput->blockSignals(false); +} + +void ImageEffect_Charcoal::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("charcoal Tool Dialog"); + config->writeEntry("PencilAjustment", m_pencilInput->value()); + config->writeEntry("SmoothAjustment", m_smoothInput->value()); + config->sync(); +} + +void ImageEffect_Charcoal::resetValues() +{ + m_pencilInput->blockSignals(true); + m_smoothInput->blockSignals(true); + m_pencilInput->setValue(5); + m_smoothInput->setValue(10); + m_pencilInput->blockSignals(false); + m_smoothInput->blockSignals(false); +} + +void ImageEffect_Charcoal::prepareEffect() +{ + m_pencilInput->setEnabled(false); + m_smoothInput->setEnabled(false); + + double pencil = (double)m_pencilInput->value()/10.0; + double smooth = (double)m_smoothInput->value(); + + Digikam::DImg image = m_imagePreviewWidget->getOriginalRegionImage(); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>(new Charcoal(&image, this, pencil, smooth)); +} + +void ImageEffect_Charcoal::prepareFinal() +{ + m_pencilInput->setEnabled(false); + m_smoothInput->setEnabled(false); + + double pencil = (double)m_pencilInput->value()/10.0; + double smooth = (double)m_smoothInput->value(); + + Digikam::ImageIface iface(0, 0); + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>(new Charcoal(iface.getOriginalImg(), + this, pencil, smooth)); +} + +void ImageEffect_Charcoal::putPreviewData(void) +{ + m_imagePreviewWidget->setPreviewImage(m_threadedFilter->getTargetImage()); +} + +void ImageEffect_Charcoal::putFinalData(void) +{ + Digikam::ImageIface iface(0, 0); + iface.putOriginalImage(i18n("Charcoal"), m_threadedFilter->getTargetImage().bits()); +} + +} // NameSpace DigikamCharcoalImagesPlugin + diff --git a/src/imageplugins/charcoal/imageeffect_charcoal.h b/src/imageplugins/charcoal/imageeffect_charcoal.h new file mode 100644 index 00000000..31916ecc --- /dev/null +++ b/src/imageplugins/charcoal/imageeffect_charcoal.h @@ -0,0 +1,69 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-26 + * Description : a digikam image editor plugin to + * simulate charcoal drawing. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_CHARCOAL_H +#define IMAGEEFFECT_CHARCOAL_H + +// Local includes. + +#include "ctrlpaneldlg.h" + +class KIntNumInput; + +namespace DigikamCharcoalImagesPlugin +{ + +class ImageEffect_Charcoal : public Digikam::CtrlPanelDlg +{ + TQ_OBJECT + + +public: + + ImageEffect_Charcoal(TQWidget* parent); + ~ImageEffect_Charcoal(); + +private slots: + + void readUserSettings(); + +private: + + void writeUserSettings(); + void resetValues(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + KIntNumInput *m_pencilInput; + KIntNumInput *m_smoothInput; +}; + +} // NameSpace DigikamCharcoalImagesPlugin + +#endif /* IMAGEEFFECT_CHARCOAL_H */ diff --git a/src/imageplugins/charcoal/imageplugin_charcoal.cpp b/src/imageplugins/charcoal/imageplugin_charcoal.cpp new file mode 100644 index 00000000..ae28e7ca --- /dev/null +++ b/src/imageplugins/charcoal/imageplugin_charcoal.cpp @@ -0,0 +1,72 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-26 + * Description : a digikam image editor plugin to + * simulate charcoal drawing. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> +#include <tdeapplication.h> + +// Local includes. + +#include "ddebug.h" +#include "charcoaltool.h" +#include "imageplugin_charcoal.h" +#include "imageplugin_charcoal.moc" + +using namespace DigikamCharcoalImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_charcoal, + KGenericFactory<ImagePlugin_Charcoal>("digikamimageplugin_charcoal")); + +ImagePlugin_Charcoal::ImagePlugin_Charcoal(TQObject *parent, const char*, + const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_Charcoal") +{ + m_charcoalAction = new TDEAction(i18n("Charcoal Drawing..."), "charcoaltool", 0, + this, TQ_SLOT(slotCharcoal()), + actionCollection(), "imageplugin_charcoal"); + + setXMLFile( "digikamimageplugin_charcoal_ui.rc" ); + + DDebug() << "ImagePlugin_Charcoal plugin loaded" << endl; +} + +ImagePlugin_Charcoal::~ImagePlugin_Charcoal() +{ +} + +void ImagePlugin_Charcoal::setEnabledActions(bool enable) +{ + m_charcoalAction->setEnabled(enable); +} + +void ImagePlugin_Charcoal::slotCharcoal() +{ + CharcoalTool *tool = new CharcoalTool(this); + loadTool(tool); +} diff --git a/src/imageplugins/charcoal/imageplugin_charcoal.h b/src/imageplugins/charcoal/imageplugin_charcoal.h new file mode 100644 index 00000000..c642087a --- /dev/null +++ b/src/imageplugins/charcoal/imageplugin_charcoal.h @@ -0,0 +1,57 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-26 + * Description : a digikam image editor plugin to + * simulate charcoal drawing. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_CHARCOAL_H +#define IMAGEPLUGIN_CHARCOAL_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_Charcoal : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_Charcoal(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_Charcoal(); + + void setEnabledActions(bool enable); + +private slots: + + void slotCharcoal(); + +private: + + TDEAction *m_charcoalAction; +}; + +#endif /* IMAGEPLUGIN_CHARCOAL_H */ diff --git a/src/imageplugins/colorfx/Makefile.am b/src/imageplugins/colorfx/Makefile.am new file mode 100644 index 00000000..a0d2e4fa --- /dev/null +++ b/src/imageplugins/colorfx/Makefile.am @@ -0,0 +1,34 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_colorfx_la_SOURCES = imageplugin_colorfx.cpp \ + colorfxtool.cpp + +digikamimageplugin_colorfx_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_colorfx_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_colorfx.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_colorfx.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_colorfx_ui.rc + diff --git a/src/imageplugins/colorfx/colorfxtool.cpp b/src/imageplugins/colorfx/colorfxtool.cpp new file mode 100644 index 00000000..dd16e7cf --- /dev/null +++ b/src/imageplugins/colorfx/colorfxtool.cpp @@ -0,0 +1,699 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-02-14 + * Description : a digiKam image plugin for to apply a color + * effect to an image. + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqcombobox.h> +#include <tqframe.h> +#include <tqhbuttongroup.h> +#include <tqhgroupbox.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqpushbutton.h> +#include <tqtooltip.h> +#include <tqvbox.h> +#include <tqvgroupbox.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <khelpmenu.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <tdepopupmenu.h> +#include <kstandarddirs.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> +#include <libkdcraw/rcombobox.h> + +// Local includes. + +#include "colorgradientwidget.h" +#include "daboutdata.h" +#include "ddebug.h" +#include "dimg.h" +#include "dimgimagefilters.h" +#include "editortoolsettings.h" +#include "histogramwidget.h" +#include "imagecurves.h" +#include "imagehistogram.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "colorfxtool.h" +#include "colorfxtool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamColorFXImagesPlugin +{ + +ColorFXTool::ColorFXTool(TQObject* parent) + : EditorTool(parent) +{ + setName("coloreffects"); + setToolName(i18n("Color Effects")); + setToolIcon(SmallIcon("colorfx")); + + m_destinationPreviewData = 0; + + // ------------------------------------------------------------- + + m_previewWidget = new ImageWidget("coloreffects Tool", 0, + i18n("<p>This is the color effects preview")); + + setToolView(m_previewWidget); + + // ------------------------------------------------------------- + + EditorToolSettings *gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel); + + TQGridLayout* gridSettings = new TQGridLayout(gboxSettings->plainPage(), 9, 4); + + TQLabel *label1 = new TQLabel(i18n("Channel:"), gboxSettings->plainPage()); + label1->setAlignment(TQt::AlignRight | TQt::AlignVCenter); + m_channelCB = new TQComboBox(false, 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("<p>Select the histogram channel to display here:<p>" + "<b>Luminosity</b>: display the image's luminosity values.<p>" + "<b>Red</b>: display the red image-channel values.<p>" + "<b>Green</b>: display the green image-channel values.<p>" + "<b>Blue</b>: display the blue image-channel values.<p>")); + + m_scaleBG = new TQHButtonGroup(gboxSettings->plainPage()); + m_scaleBG->setExclusive(true); + m_scaleBG->setFrameShape(TQFrame::NoFrame); + m_scaleBG->setInsideMargin(0); + TQWhatsThis::add( m_scaleBG, i18n("<p>Select the histogram scale here.<p>" + "If the image's maximal counts are small, you can use the linear scale.<p>" + "Logarithmic scale can be used when the maximal counts 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("<p>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("<p>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); + + // ------------------------------------------------------------- + + TQVBox *histoBox = new TQVBox(gboxSettings->plainPage()); + m_histogramWidget = new HistogramWidget(256, 140, histoBox, false, true, true); + TQWhatsThis::add( m_histogramWidget, i18n("<p>Here you can see the target preview image histogram drawing " + "of the selected image channel. This one is re-computed at any " + "settings changes.")); + TQLabel *space = new TQLabel(histoBox); + space->setFixedHeight(1); + m_hGradient = new ColorGradientWidget( ColorGradientWidget::Horizontal, 10, histoBox ); + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + + // ------------------------------------------------------------- + + m_effectTypeLabel = new TQLabel(i18n("Type:"), gboxSettings->plainPage()); + + m_effectType = new RComboBox(gboxSettings->plainPage()); + m_effectType->insertItem(i18n("Solarize")); + m_effectType->insertItem(i18n("Vivid")); + m_effectType->insertItem(i18n("Neon")); + m_effectType->insertItem(i18n("Find Edges")); + m_effectType->setDefaultItem(Solarize); + TQWhatsThis::add( m_effectType, i18n("<p>Select the effect type to apply to the image here.<p>" + "<b>Solarize</b>: simulates solarization of photograph.<p>" + "<b>Vivid</b>: simulates the Velvia(tm) slide film colors.<p>" + "<b>Neon</b>: coloring the edges in a photograph to " + "reproduce a fluorescent light effect.<p>" + "<b>Find Edges</b>: detects the edges in a photograph " + "and their strength." + )); + + m_levelLabel = new TQLabel(i18n("Level:"), gboxSettings->plainPage()); + m_levelInput = new RIntNumInput(gboxSettings->plainPage()); + m_levelInput->setRange(0, 100, 1); + m_levelInput->setDefaultValue(0); + TQWhatsThis::add( m_levelInput, i18n("<p>Set here the level of the effect.")); + + m_iterationLabel = new TQLabel(i18n("Iteration:"), gboxSettings->plainPage()); + m_iterationInput = new RIntNumInput(gboxSettings->plainPage()); + m_iterationInput->setRange(0, 100, 1); + m_iterationInput->setDefaultValue(0); + TQWhatsThis::add( m_iterationInput, i18n("<p>This value controls the number of iterations " + "to use with the Neon and Find Edges effects.")); + + gridSettings->addMultiCellLayout(l1, 0, 0, 0, 4); + gridSettings->addMultiCellWidget(histoBox, 1, 2, 0, 4); + gridSettings->addMultiCellWidget(m_effectTypeLabel, 3, 3, 0, 4); + gridSettings->addMultiCellWidget(m_effectType, 4, 4, 0, 4); + gridSettings->addMultiCellWidget(m_levelLabel, 5, 5, 0, 4); + gridSettings->addMultiCellWidget(m_levelInput, 6, 6, 0, 4); + gridSettings->addMultiCellWidget(m_iterationLabel, 7, 7, 0, 4); + gridSettings->addMultiCellWidget(m_iterationInput, 8, 8, 0, 4); + gridSettings->setRowStretch(9, 10); + + setToolSettings(gboxSettings); + init(); + + // ------------------------------------------------------------- + + 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_previewWidget, TQ_SIGNAL(spotPositionChangedFromTarget( const DColor &, const TQPoint & )), + this, TQ_SLOT(slotColorSelectedFromTarget( const DColor & ))); + + connect(m_levelInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_iterationInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_previewWidget, TQ_SIGNAL(signalResized()), + this, TQ_SLOT(slotEffect())); + + connect(m_effectType, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotEffectTypeChanged(int))); +} + +ColorFXTool::~ColorFXTool() +{ + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; +} + +void ColorFXTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("coloreffect Tool"); + m_effectType->setCurrentItem(config->readNumEntry("EffectType", m_effectType->defaultItem())); + m_levelInput->setValue(config->readNumEntry("LevelAjustment", m_levelInput->defaultValue())); + m_iterationInput->setValue(config->readNumEntry("IterationAjustment", m_iterationInput->defaultValue())); + slotEffectTypeChanged(m_effectType->currentItem()); //check for enable/disable of iteration + + m_histogramWidget->reset(); + slotChannelChanged(m_channelCB->currentItem()); + slotScaleChanged(m_scaleBG->selectedId()); +} + +void ColorFXTool::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("coloreffect Tool"); + config->writeEntry("EffectType", m_effectType->currentItem()); + config->writeEntry("LevelAjustment", m_levelInput->value()); + config->writeEntry("IterationAjustment", m_iterationInput->value()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void ColorFXTool::slotResetSettings() +{ + m_levelInput->blockSignals(true); + m_iterationInput->blockSignals(true); + m_effectType->blockSignals(true); + + m_levelInput->slotReset(); + m_iterationInput->slotReset(); + m_effectType->slotReset(); + + m_levelInput->blockSignals(false); + m_iterationInput->blockSignals(false); + m_effectType->blockSignals(false); + + slotEffect(); +} + +void ColorFXTool::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 ColorFXTool::slotScaleChanged(int scale) +{ + m_histogramWidget->m_scaleType = scale; + m_histogramWidget->repaint(false); +} + +void ColorFXTool::slotColorSelectedFromTarget(const DColor &color) +{ + m_histogramWidget->setHistogramGuideByColor(color); +} + +void ColorFXTool::slotEffectTypeChanged(int type) +{ + m_levelInput->setEnabled(true); + m_levelLabel->setEnabled(true); + + m_levelInput->blockSignals(true); + m_iterationInput->blockSignals(true); + m_levelInput->setRange(0, 100, 1); + m_levelInput->setValue(25); + + switch (type) + { + case Solarize: + m_levelInput->setRange(0, 100, 1); + m_levelInput->setValue(0); + m_iterationInput->setEnabled(false); + m_iterationLabel->setEnabled(false); + break; + + case Vivid: + m_levelInput->setRange(0, 50, 1); + m_levelInput->setValue(5); + m_iterationInput->setEnabled(false); + m_iterationLabel->setEnabled(false); + break; + + case Neon: + case FindEdges: + m_levelInput->setRange(0, 5, 1); + m_levelInput->setValue(3); + m_iterationInput->setEnabled(true); + m_iterationLabel->setEnabled(true); + m_iterationInput->setRange(0, 5, 1); + m_iterationInput->setValue(2); + break; + } + + m_levelInput->blockSignals(false); + m_iterationInput->blockSignals(false); + + slotEffect(); +} + +void ColorFXTool::slotEffect() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + ImageIface* iface = m_previewWidget->imageIface(); + m_destinationPreviewData = iface->getPreviewImage(); + int w = iface->previewWidth(); + int h = iface->previewHeight(); + bool sb = iface->previewSixteenBit(); + + colorEffect(m_destinationPreviewData, w, h, sb); + + iface->putPreviewImage(m_destinationPreviewData); + m_previewWidget->updatePreview(); + + // Update histogram. + + m_histogramWidget->updateData(m_destinationPreviewData, w, h, sb, 0, 0, 0, false); + + kapp->restoreOverrideCursor(); +} + +void ColorFXTool::finalRendering() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + ImageIface* iface = m_previewWidget->imageIface(); + uchar *data = iface->getOriginalImage(); + int w = iface->originalWidth(); + int h = iface->originalHeight(); + bool sb = iface->originalSixteenBit(); + + if (data) + { + colorEffect(data, w, h, sb); + TQString name; + + switch (m_effectType->currentItem()) + { + case Solarize: + name = i18n("ColorFX"); + break; + + case Vivid: + name = i18n("Vivid"); + break; + + case Neon: + name = i18n("Neon"); + break; + + case FindEdges: + name = i18n("Find Edges"); + break; + } + + iface->putOriginalImage(name, data); + delete[] data; + } + + kapp->restoreOverrideCursor(); +} + +void ColorFXTool::colorEffect(uchar *data, int w, int h, bool sb) +{ + switch (m_effectType->currentItem()) + { + case Solarize: + solarize(m_levelInput->value(), data, w, h, sb); + break; + + case Vivid: + vivid(m_levelInput->value(), data, w, h, sb); + break; + + case Neon: + neon(data, w, h, sb, m_levelInput->value(), m_iterationInput->value()); + break; + + case FindEdges: + findEdges(data, w, h, sb, m_levelInput->value(), m_iterationInput->value()); + break; + } +} + +void ColorFXTool::solarize(int factor, uchar *data, int w, int h, bool sb) +{ + bool stretch = true; + + if (!sb) // 8 bits image. + { + uint threshold = (uint)((100-factor)*(255+1)/100); + threshold = TQMAX(1, threshold); + uchar *ptr = data; + uchar a, r, g, b; + + for (int x=0 ; x < w*h ; x++) + { + b = ptr[0]; + g = ptr[1]; + r = ptr[2]; + a = ptr[3]; + + if (stretch) + { + r = (r > threshold) ? (255-r)*255/(255-threshold) : r*255/threshold; + g = (g > threshold) ? (255-g)*255/(255-threshold) : g*255/threshold; + b = (b > threshold) ? (255-b)*255/(255-threshold) : b*255/threshold; + } + else + { + if (r > threshold) + r = (255-r); + if (g > threshold) + g = (255-g); + if (b > threshold) + b = (255-b); + } + + ptr[0] = b; + ptr[1] = g; + ptr[2] = r; + ptr[3] = a; + + ptr += 4; + } + } + else // 16 bits image. + { + uint threshold = (uint)((100-factor)*(65535+1)/100); + threshold = TQMAX(1, threshold); + unsigned short *ptr = (unsigned short *)data; + unsigned short a, r, g, b; + + for (int x=0 ; x < w*h ; x++) + { + b = ptr[0]; + g = ptr[1]; + r = ptr[2]; + a = ptr[3]; + + if (stretch) + { + r = (r > threshold) ? (65535-r)*65535/(65535-threshold) : r*65535/threshold; + g = (g > threshold) ? (65535-g)*65535/(65535-threshold) : g*65535/threshold; + b = (b > threshold) ? (65535-b)*65535/(65535-threshold) : b*65535/threshold; + } + else + { + if (r > threshold) + r = (65535-r); + if (g > threshold) + g = (65535-g); + if (b > threshold) + b = (65535-b); + } + + ptr[0] = b; + ptr[1] = g; + ptr[2] = r; + ptr[3] = a; + + ptr += 4; + } + } +} + +void ColorFXTool::vivid(int factor, uchar *data, int w, int h, bool sb) +{ + float amount = factor/100.0; + + DImgImageFilters filter; + + // Apply Channel Mixer adjustments. + + filter.channelMixerImage( + data, w, h, sb, // Image data. + true, // Preserve Luminosity + false, // Disable Black & White mode. + 1.0 + amount + amount, (-1.0)*amount, (-1.0)*amount, // Red Gains. + (-1.0)*amount, 1.0 + amount + amount, (-1.0)*amount, // Green Gains. + (-1.0)*amount, (-1.0)*amount, 1.0 + amount + amount // Blue Gains. + ); + + // Allocate the destination image data. + + uchar *dest = new uchar[w*h*(sb ? 8 : 4)]; + + // And now apply the curve correction. + + ImageCurves Curves(sb); + + if (!sb) // 8 bits image. + { + Curves.setCurvePoint(ImageHistogram::ValueChannel, 0, TQPoint(0, 0)); + Curves.setCurvePoint(ImageHistogram::ValueChannel, 5, TQPoint(63, 60)); + Curves.setCurvePoint(ImageHistogram::ValueChannel, 10, TQPoint(191, 194)); + Curves.setCurvePoint(ImageHistogram::ValueChannel, 16, TQPoint(255, 255)); + } + else // 16 bits image. + { + Curves.setCurvePoint(ImageHistogram::ValueChannel, 0, TQPoint(0, 0)); + Curves.setCurvePoint(ImageHistogram::ValueChannel, 5, TQPoint(16128, 15360)); + Curves.setCurvePoint(ImageHistogram::ValueChannel, 10, TQPoint(48896, 49664)); + Curves.setCurvePoint(ImageHistogram::ValueChannel, 16, TQPoint(65535, 65535)); + } + + Curves.curvesCalculateCurve(ImageHistogram::AlphaChannel); // Calculate cure on all channels. + Curves.curvesLutSetup(ImageHistogram::AlphaChannel); // ... and apply it on all channels + Curves.curvesLutProcess(data, dest, w, h); + + memcpy(data, dest, w*h*(sb ? 8 : 4)); + delete [] dest; +} + +/* Function to apply the Neon effect + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Intensity => Intensity value + * BW => Border Width + * + * Theory => Wow, this is a great effect, you've never seen a Neon effect + * like this on PSC. Is very similar to Growing Edges (photoshop) + * Some pictures will be very interesting + */ +void ColorFXTool::neon(uchar *data, int w, int h, bool sb, int Intensity, int BW) +{ + neonFindEdges(data, w, h, sb, true, Intensity, BW); +} + +/* Function to apply the Find Edges effect + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Intensity => Intensity value + * BW => Border Width + * + * Theory => Wow, another Photoshop filter (FindEdges). Do you understand + * Neon effect ? This is the same engine, but is inversed with + * 255 - color. + */ +void ColorFXTool::findEdges(uchar *data, int w, int h, bool sb, int Intensity, int BW) +{ + neonFindEdges(data, w, h, sb, false, Intensity, BW); +} + +// Implementation of neon and FindEdges. They share 99% of their code. +void ColorFXTool::neonFindEdges(uchar *data, int w, int h, bool sb, bool neon, int Intensity, int BW) +{ + int Width = w; + int Height = h; + bool sixteenBit = sb; + int bytesDepth = sb ? 8 : 4; + uchar* pResBits = new uchar[Width*Height*bytesDepth]; + + Intensity = (Intensity < 0) ? 0 : (Intensity > 5) ? 5 : Intensity; + BW = (BW < 1) ? 1 : (BW > 5) ? 5 : BW; + + uchar *ptr, *ptr1, *ptr2; + + // these must be uint, we need full 2^32 range for 16 bit + uint color_1, color_2, colorPoint, colorOther1, colorOther2; + + // initial copy + memcpy (pResBits, data, Width*Height*bytesDepth); + + double intensityFactor = sqrt( 1 << Intensity ); + + for (int h = 0; h < Height; h++) + { + for (int w = 0; w < Width; w++) + { + ptr = pResBits + getOffset(Width, w, h, bytesDepth); + ptr1 = pResBits + getOffset(Width, w + Lim_Max (w, BW, Width), h, bytesDepth); + ptr2 = pResBits + getOffset(Width, w, h + Lim_Max (h, BW, Height), bytesDepth); + + if (sixteenBit) + { + for (int k = 0; k <= 2; k++) + { + colorPoint = ((unsigned short *)ptr)[k]; + colorOther1 = ((unsigned short *)ptr1)[k]; + colorOther2 = ((unsigned short *)ptr2)[k]; + color_1 = (colorPoint - colorOther1) * (colorPoint - colorOther1); + color_2 = (colorPoint - colorOther2) * (colorPoint - colorOther2); + + // old algorithm was + // sqrt ((color_1 + color_2) << Intensity) + // As (a << I) = a * (1 << I) = a * (2^I), and we can split the square root + + if (neon) + ((unsigned short *)ptr)[k] = CLAMP065535 ((int)( sqrt((double)color_1 + color_2) * intensityFactor )); + else + ((unsigned short *)ptr)[k] = 65535 - CLAMP065535 ((int)( sqrt((double)color_1 + color_2) * intensityFactor )); + } + } + else + { + for (int k = 0; k <= 2; k++) + { + colorPoint = ptr[k]; + colorOther1 = ptr1[k]; + colorOther2 = ptr2[k]; + color_1 = (colorPoint - colorOther1) * (colorPoint - colorOther1); + color_2 = (colorPoint - colorOther2) * (colorPoint - colorOther2); + + if (neon) + ptr[k] = CLAMP0255 ((int)( sqrt((double)color_1 + color_2) * intensityFactor )); + else + ptr[k] = 255 - CLAMP0255 ((int)( sqrt((double)color_1 + color_2) * intensityFactor )); + } + } + } + } + + memcpy (data, pResBits, Width*Height*bytesDepth); + delete [] pResBits; +} + +int ColorFXTool::getOffset(int Width, int X, int Y, int bytesDepth) +{ + return (Y * Width * bytesDepth) + (X * bytesDepth); +} + +inline int ColorFXTool::Lim_Max(int Now, int Up, int Max) +{ + --Max; + while (Now > Max - Up) --Up; + return (Up); +} + +} // NameSpace DigikamColorFXImagesPlugin + diff --git a/src/imageplugins/colorfx/colorfxtool.h b/src/imageplugins/colorfx/colorfxtool.h new file mode 100644 index 00000000..6040f53e --- /dev/null +++ b/src/imageplugins/colorfx/colorfxtool.h @@ -0,0 +1,136 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-02-14 + * Description : a digiKam image plugin for to apply a color + * effect to an image. + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * 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. + * + * ============================================================ */ + +#ifndef COLORFXTOOL_H +#define COLORFXTOOL_H + +// Digikam includes. + +#include "editortool.h" + +class TQHButtonGroup; +class TQComboBox; +class TQLabel; + +namespace KDcrawIface +{ +class RIntNumInput; +class RComboBox; +} + +namespace Digikam +{ +class ImageWidget; +class ColorGradientWidget; +class HistogramWidget; +class DColor; +} + +namespace DigikamColorFXImagesPlugin +{ + +class ColorFXTool : public Digikam::EditorTool +{ + TQ_OBJECT + + +public: + + ColorFXTool(TQObject *parent); + ~ColorFXTool(); + +private: + + void readSettings(); + void writeSettings(); + void finalRendering(); + void colorEffect(uchar *data, int w, int h, bool sb); + void solarize(int factor, uchar *data, int w, int h, bool sb); + void vivid(int factor, uchar *data, int w, int h, bool sb); + void neon(uchar *data, int w, int h, bool sb, int Intensity, int BW); + void findEdges(uchar *data, int w, int h, bool sb, int Intensity, int BW); + void neonFindEdges(uchar *data, int w, int h, bool sb, bool neon, int Intensity, int BW); + + inline int getOffset(int Width, int X, int Y, int bytesDepth); + inline int Lim_Max(int Now, int Up, int Max); + +private slots: + + void slotEffectTypeChanged(int type); + void slotEffect(); + void slotResetSettings(); + void slotChannelChanged(int channel); + void slotScaleChanged(int scale); + void slotColorSelectedFromTarget(const Digikam::DColor &color); + +private: + + enum HistogramScale + { + Linear=0, + Logarithmic + }; + + enum ColorChannel + { + LuminosityChannel=0, + RedChannel, + GreenChannel, + BlueChannel + }; + + enum ColorFXTypes + { + Solarize=0, + Vivid, + Neon, + FindEdges + }; + + uchar *m_destinationPreviewData; + + TQComboBox *m_channelCB; + + TQHButtonGroup *m_scaleBG; + + TQLabel *m_effectTypeLabel; + TQLabel *m_levelLabel; + TQLabel *m_iterationLabel; + + KDcrawIface::RIntNumInput *m_levelInput; + KDcrawIface::RIntNumInput *m_iterationInput; + + KDcrawIface::RComboBox *m_effectType; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::ColorGradientWidget *m_hGradient; + + Digikam::HistogramWidget *m_histogramWidget; +}; + +} // NameSpace DigikamColorFXImagesPlugin + +#endif /* COLORFXTOOL_H */ diff --git a/src/imageplugins/colorfx/digikamimageplugin_colorfx.desktop b/src/imageplugins/colorfx/digikamimageplugin_colorfx.desktop new file mode 100644 index 00000000..7350f6d9 --- /dev/null +++ b/src/imageplugins/colorfx/digikamimageplugin_colorfx.desktop @@ -0,0 +1,40 @@ +[Desktop Entry] +Name=ImagePlugin_ColorFx +Name[fi]=Väriefektit +Name[it]=PluginImmagini_EffettiDiColore +Name[nl]=Afbeeldingsplugin_Kleureffecten +Name[sr]=Ефекти боје +Name[sr@Latn]=Efekti boje +Name[sv]=Insticksprogram med färgeffekter +Name[tr]=ResimEklentisi_RenkFx +Name[xx]=xxImagePlugin_ColorFxxx +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=Color special effects plugin for digiKam +Comment[ca]=Connector pel digiKam d'efectes especials de color +Comment[da]=Digikam plugin med specialeffekter for farve +Comment[de]=digiKam-Modul zum Erzeugen von speziellen Farbeffekten +Comment[el]=Πρόσθετο ειδικών εφέ χρώματος για το digiKam +Comment[es]=Plugin para digiKam con efectos especiales de color +Comment[et]=DigiKami värvieriefektide plugin +Comment[fi]=Erikoisia väritehosteita +Comment[is]=Íforrit fyrir digiKam sem litmeðhöndlar sérstaklega myndir +Comment[it]=Plugin degli effetti speciali dei colori per digiKam +Comment[ja]=digiKam 色特殊効果プラグイン +Comment[nds]=digiKam-Moduul för Klöör-Effekten +Comment[nl]=Digikam-plugin voor kleureffecten +Comment[pl]=Wtyczka specjalnych efektów koloru do programu digiKam +Comment[pt]=Um 'plugin' do digiKam para efeitos especiais de cores +Comment[pt_BR]=Plugin de efeitos especiais de Cor +Comment[sk]=digiKam plugin pre špeciálne farebné efekty +Comment[sr]=Прикључак посебних ефеката боје за digiKam +Comment[sr@Latn]=Priključak posebnih efekata boje za digiKam +Comment[sv]=Digikam insticksprogram med specialeffekter för färg +Comment[tr]=digiKam için özel renk eklentisi +Comment[uk]=Втулок спецефектів кольорів для digiKam +Comment[vi]=Phần bổ sung hiệu ứng màu sắc cho digiKam +Comment[xx]=xxColor special effects plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_colorfx +author=Caulier Gilles, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/colorfx/digikamimageplugin_colorfx_ui.rc b/src/imageplugins/colorfx/digikamimageplugin_colorfx_ui.rc new file mode 100644 index 00000000..443a00bd --- /dev/null +++ b/src/imageplugins/colorfx/digikamimageplugin_colorfx_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="7" name="digikamimageplugin_colorfx" > + + <MenuBar> + + <Menu name="Color" ><text>&Color</text> + <Action name="imageplugin_colorfx" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action shortcut="" name="imageplugin_colorfx" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/colorfx/imageeffect_colorfx.cpp b/src/imageplugins/colorfx/imageeffect_colorfx.cpp new file mode 100644 index 00000000..a4ab6fe7 --- /dev/null +++ b/src/imageplugins/colorfx/imageeffect_colorfx.cpp @@ -0,0 +1,690 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-02-14 + * Description : a digiKam image plugin for to apply a color + * effect to an image. + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqvgroupbox.h> +#include <tqhgroupbox.h> +#include <tqhbuttongroup.h> +#include <tqcombobox.h> +#include <tqlabel.h> +#include <tqpushbutton.h> +#include <tqwhatsthis.h> +#include <tqlayout.h> +#include <tqframe.h> +#include <tqvbox.h> +#include <tqtooltip.h> + +// KDE includes. + +#include <tdeconfig.h> +#include <knuminput.h> +#include <tdelocale.h> +#include <kcursor.h> +#include <tdeaboutdata.h> +#include <khelpmenu.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <tdepopupmenu.h> +#include <kstandarddirs.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "dimg.h" +#include "dimgimagefilters.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "imagecurves.h" +#include "imagehistogram.h" +#include "histogramwidget.h" +#include "colorgradientwidget.h" +#include "imageeffect_colorfx.h" +#include "imageeffect_colorfx.moc" + +namespace DigikamColorFXImagesPlugin +{ + +ImageEffect_ColorFX::ImageEffect_ColorFX(TQWidget* parent) + : Digikam::ImageDlgBase(parent, + i18n("Apply Color Special Effects to Photograph"), + "coloreffect", false, false) +{ + m_destinationPreviewData = 0; + + // About data and help button. + + TDEAboutData *about = new TDEAboutData("digikam", + I18N_NOOP("Color Effects"), + digikam_version, + I18N_NOOP("A digiKam plugin to apply special color effects to an image."), + TDEAboutData::License_GPL, + "(c) 2004-2005, Renchi Raju\n(c) 2006-2008, Gilles Caulier", + 0, + "http://www.digikam.org"); + + about->addAuthor("Renchi Raju", I18N_NOOP("Original Author"), + "renchi@pooh.tam.uiuc.edu"); + + about->addAuthor("Caulier Gilles", I18N_NOOP("Maintainer"), + "caulier dot gilles at gmail dot com"); + + setAboutData(about); + + // ------------------------------------------------------------- + + m_previewWidget = new Digikam::ImageWidget("coloreffect Tool Dialog", plainPage(), + i18n("<p>This is the color effect preview")); + + setPreviewAreaWidget(m_previewWidget); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(plainPage()); + TQGridLayout* gridSettings = new TQGridLayout( gboxSettings, 9, 4, spacingHint()); + + TQLabel *label1 = new TQLabel(i18n("Channel:"), gboxSettings); + label1->setAlignment ( TQt::AlignRight | TQt::AlignVCenter ); + m_channelCB = new TQComboBox( false, gboxSettings ); + 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("<p>Select the histogram channel to display here:<p>" + "<b>Luminosity</b>: display the image's luminosity values.<p>" + "<b>Red</b>: display the red image-channel values.<p>" + "<b>Green</b>: display the green image-channel values.<p>" + "<b>Blue</b>: display the blue image-channel values.<p>")); + + m_scaleBG = new TQHButtonGroup(gboxSettings); + m_scaleBG->setExclusive(true); + m_scaleBG->setFrameShape(TQFrame::NoFrame); + m_scaleBG->setInsideMargin( 0 ); + TQWhatsThis::add( m_scaleBG, i18n("<p>Select the histogram scale here.<p>" + "If the image's maximal counts are small, you can use the linear scale.<p>" + "Logarithmic scale can be used when the maximal counts 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( "<p>Linear" ) ); + m_scaleBG->insert(linHistoButton, Digikam::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( "<p>Logarithmic" ) ); + m_scaleBG->insert(logHistoButton, Digikam::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, 4); + + // ------------------------------------------------------------- + + TQVBox *histoBox = new TQVBox(gboxSettings); + m_histogramWidget = new Digikam::HistogramWidget(256, 140, histoBox, false, true, true); + TQWhatsThis::add( m_histogramWidget, i18n("<p>Here you can see the target preview image histogram drawing " + "of the selected image channel. This one is re-computed at any " + "settings changes.")); + TQLabel *space = new TQLabel(histoBox); + space->setFixedHeight(1); + m_hGradient = new Digikam::ColorGradientWidget( Digikam::ColorGradientWidget::Horizontal, 10, histoBox ); + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + + gridSettings->addMultiCellWidget(histoBox, 1, 2, 0, 4); + + // ------------------------------------------------------------- + + m_effectTypeLabel = new TQLabel(i18n("Type:"), gboxSettings); + + m_effectType = new TQComboBox( false, gboxSettings ); + m_effectType->insertItem( i18n("Solarize") ); + m_effectType->insertItem( i18n("Vivid") ); + m_effectType->insertItem( i18n("Neon") ); + m_effectType->insertItem( i18n("Find Edges") ); + TQWhatsThis::add( m_effectType, i18n("<p>Select the effect type to apply to the image here.<p>" + "<b>Solarize</b>: simulates solarization of photograph.<p>" + "<b>Vivid</b>: simulates the Velvia(tm) slide film colors.<p>" + "<b>Neon</b>: coloring the edges in a photograph to " + "reproduce a fluorescent light effect.<p>" + "<b>Find Edges</b>: detects the edges in a photograph " + "and their strength." + )); + gridSettings->addMultiCellWidget(m_effectTypeLabel, 3, 3, 0, 4); + gridSettings->addMultiCellWidget(m_effectType, 4, 4, 0, 4); + + m_levelLabel = new TQLabel(i18n("Level:"), gboxSettings); + m_levelInput = new KIntNumInput(gboxSettings); + m_levelInput->setRange(0, 100, 1, true); + TQWhatsThis::add( m_levelInput, i18n("<p>Set here the level of the effect.")); + + gridSettings->addMultiCellWidget(m_levelLabel, 5, 5, 0, 4); + gridSettings->addMultiCellWidget(m_levelInput, 6, 6, 0, 4); + + m_iterationLabel = new TQLabel(i18n("Iteration:"), gboxSettings); + m_iterationInput = new KIntNumInput(gboxSettings); + m_iterationInput->setRange(0, 100, 1, true); + TQWhatsThis::add( m_iterationInput, i18n("<p>This value controls the number of iterations " + "to use with the Neon and Find Edges effects.")); + + gridSettings->addMultiCellWidget(m_iterationLabel, 7, 7, 0, 4); + gridSettings->addMultiCellWidget(m_iterationInput, 8, 8, 0, 4); + + gridSettings->setRowStretch(9, 10); + setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + 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_previewWidget, TQ_SIGNAL(spotPositionChangedFromTarget( const Digikam::DColor &, const TQPoint & )), + this, TQ_SLOT(slotColorSelectedFromTarget( const Digikam::DColor & ))); + + connect(m_levelInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_iterationInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_previewWidget, TQ_SIGNAL(signalResized()), + this, TQ_SLOT(slotEffect())); + + connect(m_effectType, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotEffectTypeChanged(int))); +} + +ImageEffect_ColorFX::~ImageEffect_ColorFX() +{ + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + delete m_previewWidget; +} + +void ImageEffect_ColorFX::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("coloreffect Tool Dialog"); + m_effectType->setCurrentItem(config->readNumEntry("EffectType", ColorFX)); + m_levelInput->setValue(config->readNumEntry("LevelAjustment", 0)); + m_iterationInput->setValue(config->readNumEntry("IterationAjustment", 3)); + slotEffectTypeChanged(m_effectType->currentItem()); //check for enable/disable of iteration +} + +void ImageEffect_ColorFX::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("coloreffect Tool Dialog"); + config->writeEntry("EffectType", m_effectType->currentItem()); + config->writeEntry("LevelAjustment", m_levelInput->value()); + config->writeEntry("IterationAjustment", m_iterationInput->value()); + config->sync(); +} + +void ImageEffect_ColorFX::resetValues() +{ + m_levelInput->setValue(0); +} + +void ImageEffect_ColorFX::slotChannelChanged(int channel) +{ + switch(channel) + { + case LuminosityChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::ValueHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + break; + + case RedChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::RedChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "red" ) ); + break; + + case GreenChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::GreenChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "green" ) ); + break; + + case BlueChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::BlueChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "blue" ) ); + break; + } + + m_histogramWidget->repaint(false); +} + +void ImageEffect_ColorFX::slotScaleChanged(int scale) +{ + m_histogramWidget->m_scaleType = scale; + m_histogramWidget->repaint(false); +} + +void ImageEffect_ColorFX::slotColorSelectedFromTarget( const Digikam::DColor &color ) +{ + m_histogramWidget->setHistogramGuideByColor(color); +} + +void ImageEffect_ColorFX::slotEffectTypeChanged(int type) +{ + m_levelInput->setEnabled(true); + m_levelLabel->setEnabled(true); + + m_levelInput->blockSignals(true); + m_iterationInput->blockSignals(true); + m_levelInput->setRange(0, 100, 1, true); + m_levelInput->setValue(25); + + switch (type) + { + case ColorFX: + m_levelInput->setRange(0, 100, 1, true); + m_levelInput->setValue(0); + m_iterationInput->setEnabled(false); + m_iterationLabel->setEnabled(false); + break; + + case Vivid: + m_levelInput->setRange(0, 50, 1, true); + m_levelInput->setValue(5); + m_iterationInput->setEnabled(false); + m_iterationLabel->setEnabled(false); + break; + + case Neon: + case FindEdges: + m_levelInput->setRange(0, 5, 1, true); + m_levelInput->setValue(3); + m_iterationInput->setEnabled(true); + m_iterationLabel->setEnabled(true); + m_iterationInput->setRange(0, 5, 1, true); + m_iterationInput->setValue(2); + break; + } + + m_levelInput->blockSignals(false); + m_iterationInput->blockSignals(false); + + slotEffect(); +} + +void ImageEffect_ColorFX::slotEffect() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + Digikam::ImageIface* iface = m_previewWidget->imageIface(); + uchar *m_destinationPreviewData = iface->getPreviewImage(); + int w = iface->previewWidth(); + int h = iface->previewHeight(); + bool sb = iface->previewSixteenBit(); + + colorEffect(m_destinationPreviewData, w, h, sb); + + iface->putPreviewImage(m_destinationPreviewData); + m_previewWidget->updatePreview(); + + // Update histogram. + + m_histogramWidget->updateData(m_destinationPreviewData, w, h, sb, 0, 0, 0, false); + + kapp->restoreOverrideCursor(); +} + +void ImageEffect_ColorFX::finalRendering() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + Digikam::ImageIface* iface = m_previewWidget->imageIface(); + uchar *data = iface->getOriginalImage(); + int w = iface->originalWidth(); + int h = iface->originalHeight(); + bool sb = iface->originalSixteenBit(); + + if (data) + { + colorEffect(data, w, h, sb); + TQString name; + + switch (m_effectType->currentItem()) + { + case ColorFX: + name = i18n("ColorFX"); + break; + + case Vivid: + name = i18n("Vivid"); + break; + + case Neon: + name = i18n("Neon"); + break; + + case FindEdges: + name = i18n("Find Edges"); + break; + } + + iface->putOriginalImage(name, data); + delete [] data; + } + + kapp->restoreOverrideCursor(); + accept(); +} + +void ImageEffect_ColorFX::colorEffect(uchar *data, int w, int h, bool sb) +{ + switch (m_effectType->currentItem()) + { + case ColorFX: + solarize(m_levelInput->value(), data, w, h, sb); + break; + + case Vivid: + vivid(m_levelInput->value(), data, w, h, sb); + break; + + case Neon: + neon(data, w, h, sb, m_levelInput->value(), m_iterationInput->value()); + break; + + case FindEdges: + findEdges(data, w, h, sb, m_levelInput->value(), m_iterationInput->value()); + break; + } +} + +void ImageEffect_ColorFX::solarize(int factor, uchar *data, int w, int h, bool sb) +{ + bool stretch = true; + + if (!sb) // 8 bits image. + { + uint threshold = (uint)((100-factor)*(255+1)/100); + threshold = TQMAX(1, threshold); + uchar *ptr = data; + uchar a, r, g, b; + + for (int x=0 ; x < w*h ; x++) + { + b = ptr[0]; + g = ptr[1]; + r = ptr[2]; + a = ptr[3]; + + if (stretch) + { + r = (r > threshold) ? (255-r)*255/(255-threshold) : r*255/threshold; + g = (g > threshold) ? (255-g)*255/(255-threshold) : g*255/threshold; + b = (b > threshold) ? (255-b)*255/(255-threshold) : b*255/threshold; + } + else + { + if (r > threshold) + r = (255-r); + if (g > threshold) + g = (255-g); + if (b > threshold) + b = (255-b); + } + + ptr[0] = b; + ptr[1] = g; + ptr[2] = r; + ptr[3] = a; + + ptr += 4; + } + } + else // 16 bits image. + { + uint threshold = (uint)((100-factor)*(65535+1)/100); + threshold = TQMAX(1, threshold); + unsigned short *ptr = (unsigned short *)data; + unsigned short a, r, g, b; + + for (int x=0 ; x < w*h ; x++) + { + b = ptr[0]; + g = ptr[1]; + r = ptr[2]; + a = ptr[3]; + + if (stretch) + { + r = (r > threshold) ? (65535-r)*65535/(65535-threshold) : r*65535/threshold; + g = (g > threshold) ? (65535-g)*65535/(65535-threshold) : g*65535/threshold; + b = (b > threshold) ? (65535-b)*65535/(65535-threshold) : b*65535/threshold; + } + else + { + if (r > threshold) + r = (65535-r); + if (g > threshold) + g = (65535-g); + if (b > threshold) + b = (65535-b); + } + + ptr[0] = b; + ptr[1] = g; + ptr[2] = r; + ptr[3] = a; + + ptr += 4; + } + } +} + +void ImageEffect_ColorFX::vivid(int factor, uchar *data, int w, int h, bool sb) +{ + float amount = factor/100.0; + + Digikam::DImgImageFilters filter; + + // Apply Channel Mixer adjustments. + + filter.channelMixerImage( + data, w, h, sb, // Image data. + true, // Preserve Luminosity + false, // Disable Black & White mode. + 1.0 + amount + amount, (-1.0)*amount, (-1.0)*amount, // Red Gains. + (-1.0)*amount, 1.0 + amount + amount, (-1.0)*amount, // Green Gains. + (-1.0)*amount, (-1.0)*amount, 1.0 + amount + amount // Blue Gains. + ); + + // Allocate the destination image data. + + uchar *dest = new uchar[w*h*(sb ? 8 : 4)]; + + // And now apply the curve correction. + + Digikam::ImageCurves Curves(sb); + + if (!sb) // 8 bits image. + { + Curves.setCurvePoint(Digikam::ImageHistogram::ValueChannel, 0, TQPoint(0, 0)); + Curves.setCurvePoint(Digikam::ImageHistogram::ValueChannel, 5, TQPoint(63, 60)); + Curves.setCurvePoint(Digikam::ImageHistogram::ValueChannel, 10, TQPoint(191, 194)); + Curves.setCurvePoint(Digikam::ImageHistogram::ValueChannel, 16, TQPoint(255, 255)); + } + else // 16 bits image. + { + Curves.setCurvePoint(Digikam::ImageHistogram::ValueChannel, 0, TQPoint(0, 0)); + Curves.setCurvePoint(Digikam::ImageHistogram::ValueChannel, 5, TQPoint(16128, 15360)); + Curves.setCurvePoint(Digikam::ImageHistogram::ValueChannel, 10, TQPoint(48896, 49664)); + Curves.setCurvePoint(Digikam::ImageHistogram::ValueChannel, 16, TQPoint(65535, 65535)); + } + + Curves.curvesCalculateCurve(Digikam::ImageHistogram::AlphaChannel); // Calculate cure on all channels. + Curves.curvesLutSetup(Digikam::ImageHistogram::AlphaChannel); // ... and apply it on all channels + Curves.curvesLutProcess(data, dest, w, h); + + memcpy(data, dest, w*h*(sb ? 8 : 4)); + delete [] dest; +} + +/* Function to apply the Neon effect + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Intensity => Intensity value + * BW => Border Width + * + * Theory => Wow, this is a great effect, you've never seen a Neon effect + * like this on PSC. Is very similar to Growing Edges (photoshop) + * Some pictures will be very interesting + */ +void ImageEffect_ColorFX::neon(uchar *data, int w, int h, bool sb, int Intensity, int BW) +{ + neonFindEdges(data, w, h, sb, true, Intensity, BW); +} + +/* Function to apply the Find Edges effect + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Intensity => Intensity value + * BW => Border Width + * + * Theory => Wow, another Photoshop filter (FindEdges). Do you understand + * Neon effect ? This is the same engine, but is inversed with + * 255 - color. + */ +void ImageEffect_ColorFX::findEdges(uchar *data, int w, int h, bool sb, int Intensity, int BW) +{ + neonFindEdges(data, w, h, sb, false, Intensity, BW); +} + +// Implementation of neon and FindEdges. They share 99% of their code. +void ImageEffect_ColorFX::neonFindEdges(uchar *data, int w, int h, bool sb, bool neon, int Intensity, int BW) +{ + int Width = w; + int Height = h; + bool sixteenBit = sb; + int bytesDepth = sb ? 8 : 4; + uchar* pResBits = new uchar[Width*Height*bytesDepth]; + + Intensity = (Intensity < 0) ? 0 : (Intensity > 5) ? 5 : Intensity; + BW = (BW < 1) ? 1 : (BW > 5) ? 5 : BW; + + uchar *ptr, *ptr1, *ptr2; + + // these must be uint, we need full 2^32 range for 16 bit + uint color_1, color_2, colorPoint, colorOther1, colorOther2; + + // initial copy + memcpy (pResBits, data, Width*Height*bytesDepth); + + double intensityFactor = sqrt( 1 << Intensity ); + + for (int h = 0; h < Height; h++) + { + for (int w = 0; w < Width; w++) + { + ptr = pResBits + getOffset(Width, w, h, bytesDepth); + ptr1 = pResBits + getOffset(Width, w + Lim_Max (w, BW, Width), h, bytesDepth); + ptr2 = pResBits + getOffset(Width, w, h + Lim_Max (h, BW, Height), bytesDepth); + + if (sixteenBit) + { + for (int k = 0; k <= 2; k++) + { + colorPoint = ((unsigned short *)ptr)[k]; + colorOther1 = ((unsigned short *)ptr1)[k]; + colorOther2 = ((unsigned short *)ptr2)[k]; + color_1 = (colorPoint - colorOther1) * (colorPoint - colorOther1); + color_2 = (colorPoint - colorOther2) * (colorPoint - colorOther2); + + // old algorithm was + // sqrt ((color_1 + color_2) << Intensity) + // As (a << I) = a * (1 << I) = a * (2^I), and we can split the square root + + if (neon) + ((unsigned short *)ptr)[k] = CLAMP065535 ((int)( sqrt(color_1 + color_2) * intensityFactor )); + else + ((unsigned short *)ptr)[k] = 65535 - CLAMP065535 ((int)( sqrt(color_1 + color_2) * intensityFactor )); + } + } + else + { + for (int k = 0; k <= 2; k++) + { + colorPoint = ptr[k]; + colorOther1 = ptr1[k]; + colorOther2 = ptr2[k]; + color_1 = (colorPoint - colorOther1) * (colorPoint - colorOther1); + color_2 = (colorPoint - colorOther2) * (colorPoint - colorOther2); + + if (neon) + ptr[k] = CLAMP0255 ((int)( sqrt(color_1 + color_2) * intensityFactor )); + else + ptr[k] = 255 - CLAMP0255 ((int)( sqrt(color_1 + color_2) * intensityFactor )); + } + } + } + } + + memcpy (data, pResBits, Width*Height*bytesDepth); + delete [] pResBits; +} + +int ImageEffect_ColorFX::getOffset(int Width, int X, int Y, int bytesDepth) +{ + return (Y * Width * bytesDepth) + (X * bytesDepth); +} + +inline int ImageEffect_ColorFX::Lim_Max(int Now, int Up, int Max) +{ + --Max; + while (Now > Max - Up) --Up; + return (Up); +} + +} // NameSpace DigikamColorFXImagesPlugin + diff --git a/src/imageplugins/colorfx/imageeffect_colorfx.h b/src/imageplugins/colorfx/imageeffect_colorfx.h new file mode 100644 index 00000000..d6d7d105 --- /dev/null +++ b/src/imageplugins/colorfx/imageeffect_colorfx.h @@ -0,0 +1,131 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-02-14 + * Description : a digiKam image plugin for to apply a color + * effect to an image. + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_COLORFX_H +#define IMAGEEFFECT_COLORFX_H + +// Digikam includes. + +#include "imagedlgbase.h" + +class TQHButtonGroup; +class TQComboBox; +class TQLabel; + +class KIntNumInput; + +namespace Digikam +{ +class ImageWidget; +class ColorGradientWidget; +class HistogramWidget; +class DColor; +} + +namespace DigikamColorFXImagesPlugin +{ + +class ImageEffect_ColorFX : public Digikam::ImageDlgBase +{ + TQ_OBJECT + + +public: + + ImageEffect_ColorFX(TQWidget *parent); + ~ImageEffect_ColorFX(); + +private: + + void readUserSettings(); + void writeUserSettings(); + void resetValues(); + void finalRendering(); + void colorEffect(uchar *data, int w, int h, bool sb); + void solarize(int factor, uchar *data, int w, int h, bool sb); + void vivid(int factor, uchar *data, int w, int h, bool sb); + void neon(uchar *data, int w, int h, bool sb, int Intensity, int BW); + void findEdges(uchar *data, int w, int h, bool sb, int Intensity, int BW); + void neonFindEdges(uchar *data, int w, int h, bool sb, bool neon, int Intensity, int BW); + + inline int getOffset(int Width, int X, int Y, int bytesDepth); + inline int Lim_Max(int Now, int Up, int Max); + +private slots: + + void slotEffectTypeChanged(int type); + void slotEffect(); + void slotChannelChanged(int channel); + void slotScaleChanged(int scale); + void slotColorSelectedFromTarget(const Digikam::DColor &color); + +private: + + enum HistogramScale + { + Linear=0, + Logarithmic + }; + + enum ColorChannel + { + LuminosityChannel=0, + RedChannel, + GreenChannel, + BlueChannel + }; + + enum ColorFXTypes + { + ColorFX=0, + Vivid, + Neon, + FindEdges + }; + + uchar *m_destinationPreviewData; + + TQComboBox *m_channelCB; + TQComboBox *m_effectType; + + TQHButtonGroup *m_scaleBG; + + TQLabel *m_effectTypeLabel; + TQLabel *m_levelLabel; + TQLabel *m_iterationLabel; + + KIntNumInput *m_levelInput; + KIntNumInput *m_iterationInput; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::ColorGradientWidget *m_hGradient; + + Digikam::HistogramWidget *m_histogramWidget; +}; + +} // NameSpace DigikamColorFXImagesPlugin + +#endif /* IMAGEEFFECT_COLORFX_H */ diff --git a/src/imageplugins/colorfx/imageplugin_colorfx.cpp b/src/imageplugins/colorfx/imageplugin_colorfx.cpp new file mode 100644 index 00000000..f4725028 --- /dev/null +++ b/src/imageplugins/colorfx/imageplugin_colorfx.cpp @@ -0,0 +1,73 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-02-14 + * Description : a digiKam image plugin for to apply a color + * effect to an image. + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * 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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> +#include <tdeapplication.h> + +// Local includes. + +#include "ddebug.h" +#include "colorfxtool.h" +#include "imageplugin_colorfx.h" +#include "imageplugin_colorfx.moc" + +using namespace DigikamColorFXImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_colorfx, + KGenericFactory<ImagePlugin_ColorFX>("digikamimageplugin_colorfx")); + +ImagePlugin_ColorFX::ImagePlugin_ColorFX(TQObject *parent, const char*, const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_ColorFX") +{ + m_solarizeAction = new TDEAction(i18n("Color Effects..."), "colorfx", 0, + this, TQ_SLOT(slotColorFX()), + actionCollection(), "imageplugin_colorfx"); + + setXMLFile( "digikamimageplugin_colorfx_ui.rc" ); + + DDebug() << "ImagePlugin_ColorFX plugin loaded" << endl; +} + +ImagePlugin_ColorFX::~ImagePlugin_ColorFX() +{ +} + +void ImagePlugin_ColorFX::setEnabledActions(bool enable) +{ + m_solarizeAction->setEnabled(enable); +} + +void ImagePlugin_ColorFX::slotColorFX() +{ + ColorFXTool *colorfx = new ColorFXTool(this); + loadTool(colorfx); +} + diff --git a/src/imageplugins/colorfx/imageplugin_colorfx.h b/src/imageplugins/colorfx/imageplugin_colorfx.h new file mode 100644 index 00000000..d7aaa83f --- /dev/null +++ b/src/imageplugins/colorfx/imageplugin_colorfx.h @@ -0,0 +1,57 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-02-14 + * Description : a digiKam image plugin for to apply a color + * effect to an image. + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * 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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_COLORFX_H +#define IMAGEPLUGIN_COLORFX_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_ColorFX : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_ColorFX(TQObject *parent, const char* name, const TQStringList &args); + ~ImagePlugin_ColorFX(); + + void setEnabledActions(bool enable); + +private slots: + + void slotColorFX(); + +private: + + TDEAction *m_solarizeAction; +}; + +#endif /* IMAGEPLUGIN_COLORFX_H */ diff --git a/src/imageplugins/coreplugin/Makefile.am b/src/imageplugins/coreplugin/Makefile.am new file mode 100644 index 00000000..b36d6f36 --- /dev/null +++ b/src/imageplugins/coreplugin/Makefile.am @@ -0,0 +1,52 @@ +SUBDIRS = sharpnesseditor hsl ratiocrop +COMPILE_FIRST = sharpnesseditor hsl ratiocrop +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + -I$(top_srcdir)/src/imageplugins/coreplugin/sharpnesseditor \ + -I$(top_srcdir)/src/imageplugins/coreplugin/hsl \ + -I$(top_srcdir)/src/imageplugins/coreplugin/ratiocrop \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_core_la_SOURCES = imageplugin_core.cpp bwsepiatool.cpp \ + autocorrectiontool.cpp \ + rgbtool.cpp \ + redeyetool.cpp blurtool.cpp \ + iccprooftool.cpp bcgtool.cpp + +noinst_HEADERS = autocorrectiontool.h blurtool.h \ + rgbtool.h bcgtool.h \ + bwsepiatool.h iccprooftool.h redeyetool.h + +digikamimageplugin_core_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/imageplugins/coreplugin/sharpnesseditor/libsharpnesseditor.la \ + $(top_builddir)/src/imageplugins/coreplugin/hsl/libhsl.la \ + $(top_builddir)/src/imageplugins/coreplugin/ratiocrop/libratiocrop.la \ + $(top_builddir)/src/digikam/libdigikam.la \ + $(top_builddir)/src/utilities/imageeditor/editor/libdimgeditor.la \ + $(top_builddir)/src/libs/curves/libcurves.la \ + $(top_builddir)/src/libs/widgets/common/libcommonwidgets.la \ + $(top_builddir)/src/libs/widgets/imageplugins/libimagepluginswidgets.la + +digikamimageplugin_core_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio -lkexiv2 -ltdeutils + +kde_services_DATA = digikamimageplugin_core.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_core.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_core_ui.rc diff --git a/src/imageplugins/coreplugin/autocorrectiontool.cpp b/src/imageplugins/coreplugin/autocorrectiontool.cpp new file mode 100644 index 00000000..32f00b44 --- /dev/null +++ b/src/imageplugins/coreplugin/autocorrectiontool.cpp @@ -0,0 +1,438 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-31 + * Description : Auto-Color correction tool. + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqcheckbox.h> +#include <tqcolor.h> +#include <tqcombobox.h> +#include <tqframe.h> +#include <tqgroupbox.h> +#include <tqhbuttongroup.h> +#include <tqhgroupbox.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqlistbox.h> +#include <tqpushbutton.h> +#include <tqradiobutton.h> +#include <tqtimer.h> +#include <tqtooltip.h> +#include <tqvbox.h> +#include <tqvgroupbox.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <kstandarddirs.h> + +// Digikam includes. + +#include "colorgradientwidget.h" +#include "dimg.h" +#include "dimgimagefilters.h" +#include "editortoolsettings.h" +#include "histogramwidget.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "listboxpreviewitem.h" +#include "whitebalance.h" + +// Local includes. + +#include "autocorrectiontool.h" +#include "autocorrectiontool.moc" + +using namespace Digikam; + +namespace DigikamImagesPluginCore +{ + +AutoCorrectionTool::AutoCorrectionTool(TQObject* parent) + : EditorTool(parent) +{ + setName("autocorrection"); + setToolName(i18n("Auto-Correction")); + setToolIcon(SmallIcon("autocorrection")); + setToolHelp("autocolorcorrectiontool.anchor"); + + // ------------------------------------------------------------- + + m_previewWidget = new ImageWidget("autocorrection Tool", 0, + i18n("<p>Here you can see the auto-color correction tool " + "preview. You can pick color on image " + "to see the color level corresponding on histogram.")); + setToolView(m_previewWidget); + + // ------------------------------------------------------------- + + ImageIface iface(0, 0); + m_thumbnailImage = iface.getOriginalImg()->smoothScale(128, 128, TQSize::ScaleMin); + m_destinationPreviewData = 0; + + EditorToolSettings *gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel); + + TQGridLayout* gridSettings = new TQGridLayout(gboxSettings->plainPage(), 2, 4); + + TQLabel *label1 = new TQLabel(i18n("Channel:"), gboxSettings->plainPage()); + label1->setAlignment ( TQt::AlignRight | TQt::AlignVCenter ); + m_channelCB = new TQComboBox( false, 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("<p>Select the histogram channel to display here:<p>" + "<b>Luminosity</b>: display the image's luminosity values.<p>" + "<b>Red</b>: display the red image-channel values.<p>" + "<b>Green</b>: display the green image-channel values.<p>" + "<b>Blue</b>: display the blue image-channel values.<p>")); + + m_scaleBG = new TQHButtonGroup(gboxSettings->plainPage()); + m_scaleBG->setExclusive(true); + m_scaleBG->setFrameShape(TQFrame::NoFrame); + m_scaleBG->setInsideMargin( 0 ); + TQWhatsThis::add( m_scaleBG, i18n("<p>Select the histogram scale here.<p>" + "If the image's maximal counts are small, you can use the linear scale.<p>" + "Logarithmic scale can be used when the maximal counts 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("<p>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("<p>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); + + // ------------------------------------------------------------- + + TQVBox *histoBox = new TQVBox(gboxSettings->plainPage()); + m_histogramWidget = new HistogramWidget(256, 140, histoBox, false, true, true); + TQWhatsThis::add( m_histogramWidget, i18n("<p>Here you can see the target preview image histogram drawing " + "of the selected image channel. This one is re-computed at any " + "settings changes.")); + TQLabel *space = new TQLabel(histoBox); + space->setFixedHeight(1); + m_hGradient = new ColorGradientWidget(ColorGradientWidget::Horizontal, 10, histoBox); + m_hGradient->setColors(TQColor("black"), TQColor("white")); + + // ------------------------------------------------------------- + + m_correctionTools = new TQListBox(gboxSettings->plainPage()); + m_correctionTools->setColumnMode(1); + m_correctionTools->setVariableWidth(false); + m_correctionTools->setVariableHeight(false); + ListBoxWhatsThis* whatsThis = new ListBoxWhatsThis(m_correctionTools); + + TQPixmap pix = getThumbnailForEffect(AutoLevelsCorrection); + ListBoxPreviewItem *item = new ListBoxPreviewItem(pix, i18n("Auto Levels")); + whatsThis->add( item, i18n("<b>Auto Levels</b>:" + "<p>This option maximizes the tonal range in the Red, " + "Green, and Blue channels. It searches the image shadow and highlight " + "limit values and adjusts the Red, Green, and Blue channels " + "to a full histogram range.</p>")); + m_correctionTools->insertItem(item, AutoLevelsCorrection); + + pix = getThumbnailForEffect(NormalizeCorrection); + item = new ListBoxPreviewItem(pix, i18n("Normalize")); + whatsThis->add( item, i18n("<b>Normalize</b>:" + "<p>This option scales brightness values across the active " + "image so that the darkest point becomes black, and the " + "brightest point becomes as bright as possible without " + "altering its hue. This is often a \"magic fix\" for " + "images that are dim or washed out.</p>")); + m_correctionTools->insertItem(item, NormalizeCorrection); + + pix = getThumbnailForEffect(EqualizeCorrection); + item = new ListBoxPreviewItem(pix, i18n("Equalize")); + whatsThis->add( item, i18n("<b>Equalize</b>:" + "<p>This option adjusts the brightness of colors across the " + "active image so that the histogram for the value channel " + "is as nearly as possible flat, that is, so that each possible " + "brightness value appears at about the same number of pixels " + "as each other value. Sometimes Equalize works wonderfully at " + "enhancing the contrasts in an image. Other times it gives " + "garbage. It is a very powerful operation, which can either work " + "miracles on an image or destroy it.</p>")); + m_correctionTools->insertItem(item, EqualizeCorrection); + + pix = getThumbnailForEffect(StretchContrastCorrection); + item = new ListBoxPreviewItem(pix, i18n("Stretch Contrast")); + whatsThis->add( item, i18n("<b>Stretch Contrast</b>:" + "<p>This option enhances the contrast and brightness " + "of the RGB values of an image by stretching the lowest " + "and highest values to their fullest range, adjusting " + "everything in between.</p>")); + m_correctionTools->insertItem(item, StretchContrastCorrection); + + pix = getThumbnailForEffect(AutoExposureCorrection); + item = new ListBoxPreviewItem(pix, i18n("Auto Exposure")); + whatsThis->add( item, i18n("<b>Auto Exposure</b>:" + "<p>This option enhances the contrast and brightness " + "of the RGB values of an image to calculate optimal " + "exposition and black level using image histogram " + "properties.</p>")); + m_correctionTools->insertItem(item, AutoExposureCorrection); + + // ------------------------------------------------------------- + + m_correctionTools->setFocus(); + gridSettings->addMultiCellLayout(l1, 0, 0, 0, 4); + gridSettings->addMultiCellWidget(histoBox, 1, 1, 0, 4); + gridSettings->addMultiCellWidget(m_correctionTools, 2, 2, 0, 4); + gridSettings->setRowStretch(2, 10); + gridSettings->setSpacing(gboxSettings->spacingHint()); + gridSettings->setMargin(gboxSettings->spacingHint()); + + setToolSettings(gboxSettings); + init(); + + // ------------------------------------------------------------- + + 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_previewWidget, TQ_SIGNAL(spotPositionChangedFromTarget(const DColor&, const TQPoint&)), + this, TQ_SLOT(slotColorSelectedFromTarget(const DColor&))); + + connect(m_correctionTools, TQ_SIGNAL(highlighted(int)), + this, TQ_SLOT(slotEffect())); + + connect(m_previewWidget, TQ_SIGNAL(signalResized()), + this, TQ_SLOT(slotEffect())); +} + +AutoCorrectionTool::~AutoCorrectionTool() +{ + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; +} + +void AutoCorrectionTool::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 AutoCorrectionTool::slotScaleChanged(int scale) +{ + m_histogramWidget->m_scaleType = scale; + m_histogramWidget->repaint(false); +} + +void AutoCorrectionTool::slotColorSelectedFromTarget(const DColor& color) +{ + m_histogramWidget->setHistogramGuideByColor(color); +} + +void AutoCorrectionTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("autocorrection Tool"); + m_channelCB->setCurrentItem(config->readNumEntry("Histogram Channel", 0)); // Luminosity. + m_scaleBG->setButton(config->readNumEntry("Histogram Scale", HistogramWidget::LogScaleHistogram)); + m_correctionTools->setCurrentItem(config->readNumEntry("Auto Correction Filter", AutoLevelsCorrection)); + m_histogramWidget->reset(); + slotChannelChanged(m_channelCB->currentItem()); + slotScaleChanged(m_scaleBG->selectedId()); +} + +void AutoCorrectionTool::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("autocorrection Tool"); + config->writeEntry("Histogram Channel", m_channelCB->currentItem()); + config->writeEntry("Histogram Scale", m_scaleBG->selectedId()); + config->writeEntry("Auto Correction Filter", m_correctionTools->currentItem()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void AutoCorrectionTool::slotResetSettings() +{ + m_correctionTools->blockSignals(true); + m_correctionTools->setCurrentItem(AutoLevelsCorrection); + m_correctionTools->blockSignals(false); + + slotEffect(); +} + +void AutoCorrectionTool::slotEffect() +{ + kapp->setOverrideCursor(KCursor::waitCursor()); + + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + ImageIface* iface = m_previewWidget->imageIface(); + m_destinationPreviewData = iface->getPreviewImage(); + int w = iface->previewWidth(); + int h = iface->previewHeight(); + bool sb = iface->previewSixteenBit(); + + autoCorrection(m_destinationPreviewData, w, h, sb, m_correctionTools->currentItem()); + + iface->putPreviewImage(m_destinationPreviewData); + m_previewWidget->updatePreview(); + + // Update histogram. + + m_histogramWidget->updateData(m_destinationPreviewData, w, h, sb, 0, 0, 0, false); + + kapp->restoreOverrideCursor(); +} + +TQPixmap AutoCorrectionTool::getThumbnailForEffect(AutoCorrectionType type) +{ + DImg thumb = m_thumbnailImage.copy(); + autoCorrection(thumb.bits(), thumb.width(), thumb.height(), thumb.sixteenBit(), type); + return (thumb.convertToPixmap()); +} + + +void AutoCorrectionTool::finalRendering() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + ImageIface* iface = m_previewWidget->imageIface(); + uchar *data = iface->getOriginalImage(); + int w = iface->originalWidth(); + int h = iface->originalHeight(); + bool sb = iface->originalSixteenBit(); + + if (data) + { + int type = m_correctionTools->currentItem(); + autoCorrection(data, w, h, sb, type); + TQString name; + + switch (type) + { + case AutoLevelsCorrection: + name = i18n("Auto Levels"); + break; + + case NormalizeCorrection: + name = i18n("Normalize"); + break; + + case EqualizeCorrection: + name = i18n("Equalize"); + break; + + case StretchContrastCorrection: + name = i18n("Stretch Contrast"); + break; + + case AutoExposureCorrection: + name = i18n("Auto Exposure"); + break; + } + + iface->putOriginalImage(name, data); + delete [] data; + } + + kapp->restoreOverrideCursor(); +} + +void AutoCorrectionTool::autoCorrection(uchar *data, int w, int h, bool sb, int type) +{ + DImgImageFilters filter; + + switch (type) + { + case AutoLevelsCorrection: + filter.autoLevelsCorrectionImage(data, w, h, sb); + break; + + case NormalizeCorrection: + filter.normalizeImage(data, w, h, sb); + break; + + case EqualizeCorrection: + filter.equalizeImage(data, w, h, sb); + break; + + case StretchContrastCorrection: + filter.stretchContrastImage(data, w, h, sb); + break; + + case AutoExposureCorrection: + WhiteBalance wbFilter(sb); + double blackLevel; + double exposureLevel; + wbFilter.autoExposureAdjustement(data, w, h, sb, blackLevel, exposureLevel); + wbFilter.whiteBalance(data, w, h, sb, blackLevel, exposureLevel); + break; + } +} + +} // NameSpace DigikamImagesPluginCore + diff --git a/src/imageplugins/coreplugin/autocorrectiontool.h b/src/imageplugins/coreplugin/autocorrectiontool.h new file mode 100644 index 00000000..73a388f2 --- /dev/null +++ b/src/imageplugins/coreplugin/autocorrectiontool.h @@ -0,0 +1,128 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-31 + * Description : Auto-Color correction tool. + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +#ifndef AUTOCORRECTIONTOOL_H +#define AUTOCORRECTIONTOOL_H + +// TQt includes. + +#include <tqstring.h> + +// Digikam includes. + +#include "editortool.h" + +class TQHButtonGroup; +class TQComboBox; +class TQListBox; +class TQButtonGroup; + +namespace Digikam +{ +class HistogramWidget; +class ColorGradientWidget; +class ImageWidget; +class DColor; +class DImg; +} + +namespace DigikamImagesPluginCore +{ + +class AutoCorrectionTool : public Digikam::EditorTool +{ + TQ_OBJECT + + +public: + + AutoCorrectionTool(TQObject *parent); + ~AutoCorrectionTool(); + +protected: + + void finalRendering(); + +private slots: + + void slotEffect(); + void slotResetSettings(); + void slotChannelChanged(int channel); + void slotScaleChanged(int scale); + void slotColorSelectedFromTarget(const Digikam::DColor &color); + +private: + + enum AutoCorrectionType + { + AutoLevelsCorrection=0, + NormalizeCorrection, + EqualizeCorrection, + StretchContrastCorrection, + AutoExposureCorrection + }; + +private: + + void readSettings(); + void writeSettings(); + + void autoCorrection(uchar *data, int w, int h, bool sb, int type); + TQPixmap getThumbnailForEffect(AutoCorrectionType type); + +private: + + enum HistogramScale + { + Linear=0, + Logarithmic + }; + + enum ColorChannel + { + LuminosityChannel=0, + RedChannel, + GreenChannel, + BlueChannel + }; + + uchar *m_destinationPreviewData; + + TQComboBox *m_channelCB; + + TQHButtonGroup *m_scaleBG; + + TQListBox *m_correctionTools; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::ColorGradientWidget *m_hGradient; + + Digikam::HistogramWidget *m_histogramWidget; + + Digikam::DImg m_thumbnailImage; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* AUTOCORRECTIONTOOL_H */ diff --git a/src/imageplugins/coreplugin/bcgtool.cpp b/src/imageplugins/coreplugin/bcgtool.cpp new file mode 100644 index 00000000..17ecf838 --- /dev/null +++ b/src/imageplugins/coreplugin/bcgtool.cpp @@ -0,0 +1,366 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-06-05 + * Description : digiKam image editor to adjust Brightness, + Contrast, and Gamma of picture. + * + * Copyright (C) 2004 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2005-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqcheckbox.h> +#include <tqcolor.h> +#include <tqcombobox.h> +#include <tqframe.h> +#include <tqgroupbox.h> +#include <tqhbuttongroup.h> +#include <tqhgroupbox.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqpushbutton.h> +#include <tqtooltip.h> +#include <tqvbox.h> +#include <tqvgroupbox.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <kstandarddirs.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> + +// Digikam includes. + +#include "bcgmodifier.h" +#include "colorgradientwidget.h" +#include "dimg.h" +#include "editortoolsettings.h" +#include "histogramwidget.h" +#include "imageiface.h" +#include "imagewidget.h" + +// Local includes. + +#include "bcgtool.h" +#include "bcgtool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamImagesPluginCore +{ + +BCGTool::BCGTool(TQObject* parent) + : EditorTool(parent) +{ + setName("bcgadjust"); + setToolName(i18n("Brightness / Contrast / Gamma")); + setToolIcon(SmallIcon("contrast")); + setToolHelp("bcgadjusttool.anchor"); + + m_destinationPreviewData = 0; + + m_previewWidget = new ImageWidget("bcgadjust Tool", 0, + i18n("<p>Here you can see the image " + "brightness-contrast-gamma adjustments preview. " + "You can pick color on image " + "to see the color level corresponding on histogram.")); + setToolView(m_previewWidget); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel); + + TQGridLayout* gridSettings = new TQGridLayout(m_gboxSettings->plainPage(), 9, 4); + + 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("<p>Select the histogram channel to display here:<p>" + "<b>Luminosity</b>: display the image's luminosity values.<p>" + "<b>Red</b>: display the red image-channel values.<p>" + "<b>Green</b>: display the green image-channel values.<p>" + "<b>Blue</b>: display the blue image-channel values.<p>")); + + 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("<p>Select the histogram scale here.<p>" + "If the image's maximal counts are small, you can use the linear scale.<p>" + "Logarithmic scale can be used when the maximal counts 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("<p>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("<p>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); + + // ------------------------------------------------------------- + + TQVBox *histoBox = new TQVBox(m_gboxSettings->plainPage()); + m_histogramWidget = new HistogramWidget(256, 140, histoBox, false, true, true); + TQWhatsThis::add( m_histogramWidget, i18n("<p>Here you can see the target preview image histogram drawing " + "of the selected image channel. This one is re-computed at any " + "settings changes.")); + TQLabel *space = new TQLabel(histoBox); + space->setFixedHeight(1); + m_hGradient = new ColorGradientWidget(ColorGradientWidget::Horizontal, 10, histoBox); + m_hGradient->setColors(TQColor("black"), TQColor("white")); + + // ------------------------------------------------------------- + + TQLabel *label2 = new TQLabel(i18n("Brightness:"), m_gboxSettings->plainPage()); + m_bInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_bInput->setRange(-100, 100, 1); + m_bInput->setDefaultValue(0); + TQWhatsThis::add( m_bInput, i18n("<p>Set here the brightness adjustment of the image.")); + + TQLabel *label3 = new TQLabel(i18n("Contrast:"), m_gboxSettings->plainPage()); + m_cInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_cInput->setRange(-100, 100, 1); + m_cInput->setDefaultValue(0); + TQWhatsThis::add( m_cInput, i18n("<p>Set here the contrast adjustment of the image.")); + + TQLabel *label4 = new TQLabel(i18n("Gamma:"), m_gboxSettings->plainPage()); + m_gInput = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_gInput->setPrecision(2); + m_gInput->setRange(0.1, 3.0, 0.01); + m_gInput->setDefaultValue(1.0); + TQWhatsThis::add( m_gInput, i18n("<p>Set here the gamma adjustment of the image.")); + + // ------------------------------------------------------------- + + gridSettings->addMultiCellLayout(l1, 0, 0, 0, 4); + gridSettings->addMultiCellWidget(histoBox, 1, 2, 0, 4); + gridSettings->addMultiCellWidget(label2, 3, 3, 0, 4); + gridSettings->addMultiCellWidget(m_bInput, 4, 4, 0, 4); + gridSettings->addMultiCellWidget(label3, 5, 5, 0, 4); + gridSettings->addMultiCellWidget(m_cInput, 6, 6, 0, 4); + gridSettings->addMultiCellWidget(label4, 7, 7, 0, 4); + gridSettings->addMultiCellWidget(m_gInput, 8, 8, 0, 4); + gridSettings->setRowStretch(9, 10); + + setToolSettings(m_gboxSettings); + init(); + + // ------------------------------------------------------------- + + 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_previewWidget, TQ_SIGNAL(spotPositionChangedFromTarget( const Digikam::DColor &, const TQPoint & )), + this, TQ_SLOT(slotColorSelectedFromTarget( const Digikam::DColor & ))); + + connect(m_bInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_cInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_gInput, TQ_SIGNAL(valueChanged(double)), + this, TQ_SLOT(slotTimer())); + + connect(m_previewWidget, TQ_SIGNAL(signalResized()), + this, TQ_SLOT(slotEffect())); + + // ------------------------------------------------------------- + + m_gboxSettings->enableButton(EditorToolSettings::Ok, false); +} + +BCGTool::~BCGTool() +{ + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; +} + +void BCGTool::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 BCGTool::slotScaleChanged(int scale) +{ + m_histogramWidget->m_scaleType = scale; + m_histogramWidget->repaint(false); +} + +void BCGTool::slotColorSelectedFromTarget(const DColor &color) +{ + m_histogramWidget->setHistogramGuideByColor(color); +} + +void BCGTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("bcgadjust Tool"); + m_channelCB->setCurrentItem(config->readNumEntry("Histogram Channel", 0)); // Luminosity. + m_scaleBG->setButton(config->readNumEntry("Histogram Scale", HistogramWidget::LogScaleHistogram)); + m_bInput->setValue(config->readNumEntry("BrightnessAjustment", m_bInput->defaultValue())); + m_cInput->setValue(config->readNumEntry("ContrastAjustment", m_cInput->defaultValue())); + m_gInput->setValue(config->readDoubleNumEntry("GammaAjustment", m_gInput->defaultValue())); + m_histogramWidget->reset(); + slotChannelChanged(m_channelCB->currentItem()); + slotScaleChanged(m_scaleBG->selectedId()); +} + +void BCGTool::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("bcgadjust Tool"); + config->writeEntry("Histogram Channel", m_channelCB->currentItem()); + config->writeEntry("Histogram Scale", m_scaleBG->selectedId()); + config->writeEntry("BrightnessAjustment", m_bInput->value()); + config->writeEntry("ContrastAjustment", m_cInput->value()); + config->writeEntry("GammaAjustment", m_gInput->value()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void BCGTool::slotResetSettings() +{ + m_bInput->blockSignals(true); + m_cInput->blockSignals(true); + m_gInput->blockSignals(true); + + m_bInput->slotReset(); + m_cInput->slotReset(); + m_gInput->slotReset(); + + m_bInput->blockSignals(false); + m_cInput->blockSignals(false); + m_gInput->blockSignals(false); + + slotEffect(); +} + +void BCGTool::slotEffect() +{ + kapp->setOverrideCursor(KCursor::waitCursor()); + + double b = (double) m_bInput->value() / 250.0; + double c = (double) (m_cInput->value() / 100.0) + 1.00; + double g = m_gInput->value(); + + m_gboxSettings->enableButton(EditorToolSettings::Ok, + ( b != 0.0 || c != 1.0 || g != 1.0 )); + + m_histogramWidget->stopHistogramComputation(); + + 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); + BCGModifier cmod; + cmod.setGamma(g); + cmod.setBrightness(b); + cmod.setContrast(c); + cmod.applyBCG(preview); + iface->putPreviewImage(preview.bits()); + + m_previewWidget->updatePreview(); + + // Update histogram. + + memcpy(m_destinationPreviewData, preview.bits(), preview.numBytes()); + m_histogramWidget->updateData(m_destinationPreviewData, w, h, sb, 0, 0, 0, false); + + kapp->restoreOverrideCursor(); +} + +void BCGTool::finalRendering() +{ + kapp->setOverrideCursor(KCursor::waitCursor()); + ImageIface* iface = m_previewWidget->imageIface(); + + double b = (double) m_bInput->value() / 250.0; + double c = (double) (m_cInput->value() / 100.0) + 1.00; + double g = m_gInput->value(); + + iface->setOriginalBCG(b, c, g); + kapp->restoreOverrideCursor(); +} + +} // NameSpace DigikamImagesPluginCore + diff --git a/src/imageplugins/coreplugin/bcgtool.h b/src/imageplugins/coreplugin/bcgtool.h new file mode 100644 index 00000000..4a1e9d21 --- /dev/null +++ b/src/imageplugins/coreplugin/bcgtool.h @@ -0,0 +1,115 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-06-05 + * Description : digiKam image editor to adjust Brightness, + Contrast, and Gamma of picture. + * + * Copyright (C) 2004 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2005-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. + * + * ============================================================ */ + +#ifndef BCGTOOL_H +#define BCGTOOL_H + +// Digikam includes. + +#include "editortool.h" + +class TQCheckBox; +class TQComboBox; +class TQHButtonGroup; + +namespace KDcrawIface +{ +class RIntNumInput; +class RDoubleNumInput; +} + +namespace Digikam +{ +class HistogramWidget; +class ColorGradientWidget; +class ImageWidget; +class DColor; +} + +namespace DigikamImagesPluginCore +{ + +class BCGTool : public Digikam::EditorTool +{ + TQ_OBJECT + + +public: + + BCGTool(TQObject *parent); + ~BCGTool(); + +private slots: + + void slotEffect(); + void slotResetSettings(); + void slotChannelChanged(int channel); + void slotScaleChanged(int scale); + void slotColorSelectedFromTarget( const Digikam::DColor &color ); + +private: + + void readSettings(); + void writeSettings(); + void finalRendering(); + +private: + + enum HistogramScale + { + Linear=0, + Logarithmic + }; + + enum ColorChannel + { + LuminosityChannel=0, + RedChannel, + GreenChannel, + BlueChannel + }; + + uchar *m_destinationPreviewData; + + TQComboBox *m_channelCB; + + TQHButtonGroup *m_scaleBG; + + KDcrawIface::RIntNumInput *m_bInput; + KDcrawIface::RIntNumInput *m_cInput; + KDcrawIface::RDoubleNumInput *m_gInput; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::ColorGradientWidget *m_hGradient; + + Digikam::HistogramWidget *m_histogramWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* BCGTOOL_H */ diff --git a/src/imageplugins/coreplugin/blurtool.cpp b/src/imageplugins/coreplugin/blurtool.cpp new file mode 100644 index 00000000..85e1dc19 --- /dev/null +++ b/src/imageplugins/coreplugin/blurtool.cpp @@ -0,0 +1,169 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-09 + * Description : a tool to blur an image + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqlayout.h> +#include <tqlabel.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeaboutdata.h> +#include <kiconloader.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <tdelocale.h> +#include <tdeapplication.h> + +// Digikam includes. + +#include "ddebug.h" +#include "imageiface.h" +#include "imagepanelwidget.h" +#include "editortoolsettings.h" +#include "dimggaussianblur.h" + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> + +// Local includes. + +#include "blurtool.h" +#include "blurtool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamImagesPluginCore +{ + +BlurTool::BlurTool(TQObject* parent) + : EditorToolThreaded(parent) +{ + setName("gaussianblur"); + setToolName(i18n("Blur")); + setToolIcon(SmallIcon("blurimage")); + setToolHelp("blursharpentool.anchor"); + + // --------------------------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel| + EditorToolSettings::Try, + EditorToolSettings::PanIcon); + TQGridLayout* grid = new TQGridLayout( m_gboxSettings->plainPage(), 2, 1); + TQLabel *label = new TQLabel(i18n("Smoothness:"), m_gboxSettings->plainPage()); + + m_radiusInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_radiusInput->setRange(0, 100, 1); + m_radiusInput->setDefaultValue(0); + TQWhatsThis::add(m_radiusInput, i18n("<p>A smoothness of 0 has no effect, " + "1 and above determine the Gaussian blur matrix radius " + "that determines how much to blur the image.")); + + grid->addMultiCellWidget(label, 0, 0, 0, 1); + grid->addMultiCellWidget(m_radiusInput, 1, 1, 0, 1); + grid->setRowStretch(2, 10); + grid->setMargin(m_gboxSettings->spacingHint()); + grid->setSpacing(m_gboxSettings->spacingHint()); + + setToolSettings(m_gboxSettings); + + m_previewWidget = new ImagePanelWidget(470, 350, "gaussianblur Tool", m_gboxSettings->panIconView()); + + setToolView(m_previewWidget); + init(); +} + +BlurTool::~BlurTool() +{ +} + +void BlurTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("gaussianblur Tool"); + m_radiusInput->setValue(config->readNumEntry("RadiusAjustment", m_radiusInput->defaultValue())); +} + +void BlurTool::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("gaussianblur Tool"); + config->writeEntry("RadiusAjustment", m_radiusInput->value()); + config->sync(); +} + +void BlurTool::slotResetSettings() +{ + m_radiusInput->blockSignals(true); + m_radiusInput->slotReset(); + m_radiusInput->blockSignals(false); +} + +void BlurTool::prepareEffect() +{ + m_radiusInput->setEnabled(false); + + DImg img = m_previewWidget->getOriginalRegionImage(); + + setFilter(dynamic_cast<DImgThreadedFilter*>(new DImgGaussianBlur(&img, this, m_radiusInput->value()))); +} + +void BlurTool::prepareFinal() +{ + m_radiusInput->setEnabled(false); + + ImageIface iface(0, 0); + uchar *data = iface.getOriginalImage(); + int w = iface.originalWidth(); + int h = iface.originalHeight(); + bool sixteenBit = iface.originalSixteenBit(); + bool hasAlpha = iface.originalHasAlpha(); + DImg orgImage = DImg(w, h, sixteenBit, hasAlpha ,data); + delete [] data; + setFilter(dynamic_cast<DImgThreadedFilter*>(new DImgGaussianBlur(&orgImage, this, m_radiusInput->value()))); +} + +void BlurTool::putPreviewData() +{ + DImg imDest = filter()->getTargetImage(); + m_previewWidget->setPreviewImage(imDest); +} + +void BlurTool::putFinalData() +{ + ImageIface iface(0, 0); + DImg imDest = filter()->getTargetImage(); + iface.putOriginalImage(i18n("Gaussian Blur"), imDest.bits()); +} + +void BlurTool::renderingFinished() +{ + m_radiusInput->setEnabled(true); +} + +} // NameSpace DigikamImagesPluginCore diff --git a/src/imageplugins/coreplugin/blurtool.h b/src/imageplugins/coreplugin/blurtool.h new file mode 100644 index 00000000..545f4aa2 --- /dev/null +++ b/src/imageplugins/coreplugin/blurtool.h @@ -0,0 +1,81 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-09 + * Description : a tool to blur an image + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_BLUR_H +#define IMAGEEFFECT_BLUR_H + +// Digikam includes. + +#include "editortool.h" + +namespace KDcrawIface +{ +class RIntNumInput; +} + +namespace Digikam +{ +class EditorToolSettings; +class ImagePanelWidget; +} + +namespace DigikamImagesPluginCore +{ + +class BlurTool : public Digikam::EditorToolThreaded +{ + TQ_OBJECT + + +public: + + BlurTool(TQObject *parent); + ~BlurTool(); + +private slots: + + void slotResetSettings(); + +private: + + void readSettings(); + void writeSettings(); + void prepareEffect(); + void prepareFinal(); + void abortPreview(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + KDcrawIface::RIntNumInput *m_radiusInput; + + Digikam::ImagePanelWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* IMAGEEFFECT_BLUR_H */ diff --git a/src/imageplugins/coreplugin/bwsepiatool.cpp b/src/imageplugins/coreplugin/bwsepiatool.cpp new file mode 100644 index 00000000..06c30462 --- /dev/null +++ b/src/imageplugins/coreplugin/bwsepiatool.cpp @@ -0,0 +1,1177 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-06 + * Description : Black and White conversion tool. + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqcolor.h> +#include <tqcombobox.h> +#include <tqfile.h> +#include <tqframe.h> +#include <tqgroupbox.h> +#include <tqhbuttongroup.h> +#include <tqhgroupbox.h> +#include <tqintdict.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqlistbox.h> +#include <tqpushbutton.h> +#include <tqtextstream.h> +#include <tqtimer.h> +#include <tqtooltip.h> +#include <tqvbox.h> +#include <tqvgroupbox.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <tdefiledialog.h> +#include <tdeglobalsettings.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <kstandarddirs.h> +#include <ktabwidget.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> + +// Digikam includes. + +#include "bcgmodifier.h" +#include "colorgradientwidget.h" +#include "curveswidget.h" +#include "dimg.h" +#include "dimgimagefilters.h" +#include "editortoolsettings.h" +#include "histogramwidget.h" +#include "imagecurves.h" +#include "imagehistogram.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "listboxpreviewitem.h" + +// Local includes. + +#include "bwsepiatool.h" +#include "bwsepiatool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamImagesPluginCore +{ + +class PreviewPixmapFactory : public TQObject +{ +public: + + PreviewPixmapFactory(BWSepiaTool* bwSepia); + + void invalidate() { m_previewPixmapMap.clear(); } + + const TQPixmap* pixmap(int id); + +private: + + TQPixmap makePixmap(int id); + + TQIntDict<TQPixmap> m_previewPixmapMap; + BWSepiaTool *m_bwSepia; +}; + +PreviewPixmapFactory::PreviewPixmapFactory(BWSepiaTool* bwSepia) + : TQObject(bwSepia), m_bwSepia(bwSepia) +{ + m_previewPixmapMap.setAutoDelete(true); +} + +const TQPixmap* PreviewPixmapFactory::pixmap(int id) +{ + if (m_previewPixmapMap.find(id) == 0) + { + TQPixmap pix = makePixmap(id); + m_previewPixmapMap.insert(id, new TQPixmap(pix)); + } + + TQPixmap* res = m_previewPixmapMap[id]; + + return res; +} + +TQPixmap PreviewPixmapFactory::makePixmap(int id) +{ + return m_bwSepia->getThumbnailForEffect(id); +} + +// ----------------------------------------------------------------------------------- + +class ListBoxBWPreviewItem : public ListBoxPreviewItem +{ + +public: + + ListBoxBWPreviewItem(TQListBox *listbox, const TQString &text, + PreviewPixmapFactory* factory, int id) + : ListBoxPreviewItem(listbox, TQPixmap(), text) + { + m_previewPixmapFactory = factory; + m_id = id; + }; + + virtual const TQPixmap* pixmap() const; + +private: + + int m_id; + PreviewPixmapFactory* m_previewPixmapFactory; +}; + +const TQPixmap* ListBoxBWPreviewItem::pixmap() const +{ + return m_previewPixmapFactory->pixmap(m_id); +} + +// ----------------------------------------------------------------------------------- + +BWSepiaTool::BWSepiaTool(TQObject* parent) + : EditorTool(parent) +{ + setName("convertbw"); + setToolName(i18n("Black && White")); + setToolIcon(SmallIcon("bwtonal")); + setToolHelp("blackandwhitetool.anchor"); + + m_destinationPreviewData = 0; + + ImageIface iface(0, 0); + m_originalImage = iface.getOriginalImg(); + m_thumbnailImage = m_originalImage->smoothScale(128, 128, TQSize::ScaleMin); + + // ------------------------------------------------------------- + + m_previewWidget = new ImageWidget("convertbw Tool", 0, + i18n("<p>Here you can see the black and white conversion tool preview. " + "You can pick color on image " + "to see the color level corresponding on histogram.")); + setToolView(m_previewWidget); + + // ------------------------------------------------------------- + + EditorToolSettings *gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Load| + EditorToolSettings::SaveAs| + EditorToolSettings::Ok| + EditorToolSettings::Cancel); + + TQGridLayout* gridSettings = new TQGridLayout(gboxSettings->plainPage(), 4, 4); + + TQLabel *label1 = new TQLabel(i18n("Channel:"), gboxSettings->plainPage()); + label1->setAlignment(TQt::AlignRight | TQt::AlignVCenter); + m_channelCB = new TQComboBox(false, 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("<p>Select the histogram channel to display here:<p>" + "<b>Luminosity</b>: display the image's luminosity values.<p>" + "<b>Red</b>: display the red image-channel values.<p>" + "<b>Green</b>: display the green image-channel values.<p>" + "<b>Blue</b>: display the blue image-channel values.<p>")); + + m_scaleBG = new TQHButtonGroup(gboxSettings->plainPage()); + m_scaleBG->setExclusive(true); + m_scaleBG->setFrameShape(TQFrame::NoFrame); + m_scaleBG->setInsideMargin(0); + TQWhatsThis::add( m_scaleBG, i18n("<p>Select the histogram scale here.<p>" + "If the image's maximal counts are small, you can use the linear scale.<p>" + "Logarithmic scale can be used when the maximal counts 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("<p>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("<p>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, 4); + + // ------------------------------------------------------------- + + TQVBox *histoBox = new TQVBox(gboxSettings->plainPage()); + m_histogramWidget = new HistogramWidget(256, 140, histoBox, false, true, true); + TQWhatsThis::add( m_histogramWidget, i18n("<p>Here you can see the target preview image histogram drawing " + "of the selected image channel. This one is re-computed at any " + "settings 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, 4); + + // ------------------------------------------------------------- + + m_tab = new KTabWidget(gboxSettings->plainPage()); + + m_bwFilm = new TQListBox(m_tab); + m_bwFilm->setColumnMode(1); + m_bwFilm->setVariableWidth(false); + m_bwFilm->setVariableHeight(false); + ListBoxWhatsThis* whatsThis2 = new ListBoxWhatsThis(m_bwFilm); + m_previewPixmapFactory = new PreviewPixmapFactory(this); + + int type = BWGeneric; + + ListBoxBWPreviewItem *item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Generic"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Generic</b>:" + "<p>Simulate a generic black and white film</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Agfa 200X"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Agfa 200X</b>:" + "<p>Simulate the Agfa 200X black and white film at 200 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Agfa Pan 25"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Agfa Pan 25</b>:" + "<p>Simulate the Agfa Pan black and white film at 25 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Agfa Pan 100"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Agfa Pan 100</b>:" + "<p>Simulate the Agfa Pan black and white film at 100 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Agfa Pan 400"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Agfa Pan 400</b>:" + "<p>Simulate the Agfa Pan black and white film at 400 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Ilford Delta 100"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Ilford Delta 100</b>:" + "<p>Simulate the Ilford Delta black and white film at 100 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Ilford Delta 400"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Ilford Delta 400</b>:" + "<p>Simulate the Ilford Delta black and white film at 400 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Ilford Delta 400 Pro 3200"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Ilford Delta 400 Pro 3200</b>:" + "<p>Simulate the Ilford Delta 400 Pro black and white film at 3200 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Ilford FP4 Plus"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Ilford FP4 Plus</b>:" + "<p>Simulate the Ilford FP4 Plus black and white film at 125 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Ilford HP5 Plus"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Ilford HP5 Plus</b>:" + "<p>Simulate the Ilford HP5 Plus black and white film at 400 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Ilford PanF Plus"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Ilford PanF Plus</b>:" + "<p>Simulate the Ilford PanF Plus black and white film at 50 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Ilford XP2 Super"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Ilford XP2 Super</b>:" + "<p>Simulate the Ilford XP2 Super black and white film at 400 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Kodak Tmax 100"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Kodak Tmax 100</b>:" + "<p>Simulate the Kodak Tmax black and white film at 100 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Kodak Tmax 400"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Kodak Tmax 400</b>:" + "<p>Simulate the Kodak Tmax black and white film at 400 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Kodak TriX"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Kodak TriX</b>:" + "<p>Simulate the Kodak TriX black and white film at 400 ISO</p>")); + + // ------------------------------------------------------------- + + TQVBox *vbox = new TQVBox(m_tab); + + m_bwFilters = new TQListBox(vbox); + m_bwFilters->setColumnMode(1); + m_bwFilters->setVariableWidth(false); + m_bwFilters->setVariableHeight(false); + ListBoxWhatsThis* whatsThis = new ListBoxWhatsThis(m_bwFilters); + + type = BWNoFilter; + + item = new ListBoxBWPreviewItem(m_bwFilters, + i18n("No Lens Filter"), m_previewPixmapFactory, type); + whatsThis->add( item, i18n("<b>No Lens Filter</b>:" + "<p>Do not apply a lens filter when rendering the image.</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilters, i18n("Green Filter"), m_previewPixmapFactory, type); + whatsThis->add( item, i18n("<b>Black & White with Green Filter</b>:" + "<p>Simulate black and white film exposure using a green filter. " + "This is usefule for all scenic shoots, especially portraits " + "photographed against the sky.</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilters, i18n("Orange Filter"), m_previewPixmapFactory, type); + whatsThis->add( item, i18n("<b>Black & White with Orange Filter</b>:" + "<p>Simulate black and white film exposure using an orange filter. " + "This will enhance landscapes, marine scenes and aerial " + "photography.</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilters, i18n("Red Filter"), m_previewPixmapFactory, type); + whatsThis->add( item, i18n("<b>Black & White with Red Filter</b>:" + "<p>Simulate black and white film exposure using a red filter. " + "This creates dramatic sky effects, and simulates moonlight scenes " + "in the daytime.</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilters, i18n("Yellow Filter"), m_previewPixmapFactory, type); + whatsThis->add( item, i18n("<b>Black & White with Yellow Filter</b>:" + "<p>Simulate black and white film exposure using a yellow filter. " + "This has the most natural tonal correction, and improves contrast. Ideal for " + "landscapes.</p>")); + + m_strengthInput = new RIntNumInput(vbox); + m_strengthInput->input()->setLabel(i18n("Strength:"), AlignLeft | AlignVCenter); + m_strengthInput->setRange(1, 5, 1); + m_strengthInput->setDefaultValue(1); + TQWhatsThis::add(m_strengthInput, i18n("<p>Here, set the strength adjustment of the lens filter.")); + + // ------------------------------------------------------------- + + m_bwTone = new TQListBox(m_tab); + m_bwTone->setColumnMode(1); + m_bwTone->setVariableWidth(false); + m_bwTone->setVariableHeight(false); + ListBoxWhatsThis* whatsThis3 = new ListBoxWhatsThis(m_bwTone); + + type = BWNoTone; + + item = new ListBoxBWPreviewItem(m_bwTone, i18n("No Tone Filter"), m_previewPixmapFactory, type); + whatsThis3->add( item, i18n("<b>No Tone Filter</b>:" + "<p>Do not apply a tone filter to the image.</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwTone, i18n("Sepia Tone"), m_previewPixmapFactory, type); + whatsThis3->add( item, i18n("<b>Black & White with Sepia Tone</b>:" + "<p>Gives a warm highlight and mid-tone while adding a bit of coolness to " + "the shadows - very similar to the process of bleaching a print and " + "re-developing in a sepia toner.</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwTone, i18n("Brown Tone"), m_previewPixmapFactory, type); + whatsThis3->add( item, i18n("<b>Black & White with Brown Tone</b>:" + "<p>This filter is more neutral than the Sepia Tone " + "filter.</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwTone, i18n("Cold Tone"), m_previewPixmapFactory, type); + whatsThis3->add( item, i18n("<b>Black & White with Cold Tone</b>:" + "<p>Start subtle and replicates printing on a cold tone black and white " + "paper such as a bromide enlarging " + "paper.</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwTone, i18n("Selenium Tone"), m_previewPixmapFactory, type); + whatsThis3->add( item, i18n("<b>Black & White with Selenium Tone</b>:" + "<p>This effect replicates traditional selenium chemical toning done " + "in the darkroom.</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwTone, i18n("Platinum Tone"), m_previewPixmapFactory, type); + whatsThis3->add( item, i18n("<b>Black & White with Platinum Tone</b>:" + "<p>This effect replicates traditional platinum chemical toning done " + "in the darkroom.</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwTone, i18n("Green Tone"), m_previewPixmapFactory, type); + whatsThis3->add( item, i18n("<b>Black & White with greenish tint</b>:" + "<p>This effect is also known as Verdante.</p>")); + + // ------------------------------------------------------------- + + TQWidget *curveBox = new TQWidget( m_tab ); + TQGridLayout *gridTab2 = new TQGridLayout(curveBox, 5, 2, 0); + + ColorGradientWidget* vGradient = new ColorGradientWidget( + ColorGradientWidget::Vertical, + 10, curveBox); + vGradient->setColors(TQColor("white"), TQColor("black")); + + TQLabel *spacev = new TQLabel(curveBox); + spacev->setFixedWidth(1); + + m_curvesWidget = new CurvesWidget(256, 256, m_originalImage->bits(), m_originalImage->width(), + m_originalImage->height(), m_originalImage->sixteenBit(), + curveBox); + TQWhatsThis::add( m_curvesWidget, i18n("<p>This is the curve adjustment of the image luminosity")); + + TQLabel *spaceh = new TQLabel(curveBox); + spaceh->setFixedHeight(1); + + ColorGradientWidget *hGradient = new ColorGradientWidget( + ColorGradientWidget::Horizontal, + 10, curveBox); + hGradient->setColors(TQColor("black"), TQColor("white")); + + m_cInput = new RIntNumInput(curveBox); + m_cInput->input()->setLabel(i18n("Contrast:"), AlignLeft | AlignVCenter); + m_cInput->setRange(-100, 100, 1); + m_cInput->setDefaultValue(0); + TQWhatsThis::add( m_cInput, i18n("<p>Set here the contrast adjustment of the image.")); + + gridTab2->addMultiCellWidget(vGradient, 0, 0, 0, 0); + gridTab2->addMultiCellWidget(spacev, 0, 0, 1, 1); + gridTab2->addMultiCellWidget(m_curvesWidget, 0, 0, 2, 2); + gridTab2->addMultiCellWidget(spaceh, 1, 1, 2, 2); + gridTab2->addMultiCellWidget(hGradient, 2, 2, 2, 2); + gridTab2->addMultiCellWidget(m_cInput, 4, 4, 0, 2); +// gridTab2->setRowSpacing(3); + gridTab2->setRowStretch(5, 10); + + // ------------------------------------------------------------- + + m_tab->insertTab(m_bwFilm, i18n("Film"), FilmTab); + m_tab->insertTab(vbox, i18n("Lens Filters"), BWFiltersTab); + m_tab->insertTab(m_bwTone, i18n("Tone"), ToneTab); + m_tab->insertTab(curveBox, i18n("Lightness"), LuminosityTab); + + gridSettings->addMultiCellWidget(m_tab, 3, 3, 0, 4); + gridSettings->setRowStretch(3, 10); + setToolSettings(gboxSettings); + init(); + + // ------------------------------------------------------------- + + 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_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 & ))); + + connect(m_bwFilters, TQ_SIGNAL(highlighted(int)), + this, TQ_SLOT(slotFilterSelected(int))); + + connect(m_strengthInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_bwFilm, TQ_SIGNAL(highlighted(int)), + this, TQ_SLOT(slotEffect())); + + connect(m_bwTone, TQ_SIGNAL(highlighted(int)), + this, TQ_SLOT(slotEffect())); + + connect(m_curvesWidget, TQ_SIGNAL(signalCurvesChanged()), + this, TQ_SLOT(slotTimer())); + + connect(m_cInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_previewWidget, TQ_SIGNAL(signalResized()), + this, TQ_SLOT(slotEffect())); +} + +BWSepiaTool::~BWSepiaTool() +{ + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; +} + +void BWSepiaTool::slotFilterSelected(int filter) +{ + if (filter == BWNoFilter) + m_strengthInput->setEnabled(false); + else + m_strengthInput->setEnabled(true); + + slotEffect(); +} + +TQPixmap BWSepiaTool::getThumbnailForEffect(int type) +{ + DImg thumb = m_thumbnailImage.copy(); + int w = thumb.width(); + int h = thumb.height(); + bool sb = thumb.sixteenBit(); + bool a = thumb.hasAlpha(); + + if (type < BWGeneric) + { + // In Filter view, we will render a preview of the B&W filter with the generic B&W film. + blackAndWhiteConversion(thumb.bits(), w, h, sb, type); + blackAndWhiteConversion(thumb.bits(), w, h, sb, BWGeneric); + } + else + { + // In Film and Tone view, we will render the preview without to use the B&W Filter + blackAndWhiteConversion(thumb.bits(), w, h, sb, type); + } + + if (m_curvesWidget->curves()) // in case we're called before the creator is done + { + uchar *targetData = new uchar[w*h*(sb ? 8 : 4)]; + m_curvesWidget->curves()->curvesLutSetup(ImageHistogram::AlphaChannel); + m_curvesWidget->curves()->curvesLutProcess(thumb.bits(), targetData, w, h); + + DImg preview(w, h, sb, a, targetData); + BCGModifier cmod; + cmod.setContrast((double)(m_cInput->value()/100.0) + 1.00); + cmod.applyBCG(preview); + + thumb.putImageData(preview.bits()); + + delete [] targetData; + } + return (thumb.convertToPixmap()); +} + +void BWSepiaTool::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 BWSepiaTool::slotScaleChanged(int scale) +{ + m_histogramWidget->m_scaleType = scale; + m_histogramWidget->repaint(false); + m_curvesWidget->m_scaleType = scale; + m_curvesWidget->repaint(false); +} + +void BWSepiaTool::slotSpotColorChanged(const DColor &color) +{ + m_curvesWidget->setCurveGuide(color); +} + +void BWSepiaTool::slotColorSelectedFromTarget(const DColor &color) +{ + m_histogramWidget->setHistogramGuideByColor(color); +} + +void BWSepiaTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("convertbw Tool"); + + m_tab->setCurrentPage(config->readNumEntry("Settings Tab", BWFiltersTab)); + m_channelCB->setCurrentItem(config->readNumEntry("Histogram Channel", 0)); // Luminosity. + m_scaleBG->setButton(config->readNumEntry("Histogram Scale", HistogramWidget::LogScaleHistogram)); + m_bwFilters->setCurrentItem(config->readNumEntry("BW Filter", 0)); + m_bwFilm->setCurrentItem(config->readNumEntry("BW Film", 0)); + m_bwTone->setCurrentItem(config->readNumEntry("BW Tone", 0)); + m_cInput->setValue(config->readNumEntry("ContrastAjustment", m_cInput->defaultValue())); + m_strengthInput->setValue(config->readNumEntry("StrengthAjustment", m_strengthInput->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()); + slotFilterSelected(m_bwFilters->currentItem()); +} + +void BWSepiaTool::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("convertbw Tool"); + config->writeEntry("Settings Tab", m_tab->currentPageIndex()); + config->writeEntry("Histogram Channel", m_channelCB->currentItem()); + config->writeEntry("Histogram Scale", m_scaleBG->selectedId()); + config->writeEntry("BW Filter", m_bwFilters->currentItem()); + config->writeEntry("BW Film", m_bwFilm->currentItem()); + config->writeEntry("BW Tone", m_bwTone->currentItem()); + config->writeEntry("ContrastAjustment", m_cInput->value()); + config->writeEntry("StrengthAjustment", m_strengthInput->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 BWSepiaTool::slotResetSettings() +{ + m_bwFilm->blockSignals(true); + m_bwFilters->blockSignals(true); + m_bwTone->blockSignals(true); + m_cInput->blockSignals(true); + m_strengthInput->blockSignals(true); + + m_bwFilm->setCurrentItem(0); + m_bwFilm->setSelected(0, true); + + m_bwFilters->setCurrentItem(0); + m_bwFilters->setSelected(0, true); + + m_bwTone->setCurrentItem(0); + m_bwTone->setSelected(0, true); + + m_cInput->slotReset(); + m_strengthInput->slotReset(); + + for (int channel = 0; channel < 5; channel++) + m_curvesWidget->curves()->curvesChannelReset(channel); + + m_curvesWidget->reset(); + + m_bwFilm->blockSignals(false); + m_bwFilters->blockSignals(false); + m_bwTone->blockSignals(false); + m_cInput->blockSignals(false); + m_strengthInput->blockSignals(false); + + m_histogramWidget->reset(); + m_previewPixmapFactory->invalidate(); + m_bwFilters->triggerUpdate(false); + m_bwTone->triggerUpdate(false); + + slotEffect(); +} + +void BWSepiaTool::slotEffect() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + + m_histogramWidget->stopHistogramComputation(); + + 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(); + + // Apply black and white filter. + + blackAndWhiteConversion(m_destinationPreviewData, w, h, sb, m_bwFilters->currentItem()); + + // Apply black and white film type. + + blackAndWhiteConversion(m_destinationPreviewData, w, h, sb, m_bwFilm->currentItem() + BWGeneric); + + // Apply color tone filter. + + blackAndWhiteConversion(m_destinationPreviewData, w, h, sb, m_bwTone->currentItem() + BWNoTone); + + // Calculate and apply the curve on image. + + uchar *targetData = new uchar[w*h*(sb ? 8 : 4)]; + m_curvesWidget->curves()->curvesLutSetup(ImageHistogram::AlphaChannel); + m_curvesWidget->curves()->curvesLutProcess(m_destinationPreviewData, targetData, w, h); + + // Adjust contrast. + + DImg preview(w, h, sb, a, targetData); + BCGModifier cmod; + cmod.setContrast((double)(m_cInput->value()/100.0) + 1.00); + cmod.applyBCG(preview); + iface->putPreviewImage(preview.bits()); + + m_previewWidget->updatePreview(); + + // Update histogram. + + memcpy(m_destinationPreviewData, preview.bits(), preview.numBytes()); + m_histogramWidget->updateData(m_destinationPreviewData, w, h, sb, 0, 0, 0, false); + delete [] targetData; + + kapp->restoreOverrideCursor(); +} + +void BWSepiaTool::finalRendering() +{ + 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) + { + // Apply black and white filter. + + blackAndWhiteConversion(data, w, h, sb, m_bwFilters->currentItem()); + + // Apply black and white film type. + + blackAndWhiteConversion(data, w, h, sb, m_bwFilm->currentItem() + BWGeneric); + + // Apply color tone filter. + + blackAndWhiteConversion(data, w, h, sb, m_bwTone->currentItem() + BWNoTone); + + // Calculate and apply the curve on image. + + uchar *targetData = new uchar[w*h*(sb ? 8 : 4)]; + m_curvesWidget->curves()->curvesLutSetup(ImageHistogram::AlphaChannel); + m_curvesWidget->curves()->curvesLutProcess(data, targetData, w, h); + + // Adjust contrast. + + DImg img(w, h, sb, a, targetData); + BCGModifier cmod; + cmod.setContrast((double)(m_cInput->value()/100.0) + 1.00); + cmod.applyBCG(img); + + iface->putOriginalImage(i18n("Convert to Black && White"), img.bits()); + + delete [] data; + delete [] targetData; + } + + kapp->restoreOverrideCursor(); +} + +void BWSepiaTool::blackAndWhiteConversion(uchar *data, int w, int h, bool sb, int type) +{ + // Value to multiply RGB 8 bits component of mask used by changeTonality() method. + int mul = sb ? 255 : 1; + DImgImageFilters filter; + double strength = 1.0 + ((double)m_strengthInput->value() - 1.0) * (1.0 / 3.0); + + switch (type) + { + case BWNoFilter: + m_redAttn = 0.0; + m_greenAttn = 0.0; + m_blueAttn = 0.0; + break; + + case BWGreenFilter: + m_redAttn = -0.20 * strength; + m_greenAttn = +0.11 * strength; + m_blueAttn = +0.09 * strength; + break; + + case BWOrangeFilter: + m_redAttn = +0.48 * strength; + m_greenAttn = -0.37 * strength; + m_blueAttn = -0.11 * strength; + break; + + case BWRedFilter: + m_redAttn = +0.60 * strength; + m_greenAttn = -0.49 * strength; + m_blueAttn = -0.11 * strength; + break; + + case BWYellowFilter: + m_redAttn = +0.30 * strength; + m_greenAttn = -0.31 * strength; + m_blueAttn = +0.01 * strength; + break; + + // -------------------------------------------------------------------------------- + + case BWGeneric: + case BWNoTone: + m_redMult = 0.24; + m_greenMult = 0.68; + m_blueMult = 0.08; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWAgfa200X: + m_redMult = 0.18; + m_greenMult = 0.41; + m_blueMult = 0.41; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWAgfapan25: + m_redMult = 0.25; + m_greenMult = 0.39; + m_blueMult = 0.36; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWAgfapan100: + m_redMult = 0.21; + m_greenMult = 0.40; + m_blueMult = 0.39; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWAgfapan400: + m_redMult = 0.20; + m_greenMult = 0.41; + m_blueMult = 0.39; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWIlfordDelta100: + m_redMult = 0.21; + m_greenMult = 0.42; + m_blueMult = 0.37; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWIlfordDelta400: + m_redMult = 0.22; + m_greenMult = 0.42; + m_blueMult = 0.36; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWIlfordDelta400Pro3200: + m_redMult = 0.31; + m_greenMult = 0.36; + m_blueMult = 0.33; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWIlfordFP4: + m_redMult = 0.28; + m_greenMult = 0.41; + m_blueMult = 0.31; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWIlfordHP5: + m_redMult = 0.23; + m_greenMult = 0.37; + m_blueMult = 0.40; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWIlfordPanF: + m_redMult = 0.33; + m_greenMult = 0.36; + m_blueMult = 0.31; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWIlfordXP2Super: + m_redMult = 0.21; + m_greenMult = 0.42; + m_blueMult = 0.37; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWKodakTmax100: + m_redMult = 0.24; + m_greenMult = 0.37; + m_blueMult = 0.39; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWKodakTmax400: + m_redMult = 0.27; + m_greenMult = 0.36; + m_blueMult = 0.37; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWKodakTriX: + m_redMult = 0.25; + m_greenMult = 0.35; + m_blueMult = 0.40; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + // -------------------------------------------------------------------------------- + + case BWSepiaTone: + filter.changeTonality(data, w, h, sb, 162*mul, 132*mul, 101*mul); + break; + + case BWBrownTone: + filter.changeTonality(data, w, h, sb, 129*mul, 115*mul, 104*mul); + break; + + case BWColdTone: + filter.changeTonality(data, w, h, sb, 102*mul, 109*mul, 128*mul); + break; + + case BWSeleniumTone: + filter.changeTonality(data, w, h, sb, 122*mul, 115*mul, 122*mul); + break; + + case BWPlatinumTone: + filter.changeTonality(data, w, h, sb, 115*mul, 110*mul, 106*mul); + break; + + case BWGreenTone: + filter.changeTonality(data, w, h, sb, 108*mul, 116*mul, 100*mul); + break; + + } +} + +//-- Load all settings from file -------------------------------------- + +void BWSepiaTool::slotLoadSettings() +{ + KURL loadFile = KFileDialog::getOpenURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), kapp->activeWindow(), + TQString( i18n("Black & White Settings File to Load")) ); + if( loadFile.isEmpty() ) + return; + + TQFile file(loadFile.path()); + + if (file.open(IO_ReadOnly)) + { + TQTextStream stream(&file); + + if (stream.readLine() != "# Black & White Configuration File") + { + KMessageBox::error(kapp->activeWindow(), + i18n("\"%1\" is not a Black & White settings text file.") + .arg(loadFile.fileName())); + file.close(); + return; + } + + m_bwFilters->blockSignals(true); + m_bwTone->blockSignals(true); + m_cInput->blockSignals(true); + + m_bwFilters->setCurrentItem(stream.readLine().toInt()); + m_bwTone->setCurrentItem(stream.readLine().toInt()); + 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); + } + + for (int i = 0 ; i < 5 ; i++) + m_curvesWidget->curves()->curvesCalculateCurve(i); + + m_bwFilters->blockSignals(false); + m_bwTone->blockSignals(false); + m_cInput->blockSignals(false); + + m_histogramWidget->reset(); + m_previewPixmapFactory->invalidate(); + m_bwFilters->triggerUpdate(false); + m_bwTone->triggerUpdate(false); + + slotEffect(); + } + else + KMessageBox::error(kapp->activeWindow(), + i18n("Cannot load settings from the Black & White text file.")); + + file.close(); +} + +//-- Save all settings to file --------------------------------------- + +void BWSepiaTool::slotSaveAsSettings() +{ + KURL saveFile = KFileDialog::getSaveURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), kapp->activeWindow(), + TQString( i18n("Black & White Settings File to Save"))); + if( saveFile.isEmpty() ) + return; + + TQFile file(saveFile.path()); + + if (file.open(IO_WriteOnly)) + { + TQTextStream stream(&file); + stream << "# Black & White Configuration File\n"; + stream << m_bwFilters->currentItem() << "\n"; + stream << m_bwTone->currentItem() << "\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 Black & White text file.")); + + file.close(); +} + +} // NameSpace DigikamImagesPluginCore diff --git a/src/imageplugins/coreplugin/bwsepiatool.h b/src/imageplugins/coreplugin/bwsepiatool.h new file mode 100644 index 00000000..7145f567 --- /dev/null +++ b/src/imageplugins/coreplugin/bwsepiatool.h @@ -0,0 +1,193 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-06 + * Description : Black and White conversion tool. + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * 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. + * + * ============================================================ */ + + +#ifndef BWSEPIATOOL_H +#define BWSEPIATOOL_H + +// TQt includes. + +#include <tqstring.h> + +// Digikam includes. + +#include "editortool.h" + +class TQHButtonGroup; +class TQComboBox; +class TQButtonGroup; +class TQListBox; + +class KTabWidget; + +namespace KDcrawIface +{ +class RIntNumInput; +} + +namespace Digikam +{ +class HistogramWidget; +class ColorGradientWidget; +class ImageWidget; +class DColor; +class DImg; +class CurvesWidget; +} + +namespace DigikamImagesPluginCore +{ + +class PreviewPixmapFactory; + +class BWSepiaTool : public Digikam::EditorTool +{ + TQ_OBJECT + + +public: + + BWSepiaTool(TQObject *parent); + ~BWSepiaTool(); + + friend class PreviewPixmapFactory; + +protected: + + TQPixmap getThumbnailForEffect(int type); + void finalRendering(); + +private: + + void readSettings(); + void writeSettings(); + void blackAndWhiteConversion(uchar *data, int w, int h, bool sb, int type); + +private slots: + + void slotResetSettings(); + void slotSaveAsSettings(); + void slotLoadSettings(); + void slotEffect(); + void slotChannelChanged(int channel); + void slotScaleChanged(int scale); + void slotSpotColorChanged(const Digikam::DColor &color); + void slotColorSelectedFromTarget( const Digikam::DColor &color ); + void slotFilterSelected(int filter); + +private: + + enum BlackWhiteConversionType + { + BWNoFilter=0, // B&W filter to the front of lens. + BWGreenFilter, + BWOrangeFilter, + BWRedFilter, + BWYellowFilter, + + BWGeneric, // B&W film simulation. + BWAgfa200X, + BWAgfapan25, + BWAgfapan100, + BWAgfapan400, + BWIlfordDelta100, + BWIlfordDelta400, + BWIlfordDelta400Pro3200, + BWIlfordFP4, + BWIlfordHP5, + BWIlfordPanF, + BWIlfordXP2Super, + BWKodakTmax100, + BWKodakTmax400, + BWKodakTriX, + + BWNoTone, // Chemical color tone filter. + BWSepiaTone, + BWBrownTone, + BWColdTone, + BWSeleniumTone, + BWPlatinumTone, + BWGreenTone + }; + + enum HistogramScale + { + Linear=0, + Logarithmic + }; + + enum ColorChannel + { + LuminosityChannel=0, + RedChannel, + GreenChannel, + BlueChannel + }; + + enum SettingsTab + { + FilmTab=0, + BWFiltersTab, + ToneTab, + LuminosityTab + }; + + // Color filter attenuation in percents. + double m_redAttn, m_greenAttn, m_blueAttn; + + // Channel mixer color multiplier. + double m_redMult, m_greenMult, m_blueMult; + + uchar *m_destinationPreviewData; + + TQComboBox *m_channelCB; + + TQHButtonGroup *m_scaleBG; + + TQListBox *m_bwFilters; + TQListBox *m_bwFilm; + TQListBox *m_bwTone; + + KDcrawIface::RIntNumInput *m_cInput; + KDcrawIface::RIntNumInput *m_strengthInput; + + KTabWidget *m_tab; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::ColorGradientWidget *m_hGradient; + + Digikam::HistogramWidget *m_histogramWidget; + + Digikam::CurvesWidget *m_curvesWidget; + + Digikam::DImg *m_originalImage; + Digikam::DImg m_thumbnailImage; + + PreviewPixmapFactory *m_previewPixmapFactory; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* BWSEPIATOOL_H */ diff --git a/src/imageplugins/coreplugin/digikamimageplugin_core.desktop b/src/imageplugins/coreplugin/digikamimageplugin_core.desktop new file mode 100644 index 00000000..8f8b3d10 --- /dev/null +++ b/src/imageplugins/coreplugin/digikamimageplugin_core.desktop @@ -0,0 +1,47 @@ +[Desktop Entry] +Name=ImagePlugin_Core +Name[el]=ΠρόσθετοΕικόνας_Πυρήνας +Name[fi]=Liitännäisten ydin +Name[hr]=Jezgra +Name[it]=PluginImmagini_Nocciolo +Name[nl]=Afbeeldingsplugin_Kern +Name[sr]=Језгро прикључака +Name[sr@Latn]=Jezgro priključaka +Name[sv]=Insticksprogram med bildkärna +Name[tr]=ResimEklentisi_Çekirdek +Name[xx]=xxImagePlugin_Corexx +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=digiKam Core Image Plugin +Comment[bg]=Основна приставка за снимки на digiKam +Comment[ca]=Connector d'imatges bàsic del digiKam +Comment[da]=Grundlæggende Digikam billed-plugin +Comment[de]=digiKam-Kernmodul +Comment[el]=Πρόσθετο εικόνων πυρήνα digiKam +Comment[es]=Plugin fundamental de digiKam de imágenes +Comment[et]=DigiKami peamine pildiplugin +Comment[fa]=وصلۀ تصویر هستۀ digiKam +Comment[fi]=digiKamin liitännäisten ydin +Comment[gl]=Plugin de Imaxe Básico de digiKam +Comment[hr]=digiKam dodatak za slike +Comment[it]=Plugin delle immagini centrale di digiKam +Comment[ja]=digiKam コア画像プラグイン +Comment[nds]=Karn-Bildmoduul vun digiKam +Comment[nl]=Digikam kernafbeeldingsplugin +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਕੋਰ ਚਿੱਤਰ ਪਲੱਗਇਨ +Comment[pl]=Podstawowa wtyczka obrazu digiKama +Comment[pt]='Plugin' de Imagem Básico do digiKam +Comment[pt_BR]=Plugin digiKam para Centralização da imagem +Comment[ru]=Модуль digiKam основная работа с изображением +Comment[sk]=Základný obrázkový plugin digiKamu +Comment[sr]=Језгро digiKam-ових сликовних прикључака +Comment[sr@Latn]=Jezgro digiKam-ovih slikovnih priključaka +Comment[sv]=Insticksprogram med bildkärna för Digikam +Comment[tr]=digiKam Çekirdek Resim Eklentisi +Comment[uk]=Втулок основи зображення для digiKam +Comment[vi]=Phần bổ sung ảnh lõi digiKam +Comment[xx]=xxdigiKam Core Image Pluginxx + +X-TDE-Library=digikamimageplugin_core +author=Caulier Gilles, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/coreplugin/digikamimageplugin_core_ui.rc b/src/imageplugins/coreplugin/digikamimageplugin_core_ui.rc new file mode 100644 index 00000000..cb1148bd --- /dev/null +++ b/src/imageplugins/coreplugin/digikamimageplugin_core_ui.rc @@ -0,0 +1,56 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="7" name="digikamimageplugin_core" > + + <MenuBar> + + <Menu name="Color"><text>&Color</text> + <Action name="implugcore_autocorrection" /> + <Action name="imageplugin_whitebalance" /> + <Action name="implugcore_bcg" /> + <Action name="implugcore_hsl" /> + <Action name="imageplugin_colorfx" /> + <Action name="implugcore_rgb" /> + <Separator /> + <Action name="imageplugin_adjustcurves" /> + <Action name="imageplugin_adjustlevels" /> + <Action name="implugcore_invert" /> + <Action name="implugcore_blackwhite" /> + <Menu name="Depth"><text>&Depth</text> + <Action name="implugcore_convertto8bits" /> + <Action name="implugcore_convertto16bits" /> + </Menu> + <Separator /> + <Action name="implugcore_colormanagement" /> + <Separator /> + </Menu> + <Menu name="Enhance"><text>Enh&ance</text> + <Action name="implugcore_sharpen" /> + <Action name="implugcore_blur" /> + <Separator /> + <Action name="implugcore_redeye" /> + </Menu> + + <Menu name="Transform" ><text>Tra&nsform</text> + <Action name="implugcore_ratiocrop" /> + </Menu> + + <Menu name="Filters" ><text>F&ilters</text> + <Action name="imageplugin_infrared" /> + <Action name="imageplugin_filmgrain" /> + <Action name="imageplugin_oilpaint" /> + <Action name="imageplugin_charcoal" /> + <Action name="imageplugin_emboss" /> + <Action name="imageplugin_distortionfx" /> + <Action name="imageplugin_blurfx" /> + <Action name="imageplugin_raindrop" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties/> + +</kpartgui> diff --git a/src/imageplugins/coreplugin/hsl/Makefile.am b/src/imageplugins/coreplugin/hsl/Makefile.am new file mode 100644 index 00000000..4465d44c --- /dev/null +++ b/src/imageplugins/coreplugin/hsl/Makefile.am @@ -0,0 +1,26 @@ +noinst_LTLIBRARIES = libhsl.la +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +libhsl_la_SOURCES = hsltool.cpp hspreviewwidget.cpp + +libhsl_la_LDFLAGS = $(all_libraries) + +noinst_HEADERS = hsltool.h hspreviewwidget.h + diff --git a/src/imageplugins/coreplugin/hsl/hsltool.cpp b/src/imageplugins/coreplugin/hsl/hsltool.cpp new file mode 100644 index 00000000..5fa3d746 --- /dev/null +++ b/src/imageplugins/coreplugin/hsl/hsltool.cpp @@ -0,0 +1,453 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-16 + * Description : digiKam image editor to adjust Hue, Saturation, + * and Lightness of picture. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqcolor.h> +#include <tqcombobox.h> +#include <tqframe.h> +#include <tqgroupbox.h> +#include <tqhbuttongroup.h> +#include <tqhgroupbox.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqpushbutton.h> +#include <tqtimer.h> +#include <tqtooltip.h> +#include <tqvbox.h> +#include <tqvgroupbox.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeapplication.h> +#include <kcolordialog.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <kstandarddirs.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> + +// Digikam includes. + +#include "colorgradientwidget.h" +#include "dimg.h" +#include "editortoolsettings.h" +#include "histogramwidget.h" +#include "hslmodifier.h" +#include "hspreviewwidget.h" +#include "imageiface.h" +#include "imagewidget.h" + +// Local includes. + +#include "hsltool.h" +#include "hsltool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamImagesPluginCore +{ + +HSLTool::HSLTool(TQObject* parent) + : EditorTool(parent) +{ + setName("adjusthsl"); + setToolName(i18n("Hue / Saturation / Lightness")); + setToolIcon(SmallIcon("adjusthsl")); + setToolHelp("hsladjusttool.anchor"); + + m_destinationPreviewData = 0; + + ImageIface iface(0, 0); + m_originalImage = iface.getOriginalImg(); + + m_previewWidget = new ImageWidget("hsladjust Tool", 0, + i18n("<p>Here you can see the image " + "Hue/Saturation/Lightness adjustments preview. " + "You can pick color on image " + "to see the color level corresponding on histogram.")); + setToolView(m_previewWidget); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel); + + TQGridLayout* gridSettings = new TQGridLayout(m_gboxSettings->plainPage(), 11, 4); + + 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("<p>Select the histogram channel to display here:<p>" + "<b>Luminosity</b>: display the image's luminosity values.<p>" + "<b>Red</b>: display the red image-channel values.<p>" + "<b>Green</b>: display the green image-channel values.<p>" + "<b>Blue</b>: display the blue image-channel values.<p>")); + + 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("<p>Select the histogram scale here.<p>" + "If the image's maximal counts are small, you can use the linear scale.<p>" + "Logarithmic scale can be used when the maximal counts 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("<p>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("<p>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, 4); + + // ------------------------------------------------------------- + + TQVBox *histoBox = new TQVBox(m_gboxSettings->plainPage()); + m_histogramWidget = new HistogramWidget(256, 140, histoBox, false, true, true); + TQWhatsThis::add( m_histogramWidget, i18n("<p>Here you can see the target preview image histogram drawing " + "of the selected image channel. This one is re-computed at any " + "settings 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, 4); + + // ------------------------------------------------------------- + + m_HSSelector = new KHSSelector(m_gboxSettings->plainPage()); + TQWhatsThis::add( m_HSSelector, i18n("<p>Select the hue and saturation adjustments of the image here.")); + m_HSSelector->setMinimumSize(256, 142); + gridSettings->addMultiCellWidget(m_HSSelector, 3, 3, 0, 4); + + m_HSPreview = new HSPreviewWidget(m_gboxSettings->plainPage()); + TQWhatsThis::add( m_HSPreview, i18n("<p>You can see here a color preview of the hue and " + "saturation adjustments.")); + m_HSPreview->setMinimumSize(256, 15); + gridSettings->addMultiCellWidget(m_HSPreview, 4, 4, 0, 4); + + TQLabel *label2 = new TQLabel(i18n("Hue:"), m_gboxSettings->plainPage()); + m_hInput = new RDoubleNumInput(m_gboxSettings); + m_hInput->setPrecision(0); + m_hInput->setRange(-180.0, 180.0, 1.0); + m_hInput->setDefaultValue(0.0); + TQWhatsThis::add( m_hInput, i18n("<p>Set here the hue adjustment of the image.")); + gridSettings->addMultiCellWidget(label2, 5, 5, 0, 4); + gridSettings->addMultiCellWidget(m_hInput, 6, 6, 0, 4); + + TQLabel *label3 = new TQLabel(i18n("Saturation:"), m_gboxSettings->plainPage()); + m_sInput = new RDoubleNumInput(m_gboxSettings); + m_sInput->setPrecision(2); + m_sInput->setRange(-100.0, 100.0, 0.01); + m_sInput->setDefaultValue(0.0); + TQWhatsThis::add( m_sInput, i18n("<p>Set here the saturation adjustment of the image.")); + gridSettings->addMultiCellWidget(label3, 7, 7, 0, 4); + gridSettings->addMultiCellWidget(m_sInput, 8, 8, 0, 4); + + TQLabel *label4 = new TQLabel(i18n("Lightness:"), m_gboxSettings->plainPage()); + m_lInput = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_lInput->setPrecision(2); + m_lInput->setRange(-100.0, 100.0, 0.01); + m_lInput->setDefaultValue(0.0); + TQWhatsThis::add( m_lInput, i18n("<p>Set here the lightness adjustment of the image.")); + gridSettings->addMultiCellWidget(label4, 9, 9, 0, 4); + gridSettings->addMultiCellWidget(m_lInput, 10, 10, 0, 4); + + gridSettings->setRowStretch(11, 10); + setToolSettings(m_gboxSettings); + init(); + + // ------------------------------------------------------------- + + connect(m_HSSelector, TQ_SIGNAL(valueChanged(int, int)), + this, TQ_SLOT(slotHSChanged(int, int))); + + 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_previewWidget, TQ_SIGNAL(spotPositionChangedFromTarget( const Digikam::DColor &, const TQPoint & )), + this, TQ_SLOT(slotColorSelectedFromTarget( const Digikam::DColor & ))); + + connect(m_hInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_hInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotHChanged(double))); + + connect(m_sInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_sInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotSChanged(double))); + + connect(m_lInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_previewWidget, TQ_SIGNAL(signalResized()), + this, TQ_SLOT(slotEffect())); + + // ------------------------------------------------------------- + + m_gboxSettings->enableButton(EditorToolSettings::Ok, false); +} + +HSLTool::~HSLTool() +{ + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; +} + +void HSLTool::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 HSLTool::slotScaleChanged(int scale) +{ + m_histogramWidget->m_scaleType = scale; + m_histogramWidget->repaint(false); +} + +void HSLTool::slotColorSelectedFromTarget( const DColor &color ) +{ + m_histogramWidget->setHistogramGuideByColor(color); +} + +void HSLTool::slotHSChanged(int h, int s) +{ + double hue = double(h); + if (h >= 180 && h <= 359) + hue = double(h) - 359.0; + + double sat = ((double) s * (200.0 / 255.0)) - 100.0; + + m_hInput->blockSignals(true); + m_sInput->blockSignals(true); + + m_hInput->setValue(hue); + m_sInput->setValue(sat); + + m_hInput->blockSignals(false); + m_sInput->blockSignals(false); + + slotTimer(); +} + +void HSLTool::slotHChanged(double h) +{ + int hue = int(h); + if (h >= -180 && h < 0) + hue = int(h) + 359; + + m_HSSelector->blockSignals(true); + m_HSSelector->setXValue(hue); + m_HSSelector->blockSignals(false); +} + +void HSLTool::slotSChanged(double s) +{ + int sat = (int) ((s + 100.0) * (255.0 / 200.0)); + + m_HSSelector->blockSignals(true); + m_HSSelector->setYValue(sat); + m_HSSelector->blockSignals(false); +} + +void HSLTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("hsladjust Tool"); + m_channelCB->setCurrentItem(config->readNumEntry("Histogram Channel", 0)); // Luminosity. + m_scaleBG->setButton(config->readNumEntry("Histogram Scale", HistogramWidget::LogScaleHistogram)); + m_hInput->setValue(config->readDoubleNumEntry("HueAjustment", m_hInput->defaultValue())); + m_sInput->setValue(config->readDoubleNumEntry("SaturationAjustment", m_sInput->defaultValue())); + m_lInput->setValue(config->readDoubleNumEntry("LighnessAjustment", m_lInput->defaultValue())); + slotHChanged(m_hInput->value()); + slotSChanged(m_sInput->value()); + + m_histogramWidget->reset(); + + slotChannelChanged(m_channelCB->currentItem()); + slotScaleChanged(m_scaleBG->selectedId()); +} + +void HSLTool::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("hsladjust Tool"); + config->writeEntry("Histogram Channel", m_channelCB->currentItem()); + config->writeEntry("Histogram Scale", m_scaleBG->selectedId()); + config->writeEntry("HueAjustment", m_hInput->value()); + config->writeEntry("SaturationAjustment", m_sInput->value()); + config->writeEntry("LighnessAjustment", m_lInput->value()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void HSLTool::slotResetSettings() +{ + m_hInput->blockSignals(true); + m_sInput->blockSignals(true); + m_lInput->blockSignals(true); + + m_hInput->slotReset(); + m_sInput->slotReset(); + m_lInput->slotReset(); + + slotHChanged(0.0); + slotSChanged(0.0); + + slotEffect(); + + m_hInput->blockSignals(false); + m_sInput->blockSignals(false); + m_lInput->blockSignals(false); +} + +void HSLTool::slotEffect() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + + double hu = m_hInput->value(); + double sa = m_sInput->value(); + double lu = m_lInput->value(); + + m_gboxSettings->enableButton(EditorToolSettings::Ok, + ( hu != 0.0 || sa != 0.0 || lu != 0.0)); + + m_HSPreview->setHS(hu, sa); + m_histogramWidget->stopHistogramComputation(); + + 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); + HSLModifier cmod; + cmod.setHue(hu); + cmod.setSaturation(sa); + cmod.setLightness(lu); + cmod.applyHSL(preview); + iface->putPreviewImage(preview.bits()); + + m_previewWidget->updatePreview(); + + // Update histogram. + + memcpy(m_destinationPreviewData, preview.bits(), preview.numBytes()); + m_histogramWidget->updateData(m_destinationPreviewData, w, h, sb, 0, 0, 0, false); + + kapp->restoreOverrideCursor(); +} + +void HSLTool::finalRendering() +{ + kapp->setOverrideCursor(KCursor::waitCursor()); + + double hu = m_hInput->value(); + double sa = m_sInput->value(); + double lu = m_lInput->value(); + + 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(); + DImg original(w, h, sb, a, data); + delete [] data; + + HSLModifier cmod; + cmod.setHue(hu); + cmod.setSaturation(sa); + cmod.setLightness(lu); + cmod.applyHSL(original); + + iface->putOriginalImage(i18n("HSL Adjustments"), original.bits()); + kapp->restoreOverrideCursor(); +} + +} // NameSpace DigikamImagesPluginCore + diff --git a/src/imageplugins/coreplugin/hsl/hsltool.h b/src/imageplugins/coreplugin/hsl/hsltool.h new file mode 100644 index 00000000..751bacf3 --- /dev/null +++ b/src/imageplugins/coreplugin/hsl/hsltool.h @@ -0,0 +1,126 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-16 + * Description : digiKam image editor to adjust Hue, Saturation, + * and Lightness of picture. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef HSLTOOL_H +#define HSLTOOL_H + +// Digikam includes. + +#include "editortool.h" + +class TQComboBox; +class TQHButtonGroup; + +class KHSSelector; + +namespace KDcrawIface +{ +class RDoubleNumInput; +} + +namespace Digikam +{ +class HistogramWidget; +class ColorGradientWidget; +class ImageWidget; +class DColor; +class DImg; +class EditorToolSettings; +} + +namespace DigikamImagesPluginCore +{ +class HSPreviewWidget; + +class HSLTool : public Digikam::EditorTool +{ + TQ_OBJECT + + +public: + + HSLTool(TQObject *parent); + ~HSLTool(); + +private slots: + + void slotEffect(); + void slotChannelChanged(int channel); + void slotScaleChanged(int scale); + void slotColorSelectedFromTarget( const Digikam::DColor &color ); + void slotHSChanged(int h, int s); + void slotHChanged(double h); + void slotSChanged(double s); + void slotResetSettings(); + +private: + + void writeSettings(); + void readSettings(); + void finalRendering(); + +private: + + enum HistogramScale + { + Linear=0, + Logarithmic + }; + + enum ColorChannel + { + LuminosityChannel=0, + RedChannel, + GreenChannel, + BlueChannel + }; + + uchar *m_destinationPreviewData; + + TQComboBox *m_channelCB; + + TQHButtonGroup *m_scaleBG; + + KDcrawIface::RDoubleNumInput *m_hInput; + KDcrawIface::RDoubleNumInput *m_sInput; + KDcrawIface::RDoubleNumInput *m_lInput; + + KHSSelector *m_HSSelector; + + HSPreviewWidget *m_HSPreview; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::ColorGradientWidget *m_hGradient; + + Digikam::HistogramWidget *m_histogramWidget; + + Digikam::DImg *m_originalImage; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* HSLTOOL_H */ diff --git a/src/imageplugins/coreplugin/hsl/hspreviewwidget.cpp b/src/imageplugins/coreplugin/hsl/hspreviewwidget.cpp new file mode 100644 index 00000000..3841ca38 --- /dev/null +++ b/src/imageplugins/coreplugin/hsl/hspreviewwidget.cpp @@ -0,0 +1,126 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-01-08 + * Description : Hue/Saturation preview widget + * + * Copyright (C) 2007 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqdrawutil.h> +#include <tqimage.h> +#include <tqpainter.h> +#include <tqpixmap.h> + +// KDE includes. + +#include <tdeapplication.h> +#include <tdelocale.h> +#include <kimageeffect.h> + +// Local includes. + +#include "hslmodifier.h" +#include "dimg.h" +#include "hspreviewwidget.h" +#include "hspreviewwidget.moc" + +namespace DigikamImagesPluginCore +{ + +class HSPreviewWidgetPrivate +{ + +public: + + HSPreviewWidgetPrivate() + { + hue = 0.0; + sat = 0.0; + } + + int xBorder; + + double hue; + double sat; + + TQPixmap pixmap; +}; + +HSPreviewWidget::HSPreviewWidget(TQWidget *parent, int xBorder) + : TQWidget(parent, 0, TQt::WDestructiveClose) +{ + d = new HSPreviewWidgetPrivate; + d->xBorder = xBorder; +} + +HSPreviewWidget::~HSPreviewWidget() +{ + delete d; +} + +void HSPreviewWidget::setHS(double hue, double sat) +{ + d->hue = hue; + d->sat = sat; + updatePixmap(); + update(); +} + +void HSPreviewWidget::resizeEvent( TQResizeEvent * ) +{ + updatePixmap(); +} + +void HSPreviewWidget::paintEvent( TQPaintEvent * ) +{ + bitBlt(this, 0+d->xBorder, 0, &d->pixmap); +} + +void HSPreviewWidget::updatePixmap() +{ + int xSize = width()-2*d->xBorder; + int ySize = height(); + + Digikam::DImg image(xSize, ySize, false, false, 0, false); + TQColor col; + uint *p; + + for ( int s = ySize-1; s >= 0; s-- ) + { + p = (uint *)image.scanLine(ySize - s - 1); + + for( int h = 0 ; h < xSize ; h++ ) + { + col.setHsv( 359*h/(xSize-1), 255, 192 ); + *p = col.rgb(); + p++; + } + } + + Digikam::HSLModifier cmod; + cmod.setHue(d->hue); + cmod.setSaturation(d->sat); + cmod.setLightness(0.0); + cmod.applyHSL(image); + + d->pixmap = image.convertToPixmap(); +} + +} // NameSpace DigikamImagesPluginCore diff --git a/src/imageplugins/coreplugin/hsl/hspreviewwidget.h b/src/imageplugins/coreplugin/hsl/hspreviewwidget.h new file mode 100644 index 00000000..3744907c --- /dev/null +++ b/src/imageplugins/coreplugin/hsl/hspreviewwidget.h @@ -0,0 +1,64 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-01-08 + * Description : Hue/Saturation preview widget + * + * Copyright (C) 2007 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. + * + * ============================================================ */ + +#ifndef HSPREVIEWWIDGET_H +#define HSPREVIEWWIDGET_H + +// TQt includes. + +#include <tqwidget.h> + +namespace DigikamImagesPluginCore +{ + +class HSPreviewWidgetPrivate; + +class HSPreviewWidget : public TQWidget +{ + TQ_OBJECT + + +public: + + HSPreviewWidget(TQWidget *parent=0, int xBorder=0); + ~HSPreviewWidget(); + + void setHS(double hue, double sat); + +protected: + + void resizeEvent( TQResizeEvent * ); + void paintEvent( TQPaintEvent * ); + +private: + + void updatePixmap(); + +private: + + HSPreviewWidgetPrivate *d; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* HSPREVIEWWIDGET_H */ diff --git a/src/imageplugins/coreplugin/hsl/imageeffect_hsl.cpp b/src/imageplugins/coreplugin/hsl/imageeffect_hsl.cpp new file mode 100644 index 00000000..e179d36f --- /dev/null +++ b/src/imageplugins/coreplugin/hsl/imageeffect_hsl.cpp @@ -0,0 +1,428 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-16 + * Description : digiKam image editor to adjust Hue, Saturation, + * and Lightness of picture. + * + * Copyright (C) 2004-2007 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqcolor.h> +#include <tqgroupbox.h> +#include <tqhgroupbox.h> +#include <tqvgroupbox.h> +#include <tqvbox.h> +#include <tqhbuttongroup.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqframe.h> +#include <tqlabel.h> +#include <tqpushbutton.h> +#include <tqcombobox.h> +#include <tqwhatsthis.h> +#include <tqtooltip.h> +#include <tqtimer.h> + +// KDE includes. + +#include <knuminput.h> +#include <tdelocale.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <kstandarddirs.h> +#include <kcolordialog.h> + +// Digikam includes. + +#include "imageiface.h" +#include "imagewidget.h" +#include "histogramwidget.h" +#include "colorgradientwidget.h" +#include "hslmodifier.h" +#include "dimg.h" + +// Local includes. + +#include "hspreviewwidget.h" +#include "imageeffect_hsl.h" +#include "imageeffect_hsl.moc" + +namespace DigikamImagesPluginCore +{ + +ImageEffect_HSL::ImageEffect_HSL(TQWidget* parent) + : Digikam::ImageDlgBase(parent, i18n("Hue/Saturation/Lightness"), "hsladjust", false) +{ + m_destinationPreviewData = 0L; + setHelp("hsladjusttool.anchor", "digikam"); + + m_previewWidget = new Digikam::ImageWidget("hsladjust Tool Dialog", plainPage(), + i18n("<p>Here you can see the image " + "Hue/Saturation/Lightness adjustments preview. " + "You can pick color on image " + "to see the color level corresponding on histogram.")); + setPreviewAreaWidget(m_previewWidget); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(plainPage()); + TQGridLayout* gridSettings = new TQGridLayout(gboxSettings, 11, 4, spacingHint()); + + TQLabel *label1 = new TQLabel(i18n("Channel:"), gboxSettings); + label1->setAlignment ( TQt::AlignRight | TQt::AlignVCenter ); + m_channelCB = new TQComboBox( false, gboxSettings ); + 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("<p>Select the histogram channel to display here:<p>" + "<b>Luminosity</b>: display the image's luminosity values.<p>" + "<b>Red</b>: display the red image-channel values.<p>" + "<b>Green</b>: display the green image-channel values.<p>" + "<b>Blue</b>: display the blue image-channel values.<p>")); + + m_scaleBG = new TQHButtonGroup(gboxSettings); + m_scaleBG->setExclusive(true); + m_scaleBG->setFrameShape(TQFrame::NoFrame); + m_scaleBG->setInsideMargin( 0 ); + TQWhatsThis::add( m_scaleBG, i18n("<p>Select the histogram scale here.<p>" + "If the image's maximal counts are small, you can use the linear scale.<p>" + "Logarithmic scale can be used when the maximal counts 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( "<p>Linear" ) ); + m_scaleBG->insert(linHistoButton, Digikam::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( "<p>Logarithmic" ) ); + m_scaleBG->insert(logHistoButton, Digikam::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, 4); + + // ------------------------------------------------------------- + + TQVBox *histoBox = new TQVBox(gboxSettings); + m_histogramWidget = new Digikam::HistogramWidget(256, 140, histoBox, false, true, true); + TQWhatsThis::add( m_histogramWidget, i18n("<p>Here you can see the target preview image histogram drawing " + "of the selected image channel. This one is re-computed at any " + "settings changes.")); + TQLabel *space = new TQLabel(histoBox); + space->setFixedHeight(1); + m_hGradient = new Digikam::ColorGradientWidget( Digikam::ColorGradientWidget::Horizontal, 10, histoBox ); + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + + gridSettings->addMultiCellWidget(histoBox, 1, 2, 0, 4); + + // ------------------------------------------------------------- + + m_HSSelector = new KHSSelector(gboxSettings); + TQWhatsThis::add( m_HSSelector, i18n("<p>Select the hue and saturation adjustments of the image here.")); + m_HSSelector->setMinimumSize(256, 142); + gridSettings->addMultiCellWidget(m_HSSelector, 3, 3, 0, 4); + + m_HSPreview = new HSPreviewWidget(gboxSettings, spacingHint()); + TQWhatsThis::add( m_HSPreview, i18n("<p>You can see here a color preview of the hue and " + "saturation adjustments.")); + m_HSPreview->setMinimumSize(256, 15); + gridSettings->addMultiCellWidget(m_HSPreview, 4, 4, 0, 4); + + TQLabel *label2 = new TQLabel(i18n("Hue:"), gboxSettings); + m_hInput = new KDoubleNumInput(gboxSettings); + m_hInput->setPrecision(0); + m_hInput->setRange(-180.0, 180.0, 1.0, true); + m_hInput->setValue(0.0); + TQWhatsThis::add( m_hInput, i18n("<p>Set here the hue adjustment of the image.")); + gridSettings->addMultiCellWidget(label2, 5, 5, 0, 4); + gridSettings->addMultiCellWidget(m_hInput, 6, 6, 0, 4); + + TQLabel *label3 = new TQLabel(i18n("Saturation:"), gboxSettings); + m_sInput = new KDoubleNumInput(gboxSettings); + m_sInput->setPrecision(2); + m_sInput->setRange(-100.0, 100.0, 0.01, true); + m_sInput->setValue(0.0); + TQWhatsThis::add( m_sInput, i18n("<p>Set here the saturation adjustment of the image.")); + gridSettings->addMultiCellWidget(label3, 7, 7, 0, 4); + gridSettings->addMultiCellWidget(m_sInput, 8, 8, 0, 4); + + TQLabel *label4 = new TQLabel(i18n("Lightness:"), gboxSettings); + m_lInput = new KDoubleNumInput(gboxSettings); + m_lInput->setPrecision(2); + m_lInput->setRange(-100.0, 100.0, 0.01, true); + m_lInput->setValue(0.0); + TQWhatsThis::add( m_lInput, i18n("<p>Set here the lightness adjustment of the image.")); + gridSettings->addMultiCellWidget(label4, 9, 9, 0, 4); + gridSettings->addMultiCellWidget(m_lInput, 10, 10, 0, 4); + + gridSettings->setRowStretch(11, 10); + setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + connect(m_HSSelector, TQ_SIGNAL(valueChanged(int, int)), + this, TQ_SLOT(slotHSChanged(int, int))); + + 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_previewWidget, TQ_SIGNAL(spotPositionChangedFromTarget( const Digikam::DColor &, const TQPoint & )), + this, TQ_SLOT(slotColorSelectedFromTarget( const Digikam::DColor & ))); + + connect(m_hInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_hInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotHChanged(double))); + + connect(m_sInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_sInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotSChanged(double))); + + connect(m_lInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_previewWidget, TQ_SIGNAL(signalResized()), + this, TQ_SLOT(slotEffect())); + + // ------------------------------------------------------------- + + enableButtonOK( false ); +} + +ImageEffect_HSL::~ImageEffect_HSL() +{ + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + delete m_histogramWidget; + delete m_previewWidget; +} + +void ImageEffect_HSL::slotChannelChanged(int channel) +{ + switch(channel) + { + case LuminosityChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::ValueHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + break; + + case RedChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::RedChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "red" ) ); + break; + + case GreenChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::GreenChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "green" ) ); + break; + + case BlueChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::BlueChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "blue" ) ); + break; + } + + m_histogramWidget->repaint(false); +} + +void ImageEffect_HSL::slotScaleChanged(int scale) +{ + m_histogramWidget->m_scaleType = scale; + m_histogramWidget->repaint(false); +} + +void ImageEffect_HSL::slotColorSelectedFromTarget( const Digikam::DColor &color ) +{ + m_histogramWidget->setHistogramGuideByColor(color); +} + +void ImageEffect_HSL::slotHSChanged(int h, int s) +{ + double hue = double(h); + if (h >= 180 && h <= 359) + hue = double(h) - 359.0; + + double sat = ((double)s * (200.0/255.0)) - 100.0; + + m_hInput->blockSignals(true); + m_sInput->blockSignals(true); + m_hInput->setValue(hue); + m_sInput->setValue(sat); + m_hInput->blockSignals(false); + m_sInput->blockSignals(false); + slotTimer(); +} + +void ImageEffect_HSL::slotHChanged(double h) +{ + int hue = int(h); + if (h >= -180 && h < 0) + hue = int(h) + 359; + + m_HSSelector->blockSignals(true); + m_HSSelector->setXValue(hue); + m_HSSelector->blockSignals(false); +} + +void ImageEffect_HSL::slotSChanged(double s) +{ + int sat = (int)((s + 100.0) * (255.0/200.0)); + + m_HSSelector->blockSignals(true); + m_HSSelector->setYValue(sat); + m_HSSelector->blockSignals(false); +} + +void ImageEffect_HSL::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("hsladjust Tool Dialog"); + m_channelCB->setCurrentItem(config->readNumEntry("Histogram Channel", 0)); // Luminosity. + m_scaleBG->setButton(config->readNumEntry("Histogram Scale", Digikam::HistogramWidget::LogScaleHistogram)); + m_hInput->setValue(config->readDoubleNumEntry("HueAjustment", 0.0)); + m_sInput->setValue(config->readDoubleNumEntry("SaturationAjustment", 0.0)); + m_lInput->setValue(config->readDoubleNumEntry("LighnessAjustment", 0.0)); + slotHChanged(m_hInput->value()); + slotSChanged(m_sInput->value()); + slotChannelChanged(m_channelCB->currentItem()); + slotScaleChanged(m_scaleBG->selectedId()); +} + +void ImageEffect_HSL::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("hsladjust Tool Dialog"); + config->writeEntry("Histogram Channel", m_channelCB->currentItem()); + config->writeEntry("Histogram Scale", m_scaleBG->selectedId()); + config->writeEntry("HueAjustment", m_hInput->value()); + config->writeEntry("SaturationAjustment", m_sInput->value()); + config->writeEntry("LighnessAjustment", m_lInput->value()); + config->sync(); +} + +void ImageEffect_HSL::resetValues() +{ + m_hInput->blockSignals(true); + m_sInput->blockSignals(true); + m_lInput->blockSignals(true); + m_hInput->setValue(0.0); + m_sInput->setValue(0.0); + m_lInput->setValue(0.0); + slotHChanged(0.0); + slotSChanged(0.0); + m_hInput->blockSignals(false); + m_sInput->blockSignals(false); + m_lInput->blockSignals(false); +} + +void ImageEffect_HSL::slotEffect() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + + double hu = m_hInput->value(); + double sa = m_sInput->value(); + double lu = m_lInput->value(); + + enableButtonOK( hu != 0.0 || sa != 0.0 || lu != 0.0); + + m_HSPreview->setHS(hu, sa); + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + Digikam::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(); + + Digikam::DImg preview(w, h, sb, a, m_destinationPreviewData); + Digikam::HSLModifier cmod; + cmod.setHue(hu); + cmod.setSaturation(sa); + cmod.setLightness(lu); + cmod.applyHSL(preview); + iface->putPreviewImage(preview.bits()); + + m_previewWidget->updatePreview(); + + // Update histogram. + + memcpy(m_destinationPreviewData, preview.bits(), preview.numBytes()); + m_histogramWidget->updateData(m_destinationPreviewData, w, h, sb, 0, 0, 0, false); + + kapp->restoreOverrideCursor(); +} + +void ImageEffect_HSL::finalRendering() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + + double hu = m_hInput->value(); + double sa = m_sInput->value(); + double lu = m_lInput->value(); + + Digikam::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(); + Digikam::DImg original(w, h, sb, a, data); + delete [] data; + + Digikam::HSLModifier cmod; + cmod.setHue(hu); + cmod.setSaturation(sa); + cmod.setLightness(lu); + cmod.applyHSL(original); + + iface->putOriginalImage(i18n("HSL Adjustments"), original.bits()); + kapp->restoreOverrideCursor(); + accept(); +} + +} // NameSpace DigikamImagesPluginCore + diff --git a/src/imageplugins/coreplugin/hsl/imageeffect_hsl.h b/src/imageplugins/coreplugin/hsl/imageeffect_hsl.h new file mode 100644 index 00000000..24880f4d --- /dev/null +++ b/src/imageplugins/coreplugin/hsl/imageeffect_hsl.h @@ -0,0 +1,116 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-16 + * Description : digiKam image editor to adjust Hue, Saturation, + * and Lightness of picture. + * + * Copyright (C) 2004-2007 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_HSL_H +#define IMAGEEFFECT_HSL_H + +// Digikam include. + +#include "imagedlgbase.h" + +class TQComboBox; +class TQHButtonGroup; + +class KDoubleNumInput; +class KHSSelector; + +namespace Digikam +{ +class HistogramWidget; +class ColorGradientWidget; +class ImageWidget; +class DColor; +} + +namespace DigikamImagesPluginCore +{ +class HSPreviewWidget; + +class ImageEffect_HSL : public Digikam::ImageDlgBase +{ + TQ_OBJECT + + +public: + + ImageEffect_HSL(TQWidget *parent); + ~ImageEffect_HSL(); + +private slots: + + void slotEffect(); + void slotChannelChanged(int channel); + void slotScaleChanged(int scale); + void slotColorSelectedFromTarget( const Digikam::DColor &color ); + void slotHSChanged(int h, int s); + void slotHChanged(double h); + void slotSChanged(double s); + +private: + + void writeUserSettings(); + void readUserSettings(); + void resetValues(); + void finalRendering(); + +private: + + enum HistogramScale + { + Linear=0, + Logarithmic + }; + + enum ColorChannel + { + LuminosityChannel=0, + RedChannel, + GreenChannel, + BlueChannel + }; + + uchar *m_destinationPreviewData; + + TQComboBox *m_channelCB; + + TQHButtonGroup *m_scaleBG; + + KDoubleNumInput *m_hInput; + KDoubleNumInput *m_sInput; + KDoubleNumInput *m_lInput; + + KHSSelector *m_HSSelector; + + HSPreviewWidget *m_HSPreview; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::ColorGradientWidget *m_hGradient; + + Digikam::HistogramWidget *m_histogramWidget; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* IMAGEEFFECT_HSL_H */ diff --git a/src/imageplugins/coreplugin/iccprooftool.cpp b/src/imageplugins/coreplugin/iccprooftool.cpp new file mode 100644 index 00000000..b74adf9a --- /dev/null +++ b/src/imageplugins/coreplugin/iccprooftool.cpp @@ -0,0 +1,1310 @@ +/* ============================================================ + * + * 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 <fj.cruz@supercable.es> + * 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqcheckbox.h> +#include <tqcolor.h> +#include <tqcombobox.h> +#include <tqfile.h> +#include <tqframe.h> +#include <tqgroupbox.h> +#include <tqhbox.h> +#include <tqhbuttongroup.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqpoint.h> +#include <tqpushbutton.h> +#include <tqradiobutton.h> +#include <tqtextstream.h> +#include <tqtoolbox.h> +#include <tqtooltip.h> +#include <tqvbox.h> +#include <tqvbuttongroup.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <tdefile.h> +#include <tdefiledialog.h> +#include <tdeglobalsettings.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <ksqueezedtextlabel.h> +#include <kstandarddirs.h> +#include <ktabwidget.h> +#include <kurllabel.h> +#include <kurlrequester.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> +#include <libkdcraw/rcombobox.h> + +// 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("<p>Here you can see the image preview after " + "applying a color profile</p>")); + 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("<p>Select the histogram channel to display here:<p>" + "<b>Luminosity</b>: display the image's luminosity values.<p>" + "<b>Red</b>: display the red channel values.<p>" + "<b>Green</b>: display the green channel values.<p>" + "<b>Blue</b>: display the blue channel values.<p>")); + + 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("<p>Select the histogram scale here.<p>" + "If the image's maximal values are small, you can use the linear scale.<p>" + "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("<p>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("<p>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("<p>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("<p>Here you can set general parameters.</p>")); + + TQGridLayout *zeroPageLayout = new TQGridLayout(generalOptions, 5, 1); + + m_doSoftProofBox = new TQCheckBox(generalOptions); + m_doSoftProofBox->setText(i18n("Soft-proofing")); + TQWhatsThis::add(m_doSoftProofBox, i18n("<p>Rendering emulation of the device described " + "by the \"Proofing\" profile. Useful to preview the final " + "result without rendering to physical medium.</p>")); + + m_checkGamutBox = new TQCheckBox(generalOptions); + m_checkGamutBox->setText(i18n("Check gamut")); + TQWhatsThis::add(m_checkGamutBox, i18n("<p>You can use this option if you want to show " + "the colors that are outside the printer's gamut<p>")); + + m_embeddProfileBox = new TQCheckBox(generalOptions); + m_embeddProfileBox->setChecked(true); + m_embeddProfileBox->setText(i18n("Assign profile")); + TQWhatsThis::add(m_embeddProfileBox, i18n("<p>You can use this option to embed " + "the selected workspace color profile into the image.</p>")); + + m_BPCBox = new TQCheckBox(generalOptions); + m_BPCBox->setText(i18n("Use BPC")); + TQWhatsThis::add(m_BPCBox, i18n("<p>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.</p>" + "<p>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.</p>")); + + 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("<ul><li>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.<br>" + "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.<br>" + "This intent is most suitable for display of photographs and images, and is the default " + "intent.</li>" + "<li> 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.<br>" + "This intent preserves the white point and is most suitable for spot colors (Pantone, " + "TruMatch, logo colors, ...).</li>" + "<li>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.</li>" + "<li>Saturation intent preserves the saturation of colors in the image at the possible " + "expense of hue and lightness.<br>" + "Implementation of this intent remains somewhat problematic, and the ICC is still working " + "on methods to achieve the desired effects.<br>" + "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.</li></ul>")); + + 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("<p>Set here all parameters relevant of Input Color " + "Profiles.</p>")); + + 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("<p>Set here all parameters relevant to Color Workspace " + "Profiles.</p>")); + + 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("<p>Set here all parameters relevant to Proofing Color " + "Profiles.</p>")); + + 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("<p>Set here all lightness adjustments to the target image.</p>")); + + 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("<p>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("<p>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.<p>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("<p>The selected ICC input profile path seems to be invalid.<p>" + "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("<p>The selected ICC proof profile path seems to be invalid.<p>" + "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("<p>Selected ICC workspace profile path seems to be invalid.<p>" + "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("<p>Your settings are not sufficient.</p>" + "<p>To apply a color transform, you need at least two ICC profiles:</p>" + "<ul><li>An \"Input\" profile.</li>" + "<li>A \"Workspace\" profile.</li></ul>" + "<p>If you want to do a \"soft-proof\" transform, in addition to these profiles " + "you need a \"Proof\" profile.</p>"); + 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("<p>Selected ICC input profile path seems " + "to be invalid.<p>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("<p>The selected ICC proof profile path seems " + "to be invalid.<p>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("<p>Selected ICC workspace profile path seems " + "to be invalid.<p>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("<p>You have selected the \"Default builtin sRGB profile\"</p>"); + message.append(i18n("<p>This profile is built on the fly, so there is no relevant information " + "about it.</p>")); + 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("<p>You have not enabled Color Management in the digiKam preferences.</p>"); + message.append(i18n("<p>\"Use of default profile\" options will be disabled now.</p>")); + 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 diff --git a/src/imageplugins/coreplugin/iccprooftool.h b/src/imageplugins/coreplugin/iccprooftool.h new file mode 100644 index 00000000..86d93ea9 --- /dev/null +++ b/src/imageplugins/coreplugin/iccprooftool.h @@ -0,0 +1,209 @@ +/* ============================================================ + * + * 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 <fj.cruz@supercable.es> + * 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. + * + * ============================================================ */ + +#ifndef ICCPROOFTOOL_H +#define ICCPROOFTOOL_H + +// Digikam includes. + +#include "editortool.h" + +class TQCheckBox; +class TQComboBox; +class TQVButtonGroup; +class TQButtonGroup; +class TQHButtonGroup; +class TQRadioButton; +class TQPushButton; +class TQToolBox; + +class KURLRequester; + +namespace KDcrawIface +{ +class RIntNumInput; +class RComboBox; +} + +namespace Digikam +{ +class ICCTransform; +class ImageWidget; +class HistogramWidget; +class ColorGradientWidget; +class DColor; +class ICCPreviewWidget; +class CurvesWidget; +} + +namespace DigikamImagesPluginCore +{ + +class ICCProofTool : public Digikam::EditorTool +{ + TQ_OBJECT + + +public: + + ICCProofTool(TQObject* parent); + ~ICCProofTool(); + +protected: + + void finalRendering(); + +private: + + void readSettings(); + void writeSettings(); + + void getICCInfo(const TQString&); + void getICCInfo(const TQByteArray&); + + bool useBPC(); + bool doProof(); + bool checkGamut(); + bool embedProfile(); + + bool useEmbeddedProfile(); + bool useBuiltinProfile(); + bool useDefaultInProfile(); + bool useSelectedInProfile(); + + bool useDefaultSpaceProfile(); + bool useSelectedSpaceProfile(); + + bool useDefaultProofProfile(); + bool useSelectedProofProfile(); + +private slots: + + void slotSaveAsSettings(); + void slotLoadSettings(); + void slotEffect(); + void slotResetSettings(); + void slotChannelChanged(int); + void slotScaleChanged(int); + void slotSpotColorChanged(const Digikam::DColor &); + void slotColorSelectedFromTarget(const Digikam::DColor &); + void slotToggledWidgets(bool); + void slotInICCInfo(); + void slotProofICCInfo(); + void slotSpaceICCInfo(); + void slotCMDisabledWarning(); + void processLCMSURL(const TQString&); + +private: + + enum HistogramScale + { + Linear = 0, + Logarithmic + }; + + enum ColorChannel + { + LuminosityChannel = 0, + RedChannel, + GreenChannel, + BlueChannel + }; + + enum ICCSettingsTab + { + GENERALPAGE=0, + INPUTPAGE, + WORKSPACEPAGE, + PROOFINGPAGE, + LIGHTNESSPAGE + }; + + bool m_cmEnabled; + bool m_hasICC; + + uchar *m_destinationPreviewData; + + TQComboBox *m_channelCB; + + TQCheckBox *m_doSoftProofBox; + TQCheckBox *m_checkGamutBox; + TQCheckBox *m_embeddProfileBox; + TQCheckBox *m_BPCBox; + + TQRadioButton *m_useEmbeddedProfile; + TQRadioButton *m_useInDefaultProfile; + TQRadioButton *m_useInSelectedProfile; + TQRadioButton *m_useProofDefaultProfile; + TQRadioButton *m_useProofSelectedProfile; + TQRadioButton *m_useSpaceDefaultProfile; + TQRadioButton *m_useSpaceSelectedProfile; + TQRadioButton *m_useSRGBDefaultProfile; + + TQString m_inPath; + TQString m_spacePath; + TQString m_proofPath; + + TQButtonGroup *m_optionsBG; + TQButtonGroup *m_inProfileBG; + TQButtonGroup *m_spaceProfileBG; + TQButtonGroup *m_proofProfileBG; + + TQHButtonGroup *m_scaleBG; + TQVButtonGroup *m_renderingIntentBG; + TQVButtonGroup *m_profilesBG; + + TQByteArray m_embeddedICC; + + TQToolBox *m_toolBoxWidgets; + + KURLRequester *m_inProfilesPath; + KURLRequester *m_spaceProfilePath; + KURLRequester *m_proofProfilePath; + + KDcrawIface::RIntNumInput *m_cInput; + + KDcrawIface::RComboBox *m_renderingIntentsCB; + + Digikam::DImg *m_originalImage; + + Digikam::CurvesWidget *m_curvesWidget; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::ColorGradientWidget *m_hGradient; + + Digikam::HistogramWidget *m_histogramWidget; + + Digikam::ICCPreviewWidget *m_iccInPreviewWidget; + Digikam::ICCPreviewWidget *m_iccSpacePreviewWidget; + Digikam::ICCPreviewWidget *m_iccProofPreviewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif // ICCPROOFTOOL_H diff --git a/src/imageplugins/coreplugin/imageeffect_autocorrection.cpp b/src/imageplugins/coreplugin/imageeffect_autocorrection.cpp new file mode 100644 index 00000000..290b93cb --- /dev/null +++ b/src/imageplugins/coreplugin/imageeffect_autocorrection.cpp @@ -0,0 +1,431 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-31 + * Description : Auto-Color correction tool. + * + * Copyright (C) 2005-2007 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. + * + * ============================================================ */ + + // TQt includes. + +#include <tqcolor.h> +#include <tqgroupbox.h> +#include <tqhgroupbox.h> +#include <tqvgroupbox.h> +#include <tqhbuttongroup.h> +#include <tqradiobutton.h> +#include <tqvgroupbox.h> +#include <tqhbuttongroup.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqframe.h> +#include <tqtimer.h> +#include <tqvbox.h> +#include <tqlabel.h> +#include <tqpushbutton.h> +#include <tqcheckbox.h> +#include <tqcombobox.h> +#include <tqlistbox.h> +#include <tqwhatsthis.h> +#include <tqtooltip.h> + +// KDE includes. + +#include <kcursor.h> +#include <kstandarddirs.h> +#include <tdeconfig.h> +#include <tdelocale.h> +#include <tdeapplication.h> + +// Digikam includes. + +#include "imageiface.h" +#include "imagewidget.h" +#include "histogramwidget.h" +#include "colorgradientwidget.h" +#include "dimgimagefilters.h" +#include "whitebalance.h" +#include "dimg.h" +#include "listboxpreviewitem.h" + +// Local includes. + +#include "imageeffect_autocorrection.h" +#include "imageeffect_autocorrection.moc" + +namespace DigikamImagesPluginCore +{ + +ImageEffect_AutoCorrection::ImageEffect_AutoCorrection(TQWidget* parent) + : Digikam::ImageDlgBase(parent, i18n("Auto Color Correction"), + "autocorrection", false), m_destinationPreviewData(0L) +{ + setHelp("autocolorcorrectiontool.anchor", "digikam"); + + // ------------------------------------------------------------- + + m_previewWidget = new Digikam::ImageWidget("autocorrection Tool Dialog", plainPage(), + i18n("<p>Here you can see the auto-color correction tool " + "preview. You can pick color on image " + "to see the color level corresponding on histogram.")); + setPreviewAreaWidget(m_previewWidget); + + // ------------------------------------------------------------- + + Digikam::ImageIface iface(0, 0); + m_thumbnailImage = iface.getOriginalImg()->smoothScale(128, 128, TQSize::ScaleMin); + + TQWidget *gboxSettings = new TQWidget(plainPage()); + TQGridLayout* gridSettings = new TQGridLayout( gboxSettings, 4, 4, spacingHint()); + + TQLabel *label1 = new TQLabel(i18n("Channel:"), gboxSettings); + label1->setAlignment ( TQt::AlignRight | TQt::AlignVCenter ); + m_channelCB = new TQComboBox( false, gboxSettings ); + 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("<p>Select the histogram channel to display here:<p>" + "<b>Luminosity</b>: display the image's luminosity values.<p>" + "<b>Red</b>: display the red image-channel values.<p>" + "<b>Green</b>: display the green image-channel values.<p>" + "<b>Blue</b>: display the blue image-channel values.<p>")); + + m_scaleBG = new TQHButtonGroup(gboxSettings); + m_scaleBG->setExclusive(true); + m_scaleBG->setFrameShape(TQFrame::NoFrame); + m_scaleBG->setInsideMargin( 0 ); + TQWhatsThis::add( m_scaleBG, i18n("<p>Select the histogram scale here.<p>" + "If the image's maximal counts are small, you can use the linear scale.<p>" + "Logarithmic scale can be used when the maximal counts 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( "<p>Linear" ) ); + m_scaleBG->insert(linHistoButton, Digikam::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( "<p>Logarithmic" ) ); + m_scaleBG->insert(logHistoButton, Digikam::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, 4); + + // ------------------------------------------------------------- + + TQVBox *histoBox = new TQVBox(gboxSettings); + m_histogramWidget = new Digikam::HistogramWidget(256, 140, histoBox, false, true, true); + TQWhatsThis::add( m_histogramWidget, i18n("<p>Here you can see the target preview image histogram drawing " + "of the selected image channel. This one is re-computed at any " + "settings changes.")); + TQLabel *space = new TQLabel(histoBox); + space->setFixedHeight(1); + m_hGradient = new Digikam::ColorGradientWidget( Digikam::ColorGradientWidget::Horizontal, 10, histoBox ); + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + + gridSettings->addMultiCellWidget(histoBox, 1, 2, 0, 4); + + // ------------------------------------------------------------- + + m_correctionTools = new TQListBox(gboxSettings); + m_correctionTools->setColumnMode(1); + m_correctionTools->setVariableWidth(false); + m_correctionTools->setVariableHeight(false); + Digikam::ListBoxWhatsThis* whatsThis = new Digikam::ListBoxWhatsThis(m_correctionTools); + + TQPixmap pix = getThumbnailForEffect(AutoLevelsCorrection); + Digikam::ListBoxPreviewItem *item = new Digikam::ListBoxPreviewItem(pix, i18n("Auto Levels")); + whatsThis->add( item, i18n("<b>Auto Levels</b>:" + "<p>This option maximizes the tonal range in the Red, " + "Green, and Blue channels. It searches the image shadow and highlight " + "limit values and adjusts the Red, Green, and Blue channels " + "to a full histogram range.</p>")); + m_correctionTools->insertItem(item, AutoLevelsCorrection); + + pix = getThumbnailForEffect(NormalizeCorrection); + item = new Digikam::ListBoxPreviewItem(pix, i18n("Normalize")); + whatsThis->add( item, i18n("<b>Normalize</b>:" + "<p>This option scales brightness values across the active " + "image so that the darkest point becomes black, and the " + "brightest point becomes as bright as possible without " + "altering its hue. This is often a \"magic fix\" for " + "images that are dim or washed out.</p>")); + m_correctionTools->insertItem(item, NormalizeCorrection); + + pix = getThumbnailForEffect(EqualizeCorrection); + item = new Digikam::ListBoxPreviewItem(pix, i18n("Equalize")); + whatsThis->add( item, i18n("<b>Equalize</b>:" + "<p>This option adjusts the brightness of colors across the " + "active image so that the histogram for the value channel " + "is as nearly as possible flat, that is, so that each possible " + "brightness value appears at about the same number of pixels " + "as each other value. Sometimes Equalize works wonderfully at " + "enhancing the contrasts in an image. Other times it gives " + "garbage. It is a very powerful operation, which can either work " + "miracles on an image or destroy it.</p>")); + m_correctionTools->insertItem(item, EqualizeCorrection); + + pix = getThumbnailForEffect(StretchContrastCorrection); + item = new Digikam::ListBoxPreviewItem(pix, i18n("Stretch Contrast")); + whatsThis->add( item, i18n("<b>Stretch Contrast</b>:" + "<p>This option enhances the contrast and brightness " + "of the RGB values of an image by stretching the lowest " + "and highest values to their fullest range, adjusting " + "everything in between.</p>")); + m_correctionTools->insertItem(item, StretchContrastCorrection); + + pix = getThumbnailForEffect(AutoExposureCorrection); + item = new Digikam::ListBoxPreviewItem(pix, i18n("Auto Exposure")); + whatsThis->add( item, i18n("<b>Auto Exposure</b>:" + "<p>This option enhances the contrast and brightness " + "of the RGB values of an image to calculate optimal " + "exposition and black level using image histogram " + "properties.</p>")); + m_correctionTools->insertItem(item, AutoExposureCorrection); + + // ------------------------------------------------------------- + + m_correctionTools->setFocus(); + gridSettings->addMultiCellWidget(m_correctionTools, 3, 3, 0, 4); + gridSettings->setRowStretch(3, 10); + setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + 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_previewWidget, TQ_SIGNAL(spotPositionChangedFromTarget( const Digikam::DColor &, const TQPoint & )), + this, TQ_SLOT(slotColorSelectedFromTarget( const Digikam::DColor & ))); + + connect(m_correctionTools, TQ_SIGNAL(highlighted(int)), + this, TQ_SLOT(slotEffect())); + + connect(m_previewWidget, TQ_SIGNAL(signalResized()), + this, TQ_SLOT(slotEffect())); +} + +ImageEffect_AutoCorrection::~ImageEffect_AutoCorrection() +{ + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + delete m_histogramWidget; + delete m_previewWidget; +} + +void ImageEffect_AutoCorrection::slotChannelChanged(int channel) +{ + switch(channel) + { + case LuminosityChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::ValueHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + break; + + case RedChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::RedChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "red" ) ); + break; + + case GreenChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::GreenChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "green" ) ); + break; + + case BlueChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::BlueChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "blue" ) ); + break; + } + + m_histogramWidget->repaint(false); +} + +void ImageEffect_AutoCorrection::slotScaleChanged(int scale) +{ + m_histogramWidget->m_scaleType = scale; + m_histogramWidget->repaint(false); +} + +void ImageEffect_AutoCorrection::slotColorSelectedFromTarget( const Digikam::DColor &color ) +{ + m_histogramWidget->setHistogramGuideByColor(color); +} + +void ImageEffect_AutoCorrection::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("autocorrection Tool Dialog"); + m_channelCB->setCurrentItem(config->readNumEntry("Histogram Channel", 0)); // Luminosity. + m_scaleBG->setButton(config->readNumEntry("Histogram Scale", Digikam::HistogramWidget::LogScaleHistogram)); + m_correctionTools->setCurrentItem(config->readNumEntry("Auto Correction Filter", AutoLevelsCorrection)); + slotChannelChanged(m_channelCB->currentItem()); + slotScaleChanged(m_scaleBG->selectedId()); +} + +void ImageEffect_AutoCorrection::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("autocorrection Tool Dialog"); + config->writeEntry("Histogram Channel", m_channelCB->currentItem()); + config->writeEntry("Histogram Scale", m_scaleBG->selectedId()); + config->writeEntry("Auto Correction Filter", m_correctionTools->currentItem()); + config->sync(); +} + +void ImageEffect_AutoCorrection::resetValues() +{ + m_correctionTools->blockSignals(true); + m_correctionTools->setCurrentItem(AutoLevelsCorrection); + m_correctionTools->blockSignals(false); +} + +void ImageEffect_AutoCorrection::slotEffect() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + Digikam::ImageIface* iface = m_previewWidget->imageIface(); + uchar *m_destinationPreviewData = iface->getPreviewImage(); + int w = iface->previewWidth(); + int h = iface->previewHeight(); + bool sb = iface->previewSixteenBit(); + + autoCorrection(m_destinationPreviewData, w, h, sb, m_correctionTools->currentItem()); + + iface->putPreviewImage(m_destinationPreviewData); + m_previewWidget->updatePreview(); + + // Update histogram. + + m_histogramWidget->updateData(m_destinationPreviewData, w, h, sb, 0, 0, 0, false); + + kapp->restoreOverrideCursor(); +} + +TQPixmap ImageEffect_AutoCorrection::getThumbnailForEffect(AutoCorrectionType type) +{ + Digikam::DImg thumb = m_thumbnailImage.copy(); + autoCorrection(thumb.bits(), thumb.width(), thumb.height(), thumb.sixteenBit(), type); + return (thumb.convertToPixmap()); +} + + +void ImageEffect_AutoCorrection::finalRendering() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + Digikam::ImageIface* iface = m_previewWidget->imageIface(); + uchar *data = iface->getOriginalImage(); + int w = iface->originalWidth(); + int h = iface->originalHeight(); + bool sb = iface->originalSixteenBit(); + + if (data) + { + int type = m_correctionTools->currentItem(); + autoCorrection(data, w, h, sb, type); + TQString name; + + switch (type) + { + case AutoLevelsCorrection: + name = i18n("Auto Levels"); + break; + + case NormalizeCorrection: + name = i18n("Normalize"); + break; + + case EqualizeCorrection: + name = i18n("Equalize"); + break; + + case StretchContrastCorrection: + name = i18n("Stretch Contrast"); + break; + + case AutoExposureCorrection: + name = i18n("Auto Exposure"); + break; + } + + iface->putOriginalImage(name, data); + delete [] data; + } + + kapp->restoreOverrideCursor(); + accept(); +} + +void ImageEffect_AutoCorrection::autoCorrection(uchar *data, int w, int h, bool sb, int type) +{ + Digikam::DImgImageFilters filter; + + switch (type) + { + case AutoLevelsCorrection: + filter.autoLevelsCorrectionImage(data, w, h, sb); + break; + + case NormalizeCorrection: + filter.normalizeImage(data, w, h, sb); + break; + + case EqualizeCorrection: + filter.equalizeImage(data, w, h, sb); + break; + + case StretchContrastCorrection: + filter.stretchContrastImage(data, w, h, sb); + break; + + case AutoExposureCorrection: + Digikam::WhiteBalance wbFilter(sb); + double blackLevel; + double exposureLevel; + wbFilter.autoExposureAdjustement(data, w, h, sb, blackLevel, exposureLevel); + wbFilter.whiteBalance(data, w, h, sb, blackLevel, exposureLevel); + break; + } +} + +} // NameSpace DigikamImagesPluginCore + diff --git a/src/imageplugins/coreplugin/imageeffect_autocorrection.h b/src/imageplugins/coreplugin/imageeffect_autocorrection.h new file mode 100644 index 00000000..c707ac1b --- /dev/null +++ b/src/imageplugins/coreplugin/imageeffect_autocorrection.h @@ -0,0 +1,128 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-31 + * Description : Auto-Color correction tool. + * + * Copyright (C) 2005-2007 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_AUTOCORRECTION_H +#define IMAGEEFFECT_AUTOCORRECTION_H + +// TQt Includes. + +#include <tqstring.h> + +// Digikam include. + +#include "imagedlgbase.h" + +class TQHButtonGroup; +class TQComboBox; +class TQListBox; +class TQButtonGroup; + +namespace Digikam +{ +class HistogramWidget; +class ColorGradientWidget; +class ImageWidget; +class DColor; +class DImg; +} + +namespace DigikamImagesPluginCore +{ + +class ImageEffect_AutoCorrection : public Digikam::ImageDlgBase +{ + TQ_OBJECT + + +public: + + ImageEffect_AutoCorrection(TQWidget *parent); + ~ImageEffect_AutoCorrection(); + +protected: + + void finalRendering(); + +private slots: + + void slotEffect(); + void slotChannelChanged(int channel); + void slotScaleChanged(int scale); + void slotColorSelectedFromTarget(const Digikam::DColor &color); + +private: + + enum AutoCorrectionType + { + AutoLevelsCorrection=0, + NormalizeCorrection, + EqualizeCorrection, + StretchContrastCorrection, + AutoExposureCorrection + }; + +private: + + void readUserSettings(); + void writeUserSettings(); + void resetValues(); + + void autoCorrection(uchar *data, int w, int h, bool sb, int type); + TQPixmap getThumbnailForEffect(AutoCorrectionType type); + +private: + + enum HistogramScale + { + Linear=0, + Logarithmic + }; + + enum ColorChannel + { + LuminosityChannel=0, + RedChannel, + GreenChannel, + BlueChannel + }; + + uchar *m_destinationPreviewData; + + TQComboBox *m_channelCB; + + TQHButtonGroup *m_scaleBG; + + TQListBox *m_correctionTools; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::ColorGradientWidget *m_hGradient; + + Digikam::HistogramWidget *m_histogramWidget; + + Digikam::DImg m_thumbnailImage; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* IMAGEEFFECT_AUTOCORRECTION_H */ diff --git a/src/imageplugins/coreplugin/imageeffect_bcg.cpp b/src/imageplugins/coreplugin/imageeffect_bcg.cpp new file mode 100644 index 00000000..9d21115d --- /dev/null +++ b/src/imageplugins/coreplugin/imageeffect_bcg.cpp @@ -0,0 +1,350 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-06-05 + * Description : digiKam image editor to adjust Brightness, + Contrast, and Gamma of picture. + * + * Copyright (C) 2004 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2005-2007 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqcolor.h> +#include <tqgroupbox.h> +#include <tqhgroupbox.h> +#include <tqvgroupbox.h> +#include <tqhbuttongroup.h> +#include <tqlabel.h> +#include <tqvbox.h> +#include <tqlayout.h> +#include <tqframe.h> +#include <tqlabel.h> +#include <tqpushbutton.h> +#include <tqcheckbox.h> +#include <tqcombobox.h> +#include <tqwhatsthis.h> +#include <tqtooltip.h> + +// KDE includes. + +#include <knuminput.h> +#include <tdelocale.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <kstandarddirs.h> + +// Digikam includes. + +#include "imageiface.h" +#include "imagewidget.h" +#include "histogramwidget.h" +#include "colorgradientwidget.h" +#include "bcgmodifier.h" +#include "dimg.h" + +// Local includes. + +#include "imageeffect_bcg.h" +#include "imageeffect_bcg.moc" + +namespace DigikamImagesPluginCore +{ + +ImageEffect_BCG::ImageEffect_BCG(TQWidget* parent) + : Digikam::ImageDlgBase(parent, i18n("Brightness Contrast Gamma Adjustments"), + "bcgadjust", false) +{ + m_destinationPreviewData = 0L; + setHelp("bcgadjusttool.anchor", "digikam"); + + m_previewWidget = new Digikam::ImageWidget("bcgadjust Tool Dialog", plainPage(), + i18n("<p>Here you can see the image " + "brightness-contrast-gamma adjustments preview. " + "You can pick color on image " + "to see the color level corresponding on histogram.")); + setPreviewAreaWidget(m_previewWidget); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(plainPage()); + TQGridLayout* gridSettings = new TQGridLayout( gboxSettings, 9, 4, spacingHint()); + + TQLabel *label1 = new TQLabel(i18n("Channel:"), gboxSettings); + label1->setAlignment ( TQt::AlignRight | TQt::AlignVCenter ); + m_channelCB = new TQComboBox( false, gboxSettings ); + 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("<p>Select the histogram channel to display here:<p>" + "<b>Luminosity</b>: display the image's luminosity values.<p>" + "<b>Red</b>: display the red image-channel values.<p>" + "<b>Green</b>: display the green image-channel values.<p>" + "<b>Blue</b>: display the blue image-channel values.<p>")); + + m_scaleBG = new TQHButtonGroup(gboxSettings); + m_scaleBG->setExclusive(true); + m_scaleBG->setFrameShape(TQFrame::NoFrame); + m_scaleBG->setInsideMargin( 0 ); + TQWhatsThis::add( m_scaleBG, i18n("<p>Select the histogram scale here.<p>" + "If the image's maximal counts are small, you can use the linear scale.<p>" + "Logarithmic scale can be used when the maximal counts 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( "<p>Linear" ) ); + m_scaleBG->insert(linHistoButton, Digikam::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( "<p>Logarithmic" ) ); + m_scaleBG->insert(logHistoButton, Digikam::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, 4); + + // ------------------------------------------------------------- + + TQVBox *histoBox = new TQVBox(gboxSettings); + m_histogramWidget = new Digikam::HistogramWidget(256, 140, histoBox, false, true, true); + TQWhatsThis::add( m_histogramWidget, i18n("<p>Here you can see the target preview image histogram drawing " + "of the selected image channel. This one is re-computed at any " + "settings changes.")); + TQLabel *space = new TQLabel(histoBox); + space->setFixedHeight(1); + m_hGradient = new Digikam::ColorGradientWidget( Digikam::ColorGradientWidget::Horizontal, 10, histoBox ); + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + + gridSettings->addMultiCellWidget(histoBox, 1, 2, 0, 4); + + // ------------------------------------------------------------- + + TQLabel *label2 = new TQLabel(i18n("Brightness:"), gboxSettings); + m_bInput = new KIntNumInput(gboxSettings); + m_bInput->setRange(-100, 100, 1, true); + m_bInput->setValue(0); + TQWhatsThis::add( m_bInput, i18n("<p>Set here the brightness adjustment of the image.")); + gridSettings->addMultiCellWidget(label2, 3, 3, 0, 4); + gridSettings->addMultiCellWidget(m_bInput, 4, 4, 0, 4); + + TQLabel *label3 = new TQLabel(i18n("Contrast:"), gboxSettings); + m_cInput = new KIntNumInput(gboxSettings); + m_cInput->setRange(-100, 100, 1, true); + m_cInput->setValue(0); + TQWhatsThis::add( m_cInput, i18n("<p>Set here the contrast adjustment of the image.")); + gridSettings->addMultiCellWidget(label3, 5, 5, 0, 4); + gridSettings->addMultiCellWidget(m_cInput, 6, 6, 0, 4); + + TQLabel *label4 = new TQLabel(i18n("Gamma:"), gboxSettings); + m_gInput = new KDoubleNumInput(gboxSettings); + m_gInput->setPrecision(2); + m_gInput->setRange(0.1, 3.0, 0.01, true); + m_gInput->setValue(1.0); + TQWhatsThis::add( m_gInput, i18n("<p>Set here the gamma adjustment of the image.")); + gridSettings->addMultiCellWidget(label4, 7, 7, 0, 4); + gridSettings->addMultiCellWidget(m_gInput, 8, 8, 0, 4); + + gridSettings->setRowStretch(9, 10); + setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + 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_previewWidget, TQ_SIGNAL(spotPositionChangedFromTarget( const Digikam::DColor &, const TQPoint & )), + this, TQ_SLOT(slotColorSelectedFromTarget( const Digikam::DColor & ))); + + connect(m_bInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_cInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_gInput, TQ_SIGNAL(valueChanged(double)), + this, TQ_SLOT(slotTimer())); + + connect(m_previewWidget, TQ_SIGNAL(signalResized()), + this, TQ_SLOT(slotEffect())); + + // ------------------------------------------------------------- + + enableButtonOK( false ); +} + +ImageEffect_BCG::~ImageEffect_BCG() +{ + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + delete m_histogramWidget; + delete m_previewWidget; +} + +void ImageEffect_BCG::slotChannelChanged(int channel) +{ + switch(channel) + { + case LuminosityChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::ValueHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + break; + + case RedChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::RedChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "red" ) ); + break; + + case GreenChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::GreenChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "green" ) ); + break; + + case BlueChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::BlueChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "blue" ) ); + break; + } + + m_histogramWidget->repaint(false); +} + +void ImageEffect_BCG::slotScaleChanged(int scale) +{ + m_histogramWidget->m_scaleType = scale; + m_histogramWidget->repaint(false); +} + +void ImageEffect_BCG::slotColorSelectedFromTarget( const Digikam::DColor &color ) +{ + m_histogramWidget->setHistogramGuideByColor(color); +} + +void ImageEffect_BCG::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("bcgadjust Tool Dialog"); + m_channelCB->setCurrentItem(config->readNumEntry("Histogram Channel", 0)); // Luminosity. + m_scaleBG->setButton(config->readNumEntry("Histogram Scale", Digikam::HistogramWidget::LogScaleHistogram)); + m_bInput->setValue(config->readNumEntry("BrightnessAjustment", 0)); + m_cInput->setValue(config->readNumEntry("ContrastAjustment", 0)); + m_gInput->setValue(config->readDoubleNumEntry("GammaAjustment", 1.0)); + slotChannelChanged(m_channelCB->currentItem()); + slotScaleChanged(m_scaleBG->selectedId()); +} + +void ImageEffect_BCG::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("bcgadjust Tool Dialog"); + config->writeEntry("Histogram Channel", m_channelCB->currentItem()); + config->writeEntry("Histogram Scale", m_scaleBG->selectedId()); + config->writeEntry("BrightnessAjustment", m_bInput->value()); + config->writeEntry("ContrastAjustment", m_cInput->value()); + config->writeEntry("GammaAjustment", m_gInput->value()); + config->sync(); +} + +void ImageEffect_BCG::resetValues() +{ + m_bInput->blockSignals(true); + m_cInput->blockSignals(true); + m_gInput->blockSignals(true); + m_bInput->setValue(0); + m_cInput->setValue(0); + m_gInput->setValue(1.0); + m_bInput->blockSignals(false); + m_cInput->blockSignals(false); + m_gInput->blockSignals(false); +} + +void ImageEffect_BCG::slotEffect() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + + double b = (double)m_bInput->value()/250.0; + double c = (double)(m_cInput->value()/100.0) + 1.00; + double g = m_gInput->value(); + + enableButtonOK( b != 0.0 || c != 1.0 || g != 1.0 ); + + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + Digikam::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(); + + Digikam::DImg preview(w, h, sb, a, m_destinationPreviewData); + Digikam::BCGModifier cmod; + cmod.setGamma(g); + cmod.setBrightness(b); + cmod.setContrast(c); + cmod.applyBCG(preview); + iface->putPreviewImage(preview.bits()); + + m_previewWidget->updatePreview(); + + // Update histogram. + + memcpy(m_destinationPreviewData, preview.bits(), preview.numBytes()); + m_histogramWidget->updateData(m_destinationPreviewData, w, h, sb, 0, 0, 0, false); + + kapp->restoreOverrideCursor(); +} + +void ImageEffect_BCG::finalRendering() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + Digikam::ImageIface* iface = m_previewWidget->imageIface(); + + double b = (double)m_bInput->value()/250.0; + double c = (double)(m_cInput->value()/100.0) + 1.00; + double g = m_gInput->value(); + + iface->setOriginalBCG(b, c, g); + kapp->restoreOverrideCursor(); + accept(); +} + +} // NameSpace DigikamImagesPluginCore + diff --git a/src/imageplugins/coreplugin/imageeffect_bcg.h b/src/imageplugins/coreplugin/imageeffect_bcg.h new file mode 100644 index 00000000..a9cd020b --- /dev/null +++ b/src/imageplugins/coreplugin/imageeffect_bcg.h @@ -0,0 +1,110 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-06-05 + * Description : digiKam image editor to adjust Brightness, + Contrast, and Gamma of picture. + * + * Copyright (C) 2004 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2005-2007 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_BCG_H +#define IMAGEEFFECT_BCG_H + +// Digikam include. + +#include "imagedlgbase.h" + +class TQCheckBox; +class TQComboBox; +class TQHButtonGroup; + +class KIntNumInput; +class KDoubleNumInput; + +namespace Digikam +{ +class HistogramWidget; +class ColorGradientWidget; +class ImageWidget; +class DColor; +} + +namespace DigikamImagesPluginCore +{ + +class ImageEffect_BCG : public Digikam::ImageDlgBase +{ + TQ_OBJECT + + +public: + + ImageEffect_BCG(TQWidget *parent); + ~ImageEffect_BCG(); + +private slots: + + void slotEffect(); + void slotChannelChanged(int channel); + void slotScaleChanged(int scale); + void slotColorSelectedFromTarget( const Digikam::DColor &color ); + +private: + + void readUserSettings(); + void writeUserSettings(); + void resetValues(); + void finalRendering(); + +private: + + enum HistogramScale + { + Linear=0, + Logarithmic + }; + + enum ColorChannel + { + LuminosityChannel=0, + RedChannel, + GreenChannel, + BlueChannel + }; + + uchar *m_destinationPreviewData; + + TQComboBox *m_channelCB; + + TQHButtonGroup *m_scaleBG; + + KIntNumInput *m_bInput; + KIntNumInput *m_cInput; + KDoubleNumInput *m_gInput; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::ColorGradientWidget *m_hGradient; + + Digikam::HistogramWidget *m_histogramWidget; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* IMAGEEFFECT_BCG_H */ diff --git a/src/imageplugins/coreplugin/imageeffect_blur.cpp b/src/imageplugins/coreplugin/imageeffect_blur.cpp new file mode 100644 index 00000000..bd23854b --- /dev/null +++ b/src/imageplugins/coreplugin/imageeffect_blur.cpp @@ -0,0 +1,147 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-09 + * Description : a tool to blur an image + * + * Copyright (C) 2004-2007 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqlayout.h> +#include <tqlabel.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeaboutdata.h> +#include <knuminput.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <tdelocale.h> +#include <tdeapplication.h> + +// Digikam includes. + +#include "ddebug.h" +#include "imageiface.h" +#include "dimggaussianblur.h" + +// Local includes. + +#include "imageeffect_blur.h" +#include "imageeffect_blur.moc" + +namespace DigikamImagesPluginCore +{ + +ImageEffect_Blur::ImageEffect_Blur(TQWidget* parent) + : Digikam::CtrlPanelDlg(parent, i18n("Apply Gaussian Blur on Photograph"), + "gaussianblur", false, true, true) +{ + setHelp("blursharpentool.anchor", "digikam"); + + TQWidget *gboxSettings = new TQWidget(m_imagePreviewWidget); + TQGridLayout* gridSettings = new TQGridLayout( gboxSettings, 1, 1, 0, spacingHint()); + TQLabel *label = new TQLabel(i18n("Smoothness:"), gboxSettings); + + m_radiusInput = new KIntNumInput(gboxSettings); + m_radiusInput->setRange(0, 100, 1, true); + m_radiusInput->setValue(0); + TQWhatsThis::add( m_radiusInput, i18n("<p>A smoothness of 0 has no effect, " + "1 and above determine the Gaussian blur matrix radius " + "that determines how much to blur the image.")); + + gridSettings->addMultiCellWidget(label, 0, 0, 0, 1); + gridSettings->addMultiCellWidget(m_radiusInput, 1, 1, 0, 1); + + m_imagePreviewWidget->setUserAreaWidget(gboxSettings); +} + +ImageEffect_Blur::~ImageEffect_Blur() +{ +} + +void ImageEffect_Blur::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("gaussianblur Tool Dialog"); + m_radiusInput->setValue(config->readNumEntry("RadiusAjustment", 0)); +} + +void ImageEffect_Blur::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("gaussianblur Tool Dialog"); + config->writeEntry("RadiusAjustment", m_radiusInput->value()); + config->sync(); +} + +void ImageEffect_Blur::resetValues(void) +{ + m_radiusInput->blockSignals(true); + m_radiusInput->setValue(0); + m_radiusInput->blockSignals(false); +} + +void ImageEffect_Blur::prepareEffect() +{ + m_radiusInput->setEnabled(false); + + Digikam::DImg img = m_imagePreviewWidget->getOriginalRegionImage(); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *> + (new Digikam::DImgGaussianBlur(&img, this, m_radiusInput->value())); +} + +void ImageEffect_Blur::prepareFinal() +{ + m_radiusInput->setEnabled(false); + + Digikam::ImageIface iface(0, 0); + uchar *data = iface.getOriginalImage(); + int w = iface.originalWidth(); + int h = iface.originalHeight(); + bool sixteenBit = iface.originalSixteenBit(); + bool hasAlpha = iface.originalHasAlpha(); + Digikam::DImg orgImage = Digikam::DImg(w, h, sixteenBit, hasAlpha ,data); + delete [] data; + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *> + (new Digikam::DImgGaussianBlur(&orgImage, this, m_radiusInput->value())); +} + +void ImageEffect_Blur::putPreviewData(void) +{ + Digikam::DImg imDest = m_threadedFilter->getTargetImage(); + m_imagePreviewWidget->setPreviewImage(imDest); +} + +void ImageEffect_Blur::putFinalData(void) +{ + Digikam::ImageIface iface(0, 0); + Digikam::DImg imDest = m_threadedFilter->getTargetImage(); + iface.putOriginalImage(i18n("Gaussian Blur"), imDest.bits()); +} + +void ImageEffect_Blur::renderingFinished(void) +{ + m_radiusInput->setEnabled(true); +} + +} // NameSpace DigikamImagesPluginCore + diff --git a/src/imageplugins/coreplugin/imageeffect_blur.h b/src/imageplugins/coreplugin/imageeffect_blur.h new file mode 100644 index 00000000..eab7694e --- /dev/null +++ b/src/imageplugins/coreplugin/imageeffect_blur.h @@ -0,0 +1,68 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-09 + * Description : a tool to blur an image + * + * Copyright (C) 2004-2007 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_BLUR_H +#define IMAGEEFFECT_BLUR_H + +// Digikam include. + +#include "ctrlpaneldlg.h" + +class KIntNumInput; + +namespace DigikamImagesPluginCore +{ + +class ImageEffect_Blur : public Digikam::CtrlPanelDlg +{ + TQ_OBJECT + + +public: + + ImageEffect_Blur(TQWidget *parent); + ~ImageEffect_Blur(); + +private slots: + + void readUserSettings(); + +private: + + void writeUserSettings(); + void resetValues(); + void prepareEffect(); + void prepareFinal(); + void abortPreview(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + KIntNumInput *m_radiusInput; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* IMAGEEFFECT_BLUR_H */ diff --git a/src/imageplugins/coreplugin/imageeffect_bwsepia.cpp b/src/imageplugins/coreplugin/imageeffect_bwsepia.cpp new file mode 100644 index 00000000..7dcdf0da --- /dev/null +++ b/src/imageplugins/coreplugin/imageeffect_bwsepia.cpp @@ -0,0 +1,1183 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-06 + * Description : Black and White conversion tool. + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2006-2007 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. + * + * ============================================================ */ + + // TQt includes. + +#include <tqcolor.h> +#include <tqgroupbox.h> +#include <tqhgroupbox.h> +#include <tqvgroupbox.h> +#include <tqhbuttongroup.h> +#include <tqlistbox.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqframe.h> +#include <tqlabel.h> +#include <tqpushbutton.h> +#include <tqtimer.h> +#include <tqcombobox.h> +#include <tqwhatsthis.h> +#include <tqtooltip.h> +#include <tqintdict.h> +#include <tqtextstream.h> +#include <tqfile.h> +#include <tqvbox.h> + +// KDE includes. + +#include <tdefiledialog.h> +#include <tdeglobalsettings.h> +#include <tdemessagebox.h> +#include <kcursor.h> +#include <tdelocale.h> +#include <kstandarddirs.h> +#include <tdeapplication.h> +#include <knuminput.h> +#include <ktabwidget.h> +#include <tdeconfig.h> + +// Digikam includes. + +#include "imageiface.h" +#include "imagehistogram.h" +#include "dimgimagefilters.h" +#include "imagewidget.h" +#include "imagecurves.h" +#include "histogramwidget.h" +#include "curveswidget.h" +#include "colorgradientwidget.h" +#include "dimg.h" +#include "bcgmodifier.h" +#include "listboxpreviewitem.h" + +// Local includes. + +#include "imageeffect_bwsepia.h" +#include "imageeffect_bwsepia.moc" + +namespace DigikamImagesPluginCore +{ + +class PreviewPixmapFactory : public TQObject +{ +public: + + PreviewPixmapFactory(ImageEffect_BWSepia* bwSepia); + + void invalidate() { m_previewPixmapMap.clear(); } + + const TQPixmap* pixmap(int id); + +private: + + TQPixmap makePixmap(int id); + + TQIntDict<TQPixmap> m_previewPixmapMap; + ImageEffect_BWSepia *m_bwSepia; +}; + +PreviewPixmapFactory::PreviewPixmapFactory(ImageEffect_BWSepia* bwSepia) + : TQObject(bwSepia), m_bwSepia(bwSepia) +{ + m_previewPixmapMap.setAutoDelete(true); +} + +const TQPixmap* PreviewPixmapFactory::pixmap(int id) +{ + if (m_previewPixmapMap.find(id) == 0) + { + TQPixmap pix = makePixmap(id); + m_previewPixmapMap.insert(id, new TQPixmap(pix)); + } + + TQPixmap* res = m_previewPixmapMap[id]; + + return res; +} + +TQPixmap PreviewPixmapFactory::makePixmap(int id) +{ + return m_bwSepia->getThumbnailForEffect(id); +} + +// ----------------------------------------------------------------------------------- + +class ListBoxBWPreviewItem : public Digikam::ListBoxPreviewItem +{ + +public: + + ListBoxBWPreviewItem(TQListBox *listbox, const TQString &text, + PreviewPixmapFactory* factory, int id) + : ListBoxPreviewItem(listbox, TQPixmap(), text) + { + m_previewPixmapFactory = factory; + m_id = id; + }; + + virtual const TQPixmap* pixmap() const; + +private: + + int m_id; + PreviewPixmapFactory* m_previewPixmapFactory; +}; + +const TQPixmap* ListBoxBWPreviewItem::pixmap() const +{ + return m_previewPixmapFactory->pixmap(m_id); +} + +// ----------------------------------------------------------------------------------- + +ImageEffect_BWSepia::ImageEffect_BWSepia(TQWidget* parent) + : Digikam::ImageDlgBase(parent, i18n("Convert to Black & White"), + "convertbw", true, false), + m_destinationPreviewData(0L), + m_channelCB(0), + m_scaleBG(0), + m_bwFilters(0), + m_bwTone(0), + m_cInput(0), + m_tab(0), + m_previewWidget(0), + m_histogramWidget(0), + m_curvesWidget(0), + m_curves(0), + m_originalImage(0), + m_previewPixmapFactory(0) +{ + setHelp("blackandwhitetool.anchor", "digikam"); + + Digikam::ImageIface iface(0, 0); + m_originalImage = iface.getOriginalImg(); + m_thumbnailImage = m_originalImage->smoothScale(128, 128, TQSize::ScaleMin); + m_curves = new Digikam::ImageCurves(m_originalImage->sixteenBit()); + + // ------------------------------------------------------------- + + m_previewWidget = new Digikam::ImageWidget("convertbw Tool Dialog", plainPage(), + i18n("<p>Here you can see the black and white conversion tool preview. " + "You can pick color on image " + "to see the color level corresponding on histogram.")); + setPreviewAreaWidget(m_previewWidget); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(plainPage()); + TQGridLayout* gridSettings = new TQGridLayout( gboxSettings, 4, 4, spacingHint()); + + TQLabel *label1 = new TQLabel(i18n("Channel:"), gboxSettings); + label1->setAlignment ( TQt::AlignRight | TQt::AlignVCenter ); + m_channelCB = new TQComboBox( false, gboxSettings ); + 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("<p>Select the histogram channel to display here:<p>" + "<b>Luminosity</b>: display the image's luminosity values.<p>" + "<b>Red</b>: display the red image-channel values.<p>" + "<b>Green</b>: display the green image-channel values.<p>" + "<b>Blue</b>: display the blue image-channel values.<p>")); + + m_scaleBG = new TQHButtonGroup(gboxSettings); + m_scaleBG->setExclusive(true); + m_scaleBG->setFrameShape(TQFrame::NoFrame); + m_scaleBG->setInsideMargin( 0 ); + TQWhatsThis::add( m_scaleBG, i18n("<p>Select the histogram scale here.<p>" + "If the image's maximal counts are small, you can use the linear scale.<p>" + "Logarithmic scale can be used when the maximal counts 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( "<p>Linear" ) ); + m_scaleBG->insert(linHistoButton, Digikam::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( "<p>Logarithmic" ) ); + m_scaleBG->insert(logHistoButton, Digikam::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, 4); + + // ------------------------------------------------------------- + + TQVBox *histoBox = new TQVBox(gboxSettings); + m_histogramWidget = new Digikam::HistogramWidget(256, 140, histoBox, false, true, true); + TQWhatsThis::add( m_histogramWidget, i18n("<p>Here you can see the target preview image histogram drawing " + "of the selected image channel. This one is re-computed at any " + "settings changes.")); + TQLabel *space = new TQLabel(histoBox); + space->setFixedHeight(1); + m_hGradient = new Digikam::ColorGradientWidget( Digikam::ColorGradientWidget::Horizontal, 10, histoBox ); + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + + gridSettings->addMultiCellWidget(histoBox, 1, 2, 0, 4); + + // ------------------------------------------------------------- + + m_tab = new KTabWidget(gboxSettings); + + m_bwFilm = new TQListBox(m_tab); + m_bwFilm->setColumnMode(1); + m_bwFilm->setVariableWidth(false); + m_bwFilm->setVariableHeight(false); + Digikam::ListBoxWhatsThis* whatsThis2 = new Digikam::ListBoxWhatsThis(m_bwFilm); + m_previewPixmapFactory = new PreviewPixmapFactory(this); + + int type = BWGeneric; + + ListBoxBWPreviewItem *item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Generic"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Generic</b>:" + "<p>Simulate a generic black and white film</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Agfa 200X"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Agfa 200X</b>:" + "<p>Simulate the Agfa 200X black and white film at 200 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Agfa Pan 25"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Agfa Pan 25</b>:" + "<p>Simulate the Agfa Pan black and white film at 25 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Agfa Pan 100"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Agfa Pan 100</b>:" + "<p>Simulate the Agfa Pan black and white film at 100 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Agfa Pan 400"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Agfa Pan 400</b>:" + "<p>Simulate the Agfa Pan black and white film at 400 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Ilford Delta 100"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Ilford Delta 100</b>:" + "<p>Simulate the Ilford Delta black and white film at 100 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Ilford Delta 400"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Ilford Delta 400</b>:" + "<p>Simulate the Ilford Delta black and white film at 400 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Ilford Delta 400 Pro 3200"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Ilford Delta 400 Pro 3200</b>:" + "<p>Simulate the Ilford Delta 400 Pro black and white film at 3200 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Ilford FP4 Plus"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Ilford FP4 Plus</b>:" + "<p>Simulate the Ilford FP4 Plus black and white film at 125 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Ilford HP5 Plus"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Ilford HP5 Plus</b>:" + "<p>Simulate the Ilford HP5 Plus black and white film at 400 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Ilford PanF Plus"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Ilford PanF Plus</b>:" + "<p>Simulate the Ilford PanF Plus black and white film at 50 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Ilford XP2 Super"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Ilford XP2 Super</b>:" + "<p>Simulate the Ilford XP2 Super black and white film at 400 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Kodak Tmax 100"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Kodak Tmax 100</b>:" + "<p>Simulate the Kodak Tmax black and white film at 100 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Kodak Tmax 400"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Kodak Tmax 400</b>:" + "<p>Simulate the Kodak Tmax black and white film at 400 ISO</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilm, i18n("Kodak TriX"), m_previewPixmapFactory, type); + whatsThis2->add( item, i18n("<b>Kodak TriX</b>:" + "<p>Simulate the Kodak TriX black and white film at 400 ISO</p>")); + + // ------------------------------------------------------------- + + TQVBox *vbox = new TQVBox(m_tab); + vbox->setSpacing(spacingHint()); + + m_bwFilters = new TQListBox(vbox); + m_bwFilters->setColumnMode(1); + m_bwFilters->setVariableWidth(false); + m_bwFilters->setVariableHeight(false); + Digikam::ListBoxWhatsThis* whatsThis = new Digikam::ListBoxWhatsThis(m_bwFilters); + + type = BWNoFilter; + + item = new ListBoxBWPreviewItem(m_bwFilters, + i18n("No Lens Filter"), m_previewPixmapFactory, type); + whatsThis->add( item, i18n("<b>No Lens Filter</b>:" + "<p>Do not apply a lens filter when rendering the image.</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilters, i18n("Green Filter"), m_previewPixmapFactory, type); + whatsThis->add( item, i18n("<b>Black & White with Green Filter</b>:" + "<p>Simulate black and white film exposure using a green filter. " + "This is usefule for all scenic shoots, especially portraits " + "photographed against the sky.</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilters, i18n("Orange Filter"), m_previewPixmapFactory, type); + whatsThis->add( item, i18n("<b>Black & White with Orange Filter</b>:" + "<p>Simulate black and white film exposure using an orange filter. " + "This will enhance landscapes, marine scenes and aerial " + "photography.</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilters, i18n("Red Filter"), m_previewPixmapFactory, type); + whatsThis->add( item, i18n("<b>Black & White with Red Filter</b>:" + "<p>Simulate black and white film exposure using a red filter. " + "This creates dramatic sky effects, and simulates moonlight scenes " + "in the daytime.</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwFilters, i18n("Yellow Filter"), m_previewPixmapFactory, type); + whatsThis->add( item, i18n("<b>Black & White with Yellow Filter</b>:" + "<p>Simulate black and white film exposure using a yellow filter. " + "This has the most natural tonal correction, and improves contrast. Ideal for " + "landscapes.</p>")); + + m_strengthInput = new KIntNumInput(vbox); + m_strengthInput->setLabel(i18n("Strength:"), AlignLeft | AlignVCenter); + m_strengthInput->setRange(1, 5, 1, true); + m_strengthInput->setValue(1); + TQWhatsThis::add(m_strengthInput, i18n("<p>Here, set the strength adjustment of the lens filter.")); + + // ------------------------------------------------------------- + + m_bwTone = new TQListBox(m_tab); + m_bwTone->setColumnMode(1); + m_bwTone->setVariableWidth(false); + m_bwTone->setVariableHeight(false); + Digikam::ListBoxWhatsThis* whatsThis3 = new Digikam::ListBoxWhatsThis(m_bwTone); + + type = BWNoTone; + + item = new ListBoxBWPreviewItem(m_bwTone, i18n("No Tone Filter"), m_previewPixmapFactory, type); + whatsThis3->add( item, i18n("<b>No Tone Filter</b>:" + "<p>Do not apply a tone filter to the image.</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwTone, i18n("Sepia Tone"), m_previewPixmapFactory, type); + whatsThis3->add( item, i18n("<b>Black & White with Sepia Tone</b>:" + "<p>Gives a warm highlight and mid-tone while adding a bit of coolness to " + "the shadows - very similar to the process of bleaching a print and " + "re-developing in a sepia toner.</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwTone, i18n("Brown Tone"), m_previewPixmapFactory, type); + whatsThis3->add( item, i18n("<b>Black & White with Brown Tone</b>:" + "<p>This filter is more neutral than the Sepia Tone " + "filter.</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwTone, i18n("Cold Tone"), m_previewPixmapFactory, type); + whatsThis3->add( item, i18n("<b>Black & White with Cold Tone</b>:" + "<p>Start subtle and replicates printing on a cold tone black and white " + "paper such as a bromide enlarging " + "paper.</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwTone, i18n("Selenium Tone"), m_previewPixmapFactory, type); + whatsThis3->add( item, i18n("<b>Black & White with Selenium Tone</b>:" + "<p>This effect replicates traditional selenium chemical toning done " + "in the darkroom.</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwTone, i18n("Platinum Tone"), m_previewPixmapFactory, type); + whatsThis3->add( item, i18n("<b>Black & White with Platinum Tone</b>:" + "<p>This effect replicates traditional platinum chemical toning done " + "in the darkroom.</p>")); + + ++type; + item = new ListBoxBWPreviewItem(m_bwTone, i18n("Green Tone"), m_previewPixmapFactory, type); + whatsThis3->add( item, i18n("<b>Black & White with greenish tint</b>:" + "<p>This effect is also known as Verdante.</p>")); + + // ------------------------------------------------------------- + + TQWidget *curveBox = new TQWidget( m_tab ); + TQGridLayout *gridTab2 = new TQGridLayout(curveBox, 5, 2, spacingHint(), 0); + + Digikam::ColorGradientWidget* vGradient = new Digikam::ColorGradientWidget( + Digikam::ColorGradientWidget::Vertical, + 10, curveBox ); + vGradient->setColors( TQColor( "white" ), TQColor( "black" ) ); + + TQLabel *spacev = new TQLabel(curveBox); + spacev->setFixedWidth(1); + + m_curvesWidget = new Digikam::CurvesWidget(256, 256, m_originalImage->bits(), m_originalImage->width(), + m_originalImage->height(), m_originalImage->sixteenBit(), + m_curves, curveBox); + TQWhatsThis::add( m_curvesWidget, i18n("<p>This is the curve adjustment of the image luminosity")); + + TQLabel *spaceh = new TQLabel(curveBox); + spaceh->setFixedHeight(1); + + Digikam::ColorGradientWidget *hGradient = new Digikam::ColorGradientWidget( + Digikam::ColorGradientWidget::Horizontal, + 10, curveBox ); + hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + + m_cInput = new KIntNumInput(curveBox); + m_cInput->setLabel(i18n("Contrast:"), AlignLeft | AlignVCenter); + m_cInput->setRange(-100, 100, 1, true); + m_cInput->setValue(0); + TQWhatsThis::add( m_cInput, i18n("<p>Set here the contrast adjustment of the image.")); + + gridTab2->addMultiCellWidget(vGradient, 0, 0, 0, 0); + gridTab2->addMultiCellWidget(spacev, 0, 0, 1, 1); + gridTab2->addMultiCellWidget(m_curvesWidget, 0, 0, 2, 2); + gridTab2->addMultiCellWidget(spaceh, 1, 1, 2, 2); + gridTab2->addMultiCellWidget(hGradient, 2, 2, 2, 2); + gridTab2->addMultiCellWidget(m_cInput, 4, 4, 0, 2); + gridTab2->setRowSpacing(3, spacingHint()); + gridTab2->setRowStretch(5, 10); + + // ------------------------------------------------------------- + + m_tab->insertTab(m_bwFilm, i18n("Film"), FilmTab); + m_tab->insertTab(vbox, i18n("Lens Filters"), BWFiltersTab); + m_tab->insertTab(m_bwTone, i18n("Tone"), ToneTab); + m_tab->insertTab(curveBox, i18n("Lightness"), LuminosityTab); + + gridSettings->addMultiCellWidget(m_tab, 3, 3, 0, 4); + gridSettings->setRowStretch(3, 10); + setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + 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_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 & ))); + + connect(m_bwFilters, TQ_SIGNAL(highlighted(int)), + this, TQ_SLOT(slotFilterSelected(int))); + + connect(m_strengthInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_bwFilm, TQ_SIGNAL(highlighted(int)), + this, TQ_SLOT(slotEffect())); + + connect(m_bwTone, TQ_SIGNAL(highlighted(int)), + this, TQ_SLOT(slotEffect())); + + connect(m_curvesWidget, TQ_SIGNAL(signalCurvesChanged()), + this, TQ_SLOT(slotTimer())); + + connect(m_cInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_previewWidget, TQ_SIGNAL(signalResized()), + this, TQ_SLOT(slotEffect())); +} + +ImageEffect_BWSepia::~ImageEffect_BWSepia() +{ + m_histogramWidget->stopHistogramComputation(); + + delete [] m_destinationPreviewData; + + delete m_histogramWidget; + delete m_previewWidget; + delete m_curvesWidget; + delete m_curves; +} + +void ImageEffect_BWSepia::slotFilterSelected(int filter) +{ + if (filter == BWNoFilter) + m_strengthInput->setEnabled(false); + else + m_strengthInput->setEnabled(true); + + slotEffect(); +} + +TQPixmap ImageEffect_BWSepia::getThumbnailForEffect(int type) +{ + Digikam::DImg thumb = m_thumbnailImage.copy(); + int w = thumb.width(); + int h = thumb.height(); + bool sb = thumb.sixteenBit(); + bool a = thumb.hasAlpha(); + + if (type < BWGeneric) + { + // In Filter view, we will render a preview of the B&W filter with the generic B&W film. + blackAndWhiteConversion(thumb.bits(), w, h, sb, type); + blackAndWhiteConversion(thumb.bits(), w, h, sb, BWGeneric); + } + else + { + // In Film and Tone view, we will render the preview without to use the B&W Filter + blackAndWhiteConversion(thumb.bits(), w, h, sb, type); + } + + if (m_curves) // in case we're called before the creator is done + { + uchar *targetData = new uchar[w*h*(sb ? 8 : 4)]; + m_curves->curvesLutSetup(Digikam::ImageHistogram::AlphaChannel); + m_curves->curvesLutProcess(thumb.bits(), targetData, w, h); + + Digikam::DImg preview(w, h, sb, a, targetData); + Digikam::BCGModifier cmod; + cmod.setContrast((double)(m_cInput->value()/100.0) + 1.00); + cmod.applyBCG(preview); + + thumb.putImageData(preview.bits()); + + delete [] targetData; + } + return (thumb.convertToPixmap()); +} + +void ImageEffect_BWSepia::slotChannelChanged(int channel) +{ + switch(channel) + { + case LuminosityChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::ValueHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + break; + + case RedChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::RedChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "red" ) ); + break; + + case GreenChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::GreenChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "green" ) ); + break; + + case BlueChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::BlueChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "blue" ) ); + break; + } + + m_histogramWidget->repaint(false); +} + +void ImageEffect_BWSepia::slotScaleChanged(int scale) +{ + m_histogramWidget->m_scaleType = scale; + m_histogramWidget->repaint(false); + m_curvesWidget->m_scaleType = scale; + m_curvesWidget->repaint(false); +} + +void ImageEffect_BWSepia::slotSpotColorChanged(const Digikam::DColor &color) +{ + m_curvesWidget->setCurveGuide(color); +} + +void ImageEffect_BWSepia::slotColorSelectedFromTarget( const Digikam::DColor &color ) +{ + m_histogramWidget->setHistogramGuideByColor(color); +} + +void ImageEffect_BWSepia::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("convertbw Tool Dialog"); + + m_tab->setCurrentPage(config->readNumEntry("Settings Tab", BWFiltersTab)); + m_channelCB->setCurrentItem(config->readNumEntry("Histogram Channel", 0)); // Luminosity. + m_scaleBG->setButton(config->readNumEntry("Histogram Scale", Digikam::HistogramWidget::LogScaleHistogram)); + m_bwFilters->setCurrentItem(config->readNumEntry("BW Filter", 0)); + m_bwFilm->setCurrentItem(config->readNumEntry("BW Film", 0)); + m_bwTone->setCurrentItem(config->readNumEntry("BW Tone", 0)); + m_cInput->setValue(config->readNumEntry("ContrastAjustment", 0)); + m_strengthInput->setValue(config->readNumEntry("StrengthAjustment", 1)); + + for (int i = 0 ; i < 5 ; i++) + m_curves->curvesChannelReset(i); + + m_curves->setCurveType(m_curvesWidget->m_channelType, Digikam::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_curves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, j, p); + } + + for (int i = 0 ; i < 5 ; i++) + m_curves->curvesCalculateCurve(i); + + slotChannelChanged(m_channelCB->currentItem()); + slotScaleChanged(m_scaleBG->selectedId()); + slotFilterSelected(m_bwFilters->currentItem()); +} + +void ImageEffect_BWSepia::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("convertbw Tool Dialog"); + config->writeEntry("Settings Tab", m_tab->currentPageIndex()); + config->writeEntry("Histogram Channel", m_channelCB->currentItem()); + config->writeEntry("Histogram Scale", m_scaleBG->selectedId()); + config->writeEntry("BW Filter", m_bwFilters->currentItem()); + config->writeEntry("BW Film", m_bwFilm->currentItem()); + config->writeEntry("BW Tone", m_bwTone->currentItem()); + config->writeEntry("ContrastAjustment", m_cInput->value()); + config->writeEntry("StrengthAjustment", m_strengthInput->value()); + + for (int j = 0 ; j < 17 ; j++) + { + TQPoint p = m_curves->getCurvePoint(Digikam::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); + } + + config->sync(); +} + +void ImageEffect_BWSepia::resetValues() +{ + m_bwFilters->blockSignals(true); + m_bwTone->blockSignals(true); + m_cInput->blockSignals(true); + m_strengthInput->blockSignals(true); + + m_bwFilters->setCurrentItem(0); + m_bwFilters->setSelected(0, true); + + m_bwTone->setCurrentItem(0); + m_bwTone->setSelected(0, true); + + m_cInput->setValue(0); + + for (int channel = 0 ; channel < 5 ; channel++) + m_curves->curvesChannelReset(channel); + + m_curvesWidget->reset(); + + m_cInput->blockSignals(false); + m_bwTone->blockSignals(false); + m_bwFilters->blockSignals(false); + m_strengthInput->blockSignals(false); + + m_histogramWidget->reset(); + m_previewPixmapFactory->invalidate(); + m_bwFilters->triggerUpdate(false); + m_bwTone->triggerUpdate(false); +} + +void ImageEffect_BWSepia::slotEffect() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + + m_histogramWidget->stopHistogramComputation(); + + delete [] m_destinationPreviewData; + + Digikam::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(); + + // Apply black and white filter. + + blackAndWhiteConversion(m_destinationPreviewData, w, h, sb, m_bwFilters->currentItem()); + + // Apply black and white film type. + + blackAndWhiteConversion(m_destinationPreviewData, w, h, sb, m_bwFilm->currentItem() + BWGeneric); + + // Apply color tone filter. + + blackAndWhiteConversion(m_destinationPreviewData, w, h, sb, m_bwTone->currentItem() + BWNoTone); + + // Calculate and apply the curve on image. + + uchar *targetData = new uchar[w*h*(sb ? 8 : 4)]; + m_curves->curvesLutSetup(Digikam::ImageHistogram::AlphaChannel); + m_curves->curvesLutProcess(m_destinationPreviewData, targetData, w, h); + + // Adjust contrast. + + Digikam::DImg preview(w, h, sb, a, targetData); + Digikam::BCGModifier cmod; + cmod.setContrast((double)(m_cInput->value()/100.0) + 1.00); + cmod.applyBCG(preview); + iface->putPreviewImage(preview.bits()); + + m_previewWidget->updatePreview(); + + // Update histogram. + + memcpy(m_destinationPreviewData, preview.bits(), preview.numBytes()); + m_histogramWidget->updateData(m_destinationPreviewData, w, h, sb, 0, 0, 0, false); + delete [] targetData; + + kapp->restoreOverrideCursor(); +} + +void ImageEffect_BWSepia::slotTimer() +{ + Digikam::ImageDlgBase::slotTimer(); + if (m_previewPixmapFactory && m_bwFilters && m_bwTone) + { + m_previewPixmapFactory->invalidate(); + m_bwFilters->triggerUpdate(false); + m_bwTone->triggerUpdate(false); + } +} + +void ImageEffect_BWSepia::finalRendering() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + Digikam::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) + { + // Apply black and white filter. + + blackAndWhiteConversion(data, w, h, sb, m_bwFilters->currentItem()); + + // Apply black and white film type. + + blackAndWhiteConversion(data, w, h, sb, m_bwFilm->currentItem() + BWGeneric); + + // Apply color tone filter. + + blackAndWhiteConversion(data, w, h, sb, m_bwTone->currentItem() + BWNoTone); + + // Calculate and apply the curve on image. + + uchar *targetData = new uchar[w*h*(sb ? 8 : 4)]; + m_curves->curvesLutSetup(Digikam::ImageHistogram::AlphaChannel); + m_curves->curvesLutProcess(data, targetData, w, h); + + // Adjust contrast. + + Digikam::DImg img(w, h, sb, a, targetData); + Digikam::BCGModifier cmod; + cmod.setContrast((double)(m_cInput->value()/100.0) + 1.00); + cmod.applyBCG(img); + + iface->putOriginalImage(i18n("Convert to Black && White"), img.bits()); + + delete [] data; + delete [] targetData; + } + + kapp->restoreOverrideCursor(); + accept(); +} + +void ImageEffect_BWSepia::blackAndWhiteConversion(uchar *data, int w, int h, bool sb, int type) +{ + // Value to multiply RGB 8 bits component of mask used by changeTonality() method. + int mul = sb ? 255 : 1; + Digikam::DImgImageFilters filter; + double strength = 1.0 + ((double)m_strengthInput->value() - 1.0) * (1.0 / 3.0); + + switch (type) + { + case BWNoFilter: + m_redAttn = 0.0; + m_greenAttn = 0.0; + m_blueAttn = 0.0; + break; + + case BWGreenFilter: + m_redAttn = -0.20 * strength; + m_greenAttn = +0.11 * strength; + m_blueAttn = +0.09 * strength; + break; + + case BWOrangeFilter: + m_redAttn = +0.48 * strength; + m_greenAttn = -0.37 * strength; + m_blueAttn = -0.11 * strength; + break; + + case BWRedFilter: + m_redAttn = +0.60 * strength; + m_greenAttn = -0.49 * strength; + m_blueAttn = -0.11 * strength; + break; + + case BWYellowFilter: + m_redAttn = +0.30 * strength; + m_greenAttn = -0.31 * strength; + m_blueAttn = +0.01 * strength; + break; + + // -------------------------------------------------------------------------------- + + case BWGeneric: + case BWNoTone: + m_redMult = 0.24; + m_greenMult = 0.68; + m_blueMult = 0.08; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWAgfa200X: + m_redMult = 0.18; + m_greenMult = 0.41; + m_blueMult = 0.41; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWAgfapan25: + m_redMult = 0.25; + m_greenMult = 0.39; + m_blueMult = 0.36; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWAgfapan100: + m_redMult = 0.21; + m_greenMult = 0.40; + m_blueMult = 0.39; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWAgfapan400: + m_redMult = 0.20; + m_greenMult = 0.41; + m_blueMult = 0.39; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWIlfordDelta100: + m_redMult = 0.21; + m_greenMult = 0.42; + m_blueMult = 0.37; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWIlfordDelta400: + m_redMult = 0.22; + m_greenMult = 0.42; + m_blueMult = 0.36; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWIlfordDelta400Pro3200: + m_redMult = 0.31; + m_greenMult = 0.36; + m_blueMult = 0.33; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWIlfordFP4: + m_redMult = 0.28; + m_greenMult = 0.41; + m_blueMult = 0.31; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWIlfordHP5: + m_redMult = 0.23; + m_greenMult = 0.37; + m_blueMult = 0.40; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWIlfordPanF: + m_redMult = 0.33; + m_greenMult = 0.36; + m_blueMult = 0.31; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWIlfordXP2Super: + m_redMult = 0.21; + m_greenMult = 0.42; + m_blueMult = 0.37; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWKodakTmax100: + m_redMult = 0.24; + m_greenMult = 0.37; + m_blueMult = 0.39; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWKodakTmax400: + m_redMult = 0.27; + m_greenMult = 0.36; + m_blueMult = 0.37; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + case BWKodakTriX: + m_redMult = 0.25; + m_greenMult = 0.35; + m_blueMult = 0.40; + filter.channelMixerImage(data, w, h, sb, true, true, + m_redMult + m_redMult*m_redAttn, m_greenMult + m_greenMult*m_greenAttn, m_blueMult + m_blueMult*m_blueAttn, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + break; + + // -------------------------------------------------------------------------------- + + case BWSepiaTone: + filter.changeTonality(data, w, h, sb, 162*mul, 132*mul, 101*mul); + break; + + case BWBrownTone: + filter.changeTonality(data, w, h, sb, 129*mul, 115*mul, 104*mul); + break; + + case BWColdTone: + filter.changeTonality(data, w, h, sb, 102*mul, 109*mul, 128*mul); + break; + + case BWSeleniumTone: + filter.changeTonality(data, w, h, sb, 122*mul, 115*mul, 122*mul); + break; + + case BWPlatinumTone: + filter.changeTonality(data, w, h, sb, 115*mul, 110*mul, 106*mul); + break; + + case BWGreenTone: + filter.changeTonality(data, w, h, sb, 108*mul, 116*mul, 100*mul); + break; + + } +} + +//-- Load all settings from file -------------------------------------- + +void ImageEffect_BWSepia::slotUser3() +{ + KURL loadFile = KFileDialog::getOpenURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), this, + TQString( i18n("Black & White Settings File to Load")) ); + if( loadFile.isEmpty() ) + return; + + TQFile file(loadFile.path()); + + if ( file.open(IO_ReadOnly) ) + { + TQTextStream stream( &file ); + + if ( stream.readLine() != "# Black & White Configuration File" ) + { + KMessageBox::error(this, + i18n("\"%1\" is not a Black & White settings text file.") + .arg(loadFile.fileName())); + file.close(); + return; + } + + m_bwFilters->blockSignals(true); + m_bwTone->blockSignals(true); + m_cInput->blockSignals(true); + + m_bwFilters->setCurrentItem(stream.readLine().toInt()); + m_bwTone->setCurrentItem(stream.readLine().toInt()); + m_cInput->setValue(stream.readLine().toInt()); + + for (int i = 0 ; i < 5 ; i++) + m_curves->curvesChannelReset(i); + + m_curves->setCurveType(m_curvesWidget->m_channelType, Digikam::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_curves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, j, p); + } + + for (int i = 0 ; i < 5 ; i++) + m_curves->curvesCalculateCurve(i); + + m_bwFilters->blockSignals(false); + m_bwTone->blockSignals(false); + m_cInput->blockSignals(false); + + m_histogramWidget->reset(); + m_previewPixmapFactory->invalidate(); + m_bwFilters->triggerUpdate(false); + m_bwTone->triggerUpdate(false); + + slotEffect(); + } + else + KMessageBox::error(this, i18n("Cannot load settings from the Black & White text file.")); + + file.close(); +} + +//-- Save all settings to file --------------------------------------- + +void ImageEffect_BWSepia::slotUser2() +{ + KURL saveFile = KFileDialog::getSaveURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), this, + TQString( i18n("Black & White Settings File to Save")) ); + if( saveFile.isEmpty() ) + return; + + TQFile file(saveFile.path()); + + if ( file.open(IO_WriteOnly) ) + { + TQTextStream stream( &file ); + stream << "# Black & White Configuration File\n"; + stream << m_bwFilters->currentItem() << "\n"; + stream << m_bwTone->currentItem() << "\n"; + stream << m_cInput->value() << "\n"; + + for (int j = 0 ; j < 17 ; j++) + { + TQPoint p = m_curves->getCurvePoint(Digikam::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(this, i18n("Cannot save settings to the Black & White text file.")); + + file.close(); +} + +} // NameSpace DigikamImagesPluginCore + + diff --git a/src/imageplugins/coreplugin/imageeffect_bwsepia.h b/src/imageplugins/coreplugin/imageeffect_bwsepia.h new file mode 100644 index 00000000..74b4edf3 --- /dev/null +++ b/src/imageplugins/coreplugin/imageeffect_bwsepia.h @@ -0,0 +1,195 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-06 + * Description : Black and White conversion tool. + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2006-2007 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. + * + * ============================================================ */ + + +#ifndef IMAGEEFFECT_BWSEPIA_H +#define IMAGEEFFECT_BWSEPIA_H + +// TQt Includes. + +#include <tqstring.h> + +// Digikam include. + +#include "imagedlgbase.h" + +class TQHButtonGroup; +class TQComboBox; +class TQButtonGroup; + +class KIntNumInput; +class KTabWidget; + +namespace Digikam +{ +class HistogramWidget; +class ColorGradientWidget; +class ImageWidget; +class DColor; +class DImg; +class ImageCurves; +class CurvesWidget; +} + +namespace DigikamImagesPluginCore +{ + +class PreviewPixmapFactory; + +class ImageEffect_BWSepia : public Digikam::ImageDlgBase +{ + TQ_OBJECT + + +public: + + ImageEffect_BWSepia(TQWidget *parent); + ~ImageEffect_BWSepia(); + + friend class PreviewPixmapFactory; + +protected: + + TQPixmap getThumbnailForEffect(int type); + void finalRendering(); + +protected slots: + + virtual void slotTimer(); + +private: + + void readUserSettings(); + void writeUserSettings(); + void resetValues(); + void blackAndWhiteConversion(uchar *data, int w, int h, bool sb, int type); + +private slots: + + void slotUser2(); + void slotUser3(); + void slotEffect(); + void slotChannelChanged(int channel); + void slotScaleChanged(int scale); + void slotSpotColorChanged(const Digikam::DColor &color); + void slotColorSelectedFromTarget( const Digikam::DColor &color ); + void slotFilterSelected(int filter); + +private: + + enum BlackWhiteConversionType + { + BWNoFilter=0, // B&W filter to the front of lens. + BWGreenFilter, + BWOrangeFilter, + BWRedFilter, + BWYellowFilter, + + BWGeneric, // B&W film simulation. + BWAgfa200X, + BWAgfapan25, + BWAgfapan100, + BWAgfapan400, + BWIlfordDelta100, + BWIlfordDelta400, + BWIlfordDelta400Pro3200, + BWIlfordFP4, + BWIlfordHP5, + BWIlfordPanF, + BWIlfordXP2Super, + BWKodakTmax100, + BWKodakTmax400, + BWKodakTriX, + + BWNoTone, // Chemical color tone filter. + BWSepiaTone, + BWBrownTone, + BWColdTone, + BWSeleniumTone, + BWPlatinumTone, + BWGreenTone + }; + + enum HistogramScale + { + Linear=0, + Logarithmic + }; + + enum ColorChannel + { + LuminosityChannel=0, + RedChannel, + GreenChannel, + BlueChannel + }; + + enum SettingsTab + { + FilmTab=0, + BWFiltersTab, + ToneTab, + LuminosityTab + }; + + // Color filter attenuation in percents. + double m_redAttn, m_greenAttn, m_blueAttn; + + // Channel mixer color multiplier. + double m_redMult, m_greenMult, m_blueMult; + + uchar *m_destinationPreviewData; + + TQComboBox *m_channelCB; + + TQHButtonGroup *m_scaleBG; + + TQListBox *m_bwFilters; + TQListBox *m_bwFilm; + TQListBox *m_bwTone; + + KIntNumInput *m_cInput; + KIntNumInput *m_strengthInput; + + KTabWidget *m_tab; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::ColorGradientWidget *m_hGradient; + + Digikam::HistogramWidget *m_histogramWidget; + + Digikam::CurvesWidget *m_curvesWidget; + + Digikam::ImageCurves *m_curves; + + Digikam::DImg *m_originalImage; + Digikam::DImg m_thumbnailImage; + + PreviewPixmapFactory *m_previewPixmapFactory; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* IMAGEEFFECT_BWSEPIA_H */ diff --git a/src/imageplugins/coreplugin/imageeffect_iccproof.cpp b/src/imageplugins/coreplugin/imageeffect_iccproof.cpp new file mode 100644 index 00000000..79a09983 --- /dev/null +++ b/src/imageplugins/coreplugin/imageeffect_iccproof.cpp @@ -0,0 +1,1284 @@ +/* ============================================================ + * + * 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 <fj.cruz@supercable.es> + * 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqcolor.h> +#include <tqgroupbox.h> +#include <tqhbox.h> +#include <tqhbuttongroup.h> +#include <tqvbuttongroup.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqframe.h> +#include <tqpoint.h> +#include <tqvbox.h> +#include <tqlabel.h> +#include <tqpushbutton.h> +#include <tqcheckbox.h> +#include <tqcombobox.h> +#include <tqwhatsthis.h> +#include <tqtooltip.h> +#include <tqradiobutton.h> +#include <tqfile.h> +#include <tqtoolbox.h> +#include <tqtextstream.h> + +// KDE includes. + +#include <knuminput.h> +#include <tdelocale.h> +#include <tdeapplication.h> +#include <kcursor.h> +#include <kstandarddirs.h> +#include <ktabwidget.h> +#include <tdeconfig.h> +#include <kurlrequester.h> +#include <kurllabel.h> +#include <tdefiledialog.h> +#include <tdefile.h> +#include <tdemessagebox.h> +#include <tdeglobalsettings.h> +#include <kiconloader.h> +#include <ksqueezedtextlabel.h> + +// Digikam includes. + +#include "ddebug.h" +#include "bcgmodifier.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "imagehistogram.h" +#include "imagecurves.h" +#include "curveswidget.h" +#include "histogramwidget.h" +#include "colorgradientwidget.h" +#include "dimg.h" +#include "dimgimagefilters.h" +#include "iccpreviewwidget.h" +#include "icctransform.h" +#include "iccprofileinfodlg.h" + +// Local includes. + +#include "imageeffect_iccproof.h" +#include "imageeffect_iccproof.moc" + +namespace DigikamImagesPluginCore +{ + +ImageEffect_ICCProof::ImageEffect_ICCProof(TQWidget* parent) + : Digikam::ImageDlgBase(parent,i18n("Color Management"), + "colormanagement", true, false) +{ + m_destinationPreviewData = 0; + m_cmEnabled = true; + m_hasICC = false; + + setHelp("colormanagement.anchor", "digikam"); + + Digikam::ImageIface iface(0, 0); + m_originalImage = iface.getOriginalImg(); + m_embeddedICC = iface.getEmbeddedICCFromOriginalImage(); + m_curves = new Digikam::ImageCurves(m_originalImage->sixteenBit()); + + m_previewWidget = new Digikam::ImageWidget("colormanagement Tool Dialog", plainPage(), + i18n("<p>Here you can see the image preview after " + "applying a color profile</p>")); + setPreviewAreaWidget(m_previewWidget); + + // ------------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(plainPage()); + TQGridLayout *gridSettings = new TQGridLayout( gboxSettings, 3, 2, spacingHint()); + + TQLabel *label1 = new TQLabel(i18n("Channel: "), gboxSettings); + label1->setAlignment(TQt::AlignRight | TQt::AlignVCenter); + m_channelCB = new TQComboBox(false, gboxSettings); + 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("<p>Select the histogram channel to display here:<p>" + "<b>Luminosity</b>: display the image's luminosity values.<p>" + "<b>Red</b>: display the red channel values.<p>" + "<b>Green</b>: display the green channel values.<p>" + "<b>Blue</b>: display the blue channel values.<p>")); + + m_scaleBG = new TQHButtonGroup(gboxSettings); + m_scaleBG->setExclusive(true); + m_scaleBG->setFrameShape(TQFrame::NoFrame); + m_scaleBG->setInsideMargin( 0 ); + TQWhatsThis::add( m_scaleBG, i18n("<p>Select the histogram scale here.<p>" + "If the image's maximal values are small, you can use the linear scale.<p>" + "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( "<p>Linear" ) ); + m_scaleBG->insert(linHistoButton, Digikam::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( "<p>Logarithmic" ) ); + m_scaleBG->insert(logHistoButton, Digikam::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(gboxSettings); + m_histogramWidget = new Digikam::HistogramWidget(256, 140, histoBox, false, true, true); + TQWhatsThis::add( m_histogramWidget, i18n("<p>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 Digikam::ColorGradientWidget( Digikam::ColorGradientWidget::Horizontal, 10, + histoBox ); + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + + gridSettings->addMultiCellWidget(histoBox, 1, 2, 0, 2); + + // ------------------------------------------------------------- + + m_toolBoxWidgets = new TQToolBox(gboxSettings); + 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("<p>Here you can set general parameters.</p>")); + + TQGridLayout *zeroPageLayout = new TQGridLayout(generalOptions, 5, 1, spacingHint()); + + m_doSoftProofBox = new TQCheckBox(generalOptions); + m_doSoftProofBox->setText(i18n("Soft-proofing")); + TQWhatsThis::add(m_doSoftProofBox, i18n("<p>Rendering emulation of the device described " + "by the \"Proofing\" profile. Useful to preview the final " + "result without rendering to physical medium.</p>")); + + m_checkGamutBox = new TQCheckBox(generalOptions); + m_checkGamutBox->setText(i18n("Check gamut")); + TQWhatsThis::add(m_checkGamutBox, i18n("<p>You can use this option if you want to show " + "the colors that are outside the printer's gamut<p>")); + + m_embeddProfileBox = new TQCheckBox(generalOptions); + m_embeddProfileBox->setChecked(true); + m_embeddProfileBox->setText(i18n("Assign profile")); + TQWhatsThis::add(m_embeddProfileBox, i18n("<p>You can use this option to embed " + "the selected workspace color profile into the image.</p>")); + + m_BPCBox = new TQCheckBox(generalOptions); + m_BPCBox->setText(i18n("Use BPC")); + TQWhatsThis::add(m_BPCBox, i18n("<p>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.</p>" + "<p>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.</p>")); + + TQLabel *intent = new TQLabel(i18n("Rendering Intent:"), generalOptions); + m_renderingIntentsCB = new TQComboBox(false, generalOptions); + m_renderingIntentsCB->insertItem("Perceptual"); + m_renderingIntentsCB->insertItem("Absolute Colorimetric"); + m_renderingIntentsCB->insertItem("Relative Colorimetric"); + m_renderingIntentsCB->insertItem("Saturation"); + TQWhatsThis::add( m_renderingIntentsCB, i18n("<ul><li>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.<br>" + "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.<br>" + "This intent is most suitable for display of photographs and images, and is the default " + "intent.</li>" + "<li> 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.<br>" + "This intent preserves the white point and is most suitable for spot colors (Pantone, " + "TruMatch, logo colors, ...).</li>" + "<li>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.</li>" + "<li>Saturation intent preserves the saturation of colors in the image at the possible " + "expense of hue and lightness.<br>" + "Implementation of this intent remains somewhat problematic, and the ICC is still working " + "on methods to achieve the desired effects.<br>" + "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.</li></ul>")); + + 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("<p>Set here all parameters relevant of Input Color " + "Profiles.</p>")); + + TQGridLayout *firstPageLayout = new TQGridLayout(inProfiles, 4, 2, spacingHint()); + + 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 Digikam::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("<p>Set here all parameters relevant to Color Workspace " + "Profiles.</p>")); + + TQGridLayout *secondPageLayout = new TQGridLayout(spaceProfiles, 3, 2, spacingHint()); + + 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 Digikam::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("<p>Set here all parameters relevant to Proofing Color " + "Profiles.</p>")); + + TQGridLayout *thirdPageLayout = new TQGridLayout(proofProfiles, 3, 2, + spacingHint(), spacingHint()); + + 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 Digikam::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("<p>Set here all lightness adjustments to the target image.</p>")); + + TQGridLayout *fourPageLayout = new TQGridLayout( lightnessadjust, 5, 2, spacingHint(), 0); + + Digikam::ColorGradientWidget* vGradient = new Digikam::ColorGradientWidget( + Digikam::ColorGradientWidget::Vertical, + 10, lightnessadjust ); + vGradient->setColors( TQColor( "white" ), TQColor( "black" ) ); + + TQLabel *spacev = new TQLabel(lightnessadjust); + spacev->setFixedWidth(1); + + m_curvesWidget = new Digikam::CurvesWidget(256, 192, m_originalImage->bits(), m_originalImage->width(), + m_originalImage->height(), m_originalImage->sixteenBit(), + m_curves, lightnessadjust); + TQWhatsThis::add( m_curvesWidget, i18n("<p>This is the curve adjustment of the image luminosity")); + + TQLabel *spaceh = new TQLabel(lightnessadjust); + spaceh->setFixedHeight(1); + + Digikam::ColorGradientWidget *hGradient = new Digikam::ColorGradientWidget( + Digikam::ColorGradientWidget::Horizontal, + 10, lightnessadjust ); + hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + + m_cInput = new KIntNumInput(lightnessadjust); + m_cInput->setLabel(i18n("Contrast:"), AlignLeft | AlignVCenter); + m_cInput->setRange(-100, 100, 1, true); + m_cInput->setValue(0); + TQWhatsThis::add( m_cInput, i18n("<p>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, spacingHint()); + fourPageLayout->setRowStretch(5, 10); + + // ------------------------------------------------------------- + + gridSettings->addMultiCellWidget(m_toolBoxWidgets, 3, 3, 0, 2); + setUserAreaWidget(gboxSettings); + enableButtonOK(false); + + // ------------------------------------------------------------- + + 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())); +} + +ImageEffect_ICCProof::~ImageEffect_ICCProof() +{ + m_histogramWidget->stopHistogramComputation(); + + delete [] m_destinationPreviewData; + delete m_histogramWidget; + delete m_previewWidget; + delete m_curvesWidget; + delete m_curves; +} + +void ImageEffect_ICCProof::readUserSettings() +{ + 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.<p>Please fix this in the digiKam ICC setup."); + slotToggledWidgets( false ); + KMessageBox::information(this, message); + } + } + + // Plugin settings. + config->setGroup("colormanagement Tool Dialog"); + m_channelCB->setCurrentItem(config->readNumEntry("Histogram Channel", 0)); // Luminosity. + m_scaleBG->setButton(config->readNumEntry("Histogram Scale", Digikam::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", 0)); + 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", 0)); + + for (int i = 0 ; i < 5 ; i++) + m_curves->curvesChannelReset(i); + + m_curves->setCurveType(m_curvesWidget->m_channelType, Digikam::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_curves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, j, p); + } + + for (int i = 0 ; i < 5 ; i++) + m_curves->curvesCalculateCurve(i); + + slotChannelChanged(m_channelCB->currentItem()); + slotScaleChanged(m_scaleBG->selectedId()); +} + +void ImageEffect_ICCProof::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("colormanagement Tool Dialog"); + 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_curves->getCurvePoint(Digikam::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); + } + + config->sync(); +} + +void ImageEffect_ICCProof::processLCMSURL(const TQString& url) +{ + TDEApplication::kApplication()->invokeBrowser(url); +} + +void ImageEffect_ICCProof::slotSpotColorChanged(const Digikam::DColor &color) +{ + m_curvesWidget->setCurveGuide(color); +} + +void ImageEffect_ICCProof::slotColorSelectedFromTarget( const Digikam::DColor &color ) +{ + m_histogramWidget->setHistogramGuideByColor(color); +} + +void ImageEffect_ICCProof::slotChannelChanged( int channel ) +{ + switch(channel) + { + case LuminosityChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::ValueHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + break; + + case RedChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::RedChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "red" ) ); + break; + + case GreenChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::GreenChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "green" ) ); + break; + + case BlueChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::BlueChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "blue" ) ); + break; + } + + m_histogramWidget->repaint(false); +} + +void ImageEffect_ICCProof::slotScaleChanged( int scale ) +{ + m_histogramWidget->m_scaleType = scale; + m_histogramWidget->repaint(false); +} + +void ImageEffect_ICCProof::resetValues() +{ + m_cInput->blockSignals(true); + m_cInput->setValue(0); + + for (int i = 0 ; i < 5 ; i++) + m_curves->curvesChannelReset(i); + + m_curvesWidget->reset(); + m_cInput->blockSignals(false); +} + +void ImageEffect_ICCProof::slotEffect() +{ + kapp->setOverrideCursor(KCursor::waitCursor()); + enableButtonOK(true); + m_histogramWidget->stopHistogramComputation(); + + Digikam::IccTransform transform; + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + Digikam::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(); + + Digikam::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(this, i18n("<p>The selected ICC input profile path seems to be invalid.<p>" + "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(this, i18n("<p>The selected ICC proof profile path seems to be invalid.<p>" + "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(this, i18n("<p>Selected ICC workspace profile path seems to be invalid.<p>" + "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("<p>Your settings are not sufficient.</p>" + "<p>To apply a color transform, you need at least two ICC profiles:</p>" + "<ul><li>An \"Input\" profile.</li>" + "<li>A \"Workspace\" profile.</li></ul>" + "<p>If you want to do a \"soft-proof\" transform, in addition to these profiles " + "you need a \"Proof\" profile.</p>"); + KMessageBox::information(this, error); + enableButtonOK(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 ------------- + + Digikam::DImg preview2(w, h, sb, a, 0, false); + m_curves->curvesLutSetup(Digikam::ImageHistogram::AlphaChannel); + m_curves->curvesLutProcess(preview.bits(), preview2.bits(), w, h); + + //-- Adjust contrast --------------------------------------------------------- + + Digikam::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 ImageEffect_ICCProof::finalRendering() +{ + if (!m_doSoftProofBox->isChecked()) + { + kapp->setOverrideCursor( KCursor::waitCursor() ); + + Digikam::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) + { + Digikam::IccTransform transform; + + Digikam::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(this, i18n("<p>Selected ICC input profile path seems " + "to be invalid.<p>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(this, i18n("<p>The selected ICC proof profile path seems " + "to be invalid.<p>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(this, i18n("<p>Selected ICC workspace profile path seems " + "to be invalid.<p>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 ------------- + + Digikam::DImg img2(w, h, sb, a, 0, false); + m_curves->curvesLutSetup(Digikam::ImageHistogram::AlphaChannel); + m_curves->curvesLutProcess(img.bits(), img2.bits(), w, h); + + //-- Adjust contrast --------------------------------------------------------- + + Digikam::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(); + } + + accept(); +} + +void ImageEffect_ICCProof::slotToggledWidgets( bool t) +{ + m_useInDefaultProfile->setEnabled(t); + m_useProofDefaultProfile->setEnabled(t); + m_useSpaceDefaultProfile->setEnabled(t); +} + +void ImageEffect_ICCProof::slotInICCInfo() +{ + if (useEmbeddedProfile()) + { + getICCInfo(m_embeddedICC); + } + else if(useBuiltinProfile()) + { + TQString message = i18n("<p>You have selected the \"Default builtin sRGB profile\"</p>"); + message.append(i18n("<p>This profile is built on the fly, so there is no relevant information " + "about it.</p>")); + KMessageBox::information(this, message); + } + else if (useDefaultInProfile()) + { + getICCInfo(m_inPath); + } + else if (useSelectedInProfile()) + { + getICCInfo(m_inProfilesPath->url()); + } +} + +void ImageEffect_ICCProof::slotProofICCInfo() +{ + if (useDefaultProofProfile()) + { + getICCInfo(m_proofPath); + } + else + { + getICCInfo(m_proofProfilePath->url()); + } +} + +void ImageEffect_ICCProof::slotSpaceICCInfo() +{ + if (useDefaultSpaceProfile()) + { + getICCInfo(m_spacePath); + } + else + { + getICCInfo(m_spaceProfilePath->url()); + } +} + +void ImageEffect_ICCProof::getICCInfo(const TQString& profile) +{ + if (profile.isEmpty()) + { + KMessageBox::error(this, i18n("Sorry, there is no selected profile"), i18n("Profile Error")); + return; + } + + Digikam::ICCProfileInfoDlg infoDlg(this, profile); + infoDlg.exec(); +} + +void ImageEffect_ICCProof::getICCInfo(const TQByteArray& profile) +{ + if (profile.isNull()) + { + KMessageBox::error(this, i18n("Sorry, it seems there is no embedded profile"), i18n("Profile Error")); + return; + } + + Digikam::ICCProfileInfoDlg infoDlg(this, TQString(), profile); + infoDlg.exec(); +} + +void ImageEffect_ICCProof::slotCMDisabledWarning() +{ + if (!m_cmEnabled) + { + TQString message = i18n("<p>You have not enabled Color Management in the digiKam preferences.</p>"); + message.append( i18n("<p>\"Use of default profile\" options will be disabled now.</p>")); + KMessageBox::information(this, message); + slotToggledWidgets(false); + } +} + +//-- General Tab --------------------------- + +bool ImageEffect_ICCProof::useBPC() +{ + return m_BPCBox->isChecked(); +} + +bool ImageEffect_ICCProof::doProof() +{ + return m_doSoftProofBox->isChecked(); +} + +bool ImageEffect_ICCProof::checkGamut() +{ + return m_checkGamutBox->isChecked(); +} + +bool ImageEffect_ICCProof::embedProfile() +{ + return m_embeddProfileBox->isChecked(); +} + +//-- Input Tab --------------------------- + +bool ImageEffect_ICCProof::useEmbeddedProfile() +{ + return m_useEmbeddedProfile->isChecked(); +} + +bool ImageEffect_ICCProof::useBuiltinProfile() +{ + return m_useSRGBDefaultProfile->isChecked(); +} + +bool ImageEffect_ICCProof::useDefaultInProfile() +{ + return m_useInDefaultProfile->isChecked(); +} + +bool ImageEffect_ICCProof::useSelectedInProfile() +{ + return m_useInSelectedProfile->isChecked(); +} + +//-- Workspace Tab --------------------------- + +bool ImageEffect_ICCProof::useDefaultSpaceProfile() +{ + return m_useSpaceDefaultProfile->isChecked(); +} + +//-- Proofing Tab --------------------------- + +bool ImageEffect_ICCProof::useDefaultProofProfile() +{ + return m_useProofDefaultProfile->isChecked(); +} + +//-- Load all settings from file -------------------------------------- + +void ImageEffect_ICCProof::slotUser3() +{ + KURL loadColorManagementFile = KFileDialog::getOpenURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), this, + 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(this, + 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_curves->curvesChannelReset(i); + + m_curves->setCurveType(m_curvesWidget->m_channelType, Digikam::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_curves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, j, p); + } + + blockSignals(false); + + for (int i = 0 ; i < 5 ; i++) + m_curves->curvesCalculateCurve(i); + + m_histogramWidget->reset(); + slotEffect(); + } + else + KMessageBox::error(this, i18n("Cannot load settings from the Color Management text file.")); + + file.close(); +} + +//-- Save all settings to file --------------------------------------- + +void ImageEffect_ICCProof::slotUser2() +{ + KURL saveColorManagementFile = KFileDialog::getSaveURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), this, + 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_curves->getCurvePoint(Digikam::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(this, i18n("Cannot save settings to the Color Management text file.")); + + file.close(); +} + +} // NameSpace DigikamImagesPluginCore diff --git a/src/imageplugins/coreplugin/imageeffect_iccproof.h b/src/imageplugins/coreplugin/imageeffect_iccproof.h new file mode 100644 index 00000000..58112aef --- /dev/null +++ b/src/imageplugins/coreplugin/imageeffect_iccproof.h @@ -0,0 +1,204 @@ +/* ============================================================ + * + * 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 <fj.cruz@supercable.es> + * 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_ICCPROOF_H +#define IMAGEEFFECT_ICCPROOF_H + +// Digikam include. + +#include "imagedlgbase.h" + +class TQCheckBox; +class TQComboBox; +class TQVButtonGroup; +class TQButtonGroup; +class TQHButtonGroup; +class TQRadioButton; +class TQPushButton; +class TQToolBox; + +class KURLRequester; +class KIntNumInput; + +namespace Digikam +{ +class ICCTransform; +class ImageWidget; +class HistogramWidget; +class ColorGradientWidget; +class DColor; +class ICCPreviewWidget; +class ImageCurves; +class CurvesWidget; +} + +namespace DigikamImagesPluginCore +{ + +class ImageEffect_ICCProof : public Digikam::ImageDlgBase +{ + TQ_OBJECT + + +public: + + ImageEffect_ICCProof(TQWidget* parent); + ~ImageEffect_ICCProof(); + +protected: + + void finalRendering(); + +private: + + void readUserSettings(); + void writeUserSettings(); + void resetValues(); + + void getICCInfo(const TQString&); + void getICCInfo(const TQByteArray&); + + bool useBPC(); + bool doProof(); + bool checkGamut(); + bool embedProfile(); + + bool useEmbeddedProfile(); + bool useBuiltinProfile(); + bool useDefaultInProfile(); + bool useSelectedInProfile(); + + bool useDefaultSpaceProfile(); + bool useSelectedSpaceProfile(); + + bool useDefaultProofProfile(); + bool useSelectedProofProfile(); + +private slots: + + void slotUser2(); + void slotUser3(); + void slotEffect(); + void slotChannelChanged(int); + void slotScaleChanged(int); + void slotSpotColorChanged(const Digikam::DColor &); + void slotColorSelectedFromTarget(const Digikam::DColor &); + void slotToggledWidgets(bool); + void slotInICCInfo(); + void slotProofICCInfo(); + void slotSpaceICCInfo(); + void slotCMDisabledWarning(); + void processLCMSURL(const TQString&); + +private: + + enum HistogramScale + { + Linear = 0, + Logarithmic + }; + + enum ColorChannel + { + LuminosityChannel = 0, + RedChannel, + GreenChannel, + BlueChannel + }; + + enum ICCSettingsTab + { + GENERALPAGE=0, + INPUTPAGE, + WORKSPACEPAGE, + PROOFINGPAGE, + LIGHTNESSPAGE + }; + + bool m_cmEnabled; + bool m_hasICC; + + uchar *m_destinationPreviewData; + + TQComboBox *m_channelCB; + TQComboBox *m_renderingIntentsCB; + + TQCheckBox *m_doSoftProofBox; + TQCheckBox *m_checkGamutBox; + TQCheckBox *m_embeddProfileBox; + TQCheckBox *m_BPCBox; + + TQRadioButton *m_useEmbeddedProfile; + TQRadioButton *m_useInDefaultProfile; + TQRadioButton *m_useInSelectedProfile; + TQRadioButton *m_useProofDefaultProfile; + TQRadioButton *m_useProofSelectedProfile; + TQRadioButton *m_useSpaceDefaultProfile; + TQRadioButton *m_useSpaceSelectedProfile; + TQRadioButton *m_useSRGBDefaultProfile; + + TQString m_inPath; + TQString m_spacePath; + TQString m_proofPath; + + TQButtonGroup *m_optionsBG; + TQButtonGroup *m_inProfileBG; + TQButtonGroup *m_spaceProfileBG; + TQButtonGroup *m_proofProfileBG; + + TQHButtonGroup *m_scaleBG; + TQVButtonGroup *m_renderingIntentBG; + TQVButtonGroup *m_profilesBG; + + TQByteArray m_embeddedICC; + + TQToolBox *m_toolBoxWidgets; + + KIntNumInput *m_cInput; + + KURLRequester *m_inProfilesPath; + KURLRequester *m_spaceProfilePath; + KURLRequester *m_proofProfilePath; + + Digikam::DImg *m_originalImage; + + Digikam::CurvesWidget *m_curvesWidget; + + Digikam::ImageCurves *m_curves; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::ColorGradientWidget *m_hGradient; + + Digikam::HistogramWidget *m_histogramWidget; + + Digikam::ICCPreviewWidget *m_iccInPreviewWidget; + Digikam::ICCPreviewWidget *m_iccSpacePreviewWidget; + Digikam::ICCPreviewWidget *m_iccProofPreviewWidget; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif // IMAGEEFFECT_ICCPROOF_H diff --git a/src/imageplugins/coreplugin/imageeffect_redeye.cpp b/src/imageplugins/coreplugin/imageeffect_redeye.cpp new file mode 100644 index 00000000..df3ae2e7 --- /dev/null +++ b/src/imageplugins/coreplugin/imageeffect_redeye.cpp @@ -0,0 +1,574 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-06-06 + * Description : Red eyes correction tool for image editor + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqcolor.h> +#include <tqhbox.h> +#include <tqhgroupbox.h> +#include <tqvgroupbox.h> +#include <tqhbuttongroup.h> +#include <tqvbox.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqframe.h> +#include <tqlabel.h> +#include <tqpushbutton.h> +#include <tqcombobox.h> +#include <tqwhatsthis.h> +#include <tqtooltip.h> + +// KDE includes. + +#include <kcolordialog.h> +#include <knuminput.h> +#include <tdelocale.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <kstandarddirs.h> +#include <kcolordialog.h> + +// Digikam includes. + +#include "imageiface.h" +#include "imagewidget.h" +#include "histogramwidget.h" +#include "colorgradientwidget.h" +#include "bcgmodifier.h" +#include "dimg.h" +#include "dimgimagefilters.h" + +// Local includes. + +#include "imageeffect_redeye.h" +#include "imageeffect_redeye.moc" + +namespace DigikamImagesPluginCore +{ + +ImageEffect_RedEye::ImageEffect_RedEye(TQWidget* parent) + : Digikam::ImageDlgBase(parent, i18n("Red Eye Reduction"), "redeye", false) +{ + m_destinationPreviewData = 0; + setHelp("redeyecorrectiontool.anchor", "digikam"); + + m_previewWidget = new Digikam::ImageWidget("redeye Tool Dialog", plainPage(), + i18n("<p>Here you can see the image selection preview with " + "red eye reduction applied."), + true, Digikam::ImageGuideWidget::PickColorMode, true, true); + setPreviewAreaWidget(m_previewWidget); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(plainPage()); + TQGridLayout* gridSettings = new TQGridLayout(gboxSettings, 11, 4, spacingHint()); + + TQLabel *label1 = new TQLabel(i18n("Channel:"), gboxSettings); + label1->setAlignment ( TQt::AlignRight | TQt::AlignVCenter ); + m_channelCB = new TQComboBox( false, gboxSettings ); + 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("<p>Select the histogram channel to display here:<p>" + "<b>Luminosity</b>: display the image's luminosity values.<p>" + "<b>Red</b>: display the red image channel values.<p>" + "<b>Green</b>: display the green image channel values.<p>" + "<b>Blue</b>: display the blue image channel values.<p>")); + + m_scaleBG = new TQHButtonGroup(gboxSettings); + m_scaleBG->setExclusive(true); + m_scaleBG->setFrameShape(TQFrame::NoFrame); + m_scaleBG->setInsideMargin(0); + TQWhatsThis::add( m_scaleBG, i18n("<p>Select the histogram scale here.<p>" + "If the image's maximum counts are small, you can use the linear scale.<p>" + "The logarithmic scale can be used when the maximal counts are big " + "to show all values (small and large) on the graph.")); + + TQPushButton *linHistoButton = new TQPushButton( m_scaleBG ); + TQToolTip::add( linHistoButton, i18n( "<p>Linear" ) ); + m_scaleBG->insert(linHistoButton, Digikam::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( "<p>Logarithmic" ) ); + m_scaleBG->insert(logHistoButton, Digikam::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); + + // ------------------------------------------------------------- + + TQVBox *histoBox = new TQVBox(gboxSettings); + m_histogramWidget = new Digikam::HistogramWidget(256, 140, histoBox, false, true, true); + TQWhatsThis::add( m_histogramWidget, i18n("<p>Here you can see the target preview image histogram " + "of the selected image channel. It is " + "updated upon setting changes.")); + TQLabel *space = new TQLabel(histoBox); + space->setFixedHeight(1); + m_hGradient = new Digikam::ColorGradientWidget(Digikam::ColorGradientWidget::Horizontal, 10, histoBox); + m_hGradient->setColors(TQColor("black"), TQColor("white")); + + // ------------------------------------------------------------- + + m_thresholdLabel = new TQLabel(i18n("Sensitivity:"), gboxSettings); + m_redThreshold = new KIntNumInput(gboxSettings); + m_redThreshold->setRange(10, 90, 1, true); + m_redThreshold->setValue(20); + TQWhatsThis::add(m_redThreshold, i18n("<p>Sets the red color pixels selection threshold. " + "Low values will select more red color pixels (agressive correction), high " + "values less (mild correction). Use low value if eye have been selected " + "exactly. Use high value if other parts of the face are also selected.")); + + m_smoothLabel = new TQLabel(i18n("Smooth:"), gboxSettings); + m_smoothLevel = new KIntNumInput(gboxSettings); + m_smoothLevel->setRange(0, 5, 1, true); + m_smoothLevel->setValue(1); + TQWhatsThis::add(m_smoothLevel, i18n("<p>Sets the smoothness value when blurring the border " + "of the changed pixels. " + "This leads to a more naturally looking pupil.")); + + TQLabel *label3 = new TQLabel(i18n("Coloring Tint:"), gboxSettings); + m_HSSelector = new KHSSelector(gboxSettings); + m_VSelector = new KValueSelector(gboxSettings); + m_HSSelector->setMinimumSize(200, 142); + m_VSelector->setMinimumSize(26, 142); + TQWhatsThis::add(m_HSSelector, i18n("<p>Sets a custom color to re-colorize the eyes.")); + + TQLabel *label4 = new TQLabel(i18n("Tint Level:"), gboxSettings); + m_tintLevel = new KIntNumInput(gboxSettings); + m_tintLevel->setRange(1, 200, 1, true); + m_tintLevel->setValue(128); + TQWhatsThis::add(m_tintLevel, i18n("<p>Set the tint level to adjust the luminosity of " + "the new color of the pupil.")); + + gridSettings->addMultiCellLayout(l1, 0, 0, 0, 4); + gridSettings->addMultiCellWidget(histoBox, 1, 2, 0, 4); + gridSettings->addMultiCellWidget(m_thresholdLabel, 3, 3, 0, 4); + gridSettings->addMultiCellWidget(m_redThreshold, 4, 4, 0, 4); + gridSettings->addMultiCellWidget(m_smoothLabel, 5, 5, 0, 4); + gridSettings->addMultiCellWidget(m_smoothLevel, 6, 6, 0, 4); + gridSettings->addMultiCellWidget(label3, 7, 7, 0, 4); + gridSettings->addMultiCellWidget(m_HSSelector, 8, 8, 0, 3); + gridSettings->addMultiCellWidget(m_VSelector, 8, 8, 4, 4); + gridSettings->addMultiCellWidget(label4, 9, 9, 0, 4); + gridSettings->addMultiCellWidget(m_tintLevel, 10, 10, 0, 4); + gridSettings->setRowStretch(11, 10); + gridSettings->setColStretch(3, 10); + setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + 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_previewWidget, TQ_SIGNAL(spotPositionChangedFromTarget(const Digikam::DColor&, const TQPoint&)), + this, TQ_SLOT(slotColorSelectedFromTarget(const Digikam::DColor&))); + + connect(m_previewWidget, TQ_SIGNAL(signalResized()), + this, TQ_SLOT(slotEffect())); + + connect(m_redThreshold, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_smoothLevel, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_HSSelector, TQ_SIGNAL(valueChanged(int, int)), + this, TQ_SLOT(slotHSChanged(int, int))); + + connect(m_VSelector, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_tintLevel, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); +} + +ImageEffect_RedEye::~ImageEffect_RedEye() +{ + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + delete m_histogramWidget; + delete m_previewWidget; +} + +void ImageEffect_RedEye::slotHSChanged(int h, int s) +{ + m_VSelector->blockSignals(true); + m_VSelector->setHue(h); + m_VSelector->setSaturation(s); + m_VSelector->updateContents(); + m_VSelector->repaint(false); + m_VSelector->blockSignals(false); + slotTimer(); +} + +void ImageEffect_RedEye::slotChannelChanged(int channel) +{ + switch(channel) + { + case LuminosityChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::ValueHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + break; + + case RedChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::RedChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "red" ) ); + break; + + case GreenChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::GreenChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "green" ) ); + break; + + case BlueChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::BlueChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "blue" ) ); + break; + } + + m_histogramWidget->repaint(false); +} + +void ImageEffect_RedEye::slotScaleChanged(int scale) +{ + m_histogramWidget->m_scaleType = scale; + m_histogramWidget->repaint(false); +} + +void ImageEffect_RedEye::slotColorSelectedFromTarget(const Digikam::DColor& color) +{ + m_histogramWidget->setHistogramGuideByColor(color); +} + +void ImageEffect_RedEye::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("redeye Tool Dialog"); + m_channelCB->setCurrentItem(config->readNumEntry("Histogram Channel", 0)); // Luminosity. + m_scaleBG->setButton(config->readNumEntry("Histogram Scale", Digikam::HistogramWidget::LogScaleHistogram)); + m_redThreshold->setValue(config->readNumEntry("RedThreshold", 20)); + m_smoothLevel->setValue(config->readNumEntry("SmoothLevel", 1)); + m_HSSelector->setXValue(config->readNumEntry("HueColoringTint", 0)); + m_HSSelector->setYValue(config->readNumEntry("SatColoringTint", 0)); + m_VSelector->setValue(config->readNumEntry("ValColoringTint", 0)); + m_tintLevel->setValue(config->readNumEntry("TintLevel", 128)); + + slotHSChanged(m_HSSelector->xValue(), m_HSSelector->yValue()); + slotChannelChanged(m_channelCB->currentItem()); + slotScaleChanged(m_scaleBG->selectedId()); +} + +void ImageEffect_RedEye::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("redeye Tool Dialog"); + config->writeEntry("Histogram Channel", m_channelCB->currentItem()); + config->writeEntry("Histogram Scale", m_scaleBG->selectedId()); + config->writeEntry("RedThreshold", m_redThreshold->value()); + config->writeEntry("SmoothLevel", m_smoothLevel->value()); + config->writeEntry("HueColoringTint", m_HSSelector->xValue()); + config->writeEntry("SatColoringTint", m_HSSelector->yValue()); + config->writeEntry("ValColoringTint", m_VSelector->value()); + config->writeEntry("TintLevel", m_tintLevel->value()); + config->sync(); +} + +void ImageEffect_RedEye::resetValues() +{ + m_redThreshold->blockSignals(true); + m_HSSelector->blockSignals(true); + m_VSelector->blockSignals(true); + m_tintLevel->blockSignals(true); + + m_redThreshold->setValue(20); + m_smoothLevel->setValue(1); + + // Black color by default + m_HSSelector->setXValue(0); + m_HSSelector->setYValue(0); + m_VSelector->setValue(0); + + m_tintLevel->setValue(128); + + m_redThreshold->blockSignals(false); + m_HSSelector->blockSignals(false); + m_VSelector->blockSignals(false); + m_tintLevel->blockSignals(false); +} + +void ImageEffect_RedEye::slotEffect() +{ + kapp->setOverrideCursor(KCursor::waitCursor()); + + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + // Here, we need to use the real selection image data because we will apply + // a Gaussian blur filter on pixels and we cannot use directly the preview scaled image + // else the blur radius will not give the same result between preview and final rendering. + Digikam::ImageIface* iface = m_previewWidget->imageIface(); + m_destinationPreviewData = iface->getImageSelection(); + int w = iface->selectedWidth(); + int h = iface->selectedHeight(); + bool sb = iface->originalSixteenBit(); + bool a = iface->originalHasAlpha(); + Digikam::DImg selection(w, h, sb, a, m_destinationPreviewData); + + redEyeFilter(selection); + + Digikam::DImg preview = selection.smoothScale(iface->previewWidth(), iface->previewHeight()); + + iface->putPreviewImage(preview.bits()); + m_previewWidget->updatePreview(); + + // Update histogram. + + memcpy(m_destinationPreviewData, selection.bits(), selection.numBytes()); + m_histogramWidget->updateData(m_destinationPreviewData, w, h, sb, 0, 0, 0, false); + + kapp->restoreOverrideCursor(); +} + +void ImageEffect_RedEye::finalRendering() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + + Digikam::ImageIface* iface = m_previewWidget->imageIface(); + uchar *data = iface->getImageSelection(); + int w = iface->selectedWidth(); + int h = iface->selectedHeight(); + bool sixteenBit = iface->originalSixteenBit(); + bool hasAlpha = iface->originalHasAlpha(); + Digikam::DImg selection(w, h, sixteenBit, hasAlpha, data); + delete [] data; + + redEyeFilter(selection); + + iface->putImageSelection(i18n("Red Eyes Correction"), selection.bits()); + + kapp->restoreOverrideCursor(); + accept(); +} + +void ImageEffect_RedEye::redEyeFilter(Digikam::DImg& selection) +{ + Digikam::DImg mask(selection.width(), selection.height(), selection.sixteenBit(), true, + selection.bits(), true); + + selection = mask.copy(); + float redThreshold = m_redThreshold->value()/10.0; + int hue = m_HSSelector->xValue(); + int sat = m_HSSelector->yValue(); + int val = m_VSelector->value(); + KColor coloring; + coloring.setHsv(hue, sat, val); + + struct channel + { + float red_gain; + float green_gain; + float blue_gain; + }; + + channel red_chan, green_chan, blue_chan; + + red_chan.red_gain = 0.1; + red_chan.green_gain = 0.6; + red_chan.blue_gain = 0.3; + + green_chan.red_gain = 0.0; + green_chan.green_gain = 1.0; + green_chan.blue_gain = 0.0; + + blue_chan.red_gain = 0.0; + blue_chan.green_gain = 0.0; + blue_chan.blue_gain = 1.0; + + float red_norm, green_norm, blue_norm; + int level = 201 - m_tintLevel->value(); + + red_norm = 1.0 / (red_chan.red_gain + red_chan.green_gain + red_chan.blue_gain); + green_norm = 1.0 / (green_chan.red_gain + green_chan.green_gain + green_chan.blue_gain); + blue_norm = 1.0 / (blue_chan.red_gain + blue_chan.green_gain + blue_chan.blue_gain); + + red_norm *= coloring.red() / level; + green_norm *= coloring.green() / level; + blue_norm *= coloring.blue() / level; + + // Perform a red color pixels detection in selection image and create a correction mask using an alpha channel. + + if (!selection.sixteenBit()) // 8 bits image. + { + uchar* ptr = selection.bits(); + uchar* mptr = mask.bits(); + uchar r, g, b, r1, g1, b1; + + for (uint i = 0 ; i < selection.width() * selection.height() ; i++) + { + b = ptr[0]; + g = ptr[1]; + r = ptr[2]; + mptr[3] = 255; + + if (r >= ( redThreshold * g)) + { + r1 = TQMIN(255, (int)(red_norm * (red_chan.red_gain * r + + red_chan.green_gain * g + + red_chan.blue_gain * b))); + + g1 = TQMIN(255, (int)(green_norm * (green_chan.red_gain * r + + green_chan.green_gain * g + + green_chan.blue_gain * b))); + + b1 = TQMIN(255, (int)(blue_norm * (blue_chan.red_gain * r + + blue_chan.green_gain * g + + blue_chan.blue_gain * b))); + + mptr[0] = b1; + mptr[1] = g1; + mptr[2] = r1; + mptr[3] = TQMIN( (int)((r-g) / 150.0 * 255.0), 255); + } + + ptr += 4; + mptr+= 4; + } + } + else // 16 bits image. + { + unsigned short* ptr = (unsigned short*)selection.bits(); + unsigned short* mptr = (unsigned short*)mask.bits(); + unsigned short r, g, b, r1, g1, b1; + + for (uint i = 0 ; i < selection.width() * selection.height() ; i++) + { + b = ptr[0]; + g = ptr[1]; + r = ptr[2]; + mptr[3] = 65535; + + if (r >= ( redThreshold * g)) + { + r1 = TQMIN(65535, (int)(red_norm * (red_chan.red_gain * r + + red_chan.green_gain * g + + red_chan.blue_gain * b))); + + g1 = TQMIN(65535, (int)(green_norm * (green_chan.red_gain * r + + green_chan.green_gain * g + + green_chan.blue_gain * b))); + + b1 = TQMIN(65535, (int)(blue_norm * (blue_chan.red_gain * r + + blue_chan.green_gain * g + + blue_chan.blue_gain * b))); + + mptr[0] = b1; + mptr[1] = g1; + mptr[2] = r1; + mptr[3] = TQMIN( (int)((r-g) / 38400.0 * 65535.0), 65535);; + } + + ptr += 4; + mptr+= 4; + } + } + + // Now, we will blur only the transparency pixels from the mask. + + Digikam::DImg mask2 = mask.copy(); + Digikam::DImgImageFilters filter; + filter.gaussianBlurImage(mask2.bits(), mask2.width(), mask2.height(), + mask2.sixteenBit(), m_smoothLevel->value()); + + if (!selection.sixteenBit()) // 8 bits image. + { + uchar* mptr = mask.bits(); + uchar* mptr2 = mask2.bits(); + + for (uint i = 0 ; i < mask2.width() * mask2.height() ; i++) + { + if (mptr2[3] < 255) + { + mptr[0] = mptr2[0]; + mptr[1] = mptr2[1]; + mptr[2] = mptr2[2]; + mptr[3] = mptr2[3]; + } + + mptr += 4; + mptr2+= 4; + } + } + else // 16 bits image. + { + unsigned short* mptr = (unsigned short*)mask.bits(); + unsigned short* mptr2 = (unsigned short*)mask2.bits(); + + for (uint i = 0 ; i < mask2.width() * mask2.height() ; i++) + { + if (mptr2[3] < 65535) + { + mptr[0] = mptr2[0]; + mptr[1] = mptr2[1]; + mptr[2] = mptr2[2]; + mptr[3] = mptr2[3]; + } + + mptr += 4; + mptr2+= 4; + } + } + + // - Perform pixels blending using alpha channel between the mask and the selection. + + Digikam::DColorComposer *composer = Digikam::DColorComposer::getComposer(Digikam::DColorComposer::PorterDuffSrcOver); + + // NOTE: 'mask' is the Source image, 'selection' is the Destination image. + + selection.bitBlendImage(composer, &mask, + 0, 0, mask.width(), mask.height(), + 0, 0); +} + +} // NameSpace DigikamImagesPluginCore diff --git a/src/imageplugins/coreplugin/imageeffect_redeye.h b/src/imageplugins/coreplugin/imageeffect_redeye.h new file mode 100644 index 00000000..79b517ee --- /dev/null +++ b/src/imageplugins/coreplugin/imageeffect_redeye.h @@ -0,0 +1,153 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-06-06 + * Description : Red eyes correction tool for image editor + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2004-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. + * + * ============================================================ */ + + +#ifndef IMAGEEFFECT_REDEYE_H +#define IMAGEEFFECT_REDEYE_H + +// KDE includes. + +#include <kpassivepopup.h> + +// Digikam include. + +#include "imagedlgbase.h" + +class TQLabel; +class TQComboBox; +class TQHButtonGroup; + +class KHSSelector; +class KValueSelector; +class KIntNumInput; + +namespace Digikam +{ +class HistogramWidget; +class ColorGradientWidget; +class ImageWidget; +class DColor; +class DImg; +} + +namespace DigikamImagesPluginCore +{ + +class RedEyePassivePopup : public KPassivePopup +{ +public: + + RedEyePassivePopup(TQWidget* parent) + : KPassivePopup(parent), m_parent(parent) + { + } + +protected: + + virtual void positionSelf() + { + move(m_parent->x() + 30, m_parent->y() + 30); + } + +private: + + TQWidget* m_parent; +}; + +// ---------------------------------------------------------------- + +class ImageEffect_RedEye : public Digikam::ImageDlgBase +{ + TQ_OBJECT + + +public: + + ImageEffect_RedEye(TQWidget *parent); + ~ImageEffect_RedEye(); + +private slots: + + void slotEffect(); + void slotChannelChanged(int channel); + void slotScaleChanged(int scale); + void slotColorSelectedFromTarget(const Digikam::DColor &color); + void slotHSChanged(int h, int s); + +private: + + void readUserSettings(); + void writeUserSettings(); + void resetValues(); + void finalRendering(); + void redEyeFilter(Digikam::DImg& selection); + +private: + + enum HistogramScale + { + Linear=0, + Logarithmic + }; + + enum ColorChannel + { + LuminosityChannel=0, + RedChannel, + GreenChannel, + BlueChannel + }; + + enum RedThresold + { + Mild=0, + Aggressive + }; + + uchar *m_destinationPreviewData; + + TQLabel *m_thresholdLabel; + TQLabel *m_smoothLabel; + + TQComboBox *m_channelCB; + + TQHButtonGroup *m_scaleBG; + + KIntNumInput *m_tintLevel; + KIntNumInput *m_redThreshold; + KIntNumInput *m_smoothLevel; + + KHSSelector *m_HSSelector; + KValueSelector *m_VSelector; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::ColorGradientWidget *m_hGradient; + + Digikam::HistogramWidget *m_histogramWidget; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* IMAGEEFFECT_REDEYE_H */ diff --git a/src/imageplugins/coreplugin/imageeffect_rgb.cpp b/src/imageplugins/coreplugin/imageeffect_rgb.cpp new file mode 100644 index 00000000..fcff9c41 --- /dev/null +++ b/src/imageplugins/coreplugin/imageeffect_rgb.cpp @@ -0,0 +1,419 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-11 + * Description : digiKam image editor Color Balance tool. + * + * Copyright (C) 2004-2007 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqspinbox.h> +#include <tqslider.h> +#include <tqcolor.h> +#include <tqgroupbox.h> +#include <tqhgroupbox.h> +#include <tqvgroupbox.h> +#include <tqhbuttongroup.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqframe.h> +#include <tqvbox.h> +#include <tqlabel.h> +#include <tqpushbutton.h> +#include <tqcheckbox.h> +#include <tqcombobox.h> +#include <tqwhatsthis.h> +#include <tqtooltip.h> + +// KDE includes. + +#include <tdeconfig.h> +#include <tdelocale.h> +#include <tdeapplication.h> +#include <kcursor.h> +#include <kstandarddirs.h> + +// Digikam includes. + +#include "imageiface.h" +#include "imagewidget.h" +#include "histogramwidget.h" +#include "colorgradientwidget.h" +#include "colormodifier.h" +#include "dimg.h" + +// Local includes. + +#include "imageeffect_rgb.h" +#include "imageeffect_rgb.moc" + +namespace DigikamImagesPluginCore +{ + +ImageEffect_RGB::ImageEffect_RGB(TQWidget* parent) + : Digikam::ImageDlgBase(parent, i18n("Color Balance"), "colorbalance", false) +{ + m_destinationPreviewData = 0L; + setHelp("colorbalancetool.anchor", "digikam"); + + m_previewWidget = new Digikam::ImageWidget("colorbalance Tool Dialog", plainPage(), + i18n("<p>Here you can see the image " + "color-balance adjustments preview. " + "You can pick color on image " + "to see the color level corresponding on histogram.")); + setPreviewAreaWidget(m_previewWidget); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(plainPage()); + TQGridLayout* gridSettings = new TQGridLayout( gboxSettings, 7, 4, spacingHint()); + + TQLabel *label1 = new TQLabel(i18n("Channel:"), gboxSettings); + label1->setAlignment ( TQt::AlignRight | TQt::AlignVCenter ); + m_channelCB = new TQComboBox( false, gboxSettings ); + 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("<p>Select the histogram channel to display here:<p>" + "<b>Luminosity</b>: display the image's luminosity values.<p>" + "<b>Red</b>: display the red image-channel values.<p>" + "<b>Green</b>: display the green image-channel values.<p>" + "<b>Blue</b>: display the blue image-channel values.<p>")); + + m_scaleBG = new TQHButtonGroup(gboxSettings); + m_scaleBG->setExclusive(true); + m_scaleBG->setFrameShape(TQFrame::NoFrame); + m_scaleBG->setInsideMargin( 0 ); + TQWhatsThis::add( m_scaleBG, i18n("<p>Select the histogram scale here.<p>" + "If the image's maximal counts are small, you can use the linear scale.<p>" + "Logarithmic scale can be used when the maximal counts 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( "<p>Linear" ) ); + m_scaleBG->insert(linHistoButton, Digikam::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( "<p>Logarithmic" ) ); + m_scaleBG->insert(logHistoButton, Digikam::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, 4); + + // ------------------------------------------------------------- + + TQVBox *histoBox = new TQVBox(gboxSettings); + m_histogramWidget = new Digikam::HistogramWidget(256, 140, histoBox, false, true, true); + TQWhatsThis::add( m_histogramWidget, i18n("<p>Here you can see the target preview image histogram drawing " + "of the selected image channel. This one is re-computed at any " + "settings changes.")); + TQLabel *space = new TQLabel(histoBox); + space->setFixedHeight(1); + m_hGradient = new Digikam::ColorGradientWidget( Digikam::ColorGradientWidget::Horizontal, 10, histoBox ); + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + + gridSettings->addMultiCellWidget(histoBox, 1, 2, 0, 4); + + // ------------------------------------------------------------- + + TQLabel *labelLeft = new TQLabel(i18n("Cyan"), gboxSettings); + labelLeft->setAlignment ( TQt::AlignRight | TQt::AlignVCenter ); + m_rSlider = new TQSlider(-100, 100, 1, 0, TQt::Horizontal, gboxSettings, "m_rSlider"); + m_rSlider->setTickmarks(TQSlider::Below); + m_rSlider->setTickInterval(20); + TQWhatsThis::add( m_rSlider, i18n("<p>Set here the cyan/red color adjustment of the image.")); + TQLabel *labelRight = new TQLabel(i18n("Red"), gboxSettings); + labelRight->setAlignment ( TQt::AlignLeft | TQt::AlignVCenter ); + m_rInput = new TQSpinBox(-100, 100, 1, gboxSettings, "m_rInput"); + + gridSettings->addMultiCellWidget(labelLeft, 3, 3, 0, 0); + gridSettings->addMultiCellWidget(m_rSlider, 3, 3, 1, 1); + gridSettings->addMultiCellWidget(labelRight, 3, 3, 2, 2); + gridSettings->addMultiCellWidget(m_rInput, 3, 3, 3, 3); + + // ------------------------------------------------------------- + + labelLeft = new TQLabel(i18n("Magenta"), gboxSettings); + labelLeft->setAlignment ( TQt::AlignRight | TQt::AlignVCenter ); + m_gSlider = new TQSlider(-100, 100, 1, 0, TQt::Horizontal, gboxSettings, "m_gSlider"); + m_gSlider->setTickmarks(TQSlider::Below); + m_gSlider->setTickInterval(20); + TQWhatsThis::add( m_gSlider, i18n("<p>Set here the magenta/green color adjustment of the image.")); + labelRight = new TQLabel(i18n("Green"), gboxSettings); + labelRight->setAlignment ( TQt::AlignLeft | TQt::AlignVCenter ); + m_gInput = new TQSpinBox(-100, 100, 1, gboxSettings, "m_gInput"); + + gridSettings->addMultiCellWidget(labelLeft, 4, 4, 0, 0); + gridSettings->addMultiCellWidget(m_gSlider, 4, 4, 1, 1); + gridSettings->addMultiCellWidget(labelRight, 4, 4, 2, 2); + gridSettings->addMultiCellWidget(m_gInput, 4, 4, 3, 3); + + // ------------------------------------------------------------- + + labelLeft = new TQLabel(i18n("Yellow"), gboxSettings); + labelLeft->setAlignment ( TQt::AlignRight | TQt::AlignVCenter ); + m_bSlider = new TQSlider(-100, 100, 1, 0, TQt::Horizontal, gboxSettings, "m_bSlider"); + m_bSlider->setTickmarks(TQSlider::Below); + m_bSlider->setTickInterval(20); + TQWhatsThis::add( m_bSlider, i18n("<p>Set here the yellow/blue color adjustment of the image.")); + labelRight = new TQLabel(i18n("Blue"), gboxSettings); + labelRight->setAlignment ( TQt::AlignLeft | TQt::AlignVCenter ); + m_bInput = new TQSpinBox(-100, 100, 1, gboxSettings, "m_bInput"); + + gridSettings->addMultiCellWidget(labelLeft, 5, 5, 0, 0); + gridSettings->addMultiCellWidget(m_bSlider, 5, 5, 1, 1); + gridSettings->addMultiCellWidget(labelRight, 5, 5, 2, 2); + gridSettings->addMultiCellWidget(m_bInput, 5, 5, 3, 3); + + m_rInput->setValue(0); + m_gInput->setValue(0); + m_bInput->setValue(0); + + gridSettings->setRowStretch(6, 10); + setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + 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_previewWidget, TQ_SIGNAL(spotPositionChangedFromTarget( const Digikam::DColor &, const TQPoint & )), + this, TQ_SLOT(slotColorSelectedFromTarget( const Digikam::DColor & ))); + + connect(m_rSlider, TQ_SIGNAL(valueChanged(int)), + m_rInput, TQ_SLOT(setValue(int))); + connect(m_rInput, TQ_SIGNAL(valueChanged (int)), + m_rSlider, TQ_SLOT(setValue(int))); + connect(m_rInput, TQ_SIGNAL(valueChanged (int)), + this, TQ_SLOT(slotTimer())); + + connect(m_gSlider, TQ_SIGNAL(valueChanged(int)), + m_gInput, TQ_SLOT(setValue(int))); + connect(m_gInput, TQ_SIGNAL(valueChanged (int)), + m_gSlider, TQ_SLOT(setValue(int))); + connect(m_gInput, TQ_SIGNAL(valueChanged (int)), + this, TQ_SLOT(slotTimer())); + + connect(m_bSlider, TQ_SIGNAL(valueChanged(int)), + m_bInput, TQ_SLOT(setValue(int))); + connect(m_bInput, TQ_SIGNAL(valueChanged (int)), + m_bSlider, TQ_SLOT(setValue(int))); + connect(m_bInput, TQ_SIGNAL(valueChanged (int)), + this, TQ_SLOT(slotTimer())); + + connect(m_previewWidget, TQ_SIGNAL(signalResized()), + this, TQ_SLOT(slotEffect())); + + // ------------------------------------------------------------- + + enableButtonOK( false ); +} + +ImageEffect_RGB::~ImageEffect_RGB() +{ + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + delete m_histogramWidget; + delete m_previewWidget; +} + +void ImageEffect_RGB::slotChannelChanged(int channel) +{ + switch(channel) + { + case LuminosityChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::ValueHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + break; + + case RedChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::RedChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "red" ) ); + break; + + case GreenChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::GreenChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "green" ) ); + break; + + case BlueChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::BlueChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "blue" ) ); + break; + } + + m_histogramWidget->repaint(false); +} + +void ImageEffect_RGB::slotScaleChanged(int scale) +{ + m_histogramWidget->m_scaleType = scale; + m_histogramWidget->repaint(false); +} + +void ImageEffect_RGB::slotColorSelectedFromTarget( const Digikam::DColor &color ) +{ + m_histogramWidget->setHistogramGuideByColor(color); +} + +void ImageEffect_RGB::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("colorbalance Tool Dialog"); + m_channelCB->setCurrentItem(config->readNumEntry("Histogram Channel", 0)); // Luminosity. + m_scaleBG->setButton(config->readNumEntry("Histogram Scale", Digikam::HistogramWidget::LogScaleHistogram)); + int r = config->readNumEntry("RedAjustment", 0); + int g = config->readNumEntry("GreenAjustment", 0); + int b = config->readNumEntry("BlueAjustment", 0); + adjustSliders(r, g, b); + slotChannelChanged(m_channelCB->currentItem()); + slotScaleChanged(m_scaleBG->selectedId()); +} + +void ImageEffect_RGB::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("colorbalance Tool Dialog"); + config->writeEntry("Histogram Channel", m_channelCB->currentItem()); + config->writeEntry("Histogram Scale", m_scaleBG->selectedId()); + config->writeEntry("RedAjustment", m_rSlider->value()); + config->writeEntry("GreenAjustment", m_gInput->value()); + config->writeEntry("BlueAjustment", m_bInput->value()); + config->sync(); +} + +void ImageEffect_RGB::resetValues() +{ + adjustSliders(0, 0, 0); +} + +void ImageEffect_RGB::adjustSliders(int r, int g, int b) +{ + m_rSlider->blockSignals(true); + m_gSlider->blockSignals(true); + m_bSlider->blockSignals(true); + m_rInput->blockSignals(true); + m_gInput->blockSignals(true); + m_bInput->blockSignals(true); + + m_rSlider->setValue(r); + m_gSlider->setValue(g); + m_bSlider->setValue(b); + m_rInput->setValue(r); + m_gInput->setValue(g); + m_bInput->setValue(b); + + m_rSlider->blockSignals(false); + m_gSlider->blockSignals(false); + m_bSlider->blockSignals(false); + m_rInput->blockSignals(false); + m_gInput->blockSignals(false); + m_bInput->blockSignals(false); + + slotEffect(); +} + +void ImageEffect_RGB::slotEffect() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + + enableButtonOK(m_rInput->value() != 0 || + m_gInput->value() != 0 || + m_bInput->value() != 0); + + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + Digikam::ImageIface* iface = m_previewWidget->imageIface(); + m_destinationPreviewData = iface->getPreviewImage(); + int w = iface->previewWidth(); + int h = iface->previewHeight(); + bool alpha = iface->previewHasAlpha(); + bool sixteenBit = iface->previewSixteenBit(); + + double r = ((double)m_rInput->value() + 100.0)/100.0; + double g = ((double)m_gInput->value() + 100.0)/100.0; + double b = ((double)m_bInput->value() + 100.0)/100.0; + double a = 1.0; + + Digikam::DImg preview(w, h, sixteenBit, alpha, m_destinationPreviewData); + Digikam::ColorModifier cmod; + cmod.applyColorModifier(preview, r, g, b, a); + iface->putPreviewImage(preview.bits()); + + m_previewWidget->updatePreview(); + + // Update histogram. + + memcpy(m_destinationPreviewData, preview.bits(), preview.numBytes()); + m_histogramWidget->updateData(m_destinationPreviewData, w, h, sixteenBit, 0, 0, 0, false); + + kapp->restoreOverrideCursor(); +} + +void ImageEffect_RGB::finalRendering() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + + double r = ((double)m_rInput->value() + 100.0)/100.0; + double g = ((double)m_gInput->value() + 100.0)/100.0; + double b = ((double)m_bInput->value() + 100.0)/100.0; + double a = 1.0; + + Digikam::ImageIface* iface = m_previewWidget->imageIface(); + uchar *data = iface->getOriginalImage(); + int w = iface->originalWidth(); + int h = iface->originalHeight(); + bool alpha = iface->originalHasAlpha(); + bool sixteenBit = iface->originalSixteenBit(); + Digikam::DImg original(w, h, sixteenBit, alpha, data); + delete [] data; + + Digikam::ColorModifier cmod; + cmod.applyColorModifier(original, r, g, b, a); + + iface->putOriginalImage(i18n("Color Balance"), original.bits()); + kapp->restoreOverrideCursor(); + accept(); +} + +} // NameSpace DigikamImagesPluginCore + diff --git a/src/imageplugins/coreplugin/imageeffect_rgb.h b/src/imageplugins/coreplugin/imageeffect_rgb.h new file mode 100644 index 00000000..9f5db52c --- /dev/null +++ b/src/imageplugins/coreplugin/imageeffect_rgb.h @@ -0,0 +1,113 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-11 + * Description : digiKam image editor Color Balance tool. + * + * Copyright (C) 2004-2007 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_RGB_H +#define IMAGEEFFECT_RGB_H + +// Digikam include. + +#include "imagedlgbase.h" + +class TQComboBox; +class TQHButtonGroup; + +class TQSpinBox; +class TQSlider; + +namespace Digikam +{ +class HistogramWidget; +class ColorGradientWidget; +class ImageWidget; +class DColor; +} + +namespace DigikamImagesPluginCore +{ + +class ImageEffect_RGB : public Digikam::ImageDlgBase +{ + TQ_OBJECT + + +public: + + ImageEffect_RGB(TQWidget *parent); + ~ImageEffect_RGB(); + +private: + + void writeUserSettings(); + void readUserSettings(); + void resetValues(); + void adjustSliders(int r, int g, int b); + void finalRendering(); + +private slots: + + void slotEffect(); + void slotChannelChanged(int channel); + void slotScaleChanged(int scale); + void slotColorSelectedFromTarget( const Digikam::DColor &color ); + +private: + + enum HistogramScale + { + Linear=0, + Logarithmic + }; + + enum ColorChannel + { + LuminosityChannel=0, + RedChannel, + GreenChannel, + BlueChannel + }; + + uchar *m_destinationPreviewData; + + TQComboBox *m_channelCB; + + TQHButtonGroup *m_scaleBG; + + TQSpinBox *m_rInput; + TQSpinBox *m_gInput; + TQSpinBox *m_bInput; + + TQSlider *m_rSlider; + TQSlider *m_gSlider; + TQSlider *m_bSlider; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::ColorGradientWidget *m_hGradient; + + Digikam::HistogramWidget *m_histogramWidget; + +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* IMAGEEFFECT_RGB_H */ diff --git a/src/imageplugins/coreplugin/imageplugin_core.cpp b/src/imageplugins/coreplugin/imageplugin_core.cpp new file mode 100644 index 00000000..22c63b34 --- /dev/null +++ b/src/imageplugins/coreplugin/imageplugin_core.cpp @@ -0,0 +1,295 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-06-04 + * Description : digiKam image editor plugin core + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2005-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> + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> +#include <tdemessagebox.h> +#include <tdeapplication.h> + +// Local includes. + +#include "ddebug.h" +#include "dimg.h" +#include "dimgimagefilters.h" +#include "imageiface.h" +#include "rgbtool.h" +#include "hsltool.h" +#include "bcgtool.h" +#include "bwsepiatool.h" +#include "redeyetool.h" +#include "blurtool.h" +#include "sharpentool.h" +#include "ratiocroptool.h" +#include "autocorrectiontool.h" +#include "iccprooftool.h" +#include "imageplugin_core.h" +#include "imageplugin_core.moc" + +using namespace DigikamImagesPluginCore; +using namespace Digikam; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_core, + KGenericFactory<ImagePlugin_Core>("digikam")); + +ImagePlugin_Core::ImagePlugin_Core(TQObject *parent, const char*, const TQStringList&) + : ImagePlugin(parent, "ImagePlugin_Core") +{ + //------------------------------- + // Fix and Colors menu actions + + m_blurAction = new TDEAction(i18n("Blur..."), "blurimage", 0, + this, TQ_SLOT(slotBlur()), + actionCollection(), "implugcore_blur"); + + m_sharpenAction = new TDEAction(i18n("Sharpen..."), "sharpenimage", 0, + this, TQ_SLOT(slotSharpen()), + actionCollection(), "implugcore_sharpen"); + + m_redeyeAction = new TDEAction(i18n("Red Eye..."), "redeyes", 0, + this, TQ_SLOT(slotRedEye()), + actionCollection(), "implugcore_redeye"); + m_redeyeAction->setWhatsThis( i18n( "This filter can be used to correct red eyes in a photo. " + "Select a region including the eyes to use this option.") ); + + m_BCGAction = new TDEAction(i18n("Brightness/Contrast/Gamma..."), "contrast", 0, + this, TQ_SLOT(slotBCG()), + actionCollection(), "implugcore_bcg"); + + m_HSLAction = new TDEAction(i18n("Hue/Saturation/Lightness..."), "adjusthsl", + CTRL+Key_U, // NOTE: Photoshop 7 use CTRL+U. + this, TQ_SLOT(slotHSL()), + actionCollection(), "implugcore_hsl"); + + m_RGBAction = new TDEAction(i18n("Color Balance..."), "adjustrgb", + CTRL+Key_B, // NOTE: Photoshop 7 use CTRL+B. + this, TQ_SLOT(slotRGB()), + actionCollection(), "implugcore_rgb"); + + m_autoCorrectionAction = new TDEAction(i18n("Auto-Correction..."), "autocorrection", + CTRL+SHIFT+Key_B, // NOTE: Photoshop 7 use CTRL+SHIFT+B with 'Auto-Color' option. + this, TQ_SLOT(slotAutoCorrection()), + actionCollection(), "implugcore_autocorrection"); + + m_invertAction = new TDEAction(i18n("Invert"), "invertimage", + CTRL+Key_I, // NOTE: Photoshop 7 use CTRL+I. + this, TQ_SLOT(slotInvert()), + actionCollection(), "implugcore_invert"); + + m_convertTo8Bits = new TDEAction(i18n("8 bits"), "depth16to8", 0, + this, TQ_SLOT(slotConvertTo8Bits()), + actionCollection(), "implugcore_convertto8bits"); + + m_convertTo16Bits = new TDEAction(i18n("16 bits"), "depth8to16", 0, + this, TQ_SLOT(slotConvertTo16Bits()), + actionCollection(), "implugcore_convertto16bits"); + + m_colorManagementAction = new TDEAction(i18n("Color Management..."), "colormanagement", 0, + this, TQ_SLOT(slotColorManagement()), + actionCollection(), "implugcore_colormanagement"); + //------------------------------- + // Filters menu actions. + + m_BWAction = new TDEAction(i18n("Black && White..."), "bwtonal", 0, + this, TQ_SLOT(slotBW()), + actionCollection(), "implugcore_blackwhite"); + + //------------------------------- + // Transform menu actions. + + m_aspectRatioCropAction = new TDEAction(i18n("Aspect Ratio Crop..."), "ratiocrop", 0, + this, TQ_SLOT(slotRatioCrop()), + actionCollection(), "implugcore_ratiocrop"); + + //------------------------------- + // Init. menu actions. + + setXMLFile("digikamimageplugin_core_ui.rc"); + + DDebug() << "ImagePlugin_Core plugin loaded" << endl; +} + +ImagePlugin_Core::~ImagePlugin_Core() +{ +} + +void ImagePlugin_Core::setEnabledSelectionActions(bool) +{ +} + +void ImagePlugin_Core::setEnabledActions(bool enable) +{ + m_redeyeAction->setEnabled(enable); + m_BCGAction->setEnabled(enable); + m_HSLAction->setEnabled(enable); + m_RGBAction->setEnabled(enable); + m_autoCorrectionAction->setEnabled(enable); + m_invertAction->setEnabled(enable); + m_BWAction->setEnabled(enable); + m_aspectRatioCropAction->setEnabled(enable); + m_sharpenAction->setEnabled(enable); + m_blurAction->setEnabled(enable); + m_colorManagementAction->setEnabled(enable); + m_convertTo8Bits->setEnabled(enable); + m_convertTo16Bits->setEnabled(enable); +} + +void ImagePlugin_Core::slotBlur() +{ + BlurTool *tool = new BlurTool(this); + loadTool(tool); +} + +void ImagePlugin_Core::slotSharpen() +{ + SharpenTool *tool = new SharpenTool(this); + loadTool(tool); +} + +void ImagePlugin_Core::slotBCG() +{ + BCGTool *bcg = new BCGTool(this); + loadTool(bcg); +} + +void ImagePlugin_Core::slotRGB() +{ + RGBTool *rgb = new RGBTool(this); + loadTool(rgb); +} + +void ImagePlugin_Core::slotHSL() +{ + HSLTool *hsl = new HSLTool(this); + loadTool(hsl); +} + +void ImagePlugin_Core::slotAutoCorrection() +{ + AutoCorrectionTool *autocorrection = new AutoCorrectionTool(this); + loadTool(autocorrection); +} + +void ImagePlugin_Core::slotInvert() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + + ImageIface iface(0, 0); + + uchar *data = iface.getOriginalImage(); + int w = iface.originalWidth(); + int h = iface.originalHeight(); + bool sixteenBit = iface.originalSixteenBit(); + + DImgImageFilters filter; + filter.invertImage(data, w, h, sixteenBit); + iface.putOriginalImage(i18n("Invert"), data); + delete [] data; + + kapp->restoreOverrideCursor(); +} + +void ImagePlugin_Core::slotBW() +{ + BWSepiaTool *bwsepia = new BWSepiaTool(this); + loadTool(bwsepia); +} + +void ImagePlugin_Core::slotRedEye() +{ + ImageIface iface(0, 0); + + if (!iface.selectedWidth() || !iface.selectedHeight()) + { + RedEyePassivePopup* popup = new RedEyePassivePopup(kapp->activeWindow()); + popup->setView(i18n("Red-Eye Correction Tool"), + i18n("You need to select a region including the eyes to use " + "the red-eye correction tool")); + popup->setAutoDelete(true); + popup->setTimeout(2500); + popup->show(); + return; + } + + RedEyeTool *redeye = new RedEyeTool(this); + loadTool(redeye); +} + +void ImagePlugin_Core::slotColorManagement() +{ + ICCProofTool *tool = new ICCProofTool(this); + loadTool(tool); +} + +void ImagePlugin_Core::slotRatioCrop() +{ + RatioCropTool *ratiocrop = new RatioCropTool(this); + loadTool(ratiocrop); +} + +void ImagePlugin_Core::slotConvertTo8Bits() +{ + ImageIface iface(0, 0); + + if (!iface.originalSixteenBit()) + { + KMessageBox::error(kapp->activeWindow(), i18n("This image is already using a depth of 8 bits / color / pixel.")); + return; + } + else + { + if (KMessageBox::warningContinueCancel( + kapp->activeWindow(), + i18n("Performing this operation will reduce image color quality. " + "Do you want to continue?"), TQString(), + KStdGuiItem::cont(), + TQString("ImagePluginCore16To8Bits")) == KMessageBox::Cancel) + return; + } + + kapp->setOverrideCursor( KCursor::waitCursor() ); + iface.convertOriginalColorDepth(32); + kapp->restoreOverrideCursor(); +} + +void ImagePlugin_Core::slotConvertTo16Bits() +{ + ImageIface iface(0, 0); + + if (iface.originalSixteenBit()) + { + KMessageBox::error(kapp->activeWindow(), i18n("This image is already using a depth of 16 bits / color / pixel.")); + return; + } + + kapp->setOverrideCursor( KCursor::waitCursor() ); + iface.convertOriginalColorDepth(64); + kapp->restoreOverrideCursor(); +} diff --git a/src/imageplugins/coreplugin/imageplugin_core.h b/src/imageplugins/coreplugin/imageplugin_core.h new file mode 100644 index 00000000..41168d26 --- /dev/null +++ b/src/imageplugins/coreplugin/imageplugin_core.h @@ -0,0 +1,85 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-06-04 + * Description : digiKam image editor plugin core + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2005-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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_CORE_H +#define IMAGEPLUGIN_CORE_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_Core : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_Core(TQObject *parent, const char* name, const TQStringList &args); + ~ImagePlugin_Core(); + + void setEnabledSelectionActions(bool enable); + void setEnabledActions(bool enable); + +private slots: + + void slotBlur(); + void slotSharpen(); + void slotBCG(); + void slotRGB(); + void slotHSL(); + void slotAutoCorrection(); + void slotInvert(); + + void slotBW(); + + void slotRedEye(); + void slotRatioCrop(); + + void slotConvertTo8Bits(); + void slotConvertTo16Bits(); + + void slotColorManagement(); + +private: + + TDEAction *m_redeyeAction; + TDEAction *m_BCGAction; + TDEAction *m_HSLAction; + TDEAction *m_RGBAction; + TDEAction *m_autoCorrectionAction; + TDEAction *m_invertAction; + TDEAction *m_BWAction; + TDEAction *m_aspectRatioCropAction; + TDEAction *m_sharpenAction; + TDEAction *m_blurAction; + TDEAction *m_colorManagementAction; + TDEAction *m_convertTo8Bits; + TDEAction *m_convertTo16Bits; +}; + +#endif /* IMAGEPLUGIN_CORE_H */ diff --git a/src/imageplugins/coreplugin/ratiocrop/Makefile.am b/src/imageplugins/coreplugin/ratiocrop/Makefile.am new file mode 100644 index 00000000..47ec5b58 --- /dev/null +++ b/src/imageplugins/coreplugin/ratiocrop/Makefile.am @@ -0,0 +1,26 @@ +noinst_LTLIBRARIES = libratiocrop.la +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +libratiocrop_la_SOURCES = ratiocroptool.cpp imageselectionwidget.cpp + +libratiocrop_la_LDFLAGS = $(all_libraries) + +noinst_HEADERS = ratiocroptool.h imageselectionwidget.h + diff --git a/src/imageplugins/coreplugin/ratiocrop/imageeffect_ratiocrop.cpp b/src/imageplugins/coreplugin/ratiocrop/imageeffect_ratiocrop.cpp new file mode 100644 index 00000000..64bc7a8e --- /dev/null +++ b/src/imageplugins/coreplugin/ratiocrop/imageeffect_ratiocrop.cpp @@ -0,0 +1,799 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-06 + * Description : digiKam image editor Ratio Crop tool + * + * Copyright (C) 2007 by Jaromir Malenko <malenko at email dot cz> + * Copyright (C) 2008 by Roberto Castagnola <roberto dot castagnola at gmail dot com> + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqlayout.h> +#include <tqframe.h> +#include <tqrect.h> +#include <tqvgroupbox.h> +#include <tqlabel.h> +#include <tqwhatsthis.h> +#include <tqcombobox.h> +#include <tqspinbox.h> +#include <tqimage.h> +#include <tqpushbutton.h> +#include <tqtimer.h> +#include <tqcheckbox.h> + +// KDE includes. + +#include <kcursor.h> +#include <tdelocale.h> +#include <knuminput.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <kstandarddirs.h> +#include <kcolorbutton.h> + +// Digikam includes. + +#include "imageiface.h" +#include "imageselectionwidget.h" + +// Local includes. + +#include "imageeffect_ratiocrop.h" +#include "imageeffect_ratiocrop.moc" + +namespace DigikamImagesPluginCore +{ + +ImageEffect_RatioCrop::ImageEffect_RatioCrop(TQWidget* parent) + : Digikam::ImageDlgBase(parent, i18n("Aspect Ratio Crop & Composition Guide"), + "aspectratiocrop", false) +{ + setHelp("ratiocroptool.anchor", "digikam"); + setButtonWhatsThis ( User1, i18n("<p>Set selection area to the maximum size according " + "to the current ratio.") ); + setButtonText(User1, i18n("&Max. Aspect")); + showButton(User1, true); + + // ------------------------------------------------------------- + + TQFrame *frame = new TQFrame(plainPage()); + frame->setFrameStyle(TQFrame::Panel|TQFrame::Sunken); + TQVBoxLayout* l = new TQVBoxLayout(frame, 5, 0); + m_imageSelectionWidget = new ImageSelectionWidget(480, 320, frame); + l->addWidget(m_imageSelectionWidget); + TQWhatsThis::add( m_imageSelectionWidget, i18n("<p>Here you can see the aspect ratio selection preview " + "used for cropping. You can use the mouse to move and " + "resize the crop area. " + "Press and hold the CTRL key to move the opposite corner too. " + "Press and hold the SHIFT key to move the closest corner to the " + "mouse pointer.")); + setPreviewAreaWidget(frame); + + m_originalIsLandscape = m_imageSelectionWidget->getOriginalImageWidth() > + m_imageSelectionWidget->getOriginalImageHeight(); + + // ------------------------------------------------------------- + + TQWidget *gbox2 = new TQWidget(plainPage()); + TQGridLayout *gridBox2 = new TQGridLayout( gbox2, 2, 0); + + TQFrame *cropSelection = new TQFrame( gbox2 ); + cropSelection->setFrameStyle(TQFrame::Panel|TQFrame::Sunken); + TQGridLayout* grid = new TQGridLayout( cropSelection, 6, 4, spacingHint()); + + TQLabel *label = new TQLabel(i18n("Aspect ratio:"), cropSelection); + m_ratioCB = new TQComboBox( false, cropSelection ); + setRatioCBText(ImageSelectionWidget::Landscape); + TQWhatsThis::add( m_ratioCB, i18n("<p>Select your constrained aspect ratio for cropping. " + "Aspect Ratio Crop tool uses a relative ratio. That means it " + "is the same if you use centimeters or inches and it doesn't " + "specify the physical size.<p>" + "You can see below a correspondence list of traditional photographic " + "paper sizes and aspect ratio crop:<p>" + "<b>2:3</b>: 10x15cm, 20x30cm, 30x45cm, 4x6\", 8x12\", " + "12x18\", 16x24\", 20x30\"<p>" + "<b>3:4</b>: 6x8cm, 15x20cm, 18x24cm, 30x40cm, 3.75x5\", 4.5x6\", " + "6x8\", 7.5x10\", 9x12\"<p>" + "<b>4:5</b>: 20x25cm, 40x50cm, 8x10\", 16x20\"<p>" + "<b>5:7</b>: 15x21cm, 30x42cm, 5x7\"<p>" + "<b>7:10</b>: 21x30cm, 42x60cm, 3.5x5\"<p>" + "The <b>Golden Ratio</b> is 1:1.618. A composition following this rule " + "is considered visually harmonious but can be unadapted to print on " + "standard photographic paper.")); + + m_preciseCrop = new TQCheckBox(i18n("Exact"), cropSelection); + TQWhatsThis::add( m_preciseCrop, i18n("<p>Enable this option to force exact aspect ratio crop.")); + + m_orientLabel = new TQLabel(i18n("Orientation:"), cropSelection); + m_orientCB = new TQComboBox( false, cropSelection ); + m_orientCB->insertItem( i18n("Landscape") ); + m_orientCB->insertItem( i18n("Portrait") ); + TQWhatsThis::add( m_orientCB, i18n("<p>Select constrained aspect ratio orientation.")); + + m_autoOrientation = new TQCheckBox(i18n("Auto"), cropSelection); + TQWhatsThis::add( m_autoOrientation, i18n("<p>Enable this option to automatically set the orientation.")); + + grid->addMultiCellWidget(label, 0, 0, 0, 0); + grid->addMultiCellWidget(m_ratioCB, 0, 0, 1, 3); + grid->addMultiCellWidget(m_preciseCrop, 0, 0, 4, 4); + grid->addMultiCellWidget(m_orientLabel, 2, 2, 0, 0); + grid->addMultiCellWidget(m_orientCB, 2, 2, 1, 3); + grid->addMultiCellWidget(m_autoOrientation, 2, 2, 4, 4); + + // ------------------------------------------------------------- + + m_customLabel1 = new TQLabel(i18n("Custom ratio:"), cropSelection); + m_customLabel1->setAlignment(AlignLeft|AlignVCenter); + m_customRatioNInput = new KIntSpinBox(1, 10000, 1, 1, 10, cropSelection); + TQWhatsThis::add( m_customRatioNInput, i18n("<p>Set here the desired custom aspect numerator value.")); + m_customLabel2 = new TQLabel(" : ", cropSelection); + m_customLabel2->setAlignment(AlignCenter|AlignVCenter); + m_customRatioDInput = new KIntSpinBox(1, 10000, 1, 1, 10, cropSelection); + TQWhatsThis::add( m_customRatioDInput, i18n("<p>Set here the desired custom aspect denominator value.")); + + grid->addMultiCellWidget(m_customLabel1, 1, 1, 0, 0); + grid->addMultiCellWidget(m_customRatioNInput, 1, 1, 1, 1); + grid->addMultiCellWidget(m_customLabel2, 1, 1, 2, 2); + grid->addMultiCellWidget(m_customRatioDInput, 1, 1, 3, 3); + + // ------------------------------------------------------------- + + m_xInput = new KIntNumInput(cropSelection); + TQWhatsThis::add( m_xInput, i18n("<p>Set here the top left selection corner position for cropping.")); + m_xInput->setLabel(i18n("X:"), AlignLeft|AlignVCenter); + m_xInput->setRange(0, m_imageSelectionWidget->getOriginalImageWidth(), 1, true); + + m_widthInput = new KIntNumInput(cropSelection); + m_widthInput->setLabel(i18n("Width:"), AlignLeft|AlignVCenter); + TQWhatsThis::add( m_widthInput, i18n("<p>Set here the width selection for cropping.")); + m_widthInput->setRange(m_imageSelectionWidget->getMinWidthRange(), + m_imageSelectionWidget->getMaxWidthRange(), + m_imageSelectionWidget->getWidthStep(), true); + + m_centerWidth = new TQPushButton(cropSelection); + TDEGlobal::dirs()->addResourceType("centerwidth", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + TQString directory = TDEGlobal::dirs()->findResourceDir("centerwidth", "centerwidth.png"); + m_centerWidth->setPixmap( TQPixmap( directory + "centerwidth.png" ) ); + TQWhatsThis::add( m_centerWidth, i18n("<p>Set width position to center.")); + + grid->addMultiCellWidget(m_xInput, 3, 3, 0, 3); + grid->addMultiCellWidget(m_widthInput, 4, 4, 0, 3); + grid->addMultiCellWidget(m_centerWidth, 3, 3, 4, 4); + + // ------------------------------------------------------------- + + m_yInput = new KIntNumInput(cropSelection); + m_yInput->setLabel(i18n("Y:"), AlignLeft|AlignVCenter); + TQWhatsThis::add( m_yInput, i18n("<p>Set here the top left selection corner position for cropping.")); + m_yInput->setRange(0, m_imageSelectionWidget->getOriginalImageHeight(), 1, true); + + m_heightInput = new KIntNumInput(cropSelection); + m_heightInput->setLabel(i18n("Height:"), AlignLeft|AlignVCenter); + TQWhatsThis::add( m_heightInput, i18n("<p>Set here the height selection for cropping.")); + m_heightInput->setRange(m_imageSelectionWidget->getMinHeightRange(), + m_imageSelectionWidget->getMaxHeightRange(), + m_imageSelectionWidget->getHeightStep(), true); + + m_centerHeight = new TQPushButton(cropSelection); + TDEGlobal::dirs()->addResourceType("centerheight", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("centerheight", "centerheight.png"); + m_centerHeight->setPixmap( TQPixmap( directory + "centerheight.png" ) ); + TQWhatsThis::add( m_centerHeight, i18n("<p>Set height position to center.")); + + grid->addMultiCellWidget(m_yInput, 5, 5, 0, 3); + grid->addMultiCellWidget(m_heightInput, 6, 6, 0, 3); + grid->addMultiCellWidget(m_centerHeight, 5, 5, 4, 4); + + gridBox2->addMultiCellWidget(cropSelection, 0, 0, 0, 0); + + // ------------------------------------------------------------- + + TQFrame* compositionGuide = new TQFrame( gbox2 ); + TQGridLayout* grid2 = new TQGridLayout( compositionGuide, 7, 2, spacingHint()); + compositionGuide->setFrameStyle(TQFrame::Panel|TQFrame::Sunken); + + TQLabel *labelGuideLines = new TQLabel(i18n("Composition guide:"), compositionGuide); + m_guideLinesCB = new TQComboBox( false, compositionGuide ); + m_guideLinesCB->insertItem( i18n("Rules of Thirds") ); + m_guideLinesCB->insertItem( i18n("Harmonious Triangles") ); + m_guideLinesCB->insertItem( i18n("Golden Mean") ); + m_guideLinesCB->insertItem( i18n("None") ); + m_guideLinesCB->setCurrentText( i18n("None") ); + TQWhatsThis::add( m_guideLinesCB, i18n("<p>With this option, you can display guide lines " + "which help you to compose your photograph.")); + + m_goldenSectionBox = new TQCheckBox(i18n("Golden sections"), compositionGuide); + TQWhatsThis::add( m_goldenSectionBox, i18n("<p>Enable this option to show golden sections.")); + + m_goldenSpiralSectionBox = new TQCheckBox(i18n("Golden spiral sections"), compositionGuide); + TQWhatsThis::add( m_goldenSpiralSectionBox, i18n("<p>Enable this option to show golden spiral sections.")); + + m_goldenSpiralBox = new TQCheckBox(i18n("Golden spiral"), compositionGuide); + TQWhatsThis::add( m_goldenSpiralBox, i18n("<p>Enable this option to show golden spiral guide.")); + + m_goldenTriangleBox = new TQCheckBox(i18n("Golden triangles"), compositionGuide); + TQWhatsThis::add( m_goldenTriangleBox, i18n("<p>Enable this option to show golden triangles.")); + + m_flipHorBox = new TQCheckBox(i18n("Flip horizontally"), compositionGuide); + TQWhatsThis::add( m_flipHorBox, i18n("<p>Enable this option to flip horizontally guidelines.")); + + m_flipVerBox = new TQCheckBox(i18n("Flip vertically"), compositionGuide); + TQWhatsThis::add( m_flipVerBox, i18n("<p>Enable this option to flip vertically guidelines.")); + + m_colorGuideLabel = new TQLabel(i18n("Color and width:"), compositionGuide); + m_guideColorBt = new KColorButton( TQColor( 250, 250, 255 ), compositionGuide ); + m_guideSize = new TQSpinBox( 1, 5, 1, compositionGuide); + TQWhatsThis::add( m_guideColorBt, i18n("<p>Set here the color used to draw composition guides.")); + TQWhatsThis::add( m_guideSize, i18n("<p>Set here the width in pixels used to draw composition guides.")); + + grid2->addMultiCellWidget(labelGuideLines, 0, 0, 0, 0); + grid2->addMultiCellWidget(m_guideLinesCB, 0, 0, 1, 2); + grid2->addMultiCellWidget(m_goldenSectionBox, 1, 1, 0, 2); + grid2->addMultiCellWidget(m_goldenSpiralSectionBox, 2, 2, 0, 2); + grid2->addMultiCellWidget(m_goldenSpiralBox, 3, 3, 0, 2); + grid2->addMultiCellWidget(m_goldenTriangleBox, 4, 4, 0, 2); + grid2->addMultiCellWidget(m_flipHorBox, 5, 5, 0, 2); + grid2->addMultiCellWidget(m_flipVerBox, 6, 6, 0, 2); + grid2->addMultiCellWidget(m_colorGuideLabel, 7, 7, 0, 0); + grid2->addMultiCellWidget(m_guideColorBt, 7, 7, 1, 1); + grid2->addMultiCellWidget(m_guideSize, 7, 7, 2, 2); + + gridBox2->addMultiCellWidget(compositionGuide, 1, 1, 0, 0); + gridBox2->setRowStretch(2, 10); + + setUserAreaWidget(gbox2); + + // ------------------------------------------------------------- + + connect(m_ratioCB, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotRatioChanged(int))); + + connect(m_preciseCrop, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotPreciseCropChanged(bool))); + + connect(m_orientCB, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotOrientChanged(int))); + + connect(m_autoOrientation, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotAutoOrientChanged(bool))); + + connect(m_xInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotXChanged(int))); + + connect(m_yInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotYChanged(int))); + + connect(m_customRatioNInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotCustomNRatioChanged(int))); + + connect(m_customRatioDInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotCustomDRatioChanged(int))); + + connect(m_guideLinesCB, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotGuideTypeChanged(int))); + + connect(m_goldenSectionBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotGoldenGuideTypeChanged())); + + connect(m_goldenSpiralSectionBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotGoldenGuideTypeChanged())); + + connect(m_goldenSpiralBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotGoldenGuideTypeChanged())); + + connect(m_goldenTriangleBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotGoldenGuideTypeChanged())); + + connect(m_flipHorBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotGoldenGuideTypeChanged())); + + connect(m_flipVerBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotGoldenGuideTypeChanged())); + + connect(m_guideColorBt, TQ_SIGNAL(changed(const TQColor &)), + m_imageSelectionWidget, TQ_SLOT(slotChangeGuideColor(const TQColor &))); + + connect(m_guideSize, TQ_SIGNAL(valueChanged(int)), + m_imageSelectionWidget, TQ_SLOT(slotChangeGuideSize(int))); + + connect(m_widthInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotWidthChanged(int))); + + connect(m_heightInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotHeightChanged(int))); + + connect(m_imageSelectionWidget, TQ_SIGNAL(signalSelectionChanged(TQRect)), + this, TQ_SLOT(slotSelectionChanged(TQRect))); + + connect(m_imageSelectionWidget, TQ_SIGNAL(signalSelectionMoved(TQRect)), + this, TQ_SLOT(slotSelectionChanged(TQRect))); + + connect(m_imageSelectionWidget, TQ_SIGNAL(signalSelectionOrientationChanged(int)), + this, TQ_SLOT(slotSelectionOrientationChanged(int))); + + connect(m_centerWidth, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotCenterWidth())); + + connect(m_centerHeight, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotCenterHeight())); + + // ------------------------------------------------------------- + + // Sets current region selection + slotSelectionChanged(m_imageSelectionWidget->getRegionSelection()); + + readSettings(); +} + +ImageEffect_RatioCrop::~ImageEffect_RatioCrop() +{ +} + +void ImageEffect_RatioCrop::readSettings() +{ + TQColor defaultGuideColor(250, 250, 255); + TDEConfig *config = kapp->config(); + config->setGroup("aspectratiocrop Tool Dialog"); + + // No guide lines per default. + m_guideLinesCB->setCurrentItem( config->readNumEntry("Guide Lines Type", + ImageSelectionWidget::GuideNone) ); + m_goldenSectionBox->setChecked( config->readBoolEntry("Golden Section", true) ); + m_goldenSpiralSectionBox->setChecked( config->readBoolEntry("Golden Spiral Section", false) ); + m_goldenSpiralBox->setChecked( config->readBoolEntry("Golden Spiral", false) ); + m_goldenTriangleBox->setChecked( config->readBoolEntry("Golden Triangle", false) ); + m_flipHorBox->setChecked( config->readBoolEntry("Golden Flip Horizontal", false) ); + m_flipVerBox->setChecked( config->readBoolEntry("Golden Flip Vertical", false) ); + m_guideColorBt->setColor(config->readColorEntry("Guide Color", &defaultGuideColor)); + m_guideSize->setValue(config->readNumEntry("Guide Width", 1)); + m_imageSelectionWidget->slotGuideLines(m_guideLinesCB->currentItem()); + m_imageSelectionWidget->slotChangeGuideColor(m_guideColorBt->color()); + + m_preciseCrop->setChecked( config->readBoolEntry("Precise Aspect Ratio Crop", false) ); + m_imageSelectionWidget->setPreciseCrop( m_preciseCrop->isChecked() ); + + if (m_originalIsLandscape) + { + m_orientCB->setCurrentItem( config->readNumEntry("Hor.Oriented Aspect Ratio Orientation", + ImageSelectionWidget::Landscape) ); + + m_imageSelectionWidget->setSelectionOrientation(m_orientCB->currentItem()); + + m_customRatioNInput->setValue( config->readNumEntry("Hor.Oriented Custom Aspect Ratio Num", 1) ); + m_customRatioDInput->setValue( config->readNumEntry("Hor.Oriented Custom Aspect Ratio Den", 1) ); + m_ratioCB->setCurrentItem( config->readNumEntry("Hor.Oriented Aspect Ratio", + ImageSelectionWidget::RATIO03X04) ); + + applyRatioChanges(m_ratioCB->currentItem()); + + // Empty selection so it can be moved w/out size constraint + m_widthInput->setValue( 0 ); + m_heightInput->setValue( 0 ); + + m_xInput->setValue( config->readNumEntry("Hor.Oriented Custom Aspect Ratio Xpos", 50) ); + m_yInput->setValue( config->readNumEntry("Hor.Oriented Custom Aspect Ratio Ypos", 50) ); + + m_widthInput->setValue( config->readNumEntry("Hor.Oriented Custom Aspect Ratio Width", 800) ); + m_heightInput->setValue( config->readNumEntry("Hor.Oriented Custom Aspect Ratio Height", 600) ); + } + else + { + m_orientCB->setCurrentItem( config->readNumEntry("Ver.Oriented Aspect Ratio Orientation", + ImageSelectionWidget::Portrait) ); + + m_imageSelectionWidget->setSelectionOrientation(m_orientCB->currentItem()); + + m_customRatioNInput->setValue( config->readNumEntry("Ver.Oriented Custom Aspect Ratio Num", 1) ); + m_customRatioDInput->setValue( config->readNumEntry("Ver.Oriented Custom Aspect Ratio Den", 1) ); + m_ratioCB->setCurrentItem( config->readNumEntry("Ver.Oriented Aspect Ratio", + ImageSelectionWidget::RATIO03X04) ); + + applyRatioChanges(m_ratioCB->currentItem()); + + // Empty selection so it can be moved w/out size constraint + m_widthInput->setValue( 0 ); + m_heightInput->setValue( 0 ); + + m_xInput->setValue( config->readNumEntry("Ver.Oriented Custom Aspect Ratio Xpos", 50) ); + m_yInput->setValue( config->readNumEntry("Ver.Oriented Custom Aspect Ratio Ypos", 50) ); + + m_widthInput->setValue( config->readNumEntry("Ver.Oriented Custom Aspect Ratio Width", 800) ); + m_heightInput->setValue( config->readNumEntry("Ver.Oriented Custom Aspect Ratio Height", 600) ); + } + + m_autoOrientation->setChecked( config->readBoolEntry("Auto Orientation", false) ); + slotAutoOrientChanged( m_autoOrientation->isChecked() ); +} + +void ImageEffect_RatioCrop::writeSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("aspectratiocrop Tool Dialog"); + + if (m_originalIsLandscape) + { + config->writeEntry( "Hor.Oriented Aspect Ratio", m_ratioCB->currentItem() ); + config->writeEntry( "Hor.Oriented Aspect Ratio Orientation", m_orientCB->currentItem() ); + config->writeEntry( "Hor.Oriented Custom Aspect Ratio Num", m_customRatioNInput->value() ); + config->writeEntry( "Hor.Oriented Custom Aspect Ratio Den", m_customRatioDInput->value() ); + + config->writeEntry( "Hor.Oriented Custom Aspect Ratio Xpos", m_xInput->value() ); + config->writeEntry( "Hor.Oriented Custom Aspect Ratio Ypos", m_yInput->value() ); + config->writeEntry( "Hor.Oriented Custom Aspect Ratio Width", m_widthInput->value() ); + config->writeEntry( "Hor.Oriented Custom Aspect Ratio Height", m_heightInput->value() ); + } + else + { + config->writeEntry( "Ver.Oriented Aspect Ratio", m_ratioCB->currentItem() ); + config->writeEntry( "Ver.Oriented Aspect Ratio Orientation", m_orientCB->currentItem() ); + config->writeEntry( "Ver.Oriented Custom Aspect Ratio Num", m_customRatioNInput->value() ); + config->writeEntry( "Ver.Oriented Custom Aspect Ratio Den", m_customRatioDInput->value() ); + + config->writeEntry( "Ver.Oriented Custom Aspect Ratio Xpos", m_xInput->value() ); + config->writeEntry( "Ver.Oriented Custom Aspect Ratio Ypos", m_yInput->value() ); + config->writeEntry( "Ver.Oriented Custom Aspect Ratio Width", m_widthInput->value() ); + config->writeEntry( "Ver.Oriented Custom Aspect Ratio Height", m_heightInput->value() ); + } + + config->writeEntry( "Precise Aspect Ratio Crop", m_preciseCrop->isChecked() ); + config->writeEntry( "Auto Orientation", m_autoOrientation->isChecked() ); + config->writeEntry( "Guide Lines Type", m_guideLinesCB->currentItem() ); + config->writeEntry( "Golden Section", m_goldenSectionBox->isChecked() ); + config->writeEntry( "Golden Spiral Section", m_goldenSpiralSectionBox->isChecked() ); + config->writeEntry( "Golden Spiral", m_goldenSpiralBox->isChecked() ); + config->writeEntry( "Golden Triangle", m_goldenTriangleBox->isChecked() ); + config->writeEntry( "Golden Flip Horizontal", m_flipHorBox->isChecked() ); + config->writeEntry( "Golden Flip Vertical", m_flipVerBox->isChecked() ); + config->writeEntry( "Guide Color", m_guideColorBt->color() ); + config->writeEntry( "Guide Width", m_guideSize->value() ); + config->sync(); +} + +void ImageEffect_RatioCrop::slotDefault() +{ + m_imageSelectionWidget->resetSelection(); +} + +void ImageEffect_RatioCrop::slotUser1() +{ + m_imageSelectionWidget->maxAspectSelection(); +} + +void ImageEffect_RatioCrop::slotCenterWidth() +{ + m_imageSelectionWidget->setCenterSelection(ImageSelectionWidget::CenterWidth); +} + +void ImageEffect_RatioCrop::slotCenterHeight() +{ + m_imageSelectionWidget->setCenterSelection(ImageSelectionWidget::CenterHeight); +} + +void ImageEffect_RatioCrop::slotSelectionChanged(TQRect rect) +{ + m_xInput->blockSignals(true); + m_yInput->blockSignals(true); + m_widthInput->blockSignals(true); + m_heightInput->blockSignals(true); + + m_xInput->setRange(0, m_imageSelectionWidget->getOriginalImageWidth() - rect.width(), 1, true); + m_yInput->setRange(0, m_imageSelectionWidget->getOriginalImageHeight() - rect.height(), 1, true); + m_widthInput->setRange(m_imageSelectionWidget->getMinWidthRange(), + m_imageSelectionWidget->getMaxWidthRange(), + m_imageSelectionWidget->getWidthStep(), true); + m_heightInput->setRange(m_imageSelectionWidget->getMinHeightRange(), + m_imageSelectionWidget->getMaxHeightRange(), + m_imageSelectionWidget->getHeightStep(), true); + + m_xInput->setValue(rect.x()); + m_yInput->setValue(rect.y()); + m_widthInput->setValue(rect.width()); + m_heightInput->setValue(rect.height()); + + enableButtonOK( rect.isValid() ); + m_preciseCrop->setEnabled(m_imageSelectionWidget->preciseCropAvailable()); + + m_xInput->blockSignals(false); + m_yInput->blockSignals(false); + m_widthInput->blockSignals(false); + m_heightInput->blockSignals(false); +} + +void ImageEffect_RatioCrop::setRatioCBText(int orientation) +{ + int item = m_ratioCB->currentItem(); + + m_ratioCB->blockSignals(true); + m_ratioCB->clear(); + m_ratioCB->insertItem( i18n("Custom") ); + m_ratioCB->insertItem( "1:1" ); + if ( orientation == ImageSelectionWidget::Landscape ) + { + m_ratioCB->insertItem( "3:2" ); + m_ratioCB->insertItem( "4:3" ); + m_ratioCB->insertItem( "5:4" ); + m_ratioCB->insertItem( "7:5" ); + m_ratioCB->insertItem( "10:7" ); + } + else + { + m_ratioCB->insertItem( "2:3" ); + m_ratioCB->insertItem( "3:4" ); + m_ratioCB->insertItem( "4:5" ); + m_ratioCB->insertItem( "5:7" ); + m_ratioCB->insertItem( "7:10" ); + } + m_ratioCB->insertItem( i18n("Golden Ratio") ); + m_ratioCB->insertItem( i18n("None") ); + m_ratioCB->setCurrentItem( item ); + m_ratioCB->blockSignals(false); +} + +void ImageEffect_RatioCrop::slotSelectionOrientationChanged(int newOrientation) +{ + // Change text for Aspect ratio ComboBox + + setRatioCBText(newOrientation); + + // Change Orientation ComboBox + + m_orientCB->setCurrentItem(newOrientation); + + // Reverse custom values + + if ( ( m_customRatioNInput->value() < m_customRatioDInput->value() && + newOrientation == ImageSelectionWidget::Landscape ) || + ( m_customRatioNInput->value() > m_customRatioDInput->value() && + newOrientation == ImageSelectionWidget::Portrait ) ) + { + m_customRatioNInput->blockSignals(true); + m_customRatioDInput->blockSignals(true); + + int tmp = m_customRatioNInput->value(); + m_customRatioNInput->setValue( m_customRatioDInput->value() ); + m_customRatioDInput->setValue( tmp ); + + m_customRatioNInput->blockSignals(false); + m_customRatioDInput->blockSignals(false); + } +} + +void ImageEffect_RatioCrop::slotXChanged(int x) +{ + m_imageSelectionWidget->setSelectionX(x); +} + +void ImageEffect_RatioCrop::slotYChanged(int y) +{ + m_imageSelectionWidget->setSelectionY(y); +} + +void ImageEffect_RatioCrop::slotWidthChanged(int w) +{ + m_imageSelectionWidget->setSelectionWidth(w); +} + +void ImageEffect_RatioCrop::slotHeightChanged(int h) +{ + m_imageSelectionWidget->setSelectionHeight(h); +} + +void ImageEffect_RatioCrop::slotPreciseCropChanged(bool a) +{ + m_imageSelectionWidget->setPreciseCrop(a); +} + +void ImageEffect_RatioCrop::slotOrientChanged(int o) +{ + m_imageSelectionWidget->setSelectionOrientation(o); + + // Reset selection area. + slotDefault(); +} + +void ImageEffect_RatioCrop::slotAutoOrientChanged(bool a) +{ + m_orientCB->setEnabled(!a /*|| m_ratioCB->currentItem() == ImageSelectionWidget::RATIONONE*/); + m_imageSelectionWidget->setAutoOrientation(a); +} + +void ImageEffect_RatioCrop::slotRatioChanged(int a) +{ + applyRatioChanges(a); + + // Reset selection area. + slotDefault(); +} + +void ImageEffect_RatioCrop::applyRatioChanges(int a) +{ + m_imageSelectionWidget->setSelectionAspectRatioType(a); + + if ( a == ImageSelectionWidget::RATIOCUSTOM ) + { + m_customLabel1->setEnabled(true); + m_customLabel2->setEnabled(true); + m_customRatioNInput->setEnabled(true); + m_customRatioDInput->setEnabled(true); + m_orientLabel->setEnabled(true); + m_orientCB->setEnabled(! m_autoOrientation->isChecked()); + m_autoOrientation->setEnabled(true); + slotCustomRatioChanged(); + } + else if ( a == ImageSelectionWidget::RATIONONE ) + { + m_orientLabel->setEnabled(false); + m_orientCB->setEnabled(false); + m_autoOrientation->setEnabled(false); + m_customLabel1->setEnabled(false); + m_customLabel2->setEnabled(false); + m_customRatioNInput->setEnabled(false); + m_customRatioDInput->setEnabled(false); + } + else // Pre-config ratio selected. + { + m_orientLabel->setEnabled(true); + m_orientCB->setEnabled(! m_autoOrientation->isChecked()); + m_autoOrientation->setEnabled(true); + m_customLabel1->setEnabled(false); + m_customLabel2->setEnabled(false); + m_customRatioNInput->setEnabled(false); + m_customRatioDInput->setEnabled(false); + } +} + +void ImageEffect_RatioCrop::slotGuideTypeChanged(int t) +{ + if ( t == ImageSelectionWidget::GuideNone ) + { + m_goldenSectionBox->setEnabled(false); + m_goldenSpiralSectionBox->setEnabled(false); + m_goldenSpiralBox->setEnabled(false); + m_goldenTriangleBox->setEnabled(false); + m_flipHorBox->setEnabled(false); + m_flipVerBox->setEnabled(false); + m_colorGuideLabel->setEnabled(false); + m_guideColorBt->setEnabled(false); + m_guideSize->setEnabled(false); + } + else if ( t == ImageSelectionWidget::RulesOfThirds ) + { + m_goldenSectionBox->setEnabled(false); + m_goldenSpiralSectionBox->setEnabled(false); + m_goldenSpiralBox->setEnabled(false); + m_goldenTriangleBox->setEnabled(false); + m_flipHorBox->setEnabled(false); + m_flipVerBox->setEnabled(false); + m_colorGuideLabel->setEnabled(true); + m_guideColorBt->setEnabled(true); + m_guideSize->setEnabled(true); + } + else if ( t == ImageSelectionWidget::HarmoniousTriangles ) + { + m_goldenSectionBox->setEnabled(false); + m_goldenSpiralSectionBox->setEnabled(false); + m_goldenSpiralBox->setEnabled(false); + m_goldenTriangleBox->setEnabled(false); + m_flipHorBox->setEnabled(true); + m_flipVerBox->setEnabled(true); + m_colorGuideLabel->setEnabled(true); + m_guideColorBt->setEnabled(true); + m_guideSize->setEnabled(true); + } + else + { + m_goldenSectionBox->setEnabled(true); + m_goldenSpiralSectionBox->setEnabled(true); + m_goldenSpiralBox->setEnabled(true); + m_goldenTriangleBox->setEnabled(true); + m_flipHorBox->setEnabled(true); + m_flipVerBox->setEnabled(true); + m_colorGuideLabel->setEnabled(true); + m_guideColorBt->setEnabled(true); + m_guideSize->setEnabled(true); + } + + m_imageSelectionWidget->setGoldenGuideTypes(m_goldenSectionBox->isChecked(), + m_goldenSpiralSectionBox->isChecked(), + m_goldenSpiralBox->isChecked(), + m_goldenTriangleBox->isChecked(), + m_flipHorBox->isChecked(), + m_flipVerBox->isChecked()); + m_imageSelectionWidget->slotGuideLines(t); +} + +void ImageEffect_RatioCrop::slotGoldenGuideTypeChanged() +{ + slotGuideTypeChanged(m_guideLinesCB->currentItem()); +} + +void ImageEffect_RatioCrop::slotCustomNRatioChanged(int a) +{ + if ( ! m_autoOrientation->isChecked() ) + { + if ( ( m_orientCB->currentItem() == ImageSelectionWidget::Portrait && + m_customRatioDInput->value() < a ) || + ( m_orientCB->currentItem() == ImageSelectionWidget::Landscape && + m_customRatioDInput->value() > a ) ) + { + m_customRatioDInput->blockSignals(true); + m_customRatioDInput->setValue(a); + m_customRatioDInput->blockSignals(false); + } + } + + slotCustomRatioChanged(); +} + +void ImageEffect_RatioCrop::slotCustomDRatioChanged(int a) +{ + if ( ! m_autoOrientation->isChecked() ) + { + if ( ( m_orientCB->currentItem() == ImageSelectionWidget::Landscape && + m_customRatioNInput->value() < a ) || + ( m_orientCB->currentItem() == ImageSelectionWidget::Portrait && + m_customRatioNInput->value() > a ) ) + { + m_customRatioNInput->blockSignals(true); + m_customRatioNInput->setValue(a); + m_customRatioNInput->blockSignals(false); + } + } + + slotCustomRatioChanged(); +} + +void ImageEffect_RatioCrop::slotCustomRatioChanged() +{ + m_imageSelectionWidget->setSelectionAspectRatioValue( + m_customRatioNInput->value(), m_customRatioDInput->value() ); + + // Reset selection area. + slotDefault(); +} + +void ImageEffect_RatioCrop::slotOk() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + + TQRect currentRegion = m_imageSelectionWidget->getRegionSelection(); + Digikam::ImageIface* iface = m_imageSelectionWidget->imageIface(); + uchar *data = iface->getOriginalImage(); + int w = iface->originalWidth(); + int h = iface->originalHeight(); + bool a = iface->originalHasAlpha(); + bool sb = iface->originalSixteenBit(); + + TQRect normalizedRegion = currentRegion.normalize(); + if (normalizedRegion.right() > w) normalizedRegion.setRight(w); + if (normalizedRegion.bottom() > h) normalizedRegion.setBottom(h); + + Digikam::DImg imOrg(w, h, sb, a, data); + delete [] data; + imOrg.crop(normalizedRegion); + + iface->putOriginalImage(i18n("Aspect Ratio Crop"), imOrg.bits(), imOrg.width(), imOrg.height()); + + kapp->restoreOverrideCursor(); + writeSettings(); + accept(); +} + +} // NameSpace DigikamImagesPluginCore diff --git a/src/imageplugins/coreplugin/ratiocrop/imageeffect_ratiocrop.h b/src/imageplugins/coreplugin/ratiocrop/imageeffect_ratiocrop.h new file mode 100644 index 00000000..ca24eeac --- /dev/null +++ b/src/imageplugins/coreplugin/ratiocrop/imageeffect_ratiocrop.h @@ -0,0 +1,132 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-06 + * Description : digiKam image editor Ratio Crop tool + * + * Copyright (C) 2007 by Jaromir Malenko <malenko at email dot cz> + * Copyright (C) 2008 by Roberto Castagnola <roberto dot castagnola at gmail dot com> + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_RATIOCROP_H +#define IMAGEEFFECT_RATIOCROP_H + +// Digikam include. + +#include "imagedlgbase.h" + +class TQLabel; +class TQComboBox; +class TQPushButton; +class TQCheckBox; +class TQSpinBox; + +class KIntNumInput; +class KIntSpinBox; +class KColorButton; + +namespace DigikamImagesPluginCore +{ + +class ImageSelectionWidget; + +class ImageEffect_RatioCrop : public Digikam::ImageDlgBase +{ + TQ_OBJECT + + +public: + + ImageEffect_RatioCrop(TQWidget *parent); + ~ImageEffect_RatioCrop(); + +private: + + void readSettings(); + void writeSettings(); + + void applyRatioChanges(int a); + void setRatioCBText(int orientation); + +private slots: + + void slotUser1(); + void slotDefault(); + void slotOk(); + + void slotCenterWidth(); + void slotCenterHeight(); + void slotXChanged(int x); + void slotYChanged(int y); + void slotWidthChanged(int w); + void slotHeightChanged(int h); + void slotCustomRatioChanged(); + void slotCustomNRatioChanged(int a); + void slotCustomDRatioChanged(int a); + void slotPreciseCropChanged(bool a); + void slotOrientChanged(int o); + void slotAutoOrientChanged(bool a); + void slotRatioChanged(int a); + void slotSelectionChanged(TQRect rect ); + void slotSelectionOrientationChanged(int); + void slotGuideTypeChanged(int t); + void slotGoldenGuideTypeChanged(); + +private: + + bool m_originalIsLandscape; + + TQLabel *m_customLabel1; + TQLabel *m_customLabel2; + TQLabel *m_orientLabel; + TQLabel *m_colorGuideLabel; + + TQComboBox *m_ratioCB; + TQComboBox *m_orientCB; + TQComboBox *m_guideLinesCB; + + TQPushButton *m_centerWidth; + TQPushButton *m_centerHeight; + + TQCheckBox *m_goldenSectionBox; + TQCheckBox *m_goldenSpiralSectionBox; + TQCheckBox *m_goldenSpiralBox; + TQCheckBox *m_goldenTriangleBox; + TQCheckBox *m_flipHorBox; + TQCheckBox *m_flipVerBox; + TQCheckBox *m_autoOrientation; + TQCheckBox *m_preciseCrop; + + TQSpinBox *m_guideSize; + + KIntNumInput *m_widthInput; + KIntNumInput *m_heightInput; + KIntNumInput *m_xInput; + KIntNumInput *m_yInput; + + KIntSpinBox *m_customRatioNInput; + KIntSpinBox *m_customRatioDInput; + + KColorButton *m_guideColorBt; + + ImageSelectionWidget *m_imageSelectionWidget; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* IMAGEEFFECT_RATIOCROP_H */ diff --git a/src/imageplugins/coreplugin/ratiocrop/imageselectionwidget.cpp b/src/imageplugins/coreplugin/ratiocrop/imageselectionwidget.cpp new file mode 100644 index 00000000..17eaf415 --- /dev/null +++ b/src/imageplugins/coreplugin/ratiocrop/imageselectionwidget.cpp @@ -0,0 +1,1422 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-09 + * Description : image selection widget used by ratio crop tool. + * + * Copyright (C) 2007 by Jaromir Malenko <malenko at email.cz> + * Copyright (C) 2008 by Roberto Castagnola <roberto dot castagnola at gmail dot com> + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#define OPACITY 0.7 +#define RCOL 0xAA +#define GCOL 0xAA +#define BCOL 0xAA + +#define MINRANGE 0 + +// Golden number (1+sqrt(5))/2 +#define PHI 1.61803398874989479 +// 1/PHI +#define INVPHI 0.61803398874989479 + +// C++ includes. + +#include <iostream> +#include <cstdio> +#include <cmath> +#include <cstdlib> + +// TQt includes. + +#include <tqregion.h> +#include <tqcolor.h> +#include <tqpainter.h> +#include <tqbrush.h> +#include <tqpixmap.h> +#include <tqimage.h> +#include <tqpen.h> +#include <tqpoint.h> +#include <tqtimer.h> +#include <tqsizepolicy.h> + +// KDE includes. + +#include <kstandarddirs.h> +#include <kcursor.h> +#include <tdeglobal.h> + +// Local includes. + +#include "ddebug.h" +#include "imageiface.h" +#include "dimg.h" +#include "imageselectionwidget.h" +#include "imageselectionwidget.moc" + +namespace DigikamImagesPluginCore +{ + +class ImageSelectionWidgetPriv +{ +public: + + enum ResizingMode + { + ResizingNone = 0, + ResizingTopLeft, + ResizingTopRight, + ResizingBottomLeft, + ResizingBottomRight + }; + + ImageSelectionWidgetPriv() + { + currentResizing = ResizingNone; + iface = 0; + pixmap = 0; + guideSize = 1; + } + + // Golden guide types. + bool drawGoldenSection; + bool drawGoldenSpiralSection; + bool drawGoldenSpiral; + bool drawGoldenTriangle; + + // Golden guide translations. + bool flipHorGoldenGuide; + bool flipVerGoldenGuide; + + bool moving; + bool autoOrientation; + bool preciseCrop; + + int guideLinesType; + int guideSize; + + int currentAspectRatioType; + int currentResizing; + int currentOrientation; + + float currentWidthRatioValue; + float currentHeightRatioValue; + + TQPoint lastPos; + + TQRect rect; + TQRect image; // Real image dimension. + TQRect regionSelection; // Real size image selection. + TQRect localRegionSelection; // Local size selection. + + // Draggable local region selection corners. + TQRect localTopLeftCorner; + TQRect localBottomLeftCorner; + TQRect localTopRightCorner; + TQRect localBottomRightCorner; + + TQPixmap *pixmap; + + TQColor guideColor; + + Digikam::DImg preview; + + Digikam::ImageIface *iface; +}; + +ImageSelectionWidget::ImageSelectionWidget(int w, int h, TQWidget *parent, + int widthRatioValue, int heightRatioValue, + int aspectRatioType, int orient, int guideLinesType) + : TQWidget(parent, 0, TQt::WDestructiveClose) +{ + d = new ImageSelectionWidgetPriv; + d->currentAspectRatioType = aspectRatioType; + d->currentWidthRatioValue = widthRatioValue; + d->currentHeightRatioValue = heightRatioValue; + d->currentOrientation = orient; + d->guideLinesType = guideLinesType; + d->autoOrientation = false; + d->preciseCrop = false; + d->moving = true; + reverseRatioValues(); + + setBackgroundMode(TQt::NoBackground); + setMinimumSize(w, h); + setMouseTracking(true); + + d->iface = new Digikam::ImageIface(w, h); + uchar *data = d->iface->getPreviewImage(); + int width = d->iface->previewWidth(); + int height = d->iface->previewHeight(); + bool sixteenBit = d->iface->previewSixteenBit(); + bool hasAlpha = d->iface->previewHasAlpha(); + d->preview = Digikam::DImg(width, height, sixteenBit, hasAlpha, data); + delete [] data; + d->preview.convertToEightBit(); + d->pixmap = new TQPixmap(w, h); + + d->image = TQRect(0, 0, d->iface->originalWidth(), d->iface->originalHeight()); + d->rect = TQRect(w/2-d->preview.width()/2, h/2-d->preview.height()/2, + d->preview.width(), d->preview.height()); + updatePixmap(); + setGoldenGuideTypes(true, false, false, false, false, false); +} + +ImageSelectionWidget::~ImageSelectionWidget() +{ + delete d->iface; + delete d->pixmap; + delete d; +} + +Digikam::ImageIface* ImageSelectionWidget::imageIface() +{ + return d->iface; +} + +void ImageSelectionWidget::resizeEvent(TQResizeEvent *e) +{ + delete d->pixmap; + + int w = e->size().width(); + int h = e->size().height(); + + uchar *data = d->iface->setPreviewImageSize(w, h); + int width = d->iface->previewWidth(); + int height = d->iface->previewHeight(); + bool sixteenBit = d->iface->previewSixteenBit(); + bool hasAlpha = d->iface->previewHasAlpha(); + d->preview = Digikam::DImg(width, height, sixteenBit, hasAlpha, data); + delete [] data; + d->preview.convertToEightBit(); + + d->pixmap = new TQPixmap(w, h); + + d->rect = TQRect(w/2-d->preview.width()/2, h/2-d->preview.height()/2, + d->preview.width(), d->preview.height()); + updatePixmap(); +} + +int ImageSelectionWidget::getOriginalImageWidth() +{ + return d->image.width(); +} + +int ImageSelectionWidget::getOriginalImageHeight() +{ + return d->image.height(); +} + +TQRect ImageSelectionWidget::getRegionSelection() +{ + return d->regionSelection; +} + +int ImageSelectionWidget::getMinWidthRange() +{ + return MINRANGE; +} + +int ImageSelectionWidget::getMinHeightRange() +{ + return MINRANGE; +} + +int ImageSelectionWidget::getMaxWidthRange() +{ + int maxW = d->image.width() - d->regionSelection.left(); + + if (d->currentAspectRatioType != RATIONONE) + { + // Compute max width taking aspect ratio into account + int t = d->currentWidthRatioValue > d->currentHeightRatioValue ? 1 : 0; + int h = d->image.height() - d->regionSelection.top(); + int w = rint( ( h + t ) * d->currentWidthRatioValue / + d->currentHeightRatioValue ) - t; + if ( w < maxW ) + maxW = w; + } + + // Return max width adjusted if a precise crop is wanted + return computePreciseSize(maxW, d->currentWidthRatioValue); +} + +int ImageSelectionWidget::getMaxHeightRange() +{ + int maxH = d->image.height() - d->regionSelection.top(); + + if (d->currentAspectRatioType != RATIONONE) + { + // Compute max height taking aspect ratio into account + int t = d->currentHeightRatioValue > d->currentWidthRatioValue ? 1 : 0; + int w = d->image.width() - d->regionSelection.left(); + int h = rint( ( w + t ) * d->currentHeightRatioValue / + d->currentWidthRatioValue ) - t; + if ( h < maxH ) + maxH = h; + } + + // Return max height adjusted if a precise crop is wanted + return computePreciseSize(maxH, d->currentHeightRatioValue); +} + +int ImageSelectionWidget::getWidthStep() +{ + if ( d->preciseCrop && preciseCropAvailable() ) + return d->currentWidthRatioValue; + else + return 1; +} + +int ImageSelectionWidget::getHeightStep() +{ + if ( d->preciseCrop && preciseCropAvailable() ) + return d->currentHeightRatioValue; + else + return 1; +} + +// Draw a new centered selection with half width (if orientation = Landscape) +// or with half height (if orientation = Portrait) +void ImageSelectionWidget::resetSelection() +{ + d->regionSelection.setWidth(d->image.width()/2); + d->regionSelection.setHeight(d->image.height()/2); + applyAspectRatio(d->currentOrientation == Portrait, false); + + setCenterSelection(CenterImage); +} + +void ImageSelectionWidget::setCenterSelection(int centerType) +{ + // Adjust selection size if bigger than real image + if ( d->regionSelection.height() > d->image.height() ) + { + d->regionSelection.setHeight(d->image.height()); + applyAspectRatio(true, false); + } + if ( d->regionSelection.width() > d->image.width() ) + { + d->regionSelection.setWidth(d->image.width()); + applyAspectRatio(false, false); + } + + // Set center point for selection + TQPoint center = d->image.center(); + switch (centerType) + { + case CenterWidth: + center.setY(d->regionSelection.center().y()); + break; + + case CenterHeight: + center.setX(d->regionSelection.center().x()); + break; + } + d->regionSelection.moveCenter(center); + + // Repaint + updatePixmap(); + repaint(false); + regionSelectionChanged(); +} + +// Draw a new centered selection with max size +void ImageSelectionWidget::maxAspectSelection() +{ + d->regionSelection.setWidth(d->image.width()); + d->regionSelection.setHeight(d->image.height()); + if ( d->currentAspectRatioType != RATIONONE ) + applyAspectRatio(d->currentOrientation == Portrait, false); + + setCenterSelection(CenterImage); +} + +void ImageSelectionWidget::setGoldenGuideTypes(bool drawGoldenSection, bool drawGoldenSpiralSection, + bool drawGoldenSpiral, bool drawGoldenTriangle, + bool flipHorGoldenGuide, bool flipVerGoldenGuide) +{ + d->drawGoldenSection = drawGoldenSection; + d->drawGoldenSpiralSection = drawGoldenSpiralSection; + d->drawGoldenSpiral = drawGoldenSpiral; + d->drawGoldenTriangle = drawGoldenTriangle; + d->flipHorGoldenGuide = flipHorGoldenGuide; + d->flipVerGoldenGuide = flipVerGoldenGuide; +} + +void ImageSelectionWidget::slotGuideLines(int guideLinesType) +{ + d->guideLinesType = guideLinesType; + updatePixmap(); + repaint(false); +} + +void ImageSelectionWidget::slotChangeGuideColor(const TQColor &color) +{ + d->guideColor = color; + updatePixmap(); + repaint(false); +} + +void ImageSelectionWidget::slotChangeGuideSize(int size) +{ + d->guideSize = size; + updatePixmap(); + repaint(false); +} + +void ImageSelectionWidget::setSelectionOrientation(int orient) +{ + d->currentOrientation = orient; + reverseRatioValues(); + applyAspectRatio(true); + emit signalSelectionOrientationChanged( d->currentOrientation ); +} + +void ImageSelectionWidget::setSelectionAspectRatioType(int aspectRatioType) +{ + d->currentAspectRatioType = aspectRatioType; + + // Set ratio values + switch(aspectRatioType) + { + case RATIO01X01: + d->currentWidthRatioValue = 1.0; + d->currentHeightRatioValue = 1.0; + break; + + case RATIO03X04: + d->currentWidthRatioValue = 4.0; + d->currentHeightRatioValue = 3.0; + break; + + case RATIO02x03: + d->currentWidthRatioValue = 3.0; + d->currentHeightRatioValue = 2.0; + break; + + case RATIO05x07: + d->currentWidthRatioValue = 7.0; + d->currentHeightRatioValue = 5.0; + break; + + case RATIO07x10: + d->currentWidthRatioValue = 10.0; + d->currentHeightRatioValue = 7.0; + break; + + case RATIO04X05: + d->currentWidthRatioValue = 5.0; + d->currentHeightRatioValue = 4.0; + break; + + case RATIOGOLDEN: + d->currentWidthRatioValue = PHI; + d->currentHeightRatioValue = 1.0; + break; + } + + reverseRatioValues(); + applyAspectRatio(false); +} + +void ImageSelectionWidget::setSelectionAspectRatioValue(int widthRatioValue, + int heightRatioValue) +{ + int gdc = widthRatioValue; + + // Compute greatest common divisor using Euclidean algorithm + for (int tmp, mod = heightRatioValue; mod != 0; mod = tmp % mod) + { + tmp = gdc; + gdc = mod; + } + + d->currentWidthRatioValue = widthRatioValue / gdc; + d->currentHeightRatioValue = heightRatioValue / gdc; + d->currentAspectRatioType = RATIOCUSTOM; + + // Fix orientation + if ( d->autoOrientation ) + { + if ( heightRatioValue > widthRatioValue && + d->currentOrientation == Landscape ) + { + d->currentOrientation = Portrait; + emit signalSelectionOrientationChanged( d->currentOrientation ); + } + else if ( widthRatioValue > heightRatioValue && + d->currentOrientation == Portrait ) + { + d->currentOrientation = Landscape; + emit signalSelectionOrientationChanged( d->currentOrientation ); + } + } + else + reverseRatioValues(); + + applyAspectRatio(false); +} + +void ImageSelectionWidget::reverseRatioValues() +{ + // Reverse ratio values if needed + if ( ( d->currentWidthRatioValue > d->currentHeightRatioValue && + d->currentOrientation == Portrait ) || + ( d->currentHeightRatioValue > d->currentWidthRatioValue && + d->currentOrientation == Landscape ) ) + { + float tmp = d->currentWidthRatioValue; + d->currentWidthRatioValue = d->currentHeightRatioValue; + d->currentHeightRatioValue = tmp; + } +} + +bool ImageSelectionWidget::preciseCropAvailable() +{ + // Define when precise crop feature can be used + // No needed when aspect ratio is 1:1 + switch(d->currentAspectRatioType) + { + case RATIONONE: + case RATIO01X01: + case RATIOGOLDEN: + return false; + + case RATIOCUSTOM: + return ( d->currentWidthRatioValue != d->currentHeightRatioValue ); + + default: + return true; + } +} + +void ImageSelectionWidget::setPreciseCrop(bool precise) +{ + d->preciseCrop = precise; + applyAspectRatio(false, true); + regionSelectionChanged(); +} + +void ImageSelectionWidget::setAutoOrientation(bool orientation) +{ + d->autoOrientation = orientation; +} + +void ImageSelectionWidget::setSelectionX(int x) +{ + d->regionSelection.moveLeft(x); + regionSelectionMoved(); +} + +void ImageSelectionWidget::setSelectionY(int y) +{ + d->regionSelection.moveTop(y); + regionSelectionMoved(); +} + +void ImageSelectionWidget::setSelectionWidth(int w) +{ + d->regionSelection.setWidth(w); + applyAspectRatio(false, true); + + regionSelectionChanged(); +} + +void ImageSelectionWidget::setSelectionHeight(int h) +{ + d->regionSelection.setHeight(h); + applyAspectRatio(true, true); + + regionSelectionChanged(); +} + +TQPoint ImageSelectionWidget::convertPoint(const TQPoint pm, bool localToReal) +{ + return convertPoint(pm.x(), pm.y(), localToReal); +} + +TQPoint ImageSelectionWidget::convertPoint(int x, int y, bool localToReal) +{ + int pmX, pmY; + + if (localToReal) + { + pmX = ( x - d->rect.left() ) * (float)d->image.width() / + (float)d->preview.width(); + + pmY = ( y - d->rect.top() ) * (float)d->image.height() / + (float)d->preview.height(); + } + else + { + pmX = d->rect.left() + ( x * (float)d->preview.width() / + (float)d->image.width() ); + + pmY = d->rect.top() + ( y * (float)d->preview.height() / + (float)d->image.height() ); + } + + return TQPoint(pmX, pmY); +} + +int ImageSelectionWidget::computePreciseSize(int size, int step) +{ + // Adjust size if precise crop is wanted + if ( d->preciseCrop && preciseCropAvailable() ) + size = int(size / step) * step; + + return size; +} + +void ImageSelectionWidget::applyAspectRatio(bool useHeight, bool repaintWidget) +{ + // Save selection area for re-adjustment after changing width and height. + TQRect oldRegionSelection = d->regionSelection; + + if ( !useHeight ) // Width changed. + { + int w = computePreciseSize(d->regionSelection.width(), + d->currentWidthRatioValue); + + d->regionSelection.setWidth(w); + switch(d->currentAspectRatioType) + { + case RATIONONE: + break; + + default: + d->regionSelection.setHeight(rint( w * d->currentHeightRatioValue / + d->currentWidthRatioValue ) ); + break; + } + } + else // Height changed. + { + int h = computePreciseSize(d->regionSelection.height(), + d->currentHeightRatioValue); + + d->regionSelection.setHeight(h); + switch(d->currentAspectRatioType) + { + case RATIONONE: + break; + + default: + d->regionSelection.setWidth(rint( h * d->currentWidthRatioValue / + d->currentHeightRatioValue ) ); + break; + } + } + + // If we change selection size by a corner, re-adjust the oposite corner position. + switch(d->currentResizing) + { + case ImageSelectionWidgetPriv::ResizingTopLeft: + d->regionSelection.moveBottomRight( oldRegionSelection.bottomRight() ); + break; + + case ImageSelectionWidgetPriv::ResizingTopRight: + d->regionSelection.moveBottomLeft( oldRegionSelection.bottomLeft() ); + break; + + case ImageSelectionWidgetPriv::ResizingBottomLeft: + d->regionSelection.moveTopRight( oldRegionSelection.topRight() ); + break; + + case ImageSelectionWidgetPriv::ResizingBottomRight: + d->regionSelection.moveTopLeft( oldRegionSelection.topLeft() ); + break; + } + + if (repaintWidget) + { + updatePixmap(); + repaint(false); + } +} + +void ImageSelectionWidget::normalizeRegion() +{ + // Perform normalization of selection area. + + if (d->regionSelection.left() < d->image.left()) + d->regionSelection.moveLeft(d->image.left()); + + if (d->regionSelection.top() < d->image.top()) + d->regionSelection.moveTop(d->image.top()); + + if (d->regionSelection.right() > d->image.right()) + d->regionSelection.moveRight(d->image.right()); + + if (d->regionSelection.bottom() > d->image.bottom()) + d->regionSelection.moveBottom(d->image.bottom()); +} + +void ImageSelectionWidget::regionSelectionMoved() +{ + normalizeRegion(); + + updatePixmap(); + repaint(false); + + emit signalSelectionMoved( d->regionSelection ); +} + +void ImageSelectionWidget::regionSelectionChanged() +{ + // Compute the intersection of selection region and image region + TQRect cut = d->regionSelection & d->image; + + // Adjust selection size if it was cropped + if ( d->regionSelection.width() > cut.width() ) + { + d->regionSelection = cut; + applyAspectRatio(false); + } + if ( d->regionSelection.height() > cut.height() ) + { + d->regionSelection = cut; + applyAspectRatio(true); + } + + emit signalSelectionChanged( d->regionSelection ); +} + +void ImageSelectionWidget::updatePixmap() +{ + // Updated local selection region. + d->localRegionSelection.setTopLeft( + convertPoint(d->regionSelection.topLeft(), false)); + d->localRegionSelection.setBottomRight( + convertPoint(d->regionSelection.bottomRight(), false)); + + // Updated dragging corners region. + d->localTopLeftCorner.setRect(d->localRegionSelection.left(), + d->localRegionSelection.top(), 8, 8); + d->localBottomLeftCorner.setRect(d->localRegionSelection.left(), + d->localRegionSelection.bottom() - 7, 8, 8); + d->localTopRightCorner.setRect(d->localRegionSelection.right() - 7, + d->localRegionSelection.top(), 8, 8); + d->localBottomRightCorner.setRect(d->localRegionSelection.right() - 7, + d->localRegionSelection.bottom() - 7, 8, 8); + + // Drawing background and image. + d->pixmap->fill(colorGroup().background()); + + if (d->preview.isNull()) + return; + + // Drawing region outside selection grayed. + + Digikam::DImg image = d->preview.copy(); + + uchar* ptr = image.bits(); + uchar r, g, b; + + for (int y=d->rect.top() ; y <= d->rect.bottom() ; y++) + { + for (int x=d->rect.left() ; x <= d->rect.right() ; x++) + { + if (! d->localRegionSelection.contains(x, y, true) ) + { + b = ptr[0]; + g = ptr[1]; + r = ptr[2]; + + r += (uchar)((RCOL - r) * OPACITY); + g += (uchar)((GCOL - g) * OPACITY); + b += (uchar)((BCOL - b) * OPACITY); + + ptr[0] = b; + ptr[1] = g; + ptr[2] = r; + } + + ptr+=4; + } + } + + TQPixmap pix = d->iface->convertToPixmap(image); + bitBlt(d->pixmap, d->rect.x(), d->rect.y(), &pix); + + // Stop here if no selection to draw + if ( d->regionSelection.isEmpty() ) + return; + + TQPainter p(d->pixmap); + + // Drawing selection borders. + + p.setPen(TQPen(TQColor(250, 250, 255), 1, TQt::SolidLine)); + p.drawRect(d->localRegionSelection); + + // Drawing selection corners. + + p.drawRect(d->localTopLeftCorner); + p.drawRect(d->localBottomLeftCorner); + p.drawRect(d->localTopRightCorner); + p.drawRect(d->localBottomRightCorner); + + // Drawing guide lines. + + // Constraint drawing only on local selection region. + // This is needed because arcs and incurved lines can draw + // outside a little of local selection region. + p.setClipping(true); + p.setClipRect(d->localRegionSelection); + + switch (d->guideLinesType) + { + case RulesOfThirds: + { + int xThird = d->localRegionSelection.width() / 3; + int yThird = d->localRegionSelection.height() / 3; + + p.setPen(TQPen(TQt::white, d->guideSize, TQt::SolidLine)); + p.drawLine( d->localRegionSelection.left() + xThird, d->localRegionSelection.top(), + d->localRegionSelection.left() + xThird, d->localRegionSelection.bottom() ); + p.drawLine( d->localRegionSelection.left() + 2*xThird, d->localRegionSelection.top(), + d->localRegionSelection.left() + 2*xThird, d->localRegionSelection.bottom() ); + + p.drawLine( d->localRegionSelection.left(), d->localRegionSelection.top() + yThird, + d->localRegionSelection.right(), d->localRegionSelection.top() + yThird ); + p.drawLine( d->localRegionSelection.left(), d->localRegionSelection.top() + 2*yThird, + d->localRegionSelection.right(), d->localRegionSelection.top() + 2*yThird ); + + p.setPen(TQPen(d->guideColor, d->guideSize, TQt::DotLine)); + p.drawLine( d->localRegionSelection.left() + xThird, d->localRegionSelection.top(), + d->localRegionSelection.left() + xThird, d->localRegionSelection.bottom() ); + p.drawLine( d->localRegionSelection.left() + 2*xThird, d->localRegionSelection.top(), + d->localRegionSelection.left() + 2*xThird, d->localRegionSelection.bottom() ); + + p.drawLine( d->localRegionSelection.left(), d->localRegionSelection.top() + yThird, + d->localRegionSelection.right(), d->localRegionSelection.top() + yThird ); + p.drawLine( d->localRegionSelection.left(), d->localRegionSelection.top() + 2*yThird, + d->localRegionSelection.right(), d->localRegionSelection.top() + 2*yThird ); + break; + } + + case DiagonalMethod: + { + // Move coordinates to top, left + p.translate(d->localRegionSelection.topLeft().x(), d->localRegionSelection.topLeft().y()); + + float w = (float)d->localRegionSelection.width(); + float h = (float)d->localRegionSelection.height(); + + p.setPen(TQPen(TQt::white, d->guideSize, TQt::SolidLine)); + if (w > h) + { + p.drawLine( 0, 0, h, h); + p.drawLine( 0, h, h, 0); + p.drawLine( w-h, 0, w, h); + p.drawLine( w-h, h, w, 0); + + } + else + { + p.drawLine( 0, 0, w, w); + p.drawLine( 0, w, w, 0); + p.drawLine( 0, h-w, w, h); + p.drawLine( 0, h, w, h-w); + } + + p.setPen(TQPen(d->guideColor, d->guideSize, TQt::DotLine)); + if (w > h) + { + p.drawLine( 0, 0, h, h); + p.drawLine( 0, h, h, 0); + p.drawLine( w-h, 0, w, h); + p.drawLine( w-h, h, w, 0); + + } + else + { + p.drawLine( 0, 0, w, w); + p.drawLine( 0, w, w, 0); + p.drawLine( 0, h-w, w, h); + p.drawLine( 0, h, w, h-w); + } + break; + } + + case HarmoniousTriangles: + { + // Move coordinates to local center selection. + p.translate(d->localRegionSelection.center().x(), d->localRegionSelection.center().y()); + + // Flip horizontal. + if (d->flipHorGoldenGuide) + p.scale(-1, 1); + + // Flip verical. + if (d->flipVerGoldenGuide) + p.scale(1, -1); + + float w = (float)d->localRegionSelection.width(); + float h = (float)d->localRegionSelection.height(); + int dst = (int)((h*cos(atan(w/h)) / (cos(atan(h/w))))); + + p.setPen(TQPen(TQt::white, d->guideSize, TQt::SolidLine)); + p.drawLine( -d->localRegionSelection.width()/2, -d->localRegionSelection.height()/2, + d->localRegionSelection.width()/2, d->localRegionSelection.height()/2); + + p.drawLine( -d->localRegionSelection.width()/2 + dst, -d->localRegionSelection.height()/2, + -d->localRegionSelection.width()/2, d->localRegionSelection.height()/2); + + p.drawLine( d->localRegionSelection.width()/2, -d->localRegionSelection.height()/2, + d->localRegionSelection.width()/2 - dst, d->localRegionSelection.height()/2); + + p.setPen(TQPen(d->guideColor, d->guideSize, TQt::DotLine)); + p.drawLine( -d->localRegionSelection.width()/2, -d->localRegionSelection.height()/2, + d->localRegionSelection.width()/2, d->localRegionSelection.height()/2); + + p.drawLine( -d->localRegionSelection.width()/2 + dst, -d->localRegionSelection.height()/2, + -d->localRegionSelection.width()/2, d->localRegionSelection.height()/2); + + p.drawLine( d->localRegionSelection.width()/2, -d->localRegionSelection.height()/2, + d->localRegionSelection.width()/2 - dst, d->localRegionSelection.height()/2); + break; + } + + case GoldenMean: + { + // Move coordinates to local center selection. + p.translate(d->localRegionSelection.center().x(), d->localRegionSelection.center().y()); + + // Flip horizontal. + if (d->flipHorGoldenGuide) + p.scale(-1, 1); + + // Flip vertical. + if (d->flipVerGoldenGuide) + p.scale(1, -1); + + int w = d->localRegionSelection.width(); + int h = d->localRegionSelection.height(); + + // lengths for the golden mean and half the sizes of the region: + int w_g = (int)(w*INVPHI); + int h_g = (int)(h*INVPHI); + int w_2 = w/2; + int h_2 = h/2; + + TQRect R1(-w_2, -h_2, w_g, h); + // w - 2*w_2 corrects for one-pixel difference + // so that R2.right() is really at the right end of the region + TQRect R2(w_g-w_2, h_2-h_g, w-w_g+1-(w - 2*w_2), h_g); + + TQRect R3((int)(w_2 - R2.width()*INVPHI), -h_2, + (int)(R2.width()*INVPHI), h - R2.height()); + TQRect R4(R2.x(), R1.y(), R3.x() - R2.x(), + (int)(R3.height()*INVPHI)); + TQRect R5(R4.x(), R4.bottom(), (int)(R4.width()*INVPHI), + R3.height() - R4.height()); + TQRect R6(R5.x() + R5.width(), R5.bottom() - (int)(R5.height()*INVPHI), + R3.x() - R5.right(), (int)(R5.height()*INVPHI)); + TQRect R7(R6.right() - (int)(R6.width()*INVPHI), R4.bottom(), + (int)(R6.width()*INVPHI), R5.height() - R6.height()); + + p.setPen(TQPen(TQt::white, d->guideSize, TQt::SolidLine)); + + // Drawing Golden sections. + if (d->drawGoldenSection) + { + // horizontal lines: + p.drawLine( R1.left(), R2.top(), + R2.right(), R2.top()); + + p.drawLine( R1.left(), R1.top() + R2.height(), + R2.right(), R1.top() + R2.height()); + + // vertical lines: + p.drawLine( R1.right(), R1.top(), + R1.right(), R1.bottom() ); + + p.drawLine( R1.left()+R2.width(), R1.top(), + R1.left()+R2.width(), R1.bottom() ); + } + + // Drawing Golden triangle guides. + if (d->drawGoldenTriangle) + { + p.drawLine( R1.left(), R1.bottom(), + R2.right(), R1.top() ); + + p.drawLine( R1.left(), R1.top(), + R2.right() - R1.width(), R1.bottom()); + + p.drawLine( R1.left() + R1.width(), R1.top(), + R2.right(), R1.bottom() ); + } + + // Drawing Golden spiral sections. + if (d->drawGoldenSpiralSection) + { + p.drawLine( R1.topRight(), R1.bottomRight() ); + p.drawLine( R2.topLeft(), R2.topRight() ); + p.drawLine( R3.topLeft(), R3.bottomLeft() ); + p.drawLine( R4.bottomLeft(), R4.bottomRight() ); + p.drawLine( R5.topRight(), R5.bottomRight() ); + p.drawLine( R6.topLeft(), R6.topRight() ); + p.drawLine( R7.topLeft(), R7.bottomLeft() ); + } + + // Drawing Golden Spiral. + if (d->drawGoldenSpiral) + { + p.drawArc ( R1.left(), + R1.top() - R1.height(), + 2*R1.width(), 2*R1.height(), + 180*16, 90*16); + + p.drawArc ( R2.right() - 2*R2.width(), + R1.bottom() - 2*R2.height(), + 2*R2.width(), 2*R2.height(), + 270*16, 90*16); + + p.drawArc ( R2.right() - 2*R3.width(), + R3.top(), + 2*R3.width(), 2*R3.height(), + 0, 90*16); + + p.drawArc ( R4.left(), + R4.top(), + 2*R4.width(), 2*R4.height(), + 90*16, 90*16); + + p.drawArc ( R5.left(), + R5.top()-R5.height(), + 2*R5.width(), 2*R5.height(), + 180*16, 90*16); + + p.drawArc ( R6.left()-R6.width(), + R6.top()-R6.height(), + 2*R6.width(), 2*R6.height(), + 270*16, 90*16); + + p.drawArc ( R7.left()-R7.width(), + R7.top(), + 2*R7.width(), 2*R7.height(), + 0, 90*16); + } + + p.setPen(TQPen(d->guideColor, d->guideSize, TQt::DotLine)); + + // Drawing Golden sections. + if (d->drawGoldenSection) + { + // horizontal lines: + p.drawLine( R1.left(), R2.top(), + R2.right(), R2.top()); + + p.drawLine( R1.left(), R1.top() + R2.height(), + R2.right(), R1.top() + R2.height()); + + // vertical lines: + p.drawLine( R1.right(), R1.top(), + R1.right(), R1.bottom() ); + + p.drawLine( R1.left()+R2.width(), R1.top(), + R1.left()+R2.width(), R1.bottom() ); + } + + // Drawing Golden triangle guides. + if (d->drawGoldenTriangle) + { + p.drawLine( R1.left(), R1.bottom(), + R2.right(), R1.top() ); + + p.drawLine( R1.left(), R1.top(), + R2.right() - R1.width(), R1.bottom()); + + p.drawLine( R1.left() + R1.width(), R1.top(), + R2.right(), R1.bottom() ); + } + + // Drawing Golden spiral sections. + if (d->drawGoldenSpiralSection) + { + p.drawLine( R1.topRight(), R1.bottomRight() ); + p.drawLine( R2.topLeft(), R2.topRight() ); + p.drawLine( R3.topLeft(), R3.bottomLeft() ); + p.drawLine( R4.bottomLeft(), R4.bottomRight() ); + p.drawLine( R5.topRight(), R5.bottomRight() ); + p.drawLine( R6.topLeft(), R6.topRight() ); + p.drawLine( R7.topLeft(), R7.bottomLeft() ); + } + + // Drawing Golden Spiral. + if (d->drawGoldenSpiral) + { + p.drawArc ( R1.left(), + R1.top() - R1.height(), + 2*R1.width(), 2*R1.height(), + 180*16, 90*16); + + p.drawArc ( R2.right() - 2*R2.width(), + R1.bottom() - 2*R2.height(), + 2*R2.width(), 2*R2.height(), + 270*16, 90*16); + + p.drawArc ( R2.right() - 2*R3.width(), + R3.top(), + 2*R3.width(), 2*R3.height(), + 0, 90*16); + + p.drawArc ( R4.left(), + R4.top(), + 2*R4.width(), 2*R4.height(), + 90*16, 90*16); + + p.drawArc ( R5.left(), + R5.top()-R5.height(), + 2*R5.width(), 2*R5.height(), + 180*16, 90*16); + + p.drawArc ( R6.left()-R6.width(), + R6.top()-R6.height(), + 2*R6.width(), 2*R6.height(), + 270*16, 90*16); + + p.drawArc ( R7.left()-R7.width(), + R7.top(), + 2*R7.width(), 2*R7.height(), + 0, 90*16); + } + + break; + } + } + + p.setClipping(false); + + p.end(); +} + +void ImageSelectionWidget::paintEvent( TQPaintEvent * ) +{ + bitBlt(this, 0, 0, d->pixmap); +} + +TQPoint ImageSelectionWidget::opposite() +{ + TQPoint opp; + + switch(d->currentResizing) + { + case ImageSelectionWidgetPriv::ResizingTopRight: + opp = d->regionSelection.bottomLeft(); + break; + + case ImageSelectionWidgetPriv::ResizingBottomLeft: + opp = d->regionSelection.topRight(); + break; + + case ImageSelectionWidgetPriv::ResizingBottomRight: + opp = d->regionSelection.topLeft(); + break; + + case ImageSelectionWidgetPriv::ResizingTopLeft: + default: + opp = d->regionSelection.bottomRight(); + break; + } + + return opp; +} + +float ImageSelectionWidget::distance(TQPoint a, TQPoint b) +{ + return sqrt(pow(a.x() - b.x(), 2) + pow(a.y() - b.y(), 2)); +} + +void ImageSelectionWidget::setCursorResizing() +{ + switch(d->currentResizing) + { + case ImageSelectionWidgetPriv::ResizingTopLeft: + setCursor( KCursor::sizeFDiagCursor() ); + break; + + case ImageSelectionWidgetPriv::ResizingTopRight: + setCursor( KCursor::sizeBDiagCursor() ); + break; + + case ImageSelectionWidgetPriv::ResizingBottomLeft: + setCursor( KCursor::sizeBDiagCursor() ); + break; + + case ImageSelectionWidgetPriv::ResizingBottomRight: + setCursor( KCursor::sizeFDiagCursor() ); + break; + } +} + +void ImageSelectionWidget::placeSelection(TQPoint pm, bool symmetric, TQPoint center) +{ + // Set orientation + if ( d->autoOrientation ) + { + TQPoint rel = pm - opposite(); + + if ( abs(rel.x()) > abs(rel.y()) ) + { + if ( d->currentOrientation == Portrait ) + { + d->currentOrientation = Landscape; + reverseRatioValues(); + emit signalSelectionOrientationChanged( d->currentOrientation ); + } + } + else + { + if ( d->currentOrientation == Landscape ) + { + d->currentOrientation = Portrait; + reverseRatioValues(); + emit signalSelectionOrientationChanged( d->currentOrientation ); + } + } + } + + // Place the corner at the mouse + // If a symmetric selection is wanted, place opposite corner to + // the center, double selection size and move it to old center after + // computing aspect ratio. + switch(d->currentResizing) + { + case ImageSelectionWidgetPriv::ResizingTopLeft: + // Place corners to the proper position + d->regionSelection.setTopLeft(pm); + if ( symmetric ) + d->regionSelection.setBottomRight(center); + break; + + case ImageSelectionWidgetPriv::ResizingTopRight: + d->regionSelection.setTopRight(pm); + if ( symmetric ) + d->regionSelection.setBottomLeft(center); + break; + + case ImageSelectionWidgetPriv::ResizingBottomLeft: + d->regionSelection.setBottomLeft(pm); + if ( symmetric ) + d->regionSelection.setTopRight(center); + break; + + case ImageSelectionWidgetPriv::ResizingBottomRight: + d->regionSelection.setBottomRight(pm); + if ( symmetric ) + d->regionSelection.setTopLeft(center); + break; + } + + if ( symmetric ) + d->regionSelection.setSize(d->regionSelection.size()*2); + applyAspectRatio(d->currentOrientation == Portrait, false); + if ( symmetric ) + d->regionSelection.moveCenter(center); + + // Repaint + updatePixmap(); + repaint(false); +} + +void ImageSelectionWidget::mousePressEvent ( TQMouseEvent * e ) +{ + if ( e->button() == TQt::LeftButton ) + { + TQPoint pm = TQPoint(e->x(), e->y()); + TQPoint pmVirtual = convertPoint(pm); + d->moving = false; + + if ( (e->state() & TQt::ShiftButton) == TQt::ShiftButton ) + { + bool symmetric = (e->state() & TQt::ControlButton ) == TQt::ControlButton; + TQPoint center = d->regionSelection.center(); + + // Find the closest corner + + TQPoint points[] = { d->regionSelection.topLeft(), + d->regionSelection.topRight(), + d->regionSelection.bottomLeft(), + d->regionSelection.bottomRight() }; + int resizings[] = { ImageSelectionWidgetPriv::ResizingTopLeft, + ImageSelectionWidgetPriv::ResizingTopRight, + ImageSelectionWidgetPriv::ResizingBottomLeft, + ImageSelectionWidgetPriv::ResizingBottomRight }; + float dist = -1; + for (int i = 0 ; i < 4 ; i++) + { + TQPoint point = points[i]; + float dist2 = distance(pmVirtual, point); + if (dist2 < dist || d->currentResizing == ImageSelectionWidgetPriv::ResizingNone) + { + dist = dist2; + d->currentResizing = resizings[i]; + } + } + + setCursorResizing(); + + placeSelection(pmVirtual, symmetric, center); + } + else + { + if ( d->localTopLeftCorner.contains( pm ) ) + d->currentResizing = ImageSelectionWidgetPriv::ResizingTopLeft; + else if ( d->localTopRightCorner.contains( pm ) ) + d->currentResizing = ImageSelectionWidgetPriv::ResizingTopRight; + else if ( d->localBottomLeftCorner.contains( pm ) ) + d->currentResizing = ImageSelectionWidgetPriv::ResizingBottomLeft; + else if ( d->localBottomRightCorner.contains( pm ) ) + d->currentResizing = ImageSelectionWidgetPriv::ResizingBottomRight; + else + { + d->lastPos = pmVirtual; + setCursor( KCursor::sizeAllCursor() ); + + if (d->regionSelection.contains( pmVirtual ) ) + { + d->moving = true; + } + else + { + d->regionSelection.moveCenter( pmVirtual ); + normalizeRegion(); + updatePixmap(); + repaint(false); + } + } + } + } +} + +void ImageSelectionWidget::mouseReleaseEvent ( TQMouseEvent * ) +{ + if ( d->currentResizing != ImageSelectionWidgetPriv::ResizingNone ) + { + setCursor( KCursor::arrowCursor() ); + regionSelectionChanged(); + d->currentResizing = ImageSelectionWidgetPriv::ResizingNone; + } + else if ( d->regionSelection.contains( d->lastPos ) ) + { + setCursor( KCursor::handCursor() ); + regionSelectionMoved(); + } + else + { + setCursor( KCursor::arrowCursor() ); + regionSelectionMoved(); + } +} + +void ImageSelectionWidget::mouseMoveEvent ( TQMouseEvent * e ) +{ + if ( ( e->state() & TQt::LeftButton ) == TQt::LeftButton ) + { + if ( d->moving ) + { + setCursor( KCursor::sizeAllCursor() ); + TQPoint newPos = convertPoint(e->x(), e->y()); + + d->regionSelection.moveBy( newPos.x() - d->lastPos.x(), + newPos.y() - d->lastPos.y() ); + + d->lastPos = newPos; + + normalizeRegion(); + + updatePixmap(); + repaint(false); + } + else + { + TQPoint pmVirtual = convertPoint(e->x(), e->y()); + + if ( d->currentResizing == ImageSelectionWidgetPriv::ResizingNone ) + { + d->regionSelection.setTopLeft( pmVirtual ); + d->regionSelection.setBottomRight( pmVirtual ); + d->currentResizing = ImageSelectionWidgetPriv::ResizingTopLeft; // set to anything + } + + TQPoint center = d->regionSelection.center(); + bool symmetric = (e->state() & TQt::ControlButton ) == TQt::ControlButton; + + // Change resizing mode + + TQPoint opp = symmetric ? center : opposite(); + TQPoint dir = pmVirtual - opp; + + if ( dir.x() > 0 && dir.y() > 0 && d->currentResizing != ImageSelectionWidgetPriv::ResizingBottomRight) + { + d->currentResizing = ImageSelectionWidgetPriv::ResizingBottomRight; + d->regionSelection.setTopLeft( opp ); + setCursor( KCursor::sizeFDiagCursor() ); + } + else if ( dir.x() > 0 && dir.y() < 0 && d->currentResizing != ImageSelectionWidgetPriv::ResizingTopRight) + { + d->currentResizing = ImageSelectionWidgetPriv::ResizingTopRight; + d->regionSelection.setBottomLeft( opp ); + setCursor( KCursor::sizeBDiagCursor() ); + } + else if ( dir.x() < 0 && dir.y() > 0 && d->currentResizing != ImageSelectionWidgetPriv::ResizingBottomLeft) + { + d->currentResizing = ImageSelectionWidgetPriv::ResizingBottomLeft; + d->regionSelection.setTopRight( opp ); + setCursor( KCursor::sizeBDiagCursor() ); + } + else if ( dir.x() < 0 && dir.y() < 0 && d->currentResizing != ImageSelectionWidgetPriv::ResizingTopLeft) + { + d->currentResizing = ImageSelectionWidgetPriv::ResizingTopLeft; + d->regionSelection.setBottomRight( opp ); + setCursor( KCursor::sizeFDiagCursor() ); + } + else + { + if ( dir.x() == 0 && dir.y() == 0 ) + setCursor( KCursor::sizeAllCursor() ); + else if ( dir.x() == 0 ) + setCursor( KCursor::sizeHorCursor() ); + else if ( dir.y() == 0 ) + setCursor( KCursor::sizeVerCursor() ); + } + + placeSelection(pmVirtual, symmetric, center); + } + } + else + { + if ( d->localTopLeftCorner.contains( e->x(), e->y() ) || + d->localBottomRightCorner.contains( e->x(), e->y() ) ) + setCursor( KCursor::sizeFDiagCursor() ); + else if ( d->localTopRightCorner.contains( e->x(), e->y() ) || + d->localBottomLeftCorner.contains( e->x(), e->y() ) ) + setCursor( KCursor::sizeBDiagCursor() ); + else if ( d->localRegionSelection.contains( e->x(), e->y() ) ) + setCursor( KCursor::handCursor() ); + else + setCursor( KCursor::arrowCursor() ); + } +} + +} // NameSpace DigikamImagesPluginCore diff --git a/src/imageplugins/coreplugin/ratiocrop/imageselectionwidget.h b/src/imageplugins/coreplugin/ratiocrop/imageselectionwidget.h new file mode 100644 index 00000000..0d2bd4fd --- /dev/null +++ b/src/imageplugins/coreplugin/ratiocrop/imageselectionwidget.h @@ -0,0 +1,176 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-09 + * Description : image selection widget used by ratio crop tool. + * + * Copyright (C) 2007 by Jaromir Malenko <malenko at email.cz> + * Copyright (C) 2008 by Roberto Castagnola <roberto dot castagnola at gmail dot com> + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef IMAGESELECTIONWIDGET_H +#define IMAGESELECTIONWIDGET_H + +// TQt includes. + +#include <tqwidget.h> +#include <tqrect.h> +#include <tqcolor.h> + +namespace Digikam +{ +class ImageIface; +} + +namespace DigikamImagesPluginCore +{ + +class ImageSelectionWidgetPriv; + +class ImageSelectionWidget : public TQWidget +{ + +TQ_OBJECT + + +public: + + enum RatioAspect // Constrained Aspect Ratio list. + { + RATIOCUSTOM=0, // Custom aspect ratio. + RATIO01X01, // 1:1 + RATIO02x03, // 2:3 + RATIO03X04, // 3:4 + RATIO04X05, // 4:5 + RATIO05x07, // 5:7 + RATIO07x10, // 7:10 + RATIOGOLDEN, // Golden ratio : 1:1.618 + RATIONONE // No aspect ratio. + }; + + enum Orient + { + Landscape = 0, + Portrait + }; + + enum CenterType + { + CenterWidth = 0, // Center selection to the center of image width. + CenterHeight, // Center selection to the center of image height. + CenterImage // Center selection to the center of image. + }; + + // Proportion : Golden Ratio and Rule of Thirds. More information at this url: + // http://photoinf.com/General/Robert_Berdan/Composition_and_the_Elements_of_Visual_Design.htm + + enum GuideLineType + { + RulesOfThirds = 0, // Line guides position to 1/3 width and height. + DiagonalMethod, // Diagonal Method to improve composition. + HarmoniousTriangles, // Harmonious Triangle to improve composition. + GoldenMean, // Guides tools using Phi ratio (1.618). + GuideNone // No guide line. + }; + +public: + + ImageSelectionWidget(int width, int height, TQWidget *parent=0, + int widthRatioValue=1, int heightRatioValue=1, + int aspectRatio=RATIO01X01, int orient=Landscape, + int guideLinesType=GuideNone); + ~ImageSelectionWidget(); + + void setCenterSelection(int centerType=CenterImage); + void setSelectionX(int x); + void setSelectionY(int y); + void setSelectionWidth(int w); + void setSelectionHeight(int h); + void setSelectionOrientation(int orient); + void setPreciseCrop(bool precise); + void setAutoOrientation(bool orientation); + void setSelectionAspectRatioType(int aspectRatioType); + void setSelectionAspectRatioValue(int widthRatioValue, int heightRatioValue); + void setGoldenGuideTypes(bool drawGoldenSection, bool drawGoldenSpiralSection, + bool drawGoldenSpiral, bool drawGoldenTriangle, + bool flipHorGoldenGuide, bool flipVerGoldenGuide); + + int getOriginalImageWidth(); + int getOriginalImageHeight(); + TQRect getRegionSelection(); + + int getMinWidthRange(); + int getMinHeightRange(); + int getMaxWidthRange(); + int getMaxHeightRange(); + int getWidthStep(); + int getHeightStep(); + + bool preciseCropAvailable(); + + void resetSelection(); + void maxAspectSelection(); + + Digikam::ImageIface* imageIface(); + +public slots: + + void slotGuideLines(int guideLinesType); + void slotChangeGuideColor(const TQColor &color); + void slotChangeGuideSize(int size); + +signals: + + void signalSelectionMoved( TQRect rect ); + void signalSelectionChanged( TQRect rect ); + void signalSelectionOrientationChanged( int newOrientation ); + +protected: + + void paintEvent( TQPaintEvent *e ); + void mousePressEvent ( TQMouseEvent * e ); + void mouseReleaseEvent ( TQMouseEvent * e ); + void mouseMoveEvent ( TQMouseEvent * e ); + void resizeEvent(TQResizeEvent * e); + +private: + + // Recalculate the target selection position and emit 'signalSelectionMoved'. + void regionSelectionMoved(); + + void regionSelectionChanged(); + TQPoint convertPoint(const TQPoint pm, bool localToReal=true); + TQPoint convertPoint(int x, int y, bool localToReal=true); + void normalizeRegion(); + void reverseRatioValues(); + int computePreciseSize(int size, int step); + void applyAspectRatio(bool useHeight, bool repaintWidget=true); + void updatePixmap(); + TQPoint opposite(); + float distance(TQPoint a, TQPoint b); + void placeSelection(TQPoint pm, bool symetric, TQPoint center); + void setCursorResizing(); + +private: + + ImageSelectionWidgetPriv* d; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* IMAGESELECTIONWIDGET_H */ diff --git a/src/imageplugins/coreplugin/ratiocrop/ratiocroptool.cpp b/src/imageplugins/coreplugin/ratiocrop/ratiocroptool.cpp new file mode 100644 index 00000000..ed0e670e --- /dev/null +++ b/src/imageplugins/coreplugin/ratiocrop/ratiocroptool.cpp @@ -0,0 +1,853 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-06 + * Description : digiKam image editor Ratio Crop tool + * + * Copyright (C) 2007 by Jaromir Malenko <malenko at email dot cz> + * Copyright (C) 2008 by Roberto Castagnola <roberto dot castagnola at gmail dot com> + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqcheckbox.h> +#include <tqframe.h> +#include <tqimage.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqrect.h> +#include <tqspinbox.h> +#include <tqtimer.h> +#include <tqtoolbutton.h> +#include <tqtooltip.h> +#include <tqvgroupbox.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeapplication.h> +#include <kcolorbutton.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <kpushbutton.h> +#include <kstandarddirs.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> +#include <libkdcraw/rcombobox.h> + +// Digikam includes. + +#include "editortoolsettings.h" +#include "imageiface.h" +#include "imageselectionwidget.h" + +// Local includes. + +#include "ratiocroptool.h" +#include "ratiocroptool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamImagesPluginCore +{ + +RatioCropTool::RatioCropTool(TQObject* parent) + : EditorTool(parent) +{ + setName("aspectratiocrop"); + setToolName(i18n("Aspect Ratio Crop")); + setToolIcon(SmallIcon("ratiocrop")); + setToolHelp("ratiocroptool.anchor"); + + // ------------------------------------------------------------- + + m_imageSelectionWidget = new ImageSelectionWidget(480, 320); + TQWhatsThis::add(m_imageSelectionWidget, + i18n("<p>Here you can see the aspect ratio selection preview " + "used for cropping. You can use the mouse to move and " + "resize the crop area. " + "Press and hold the CTRL key to move the opposite corner too. " + "Press and hold the SHIFT key to move the closest corner to the " + "mouse pointer.")); + + m_originalIsLandscape = ((m_imageSelectionWidget->getOriginalImageWidth()) > + (m_imageSelectionWidget->getOriginalImageHeight())); + + setToolView(m_imageSelectionWidget); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Try| + EditorToolSettings::Cancel); + + // ------------------------------------------------------------- + + // need to set the button to a KStdGuiItem that has no icon + m_gboxSettings->button(EditorToolSettings::Try)->setGuiItem(KStdGuiItem::Test); + // now we can set the correct text for the button + m_gboxSettings->button(EditorToolSettings::Try)->setText(i18n("Max. Aspect")); + + TQToolTip::add(m_gboxSettings->button(EditorToolSettings::Try), + i18n("<p>Set selection area to the maximum size according " + "to the current ratio.")); + + // ------------------------------------------------------------- + + TQGridLayout *gboxLayout = new TQGridLayout(m_gboxSettings->plainPage(), 3, 2); + + TQFrame *cropSelection = new TQFrame(m_gboxSettings->plainPage()); + cropSelection->setFrameStyle(TQFrame::Panel | TQFrame::Sunken); + + TQGridLayout* grid = new TQGridLayout(cropSelection, 7, 5); + + TQLabel *label = new TQLabel(i18n("Ratio:"), cropSelection); + m_ratioCB = new RComboBox(cropSelection); + m_ratioCB->setDefaultItem(ImageSelectionWidget::RATIO03X04); + setRatioCBText(ImageSelectionWidget::Landscape); + TQWhatsThis::add( m_ratioCB, i18n("<p>Select your constrained aspect ratio for cropping. " + "Aspect Ratio Crop tool uses a relative ratio. That means it " + "is the same if you use centimeters or inches and it doesn't " + "specify the physical size.<p>" + "You can see below a correspondence list of traditional photographic " + "paper sizes and aspect ratio crop:<p>" + "<b>2:3</b>: 10x15cm, 20x30cm, 30x45cm, 4x6\", 8x12\", " + "12x18\", 16x24\", 20x30\"<p>" + "<b>3:4</b>: 6x8cm, 15x20cm, 18x24cm, 30x40cm, 3.75x5\", 4.5x6\", " + "6x8\", 7.5x10\", 9x12\"<p>" + "<b>4:5</b>: 20x25cm, 40x50cm, 8x10\", 16x20\"<p>" + "<b>5:7</b>: 15x21cm, 30x42cm, 5x7\"<p>" + "<b>7:10</b>: 21x30cm, 42x60cm, 3.5x5\"<p>" + "The <b>Golden Ratio</b> is 1:1.618. A composition following this rule " + "is considered visually harmonious but can be unadapted to print on " + "standard photographic paper.")); + + m_preciseCrop = new TQCheckBox(i18n("Exact"), cropSelection); + TQWhatsThis::add( m_preciseCrop, i18n("<p>Enable this option to force exact aspect ratio crop.")); + + m_orientLabel = new TQLabel(i18n("Orientation:"), cropSelection); + m_orientCB = new RComboBox(cropSelection); + m_orientCB->insertItem( i18n("Landscape")); + m_orientCB->insertItem( i18n("Portrait")); + m_orientCB->setDefaultItem(ImageSelectionWidget::Landscape); + TQWhatsThis::add( m_orientCB, i18n("<p>Select constrained aspect ratio orientation.")); + + m_autoOrientation = new TQCheckBox(i18n("Auto"), cropSelection); + TQWhatsThis::add( m_autoOrientation, i18n("<p>Enable this option to automatically set the orientation.")); + + // ------------------------------------------------------------- + + m_customLabel1 = new TQLabel(i18n("Custom:"), cropSelection); + m_customLabel1->setAlignment(AlignLeft|AlignVCenter); + m_customRatioNInput = new RIntNumInput(cropSelection); + m_customRatioNInput->input()->setRange(1, 10000, 1, false); + m_customRatioNInput->setDefaultValue(1); + TQWhatsThis::add( m_customRatioNInput, i18n("<p>Set here the desired custom aspect numerator value.")); + + m_customLabel2 = new TQLabel(" : ", cropSelection); + m_customLabel2->setAlignment(AlignCenter|AlignVCenter); + m_customRatioDInput = new RIntNumInput(cropSelection); + m_customRatioDInput->input()->setRange(1, 10000, 1, false); + m_customRatioDInput->setDefaultValue(1); + TQWhatsThis::add( m_customRatioDInput, i18n("<p>Set here the desired custom aspect denominator value.")); + + // ------------------------------------------------------------- + + m_xInput = new RIntNumInput(cropSelection); + m_xInput->input()->setLabel(i18n("X:"), AlignLeft|AlignVCenter); + m_xInput->setRange(0, m_imageSelectionWidget->getOriginalImageWidth(), 1); + m_xInput->setDefaultValue(50); + TQWhatsThis::add( m_xInput, i18n("<p>Set here the top left selection corner position for cropping.")); + + m_widthInput = new RIntNumInput(cropSelection); + m_widthInput->input()->setLabel(i18n("Width:"), AlignLeft|AlignVCenter); + m_widthInput->setRange(m_imageSelectionWidget->getMinWidthRange(), + m_imageSelectionWidget->getMaxWidthRange(), + m_imageSelectionWidget->getWidthStep()); + m_widthInput->setDefaultValue(800); + TQWhatsThis::add( m_widthInput, i18n("<p>Set here the width selection for cropping.")); + + m_centerWidth = new TQToolButton(cropSelection); + TDEGlobal::dirs()->addResourceType("centerwidth", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + TQString directory = TDEGlobal::dirs()->findResourceDir("centerwidth", "centerwidth.png"); + m_centerWidth->setPixmap(TQPixmap(directory + "centerwidth.png")); + TQWhatsThis::add(m_centerWidth, i18n("<p>Set width position to center.")); + + // ------------------------------------------------------------- + + m_yInput = new RIntNumInput(cropSelection); + m_yInput->input()->setLabel(i18n("Y:"), AlignLeft | AlignVCenter); + m_yInput->setRange(0, m_imageSelectionWidget->getOriginalImageHeight(), 1); + m_yInput->setDefaultValue(50); + TQWhatsThis::add(m_yInput, i18n("<p>Set here the top left selection corner position for cropping.")); + + m_heightInput = new RIntNumInput(cropSelection); + m_heightInput->input()->setLabel(i18n("Height:"), AlignLeft | AlignVCenter); + m_heightInput->setRange(m_imageSelectionWidget->getMinHeightRange(), + m_imageSelectionWidget->getMaxHeightRange(), + m_imageSelectionWidget->getHeightStep()); + m_heightInput->setDefaultValue(600); + TQWhatsThis::add( m_heightInput, i18n("<p>Set here the height selection for cropping.")); + + m_centerHeight = new TQToolButton(cropSelection); + TDEGlobal::dirs()->addResourceType("centerheight", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("centerheight", "centerheight.png"); + m_centerHeight->setPixmap(TQPixmap(directory + "centerheight.png")); + TQWhatsThis::add(m_centerHeight, i18n("<p>Set height position to center.")); + + grid->addMultiCellWidget(label, 0, 0, 0, 0); + grid->addMultiCellWidget(m_ratioCB, 0, 0, 1, 3); + grid->addMultiCellWidget(m_preciseCrop, 0, 0, 4, 4); + grid->addMultiCellWidget(m_customLabel1, 1, 1, 0, 0); + grid->addMultiCellWidget(m_customRatioNInput, 1, 1, 1, 1); + grid->addMultiCellWidget(m_customLabel2, 1, 1, 2, 2); + grid->addMultiCellWidget(m_customRatioDInput, 1, 1, 3, 3); + grid->addMultiCellWidget(m_orientLabel, 2, 2, 0, 0); + grid->addMultiCellWidget(m_orientCB, 2, 2, 1, 3); + grid->addMultiCellWidget(m_autoOrientation, 2, 2, 4, 4); + grid->addMultiCellWidget(m_xInput, 3, 3, 0, 3); + grid->addMultiCellWidget(m_widthInput, 4, 4, 0, 3); + grid->addMultiCellWidget(m_centerWidth, 4, 4, 4, 4); + grid->addMultiCellWidget(m_yInput, 5, 5, 0, 3); + grid->addMultiCellWidget(m_heightInput, 6, 6, 0, 3); + grid->addMultiCellWidget(m_centerHeight, 6, 6, 4, 4); + grid->setMargin(m_gboxSettings->spacingHint()); + grid->setSpacing(m_gboxSettings->spacingHint()); + + // ------------------------------------------------------------- + + TQFrame* compositionGuide = new TQFrame(m_gboxSettings->plainPage()); + TQGridLayout* grid2 = new TQGridLayout(compositionGuide, 8, 3); + compositionGuide->setFrameStyle(TQFrame::Panel|TQFrame::Sunken); + + TQLabel *labelGuideLines = new TQLabel(i18n("Composition guide:"), compositionGuide); + m_guideLinesCB = new RComboBox(compositionGuide); + m_guideLinesCB->insertItem( i18n("Rules of Thirds")); + m_guideLinesCB->insertItem( i18n("Diagonal Method")); + m_guideLinesCB->insertItem( i18n("Harmonious Triangles")); + m_guideLinesCB->insertItem( i18n("Golden Mean")); + m_guideLinesCB->insertItem( i18n("None")); + m_guideLinesCB->setDefaultItem(ImageSelectionWidget::GuideNone); + TQWhatsThis::add( m_guideLinesCB, i18n("<p>With this option, you can display guide lines " + "which help you to compose your photograph.")); + + m_goldenSectionBox = new TQCheckBox(i18n("Golden sections"), compositionGuide); + TQWhatsThis::add( m_goldenSectionBox, i18n("<p>Enable this option to show golden sections.")); + + m_goldenSpiralSectionBox = new TQCheckBox(i18n("Golden spiral sections"), compositionGuide); + TQWhatsThis::add( m_goldenSpiralSectionBox, i18n("<p>Enable this option to show golden spiral sections.")); + + m_goldenSpiralBox = new TQCheckBox(i18n("Golden spiral"), compositionGuide); + TQWhatsThis::add( m_goldenSpiralBox, i18n("<p>Enable this option to show golden spiral guide.")); + + m_goldenTriangleBox = new TQCheckBox(i18n("Golden triangles"), compositionGuide); + TQWhatsThis::add( m_goldenTriangleBox, i18n("<p>Enable this option to show golden triangles.")); + + m_flipHorBox = new TQCheckBox(i18n("Flip horizontally"), compositionGuide); + TQWhatsThis::add( m_flipHorBox, i18n("<p>Enable this option to flip horizontally guidelines.")); + + m_flipVerBox = new TQCheckBox(i18n("Flip vertically"), compositionGuide); + TQWhatsThis::add( m_flipVerBox, i18n("<p>Enable this option to flip vertically guidelines.")); + + m_colorGuideLabel = new TQLabel(i18n("Color and width:"), compositionGuide); + m_guideColorBt = new KColorButton(TQColor(250, 250, 255), compositionGuide); + m_guideSize = new RIntNumInput(compositionGuide); + m_guideSize->input()->setRange(1, 5, 1, false); + m_guideSize->setDefaultValue(1); + TQWhatsThis::add( m_guideColorBt, i18n("<p>Set here the color used to draw composition guides.")); + TQWhatsThis::add( m_guideSize, i18n("<p>Set here the width in pixels used to draw composition guides.")); + + grid2->addMultiCellWidget(labelGuideLines, 0, 0, 0, 0); + grid2->addMultiCellWidget(m_guideLinesCB, 0, 0, 1, 2); + grid2->addMultiCellWidget(m_goldenSectionBox, 1, 1, 0, 2); + grid2->addMultiCellWidget(m_goldenSpiralSectionBox, 2, 2, 0, 2); + grid2->addMultiCellWidget(m_goldenSpiralBox, 3, 3, 0, 2); + grid2->addMultiCellWidget(m_goldenTriangleBox, 4, 4, 0, 2); + grid2->addMultiCellWidget(m_flipHorBox, 5, 5, 0, 2); + grid2->addMultiCellWidget(m_flipVerBox, 6, 6, 0, 2); + grid2->addMultiCellWidget(m_colorGuideLabel, 7, 7, 0, 0); + grid2->addMultiCellWidget(m_guideColorBt, 7, 7, 1, 1); + grid2->addMultiCellWidget(m_guideSize, 7, 7, 2, 2); + grid2->setMargin(m_gboxSettings->spacingHint()); + grid2->setSpacing(m_gboxSettings->spacingHint()); + + + // ------------------------------------------------------------- + + gboxLayout->addMultiCellWidget(cropSelection, 0, 0, 0, 1); + gboxLayout->addMultiCellWidget(compositionGuide, 1, 1, 0, 1); + gboxLayout->setRowStretch(2, 10); + gboxLayout->setMargin(m_gboxSettings->spacingHint()); + gboxLayout->setSpacing(m_gboxSettings->spacingHint()); + + setToolSettings(m_gboxSettings); + init(); + + // ------------------------------------------------------------- + + connect(m_ratioCB, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotRatioChanged(int))); + + connect(m_preciseCrop, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotPreciseCropChanged(bool))); + + connect(m_orientCB, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotOrientChanged(int))); + + connect(m_autoOrientation, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotAutoOrientChanged(bool))); + + connect(m_xInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotXChanged(int))); + + connect(m_yInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotYChanged(int))); + + connect(m_customRatioNInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotCustomNRatioChanged(int))); + + connect(m_customRatioDInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotCustomDRatioChanged(int))); + + connect(m_guideLinesCB, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotGuideTypeChanged(int))); + + connect(m_goldenSectionBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotGoldenGuideTypeChanged())); + + connect(m_goldenSpiralSectionBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotGoldenGuideTypeChanged())); + + connect(m_goldenSpiralBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotGoldenGuideTypeChanged())); + + connect(m_goldenTriangleBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotGoldenGuideTypeChanged())); + + connect(m_flipHorBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotGoldenGuideTypeChanged())); + + connect(m_flipVerBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotGoldenGuideTypeChanged())); + + connect(m_guideColorBt, TQ_SIGNAL(changed(const TQColor&)), + m_imageSelectionWidget, TQ_SLOT(slotChangeGuideColor(const TQColor&))); + + connect(m_guideSize, TQ_SIGNAL(valueChanged(int)), + m_imageSelectionWidget, TQ_SLOT(slotChangeGuideSize(int))); + + connect(m_widthInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotWidthChanged(int))); + + connect(m_heightInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotHeightChanged(int))); + + connect(m_imageSelectionWidget, TQ_SIGNAL(signalSelectionChanged(TQRect)), + this, TQ_SLOT(slotSelectionChanged(TQRect))); + + connect(m_imageSelectionWidget, TQ_SIGNAL(signalSelectionMoved(TQRect)), + this, TQ_SLOT(slotSelectionChanged(TQRect))); + + connect(m_imageSelectionWidget, TQ_SIGNAL(signalSelectionOrientationChanged(int)), + this, TQ_SLOT(slotSelectionOrientationChanged(int))); + + connect(m_centerWidth, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotCenterWidth())); + + connect(m_centerHeight, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotCenterHeight())); + + // we need to disconnect the standard connection of the Try button first + disconnect(m_gboxSettings, TQ_SIGNAL(signalTryClicked()), + this, TQ_SLOT(slotEffect())); + + connect(m_gboxSettings, TQ_SIGNAL(signalTryClicked()), + this, TQ_SLOT(slotMaxAspectRatio())); + + // ------------------------------------------------------------- + + // Sets current region selection + slotSelectionChanged(m_imageSelectionWidget->getRegionSelection()); +} + +RatioCropTool::~RatioCropTool() +{ +} + +void RatioCropTool::readSettings() +{ + TQColor defaultGuideColor(250, 250, 255); + TDEConfig *config = kapp->config(); + config->setGroup("aspectratiocrop Tool"); + + // No guide lines per default. + m_guideLinesCB->setCurrentItem(config->readNumEntry("Guide Lines Type", ImageSelectionWidget::GuideNone)); + m_goldenSectionBox->setChecked(config->readBoolEntry("Golden Section", true)); + m_goldenSpiralSectionBox->setChecked(config->readBoolEntry("Golden Spiral Section", false)); + m_goldenSpiralBox->setChecked(config->readBoolEntry("Golden Spiral", false)); + m_goldenTriangleBox->setChecked(config->readBoolEntry("Golden Triangle", false)); + m_flipHorBox->setChecked(config->readBoolEntry("Golden Flip Horizontal", false)); + m_flipVerBox->setChecked(config->readBoolEntry("Golden Flip Vertical", false)); + m_guideColorBt->setColor(config->readColorEntry("Guide Color", &defaultGuideColor)); + m_guideSize->setValue(config->readNumEntry("Guide Width", m_guideSize->defaultValue())); + m_imageSelectionWidget->slotGuideLines(m_guideLinesCB->currentItem()); + m_imageSelectionWidget->slotChangeGuideColor(m_guideColorBt->color()); + + m_preciseCrop->setChecked(config->readBoolEntry("Precise Aspect Ratio Crop", false)); + m_imageSelectionWidget->setPreciseCrop(m_preciseCrop->isChecked()); + + // Empty selection so it can be moved w/out size constraint + m_widthInput->setValue(0); + m_heightInput->setValue(0); + + m_xInput->setValue(config->readNumEntry("Hor.Oriented Custom Aspect Ratio Xpos", + m_xInput->defaultValue())); + m_yInput->setValue(config->readNumEntry("Hor.Oriented Custom Aspect Ratio Ypos", + m_yInput->defaultValue())); + + m_widthInput->setValue(config->readNumEntry("Hor.Oriented Custom Aspect Ratio Width", + m_widthInput->defaultValue())); + m_heightInput->setValue(config->readNumEntry("Hor.Oriented Custom Aspect Ratio Height", + m_heightInput->defaultValue())); + + m_imageSelectionWidget->setSelectionOrientation(m_orientCB->currentItem()); + + m_customRatioNInput->setValue(config->readNumEntry("Hor.Oriented Custom Aspect Ratio Num", + m_customRatioNInput->defaultValue())); + m_customRatioDInput->setValue(config->readNumEntry("Hor.Oriented Custom Aspect Ratio Den", + m_customRatioDInput->defaultValue())); + + m_ratioCB->setCurrentItem(config->readNumEntry("Hor.Oriented Aspect Ratio", + m_ratioCB->defaultItem())); + + if (m_originalIsLandscape) + { + m_orientCB->setCurrentItem(config->readNumEntry("Hor.Oriented Aspect Ratio Orientation", + ImageSelectionWidget::Landscape)); + m_orientCB->setDefaultItem(ImageSelectionWidget::Landscape); + } + else + { + m_orientCB->setCurrentItem(config->readNumEntry("Ver.Oriented Aspect Ratio Orientation", + ImageSelectionWidget::Portrait)); + m_orientCB->setDefaultItem(ImageSelectionWidget::Portrait); + } + + applyRatioChanges(m_ratioCB->currentItem()); + + m_autoOrientation->setChecked( config->readBoolEntry("Auto Orientation", false) ); + slotAutoOrientChanged( m_autoOrientation->isChecked() ); +} + +void RatioCropTool::writeSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("aspectratiocrop Tool"); + + if (m_originalIsLandscape) + { + config->writeEntry("Hor.Oriented Aspect Ratio", m_ratioCB->currentItem()); + config->writeEntry("Hor.Oriented Aspect Ratio Orientation", m_orientCB->currentItem()); + config->writeEntry("Hor.Oriented Custom Aspect Ratio Num", m_customRatioNInput->value()); + config->writeEntry("Hor.Oriented Custom Aspect Ratio Den", m_customRatioDInput->value()); + + config->writeEntry("Hor.Oriented Custom Aspect Ratio Xpos", m_xInput->value()); + config->writeEntry("Hor.Oriented Custom Aspect Ratio Ypos", m_yInput->value()); + config->writeEntry("Hor.Oriented Custom Aspect Ratio Width", m_widthInput->value()); + config->writeEntry("Hor.Oriented Custom Aspect Ratio Height", m_heightInput->value()); + } + else + { + config->writeEntry("Ver.Oriented Aspect Ratio", m_ratioCB->currentItem()); + config->writeEntry("Ver.Oriented Aspect Ratio Orientation", m_orientCB->currentItem()); + config->writeEntry("Ver.Oriented Custom Aspect Ratio Num", m_customRatioNInput->value()); + config->writeEntry("Ver.Oriented Custom Aspect Ratio Den", m_customRatioDInput->value()); + + config->writeEntry("Ver.Oriented Custom Aspect Ratio Xpos", m_xInput->value()); + config->writeEntry("Ver.Oriented Custom Aspect Ratio Ypos", m_yInput->value()); + config->writeEntry("Ver.Oriented Custom Aspect Ratio Width", m_widthInput->value()); + config->writeEntry("Ver.Oriented Custom Aspect Ratio Height", m_heightInput->value()); + } + + config->writeEntry("Precise Aspect Ratio Crop", m_preciseCrop->isChecked()); + config->writeEntry("Auto Orientation", m_autoOrientation->isChecked()); + config->writeEntry("Guide Lines Type", m_guideLinesCB->currentItem()); + config->writeEntry("Golden Section", m_goldenSectionBox->isChecked()); + config->writeEntry("Golden Spiral Section", m_goldenSpiralSectionBox->isChecked()); + config->writeEntry("Golden Spiral", m_goldenSpiralBox->isChecked()); + config->writeEntry("Golden Triangle", m_goldenTriangleBox->isChecked()); + config->writeEntry("Golden Flip Horizontal", m_flipHorBox->isChecked()); + config->writeEntry("Golden Flip Vertical", m_flipVerBox->isChecked()); + config->writeEntry("Guide Color", m_guideColorBt->color()); + config->writeEntry("Guide Width", m_guideSize->value()); + config->sync(); +} + +void RatioCropTool::slotResetSettings() +{ + m_imageSelectionWidget->resetSelection(); +} + +void RatioCropTool::slotMaxAspectRatio() +{ + m_imageSelectionWidget->maxAspectSelection(); +} + +void RatioCropTool::slotCenterWidth() +{ + m_imageSelectionWidget->setCenterSelection(ImageSelectionWidget::CenterWidth); +} + +void RatioCropTool::slotCenterHeight() +{ + m_imageSelectionWidget->setCenterSelection(ImageSelectionWidget::CenterHeight); +} + +void RatioCropTool::slotSelectionChanged(TQRect rect) +{ + m_xInput->blockSignals(true); + m_yInput->blockSignals(true); + m_widthInput->blockSignals(true); + m_heightInput->blockSignals(true); + + m_xInput->setRange(0, m_imageSelectionWidget->getOriginalImageWidth() - rect.width(), 1); + m_yInput->setRange(0, m_imageSelectionWidget->getOriginalImageHeight() - rect.height(), 1); + + m_widthInput->setRange(m_imageSelectionWidget->getMinWidthRange(), + m_imageSelectionWidget->getMaxWidthRange(), + m_imageSelectionWidget->getWidthStep()); + + m_heightInput->setRange(m_imageSelectionWidget->getMinHeightRange(), + m_imageSelectionWidget->getMaxHeightRange(), + m_imageSelectionWidget->getHeightStep()); + + m_xInput->setValue(rect.x()); + m_yInput->setValue(rect.y()); + m_widthInput->setValue(rect.width()); + m_heightInput->setValue(rect.height()); + + m_gboxSettings->enableButton(EditorToolSettings::Ok, rect.isValid()); + m_preciseCrop->setEnabled(m_imageSelectionWidget->preciseCropAvailable()); + + m_xInput->blockSignals(false); + m_yInput->blockSignals(false); + m_widthInput->blockSignals(false); + m_heightInput->blockSignals(false); +} + +void RatioCropTool::setRatioCBText(int orientation) +{ + int item = m_ratioCB->currentItem(); + + m_ratioCB->blockSignals(true); + m_ratioCB->combo()->clear(); + m_ratioCB->insertItem(i18n("Custom")); + m_ratioCB->insertItem("1:1"); + if (orientation == ImageSelectionWidget::Landscape) + { + m_ratioCB->insertItem("3:2"); + m_ratioCB->insertItem("4:3"); + m_ratioCB->insertItem("5:4"); + m_ratioCB->insertItem("7:5"); + m_ratioCB->insertItem("10:7"); + } + else + { + m_ratioCB->insertItem("2:3"); + m_ratioCB->insertItem("3:4"); + m_ratioCB->insertItem("4:5"); + m_ratioCB->insertItem("5:7"); + m_ratioCB->insertItem("7:10"); + } + m_ratioCB->insertItem(i18n("Golden Ratio")); + m_ratioCB->insertItem(i18n("None")); + m_ratioCB->setCurrentItem(item); + m_ratioCB->blockSignals(false); +} + +void RatioCropTool::slotSelectionOrientationChanged(int newOrientation) +{ + // Change text for Aspect ratio ComboBox + + setRatioCBText(newOrientation); + + // Change Orientation ComboBox + + m_orientCB->setCurrentItem(newOrientation); + + // Reverse custom values + + if ( ( m_customRatioNInput->value() < m_customRatioDInput->value() && + newOrientation == ImageSelectionWidget::Landscape) || + ( m_customRatioNInput->value() > m_customRatioDInput->value() && + newOrientation == ImageSelectionWidget::Portrait)) + { + m_customRatioNInput->blockSignals(true); + m_customRatioDInput->blockSignals(true); + + int tmp = m_customRatioNInput->value(); + m_customRatioNInput->setValue(m_customRatioDInput->value()); + m_customRatioDInput->setValue(tmp); + + m_customRatioNInput->blockSignals(false); + m_customRatioDInput->blockSignals(false); + } +} + +void RatioCropTool::slotXChanged(int x) +{ + m_imageSelectionWidget->setSelectionX(x); +} + +void RatioCropTool::slotYChanged(int y) +{ + m_imageSelectionWidget->setSelectionY(y); +} + +void RatioCropTool::slotWidthChanged(int w) +{ + m_imageSelectionWidget->setSelectionWidth(w); +} + +void RatioCropTool::slotHeightChanged(int h) +{ + m_imageSelectionWidget->setSelectionHeight(h); +} + +void RatioCropTool::slotPreciseCropChanged(bool a) +{ + m_imageSelectionWidget->setPreciseCrop(a); +} + +void RatioCropTool::slotOrientChanged(int o) +{ + m_imageSelectionWidget->setSelectionOrientation(o); + + // Reset selection area. + slotResetSettings(); +} + +void RatioCropTool::slotAutoOrientChanged(bool a) +{ + m_orientCB->setEnabled(!a /*|| m_ratioCB->currentItem() == ImageSelectionWidget::RATIONONE*/); + m_imageSelectionWidget->setAutoOrientation(a); +} + +void RatioCropTool::slotRatioChanged(int a) +{ + applyRatioChanges(a); + + // Reset selection area. + slotResetSettings(); +} + +void RatioCropTool::applyRatioChanges(int a) +{ + m_imageSelectionWidget->setSelectionAspectRatioType(a); + + if (a == ImageSelectionWidget::RATIOCUSTOM) + { + m_customLabel1->setEnabled(true); + m_customLabel2->setEnabled(true); + m_customRatioNInput->setEnabled(true); + m_customRatioDInput->setEnabled(true); + m_orientLabel->setEnabled(true); + m_orientCB->setEnabled(!m_autoOrientation->isChecked()); + m_autoOrientation->setEnabled(true); + slotCustomRatioChanged(); + } + else if (a == ImageSelectionWidget::RATIONONE) + { + m_orientLabel->setEnabled(false); + m_orientCB->setEnabled(false); + m_autoOrientation->setEnabled(false); + m_customLabel1->setEnabled(false); + m_customLabel2->setEnabled(false); + m_customRatioNInput->setEnabled(false); + m_customRatioDInput->setEnabled(false); + } + else // Pre-config ratio selected. + { + m_orientLabel->setEnabled(true); + m_orientCB->setEnabled(!m_autoOrientation->isChecked()); + m_autoOrientation->setEnabled(true); + m_customLabel1->setEnabled(false); + m_customLabel2->setEnabled(false); + m_customRatioNInput->setEnabled(false); + m_customRatioDInput->setEnabled(false); + } +} + +void RatioCropTool::slotGuideTypeChanged(int t) +{ + if (t == ImageSelectionWidget::GuideNone) + { + m_goldenSectionBox->setEnabled(false); + m_goldenSpiralSectionBox->setEnabled(false); + m_goldenSpiralBox->setEnabled(false); + m_goldenTriangleBox->setEnabled(false); + m_flipHorBox->setEnabled(false); + m_flipVerBox->setEnabled(false); + m_colorGuideLabel->setEnabled(false); + m_guideColorBt->setEnabled(false); + m_guideSize->setEnabled(false); + } + else if (t == ImageSelectionWidget::RulesOfThirds) + { + m_goldenSectionBox->setEnabled(false); + m_goldenSpiralSectionBox->setEnabled(false); + m_goldenSpiralBox->setEnabled(false); + m_goldenTriangleBox->setEnabled(false); + m_flipHorBox->setEnabled(false); + m_flipVerBox->setEnabled(false); + m_colorGuideLabel->setEnabled(true); + m_guideColorBt->setEnabled(true); + m_guideSize->setEnabled(true); + } + else if (t == ImageSelectionWidget::DiagonalMethod) + { + m_goldenSectionBox->setEnabled(false); + m_goldenSpiralSectionBox->setEnabled(false); + m_goldenSpiralBox->setEnabled(false); + m_goldenTriangleBox->setEnabled(false); + m_flipHorBox->setEnabled(false); + m_flipVerBox->setEnabled(false); + m_colorGuideLabel->setEnabled(true); + m_guideColorBt->setEnabled(true); + m_guideSize->setEnabled(true); + } + else if (t == ImageSelectionWidget::HarmoniousTriangles) + { + m_goldenSectionBox->setEnabled(false); + m_goldenSpiralSectionBox->setEnabled(false); + m_goldenSpiralBox->setEnabled(false); + m_goldenTriangleBox->setEnabled(false); + m_flipHorBox->setEnabled(true); + m_flipVerBox->setEnabled(true); + m_colorGuideLabel->setEnabled(true); + m_guideColorBt->setEnabled(true); + m_guideSize->setEnabled(true); + } + else + { + m_goldenSectionBox->setEnabled(true); + m_goldenSpiralSectionBox->setEnabled(true); + m_goldenSpiralBox->setEnabled(true); + m_goldenTriangleBox->setEnabled(true); + m_flipHorBox->setEnabled(true); + m_flipVerBox->setEnabled(true); + m_colorGuideLabel->setEnabled(true); + m_guideColorBt->setEnabled(true); + m_guideSize->setEnabled(true); + } + + m_imageSelectionWidget->setGoldenGuideTypes(m_goldenSectionBox->isChecked(), + m_goldenSpiralSectionBox->isChecked(), + m_goldenSpiralBox->isChecked(), + m_goldenTriangleBox->isChecked(), + m_flipHorBox->isChecked(), + m_flipVerBox->isChecked()); + m_imageSelectionWidget->slotGuideLines(t); +} + +void RatioCropTool::slotGoldenGuideTypeChanged() +{ + slotGuideTypeChanged(m_guideLinesCB->currentItem()); +} + +void RatioCropTool::slotCustomNRatioChanged(int a) +{ + if ( ! m_autoOrientation->isChecked() ) + { + if ( ( m_orientCB->currentItem() == ImageSelectionWidget::Portrait && + m_customRatioDInput->value() < a) || + ( m_orientCB->currentItem() == ImageSelectionWidget::Landscape && + m_customRatioDInput->value() > a)) + { + m_customRatioDInput->blockSignals(true); + m_customRatioDInput->setValue(a); + m_customRatioDInput->blockSignals(false); + } + } + + slotCustomRatioChanged(); +} + +void RatioCropTool::slotCustomDRatioChanged(int a) +{ + if ( ! m_autoOrientation->isChecked() ) + { + if ( ( m_orientCB->currentItem() == ImageSelectionWidget::Landscape && + m_customRatioNInput->value() < a) || + ( m_orientCB->currentItem() == ImageSelectionWidget::Portrait && + m_customRatioNInput->value() > a)) + { + m_customRatioNInput->blockSignals(true); + m_customRatioNInput->setValue(a); + m_customRatioNInput->blockSignals(false); + } + } + + slotCustomRatioChanged(); +} + +void RatioCropTool::slotCustomRatioChanged() +{ + m_imageSelectionWidget->setSelectionAspectRatioValue(m_customRatioNInput->value(), + m_customRatioDInput->value()); + + // Reset selection area. + slotResetSettings(); +} + +void RatioCropTool::finalRendering() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + + TQRect currentRegion = m_imageSelectionWidget->getRegionSelection(); + ImageIface* iface = m_imageSelectionWidget->imageIface(); + uchar *data = iface->getOriginalImage(); + int w = iface->originalWidth(); + int h = iface->originalHeight(); + bool a = iface->originalHasAlpha(); + bool sb = iface->originalSixteenBit(); + + TQRect normalizedRegion = currentRegion.normalize(); + if (normalizedRegion.right() > w) + normalizedRegion.setRight(w); + + if (normalizedRegion.bottom() > h) + normalizedRegion.setBottom(h); + + DImg imOrg(w, h, sb, a, data); + delete [] data; + imOrg.crop(normalizedRegion); + + iface->putOriginalImage(i18n("Aspect Ratio Crop"), imOrg.bits(), imOrg.width(), imOrg.height()); + + kapp->restoreOverrideCursor(); + writeSettings(); +} + +} // NameSpace DigikamImagesPluginCore diff --git a/src/imageplugins/coreplugin/ratiocrop/ratiocroptool.h b/src/imageplugins/coreplugin/ratiocrop/ratiocroptool.h new file mode 100644 index 00000000..833677da --- /dev/null +++ b/src/imageplugins/coreplugin/ratiocrop/ratiocroptool.h @@ -0,0 +1,135 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-06 + * Description : digiKam image editor Ratio Crop tool + * + * Copyright (C) 2007 by Jaromir Malenko <malenko at email dot cz> + * Copyright (C) 2008 by Roberto Castagnola <roberto dot castagnola at gmail dot com> + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef RATIOCROPTOOL_H +#define RATIOCROPTOOL_H + +// Digikam includes. + +#include "editortool.h" + +class TQCheckBox; +class TQLabel; +class TQToolButton; + +class KColorButton; + +namespace KDcrawIface +{ +class RComboBox; +class RIntNumInput; +} + +namespace DigikamImagesPluginCore +{ + +class ImageSelectionWidget; + +class RatioCropTool : public Digikam::EditorTool +{ + TQ_OBJECT + + +public: + + RatioCropTool(TQObject *parent); + ~RatioCropTool(); + +private: + + void readSettings(); + void writeSettings(); + void finalRendering(); + + void applyRatioChanges(int a); + void setRatioCBText(int orientation); + +private slots: + + void slotMaxAspectRatio(); + void slotResetSettings(); + + void slotCenterWidth(); + void slotCenterHeight(); + void slotXChanged(int x); + void slotYChanged(int y); + void slotWidthChanged(int w); + void slotHeightChanged(int h); + void slotCustomRatioChanged(); + void slotCustomNRatioChanged(int a); + void slotCustomDRatioChanged(int a); + void slotPreciseCropChanged(bool a); + void slotOrientChanged(int o); + void slotAutoOrientChanged(bool a); + void slotRatioChanged(int a); + void slotSelectionChanged(TQRect rect ); + void slotSelectionOrientationChanged(int); + void slotGuideTypeChanged(int t); + void slotGoldenGuideTypeChanged(); + +private: + + bool m_originalIsLandscape; + + TQLabel *m_customLabel1; + TQLabel *m_customLabel2; + TQLabel *m_orientLabel; + TQLabel *m_colorGuideLabel; + + + TQToolButton *m_centerWidth; + TQToolButton *m_centerHeight; + + TQCheckBox *m_goldenSectionBox; + TQCheckBox *m_goldenSpiralSectionBox; + TQCheckBox *m_goldenSpiralBox; + TQCheckBox *m_goldenTriangleBox; + TQCheckBox *m_flipHorBox; + TQCheckBox *m_flipVerBox; + TQCheckBox *m_autoOrientation; + TQCheckBox *m_preciseCrop; + + KDcrawIface::RComboBox *m_guideLinesCB; + KDcrawIface::RComboBox *m_orientCB; + KDcrawIface::RComboBox *m_ratioCB; + + KDcrawIface::RIntNumInput *m_customRatioDInput; + KDcrawIface::RIntNumInput *m_customRatioNInput; + KDcrawIface::RIntNumInput *m_guideSize; + KDcrawIface::RIntNumInput *m_heightInput; + KDcrawIface::RIntNumInput *m_widthInput; + KDcrawIface::RIntNumInput *m_xInput; + KDcrawIface::RIntNumInput *m_yInput; + + KColorButton *m_guideColorBt; + + ImageSelectionWidget *m_imageSelectionWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* RATIOCROPTOOL_H */ diff --git a/src/imageplugins/coreplugin/redeyetool.cpp b/src/imageplugins/coreplugin/redeyetool.cpp new file mode 100644 index 00000000..5b5af7e7 --- /dev/null +++ b/src/imageplugins/coreplugin/redeyetool.cpp @@ -0,0 +1,587 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-06-06 + * Description : Red eyes correction tool for image editor + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqcolor.h> +#include <tqhbox.h> +#include <tqhgroupbox.h> +#include <tqvgroupbox.h> +#include <tqhbuttongroup.h> +#include <tqvbox.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqframe.h> +#include <tqlabel.h> +#include <tqpushbutton.h> +#include <tqcombobox.h> +#include <tqwhatsthis.h> +#include <tqtooltip.h> + +// KDE includes. + +#include <tdeapplication.h> +#include <kcolordialog.h> +#include <kcolordialog.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <kstandarddirs.h> + +// Digikam includes. + +#include "bcgmodifier.h" +#include "colorgradientwidget.h" +#include "dimg.h" +#include "dimgimagefilters.h" +#include "editortoolsettings.h" +#include "histogramwidget.h" +#include "imageiface.h" +#include "imagewidget.h" + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> + +// Local includes. + +#include "redeyetool.h" +#include "redeyetool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamImagesPluginCore +{ + +RedEyeTool::RedEyeTool(TQObject* parent) + : EditorTool(parent) +{ + setName("redeye"); + setToolName(i18n("Red Eye")); + setToolIcon(SmallIcon("redeyes")); + setToolHelp("redeyecorrectiontool.anchor"); + + m_destinationPreviewData = 0; + + m_previewWidget = new ImageWidget("redeye Tool", 0, + i18n("<p>Here you can see the image selection preview with " + "red eye reduction applied."), + true, ImageGuideWidget::PickColorMode, true, true); + setToolView(m_previewWidget); + + // ------------------------------------------------------------- + + EditorToolSettings *gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel); + + TQGridLayout* gridSettings = new TQGridLayout(gboxSettings->plainPage(), 11, 4); + + TQLabel *label1 = new TQLabel(i18n("Channel:"), gboxSettings->plainPage()); + label1->setAlignment(TQt::AlignRight | TQt::AlignVCenter); + m_channelCB = new TQComboBox(false, 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("<p>Select the histogram channel to display here:<p>" + "<b>Luminosity</b>: display the image's luminosity values.<p>" + "<b>Red</b>: display the red image channel values.<p>" + "<b>Green</b>: display the green image channel values.<p>" + "<b>Blue</b>: display the blue image channel values.<p>")); + + m_scaleBG = new TQHButtonGroup(gboxSettings->plainPage()); + m_scaleBG->setExclusive(true); + m_scaleBG->setFrameShape(TQFrame::NoFrame); + m_scaleBG->setInsideMargin(0); + TQWhatsThis::add( m_scaleBG, i18n("<p>Select the histogram scale here.<p>" + "If the image's maximum counts are small, you can use the linear scale.<p>" + "The logarithmic scale can be used when the maximal counts are big " + "to show all values (small and large) on the graph.")); + + TQPushButton *linHistoButton = new TQPushButton(m_scaleBG); + TQToolTip::add(linHistoButton, i18n("<p>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("<p>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); + + // ------------------------------------------------------------- + + TQVBox *histoBox = new TQVBox(gboxSettings->plainPage()); + m_histogramWidget = new HistogramWidget(256, 140, histoBox, false, true, true); + TQWhatsThis::add( m_histogramWidget, i18n("<p>Here you can see the target preview image histogram " + "of the selected image channel. It is " + "updated upon 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")); + + // ------------------------------------------------------------- + + m_thresholdLabel = new TQLabel(i18n("Sensitivity:"), gboxSettings->plainPage()); + m_redThreshold = new RIntNumInput(gboxSettings->plainPage()); + m_redThreshold->setRange(10, 90, 1); + m_redThreshold->setDefaultValue(20); + TQWhatsThis::add(m_redThreshold, i18n("<p>Sets the red color pixels selection threshold. " + "Low values will select more red color pixels (agressive correction), high " + "values less (mild correction). Use low value if eye have been selected " + "exactly. Use high value if other parts of the face are also selected.")); + + m_smoothLabel = new TQLabel(i18n("Smooth:"), gboxSettings->plainPage()); + m_smoothLevel = new RIntNumInput(gboxSettings->plainPage()); + m_smoothLevel->setRange(0, 5, 1); + m_smoothLevel->setDefaultValue(1); + TQWhatsThis::add(m_smoothLevel, i18n("<p>Sets the smoothness value when blurring the border " + "of the changed pixels. " + "This leads to a more naturally looking pupil.")); + + TQLabel *label3 = new TQLabel(i18n("Coloring Tint:"), gboxSettings->plainPage()); + m_HSSelector = new KHSSelector(gboxSettings->plainPage()); + m_VSelector = new KValueSelector(gboxSettings->plainPage()); + m_HSSelector->setMinimumSize(200, 142); + m_VSelector->setMinimumSize(26, 142); + TQWhatsThis::add(m_HSSelector, i18n("<p>Sets a custom color to re-colorize the eyes.")); + + TQLabel *label4 = new TQLabel(i18n("Tint Level:"), gboxSettings->plainPage()); + m_tintLevel = new RIntNumInput(gboxSettings->plainPage()); + m_tintLevel->setRange(1, 200, 1); + m_tintLevel->setDefaultValue(128); + TQWhatsThis::add(m_tintLevel, i18n("<p>Set the tint level to adjust the luminosity of " + "the new color of the pupil.")); + + gridSettings->addMultiCellLayout(l1, 0, 0, 0, 4); + gridSettings->addMultiCellWidget(histoBox, 1, 2, 0, 4); + gridSettings->addMultiCellWidget(m_thresholdLabel, 3, 3, 0, 4); + gridSettings->addMultiCellWidget(m_redThreshold, 4, 4, 0, 4); + gridSettings->addMultiCellWidget(m_smoothLabel, 5, 5, 0, 4); + gridSettings->addMultiCellWidget(m_smoothLevel, 6, 6, 0, 4); + gridSettings->addMultiCellWidget(label3, 7, 7, 0, 4); + gridSettings->addMultiCellWidget(m_HSSelector, 8, 8, 0, 3); + gridSettings->addMultiCellWidget(m_VSelector, 8, 8, 4, 4); + gridSettings->addMultiCellWidget(label4, 9, 9, 0, 4); + gridSettings->addMultiCellWidget(m_tintLevel, 10, 10, 0, 4); + gridSettings->setRowStretch(11, 10); + gridSettings->setColStretch(3, 10); + + setToolSettings(gboxSettings); + init(); + + // ------------------------------------------------------------- + + 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_previewWidget, TQ_SIGNAL(spotPositionChangedFromTarget(const Digikam::DColor&, const TQPoint&)), + this, TQ_SLOT(slotColorSelectedFromTarget(const Digikam::DColor&))); + + connect(m_previewWidget, TQ_SIGNAL(signalResized()), + this, TQ_SLOT(slotEffect())); + + connect(m_redThreshold, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_smoothLevel, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_HSSelector, TQ_SIGNAL(valueChanged(int, int)), + this, TQ_SLOT(slotHSChanged(int, int))); + + connect(m_VSelector, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_tintLevel, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); +} + +RedEyeTool::~RedEyeTool() +{ + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; +} + +void RedEyeTool::slotHSChanged(int h, int s) +{ + m_VSelector->blockSignals(true); + m_VSelector->setHue(h); + m_VSelector->setSaturation(s); + m_VSelector->updateContents(); + m_VSelector->repaint(false); + m_VSelector->blockSignals(false); + slotTimer(); +} + +void RedEyeTool::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 RedEyeTool::slotScaleChanged(int scale) +{ + m_histogramWidget->m_scaleType = scale; + m_histogramWidget->repaint(false); +} + +void RedEyeTool::slotColorSelectedFromTarget(const DColor& color) +{ + m_histogramWidget->setHistogramGuideByColor(color); +} + +void RedEyeTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("redeye Tool"); + m_channelCB->setCurrentItem(config->readNumEntry("Histogram Channel", 0)); // Luminosity. + m_scaleBG->setButton(config->readNumEntry("Histogram Scale", HistogramWidget::LogScaleHistogram)); + m_redThreshold->setValue(config->readNumEntry("RedThreshold", m_redThreshold->defaultValue())); + m_smoothLevel->setValue(config->readNumEntry("SmoothLevel", m_smoothLevel->defaultValue())); + m_HSSelector->setXValue(config->readNumEntry("HueColoringTint", 0)); + m_HSSelector->setYValue(config->readNumEntry("SatColoringTint", 0)); + m_VSelector->setValue(config->readNumEntry("ValColoringTint", 0)); + m_tintLevel->setValue(config->readNumEntry("TintLevel", m_tintLevel->defaultValue())); + + slotHSChanged(m_HSSelector->xValue(), m_HSSelector->yValue()); + m_histogramWidget->reset(); + slotChannelChanged(m_channelCB->currentItem()); + slotScaleChanged(m_scaleBG->selectedId()); +} + +void RedEyeTool::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("redeye Tool"); + config->writeEntry("Histogram Channel", m_channelCB->currentItem()); + config->writeEntry("Histogram Scale", m_scaleBG->selectedId()); + config->writeEntry("RedThreshold", m_redThreshold->value()); + config->writeEntry("SmoothLevel", m_smoothLevel->value()); + config->writeEntry("HueColoringTint", m_HSSelector->xValue()); + config->writeEntry("SatColoringTint", m_HSSelector->yValue()); + config->writeEntry("ValColoringTint", m_VSelector->value()); + config->writeEntry("TintLevel", m_tintLevel->value()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void RedEyeTool::slotResetSettings() +{ + m_redThreshold->blockSignals(true); + m_HSSelector->blockSignals(true); + m_VSelector->blockSignals(true); + m_tintLevel->blockSignals(true); + + m_redThreshold->slotReset(); + m_smoothLevel->slotReset(); + + // Black color by default + m_HSSelector->setXValue(0); + m_HSSelector->setYValue(0); + m_VSelector->setValue(0); + + m_tintLevel->slotReset(); + + m_redThreshold->blockSignals(false); + m_HSSelector->blockSignals(false); + m_VSelector->blockSignals(false); + m_tintLevel->blockSignals(false); +} + +void RedEyeTool::slotEffect() +{ + kapp->setOverrideCursor(KCursor::waitCursor()); + + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + // Here, we need to use the real selection image data because we will apply + // a Gaussian blur filter on pixels and we cannot use directly the preview scaled image + // else the blur radius will not give the same result between preview and final rendering. + ImageIface* iface = m_previewWidget->imageIface(); + m_destinationPreviewData = iface->getImageSelection(); + int w = iface->selectedWidth(); + int h = iface->selectedHeight(); + bool sb = iface->originalSixteenBit(); + bool a = iface->originalHasAlpha(); + DImg selection(w, h, sb, a, m_destinationPreviewData); + + redEyeFilter(selection); + + DImg preview = selection.smoothScale(iface->previewWidth(), iface->previewHeight()); + + iface->putPreviewImage(preview.bits()); + m_previewWidget->updatePreview(); + + // Update histogram. + + memcpy(m_destinationPreviewData, selection.bits(), selection.numBytes()); + m_histogramWidget->updateData(m_destinationPreviewData, w, h, sb, 0, 0, 0, false); + + kapp->restoreOverrideCursor(); +} + +void RedEyeTool::finalRendering() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + + ImageIface* iface = m_previewWidget->imageIface(); + uchar *data = iface->getImageSelection(); + int w = iface->selectedWidth(); + int h = iface->selectedHeight(); + bool sixteenBit = iface->originalSixteenBit(); + bool hasAlpha = iface->originalHasAlpha(); + DImg selection(w, h, sixteenBit, hasAlpha, data); + delete [] data; + + redEyeFilter(selection); + + iface->putImageSelection(i18n("Red Eyes Correction"), selection.bits()); + + kapp->restoreOverrideCursor(); +} + +void RedEyeTool::redEyeFilter(DImg& selection) +{ + DImg mask(selection.width(), selection.height(), selection.sixteenBit(), true, + selection.bits(), true); + + selection = mask.copy(); + float redThreshold = m_redThreshold->value()/10.0; + int hue = m_HSSelector->xValue(); + int sat = m_HSSelector->yValue(); + int val = m_VSelector->value(); + KColor coloring; + coloring.setHsv(hue, sat, val); + + struct channel + { + float red_gain; + float green_gain; + float blue_gain; + }; + + channel red_chan, green_chan, blue_chan; + + red_chan.red_gain = 0.1; + red_chan.green_gain = 0.6; + red_chan.blue_gain = 0.3; + + green_chan.red_gain = 0.0; + green_chan.green_gain = 1.0; + green_chan.blue_gain = 0.0; + + blue_chan.red_gain = 0.0; + blue_chan.green_gain = 0.0; + blue_chan.blue_gain = 1.0; + + float red_norm, green_norm, blue_norm; + int level = 201 - m_tintLevel->value(); + + red_norm = 1.0 / (red_chan.red_gain + red_chan.green_gain + red_chan.blue_gain); + green_norm = 1.0 / (green_chan.red_gain + green_chan.green_gain + green_chan.blue_gain); + blue_norm = 1.0 / (blue_chan.red_gain + blue_chan.green_gain + blue_chan.blue_gain); + + red_norm *= coloring.red() / level; + green_norm *= coloring.green() / level; + blue_norm *= coloring.blue() / level; + + // Perform a red color pixels detection in selection image and create a correction mask using an alpha channel. + + if (!selection.sixteenBit()) // 8 bits image. + { + uchar* ptr = selection.bits(); + uchar* mptr = mask.bits(); + uchar r, g, b, r1, g1, b1; + + for (uint i = 0 ; i < selection.width() * selection.height() ; i++) + { + b = ptr[0]; + g = ptr[1]; + r = ptr[2]; + mptr[3] = 255; + + if (r >= ( redThreshold * g)) + { + r1 = TQMIN(255, (int)(red_norm * (red_chan.red_gain * r + + red_chan.green_gain * g + + red_chan.blue_gain * b))); + + g1 = TQMIN(255, (int)(green_norm * (green_chan.red_gain * r + + green_chan.green_gain * g + + green_chan.blue_gain * b))); + + b1 = TQMIN(255, (int)(blue_norm * (blue_chan.red_gain * r + + blue_chan.green_gain * g + + blue_chan.blue_gain * b))); + + mptr[0] = b1; + mptr[1] = g1; + mptr[2] = r1; + mptr[3] = TQMIN( (int)((r-g) / 150.0 * 255.0), 255); + } + + ptr += 4; + mptr+= 4; + } + } + else // 16 bits image. + { + unsigned short* ptr = (unsigned short*)selection.bits(); + unsigned short* mptr = (unsigned short*)mask.bits(); + unsigned short r, g, b, r1, g1, b1; + + for (uint i = 0 ; i < selection.width() * selection.height() ; i++) + { + b = ptr[0]; + g = ptr[1]; + r = ptr[2]; + mptr[3] = 65535; + + if (r >= ( redThreshold * g)) + { + r1 = TQMIN(65535, (int)(red_norm * (red_chan.red_gain * r + + red_chan.green_gain * g + + red_chan.blue_gain * b))); + + g1 = TQMIN(65535, (int)(green_norm * (green_chan.red_gain * r + + green_chan.green_gain * g + + green_chan.blue_gain * b))); + + b1 = TQMIN(65535, (int)(blue_norm * (blue_chan.red_gain * r + + blue_chan.green_gain * g + + blue_chan.blue_gain * b))); + + mptr[0] = b1; + mptr[1] = g1; + mptr[2] = r1; + mptr[3] = TQMIN( (int)((r-g) / 38400.0 * 65535.0), 65535);; + } + + ptr += 4; + mptr+= 4; + } + } + + // Now, we will blur only the transparency pixels from the mask. + + DImg mask2 = mask.copy(); + DImgImageFilters filter; + filter.gaussianBlurImage(mask2.bits(), mask2.width(), mask2.height(), + mask2.sixteenBit(), m_smoothLevel->value()); + + if (!selection.sixteenBit()) // 8 bits image. + { + uchar* mptr = mask.bits(); + uchar* mptr2 = mask2.bits(); + + for (uint i = 0 ; i < mask2.width() * mask2.height() ; i++) + { + if (mptr2[3] < 255) + { + mptr[0] = mptr2[0]; + mptr[1] = mptr2[1]; + mptr[2] = mptr2[2]; + mptr[3] = mptr2[3]; + } + + mptr += 4; + mptr2+= 4; + } + } + else // 16 bits image. + { + unsigned short* mptr = (unsigned short*)mask.bits(); + unsigned short* mptr2 = (unsigned short*)mask2.bits(); + + for (uint i = 0 ; i < mask2.width() * mask2.height() ; i++) + { + if (mptr2[3] < 65535) + { + mptr[0] = mptr2[0]; + mptr[1] = mptr2[1]; + mptr[2] = mptr2[2]; + mptr[3] = mptr2[3]; + } + + mptr += 4; + mptr2+= 4; + } + } + + // - Perform pixels blending using alpha channel between the mask and the selection. + + DColorComposer *composer = DColorComposer::getComposer(DColorComposer::PorterDuffSrcOver); + + // NOTE: 'mask' is the Source image, 'selection' is the Destination image. + + selection.bitBlendImage(composer, &mask, + 0, 0, mask.width(), mask.height(), + 0, 0); +} + +} // NameSpace DigikamImagesPluginCore diff --git a/src/imageplugins/coreplugin/redeyetool.h b/src/imageplugins/coreplugin/redeyetool.h new file mode 100644 index 00000000..eb614fd3 --- /dev/null +++ b/src/imageplugins/coreplugin/redeyetool.h @@ -0,0 +1,157 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-06-06 + * Description : Red eyes correction tool for image editor + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2004-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. + * + * ============================================================ */ + + +#ifndef REDEYETOOL_H +#define REDEYETOOL_H + +// KDE includes. + +#include <kpassivepopup.h> + +// Digikam includes. + +#include "editortool.h" + +class TQLabel; +class TQComboBox; +class TQHButtonGroup; + +class KHSSelector; +class KValueSelector; + +namespace KDcrawIface +{ +class RIntNumInput; +} + +namespace Digikam +{ +class HistogramWidget; +class ColorGradientWidget; +class ImageWidget; +class DColor; +class DImg; +} + +namespace DigikamImagesPluginCore +{ + +class RedEyePassivePopup : public KPassivePopup +{ +public: + + RedEyePassivePopup(TQWidget* parent) + : KPassivePopup(parent), m_parent(parent) + { + } + +protected: + + virtual void positionSelf() + { + move(m_parent->x() + 30, m_parent->y() + 30); + } + +private: + + TQWidget* m_parent; +}; + +// ---------------------------------------------------------------- + +class RedEyeTool : public Digikam::EditorTool +{ + TQ_OBJECT + + +public: + + RedEyeTool(TQObject *parent); + ~RedEyeTool(); + +private slots: + + void slotEffect(); + void slotResetSettings(); + void slotChannelChanged(int channel); + void slotScaleChanged(int scale); + void slotColorSelectedFromTarget(const Digikam::DColor &color); + void slotHSChanged(int h, int s); + +private: + + void readSettings(); + void writeSettings(); + void finalRendering(); + void redEyeFilter(Digikam::DImg& selection); + +private: + + enum HistogramScale + { + Linear=0, + Logarithmic + }; + + enum ColorChannel + { + LuminosityChannel=0, + RedChannel, + GreenChannel, + BlueChannel + }; + + enum RedThresold + { + Mild=0, + Aggressive + }; + + uchar *m_destinationPreviewData; + + TQLabel *m_thresholdLabel; + TQLabel *m_smoothLabel; + + TQComboBox *m_channelCB; + + TQHButtonGroup *m_scaleBG; + + KDcrawIface::RIntNumInput *m_tintLevel; + KDcrawIface::RIntNumInput *m_redThreshold; + KDcrawIface::RIntNumInput *m_smoothLevel; + + KHSSelector *m_HSSelector; + KValueSelector *m_VSelector; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::ColorGradientWidget *m_hGradient; + + Digikam::HistogramWidget *m_histogramWidget; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* REDEYETOOL_H */ diff --git a/src/imageplugins/coreplugin/rgbtool.cpp b/src/imageplugins/coreplugin/rgbtool.cpp new file mode 100644 index 00000000..e27e396e --- /dev/null +++ b/src/imageplugins/coreplugin/rgbtool.cpp @@ -0,0 +1,440 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-11 + * Description : digiKam image editor Color Balance tool. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqcheckbox.h> +#include <tqcolor.h> +#include <tqcombobox.h> +#include <tqframe.h> +#include <tqgroupbox.h> +#include <tqhbuttongroup.h> +#include <tqhgroupbox.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqpushbutton.h> +#include <tqslider.h> +#include <tqtooltip.h> +#include <tqvbox.h> +#include <tqvgroupbox.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <kstandarddirs.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> + +// Digikam includes. + +#include "colorgradientwidget.h" +#include "colormodifier.h" +#include "dimg.h" +#include "editortoolsettings.h" +#include "histogramwidget.h" +#include "imageiface.h" +#include "imagewidget.h" + +// Local includes. + +#include "rgbtool.h" +#include "rgbtool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamImagesPluginCore +{ + +RGBTool::RGBTool(TQObject* parent) + : EditorTool(parent) +{ + setName("colorbalance"); + setToolName(i18n("Color Balance")); + setToolIcon(SmallIcon("adjustrgb")); + + m_destinationPreviewData = 0; + + m_previewWidget = new ImageWidget("colorbalance Tool", 0, + i18n("<p>Here you can see the image " + "color-balance adjustments preview. " + "You can pick color on image " + "to see the color level corresponding on histogram.")); + setToolView(m_previewWidget); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel); + + TQGridLayout* gridSettings = new TQGridLayout(m_gboxSettings->plainPage(), 7, 4); + + 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("<p>Select the histogram channel to display here:<p>" + "<b>Luminosity</b>: display the image's luminosity values.<p>" + "<b>Red</b>: display the red image-channel values.<p>" + "<b>Green</b>: display the green image-channel values.<p>" + "<b>Blue</b>: display the blue image-channel values.<p>")); + + 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("<p>Select the histogram scale here.<p>" + "If the image's maximal counts are small, you can use the linear scale.<p>" + "Logarithmic scale can be used when the maximal counts 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("<p>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("<p>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, 4); + + // ------------------------------------------------------------- + + TQVBox *histoBox = new TQVBox(m_gboxSettings->plainPage()); + m_histogramWidget = new HistogramWidget(256, 140, histoBox, false, true, true); + TQWhatsThis::add( m_histogramWidget, i18n("<p>Here you can see the target preview image histogram drawing " + "of the selected image channel. This one is re-computed at any " + "settings 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, 4); + + // ------------------------------------------------------------- + + TQLabel *labelLeft = new TQLabel(i18n("Cyan"), m_gboxSettings->plainPage()); + labelLeft->setAlignment ( TQt::AlignRight | TQt::AlignVCenter ); + m_rSlider = new TQSlider(-100, 100, 1, 0, TQt::Horizontal, m_gboxSettings->plainPage(), "m_rSlider"); + m_rSlider->setTickmarks(TQSlider::Below); + m_rSlider->setTickInterval(20); + TQWhatsThis::add( m_rSlider, i18n("<p>Set here the cyan/red color adjustment of the image.")); + TQLabel *labelRight = new TQLabel(i18n("Red"), m_gboxSettings->plainPage()); + labelRight->setAlignment ( TQt::AlignLeft | TQt::AlignVCenter ); + m_rInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_rInput->setDefaultValue(0); + m_rInput->input()->setRange(-100, 100, 1, false); + + gridSettings->addMultiCellWidget(labelLeft, 3, 3, 0, 0); + gridSettings->addMultiCellWidget(m_rSlider, 3, 3, 1, 1); + gridSettings->addMultiCellWidget(labelRight, 3, 3, 2, 2); + gridSettings->addMultiCellWidget(m_rInput, 3, 3, 3, 3); + + // ------------------------------------------------------------- + + labelLeft = new TQLabel(i18n("Magenta"), m_gboxSettings->plainPage()); + labelLeft->setAlignment(TQt::AlignRight | TQt::AlignVCenter); + m_gSlider = new TQSlider(-100, 100, 1, 0, TQt::Horizontal, m_gboxSettings->plainPage(), "m_gSlider"); + m_gSlider->setTickmarks(TQSlider::Below); + m_gSlider->setTickInterval(20); + TQWhatsThis::add( m_gSlider, i18n("<p>Set here the magenta/green color adjustment of the image.")); + labelRight = new TQLabel(i18n("Green"), m_gboxSettings->plainPage()); + labelRight->setAlignment(TQt::AlignLeft | TQt::AlignVCenter); + m_gInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_gInput->setDefaultValue(0); + m_gInput->input()->setRange(-100, 100, 1, false); + + gridSettings->addMultiCellWidget(labelLeft, 4, 4, 0, 0); + gridSettings->addMultiCellWidget(m_gSlider, 4, 4, 1, 1); + gridSettings->addMultiCellWidget(labelRight, 4, 4, 2, 2); + gridSettings->addMultiCellWidget(m_gInput, 4, 4, 3, 3); + + // ------------------------------------------------------------- + + labelLeft = new TQLabel(i18n("Yellow"), m_gboxSettings->plainPage()); + labelLeft->setAlignment ( TQt::AlignRight | TQt::AlignVCenter ); + m_bSlider = new TQSlider(-100, 100, 1, 0, TQt::Horizontal, m_gboxSettings->plainPage(), "m_bSlider"); + m_bSlider->setTickmarks(TQSlider::Below); + m_bSlider->setTickInterval(20); + TQWhatsThis::add( m_bSlider, i18n("<p>Set here the yellow/blue color adjustment of the image.")); + labelRight = new TQLabel(i18n("Blue"), m_gboxSettings->plainPage()); + labelRight->setAlignment(TQt::AlignLeft | TQt::AlignVCenter); + m_bInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_bInput->setDefaultValue(0); + m_bInput->input()->setRange(-100, 100, 1, false); + + gridSettings->addMultiCellWidget(labelLeft, 5, 5, 0, 0); + gridSettings->addMultiCellWidget(m_bSlider, 5, 5, 1, 1); + gridSettings->addMultiCellWidget(labelRight, 5, 5, 2, 2); + gridSettings->addMultiCellWidget(m_bInput, 5, 5, 3, 3); + + m_rInput->setValue(0); + m_gInput->setValue(0); + m_bInput->setValue(0); + + gridSettings->setRowStretch(6, 10); + setToolSettings(m_gboxSettings); + init(); + + // ------------------------------------------------------------- + + 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_previewWidget, TQ_SIGNAL(spotPositionChangedFromTarget( const Digikam::DColor &, const TQPoint & )), + this, TQ_SLOT(slotColorSelectedFromTarget( const Digikam::DColor & ))); + + connect(m_rSlider, TQ_SIGNAL(valueChanged(int)), + m_rInput, TQ_SLOT(setValue(int))); + connect(m_rInput, TQ_SIGNAL(valueChanged (int)), + m_rSlider, TQ_SLOT(setValue(int))); + connect(m_rInput, TQ_SIGNAL(valueChanged (int)), + this, TQ_SLOT(slotTimer())); + + connect(m_gSlider, TQ_SIGNAL(valueChanged(int)), + m_gInput, TQ_SLOT(setValue(int))); + connect(m_gInput, TQ_SIGNAL(valueChanged (int)), + m_gSlider, TQ_SLOT(setValue(int))); + connect(m_gInput, TQ_SIGNAL(valueChanged (int)), + this, TQ_SLOT(slotTimer())); + + connect(m_bSlider, TQ_SIGNAL(valueChanged(int)), + m_bInput, TQ_SLOT(setValue(int))); + connect(m_bInput, TQ_SIGNAL(valueChanged (int)), + m_bSlider, TQ_SLOT(setValue(int))); + connect(m_bInput, TQ_SIGNAL(valueChanged (int)), + this, TQ_SLOT(slotTimer())); + + connect(m_previewWidget, TQ_SIGNAL(signalResized()), + this, TQ_SLOT(slotEffect())); + + // ------------------------------------------------------------- + + m_gboxSettings->enableButton(EditorToolSettings::Ok, false); +} + +RGBTool::~RGBTool() +{ + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; +} + +void RGBTool::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 RGBTool::slotScaleChanged(int scale) +{ + m_histogramWidget->m_scaleType = scale; + m_histogramWidget->repaint(false); +} + +void RGBTool::slotColorSelectedFromTarget(const DColor &color) +{ + m_histogramWidget->setHistogramGuideByColor(color); +} + +void RGBTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("colorbalance Tool"); + m_channelCB->setCurrentItem(config->readNumEntry("Histogram Channel", 0)); // Luminosity. + m_scaleBG->setButton(config->readNumEntry("Histogram Scale", HistogramWidget::LogScaleHistogram)); + int r = config->readNumEntry("RedAjustment", m_rInput->defaultValue()); + int g = config->readNumEntry("GreenAjustment", m_gInput->defaultValue()); + int b = config->readNumEntry("BlueAjustment", m_bInput->defaultValue()); + adjustSliders(r, g, b); + m_histogramWidget->reset(); + slotChannelChanged(m_channelCB->currentItem()); + slotScaleChanged(m_scaleBG->selectedId()); +} + +void RGBTool::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("colorbalance Tool"); + config->writeEntry("Histogram Channel", m_channelCB->currentItem()); + config->writeEntry("Histogram Scale", m_scaleBG->selectedId()); + config->writeEntry("RedAjustment", m_rSlider->value()); + config->writeEntry("GreenAjustment", m_gInput->value()); + config->writeEntry("BlueAjustment", m_bInput->value()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void RGBTool::slotResetSettings() +{ + int r = m_rInput->defaultValue(); + int g = m_gInput->defaultValue(); + int b = m_bInput->defaultValue(); + + adjustSliders(r, g, b); +} + +void RGBTool::adjustSliders(int r, int g, int b) +{ + m_rSlider->blockSignals(true); + m_gSlider->blockSignals(true); + m_bSlider->blockSignals(true); + m_rInput->blockSignals(true); + m_gInput->blockSignals(true); + m_bInput->blockSignals(true); + + m_rSlider->setValue(r); + m_gSlider->setValue(g); + m_bSlider->setValue(b); + m_rInput->setValue(r); + m_gInput->setValue(g); + m_bInput->setValue(b); + + m_rSlider->blockSignals(false); + m_gSlider->blockSignals(false); + m_bSlider->blockSignals(false); + m_rInput->blockSignals(false); + m_gInput->blockSignals(false); + m_bInput->blockSignals(false); + + slotEffect(); +} + +void RGBTool::slotEffect() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + + m_gboxSettings->enableButton(EditorToolSettings::Ok, + (m_rInput->value() != 0 || + m_gInput->value() != 0 || + m_bInput->value() != 0)); + + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + ImageIface* iface = m_previewWidget->imageIface(); + m_destinationPreviewData = iface->getPreviewImage(); + int w = iface->previewWidth(); + int h = iface->previewHeight(); + bool alpha = iface->previewHasAlpha(); + bool sixteenBit = iface->previewSixteenBit(); + + double r = ((double) m_rInput->value() + 100.0) / 100.0; + double g = ((double) m_gInput->value() + 100.0) / 100.0; + double b = ((double) m_bInput->value() + 100.0) / 100.0; + double a = 1.0; + + DImg preview(w, h, sixteenBit, alpha, m_destinationPreviewData); + ColorModifier cmod; + cmod.applyColorModifier(preview, r, g, b, a); + iface->putPreviewImage(preview.bits()); + + m_previewWidget->updatePreview(); + + // Update histogram. + + memcpy(m_destinationPreviewData, preview.bits(), preview.numBytes()); + m_histogramWidget->updateData(m_destinationPreviewData, w, h, sixteenBit, 0, 0, 0, false); + + kapp->restoreOverrideCursor(); +} + +void RGBTool::finalRendering() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + + double r = ((double) m_rInput->value() + 100.0) / 100.0; + double g = ((double) m_gInput->value() + 100.0) / 100.0; + double b = ((double) m_bInput->value() + 100.0) / 100.0; + double a = 1.0; + + ImageIface* iface = m_previewWidget->imageIface(); + uchar *data = iface->getOriginalImage(); + int w = iface->originalWidth(); + int h = iface->originalHeight(); + bool alpha = iface->originalHasAlpha(); + bool sixteenBit = iface->originalSixteenBit(); + DImg original(w, h, sixteenBit, alpha, data); + delete [] data; + + ColorModifier cmod; + cmod.applyColorModifier(original, r, g, b, a); + + iface->putOriginalImage(i18n("Color Balance"), original.bits()); + kapp->restoreOverrideCursor(); +} + +} // NameSpace DigikamImagesPluginCore + diff --git a/src/imageplugins/coreplugin/rgbtool.h b/src/imageplugins/coreplugin/rgbtool.h new file mode 100644 index 00000000..dadb6a0e --- /dev/null +++ b/src/imageplugins/coreplugin/rgbtool.h @@ -0,0 +1,119 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-11 + * Description : digiKam image editor Color Balance tool. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef RGBTOOL_H +#define RGBTOOL_H + +// Digikam includes. + +#include "editortool.h" + +class TQComboBox; +class TQHButtonGroup; + +class TQSlider; + +namespace KDcrawIface +{ +class RIntNumInput; +} + +namespace Digikam +{ +class HistogramWidget; +class ColorGradientWidget; +class ImageWidget; +class DColor; +} + +namespace DigikamImagesPluginCore +{ + +class RGBTool : public Digikam::EditorTool +{ + TQ_OBJECT + + +public: + + RGBTool(TQObject *parent); + ~RGBTool(); + +private: + + void writeSettings(); + void readSettings(); + void adjustSliders(int r, int g, int b); + void finalRendering(); + +private slots: + + void slotEffect(); + void slotResetSettings(); + void slotChannelChanged(int channel); + void slotScaleChanged(int scale); + void slotColorSelectedFromTarget( const Digikam::DColor &color ); + +private: + + enum HistogramScale + { + Linear=0, + Logarithmic + }; + + enum ColorChannel + { + LuminosityChannel=0, + RedChannel, + GreenChannel, + BlueChannel + }; + + uchar *m_destinationPreviewData; + + TQComboBox *m_channelCB; + + TQHButtonGroup *m_scaleBG; + + KDcrawIface::RIntNumInput *m_rInput; + KDcrawIface::RIntNumInput *m_gInput; + KDcrawIface::RIntNumInput *m_bInput; + + TQSlider *m_rSlider; + TQSlider *m_gSlider; + TQSlider *m_bSlider; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::ColorGradientWidget *m_hGradient; + + Digikam::HistogramWidget *m_histogramWidget; + + Digikam::EditorToolSettings *m_gboxSettings; + +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* RGBTOOL_H */ diff --git a/src/imageplugins/coreplugin/sharpnesseditor/Makefile.am b/src/imageplugins/coreplugin/sharpnesseditor/Makefile.am new file mode 100644 index 00000000..c02087ee --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/Makefile.am @@ -0,0 +1,32 @@ +SUBDIRS = clapack +COMPILE_FIRST = clapack + +noinst_LTLIBRARIES = libsharpnesseditor.la +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + -I$(top_srcdir)/src/imageplugins/coreplugin/sharpnesseditor/clapack \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +libsharpnesseditor_la_LIBADD = $(top_builddir)/src/imageplugins/coreplugin/sharpnesseditor/clapack/liblapack.la + +libsharpnesseditor_la_SOURCES = sharpentool.cpp unsharp.cpp matrix.cpp refocus.cpp + +libsharpnesseditor_la_LDFLAGS = $(all_libraries) + +noinst_HEADERS = sharpentool.h unsharp.h matrix.h refocus.h + diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/LICENCE b/src/imageplugins/coreplugin/sharpnesseditor/clapack/LICENCE new file mode 100644 index 00000000..a338f860 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/LICENCE @@ -0,0 +1,12 @@ +REDISTRIBUTABLE + +LAPACK is a freely-available software package. It is available from netlib via anonymous ftp and the World Wide Web. +Thus, it can be included in commercial software packages (and has been). We only ask that proper credit be given to the authors. + +Like all software, it is copyrighted. It is not trademarked, but we do ask the following: + +If you modify the source for these routines we ask that you change the name of the routine +and comment the changes made to the original. + +We will gladly answer any questions regarding the software. If a modification is done, however, +it is the responsibility of the person who modified the routine to provide support. diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/Makefile.am b/src/imageplugins/coreplugin/sharpnesseditor/clapack/Makefile.am new file mode 100644 index 00000000..bf478556 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/Makefile.am @@ -0,0 +1,7 @@ +noinst_LTLIBRARIES = liblapack.la + +liblapack_la_CFLAGS = -w + +noinst_HEADERS = blaswrap.h clapack.h f2c.h fio.h fmt.h fp.h + +liblapack_la_SOURCES = abort_.c dgesv.c dlaswp.c endfile.c idamax.c open.c sig_die.c wref.c close.c dgetf2.c dscal.c err.c ieeeck.c s_cmp.c s_stop.c wrtfmt.c dgemm.c dgetrf.c dswap.c fmt.c ilaenv.c s_copy.c wsfe.c dger.c dgetrs.c dtrsm.c fmtlib.c lsame.c sfe.c util.c xerbla.c diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/README b/src/imageplugins/coreplugin/sharpnesseditor/clapack/README new file mode 100644 index 00000000..530f73ee --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/README @@ -0,0 +1,2 @@ +The sources in this directory were copied from the CLAPACK +distribution (see http://www.netlib.org/clapack). diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/abort_.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/abort_.c new file mode 100644 index 00000000..67278e93 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/abort_.c @@ -0,0 +1,10 @@ +#include "stdio.h" +#include "f2c.h" + +extern void sig_die(char*,int); + +int abort_(void) +{ +sig_die("Fortran abort routine called", 1); +return 0; /* not reached */ +} diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/blaswrap.h b/src/imageplugins/coreplugin/sharpnesseditor/clapack/blaswrap.h new file mode 100644 index 00000000..84c08d30 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/blaswrap.h @@ -0,0 +1,158 @@ +/* CLAPACK 3.0 BLAS wrapper macros + * Feb 5, 2000 + */ + +#ifndef __BLASWRAP_H +#define __BLASWRAP_H + +#ifndef NO_BLAS_WRAP + +/* BLAS1 routines */ +#define srotg_ f2c_srotg +#define drotg_ f2c_drotg +#define srotmg_ f2c_srotmg +#define drotmg_ f2c_drotmg +#define srot_ f2c_srot +#define drot_ f2c_drot +#define srotm_ f2c_srotm +#define drotm_ f2c_drotm +#define sswap_ f2c_sswap +#define dswap_ f2c_dswap +#define cswap_ f2c_cswap +#define zswap_ f2c_zswap +#define sscal_ f2c_sscal +#define dscal_ f2c_dscal +#define cscal_ f2c_cscal +#define zscal_ f2c_zscal +#define csscal_ f2c_csscal +#define zdscal_ f2c_zdscal +#define scopy_ f2c_scopy +#define dcopy_ f2c_dcopy +#define ccopy_ f2c_ccopy +#define zcopy_ f2c_zcopy +#define saxpy_ f2c_saxpy +#define daxpy_ f2c_daxpy +#define caxpy_ f2c_caxpy +#define zaxpy_ f2c_zaxpy +#define sdot_ f2c_sdot +#define ddot_ f2c_ddot +#define cdotu_ f2c_cdotu +#define zdotu_ f2c_zdotu +#define cdotc_ f2c_cdotc +#define zdotc_ f2c_zdotc +#define snrm2_ f2c_snrm2 +#define dnrm2_ f2c_dnrm2 +#define scnrm2_ f2c_scnrm2 +#define dznrm2_ f2c_dznrm2 +#define sasum_ f2c_sasum +#define dasum_ f2c_dasum +#define scasum_ f2c_scasum +#define dzasum_ f2c_dzasum +#define isamax_ f2c_isamax +#define idamax_ f2c_idamax +#define icamax_ f2c_icamax +#define izamax_ f2c_izamax + +/* BLAS2 routines */ +#define sgemv_ f2c_sgemv +#define dgemv_ f2c_dgemv +#define cgemv_ f2c_cgemv +#define zgemv_ f2c_zgemv +#define sgbmv_ f2c_sgbmv +#define dgbmv_ f2c_dgbmv +#define cgbmv_ f2c_cgbmv +#define zgbmv_ f2c_zgbmv +#define chemv_ f2c_chemv +#define zhemv_ f2c_zhemv +#define chbmv_ f2c_chbmv +#define zhbmv_ f2c_zhbmv +#define chpmv_ f2c_chpmv +#define zhpmv_ f2c_zhpmv +#define ssymv_ f2c_ssymv +#define dsymv_ f2c_dsymv +#define ssbmv_ f2c_ssbmv +#define dsbmv_ f2c_dsbmv +#define sspmv_ f2c_sspmv +#define dspmv_ f2c_dspmv +#define strmv_ f2c_strmv +#define dtrmv_ f2c_dtrmv +#define ctrmv_ f2c_ctrmv +#define ztrmv_ f2c_ztrmv +#define stbmv_ f2c_stbmv +#define dtbmv_ f2c_dtbmv +#define ctbmv_ f2c_ctbmv +#define ztbmv_ f2c_ztbmv +#define stpmv_ f2c_stpmv +#define dtpmv_ f2c_dtpmv +#define ctpmv_ f2c_ctpmv +#define ztpmv_ f2c_ztpmv +#define strsv_ f2c_strsv +#define dtrsv_ f2c_dtrsv +#define ctrsv_ f2c_ctrsv +#define ztrsv_ f2c_ztrsv +#define stbsv_ f2c_stbsv +#define dtbsv_ f2c_dtbsv +#define ctbsv_ f2c_ctbsv +#define ztbsv_ f2c_ztbsv +#define stpsv_ f2c_stpsv +#define dtpsv_ f2c_dtpsv +#define ctpsv_ f2c_ctpsv +#define ztpsv_ f2c_ztpsv +#define sger_ f2c_sger +#define dger_ f2c_dger +#define cgeru_ f2c_cgeru +#define zgeru_ f2c_zgeru +#define cgerc_ f2c_cgerc +#define zgerc_ f2c_zgerc +#define cher_ f2c_cher +#define zher_ f2c_zher +#define chpr_ f2c_chpr +#define zhpr_ f2c_zhpr +#define cher2_ f2c_cher2 +#define zher2_ f2c_zher2 +#define chpr2_ f2c_chpr2 +#define zhpr2_ f2c_zhpr2 +#define ssyr_ f2c_ssyr +#define dsyr_ f2c_dsyr +#define sspr_ f2c_sspr +#define dspr_ f2c_dspr +#define ssyr2_ f2c_ssyr2 +#define dsyr2_ f2c_dsyr2 +#define sspr2_ f2c_sspr2 +#define dspr2_ f2c_dspr2 + +/* BLAS3 routines */ +#define sgemm_ f2c_sgemm +#define dgemm_ f2c_dgemm +#define cgemm_ f2c_cgemm +#define zgemm_ f2c_zgemm +#define ssymm_ f2c_ssymm +#define dsymm_ f2c_dsymm +#define csymm_ f2c_csymm +#define zsymm_ f2c_zsymm +#define chemm_ f2c_chemm +#define zhemm_ f2c_zhemm +#define ssyrk_ f2c_ssyrk +#define dsyrk_ f2c_dsyrk +#define csyrk_ f2c_csyrk +#define zsyrk_ f2c_zsyrk +#define cherk_ f2c_cherk +#define zherk_ f2c_zherk +#define ssyr2k_ f2c_ssyr2k +#define dsyr2k_ f2c_dsyr2k +#define csyr2k_ f2c_csyr2k +#define zsyr2k_ f2c_zsyr2k +#define cher2k_ f2c_cher2k +#define zher2k_ f2c_zher2k +#define strmm_ f2c_strmm +#define dtrmm_ f2c_dtrmm +#define ctrmm_ f2c_ctrmm +#define ztrmm_ f2c_ztrmm +#define strsm_ f2c_strsm +#define dtrsm_ f2c_dtrsm +#define ctrsm_ f2c_ctrsm +#define ztrsm_ f2c_ztrsm + +#endif /* NO_BLAS_WRAP */ + +#endif /* __BLASWRAP_H */ diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/clapack.h b/src/imageplugins/coreplugin/sharpnesseditor/clapack/clapack.h new file mode 100644 index 00000000..cad9a4c2 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/clapack.h @@ -0,0 +1,5079 @@ +#ifndef __CLAPACK_H +#define __CLAPACK_H + +/* Subroutine */ int cbdsqr_(char *uplo, integer *n, integer *ncvt, integer * + nru, integer *ncc, real *d__, real *e, complex *vt, integer *ldvt, + complex *u, integer *ldu, complex *c__, integer *ldc, real *rwork, + integer *info); + +/* Subroutine */ int cgbbrd_(char *vect, integer *m, integer *n, integer *ncc, + integer *kl, integer *ku, complex *ab, integer *ldab, real *d__, + real *e, complex *q, integer *ldq, complex *pt, integer *ldpt, + complex *c__, integer *ldc, complex *work, real *rwork, integer *info); + +/* Subroutine */ int cgbcon_(char *norm, integer *n, integer *kl, integer *ku, + complex *ab, integer *ldab, integer *ipiv, real *anorm, real *rcond, + complex *work, real *rwork, integer *info); + +/* Subroutine */ int cgbequ_(integer *m, integer *n, integer *kl, integer *ku, + complex *ab, integer *ldab, real *r__, real *c__, real *rowcnd, real + *colcnd, real *amax, integer *info); + +/* Subroutine */ int cgbrfs_(char *trans, integer *n, integer *kl, integer * + ku, integer *nrhs, complex *ab, integer *ldab, complex *afb, integer * + ldafb, integer *ipiv, complex *b, integer *ldb, complex *x, integer * + ldx, real *ferr, real *berr, complex *work, real *rwork, integer * + info); + +/* Subroutine */ int cgbsv_(integer *n, integer *kl, integer *ku, integer * + nrhs, complex *ab, integer *ldab, integer *ipiv, complex *b, integer * + ldb, integer *info); + +/* Subroutine */ int cgbsvx_(char *fact, char *trans, integer *n, integer *kl, + integer *ku, integer *nrhs, complex *ab, integer *ldab, complex *afb, + integer *ldafb, integer *ipiv, char *equed, real *r__, real *c__, + complex *b, integer *ldb, complex *x, integer *ldx, real *rcond, real + *ferr, real *berr, complex *work, real *rwork, integer *info); + +/* Subroutine */ int cgbtf2_(integer *m, integer *n, integer *kl, integer *ku, + complex *ab, integer *ldab, integer *ipiv, integer *info); + +/* Subroutine */ int cgbtrf_(integer *m, integer *n, integer *kl, integer *ku, + complex *ab, integer *ldab, integer *ipiv, integer *info); + +/* Subroutine */ int cgbtrs_(char *trans, integer *n, integer *kl, integer * + ku, integer *nrhs, complex *ab, integer *ldab, integer *ipiv, complex + *b, integer *ldb, integer *info); + +/* Subroutine */ int cgebak_(char *job, char *side, integer *n, integer *ilo, + integer *ihi, real *scale, integer *m, complex *v, integer *ldv, + integer *info); + +/* Subroutine */ int cgebal_(char *job, integer *n, complex *a, integer *lda, + integer *ilo, integer *ihi, real *scale, integer *info); + +/* Subroutine */ int cgebd2_(integer *m, integer *n, complex *a, integer *lda, + real *d__, real *e, complex *tauq, complex *taup, complex *work, + integer *info); + +/* Subroutine */ int cgebrd_(integer *m, integer *n, complex *a, integer *lda, + real *d__, real *e, complex *tauq, complex *taup, complex *work, + integer *lwork, integer *info); + +/* Subroutine */ int cgecon_(char *norm, integer *n, complex *a, integer *lda, + real *anorm, real *rcond, complex *work, real *rwork, integer *info); + +/* Subroutine */ int cgeequ_(integer *m, integer *n, complex *a, integer *lda, + real *r__, real *c__, real *rowcnd, real *colcnd, real *amax, + integer *info); + +/* Subroutine */ int cgees_(char *jobvs, char *sort, L_fp select, integer *n, + complex *a, integer *lda, integer *sdim, complex *w, complex *vs, + integer *ldvs, complex *work, integer *lwork, real *rwork, logical * + bwork, integer *info); + +/* Subroutine */ int cgeesx_(char *jobvs, char *sort, L_fp select, char * + sense, integer *n, complex *a, integer *lda, integer *sdim, complex * + w, complex *vs, integer *ldvs, real *rconde, real *rcondv, complex * + work, integer *lwork, real *rwork, logical *bwork, integer *info); + +/* Subroutine */ int cgeev_(char *jobvl, char *jobvr, integer *n, complex *a, + integer *lda, complex *w, complex *vl, integer *ldvl, complex *vr, + integer *ldvr, complex *work, integer *lwork, real *rwork, integer * + info); + +/* Subroutine */ int cgeevx_(char *balanc, char *jobvl, char *jobvr, char * + sense, integer *n, complex *a, integer *lda, complex *w, complex *vl, + integer *ldvl, complex *vr, integer *ldvr, integer *ilo, integer *ihi, + real *scale, real *abnrm, real *rconde, real *rcondv, complex *work, + integer *lwork, real *rwork, integer *info); + +/* Subroutine */ int cgegs_(char *jobvsl, char *jobvsr, integer *n, complex * + a, integer *lda, complex *b, integer *ldb, complex *alpha, complex * + beta, complex *vsl, integer *ldvsl, complex *vsr, integer *ldvsr, + complex *work, integer *lwork, real *rwork, integer *info); + +/* Subroutine */ int cgegv_(char *jobvl, char *jobvr, integer *n, complex *a, + integer *lda, complex *b, integer *ldb, complex *alpha, complex *beta, + complex *vl, integer *ldvl, complex *vr, integer *ldvr, complex * + work, integer *lwork, real *rwork, integer *info); + +/* Subroutine */ int cgehd2_(integer *n, integer *ilo, integer *ihi, complex * + a, integer *lda, complex *tau, complex *work, integer *info); + +/* Subroutine */ int cgehrd_(integer *n, integer *ilo, integer *ihi, complex * + a, integer *lda, complex *tau, complex *work, integer *lwork, integer + *info); + +/* Subroutine */ int cgelq2_(integer *m, integer *n, complex *a, integer *lda, + complex *tau, complex *work, integer *info); + +/* Subroutine */ int cgelqf_(integer *m, integer *n, complex *a, integer *lda, + complex *tau, complex *work, integer *lwork, integer *info); + +/* Subroutine */ int cgels_(char *trans, integer *m, integer *n, integer * + nrhs, complex *a, integer *lda, complex *b, integer *ldb, complex * + work, integer *lwork, integer *info); + +/* Subroutine */ int cgelsx_(integer *m, integer *n, integer *nrhs, complex * + a, integer *lda, complex *b, integer *ldb, integer *jpvt, real *rcond, + integer *rank, complex *work, real *rwork, integer *info); + +/* Subroutine */ int cgelsy_(integer *m, integer *n, integer *nrhs, complex * + a, integer *lda, complex *b, integer *ldb, integer *jpvt, real *rcond, + integer *rank, complex *work, integer *lwork, real *rwork, integer * + info); + +/* Subroutine */ int cgeql2_(integer *m, integer *n, complex *a, integer *lda, + complex *tau, complex *work, integer *info); + +/* Subroutine */ int cgeqlf_(integer *m, integer *n, complex *a, integer *lda, + complex *tau, complex *work, integer *lwork, integer *info); + +/* Subroutine */ int cgeqp3_(integer *m, integer *n, complex *a, integer *lda, + integer *jpvt, complex *tau, complex *work, integer *lwork, real * + rwork, integer *info); + +/* Subroutine */ int cgeqpf_(integer *m, integer *n, complex *a, integer *lda, + integer *jpvt, complex *tau, complex *work, real *rwork, integer * + info); + +/* Subroutine */ int cgeqr2_(integer *m, integer *n, complex *a, integer *lda, + complex *tau, complex *work, integer *info); + +/* Subroutine */ int cgeqrf_(integer *m, integer *n, complex *a, integer *lda, + complex *tau, complex *work, integer *lwork, integer *info); + +/* Subroutine */ int cgerfs_(char *trans, integer *n, integer *nrhs, complex * + a, integer *lda, complex *af, integer *ldaf, integer *ipiv, complex * + b, integer *ldb, complex *x, integer *ldx, real *ferr, real *berr, + complex *work, real *rwork, integer *info); + +/* Subroutine */ int cgerq2_(integer *m, integer *n, complex *a, integer *lda, + complex *tau, complex *work, integer *info); + +/* Subroutine */ int cgerqf_(integer *m, integer *n, complex *a, integer *lda, + complex *tau, complex *work, integer *lwork, integer *info); + +/* Subroutine */ int cgesc2_(integer *n, complex *a, integer *lda, complex * + rhs, integer *ipiv, integer *jpiv, real *scale); + +/* Subroutine */ int cgesv_(integer *n, integer *nrhs, complex *a, integer * + lda, integer *ipiv, complex *b, integer *ldb, integer *info); + +/* Subroutine */ int cgesvx_(char *fact, char *trans, integer *n, integer * + nrhs, complex *a, integer *lda, complex *af, integer *ldaf, integer * + ipiv, char *equed, real *r__, real *c__, complex *b, integer *ldb, + complex *x, integer *ldx, real *rcond, real *ferr, real *berr, + complex *work, real *rwork, integer *info); + +/* Subroutine */ int cgetc2_(integer *n, complex *a, integer *lda, integer * + ipiv, integer *jpiv, integer *info); + +/* Subroutine */ int cgetf2_(integer *m, integer *n, complex *a, integer *lda, + integer *ipiv, integer *info); + +/* Subroutine */ int cgetrf_(integer *m, integer *n, complex *a, integer *lda, + integer *ipiv, integer *info); + +/* Subroutine */ int cgetri_(integer *n, complex *a, integer *lda, integer * + ipiv, complex *work, integer *lwork, integer *info); + +/* Subroutine */ int cgetrs_(char *trans, integer *n, integer *nrhs, complex * + a, integer *lda, integer *ipiv, complex *b, integer *ldb, integer * + info); + +/* Subroutine */ int cggbak_(char *job, char *side, integer *n, integer *ilo, + integer *ihi, real *lscale, real *rscale, integer *m, complex *v, + integer *ldv, integer *info); + +/* Subroutine */ int cggbal_(char *job, integer *n, complex *a, integer *lda, + complex *b, integer *ldb, integer *ilo, integer *ihi, real *lscale, + real *rscale, real *work, integer *info); + +/* Subroutine */ int cgges_(char *jobvsl, char *jobvsr, char *sort, L_fp + selctg, integer *n, complex *a, integer *lda, complex *b, integer * + ldb, integer *sdim, complex *alpha, complex *beta, complex *vsl, + integer *ldvsl, complex *vsr, integer *ldvsr, complex *work, integer * + lwork, real *rwork, logical *bwork, integer *info); + +/* Subroutine */ int cggesx_(char *jobvsl, char *jobvsr, char *sort, L_fp + selctg, char *sense, integer *n, complex *a, integer *lda, complex *b, + integer *ldb, integer *sdim, complex *alpha, complex *beta, complex * + vsl, integer *ldvsl, complex *vsr, integer *ldvsr, real *rconde, real + *rcondv, complex *work, integer *lwork, real *rwork, integer *iwork, + integer *liwork, logical *bwork, integer *info); + +/* Subroutine */ int cggev_(char *jobvl, char *jobvr, integer *n, complex *a, + integer *lda, complex *b, integer *ldb, complex *alpha, complex *beta, + complex *vl, integer *ldvl, complex *vr, integer *ldvr, complex * + work, integer *lwork, real *rwork, integer *info); + +/* Subroutine */ int cggevx_(char *balanc, char *jobvl, char *jobvr, char * + sense, integer *n, complex *a, integer *lda, complex *b, integer *ldb, + complex *alpha, complex *beta, complex *vl, integer *ldvl, complex * + vr, integer *ldvr, integer *ilo, integer *ihi, real *lscale, real * + rscale, real *abnrm, real *bbnrm, real *rconde, real *rcondv, complex + *work, integer *lwork, real *rwork, integer *iwork, logical *bwork, + integer *info); + +/* Subroutine */ int cggglm_(integer *n, integer *m, integer *p, complex *a, + integer *lda, complex *b, integer *ldb, complex *d__, complex *x, + complex *y, complex *work, integer *lwork, integer *info); + +/* Subroutine */ int cgghrd_(char *compq, char *compz, integer *n, integer * + ilo, integer *ihi, complex *a, integer *lda, complex *b, integer *ldb, + complex *q, integer *ldq, complex *z__, integer *ldz, integer *info); + +/* Subroutine */ int cgglse_(integer *m, integer *n, integer *p, complex *a, + integer *lda, complex *b, integer *ldb, complex *c__, complex *d__, + complex *x, complex *work, integer *lwork, integer *info); + +/* Subroutine */ int cggqrf_(integer *n, integer *m, integer *p, complex *a, + integer *lda, complex *taua, complex *b, integer *ldb, complex *taub, + complex *work, integer *lwork, integer *info); + +/* Subroutine */ int cggrqf_(integer *m, integer *p, integer *n, complex *a, + integer *lda, complex *taua, complex *b, integer *ldb, complex *taub, + complex *work, integer *lwork, integer *info); + +/* Subroutine */ int cggsvd_(char *jobu, char *jobv, char *jobq, integer *m, + integer *n, integer *p, integer *k, integer *l, complex *a, integer * + lda, complex *b, integer *ldb, real *alpha, real *beta, complex *u, + integer *ldu, complex *v, integer *ldv, complex *q, integer *ldq, + complex *work, real *rwork, integer *iwork, integer *info); + +/* Subroutine */ int cggsvp_(char *jobu, char *jobv, char *jobq, integer *m, + integer *p, integer *n, complex *a, integer *lda, complex *b, integer + *ldb, real *tola, real *tolb, integer *k, integer *l, complex *u, + integer *ldu, complex *v, integer *ldv, complex *q, integer *ldq, + integer *iwork, real *rwork, complex *tau, complex *work, integer * + info); + +/* Subroutine */ int cgtcon_(char *norm, integer *n, complex *dl, complex * + d__, complex *du, complex *du2, integer *ipiv, real *anorm, real * + rcond, complex *work, integer *info); + +/* Subroutine */ int cgtrfs_(char *trans, integer *n, integer *nrhs, complex * + dl, complex *d__, complex *du, complex *dlf, complex *df, complex * + duf, complex *du2, integer *ipiv, complex *b, integer *ldb, complex * + x, integer *ldx, real *ferr, real *berr, complex *work, real *rwork, + integer *info); + +/* Subroutine */ int cgtsv_(integer *n, integer *nrhs, complex *dl, complex * + d__, complex *du, complex *b, integer *ldb, integer *info); + +/* Subroutine */ int cgtsvx_(char *fact, char *trans, integer *n, integer * + nrhs, complex *dl, complex *d__, complex *du, complex *dlf, complex * + df, complex *duf, complex *du2, integer *ipiv, complex *b, integer * + ldb, complex *x, integer *ldx, real *rcond, real *ferr, real *berr, + complex *work, real *rwork, integer *info); + +/* Subroutine */ int cgttrf_(integer *n, complex *dl, complex *d__, complex * + du, complex *du2, integer *ipiv, integer *info); + +/* Subroutine */ int cgttrs_(char *trans, integer *n, integer *nrhs, complex * + dl, complex *d__, complex *du, complex *du2, integer *ipiv, complex * + b, integer *ldb, integer *info); + +/* Subroutine */ int cgtts2_(integer *itrans, integer *n, integer *nrhs, + complex *dl, complex *d__, complex *du, complex *du2, integer *ipiv, + complex *b, integer *ldb); + +/* Subroutine */ int chbev_(char *jobz, char *uplo, integer *n, integer *kd, + complex *ab, integer *ldab, real *w, complex *z__, integer *ldz, + complex *work, real *rwork, integer *info); + +/* Subroutine */ int chbevd_(char *jobz, char *uplo, integer *n, integer *kd, + complex *ab, integer *ldab, real *w, complex *z__, integer *ldz, + complex *work, integer *lwork, real *rwork, integer *lrwork, integer * + iwork, integer *liwork, integer *info); + +/* Subroutine */ int chbevx_(char *jobz, char *range, char *uplo, integer *n, + integer *kd, complex *ab, integer *ldab, complex *q, integer *ldq, + real *vl, real *vu, integer *il, integer *iu, real *abstol, integer * + m, real *w, complex *z__, integer *ldz, complex *work, real *rwork, + integer *iwork, integer *ifail, integer *info); + +/* Subroutine */ int chbgst_(char *vect, char *uplo, integer *n, integer *ka, + integer *kb, complex *ab, integer *ldab, complex *bb, integer *ldbb, + complex *x, integer *ldx, complex *work, real *rwork, integer *info); + +/* Subroutine */ int chbgv_(char *jobz, char *uplo, integer *n, integer *ka, + integer *kb, complex *ab, integer *ldab, complex *bb, integer *ldbb, + real *w, complex *z__, integer *ldz, complex *work, real *rwork, + integer *info); + +/* Subroutine */ int chbgvx_(char *jobz, char *range, char *uplo, integer *n, + integer *ka, integer *kb, complex *ab, integer *ldab, complex *bb, + integer *ldbb, complex *q, integer *ldq, real *vl, real *vu, integer * + il, integer *iu, real *abstol, integer *m, real *w, complex *z__, + integer *ldz, complex *work, real *rwork, integer *iwork, integer * + ifail, integer *info); + +/* Subroutine */ int chbtrd_(char *vect, char *uplo, integer *n, integer *kd, + complex *ab, integer *ldab, real *d__, real *e, complex *q, integer * + ldq, complex *work, integer *info); + +/* Subroutine */ int checon_(char *uplo, integer *n, complex *a, integer *lda, + integer *ipiv, real *anorm, real *rcond, complex *work, integer * + info); + +/* Subroutine */ int cheev_(char *jobz, char *uplo, integer *n, complex *a, + integer *lda, real *w, complex *work, integer *lwork, real *rwork, + integer *info); + +/* Subroutine */ int cheevd_(char *jobz, char *uplo, integer *n, complex *a, + integer *lda, real *w, complex *work, integer *lwork, real *rwork, + integer *lrwork, integer *iwork, integer *liwork, integer *info); + +/* Subroutine */ int cheevr_(char *jobz, char *range, char *uplo, integer *n, + complex *a, integer *lda, real *vl, real *vu, integer *il, integer * + iu, real *abstol, integer *m, real *w, complex *z__, integer *ldz, + integer *isuppz, complex *work, integer *lwork, real *rwork, integer * + lrwork, integer *iwork, integer *liwork, integer *info); + +/* Subroutine */ int cheevx_(char *jobz, char *range, char *uplo, integer *n, + complex *a, integer *lda, real *vl, real *vu, integer *il, integer * + iu, real *abstol, integer *m, real *w, complex *z__, integer *ldz, + complex *work, integer *lwork, real *rwork, integer *iwork, integer * + ifail, integer *info); + +/* Subroutine */ int chegs2_(integer *itype, char *uplo, integer *n, complex * + a, integer *lda, complex *b, integer *ldb, integer *info); + +/* Subroutine */ int chegst_(integer *itype, char *uplo, integer *n, complex * + a, integer *lda, complex *b, integer *ldb, integer *info); + +/* Subroutine */ int chegv_(integer *itype, char *jobz, char *uplo, integer * + n, complex *a, integer *lda, complex *b, integer *ldb, real *w, + complex *work, integer *lwork, real *rwork, integer *info); + +/* Subroutine */ int chegvd_(integer *itype, char *jobz, char *uplo, integer * + n, complex *a, integer *lda, complex *b, integer *ldb, real *w, + complex *work, integer *lwork, real *rwork, integer *lrwork, integer * + iwork, integer *liwork, integer *info); + +/* Subroutine */ int chegvx_(integer *itype, char *jobz, char *range, char * + uplo, integer *n, complex *a, integer *lda, complex *b, integer *ldb, + real *vl, real *vu, integer *il, integer *iu, real *abstol, integer * + m, real *w, complex *z__, integer *ldz, complex *work, integer *lwork, + real *rwork, integer *iwork, integer *ifail, integer *info); + +/* Subroutine */ int cherfs_(char *uplo, integer *n, integer *nrhs, complex * + a, integer *lda, complex *af, integer *ldaf, integer *ipiv, complex * + b, integer *ldb, complex *x, integer *ldx, real *ferr, real *berr, + complex *work, real *rwork, integer *info); + +/* Subroutine */ int chesv_(char *uplo, integer *n, integer *nrhs, complex *a, + integer *lda, integer *ipiv, complex *b, integer *ldb, complex *work, + integer *lwork, integer *info); + +/* Subroutine */ int chesvx_(char *fact, char *uplo, integer *n, integer * + nrhs, complex *a, integer *lda, complex *af, integer *ldaf, integer * + ipiv, complex *b, integer *ldb, complex *x, integer *ldx, real *rcond, + real *ferr, real *berr, complex *work, integer *lwork, real *rwork, + integer *info); + +/* Subroutine */ int chetf2_(char *uplo, integer *n, complex *a, integer *lda, + integer *ipiv, integer *info); + +/* Subroutine */ int chetrd_(char *uplo, integer *n, complex *a, integer *lda, + real *d__, real *e, complex *tau, complex *work, integer *lwork, + integer *info); + +/* Subroutine */ int chetrf_(char *uplo, integer *n, complex *a, integer *lda, + integer *ipiv, complex *work, integer *lwork, integer *info); + +/* Subroutine */ int chetri_(char *uplo, integer *n, complex *a, integer *lda, + integer *ipiv, complex *work, integer *info); + +/* Subroutine */ int chetrs_(char *uplo, integer *n, integer *nrhs, complex * + a, integer *lda, integer *ipiv, complex *b, integer *ldb, integer * + info); + +/* Subroutine */ int chgeqz_(char *job, char *compq, char *compz, integer *n, + integer *ilo, integer *ihi, complex *a, integer *lda, complex *b, + integer *ldb, complex *alpha, complex *beta, complex *q, integer *ldq, + complex *z__, integer *ldz, complex *work, integer *lwork, real * + rwork, integer *info); + +/* Subroutine */ int chpcon_(char *uplo, integer *n, complex *ap, integer * + ipiv, real *anorm, real *rcond, complex *work, integer *info); + +/* Subroutine */ int chpev_(char *jobz, char *uplo, integer *n, complex *ap, + real *w, complex *z__, integer *ldz, complex *work, real *rwork, + integer *info); + +/* Subroutine */ int chpevd_(char *jobz, char *uplo, integer *n, complex *ap, + real *w, complex *z__, integer *ldz, complex *work, integer *lwork, + real *rwork, integer *lrwork, integer *iwork, integer *liwork, + integer *info); + +/* Subroutine */ int chpevx_(char *jobz, char *range, char *uplo, integer *n, + complex *ap, real *vl, real *vu, integer *il, integer *iu, real * + abstol, integer *m, real *w, complex *z__, integer *ldz, complex * + work, real *rwork, integer *iwork, integer *ifail, integer *info); + +/* Subroutine */ int chpgst_(integer *itype, char *uplo, integer *n, complex * + ap, complex *bp, integer *info); + +/* Subroutine */ int chpgv_(integer *itype, char *jobz, char *uplo, integer * + n, complex *ap, complex *bp, real *w, complex *z__, integer *ldz, + complex *work, real *rwork, integer *info); + +/* Subroutine */ int chpgvd_(integer *itype, char *jobz, char *uplo, integer * + n, complex *ap, complex *bp, real *w, complex *z__, integer *ldz, + complex *work, integer *lwork, real *rwork, integer *lrwork, integer * + iwork, integer *liwork, integer *info); + +/* Subroutine */ int chpgvx_(integer *itype, char *jobz, char *range, char * + uplo, integer *n, complex *ap, complex *bp, real *vl, real *vu, + integer *il, integer *iu, real *abstol, integer *m, real *w, complex * + z__, integer *ldz, complex *work, real *rwork, integer *iwork, + integer *ifail, integer *info); + +/* Subroutine */ int chprfs_(char *uplo, integer *n, integer *nrhs, complex * + ap, complex *afp, integer *ipiv, complex *b, integer *ldb, complex *x, + integer *ldx, real *ferr, real *berr, complex *work, real *rwork, + integer *info); + +/* Subroutine */ int chpsv_(char *uplo, integer *n, integer *nrhs, complex * + ap, integer *ipiv, complex *b, integer *ldb, integer *info); + +/* Subroutine */ int chpsvx_(char *fact, char *uplo, integer *n, integer * + nrhs, complex *ap, complex *afp, integer *ipiv, complex *b, integer * + ldb, complex *x, integer *ldx, real *rcond, real *ferr, real *berr, + complex *work, real *rwork, integer *info); + +/* Subroutine */ int chptrd_(char *uplo, integer *n, complex *ap, real *d__, + real *e, complex *tau, integer *info); + +/* Subroutine */ int chptrf_(char *uplo, integer *n, complex *ap, integer * + ipiv, integer *info); + +/* Subroutine */ int chptri_(char *uplo, integer *n, complex *ap, integer * + ipiv, complex *work, integer *info); + +/* Subroutine */ int chptrs_(char *uplo, integer *n, integer *nrhs, complex * + ap, integer *ipiv, complex *b, integer *ldb, integer *info); + +/* Subroutine */ int chsein_(char *side, char *eigsrc, char *initv, logical * + select, integer *n, complex *h__, integer *ldh, complex *w, complex * + vl, integer *ldvl, complex *vr, integer *ldvr, integer *mm, integer * + m, complex *work, real *rwork, integer *ifaill, integer *ifailr, + integer *info); + +/* Subroutine */ int chseqr_(char *job, char *compz, integer *n, integer *ilo, + integer *ihi, complex *h__, integer *ldh, complex *w, complex *z__, + integer *ldz, complex *work, integer *lwork, integer *info); + +/* Subroutine */ int clabrd_(integer *m, integer *n, integer *nb, complex *a, + integer *lda, real *d__, real *e, complex *tauq, complex *taup, + complex *x, integer *ldx, complex *y, integer *ldy); + +/* Subroutine */ int clacgv_(integer *n, complex *x, integer *incx); + +/* Subroutine */ int clacon_(integer *n, complex *v, complex *x, real *est, + integer *kase); + +/* Subroutine */ int clacp2_(char *uplo, integer *m, integer *n, real *a, + integer *lda, complex *b, integer *ldb); + +/* Subroutine */ int clacpy_(char *uplo, integer *m, integer *n, complex *a, + integer *lda, complex *b, integer *ldb); + +/* Subroutine */ int clacrm_(integer *m, integer *n, complex *a, integer *lda, + real *b, integer *ldb, complex *c__, integer *ldc, real *rwork); + +/* Subroutine */ int clacrt_(integer *n, complex *cx, integer *incx, complex * + cy, integer *incy, complex *c__, complex *s); + +/* Subroutine */ int claed0_(integer *qsiz, integer *n, real *d__, real *e, + complex *q, integer *ldq, complex *qstore, integer *ldqs, real *rwork, + integer *iwork, integer *info); + +/* Subroutine */ int claed7_(integer *n, integer *cutpnt, integer *qsiz, + integer *tlvls, integer *curlvl, integer *curpbm, real *d__, complex * + q, integer *ldq, real *rho, integer *indxq, real *qstore, integer * + qptr, integer *prmptr, integer *perm, integer *givptr, integer * + givcol, real *givnum, complex *work, real *rwork, integer *iwork, + integer *info); + +/* Subroutine */ int claed8_(integer *k, integer *n, integer *qsiz, complex * + q, integer *ldq, real *d__, real *rho, integer *cutpnt, real *z__, + real *dlamda, complex *q2, integer *ldq2, real *w, integer *indxp, + integer *indx, integer *indxq, integer *perm, integer *givptr, + integer *givcol, real *givnum, integer *info); + +/* Subroutine */ int claein_(logical *rightv, logical *noinit, integer *n, + complex *h__, integer *ldh, complex *w, complex *v, complex *b, + integer *ldb, real *rwork, real *eps3, real *smlnum, integer *info); + +/* Subroutine */ int claesy_(complex *a, complex *b, complex *c__, complex * + rt1, complex *rt2, complex *evscal, complex *cs1, complex *sn1); + +/* Subroutine */ int claev2_(complex *a, complex *b, complex *c__, real *rt1, + real *rt2, real *cs1, complex *sn1); + +/* Subroutine */ int clags2_(logical *upper, real *a1, complex *a2, real *a3, + real *b1, complex *b2, real *b3, real *csu, complex *snu, real *csv, + complex *snv, real *csq, complex *snq); + +/* Subroutine */ int clagtm_(char *trans, integer *n, integer *nrhs, real * + alpha, complex *dl, complex *d__, complex *du, complex *x, integer * + ldx, real *beta, complex *b, integer *ldb); + +/* Subroutine */ int clahef_(char *uplo, integer *n, integer *nb, integer *kb, + complex *a, integer *lda, integer *ipiv, complex *w, integer *ldw, + integer *info); + +/* Subroutine */ int clahqr_(logical *wantt, logical *wantz, integer *n, + integer *ilo, integer *ihi, complex *h__, integer *ldh, complex *w, + integer *iloz, integer *ihiz, complex *z__, integer *ldz, integer * + info); + +/* Subroutine */ int clahrd_(integer *n, integer *k, integer *nb, complex *a, + integer *lda, complex *tau, complex *t, integer *ldt, complex *y, + integer *ldy); + +/* Subroutine */ int claic1_(integer *job, integer *j, complex *x, real *sest, + complex *w, complex *gamma, real *sestpr, complex *s, complex *c__); + +/* Subroutine */ int clals0_(integer *icompq, integer *nl, integer *nr, + integer *sqre, integer *nrhs, complex *b, integer *ldb, complex *bx, + integer *ldbx, integer *perm, integer *givptr, integer *givcol, + integer *ldgcol, real *givnum, integer *ldgnum, real *poles, real * + difl, real *difr, real *z__, integer *k, real *c__, real *s, real * + rwork, integer *info); + +/* Subroutine */ int clalsa_(integer *icompq, integer *smlsiz, integer *n, + integer *nrhs, complex *b, integer *ldb, complex *bx, integer *ldbx, + real *u, integer *ldu, real *vt, integer *k, real *difl, real *difr, + real *z__, real *poles, integer *givptr, integer *givcol, integer * + ldgcol, integer *perm, real *givnum, real *c__, real *s, real *rwork, + integer *iwork, integer *info); + +/* Subroutine */ int clapll_(integer *n, complex *x, integer *incx, complex * + y, integer *incy, real *ssmin); + +/* Subroutine */ int clapmt_(logical *forwrd, integer *m, integer *n, complex + *x, integer *ldx, integer *k); + +/* Subroutine */ int claqgb_(integer *m, integer *n, integer *kl, integer *ku, + complex *ab, integer *ldab, real *r__, real *c__, real *rowcnd, real + *colcnd, real *amax, char *equed); + +/* Subroutine */ int claqge_(integer *m, integer *n, complex *a, integer *lda, + real *r__, real *c__, real *rowcnd, real *colcnd, real *amax, char * + equed); + +/* Subroutine */ int claqhb_(char *uplo, integer *n, integer *kd, complex *ab, + integer *ldab, real *s, real *scond, real *amax, char *equed); + +/* Subroutine */ int claqhe_(char *uplo, integer *n, complex *a, integer *lda, + real *s, real *scond, real *amax, char *equed); + +/* Subroutine */ int claqhp_(char *uplo, integer *n, complex *ap, real *s, + real *scond, real *amax, char *equed); + +/* Subroutine */ int claqp2_(integer *m, integer *n, integer *offset, complex + *a, integer *lda, integer *jpvt, complex *tau, real *vn1, real *vn2, + complex *work); + +/* Subroutine */ int claqps_(integer *m, integer *n, integer *offset, integer + *nb, integer *kb, complex *a, integer *lda, integer *jpvt, complex * + tau, real *vn1, real *vn2, complex *auxv, complex *f, integer *ldf); + +/* Subroutine */ int claqsb_(char *uplo, integer *n, integer *kd, complex *ab, + integer *ldab, real *s, real *scond, real *amax, char *equed); + +/* Subroutine */ int claqsp_(char *uplo, integer *n, complex *ap, real *s, + real *scond, real *amax, char *equed); + +/* Subroutine */ int claqsy_(char *uplo, integer *n, complex *a, integer *lda, + real *s, real *scond, real *amax, char *equed); + +/* Subroutine */ int clar1v_(integer *n, integer *b1, integer *bn, real * + sigma, real *d__, real *l, real *ld, real *lld, real *gersch, complex + *z__, real *ztz, real *mingma, integer *r__, integer *isuppz, real * + work); + +/* Subroutine */ int clar2v_(integer *n, complex *x, complex *y, complex *z__, + integer *incx, real *c__, complex *s, integer *incc); + +/* Subroutine */ int clarcm_(integer *m, integer *n, real *a, integer *lda, + complex *b, integer *ldb, complex *c__, integer *ldc, real *rwork); + +/* Subroutine */ int clarf_(char *side, integer *m, integer *n, complex *v, + integer *incv, complex *tau, complex *c__, integer *ldc, complex * + work); + +/* Subroutine */ int clarfb_(char *side, char *trans, char *direct, char * + storev, integer *m, integer *n, integer *k, complex *v, integer *ldv, + complex *t, integer *ldt, complex *c__, integer *ldc, complex *work, + integer *ldwork); + +/* Subroutine */ int clarfg_(integer *n, complex *alpha, complex *x, integer * + incx, complex *tau); + +/* Subroutine */ int clarft_(char *direct, char *storev, integer *n, integer * + k, complex *v, integer *ldv, complex *tau, complex *t, integer *ldt); + +/* Subroutine */ int clarfx_(char *side, integer *m, integer *n, complex *v, + complex *tau, complex *c__, integer *ldc, complex *work); + +/* Subroutine */ int clargv_(integer *n, complex *x, integer *incx, complex * + y, integer *incy, real *c__, integer *incc); + +/* Subroutine */ int clarnv_(integer *idist, integer *iseed, integer *n, + complex *x); + +/* Subroutine */ int clarrv_(integer *n, real *d__, real *l, integer *isplit, + integer *m, real *w, integer *iblock, real *gersch, real *tol, + complex *z__, integer *ldz, integer *isuppz, real *work, integer * + iwork, integer *info); + +/* Subroutine */ int clartg_(complex *f, complex *g, real *cs, complex *sn, + complex *r__); + +/* Subroutine */ int clartv_(integer *n, complex *x, integer *incx, complex * + y, integer *incy, real *c__, complex *s, integer *incc); + +/* Subroutine */ int clarz_(char *side, integer *m, integer *n, integer *l, + complex *v, integer *incv, complex *tau, complex *c__, integer *ldc, + complex *work); + +/* Subroutine */ int clarzb_(char *side, char *trans, char *direct, char * + storev, integer *m, integer *n, integer *k, integer *l, complex *v, + integer *ldv, complex *t, integer *ldt, complex *c__, integer *ldc, + complex *work, integer *ldwork); + +/* Subroutine */ int clarzt_(char *direct, char *storev, integer *n, integer * + k, complex *v, integer *ldv, complex *tau, complex *t, integer *ldt); + +/* Subroutine */ int clascl_(char *type__, integer *kl, integer *ku, real * + cfrom, real *cto, integer *m, integer *n, complex *a, integer *lda, + integer *info); + +/* Subroutine */ int claset_(char *uplo, integer *m, integer *n, complex * + alpha, complex *beta, complex *a, integer *lda); + +/* Subroutine */ int clasr_(char *side, char *pivot, char *direct, integer *m, + integer *n, real *c__, real *s, complex *a, integer *lda); + +/* Subroutine */ int classq_(integer *n, complex *x, integer *incx, real * + scale, real *sumsq); + +/* Subroutine */ int claswp_(integer *n, complex *a, integer *lda, integer * + k1, integer *k2, integer *ipiv, integer *incx); + +/* Subroutine */ int clasyf_(char *uplo, integer *n, integer *nb, integer *kb, + complex *a, integer *lda, integer *ipiv, complex *w, integer *ldw, + integer *info); + +/* Subroutine */ int clatbs_(char *uplo, char *trans, char *diag, char * + normin, integer *n, integer *kd, complex *ab, integer *ldab, complex * + x, real *scale, real *cnorm, integer *info); + +/* Subroutine */ int clatdf_(integer *ijob, integer *n, complex *z__, integer + *ldz, complex *rhs, real *rdsum, real *rdscal, integer *ipiv, integer + *jpiv); + +/* Subroutine */ int clatps_(char *uplo, char *trans, char *diag, char * + normin, integer *n, complex *ap, complex *x, real *scale, real *cnorm, + integer *info); + +/* Subroutine */ int clatrd_(char *uplo, integer *n, integer *nb, complex *a, + integer *lda, real *e, complex *tau, complex *w, integer *ldw); + +/* Subroutine */ int clatrs_(char *uplo, char *trans, char *diag, char * + normin, integer *n, complex *a, integer *lda, complex *x, real *scale, + real *cnorm, integer *info); + +/* Subroutine */ int clatrz_(integer *m, integer *n, integer *l, complex *a, + integer *lda, complex *tau, complex *work); + +/* Subroutine */ int clatzm_(char *side, integer *m, integer *n, complex *v, + integer *incv, complex *tau, complex *c1, complex *c2, integer *ldc, + complex *work); + +/* Subroutine */ int clauu2_(char *uplo, integer *n, complex *a, integer *lda, + integer *info); + +/* Subroutine */ int clauum_(char *uplo, integer *n, complex *a, integer *lda, + integer *info); + +/* Subroutine */ int cpbcon_(char *uplo, integer *n, integer *kd, complex *ab, + integer *ldab, real *anorm, real *rcond, complex *work, real *rwork, + integer *info); + +/* Subroutine */ int cpbequ_(char *uplo, integer *n, integer *kd, complex *ab, + integer *ldab, real *s, real *scond, real *amax, integer *info); + +/* Subroutine */ int cpbrfs_(char *uplo, integer *n, integer *kd, integer * + nrhs, complex *ab, integer *ldab, complex *afb, integer *ldafb, + complex *b, integer *ldb, complex *x, integer *ldx, real *ferr, real * + berr, complex *work, real *rwork, integer *info); + +/* Subroutine */ int cpbstf_(char *uplo, integer *n, integer *kd, complex *ab, + integer *ldab, integer *info); + +/* Subroutine */ int cpbsv_(char *uplo, integer *n, integer *kd, integer * + nrhs, complex *ab, integer *ldab, complex *b, integer *ldb, integer * + info); + +/* Subroutine */ int cpbsvx_(char *fact, char *uplo, integer *n, integer *kd, + integer *nrhs, complex *ab, integer *ldab, complex *afb, integer * + ldafb, char *equed, real *s, complex *b, integer *ldb, complex *x, + integer *ldx, real *rcond, real *ferr, real *berr, complex *work, + real *rwork, integer *info); + +/* Subroutine */ int cpbtf2_(char *uplo, integer *n, integer *kd, complex *ab, + integer *ldab, integer *info); + +/* Subroutine */ int cpbtrf_(char *uplo, integer *n, integer *kd, complex *ab, + integer *ldab, integer *info); + +/* Subroutine */ int cpbtrs_(char *uplo, integer *n, integer *kd, integer * + nrhs, complex *ab, integer *ldab, complex *b, integer *ldb, integer * + info); + +/* Subroutine */ int cpocon_(char *uplo, integer *n, complex *a, integer *lda, + real *anorm, real *rcond, complex *work, real *rwork, integer *info); + +/* Subroutine */ int cpoequ_(integer *n, complex *a, integer *lda, real *s, + real *scond, real *amax, integer *info); + +/* Subroutine */ int cporfs_(char *uplo, integer *n, integer *nrhs, complex * + a, integer *lda, complex *af, integer *ldaf, complex *b, integer *ldb, + complex *x, integer *ldx, real *ferr, real *berr, complex *work, + real *rwork, integer *info); + +/* Subroutine */ int cposv_(char *uplo, integer *n, integer *nrhs, complex *a, + integer *lda, complex *b, integer *ldb, integer *info); + +/* Subroutine */ int cposvx_(char *fact, char *uplo, integer *n, integer * + nrhs, complex *a, integer *lda, complex *af, integer *ldaf, char * + equed, real *s, complex *b, integer *ldb, complex *x, integer *ldx, + real *rcond, real *ferr, real *berr, complex *work, real *rwork, + integer *info); + +/* Subroutine */ int cpotf2_(char *uplo, integer *n, complex *a, integer *lda, + integer *info); + +/* Subroutine */ int cpotrf_(char *uplo, integer *n, complex *a, integer *lda, + integer *info); + +/* Subroutine */ int cpotri_(char *uplo, integer *n, complex *a, integer *lda, + integer *info); + +/* Subroutine */ int cpotrs_(char *uplo, integer *n, integer *nrhs, complex * + a, integer *lda, complex *b, integer *ldb, integer *info); + +/* Subroutine */ int cppcon_(char *uplo, integer *n, complex *ap, real *anorm, + real *rcond, complex *work, real *rwork, integer *info); + +/* Subroutine */ int cppequ_(char *uplo, integer *n, complex *ap, real *s, + real *scond, real *amax, integer *info); + +/* Subroutine */ int cpprfs_(char *uplo, integer *n, integer *nrhs, complex * + ap, complex *afp, complex *b, integer *ldb, complex *x, integer *ldx, + real *ferr, real *berr, complex *work, real *rwork, integer *info); + +/* Subroutine */ int cppsv_(char *uplo, integer *n, integer *nrhs, complex * + ap, complex *b, integer *ldb, integer *info); + +/* Subroutine */ int cppsvx_(char *fact, char *uplo, integer *n, integer * + nrhs, complex *ap, complex *afp, char *equed, real *s, complex *b, + integer *ldb, complex *x, integer *ldx, real *rcond, real *ferr, real + *berr, complex *work, real *rwork, integer *info); + +/* Subroutine */ int cpptrf_(char *uplo, integer *n, complex *ap, integer * + info); + +/* Subroutine */ int cpptri_(char *uplo, integer *n, complex *ap, integer * + info); + +/* Subroutine */ int cpptrs_(char *uplo, integer *n, integer *nrhs, complex * + ap, complex *b, integer *ldb, integer *info); + +/* Subroutine */ int cptcon_(integer *n, real *d__, complex *e, real *anorm, + real *rcond, real *rwork, integer *info); + +/* Subroutine */ int cptrfs_(char *uplo, integer *n, integer *nrhs, real *d__, + complex *e, real *df, complex *ef, complex *b, integer *ldb, complex + *x, integer *ldx, real *ferr, real *berr, complex *work, real *rwork, + integer *info); + +/* Subroutine */ int cptsv_(integer *n, integer *nrhs, real *d__, complex *e, + complex *b, integer *ldb, integer *info); + +/* Subroutine */ int cptsvx_(char *fact, integer *n, integer *nrhs, real *d__, + complex *e, real *df, complex *ef, complex *b, integer *ldb, complex + *x, integer *ldx, real *rcond, real *ferr, real *berr, complex *work, + real *rwork, integer *info); + +/* Subroutine */ int cpttrf_(integer *n, real *d__, complex *e, integer *info); + +/* Subroutine */ int cpttrs_(char *uplo, integer *n, integer *nrhs, real *d__, + complex *e, complex *b, integer *ldb, integer *info); + +/* Subroutine */ int cptts2_(integer *iuplo, integer *n, integer *nrhs, real * + d__, complex *e, complex *b, integer *ldb); + +/* Subroutine */ int crot_(integer *n, complex *cx, integer *incx, complex * + cy, integer *incy, real *c__, complex *s); + +/* Subroutine */ int cspcon_(char *uplo, integer *n, complex *ap, integer * + ipiv, real *anorm, real *rcond, complex *work, integer *info); + +/* Subroutine */ int cspmv_(char *uplo, integer *n, complex *alpha, complex * + ap, complex *x, integer *incx, complex *beta, complex *y, integer * + incy); + +/* Subroutine */ int cspr_(char *uplo, integer *n, complex *alpha, complex *x, + integer *incx, complex *ap); + +/* Subroutine */ int csprfs_(char *uplo, integer *n, integer *nrhs, complex * + ap, complex *afp, integer *ipiv, complex *b, integer *ldb, complex *x, + integer *ldx, real *ferr, real *berr, complex *work, real *rwork, + integer *info); + +/* Subroutine */ int cspsv_(char *uplo, integer *n, integer *nrhs, complex * + ap, integer *ipiv, complex *b, integer *ldb, integer *info); + +/* Subroutine */ int cspsvx_(char *fact, char *uplo, integer *n, integer * + nrhs, complex *ap, complex *afp, integer *ipiv, complex *b, integer * + ldb, complex *x, integer *ldx, real *rcond, real *ferr, real *berr, + complex *work, real *rwork, integer *info); + +/* Subroutine */ int csptrf_(char *uplo, integer *n, complex *ap, integer * + ipiv, integer *info); + +/* Subroutine */ int csptri_(char *uplo, integer *n, complex *ap, integer * + ipiv, complex *work, integer *info); + +/* Subroutine */ int csptrs_(char *uplo, integer *n, integer *nrhs, complex * + ap, integer *ipiv, complex *b, integer *ldb, integer *info); + +/* Subroutine */ int csrot_(integer *n, complex *cx, integer *incx, complex * + cy, integer *incy, real *c__, real *s); + +/* Subroutine */ int csrscl_(integer *n, real *sa, complex *sx, integer *incx); + +/* Subroutine */ int cstedc_(char *compz, integer *n, real *d__, real *e, + complex *z__, integer *ldz, complex *work, integer *lwork, real * + rwork, integer *lrwork, integer *iwork, integer *liwork, integer * + info); + +/* Subroutine */ int cstein_(integer *n, real *d__, real *e, integer *m, real + *w, integer *iblock, integer *isplit, complex *z__, integer *ldz, + real *work, integer *iwork, integer *ifail, integer *info); + +/* Subroutine */ int csteqr_(char *compz, integer *n, real *d__, real *e, + complex *z__, integer *ldz, real *work, integer *info); + +/* Subroutine */ int csycon_(char *uplo, integer *n, complex *a, integer *lda, + integer *ipiv, real *anorm, real *rcond, complex *work, integer * + info); + +/* Subroutine */ int csymv_(char *uplo, integer *n, complex *alpha, complex * + a, integer *lda, complex *x, integer *incx, complex *beta, complex *y, + integer *incy); + +/* Subroutine */ int csyr_(char *uplo, integer *n, complex *alpha, complex *x, + integer *incx, complex *a, integer *lda); + +/* Subroutine */ int csyrfs_(char *uplo, integer *n, integer *nrhs, complex * + a, integer *lda, complex *af, integer *ldaf, integer *ipiv, complex * + b, integer *ldb, complex *x, integer *ldx, real *ferr, real *berr, + complex *work, real *rwork, integer *info); + +/* Subroutine */ int csysv_(char *uplo, integer *n, integer *nrhs, complex *a, + integer *lda, integer *ipiv, complex *b, integer *ldb, complex *work, + integer *lwork, integer *info); + +/* Subroutine */ int csysvx_(char *fact, char *uplo, integer *n, integer * + nrhs, complex *a, integer *lda, complex *af, integer *ldaf, integer * + ipiv, complex *b, integer *ldb, complex *x, integer *ldx, real *rcond, + real *ferr, real *berr, complex *work, integer *lwork, real *rwork, + integer *info); + +/* Subroutine */ int csytf2_(char *uplo, integer *n, complex *a, integer *lda, + integer *ipiv, integer *info); + +/* Subroutine */ int csytrf_(char *uplo, integer *n, complex *a, integer *lda, + integer *ipiv, complex *work, integer *lwork, integer *info); + +/* Subroutine */ int csytri_(char *uplo, integer *n, complex *a, integer *lda, + integer *ipiv, complex *work, integer *info); + +/* Subroutine */ int csytrs_(char *uplo, integer *n, integer *nrhs, complex * + a, integer *lda, integer *ipiv, complex *b, integer *ldb, integer * + info); + +/* Subroutine */ int ctbcon_(char *norm, char *uplo, char *diag, integer *n, + integer *kd, complex *ab, integer *ldab, real *rcond, complex *work, + real *rwork, integer *info); + +/* Subroutine */ int ctbrfs_(char *uplo, char *trans, char *diag, integer *n, + integer *kd, integer *nrhs, complex *ab, integer *ldab, complex *b, + integer *ldb, complex *x, integer *ldx, real *ferr, real *berr, + complex *work, real *rwork, integer *info); + +/* Subroutine */ int ctbtrs_(char *uplo, char *trans, char *diag, integer *n, + integer *kd, integer *nrhs, complex *ab, integer *ldab, complex *b, + integer *ldb, integer *info); + +/* Subroutine */ int ctgevc_(char *side, char *howmny, logical *select, + integer *n, complex *a, integer *lda, complex *b, integer *ldb, + complex *vl, integer *ldvl, complex *vr, integer *ldvr, integer *mm, + integer *m, complex *work, real *rwork, integer *info); + +/* Subroutine */ int ctgex2_(logical *wantq, logical *wantz, integer *n, + complex *a, integer *lda, complex *b, integer *ldb, complex *q, + integer *ldq, complex *z__, integer *ldz, integer *j1, integer *info); + +/* Subroutine */ int ctgexc_(logical *wantq, logical *wantz, integer *n, + complex *a, integer *lda, complex *b, integer *ldb, complex *q, + integer *ldq, complex *z__, integer *ldz, integer *ifst, integer * + ilst, integer *info); + +/* Subroutine */ int ctgsen_(integer *ijob, logical *wantq, logical *wantz, + logical *select, integer *n, complex *a, integer *lda, complex *b, + integer *ldb, complex *alpha, complex *beta, complex *q, integer *ldq, + complex *z__, integer *ldz, integer *m, real *pl, real *pr, real * + dif, complex *work, integer *lwork, integer *iwork, integer *liwork, + integer *info); + +/* Subroutine */ int ctgsja_(char *jobu, char *jobv, char *jobq, integer *m, + integer *p, integer *n, integer *k, integer *l, complex *a, integer * + lda, complex *b, integer *ldb, real *tola, real *tolb, real *alpha, + real *beta, complex *u, integer *ldu, complex *v, integer *ldv, + complex *q, integer *ldq, complex *work, integer *ncycle, integer * + info); + +/* Subroutine */ int ctgsna_(char *job, char *howmny, logical *select, + integer *n, complex *a, integer *lda, complex *b, integer *ldb, + complex *vl, integer *ldvl, complex *vr, integer *ldvr, real *s, real + *dif, integer *mm, integer *m, complex *work, integer *lwork, integer + *iwork, integer *info); + +/* Subroutine */ int ctgsy2_(char *trans, integer *ijob, integer *m, integer * + n, complex *a, integer *lda, complex *b, integer *ldb, complex *c__, + integer *ldc, complex *d__, integer *ldd, complex *e, integer *lde, + complex *f, integer *ldf, real *scale, real *rdsum, real *rdscal, + integer *info); + +/* Subroutine */ int ctgsyl_(char *trans, integer *ijob, integer *m, integer * + n, complex *a, integer *lda, complex *b, integer *ldb, complex *c__, + integer *ldc, complex *d__, integer *ldd, complex *e, integer *lde, + complex *f, integer *ldf, real *scale, real *dif, complex *work, + integer *lwork, integer *iwork, integer *info); + +/* Subroutine */ int ctpcon_(char *norm, char *uplo, char *diag, integer *n, + complex *ap, real *rcond, complex *work, real *rwork, integer *info); + +/* Subroutine */ int ctprfs_(char *uplo, char *trans, char *diag, integer *n, + integer *nrhs, complex *ap, complex *b, integer *ldb, complex *x, + integer *ldx, real *ferr, real *berr, complex *work, real *rwork, + integer *info); + +/* Subroutine */ int ctptri_(char *uplo, char *diag, integer *n, complex *ap, + integer *info); + +/* Subroutine */ int ctptrs_(char *uplo, char *trans, char *diag, integer *n, + integer *nrhs, complex *ap, complex *b, integer *ldb, integer *info); + +/* Subroutine */ int ctrcon_(char *norm, char *uplo, char *diag, integer *n, + complex *a, integer *lda, real *rcond, complex *work, real *rwork, + integer *info); + +/* Subroutine */ int ctrevc_(char *side, char *howmny, logical *select, + integer *n, complex *t, integer *ldt, complex *vl, integer *ldvl, + complex *vr, integer *ldvr, integer *mm, integer *m, complex *work, + real *rwork, integer *info); + +/* Subroutine */ int ctrexc_(char *compq, integer *n, complex *t, integer * + ldt, complex *q, integer *ldq, integer *ifst, integer *ilst, integer * + info); + +/* Subroutine */ int ctrrfs_(char *uplo, char *trans, char *diag, integer *n, + integer *nrhs, complex *a, integer *lda, complex *b, integer *ldb, + complex *x, integer *ldx, real *ferr, real *berr, complex *work, real + *rwork, integer *info); + +/* Subroutine */ int ctrsen_(char *job, char *compq, logical *select, integer + *n, complex *t, integer *ldt, complex *q, integer *ldq, complex *w, + integer *m, real *s, real *sep, complex *work, integer *lwork, + integer *info); + +/* Subroutine */ int ctrsna_(char *job, char *howmny, logical *select, + integer *n, complex *t, integer *ldt, complex *vl, integer *ldvl, + complex *vr, integer *ldvr, real *s, real *sep, integer *mm, integer * + m, complex *work, integer *ldwork, real *rwork, integer *info); + +/* Subroutine */ int ctrsyl_(char *trana, char *tranb, integer *isgn, integer + *m, integer *n, complex *a, integer *lda, complex *b, integer *ldb, + complex *c__, integer *ldc, real *scale, integer *info); + +/* Subroutine */ int ctrti2_(char *uplo, char *diag, integer *n, complex *a, + integer *lda, integer *info); + +/* Subroutine */ int ctrtri_(char *uplo, char *diag, integer *n, complex *a, + integer *lda, integer *info); + +/* Subroutine */ int ctrtrs_(char *uplo, char *trans, char *diag, integer *n, + integer *nrhs, complex *a, integer *lda, complex *b, integer *ldb, + integer *info); + +/* Subroutine */ int ctzrqf_(integer *m, integer *n, complex *a, integer *lda, + complex *tau, integer *info); + +/* Subroutine */ int ctzrzf_(integer *m, integer *n, complex *a, integer *lda, + complex *tau, complex *work, integer *lwork, integer *info); + +/* Subroutine */ int cung2l_(integer *m, integer *n, integer *k, complex *a, + integer *lda, complex *tau, complex *work, integer *info); + +/* Subroutine */ int cung2r_(integer *m, integer *n, integer *k, complex *a, + integer *lda, complex *tau, complex *work, integer *info); + +/* Subroutine */ int cungbr_(char *vect, integer *m, integer *n, integer *k, + complex *a, integer *lda, complex *tau, complex *work, integer *lwork, + integer *info); + +/* Subroutine */ int cunghr_(integer *n, integer *ilo, integer *ihi, complex * + a, integer *lda, complex *tau, complex *work, integer *lwork, integer + *info); + +/* Subroutine */ int cungl2_(integer *m, integer *n, integer *k, complex *a, + integer *lda, complex *tau, complex *work, integer *info); + +/* Subroutine */ int cunglq_(integer *m, integer *n, integer *k, complex *a, + integer *lda, complex *tau, complex *work, integer *lwork, integer * + info); + +/* Subroutine */ int cungql_(integer *m, integer *n, integer *k, complex *a, + integer *lda, complex *tau, complex *work, integer *lwork, integer * + info); + +/* Subroutine */ int cungqr_(integer *m, integer *n, integer *k, complex *a, + integer *lda, complex *tau, complex *work, integer *lwork, integer * + info); + +/* Subroutine */ int cungr2_(integer *m, integer *n, integer *k, complex *a, + integer *lda, complex *tau, complex *work, integer *info); + +/* Subroutine */ int cungrq_(integer *m, integer *n, integer *k, complex *a, + integer *lda, complex *tau, complex *work, integer *lwork, integer * + info); + +/* Subroutine */ int cungtr_(char *uplo, integer *n, complex *a, integer *lda, + complex *tau, complex *work, integer *lwork, integer *info); + +/* Subroutine */ int cunm2l_(char *side, char *trans, integer *m, integer *n, + integer *k, complex *a, integer *lda, complex *tau, complex *c__, + integer *ldc, complex *work, integer *info); + +/* Subroutine */ int cunm2r_(char *side, char *trans, integer *m, integer *n, + integer *k, complex *a, integer *lda, complex *tau, complex *c__, + integer *ldc, complex *work, integer *info); + +/* Subroutine */ int cunmbr_(char *vect, char *side, char *trans, integer *m, + integer *n, integer *k, complex *a, integer *lda, complex *tau, + complex *c__, integer *ldc, complex *work, integer *lwork, integer * + info); + +/* Subroutine */ int cunmhr_(char *side, char *trans, integer *m, integer *n, + integer *ilo, integer *ihi, complex *a, integer *lda, complex *tau, + complex *c__, integer *ldc, complex *work, integer *lwork, integer * + info); + +/* Subroutine */ int cunml2_(char *side, char *trans, integer *m, integer *n, + integer *k, complex *a, integer *lda, complex *tau, complex *c__, + integer *ldc, complex *work, integer *info); + +/* Subroutine */ int cunmlq_(char *side, char *trans, integer *m, integer *n, + integer *k, complex *a, integer *lda, complex *tau, complex *c__, + integer *ldc, complex *work, integer *lwork, integer *info); + +/* Subroutine */ int cunmql_(char *side, char *trans, integer *m, integer *n, + integer *k, complex *a, integer *lda, complex *tau, complex *c__, + integer *ldc, complex *work, integer *lwork, integer *info); + +/* Subroutine */ int cunmqr_(char *side, char *trans, integer *m, integer *n, + integer *k, complex *a, integer *lda, complex *tau, complex *c__, + integer *ldc, complex *work, integer *lwork, integer *info); + +/* Subroutine */ int cunmr2_(char *side, char *trans, integer *m, integer *n, + integer *k, complex *a, integer *lda, complex *tau, complex *c__, + integer *ldc, complex *work, integer *info); + +/* Subroutine */ int cunmr3_(char *side, char *trans, integer *m, integer *n, + integer *k, integer *l, complex *a, integer *lda, complex *tau, + complex *c__, integer *ldc, complex *work, integer *info); + +/* Subroutine */ int cunmrq_(char *side, char *trans, integer *m, integer *n, + integer *k, complex *a, integer *lda, complex *tau, complex *c__, + integer *ldc, complex *work, integer *lwork, integer *info); + +/* Subroutine */ int cunmrz_(char *side, char *trans, integer *m, integer *n, + integer *k, integer *l, complex *a, integer *lda, complex *tau, + complex *c__, integer *ldc, complex *work, integer *lwork, integer * + info); + +/* Subroutine */ int cunmtr_(char *side, char *uplo, char *trans, integer *m, + integer *n, complex *a, integer *lda, complex *tau, complex *c__, + integer *ldc, complex *work, integer *lwork, integer *info); + +/* Subroutine */ int cupgtr_(char *uplo, integer *n, complex *ap, complex * + tau, complex *q, integer *ldq, complex *work, integer *info); + +/* Subroutine */ int cupmtr_(char *side, char *uplo, char *trans, integer *m, + integer *n, complex *ap, complex *tau, complex *c__, integer *ldc, + complex *work, integer *info); + +/* Subroutine */ int dbdsdc_(char *uplo, char *compq, integer *n, doublereal * + d__, doublereal *e, doublereal *u, integer *ldu, doublereal *vt, + integer *ldvt, doublereal *q, integer *iq, doublereal *work, integer * + iwork, integer *info); + +/* Subroutine */ int dbdsqr_(char *uplo, integer *n, integer *ncvt, integer * + nru, integer *ncc, doublereal *d__, doublereal *e, doublereal *vt, + integer *ldvt, doublereal *u, integer *ldu, doublereal *c__, integer * + ldc, doublereal *work, integer *info); + +/* Subroutine */ int ddisna_(char *job, integer *m, integer *n, doublereal * + d__, doublereal *sep, integer *info); + +/* Subroutine */ int dgbbrd_(char *vect, integer *m, integer *n, integer *ncc, + integer *kl, integer *ku, doublereal *ab, integer *ldab, doublereal * + d__, doublereal *e, doublereal *q, integer *ldq, doublereal *pt, + integer *ldpt, doublereal *c__, integer *ldc, doublereal *work, + integer *info); + +/* Subroutine */ int dgbcon_(char *norm, integer *n, integer *kl, integer *ku, + doublereal *ab, integer *ldab, integer *ipiv, doublereal *anorm, + doublereal *rcond, doublereal *work, integer *iwork, integer *info); + +/* Subroutine */ int dgbequ_(integer *m, integer *n, integer *kl, integer *ku, + doublereal *ab, integer *ldab, doublereal *r__, doublereal *c__, + doublereal *rowcnd, doublereal *colcnd, doublereal *amax, integer * + info); + +/* Subroutine */ int dgbrfs_(char *trans, integer *n, integer *kl, integer * + ku, integer *nrhs, doublereal *ab, integer *ldab, doublereal *afb, + integer *ldafb, integer *ipiv, doublereal *b, integer *ldb, + doublereal *x, integer *ldx, doublereal *ferr, doublereal *berr, + doublereal *work, integer *iwork, integer *info); + +/* Subroutine */ int dgbsv_(integer *n, integer *kl, integer *ku, integer * + nrhs, doublereal *ab, integer *ldab, integer *ipiv, doublereal *b, + integer *ldb, integer *info); + +/* Subroutine */ int dgbsvx_(char *fact, char *trans, integer *n, integer *kl, + integer *ku, integer *nrhs, doublereal *ab, integer *ldab, + doublereal *afb, integer *ldafb, integer *ipiv, char *equed, + doublereal *r__, doublereal *c__, doublereal *b, integer *ldb, + doublereal *x, integer *ldx, doublereal *rcond, doublereal *ferr, + doublereal *berr, doublereal *work, integer *iwork, integer *info); + +/* Subroutine */ int dgbtf2_(integer *m, integer *n, integer *kl, integer *ku, + doublereal *ab, integer *ldab, integer *ipiv, integer *info); + +/* Subroutine */ int dgbtrf_(integer *m, integer *n, integer *kl, integer *ku, + doublereal *ab, integer *ldab, integer *ipiv, integer *info); + +/* Subroutine */ int dgbtrs_(char *trans, integer *n, integer *kl, integer * + ku, integer *nrhs, doublereal *ab, integer *ldab, integer *ipiv, + doublereal *b, integer *ldb, integer *info); + +/* Subroutine */ int dgebak_(char *job, char *side, integer *n, integer *ilo, + integer *ihi, doublereal *scale, integer *m, doublereal *v, integer * + ldv, integer *info); + +/* Subroutine */ int dgebal_(char *job, integer *n, doublereal *a, integer * + lda, integer *ilo, integer *ihi, doublereal *scale, integer *info); + +/* Subroutine */ int dgebd2_(integer *m, integer *n, doublereal *a, integer * + lda, doublereal *d__, doublereal *e, doublereal *tauq, doublereal * + taup, doublereal *work, integer *info); + +/* Subroutine */ int dgebrd_(integer *m, integer *n, doublereal *a, integer * + lda, doublereal *d__, doublereal *e, doublereal *tauq, doublereal * + taup, doublereal *work, integer *lwork, integer *info); + +/* Subroutine */ int dgecon_(char *norm, integer *n, doublereal *a, integer * + lda, doublereal *anorm, doublereal *rcond, doublereal *work, integer * + iwork, integer *info); + +/* Subroutine */ int dgeequ_(integer *m, integer *n, doublereal *a, integer * + lda, doublereal *r__, doublereal *c__, doublereal *rowcnd, doublereal + *colcnd, doublereal *amax, integer *info); + +/* Subroutine */ int dgees_(char *jobvs, char *sort, L_fp select, integer *n, + doublereal *a, integer *lda, integer *sdim, doublereal *wr, + doublereal *wi, doublereal *vs, integer *ldvs, doublereal *work, + integer *lwork, logical *bwork, integer *info); + +/* Subroutine */ int dgeesx_(char *jobvs, char *sort, L_fp select, char * + sense, integer *n, doublereal *a, integer *lda, integer *sdim, + doublereal *wr, doublereal *wi, doublereal *vs, integer *ldvs, + doublereal *rconde, doublereal *rcondv, doublereal *work, integer * + lwork, integer *iwork, integer *liwork, logical *bwork, integer *info); + +/* Subroutine */ int dgeev_(char *jobvl, char *jobvr, integer *n, doublereal * + a, integer *lda, doublereal *wr, doublereal *wi, doublereal *vl, + integer *ldvl, doublereal *vr, integer *ldvr, doublereal *work, + integer *lwork, integer *info); + +/* Subroutine */ int dgeevx_(char *balanc, char *jobvl, char *jobvr, char * + sense, integer *n, doublereal *a, integer *lda, doublereal *wr, + doublereal *wi, doublereal *vl, integer *ldvl, doublereal *vr, + integer *ldvr, integer *ilo, integer *ihi, doublereal *scale, + doublereal *abnrm, doublereal *rconde, doublereal *rcondv, doublereal + *work, integer *lwork, integer *iwork, integer *info); + +/* Subroutine */ int dgegs_(char *jobvsl, char *jobvsr, integer *n, + doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal * + alphar, doublereal *alphai, doublereal *beta, doublereal *vsl, + integer *ldvsl, doublereal *vsr, integer *ldvsr, doublereal *work, + integer *lwork, integer *info); + +/* Subroutine */ int dgegv_(char *jobvl, char *jobvr, integer *n, doublereal * + a, integer *lda, doublereal *b, integer *ldb, doublereal *alphar, + doublereal *alphai, doublereal *beta, doublereal *vl, integer *ldvl, + doublereal *vr, integer *ldvr, doublereal *work, integer *lwork, + integer *info); + +/* Subroutine */ int dgehd2_(integer *n, integer *ilo, integer *ihi, + doublereal *a, integer *lda, doublereal *tau, doublereal *work, + integer *info); + +/* Subroutine */ int dgehrd_(integer *n, integer *ilo, integer *ihi, + doublereal *a, integer *lda, doublereal *tau, doublereal *work, + integer *lwork, integer *info); + +/* Subroutine */ int dgelq2_(integer *m, integer *n, doublereal *a, integer * + lda, doublereal *tau, doublereal *work, integer *info); + +/* Subroutine */ int dgelqf_(integer *m, integer *n, doublereal *a, integer * + lda, doublereal *tau, doublereal *work, integer *lwork, integer *info); + +/* Subroutine */ int dgels_(char *trans, integer *m, integer *n, integer * + nrhs, doublereal *a, integer *lda, doublereal *b, integer *ldb, + doublereal *work, integer *lwork, integer *info); + +/* Subroutine */ int dgelsd_(integer *m, integer *n, integer *nrhs, + doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal * + s, doublereal *rcond, integer *rank, doublereal *work, integer *lwork, + integer *iwork, integer *info); + +/* Subroutine */ int dgelss_(integer *m, integer *n, integer *nrhs, + doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal * + s, doublereal *rcond, integer *rank, doublereal *work, integer *lwork, + integer *info); + +/* Subroutine */ int dgelsx_(integer *m, integer *n, integer *nrhs, + doublereal *a, integer *lda, doublereal *b, integer *ldb, integer * + jpvt, doublereal *rcond, integer *rank, doublereal *work, integer * + info); + +/* Subroutine */ int dgelsy_(integer *m, integer *n, integer *nrhs, + doublereal *a, integer *lda, doublereal *b, integer *ldb, integer * + jpvt, doublereal *rcond, integer *rank, doublereal *work, integer * + lwork, integer *info); + +/* Subroutine */ int dgeql2_(integer *m, integer *n, doublereal *a, integer * + lda, doublereal *tau, doublereal *work, integer *info); + +/* Subroutine */ int dgeqlf_(integer *m, integer *n, doublereal *a, integer * + lda, doublereal *tau, doublereal *work, integer *lwork, integer *info); + +/* Subroutine */ int dgeqp3_(integer *m, integer *n, doublereal *a, integer * + lda, integer *jpvt, doublereal *tau, doublereal *work, integer *lwork, + integer *info); + +/* Subroutine */ int dgeqpf_(integer *m, integer *n, doublereal *a, integer * + lda, integer *jpvt, doublereal *tau, doublereal *work, integer *info); + +/* Subroutine */ int dgeqr2_(integer *m, integer *n, doublereal *a, integer * + lda, doublereal *tau, doublereal *work, integer *info); + +/* Subroutine */ int dgeqrf_(integer *m, integer *n, doublereal *a, integer * + lda, doublereal *tau, doublereal *work, integer *lwork, integer *info); + +/* Subroutine */ int dgerfs_(char *trans, integer *n, integer *nrhs, + doublereal *a, integer *lda, doublereal *af, integer *ldaf, integer * + ipiv, doublereal *b, integer *ldb, doublereal *x, integer *ldx, + doublereal *ferr, doublereal *berr, doublereal *work, integer *iwork, + integer *info); + +/* Subroutine */ int dgerq2_(integer *m, integer *n, doublereal *a, integer * + lda, doublereal *tau, doublereal *work, integer *info); + +/* Subroutine */ int dgerqf_(integer *m, integer *n, doublereal *a, integer * + lda, doublereal *tau, doublereal *work, integer *lwork, integer *info); + +/* Subroutine */ int dgesc2_(integer *n, doublereal *a, integer *lda, + doublereal *rhs, integer *ipiv, integer *jpiv, doublereal *scale); + +/* Subroutine */ int dgesdd_(char *jobz, integer *m, integer *n, doublereal * + a, integer *lda, doublereal *s, doublereal *u, integer *ldu, + doublereal *vt, integer *ldvt, doublereal *work, integer *lwork, + integer *iwork, integer *info); + +/* Subroutine */ int dgesv_(integer *n, integer *nrhs, doublereal *a, integer + *lda, integer *ipiv, doublereal *b, integer *ldb, integer *info); + +/* Subroutine */ int dgesvd_(char *jobu, char *jobvt, integer *m, integer *n, + doublereal *a, integer *lda, doublereal *s, doublereal *u, integer * + ldu, doublereal *vt, integer *ldvt, doublereal *work, integer *lwork, + integer *info); + +/* Subroutine */ int dgesvx_(char *fact, char *trans, integer *n, integer * + nrhs, doublereal *a, integer *lda, doublereal *af, integer *ldaf, + integer *ipiv, char *equed, doublereal *r__, doublereal *c__, + doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal * + rcond, doublereal *ferr, doublereal *berr, doublereal *work, integer * + iwork, integer *info); + +/* Subroutine */ int dgetc2_(integer *n, doublereal *a, integer *lda, integer + *ipiv, integer *jpiv, integer *info); + +/* Subroutine */ int dgetf2_(integer *m, integer *n, doublereal *a, integer * + lda, integer *ipiv, integer *info); + +/* Subroutine */ int dgetrf_(integer *m, integer *n, doublereal *a, integer * + lda, integer *ipiv, integer *info); + +/* Subroutine */ int dgetri_(integer *n, doublereal *a, integer *lda, integer + *ipiv, doublereal *work, integer *lwork, integer *info); + +/* Subroutine */ int dgetrs_(char *trans, integer *n, integer *nrhs, + doublereal *a, integer *lda, integer *ipiv, doublereal *b, integer * + ldb, integer *info); + +/* Subroutine */ int dggbak_(char *job, char *side, integer *n, integer *ilo, + integer *ihi, doublereal *lscale, doublereal *rscale, integer *m, + doublereal *v, integer *ldv, integer *info); + +/* Subroutine */ int dggbal_(char *job, integer *n, doublereal *a, integer * + lda, doublereal *b, integer *ldb, integer *ilo, integer *ihi, + doublereal *lscale, doublereal *rscale, doublereal *work, integer * + info); + +/* Subroutine */ int dgges_(char *jobvsl, char *jobvsr, char *sort, L_fp + delctg, integer *n, doublereal *a, integer *lda, doublereal *b, + integer *ldb, integer *sdim, doublereal *alphar, doublereal *alphai, + doublereal *beta, doublereal *vsl, integer *ldvsl, doublereal *vsr, + integer *ldvsr, doublereal *work, integer *lwork, logical *bwork, + integer *info); + +/* Subroutine */ int dggesx_(char *jobvsl, char *jobvsr, char *sort, L_fp + delctg, char *sense, integer *n, doublereal *a, integer *lda, + doublereal *b, integer *ldb, integer *sdim, doublereal *alphar, + doublereal *alphai, doublereal *beta, doublereal *vsl, integer *ldvsl, + doublereal *vsr, integer *ldvsr, doublereal *rconde, doublereal * + rcondv, doublereal *work, integer *lwork, integer *iwork, integer * + liwork, logical *bwork, integer *info); + +/* Subroutine */ int dggev_(char *jobvl, char *jobvr, integer *n, doublereal * + a, integer *lda, doublereal *b, integer *ldb, doublereal *alphar, + doublereal *alphai, doublereal *beta, doublereal *vl, integer *ldvl, + doublereal *vr, integer *ldvr, doublereal *work, integer *lwork, + integer *info); + +/* Subroutine */ int dggevx_(char *balanc, char *jobvl, char *jobvr, char * + sense, integer *n, doublereal *a, integer *lda, doublereal *b, + integer *ldb, doublereal *alphar, doublereal *alphai, doublereal * + beta, doublereal *vl, integer *ldvl, doublereal *vr, integer *ldvr, + integer *ilo, integer *ihi, doublereal *lscale, doublereal *rscale, + doublereal *abnrm, doublereal *bbnrm, doublereal *rconde, doublereal * + rcondv, doublereal *work, integer *lwork, integer *iwork, logical * + bwork, integer *info); + +/* Subroutine */ int dggglm_(integer *n, integer *m, integer *p, doublereal * + a, integer *lda, doublereal *b, integer *ldb, doublereal *d__, + doublereal *x, doublereal *y, doublereal *work, integer *lwork, + integer *info); + +/* Subroutine */ int dgghrd_(char *compq, char *compz, integer *n, integer * + ilo, integer *ihi, doublereal *a, integer *lda, doublereal *b, + integer *ldb, doublereal *q, integer *ldq, doublereal *z__, integer * + ldz, integer *info); + +/* Subroutine */ int dgglse_(integer *m, integer *n, integer *p, doublereal * + a, integer *lda, doublereal *b, integer *ldb, doublereal *c__, + doublereal *d__, doublereal *x, doublereal *work, integer *lwork, + integer *info); + +/* Subroutine */ int dggqrf_(integer *n, integer *m, integer *p, doublereal * + a, integer *lda, doublereal *taua, doublereal *b, integer *ldb, + doublereal *taub, doublereal *work, integer *lwork, integer *info); + +/* Subroutine */ int dggrqf_(integer *m, integer *p, integer *n, doublereal * + a, integer *lda, doublereal *taua, doublereal *b, integer *ldb, + doublereal *taub, doublereal *work, integer *lwork, integer *info); + +/* Subroutine */ int dggsvd_(char *jobu, char *jobv, char *jobq, integer *m, + integer *n, integer *p, integer *k, integer *l, doublereal *a, + integer *lda, doublereal *b, integer *ldb, doublereal *alpha, + doublereal *beta, doublereal *u, integer *ldu, doublereal *v, integer + *ldv, doublereal *q, integer *ldq, doublereal *work, integer *iwork, + integer *info); + +/* Subroutine */ int dggsvp_(char *jobu, char *jobv, char *jobq, integer *m, + integer *p, integer *n, doublereal *a, integer *lda, doublereal *b, + integer *ldb, doublereal *tola, doublereal *tolb, integer *k, integer + *l, doublereal *u, integer *ldu, doublereal *v, integer *ldv, + doublereal *q, integer *ldq, integer *iwork, doublereal *tau, + doublereal *work, integer *info); + +/* Subroutine */ int dgtcon_(char *norm, integer *n, doublereal *dl, + doublereal *d__, doublereal *du, doublereal *du2, integer *ipiv, + doublereal *anorm, doublereal *rcond, doublereal *work, integer * + iwork, integer *info); + +/* Subroutine */ int dgtrfs_(char *trans, integer *n, integer *nrhs, + doublereal *dl, doublereal *d__, doublereal *du, doublereal *dlf, + doublereal *df, doublereal *duf, doublereal *du2, integer *ipiv, + doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal * + ferr, doublereal *berr, doublereal *work, integer *iwork, integer * + info); + +/* Subroutine */ int dgtsv_(integer *n, integer *nrhs, doublereal *dl, + doublereal *d__, doublereal *du, doublereal *b, integer *ldb, integer + *info); + +/* Subroutine */ int dgtsvx_(char *fact, char *trans, integer *n, integer * + nrhs, doublereal *dl, doublereal *d__, doublereal *du, doublereal * + dlf, doublereal *df, doublereal *duf, doublereal *du2, integer *ipiv, + doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal * + rcond, doublereal *ferr, doublereal *berr, doublereal *work, integer * + iwork, integer *info); + +/* Subroutine */ int dgttrf_(integer *n, doublereal *dl, doublereal *d__, + doublereal *du, doublereal *du2, integer *ipiv, integer *info); + +/* Subroutine */ int dgttrs_(char *trans, integer *n, integer *nrhs, + doublereal *dl, doublereal *d__, doublereal *du, doublereal *du2, + integer *ipiv, doublereal *b, integer *ldb, integer *info); + +/* Subroutine */ int dgtts2_(integer *itrans, integer *n, integer *nrhs, + doublereal *dl, doublereal *d__, doublereal *du, doublereal *du2, + integer *ipiv, doublereal *b, integer *ldb); + +/* Subroutine */ int dhgeqz_(char *job, char *compq, char *compz, integer *n, + integer *ilo, integer *ihi, doublereal *a, integer *lda, doublereal * + b, integer *ldb, doublereal *alphar, doublereal *alphai, doublereal * + beta, doublereal *q, integer *ldq, doublereal *z__, integer *ldz, + doublereal *work, integer *lwork, integer *info); + +/* Subroutine */ int dhsein_(char *side, char *eigsrc, char *initv, logical * + select, integer *n, doublereal *h__, integer *ldh, doublereal *wr, + doublereal *wi, doublereal *vl, integer *ldvl, doublereal *vr, + integer *ldvr, integer *mm, integer *m, doublereal *work, integer * + ifaill, integer *ifailr, integer *info); + +/* Subroutine */ int dhseqr_(char *job, char *compz, integer *n, integer *ilo, + integer *ihi, doublereal *h__, integer *ldh, doublereal *wr, + doublereal *wi, doublereal *z__, integer *ldz, doublereal *work, + integer *lwork, integer *info); + +/* Subroutine */ int dlabad_(doublereal *small, doublereal *large); + +/* Subroutine */ int dlabrd_(integer *m, integer *n, integer *nb, doublereal * + a, integer *lda, doublereal *d__, doublereal *e, doublereal *tauq, + doublereal *taup, doublereal *x, integer *ldx, doublereal *y, integer + *ldy); + +/* Subroutine */ int dlacon_(integer *n, doublereal *v, doublereal *x, + integer *isgn, doublereal *est, integer *kase); + +/* Subroutine */ int dlacpy_(char *uplo, integer *m, integer *n, doublereal * + a, integer *lda, doublereal *b, integer *ldb); + +/* Subroutine */ int dladiv_(doublereal *a, doublereal *b, doublereal *c__, + doublereal *d__, doublereal *p, doublereal *q); + +/* Subroutine */ int dlae2_(doublereal *a, doublereal *b, doublereal *c__, + doublereal *rt1, doublereal *rt2); + +/* Subroutine */ int dlaebz_(integer *ijob, integer *nitmax, integer *n, + integer *mmax, integer *minp, integer *nbmin, doublereal *abstol, + doublereal *reltol, doublereal *pivmin, doublereal *d__, doublereal * + e, doublereal *e2, integer *nval, doublereal *ab, doublereal *c__, + integer *mout, integer *nab, doublereal *work, integer *iwork, + integer *info); + +/* Subroutine */ int dlaed0_(integer *icompq, integer *qsiz, integer *n, + doublereal *d__, doublereal *e, doublereal *q, integer *ldq, + doublereal *qstore, integer *ldqs, doublereal *work, integer *iwork, + integer *info); + +/* Subroutine */ int dlaed1_(integer *n, doublereal *d__, doublereal *q, + integer *ldq, integer *indxq, doublereal *rho, integer *cutpnt, + doublereal *work, integer *iwork, integer *info); + +/* Subroutine */ int dlaed2_(integer *k, integer *n, integer *n1, doublereal * + d__, doublereal *q, integer *ldq, integer *indxq, doublereal *rho, + doublereal *z__, doublereal *dlamda, doublereal *w, doublereal *q2, + integer *indx, integer *indxc, integer *indxp, integer *coltyp, + integer *info); + +/* Subroutine */ int dlaed3_(integer *k, integer *n, integer *n1, doublereal * + d__, doublereal *q, integer *ldq, doublereal *rho, doublereal *dlamda, + doublereal *q2, integer *indx, integer *ctot, doublereal *w, + doublereal *s, integer *info); + +/* Subroutine */ int dlaed4_(integer *n, integer *i__, doublereal *d__, + doublereal *z__, doublereal *delta, doublereal *rho, doublereal *dlam, + integer *info); + +/* Subroutine */ int dlaed5_(integer *i__, doublereal *d__, doublereal *z__, + doublereal *delta, doublereal *rho, doublereal *dlam); + +/* Subroutine */ int dlaed6_(integer *kniter, logical *orgati, doublereal * + rho, doublereal *d__, doublereal *z__, doublereal *finit, doublereal * + tau, integer *info); + +/* Subroutine */ int dlaed7_(integer *icompq, integer *n, integer *qsiz, + integer *tlvls, integer *curlvl, integer *curpbm, doublereal *d__, + doublereal *q, integer *ldq, integer *indxq, doublereal *rho, integer + *cutpnt, doublereal *qstore, integer *qptr, integer *prmptr, integer * + perm, integer *givptr, integer *givcol, doublereal *givnum, + doublereal *work, integer *iwork, integer *info); + +/* Subroutine */ int dlaed8_(integer *icompq, integer *k, integer *n, integer + *qsiz, doublereal *d__, doublereal *q, integer *ldq, integer *indxq, + doublereal *rho, integer *cutpnt, doublereal *z__, doublereal *dlamda, + doublereal *q2, integer *ldq2, doublereal *w, integer *perm, integer + *givptr, integer *givcol, doublereal *givnum, integer *indxp, integer + *indx, integer *info); + +/* Subroutine */ int dlaed9_(integer *k, integer *kstart, integer *kstop, + integer *n, doublereal *d__, doublereal *q, integer *ldq, doublereal * + rho, doublereal *dlamda, doublereal *w, doublereal *s, integer *lds, + integer *info); + +/* Subroutine */ int dlaeda_(integer *n, integer *tlvls, integer *curlvl, + integer *curpbm, integer *prmptr, integer *perm, integer *givptr, + integer *givcol, doublereal *givnum, doublereal *q, integer *qptr, + doublereal *z__, doublereal *ztemp, integer *info); + +/* Subroutine */ int dlaein_(logical *rightv, logical *noinit, integer *n, + doublereal *h__, integer *ldh, doublereal *wr, doublereal *wi, + doublereal *vr, doublereal *vi, doublereal *b, integer *ldb, + doublereal *work, doublereal *eps3, doublereal *smlnum, doublereal * + bignum, integer *info); + +/* Subroutine */ int dlaev2_(doublereal *a, doublereal *b, doublereal *c__, + doublereal *rt1, doublereal *rt2, doublereal *cs1, doublereal *sn1); + +/* Subroutine */ int dlaexc_(logical *wantq, integer *n, doublereal *t, + integer *ldt, doublereal *q, integer *ldq, integer *j1, integer *n1, + integer *n2, doublereal *work, integer *info); + +/* Subroutine */ int dlag2_(doublereal *a, integer *lda, doublereal *b, + integer *ldb, doublereal *safmin, doublereal *scale1, doublereal * + scale2, doublereal *wr1, doublereal *wr2, doublereal *wi); + +/* Subroutine */ int dlags2_(logical *upper, doublereal *a1, doublereal *a2, + doublereal *a3, doublereal *b1, doublereal *b2, doublereal *b3, + doublereal *csu, doublereal *snu, doublereal *csv, doublereal *snv, + doublereal *csq, doublereal *snq); + +/* Subroutine */ int dlagtf_(integer *n, doublereal *a, doublereal *lambda, + doublereal *b, doublereal *c__, doublereal *tol, doublereal *d__, + integer *in, integer *info); + +/* Subroutine */ int dlagtm_(char *trans, integer *n, integer *nrhs, + doublereal *alpha, doublereal *dl, doublereal *d__, doublereal *du, + doublereal *x, integer *ldx, doublereal *beta, doublereal *b, integer + *ldb); + +/* Subroutine */ int dlagts_(integer *job, integer *n, doublereal *a, + doublereal *b, doublereal *c__, doublereal *d__, integer *in, + doublereal *y, doublereal *tol, integer *info); + +/* Subroutine */ int dlagv2_(doublereal *a, integer *lda, doublereal *b, + integer *ldb, doublereal *alphar, doublereal *alphai, doublereal * + beta, doublereal *csl, doublereal *snl, doublereal *csr, doublereal * + snr); + +/* Subroutine */ int dlahqr_(logical *wantt, logical *wantz, integer *n, + integer *ilo, integer *ihi, doublereal *h__, integer *ldh, doublereal + *wr, doublereal *wi, integer *iloz, integer *ihiz, doublereal *z__, + integer *ldz, integer *info); + +/* Subroutine */ int dlahrd_(integer *n, integer *k, integer *nb, doublereal * + a, integer *lda, doublereal *tau, doublereal *t, integer *ldt, + doublereal *y, integer *ldy); + +/* Subroutine */ int dlaic1_(integer *job, integer *j, doublereal *x, + doublereal *sest, doublereal *w, doublereal *gamma, doublereal * + sestpr, doublereal *s, doublereal *c__); + +/* Subroutine */ int dlaln2_(logical *ltrans, integer *na, integer *nw, + doublereal *smin, doublereal *ca, doublereal *a, integer *lda, + doublereal *d1, doublereal *d2, doublereal *b, integer *ldb, + doublereal *wr, doublereal *wi, doublereal *x, integer *ldx, + doublereal *scale, doublereal *xnorm, integer *info); + +/* Subroutine */ int dlals0_(integer *icompq, integer *nl, integer *nr, + integer *sqre, integer *nrhs, doublereal *b, integer *ldb, doublereal + *bx, integer *ldbx, integer *perm, integer *givptr, integer *givcol, + integer *ldgcol, doublereal *givnum, integer *ldgnum, doublereal * + poles, doublereal *difl, doublereal *difr, doublereal *z__, integer * + k, doublereal *c__, doublereal *s, doublereal *work, integer *info); + +/* Subroutine */ int dlalsa_(integer *icompq, integer *smlsiz, integer *n, + integer *nrhs, doublereal *b, integer *ldb, doublereal *bx, integer * + ldbx, doublereal *u, integer *ldu, doublereal *vt, integer *k, + doublereal *difl, doublereal *difr, doublereal *z__, doublereal * + poles, integer *givptr, integer *givcol, integer *ldgcol, integer * + perm, doublereal *givnum, doublereal *c__, doublereal *s, doublereal * + work, integer *iwork, integer *info); + +/* Subroutine */ int dlalsd_(char *uplo, integer *smlsiz, integer *n, integer + *nrhs, doublereal *d__, doublereal *e, doublereal *b, integer *ldb, + doublereal *rcond, integer *rank, doublereal *work, integer *iwork, + integer *info); + +/* Subroutine */ int dlamc1_(integer *beta, integer *t, logical *rnd, logical + *ieee1); + +/* Subroutine */ int dlamc2_(integer *beta, integer *t, logical *rnd, + doublereal *eps, integer *emin, doublereal *rmin, integer *emax, + doublereal *rmax); + +/* Subroutine */ int dlamc4_(integer *emin, doublereal *start, integer *base); + +/* Subroutine */ int dlamc5_(integer *beta, integer *p, integer *emin, + logical *ieee, integer *emax, doublereal *rmax); + +/* Subroutine */ int dlamrg_(integer *n1, integer *n2, doublereal *a, integer + *dtrd1, integer *dtrd2, integer *index); + +/* Subroutine */ int dlanv2_(doublereal *a, doublereal *b, doublereal *c__, + doublereal *d__, doublereal *rt1r, doublereal *rt1i, doublereal *rt2r, + doublereal *rt2i, doublereal *cs, doublereal *sn); + +/* Subroutine */ int dlapll_(integer *n, doublereal *x, integer *incx, + doublereal *y, integer *incy, doublereal *ssmin); + +/* Subroutine */ int dlapmt_(logical *forwrd, integer *m, integer *n, + doublereal *x, integer *ldx, integer *k); + +/* Subroutine */ int dlaqgb_(integer *m, integer *n, integer *kl, integer *ku, + doublereal *ab, integer *ldab, doublereal *r__, doublereal *c__, + doublereal *rowcnd, doublereal *colcnd, doublereal *amax, char *equed); + +/* Subroutine */ int dlaqge_(integer *m, integer *n, doublereal *a, integer * + lda, doublereal *r__, doublereal *c__, doublereal *rowcnd, doublereal + *colcnd, doublereal *amax, char *equed); + +/* Subroutine */ int dlaqp2_(integer *m, integer *n, integer *offset, + doublereal *a, integer *lda, integer *jpvt, doublereal *tau, + doublereal *vn1, doublereal *vn2, doublereal *work); + +/* Subroutine */ int dlaqps_(integer *m, integer *n, integer *offset, integer + *nb, integer *kb, doublereal *a, integer *lda, integer *jpvt, + doublereal *tau, doublereal *vn1, doublereal *vn2, doublereal *auxv, + doublereal *f, integer *ldf); + +/* Subroutine */ int dlaqsb_(char *uplo, integer *n, integer *kd, doublereal * + ab, integer *ldab, doublereal *s, doublereal *scond, doublereal *amax, + char *equed); + +/* Subroutine */ int dlaqsp_(char *uplo, integer *n, doublereal *ap, + doublereal *s, doublereal *scond, doublereal *amax, char *equed); + +/* Subroutine */ int dlaqsy_(char *uplo, integer *n, doublereal *a, integer * + lda, doublereal *s, doublereal *scond, doublereal *amax, char *equed); + +/* Subroutine */ int dlaqtr_(logical *ltran, logical *lreal, integer *n, + doublereal *t, integer *ldt, doublereal *b, doublereal *w, doublereal + *scale, doublereal *x, doublereal *work, integer *info); + +/* Subroutine */ int dlar1v_(integer *n, integer *b1, integer *bn, doublereal + *sigma, doublereal *d__, doublereal *l, doublereal *ld, doublereal * + lld, doublereal *gersch, doublereal *z__, doublereal *ztz, doublereal + *mingma, integer *r__, integer *isuppz, doublereal *work); + +/* Subroutine */ int dlar2v_(integer *n, doublereal *x, doublereal *y, + doublereal *z__, integer *incx, doublereal *c__, doublereal *s, + integer *incc); + +/* Subroutine */ int dlarf_(char *side, integer *m, integer *n, doublereal *v, + integer *incv, doublereal *tau, doublereal *c__, integer *ldc, + doublereal *work); + +/* Subroutine */ int dlarfb_(char *side, char *trans, char *direct, char * + storev, integer *m, integer *n, integer *k, doublereal *v, integer * + ldv, doublereal *t, integer *ldt, doublereal *c__, integer *ldc, + doublereal *work, integer *ldwork); + +/* Subroutine */ int dlarfg_(integer *n, doublereal *alpha, doublereal *x, + integer *incx, doublereal *tau); + +/* Subroutine */ int dlarft_(char *direct, char *storev, integer *n, integer * + k, doublereal *v, integer *ldv, doublereal *tau, doublereal *t, + integer *ldt); + +/* Subroutine */ int dlarfx_(char *side, integer *m, integer *n, doublereal * + v, doublereal *tau, doublereal *c__, integer *ldc, doublereal *work); + +/* Subroutine */ int dlargv_(integer *n, doublereal *x, integer *incx, + doublereal *y, integer *incy, doublereal *c__, integer *incc); + +/* Subroutine */ int dlarnv_(integer *idist, integer *iseed, integer *n, + doublereal *x); + +/* Subroutine */ int dlarrb_(integer *n, doublereal *d__, doublereal *l, + doublereal *ld, doublereal *lld, integer *ifirst, integer *ilast, + doublereal *sigma, doublereal *reltol, doublereal *w, doublereal * + wgap, doublereal *werr, doublereal *work, integer *iwork, integer * + info); + +/* Subroutine */ int dlarre_(integer *n, doublereal *d__, doublereal *e, + doublereal *tol, integer *nsplit, integer *isplit, integer *m, + doublereal *w, doublereal *woff, doublereal *gersch, doublereal *work, + integer *info); + +/* Subroutine */ int dlarrf_(integer *n, doublereal *d__, doublereal *l, + doublereal *ld, doublereal *lld, integer *ifirst, integer *ilast, + doublereal *w, doublereal *dplus, doublereal *lplus, doublereal *work, + integer *iwork, integer *info); + +/* Subroutine */ int dlarrv_(integer *n, doublereal *d__, doublereal *l, + integer *isplit, integer *m, doublereal *w, integer *iblock, + doublereal *gersch, doublereal *tol, doublereal *z__, integer *ldz, + integer *isuppz, doublereal *work, integer *iwork, integer *info); + +/* Subroutine */ int dlartg_(doublereal *f, doublereal *g, doublereal *cs, + doublereal *sn, doublereal *r__); + +/* Subroutine */ int dlartv_(integer *n, doublereal *x, integer *incx, + doublereal *y, integer *incy, doublereal *c__, doublereal *s, integer + *incc); + +/* Subroutine */ int dlaruv_(integer *iseed, integer *n, doublereal *x); + +/* Subroutine */ int dlarz_(char *side, integer *m, integer *n, integer *l, + doublereal *v, integer *incv, doublereal *tau, doublereal *c__, + integer *ldc, doublereal *work); + +/* Subroutine */ int dlarzb_(char *side, char *trans, char *direct, char * + storev, integer *m, integer *n, integer *k, integer *l, doublereal *v, + integer *ldv, doublereal *t, integer *ldt, doublereal *c__, integer * + ldc, doublereal *work, integer *ldwork); + +/* Subroutine */ int dlarzt_(char *direct, char *storev, integer *n, integer * + k, doublereal *v, integer *ldv, doublereal *tau, doublereal *t, + integer *ldt); + +/* Subroutine */ int dlas2_(doublereal *f, doublereal *g, doublereal *h__, + doublereal *ssmin, doublereal *ssmax); + +/* Subroutine */ int dlascl_(char *type__, integer *kl, integer *ku, + doublereal *cfrom, doublereal *cto, integer *m, integer *n, + doublereal *a, integer *lda, integer *info); + +/* Subroutine */ int dlasd0_(integer *n, integer *sqre, doublereal *d__, + doublereal *e, doublereal *u, integer *ldu, doublereal *vt, integer * + ldvt, integer *smlsiz, integer *iwork, doublereal *work, integer * + info); + +/* Subroutine */ int dlasd1_(integer *nl, integer *nr, integer *sqre, + doublereal *d__, doublereal *alpha, doublereal *beta, doublereal *u, + integer *ldu, doublereal *vt, integer *ldvt, integer *idxq, integer * + iwork, doublereal *work, integer *info); + +/* Subroutine */ int dlasd2_(integer *nl, integer *nr, integer *sqre, integer + *k, doublereal *d__, doublereal *z__, doublereal *alpha, doublereal * + beta, doublereal *u, integer *ldu, doublereal *vt, integer *ldvt, + doublereal *dsigma, doublereal *u2, integer *ldu2, doublereal *vt2, + integer *ldvt2, integer *idxp, integer *idx, integer *idxc, integer * + idxq, integer *coltyp, integer *info); + +/* Subroutine */ int dlasd3_(integer *nl, integer *nr, integer *sqre, integer + *k, doublereal *d__, doublereal *q, integer *ldq, doublereal *dsigma, + doublereal *u, integer *ldu, doublereal *u2, integer *ldu2, + doublereal *vt, integer *ldvt, doublereal *vt2, integer *ldvt2, + integer *idxc, integer *ctot, doublereal *z__, integer *info); + +/* Subroutine */ int dlasd4_(integer *n, integer *i__, doublereal *d__, + doublereal *z__, doublereal *delta, doublereal *rho, doublereal * + sigma, doublereal *work, integer *info); + +/* Subroutine */ int dlasd5_(integer *i__, doublereal *d__, doublereal *z__, + doublereal *delta, doublereal *rho, doublereal *dsigma, doublereal * + work); + +/* Subroutine */ int dlasd6_(integer *icompq, integer *nl, integer *nr, + integer *sqre, doublereal *d__, doublereal *vf, doublereal *vl, + doublereal *alpha, doublereal *beta, integer *idxq, integer *perm, + integer *givptr, integer *givcol, integer *ldgcol, doublereal *givnum, + integer *ldgnum, doublereal *poles, doublereal *difl, doublereal * + difr, doublereal *z__, integer *k, doublereal *c__, doublereal *s, + doublereal *work, integer *iwork, integer *info); + +/* Subroutine */ int dlasd7_(integer *icompq, integer *nl, integer *nr, + integer *sqre, integer *k, doublereal *d__, doublereal *z__, + doublereal *zw, doublereal *vf, doublereal *vfw, doublereal *vl, + doublereal *vlw, doublereal *alpha, doublereal *beta, doublereal * + dsigma, integer *idx, integer *idxp, integer *idxq, integer *perm, + integer *givptr, integer *givcol, integer *ldgcol, doublereal *givnum, + integer *ldgnum, doublereal *c__, doublereal *s, integer *info); + +/* Subroutine */ int dlasd8_(integer *icompq, integer *k, doublereal *d__, + doublereal *z__, doublereal *vf, doublereal *vl, doublereal *difl, + doublereal *difr, integer *lddifr, doublereal *dsigma, doublereal * + work, integer *info); + +/* Subroutine */ int dlasd9_(integer *icompq, integer *ldu, integer *k, + doublereal *d__, doublereal *z__, doublereal *vf, doublereal *vl, + doublereal *difl, doublereal *difr, doublereal *dsigma, doublereal * + work, integer *info); + +/* Subroutine */ int dlasda_(integer *icompq, integer *smlsiz, integer *n, + integer *sqre, doublereal *d__, doublereal *e, doublereal *u, integer + *ldu, doublereal *vt, integer *k, doublereal *difl, doublereal *difr, + doublereal *z__, doublereal *poles, integer *givptr, integer *givcol, + integer *ldgcol, integer *perm, doublereal *givnum, doublereal *c__, + doublereal *s, doublereal *work, integer *iwork, integer *info); + +/* Subroutine */ int dlasdq_(char *uplo, integer *sqre, integer *n, integer * + ncvt, integer *nru, integer *ncc, doublereal *d__, doublereal *e, + doublereal *vt, integer *ldvt, doublereal *u, integer *ldu, + doublereal *c__, integer *ldc, doublereal *work, integer *info); + +/* Subroutine */ int dlasdt_(integer *n, integer *lvl, integer *nd, integer * + inode, integer *ndiml, integer *ndimr, integer *msub); + +/* Subroutine */ int dlaset_(char *uplo, integer *m, integer *n, doublereal * + alpha, doublereal *beta, doublereal *a, integer *lda); + +/* Subroutine */ int dlasq1_(integer *n, doublereal *d__, doublereal *e, + doublereal *work, integer *info); + +/* Subroutine */ int dlasq2_(integer *n, doublereal *z__, integer *info); + +/* Subroutine */ int dlasq3_(integer *i0, integer *n0, doublereal *z__, + integer *pp, doublereal *dmin__, doublereal *sigma, doublereal *desig, + doublereal *qmax, integer *nfail, integer *iter, integer *ndiv, + logical *ieee); + +/* Subroutine */ int dlasq4_(integer *i0, integer *n0, doublereal *z__, + integer *pp, integer *n0in, doublereal *dmin__, doublereal *dmin1, + doublereal *dmin2, doublereal *dn, doublereal *dn1, doublereal *dn2, + doublereal *tau, integer *ttype); + +/* Subroutine */ int dlasq5_(integer *i0, integer *n0, doublereal *z__, + integer *pp, doublereal *tau, doublereal *dmin__, doublereal *dmin1, + doublereal *dmin2, doublereal *dn, doublereal *dnm1, doublereal *dnm2, + logical *ieee); + +/* Subroutine */ int dlasq6_(integer *i0, integer *n0, doublereal *z__, + integer *pp, doublereal *dmin__, doublereal *dmin1, doublereal *dmin2, + doublereal *dn, doublereal *dnm1, doublereal *dnm2); + +/* Subroutine */ int dlasr_(char *side, char *pivot, char *direct, integer *m, + integer *n, doublereal *c__, doublereal *s, doublereal *a, integer * + lda); + +/* Subroutine */ int dlasrt_(char *id, integer *n, doublereal *d__, integer * + info); + +/* Subroutine */ int dlassq_(integer *n, doublereal *x, integer *incx, + doublereal *scale, doublereal *sumsq); + +/* Subroutine */ int dlasv2_(doublereal *f, doublereal *g, doublereal *h__, + doublereal *ssmin, doublereal *ssmax, doublereal *snr, doublereal * + csr, doublereal *snl, doublereal *csl); + +/* Subroutine */ int dlaswp_(integer *n, doublereal *a, integer *lda, integer + *k1, integer *k2, integer *ipiv, integer *incx); + +/* Subroutine */ int dlasy2_(logical *ltranl, logical *ltranr, integer *isgn, + integer *n1, integer *n2, doublereal *tl, integer *ldtl, doublereal * + tr, integer *ldtr, doublereal *b, integer *ldb, doublereal *scale, + doublereal *x, integer *ldx, doublereal *xnorm, integer *info); + +/* Subroutine */ int dlasyf_(char *uplo, integer *n, integer *nb, integer *kb, + doublereal *a, integer *lda, integer *ipiv, doublereal *w, integer * + ldw, integer *info); + +/* Subroutine */ int dlatbs_(char *uplo, char *trans, char *diag, char * + normin, integer *n, integer *kd, doublereal *ab, integer *ldab, + doublereal *x, doublereal *scale, doublereal *cnorm, integer *info); + +/* Subroutine */ int dlatdf_(integer *ijob, integer *n, doublereal *z__, + integer *ldz, doublereal *rhs, doublereal *rdsum, doublereal *rdscal, + integer *ipiv, integer *jpiv); + +/* Subroutine */ int dlatps_(char *uplo, char *trans, char *diag, char * + normin, integer *n, doublereal *ap, doublereal *x, doublereal *scale, + doublereal *cnorm, integer *info); + +/* Subroutine */ int dlatrd_(char *uplo, integer *n, integer *nb, doublereal * + a, integer *lda, doublereal *e, doublereal *tau, doublereal *w, + integer *ldw); + +/* Subroutine */ int dlatrs_(char *uplo, char *trans, char *diag, char * + normin, integer *n, doublereal *a, integer *lda, doublereal *x, + doublereal *scale, doublereal *cnorm, integer *info); + +/* Subroutine */ int dlatrz_(integer *m, integer *n, integer *l, doublereal * + a, integer *lda, doublereal *tau, doublereal *work); + +/* Subroutine */ int dlatzm_(char *side, integer *m, integer *n, doublereal * + v, integer *incv, doublereal *tau, doublereal *c1, doublereal *c2, + integer *ldc, doublereal *work); + +/* Subroutine */ int dlauu2_(char *uplo, integer *n, doublereal *a, integer * + lda, integer *info); + +/* Subroutine */ int dlauum_(char *uplo, integer *n, doublereal *a, integer * + lda, integer *info); + +/* Subroutine */ int dopgtr_(char *uplo, integer *n, doublereal *ap, + doublereal *tau, doublereal *q, integer *ldq, doublereal *work, + integer *info); + +/* Subroutine */ int dopmtr_(char *side, char *uplo, char *trans, integer *m, + integer *n, doublereal *ap, doublereal *tau, doublereal *c__, integer + *ldc, doublereal *work, integer *info); + +/* Subroutine */ int dorg2l_(integer *m, integer *n, integer *k, doublereal * + a, integer *lda, doublereal *tau, doublereal *work, integer *info); + +/* Subroutine */ int dorg2r_(integer *m, integer *n, integer *k, doublereal * + a, integer *lda, doublereal *tau, doublereal *work, integer *info); + +/* Subroutine */ int dorgbr_(char *vect, integer *m, integer *n, integer *k, + doublereal *a, integer *lda, doublereal *tau, doublereal *work, + integer *lwork, integer *info); + +/* Subroutine */ int dorghr_(integer *n, integer *ilo, integer *ihi, + doublereal *a, integer *lda, doublereal *tau, doublereal *work, + integer *lwork, integer *info); + +/* Subroutine */ int dorgl2_(integer *m, integer *n, integer *k, doublereal * + a, integer *lda, doublereal *tau, doublereal *work, integer *info); + +/* Subroutine */ int dorglq_(integer *m, integer *n, integer *k, doublereal * + a, integer *lda, doublereal *tau, doublereal *work, integer *lwork, + integer *info); + +/* Subroutine */ int dorgql_(integer *m, integer *n, integer *k, doublereal * + a, integer *lda, doublereal *tau, doublereal *work, integer *lwork, + integer *info); + +/* Subroutine */ int dorgqr_(integer *m, integer *n, integer *k, doublereal * + a, integer *lda, doublereal *tau, doublereal *work, integer *lwork, + integer *info); + +/* Subroutine */ int dorgr2_(integer *m, integer *n, integer *k, doublereal * + a, integer *lda, doublereal *tau, doublereal *work, integer *info); + +/* Subroutine */ int dorgrq_(integer *m, integer *n, integer *k, doublereal * + a, integer *lda, doublereal *tau, doublereal *work, integer *lwork, + integer *info); + +/* Subroutine */ int dorgtr_(char *uplo, integer *n, doublereal *a, integer * + lda, doublereal *tau, doublereal *work, integer *lwork, integer *info); + +/* Subroutine */ int dorm2l_(char *side, char *trans, integer *m, integer *n, + integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal * + c__, integer *ldc, doublereal *work, integer *info); + +/* Subroutine */ int dorm2r_(char *side, char *trans, integer *m, integer *n, + integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal * + c__, integer *ldc, doublereal *work, integer *info); + +/* Subroutine */ int dormbr_(char *vect, char *side, char *trans, integer *m, + integer *n, integer *k, doublereal *a, integer *lda, doublereal *tau, + doublereal *c__, integer *ldc, doublereal *work, integer *lwork, + integer *info); + +/* Subroutine */ int dormhr_(char *side, char *trans, integer *m, integer *n, + integer *ilo, integer *ihi, doublereal *a, integer *lda, doublereal * + tau, doublereal *c__, integer *ldc, doublereal *work, integer *lwork, + integer *info); + +/* Subroutine */ int dorml2_(char *side, char *trans, integer *m, integer *n, + integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal * + c__, integer *ldc, doublereal *work, integer *info); + +/* Subroutine */ int dormlq_(char *side, char *trans, integer *m, integer *n, + integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal * + c__, integer *ldc, doublereal *work, integer *lwork, integer *info); + +/* Subroutine */ int dormql_(char *side, char *trans, integer *m, integer *n, + integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal * + c__, integer *ldc, doublereal *work, integer *lwork, integer *info); + +/* Subroutine */ int dormqr_(char *side, char *trans, integer *m, integer *n, + integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal * + c__, integer *ldc, doublereal *work, integer *lwork, integer *info); + +/* Subroutine */ int dormr2_(char *side, char *trans, integer *m, integer *n, + integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal * + c__, integer *ldc, doublereal *work, integer *info); + +/* Subroutine */ int dormr3_(char *side, char *trans, integer *m, integer *n, + integer *k, integer *l, doublereal *a, integer *lda, doublereal *tau, + doublereal *c__, integer *ldc, doublereal *work, integer *info); + +/* Subroutine */ int dormrq_(char *side, char *trans, integer *m, integer *n, + integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal * + c__, integer *ldc, doublereal *work, integer *lwork, integer *info); + +/* Subroutine */ int dormrz_(char *side, char *trans, integer *m, integer *n, + integer *k, integer *l, doublereal *a, integer *lda, doublereal *tau, + doublereal *c__, integer *ldc, doublereal *work, integer *lwork, + integer *info); + +/* Subroutine */ int dormtr_(char *side, char *uplo, char *trans, integer *m, + integer *n, doublereal *a, integer *lda, doublereal *tau, doublereal * + c__, integer *ldc, doublereal *work, integer *lwork, integer *info); + +/* Subroutine */ int dpbcon_(char *uplo, integer *n, integer *kd, doublereal * + ab, integer *ldab, doublereal *anorm, doublereal *rcond, doublereal * + work, integer *iwork, integer *info); + +/* Subroutine */ int dpbequ_(char *uplo, integer *n, integer *kd, doublereal * + ab, integer *ldab, doublereal *s, doublereal *scond, doublereal *amax, + integer *info); + +/* Subroutine */ int dpbrfs_(char *uplo, integer *n, integer *kd, integer * + nrhs, doublereal *ab, integer *ldab, doublereal *afb, integer *ldafb, + doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal * + ferr, doublereal *berr, doublereal *work, integer *iwork, integer * + info); + +/* Subroutine */ int dpbstf_(char *uplo, integer *n, integer *kd, doublereal * + ab, integer *ldab, integer *info); + +/* Subroutine */ int dpbsv_(char *uplo, integer *n, integer *kd, integer * + nrhs, doublereal *ab, integer *ldab, doublereal *b, integer *ldb, + integer *info); + +/* Subroutine */ int dpbsvx_(char *fact, char *uplo, integer *n, integer *kd, + integer *nrhs, doublereal *ab, integer *ldab, doublereal *afb, + integer *ldafb, char *equed, doublereal *s, doublereal *b, integer * + ldb, doublereal *x, integer *ldx, doublereal *rcond, doublereal *ferr, + doublereal *berr, doublereal *work, integer *iwork, integer *info); + +/* Subroutine */ int dpbtf2_(char *uplo, integer *n, integer *kd, doublereal * + ab, integer *ldab, integer *info); + +/* Subroutine */ int dpbtrf_(char *uplo, integer *n, integer *kd, doublereal * + ab, integer *ldab, integer *info); + +/* Subroutine */ int dpbtrs_(char *uplo, integer *n, integer *kd, integer * + nrhs, doublereal *ab, integer *ldab, doublereal *b, integer *ldb, + integer *info); + +/* Subroutine */ int dpocon_(char *uplo, integer *n, doublereal *a, integer * + lda, doublereal *anorm, doublereal *rcond, doublereal *work, integer * + iwork, integer *info); + +/* Subroutine */ int dpoequ_(integer *n, doublereal *a, integer *lda, + doublereal *s, doublereal *scond, doublereal *amax, integer *info); + +/* Subroutine */ int dporfs_(char *uplo, integer *n, integer *nrhs, + doublereal *a, integer *lda, doublereal *af, integer *ldaf, + doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal * + ferr, doublereal *berr, doublereal *work, integer *iwork, integer * + info); + +/* Subroutine */ int dposv_(char *uplo, integer *n, integer *nrhs, doublereal + *a, integer *lda, doublereal *b, integer *ldb, integer *info); + +/* Subroutine */ int dposvx_(char *fact, char *uplo, integer *n, integer * + nrhs, doublereal *a, integer *lda, doublereal *af, integer *ldaf, + char *equed, doublereal *s, doublereal *b, integer *ldb, doublereal * + x, integer *ldx, doublereal *rcond, doublereal *ferr, doublereal * + berr, doublereal *work, integer *iwork, integer *info); + +/* Subroutine */ int dpotf2_(char *uplo, integer *n, doublereal *a, integer * + lda, integer *info); + +/* Subroutine */ int dpotrf_(char *uplo, integer *n, doublereal *a, integer * + lda, integer *info); + +/* Subroutine */ int dpotri_(char *uplo, integer *n, doublereal *a, integer * + lda, integer *info); + +/* Subroutine */ int dpotrs_(char *uplo, integer *n, integer *nrhs, + doublereal *a, integer *lda, doublereal *b, integer *ldb, integer * + info); + +/* Subroutine */ int dppcon_(char *uplo, integer *n, doublereal *ap, + doublereal *anorm, doublereal *rcond, doublereal *work, integer * + iwork, integer *info); + +/* Subroutine */ int dppequ_(char *uplo, integer *n, doublereal *ap, + doublereal *s, doublereal *scond, doublereal *amax, integer *info); + +/* Subroutine */ int dpprfs_(char *uplo, integer *n, integer *nrhs, + doublereal *ap, doublereal *afp, doublereal *b, integer *ldb, + doublereal *x, integer *ldx, doublereal *ferr, doublereal *berr, + doublereal *work, integer *iwork, integer *info); + +/* Subroutine */ int dppsv_(char *uplo, integer *n, integer *nrhs, doublereal + *ap, doublereal *b, integer *ldb, integer *info); + +/* Subroutine */ int dppsvx_(char *fact, char *uplo, integer *n, integer * + nrhs, doublereal *ap, doublereal *afp, char *equed, doublereal *s, + doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal * + rcond, doublereal *ferr, doublereal *berr, doublereal *work, integer * + iwork, integer *info); + +/* Subroutine */ int dpptrf_(char *uplo, integer *n, doublereal *ap, integer * + info); + +/* Subroutine */ int dpptri_(char *uplo, integer *n, doublereal *ap, integer * + info); + +/* Subroutine */ int dpptrs_(char *uplo, integer *n, integer *nrhs, + doublereal *ap, doublereal *b, integer *ldb, integer *info); + +/* Subroutine */ int dptcon_(integer *n, doublereal *d__, doublereal *e, + doublereal *anorm, doublereal *rcond, doublereal *work, integer *info); + +/* Subroutine */ int dpteqr_(char *compz, integer *n, doublereal *d__, + doublereal *e, doublereal *z__, integer *ldz, doublereal *work, + integer *info); + +/* Subroutine */ int dptrfs_(integer *n, integer *nrhs, doublereal *d__, + doublereal *e, doublereal *df, doublereal *ef, doublereal *b, integer + *ldb, doublereal *x, integer *ldx, doublereal *ferr, doublereal *berr, + doublereal *work, integer *info); + +/* Subroutine */ int dptsv_(integer *n, integer *nrhs, doublereal *d__, + doublereal *e, doublereal *b, integer *ldb, integer *info); + +/* Subroutine */ int dptsvx_(char *fact, integer *n, integer *nrhs, + doublereal *d__, doublereal *e, doublereal *df, doublereal *ef, + doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal * + rcond, doublereal *ferr, doublereal *berr, doublereal *work, integer * + info); + +/* Subroutine */ int dpttrf_(integer *n, doublereal *d__, doublereal *e, + integer *info); + +/* Subroutine */ int dpttrs_(integer *n, integer *nrhs, doublereal *d__, + doublereal *e, doublereal *b, integer *ldb, integer *info); + +/* Subroutine */ int dptts2_(integer *n, integer *nrhs, doublereal *d__, + doublereal *e, doublereal *b, integer *ldb); + +/* Subroutine */ int drscl_(integer *n, doublereal *sa, doublereal *sx, + integer *incx); + +/* Subroutine */ int dsbev_(char *jobz, char *uplo, integer *n, integer *kd, + doublereal *ab, integer *ldab, doublereal *w, doublereal *z__, + integer *ldz, doublereal *work, integer *info); + +/* Subroutine */ int dsbevd_(char *jobz, char *uplo, integer *n, integer *kd, + doublereal *ab, integer *ldab, doublereal *w, doublereal *z__, + integer *ldz, doublereal *work, integer *lwork, integer *iwork, + integer *liwork, integer *info); + +/* Subroutine */ int dsbevx_(char *jobz, char *range, char *uplo, integer *n, + integer *kd, doublereal *ab, integer *ldab, doublereal *q, integer * + ldq, doublereal *vl, doublereal *vu, integer *il, integer *iu, + doublereal *abstol, integer *m, doublereal *w, doublereal *z__, + integer *ldz, doublereal *work, integer *iwork, integer *ifail, + integer *info); + +/* Subroutine */ int dsbgst_(char *vect, char *uplo, integer *n, integer *ka, + integer *kb, doublereal *ab, integer *ldab, doublereal *bb, integer * + ldbb, doublereal *x, integer *ldx, doublereal *work, integer *info); + +/* Subroutine */ int dsbgv_(char *jobz, char *uplo, integer *n, integer *ka, + integer *kb, doublereal *ab, integer *ldab, doublereal *bb, integer * + ldbb, doublereal *w, doublereal *z__, integer *ldz, doublereal *work, + integer *info); + +/* Subroutine */ int dsbgvd_(char *jobz, char *uplo, integer *n, integer *ka, + integer *kb, doublereal *ab, integer *ldab, doublereal *bb, integer * + ldbb, doublereal *w, doublereal *z__, integer *ldz, doublereal *work, + integer *lwork, integer *iwork, integer *liwork, integer *info); + +/* Subroutine */ int dsbgvx_(char *jobz, char *range, char *uplo, integer *n, + integer *ka, integer *kb, doublereal *ab, integer *ldab, doublereal * + bb, integer *ldbb, doublereal *q, integer *ldq, doublereal *vl, + doublereal *vu, integer *il, integer *iu, doublereal *abstol, integer + *m, doublereal *w, doublereal *z__, integer *ldz, doublereal *work, + integer *iwork, integer *ifail, integer *info); + +/* Subroutine */ int dsbtrd_(char *vect, char *uplo, integer *n, integer *kd, + doublereal *ab, integer *ldab, doublereal *d__, doublereal *e, + doublereal *q, integer *ldq, doublereal *work, integer *info); + +/* Subroutine */ int dspcon_(char *uplo, integer *n, doublereal *ap, integer * + ipiv, doublereal *anorm, doublereal *rcond, doublereal *work, integer + *iwork, integer *info); + +/* Subroutine */ int dspev_(char *jobz, char *uplo, integer *n, doublereal * + ap, doublereal *w, doublereal *z__, integer *ldz, doublereal *work, + integer *info); + +/* Subroutine */ int dspevd_(char *jobz, char *uplo, integer *n, doublereal * + ap, doublereal *w, doublereal *z__, integer *ldz, doublereal *work, + integer *lwork, integer *iwork, integer *liwork, integer *info); + +/* Subroutine */ int dspevx_(char *jobz, char *range, char *uplo, integer *n, + doublereal *ap, doublereal *vl, doublereal *vu, integer *il, integer * + iu, doublereal *abstol, integer *m, doublereal *w, doublereal *z__, + integer *ldz, doublereal *work, integer *iwork, integer *ifail, + integer *info); + +/* Subroutine */ int dspgst_(integer *itype, char *uplo, integer *n, + doublereal *ap, doublereal *bp, integer *info); + +/* Subroutine */ int dspgv_(integer *itype, char *jobz, char *uplo, integer * + n, doublereal *ap, doublereal *bp, doublereal *w, doublereal *z__, + integer *ldz, doublereal *work, integer *info); + +/* Subroutine */ int dspgvd_(integer *itype, char *jobz, char *uplo, integer * + n, doublereal *ap, doublereal *bp, doublereal *w, doublereal *z__, + integer *ldz, doublereal *work, integer *lwork, integer *iwork, + integer *liwork, integer *info); + +/* Subroutine */ int dspgvx_(integer *itype, char *jobz, char *range, char * + uplo, integer *n, doublereal *ap, doublereal *bp, doublereal *vl, + doublereal *vu, integer *il, integer *iu, doublereal *abstol, integer + *m, doublereal *w, doublereal *z__, integer *ldz, doublereal *work, + integer *iwork, integer *ifail, integer *info); + +/* Subroutine */ int dsprfs_(char *uplo, integer *n, integer *nrhs, + doublereal *ap, doublereal *afp, integer *ipiv, doublereal *b, + integer *ldb, doublereal *x, integer *ldx, doublereal *ferr, + doublereal *berr, doublereal *work, integer *iwork, integer *info); + +/* Subroutine */ int dspsv_(char *uplo, integer *n, integer *nrhs, doublereal + *ap, integer *ipiv, doublereal *b, integer *ldb, integer *info); + +/* Subroutine */ int dspsvx_(char *fact, char *uplo, integer *n, integer * + nrhs, doublereal *ap, doublereal *afp, integer *ipiv, doublereal *b, + integer *ldb, doublereal *x, integer *ldx, doublereal *rcond, + doublereal *ferr, doublereal *berr, doublereal *work, integer *iwork, + integer *info); + +/* Subroutine */ int dsptrd_(char *uplo, integer *n, doublereal *ap, + doublereal *d__, doublereal *e, doublereal *tau, integer *info); + +/* Subroutine */ int dsptrf_(char *uplo, integer *n, doublereal *ap, integer * + ipiv, integer *info); + +/* Subroutine */ int dsptri_(char *uplo, integer *n, doublereal *ap, integer * + ipiv, doublereal *work, integer *info); + +/* Subroutine */ int dsptrs_(char *uplo, integer *n, integer *nrhs, + doublereal *ap, integer *ipiv, doublereal *b, integer *ldb, integer * + info); + +/* Subroutine */ int dstebz_(char *range, char *order, integer *n, doublereal + *vl, doublereal *vu, integer *il, integer *iu, doublereal *abstol, + doublereal *d__, doublereal *e, integer *m, integer *nsplit, + doublereal *w, integer *iblock, integer *isplit, doublereal *work, + integer *iwork, integer *info); + +/* Subroutine */ int dstedc_(char *compz, integer *n, doublereal *d__, + doublereal *e, doublereal *z__, integer *ldz, doublereal *work, + integer *lwork, integer *iwork, integer *liwork, integer *info); + +/* Subroutine */ int dstegr_(char *jobz, char *range, integer *n, doublereal * + d__, doublereal *e, doublereal *vl, doublereal *vu, integer *il, + integer *iu, doublereal *abstol, integer *m, doublereal *w, + doublereal *z__, integer *ldz, integer *isuppz, doublereal *work, + integer *lwork, integer *iwork, integer *liwork, integer *info); + +/* Subroutine */ int dstein_(integer *n, doublereal *d__, doublereal *e, + integer *m, doublereal *w, integer *iblock, integer *isplit, + doublereal *z__, integer *ldz, doublereal *work, integer *iwork, + integer *ifail, integer *info); + +/* Subroutine */ int dsteqr_(char *compz, integer *n, doublereal *d__, + doublereal *e, doublereal *z__, integer *ldz, doublereal *work, + integer *info); + +/* Subroutine */ int dsterf_(integer *n, doublereal *d__, doublereal *e, + integer *info); + +/* Subroutine */ int dstev_(char *jobz, integer *n, doublereal *d__, + doublereal *e, doublereal *z__, integer *ldz, doublereal *work, + integer *info); + +/* Subroutine */ int dstevd_(char *jobz, integer *n, doublereal *d__, + doublereal *e, doublereal *z__, integer *ldz, doublereal *work, + integer *lwork, integer *iwork, integer *liwork, integer *info); + +/* Subroutine */ int dstevr_(char *jobz, char *range, integer *n, doublereal * + d__, doublereal *e, doublereal *vl, doublereal *vu, integer *il, + integer *iu, doublereal *abstol, integer *m, doublereal *w, + doublereal *z__, integer *ldz, integer *isuppz, doublereal *work, + integer *lwork, integer *iwork, integer *liwork, integer *info); + +/* Subroutine */ int dstevx_(char *jobz, char *range, integer *n, doublereal * + d__, doublereal *e, doublereal *vl, doublereal *vu, integer *il, + integer *iu, doublereal *abstol, integer *m, doublereal *w, + doublereal *z__, integer *ldz, doublereal *work, integer *iwork, + integer *ifail, integer *info); + +/* Subroutine */ int dsycon_(char *uplo, integer *n, doublereal *a, integer * + lda, integer *ipiv, doublereal *anorm, doublereal *rcond, doublereal * + work, integer *iwork, integer *info); + +/* Subroutine */ int dsyev_(char *jobz, char *uplo, integer *n, doublereal *a, + integer *lda, doublereal *w, doublereal *work, integer *lwork, + integer *info); + +/* Subroutine */ int dsyevd_(char *jobz, char *uplo, integer *n, doublereal * + a, integer *lda, doublereal *w, doublereal *work, integer *lwork, + integer *iwork, integer *liwork, integer *info); + +/* Subroutine */ int dsyevr_(char *jobz, char *range, char *uplo, integer *n, + doublereal *a, integer *lda, doublereal *vl, doublereal *vu, integer * + il, integer *iu, doublereal *abstol, integer *m, doublereal *w, + doublereal *z__, integer *ldz, integer *isuppz, doublereal *work, + integer *lwork, integer *iwork, integer *liwork, integer *info); + +/* Subroutine */ int dsyevx_(char *jobz, char *range, char *uplo, integer *n, + doublereal *a, integer *lda, doublereal *vl, doublereal *vu, integer * + il, integer *iu, doublereal *abstol, integer *m, doublereal *w, + doublereal *z__, integer *ldz, doublereal *work, integer *lwork, + integer *iwork, integer *ifail, integer *info); + +/* Subroutine */ int dsygs2_(integer *itype, char *uplo, integer *n, + doublereal *a, integer *lda, doublereal *b, integer *ldb, integer * + info); + +/* Subroutine */ int dsygst_(integer *itype, char *uplo, integer *n, + doublereal *a, integer *lda, doublereal *b, integer *ldb, integer * + info); + +/* Subroutine */ int dsygv_(integer *itype, char *jobz, char *uplo, integer * + n, doublereal *a, integer *lda, doublereal *b, integer *ldb, + doublereal *w, doublereal *work, integer *lwork, integer *info); + +/* Subroutine */ int dsygvd_(integer *itype, char *jobz, char *uplo, integer * + n, doublereal *a, integer *lda, doublereal *b, integer *ldb, + doublereal *w, doublereal *work, integer *lwork, integer *iwork, + integer *liwork, integer *info); + +/* Subroutine */ int dsygvx_(integer *itype, char *jobz, char *range, char * + uplo, integer *n, doublereal *a, integer *lda, doublereal *b, integer + *ldb, doublereal *vl, doublereal *vu, integer *il, integer *iu, + doublereal *abstol, integer *m, doublereal *w, doublereal *z__, + integer *ldz, doublereal *work, integer *lwork, integer *iwork, + integer *ifail, integer *info); + +/* Subroutine */ int dsyrfs_(char *uplo, integer *n, integer *nrhs, + doublereal *a, integer *lda, doublereal *af, integer *ldaf, integer * + ipiv, doublereal *b, integer *ldb, doublereal *x, integer *ldx, + doublereal *ferr, doublereal *berr, doublereal *work, integer *iwork, + integer *info); + +/* Subroutine */ int dsysv_(char *uplo, integer *n, integer *nrhs, doublereal + *a, integer *lda, integer *ipiv, doublereal *b, integer *ldb, + doublereal *work, integer *lwork, integer *info); + +/* Subroutine */ int dsysvx_(char *fact, char *uplo, integer *n, integer * + nrhs, doublereal *a, integer *lda, doublereal *af, integer *ldaf, + integer *ipiv, doublereal *b, integer *ldb, doublereal *x, integer * + ldx, doublereal *rcond, doublereal *ferr, doublereal *berr, + doublereal *work, integer *lwork, integer *iwork, integer *info); + +/* Subroutine */ int dsytd2_(char *uplo, integer *n, doublereal *a, integer * + lda, doublereal *d__, doublereal *e, doublereal *tau, integer *info); + +/* Subroutine */ int dsytf2_(char *uplo, integer *n, doublereal *a, integer * + lda, integer *ipiv, integer *info); + +/* Subroutine */ int dsytrd_(char *uplo, integer *n, doublereal *a, integer * + lda, doublereal *d__, doublereal *e, doublereal *tau, doublereal * + work, integer *lwork, integer *info); + +/* Subroutine */ int dsytrf_(char *uplo, integer *n, doublereal *a, integer * + lda, integer *ipiv, doublereal *work, integer *lwork, integer *info); + +/* Subroutine */ int dsytri_(char *uplo, integer *n, doublereal *a, integer * + lda, integer *ipiv, doublereal *work, integer *info); + +/* Subroutine */ int dsytrs_(char *uplo, integer *n, integer *nrhs, + doublereal *a, integer *lda, integer *ipiv, doublereal *b, integer * + ldb, integer *info); + +/* Subroutine */ int dtbcon_(char *norm, char *uplo, char *diag, integer *n, + integer *kd, doublereal *ab, integer *ldab, doublereal *rcond, + doublereal *work, integer *iwork, integer *info); + +/* Subroutine */ int dtbrfs_(char *uplo, char *trans, char *diag, integer *n, + integer *kd, integer *nrhs, doublereal *ab, integer *ldab, doublereal + *b, integer *ldb, doublereal *x, integer *ldx, doublereal *ferr, + doublereal *berr, doublereal *work, integer *iwork, integer *info); + +/* Subroutine */ int dtbtrs_(char *uplo, char *trans, char *diag, integer *n, + integer *kd, integer *nrhs, doublereal *ab, integer *ldab, doublereal + *b, integer *ldb, integer *info); + +/* Subroutine */ int dtgevc_(char *side, char *howmny, logical *select, + integer *n, doublereal *a, integer *lda, doublereal *b, integer *ldb, + doublereal *vl, integer *ldvl, doublereal *vr, integer *ldvr, integer + *mm, integer *m, doublereal *work, integer *info); + +/* Subroutine */ int dtgex2_(logical *wantq, logical *wantz, integer *n, + doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal * + q, integer *ldq, doublereal *z__, integer *ldz, integer *j1, integer * + n1, integer *n2, doublereal *work, integer *lwork, integer *info); + +/* Subroutine */ int dtgexc_(logical *wantq, logical *wantz, integer *n, + doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal * + q, integer *ldq, doublereal *z__, integer *ldz, integer *ifst, + integer *ilst, doublereal *work, integer *lwork, integer *info); + +/* Subroutine */ int dtgsen_(integer *ijob, logical *wantq, logical *wantz, + logical *select, integer *n, doublereal *a, integer *lda, doublereal * + b, integer *ldb, doublereal *alphar, doublereal *alphai, doublereal * + beta, doublereal *q, integer *ldq, doublereal *z__, integer *ldz, + integer *m, doublereal *pl, doublereal *pr, doublereal *dif, + doublereal *work, integer *lwork, integer *iwork, integer *liwork, + integer *info); + +/* Subroutine */ int dtgsja_(char *jobu, char *jobv, char *jobq, integer *m, + integer *p, integer *n, integer *k, integer *l, doublereal *a, + integer *lda, doublereal *b, integer *ldb, doublereal *tola, + doublereal *tolb, doublereal *alpha, doublereal *beta, doublereal *u, + integer *ldu, doublereal *v, integer *ldv, doublereal *q, integer * + ldq, doublereal *work, integer *ncycle, integer *info); + +/* Subroutine */ int dtgsna_(char *job, char *howmny, logical *select, + integer *n, doublereal *a, integer *lda, doublereal *b, integer *ldb, + doublereal *vl, integer *ldvl, doublereal *vr, integer *ldvr, + doublereal *s, doublereal *dif, integer *mm, integer *m, doublereal * + work, integer *lwork, integer *iwork, integer *info); + +/* Subroutine */ int dtgsy2_(char *trans, integer *ijob, integer *m, integer * + n, doublereal *a, integer *lda, doublereal *b, integer *ldb, + doublereal *c__, integer *ldc, doublereal *d__, integer *ldd, + doublereal *e, integer *lde, doublereal *f, integer *ldf, doublereal * + scale, doublereal *rdsum, doublereal *rdscal, integer *iwork, integer + *pq, integer *info); + +/* Subroutine */ int dtgsyl_(char *trans, integer *ijob, integer *m, integer * + n, doublereal *a, integer *lda, doublereal *b, integer *ldb, + doublereal *c__, integer *ldc, doublereal *d__, integer *ldd, + doublereal *e, integer *lde, doublereal *f, integer *ldf, doublereal * + scale, doublereal *dif, doublereal *work, integer *lwork, integer * + iwork, integer *info); + +/* Subroutine */ int dtpcon_(char *norm, char *uplo, char *diag, integer *n, + doublereal *ap, doublereal *rcond, doublereal *work, integer *iwork, + integer *info); + +/* Subroutine */ int dtprfs_(char *uplo, char *trans, char *diag, integer *n, + integer *nrhs, doublereal *ap, doublereal *b, integer *ldb, + doublereal *x, integer *ldx, doublereal *ferr, doublereal *berr, + doublereal *work, integer *iwork, integer *info); + +/* Subroutine */ int dtptri_(char *uplo, char *diag, integer *n, doublereal * + ap, integer *info); + +/* Subroutine */ int dtptrs_(char *uplo, char *trans, char *diag, integer *n, + integer *nrhs, doublereal *ap, doublereal *b, integer *ldb, integer * + info); + +/* Subroutine */ int dtrcon_(char *norm, char *uplo, char *diag, integer *n, + doublereal *a, integer *lda, doublereal *rcond, doublereal *work, + integer *iwork, integer *info); + +/* Subroutine */ int dtrevc_(char *side, char *howmny, logical *select, + integer *n, doublereal *t, integer *ldt, doublereal *vl, integer * + ldvl, doublereal *vr, integer *ldvr, integer *mm, integer *m, + doublereal *work, integer *info); + +/* Subroutine */ int dtrexc_(char *compq, integer *n, doublereal *t, integer * + ldt, doublereal *q, integer *ldq, integer *ifst, integer *ilst, + doublereal *work, integer *info); + +/* Subroutine */ int dtrrfs_(char *uplo, char *trans, char *diag, integer *n, + integer *nrhs, doublereal *a, integer *lda, doublereal *b, integer * + ldb, doublereal *x, integer *ldx, doublereal *ferr, doublereal *berr, + doublereal *work, integer *iwork, integer *info); + +/* Subroutine */ int dtrsen_(char *job, char *compq, logical *select, integer + *n, doublereal *t, integer *ldt, doublereal *q, integer *ldq, + doublereal *wr, doublereal *wi, integer *m, doublereal *s, doublereal + *sep, doublereal *work, integer *lwork, integer *iwork, integer * + liwork, integer *info); + +/* Subroutine */ int dtrsna_(char *job, char *howmny, logical *select, + integer *n, doublereal *t, integer *ldt, doublereal *vl, integer * + ldvl, doublereal *vr, integer *ldvr, doublereal *s, doublereal *sep, + integer *mm, integer *m, doublereal *work, integer *ldwork, integer * + iwork, integer *info); + +/* Subroutine */ int dtrsyl_(char *trana, char *tranb, integer *isgn, integer + *m, integer *n, doublereal *a, integer *lda, doublereal *b, integer * + ldb, doublereal *c__, integer *ldc, doublereal *scale, integer *info); + +/* Subroutine */ int dtrti2_(char *uplo, char *diag, integer *n, doublereal * + a, integer *lda, integer *info); + +/* Subroutine */ int dtrtri_(char *uplo, char *diag, integer *n, doublereal * + a, integer *lda, integer *info); + +/* Subroutine */ int dtrtrs_(char *uplo, char *trans, char *diag, integer *n, + integer *nrhs, doublereal *a, integer *lda, doublereal *b, integer * + ldb, integer *info); + +/* Subroutine */ int dtzrqf_(integer *m, integer *n, doublereal *a, integer * + lda, doublereal *tau, integer *info); + +/* Subroutine */ int dtzrzf_(integer *m, integer *n, doublereal *a, integer * + lda, doublereal *tau, doublereal *work, integer *lwork, integer *info); + +integer icmax1_(integer *n, complex *cx, integer *incx); + +integer ieeeck_(integer *ispec, real *zero, real *one); + +integer ilaenv_(integer *ispec, char *name__, char *opts, integer *n1, + integer *n2, integer *n3, integer *n4, ftnlen name_len, ftnlen + opts_len); + +integer izmax1_(integer *n, doublecomplex *cx, integer *incx); + +/* Subroutine */ int sbdsdc_(char *uplo, char *compq, integer *n, real *d__, + real *e, real *u, integer *ldu, real *vt, integer *ldvt, real *q, + integer *iq, real *work, integer *iwork, integer *info); + +/* Subroutine */ int sbdsqr_(char *uplo, integer *n, integer *ncvt, integer * + nru, integer *ncc, real *d__, real *e, real *vt, integer *ldvt, real * + u, integer *ldu, real *c__, integer *ldc, real *work, integer *info); + +/* Subroutine */ int sdisna_(char *job, integer *m, integer *n, real *d__, + real *sep, integer *info); + +/* Subroutine */ int sgbbrd_(char *vect, integer *m, integer *n, integer *ncc, + integer *kl, integer *ku, real *ab, integer *ldab, real *d__, real * + e, real *q, integer *ldq, real *pt, integer *ldpt, real *c__, integer + *ldc, real *work, integer *info); + +/* Subroutine */ int sgbcon_(char *norm, integer *n, integer *kl, integer *ku, + real *ab, integer *ldab, integer *ipiv, real *anorm, real *rcond, + real *work, integer *iwork, integer *info); + +/* Subroutine */ int sgbequ_(integer *m, integer *n, integer *kl, integer *ku, + real *ab, integer *ldab, real *r__, real *c__, real *rowcnd, real * + colcnd, real *amax, integer *info); + +/* Subroutine */ int sgbrfs_(char *trans, integer *n, integer *kl, integer * + ku, integer *nrhs, real *ab, integer *ldab, real *afb, integer *ldafb, + integer *ipiv, real *b, integer *ldb, real *x, integer *ldx, real * + ferr, real *berr, real *work, integer *iwork, integer *info); + +/* Subroutine */ int sgbsv_(integer *n, integer *kl, integer *ku, integer * + nrhs, real *ab, integer *ldab, integer *ipiv, real *b, integer *ldb, + integer *info); + +/* Subroutine */ int sgbsvx_(char *fact, char *trans, integer *n, integer *kl, + integer *ku, integer *nrhs, real *ab, integer *ldab, real *afb, + integer *ldafb, integer *ipiv, char *equed, real *r__, real *c__, + real *b, integer *ldb, real *x, integer *ldx, real *rcond, real *ferr, + real *berr, real *work, integer *iwork, integer *info); + +/* Subroutine */ int sgbtf2_(integer *m, integer *n, integer *kl, integer *ku, + real *ab, integer *ldab, integer *ipiv, integer *info); + +/* Subroutine */ int sgbtrf_(integer *m, integer *n, integer *kl, integer *ku, + real *ab, integer *ldab, integer *ipiv, integer *info); + +/* Subroutine */ int sgbtrs_(char *trans, integer *n, integer *kl, integer * + ku, integer *nrhs, real *ab, integer *ldab, integer *ipiv, real *b, + integer *ldb, integer *info); + +/* Subroutine */ int sgebak_(char *job, char *side, integer *n, integer *ilo, + integer *ihi, real *scale, integer *m, real *v, integer *ldv, integer + *info); + +/* Subroutine */ int sgebal_(char *job, integer *n, real *a, integer *lda, + integer *ilo, integer *ihi, real *scale, integer *info); + +/* Subroutine */ int sgebd2_(integer *m, integer *n, real *a, integer *lda, + real *d__, real *e, real *tauq, real *taup, real *work, integer *info); + +/* Subroutine */ int sgebrd_(integer *m, integer *n, real *a, integer *lda, + real *d__, real *e, real *tauq, real *taup, real *work, integer * + lwork, integer *info); + +/* Subroutine */ int sgecon_(char *norm, integer *n, real *a, integer *lda, + real *anorm, real *rcond, real *work, integer *iwork, integer *info); + +/* Subroutine */ int sgeequ_(integer *m, integer *n, real *a, integer *lda, + real *r__, real *c__, real *rowcnd, real *colcnd, real *amax, integer + *info); + +/* Subroutine */ int sgees_(char *jobvs, char *sort, L_fp select, integer *n, + real *a, integer *lda, integer *sdim, real *wr, real *wi, real *vs, + integer *ldvs, real *work, integer *lwork, logical *bwork, integer * + info); + +/* Subroutine */ int sgeesx_(char *jobvs, char *sort, L_fp select, char * + sense, integer *n, real *a, integer *lda, integer *sdim, real *wr, + real *wi, real *vs, integer *ldvs, real *rconde, real *rcondv, real * + work, integer *lwork, integer *iwork, integer *liwork, logical *bwork, + integer *info); + +/* Subroutine */ int sgeev_(char *jobvl, char *jobvr, integer *n, real *a, + integer *lda, real *wr, real *wi, real *vl, integer *ldvl, real *vr, + integer *ldvr, real *work, integer *lwork, integer *info); + +/* Subroutine */ int sgeevx_(char *balanc, char *jobvl, char *jobvr, char * + sense, integer *n, real *a, integer *lda, real *wr, real *wi, real * + vl, integer *ldvl, real *vr, integer *ldvr, integer *ilo, integer * + ihi, real *scale, real *abnrm, real *rconde, real *rcondv, real *work, + integer *lwork, integer *iwork, integer *info); + +/* Subroutine */ int sgegs_(char *jobvsl, char *jobvsr, integer *n, real *a, + integer *lda, real *b, integer *ldb, real *alphar, real *alphai, real + *beta, real *vsl, integer *ldvsl, real *vsr, integer *ldvsr, real * + work, integer *lwork, integer *info); + +/* Subroutine */ int sgegv_(char *jobvl, char *jobvr, integer *n, real *a, + integer *lda, real *b, integer *ldb, real *alphar, real *alphai, real + *beta, real *vl, integer *ldvl, real *vr, integer *ldvr, real *work, + integer *lwork, integer *info); + +/* Subroutine */ int sgehd2_(integer *n, integer *ilo, integer *ihi, real *a, + integer *lda, real *tau, real *work, integer *info); + +/* Subroutine */ int sgehrd_(integer *n, integer *ilo, integer *ihi, real *a, + integer *lda, real *tau, real *work, integer *lwork, integer *info); + +/* Subroutine */ int sgelq2_(integer *m, integer *n, real *a, integer *lda, + real *tau, real *work, integer *info); + +/* Subroutine */ int sgelqf_(integer *m, integer *n, real *a, integer *lda, + real *tau, real *work, integer *lwork, integer *info); + +/* Subroutine */ int sgels_(char *trans, integer *m, integer *n, integer * + nrhs, real *a, integer *lda, real *b, integer *ldb, real *work, + integer *lwork, integer *info); + +/* Subroutine */ int sgelsd_(integer *m, integer *n, integer *nrhs, real *a, + integer *lda, real *b, integer *ldb, real *s, real *rcond, integer * + rank, real *work, integer *lwork, integer *iwork, integer *info); + +/* Subroutine */ int sgelss_(integer *m, integer *n, integer *nrhs, real *a, + integer *lda, real *b, integer *ldb, real *s, real *rcond, integer * + rank, real *work, integer *lwork, integer *info); + +/* Subroutine */ int sgelsx_(integer *m, integer *n, integer *nrhs, real *a, + integer *lda, real *b, integer *ldb, integer *jpvt, real *rcond, + integer *rank, real *work, integer *info); + +/* Subroutine */ int sgelsy_(integer *m, integer *n, integer *nrhs, real *a, + integer *lda, real *b, integer *ldb, integer *jpvt, real *rcond, + integer *rank, real *work, integer *lwork, integer *info); + +/* Subroutine */ int sgeql2_(integer *m, integer *n, real *a, integer *lda, + real *tau, real *work, integer *info); + +/* Subroutine */ int sgeqlf_(integer *m, integer *n, real *a, integer *lda, + real *tau, real *work, integer *lwork, integer *info); + +/* Subroutine */ int sgeqp3_(integer *m, integer *n, real *a, integer *lda, + integer *jpvt, real *tau, real *work, integer *lwork, integer *info); + +/* Subroutine */ int sgeqpf_(integer *m, integer *n, real *a, integer *lda, + integer *jpvt, real *tau, real *work, integer *info); + +/* Subroutine */ int sgeqr2_(integer *m, integer *n, real *a, integer *lda, + real *tau, real *work, integer *info); + +/* Subroutine */ int sgeqrf_(integer *m, integer *n, real *a, integer *lda, + real *tau, real *work, integer *lwork, integer *info); + +/* Subroutine */ int sgerfs_(char *trans, integer *n, integer *nrhs, real *a, + integer *lda, real *af, integer *ldaf, integer *ipiv, real *b, + integer *ldb, real *x, integer *ldx, real *ferr, real *berr, real * + work, integer *iwork, integer *info); + +/* Subroutine */ int sgerq2_(integer *m, integer *n, real *a, integer *lda, + real *tau, real *work, integer *info); + +/* Subroutine */ int sgerqf_(integer *m, integer *n, real *a, integer *lda, + real *tau, real *work, integer *lwork, integer *info); + +/* Subroutine */ int sgesc2_(integer *n, real *a, integer *lda, real *rhs, + integer *ipiv, integer *jpiv, real *scale); + +/* Subroutine */ int sgesdd_(char *jobz, integer *m, integer *n, real *a, + integer *lda, real *s, real *u, integer *ldu, real *vt, integer *ldvt, + real *work, integer *lwork, integer *iwork, integer *info); + +/* Subroutine */ int sgesv_(integer *n, integer *nrhs, real *a, integer *lda, + integer *ipiv, real *b, integer *ldb, integer *info); + +/* Subroutine */ int sgesvd_(char *jobu, char *jobvt, integer *m, integer *n, + real *a, integer *lda, real *s, real *u, integer *ldu, real *vt, + integer *ldvt, real *work, integer *lwork, integer *info); + +/* Subroutine */ int sgesvx_(char *fact, char *trans, integer *n, integer * + nrhs, real *a, integer *lda, real *af, integer *ldaf, integer *ipiv, + char *equed, real *r__, real *c__, real *b, integer *ldb, real *x, + integer *ldx, real *rcond, real *ferr, real *berr, real *work, + integer *iwork, integer *info); + +/* Subroutine */ int sgetc2_(integer *n, real *a, integer *lda, integer *ipiv, + integer *jpiv, integer *info); + +/* Subroutine */ int sgetf2_(integer *m, integer *n, real *a, integer *lda, + integer *ipiv, integer *info); + +/* Subroutine */ int sgetrf_(integer *m, integer *n, real *a, integer *lda, + integer *ipiv, integer *info); + +/* Subroutine */ int sgetri_(integer *n, real *a, integer *lda, integer *ipiv, + real *work, integer *lwork, integer *info); + +/* Subroutine */ int sgetrs_(char *trans, integer *n, integer *nrhs, real *a, + integer *lda, integer *ipiv, real *b, integer *ldb, integer *info); + +/* Subroutine */ int sggbak_(char *job, char *side, integer *n, integer *ilo, + integer *ihi, real *lscale, real *rscale, integer *m, real *v, + integer *ldv, integer *info); + +/* Subroutine */ int sggbal_(char *job, integer *n, real *a, integer *lda, + real *b, integer *ldb, integer *ilo, integer *ihi, real *lscale, real + *rscale, real *work, integer *info); + +/* Subroutine */ int sgges_(char *jobvsl, char *jobvsr, char *sort, L_fp + selctg, integer *n, real *a, integer *lda, real *b, integer *ldb, + integer *sdim, real *alphar, real *alphai, real *beta, real *vsl, + integer *ldvsl, real *vsr, integer *ldvsr, real *work, integer *lwork, + logical *bwork, integer *info); + +/* Subroutine */ int sggesx_(char *jobvsl, char *jobvsr, char *sort, L_fp + selctg, char *sense, integer *n, real *a, integer *lda, real *b, + integer *ldb, integer *sdim, real *alphar, real *alphai, real *beta, + real *vsl, integer *ldvsl, real *vsr, integer *ldvsr, real *rconde, + real *rcondv, real *work, integer *lwork, integer *iwork, integer * + liwork, logical *bwork, integer *info); + +/* Subroutine */ int sggev_(char *jobvl, char *jobvr, integer *n, real *a, + integer *lda, real *b, integer *ldb, real *alphar, real *alphai, real + *beta, real *vl, integer *ldvl, real *vr, integer *ldvr, real *work, + integer *lwork, integer *info); + +/* Subroutine */ int sggevx_(char *balanc, char *jobvl, char *jobvr, char * + sense, integer *n, real *a, integer *lda, real *b, integer *ldb, real + *alphar, real *alphai, real *beta, real *vl, integer *ldvl, real *vr, + integer *ldvr, integer *ilo, integer *ihi, real *lscale, real *rscale, + real *abnrm, real *bbnrm, real *rconde, real *rcondv, real *work, + integer *lwork, integer *iwork, logical *bwork, integer *info); + +/* Subroutine */ int sggglm_(integer *n, integer *m, integer *p, real *a, + integer *lda, real *b, integer *ldb, real *d__, real *x, real *y, + real *work, integer *lwork, integer *info); + +/* Subroutine */ int sgghrd_(char *compq, char *compz, integer *n, integer * + ilo, integer *ihi, real *a, integer *lda, real *b, integer *ldb, real + *q, integer *ldq, real *z__, integer *ldz, integer *info); + +/* Subroutine */ int sgglse_(integer *m, integer *n, integer *p, real *a, + integer *lda, real *b, integer *ldb, real *c__, real *d__, real *x, + real *work, integer *lwork, integer *info); + +/* Subroutine */ int sggqrf_(integer *n, integer *m, integer *p, real *a, + integer *lda, real *taua, real *b, integer *ldb, real *taub, real * + work, integer *lwork, integer *info); + +/* Subroutine */ int sggrqf_(integer *m, integer *p, integer *n, real *a, + integer *lda, real *taua, real *b, integer *ldb, real *taub, real * + work, integer *lwork, integer *info); + +/* Subroutine */ int sggsvd_(char *jobu, char *jobv, char *jobq, integer *m, + integer *n, integer *p, integer *k, integer *l, real *a, integer *lda, + real *b, integer *ldb, real *alpha, real *beta, real *u, integer * + ldu, real *v, integer *ldv, real *q, integer *ldq, real *work, + integer *iwork, integer *info); + +/* Subroutine */ int sggsvp_(char *jobu, char *jobv, char *jobq, integer *m, + integer *p, integer *n, real *a, integer *lda, real *b, integer *ldb, + real *tola, real *tolb, integer *k, integer *l, real *u, integer *ldu, + real *v, integer *ldv, real *q, integer *ldq, integer *iwork, real * + tau, real *work, integer *info); + +/* Subroutine */ int sgtcon_(char *norm, integer *n, real *dl, real *d__, + real *du, real *du2, integer *ipiv, real *anorm, real *rcond, real * + work, integer *iwork, integer *info); + +/* Subroutine */ int sgtrfs_(char *trans, integer *n, integer *nrhs, real *dl, + real *d__, real *du, real *dlf, real *df, real *duf, real *du2, + integer *ipiv, real *b, integer *ldb, real *x, integer *ldx, real * + ferr, real *berr, real *work, integer *iwork, integer *info); + +/* Subroutine */ int sgtsv_(integer *n, integer *nrhs, real *dl, real *d__, + real *du, real *b, integer *ldb, integer *info); + +/* Subroutine */ int sgtsvx_(char *fact, char *trans, integer *n, integer * + nrhs, real *dl, real *d__, real *du, real *dlf, real *df, real *duf, + real *du2, integer *ipiv, real *b, integer *ldb, real *x, integer * + ldx, real *rcond, real *ferr, real *berr, real *work, integer *iwork, + integer *info); + +/* Subroutine */ int sgttrf_(integer *n, real *dl, real *d__, real *du, real * + du2, integer *ipiv, integer *info); + +/* Subroutine */ int sgttrs_(char *trans, integer *n, integer *nrhs, real *dl, + real *d__, real *du, real *du2, integer *ipiv, real *b, integer *ldb, + integer *info); + +/* Subroutine */ int sgtts2_(integer *itrans, integer *n, integer *nrhs, real + *dl, real *d__, real *du, real *du2, integer *ipiv, real *b, integer * + ldb); + +/* Subroutine */ int shgeqz_(char *job, char *compq, char *compz, integer *n, + integer *ilo, integer *ihi, real *a, integer *lda, real *b, integer * + ldb, real *alphar, real *alphai, real *beta, real *q, integer *ldq, + real *z__, integer *ldz, real *work, integer *lwork, integer *info); + +/* Subroutine */ int shsein_(char *side, char *eigsrc, char *initv, logical * + select, integer *n, real *h__, integer *ldh, real *wr, real *wi, real + *vl, integer *ldvl, real *vr, integer *ldvr, integer *mm, integer *m, + real *work, integer *ifaill, integer *ifailr, integer *info); + +/* Subroutine */ int shseqr_(char *job, char *compz, integer *n, integer *ilo, + integer *ihi, real *h__, integer *ldh, real *wr, real *wi, real *z__, + integer *ldz, real *work, integer *lwork, integer *info); + +/* Subroutine */ int slabad_(real *small, real *large); + +/* Subroutine */ int slabrd_(integer *m, integer *n, integer *nb, real *a, + integer *lda, real *d__, real *e, real *tauq, real *taup, real *x, + integer *ldx, real *y, integer *ldy); + +/* Subroutine */ int slacon_(integer *n, real *v, real *x, integer *isgn, + real *est, integer *kase); + +/* Subroutine */ int slacpy_(char *uplo, integer *m, integer *n, real *a, + integer *lda, real *b, integer *ldb); + +/* Subroutine */ int sladiv_(real *a, real *b, real *c__, real *d__, real *p, + real *q); + +/* Subroutine */ int slae2_(real *a, real *b, real *c__, real *rt1, real *rt2); + +/* Subroutine */ int slaebz_(integer *ijob, integer *nitmax, integer *n, + integer *mmax, integer *minp, integer *nbmin, real *abstol, real * + reltol, real *pivmin, real *d__, real *e, real *e2, integer *nval, + real *ab, real *c__, integer *mout, integer *nab, real *work, integer + *iwork, integer *info); + +/* Subroutine */ int slaed0_(integer *icompq, integer *qsiz, integer *n, real + *d__, real *e, real *q, integer *ldq, real *qstore, integer *ldqs, + real *work, integer *iwork, integer *info); + +/* Subroutine */ int slaed1_(integer *n, real *d__, real *q, integer *ldq, + integer *indxq, real *rho, integer *cutpnt, real *work, integer * + iwork, integer *info); + +/* Subroutine */ int slaed2_(integer *k, integer *n, integer *n1, real *d__, + real *q, integer *ldq, integer *indxq, real *rho, real *z__, real * + dlamda, real *w, real *q2, integer *indx, integer *indxc, integer * + indxp, integer *coltyp, integer *info); + +/* Subroutine */ int slaed3_(integer *k, integer *n, integer *n1, real *d__, + real *q, integer *ldq, real *rho, real *dlamda, real *q2, integer * + indx, integer *ctot, real *w, real *s, integer *info); + +/* Subroutine */ int slaed4_(integer *n, integer *i__, real *d__, real *z__, + real *delta, real *rho, real *dlam, integer *info); + +/* Subroutine */ int slaed5_(integer *i__, real *d__, real *z__, real *delta, + real *rho, real *dlam); + +/* Subroutine */ int slaed6_(integer *kniter, logical *orgati, real *rho, + real *d__, real *z__, real *finit, real *tau, integer *info); + +/* Subroutine */ int slaed7_(integer *icompq, integer *n, integer *qsiz, + integer *tlvls, integer *curlvl, integer *curpbm, real *d__, real *q, + integer *ldq, integer *indxq, real *rho, integer *cutpnt, real * + qstore, integer *qptr, integer *prmptr, integer *perm, integer * + givptr, integer *givcol, real *givnum, real *work, integer *iwork, + integer *info); + +/* Subroutine */ int slaed8_(integer *icompq, integer *k, integer *n, integer + *qsiz, real *d__, real *q, integer *ldq, integer *indxq, real *rho, + integer *cutpnt, real *z__, real *dlamda, real *q2, integer *ldq2, + real *w, integer *perm, integer *givptr, integer *givcol, real * + givnum, integer *indxp, integer *indx, integer *info); + +/* Subroutine */ int slaed9_(integer *k, integer *kstart, integer *kstop, + integer *n, real *d__, real *q, integer *ldq, real *rho, real *dlamda, + real *w, real *s, integer *lds, integer *info); + +/* Subroutine */ int slaeda_(integer *n, integer *tlvls, integer *curlvl, + integer *curpbm, integer *prmptr, integer *perm, integer *givptr, + integer *givcol, real *givnum, real *q, integer *qptr, real *z__, + real *ztemp, integer *info); + +/* Subroutine */ int slaein_(logical *rightv, logical *noinit, integer *n, + real *h__, integer *ldh, real *wr, real *wi, real *vr, real *vi, real + *b, integer *ldb, real *work, real *eps3, real *smlnum, real *bignum, + integer *info); + +/* Subroutine */ int slaev2_(real *a, real *b, real *c__, real *rt1, real * + rt2, real *cs1, real *sn1); + +/* Subroutine */ int slaexc_(logical *wantq, integer *n, real *t, integer * + ldt, real *q, integer *ldq, integer *j1, integer *n1, integer *n2, + real *work, integer *info); + +/* Subroutine */ int slag2_(real *a, integer *lda, real *b, integer *ldb, + real *safmin, real *scale1, real *scale2, real *wr1, real *wr2, real * + wi); + +/* Subroutine */ int slags2_(logical *upper, real *a1, real *a2, real *a3, + real *b1, real *b2, real *b3, real *csu, real *snu, real *csv, real * + snv, real *csq, real *snq); + +/* Subroutine */ int slagtf_(integer *n, real *a, real *lambda, real *b, real + *c__, real *tol, real *d__, integer *in, integer *info); + +/* Subroutine */ int slagtm_(char *trans, integer *n, integer *nrhs, real * + alpha, real *dl, real *d__, real *du, real *x, integer *ldx, real * + beta, real *b, integer *ldb); + +/* Subroutine */ int slagts_(integer *job, integer *n, real *a, real *b, real + *c__, real *d__, integer *in, real *y, real *tol, integer *info); + +/* Subroutine */ int slagv2_(real *a, integer *lda, real *b, integer *ldb, + real *alphar, real *alphai, real *beta, real *csl, real *snl, real * + csr, real *snr); + +/* Subroutine */ int slahqr_(logical *wantt, logical *wantz, integer *n, + integer *ilo, integer *ihi, real *h__, integer *ldh, real *wr, real * + wi, integer *iloz, integer *ihiz, real *z__, integer *ldz, integer * + info); + +/* Subroutine */ int slahrd_(integer *n, integer *k, integer *nb, real *a, + integer *lda, real *tau, real *t, integer *ldt, real *y, integer *ldy); + +/* Subroutine */ int slaic1_(integer *job, integer *j, real *x, real *sest, + real *w, real *gamma, real *sestpr, real *s, real *c__); + +/* Subroutine */ int slaln2_(logical *ltrans, integer *na, integer *nw, real * + smin, real *ca, real *a, integer *lda, real *d1, real *d2, real *b, + integer *ldb, real *wr, real *wi, real *x, integer *ldx, real *scale, + real *xnorm, integer *info); + +/* Subroutine */ int slals0_(integer *icompq, integer *nl, integer *nr, + integer *sqre, integer *nrhs, real *b, integer *ldb, real *bx, + integer *ldbx, integer *perm, integer *givptr, integer *givcol, + integer *ldgcol, real *givnum, integer *ldgnum, real *poles, real * + difl, real *difr, real *z__, integer *k, real *c__, real *s, real * + work, integer *info); + +/* Subroutine */ int slalsa_(integer *icompq, integer *smlsiz, integer *n, + integer *nrhs, real *b, integer *ldb, real *bx, integer *ldbx, real * + u, integer *ldu, real *vt, integer *k, real *difl, real *difr, real * + z__, real *poles, integer *givptr, integer *givcol, integer *ldgcol, + integer *perm, real *givnum, real *c__, real *s, real *work, integer * + iwork, integer *info); + +/* Subroutine */ int slalsd_(char *uplo, integer *smlsiz, integer *n, integer + *nrhs, real *d__, real *e, real *b, integer *ldb, real *rcond, + integer *rank, real *work, integer *iwork, integer *info); + +/* Subroutine */ int slamc1_(integer *beta, integer *t, logical *rnd, logical + *ieee1); + +/* Subroutine */ int slamc2_(integer *beta, integer *t, logical *rnd, real * + eps, integer *emin, real *rmin, integer *emax, real *rmax); + +/* Subroutine */ int slamc4_(integer *emin, real *start, integer *base); + +/* Subroutine */ int slamc5_(integer *beta, integer *p, integer *emin, + logical *ieee, integer *emax, real *rmax); + +/* Subroutine */ int slamrg_(integer *n1, integer *n2, real *a, integer * + strd1, integer *strd2, integer *index); + +/* Subroutine */ int slanv2_(real *a, real *b, real *c__, real *d__, real * + rt1r, real *rt1i, real *rt2r, real *rt2i, real *cs, real *sn); + +/* Subroutine */ int slapll_(integer *n, real *x, integer *incx, real *y, + integer *incy, real *ssmin); + +/* Subroutine */ int slapmt_(logical *forwrd, integer *m, integer *n, real *x, + integer *ldx, integer *k); + +/* Subroutine */ int slaqgb_(integer *m, integer *n, integer *kl, integer *ku, + real *ab, integer *ldab, real *r__, real *c__, real *rowcnd, real * + colcnd, real *amax, char *equed); + +/* Subroutine */ int slaqge_(integer *m, integer *n, real *a, integer *lda, + real *r__, real *c__, real *rowcnd, real *colcnd, real *amax, char * + equed); + +/* Subroutine */ int slaqp2_(integer *m, integer *n, integer *offset, real *a, + integer *lda, integer *jpvt, real *tau, real *vn1, real *vn2, real * + work); + +/* Subroutine */ int slaqps_(integer *m, integer *n, integer *offset, integer + *nb, integer *kb, real *a, integer *lda, integer *jpvt, real *tau, + real *vn1, real *vn2, real *auxv, real *f, integer *ldf); + +/* Subroutine */ int slaqsb_(char *uplo, integer *n, integer *kd, real *ab, + integer *ldab, real *s, real *scond, real *amax, char *equed); + +/* Subroutine */ int slaqsp_(char *uplo, integer *n, real *ap, real *s, real * + scond, real *amax, char *equed); + +/* Subroutine */ int slaqsy_(char *uplo, integer *n, real *a, integer *lda, + real *s, real *scond, real *amax, char *equed); + +/* Subroutine */ int slaqtr_(logical *ltran, logical *lreal, integer *n, real + *t, integer *ldt, real *b, real *w, real *scale, real *x, real *work, + integer *info); + +/* Subroutine */ int slar1v_(integer *n, integer *b1, integer *bn, real * + sigma, real *d__, real *l, real *ld, real *lld, real *gersch, real * + z__, real *ztz, real *mingma, integer *r__, integer *isuppz, real * + work); + +/* Subroutine */ int slar2v_(integer *n, real *x, real *y, real *z__, integer + *incx, real *c__, real *s, integer *incc); + +/* Subroutine */ int slarf_(char *side, integer *m, integer *n, real *v, + integer *incv, real *tau, real *c__, integer *ldc, real *work); + +/* Subroutine */ int slarfb_(char *side, char *trans, char *direct, char * + storev, integer *m, integer *n, integer *k, real *v, integer *ldv, + real *t, integer *ldt, real *c__, integer *ldc, real *work, integer * + ldwork); + +/* Subroutine */ int slarfg_(integer *n, real *alpha, real *x, integer *incx, + real *tau); + +/* Subroutine */ int slarft_(char *direct, char *storev, integer *n, integer * + k, real *v, integer *ldv, real *tau, real *t, integer *ldt); + +/* Subroutine */ int slarfx_(char *side, integer *m, integer *n, real *v, + real *tau, real *c__, integer *ldc, real *work); + +/* Subroutine */ int slargv_(integer *n, real *x, integer *incx, real *y, + integer *incy, real *c__, integer *incc); + +/* Subroutine */ int slarnv_(integer *idist, integer *iseed, integer *n, real + *x); + +/* Subroutine */ int slarrb_(integer *n, real *d__, real *l, real *ld, real * + lld, integer *ifirst, integer *ilast, real *sigma, real *reltol, real + *w, real *wgap, real *werr, real *work, integer *iwork, integer *info); + +/* Subroutine */ int slarre_(integer *n, real *d__, real *e, real *tol, + integer *nsplit, integer *isplit, integer *m, real *w, real *woff, + real *gersch, real *work, integer *info); + +/* Subroutine */ int slarrf_(integer *n, real *d__, real *l, real *ld, real * + lld, integer *ifirst, integer *ilast, real *w, real *dplus, real * + lplus, real *work, integer *iwork, integer *info); + +/* Subroutine */ int slarrv_(integer *n, real *d__, real *l, integer *isplit, + integer *m, real *w, integer *iblock, real *gersch, real *tol, real * + z__, integer *ldz, integer *isuppz, real *work, integer *iwork, + integer *info); + +/* Subroutine */ int slartg_(real *f, real *g, real *cs, real *sn, real *r__); + +/* Subroutine */ int slartv_(integer *n, real *x, integer *incx, real *y, + integer *incy, real *c__, real *s, integer *incc); + +/* Subroutine */ int slaruv_(integer *iseed, integer *n, real *x); + +/* Subroutine */ int slarz_(char *side, integer *m, integer *n, integer *l, + real *v, integer *incv, real *tau, real *c__, integer *ldc, real * + work); + +/* Subroutine */ int slarzb_(char *side, char *trans, char *direct, char * + storev, integer *m, integer *n, integer *k, integer *l, real *v, + integer *ldv, real *t, integer *ldt, real *c__, integer *ldc, real * + work, integer *ldwork); + +/* Subroutine */ int slarzt_(char *direct, char *storev, integer *n, integer * + k, real *v, integer *ldv, real *tau, real *t, integer *ldt); + +/* Subroutine */ int slas2_(real *f, real *g, real *h__, real *ssmin, real * + ssmax); + +/* Subroutine */ int slascl_(char *type__, integer *kl, integer *ku, real * + cfrom, real *cto, integer *m, integer *n, real *a, integer *lda, + integer *info); + +/* Subroutine */ int slasd0_(integer *n, integer *sqre, real *d__, real *e, + real *u, integer *ldu, real *vt, integer *ldvt, integer *smlsiz, + integer *iwork, real *work, integer *info); + +/* Subroutine */ int slasd1_(integer *nl, integer *nr, integer *sqre, real * + d__, real *alpha, real *beta, real *u, integer *ldu, real *vt, + integer *ldvt, integer *idxq, integer *iwork, real *work, integer * + info); + +/* Subroutine */ int slasd2_(integer *nl, integer *nr, integer *sqre, integer + *k, real *d__, real *z__, real *alpha, real *beta, real *u, integer * + ldu, real *vt, integer *ldvt, real *dsigma, real *u2, integer *ldu2, + real *vt2, integer *ldvt2, integer *idxp, integer *idx, integer *idxc, + integer *idxq, integer *coltyp, integer *info); + +/* Subroutine */ int slasd3_(integer *nl, integer *nr, integer *sqre, integer + *k, real *d__, real *q, integer *ldq, real *dsigma, real *u, integer * + ldu, real *u2, integer *ldu2, real *vt, integer *ldvt, real *vt2, + integer *ldvt2, integer *idxc, integer *ctot, real *z__, integer * + info); + +/* Subroutine */ int slasd4_(integer *n, integer *i__, real *d__, real *z__, + real *delta, real *rho, real *sigma, real *work, integer *info); + +/* Subroutine */ int slasd5_(integer *i__, real *d__, real *z__, real *delta, + real *rho, real *dsigma, real *work); + +/* Subroutine */ int slasd6_(integer *icompq, integer *nl, integer *nr, + integer *sqre, real *d__, real *vf, real *vl, real *alpha, real *beta, + integer *idxq, integer *perm, integer *givptr, integer *givcol, + integer *ldgcol, real *givnum, integer *ldgnum, real *poles, real * + difl, real *difr, real *z__, integer *k, real *c__, real *s, real * + work, integer *iwork, integer *info); + +/* Subroutine */ int slasd7_(integer *icompq, integer *nl, integer *nr, + integer *sqre, integer *k, real *d__, real *z__, real *zw, real *vf, + real *vfw, real *vl, real *vlw, real *alpha, real *beta, real *dsigma, + integer *idx, integer *idxp, integer *idxq, integer *perm, integer * + givptr, integer *givcol, integer *ldgcol, real *givnum, integer * + ldgnum, real *c__, real *s, integer *info); + +/* Subroutine */ int slasd8_(integer *icompq, integer *k, real *d__, real * + z__, real *vf, real *vl, real *difl, real *difr, integer *lddifr, + real *dsigma, real *work, integer *info); + +/* Subroutine */ int slasd9_(integer *icompq, integer *ldu, integer *k, real * + d__, real *z__, real *vf, real *vl, real *difl, real *difr, real * + dsigma, real *work, integer *info); + +/* Subroutine */ int slasda_(integer *icompq, integer *smlsiz, integer *n, + integer *sqre, real *d__, real *e, real *u, integer *ldu, real *vt, + integer *k, real *difl, real *difr, real *z__, real *poles, integer * + givptr, integer *givcol, integer *ldgcol, integer *perm, real *givnum, + real *c__, real *s, real *work, integer *iwork, integer *info); + +/* Subroutine */ int slasdq_(char *uplo, integer *sqre, integer *n, integer * + ncvt, integer *nru, integer *ncc, real *d__, real *e, real *vt, + integer *ldvt, real *u, integer *ldu, real *c__, integer *ldc, real * + work, integer *info); + +/* Subroutine */ int slasdt_(integer *n, integer *lvl, integer *nd, integer * + inode, integer *ndiml, integer *ndimr, integer *msub); + +/* Subroutine */ int slaset_(char *uplo, integer *m, integer *n, real *alpha, + real *beta, real *a, integer *lda); + +/* Subroutine */ int slasq1_(integer *n, real *d__, real *e, real *work, + integer *info); + +/* Subroutine */ int slasq2_(integer *n, real *z__, integer *info); + +/* Subroutine */ int slasq3_(integer *i0, integer *n0, real *z__, integer *pp, + real *dmin__, real *sigma, real *desig, real *qmax, integer *nfail, + integer *iter, integer *ndiv, logical *ieee); + +/* Subroutine */ int slasq4_(integer *i0, integer *n0, real *z__, integer *pp, + integer *n0in, real *dmin__, real *dmin1, real *dmin2, real *dn, + real *dn1, real *dn2, real *tau, integer *ttype); + +/* Subroutine */ int slasq5_(integer *i0, integer *n0, real *z__, integer *pp, + real *tau, real *dmin__, real *dmin1, real *dmin2, real *dn, real * + dnm1, real *dnm2, logical *ieee); + +/* Subroutine */ int slasq6_(integer *i0, integer *n0, real *z__, integer *pp, + real *dmin__, real *dmin1, real *dmin2, real *dn, real *dnm1, real * + dnm2); + +/* Subroutine */ int slasr_(char *side, char *pivot, char *direct, integer *m, + integer *n, real *c__, real *s, real *a, integer *lda); + +/* Subroutine */ int slasrt_(char *id, integer *n, real *d__, integer *info); + +/* Subroutine */ int slassq_(integer *n, real *x, integer *incx, real *scale, + real *sumsq); + +/* Subroutine */ int slasv2_(real *f, real *g, real *h__, real *ssmin, real * + ssmax, real *snr, real *csr, real *snl, real *csl); + +/* Subroutine */ int slaswp_(integer *n, real *a, integer *lda, integer *k1, + integer *k2, integer *ipiv, integer *incx); + +/* Subroutine */ int slasy2_(logical *ltranl, logical *ltranr, integer *isgn, + integer *n1, integer *n2, real *tl, integer *ldtl, real *tr, integer * + ldtr, real *b, integer *ldb, real *scale, real *x, integer *ldx, real + *xnorm, integer *info); + +/* Subroutine */ int slasyf_(char *uplo, integer *n, integer *nb, integer *kb, + real *a, integer *lda, integer *ipiv, real *w, integer *ldw, integer + *info); + +/* Subroutine */ int slatbs_(char *uplo, char *trans, char *diag, char * + normin, integer *n, integer *kd, real *ab, integer *ldab, real *x, + real *scale, real *cnorm, integer *info); + +/* Subroutine */ int slatdf_(integer *ijob, integer *n, real *z__, integer * + ldz, real *rhs, real *rdsum, real *rdscal, integer *ipiv, integer * + jpiv); + +/* Subroutine */ int slatps_(char *uplo, char *trans, char *diag, char * + normin, integer *n, real *ap, real *x, real *scale, real *cnorm, + integer *info); + +/* Subroutine */ int slatrd_(char *uplo, integer *n, integer *nb, real *a, + integer *lda, real *e, real *tau, real *w, integer *ldw); + +/* Subroutine */ int slatrs_(char *uplo, char *trans, char *diag, char * + normin, integer *n, real *a, integer *lda, real *x, real *scale, real + *cnorm, integer *info); + +/* Subroutine */ int slatrz_(integer *m, integer *n, integer *l, real *a, + integer *lda, real *tau, real *work); + +/* Subroutine */ int slatzm_(char *side, integer *m, integer *n, real *v, + integer *incv, real *tau, real *c1, real *c2, integer *ldc, real * + work); + +/* Subroutine */ int slauu2_(char *uplo, integer *n, real *a, integer *lda, + integer *info); + +/* Subroutine */ int slauum_(char *uplo, integer *n, real *a, integer *lda, + integer *info); + +/* Subroutine */ int sopgtr_(char *uplo, integer *n, real *ap, real *tau, + real *q, integer *ldq, real *work, integer *info); + +/* Subroutine */ int sopmtr_(char *side, char *uplo, char *trans, integer *m, + integer *n, real *ap, real *tau, real *c__, integer *ldc, real *work, + integer *info); + +/* Subroutine */ int sorg2l_(integer *m, integer *n, integer *k, real *a, + integer *lda, real *tau, real *work, integer *info); + +/* Subroutine */ int sorg2r_(integer *m, integer *n, integer *k, real *a, + integer *lda, real *tau, real *work, integer *info); + +/* Subroutine */ int sorgbr_(char *vect, integer *m, integer *n, integer *k, + real *a, integer *lda, real *tau, real *work, integer *lwork, integer + *info); + +/* Subroutine */ int sorghr_(integer *n, integer *ilo, integer *ihi, real *a, + integer *lda, real *tau, real *work, integer *lwork, integer *info); + +/* Subroutine */ int sorgl2_(integer *m, integer *n, integer *k, real *a, + integer *lda, real *tau, real *work, integer *info); + +/* Subroutine */ int sorglq_(integer *m, integer *n, integer *k, real *a, + integer *lda, real *tau, real *work, integer *lwork, integer *info); + +/* Subroutine */ int sorgql_(integer *m, integer *n, integer *k, real *a, + integer *lda, real *tau, real *work, integer *lwork, integer *info); + +/* Subroutine */ int sorgqr_(integer *m, integer *n, integer *k, real *a, + integer *lda, real *tau, real *work, integer *lwork, integer *info); + +/* Subroutine */ int sorgr2_(integer *m, integer *n, integer *k, real *a, + integer *lda, real *tau, real *work, integer *info); + +/* Subroutine */ int sorgrq_(integer *m, integer *n, integer *k, real *a, + integer *lda, real *tau, real *work, integer *lwork, integer *info); + +/* Subroutine */ int sorgtr_(char *uplo, integer *n, real *a, integer *lda, + real *tau, real *work, integer *lwork, integer *info); + +/* Subroutine */ int sorm2l_(char *side, char *trans, integer *m, integer *n, + integer *k, real *a, integer *lda, real *tau, real *c__, integer *ldc, + real *work, integer *info); + +/* Subroutine */ int sorm2r_(char *side, char *trans, integer *m, integer *n, + integer *k, real *a, integer *lda, real *tau, real *c__, integer *ldc, + real *work, integer *info); + +/* Subroutine */ int sormbr_(char *vect, char *side, char *trans, integer *m, + integer *n, integer *k, real *a, integer *lda, real *tau, real *c__, + integer *ldc, real *work, integer *lwork, integer *info); + +/* Subroutine */ int sormhr_(char *side, char *trans, integer *m, integer *n, + integer *ilo, integer *ihi, real *a, integer *lda, real *tau, real * + c__, integer *ldc, real *work, integer *lwork, integer *info); + +/* Subroutine */ int sorml2_(char *side, char *trans, integer *m, integer *n, + integer *k, real *a, integer *lda, real *tau, real *c__, integer *ldc, + real *work, integer *info); + +/* Subroutine */ int sormlq_(char *side, char *trans, integer *m, integer *n, + integer *k, real *a, integer *lda, real *tau, real *c__, integer *ldc, + real *work, integer *lwork, integer *info); + +/* Subroutine */ int sormql_(char *side, char *trans, integer *m, integer *n, + integer *k, real *a, integer *lda, real *tau, real *c__, integer *ldc, + real *work, integer *lwork, integer *info); + +/* Subroutine */ int sormqr_(char *side, char *trans, integer *m, integer *n, + integer *k, real *a, integer *lda, real *tau, real *c__, integer *ldc, + real *work, integer *lwork, integer *info); + +/* Subroutine */ int sormr2_(char *side, char *trans, integer *m, integer *n, + integer *k, real *a, integer *lda, real *tau, real *c__, integer *ldc, + real *work, integer *info); + +/* Subroutine */ int sormr3_(char *side, char *trans, integer *m, integer *n, + integer *k, integer *l, real *a, integer *lda, real *tau, real *c__, + integer *ldc, real *work, integer *info); + +/* Subroutine */ int sormrq_(char *side, char *trans, integer *m, integer *n, + integer *k, real *a, integer *lda, real *tau, real *c__, integer *ldc, + real *work, integer *lwork, integer *info); + +/* Subroutine */ int sormrz_(char *side, char *trans, integer *m, integer *n, + integer *k, integer *l, real *a, integer *lda, real *tau, real *c__, + integer *ldc, real *work, integer *lwork, integer *info); + +/* Subroutine */ int sormtr_(char *side, char *uplo, char *trans, integer *m, + integer *n, real *a, integer *lda, real *tau, real *c__, integer *ldc, + real *work, integer *lwork, integer *info); + +/* Subroutine */ int spbcon_(char *uplo, integer *n, integer *kd, real *ab, + integer *ldab, real *anorm, real *rcond, real *work, integer *iwork, + integer *info); + +/* Subroutine */ int spbequ_(char *uplo, integer *n, integer *kd, real *ab, + integer *ldab, real *s, real *scond, real *amax, integer *info); + +/* Subroutine */ int spbrfs_(char *uplo, integer *n, integer *kd, integer * + nrhs, real *ab, integer *ldab, real *afb, integer *ldafb, real *b, + integer *ldb, real *x, integer *ldx, real *ferr, real *berr, real * + work, integer *iwork, integer *info); + +/* Subroutine */ int spbstf_(char *uplo, integer *n, integer *kd, real *ab, + integer *ldab, integer *info); + +/* Subroutine */ int spbsv_(char *uplo, integer *n, integer *kd, integer * + nrhs, real *ab, integer *ldab, real *b, integer *ldb, integer *info); + +/* Subroutine */ int spbsvx_(char *fact, char *uplo, integer *n, integer *kd, + integer *nrhs, real *ab, integer *ldab, real *afb, integer *ldafb, + char *equed, real *s, real *b, integer *ldb, real *x, integer *ldx, + real *rcond, real *ferr, real *berr, real *work, integer *iwork, + integer *info); + +/* Subroutine */ int spbtf2_(char *uplo, integer *n, integer *kd, real *ab, + integer *ldab, integer *info); + +/* Subroutine */ int spbtrf_(char *uplo, integer *n, integer *kd, real *ab, + integer *ldab, integer *info); + +/* Subroutine */ int spbtrs_(char *uplo, integer *n, integer *kd, integer * + nrhs, real *ab, integer *ldab, real *b, integer *ldb, integer *info); + +/* Subroutine */ int spocon_(char *uplo, integer *n, real *a, integer *lda, + real *anorm, real *rcond, real *work, integer *iwork, integer *info); + +/* Subroutine */ int spoequ_(integer *n, real *a, integer *lda, real *s, real + *scond, real *amax, integer *info); + +/* Subroutine */ int sporfs_(char *uplo, integer *n, integer *nrhs, real *a, + integer *lda, real *af, integer *ldaf, real *b, integer *ldb, real *x, + integer *ldx, real *ferr, real *berr, real *work, integer *iwork, + integer *info); + +/* Subroutine */ int sposv_(char *uplo, integer *n, integer *nrhs, real *a, + integer *lda, real *b, integer *ldb, integer *info); + +/* Subroutine */ int sposvx_(char *fact, char *uplo, integer *n, integer * + nrhs, real *a, integer *lda, real *af, integer *ldaf, char *equed, + real *s, real *b, integer *ldb, real *x, integer *ldx, real *rcond, + real *ferr, real *berr, real *work, integer *iwork, integer *info); + +/* Subroutine */ int spotf2_(char *uplo, integer *n, real *a, integer *lda, + integer *info); + +/* Subroutine */ int spotrf_(char *uplo, integer *n, real *a, integer *lda, + integer *info); + +/* Subroutine */ int spotri_(char *uplo, integer *n, real *a, integer *lda, + integer *info); + +/* Subroutine */ int spotrs_(char *uplo, integer *n, integer *nrhs, real *a, + integer *lda, real *b, integer *ldb, integer *info); + +/* Subroutine */ int sppcon_(char *uplo, integer *n, real *ap, real *anorm, + real *rcond, real *work, integer *iwork, integer *info); + +/* Subroutine */ int sppequ_(char *uplo, integer *n, real *ap, real *s, real * + scond, real *amax, integer *info); + +/* Subroutine */ int spprfs_(char *uplo, integer *n, integer *nrhs, real *ap, + real *afp, real *b, integer *ldb, real *x, integer *ldx, real *ferr, + real *berr, real *work, integer *iwork, integer *info); + +/* Subroutine */ int sppsv_(char *uplo, integer *n, integer *nrhs, real *ap, + real *b, integer *ldb, integer *info); + +/* Subroutine */ int sppsvx_(char *fact, char *uplo, integer *n, integer * + nrhs, real *ap, real *afp, char *equed, real *s, real *b, integer * + ldb, real *x, integer *ldx, real *rcond, real *ferr, real *berr, real + *work, integer *iwork, integer *info); + +/* Subroutine */ int spptrf_(char *uplo, integer *n, real *ap, integer *info); + +/* Subroutine */ int spptri_(char *uplo, integer *n, real *ap, integer *info); + +/* Subroutine */ int spptrs_(char *uplo, integer *n, integer *nrhs, real *ap, + real *b, integer *ldb, integer *info); + +/* Subroutine */ int sptcon_(integer *n, real *d__, real *e, real *anorm, + real *rcond, real *work, integer *info); + +/* Subroutine */ int spteqr_(char *compz, integer *n, real *d__, real *e, + real *z__, integer *ldz, real *work, integer *info); + +/* Subroutine */ int sptrfs_(integer *n, integer *nrhs, real *d__, real *e, + real *df, real *ef, real *b, integer *ldb, real *x, integer *ldx, + real *ferr, real *berr, real *work, integer *info); + +/* Subroutine */ int sptsv_(integer *n, integer *nrhs, real *d__, real *e, + real *b, integer *ldb, integer *info); + +/* Subroutine */ int sptsvx_(char *fact, integer *n, integer *nrhs, real *d__, + real *e, real *df, real *ef, real *b, integer *ldb, real *x, integer + *ldx, real *rcond, real *ferr, real *berr, real *work, integer *info); + +/* Subroutine */ int spttrf_(integer *n, real *d__, real *e, integer *info); + +/* Subroutine */ int spttrs_(integer *n, integer *nrhs, real *d__, real *e, + real *b, integer *ldb, integer *info); + +/* Subroutine */ int sptts2_(integer *n, integer *nrhs, real *d__, real *e, + real *b, integer *ldb); + +/* Subroutine */ int srscl_(integer *n, real *sa, real *sx, integer *incx); + +/* Subroutine */ int ssbev_(char *jobz, char *uplo, integer *n, integer *kd, + real *ab, integer *ldab, real *w, real *z__, integer *ldz, real *work, + integer *info); + +/* Subroutine */ int ssbevd_(char *jobz, char *uplo, integer *n, integer *kd, + real *ab, integer *ldab, real *w, real *z__, integer *ldz, real *work, + integer *lwork, integer *iwork, integer *liwork, integer *info); + +/* Subroutine */ int ssbevx_(char *jobz, char *range, char *uplo, integer *n, + integer *kd, real *ab, integer *ldab, real *q, integer *ldq, real *vl, + real *vu, integer *il, integer *iu, real *abstol, integer *m, real * + w, real *z__, integer *ldz, real *work, integer *iwork, integer * + ifail, integer *info); + +/* Subroutine */ int ssbgst_(char *vect, char *uplo, integer *n, integer *ka, + integer *kb, real *ab, integer *ldab, real *bb, integer *ldbb, real * + x, integer *ldx, real *work, integer *info); + +/* Subroutine */ int ssbgv_(char *jobz, char *uplo, integer *n, integer *ka, + integer *kb, real *ab, integer *ldab, real *bb, integer *ldbb, real * + w, real *z__, integer *ldz, real *work, integer *info); + +/* Subroutine */ int ssbgvd_(char *jobz, char *uplo, integer *n, integer *ka, + integer *kb, real *ab, integer *ldab, real *bb, integer *ldbb, real * + w, real *z__, integer *ldz, real *work, integer *lwork, integer * + iwork, integer *liwork, integer *info); + +/* Subroutine */ int ssbgvx_(char *jobz, char *range, char *uplo, integer *n, + integer *ka, integer *kb, real *ab, integer *ldab, real *bb, integer * + ldbb, real *q, integer *ldq, real *vl, real *vu, integer *il, integer + *iu, real *abstol, integer *m, real *w, real *z__, integer *ldz, real + *work, integer *iwork, integer *ifail, integer *info); + +/* Subroutine */ int ssbtrd_(char *vect, char *uplo, integer *n, integer *kd, + real *ab, integer *ldab, real *d__, real *e, real *q, integer *ldq, + real *work, integer *info); + +/* Subroutine */ int sspcon_(char *uplo, integer *n, real *ap, integer *ipiv, + real *anorm, real *rcond, real *work, integer *iwork, integer *info); + +/* Subroutine */ int sspev_(char *jobz, char *uplo, integer *n, real *ap, + real *w, real *z__, integer *ldz, real *work, integer *info); + +/* Subroutine */ int sspevd_(char *jobz, char *uplo, integer *n, real *ap, + real *w, real *z__, integer *ldz, real *work, integer *lwork, integer + *iwork, integer *liwork, integer *info); + +/* Subroutine */ int sspevx_(char *jobz, char *range, char *uplo, integer *n, + real *ap, real *vl, real *vu, integer *il, integer *iu, real *abstol, + integer *m, real *w, real *z__, integer *ldz, real *work, integer * + iwork, integer *ifail, integer *info); + +/* Subroutine */ int sspgst_(integer *itype, char *uplo, integer *n, real *ap, + real *bp, integer *info); + +/* Subroutine */ int sspgv_(integer *itype, char *jobz, char *uplo, integer * + n, real *ap, real *bp, real *w, real *z__, integer *ldz, real *work, + integer *info); + +/* Subroutine */ int sspgvd_(integer *itype, char *jobz, char *uplo, integer * + n, real *ap, real *bp, real *w, real *z__, integer *ldz, real *work, + integer *lwork, integer *iwork, integer *liwork, integer *info); + +/* Subroutine */ int sspgvx_(integer *itype, char *jobz, char *range, char * + uplo, integer *n, real *ap, real *bp, real *vl, real *vu, integer *il, + integer *iu, real *abstol, integer *m, real *w, real *z__, integer * + ldz, real *work, integer *iwork, integer *ifail, integer *info); + +/* Subroutine */ int ssprfs_(char *uplo, integer *n, integer *nrhs, real *ap, + real *afp, integer *ipiv, real *b, integer *ldb, real *x, integer * + ldx, real *ferr, real *berr, real *work, integer *iwork, integer * + info); + +/* Subroutine */ int sspsv_(char *uplo, integer *n, integer *nrhs, real *ap, + integer *ipiv, real *b, integer *ldb, integer *info); + +/* Subroutine */ int sspsvx_(char *fact, char *uplo, integer *n, integer * + nrhs, real *ap, real *afp, integer *ipiv, real *b, integer *ldb, real + *x, integer *ldx, real *rcond, real *ferr, real *berr, real *work, + integer *iwork, integer *info); + +/* Subroutine */ int ssptrd_(char *uplo, integer *n, real *ap, real *d__, + real *e, real *tau, integer *info); + +/* Subroutine */ int ssptrf_(char *uplo, integer *n, real *ap, integer *ipiv, + integer *info); + +/* Subroutine */ int ssptri_(char *uplo, integer *n, real *ap, integer *ipiv, + real *work, integer *info); + +/* Subroutine */ int ssptrs_(char *uplo, integer *n, integer *nrhs, real *ap, + integer *ipiv, real *b, integer *ldb, integer *info); + +/* Subroutine */ int sstebz_(char *range, char *order, integer *n, real *vl, + real *vu, integer *il, integer *iu, real *abstol, real *d__, real *e, + integer *m, integer *nsplit, real *w, integer *iblock, integer * + isplit, real *work, integer *iwork, integer *info); + +/* Subroutine */ int sstedc_(char *compz, integer *n, real *d__, real *e, + real *z__, integer *ldz, real *work, integer *lwork, integer *iwork, + integer *liwork, integer *info); + +/* Subroutine */ int sstegr_(char *jobz, char *range, integer *n, real *d__, + real *e, real *vl, real *vu, integer *il, integer *iu, real *abstol, + integer *m, real *w, real *z__, integer *ldz, integer *isuppz, real * + work, integer *lwork, integer *iwork, integer *liwork, integer *info); + +/* Subroutine */ int sstein_(integer *n, real *d__, real *e, integer *m, real + *w, integer *iblock, integer *isplit, real *z__, integer *ldz, real * + work, integer *iwork, integer *ifail, integer *info); + +/* Subroutine */ int ssteqr_(char *compz, integer *n, real *d__, real *e, + real *z__, integer *ldz, real *work, integer *info); + +/* Subroutine */ int ssterf_(integer *n, real *d__, real *e, integer *info); + +/* Subroutine */ int sstev_(char *jobz, integer *n, real *d__, real *e, real * + z__, integer *ldz, real *work, integer *info); + +/* Subroutine */ int sstevd_(char *jobz, integer *n, real *d__, real *e, real + *z__, integer *ldz, real *work, integer *lwork, integer *iwork, + integer *liwork, integer *info); + +/* Subroutine */ int sstevr_(char *jobz, char *range, integer *n, real *d__, + real *e, real *vl, real *vu, integer *il, integer *iu, real *abstol, + integer *m, real *w, real *z__, integer *ldz, integer *isuppz, real * + work, integer *lwork, integer *iwork, integer *liwork, integer *info); + +/* Subroutine */ int sstevx_(char *jobz, char *range, integer *n, real *d__, + real *e, real *vl, real *vu, integer *il, integer *iu, real *abstol, + integer *m, real *w, real *z__, integer *ldz, real *work, integer * + iwork, integer *ifail, integer *info); + +/* Subroutine */ int ssycon_(char *uplo, integer *n, real *a, integer *lda, + integer *ipiv, real *anorm, real *rcond, real *work, integer *iwork, + integer *info); + +/* Subroutine */ int ssyev_(char *jobz, char *uplo, integer *n, real *a, + integer *lda, real *w, real *work, integer *lwork, integer *info); + +/* Subroutine */ int ssyevd_(char *jobz, char *uplo, integer *n, real *a, + integer *lda, real *w, real *work, integer *lwork, integer *iwork, + integer *liwork, integer *info); + +/* Subroutine */ int ssyevr_(char *jobz, char *range, char *uplo, integer *n, + real *a, integer *lda, real *vl, real *vu, integer *il, integer *iu, + real *abstol, integer *m, real *w, real *z__, integer *ldz, integer * + isuppz, real *work, integer *lwork, integer *iwork, integer *liwork, + integer *info); + +/* Subroutine */ int ssyevx_(char *jobz, char *range, char *uplo, integer *n, + real *a, integer *lda, real *vl, real *vu, integer *il, integer *iu, + real *abstol, integer *m, real *w, real *z__, integer *ldz, real * + work, integer *lwork, integer *iwork, integer *ifail, integer *info); + +/* Subroutine */ int ssygs2_(integer *itype, char *uplo, integer *n, real *a, + integer *lda, real *b, integer *ldb, integer *info); + +/* Subroutine */ int ssygst_(integer *itype, char *uplo, integer *n, real *a, + integer *lda, real *b, integer *ldb, integer *info); + +/* Subroutine */ int ssygv_(integer *itype, char *jobz, char *uplo, integer * + n, real *a, integer *lda, real *b, integer *ldb, real *w, real *work, + integer *lwork, integer *info); + +/* Subroutine */ int ssygvd_(integer *itype, char *jobz, char *uplo, integer * + n, real *a, integer *lda, real *b, integer *ldb, real *w, real *work, + integer *lwork, integer *iwork, integer *liwork, integer *info); + +/* Subroutine */ int ssygvx_(integer *itype, char *jobz, char *range, char * + uplo, integer *n, real *a, integer *lda, real *b, integer *ldb, real * + vl, real *vu, integer *il, integer *iu, real *abstol, integer *m, + real *w, real *z__, integer *ldz, real *work, integer *lwork, integer + *iwork, integer *ifail, integer *info); + +/* Subroutine */ int ssyrfs_(char *uplo, integer *n, integer *nrhs, real *a, + integer *lda, real *af, integer *ldaf, integer *ipiv, real *b, + integer *ldb, real *x, integer *ldx, real *ferr, real *berr, real * + work, integer *iwork, integer *info); + +/* Subroutine */ int ssysv_(char *uplo, integer *n, integer *nrhs, real *a, + integer *lda, integer *ipiv, real *b, integer *ldb, real *work, + integer *lwork, integer *info); + +/* Subroutine */ int ssysvx_(char *fact, char *uplo, integer *n, integer * + nrhs, real *a, integer *lda, real *af, integer *ldaf, integer *ipiv, + real *b, integer *ldb, real *x, integer *ldx, real *rcond, real *ferr, + real *berr, real *work, integer *lwork, integer *iwork, integer * + info); + +/* Subroutine */ int ssytd2_(char *uplo, integer *n, real *a, integer *lda, + real *d__, real *e, real *tau, integer *info); + +/* Subroutine */ int ssytf2_(char *uplo, integer *n, real *a, integer *lda, + integer *ipiv, integer *info); + +/* Subroutine */ int ssytrd_(char *uplo, integer *n, real *a, integer *lda, + real *d__, real *e, real *tau, real *work, integer *lwork, integer * + info); + +/* Subroutine */ int ssytrf_(char *uplo, integer *n, real *a, integer *lda, + integer *ipiv, real *work, integer *lwork, integer *info); + +/* Subroutine */ int ssytri_(char *uplo, integer *n, real *a, integer *lda, + integer *ipiv, real *work, integer *info); + +/* Subroutine */ int ssytrs_(char *uplo, integer *n, integer *nrhs, real *a, + integer *lda, integer *ipiv, real *b, integer *ldb, integer *info); + +/* Subroutine */ int stbcon_(char *norm, char *uplo, char *diag, integer *n, + integer *kd, real *ab, integer *ldab, real *rcond, real *work, + integer *iwork, integer *info); + +/* Subroutine */ int stbrfs_(char *uplo, char *trans, char *diag, integer *n, + integer *kd, integer *nrhs, real *ab, integer *ldab, real *b, integer + *ldb, real *x, integer *ldx, real *ferr, real *berr, real *work, + integer *iwork, integer *info); + +/* Subroutine */ int stbtrs_(char *uplo, char *trans, char *diag, integer *n, + integer *kd, integer *nrhs, real *ab, integer *ldab, real *b, integer + *ldb, integer *info); + +/* Subroutine */ int stgevc_(char *side, char *howmny, logical *select, + integer *n, real *a, integer *lda, real *b, integer *ldb, real *vl, + integer *ldvl, real *vr, integer *ldvr, integer *mm, integer *m, real + *work, integer *info); + +/* Subroutine */ int stgex2_(logical *wantq, logical *wantz, integer *n, real + *a, integer *lda, real *b, integer *ldb, real *q, integer *ldq, real * + z__, integer *ldz, integer *j1, integer *n1, integer *n2, real *work, + integer *lwork, integer *info); + +/* Subroutine */ int stgexc_(logical *wantq, logical *wantz, integer *n, real + *a, integer *lda, real *b, integer *ldb, real *q, integer *ldq, real * + z__, integer *ldz, integer *ifst, integer *ilst, real *work, integer * + lwork, integer *info); + +/* Subroutine */ int stgsen_(integer *ijob, logical *wantq, logical *wantz, + logical *select, integer *n, real *a, integer *lda, real *b, integer * + ldb, real *alphar, real *alphai, real *beta, real *q, integer *ldq, + real *z__, integer *ldz, integer *m, real *pl, real *pr, real *dif, + real *work, integer *lwork, integer *iwork, integer *liwork, integer * + info); + +/* Subroutine */ int stgsja_(char *jobu, char *jobv, char *jobq, integer *m, + integer *p, integer *n, integer *k, integer *l, real *a, integer *lda, + real *b, integer *ldb, real *tola, real *tolb, real *alpha, real * + beta, real *u, integer *ldu, real *v, integer *ldv, real *q, integer * + ldq, real *work, integer *ncycle, integer *info); + +/* Subroutine */ int stgsna_(char *job, char *howmny, logical *select, + integer *n, real *a, integer *lda, real *b, integer *ldb, real *vl, + integer *ldvl, real *vr, integer *ldvr, real *s, real *dif, integer * + mm, integer *m, real *work, integer *lwork, integer *iwork, integer * + info); + +/* Subroutine */ int stgsy2_(char *trans, integer *ijob, integer *m, integer * + n, real *a, integer *lda, real *b, integer *ldb, real *c__, integer * + ldc, real *d__, integer *ldd, real *e, integer *lde, real *f, integer + *ldf, real *scale, real *rdsum, real *rdscal, integer *iwork, integer + *pq, integer *info); + +/* Subroutine */ int stgsyl_(char *trans, integer *ijob, integer *m, integer * + n, real *a, integer *lda, real *b, integer *ldb, real *c__, integer * + ldc, real *d__, integer *ldd, real *e, integer *lde, real *f, integer + *ldf, real *scale, real *dif, real *work, integer *lwork, integer * + iwork, integer *info); + +/* Subroutine */ int stpcon_(char *norm, char *uplo, char *diag, integer *n, + real *ap, real *rcond, real *work, integer *iwork, integer *info); + +/* Subroutine */ int stprfs_(char *uplo, char *trans, char *diag, integer *n, + integer *nrhs, real *ap, real *b, integer *ldb, real *x, integer *ldx, + real *ferr, real *berr, real *work, integer *iwork, integer *info); + +/* Subroutine */ int stptri_(char *uplo, char *diag, integer *n, real *ap, + integer *info); + +/* Subroutine */ int stptrs_(char *uplo, char *trans, char *diag, integer *n, + integer *nrhs, real *ap, real *b, integer *ldb, integer *info); + +/* Subroutine */ int strcon_(char *norm, char *uplo, char *diag, integer *n, + real *a, integer *lda, real *rcond, real *work, integer *iwork, + integer *info); + +/* Subroutine */ int strevc_(char *side, char *howmny, logical *select, + integer *n, real *t, integer *ldt, real *vl, integer *ldvl, real *vr, + integer *ldvr, integer *mm, integer *m, real *work, integer *info); + +/* Subroutine */ int strexc_(char *compq, integer *n, real *t, integer *ldt, + real *q, integer *ldq, integer *ifst, integer *ilst, real *work, + integer *info); + +/* Subroutine */ int strrfs_(char *uplo, char *trans, char *diag, integer *n, + integer *nrhs, real *a, integer *lda, real *b, integer *ldb, real *x, + integer *ldx, real *ferr, real *berr, real *work, integer *iwork, + integer *info); + +/* Subroutine */ int strsen_(char *job, char *compq, logical *select, integer + *n, real *t, integer *ldt, real *q, integer *ldq, real *wr, real *wi, + integer *m, real *s, real *sep, real *work, integer *lwork, integer * + iwork, integer *liwork, integer *info); + +/* Subroutine */ int strsna_(char *job, char *howmny, logical *select, + integer *n, real *t, integer *ldt, real *vl, integer *ldvl, real *vr, + integer *ldvr, real *s, real *sep, integer *mm, integer *m, real * + work, integer *ldwork, integer *iwork, integer *info); + +/* Subroutine */ int strsyl_(char *trana, char *tranb, integer *isgn, integer + *m, integer *n, real *a, integer *lda, real *b, integer *ldb, real * + c__, integer *ldc, real *scale, integer *info); + +/* Subroutine */ int strti2_(char *uplo, char *diag, integer *n, real *a, + integer *lda, integer *info); + +/* Subroutine */ int strtri_(char *uplo, char *diag, integer *n, real *a, + integer *lda, integer *info); + +/* Subroutine */ int strtrs_(char *uplo, char *trans, char *diag, integer *n, + integer *nrhs, real *a, integer *lda, real *b, integer *ldb, integer * + info); + +/* Subroutine */ int stzrqf_(integer *m, integer *n, real *a, integer *lda, + real *tau, integer *info); + +/* Subroutine */ int stzrzf_(integer *m, integer *n, real *a, integer *lda, + real *tau, real *work, integer *lwork, integer *info); + +/* Subroutine */ int xerbla_(char *srname, integer *info); + +/* Subroutine */ int zbdsqr_(char *uplo, integer *n, integer *ncvt, integer * + nru, integer *ncc, doublereal *d__, doublereal *e, doublecomplex *vt, + integer *ldvt, doublecomplex *u, integer *ldu, doublecomplex *c__, + integer *ldc, doublereal *rwork, integer *info); + +/* Subroutine */ int zdrot_(integer *n, doublecomplex *cx, integer *incx, + doublecomplex *cy, integer *incy, doublereal *c__, doublereal *s); + +/* Subroutine */ int zdrscl_(integer *n, doublereal *sa, doublecomplex *sx, + integer *incx); + +/* Subroutine */ int zgbbrd_(char *vect, integer *m, integer *n, integer *ncc, + integer *kl, integer *ku, doublecomplex *ab, integer *ldab, + doublereal *d__, doublereal *e, doublecomplex *q, integer *ldq, + doublecomplex *pt, integer *ldpt, doublecomplex *c__, integer *ldc, + doublecomplex *work, doublereal *rwork, integer *info); + +/* Subroutine */ int zgbcon_(char *norm, integer *n, integer *kl, integer *ku, + doublecomplex *ab, integer *ldab, integer *ipiv, doublereal *anorm, + doublereal *rcond, doublecomplex *work, doublereal *rwork, integer * + info); + +/* Subroutine */ int zgbequ_(integer *m, integer *n, integer *kl, integer *ku, + doublecomplex *ab, integer *ldab, doublereal *r__, doublereal *c__, + doublereal *rowcnd, doublereal *colcnd, doublereal *amax, integer * + info); + +/* Subroutine */ int zgbrfs_(char *trans, integer *n, integer *kl, integer * + ku, integer *nrhs, doublecomplex *ab, integer *ldab, doublecomplex * + afb, integer *ldafb, integer *ipiv, doublecomplex *b, integer *ldb, + doublecomplex *x, integer *ldx, doublereal *ferr, doublereal *berr, + doublecomplex *work, doublereal *rwork, integer *info); + +/* Subroutine */ int zgbsv_(integer *n, integer *kl, integer *ku, integer * + nrhs, doublecomplex *ab, integer *ldab, integer *ipiv, doublecomplex * + b, integer *ldb, integer *info); + +/* Subroutine */ int zgbsvx_(char *fact, char *trans, integer *n, integer *kl, + integer *ku, integer *nrhs, doublecomplex *ab, integer *ldab, + doublecomplex *afb, integer *ldafb, integer *ipiv, char *equed, + doublereal *r__, doublereal *c__, doublecomplex *b, integer *ldb, + doublecomplex *x, integer *ldx, doublereal *rcond, doublereal *ferr, + doublereal *berr, doublecomplex *work, doublereal *rwork, integer * + info); + +/* Subroutine */ int zgbtf2_(integer *m, integer *n, integer *kl, integer *ku, + doublecomplex *ab, integer *ldab, integer *ipiv, integer *info); + +/* Subroutine */ int zgbtrf_(integer *m, integer *n, integer *kl, integer *ku, + doublecomplex *ab, integer *ldab, integer *ipiv, integer *info); + +/* Subroutine */ int zgbtrs_(char *trans, integer *n, integer *kl, integer * + ku, integer *nrhs, doublecomplex *ab, integer *ldab, integer *ipiv, + doublecomplex *b, integer *ldb, integer *info); + +/* Subroutine */ int zgebak_(char *job, char *side, integer *n, integer *ilo, + integer *ihi, doublereal *scale, integer *m, doublecomplex *v, + integer *ldv, integer *info); + +/* Subroutine */ int zgebal_(char *job, integer *n, doublecomplex *a, integer + *lda, integer *ilo, integer *ihi, doublereal *scale, integer *info); + +/* Subroutine */ int zgebd2_(integer *m, integer *n, doublecomplex *a, + integer *lda, doublereal *d__, doublereal *e, doublecomplex *tauq, + doublecomplex *taup, doublecomplex *work, integer *info); + +/* Subroutine */ int zgebrd_(integer *m, integer *n, doublecomplex *a, + integer *lda, doublereal *d__, doublereal *e, doublecomplex *tauq, + doublecomplex *taup, doublecomplex *work, integer *lwork, integer * + info); + +/* Subroutine */ int zgecon_(char *norm, integer *n, doublecomplex *a, + integer *lda, doublereal *anorm, doublereal *rcond, doublecomplex * + work, doublereal *rwork, integer *info); + +/* Subroutine */ int zgeequ_(integer *m, integer *n, doublecomplex *a, + integer *lda, doublereal *r__, doublereal *c__, doublereal *rowcnd, + doublereal *colcnd, doublereal *amax, integer *info); + +/* Subroutine */ int zgees_(char *jobvs, char *sort, L_fp select, integer *n, + doublecomplex *a, integer *lda, integer *sdim, doublecomplex *w, + doublecomplex *vs, integer *ldvs, doublecomplex *work, integer *lwork, + doublereal *rwork, logical *bwork, integer *info); + +/* Subroutine */ int zgeesx_(char *jobvs, char *sort, L_fp select, char * + sense, integer *n, doublecomplex *a, integer *lda, integer *sdim, + doublecomplex *w, doublecomplex *vs, integer *ldvs, doublereal * + rconde, doublereal *rcondv, doublecomplex *work, integer *lwork, + doublereal *rwork, logical *bwork, integer *info); + +/* Subroutine */ int zgeev_(char *jobvl, char *jobvr, integer *n, + doublecomplex *a, integer *lda, doublecomplex *w, doublecomplex *vl, + integer *ldvl, doublecomplex *vr, integer *ldvr, doublecomplex *work, + integer *lwork, doublereal *rwork, integer *info); + +/* Subroutine */ int zgeevx_(char *balanc, char *jobvl, char *jobvr, char * + sense, integer *n, doublecomplex *a, integer *lda, doublecomplex *w, + doublecomplex *vl, integer *ldvl, doublecomplex *vr, integer *ldvr, + integer *ilo, integer *ihi, doublereal *scale, doublereal *abnrm, + doublereal *rconde, doublereal *rcondv, doublecomplex *work, integer * + lwork, doublereal *rwork, integer *info); + +/* Subroutine */ int zgegs_(char *jobvsl, char *jobvsr, integer *n, + doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, + doublecomplex *alpha, doublecomplex *beta, doublecomplex *vsl, + integer *ldvsl, doublecomplex *vsr, integer *ldvsr, doublecomplex * + work, integer *lwork, doublereal *rwork, integer *info); + +/* Subroutine */ int zgegv_(char *jobvl, char *jobvr, integer *n, + doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, + doublecomplex *alpha, doublecomplex *beta, doublecomplex *vl, integer + *ldvl, doublecomplex *vr, integer *ldvr, doublecomplex *work, integer + *lwork, doublereal *rwork, integer *info); + +/* Subroutine */ int zgehd2_(integer *n, integer *ilo, integer *ihi, + doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * + work, integer *info); + +/* Subroutine */ int zgehrd_(integer *n, integer *ilo, integer *ihi, + doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * + work, integer *lwork, integer *info); + +/* Subroutine */ int zgelq2_(integer *m, integer *n, doublecomplex *a, + integer *lda, doublecomplex *tau, doublecomplex *work, integer *info); + +/* Subroutine */ int zgelqf_(integer *m, integer *n, doublecomplex *a, + integer *lda, doublecomplex *tau, doublecomplex *work, integer *lwork, + integer *info); + +/* Subroutine */ int zgels_(char *trans, integer *m, integer *n, integer * + nrhs, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, + doublecomplex *work, integer *lwork, integer *info); + +/* Subroutine */ int zgelsx_(integer *m, integer *n, integer *nrhs, + doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, + integer *jpvt, doublereal *rcond, integer *rank, doublecomplex *work, + doublereal *rwork, integer *info); + +/* Subroutine */ int zgelsy_(integer *m, integer *n, integer *nrhs, + doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, + integer *jpvt, doublereal *rcond, integer *rank, doublecomplex *work, + integer *lwork, doublereal *rwork, integer *info); + +/* Subroutine */ int zgeql2_(integer *m, integer *n, doublecomplex *a, + integer *lda, doublecomplex *tau, doublecomplex *work, integer *info); + +/* Subroutine */ int zgeqlf_(integer *m, integer *n, doublecomplex *a, + integer *lda, doublecomplex *tau, doublecomplex *work, integer *lwork, + integer *info); + +/* Subroutine */ int zgeqp3_(integer *m, integer *n, doublecomplex *a, + integer *lda, integer *jpvt, doublecomplex *tau, doublecomplex *work, + integer *lwork, doublereal *rwork, integer *info); + +/* Subroutine */ int zgeqpf_(integer *m, integer *n, doublecomplex *a, + integer *lda, integer *jpvt, doublecomplex *tau, doublecomplex *work, + doublereal *rwork, integer *info); + +/* Subroutine */ int zgeqr2_(integer *m, integer *n, doublecomplex *a, + integer *lda, doublecomplex *tau, doublecomplex *work, integer *info); + +/* Subroutine */ int zgeqrf_(integer *m, integer *n, doublecomplex *a, + integer *lda, doublecomplex *tau, doublecomplex *work, integer *lwork, + integer *info); + +/* Subroutine */ int zgerfs_(char *trans, integer *n, integer *nrhs, + doublecomplex *a, integer *lda, doublecomplex *af, integer *ldaf, + integer *ipiv, doublecomplex *b, integer *ldb, doublecomplex *x, + integer *ldx, doublereal *ferr, doublereal *berr, doublecomplex *work, + doublereal *rwork, integer *info); + +/* Subroutine */ int zgerq2_(integer *m, integer *n, doublecomplex *a, + integer *lda, doublecomplex *tau, doublecomplex *work, integer *info); + +/* Subroutine */ int zgerqf_(integer *m, integer *n, doublecomplex *a, + integer *lda, doublecomplex *tau, doublecomplex *work, integer *lwork, + integer *info); + +/* Subroutine */ int zgesc2_(integer *n, doublecomplex *a, integer *lda, + doublecomplex *rhs, integer *ipiv, integer *jpiv, doublereal *scale); + +/* Subroutine */ int zgesv_(integer *n, integer *nrhs, doublecomplex *a, + integer *lda, integer *ipiv, doublecomplex *b, integer *ldb, integer * + info); + +/* Subroutine */ int zgesvx_(char *fact, char *trans, integer *n, integer * + nrhs, doublecomplex *a, integer *lda, doublecomplex *af, integer * + ldaf, integer *ipiv, char *equed, doublereal *r__, doublereal *c__, + doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, + doublereal *rcond, doublereal *ferr, doublereal *berr, doublecomplex * + work, doublereal *rwork, integer *info); + +/* Subroutine */ int zgetc2_(integer *n, doublecomplex *a, integer *lda, + integer *ipiv, integer *jpiv, integer *info); + +/* Subroutine */ int zgetf2_(integer *m, integer *n, doublecomplex *a, + integer *lda, integer *ipiv, integer *info); + +/* Subroutine */ int zgetrf_(integer *m, integer *n, doublecomplex *a, + integer *lda, integer *ipiv, integer *info); + +/* Subroutine */ int zgetri_(integer *n, doublecomplex *a, integer *lda, + integer *ipiv, doublecomplex *work, integer *lwork, integer *info); + +/* Subroutine */ int zgetrs_(char *trans, integer *n, integer *nrhs, + doublecomplex *a, integer *lda, integer *ipiv, doublecomplex *b, + integer *ldb, integer *info); + +/* Subroutine */ int zggbak_(char *job, char *side, integer *n, integer *ilo, + integer *ihi, doublereal *lscale, doublereal *rscale, integer *m, + doublecomplex *v, integer *ldv, integer *info); + +/* Subroutine */ int zggbal_(char *job, integer *n, doublecomplex *a, integer + *lda, doublecomplex *b, integer *ldb, integer *ilo, integer *ihi, + doublereal *lscale, doublereal *rscale, doublereal *work, integer * + info); + +/* Subroutine */ int zgges_(char *jobvsl, char *jobvsr, char *sort, L_fp + delctg, integer *n, doublecomplex *a, integer *lda, doublecomplex *b, + integer *ldb, integer *sdim, doublecomplex *alpha, doublecomplex * + beta, doublecomplex *vsl, integer *ldvsl, doublecomplex *vsr, integer + *ldvsr, doublecomplex *work, integer *lwork, doublereal *rwork, + logical *bwork, integer *info); + +/* Subroutine */ int zggesx_(char *jobvsl, char *jobvsr, char *sort, L_fp + delctg, char *sense, integer *n, doublecomplex *a, integer *lda, + doublecomplex *b, integer *ldb, integer *sdim, doublecomplex *alpha, + doublecomplex *beta, doublecomplex *vsl, integer *ldvsl, + doublecomplex *vsr, integer *ldvsr, doublereal *rconde, doublereal * + rcondv, doublecomplex *work, integer *lwork, doublereal *rwork, + integer *iwork, integer *liwork, logical *bwork, integer *info); + +/* Subroutine */ int zggev_(char *jobvl, char *jobvr, integer *n, + doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, + doublecomplex *alpha, doublecomplex *beta, doublecomplex *vl, integer + *ldvl, doublecomplex *vr, integer *ldvr, doublecomplex *work, integer + *lwork, doublereal *rwork, integer *info); + +/* Subroutine */ int zggevx_(char *balanc, char *jobvl, char *jobvr, char * + sense, integer *n, doublecomplex *a, integer *lda, doublecomplex *b, + integer *ldb, doublecomplex *alpha, doublecomplex *beta, + doublecomplex *vl, integer *ldvl, doublecomplex *vr, integer *ldvr, + integer *ilo, integer *ihi, doublereal *lscale, doublereal *rscale, + doublereal *abnrm, doublereal *bbnrm, doublereal *rconde, doublereal * + rcondv, doublecomplex *work, integer *lwork, doublereal *rwork, + integer *iwork, logical *bwork, integer *info); + +/* Subroutine */ int zggglm_(integer *n, integer *m, integer *p, + doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, + doublecomplex *d__, doublecomplex *x, doublecomplex *y, doublecomplex + *work, integer *lwork, integer *info); + +/* Subroutine */ int zgghrd_(char *compq, char *compz, integer *n, integer * + ilo, integer *ihi, doublecomplex *a, integer *lda, doublecomplex *b, + integer *ldb, doublecomplex *q, integer *ldq, doublecomplex *z__, + integer *ldz, integer *info); + +/* Subroutine */ int zgglse_(integer *m, integer *n, integer *p, + doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, + doublecomplex *c__, doublecomplex *d__, doublecomplex *x, + doublecomplex *work, integer *lwork, integer *info); + +/* Subroutine */ int zggqrf_(integer *n, integer *m, integer *p, + doublecomplex *a, integer *lda, doublecomplex *taua, doublecomplex *b, + integer *ldb, doublecomplex *taub, doublecomplex *work, integer * + lwork, integer *info); + +/* Subroutine */ int zggrqf_(integer *m, integer *p, integer *n, + doublecomplex *a, integer *lda, doublecomplex *taua, doublecomplex *b, + integer *ldb, doublecomplex *taub, doublecomplex *work, integer * + lwork, integer *info); + +/* Subroutine */ int zggsvd_(char *jobu, char *jobv, char *jobq, integer *m, + integer *n, integer *p, integer *k, integer *l, doublecomplex *a, + integer *lda, doublecomplex *b, integer *ldb, doublereal *alpha, + doublereal *beta, doublecomplex *u, integer *ldu, doublecomplex *v, + integer *ldv, doublecomplex *q, integer *ldq, doublecomplex *work, + doublereal *rwork, integer *iwork, integer *info); + +/* Subroutine */ int zggsvp_(char *jobu, char *jobv, char *jobq, integer *m, + integer *p, integer *n, doublecomplex *a, integer *lda, doublecomplex + *b, integer *ldb, doublereal *tola, doublereal *tolb, integer *k, + integer *l, doublecomplex *u, integer *ldu, doublecomplex *v, integer + *ldv, doublecomplex *q, integer *ldq, integer *iwork, doublereal * + rwork, doublecomplex *tau, doublecomplex *work, integer *info); + +/* Subroutine */ int zgtcon_(char *norm, integer *n, doublecomplex *dl, + doublecomplex *d__, doublecomplex *du, doublecomplex *du2, integer * + ipiv, doublereal *anorm, doublereal *rcond, doublecomplex *work, + integer *info); + +/* Subroutine */ int zgtrfs_(char *trans, integer *n, integer *nrhs, + doublecomplex *dl, doublecomplex *d__, doublecomplex *du, + doublecomplex *dlf, doublecomplex *df, doublecomplex *duf, + doublecomplex *du2, integer *ipiv, doublecomplex *b, integer *ldb, + doublecomplex *x, integer *ldx, doublereal *ferr, doublereal *berr, + doublecomplex *work, doublereal *rwork, integer *info); + +/* Subroutine */ int zgtsv_(integer *n, integer *nrhs, doublecomplex *dl, + doublecomplex *d__, doublecomplex *du, doublecomplex *b, integer *ldb, + integer *info); + +/* Subroutine */ int zgtsvx_(char *fact, char *trans, integer *n, integer * + nrhs, doublecomplex *dl, doublecomplex *d__, doublecomplex *du, + doublecomplex *dlf, doublecomplex *df, doublecomplex *duf, + doublecomplex *du2, integer *ipiv, doublecomplex *b, integer *ldb, + doublecomplex *x, integer *ldx, doublereal *rcond, doublereal *ferr, + doublereal *berr, doublecomplex *work, doublereal *rwork, integer * + info); + +/* Subroutine */ int zgttrf_(integer *n, doublecomplex *dl, doublecomplex * + d__, doublecomplex *du, doublecomplex *du2, integer *ipiv, integer * + info); + +/* Subroutine */ int zgttrs_(char *trans, integer *n, integer *nrhs, + doublecomplex *dl, doublecomplex *d__, doublecomplex *du, + doublecomplex *du2, integer *ipiv, doublecomplex *b, integer *ldb, + integer *info); + +/* Subroutine */ int zgtts2_(integer *itrans, integer *n, integer *nrhs, + doublecomplex *dl, doublecomplex *d__, doublecomplex *du, + doublecomplex *du2, integer *ipiv, doublecomplex *b, integer *ldb); + +/* Subroutine */ int zhbev_(char *jobz, char *uplo, integer *n, integer *kd, + doublecomplex *ab, integer *ldab, doublereal *w, doublecomplex *z__, + integer *ldz, doublecomplex *work, doublereal *rwork, integer *info); + +/* Subroutine */ int zhbevd_(char *jobz, char *uplo, integer *n, integer *kd, + doublecomplex *ab, integer *ldab, doublereal *w, doublecomplex *z__, + integer *ldz, doublecomplex *work, integer *lwork, doublereal *rwork, + integer *lrwork, integer *iwork, integer *liwork, integer *info); + +/* Subroutine */ int zhbevx_(char *jobz, char *range, char *uplo, integer *n, + integer *kd, doublecomplex *ab, integer *ldab, doublecomplex *q, + integer *ldq, doublereal *vl, doublereal *vu, integer *il, integer * + iu, doublereal *abstol, integer *m, doublereal *w, doublecomplex *z__, + integer *ldz, doublecomplex *work, doublereal *rwork, integer *iwork, + integer *ifail, integer *info); + +/* Subroutine */ int zhbgst_(char *vect, char *uplo, integer *n, integer *ka, + integer *kb, doublecomplex *ab, integer *ldab, doublecomplex *bb, + integer *ldbb, doublecomplex *x, integer *ldx, doublecomplex *work, + doublereal *rwork, integer *info); + +/* Subroutine */ int zhbgv_(char *jobz, char *uplo, integer *n, integer *ka, + integer *kb, doublecomplex *ab, integer *ldab, doublecomplex *bb, + integer *ldbb, doublereal *w, doublecomplex *z__, integer *ldz, + doublecomplex *work, doublereal *rwork, integer *info); + +/* Subroutine */ int zhbgvx_(char *jobz, char *range, char *uplo, integer *n, + integer *ka, integer *kb, doublecomplex *ab, integer *ldab, + doublecomplex *bb, integer *ldbb, doublecomplex *q, integer *ldq, + doublereal *vl, doublereal *vu, integer *il, integer *iu, doublereal * + abstol, integer *m, doublereal *w, doublecomplex *z__, integer *ldz, + doublecomplex *work, doublereal *rwork, integer *iwork, integer * + ifail, integer *info); + +/* Subroutine */ int zhbtrd_(char *vect, char *uplo, integer *n, integer *kd, + doublecomplex *ab, integer *ldab, doublereal *d__, doublereal *e, + doublecomplex *q, integer *ldq, doublecomplex *work, integer *info); + +/* Subroutine */ int zhecon_(char *uplo, integer *n, doublecomplex *a, + integer *lda, integer *ipiv, doublereal *anorm, doublereal *rcond, + doublecomplex *work, integer *info); + +/* Subroutine */ int zheev_(char *jobz, char *uplo, integer *n, doublecomplex + *a, integer *lda, doublereal *w, doublecomplex *work, integer *lwork, + doublereal *rwork, integer *info); + +/* Subroutine */ int zheevd_(char *jobz, char *uplo, integer *n, + doublecomplex *a, integer *lda, doublereal *w, doublecomplex *work, + integer *lwork, doublereal *rwork, integer *lrwork, integer *iwork, + integer *liwork, integer *info); + +/* Subroutine */ int zheevr_(char *jobz, char *range, char *uplo, integer *n, + doublecomplex *a, integer *lda, doublereal *vl, doublereal *vu, + integer *il, integer *iu, doublereal *abstol, integer *m, doublereal * + w, doublecomplex *z__, integer *ldz, integer *isuppz, doublecomplex * + work, integer *lwork, doublereal *rwork, integer *lrwork, integer * + iwork, integer *liwork, integer *info); + +/* Subroutine */ int zheevx_(char *jobz, char *range, char *uplo, integer *n, + doublecomplex *a, integer *lda, doublereal *vl, doublereal *vu, + integer *il, integer *iu, doublereal *abstol, integer *m, doublereal * + w, doublecomplex *z__, integer *ldz, doublecomplex *work, integer * + lwork, doublereal *rwork, integer *iwork, integer *ifail, integer * + info); + +/* Subroutine */ int zhegs2_(integer *itype, char *uplo, integer *n, + doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, + integer *info); + +/* Subroutine */ int zhegst_(integer *itype, char *uplo, integer *n, + doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, + integer *info); + +/* Subroutine */ int zhegv_(integer *itype, char *jobz, char *uplo, integer * + n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, + doublereal *w, doublecomplex *work, integer *lwork, doublereal *rwork, + integer *info); + +/* Subroutine */ int zhegvd_(integer *itype, char *jobz, char *uplo, integer * + n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, + doublereal *w, doublecomplex *work, integer *lwork, doublereal *rwork, + integer *lrwork, integer *iwork, integer *liwork, integer *info); + +/* Subroutine */ int zhegvx_(integer *itype, char *jobz, char *range, char * + uplo, integer *n, doublecomplex *a, integer *lda, doublecomplex *b, + integer *ldb, doublereal *vl, doublereal *vu, integer *il, integer * + iu, doublereal *abstol, integer *m, doublereal *w, doublecomplex *z__, + integer *ldz, doublecomplex *work, integer *lwork, doublereal *rwork, + integer *iwork, integer *ifail, integer *info); + +/* Subroutine */ int zherfs_(char *uplo, integer *n, integer *nrhs, + doublecomplex *a, integer *lda, doublecomplex *af, integer *ldaf, + integer *ipiv, doublecomplex *b, integer *ldb, doublecomplex *x, + integer *ldx, doublereal *ferr, doublereal *berr, doublecomplex *work, + doublereal *rwork, integer *info); + +/* Subroutine */ int zhesv_(char *uplo, integer *n, integer *nrhs, + doublecomplex *a, integer *lda, integer *ipiv, doublecomplex *b, + integer *ldb, doublecomplex *work, integer *lwork, integer *info); + +/* Subroutine */ int zhesvx_(char *fact, char *uplo, integer *n, integer * + nrhs, doublecomplex *a, integer *lda, doublecomplex *af, integer * + ldaf, integer *ipiv, doublecomplex *b, integer *ldb, doublecomplex *x, + integer *ldx, doublereal *rcond, doublereal *ferr, doublereal *berr, + doublecomplex *work, integer *lwork, doublereal *rwork, integer *info); + +/* Subroutine */ int zhetf2_(char *uplo, integer *n, doublecomplex *a, + integer *lda, integer *ipiv, integer *info); + +/* Subroutine */ int zhetrd_(char *uplo, integer *n, doublecomplex *a, + integer *lda, doublereal *d__, doublereal *e, doublecomplex *tau, + doublecomplex *work, integer *lwork, integer *info); + +/* Subroutine */ int zhetrf_(char *uplo, integer *n, doublecomplex *a, + integer *lda, integer *ipiv, doublecomplex *work, integer *lwork, + integer *info); + +/* Subroutine */ int zhetri_(char *uplo, integer *n, doublecomplex *a, + integer *lda, integer *ipiv, doublecomplex *work, integer *info); + +/* Subroutine */ int zhetrs_(char *uplo, integer *n, integer *nrhs, + doublecomplex *a, integer *lda, integer *ipiv, doublecomplex *b, + integer *ldb, integer *info); + +/* Subroutine */ int zhgeqz_(char *job, char *compq, char *compz, integer *n, + integer *ilo, integer *ihi, doublecomplex *a, integer *lda, + doublecomplex *b, integer *ldb, doublecomplex *alpha, doublecomplex * + beta, doublecomplex *q, integer *ldq, doublecomplex *z__, integer * + ldz, doublecomplex *work, integer *lwork, doublereal *rwork, integer * + info); + +/* Subroutine */ int zhpcon_(char *uplo, integer *n, doublecomplex *ap, + integer *ipiv, doublereal *anorm, doublereal *rcond, doublecomplex * + work, integer *info); + +/* Subroutine */ int zhpev_(char *jobz, char *uplo, integer *n, doublecomplex + *ap, doublereal *w, doublecomplex *z__, integer *ldz, doublecomplex * + work, doublereal *rwork, integer *info); + +/* Subroutine */ int zhpevd_(char *jobz, char *uplo, integer *n, + doublecomplex *ap, doublereal *w, doublecomplex *z__, integer *ldz, + doublecomplex *work, integer *lwork, doublereal *rwork, integer * + lrwork, integer *iwork, integer *liwork, integer *info); + +/* Subroutine */ int zhpevx_(char *jobz, char *range, char *uplo, integer *n, + doublecomplex *ap, doublereal *vl, doublereal *vu, integer *il, + integer *iu, doublereal *abstol, integer *m, doublereal *w, + doublecomplex *z__, integer *ldz, doublecomplex *work, doublereal * + rwork, integer *iwork, integer *ifail, integer *info); + +/* Subroutine */ int zhpgst_(integer *itype, char *uplo, integer *n, + doublecomplex *ap, doublecomplex *bp, integer *info); + +/* Subroutine */ int zhpgv_(integer *itype, char *jobz, char *uplo, integer * + n, doublecomplex *ap, doublecomplex *bp, doublereal *w, doublecomplex + *z__, integer *ldz, doublecomplex *work, doublereal *rwork, integer * + info); + +/* Subroutine */ int zhpgvd_(integer *itype, char *jobz, char *uplo, integer * + n, doublecomplex *ap, doublecomplex *bp, doublereal *w, doublecomplex + *z__, integer *ldz, doublecomplex *work, integer *lwork, doublereal * + rwork, integer *lrwork, integer *iwork, integer *liwork, integer * + info); + +/* Subroutine */ int zhpgvx_(integer *itype, char *jobz, char *range, char * + uplo, integer *n, doublecomplex *ap, doublecomplex *bp, doublereal * + vl, doublereal *vu, integer *il, integer *iu, doublereal *abstol, + integer *m, doublereal *w, doublecomplex *z__, integer *ldz, + doublecomplex *work, doublereal *rwork, integer *iwork, integer * + ifail, integer *info); + +/* Subroutine */ int zhprfs_(char *uplo, integer *n, integer *nrhs, + doublecomplex *ap, doublecomplex *afp, integer *ipiv, doublecomplex * + b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *ferr, + doublereal *berr, doublecomplex *work, doublereal *rwork, integer * + info); + +/* Subroutine */ int zhpsv_(char *uplo, integer *n, integer *nrhs, + doublecomplex *ap, integer *ipiv, doublecomplex *b, integer *ldb, + integer *info); + +/* Subroutine */ int zhpsvx_(char *fact, char *uplo, integer *n, integer * + nrhs, doublecomplex *ap, doublecomplex *afp, integer *ipiv, + doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, + doublereal *rcond, doublereal *ferr, doublereal *berr, doublecomplex * + work, doublereal *rwork, integer *info); + +/* Subroutine */ int zhptrd_(char *uplo, integer *n, doublecomplex *ap, + doublereal *d__, doublereal *e, doublecomplex *tau, integer *info); + +/* Subroutine */ int zhptrf_(char *uplo, integer *n, doublecomplex *ap, + integer *ipiv, integer *info); + +/* Subroutine */ int zhptri_(char *uplo, integer *n, doublecomplex *ap, + integer *ipiv, doublecomplex *work, integer *info); + +/* Subroutine */ int zhptrs_(char *uplo, integer *n, integer *nrhs, + doublecomplex *ap, integer *ipiv, doublecomplex *b, integer *ldb, + integer *info); + +/* Subroutine */ int zhsein_(char *side, char *eigsrc, char *initv, logical * + select, integer *n, doublecomplex *h__, integer *ldh, doublecomplex * + w, doublecomplex *vl, integer *ldvl, doublecomplex *vr, integer *ldvr, + integer *mm, integer *m, doublecomplex *work, doublereal *rwork, + integer *ifaill, integer *ifailr, integer *info); + +/* Subroutine */ int zhseqr_(char *job, char *compz, integer *n, integer *ilo, + integer *ihi, doublecomplex *h__, integer *ldh, doublecomplex *w, + doublecomplex *z__, integer *ldz, doublecomplex *work, integer *lwork, + integer *info); + +/* Subroutine */ int zlabrd_(integer *m, integer *n, integer *nb, + doublecomplex *a, integer *lda, doublereal *d__, doublereal *e, + doublecomplex *tauq, doublecomplex *taup, doublecomplex *x, integer * + ldx, doublecomplex *y, integer *ldy); + +/* Subroutine */ int zlacgv_(integer *n, doublecomplex *x, integer *incx); + +/* Subroutine */ int zlacon_(integer *n, doublecomplex *v, doublecomplex *x, + doublereal *est, integer *kase); + +/* Subroutine */ int zlacp2_(char *uplo, integer *m, integer *n, doublereal * + a, integer *lda, doublecomplex *b, integer *ldb); + +/* Subroutine */ int zlacpy_(char *uplo, integer *m, integer *n, + doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb); + +/* Subroutine */ int zlacrm_(integer *m, integer *n, doublecomplex *a, + integer *lda, doublereal *b, integer *ldb, doublecomplex *c__, + integer *ldc, doublereal *rwork); + +/* Subroutine */ int zlacrt_(integer *n, doublecomplex *cx, integer *incx, + doublecomplex *cy, integer *incy, doublecomplex *c__, doublecomplex * + s); + +/* Subroutine */ int zlaed0_(integer *qsiz, integer *n, doublereal *d__, + doublereal *e, doublecomplex *q, integer *ldq, doublecomplex *qstore, + integer *ldqs, doublereal *rwork, integer *iwork, integer *info); + +/* Subroutine */ int zlaed7_(integer *n, integer *cutpnt, integer *qsiz, + integer *tlvls, integer *curlvl, integer *curpbm, doublereal *d__, + doublecomplex *q, integer *ldq, doublereal *rho, integer *indxq, + doublereal *qstore, integer *qptr, integer *prmptr, integer *perm, + integer *givptr, integer *givcol, doublereal *givnum, doublecomplex * + work, doublereal *rwork, integer *iwork, integer *info); + +/* Subroutine */ int zlaed8_(integer *k, integer *n, integer *qsiz, + doublecomplex *q, integer *ldq, doublereal *d__, doublereal *rho, + integer *cutpnt, doublereal *z__, doublereal *dlamda, doublecomplex * + q2, integer *ldq2, doublereal *w, integer *indxp, integer *indx, + integer *indxq, integer *perm, integer *givptr, integer *givcol, + doublereal *givnum, integer *info); + +/* Subroutine */ int zlaein_(logical *rightv, logical *noinit, integer *n, + doublecomplex *h__, integer *ldh, doublecomplex *w, doublecomplex *v, + doublecomplex *b, integer *ldb, doublereal *rwork, doublereal *eps3, + doublereal *smlnum, integer *info); + +/* Subroutine */ int zlaesy_(doublecomplex *a, doublecomplex *b, + doublecomplex *c__, doublecomplex *rt1, doublecomplex *rt2, + doublecomplex *evscal, doublecomplex *cs1, doublecomplex *sn1); + +/* Subroutine */ int zlaev2_(doublecomplex *a, doublecomplex *b, + doublecomplex *c__, doublereal *rt1, doublereal *rt2, doublereal *cs1, + doublecomplex *sn1); + +/* Subroutine */ int zlags2_(logical *upper, doublereal *a1, doublecomplex * + a2, doublereal *a3, doublereal *b1, doublecomplex *b2, doublereal *b3, + doublereal *csu, doublecomplex *snu, doublereal *csv, doublecomplex * + snv, doublereal *csq, doublecomplex *snq); + +/* Subroutine */ int zlagtm_(char *trans, integer *n, integer *nrhs, + doublereal *alpha, doublecomplex *dl, doublecomplex *d__, + doublecomplex *du, doublecomplex *x, integer *ldx, doublereal *beta, + doublecomplex *b, integer *ldb); + +/* Subroutine */ int zlahef_(char *uplo, integer *n, integer *nb, integer *kb, + doublecomplex *a, integer *lda, integer *ipiv, doublecomplex *w, + integer *ldw, integer *info); + +/* Subroutine */ int zlahqr_(logical *wantt, logical *wantz, integer *n, + integer *ilo, integer *ihi, doublecomplex *h__, integer *ldh, + doublecomplex *w, integer *iloz, integer *ihiz, doublecomplex *z__, + integer *ldz, integer *info); + +/* Subroutine */ int zlahrd_(integer *n, integer *k, integer *nb, + doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *t, + integer *ldt, doublecomplex *y, integer *ldy); + +/* Subroutine */ int zlaic1_(integer *job, integer *j, doublecomplex *x, + doublereal *sest, doublecomplex *w, doublecomplex *gamma, doublereal * + sestpr, doublecomplex *s, doublecomplex *c__); + +/* Subroutine */ int zlals0_(integer *icompq, integer *nl, integer *nr, + integer *sqre, integer *nrhs, doublecomplex *b, integer *ldb, + doublecomplex *bx, integer *ldbx, integer *perm, integer *givptr, + integer *givcol, integer *ldgcol, doublereal *givnum, integer *ldgnum, + doublereal *poles, doublereal *difl, doublereal *difr, doublereal * + z__, integer *k, doublereal *c__, doublereal *s, doublereal *rwork, + integer *info); + +/* Subroutine */ int zlalsa_(integer *icompq, integer *smlsiz, integer *n, + integer *nrhs, doublecomplex *b, integer *ldb, doublecomplex *bx, + integer *ldbx, doublereal *u, integer *ldu, doublereal *vt, integer * + k, doublereal *difl, doublereal *difr, doublereal *z__, doublereal * + poles, integer *givptr, integer *givcol, integer *ldgcol, integer * + perm, doublereal *givnum, doublereal *c__, doublereal *s, doublereal * + rwork, integer *iwork, integer *info); + +/* Subroutine */ int zlapll_(integer *n, doublecomplex *x, integer *incx, + doublecomplex *y, integer *incy, doublereal *ssmin); + +/* Subroutine */ int zlapmt_(logical *forwrd, integer *m, integer *n, + doublecomplex *x, integer *ldx, integer *k); + +/* Subroutine */ int zlaqgb_(integer *m, integer *n, integer *kl, integer *ku, + doublecomplex *ab, integer *ldab, doublereal *r__, doublereal *c__, + doublereal *rowcnd, doublereal *colcnd, doublereal *amax, char *equed); + +/* Subroutine */ int zlaqge_(integer *m, integer *n, doublecomplex *a, + integer *lda, doublereal *r__, doublereal *c__, doublereal *rowcnd, + doublereal *colcnd, doublereal *amax, char *equed); + +/* Subroutine */ int zlaqhb_(char *uplo, integer *n, integer *kd, + doublecomplex *ab, integer *ldab, doublereal *s, doublereal *scond, + doublereal *amax, char *equed); + +/* Subroutine */ int zlaqhe_(char *uplo, integer *n, doublecomplex *a, + integer *lda, doublereal *s, doublereal *scond, doublereal *amax, + char *equed); + +/* Subroutine */ int zlaqhp_(char *uplo, integer *n, doublecomplex *ap, + doublereal *s, doublereal *scond, doublereal *amax, char *equed); + +/* Subroutine */ int zlaqp2_(integer *m, integer *n, integer *offset, + doublecomplex *a, integer *lda, integer *jpvt, doublecomplex *tau, + doublereal *vn1, doublereal *vn2, doublecomplex *work); + +/* Subroutine */ int zlaqps_(integer *m, integer *n, integer *offset, integer + *nb, integer *kb, doublecomplex *a, integer *lda, integer *jpvt, + doublecomplex *tau, doublereal *vn1, doublereal *vn2, doublecomplex * + auxv, doublecomplex *f, integer *ldf); + +/* Subroutine */ int zlaqsb_(char *uplo, integer *n, integer *kd, + doublecomplex *ab, integer *ldab, doublereal *s, doublereal *scond, + doublereal *amax, char *equed); + +/* Subroutine */ int zlaqsp_(char *uplo, integer *n, doublecomplex *ap, + doublereal *s, doublereal *scond, doublereal *amax, char *equed); + +/* Subroutine */ int zlaqsy_(char *uplo, integer *n, doublecomplex *a, + integer *lda, doublereal *s, doublereal *scond, doublereal *amax, + char *equed); + +/* Subroutine */ int zlar1v_(integer *n, integer *b1, integer *bn, doublereal + *sigma, doublereal *d__, doublereal *l, doublereal *ld, doublereal * + lld, doublereal *gersch, doublecomplex *z__, doublereal *ztz, + doublereal *mingma, integer *r__, integer *isuppz, doublereal *work); + +/* Subroutine */ int zlar2v_(integer *n, doublecomplex *x, doublecomplex *y, + doublecomplex *z__, integer *incx, doublereal *c__, doublecomplex *s, + integer *incc); + +/* Subroutine */ int zlarcm_(integer *m, integer *n, doublereal *a, integer * + lda, doublecomplex *b, integer *ldb, doublecomplex *c__, integer *ldc, + doublereal *rwork); + +/* Subroutine */ int zlarf_(char *side, integer *m, integer *n, doublecomplex + *v, integer *incv, doublecomplex *tau, doublecomplex *c__, integer * + ldc, doublecomplex *work); + +/* Subroutine */ int zlarfb_(char *side, char *trans, char *direct, char * + storev, integer *m, integer *n, integer *k, doublecomplex *v, integer + *ldv, doublecomplex *t, integer *ldt, doublecomplex *c__, integer * + ldc, doublecomplex *work, integer *ldwork); + +/* Subroutine */ int zlarfg_(integer *n, doublecomplex *alpha, doublecomplex * + x, integer *incx, doublecomplex *tau); + +/* Subroutine */ int zlarft_(char *direct, char *storev, integer *n, integer * + k, doublecomplex *v, integer *ldv, doublecomplex *tau, doublecomplex * + t, integer *ldt); + +/* Subroutine */ int zlarfx_(char *side, integer *m, integer *n, + doublecomplex *v, doublecomplex *tau, doublecomplex *c__, integer * + ldc, doublecomplex *work); + +/* Subroutine */ int zlargv_(integer *n, doublecomplex *x, integer *incx, + doublecomplex *y, integer *incy, doublereal *c__, integer *incc); + +/* Subroutine */ int zlarnv_(integer *idist, integer *iseed, integer *n, + doublecomplex *x); + +/* Subroutine */ int zlarrv_(integer *n, doublereal *d__, doublereal *l, + integer *isplit, integer *m, doublereal *w, integer *iblock, + doublereal *gersch, doublereal *tol, doublecomplex *z__, integer *ldz, + integer *isuppz, doublereal *work, integer *iwork, integer *info); + +/* Subroutine */ int zlartg_(doublecomplex *f, doublecomplex *g, doublereal * + cs, doublecomplex *sn, doublecomplex *r__); + +/* Subroutine */ int zlartv_(integer *n, doublecomplex *x, integer *incx, + doublecomplex *y, integer *incy, doublereal *c__, doublecomplex *s, + integer *incc); + +/* Subroutine */ int zlarz_(char *side, integer *m, integer *n, integer *l, + doublecomplex *v, integer *incv, doublecomplex *tau, doublecomplex * + c__, integer *ldc, doublecomplex *work); + +/* Subroutine */ int zlarzb_(char *side, char *trans, char *direct, char * + storev, integer *m, integer *n, integer *k, integer *l, doublecomplex + *v, integer *ldv, doublecomplex *t, integer *ldt, doublecomplex *c__, + integer *ldc, doublecomplex *work, integer *ldwork); + +/* Subroutine */ int zlarzt_(char *direct, char *storev, integer *n, integer * + k, doublecomplex *v, integer *ldv, doublecomplex *tau, doublecomplex * + t, integer *ldt); + +/* Subroutine */ int zlascl_(char *type__, integer *kl, integer *ku, + doublereal *cfrom, doublereal *cto, integer *m, integer *n, + doublecomplex *a, integer *lda, integer *info); + +/* Subroutine */ int zlaset_(char *uplo, integer *m, integer *n, + doublecomplex *alpha, doublecomplex *beta, doublecomplex *a, integer * + lda); + +/* Subroutine */ int zlasr_(char *side, char *pivot, char *direct, integer *m, + integer *n, doublereal *c__, doublereal *s, doublecomplex *a, + integer *lda); + +/* Subroutine */ int zlassq_(integer *n, doublecomplex *x, integer *incx, + doublereal *scale, doublereal *sumsq); + +/* Subroutine */ int zlaswp_(integer *n, doublecomplex *a, integer *lda, + integer *k1, integer *k2, integer *ipiv, integer *incx); + +/* Subroutine */ int zlasyf_(char *uplo, integer *n, integer *nb, integer *kb, + doublecomplex *a, integer *lda, integer *ipiv, doublecomplex *w, + integer *ldw, integer *info); + +/* Subroutine */ int zlatbs_(char *uplo, char *trans, char *diag, char * + normin, integer *n, integer *kd, doublecomplex *ab, integer *ldab, + doublecomplex *x, doublereal *scale, doublereal *cnorm, integer *info); + +/* Subroutine */ int zlatdf_(integer *ijob, integer *n, doublecomplex *z__, + integer *ldz, doublecomplex *rhs, doublereal *rdsum, doublereal * + rdscal, integer *ipiv, integer *jpiv); + +/* Subroutine */ int zlatps_(char *uplo, char *trans, char *diag, char * + normin, integer *n, doublecomplex *ap, doublecomplex *x, doublereal * + scale, doublereal *cnorm, integer *info); + +/* Subroutine */ int zlatrd_(char *uplo, integer *n, integer *nb, + doublecomplex *a, integer *lda, doublereal *e, doublecomplex *tau, + doublecomplex *w, integer *ldw); + +/* Subroutine */ int zlatrs_(char *uplo, char *trans, char *diag, char * + normin, integer *n, doublecomplex *a, integer *lda, doublecomplex *x, + doublereal *scale, doublereal *cnorm, integer *info); + +/* Subroutine */ int zlatrz_(integer *m, integer *n, integer *l, + doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * + work); + +/* Subroutine */ int zlatzm_(char *side, integer *m, integer *n, + doublecomplex *v, integer *incv, doublecomplex *tau, doublecomplex * + c1, doublecomplex *c2, integer *ldc, doublecomplex *work); + +/* Subroutine */ int zlauu2_(char *uplo, integer *n, doublecomplex *a, + integer *lda, integer *info); + +/* Subroutine */ int zlauum_(char *uplo, integer *n, doublecomplex *a, + integer *lda, integer *info); + +/* Subroutine */ int zpbcon_(char *uplo, integer *n, integer *kd, + doublecomplex *ab, integer *ldab, doublereal *anorm, doublereal * + rcond, doublecomplex *work, doublereal *rwork, integer *info); + +/* Subroutine */ int zpbequ_(char *uplo, integer *n, integer *kd, + doublecomplex *ab, integer *ldab, doublereal *s, doublereal *scond, + doublereal *amax, integer *info); + +/* Subroutine */ int zpbrfs_(char *uplo, integer *n, integer *kd, integer * + nrhs, doublecomplex *ab, integer *ldab, doublecomplex *afb, integer * + ldafb, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, + doublereal *ferr, doublereal *berr, doublecomplex *work, doublereal * + rwork, integer *info); + +/* Subroutine */ int zpbstf_(char *uplo, integer *n, integer *kd, + doublecomplex *ab, integer *ldab, integer *info); + +/* Subroutine */ int zpbsv_(char *uplo, integer *n, integer *kd, integer * + nrhs, doublecomplex *ab, integer *ldab, doublecomplex *b, integer * + ldb, integer *info); + +/* Subroutine */ int zpbsvx_(char *fact, char *uplo, integer *n, integer *kd, + integer *nrhs, doublecomplex *ab, integer *ldab, doublecomplex *afb, + integer *ldafb, char *equed, doublereal *s, doublecomplex *b, integer + *ldb, doublecomplex *x, integer *ldx, doublereal *rcond, doublereal * + ferr, doublereal *berr, doublecomplex *work, doublereal *rwork, + integer *info); + +/* Subroutine */ int zpbtf2_(char *uplo, integer *n, integer *kd, + doublecomplex *ab, integer *ldab, integer *info); + +/* Subroutine */ int zpbtrf_(char *uplo, integer *n, integer *kd, + doublecomplex *ab, integer *ldab, integer *info); + +/* Subroutine */ int zpbtrs_(char *uplo, integer *n, integer *kd, integer * + nrhs, doublecomplex *ab, integer *ldab, doublecomplex *b, integer * + ldb, integer *info); + +/* Subroutine */ int zpocon_(char *uplo, integer *n, doublecomplex *a, + integer *lda, doublereal *anorm, doublereal *rcond, doublecomplex * + work, doublereal *rwork, integer *info); + +/* Subroutine */ int zpoequ_(integer *n, doublecomplex *a, integer *lda, + doublereal *s, doublereal *scond, doublereal *amax, integer *info); + +/* Subroutine */ int zporfs_(char *uplo, integer *n, integer *nrhs, + doublecomplex *a, integer *lda, doublecomplex *af, integer *ldaf, + doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, + doublereal *ferr, doublereal *berr, doublecomplex *work, doublereal * + rwork, integer *info); + +/* Subroutine */ int zposv_(char *uplo, integer *n, integer *nrhs, + doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, + integer *info); + +/* Subroutine */ int zposvx_(char *fact, char *uplo, integer *n, integer * + nrhs, doublecomplex *a, integer *lda, doublecomplex *af, integer * + ldaf, char *equed, doublereal *s, doublecomplex *b, integer *ldb, + doublecomplex *x, integer *ldx, doublereal *rcond, doublereal *ferr, + doublereal *berr, doublecomplex *work, doublereal *rwork, integer * + info); + +/* Subroutine */ int zpotf2_(char *uplo, integer *n, doublecomplex *a, + integer *lda, integer *info); + +/* Subroutine */ int zpotrf_(char *uplo, integer *n, doublecomplex *a, + integer *lda, integer *info); + +/* Subroutine */ int zpotri_(char *uplo, integer *n, doublecomplex *a, + integer *lda, integer *info); + +/* Subroutine */ int zpotrs_(char *uplo, integer *n, integer *nrhs, + doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, + integer *info); + +/* Subroutine */ int zppcon_(char *uplo, integer *n, doublecomplex *ap, + doublereal *anorm, doublereal *rcond, doublecomplex *work, doublereal + *rwork, integer *info); + +/* Subroutine */ int zppequ_(char *uplo, integer *n, doublecomplex *ap, + doublereal *s, doublereal *scond, doublereal *amax, integer *info); + +/* Subroutine */ int zpprfs_(char *uplo, integer *n, integer *nrhs, + doublecomplex *ap, doublecomplex *afp, doublecomplex *b, integer *ldb, + doublecomplex *x, integer *ldx, doublereal *ferr, doublereal *berr, + doublecomplex *work, doublereal *rwork, integer *info); + +/* Subroutine */ int zppsv_(char *uplo, integer *n, integer *nrhs, + doublecomplex *ap, doublecomplex *b, integer *ldb, integer *info); + +/* Subroutine */ int zppsvx_(char *fact, char *uplo, integer *n, integer * + nrhs, doublecomplex *ap, doublecomplex *afp, char *equed, doublereal * + s, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, + doublereal *rcond, doublereal *ferr, doublereal *berr, doublecomplex * + work, doublereal *rwork, integer *info); + +/* Subroutine */ int zpptrf_(char *uplo, integer *n, doublecomplex *ap, + integer *info); + +/* Subroutine */ int zpptri_(char *uplo, integer *n, doublecomplex *ap, + integer *info); + +/* Subroutine */ int zpptrs_(char *uplo, integer *n, integer *nrhs, + doublecomplex *ap, doublecomplex *b, integer *ldb, integer *info); + +/* Subroutine */ int zptcon_(integer *n, doublereal *d__, doublecomplex *e, + doublereal *anorm, doublereal *rcond, doublereal *rwork, integer * + info); + +/* Subroutine */ int zptrfs_(char *uplo, integer *n, integer *nrhs, + doublereal *d__, doublecomplex *e, doublereal *df, doublecomplex *ef, + doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, + doublereal *ferr, doublereal *berr, doublecomplex *work, doublereal * + rwork, integer *info); + +/* Subroutine */ int zptsv_(integer *n, integer *nrhs, doublereal *d__, + doublecomplex *e, doublecomplex *b, integer *ldb, integer *info); + +/* Subroutine */ int zptsvx_(char *fact, integer *n, integer *nrhs, + doublereal *d__, doublecomplex *e, doublereal *df, doublecomplex *ef, + doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, + doublereal *rcond, doublereal *ferr, doublereal *berr, doublecomplex * + work, doublereal *rwork, integer *info); + +/* Subroutine */ int zpttrf_(integer *n, doublereal *d__, doublecomplex *e, + integer *info); + +/* Subroutine */ int zpttrs_(char *uplo, integer *n, integer *nrhs, + doublereal *d__, doublecomplex *e, doublecomplex *b, integer *ldb, + integer *info); + +/* Subroutine */ int zptts2_(integer *iuplo, integer *n, integer *nrhs, + doublereal *d__, doublecomplex *e, doublecomplex *b, integer *ldb); + +/* Subroutine */ int zrot_(integer *n, doublecomplex *cx, integer *incx, + doublecomplex *cy, integer *incy, doublereal *c__, doublecomplex *s); + +/* Subroutine */ int zspcon_(char *uplo, integer *n, doublecomplex *ap, + integer *ipiv, doublereal *anorm, doublereal *rcond, doublecomplex * + work, integer *info); + +/* Subroutine */ int zspmv_(char *uplo, integer *n, doublecomplex *alpha, + doublecomplex *ap, doublecomplex *x, integer *incx, doublecomplex * + beta, doublecomplex *y, integer *incy); + +/* Subroutine */ int zspr_(char *uplo, integer *n, doublecomplex *alpha, + doublecomplex *x, integer *incx, doublecomplex *ap); + +/* Subroutine */ int zsprfs_(char *uplo, integer *n, integer *nrhs, + doublecomplex *ap, doublecomplex *afp, integer *ipiv, doublecomplex * + b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *ferr, + doublereal *berr, doublecomplex *work, doublereal *rwork, integer * + info); + +/* Subroutine */ int zspsv_(char *uplo, integer *n, integer *nrhs, + doublecomplex *ap, integer *ipiv, doublecomplex *b, integer *ldb, + integer *info); + +/* Subroutine */ int zspsvx_(char *fact, char *uplo, integer *n, integer * + nrhs, doublecomplex *ap, doublecomplex *afp, integer *ipiv, + doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, + doublereal *rcond, doublereal *ferr, doublereal *berr, doublecomplex * + work, doublereal *rwork, integer *info); + +/* Subroutine */ int zsptrf_(char *uplo, integer *n, doublecomplex *ap, + integer *ipiv, integer *info); + +/* Subroutine */ int zsptri_(char *uplo, integer *n, doublecomplex *ap, + integer *ipiv, doublecomplex *work, integer *info); + +/* Subroutine */ int zsptrs_(char *uplo, integer *n, integer *nrhs, + doublecomplex *ap, integer *ipiv, doublecomplex *b, integer *ldb, + integer *info); + +/* Subroutine */ int zstedc_(char *compz, integer *n, doublereal *d__, + doublereal *e, doublecomplex *z__, integer *ldz, doublecomplex *work, + integer *lwork, doublereal *rwork, integer *lrwork, integer *iwork, + integer *liwork, integer *info); + +/* Subroutine */ int zstein_(integer *n, doublereal *d__, doublereal *e, + integer *m, doublereal *w, integer *iblock, integer *isplit, + doublecomplex *z__, integer *ldz, doublereal *work, integer *iwork, + integer *ifail, integer *info); + +/* Subroutine */ int zsteqr_(char *compz, integer *n, doublereal *d__, + doublereal *e, doublecomplex *z__, integer *ldz, doublereal *work, + integer *info); + +/* Subroutine */ int zsycon_(char *uplo, integer *n, doublecomplex *a, + integer *lda, integer *ipiv, doublereal *anorm, doublereal *rcond, + doublecomplex *work, integer *info); + +/* Subroutine */ int zsymv_(char *uplo, integer *n, doublecomplex *alpha, + doublecomplex *a, integer *lda, doublecomplex *x, integer *incx, + doublecomplex *beta, doublecomplex *y, integer *incy); + +/* Subroutine */ int zsyr_(char *uplo, integer *n, doublecomplex *alpha, + doublecomplex *x, integer *incx, doublecomplex *a, integer *lda); + +/* Subroutine */ int zsyrfs_(char *uplo, integer *n, integer *nrhs, + doublecomplex *a, integer *lda, doublecomplex *af, integer *ldaf, + integer *ipiv, doublecomplex *b, integer *ldb, doublecomplex *x, + integer *ldx, doublereal *ferr, doublereal *berr, doublecomplex *work, + doublereal *rwork, integer *info); + +/* Subroutine */ int zsysv_(char *uplo, integer *n, integer *nrhs, + doublecomplex *a, integer *lda, integer *ipiv, doublecomplex *b, + integer *ldb, doublecomplex *work, integer *lwork, integer *info); + +/* Subroutine */ int zsysvx_(char *fact, char *uplo, integer *n, integer * + nrhs, doublecomplex *a, integer *lda, doublecomplex *af, integer * + ldaf, integer *ipiv, doublecomplex *b, integer *ldb, doublecomplex *x, + integer *ldx, doublereal *rcond, doublereal *ferr, doublereal *berr, + doublecomplex *work, integer *lwork, doublereal *rwork, integer *info); + +/* Subroutine */ int zsytf2_(char *uplo, integer *n, doublecomplex *a, + integer *lda, integer *ipiv, integer *info); + +/* Subroutine */ int zsytrf_(char *uplo, integer *n, doublecomplex *a, + integer *lda, integer *ipiv, doublecomplex *work, integer *lwork, + integer *info); + +/* Subroutine */ int zsytri_(char *uplo, integer *n, doublecomplex *a, + integer *lda, integer *ipiv, doublecomplex *work, integer *info); + +/* Subroutine */ int zsytrs_(char *uplo, integer *n, integer *nrhs, + doublecomplex *a, integer *lda, integer *ipiv, doublecomplex *b, + integer *ldb, integer *info); + +/* Subroutine */ int ztbcon_(char *norm, char *uplo, char *diag, integer *n, + integer *kd, doublecomplex *ab, integer *ldab, doublereal *rcond, + doublecomplex *work, doublereal *rwork, integer *info); + +/* Subroutine */ int ztbrfs_(char *uplo, char *trans, char *diag, integer *n, + integer *kd, integer *nrhs, doublecomplex *ab, integer *ldab, + doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, + doublereal *ferr, doublereal *berr, doublecomplex *work, doublereal * + rwork, integer *info); + +/* Subroutine */ int ztbtrs_(char *uplo, char *trans, char *diag, integer *n, + integer *kd, integer *nrhs, doublecomplex *ab, integer *ldab, + doublecomplex *b, integer *ldb, integer *info); + +/* Subroutine */ int ztgevc_(char *side, char *howmny, logical *select, + integer *n, doublecomplex *a, integer *lda, doublecomplex *b, integer + *ldb, doublecomplex *vl, integer *ldvl, doublecomplex *vr, integer * + ldvr, integer *mm, integer *m, doublecomplex *work, doublereal *rwork, + integer *info); + +/* Subroutine */ int ztgex2_(logical *wantq, logical *wantz, integer *n, + doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, + doublecomplex *q, integer *ldq, doublecomplex *z__, integer *ldz, + integer *j1, integer *info); + +/* Subroutine */ int ztgexc_(logical *wantq, logical *wantz, integer *n, + doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, + doublecomplex *q, integer *ldq, doublecomplex *z__, integer *ldz, + integer *ifst, integer *ilst, integer *info); + +/* Subroutine */ int ztgsen_(integer *ijob, logical *wantq, logical *wantz, + logical *select, integer *n, doublecomplex *a, integer *lda, + doublecomplex *b, integer *ldb, doublecomplex *alpha, doublecomplex * + beta, doublecomplex *q, integer *ldq, doublecomplex *z__, integer * + ldz, integer *m, doublereal *pl, doublereal *pr, doublereal *dif, + doublecomplex *work, integer *lwork, integer *iwork, integer *liwork, + integer *info); + +/* Subroutine */ int ztgsja_(char *jobu, char *jobv, char *jobq, integer *m, + integer *p, integer *n, integer *k, integer *l, doublecomplex *a, + integer *lda, doublecomplex *b, integer *ldb, doublereal *tola, + doublereal *tolb, doublereal *alpha, doublereal *beta, doublecomplex * + u, integer *ldu, doublecomplex *v, integer *ldv, doublecomplex *q, + integer *ldq, doublecomplex *work, integer *ncycle, integer *info); + +/* Subroutine */ int ztgsna_(char *job, char *howmny, logical *select, + integer *n, doublecomplex *a, integer *lda, doublecomplex *b, integer + *ldb, doublecomplex *vl, integer *ldvl, doublecomplex *vr, integer * + ldvr, doublereal *s, doublereal *dif, integer *mm, integer *m, + doublecomplex *work, integer *lwork, integer *iwork, integer *info); + +/* Subroutine */ int ztgsy2_(char *trans, integer *ijob, integer *m, integer * + n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, + doublecomplex *c__, integer *ldc, doublecomplex *d__, integer *ldd, + doublecomplex *e, integer *lde, doublecomplex *f, integer *ldf, + doublereal *scale, doublereal *rdsum, doublereal *rdscal, integer * + info); + +/* Subroutine */ int ztgsyl_(char *trans, integer *ijob, integer *m, integer * + n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, + doublecomplex *c__, integer *ldc, doublecomplex *d__, integer *ldd, + doublecomplex *e, integer *lde, doublecomplex *f, integer *ldf, + doublereal *scale, doublereal *dif, doublecomplex *work, integer * + lwork, integer *iwork, integer *info); + +/* Subroutine */ int ztpcon_(char *norm, char *uplo, char *diag, integer *n, + doublecomplex *ap, doublereal *rcond, doublecomplex *work, doublereal + *rwork, integer *info); + +/* Subroutine */ int ztprfs_(char *uplo, char *trans, char *diag, integer *n, + integer *nrhs, doublecomplex *ap, doublecomplex *b, integer *ldb, + doublecomplex *x, integer *ldx, doublereal *ferr, doublereal *berr, + doublecomplex *work, doublereal *rwork, integer *info); + +/* Subroutine */ int ztptri_(char *uplo, char *diag, integer *n, + doublecomplex *ap, integer *info); + +/* Subroutine */ int ztptrs_(char *uplo, char *trans, char *diag, integer *n, + integer *nrhs, doublecomplex *ap, doublecomplex *b, integer *ldb, + integer *info); + +/* Subroutine */ int ztrcon_(char *norm, char *uplo, char *diag, integer *n, + doublecomplex *a, integer *lda, doublereal *rcond, doublecomplex * + work, doublereal *rwork, integer *info); + +/* Subroutine */ int ztrevc_(char *side, char *howmny, logical *select, + integer *n, doublecomplex *t, integer *ldt, doublecomplex *vl, + integer *ldvl, doublecomplex *vr, integer *ldvr, integer *mm, integer + *m, doublecomplex *work, doublereal *rwork, integer *info); + +/* Subroutine */ int ztrexc_(char *compq, integer *n, doublecomplex *t, + integer *ldt, doublecomplex *q, integer *ldq, integer *ifst, integer * + ilst, integer *info); + +/* Subroutine */ int ztrrfs_(char *uplo, char *trans, char *diag, integer *n, + integer *nrhs, doublecomplex *a, integer *lda, doublecomplex *b, + integer *ldb, doublecomplex *x, integer *ldx, doublereal *ferr, + doublereal *berr, doublecomplex *work, doublereal *rwork, integer * + info); + +/* Subroutine */ int ztrsen_(char *job, char *compq, logical *select, integer + *n, doublecomplex *t, integer *ldt, doublecomplex *q, integer *ldq, + doublecomplex *w, integer *m, doublereal *s, doublereal *sep, + doublecomplex *work, integer *lwork, integer *info); + +/* Subroutine */ int ztrsna_(char *job, char *howmny, logical *select, + integer *n, doublecomplex *t, integer *ldt, doublecomplex *vl, + integer *ldvl, doublecomplex *vr, integer *ldvr, doublereal *s, + doublereal *sep, integer *mm, integer *m, doublecomplex *work, + integer *ldwork, doublereal *rwork, integer *info); + +/* Subroutine */ int ztrsyl_(char *trana, char *tranb, integer *isgn, integer + *m, integer *n, doublecomplex *a, integer *lda, doublecomplex *b, + integer *ldb, doublecomplex *c__, integer *ldc, doublereal *scale, + integer *info); + +/* Subroutine */ int ztrti2_(char *uplo, char *diag, integer *n, + doublecomplex *a, integer *lda, integer *info); + +/* Subroutine */ int ztrtri_(char *uplo, char *diag, integer *n, + doublecomplex *a, integer *lda, integer *info); + +/* Subroutine */ int ztrtrs_(char *uplo, char *trans, char *diag, integer *n, + integer *nrhs, doublecomplex *a, integer *lda, doublecomplex *b, + integer *ldb, integer *info); + +/* Subroutine */ int ztzrqf_(integer *m, integer *n, doublecomplex *a, + integer *lda, doublecomplex *tau, integer *info); + +/* Subroutine */ int ztzrzf_(integer *m, integer *n, doublecomplex *a, + integer *lda, doublecomplex *tau, doublecomplex *work, integer *lwork, + integer *info); + +/* Subroutine */ int zung2l_(integer *m, integer *n, integer *k, + doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * + work, integer *info); + +/* Subroutine */ int zung2r_(integer *m, integer *n, integer *k, + doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * + work, integer *info); + +/* Subroutine */ int zungbr_(char *vect, integer *m, integer *n, integer *k, + doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * + work, integer *lwork, integer *info); + +/* Subroutine */ int zunghr_(integer *n, integer *ilo, integer *ihi, + doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * + work, integer *lwork, integer *info); + +/* Subroutine */ int zungl2_(integer *m, integer *n, integer *k, + doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * + work, integer *info); + +/* Subroutine */ int zunglq_(integer *m, integer *n, integer *k, + doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * + work, integer *lwork, integer *info); + +/* Subroutine */ int zungql_(integer *m, integer *n, integer *k, + doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * + work, integer *lwork, integer *info); + +/* Subroutine */ int zungqr_(integer *m, integer *n, integer *k, + doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * + work, integer *lwork, integer *info); + +/* Subroutine */ int zungr2_(integer *m, integer *n, integer *k, + doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * + work, integer *info); + +/* Subroutine */ int zungrq_(integer *m, integer *n, integer *k, + doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * + work, integer *lwork, integer *info); + +/* Subroutine */ int zungtr_(char *uplo, integer *n, doublecomplex *a, + integer *lda, doublecomplex *tau, doublecomplex *work, integer *lwork, + integer *info); + +/* Subroutine */ int zunm2l_(char *side, char *trans, integer *m, integer *n, + integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, + doublecomplex *c__, integer *ldc, doublecomplex *work, integer *info); + +/* Subroutine */ int zunm2r_(char *side, char *trans, integer *m, integer *n, + integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, + doublecomplex *c__, integer *ldc, doublecomplex *work, integer *info); + +/* Subroutine */ int zunmbr_(char *vect, char *side, char *trans, integer *m, + integer *n, integer *k, doublecomplex *a, integer *lda, doublecomplex + *tau, doublecomplex *c__, integer *ldc, doublecomplex *work, integer * + lwork, integer *info); + +/* Subroutine */ int zunmhr_(char *side, char *trans, integer *m, integer *n, + integer *ilo, integer *ihi, doublecomplex *a, integer *lda, + doublecomplex *tau, doublecomplex *c__, integer *ldc, doublecomplex * + work, integer *lwork, integer *info); + +/* Subroutine */ int zunml2_(char *side, char *trans, integer *m, integer *n, + integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, + doublecomplex *c__, integer *ldc, doublecomplex *work, integer *info); + +/* Subroutine */ int zunmlq_(char *side, char *trans, integer *m, integer *n, + integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, + doublecomplex *c__, integer *ldc, doublecomplex *work, integer *lwork, + integer *info); + +/* Subroutine */ int zunmql_(char *side, char *trans, integer *m, integer *n, + integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, + doublecomplex *c__, integer *ldc, doublecomplex *work, integer *lwork, + integer *info); + +/* Subroutine */ int zunmqr_(char *side, char *trans, integer *m, integer *n, + integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, + doublecomplex *c__, integer *ldc, doublecomplex *work, integer *lwork, + integer *info); + +/* Subroutine */ int zunmr2_(char *side, char *trans, integer *m, integer *n, + integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, + doublecomplex *c__, integer *ldc, doublecomplex *work, integer *info); + +/* Subroutine */ int zunmr3_(char *side, char *trans, integer *m, integer *n, + integer *k, integer *l, doublecomplex *a, integer *lda, doublecomplex + *tau, doublecomplex *c__, integer *ldc, doublecomplex *work, integer * + info); + +/* Subroutine */ int zunmrq_(char *side, char *trans, integer *m, integer *n, + integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, + doublecomplex *c__, integer *ldc, doublecomplex *work, integer *lwork, + integer *info); + +/* Subroutine */ int zunmrz_(char *side, char *trans, integer *m, integer *n, + integer *k, integer *l, doublecomplex *a, integer *lda, doublecomplex + *tau, doublecomplex *c__, integer *ldc, doublecomplex *work, integer * + lwork, integer *info); + +/* Subroutine */ int zunmtr_(char *side, char *uplo, char *trans, integer *m, + integer *n, doublecomplex *a, integer *lda, doublecomplex *tau, + doublecomplex *c__, integer *ldc, doublecomplex *work, integer *lwork, + integer *info); + +/* Subroutine */ int zupgtr_(char *uplo, integer *n, doublecomplex *ap, + doublecomplex *tau, doublecomplex *q, integer *ldq, doublecomplex * + work, integer *info); + +/* Subroutine */ int zupmtr_(char *side, char *uplo, char *trans, integer *m, + integer *n, doublecomplex *ap, doublecomplex *tau, doublecomplex *c__, + integer *ldc, doublecomplex *work, integer *info); + +#endif /* __CLAPACK_H */ diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/close.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/close.c new file mode 100644 index 00000000..d305ccf8 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/close.c @@ -0,0 +1,80 @@ +#include "f2c.h" +#include "fio.h" +#undef abs +#undef min +#undef max +#include "stdlib.h" +#ifdef NON_UNIX_STDIO +#ifndef unlink +#define unlink remove +#endif +#else +#ifdef MSDOS +#include "io.h" +#else +#ifdef __cplusplus +extern "C" int unlink(const char*); +#else +extern int unlink(const char*); +#endif +#endif +#endif + +integer f_clos(cllist *a) +{ unit *b; + + if(a->cunit >= MXUNIT) return(0); + b= &f__units[a->cunit]; + if(b->ufd==NULL) + goto done; + if (b->uscrtch == 1) + goto Delete; + if (!a->csta) + goto Keep; + switch(*a->csta) { + default: + Keep: + case 'k': + case 'K': + if(b->uwrt == 1) + t_runc((alist *)a); + if(b->ufnm) { + fclose(b->ufd); + free(b->ufnm); + } + break; + case 'd': + case 'D': + Delete: + fclose(b->ufd); + if(b->ufnm) { + unlink(b->ufnm); /*SYSDEP*/ + free(b->ufnm); + } + } + b->ufd=NULL; + done: + b->uend=0; + b->ufnm=NULL; + return(0); + } +void f_exit(void) +{ int i; + static cllist xx; + if (!xx.cerr) { + xx.cerr=1; + xx.csta=NULL; + for(i=0;i<MXUNIT;i++) + { + xx.cunit=i; + (void) f_clos(&xx); + } + } +} +int flush_(void) +{ int i; + for(i=0;i<MXUNIT;i++) + if(f__units[i].ufd != NULL && f__units[i].uwrt) + fflush(f__units[i].ufd); +return 0; +} diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/dgemm.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/dgemm.c new file mode 100644 index 00000000..964a278a --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/dgemm.c @@ -0,0 +1,313 @@ +#include "blaswrap.h" +#include "f2c.h" + +/* Subroutine */ int dgemm_(char *transa, char *transb, integer *m, integer * + n, integer *k, doublereal *alpha, doublereal *a, integer *lda, + doublereal *b, integer *ldb, doublereal *beta, doublereal *c__, + integer *ldc) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, c_dim1, c_offset, i__1, i__2, + i__3; + /* Local variables */ + static integer info; + static logical nota, notb; + static doublereal temp; + static integer i__, j, l, ncola; + extern logical lsame_(char *, char *); + static integer nrowa, nrowb; + extern /* Subroutine */ int xerbla_(char *, integer *); +#define a_ref(a_1,a_2) a[(a_2)*a_dim1 + a_1] +#define b_ref(a_1,a_2) b[(a_2)*b_dim1 + a_1] +#define c___ref(a_1,a_2) c__[(a_2)*c_dim1 + a_1] +/* Purpose + ======= + DGEMM performs one of the matrix-matrix operations + C := alpha*op( A )*op( B ) + beta*C, + where op( X ) is one of + op( X ) = X or op( X ) = X', + alpha and beta are scalars, and A, B and C are matrices, with op( A ) + an m by k matrix, op( B ) a k by n matrix and C an m by n matrix. + Parameters + ========== + TRANSA - CHARACTER*1. + On entry, TRANSA specifies the form of op( A ) to be used in + the matrix multiplication as follows: + TRANSA = 'N' or 'n', op( A ) = A. + TRANSA = 'T' or 't', op( A ) = A'. + TRANSA = 'C' or 'c', op( A ) = A'. + Unchanged on exit. + TRANSB - CHARACTER*1. + On entry, TRANSB specifies the form of op( B ) to be used in + the matrix multiplication as follows: + TRANSB = 'N' or 'n', op( B ) = B. + TRANSB = 'T' or 't', op( B ) = B'. + TRANSB = 'C' or 'c', op( B ) = B'. + Unchanged on exit. + M - INTEGER. + On entry, M specifies the number of rows of the matrix + op( A ) and of the matrix C. M must be at least zero. + Unchanged on exit. + N - INTEGER. + On entry, N specifies the number of columns of the matrix + op( B ) and the number of columns of the matrix C. N must be + at least zero. + Unchanged on exit. + K - INTEGER. + On entry, K specifies the number of columns of the matrix + op( A ) and the number of rows of the matrix op( B ). K must + be at least zero. + Unchanged on exit. + ALPHA - DOUBLE PRECISION. + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + A - DOUBLE PRECISION array of DIMENSION ( LDA, ka ), where ka is + k when TRANSA = 'N' or 'n', and is m otherwise. + Before entry with TRANSA = 'N' or 'n', the leading m by k + part of the array A must contain the matrix A, otherwise + the leading k by m part of the array A must contain the + matrix A. + Unchanged on exit. + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When TRANSA = 'N' or 'n' then + LDA must be at least max( 1, m ), otherwise LDA must be at + least max( 1, k ). + Unchanged on exit. + B - DOUBLE PRECISION array of DIMENSION ( LDB, kb ), where kb is + n when TRANSB = 'N' or 'n', and is k otherwise. + Before entry with TRANSB = 'N' or 'n', the leading k by n + part of the array B must contain the matrix B, otherwise + the leading n by k part of the array B must contain the + matrix B. + Unchanged on exit. + LDB - INTEGER. + On entry, LDB specifies the first dimension of B as declared + in the calling (sub) program. When TRANSB = 'N' or 'n' then + LDB must be at least max( 1, k ), otherwise LDB must be at + least max( 1, n ). + Unchanged on exit. + BETA - DOUBLE PRECISION. + On entry, BETA specifies the scalar beta. When BETA is + supplied as zero then C need not be set on input. + Unchanged on exit. + C - DOUBLE PRECISION array of DIMENSION ( LDC, n ). + Before entry, the leading m by n part of the array C must + contain the matrix C, except when beta is zero, in which + case C need not be set on entry. + On exit, the array C is overwritten by the m by n matrix + ( alpha*op( A )*op( B ) + beta*C ). + LDC - INTEGER. + On entry, LDC specifies the first dimension of C as declared + in the calling (sub) program. LDC must be at least + max( 1, m ). + Unchanged on exit. + Level 3 Blas routine. + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + Set NOTA and NOTB as true if A and B respectively are not + transposed and set NROWA, NCOLA and NROWB as the number of rows + and columns of A and the number of rows of B respectively. + Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1 * 1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1 * 1; + b -= b_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1 * 1; + c__ -= c_offset; + /* Function Body */ + nota = lsame_(transa, "N"); + notb = lsame_(transb, "N"); + if (nota) { + nrowa = *m; + ncola = *k; + } else { + nrowa = *k; + ncola = *m; + } + if (notb) { + nrowb = *k; + } else { + nrowb = *n; + } +/* Test the input parameters. */ + info = 0; + if (! nota && ! lsame_(transa, "C") && ! lsame_( + transa, "T")) { + info = 1; + } else if (! notb && ! lsame_(transb, "C") && ! + lsame_(transb, "T")) { + info = 2; + } else if (*m < 0) { + info = 3; + } else if (*n < 0) { + info = 4; + } else if (*k < 0) { + info = 5; + } else if (*lda < max(1,nrowa)) { + info = 8; + } else if (*ldb < max(1,nrowb)) { + info = 10; + } else if (*ldc < max(1,*m)) { + info = 13; + } + if (info != 0) { + xerbla_("DGEMM ", &info); + return 0; + } +/* Quick return if possible. */ + if (*m == 0 || *n == 0 || (*alpha == 0. || *k == 0) && *beta == 1.) { + return 0; + } +/* And if alpha.eq.zero. */ + if (*alpha == 0.) { + if (*beta == 0.) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c___ref(i__, j) = 0.; +/* L10: */ + } +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c___ref(i__, j) = *beta * c___ref(i__, j); +/* L30: */ + } +/* L40: */ + } + } + return 0; + } +/* Start the operations. */ + if (notb) { + if (nota) { +/* Form C := alpha*A*B + beta*C. */ + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c___ref(i__, j) = 0.; +/* L50: */ + } + } else if (*beta != 1.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c___ref(i__, j) = *beta * c___ref(i__, j); +/* L60: */ + } + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + if (b_ref(l, j) != 0.) { + temp = *alpha * b_ref(l, j); + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + c___ref(i__, j) = c___ref(i__, j) + temp * a_ref( + i__, l); +/* L70: */ + } + } +/* L80: */ + } +/* L90: */ + } + } else { +/* Form C := alpha*A'*B + beta*C */ + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = 0.; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + temp += a_ref(l, i__) * b_ref(l, j); +/* L100: */ + } + if (*beta == 0.) { + c___ref(i__, j) = *alpha * temp; + } else { + c___ref(i__, j) = *alpha * temp + *beta * c___ref(i__, + j); + } +/* L110: */ + } +/* L120: */ + } + } + } else { + if (nota) { +/* Form C := alpha*A*B' + beta*C */ + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c___ref(i__, j) = 0.; +/* L130: */ + } + } else if (*beta != 1.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c___ref(i__, j) = *beta * c___ref(i__, j); +/* L140: */ + } + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + if (b_ref(j, l) != 0.) { + temp = *alpha * b_ref(j, l); + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + c___ref(i__, j) = c___ref(i__, j) + temp * a_ref( + i__, l); +/* L150: */ + } + } +/* L160: */ + } +/* L170: */ + } + } else { +/* Form C := alpha*A'*B' + beta*C */ + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = 0.; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + temp += a_ref(l, i__) * b_ref(j, l); +/* L180: */ + } + if (*beta == 0.) { + c___ref(i__, j) = *alpha * temp; + } else { + c___ref(i__, j) = *alpha * temp + *beta * c___ref(i__, + j); + } +/* L190: */ + } +/* L200: */ + } + } + } + return 0; +/* End of DGEMM . */ +} /* dgemm_ */ +#undef c___ref +#undef b_ref +#undef a_ref + diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/dger.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/dger.c new file mode 100644 index 00000000..c53835fa --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/dger.c @@ -0,0 +1,143 @@ +#include "blaswrap.h" +#include "f2c.h" + +/* Subroutine */ int dger_(integer *m, integer *n, doublereal *alpha, + doublereal *x, integer *incx, doublereal *y, integer *incy, + doublereal *a, integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + /* Local variables */ + static integer info; + static doublereal temp; + static integer i__, j, ix, jy, kx; + extern /* Subroutine */ int xerbla_(char *, integer *); +#define a_ref(a_1,a_2) a[(a_2)*a_dim1 + a_1] +/* Purpose + ======= + DGER performs the rank 1 operation + A := alpha*x*y' + A, + where alpha is a scalar, x is an m element vector, y is an n element + vector and A is an m by n matrix. + Parameters + ========== + M - INTEGER. + On entry, M specifies the number of rows of the matrix A. + M must be at least zero. + Unchanged on exit. + N - INTEGER. + On entry, N specifies the number of columns of the matrix A. + N must be at least zero. + Unchanged on exit. + ALPHA - DOUBLE PRECISION. + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + X - DOUBLE PRECISION array of dimension at least + ( 1 + ( m - 1 )*abs( INCX ) ). + Before entry, the incremented array X must contain the m + element vector x. + Unchanged on exit. + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + Y - DOUBLE PRECISION array of dimension at least + ( 1 + ( n - 1 )*abs( INCY ) ). + Before entry, the incremented array Y must contain the n + element vector y. + Unchanged on exit. + INCY - INTEGER. + On entry, INCY specifies the increment for the elements of + Y. INCY must not be zero. + Unchanged on exit. + A - DOUBLE PRECISION array of DIMENSION ( LDA, n ). + Before entry, the leading m by n part of the array A must + contain the matrix of coefficients. On exit, A is + overwritten by the updated matrix. + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, m ). + Unchanged on exit. + Level 2 Blas routine. + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + Test the input parameters. + Parameter adjustments */ + --x; + --y; + a_dim1 = *lda; + a_offset = 1 + a_dim1 * 1; + a -= a_offset; + /* Function Body */ + info = 0; + if (*m < 0) { + info = 1; + } else if (*n < 0) { + info = 2; + } else if (*incx == 0) { + info = 5; + } else if (*incy == 0) { + info = 7; + } else if (*lda < max(1,*m)) { + info = 9; + } + if (info != 0) { + xerbla_("DGER ", &info); + return 0; + } +/* Quick return if possible. */ + if (*m == 0 || *n == 0 || *alpha == 0.) { + return 0; + } +/* Start the operations. In this version the elements of A are + accessed sequentially with one pass through A. */ + if (*incy > 0) { + jy = 1; + } else { + jy = 1 - (*n - 1) * *incy; + } + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (y[jy] != 0.) { + temp = *alpha * y[jy]; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + a_ref(i__, j) = a_ref(i__, j) + x[i__] * temp; +/* L10: */ + } + } + jy += *incy; +/* L20: */ + } + } else { + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (*m - 1) * *incx; + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (y[jy] != 0.) { + temp = *alpha * y[jy]; + ix = kx; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + a_ref(i__, j) = a_ref(i__, j) + x[ix] * temp; + ix += *incx; +/* L30: */ + } + } + jy += *incy; +/* L40: */ + } + } + return 0; +/* End of DGER . */ +} /* dger_ */ +#undef a_ref + diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/dgesv.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/dgesv.c new file mode 100644 index 00000000..5c0dc52b --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/dgesv.c @@ -0,0 +1,117 @@ +#include "blaswrap.h" +#include "f2c.h" + +/* Subroutine */ int dgesv_(integer *n, integer *nrhs, doublereal *a, integer + *lda, integer *ipiv, doublereal *b, integer *ldb, integer *info) +{ +/* -- LAPACK driver routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + March 31, 1993 + + + Purpose + ======= + + DGESV computes the solution to a real system of linear equations + A * X = B, + where A is an N-by-N matrix and X and B are N-by-NRHS matrices. + + The LU decomposition with partial pivoting and row interchanges is + used to factor A as + A = P * L * U, + where P is a permutation matrix, L is unit lower triangular, and U is + upper triangular. The factored form of A is then used to solve the + system of equations A * X = B. + + Arguments + ========= + + N (input) INTEGER + The number of linear equations, i.e., the order of the + matrix A. N >= 0. + + NRHS (input) INTEGER + The number of right hand sides, i.e., the number of columns + of the matrix B. NRHS >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the N-by-N coefficient matrix A. + On exit, the factors L and U from the factorization + A = P*L*U; the unit diagonal elements of L are not stored. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + IPIV (output) INTEGER array, dimension (N) + The pivot indices that define the permutation matrix P; + row i of the matrix was interchanged with row IPIV(i). + + B (input/output) DOUBLE PRECISION array, dimension (LDB,NRHS) + On entry, the N-by-NRHS matrix of right hand side matrix B. + On exit, if INFO = 0, the N-by-NRHS solution matrix X. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, U(i,i) is exactly zero. The factorization + has been completed, but the factor U is exactly + singular, so the solution could not be computed. + + ===================================================================== + + + Test the input parameters. + + Parameter adjustments */ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1; + /* Local variables */ + extern /* Subroutine */ int dgetrf_(integer *, integer *, doublereal *, + integer *, integer *, integer *), xerbla_(char *, integer *), dgetrs_(char *, integer *, integer *, doublereal *, + integer *, integer *, doublereal *, integer *, integer *); + + a_dim1 = *lda; + a_offset = 1 + a_dim1 * 1; + a -= a_offset; + --ipiv; + b_dim1 = *ldb; + b_offset = 1 + b_dim1 * 1; + b -= b_offset; + + /* Function Body */ + *info = 0; + if (*n < 0) { + *info = -1; + } else if (*nrhs < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } else if (*ldb < max(1,*n)) { + *info = -7; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DGESV ", &i__1); + return 0; + } + +/* Compute the LU factorization of A. */ + + dgetrf_(n, n, &a[a_offset], lda, &ipiv[1], info); + if (*info == 0) { + +/* Solve the system A*X = B, overwriting B with X. */ + + dgetrs_("No transpose", n, nrhs, &a[a_offset], lda, &ipiv[1], &b[ + b_offset], ldb, info); + } + return 0; + +/* End of DGESV */ + +} /* dgesv_ */ + diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/dgetf2.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/dgetf2.c new file mode 100644 index 00000000..83bf1872 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/dgetf2.c @@ -0,0 +1,157 @@ +#include "blaswrap.h" +#include "f2c.h" + +/* Subroutine */ int dgetf2_(integer *m, integer *n, doublereal *a, integer * + lda, integer *ipiv, integer *info) +{ +/* -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + June 30, 1992 + + + Purpose + ======= + + DGETF2 computes an LU factorization of a general m-by-n matrix A + using partial pivoting with row interchanges. + + The factorization has the form + A = P * L * U + where P is a permutation matrix, L is lower triangular with unit + diagonal elements (lower trapezoidal if m > n), and U is upper + triangular (upper trapezoidal if m < n). + + This is the right-looking Level 2 BLAS version of the algorithm. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the m by n matrix to be factored. + On exit, the factors L and U from the factorization + A = P*L*U; the unit diagonal elements of L are not stored. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + IPIV (output) INTEGER array, dimension (min(M,N)) + The pivot indices; for 1 <= i <= min(M,N), row i of the + matrix was interchanged with row IPIV(i). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -k, the k-th argument had an illegal value + > 0: if INFO = k, U(k,k) is exactly zero. The factorization + has been completed, but the factor U is exactly + singular, and division by zero will occur if it is used + to solve a system of equations. + + ===================================================================== + + + Test the input parameters. + + Parameter adjustments */ + /* Table of constant values */ + static integer c__1 = 1; + static doublereal c_b6 = -1.; + + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + doublereal d__1; + /* Local variables */ + extern /* Subroutine */ int dger_(integer *, integer *, doublereal *, + doublereal *, integer *, doublereal *, integer *, doublereal *, + integer *); + static integer j; + extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, + integer *), dswap_(integer *, doublereal *, integer *, doublereal + *, integer *); + static integer jp; + extern integer idamax_(integer *, doublereal *, integer *); + extern /* Subroutine */ int xerbla_(char *, integer *); +#define a_ref(a_1,a_2) a[(a_2)*a_dim1 + a_1] + + + a_dim1 = *lda; + a_offset = 1 + a_dim1 * 1; + a -= a_offset; + --ipiv; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DGETF2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + return 0; + } + + i__1 = min(*m,*n); + for (j = 1; j <= i__1; ++j) { + +/* Find pivot and test for singularity. */ + + i__2 = *m - j + 1; + jp = j - 1 + idamax_(&i__2, &a_ref(j, j), &c__1); + ipiv[j] = jp; + if (a_ref(jp, j) != 0.) { + +/* Apply the interchange to columns 1:N. */ + + if (jp != j) { + dswap_(n, &a_ref(j, 1), lda, &a_ref(jp, 1), lda); + } + +/* Compute elements J+1:M of J-th column. */ + + if (j < *m) { + i__2 = *m - j; + d__1 = 1. / a_ref(j, j); + dscal_(&i__2, &d__1, &a_ref(j + 1, j), &c__1); + } + + } else if (*info == 0) { + + *info = j; + } + + if (j < min(*m,*n)) { + +/* Update trailing submatrix. */ + + i__2 = *m - j; + i__3 = *n - j; + dger_(&i__2, &i__3, &c_b6, &a_ref(j + 1, j), &c__1, &a_ref(j, j + + 1), lda, &a_ref(j + 1, j + 1), lda); + } +/* L10: */ + } + return 0; + +/* End of DGETF2 */ + +} /* dgetf2_ */ + +#undef a_ref + + diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/dgetrf.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/dgetrf.c new file mode 100644 index 00000000..13175f01 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/dgetrf.c @@ -0,0 +1,197 @@ +#include "blaswrap.h" +#include "f2c.h" + +/* Subroutine */ int dgetrf_(integer *m, integer *n, doublereal *a, integer * + lda, integer *ipiv, integer *info) +{ +/* -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + March 31, 1993 + + + Purpose + ======= + + DGETRF computes an LU factorization of a general M-by-N matrix A + using partial pivoting with row interchanges. + + The factorization has the form + A = P * L * U + where P is a permutation matrix, L is lower triangular with unit + diagonal elements (lower trapezoidal if m > n), and U is upper + triangular (upper trapezoidal if m < n). + + This is the right-looking Level 3 BLAS version of the algorithm. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the M-by-N matrix to be factored. + On exit, the factors L and U from the factorization + A = P*L*U; the unit diagonal elements of L are not stored. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + IPIV (output) INTEGER array, dimension (min(M,N)) + The pivot indices; for 1 <= i <= min(M,N), row i of the + matrix was interchanged with row IPIV(i). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, U(i,i) is exactly zero. The factorization + has been completed, but the factor U is exactly + singular, and division by zero will occur if it is used + to solve a system of equations. + + ===================================================================== + + + Test the input parameters. + + Parameter adjustments */ + /* Table of constant values */ + static integer c__1 = 1; + static integer c_n1 = -1; + static doublereal c_b16 = 1.; + static doublereal c_b19 = -1.; + + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + /* Local variables */ + static integer i__, j; + extern /* Subroutine */ int dgemm_(char *, char *, integer *, integer *, + integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *); + static integer iinfo; + extern /* Subroutine */ int dtrsm_(char *, char *, char *, char *, + integer *, integer *, doublereal *, doublereal *, integer *, + doublereal *, integer *), dgetf2_( + integer *, integer *, doublereal *, integer *, integer *, integer + *); + static integer jb, nb; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int dlaswp_(integer *, doublereal *, integer *, + integer *, integer *, integer *, integer *); +#define a_ref(a_1,a_2) a[(a_2)*a_dim1 + a_1] + + + a_dim1 = *lda; + a_offset = 1 + a_dim1 * 1; + a -= a_offset; + --ipiv; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DGETRF", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + return 0; + } + +/* Determine the block size for this environment. */ + + nb = ilaenv_(&c__1, "DGETRF", " ", m, n, &c_n1, &c_n1, (ftnlen)6, (ftnlen) + 1); + if (nb <= 1 || nb >= min(*m,*n)) { + +/* Use unblocked code. */ + + dgetf2_(m, n, &a[a_offset], lda, &ipiv[1], info); + } else { + +/* Use blocked code. */ + + i__1 = min(*m,*n); + i__2 = nb; + for (j = 1; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { +/* Computing MIN */ + i__3 = min(*m,*n) - j + 1; + jb = min(i__3,nb); + +/* Factor diagonal and subdiagonal blocks and test for exact + singularity. */ + + i__3 = *m - j + 1; + dgetf2_(&i__3, &jb, &a_ref(j, j), lda, &ipiv[j], &iinfo); + +/* Adjust INFO and the pivot indices. */ + + if (*info == 0 && iinfo > 0) { + *info = iinfo + j - 1; + } +/* Computing MIN */ + i__4 = *m, i__5 = j + jb - 1; + i__3 = min(i__4,i__5); + for (i__ = j; i__ <= i__3; ++i__) { + ipiv[i__] = j - 1 + ipiv[i__]; +/* L10: */ + } + +/* Apply interchanges to columns 1:J-1. */ + + i__3 = j - 1; + i__4 = j + jb - 1; + dlaswp_(&i__3, &a[a_offset], lda, &j, &i__4, &ipiv[1], &c__1); + + if (j + jb <= *n) { + +/* Apply interchanges to columns J+JB:N. */ + + i__3 = *n - j - jb + 1; + i__4 = j + jb - 1; + dlaswp_(&i__3, &a_ref(1, j + jb), lda, &j, &i__4, &ipiv[1], & + c__1); + +/* Compute block row of U. */ + + i__3 = *n - j - jb + 1; + dtrsm_("Left", "Lower", "No transpose", "Unit", &jb, &i__3, & + c_b16, &a_ref(j, j), lda, &a_ref(j, j + jb), lda); + if (j + jb <= *m) { + +/* Update trailing submatrix. */ + + i__3 = *m - j - jb + 1; + i__4 = *n - j - jb + 1; + dgemm_("No transpose", "No transpose", &i__3, &i__4, &jb, + &c_b19, &a_ref(j + jb, j), lda, &a_ref(j, j + jb), + lda, &c_b16, &a_ref(j + jb, j + jb), lda); + } + } +/* L20: */ + } + } + return 0; + +/* End of DGETRF */ + +} /* dgetrf_ */ + +#undef a_ref + + diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/dgetrs.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/dgetrs.c new file mode 100644 index 00000000..c4dd0b38 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/dgetrs.c @@ -0,0 +1,159 @@ +#include "blaswrap.h" +#include "f2c.h" + +/* Subroutine */ int dgetrs_(char *trans, integer *n, integer *nrhs, + doublereal *a, integer *lda, integer *ipiv, doublereal *b, integer * + ldb, integer *info) +{ +/* -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + March 31, 1993 + + + Purpose + ======= + + DGETRS solves a system of linear equations + A * X = B or A' * X = B + with a general N-by-N matrix A using the LU factorization computed + by DGETRF. + + Arguments + ========= + + TRANS (input) CHARACTER*1 + Specifies the form of the system of equations: + = 'N': A * X = B (No transpose) + = 'T': A'* X = B (Transpose) + = 'C': A'* X = B (Conjugate transpose = Transpose) + + N (input) INTEGER + The order of the matrix A. N >= 0. + + NRHS (input) INTEGER + The number of right hand sides, i.e., the number of columns + of the matrix B. NRHS >= 0. + + A (input) DOUBLE PRECISION array, dimension (LDA,N) + The factors L and U from the factorization A = P*L*U + as computed by DGETRF. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + IPIV (input) INTEGER array, dimension (N) + The pivot indices from DGETRF; for 1<=i<=N, row i of the + matrix was interchanged with row IPIV(i). + + B (input/output) DOUBLE PRECISION array, dimension (LDB,NRHS) + On entry, the right hand side matrix B. + On exit, the solution matrix X. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input parameters. + + Parameter adjustments */ + /* Table of constant values */ + static integer c__1 = 1; + static doublereal c_b12 = 1.; + static integer c_n1 = -1; + + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1; + /* Local variables */ + extern logical lsame_(char *, char *); + extern /* Subroutine */ int dtrsm_(char *, char *, char *, char *, + integer *, integer *, doublereal *, doublereal *, integer *, + doublereal *, integer *), xerbla_( + char *, integer *), dlaswp_(integer *, doublereal *, + integer *, integer *, integer *, integer *, integer *); + static logical notran; + + + a_dim1 = *lda; + a_offset = 1 + a_dim1 * 1; + a -= a_offset; + --ipiv; + b_dim1 = *ldb; + b_offset = 1 + b_dim1 * 1; + b -= b_offset; + + /* Function Body */ + *info = 0; + notran = lsame_(trans, "N"); + if (! notran && ! lsame_(trans, "T") && ! lsame_( + trans, "C")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*nrhs < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*ldb < max(1,*n)) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DGETRS", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0 || *nrhs == 0) { + return 0; + } + + if (notran) { + +/* Solve A * X = B. + + Apply row interchanges to the right hand sides. */ + + dlaswp_(nrhs, &b[b_offset], ldb, &c__1, n, &ipiv[1], &c__1); + +/* Solve L*X = B, overwriting B with X. */ + + dtrsm_("Left", "Lower", "No transpose", "Unit", n, nrhs, &c_b12, &a[ + a_offset], lda, &b[b_offset], ldb); + +/* Solve U*X = B, overwriting B with X. */ + + dtrsm_("Left", "Upper", "No transpose", "Non-unit", n, nrhs, &c_b12, & + a[a_offset], lda, &b[b_offset], ldb); + } else { + +/* Solve A' * X = B. + + Solve U'*X = B, overwriting B with X. */ + + dtrsm_("Left", "Upper", "Transpose", "Non-unit", n, nrhs, &c_b12, &a[ + a_offset], lda, &b[b_offset], ldb); + +/* Solve L'*X = B, overwriting B with X. */ + + dtrsm_("Left", "Lower", "Transpose", "Unit", n, nrhs, &c_b12, &a[ + a_offset], lda, &b[b_offset], ldb); + +/* Apply row interchanges to the solution vectors. */ + + dlaswp_(nrhs, &b[b_offset], ldb, &c__1, n, &ipiv[1], &c_n1); + } + + return 0; + +/* End of DGETRS */ + +} /* dgetrs_ */ + diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/dlaswp.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/dlaswp.c new file mode 100644 index 00000000..4dd6fd7b --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/dlaswp.c @@ -0,0 +1,143 @@ +#include "blaswrap.h" +#include "f2c.h" + +/* Subroutine */ int dlaswp_(integer *n, doublereal *a, integer *lda, integer + *k1, integer *k2, integer *ipiv, integer *incx) +{ +/* -- LAPACK auxiliary routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + June 30, 1999 + + + Purpose + ======= + + DLASWP performs a series of row interchanges on the matrix A. + One row interchange is initiated for each of rows K1 through K2 of A. + + Arguments + ========= + + N (input) INTEGER + The number of columns of the matrix A. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the matrix of column dimension N to which the row + interchanges will be applied. + On exit, the permuted matrix. + + LDA (input) INTEGER + The leading dimension of the array A. + + K1 (input) INTEGER + The first element of IPIV for which a row interchange will + be done. + + K2 (input) INTEGER + The last element of IPIV for which a row interchange will + be done. + + IPIV (input) INTEGER array, dimension (M*abs(INCX)) + The vector of pivot indices. Only the elements in positions + K1 through K2 of IPIV are accessed. + IPIV(K) = L implies rows K and L are to be interchanged. + + INCX (input) INTEGER + The increment between successive values of IPIV. If IPIV + is negative, the pivots are applied in reverse order. + + Further Details + =============== + + Modified by + R. C. Whaley, Computer Science Dept., Univ. of Tenn., Knoxville, USA + + ===================================================================== + + + Interchange row I with row IPIV(I) for each of rows K1 through K2. + + Parameter adjustments */ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + /* Local variables */ + static doublereal temp; + static integer i__, j, k, i1, i2, n32, ip, ix, ix0, inc; +#define a_ref(a_1,a_2) a[(a_2)*a_dim1 + a_1] + + a_dim1 = *lda; + a_offset = 1 + a_dim1 * 1; + a -= a_offset; + --ipiv; + + /* Function Body */ + if (*incx > 0) { + ix0 = *k1; + i1 = *k1; + i2 = *k2; + inc = 1; + } else if (*incx < 0) { + ix0 = (1 - *k2) * *incx + 1; + i1 = *k2; + i2 = *k1; + inc = -1; + } else { + return 0; + } + + n32 = *n / 32 << 5; + if (n32 != 0) { + i__1 = n32; + for (j = 1; j <= i__1; j += 32) { + ix = ix0; + i__2 = i2; + i__3 = inc; + for (i__ = i1; i__3 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += i__3) + { + ip = ipiv[ix]; + if (ip != i__) { + i__4 = j + 31; + for (k = j; k <= i__4; ++k) { + temp = a_ref(i__, k); + a_ref(i__, k) = a_ref(ip, k); + a_ref(ip, k) = temp; +/* L10: */ + } + } + ix += *incx; +/* L20: */ + } +/* L30: */ + } + } + if (n32 != *n) { + ++n32; + ix = ix0; + i__1 = i2; + i__3 = inc; + for (i__ = i1; i__3 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__3) { + ip = ipiv[ix]; + if (ip != i__) { + i__2 = *n; + for (k = n32; k <= i__2; ++k) { + temp = a_ref(i__, k); + a_ref(i__, k) = a_ref(ip, k); + a_ref(ip, k) = temp; +/* L40: */ + } + } + ix += *incx; +/* L50: */ + } + } + + return 0; + +/* End of DLASWP */ + +} /* dlaswp_ */ + +#undef a_ref + + diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/dscal.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/dscal.c new file mode 100644 index 00000000..e0e6ffb9 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/dscal.c @@ -0,0 +1,62 @@ +#include "blaswrap.h" +#include "f2c.h" + +/* Subroutine */ int dscal_(integer *n, doublereal *da, doublereal *dx, + integer *incx) +{ + /* System generated locals */ + integer i__1, i__2; + /* Local variables */ + static integer i__, m, nincx, mp1; +/* scales a vector by a constant. + uses unrolled loops for increment equal to one. + jack dongarra, linpack, 3/11/78. + modified 3/93 to return if incx .le. 0. + modified 12/3/93, array(1) declarations changed to array(*) + Parameter adjustments */ + --dx; + /* Function Body */ + if (*n <= 0 || *incx <= 0) { + return 0; + } + if (*incx == 1) { + goto L20; + } +/* code for increment not equal to 1 */ + nincx = *n * *incx; + i__1 = nincx; + i__2 = *incx; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + dx[i__] = *da * dx[i__]; +/* L10: */ + } + return 0; +/* code for increment equal to 1 + clean-up loop */ +L20: + m = *n % 5; + if (m == 0) { + goto L40; + } + i__2 = m; + for (i__ = 1; i__ <= i__2; ++i__) { + dx[i__] = *da * dx[i__]; +/* L30: */ + } + if (*n < 5) { + return 0; + } +L40: + mp1 = m + 1; + i__2 = *n; + for (i__ = mp1; i__ <= i__2; i__ += 5) { + dx[i__] = *da * dx[i__]; + dx[i__ + 1] = *da * dx[i__ + 1]; + dx[i__ + 2] = *da * dx[i__ + 2]; + dx[i__ + 3] = *da * dx[i__ + 3]; + dx[i__ + 4] = *da * dx[i__ + 4]; +/* L50: */ + } + return 0; +} /* dscal_ */ + diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/dswap.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/dswap.c new file mode 100644 index 00000000..5aacf29b --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/dswap.c @@ -0,0 +1,81 @@ +#include "blaswrap.h" +#include "f2c.h" + +/* Subroutine */ int dswap_(integer *n, doublereal *dx, integer *incx, + doublereal *dy, integer *incy) +{ + /* System generated locals */ + integer i__1; + /* Local variables */ + static integer i__, m; + static doublereal dtemp; + static integer ix, iy, mp1; +/* interchanges two vectors. + uses unrolled loops for increments equal one. + jack dongarra, linpack, 3/11/78. + modified 12/3/93, array(1) declarations changed to array(*) + Parameter adjustments */ + --dy; + --dx; + /* Function Body */ + if (*n <= 0) { + return 0; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } +/* code for unequal increments or equal increments not equal + to 1 */ + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + dtemp = dx[ix]; + dx[ix] = dy[iy]; + dy[iy] = dtemp; + ix += *incx; + iy += *incy; +/* L10: */ + } + return 0; +/* code for both increments equal to 1 + clean-up loop */ +L20: + m = *n % 3; + if (m == 0) { + goto L40; + } + i__1 = m; + for (i__ = 1; i__ <= i__1; ++i__) { + dtemp = dx[i__]; + dx[i__] = dy[i__]; + dy[i__] = dtemp; +/* L30: */ + } + if (*n < 3) { + return 0; + } +L40: + mp1 = m + 1; + i__1 = *n; + for (i__ = mp1; i__ <= i__1; i__ += 3) { + dtemp = dx[i__]; + dx[i__] = dy[i__]; + dy[i__] = dtemp; + dtemp = dx[i__ + 1]; + dx[i__ + 1] = dy[i__ + 1]; + dy[i__ + 1] = dtemp; + dtemp = dx[i__ + 2]; + dx[i__ + 2] = dy[i__ + 2]; + dy[i__ + 2] = dtemp; +/* L50: */ + } + return 0; +} /* dswap_ */ + diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/dtrsm.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/dtrsm.c new file mode 100644 index 00000000..d178c1ed --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/dtrsm.c @@ -0,0 +1,404 @@ +#include "blaswrap.h" +#include "f2c.h" + +/* Subroutine */ int dtrsm_(char *side, char *uplo, char *transa, char *diag, + integer *m, integer *n, doublereal *alpha, doublereal *a, integer * + lda, doublereal *b, integer *ldb) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1, i__2, i__3; + /* Local variables */ + static integer info; + static doublereal temp; + static integer i__, j, k; + static logical lside; + extern logical lsame_(char *, char *); + static integer nrowa; + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical nounit; +#define a_ref(a_1,a_2) a[(a_2)*a_dim1 + a_1] +#define b_ref(a_1,a_2) b[(a_2)*b_dim1 + a_1] +/* Purpose + ======= + DTRSM solves one of the matrix equations + op( A )*X = alpha*B, or X*op( A ) = alpha*B, + where alpha is a scalar, X and B are m by n matrices, A is a unit, or + non-unit, upper or lower triangular matrix and op( A ) is one of + op( A ) = A or op( A ) = A'. + The matrix X is overwritten on B. + Parameters + ========== + SIDE - CHARACTER*1. + On entry, SIDE specifies whether op( A ) appears on the left + or right of X as follows: + SIDE = 'L' or 'l' op( A )*X = alpha*B. + SIDE = 'R' or 'r' X*op( A ) = alpha*B. + Unchanged on exit. + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the matrix A is an upper or + lower triangular matrix as follows: + UPLO = 'U' or 'u' A is an upper triangular matrix. + UPLO = 'L' or 'l' A is a lower triangular matrix. + Unchanged on exit. + TRANSA - CHARACTER*1. + On entry, TRANSA specifies the form of op( A ) to be used in + the matrix multiplication as follows: + TRANSA = 'N' or 'n' op( A ) = A. + TRANSA = 'T' or 't' op( A ) = A'. + TRANSA = 'C' or 'c' op( A ) = A'. + Unchanged on exit. + DIAG - CHARACTER*1. + On entry, DIAG specifies whether or not A is unit triangular + as follows: + DIAG = 'U' or 'u' A is assumed to be unit triangular. + DIAG = 'N' or 'n' A is not assumed to be unit + triangular. + Unchanged on exit. + M - INTEGER. + On entry, M specifies the number of rows of B. M must be at + least zero. + Unchanged on exit. + N - INTEGER. + On entry, N specifies the number of columns of B. N must be + at least zero. + Unchanged on exit. + ALPHA - DOUBLE PRECISION. + On entry, ALPHA specifies the scalar alpha. When alpha is + zero then A is not referenced and B need not be set before + entry. + Unchanged on exit. + A - DOUBLE PRECISION array of DIMENSION ( LDA, k ), where k is m + when SIDE = 'L' or 'l' and is n when SIDE = 'R' or 'r'. + Before entry with UPLO = 'U' or 'u', the leading k by k + upper triangular part of the array A must contain the upper + triangular matrix and the strictly lower triangular part of + A is not referenced. + Before entry with UPLO = 'L' or 'l', the leading k by k + lower triangular part of the array A must contain the lower + triangular matrix and the strictly upper triangular part of + A is not referenced. + Note that when DIAG = 'U' or 'u', the diagonal elements of + A are not referenced either, but are assumed to be unity. + Unchanged on exit. + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When SIDE = 'L' or 'l' then + LDA must be at least max( 1, m ), when SIDE = 'R' or 'r' + then LDA must be at least max( 1, n ). + Unchanged on exit. + B - DOUBLE PRECISION array of DIMENSION ( LDB, n ). + Before entry, the leading m by n part of the array B must + contain the right-hand side matrix B, and on exit is + overwritten by the solution matrix X. + LDB - INTEGER. + On entry, LDB specifies the first dimension of B as declared + in the calling (sub) program. LDB must be at least + max( 1, m ). + Unchanged on exit. + Level 3 Blas routine. + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + Test the input parameters. + Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1 * 1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1 * 1; + b -= b_offset; + /* Function Body */ + lside = lsame_(side, "L"); + if (lside) { + nrowa = *m; + } else { + nrowa = *n; + } + nounit = lsame_(diag, "N"); + upper = lsame_(uplo, "U"); + info = 0; + if (! lside && ! lsame_(side, "R")) { + info = 1; + } else if (! upper && ! lsame_(uplo, "L")) { + info = 2; + } else if (! lsame_(transa, "N") && ! lsame_(transa, + "T") && ! lsame_(transa, "C")) { + info = 3; + } else if (! lsame_(diag, "U") && ! lsame_(diag, + "N")) { + info = 4; + } else if (*m < 0) { + info = 5; + } else if (*n < 0) { + info = 6; + } else if (*lda < max(1,nrowa)) { + info = 9; + } else if (*ldb < max(1,*m)) { + info = 11; + } + if (info != 0) { + xerbla_("DTRSM ", &info); + return 0; + } +/* Quick return if possible. */ + if (*n == 0) { + return 0; + } +/* And when alpha.eq.zero. */ + if (*alpha == 0.) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b_ref(i__, j) = 0.; +/* L10: */ + } +/* L20: */ + } + return 0; + } +/* Start the operations. */ + if (lside) { + if (lsame_(transa, "N")) { +/* Form B := alpha*inv( A )*B. */ + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*alpha != 1.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b_ref(i__, j) = *alpha * b_ref(i__, j); +/* L30: */ + } + } + for (k = *m; k >= 1; --k) { + if (b_ref(k, j) != 0.) { + if (nounit) { + b_ref(k, j) = b_ref(k, j) / a_ref(k, k); + } + i__2 = k - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + b_ref(i__, j) = b_ref(i__, j) - b_ref(k, j) * + a_ref(i__, k); +/* L40: */ + } + } +/* L50: */ + } +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*alpha != 1.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b_ref(i__, j) = *alpha * b_ref(i__, j); +/* L70: */ + } + } + i__2 = *m; + for (k = 1; k <= i__2; ++k) { + if (b_ref(k, j) != 0.) { + if (nounit) { + b_ref(k, j) = b_ref(k, j) / a_ref(k, k); + } + i__3 = *m; + for (i__ = k + 1; i__ <= i__3; ++i__) { + b_ref(i__, j) = b_ref(i__, j) - b_ref(k, j) * + a_ref(i__, k); +/* L80: */ + } + } +/* L90: */ + } +/* L100: */ + } + } + } else { +/* Form B := alpha*inv( A' )*B. */ + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = *alpha * b_ref(i__, j); + i__3 = i__ - 1; + for (k = 1; k <= i__3; ++k) { + temp -= a_ref(k, i__) * b_ref(k, j); +/* L110: */ + } + if (nounit) { + temp /= a_ref(i__, i__); + } + b_ref(i__, j) = temp; +/* L120: */ + } +/* L130: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + for (i__ = *m; i__ >= 1; --i__) { + temp = *alpha * b_ref(i__, j); + i__2 = *m; + for (k = i__ + 1; k <= i__2; ++k) { + temp -= a_ref(k, i__) * b_ref(k, j); +/* L140: */ + } + if (nounit) { + temp /= a_ref(i__, i__); + } + b_ref(i__, j) = temp; +/* L150: */ + } +/* L160: */ + } + } + } + } else { + if (lsame_(transa, "N")) { +/* Form B := alpha*B*inv( A ). */ + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*alpha != 1.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b_ref(i__, j) = *alpha * b_ref(i__, j); +/* L170: */ + } + } + i__2 = j - 1; + for (k = 1; k <= i__2; ++k) { + if (a_ref(k, j) != 0.) { + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + b_ref(i__, j) = b_ref(i__, j) - a_ref(k, j) * + b_ref(i__, k); +/* L180: */ + } + } +/* L190: */ + } + if (nounit) { + temp = 1. / a_ref(j, j); + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b_ref(i__, j) = temp * b_ref(i__, j); +/* L200: */ + } + } +/* L210: */ + } + } else { + for (j = *n; j >= 1; --j) { + if (*alpha != 1.) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + b_ref(i__, j) = *alpha * b_ref(i__, j); +/* L220: */ + } + } + i__1 = *n; + for (k = j + 1; k <= i__1; ++k) { + if (a_ref(k, j) != 0.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b_ref(i__, j) = b_ref(i__, j) - a_ref(k, j) * + b_ref(i__, k); +/* L230: */ + } + } +/* L240: */ + } + if (nounit) { + temp = 1. / a_ref(j, j); + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + b_ref(i__, j) = temp * b_ref(i__, j); +/* L250: */ + } + } +/* L260: */ + } + } + } else { +/* Form B := alpha*B*inv( A' ). */ + if (upper) { + for (k = *n; k >= 1; --k) { + if (nounit) { + temp = 1. / a_ref(k, k); + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + b_ref(i__, k) = temp * b_ref(i__, k); +/* L270: */ + } + } + i__1 = k - 1; + for (j = 1; j <= i__1; ++j) { + if (a_ref(j, k) != 0.) { + temp = a_ref(j, k); + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b_ref(i__, j) = b_ref(i__, j) - temp * b_ref( + i__, k); +/* L280: */ + } + } +/* L290: */ + } + if (*alpha != 1.) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + b_ref(i__, k) = *alpha * b_ref(i__, k); +/* L300: */ + } + } +/* L310: */ + } + } else { + i__1 = *n; + for (k = 1; k <= i__1; ++k) { + if (nounit) { + temp = 1. / a_ref(k, k); + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b_ref(i__, k) = temp * b_ref(i__, k); +/* L320: */ + } + } + i__2 = *n; + for (j = k + 1; j <= i__2; ++j) { + if (a_ref(j, k) != 0.) { + temp = a_ref(j, k); + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + b_ref(i__, j) = b_ref(i__, j) - temp * b_ref( + i__, k); +/* L330: */ + } + } +/* L340: */ + } + if (*alpha != 1.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b_ref(i__, k) = *alpha * b_ref(i__, k); +/* L350: */ + } + } +/* L360: */ + } + } + } + } + return 0; +/* End of DTRSM . */ +} /* dtrsm_ */ +#undef b_ref +#undef a_ref + diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/endfile.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/endfile.c new file mode 100644 index 00000000..d309fc26 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/endfile.c @@ -0,0 +1,102 @@ +#include "f2c.h" +#include "fio.h" + +#undef abs +#undef min +#undef max +#include "stdlib.h" +#include "string.h" + +extern char *f__r_mode[], *f__w_mode[]; + +integer f_end(alist *a) +{ + unit *b; + FILE *tf; + + if(a->aunit>=MXUNIT || a->aunit<0) err(a->aerr,101,"endfile"); + b = &f__units[a->aunit]; + if(b->ufd==NULL) { + char nbuf[10]; + sprintf(nbuf,"fort.%ld",a->aunit); + if (tf = fopen(nbuf, f__w_mode[0])) + fclose(tf); + return(0); + } + b->uend=1; + return(b->useek ? t_runc(a) : 0); +} + +static int copy(FILE *from, long len, FILE *to) +{ + int len1; + char buf[BUFSIZ]; + + while(fread(buf, len1 = len > BUFSIZ ? BUFSIZ : (int)len, 1, from)) { + if (!fwrite(buf, len1, 1, to)) + return 1; + if ((len -= len1) <= 0) + break; + } + return 0; + } + +int t_runc(alist *a) +{ + long loc, len; + unit *b; + FILE *bf, *tf; + int rc = 0; + + b = &f__units[a->aunit]; + if(b->url) + return(0); /*don't truncate direct files*/ + loc=ftell(bf = b->ufd); + fseek(bf,0L,SEEK_END); + len=ftell(bf); + if (loc >= len || b->useek == 0 || b->ufnm == NULL) + return(0); + fclose(b->ufd); + if (!loc) { + if (!(bf = fopen(b->ufnm, f__w_mode[b->ufmt]))) + rc = 1; + if (b->uwrt) + b->uwrt = 1; + goto done; + } + if (!(bf = fopen(b->ufnm, f__r_mode[0])) + || !(tf = tmpfile())) { +#ifdef NON_UNIX_STDIO + bad: +#endif + rc = 1; + goto done; + } + if (copy(bf, loc, tf)) { + bad1: + rc = 1; + goto done1; + } + if (!(bf = freopen(b->ufnm, f__w_mode[0], bf))) + goto bad1; + rewind(tf); + if (copy(tf, loc, bf)) + goto bad1; + b->urw = 2; +#ifdef NON_UNIX_STDIO + if (b->ufmt) { + fclose(bf); + if (!(bf = fopen(b->ufnm, f__w_mode[3]))) + goto bad; + fseek(bf,0L,SEEK_END); + b->urw = 3; + } +#endif +done1: + fclose(tf); +done: + f__cf = b->ufd = bf; + if (rc) + err(a->aerr,111,"endfile"); + return 0; + } diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/err.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/err.c new file mode 100644 index 00000000..90af7cae --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/err.c @@ -0,0 +1,240 @@ +#ifndef NON_UNIX_STDIO +#define _INCLUDE_POSIX_SOURCE /* for HP-UX */ +#define _INCLUDE_XOPEN_SOURCE /* for HP-UX */ +#include "sys/types.h" +#include "sys/stat.h" +#endif +#include "f2c.h" +#undef abs +#undef min +#undef max +#include "stdlib.h" +#include "fio.h" +#include "fmt.h" /* for struct syl */ + +/*global definitions*/ +unit f__units[MXUNIT]; /*unit table*/ +flag f__init; /*0 on entry, 1 after initializations*/ +cilist *f__elist; /*active external io list*/ +icilist *f__svic; /*active internal io list*/ +flag f__reading; /*1 if reading, 0 if writing*/ +flag f__cplus,f__cblank; +char *f__fmtbuf; +flag f__external; /*1 if external io, 0 if internal */ +int (*f__getn)(void); /* for formatted input */ +void (*f__putn)(int); /* for formatted output */ +int (*f__doed)(struct syl*, char*, ftnlen),(*f__doned)(struct syl*); +int (*f__dorevert)(void),(*f__donewrec)(void),(*f__doend)(void); +flag f__sequential; /*1 if sequential io, 0 if direct*/ +flag f__formatted; /*1 if formatted io, 0 if unformatted*/ +FILE *f__cf; /*current file*/ +unit *f__curunit; /*current unit*/ +int f__recpos; /*place in current record*/ +int f__cursor, f__hiwater, f__scale; +char *f__icptr; + +/*error messages*/ +char *F_err[] = +{ + "error in format", /* 100 */ + "illegal unit number", /* 101 */ + "formatted io not allowed", /* 102 */ + "unformatted io not allowed", /* 103 */ + "direct io not allowed", /* 104 */ + "sequential io not allowed", /* 105 */ + "can't backspace file", /* 106 */ + "null file name", /* 107 */ + "can't stat file", /* 108 */ + "unit not connected", /* 109 */ + "off end of record", /* 110 */ + "truncation failed in endfile", /* 111 */ + "incomprehensible list input", /* 112 */ + "out of free space", /* 113 */ + "unit not connected", /* 114 */ + "read unexpected character", /* 115 */ + "bad logical input field", /* 116 */ + "bad variable type", /* 117 */ + "bad namelist name", /* 118 */ + "variable not in namelist", /* 119 */ + "no end record", /* 120 */ + "variable count incorrect", /* 121 */ + "subscript for scalar variable", /* 122 */ + "invalid array section", /* 123 */ + "substring out of bounds", /* 124 */ + "subscript out of bounds", /* 125 */ + "can't read file", /* 126 */ + "can't write file", /* 127 */ + "'new' file exists", /* 128 */ + "can't append to file", /* 129 */ + "non-positive record number" /* 130 */ +}; +#define MAXERR (sizeof(F_err)/sizeof(char *)+100) + +int f__canseek(FILE *f) /*SYSDEP*/ +{ +#ifdef NON_UNIX_STDIO + return !isatty(fileno(f)); +#else + struct stat x; + + if (fstat(fileno(f),&x) < 0) + return(0); +#ifdef S_IFMT + switch(x.st_mode & S_IFMT) { + case S_IFDIR: + case S_IFREG: + if(x.st_nlink > 0) /* !pipe */ + return(1); + else + return(0); + case S_IFCHR: + if(isatty(fileno(f))) + return(0); + return(1); +#ifdef S_IFBLK + case S_IFBLK: + return(1); +#endif + } +#else +#ifdef S_ISDIR + /* POSIX version */ + if (S_ISREG(x.st_mode) || S_ISDIR(x.st_mode)) { + if(x.st_nlink > 0) /* !pipe */ + return(1); + else + return(0); + } + if (S_ISCHR(x.st_mode)) { + if(isatty(fileno(f))) + return(0); + return(1); + } + if (S_ISBLK(x.st_mode)) + return(1); +#else + Help! How does fstat work on this system? +#endif +#endif + return(0); /* who knows what it is? */ +#endif +} + +void f__fatal(int n, char *s) +{ + if(n<100 && n>=0) perror(s); /*SYSDEP*/ + else if(n >= (int)MAXERR || n < -1) + { fprintf(stderr,"%s: illegal error number %d\n",s,n); + } + else if(n == -1) fprintf(stderr,"%s: end of file\n",s); + else + fprintf(stderr,"%s: %s\n",s,F_err[n-100]); + if (f__curunit) { + fprintf(stderr,"apparent state: unit %d ", + (int)(f__curunit-f__units)); + fprintf(stderr, f__curunit->ufnm ? "named %s\n" : "(unnamed)\n", + f__curunit->ufnm); + } + else + fprintf(stderr,"apparent state: internal I/O\n"); + if (f__fmtbuf) + fprintf(stderr,"last format: %s\n",f__fmtbuf); + fprintf(stderr,"lately %s %s %s %s",f__reading?"reading":"writing", + f__sequential?"sequential":"direct",f__formatted?"formatted":"unformatted", + f__external?"external":"internal"); + sig_die(" IO", 1); +} +/*initialization routine*/ + VOID +f_init(Void) +{ unit *p; + + f__init=1; + p= &f__units[0]; + p->ufd=stderr; + p->useek=f__canseek(stderr); + p->ufmt=1; + p->uwrt=1; + p = &f__units[5]; + p->ufd=stdin; + p->useek=f__canseek(stdin); + p->ufmt=1; + p->uwrt=0; + p= &f__units[6]; + p->ufd=stdout; + p->useek=f__canseek(stdout); + p->ufmt=1; + p->uwrt=1; +} + +int f__nowreading(unit *x) +{ + long loc; + int ufmt, urw; + extern char *f__r_mode[], *f__w_mode[]; + + if (x->urw & 1) + goto done; + if (!x->ufnm) + goto cantread; + ufmt = x->url ? 0 : x->ufmt; + loc = ftell(x->ufd); + urw = 3; + if (!freopen(x->ufnm, f__w_mode[ufmt|2], x->ufd)) { + urw = 1; + if(!freopen(x->ufnm, f__r_mode[ufmt], x->ufd)) { + cantread: + errno = 126; + return 1; + } + } + fseek(x->ufd,loc,SEEK_SET); + x->urw = urw; + done: + x->uwrt = 0; + return 0; +} + +int f__nowwriting(unit *x) +{ + long loc; + int ufmt; + extern char *f__w_mode[]; + + if (x->urw & 2) + goto done; + if (!x->ufnm) + goto cantwrite; + ufmt = x->url ? 0 : x->ufmt; + if (x->uwrt == 3) { /* just did write, rewind */ + if (!(f__cf = x->ufd = + freopen(x->ufnm,f__w_mode[ufmt],x->ufd))) + goto cantwrite; + x->urw = 2; + } + else { + loc=ftell(x->ufd); + if (!(f__cf = x->ufd = + freopen(x->ufnm, f__w_mode[ufmt |= 2], x->ufd))) + { + x->ufd = NULL; + cantwrite: + errno = 127; + return(1); + } + x->urw = 3; + fseek(x->ufd,loc,SEEK_SET); + } + done: + x->uwrt = 1; + return 0; +} + +int err__fl(int f, int m, char *s) +{ + if (!f) + f__fatal(m, s); + if (f__doend) + (*f__doend)(); + return errno = m; + } diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/f2c.h b/src/imageplugins/coreplugin/sharpnesseditor/clapack/f2c.h new file mode 100644 index 00000000..6514cd91 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/f2c.h @@ -0,0 +1,223 @@ +/* f2c.h -- Standard Fortran to C header file */ + +/** barf [ba:rf] 2. "He suggested using FORTRAN, and everybody barfed." + + - From The Shogakukan DICTIONARY OF NEW ENGLISH (Second edition) */ + +#ifndef F2C_INCLUDE +#define F2C_INCLUDE + +typedef long int integer; +typedef unsigned long uinteger; +typedef char *address; +typedef short int shortint; +typedef float real; +typedef double doublereal; +typedef struct { real r, i; } complex; +typedef struct { doublereal r, i; } doublecomplex; +typedef long int logical; +typedef short int shortlogical; +typedef char logical1; +typedef char integer1; +#if 0 /* Adjust for integer*8. */ +typedef long long longint; /* system-dependent */ +typedef unsigned long long ulongint; /* system-dependent */ +#define qbit_clear(a,b) ((a) & ~((ulongint)1 << (b))) +#define qbit_set(a,b) ((a) | ((ulongint)1 << (b))) +#endif + +#define TRUE_ (1) +#define FALSE_ (0) + +/* Extern is for use with -E */ +#ifndef Extern +#define Extern extern +#endif + +/* I/O stuff */ + +#ifdef f2c_i2 +/* for -i2 */ +typedef short flag; +typedef short ftnlen; +typedef short ftnint; +#else +typedef long int flag; +typedef long int ftnlen; +typedef long int ftnint; +#endif + +/*external read, write*/ +typedef struct +{ flag cierr; + ftnint ciunit; + flag ciend; + char *cifmt; + ftnint cirec; +} cilist; + +/*internal read, write*/ +typedef struct +{ flag icierr; + char *iciunit; + flag iciend; + char *icifmt; + ftnint icirlen; + ftnint icirnum; +} icilist; + +/*open*/ +typedef struct +{ flag oerr; + ftnint ounit; + char *ofnm; + ftnlen ofnmlen; + char *osta; + char *oacc; + char *ofm; + ftnint orl; + char *oblnk; +} olist; + +/*close*/ +typedef struct +{ flag cerr; + ftnint cunit; + char *csta; +} cllist; + +/*rewind, backspace, endfile*/ +typedef struct +{ flag aerr; + ftnint aunit; +} alist; + +/* inquire */ +typedef struct +{ flag inerr; + ftnint inunit; + char *infile; + ftnlen infilen; + ftnint *inex; /*parameters in standard's order*/ + ftnint *inopen; + ftnint *innum; + ftnint *innamed; + char *inname; + ftnlen innamlen; + char *inacc; + ftnlen inacclen; + char *inseq; + ftnlen inseqlen; + char *indir; + ftnlen indirlen; + char *infmt; + ftnlen infmtlen; + char *inform; + ftnint informlen; + char *inunf; + ftnlen inunflen; + ftnint *inrecl; + ftnint *innrec; + char *inblank; + ftnlen inblanklen; +} inlist; + +#define VOID void + +union Multitype { /* for multiple entry points */ + integer1 g; + shortint h; + integer i; + /* longint j; */ + real r; + doublereal d; + complex c; + doublecomplex z; + }; + +typedef union Multitype Multitype; + +/*typedef long int Long;*/ /* No longer used; formerly in Namelist */ + +struct Vardesc { /* for Namelist */ + char *name; + char *addr; + ftnlen *dims; + int type; + }; +typedef struct Vardesc Vardesc; + +struct Namelist { + char *name; + Vardesc **vars; + int nvars; + }; +typedef struct Namelist Namelist; + +#define abs(x) ((x) >= 0 ? (x) : -(x)) +#define dabs(x) (doublereal)abs(x) +#define min(a,b) ((a) <= (b) ? (a) : (b)) +#define max(a,b) ((a) >= (b) ? (a) : (b)) +#define dmin(a,b) (doublereal)min(a,b) +#define dmax(a,b) (doublereal)max(a,b) +#define bit_test(a,b) ((a) >> (b) & 1) +#define bit_clear(a,b) ((a) & ~((uinteger)1 << (b))) +#define bit_set(a,b) ((a) | ((uinteger)1 << (b))) + +/* procedure parameter types for -A and -C++ */ + +#define F2C_proc_par_types 1 +#ifdef __cplusplus +typedef int /* Unknown procedure type */ (*U_fp)(...); +typedef shortint (*J_fp)(...); +typedef integer (*I_fp)(...); +typedef real (*R_fp)(...); +typedef doublereal (*D_fp)(...), (*E_fp)(...); +typedef /* Complex */ VOID (*C_fp)(...); +typedef /* Double Complex */ VOID (*Z_fp)(...); +typedef logical (*L_fp)(...); +typedef shortlogical (*K_fp)(...); +typedef /* Character */ VOID (*H_fp)(...); +typedef /* Subroutine */ int (*S_fp)(...); +#else +typedef int /* Unknown procedure type */ (*U_fp)(); +typedef shortint (*J_fp)(); +typedef integer (*I_fp)(); +typedef real (*R_fp)(); +typedef doublereal (*D_fp)(), (*E_fp)(); +typedef /* Complex */ VOID (*C_fp)(); +typedef /* Double Complex */ VOID (*Z_fp)(); +typedef logical (*L_fp)(); +typedef shortlogical (*K_fp)(); +typedef /* Character */ VOID (*H_fp)(); +typedef /* Subroutine */ int (*S_fp)(); +#endif +/* E_fp is for real functions when -R is not specified */ +typedef VOID C_f; /* complex function */ +typedef VOID H_f; /* character function */ +typedef VOID Z_f; /* double complex function */ +typedef doublereal E_f; /* real function with -R not specified */ + +/* undef any lower-case symbols that your C compiler predefines, e.g.: */ + +#ifndef Skip_f2c_Undefs +#undef cray +#undef gcos +#undef mc68010 +#undef mc68020 +#undef mips +#undef pdp11 +#undef sgi +#undef sparc +#undef sun +#undef sun2 +#undef sun3 +#undef sun4 +#undef u370 +#undef u3b +#undef u3b2 +#undef u3b5 +#undef unix +#undef vax +#endif +#endif diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/fio.h b/src/imageplugins/coreplugin/sharpnesseditor/clapack/fio.h new file mode 100644 index 00000000..b1632d50 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/fio.h @@ -0,0 +1,96 @@ +#include "stdio.h" +#include "errno.h" +#ifndef NULL +/* ANSI C */ +#include "stddef.h" +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 +#endif + +#ifdef MSDOS +#ifndef NON_UNIX_STDIO +#define NON_UNIX_STDIO +#endif +#endif + +#ifdef UIOLEN_int +typedef int uiolen; +#else +typedef long uiolen; +#endif + +/*units*/ +typedef struct +{ FILE *ufd; /*0=unconnected*/ + char *ufnm; +#ifndef MSDOS + long uinode; + int udev; +#endif + int url; /*0=sequential*/ + flag useek; /*true=can backspace, use dir, ...*/ + flag ufmt; + flag urw; /* (1 for can read) | (2 for can write) */ + flag ublnk; + flag uend; + flag uwrt; /*last io was write*/ + flag uscrtch; +} unit; + +extern flag f__init; +extern cilist *f__elist; /*active external io list*/ +extern flag f__reading,f__external,f__sequential,f__formatted; +#undef Void +#define Void void +#ifdef __cplusplus +extern "C" { +#endif +extern int (*f__getn)(void); /* for formatted input */ +extern void (*f__putn)(int); /* for formatted output */ +extern void x_putc(int); +extern long f__inode(char*,int*); +extern void sig_die(char*,int); +extern void f__fatal(int,char*); +extern int t_runc(alist*); +extern int f__nowreading(unit*), f__nowwriting(unit*); +extern int fk_open(int,int,ftnint); +extern int en_fio(void); +extern void f_init(void); +extern int (*f__donewrec)(void), t_putc(int), x_wSL(void); +extern void b_char(char*,char*,ftnlen), g_char(char*,ftnlen,char*); +extern int c_sfe(cilist*), z_rnew(void); +extern int isatty(int); +extern int err__fl(int,int,char*); +extern int xrd_SL(void); +extern int f__putbuf(int); +#ifdef __cplusplus + } +#endif +extern int (*f__doend)(Void); +extern FILE *f__cf; /*current file*/ +extern unit *f__curunit; /*current unit*/ +extern unit f__units[]; +#define err(f,m,s) {if(f) errno= m; else f__fatal(m,s); return(m);} +#define errfl(f,m,s) return err__fl((int)f,m,s) + +/*Table sizes*/ +#define MXUNIT 100 + +extern int f__recpos; /*position in current record*/ +extern int f__cursor; /* offset to move to */ +extern int f__hiwater; /* so TL doesn't confuse us */ + +#define WRITE 1 +#define READ 2 +#define SEQ 3 +#define DIR 4 +#define FMT 5 +#define UNF 6 +#define EXT 7 +#define INT 8 + +#define buf_end(x) (x->_flag & _IONBF ? x->_ptr : x->_base + BUFSIZ) diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/fmt.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/fmt.c new file mode 100644 index 00000000..a4fcbc38 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/fmt.c @@ -0,0 +1,470 @@ +#include "f2c.h" +#include "fio.h" +#include "fmt.h" +#define skip(s) while(*s==' ') s++ +#ifdef interdata +#define SYLMX 300 +#endif +#ifdef pdp11 +#define SYLMX 300 +#endif +#ifdef vax +#define SYLMX 300 +#endif +#ifndef SYLMX +#define SYLMX 300 +#endif +#define GLITCH '\2' + /* special quote character for stu */ +extern int f__cursor,f__scale; +extern flag f__cblank,f__cplus; /*blanks in I and compulsory plus*/ +static struct syl f__syl[SYLMX]; +int f__parenlvl,f__pc,f__revloc; + +static char *ap_end(char *s) +{ char quote; + quote= *s++; + for(;*s;s++) + { if(*s!=quote) continue; + if(*++s!=quote) return(s); + } + if(f__elist->cierr) { + errno = 100; + return(NULL); + } + f__fatal(100, "bad string"); + /*NOTREACHED*/ return 0; +} + +static int op_gen(int a, int b, int c, int d) +{ struct syl *p= &f__syl[f__pc]; + if(f__pc>=SYLMX) + { fprintf(stderr,"format too complicated:\n"); + sig_die(f__fmtbuf, 1); + } + p->op=a; + p->p1=b; + p->p2.i[0]=c; + p->p2.i[1]=d; + return(f__pc++); +} + +static char *f_list(char*); +static char *gt_num(char *s, int *n, int n1) +{ int m=0,f__cnt=0; + char c; + for(c= *s;;c = *s) + { if(c==' ') + { s++; + continue; + } + if(c>'9' || c<'0') break; + m=10*m+c-'0'; + f__cnt++; + s++; + } + if(f__cnt==0) { + if (!n1) + s = 0; + *n=n1; + } + else *n=m; + return(s); +} + +static char *f_s(char *s, int curloc) +{ + skip(s); + if(*s++!='(') + { + return(NULL); + } + if(f__parenlvl++ ==1) f__revloc=curloc; + if(op_gen(RET1,curloc,0,0)<0 || + (s=f_list(s))==NULL) + { + return(NULL); + } + skip(s); + return(s); +} + +static int ne_d(char *s, char **p) +{ int n,x,sign=0; + struct syl *sp; + switch(*s) + { + default: + return(0); + case ':': (void) op_gen(COLON,0,0,0); break; + case '$': + (void) op_gen(NONL, 0, 0, 0); break; + case 'B': + case 'b': + if(*++s=='z' || *s == 'Z') (void) op_gen(BZ,0,0,0); + else (void) op_gen(BN,0,0,0); + break; + case 'S': + case 's': + if(*(s+1)=='s' || *(s+1) == 'S') + { x=SS; + s++; + } + else if(*(s+1)=='p' || *(s+1) == 'P') + { x=SP; + s++; + } + else x=S; + (void) op_gen(x,0,0,0); + break; + case '/': (void) op_gen(SLASH,0,0,0); break; + case '-': sign=1; + case '+': s++; /*OUTRAGEOUS CODING TRICK*/ + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (!(s=gt_num(s,&n,0))) { + bad: *p = 0; + return 1; + } + switch(*s) + { + default: + return(0); + case 'P': + case 'p': if(sign) n= -n; (void) op_gen(P,n,0,0); break; + case 'X': + case 'x': (void) op_gen(X,n,0,0); break; + case 'H': + case 'h': + sp = &f__syl[op_gen(H,n,0,0)]; + sp->p2.s = s + 1; + s+=n; + break; + } + break; + case GLITCH: + case '"': + case '\'': + sp = &f__syl[op_gen(APOS,0,0,0)]; + sp->p2.s = s; + if((*p = ap_end(s)) == NULL) + return(0); + return(1); + case 'T': + case 't': + if(*(s+1)=='l' || *(s+1) == 'L') + { x=TL; + s++; + } + else if(*(s+1)=='r'|| *(s+1) == 'R') + { x=TR; + s++; + } + else x=T; + if (!(s=gt_num(s+1,&n,0))) + goto bad; + s--; + (void) op_gen(x,n,0,0); + break; + case 'X': + case 'x': (void) op_gen(X,1,0,0); break; + case 'P': + case 'p': (void) op_gen(P,1,0,0); break; + } + s++; + *p=s; + return(1); +} + +static int e_d(char *s, char **p) +{ int i,im,n,w,d,e,found=0,x=0; + char *sv=s; + s=gt_num(s,&n,1); + (void) op_gen(STACK,n,0,0); + switch(*s++) + { + default: break; + case 'E': + case 'e': x=1; + case 'G': + case 'g': + found=1; + if (!(s=gt_num(s,&w,0))) { + bad: + *p = 0; + return 1; + } + if(w==0) break; + if(*s=='.') { + if (!(s=gt_num(s+1,&d,0))) + goto bad; + } + else d=0; + if(*s!='E' && *s != 'e') + (void) op_gen(x==1?E:G,w,d,0); /* default is Ew.dE2 */ + else { + if (!(s=gt_num(s+1,&e,0))) + goto bad; + (void) op_gen(x==1?EE:GE,w,d,e); + } + break; + case 'O': + case 'o': + i = O; + im = OM; + goto finish_I; + case 'Z': + case 'z': + i = Z; + im = ZM; + goto finish_I; + case 'L': + case 'l': + found=1; + if (!(s=gt_num(s,&w,0))) + goto bad; + if(w==0) break; + (void) op_gen(L,w,0,0); + break; + case 'A': + case 'a': + found=1; + skip(s); + if(*s>='0' && *s<='9') + { s=gt_num(s,&w,1); + if(w==0) break; + (void) op_gen(AW,w,0,0); + break; + } + (void) op_gen(A,0,0,0); + break; + case 'F': + case 'f': + if (!(s=gt_num(s,&w,0))) + goto bad; + found=1; + if(w==0) break; + if(*s=='.') { + if (!(s=gt_num(s+1,&d,0))) + goto bad; + } + else d=0; + (void) op_gen(F,w,d,0); + break; + case 'D': + case 'd': + found=1; + if (!(s=gt_num(s,&w,0))) + goto bad; + if(w==0) break; + if(*s=='.') { + if (!(s=gt_num(s+1,&d,0))) + goto bad; + } + else d=0; + (void) op_gen(D,w,d,0); + break; + case 'I': + case 'i': + i = I; + im = IM; + finish_I: + if (!(s=gt_num(s,&w,0))) + goto bad; + found=1; + if(w==0) break; + if(*s!='.') + { (void) op_gen(i,w,0,0); + break; + } + if (!(s=gt_num(s+1,&d,0))) + goto bad; + (void) op_gen(im,w,d,0); + break; + } + if(found==0) + { f__pc--; /*unSTACK*/ + *p=sv; + return(0); + } + *p=s; + return(1); +} + +static char *i_tem(char *s) +{ char *t; + int n,curloc; + if(*s==')') return(s); + if(ne_d(s,&t)) return(t); + if(e_d(s,&t)) return(t); + s=gt_num(s,&n,1); + if((curloc=op_gen(STACK,n,0,0))<0) return(NULL); + return(f_s(s,curloc)); +} + +static char *f_list(char *s) +{ + for(;*s!=0;) + { skip(s); + if((s=i_tem(s))==NULL) return(NULL); + skip(s); + if(*s==',') s++; + else if(*s==')') + { if(--f__parenlvl==0) + { + (void) op_gen(REVERT,f__revloc,0,0); + return(++s); + } + (void) op_gen(GOTO,0,0,0); + return(++s); + } + } + return(NULL); +} + +int pars_f(char *s) +{ + f__parenlvl=f__revloc=f__pc=0; + if(f_s(s,0) == NULL) + { + return(-1); + } + return(0); +} + +#define STKSZ 10 +int f__cnt[STKSZ],f__ret[STKSZ],f__cp,f__rp; +flag f__workdone, f__nonl; + +static int type_f(int n) +{ + switch(n) + { + default: + return(n); + case RET1: + return(RET1); + case REVERT: return(REVERT); + case GOTO: return(GOTO); + case STACK: return(STACK); + case X: + case SLASH: + case APOS: case H: + case T: case TL: case TR: + return(NED); + case F: + case I: + case IM: + case A: case AW: + case O: case OM: + case L: + case E: case EE: case D: + case G: case GE: + case Z: case ZM: + return(ED); + } +} + +integer do_fio(ftnint *number, char *ptr, ftnlen len) +{ struct syl *p; + int n,i; + for(i=0;i<*number;i++,ptr+=len) + { +loop: switch(type_f((p= &f__syl[f__pc])->op)) + { + default: + fprintf(stderr,"unknown code in do_fio: %d\n%s\n", + p->op,f__fmtbuf); + err(f__elist->cierr,100,"do_fio"); + case NED: + if((*f__doned)(p)) + { f__pc++; + goto loop; + } + f__pc++; + continue; + case ED: + if(f__cnt[f__cp]<=0) + { f__cp--; + f__pc++; + goto loop; + } + if(ptr==NULL) + return((*f__doend)()); + f__cnt[f__cp]--; + f__workdone=1; + if((n=(*f__doed)(p,ptr,len))>0) + errfl(f__elist->cierr,errno,"fmt"); + if(n<0) + err(f__elist->ciend,(EOF),"fmt"); + continue; + case STACK: + f__cnt[++f__cp]=p->p1; + f__pc++; + goto loop; + case RET1: + f__ret[++f__rp]=p->p1; + f__pc++; + goto loop; + case GOTO: + if(--f__cnt[f__cp]<=0) + { f__cp--; + f__rp--; + f__pc++; + goto loop; + } + f__pc=1+f__ret[f__rp--]; + goto loop; + case REVERT: + f__rp=f__cp=0; + f__pc = p->p1; + if(ptr==NULL) + return((*f__doend)()); + if(!f__workdone) return(0); + if((n=(*f__dorevert)()) != 0) return(n); + goto loop; + case COLON: + if(ptr==NULL) + return((*f__doend)()); + f__pc++; + goto loop; + case NONL: + f__nonl = 1; + f__pc++; + goto loop; + case S: + case SS: + f__cplus=0; + f__pc++; + goto loop; + case SP: + f__cplus = 1; + f__pc++; + goto loop; + case P: f__scale=p->p1; + f__pc++; + goto loop; + case BN: + f__cblank=0; + f__pc++; + goto loop; + case BZ: + f__cblank=1; + f__pc++; + goto loop; + } + } + return(0); +} + +int en_fio(Void) +{ ftnint one=1; + return(do_fio(&one,(char *)NULL,(ftnint)0)); +} + + VOID +fmt_bg(Void) +{ + f__workdone=f__cp=f__rp=f__pc=f__cursor=0; + f__cnt[0]=f__ret[0]=0; +} diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/fmt.h b/src/imageplugins/coreplugin/sharpnesseditor/clapack/fmt.h new file mode 100644 index 00000000..b46bc9c5 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/fmt.h @@ -0,0 +1,86 @@ +struct syl +{ int op; + int p1; + union { int i[2]; char *s;} p2; + }; +#define RET1 1 +#define REVERT 2 +#define GOTO 3 +#define X 4 +#define SLASH 5 +#define STACK 6 +#define I 7 +#define ED 8 +#define NED 9 +#define IM 10 +#define APOS 11 +#define H 12 +#define TL 13 +#define TR 14 +#define T 15 +#define COLON 16 +#define S 17 +#define SP 18 +#define SS 19 +#define P 20 +#define BN 21 +#define BZ 22 +#define F 23 +#define E 24 +#define EE 25 +#define D 26 +#define G 27 +#define GE 28 +#define L 29 +#define A 30 +#define AW 31 +#define O 32 +#define NONL 33 +#define OM 34 +#define Z 35 +#define ZM 36 +extern int f__pc,f__parenlvl,f__revloc; +typedef union +{ real pf; + doublereal pd; +} ufloat; +typedef union +{ short is; + signed char ic; + integer il; +#ifdef Allow_TYQUAD + longint ili; +#endif +} Uint; +#ifdef __cplusplus +extern "C" { +#endif +extern int (*f__doed)(struct syl*, char*, ftnlen),(*f__doned)(struct syl*); +extern int (*f__dorevert)(void); +extern void fmt_bg(void); +extern int pars_f(char*); +extern int rd_ed(struct syl*, char*, ftnlen),rd_ned(struct syl*); +extern int w_ed(struct syl*, char*, ftnlen),w_ned(struct syl*); +extern int wrt_E(ufloat*, int, int, int, ftnlen); +extern int wrt_F(ufloat*, int, int, ftnlen); +extern int wrt_L(Uint*, int, ftnlen); +#ifdef __cplusplus + } +#endif +extern flag f__cblank,f__cplus,f__workdone, f__nonl; +extern char *f__fmtbuf; +extern int f__scale; +#define GET(x) if((x=(*f__getn)())<0) return(x) +#define VAL(x) (x!='\n'?x:' ') +#define PUT(x) (*f__putn)(x) +extern int f__cursor; + +#undef TYQUAD +#ifndef Allow_TYQUAD +#undef longint +#define longint long +#else +#define TYQUAD 14 +#endif + +extern char *f__icvt(longint, int*, int*, int); diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/fmtlib.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/fmtlib.c new file mode 100644 index 00000000..8343337b --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/fmtlib.c @@ -0,0 +1,40 @@ +/* @(#)fmtlib.c 1.2 */ +#define MAXINTLENGTH 23 + +#include "f2c.h" +#ifndef Allow_TYQUAD +#undef longint +#define longint long +#undef ulongint +#define ulongint unsigned long +#endif + +char *f__icvt(longint value, int *ndigit, int *sign, int base) +{ + static char buf[MAXINTLENGTH+1]; + int i; + ulongint uvalue; + + if(value > 0) { + uvalue = value; + *sign = 0; + } + else if (value < 0) { + uvalue = -value; + *sign = 1; + } + else { + *sign = 0; + *ndigit = 1; + buf[MAXINTLENGTH-1] = '0'; + return &buf[MAXINTLENGTH-1]; + } + i = MAXINTLENGTH; + do { + buf[--i] = (uvalue%base) + '0'; + uvalue /= base; + } + while(uvalue > 0); + *ndigit = MAXINTLENGTH - i; + return &buf[i]; + } diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/fp.h b/src/imageplugins/coreplugin/sharpnesseditor/clapack/fp.h new file mode 100644 index 00000000..40743d79 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/fp.h @@ -0,0 +1,28 @@ +#define FMAX 40 +#define EXPMAXDIGS 8 +#define EXPMAX 99999999 +/* FMAX = max number of nonzero digits passed to atof() */ +/* EXPMAX = 10^EXPMAXDIGS - 1 = largest allowed exponent absolute value */ + +#ifdef V10 /* Research Tenth-Edition Unix */ +#include "local.h" +#endif + +/* MAXFRACDIGS and MAXINTDIGS are for wrt_F -- bounds (not necessarily + tight) on the maximum number of digits to the right and left of + * the decimal point. + */ + +#ifdef VAX +#define MAXFRACDIGS 56 +#define MAXINTDIGS 38 +#else +#ifdef CRAY +#define MAXFRACDIGS 9880 +#define MAXINTDIGS 9864 +#else +/* values that suffice for IEEE double */ +#define MAXFRACDIGS 344 +#define MAXINTDIGS 308 +#endif +#endif diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/idamax.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/idamax.c new file mode 100644 index 00000000..2cc54813 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/idamax.c @@ -0,0 +1,61 @@ +#include "blaswrap.h" +#include "f2c.h" + +integer idamax_(integer *n, doublereal *dx, integer *incx) +{ + /* System generated locals */ + integer ret_val, i__1; + doublereal d__1; + /* Local variables */ + static doublereal dmax__; + static integer i__, ix; +/* finds the index of element having max. absolute value. + jack dongarra, linpack, 3/11/78. + modified 3/93 to return if incx .le. 0. + modified 12/3/93, array(1) declarations changed to array(*) + Parameter adjustments */ + --dx; + /* Function Body */ + ret_val = 0; + if (*n < 1 || *incx <= 0) { + return ret_val; + } + ret_val = 1; + if (*n == 1) { + return ret_val; + } + if (*incx == 1) { + goto L20; + } +/* code for increment not equal to 1 */ + ix = 1; + dmax__ = abs(dx[1]); + ix += *incx; + i__1 = *n; + for (i__ = 2; i__ <= i__1; ++i__) { + if ((d__1 = dx[ix], abs(d__1)) <= dmax__) { + goto L5; + } + ret_val = i__; + dmax__ = (d__1 = dx[ix], abs(d__1)); +L5: + ix += *incx; +/* L10: */ + } + return ret_val; +/* code for increment equal to 1 */ +L20: + dmax__ = abs(dx[1]); + i__1 = *n; + for (i__ = 2; i__ <= i__1; ++i__) { + if ((d__1 = dx[i__], abs(d__1)) <= dmax__) { + goto L30; + } + ret_val = i__; + dmax__ = (d__1 = dx[i__], abs(d__1)); +L30: + ; + } + return ret_val; +} /* idamax_ */ + diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/ieeeck.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/ieeeck.c new file mode 100644 index 00000000..39256a48 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/ieeeck.c @@ -0,0 +1,150 @@ +#include "blaswrap.h" +#include "f2c.h" + +integer ieeeck_(integer *ispec, real *zero, real *one) +{ +/* -- LAPACK auxiliary routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + June 30, 1998 + + + Purpose + ======= + + IEEECK is called from the ILAENV to verify that Infinity and + possibly NaN arithmetic is safe (i.e. will not trap). + + Arguments + ========= + + ISPEC (input) INTEGER + Specifies whether to test just for inifinity arithmetic + or whether to test for infinity and NaN arithmetic. + = 0: Verify infinity arithmetic only. + = 1: Verify infinity and NaN arithmetic. + + ZERO (input) REAL + Must contain the value 0.0 + This is passed to prevent the compiler from optimizing + away this code. + + ONE (input) REAL + Must contain the value 1.0 + This is passed to prevent the compiler from optimizing + away this code. + + RETURN VALUE: INTEGER + = 0: Arithmetic failed to produce the correct answers + = 1: Arithmetic produced the correct answers */ + /* System generated locals */ + integer ret_val; + /* Local variables */ + static real neginf, posinf, negzro, newzro, nan1, nan2, nan3, nan4, nan5, + nan6; + + + ret_val = 1; + + posinf = *one / *zero; + if (posinf <= *one) { + ret_val = 0; + return ret_val; + } + + neginf = -(*one) / *zero; + if (neginf >= *zero) { + ret_val = 0; + return ret_val; + } + + negzro = *one / (neginf + *one); + if (negzro != *zero) { + ret_val = 0; + return ret_val; + } + + neginf = *one / negzro; + if (neginf >= *zero) { + ret_val = 0; + return ret_val; + } + + newzro = negzro + *zero; + if (newzro != *zero) { + ret_val = 0; + return ret_val; + } + + posinf = *one / newzro; + if (posinf <= *one) { + ret_val = 0; + return ret_val; + } + + neginf *= posinf; + if (neginf >= *zero) { + ret_val = 0; + return ret_val; + } + + posinf *= posinf; + if (posinf <= *one) { + ret_val = 0; + return ret_val; + } + + + + +/* Return if we were only asked to check infinity arithmetic */ + + if (*ispec == 0) { + return ret_val; + } + + nan1 = posinf + neginf; + + nan2 = posinf / neginf; + + nan3 = posinf / posinf; + + nan4 = posinf * *zero; + + nan5 = neginf * negzro; + + nan6 = nan5 * 0.f; + + if (nan1 == nan1) { + ret_val = 0; + return ret_val; + } + + if (nan2 == nan2) { + ret_val = 0; + return ret_val; + } + + if (nan3 == nan3) { + ret_val = 0; + return ret_val; + } + + if (nan4 == nan4) { + ret_val = 0; + return ret_val; + } + + if (nan5 == nan5) { + ret_val = 0; + return ret_val; + } + + if (nan6 == nan6) { + ret_val = 0; + return ret_val; + } + + return ret_val; +} /* ieeeck_ */ + diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/ilaenv.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/ilaenv.c new file mode 100644 index 00000000..58299fff --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/ilaenv.c @@ -0,0 +1,610 @@ +#include "blaswrap.h" +#include "f2c.h" + +integer ilaenv_(integer *ispec, char *name__, char *opts, integer *n1, + integer *n2, integer *n3, integer *n4, ftnlen name_len, ftnlen + opts_len) +{ +/* -- LAPACK auxiliary routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + June 30, 1999 + + + Purpose + ======= + + ILAENV is called from the LAPACK routines to choose problem-dependent + parameters for the local environment. See ISPEC for a description of + the parameters. + + This version provides a set of parameters which should give good, + but not optimal, performance on many of the currently available + computers. Users are encouraged to modify this subroutine to set + the tuning parameters for their particular machine using the option + and problem size information in the arguments. + + This routine will not function correctly if it is converted to all + lower case. Converting it to all upper case is allowed. + + Arguments + ========= + + ISPEC (input) INTEGER + Specifies the parameter to be returned as the value of + ILAENV. + = 1: the optimal blocksize; if this value is 1, an unblocked + algorithm will give the best performance. + = 2: the minimum block size for which the block routine + should be used; if the usable block size is less than + this value, an unblocked routine should be used. + = 3: the crossover point (in a block routine, for N less + than this value, an unblocked routine should be used) + = 4: the number of shifts, used in the nonsymmetric + eigenvalue routines + = 5: the minimum column dimension for blocking to be used; + rectangular blocks must have dimension at least k by m, + where k is given by ILAENV(2,...) and m by ILAENV(5,...) + = 6: the crossover point for the SVD (when reducing an m by n + matrix to bidiagonal form, if max(m,n)/min(m,n) exceeds + this value, a QR factorization is used first to reduce + the matrix to a triangular form.) + = 7: the number of processors + = 8: the crossover point for the multishift QR and QZ methods + for nonsymmetric eigenvalue problems. + = 9: maximum size of the subproblems at the bottom of the + computation tree in the divide-and-conquer algorithm + (used by xGELSD and xGESDD) + =10: ieee NaN arithmetic can be trusted not to trap + =11: infinity arithmetic can be trusted not to trap + + NAME (input) CHARACTER*(*) + The name of the calling subroutine, in either upper case or + lower case. + + OPTS (input) CHARACTER*(*) + The character options to the subroutine NAME, concatenated + into a single character string. For example, UPLO = 'U', + TRANS = 'T', and DIAG = 'N' for a triangular routine would + be specified as OPTS = 'UTN'. + + N1 (input) INTEGER + N2 (input) INTEGER + N3 (input) INTEGER + N4 (input) INTEGER + Problem dimensions for the subroutine NAME; these may not all + be required. + + (ILAENV) (output) INTEGER + >= 0: the value of the parameter specified by ISPEC + < 0: if ILAENV = -k, the k-th argument had an illegal value. + + Further Details + =============== + + The following conventions have been used when calling ILAENV from the + LAPACK routines: + 1) OPTS is a concatenation of all of the character options to + subroutine NAME, in the same order that they appear in the + argument list for NAME, even if they are not used in determining + the value of the parameter specified by ISPEC. + 2) The problem dimensions N1, N2, N3, N4 are specified in the order + that they appear in the argument list for NAME. N1 is used + first, N2 second, and so on, and unused problem dimensions are + passed a value of -1. + 3) The parameter value returned by ILAENV is checked for validity in + the calling subroutine. For example, ILAENV is used to retrieve + the optimal blocksize for STRTRI as follows: + + NB = ILAENV( 1, 'STRTRI', UPLO // DIAG, N, -1, -1, -1 ) + IF( NB.LE.1 ) NB = MAX( 1, N ) + + ===================================================================== */ + /* Table of constant values */ + static integer c__0 = 0; + static real c_b162 = 0.f; + static real c_b163 = 1.f; + static integer c__1 = 1; + + /* System generated locals */ + integer ret_val; + /* Builtin functions + Subroutine */ int s_copy(char *, char *, ftnlen, ftnlen); + integer s_cmp(char *, char *, ftnlen, ftnlen); + /* Local variables */ + static integer i__; + static logical cname, sname; + static integer nbmin; + static char c1[1], c2[2], c3[3], c4[2]; + static integer ic, nb; + extern integer ieeeck_(integer *, real *, real *); + static integer iz, nx; + static char subnam[6]; + + + + + switch (*ispec) { + case 1: goto L100; + case 2: goto L100; + case 3: goto L100; + case 4: goto L400; + case 5: goto L500; + case 6: goto L600; + case 7: goto L700; + case 8: goto L800; + case 9: goto L900; + case 10: goto L1000; + case 11: goto L1100; + } + +/* Invalid value for ISPEC */ + + ret_val = -1; + return ret_val; + +L100: + +/* Convert NAME to upper case if the first character is lower case. */ + + ret_val = 1; + s_copy(subnam, name__, (ftnlen)6, name_len); + ic = *(unsigned char *)subnam; + iz = 'Z'; + if (iz == 90 || iz == 122) { + +/* ASCII character set */ + + if (ic >= 97 && ic <= 122) { + *(unsigned char *)subnam = (char) (ic - 32); + for (i__ = 2; i__ <= 6; ++i__) { + ic = *(unsigned char *)&subnam[i__ - 1]; + if (ic >= 97 && ic <= 122) { + *(unsigned char *)&subnam[i__ - 1] = (char) (ic - 32); + } +/* L10: */ + } + } + + } else if (iz == 233 || iz == 169) { + +/* EBCDIC character set */ + + if (ic >= 129 && ic <= 137 || ic >= 145 && ic <= 153 || ic >= 162 && + ic <= 169) { + *(unsigned char *)subnam = (char) (ic + 64); + for (i__ = 2; i__ <= 6; ++i__) { + ic = *(unsigned char *)&subnam[i__ - 1]; + if (ic >= 129 && ic <= 137 || ic >= 145 && ic <= 153 || ic >= + 162 && ic <= 169) { + *(unsigned char *)&subnam[i__ - 1] = (char) (ic + 64); + } +/* L20: */ + } + } + + } else if (iz == 218 || iz == 250) { + +/* Prime machines: ASCII+128 */ + + if (ic >= 225 && ic <= 250) { + *(unsigned char *)subnam = (char) (ic - 32); + for (i__ = 2; i__ <= 6; ++i__) { + ic = *(unsigned char *)&subnam[i__ - 1]; + if (ic >= 225 && ic <= 250) { + *(unsigned char *)&subnam[i__ - 1] = (char) (ic - 32); + } +/* L30: */ + } + } + } + + *(unsigned char *)c1 = *(unsigned char *)subnam; + sname = *(unsigned char *)c1 == 'S' || *(unsigned char *)c1 == 'D'; + cname = *(unsigned char *)c1 == 'C' || *(unsigned char *)c1 == 'Z'; + if (! (cname || sname)) { + return ret_val; + } + s_copy(c2, subnam + 1, (ftnlen)2, (ftnlen)2); + s_copy(c3, subnam + 3, (ftnlen)3, (ftnlen)3); + s_copy(c4, c3 + 1, (ftnlen)2, (ftnlen)2); + + switch (*ispec) { + case 1: goto L110; + case 2: goto L200; + case 3: goto L300; + } + +L110: + +/* ISPEC = 1: block size + + In these examples, separate code is provided for setting NB for + real and complex. We assume that NB will take the same value in + single or double precision. */ + + nb = 1; + + if (s_cmp(c2, "GE", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nb = 64; + } else { + nb = 64; + } + } else if (s_cmp(c3, "QRF", (ftnlen)3, (ftnlen)3) == 0 || s_cmp(c3, + "RQF", (ftnlen)3, (ftnlen)3) == 0 || s_cmp(c3, "LQF", (ftnlen) + 3, (ftnlen)3) == 0 || s_cmp(c3, "QLF", (ftnlen)3, (ftnlen)3) + == 0) { + if (sname) { + nb = 32; + } else { + nb = 32; + } + } else if (s_cmp(c3, "HRD", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nb = 32; + } else { + nb = 32; + } + } else if (s_cmp(c3, "BRD", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nb = 32; + } else { + nb = 32; + } + } else if (s_cmp(c3, "TRI", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nb = 64; + } else { + nb = 64; + } + } + } else if (s_cmp(c2, "PO", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nb = 64; + } else { + nb = 64; + } + } + } else if (s_cmp(c2, "SY", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nb = 64; + } else { + nb = 64; + } + } else if (sname && s_cmp(c3, "TRD", (ftnlen)3, (ftnlen)3) == 0) { + nb = 32; + } else if (sname && s_cmp(c3, "GST", (ftnlen)3, (ftnlen)3) == 0) { + nb = 64; + } + } else if (cname && s_cmp(c2, "HE", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) { + nb = 64; + } else if (s_cmp(c3, "TRD", (ftnlen)3, (ftnlen)3) == 0) { + nb = 32; + } else if (s_cmp(c3, "GST", (ftnlen)3, (ftnlen)3) == 0) { + nb = 64; + } + } else if (sname && s_cmp(c2, "OR", (ftnlen)2, (ftnlen)2) == 0) { + if (*(unsigned char *)c3 == 'G') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nb = 32; + } + } else if (*(unsigned char *)c3 == 'M') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nb = 32; + } + } + } else if (cname && s_cmp(c2, "UN", (ftnlen)2, (ftnlen)2) == 0) { + if (*(unsigned char *)c3 == 'G') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nb = 32; + } + } else if (*(unsigned char *)c3 == 'M') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nb = 32; + } + } + } else if (s_cmp(c2, "GB", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + if (*n4 <= 64) { + nb = 1; + } else { + nb = 32; + } + } else { + if (*n4 <= 64) { + nb = 1; + } else { + nb = 32; + } + } + } + } else if (s_cmp(c2, "PB", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + if (*n2 <= 64) { + nb = 1; + } else { + nb = 32; + } + } else { + if (*n2 <= 64) { + nb = 1; + } else { + nb = 32; + } + } + } + } else if (s_cmp(c2, "TR", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRI", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nb = 64; + } else { + nb = 64; + } + } + } else if (s_cmp(c2, "LA", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "UUM", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nb = 64; + } else { + nb = 64; + } + } + } else if (sname && s_cmp(c2, "ST", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "EBZ", (ftnlen)3, (ftnlen)3) == 0) { + nb = 1; + } + } + ret_val = nb; + return ret_val; + +L200: + +/* ISPEC = 2: minimum block size */ + + nbmin = 2; + if (s_cmp(c2, "GE", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "QRF", (ftnlen)3, (ftnlen)3) == 0 || s_cmp(c3, "RQF", ( + ftnlen)3, (ftnlen)3) == 0 || s_cmp(c3, "LQF", (ftnlen)3, ( + ftnlen)3) == 0 || s_cmp(c3, "QLF", (ftnlen)3, (ftnlen)3) == 0) + { + if (sname) { + nbmin = 2; + } else { + nbmin = 2; + } + } else if (s_cmp(c3, "HRD", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nbmin = 2; + } else { + nbmin = 2; + } + } else if (s_cmp(c3, "BRD", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nbmin = 2; + } else { + nbmin = 2; + } + } else if (s_cmp(c3, "TRI", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nbmin = 2; + } else { + nbmin = 2; + } + } + } else if (s_cmp(c2, "SY", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nbmin = 8; + } else { + nbmin = 8; + } + } else if (sname && s_cmp(c3, "TRD", (ftnlen)3, (ftnlen)3) == 0) { + nbmin = 2; + } + } else if (cname && s_cmp(c2, "HE", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRD", (ftnlen)3, (ftnlen)3) == 0) { + nbmin = 2; + } + } else if (sname && s_cmp(c2, "OR", (ftnlen)2, (ftnlen)2) == 0) { + if (*(unsigned char *)c3 == 'G') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nbmin = 2; + } + } else if (*(unsigned char *)c3 == 'M') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nbmin = 2; + } + } + } else if (cname && s_cmp(c2, "UN", (ftnlen)2, (ftnlen)2) == 0) { + if (*(unsigned char *)c3 == 'G') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nbmin = 2; + } + } else if (*(unsigned char *)c3 == 'M') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nbmin = 2; + } + } + } + ret_val = nbmin; + return ret_val; + +L300: + +/* ISPEC = 3: crossover point */ + + nx = 0; + if (s_cmp(c2, "GE", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "QRF", (ftnlen)3, (ftnlen)3) == 0 || s_cmp(c3, "RQF", ( + ftnlen)3, (ftnlen)3) == 0 || s_cmp(c3, "LQF", (ftnlen)3, ( + ftnlen)3) == 0 || s_cmp(c3, "QLF", (ftnlen)3, (ftnlen)3) == 0) + { + if (sname) { + nx = 128; + } else { + nx = 128; + } + } else if (s_cmp(c3, "HRD", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nx = 128; + } else { + nx = 128; + } + } else if (s_cmp(c3, "BRD", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nx = 128; + } else { + nx = 128; + } + } + } else if (s_cmp(c2, "SY", (ftnlen)2, (ftnlen)2) == 0) { + if (sname && s_cmp(c3, "TRD", (ftnlen)3, (ftnlen)3) == 0) { + nx = 32; + } + } else if (cname && s_cmp(c2, "HE", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRD", (ftnlen)3, (ftnlen)3) == 0) { + nx = 32; + } + } else if (sname && s_cmp(c2, "OR", (ftnlen)2, (ftnlen)2) == 0) { + if (*(unsigned char *)c3 == 'G') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nx = 128; + } + } + } else if (cname && s_cmp(c2, "UN", (ftnlen)2, (ftnlen)2) == 0) { + if (*(unsigned char *)c3 == 'G') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nx = 128; + } + } + } + ret_val = nx; + return ret_val; + +L400: + +/* ISPEC = 4: number of shifts (used by xHSEQR) */ + + ret_val = 6; + return ret_val; + +L500: + +/* ISPEC = 5: minimum column dimension (not used) */ + + ret_val = 2; + return ret_val; + +L600: + +/* ISPEC = 6: crossover point for SVD (used by xGELSS and xGESVD) */ + + ret_val = (integer) ((real) min(*n1,*n2) * 1.6f); + return ret_val; + +L700: + +/* ISPEC = 7: number of processors (not used) */ + + ret_val = 1; + return ret_val; + +L800: + +/* ISPEC = 8: crossover point for multishift (used by xHSEQR) */ + + ret_val = 50; + return ret_val; + +L900: + +/* ISPEC = 9: maximum size of the subproblems at the bottom of the + computation tree in the divide-and-conquer algorithm + (used by xGELSD and xGESDD) */ + + ret_val = 25; + return ret_val; + +L1000: + +/* ISPEC = 10: ieee NaN arithmetic can be trusted not to trap + + ILAENV = 0 */ + ret_val = 1; + if (ret_val == 1) { + ret_val = ieeeck_(&c__0, &c_b162, &c_b163); + } + return ret_val; + +L1100: + +/* ISPEC = 11: infinity arithmetic can be trusted not to trap + + ILAENV = 0 */ + ret_val = 1; + if (ret_val == 1) { + ret_val = ieeeck_(&c__1, &c_b162, &c_b163); + } + return ret_val; + +/* End of ILAENV */ + +} /* ilaenv_ */ + diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/lsame.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/lsame.c new file mode 100644 index 00000000..d9baaa3f --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/lsame.c @@ -0,0 +1,101 @@ +#include "f2c.h" + +logical lsame_(char *ca, char *cb) +{ +/* -- LAPACK auxiliary routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994 + + + Purpose + ======= + + LSAME returns .TRUE. if CA is the same letter as CB regardless of + case. + + Arguments + ========= + + CA (input) CHARACTER*1 + CB (input) CHARACTER*1 + CA and CB specify the single characters to be compared. + + ===================================================================== + + + + Test if the characters are equal */ + /* System generated locals */ + logical ret_val; + /* Local variables */ + static integer inta, intb, zcode; + + + ret_val = *(unsigned char *)ca == *(unsigned char *)cb; + if (ret_val) { + return ret_val; + } + +/* Now test for equivalence if both characters are alphabetic. */ + + zcode = 'Z'; + +/* Use 'Z' rather than 'A' so that ASCII can be detected on Prime + machines, on which ICHAR returns a value with bit 8 set. + ICHAR('A') on Prime machines returns 193 which is the same as + ICHAR('A') on an EBCDIC machine. */ + + inta = *(unsigned char *)ca; + intb = *(unsigned char *)cb; + + if (zcode == 90 || zcode == 122) { + +/* ASCII is assumed - ZCODE is the ASCII code of either lower o +r + upper case 'Z'. */ + + if (inta >= 97 && inta <= 122) { + inta += -32; + } + if (intb >= 97 && intb <= 122) { + intb += -32; + } + + } else if (zcode == 233 || zcode == 169) { + +/* EBCDIC is assumed - ZCODE is the EBCDIC code of either lower + or + upper case 'Z'. */ + + if (inta >= 129 && inta <= 137 || inta >= 145 && inta <= 153 || inta + >= 162 && inta <= 169) { + inta += 64; + } + if (intb >= 129 && intb <= 137 || intb >= 145 && intb <= 153 || intb + >= 162 && intb <= 169) { + intb += 64; + } + + } else if (zcode == 218 || zcode == 250) { + +/* ASCII is assumed, on Prime machines - ZCODE is the ASCII cod +e + plus 128 of either lower or upper case 'Z'. */ + + if (inta >= 225 && inta <= 250) { + inta += -32; + } + if (intb >= 225 && intb <= 250) { + intb += -32; + } + } + ret_val = inta == intb; + +/* RETURN + + End of LSAME */ + + return ret_val; +} /* lsame_ */ + diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/open.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/open.c new file mode 100644 index 00000000..e7810757 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/open.c @@ -0,0 +1,256 @@ +#include "f2c.h" +#include "fio.h" +#include "string.h" +#ifndef NON_POSIX_STDIO +#ifdef MSDOS +#include "io.h" +#else +#include "unistd.h" /* for access */ +#endif +#endif + +#undef abs +#undef min +#undef max +#include "stdlib.h" +extern int f__canseek(FILE*); +extern integer f_clos(cllist*); + +#ifdef NON_ANSI_RW_MODES +char *f__r_mode[2] = {"r", "r"}; +char *f__w_mode[4] = {"w", "w", "r+w", "r+w"}; +#else +char *f__r_mode[2] = {"rb", "r"}; +char *f__w_mode[4] = {"wb", "w", "r+b", "r+"}; +#endif + +static char f__buf0[400], *f__buf = f__buf0; +int f__buflen = (int)sizeof(f__buf0); + +static void f__bufadj(int n, int c) +{ + unsigned int len; + char *nbuf, *s, *t, *te; + + if (f__buf == f__buf0) + f__buflen = 1024; + while(f__buflen <= n) + f__buflen <<= 1; + len = (unsigned int)f__buflen; + if (len != f__buflen || !(nbuf = (char*)malloc(len))) + f__fatal(113, "malloc failure"); + s = nbuf; + t = f__buf; + te = t + c; + while(t < te) + *s++ = *t++; + if (f__buf != f__buf0) + free(f__buf); + f__buf = nbuf; + } + +int f__putbuf(int c) +{ + char *s, *se; + int n; + + if (f__hiwater > f__recpos) + f__recpos = f__hiwater; + n = f__recpos + 1; + if (n >= f__buflen) + f__bufadj(n, f__recpos); + s = f__buf; + se = s + f__recpos; + if (c) + *se++ = c; + *se = 0; + for(;;) { + fputs(s, f__cf); + s += strlen(s); + if (s >= se) + break; /* normally happens the first time */ + putc(*s++, f__cf); + } + return 0; + } + +void x_putc(int c) +{ + if (f__recpos >= f__buflen) + f__bufadj(f__recpos, f__buflen); + f__buf[f__recpos++] = c; + } + +#define opnerr(f,m,s) {if(f) errno= m; else opn_err(m,s,a); return(m);} + +static void opn_err(int m, char *s, olist *a) +{ + if (a->ofnm) { + /* supply file name to error message */ + if (a->ofnmlen >= f__buflen) + f__bufadj((int)a->ofnmlen, 0); + g_char(a->ofnm, a->ofnmlen, f__curunit->ufnm = f__buf); + } + f__fatal(m, s); + } + +integer f_open(olist *a) +{ unit *b; + integer rv; + char buf[256], *s; + cllist x; + int ufmt; + FILE *tf; +#ifndef NON_UNIX_STDIO + int n; +#endif + f__external = 1; + if(a->ounit>=MXUNIT || a->ounit<0) + err(a->oerr,101,"open") + if (!f__init) + f_init(); + f__curunit = b = &f__units[a->ounit]; + if(b->ufd) { + if(a->ofnm==0) + { + same: if (a->oblnk) + b->ublnk = *a->oblnk == 'z' || *a->oblnk == 'Z'; + return(0); + } +#ifdef NON_UNIX_STDIO + if (b->ufnm + && strlen(b->ufnm) == a->ofnmlen + && !strncmp(b->ufnm, a->ofnm, (unsigned)a->ofnmlen)) + goto same; +#else + g_char(a->ofnm,a->ofnmlen,buf); + if (f__inode(buf,&n) == b->uinode && n == b->udev) + goto same; +#endif + x.cunit=a->ounit; + x.csta=0; + x.cerr=a->oerr; + if ((rv = f_clos(&x)) != 0) + return rv; + } + b->url = (int)a->orl; + b->ublnk = a->oblnk && (*a->oblnk == 'z' || *a->oblnk == 'Z'); + if(a->ofm==0) + { if(b->url>0) b->ufmt=0; + else b->ufmt=1; + } + else if(*a->ofm=='f' || *a->ofm == 'F') b->ufmt=1; + else b->ufmt=0; + ufmt = b->ufmt; +#ifdef url_Adjust + if (b->url && !ufmt) + url_Adjust(b->url); +#endif + if (a->ofnm) { + g_char(a->ofnm,a->ofnmlen,buf); + if (!buf[0]) + opnerr(a->oerr,107,"open") + } + else + sprintf(buf, "fort.%ld", (long)a->ounit); + b->uscrtch = 0; + b->uend=0; + b->uwrt = 0; + b->ufd = 0; + b->urw = 3; + switch(a->osta ? *a->osta : 'u') + { + case 'o': + case 'O': +#ifdef NON_POSIX_STDIO + if (!(tf = fopen(buf,"r"))) + opnerr(a->oerr,errno,"open") + fclose(tf); +#else + if (access(buf,0)) + opnerr(a->oerr,errno,"open") +#endif + break; + case 's': + case 'S': + b->uscrtch=1; +#ifdef NON_ANSI_STDIO + (void) strcpy(buf,"tmp.FXXXXXX"); + (void) mktemp(buf); + goto replace; +#else + if (!(b->ufd = tmpfile())) + opnerr(a->oerr,errno,"open") + b->ufnm = 0; +#ifndef NON_UNIX_STDIO + b->uinode = b->udev = -1; +#endif + b->useek = 1; + return 0; +#endif + + case 'n': + case 'N': +#ifdef NON_POSIX_STDIO + if ((tf = fopen(buf,"r")) || (tf = fopen(buf,"a"))) { + fclose(tf); + opnerr(a->oerr,128,"open") + } +#else + if (!access(buf,0)) + opnerr(a->oerr,128,"open") +#endif + /* no break */ + case 'r': /* Fortran 90 replace option */ + case 'R': +#ifdef NON_ANSI_STDIO + replace: +#endif + if (tf = fopen(buf,f__w_mode[0])) + fclose(tf); + } + + b->ufnm=(char *) malloc((unsigned int)(strlen(buf)+1)); + if(b->ufnm==NULL) opnerr(a->oerr,113,"no space"); + (void) strcpy(b->ufnm,buf); + if ((s = a->oacc) && b->url) + ufmt = 0; + if(!(tf = fopen(buf, f__w_mode[ufmt|2]))) { + if (tf = fopen(buf, f__r_mode[ufmt])) + b->urw = 1; + else if (tf = fopen(buf, f__w_mode[ufmt])) { + b->uwrt = 1; + b->urw = 2; + } + else + err(a->oerr, errno, "open"); + } + b->useek = f__canseek(b->ufd = tf); +#ifndef NON_UNIX_STDIO + if((b->uinode = f__inode(buf,&b->udev)) == -1) + opnerr(a->oerr,108,"open") +#endif + if(b->useek) + if (a->orl) + rewind(b->ufd); + else if ((s = a->oacc) && (*s == 'a' || *s == 'A') + && fseek(b->ufd, 0L, SEEK_END)) + opnerr(a->oerr,129,"open"); + return(0); +} + +int fk_open(int seq, int fmt, ftnint n) +{ char nbuf[10]; + olist a; + (void) sprintf(nbuf,"fort.%ld",(long)n); + a.oerr=1; + a.ounit=n; + a.ofnm=nbuf; + a.ofnmlen=strlen(nbuf); + a.osta=NULL; + a.oacc= seq==SEQ?"s":"d"; + a.ofm = fmt==FMT?"f":"u"; + a.orl = seq==DIR?1:0; + a.oblnk=NULL; + return(f_open(&a)); +} diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/s_cmp.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/s_cmp.c new file mode 100644 index 00000000..cd6a7dc4 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/s_cmp.c @@ -0,0 +1,40 @@ +#include "f2c.h" + +/* compare two strings */ + +integer s_cmp(char *a0, char *b0, ftnlen la, ftnlen lb) +{ +unsigned char *a, *aend, *b, *bend; +a = (unsigned char *)a0; +b = (unsigned char *)b0; +aend = a + la; +bend = b + lb; + +if(la <= lb) + { + while(a < aend) + if(*a != *b) + return( *a - *b ); + else + { ++a; ++b; } + + while(b < bend) + if(*b != ' ') + return( ' ' - *b ); + else ++b; + } + +else + { + while(b < bend) + if(*a == *b) + { ++a; ++b; } + else + return( *a - *b ); + while(a < aend) + if(*a != ' ') + return(*a - ' '); + else ++a; + } +return(0); +} diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/s_copy.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/s_copy.c new file mode 100644 index 00000000..289c67dd --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/s_copy.c @@ -0,0 +1,47 @@ +/* Unless compiled with -DNO_OVERWRITE, this variant of s_copy allows the + * target of an assignment to appear on its right-hand side (contrary + * to the Fortran 77 Standard, but in accordance with Fortran 90), + * as in a(2:5) = a(4:7) . + */ + +#include "f2c.h" + +/* assign strings: a = b */ + +void s_copy(char *a, char *b, ftnlen la, ftnlen lb) +{ + char *aend, *bend; + + aend = a + la; + + if(la <= lb) +#ifndef NO_OVERWRITE + if (a <= b || a >= b + la) +#endif + while(a < aend) + *a++ = *b++; +#ifndef NO_OVERWRITE + else + for(b += la; a < aend; ) + *--aend = *--b; +#endif + + else { + bend = b + lb; +#ifndef NO_OVERWRITE + if (a <= b || a >= bend) +#endif + while(b < bend) + *a++ = *b++; +#ifndef NO_OVERWRITE + else { + a += lb; + while(b < bend) + *--a = *--bend; + a += lb; + } +#endif + while(a < aend) + *a++ = ' '; + } + } diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/s_stop.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/s_stop.c new file mode 100644 index 00000000..049f71b6 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/s_stop.c @@ -0,0 +1,37 @@ +#include "stdio.h" +#include "f2c.h" + +#undef abs +#undef min +#undef max +#include "stdlib.h" +#ifdef __cplusplus +extern "C" { +#endif +void f_exit(void); + +int s_stop(char *s, ftnlen n) +{ +int i; + +if(n > 0) + { + fprintf(stderr, "STOP "); + for(i = 0; i<n ; ++i) + putc(*s++, stderr); + fprintf(stderr, " statement executed\n"); + } +#ifdef NO_ONEXIT +f_exit(); +#endif +exit(0); + +/* We cannot avoid (useless) compiler diagnostics here: */ +/* some compilers complain if there is no return statement, */ +/* and others complain that this one cannot be reached. */ + +return 0; /* NOT REACHED */ +} +#ifdef __cplusplus +} +#endif diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/sfe.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/sfe.c new file mode 100644 index 00000000..4f8907ea --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/sfe.c @@ -0,0 +1,29 @@ +/* sequential formatted external common routines*/ +#include "f2c.h" +#include "fio.h" + +extern char *f__fmtbuf; + +integer e_rsfe(Void) +{ int n; + n=en_fio(); + f__fmtbuf=NULL; + return(n); +} + +int c_sfe(cilist *a) /* check */ +{ unit *p; + f__curunit = p = &f__units[a->ciunit]; + if(a->ciunit >= MXUNIT || a->ciunit<0) + err(a->cierr,101,"startio"); + if(p->ufd==NULL && fk_open(SEQ,FMT,a->ciunit)) err(a->cierr,114,"sfe") + if(!p->ufmt) err(a->cierr,102,"sfe") + return(0); +} + +integer e_wsfe(Void) +{ + int n = en_fio(); + f__fmtbuf = NULL; + return n; +} diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/sig_die.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/sig_die.c new file mode 100644 index 00000000..78335200 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/sig_die.c @@ -0,0 +1,41 @@ +#include "stdio.h" +#include "signal.h" + +#ifndef SIGIOT +#ifdef SIGABRT +#define SIGIOT SIGABRT +#endif +#endif + +#include "stdlib.h" +#ifdef __cplusplus +extern "C" { +#endif + extern void f_exit(void); + +void sig_die(char *s, int kill) +{ + /* print error message, then clear buffers */ + fprintf(stderr, "%s\n", s); + + if(kill) + { + fflush(stderr); + f_exit(); + fflush(stderr); + /* now get a core */ +#ifdef SIGIOT + signal(SIGIOT, SIG_DFL); +#endif + abort(); + } + else { +#ifdef NO_ONEXIT + f_exit(); +#endif + exit(1); + } + } +#ifdef __cplusplus +} +#endif diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/util.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/util.c new file mode 100644 index 00000000..684cdfc4 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/util.c @@ -0,0 +1,39 @@ +#ifndef NON_UNIX_STDIO +#define _INCLUDE_POSIX_SOURCE /* for HP-UX */ +#define _INCLUDE_XOPEN_SOURCE /* for HP-UX */ +#include "sys/types.h" +#include "sys/stat.h" +#endif +#include "f2c.h" +#include "fio.h" + +void g_char(char *a, ftnlen alen, char *b) +{ + char *x = a + alen, *y = b + alen; + + for(;; y--) { + if (x <= a) { + *b = 0; + return; + } + if (*--x != ' ') + break; + } + *y-- = 0; + do *y-- = *x; + while(x-- > a); + } + +void b_char(char *a, char *b, ftnlen blen) +{ int i; + for(i=0;i<blen && *a!=0;i++) *b++= *a++; + for(;i<blen;i++) *b++=' '; +} +#ifndef NON_UNIX_STDIO +long f__inode(char *a, int *dev) +{ struct stat x; + if(stat(a,&x)<0) return(-1); + *dev = x.st_dev; + return(x.st_ino); +} +#endif diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/wref.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/wref.c new file mode 100644 index 00000000..636489c3 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/wref.c @@ -0,0 +1,266 @@ +#include "f2c.h" +#include "fio.h" + +#undef abs +#undef min +#undef max +#include "stdlib.h" +#include "string.h" + +#include "fmt.h" +#include "fp.h" +#ifndef VAX +#include "ctype.h" +#endif + +int wrt_E(ufloat *p, int w, int d, int e, ftnlen len) +{ + char buf[FMAX+EXPMAXDIGS+4], *s, *se; + int d1, delta, e1, i, sign, signspace; + double dd; +#ifdef WANT_LEAD_0 + int insert0 = 0; +#endif +#ifndef VAX + int e0 = e; +#endif + + if(e <= 0) + e = 2; + if(f__scale) { + if(f__scale >= d + 2 || f__scale <= -d) + goto nogood; + } + if(f__scale <= 0) + --d; + if (len == sizeof(real)) + dd = p->pf; + else + dd = p->pd; + if (dd < 0.) { + signspace = sign = 1; + dd = -dd; + } + else { + sign = 0; + signspace = (int)f__cplus; +#ifndef VAX + if (!dd) + dd = 0.; /* avoid -0 */ +#endif + } + delta = w - (2 /* for the . and the d adjustment above */ + + 2 /* for the E+ */ + signspace + d + e); +#ifdef WANT_LEAD_0 + if (f__scale <= 0 && delta > 0) { + delta--; + insert0 = 1; + } + else +#endif + if (delta < 0) { +nogood: + while(--w >= 0) + PUT('*'); + return(0); + } + if (f__scale < 0) + d += f__scale; + if (d > FMAX) { + d1 = d - FMAX; + d = FMAX; + } + else + d1 = 0; + sprintf(buf,"%#.*E", d, dd); +#ifndef VAX + /* check for NaN, Infinity */ + if (!isdigit(buf[0])) { + switch(buf[0]) { + case 'n': + case 'N': + signspace = 0; /* no sign for NaNs */ + } + delta = w - strlen(buf) - signspace; + if (delta < 0) + goto nogood; + while(--delta >= 0) + PUT(' '); + if (signspace) + PUT(sign ? '-' : '+'); + for(s = buf; *s; s++) + PUT(*s); + return 0; + } +#endif + se = buf + d + 3; +#ifdef GOOD_SPRINTF_EXPONENT /* When possible, exponent has 2 digits. */ + if (f__scale != 1 && dd) + sprintf(se, "%+.2d", atoi(se) + 1 - f__scale); +#else + if (dd) + sprintf(se, "%+.2d", atoi(se) + 1 - f__scale); + else + strcpy(se, "+00"); +#endif + s = ++se; + if (e < 2) { + if (*s != '0') + goto nogood; + } +#ifndef VAX + /* accommodate 3 significant digits in exponent */ + if (s[2]) { +#ifdef Pedantic + if (!e0 && !s[3]) + for(s -= 2, e1 = 2; s[0] = s[1]; s++); + + /* Pedantic gives the behavior that Fortran 77 specifies, */ + /* i.e., requires that E be specified for exponent fields */ + /* of more than 3 digits. With Pedantic undefined, we get */ + /* the behavior that Cray displays -- you get a bigger */ + /* exponent field if it fits. */ +#else + if (!e0) { + for(s -= 2, e1 = 2; s[0] = s[1]; s++) +#ifdef CRAY + delta--; + if ((delta += 4) < 0) + goto nogood +#endif + ; + } +#endif + else if (e0 >= 0) + goto shift; + else + e1 = e; + } + else + shift: +#endif + for(s += 2, e1 = 2; *s; ++e1, ++s) + if (e1 >= e) + goto nogood; + while(--delta >= 0) + PUT(' '); + if (signspace) + PUT(sign ? '-' : '+'); + s = buf; + i = f__scale; + if (f__scale <= 0) { +#ifdef WANT_LEAD_0 + if (insert0) + PUT('0'); +#endif + PUT('.'); + for(; i < 0; ++i) + PUT('0'); + PUT(*s); + s += 2; + } + else if (f__scale > 1) { + PUT(*s); + s += 2; + while(--i > 0) + PUT(*s++); + PUT('.'); + } + if (d1) { + se -= 2; + while(s < se) PUT(*s++); + se += 2; + do PUT('0'); while(--d1 > 0); + } + while(s < se) + PUT(*s++); + if (e < 2) + PUT(s[1]); + else { + while(++e1 <= e) + PUT('0'); + while(*s) + PUT(*s++); + } + return 0; + } + +int wrt_F(ufloat *p, int w, int d, ftnlen len) +{ + int d1, sign, n; + double x; + char *b, buf[MAXINTDIGS+MAXFRACDIGS+4], *s; + + x= (len==sizeof(real)?p->pf:p->pd); + if (d < MAXFRACDIGS) + d1 = 0; + else { + d1 = d - MAXFRACDIGS; + d = MAXFRACDIGS; + } + if (x < 0.) + { x = -x; sign = 1; } + else { + sign = 0; +#ifndef VAX + if (!x) + x = 0.; +#endif + } + + if (n = f__scale) + if (n > 0) + do x *= 10.; while(--n > 0); + else + do x *= 0.1; while(++n < 0); + +#ifdef USE_STRLEN + sprintf(b = buf, "%#.*f", d, x); + n = strlen(b) + d1; +#else + n = sprintf(b = buf, "%#.*f", d, x) + d1; +#endif + +#ifndef WANT_LEAD_0 + if (buf[0] == '0' && d) + { ++b; --n; } +#endif + if (sign) { + /* check for all zeros */ + for(s = b;;) { + while(*s == '0') s++; + switch(*s) { + case '.': + s++; continue; + case 0: + sign = 0; + } + break; + } + } + if (sign || f__cplus) + ++n; + if (n > w) { +#ifdef WANT_LEAD_0 + if (buf[0] == '0' && --n == w) + ++b; + else +#endif + { + while(--w >= 0) + PUT('*'); + return 0; + } + } + for(w -= n; --w >= 0; ) + PUT(' '); + if (sign) + PUT('-'); + else if (f__cplus) + PUT('+'); + while(n = *b++) + PUT(n); + while(--d1 >= 0) + PUT('0'); + return 0; + } diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/wrtfmt.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/wrtfmt.c new file mode 100644 index 00000000..74d1131a --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/wrtfmt.c @@ -0,0 +1,321 @@ +#include "f2c.h" +#include "fio.h" +#include "fmt.h" + +extern icilist *f__svic; +extern char *f__icptr; + + static int +mv_cur(Void) /* shouldn't use fseek because it insists on calling fflush */ + /* instead we know too much about stdio */ +{ + int cursor = f__cursor; + f__cursor = 0; + if(f__external == 0) { + if(cursor < 0) { + if(f__hiwater < f__recpos) + f__hiwater = f__recpos; + f__recpos += cursor; + f__icptr += cursor; + if(f__recpos < 0) + err(f__elist->cierr, 110, "left off"); + } + else if(cursor > 0) { + if(f__recpos + cursor >= f__svic->icirlen) + err(f__elist->cierr, 110, "recend"); + if(f__hiwater <= f__recpos) + for(; cursor > 0; cursor--) + (*f__putn)(' '); + else if(f__hiwater <= f__recpos + cursor) { + cursor -= f__hiwater - f__recpos; + f__icptr += f__hiwater - f__recpos; + f__recpos = f__hiwater; + for(; cursor > 0; cursor--) + (*f__putn)(' '); + } + else { + f__icptr += cursor; + f__recpos += cursor; + } + } + return(0); + } + if (cursor > 0) { + if(f__hiwater <= f__recpos) + for(;cursor>0;cursor--) (*f__putn)(' '); + else if(f__hiwater <= f__recpos + cursor) { + cursor -= f__hiwater - f__recpos; + f__recpos = f__hiwater; + for(; cursor > 0; cursor--) + (*f__putn)(' '); + } + else { + f__recpos += cursor; + } + } + else if (cursor < 0) + { + if(cursor + f__recpos < 0) + err(f__elist->cierr,110,"left off"); + if(f__hiwater < f__recpos) + f__hiwater = f__recpos; + f__recpos += cursor; + } + return(0); +} + +static int wrt_Z(Uint *n, int w, int minlen, ftnlen len) +{ + char *s, *se; + int i, w1; + static int one = 1; + static char hex[] = "0123456789ABCDEF"; + s = (char *)n; + --len; + if (*(char *)&one) { + /* little endian */ + se = s; + s += len; + i = -1; + } + else { + se = s + len; + i = 1; + } + for(;; s += i) + if (s == se || *s) + break; + w1 = (i*(se-s) << 1) + 1; + if (*s & 0xf0) + w1++; + if (w1 > w) + for(i = 0; i < w; i++) + (*f__putn)('*'); + else { + if ((minlen -= w1) > 0) + w1 += minlen; + while(--w >= w1) + (*f__putn)(' '); + while(--minlen >= 0) + (*f__putn)('0'); + if (!(*s & 0xf0)) { + (*f__putn)(hex[*s & 0xf]); + if (s == se) + return 0; + s += i; + } + for(;; s += i) { + (*f__putn)(hex[*s >> 4 & 0xf]); + (*f__putn)(hex[*s & 0xf]); + if (s == se) + break; + } + } + return 0; + } + +static int wrt_I(Uint *n, int w, ftnlen len, int base) +{ int ndigit,sign,spare,i; + longint x; + char *ans; + if(len==sizeof(integer)) x=n->il; + else if(len == sizeof(char)) x = n->ic; +#ifdef Allow_TYQUAD + else if (len == sizeof(longint)) x = n->ili; +#endif + else x=n->is; + ans=f__icvt(x,&ndigit,&sign, base); + spare=w-ndigit; + if(sign || f__cplus) spare--; + if(spare<0) + for(i=0;i<w;i++) (*f__putn)('*'); + else + { for(i=0;i<spare;i++) (*f__putn)(' '); + if(sign) (*f__putn)('-'); + else if(f__cplus) (*f__putn)('+'); + for(i=0;i<ndigit;i++) (*f__putn)(*ans++); + } + return(0); +} + +static int wrt_IM(Uint *n, int w, int m, ftnlen len, int base) +{ int ndigit,sign,spare,i,xsign; + longint x; + char *ans; + if(sizeof(integer)==len) x=n->il; + else if(len == sizeof(char)) x = n->ic; +#ifdef Allow_TYQUAD + else if (len == sizeof(longint)) x = n->ili; +#endif + else x=n->is; + ans=f__icvt(x,&ndigit,&sign, base); + if(sign || f__cplus) xsign=1; + else xsign=0; + if(ndigit+xsign>w || m+xsign>w) + { for(i=0;i<w;i++) (*f__putn)('*'); + return(0); + } + if(x==0 && m==0) + { for(i=0;i<w;i++) (*f__putn)(' '); + return(0); + } + if(ndigit>=m) + spare=w-ndigit-xsign; + else + spare=w-m-xsign; + for(i=0;i<spare;i++) (*f__putn)(' '); + if(sign) (*f__putn)('-'); + else if(f__cplus) (*f__putn)('+'); + for(i=0;i<m-ndigit;i++) (*f__putn)('0'); + for(i=0;i<ndigit;i++) (*f__putn)(*ans++); + return(0); +} + +static int wrt_AP(char *s) +{ char quote; + int i; + + if(f__cursor && (i = mv_cur())) + return i; + quote = *s++; + for(;*s;s++) + { if(*s!=quote) (*f__putn)(*s); + else if(*++s==quote) (*f__putn)(*s); + else return(1); + } + return(1); +} + +static int wrt_H(int a, char *s) +{ + int i; + + if(f__cursor && (i = mv_cur())) + return i; + while(a--) (*f__putn)(*s++); + return(1); +} + +int wrt_L(Uint *n, int len, ftnlen sz) +{ int i; + long x; + if(sizeof(long)==sz) x=n->il; + else if(sz == sizeof(char)) x = n->ic; + else x=n->is; + for(i=0;i<len-1;i++) + (*f__putn)(' '); + if(x) (*f__putn)('T'); + else (*f__putn)('F'); + return(0); +} + +static int wrt_A(char *p, ftnlen len) +{ + while(len-- > 0) (*f__putn)(*p++); + return(0); +} + +static int wrt_AW(char * p, int w, ftnlen len) +{ + while(w>len) + { w--; + (*f__putn)(' '); + } + while(w-- > 0) + (*f__putn)(*p++); + return(0); +} + +static int wrt_G(ufloat *p, int w, int d, int e, ftnlen len) +{ double up = 1,x; + int i=0,oldscale,n,j; + x = len==sizeof(real)?p->pf:p->pd; + if(x < 0 ) x = -x; + if(x<.1) { + if (x != 0.) + return(wrt_E(p,w,d,e,len)); + i = 1; + goto have_i; + } + for(;i<=d;i++,up*=10) + { if(x>=up) continue; + have_i: + oldscale = f__scale; + f__scale = 0; + if(e==0) n=4; + else n=e+2; + i=wrt_F(p,w-n,d-i,len); + for(j=0;j<n;j++) (*f__putn)(' '); + f__scale=oldscale; + return(i); + } + return(wrt_E(p,w,d,e,len)); +} + +int w_ed(struct syl *p, char *ptr, ftnlen len) +{ + int i; + + if(f__cursor && (i = mv_cur())) + return i; + switch(p->op) + { + default: + fprintf(stderr,"w_ed, unexpected code: %d\n", p->op); + sig_die(f__fmtbuf, 1); + case I: return(wrt_I((Uint *)ptr,p->p1,len, 10)); + case IM: + return(wrt_IM((Uint *)ptr,p->p1,p->p2.i[0],len,10)); + + /* O and OM don't work right for character, double, complex, */ + /* or doublecomplex, and they differ from Fortran 90 in */ + /* showing a minus sign for negative values. */ + + case O: return(wrt_I((Uint *)ptr, p->p1, len, 8)); + case OM: + return(wrt_IM((Uint *)ptr,p->p1,p->p2.i[0],len,8)); + case L: return(wrt_L((Uint *)ptr,p->p1, len)); + case A: return(wrt_A(ptr,len)); + case AW: + return(wrt_AW(ptr,p->p1,len)); + case D: + case E: + case EE: + return(wrt_E((ufloat *)ptr,p->p1,p->p2.i[0],p->p2.i[1],len)); + case G: + case GE: + return(wrt_G((ufloat *)ptr,p->p1,p->p2.i[0],p->p2.i[1],len)); + case F: return(wrt_F((ufloat *)ptr,p->p1,p->p2.i[0],len)); + + /* Z and ZM assume 8-bit bytes. */ + + case Z: return(wrt_Z((Uint *)ptr,p->p1,0,len)); + case ZM: + return(wrt_Z((Uint *)ptr,p->p1,p->p2.i[0],len)); + } +} + +int w_ned(struct syl *p) +{ + switch(p->op) + { + default: fprintf(stderr,"w_ned, unexpected code: %d\n", p->op); + sig_die(f__fmtbuf, 1); + case SLASH: + return((*f__donewrec)()); + case T: f__cursor = p->p1-f__recpos - 1; + return(1); + case TL: f__cursor -= p->p1; + if(f__cursor < -f__recpos) /* TL1000, 1X */ + f__cursor = -f__recpos; + return(1); + case TR: + case X: + f__cursor += p->p1; + return(1); + case APOS: + return(wrt_AP(p->p2.s)); + case H: + return(wrt_H(p->p1,p->p2.s)); + } +} diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/wsfe.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/wsfe.c new file mode 100644 index 00000000..b772df32 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/wsfe.c @@ -0,0 +1,69 @@ +/*write sequential formatted external*/ +#include "f2c.h" +#include "fio.h" +#include "fmt.h" +extern int f__hiwater; + + int +x_wSL(Void) +{ + int n = f__putbuf('\n'); + f__hiwater = f__recpos = f__cursor = 0; + return(n == 0); +} + + static int +xw_end(Void) +{ + int n; + + if(f__nonl) { + f__putbuf(n = 0); + fflush(f__cf); + } + else + n = f__putbuf('\n'); + f__hiwater = f__recpos = f__cursor = 0; + return n; +} + + static int +xw_rev(Void) +{ + int n = 0; + if(f__workdone) { + n = f__putbuf('\n'); + f__workdone = 0; + } + f__hiwater = f__recpos = f__cursor = 0; + return n; +} + +integer s_wsfe(cilist *a) /*start*/ +{ int n; + if(!f__init) f_init(); + f__reading=0; + f__sequential=1; + f__formatted=1; + f__external=1; + if(n=c_sfe(a)) return(n); + f__elist=a; + f__hiwater = f__cursor=f__recpos=0; + f__nonl = 0; + f__scale=0; + f__fmtbuf=a->cifmt; + f__cf=f__curunit->ufd; + if(pars_f(f__fmtbuf)<0) err(a->cierr,100,"startio"); + f__putn= x_putc; + f__doed= w_ed; + f__doned= w_ned; + f__doend=xw_end; + f__dorevert=xw_rev; + f__donewrec=x_wSL; + fmt_bg(); + f__cplus=0; + f__cblank=f__curunit->ublnk; + if(f__curunit->uwrt != 1 && f__nowwriting(f__curunit)) + err(a->cierr,errno,"write start"); + return(0); +} diff --git a/src/imageplugins/coreplugin/sharpnesseditor/clapack/xerbla.c b/src/imageplugins/coreplugin/sharpnesseditor/clapack/xerbla.c new file mode 100644 index 00000000..d8ef512b --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/clapack/xerbla.c @@ -0,0 +1,58 @@ +#include "blaswrap.h" +#include "f2c.h" + +/* Subroutine */ int xerbla_(char *srname, integer *info) +{ +/* -- LAPACK auxiliary routine (preliminary version) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + February 29, 1992 + + + Purpose + ======= + + XERBLA is an error handler for the LAPACK routines. + It is called by an LAPACK routine if an input parameter has an + invalid value. A message is printed and execution stops. + + Installers may consider modifying the STOP statement in order to + call system-specific exception-handling facilities. + + Arguments + ========= + + SRNAME (input) CHARACTER*6 + The name of the routine which called XERBLA. + + INFO (input) INTEGER + The position of the invalid parameter in the parameter list + of the calling routine. */ + /* Table of constant values */ + static integer c__1 = 1; + + /* Format strings */ + static char fmt_9999[] = "(\002 ** On entry to \002,a6,\002 parameter nu" + "mber \002,i2,\002 had \002,\002an illegal value\002)"; + /* Builtin functions */ + integer s_wsfe(cilist *), do_fio(integer *, char *, ftnlen), e_wsfe(void); + /* Subroutine */ int s_stop(char *, ftnlen); + /* Fortran I/O blocks */ + static cilist io___1 = { 0, 6, 0, fmt_9999, 0 }; + + + + + s_wsfe(&io___1); + do_fio(&c__1, srname, (ftnlen)6); + do_fio(&c__1, (char *)&(*info), (ftnlen)sizeof(integer)); + e_wsfe(); + + s_stop("", (ftnlen)0); + + +/* End of XERBLA */ + + return 0; +} /* xerbla_ */ + diff --git a/src/imageplugins/coreplugin/sharpnesseditor/imageeffect_sharpen.cpp b/src/imageplugins/coreplugin/sharpnesseditor/imageeffect_sharpen.cpp new file mode 100644 index 00000000..b2ae9a62 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/imageeffect_sharpen.cpp @@ -0,0 +1,696 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-09 + * Description : a tool to sharp an image + * + * Copyright (C) 2004-2007 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. + * + * ============================================================ */ + +#define MAX_MATRIX_SIZE 25 + +// C++ includes. + +#include <cmath> + +// TQt includes. + +#include <tqlayout.h> +#include <tqlabel.h> +#include <tqwhatsthis.h> +#include <tqcombobox.h> +#include <tqwidgetstack.h> + +// KDE includes. + +#include <tdeaboutdata.h> +#include <knuminput.h> +#include <kcursor.h> +#include <tdelocale.h> +#include <tdeapplication.h> +#include <kseparator.h> +#include <tdeconfig.h> +#include <kurl.h> +#include <tdefiledialog.h> +#include <tdeglobalsettings.h> +#include <tdemessagebox.h> + +// Local includes. + +#include "ddebug.h" +#include "imageiface.h" +#include "dimgsharpen.h" +#include "unsharp.h" +#include "refocus.h" +#include "imageeffect_sharpen.h" +#include "imageeffect_sharpen.moc" + +namespace DigikamImagesPluginCore +{ + +ImageEffect_Sharpen::ImageEffect_Sharpen(TQWidget* parent) + : Digikam::CtrlPanelDlg(parent, i18n("Sharpening Photograph"), "sharpen", + true, true, true) +{ + setHelp("blursharpentool.anchor", "digikam"); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(m_imagePreviewWidget); + TQGridLayout* gridSettings = new TQGridLayout( gboxSettings, 2, 1, 0, spacingHint()); + + TQLabel *label1 = new TQLabel(i18n("Method:"), gboxSettings); + + m_sharpMethod = new TQComboBox( false, gboxSettings ); + m_sharpMethod->insertItem( i18n("Simple sharp") ); + m_sharpMethod->insertItem( i18n("Unsharp mask") ); + m_sharpMethod->insertItem( i18n("Refocus") ); + TQWhatsThis::add( m_sharpMethod, i18n("<p>Select the sharpening method to apply to the image.")); + + m_stack = new TQWidgetStack(gboxSettings); + + gridSettings->addMultiCellWidget(label1, 0, 0, 0, 0); + gridSettings->addMultiCellWidget(m_sharpMethod, 0, 0, 1, 1); + gridSettings->addMultiCellWidget(new KSeparator(gboxSettings), 1, 1, 0, 1); + gridSettings->addMultiCellWidget(m_stack, 2, 2, 0, 1); + + // ------------------------------------------------------------- + + TQWidget *simpleSharpSettings = new TQWidget(m_stack); + TQGridLayout* grid1 = new TQGridLayout( simpleSharpSettings, 2, 1, 0, spacingHint()); + + TQLabel *label = new TQLabel(i18n("Sharpness:"), simpleSharpSettings); + m_radiusInput = new KIntNumInput(simpleSharpSettings); + m_radiusInput->setRange(0, 100, 1, true); + m_radiusInput->setValue(0); + TQWhatsThis::add( m_radiusInput, i18n("<p>A sharpness of 0 has no effect, " + "1 and above determine the sharpen matrix radius " + "that determines how much to sharpen the image.")); + + grid1->addMultiCellWidget(label, 0, 0, 0, 1); + grid1->addMultiCellWidget(m_radiusInput, 1, 1, 0, 1); + grid1->setRowStretch(2, 10); + m_stack->addWidget(simpleSharpSettings, SimpleSharp); + + // ------------------------------------------------------------- + + TQWidget *unsharpMaskSettings = new TQWidget(m_stack); + TQGridLayout* grid2 = new TQGridLayout( unsharpMaskSettings, 6, 1, 0, spacingHint()); + + TQLabel *label2 = new TQLabel(i18n("Radius:"), unsharpMaskSettings); + m_radiusInput2 = new KIntNumInput(unsharpMaskSettings); + m_radiusInput2->setRange(1, 120, 1, true); + TQWhatsThis::add( m_radiusInput2, i18n("<p>Radius value is the gaussian blur matrix radius value " + "used to determines how much to blur the image.") ); + + TQLabel *label3 = new TQLabel(i18n("Amount:"), unsharpMaskSettings); + m_amountInput = new KDoubleNumInput(unsharpMaskSettings); + m_amountInput->setPrecision(1); + m_amountInput->setRange(0.0, 5.0, 0.1, true); + TQWhatsThis::add( m_amountInput, i18n("<p>The value of the difference between the " + "original and the blur image that is added back into the original.") ); + + TQLabel *label4 = new TQLabel(i18n("Threshold:"), unsharpMaskSettings); + m_thresholdInput = new KDoubleNumInput(unsharpMaskSettings); + m_thresholdInput->setPrecision(2); + m_thresholdInput->setRange(0.0, 1.0, 0.01, true); + TQWhatsThis::add( m_thresholdInput, i18n("<p>The threshold, as a fraction of the maximum " + "luminosity value, needed to apply the difference amount.") ); + + grid2->addMultiCellWidget(label2, 0, 0, 0, 1); + grid2->addMultiCellWidget(m_radiusInput2, 1, 1, 0, 1); + grid2->addMultiCellWidget(label3, 2, 2, 0, 1); + grid2->addMultiCellWidget(m_amountInput, 3, 3, 0, 1); + grid2->addMultiCellWidget(label4, 4, 4, 0, 1); + grid2->addMultiCellWidget(m_thresholdInput, 5, 5, 0, 1); + grid2->setRowStretch(6, 10); + m_stack->addWidget(unsharpMaskSettings, UnsharpMask); + + // ------------------------------------------------------------- + + TQWidget *refocusSettings = new TQWidget(m_stack); + TQGridLayout* grid3 = new TQGridLayout(refocusSettings, 10, 1, 0, spacingHint()); + + TQLabel *label5 = new TQLabel(i18n("Circular sharpness:"), refocusSettings); + m_radius = new KDoubleNumInput(refocusSettings); + m_radius->setPrecision(2); + m_radius->setRange(0.0, 5.0, 0.01, true); + TQWhatsThis::add( m_radius, i18n("<p>This is the radius of the circular convolution. It is the most important " + "parameter for using this plugin. For most images the default value of 1.0 " + "should give good results. Select a higher value when your image is very blurred.")); + + TQLabel *label6 = new TQLabel(i18n("Correlation:"), refocusSettings); + m_correlation = new KDoubleNumInput(refocusSettings); + m_correlation->setPrecision(2); + m_correlation->setRange(0.0, 1.0, 0.01, true); + TQWhatsThis::add( m_correlation, i18n("<p>Increasing the correlation may help to reduce artifacts. The correlation can " + "range from 0-1. Useful values are 0.5 and values close to 1, e.g. 0.95 and 0.99. " + "Using a high value for the correlation will reduce the sharpening effect of the " + "plugin.")); + + TQLabel *label7 = new TQLabel(i18n("Noise filter:"), refocusSettings); + m_noise = new KDoubleNumInput(refocusSettings); + m_noise->setPrecision(3); + m_noise->setRange(0.0, 1.0, 0.001, true); + TQWhatsThis::add( m_noise, i18n("<p>Increasing the noise filter parameter may help to reduce artifacts. The noise filter " + "can range from 0-1 but values higher than 0.1 are rarely helpful. When the noise filter " + "value is too low, e.g. 0.0 the image quality will be very poor. A useful value is 0.01. " + "Using a high value for the noise filter will reduce the sharpening " + "effect of the plugin.")); + + TQLabel *label8 = new TQLabel(i18n("Gaussian sharpness:"), refocusSettings); + m_gauss = new KDoubleNumInput(refocusSettings); + m_gauss->setPrecision(2); + m_gauss->setRange(0.0, 1.0, 0.01, true); + TQWhatsThis::add( m_gauss, i18n("<p>This is the sharpness for the gaussian convolution. Use this parameter when your " + "blurring is of a Gaussian type. In most cases you should set this parameter to 0, because " + "it causes nasty artifacts. When you use non-zero values, you will probably have to " + "increase the correlation and/or noise filter parameters too.")); + + TQLabel *label9 = new TQLabel(i18n("Matrix size:"), refocusSettings); + m_matrixSize = new KIntNumInput(refocusSettings); + m_matrixSize->setRange(0, MAX_MATRIX_SIZE, 1, true); + TQWhatsThis::add( m_matrixSize, i18n("<p>This parameter determines the size of the transformation matrix. " + "Increasing the matrix width may give better results, especially when you have " + "chosen large values for circular or gaussian sharpness.")); + + grid3->addMultiCellWidget(label5, 0, 0, 0, 1); + grid3->addMultiCellWidget(m_radius, 1, 1, 0, 1); + grid3->addMultiCellWidget(label6, 2, 2, 0, 1); + grid3->addMultiCellWidget(m_correlation, 3, 3, 0, 1); + grid3->addMultiCellWidget(label7, 4, 4, 0, 1); + grid3->addMultiCellWidget(m_noise, 5, 5, 0, 1); + grid3->addMultiCellWidget(label8, 6, 6, 0, 1); + grid3->addMultiCellWidget(m_gauss, 7, 7, 0, 1); + grid3->addMultiCellWidget(label9, 8, 8, 0, 1); + grid3->addMultiCellWidget(m_matrixSize, 9, 9, 0, 1); + grid3->setRowStretch(10, 10); + m_stack->addWidget(refocusSettings, Refocus); + + m_imagePreviewWidget->setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + connect(m_sharpMethod, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotSharpMethodActived(int))); + + // ------------------------------------------------------------- + + // Image creation with dummy borders (mosaic mode) used by Refocus method. It needs to do + // it before to apply deconvolution filter on original image border pixels including + // on matrix size area. This way limit artifacts on image border. + + Digikam::ImageIface iface(0, 0); + + uchar* data = iface.getOriginalImage(); + int w = iface.originalWidth(); + int h = iface.originalHeight(); + bool sb = iface.originalSixteenBit(); + bool a = iface.originalHasAlpha(); + + m_img = Digikam::DImg( w + 4*MAX_MATRIX_SIZE, h + 4*MAX_MATRIX_SIZE, sb, a); + + Digikam::DImg tmp; + Digikam::DImg org(w, h, sb, a, data); + + // Copy original. + m_img.bitBltImage(&org, 2*MAX_MATRIX_SIZE, 2*MAX_MATRIX_SIZE); + + // Create dummy top border + tmp = org.copy(0, 0, w, 2*MAX_MATRIX_SIZE); + tmp.flip(Digikam::DImg::VERTICAL); + m_img.bitBltImage(&tmp, 2*MAX_MATRIX_SIZE, 0); + + // Create dummy bottom border + tmp = org.copy(0, h-2*MAX_MATRIX_SIZE, w, 2*MAX_MATRIX_SIZE); + tmp.flip(Digikam::DImg::VERTICAL); + m_img.bitBltImage(&tmp, 2*MAX_MATRIX_SIZE, 2*MAX_MATRIX_SIZE+h); + + // Create dummy left border + tmp = org.copy(0, 0, 2*MAX_MATRIX_SIZE, h); + tmp.flip(Digikam::DImg::HORIZONTAL); + m_img.bitBltImage(&tmp, 0, 2*MAX_MATRIX_SIZE); + + // Create dummy right border + tmp = org.copy(w-2*MAX_MATRIX_SIZE, 0, 2*MAX_MATRIX_SIZE, h); + tmp.flip(Digikam::DImg::HORIZONTAL); + m_img.bitBltImage(&tmp, w+2*MAX_MATRIX_SIZE, 2*MAX_MATRIX_SIZE); + + // Create dummy top/left corner + tmp = org.copy(0, 0, 2*MAX_MATRIX_SIZE, 2*MAX_MATRIX_SIZE); + tmp.flip(Digikam::DImg::HORIZONTAL); + tmp.flip(Digikam::DImg::VERTICAL); + m_img.bitBltImage(&tmp, 0, 0); + + // Create dummy top/right corner + tmp = org.copy(w-2*MAX_MATRIX_SIZE, 0, 2*MAX_MATRIX_SIZE, 2*MAX_MATRIX_SIZE); + tmp.flip(Digikam::DImg::HORIZONTAL); + tmp.flip(Digikam::DImg::VERTICAL); + m_img.bitBltImage(&tmp, w+2*MAX_MATRIX_SIZE, 0); + + // Create dummy bottom/left corner + tmp = org.copy(0, h-2*MAX_MATRIX_SIZE, 2*MAX_MATRIX_SIZE, 2*MAX_MATRIX_SIZE); + tmp.flip(Digikam::DImg::HORIZONTAL); + tmp.flip(Digikam::DImg::VERTICAL); + m_img.bitBltImage(&tmp, 0, h+2*MAX_MATRIX_SIZE); + + // Create dummy bottom/right corner + tmp = org.copy(w-2*MAX_MATRIX_SIZE, h-2*MAX_MATRIX_SIZE, 2*MAX_MATRIX_SIZE, 2*MAX_MATRIX_SIZE); + tmp.flip(Digikam::DImg::HORIZONTAL); + tmp.flip(Digikam::DImg::VERTICAL); + m_img.bitBltImage(&tmp, w+2*MAX_MATRIX_SIZE, h+2*MAX_MATRIX_SIZE); + + delete [] data; +} + +ImageEffect_Sharpen::~ImageEffect_Sharpen() +{ +} + +void ImageEffect_Sharpen::renderingFinished(void) +{ + switch (m_stack->id(m_stack->visibleWidget())) + { + case SimpleSharp: + { + m_radiusInput->setEnabled(true); + enableButton(User2, false); + enableButton(User3, false); + break; + } + + case UnsharpMask: + { + m_radiusInput2->setEnabled(true); + m_amountInput->setEnabled(true); + m_thresholdInput->setEnabled(true); + enableButton(User2, false); + enableButton(User3, false); + break; + } + + case Refocus: + { + m_matrixSize->setEnabled(true); + m_radius->setEnabled(true); + m_gauss->setEnabled(true); + m_correlation->setEnabled(true); + m_noise->setEnabled(true); + break; + } + } +} + +void ImageEffect_Sharpen::slotSharpMethodActived(int w) +{ + m_stack->raiseWidget(w); + if (w == Refocus) + { + enableButton(User2, true); + enableButton(User3, true); + } + else + { + enableButton(User2, false); + enableButton(User3, false); + } +} + +void ImageEffect_Sharpen::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("sharpen Tool Dialog"); + m_radiusInput->blockSignals(true); + m_radiusInput2->blockSignals(true); + m_amountInput->blockSignals(true); + m_thresholdInput->blockSignals(true); + m_matrixSize->blockSignals(true); + m_radius->blockSignals(true); + m_gauss->blockSignals(true); + m_correlation->blockSignals(true); + m_noise->blockSignals(true); + m_sharpMethod->blockSignals(true); + m_radiusInput->setValue(config->readNumEntry("SimpleSharpRadiusAjustment", 0)); + m_radiusInput2->setValue(config->readNumEntry("UnsharpMaskRadiusAjustment", 1)); + m_amountInput->setValue(config->readDoubleNumEntry("UnsharpMaskAmountAjustment", 1.0)); + m_thresholdInput->setValue(config->readDoubleNumEntry("UnsharpMaskThresholdAjustment", 0.05)); + m_matrixSize->setValue(config->readNumEntry("RefocusMatrixSize", 5)); + m_radius->setValue(config->readDoubleNumEntry("RefocusRadiusAjustment", 1.0)); + m_gauss->setValue(config->readDoubleNumEntry("RefocusGaussAjustment", 0.0)); + m_correlation->setValue(config->readDoubleNumEntry("RefocusCorrelationAjustment", 0.5)); + m_noise->setValue(config->readDoubleNumEntry("RefocusNoiseAjustment", 0.03)); + m_sharpMethod->setCurrentItem(config->readNumEntry("SharpenMethod", SimpleSharp)); + m_radiusInput->blockSignals(false); + m_radiusInput2->blockSignals(false); + m_amountInput->blockSignals(false); + m_thresholdInput->blockSignals(false); + m_matrixSize->blockSignals(false); + m_radius->blockSignals(false); + m_gauss->blockSignals(false); + m_correlation->blockSignals(false); + m_noise->blockSignals(false); + m_sharpMethod->blockSignals(false); + slotSharpMethodActived(m_sharpMethod->currentItem()); +} + +void ImageEffect_Sharpen::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("sharpen Tool Dialog"); + config->writeEntry("SimpleSharpRadiusAjustment", m_radiusInput->value()); + config->writeEntry("UnsharpMaskRadiusAjustment", m_radiusInput2->value()); + config->writeEntry("UnsharpMaskAmountAjustment", m_amountInput->value()); + config->writeEntry("UnsharpMaskThresholdAjustment", m_thresholdInput->value()); + config->writeEntry("RefocusMatrixSize", m_matrixSize->value()); + config->writeEntry("RefocusRadiusAjustment", m_radius->value()); + config->writeEntry("RefocusGaussAjustment", m_gauss->value()); + config->writeEntry("RefocusCorrelationAjustment", m_correlation->value()); + config->writeEntry("RefocusNoiseAjustment", m_noise->value()); + config->writeEntry("SharpenMethod", m_sharpMethod->currentItem()); + config->sync(); +} + +void ImageEffect_Sharpen::resetValues(void) +{ + switch (m_stack->id(m_stack->visibleWidget())) + { + case SimpleSharp: + { + m_radiusInput->blockSignals(true); + m_radiusInput->setValue(0); + m_radiusInput->blockSignals(false); + break; + } + + case UnsharpMask: + { + m_radiusInput2->blockSignals(true); + m_amountInput->blockSignals(true); + m_thresholdInput->blockSignals(true); + m_radiusInput2->setValue(1); + m_amountInput->setValue(1.0); + m_thresholdInput->setValue(0.05); + m_radiusInput2->blockSignals(false); + m_amountInput->blockSignals(false); + m_thresholdInput->blockSignals(false); + break; + } + + case Refocus: + { + m_matrixSize->blockSignals(true); + m_radius->blockSignals(true); + m_gauss->blockSignals(true); + m_correlation->blockSignals(true); + m_noise->blockSignals(true); + m_matrixSize->setValue(5); + m_radius->setValue(1.0); + m_gauss->setValue(0.0); + m_correlation->setValue(0.5); + m_noise->setValue(0.03); + m_matrixSize->blockSignals(false); + m_radius->blockSignals(false); + m_gauss->blockSignals(false); + m_correlation->blockSignals(false); + m_noise->blockSignals(false); + break; + } + } +} + +void ImageEffect_Sharpen::prepareEffect() +{ + switch (m_stack->id(m_stack->visibleWidget())) + { + case SimpleSharp: + { + m_radiusInput->setEnabled(false); + + Digikam::DImg img = m_imagePreviewWidget->getOriginalRegionImage(); + + double radius = m_radiusInput->value()/10.0; + double sigma; + + if (radius < 1.0) sigma = radius; + else sigma = sqrt(radius); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *> + (new Digikam::DImgSharpen(&img, this, radius, sigma )); + break; + } + + case UnsharpMask: + { + m_radiusInput2->setEnabled(false); + m_amountInput->setEnabled(false); + m_thresholdInput->setEnabled(false); + + Digikam::DImg img = m_imagePreviewWidget->getOriginalRegionImage(); + + int r = m_radiusInput2->value(); + double a = m_amountInput->value(); + double th = m_thresholdInput->value(); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *> + (new DigikamImagesPluginCore::UnsharpMask(&img, this, r, a, th)); + break; + } + + case Refocus: + { + m_matrixSize->setEnabled(false); + m_radius->setEnabled(false); + m_gauss->setEnabled(false); + m_correlation->setEnabled(false); + m_noise->setEnabled(false); + + int ms = m_matrixSize->value(); + double r = m_radius->value(); + double g = m_gauss->value(); + double c = m_correlation->value(); + double n = m_noise->value(); + + TQRect area = m_imagePreviewWidget->getOriginalImageRegionToRender(); + TQRect tmpRect; + tmpRect.setLeft(area.left()-2*ms); + tmpRect.setRight(area.right()+2*ms); + tmpRect.setTop(area.top()-2*ms); + tmpRect.setBottom(area.bottom()+2*ms); + tmpRect.moveBy(2*MAX_MATRIX_SIZE, 2*MAX_MATRIX_SIZE); + Digikam::DImg imTemp = m_img.copy(tmpRect); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *> + (new DigikamImagesPluginCore::Refocus(&imTemp, this, ms, r, g, c, n)); + break; + } + } +} + +void ImageEffect_Sharpen::prepareFinal() +{ + switch (m_stack->id(m_stack->visibleWidget())) + { + case SimpleSharp: + { + m_radiusInput->setEnabled(false); + + double radius = m_radiusInput->value()/10.0; + double sigma; + + if (radius < 1.0) sigma = radius; + else sigma = sqrt(radius); + + Digikam::ImageIface iface(0, 0); + uchar *data = iface.getOriginalImage(); + int w = iface.originalWidth(); + int h = iface.originalHeight(); + bool sixteenBit = iface.originalSixteenBit(); + bool hasAlpha = iface.originalHasAlpha(); + Digikam::DImg orgImage = Digikam::DImg(w, h, sixteenBit, hasAlpha ,data); + delete [] data; + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *> + (new Digikam::DImgSharpen(&orgImage, this, radius, sigma )); + break; + } + + case UnsharpMask: + { + m_radiusInput2->setEnabled(false); + m_amountInput->setEnabled(false); + m_thresholdInput->setEnabled(false); + + int r = m_radiusInput2->value(); + double a = m_amountInput->value(); + double th = m_thresholdInput->value(); + + Digikam::ImageIface iface(0, 0); + uchar *data = iface.getOriginalImage(); + int w = iface.originalWidth(); + int h = iface.originalHeight(); + bool sixteenBit = iface.originalSixteenBit(); + bool hasAlpha = iface.originalHasAlpha(); + Digikam::DImg orgImage = Digikam::DImg(w, h, sixteenBit, hasAlpha ,data); + delete [] data; + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *> + (new DigikamImagesPluginCore::UnsharpMask(&orgImage, this, r, a, th)); + break; + } + + case Refocus: + { + + m_matrixSize->setEnabled(false); + m_radius->setEnabled(false); + m_gauss->setEnabled(false); + m_correlation->setEnabled(false); + m_noise->setEnabled(false); + + int ms = m_matrixSize->value(); + double r = m_radius->value(); + double g = m_gauss->value(); + double c = m_correlation->value(); + double n = m_noise->value(); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *> + (new DigikamImagesPluginCore::Refocus(&m_img, this, ms, r, g, c, n)); + break; + } + } +} + +void ImageEffect_Sharpen::putPreviewData(void) +{ + switch (m_stack->id(m_stack->visibleWidget())) + { + case SimpleSharp: + case UnsharpMask: + { + Digikam::DImg imDest = m_threadedFilter->getTargetImage(); + m_imagePreviewWidget->setPreviewImage(imDest); + break; + } + + case Refocus: + { + int ms = m_matrixSize->value(); + TQRect area = m_imagePreviewWidget->getOriginalImageRegionToRender(); + + Digikam::DImg imDest = m_threadedFilter->getTargetImage() + .copy(2*ms, 2*ms, area.width(), area.height()); + m_imagePreviewWidget->setPreviewImage(imDest); + break; + } + } +} + +void ImageEffect_Sharpen::putFinalData(void) +{ + Digikam::ImageIface iface(0, 0); + Digikam::DImg imDest = m_threadedFilter->getTargetImage(); + + switch (m_stack->id(m_stack->visibleWidget())) + { + case SimpleSharp: + { + iface.putOriginalImage(i18n("Sharpen"), imDest.bits()); + break; + } + + case UnsharpMask: + { + iface.putOriginalImage(i18n("Unsharp Mask"), imDest.bits()); + break; + } + + case Refocus: + { + TQRect area = m_imagePreviewWidget->getOriginalImageRegionToRender(); + Digikam::ImageIface iface(0, 0); + + iface.putOriginalImage(i18n("Refocus"), m_threadedFilter->getTargetImage() + .copy(2*MAX_MATRIX_SIZE, 2*MAX_MATRIX_SIZE, + iface.originalWidth(), + iface.originalHeight()) + .bits()); + break; + } + } +} + +void ImageEffect_Sharpen::slotUser3() +{ + KURL loadRestorationFile = KFileDialog::getOpenURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), this, + TQString( i18n("Photograph Refocus Settings File to Load")) ); + if ( loadRestorationFile.isEmpty() ) + return; + + TQFile file(loadRestorationFile.path()); + + if ( file.open(IO_ReadOnly) ) + { + TQTextStream stream( &file ); + if ( stream.readLine() != "# Photograph Refocus Configuration File" ) + { + KMessageBox::error(this, + i18n("\"%1\" is not a Photograph Refocus settings text file.") + .arg(loadRestorationFile.fileName())); + file.close(); + return; + } + + blockSignals(true); + m_matrixSize->setValue( stream.readLine().toInt() ); + m_radius->setValue( stream.readLine().toDouble() ); + m_gauss->setValue( stream.readLine().toDouble() ); + m_correlation->setValue( stream.readLine().toDouble() ); + m_noise->setValue( stream.readLine().toDouble() ); + blockSignals(false); + } + else + KMessageBox::error(this, i18n("Cannot load settings from the Photograph Refocus text file.")); + + file.close(); +} + +void ImageEffect_Sharpen::slotUser2() +{ + KURL saveRestorationFile = KFileDialog::getSaveURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), this, + TQString( i18n("Photograph Refocus Settings File to Save")) ); + if ( saveRestorationFile.isEmpty() ) + return; + + TQFile file(saveRestorationFile.path()); + + if ( file.open(IO_WriteOnly) ) + { + TQTextStream stream( &file ); + stream << "# Photograph Refocus Configuration File\n"; + stream << m_matrixSize->value() << "\n"; + stream << m_radius->value() << "\n"; + stream << m_gauss->value() << "\n"; + stream << m_correlation->value() << "\n"; + stream << m_noise->value() << "\n"; + } + else + KMessageBox::error(this, i18n("Cannot save settings to the Photograph Refocus text file.")); + + file.close(); +} + +} // NameSpace DigikamImagesPluginCore diff --git a/src/imageplugins/coreplugin/sharpnesseditor/imageeffect_sharpen.h b/src/imageplugins/coreplugin/sharpnesseditor/imageeffect_sharpen.h new file mode 100644 index 00000000..fa926383 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/imageeffect_sharpen.h @@ -0,0 +1,102 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-09 + * Description : a tool to sharp an image + * + * Copyright (C) 2004-2007 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_SHARPEN_H +#define IMAGEEFFECT_SHARPEN_H + +// Digikam include. + +#include "ctrlpaneldlg.h" + +class TQComboBox; +class TQWidgetStack; + +class KIntNumInput; +class KDoubleNumInput; + +namespace Digikam +{ + class DImg; +} + +namespace DigikamImagesPluginCore +{ + +class ImageEffect_Sharpen : public Digikam::CtrlPanelDlg +{ + TQ_OBJECT + + +public: + + ImageEffect_Sharpen(TQWidget *parent); + ~ImageEffect_Sharpen(); + +private slots: + + void slotUser2(); + void slotUser3(); + void readUserSettings(); + void slotSharpMethodActived(int); + +private: + + void writeUserSettings(); + void resetValues(); + void prepareEffect(); + void prepareFinal(); + void abortPreview(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + enum SharpingMethods + { + SimpleSharp=0, + UnsharpMask, + Refocus + }; + + TQWidgetStack *m_stack; + + TQComboBox *m_sharpMethod; + + KIntNumInput *m_matrixSize; + KIntNumInput *m_radiusInput; + KIntNumInput *m_radiusInput2; + + KDoubleNumInput *m_radius; + KDoubleNumInput *m_gauss; + KDoubleNumInput *m_correlation; + KDoubleNumInput *m_noise; + KDoubleNumInput *m_amountInput; + KDoubleNumInput *m_thresholdInput; + + Digikam::DImg m_img; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* IMAGEEFFECT_SHARPEN_H */ diff --git a/src/imageplugins/coreplugin/sharpnesseditor/matrix.cpp b/src/imageplugins/coreplugin/sharpnesseditor/matrix.cpp new file mode 100644 index 00000000..cfb8afe4 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/matrix.cpp @@ -0,0 +1,663 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-04-29 + * Description : refocus deconvolution matrix implementation. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * Original implementation from Refocus Gimp plug-in + * Copyright (C) 1999-2003 Ernst Lippe + * + * 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. + * + * ============================================================ */ + +// Uncomment this line to debug matrix computation. +//#define RF_DEBUG 1 + +// Square +#define SQR(x) ((x) * (x)) + +// C++ includes. + +#include <cmath> + +extern "C" +{ +#include "f2c.h" +#include "clapack.h" +} + +// TQt includes. + +#include <tqglobal.h> +#include <tqstring.h> + +// Local includes. + +#include "ddebug.h" +#include "matrix.h" + +namespace DigikamImagesPluginCore +{ + +Mat *RefocusMatrix::allocate_matrix (int nrows, int ncols) +{ + Mat *result = new Mat; + memset (result, 0, sizeof(result)); + + result->cols = ncols; + result->rows = nrows; + result->data = new double [nrows * ncols]; + memset (result->data, 0, nrows * ncols * sizeof(double)); + + return (result); +} + +void RefocusMatrix::finish_matrix (Mat * mat) +{ + delete [] mat->data; +} + +void RefocusMatrix::finish_and_free_matrix (Mat * mat) +{ + delete [] mat->data; + delete mat; +} + +double *RefocusMatrix::mat_eltptr (Mat * mat, const int r, const int c) +{ + Q_ASSERT ((r >= 0) && (r < mat->rows)); + Q_ASSERT ((c >= 0) && (c < mat->rows)); + return (&(mat->data[mat->rows * c + r])); +} + +double RefocusMatrix::mat_elt (const Mat * mat, const int r, const int c) +{ + Q_ASSERT ((r >= 0) && (r < mat->rows)); + Q_ASSERT ((c >= 0) && (c < mat->rows)); + return (mat->data[mat->rows * c + r]); +} + +void RefocusMatrix::init_c_mat (CMat * mat, const int radius) +{ + mat->radius = radius; + mat->row_stride = 2 * radius + 1; + mat->data = new double [SQR (mat->row_stride)]; + memset (mat->data, 0, SQR (mat->row_stride) * sizeof(double)); + mat->center = mat->data + mat->row_stride * mat->radius + mat->radius; +} + +CMat *RefocusMatrix::allocate_c_mat (const int radius) +{ + CMat *result = new CMat; + memset(result, 0, sizeof(result)); + init_c_mat (result, radius); + return (result); +} + +void RefocusMatrix::finish_c_mat (CMat * mat) +{ + delete [] mat->data; + mat->data = NULL; +} + +inline double *RefocusMatrix::c_mat_eltptr (CMat * mat, const int col, const int row) +{ + Q_ASSERT ((TQABS (row) <= mat->radius) && (TQABS (col) <= mat->radius)); + return (mat->center + mat->row_stride * row + col); +} + +inline double RefocusMatrix::c_mat_elt (const CMat * const mat, const int col, const int row) +{ + Q_ASSERT ((TQABS (row) <= mat->radius) && (TQABS (col) <= mat->radius)); + return (mat->center[mat->row_stride * row + col]); +} + +void RefocusMatrix::convolve_mat (CMat * result, const CMat * const mata, const CMat * const matb) +{ + int xr, yr, xa, ya; + + for (yr = -result->radius; yr <= result->radius; yr++) + { + for (xr = -result->radius; xr <= result->radius; xr++) + { + const int ya_low = TQMAX (-mata->radius, yr - matb->radius); + const int ya_high = TQMIN (mata->radius, yr + matb->radius); + const int xa_low = TQMAX (-mata->radius, xr - matb->radius); + const int xa_high = TQMIN (mata->radius, xr + matb->radius); + double val = 0.0; + + for (ya = ya_low; ya <= ya_high; ya++) + { + for (xa = xa_low; xa <= xa_high; xa++) + { + val += c_mat_elt (mata, xa, ya) * + c_mat_elt (matb, xr - xa, yr - ya); + } + } + + *c_mat_eltptr (result, xr, yr) = val; + } + } +} + +void RefocusMatrix::convolve_star_mat (CMat * result, const CMat * const mata, const CMat * const matb) +{ + int xr, yr, xa, ya; + + for (yr = -result->radius; yr <= result->radius; yr++) + { + for (xr = -result->radius; xr <= result->radius; xr++) + { + const int ya_low = TQMAX (-mata->radius, -matb->radius - yr); + const int ya_high = TQMIN (mata->radius, matb->radius - yr); + const int xa_low = TQMAX (-mata->radius, -matb->radius - xr); + const int xa_high = TQMIN (mata->radius, matb->radius - xr); + double val = 0.0; + + for (ya = ya_low; ya <= ya_high; ya++) + { + for (xa = xa_low; xa <= xa_high; xa++) + { + val += c_mat_elt (mata, xa, ya) * + c_mat_elt (matb, xr + xa, yr + ya); + } + } + + *c_mat_eltptr (result, xr, yr) = val; + } + } +} + +void RefocusMatrix::convolve_mat_fun (CMat * result, const CMat * const mata, double (f) (int, int)) +{ + int xr, yr, xa, ya; + + for (yr = -result->radius; yr <= result->radius; yr++) + { + for (xr = -result->radius; xr <= result->radius; xr++) + { + double val = 0.0; + + for (ya = -mata->radius; ya <= mata->radius; ya++) + { + for (xa = -mata->radius; xa <= mata->radius; xa++) + { + val += c_mat_elt (mata, xa, ya) * f (xr - xa, yr - ya); + } + } + + *c_mat_eltptr (result, xr, yr) = val; + } + } +} + +int RefocusMatrix::as_idx (const int k, const int l, const int m) +{ + return ((k + m) * (2 * m + 1) + (l + m)); +} + +int RefocusMatrix::as_cidx (const int k, const int l) +{ + const int a = TQMAX (TQABS (k), TQABS (l)); + const int b = TQMIN (TQABS (k), TQABS (l)); + return ((a * (a + 1)) / 2 + b); +} + +void RefocusMatrix::print_c_mat (const CMat * const mat) +{ + int x, y; + + for (y = -mat->radius; y <= mat->radius; y++) + { + TQString output, num; + + for (x = -mat->radius; x <= mat->radius; x++) + { + output.append( num.setNum( c_mat_elt (mat, x, y) ) ); + } + + DDebug() << output << endl; + } +} + +void RefocusMatrix::print_matrix (Mat * matrix) +{ + int col_idx, row_idx; + + for (row_idx = 0; row_idx < matrix->rows; row_idx++) + { + TQString output, num; + + for (col_idx = 0; col_idx < matrix->cols; col_idx++) + { + output.append( num.setNum( mat_elt (matrix, row_idx, col_idx) ) ); + } + + DDebug() << output << endl; + } +} + +Mat *RefocusMatrix::make_s_matrix (CMat * mat, int m, double noise_factor) +{ + const int mat_size = SQR (2 * m + 1); + Mat *result = allocate_matrix (mat_size, mat_size); + int yr, yc, xr, xc; + + for (yr = -m; yr <= m; yr++) + { + for (xr = -m; xr <= m; xr++) + { + for (yc = -m; yc <= m; yc++) + { + for (xc = -m; xc <= m; xc++) + { + *mat_eltptr (result, as_idx (xr, yr, m), + as_idx (xc, yc, m)) = + c_mat_elt (mat, xr - xc, yr - yc); + if ((xr == xc) && (yr == yc)) + { + *mat_eltptr (result, as_idx (xr, yr, m), + as_idx (xc, yc, m)) += noise_factor; + } + } + } + } + } + + return (result); +} + +Mat *RefocusMatrix::make_s_cmatrix (CMat * mat, int m, double noise_factor) +{ + const int mat_size = as_cidx (m + 1, 0); + Mat *result = allocate_matrix (mat_size, mat_size); + int yr, yc, xr, xc; + + for (yr = 0; yr <= m; yr++) + { + for (xr = 0; xr <= yr; xr++) + { + for (yc = -m; yc <= m; yc++) + { + for (xc = -m; xc <= m; xc++) + { + *mat_eltptr (result, as_cidx (xr, yr), as_cidx (xc, yc)) += + c_mat_elt (mat, xr - xc, yr - yc); + if ((xr == xc) && (yr == yc)) + { + *mat_eltptr (result, as_cidx (xr, yr), + as_cidx (xc, yc)) += noise_factor; + } + } + } + } + } + + return (result); +} + +double RefocusMatrix::correlation (const int x, const int y, const double gamma, const double musq) +{ + return (musq + pow (gamma, sqrt (SQR (x) + SQR (y)))); +} + +Mat *RefocusMatrix::copy_vec (const CMat * const mat, const int m) +{ + Mat *result = allocate_matrix (SQR (2 * m + 1), 1); + int x, y, index = 0; + + for (y = -m; y <= m; y++) + { + for (x = -m; x <= m; x++) + { + *mat_eltptr (result, index, 0) = c_mat_elt (mat, x, y); + index++; + } + } + + Q_ASSERT (index == SQR (2 * m + 1)); + return (result); +} + +Mat *RefocusMatrix::copy_cvec (const CMat * const mat, const int m) +{ + Mat *result = allocate_matrix (as_cidx (m + 1, 0), 1); + int x, y, index = 0; + + for (y = 0; y <= m; y++) + { + for (x = 0; x <= y; x++) + { + *mat_eltptr (result, index, 0) = c_mat_elt (mat, x, y); + index++; + } + } + + Q_ASSERT (index == as_cidx (m + 1, 0)); + return (result); +} + +CMat *RefocusMatrix::copy_cvec2mat (const Mat * const cvec, const int m) +{ + CMat *result = allocate_c_mat (m); + int x, y; + + for (y = -m; y <= m; y++) + { + for (x = -m; x <= m; x++) + { + *c_mat_eltptr (result, x, y) = mat_elt (cvec, as_cidx (x, y), 0); + } + } + + return (result); +} + +CMat *RefocusMatrix::copy_vec2mat (const Mat * const cvec, const int m) +{ + CMat *result = allocate_c_mat (m); + int x, y; + + for (y = -m; y <= m; y++) + { + for (x = -m; x <= m; x++) + { + *c_mat_eltptr (result, x, y) = mat_elt (cvec, as_idx (x, y, m), 0); + } + } + + return (result); +} + +CMat *RefocusMatrix::compute_g (const CMat * const convolution, const int m, const double gamma, + const double noise_factor, const double musq, const bool symmetric) +{ + CMat h_conv_ruv, a, corr; + CMat *result; + Mat *b; + Mat *s; + int status; + + init_c_mat (&h_conv_ruv, 3 * m); + fill_matrix2 (&corr, 4 * m, correlation, gamma, musq); + convolve_mat (&h_conv_ruv, convolution, &corr); + init_c_mat (&a, 2 * m); + convolve_star_mat (&a, convolution, &h_conv_ruv); + + if (symmetric) + { + s = make_s_cmatrix (&a, m, noise_factor); + b = copy_cvec (&h_conv_ruv, m); + } + else + { + s = make_s_matrix (&a, m, noise_factor); + b = copy_vec (&h_conv_ruv, m); + } + +#ifdef RF_DEBUG + DDebug() << "Convolution:" << endl; + print_c_mat (convolution); + DDebug() << "h_conv_ruv:" << endl; + print_c_mat (&h_conv_ruv); + DDebug() << "Value of s:" << endl; + print_matrix (s); +#endif + + Q_ASSERT (s->cols == s->rows); + Q_ASSERT (s->rows == b->rows); + status = dgesv (s->rows, 1, s->data, s->rows, b->data, b->rows); + + if (symmetric) + { + result = copy_cvec2mat (b, m); + } + else + { + result = copy_vec2mat (b, m); + } + +#ifdef RF_DEBUG + DDebug() << "Deconvolution:" << endl; + print_c_mat (result); +#endif + + finish_c_mat (&a); + finish_c_mat (&h_conv_ruv); + finish_c_mat (&corr); + finish_and_free_matrix (s); + finish_and_free_matrix (b); + return (result); +} + +CMat *RefocusMatrix::compute_g_matrix (const CMat * const convolution, const int m, + const double gamma, const double noise_factor, + const double musq, const bool symmetric) +{ +#ifdef RF_DEBUG + DDebug() << "matrix size: " << m << endl; + DDebug() << "correlation: " << gamma << endl; + DDebug() << "noise: " << noise_factor << endl; +#endif + + CMat *g = compute_g (convolution, m, gamma, noise_factor, musq, symmetric); + int r, c; + double sum = 0.0; + + /* Determine sum of array */ + for (r = -g->radius; r <= g->radius; r++) + { + for (c = -g->radius; c <= g->radius; c++) + { + sum += c_mat_elt (g, r, c); + } + } + + for (r = -g->radius; r <= g->radius; r++) + { + for (c = -g->radius; c <= g->radius; c++) + { + *c_mat_eltptr (g, r, c) /= sum; + } + } + + return (g); +} + +void RefocusMatrix::fill_matrix (CMat * matrix, const int m, + double f (const int, const int, const double), + const double fun_arg) +{ + int x, y; + init_c_mat (matrix, m); + + for (y = -m; y <= m; y++) + { + for (x = -m; x <= m; x++) + { + *c_mat_eltptr (matrix, x, y) = f (x, y, fun_arg); + } + } +} + +void RefocusMatrix::fill_matrix2 (CMat * matrix, const int m, + double f (const int, const int, const double, const double), + const double fun_arg1, const double fun_arg2) +{ + int x, y; + init_c_mat (matrix, m); + + for (y = -m; y <= m; y++) + { + for (x = -m; x <= m; x++) + { + *c_mat_eltptr (matrix, x, y) = f (x, y, fun_arg1, fun_arg2); + } + } +} + +void RefocusMatrix::make_gaussian_convolution (const double gradius, CMat * convolution, const int m) +{ + int x, y; + +#ifdef RF_DEBUG + DDebug() << "gauss: " << gradius << endl; +#endif + + init_c_mat (convolution, m); + + if (SQR (gradius) <= 1 / 3.40282347e38F) + { + for (y = -m; y <= m; y++) + { + for (x = -m; x <= m; x++) + { + *c_mat_eltptr (convolution, x, y) = 0; + } + } + + *c_mat_eltptr (convolution, 0, 0) = 1; + } + else + { + const double alpha = log (2.0) / SQR (gradius); + + for (y = -m; y <= m; y++) + { + for (x = -m; x <= m; x++) + { + *c_mat_eltptr (convolution, x, y) = + exp (-alpha * (SQR (x) + SQR (y))); + } + } + } +} + +/** Return the integral of sqrt(radius^2 - z^2) for z = 0 to x. */ + +double RefocusMatrix::circle_integral (const double x, const double radius) +{ + if (radius == 0) + { + // Perhaps some epsilon must be added here. + return (0); + } + else + { + const double sin = x / radius; + const double sq_diff = SQR (radius) - SQR (x); + // From a mathematical point of view the following is redundant. + // Numerically they are not equivalent! + + if ((sq_diff < 0.0) || (sin < -1.0) || (sin > 1.0)) + { + if (sin < 0) + { + return (-0.25 * SQR (radius) * M_PI); + } + else + { + return (0.25 * SQR (radius) * M_PI); + } + } + else + { + return (0.5 * x * sqrt (sq_diff) + 0.5 * SQR (radius) * asin (sin)); + } + } +} + +double RefocusMatrix::circle_intensity (const int x, const int y, const double radius) +{ + if (radius == 0) + { + return (((x == 0) && (y == 0)) ? 1 : 0); + } + else + { + double xlo = TQABS (x) - 0.5, xhi = TQABS (x) + 0.5, + ylo = TQABS (y) - 0.5, yhi = TQABS (y) + 0.5; + double symmetry_factor = 1, xc1, xc2; + + if (xlo < 0) + { + xlo = 0; + symmetry_factor *= 2; + } + + if (ylo < 0) + { + ylo = 0; + symmetry_factor *= 2; + } + + if (SQR (xlo) + SQR (yhi) > SQR (radius)) + { + xc1 = xlo; + } + else if (SQR (xhi) + SQR (yhi) > SQR (radius)) + { + xc1 = sqrt (SQR (radius) - SQR (yhi)); + } + else + { + xc1 = xhi; + } + + if (SQR (xlo) + SQR (ylo) > SQR (radius)) + { + xc2 = xlo; + } + else if (SQR (xhi) + SQR (ylo) > SQR (radius)) + { + xc2 = sqrt (SQR (radius) - SQR (ylo)); + } + else + { + xc2 = xhi; + } + + return (((yhi - ylo) * (xc1 - xlo) + + circle_integral (xc2, radius) - circle_integral (xc1, radius) - + (xc2 - xc1) * ylo) * symmetry_factor / (M_PI * SQR (radius))); + } +} + +void RefocusMatrix::make_circle_convolution (const double radius, CMat * convolution, const int m) +{ +#ifdef RF_DEBUG + DDebug() << "radius: " << radius << endl; +#endif + + fill_matrix (convolution, m, circle_intensity, radius); +} + +int RefocusMatrix::dgesv (const int N, const int NRHS, double *A, const int lda, double *B, const int ldb) +{ + int result = 0; + integer i_N = N, i_NHRS = NRHS, i_lda = lda, i_ldb = ldb, info; + integer *ipiv = new integer[N]; + + // Clapack call. + dgesv_ (&i_N, &i_NHRS, A, &i_lda, ipiv, B, &i_ldb, &info); + + delete [] ipiv; + result = info; + return (result); +} + +} // NameSpace DigikamImagesPluginCore diff --git a/src/imageplugins/coreplugin/sharpnesseditor/matrix.h b/src/imageplugins/coreplugin/sharpnesseditor/matrix.h new file mode 100644 index 00000000..6b2f65cb --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/matrix.h @@ -0,0 +1,129 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-04-29 + * Description : refocus deconvolution matrix implementation. + * + * Copyright (C) 2005-2007 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. + * + * ============================================================ */ + +#ifndef MATRIX_H_INCLUDED +#define MATRIX_H_INCLUDED + +// C ++ includes. + +#include <cstdio> + +namespace DigikamImagesPluginCore +{ + +/** +* CMat: +* @radius: Radius of the matrix. +* +* Centered matrix. This is a square matrix where +* the indices range from [-radius, radius]. +* The matrix contains (2 * radius + 1) ** 2 elements. +* +**/ +typedef struct +{ + int radius; // Radius of the matrix + int row_stride; // Size of one row = 2 * radius + 1 + double *data; // Contents of matrix + double *center; // Points to element with index (0, 0) +} +CMat; + +/** +* Mat: +* @rows: Number of rows in the matrix. +* +* Normal matrix type. Indices range from +* [0, rows -1 ] and [0, cols - 1]. +* +**/ +typedef struct +{ + int rows; // Number of rows in the matrix + int cols; // Number of columns in the matrix + double *data; // Content of the matrix +} +Mat; + +class RefocusMatrix +{ + +public: + + static void fill_matrix (CMat * matrix, const int m, double f (int, int, double), const double fun_arg); + + static void fill_matrix2 (CMat * matrix, const int m, + double f (const int, const int, const double, const double), + const double fun_arg1, const double fun_arg2); + + static void make_circle_convolution (const double radius, CMat *convolution, const int m); + + static void make_gaussian_convolution (const double alpha, CMat *convolution, const int m); + + static void convolve_star_mat (CMat *result, const CMat *const mata, const CMat* const matb); + + static CMat *compute_g_matrix (const CMat * const convolution, const int m, + const double gamma, const double noise_factor, + const double musq, const bool symmetric); + + static void finish_matrix (Mat * mat); + static void finish_and_free_matrix (Mat * mat); + static void init_c_mat (CMat * mat, const int radius); + static void finish_c_mat (CMat * mat); + +private: + + // Debug methods. + static void print_c_mat (const CMat * const mat); + static void print_matrix (Mat * matrix); + + static Mat *allocate_matrix (int nrows, int ncols); + static double *mat_eltptr (Mat * mat, const int r, const int c); + static double mat_elt (const Mat * mat, const int r, const int c); + static CMat *allocate_c_mat (const int radius); + static inline double *c_mat_eltptr (CMat * mat, const int col, const int row); + static inline double c_mat_elt (const CMat * const mat, const int col, const int row); + static void convolve_mat (CMat * result, const CMat * const mata, const CMat * const matb); + static void convolve_mat_fun (CMat * result, const CMat * const mata, double (f) (int, int)); + static int as_idx (const int k, const int l, const int m); + static int as_cidx (const int k, const int l); + static Mat *make_s_matrix (CMat * mat, int m, double noise_factor); + static Mat *make_s_cmatrix (CMat * mat, int m, double noise_factor); + static double correlation (const int x, const int y, const double gamma, const double musq); + static Mat *copy_vec (const CMat * const mat, const int m); + static Mat *copy_cvec (const CMat * const mat, const int m); + static CMat *copy_cvec2mat (const Mat * const cvec, const int m); + static CMat *copy_vec2mat (const Mat * const cvec, const int m); + static CMat *compute_g (const CMat * const convolution, const int m, const double gamma, + const double noise_factor, const double musq, const bool symmetric); + static double circle_integral (const double x, const double radius); + static double circle_intensity (const int x, const int y, const double radius); + + // CLapack interface. + static int dgesv (const int N, const int NRHS, double *A, const int lda, double *B, const int ldb); + +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* MATRIX_H_INCLUDED */ diff --git a/src/imageplugins/coreplugin/sharpnesseditor/refocus.cpp b/src/imageplugins/coreplugin/sharpnesseditor/refocus.cpp new file mode 100644 index 00000000..7e99d663 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/refocus.cpp @@ -0,0 +1,199 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : Refocus threaded image filter. + * + * Copyright (C) 2005-2007 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> + +// Local includes. + +#include "ddebug.h" +#include "dimg.h" +#include "dcolor.h" +#include "dimgimagefilters.h" +#include "matrix.h" +#include "refocus.h" + +namespace DigikamImagesPluginCore +{ + +Refocus::Refocus(Digikam::DImg *orgImage, TQObject *parent, int matrixSize, double radius, + double gauss, double correlation, double noise) + : Digikam::DImgThreadedFilter(orgImage, parent, "Refocus") +{ + m_matrixSize = matrixSize; + m_radius = radius; + m_gauss = gauss; + m_correlation = correlation; + m_noise = noise; + initFilter(); +} + +void Refocus::filterImage(void) +{ + refocusImage(m_orgImage.bits(), m_orgImage.width(), m_orgImage.height(), + m_orgImage.sixteenBit(), m_matrixSize, m_radius, m_gauss, + m_correlation, m_noise); +} + +void Refocus::refocusImage(uchar* data, int width, int height, bool sixteenBit, + int matrixSize, double radius, double gauss, + double correlation, double noise) +{ + CMat *matrix=0; + + // Compute matrix + DDebug() << "Refocus::Compute matrix..." << endl; + + CMat circle, gaussian, convolution; + + RefocusMatrix::make_gaussian_convolution (gauss, &gaussian, matrixSize); + RefocusMatrix::make_circle_convolution (radius, &circle, matrixSize); + RefocusMatrix::init_c_mat (&convolution, matrixSize); + RefocusMatrix::convolve_star_mat (&convolution, &gaussian, &circle); + + matrix = RefocusMatrix::compute_g_matrix (&convolution, matrixSize, correlation, noise, 0.0, true); + + RefocusMatrix::finish_c_mat (&convolution); + RefocusMatrix::finish_c_mat (&gaussian); + RefocusMatrix::finish_c_mat (&circle); + + // Apply deconvolution kernel to image. + DDebug() << "Refocus::Apply Matrix to image..." << endl; + convolveImage(data, m_destImage.bits(), width, height, sixteenBit, + matrix->data, 2 * matrixSize + 1); + + // Clean up memory + delete matrix; +} + +void Refocus::convolveImage(uchar *orgData, uchar *destData, int width, int height, + bool sixteenBit, const double *const matrix, int mat_size) +{ + int progress; + unsigned short *orgData16 = (unsigned short *)orgData; + unsigned short *destData16 = (unsigned short *)destData; + + double valRed, valGreen, valBlue; + int x1, y1, x2, y2, index1, index2; + + const int imageSize = width*height; + const int mat_offset = mat_size / 2; + + for (y1 = 0; !m_cancel && (y1 < height); y1++) + { + for (x1 = 0; !m_cancel && (x1 < width); x1++) + { + valRed = valGreen = valBlue = 0.0; + + if (!sixteenBit) // 8 bits image. + { + uchar red, green, blue; + uchar *ptr; + + for (y2 = 0; !m_cancel && (y2 < mat_size); y2++) + { + for (x2 = 0; !m_cancel && (x2 < mat_size); x2++) + { + index1 = width * (y1 + y2 - mat_offset) + + x1 + x2 - mat_offset; + + if ( index1 >= 0 && index1 < imageSize ) + { + ptr = &orgData[index1*4]; + blue = ptr[0]; + green = ptr[1]; + red = ptr[2]; + const double matrixValue = matrix[y2 * mat_size + x2]; + valRed += matrixValue * red; + valGreen += matrixValue * green; + valBlue += matrixValue * blue; + } + } + } + + index2 = y1 * width + x1; + + if (index2 >= 0 && index2 < imageSize) + { + // To get Alpha channel value from original (unchanged) + memcpy (&destData[index2*4], &orgData[index2*4], 4); + ptr = &destData[index2*4]; + + // Overwrite RGB values to destination. + ptr[0] = (uchar) CLAMP (valBlue, 0, 255); + ptr[1] = (uchar) CLAMP (valGreen, 0, 255); + ptr[2] = (uchar) CLAMP (valRed, 0, 255); + } + } + else // 16 bits image. + { + unsigned short red, green, blue; + unsigned short *ptr; + + for (y2 = 0; !m_cancel && (y2 < mat_size); y2++) + { + for (x2 = 0; !m_cancel && (x2 < mat_size); x2++) + { + index1 = width * (y1 + y2 - mat_offset) + + x1 + x2 - mat_offset; + + if ( index1 >= 0 && index1 < imageSize ) + { + ptr = &orgData16[index1*4]; + blue = ptr[0]; + green = ptr[1]; + red = ptr[2]; + const double matrixValue = matrix[y2 * mat_size + x2]; + valRed += matrixValue * red; + valGreen += matrixValue * green; + valBlue += matrixValue * blue; + } + } + } + + index2 = y1 * width + x1; + + if (index2 >= 0 && index2 < imageSize) + { + // To get Alpha channel value from original (unchanged) + memcpy (&destData16[index2*4], &orgData16[index2*4], 8); + ptr = &destData16[index2*4]; + + // Overwrite RGB values to destination. + ptr[0] = (unsigned short) CLAMP (valBlue, 0, 65535); + ptr[1] = (unsigned short) CLAMP (valGreen, 0, 65535); + ptr[2] = (unsigned short) CLAMP (valRed, 0, 65535); + } + } + } + + // Update the progress bar in dialog. + progress = (int)(((double)y1 * 100.0) / height); + if (progress%5 == 0) + postProgress( progress ); + } +} + +} // NameSpace DigikamImagesPluginCore + diff --git a/src/imageplugins/coreplugin/sharpnesseditor/refocus.h b/src/imageplugins/coreplugin/sharpnesseditor/refocus.h new file mode 100644 index 00000000..323b24b9 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/refocus.h @@ -0,0 +1,67 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : Refocus threaded image filter. + * + * Copyright (C) 2005-2007 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. + * + * ============================================================ */ + +#ifndef REFOCUS_H +#define REFOCUS_H + +// Local includes. + +#include "dimgthreadedfilter.h" + +namespace DigikamImagesPluginCore +{ + +class Refocus : public Digikam::DImgThreadedFilter +{ + +public: + + Refocus(Digikam::DImg *orgImage, TQObject *parent=0, int matrixSize=5, double radius=0.9, + double gauss=0.0, double correlation=0.5, double noise=0.01); + + ~Refocus(){}; + +private: // Refocus filter methods. + + virtual void filterImage(void); + + void refocusImage(uchar* data, int width, int height, bool sixteenBit, + int matrixSize, double radius, double gauss, + double correlation, double noise); + + void convolveImage(uchar *orgData, uchar *destData, int width, int height, + bool sixteenBit, const double *const matrix, int mat_size); + +private: // Refocus filter data. + + int m_matrixSize; + + double m_radius; + double m_gauss; + double m_correlation; + double m_noise; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* REFOCUS_H */ diff --git a/src/imageplugins/coreplugin/sharpnesseditor/sharpentool.cpp b/src/imageplugins/coreplugin/sharpnesseditor/sharpentool.cpp new file mode 100644 index 00000000..aee5d841 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/sharpentool.cpp @@ -0,0 +1,741 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-09 + * Description : a tool to sharp an image + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#define MAX_MATRIX_SIZE 25 + +// C++ includes. + +#include <cmath> + +// TQt includes. + +#include <tqlayout.h> +#include <tqlabel.h> +#include <tqwhatsthis.h> +#include <tqwidgetstack.h> + +// KDE includes. + +#include <tdeaboutdata.h> +#include <kcursor.h> +#include <tdelocale.h> +#include <tdeapplication.h> +#include <kseparator.h> +#include <tdeconfig.h> +#include <kurl.h> +#include <kiconloader.h> +#include <tdefiledialog.h> +#include <tdeglobalsettings.h> +#include <tdemessagebox.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> +#include <libkdcraw/rcombobox.h> + +// Local includes. + +#include "ddebug.h" +#include "imageiface.h" +#include "imagepanelwidget.h" +#include "editortoolsettings.h" +#include "dimgsharpen.h" +#include "unsharp.h" +#include "refocus.h" +#include "sharpentool.h" +#include "sharpentool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamImagesPluginCore +{ + +SharpenTool::SharpenTool(TQObject* parent) + : EditorToolThreaded(parent) +{ + setName("sharpen"); + setToolName(i18n("Sharpen")); + setToolIcon(SmallIcon("sharpenimage")); + setToolHelp("blursharpentool.anchor"); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel| + EditorToolSettings::Load| + EditorToolSettings::SaveAs| + EditorToolSettings::Try, + EditorToolSettings::PanIcon); + TQGridLayout* grid = new TQGridLayout( m_gboxSettings->plainPage(), 3, 1); + + TQLabel *label1 = new TQLabel(i18n("Method:"), m_gboxSettings->plainPage()); + + m_sharpMethod = new RComboBox(m_gboxSettings->plainPage()); + m_sharpMethod->insertItem( i18n("Simple sharp") ); + m_sharpMethod->insertItem( i18n("Unsharp mask") ); + m_sharpMethod->insertItem( i18n("Refocus") ); + m_sharpMethod->setDefaultItem(SimpleSharp); + TQWhatsThis::add( m_sharpMethod, i18n("<p>Select the sharpening method to apply to the image.")); + + m_stack = new TQWidgetStack(m_gboxSettings->plainPage()); + + grid->addMultiCellWidget(label1, 0, 0, 0, 0); + grid->addMultiCellWidget(m_sharpMethod, 0, 0, 1, 1); + grid->addMultiCellWidget(new KSeparator(m_gboxSettings->plainPage()), 1, 1, 0, 1); + grid->addMultiCellWidget(m_stack, 2, 2, 0, 1); + grid->setRowStretch(3, 10); + grid->setMargin(m_gboxSettings->spacingHint()); + grid->setSpacing(m_gboxSettings->spacingHint()); + + // ------------------------------------------------------------- + + TQWidget *simpleSharpSettings = new TQWidget(m_stack); + TQGridLayout* grid1 = new TQGridLayout( simpleSharpSettings, 2, 1); + + TQLabel *label = new TQLabel(i18n("Sharpness:"), simpleSharpSettings); + m_radiusInput = new RIntNumInput(simpleSharpSettings); + m_radiusInput->setRange(0, 100, 1); + m_radiusInput->setDefaultValue(0); + TQWhatsThis::add( m_radiusInput, i18n("<p>A sharpness of 0 has no effect, " + "1 and above determine the sharpen matrix radius " + "that determines how much to sharpen the image.")); + + grid1->addMultiCellWidget(label, 0, 0, 0, 1); + grid1->addMultiCellWidget(m_radiusInput, 1, 1, 0, 1); + grid1->setRowStretch(2, 10); + grid1->setMargin(0); + grid1->setSpacing(0); + + m_stack->addWidget(simpleSharpSettings, SimpleSharp); + + // ------------------------------------------------------------- + + TQWidget *unsharpMaskSettings = new TQWidget(m_stack); + TQGridLayout* grid2 = new TQGridLayout( unsharpMaskSettings, 6, 1); + + TQLabel *label2 = new TQLabel(i18n("Radius:"), unsharpMaskSettings); + m_radiusInput2 = new RIntNumInput(unsharpMaskSettings); + m_radiusInput2->setRange(1, 120, 1); + m_radiusInput2->setDefaultValue(1); + TQWhatsThis::add( m_radiusInput2, i18n("<p>Radius value is the gaussian blur matrix radius value " + "used to determines how much to blur the image.") ); + + TQLabel *label3 = new TQLabel(i18n("Amount:"), unsharpMaskSettings); + m_amountInput = new RDoubleNumInput(unsharpMaskSettings); + m_amountInput->setPrecision(1); + m_amountInput->setRange(0.0, 5.0, 0.1); + m_amountInput->setDefaultValue(1.0); + TQWhatsThis::add( m_amountInput, i18n("<p>The value of the difference between the " + "original and the blur image that is added back into the original.") ); + + TQLabel *label4 = new TQLabel(i18n("Threshold:"), unsharpMaskSettings); + m_thresholdInput = new RDoubleNumInput(unsharpMaskSettings); + m_thresholdInput->setPrecision(2); + m_thresholdInput->setRange(0.0, 1.0, 0.01); + m_thresholdInput->setDefaultValue(0.05); + TQWhatsThis::add( m_thresholdInput, i18n("<p>The threshold, as a fraction of the maximum " + "luminosity value, needed to apply the difference amount.") ); + + grid2->addMultiCellWidget(label2, 0, 0, 0, 1); + grid2->addMultiCellWidget(m_radiusInput2, 1, 1, 0, 1); + grid2->addMultiCellWidget(label3, 2, 2, 0, 1); + grid2->addMultiCellWidget(m_amountInput, 3, 3, 0, 1); + grid2->addMultiCellWidget(label4, 4, 4, 0, 1); + grid2->addMultiCellWidget(m_thresholdInput, 5, 5, 0, 1); + grid2->setRowStretch(6, 10); + grid2->setMargin(0); + grid2->setSpacing(0); + + m_stack->addWidget(unsharpMaskSettings, UnsharpMask); + + // ------------------------------------------------------------- + + TQWidget *refocusSettings = new TQWidget(m_stack); + TQGridLayout* grid3 = new TQGridLayout(refocusSettings, 10, 1); + + TQLabel *label5 = new TQLabel(i18n("Circular sharpness:"), refocusSettings); + m_radius = new RDoubleNumInput(refocusSettings); + m_radius->setPrecision(2); + m_radius->setRange(0.0, 5.0, 0.01); + m_radius->setDefaultValue(1.0); + TQWhatsThis::add( m_radius, i18n("<p>This is the radius of the circular convolution. It is the most important " + "parameter for using this plugin. For most images the default value of 1.0 " + "should give good results. Select a higher value when your image is very blurred.")); + + TQLabel *label6 = new TQLabel(i18n("Correlation:"), refocusSettings); + m_correlation = new RDoubleNumInput(refocusSettings); + m_correlation->setPrecision(2); + m_correlation->setRange(0.0, 1.0, 0.01); + m_correlation->setDefaultValue(0.5); + TQWhatsThis::add( m_correlation, i18n("<p>Increasing the correlation may help to reduce artifacts. The correlation can " + "range from 0-1. Useful values are 0.5 and values close to 1, e.g. 0.95 and 0.99. " + "Using a high value for the correlation will reduce the sharpening effect of the " + "plugin.")); + + TQLabel *label7 = new TQLabel(i18n("Noise filter:"), refocusSettings); + m_noise = new RDoubleNumInput(refocusSettings); + m_noise->setPrecision(3); + m_noise->setRange(0.0, 1.0, 0.001); + m_noise->setDefaultValue(0.03); + TQWhatsThis::add( m_noise, i18n("<p>Increasing the noise filter parameter may help to reduce artifacts. The noise filter " + "can range from 0-1 but values higher than 0.1 are rarely helpful. When the noise filter " + "value is too low, e.g. 0.0 the image quality will be very poor. A useful value is 0.01. " + "Using a high value for the noise filter will reduce the sharpening " + "effect of the plugin.")); + + TQLabel *label8 = new TQLabel(i18n("Gaussian sharpness:"), refocusSettings); + m_gauss = new RDoubleNumInput(refocusSettings); + m_gauss->setPrecision(2); + m_gauss->setRange(0.0, 1.0, 0.01); + m_gauss->setDefaultValue(0.0); + TQWhatsThis::add( m_gauss, i18n("<p>This is the sharpness for the gaussian convolution. Use this parameter when your " + "blurring is of a Gaussian type. In most cases you should set this parameter to 0, because " + "it causes nasty artifacts. When you use non-zero values, you will probably have to " + "increase the correlation and/or noise filter parameters too.")); + + TQLabel *label9 = new TQLabel(i18n("Matrix size:"), refocusSettings); + m_matrixSize = new RIntNumInput(refocusSettings); + m_matrixSize->setRange(0, MAX_MATRIX_SIZE, 1); + m_matrixSize->setDefaultValue(5); + TQWhatsThis::add( m_matrixSize, i18n("<p>This parameter determines the size of the transformation matrix. " + "Increasing the matrix width may give better results, especially when you have " + "chosen large values for circular or gaussian sharpness.")); + + grid3->addMultiCellWidget(label5, 0, 0, 0, 1); + grid3->addMultiCellWidget(m_radius, 1, 1, 0, 1); + grid3->addMultiCellWidget(label6, 2, 2, 0, 1); + grid3->addMultiCellWidget(m_correlation, 3, 3, 0, 1); + grid3->addMultiCellWidget(label7, 4, 4, 0, 1); + grid3->addMultiCellWidget(m_noise, 5, 5, 0, 1); + grid3->addMultiCellWidget(label8, 6, 6, 0, 1); + grid3->addMultiCellWidget(m_gauss, 7, 7, 0, 1); + grid3->addMultiCellWidget(label9, 8, 8, 0, 1); + grid3->addMultiCellWidget(m_matrixSize, 9, 9, 0, 1); + grid3->setRowStretch(10, 10); + grid3->setMargin(0); + grid3->setSpacing(0); + + m_stack->addWidget(refocusSettings, Refocus); + + setToolSettings(m_gboxSettings); + + m_previewWidget = new ImagePanelWidget(470, 350, "sharpen Tool", m_gboxSettings->panIconView()); + + setToolView(m_previewWidget); + init(); + + // ------------------------------------------------------------- + + connect(m_sharpMethod, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotSharpMethodActived(int))); + + // ------------------------------------------------------------- + + // Image creation with dummy borders (mosaic mode) used by Refocus method. It needs to do + // it before to apply deconvolution filter on original image border pixels including + // on matrix size area. This way limit artifacts on image border. + + ImageIface iface(0, 0); + + uchar* data = iface.getOriginalImage(); + int w = iface.originalWidth(); + int h = iface.originalHeight(); + bool sb = iface.originalSixteenBit(); + bool a = iface.originalHasAlpha(); + + m_img = DImg( w + 4*MAX_MATRIX_SIZE, h + 4*MAX_MATRIX_SIZE, sb, a); + + DImg tmp; + DImg org(w, h, sb, a, data); + + // Copy original. + m_img.bitBltImage(&org, 2*MAX_MATRIX_SIZE, 2*MAX_MATRIX_SIZE); + + // Create dummy top border + tmp = org.copy(0, 0, w, 2*MAX_MATRIX_SIZE); + tmp.flip(DImg::VERTICAL); + m_img.bitBltImage(&tmp, 2*MAX_MATRIX_SIZE, 0); + + // Create dummy bottom border + tmp = org.copy(0, h-2*MAX_MATRIX_SIZE, w, 2*MAX_MATRIX_SIZE); + tmp.flip(DImg::VERTICAL); + m_img.bitBltImage(&tmp, 2*MAX_MATRIX_SIZE, 2*MAX_MATRIX_SIZE+h); + + // Create dummy left border + tmp = org.copy(0, 0, 2*MAX_MATRIX_SIZE, h); + tmp.flip(DImg::HORIZONTAL); + m_img.bitBltImage(&tmp, 0, 2*MAX_MATRIX_SIZE); + + // Create dummy right border + tmp = org.copy(w-2*MAX_MATRIX_SIZE, 0, 2*MAX_MATRIX_SIZE, h); + tmp.flip(DImg::HORIZONTAL); + m_img.bitBltImage(&tmp, w+2*MAX_MATRIX_SIZE, 2*MAX_MATRIX_SIZE); + + // Create dummy top/left corner + tmp = org.copy(0, 0, 2*MAX_MATRIX_SIZE, 2*MAX_MATRIX_SIZE); + tmp.flip(DImg::HORIZONTAL); + tmp.flip(DImg::VERTICAL); + m_img.bitBltImage(&tmp, 0, 0); + + // Create dummy top/right corner + tmp = org.copy(w-2*MAX_MATRIX_SIZE, 0, 2*MAX_MATRIX_SIZE, 2*MAX_MATRIX_SIZE); + tmp.flip(DImg::HORIZONTAL); + tmp.flip(DImg::VERTICAL); + m_img.bitBltImage(&tmp, w+2*MAX_MATRIX_SIZE, 0); + + // Create dummy bottom/left corner + tmp = org.copy(0, h-2*MAX_MATRIX_SIZE, 2*MAX_MATRIX_SIZE, 2*MAX_MATRIX_SIZE); + tmp.flip(DImg::HORIZONTAL); + tmp.flip(DImg::VERTICAL); + m_img.bitBltImage(&tmp, 0, h+2*MAX_MATRIX_SIZE); + + // Create dummy bottom/right corner + tmp = org.copy(w-2*MAX_MATRIX_SIZE, h-2*MAX_MATRIX_SIZE, 2*MAX_MATRIX_SIZE, 2*MAX_MATRIX_SIZE); + tmp.flip(DImg::HORIZONTAL); + tmp.flip(DImg::VERTICAL); + m_img.bitBltImage(&tmp, w+2*MAX_MATRIX_SIZE, h+2*MAX_MATRIX_SIZE); + + delete [] data; +} + +SharpenTool::~SharpenTool() +{ +} + +void SharpenTool::renderingFinished() +{ + switch (m_stack->id(m_stack->visibleWidget())) + { + case SimpleSharp: + { + m_radiusInput->setEnabled(true); + m_gboxSettings->enableButton(EditorToolSettings::Load, false); + m_gboxSettings->enableButton(EditorToolSettings::SaveAs, false); + break; + } + + case UnsharpMask: + { + m_radiusInput2->setEnabled(true); + m_amountInput->setEnabled(true); + m_thresholdInput->setEnabled(true); + m_gboxSettings->enableButton(EditorToolSettings::Load, false); + m_gboxSettings->enableButton(EditorToolSettings::SaveAs, false); + break; + } + + case Refocus: + { + m_matrixSize->setEnabled(true); + m_radius->setEnabled(true); + m_gauss->setEnabled(true); + m_correlation->setEnabled(true); + m_noise->setEnabled(true); + break; + } + } +} + +void SharpenTool::slotSharpMethodActived(int w) +{ + m_stack->raiseWidget(w); + if (w == Refocus) + { + m_gboxSettings->enableButton(EditorToolSettings::Load, true); + m_gboxSettings->enableButton(EditorToolSettings::SaveAs, true); + } + else + { + m_gboxSettings->enableButton(EditorToolSettings::Load, false); + m_gboxSettings->enableButton(EditorToolSettings::SaveAs, false); + } +} + +void SharpenTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("sharpen Tool"); + m_radiusInput->blockSignals(true); + m_radiusInput2->blockSignals(true); + m_amountInput->blockSignals(true); + m_thresholdInput->blockSignals(true); + m_matrixSize->blockSignals(true); + m_radius->blockSignals(true); + m_gauss->blockSignals(true); + m_correlation->blockSignals(true); + m_noise->blockSignals(true); + m_sharpMethod->blockSignals(true); + + m_radiusInput->setValue(config->readNumEntry("SimpleSharpRadiusAjustment", m_radiusInput->defaultValue())); + m_radiusInput2->setValue(config->readNumEntry("UnsharpMaskRadiusAjustment", m_radiusInput2->defaultValue())); + m_amountInput->setValue(config->readDoubleNumEntry("UnsharpMaskAmountAjustment", m_amountInput->defaultValue())); + m_thresholdInput->setValue(config->readDoubleNumEntry("UnsharpMaskThresholdAjustment", m_thresholdInput->defaultValue())); + m_matrixSize->setValue(config->readNumEntry("RefocusMatrixSize", m_matrixSize->defaultValue())); + m_radius->setValue(config->readDoubleNumEntry("RefocusRadiusAjustment", m_radius->defaultValue())); + m_gauss->setValue(config->readDoubleNumEntry("RefocusGaussAjustment", m_gauss->defaultValue())); + m_correlation->setValue(config->readDoubleNumEntry("RefocusCorrelationAjustment", m_correlation->defaultValue())); + m_noise->setValue(config->readDoubleNumEntry("RefocusNoiseAjustment", m_noise->defaultValue())); + m_sharpMethod->setCurrentItem(config->readNumEntry("SharpenMethod", SimpleSharp)); + + m_radiusInput->blockSignals(false); + m_radiusInput2->blockSignals(false); + m_amountInput->blockSignals(false); + m_thresholdInput->blockSignals(false); + m_matrixSize->blockSignals(false); + m_radius->blockSignals(false); + m_gauss->blockSignals(false); + m_correlation->blockSignals(false); + m_noise->blockSignals(false); + m_sharpMethod->blockSignals(false); + + slotSharpMethodActived(m_sharpMethod->currentItem()); +} + +void SharpenTool::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("sharpen Tool"); + config->writeEntry("SimpleSharpRadiusAjustment", m_radiusInput->value()); + config->writeEntry("UnsharpMaskRadiusAjustment", m_radiusInput2->value()); + config->writeEntry("UnsharpMaskAmountAjustment", m_amountInput->value()); + config->writeEntry("UnsharpMaskThresholdAjustment", m_thresholdInput->value()); + config->writeEntry("RefocusMatrixSize", m_matrixSize->value()); + config->writeEntry("RefocusRadiusAjustment", m_radius->value()); + config->writeEntry("RefocusGaussAjustment", m_gauss->value()); + config->writeEntry("RefocusCorrelationAjustment", m_correlation->value()); + config->writeEntry("RefocusNoiseAjustment", m_noise->value()); + config->writeEntry("SharpenMethod", m_sharpMethod->currentItem()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void SharpenTool::slotResetSettings() +{ + switch (m_stack->id(m_stack->visibleWidget())) + { + case SimpleSharp: + { + m_radiusInput->blockSignals(true); + m_radiusInput->slotReset(); + m_radiusInput->blockSignals(false); + break; + } + + case UnsharpMask: + { + m_radiusInput2->blockSignals(true); + m_amountInput->blockSignals(true); + m_thresholdInput->blockSignals(true); + + m_radiusInput2->slotReset(); + m_amountInput->slotReset(); + m_thresholdInput->slotReset(); + + m_radiusInput2->blockSignals(false); + m_amountInput->blockSignals(false); + m_thresholdInput->blockSignals(false); + break; + } + + case Refocus: + { + m_matrixSize->blockSignals(true); + m_radius->blockSignals(true); + m_gauss->blockSignals(true); + m_correlation->blockSignals(true); + m_noise->blockSignals(true); + + m_matrixSize->slotReset(); + m_radius->slotReset(); + m_gauss->slotReset(); + m_correlation->slotReset(); + m_noise->slotReset(); + + m_matrixSize->blockSignals(false); + m_radius->blockSignals(false); + m_gauss->blockSignals(false); + m_correlation->blockSignals(false); + m_noise->blockSignals(false); + break; + } + } +} + +void SharpenTool::prepareEffect() +{ + switch (m_stack->id(m_stack->visibleWidget())) + { + case SimpleSharp: + { + m_radiusInput->setEnabled(false); + + DImg img = m_previewWidget->getOriginalRegionImage(); + + double radius = m_radiusInput->value()/10.0; + double sigma; + + if (radius < 1.0) sigma = radius; + else sigma = sqrt(radius); + + setFilter(dynamic_cast<DImgThreadedFilter*>(new DImgSharpen(&img, this, radius, sigma ))); + break; + } + + case UnsharpMask: + { + m_radiusInput2->setEnabled(false); + m_amountInput->setEnabled(false); + m_thresholdInput->setEnabled(false); + + DImg img = m_previewWidget->getOriginalRegionImage(); + + int r = m_radiusInput2->value(); + double a = m_amountInput->value(); + double th = m_thresholdInput->value(); + + setFilter(dynamic_cast<DImgThreadedFilter*>(new DigikamImagesPluginCore::UnsharpMask(&img, this, r, a, th))); + break; + } + + case Refocus: + { + m_matrixSize->setEnabled(false); + m_radius->setEnabled(false); + m_gauss->setEnabled(false); + m_correlation->setEnabled(false); + m_noise->setEnabled(false); + + int ms = m_matrixSize->value(); + double r = m_radius->value(); + double g = m_gauss->value(); + double c = m_correlation->value(); + double n = m_noise->value(); + + TQRect area = m_previewWidget->getOriginalImageRegionToRender(); + TQRect tmpRect; + tmpRect.setLeft(area.left()-2*ms); + tmpRect.setRight(area.right()+2*ms); + tmpRect.setTop(area.top()-2*ms); + tmpRect.setBottom(area.bottom()+2*ms); + tmpRect.moveBy(2*MAX_MATRIX_SIZE, 2*MAX_MATRIX_SIZE); + DImg imTemp = m_img.copy(tmpRect); + + setFilter(dynamic_cast<DImgThreadedFilter*>(new DigikamImagesPluginCore::Refocus(&imTemp, this, ms, r, g, c, n))); + break; + } + } +} + +void SharpenTool::prepareFinal() +{ + switch (m_stack->id(m_stack->visibleWidget())) + { + case SimpleSharp: + { + m_radiusInput->setEnabled(false); + + double radius = m_radiusInput->value()/10.0; + double sigma; + + if (radius < 1.0) sigma = radius; + else sigma = sqrt(radius); + + ImageIface iface(0, 0); + uchar *data = iface.getOriginalImage(); + int w = iface.originalWidth(); + int h = iface.originalHeight(); + bool sixteenBit = iface.originalSixteenBit(); + bool hasAlpha = iface.originalHasAlpha(); + DImg orgImage = DImg(w, h, sixteenBit, hasAlpha ,data); + delete [] data; + setFilter(dynamic_cast<DImgThreadedFilter*>(new DImgSharpen(&orgImage, this, radius, sigma ))); + break; + } + + case UnsharpMask: + { + m_radiusInput2->setEnabled(false); + m_amountInput->setEnabled(false); + m_thresholdInput->setEnabled(false); + + int r = m_radiusInput2->value(); + double a = m_amountInput->value(); + double th = m_thresholdInput->value(); + + ImageIface iface(0, 0); + uchar *data = iface.getOriginalImage(); + int w = iface.originalWidth(); + int h = iface.originalHeight(); + bool sixteenBit = iface.originalSixteenBit(); + bool hasAlpha = iface.originalHasAlpha(); + DImg orgImage = DImg(w, h, sixteenBit, hasAlpha ,data); + delete [] data; + setFilter(dynamic_cast<DImgThreadedFilter*>(new DigikamImagesPluginCore::UnsharpMask(&orgImage, this, r, a, th))); + break; + } + + case Refocus: + { + + m_matrixSize->setEnabled(false); + m_radius->setEnabled(false); + m_gauss->setEnabled(false); + m_correlation->setEnabled(false); + m_noise->setEnabled(false); + + int ms = m_matrixSize->value(); + double r = m_radius->value(); + double g = m_gauss->value(); + double c = m_correlation->value(); + double n = m_noise->value(); + + setFilter(dynamic_cast<DImgThreadedFilter*>(new DigikamImagesPluginCore::Refocus(&m_img, this, ms, r, g, c, n))); + break; + } + } +} + +void SharpenTool::putPreviewData() +{ + switch (m_stack->id(m_stack->visibleWidget())) + { + case SimpleSharp: + case UnsharpMask: + { + DImg imDest = filter()->getTargetImage(); + m_previewWidget->setPreviewImage(imDest); + break; + } + + case Refocus: + { + int ms = m_matrixSize->value(); + TQRect area = m_previewWidget->getOriginalImageRegionToRender(); + + DImg imDest = filter()->getTargetImage() + .copy(2*ms, 2*ms, area.width(), area.height()); + m_previewWidget->setPreviewImage(imDest); + break; + } + } +} + +void SharpenTool::putFinalData() +{ + ImageIface iface(0, 0); + DImg imDest = filter()->getTargetImage(); + + switch (m_stack->id(m_stack->visibleWidget())) + { + case SimpleSharp: + { + iface.putOriginalImage(i18n("Sharpen"), imDest.bits()); + break; + } + + case UnsharpMask: + { + iface.putOriginalImage(i18n("Unsharp Mask"), imDest.bits()); + break; + } + + case Refocus: + { + TQRect area = m_previewWidget->getOriginalImageRegionToRender(); + ImageIface iface(0, 0); + + iface.putOriginalImage(i18n("Refocus"), filter()->getTargetImage() + .copy(2*MAX_MATRIX_SIZE, 2*MAX_MATRIX_SIZE, + iface.originalWidth(), + iface.originalHeight()) + .bits()); + break; + } + } +} + +void SharpenTool::slotLoadSettings() +{ + KURL loadRestorationFile = KFileDialog::getOpenURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), kapp->activeWindow(), + TQString( i18n("Photograph Refocus Settings File to Load")) ); + if ( loadRestorationFile.isEmpty() ) + return; + + TQFile file(loadRestorationFile.path()); + + if ( file.open(IO_ReadOnly) ) + { + TQTextStream stream( &file ); + if ( stream.readLine() != "# Photograph Refocus Configuration File" ) + { + KMessageBox::error(kapp->activeWindow(), + i18n("\"%1\" is not a Photograph Refocus settings text file.") + .arg(loadRestorationFile.fileName())); + file.close(); + return; + } + + blockSignals(true); + m_matrixSize->setValue( stream.readLine().toInt() ); + m_radius->setValue( stream.readLine().toDouble() ); + m_gauss->setValue( stream.readLine().toDouble() ); + m_correlation->setValue( stream.readLine().toDouble() ); + m_noise->setValue( stream.readLine().toDouble() ); + blockSignals(false); + } + else + KMessageBox::error(kapp->activeWindow(), i18n("Cannot load settings from the Photograph Refocus text file.")); + + file.close(); +} + +void SharpenTool::slotSaveAsSettings() +{ + KURL saveRestorationFile = KFileDialog::getSaveURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), kapp->activeWindow(), + TQString( i18n("Photograph Refocus Settings File to Save")) ); + if ( saveRestorationFile.isEmpty() ) + return; + + TQFile file(saveRestorationFile.path()); + + if ( file.open(IO_WriteOnly) ) + { + TQTextStream stream( &file ); + stream << "# Photograph Refocus Configuration File\n"; + stream << m_matrixSize->value() << "\n"; + stream << m_radius->value() << "\n"; + stream << m_gauss->value() << "\n"; + stream << m_correlation->value() << "\n"; + stream << m_noise->value() << "\n"; + } + else + KMessageBox::error(kapp->activeWindow(), i18n("Cannot save settings to the Photograph Refocus text file.")); + + file.close(); +} + +} // NameSpace DigikamImagesPluginCore diff --git a/src/imageplugins/coreplugin/sharpnesseditor/sharpentool.h b/src/imageplugins/coreplugin/sharpnesseditor/sharpentool.h new file mode 100644 index 00000000..8dbca1c5 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/sharpentool.h @@ -0,0 +1,111 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-09 + * Description : a tool to sharp an image + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef SHARPENTOOL_H +#define SHARPENTOOL_H + +// Digikam includes. + +#include "editortool.h" + +class TQWidgetStack; + +namespace KDcrawIface +{ +class RIntNumInput; +class RDoubleNumInput; +class RComboBox; +} + +namespace Digikam +{ +class DImg; +class EditorToolSettings; +class ImagePanelWidget; +} + +namespace DigikamImagesPluginCore +{ + +class SharpenTool : public Digikam::EditorToolThreaded +{ + TQ_OBJECT + + +public: + + SharpenTool(TQObject *parent); + ~SharpenTool(); + +private slots: + + void slotSaveAsSettings(); + void slotLoadSettings(); + void slotResetSettings(); + void slotSharpMethodActived(int); + +private: + + void readSettings(); + void writeSettings(); + void prepareEffect(); + void prepareFinal(); + void abortPreview(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + enum SharpingMethods + { + SimpleSharp=0, + UnsharpMask, + Refocus + }; + + TQWidgetStack *m_stack; + + KDcrawIface::RComboBox *m_sharpMethod; + + KDcrawIface::RIntNumInput *m_matrixSize; + KDcrawIface::RIntNumInput *m_radiusInput; + KDcrawIface::RIntNumInput *m_radiusInput2; + + KDcrawIface::RDoubleNumInput *m_radius; + KDcrawIface::RDoubleNumInput *m_gauss; + KDcrawIface::RDoubleNumInput *m_correlation; + KDcrawIface::RDoubleNumInput *m_noise; + KDcrawIface::RDoubleNumInput *m_amountInput; + KDcrawIface::RDoubleNumInput *m_thresholdInput; + + Digikam::DImg m_img; + + Digikam::ImagePanelWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* SHARPENTOOL_H */ diff --git a/src/imageplugins/coreplugin/sharpnesseditor/unsharp.cpp b/src/imageplugins/coreplugin/sharpnesseditor/unsharp.cpp new file mode 100644 index 00000000..fb1b9d21 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/unsharp.cpp @@ -0,0 +1,127 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : Unsharp Mask threaded image filter. + * + * Copyright (C) 2005-2007 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> +#include <cstdlib> + +// Local includes. + +#include "ddebug.h" +#include "dimg.h" +#include "dcolor.h" +#include "dimgimagefilters.h" +#include "dimggaussianblur.h" +#include "unsharp.h" + +namespace DigikamImagesPluginCore +{ + +UnsharpMask::UnsharpMask(Digikam::DImg *orgImage, TQObject *parent, int radius, + double amount, double threshold) + : DImgThreadedFilter(orgImage, parent, "UnsharpMask") +{ + m_radius = radius; + m_amount = amount; + m_threshold = threshold; + initFilter(); +} + +void UnsharpMask::filterImage(void) +{ + int progress; + int quantum; + double quantumThreshold; + double value; + Digikam::DColor p; + Digikam::DColor q; + + if (m_orgImage.isNull()) + { + DWarning() << k_funcinfo << "No image data available!" << endl; + return; + } + + Digikam::DImgGaussianBlur(this, m_orgImage, m_destImage, 0, 10, (int)(m_radius)); + + quantum = m_destImage.sixteenBit() ? 65535 : 255; + quantumThreshold = quantum*m_threshold; + + for (uint y = 0 ; !m_cancel && (y < m_destImage.height()) ; y++) + { + for (uint x = 0 ; !m_cancel && (x < m_destImage.width()) ; x++) + { + p = m_orgImage.getPixelColor(x, y); + q = m_destImage.getPixelColor(x, y); + + // Red channel. + value = (double)(p.red())-(double)(q.red()); + + if (fabs(2.0*value) < quantumThreshold) + value = (double)(p.red()); + else + value = (double)(p.red()) + value*m_amount; + + q.setRed(CLAMP(ROUND(value), 0, quantum)); + + // Green Channel. + value = (double)(p.green())-(double)(q.green()); + + if (fabs(2.0*value) < quantumThreshold) + value = (double)(p.green()); + else + value = (double)(p.green()) + value*m_amount; + + q.setGreen(CLAMP(ROUND(value), 0, quantum)); + + // Blue Channel. + value = (double)(p.blue())-(double)(q.blue()); + + if (fabs(2.0*value) < quantumThreshold) + value = (double)(p.blue()); + else + value = (double)(p.blue()) + value*m_amount; + + q.setBlue(CLAMP(ROUND(value), 0, quantum)); + + // Alpha Channel. + value = (double)(p.alpha())-(double)(q.alpha()); + + if (fabs(2.0*value) < quantumThreshold) + value = (double)(p.alpha()); + else + value = (double)(p.alpha()) + value*m_amount; + + q.setAlpha(CLAMP(ROUND(value), 0, quantum)); + + m_destImage.setPixelColor(x, y, q); + } + + progress = (int)(10.0 + ((double)y * 90.0) / m_destImage.height()); + if ( progress%5 == 0 ) + postProgress( progress ); + } +} + +} // NameSpace DigikamImagesPluginCore diff --git a/src/imageplugins/coreplugin/sharpnesseditor/unsharp.h b/src/imageplugins/coreplugin/sharpnesseditor/unsharp.h new file mode 100644 index 00000000..a1780ab4 --- /dev/null +++ b/src/imageplugins/coreplugin/sharpnesseditor/unsharp.h @@ -0,0 +1,58 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : Unsharp Mask threaded image filter. + * + * Copyright (C) 2005-2007 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. + * + * ============================================================ */ + +#ifndef UNSHARP_MASK_H +#define UNSHARP_MASK_H + +// Local includes. + +#include "dimgthreadedfilter.h" + +namespace DigikamImagesPluginCore +{ + +class UnsharpMask : public Digikam::DImgThreadedFilter +{ + +public: + + UnsharpMask(Digikam::DImg *orgImage, TQObject *parent=0, int radius=1, + double amount=1.0, double threshold=0.05); + + ~UnsharpMask(){}; + +private: + + virtual void filterImage(void); + +private: + + int m_radius; + + double m_amount; + double m_threshold; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* UNSHARP_MASK_H */ diff --git a/src/imageplugins/distortionfx/Makefile.am b/src/imageplugins/distortionfx/Makefile.am new file mode 100644 index 00000000..fcb7b74a --- /dev/null +++ b/src/imageplugins/distortionfx/Makefile.am @@ -0,0 +1,34 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_distortionfx_la_SOURCES = imageplugin_distortionfx.cpp \ + distortionfxtool.cpp distortionfx.cpp + +digikamimageplugin_distortionfx_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_distortionfx_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_distortionfx.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_distortionfx.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_distortionfx_ui.rc + diff --git a/src/imageplugins/distortionfx/digikamimageplugin_distortionfx.desktop b/src/imageplugins/distortionfx/digikamimageplugin_distortionfx.desktop new file mode 100644 index 00000000..8baca4eb --- /dev/null +++ b/src/imageplugins/distortionfx/digikamimageplugin_distortionfx.desktop @@ -0,0 +1,50 @@ +[Desktop Entry] +Name=ImagePlugin_DistortionFX +Name[bg]=Приставка за снимки - Изкривяващи ефекти +Name[da]=Plugin for forvrængningseffekt +Name[el]=ΠρόσθετοΕικόνας_ΕφέΠαραμόρφωσης +Name[fi]=Vääristymä +Name[hr]=Izobličenje +Name[it]=PluginImmagini_EffettiDiDistorsione +Name[nl]=Afbeeldingsplugin_Vervormingseffect +Name[sr]=Ефекти изобличења +Name[sr@Latn]=Efekti izobličenja +Name[sv]=Insticksprogram för förvrängningseffekt +Name[tr]=ResimEklentisi_Bozma +Name[xx]=xxImagePlugin_DistortionFXxx +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=Distortion special effects plugin for digiKam +Comment[bg]=Приставка на digiKam с изкривяващи снимките ефекти +Comment[ca]=Connector pel digiKam d'efectes especials de distorsió +Comment[da]=Digikam plugin for forvrængningsspecialeffekt +Comment[de]=digiKam-Modul zum Erzeugen von speziellen Verzerrungseffekten +Comment[el]=Πρόσθετο ειδικών εφέ παραμόρφωσης για το digiKam +Comment[es]=Plugin para digiKam con efectos de distorsión especiales +Comment[et]=DigiKami spetsiaalsete moonutusefektide plugin +Comment[fa]=وصلۀ جلوههای ویژۀ اعواج برای digiKam +Comment[fi]=Vääristymäerikoistehosteita +Comment[gl]=Un plugin de digiKam para efeitos especiais de distorsión +Comment[hr]=digiKam dodatak za efekt izobličavanja +Comment[is]=Íforrit fyrir digiKam sem afbakar sérstaklega myndir +Comment[it]=Plugin degli effetti speciali di distorsione per digiKam +Comment[ja]=digiKam ゆがめ特殊効果プラグイン +Comment[nds]=digiKam-Moduul för Vertarren-Effekten +Comment[nl]=Digikam-plugin voor vervormingseffect +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਖਿੰਡਾਉਣ ਖਾਸ ਪਰਭਾਵ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam oferująca efekty zniekształceń +Comment[pt]=Um 'plugin' do digiKam para efeitos especiais de distorção +Comment[pt_BR]=Plugin de efeito especial de distorção +Comment[ru]=Модуль специальных шумовых эффектов для digiKam +Comment[sk]=digiKam plugin pre špeciálne efekty skreslenia +Comment[sr]=digiKam-ов прикључак за ефекте изобличења +Comment[sr@Latn]=digiKam-ov priključak za efekte izobličenja +Comment[sv]=Digikam insticksprogram för förvrängningsspecialeffekt +Comment[tr]=Bozma etkileri uygulamak için bir digiKam eklentisi +Comment[uk]=Втулок спеціальних ефектів спотворення для digiKam +Comment[vi]=Phần bổ sung hiệu ứng méo mó ảnh cho digiKam +Comment[xx]=xxDistortion special effects plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_distortionfx +author=Caulier Gilles, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/distortionfx/digikamimageplugin_distortionfx_ui.rc b/src/imageplugins/distortionfx/digikamimageplugin_distortionfx_ui.rc new file mode 100644 index 00000000..99b905ad --- /dev/null +++ b/src/imageplugins/distortionfx/digikamimageplugin_distortionfx_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="5" name="digikamimageplugin_distortionfx" > + + <MenuBar> + + <Menu name="Filters" ><text>F&ilters</text> + <Action name="imageplugin_distortionfx" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action shortcut="" name="imageplugin_distortionfx" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/distortionfx/distortionfx.cpp b/src/imageplugins/distortionfx/distortionfx.cpp new file mode 100644 index 00000000..d17abd4f --- /dev/null +++ b/src/imageplugins/distortionfx/distortionfx.cpp @@ -0,0 +1,869 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-07-18 + * Description : Distortion FX threaded image filter. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * Original Distortion algorithms copyrighted 2004-2005 by + * Pieter Z. Voloshyn <pieter dot voloshyn 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. + * + * ============================================================ */ + +// Represents 1 +#define ANGLE_RATIO 0.017453292519943295769236907685 + +// C++ includes. + +#include <cmath> +#include <cstdlib> + +// TQt includes. + +#include <tqdatetime.h> + +// Local includes. + +#include "dimg.h" +#include "dimgimagefilters.h" +#include "distortionfx.h" + +namespace DigikamDistortionFXImagesPlugin +{ + +DistortionFX::DistortionFX(Digikam::DImg *orgImage, TQObject *parent, int effectType, + int level, int iteration, bool antialiasing) + : Digikam::DImgThreadedFilter(orgImage, parent, "DistortionFX") +{ + m_effectType = effectType; + m_level = level; + m_iteration = iteration; + m_antiAlias = antialiasing; + + initFilter(); +} + +void DistortionFX::filterImage(void) +{ + int w = m_orgImage.width(); + int h = m_orgImage.height(); + int l = m_level; + int f = m_iteration; + + switch (m_effectType) + { + case FishEye: + fisheye(&m_orgImage, &m_destImage, (double)(l/5.0), m_antiAlias); + break; + + case Twirl: + twirl(&m_orgImage, &m_destImage, l, m_antiAlias); + break; + + case CilindricalHor: + cilindrical(&m_orgImage, &m_destImage, (double)l, true, false, m_antiAlias); + break; + + case CilindricalVert: + cilindrical(&m_orgImage, &m_destImage, (double)l, false, true, m_antiAlias); + break; + + case CilindricalHV: + cilindrical(&m_orgImage, &m_destImage, (double)l, true, true, m_antiAlias); + break; + + case Caricature: + fisheye(&m_orgImage, &m_destImage, (double)(-l/5.0), m_antiAlias); + break; + + case MultipleCorners: + multipleCorners(&m_orgImage, &m_destImage, l, m_antiAlias); + break; + + case WavesHorizontal: + waves(&m_orgImage, &m_destImage, l, f, true, true); + break; + + case WavesVertical: + waves(&m_orgImage, &m_destImage, l, f, true, false); + break; + + case BlockWaves1: + blockWaves(&m_orgImage, &m_destImage, l, f, false); + break; + + case BlockWaves2: + blockWaves(&m_orgImage, &m_destImage, l, f, true); + break; + + case CircularWaves1: + circularWaves(&m_orgImage, &m_destImage, w/2, h/2, (double)l, (double)f, 0.0, false, m_antiAlias); + break; + + case CircularWaves2: + circularWaves(&m_orgImage, &m_destImage, w/2, h/2, (double)l, (double)f, 25.0, true, m_antiAlias); + break; + + case PolarCoordinates: + polarCoordinates(&m_orgImage, &m_destImage, true, m_antiAlias); + break; + + case UnpolarCoordinates: + polarCoordinates(&m_orgImage, &m_destImage, false, m_antiAlias); + break; + + case Tile: + tile(&m_orgImage, &m_destImage, 200-f, 200-f, l); + break; + } +} + +/* + This code is shared by six methods. + Write value of pixel w|h in data to pixel nw|nh in pResBits. + Antialias if requested. +*/ +void DistortionFX::setPixelFromOther(int Width, int Height, bool sixteenBit, int bytesDepth, + uchar *data, uchar *pResBits, + int w, int h, double nw, double nh, bool AntiAlias) +{ + Digikam::DColor color; + int offset, offsetOther; + + offset = getOffset(Width, w, h, bytesDepth); + + if (AntiAlias) + { + uchar *ptr = pResBits + offset; + if (sixteenBit) + { + unsigned short *ptr16 = (unsigned short *)ptr; + Digikam::DImgImageFilters().pixelAntiAliasing16((unsigned short *)data, Width, Height, nw, nh, + ptr16+3, ptr16+2, ptr16+1, ptr16); + } + else + { + Digikam::DImgImageFilters().pixelAntiAliasing(data, Width, Height, nw, nh, + ptr+3, ptr+2, ptr+1, ptr); + } + } + else + { + // we get the position adjusted + offsetOther = getOffsetAdjusted(Width, Height, (int)nw, (int)nh, bytesDepth); + // read color + color.setColor(data + offsetOther, sixteenBit); + // write color to destination + color.setPixel(pResBits + offset); + } +} + +/* Function to apply the fisheye effect backported from ImageProcessing version 2 + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Coeff => Distortion effect coeff. Positive value render 'Fish Eyes' effect, + * and negative values render 'Caricature' effect. + * Antialias => Smart bluring result. + * + * Theory => This is a great effect if you take employee photos + * Its pure trigonometry. I think if you study hard the code you + * understand very well. + */ +void DistortionFX::fisheye(Digikam::DImg *orgImage, Digikam::DImg *destImage, double Coeff, bool AntiAlias) +{ + if (Coeff == 0.0) return; + + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pResBits = destImage->bits(); + + int h, w; + double nh, nw, th, tw; + + int progress; + int nHalfW = Width / 2, nHalfH = Height / 2; + + Digikam::DColor color; + int offset; + + double lfXScale = 1.0, lfYScale = 1.0; + double lfRadius, lfRadMax, lfAngle, lfCoeff, lfCoeffStep = Coeff / 1000.0; + + if (Width > Height) + lfYScale = (double)Width / (double)Height; + else if (Height > Width) + lfXScale = (double)Height / (double)Width; + + lfRadMax = (double)TQMAX(Height, Width) / 2.0; + lfCoeff = lfRadMax / log (fabs (lfCoeffStep) * lfRadMax + 1.0); + + // main loop + + for (h = 0; !m_cancel && (h < Height); h++) + { + th = lfYScale * (double)(h - nHalfH); + + for (w = 0; !m_cancel && (w < Width); w++) + { + tw = lfXScale * (double)(w - nHalfW); + + // we find the distance from the center + lfRadius = sqrt (th * th + tw * tw); + + if (lfRadius < lfRadMax) + { + lfAngle = atan2 (th, tw); + + if (Coeff > 0.0) + lfRadius = (exp (lfRadius / lfCoeff) - 1.0) / lfCoeffStep; + else + lfRadius = lfCoeff * log (1.0 + (-1.0 * lfCoeffStep) * lfRadius); + + nw = (double)nHalfW + (lfRadius / lfXScale) * cos (lfAngle); + nh = (double)nHalfH + (lfRadius / lfYScale) * sin (lfAngle); + + setPixelFromOther(Width, Height, sixteenBit, bytesDepth, data, pResBits, w, h, nw, nh, AntiAlias); + } + else + { + // copy pixel + offset = getOffset(Width, w, h, bytesDepth); + color.setColor(data + offset, sixteenBit); + color.setPixel(pResBits + offset); + } + } + + // Update the progress bar in dialog. + progress = (int) (((double)(h) * 100.0) / Height); + + if (progress%5 == 0) + postProgress(progress); + } +} + +/* Function to apply the twirl effect backported from ImageProcessing version 2 + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Twirl => Distance value. + * Antialias => Smart bluring result. + * + * Theory => Take spiral studies, you will understand better, I'm studying + * hard on this effect, because it is not too fast. + */ +void DistortionFX::twirl(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Twirl, bool AntiAlias) +{ + // if twirl value is zero, we do nothing + + if (Twirl == 0) + return; + + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pResBits = destImage->bits(); + + int h, w; + double tw, th, nh, nw; + + Digikam::DColor color; + int offset; + + int progress; + int nHalfW = Width / 2, nHalfH = Height / 2; + + double lfXScale = 1.0, lfYScale = 1.0; + double lfAngle, lfNewAngle, lfAngleStep, lfAngleSum, lfCurrentRadius, lfRadMax; + + if (Width > Height) + lfYScale = (double)Width / (double)Height; + else if (Height > Width) + lfXScale = (double)Height / (double)Width; + + // the angle step is twirl divided by 10000 + lfAngleStep = Twirl / 10000.0; + // now, we get the minimum radius + lfRadMax = (double)TQMAX(Width, Height) / 2.0; + + // main loop + + for (h = 0; !m_cancel && (h < Height); h++) + { + th = lfYScale * (double)(h - nHalfH); + + for (w = 0; !m_cancel && (w < Width); w++) + { + tw = lfXScale * (double)(w - nHalfW); + + // now, we get the distance + lfCurrentRadius = sqrt (th * th + tw * tw); + + // if distance is less than maximum radius... + if (lfCurrentRadius < lfRadMax) + { + // we find the angle from the center + lfAngle = atan2 (th, tw); + // we get the accumuled angle + lfAngleSum = lfAngleStep * (-1.0 * (lfCurrentRadius - lfRadMax)); + // ok, we sum angle with accumuled to find a new angle + lfNewAngle = lfAngle + lfAngleSum; + + // now we find the exact position's x and y + nw = (double)nHalfW + cos (lfNewAngle) * (lfCurrentRadius / lfXScale); + nh = (double)nHalfH + sin (lfNewAngle) * (lfCurrentRadius / lfYScale); + + setPixelFromOther(Width, Height, sixteenBit, bytesDepth, data, pResBits, w, h, nw, nh, AntiAlias); + } + else + { + // copy pixel + offset = getOffset(Width, w, h, bytesDepth); + color.setColor(data + offset, sixteenBit); + color.setPixel(pResBits + offset); + } + } + + // Update the progress bar in dialog. + progress = (int) (((double)h * 100.0) / Height); + + if (progress%5 == 0) + postProgress(progress); + } +} + +/* Function to apply the Cilindrical effect backported from ImageProcessing version 2 + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Coeff => Cilindrical value. + * Horizontal => Apply horizontally. + * Vertical => Apply vertically. + * Antialias => Smart bluring result. + * + * Theory => This is a great effect, similar to Spherize (Photoshop). + * If you understand FishEye, you will understand Cilindrical + * FishEye apply a logarithm function using a sphere radius, + * Spherize use the same function but in a rectangular + * environment. + */ +void DistortionFX::cilindrical(Digikam::DImg *orgImage, Digikam::DImg *destImage, double Coeff, + bool Horizontal, bool Vertical, bool AntiAlias) + +{ + if ((Coeff == 0.0) || (! (Horizontal || Vertical))) + return; + + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pResBits = destImage->bits(); + + int progress; + + int h, w; + double nh, nw; + + int nHalfW = Width / 2, nHalfH = Height / 2; + double lfCoeffX = 1.0, lfCoeffY = 1.0, lfCoeffStep = Coeff / 1000.0; + + if (Horizontal) + lfCoeffX = (double)nHalfW / log (fabs (lfCoeffStep) * nHalfW + 1.0); + if (Vertical) + lfCoeffY = (double)nHalfH / log (fabs (lfCoeffStep) * nHalfH + 1.0); + + // initial copy + memcpy (pResBits, data, orgImage->numBytes()); + + // main loop + + for (h = 0; !m_cancel && (h < Height); h++) + { + for (w = 0; !m_cancel && (w < Width); w++) + { + // we find the distance from the center + nh = fabs ((double)(h - nHalfH)); + nw = fabs ((double)(w - nHalfW)); + + if (Horizontal) + { + if (Coeff > 0.0) + nw = (exp (nw / lfCoeffX) - 1.0) / lfCoeffStep; + else + nw = lfCoeffX * log (1.0 + (-1.0 * lfCoeffStep) * nw); + } + + if (Vertical) + { + if (Coeff > 0.0) + nh = (exp (nh / lfCoeffY) - 1.0) / lfCoeffStep; + else + nh = lfCoeffY * log (1.0 + (-1.0 * lfCoeffStep) * nh); + } + + nw = (double)nHalfW + ((w >= nHalfW) ? nw : -nw); + nh = (double)nHalfH + ((h >= nHalfH) ? nh : -nh); + + setPixelFromOther(Width, Height, sixteenBit, bytesDepth, data, pResBits, w, h, nw, nh, AntiAlias); + } + + // Update the progress bar in dialog. + progress = (int) (((double)h * 100.0) / Height); + + if (progress%5 == 0) + postProgress(progress); + } +} + +/* Function to apply the Multiple Corners effect backported from ImageProcessing version 2 + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Factor => nb corners. + * Antialias => Smart bluring result. + * + * Theory => This is an amazing function, you've never seen this before. + * I was testing some trigonometric functions, and I saw that if + * I multiply the angle by 2, the result is an image like this + * If we multiply by 3, we can create the SixCorners effect. + */ +void DistortionFX::multipleCorners(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Factor, bool AntiAlias) +{ + if (Factor == 0) return; + + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pResBits = destImage->bits(); + + int h, w; + double nh, nw; + int progress; + + int nHalfW = Width / 2, nHalfH = Height / 2; + double lfAngle, lfNewRadius, lfCurrentRadius, lfRadMax; + + lfRadMax = sqrt (Height * Height + Width * Width) / 2.0; + + // main loop + + for (h = 0; !m_cancel && (h < Height); h++) + { + for (w = 0; !m_cancel && (w < Width); w++) + { + // we find the distance from the center + nh = nHalfH - h; + nw = nHalfW - w; + + // now, we get the distance + lfCurrentRadius = sqrt (nh * nh + nw * nw); + // we find the angle from the center + lfAngle = atan2 (nh, nw) * (double)Factor; + + // ok, we sum angle with accumuled to find a new angle + lfNewRadius = lfCurrentRadius * lfCurrentRadius / lfRadMax; + + // now we find the exact position's x and y + nw = (double)nHalfW - (cos (lfAngle) * lfNewRadius); + nh = (double)nHalfH - (sin (lfAngle) * lfNewRadius); + + setPixelFromOther(Width, Height, sixteenBit, bytesDepth, data, pResBits, w, h, nw, nh, AntiAlias); + } + + // Update the progress bar in dialog. + progress = (int) (((double)h * 100.0) / Height); + + if (progress%5 == 0) + postProgress(progress); + } +} + +/* Function to apply the Polar Coordinates effect backported from ImageProcessing version 2 + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Type => if true Polar Coordinate to Polar else inverse. + * Antialias => Smart bluring result. + * + * Theory => Similar to PolarCoordinates from Photoshop. We apply the polar + * transformation in a proportional (Height and Width) radius. + */ +void DistortionFX::polarCoordinates(Digikam::DImg *orgImage, Digikam::DImg *destImage, bool Type, bool AntiAlias) +{ + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pResBits = destImage->bits(); + + int h, w; + double nh, nw, th, tw; + int progress; + + int nHalfW = Width / 2, nHalfH = Height / 2; + double lfXScale = 1.0, lfYScale = 1.0; + double lfAngle, lfRadius, lfRadMax; + + if (Width > Height) + lfYScale = (double)Width / (double)Height; + else if (Height > Width) + lfXScale = (double)Height / (double)Width; + + lfRadMax = (double)TQMAX(Height, Width) / 2.0; + + // main loop + + for (h = 0; !m_cancel && (h < Height); h++) + { + th = lfYScale * (double)(h - nHalfH); + + for (w = 0; !m_cancel && (w < Width); w++) + { + tw = lfXScale * (double)(w - nHalfW); + + if (Type) + { + // now, we get the distance + lfRadius = sqrt (th * th + tw * tw); + // we find the angle from the center + lfAngle = atan2 (tw, th); + + // now we find the exact position's x and y + nh = lfRadius * (double) Height / lfRadMax; + nw = lfAngle * (double) Width / (2 * M_PI); + + nw = (double)nHalfW + nw; + } + else + { + lfRadius = (double)(h) * lfRadMax / (double)Height; + lfAngle = (double)(w) * (2 * M_PI) / (double) Width; + + nw = (double)nHalfW - (lfRadius / lfXScale) * sin (lfAngle); + nh = (double)nHalfH - (lfRadius / lfYScale) * cos (lfAngle); + } + + setPixelFromOther(Width, Height, sixteenBit, bytesDepth, data, pResBits, w, h, nw, nh, AntiAlias); + } + + // Update the progress bar in dialog. + progress = (int) (((double)h * 100.0) / Height); + + if (progress%5 == 0) + postProgress(progress); + } +} + +/* Function to apply the circular waves effect backported from ImageProcessing version 2 + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * X, Y => Position of circle center on the image. + * Amplitude => Sinoidal maximum height + * Frequency => Frequency value. + * Phase => Phase value. + * WavesType => If true the amplitude is proportional to radius. + * Antialias => Smart bluring result. + * + * Theory => Similar to Waves effect, but here I apply a senoidal function + * with the angle point. + */ +void DistortionFX::circularWaves(Digikam::DImg *orgImage, Digikam::DImg *destImage, int X, int Y, double Amplitude, + double Frequency, double Phase, bool WavesType, bool AntiAlias) +{ + if (Amplitude < 0.0) Amplitude = 0.0; + if (Frequency < 0.0) Frequency = 0.0; + + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pResBits = destImage->bits(); + + int h, w; + double nh, nw; + int progress; + + double lfRadius, lfRadMax, lfNewAmp = Amplitude; + double lfFreqAngle = Frequency * ANGLE_RATIO; + + Phase *= ANGLE_RATIO; + + lfRadMax = sqrt (Height * Height + Width * Width); + + for (h = 0; !m_cancel && (h < Height); h++) + { + for (w = 0; !m_cancel && (w < Width); w++) + { + nw = X - w; + nh = Y - h; + + lfRadius = sqrt (nw * nw + nh * nh); + + if (WavesType) + lfNewAmp = Amplitude * lfRadius / lfRadMax; + + nw = (double)w + lfNewAmp * sin(lfFreqAngle * lfRadius + Phase); + nh = (double)h + lfNewAmp * cos(lfFreqAngle * lfRadius + Phase); + + setPixelFromOther(Width, Height, sixteenBit, bytesDepth, data, pResBits, w, h, nw, nh, AntiAlias); + } + + // Update the progress bar in dialog. + progress = (int) (((double)h * 100.0) / Height); + + if (progress%5 == 0) + postProgress(progress); + } +} + +/* Function to apply the waves effect + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Amplitude => Sinoidal maximum height. + * Frequency => Frequency value. + * FillSides => Like a boolean variable. + * Direction => Vertical or horizontal flag. + * + * Theory => This is an amazing effect, very funny, and very simple to + * understand. You just need understand how sin and cos works. + */ +void DistortionFX::waves(Digikam::DImg *orgImage, Digikam::DImg *destImage, + int Amplitude, int Frequency, + bool FillSides, bool Direction) +{ + if (Amplitude < 0) Amplitude = 0; + if (Frequency < 0) Frequency = 0; + + int Width = orgImage->width(); + int Height = orgImage->height(); + + int progress; + int h, w; + + if (Direction) // Horizontal + { + int tx; + + for (h = 0; !m_cancel && (h < Height); h++) + { + tx = lround(Amplitude * sin ((Frequency * 2) * h * (M_PI / 180))); + destImage->bitBltImage(orgImage, 0, h, Width, 1, tx, h); + + if (FillSides) + { + destImage->bitBltImage(orgImage, Width - tx, h, tx, 1, 0, h); + destImage->bitBltImage(orgImage, 0, h, Width - (Width - 2 * Amplitude + tx), 1, Width + tx, h); + } + + // Update the progress bar in dialog. + progress = (int) (((double)h * 100.0) / Height); + + if (progress%5 == 0) + postProgress(progress); + } + } + else + { + int ty; + + for (w = 0; !m_cancel && (w < Width); w++) + { + ty = lround(Amplitude * sin ((Frequency * 2) * w * (M_PI / 180))); + destImage->bitBltImage(orgImage, w, 0, 1, Height, w, ty); + + if (FillSides) + { + destImage->bitBltImage(orgImage, w, Height - ty, 1, ty, w, 0); + destImage->bitBltImage(orgImage, w, 0, 1, Height - (Height - 2 * Amplitude + ty), w, Height + ty); + } + + // Update the progress bar in dialog. + progress = (int) (((double)w * 100.0) / Width); + + if (progress%5 == 0) + postProgress(progress); + } + } +} + +/* Function to apply the block waves effect + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Amplitude => Sinoidal maximum height + * Frequency => Frequency value + * Mode => The mode to be applied. + * + * Theory => This is an amazing effect, very funny when amplitude and + * frequency are small values. + */ +void DistortionFX::blockWaves(Digikam::DImg *orgImage, Digikam::DImg *destImage, + int Amplitude, int Frequency, bool Mode) +{ + if (Amplitude < 0) Amplitude = 0; + if (Frequency < 0) Frequency = 0; + + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pResBits = destImage->bits(); + + int nw, nh, progress; + double Radius; + + Digikam::DColor color; + int offset, offsetOther; + + int nHalfW = Width / 2, nHalfH = Height / 2; + + for (int w = 0; !m_cancel && (w < Width); w++) + { + for (int h = 0; !m_cancel && (h < Height); h++) + { + nw = nHalfW - w; + nh = nHalfH - h; + + Radius = sqrt (nw * nw + nh * nh); + + if (Mode) + { + nw = (int)(w + Amplitude * sin (Frequency * nw * (M_PI / 180))); + nh = (int)(h + Amplitude * cos (Frequency * nh * (M_PI / 180))); + } + else + { + nw = (int)(w + Amplitude * sin (Frequency * w * (M_PI / 180))); + nh = (int)(h + Amplitude * cos (Frequency * h * (M_PI / 180))); + } + + offset = getOffset(Width, w, h, bytesDepth); + offsetOther = getOffsetAdjusted(Width, Height, (int)nw, (int)nh, bytesDepth); + + // read color + color.setColor(data + offsetOther, sixteenBit); + // write color to destination + color.setPixel(pResBits + offset); + } + + // Update the progress bar in dialog. + progress = (int) (((double)w * 100.0) / Width); + + if (progress%5 == 0) + postProgress(progress); + } +} + +/* Function to apply the tile effect + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * WSize => Tile Width + * HSize => Tile Height + * Random => Maximum random value + * + * Theory => Similar to Tile effect from Photoshop and very easy to + * understand. We get a rectangular area using WSize and HSize and + * replace in a position with a random distance from the original + * position. + */ +void DistortionFX::tile(Digikam::DImg *orgImage, Digikam::DImg *destImage, + int WSize, int HSize, int Random) +{ + if (WSize < 1) WSize = 1; + if (HSize < 1) HSize = 1; + if (Random < 1) Random = 1; + + int Width = orgImage->width(); + int Height = orgImage->height(); + + TQDateTime dt = TQDateTime::currentDateTime(); + TQDateTime Y2000( TQDate(2000, 1, 1), TQTime(0, 0, 0) ); + uint seed = dt.secsTo(Y2000); + + int tx, ty, h, w, progress; + + for (h = 0; !m_cancel && (h < Height); h += HSize) + { + for (w = 0; !m_cancel && (w < Width); w += WSize) + { + tx = (int)(rand_r(&seed) % Random) - (Random / 2); + ty = (int)(rand_r(&seed) % Random) - (Random / 2); + destImage->bitBltImage(orgImage, w, h, WSize, HSize, w + tx, h + ty); + } + + // Update the progress bar in dialog. + progress = (int)(((double)h * 100.0) / Height); + + if (progress%5 == 0) + postProgress(progress); + } +} + +// UNUSED +/* Function to return the maximum radius with a determined angle + * + * Height => Height of the image + * Width => Width of the image + * Angle => Angle to analize the maximum radius + * + * Theory => This function calcule the maximum radius to that angle + * so, we can build an oval circunference + */ + /* +double DistortionFX::maximumRadius(int Height, int Width, double Angle) +{ + double MaxRad, MinRad; + double Radius, DegAngle = fabs (Angle * 57.295); // Rads -> Degrees + + MinRad = TQMIN (Height, Width) / 2.0; // Gets the minor radius + MaxRad = TQMAX (Height, Width) / 2.0; // Gets the major radius + + // Find the quadrant between -PI/2 and PI/2 + if (DegAngle > 90.0) + Radius = proportionalValue (MinRad, MaxRad, (DegAngle * (255.0 / 90.0))); + else + Radius = proportionalValue (MaxRad, MinRad, ((DegAngle - 90.0) * (255.0 / 90.0))); + return (Radius); +} + */ + +} // NameSpace DigikamDistortionFXImagesPlugin diff --git a/src/imageplugins/distortionfx/distortionfx.h b/src/imageplugins/distortionfx/distortionfx.h new file mode 100644 index 00000000..073f4df2 --- /dev/null +++ b/src/imageplugins/distortionfx/distortionfx.h @@ -0,0 +1,149 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-07-18 + * Description : Distortion FX threaded image filter. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * Original Distortion algorithms copyrighted 2004-2005 by + * Pieter Z. Voloshyn <pieter dot voloshyn 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. + * + * ============================================================ */ + +#ifndef DISTORTION_FX_H +#define DISTORTION_FX_H + +// TQt includes. + +#include <tqsize.h> + +// Digikam includes. + +#include "dimgthreadedfilter.h" + +namespace DigikamDistortionFXImagesPlugin +{ + +class DistortionFX : public Digikam::DImgThreadedFilter +{ + +public: + + DistortionFX(Digikam::DImg *orgImage, TQObject *parent=0, int effectType=0, + int level=0, int iteration=0, bool antialiasing=true); + + ~DistortionFX(){}; + +public: + + enum DistortionFXTypes + { + FishEye=0, + Twirl, + CilindricalHor, + CilindricalVert, + CilindricalHV, + Caricature, + MultipleCorners, + WavesHorizontal, + WavesVertical, + BlockWaves1, + BlockWaves2, + CircularWaves1, + CircularWaves2, + PolarCoordinates, + UnpolarCoordinates, + Tile + }; + +private: + + virtual void filterImage(void); + + // Backported from ImageProcessing version 2 + void fisheye(Digikam::DImg *orgImage, Digikam::DImg *destImage, double Coeff, bool AntiAlias=true); + void twirl(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Twirl, bool AntiAlias=true); + void cilindrical(Digikam::DImg *orgImage, Digikam::DImg *destImage, double Coeff, + bool Horizontal, bool Vertical, bool AntiAlias=true); + void multipleCorners(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Factor, bool AntiAlias=true); + void polarCoordinates(Digikam::DImg *orgImage, Digikam::DImg *destImage, bool Type, bool AntiAlias=true); + void circularWaves(Digikam::DImg *orgImage, Digikam::DImg *destImage, int X, int Y, double Amplitude, + double Frequency, double Phase, bool WavesType, bool AntiAlias=true); + + // Backported from ImageProcessing version 1 + void waves(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Amplitude, int Frequency, + bool FillSides, bool Direction); + void blockWaves(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Amplitude, int Frequency, bool Mode); + void tile(Digikam::DImg *orgImage, Digikam::DImg *destImage, int WSize, int HSize, int Random); + + void setPixelFromOther(int Width, int Height, bool sixteenBit, int bytesDepth, + uchar *data, uchar *pResBits, + int w, int h, double nw, double nh, bool AntiAlias); + /* + //UNUSED + + inline double maximumRadius(int Height, int Width, double Angle); + + // This function does the same thing that ShadeColors function but using double variables. + inline double proportionalValue (double DestValue, double SrcValue, double Shade) + { + if (Shade == 0.0) return DestValue; + if (Shade == 255.0) return SrcValue; + return ((DestValue * (255.0 - Shade) + SrcValue * Shade) / 256.0); + }; + */ + + // Return the limit defined the max and min values. + inline int Lim_Max(int Now, int Up, int Max) + { + --Max; + while (Now > Max - Up) --Up; + return (Up); + }; + + inline bool isInside (int Width, int Height, int X, int Y) + { + bool bIsWOk = ((X < 0) ? false : (X >= Width ) ? false : true); + bool bIsHOk = ((Y < 0) ? false : (Y >= Height) ? false : true); + return (bIsWOk && bIsHOk); + }; + + inline int getOffset(int Width, int X, int Y, int bytesDepth) + { + return (Y * Width * bytesDepth) + (X * bytesDepth); + }; + + inline int getOffsetAdjusted(int Width, int Height, int X, int Y, int bytesDepth) + { + X = (X < 0) ? 0 : ((X >= Width ) ? (Width - 1) : X); + Y = (Y < 0) ? 0 : ((Y >= Height) ? (Height - 1) : Y); + return getOffset(Width, X, Y, bytesDepth); + }; + +private: + + bool m_antiAlias; + + int m_level; + int m_iteration; + int m_effectType; +}; + +} // NameSpace DigikamDistortionFXImagesPlugin + +#endif /* DISTORTION_FX_H */ diff --git a/src/imageplugins/distortionfx/distortionfxtool.cpp b/src/imageplugins/distortionfx/distortionfxtool.cpp new file mode 100644 index 00000000..45ff0e45 --- /dev/null +++ b/src/imageplugins/distortionfx/distortionfxtool.cpp @@ -0,0 +1,398 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-11 + * Description : a plugin to apply Distortion FX to an image. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * Original Distortion algorithms copyrighted 2004-2005 by + * Pieter Z. Voloshyn <pieter dot voloshyn 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqframe.h> +#include <tqimage.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqspinbox.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <khelpmenu.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <kprogress.h> +#include <kstandarddirs.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> +#include <libkdcraw/rcombobox.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "dimg.h" +#include "editortoolsettings.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "distortionfx.h" +#include "distortionfxtool.h" +#include "distortionfxtool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamDistortionFXImagesPlugin +{ + +DistortionFXTool::DistortionFXTool(TQObject* parent) + : EditorToolThreaded(parent) +{ + setName("distortionfx"); + setToolName(i18n("Distortion Effects")); + setToolIcon(SmallIcon("distortionfx")); + + m_previewWidget = new ImageWidget("distortionfx Tool", 0, + i18n("<p>This is the preview of the distortion effect " + "applied to the photograph."), + false, ImageGuideWidget::HVGuideMode); + + setToolView(m_previewWidget); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel, + EditorToolSettings::ColorGuide); + + TQGridLayout* gridSettings = new TQGridLayout(m_gboxSettings->plainPage(), 7, 2); + + m_effectTypeLabel = new TQLabel(i18n("Type:"), m_gboxSettings->plainPage()); + + m_effectType = new RComboBox(m_gboxSettings->plainPage()); + m_effectType->insertItem(i18n("Fish Eyes")); + m_effectType->insertItem(i18n("Twirl")); + m_effectType->insertItem(i18n("Cylindrical Hor.")); + m_effectType->insertItem(i18n("Cylindrical Vert.")); + m_effectType->insertItem(i18n("Cylindrical H/V.")); + m_effectType->insertItem(i18n("Caricature")); + m_effectType->insertItem(i18n("Multiple Corners")); + m_effectType->insertItem(i18n("Waves Hor.")); + m_effectType->insertItem(i18n("Waves Vert.")); + m_effectType->insertItem(i18n("Block Waves 1")); + m_effectType->insertItem(i18n("Block Waves 2")); + m_effectType->insertItem(i18n("Circular Waves 1")); + m_effectType->insertItem(i18n("Circular Waves 2")); + m_effectType->insertItem(i18n("Polar Coordinates")); + m_effectType->insertItem(i18n("Unpolar Coordinates")); + m_effectType->insertItem(i18n("Tile")); + m_effectType->setDefaultItem(DistortionFX::FishEye); + TQWhatsThis::add( m_effectType, i18n("<p>Here, select the type of effect to apply to the image.<p>" + "<b>Fish Eyes</b>: warps the photograph around a 3D spherical shape to " + "reproduce the common photograph 'Fish Eyes' effect.<p>" + "<b>Twirl</b>: spins the photograph to produce a Twirl pattern.<p>" + "<b>Cylinder Hor.</b>: warps the photograph around a horizontal cylinder.<p>" + "<b>Cylinder Vert.</b>: warps the photograph around a vertical cylinder.<p>" + "<b>Cylinder H/V.</b>: warps the photograph around 2 cylinders, vertical " + "and horizontal.<p>" + "<b>Caricature</b>: distorts the photograph with the 'Fish Eyes' effect inverted.<p>" + "<b>Multiple Corners</b>: splits the photograph like a multiple corners pattern.<p>" + "<b>Waves Horizontal</b>: distorts the photograph with horizontal waves.<p>" + "<b>Waves Vertical</b>: distorts the photograph with vertical waves.<p>" + "<b>Block Waves 1</b>: divides the image into cells and makes it look as " + "if it is being viewed through glass blocks.<p>" + "<b>Block Waves 2</b>: like Block Waves 1 but with another version " + "of glass blocks distortion.<p>" + "<b>Circular Waves 1</b>: distorts the photograph with circular waves.<p>" + "<b>Circular Waves 2</b>: another variation of the Circular Waves effect.<p>" + "<b>Polar Coordinates</b>: converts the photograph from rectangular " + "to polar coordinates.<p>" + "<b>Unpolar Coordinates</b>: the Polar Coordinates effect inverted.<p>" + "<b>Tile</b>: splits the photograph into square blocks and moves " + "them randomly inside the image.<p>" + )); + + m_levelLabel = new TQLabel(i18n("Level:"), m_gboxSettings->plainPage()); + m_levelInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_levelInput->setRange(0, 100, 1); + m_levelInput->setDefaultValue(50); + TQWhatsThis::add( m_levelInput, i18n("<p>Set here the level of the effect.")); + + + m_iterationLabel = new TQLabel(i18n("Iteration:"), m_gboxSettings->plainPage()); + m_iterationInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_iterationInput->setRange(0, 100, 1); + m_iterationInput->setDefaultValue(10); + TQWhatsThis::add( m_iterationInput, i18n("<p>This value controls the iterations to use for Waves, " + "Tile, and Neon effects.")); + + gridSettings->addMultiCellWidget(m_effectTypeLabel, 0, 0, 0, 1); + gridSettings->addMultiCellWidget(m_effectType, 1, 1, 0, 1); + gridSettings->addMultiCellWidget(m_levelLabel, 2, 2, 0, 1); + gridSettings->addMultiCellWidget(m_levelInput, 3, 3, 0, 1); + gridSettings->addMultiCellWidget(m_iterationLabel, 4, 4, 0, 1); + gridSettings->addMultiCellWidget(m_iterationInput, 5, 5, 0, 1); + gridSettings->setRowStretch(6, 10); + + setToolSettings(m_gboxSettings); + init(); + + // ------------------------------------------------------------- + + connect(m_effectType, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotEffectTypeChanged(int))); + + connect(m_levelInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_iterationInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_gboxSettings, TQ_SIGNAL(signalColorGuideChanged()), + this, TQ_SLOT(slotColorGuideChanged())); +} + +DistortionFXTool::~DistortionFXTool() +{ +} + +void DistortionFXTool::slotColorGuideChanged() +{ + m_previewWidget->slotChangeGuideColor(m_gboxSettings->guideColor()); + m_previewWidget->slotChangeGuideSize(m_gboxSettings->guideSize()); +} + +void DistortionFXTool::renderingFinished() +{ + m_effectTypeLabel->setEnabled(true); + m_effectType->setEnabled(true); + m_levelInput->setEnabled(true); + m_levelLabel->setEnabled(true); + m_iterationInput->setEnabled(true); + m_iterationLabel->setEnabled(true); + + switch (m_effectType->currentItem()) + { + case DistortionFX::FishEye: + case DistortionFX::Twirl: + case DistortionFX::CilindricalHor: + case DistortionFX::CilindricalVert: + case DistortionFX::CilindricalHV: + case DistortionFX::Caricature: + case DistortionFX::MultipleCorners: + break; + + case DistortionFX::PolarCoordinates: + case DistortionFX::UnpolarCoordinates: + m_levelInput->setEnabled(false); + m_levelLabel->setEnabled(false); + break; + + case DistortionFX::WavesHorizontal: + case DistortionFX::WavesVertical: + case DistortionFX::BlockWaves1: + case DistortionFX::BlockWaves2: + case DistortionFX::CircularWaves1: + case DistortionFX::CircularWaves2: + case DistortionFX::Tile: + m_iterationInput->setEnabled(true); + m_iterationLabel->setEnabled(true); + break; + } +} + +void DistortionFXTool::readSettings(void) +{ + TDEConfig *config = kapp->config(); + config->setGroup("distortionfx Tool"); + + m_effectType->blockSignals(true); + m_iterationInput->blockSignals(true); + m_levelInput->blockSignals(true); + + m_effectType->setCurrentItem(config->readNumEntry("EffectType", + m_effectType->defaultItem())); + m_iterationInput->setValue(config->readNumEntry("IterationAjustment", + m_iterationInput->defaultValue())); + m_levelInput->setValue(config->readNumEntry("LevelAjustment", + m_levelInput->defaultValue())); + + m_effectType->blockSignals(false); + m_iterationInput->blockSignals(false); + m_levelInput->blockSignals(false); + + slotEffect(); +} + +void DistortionFXTool::writeSettings(void) +{ + TDEConfig *config = kapp->config(); + config->setGroup("distortionfx Tool"); + config->writeEntry("EffectType", m_effectType->currentItem()); + config->writeEntry("IterationAjustment", m_iterationInput->value()); + config->writeEntry("LevelAjustment", m_levelInput->value()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void DistortionFXTool::slotResetSettings() +{ + m_effectType->blockSignals(true); + m_levelInput->blockSignals(true); + m_iterationInput->blockSignals(true); + + m_levelInput->slotReset(); + m_iterationInput->slotReset(); + m_effectType->slotReset(); + slotEffectTypeChanged(m_effectType->defaultItem()); + + m_effectType->blockSignals(false); + m_levelInput->blockSignals(false); + m_iterationInput->blockSignals(false); +} + +void DistortionFXTool::slotEffectTypeChanged(int type) +{ + m_levelInput->setEnabled(true); + m_levelLabel->setEnabled(true); + + m_levelInput->blockSignals(true); + m_iterationInput->blockSignals(true); + m_levelInput->setRange(0, 100, 1); + m_levelInput->setValue(25); + + switch (type) + { + case DistortionFX::Twirl: + m_levelInput->setRange(-50, 50, 1); + m_levelInput->setValue(10); + break; + + case DistortionFX::FishEye: + case DistortionFX::CilindricalHor: + case DistortionFX::CilindricalVert: + case DistortionFX::CilindricalHV: + case DistortionFX::Caricature: + m_levelInput->setRange(0, 200, 1); + m_levelInput->setValue(50); + break; + + case DistortionFX::MultipleCorners: + m_levelInput->setRange(1, 10, 1); + m_levelInput->setValue(4); + break; + + case DistortionFX::WavesHorizontal: + case DistortionFX::WavesVertical: + case DistortionFX::BlockWaves1: + case DistortionFX::BlockWaves2: + case DistortionFX::CircularWaves1: + case DistortionFX::CircularWaves2: + case DistortionFX::Tile: + m_iterationInput->setEnabled(true); + m_iterationLabel->setEnabled(true); + m_iterationInput->setRange(0, 200, 1); + m_iterationInput->setValue(10); + break; + + case DistortionFX::PolarCoordinates: + case DistortionFX::UnpolarCoordinates: + m_levelInput->setEnabled(false); + m_levelLabel->setEnabled(false); + break; + } + + m_levelInput->blockSignals(false); + m_iterationInput->blockSignals(false); + + slotEffect(); +} + +void DistortionFXTool::prepareEffect() +{ + m_effectTypeLabel->setEnabled(false); + m_effectType->setEnabled(false); + m_levelInput->setEnabled(false); + m_levelLabel->setEnabled(false); + m_iterationInput->setEnabled(false); + m_iterationLabel->setEnabled(false); + + int l = m_levelInput->value(); + int f = m_iterationInput->value(); + int e = m_effectType->currentItem(); + + ImageIface* iface = m_previewWidget->imageIface(); + + uchar *data = iface->getPreviewImage(); + DImg image(iface->previewWidth(), iface->previewHeight(), iface->previewSixteenBit(), + iface->previewHasAlpha(), data); + delete [] data; + + setFilter(dynamic_cast<DImgThreadedFilter *> (new DistortionFX(&image, this, e, l, f))); +} + +void DistortionFXTool::prepareFinal() +{ + m_effectTypeLabel->setEnabled(false); + m_effectType->setEnabled(false); + m_levelInput->setEnabled(false); + m_levelLabel->setEnabled(false); + m_iterationInput->setEnabled(false); + m_iterationLabel->setEnabled(false); + + int l = m_levelInput->value(); + int f = m_iterationInput->value(); + int e = m_effectType->currentItem(); + + ImageIface iface(0, 0); + + setFilter(dynamic_cast<DImgThreadedFilter *> (new DistortionFX(iface.getOriginalImg(), this, e, l, f))); +} + +void DistortionFXTool::putPreviewData(void) +{ + ImageIface* iface = m_previewWidget->imageIface(); + + DImg imDest = filter()->getTargetImage() + .smoothScale(iface->previewWidth(), iface->previewHeight()); + iface->putPreviewImage(imDest.bits()); + + m_previewWidget->updatePreview(); +} + +void DistortionFXTool::putFinalData(void) +{ + ImageIface iface(0, 0); + DImg targetImage = filter()->getTargetImage(); + iface.putOriginalImage(i18n("Distortion Effects"), + targetImage.bits(), + targetImage.width(), targetImage.height()); +} + +} // NameSpace DigikamDistortionFXImagesPlugin + diff --git a/src/imageplugins/distortionfx/distortionfxtool.h b/src/imageplugins/distortionfx/distortionfxtool.h new file mode 100644 index 00000000..bcdd6088 --- /dev/null +++ b/src/imageplugins/distortionfx/distortionfxtool.h @@ -0,0 +1,96 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-11 + * Description : a plugin to apply Distortion FX to an image. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * Original Distortion algorithms copyrighted 2004-2005 by + * Pieter Z. Voloshyn <pieter dot voloshyn 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. + * + * ============================================================ */ + +#ifndef DISTORTIONFXTOOL_H +#define DISTORTIONFXTOOL_H + +// Digikam includes. + +#include "editortool.h" + +class TQLabel; + +namespace KDcrawIface +{ +class RIntNumInput; +class RComboBox; +} + +namespace Digikam +{ +class ImageWidget; +} + +namespace DigikamDistortionFXImagesPlugin +{ + +class DistortionFXTool : public Digikam::EditorToolThreaded +{ + TQ_OBJECT + + +public: + + DistortionFXTool(TQObject *parent); + ~DistortionFXTool(); + +private slots: + + void slotEffectTypeChanged(int type); + void slotResetSettings(); + void slotColorGuideChanged(); + +private: + + void readSettings(); + void writeSettings(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + + TQLabel *m_effectTypeLabel; + TQLabel *m_levelLabel; + TQLabel *m_iterationLabel; + + KDcrawIface::RComboBox *m_effectType; + + KDcrawIface::RIntNumInput *m_levelInput; + KDcrawIface::RIntNumInput *m_iterationInput; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamDistortionFXImagesPlugin + +#endif /* DISTORTIONFXTOOL_H */ diff --git a/src/imageplugins/distortionfx/imageeffect_distortionfx.cpp b/src/imageplugins/distortionfx/imageeffect_distortionfx.cpp new file mode 100644 index 00000000..695e7749 --- /dev/null +++ b/src/imageplugins/distortionfx/imageeffect_distortionfx.cpp @@ -0,0 +1,378 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-11 + * Description : a plugin to apply Distortion FX to an image. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * Original Distortion algorithms copyrighted 2004-2005 by + * Pieter Z. Voloshyn <pieter dot voloshyn 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqlabel.h> +#include <tqwhatsthis.h> +#include <tqlayout.h> +#include <tqframe.h> +#include <tqimage.h> +#include <tqspinbox.h> +#include <tqcombobox.h> + +// KDE includes. + +#include <tdeconfig.h> +#include <tdelocale.h> +#include <kcursor.h> +#include <tdeaboutdata.h> +#include <khelpmenu.h> +#include <tdeapplication.h> +#include <knuminput.h> +#include <kstandarddirs.h> +#include <kprogress.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "distortionfx.h" +#include "imageeffect_distortionfx.h" +#include "imageeffect_distortionfx.moc" + +namespace DigikamDistortionFXImagesPlugin +{ + +ImageEffect_DistortionFX::ImageEffect_DistortionFX(TQWidget* parent) + : Digikam::ImageGuideDlg(parent, i18n("Distortion Effects"), + "distortionfx", false, true, false, + Digikam::ImageGuideWidget::HVGuideMode) +{ + // About data and help button. + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Distortion Effects"), + digikam_version, + I18N_NOOP("A digiKam image plugin to apply distortion effects to an image."), + TDEAboutData::License_GPL, + "(c) 2005, Gilles Caulier\n" + "(c) 2006-2008, Gilles Caulier and Marcel Wiesweg", + 0, + "http://www.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + about->addAuthor("Pieter Z. Voloshyn", I18N_NOOP("Distortion algorithms"), + "pieter dot voloshyn at gmail dot com"); + + about->addAuthor("Marcel Wiesweg", I18N_NOOP("Developer"), + "marcel dot wiesweg at gmx dot de"); + + setAboutData(about); + + TQWhatsThis::add( m_imagePreviewWidget, i18n("<p>This is the preview of the distortion effect " + "applied to the photograph.") ); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(plainPage()); + TQGridLayout* gridSettings = new TQGridLayout( gboxSettings, 5, 2, spacingHint()); + + m_effectTypeLabel = new TQLabel(i18n("Type:"), gboxSettings); + + m_effectType = new TQComboBox( false, gboxSettings ); + m_effectType->insertItem( i18n("Fish Eyes") ); + m_effectType->insertItem( i18n("Twirl") ); + m_effectType->insertItem( i18n("Cylindrical Hor.") ); + m_effectType->insertItem( i18n("Cylindrical Vert.") ); + m_effectType->insertItem( i18n("Cylindrical H/V.") ); + m_effectType->insertItem( i18n("Caricature") ); + m_effectType->insertItem( i18n("Multiple Corners") ); + m_effectType->insertItem( i18n("Waves Hor.") ); + m_effectType->insertItem( i18n("Waves Vert.") ); + m_effectType->insertItem( i18n("Block Waves 1") ); + m_effectType->insertItem( i18n("Block Waves 2") ); + m_effectType->insertItem( i18n("Circular Waves 1") ); + m_effectType->insertItem( i18n("Circular Waves 2") ); + m_effectType->insertItem( i18n("Polar Coordinates") ); + m_effectType->insertItem( i18n("Unpolar Coordinates") ); + m_effectType->insertItem( i18n("Tile") ); + TQWhatsThis::add( m_effectType, i18n("<p>Here, select the type of effect to apply to the image.<p>" + "<b>Fish Eyes</b>: warps the photograph around a 3D spherical shape to " + "reproduce the common photograph 'Fish Eyes' effect.<p>" + "<b>Twirl</b>: spins the photograph to produce a Twirl pattern.<p>" + "<b>Cylinder Hor.</b>: warps the photograph around a horizontal cylinder.<p>" + "<b>Cylinder Vert.</b>: warps the photograph around a vertical cylinder.<p>" + "<b>Cylinder H/V.</b>: warps the photograph around 2 cylinders, vertical " + "and horizontal.<p>" + "<b>Caricature</b>: distorts the photograph with the 'Fish Eyes' effect inverted.<p>" + "<b>Multiple Corners</b>: splits the photograph like a multiple corners pattern.<p>" + "<b>WavesQt Horizontal</b>: distorts the photograph with horizontal waves.<p>" + "<b>Waves Vertical</b>: distorts the photograph with vertical waves.<p>" + "<b>Block Waves 1</b>: divides the image into cells and makes it look as " + "if it is being viewed through glass blocks.<p>" + "<b>Block Waves 2</b>: like Block Waves 1 but with another version " + "of glass blocks distortion.<p>" + "<b>Circular Waves 1</b>: distorts the photograph with circular waves.<p>" + "<b>Circular Waves 2</b>: another variation of the Circular Waves effect.<p>" + "<b>Polar Coordinates</b>: converts the photograph from rectangular " + "to polar coordinates.<p>" + "<b>Unpolar Coordinates</b>: the Polar Coordinates effect inverted.<p>" + "<b>Tile</b>: splits the photograph into square blocks and moves " + "them randomly inside the image.<p>" + )); + gridSettings->addMultiCellWidget(m_effectTypeLabel, 0, 0, 0, 2); + gridSettings->addMultiCellWidget(m_effectType, 1, 1, 0, 2); + + m_levelLabel = new TQLabel(i18n("Level:"), gboxSettings); + m_levelInput = new KIntNumInput(gboxSettings); + m_levelInput->setRange(0, 100, 1, true); + TQWhatsThis::add( m_levelInput, i18n("<p>Set here the level of the effect.")); + + gridSettings->addMultiCellWidget(m_levelLabel, 2, 2, 0, 2); + gridSettings->addMultiCellWidget(m_levelInput, 3, 3, 0, 2); + + m_iterationLabel = new TQLabel(i18n("Iteration:"), gboxSettings); + m_iterationInput = new KIntNumInput(gboxSettings); + m_iterationInput->setRange(0, 100, 1, true); + TQWhatsThis::add( m_iterationInput, i18n("<p>This value controls the iterations to use for Waves, " + "Tile, and Neon effects.")); + + gridSettings->addMultiCellWidget(m_iterationLabel, 4, 4, 0, 2); + gridSettings->addMultiCellWidget(m_iterationInput, 5, 5, 0, 2); + + setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + connect(m_effectType, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotEffectTypeChanged(int))); + + connect(m_levelInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_iterationInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); +} + +ImageEffect_DistortionFX::~ImageEffect_DistortionFX() +{ +} + +void ImageEffect_DistortionFX::renderingFinished() +{ + m_effectTypeLabel->setEnabled(true); + m_effectType->setEnabled(true); + m_levelInput->setEnabled(true); + m_levelLabel->setEnabled(true); + m_iterationInput->setEnabled(true); + m_iterationLabel->setEnabled(true); + + switch (m_effectType->currentItem()) + { + case DistortionFX::FishEye: + case DistortionFX::Twirl: + case DistortionFX::CilindricalHor: + case DistortionFX::CilindricalVert: + case DistortionFX::CilindricalHV: + case DistortionFX::Caricature: + case DistortionFX::MultipleCorners: + break; + + case DistortionFX::PolarCoordinates: + case DistortionFX::UnpolarCoordinates: + m_levelInput->setEnabled(false); + m_levelLabel->setEnabled(false); + break; + + case DistortionFX::WavesHorizontal: + case DistortionFX::WavesVertical: + case DistortionFX::BlockWaves1: + case DistortionFX::BlockWaves2: + case DistortionFX::CircularWaves1: + case DistortionFX::CircularWaves2: + case DistortionFX::Tile: + m_iterationInput->setEnabled(true); + m_iterationLabel->setEnabled(true); + break; + } +} + +void ImageEffect_DistortionFX::readUserSettings(void) +{ + TDEConfig *config = kapp->config(); + config->setGroup("distortionfx Tool Dialog"); + + m_effectType->blockSignals(true); + m_iterationInput->blockSignals(true); + m_levelInput->blockSignals(true); + + m_effectType->setCurrentItem(config->readNumEntry("EffectType", DistortionFX::FishEye)); + m_iterationInput->setValue(config->readNumEntry("IterationAjustment", 10)); + m_levelInput->setValue(config->readNumEntry("LevelAjustment", 50)); + + m_effectType->blockSignals(false); + m_iterationInput->blockSignals(false); + m_levelInput->blockSignals(false); + + slotEffect(); +} + +void ImageEffect_DistortionFX::writeUserSettings(void) +{ + TDEConfig *config = kapp->config(); + config->setGroup("distortionfx Tool Dialog"); + config->writeEntry("EffectType", m_effectType->currentItem()); + config->writeEntry("IterationAjustment", m_iterationInput->value()); + config->writeEntry("LevelAjustment", m_levelInput->value()); + config->sync(); +} + +void ImageEffect_DistortionFX::resetValues() +{ + m_effectType->blockSignals(true); + m_effectType->setCurrentItem(DistortionFX::FishEye); + slotEffectTypeChanged(DistortionFX::FishEye); + m_effectType->blockSignals(false); +} + +void ImageEffect_DistortionFX::slotEffectTypeChanged(int type) +{ + m_levelInput->setEnabled(true); + m_levelLabel->setEnabled(true); + + m_levelInput->blockSignals(true); + m_iterationInput->blockSignals(true); + m_levelInput->setRange(0, 100, 1, true); + m_levelInput->setValue(25); + + switch (type) + { + case DistortionFX::Twirl: + m_levelInput->setRange(-50, 50, 1, true); + m_levelInput->setValue(10); + break; + + case DistortionFX::FishEye: + case DistortionFX::CilindricalHor: + case DistortionFX::CilindricalVert: + case DistortionFX::CilindricalHV: + case DistortionFX::Caricature: + m_levelInput->setRange(0, 200, 1, true); + m_levelInput->setValue(50); + break; + + case DistortionFX::MultipleCorners: + m_levelInput->setRange(1, 10, 1, true); + m_levelInput->setValue(4); + break; + + case DistortionFX::WavesHorizontal: + case DistortionFX::WavesVertical: + case DistortionFX::BlockWaves1: + case DistortionFX::BlockWaves2: + case DistortionFX::CircularWaves1: + case DistortionFX::CircularWaves2: + case DistortionFX::Tile: + m_iterationInput->setEnabled(true); + m_iterationLabel->setEnabled(true); + m_iterationInput->setRange(0, 200, 1, true); + m_iterationInput->setValue(10); + break; + + case DistortionFX::PolarCoordinates: + case DistortionFX::UnpolarCoordinates: + m_levelInput->setEnabled(false); + m_levelLabel->setEnabled(false); + break; + } + + m_levelInput->blockSignals(false); + m_iterationInput->blockSignals(false); + + slotEffect(); +} + +void ImageEffect_DistortionFX::prepareEffect() +{ + m_effectTypeLabel->setEnabled(false); + m_effectType->setEnabled(false); + m_levelInput->setEnabled(false); + m_levelLabel->setEnabled(false); + m_iterationInput->setEnabled(false); + m_iterationLabel->setEnabled(false); + + int l = m_levelInput->value(); + int f = m_iterationInput->value(); + int e = m_effectType->currentItem(); + + Digikam::ImageIface* iface = m_imagePreviewWidget->imageIface(); + + uchar *data = iface->getPreviewImage(); + Digikam::DImg image(iface->previewWidth(), iface->previewHeight(), iface->previewSixteenBit(), + iface->previewHasAlpha(), data); + delete [] data; + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new DistortionFX(&image, this, e, l, f)); +} + +void ImageEffect_DistortionFX::prepareFinal() +{ + m_effectTypeLabel->setEnabled(false); + m_effectType->setEnabled(false); + m_levelInput->setEnabled(false); + m_levelLabel->setEnabled(false); + m_iterationInput->setEnabled(false); + m_iterationLabel->setEnabled(false); + + int l = m_levelInput->value(); + int f = m_iterationInput->value(); + int e = m_effectType->currentItem(); + + Digikam::ImageIface iface(0, 0); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new DistortionFX(iface.getOriginalImg(), this, e, l, f)); +} + +void ImageEffect_DistortionFX::putPreviewData(void) +{ + Digikam::ImageIface* iface = m_imagePreviewWidget->imageIface(); + + Digikam::DImg imDest = m_threadedFilter->getTargetImage() + .smoothScale(iface->previewWidth(), iface->previewHeight()); + iface->putPreviewImage(imDest.bits()); + + m_imagePreviewWidget->updatePreview(); +} + +void ImageEffect_DistortionFX::putFinalData(void) +{ + Digikam::ImageIface iface(0, 0); + + iface.putOriginalImage(i18n("Distortion Effects"), + m_threadedFilter->getTargetImage().bits()); +} + +} // NameSpace DigikamDistortionFXImagesPlugin + diff --git a/src/imageplugins/distortionfx/imageeffect_distortionfx.h b/src/imageplugins/distortionfx/imageeffect_distortionfx.h new file mode 100644 index 00000000..652b372b --- /dev/null +++ b/src/imageplugins/distortionfx/imageeffect_distortionfx.h @@ -0,0 +1,82 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-11 + * Description : a plugin to apply Distortion FX to an image. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * Original Distortion algorithms copyrighted 2004-2005 by + * Pieter Z. Voloshyn <pieter dot voloshyn 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_DISTORTIONFX_H +#define IMAGEEFFECT_DISTORTIONFX_H + +// Digikam includes. + +#include "imageguidedlg.h" + +class TQComboBox; +class TQLabel; + +class KIntNumInput; + +namespace DigikamDistortionFXImagesPlugin +{ + +class ImageEffect_DistortionFX : public Digikam::ImageGuideDlg +{ + TQ_OBJECT + + +public: + + ImageEffect_DistortionFX(TQWidget *parent); + ~ImageEffect_DistortionFX(); + +private slots: + + void slotEffectTypeChanged(int type); + void readUserSettings(); + +private: + + void writeUserSettings(); + void resetValues(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + TQComboBox *m_effectType; + + TQLabel *m_effectTypeLabel; + TQLabel *m_levelLabel; + TQLabel *m_iterationLabel; + + KIntNumInput *m_levelInput; + KIntNumInput *m_iterationInput; +}; + +} // NameSpace DigikamDistortionFXImagesPlugin + +#endif /* IMAGEEFFECT_DISTORTIONFX_H */ diff --git a/src/imageplugins/distortionfx/imageplugin_distortionfx.cpp b/src/imageplugins/distortionfx/imageplugin_distortionfx.cpp new file mode 100644 index 00000000..582e1b99 --- /dev/null +++ b/src/imageplugins/distortionfx/imageplugin_distortionfx.cpp @@ -0,0 +1,72 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-11 + * Description : a plugin to apply Distortion FX to an image. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * Original Distortion algorithms copyrighted 2004-2005 by + * Pieter Z. Voloshyn <pieter dot voloshyn 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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> + +// Local includes. + +#include "ddebug.h" +#include "distortionfxtool.h" +#include "imageplugin_distortionfx.h" +#include "imageplugin_distortionfx.moc" + +using namespace DigikamDistortionFXImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_distortionfx, + KGenericFactory<ImagePlugin_DistortionFX>("digikamimageplugin_distortionfx")); + +ImagePlugin_DistortionFX::ImagePlugin_DistortionFX(TQObject *parent, const char*, const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_DistortionFX") +{ + m_distortionfxAction = new TDEAction(i18n("Distortion Effects..."), "distortionfx", 0, + this, TQ_SLOT(slotDistortionFX()), + actionCollection(), "imageplugin_distortionfx"); + + setXMLFile( "digikamimageplugin_distortionfx_ui.rc" ); + + DDebug() << "ImagePlugin_DistortionFX plugin loaded" << endl; +} + +ImagePlugin_DistortionFX::~ImagePlugin_DistortionFX() +{ +} + +void ImagePlugin_DistortionFX::setEnabledActions(bool enable) +{ + m_distortionfxAction->setEnabled(enable); +} + +void ImagePlugin_DistortionFX::slotDistortionFX() +{ + DistortionFXTool *distortionfx = new DistortionFXTool(this); + loadTool(distortionfx); +} diff --git a/src/imageplugins/distortionfx/imageplugin_distortionfx.h b/src/imageplugins/distortionfx/imageplugin_distortionfx.h new file mode 100644 index 00000000..2af33a14 --- /dev/null +++ b/src/imageplugins/distortionfx/imageplugin_distortionfx.h @@ -0,0 +1,59 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-11 + * Description : a plugin to apply Distortion FX to an image. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * Original Distortion algorithms copyrighted 2004-2005 by + * Pieter Z. Voloshyn <pieter dot voloshyn 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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_DISTORTIONFX_H +#define IMAGEPLUGIN_DISTORTIONFX_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_DistortionFX : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_DistortionFX(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_DistortionFX(); + + void setEnabledActions(bool enable); + +private slots: + + void slotDistortionFX(); + +private: + + TDEAction *m_distortionfxAction; +}; + +#endif /* IMAGEPLUGIN_DISTORTIONFX_H */ diff --git a/src/imageplugins/emboss/Makefile.am b/src/imageplugins/emboss/Makefile.am new file mode 100644 index 00000000..c595aa30 --- /dev/null +++ b/src/imageplugins/emboss/Makefile.am @@ -0,0 +1,34 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_emboss_la_SOURCES = imageplugin_emboss.cpp \ + embosstool.cpp emboss.cpp + +digikamimageplugin_emboss_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_emboss_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_emboss.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_emboss.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_emboss_ui.rc + diff --git a/src/imageplugins/emboss/digikamimageplugin_emboss.desktop b/src/imageplugins/emboss/digikamimageplugin_emboss.desktop new file mode 100644 index 00000000..414f235b --- /dev/null +++ b/src/imageplugins/emboss/digikamimageplugin_emboss.desktop @@ -0,0 +1,51 @@ +[Desktop Entry] +Name=ImagePlugin_Emboss +Name[bg]=Приставка за снимки - Релеф +Name[da]=Billedplugin_Præg i relief +Name[el]=ΠρόσθετοΕικόνας_Εμβάθυνση +Name[fi]=Kohokuvio +Name[hr]=Reljef +Name[it]=PluginImmagini_Rilievo +Name[nl]=Afbeeldingsplugin_Reliëf +Name[sr]=Рељеф +Name[sr@Latn]=Reljef +Name[sv]=Insticksprogram för reliefeffekt +Name[tr]=ResimEklentisi_Kabart +Name[xx]=xxImagePlugin_Embossxx +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=Emboss image effect plugin for digiKam +Comment[bg]=Приставка на digiKam за добавяне на релеф към снимки +Comment[ca]=Connector pel digiKam d'efecte d'imatge de relleu +Comment[cs]=Efektový modul pro tvorbu reliéfu pro digiKam +Comment[da]=Reliefprægnings-plugin for Digikam +Comment[de]=digiKam-Modul zum Erzeugen eines Gravureffektes +Comment[el]=Πρόσθετο εφέ εμβάθυνσης για το digiKam +Comment[es]=Plugin para digiKam con efectos de bajo relieve +Comment[et]=DigiKami kohrutuse pildiefektiplugin +Comment[fa]=برجسته کردن وصلۀ جلوۀ تصویر برای digiKam +Comment[fi]=Kohokuvioefekti kohteiden ääriviivoista +Comment[gl]=Un plugin de digiKam para dar-lle relevo á imaxe +Comment[hr]=digiKam dodatak za efekt reljefa +Comment[is]=Íforrit fyrir digiKam sem framkallar upphleypingaráhrif +Comment[it]=Plugin di effetto di rilievo delle immagini per digiKam +Comment[ja]=digiKam エンボス効果プラグイン +Comment[nds]=digiKam-Moduul för Ingraav-Effekten +Comment[nl]=Digikam-plugin voor reliëf-afbeeldingen +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਈਮਬੋਸ ਚਿੱਤਰ ਪਰਭਾਵ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam oferująca efekty zniekształceń +Comment[pt]=Um 'plugin' do digiKam para gravar em relevo a imagem +Comment[pt_BR]=Plugin de efeito de estampa +Comment[ru]=Модуль рельефного рисунка для digiKam +Comment[sk]=digiKam plugin pre efekt reliéfu +Comment[sr]=digiKam-ов прикључак за ефекат рељефа на сликама +Comment[sr@Latn]=digiKam-ov priključak za efekat reljefa na slikama +Comment[sv]=Digikam insticksprogram för reliefbildeffekt +Comment[tr]=digiKam için resim kabartma etkisi eklentisi +Comment[uk]=Втулок створення ефекту барельєфу для digiKam +Comment[vi]=Phần bổ sung hiệu ứng chạm nổi ảnh cho digiKam +Comment[xx]=xxEmboss image effect plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_emboss +author=Gilles Caulier, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/emboss/digikamimageplugin_emboss_ui.rc b/src/imageplugins/emboss/digikamimageplugin_emboss_ui.rc new file mode 100644 index 00000000..1a6943c6 --- /dev/null +++ b/src/imageplugins/emboss/digikamimageplugin_emboss_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="5" name="digikamimageplugin_emboss" > + + <MenuBar> + + <Menu name="Filters" ><text>F&ilters</text> + <Action name="imageplugin_emboss" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action shortcut="" name="imageplugin_emboss" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/emboss/emboss.cpp b/src/imageplugins/emboss/emboss.cpp new file mode 100644 index 00000000..d4225148 --- /dev/null +++ b/src/imageplugins/emboss/emboss.cpp @@ -0,0 +1,127 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : Emboss threaded image filter. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * Original Emboss algorithm copyrighted 2004 by + * Pieter Z. Voloshyn <pieter dot voloshyn 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> +#include <cstdlib> + +// Local includes. + +#include "dimg.h" +#include "dimgimagefilters.h" +#include "emboss.h" + +namespace DigikamEmbossImagesPlugin +{ + +Emboss::Emboss(Digikam::DImg *orgImage, TQObject *parent, int depth) + : Digikam::DImgThreadedFilter(orgImage, parent, "Emboss") +{ + m_depth = depth; + initFilter(); +} + +void Emboss::filterImage(void) +{ + embossImage(&m_orgImage, &m_destImage, m_depth); +} + +// This method have been ported from Pieter Z. Voloshyn algorithm code. + +/* Function to apply the Emboss effect + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * d => Emboss value + * + * Theory => This is an amazing effect. And the theory is very simple to + * understand. You get the diference between the colors and + * increase it. After this, get the gray tone + */ + +void Emboss::embossImage(Digikam::DImg *orgImage, Digikam::DImg *destImage, int d) +{ + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* Bits = destImage->bits(); + + // Initial copy + memcpy (Bits, data, destImage->numBytes()); + + double Depth = d / 10.0; + + int progress; + int red, green, blue, gray; + Digikam::DColor color, colorOther; + int offset, offsetOther; + + for (int h = 0 ; !m_cancel && (h < Height) ; h++) + { + for (int w = 0 ; !m_cancel && (w < Width) ; w++) + { + offset = getOffset(Width, w, h, bytesDepth); + offsetOther = getOffset(Width, w + Lim_Max (w, 1, Width), h + Lim_Max (h, 1, Height), bytesDepth); + + color.setColor(Bits + offset, sixteenBit); + colorOther.setColor(Bits + offsetOther, sixteenBit); + + if (sixteenBit) + { + red = abs ((int)((color.red() - colorOther.red()) * Depth + 32768)); + green = abs ((int)((color.green() - colorOther.green()) * Depth + 32768)); + blue = abs ((int)((color.blue() - colorOther.blue()) * Depth + 32768)); + + gray = CLAMP065535 ((red + green + blue) / 3); + } + else + { + red = abs ((int)((color.red() - colorOther.red()) * Depth + 128)); + green = abs ((int)((color.green() - colorOther.green()) * Depth + 128)); + blue = abs ((int)((color.blue() - colorOther.blue()) * Depth + 128)); + + gray = CLAMP0255 ((red + green + blue) / 3); + } + + // Overwrite RGB values to destination. Alpha remains unchanged. + color.setRed(gray); + color.setGreen(gray); + color.setBlue(gray); + color.setPixel(Bits + offset); + } + + progress = (int) (((double)h * 100.0) / Height); + if ( progress%5 == 0 ) + postProgress( progress ); + } +} + +} // NameSpace DigikamEmbossImagesPlugin diff --git a/src/imageplugins/emboss/emboss.h b/src/imageplugins/emboss/emboss.h new file mode 100644 index 00000000..470755a6 --- /dev/null +++ b/src/imageplugins/emboss/emboss.h @@ -0,0 +1,75 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : Emboss threaded image filter. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * Original Emboss algorithm copyrighted 2004 by + * Pieter Z. Voloshyn <pieter dot voloshyn 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. + * + * ============================================================ */ + +#ifndef EMBOSS_H +#define EMBOSS_H + +// Digikam includes. + +#include "dimgthreadedfilter.h" + +namespace DigikamEmbossImagesPlugin +{ + +class Emboss : public Digikam::DImgThreadedFilter +{ + +public: + + Emboss(Digikam::DImg *orgImage, TQObject *parent=0, int depth=30); + ~Emboss(){}; + +private: + + virtual void filterImage(void); + + + void embossImage(Digikam::DImg *orgImage, Digikam::DImg *destImage, int d); + + // Function to limit the max and min values defined by the developer. + + inline int Lim_Max (int Now, int Up, int Max) + { + --Max; + while (Now > Max - Up) + --Up; + return (Up); + }; + + inline int getOffset(int Width, int X, int Y, int bytesDepth) + { + return (Y * Width * bytesDepth) + (X * bytesDepth); + }; + +private: + + int m_depth; +}; + +} // NameSpace DigikamEmbossImagesPlugin + +#endif /* EMBOSS_H */ diff --git a/src/imageplugins/emboss/embosstool.cpp b/src/imageplugins/emboss/embosstool.cpp new file mode 100644 index 00000000..f16ef4de --- /dev/null +++ b/src/imageplugins/emboss/embosstool.cpp @@ -0,0 +1,167 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-26 + * Description : a digiKam image editor plugin to emboss + * an image. + * + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <tqlabel.h> +#include <tqlayout.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <kstandarddirs.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> + +// Local includes. + +#include "daboutdata.h" +#include "imageiface.h" +#include "imagepanelwidget.h" +#include "editortoolsettings.h" +#include "emboss.h" +#include "embosstool.h" +#include "embosstool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamEmbossImagesPlugin +{ + +EmbossTool::EmbossTool(TQObject* parent) + : EditorToolThreaded(parent) +{ + setName("emboss"); + setToolName(i18n("Emboss")); + setToolIcon(SmallIcon("embosstool")); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel| + EditorToolSettings::PanIcon); + TQGridLayout* grid = new TQGridLayout( m_gboxSettings->plainPage(), 2, 1); + TQLabel *label1 = new TQLabel(i18n("Depth:"), m_gboxSettings->plainPage()); + + m_depthInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_depthInput->setRange(10, 300, 1); + m_depthInput->setDefaultValue(30); + TQWhatsThis::add( m_depthInput, i18n("<p>Set here the depth of the embossing image effect.") ); + + grid->addMultiCellWidget(label1, 0, 0, 0, 1); + grid->addMultiCellWidget(m_depthInput, 1, 1, 0, 1); + grid->setRowStretch(2, 10); + grid->setMargin(m_gboxSettings->spacingHint()); + grid->setSpacing(m_gboxSettings->spacingHint()); + + setToolSettings(m_gboxSettings); + + // ------------------------------------------------------------- + + m_previewWidget = new ImagePanelWidget(470, 350, "emboss Tool", m_gboxSettings->panIconView()); + + setToolView(m_previewWidget); + init(); + + // ------------------------------------------------------------- + + connect(m_depthInput, TQ_SIGNAL(valueChanged (int)), + this, TQ_SLOT(slotTimer())); +} + +EmbossTool::~EmbossTool() +{ +} + +void EmbossTool::renderingFinished() +{ + m_depthInput->setEnabled(true); +} + +void EmbossTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("emboss Tool"); + m_depthInput->blockSignals(true); + m_depthInput->setValue(config->readNumEntry("DepthAjustment", m_depthInput->defaultValue())); + m_depthInput->blockSignals(false); +} + +void EmbossTool::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("emboss Tool"); + config->writeEntry("DepthAjustment", m_depthInput->value()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void EmbossTool::slotResetSettings() +{ + m_depthInput->blockSignals(true); + m_depthInput->slotReset(); + m_depthInput->blockSignals(false); +} + +void EmbossTool::prepareEffect() +{ + m_depthInput->setEnabled(false); + + DImg image = m_previewWidget->getOriginalRegionImage(); + int depth = m_depthInput->value(); + + setFilter(dynamic_cast<DImgThreadedFilter*>(new Emboss(&image, this, depth))); +} + +void EmbossTool::prepareFinal() +{ + m_depthInput->setEnabled(false); + + int depth = m_depthInput->value(); + ImageIface iface(0, 0); + setFilter(dynamic_cast<DImgThreadedFilter*>(new Emboss(iface.getOriginalImg(), this, depth))); +} + +void EmbossTool::putPreviewData() +{ + m_previewWidget->setPreviewImage(filter()->getTargetImage()); +} + +void EmbossTool::putFinalData() +{ + ImageIface iface(0, 0); + iface.putOriginalImage(i18n("Emboss"), filter()->getTargetImage().bits()); +} + +} // NameSpace DigikamEmbossImagesPlugin diff --git a/src/imageplugins/emboss/embosstool.h b/src/imageplugins/emboss/embosstool.h new file mode 100644 index 00000000..224858f7 --- /dev/null +++ b/src/imageplugins/emboss/embosstool.h @@ -0,0 +1,82 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-26 + * Description : a digiKam image editor plugin to emboss + * an image. + * + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef EMBOSSTOOL_H +#define EMBOSSTOOL_H + +// Digikam includes. + +#include "editortool.h" + +namespace KDcrawIface +{ +class RIntNumInput; +} + +namespace Digikam +{ +class EditorToolSettings; +class ImagePanelWidget; +} + +namespace DigikamEmbossImagesPlugin +{ + +class EmbossTool : public Digikam::EditorToolThreaded +{ + TQ_OBJECT + + +public: + + EmbossTool(TQObject* parent); + ~EmbossTool(); + +private slots: + + void slotResetSettings(); + +private: + + void readSettings(); + void writeSettings(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + KDcrawIface::RIntNumInput *m_depthInput; + + Digikam::ImagePanelWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamEmbossImagesPlugin + +#endif /* EMBOSSTOOL_H */ diff --git a/src/imageplugins/emboss/imageeffect_emboss.cpp b/src/imageplugins/emboss/imageeffect_emboss.cpp new file mode 100644 index 00000000..b4557c80 --- /dev/null +++ b/src/imageplugins/emboss/imageeffect_emboss.cpp @@ -0,0 +1,170 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-26 + * Description : a digiKam image editor plugin to emboss + * an image. + * + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <tqlabel.h> +#include <tqwhatsthis.h> +#include <tqlayout.h> + +// KDE includes. + +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <kstandarddirs.h> +#include <knuminput.h> +#include <tdeconfig.h> + +// Local includes. + +#include "version.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "emboss.h" +#include "imageeffect_emboss.h" +#include "imageeffect_emboss.moc" + +namespace DigikamEmbossImagesPlugin +{ + +ImageEffect_Emboss::ImageEffect_Emboss(TQWidget* parent) + : Digikam::CtrlPanelDlg(parent, i18n("Emboss Image"), "emboss", false, false, true, + Digikam::ImagePannelWidget::SeparateViewAll) +{ + TQString whatsThis; + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Emboss Image"), + digikam_version, + I18N_NOOP("Emboss image effect plugin for digiKam."), + TDEAboutData::License_GPL, + "(c) 2004-2006, Gilles Caulier\n" + "(c) 2006-2008, Gilles Caulier and Marcel Wiesweg", + 0, + "http://www.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + about->addAuthor("Pieter Z. Voloshyn", I18N_NOOP("Emboss algorithm"), + "pieter dot voloshyn at gmail dot com"); + + about->addAuthor("Marcel Wiesweg", I18N_NOOP("Developer"), + "marcel dot wiesweg at gmx dot de"); + + setAboutData(about); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(m_imagePreviewWidget); + TQGridLayout* gridSettings = new TQGridLayout( gboxSettings, 1, 1, 0, spacingHint()); + TQLabel *label1 = new TQLabel(i18n("Depth:"), gboxSettings); + + m_depthInput = new KIntNumInput(gboxSettings); + m_depthInput->setRange(10, 300, 1, true); + TQWhatsThis::add( m_depthInput, i18n("<p>Set here the depth of the embossing image effect.") ); + + gridSettings->addMultiCellWidget(label1, 0, 0, 0, 1); + gridSettings->addMultiCellWidget(m_depthInput, 1, 1, 0, 1); + + m_imagePreviewWidget->setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + connect(m_depthInput, TQ_SIGNAL(valueChanged (int)), + this, TQ_SLOT(slotTimer())); +} + +ImageEffect_Emboss::~ImageEffect_Emboss() +{ +} + +void ImageEffect_Emboss::renderingFinished() +{ + m_depthInput->setEnabled(true); +} + +void ImageEffect_Emboss::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("emboss Tool Dialog"); + m_depthInput->blockSignals(true); + m_depthInput->setValue(config->readNumEntry("DepthAjustment", 30)); + m_depthInput->blockSignals(false); +} + +void ImageEffect_Emboss::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("emboss Tool Dialog"); + config->writeEntry("DepthAjustment", m_depthInput->value()); + config->sync(); +} + +void ImageEffect_Emboss::resetValues() +{ + m_depthInput->blockSignals(true); + m_depthInput->setValue(30); + m_depthInput->blockSignals(false); +} + +void ImageEffect_Emboss::prepareEffect() +{ + m_depthInput->setEnabled(false); + + Digikam::DImg image = m_imagePreviewWidget->getOriginalRegionImage(); + + int depth = m_depthInput->value(); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>(new Emboss(&image, this, depth)); +} + +void ImageEffect_Emboss::prepareFinal() +{ + m_depthInput->setEnabled(false); + + int depth = m_depthInput->value(); + + Digikam::ImageIface iface(0, 0); + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>(new Emboss(iface.getOriginalImg(), this, depth)); +} + +void ImageEffect_Emboss::putPreviewData(void) +{ + m_imagePreviewWidget->setPreviewImage(m_threadedFilter->getTargetImage()); +} + +void ImageEffect_Emboss::putFinalData(void) +{ + Digikam::ImageIface iface(0, 0); + + iface.putOriginalImage(i18n("Emboss"), + m_threadedFilter->getTargetImage().bits()); +} + +} // NameSpace DigikamEmbossImagesPlugin + diff --git a/src/imageplugins/emboss/imageeffect_emboss.h b/src/imageplugins/emboss/imageeffect_emboss.h new file mode 100644 index 00000000..19cf4f77 --- /dev/null +++ b/src/imageplugins/emboss/imageeffect_emboss.h @@ -0,0 +1,69 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-26 + * Description : a digiKam image editor plugin to emboss + * an image. + * + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_EMBOSS_H +#define IMAGEEFFECT_EMBOSS_H + +// Digikam includes. + +#include "ctrlpaneldlg.h" + +class KIntNumInput; + +namespace DigikamEmbossImagesPlugin +{ + +class ImageEffect_Emboss : public Digikam::CtrlPanelDlg +{ + TQ_OBJECT + + +public: + + ImageEffect_Emboss(TQWidget* parent); + ~ImageEffect_Emboss(); + +private slots: + + void readUserSettings(); + +private: + + void writeUserSettings(); + void resetValues(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + KIntNumInput *m_depthInput; +}; + +} // NameSpace DigikamEmbossImagesPlugin + +#endif /* IMAGEEFFECT_EMBOSS_H */ diff --git a/src/imageplugins/emboss/imageplugin_emboss.cpp b/src/imageplugins/emboss/imageplugin_emboss.cpp new file mode 100644 index 00000000..6bd616d6 --- /dev/null +++ b/src/imageplugins/emboss/imageplugin_emboss.cpp @@ -0,0 +1,72 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-26 + * Description : a digiKam image editor plugin to emboss + * an image. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> +#include <tdeapplication.h> + +// Local includes. + +#include "ddebug.h" +#include "embosstool.h" +#include "imageplugin_emboss.h" +#include "imageplugin_emboss.moc" + +using namespace DigikamEmbossImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_emboss, + KGenericFactory<ImagePlugin_Emboss>("digikamimageplugin_emboss")); + +ImagePlugin_Emboss::ImagePlugin_Emboss(TQObject *parent, const char*, + const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_Emboss") +{ + m_embossAction = new TDEAction(i18n("Emboss..."), "embosstool", 0, + this, TQ_SLOT(slotEmboss()), + actionCollection(), "imageplugin_emboss"); + + setXMLFile( "digikamimageplugin_emboss_ui.rc" ); + + DDebug() << "ImagePlugin_Emboss plugin loaded" << endl; +} + +ImagePlugin_Emboss::~ImagePlugin_Emboss() +{ +} + +void ImagePlugin_Emboss::setEnabledActions(bool enable) +{ + m_embossAction->setEnabled(enable); +} + +void ImagePlugin_Emboss::slotEmboss() +{ + EmbossTool *tool = new EmbossTool(this); + loadTool(tool); +} diff --git a/src/imageplugins/emboss/imageplugin_emboss.h b/src/imageplugins/emboss/imageplugin_emboss.h new file mode 100644 index 00000000..1ccac064 --- /dev/null +++ b/src/imageplugins/emboss/imageplugin_emboss.h @@ -0,0 +1,57 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-26 + * Description : a digiKam image editor plugin to emboss + * an image. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_EMBOSS_H +#define IMAGEPLUGIN_EMBOSS_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_Emboss : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_Emboss(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_Emboss(); + + void setEnabledActions(bool enable); + +private slots: + + void slotEmboss(); + +private: + + TDEAction *m_embossAction; +}; + +#endif /* IMAGEPLUGIN_EMBOSS_H */ diff --git a/src/imageplugins/filmgrain/Makefile.am b/src/imageplugins/filmgrain/Makefile.am new file mode 100644 index 00000000..c23c9d8e --- /dev/null +++ b/src/imageplugins/filmgrain/Makefile.am @@ -0,0 +1,34 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_filmgrain_la_SOURCES = imageplugin_filmgrain.cpp \ + filmgraintool.cpp filmgrain.cpp + +digikamimageplugin_filmgrain_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_filmgrain_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_filmgrain.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_filmgrain.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_filmgrain_ui.rc + diff --git a/src/imageplugins/filmgrain/digikamimageplugin_filmgrain.desktop b/src/imageplugins/filmgrain/digikamimageplugin_filmgrain.desktop new file mode 100644 index 00000000..5ad6582b --- /dev/null +++ b/src/imageplugins/filmgrain/digikamimageplugin_filmgrain.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Name=ImagePlugin_FilmGrain +Name[bg]=Приставка за снимки - Филмово зърно +Name[da]=Billedplugin_Filmkorn +Name[el]=ΠρόσθετοΕικόνας_ΚόκκοςΦιλμ +Name[fi]=Filmirakeet +Name[hr]=Zrnatost +Name[it]=PluginImmagini_GranaPellicola +Name[nl]=Afbeeldingsplugin_Filmkorrel +Name[sr]=Зрнаст филм +Name[sr@Latn]=Zrnast film +Name[sv]=Insticksprogram för filmkorn +Name[tr]=ResimEklentisi_FilmTanecikleri +Name[xx]=xxImagePlugin_FilmGrainxx + +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=Film grain image effect plugin for digiKam +Comment[bg]=Приставка на digiKam за наподобяване на филмово зърно +Comment[ca]=Connector pel digiKam d'efecte d'imatge de gra de pel·lícula +Comment[cs]=Efektový modul pro tvorbu filmového zrna pro digiKam +Comment[da]=Plugin til filmkorn-effekt på billeder i Digikam +Comment[de]=digiKam-Modul zum Erzeugen eines Effektes von körnigem Film +Comment[el]=Πρόσθετο εφέ κόκκου φιλμ για το digiKam +Comment[es]=Plugin para digiKam de efectos de imagen tipo grano fino de película +Comment[et]=DigiKami teralisuse pildiefektiplugin +Comment[fa]=وصلۀ جلوۀ تصویر خرده فیلم برای digiKam +Comment[fi]=Filmikuvien rakeisuuden jäljittelijä +Comment[gl]=Un plugin de digiKam para o efeito de grao de filme +Comment[hr]=digiKam dodatak za efekt zrnatosti filma +Comment[is]=Íforrit fyrir digiKam sem líkir eftir filmukornum +Comment[it]=Plugin per l'effetto di grana della pellicola delle immagini per digiKam +Comment[ja]=digiKam フィルム粒子効果プラグイン +Comment[nds]=digiKam-Moduul för Effekten vun körnig Film +Comment[nl]=Digikam-plugin voor filmkorrel +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਫਿਲਮ ਗਰੇਨ ਚਿੱਤਰ ਪਰਭਾਵ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam oferująca efekty zniekształceń +Comment[pt]=Um 'plugin' do digiKam para o efeito de grão de filme +Comment[pt_BR]=Um 'plugin' do digiKam para o efeito de grão de filme +Comment[ru]=Модуль зернистости изображения для digiKam +Comment[sk]=digiKam obrázkový plugin pre efekt filmového zrna +Comment[sr]=digiKam-ов прикључак за ефекат зрнастости филма +Comment[sr@Latn]=digiKam-ov priključak za efekat zrnastosti filma +Comment[sv]=Digikam insticksprogram för filmkornsbildeffekt +Comment[tr]=digiKam için film tanecikleri etkisi eklentisi +Comment[uk]=Втулок digiKam для створення ефекту фільму на зображеннях +Comment[vi]=Phần bổ sung hiệu ứng chạm mịn mặt màng ảnh cho digiKam +Comment[xx]=xxFilm grain image effect plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_filmgrain +author=Gilles Caulier, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/filmgrain/digikamimageplugin_filmgrain_ui.rc b/src/imageplugins/filmgrain/digikamimageplugin_filmgrain_ui.rc new file mode 100644 index 00000000..770c2dbd --- /dev/null +++ b/src/imageplugins/filmgrain/digikamimageplugin_filmgrain_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="5" name="digikamimageplugin_filmgrain" > + + <MenuBar> + + <Menu name="Filters" ><text>F&ilters</text> + <Action name="imageplugin_filmgrain" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action shortcut="" name="imageplugin_filmgrain" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/filmgrain/filmgrain.cpp b/src/imageplugins/filmgrain/filmgrain.cpp new file mode 100644 index 00000000..57616eb9 --- /dev/null +++ b/src/imageplugins/filmgrain/filmgrain.cpp @@ -0,0 +1,202 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : FilmGrain threaded image filter. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2005-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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> +#include <cstdlib> + +// TQt includes. + +#include <tqdatetime.h> + +// Local includes. + +#include "ddebug.h" +#include "dimg.h" +#include "dimggaussianblur.h" +#include "imagecurves.h" +#include "imagehistogram.h" +#include "dimgimagefilters.h" +#include "filmgrain.h" + +namespace DigikamFilmGrainImagesPlugin +{ + +FilmGrain::FilmGrain(Digikam::DImg *orgImage, TQObject *parent, int sensibility) + : Digikam::DImgThreadedFilter(orgImage, parent, "FilmGrain") +{ + m_sensibility = sensibility; + initFilter(); +} + +void FilmGrain::filterImage(void) +{ + filmgrainImage(&m_orgImage, m_sensibility); +} + +// This method is based on the Simulate Film grain tutorial from GimpGuru.org web site +// available at this url : http://www.gimpguru.org/Tutorials/FilmGrain + +void FilmGrain::filmgrainImage(Digikam::DImg *orgImage, int Sensibility) +{ + // Sensibility: 800..6400 + + if (Sensibility <= 0) return; + + int Width = orgImage->width(); + int Height = orgImage->height(); + int bytesDepth = orgImage->bytesDepth(); + bool sixteenBit = orgImage->sixteenBit(); + uchar* data = orgImage->bits(); + + Digikam::DImg grain(Width, Height, sixteenBit); // Grain blured without curves adjustment. + Digikam::DImg mask(Width, Height, sixteenBit); // Grain mask with curves adjustment. + uchar* pGrainBits = grain.bits(); + uchar* pMaskBits = mask.bits(); + uchar* pOutBits = m_destImage.bits(); // Destination image with merged grain mask and original. + + int Noise, Shade, nRand, component, progress; + uchar *ptr; + Digikam::DColor blendData, grainData, maskData, outData; + + if (sixteenBit) + Noise = (Sensibility / 10 + 1) * 256 - 1; + else + Noise = Sensibility / 10; + + // This value controls the shading pixel effect between original image and grain mask. + if (sixteenBit) + Shade = (52 + 1) * 256 - 1; + else + Shade = 52; + + TQDateTime dt = TQDateTime::currentDateTime(); + TQDateTime Y2000( TQDate(2000, 1, 1), TQTime(0, 0, 0) ); + uint seed = (uint) dt.secsTo(Y2000); + + // Make gray grain mask. + + grainData.setSixteenBit(sixteenBit); + + for (int x = 0; !m_cancel && x < Width; x++) + { + for (int y = 0; !m_cancel && y < Height; y++) + { + ptr = pGrainBits + x*bytesDepth + (y*Width*bytesDepth); + + nRand = (rand_r(&seed) % Noise) - (Noise / 2); + if (sixteenBit) + component = CLAMP(32768 + nRand, 0, 65535); + else + component = CLAMP(128 + nRand, 0, 255); + + grainData.setRed (component); + grainData.setGreen(component); + grainData.setBlue (component); + grainData.setAlpha(0); + + grainData.setPixel(ptr); + } + + // Update progress bar in dialog. + progress = (int) (((double)x * 25.0) / Width); + + if (progress%5 == 0) + postProgress( progress ); + } + + // Smooth grain mask using gaussian blur with radius 1. + Digikam::DImgGaussianBlur(this, grain, grain, 25, 30, 1); + + // Normally, film grain tends to be most noticeable in the midtones, and much less + // so in the shadows and highlights. Adjust histogram curve to adjust grain like this. + + Digikam::ImageCurves *grainCurves = new Digikam::ImageCurves(sixteenBit); + + // We modify only global luminosity of the grain. + if (sixteenBit) + { + grainCurves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, 0, TQPoint(0, 0)); + grainCurves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, 8, TQPoint(32768, 32768)); + grainCurves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, 16, TQPoint(65535, 0)); + } + else + { + grainCurves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, 0, TQPoint(0, 0)); + grainCurves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, 8, TQPoint(128, 128)); + grainCurves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, 16, TQPoint(255, 0)); + } + + // Calculate curves and lut to apply on grain. + grainCurves->curvesCalculateCurve(Digikam::ImageHistogram::ValueChannel); + grainCurves->curvesLutSetup(Digikam::ImageHistogram::AlphaChannel); + grainCurves->curvesLutProcess(pGrainBits, pMaskBits, Width, Height); + + grain.reset(); + delete grainCurves; + + // Update progress bar in dialog. + postProgress( 40 ); + + // Merge src image with grain using shade coefficient. + + int alpha; + // get composer for default blending + Digikam::DColorComposer *composer = Digikam::DColorComposer::getComposer(Digikam::DColorComposer::PorterDuffNone); + + for (int x = 0; !m_cancel && x < Width; x++) + { + for (int y = 0; !m_cancel && y < Height; y++) + { + int offset = x*bytesDepth + (y*Width*bytesDepth); + + // read color from orig image + blendData.setColor(data + offset, sixteenBit); + // read color from mask + maskData.setColor(pMaskBits + offset, sixteenBit); + // set shade as alpha value - it will be used as source alpha when blending + maskData.setAlpha(Shade); + + // compose, write result to blendData. + // Preserve alpha, do not blend it (taken from old algorithm - correct?) + alpha = blendData.alpha(); + composer->compose(blendData, maskData); + blendData.setAlpha(alpha); + + // write to destination + blendData.setPixel(pOutBits + offset); + } + + // Update progress bar in dialog. + progress = (int) (50.0 + ((double)x * 50.0) / Width); + + if (progress%5 == 0) + postProgress( progress ); + } + + delete composer; +} + +} // NameSpace DigikamFilmGrainImagesPlugin diff --git a/src/imageplugins/filmgrain/filmgrain.h b/src/imageplugins/filmgrain/filmgrain.h new file mode 100644 index 00000000..42bcf03c --- /dev/null +++ b/src/imageplugins/filmgrain/filmgrain.h @@ -0,0 +1,58 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : FilmGrain threaded image filter. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2005-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + + +#ifndef FILMGRAIN_H +#define FILMGRAIN_H + +// Digikam includes. + +#include "dimgthreadedfilter.h" + +namespace DigikamFilmGrainImagesPlugin +{ + +class FilmGrain : public Digikam::DImgThreadedFilter +{ + +public: + + FilmGrain(Digikam::DImg *orgImage, TQObject *parent=0, int sensibility=12); + + ~FilmGrain(){}; + +private: + + virtual void filterImage(void); + + void filmgrainImage(Digikam::DImg *orgImage, int Sensibility); + +private: + + int m_sensibility; +}; + +} // NameSpace DigikamFilmGrainImagesPlugin + +#endif /* FILMGRAIN_H */ diff --git a/src/imageplugins/filmgrain/filmgraintool.cpp b/src/imageplugins/filmgrain/filmgraintool.cpp new file mode 100644 index 00000000..5799d814 --- /dev/null +++ b/src/imageplugins/filmgrain/filmgraintool.cpp @@ -0,0 +1,195 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-26 + * Description : a digiKam image editor plugin for add film + * grain on an image. + * + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <tqlabel.h> +#include <tqwhatsthis.h> +#include <tqlcdnumber.h> +#include <tqslider.h> +#include <tqlayout.h> +#include <tqimage.h> + +// KDE includes. + +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <kstandarddirs.h> +#include <tdeconfig.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "imagepanelwidget.h" +#include "editortoolsettings.h" +#include "filmgrain.h" +#include "filmgraintool.h" +#include "filmgraintool.moc" + +using namespace Digikam; + +namespace DigikamFilmGrainImagesPlugin +{ + +FilmGrainTool::FilmGrainTool(TQObject* parent) + : EditorToolThreaded(parent) +{ + setName("filmgrain"); + setToolName(i18n("Film Grain")); + setToolIcon(SmallIcon("filmgrain")); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel| + EditorToolSettings::Try, + EditorToolSettings::PanIcon); + + TQGridLayout* grid = new TQGridLayout( m_gboxSettings->plainPage(), 2, 1); + TQLabel *label1 = new TQLabel(i18n("Sensitivity (ISO):"), m_gboxSettings->plainPage()); + + m_sensibilitySlider = new TQSlider(2, 30, 1, 12, TQt::Horizontal, m_gboxSettings->plainPage()); + m_sensibilitySlider->setTracking(false); + m_sensibilitySlider->setTickInterval(1); + m_sensibilitySlider->setTickmarks(TQSlider::Below); + + m_sensibilityLCDValue = new TQLCDNumber(4, m_gboxSettings->plainPage()); + m_sensibilityLCDValue->setSegmentStyle(TQLCDNumber::Flat); + m_sensibilityLCDValue->display(TQString::number(2400)); + TQString whatsThis = i18n("<p>Set here the film ISO-sensitivity to " + "use for simulating the film graininess."); + + TQWhatsThis::add(m_sensibilityLCDValue, whatsThis); + TQWhatsThis::add(m_sensibilitySlider, whatsThis); + + grid->addMultiCellWidget(label1, 0, 0, 0, 1); + grid->addMultiCellWidget(m_sensibilitySlider, 1, 1, 0, 0); + grid->addMultiCellWidget(m_sensibilityLCDValue, 1, 1, 1, 1); + grid->setRowStretch(2, 10); + grid->setMargin(m_gboxSettings->spacingHint()); + grid->setSpacing(m_gboxSettings->spacingHint()); + + setToolSettings(m_gboxSettings); + + // ------------------------------------------------------------- + + m_previewWidget = new ImagePanelWidget(470, 350, "filmgrain Tool", m_gboxSettings->panIconView()); + + setToolView(m_previewWidget); + init(); + + // ------------------------------------------------------------- + + connect( m_sensibilitySlider, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer()) ); + + // this connection is necessary to change the LCD display when + // the value is changed by single clicking on the slider + connect( m_sensibilitySlider, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotSliderMoved(int)) ); + + connect( m_sensibilitySlider, TQ_SIGNAL(sliderMoved(int)), + this, TQ_SLOT(slotSliderMoved(int)) ); +} + +FilmGrainTool::~FilmGrainTool() +{ +} + +void FilmGrainTool::renderingFinished() +{ + m_sensibilitySlider->setEnabled(true); +} + +void FilmGrainTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("filmgrain Tool"); + m_sensibilitySlider->blockSignals(true); + m_sensibilitySlider->setValue(config->readNumEntry("SensitivityAjustment", 12)); + m_sensibilitySlider->blockSignals(false); + slotSliderMoved(m_sensibilitySlider->value()); +} + +void FilmGrainTool::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("filmgrain Tool"); + config->writeEntry("SensitivityAjustment", m_sensibilitySlider->value()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void FilmGrainTool::slotResetSettings() +{ + m_sensibilitySlider->blockSignals(true); + m_sensibilitySlider->setValue(12); + m_sensibilitySlider->blockSignals(false); +} + +void FilmGrainTool::slotSliderMoved(int v) +{ + m_sensibilityLCDValue->display( TQString::number(400+200*v) ); +} + +void FilmGrainTool::prepareEffect() +{ + m_sensibilitySlider->setEnabled(false); + + DImg image = m_previewWidget->getOriginalRegionImage(); + int s = 400 + 200 * m_sensibilitySlider->value(); + + setFilter(dynamic_cast<DImgThreadedFilter*>(new FilmGrain(&image, this, s))); +} + +void FilmGrainTool::prepareFinal() +{ + m_sensibilitySlider->setEnabled(false); + + int s = 400 + 200 * m_sensibilitySlider->value(); + + ImageIface iface(0, 0); + + setFilter(dynamic_cast<DImgThreadedFilter*>(new FilmGrain(iface.getOriginalImg(), this, s))); +} + +void FilmGrainTool::putPreviewData() +{ + m_previewWidget->setPreviewImage(filter()->getTargetImage()); +} + +void FilmGrainTool::putFinalData() +{ + ImageIface iface(0, 0); + iface.putOriginalImage(i18n("Film Grain"), filter()->getTargetImage().bits()); +} + +} // NameSpace DigikamFilmGrainImagesPlugin diff --git a/src/imageplugins/filmgrain/filmgraintool.h b/src/imageplugins/filmgrain/filmgraintool.h new file mode 100644 index 00000000..1a179b53 --- /dev/null +++ b/src/imageplugins/filmgrain/filmgraintool.h @@ -0,0 +1,83 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-26 + * Description : a digiKam image editor plugin for add film + * grain on an image. + * + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef FILMGRAINTOOL_H +#define FILMGRAINTOOL_H + +// Digikam includes. + +#include "editortool.h" + +class TQSlider; +class TQLCDNumber; + +namespace Digikam +{ +class EditorToolSettings; +class ImagePanelWidget; +} + +namespace DigikamFilmGrainImagesPlugin +{ + +class FilmGrainTool : public Digikam::EditorToolThreaded +{ + TQ_OBJECT + + +public: + + FilmGrainTool(TQObject* parent); + ~FilmGrainTool(); + +private slots: + + void slotSliderMoved(int); + void slotResetSettings(); + +private: + + void readSettings(); + void writeSettings(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + TQSlider *m_sensibilitySlider; + + TQLCDNumber *m_sensibilityLCDValue; + + Digikam::ImagePanelWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamFilmGrainImagesPlugin + +#endif /* FILMGRAINTOOL_H */ diff --git a/src/imageplugins/filmgrain/imageeffect_filmgrain.cpp b/src/imageplugins/filmgrain/imageeffect_filmgrain.cpp new file mode 100644 index 00000000..e008095a --- /dev/null +++ b/src/imageplugins/filmgrain/imageeffect_filmgrain.cpp @@ -0,0 +1,195 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-26 + * Description : a digiKam image editor plugin for add film + * grain on an image. + * + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <tqlabel.h> +#include <tqwhatsthis.h> +#include <tqlcdnumber.h> +#include <tqslider.h> +#include <tqlayout.h> +#include <tqimage.h> + +// KDE includes. + +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <kstandarddirs.h> +#include <tdeconfig.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "filmgrain.h" +#include "imageeffect_filmgrain.h" +#include "imageeffect_filmgrain.moc" + +namespace DigikamFilmGrainImagesPlugin +{ + +ImageEffect_FilmGrain::ImageEffect_FilmGrain(TQWidget* parent) + : Digikam::CtrlPanelDlg(parent, i18n("Add Film Grain to Photograph"), + "filmgrain", false, false, true, + Digikam::ImagePannelWidget::SeparateViewAll) +{ + TQString whatsThis; + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Film Grain"), + digikam_version, + I18N_NOOP("A digiKam image plugin to apply a film grain " + "effect to an image."), + TDEAboutData::License_GPL, + "(c) 2004-2005, Gilles Caulier\n" + "(c) 2006-2008, Gilles Caulier and Marcel Wiesweg", + 0, + "http://www.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + about->addAuthor("Marcel Wiesweg", I18N_NOOP("Developer"), + "marcel dot wiesweg at gmx dot de"); + + setAboutData(about); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(m_imagePreviewWidget); + TQGridLayout* gridSettings = new TQGridLayout( gboxSettings, 1, 1, 0, spacingHint()); + TQLabel *label1 = new TQLabel(i18n("Sensitivity (ISO):"), gboxSettings); + + m_sensibilitySlider = new TQSlider(2, 30, 1, 12, TQt::Horizontal, gboxSettings); + m_sensibilitySlider->setTracking ( false ); + m_sensibilitySlider->setTickInterval(1); + m_sensibilitySlider->setTickmarks(TQSlider::Below); + + m_sensibilityLCDValue = new TQLCDNumber (4, gboxSettings); + m_sensibilityLCDValue->setSegmentStyle ( TQLCDNumber::Flat ); + m_sensibilityLCDValue->display( TQString::number(2400) ); + whatsThis = i18n("<p>Set here the film ISO-sensitivity to use for simulating the film graininess."); + + TQWhatsThis::add( m_sensibilityLCDValue, whatsThis); + TQWhatsThis::add( m_sensibilitySlider, whatsThis); + + gridSettings->addMultiCellWidget(label1, 0, 0, 0, 1); + gridSettings->addMultiCellWidget(m_sensibilitySlider, 1, 1, 0, 0); + gridSettings->addMultiCellWidget(m_sensibilityLCDValue, 1, 1, 1, 1); + + m_imagePreviewWidget->setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + connect( m_sensibilitySlider, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer()) ); + + // this connection is necessary to change the LCD display when + // the value is changed by single clicking on the slider + connect( m_sensibilitySlider, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotSliderMoved(int)) ); + + connect( m_sensibilitySlider, TQ_SIGNAL(sliderMoved(int)), + this, TQ_SLOT(slotSliderMoved(int)) ); +} + +ImageEffect_FilmGrain::~ImageEffect_FilmGrain() +{ +} + +void ImageEffect_FilmGrain::renderingFinished() +{ + m_sensibilitySlider->setEnabled(true); +} + +void ImageEffect_FilmGrain::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("filmgrain Tool Dialog"); + m_sensibilitySlider->blockSignals(true); + m_sensibilitySlider->setValue(config->readNumEntry("SensitivityAjustment", 12)); + m_sensibilitySlider->blockSignals(false); + slotSliderMoved(m_sensibilitySlider->value()); +} + +void ImageEffect_FilmGrain::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("filmgrain Tool Dialog"); + config->writeEntry("SensitivityAjustment", m_sensibilitySlider->value()); + config->sync(); +} + +void ImageEffect_FilmGrain::resetValues() +{ + m_sensibilitySlider->blockSignals(true); + m_sensibilitySlider->setValue(12); + m_sensibilitySlider->blockSignals(false); +} + +void ImageEffect_FilmGrain::slotSliderMoved(int v) +{ + m_sensibilityLCDValue->display( TQString::number(400+200*v) ); +} + +void ImageEffect_FilmGrain::prepareEffect() +{ + m_sensibilitySlider->setEnabled(false); + + Digikam::DImg image = m_imagePreviewWidget->getOriginalRegionImage(); + int s = 400 + 200 * m_sensibilitySlider->value(); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>(new FilmGrain(&image, this, s)); +} + +void ImageEffect_FilmGrain::prepareFinal() +{ + m_sensibilitySlider->setEnabled(false); + + int s = 400 + 200 * m_sensibilitySlider->value(); + + Digikam::ImageIface iface(0, 0); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>(new FilmGrain(iface.getOriginalImg(), this, s)); +} + +void ImageEffect_FilmGrain::putPreviewData(void) +{ + m_imagePreviewWidget->setPreviewImage(m_threadedFilter->getTargetImage()); +} + +void ImageEffect_FilmGrain::putFinalData(void) +{ + Digikam::ImageIface iface(0, 0); + iface.putOriginalImage(i18n("Film Grain"), m_threadedFilter->getTargetImage().bits()); +} + +} // NameSpace DigikamFilmGrainImagesPlugin + diff --git a/src/imageplugins/filmgrain/imageeffect_filmgrain.h b/src/imageplugins/filmgrain/imageeffect_filmgrain.h new file mode 100644 index 00000000..ba66e0a2 --- /dev/null +++ b/src/imageplugins/filmgrain/imageeffect_filmgrain.h @@ -0,0 +1,74 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-26 + * Description : a digiKam image editor plugin for add film + * grain on an image. + * + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + + +#ifndef IMAGEEFFECT_FILMGRAIN_H +#define IMAGEEFFECT_FILMGRAIN_H + +// Digikam includes. + +#include "ctrlpaneldlg.h" + +class TQSlider; +class TQLCDNumber; + +namespace DigikamFilmGrainImagesPlugin +{ + +class ImageEffect_FilmGrain : public Digikam::CtrlPanelDlg +{ + TQ_OBJECT + + +public: + + ImageEffect_FilmGrain(TQWidget* parent); + ~ImageEffect_FilmGrain(); + +private slots: + + void slotSliderMoved(int); + void readUserSettings(); + +private: + + void writeUserSettings(); + void resetValues(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + TQSlider *m_sensibilitySlider; + + TQLCDNumber *m_sensibilityLCDValue; +}; + +} // NameSpace DigikamFilmGrainImagesPlugin + +#endif /* IMAGEEFFECT_FILMGRAIN_H */ diff --git a/src/imageplugins/filmgrain/imageplugin_filmgrain.cpp b/src/imageplugins/filmgrain/imageplugin_filmgrain.cpp new file mode 100644 index 00000000..efa2c35d --- /dev/null +++ b/src/imageplugins/filmgrain/imageplugin_filmgrain.cpp @@ -0,0 +1,71 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-10-01 + * Description : a digiKam image editor plugin for add film + * grain on an image. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> +#include <tdeapplication.h> + +// Local includes. + +#include "ddebug.h" +#include "filmgraintool.h" +#include "imageplugin_filmgrain.h" +#include "imageplugin_filmgrain.moc" + +using namespace DigikamFilmGrainImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_filmgrain, + KGenericFactory<ImagePlugin_FilmGrain>("digikamimageplugin_filmgrain")); + +ImagePlugin_FilmGrain::ImagePlugin_FilmGrain(TQObject *parent, const char*, const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_FilmGrain") +{ + m_filmgrainAction = new TDEAction(i18n("Add Film Grain..."), "filmgrain", 0, + this, TQ_SLOT(slotFilmGrain()), + actionCollection(), "imageplugin_filmgrain"); + + setXMLFile( "digikamimageplugin_filmgrain_ui.rc" ); + + DDebug() << "ImagePlugin_FilmGrain plugin loaded" << endl; +} + +ImagePlugin_FilmGrain::~ImagePlugin_FilmGrain() +{ +} + +void ImagePlugin_FilmGrain::setEnabledActions(bool enable) +{ + m_filmgrainAction->setEnabled(enable); +} + +void ImagePlugin_FilmGrain::slotFilmGrain() +{ + FilmGrainTool *tool = new FilmGrainTool(this); + loadTool(tool); +} diff --git a/src/imageplugins/filmgrain/imageplugin_filmgrain.h b/src/imageplugins/filmgrain/imageplugin_filmgrain.h new file mode 100644 index 00000000..495da122 --- /dev/null +++ b/src/imageplugins/filmgrain/imageplugin_filmgrain.h @@ -0,0 +1,57 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-10-01 + * Description : a digiKam image editor plugin for add film + * grain on an image. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_FILMGRAIN_H +#define IMAGEPLUGIN_FILMGRAIN_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_FilmGrain : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_FilmGrain(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_FilmGrain(); + + void setEnabledActions(bool enable); + +private slots: + + void slotFilmGrain(); + +private: + + TDEAction *m_filmgrainAction; +}; + +#endif /* IMAGEPLUGIN_FILMGRAIN_H */ diff --git a/src/imageplugins/freerotation/Makefile.am b/src/imageplugins/freerotation/Makefile.am new file mode 100644 index 00000000..e2b67283 --- /dev/null +++ b/src/imageplugins/freerotation/Makefile.am @@ -0,0 +1,34 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_freerotation_la_SOURCES = imageplugin_freerotation.cpp \ + freerotationtool.cpp freerotation.cpp + +digikamimageplugin_freerotation_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_freerotation_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_freerotation.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_freerotation.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_freerotation_ui.rc + diff --git a/src/imageplugins/freerotation/digikamimageplugin_freerotation.desktop b/src/imageplugins/freerotation/digikamimageplugin_freerotation.desktop new file mode 100644 index 00000000..47659a0d --- /dev/null +++ b/src/imageplugins/freerotation/digikamimageplugin_freerotation.desktop @@ -0,0 +1,51 @@ +[Desktop Entry] +Name=ImagePlugin_FreeRotation +Name[bg]=Приставка за снимки - Свободно завъртане +Name[da]=Billedplugin_Fri rotation +Name[el]=ΠρόσθετοΕικόνας_ΕλεύθερηΠεριστροφή +Name[fi]=Kierto +Name[hr]=Slobodno obrtanje +Name[it]=PluginImmagini_RotazioneLibera +Name[nl]=Afbeeldingsplugin_VrijeRotatie +Name[sr]=Слободно окретање +Name[sr@Latn]=Slobodno okretanje +Name[sv]=Insticksprogram för bildrotation +Name[tr]=ResimEklentisi_SerbestDöndürme +Name[xx]=xxImagePlugin_FreeRotationxx + +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=Free rotation plugin for digiKam +Comment[bg]=Приставка на digiKam за свободно завъртане на снимки +Comment[ca]=Connector pel digiKam de gir lliure +Comment[da]=Plugin til fri rotation af billeder til Digikam +Comment[de]=digiKam-Modul zur freien Drehung von Bildern +Comment[el]=Πρόσθετο ελεύθερης περιστροφής για το digiKam +Comment[es]=Plugin para digiKam de rotación +Comment[et]=DigiKami pildi vaba pööramise plugin +Comment[fa]=وصلۀ چرخش آزاد برای digiKam +Comment[fi]=Kiertää kuvaa vapaasti määritettävien asteiden verran +Comment[gl]=Un plugin de digiKam para a rotazón libre da imaxe +Comment[hr]=digiKam dodatak za slobodno obrtanje +Comment[is]=Íforrit fyrir digiKam sem leyfir frjálsan snúning mynda +Comment[it]=Plugin per la rotazione libera per digiKam +Comment[ja]=digiKam 画像自由回転プラグイン +Comment[nds]=digiKam-Moduul för't fre'e Dreihen +Comment[nl]=Digikam-plugin voor vrije rotatie +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਮੁਕਤ ਘੁੰਮਾਉਣ ਵਾਲੀ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam umożliwiająca swobodny obrót obrazu +Comment[pt]=Um 'plugin' do digiKam para a rotação livre da imagem +Comment[pt_BR]=Plugin de Rotação Livre +Comment[ru]=Модуль свободного вращения для digiKam +Comment[sk]=digiKam plugin voľného otáčania +Comment[sr]=digiKam-ов прикључак за слободно окретање +Comment[sr@Latn]=digiKam-ov priključak za slobodno okretanje +Comment[sv]=Digikam insticksprogram för bildrotation +Comment[tr]=digiKam için serbest döndürme eklentisi +Comment[uk]=Втулок вільного обертання для digiKam +Comment[vi]=Phần bổ sung xoay tự do cho digiKam +Comment[xx]=xxFree rotation plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_freerotation +author=Gilles Caulier, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/freerotation/digikamimageplugin_freerotation_ui.rc b/src/imageplugins/freerotation/digikamimageplugin_freerotation_ui.rc new file mode 100644 index 00000000..fbbf9605 --- /dev/null +++ b/src/imageplugins/freerotation/digikamimageplugin_freerotation_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="4" name="digikamimageplugin_freerotation" > + + <MenuBar> + + <Menu name="Transform" ><text>Tra&nsform</text> + <Action name="imageplugin_freerotation" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action shortcut="" name="imageplugin_freerotation" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/freerotation/freerotation.cpp b/src/imageplugins/freerotation/freerotation.cpp new file mode 100644 index 00000000..3f8803d5 --- /dev/null +++ b/src/imageplugins/freerotation/freerotation.cpp @@ -0,0 +1,263 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-07-18 + * Description : Free rotation threaded image filter. + * + * Copyright (C) 2004-2007 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. + * + * ============================================================ */ + +// Degrees to radian convertion coeff (PI/180). To optimize computation. +#define DEG2RAD 0.017453292519943 + +// C++ includes. + +#include <cmath> +#include <cstdlib> + +// Local includes. + +#include "dimg.h" +#include "dimgimagefilters.h" +#include "freerotation.h" + +namespace DigikamFreeRotationImagesPlugin +{ + +FreeRotation::FreeRotation(Digikam::DImg *orgImage, TQObject *parent, double angle, bool antialiasing, + int autoCrop, TQColor backgroundColor, int orgW, int orgH) + : Digikam::DImgThreadedFilter(orgImage, parent, "FreeRotation") +{ + m_angle = angle; + m_orgW = orgW; + m_orgH = orgH; + m_antiAlias = antialiasing; + m_autoCrop = autoCrop; + m_backgroundColor = backgroundColor; + + initFilter(); +} + +void FreeRotation::filterImage(void) +{ + int progress; + int w, h, nw, nh, j, i = 0; + int nNewHeight, nNewWidth; + int nhdx, nhdy, nhsx, nhsy; + double lfSin, lfCos, lfx, lfy; + + int nWidth = m_orgImage.width(); + int nHeight = m_orgImage.height(); + + uchar *pBits = m_orgImage.bits(); + unsigned short *pBits16 = (unsigned short*)m_orgImage.bits(); + + // first of all, we need to calcule the sin and cos of the given angle + + lfSin = sin (m_angle * -DEG2RAD); + lfCos = cos (m_angle * -DEG2RAD); + + // now, we have to calc the new size for the destination image + + if ((lfSin * lfCos) < 0) + { + nNewWidth = ROUND (fabs (nWidth * lfCos - nHeight * lfSin)); + nNewHeight = ROUND (fabs (nWidth * lfSin - nHeight * lfCos)); + } + else + { + nNewWidth = ROUND (fabs (nWidth * lfCos + nHeight * lfSin)); + nNewHeight = ROUND (fabs (nWidth * lfSin + nHeight * lfCos)); + } + + // getting the destination's center position + + nhdx = nNewWidth / 2; + nhdy = nNewHeight / 2; + + // getting the source's center position + + nhsx = nWidth / 2; + nhsy = nHeight / 2; + + // now, we have to alloc a new image + + bool sixteenBit = m_orgImage.sixteenBit(); + + m_destImage = Digikam::DImg(nNewWidth, nNewHeight, sixteenBit, m_orgImage.hasAlpha()); + m_destImage.fill( Digikam::DColor(m_backgroundColor.rgb(), sixteenBit) ); + + uchar *pResBits = m_destImage.bits(); + unsigned short *pResBits16 = (unsigned short *)m_destImage.bits(); + + Digikam::DImgImageFilters filters; + + // main loop + + for (h = 0; !m_cancel && (h < nNewHeight); h++) + { + nh = h - nhdy; + + for (w = 0; !m_cancel && (w < nNewWidth); w++) + { + nw = w - nhdx; + + i = setPosition (nNewWidth, w, h); + + lfx = (double)nw * lfCos - (double)nh * lfSin + nhsx; + lfy = (double)nw * lfSin + (double)nh * lfCos + nhsy; + + if (isInside (nWidth, nHeight, (int)lfx, (int)lfy)) + { + if (m_antiAlias) + { + if (!sixteenBit) + filters.pixelAntiAliasing(pBits, nWidth, nHeight, lfx, lfy, + &pResBits[i+3], &pResBits[i+2], + &pResBits[i+1], &pResBits[i]); + else + filters.pixelAntiAliasing16(pBits16, nWidth, nHeight, lfx, lfy, + &pResBits16[i+3], &pResBits16[i+2], + &pResBits16[i+1], &pResBits16[i]); + } + else + { + j = setPosition (nWidth, (int)lfx, (int)lfy); + + for (int p = 0 ; p < 4 ; p++) + { + if (!sixteenBit) + pResBits[i] = pBits[j]; + else + pResBits16[i] = pBits16[j]; + + i++; + j++; + } + } + } + } + + // Update the progress bar in dialog. + progress = (int)(((double)h * 100.0) / nNewHeight); + if (progress%5 == 0) + postProgress( progress ); + } + + // Compute the rotated destination image size using original image dimensions. + int W, H; + double absAngle = fabs(m_angle); + + if (absAngle < 90.0) + { + W = (int)(m_orgW * cos(absAngle * DEG2RAD) + m_orgH * sin(absAngle * DEG2RAD)); + H = (int)(m_orgH * cos(absAngle * DEG2RAD) + m_orgW * sin(absAngle * DEG2RAD)); + } + else + { + H = (int)(m_orgW * cos((absAngle-90.0) * DEG2RAD) + m_orgH * sin((absAngle-90.0) * DEG2RAD)); + W = (int)(m_orgH * cos((absAngle-90.0) * DEG2RAD) + m_orgW * sin((absAngle-90.0) * DEG2RAD)); + } + + // Auto-cropping destination image without black holes around. + TQRect autoCrop; + + switch(m_autoCrop) + { + case WidestArea: + { + // 'Widest Area' method (by Renchi Raju). + + autoCrop.setX( (int)(nHeight * sin(absAngle * DEG2RAD)) ); + autoCrop.setY( (int)(nWidth * sin(absAngle * DEG2RAD)) ); + autoCrop.setWidth( (int)(nNewWidth - 2*nHeight * sin(absAngle * DEG2RAD)) ); + autoCrop.setHeight( (int)(nNewHeight - 2*nWidth * sin(absAngle * DEG2RAD)) ); + + if (!autoCrop.isValid()) + { + m_destImage = Digikam::DImg(m_orgImage.width(), m_orgImage.height(), + m_orgImage.sixteenBit(), m_orgImage.hasAlpha()); + m_destImage.fill( Digikam::DColor(m_backgroundColor.rgb(), sixteenBit) ); + m_newSize = TQSize(); + } + else + { + m_destImage = m_destImage.copy(autoCrop); + m_newSize.setWidth( (int)(W - 2*m_orgH * sin(absAngle * DEG2RAD)) ); + m_newSize.setHeight( (int)(H - 2*m_orgW * sin(absAngle * DEG2RAD)) ); + } + break; + } + + case LargestArea: + { + // 'Largest Area' method (by Gerhard Kulzer). + + float gamma = atan((float)nHeight / (float)nWidth); + + if (absAngle < 90.0) + { + autoCrop.setWidth( (int)((float)nHeight / cos(absAngle*DEG2RAD) / + ( tan(gamma) + tan(absAngle*DEG2RAD) )) ); + autoCrop.setHeight( (int)((float)autoCrop.width() * tan(gamma)) ); + } + else + { + autoCrop.setHeight( (int)((float)nHeight / cos((absAngle-90.0)*DEG2RAD) / + ( tan(gamma) + tan((absAngle-90.0)*DEG2RAD) )) ); + autoCrop.setWidth( (int)((float)autoCrop.height() * tan(gamma)) ); + } + + autoCrop.moveCenter( TQPoint(nNewWidth/2, nNewHeight/2)); + + if (!autoCrop.isValid()) + { + m_destImage = Digikam::DImg(m_orgImage.width(), m_orgImage.height(), + m_orgImage.sixteenBit(), m_orgImage.hasAlpha()); + m_destImage.fill( Digikam::DColor(m_backgroundColor.rgb(), sixteenBit) ); + m_newSize = TQSize(); + } + else + { + m_destImage = m_destImage.copy(autoCrop); + gamma = atan((float)m_orgH / (float)m_orgW); + + if (absAngle < 90.0) + { + m_newSize.setWidth( (int)((float)m_orgH / cos(absAngle*DEG2RAD) / + ( tan(gamma) + tan(absAngle*DEG2RAD) )) ); + m_newSize.setHeight( (int)((float)m_newSize.width() * tan(gamma)) ); + } + else + { + m_newSize.setHeight( (int)((float)m_orgH / cos((absAngle-90.0)*DEG2RAD) / + ( tan(gamma) + tan((absAngle-90.0)*DEG2RAD) )) ); + m_newSize.setWidth( (int)((float)m_newSize.height() * tan(gamma)) ); + } + } + break; + } + default: // No auto croping. + { + m_newSize.setWidth( W ); + m_newSize.setHeight( H ); + break; + } + } +} + +} // NameSpace DigikamFreeRotationImagesPlugin diff --git a/src/imageplugins/freerotation/freerotation.h b/src/imageplugins/freerotation/freerotation.h new file mode 100644 index 00000000..7dc4cc8c --- /dev/null +++ b/src/imageplugins/freerotation/freerotation.h @@ -0,0 +1,94 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-07-18 + * Description : Free rotation threaded image filter. + * + * Copyright (C) 2004-2007 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. + * + * ============================================================ */ + +#ifndef FREE_ROTATION_H +#define FREE_ROTATION_H + +// TQt includes. + +#include <tqsize.h> +#include <tqcolor.h> + +// Digikam includes. + +#include "dimgthreadedfilter.h" + +namespace DigikamFreeRotationImagesPlugin +{ + +class FreeRotation : public Digikam::DImgThreadedFilter +{ + +public: + + FreeRotation(Digikam::DImg *orgImage, TQObject *parent=0, double angle=0.0, + bool antialiasing=true, int autoCrop=NoAutoCrop, TQColor backgroundColor=TQt::black, + int orgW=0, int orgH=0); + + ~FreeRotation(){}; + + TQSize getNewSize(void){ return m_newSize; }; + +public: + + enum AutoCropTypes + { + NoAutoCrop=0, + WidestArea, + LargestArea + }; + +private: + + virtual void filterImage(void); + + inline int setPosition (int Width, int X, int Y) + { + return (Y *Width*4 + 4*X); + }; + + inline bool isInside (int Width, int Height, int X, int Y) + { + bool bIsWOk = ((X < 0) ? false : (X >= Width ) ? false : true); + bool bIsHOk = ((Y < 0) ? false : (Y >= Height) ? false : true); + return (bIsWOk && bIsHOk); + }; + +private: + + bool m_antiAlias; + + int m_autoCrop; + int m_orgW; + int m_orgH; + + double m_angle; + + TQSize m_newSize; + + TQColor m_backgroundColor; +}; + +} // NameSpace DigikamFreeRotationImagesPlugin + +#endif /* FREE_ROTATION_H */ diff --git a/src/imageplugins/freerotation/freerotationtool.cpp b/src/imageplugins/freerotation/freerotationtool.cpp new file mode 100644 index 00000000..b25f2196 --- /dev/null +++ b/src/imageplugins/freerotation/freerotationtool.cpp @@ -0,0 +1,318 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-11-28 + * Description : a digiKam image editor plugin to process image + * free rotation. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqcheckbox.h> +#include <tqimage.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <kseparator.h> +#include <kstandarddirs.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> +#include <libkdcraw/rcombobox.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "editortoolsettings.h" +#include "freerotation.h" +#include "freerotationtool.h" +#include "freerotationtool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamFreeRotationImagesPlugin +{ + +FreeRotationTool::FreeRotationTool(TQObject* parent) + : EditorToolThreaded(parent) +{ + setName("freerotation"); + setToolName(i18n("Free Rotation")); + setToolIcon(SmallIcon("freerotation")); + + m_previewWidget = new ImageWidget("freerotation Tool", 0, + i18n("<p>This is the free rotation operation preview. " + "If you move the mouse cursor on this preview, " + "a vertical and horizontal dashed line will be drawn " + "to guide you in adjusting the free rotation correction. " + "Release the left mouse button to freeze the dashed " + "line's position."), + false, ImageGuideWidget::HVGuideMode); + + setToolView(m_previewWidget); + + // ------------------------------------------------------------- + + TQString temp; + Digikam::ImageIface iface(0, 0); + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel, + EditorToolSettings::ColorGuide); + TQGridLayout* grid = new TQGridLayout(m_gboxSettings->plainPage(), 9, 2); + + TQLabel *label1 = new TQLabel(i18n("New width:"), m_gboxSettings->plainPage()); + m_newWidthLabel = new TQLabel(temp.setNum( iface.originalWidth()) + i18n(" px"), m_gboxSettings->plainPage()); + m_newWidthLabel->setAlignment( AlignBottom | AlignRight ); + + TQLabel *label2 = new TQLabel(i18n("New height:"), m_gboxSettings->plainPage()); + m_newHeightLabel = new TQLabel(temp.setNum( iface.originalHeight()) + i18n(" px"), m_gboxSettings->plainPage()); + m_newHeightLabel->setAlignment( AlignBottom | AlignRight ); + + KSeparator *line = new KSeparator(Horizontal, m_gboxSettings->plainPage()); + + TQLabel *label3 = new TQLabel(i18n("Main angle:"), m_gboxSettings->plainPage()); + m_angleInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_angleInput->setRange(-180, 180, 1); + m_angleInput->setDefaultValue(0); + TQWhatsThis::add( m_angleInput, i18n("<p>An angle in degrees by which to rotate the image. " + "A positive angle rotates the image clockwise; " + "a negative angle rotates it counter-clockwise.")); + + TQLabel *label4 = new TQLabel(i18n("Fine angle:"), m_gboxSettings->plainPage()); + m_fineAngleInput = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_fineAngleInput->setRange(-5.0, 5.0, 0.01); + m_fineAngleInput->setDefaultValue(0); + TQWhatsThis::add( m_fineAngleInput, i18n("<p>This value in degrees will be added to main angle value " + "to set fine target angle.")); + + m_antialiasInput = new TQCheckBox(i18n("Anti-Aliasing"), m_gboxSettings->plainPage()); + TQWhatsThis::add( m_antialiasInput, i18n("<p>Enable this option to apply the anti-aliasing filter " + "to the rotated image. " + "In order to smooth the target image, it will be blurred a little.")); + + TQLabel *label5 = new TQLabel(i18n("Auto-crop:"), m_gboxSettings->plainPage()); + m_autoCropCB = new RComboBox(m_gboxSettings->plainPage()); + m_autoCropCB->insertItem( i18n("None") ); + m_autoCropCB->insertItem( i18n("Widest Area") ); + m_autoCropCB->insertItem( i18n("Largest Area") ); + m_autoCropCB->setDefaultItem(FreeRotation::NoAutoCrop); + TQWhatsThis::add( m_autoCropCB, i18n("<p>Select the method to process image auto-cropping " + "to remove black frames around a rotated image.")); + + grid->addMultiCellWidget(label1, 0, 0, 0, 0); + grid->addMultiCellWidget(m_newWidthLabel, 0, 0, 1, 2); + grid->addMultiCellWidget(label2, 1, 1, 0, 0); + grid->addMultiCellWidget(m_newHeightLabel, 1, 1, 1, 2); + grid->addMultiCellWidget(line, 2, 2, 0, 2); + grid->addMultiCellWidget(label3, 3, 3, 0, 2); + grid->addMultiCellWidget(m_angleInput, 4, 4, 0, 2); + grid->addMultiCellWidget(label4, 5, 5, 0, 2); + grid->addMultiCellWidget(m_fineAngleInput, 6, 6, 0, 2); + grid->addMultiCellWidget(m_antialiasInput, 7, 7, 0, 2); + grid->addMultiCellWidget(label5, 8, 8, 0, 0); + grid->addMultiCellWidget(m_autoCropCB, 8, 8, 1, 2); + grid->setRowStretch(9, 10); + grid->setMargin(m_gboxSettings->spacingHint()); + grid->setSpacing(m_gboxSettings->spacingHint()); + + setToolSettings(m_gboxSettings); + init(); + + // ------------------------------------------------------------- + + connect(m_angleInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_fineAngleInput, TQ_SIGNAL(valueChanged(double)), + this, TQ_SLOT(slotTimer())); + + connect(m_antialiasInput, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotEffect())); + + connect(m_autoCropCB, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotEffect())); + + connect(m_gboxSettings, TQ_SIGNAL(signalColorGuideChanged()), + this, TQ_SLOT(slotColorGuideChanged())); +} + +FreeRotationTool::~FreeRotationTool() +{ +} + +void FreeRotationTool::slotColorGuideChanged() +{ + m_previewWidget->slotChangeGuideColor(m_gboxSettings->guideColor()); + m_previewWidget->slotChangeGuideSize(m_gboxSettings->guideSize()); +} + +void FreeRotationTool::readSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("freerotation Tool"); + m_angleInput->setValue(config->readNumEntry("Main Angle", m_angleInput->defaultValue())); + m_fineAngleInput->setValue(config->readDoubleNumEntry("Fine Angle", m_fineAngleInput->defaultValue())); + m_autoCropCB->setCurrentItem(config->readNumEntry("Auto Crop Type", m_autoCropCB->defaultItem())); + m_antialiasInput->setChecked(config->readBoolEntry("Anti Aliasing", true)); + m_gboxSettings->setGuideColor(config->readColorEntry("Guide Color", &TQt::red)); + m_gboxSettings->setGuideSize(config->readNumEntry("Guide Width", 1)); + + slotColorGuideChanged(); + slotEffect(); +} + +void FreeRotationTool::writeSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("freerotation Tool"); + config->writeEntry("Main Angle", m_angleInput->value()); + config->writeEntry("Fine Angle", m_fineAngleInput->value()); + config->writeEntry("Auto Crop Type", m_autoCropCB->currentItem()); + config->writeEntry("Anti Aliasing", m_antialiasInput->isChecked()); + config->writeEntry("Guide Color", m_gboxSettings->guideColor()); + config->writeEntry("Guide Width", m_gboxSettings->guideSize()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void FreeRotationTool::slotResetSettings() +{ + m_angleInput->blockSignals(true); + m_antialiasInput->blockSignals(true); + m_autoCropCB->blockSignals(true); + + m_angleInput->slotReset(); + m_fineAngleInput->slotReset(); + m_antialiasInput->setChecked(true); + m_autoCropCB->slotReset(); + + m_angleInput->blockSignals(false); + m_antialiasInput->blockSignals(false); + m_autoCropCB->blockSignals(false); +} + +void FreeRotationTool::prepareEffect() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + m_angleInput->setEnabled(false); + m_fineAngleInput->setEnabled(false); + m_antialiasInput->setEnabled(false); + m_autoCropCB->setEnabled(false); + + double angle = m_angleInput->value() + m_fineAngleInput->value(); + bool antialiasing = m_antialiasInput->isChecked(); + int autocrop = m_autoCropCB->currentItem(); + TQColor background = toolView()->paletteBackgroundColor().rgb(); + ImageIface* iface = m_previewWidget->imageIface(); + int orgW = iface->originalWidth(); + int orgH = iface->originalHeight(); + + uchar *data = iface->getPreviewImage(); + DImg image(iface->previewWidth(), iface->previewHeight(), iface->previewSixteenBit(), + iface->previewHasAlpha(), data); + delete [] data; + + setFilter(dynamic_cast<DImgThreadedFilter*>(new FreeRotation(&image, this, angle, antialiasing, + autocrop, background, orgW, orgH))); +} + +void FreeRotationTool::prepareFinal() +{ + m_angleInput->setEnabled(false); + m_fineAngleInput->setEnabled(false); + m_antialiasInput->setEnabled(false); + m_autoCropCB->setEnabled(false); + + double angle = m_angleInput->value() + m_fineAngleInput->value(); + bool antialiasing = m_antialiasInput->isChecked(); + int autocrop = m_autoCropCB->currentItem(); + TQColor background = TQt::black; + + ImageIface iface(0, 0); + int orgW = iface.originalWidth(); + int orgH = iface.originalHeight(); + + uchar *data = iface.getOriginalImage(); + DImg orgImage(orgW, orgH, iface.originalSixteenBit(), iface.originalHasAlpha(), data); + delete [] data; + + setFilter(dynamic_cast<DImgThreadedFilter *>(new FreeRotation(&orgImage, this, angle, antialiasing, + autocrop, background, orgW, orgH))); +} + +void FreeRotationTool::putPreviewData() +{ + ImageIface* iface = m_previewWidget->imageIface(); + int w = iface->previewWidth(); + int h = iface->previewHeight(); + + DImg imTemp = filter()->getTargetImage().smoothScale(w, h, TQSize::ScaleMin); + DImg imDest( w, h, filter()->getTargetImage().sixteenBit(), + filter()->getTargetImage().hasAlpha() ); + + imDest.fill(DColor(toolView()->paletteBackgroundColor().rgb(), + filter()->getTargetImage().sixteenBit()) ); + imDest.bitBltImage(&imTemp, (w-imTemp.width())/2, (h-imTemp.height())/2); + + iface->putPreviewImage((imDest.smoothScale(iface->previewWidth(), + iface->previewHeight())).bits()); + + m_previewWidget->updatePreview(); + TQSize newSize = dynamic_cast<FreeRotation*>(filter())->getNewSize(); + TQString temp; + m_newWidthLabel->setText(temp.setNum( newSize.width()) + i18n(" px") ); + m_newHeightLabel->setText(temp.setNum( newSize.height()) + i18n(" px") ); +} + +void FreeRotationTool::putFinalData() +{ + ImageIface iface(0, 0); + DImg targetImage = filter()->getTargetImage(); + iface.putOriginalImage(i18n("Free Rotation"), + targetImage.bits(), + targetImage.width(), targetImage.height()); +} + +void FreeRotationTool::renderingFinished() +{ + m_angleInput->setEnabled(true); + m_fineAngleInput->setEnabled(true); + m_antialiasInput->setEnabled(true); + m_autoCropCB->setEnabled(true); + kapp->restoreOverrideCursor(); +} + +} // NameSpace DigikamFreeRotationImagesPlugin diff --git a/src/imageplugins/freerotation/freerotationtool.h b/src/imageplugins/freerotation/freerotationtool.h new file mode 100644 index 00000000..fd17f4ff --- /dev/null +++ b/src/imageplugins/freerotation/freerotationtool.h @@ -0,0 +1,97 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-11-28 + * Description : a digiKam image editor plugin to process image + * free rotation. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef FREEROTATIONTOOL_H +#define FREEROTATIONTOOL_H + +// Local includes. + +#include "editortool.h" + +class TQFrame; +class TQLabel; +class TQCheckBox; + +namespace KDcrawIface +{ +class RIntNumInput; +class RDoubleNumInput; +class RComboBox; +} + +namespace Digikam +{ +class EditorToolSettings; +class ImageWidget; +} + +namespace DigikamFreeRotationImagesPlugin +{ + +class FreeRotationTool : public Digikam::EditorToolThreaded +{ + TQ_OBJECT + + +public: + + FreeRotationTool(TQObject *parent); + ~FreeRotationTool(); + +private slots: + + void slotResetSettings(); + void slotColorGuideChanged(); + +private: + + void readSettings(); + void writeSettings(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + TQLabel *m_newWidthLabel; + TQLabel *m_newHeightLabel; + + TQCheckBox *m_antialiasInput; + + KDcrawIface::RComboBox *m_autoCropCB; + + KDcrawIface::RIntNumInput *m_angleInput; + + KDcrawIface::RDoubleNumInput *m_fineAngleInput; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamFreeRotationImagesPlugin + +#endif /* FREEROTATIONTOOL_H */ diff --git a/src/imageplugins/freerotation/imageeffect_freerotation.cpp b/src/imageplugins/freerotation/imageeffect_freerotation.cpp new file mode 100644 index 00000000..bce50f07 --- /dev/null +++ b/src/imageplugins/freerotation/imageeffect_freerotation.cpp @@ -0,0 +1,308 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-11-28 + * Description : a digiKam image editor plugin to process image + * free rotation. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqlabel.h> +#include <tqcheckbox.h> +#include <tqwhatsthis.h> +#include <tqlayout.h> +#include <tqimage.h> +#include <tqcombobox.h> + +// KDE includes. + +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <kstandarddirs.h> +#include <knuminput.h> +#include <kcursor.h> +#include <kseparator.h> +#include <tdeconfig.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "freerotation.h" +#include "imageeffect_freerotation.h" +#include "imageeffect_freerotation.moc" + +namespace DigikamFreeRotationImagesPlugin +{ + +ImageEffect_FreeRotation::ImageEffect_FreeRotation(TQWidget* parent) + : Digikam::ImageGuideDlg(parent, i18n("Free Rotation"), "freerotation", + false, true, true, Digikam::ImageGuideWidget::HVGuideMode) +{ + // No need Abort button action. + showButton(User1, false); + + TQString whatsThis; + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Free Rotation"), + digikam_version, + I18N_NOOP("A digiKam image plugin to process free image " + "rotation."), + TDEAboutData::License_GPL, + "(c) 2004-2008, Gilles Caulier", + 0, + "http://www.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + about->addAuthor("Pieter Z. Voloshyn", I18N_NOOP("Free Rotation algorithm"), + "pieter dot voloshyn at gmail dot com"); + + setAboutData(about); + + TQWhatsThis::add( m_imagePreviewWidget, i18n("<p>This is the free image operation preview. " + "If you move the mouse cursor on this preview, " + "a vertical and horizontal dashed line will be drawn " + "to guide you in adjusting the free rotation correction. " + "Release the left mouse button to freeze the dashed " + "line's position.")); + + // ------------------------------------------------------------- + + TQString temp; + Digikam::ImageIface iface(0, 0); + + TQWidget *gboxSettings = new TQWidget(plainPage()); + TQGridLayout* gridSettings = new TQGridLayout( gboxSettings, 9, 2, spacingHint()); + + TQLabel *label1 = new TQLabel(i18n("New width:"), gboxSettings); + m_newWidthLabel = new TQLabel(temp.setNum( iface.originalWidth()) + i18n(" px"), gboxSettings); + m_newWidthLabel->setAlignment( AlignBottom | AlignRight ); + + TQLabel *label2 = new TQLabel(i18n("New height:"), gboxSettings); + m_newHeightLabel = new TQLabel(temp.setNum( iface.originalHeight()) + i18n(" px"), gboxSettings); + m_newHeightLabel->setAlignment( AlignBottom | AlignRight ); + + gridSettings->addMultiCellWidget(label1, 0, 0, 0, 0); + gridSettings->addMultiCellWidget(m_newWidthLabel, 0, 0, 1, 2); + gridSettings->addMultiCellWidget(label2, 1, 1, 0, 0); + gridSettings->addMultiCellWidget(m_newHeightLabel, 1, 1, 1, 2); + + KSeparator *line = new KSeparator(Horizontal, gboxSettings); + gridSettings->addMultiCellWidget(line, 2, 2, 0, 2); + + TQLabel *label3 = new TQLabel(i18n("Main angle:"), gboxSettings); + m_angleInput = new KIntNumInput(gboxSettings); + m_angleInput->setRange(-180, 180, 1, true); + m_angleInput->setValue(0); + TQWhatsThis::add( m_angleInput, i18n("<p>An angle in degrees by which to rotate the image. " + "A positive angle rotates the image clockwise; " + "a negative angle rotates it counter-clockwise.")); + + gridSettings->addMultiCellWidget(label3, 3, 3, 0, 2); + gridSettings->addMultiCellWidget(m_angleInput, 4, 4, 0, 2); + + TQLabel *label4 = new TQLabel(i18n("Fine angle:"), gboxSettings); + m_fineAngleInput = new KDoubleNumInput(gboxSettings); + m_fineAngleInput->setRange(-5.0, 5.0, 0.01, true); + m_fineAngleInput->setValue(0); + TQWhatsThis::add( m_fineAngleInput, i18n("<p>This value in degrees will be added to main angle value " + "to set fine target angle.")); + + gridSettings->addMultiCellWidget(label4, 5, 5, 0, 2); + gridSettings->addMultiCellWidget(m_fineAngleInput, 6, 6, 0, 2); + + m_antialiasInput = new TQCheckBox(i18n("Anti-Aliasing"), gboxSettings); + TQWhatsThis::add( m_antialiasInput, i18n("<p>Enable this option to apply the anti-aliasing filter " + "to the rotated image. " + "In order to smooth the target image, it will be blurred a little.")); + gridSettings->addMultiCellWidget(m_antialiasInput, 7, 7, 0, 2); + + TQLabel *label5 = new TQLabel(i18n("Auto-crop:"), gboxSettings); + m_autoCropCB = new TQComboBox(false, gboxSettings); + m_autoCropCB->insertItem( i18n("None") ); + m_autoCropCB->insertItem( i18n("Widest Area") ); + m_autoCropCB->insertItem( i18n("Largest Area") ); + TQWhatsThis::add( m_autoCropCB, i18n("<p>Select the method to process image auto-cropping " + "to remove black frames around a rotated image.")); + gridSettings->addMultiCellWidget(label5, 8, 8, 0, 0); + gridSettings->addMultiCellWidget(m_autoCropCB, 8, 8, 1, 2); + + setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + connect(m_angleInput, TQ_SIGNAL(valueChanged (int)), + this, TQ_SLOT(slotTimer())); + + connect(m_fineAngleInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_antialiasInput, TQ_SIGNAL(toggled (bool)), + this, TQ_SLOT(slotEffect())); + + connect(m_autoCropCB, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotEffect())); +} + +ImageEffect_FreeRotation::~ImageEffect_FreeRotation() +{ +} + +void ImageEffect_FreeRotation::readUserSettings(void) +{ + TDEConfig *config = kapp->config(); + config->setGroup("freerotation Tool Dialog"); + m_angleInput->setValue(config->readNumEntry("Main Angle", 0)); + m_fineAngleInput->setValue(config->readDoubleNumEntry("Fine Angle", 0.0)); + m_autoCropCB->setCurrentItem(config->readNumEntry("Auto Crop Type", FreeRotation::NoAutoCrop)); + m_antialiasInput->setChecked(config->readBoolEntry("Anti Aliasing", true)); + slotEffect(); +} + +void ImageEffect_FreeRotation::writeUserSettings(void) +{ + TDEConfig *config = kapp->config(); + config->setGroup("freerotation Tool Dialog"); + config->writeEntry("Main Angle", m_angleInput->value()); + config->writeEntry("Fine Angle", m_fineAngleInput->value()); + config->writeEntry( "Auto Crop Type", m_autoCropCB->currentItem() ); + config->writeEntry( "Anti Aliasing", m_antialiasInput->isChecked() ); + config->sync(); +} + +void ImageEffect_FreeRotation::resetValues() +{ + m_angleInput->blockSignals(true); + m_antialiasInput->blockSignals(true); + m_autoCropCB->blockSignals(true); + m_angleInput->setValue(0); + m_fineAngleInput->setValue(0.0); + m_antialiasInput->setChecked(true); + m_autoCropCB->setCurrentItem(FreeRotation::NoAutoCrop); + m_angleInput->blockSignals(false); + m_antialiasInput->blockSignals(false); + m_autoCropCB->blockSignals(false); +} + +void ImageEffect_FreeRotation::prepareEffect() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + m_angleInput->setEnabled(false); + m_fineAngleInput->setEnabled(false); + m_antialiasInput->setEnabled(false); + m_autoCropCB->setEnabled(false); + + double angle = m_angleInput->value() + m_fineAngleInput->value(); + bool antialiasing = m_antialiasInput->isChecked(); + int autocrop = m_autoCropCB->currentItem(); + TQColor background = paletteBackgroundColor().rgb(); + + Digikam::ImageIface* iface = m_imagePreviewWidget->imageIface(); + int orgW = iface->originalWidth(); + int orgH = iface->originalHeight(); + + uchar *data = iface->getPreviewImage(); + Digikam::DImg image(iface->previewWidth(), iface->previewHeight(), iface->previewSixteenBit(), + iface->previewHasAlpha(), data); + delete [] data; + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new FreeRotation(&image, this, angle, antialiasing, autocrop, + background, orgW, orgH)); +} + +void ImageEffect_FreeRotation::prepareFinal() +{ + m_angleInput->setEnabled(false); + m_fineAngleInput->setEnabled(false); + m_antialiasInput->setEnabled(false); + m_autoCropCB->setEnabled(false); + + double angle = m_angleInput->value() + m_fineAngleInput->value(); + bool antialiasing = m_antialiasInput->isChecked(); + int autocrop = m_autoCropCB->currentItem(); + TQColor background = TQt::black; + + Digikam::ImageIface iface(0, 0); + int orgW = iface.originalWidth(); + int orgH = iface.originalHeight(); + + uchar *data = iface.getOriginalImage(); + Digikam::DImg orgImage(orgW, orgH, iface.originalSixteenBit(), + iface.originalHasAlpha(), data); + delete [] data; + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new FreeRotation(&orgImage, this, angle, antialiasing, autocrop, + background, orgW, orgH)); +} + +void ImageEffect_FreeRotation::putPreviewData(void) +{ + Digikam::ImageIface* iface = m_imagePreviewWidget->imageIface(); + int w = iface->previewWidth(); + int h = iface->previewHeight(); + + Digikam::DImg imTemp = m_threadedFilter->getTargetImage().smoothScale(w, h, TQSize::ScaleMin); + Digikam::DImg imDest( w, h, m_threadedFilter->getTargetImage().sixteenBit(), + m_threadedFilter->getTargetImage().hasAlpha() ); + + imDest.fill( Digikam::DColor(paletteBackgroundColor().rgb(), + m_threadedFilter->getTargetImage().sixteenBit()) ); + imDest.bitBltImage(&imTemp, (w-imTemp.width())/2, (h-imTemp.height())/2); + + iface->putPreviewImage((imDest.smoothScale(iface->previewWidth(), + iface->previewHeight())).bits()); + + m_imagePreviewWidget->updatePreview(); + TQSize newSize = dynamic_cast<FreeRotation *>(m_threadedFilter)->getNewSize(); + TQString temp; + m_newWidthLabel->setText(temp.setNum( newSize.width()) + i18n(" px") ); + m_newHeightLabel->setText(temp.setNum( newSize.height()) + i18n(" px") ); +} + +void ImageEffect_FreeRotation::putFinalData(void) +{ + Digikam::ImageIface iface(0, 0); + Digikam::DImg targetImage = m_threadedFilter->getTargetImage(); + iface.putOriginalImage(i18n("Free Rotation"), + targetImage.bits(), + targetImage.width(), targetImage.height()); +} + +void ImageEffect_FreeRotation::renderingFinished() +{ + m_angleInput->setEnabled(true); + m_fineAngleInput->setEnabled(true); + m_antialiasInput->setEnabled(true); + m_autoCropCB->setEnabled(true); + kapp->restoreOverrideCursor(); +} + +} // NameSpace DigikamFreeRotationImagesPlugin + diff --git a/src/imageplugins/freerotation/imageeffect_freerotation.h b/src/imageplugins/freerotation/imageeffect_freerotation.h new file mode 100644 index 00000000..a90be09d --- /dev/null +++ b/src/imageplugins/freerotation/imageeffect_freerotation.h @@ -0,0 +1,83 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-11-28 + * Description : a digiKam image editor plugin to process image + * free rotation. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_FREEROTATION_H +#define IMAGEEFFECT_FREEROTATION_H + +// Local includes. + +#include "imageguidedlg.h" + +class TQFrame; +class TQLabel; +class TQCheckBox; +class TQComboBox; + +class KIntNumInput; +class KDoubleNumInput; + +namespace DigikamFreeRotationImagesPlugin +{ + +class ImageEffect_FreeRotation : public Digikam::ImageGuideDlg +{ + TQ_OBJECT + + +public: + + ImageEffect_FreeRotation(TQWidget *parent); + ~ImageEffect_FreeRotation(); + +private slots: + + void readUserSettings(void); + +protected: + + void writeUserSettings(); + void resetValues(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + TQLabel *m_newWidthLabel; + TQLabel *m_newHeightLabel; + + TQCheckBox *m_antialiasInput; + + TQComboBox *m_autoCropCB; + + KIntNumInput *m_angleInput; + + KDoubleNumInput *m_fineAngleInput; +}; + +} // NameSpace DigikamFreeRotationImagesPlugin + +#endif /* IMAGEEFFECT_FREEROTATION_H */ diff --git a/src/imageplugins/freerotation/imageplugin_freerotation.cpp b/src/imageplugins/freerotation/imageplugin_freerotation.cpp new file mode 100644 index 00000000..0c04a2ca --- /dev/null +++ b/src/imageplugins/freerotation/imageplugin_freerotation.cpp @@ -0,0 +1,70 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-11-28 + * Description : a digiKam image editor plugin to process image + * free rotation. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> + +// Local includes. + +#include "ddebug.h" +#include "freerotationtool.h" +#include "imageplugin_freerotation.h" +#include "imageplugin_freerotation.moc" + +using namespace DigikamFreeRotationImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_freerotation, + KGenericFactory<ImagePlugin_FreeRotation>("digikamimageplugin_freerotation")); + +ImagePlugin_FreeRotation::ImagePlugin_FreeRotation(TQObject *parent, const char*, const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_FreeRotation") +{ + m_freerotationAction = new TDEAction(i18n("Free Rotation..."), "freerotation", 0, + this, TQ_SLOT(slotFreeRotation()), + actionCollection(), "imageplugin_freerotation"); + + setXMLFile("digikamimageplugin_freerotation_ui.rc"); + + DDebug() << "ImagePlugin_FreeRotation plugin loaded" << endl; +} + +ImagePlugin_FreeRotation::~ImagePlugin_FreeRotation() +{ +} + +void ImagePlugin_FreeRotation::setEnabledActions(bool enable) +{ + m_freerotationAction->setEnabled(enable); +} + +void ImagePlugin_FreeRotation::slotFreeRotation() +{ + FreeRotationTool *tool = new FreeRotationTool(this); + loadTool(tool); +} diff --git a/src/imageplugins/freerotation/imageplugin_freerotation.h b/src/imageplugins/freerotation/imageplugin_freerotation.h new file mode 100644 index 00000000..2a0c2627 --- /dev/null +++ b/src/imageplugins/freerotation/imageplugin_freerotation.h @@ -0,0 +1,57 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-11-28 + * Description : a digiKam image editor plugin to process image + * free rotation. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_FREEROTATION_H +#define IMAGEPLUGIN_FREEROTATION_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_FreeRotation : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_FreeRotation(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_FreeRotation(); + + void setEnabledActions(bool enable); + +private slots: + + void slotFreeRotation(); + +private: + + TDEAction *m_freerotationAction; +}; + +#endif /* IMAGEPLUGIN_FREEROTATION_H */ diff --git a/src/imageplugins/hotpixels/Makefile.am b/src/imageplugins/hotpixels/Makefile.am new file mode 100644 index 00000000..711fe84e --- /dev/null +++ b/src/imageplugins/hotpixels/Makefile.am @@ -0,0 +1,36 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/threadimageio \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_hotpixels_la_SOURCES = blackframeparser.cpp weights.cpp \ + hotpixelfixer.cpp imageplugin_hotpixels.cpp \ + blackframelistview.cpp hotpixelstool.cpp + +digikamimageplugin_hotpixels_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_hotpixels_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_hotpixels.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_hotpixels.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_hotpixels_ui.rc + diff --git a/src/imageplugins/hotpixels/TODO b/src/imageplugins/hotpixels/TODO new file mode 100644 index 00000000..880e1a36 --- /dev/null +++ b/src/imageplugins/hotpixels/TODO @@ -0,0 +1,4 @@ +- Store black frames. Include the fullsize image to be able to reedit it if necessary. +- Add a hand hot-pixel editor for the hot pixels on the black frame +- Use the same hot-pixel editor from the image view, to edit a new black frame with the added data + diff --git a/src/imageplugins/hotpixels/blackframelistview.cpp b/src/imageplugins/hotpixels/blackframelistview.cpp new file mode 100644 index 00000000..1202b094 --- /dev/null +++ b/src/imageplugins/hotpixels/blackframelistview.cpp @@ -0,0 +1,176 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-07-05 + * Description : a ListView to display black frames + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * + * 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. + * + * ============================================================ */ + +#define THUMB_WIDTH 150 + +// TQt includes. + +#include <tqpainter.h> +#include <tqtooltip.h> + +// Local includes. + +#include "blackframelistview.h" +#include "blackframelistview.moc" + +namespace DigikamHotPixelsImagesPlugin +{ + +BlackFrameListView::BlackFrameListView(TQWidget* parent) + : TQListView(parent) +{ + addColumn(i18n("Preview")); + addColumn(i18n("Size")); + addColumn(i18n("This is a column which will contain the amount of HotPixels " + "found in the black frame file", "HP")); + setAllColumnsShowFocus(true); + setResizeMode(TQListView::LastColumn); + setSelectionMode(TQListView::Single); +} + +// -------------------------------------------------------------------------- + +BlackFrameListViewItem::BlackFrameListViewItem(BlackFrameListView* parent, const KURL &url) + : TQObject(parent), TQListViewItem(parent) +{ + m_parent = parent; + m_blackFrameURL = url; + m_parser = new BlackFrameParser(parent); + m_parser->parseBlackFrame(url); + + connect(m_parser, TQ_SIGNAL(parsed(TQValueList<HotPixel>)), + this, TQ_SLOT(slotParsed(TQValueList<HotPixel>))); + + connect(this, TQ_SIGNAL(parsed(TQValueList<HotPixel>, const KURL&)), + parent, TQ_SLOT(slotParsed(TQValueList<HotPixel>, const KURL&))); + + connect(m_parser, TQ_SIGNAL(signalLoadingProgress(float)), + this, TQ_SIGNAL(signalLoadingProgress(float))); + + connect(m_parser, TQ_SIGNAL(signalLoadingComplete()), + this, TQ_SIGNAL(signalLoadingComplete())); +} + +void BlackFrameListViewItem::activate() +{ + TQToolTip::add( m_parent, m_blackFrameDesc); + emit parsed(m_hotPixels, m_blackFrameURL); +} + +TQString BlackFrameListViewItem::text(int column)const +{ + switch (column) + { + case 0: + { + // First column includes the pixmap + break; + } + case 1: + { + // The image size. + if (!m_imageSize.isEmpty()) + return (TQString("%1x%2").arg(m_imageSize.width()).arg(m_imageSize.height())); + break; + } + case 2: + { + // The amount of hot pixels found in the black frame. + return (TQString::number(m_hotPixels.count())); + break; + } + } + + return TQString(); +} + +void BlackFrameListViewItem::paintCell(TQPainter* p, const TQColorGroup& cg, int column, int width, int align) +{ + //Let the normal listview item draw it all for now + TQListViewItem::paintCell(p, cg, column, width, align); +} + +void BlackFrameListViewItem::slotParsed(TQValueList<HotPixel> hotPixels) +{ + m_hotPixels = hotPixels; + m_image = m_parser->image(); + m_imageSize = m_image.size(); + m_thumb = thumb(TQSize(THUMB_WIDTH, THUMB_WIDTH/3*2)); + setPixmap(0, m_thumb); + + m_blackFrameDesc = TQString("<p><b>" + m_blackFrameURL.fileName() + "</b>:<p>"); + TQValueList <HotPixel>::Iterator end(m_hotPixels.end()); + for (TQValueList <HotPixel>::Iterator it = m_hotPixels.begin() ; it != end ; ++it) + m_blackFrameDesc.append( TQString("[%1,%2] ").arg((*it).x()).arg((*it).y()) ); + + emit parsed(m_hotPixels, m_blackFrameURL); +} + +TQPixmap BlackFrameListViewItem::thumb(const TQSize& size) +{ + TQPixmap thumb; + + //First scale it down to the size + thumb = m_image.smoothScale(size, TQImage::ScaleMin); + + //And draw the hot pixel positions on the thumb + TQPainter p(&thumb); + + //Take scaling into account + float xRatio, yRatio; + float hpThumbX, hpThumbY; + TQRect hpRect; + + xRatio = (float)size.width()/(float)m_image.width(); + yRatio = (float)size.height()/(float)m_image.height(); + + //Draw hot pixels one by one + TQValueList <HotPixel>::Iterator it; + TQValueList <HotPixel>::Iterator end(m_hotPixels.end()); + for (it=m_hotPixels.begin() ; it!=end ; ++it) + { + hpRect = (*it).rect; + hpThumbX = (hpRect.x()+hpRect.width()/2)*xRatio; + hpThumbY = (hpRect.y()+hpRect.height()/2)*yRatio; + + p.setPen(TQPen(TQt::black)); + p.drawLine((int)hpThumbX, (int)hpThumbY-1, (int)hpThumbX, (int)hpThumbY+1); + p.drawLine((int)hpThumbX-1, (int)hpThumbY, (int)hpThumbX+1, (int)hpThumbY); + p.setPen(TQPen(TQt::white)); + p.drawPoint((int)hpThumbX-1, (int)hpThumbY-1); + p.drawPoint((int)hpThumbX+1, (int)hpThumbY+1); + p.drawPoint((int)hpThumbX-1, (int)hpThumbY+1); + p.drawPoint((int)hpThumbX+1, (int)hpThumbY-1); + } + + return thumb; +} + +int BlackFrameListViewItem::width(const TQFontMetrics& fm,const TQListView* lv,int c)const +{ + if (c==0) return THUMB_WIDTH; + else return TQListViewItem::width(fm,lv,c); +} + +} // NameSpace DigikamHotPixelsImagesPlugin diff --git a/src/imageplugins/hotpixels/blackframelistview.h b/src/imageplugins/hotpixels/blackframelistview.h new file mode 100644 index 00000000..977d226d --- /dev/null +++ b/src/imageplugins/hotpixels/blackframelistview.h @@ -0,0 +1,127 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-07-05 + * Description : a ListView to display black frames + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * + * 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. + * + * ============================================================ */ + +#ifndef BLACKFRAMELISTVIEW_H +#define BLACKFRAMELISTVIEW_H + +// TQt includes. + +#include <tqimage.h> +#include <tqstring.h> +#include <tqsize.h> +#include <tqpoint.h> +#include <tqvaluelist.h> +#include <tqlistview.h> + +// KDE includes. + +#include <kurl.h> +#include <tdelocale.h> + +// Local includes. + +#include "blackframeparser.h" +#include "hotpixel.h" + +namespace DigikamHotPixelsImagesPlugin +{ + +class BlackFrameListView : public TQListView +{ + TQ_OBJECT + + +public: + + BlackFrameListView(TQWidget* parent=0); + ~BlackFrameListView(){}; + +signals: + + void blackFrameSelected(TQValueList<HotPixel>, const KURL&); + +private slots: + + void slotParsed(TQValueList<HotPixel> hotPixels, const KURL& blackFrameURL) + { + emit blackFrameSelected(hotPixels, blackFrameURL); + }; +}; + +// -------------------------------------------------------------------------- + +class BlackFrameListViewItem : public TQObject, TQListViewItem +{ +TQ_OBJECT + + +public: + + BlackFrameListViewItem(BlackFrameListView* parent, const KURL &url); + ~BlackFrameListViewItem(){}; + + virtual TQString text(int column)const; + virtual void paintCell(TQPainter* p, const TQColorGroup& cg, int column, int width, int align); + virtual int width(const TQFontMetrics& fm, const TQListView* lv, int c)const; + +signals: + + void parsed(TQValueList<HotPixel>, const KURL&); + void signalLoadingProgress(float); + void signalLoadingComplete(); + +protected: + + void activate(); + +private: + + TQPixmap thumb(const TQSize& size); + +private slots: + + void slotParsed(TQValueList<HotPixel>); + +private: + + // Data contained within each listview item + TQImage m_thumb; + TQImage m_image; + + TQSize m_imageSize; + + TQValueList <HotPixel> m_hotPixels; + + TQString m_blackFrameDesc; + + KURL m_blackFrameURL; + + BlackFrameParser *m_parser; + + BlackFrameListView *m_parent; +}; + +} // NameSpace DigikamHotPixelsImagesPlugin + +#endif // BLACKFRAMELISTVIEW_H diff --git a/src/imageplugins/hotpixels/blackframeparser.cpp b/src/imageplugins/hotpixels/blackframeparser.cpp new file mode 100644 index 00000000..7306f4e6 --- /dev/null +++ b/src/imageplugins/hotpixels/blackframeparser.cpp @@ -0,0 +1,211 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-27 + * Description : black frames parser + * + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * Part of the algorithm for finding the hot pixels was based on + * the code of jpegpixi, which was released under the GPL license, + * and is Copyright (C) 2003, 2004 Martin Dickopp + * + * 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. + * + * ============================================================ */ + +// Denominator for relative quantities. +#define DENOM (DENOM_STQRT * DENOM_STQRT) + +// Square root of denominator for relative quantities. +#define DENOM_STQRT 10000 + +// Convert relative to absolute numbers. Care must be taken not to overflow integers. +#define REL_TO_ABS(n,m) \ + ((((n) / DENOM_STQRT) * (m) + ((n) % DENOM_STQRT) * (m) / DENOM_STQRT) / DENOM_STQRT) + +// TQt includes. + +#include <tqimage.h> +#include <tqstringlist.h> + +// KDE includes. + +#include <tdeapplication.h> +#include <tdeversion.h> +#include <tdeio/netaccess.h> +#include <tdeio/job.h> + +// Local includes. + +#include "blackframeparser.h" +#include "blackframeparser.moc" + +namespace DigikamHotPixelsImagesPlugin +{ + +BlackFrameParser::BlackFrameParser(TQObject *parent) + : TQObject(parent) +{ + m_imageLoaderThread = 0; +} + +BlackFrameParser::~BlackFrameParser() +{ + delete m_imageLoaderThread; +} + +void BlackFrameParser::parseHotPixels(const TQString &file) +{ + parseBlackFrame(KURL(file)); +} + +void BlackFrameParser::parseBlackFrame(const KURL &url) +{ +#if KDE_IS_VERSION(3,2,0) + TDEIO::NetAccess::download(url, m_localFile, kapp->activeWindow()); +#else + TDEIO::NetAccess::download(url, m_localFile); +#endif + + if (!m_imageLoaderThread) + { + m_imageLoaderThread = new LoadSaveThread(); + + connect(m_imageLoaderThread, TQ_SIGNAL(signalLoadingProgress(const LoadingDescription&, float)), + this, TQ_SLOT(slotLoadingProgress(const LoadingDescription&, float))); + + connect(m_imageLoaderThread, TQ_SIGNAL(signalImageLoaded(const LoadingDescription&, const DImg&)), + this, TQ_SLOT(slotLoadImageFromUrlComplete(const LoadingDescription&, const DImg&))); + } + + LoadingDescription desc = LoadingDescription(m_localFile, DRawDecoding()); + m_imageLoaderThread->load(desc); +} + +void BlackFrameParser::slotLoadingProgress(const LoadingDescription&, float v) +{ + emit signalLoadingProgress(v); +} + +void BlackFrameParser::slotLoadImageFromUrlComplete(const LoadingDescription&, const DImg& img) +{ + DImg image(img); + m_Image = image.copyTQImage(); + blackFrameParsing(); + emit signalLoadingComplete(); +} + +void BlackFrameParser::parseBlackFrame(TQImage& img) +{ + m_Image = img; + blackFrameParsing(); +} + +// Parses black frames + +void BlackFrameParser::blackFrameParsing() +{ + // Now find the hot pixels and store them in a list + TQValueList<HotPixel> hpList; + + for (int y=0 ; y < m_Image.height() ; ++y) + { + for (int x=0 ; x < m_Image.width() ; ++x) + { + //Get each point in the image + TQRgb pixrgb = m_Image.pixel(x,y); + TQColor color; color.setRgb(pixrgb); + + // Find maximum component value. + int maxValue; + int threshold = DENOM/10; + const int threshold_value = REL_TO_ABS(threshold, 255); + maxValue = (color.red()>color.blue()) ? color.red() : color.blue(); + if (color.green() > maxValue) maxValue = color.green(); + + // If the component is bigger than the threshold, add the point + if (maxValue > threshold_value) + { + HotPixel point; + point.rect = TQRect (x, y, 1, 1); + //TODO:check this + point.luminosity = ((2 * DENOM) / 255 ) * maxValue / 2; + + hpList.append(point); + } + } + } + + //Now join points together into groups + consolidatePixels (hpList); + + //And notify + emit parsed(hpList); +} + +// Consolidate adjacent points into larger points. + +void BlackFrameParser::consolidatePixels (TQValueList<HotPixel>& list) +{ + if (list.isEmpty()) + return; + + /* Consolidate horizontally. */ + + TQValueList<HotPixel>::iterator it, prevPointIt; + + prevPointIt = list.begin(); + it = list.begin(); + ++it; + + HotPixel tmp; + HotPixel point; + HotPixel point_below; + TQValueList<HotPixel>::iterator end(list.end()); + for (; it != end; ++it ) + { + while (1) + { + point = (*it); + tmp = point; + + TQValueList<HotPixel>::Iterator point_below_it; + point_below_it = list.find (tmp); //find any intersecting hotp below tmp + if (point_below_it != list.end()) + { + point_below =* point_below_it; + validateAndConsolidate (&point, &point_below); + + point.rect.setX(MIN(point.x(), point_below.x())); + point.rect.setWidth(MAX(point.x() + point.width(), + point_below.x() + point_below.width()) - point.x()); + point.rect.setHeight(MAX(point.y() + point.height(), + point_below.y() + point_below.height()) - point.y()); + *it = point; + list.remove (point_below_it); //TODO: Check! this could remove it++? + } + else + break; + } + } +} + +void BlackFrameParser::validateAndConsolidate (HotPixel *a, HotPixel *b) +{ + a->luminosity = MAX (a->luminosity, b->luminosity); +} + +} // NameSpace DigikamHotPixelsImagesPlugin diff --git a/src/imageplugins/hotpixels/blackframeparser.h b/src/imageplugins/hotpixels/blackframeparser.h new file mode 100644 index 00000000..f13ebdc4 --- /dev/null +++ b/src/imageplugins/hotpixels/blackframeparser.h @@ -0,0 +1,102 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-27 + * Description : black frames parser + * + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * Part of the algorithm for finding the hot pixels was based on + * the code of jpegpixi, which was released under the GPL license, + * and is Copyright (C) 2003, 2004 Martin Dickopp + * + * 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. + * + * ============================================================ */ + +#ifndef BLACKFRAMEPARSER_H +#define BLACKFRAMEPARSER_H + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +// TQt includes. + +#include <tqimage.h> +#include <tqobject.h> +#include <tqvaluelist.h> +#include <tqstring.h> +#include <tqrect.h> + +// KDE includes. + +#include <kurl.h> + +// Local includes. + +#include "dimg.h" +#include "loadsavethread.h" +#include "hotpixel.h" + +using namespace Digikam; + +namespace DigikamHotPixelsImagesPlugin +{ + +class BlackFrameParser: public TQObject +{ + TQ_OBJECT + + +public: + + BlackFrameParser(TQObject *parent); + ~BlackFrameParser(); + + void parseHotPixels(const TQString &file); + void parseBlackFrame(const KURL &url); + void parseBlackFrame(TQImage& img); + TQImage image(){return m_Image;} + +signals: + + void parsed(TQValueList<HotPixel>); + void signalLoadingProgress(float); + void signalLoadingComplete(); + +private slots: + + void slotLoadingProgress(const LoadingDescription&, float); + void slotLoadImageFromUrlComplete(const LoadingDescription&, const DImg&); + +private: + + void blackFrameParsing(); + void consolidatePixels(TQValueList<HotPixel>& list); + void validateAndConsolidate(HotPixel *a, HotPixel *b); + +private: + + TQString m_OutputString; + TQString m_localFile; + + TQImage m_Image; + + LoadSaveThread *m_imageLoaderThread; +}; + +} // NameSpace DigikamHotPixelsImagesPlugin + +#endif // BLACKFRAMEPARSER_H diff --git a/src/imageplugins/hotpixels/digikamimageplugin_hotpixels.desktop b/src/imageplugins/hotpixels/digikamimageplugin_hotpixels.desktop new file mode 100644 index 00000000..5b12fe2c --- /dev/null +++ b/src/imageplugins/hotpixels/digikamimageplugin_hotpixels.desktop @@ -0,0 +1,50 @@ +[Desktop Entry] +Name=ImagePlugin_HotPixels +Name[bg]=Приставка за снимки - Горещи пиксели +Name[el]=ΠρόσθετοΕικόνας_ΈντοναΕικονοστοιχεία +Name[fi]=KuumatPikselit +Name[hr]=Vrući pikseli +Name[it]=PluginImmagini_PixelBruciati +Name[ms]=ImagePlugin_PikselPanas +Name[nl]=Afbeeldingsplugin_HotPixels +Name[sr]=Врући пиксели +Name[sr@Latn]=Vrući pikseli +Name[sv]=Insticksprogram för heta bildpunkter +Name[tr]=ResimEklentisi_Çekirdek +Name[xx]=xxImagePlugin_HotPixelsxx +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=Hot pixel correction plugin for digiKam +Comment[ca]=Connector per al digiKam de correcció de píxels cremats +Comment[da]=Hot pixel rettelsesplugin for Digikam +Comment[de]=digiKam-Modul zur Korrektur von heißen (defekten) Pixeln +Comment[el]=Πρόσθετο διόρθωσης έντονων εικονοστοιχείων για το digiKam +Comment[es]=Plugin para digiKampara corregir los píxeles quemados de la imagen +Comment[et]=DigiKami kuumade pikslite korrigeerimise plugin +Comment[fa]=وصلۀ اصلاح تصویردانۀ Hot برای digiKam +Comment[fi]=Digitaalisen rakeisuushäiriön korjaus +Comment[gl]=Un plugin de digiKam para corrixir os pixels queimados da imaxe +Comment[hr]=digiKam dodatak za ispravljanje vrućih piksela +Comment[is]=Íforrit fyrir digiKam sem fjarlægir skemmda díla (hot pixels) +Comment[it]=Plugin di correzione dei pixel bruciati per digiKam +Comment[ja]=digiKam ホットピクセル除去プラグイン +Comment[ms]=Plugin pembetulan piksel panas untuk digiKam +Comment[nds]=digiKam-Moduul för't Richten vun hitte Pixels +Comment[nl]=Digikam-plugin voor het corrigeren van de hotpixels +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਹਾਟ ਪਿਕਸਲ ਸੋਧ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam usuwająca "gorące piksele" +Comment[pt]=Um 'plugin' do digiKam para corrigir os pixels queimados da imagem +Comment[pt_BR]=Plugin de Correção de hot pixel para o digiKam +Comment[ru]=Модуль коррекции ярких пикселей для digiKam +Comment[sk]=digiKam plugin pre korekciu vypálených pixelov +Comment[sr]=digiKam-ов прикључак исправку врућих пиксела +Comment[sr@Latn]=digiKam-ov priključak ispravku vrućih piksela +Comment[sv]=Digikam insticksprogram för korrigering av heta bildpunkter +Comment[tr]=digiKam için beyaz dengesini düzeltme eklentisi +Comment[uk]=Втулок виправлення гарячих пікселів для Digikam +Comment[vi]=Phần bổ sung sửa điểm ảnh nóng cho digiKam +Comment[xx]=xxHot pixel correction plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_hotpixels +author=Unai Garro, ugarro at sourceforge dot net diff --git a/src/imageplugins/hotpixels/digikamimageplugin_hotpixels_ui.rc b/src/imageplugins/hotpixels/digikamimageplugin_hotpixels_ui.rc new file mode 100644 index 00000000..b80d7f5a --- /dev/null +++ b/src/imageplugins/hotpixels/digikamimageplugin_hotpixels_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="4" name="digikamimageplugin_hotpixels" > + + <MenuBar> + + <Menu name="Enhance" ><text>Enh&ance</text> + <Action name="imageplugin_hotpixels" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action shortcut="" name="imageplugin_hotpixels" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/hotpixels/hotpixel.h b/src/imageplugins/hotpixels/hotpixel.h new file mode 100644 index 00000000..bceb539f --- /dev/null +++ b/src/imageplugins/hotpixels/hotpixel.h @@ -0,0 +1,74 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-27 + * Description : Threaded image filter to fix hot pixels + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * + * 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. + * + * ============================================================ */ + +#ifndef HOTPIXEL_H +#define HOTPIXEL_H + +// TQt includes. + +#include <tqrect.h> + +namespace DigikamHotPixelsImagesPlugin +{ + +class HotPixel +{ + +public: + + TQRect rect; + int luminosity; + int y() const {return rect.y(); }; + int x() const {return rect.x(); }; + int width()const {return rect.width(); }; + int height()const {return rect.height();}; + + bool operator==(const HotPixel p) const + { + //we can say they're same hotpixel spot if they + //touch(next to) each other horizontally or vertically, not diagonal corners + //return (rect.intersects(p.rect)); + return (rect != p.rect) && (x() + width() >= p.x() && x() <= p.x() + p.width() + && y() + height() >= p.y() && y() <= p.y() + p.height()) + && !diagonal(rect, p.rect); + } + +private: + + bool diagonal(TQRect r1,TQRect r2) const + { + //locate next-to positions + + bool top = r1.y() + height()-1 == r2.y()-1; //r1 is on the top of r2 + bool left = r1.x() + width()-1 == r2.x()-1; //r1 is on the left of r2 + bool right = r1.x() == r2.x() + r2.width(); + bool bottom = r1.y() == r2.y() + r2.height(); + + return ((top && left) || (top && right) || (bottom && left) || (bottom && right)); + } +}; + +} // NameSpace DigikamHotPixelsImagesPlugin + +#endif // HOTPIXEL_H diff --git a/src/imageplugins/hotpixels/hotpixelfixer.cpp b/src/imageplugins/hotpixels/hotpixelfixer.cpp new file mode 100644 index 00000000..d29b8525 --- /dev/null +++ b/src/imageplugins/hotpixels/hotpixelfixer.cpp @@ -0,0 +1,302 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-27 + * Description : Threaded image filter to fix hot pixels + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * + * 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> +#include <cstdlib> + +// TQt includes. + +#include <tqcolor.h> +#include <tqregexp.h> +#include <tqstringlist.h> + +// Local includes. + +#include "dimg.h" +#include "ddebug.h" +#include "hotpixelfixer.h" + +#ifdef HAVE_FLOAT_H +#if HAVE_FLOAT_H +# include <float.h> +#endif +#endif + +#ifndef DBL_MIN +# define DBL_MIN 1e-37 +#endif +#ifndef DBL_MAX +# define DBL_MAX 1e37 +#endif + +namespace DigikamHotPixelsImagesPlugin +{ + +HotPixelFixer::HotPixelFixer(Digikam::DImg *orgImage, TQObject *parent, const TQValueList<HotPixel>& hpList, + int interpolationMethod) + : Digikam::DImgThreadedFilter(orgImage, parent, "HotPixels") +{ + m_hpList = hpList; + m_interpolationMethod = interpolationMethod; + mWeightList.clear(); + + initFilter(); +} + +HotPixelFixer::~HotPixelFixer() +{ +} + +void HotPixelFixer::filterImage(void) +{ + TQValueList <HotPixel>::ConstIterator it; + TQValueList <HotPixel>::ConstIterator end(m_hpList.end()); + for (it = m_hpList.begin() ; it != end ; ++it) + { + HotPixel hp = *it; + interpolate(m_orgImage, hp, m_interpolationMethod); + } + + m_destImage = m_orgImage; +} + +// Interpolates a pixel block +void HotPixelFixer::interpolate (Digikam::DImg &img, HotPixel &hp, int method) +{ + const int xPos = hp.x(); + const int yPos = hp.y(); + bool sixtBits = img.sixteenBit(); + + // Interpolate pixel. + switch (method) + { + case AVERAGE_INTERPOLATION: + { + // We implement the bidimendional one first. + // TODO: implement the rest of directions (V & H) here + + //case twodim: + // { + int sum_weight = 0; + double vr=0.0,vg=0.0,vb=0.0; + int x, y; + Digikam::DColor col; + + for (x = xPos; x < xPos+hp.width(); ++x) + { + if (validPoint(img,TQPoint(x,yPos-1))) + { + col=img.getPixelColor(x,yPos-1); + vr += col.red(); + vg += col.green(); + vb += col.blue(); + ++sum_weight; + } + if (validPoint(img,TQPoint(x,yPos+hp.height()))) + { + col=img.getPixelColor(x,yPos+hp.height()); + vr += col.red(); + vg += col.green(); + vb += col.blue(); + ++sum_weight; + } + } + + for (y = yPos; y < hp.height(); ++y) + { + if (validPoint(img,TQPoint(xPos-1,y))) + { + col=img.getPixelColor(xPos,y); + vr += col.red(); + vg += col.green(); + vb += col.blue(); + ++sum_weight; + } + if (validPoint(img,TQPoint(xPos+hp.width(),y))) + { + col=img.getPixelColor(xPos+hp.width(),y); + vr += col.red(); + vg += col.green(); + vb += col.blue(); + ++sum_weight; + } + } + + if (sum_weight > 0) + { + vr /= (double)sum_weight; + vg /= (double)sum_weight; + vb /= (double)sum_weight; + + + for (x = 0; x < hp.width(); ++x) + for (y = 0; y < hp.height(); ++y) + if (validPoint(img,TQPoint(xPos+x,yPos+y))) + { + int alpha=sixtBits ? 65535 : 255; + int ir=(int )round(vr),ig=(int) round(vg),ib=(int) round(vb); + img.setPixelColor(xPos+x,yPos+y,Digikam::DColor(ir,ig,ib,alpha,sixtBits)); + } + } + break; + } //Case average + + case LINEAR_INTERPOLATION: + //(Bi)linear interpolation. + weightPixels (img,hp,LINEAR_INTERPOLATION,TWODIM_DIRECTION,sixtBits ? 65535: 255); + break; + + case QUADRATIC_INTERPOLATION: + // (Bi)quadratic interpolation. + weightPixels (img,hp,QUADRATIC_INTERPOLATION,TWODIM_DIRECTION,sixtBits ? 65535 : 255); + break; + + case CUBIC_INTERPOLATION: + // (Bi)cubic interpolation. + weightPixels (img,hp,CUBIC_INTERPOLATION,TWODIM_DIRECTION,sixtBits ? 65535 : 255); + break; + } //switch +} + +void HotPixelFixer::weightPixels (Digikam::DImg &img, HotPixel &px, int method, Direction dir,int maxComponent) +{ + //TODO: implement direction here too + + for (int iComp = 0; iComp < 3; ++iComp) + { + // Obtain weight data block. + + Weights w; + int polynomeOrder=-1; + + switch (method) + { + case AVERAGE_INTERPOLATION: // Gilles: to prevent warnings from compiler. + break; + case LINEAR_INTERPOLATION: + polynomeOrder=1; + break; + case QUADRATIC_INTERPOLATION: + polynomeOrder=2; + break; + case CUBIC_INTERPOLATION: + polynomeOrder=3; + break; + } + if (polynomeOrder<0) return; + + // In the one-dimensional case, the width must be 1, + // and the size must be stored in height + + w.setWidth(dir == TWODIM_DIRECTION ? px.width() : 1); + w.setHeight(dir == HORIZONTAL_DIRECTION ? px.width() : px.height()); + w.setPolynomeOrder(polynomeOrder); + w.setTwoDim(dir == TWODIM_DIRECTION); + + //TODO: check this, it must not recalculate existing calculated weights + //for now I don't think it is finding the duplicates fine, so it uses + //the previous one always... + + //if (mWeightList.find(w)==mWeightList.end()) + //{ + w.calculateWeights(); + + // mWeightList.append(w); + + //} + + // Calculate weighted pixel sum. + for (int y = 0; y<px.height(); ++y) + { + for (int x = 0; x < px.width(); ++x) + { + if (validPoint (img,TQPoint(px.x()+x,px.y()+y))) + { + double sum_weight = 0.0, v = 0.0; + size_t i; + + for (i = 0; i < w.positions().count(); ++i) + { + // In the one-dimensional case, only the y coordinate is used. + const int xx = px.x()+(dir == VERTICAL_DIRECTION ? x : + dir== HORIZONTAL_DIRECTION ? w.positions()[i].y() : w.positions()[i].x()); + const int yy = px.y()+(dir == HORIZONTAL_DIRECTION ? y : + w.positions()[i].y()); + + if (validPoint (img,TQPoint(xx, yy))) + { + //TODO: check this. I think it is broken + double weight; + if (dir==VERTICAL_DIRECTION) + { + weight = w[i][y][0]; + } + else if (dir==HORIZONTAL_DIRECTION) + { + weight=w[i][0][x]; + } + else + { + weight=w[i][y][x]; + } + + if (iComp==0) v += weight * img.getPixelColor(xx, yy).red(); + else if (iComp==1) v += weight * img.getPixelColor(xx, yy).green(); + else v += weight * img.getPixelColor(xx, yy).blue(); + + sum_weight += weight; + } + } + + Digikam::DColor color=img.getPixelColor(px.x()+x,px.y()+y); + int component; + if (fabs (v) <= DBL_MIN) + component=0; + else if (sum_weight >= DBL_MIN) + { + component=(int) (v/sum_weight); + //Clamp value + if (component<0) component=0; + if (component>maxComponent) component=maxComponent; + } + else if (v >= 0.0) + component=maxComponent; + else + component=0; + + if (iComp==0) color.setRed(component); + else if (iComp==1) color.setGreen(component); + else color.setBlue(component); + + + img.setPixelColor(px.x()+x,px.y()+y,color); + } + } + } + } +} + +} // NameSpace DigikamHotPixelsImagesPlugin diff --git a/src/imageplugins/hotpixels/hotpixelfixer.h b/src/imageplugins/hotpixels/hotpixelfixer.h new file mode 100644 index 00000000..2bf8131c --- /dev/null +++ b/src/imageplugins/hotpixels/hotpixelfixer.h @@ -0,0 +1,98 @@ +/* ============================================================ + * Authors: Unai Garro <ugarro at users dot sourceforge dot net> + * Gilles Caulier <caulier dot gilles at free dot fr> + * Date : 2005-03-27 + * Description : Threaded image filter to fix hot pixels + * + * Copyright 2005-2007 by Unai Garro and Gilles Caulier + * + * The algorithm for fixing the hot pixels was based on + * the code of jpegpixi, which was released under the GPL license, + * and is Copyright (C) 2003, 2004 Martin Dickopp + * + * 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. + * + * ============================================================*/ + +#ifndef HOTPIXELFIXER_H +#define HOTPIXELFIXER_H + +// TQt includes. + +#include <tqimage.h> +#include <tqobject.h> +#include <tqvaluelist.h> +#include <tqrect.h> +#include <tqstring.h> + +// Digikam includes. + +#include "dimgthreadedfilter.h" + +// Local includes. + +#include "hotpixel.h" +#include "weights.h" + +namespace DigikamHotPixelsImagesPlugin +{ + +class HotPixelFixer : public Digikam::DImgThreadedFilter +{ + +public: + + enum InterpolationMethod + { + AVERAGE_INTERPOLATION = 0, + LINEAR_INTERPOLATION = 1, + QUADRATIC_INTERPOLATION = 2, + CUBIC_INTERPOLATION = 3 + }; + + enum Direction + { + TWODIM_DIRECTION = 0, + VERTICAL_DIRECTION = 1, + HORIZONTAL_DIRECTION = 2 + }; + +public: + + HotPixelFixer(Digikam::DImg *orgImage, TQObject *parent, + const TQValueList<HotPixel>& hpList, int interpolationMethod); + ~HotPixelFixer(); + +private: + + virtual void filterImage(void); + + void interpolate (Digikam::DImg &img,HotPixel &hp, int method); + void weightPixels (Digikam::DImg &img, HotPixel &px, int method, Direction dir, int maxComponent); + + inline bool validPoint(Digikam::DImg &img, TQPoint p) + { + return (p.x()>=0 && p.y()>=0 && p.x()<(long) img.width() && p.y()<(long) img.height()); + }; + + TQValueList <Weights> mWeightList; + +private: + + int m_interpolationMethod; + + TQValueList<HotPixel> m_hpList; +}; + +} // NameSpace DigikamHotPixelsImagesPlugin + +#endif // HOTPIXELFIXER_H diff --git a/src/imageplugins/hotpixels/hotpixelstool.cpp b/src/imageplugins/hotpixels/hotpixelstool.cpp new file mode 100644 index 00000000..fbcc6c9f --- /dev/null +++ b/src/imageplugins/hotpixels/hotpixelstool.cpp @@ -0,0 +1,276 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-27 + * Description : a digiKam image plugin for fixing dots produced by + * hot/stuck/dead pixels from a CCD. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * + * 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 <tqcombobox.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqwhatsthis.h> +#include <tqpushbutton.h> +#include <tqpointarray.h> + +// KDE includes. + +#include <tdelocale.h> +#include <tdeconfig.h> +#include <kimageio.h> +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <kstandarddirs.h> +#include <tdefiledialog.h> +#include <kprogress.h> +#include <kiconloader.h> +#include <kpushbutton.h> + +// LibKDcraw includes. + +#include <libkdcraw/rcombobox.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "imagepanelwidget.h" +#include "editortooliface.h" +#include "editortoolsettings.h" +#include "imagedialog.h" +#include "blackframelistview.h" +#include "hotpixelstool.h" +#include "hotpixelstool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamHotPixelsImagesPlugin +{ + +HotPixelsTool::HotPixelsTool(TQObject* parent) + : EditorToolThreaded(parent) +{ + setName("hotpixels"); + setToolName(i18n("Hot Pixels")); + setToolIcon(SmallIcon("hotpixels")); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Ok| + EditorToolSettings::Try| + EditorToolSettings::Cancel, + EditorToolSettings::PanIcon); + + TQGridLayout* grid = new TQGridLayout(m_gboxSettings->plainPage(), 3, 2); + + TQLabel *filterMethodLabel = new TQLabel(i18n("Filter:"), m_gboxSettings->plainPage()); + m_filterMethodCombo = new RComboBox(m_gboxSettings->plainPage()); + m_filterMethodCombo->insertItem(i18n("Average")); + m_filterMethodCombo->insertItem(i18n("Linear")); + m_filterMethodCombo->insertItem(i18n("Quadratic")); + m_filterMethodCombo->insertItem(i18n("Cubic")); + m_filterMethodCombo->setDefaultItem(HotPixelFixer::QUADRATIC_INTERPOLATION); + + m_blackFrameButton = new TQPushButton(i18n("Black Frame..."), m_gboxSettings->plainPage()); + TQWhatsThis::add(m_blackFrameButton, i18n("<p>Use this button to " + "add a new black frame file which will be used by the hot pixels removal filter.")); + + m_blackFrameListView = new BlackFrameListView(m_gboxSettings->plainPage()); + + grid->addMultiCellWidget(filterMethodLabel, 0, 0, 0, 0); + grid->addMultiCellWidget(m_filterMethodCombo, 0, 0, 1, 1); + grid->addMultiCellWidget(m_blackFrameButton, 0, 0, 2, 2); + grid->addMultiCellWidget(m_blackFrameListView, 1, 2, 0, 2); + grid->setRowStretch(3, 10); + grid->setMargin(m_gboxSettings->spacingHint()); + grid->setSpacing(m_gboxSettings->spacingHint()); + + setToolSettings(m_gboxSettings); + + // ------------------------------------------------------------- + + m_previewWidget = new ImagePanelWidget(470, 350, "hotpixels Tool", m_gboxSettings->panIconView(), + 0, ImagePanelWidget::SeparateViewDuplicate); + + setToolView(m_previewWidget); + init(); + + // ------------------------------------------------------------- + + connect(m_filterMethodCombo, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotEffect())); + + connect(m_blackFrameButton, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotAddBlackFrame())); + + connect(m_blackFrameListView, TQ_SIGNAL(blackFrameSelected(TQValueList<HotPixel>, const KURL&)), + this, TQ_SLOT(slotBlackFrame(TQValueList<HotPixel>, const KURL&))); +} + +HotPixelsTool::~HotPixelsTool() +{ +} + +void HotPixelsTool::readSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("hotpixels Tool"); + m_blackFrameURL = KURL(config->readEntry("Last Black Frame File", TQString())); + m_filterMethodCombo->setCurrentItem(config->readNumEntry("Filter Method", + m_filterMethodCombo->defaultItem())); + + if (m_blackFrameURL.isValid()) + { + EditorToolIface::editorToolIface()->setToolStartProgress(i18n("Loading: ")); + BlackFrameListViewItem *item = new BlackFrameListViewItem(m_blackFrameListView, m_blackFrameURL); + + connect(item, TQ_SIGNAL(signalLoadingProgress(float)), + this, TQ_SLOT(slotLoadingProgress(float))); + + connect(item, TQ_SIGNAL(signalLoadingComplete()), + this, TQ_SLOT(slotLoadingComplete())); + } +} + +void HotPixelsTool::slotLoadingProgress(float v) +{ + EditorToolIface::editorToolIface()->setToolProgress((int)(v*100)); +} + +void HotPixelsTool::slotLoadingComplete() +{ + EditorToolIface::editorToolIface()->setToolStopProgress(); +} + +void HotPixelsTool::writeSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("hotpixels Tool"); + config->writeEntry("Last Black Frame File", m_blackFrameURL.url()); + config->writeEntry("Filter Method", m_filterMethodCombo->currentItem()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void HotPixelsTool::slotResetSettings() +{ + m_filterMethodCombo->blockSignals(true); + m_filterMethodCombo->slotReset(); + m_filterMethodCombo->blockSignals(false); +} + +void HotPixelsTool::slotAddBlackFrame() +{ + KURL url = ImageDialog::getImageURL(kapp->activeWindow(), m_blackFrameURL, i18n("Select Black Frame Image")); + + if (!url.isEmpty()) + { + // Load the selected file and insert into the list. + + m_blackFrameURL = url; + m_blackFrameListView->clear(); + BlackFrameListViewItem *item = new BlackFrameListViewItem(m_blackFrameListView, m_blackFrameURL); + + connect(item, TQ_SIGNAL(signalLoadingProgress(float)), + this, TQ_SLOT(slotLoadingProgress(float))); + + connect(item, TQ_SIGNAL(signalLoadingComplete()), + this, TQ_SLOT(slotLoadingComplete())); + } +} + +void HotPixelsTool::renderingFinished() +{ + m_filterMethodCombo->setEnabled(true); + m_blackFrameListView->setEnabled(true); +} + +void HotPixelsTool::prepareEffect() +{ + m_filterMethodCombo->setEnabled(false); + m_blackFrameListView->setEnabled(false); + + DImg image = m_previewWidget->getOriginalRegionImage(); + int interpolationMethod = m_filterMethodCombo->currentItem(); + + TQValueList<HotPixel> hotPixelsRegion; + TQRect area = m_previewWidget->getOriginalImageRegionToRender(); + TQValueList<HotPixel>::Iterator end(m_hotPixelsList.end()); + + for (TQValueList<HotPixel>::Iterator it = m_hotPixelsList.begin() ; it != end ; ++it ) + { + HotPixel hp = (*it); + + if ( area.contains( hp.rect ) ) + { + hp.rect.moveTopLeft(TQPoint( hp.rect.x()-area.x(), hp.rect.y()-area.y() )); + hotPixelsRegion.append(hp); + } + } + + setFilter(dynamic_cast<DImgThreadedFilter*>(new HotPixelFixer(&image, this, hotPixelsRegion, interpolationMethod))); +} + +void HotPixelsTool::prepareFinal() +{ + m_filterMethodCombo->setEnabled(false); + m_blackFrameListView->setEnabled(false); + + int interpolationMethod = m_filterMethodCombo->currentItem(); + + ImageIface iface(0, 0); + setFilter(dynamic_cast<DImgThreadedFilter*>(new HotPixelFixer(iface.getOriginalImg(), this,m_hotPixelsList,interpolationMethod))); +} + +void HotPixelsTool::putPreviewData() +{ + m_previewWidget->setPreviewImage(filter()->getTargetImage()); +} + +void HotPixelsTool::putFinalData() +{ + ImageIface iface(0, 0); + iface.putOriginalImage(i18n("Hot Pixels Correction"), filter()->getTargetImage().bits()); +} + +void HotPixelsTool::slotBlackFrame(TQValueList<HotPixel> hpList, const KURL& blackFrameURL) +{ + m_blackFrameURL = blackFrameURL; + m_hotPixelsList = hpList; + + TQPointArray pointList(m_hotPixelsList.size()); + TQValueList <HotPixel>::Iterator it; + int i = 0; + TQValueList <HotPixel>::Iterator end(m_hotPixelsList.end()); + + for (it = m_hotPixelsList.begin() ; it != end ; ++it, i++) + pointList.setPoint(i, (*it).rect.center()); + + m_previewWidget->setPanIconHighLightPoints(pointList); + + slotEffect(); +} + +} // NameSpace DigikamHotPixelsImagesPlugin diff --git a/src/imageplugins/hotpixels/hotpixelstool.h b/src/imageplugins/hotpixels/hotpixelstool.h new file mode 100644 index 00000000..727c6387 --- /dev/null +++ b/src/imageplugins/hotpixels/hotpixelstool.h @@ -0,0 +1,113 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-27 + * Description : a digiKam image plugin for fixing dots produced by + * hot/stuck/dead pixels from a CCD. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_HOTPIXELS_H +#define IMAGEEFFECT_HOTPIXELS_H + +#define MAX_PIXEL_DEPTH 4 + +// TQt includes. + +#include <tqvaluelist.h> + +// KDE includes. + +#include <kurl.h> + +// Digikam includes. + +#include "editortool.h" + +// Local includes. + +#include "hotpixelfixer.h" + +class TQPushButton; + +namespace KDcrawIface +{ +class RComboBox; +} + +namespace Digikam +{ +class EditorToolSettings; +class ImagePanelWidget; +} + +namespace DigikamHotPixelsImagesPlugin +{ + +class BlackFrameListView; + +class HotPixelsTool : public Digikam::EditorToolThreaded +{ + TQ_OBJECT + + +public: + + HotPixelsTool(TQObject *parent); + ~HotPixelsTool(); + +private slots: + + void slotBlackFrame(TQValueList<HotPixel> hpList, const KURL& blackFrameURL); + void slotResetSettings(); + void slotAddBlackFrame(); + void slotLoadingProgress(float); + void slotLoadingComplete(); + +private: + + void readSettings(); + void writeSettings(); + void prepareEffect(); + void prepareFinal(); + void abortPreview(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + TQPushButton *m_blackFrameButton; + + TQValueList<HotPixel> m_hotPixelsList; + + KURL m_blackFrameURL; + + BlackFrameListView *m_blackFrameListView; + + KDcrawIface::RComboBox *m_filterMethodCombo; + + Digikam::ImagePanelWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamHotPixelsImagesPlugin + +#endif /* IMAGEEFFECT_HOTPIXELS_H */ diff --git a/src/imageplugins/hotpixels/imageeffect_hotpixels.cpp b/src/imageplugins/hotpixels/imageeffect_hotpixels.cpp new file mode 100644 index 00000000..67e9a1b2 --- /dev/null +++ b/src/imageplugins/hotpixels/imageeffect_hotpixels.cpp @@ -0,0 +1,279 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-27 + * Description : a digiKam image plugin for fixing dots produced by + * hot/stuck/dead pixels from a CCD. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * + * 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 <tqcombobox.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqwhatsthis.h> +#include <tqpushbutton.h> +#include <tqpointarray.h> + +// KDE includes. + +#include <tdelocale.h> +#include <tdeconfig.h> +#include <kimageio.h> +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <kstandarddirs.h> +#include <tdefiledialog.h> +#include <kprogress.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "imagedialog.h" +#include "blackframelistview.h" +#include "imageeffect_hotpixels.h" +#include "imageeffect_hotpixels.moc" + +namespace DigikamHotPixelsImagesPlugin +{ + +ImageEffect_HotPixels::ImageEffect_HotPixels(TQWidget* parent) + : CtrlPanelDlg(parent, i18n("Hot Pixels Correction"), + "hotpixels", false, false, false, + Digikam::ImagePannelWidget::SeparateViewDuplicate) +{ + // No need Abort button action. + showButton(User1, false); + + TQString whatsThis; + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Hot Pixels Correction"), + digikam_version, + I18N_NOOP("A digiKam image plugin for fixing dots produced by " + "hot/stuck/dead pixels from a CCD."), + TDEAboutData::License_GPL, + "(c) 2005-2006, Unai Garro\n(c) 2005-2008, Gilles Caulier", + 0, + "http://www.digikam.org"); + + about->addAuthor("Unai Garro", I18N_NOOP("Author and maintainer"), + "ugarro at sourceforge dot net"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Developer"), + "caulier dot gilles at gmail dot com"); + + setAboutData(about); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(m_imagePreviewWidget); + TQGridLayout* gridSettings = new TQGridLayout(gboxSettings, 3, 2, 0, spacingHint()); + + TQLabel *filterMethodLabel = new TQLabel(i18n("Filter:"), gboxSettings); + m_filterMethodCombo = new TQComboBox(gboxSettings); + m_filterMethodCombo->insertItem(i18n("Average")); + m_filterMethodCombo->insertItem(i18n("Linear")); + m_filterMethodCombo->insertItem(i18n("Quadratic")); + m_filterMethodCombo->insertItem(i18n("Cubic")); + + m_blackFrameButton = new TQPushButton(i18n("Black Frame..."), gboxSettings); + setButtonWhatsThis( Apply, i18n("<p>Use this button to add a new black frame file which will " + "be used by the hot pixels removal filter.") ); + + m_blackFrameListView = new BlackFrameListView(gboxSettings); + m_progressBar = new KProgress(100, gboxSettings); + m_progressBar->setValue(0); + m_progressBar->hide(); + + gridSettings->addMultiCellWidget(filterMethodLabel, 0, 0, 0, 0); + gridSettings->addMultiCellWidget(m_filterMethodCombo, 0, 0, 1, 1); + gridSettings->addMultiCellWidget(m_blackFrameButton, 0, 0, 2, 2); + gridSettings->addMultiCellWidget(m_blackFrameListView, 1, 2, 0, 2); + gridSettings->addMultiCellWidget(m_progressBar, 3, 3, 0, 2); + + m_imagePreviewWidget->setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + connect(m_filterMethodCombo, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotEffect())); + + connect(m_blackFrameButton, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotAddBlackFrame())); + + connect(m_blackFrameListView, TQ_SIGNAL(blackFrameSelected(TQValueList<HotPixel>, const KURL&)), + this, TQ_SLOT(slotBlackFrame(TQValueList<HotPixel>, const KURL&))); +} + +ImageEffect_HotPixels::~ImageEffect_HotPixels() +{ +} + +void ImageEffect_HotPixels::readUserSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("hotpixels Tool Dialog"); + m_blackFrameURL = KURL(config->readEntry("Last Black Frame File", TQString())); + m_filterMethodCombo->setCurrentItem(config->readNumEntry("Filter Method", + HotPixelFixer::QUADRATIC_INTERPOLATION)); + + if (m_blackFrameURL.isValid()) + { + BlackFrameListViewItem *item = new BlackFrameListViewItem(m_blackFrameListView, m_blackFrameURL); + + connect(item, TQ_SIGNAL(signalLoadingProgress(float)), + this, TQ_SLOT(slotLoadingProgress(float))); + + connect(item, TQ_SIGNAL(signalLoadingComplete()), + this, TQ_SLOT(slotLoadingComplete())); + } +} + +void ImageEffect_HotPixels::writeUserSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("hotpixels Tool Dialog"); + config->writeEntry("Last Black Frame File", m_blackFrameURL.url()); + config->writeEntry("Filter Method", m_filterMethodCombo->currentItem()); + config->sync(); +} + +void ImageEffect_HotPixels::resetValues() +{ + m_filterMethodCombo->blockSignals(true); + m_filterMethodCombo->setCurrentItem(HotPixelFixer::QUADRATIC_INTERPOLATION); + m_filterMethodCombo->blockSignals(false); +} + +void ImageEffect_HotPixels::slotAddBlackFrame() +{ + KURL url = Digikam::ImageDialog::getImageURL(this, m_blackFrameURL, + i18n("Select Black Frame Image")); + + if (!url.isEmpty()) + { + // Load the selected file and insert into the list. + + m_blackFrameURL = url; + m_blackFrameListView->clear(); + BlackFrameListViewItem *item = new BlackFrameListViewItem(m_blackFrameListView, m_blackFrameURL); + + connect(item, TQ_SIGNAL(signalLoadingProgress(float)), + this, TQ_SLOT(slotLoadingProgress(float))); + + connect(item, TQ_SIGNAL(signalLoadingComplete()), + this, TQ_SLOT(slotLoadingComplete())); + } +} + +void ImageEffect_HotPixels::slotLoadingProgress(float v) +{ + m_progressBar->show(); + m_progressBar->setValue((int)(v*100)); +} + +void ImageEffect_HotPixels::slotLoadingComplete() +{ + m_progressBar->hide(); +} + +void ImageEffect_HotPixels::renderingFinished() +{ + m_filterMethodCombo->setEnabled(true); + m_blackFrameListView->setEnabled(true); + enableButton(Apply, true); +} + +void ImageEffect_HotPixels::prepareEffect() +{ + m_filterMethodCombo->setEnabled(false); + m_blackFrameListView->setEnabled(false); + enableButton(Apply, false); + + Digikam::DImg image = m_imagePreviewWidget->getOriginalRegionImage(); + int interpolationMethod = m_filterMethodCombo->currentItem(); + + TQValueList<HotPixel> hotPixelsRegion; + TQRect area = m_imagePreviewWidget->getOriginalImageRegionToRender(); + TQValueList<HotPixel>::Iterator end(m_hotPixelsList.end()); + + for (TQValueList<HotPixel>::Iterator it = m_hotPixelsList.begin() ; it != end ; ++it ) + { + HotPixel hp = (*it); + + if ( area.contains( hp.rect ) ) + { + hp.rect.moveTopLeft(TQPoint( hp.rect.x()-area.x(), hp.rect.y()-area.y() )); + hotPixelsRegion.append(hp); + } + } + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new HotPixelFixer(&image, this, hotPixelsRegion, interpolationMethod)); +} + +void ImageEffect_HotPixels::prepareFinal() +{ + m_filterMethodCombo->setEnabled(false); + m_blackFrameListView->setEnabled(false); + enableButton(Apply, false); + + int interpolationMethod = m_filterMethodCombo->currentItem(); + + Digikam::ImageIface iface(0, 0); + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new HotPixelFixer(iface.getOriginalImg(), this,m_hotPixelsList,interpolationMethod)); +} + +void ImageEffect_HotPixels::putPreviewData() +{ + m_imagePreviewWidget->setPreviewImage(m_threadedFilter->getTargetImage()); +} + +void ImageEffect_HotPixels::putFinalData() +{ + Digikam::ImageIface iface(0, 0); + iface.putOriginalImage(i18n("Hot Pixels Correction"), m_threadedFilter->getTargetImage().bits()); +} + +void ImageEffect_HotPixels::slotBlackFrame(TQValueList<HotPixel> hpList, const KURL& blackFrameURL) +{ + m_blackFrameURL = blackFrameURL; + m_hotPixelsList = hpList; + + TQPointArray pointList(m_hotPixelsList.size()); + TQValueList <HotPixel>::Iterator it; + int i = 0; + TQValueList <HotPixel>::Iterator end(m_hotPixelsList.end()); + + for (it = m_hotPixelsList.begin() ; it != end ; ++it, i++) + pointList.setPoint(i, (*it).rect.center()); + + m_imagePreviewWidget->setPanIconHighLightPoints(pointList); + + slotEffect(); +} + +} // NameSpace DigikamHotPixelsImagesPlugin diff --git a/src/imageplugins/hotpixels/imageeffect_hotpixels.h b/src/imageplugins/hotpixels/imageeffect_hotpixels.h new file mode 100644 index 00000000..4a8b0868 --- /dev/null +++ b/src/imageplugins/hotpixels/imageeffect_hotpixels.h @@ -0,0 +1,104 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-27 + * Description : a digiKam image plugin for fixing dots produced by + * hot/stuck/dead pixels from a CCD. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_HOTPIXELS_H +#define IMAGEEFFECT_HOTPIXELS_H + +#define MAX_PIXEL_DEPTH 4 + +// TQt includes. + +#include <tqvaluelist.h> + +// KDE includes. + +#include <kurl.h> + +// Digikam includes. + +#include "ctrlpaneldlg.h" + +// Local includes. + +#include "hotpixelfixer.h" + +class TQComboBox; +class TQPushButton; + +class KProgress; + +namespace DigikamHotPixelsImagesPlugin +{ + +class BlackFrameListView; + +class ImageEffect_HotPixels : public Digikam::CtrlPanelDlg +{ + TQ_OBJECT + + +public: + + ImageEffect_HotPixels(TQWidget *parent); + ~ImageEffect_HotPixels(); + +private slots: + + void slotLoadingProgress(float v); + void slotLoadingComplete(); + + void slotBlackFrame(TQValueList<HotPixel> hpList, const KURL& blackFrameURL); + void slotAddBlackFrame(); + void readUserSettings(); + +private: + + void writeUserSettings(); + void resetValues(); + void prepareEffect(); + void prepareFinal(); + void abortPreview(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + TQComboBox *m_filterMethodCombo; + + TQPushButton *m_blackFrameButton; + + TQValueList<HotPixel> m_hotPixelsList; + + KURL m_blackFrameURL; + + KProgress *m_progressBar; + + BlackFrameListView *m_blackFrameListView; +}; + +} // NameSpace DigikamHotPixelsImagesPlugin + +#endif /* IMAGEEFFECT_HOTPIXELS_H */ diff --git a/src/imageplugins/hotpixels/imageplugin_hotpixels.cpp b/src/imageplugins/hotpixels/imageplugin_hotpixels.cpp new file mode 100644 index 00000000..864b59dc --- /dev/null +++ b/src/imageplugins/hotpixels/imageplugin_hotpixels.cpp @@ -0,0 +1,72 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-27 + * Description : a digiKam image plugin for fixing dots produced by + * hot/stuck/dead pixels from a CCD. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * + * 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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> +#include <tdeapplication.h> + +// Local includes. + +#include "ddebug.h" +#include "hotpixelstool.h" +#include "imageplugin_hotpixels.h" +#include "imageplugin_hotpixels.moc" + +using namespace DigikamHotPixelsImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_hotpixels, + KGenericFactory<ImagePlugin_HotPixels>("digikamimageplugin_hotpixels")); + +ImagePlugin_HotPixels::ImagePlugin_HotPixels(TQObject *parent, const char*, const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_HotPixels") +{ + m_hotpixelsAction = new TDEAction(i18n("Hot Pixels..."), "hotpixels", 0, + this, TQ_SLOT(slotHotPixels()), + actionCollection(), "imageplugin_hotpixels"); + + setXMLFile("digikamimageplugin_hotpixels_ui.rc"); + + DDebug() << "ImagePlugin_HotPixels plugin loaded" << endl; +} + +ImagePlugin_HotPixels::~ImagePlugin_HotPixels() +{ +} + +void ImagePlugin_HotPixels::setEnabledActions(bool enable) +{ + m_hotpixelsAction->setEnabled(enable); +} + +void ImagePlugin_HotPixels::slotHotPixels() +{ + HotPixelsTool *tool = new HotPixelsTool(this); + loadTool(tool); +} diff --git a/src/imageplugins/hotpixels/imageplugin_hotpixels.h b/src/imageplugins/hotpixels/imageplugin_hotpixels.h new file mode 100644 index 00000000..c639b830 --- /dev/null +++ b/src/imageplugins/hotpixels/imageplugin_hotpixels.h @@ -0,0 +1,56 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-27 + * Description : a digiKam image plugin for fixing dots produced by + * hot/stuck/dead pixels from a CCD. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_HOTPIXELS_H +#define IMAGEPLUGIN_HOTPIXELS_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_HotPixels : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_HotPixels(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_HotPixels(); + + void setEnabledActions(bool enable); + +private slots: + + void slotHotPixels(); + +private: + + TDEAction *m_hotpixelsAction; +}; + +#endif /* IMAGEPLUGIN_HOTPIXELS_H */ diff --git a/src/imageplugins/hotpixels/weights.cpp b/src/imageplugins/hotpixels/weights.cpp new file mode 100644 index 00000000..e0d3f246 --- /dev/null +++ b/src/imageplugins/hotpixels/weights.cpp @@ -0,0 +1,283 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-27 + * Description : a class to calculate filter weights + * + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * + * 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 <cstring> + +// Local includes. + +#include "weights.h" + +namespace DigikamHotPixelsImagesPlugin +{ + +Weights::Weights(const Weights &w) +{ + (*this) = w; +} + +void Weights::operator=(const Weights &w) +{ + mHeight=w.height(); + mWidth=w.width(); + mPositions=(w.positions()); + mCoefficientNumber=w.coefficientNumber(); + mTwoDim=w.twoDim(); + mPolynomeOrder=w.polynomeOrder(); + + // Allocate memory and copy weights + // if the original one was calculated + + if (!w.weightMatrices()) return; + else + { + double*** origMatrices=w.weightMatrices(); + mWeightMatrices = new double**[mPositions.count()]; //allocate mPositions.count() matrices + + for (uint i=0; i<mPositions.count(); i++) + { + mWeightMatrices[i]=new double*[mHeight]; //allocate mHeight rows on each position + for (unsigned int j=0; j<mHeight; j++) + { + mWeightMatrices[i][j]=new double[mWidth]; //Allocate mWidth columns on each row + for (unsigned int k=0; k<mWidth; k++) + { + mWeightMatrices[i][j][k]=origMatrices[i][j][k]; + } + } + } + } +} + +void Weights::calculateWeights() +{ + mCoefficientNumber = (mTwoDim + ? ((size_t)mPolynomeOrder + 1) * ((size_t)mPolynomeOrder + 1) + : (size_t)mPolynomeOrder + 1); + double *matrix; /* num_coeff * num_coeff */ + double *vector0; /* mPositions.count() * num_coeff */ + double *vector1; /* mPositions.count() * num_coeff */ + size_t ix,iy,i,j; + int x, y; + + // Determine coordinates of pixels to be sampled + + if (mTwoDim) + { + + int iPolynomeOrder=(int) mPolynomeOrder; //lets avoid signed/unsigned comparison warnings + int iHeight = (int) height(); //" + int iWidth = (int) width(); //" + + for (y = -iPolynomeOrder; y < iHeight + iPolynomeOrder; ++y) + { + for (x = -iPolynomeOrder; x < iWidth + iPolynomeOrder; ++x) + { + if ((x < 0 && y < 0 && -x - y < iPolynomeOrder + 2) + || (x < 0 && y >= iHeight && -x + y - iHeight < iPolynomeOrder + 1) + || (x >= iWidth && y < 0 && x - y - iWidth < iPolynomeOrder + 1) + || (x >= iWidth && y >= iHeight && x + y - iWidth - iHeight < iPolynomeOrder) + || (x < 0 && y >= 0 && y < iHeight) || (x >= iWidth && y >= 0 && y < iHeight) + || (y < 0 && x >= 0 && x < iWidth ) || (y >= iHeight && x >= 0 && x < iWidth)) + { + TQPoint position(x,y); + mPositions.append(position); + } + } + } + } + else + { + // In the one-dimensional case, only the y coordinate and y size is used. */ + + for (y = -mPolynomeOrder; y < 0; ++y) + { + TQPoint position(0,y); + mPositions.append(position); + } + + for (y = (int) height(); y < (int) height() + (int) mPolynomeOrder; ++y) + { + TQPoint position(0,y); + mPositions.append(position); + } + } + + // Allocate memory. + + matrix = new double[mCoefficientNumber*mCoefficientNumber]; + vector0 = new double[mPositions.count() * mCoefficientNumber]; + vector1 = new double[mPositions.count() * mCoefficientNumber]; + + // Calculate coefficient matrix and vectors + + for (iy = 0; iy < mCoefficientNumber; ++iy) + { + for (ix = 0; ix < mCoefficientNumber; ++ix) + matrix [iy*mCoefficientNumber+ix] = 0.0; + + for (j = 0; j < mPositions.count(); ++j) + { + vector0 [iy * mPositions.count() + j] = polyTerm (iy, mPositions [j].x(), + mPositions [j].y(), mPolynomeOrder); + + for (ix = 0; ix < mCoefficientNumber; ++ix) + matrix [iy * mCoefficientNumber + ix] += (vector0 [iy * mPositions.count() + j] + * polyTerm (ix, mPositions [j].x(), mPositions[j].y(), mPolynomeOrder)); + } + } + + // Invert matrix. + + matrixInv (matrix, mCoefficientNumber); + + // Multiply inverse matrix with vector. + + for (iy = 0; iy < mCoefficientNumber; ++iy) + for (j = 0; j < mPositions.count(); ++j) + { + vector1 [iy * mPositions.count() + j] = 0.0; + + for (ix = 0; ix < mCoefficientNumber; ++ix) + vector1 [iy * mPositions.count() + j] += matrix [iy * mCoefficientNumber + ix] + * vector0 [ix * mPositions.count() + j]; + } + + // Store weights + + mWeightMatrices = new double**[mPositions.count()]; //allocate mPositions.count() matrices + + for (i=0; i<mPositions.count(); i++) + { + mWeightMatrices[i] = new double*[mHeight]; //allocate mHeight rows on each position + for (j=0; j<mHeight; j++) + mWeightMatrices[i][j] = new double[mWidth]; //Allocate mWidth columns on each row + } + + for (y = 0; y < (int) mHeight; ++y) + { + for (x = 0; x < (int) mWidth; ++x) + { + for (j = 0; j < mPositions.count(); ++j) + { + mWeightMatrices [j][y][x] = 0.0; + + for (iy = 0; iy < mCoefficientNumber; ++iy) + mWeightMatrices [j][y][x] += vector1 [iy * mPositions.count() + j] + * polyTerm (iy, x, y, mPolynomeOrder); + + mWeightMatrices [j][y][x] *= (double) mPositions.count(); + } + } + } + + delete[] vector1; + delete[] vector0; + delete[] matrix; +} + +bool Weights::operator==(const Weights& ws) const +{ + return (mHeight==ws.height() && + mWidth==ws.width() && + mPolynomeOrder==ws.polynomeOrder() && + mTwoDim==ws.twoDim() + ); +} + + //Invert a quadratic matrix. +void Weights::matrixInv (double *const a, const size_t size) +{ + double *const b = new double[size * size]; + size_t ix, iy, j; + + // Copy matrix to new location. + + memcpy (b, a, sizeof (double) * size * size); + + // Set destination matrix to unit matrix. + + for (iy = 0; iy < size; ++iy) + for (ix = 0; ix < size; ++ix) + a [iy * size + ix] = ix == iy ? 1.0 : 0.0; + + // Convert matrix to upper triangle form. + + for (iy = 0; iy < size - 1; ++iy) + { + for (j = iy + 1; j < size; ++j) + { + const double factor = b [j * size + iy] / b [iy * size + iy]; + + for (ix = 0; ix < size; ++ix) + { + b [j * size + ix] -= factor * b [iy * size + ix]; + a [j * size + ix] -= factor * a [iy * size + ix]; + } + } + } + + // Convert matrix to diagonal form. + + for (iy = size - 1; iy > 0; --iy) + { + for (j = 0; j < iy; ++j) + { + const double factor = b [j * size + iy] / b [iy * size + iy]; + + for (ix = 0; ix < size; ++ix) + a [j * size + ix] -= factor * a [iy * size + ix]; + } + } + + // Convert matrix to unit matrix. + + for (iy = 0; iy < size; ++iy) + for (ix = 0; ix < size; ++ix) + a [iy * size + ix] /= b [iy * size + iy]; + + delete [] b; +} + +// Calculates one term of the polynomial +double Weights::polyTerm (const size_t i_coeff, const int x, const int y, const int poly_order) +{ + const size_t x_power = i_coeff / ((size_t)poly_order + 1); + const size_t y_power = i_coeff % ((size_t)poly_order + 1); + int result; + size_t i; + + result = 1; + + for (i = 0; i < x_power; ++i) + result *= x; + + for (i = 0; i < y_power; ++i) + result *= y; + + return (double)result; +} + +} // NameSpace DigikamHotPixelsImagesPlugin + diff --git a/src/imageplugins/hotpixels/weights.h b/src/imageplugins/hotpixels/weights.h new file mode 100644 index 00000000..b82fde89 --- /dev/null +++ b/src/imageplugins/hotpixels/weights.h @@ -0,0 +1,90 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-27 + * Description : a class to calculate filter weights + * + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * + * 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. + * + * ============================================================ */ + +#ifndef WEIGHTS_H +#define WEIGHTS_H + +// TQt includes. + +#include <tqrect.h> +#include <tqvaluelist.h> + +namespace DigikamHotPixelsImagesPlugin +{ + +class Weights +{ +public: + + Weights(){}; + Weights(const Weights &w); + void operator=(const Weights &w); + + ~Weights() + { + if (!mWeightMatrices) return; + for (unsigned int i=0; i<mPositions.count(); i++) + { + for (unsigned int j=0; j<mHeight; j++) delete[] mWeightMatrices[i][j]; + } + } + + unsigned int height() const { return mHeight; }; + unsigned int polynomeOrder() const { return mPolynomeOrder; }; + bool twoDim() const { return mTwoDim; }; + unsigned int width() const { return mWidth; }; + + void setHeight(int h) { mHeight=h; }; + void setPolynomeOrder(int order) { mPolynomeOrder=order; }; + void setTwoDim(bool td) { mTwoDim=td; }; + void setWidth(int w) { mWidth=w; }; + + void calculateWeights(); + bool operator==(const Weights& ws) const; + double** operator[](int n) const { return mWeightMatrices[n]; }; + const TQValueList <TQPoint> positions() const { return mPositions; }; + +protected: + + int coefficientNumber() const { return mCoefficientNumber; }; + + double*** weightMatrices() const { return mWeightMatrices; }; + +private: + + double polyTerm (const size_t i_coeff, const int x, const int y, const int poly_order); + void matrixInv (double *const a, const size_t size); + +private: + + unsigned int mHeight,mWidth; + unsigned int mCoefficientNumber; + bool mTwoDim; + unsigned int mPolynomeOrder; + double *** mWeightMatrices; //Stores a list of weight matrices + TQValueList <TQPoint> mPositions; +}; + +} // NameSpace DigikamHotPixelsImagesPlugin + +#endif // WEIGHTS_H diff --git a/src/imageplugins/infrared/Makefile.am b/src/imageplugins/infrared/Makefile.am new file mode 100644 index 00000000..1e9cd294 --- /dev/null +++ b/src/imageplugins/infrared/Makefile.am @@ -0,0 +1,34 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_infrared_la_SOURCES = imageplugin_infrared.cpp \ + infraredtool.cpp infrared.cpp + +digikamimageplugin_infrared_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_infrared_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_infrared.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_infrared.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_infrared_ui.rc + diff --git a/src/imageplugins/infrared/digikamimageplugin_infrared.desktop b/src/imageplugins/infrared/digikamimageplugin_infrared.desktop new file mode 100644 index 00000000..716de474 --- /dev/null +++ b/src/imageplugins/infrared/digikamimageplugin_infrared.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Name=ImagePlugin_Infrared +Name[bg]=Приставка за снимки - Инфрачервен филм +Name[da]=Plugin for infrarødt +Name[el]=ΠρόσθετοΕικόνας_Υπέρυθρο +Name[fi]=Infrapuna +Name[hr]=Infracrveno +Name[it]=PluginImmagini_Infrarosso +Name[ms]=ImagePlugin_Inframerah +Name[nl]=Afbeeldingsplugin_Infrarood +Name[sr]=Инфрацрвено +Name[sr@Latn]=Infracrveno +Name[sv]=Insticksprogram för infrarött +Name[tr]=ResimEklentisi_Kızılötesi +Name[xx]=xxImagePlugin_Infraredxx + +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=Simulate infrared film plugin for digiKam +Comment[bg]=Приставка на digiKam за наподобяване на снимка с инфрачервен филм +Comment[ca]=Connector pel digiKam de simulació de pel·lícula d'infraroigs +Comment[da]=Digikam plugin til at simulere infrarød film +Comment[de]=digiKam-Modul für die Simulation eines Infrarot-Filmes +Comment[el]=Πρόσθετο εξομοίωσης υπέρυθρου φιλμ για το digiKam +Comment[es]=Plugin para digiKam para simular la película infrarroja +Comment[et]=DigiKami infrapunafilmi matkimise plugin +Comment[fa]=شبیهسازی وصلۀ فیلم مادون قرمز برای digiKam +Comment[fi]=Jäljittelee infrapunafilmiä +Comment[gl]=Un plugin de digiKam para simulazón de infravermellos +Comment[hr]=digiKam dodatak za oponašanje IC filma +Comment[is]=Íforrit fyrir digiKam sem líkir eftir innrauðri filmu +Comment[it]=Plugin di simulazione di pellicola infrarossa per digiKam +Comment[ja]=digiKam 赤外線フィルム効果プラグイン +Comment[nds]=digiKam-Moduul för't Simuleren vun Infraroot-Filmen +Comment[nl]=Digikam-plugin voor infraroodfilm-effect +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਸਿਮੂਲੇਸ਼ਨ ਇੰਫਰਾਰੈੱਡ ਫਿਲਮ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam symulująca efekt podczerwonej kliszy +Comment[pt]=Um 'plugin' do digiKam para simulação de infravermelhos +Comment[pt_BR]=Um 'plugin' do digiKam para simulação de infravermelhos +Comment[ru]=Модуль имитирующий инфракрасное фильм для digiKam +Comment[sk]=digiKam plugin pre napodobenie infračerveného filmu +Comment[sr]=digiKam-ов прикључак који симулира инфрацрвени филм +Comment[sr@Latn]=digiKam-ov priključak koji simulira infracrveni film +Comment[sv]=Digikam insticksprogram för att simulera infraröd film +Comment[tr]=digiKam için kızılötesi film benzetme eklentisi +Comment[uk]=Втулок симуляції інфрачервоного фільму для digiKam +Comment[vi]=Phần bổ sung mô phỏng phim ảnh hồng ngoại cho digiKam +Comment[xx]=xxSimulate infrared film plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_infrared +author=Gilles Caulier, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/infrared/digikamimageplugin_infrared_ui.rc b/src/imageplugins/infrared/digikamimageplugin_infrared_ui.rc new file mode 100644 index 00000000..1df83fa6 --- /dev/null +++ b/src/imageplugins/infrared/digikamimageplugin_infrared_ui.rc @@ -0,0 +1,19 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="5" name="digikamimageplugin_infrared" > + <MenuBar> + + <Menu name="Filters" ><text>F&ilters</text> + <Action name="imageplugin_infrared" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action shortcut="" name="imageplugin_infrared" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/infrared/imageeffect_infrared.cpp b/src/imageplugins/infrared/imageeffect_infrared.cpp new file mode 100644 index 00000000..f8069255 --- /dev/null +++ b/src/imageplugins/infrared/imageeffect_infrared.cpp @@ -0,0 +1,227 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-22 + * Description : a digiKam image editor plugin for simulate + * infrared film. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <tqimage.h> +#include <tqlabel.h> +#include <tqwhatsthis.h> +#include <tqlcdnumber.h> +#include <tqslider.h> +#include <tqlayout.h> +#include <tqdatetime.h> +#include <tqcheckbox.h> + +// KDE includes. + +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <kstandarddirs.h> +#include <tdeconfig.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "infrared.h" +#include "imageeffect_infrared.h" +#include "imageeffect_infrared.moc" + +namespace DigikamInfraredImagesPlugin +{ + +ImageEffect_Infrared::ImageEffect_Infrared(TQWidget* parent) + : Digikam::CtrlPanelDlg(parent, i18n("Simulate Infrared Film to Photograph"), + "infrared", false, false, true, + Digikam::ImagePannelWidget::SeparateViewAll) +{ + TQString whatsThis; + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Infrared Film"), + digikam_version, + I18N_NOOP("A digiKam image plugin to simulate infrared film."), + TDEAboutData::License_GPL, + "(c) 2005, Gilles Caulier\n" + "(c) 2006-2008, Gilles Caulier and Marcel Wiesweg", + 0, + "http://www.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + about->addAuthor("Marcel Wiesweg", I18N_NOOP("Developer"), + "marcel dot wiesweg at gmx dot de"); + + setAboutData(about); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(m_imagePreviewWidget); + TQGridLayout* gridSettings = new TQGridLayout( gboxSettings, 2, 1, 0, spacingHint()); + TQLabel *label1 = new TQLabel(i18n("Sensitivity (ISO):"), gboxSettings); + + m_sensibilitySlider = new TQSlider(1, 25, 1, 1, TQt::Horizontal, gboxSettings); + m_sensibilitySlider->setTracking ( false ); + m_sensibilitySlider->setTickInterval(1); + m_sensibilitySlider->setTickmarks(TQSlider::Below); + + m_sensibilityLCDValue = new TQLCDNumber (4, gboxSettings); + m_sensibilityLCDValue->setSegmentStyle ( TQLCDNumber::Flat ); + m_sensibilityLCDValue->display( TQString::number(200) ); + whatsThis = i18n("<p>Set here the ISO-sensitivity of the simulated infrared film. " + "Increasing this value will increase the proportion of green color in the mix. " + "It will also increase the halo effect on the hightlights, and the film " + "graininess (if that box is checked).</p>" + "<p>Note: to simulate an <b>Ilford SFX200</b> infrared film, use a sensitivity excursion of 200 to 800. " + "A sensitivity over 800 simulates <b>Kodak HIE</b> high-speed infrared film. This last one creates a more " + "dramatic photographic style.</p>"); + + TQWhatsThis::add( m_sensibilityLCDValue, whatsThis); + TQWhatsThis::add( m_sensibilitySlider, whatsThis); + + gridSettings->addMultiCellWidget(label1, 0, 0, 0, 1); + gridSettings->addMultiCellWidget(m_sensibilitySlider, 1, 1, 0, 0); + gridSettings->addMultiCellWidget(m_sensibilityLCDValue, 1, 1, 1, 1); + + // ------------------------------------------------------------- + + m_addFilmGrain = new TQCheckBox( i18n("Add film grain"), gboxSettings); + m_addFilmGrain->setChecked( true ); + TQWhatsThis::add( m_addFilmGrain, i18n("<p>This option adds infrared film grain to " + "the image depending on ISO-sensitivity.")); + gridSettings->addMultiCellWidget(m_addFilmGrain, 2, 2, 0, 1); + + m_imagePreviewWidget->setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + connect( m_sensibilitySlider, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer()) ); + + // this connection is necessary to change the LCD display when + // the value is changed by single clicking on the slider + connect( m_sensibilitySlider, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotSliderMoved(int)) ); + + connect( m_sensibilitySlider, TQ_SIGNAL(sliderMoved(int)), + this, TQ_SLOT(slotSliderMoved(int)) ); + + connect( m_addFilmGrain, TQ_SIGNAL(toggled (bool)), + this, TQ_SLOT(slotEffect()) ); +} + +ImageEffect_Infrared::~ImageEffect_Infrared() +{ +} + +void ImageEffect_Infrared::renderingFinished() +{ + m_sensibilitySlider->setEnabled(true); + m_addFilmGrain->setEnabled(true); +} + +void ImageEffect_Infrared::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("infrared Tool Dialog"); + m_sensibilitySlider->blockSignals(true); + m_addFilmGrain->blockSignals(true); + m_sensibilitySlider->setValue(config->readNumEntry("SensitivityAjustment", 1)); + m_addFilmGrain->setChecked(config->readBoolEntry("AddFilmGrain", false)); + m_sensibilitySlider->blockSignals(false); + m_addFilmGrain->blockSignals(false); + slotSliderMoved(m_sensibilitySlider->value()); +} + +void ImageEffect_Infrared::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("infrared Tool Dialog"); + config->writeEntry("SensitivityAjustment", m_sensibilitySlider->value()); + config->writeEntry("AddFilmGrain", m_addFilmGrain->isChecked()); + config->sync(); +} + +void ImageEffect_Infrared::resetValues() +{ + m_sensibilitySlider->blockSignals(true); + m_addFilmGrain->blockSignals(true); + m_sensibilitySlider->setValue(1); + m_addFilmGrain->setChecked(false); + m_sensibilitySlider->blockSignals(false); + m_addFilmGrain->blockSignals(false); +} + +void ImageEffect_Infrared::slotSliderMoved(int v) +{ + m_sensibilityLCDValue->display( TQString::number(100 + 100 * v) ); +} + +void ImageEffect_Infrared::prepareEffect() +{ + m_addFilmGrain->setEnabled(false); + m_sensibilitySlider->setEnabled(false); + + Digikam::DImg image = m_imagePreviewWidget->getOriginalRegionImage(); + int s = 100 + 100 * m_sensibilitySlider->value(); + bool g = m_addFilmGrain->isChecked(); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new Infrared(&image, this, s, g)); +} + +void ImageEffect_Infrared::prepareFinal() +{ + m_addFilmGrain->setEnabled(false); + m_sensibilitySlider->setEnabled(false); + + int s = 100 + 100 * m_sensibilitySlider->value(); + bool g = m_addFilmGrain->isChecked(); + + Digikam::ImageIface iface(0, 0); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new Infrared(iface.getOriginalImg(), this, s, g)); +} + +void ImageEffect_Infrared::putPreviewData(void) +{ + m_imagePreviewWidget->setPreviewImage(m_threadedFilter->getTargetImage()); +} + +void ImageEffect_Infrared::putFinalData(void) +{ + Digikam::ImageIface iface(0, 0); + iface.putOriginalImage(i18n("Infrared"), m_threadedFilter->getTargetImage().bits()); +} + +} // NameSpace DigikamInfraredImagesPlugin + diff --git a/src/imageplugins/infrared/imageeffect_infrared.h b/src/imageplugins/infrared/imageeffect_infrared.h new file mode 100644 index 00000000..d6c28237 --- /dev/null +++ b/src/imageplugins/infrared/imageeffect_infrared.h @@ -0,0 +1,76 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-22 + * Description : a digiKam image editor plugin for simulate + * infrared film. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_INFRARED_H +#define IMAGEEFFECT_INFRARED_H + +// Digikam includes. + +#include "ctrlpaneldlg.h" + +class TQSlider; +class TQLCDNumber; +class TQCheckBox; + +namespace DigikamInfraredImagesPlugin +{ + +class ImageEffect_Infrared : public Digikam::CtrlPanelDlg +{ + TQ_OBJECT + + +public: + + ImageEffect_Infrared(TQWidget* parent); + ~ImageEffect_Infrared(); + +private slots: + + void slotSliderMoved(int); + void readUserSettings(); + +private: + + void writeUserSettings(); + void resetValues(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + TQCheckBox *m_addFilmGrain; + + TQSlider *m_sensibilitySlider; + + TQLCDNumber *m_sensibilityLCDValue; +}; + +} // NameSpace DigikamInfraredImagesPlugin + +#endif /* IMAGEEFFECT_INFRARED_H */ diff --git a/src/imageplugins/infrared/imageplugin_infrared.cpp b/src/imageplugins/infrared/imageplugin_infrared.cpp new file mode 100644 index 00000000..4b845908 --- /dev/null +++ b/src/imageplugins/infrared/imageplugin_infrared.cpp @@ -0,0 +1,71 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-22 + * Description : a digiKam image editor plugin for simulate + * infrared film. + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> +#include <tdeapplication.h> + +// Local includes. + +#include "ddebug.h" +#include "infraredtool.h" +#include "imageplugin_infrared.h" +#include "imageplugin_infrared.moc" + +using namespace DigikamInfraredImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_infrared, + KGenericFactory<ImagePlugin_Infrared>("digikamimageplugin_infrared")); + +ImagePlugin_Infrared::ImagePlugin_Infrared(TQObject *parent, const char*, const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_Infrared") +{ + m_infraredAction = new TDEAction(i18n("Infrared Film..."), "infrared", 0, + this, TQ_SLOT(slotInfrared()), + actionCollection(), "imageplugin_infrared"); + + setXMLFile( "digikamimageplugin_infrared_ui.rc" ); + + DDebug() << "ImagePlugin_Infrared plugin loaded" << endl; +} + +ImagePlugin_Infrared::~ImagePlugin_Infrared() +{ +} + +void ImagePlugin_Infrared::setEnabledActions(bool enable) +{ + m_infraredAction->setEnabled(enable); +} + +void ImagePlugin_Infrared::slotInfrared() +{ + InfraredTool *tool = new InfraredTool(this); + loadTool(tool); +} diff --git a/src/imageplugins/infrared/imageplugin_infrared.h b/src/imageplugins/infrared/imageplugin_infrared.h new file mode 100644 index 00000000..7b6fa12a --- /dev/null +++ b/src/imageplugins/infrared/imageplugin_infrared.h @@ -0,0 +1,57 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-22 + * Description : a digiKam image editor plugin for simulate + * infrared film. + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_INFRARED_H +#define IMAGEPLUGIN_INFRARED_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_Infrared : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_Infrared(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_Infrared(); + + void setEnabledActions(bool enable); + +private slots: + + void slotInfrared(); + +private: + + TDEAction *m_infraredAction; +}; + +#endif /* IMAGEPLUGIN_INFRARED_H */ diff --git a/src/imageplugins/infrared/infrared.cpp b/src/imageplugins/infrared/infrared.cpp new file mode 100644 index 00000000..fa2983d5 --- /dev/null +++ b/src/imageplugins/infrared/infrared.cpp @@ -0,0 +1,367 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : Infrared threaded image filter. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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> +#include <cstdlib> + +// TQt includes. + +#include <tqdatetime.h> + +// Local includes. + +#include "ddebug.h" +#include "dimg.h" +#include "dimggaussianblur.h" +#include "imagecurves.h" +#include "imagehistogram.h" +#include "dimgimagefilters.h" +#include "infrared.h" + +namespace DigikamInfraredImagesPlugin +{ + +Infrared::Infrared(Digikam::DImg *orgImage, TQObject *parent, int sensibility, bool grain) + : Digikam::DImgThreadedFilter(orgImage, parent, "Infrared") +{ + m_sensibility = sensibility; + m_grain = grain; + initFilter(); +} + +void Infrared::filterImage(void) +{ + infraredImage(&m_orgImage, m_sensibility, m_grain); +} + +// This method is based on the Simulate Infrared Film tutorial from GimpGuru.org web site +// available at this url : http://www.gimpguru.org/Tutorials/SimulatedInfrared/ + +inline static int intMult8(uint a, uint b) +{ + uint t = a * b + 0x80; + return ((t >> 8) + t) >> 8; +} + +inline static int intMult16(uint a, uint b) +{ + uint t = a * b + 0x8000; + return ((t >> 16) + t) >> 16; +} + +/* More info about IR film can be seen at this url : + +http://www.pauck.de/marco/photo/infrared/comparison_of_films/comparison_of_films.html +*/ + +void Infrared::infraredImage(Digikam::DImg *orgImage, int Sensibility, bool Grain) +{ + // Sensibility: 200..2600 + + if (Sensibility <= 0) return; + + int Width = orgImage->width(); + int Height = orgImage->height(); + int bytesDepth = orgImage->bytesDepth(); + uint numBytes = orgImage->numBytes(); + bool sixteenBit = orgImage->sixteenBit(); + uchar* data = orgImage->bits(); + + // Infrared film variables depending on Sensibility. + // We can reproduce famous Ilford SFX200 infrared film + // http://www.ilford.com/html/us_english/prod_html/sfx200/sfx200.html + // This film have a sensibility escursion from 200 to 800 ISO. + // Over 800 ISO, we reproduce The Kodak HIE hight speed infrared film. + + // Infrared film grain. + int Noise = (Sensibility + 3000) / 10; + if (sixteenBit) + Noise = (Noise + 1) * 256 - 1; + + int blurRadius = (int)((Sensibility / 200.0) + 1.0); // Gaussian blur infrared hightlight effect + // [2 to 5]. + float greenBoost = 2.1 - (Sensibility / 2000.0); // Infrared green color boost [1.7 to 2.0]. + + int nRand, offset, progress; + + uchar* pBWBits = 0; // Black and White conversion. + uchar* pBWBlurBits = 0; // Black and White with blur. + uchar* pGrainBits = 0; // Grain blured without curves adjustment. + uchar* pMaskBits = 0; // Grain mask with curves adjustment. + uchar* pOverlayBits = 0; // Overlay to merge with original converted in gray scale. + uchar* pOutBits = m_destImage.bits(); // Destination image with merged grain mask and original. + + Digikam::DColor bwData, bwBlurData, grainData, maskData, overData, outData; + + //------------------------------------------ + // 1 - Create GrayScale green boosted image. + //------------------------------------------ + + // Convert to gray scale with boosting Green channel. + // Infrared film increase green color. + + Digikam::DImg BWImage(Width, Height, sixteenBit); // Black and White conversion. + pBWBits = BWImage.bits(); + memcpy (pBWBits, data, numBytes); + + Digikam::DImgImageFilters().channelMixerImage(pBWBits, Width, Height, sixteenBit, // Image data. + true, // Preserve luminosity. + true, // Monochrome. + 0.4, greenBoost, -0.8, // Red channel gains. + 0.0, 1.0, 0.0, // Green channel gains (not used). + 0.0, 0.0, 1.0); // Blue channel gains (not used). + postProgress( 10 ); + if (m_cancel) + { + return; + } + + // Apply a Gaussian blur to the black and white image. + // This way simulate Infrared film dispersion for the highlights. + + Digikam::DImg BWBlurImage(Width, Height, sixteenBit); + pBWBlurBits = BWBlurImage.bits(); + + Digikam::DImgGaussianBlur(this, BWImage, BWBlurImage, 10, 20, blurRadius); + + if (m_cancel) + { + return; + } + + //----------------------------------------------------------------- + // 2 - Create Gaussian blured averlay mask with grain if necessary. + //----------------------------------------------------------------- + + + if (Grain) + { + + // Create gray grain mask. + + TQDateTime dt = TQDateTime::currentDateTime(); + TQDateTime Y2000( TQDate(2000, 1, 1), TQTime(0, 0, 0) ); + uint seed = ((uint) dt.secsTo(Y2000)); + + pGrainBits = new uchar[numBytes]; // Grain blured without curves adjustment. + uchar *ptr; + int component; + grainData.setSixteenBit(sixteenBit); + + for (int x = 0; !m_cancel && x < Width; x++) + { + for (int y = 0; !m_cancel && y < Height; y++) + { + ptr = pGrainBits + x*bytesDepth + (y*Width*bytesDepth); + + nRand = (rand_r(&seed) % Noise) - (Noise / 2); + if (sixteenBit) + component = CLAMP(32768 + nRand, 0, 65535); + else + component = CLAMP(128 + nRand, 0, 255); + + grainData.setRed (component); + grainData.setGreen(component); + grainData.setBlue (component); + grainData.setAlpha(0); + + grainData.setPixel(ptr); + } + + // Update progress bar in dialog. + progress = (int) (30.0 + ((double)x * 10.0) / Width); + + if (progress%5 == 0) + postProgress( progress ); + } + + // Smooth grain mask using gaussian blur. + + Digikam::DImgImageFilters().gaussianBlurImage(pGrainBits, Width, Height, sixteenBit, 1); + + postProgress( 40 ); + if (m_cancel) + { + delete [] pGrainBits; + return; + } + } + + postProgress( 50 ); + if (m_cancel) + { + delete [] pGrainBits; + return; + } + + // Normally, film grain tends to be most noticeable in the midtones, and much less + // so in the shadows and highlights. Adjust histogram curve to adjust grain like this. + + if (Grain) + { + Digikam::ImageCurves *grainCurves = new Digikam::ImageCurves(sixteenBit); + pMaskBits = new uchar[numBytes]; // Grain mask with curves adjustment. + + // We modify only global luminosity of the grain. + if (sixteenBit) + { + grainCurves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, 0, TQPoint(0, 0)); + grainCurves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, 8, TQPoint(32768, 32768)); + grainCurves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, 16, TQPoint(65535, 0)); + } + else + { + grainCurves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, 0, TQPoint(0, 0)); + grainCurves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, 8, TQPoint(128, 128)); + grainCurves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, 16, TQPoint(255, 0)); + } + + // Calculate curves and lut to apply on grain. + grainCurves->curvesCalculateCurve(Digikam::ImageHistogram::ValueChannel); + grainCurves->curvesLutSetup(Digikam::ImageHistogram::AlphaChannel); + grainCurves->curvesLutProcess(pGrainBits, pMaskBits, Width, Height); + delete grainCurves; + + // delete it here, not used any more + delete [] pGrainBits; + pGrainBits = 0; + } + + postProgress( 60 ); + if (m_cancel) + { + delete [] pGrainBits; + delete [] pMaskBits; + return; + } + + // Merge gray scale image with grain using shade coefficient. + + if (Grain) + { + pOverlayBits = new uchar[numBytes]; // Overlay to merge with original converted in gray scale. + + // get composer for default blending + Digikam::DColorComposer *composer = Digikam::DColorComposer::getComposer(Digikam::DColorComposer::PorterDuffNone); + int alpha; + + int Shade = 52; // This value control the shading pixel effect between original image and grain mask. + if (sixteenBit) + Shade = (Shade + 1) * 256 - 1; + + for (int x = 0; !m_cancel && x < Width; x++) + { + for (int y = 0; !m_cancel && y < Height; y++) + { + int offset = x*bytesDepth + (y*Width*bytesDepth); + + // read color from orig image + bwBlurData.setColor(pBWBlurBits + offset, sixteenBit); + // read color from mask + maskData.setColor(pMaskBits + offset, sixteenBit); + // set shade as alpha value - it will be used as source alpha when blending + maskData.setAlpha(Shade); + + // compose, write result to blendData. + // Preserve alpha, do not blend it (taken from old algorithm - correct?) + alpha = bwBlurData.alpha(); + composer->compose(bwBlurData, maskData); + bwBlurData.setAlpha(alpha); + + // write to destination + bwBlurData.setPixel(pOverlayBits + offset); + } + + // Update progress bar in dialog. + progress = (int) (70.0 + ((double)x * 10.0) / Width); + + if (progress%5 == 0) + postProgress( progress ); + } + + delete composer; + + // delete it here, not used any more + BWBlurImage.reset(); + delete [] pMaskBits; + pMaskBits = 0; + } + else + { + // save a memcpy + pOverlayBits = pBWBlurBits; + pBWBlurBits = 0; + } + + //------------------------------------------ + // 3 - Merge Grayscale image & overlay mask. + //------------------------------------------ + + // Merge overlay and gray scale image using 'Overlay' Gimp method for increase the highlight. + // The result is usually a brighter picture. + // Overlay mode composite value computation is D = A * (B + (2 * B) * (255 - A)). + + outData.setSixteenBit(sixteenBit); + for (int x = 0; !m_cancel && x < Width; x++) + { + for (int y = 0; !m_cancel && y < Height; y++) + { + offset = x*bytesDepth + (y*Width*bytesDepth); + + bwData.setColor (pBWBits + offset, sixteenBit); + overData.setColor(pOverlayBits + offset, sixteenBit); + + if (sixteenBit) + { + outData.setRed ( intMult16 (bwData.red(), bwData.red() + intMult16(2 * overData.red(), 65535 - bwData.red()) ) ); + outData.setGreen( intMult16 (bwData.green(), bwData.green() + intMult16(2 * overData.green(), 65535 - bwData.green()) ) ); + outData.setBlue ( intMult16 (bwData.blue(), bwData.blue() + intMult16(2 * overData.blue(), 65535 - bwData.blue()) ) ); + } + else + { + outData.setRed ( intMult8 (bwData.red(), bwData.red() + intMult8(2 * overData.red(), 255 - bwData.red()) ) ); + outData.setGreen( intMult8 (bwData.green(), bwData.green() + intMult8(2 * overData.green(), 255 - bwData.green()) ) ); + outData.setBlue ( intMult8 (bwData.blue(), bwData.blue() + intMult8(2 * overData.blue(), 255 - bwData.blue()) ) ); + } + outData.setAlpha( bwData.alpha() ); + outData.setPixel( pOutBits + offset ); + } + + // Update progress bar in dialog. + progress = (int) (80.0 + ((double)x * 20.0) / Width); + + if (progress%5 == 0) + postProgress(progress); + } + + delete [] pGrainBits; + delete [] pMaskBits; + + if (Grain) + delete [] pOverlayBits; +} + +} // NameSpace DigikamInfraredImagesPlugin diff --git a/src/imageplugins/infrared/infrared.h b/src/imageplugins/infrared/infrared.h new file mode 100644 index 00000000..fc2f89ee --- /dev/null +++ b/src/imageplugins/infrared/infrared.h @@ -0,0 +1,60 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : Infrared threaded image filter. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef INFRARED_H +#define INFRARED_H + +// Digikam includes. + +#include "dimgthreadedfilter.h" + +namespace DigikamInfraredImagesPlugin +{ + +class Infrared : public Digikam::DImgThreadedFilter +{ + +public: + + Infrared(Digikam::DImg *orgImage, TQObject *parent=0, int sensibility=1, bool grain=true); + + ~Infrared(){}; + +private: // Infrared filter data. + + bool m_grain; + + int m_sensibility; + +private: // Infrared filter methods. + + virtual void filterImage(void); + + void infraredImage(Digikam::DImg *orgImage, int Sensibility, bool Grain); + +}; + +} // NameSpace DigikamInfraredImagesPlugin + +#endif /* INFRARED_H */ diff --git a/src/imageplugins/infrared/infraredtool.cpp b/src/imageplugins/infrared/infraredtool.cpp new file mode 100644 index 00000000..f34d1c8a --- /dev/null +++ b/src/imageplugins/infrared/infraredtool.cpp @@ -0,0 +1,225 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-22 + * Description : a digiKam image editor plugin for simulate + * infrared film. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <tqimage.h> +#include <tqlabel.h> +#include <tqwhatsthis.h> +#include <tqlcdnumber.h> +#include <tqslider.h> +#include <tqlayout.h> +#include <tqdatetime.h> +#include <tqcheckbox.h> + +// KDE includes. + +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <kstandarddirs.h> +#include <tdeconfig.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "imagepanelwidget.h" +#include "editortoolsettings.h" +#include "infrared.h" +#include "infraredtool.h" +#include "infraredtool.moc" + +using namespace Digikam; + +namespace DigikamInfraredImagesPlugin +{ + +InfraredTool::InfraredTool(TQObject* parent) + : EditorToolThreaded(parent) +{ + setName("infrared"); + setToolName(i18n("Infrared")); + setToolIcon(SmallIcon("infrared")); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel| + EditorToolSettings::Try, + EditorToolSettings::PanIcon); + + TQGridLayout* grid = new TQGridLayout(m_gboxSettings->plainPage(), 3, 1); + TQLabel *label1 = new TQLabel(i18n("Sensitivity (ISO):"), m_gboxSettings->plainPage()); + + m_sensibilitySlider = new TQSlider(1, 25, 1, 1, TQt::Horizontal, m_gboxSettings->plainPage()); + m_sensibilitySlider->setTracking(false); + m_sensibilitySlider->setTickInterval(1); + m_sensibilitySlider->setTickmarks(TQSlider::Below); + + m_sensibilityLCDValue = new TQLCDNumber(4, m_gboxSettings->plainPage()); + m_sensibilityLCDValue->setSegmentStyle(TQLCDNumber::Flat); + m_sensibilityLCDValue->display(TQString::number(200)); + TQString whatsThis = i18n("<p>Set here the ISO-sensitivity of the simulated infrared film. " + "Increasing this value will increase the proportion of green color in the mix. " + "It will also increase the halo effect on the hightlights, and the film " + "graininess (if that box is checked).</p>" + "<p>Note: to simulate an <b>Ilford SFX200</b> infrared film, use a sensitivity excursion of 200 to 800. " + "A sensitivity over 800 simulates <b>Kodak HIE</b> high-speed infrared film. This last one creates a more " + "dramatic photographic style.</p>"); + + TQWhatsThis::add(m_sensibilityLCDValue, whatsThis); + TQWhatsThis::add(m_sensibilitySlider, whatsThis); + + // ------------------------------------------------------------- + + m_addFilmGrain = new TQCheckBox(i18n("Add film grain"), m_gboxSettings->plainPage()); + m_addFilmGrain->setChecked(true); + TQWhatsThis::add( m_addFilmGrain, i18n("<p>This option adds infrared film grain to " + "the image depending on ISO-sensitivity.")); + + grid->addMultiCellWidget(label1, 0, 0, 0, 1); + grid->addMultiCellWidget(m_sensibilitySlider, 1, 1, 0, 0); + grid->addMultiCellWidget(m_sensibilityLCDValue, 1, 1, 1, 1); + grid->addMultiCellWidget(m_addFilmGrain, 2, 2, 0, 1); + grid->setRowStretch(3, 10); + grid->setMargin(m_gboxSettings->spacingHint()); + grid->setSpacing(m_gboxSettings->spacingHint()); + + setToolSettings(m_gboxSettings); + + // ------------------------------------------------------------- + + m_previewWidget = new ImagePanelWidget(470, 350, "infrared Tool", m_gboxSettings->panIconView()); + + setToolView(m_previewWidget); + init(); + + // ------------------------------------------------------------- + + connect( m_sensibilitySlider, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer()) ); + + // this connection is necessary to change the LCD display when + // the value is changed by single clicking on the slider + connect( m_sensibilitySlider, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotSliderMoved(int)) ); + + connect( m_sensibilitySlider, TQ_SIGNAL(sliderMoved(int)), + this, TQ_SLOT(slotSliderMoved(int)) ); + + connect( m_addFilmGrain, TQ_SIGNAL(toggled (bool)), + this, TQ_SLOT(slotEffect()) ); +} + +InfraredTool::~InfraredTool() +{ +} + +void InfraredTool::renderingFinished() +{ + m_sensibilitySlider->setEnabled(true); + m_addFilmGrain->setEnabled(true); +} + +void InfraredTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("infrared Tool"); + m_sensibilitySlider->blockSignals(true); + m_addFilmGrain->blockSignals(true); + m_sensibilitySlider->setValue(config->readNumEntry("SensitivityAjustment", 1)); + m_addFilmGrain->setChecked(config->readBoolEntry("AddFilmGrain", false)); + m_sensibilitySlider->blockSignals(false); + m_addFilmGrain->blockSignals(false); + slotSliderMoved(m_sensibilitySlider->value()); +} + +void InfraredTool::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("infrared Tool"); + config->writeEntry("SensitivityAjustment", m_sensibilitySlider->value()); + config->writeEntry("AddFilmGrain", m_addFilmGrain->isChecked()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void InfraredTool::slotResetSettings() +{ + m_sensibilitySlider->blockSignals(true); + m_addFilmGrain->blockSignals(true); + m_sensibilitySlider->setValue(1); + m_addFilmGrain->setChecked(false); + m_sensibilitySlider->blockSignals(false); + m_addFilmGrain->blockSignals(false); +} + +void InfraredTool::slotSliderMoved(int v) +{ + m_sensibilityLCDValue->display( TQString::number(100 + 100 * v) ); +} + +void InfraredTool::prepareEffect() +{ + m_addFilmGrain->setEnabled(false); + m_sensibilitySlider->setEnabled(false); + + DImg image = m_previewWidget->getOriginalRegionImage(); + int s = 100 + 100 * m_sensibilitySlider->value(); + bool g = m_addFilmGrain->isChecked(); + + setFilter(dynamic_cast<DImgThreadedFilter*>(new Infrared(&image, this, s, g))); +} + +void InfraredTool::prepareFinal() +{ + m_addFilmGrain->setEnabled(false); + m_sensibilitySlider->setEnabled(false); + + int s = 100 + 100 * m_sensibilitySlider->value(); + bool g = m_addFilmGrain->isChecked(); + + ImageIface iface(0, 0); + + setFilter(dynamic_cast<DImgThreadedFilter*>(new Infrared(iface.getOriginalImg(), this, s, g))); +} + +void InfraredTool::putPreviewData() +{ + m_previewWidget->setPreviewImage(filter()->getTargetImage()); +} + +void InfraredTool::putFinalData() +{ + ImageIface iface(0, 0); + iface.putOriginalImage(i18n("Infrared"), filter()->getTargetImage().bits()); +} + +} // NameSpace DigikamInfraredImagesPlugin diff --git a/src/imageplugins/infrared/infraredtool.h b/src/imageplugins/infrared/infraredtool.h new file mode 100644 index 00000000..ddb5144b --- /dev/null +++ b/src/imageplugins/infrared/infraredtool.h @@ -0,0 +1,86 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-22 + * Description : a digiKam image editor plugin for simulate + * infrared film. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef INFRAREDTOOL_H +#define INFRAREDTOOL_H + +// Digikam includes. + +#include "editortool.h" + +class TQSlider; +class TQLCDNumber; +class TQCheckBox; + +namespace Digikam +{ +class EditorToolSettings; +class ImagePanelWidget; +} + +namespace DigikamInfraredImagesPlugin +{ + +class InfraredTool : public Digikam::EditorToolThreaded +{ + TQ_OBJECT + + +public: + + InfraredTool(TQObject* parent); + ~InfraredTool(); + +private slots: + + void slotSliderMoved(int); + void slotResetSettings(); + +private: + + void readSettings(); + void writeSettings(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + TQCheckBox *m_addFilmGrain; + + TQSlider *m_sensibilitySlider; + + TQLCDNumber *m_sensibilityLCDValue; + + Digikam::ImagePanelWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamInfraredImagesPlugin + +#endif /* INFRAREDTOOL_H */ diff --git a/src/imageplugins/inpainting/Makefile.am b/src/imageplugins/inpainting/Makefile.am new file mode 100644 index 00000000..243253a8 --- /dev/null +++ b/src/imageplugins/inpainting/Makefile.am @@ -0,0 +1,34 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + -I$(top_srcdir)/src/libs/greycstoration \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_inpainting_la_SOURCES = imageplugin_inpainting.cpp \ + inpaintingtool.cpp + +digikamimageplugin_inpainting_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_inpainting_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -no-undefined -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_inpainting.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_inpainting.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_inpainting_ui.rc diff --git a/src/imageplugins/inpainting/digikamimageplugin_inpainting.desktop b/src/imageplugins/inpainting/digikamimageplugin_inpainting.desktop new file mode 100644 index 00000000..09f891a7 --- /dev/null +++ b/src/imageplugins/inpainting/digikamimageplugin_inpainting.desktop @@ -0,0 +1,49 @@ +[Desktop Entry] +Name=ImagePlugin_InPainting +Name[bg]=Приставка за снимка - Дорисуване +Name[da]=Plugin til indfyldning +Name[el]=ΠρόσθετοΕικόνας_Αποζωγραφισμός +Name[hr]=Bojanje +Name[it]=PluginImmagini_Reintegrazione +Name[nl]=Afbeeldingsplugin_Inkleuren +Name[sr]=Пребојавање +Name[sr@Latn]=Prebojavanje +Name[sv]=Insticksprogram för ifyllnad +Name[tr]=ResimEklentisi_InPainting +Name[xx]=xxImagePlugin_InPaintingxx + +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=digiKam plugin to inpaint a photograph +Comment[bg]=Приставка на digiKam за дорисуване на повредени или липсващи области от снимки +Comment[ca]=Connector pel digiKam per repintar una fotografia +Comment[da]=Digikam plugin til at indfylde i et fotografi +Comment[de]=digiKam-Modul zur Korrektur von Bildfehlern durch Inpainting +Comment[el]=Πρόσθετο αποζωγραφισμού μιας φωτογραφίας μέσα για το digiKam +Comment[es]=Plugin para digiKam repintar una parte de una fotografía +Comment[et]=DigiKami foto objektide kaotamise plugin +Comment[fa]=وصلۀ digiKam برای کشیدن یک عکس +Comment[gl]=Un plugin de digiKam para pintar por dentro unha fotografia +Comment[hr]=digiKam dodatak za bojanje u fotografiji +Comment[is]=Íforrit fyrir digiKam til að fjarlægja óæskilega hluti úr mynd +Comment[it]=Plugin di digiKam per reintegrare una fotografia +Comment[ja]=digiKam 写真修復プラグイン +Comment[nds]=digiKam-Moduul för de Bildkorrektuur dör Övermalen +Comment[nl]=Digikam-plugin voor het inkleuren van een foto +Comment[pa]=ਇੱਕ ਫੋਟੋ-ਗਰਾਫ਼ ਇਨ-ਪੇਂਟ ਲਈ ਡਿਜ਼ੀਕੈਮ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam umożliwiająca zamalowanie fragmentów zdjęcia +Comment[pt]=Um 'plugin' do digiKam para pintar por dentro uma fotografia +Comment[pt_BR]=Um 'plugin' do digiKam para pintar por dentro uma fotografia +Comment[ru]=Модуль подрисовки фотографий для digiKam +Comment[sk]=digiKam plugin na odstránenie artefaktov +Comment[sr]=digiKam-ов прикључак за пребојавање фотографије +Comment[sr@Latn]=digiKam-ov priključak za prebojavanje fotografije +Comment[sv]=Digikam insticksprogram för att fylla i ett fotografi +Comment[tr]=TDE Fotoğraf Yöneticisi +Comment[uk]=Втулок малювання на фотографіях для digiKam +Comment[vi]=Phần bổ sung sơn vào ảnh chụp cho digiKam +Comment[xx]=xxdigiKam plugin to inpaint a photographxx + +X-TDE-Library=digikamimageplugin_inpainting +author=Gilles Caulier, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/inpainting/digikamimageplugin_inpainting_ui.rc b/src/imageplugins/inpainting/digikamimageplugin_inpainting_ui.rc new file mode 100644 index 00000000..a4c13901 --- /dev/null +++ b/src/imageplugins/inpainting/digikamimageplugin_inpainting_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="5" name="digikamimageplugin_inpainting" > + + <MenuBar> + + <Menu name="Enhance" ><text>Enh&ance</text> + <Action name="imageplugin_inpainting" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action name="imageplugin_inpainting" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/inpainting/imageeffect_inpainting.cpp b/src/imageplugins/inpainting/imageeffect_inpainting.cpp new file mode 100644 index 00000000..d7f2f5fe --- /dev/null +++ b/src/imageplugins/inpainting/imageeffect_inpainting.cpp @@ -0,0 +1,466 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-30 + * Description : a digiKam image editor plugin to inpaint + * a photograph + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +// C++ include. + +#include <cstdio> +#include <cmath> +#include <cstring> + +// 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 <tqpainter.h> +#include <tqbrush.h> +#include <tqfile.h> + +// KDE includes. + +#include <kcursor.h> +#include <kurllabel.h> +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <khelpmenu.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <tdepopupmenu.h> +#include <tdefiledialog.h> +#include <kstandarddirs.h> +#include <kprogress.h> +#include <tdemessagebox.h> +#include <knuminput.h> +#include <tdeglobalsettings.h> +#include <kpassivepopup.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "imageiface.h" +#include "greycstorationsettings.h" +#include "greycstorationwidget.h" +#include "greycstorationiface.h" +#include "imageeffect_inpainting.h" +#include "imageeffect_inpainting.moc" + +namespace DigikamInPaintingImagesPlugin +{ + +class InPaintingPassivePopup : public KPassivePopup +{ +public: + + InPaintingPassivePopup(TQWidget* parent) : KPassivePopup(parent), m_parent(parent) {} + +protected: + + virtual void positionSelf() { move(m_parent->x() + 30, m_parent->y() + 30); } + +private: + + TQWidget* m_parent; +}; + +//------------------------------------------------------------------------------------------ + +void ImageEffect_InPainting::inPainting(TQWidget* parent) +{ + // -- check if we actually have a selection -------------------- + + Digikam::ImageIface iface(0, 0); + + int w = iface.selectedWidth(); + int h = iface.selectedHeight(); + + if (!w || !h) + { + InPaintingPassivePopup* popup = new InPaintingPassivePopup(parent); + popup->setView(i18n("Inpainting Photograph Tool"), + i18n("You need to select a region to inpaint to use " + "this tool")); + popup->setAutoDelete(true); + popup->setTimeout(2500); + popup->show(); + return; + } + + // -- run the dlg ---------------------------------------------- + + ImageEffect_InPainting_Dialog dlg(parent); + dlg.exec(); +} + +//------------------------------------------------------------------------------------------ + +ImageEffect_InPainting_Dialog::ImageEffect_InPainting_Dialog(TQWidget* parent) + : Digikam::ImageGuideDlg(parent, i18n("Photograph Inpainting"), + "inpainting", true, true, false, + Digikam::ImageGuideWidget::HVGuideMode, + 0, true, true, true) +{ + m_isComputed = false; + TQString whatsThis; + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Photograph Inpainting"), + digikam_version, + I18N_NOOP("A digiKam image plugin to inpaint a photograph."), + TDEAboutData::License_GPL, + "(c) 2005-2008, Gilles Caulier", + 0, + "http://www.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + about->addAuthor("David Tschumperle", I18N_NOOP("CImg library"), 0, + "http://cimg.sourceforge.net"); + + about->addAuthor("Gerhard Kulzer", I18N_NOOP("Feedback and plugin polishing"), + "gerhard at kulzer.net"); + + setAboutData(about); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(plainPage()); + TQGridLayout* gridSettings = new TQGridLayout(gboxSettings, 2, 1, spacingHint()); + m_mainTab = new TQTabWidget( gboxSettings ); + + TQWidget* firstPage = new TQWidget( m_mainTab ); + TQGridLayout* grid = new TQGridLayout( firstPage, 2, 2, marginHint(), spacingHint()); + m_mainTab->addTab( firstPage, i18n("Preset") ); + + KURLLabel *cimgLogoLabel = new KURLLabel(firstPage); + cimgLogoLabel->setText(TQString()); + 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"); + cimgLogoLabel->setPixmap( TQPixmap( directory + "logo-cimg.png" ) ); + TQToolTip::add(cimgLogoLabel, i18n("Visit CImg library website")); + + TQLabel *typeLabel = new TQLabel(i18n("Filtering type:"), firstPage); + typeLabel->setAlignment ( TQt::AlignRight | TQt::AlignVCenter); + m_inpaintingTypeCB = new TQComboBox( false, firstPage ); + m_inpaintingTypeCB->insertItem( i18n("None") ); + m_inpaintingTypeCB->insertItem( i18n("Remove Small Artefact") ); + m_inpaintingTypeCB->insertItem( i18n("Remove Medium Artefact") ); + m_inpaintingTypeCB->insertItem( i18n("Remove Large Artefact") ); + TQWhatsThis::add( m_inpaintingTypeCB, i18n("<p>Select the filter preset to use for photograph restoration:<p>" + "<b>None</b>: Most common values. Puts settings to default.<p>" + "<b>Remove Small Artefact</b>: inpaint small image artefact like image glitch.<p>" + "<b>Remove Medium Artefact</b>: inpaint medium image artefact.<p>" + "<b>Remove Large Artefact</b>: inpaint image artefact like unwanted object.<p>")); + + grid->addMultiCellWidget(cimgLogoLabel, 0, 0, 1, 1); + grid->addMultiCellWidget(typeLabel, 1, 1, 0, 0); + grid->addMultiCellWidget(m_inpaintingTypeCB, 1, 1, 1, 1); + grid->setRowStretch(1, 10); + + // ------------------------------------------------------------- + + m_settingsWidget = new Digikam::GreycstorationWidget(m_mainTab); + + gridSettings->addMultiCellWidget(m_mainTab, 0, 0, 1, 1); + gridSettings->addMultiCellWidget(new TQLabel(gboxSettings), 1, 1, 1, 1); + setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + connect(cimgLogoLabel, TQ_SIGNAL(leftClickedURL(const TQString&)), + this, TQ_SLOT(processCImgURL(const TQString&))); + + connect(m_inpaintingTypeCB, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotResetValues(int))); +} + +ImageEffect_InPainting_Dialog::~ImageEffect_InPainting_Dialog() +{ +} + +void ImageEffect_InPainting_Dialog::renderingFinished() +{ + m_mainTab->setEnabled(true); +} + +void ImageEffect_InPainting_Dialog::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("inpainting Tool Dialog"); + + Digikam::GreycstorationSettings settings; + settings.fastApprox = config->readBoolEntry("FastApprox", true); + settings.interp = config->readNumEntry("Interpolation", + Digikam::GreycstorationSettings::NearestNeighbor); + settings.amplitude = config->readDoubleNumEntry("Amplitude", 20.0); + settings.sharpness = config->readDoubleNumEntry("Sharpness", 0.3); + settings.anisotropy = config->readDoubleNumEntry("Anisotropy", 1.0); + settings.alpha = config->readDoubleNumEntry("Alpha", 0.8); + settings.sigma = config->readDoubleNumEntry("Sigma", 2.0); + settings.gaussPrec = config->readDoubleNumEntry("GaussPrec", 2.0); + settings.dl = config->readDoubleNumEntry("Dl", 0.8); + settings.da = config->readDoubleNumEntry("Da", 30.0); + settings.nbIter = config->readNumEntry("Iteration", 30); + settings.tile = config->readNumEntry("Tile", 512); + settings.btile = config->readNumEntry("BTile", 4); + m_settingsWidget->setSettings(settings); + + int p = config->readNumEntry("Preset", NoPreset); + m_inpaintingTypeCB->setCurrentItem(p); + if (p == NoPreset) + m_settingsWidget->setEnabled(true); + else + m_settingsWidget->setEnabled(false); +} + +void ImageEffect_InPainting_Dialog::writeUserSettings() +{ + Digikam::GreycstorationSettings settings = m_settingsWidget->getSettings(); + TDEConfig* config = kapp->config(); + config->setGroup("inpainting Tool Dialog"); + config->writeEntry("Preset", m_inpaintingTypeCB->currentItem()); + 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->sync(); +} + +void ImageEffect_InPainting_Dialog::slotResetValues(int i) +{ + if (i == NoPreset) + m_settingsWidget->setEnabled(true); + else + m_settingsWidget->setEnabled(false); + + resetValues(); +} + +void ImageEffect_InPainting_Dialog::resetValues() +{ + Digikam::GreycstorationSettings settings; + settings.setInpaintingDefaultSettings(); + + switch(m_inpaintingTypeCB->currentItem()) + { + case RemoveSmallArtefact: + // We use default settings here. + break; + + case RemoveMediumArtefact: + { + settings.amplitude = 50.0; + settings.nbIter = 50; + break; + } + + case RemoveLargeArtefact: + { + settings.amplitude = 100.0; + settings.nbIter = 100; + break; + } + } + + m_settingsWidget->setSettings(settings); +} + +void ImageEffect_InPainting_Dialog::processCImgURL(const TQString& url) +{ + TDEApplication::kApplication()->invokeBrowser(url); +} + +void ImageEffect_InPainting_Dialog::prepareEffect() +{ + m_mainTab->setEnabled(false); + + Digikam::ImageIface iface(0, 0); + uchar *data = iface.getOriginalImage(); + m_originalImage = Digikam::DImg(iface.originalWidth(), iface.originalHeight(), + iface.originalSixteenBit(), iface.originalHasAlpha(), data); + delete [] data; + + // Selected area from the image and mask creation: + // + // We optimize the computation time to use the current selected area in image editor + // and to create an inpainting mask with it. Because inpainting is done by interpolation + // neighboor pixels which can be located far from the selected area, we need to ajust the + // mask size in according with the parameter algorithms, especially 'amplitude'. + // Mask size is computed like this : + // + // (image_size_x + 2*amplitude , image_size_y + 2*amplitude) + + + TQRect selectionRect = TQRect(iface.selectedXOrg(), iface.selectedYOrg(), + iface.selectedWidth(), iface.selectedHeight()); + + TQPixmap inPaintingMask(iface.originalWidth(), iface.originalHeight()); + inPaintingMask.fill(TQt::black); + TQPainter p(&inPaintingMask); + p.fillRect( selectionRect, TQBrush(TQt::white) ); + p.end(); + + Digikam::GreycstorationSettings settings = m_settingsWidget->getSettings(); + + int x1 = (int)(selectionRect.left() - 2*settings.amplitude); + int y1 = (int)(selectionRect.top() - 2*settings.amplitude); + int x2 = (int)(selectionRect.right() + 2*settings.amplitude); + int y2 = (int)(selectionRect.bottom() + 2*settings.amplitude); + m_maskRect = TQRect(x1, y1, x2-x1, y2-y1); + + // Mask area normalization. + // We need to check if mask area is out of image size else inpainting give strange results. + + if (m_maskRect.left() < 0) m_maskRect.setLeft(0); + if (m_maskRect.top() < 0) m_maskRect.setTop(0); + if (m_maskRect.right() > iface.originalWidth()) m_maskRect.setRight(iface.originalWidth()); + if (m_maskRect.bottom() > iface.originalHeight()) m_maskRect.setBottom(iface.originalHeight()); + + m_maskImage = inPaintingMask.convertToImage().copy(m_maskRect); + m_cropImage = m_originalImage.copy(m_maskRect); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new Digikam::GreycstorationIface( + &m_cropImage, + settings, + Digikam::GreycstorationIface::InPainting, + 0, 0, + m_maskImage, this)); +} + +void ImageEffect_InPainting_Dialog::prepareFinal() +{ + if (!m_isComputed) + { + setProgressVisible(true); + prepareEffect(); + } + else + { + putFinalData(); + kapp->restoreOverrideCursor(); + accept(); + } +} + +void ImageEffect_InPainting_Dialog::putPreviewData() +{ + Digikam::ImageIface* iface = m_imagePreviewWidget->imageIface(); + Digikam::GreycstorationSettings settings = m_settingsWidget->getSettings(); + + m_cropImage = m_threadedFilter->getTargetImage(); + TQRect cropSel((int)(2*settings.amplitude), (int)(2*settings.amplitude), + iface->selectedWidth(), iface->selectedHeight()); + Digikam::DImg imDest = m_cropImage.copy(cropSel); + + iface->putPreviewImage((imDest.smoothScale(iface->previewWidth(), + iface->previewHeight())).bits()); + m_imagePreviewWidget->updatePreview(); + m_isComputed = true; +} + +void ImageEffect_InPainting_Dialog::putFinalData(void) +{ + Digikam::ImageIface iface(0, 0); + + if (!m_isComputed) + m_cropImage = m_threadedFilter->getTargetImage(); + + m_originalImage.bitBltImage(&m_cropImage, m_maskRect.left(), m_maskRect.top()); + + iface.putOriginalImage(i18n("InPainting"), m_originalImage.bits()); +} + +void ImageEffect_InPainting_Dialog::slotUser3() +{ + KURL loadInpaintingFile = KFileDialog::getOpenURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), this, + TQString( i18n("Photograph Inpainting Settings File to Load")) ); + if( loadInpaintingFile.isEmpty() ) + return; + + TQFile file(loadInpaintingFile.path()); + + if ( file.open(IO_ReadOnly) ) + { + if (!m_settingsWidget->loadSettings(file, TQString("# Photograph Inpainting Configuration File V2"))) + { + KMessageBox::error(this, + i18n("\"%1\" is not a Photograph Inpainting settings text file.") + .arg(loadInpaintingFile.fileName())); + file.close(); + return; + } + } + else + KMessageBox::error(this, i18n("Cannot load settings from the Photograph Inpainting text file.")); + + file.close(); + m_inpaintingTypeCB->blockSignals(true); + m_inpaintingTypeCB->setCurrentItem(NoPreset); + m_inpaintingTypeCB->blockSignals(false); + m_settingsWidget->setEnabled(true); +} + +void ImageEffect_InPainting_Dialog::slotUser2() +{ + KURL saveRestorationFile = KFileDialog::getSaveURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), this, + TQString( i18n("Photograph Inpainting Settings File to Save")) ); + if( saveRestorationFile.isEmpty() ) + return; + + TQFile file(saveRestorationFile.path()); + + if ( file.open(IO_WriteOnly) ) + m_settingsWidget->saveSettings(file, TQString("# Photograph Inpainting Configuration File V2")); + else + KMessageBox::error(this, i18n("Cannot save settings to the Photograph Inpainting text file.")); + + file.close(); +} + +} // NameSpace DigikamInPaintingImagesPlugin + diff --git a/src/imageplugins/inpainting/imageeffect_inpainting.h b/src/imageplugins/inpainting/imageeffect_inpainting.h new file mode 100644 index 00000000..542e9504 --- /dev/null +++ b/src/imageplugins/inpainting/imageeffect_inpainting.h @@ -0,0 +1,116 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-30 + * Description : a digiKam image editor plugin to inpaint + * a photograph + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + + +#ifndef IMAGEEFFECT_INPAINTING_H +#define IMAGEEFFECT_INPAINTING_H + +// TQt include. + +#include <tqimage.h> +#include <tqrect.h> +#include <tqstring.h> + +// Digikam includes. + +#include "dimg.h" +#include "imageguidedlg.h" + +class TQTabWidget; +class TQComboBox; + +namespace Digikam +{ +class GreycstorationWidget; +} + +namespace DigikamInPaintingImagesPlugin +{ + +class ImageEffect_InPainting +{ +public: + + static void inPainting(TQWidget *parent); +}; + +//----------------------------------------------------------- + +class ImageEffect_InPainting_Dialog : public Digikam::ImageGuideDlg +{ + TQ_OBJECT + + +public: + + ImageEffect_InPainting_Dialog(TQWidget* parent); + ~ImageEffect_InPainting_Dialog(); + +private slots: + + void slotUser2(); + void slotUser3(); + void readUserSettings(); + void processCImgURL(const TQString&); + void slotResetValues(int); + +private: + + void writeUserSettings(); + void resetValues(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + enum InPaintingFilteringPreset + { + NoPreset=0, + RemoveSmallArtefact, + RemoveMediumArtefact, + RemoveLargeArtefact + }; + + bool m_isComputed; + + TQRect m_maskRect; + + TQImage m_maskImage; + + TQComboBox *m_inpaintingTypeCB; + + TQTabWidget *m_mainTab; + + Digikam::DImg m_originalImage; + Digikam::DImg m_cropImage; + + Digikam::GreycstorationWidget *m_settingsWidget; +}; + +} // NameSpace DigikamInPaintingImagesPlugin + +#endif /* IMAGEEFFECT_INPAINTING_H */ diff --git a/src/imageplugins/inpainting/imageplugin_inpainting.cpp b/src/imageplugins/inpainting/imageplugin_inpainting.cpp new file mode 100644 index 00000000..2c1e30f3 --- /dev/null +++ b/src/imageplugins/inpainting/imageplugin_inpainting.cpp @@ -0,0 +1,97 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-30 + * Description : a digiKam image editor plugin to inpaint + * a photograph + * + * 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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> +#include <tdeapplication.h> + +// Local includes. + +#include "ddebug.h" +#include "imageiface.h" +#include "inpaintingtool.h" +#include "imageplugin_inpainting.h" +#include "imageplugin_inpainting.moc" + +using namespace DigikamInPaintingImagesPlugin; +using namespace Digikam; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_inpainting, + KGenericFactory<ImagePlugin_InPainting>("digikamimageplugin_inpainting")); + +ImagePlugin_InPainting::ImagePlugin_InPainting(TQObject *parent, const char*, const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_InPainting") +{ + m_inPaintingAction = new TDEAction(i18n("Inpainting..."), "inpainting", + CTRL+Key_E, + this, TQ_SLOT(slotInPainting()), + actionCollection(), "imageplugin_inpainting"); + + m_inPaintingAction->setWhatsThis( i18n( "This filter can be used to inpaint a part in a photo. " + "Select a region to inpaint to use this option.") ); + + setXMLFile( "digikamimageplugin_inpainting_ui.rc" ); + + DDebug() << "ImagePlugin_InPainting plugin loaded" << endl; +} + +ImagePlugin_InPainting::~ImagePlugin_InPainting() +{ +} + +void ImagePlugin_InPainting::setEnabledActions(bool enable) +{ + m_inPaintingAction->setEnabled(enable); +} + +void ImagePlugin_InPainting::slotInPainting() +{ + + ImageIface iface(0, 0); + + int w = iface.selectedWidth(); + int h = iface.selectedHeight(); + + if (!w || !h) + { + InPaintingPassivePopup* popup = new InPaintingPassivePopup(kapp->activeWindow()); + popup->setView(i18n("Inpainting Photograph Tool"), + i18n("You need to select a region to inpaint to use " + "this tool")); + popup->setAutoDelete(true); + popup->setTimeout(2500); + popup->show(); + return; + } + + // -- run the dlg ---------------------------------------------- + + InPaintingTool *tool = new InPaintingTool(this); + loadTool(tool); +} diff --git a/src/imageplugins/inpainting/imageplugin_inpainting.h b/src/imageplugins/inpainting/imageplugin_inpainting.h new file mode 100644 index 00000000..fb2b1f5c --- /dev/null +++ b/src/imageplugins/inpainting/imageplugin_inpainting.h @@ -0,0 +1,57 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-30 + * Description : a digiKam image editor plugin to inpaint + * a photograph + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_INPAINTING_H +#define IMAGEPLUGIN_INPAINTING_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_InPainting : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_InPainting(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_InPainting(); + + void setEnabledActions(bool enable); + +private slots: + + void slotInPainting(); + +private: + + TDEAction *m_inPaintingAction; +}; + +#endif /* IMAGEPLUGIN_INPAINTING_H */ diff --git a/src/imageplugins/inpainting/inpaintingtool.cpp b/src/imageplugins/inpainting/inpaintingtool.cpp new file mode 100644 index 00000000..2ada52bf --- /dev/null +++ b/src/imageplugins/inpainting/inpaintingtool.cpp @@ -0,0 +1,430 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-30 + * Description : a digiKam image editor plugin to inpaint + * a photograph + * + * 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 <cstdio> +#include <cmath> +#include <cstring> + +// TQt includes. + +#include <tqbrush.h> +#include <tqcheckbox.h> +#include <tqcombobox.h> +#include <tqevent.h> +#include <tqfile.h> +#include <tqframe.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqpainter.h> +#include <tqpixmap.h> +#include <tqpushbutton.h> +#include <tqtabwidget.h> +#include <tqtimer.h> +#include <tqtooltip.h> +#include <tqvgroupbox.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <kcursor.h> +#include <tdefiledialog.h> +#include <tdeglobalsettings.h> +#include <khelpmenu.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <tdepopupmenu.h> +#include <kprogress.h> +#include <kstandarddirs.h> +#include <kurllabel.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "dimgthreadedfilter.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "editortoolsettings.h" +#include "greycstorationsettings.h" +#include "greycstorationwidget.h" +#include "greycstorationiface.h" +#include "inpaintingtool.h" +#include "inpaintingtool.moc" + +using namespace Digikam; + +namespace DigikamInPaintingImagesPlugin +{ + +InPaintingTool::InPaintingTool(TQObject* parent) + : EditorToolThreaded(parent) +{ + setName("inpainting"); + setToolName(i18n("Inpainting")); + setToolIcon(SmallIcon("inpainting")); + + m_isComputed = false; + + m_previewWidget = new ImageWidget("inpainting Tool", 0, + i18n("<p>Here you can see the image selection preview with " + "inpainting applied."), + true, ImageGuideWidget::HVGuideMode, false, true); + setToolView(m_previewWidget); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Try| + EditorToolSettings::Load| + EditorToolSettings::SaveAs| + EditorToolSettings::Ok| + EditorToolSettings::Cancel); + TQGridLayout* gridSettings = new TQGridLayout(m_gboxSettings->plainPage(), 2, 1); + m_mainTab = new TQTabWidget( m_gboxSettings->plainPage() ); + + TQWidget* firstPage = new TQWidget( m_mainTab ); + TQGridLayout* grid = new TQGridLayout( firstPage, 2, 2); + m_mainTab->addTab( firstPage, i18n("Preset") ); + + KURLLabel *cimgLogoLabel = new KURLLabel(firstPage); + cimgLogoLabel->setText(TQString()); + 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"); + cimgLogoLabel->setPixmap( TQPixmap( directory + "logo-cimg.png" ) ); + TQToolTip::add(cimgLogoLabel, i18n("Visit CImg library website")); + + TQLabel *typeLabel = new TQLabel(i18n("Filtering type:"), firstPage); + typeLabel->setAlignment ( TQt::AlignRight | TQt::AlignVCenter); + m_inpaintingTypeCB = new TQComboBox( false, firstPage ); + m_inpaintingTypeCB->insertItem( i18n("None") ); + m_inpaintingTypeCB->insertItem( i18n("Remove Small Artefact") ); + m_inpaintingTypeCB->insertItem( i18n("Remove Medium Artefact") ); + m_inpaintingTypeCB->insertItem( i18n("Remove Large Artefact") ); + TQWhatsThis::add( m_inpaintingTypeCB, i18n("<p>Select the filter preset to use for photograph restoration:<p>" + "<b>None</b>: Most common values. Puts settings to default.<p>" + "<b>Remove Small Artefact</b>: inpaint small image artefact like image glitch.<p>" + "<b>Remove Medium Artefact</b>: inpaint medium image artefact.<p>" + "<b>Remove Large Artefact</b>: inpaint image artefact like unwanted object.<p>")); + + grid->addMultiCellWidget(cimgLogoLabel, 0, 0, 1, 1); + grid->addMultiCellWidget(typeLabel, 1, 1, 0, 0); + grid->addMultiCellWidget(m_inpaintingTypeCB, 1, 1, 1, 1); + grid->setMargin(m_gboxSettings->spacingHint()); + grid->setSpacing(m_gboxSettings->spacingHint()); + grid->setRowStretch(1, 10); + + // ------------------------------------------------------------- + + m_settingsWidget = new GreycstorationWidget(m_mainTab); + + gridSettings->addMultiCellWidget(m_mainTab, 0, 0, 1, 1); + gridSettings->addMultiCellWidget(new TQLabel(m_gboxSettings->plainPage()), 1, 1, 1, 1); + gridSettings->setMargin(m_gboxSettings->spacingHint()); + gridSettings->setSpacing(m_gboxSettings->spacingHint()); + gridSettings->setRowStretch(1, 10); + + setToolSettings(m_gboxSettings); + init(); + + // ------------------------------------------------------------- + + connect(cimgLogoLabel, TQ_SIGNAL(leftClickedURL(const TQString&)), + this, TQ_SLOT(processCImgURL(const TQString&))); + + connect(m_inpaintingTypeCB, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotResetValues(int))); + + // ------------------------------------------------------------- + + GreycstorationSettings defaults; + defaults.setInpaintingDefaultSettings(); + m_settingsWidget->setDefaultSettings(defaults); +} + +InPaintingTool::~InPaintingTool() +{ +} + +void InPaintingTool::renderingFinished() +{ + m_mainTab->setEnabled(true); +} + +void InPaintingTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("inpainting Tool"); + + GreycstorationSettings settings; + GreycstorationSettings defaults; + defaults.setInpaintingDefaultSettings(); + + 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); + m_settingsWidget->setSettings(settings); + + int p = config->readNumEntry("Preset", NoPreset); + m_inpaintingTypeCB->setCurrentItem(p); + if (p == NoPreset) + m_settingsWidget->setEnabled(true); + else + m_settingsWidget->setEnabled(false); +} + +void InPaintingTool::writeSettings() +{ + GreycstorationSettings settings = m_settingsWidget->getSettings(); + TDEConfig* config = kapp->config(); + config->setGroup("inpainting Tool"); + config->writeEntry("Preset", m_inpaintingTypeCB->currentItem()); + 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); + m_previewWidget->writeSettings(); + config->sync(); +} + +void InPaintingTool::slotResetValues(int i) +{ + if (i == NoPreset) + m_settingsWidget->setEnabled(true); + else + m_settingsWidget->setEnabled(false); + + slotResetSettings(); +} + +void InPaintingTool::slotResetSettings() +{ + GreycstorationSettings settings; + settings.setInpaintingDefaultSettings(); + + switch(m_inpaintingTypeCB->currentItem()) + { + case RemoveSmallArtefact: + // We use default settings here. + break; + + case RemoveMediumArtefact: + { + settings.amplitude = 50.0; + settings.nbIter = 50; + break; + } + + case RemoveLargeArtefact: + { + settings.amplitude = 100.0; + settings.nbIter = 100; + break; + } + } + + m_settingsWidget->setSettings(settings); +} + +void InPaintingTool::processCImgURL(const TQString& url) +{ + TDEApplication::kApplication()->invokeBrowser(url); +} + +void InPaintingTool::prepareEffect() +{ + m_mainTab->setEnabled(false); + + ImageIface iface(0, 0); + uchar *data = iface.getOriginalImage(); + m_originalImage = DImg(iface.originalWidth(), iface.originalHeight(), + iface.originalSixteenBit(), iface.originalHasAlpha(), data); + delete [] data; + + // Selected area from the image and mask creation: + // + // We optimize the computation time to use the current selected area in image editor + // and to create an inpainting mask with it. Because inpainting is done by interpolation + // neighboor pixels which can be located far from the selected area, we need to ajust the + // mask size in according with the parameter algorithms, especially 'amplitude'. + // Mask size is computed like this : + // + // (image_size_x + 2*amplitude , image_size_y + 2*amplitude) + + + TQRect selectionRect = TQRect(iface.selectedXOrg(), iface.selectedYOrg(), + iface.selectedWidth(), iface.selectedHeight()); + + TQPixmap inPaintingMask(iface.originalWidth(), iface.originalHeight()); + inPaintingMask.fill(TQt::black); + TQPainter p(&inPaintingMask); + p.fillRect( selectionRect, TQBrush(TQt::white) ); + p.end(); + + GreycstorationSettings settings = m_settingsWidget->getSettings(); + + int x1 = (int)(selectionRect.left() - 2*settings.amplitude); + int y1 = (int)(selectionRect.top() - 2*settings.amplitude); + int x2 = (int)(selectionRect.right() + 2*settings.amplitude); + int y2 = (int)(selectionRect.bottom() + 2*settings.amplitude); + m_maskRect = TQRect(x1, y1, x2-x1, y2-y1); + + // Mask area normalization. + // We need to check if mask area is out of image size else inpainting give strange results. + + if (m_maskRect.left() < 0) m_maskRect.setLeft(0); + if (m_maskRect.top() < 0) m_maskRect.setTop(0); + if (m_maskRect.right() > iface.originalWidth()) m_maskRect.setRight(iface.originalWidth()); + if (m_maskRect.bottom() > iface.originalHeight()) m_maskRect.setBottom(iface.originalHeight()); + + m_maskImage = inPaintingMask.convertToImage().copy(m_maskRect); + m_cropImage = m_originalImage.copy(m_maskRect); + + setFilter(dynamic_cast<DImgThreadedFilter*>( + new GreycstorationIface( + &m_cropImage, + settings, + GreycstorationIface::InPainting, + 0, 0, + m_maskImage, this))); +} + +void InPaintingTool::prepareFinal() +{ + if (!m_isComputed) + { + prepareEffect(); + } + else + { + Digikam::DImgThreadedFilter::EventData *eventData = new Digikam::DImgThreadedFilter::EventData(); + eventData->progress = 100; + eventData->starting = false; + eventData->success = true; + TQApplication::postEvent(this, new TQCustomEvent(TQEvent::User, eventData)); + } +} + +void InPaintingTool::putPreviewData() +{ + ImageIface* iface = m_previewWidget->imageIface(); + GreycstorationSettings settings = m_settingsWidget->getSettings(); + + m_cropImage = filter()->getTargetImage(); + TQRect cropSel((int)(2*settings.amplitude), (int)(2*settings.amplitude), + iface->selectedWidth(), iface->selectedHeight()); + DImg imDest = m_cropImage.copy(cropSel); + + iface->putPreviewImage((imDest.smoothScale(iface->previewWidth(), + iface->previewHeight())).bits()); + m_previewWidget->updatePreview(); + m_isComputed = true; +} + +void InPaintingTool::putFinalData() +{ + ImageIface iface(0, 0); + + if (!m_isComputed) + m_cropImage = filter()->getTargetImage(); + + m_originalImage.bitBltImage(&m_cropImage, m_maskRect.left(), m_maskRect.top()); + + iface.putOriginalImage(i18n("InPainting"), m_originalImage.bits()); +} + +void InPaintingTool::slotLoadSettings() +{ + KURL loadInpaintingFile = KFileDialog::getOpenURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), kapp->activeWindow(), + TQString( i18n("Photograph Inpainting Settings File to Load")) ); + if( loadInpaintingFile.isEmpty() ) + return; + + TQFile file(loadInpaintingFile.path()); + + if ( file.open(IO_ReadOnly) ) + { + if (!m_settingsWidget->loadSettings(file, TQString("# Photograph Inpainting Configuration File V2"))) + { + KMessageBox::error(kapp->activeWindow(), + i18n("\"%1\" is not a Photograph Inpainting settings text file.") + .arg(loadInpaintingFile.fileName())); + file.close(); + return; + } + } + else + KMessageBox::error(kapp->activeWindow(), i18n("Cannot load settings from the Photograph Inpainting text file.")); + + file.close(); + m_inpaintingTypeCB->blockSignals(true); + m_inpaintingTypeCB->setCurrentItem(NoPreset); + m_inpaintingTypeCB->blockSignals(false); + m_settingsWidget->setEnabled(true); +} + +void InPaintingTool::slotSaveAsSettings() +{ + KURL saveRestorationFile = KFileDialog::getSaveURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), kapp->activeWindow(), + TQString( i18n("Photograph Inpainting Settings File to Save")) ); + if( saveRestorationFile.isEmpty() ) + return; + + TQFile file(saveRestorationFile.path()); + + if ( file.open(IO_WriteOnly) ) + m_settingsWidget->saveSettings(file, TQString("# Photograph Inpainting Configuration File V2")); + else + KMessageBox::error(kapp->activeWindow(), i18n("Cannot save settings to the Photograph Inpainting text file.")); + + file.close(); +} + +} // NameSpace DigikamInPaintingImagesPlugin diff --git a/src/imageplugins/inpainting/inpaintingtool.h b/src/imageplugins/inpainting/inpaintingtool.h new file mode 100644 index 00000000..44202c5d --- /dev/null +++ b/src/imageplugins/inpainting/inpaintingtool.h @@ -0,0 +1,133 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-30 + * Description : a digiKam image editor plugin to inpaint + * a photograph + * + * 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. + * + * ============================================================ */ + +#ifndef INPAINTINGTOOL_H +#define INPAINTINGTOOL_H + +// TQt includes. + +#include <tqimage.h> +#include <tqrect.h> +#include <tqstring.h> + +// KDE includes. + +#include <kpassivepopup.h> + +// Digikam includes. + +#include "dimg.h" +#include "editortool.h" + +class TQTabWidget; +class TQComboBox; + +namespace Digikam +{ +class GreycstorationWidget; +class ImageWidget; +class EditorToolSettings; +} + +namespace DigikamInPaintingImagesPlugin +{ + +class InPaintingPassivePopup : public KPassivePopup +{ +public: + + InPaintingPassivePopup(TQWidget* parent) : KPassivePopup(parent), m_parent(parent) {} + +protected: + + virtual void positionSelf() { move(m_parent->x() + 30, m_parent->y() + 30); } + +private: + + TQWidget* m_parent; +}; + +//----------------------------------------------------------- + +class InPaintingTool : public Digikam::EditorToolThreaded +{ + TQ_OBJECT + + +public: + + InPaintingTool(TQObject* parent); + ~InPaintingTool(); + +private slots: + + void processCImgURL(const TQString&); + void slotResetValues(int); + void slotResetSettings(); + void slotSaveAsSettings(); + void slotLoadSettings(); + +private: + + void readSettings(); + void writeSettings(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + enum InPaintingFilteringPreset + { + NoPreset=0, + RemoveSmallArtefact, + RemoveMediumArtefact, + RemoveLargeArtefact + }; + + bool m_isComputed; + + TQRect m_maskRect; + + TQImage m_maskImage; + + TQComboBox *m_inpaintingTypeCB; + + TQTabWidget *m_mainTab; + + Digikam::DImg m_originalImage; + Digikam::DImg m_cropImage; + + Digikam::GreycstorationWidget *m_settingsWidget; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamInPaintingImagesPlugin + +#endif /* INPAINTINGTOOL_H */ diff --git a/src/imageplugins/inserttext/Makefile.am b/src/imageplugins/inserttext/Makefile.am new file mode 100644 index 00000000..2753def7 --- /dev/null +++ b/src/imageplugins/inserttext/Makefile.am @@ -0,0 +1,34 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_inserttext_la_SOURCES = imageplugin_inserttext.cpp inserttextwidget.cpp \ + inserttexttool.cpp fontchooserwidget.cpp + +digikamimageplugin_inserttext_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_inserttext_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_inserttext.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_inserttext.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_inserttext_ui.rc + diff --git a/src/imageplugins/inserttext/digikamimageplugin_inserttext.desktop b/src/imageplugins/inserttext/digikamimageplugin_inserttext.desktop new file mode 100644 index 00000000..e9ca6cfd --- /dev/null +++ b/src/imageplugins/inserttext/digikamimageplugin_inserttext.desktop @@ -0,0 +1,50 @@ +[Desktop Entry] +Name=ImagePlugin_InsertText +Name[bg]=Приставка за снимки - Добавяне на текст +Name[da]=Plugin til at indsætte tekst +Name[el]=ΠρόσθετοΕικόνας_ΕισαγωγήΚειμένου +Name[fi]=Tekstinlisäys +Name[hr]=Tekst +Name[it]=PluginImmagini_InserisciTesto +Name[nl]=Afbeeldingsplugin_TekstInvoegen +Name[sr]=Убаци текст +Name[sr@Latn]=Ubaci tekst +Name[sv]=Insticksprogram för infoga text +Name[tr]=ResimEklentisi_MetinEkle +Name[xx]=xxImagePlugin_InsertTextxx +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=Insert text to image plugin for digiKam +Comment[bg]=Приставка на digiKam за добавяне на текст към снимки +Comment[ca]=Connector pel digiKam per inserir text en una imatge +Comment[da]=Digikam plugin til at indsætte tekst i billeder +Comment[de]=digiKam-Modul zum Einfügen von Text in ein Bild +Comment[el]=Πρόσθετο εισαγωγής κειμένου σε εικόνα για το digiKam +Comment[es]=Plugin de digiKampara insertar texto a una imagen +Comment[et]=DigiKami pildile teksti lisamise plugin +Comment[fa]=درج متن در وصلۀ تصویر برای digiKam +Comment[fi]=Lisää tekstiä kuvaan +Comment[gl]=Un plugin de digiKam para inserir texto na imaxe +Comment[hr]=digiKam dodatak za umetanje teksta +Comment[is]=Íforrit fyrir digiKam sem setur texta inn á mynd +Comment[it]=Plugin per l'aggiunta di testo nell'immagire per digiKam +Comment[ja]=digiKam テキスト挿入プラグイン +Comment[nds]=digiKam-Moduul för't Infögen vun Text in en Bild +Comment[nl]=Digikam-plugin voor het invoegen van tekst +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਚਿੱਤਰ ਉੱਤੇ ਪਾਠ ਲਿਖਣ ਲਈ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam dodająca tekst do zdjęcia +Comment[pt]=Um 'plugin' do digiKam para inserir texto na imagem +Comment[pt_BR]=Plugin de inserção de texto na imagem +Comment[ru]=Модуль digiKam наложения текста на изображения +Comment[sk]=digiKam plugin pre vkladanie textu do obrázku +Comment[sr]=digiKam-ов прикључак за убацивање текста у слику +Comment[sr@Latn]=digiKam-ov priključak za ubacivanje teksta u sliku +Comment[sv]=Digikam insticksprogram för att infoga text i bilder +Comment[tr]=digiKam için resme metin ekleme eklentisi +Comment[uk]=Втулок для вставляння тексту в зображення для digiKam +Comment[vi]=Phần bổ sung chèn chữ vào ảnh cho digiKam +Comment[xx]=xxInsert text to image plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_inserttext +author=Gilles Caulier, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/inserttext/digikamimageplugin_inserttext_ui.rc b/src/imageplugins/inserttext/digikamimageplugin_inserttext_ui.rc new file mode 100644 index 00000000..4fa71fcc --- /dev/null +++ b/src/imageplugins/inserttext/digikamimageplugin_inserttext_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="5" name="digikamimageplugin_inserttext" > + + <MenuBar> + + <Menu name="Decorate" ><text>&Decorate</text> + <Action name="imageplugin_inserttext" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action name="imageplugin_inserttext" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/inserttext/fontchooserwidget.cpp b/src/imageplugins/inserttext/fontchooserwidget.cpp new file mode 100644 index 00000000..aa76ea8e --- /dev/null +++ b/src/imageplugins/inserttext/fontchooserwidget.cpp @@ -0,0 +1,738 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-14 + * Description : a simple widget to choose a font based on + * KDE FontChooserWidget implementation. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 1999 by Preston Brown <pbrown@kde.org> + * Copyright (C) 1997 by Bernd Johannes Wuebben <wuebben@kde.org> + * + * 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 <tqcheckbox.h> +#include <tqcombobox.h> +#include <tqfile.h> +#include <tqfont.h> +#include <tqfontdatabase.h> +#include <tqgroupbox.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqscrollbar.h> +#include <tqspinbox.h> +#include <tqstringlist.h> +#include <tqtooltip.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeapplication.h> +#include <kcharsets.h> +#include <tdeconfig.h> +#include <kdialog.h> +#include <tdeglobal.h> +#include <tdeglobalsettings.h> +#include <tdelistbox.h> +#include <tdelocale.h> +#include <knuminput.h> +#include <kstandarddirs.h> +#include <tqlineedit.h> + +// Local includes. + +#include "fontchooserwidget.h" +#include "fontchooserwidget.moc" + +namespace DigikamInsertTextImagesPlugin +{ + +class FontChooserWidget::FontChooserWidgetPrivate +{ +public: + + FontChooserWidgetPrivate() + { + m_palette.setColor(TQPalette::Active, TQColorGroup::Text, TQt::black); + m_palette.setColor(TQPalette::Active, TQColorGroup::Base, TQt::white); + } + + TQPalette m_palette; +}; + +FontChooserWidget::FontChooserWidget(TQWidget *parent, const char *name, + bool onlyFixed, const TQStringList &fontList, + int visibleListSize, bool diff, + TQButton::ToggleState *sizeIsRelativeState ) + : TQWidget(parent, name), usingFixed(onlyFixed) +{ + charsetsCombo = 0; + + TQString mainWhatsThisText = i18n( "Here you can choose the font to be used." ); + TQWhatsThis::add( this, mainWhatsThisText ); + + d = new FontChooserWidgetPrivate; + TQVBoxLayout *topLayout = new TQVBoxLayout( this, 0, KDialog::spacingHint() ); + int checkBoxGap = KDialog::spacingHint() / 2; + + int row = 0; + TQWidget *page = new TQWidget( this ); + topLayout->addWidget(page); + TQGridLayout *gridLayout = new TQGridLayout( page, 4, 3, 0, KDialog::spacingHint() ); + + // First, create the labels across the top + + TQHBoxLayout *familyLayout = new TQHBoxLayout(); + familyLayout->addSpacing( checkBoxGap ); + + if (diff) + { + familyCheckbox = new TQCheckBox(i18n("Font"), page); + + connect(familyCheckbox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(toggled_checkbox())); + + familyLayout->addWidget(familyCheckbox, 0, TQt::AlignLeft); + TQString familyCBToolTipText = + i18n("Change font family?"); + TQString familyCBWhatsThisText = + i18n("Enable this checkbox to change the font family settings."); + TQWhatsThis::add( familyCheckbox, familyCBWhatsThisText ); + TQToolTip::add( familyCheckbox, familyCBToolTipText ); + familyLabel = 0; + } + else + { + familyCheckbox = 0; + familyLabel = new TQLabel( i18n("Font:"), page, "familyLabel" ); + familyLayout->addWidget(familyLabel, 1, TQt::AlignLeft); + } + + gridLayout->addLayout(familyLayout, row, 0 ); + + TQHBoxLayout *styleLayout = new TQHBoxLayout(); + + if (diff) + { + styleCheckbox = new TQCheckBox(i18n("Style:"), page); + + connect(styleCheckbox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(toggled_checkbox())); + + styleLayout->addWidget(styleCheckbox, 0, TQt::AlignLeft); + TQString styleCBToolTipText = + i18n("Change font style?"); + TQString styleCBWhatsThisText = + i18n("Enable this checkbox to change the font style settings."); + TQWhatsThis::add( styleCheckbox, styleCBWhatsThisText ); + TQToolTip::add( styleCheckbox, styleCBToolTipText ); + styleLabel = 0; + } + else + { + styleCheckbox = 0; + styleLabel = new TQLabel( i18n("Style:"), page, "styleLabel"); + styleLayout->addWidget(styleLabel, 1, TQt::AlignLeft); + } + + styleLayout->addSpacing( checkBoxGap ); + gridLayout->addLayout(styleLayout, row, 1 ); + + TQHBoxLayout *sizeLayout = new TQHBoxLayout(); + + if (diff) + { + sizeCheckbox = new TQCheckBox(i18n("Size"),page); + + connect(sizeCheckbox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(toggled_checkbox())); + + sizeLayout->addWidget(sizeCheckbox, 0, TQt::AlignLeft); + TQString sizeCBToolTipText = + i18n("Change font size?"); + TQString sizeCBWhatsThisText = + i18n("Enable this checkbox to change the font size settings."); + TQWhatsThis::add( sizeCheckbox, sizeCBWhatsThisText ); + TQToolTip::add( sizeCheckbox, sizeCBToolTipText ); + sizeLabel = 0; + } + else + { + sizeCheckbox = 0; + sizeLabel = new TQLabel( i18n("Size:"), page, "sizeLabel"); + sizeLayout->addWidget(sizeLabel, 1, TQt::AlignLeft); + } + + sizeLayout->addSpacing( checkBoxGap ); + sizeLayout->addSpacing( checkBoxGap ); // prevent label from eating border + gridLayout->addLayout(sizeLayout, row, 2 ); + + row ++; + + // Now create the actual boxes that hold the info + + familyListBox = new TDEListBox( page, "familyListBox"); + familyListBox->setEnabled( !diff ); + gridLayout->addWidget( familyListBox, row, 0 ); + TQString fontFamilyWhatsThisText = i18n("Here you can choose the font family to be used." ); + TQWhatsThis::add( familyListBox, fontFamilyWhatsThisText ); + TQWhatsThis::add(diff?(TQWidget *) familyCheckbox:(TQWidget *) familyLabel, fontFamilyWhatsThisText ); + + connect(familyListBox, TQ_SIGNAL(highlighted(const TQString &)), + this, TQ_SLOT(family_chosen_slot(const TQString &))); + + if(!fontList.isEmpty()) + { + familyListBox->insertStringList(fontList); + } + else + { + fillFamilyListBox(onlyFixed); + } + + familyListBox->setMinimumHeight( minimumListHeight( familyListBox, visibleListSize ) ); + + styleListBox = new TDEListBox( page, "styleListBox"); + styleListBox->setEnabled( !diff ); + gridLayout->addWidget(styleListBox, row, 1); + TQString fontStyleWhatsThisText = i18n("Here you can choose the font style to be used." ); + TQWhatsThis::add( styleListBox, fontStyleWhatsThisText ); + TQWhatsThis::add(diff?(TQWidget *)styleCheckbox:(TQWidget *)styleLabel, fontFamilyWhatsThisText ); + styleListBox->insertItem(i18n("Regular")); + styleListBox->insertItem(i18n("Italic")); + styleListBox->insertItem(i18n("Bold")); + styleListBox->insertItem(i18n("Bold Italic")); + styleListBox->setMinimumWidth( minimumListWidth( styleListBox ) ); + styleListBox->setMinimumHeight( minimumListHeight( styleListBox, visibleListSize ) ); + + connect(styleListBox, TQ_SIGNAL(highlighted(const TQString &)), + this, TQ_SLOT(style_chosen_slot(const TQString &))); + + sizeListBox = new TDEListBox( page, "sizeListBox"); + sizeOfFont = new KIntNumInput( page, "sizeOfFont"); + sizeOfFont->setMinValue(4); + + sizeListBox->setEnabled( !diff ); + sizeOfFont->setEnabled( !diff ); + + if( sizeIsRelativeState ) + { + TQString sizeIsRelativeCBText = + i18n("Relative"); + TQString sizeIsRelativeCBToolTipText = + i18n("Font size<br><i>fixed</i> or <i>relative</i><br>to environment"); + TQString sizeIsRelativeCBWhatsThisText = + i18n("Here you can switch between a fixed font size and a font size " + "to be calculated dynamically and adjusted to any changing " + "environment (e.g. widget dimensions, paper size)." ); + sizeIsRelativeCheckBox = new TQCheckBox( sizeIsRelativeCBText, + page, + "sizeIsRelativeCheckBox" ); + sizeIsRelativeCheckBox->setTristate( diff ); + TQGridLayout *sizeLayout2 = new TQGridLayout( 3,2, KDialog::spacingHint()/2, "sizeLayout2" ); + gridLayout->addLayout(sizeLayout2, row, 2); + sizeLayout2->setColStretch( 1, 1 ); // to prevent text from eating the right border + sizeLayout2->addMultiCellWidget( sizeOfFont, 0, 0, 0, 1); + sizeLayout2->addMultiCellWidget(sizeListBox, 1,1, 0,1); + sizeLayout2->addWidget(sizeIsRelativeCheckBox, 2, 0, TQt::AlignLeft); + TQWhatsThis::add( sizeIsRelativeCheckBox, sizeIsRelativeCBWhatsThisText ); + TQToolTip::add( sizeIsRelativeCheckBox, sizeIsRelativeCBToolTipText ); + } + else + { + sizeIsRelativeCheckBox = 0L; + TQGridLayout *sizeLayout2 = new TQGridLayout( 2,1, KDialog::spacingHint()/2, "sizeLayout2" ); + gridLayout->addLayout(sizeLayout2, row, 2); + sizeLayout2->addWidget( sizeOfFont, 0, 0); + sizeLayout2->addMultiCellWidget(sizeListBox, 1,1, 0,0); + } + + TQString fontSizeWhatsThisText = i18n("Here you can choose the font size to be used." ); + TQWhatsThis::add( sizeListBox, fontSizeWhatsThisText ); + TQWhatsThis::add( diff?(TQWidget *)sizeCheckbox:(TQWidget *)sizeLabel, fontSizeWhatsThisText ); + + fillSizeList(); + sizeListBox->setMinimumWidth( minimumListWidth(sizeListBox) + + sizeListBox->fontMetrics().maxWidth() ); + sizeListBox->setMinimumHeight( minimumListHeight( sizeListBox, visibleListSize ) ); + + connect( sizeOfFont, TQ_SIGNAL( valueChanged(int) ), + this, TQ_SLOT(size_value_slot(int))); + + connect( sizeListBox, TQ_SIGNAL(highlighted(const TQString&)), + this, TQ_SLOT(size_chosen_slot(const TQString&)) ); + + sizeListBox->setSelected(sizeListBox->findItem(TQString::number(10)), true); // default to 10pt. + + row ++; + + row ++; + + TQVBoxLayout *vbox; + page = new TQWidget( this ); + topLayout->addWidget(page); + vbox = new TQVBoxLayout( page, 0, KDialog::spacingHint() ); + TQLabel *label = new TQLabel( i18n("Actual Font"), page ); + vbox->addWidget( label ); + + xlfdEdit = new TQLineEdit( page, "xlfdEdit" ); + vbox->addWidget( xlfdEdit ); + + // lets initialize the display if possible + setFont( TDEGlobalSettings::generalFont(), usingFixed ); + + // check or uncheck or gray out the "relative" checkbox + if( sizeIsRelativeState && sizeIsRelativeCheckBox ) + setSizeIsRelative( *sizeIsRelativeState ); + + TDEConfig *config = TDEGlobal::config(); + TDEConfigGroupSaver saver(config, TQString::fromLatin1("General")); + showXLFDArea(config->readBoolEntry(TQString::fromLatin1("fontSelectorShowXLFD"), false)); +} + +FontChooserWidget::~FontChooserWidget() +{ + delete d; +} + +int FontChooserWidget::minimumListWidth( const TQListBox *list ) +{ + int w=0; + + for( uint i=0; i<list->count(); i++ ) + { + int itemWidth = list->item(i)->width(list); + w = TQMAX(w,itemWidth); + } + + if( w == 0 ) + { + w = 40; + } + + w += list->frameWidth() * 2; + w += list->verticalScrollBar()->sizeHint().width(); + return w; +} + +int FontChooserWidget::minimumListHeight( const TQListBox *list, int numVisibleEntry ) +{ + int w = list->count() > 0 ? list->item(0)->height(list) : + list->fontMetrics().lineSpacing(); + + if( w < 0 ) { w = 10; } + if( numVisibleEntry <= 0 ) { numVisibleEntry = 4; } + return ( w * numVisibleEntry + 2 * list->frameWidth() ); +} + +void FontChooserWidget::fillSizeList() +{ + if(! sizeListBox) return; //assertion. + + static const int c[] = + { + 4, 5, 6, 7, + 8, 9, 10, 11, + 12, 13, 14, 15, + 16, 17, 18, 19, + 20, 22, 24, 26, + 28, 32, 48, 64, + 72, 80, 94, 102, + 116, 128, 132, 148, + 156, 164, 172, 188, + 192, 202, 212, 224, + 232, 240, 248, 256, + 0 + }; + + for(int i = 0; c[i]; ++i) + { + sizeListBox->insertItem(TQString::number(c[i])); + } +} + +void FontChooserWidget::setColor( const TQColor & col ) +{ + d->m_palette.setColor( TQPalette::Active, TQColorGroup::Text, col ); +} + +TQColor FontChooserWidget::color() const +{ + return d->m_palette.color( TQPalette::Active, TQColorGroup::Text ); +} + +void FontChooserWidget::setBackgroundColor( const TQColor & col ) +{ + d->m_palette.setColor( TQPalette::Active, TQColorGroup::Base, col ); +} + +TQColor FontChooserWidget::backgroundColor() const +{ + return d->m_palette.color( TQPalette::Active, TQColorGroup::Base ); +} + +void FontChooserWidget::setSizeIsRelative( TQButton::ToggleState relative ) +{ + // check or uncheck or gray out the "relative" checkbox + if( sizeIsRelativeCheckBox ) + { + if( TQButton::NoChange == relative ) + sizeIsRelativeCheckBox->setNoChange(); + else + sizeIsRelativeCheckBox->setChecked( TQButton::On == relative ); + } +} + +TQButton::ToggleState FontChooserWidget::sizeIsRelative() const +{ + return sizeIsRelativeCheckBox + ? sizeIsRelativeCheckBox->state() + : TQButton::NoChange; +} + +TQSize FontChooserWidget::sizeHint( void ) const +{ + return minimumSizeHint(); +} + +void FontChooserWidget::enableColumn( int column, bool state ) +{ + if( column & FamilyList ) + { + familyListBox->setEnabled(state); + } + if( column & StyleList ) + { + styleListBox->setEnabled(state); + } + if( column & SizeList ) + { + sizeListBox->setEnabled(state); + } +} + +void FontChooserWidget::setFont( const TQFont& aFont, bool onlyFixed ) +{ + selFont = aFont; + selectedSize=aFont.pointSize(); + if (selectedSize == -1) + selectedSize = TQFontInfo(aFont).pointSize(); + + if( onlyFixed != usingFixed) + { + usingFixed = onlyFixed; + fillFamilyListBox(usingFixed); + } + setupDisplay(); + displaySample(selFont); +} + +int FontChooserWidget::fontDiffFlags() { + int diffFlags = 0; + if (familyCheckbox && styleCheckbox && sizeCheckbox) + { + diffFlags = (int)(familyCheckbox->isChecked() ? FontDiffFamily : 0) + | (int)( styleCheckbox->isChecked() ? FontDiffStyle : 0) + | (int)( sizeCheckbox->isChecked() ? FontDiffSize : 0); + } + return diffFlags; +} + +void FontChooserWidget::toggled_checkbox() +{ + familyListBox->setEnabled( familyCheckbox->isChecked() ); + styleListBox->setEnabled( styleCheckbox->isChecked() ); + sizeListBox->setEnabled( sizeCheckbox->isChecked() ); + sizeOfFont->setEnabled( sizeCheckbox->isChecked() ); +} + +void FontChooserWidget::family_chosen_slot(const TQString& family) +{ + TQFontDatabase dbase; + TQStringList styles = TQStringList(dbase.styles(family)); + styleListBox->clear(); + currentStyles.clear(); + TQStringList::Iterator end(styles.end()); + for ( TQStringList::Iterator it = styles.begin(); it != end; ++it ) + { + TQString style = *it; + int pos = style.find("Plain"); + if(pos >=0) style = style.replace(pos,5,i18n("Regular")); + pos = style.find("Normal"); + if(pos >=0) style = style.replace(pos,6,i18n("Regular")); + pos = style.find("Oblique"); + if(pos >=0) style = style.replace(pos,7,i18n("Italic")); + if(!styleListBox->findItem(style)) + { + styleListBox->insertItem(i18n(style.utf8())); + currentStyles.insert(i18n(style.utf8()), *it); + } + } + if(styleListBox->count()==0) + { + styleListBox->insertItem(i18n("Regular")); + currentStyles.insert(i18n("Regular"), "Normal"); + } + + styleListBox->blockSignals(true); + TQListBoxItem *item = styleListBox->findItem(selectedStyle); + if (item) + styleListBox->setSelected(styleListBox->findItem(selectedStyle), true); + else + styleListBox->setSelected(0, true); + styleListBox->blockSignals(false); + + style_chosen_slot(TQString()); +} + +void FontChooserWidget::size_chosen_slot(const TQString& size) +{ + selectedSize=size.toInt(); + sizeOfFont->setValue(selectedSize); + selFont.setPointSize(selectedSize); + emit fontSelected(selFont); +} + +void FontChooserWidget::size_value_slot(int val) +{ + selFont.setPointSize(val); + emit fontSelected(selFont); +} + +void FontChooserWidget::style_chosen_slot(const TQString& style) +{ + TQString currentStyle; + if (style.isEmpty()) + currentStyle = styleListBox->currentText(); + else + currentStyle = style; + + int diff=0; // the difference between the font size requested and what we can show. + + sizeListBox->clear(); + TQFontDatabase dbase; + if(dbase.isSmoothlyScalable(familyListBox->currentText(), currentStyles[currentStyle])) + { // is vector font + //sampleEdit->setPaletteBackgroundPixmap( VectorPixmap ); // TODO + fillSizeList(); + } + else + { // is bitmap font. + //sampleEdit->setPaletteBackgroundPixmap( BitmapPixmap ); // TODO + TQValueList<int> sizes = dbase.smoothSizes(familyListBox->currentText(), currentStyles[currentStyle]); + if(sizes.count() > 0) + { + TQValueList<int>::iterator it; + diff=1000; + TQValueList<int>::iterator end(sizes.end()); + for ( it = sizes.begin(); it != end; ++it ) + { + if(*it <= selectedSize || diff > *it - selectedSize) diff = selectedSize - *it; + sizeListBox->insertItem(TQString::number(*it)); + } + } + else // there are times TQT does not provide the list.. + fillSizeList(); + } + sizeListBox->blockSignals(true); + sizeListBox->setSelected(sizeListBox->findItem(TQString::number(selectedSize)), true); + sizeListBox->blockSignals(false); + sizeListBox->ensureCurrentVisible(); + + selFont = dbase.font(familyListBox->currentText(), currentStyles[currentStyle], selectedSize-diff); + emit fontSelected(selFont); + if (!style.isEmpty()) + selectedStyle = style; +} + +void FontChooserWidget::displaySample(const TQFont& font) +{ + xlfdEdit->setText(font.rawName()); + xlfdEdit->setCursorPosition(0); +} + +void FontChooserWidget::setupDisplay() +{ + // Calling familyListBox->setCurrentItem() causes the value of selFont + // to change, so we save the family, style and size beforehand. + TQString family = selFont.family().lower(); + int style = (selFont.bold() ? 2 : 0) + (selFont.italic() ? 1 : 0); + int size = selFont.pointSize(); + if (size == -1) + size = TQFontInfo(selFont).pointSize(); + TQString sizeStr = TQString::number(size); + + int numEntries, i; + + numEntries = familyListBox->count(); + for (i = 0; i < numEntries; i++) + { + if (family == familyListBox->text(i).lower()) + { + familyListBox->setCurrentItem(i); + break; + } + } + + // 1st Fallback + if ( (i == numEntries) ) + { + if (family.contains('[')) + { + family = family.left(family.find('[')).stripWhiteSpace(); + for (i = 0; i < numEntries; i++) + { + if (family == familyListBox->text(i).lower()) + { + familyListBox->setCurrentItem(i); + break; + } + } + } + } + + // 2nd Fallback + if ( (i == numEntries) ) + { + TQString fallback = family+" ["; + for (i = 0; i < numEntries; i++) + { + if (familyListBox->text(i).lower().startsWith(fallback)) + { + familyListBox->setCurrentItem(i); + break; + } + } + } + + // 3rd Fallback + if ( (i == numEntries) ) + { + for (i = 0; i < numEntries; i++) + { + if (familyListBox->text(i).lower().startsWith(family)) + { + familyListBox->setCurrentItem(i); + break; + } + } + } + + // Fall back in case nothing matched. Otherwise, diff doesn't work + if ( i == numEntries ) + familyListBox->setCurrentItem( 0 ); + + styleListBox->setCurrentItem(style); + + numEntries = sizeListBox->count(); + for (i = 0; i < numEntries; i++) + { + if (sizeStr == sizeListBox->text(i)) + { + sizeListBox->setCurrentItem(i); + break; + } + } + + sizeOfFont->setValue(size); +} + +void FontChooserWidget::getFontList( TQStringList &list, uint fontListCriteria) +{ + TQFontDatabase dbase; + TQStringList lstSys(dbase.families()); + + // if we have criteria; then check fonts before adding + if (fontListCriteria) + { + TQStringList lstFonts; + TQStringList::Iterator end(lstSys.end()); + for (TQStringList::Iterator it = lstSys.begin(); it != end; ++it) + { + if ((fontListCriteria & FixedWidthFonts) > 0 && !dbase.isFixedPitch(*it)) continue; + if (((fontListCriteria & (SmoothScalableFonts | ScalableFonts)) == ScalableFonts) && + !dbase.isBitmapScalable(*it)) continue; + if ((fontListCriteria & SmoothScalableFonts) > 0 && !dbase.isSmoothlyScalable(*it)) continue; + lstFonts.append(*it); + } + + if((fontListCriteria & FixedWidthFonts) > 0) { + // Fallback.. if there are no fixed fonts found, it is probably a + // bug in the font server or TQt. In this case, just use 'fixed' + if (lstFonts.count() == 0) + lstFonts.append("fixed"); + } + + lstSys = lstFonts; + } + + lstSys.sort(); + + list = lstSys; +} + +void FontChooserWidget::addFont( TQStringList &list, const char *xfont ) +{ + const char *ptr = strchr( xfont, '-' ); + if ( !ptr ) + return; + + ptr = strchr( ptr + 1, '-' ); + if ( !ptr ) + return; + + TQString font = TQString::fromLatin1(ptr + 1); + + int pos; + if ( ( pos = font.find( '-' ) ) > 0 ) { + font.truncate( pos ); + + if ( font.find( TQString::fromLatin1("open look"), 0, false ) >= 0 ) + return; + + TQStringList::Iterator it = list.begin(); + TQStringList::Iterator end(list.end()); + for ( ; it != end; ++it ) + if ( *it == font ) + return; + list.append( font ); + } +} + +void FontChooserWidget::fillFamilyListBox(bool onlyFixedFonts) +{ + TQStringList fontList; + getFontList(fontList, onlyFixedFonts?FixedWidthFonts:0); + familyListBox->clear(); + familyListBox->insertStringList(fontList); +} + +void FontChooserWidget::showXLFDArea(bool show) +{ + if( show ) + { + xlfdEdit->parentWidget()->show(); + } + else + { + xlfdEdit->parentWidget()->hide(); + } +} + +} // NameSpace DigikamInsertTextImagesPlugin + diff --git a/src/imageplugins/inserttext/fontchooserwidget.h b/src/imageplugins/inserttext/fontchooserwidget.h new file mode 100644 index 00000000..4585c231 --- /dev/null +++ b/src/imageplugins/inserttext/fontchooserwidget.h @@ -0,0 +1,172 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-14 + * Description : a simple widget to choose a font based on + * KDE FontChooserWidget implementation. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 1999 by Preston Brown <pbrown@kde.org> + * Copyright (C) 1997 by Bernd Johannes Wuebben <wuebben@kde.org> + * + * 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. + * + * ============================================================ */ + +#ifndef FONT_CHOOSER_WIDGET_H +#define FONT_CHOOSER_WIDGET_H + +#include <tqlineedit.h> +#include <tqbutton.h> + +class TQComboBox; +class TQCheckBox; +class TQFont; +class TQGroupBox; +class TQLabel; +class TQStringList; + +class TDEListBox; +class KIntNumInput; + +namespace DigikamInsertTextImagesPlugin +{ + +class FontChooserWidget : public TQWidget +{ + TQ_OBJECT + + TQ_PROPERTY( TQFont font READ font WRITE setFont ) + +public: + + enum FontColumn + { + FamilyList=0x01, + StyleList=0x02, + SizeList=0x04 + }; + + enum FontDiff + { + FontDiffFamily=0x01, + FontDiffStyle=0x02, + FontDiffSize=0x04 + }; + + enum FontListCriteria + { + FixedWidthFonts=0x01, + ScalableFonts=0x02, + SmoothScalableFonts=0x04 + }; + +public: + + FontChooserWidget(TQWidget *parent = 0L, const char *name = 0L, + bool onlyFixed = false, + const TQStringList &fontList = TQStringList(), + int visibleListSize=8, + bool diff = false, + TQButton::ToggleState *sizeIsRelativeState = 0L ); + + ~FontChooserWidget(); + + void setFont( const TQFont &font, bool onlyFixed = false ); + void setColor( const TQColor & col ); + void setBackgroundColor( const TQColor & col ); + void setSizeIsRelative( TQButton::ToggleState relative ); + + TQFont font() const { return selFont; }; + TQColor color() const; + TQColor backgroundColor() const; + static void getFontList( TQStringList &list, uint fontListCriteria); + TQButton::ToggleState sizeIsRelative() const; + static TQString getXLFD( const TQFont &theFont ) { return theFont.rawName(); }; + + int fontDiffFlags(); + void enableColumn( int column, bool state ); + virtual TQSize sizeHint( void ) const; + +signals: + + void fontSelected( const TQFont &font ); + +private slots: + + void toggled_checkbox(); + void family_chosen_slot(const TQString&); + void size_chosen_slot(const TQString&); + void style_chosen_slot(const TQString&); + void displaySample(const TQFont &font); + void showXLFDArea(bool); + void size_value_slot(int); + +private: + + void fillFamilyListBox(bool onlyFixedFonts = false); + void fillSizeList(); + + void addFont( TQStringList &list, const char *xfont ); + + void setupDisplay(); + + int minimumListWidth( const TQListBox *list ); + int minimumListHeight( const TQListBox *list, int numVisibleEntry ); + +private: + + bool usingFixed; + int selectedSize; + + TQMap<TQString, TQString> currentStyles; + + // pointer to an optinally supplied list of fonts to + // inserted into the fontdialog font-family combo-box + TQStringList fontList; + + TQLineEdit *xlfdEdit; + + TQLabel *familyLabel; + TQLabel *styleLabel; + + TQCheckBox *familyCheckbox; + TQCheckBox *styleCheckbox; + TQCheckBox *sizeCheckbox; + TQCheckBox *sizeIsRelativeCheckBox; + + TQComboBox *charsetsCombo; + + TQFont selFont; + + TQString selectedStyle; + + TQLabel *sizeLabel; + + KIntNumInput *sizeOfFont; + + TDEListBox *familyListBox; + TDEListBox *styleListBox; + TDEListBox *sizeListBox; + +private: + + class FontChooserWidgetPrivate; + FontChooserWidgetPrivate *d; + +}; + +} // NameSpace DigikamInsertTextImagesPlugin + +#endif // FONT_CHOOSER_WIDGET_H diff --git a/src/imageplugins/inserttext/imageeffect_inserttext.cpp b/src/imageplugins/inserttext/imageeffect_inserttext.cpp new file mode 100644 index 00000000..3f88644b --- /dev/null +++ b/src/imageplugins/inserttext/imageeffect_inserttext.cpp @@ -0,0 +1,348 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-14 + * Description : a plugin to insert a text over an image. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <tqvgroupbox.h> +#include <tqlabel.h> +#include <tqpushbutton.h> +#include <tqwhatsthis.h> +#include <tqlayout.h> +#include <tqframe.h> +#include <tqcombobox.h> +#include <tqcheckbox.h> +#include <tqpixmap.h> +#include <tqpainter.h> +#include <tqbrush.h> +#include <tqpen.h> +#include <tqfont.h> +#include <tqtimer.h> +#include <tqhbuttongroup.h> +#include <tqtooltip.h> + +// KDE includes. + +#include <tdelocale.h> +#include <kcursor.h> +#include <tdeaboutdata.h> +#include <khelpmenu.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <tdepopupmenu.h> +#include <kstandarddirs.h> +#include <tdeconfig.h> +#include <kcolorbutton.h> +#include <ktextedit.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "inserttextwidget.h" +#include "fontchooserwidget.h" +#include "imageeffect_inserttext.h" +#include "imageeffect_inserttext.moc" + +namespace DigikamInsertTextImagesPlugin +{ + +ImageEffect_InsertText::ImageEffect_InsertText(TQWidget* parent) + : Digikam::ImageDlgBase(parent, i18n("Insert Text on Photograph"), + "inserttext", false, false) +{ + TQString whatsThis; + + // About data and help button. + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Insert Text"), + digikam_version, + I18N_NOOP("A digiKam image plugin for inserting text on a photograph."), + TDEAboutData::License_GPL, + "(c) 2005-2006, Gilles Caulier\n" + "(c) 2006-2007, Gilles Caulier and Marcel Wiesweg", + 0, + "http://www.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + about->addAuthor("Marcel Wiesweg", I18N_NOOP("Developer"), + "marcel dot wiesweg at gmx dot de"); + + setAboutData(about); + + // ------------------------------------------------------------- + + TQFrame *frame = new TQFrame(plainPage()); + frame->setFrameStyle(TQFrame::Panel|TQFrame::Sunken); + TQVBoxLayout* l = new TQVBoxLayout(frame, 5, 0); + m_previewWidget = new InsertTextWidget(480, 320, frame); + l->addWidget(m_previewWidget); + TQWhatsThis::add( m_previewWidget, i18n("<p>This previews the text inserted in the image. " + "You can use the mouse to move the text to the right location.")); + setPreviewAreaWidget(frame); + + // ------------------------------------------------------------- + + TQWidget *gbox2 = new TQWidget(plainPage()); + TQGridLayout *gridBox2 = new TQGridLayout( gbox2, 9, 1, spacingHint()); + + m_textEdit = new KTextEdit(gbox2); + m_textEdit->setCheckSpellingEnabled(true); + m_textEdit->setWordWrap(TQTextEdit::NoWrap); + TQWhatsThis::add( m_textEdit, i18n("<p>Here, enter the text you want to insert in your image.")); + gridBox2->addMultiCellWidget(m_textEdit, 0, 2, 0, 1); + + // ------------------------------------------------------------- + + m_fontChooserWidget = new FontChooserWidget(gbox2); + TQWhatsThis::add( m_textEdit, i18n("<p>Here you can choose the font to be used.")); + gridBox2->addMultiCellWidget(m_fontChooserWidget, 3, 3, 0, 1); + + // ------------------------------------------------------------- + + TDEIconLoader icon; + m_alignButtonGroup = new TQHButtonGroup(gbox2); + + TQPushButton *alignLeft = new TQPushButton( m_alignButtonGroup ); + m_alignButtonGroup->insert(alignLeft, ALIGN_LEFT); + alignLeft->setPixmap( icon.loadIcon( "format-text-direction-ltr", (TDEIcon::Group)TDEIcon::Small ) ); + alignLeft->setToggleButton(true); + TQToolTip::add( alignLeft, i18n( "Align text to the left" ) ); + + TQPushButton *alignRight = new TQPushButton( m_alignButtonGroup ); + m_alignButtonGroup->insert(alignRight, ALIGN_RIGHT); + alignRight->setPixmap( icon.loadIcon( "format-text-direction-rtl", (TDEIcon::Group)TDEIcon::Small ) ); + alignRight->setToggleButton(true); + TQToolTip::add( alignRight, i18n( "Align text to the right" ) ); + + TQPushButton *alignCenter = new TQPushButton( m_alignButtonGroup ); + m_alignButtonGroup->insert(alignCenter, ALIGN_CENTER); + alignCenter->setPixmap( icon.loadIcon( "text_center", (TDEIcon::Group)TDEIcon::Small ) ); + alignCenter->setToggleButton(true); + TQToolTip::add( alignCenter, i18n( "Align text to center" ) ); + + TQPushButton *alignBlock = new TQPushButton( m_alignButtonGroup ); + m_alignButtonGroup->insert(alignBlock, ALIGN_BLOCK); + alignBlock->setPixmap( icon.loadIcon( "text_block", (TDEIcon::Group)TDEIcon::Small ) ); + alignBlock->setToggleButton(true); + TQToolTip::add( alignBlock, i18n( "Align text to a block" ) ); + + m_alignButtonGroup->setExclusive(true); + m_alignButtonGroup->setFrameShape(TQFrame::NoFrame); + gridBox2->addMultiCellWidget(m_alignButtonGroup, 4, 4, 0, 1); + + // ------------------------------------------------------------- + + TQLabel *label1 = new TQLabel(i18n("Rotation:"), gbox2); + m_textRotation = new TQComboBox( false, gbox2 ); + m_textRotation->insertItem( i18n("None") ); + m_textRotation->insertItem( i18n("90 Degrees") ); + m_textRotation->insertItem( i18n("180 Degrees") ); + m_textRotation->insertItem( i18n("270 Degrees") ); + TQWhatsThis::add( m_textRotation, i18n("<p>Select the text rotation to use.")); + gridBox2->addMultiCellWidget(label1, 5, 5, 0, 0); + gridBox2->addMultiCellWidget(m_textRotation, 5, 5, 1, 1); + + // ------------------------------------------------------------- + + TQLabel *label2 = new TQLabel(i18n("Color:"), gbox2); + m_fontColorButton = new KColorButton( TQt::black, gbox2 ); + TQWhatsThis::add( m_fontColorButton, i18n("<p>Select the font color to use.")); + gridBox2->addMultiCellWidget(label2, 6, 6, 0, 0); + gridBox2->addMultiCellWidget(m_fontColorButton, 6, 6, 1, 1); + + // ------------------------------------------------------------- + + m_borderText = new TQCheckBox( i18n( "Add border"), gbox2 ); + TQToolTip::add( m_borderText, i18n( "Add a solid border around text using current text color" ) ); + + m_transparentText = new TQCheckBox( i18n( "Semi-transparent"), gbox2 ); + TQToolTip::add( m_transparentText, i18n( "Use semi-transparent text background under image" ) ); + + gridBox2->addMultiCellWidget(m_borderText, 7, 7, 0, 1); + gridBox2->addMultiCellWidget(m_transparentText, 8, 8, 0, 1); + gridBox2->setRowStretch(9, 10); + + setUserAreaWidget(gbox2); + + // ------------------------------------------------------------- + + connect(m_fontChooserWidget, TQ_SIGNAL(fontSelected (const TQFont &)), + this, TQ_SLOT(slotFontPropertiesChanged(const TQFont &))); + + connect(m_fontColorButton, TQ_SIGNAL(changed(const TQColor &)), + this, TQ_SLOT(slotUpdatePreview())); + + connect(m_textEdit, TQ_SIGNAL(textChanged()), + this, TQ_SLOT(slotUpdatePreview())); + + connect(m_alignButtonGroup, TQ_SIGNAL(released(int)), + this, TQ_SLOT(slotAlignModeChanged(int))); + + connect(m_borderText, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotUpdatePreview())); + + connect(m_transparentText, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotUpdatePreview())); + + connect(m_textRotation, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotUpdatePreview())); + + connect(this, TQ_SIGNAL(signalUpdatePreview()), TQ_SLOT(slotUpdatePreview())); + // ------------------------------------------------------------- + + slotUpdatePreview(); +} + +ImageEffect_InsertText::~ImageEffect_InsertText() +{ +} + +void ImageEffect_InsertText::readUserSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("inserttext Tool Dialog"); + TQColor black(0, 0, 0); + TQFont defaultFont; + + int orgW = m_previewWidget->imageIface()->originalWidth(); + int orgH = m_previewWidget->imageIface()->originalHeight(); + + if ( orgW > orgH ) m_defaultSizeFont = (int)(orgH / 8.0); + else m_defaultSizeFont = (int)(orgW / 8.0); + + defaultFont.setPointSize(m_defaultSizeFont); + m_textRotation->setCurrentItem( config->readNumEntry("Text Rotation", 0) ); + m_fontColorButton->setColor(config->readColorEntry("Font Color", &black)); + m_textEdit->setText(config->readEntry("Text String", i18n("Enter your text here!"))); + m_textFont = config->readFontEntry("Font Properties", &defaultFont); + m_fontChooserWidget->setFont(m_textFont); + m_alignTextMode = config->readNumEntry("Text Alignment", ALIGN_LEFT); + m_borderText->setChecked( config->readBoolEntry("Border Text", false) ); + m_transparentText->setChecked( config->readBoolEntry("Transparent Text", false) ); + m_previewWidget->setPositionHint( config->readRectEntry("Position Hint") ); + + static_cast<TQPushButton*>(m_alignButtonGroup->find(m_alignTextMode))->setOn(true); + slotAlignModeChanged(m_alignTextMode); +} + +void ImageEffect_InsertText::writeUserSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("inserttext Tool Dialog"); + + config->writeEntry( "Text Rotation", m_textRotation->currentItem() ); + config->writeEntry( "Font Color", m_fontColorButton->color() ); + config->writeEntry( "Text String", m_textEdit->text() ); + config->writeEntry( "Font Properties", m_textFont ); + config->writeEntry( "Text Alignment", m_alignTextMode ); + config->writeEntry( "Border Text", m_borderText->isChecked() ); + config->writeEntry( "Transparent Text", m_transparentText->isChecked() ); + config->writeEntry( "Position Hint", m_previewWidget->getPositionHint() ); + + config->sync(); +} + +void ImageEffect_InsertText::resetValues() +{ + m_fontColorButton->blockSignals(true); + m_alignButtonGroup->blockSignals(true); + m_fontChooserWidget->blockSignals(true); + + m_textRotation->setCurrentItem(0); // No rotation. + m_fontColorButton->setColor(TQt::black); + TQFont defaultFont; + m_textFont = defaultFont; // Reset to default TDE font. + m_textFont.setPointSize( m_defaultSizeFont ); + m_fontChooserWidget->setFont(m_textFont); + m_borderText->setChecked( false ); + m_transparentText->setChecked( false ); + m_previewWidget->resetEdit(); + static_cast<TQPushButton*>(m_alignButtonGroup->find(ALIGN_LEFT))->setOn(true); + + m_fontChooserWidget->blockSignals(false); + m_fontColorButton->blockSignals(false); + m_alignButtonGroup->blockSignals(false); + slotAlignModeChanged(ALIGN_LEFT); +} + +void ImageEffect_InsertText::slotAlignModeChanged(int mode) +{ + m_alignTextMode = mode; + m_textEdit->selectAll(true); + + switch (m_alignTextMode) + { + case ALIGN_LEFT: + m_textEdit->setAlignment( TQt::AlignLeft ); + break; + + case ALIGN_RIGHT: + m_textEdit->setAlignment( TQt::AlignRight ); + break; + + case ALIGN_CENTER: + m_textEdit->setAlignment( TQt::AlignHCenter ); + break; + + case ALIGN_BLOCK: + m_textEdit->setAlignment( TQt::AlignJustify ); + break; + } + + m_textEdit->selectAll(false); + emit signalUpdatePreview(); +} + +void ImageEffect_InsertText::slotFontPropertiesChanged(const TQFont &font) +{ + m_textFont = font; + emit signalUpdatePreview(); +} + +void ImageEffect_InsertText::slotUpdatePreview() +{ + m_previewWidget->setText(m_textEdit->text(), m_textFont, m_fontColorButton->color(), m_alignTextMode, + m_borderText->isChecked(), m_transparentText->isChecked(), + m_textRotation->currentItem()); +} + +void ImageEffect_InsertText::finalRendering() +{ + accept(); + kapp->setOverrideCursor( KCursor::waitCursor() ); + + Digikam::ImageIface iface(0, 0); + Digikam::DImg dest = m_previewWidget->makeInsertText(); + iface.putOriginalImage(i18n("Insert Text"), dest.bits(), dest.width(), dest.height()); + + kapp->restoreOverrideCursor(); +} + +} // NameSpace DigikamInsertTextImagesPlugin + diff --git a/src/imageplugins/inserttext/imageeffect_inserttext.h b/src/imageplugins/inserttext/imageeffect_inserttext.h new file mode 100644 index 00000000..2b7c204c --- /dev/null +++ b/src/imageplugins/inserttext/imageeffect_inserttext.h @@ -0,0 +1,103 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-14 + * Description : a plugin to insert a text over an image. + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_INSERTEXT_H +#define IMAGEEFFECT_INSERTEXT_H + +// TQt includes. + +#include <tqcolor.h> +#include <tqimage.h> + +// Digikam includes. + +#include "imagedlgbase.h" + +class TQLabel; +class TQFont; +class TQHButtonGroup; +class TQComboBox; +class TQCheckBox; + +class KTextEdit; +class KColorButton; + +namespace DigikamInsertTextImagesPlugin +{ + +class InsertTextWidget; +class FontChooserWidget; + +class ImageEffect_InsertText : public Digikam::ImageDlgBase +{ + TQ_OBJECT + + +public: + + ImageEffect_InsertText(TQWidget *parent); + ~ImageEffect_InsertText(); + +signals: + + void signalUpdatePreview(); + +private slots: + + void slotFontPropertiesChanged(const TQFont &font); + void slotUpdatePreview(); + void slotAlignModeChanged(int mode); + +private: + + void readUserSettings(); + void writeUserSettings(); + void resetValues(); + void finalRendering(); + +private: + + int m_alignTextMode; + int m_defaultSizeFont; + + TQComboBox *m_textRotation; + + TQCheckBox *m_borderText; + TQCheckBox *m_transparentText; + + TQHButtonGroup *m_alignButtonGroup; + + TQFont m_textFont; + + KColorButton *m_fontColorButton; + + FontChooserWidget *m_fontChooserWidget; + + KTextEdit *m_textEdit; + + InsertTextWidget *m_previewWidget; +}; + +} // NameSpace DigikamInsertTextImagesPlugin + +#endif /* IMAGEEFFECT_INSERTEXT_H */ diff --git a/src/imageplugins/inserttext/imageplugin_inserttext.cpp b/src/imageplugins/inserttext/imageplugin_inserttext.cpp new file mode 100644 index 00000000..a7a5ab6b --- /dev/null +++ b/src/imageplugins/inserttext/imageplugin_inserttext.cpp @@ -0,0 +1,70 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-14 + * Description : a plugin to insert a text over an image. + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> + +// Local includes. + +#include "ddebug.h" +#include "inserttexttool.h" +#include "imageplugin_inserttext.h" +#include "imageplugin_inserttext.moc" + +using namespace DigikamInsertTextImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_inserttext, + KGenericFactory<ImagePlugin_InsertText>("digikamimageplugin_inserttext")); + +ImagePlugin_InsertText::ImagePlugin_InsertText(TQObject *parent, const char*, const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_InsertText") +{ + m_insertTextAction = new TDEAction(i18n("Insert Text..."), "inserttext", + SHIFT+CTRL+Key_T, + this, TQ_SLOT(slotInsertText()), + actionCollection(), "imageplugin_inserttext"); + + setXMLFile("digikamimageplugin_inserttext_ui.rc"); + + DDebug() << "ImagePlugin_InsertText plugin loaded" << endl; +} + +ImagePlugin_InsertText::~ImagePlugin_InsertText() +{ +} + +void ImagePlugin_InsertText::setEnabledActions(bool enable) +{ + m_insertTextAction->setEnabled(enable); +} + +void ImagePlugin_InsertText::slotInsertText() +{ + InsertTextTool *tool = new InsertTextTool(this); + loadTool(tool); +} diff --git a/src/imageplugins/inserttext/imageplugin_inserttext.h b/src/imageplugins/inserttext/imageplugin_inserttext.h new file mode 100644 index 00000000..427b47c6 --- /dev/null +++ b/src/imageplugins/inserttext/imageplugin_inserttext.h @@ -0,0 +1,56 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-14 + * Description : a plugin to insert a text over an image. + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_INSERTTEXT_H +#define IMAGEPLUGIN_INSERTTEXT_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_InsertText : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_InsertText(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_InsertText(); + + void setEnabledActions(bool enable); + +private slots: + + void slotInsertText(); + +private: + + TDEAction *m_insertTextAction; +}; + +#endif /* IMAGEPLUGIN_INSERTTEXT_H */ diff --git a/src/imageplugins/inserttext/inserttexttool.cpp b/src/imageplugins/inserttext/inserttexttool.cpp new file mode 100644 index 00000000..3c854896 --- /dev/null +++ b/src/imageplugins/inserttext/inserttexttool.cpp @@ -0,0 +1,336 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-14 + * Description : a plugin to insert a text over an image. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <tqbrush.h> +#include <tqcheckbox.h> +#include <tqcombobox.h> +#include <tqframe.h> +#include <tqhbuttongroup.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqpainter.h> +#include <tqpen.h> +#include <tqpixmap.h> +#include <tqpushbutton.h> +#include <tqtimer.h> +#include <tqtooltip.h> +#include <tqvgroupbox.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <kcolorbutton.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <khelpmenu.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <tdepopupmenu.h> +#include <kstandarddirs.h> +#include <ktextedit.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "dimg.h" +#include "editortoolsettings.h" +#include "fontchooserwidget.h" +#include "imageiface.h" +#include "inserttextwidget.h" +#include "inserttexttool.h" +#include "inserttexttool.moc" + +using namespace Digikam; + +namespace DigikamInsertTextImagesPlugin +{ + +InsertTextTool::InsertTextTool(TQObject* parent) + : EditorTool(parent) +{ + setName("inserttext"); + setToolName(i18n("Insert Text")); + setToolIcon(SmallIcon("inserttext")); + + // ------------------------------------------------------------- + + TQFrame *frame = new TQFrame(0); + frame->setFrameStyle(TQFrame::Panel|TQFrame::Sunken); + TQVBoxLayout* l = new TQVBoxLayout(frame, 5, 0); + m_previewWidget = new InsertTextWidget(480, 320, frame); + l->addWidget(m_previewWidget); + TQWhatsThis::add(m_previewWidget, i18n("<p>This previews the text inserted in the image. " + "You can use the mouse to move the text to the right location.")); + setToolView(frame); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel); + TQGridLayout *grid = new TQGridLayout(m_gboxSettings->plainPage(), 9, 1); + + m_textEdit = new KTextEdit(m_gboxSettings->plainPage()); + m_textEdit->setCheckSpellingEnabled(true); + m_textEdit->setWordWrap(TQTextEdit::NoWrap); + TQWhatsThis::add(m_textEdit, i18n("<p>Here, enter the text you want to insert in your image.")); + + // ------------------------------------------------------------- + + m_fontChooserWidget = new FontChooserWidget(m_gboxSettings->plainPage()); + TQWhatsThis::add( m_textEdit, i18n("<p>Here you can choose the font to be used.")); + + // ------------------------------------------------------------- + + TDEIconLoader icon; + m_alignButtonGroup = new TQHButtonGroup(m_gboxSettings->plainPage()); + + TQPushButton *alignLeft = new TQPushButton(m_alignButtonGroup); + m_alignButtonGroup->insert(alignLeft, ALIGN_LEFT); + alignLeft->setPixmap(icon.loadIcon("format-text-direction-ltr", (TDEIcon::Group) TDEIcon::Small)); + alignLeft->setToggleButton(true); + TQToolTip::add(alignLeft, i18n("Align text to the left")); + + TQPushButton *alignRight = new TQPushButton(m_alignButtonGroup); + m_alignButtonGroup->insert(alignRight, ALIGN_RIGHT); + alignRight->setPixmap(icon.loadIcon("format-text-direction-rtl", (TDEIcon::Group) TDEIcon::Small)); + alignRight->setToggleButton(true); + TQToolTip::add(alignRight, i18n("Align text to the right")); + + TQPushButton *alignCenter = new TQPushButton(m_alignButtonGroup); + m_alignButtonGroup->insert(alignCenter, ALIGN_CENTER); + alignCenter->setPixmap(icon.loadIcon("text_center", (TDEIcon::Group) TDEIcon::Small)); + alignCenter->setToggleButton(true); + TQToolTip::add(alignCenter, i18n("Align text to center")); + + TQPushButton *alignBlock = new TQPushButton(m_alignButtonGroup); + m_alignButtonGroup->insert(alignBlock, ALIGN_BLOCK); + alignBlock->setPixmap(icon.loadIcon("text_block", (TDEIcon::Group) TDEIcon::Small)); + alignBlock->setToggleButton(true); + TQToolTip::add(alignBlock, i18n("Align text to a block")); + + m_alignButtonGroup->setExclusive(true); + m_alignButtonGroup->setFrameShape(TQFrame::NoFrame); + + // ------------------------------------------------------------- + + TQLabel *label1 = new TQLabel(i18n("Rotation:"), m_gboxSettings->plainPage()); + m_textRotation = new TQComboBox(false, m_gboxSettings->plainPage()); + m_textRotation->insertItem(i18n("None")); + m_textRotation->insertItem(i18n("90 Degrees")); + m_textRotation->insertItem(i18n("180 Degrees")); + m_textRotation->insertItem(i18n("270 Degrees")); + TQWhatsThis::add( m_textRotation, i18n("<p>Select the text rotation to use.")); + + // ------------------------------------------------------------- + + TQLabel *label2 = new TQLabel(i18n("Color:"), m_gboxSettings->plainPage()); + m_fontColorButton = new KColorButton( TQt::black, m_gboxSettings->plainPage() ); + TQWhatsThis::add( m_fontColorButton, i18n("<p>Select the font color to use.")); + + // ------------------------------------------------------------- + + m_borderText = new TQCheckBox(i18n("Add border"), m_gboxSettings->plainPage()); + TQToolTip::add(m_borderText, i18n("Add a solid border around text using current text color")); + + m_transparentText = new TQCheckBox(i18n("Semi-transparent"), m_gboxSettings->plainPage()); + TQToolTip::add(m_transparentText, i18n("Use semi-transparent text background under image")); + + grid->addMultiCellWidget(m_textEdit, 0, 2, 0, 1); + grid->addMultiCellWidget(m_fontChooserWidget, 3, 3, 0, 1); + grid->addMultiCellWidget(m_alignButtonGroup, 4, 4, 0, 1); + grid->addMultiCellWidget(label1, 5, 5, 0, 0); + grid->addMultiCellWidget(m_textRotation, 5, 5, 1, 1); + grid->addMultiCellWidget(label2, 6, 6, 0, 0); + grid->addMultiCellWidget(m_fontColorButton, 6, 6, 1, 1); + grid->addMultiCellWidget(m_borderText, 7, 7, 0, 1); + grid->addMultiCellWidget(m_transparentText, 8, 8, 0, 1); + grid->setMargin(0); + grid->setSpacing(m_gboxSettings->spacingHint()); + grid->setRowStretch(9, 10); + + setToolSettings(m_gboxSettings); + init(); + + // ------------------------------------------------------------- + + connect(m_fontChooserWidget, TQ_SIGNAL(fontSelected (const TQFont&)), + this, TQ_SLOT(slotFontPropertiesChanged(const TQFont&))); + + connect(m_fontColorButton, TQ_SIGNAL(changed(const TQColor&)), + this, TQ_SLOT(slotUpdatePreview())); + + connect(m_textEdit, TQ_SIGNAL(textChanged()), + this, TQ_SLOT(slotUpdatePreview())); + + connect(m_alignButtonGroup, TQ_SIGNAL(released(int)), + this, TQ_SLOT(slotAlignModeChanged(int))); + + connect(m_borderText, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotUpdatePreview())); + + connect(m_transparentText, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotUpdatePreview())); + + connect(m_textRotation, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotUpdatePreview())); + + connect(this, TQ_SIGNAL(signalUpdatePreview()), + this, TQ_SLOT(slotUpdatePreview())); + + // ------------------------------------------------------------- + + slotUpdatePreview(); +} + +InsertTextTool::~InsertTextTool() +{ +} + +void InsertTextTool::readSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("inserttext Tool"); + TQColor black(0, 0, 0); + TQFont defaultFont; + + int orgW = m_previewWidget->imageIface()->originalWidth(); + int orgH = m_previewWidget->imageIface()->originalHeight(); + + if (orgW > orgH) m_defaultSizeFont = (int)(orgH / 8.0); + else m_defaultSizeFont = (int)(orgW / 8.0); + + defaultFont.setPointSize(m_defaultSizeFont); + m_textRotation->setCurrentItem(config->readNumEntry("Text Rotation", 0)); + m_fontColorButton->setColor(config->readColorEntry("Font Color", &black)); + m_textEdit->setText(config->readEntry("Text String", i18n("Enter your text here!"))); + m_textFont = config->readFontEntry("Font Properties", &defaultFont); + m_fontChooserWidget->setFont(m_textFont); + m_alignTextMode = config->readNumEntry("Text Alignment", ALIGN_LEFT); + m_borderText->setChecked(config->readBoolEntry("Border Text", false)); + m_transparentText->setChecked(config->readBoolEntry("Transparent Text", false)); + m_previewWidget->setPositionHint(config->readRectEntry("Position Hint")); + + static_cast<TQPushButton*>(m_alignButtonGroup->find(m_alignTextMode))->setOn(true); + slotAlignModeChanged(m_alignTextMode); +} + +void InsertTextTool::writeSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("inserttext Tool"); + + config->writeEntry("Text Rotation", m_textRotation->currentItem()); + config->writeEntry("Font Color", m_fontColorButton->color()); + config->writeEntry("Text String", m_textEdit->text()); + config->writeEntry("Font Properties", m_textFont); + config->writeEntry("Text Alignment", m_alignTextMode); + config->writeEntry("Border Text", m_borderText->isChecked()); + config->writeEntry("Transparent Text", m_transparentText->isChecked()); + config->writeEntry("Position Hint", m_previewWidget->getPositionHint()); + + config->sync(); +} + +void InsertTextTool::slotResetSettings() +{ + m_fontColorButton->blockSignals(true); + m_alignButtonGroup->blockSignals(true); + m_fontChooserWidget->blockSignals(true); + + m_textRotation->setCurrentItem(0); // No rotation. + m_fontColorButton->setColor(TQt::black); + TQFont defaultFont; + m_textFont = defaultFont; // Reset to default TDE font. + m_textFont.setPointSize(m_defaultSizeFont); + m_fontChooserWidget->setFont(m_textFont); + m_borderText->setChecked(false); + m_transparentText->setChecked(false); + m_previewWidget->resetEdit(); + static_cast<TQPushButton*> (m_alignButtonGroup->find(ALIGN_LEFT))->setOn(true); + + m_fontChooserWidget->blockSignals(false); + m_fontColorButton->blockSignals(false); + m_alignButtonGroup->blockSignals(false); + slotAlignModeChanged(ALIGN_LEFT); +} + +void InsertTextTool::slotAlignModeChanged(int mode) +{ + m_alignTextMode = mode; + m_textEdit->selectAll(true); + + switch (m_alignTextMode) + { + case ALIGN_LEFT: + m_textEdit->setAlignment( TQt::AlignLeft ); + break; + + case ALIGN_RIGHT: + m_textEdit->setAlignment( TQt::AlignRight ); + break; + + case ALIGN_CENTER: + m_textEdit->setAlignment( TQt::AlignHCenter ); + break; + + case ALIGN_BLOCK: + m_textEdit->setAlignment( TQt::AlignJustify ); + break; + } + + m_textEdit->selectAll(false); + emit signalUpdatePreview(); +} + +void InsertTextTool::slotFontPropertiesChanged(const TQFont& font) +{ + m_textFont = font; + emit signalUpdatePreview(); +} + +void InsertTextTool::slotUpdatePreview() +{ + m_previewWidget->setText(m_textEdit->text(), m_textFont, m_fontColorButton->color(), m_alignTextMode, + m_borderText->isChecked(), m_transparentText->isChecked(), + m_textRotation->currentItem()); +} + +void InsertTextTool::finalRendering() +{ + kapp->setOverrideCursor(KCursor::waitCursor()); + + ImageIface iface(0, 0); + DImg dest = m_previewWidget->makeInsertText(); + iface.putOriginalImage(i18n("Insert Text"), dest.bits(), dest.width(), dest.height()); + + kapp->restoreOverrideCursor(); +} + +} // NameSpace DigikamInsertTextImagesPlugin diff --git a/src/imageplugins/inserttext/inserttexttool.h b/src/imageplugins/inserttext/inserttexttool.h new file mode 100644 index 00000000..c148aa60 --- /dev/null +++ b/src/imageplugins/inserttext/inserttexttool.h @@ -0,0 +1,111 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-14 + * Description : a plugin to insert a text over an image. + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +#ifndef INSERTEXTTOOL_H +#define INSERTEXTTOOL_H + +// TQt includes. + +#include <tqfont.h> +#include <tqcolor.h> +#include <tqimage.h> + +// Digikam includes. + +#include "editortool.h" + +class TQLabel; +class TQFont; +class TQHButtonGroup; +class TQComboBox; +class TQCheckBox; + +class KTextEdit; +class KColorButton; + +namespace Digikam +{ +class EditorToolSettings; +} + +namespace DigikamInsertTextImagesPlugin +{ + +class InsertTextWidget; +class FontChooserWidget; + +class InsertTextTool : public Digikam::EditorTool +{ + TQ_OBJECT + + +public: + + InsertTextTool(TQObject *parent); + ~InsertTextTool(); + +signals: + + void signalUpdatePreview(); + +private slots: + + void slotFontPropertiesChanged(const TQFont& font); + void slotUpdatePreview(); + void slotAlignModeChanged(int mode); + void slotResetSettings(); + +private: + + void readSettings(); + void writeSettings(); + void finalRendering(); + +private: + + int m_alignTextMode; + int m_defaultSizeFont; + + TQComboBox *m_textRotation; + + TQCheckBox *m_borderText; + TQCheckBox *m_transparentText; + + TQHButtonGroup *m_alignButtonGroup; + + TQFont m_textFont; + + KColorButton *m_fontColorButton; + + KTextEdit *m_textEdit; + + Digikam::EditorToolSettings *m_gboxSettings; + + FontChooserWidget *m_fontChooserWidget; + + InsertTextWidget *m_previewWidget; +}; + +} // NameSpace DigikamInsertTextImagesPlugin + +#endif /* INSERTEXTTOOL_H */ diff --git a/src/imageplugins/inserttext/inserttextwidget.cpp b/src/imageplugins/inserttext/inserttextwidget.cpp new file mode 100644 index 00000000..dc5b65f4 --- /dev/null +++ b/src/imageplugins/inserttext/inserttextwidget.cpp @@ -0,0 +1,622 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-14 + * Description : a widget to insert a text over an image. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <cstdio> +#include <cmath> + +// TQt includes. + +#include <tqpainter.h> +#include <tqfont.h> +#include <tqfontmetrics.h> + +// KDE includes. + +#include <kstandarddirs.h> +#include <kcursor.h> +#include <tdeglobal.h> + +// Digikam includes. + +#include "imageiface.h" + +// Local includes. + +#include "inserttextwidget.h" +#include "inserttextwidget.moc" + +namespace DigikamInsertTextImagesPlugin +{ + +InsertTextWidget::InsertTextWidget(int w, int h, TQWidget *parent) + : TQWidget(parent, 0, TQt::WDestructiveClose) +{ + m_currentMoving = false; + + m_iface = new Digikam::ImageIface(w, h); + m_data = m_iface->getPreviewImage(); + m_w = m_iface->previewWidth(); + m_h = m_iface->previewHeight(); + m_pixmap = new TQPixmap(w, h); + m_pixmap->fill(colorGroup().background()); + + setBackgroundMode(TQt::NoBackground); + setMinimumSize(w, h); + setMouseTracking(true); + + m_rect = TQRect(width()/2-m_w/2, height()/2-m_h/2, m_w, m_h); + m_textRect = TQRect(); + + m_backgroundColor = TQColor(0xCC, 0xCC, 0xCC); + m_transparency = 210; +} + +InsertTextWidget::~InsertTextWidget() +{ + delete [] m_data; + delete m_iface; + delete m_pixmap; +} + +Digikam::ImageIface* InsertTextWidget::imageIface() +{ + return m_iface; +} + +void InsertTextWidget::resetEdit() +{ + // signal this needs to be filled by makePixmap + m_textRect = TQRect(); + makePixmap(); + repaint(false); +} + +void InsertTextWidget::setText(TQString text, TQFont font, TQColor color, int alignMode, + bool border, bool transparent, int rotation) +{ + m_textString = text; + m_textColor = color; + m_textBorder = border; + m_textTransparent = transparent; + m_textRotation = rotation; + + switch (alignMode) + { + case ALIGN_LEFT: + m_alignMode = TQt::AlignLeft; + break; + + case ALIGN_RIGHT: + m_alignMode = TQt::AlignRight; + break; + + case ALIGN_CENTER: + m_alignMode = TQt::AlignHCenter; + break; + + case ALIGN_BLOCK: + m_alignMode = TQt::AlignJustify; + break; + } + + // Center text if top left corner text area is not visible. + + /* + if ( m_textFont.pointSize() != font.pointSize() && + !rect().contains( m_textRect.x(), m_textRect.y() ) ) + { + m_textFont = font; + resetEdit(); + return; + } + */ + + m_textFont = font; + + makePixmap(); + repaint(false); +} + +void InsertTextWidget::setPositionHint(TQRect hint) +{ + // interpreted by composeImage + m_positionHint = hint; + if (m_textRect.isValid()) + { + // invalidate current position so that hint is certainly interpreted + m_textRect = TQRect(); + makePixmap(); + repaint(); + } +} + +TQRect InsertTextWidget::getPositionHint() +{ + TQRect hint; + if (m_textRect.isValid()) + { + // We normalize on the size of the image, but we store as int. Precision loss is no problem. + hint.setX( (int) ((float)(m_textRect.x() - m_rect.x()) / (float)m_rect.width() * 10000.0) ); + hint.setY( (int) ((float)(m_textRect.y() - m_rect.y()) / (float)m_rect.height() * 10000.0) ); + hint.setWidth( (int) ((float)m_textRect.width() / (float)m_rect.width() * 10000.0) ); + hint.setHeight( (int) ((float)m_textRect.height() / (float)m_rect.height() * 10000.0) ); + } + return hint; +} + +Digikam::DImg InsertTextWidget::makeInsertText(void) +{ + int orgW = m_iface->originalWidth(); + int orgH = m_iface->originalHeight(); + float ratioW = (float)orgW/(float)m_w; + float ratioH = (float)orgH/(float)m_h; + + int x, y; + if (m_textRect.isValid()) + { + // convert from widget to image coordinates, then to original size + x = lroundf( (m_textRect.x() - m_rect.x()) * ratioW); + y = lroundf( (m_textRect.y() - m_rect.y()) * ratioH); + } + else + { + x = -1; + y = -1; + } + + // Get original image + Digikam::DImg image = m_iface->getOriginalImg()->copy(); + + int borderWidth = TQMAX(1, lroundf(ratioW)); + // compose and draw result on image + composeImage(&image, 0, x, y, + m_textFont, m_textFont.pointSizeFloat(), + m_textRotation, m_textColor, m_alignMode, m_textString, + m_textTransparent, m_backgroundColor, + m_textBorder ? BORDER_NORMAL : BORDER_NONE, borderWidth, borderWidth); + + return image; +} + +void InsertTextWidget::makePixmap(void) +{ + int orgW = m_iface->originalWidth(); + int orgH = m_iface->originalHeight(); + float ratioW = (float)m_w / (float)orgW; + float ratioH = (float)m_h / (float)orgH; + + int x, y; + if (m_textRect.isValid()) + { + // convert from widget to image coordinates + x = m_textRect.x() - m_rect.x(); + y = m_textRect.y() - m_rect.y(); + } + else + { + x = -1; + y = -1; + } + + // get preview image data + uchar *data = m_iface->getPreviewImage(); + Digikam::DImg image(m_iface->previewWidth(), m_iface->previewHeight(), m_iface->previewSixteenBit(), + m_iface->previewHasAlpha(), data); + delete [] data; + + // paint pixmap for drawing this widget + // First, fill with background color + m_pixmap->fill(colorGroup().background()); + TQPainter p(m_pixmap); + // Convert image to pixmap and draw it + TQPixmap imagePixmap = image.convertToPixmap(); + p.drawPixmap(m_rect.x(), m_rect.y(), + imagePixmap, 0, 0, imagePixmap.width(), imagePixmap.height()); + + // prepare painter for use by compose image + p.setClipRect(m_rect); + p.translate(m_rect.x(), m_rect.y()); + + // compose image and draw result directly on pixmap, with correct offset + TQRect textRect = composeImage(&image, &p, x, y, + m_textFont, m_textFont.pointSizeFloat() * ((ratioW > ratioH) ? ratioW : ratioH), + m_textRotation, m_textColor, m_alignMode, m_textString, + m_textTransparent, m_backgroundColor, + m_textBorder ? BORDER_NORMAL : BORDER_SUPPORT, 1, 1); + + p.end(); + + // store new text rectangle + // convert from image to widget coordinates + m_textRect.setX(textRect.x() + m_rect.x()); + m_textRect.setY(textRect.y() + m_rect.y()); + m_textRect.setSize(textRect.size()); +} + +/* + Take data from image, draw text at x|y with specified parameters. + If destPainter is null, draw to image, + if destPainter is not null, draw directly using the painter. + Returns modified area of image. +*/ +TQRect InsertTextWidget::composeImage(Digikam::DImg *image, TQPainter *destPainter, + int x, int y, + TQFont font, float pointSize, int textRotation, TQColor textColor, + int alignMode, const TQString &textString, + bool transparentBackground, TQColor backgroundColor, + BorderMode borderMode, int borderWidth, int spacing) +{ + /* + The problem we have to solve is that we have no pixel access to font rendering, + we have to let TQt do the drawing. On the other hand we need to support 16 bit, which + cannot be done with TQPixmap. + The current solution cuts out the text area, lets TQt do its drawing, converts back and blits to original. + */ + Digikam::DColorComposer *composer = Digikam::DColorComposer::getComposer(Digikam::DColorComposer::PorterDuffNone); + + int maxWidth, maxHeight; + if (x == -1 && y == -1) + { + maxWidth = image->width(); + maxHeight = image->height(); + } + else + { + maxWidth = image->width() - x; + maxHeight = image->height() - y; + } + + // find out size of the area that we are drawing to + font.setPointSizeFloat(pointSize); + TQFontMetrics fontMt( font ); + TQRect fontRect = fontMt.boundingRect(0, 0, maxWidth, maxHeight, 0, textString); + + int fontWidth, fontHeight; + + switch(textRotation) + { + case ROTATION_NONE: + case ROTATION_180: + default: + fontWidth = fontRect.width(); + fontHeight = fontRect.height(); + break; + + case ROTATION_90: + case ROTATION_270: + fontWidth = fontRect.height(); + fontHeight = fontRect.width(); + break; + } + + // x, y == -1 means that we have to find a good initial position for the text here + if (x == -1 && y == -1) + { + // was a valid position hint stored from last use? + if (m_positionHint.isValid()) + { + // We assume that people tend to orient text along the edges, + // so we do some guessing so that positions such as "in the lower right corner" + // will be remembered across different image sizes. + + // get relative positions + float fromTop = (float)m_positionHint.top() / 10000.0; + float fromBottom = 1.0 - (float)m_positionHint.bottom() / 10000.0; + float fromLeft = (float)m_positionHint.left() / 10000.0; + float fromRight = 1.0 - (float)m_positionHint.right() / 10000.0; + + // calculate horizontal position + if (fromLeft < fromRight) + { + x = (int)(fromLeft * maxWidth); + + // we are placing from the smaller distance, + // so if now the larger distance is actually too small, + // fall back to standard placement, nothing to lose. + if (x + fontWidth > maxWidth) + x = TQMAX( (maxWidth - fontWidth) / 2, 0); + } + else + { + x = maxWidth - (int)(fromRight * maxWidth) - fontWidth; + if ( x < 0 ) + x = TQMAX( (maxWidth - fontWidth) / 2, 0); + } + + // calculate vertical position + if (fromTop < fromBottom) + { + y = (int)(fromTop * maxHeight); + if (y + fontHeight > maxHeight) + y = TQMAX( (maxHeight - fontHeight) / 2, 0); + } + else + { + y = maxHeight - (int)(fromBottom * maxHeight) - fontHeight; + if ( y < 0 ) + y = TQMAX( (maxHeight - fontHeight) / 2, 0); + } + + if (! TQRect(x, y, fontWidth, fontHeight). + intersects(TQRect(0, 0, maxWidth, maxHeight)) ) + { + // emergency fallback - nothing is visible + x = TQMAX( (maxWidth - fontWidth) / 2, 0); + y = TQMAX( (maxHeight - fontHeight) / 2, 0); + } + + // invalidate position hint, use only once + m_positionHint = TQRect(); + } + else + { + // use standard position + x = TQMAX( (maxWidth - fontWidth) / 2, 0); + y = TQMAX( (maxHeight - fontHeight) / 2, 0); + } + } + + // create a rectangle relative to image + TQRect drawRect( x, y, fontWidth + 2 * borderWidth + 2 * spacing, fontHeight + 2 * borderWidth + 2 * spacing); + + // create a rectangle relative to textArea, excluding the border + TQRect textAreaBackgroundRect( borderWidth, borderWidth, fontWidth + 2 * spacing, fontHeight + 2 * spacing); + + // create a rectangle relative to textArea, excluding the border and spacing + TQRect textAreaTextRect( borderWidth + spacing, borderWidth + spacing, fontWidth, fontHeight ); + + // create a rectangle relative to textArea, including the border, + // for drawing the rectangle, taking into account that the width of the TQPen goes in and out in equal parts + TQRect textAreaDrawRect( borderWidth / 2, borderWidth / 2, fontWidth + borderWidth + 2 * spacing, + fontHeight + borderWidth + 2 * spacing ); + + // cut out the text area + Digikam::DImg textArea = image->copy(drawRect); + + if (textArea.isNull()) + return TQRect(); + + // compose semi-transparent background over textArea + if (transparentBackground) + { + Digikam::DImg transparentLayer(textAreaBackgroundRect.width(), textAreaBackgroundRect.height(), textArea.sixteenBit(), true); + Digikam::DColor transparent(backgroundColor); + transparent.setAlpha(m_transparency); + if (image->sixteenBit()) + transparent.convertToSixteenBit(); + transparentLayer.fill(transparent); + textArea.bitBlendImage(composer, &transparentLayer, 0, 0, transparentLayer.width(), transparentLayer.height(), + textAreaBackgroundRect.x(), textAreaBackgroundRect.y()); + } + + Digikam::DImg textNotDrawn; + if (textArea.sixteenBit()) + { + textNotDrawn = textArea.copy(); + textNotDrawn.convertToEightBit(); + } + else + textNotDrawn = textArea; + + // We have no direct pixel access to font rendering, so now we need to use TQt/X11 for the drawing + + // convert text area to pixmap + TQPixmap pixmap = textNotDrawn.convertToPixmap(); + // paint on pixmap + TQPainter p(&pixmap); + p.setPen( TQPen(textColor, 1) ) ; + p.setFont( font ); + p.save(); + + // translate to origin of text, leaving space for the border + p.translate(textAreaTextRect.x(), textAreaTextRect.y()); + + switch(textRotation) + { + case ROTATION_NONE: + p.drawText( 0, 0, textAreaTextRect.width(), + textAreaTextRect.height(), alignMode, textString ); + break; + case ROTATION_90: + p.translate(textAreaTextRect.width(), 0); + p.rotate(90.0); + p.drawText( 0, 0, textAreaTextRect.height(), textAreaTextRect.width(), + alignMode, textString ); + break; + case ROTATION_180: + p.translate(textAreaTextRect.width(), textAreaTextRect.height()); + p.rotate(180.0); + p.drawText( 0, 0, textAreaTextRect.width(), textAreaTextRect.height(), + alignMode, textString ); + break; + case ROTATION_270: + p.translate(0, textAreaTextRect.height()); + p.rotate(270.0); + p.drawText( 0, 0, textAreaTextRect.height(), textAreaTextRect.width(), + alignMode, textString ); + break; + } + + p.restore(); + + // Drawing rectangle around text. + + if (borderMode == BORDER_NORMAL) // Decorative border using text color. + { + p.setPen( TQPen(textColor, borderWidth, TQt::SolidLine, + TQt::SquareCap, TQt::RoundJoin) ) ; + p.drawRect(textAreaDrawRect); + } + else if (borderMode == BORDER_SUPPORT) // Make simple dot line border to help user. + { + p.setPen(TQPen(TQt::white, 1, TQt::SolidLine)); + p.drawRect(textAreaDrawRect); + p.setPen(TQPen(TQt::red, 1, TQt::DotLine)); + p.drawRect(textAreaDrawRect); + } + p.end(); + + if (!destPainter) + { + // convert to TQImage, then to DImg + TQImage pixmapImage = pixmap.convertToImage(); + Digikam::DImg textDrawn(pixmapImage.width(), pixmapImage.height(), false, true, pixmapImage.bits()); + + // This does not work: during the conversion, colors are altered significantly (diffs of 1 to 10 in each component), + // so we cannot find out which pixels have actually been touched. + /* + // Compare the result of drawing with the previous version. + // Set all unchanged pixels to transparent + Digikam::DColor color, ncolor; + uchar *ptr, *nptr; + ptr = textDrawn.bits(); + nptr = textNotDrawn.bits(); + int bytesDepth = textDrawn.bytesDepth(); + int numPixels = textDrawn.width() * textDrawn.height(); + for (int i = 0; i < numPixels; i++, ptr+= bytesDepth, nptr += bytesDepth) + { + color.setColor(ptr, false); + ncolor.setColor(nptr, false); + if ( color.red() == ncolor.red() && + color.green() == ncolor.green() && + color.blue() == ncolor.blue()) + { + color.setAlpha(0); + color.setPixel(ptr); + } + } + // convert to 16 bit if needed + */ + textDrawn.convertToDepthOfImage(&textArea); + + // now compose to original: only pixels affected by drawing text and border are changed, not whole area + textArea.bitBlendImage(composer, &textDrawn, 0, 0, textDrawn.width(), textDrawn.height(), 0, 0); + + // copy result to original image + image->bitBltImage(&textArea, drawRect.x(), drawRect.y()); + } + else + { + destPainter->drawPixmap(drawRect.x(), drawRect.y(), pixmap, 0, 0, pixmap.width(), pixmap.height()); + } + + delete composer; + + return drawRect; +} + +void InsertTextWidget::paintEvent( TQPaintEvent * ) +{ + bitBlt(this, 0, 0, m_pixmap); +} + +void InsertTextWidget::resizeEvent(TQResizeEvent * e) +{ + blockSignals(true); + delete m_pixmap; + + int w = e->size().width(); + int h = e->size().height(); + + int textX = m_textRect.x() - m_rect.x(); + int textY = m_textRect.y() - m_rect.y(); + int old_w = m_w; + int old_h = m_h; + m_data = m_iface->setPreviewImageSize(w, h); + m_w = m_iface->previewWidth(); + m_h = m_iface->previewHeight(); + + m_pixmap = new TQPixmap(w, h); + m_rect = TQRect(w/2-m_w/2, h/2-m_h/2, m_w, m_h); + + if (m_textRect.isValid()) + { + int textWidth = m_textRect.width(); + int textHeight = m_textRect.height(); + + textX = lroundf( textX * (float)m_w / (float)old_w ); + textY = lroundf( textY * (float)m_h / (float)old_h ); + textWidth = lroundf(textWidth * (float)m_w / (float)old_w ); + textHeight = lroundf(textHeight * (float)m_h / (float)old_h ); + + m_textRect.setX(textX + m_rect.x()); + m_textRect.setY(textY + m_rect.y()); + m_textRect.setWidth(textWidth); + m_textRect.setHeight(textHeight); + makePixmap(); + } + + blockSignals(false); +} + +void InsertTextWidget::mousePressEvent ( TQMouseEvent * e ) +{ + if ( e->button() == TQt::LeftButton && + m_textRect.contains( e->x(), e->y() ) ) + { + m_xpos = e->x(); + m_ypos = e->y(); + setCursor ( KCursor::sizeAllCursor() ); + m_currentMoving = true; + } +} + +void InsertTextWidget::mouseReleaseEvent ( TQMouseEvent * ) +{ + setCursor ( KCursor::arrowCursor() ); + m_currentMoving = false; +} + +void InsertTextWidget::mouseMoveEvent ( TQMouseEvent * e ) +{ + if ( rect().contains( e->x(), e->y() ) ) + { + if ( e->state() == TQt::LeftButton && m_currentMoving ) + { + uint newxpos = e->x(); + uint newypos = e->y(); + + m_textRect.moveBy(newxpos - m_xpos, newypos - m_ypos); + + makePixmap(); + repaint(false); + + m_xpos = newxpos; + m_ypos = newypos; + setCursor( KCursor::handCursor() ); + } + else if ( m_textRect.contains( e->x(), e->y() ) ) + { + setCursor ( KCursor::sizeAllCursor() ); + } + else + { + setCursor ( KCursor::arrowCursor() ); + } + } +} + +} // NameSpace DigikamInsertTextImagesPlugin diff --git a/src/imageplugins/inserttext/inserttextwidget.h b/src/imageplugins/inserttext/inserttextwidget.h new file mode 100644 index 00000000..bbce9189 --- /dev/null +++ b/src/imageplugins/inserttext/inserttextwidget.h @@ -0,0 +1,156 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-14 + * Description : a widget to insert a text over an image. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef INSERTTEXTWIDGET_H +#define INSERTTEXTWIDGET_H + +// TQt includes. + +#include <tqwidget.h> +#include <tqimage.h> +#include <tqrect.h> +#include <tqsize.h> +#include <tqpixmap.h> +#include <tqstring.h> +#include <tqfont.h> +#include <tqcolor.h> + +// KDE includes. + +#include <kurl.h> + +// Digikam includes. + +#include "dimg.h" + +class TQPixmap; + +namespace Digikam +{ +class ImageIface; +} + +namespace DigikamInsertTextImagesPlugin +{ + +enum Action +{ + ALIGN_LEFT=0, + ALIGN_RIGHT, + ALIGN_CENTER, + ALIGN_BLOCK, + BORDER_TEXT, + TRANSPARENT_TEXT +}; + +enum TextRotation +{ + ROTATION_NONE=0, + ROTATION_90, + ROTATION_180, + ROTATION_270 +}; + +enum BorderMode +{ + BORDER_NONE, + BORDER_SUPPORT, + BORDER_NORMAL +}; + +class InsertTextWidget : public TQWidget +{ +TQ_OBJECT + + +public: + + InsertTextWidget(int w, int h, TQWidget *parent=0); + ~InsertTextWidget(); + + Digikam::ImageIface* imageIface(); + Digikam::DImg makeInsertText(void); + + void setText(TQString text, TQFont font, TQColor color, int alignMode, + bool border, bool transparent, int rotation); + void resetEdit(void); + + void setPositionHint(TQRect hint); + TQRect getPositionHint(); + +protected: + + void paintEvent(TQPaintEvent *e); + void resizeEvent(TQResizeEvent * e); + void mousePressEvent(TQMouseEvent * e); + void mouseReleaseEvent(TQMouseEvent * e); + void mouseMoveEvent(TQMouseEvent * e); + + void makePixmap(void); + TQRect composeImage(Digikam::DImg *image, TQPainter *destPainter, + int x, int y, + TQFont font, float pointSize, int textRotation, TQColor textColor, + int alignMode, const TQString &textString, + bool transparentBackground, TQColor backgroundColor, + BorderMode borderMode, int borderWidth, int spacing); + +private: + + bool m_currentMoving; + bool m_textBorder; + bool m_textTransparent; + + int m_alignMode; + int m_textRotation; + + uchar *m_data; + int m_w; + int m_h; + + int m_xpos; + int m_ypos; + + int m_transparency; + + TQPixmap *m_pixmap; + + TQRect m_rect; + TQRect m_textRect; + + TQString m_textString; + + TQFont m_textFont; + + TQColor m_textColor; + + TQColor m_backgroundColor; + + TQRect m_positionHint; + + Digikam::ImageIface *m_iface; +}; + +} // NameSpace DigikamInsertTextImagesPlugin + +#endif /* INSERTTEXTWIDGET_H */ diff --git a/src/imageplugins/lensdistortion/Makefile.am b/src/imageplugins/lensdistortion/Makefile.am new file mode 100644 index 00000000..cd157aa1 --- /dev/null +++ b/src/imageplugins/lensdistortion/Makefile.am @@ -0,0 +1,34 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_lensdistortion_la_SOURCES = imageplugin_lensdistortion.cpp \ + lensdistortiontool.cpp \ + lensdistortion.cpp pixelaccess.cpp + +digikamimageplugin_lensdistortion_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_lensdistortion_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_lensdistortion.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_lensdistortion.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_lensdistortion_ui.rc diff --git a/src/imageplugins/lensdistortion/digikamimageplugin_lensdistortion.desktop b/src/imageplugins/lensdistortion/digikamimageplugin_lensdistortion.desktop new file mode 100644 index 00000000..da529559 --- /dev/null +++ b/src/imageplugins/lensdistortion/digikamimageplugin_lensdistortion.desktop @@ -0,0 +1,50 @@ +[Desktop Entry] +Name=ImagePlugin_LensDistortion +Name[bg]=Приставка за снимки - Аберации от обективи +Name[da]=Billedplugin_Linseforvrængning +Name[el]=ΠρόσθετοΕικόνας_ΠαραμόρφωσηΦακών +Name[fi]=Linssivääristymä +Name[hr]=Izobličena leća +Name[it]=PluginImmagini_DistorsioneLenticolare +Name[nl]=Afbeeldingsplugin_Lensafwijking +Name[sr]=Изобличење сочива +Name[sr@Latn]=Izobličenje sočiva +Name[sv]=Insticksprogram för linsförvrängning +Name[tr]=ResimEklentisi_MercekÇarpıtması +Name[xx]=xxImagePlugin_LensDistortionxx +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=Spherical aberration image correction plugin for digiKam +Comment[bg]=Приставка на digiKam за корекция на аберации от обективи в снимките +Comment[ca]=Connector pel digiKam per corregir l'aberració esfèrica d'una imatge +Comment[da]=Plugin til korrigering af sfærisk afvigelse for Digikam +Comment[de]=digiKam-Modul zur Reduzierung kugelförmiger Verzerrung durch Linsen +Comment[el]=Πρόσθετο διόρθωσης εικόνας σφαιρικής παρέκκλισης για το digiKam +Comment[es]=Plugin para digiKam para corrección de aberraciones de imagen esféricas +Comment[et]=DigiKami sfäärilise aberratsiooni korrigeerimise plugin +Comment[fa]=وصلۀ اصلاح تصویر انحراف کروی برای digiKam +Comment[fi]=Palloaberraatio (kalansilmävääristymä) +Comment[gl]=Un plugin de digiKam para corrixir a aberrazón esférica da imaxe +Comment[hr]=digiKam dodatak za ispravljanje kružne aberacije +Comment[is]=Íforrit fyrir digiKam sem minnkar hringskekkingu linsu +Comment[it]=Plugin di correzione dell'aberrazione sferica delle immagini per digiKam +Comment[ja]=digiKam 球面収差補正プラグイン +Comment[nds]=digiKam-Moduul för't Richten vun Kugel-Vertarren +Comment[nl]=Digikam-plugin voor het corrigeren van bolvormige afwijkingen +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਗੋਲਾ ਐਬੱਰੇਸ਼ਨ ਚਿੱਤਰ ਪਰਭਾਵ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam korygująca aberrację sferyczną +Comment[pt]=Um 'plugin' do digiKam para corrigir a aberração esférica da imagem +Comment[pt_BR]=Um 'plugin' do digiKam para corrigir a aberração esférica da imagem +Comment[ru]=Модуль digiKam коррекции сферических искажений +Comment[sk]=digiKam plugin na korekciu sférickej aberácie šošovky +Comment[sr]=digiKam-ов прикључак за исправљање сферног искривљења слике +Comment[sr@Latn]=digiKam-ov priključak za ispravljanje sfernog iskrivljenja slike +Comment[sv]=Digikam insticksprogram för korrigering av sfärisk avvikelse i bild +Comment[tr]=digiKam için resim küresel sapma düzeltme eklentisi +Comment[uk]=Втулок коректування сферичних спотворень для digiKam +Comment[vi]=Phần bổ sung sửa quang sai hình cầu ảnh cho digiKam +Comment[xx]=xxSpherical aberration image correction plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_lensdistortion +author=Gilles Caulier, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/lensdistortion/digikamimageplugin_lensdistortion_ui.rc b/src/imageplugins/lensdistortion/digikamimageplugin_lensdistortion_ui.rc new file mode 100644 index 00000000..4705467e --- /dev/null +++ b/src/imageplugins/lensdistortion/digikamimageplugin_lensdistortion_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="5" name="digikamimageplugin_lensdistortion" > + + <MenuBar> + + <Menu name="Enhance" ><text>Enh&ance</text> + <Action name="imageplugin_lensdistortion" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action name="imageplugin_lensdistortion" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/lensdistortion/imageeffect_lensdistortion.cpp b/src/imageplugins/lensdistortion/imageeffect_lensdistortion.cpp new file mode 100644 index 00000000..89420a9c --- /dev/null +++ b/src/imageplugins/lensdistortion/imageeffect_lensdistortion.cpp @@ -0,0 +1,317 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-27 + * Description : a plugin to reduce lens distorsions to an image. + * + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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++ include. + +#include <cstring> +#include <cmath> +#include <cstdlib> + +// TQt includes. + +#include <tqlabel.h> +#include <tqwhatsthis.h> +#include <tqlayout.h> +#include <tqpixmap.h> +#include <tqpainter.h> +#include <tqbrush.h> +#include <tqpen.h> + +// KDE includes. + +#include <tdelocale.h> +#include <tdeconfig.h> +#include <tdeaboutdata.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <kstandarddirs.h> +#include <knuminput.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "lensdistortion.h" +#include "imageeffect_lensdistortion.h" +#include "imageeffect_lensdistortion.moc" + +namespace DigikamLensDistortionImagesPlugin +{ + +ImageEffect_LensDistortion::ImageEffect_LensDistortion(TQWidget* parent) + : Digikam::ImageGuideDlg(parent, i18n("Lens Distortion Correction"), + "lensdistortion", false, true, true, + Digikam::ImageGuideWidget::HVGuideMode) +{ + TQString whatsThis; + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Lens Distortion Correction"), + digikam_version, + I18N_NOOP("A digiKam image plugin to reduce spherical aberration caused " + "by a lens to an image."), + TDEAboutData::License_GPL, + "(c) 2004-2006, Gilles Caulier\n" + "(c) 2006-2008, Gilles Caulier and Marcel Wiesweg", + 0, + "http://www.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + about->addAuthor("Marcel Wiesweg", I18N_NOOP("Developer"), + "marcel dot wiesweg at gmx dot de"); + + about->addAuthor("David Hodson", I18N_NOOP("Lens distortion correction algorithm."), + "hodsond at acm dot org"); + + setAboutData(about); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(plainPage()); + TQGridLayout* gridSettings = new TQGridLayout( gboxSettings, 8, 1, spacingHint()); + + m_maskPreviewLabel = new TQLabel( gboxSettings ); + m_maskPreviewLabel->setAlignment ( TQt::AlignHCenter | TQt::AlignVCenter ); + TQWhatsThis::add( m_maskPreviewLabel, i18n("<p>You can see here a thumbnail preview of the distortion correction " + "applied to a cross pattern.") ); + gridSettings->addMultiCellWidget(m_maskPreviewLabel, 0, 0, 0, 1); + + // ------------------------------------------------------------- + + TQLabel *label1 = new TQLabel(i18n("Main:"), gboxSettings); + + m_mainInput = new KDoubleNumInput(gboxSettings); + m_mainInput->setPrecision(1); + m_mainInput->setRange(-100.0, 100.0, 0.1, true); + TQWhatsThis::add( m_mainInput, i18n("<p>This value controls the amount of distortion. Negative values correct lens barrel " + "distortion, while positive values correct lens pincushion distortion.")); + + gridSettings->addMultiCellWidget(label1, 1, 1, 0, 1); + gridSettings->addMultiCellWidget(m_mainInput, 2, 2, 0, 1); + + // ------------------------------------------------------------- + + TQLabel *label2 = new TQLabel(i18n("Edge:"), gboxSettings); + + m_edgeInput = new KDoubleNumInput(gboxSettings); + m_edgeInput->setPrecision(1); + m_edgeInput->setRange(-100.0, 100.0, 0.1, true); + TQWhatsThis::add( m_edgeInput, i18n("<p>This value controls in the same manner as the Main control, but has more effect " + "at the edges of the image than at the center.")); + + gridSettings->addMultiCellWidget(label2, 3, 3, 0, 1); + gridSettings->addMultiCellWidget(m_edgeInput, 4, 4, 0, 1); + + // ------------------------------------------------------------- + + TQLabel *label3 = new TQLabel(i18n("Zoom:"), gboxSettings); + + m_rescaleInput = new KDoubleNumInput(gboxSettings); + m_rescaleInput->setPrecision(1); + m_rescaleInput->setRange(-100.0, 100.0, 0.1, true); + TQWhatsThis::add( m_rescaleInput, i18n("<p>This value rescales the overall image size.")); + + gridSettings->addMultiCellWidget(label3, 5, 5, 0, 1); + gridSettings->addMultiCellWidget(m_rescaleInput, 6, 6, 0, 1); + + // ------------------------------------------------------------- + + TQLabel *label4 = new TQLabel(i18n("Brighten:"), gboxSettings); + + m_brightenInput = new KDoubleNumInput(gboxSettings); + m_brightenInput->setPrecision(1); + m_brightenInput->setRange(-100.0, 100.0, 0.1, true); + TQWhatsThis::add( m_brightenInput, i18n("<p>This value adjusts the brightness in image corners.")); + + gridSettings->addMultiCellWidget(label4, 7, 7, 0, 1); + gridSettings->addMultiCellWidget(m_brightenInput, 8, 8, 0, 1); + + setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + connect(m_mainInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_edgeInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_rescaleInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_brightenInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + // ------------------------------------------------------------- + + /* Calc transform preview. + We would like a checkered area to demonstrate the effect. + We do not have any drawing support in DImg, so we let TQt draw. + First we create a white TQImage. We convert this to a TQPixmap, + on which we can draw. Then we convert back to TQImage, + convert the TQImage to a DImg which we only need to create once, here. + Later, we apply the effect on a copy and convert the DImg to TQPixmap. + Longing for TQt4 where we can paint directly on the TQImage... + */ + + TQImage preview(120, 120, 32); + memset(preview.bits(), 255, preview.numBytes()); + TQPixmap pix (preview); + TQPainter pt(&pix); + pt.setPen( TQPen(TQt::black, 1) ); + pt.fillRect( 0, 0, pix.width(), pix.height(), TQBrush(TQt::black, TQt::CrossPattern) ); + pt.drawRect( 0, 0, pix.width(), pix.height() ); + pt.end(); + TQImage preview2(pix.convertToImage()); + m_previewRasterImage = Digikam::DImg(preview2.width(), preview2.height(), false, false, preview2.bits()); +} + +ImageEffect_LensDistortion::~ImageEffect_LensDistortion() +{ +} + +void ImageEffect_LensDistortion::readUserSettings(void) +{ + TDEConfig *config = kapp->config(); + config->setGroup("lensdistortion Tool Dialog"); + + m_mainInput->blockSignals(true); + m_edgeInput->blockSignals(true); + m_rescaleInput->blockSignals(true); + m_brightenInput->blockSignals(true); + + m_mainInput->setValue(config->readDoubleNumEntry("2nd Order Distortion", 0.0)); + m_edgeInput->setValue(config->readDoubleNumEntry("4th Order Distortion",0.0)); + m_rescaleInput->setValue(config->readDoubleNumEntry("Zoom Factor", 0.0)); + m_brightenInput->setValue(config->readDoubleNumEntry("Brighten", 0.0)); + + m_mainInput->blockSignals(false); + m_edgeInput->blockSignals(false); + m_rescaleInput->blockSignals(false); + m_brightenInput->blockSignals(false); + + slotEffect(); +} + +void ImageEffect_LensDistortion::writeUserSettings(void) +{ + TDEConfig *config = kapp->config(); + config->setGroup("lensdistortion Tool Dialog"); + config->writeEntry("2nd Order Distortion", m_mainInput->value()); + config->writeEntry("4th Order Distortion", m_edgeInput->value()); + config->writeEntry("Zoom Factor", m_rescaleInput->value()); + config->writeEntry("Brighten", m_brightenInput->value()); + config->sync(); +} + +void ImageEffect_LensDistortion::resetValues() +{ + m_mainInput->blockSignals(true); + m_edgeInput->blockSignals(true); + m_rescaleInput->blockSignals(true); + m_brightenInput->blockSignals(true); + + m_mainInput->setValue(0.0); + m_edgeInput->setValue(0.0); + m_rescaleInput->setValue(0.0); + m_brightenInput->setValue(0.0); + + m_mainInput->blockSignals(false); + m_edgeInput->blockSignals(false); + m_rescaleInput->blockSignals(false); + m_brightenInput->blockSignals(false); +} + +void ImageEffect_LensDistortion::prepareEffect() +{ + m_mainInput->setEnabled(false); + m_edgeInput->setEnabled(false); + m_rescaleInput->setEnabled(false); + m_brightenInput->setEnabled(false); + + double m = m_mainInput->value(); + double e = m_edgeInput->value(); + double r = m_rescaleInput->value(); + double b = m_brightenInput->value(); + + LensDistortion transformPreview(&m_previewRasterImage, 0L, m, e, r, b, 0, 0); + m_maskPreviewLabel->setPixmap(TQPixmap::TQPixmap(transformPreview.getTargetImage().convertToPixmap())); + + Digikam::ImageIface* iface = m_imagePreviewWidget->imageIface(); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new LensDistortion(iface->getOriginalImg(), this, m, e, r, b, 0, 0)); +} + +void ImageEffect_LensDistortion::prepareFinal() +{ + m_mainInput->setEnabled(false); + m_edgeInput->setEnabled(false); + m_rescaleInput->setEnabled(false); + m_brightenInput->setEnabled(false); + + double m = m_mainInput->value(); + double e = m_edgeInput->value(); + double r = m_rescaleInput->value(); + double b = m_brightenInput->value(); + + Digikam::ImageIface iface(0, 0); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new LensDistortion(iface.getOriginalImg(), this, m, e, r, b, 0, 0)); +} + +void ImageEffect_LensDistortion::putPreviewData(void) +{ + Digikam::ImageIface* iface = m_imagePreviewWidget->imageIface(); + + Digikam::DImg imDest = m_threadedFilter->getTargetImage() + .smoothScale(iface->previewWidth(), iface->previewHeight()); + iface->putPreviewImage(imDest.bits()); + + m_imagePreviewWidget->updatePreview(); +} + +void ImageEffect_LensDistortion::putFinalData(void) +{ + Digikam::ImageIface iface(0, 0); + + iface.putOriginalImage(i18n("Lens Distortion"), + m_threadedFilter->getTargetImage().bits()); +} + +void ImageEffect_LensDistortion::renderingFinished() +{ + m_mainInput->setEnabled(true); + m_edgeInput->setEnabled(true); + m_rescaleInput->setEnabled(true); + m_brightenInput->setEnabled(true); +} + +} // NameSpace DigikamLensDistortionImagesPlugin + diff --git a/src/imageplugins/lensdistortion/imageeffect_lensdistortion.h b/src/imageplugins/lensdistortion/imageeffect_lensdistortion.h new file mode 100644 index 00000000..2688a5df --- /dev/null +++ b/src/imageplugins/lensdistortion/imageeffect_lensdistortion.h @@ -0,0 +1,82 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-27 + * Description : a plugin to reduce lens distorsions to an image. + * + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_LENSDISTORTION_H +#define IMAGEEFFECT_LENSDISTORTION_H + +// TQt includes. + +#include <tqimage.h> + +// Digikam includes. + +#include "dimg.h" +#include "imageguidedlg.h" + +class TQLabel; + +class KDoubleNumInput; + +namespace DigikamLensDistortionImagesPlugin +{ + +class ImageEffect_LensDistortion : public Digikam::ImageGuideDlg +{ + TQ_OBJECT + + +public: + + ImageEffect_LensDistortion(TQWidget *parent); + ~ImageEffect_LensDistortion(); + +private slots: + + void readUserSettings(); + +private: + + void writeUserSettings(); + void resetValues(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + TQLabel *m_maskPreviewLabel; + + KDoubleNumInput *m_mainInput; + KDoubleNumInput *m_edgeInput; + KDoubleNumInput *m_rescaleInput; + KDoubleNumInput *m_brightenInput; + + Digikam::DImg m_previewRasterImage; +}; + +} // NameSpace DigikamLensDistortionImagesPlugin + +#endif /* IMAGEEFFECT_LENSDISTORTION_H */ diff --git a/src/imageplugins/lensdistortion/imageplugin_lensdistortion.cpp b/src/imageplugins/lensdistortion/imageplugin_lensdistortion.cpp new file mode 100644 index 00000000..73403fa7 --- /dev/null +++ b/src/imageplugins/lensdistortion/imageplugin_lensdistortion.cpp @@ -0,0 +1,69 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-27 + * Description : a plugin to reduce lens distorsions to an image. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> + +// Local includes. + +#include "ddebug.h" +#include "lensdistortiontool.h" +#include "imageplugin_lensdistortion.h" +#include "imageplugin_lensdistortion.moc" + +using namespace DigikamLensDistortionImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_lensdistortion, + KGenericFactory<ImagePlugin_LensDistortion>("digikamimageplugin_lensdistortion")); + +ImagePlugin_LensDistortion::ImagePlugin_LensDistortion(TQObject *parent, const char*, const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_LensDistortion") +{ + m_lensdistortionAction = new TDEAction(i18n("Lens Distortion..."), "lensdistortion", 0, + this, TQ_SLOT(slotLensDistortion()), + actionCollection(), "imageplugin_lensdistortion"); + + setXMLFile("digikamimageplugin_lensdistortion_ui.rc"); + + DDebug() << "ImagePlugin_LensDistortion plugin loaded" << endl; +} + +ImagePlugin_LensDistortion::~ImagePlugin_LensDistortion() +{ +} + +void ImagePlugin_LensDistortion::setEnabledActions(bool enable) +{ + m_lensdistortionAction->setEnabled(enable); +} + +void ImagePlugin_LensDistortion::slotLensDistortion() +{ + LensDistortionTool *tool = new LensDistortionTool(this); + loadTool(tool); +} diff --git a/src/imageplugins/lensdistortion/imageplugin_lensdistortion.h b/src/imageplugins/lensdistortion/imageplugin_lensdistortion.h new file mode 100644 index 00000000..ceb24756 --- /dev/null +++ b/src/imageplugins/lensdistortion/imageplugin_lensdistortion.h @@ -0,0 +1,56 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-27 + * Description : a plugin to reduce lens distorsions to an image. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_LENSDISTORTION_H +#define IMAGEPLUGIN_LENSDISTORTION_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_LensDistortion : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_LensDistortion(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_LensDistortion(); + + void setEnabledActions(bool enable); + +private slots: + + void slotLensDistortion(); + +private: + + TDEAction *m_lensdistortionAction; +}; + +#endif /* IMAGEPLUGIN_LENSDISTORTION_H */ diff --git a/src/imageplugins/lensdistortion/lensdistortion.cpp b/src/imageplugins/lensdistortion/lensdistortion.cpp new file mode 100644 index 00000000..7b18cc93 --- /dev/null +++ b/src/imageplugins/lensdistortion/lensdistortion.cpp @@ -0,0 +1,135 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : lens distortion algorithm. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2001-2003 by David Hodson <hodsond@acm.org> + * + * 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> +#include <cstdlib> + +// Local includes. + +#include "dimg.h" +#include "ddebug.h" +#include "pixelaccess.h" +#include "lensdistortion.h" + +namespace DigikamLensDistortionImagesPlugin +{ + +LensDistortion::LensDistortion(Digikam::DImg *orgImage, TQObject *parent, double main, + double edge, double rescale, double brighten, + int center_x, int center_y) + : Digikam::DImgThreadedFilter(orgImage, parent, "LensDistortion") +{ + m_main = main; + m_edge = edge; + m_rescale = rescale; + m_brighten = brighten; + m_centre_x = center_x; + m_centre_y = center_y; + + initFilter(); +} + +void LensDistortion::filterImage(void) +{ + int Width = m_orgImage.width(); + int Height = m_orgImage.height(); + int bytesDepth = m_orgImage.bytesDepth(); + + uchar *data = m_destImage.bits(); + + // initial copy + + m_destImage.bitBltImage(&m_orgImage, 0, 0); + + // initialize coefficients + + double normallise_radius_sq = 4.0 / (Width * Width + Height * Height); + double center_x = Width * (100.0 + m_centre_x) / 200.0; + double center_y = Height * (100.0 + m_centre_y) / 200.0; + double mult_sq = m_main / 200.0; + double mult_qd = m_edge / 200.0; + double rescale = pow(2.0, - m_rescale / 100.0); + double brighten = - m_brighten / 10.0; + + PixelAccess *pa = new PixelAccess(&m_orgImage); + + /* + * start at image (i, j), increment by (step, step) + * output goes to dst, which is w x h x d in size + * NB: d <= image.bpp + */ + + // We are working on the full image. + int dstWidth = Width; + int dstHeight = Height; + uchar* dst = (uchar*)data; + int step = 1, progress; + + int iLimit, jLimit; + double srcX, srcY, mag; + + iLimit = dstWidth * step; + jLimit = dstHeight * step; + + for (int dstJ = 0 ; !m_cancel && (dstJ < jLimit) ; dstJ += step) + { + for (int dstI = 0 ; !m_cancel && (dstI < iLimit) ; dstI += step) + { + // Get source Coordinates. + double radius_sq; + double off_x; + double off_y; + double radius_mult; + + off_x = dstI - center_x; + off_y = dstJ - center_y; + radius_sq = (off_x * off_x) + (off_y * off_y); + + radius_sq *= normallise_radius_sq; + + radius_mult = radius_sq * mult_sq + radius_sq * radius_sq * mult_qd; + mag = radius_mult; + radius_mult = rescale * (1.0 + radius_mult); + + srcX = center_x + radius_mult * off_x; + srcY = center_y + radius_mult * off_y; + + brighten = 1.0 + mag * brighten; + pa->pixelAccessGetCubic(srcX, srcY, brighten, dst); + dst += bytesDepth; + } + + // Update progress bar in dialog. + + progress = (int) (((double)dstJ * 100.0) / jLimit); + if (m_parent && progress%5 == 0) + postProgress(progress); + } + + delete pa; +} + +} // NameSpace DigikamLensDistortionImagesPlugin diff --git a/src/imageplugins/lensdistortion/lensdistortion.h b/src/imageplugins/lensdistortion/lensdistortion.h new file mode 100644 index 00000000..cbc46105 --- /dev/null +++ b/src/imageplugins/lensdistortion/lensdistortion.h @@ -0,0 +1,63 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : lens distortion algorithm. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2001-2003 by David Hodson <hodsond@acm.org> + * + * 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. + * + * ============================================================ */ + +#ifndef LENS_DISTORTION_H +#define LENS_DISTORTION_H + +// Digikam includes. + +#include "dimgthreadedfilter.h" + +namespace DigikamLensDistortionImagesPlugin +{ + +class LensDistortion : public Digikam::DImgThreadedFilter +{ + +public: + + LensDistortion(Digikam::DImg *orgImage, TQObject *parent=0, double main=0.0, + double edge=0.0, double rescale=0.0, double brighten=0.0, + int center_x=0, int center_y=0); + + ~LensDistortion(){}; + +private: + + virtual void filterImage(void); + +private: + + int m_centre_x; + int m_centre_y; + + double m_main; + double m_edge; + double m_rescale; + double m_brighten; +}; + +} // NameSpace DigikamLensDistortionImagesPlugin + +#endif /* LENS_DISTORTION_H */ diff --git a/src/imageplugins/lensdistortion/lensdistortiontool.cpp b/src/imageplugins/lensdistortion/lensdistortiontool.cpp new file mode 100644 index 00000000..8d33e1df --- /dev/null +++ b/src/imageplugins/lensdistortion/lensdistortiontool.cpp @@ -0,0 +1,326 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-27 + * Description : a plugin to reduce lens distorsions to an image. + * + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <cstring> +#include <cmath> +#include <cstdlib> + +// TQt includes. + +#include <tqbrush.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqpainter.h> +#include <tqpen.h> +#include <tqpixmap.h> +#include <tqwhatsthis.h> +#include <tqimage.h> + +// KDE includes. + +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <kstandarddirs.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "editortoolsettings.h" +#include "lensdistortion.h" +#include "lensdistortiontool.h" +#include "lensdistortiontool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamLensDistortionImagesPlugin +{ + +LensDistortionTool::LensDistortionTool(TQObject* parent) + : EditorToolThreaded(parent) +{ + setName("lensdistortion"); + setToolName(i18n("Lens Distortion")); + setToolIcon(SmallIcon("lensdistortion")); + + m_previewWidget = new ImageWidget("lensdistortion Tool", 0, TQString(), + false, ImageGuideWidget::HVGuideMode); + + setToolView(m_previewWidget); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel, + EditorToolSettings::ColorGuide); + TQGridLayout* grid = new TQGridLayout(m_gboxSettings->plainPage(), 9, 1); + + m_maskPreviewLabel = new TQLabel( m_gboxSettings->plainPage() ); + m_maskPreviewLabel->setAlignment ( TQt::AlignHCenter | TQt::AlignVCenter ); + TQWhatsThis::add( m_maskPreviewLabel, i18n("<p>You can see here a thumbnail preview of the distortion correction " + "applied to a cross pattern.") ); + + // ------------------------------------------------------------- + + TQLabel *label1 = new TQLabel(i18n("Main:"), m_gboxSettings->plainPage()); + + m_mainInput = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_mainInput->setPrecision(1); + m_mainInput->setRange(-100.0, 100.0, 0.1); + m_mainInput->setDefaultValue(0.0); + TQWhatsThis::add(m_mainInput, i18n("<p>This value controls the amount of distortion. Negative values correct lens barrel " + "distortion, while positive values correct lens pincushion distortion.")); + + // ------------------------------------------------------------- + + TQLabel *label2 = new TQLabel(i18n("Edge:"), m_gboxSettings->plainPage()); + + m_edgeInput = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_edgeInput->setPrecision(1); + m_edgeInput->setRange(-100.0, 100.0, 0.1); + m_edgeInput->setDefaultValue(0.0); + TQWhatsThis::add(m_edgeInput, i18n("<p>This value controls in the same manner as the Main control, but has more effect " + "at the edges of the image than at the center.")); + + // ------------------------------------------------------------- + + TQLabel *label3 = new TQLabel(i18n("Zoom:"), m_gboxSettings->plainPage()); + + m_rescaleInput = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_rescaleInput->setPrecision(1); + m_rescaleInput->setRange(-100.0, 100.0, 0.1); + m_rescaleInput->setDefaultValue(0.0); + TQWhatsThis::add(m_rescaleInput, i18n("<p>This value rescales the overall image size.")); + + // ------------------------------------------------------------- + + TQLabel *label4 = new TQLabel(i18n("Brighten:"), m_gboxSettings->plainPage()); + + m_brightenInput = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_brightenInput->setPrecision(1); + m_brightenInput->setRange(-100.0, 100.0, 0.1); + m_brightenInput->setDefaultValue(0.0); + TQWhatsThis::add(m_brightenInput, i18n("<p>This value adjusts the brightness in image corners.")); + + grid->addMultiCellWidget(m_maskPreviewLabel, 0, 0, 0, 1); + grid->addMultiCellWidget(label1, 1, 1, 0, 1); + grid->addMultiCellWidget(m_mainInput, 2, 2, 0, 1); + grid->addMultiCellWidget(label2, 3, 3, 0, 1); + grid->addMultiCellWidget(m_edgeInput, 4, 4, 0, 1); + grid->addMultiCellWidget(label3, 5, 5, 0, 1); + grid->addMultiCellWidget(m_rescaleInput, 6, 6, 0, 1); + grid->addMultiCellWidget(label4, 7, 7, 0, 1); + grid->addMultiCellWidget(m_brightenInput, 8, 8, 0, 1); + grid->setRowStretch(9, 10); + grid->setMargin(m_gboxSettings->spacingHint()); + grid->setSpacing(m_gboxSettings->spacingHint()); + + setToolSettings(m_gboxSettings); + init(); + + // ------------------------------------------------------------- + + connect(m_mainInput, TQ_SIGNAL(valueChanged(double)), + this, TQ_SLOT(slotTimer())); + + connect(m_edgeInput, TQ_SIGNAL(valueChanged(double)), + this, TQ_SLOT(slotTimer())); + + connect(m_rescaleInput, TQ_SIGNAL(valueChanged(double)), + this, TQ_SLOT(slotTimer())); + + connect(m_brightenInput, TQ_SIGNAL(valueChanged(double)), + this, TQ_SLOT(slotTimer())); + + connect(m_gboxSettings, TQ_SIGNAL(signalColorGuideChanged()), + this, TQ_SLOT(slotColorGuideChanged())); + + // ------------------------------------------------------------- + + /* Calc transform preview. + We would like a checkered area to demonstrate the effect. + We do not have any drawing support in DImg, so we let TQt draw. + First we create a white TQImage. We convert this to a TQPixmap, + on which we can draw. Then we convert back to TQImage, + convert the TQImage to a DImg which we only need to create once, here. + Later, we apply the effect on a copy and convert the DImg to TQPixmap. + Longing for TQt4 where we can paint directly on the TQImage... + */ + + TQImage preview(120, 120, 32); + memset(preview.bits(), 255, preview.numBytes()); + TQPixmap pix (preview); + TQPainter pt(&pix); + pt.setPen( TQPen(TQt::black, 1) ); + pt.fillRect( 0, 0, pix.width(), pix.height(), TQBrush(TQt::black, TQt::CrossPattern) ); + pt.drawRect( 0, 0, pix.width(), pix.height() ); + pt.end(); + TQImage preview2(pix.convertToImage()); + m_previewRasterImage = DImg(preview2.width(), preview2.height(), false, false, preview2.bits()); +} + +LensDistortionTool::~LensDistortionTool() +{ +} + +void LensDistortionTool::slotColorGuideChanged() +{ + m_previewWidget->slotChangeGuideColor(m_gboxSettings->guideColor()); + m_previewWidget->slotChangeGuideSize(m_gboxSettings->guideSize()); +} + +void LensDistortionTool::readSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("lensdistortion Tool"); + + m_mainInput->blockSignals(true); + m_edgeInput->blockSignals(true); + m_rescaleInput->blockSignals(true); + m_brightenInput->blockSignals(true); + + m_mainInput->setValue(config->readDoubleNumEntry("2nd Order Distortion", m_mainInput->defaultValue())); + m_edgeInput->setValue(config->readDoubleNumEntry("4th Order Distortion",m_edgeInput->defaultValue())); + m_rescaleInput->setValue(config->readDoubleNumEntry("Zoom Factor", m_rescaleInput->defaultValue())); + m_brightenInput->setValue(config->readDoubleNumEntry("Brighten", m_brightenInput->defaultValue())); + m_gboxSettings->setGuideColor(config->readColorEntry("Guide Color", &TQt::red)); + m_gboxSettings->setGuideSize(config->readNumEntry("Guide Width", 1)); + + m_mainInput->blockSignals(false); + m_edgeInput->blockSignals(false); + m_rescaleInput->blockSignals(false); + m_brightenInput->blockSignals(false); + + slotColorGuideChanged(); + slotEffect(); +} + +void LensDistortionTool::writeSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("lensdistortion Tool"); + config->writeEntry("2nd Order Distortion", m_mainInput->value()); + config->writeEntry("4th Order Distortion", m_edgeInput->value()); + config->writeEntry("Zoom Factor", m_rescaleInput->value()); + config->writeEntry("Brighten", m_brightenInput->value()); + config->writeEntry("Guide Color", m_gboxSettings->guideColor()); + config->writeEntry("Guide Width", m_gboxSettings->guideSize()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void LensDistortionTool::slotResetSettings() +{ + m_mainInput->blockSignals(true); + m_edgeInput->blockSignals(true); + m_rescaleInput->blockSignals(true); + m_brightenInput->blockSignals(true); + + m_mainInput->slotReset(); + m_edgeInput->slotReset(); + m_rescaleInput->slotReset(); + m_brightenInput->slotReset(); + + m_mainInput->blockSignals(false); + m_edgeInput->blockSignals(false); + m_rescaleInput->blockSignals(false); + m_brightenInput->blockSignals(false); +} + +void LensDistortionTool::prepareEffect() +{ + m_mainInput->setEnabled(false); + m_edgeInput->setEnabled(false); + m_rescaleInput->setEnabled(false); + m_brightenInput->setEnabled(false); + + double m = m_mainInput->value(); + double e = m_edgeInput->value(); + double r = m_rescaleInput->value(); + double b = m_brightenInput->value(); + + LensDistortion transformPreview(&m_previewRasterImage, 0L, m, e, r, b, 0, 0); + m_maskPreviewLabel->setPixmap(TQPixmap(transformPreview.getTargetImage().convertToPixmap())); + + ImageIface* iface = m_previewWidget->imageIface(); + + setFilter(dynamic_cast<DImgThreadedFilter*>(new LensDistortion(iface->getOriginalImg(), this, m, e, r, b, 0, 0))); +} + +void LensDistortionTool::prepareFinal() +{ + m_mainInput->setEnabled(false); + m_edgeInput->setEnabled(false); + m_rescaleInput->setEnabled(false); + m_brightenInput->setEnabled(false); + + double m = m_mainInput->value(); + double e = m_edgeInput->value(); + double r = m_rescaleInput->value(); + double b = m_brightenInput->value(); + + ImageIface iface(0, 0); + + setFilter(dynamic_cast<DImgThreadedFilter*>(new LensDistortion(iface.getOriginalImg(), this, m, e, r, b, 0, 0))); +} + +void LensDistortionTool::putPreviewData() +{ + ImageIface* iface = m_previewWidget->imageIface(); + + DImg imDest = filter()->getTargetImage().smoothScale(iface->previewWidth(), iface->previewHeight()); + iface->putPreviewImage(imDest.bits()); + + m_previewWidget->updatePreview(); +} + +void LensDistortionTool::putFinalData() +{ + ImageIface iface(0, 0); + + iface.putOriginalImage(i18n("Lens Distortion"), filter()->getTargetImage().bits()); +} + +void LensDistortionTool::renderingFinished() +{ + m_mainInput->setEnabled(true); + m_edgeInput->setEnabled(true); + m_rescaleInput->setEnabled(true); + m_brightenInput->setEnabled(true); +} + +} // NameSpace DigikamLensDistortionImagesPlugin diff --git a/src/imageplugins/lensdistortion/lensdistortiontool.h b/src/imageplugins/lensdistortion/lensdistortiontool.h new file mode 100644 index 00000000..f3c7b67f --- /dev/null +++ b/src/imageplugins/lensdistortion/lensdistortiontool.h @@ -0,0 +1,92 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-27 + * Description : a plugin to reduce lens distorsions to an image. + * + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef LENSDISTORTIONTOOL_H +#define LENSDISTORTIONTOOL_H + +// Digikam includes. + +#include "dimg.h" +#include "editortool.h" + +class TQLabel; + +namespace KDcrawIface +{ +class RDoubleNumInput; +} + +namespace Digikam +{ +class EditorToolSettings; +class ImageWidget; +} + +namespace DigikamLensDistortionImagesPlugin +{ + +class LensDistortionTool : public Digikam::EditorToolThreaded +{ + TQ_OBJECT + + +public: + + LensDistortionTool(TQObject *parent); + ~LensDistortionTool(); + +private slots: + + void slotResetSettings(); + void slotColorGuideChanged(); + +private: + + void readSettings(); + void writeSettings(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + TQLabel *m_maskPreviewLabel; + + KDcrawIface::RDoubleNumInput *m_mainInput; + KDcrawIface::RDoubleNumInput *m_edgeInput; + KDcrawIface::RDoubleNumInput *m_rescaleInput; + KDcrawIface::RDoubleNumInput *m_brightenInput; + + Digikam::DImg m_previewRasterImage; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamLensDistortionImagesPlugin + +#endif /* LENSDISTORTIONTOOL_H */ diff --git a/src/imageplugins/lensdistortion/pixelaccess.cpp b/src/imageplugins/lensdistortion/pixelaccess.cpp new file mode 100644 index 00000000..a6041f94 --- /dev/null +++ b/src/imageplugins/lensdistortion/pixelaccess.cpp @@ -0,0 +1,314 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-27 + * Description : acess pixels method for lens distortion algorithm. + * + * Copyright (C) 2004-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <cstring> +#include <cmath> +#include <cstdlib> + +// Local includes. + +#include "ddebug.h" +#include "pixelaccess.h" + +namespace DigikamLensDistortionImagesPlugin +{ + +PixelAccess::PixelAccess(Digikam::DImg *srcImage) +{ + m_image = srcImage; + + m_width = PixelAccessWidth; + m_height = PixelAccessHeight; + + m_depth = m_image->bytesDepth(); + m_imageWidth = m_image->width(); + m_imageHeight = m_image->height(); + m_sixteenBit = m_image->sixteenBit(); + + for ( int i = 0 ; i < PixelAccessRegions ; i++ ) + { + m_buffer[i] = new Digikam::DImg(m_image->copy(0, 0, m_width, m_height)); + + m_tileMinX[i] = 1; + m_tileMaxX[i] = m_width - 2; + m_tileMinY[i] = 1; + m_tileMaxY[i] = m_height - 2; + } +} + +PixelAccess::~PixelAccess() +{ + for( int i = 0 ; i < PixelAccessRegions ; i++ ) + delete m_buffer[i]; +} + +uchar* PixelAccess::pixelAccessAddress(int i, int j) +{ + return m_buffer[0]->bits() + m_depth * (m_width * (j + 1 - m_tileMinY[0]) + (i + 1 - m_tileMinX[0])); +} + +// Swap region[n] with region[0]. +void PixelAccess::pixelAccessSelectRegion(int n) +{ + Digikam::DImg *temp; + int a, b, c, d; + int i; + + temp = m_buffer[n]; + a = m_tileMinX[n]; + b = m_tileMaxX[n]; + c = m_tileMinY[n]; + d = m_tileMaxY[n]; + + for( i = n ; i > 0 ; i--) + { + m_buffer[i] = m_buffer[i-1]; + m_tileMinX[i] = m_tileMinX[i-1]; + m_tileMaxX[i] = m_tileMaxX[i-1]; + m_tileMinY[i] = m_tileMinY[i-1]; + m_tileMaxY[i] = m_tileMaxY[i-1]; + } + + m_buffer[0] = temp; + m_tileMinX[0] = a; + m_tileMaxX[0] = b; + m_tileMinY[0] = c; + m_tileMaxY[0] = d; +} + +// Buffer[0] is cleared, should start at [i, j], fill rows that overlap image. +void PixelAccess::pixelAccessDoEdge(int i, int j) +{ + int lineStart, lineEnd; + int rowStart, rowEnd; + int lineWidth; + uchar* line; + + lineStart = i; + if (lineStart < 0) lineStart = 0; + lineEnd = i + m_width; + if (lineEnd > m_imageWidth) lineEnd = m_imageWidth; + lineWidth = lineEnd - lineStart; + + if( lineStart >= lineEnd ) + return; + + rowStart = j; + if (rowStart < 0) rowStart = 0; + rowEnd = j + m_height; + if (rowEnd > m_imageHeight) rowEnd = m_imageHeight; + + for( int y = rowStart ; y < rowEnd ; y++ ) + { + line = pixelAccessAddress(lineStart, y); + memcpy(line, m_image->scanLine(y) + lineStart * m_depth, lineWidth * m_depth); + } +} + +// Moves buffer[0] so that [x, y] is inside it. +void PixelAccess::pixelAccessReposition(int xInt, int yInt) +{ + int newStartX = xInt - PixelAccessXOffset; + int newStartY = yInt - PixelAccessYOffset; + + m_tileMinX[0] = newStartX + 1; + m_tileMaxX[0] = newStartX + m_width - 2; + m_tileMinY[0] = newStartY + 1; + m_tileMaxY[0] = newStartY + m_height - 2; + + + if ( (newStartX < 0) || ((newStartX + m_width) >= m_imageWidth) || + (newStartY < 0) || ((newStartY + m_height) >= m_imageHeight) ) + { + // some data is off edge of image + + m_buffer[0]->fill(Digikam::DColor(0,0,0,0, m_sixteenBit)); + + // This could probably be done by bitBltImage but I did not figure out how, + // so leave the working code here. And no, it is not this: + //m_buffer[0]->bitBltImage(m_image, newStartX, newStartY, m_width, m_height, 0, 0); + + if ( ((newStartX + m_width) < 0) || (newStartX >= m_imageWidth) || + ((newStartY + m_height) < 0) || (newStartY >= m_imageHeight) ) + { + // totally outside, just leave it. + } + else + { + pixelAccessDoEdge(newStartX, newStartY); + } + } + else + { + m_buffer[0]->bitBltImage(m_image, newStartX, newStartY, m_width, m_height, 0, 0); + } +} + +void PixelAccess::pixelAccessGetCubic(double srcX, double srcY, double brighten, uchar* dst) +{ + int xInt, yInt; + double dx, dy; + uchar *corner; + + xInt = (int)floor(srcX); + dx = srcX - xInt; + yInt = (int)floor(srcY); + dy = srcY - yInt; + + // We need 4x4 pixels, xInt-1 to xInt+2 horz, yInt-1 to yInt+2 vert + // they're probably in the last place we looked... + + if ((xInt >= m_tileMinX[0]) && (xInt < m_tileMaxX[0]) && + (yInt >= m_tileMinY[0]) && (yInt < m_tileMaxY[0]) ) + { + corner = pixelAccessAddress(xInt - 1, yInt - 1); + cubicInterpolate(corner, m_depth * m_width, dst, m_sixteenBit, dx, dy, brighten); + return; + } + + // Or maybe it was a while back... + + for ( int i = 1 ; i < PixelAccessRegions ; i++) + { + if ((xInt >= m_tileMinX[i]) && (xInt < m_tileMaxX[i]) && + (yInt >= m_tileMinY[i]) && (yInt < m_tileMaxY[i]) ) + { + // Check here first next time + + pixelAccessSelectRegion(i); + corner = pixelAccessAddress(xInt - 1, yInt - 1); + cubicInterpolate(corner, m_depth * m_width, dst, m_sixteenBit, dx, dy, brighten); + return; + } + } + + // Nope, recycle an old region. + + pixelAccessSelectRegion(PixelAccessRegions - 1); + pixelAccessReposition(xInt, yInt); + + corner = pixelAccessAddress(xInt - 1, yInt - 1); + cubicInterpolate(corner, m_depth * m_width, dst, m_sixteenBit, dx, dy, brighten); +} + +/* + * Catmull-Rom cubic interpolation + * + * equally spaced points p0, p1, p2, p3 + * interpolate 0 <= u < 1 between p1 and p2 + * + * (1 u u^2 u^3) ( 0.0 1.0 0.0 0.0 ) (p0) + * ( -0.5 0.0 0.5 0.0 ) (p1) + * ( 1.0 -2.5 2.0 -0.5 ) (p2) + * ( -0.5 1.5 -1.5 0.5 ) (p3) + * + */ +void PixelAccess::cubicInterpolate(uchar* src, int rowStride, uchar* dst, + bool sixteenBit, double dx, double dy, double brighten) +{ + float um1, u, up1, up2; + float vm1, v, vp1, vp2; + int c; + const int numberOfComponents = 4; + float verts[4 * numberOfComponents]; + + um1 = ((-0.5 * dx + 1.0) * dx - 0.5) * dx; + u = (1.5 * dx - 2.5) * dx * dx + 1.0; + up1 = ((-1.5 * dx + 2.0) * dx + 0.5) * dx; + up2 = (0.5 * dx - 0.5) * dx * dx; + + vm1 = ((-0.5 * dy + 1.0) * dy - 0.5) * dy; + v = (1.5 * dy - 2.5) * dy * dy + 1.0; + vp1 = ((-1.5 * dy + 2.0) * dy + 0.5) * dy; + vp2 = (0.5 * dy - 0.5) * dy * dy; + + if (sixteenBit) + { + unsigned short *src16 = (unsigned short *)src; + unsigned short *dst16 = (unsigned short *)dst; + + // for each component, read the values of 4 pixels into array + + for (c = 0 ; c < 4 * numberOfComponents ; c++) + { + verts[c] = vm1 * src16[c] + v * src16[c+rowStride] + vp1 * src16[c+rowStride*2] + vp2 * src16[c+rowStride*3]; + } + + // for each component, compute resulting value from array + + for (c = 0 ; c < numberOfComponents ; c++) + { + float result; + result = um1 * verts[c] + u * verts[c+numberOfComponents] + + up1 * verts[c+numberOfComponents*2] + up2 * verts[c+numberOfComponents*3]; + result *= brighten; + + if (result < 0.0) + { + dst16[c] = 0; + } + else if (result > 65535.0) + { + dst16[c] = 65535; + } + else + { + dst16[c] = (uint)result; + } + } + } + else + { + for (c = 0 ; c < 4 * numberOfComponents ; c++) + { + verts[c] = vm1 * src[c] + v * src[c+rowStride] + vp1 * src[c+rowStride*2] + vp2 * src[c+rowStride*3]; + } + + for (c = 0 ; c < numberOfComponents ; c++) + { + float result; + result = um1 * verts[c] + u * verts[c+numberOfComponents] + + up1 * verts[c+numberOfComponents*2] + up2 * verts[c+numberOfComponents*3]; + result *= brighten; + + if (result < 0.0) + { + dst[c] = 0; + } + else if (result > 255.0) + { + dst[c] = 255; + } + else + { + dst[c] = (uint)result; + } + } + } +} + +} // NameSpace DigikamLensDistortionImagesPlugin + diff --git a/src/imageplugins/lensdistortion/pixelaccess.h b/src/imageplugins/lensdistortion/pixelaccess.h new file mode 100644 index 00000000..734d0779 --- /dev/null +++ b/src/imageplugins/lensdistortion/pixelaccess.h @@ -0,0 +1,93 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-27 + * Description : acess pixels method for lens distortion algorithm. + * + * Copyright (C) 2004-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef PIXEL_ACCESS_H +#define PIXEL_ACCESS_H + +#define PixelAccessRegions 20 +#define PixelAccessWidth 40 +#define PixelAccessHeight 20 +#define PixelAccessXOffset 3 +#define PixelAccessYOffset 3 + +// Digikam includes. + +#include "dimg.h" + +namespace DigikamLensDistortionImagesPlugin +{ + + /* PixelAcess class: solving the eternal problem: random, cubic-interpolated, + * sub-pixel coordinate access to an image. + * Assuming that accesses are at least slightly coherent, + * PixelAccess keeps PixelAccessRegions buffers, each containing a + * PixelAccessWidth x PixelAccessHeight region of pixels. + * Buffer[0] is always checked first, so move the last accessed + * region into that position. + * When a request arrives which is outside all the regions, + * get a new region. + * The new region is placed so that the requested pixel is positioned + * at [PixelAccessXOffset, PixelAccessYOffset] in the region. + */ + +class PixelAccess +{ +public: + + PixelAccess(Digikam::DImg *srcImage); + ~PixelAccess(); + + void pixelAccessGetCubic(double srcX, double srcY, double brighten, uchar* dst); + +private: + + Digikam::DImg *m_image; + + //uchar* m_buffer[PixelAccessRegions]; + Digikam::DImg *m_buffer[PixelAccessRegions]; + + int m_width; + int m_height; + int m_depth; + int m_imageWidth; + int m_imageHeight; + bool m_sixteenBit; + int m_tileMinX[PixelAccessRegions]; + int m_tileMaxX[PixelAccessRegions]; + int m_tileMinY[PixelAccessRegions]; + int m_tileMaxY[PixelAccessRegions]; + +protected: + + inline uchar* pixelAccessAddress(int i, int j); + void pixelAccessSelectRegion(int n); + void pixelAccessDoEdge(int i, int j); + void pixelAccessReposition(int xInt, int yInt); + void cubicInterpolate(uchar* src, int rowStride, uchar* dst, + bool sixteenBit, double dx, double dy, double brighten); +}; + +} // NameSpace DigikamLensDistortionImagesPlugin + +#endif /* PIXEL_ACCESS_H */ diff --git a/src/imageplugins/noisereduction/Makefile.am b/src/imageplugins/noisereduction/Makefile.am new file mode 100644 index 00000000..c1b6ac08 --- /dev/null +++ b/src/imageplugins/noisereduction/Makefile.am @@ -0,0 +1,34 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_noisereduction_la_SOURCES = imageplugin_noisereduction.cpp \ + noisereductiontool.cpp noisereduction.cpp + +digikamimageplugin_noisereduction_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_noisereduction_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_noisereduction.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_noisereduction.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_noisereduction_ui.rc + diff --git a/src/imageplugins/noisereduction/digikamimageplugin_noisereduction.desktop b/src/imageplugins/noisereduction/digikamimageplugin_noisereduction.desktop new file mode 100644 index 00000000..9cf408e3 --- /dev/null +++ b/src/imageplugins/noisereduction/digikamimageplugin_noisereduction.desktop @@ -0,0 +1,53 @@ +[Desktop Entry] +Name=ImagePlugin_NoiseReduction +Name[da]=Plugin for støjreducering +Name[el]=ΠρόσθετοΕικόνας_ΜείωσηΘορύβου +Name[fi]=Kohinanpoisto +Name[hr]=Uklanjanje šuma +Name[it]=PluginImmagini_RiduzioneDisturbi +Name[nl]=Afbeeldingsplugin_Ruisreductie +Name[pt]=ImagePlugin_Restoration +Name[sr]=Смањење шума +Name[sr@Latn]=Smanjenje šuma +Name[sv]=Insticksprogram för brusreducering +Name[tr]=ResimEklentisi_Onarım +Name[vi]=ImagePlugin_Restoration +Name[xx]=xxImagePlugin_NoiseReductionxx +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=Noise Reduction plugin for digiKam +Comment[bg]=Приставка на digiKam за намаляване шума в снимки +Comment[ca]=Connector pel digiKam de reducció de soroll +Comment[da]=Plugin til støjreduktion for DigiKam +Comment[de]=digiKam-Modul zum Entfernen von Rauschen +Comment[el]=Πρόσθετο μείωσης θορύβου για το digiKam +Comment[es]=Plugin para digiKam de reducción de ruido +Comment[et]=DigiKami müra vähendamise plugin +Comment[fa]=وصلۀ کاهش نوفه برای digiKam +Comment[fi]=Vähentää kuvan kohinaa +Comment[fr]=Module externe pour réduire le bruit numérique dans digiKam +Comment[gl]=Un plugin de digiKam para a reduzón de ruído +Comment[hr]=digiKam dodatak za uklanjanje šuma +Comment[is]=Íforrit fyrir digiKam sem minnkar truflanir (noise) í mynd +Comment[it]=Plugin di riduzione dei disturbi per digiKam +Comment[ja]=digiKam ノイズ低減プラグイン +Comment[ms]=Plugin Pengurangan Bising untuk digiKam +Comment[nds]=digiKam-Moduul för Ruusminnern +Comment[nl]=Digikam-plugin voor ruisreductie +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਗੜਬੜ ਘਟਾਉਣ ਲਈ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam zmniejszająca szum +Comment[pt]=Um 'plugin' do digiKam para a redução de ruído +Comment[pt_BR]=Plugin de redução de ruidos +Comment[ru]=Модуль уменьшения шума для digiKam +Comment[sk]=digiKam plugin na potlačenie šumu +Comment[sr]=digiKam-ов прикључак за смањење шума +Comment[sr@Latn]=digiKam-ov priključak za smanjenje šuma +Comment[sv]=Digikam insticksprogram för brusreducering +Comment[tr]=digiKam için Parazit Azaltma eklentisi +Comment[uk]=Втулок зменшення шуму для digiKam +Comment[vi]=Phần bổ sung giảm nhiễu cho digiKam +Comment[xx]=xxNoise Reduction plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_noisereduction +author=Caulier Gilles, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/noisereduction/digikamimageplugin_noisereduction_ui.rc b/src/imageplugins/noisereduction/digikamimageplugin_noisereduction_ui.rc new file mode 100644 index 00000000..b6a663e3 --- /dev/null +++ b/src/imageplugins/noisereduction/digikamimageplugin_noisereduction_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="5" name="digikamimageplugin_noisereduction" > + + <MenuBar> + + <Menu name="Enhance" ><text>Enh&ance</text> + <Action name="imageplugin_noisereduction" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action shortcut="" name="imageplugin_noisereduction" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/noisereduction/imageeffect_noisereduction.cpp b/src/imageplugins/noisereduction/imageeffect_noisereduction.cpp new file mode 100644 index 00000000..707b05db --- /dev/null +++ b/src/imageplugins/noisereduction/imageeffect_noisereduction.cpp @@ -0,0 +1,553 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-24 + * Description : a plugin to reduce CCD noise. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqlabel.h> +#include <tqwhatsthis.h> +#include <tqtooltip.h> +#include <tqcheckbox.h> +#include <tqstring.h> +#include <tqtabwidget.h> +#include <tqimage.h> +#include <tqlayout.h> +#include <tqfile.h> +#include <tqtextstream.h> + +// KDE includes. + +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <kstandarddirs.h> +#include <knuminput.h> +#include <tdefiledialog.h> +#include <tdeglobalsettings.h> +#include <tdemessagebox.h> +#include <tdeconfig.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "noisereduction.h" +#include "imageeffect_noisereduction.h" +#include "imageeffect_noisereduction.moc" + +namespace DigikamNoiseReductionImagesPlugin +{ + +ImageEffect_NoiseReduction::ImageEffect_NoiseReduction(TQWidget* parent) + : Digikam::CtrlPanelDlg(parent, i18n("Noise Reduction"), + "noisereduction", true, true, true, + Digikam::ImagePannelWidget::SeparateViewAll) +{ + TQString whatsThis; + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Noise Reduction"), + digikam_version, + I18N_NOOP("A noise reduction image filter plugin for digiKam."), + TDEAboutData::License_GPL, + "(c) 2004-2008, Gilles Caulier", + 0, + "http://www.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + about->addAuthor("Peter Heckert", I18N_NOOP("Noise Reduction algorithm. Developer"), + "peter dot heckert at arcor dot de"); + + setAboutData(about); + + // ------------------------------------------------------------- + + TQTabWidget *mainTab = new TQTabWidget(m_imagePreviewWidget); + + TQWidget* firstPage = new TQWidget( mainTab ); + TQGridLayout* gridSettings = new TQGridLayout( firstPage, 6, 1, spacingHint()); + mainTab->addTab( firstPage, i18n("Details") ); + + TQLabel *label1 = new TQLabel(i18n("Radius:"), firstPage); + + m_radiusInput = new KDoubleNumInput(firstPage); + m_radiusInput->setPrecision(1); + m_radiusInput->setRange(0.0, 10.0, 0.1, true); + TQWhatsThis::add( m_radiusInput, i18n("<p><b>Radius</b>: this control selects the " + "gliding window size used for the filter. Larger values do not increase " + "the amount of time needed to filter each pixel in the image but " + "can cause blurring. This window moves across the image, and the " + "color in it is smoothed to remove imperfections. " + "In any case it must be about the same size as the noise granularity " + "or somewhat more. If it is set higher than necessary, then it " + "can cause unwanted blur.")); + + gridSettings->addMultiCellWidget(label1, 0, 0, 0, 0); + gridSettings->addMultiCellWidget(m_radiusInput, 0, 0, 1, 1); + + // ------------------------------------------------------------- + + TQLabel *label3 = new TQLabel(i18n("Threshold:"), firstPage); + + m_thresholdInput = new KDoubleNumInput(firstPage); + m_thresholdInput->setPrecision(2); + m_thresholdInput->setRange(0.0, 1.0, 0.01, true); + TQWhatsThis::add( m_thresholdInput, i18n("<p><b>Threshold</b>: use the slider for coarse adjustment, " + "and the spin control for fine adjustment to control edge detection sensitivity. " + "This value should be set so that edges and details are clearly visible " + "and noise is smoothed out. " + "Adjustment must be made carefully, because the gap between \"noisy\", " + "\"smooth\", and \"blur\" is very small. Adjust it as carefully as you would adjust " + "the focus of a camera.")); + + gridSettings->addMultiCellWidget(label3, 1, 1, 0, 0); + gridSettings->addMultiCellWidget(m_thresholdInput, 1, 1, 1, 1); + + // ------------------------------------------------------------- + + TQLabel *label4 = new TQLabel(i18n("Texture:"), firstPage); + + m_textureInput = new KDoubleNumInput(firstPage); + m_textureInput->setPrecision(2); + m_textureInput->setRange(-0.99, 0.99, 0.01, true); + TQWhatsThis::add( m_textureInput, i18n("<p><b>Texture</b>: this control sets the texture accuracy. " + "This value can be used, to get more or less texture accuracy. When decreased, " + "then noise and texture are blurred out, when increased then texture is " + "amplified, but also noise will increase. It has almost no effect on image edges.")); + + gridSettings->addMultiCellWidget(label4, 2, 2, 0, 0); + gridSettings->addMultiCellWidget(m_textureInput, 2, 2, 1, 1); + + // ------------------------------------------------------------- + + TQLabel *label7 = new TQLabel(i18n("Sharpness:"), firstPage); // Filter setting "Lookahead". + + m_sharpnessInput = new KDoubleNumInput(firstPage); + m_sharpnessInput->setPrecision(2); + m_sharpnessInput->setRange(0.0, 1.0, 0.1, true); + TQWhatsThis::add( m_sharpnessInput, i18n("<p><b>Sharpness</b>: " + "This value improves the frequency response for the filter. " + "When it is too strong then not all noise can be removed, or spike noise may appear. " + "Set it near to maximum, if you want to remove very weak noise or JPEG-artifacts, " + "without losing detail.")); + + gridSettings->addMultiCellWidget(label7, 3, 3, 0, 0); + gridSettings->addMultiCellWidget(m_sharpnessInput, 3, 3, 1, 1); + + // ------------------------------------------------------------- + + TQLabel *label5 = new TQLabel(i18n("Edge Lookahead:"), firstPage); // Filter setting "Sharp". + + m_lookaheadInput = new KDoubleNumInput(firstPage); + m_lookaheadInput->setPrecision(2); + m_lookaheadInput->setRange(0.01, 20.0, 0.01, true); + TQWhatsThis::add( m_lookaheadInput, i18n("<p><b>Edge</b>: " + "This value defines the pixel distance to which the filter looks ahead for edges. " + "When this value is increased, then spike noise is erased. " + "You can eventually re-adjust the <b>Edge</b> filter, when you have changed this setting. " + "When this value is too high, the adaptive filter can no longer accurately track " + "image details, and noise or blurring can occur.")); + + gridSettings->addMultiCellWidget(label5, 4, 4, 0, 0); + gridSettings->addMultiCellWidget(m_lookaheadInput, 4, 4, 1, 1); + + // ------------------------------------------------------------- + + TQLabel *label10 = new TQLabel(i18n("Erosion:"), firstPage); + + m_phaseInput = new KDoubleNumInput(firstPage); + m_phaseInput->setPrecision(1); + m_phaseInput->setRange(0.5, 20.0, 0.5, true); + TQWhatsThis::add( m_phaseInput, i18n("<p><b>Erosion</b>: " + "Use this to increase edge noise erosion and spike noise erosion " + "(noise is removed by erosion).")); + + gridSettings->addMultiCellWidget(label10, 5, 5, 0, 0); + gridSettings->addMultiCellWidget(m_phaseInput, 5, 5, 1, 1); + gridSettings->setColStretch(1, 10); + gridSettings->setRowStretch(6, 10); + + // ------------------------------------------------------------- + + TQWidget* secondPage = new TQWidget( mainTab ); + TQGridLayout* gridSettings2 = new TQGridLayout( secondPage, 4, 1, spacingHint()); + mainTab->addTab( secondPage, i18n("Advanced") ); + + TQLabel *label2 = new TQLabel(i18n("Luminance:"), secondPage); + + m_lumToleranceInput = new KDoubleNumInput(secondPage); + m_lumToleranceInput->setPrecision(1); + m_lumToleranceInput->setRange(0.0, 1.0, 0.1, true); + TQWhatsThis::add( m_lumToleranceInput, i18n("<p><b>Luminance</b>: this control sets the luminance tolerance of the image." + "We recommend using either the <b>Color</b> or the <b>Luminance</b> tolerance settings " + "to make an image correction, not both at the same time. These settings " + "do not influence the main smoothing process controlled by the <b>Details</b> " + "settings.")); + + gridSettings2->addMultiCellWidget(label2, 0, 0, 0, 0); + gridSettings2->addMultiCellWidget(m_lumToleranceInput, 0, 0, 1, 1); + + // ------------------------------------------------------------- + + TQLabel *label6 = new TQLabel(i18n("Color:"), secondPage); + + m_csmoothInput = new KDoubleNumInput(secondPage); + m_csmoothInput->setPrecision(1); + m_csmoothInput->setRange(0.0, 1.0, 0.1, true); + TQWhatsThis::add( m_csmoothInput, i18n("<p><b>Color</b>: this control sets the color tolerance of the image. It is " + "recommended using either the <b>Color</b> or the <b>Luminance</b> tolerance " + "to make image correction, not both at the same time. These settings " + "do not influence the main smoothing process controlled by the <b>Details</b> " + "settings.")); + + gridSettings2->addMultiCellWidget(label6, 1, 1, 0, 0); + gridSettings2->addMultiCellWidget(m_csmoothInput, 1, 1, 1, 1); + + // ------------------------------------------------------------- + + TQLabel *label8 = new TQLabel(i18n("Gamma:"), secondPage); + + m_gammaInput = new KDoubleNumInput(secondPage); + m_gammaInput->setPrecision(1); + m_gammaInput->setRange(0.3, 3.0, 0.1, true); + TQWhatsThis::add( m_gammaInput, i18n("<p><b>Gamma</b>: this control sets the gamma tolerance of the image. This value " + "can be used to increase the tolerance values for darker areas (which commonly " + "are noisier). This results in more blur for shadow areas.")); + + gridSettings2->addMultiCellWidget(label8, 2, 2, 0, 0); + gridSettings2->addMultiCellWidget(m_gammaInput, 2, 2, 1, 1); + + // ------------------------------------------------------------- + + TQLabel *label9 = new TQLabel(i18n("Damping:"), secondPage); + + m_dampingInput = new KDoubleNumInput(secondPage); + m_dampingInput->setPrecision(1); + m_dampingInput->setRange(0.5, 20.0, 0.5, true); + TQWhatsThis::add( m_dampingInput, i18n("<p><b>Damping</b>: this control sets the phase-jitter damping adjustment. " + "This value defines how fast the adaptive filter-radius reacts to luminance " + "variations. If increased, then edges appear smoother; if too high, then blur " + "may occur. If at minimum, then noise and phase jitter at the edges can occur. It " + "can suppress spike noise when increased, and this is the preferred method to " + "remove it.")); + + gridSettings2->addMultiCellWidget(label9, 3, 3, 0, 0); + gridSettings2->addMultiCellWidget(m_dampingInput, 3, 3, 1, 1); + gridSettings2->setColStretch(1, 10); + gridSettings2->setRowStretch(4, 10); + + m_imagePreviewWidget->setUserAreaWidget(mainTab); + + // ------------------------------------------------------------- + +// connect(m_radiusInput, TQ_SIGNAL(valueChanged(double)), +// this, TQ_SLOT(slotTimer())); +// +// connect(m_lumToleranceInput, TQ_SIGNAL(valueChanged(double)), +// this, TQ_SLOT(slotTimer())); +// +// connect(m_thresholdInput, TQ_SIGNAL(valueChanged(double)), +// this, TQ_SLOT(slotTimer())); +// +// connect(m_textureInput, TQ_SIGNAL(valueChanged(double)), +// this, TQ_SLOT(slotTimer())); +// +// connect(m_sharpnessInput, TQ_SIGNAL(valueChanged(double)), +// this, TQ_SLOT(slotTimer())); +// +// connect(m_csmoothInput, TQ_SIGNAL(valueChanged(double)), +// this, TQ_SLOT(slotTimer())); +// +// connect(m_lookaheadInput, TQ_SIGNAL(valueChanged(double)), +// this, TQ_SLOT(slotTimer())); +// +// connect(m_gammaInput, TQ_SIGNAL(valueChanged(double)), +// this, TQ_SLOT(slotTimer())); +// +// connect(m_dampingInput, TQ_SIGNAL(valueChanged(double)), +// this, TQ_SLOT(slotTimer())); +// +// connect(m_phaseInput, TQ_SIGNAL(valueChanged(double)), +// this, TQ_SLOT(slotTimer())); +} + +ImageEffect_NoiseReduction::~ImageEffect_NoiseReduction() +{ +} + +void ImageEffect_NoiseReduction::renderingFinished() +{ + m_radiusInput->setEnabled(true); + m_lumToleranceInput->setEnabled(true); + m_thresholdInput->setEnabled(true); + m_textureInput->setEnabled(true); + m_sharpnessInput->setEnabled(true); + m_csmoothInput->setEnabled(true); + m_lookaheadInput->setEnabled(true); + m_gammaInput->setEnabled(true); + m_dampingInput->setEnabled(true); + m_phaseInput->setEnabled(true); +} + +void ImageEffect_NoiseReduction::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("noisereduction Tool Dialog"); + m_radiusInput->setEnabled(true); + m_lumToleranceInput->setEnabled(true); + m_thresholdInput->setEnabled(true); + m_textureInput->setEnabled(true); + m_sharpnessInput->setEnabled(true); + m_csmoothInput->setEnabled(true); + m_lookaheadInput->setEnabled(true); + m_gammaInput->setEnabled(true); + m_dampingInput->setEnabled(true); + m_phaseInput->setEnabled(true); + + m_radiusInput->setValue(config->readDoubleNumEntry("RadiusAjustment", 1.0)); + m_lumToleranceInput->setValue(config->readDoubleNumEntry("LumToleranceAjustment", 1.0)); + m_thresholdInput->setValue(config->readDoubleNumEntry("ThresholdAjustment", 0.08)); + m_textureInput->setValue(config->readDoubleNumEntry("TextureAjustment", 0.0)); + m_sharpnessInput->setValue(config->readDoubleNumEntry("SharpnessAjustment", 0.25)); + m_csmoothInput->setValue(config->readDoubleNumEntry("CsmoothAjustment", 1.0)); + m_lookaheadInput->setValue(config->readDoubleNumEntry("LookAheadAjustment", 2.0)); + m_gammaInput->setValue(config->readDoubleNumEntry("GammaAjustment", 1.4)); + m_dampingInput->setValue(config->readDoubleNumEntry("DampingAjustment", 5.0)); + m_phaseInput->setValue(config->readDoubleNumEntry("PhaseAjustment", 1.0)); + + m_radiusInput->setEnabled(false); + m_lumToleranceInput->setEnabled(false); + m_thresholdInput->setEnabled(false); + m_textureInput->setEnabled(false); + m_sharpnessInput->setEnabled(false); + m_csmoothInput->setEnabled(false); + m_lookaheadInput->setEnabled(false); + m_gammaInput->setEnabled(false); + m_dampingInput->setEnabled(false); + m_phaseInput->setEnabled(false); +} + +void ImageEffect_NoiseReduction::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("noisereduction Tool Dialog"); + config->writeEntry("RadiusAjustment", m_radiusInput->value()); + config->writeEntry("LumToleranceAjustment", m_lumToleranceInput->value()); + config->writeEntry("ThresholdAjustment", m_thresholdInput->value()); + config->writeEntry("TextureAjustment", m_textureInput->value()); + config->writeEntry("SharpnessAjustment", m_sharpnessInput->value()); + config->writeEntry("CsmoothAjustment", m_csmoothInput->value()); + config->writeEntry("LookAheadAjustment", m_lookaheadInput->value()); + config->writeEntry("GammaAjustment", m_gammaInput->value()); + config->writeEntry("DampingAjustment", m_dampingInput->value()); + config->writeEntry("PhaseAjustment", m_phaseInput->value()); + config->sync(); +} + +void ImageEffect_NoiseReduction::resetValues() +{ + m_radiusInput->setEnabled(true); + m_lumToleranceInput->setEnabled(true); + m_thresholdInput->setEnabled(true); + m_textureInput->setEnabled(true); + m_sharpnessInput->setEnabled(true); + m_csmoothInput->setEnabled(true); + m_lookaheadInput->setEnabled(true); + m_gammaInput->setEnabled(true); + m_dampingInput->setEnabled(true); + m_phaseInput->setEnabled(true); + + m_radiusInput->setValue(1.0); + m_lumToleranceInput->setValue(1.0); + m_thresholdInput->setValue(0.08); + m_textureInput->setValue(0.0); + m_sharpnessInput->setValue(0.25); + m_csmoothInput->setValue(1.0); + m_lookaheadInput->setValue(2.0); + m_gammaInput->setValue(1.4); + m_dampingInput->setValue(5.0); + m_phaseInput->setValue(1.0); + + m_radiusInput->setEnabled(false); + m_lumToleranceInput->setEnabled(false); + m_thresholdInput->setEnabled(false); + m_textureInput->setEnabled(false); + m_sharpnessInput->setEnabled(false); + m_csmoothInput->setEnabled(false); + m_lookaheadInput->setEnabled(false); + m_gammaInput->setEnabled(false); + m_dampingInput->setEnabled(false); + m_phaseInput->setEnabled(false); +} + +void ImageEffect_NoiseReduction::prepareEffect() +{ + m_radiusInput->setEnabled(false); + m_lumToleranceInput->setEnabled(false); + m_thresholdInput->setEnabled(false); + m_textureInput->setEnabled(false); + m_sharpnessInput->setEnabled(false); + m_csmoothInput->setEnabled(false); + m_lookaheadInput->setEnabled(false); + m_gammaInput->setEnabled(false); + m_dampingInput->setEnabled(false); + m_phaseInput->setEnabled(false); + + double r = m_radiusInput->value(); + double l = m_lumToleranceInput->value(); + double th = m_thresholdInput->value(); + double tx = m_textureInput->value(); + double s = m_sharpnessInput->value(); + double c = m_csmoothInput->value(); + double a = m_lookaheadInput->value(); + double g = m_gammaInput->value(); + double d = m_dampingInput->value(); + double p = m_phaseInput->value(); + + Digikam::DImg image = m_imagePreviewWidget->getOriginalRegionImage(); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>(new NoiseReduction(&image, + this, r, l, th, tx, s, c, a, g, d, p)); +} + +void ImageEffect_NoiseReduction::prepareFinal() +{ + m_radiusInput->setEnabled(false); + m_lumToleranceInput->setEnabled(false); + m_thresholdInput->setEnabled(false); + m_textureInput->setEnabled(false); + m_sharpnessInput->setEnabled(false); + m_csmoothInput->setEnabled(false); + m_lookaheadInput->setEnabled(false); + m_gammaInput->setEnabled(false); + m_dampingInput->setEnabled(false); + m_phaseInput->setEnabled(false); + + double r = m_radiusInput->value(); + double l = m_lumToleranceInput->value(); + double th = m_thresholdInput->value(); + double tx = m_textureInput->value(); + double s = m_sharpnessInput->value(); + double c = m_csmoothInput->value(); + double a = m_lookaheadInput->value(); + double g = m_gammaInput->value(); + double d = m_dampingInput->value(); + double p = m_phaseInput->value(); + + Digikam::ImageIface iface(0, 0); + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>(new NoiseReduction(iface.getOriginalImg(), + this, r, l, th, tx, s, c, a, g, d, p)); +} + +void ImageEffect_NoiseReduction::putPreviewData(void) +{ + m_imagePreviewWidget->setPreviewImage(m_threadedFilter->getTargetImage()); +} + +void ImageEffect_NoiseReduction::putFinalData(void) +{ + Digikam::ImageIface iface(0, 0); + iface.putOriginalImage(i18n("Noise Reduction"), m_threadedFilter->getTargetImage().bits()); +} + +void ImageEffect_NoiseReduction::slotUser3() +{ + KURL loadRestorationFile = KFileDialog::getOpenURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), this, + TQString( i18n("Photograph Noise Reduction Settings File to Load")) ); + if ( loadRestorationFile.isEmpty() ) + return; + + TQFile file(loadRestorationFile.path()); + + if ( file.open(IO_ReadOnly) ) + { + TQTextStream stream( &file ); + if ( stream.readLine() != "# Photograph Noise Reduction Configuration File" ) + { + KMessageBox::error(this, + i18n("\"%1\" is not a Photograph Noise Reduction settings text file.") + .arg(loadRestorationFile.fileName())); + file.close(); + return; + } + + blockSignals(true); + m_radiusInput->setValue( stream.readLine().toDouble() ); + m_lumToleranceInput->setValue( stream.readLine().toDouble() ); + m_thresholdInput->setValue( stream.readLine().toDouble() ); + m_textureInput->setValue( stream.readLine().toDouble() ); + m_sharpnessInput->setValue( stream.readLine().toDouble() ); + m_csmoothInput->setValue( stream.readLine().toDouble() ); + m_lookaheadInput->setValue( stream.readLine().toDouble() ); + m_gammaInput->setValue( stream.readLine().toDouble() ); + m_dampingInput->setValue( stream.readLine().toDouble() ); + m_phaseInput->setValue( stream.readLine().toDouble() ); + blockSignals(false); +// slotEffect(); + } + else + KMessageBox::error(this, i18n("Cannot load settings from the Photograph Noise Reduction text file.")); + + file.close(); +} + +void ImageEffect_NoiseReduction::slotUser2() +{ + KURL saveRestorationFile = KFileDialog::getSaveURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), this, + TQString( i18n("Photograph Noise Reduction Settings File to Save")) ); + if ( saveRestorationFile.isEmpty() ) + return; + + TQFile file(saveRestorationFile.path()); + + if ( file.open(IO_WriteOnly) ) + { + TQTextStream stream( &file ); + stream << "# Photograph Noise Reduction Configuration File\n"; + stream << m_radiusInput->value() << "\n"; + stream << m_lumToleranceInput->value() << "\n"; + stream << m_thresholdInput->value() << "\n"; + stream << m_textureInput->value() << "\n"; + stream << m_sharpnessInput->value() << "\n"; + stream << m_csmoothInput->value() << "\n"; + stream << m_lookaheadInput->value() << "\n"; + stream << m_gammaInput->value() << "\n"; + stream << m_dampingInput->value() << "\n"; + stream << m_phaseInput->value() << "\n"; + + } + else + KMessageBox::error(this, i18n("Cannot save settings to the Photograph Noise Reduction text file.")); + + file.close(); +} + +} // NameSpace DigikamNoiseReductionImagesPlugin + diff --git a/src/imageplugins/noisereduction/imageeffect_noisereduction.h b/src/imageplugins/noisereduction/imageeffect_noisereduction.h new file mode 100644 index 00000000..b7ee1bb6 --- /dev/null +++ b/src/imageplugins/noisereduction/imageeffect_noisereduction.h @@ -0,0 +1,82 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-24 + * Description : a plugin to reduce CCD noise. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_NOISEREDUCTION_H +#define IMAGEEFFECT_NOISEREDUCTION_H + +// Local includes. + +#include "ctrlpaneldlg.h" + +class KDoubleNumInput; + +namespace DigikamNoiseReductionImagesPlugin +{ + +class ImageEffect_NoiseReduction : public Digikam::CtrlPanelDlg +{ + TQ_OBJECT + + +public: + + ImageEffect_NoiseReduction(TQWidget* parent); + ~ImageEffect_NoiseReduction(); + +private slots: + + void readUserSettings(); + +private: + + void writeUserSettings(); + void resetValues(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private slots: + + void slotUser2(); + void slotUser3(); + +private: + + KDoubleNumInput *m_radiusInput; + KDoubleNumInput *m_lumToleranceInput; + KDoubleNumInput *m_thresholdInput; + KDoubleNumInput *m_textureInput; + KDoubleNumInput *m_sharpnessInput; + + KDoubleNumInput *m_csmoothInput; + KDoubleNumInput *m_lookaheadInput; + KDoubleNumInput *m_gammaInput; + KDoubleNumInput *m_dampingInput; + KDoubleNumInput *m_phaseInput; +}; + +} // NameSpace DigikamNoiseReductionImagesPlugin + +#endif /* IMAGEEFFECT_NOISEREDUCTION_H */ diff --git a/src/imageplugins/noisereduction/imageplugin_noisereduction.cpp b/src/imageplugins/noisereduction/imageplugin_noisereduction.cpp new file mode 100644 index 00000000..8392933d --- /dev/null +++ b/src/imageplugins/noisereduction/imageplugin_noisereduction.cpp @@ -0,0 +1,70 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-24 + * Description : a plugin to reduce CCD noise. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> +#include <tdeapplication.h> + +// Local includes. + +#include "ddebug.h" +#include "noisereductiontool.h" +#include "imageplugin_noisereduction.h" +#include "imageplugin_noisereduction.moc" + +using namespace DigikamNoiseReductionImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_noisereduction, + KGenericFactory<ImagePlugin_NoiseReduction>("digikamimageplugin_noisereduction")); + +ImagePlugin_NoiseReduction::ImagePlugin_NoiseReduction(TQObject *parent, const char*, const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_NoiseReduction") +{ + m_noiseReductionAction = new TDEAction(i18n("Noise Reduction..."), "noisereduction", 0, + this, TQ_SLOT(slotNoiseReduction()), + actionCollection(), "imageplugin_noisereduction"); + + setXMLFile("digikamimageplugin_noisereduction_ui.rc"); + + DDebug() << "ImagePlugin_NoiseReduction plugin loaded" << endl; +} + +ImagePlugin_NoiseReduction::~ImagePlugin_NoiseReduction() +{ +} + +void ImagePlugin_NoiseReduction::setEnabledActions(bool enable) +{ + m_noiseReductionAction->setEnabled(enable); +} + +void ImagePlugin_NoiseReduction::slotNoiseReduction() +{ + NoiseReductionTool *tool = new NoiseReductionTool(this); + loadTool(tool); +} diff --git a/src/imageplugins/noisereduction/imageplugin_noisereduction.h b/src/imageplugins/noisereduction/imageplugin_noisereduction.h new file mode 100644 index 00000000..3cbcb312 --- /dev/null +++ b/src/imageplugins/noisereduction/imageplugin_noisereduction.h @@ -0,0 +1,56 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-24 + * Description : a plugin to reduce CCD noise. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_NOISEREDUCTION_H +#define IMAGEPLUGIN_NOISEREDUCTION_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_NoiseReduction : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_NoiseReduction(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_NoiseReduction(); + + void setEnabledActions(bool enable); + +private slots: + + void slotNoiseReduction(); + +private: + + TDEAction *m_noiseReductionAction; +}; + +#endif /* IMAGEPLUGIN_NOISEREDUCTION_H */ diff --git a/src/imageplugins/noisereduction/noisereduction.cpp b/src/imageplugins/noisereduction/noisereduction.cpp new file mode 100644 index 00000000..b9be4729 --- /dev/null +++ b/src/imageplugins/noisereduction/noisereduction.cpp @@ -0,0 +1,809 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : Noise Reduction threaded image filter. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * Original Noise Filter algorithm copyright (C) 2005 + * Peter Heckert <peter dot heckert at arcor dot de> + * from dcamnoise2 gimp plugin available at this url : + * http://home.arcor.de/peter.heckert/dcamnoise2-0.63.c + * + * 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. + * + * ============================================================ */ + +#define IIR1(dest,src) (dest) = (d3 = ((((src) * b + d3) * b3 + d2) * b2 + d1) * b1) +#define IIR2(dest,src) (dest) = (d2 = ((((src) * b + d2) * b3 + d1) * b2 + d3) * b1) +#define IIR3(dest,src) (dest) = (d1 = ((((src) * b + d1) * b3 + d3) * b2 + d2) * b1) + +#define IIR1A(dest,src) (dest) = fabs(d3 = ((((src) * b + d3) * b3 + d2) * b2 + d1) * b1) +#define IIR2A(dest,src) (dest) = fabs(d2 = ((((src) * b + d2) * b3 + d1) * b2 + d3) * b1) +#define IIR3A(dest,src) (dest) = fabs(d1 = ((((src) * b + d1) * b3 + d3) * b2 + d2) * b1) + +#define FR 0.212671 +#define FG 0.715160 +#define FB 0.072169 + +// Local includes. + +#include "ddebug.h" +#include "dimg.h" +#include "dimgimagefilters.h" +#include "noisereduction.h" + +namespace DigikamNoiseReductionImagesPlugin +{ + +NoiseReduction::NoiseReduction(Digikam::DImg *orgImage, TQObject *parent, + double radius, double lsmooth, double effect, double texture, double sharp, + double csmooth, double lookahead, double gamma, double damping, double phase) + : Digikam::DImgThreadedFilter(orgImage, parent, "NoiseReduction") +{ + m_radius = radius; /* default radius default = 1.0 */ + m_sharp = sharp; /* Sharpness factor default = 0.25 */ + m_lsmooth = lsmooth; /* Luminance Tolerance default = 1.0 */ + m_effect = effect; /* Adaptive filter-effect threshold default = 0.08 */ + m_texture = texture; /* Texture Detail default = 0.0 */ + + m_csmooth = csmooth; /* RGB Tolerance default = 1.0 */ + m_lookahead = lookahead; /* Lookahead default = 2.0 */ + m_gamma = gamma; /* Filter gamma default = 1.0 */ + m_damping = damping; /* Phase jitter Damping default = 5.0 */ + m_phase = phase; /* Area Noise Clip default = 1.0 */ + + m_iir.B = 0.0; + m_iir.b1 = 0.0; + m_iir.b2 = 0.0; + m_iir.b3 = 0.0; + m_iir.b0 = 0.0; + m_iir.r = 0.0; + m_iir.q = 0.0; + m_iir.p = 0; + + m_clampMax = m_orgImage.sixteenBit() ? 65535 : 255; + + initFilter(); +} + +// Remove noise on the region, given a source region, dest. +// region, width and height of the regions, and corner coordinates of +// a subregion to act upon. Everything outside the subregion is unaffected. + +void NoiseReduction::filterImage(void) +{ + int bytes = m_orgImage.bytesDepth(); // Bytes per pixel sample + uchar *srcPR = m_orgImage.bits(); + uchar *destPR = m_destImage.bits(); + int width = m_orgImage.width(); + int height = m_orgImage.height(); + + int row, col, i, progress; + float prob = 0.0; + + int w = (int)((m_radius + m_lookahead + m_damping + m_phase) * 4.0 + 40.0); + + // NOTE: commented from original implementation + // if (radius < m_lookahead) w = m_lookahead * 4.0 + 40.0; + + float csmooth = m_csmooth; + + // Raw Filter preview + + if (csmooth >= 0.99) csmooth = 1.0; + + // Allocate and init buffers + + uchar *src = new uchar[ TQMAX (width, height) * bytes ]; + uchar *dest = new uchar[ TQMAX (width, height) * bytes ]; + float *data = new float[ TQMAX (width, height) + 2*w ]; + float *data2 = new float[ TQMAX (width, height) + 2*w ]; + float *buffer = new float[ TQMAX (width, height) + 2*w ]; + float *rbuf = new float[ TQMAX (width, height) + 2*w ]; + float *tbuf = new float[ TQMAX (width, height) + 2*w ]; + + memset (src, 0, TQMAX (width, height) * bytes); + memset (dest, 0, TQMAX (width, height) * bytes); + + for (i=0 ; i < TQMAX(width,height)+2*w-1 ; i++) + data[i] = data2[i] = buffer[i] = rbuf[i] = tbuf[i] = 0.0; + + // Initialize the damping filter coefficients + + iir_init(m_radius); + + // blur the rows + + for (row = 0 ; !m_cancel && (row < height) ; row++) + { + memcpy(src, srcPR + row*width*bytes, width*bytes); + memcpy(dest, src, width*bytes); + + blur_line (data+w, data2+w, buffer+w, rbuf+w, tbuf+w, src, dest, width); + + memcpy(destPR + row*width*bytes, dest, width*bytes); + + progress = (int)(((double)row * 20.0) / height); + if ( progress%2 == 0 ) + postProgress( progress ); + } + + // blur the cols + + for (col = 0 ; !m_cancel && (col < width) ; col++) + { + for (int n = 0 ; n < height ; n++) + memcpy(src + n*bytes, destPR + (col + width*n)*bytes, bytes); + + for (int n = 0 ; n < height ; n++) + memcpy(dest + n*bytes, srcPR + (col + width*n)*bytes, bytes); + + blur_line (data+w, data2+w, buffer+w, rbuf+w, tbuf+w, src, dest, height); + + for (int n = 0 ; n < height ; n++) + memcpy(destPR + (col + width*n)*bytes, dest + n*bytes, bytes); + + progress = (int)(20.0 + ((double)col * 20.0) / width); + if ( progress%2 == 0 ) + postProgress( progress ); + } + + // merge the source and destination (which currently contains + // the blurred version) images + + for (row = 0 ; !m_cancel && (row < height) ; row++) + { + uchar *s = src; + uchar *d = dest; + unsigned short *s16 = (unsigned short *)src; + unsigned short *d16 = (unsigned short *)dest; + float value; + int u, v; + + // get source row + + memcpy(src, srcPR + row*width*bytes, width*bytes); + memcpy(dest, destPR + row*width*bytes, width*bytes); + + // get dest row and combine the two + + float t = m_csmooth; + float t2 = m_lsmooth; + + // Values are squared, so that sliders get a nonlinear chracteristic + // for better adjustment accuracy when values are small. + t*=t; + t2*=t2; + + for (u = 0 ; !m_cancel && (u < width) ; u++) + { + float dpix[3], spix[3]; + float lum, red, green, blue; + float lum2, red2, green2, blue2; + + if (m_orgImage.sixteenBit()) // 16 bits image + { + red = (float) s16[2]/(float)m_clampMax; + green = (float) s16[1]/(float)m_clampMax; + blue = (float) s16[0]/(float)m_clampMax; + } + else // 8 bits image + { + red = (float) s[2]/(float)m_clampMax; + green = (float) s[1]/(float)m_clampMax; + blue = (float) s[0]/(float)m_clampMax; + } + + spix[2] = red; + spix[1] = green; + spix[0] = blue; + + lum = (FR*red + FG*green + FB*blue); + + if (m_orgImage.sixteenBit()) // 16 bits image + { + red2 = (float) d16[2]/(float)m_clampMax; + green2 = (float) d16[1]/(float)m_clampMax; + blue2 = (float) d16[0]/(float)m_clampMax; + } + else // 8 bits image + { + red2 = (float) d[2]/(float)m_clampMax; + green2 = (float) d[1]/(float)m_clampMax; + blue2 = (float) d[0]/(float)m_clampMax; + } + + lum2 = (FR*red2 + FG*green2 + FB*blue2); + + // Calculate luminance error (contrast error) for filtered template. + // This error is biggest, where edges are. Edges anyway cannot be filtered. + // Therefore we can correct luminance error in edges without increasing noise. + // Should be adjusted carefully, or not so carefully if you intentionally want to add noise. + // Noise, if not colorized, /can/ look good, so this makes sense. + + float dl = lum - lum2; + + // Multiply dl with first derivative of gamma curve divided by derivative value for midtone 0.5 + // So bright tones will be corrected more (get more luminance noise and -information) than + // darker values because bright parts of image generally are less noisy, this is what we want. + + dl *= pow(lum2/0.5, m_gamma-1.0); + + if (t2 > 0.0) + dl *= (1.0 - exp(-dl*dl/(2.0*t2*t2))); + + // NOTE: commented from original implementation + // if (dl > p) dl = p; + // if (dl < -p) dl = -p; + + dpix[2] = red2 + dl; + dpix[1] = green2 + dl; + dpix[0] = blue2 + dl; + + for (v = 0 ; !m_cancel && (v < 3) ; v++) + { + float value = spix[v]; + float fvalue = dpix[v]; + float mvalue = (value + fvalue)/2.0; + float diff = (value) - (fvalue); + + // Multiply diff with first derivative of gamma curve divided by derivative value for midtone 0.5 + // So midtones will stay unchanged, darker values get more blur and brighter values get less blur + // when we increase gamma. + + diff *= pow(mvalue/0.5, m_gamma-1.0); + + // Calculate noise probability for pixel + // TODO : probably it is not probability but an arbitrary curve. + // Probably we should provide a GUI-interface for this!!! + + if (t > 0.0) + prob = exp(-diff*diff/(2.0*t*t)); + else + prob = 0.0; + + // Allow viewing of raw filter output + + if (t >= 0.99) + prob = 1.0; + + dpix[v] = value = fvalue * prob + value * (1.0 - prob); + } + + if (m_orgImage.sixteenBit()) // 16 bits image + { + value = dpix[0]*(float)m_clampMax+0.5; + d16[0] = (unsigned short)CLAMP(value, 0, m_clampMax); + value = dpix[1]*(float)m_clampMax+0.5; + d16[1] = (unsigned short)CLAMP(value, 0, m_clampMax); + value = dpix[2]*(float)m_clampMax+0.5; + d16[2] = (unsigned short)CLAMP(value, 0, m_clampMax); + + d16 += 4; + s16 += 4; + } + else // 8 bits image + { + value = dpix[0]*(float)m_clampMax+0.5; + d[0] = (uchar)CLAMP(value, 0, m_clampMax); + value = dpix[1]*(float)m_clampMax+0.5; + d[1] = (uchar)CLAMP(value, 0, m_clampMax); + value = dpix[2]*(float)m_clampMax+0.5; + d[2] = (uchar)CLAMP(value, 0, m_clampMax); + + d += 4; + s += 4; + } + } + + memcpy(destPR + row*width*bytes, dest, width*bytes); + + progress = (int)(40.0 + ((double)row * 60.0) / height); + if ( progress%2 == 0 ) + postProgress( progress ); + } + + delete [] data; + delete [] data2; + delete [] buffer; + delete [] rbuf; + delete [] tbuf; + delete [] dest; + delete [] src; +} + +// This function is written as if it is blurring a column at a time, +// even though it can operate on rows, too. There is no difference +// in the processing of the lines, at least to the blur_line function. +// 'len' is the length of src and dest + +void NoiseReduction::blur_line(float* const data, float* const data2, float* const buffer, + float* rbuf, float* tbuf, const uchar *src, uchar *dest, int len) +{ + int b; + int row; + int idx; + + unsigned short *src16 = (unsigned short *)src; + unsigned short *dest16 = (unsigned short *)dest; + + // Calculate radius factors + + for (row = 0, idx = 0 ; !m_cancel && (idx < len) ; row += 4, idx++) + { + // Color weigths are chosen proportional to Bayer Sensor pixel count + + if (m_orgImage.sixteenBit()) // 16 bits image + { + data[idx] = (float) dest16[row+2] / (float)m_clampMax * 0.25; // Red color + data[idx] += (float) dest16[row+1] / (float)m_clampMax * 0.5; // Green color + data[idx] += (float) dest16[row] / (float)m_clampMax * 0.25; // Blue color + data[idx] = mypow(data[idx], m_gamma); + } + else // 8 bits image + { + data[idx] = (float) dest[row+2] / (float)m_clampMax * 0.25; // Red color + data[idx] += (float) dest[row+1] / (float)m_clampMax * 0.5; // Green color + data[idx] += (float) dest[row] / (float)m_clampMax * 0.25; // Blue color + data[idx] = mypow(data[idx], m_gamma); + } + } + + filter(data, data2, buffer, rbuf, tbuf, len, -1); + + // Do actual filtering + + for (b = 0 ; !m_cancel && (b < 3) ; b++) + { + for (row = b, idx = 0 ; !m_cancel && (idx < len) ; row += 4, idx++) + { + if (m_orgImage.sixteenBit()) // 16 bits image + data[idx] = (float)src16[row] / (float)m_clampMax; + else // 8 bits image + data[idx] = (float)src[row] / (float)m_clampMax; + } + + filter(data, data2, buffer, rbuf, tbuf, len, b); + + for (row = b, idx = 0 ; !m_cancel && (idx < len) ; row += 4, idx++) + { + int value = (int)(data[idx] * (float)m_clampMax + 0.5); + + if (m_orgImage.sixteenBit()) // 16 bits image + dest16[row] = (unsigned short)CLAMP( value, 0, m_clampMax); + else // 8 bits image + dest[row] = (uchar)CLAMP( value, 0, m_clampMax); + } + } +} + +void NoiseReduction::iir_init(double r) +{ + if (m_iir.r == r) + return; + + // damping settings; + m_iir.r = r; + + double q; + + if ( r >= 2.5) + q = 0.98711 * r - 0.96330; + else + q = 3.97156 - 4.14554 * sqrt(1.0 - 0.26891 * r); + + m_iir.q = q; + m_iir.b0 = 1.57825 + ((0.422205 * q + 1.4281) * q + 2.44413) * q; + m_iir.b1 = ((1.26661 * q +2.85619) * q + 2.44413) * q / m_iir.b0; + m_iir.b2 = - ((1.26661*q +1.4281) * q * q ) / m_iir.b0; + m_iir.b3 = 0.422205 * q * q * q / m_iir.b0; + m_iir.B = 1.0 - (m_iir.b1 + m_iir.b2 + m_iir.b3); +} + +void NoiseReduction::box_filter(double *src, double *end, double *dest, double radius) +{ + int boxwidth = 1; + float box = (*src); + float fbw = 2.0 * radius; + + if (fbw < 1.0) + fbw = 1.0; + + while(boxwidth+2 <= (int) fbw) boxwidth+=2, box += (src[boxwidth/2]) + (src[-boxwidth/2]); + + double frac = (fbw - (double) boxwidth) / 2.0; + int bh = boxwidth / 2; + int bh1 = boxwidth / 2+1; + + for ( ; src <= end ; src++, dest++) + { + *dest = (box + frac * ((src[bh1])+(src[-bh1]))) / fbw; + box = box - (src[-bh]) + (src[bh1]); + } +} + +// Bidirectional IIR-filter, speed optimized + +void NoiseReduction::iir_filter(float* const start, float* const end, float* dstart, + double radius, const int type) +{ + if (!dstart) + dstart = start; + + int width; + float *src = start; + float *dest = dstart; + float *dend = dstart + (end - start); + + radius = floor((radius + 0.1) / 0.5) * 0.5; + + // NOTE: commented from original implementation + // gfloat boxwidth = radius * 2.0; + // gint bw = (gint) boxwidth; + + int ofs = (int)radius; + if (ofs < 1) ofs = 1; + + double d1, d2, d3; + + width = end - start + 1; + + if (radius < 0.25) + { + if ( start != dest ) + { + memcpy(dest, start, width*sizeof(*dest)); + return; + } + } + + iir_init(radius); + + const double b1 = m_iir.b1; + const double b2 = m_iir.b2 / m_iir.b1; + const double b3 = m_iir.b3 / m_iir.b2; + const double b = m_iir.B / m_iir.b3; + + switch(type) + { + case Gaussian: + + d1 = d2 = d3 = *dest; + dend -= 6; + src--; + dest--; + + while (dest < dend) + { + IIR1(*(++dest), *(++src)); + IIR2(*(++dest), *(++src)); + IIR3(*(++dest), *(++src)); + IIR1(*(++dest), *(++src)); + IIR2(*(++dest), *(++src)); + IIR3(*(++dest), *(++src)); + } + + dend += 6; + + while (1) + { + if (++dest > dend) break; + IIR1(*dest,*(++src)); + if (++dest > dend) break; + IIR2(*dest,*(++src)); + if (++dest > dend) break; + IIR3(*dest,*(++src)); + } + + d1 = d2 = d3 = dest[-1]; + dstart += 6; + + while (dest > dstart) + { + --dest, IIR1(*dest, *dest); + --dest, IIR2(*dest, *dest); + --dest, IIR3(*dest, *dest); + --dest, IIR1(*dest, *dest); + --dest, IIR2(*dest, *dest); + --dest, IIR3(*dest, *dest); + } + + dstart -= 6; + + while (1) + { + if (--dest < dstart) break; + IIR1(*dest, *dest); + if (--dest < dstart) break; + IIR2(*dest, *dest); + if (--dest < dstart) break; + IIR3(*dest, *dest); + } + + break; + + case SecondDerivative: // rectified and filtered second derivative, source and dest may be equal + + d1 = d2 = d3 = 0.0; + dest[0] = dest[ofs] = 0.0; + dend -= 6; + dest--; + src--; + + while (dest < dend) + { + ++src, IIR1(*(++dest), src[ofs]-src[0]); + ++src, IIR2(*(++dest), src[ofs]-src[0]); + ++src, IIR3(*(++dest), src[ofs]-src[0]); + ++src, IIR1(*(++dest), src[ofs]-src[0]); + ++src, IIR2(*(++dest), src[ofs]-src[0]); + ++src, IIR3(*(++dest), src[ofs]-src[0]); + } + + dend += 6; + + while (1) + { + if (++dest > dend) break; + ++src, IIR1(*dest, src[ofs]-src[0]); + if (++dest > dend) break; + ++src, IIR2(*dest, src[ofs]-src[0]); + if (++dest > dend) break; + ++src, IIR3(*dest, src[ofs]-src[0]); + } + + d1 = d2 = d3 = 0.0; + dest[-1] = dest[-ofs-1] = 0.0; + dstart += 6; + + while (dest > dstart) + { + --dest, IIR1A(*dest, dest[0]-dest[-ofs]); + --dest, IIR2A(*dest, dest[0]-dest[-ofs]); + --dest, IIR3A(*dest, dest[0]-dest[-ofs]); + --dest, IIR1A(*dest, dest[0]-dest[-ofs]); + --dest, IIR2A(*dest, dest[0]-dest[-ofs]); + --dest, IIR3A(*dest, dest[0]-dest[-ofs]); + } + + dstart -= 6; + + while (1) + { + if (--dest < dstart) break; + IIR1A(*dest, dest[0]-dest[-ofs]); + if (--dest < dstart) break; + IIR2A(*dest, dest[0]-dest[-ofs]); + if (--dest < dstart) break; + IIR3A(*dest, dest[0]-dest[-ofs]); + } + + break; + } +} + +// A forward-backward box filter is used here and the radius is adapted to luminance jump. +// Radius is calculated fron 1st and 2nd derivative of intensity values. +// (Its not exactly 2nd derivative, but something similar, optimized by experiment) +// The radius variations are filtered. This reduces spatial phase jitter. + +void NoiseReduction::filter(float *buffer, float *data, float *data2, float *rbuf, + float */*tbuf*/, int width, int color) +{ + float *lp = data; + float *rp = data + width-1; + float *lp2 = data2; + float *blp = buffer; + float *brp = buffer + width-1; + float *rbuflp = rbuf; + float *rbufrp = rbuf + width-1; + float fboxwidth = m_radius*2.0; + float fradius = m_radius; + float *p1, *p2; + + if (fboxwidth < 1.0) fboxwidth = 1.0 ; + if (fradius < 0.5) fradius = 0.5; + + int i, pass; + int ofs, ofs2; + float maxrad; + float fbw; + float val; + double rfact = m_effect*m_effect; + double sharp = m_sharp; + + ofs2 = (int)floor(m_damping * 2.0 + 0.1); + ofs = (int)floor(m_lookahead * 2.0 + 0.1); + int w = (int)(fboxwidth + m_damping + m_lookahead + m_phase + 2.0); + + // Mirror image edges + + for (i=1 ; i <= w ; i++) + blp[-i] = blp[i]; + + for (i=1 ; i <= w ; i++) + brp[i] = brp[-i]; + + if (color < 0) // Calc 2nd derivative + { + // boost high frequency in rbuf + + for (p1 = blp, p2 = rbuflp ; p1 <= brp ; p1++, p2++) + { + *p2 = (sharp+1.0) * p1[0] - sharp * 0.5 * (p1[-ofs]+p1[ofs]); + } + + iir_filter(rbuflp-w, rbufrp+w, blp-w, m_lookahead, SecondDerivative); + + // Mirror image edges + + for (i = 1 ; i <= w ; i++) + blp[-i] = blp[i]; + + for (i = 1 ; i <= w ; i++) + brp[i] = brp[-i]; + + // boost high frequency in rbuf + + for (p1 = blp, p2 = rbuflp ; p1 <= brp ; p1++, p2++) + { + *p2 = ((sharp+1.0) * (p1[0]) - sharp * 0.5 * ((p1[-ofs2])+(p1[ofs2]))); + } + + // Mirror rbuf edges + + for (i = 1 ; i <= w ; i++) + rbuflp[-i] = rbuflp[i]; + + for (i = 1 ; i <= w ; i++) + rbufrp[i] = rbufrp[-i]; + + // Lowpass (gauss) filter rbuf, remove phase jitter + + iir_filter(rbuflp-w+5, rbufrp+w-5, rbuflp-w+5, m_damping, Gaussian); + + for (i = -w+5; i < width-1+w-5 ; i++) + { + // NOTE: commented from original implementation + // val = rbuflp[i]; + + val = rbuflp[i]-rfact; + + // Avoid division by zero, clip negative filter overshoot + + if (val < rfact/fradius) val=rfact/fradius; + + val = rfact/val; + + // NOTE: commented from original implementation + // val = pow(val/fradius,m_phase)*fradius; + + if (val < 0.5) val = 0.5; + + rbuflp[i] = val*2.0; + } + + // Mirror rbuf edges + + for (i=1 ; i <= w ; i++) + rbuflp[-i] = rbuflp[i]; + + for (i=1 ; i <= w ; i++) + rbufrp[i] = rbufrp[-i]; + + return; + } + + // Calc lowpass filtered input signal + + iir_filter(blp-w+1, brp+w-1, lp2-w+1, m_radius, Gaussian); + + // Subtract low frequency from input signal (aka original image data) + // and predistort this signal + + val = m_texture + 1.0; + + for (i = -w+1 ; i <= width-1+w-1 ; i++) + { + blp[i] = mypow(blp[i] - lp2[i], val); + } + + float *src, *dest; + val = m_texture + 1.0; + + pass = 2; + + while (pass--) + { + float sum; + int ibw; + src = blp; + dest = lp; + maxrad = 0.0; + + // Mirror left edge + + for (i=1 ; i <= w ; i++) + src[-i] = src[i]; + + sum = (src[-1] += src[-2]); + + // forward pass + + for (rbuf = rbuflp-(int) m_phase ; rbuf <= rbufrp; src++, dest++, rbuf++) + { + // NOTE: commented from original implementation + //fbw = fabs( rbuf[-ofs2]*ll2+rbuf[-ofs2-1]*rl2); + + fbw = *rbuf; + + if (fbw > (maxrad += 1.0)) fbw = maxrad; + else if (fbw < maxrad) maxrad = fbw; + + ibw = (int)fbw; + *src = sum += *src; + *dest = (sum-src[-ibw]+(src[-ibw]-src[-ibw-1])*(fbw-ibw))/fbw; + } + + src = rp; + dest = brp; + maxrad = 0.0; + + // Mirror right edge + + for (i=1 ; i <= w ; i++) + src[i] = src[-i]; + + sum = (src[1] += src[2]); + + // backward pass + + for ( rbuf = rbufrp +(int) m_phase ; rbuf >= rbuflp; src--, dest--, rbuf--) + { + // NOTE: commented from original implementation + //fbw = fabs( rbuf[ofs2]*ll2+rbuf[ofs2+1]*rl2); + + fbw = *rbuf; + + if (fbw > (maxrad +=1.0)) fbw = maxrad; + else if (fbw < maxrad) maxrad = fbw; + + ibw = (int)fbw; + + *src = sum += *src; + *dest = (sum-src[ibw]+(src[ibw]-src[ibw+1])*(fbw-ibw))/fbw; + } + } + + val = 1.0 / (m_texture + 1.0); + + for (i = -w+1 ; i <= width-1+w-1 ; i++) + { + // Undo predistortion + + blp[i]= mypow(blp[i],val); + + // Add in low frequency + + blp[i] += lp2[i]; + + // NOTE: commented from original implementation + // if (blp[i] >= 0.0) blp[i] = pow(blp[i],val); + // else blp[i] = 0.0; + } +} + +} // NameSpace DigikamNoiseReductionImagesPlugin diff --git a/src/imageplugins/noisereduction/noisereduction.h b/src/imageplugins/noisereduction/noisereduction.h new file mode 100644 index 00000000..69e14123 --- /dev/null +++ b/src/imageplugins/noisereduction/noisereduction.h @@ -0,0 +1,257 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : Noise Reduction threaded image filter. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * Original Noise Filter algorithm copyright (C) 2005 + * Peter Heckert <peter dot heckert at arcor dot de> + * from dcamnoise2 gimp plugin available at this url : + * http://home.arcor.de/peter.heckert/dcamnoise2-0.63.c + * + * 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. + * + * ============================================================ */ + +#ifndef NOISE_REDUCTION_H +#define NOISE_REDUCTION_H + +// C++ includes. + +#include <cmath> + +// Digikam includes. + +#include "dimgthreadedfilter.h" + +/**============= NOTICE TO USE THE FILTER =============================================================== + * + * Let me explain, how the filter works, some understanding is necessary to use it: + * + * Hint for the novice user: + * In most cases only Filter Max Radius, Filter treshold and Texture Detail are needed and the other + * params can be left at their default setting. + * + * Main Filter (Preprocessing) + * First, a filtered template is generated, using an adaptive filter. + * To see this template, we must set _Luminance tolerance, _Color tolerance to 1.0. + *------------------------------------------------------------------------------------------------------------ + * + * "Filter max. Radius" is preset to 5.0 + * This is good for most noise situations. + * In any case it must be about the same size as noise granularity ore somewhat more. + * If it is set higher than necessary, then it can cause unwanted blur. + *------------------------------------------------------------------------------------------------------------ + * + * "Filter Threshold" should be set so that edges are clearly visible and noise is smoothed out. + * This threshold value is not bound to any intensity value, it is bound to the second derivative of + * intensity values. + * Simply adjust it and watch the preview. Adjustment must be made carefully, because the gap + * between "noisy", "smooth", and "blur" is very small. Adjust it as carefully as you would adjust + * the focus of a camera. + *------------------------------------------------------------------------------------------------------------ + * + * "Lookahead" defines the pixel distance in which the filter looks ahead for luminance variations + * Normally the default value should do. + * When _Lookahead is increased, then spikenoise is erased. + * Eventually readjust Filter treshold, when you changed lookahead. + * When the value is to high, then the adaptive filter cannot longer accurately track image details, and + * noise can reappear or blur can occur. + * + * Minimum value is 1.0, this gives best accuracy when blurring very weak noise. + * + * I never had good success with other values than 2.0. + * However, for images with extemely high or low resolution another value possibly is better. + * Use it only as a last ressort. + *------------------------------------------------------------------------------------------------------------ + * + * "Phase Jitter Damping" defines how fast the adaptive filter-radius reacts to luminance variations. + * I have preset a value, that should do in most cases. + * If increased, then edges appear smoother, if too high, then blur may occur. + * If at minimum then noise and phase jitter at edges can occur. + * It can suppress Spike noise when increased and this is the preferred method to remove spike noise. + *------------------------------------------------------------------------------------------------------------ + * + * "Sharpness" does just what it says, it improves sharpness. It improves the frequency response for the filter. + * When it is too strong then not all noise can be removed, or spike noise may appear. + * Set it near to maximum, if you want to remove weak noise or JPEG-artifacts, without loosing detail. + *------------------------------------------------------------------------------------------------------------ + * + * "Erosion". The new filter gives better sharpness and this also gives problems + * with spike noise. The Erosion param erodes singular spikes and it has a smooth effect to edges, and sharpens + * edges by erosion, so noise at edges is eroded. + * The effect is dependant from sharpness,phase-jitter damping and lookahead. + * Set it to minimum (zero), if you want to remove weak noise or JPEG-artifacts. + * When "Erosion" is increased, then also increasing "Phase Jitter Damping" is often useful + * + * It works nicely. Apart from removing spike noise it has a sharpening and antialiasing effect to edges + * (Sharpening occurs by erosion, not by deconvolution) + *------------------------------------------------------------------------------------------------------------ + * + * "Texture Detail" can be used, to get more or less texture accuracy. + * When decreased, then noise and texture are blurred out, when increased then texture is + * amplified, but also noise will increase. + * It has almost no effect to image edges, opposed to Filter theshold, which would blur edges, when increased. + * + * E.g. if Threshold is adjusted in away so that edges are sharp, and there is still too much area noise, then + * Texture detail could be used to reduce noise without blurring edges. + * (Another way would be to decrease radius and to increase threshold) + * + *------------------------------------------------------------------------------------------------------------ + * + * The filtered image that is now seen in the preview, is used as template for the following processing steps, + * therefore it is important to do this adjustment in first place and to do it as good as possible. + *------------------------------------------------------------------------------------------------------------ + * + * Combining original image and filtered image, using tolerance thresholds (Postprocessing) + * This can give a final touch of sharpness to your image. + * It is not necessary to do this, if you want to reduce JPEG-artifacts or weak noise. + * It's purpose is to master strong noise without loosing too much sharpness. + * + * Note, that this all is done in one filter invocation. Preprocessing and postprocessing is done in one run, + * but logically and in the algorithm they are different and ordered processes. + * + * + * Adjust _Color tolerance or/and Luminance tolerance, (if necessary) so that you get the final image. + * I recommend to use only one, either _Color or _Luminance. + * These settings do not influence the main smoothing process. What they really do is this: + * + * The tolerance values are used as error-thresholds to compare the filtered template with the original + * image. The plugin algorithm uses them to combine the filtered template with the original image + * so that noise and filter errors (blur) are thrown out. + * A filtered pixel, that is too far away from the original pixel will be overridden by original image content. + * + * Hint: + * If you cange other sliders, like lookahead or Texture Detail, then you should set color tolerance and + * luminance tolerance to 1.0 (right end), because otherwise the filtered template is partially hidden + * and e.g. the effects for the damping filter cant be seen clearly and cant be optimized. + *------------------------------------------------------------------------------------------------------------ + * + * _Gamma can be used to increase the tolerance values for darker areas (which commonly are more noisy) + * This results in more blur for shadow areas. + * + * Hint for users of previous versions: + * Gamma also influences the main-filter process. While the previous version did not have this feature, + * I have reimplemented it, however, the algorithm used is totally new. + * + * + * Keep in mind, how the filter works, then usage should be easy! + * + * + * ================ THEORY AND TECHNIC ======================================================================= + * + * Some interesting things (theoretic and technic) + * This plugin bases on the assumption, that noise has no 2-dimensional correlation and therefore + * can be removed in a 1-dimensional process. + * To remove noise, I use a four-times boxfilter with variable radius. + * + * The radius is calculated from 2nd derivative of pixeldata. + * A gauss filter is used to calculte 2nd derivative. + * The filter has some inbuilt features to clip low amplitude noise to clip very high values that would + * slow down response time. + * The 2nd derivative is lowpassfiltered and then radius is calculated as (Filter Treshold)/2nd_derivative. + * The radius modulation data is precalulated and buffered an is used to steer filter radius when + * the actual filtering occurs. + * + * Noise and texture can be further suppressed by nonlinear distortion before adaptive filtering. + * To make this possible I subtract low frequency from image data before denoising, so that I get a + * bipolar, zerosymmetric image signal. + * + * The filter works in a /one-dimensional/ way. It is applied to x and then to y axis. + * + * After filtering a zerodimensional point operator (pixel by pixel comparison) is used, where + * filter-errors are thrown out. + * This is meant to limit and control filter errors,it can give "final touch" to the image, but it has + * nothing to do with the main filter process. + * + * I do not know if something like this filter already exists. + * It is all based on my own ideas and experiments. + * Possibly a separable adaptive gauss-filter is a new thing. + * Also it is an impossible thing, from a mathemathical point of view ;-) + * It is possible only for bandwidth limited images. + * Happyly most photographic images are bandwidth limited, or when they are noisy then we want + * to limit banwith locally. And this is, what the filter does: It limits bandwidth locally, dependent + * from (approximately) 2nd derivative of intensity. + * + * Because gauss filtering is essentially linear diffusion, and because this filter uses a variable + * nonlinear modulated gaussfilter (four box passes are almost gauss) we could say, that this filter + * implements a special subclass of nonlinear adaptive diffusion, which is separable, and indeed, + * results are very similar to nonlinear diffusion filters. + * However, because the filter is separable, it is much faster and needs less memory. + */ + +namespace DigikamNoiseReductionImagesPlugin +{ + +class NoiseReduction : public Digikam::DImgThreadedFilter +{ + +public: + + NoiseReduction(Digikam::DImg *orgImage, TQObject *parent, + double radius, double lsmooth, double effect, double texture, double sharp, + double csmooth, double lookahead, double gamma, double damping, double phase); + ~NoiseReduction(){}; + +private: + + void filterImage(void); + + void iir_init(double r); + void box_filter(double *src, double *end, double *dest, double radius); + void iir_filter(float* const start, float* const end, float* dstart, double radius, const int type); + void filter(float *buffer, float *data, float *data2, float *rbuf, float *tbuf, int width, int color); + void blur_line(float* const data, float* const data2, float* const buffer, + float* rbuf, float* tbuf, const uchar *src, uchar *dest, int len); + + inline double mypow(double val, double ex) + { + if (fabs(val) < 1e-16) return 0.0; + if (val > 0.0) return exp(log(val)*ex); + return -exp(log(-val)*ex); + }; + +private: + + struct iir_param + { + double B, b1, b2, b3, b0, r, q; + double *p; + } m_iir; + + enum IIRFilteringMode + { + Gaussian=0, + SecondDerivative + }; + + int m_clampMax; + + double m_radius; + double m_lsmooth; + double m_csmooth; + double m_effect; + double m_lookahead; + double m_gamma; + double m_damping; + double m_phase; + double m_texture; + double m_sharp; +}; + +} // NameSpace DigikamNoiseReductionImagesPlugin + +#endif /* NOISE_REDUCTION_H */ diff --git a/src/imageplugins/noisereduction/noisereductiontool.cpp b/src/imageplugins/noisereduction/noisereductiontool.cpp new file mode 100644 index 00000000..d1e4908a --- /dev/null +++ b/src/imageplugins/noisereduction/noisereductiontool.cpp @@ -0,0 +1,536 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-24 + * Description : a plugin to reduce CCD noise. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqcheckbox.h> +#include <tqfile.h> +#include <tqimage.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqstring.h> +#include <tqtabwidget.h> +#include <tqtextstream.h> +#include <tqtooltip.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <tdefiledialog.h> +#include <tdeglobalsettings.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <kstandarddirs.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "imagepanelwidget.h" +#include "editortoolsettings.h" +#include "noisereduction.h" +#include "noisereductiontool.h" +#include "noisereductiontool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamNoiseReductionImagesPlugin +{ + +NoiseReductionTool::NoiseReductionTool(TQObject* parent) + : EditorToolThreaded(parent) +{ + setName("noisereduction"); + setToolName(i18n("Noise Reduction")); + setToolIcon(SmallIcon("noisereduction")); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel| + EditorToolSettings::Load| + EditorToolSettings::SaveAs| + EditorToolSettings::Try, + EditorToolSettings::PanIcon); + + TQGridLayout* grid = new TQGridLayout( m_gboxSettings->plainPage(), 1, 1); + + TQTabWidget *mainTab = new TQTabWidget(m_gboxSettings->plainPage()); + TQWidget* firstPage = new TQWidget( mainTab ); + TQGridLayout* grid1 = new TQGridLayout(firstPage, 6, 1); + + TQLabel *label1 = new TQLabel(i18n("Radius:"), firstPage); + + m_radiusInput = new RDoubleNumInput(firstPage); + m_radiusInput->setPrecision(1); + m_radiusInput->setRange(0.0, 10.0, 0.1); + m_radiusInput->setDefaultValue(1.0); + TQWhatsThis::add( m_radiusInput, i18n("<p><b>Radius</b>: this control selects the " + "gliding window size used for the filter. Larger values do not increase " + "the amount of time needed to filter each pixel in the image but " + "can cause blurring. This window moves across the image, and the " + "color in it is smoothed to remove imperfections. " + "In any case it must be about the same size as the noise granularity " + "or somewhat more. If it is set higher than necessary, then it " + "can cause unwanted blur.")); + + // ------------------------------------------------------------- + + TQLabel *label3 = new TQLabel(i18n("Threshold:"), firstPage); + + m_thresholdInput = new RDoubleNumInput(firstPage); + m_thresholdInput->setPrecision(2); + m_thresholdInput->setRange(0.0, 1.0, 0.01); + m_thresholdInput->setDefaultValue(0.08); + TQWhatsThis::add( m_thresholdInput, i18n("<p><b>Threshold</b>: use the slider for coarse adjustment, " + "and the spin control for fine adjustment to control edge detection sensitivity. " + "This value should be set so that edges and details are clearly visible " + "and noise is smoothed out. " + "Adjustment must be made carefully, because the gap between \"noisy\", " + "\"smooth\", and \"blur\" is very small. Adjust it as carefully as you would adjust " + "the focus of a camera.")); + + // ------------------------------------------------------------- + + TQLabel *label4 = new TQLabel(i18n("Texture:"), firstPage); + + m_textureInput = new RDoubleNumInput(firstPage); + m_textureInput->setPrecision(2); + m_textureInput->setRange(-0.99, 0.99, 0.01); + m_textureInput->setDefaultValue(0.0); + TQWhatsThis::add( m_textureInput, i18n("<p><b>Texture</b>: this control sets the texture accuracy. " + "This value can be used, to get more or less texture accuracy. When decreased, " + "then noise and texture are blurred out, when increased then texture is " + "amplified, but also noise will increase. It has almost no effect on image edges.")); + + // ------------------------------------------------------------- + + TQLabel *label7 = new TQLabel(i18n("Sharpness:"), firstPage); // Filter setting "Lookahead". + + m_sharpnessInput = new RDoubleNumInput(firstPage); + m_sharpnessInput->setPrecision(2); + m_sharpnessInput->setRange(0.0, 1.0, 0.1); + m_sharpnessInput->setDefaultValue(0.25); + TQWhatsThis::add( m_sharpnessInput, i18n("<p><b>Sharpness</b>: " + "This value improves the frequency response for the filter. " + "When it is too strong then not all noise can be removed, or spike noise may appear. " + "Set it near to maximum, if you want to remove very weak noise or JPEG-artifacts, " + "without losing detail.")); + + // ------------------------------------------------------------- + + TQLabel *label5 = new TQLabel(i18n("Edge Lookahead:"), firstPage); // Filter setting "Sharp". + + m_lookaheadInput = new RDoubleNumInput(firstPage); + m_lookaheadInput->setPrecision(2); + m_lookaheadInput->setRange(0.01, 20.0, 0.01); + m_lookaheadInput->setDefaultValue(2.0); + TQWhatsThis::add( m_lookaheadInput, i18n("<p><b>Edge</b>: " + "This value defines the pixel distance to which the filter looks ahead for edges. " + "When this value is increased, then spike noise is erased. " + "You can eventually re-adjust the <b>Edge</b> filter, when you have changed this setting. " + "When this value is too high, the adaptive filter can no longer accurately track " + "image details, and noise or blurring can occur.")); + + // ------------------------------------------------------------- + + TQLabel *label10 = new TQLabel(i18n("Erosion:"), firstPage); + + m_phaseInput = new RDoubleNumInput(firstPage); + m_phaseInput->setPrecision(1); + m_phaseInput->setRange(0.5, 20.0, 0.5); + m_phaseInput->setDefaultValue(1.0); + TQWhatsThis::add( m_phaseInput, i18n("<p><b>Erosion</b>: " + "Use this to increase edge noise erosion and spike noise erosion " + "(noise is removed by erosion).")); + + grid1->addMultiCellWidget(label1, 0, 0, 0, 0); + grid1->addMultiCellWidget(m_radiusInput, 0, 0, 1, 1); + grid1->addMultiCellWidget(label3, 1, 1, 0, 0); + grid1->addMultiCellWidget(m_thresholdInput, 1, 1, 1, 1); + grid1->addMultiCellWidget(label4, 2, 2, 0, 0); + grid1->addMultiCellWidget(m_textureInput, 2, 2, 1, 1); + grid1->addMultiCellWidget(label7, 3, 3, 0, 0); + grid1->addMultiCellWidget(m_sharpnessInput, 3, 3, 1, 1); + grid1->addMultiCellWidget(label5, 4, 4, 0, 0); + grid1->addMultiCellWidget(m_lookaheadInput, 4, 4, 1, 1); + grid1->addMultiCellWidget(label10, 5, 5, 0, 0); + grid1->addMultiCellWidget(m_phaseInput, 5, 5, 1, 1); + grid1->setMargin(m_gboxSettings->spacingHint()); + grid1->setSpacing(m_gboxSettings->spacingHint()); + grid1->setColStretch(1, 10); + grid1->setRowStretch(6, 10); + + mainTab->addTab( firstPage, i18n("Details") ); + + // ------------------------------------------------------------- + + TQWidget* secondPage = new TQWidget( mainTab ); + TQGridLayout* grid2 = new TQGridLayout( secondPage, 4, 1); + + TQLabel *label2 = new TQLabel(i18n("Luminance:"), secondPage); + + m_lumToleranceInput = new RDoubleNumInput(secondPage); + m_lumToleranceInput->setPrecision(1); + m_lumToleranceInput->setRange(0.0, 1.0, 0.1); + m_lumToleranceInput->setDefaultValue(1.0); + TQWhatsThis::add( m_lumToleranceInput, i18n("<p><b>Luminance</b>: this control sets the luminance tolerance of the image." + "We recommend using either the <b>Color</b> or the <b>Luminance</b> tolerance settings " + "to make an image correction, not both at the same time. These settings " + "do not influence the main smoothing process controlled by the <b>Details</b> " + "settings.")); + + // ------------------------------------------------------------- + + TQLabel *label6 = new TQLabel(i18n("Color:"), secondPage); + + m_csmoothInput = new RDoubleNumInput(secondPage); + m_csmoothInput->setPrecision(1); + m_csmoothInput->setRange(0.0, 1.0, 0.1); + m_csmoothInput->setDefaultValue(1.0); + TQWhatsThis::add( m_csmoothInput, i18n("<p><b>Color</b>: this control sets the color tolerance of the image. It is " + "recommended using either the <b>Color</b> or the <b>Luminance</b> tolerance " + "to make image correction, not both at the same time. These settings " + "do not influence the main smoothing process controlled by the <b>Details</b> " + "settings.")); + + // ------------------------------------------------------------- + + TQLabel *label8 = new TQLabel(i18n("Gamma:"), secondPage); + + m_gammaInput = new RDoubleNumInput(secondPage); + m_gammaInput->setPrecision(1); + m_gammaInput->setRange(0.3, 3.0, 0.1); + m_gammaInput->setDefaultValue(1.4); + TQWhatsThis::add( m_gammaInput, i18n("<p><b>Gamma</b>: this control sets the gamma tolerance of the image. This value " + "can be used to increase the tolerance values for darker areas (which commonly " + "are noisier). This results in more blur for shadow areas.")); + + // ------------------------------------------------------------- + + TQLabel *label9 = new TQLabel(i18n("Damping:"), secondPage); + + m_dampingInput = new RDoubleNumInput(secondPage); + m_dampingInput->setPrecision(1); + m_dampingInput->setRange(0.5, 20.0, 0.5); + m_dampingInput->setDefaultValue(5.0); + TQWhatsThis::add( m_dampingInput, i18n("<p><b>Damping</b>: this control sets the phase-jitter damping adjustment. " + "This value defines how fast the adaptive filter-radius reacts to luminance " + "variations. If increased, then edges appear smoother; if too high, then blur " + "may occur. If at minimum, then noise and phase jitter at the edges can occur. It " + "can suppress spike noise when increased, and this is the preferred method to " + "remove it.")); + + grid2->addMultiCellWidget(label2, 0, 0, 0, 0); + grid2->addMultiCellWidget(m_lumToleranceInput, 0, 0, 1, 1); + grid2->addMultiCellWidget(label6, 1, 1, 0, 0); + grid2->addMultiCellWidget(m_csmoothInput, 1, 1, 1, 1); + grid2->addMultiCellWidget(label8, 2, 2, 0, 0); + grid2->addMultiCellWidget(m_gammaInput, 2, 2, 1, 1); + grid2->addMultiCellWidget(label9, 3, 3, 0, 0); + grid2->addMultiCellWidget(m_dampingInput, 3, 3, 1, 1); + grid2->setMargin(m_gboxSettings->spacingHint()); + grid2->setSpacing(m_gboxSettings->spacingHint()); + grid2->setColStretch(1, 10); + grid2->setRowStretch(4, 10); + + mainTab->addTab( secondPage, i18n("Advanced") ); + + grid->addMultiCellWidget(mainTab, 0, 0, 0, 1); + grid->setRowStretch(1, 10); + grid->setMargin(m_gboxSettings->spacingHint()); + grid->setSpacing(m_gboxSettings->spacingHint()); + + setToolSettings(m_gboxSettings); + + m_previewWidget = new ImagePanelWidget(470, 350, "noisereduction Tool", m_gboxSettings->panIconView()); + + setToolView(m_previewWidget); + init(); +} + +NoiseReductionTool::~NoiseReductionTool() +{ +} + +void NoiseReductionTool::renderingFinished() +{ + m_radiusInput->setEnabled(true); + m_lumToleranceInput->setEnabled(true); + m_thresholdInput->setEnabled(true); + m_textureInput->setEnabled(true); + m_sharpnessInput->setEnabled(true); + m_csmoothInput->setEnabled(true); + m_lookaheadInput->setEnabled(true); + m_gammaInput->setEnabled(true); + m_dampingInput->setEnabled(true); + m_phaseInput->setEnabled(true); +} + +void NoiseReductionTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("noisereduction Tool"); + + m_radiusInput->setEnabled(false); + m_lumToleranceInput->setEnabled(false); + m_thresholdInput->setEnabled(false); + m_textureInput->setEnabled(false); + m_sharpnessInput->setEnabled(false); + m_csmoothInput->setEnabled(false); + m_lookaheadInput->setEnabled(false); + m_gammaInput->setEnabled(false); + m_dampingInput->setEnabled(false); + m_phaseInput->setEnabled(false); + + m_radiusInput->setValue(config->readDoubleNumEntry("RadiusAjustment", m_radiusInput->defaultValue())); + m_lumToleranceInput->setValue(config->readDoubleNumEntry("LumToleranceAjustment", m_lumToleranceInput->defaultValue())); + m_thresholdInput->setValue(config->readDoubleNumEntry("ThresholdAjustment", m_thresholdInput->defaultValue())); + m_textureInput->setValue(config->readDoubleNumEntry("TextureAjustment", m_textureInput->defaultValue())); + m_sharpnessInput->setValue(config->readDoubleNumEntry("SharpnessAjustment", m_sharpnessInput->defaultValue())); + m_csmoothInput->setValue(config->readDoubleNumEntry("CsmoothAjustment", m_csmoothInput->defaultValue())); + m_lookaheadInput->setValue(config->readDoubleNumEntry("LookAheadAjustment", m_lookaheadInput->defaultValue())); + m_gammaInput->setValue(config->readDoubleNumEntry("GammaAjustment", m_gammaInput->defaultValue())); + m_dampingInput->setValue(config->readDoubleNumEntry("DampingAjustment", m_dampingInput->defaultValue())); + m_phaseInput->setValue(config->readDoubleNumEntry("PhaseAjustment", m_phaseInput->defaultValue())); + + m_radiusInput->setEnabled(true); + m_lumToleranceInput->setEnabled(true); + m_thresholdInput->setEnabled(true); + m_textureInput->setEnabled(true); + m_sharpnessInput->setEnabled(true); + m_csmoothInput->setEnabled(true); + m_lookaheadInput->setEnabled(true); + m_gammaInput->setEnabled(true); + m_dampingInput->setEnabled(true); + m_phaseInput->setEnabled(true); +} + +void NoiseReductionTool::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("noisereduction Tool"); + config->writeEntry("RadiusAjustment", m_radiusInput->value()); + config->writeEntry("LumToleranceAjustment", m_lumToleranceInput->value()); + config->writeEntry("ThresholdAjustment", m_thresholdInput->value()); + config->writeEntry("TextureAjustment", m_textureInput->value()); + config->writeEntry("SharpnessAjustment", m_sharpnessInput->value()); + config->writeEntry("CsmoothAjustment", m_csmoothInput->value()); + config->writeEntry("LookAheadAjustment", m_lookaheadInput->value()); + config->writeEntry("GammaAjustment", m_gammaInput->value()); + config->writeEntry("DampingAjustment", m_dampingInput->value()); + config->writeEntry("PhaseAjustment", m_phaseInput->value()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void NoiseReductionTool::slotResetSettings() +{ + m_radiusInput->setEnabled(true); + m_lumToleranceInput->setEnabled(true); + m_thresholdInput->setEnabled(true); + m_textureInput->setEnabled(true); + m_sharpnessInput->setEnabled(true); + m_csmoothInput->setEnabled(true); + m_lookaheadInput->setEnabled(true); + m_gammaInput->setEnabled(true); + m_dampingInput->setEnabled(true); + m_phaseInput->setEnabled(true); + + m_radiusInput->slotReset(); + m_lumToleranceInput->slotReset(); + m_thresholdInput->slotReset(); + m_textureInput->slotReset(); + m_sharpnessInput->slotReset(); + m_csmoothInput->slotReset(); + m_lookaheadInput->slotReset(); + m_gammaInput->slotReset(); + m_dampingInput->slotReset(); + m_phaseInput->slotReset(); + + m_radiusInput->setEnabled(false); + m_lumToleranceInput->setEnabled(false); + m_thresholdInput->setEnabled(false); + m_textureInput->setEnabled(false); + m_sharpnessInput->setEnabled(false); + m_csmoothInput->setEnabled(false); + m_lookaheadInput->setEnabled(false); + m_gammaInput->setEnabled(false); + m_dampingInput->setEnabled(false); + m_phaseInput->setEnabled(false); +} + +void NoiseReductionTool::prepareEffect() +{ + m_radiusInput->setEnabled(false); + m_lumToleranceInput->setEnabled(false); + m_thresholdInput->setEnabled(false); + m_textureInput->setEnabled(false); + m_sharpnessInput->setEnabled(false); + m_csmoothInput->setEnabled(false); + m_lookaheadInput->setEnabled(false); + m_gammaInput->setEnabled(false); + m_dampingInput->setEnabled(false); + m_phaseInput->setEnabled(false); + + double r = m_radiusInput->value(); + double l = m_lumToleranceInput->value(); + double th = m_thresholdInput->value(); + double tx = m_textureInput->value(); + double s = m_sharpnessInput->value(); + double c = m_csmoothInput->value(); + double a = m_lookaheadInput->value(); + double g = m_gammaInput->value(); + double d = m_dampingInput->value(); + double p = m_phaseInput->value(); + + DImg image = m_previewWidget->getOriginalRegionImage(); + + setFilter(dynamic_cast<DImgThreadedFilter*>(new NoiseReduction(&image, this, r, l, th, tx, s, c, a, g, d, p))); +} + +void NoiseReductionTool::prepareFinal() +{ + m_radiusInput->setEnabled(false); + m_lumToleranceInput->setEnabled(false); + m_thresholdInput->setEnabled(false); + m_textureInput->setEnabled(false); + m_sharpnessInput->setEnabled(false); + m_csmoothInput->setEnabled(false); + m_lookaheadInput->setEnabled(false); + m_gammaInput->setEnabled(false); + m_dampingInput->setEnabled(false); + m_phaseInput->setEnabled(false); + + double r = m_radiusInput->value(); + double l = m_lumToleranceInput->value(); + double th = m_thresholdInput->value(); + double tx = m_textureInput->value(); + double s = m_sharpnessInput->value(); + double c = m_csmoothInput->value(); + double a = m_lookaheadInput->value(); + double g = m_gammaInput->value(); + double d = m_dampingInput->value(); + double p = m_phaseInput->value(); + + ImageIface iface(0, 0); + setFilter(dynamic_cast<DImgThreadedFilter*>(new NoiseReduction(iface.getOriginalImg(), this, r, l, th, tx, s, c, a, g, d, p))); +} + +void NoiseReductionTool::putPreviewData() +{ + m_previewWidget->setPreviewImage(filter()->getTargetImage()); +} + +void NoiseReductionTool::putFinalData() +{ + ImageIface iface(0, 0); + iface.putOriginalImage(i18n("Noise Reduction"), filter()->getTargetImage().bits()); +} + +void NoiseReductionTool::slotLoadSettings() +{ + KURL loadRestorationFile = KFileDialog::getOpenURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), kapp->activeWindow(), + TQString( i18n("Photograph Noise Reduction Settings File to Load")) ); + if ( loadRestorationFile.isEmpty() ) + return; + + TQFile file(loadRestorationFile.path()); + + if ( file.open(IO_ReadOnly) ) + { + TQTextStream stream( &file ); + if ( stream.readLine() != "# Photograph Noise Reduction Configuration File" ) + { + KMessageBox::error(kapp->activeWindow(), + i18n("\"%1\" is not a Photograph Noise Reduction settings text file.") + .arg(loadRestorationFile.fileName())); + file.close(); + return; + } + + blockSignals(true); + m_radiusInput->setValue( stream.readLine().toDouble() ); + m_lumToleranceInput->setValue( stream.readLine().toDouble() ); + m_thresholdInput->setValue( stream.readLine().toDouble() ); + m_textureInput->setValue( stream.readLine().toDouble() ); + m_sharpnessInput->setValue( stream.readLine().toDouble() ); + m_csmoothInput->setValue( stream.readLine().toDouble() ); + m_lookaheadInput->setValue( stream.readLine().toDouble() ); + m_gammaInput->setValue( stream.readLine().toDouble() ); + m_dampingInput->setValue( stream.readLine().toDouble() ); + m_phaseInput->setValue( stream.readLine().toDouble() ); + blockSignals(false); + } + else + KMessageBox::error(kapp->activeWindow(), i18n("Cannot load settings from the Photograph Noise Reduction text file.")); + + file.close(); +} + +void NoiseReductionTool::slotSaveAsSettings() +{ + KURL saveRestorationFile = KFileDialog::getSaveURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), kapp->activeWindow(), + TQString( i18n("Photograph Noise Reduction Settings File to Save")) ); + if ( saveRestorationFile.isEmpty() ) + return; + + TQFile file(saveRestorationFile.path()); + + if ( file.open(IO_WriteOnly) ) + { + TQTextStream stream( &file ); + stream << "# Photograph Noise Reduction Configuration File\n"; + stream << m_radiusInput->value() << "\n"; + stream << m_lumToleranceInput->value() << "\n"; + stream << m_thresholdInput->value() << "\n"; + stream << m_textureInput->value() << "\n"; + stream << m_sharpnessInput->value() << "\n"; + stream << m_csmoothInput->value() << "\n"; + stream << m_lookaheadInput->value() << "\n"; + stream << m_gammaInput->value() << "\n"; + stream << m_dampingInput->value() << "\n"; + stream << m_phaseInput->value() << "\n"; + + } + else + KMessageBox::error(kapp->activeWindow(), i18n("Cannot save settings to the Photograph Noise Reduction text file.")); + + file.close(); +} + +} // NameSpace DigikamNoiseReductionImagesPlugin diff --git a/src/imageplugins/noisereduction/noisereductiontool.h b/src/imageplugins/noisereduction/noisereductiontool.h new file mode 100644 index 00000000..8d7d5828 --- /dev/null +++ b/src/imageplugins/noisereduction/noisereductiontool.h @@ -0,0 +1,92 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-24 + * Description : a plugin to reduce CCD noise. + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef NOISEREDUCTIONTOOL_H +#define NOISEREDUCTIONTOOL_H + +// Local includes. + +#include "editortool.h" + +namespace KDcrawIface +{ +class RDoubleNumInput; +} + +namespace Digikam +{ +class EditorToolSettings; +class ImagePanelWidget; +} + +namespace DigikamNoiseReductionImagesPlugin +{ + +class NoiseReductionTool : public Digikam::EditorToolThreaded +{ + TQ_OBJECT + + +public: + + NoiseReductionTool(TQObject* parent); + ~NoiseReductionTool(); + +private: + + void readSettings(); + void writeSettings(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private slots: + + void slotSaveAsSettings(); + void slotLoadSettings(); + void slotResetSettings(); + +private: + + KDcrawIface::RDoubleNumInput *m_radiusInput; + KDcrawIface::RDoubleNumInput *m_lumToleranceInput; + KDcrawIface::RDoubleNumInput *m_thresholdInput; + KDcrawIface::RDoubleNumInput *m_textureInput; + KDcrawIface::RDoubleNumInput *m_sharpnessInput; + + KDcrawIface::RDoubleNumInput *m_csmoothInput; + KDcrawIface::RDoubleNumInput *m_lookaheadInput; + KDcrawIface::RDoubleNumInput *m_gammaInput; + KDcrawIface::RDoubleNumInput *m_dampingInput; + KDcrawIface::RDoubleNumInput *m_phaseInput; + + Digikam::ImagePanelWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamNoiseReductionImagesPlugin + +#endif /* NOISEREDUCTIONTOOL_H */ diff --git a/src/imageplugins/oilpaint/Makefile.am b/src/imageplugins/oilpaint/Makefile.am new file mode 100644 index 00000000..f50d7408 --- /dev/null +++ b/src/imageplugins/oilpaint/Makefile.am @@ -0,0 +1,34 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_oilpaint_la_SOURCES = imageplugin_oilpaint.cpp \ + oilpainttool.cpp oilpaint.cpp + +digikamimageplugin_oilpaint_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_oilpaint_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_oilpaint.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_oilpaint.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_oilpaint_ui.rc + diff --git a/src/imageplugins/oilpaint/digikamimageplugin_oilpaint.desktop b/src/imageplugins/oilpaint/digikamimageplugin_oilpaint.desktop new file mode 100644 index 00000000..875c7f16 --- /dev/null +++ b/src/imageplugins/oilpaint/digikamimageplugin_oilpaint.desktop @@ -0,0 +1,51 @@ +[Desktop Entry] +Name=ImagePlugin_OilPaint +Name[bg]=Приставка за снимки - Маслени бои +Name[da]=Billedplugin_Oliemaling +Name[el]=ΠρόσθετοΕικόνας_Ελαιογραφίας +Name[fi]=Öljyvärimaalaus +Name[hr]=Uljana slika +Name[it]=PluginImmagini_PitturaAOlio +Name[nl]=Afbeeldingsplugin_Olieverf +Name[sr]=Слика у уљу +Name[sr@Latn]=Slika u ulju +Name[sv]=Insticksprogram för oljemålning +Name[tr]=ResimEklentisi_YağlıBoya +Name[xx]=xxImagePlugin_OilPaintxx +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=Oil paint image effect plugin for digiKam +Comment[bg]=Приставка на digiKam за наподобяване на картина с маслени бои +Comment[ca]=Connector pel digiKam d'efecte de pintura a l'oli +Comment[da]=Plugin med oliemalingeffekt på billeder i Digikam +Comment[de]=digiKam-Modul zum Erzeugen eines Ölgemäldeeffektes +Comment[el]=Πρόσθετο ελαιογραφίας για το digiKam +Comment[es]=Plugin para digiKam con efectos de pintura al óleo +Comment[et]=DigiKami õlimaali pildiefektiplugin +Comment[fa]=وصلۀ جلوۀ تصویر رنگ روغن برای digiKam +Comment[fi]=Jäljittelee öljyvärimaalausta +Comment[gl]=Un plugin de digiKam para simular unha pintura ao óleo +Comment[hr]=digiKam dodatak za efekt uljane slike +Comment[is]=Íforrit fyrir digiKam sem líkir eftir olíumálun +Comment[it]=Plugin per l'effetto di pittura a olio delle immagini per digiKam +Comment[ja]=digiKam 油絵効果プラグイン +Comment[ms]=Plugin kesan imej cat minyak untuk digiKam +Comment[nds]=digiKam-Moduul för Öölbildeffekten +Comment[nl]=Digikam-plugin voor olieverfafbeeldingen +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਤੇਲ ਪੇਂਟ ਚਿੱਤਰ ਪਰਭਾਵ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam zmniejszająca szum +Comment[pt]=Um 'plugin' do digiKam para simular uma pintura a óleo +Comment[pt_BR]=Plugin de efeito de condensar cor da imagem +Comment[ru]=Модуль эффект "маслянной краски" для digiKam +Comment[sk]=digiKam plugin pre efekt olejomaľby +Comment[sr]=digiKam-ов прикључак за ефекат слике у уљу +Comment[sr@Latn]=digiKam-ov priključak za efekat slike u ulju +Comment[sv]=Digikam insticksprogram för oljemålningsbildeffekt +Comment[tr]=digiKam için resmi yağlıboyaya benzetme eklentisi +Comment[uk]=Втулок створення ефекту олійних фарб для digiKam +Comment[vi]=Phần bổ sung hiệu ứng ảnh sơn dầu cho digiKam +Comment[xx]=xxOil paint image effect plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_oilpaint +author=Gilles Caulier, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/oilpaint/digikamimageplugin_oilpaint_ui.rc b/src/imageplugins/oilpaint/digikamimageplugin_oilpaint_ui.rc new file mode 100644 index 00000000..864c09db --- /dev/null +++ b/src/imageplugins/oilpaint/digikamimageplugin_oilpaint_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="5" name="digikamimageplugin_oilpaint" > + + <MenuBar> + + <Menu name="Filters" ><text>F&ilters</text> + <Action name="imageplugin_oilpaint" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action shortcut="" name="imageplugin_oilpaint" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/oilpaint/imageeffect_oilpaint.cpp b/src/imageplugins/oilpaint/imageeffect_oilpaint.cpp new file mode 100644 index 00000000..da07be05 --- /dev/null +++ b/src/imageplugins/oilpaint/imageeffect_oilpaint.cpp @@ -0,0 +1,201 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-25 + * Description : a plugin to simulate Oil Painting + * + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <tqlabel.h> +#include <tqwhatsthis.h> +#include <tqimage.h> +#include <tqlayout.h> + +// KDE includes. + +#include <kcursor.h> +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <kstandarddirs.h> +#include <knuminput.h> +#include <tdeconfig.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "oilpaint.h" +#include "imageeffect_oilpaint.h" +#include "imageeffect_oilpaint.moc" + +namespace DigikamOilPaintImagesPlugin +{ + +ImageEffect_OilPaint::ImageEffect_OilPaint(TQWidget* parent) + : Digikam::CtrlPanelDlg(parent, i18n("Apply Oil Paint Effect"), + "oilpaint", false, false, true, + Digikam::ImagePannelWidget::SeparateViewAll) +{ + TQString whatsThis; + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Oil Paint"), + digikam_version, + I18N_NOOP("An oil painting image effect plugin for digiKam."), + TDEAboutData::License_GPL, + "(c) 2004-2005, Gilles Caulier\n" + "(c) 2006-2008, Gilles Caulier and Marcel Wiesweg", + 0, + "http://wwww.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + about->addAuthor("Pieter Z. Voloshyn", I18N_NOOP("Oil paint algorithm"), + "pieter dot voloshyn at gmail dot com"); + + about->addAuthor("Marcel Wiesweg", I18N_NOOP("Developer"), + "marcel dot wiesweg at gmx dot de"); + + setAboutData(about); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(m_imagePreviewWidget); + TQGridLayout* gridSettings = new TQGridLayout( gboxSettings, 3, 1, 0, spacingHint()); + + TQLabel *label1 = new TQLabel(i18n("Brush size:"), gboxSettings); + m_brushSizeInput = new KIntNumInput(gboxSettings); + m_brushSizeInput->setRange(1, 5, 1, true); + TQWhatsThis::add( m_brushSizeInput, i18n("<p>Set here the brush size to use for " + "simulating the oil painting.") ); + + gridSettings->addMultiCellWidget(label1, 0, 0, 0, 1); + gridSettings->addMultiCellWidget(m_brushSizeInput, 1, 1, 0, 1); + + // ------------------------------------------------------------- + + TQLabel *label2 = new TQLabel(i18n("Smooth:"), gboxSettings); + m_smoothInput = new KIntNumInput(gboxSettings); + m_smoothInput->setRange(10, 255, 1, true); + TQWhatsThis::add( m_smoothInput, i18n("<p>This value controls the smoothing effect " + "of the brush under the canvas.") ); + + gridSettings->addMultiCellWidget(label2, 2, 2, 0, 1); + gridSettings->addMultiCellWidget(m_smoothInput, 3, 3, 0, 1); + + m_imagePreviewWidget->setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + connect(m_brushSizeInput, TQ_SIGNAL(valueChanged (int)), + this, TQ_SLOT(slotTimer())); + + connect(m_smoothInput, TQ_SIGNAL(valueChanged (int)), + this, TQ_SLOT(slotTimer())); +} + +ImageEffect_OilPaint::~ImageEffect_OilPaint() +{ +} + +void ImageEffect_OilPaint::renderingFinished() +{ + m_brushSizeInput->setEnabled(true); + m_smoothInput->setEnabled(true); +} + +void ImageEffect_OilPaint::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("oilpaint Tool Dialog"); + m_brushSizeInput->blockSignals(true); + m_smoothInput->blockSignals(true); + m_brushSizeInput->setValue(config->readNumEntry("BrushSize", 1)); + m_smoothInput->setValue(config->readNumEntry("SmoothAjustment", 30)); + m_brushSizeInput->blockSignals(false); + m_smoothInput->blockSignals(false); +} + +void ImageEffect_OilPaint::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("oilpaint Tool Dialog"); + config->writeEntry("BrushSize", m_brushSizeInput->value()); + config->writeEntry("SmoothAjustment", m_smoothInput->value()); + config->sync(); +} + +void ImageEffect_OilPaint::resetValues() +{ + m_brushSizeInput->blockSignals(true); + m_smoothInput->blockSignals(true); + m_brushSizeInput->setValue(1); + m_smoothInput->setValue(30); + m_brushSizeInput->blockSignals(false); + m_smoothInput->blockSignals(false); +} + +void ImageEffect_OilPaint::prepareEffect() +{ + m_brushSizeInput->setEnabled(false); + m_smoothInput->setEnabled(false); + + Digikam::DImg image = m_imagePreviewWidget->getOriginalRegionImage(); + + int b = m_brushSizeInput->value(); + int s = m_smoothInput->value(); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>(new OilPaint(&image, this, b, s)); +} + +void ImageEffect_OilPaint::prepareFinal() +{ + m_brushSizeInput->setEnabled(false); + m_smoothInput->setEnabled(false); + + int b = m_brushSizeInput->value(); + int s = m_smoothInput->value(); + + Digikam::ImageIface iface(0, 0); + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>(new OilPaint(iface.getOriginalImg(), this, b, s)); +} + +void ImageEffect_OilPaint::putPreviewData(void) +{ + m_imagePreviewWidget->setPreviewImage(m_threadedFilter->getTargetImage()); +} + +void ImageEffect_OilPaint::putFinalData(void) +{ + Digikam::ImageIface iface(0, 0); + + iface.putOriginalImage(i18n("Oil Paint"), + m_threadedFilter->getTargetImage().bits()); +} + +} // NameSpace DigikamOilPaintImagesPlugin + diff --git a/src/imageplugins/oilpaint/imageeffect_oilpaint.h b/src/imageplugins/oilpaint/imageeffect_oilpaint.h new file mode 100644 index 00000000..527cc2ef --- /dev/null +++ b/src/imageplugins/oilpaint/imageeffect_oilpaint.h @@ -0,0 +1,69 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-25 + * Description : a plugin to simulate Oil Painting + * + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_OILPAINT_H +#define IMAGEEFFECT_OILPAINT_H + +// Digikam includes. + +#include "ctrlpaneldlg.h" + +class KIntNumInput; + +namespace DigikamOilPaintImagesPlugin +{ + +class ImageEffect_OilPaint : public Digikam::CtrlPanelDlg +{ + TQ_OBJECT + + +public: + + ImageEffect_OilPaint(TQWidget* parent); + ~ImageEffect_OilPaint(); + +private slots: + + void readUserSettings(); + +private: + + void writeUserSettings(); + void resetValues(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + KIntNumInput *m_brushSizeInput; + KIntNumInput *m_smoothInput; +}; + +} // NameSpace DigikamOilPaintImagesPlugin + +#endif /* IMAGEEFFECT_OILPAINT_H */ diff --git a/src/imageplugins/oilpaint/imageplugin_oilpaint.cpp b/src/imageplugins/oilpaint/imageplugin_oilpaint.cpp new file mode 100644 index 00000000..740e89fc --- /dev/null +++ b/src/imageplugins/oilpaint/imageplugin_oilpaint.cpp @@ -0,0 +1,70 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-25 + * Description : a plugin to simulate Oil Painting + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> +#include <tdeapplication.h> + +// Local includes. + +#include "ddebug.h" +#include "oilpainttool.h" +#include "imageplugin_oilpaint.h" +#include "imageplugin_oilpaint.moc" + +using namespace DigikamOilPaintImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_oilpaint, + KGenericFactory<ImagePlugin_OilPaint>("digikamimageplugin_oilpaint")); + +ImagePlugin_OilPaint::ImagePlugin_OilPaint(TQObject *parent, const char*, const TQStringList&) + : Digikam::ImagePlugin(parent, "ImagePlugin_OilPaint") +{ + m_oilpaintAction = new TDEAction(i18n("Oil Paint..."), "oilpaint", 0, + this, TQ_SLOT(slotOilPaint()), + actionCollection(), "imageplugin_oilpaint"); + + setXMLFile( "digikamimageplugin_oilpaint_ui.rc" ); + + DDebug() << "ImagePlugin_OilPaint plugin loaded" << endl; +} + +ImagePlugin_OilPaint::~ImagePlugin_OilPaint() +{ +} + +void ImagePlugin_OilPaint::setEnabledActions(bool enable) +{ + m_oilpaintAction->setEnabled(enable); +} + +void ImagePlugin_OilPaint::slotOilPaint() +{ + OilPaintTool *tool = new OilPaintTool(this); + loadTool(tool); +} diff --git a/src/imageplugins/oilpaint/imageplugin_oilpaint.h b/src/imageplugins/oilpaint/imageplugin_oilpaint.h new file mode 100644 index 00000000..032ee065 --- /dev/null +++ b/src/imageplugins/oilpaint/imageplugin_oilpaint.h @@ -0,0 +1,56 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-25 + * Description : a plugin to simulate Oil Painting + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_OILPAINT_H +#define IMAGEPLUGIN_OILPAINT_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_OilPaint : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_OilPaint(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_OilPaint(); + + void setEnabledActions(bool enable); + +private slots: + + void slotOilPaint(); + +private: + + TDEAction *m_oilpaintAction; +}; + +#endif /* IMAGEPLUGIN_OILPAINT_H */ diff --git a/src/imageplugins/oilpaint/oilpaint.cpp b/src/imageplugins/oilpaint/oilpaint.cpp new file mode 100644 index 00000000..be9697fa --- /dev/null +++ b/src/imageplugins/oilpaint/oilpaint.cpp @@ -0,0 +1,203 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : Oil Painting threaded image filter. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * Original OilPaint algorithm copyrighted 2004 by + * Pieter Z. Voloshyn <pieter dot voloshyn 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> +#include <cstdlib> + +// Local includes. + +#include "ddebug.h" +#include "dimg.h" +#include "dimggaussianblur.h" +#include "dimgimagefilters.h" +#include "oilpaint.h" + +namespace DigikamOilPaintImagesPlugin +{ + +OilPaint::OilPaint(Digikam::DImg *orgImage, TQObject *parent, int brushSize, int smoothness) + : Digikam::DImgThreadedFilter(orgImage, parent, "OilPaint") +{ + m_brushSize = brushSize; + m_smoothness = smoothness; + initFilter(); +} + +void OilPaint::filterImage(void) +{ + oilpaintImage(m_orgImage, m_destImage, m_brushSize, m_smoothness); +} + +// This method have been ported from Pieter Z. Voloshyn algorithm code. + +/* Function to apply the OilPaint effect. + * + * data => The image data in RGBA mode. + * w => Width of image. + * h => Height of image. + * BrushSize => Brush size. + * Smoothness => Smooth value. + * + * Theory => Using MostFrequentColor function we take the main color in + * a matrix and simply write at the original position. + */ + +void OilPaint::oilpaintImage(Digikam::DImg &orgImage, Digikam::DImg &destImage, int BrushSize, int Smoothness) +{ + int progress; + Digikam::DColor mostFrequentColor; + int w,h; + + mostFrequentColor.setSixteenBit(orgImage.sixteenBit()); + w = (int)orgImage.width(); + h = (int)orgImage.height(); + uchar *dest = destImage.bits(); + int bytesDepth = orgImage.bytesDepth(); + uchar *dptr; + + // Allocate some arrays to be used. + // Do this here once for all to save a few million new / delete operations + m_intensityCount = new uchar[Smoothness + 1]; + m_averageColorR = new uint[Smoothness + 1]; + m_averageColorG = new uint[Smoothness + 1]; + m_averageColorB = new uint[Smoothness + 1]; + + for (int h2 = 0; !m_cancel && (h2 < h); h2++) + { + for (int w2 = 0; !m_cancel && (w2 < w); w2++) + { + mostFrequentColor = MostFrequentColor(orgImage, w2, h2, BrushSize, Smoothness); + dptr = dest + w2*bytesDepth + (w*h2*bytesDepth); + mostFrequentColor.setPixel(dptr); + } + + progress = (int) (((double)h2 * 100.0) / h); + if ( progress%5 == 0 ) + postProgress( progress ); + } + + // free all the arrays + delete [] m_intensityCount; + delete [] m_averageColorR; + delete [] m_averageColorG; + delete [] m_averageColorB; +} + +// This method have been ported from Pieter Z. Voloshyn algorithm code. + +/* Function to determine the most frequent color in a matrix + * + * Bits => Bits array + * Width => Image width + * Height => Image height + * X => Position horizontal + * Y => Position vertical + * Radius => Is the radius of the matrix to be analized + * Intensity => Intensity to calcule + * + * Theory => This function creates a matrix with the analized pixel in + * the center of this matrix and find the most frequenty color + */ + +Digikam::DColor OilPaint::MostFrequentColor(Digikam::DImg &src, int X, int Y, int Radius, int Intensity) +{ + int i, w, h, I, Width, Height; + uint red, green, blue; + + uchar *dest = src.bits(); + int bytesDepth = src.bytesDepth(); + uchar *sptr; + bool sixteenBit = src.sixteenBit(); + + Digikam::DColor mostFrequentColor; + + double Scale = Intensity / (sixteenBit ? 65535.0 : 255.0); + Width = (int)src.width(); + Height = (int)src.height(); + + // Erase the array + memset(m_intensityCount, 0, (Intensity + 1) * sizeof (uchar)); + + for (w = X - Radius; w <= X + Radius; w++) + { + for (h = Y - Radius; h <= Y + Radius; h++) + { + // This condition helps to identify when a point doesn't exist + + if ((w >= 0) && (w < Width) && (h >= 0) && (h < Height)) + { + sptr = dest + w*bytesDepth + (Width*h*bytesDepth); + Digikam::DColor color(sptr, sixteenBit); + red = (uint)color.red(); + green = (uint)color.green(); + blue = (uint)color.blue(); + + I = lround(GetIntensity (red, green, blue) * Scale); + m_intensityCount[I]++; + + if (m_intensityCount[I] == 1) + { + m_averageColorR[I] = red; + m_averageColorG[I] = green; + m_averageColorB[I] = blue; + } + else + { + m_averageColorR[I] += red; + m_averageColorG[I] += green; + m_averageColorB[I] += blue; + } + } + } + } + + I = 0; + int MaxInstance = 0; + + for (i = 0 ; i <= Intensity ; i++) + { + if (m_intensityCount[i] > MaxInstance) + { + I = i; + MaxInstance = m_intensityCount[i]; + } + } + + // get Alpha channel value from original (unchanged) + mostFrequentColor = src.getPixelColor(X, Y); + + // Overwrite RGB values to destination. + mostFrequentColor.setRed(m_averageColorR[I] / MaxInstance); + mostFrequentColor.setGreen(m_averageColorG[I] / MaxInstance); + mostFrequentColor.setBlue(m_averageColorB[I] / MaxInstance); + + return mostFrequentColor; +} + +} // NameSpace DigikamOilPaintImagesPlugin diff --git a/src/imageplugins/oilpaint/oilpaint.h b/src/imageplugins/oilpaint/oilpaint.h new file mode 100644 index 00000000..998522a5 --- /dev/null +++ b/src/imageplugins/oilpaint/oilpaint.h @@ -0,0 +1,72 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : Oil Painting threaded image filter. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef OILPAINT_H +#define OILPAINT_H + +// Digikam includes. + +#include "dimgthreadedfilter.h" + +namespace DigikamOilPaintImagesPlugin +{ + +class OilPaint : public Digikam::DImgThreadedFilter +{ + +public: + + OilPaint(Digikam::DImg *orgImage, TQObject *parent=0, int brushSize=1, int smoothness=30); + + ~OilPaint(){}; + +private: + + virtual void filterImage(void); + + void oilpaintImage(Digikam::DImg &orgImage, Digikam::DImg &destImage, int BrushSize, int Smoothness); + + Digikam::DColor MostFrequentColor (Digikam::DImg &src, + int X, int Y, int Radius, int Intensity); + + // Function to calculate the color intensity and return the luminance (Y) + // component of YIQ color model. + inline double GetIntensity(uint Red, uint Green, uint Blue) + { return Red * 0.3 + Green * 0.59 + Blue * 0.11; }; + +private: + + uchar *m_intensityCount; + + int m_brushSize; + int m_smoothness; + + uint *m_averageColorR; + uint *m_averageColorG; + uint *m_averageColorB; +}; + +} // NameSpace DigikamOilPaintImagesPlugin + +#endif /* OILPAINT_H */ diff --git a/src/imageplugins/oilpaint/oilpainttool.cpp b/src/imageplugins/oilpaint/oilpainttool.cpp new file mode 100644 index 00000000..25bea302 --- /dev/null +++ b/src/imageplugins/oilpaint/oilpainttool.cpp @@ -0,0 +1,208 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-25 + * Description : a plugin to simulate Oil Painting + * + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <tqimage.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <kstandarddirs.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "imagepanelwidget.h" +#include "editortoolsettings.h" +#include "oilpaint.h" +#include "oilpainttool.h" +#include "oilpainttool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamOilPaintImagesPlugin +{ + +OilPaintTool::OilPaintTool(TQObject* parent) + : EditorToolThreaded(parent) +{ + setName("oilpaint"); + setToolName(i18n("Oil Paint")); + setToolIcon(SmallIcon("oilpaint")); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel| + EditorToolSettings::Try, + EditorToolSettings::PanIcon); + TQGridLayout* grid = new TQGridLayout( m_gboxSettings->plainPage(), 4, 1); + + TQLabel *label1 = new TQLabel(i18n("Brush size:"), m_gboxSettings->plainPage()); + m_brushSizeInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_brushSizeInput->setRange(1, 5, 1); + m_brushSizeInput->setDefaultValue(1); + TQWhatsThis::add( m_brushSizeInput, i18n("<p>Set here the brush size to use for " + "simulating the oil painting.") ); + + // ------------------------------------------------------------- + + TQLabel *label2 = new TQLabel(i18n("Smooth:"), m_gboxSettings->plainPage()); + m_smoothInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_smoothInput->setRange(10, 255, 1); + m_smoothInput->setDefaultValue(30); + TQWhatsThis::add( m_smoothInput, i18n("<p>This value controls the smoothing effect " + "of the brush under the canvas.") ); + + + grid->addMultiCellWidget(label1, 0, 0, 0, 1); + grid->addMultiCellWidget(m_brushSizeInput, 1, 1, 0, 1); + grid->addMultiCellWidget(label2, 2, 2, 0, 1); + grid->addMultiCellWidget(m_smoothInput, 3, 3, 0, 1); + grid->setRowStretch(4, 10); + grid->setMargin(m_gboxSettings->spacingHint()); + grid->setSpacing(m_gboxSettings->spacingHint()); + + setToolSettings(m_gboxSettings); + + // ------------------------------------------------------------- + + m_previewWidget = new ImagePanelWidget(470, 350, "oilpaint Tool", m_gboxSettings->panIconView()); + + setToolView(m_previewWidget); + init(); + + // ------------------------------------------------------------- + + // this filter is relative slow, so we should use the try button instead right now + + // connect(m_brushSizeInput, TQ_SIGNAL(valueChanged (int)), + // this, TQ_SLOT(slotTimer())); + // + // connect(m_smoothInput, TQ_SIGNAL(valueChanged (int)), + // this, TQ_SLOT(slotTimer())); +} + +OilPaintTool::~OilPaintTool() +{ +} + +void OilPaintTool::renderingFinished() +{ + m_brushSizeInput->setEnabled(true); + m_smoothInput->setEnabled(true); +} + +void OilPaintTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("oilpaint Tool"); + m_brushSizeInput->blockSignals(true); + m_smoothInput->blockSignals(true); + + m_brushSizeInput->setValue(config->readNumEntry("BrushSize", m_brushSizeInput->defaultValue())); + m_smoothInput->setValue(config->readNumEntry("SmoothAjustment", m_smoothInput->defaultValue())); + + m_brushSizeInput->blockSignals(false); + m_smoothInput->blockSignals(false); +} + +void OilPaintTool::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("oilpaint Tool"); + config->writeEntry("BrushSize", m_brushSizeInput->value()); + config->writeEntry("SmoothAjustment", m_smoothInput->value()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void OilPaintTool::slotResetSettings() +{ + m_brushSizeInput->blockSignals(true); + m_smoothInput->blockSignals(true); + + m_brushSizeInput->slotReset(); + m_smoothInput->slotReset(); + + m_brushSizeInput->blockSignals(false); + m_smoothInput->blockSignals(false); +} + +void OilPaintTool::prepareEffect() +{ + m_brushSizeInput->setEnabled(false); + m_smoothInput->setEnabled(false); + + DImg image = m_previewWidget->getOriginalRegionImage(); + + int b = m_brushSizeInput->value(); + int s = m_smoothInput->value(); + + setFilter(dynamic_cast<DImgThreadedFilter*>(new OilPaint(&image, this, b, s))); +} + +void OilPaintTool::prepareFinal() +{ + m_brushSizeInput->setEnabled(false); + m_smoothInput->setEnabled(false); + + int b = m_brushSizeInput->value(); + int s = m_smoothInput->value(); + + ImageIface iface(0, 0); + setFilter(dynamic_cast<DImgThreadedFilter*>(new OilPaint(iface.getOriginalImg(), this, b, s))); +} + +void OilPaintTool::putPreviewData() +{ + m_previewWidget->setPreviewImage(filter()->getTargetImage()); +} + +void OilPaintTool::putFinalData() +{ + ImageIface iface(0, 0); + iface.putOriginalImage(i18n("Oil Paint"), filter()->getTargetImage().bits()); +} + +} // NameSpace DigikamOilPaintImagesPlugin + diff --git a/src/imageplugins/oilpaint/oilpainttool.h b/src/imageplugins/oilpaint/oilpainttool.h new file mode 100644 index 00000000..9c488a57 --- /dev/null +++ b/src/imageplugins/oilpaint/oilpainttool.h @@ -0,0 +1,82 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-25 + * Description : a plugin to simulate Oil Painting + * + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef OILPAINTTOOL_H +#define OILPAINTTOOL_H + +// Digikam includes. + +#include "editortool.h" + +namespace KDcrawIface +{ +class RIntNumInput; +} + +namespace Digikam +{ +class EditorToolSettings; +class ImagePanelWidget; +} + +namespace DigikamOilPaintImagesPlugin +{ + +class OilPaintTool : public Digikam::EditorToolThreaded +{ + TQ_OBJECT + + +public: + + OilPaintTool(TQObject* parent); + ~OilPaintTool(); + +private slots: + + void slotResetSettings(); + +private: + + void readSettings(); + void writeSettings(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + KDcrawIface::RIntNumInput *m_brushSizeInput; + KDcrawIface::RIntNumInput *m_smoothInput; + + Digikam::ImagePanelWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamOilPaintImagesPlugin + +#endif /* OILPAINTTOOL_H */ diff --git a/src/imageplugins/perspective/Makefile.am b/src/imageplugins/perspective/Makefile.am new file mode 100644 index 00000000..028add37 --- /dev/null +++ b/src/imageplugins/perspective/Makefile.am @@ -0,0 +1,35 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_perspective_la_SOURCES = imageplugin_perspective.cpp \ + perspectivetool.cpp \ + perspectivewidget.cpp triangle.cpp matrix.cpp + +digikamimageplugin_perspective_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_perspective_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_perspective.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_perspective.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_perspective_ui.rc + diff --git a/src/imageplugins/perspective/digikamimageplugin_perspective.desktop b/src/imageplugins/perspective/digikamimageplugin_perspective.desktop new file mode 100644 index 00000000..a6fcc4d3 --- /dev/null +++ b/src/imageplugins/perspective/digikamimageplugin_perspective.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Name=ImagePlugin_Perspective +Name[bg]=Приставка за снимки - Перспектива +Name[da]=Billedplugin_Perspektivværktøj +Name[el]=ΠρόσθετοΕικόνας_Προοπτική +Name[fi]=Perspektiivimuunnos +Name[hr]=Perspektiva +Name[it]=PluginImmagini_Prospettiva +Name[nl]=Afbeeldingsplugin_Perspectief +Name[sr]=Перспектива +Name[sr@Latn]=Perspektiva +Name[sv]=Insticksprogram för perspektiv +Name[tr]=ResimEklentisi_Perspektif +Name[xx]=xxImagePlugin_Perspectivexx + +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=Perspective tool plugin for digiKam +Comment[bg]=Приставка на digiKam за промяна на перспективата +Comment[ca]=Connector pel digiKam d'eina de perspectiva +Comment[da]=Perspektivværktøjs-plugin for Digikam +Comment[de]=digiKam-Modul zum Justieren der Perspektive eines Bildes +Comment[el]=Πρόσθετο εργαλείο προοπτικής για το digiKam +Comment[es]=Plugin para digiKam de herramientas de perspectiva +Comment[et]=DigiKami perspektiiviplugin +Comment[fa]=وصلۀ ابزار منظره برای digiKam +Comment[fi]=Vääristää kuvan perspektiiviä +Comment[fr]=Module externe pour modifier la perspective dans digiKam +Comment[gl]=Un plugin de digiKam para a ferramenta de perspectiva +Comment[hr]=digiKam dodatak za perspektivu +Comment[it]=Plugin per lo strumento di prospettiva per digiKam +Comment[ja]=digiKam 視点調整プラグイン +Comment[ms]=Plugin alatan perspektif untuk digiKam +Comment[nds]=digiKam-Moduul för den Kietwinkel +Comment[nl]=Digikam-plugin voor perspectiefaanpassing +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਪਰੋਸਪੈਕਟਿਵ ਸੰਦ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam umożliwiająca korekcję perspektywy +Comment[pt]=Um 'plugin' do digiKam para a ferramenta de perspectiva +Comment[pt_BR]=Plugin de ferramenta de Perspectiva +Comment[ru]=Модуль изменения перспективы для digiKam +Comment[sk]=digiKam plugin pre nástroj s perspektívou +Comment[sr]=digiKam-ов прикључак за перспективу +Comment[sr@Latn]=digiKam-ov priključak za perspektivu +Comment[sv]=Digikam insticksprogram med perspektivverktyg +Comment[tr]=digiKam için perspektif aracı eklentisi +Comment[uk]=Втулок засобу побудови перспективи для digiKam +Comment[vi]=Phần bổ sung công cụ phối cảnh cho digiKam +Comment[xx]=xxPerspective tool plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_perspective +author=Gilles Caulier, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/perspective/digikamimageplugin_perspective_ui.rc b/src/imageplugins/perspective/digikamimageplugin_perspective_ui.rc new file mode 100644 index 00000000..0f3bca57 --- /dev/null +++ b/src/imageplugins/perspective/digikamimageplugin_perspective_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="4" name="digikamimageplugin_perspective" > + + <MenuBar> + + <Menu name="Transform" ><text>Tra&nsform</text> + <Action name="imageplugin_perspective" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action shortcut="" name="imageplugin_perspective" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/perspective/imageeffect_perspective.cpp b/src/imageplugins/perspective/imageeffect_perspective.cpp new file mode 100644 index 00000000..15bef877 --- /dev/null +++ b/src/imageplugins/perspective/imageeffect_perspective.cpp @@ -0,0 +1,252 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-17 + * Description : a plugin to change image perspective . + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <tqvgroupbox.h> +#include <tqlabel.h> +#include <tqspinbox.h> +#include <tqpushbutton.h> +#include <tqwhatsthis.h> +#include <tqlayout.h> +#include <tqframe.h> +#include <tqcheckbox.h> + +// KDE includes. + +#include <kcolorbutton.h> +#include <kcursor.h> +#include <tdeconfig.h> +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <khelpmenu.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <tdepopupmenu.h> +#include <kstandarddirs.h> +#include <kseparator.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "perspectivewidget.h" +#include "imageeffect_perspective.h" +#include "imageeffect_perspective.moc" + +namespace DigikamPerspectiveImagesPlugin +{ + +ImageEffect_Perspective::ImageEffect_Perspective(TQWidget* parent) + : Digikam::ImageDlgBase(parent, i18n("Adjust Photograph Perspective"), + "perspective", false, false) +{ + TQString whatsThis; + + // About data and help button. + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Perspective"), + digikam_version, + I18N_NOOP("A digiKam image plugin to process image perspective adjustment."), + TDEAboutData::License_GPL, + "(c) 2005-2006, Gilles Caulier\n" + "(c) 2006-2008, Gilles Caulier and Marcel Wiesweg", + 0, + "http://www.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + about->addAuthor("Marcel Wiesweg", I18N_NOOP("Developer"), + "marcel dot wiesweg at gmx dot de"); + + setAboutData(about); + + // ------------------------------------------------------------- + + TQFrame *frame = new TQFrame(plainPage()); + frame->setFrameStyle(TQFrame::Panel|TQFrame::Sunken); + TQVBoxLayout* l = new TQVBoxLayout(frame, 5, 0); + m_previewWidget = new PerspectiveWidget(525, 350, frame); + l->addWidget(m_previewWidget); + TQWhatsThis::add( m_previewWidget, i18n("<p>This is the perspective transformation operation preview. " + "You can use the mouse for dragging the corner to adjust the " + "perspective transformation area.")); + setPreviewAreaWidget(frame); + + // ------------------------------------------------------------- + + TQString temp; + Digikam::ImageIface iface(0, 0); + + TQWidget *gbox2 = new TQWidget(plainPage()); + TQGridLayout *gridLayout = new TQGridLayout( gbox2, 13, 2, spacingHint()); + + TQLabel *label1 = new TQLabel(i18n("New width:"), gbox2); + m_newWidthLabel = new TQLabel(temp.setNum( iface.originalWidth()) + i18n(" px"), gbox2); + m_newWidthLabel->setAlignment( AlignBottom | AlignRight ); + + TQLabel *label2 = new TQLabel(i18n("New height:"), gbox2); + m_newHeightLabel = new TQLabel(temp.setNum( iface.originalHeight()) + i18n(" px"), gbox2); + m_newHeightLabel->setAlignment( AlignBottom | AlignRight ); + + gridLayout->addMultiCellWidget(label1, 0, 0, 0, 0); + gridLayout->addMultiCellWidget(m_newWidthLabel, 0, 0, 1, 2); + gridLayout->addMultiCellWidget(label2, 1, 1, 0, 0); + gridLayout->addMultiCellWidget(m_newHeightLabel, 1, 1, 1, 2); + + // ------------------------------------------------------------- + + KSeparator *line = new KSeparator(Horizontal, gbox2); + + TQLabel *angleLabel = new TQLabel(i18n("Angles (in degrees):"), gbox2); + TQLabel *label3 = new TQLabel(i18n(" Top left:"), gbox2); + m_topLeftAngleLabel = new TQLabel(gbox2); + TQLabel *label4 = new TQLabel(i18n(" Top right:"), gbox2); + m_topRightAngleLabel = new TQLabel(gbox2); + TQLabel *label5 = new TQLabel(i18n(" Bottom left:"), gbox2); + m_bottomLeftAngleLabel = new TQLabel(gbox2); + TQLabel *label6 = new TQLabel(i18n(" Bottom right:"), gbox2); + m_bottomRightAngleLabel = new TQLabel(gbox2); + + gridLayout->addMultiCellWidget(line, 2, 2, 0, 2); + gridLayout->addMultiCellWidget(angleLabel, 3, 3, 0, 2); + gridLayout->addMultiCellWidget(label3, 4, 4, 0, 0); + gridLayout->addMultiCellWidget(m_topLeftAngleLabel, 4, 4, 1, 2); + gridLayout->addMultiCellWidget(label4, 5, 5, 0, 0); + gridLayout->addMultiCellWidget(m_topRightAngleLabel, 5, 5, 1, 2); + gridLayout->addMultiCellWidget(label5, 6, 6, 0, 0); + gridLayout->addMultiCellWidget(m_bottomLeftAngleLabel, 6, 6, 1, 2); + gridLayout->addMultiCellWidget(label6, 7, 7, 0, 0); + gridLayout->addMultiCellWidget(m_bottomRightAngleLabel, 7, 7, 1, 2); + + // ------------------------------------------------------------- + + KSeparator *line2 = new KSeparator(Horizontal, gbox2); + + m_drawWhileMovingCheckBox = new TQCheckBox(i18n("Draw preview while moving"), gbox2); + gridLayout->addMultiCellWidget(line2, 8, 8, 0, 2); + gridLayout->addMultiCellWidget(m_drawWhileMovingCheckBox, 9, 9, 0, 2); + + m_drawGridCheckBox = new TQCheckBox(i18n("Draw grid"), gbox2); + gridLayout->addMultiCellWidget(m_drawGridCheckBox, 10, 10, 0, 2); + + // ------------------------------------------------------------- + + TQLabel *label7 = new TQLabel(i18n("Guide color:"), gbox2); + m_guideColorBt = new KColorButton( TQColor( TQt::red ), gbox2 ); + TQWhatsThis::add( m_guideColorBt, i18n("<p>Set here the color used to draw guides dashed-lines.")); + gridLayout->addMultiCellWidget(label7, 11, 11, 0, 0); + gridLayout->addMultiCellWidget(m_guideColorBt, 11, 11, 2, 2); + + TQLabel *label8 = new TQLabel(i18n("Guide width:"), gbox2); + m_guideSize = new TQSpinBox( 1, 5, 1, gbox2); + TQWhatsThis::add( m_guideSize, i18n("<p>Set here the width in pixels used to draw guides dashed-lines.")); + gridLayout->addMultiCellWidget(label8, 12, 12, 0, 0); + gridLayout->addMultiCellWidget(m_guideSize, 12, 12, 2, 2); + + gridLayout->setColStretch(1, 10); + gridLayout->setRowStretch(13, 10); + + setUserAreaWidget(gbox2); + + // ------------------------------------------------------------- + + connect(m_previewWidget, TQ_SIGNAL(signalPerspectiveChanged(TQRect, float, float, float, float)), + this, TQ_SLOT(slotUpdateInfo(TQRect, float, float, float, float))); + + connect(m_drawWhileMovingCheckBox, TQ_SIGNAL(toggled(bool)), + m_previewWidget, TQ_SLOT(slotToggleDrawWhileMoving(bool))); + + connect(m_drawGridCheckBox, TQ_SIGNAL(toggled(bool)), + m_previewWidget, TQ_SLOT(slotToggleDrawGrid(bool))); + + connect(m_guideColorBt, TQ_SIGNAL(changed(const TQColor &)), + m_previewWidget, TQ_SLOT(slotChangeGuideColor(const TQColor &))); + + connect(m_guideSize, TQ_SIGNAL(valueChanged(int)), + m_previewWidget, TQ_SLOT(slotChangeGuideSize(int))); +} + +ImageEffect_Perspective::~ImageEffect_Perspective() +{ +} + +void ImageEffect_Perspective::readUserSettings(void) +{ + TQColor defaultGuideColor(TQt::red); + TDEConfig *config = kapp->config(); + config->setGroup("perspective Tool Dialog"); + m_drawWhileMovingCheckBox->setChecked(config->readBoolEntry("Draw While Moving", true)); + m_drawGridCheckBox->setChecked(config->readBoolEntry("Draw Grid", false)); + m_guideColorBt->setColor(config->readColorEntry("Guide Color", &defaultGuideColor)); + m_guideSize->setValue(config->readNumEntry("Guide Width", 1)); + m_previewWidget->slotToggleDrawWhileMoving(m_drawWhileMovingCheckBox->isChecked()); + m_previewWidget->slotToggleDrawGrid(m_drawGridCheckBox->isChecked()); + m_previewWidget->slotChangeGuideColor(m_guideColorBt->color()); + m_previewWidget->slotChangeGuideSize(m_guideSize->value()); +} + +void ImageEffect_Perspective::writeUserSettings(void) +{ + TDEConfig *config = kapp->config(); + config->setGroup("perspective Tool Dialog"); + config->writeEntry("Draw While Moving", m_drawWhileMovingCheckBox->isChecked()); + config->writeEntry("Draw Grid", m_drawGridCheckBox->isChecked()); + config->writeEntry("Guide Color", m_guideColorBt->color()); + config->writeEntry("Guide Width", m_guideSize->value()); + config->sync(); +} + +void ImageEffect_Perspective::resetValues() +{ + m_previewWidget->reset(); +} + +void ImageEffect_Perspective::finalRendering() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + m_previewWidget->applyPerspectiveAdjustment(); + accept(); + kapp->restoreOverrideCursor(); +} + +void ImageEffect_Perspective::slotUpdateInfo(TQRect newSize, float topLeftAngle, float topRightAngle, + float bottomLeftAngle, float bottomRightAngle) +{ + TQString temp; + m_newWidthLabel->setText(temp.setNum( newSize.width()) + i18n(" px") ); + m_newHeightLabel->setText(temp.setNum( newSize.height()) + i18n(" px") ); + + m_topLeftAngleLabel->setText(temp.setNum( topLeftAngle, 'f', 1 )); + m_topRightAngleLabel->setText(temp.setNum( topRightAngle, 'f', 1 )); + m_bottomLeftAngleLabel->setText(temp.setNum( bottomLeftAngle, 'f', 1 )); + m_bottomRightAngleLabel->setText(temp.setNum( bottomRightAngle, 'f', 1 )); +} + +} // NameSpace DigikamPerspectiveImagesPlugin + diff --git a/src/imageplugins/perspective/imageeffect_perspective.h b/src/imageplugins/perspective/imageeffect_perspective.h new file mode 100644 index 00000000..41388aa7 --- /dev/null +++ b/src/imageplugins/perspective/imageeffect_perspective.h @@ -0,0 +1,89 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-17 + * Description : a plugin to change image perspective . + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_PERSPECTIVE_H +#define IMAGEEFFECT_PERSPECTIVE_H + +// TQt includes. + +#include <tqrect.h> + +// Digikam includes. + +#include "imagedlgbase.h" + +class TQLabel; +class TQCheckBox; +class TQSpinBox; + +class KColorButton; + +namespace DigikamPerspectiveImagesPlugin +{ + +class PerspectiveWidget; + +class ImageEffect_Perspective : public Digikam::ImageDlgBase +{ + TQ_OBJECT + + +public: + + ImageEffect_Perspective(TQWidget* parent); + ~ImageEffect_Perspective(); + +private slots: + + void slotUpdateInfo(TQRect newSize, float topLeftAngle, float topRightAngle, + float bottomLeftAngle, float bottomRightAngle); + +private: + + void readUserSettings(); + void writeUserSettings(); + void resetValues(); + void finalRendering(); + +private: + + TQLabel *m_newWidthLabel; + TQLabel *m_newHeightLabel; + TQLabel *m_topLeftAngleLabel; + TQLabel *m_topRightAngleLabel; + TQLabel *m_bottomLeftAngleLabel; + TQLabel *m_bottomRightAngleLabel; + + TQCheckBox *m_drawWhileMovingCheckBox; + TQCheckBox *m_drawGridCheckBox; + + TQSpinBox *m_guideSize; + + KColorButton *m_guideColorBt; + + PerspectiveWidget *m_previewWidget; +}; + +} // NameSpace DigikamPerspectiveImagesPlugin + +#endif /* IMAGEEFFECT_PERSPECTIVE_H */ diff --git a/src/imageplugins/perspective/imageplugin_perspective.cpp b/src/imageplugins/perspective/imageplugin_perspective.cpp new file mode 100644 index 00000000..bb5d0444 --- /dev/null +++ b/src/imageplugins/perspective/imageplugin_perspective.cpp @@ -0,0 +1,69 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-17 + * Description : a plugin to change image perspective . + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> + +// Local includes. + +#include "ddebug.h" +#include "perspectivetool.h" +#include "imageplugin_perspective.h" +#include "imageplugin_perspective.moc" + +using namespace DigikamPerspectiveImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_perspective, + KGenericFactory<ImagePlugin_Perspective>("digikamimageplugin_perspective")); + +ImagePlugin_Perspective::ImagePlugin_Perspective(TQObject *parent, const char*, const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_Perspective") +{ + m_perspectiveAction = new TDEAction(i18n("Perspective Adjustment..."), "perspective", 0, + this, TQ_SLOT(slotPerspective()), + actionCollection(), "imageplugin_perspective"); + + setXMLFile("digikamimageplugin_perspective_ui.rc"); + + DDebug() << "ImagePlugin_Perspective plugin loaded" << endl; +} + +ImagePlugin_Perspective::~ImagePlugin_Perspective() +{ +} + +void ImagePlugin_Perspective::setEnabledActions(bool enable) +{ + m_perspectiveAction->setEnabled(enable); +} + +void ImagePlugin_Perspective::slotPerspective() +{ + PerspectiveTool *tool = new PerspectiveTool(this); + loadTool(tool); +} diff --git a/src/imageplugins/perspective/imageplugin_perspective.h b/src/imageplugins/perspective/imageplugin_perspective.h new file mode 100644 index 00000000..5dee7b1b --- /dev/null +++ b/src/imageplugins/perspective/imageplugin_perspective.h @@ -0,0 +1,56 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-17 + * Description : a plugin to change image perspective . + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_PERSPECTIVE_H +#define IMAGEPLUGIN_PERSPECTIVE_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_Perspective : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_Perspective(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_Perspective(); + + void setEnabledActions(bool enable); + +private slots: + + void slotPerspective(); + +private: + + TDEAction *m_perspectiveAction; +}; + +#endif /* IMAGEPLUGIN_PERSPECTIVE_H */ diff --git a/src/imageplugins/perspective/matrix.cpp b/src/imageplugins/perspective/matrix.cpp new file mode 100644 index 00000000..65723c56 --- /dev/null +++ b/src/imageplugins/perspective/matrix.cpp @@ -0,0 +1,177 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-17 + * Description : a matrix implementation for image + * perspective adjustment. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * Matrix3 implementation inspired from gimp 2.0 + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * 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 <cstring> + +// Local includes. + +#include "matrix.h" + +namespace DigikamPerspectiveImagesPlugin +{ + +static double identityMatrix[3][3] = { { 1.0, 0.0, 0.0 }, + { 0.0, 1.0, 0.0 }, + { 0.0, 0.0, 1.0 } }; + +Matrix::Matrix() +{ + memcpy(coeff, identityMatrix, sizeof(coeff)); +} + +void Matrix::translate (double x, double y) +{ + double g, h, i; + + g = coeff[2][0]; + h = coeff[2][1]; + i = coeff[2][2]; + + coeff[0][0] += x * g; + coeff[0][1] += x * h; + coeff[0][2] += x * i; + coeff[1][0] += y * g; + coeff[1][1] += y * h; + coeff[1][2] += y * i; +} + +void Matrix::scale(double x, double y) +{ + coeff[0][0] *= x; + coeff[0][1] *= x; + coeff[0][2] *= x; + + coeff[1][0] *= y; + coeff[1][1] *= y; + coeff[1][2] *= y; +} + +void Matrix::multiply(const Matrix &matrix) +{ + int i, j; + Matrix tmp; + double t1, t2, t3; + + for (i = 0; i < 3; i++) + { + t1 = matrix.coeff[i][0]; + t2 = matrix.coeff[i][1]; + t3 = matrix.coeff[i][2]; + + for (j = 0; j < 3; j++) + { + tmp.coeff[i][j] = t1 * coeff[0][j]; + tmp.coeff[i][j] += t2 * coeff[1][j]; + tmp.coeff[i][j] += t3 * coeff[2][j]; + } + } + + *this = tmp; +} + +void Matrix::transformPoint(double x, double y, double *newx, double *newy) const +{ + double w; + + w = coeff[2][0] * x + coeff[2][1] * y + coeff[2][2]; + + if (w == 0.0) + w = 1.0; + else + w = 1.0/w; + + *newx = (coeff[0][0] * x + + coeff[0][1] * y + + coeff[0][2]) * w; + *newy = (coeff[1][0] * x + + coeff[1][1] * y + + coeff[1][2]) * w; +} + +void Matrix::invert() +{ + Matrix inv; + double det; + + det = determinant(); + + if (det == 0.0) + return; + + det = 1.0 / det; + + inv.coeff[0][0] = (coeff[1][1] * coeff[2][2] - + coeff[1][2] * coeff[2][1]) * det; + + inv.coeff[1][0] = - (coeff[1][0] * coeff[2][2] - + coeff[1][2] * coeff[2][0]) * det; + + inv.coeff[2][0] = (coeff[1][0] * coeff[2][1] - + coeff[1][1] * coeff[2][0]) * det; + + inv.coeff[0][1] = - (coeff[0][1] * coeff[2][2] - + coeff[0][2] * coeff[2][1]) * det; + + inv.coeff[1][1] = (coeff[0][0] * coeff[2][2] - + coeff[0][2] * coeff[2][0]) * det; + + inv.coeff[2][1] = - (coeff[0][0] * coeff[2][1] - + coeff[0][1] * coeff[2][0]) * det; + + inv.coeff[0][2] = (coeff[0][1] * coeff[1][2] - + coeff[0][2] * coeff[1][1]) * det; + + inv.coeff[1][2] = - (coeff[0][0] * coeff[1][2] - + coeff[0][2] * coeff[1][0]) * det; + + inv.coeff[2][2] = (coeff[0][0] * coeff[1][1] - + coeff[0][1] * coeff[1][0]) * det; + + *this = inv; +} + +double Matrix::determinant() const +{ + double determinant; + + determinant = (coeff[0][0] * + (coeff[1][1] * coeff[2][2] - + coeff[1][2] * coeff[2][1])); + determinant -= (coeff[1][0] * + (coeff[0][1] * coeff[2][2] - + coeff[0][2] * coeff[2][1])); + determinant += (coeff[2][0] * + (coeff[0][1] * coeff[1][2] - + coeff[0][2] * coeff[1][1])); + + return determinant; +} + +} // namespace DigikamPerspectiveImagesPlugin diff --git a/src/imageplugins/perspective/matrix.h b/src/imageplugins/perspective/matrix.h new file mode 100644 index 00000000..fbc5a1aa --- /dev/null +++ b/src/imageplugins/perspective/matrix.h @@ -0,0 +1,106 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-17 + * Description : a matrix implementation for image + * perspective adjustment. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_PERSPECTIVE_MATRIX_H +#define IMAGEEFFECT_PERSPECTIVE_MATRIX_H + +namespace DigikamPerspectiveImagesPlugin +{ + +class Matrix +{ +public: + + /** + * Matrix: + * + * Initializes matrix to the identity matrix. + */ + Matrix(); + + /** + * translate: + * @x: Translation in X direction. + * @y: Translation in Y direction. + * + * Translates the matrix by x and y. + */ + void translate(double x, double y); + + /** + * scale: + * @x: X scale factor. + * @y: Y scale factor. + * + * Scales the matrix by x and y + */ + void scale(double x, double y); + + /** + * invert: + * + * Inverts this matrix. + */ + void invert(); + + /** + * multiply: + * @matrix: The other input matrix. + * + * Multiplies this matrix with another matrix + */ + void multiply(const Matrix &matrix1); + + /** + * transformPoint: + * @x: The source X coordinate. + * @y: The source Y coordinate. + * @newx: The transformed X coordinate. + * @newy: The transformed Y coordinate. + * + * Transforms a point in 2D as specified by the transformation matrix. + */ + void transformPoint(double x, double y, double *newx, double *newy) const; + + /** + * determinant: + * + * Calculates the determinant of this matrix. + * + * Returns: The determinant. + */ + double determinant() const; + + /** + * coeff: + * + * The 3x3 matrix data + */ + double coeff[3][3]; +}; + +} // namespace DigikamPerspectiveImagesPlugin + +#endif // IMAGEEFFECT_PERSPECTIVE_MATRIX_H diff --git a/src/imageplugins/perspective/perspectivetool.cpp b/src/imageplugins/perspective/perspectivetool.cpp new file mode 100644 index 00000000..30d0a2cf --- /dev/null +++ b/src/imageplugins/perspective/perspectivetool.cpp @@ -0,0 +1,244 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-17 + * Description : a plugin to change image perspective. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <tqcheckbox.h> +#include <tqframe.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqpushbutton.h> +#include <tqvgroupbox.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <kcolorbutton.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <khelpmenu.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <tdepopupmenu.h> +#include <kseparator.h> +#include <kstandarddirs.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "editortoolsettings.h" +#include "perspectivewidget.h" +#include "perspectivetool.h" +#include "perspectivetool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamPerspectiveImagesPlugin +{ + +PerspectiveTool::PerspectiveTool(TQObject* parent) + : EditorTool(parent) +{ + setName("perspective"); + setToolName(i18n("Perspective")); + setToolIcon(SmallIcon("perspective")); + + // ------------------------------------------------------------- + + TQFrame *frame = new TQFrame(0); + frame->setFrameStyle(TQFrame::Panel|TQFrame::Sunken); + TQVBoxLayout* l = new TQVBoxLayout(frame, 5, 0); + m_previewWidget = new PerspectiveWidget(525, 350, frame); + l->addWidget(m_previewWidget); + TQWhatsThis::add(m_previewWidget, i18n("<p>This is the perspective transformation operation preview. " + "You can use the mouse for dragging the corner to adjust the " + "perspective transformation area.")); + setToolView(frame); + + // ------------------------------------------------------------- + + TQString temp; + Digikam::ImageIface iface(0, 0); + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel); + + TQGridLayout *gridLayout = new TQGridLayout( m_gboxSettings->plainPage(), 13, 2); + + TQLabel *label1 = new TQLabel(i18n("New width:"), m_gboxSettings->plainPage()); + m_newWidthLabel = new TQLabel(temp.setNum( iface.originalWidth()) + i18n(" px"), m_gboxSettings->plainPage()); + m_newWidthLabel->setAlignment( AlignBottom | AlignRight ); + + TQLabel *label2 = new TQLabel(i18n("New height:"), m_gboxSettings->plainPage()); + m_newHeightLabel = new TQLabel(temp.setNum( iface.originalHeight()) + i18n(" px"), m_gboxSettings->plainPage()); + m_newHeightLabel->setAlignment( AlignBottom | AlignRight ); + + // ------------------------------------------------------------- + + KSeparator *line = new KSeparator(Horizontal, m_gboxSettings->plainPage()); + + TQLabel *angleLabel = new TQLabel(i18n("Angles (in degrees):"), m_gboxSettings->plainPage()); + TQLabel *label3 = new TQLabel(i18n(" Top left:"), m_gboxSettings->plainPage()); + m_topLeftAngleLabel = new TQLabel(m_gboxSettings->plainPage()); + TQLabel *label4 = new TQLabel(i18n(" Top right:"), m_gboxSettings->plainPage()); + m_topRightAngleLabel = new TQLabel(m_gboxSettings->plainPage()); + TQLabel *label5 = new TQLabel(i18n(" Bottom left:"), m_gboxSettings->plainPage()); + m_bottomLeftAngleLabel = new TQLabel(m_gboxSettings->plainPage()); + TQLabel *label6 = new TQLabel(i18n(" Bottom right:"), m_gboxSettings->plainPage()); + m_bottomRightAngleLabel = new TQLabel(m_gboxSettings->plainPage()); + + // ------------------------------------------------------------- + + KSeparator *line2 = new KSeparator(Horizontal, m_gboxSettings->plainPage()); + + m_drawWhileMovingCheckBox = new TQCheckBox(i18n("Draw preview while moving"), m_gboxSettings->plainPage()); + gridLayout->addMultiCellWidget(line2, 8, 8, 0, 2); + gridLayout->addMultiCellWidget(m_drawWhileMovingCheckBox, 9, 9, 0, 2); + + m_drawGridCheckBox = new TQCheckBox(i18n("Draw grid"), m_gboxSettings->plainPage()); + + // ------------------------------------------------------------- + + TQLabel *label7 = new TQLabel(i18n("Guide color:"), m_gboxSettings->plainPage()); + m_guideColorBt = new KColorButton( TQColor( TQt::red ), m_gboxSettings->plainPage() ); + TQWhatsThis::add( m_guideColorBt, i18n("<p>Set here the color used to draw guides dashed-lines.")); + gridLayout->addMultiCellWidget(label7, 11, 11, 0, 0); + gridLayout->addMultiCellWidget(m_guideColorBt, 11, 11, 2, 2); + + TQLabel *label8 = new TQLabel(i18n("Guide width:"), m_gboxSettings->plainPage()); + m_guideSize = new RIntNumInput(m_gboxSettings->plainPage()); + m_guideSize->input()->setRange(1, 5, 1, false); + m_guideSize->setDefaultValue(1); + TQWhatsThis::add( m_guideSize, i18n("<p>Set here the width in pixels used to draw guides dashed-lines.")); + + gridLayout->addMultiCellWidget(label1, 0, 0, 0, 0); + gridLayout->addMultiCellWidget(m_newWidthLabel, 0, 0, 1, 2); + gridLayout->addMultiCellWidget(label2, 1, 1, 0, 0); + gridLayout->addMultiCellWidget(m_newHeightLabel, 1, 1, 1, 2); + gridLayout->addMultiCellWidget(line, 2, 2, 0, 2); + gridLayout->addMultiCellWidget(angleLabel, 3, 3, 0, 2); + gridLayout->addMultiCellWidget(label3, 4, 4, 0, 0); + gridLayout->addMultiCellWidget(m_topLeftAngleLabel, 4, 4, 1, 2); + gridLayout->addMultiCellWidget(label4, 5, 5, 0, 0); + gridLayout->addMultiCellWidget(m_topRightAngleLabel, 5, 5, 1, 2); + gridLayout->addMultiCellWidget(label5, 6, 6, 0, 0); + gridLayout->addMultiCellWidget(m_bottomLeftAngleLabel, 6, 6, 1, 2); + gridLayout->addMultiCellWidget(label6, 7, 7, 0, 0); + gridLayout->addMultiCellWidget(m_bottomRightAngleLabel, 7, 7, 1, 2); + gridLayout->addMultiCellWidget(m_drawGridCheckBox, 10, 10, 0, 2); + gridLayout->addMultiCellWidget(label8, 12, 12, 0, 0); + gridLayout->addMultiCellWidget(m_guideSize, 12, 12, 2, 2); + gridLayout->setColStretch(1, 10); + gridLayout->setRowStretch(13, 10); + gridLayout->setMargin(m_gboxSettings->spacingHint()); + gridLayout->setSpacing(m_gboxSettings->spacingHint()); + + setToolSettings(m_gboxSettings); + init(); + + // ------------------------------------------------------------- + + connect(m_previewWidget, TQ_SIGNAL(signalPerspectiveChanged(TQRect, float, float, float, float)), + this, TQ_SLOT(slotUpdateInfo(TQRect, float, float, float, float))); + + connect(m_drawWhileMovingCheckBox, TQ_SIGNAL(toggled(bool)), + m_previewWidget, TQ_SLOT(slotToggleDrawWhileMoving(bool))); + + connect(m_drawGridCheckBox, TQ_SIGNAL(toggled(bool)), + m_previewWidget, TQ_SLOT(slotToggleDrawGrid(bool))); + + connect(m_guideColorBt, TQ_SIGNAL(changed(const TQColor&)), + m_previewWidget, TQ_SLOT(slotChangeGuideColor(const TQColor&))); + + connect(m_guideSize, TQ_SIGNAL(valueChanged(int)), + m_previewWidget, TQ_SLOT(slotChangeGuideSize(int))); +} + +PerspectiveTool::~PerspectiveTool() +{ +} + +void PerspectiveTool::readSettings() +{ + TQColor defaultGuideColor(TQt::red); + TDEConfig *config = kapp->config(); + config->setGroup("perspective Tool"); + m_drawWhileMovingCheckBox->setChecked(config->readBoolEntry("Draw While Moving", true)); + m_drawGridCheckBox->setChecked(config->readBoolEntry("Draw Grid", false)); + m_guideColorBt->setColor(config->readColorEntry("Guide Color", &defaultGuideColor)); + m_guideSize->setValue(config->readNumEntry("Guide Width", m_guideSize->defaultValue())); + m_previewWidget->slotToggleDrawWhileMoving(m_drawWhileMovingCheckBox->isChecked()); + m_previewWidget->slotToggleDrawGrid(m_drawGridCheckBox->isChecked()); + m_previewWidget->slotChangeGuideColor(m_guideColorBt->color()); + m_previewWidget->slotChangeGuideSize(m_guideSize->value()); +} + +void PerspectiveTool::writeSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("perspective Tool"); + config->writeEntry("Draw While Moving", m_drawWhileMovingCheckBox->isChecked()); + config->writeEntry("Draw Grid", m_drawGridCheckBox->isChecked()); + config->writeEntry("Guide Color", m_guideColorBt->color()); + config->writeEntry("Guide Width", m_guideSize->value()); + config->sync(); +} + +void PerspectiveTool::slotResetSettings() +{ + m_previewWidget->reset(); +} + +void PerspectiveTool::finalRendering() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + m_previewWidget->applyPerspectiveAdjustment(); + kapp->restoreOverrideCursor(); +} + +void PerspectiveTool::slotUpdateInfo(TQRect newSize, float topLeftAngle, float topRightAngle, + float bottomLeftAngle, float bottomRightAngle) +{ + TQString temp; + m_newWidthLabel->setText(temp.setNum( newSize.width()) + i18n(" px") ); + m_newHeightLabel->setText(temp.setNum( newSize.height()) + i18n(" px") ); + + m_topLeftAngleLabel->setText(temp.setNum( topLeftAngle, 'f', 1 )); + m_topRightAngleLabel->setText(temp.setNum( topRightAngle, 'f', 1 )); + m_bottomLeftAngleLabel->setText(temp.setNum( bottomLeftAngle, 'f', 1 )); + m_bottomRightAngleLabel->setText(temp.setNum( bottomRightAngle, 'f', 1 )); +} + +} // NameSpace DigikamPerspectiveImagesPlugin diff --git a/src/imageplugins/perspective/perspectivetool.h b/src/imageplugins/perspective/perspectivetool.h new file mode 100644 index 00000000..6186712f --- /dev/null +++ b/src/imageplugins/perspective/perspectivetool.h @@ -0,0 +1,100 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-17 + * Description : a plugin to change image perspective. + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_PERSPECTIVE_H +#define IMAGEEFFECT_PERSPECTIVE_H + +// TQt includes. + +#include <tqrect.h> + +// Digikam includes. + +#include "editortool.h" + +class TQLabel; +class TQCheckBox; + +class KColorButton; + +namespace KDcrawIface +{ +class RIntNumInput; +} + +namespace Digikam +{ +class EditorToolSettings; +} + +namespace DigikamPerspectiveImagesPlugin +{ + +class PerspectiveWidget; + +class PerspectiveTool : public Digikam::EditorTool +{ + TQ_OBJECT + + +public: + + PerspectiveTool(TQObject* parent); + ~PerspectiveTool(); + +private slots: + + void slotResetSettings(); + void slotUpdateInfo(TQRect newSize, float topLeftAngle, float topRightAngle, + float bottomLeftAngle, float bottomRightAngle); + +private: + + void readSettings(); + void writeSettings(); + void finalRendering(); + +private: + + TQLabel *m_newWidthLabel; + TQLabel *m_newHeightLabel; + TQLabel *m_topLeftAngleLabel; + TQLabel *m_topRightAngleLabel; + TQLabel *m_bottomLeftAngleLabel; + TQLabel *m_bottomRightAngleLabel; + + TQCheckBox *m_drawWhileMovingCheckBox; + TQCheckBox *m_drawGridCheckBox; + + KDcrawIface::RIntNumInput *m_guideSize; + + KColorButton *m_guideColorBt; + + PerspectiveWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamPerspectiveImagesPlugin + +#endif /* IMAGEEFFECT_PERSPECTIVE_H */ diff --git a/src/imageplugins/perspective/perspectivewidget.cpp b/src/imageplugins/perspective/perspectivewidget.cpp new file mode 100644 index 00000000..ae2c5c03 --- /dev/null +++ b/src/imageplugins/perspective/perspectivewidget.cpp @@ -0,0 +1,839 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-18 + * Description : a widget class to edit perspective. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * Matrix3 implementation inspired from gimp 2.0 + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * 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 <cstdio> +#include <cstdlib> +#include <cmath> + +// TQt includes. + +#include <tqregion.h> +#include <tqpainter.h> +#include <tqpen.h> +#include <tqbrush.h> +#include <tqpixmap.h> +#include <tqimage.h> +#include <tqpointarray.h> + +// KDE includes. + +#include <kstandarddirs.h> +#include <kcursor.h> +#include <tdeglobal.h> +#include <tdeapplication.h> + +// Local includes. + +#include "triangle.h" +#include "ddebug.h" +#include "imageiface.h" +#include "dimgimagefilters.h" +#include "perspectivewidget.h" +#include "perspectivewidget.moc" + +namespace DigikamPerspectiveImagesPlugin +{ + +PerspectiveWidget::PerspectiveWidget(int w, int h, TQWidget *parent) + : TQWidget(parent, 0, TQt::WDestructiveClose) +{ + setBackgroundMode(TQt::NoBackground); + setMinimumSize(w, h); + setMouseTracking(true); + + m_drawGrid = false; + m_drawWhileMoving = true; + m_currentResizing = ResizingNone; + m_guideColor = TQt::red; + m_guideSize = 1; + + m_iface = new Digikam::ImageIface(w, h); + uchar *data = m_iface->setPreviewImageSize(w, h); + m_w = m_iface->previewWidth(); + m_h = m_iface->previewHeight(); + m_origW = m_iface->originalWidth(); + m_origH = m_iface->originalHeight(); + m_previewImage = Digikam::DImg(m_w, m_h, m_iface->previewSixteenBit(), m_iface->previewHasAlpha(), data, false); + + m_pixmap = new TQPixmap(w, h); + + m_rect = TQRect(w/2-m_w/2, h/2-m_h/2, m_w, m_h); + m_grid = TQPointArray(60); + + reset(); +} + +PerspectiveWidget::~PerspectiveWidget() +{ + delete m_iface; + delete m_pixmap; +} + +Digikam::ImageIface* PerspectiveWidget::imageIface() +{ + return m_iface; +} + +TQPoint PerspectiveWidget::getTopLeftCorner(void) +{ + return TQPoint( lroundf((float)(m_topLeftPoint.x()*m_origW) / (float)m_w), + lroundf((float)(m_topLeftPoint.y()*m_origH) / (float)m_h)); +} + +TQPoint PerspectiveWidget::getTopRightCorner(void) +{ + return TQPoint( lroundf((float)(m_topRightPoint.x()*m_origW) / (float)m_w), + lroundf((float)(m_topRightPoint.y()*m_origH) / (float)m_h)); +} + +TQPoint PerspectiveWidget::getBottomLeftCorner(void) +{ + return TQPoint( lroundf((float)(m_bottomLeftPoint.x()*m_origW) / (float)m_w), + lroundf((float)(m_bottomLeftPoint.y()*m_origH) / (float)m_h)); +} + +TQPoint PerspectiveWidget::getBottomRightCorner(void) +{ + return TQPoint( lroundf((float)(m_bottomRightPoint.x()*m_origW) / (float)m_w), + lroundf((float)(m_bottomRightPoint.y()*m_origH) / (float)m_h)); +} + +TQRect PerspectiveWidget::getTargetSize(void) +{ + TQPointArray perspectiveArea; + + perspectiveArea.putPoints( 0, 4, + getTopLeftCorner().x(), getTopLeftCorner().y(), + getTopRightCorner().x(), getTopRightCorner().y(), + getBottomRightCorner().x(), getBottomRightCorner().y(), + getBottomLeftCorner().x(), getBottomLeftCorner().y() ); + + return perspectiveArea.boundingRect(); +} + +float PerspectiveWidget::getAngleTopLeft(void) +{ + Triangle topLeft(getTopLeftCorner(), getTopRightCorner(), getBottomLeftCorner()); + return topLeft.angleBAC(); +} + +float PerspectiveWidget::getAngleTopRight(void) +{ + Triangle topLeft(getTopRightCorner(), getBottomRightCorner(), getTopLeftCorner()); + return topLeft.angleBAC(); +} + +float PerspectiveWidget::getAngleBottomLeft(void) +{ + Triangle topLeft(getBottomLeftCorner(), getTopLeftCorner(), getBottomRightCorner()); + return topLeft.angleBAC(); +} + +float PerspectiveWidget::getAngleBottomRight(void) +{ + Triangle topLeft(getBottomRightCorner(), getBottomLeftCorner(), getTopRightCorner()); + return topLeft.angleBAC(); +} + +void PerspectiveWidget::reset(void) +{ + m_topLeftPoint.setX(0); + m_topLeftPoint.setY(0); + + m_topRightPoint.setX(m_w-1); + m_topRightPoint.setY(0); + + m_bottomLeftPoint.setX(0); + m_bottomLeftPoint.setY(m_h-1); + + m_bottomRightPoint.setX(m_w-1); + m_bottomRightPoint.setY(m_h-1); + + m_spot.setX(m_w / 2); + m_spot.setY(m_h / 2); + + m_antiAlias = true; + updatePixmap(); + repaint(false); +} + +void PerspectiveWidget::applyPerspectiveAdjustment(void) +{ + Digikam::DImg *orgImage = m_iface->getOriginalImg(); + Digikam::DImg destImage(orgImage->width(), orgImage->height(), orgImage->sixteenBit(), orgImage->hasAlpha()); + + Digikam::DColor background(0, 0, 0, orgImage->hasAlpha() ? 0 : 255, orgImage->sixteenBit()); + + // Perform perspective adjustment. + + buildPerspective(TQPoint(0, 0), TQPoint(m_origW, m_origH), + getTopLeftCorner(), getTopRightCorner(), + getBottomLeftCorner(), getBottomRightCorner(), + orgImage, &destImage, background); + + // Perform an auto-croping around the image. + + Digikam::DImg targetImg = destImage.copy(getTargetSize()); + + // Update target image. + m_iface->putOriginalImage(i18n("Perspective Adjustment"), + targetImg.bits(), targetImg.width(), targetImg.height()); +} + +void PerspectiveWidget::slotToggleAntiAliasing(bool a) +{ + m_antiAlias = a; + updatePixmap(); + repaint(false); +} + +void PerspectiveWidget::slotToggleDrawWhileMoving(bool draw) +{ + m_drawWhileMoving = draw; +} + +void PerspectiveWidget::slotToggleDrawGrid(bool grid) +{ + m_drawGrid = grid; + updatePixmap(); + repaint(false); +} + +void PerspectiveWidget::slotChangeGuideColor(const TQColor &color) +{ + m_guideColor = color; + updatePixmap(); + repaint(false); +} + +void PerspectiveWidget::slotChangeGuideSize(int size) +{ + m_guideSize = size; + updatePixmap(); + repaint(false); +} + +void PerspectiveWidget::updatePixmap(void) +{ + m_topLeftCorner.setRect(m_topLeftPoint.x() + m_rect.topLeft().x(), + m_topLeftPoint.y() + m_rect.topLeft().y(), 8, 8); + m_topRightCorner.setRect(m_topRightPoint.x() - 7 + m_rect.topLeft().x(), + m_topRightPoint.y() + m_rect.topLeft().y(), 8, 8); + m_bottomLeftCorner.setRect(m_bottomLeftPoint.x() + m_rect.topLeft().x(), + m_bottomLeftPoint.y() - 7 + m_rect.topLeft().y(), 8, 8); + m_bottomRightCorner.setRect(m_bottomRightPoint.x() - 7 + m_rect.topLeft().x(), + m_bottomRightPoint.y() - 7 + m_rect.topLeft().y(), 8, 8); + + // Compute the grid array + + int gXS = m_w / 15; + int gYS = m_h / 15; + + for (int i = 0 ; i < 15 ; i++) + { + int j = i*4; + + //Horizontal line. + m_grid.setPoint(j , 0, i*gYS); + m_grid.setPoint(j+1, m_w, i*gYS); + + //Vertical line. + m_grid.setPoint(j+2, i*gXS, 0); + m_grid.setPoint(j+3, i*gXS, m_h); + } + + // Draw background + + m_pixmap->fill(colorGroup().background()); + + // if we are resizing with the mouse, compute and draw only if drawWhileMoving is set + if (m_currentResizing == ResizingNone || m_drawWhileMoving) + { + // Create preview image + + Digikam::DImg destImage(m_previewImage.width(), m_previewImage.height(), + m_previewImage.sixteenBit(), m_previewImage.hasAlpha()); + + Digikam::DColor background(colorGroup().background()); + + m_transformedCenter = buildPerspective(TQPoint(0, 0), TQPoint(m_w, m_h), + m_topLeftPoint, m_topRightPoint, + m_bottomLeftPoint, m_bottomRightPoint, + &m_previewImage, &destImage, background); + + m_iface->putPreviewImage(destImage.bits()); + + // Draw image + + m_iface->paint(m_pixmap, m_rect.x(), m_rect.y(), + m_rect.width(), m_rect.height()); + } + else + { + m_transformedCenter = buildPerspective(TQPoint(0, 0), TQPoint(m_w, m_h), + m_topLeftPoint, m_topRightPoint, + m_bottomLeftPoint, m_bottomRightPoint); + } + + // Drawing selection borders. + + TQPainter p(m_pixmap); + p.setPen(TQPen(TQColor(255, 64, 64), 1, TQt::SolidLine)); + p.drawLine(m_topLeftPoint+m_rect.topLeft(), m_topRightPoint+m_rect.topLeft()); + p.drawLine(m_topRightPoint+m_rect.topLeft(), m_bottomRightPoint+m_rect.topLeft()); + p.drawLine(m_bottomRightPoint+m_rect.topLeft(), m_bottomLeftPoint+m_rect.topLeft()); + p.drawLine(m_bottomLeftPoint+m_rect.topLeft(), m_topLeftPoint+m_rect.topLeft()); + + // Drawing selection corners. + + TQBrush brush(TQColor(255, 64, 64)); + p.fillRect(m_topLeftCorner, brush); + p.fillRect(m_topRightCorner, brush); + p.fillRect(m_bottomLeftCorner, brush); + p.fillRect(m_bottomRightCorner, brush); + + // Drawing the grid. + + if (m_drawGrid) + { + for (uint i = 0 ; i < m_grid.size() ; i += 4) + { + //Horizontal line. + p.drawLine(m_grid.point(i)+m_rect.topLeft(), m_grid.point(i+1)+m_rect.topLeft()); + + //Vertical line. + p.drawLine(m_grid.point(i+2)+m_rect.topLeft(), m_grid.point(i+3)+m_rect.topLeft()); + } + } + + // Drawing transformed center. + + p.setPen(TQPen(TQColor(255, 64, 64), 3, TQt::SolidLine)); + p.drawEllipse( m_transformedCenter.x()+m_rect.topLeft().x()-2, + m_transformedCenter.y()+m_rect.topLeft().y()-2, 4, 4 ); + + // Drawing vertical and horizontal guide lines. + + int xspot = m_spot.x() + m_rect.x(); + int yspot = m_spot.y() + m_rect.y(); + p.setPen(TQPen(TQt::white, m_guideSize, TQt::SolidLine)); + p.drawLine(xspot, m_rect.top(), xspot, m_rect.bottom()); + p.drawLine(m_rect.left(), yspot, m_rect.right(), yspot); + p.setPen(TQPen(m_guideColor, m_guideSize, TQt::DotLine)); + p.drawLine(xspot, m_rect.top(), xspot, m_rect.bottom()); + p.drawLine(m_rect.left(), yspot, m_rect.right(), yspot); + + p.end(); + + emit signalPerspectiveChanged(getTargetSize(), getAngleTopLeft(), getAngleTopRight(), + getAngleBottomLeft(), getAngleBottomRight()); +} + +TQPoint PerspectiveWidget::buildPerspective(TQPoint orignTopLeft, TQPoint orignBottomRight, + TQPoint transTopLeft, TQPoint transTopRight, + TQPoint transBottomLeft, TQPoint transBottomRight, + Digikam::DImg *orgImage, Digikam::DImg *destImage, + Digikam::DColor background) +{ + Matrix matrix, transform; + double scalex; + double scaley; + + double x1 = (double)orignTopLeft.x(); + double y1 = (double)orignTopLeft.y(); + + double x2 = (double)orignBottomRight.x(); + double y2 = (double)orignBottomRight.y(); + + double tx1 = (double)transTopLeft.x(); + double ty1 = (double)transTopLeft.y(); + + double tx2 = (double)transTopRight.x(); + double ty2 = (double)transTopRight.y(); + + double tx3 = (double)transBottomLeft.x(); + double ty3 = (double)transBottomLeft.y(); + + double tx4 = (double)transBottomRight.x(); + double ty4 = (double)transBottomRight.y(); + + scalex = scaley = 1.0; + + if ((x2 - x1) > 0) + scalex = 1.0 / (double) (x2 - x1); + + if ((y2 - y1) > 0) + scaley = 1.0 / (double) (y2 - y1); + + // Determine the perspective transform that maps from + // the unit cube to the transformed coordinates + + double dx1, dx2, dx3, dy1, dy2, dy3; + + dx1 = tx2 - tx4; + dx2 = tx3 - tx4; + dx3 = tx1 - tx2 + tx4 - tx3; + + dy1 = ty2 - ty4; + dy2 = ty3 - ty4; + dy3 = ty1 - ty2 + ty4 - ty3; + + // Is the mapping affine? + + if ((dx3 == 0.0) && (dy3 == 0.0)) + { + matrix.coeff[0][0] = tx2 - tx1; + matrix.coeff[0][1] = tx4 - tx2; + matrix.coeff[0][2] = tx1; + matrix.coeff[1][0] = ty2 - ty1; + matrix.coeff[1][1] = ty4 - ty2; + matrix.coeff[1][2] = ty1; + matrix.coeff[2][0] = 0.0; + matrix.coeff[2][1] = 0.0; + } + else + { + double det1, det2; + + det1 = dx3 * dy2 - dy3 * dx2; + det2 = dx1 * dy2 - dy1 * dx2; + + if (det1 == 0.0 && det2 == 0.0) + matrix.coeff[2][0] = 1.0; + else + matrix.coeff[2][0] = det1 / det2; + + det1 = dx1 * dy3 - dy1 * dx3; + + if (det1 == 0.0 && det2 == 0.0) + matrix.coeff[2][1] = 1.0; + else + matrix.coeff[2][1] = det1 / det2; + + matrix.coeff[0][0] = tx2 - tx1 + matrix.coeff[2][0] * tx2; + matrix.coeff[0][1] = tx3 - tx1 + matrix.coeff[2][1] * tx3; + matrix.coeff[0][2] = tx1; + + matrix.coeff[1][0] = ty2 - ty1 + matrix.coeff[2][0] * ty2; + matrix.coeff[1][1] = ty3 - ty1 + matrix.coeff[2][1] * ty3; + matrix.coeff[1][2] = ty1; + } + + matrix.coeff[2][2] = 1.0; + + // transform is initialized to the identity matrix + transform.translate(-x1, -y1); + transform.scale (scalex, scaley); + transform.multiply (matrix); + + // Compute perspective transformation to image if image data containers exist. + if (orgImage && destImage) + transformAffine(orgImage, destImage, transform, background); + + // Calculate the grid array points. + double newX, newY; + for (uint i = 0 ; i < m_grid.size() ; i++) + { + transform.transformPoint(m_grid.point(i).x(), m_grid.point(i).y(), &newX, &newY); + m_grid.setPoint(i, lround(newX), lround(newY)); + } + + // Calculate and return new image center. + double newCenterX, newCenterY; + transform.transformPoint(x2/2.0, y2/2.0, &newCenterX, &newCenterY); + + return TQPoint(lround(newCenterX), lround(newCenterY)); +} + +void PerspectiveWidget::transformAffine(Digikam::DImg *orgImage, Digikam::DImg *destImage, + const Matrix &matrix, Digikam::DColor background) +{ + Matrix m(matrix), inv(matrix); + + int x1, y1, x2, y2; // target bounding box + int x, y; // target coordinates + int u1, v1, u2, v2; // source bounding box + double uinc, vinc, winc; // increments in source coordinates + // pr horizontal target coordinate + + double u[5],v[5]; // source coordinates, + // 2 + // / \ 0 is sample in the center of pixel + // 1 0 3 1..4 is offset 1 pixel in each + // \ / direction (in target space) + // 4 + + double tu[5],tv[5],tw[5]; // undivided source coordinates and divisor + + uchar *data, *newData; + bool sixteenBit; + int coords; + int width, height; + int bytesDepth; + int offset; + uchar *dest, *d; + Digikam::DColor color; + + bytesDepth = orgImage->bytesDepth(); + data = orgImage->bits(); + sixteenBit = orgImage->sixteenBit(); + width = orgImage->width(); + height = orgImage->height(); + newData = destImage->bits(); + + if (sixteenBit) + background.convertToSixteenBit(); + + //destImage->fill(background); + + Digikam::DImgImageFilters filters; + + // Find the inverse of the transformation matrix + m.invert(); + + u1 = 0; + v1 = 0; + u2 = u1 + width; + v2 = v1 + height; + + x1 = u1; + y1 = v1; + x2 = u2; + y2 = v2; + + dest = new uchar[width * bytesDepth]; + + uinc = m.coeff[0][0]; + vinc = m.coeff[1][0]; + winc = m.coeff[2][0]; + + coords = 1; + + // these loops could be rearranged, depending on which bit of code + // you'd most like to write more than once. + + for (y = y1; y < y2; y++) + { + // set up inverse transform steps + + tu[0] = uinc * (x1 + 0.5) + m.coeff[0][1] * (y + 0.5) + m.coeff[0][2] - 0.5; + tv[0] = vinc * (x1 + 0.5) + m.coeff[1][1] * (y + 0.5) + m.coeff[1][2] - 0.5; + tw[0] = winc * (x1 + 0.5) + m.coeff[2][1] * (y + 0.5) + m.coeff[2][2]; + + d = dest; + + for (x = x1; x < x2; x++) + { + int i; // normalize homogeneous coords + + for (i = 0; i < coords; i++) + { + if (tw[i] == 1.0) + { + u[i] = tu[i]; + v[i] = tv[i]; + } + else if (tw[i] != 0.0) + { + u[i] = tu[i] / tw[i]; + v[i] = tv[i] / tw[i]; + } + else + { + DDebug() << "homogeneous coordinate = 0...\n" << endl; + } + } + + // Set the destination pixels + + int iu = lround( u [0] ); + int iv = lround( v [0] ); + + if (iu >= u1 && iu < u2 && iv >= v1 && iv < v2) + { + // u, v coordinates into source + + int u = iu - u1; + int v = iv - v1; + + //TODO: Check why antialiasing shows no effect + /*if (m_antiAlias) + { + if (sixteenBit) + { + unsigned short *d16 = (unsigned short *)d; + filters.pixelAntiAliasing16((unsigned short *)data, + width, height, u, v, d16+3, d16+2, d16+1, d16); + } + else + { + filters.pixelAntiAliasing(data, width, height, u, v, + d+3, d+2, d+1, d); + } + } + else + {*/ + offset = (v * width * bytesDepth) + (u * bytesDepth); + color.setColor(data + offset, sixteenBit); + color.setPixel(d); + //} + + d += bytesDepth; + } + else // not in source range + { + // set to background color + + background.setPixel(d); + d += bytesDepth; + } + + for (i = 0; i < coords; i++) + { + tu[i] += uinc; + tv[i] += vinc; + tw[i] += winc; + } + } + + // set the pixel region row + + offset = (y - y1) * width * bytesDepth; + memcpy(newData + offset, dest, width * bytesDepth); + } + + delete [] dest; +} + +void PerspectiveWidget::paintEvent( TQPaintEvent * ) +{ + bitBlt(this, 0, 0, m_pixmap); +} + +void PerspectiveWidget::resizeEvent(TQResizeEvent * e) +{ + int old_w = m_w; + int old_h = m_h; + + delete m_pixmap; + int w = e->size().width(); + int h = e->size().height(); + uchar *data = m_iface->setPreviewImageSize(w, h); + m_w = m_iface->previewWidth(); + m_h = m_iface->previewHeight(); + m_previewImage = Digikam::DImg(m_w, m_h, m_iface->previewSixteenBit(), m_iface->previewHasAlpha(), data, false); + + m_pixmap = new TQPixmap(w, h); + TQRect oldRect = m_rect; + m_rect = TQRect(w/2-m_w/2, h/2-m_h/2, m_w, m_h); + + float xFactor = (float)m_rect.width()/(float)(oldRect.width()); + float yFactor = (float)m_rect.height()/(float)(oldRect.height()); + + m_topLeftPoint = TQPoint(lroundf(m_topLeftPoint.x()*xFactor), + lroundf(m_topLeftPoint.y()*yFactor)); + m_topRightPoint = TQPoint(lroundf(m_topRightPoint.x()*xFactor), + lroundf(m_topRightPoint.y()*yFactor)); + m_bottomLeftPoint = TQPoint(lroundf(m_bottomLeftPoint.x()*xFactor), + lroundf(m_bottomLeftPoint.y()*yFactor)); + m_bottomRightPoint = TQPoint(lroundf(m_bottomRightPoint.x()*xFactor), + lroundf(m_bottomRightPoint.y()*yFactor)); + m_transformedCenter = TQPoint(lroundf(m_transformedCenter.x()*xFactor), + lroundf(m_transformedCenter.y()*yFactor)); + + m_spot.setX((int)((float)m_spot.x() * ( (float)m_w / (float)old_w))); + m_spot.setY((int)((float)m_spot.y() * ( (float)m_h / (float)old_h))); + + updatePixmap(); +} + +void PerspectiveWidget::mousePressEvent ( TQMouseEvent * e ) +{ + if ( e->button() == TQt::LeftButton && + m_rect.contains( e->x(), e->y() )) + { + if ( m_topLeftCorner.contains( e->x(), e->y() ) ) + m_currentResizing = ResizingTopLeft; + else if ( m_bottomRightCorner.contains( e->x(), e->y() ) ) + m_currentResizing = ResizingBottomRight; + else if ( m_topRightCorner.contains( e->x(), e->y() ) ) + m_currentResizing = ResizingTopRight; + else if ( m_bottomLeftCorner.contains( e->x(), e->y() ) ) + m_currentResizing = ResizingBottomLeft; + else + { + m_spot.setX(e->x()-m_rect.x()); + m_spot.setY(e->y()-m_rect.y()); + } + } +} + +void PerspectiveWidget::mouseReleaseEvent ( TQMouseEvent * e ) +{ + if ( m_currentResizing != ResizingNone ) + { + unsetCursor(); + m_currentResizing = ResizingNone; + + // in this case, the pixmap has not been drawn on mouse move + if (!m_drawWhileMoving) + { + updatePixmap(); + repaint(false); + } + } + else + { + m_spot.setX(e->x()-m_rect.x()); + m_spot.setY(e->y()-m_rect.y()); + updatePixmap(); + repaint(false); + } +} + +void PerspectiveWidget::mouseMoveEvent ( TQMouseEvent * e ) +{ + if ( e->state() == TQt::LeftButton ) + { + if ( m_currentResizing != ResizingNone ) + { + TQPointArray unsablePoints; + TQPoint pm(e->x(), e->y()); + + if (!m_rect.contains( pm )) + { + if (pm.x() > m_rect.right()) + pm.setX(m_rect.right()); + else if (pm.x() < m_rect.left()) + pm.setX(m_rect.left()); + + if (pm.y() > m_rect.bottom()) + pm.setY(m_rect.bottom()); + else if (pm.y() < m_rect.top()) + pm.setY(m_rect.top()); + } + + if ( m_currentResizing == ResizingTopLeft ) + { + unsablePoints.putPoints(0, 7, + m_w-1, m_h-1, + 0, m_h-1, + 0, m_bottomLeftPoint.y()-10, + m_bottomLeftPoint.x(), m_bottomLeftPoint.y()-10, + m_topRightPoint.x()-10, m_topRightPoint.y(), + m_topRightPoint.x()-10, 0, + m_w-1, 0 ); + TQRegion unsableArea(unsablePoints); + + if ( unsableArea.contains(pm) ) return; + + m_topLeftPoint = pm - m_rect.topLeft(); + setCursor( KCursor::sizeFDiagCursor() ); + } + + else if ( m_currentResizing == ResizingTopRight ) + { + unsablePoints.putPoints(0, 7, + 0, m_h-1, + 0, 0, + m_topLeftPoint.x()+10, 0, + m_topLeftPoint.x()+10, m_topLeftPoint.y(), + m_bottomRightPoint.x(), m_bottomRightPoint.y()-10, + m_w-1, m_bottomRightPoint.y()-10, + m_w-1, m_h-1); + TQRegion unsableArea(unsablePoints); + + if ( unsableArea.contains(pm) ) return; + + m_topRightPoint = pm - m_rect.topLeft(); + setCursor( KCursor::sizeBDiagCursor() ); + } + + else if ( m_currentResizing == ResizingBottomLeft ) + { + unsablePoints.putPoints(0, 7, + m_w-1, 0, + m_w-1, m_h-1, + m_bottomRightPoint.x()-10, m_h-1, + m_bottomRightPoint.x()-10, m_bottomRightPoint.y()+10, + m_topLeftPoint.x(), m_topLeftPoint.y()+10, + 0, m_topLeftPoint.y(), + 0, 0); + TQRegion unsableArea(unsablePoints); + + if ( unsableArea.contains(pm) ) return; + + m_bottomLeftPoint = pm - m_rect.topLeft(); + setCursor( KCursor::sizeBDiagCursor() ); + } + + else if ( m_currentResizing == ResizingBottomRight ) + { + unsablePoints.putPoints(0, 7, + 0, 0, + m_w-1, 0, + m_w-1, m_topRightPoint.y()+10, + m_topRightPoint.x(), m_topRightPoint.y()+10, + m_bottomLeftPoint.x()+10, m_bottomLeftPoint.y(), + m_bottomLeftPoint.x()+10, m_w-1, + 0, m_w-1); + TQRegion unsableArea(unsablePoints); + + if ( unsableArea.contains(pm) ) return; + + m_bottomRightPoint = pm - m_rect.topLeft(); + setCursor( KCursor::sizeFDiagCursor() ); + } + + else + { + m_spot.setX(e->x()-m_rect.x()); + m_spot.setY(e->y()-m_rect.y()); + } + + updatePixmap(); + repaint(false); + } + } + else + { + if ( m_topLeftCorner.contains( e->x(), e->y() ) || + m_bottomRightCorner.contains( e->x(), e->y() ) ) + setCursor( KCursor::sizeFDiagCursor() ); + + else if ( m_topRightCorner.contains( e->x(), e->y() ) || + m_bottomLeftCorner.contains( e->x(), e->y() ) ) + setCursor( KCursor::sizeBDiagCursor() ); + else + unsetCursor(); + } +} + +} // NameSpace DigikamPerspectiveImagesPlugin + diff --git a/src/imageplugins/perspective/perspectivewidget.h b/src/imageplugins/perspective/perspectivewidget.h new file mode 100644 index 00000000..0047c3e8 --- /dev/null +++ b/src/imageplugins/perspective/perspectivewidget.h @@ -0,0 +1,172 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-18 + * Description : a widget class to edit perspective. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef PERSPECTIVEWIDGET_H +#define PERSPECTIVEWIDGET_H + +// TQt includes. + +#include <tqwidget.h> +#include <tqpoint.h> +#include <tqpointarray.h> +#include <tqcolor.h> +#include <tqrect.h> + +// Digikam includes. + +#include "dimg.h" + +// Local includes. + +#include "matrix.h" + +class TQPixmap; + +namespace Digikam +{ +class ImageIface; +} + +namespace DigikamPerspectiveImagesPlugin +{ + +class PerspectiveWidget : public TQWidget +{ +TQ_OBJECT + + +public: + + PerspectiveWidget(int width, int height, TQWidget *parent=0); + ~PerspectiveWidget(); + + TQRect getTargetSize(void); + TQPoint getTopLeftCorner(void); + TQPoint getTopRightCorner(void); + TQPoint getBottomLeftCorner(void); + TQPoint getBottomRightCorner(void); + void reset(void); + + float getAngleTopLeft(void); + float getAngleTopRight(void); + float getAngleBottomLeft(void); + float getAngleBottomRight(void); + + void applyPerspectiveAdjustment(void); + + Digikam::ImageIface* imageIface(); + +public slots: + + void slotToggleAntiAliasing(bool a); + void slotToggleDrawWhileMoving(bool draw); + void slotToggleDrawGrid(bool grid); + + void slotChangeGuideColor(const TQColor &color); + void slotChangeGuideSize(int size); + +signals: + + void signalPerspectiveChanged( TQRect newSize, float topLeftAngle, float topRightAngle, + float bottomLeftAngle, float bottomRightAngle ); + +protected: + + void paintEvent( TQPaintEvent *e ); + void resizeEvent( TQResizeEvent * e ); + void mousePressEvent ( TQMouseEvent * e ); + void mouseReleaseEvent ( TQMouseEvent * e ); + void mouseMoveEvent ( TQMouseEvent * e ); + +private: // Widget methods. + + void updatePixmap(void); + + void transformAffine(Digikam::DImg *orgImage, Digikam::DImg *destImage, + const Matrix &matrix, Digikam::DColor background); + + TQPoint buildPerspective(TQPoint orignTopLeft, TQPoint orignBottomRight, + TQPoint transTopLeft, TQPoint transTopRight, + TQPoint transBottomLeft, TQPoint transBottomRight, + Digikam::DImg *orgImage=0, Digikam::DImg *destImage=0, + Digikam::DColor background=Digikam::DColor()); + +private: + + enum ResizingMode + { + ResizingNone = 0, + ResizingTopLeft, + ResizingTopRight, + ResizingBottomLeft, + ResizingBottomRight + }; + + bool m_antiAlias; + bool m_drawWhileMoving; + bool m_drawGrid; + + uint *m_data; + int m_w; + int m_h; + int m_origW; + int m_origH; + + int m_currentResizing; + + int m_guideSize; + + TQRect m_rect; + + // Tranformed center area for mouse position control. + + TQPoint m_transformedCenter; + + // Draggable local region selection corners. + + TQRect m_topLeftCorner; + TQRect m_topRightCorner; + TQRect m_bottomLeftCorner; + TQRect m_bottomRightCorner; + + TQPoint m_topLeftPoint; + TQPoint m_topRightPoint; + TQPoint m_bottomLeftPoint; + TQPoint m_bottomRightPoint; + TQPoint m_spot; + + TQColor m_guideColor; + + // 60 points will be stored to compute a grid of 15x15 lines. + TQPointArray m_grid; + + TQPixmap *m_pixmap; + + Digikam::ImageIface *m_iface; + Digikam::DImg m_previewImage; +}; + +} // NameSpace DigikamPerspectiveImagesPlugin + +#endif /* PERSPECTIVEWIDGET_H */ diff --git a/src/imageplugins/perspective/triangle.cpp b/src/imageplugins/perspective/triangle.cpp new file mode 100644 index 00000000..84f80a07 --- /dev/null +++ b/src/imageplugins/perspective/triangle.cpp @@ -0,0 +1,65 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-18 + * Description : triangle geometry calculation class. + * + * Copyright (C) 2005-2007 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 <cstdio> +#include <cstdlib> +#include <cmath> + +// Local includes. + +#include "triangle.h" + +namespace DigikamPerspectiveImagesPlugin +{ + +Triangle::Triangle(TQPoint A, TQPoint B, TQPoint C) +{ + m_a = distanceP2P(B, C); + m_b = distanceP2P(A, C); + m_c = distanceP2P(A, B); +} + +float Triangle::angleABC(void) +{ + return( 57.295779513082 * acos( (m_b*m_b - m_a*m_a - m_c*m_c ) / (-2*m_a*m_c ) ) ); +} + +float Triangle::angleACB(void) +{ + return( 57.295779513082 * acos( (m_c*m_c - m_a*m_a - m_b*m_b ) / (-2*m_a*m_b ) ) ); +} + +float Triangle::angleBAC(void) +{ + return( 57.295779513082 * acos( (m_a*m_a - m_b*m_b - m_c*m_c ) / (-2*m_b*m_c ) ) ); +} + +float Triangle::distanceP2P(const TQPoint& p1, const TQPoint& p2) +{ + return(sqrt( abs( p2.x()-p1.x() ) * abs( p2.x()-p1.x() ) + + abs( p2.y()-p1.y() ) * abs( p2.y()-p1.y() ) )); +} + +} // NameSpace DigikamPerspectiveImagesPlugin diff --git a/src/imageplugins/perspective/triangle.h b/src/imageplugins/perspective/triangle.h new file mode 100644 index 00000000..27fcc087 --- /dev/null +++ b/src/imageplugins/perspective/triangle.h @@ -0,0 +1,57 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-18 + * Description : triangle geometry calculation class. + * + * Copyright (C) 2005-2007 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. + * + * ============================================================ */ + +#ifndef TRIANGLE_H +#define TRIANGLE_H + +// TQt includes. + +#include <tqpoint.h> + +namespace DigikamPerspectiveImagesPlugin +{ + +class Triangle +{ + +public: + + Triangle(TQPoint A, TQPoint B, TQPoint C); + ~Triangle(){}; + + float angleABC(void); + float angleACB(void); + float angleBAC(void); + +private: + + float m_a; + float m_b; + float m_c; + + float distanceP2P(const TQPoint& p1, const TQPoint& p2); +}; + +} // NameSpace DigikamPerspectiveImagesPlugin + +#endif /* TRIANGLE_H */ diff --git a/src/imageplugins/raindrop/Makefile.am b/src/imageplugins/raindrop/Makefile.am new file mode 100644 index 00000000..29899232 --- /dev/null +++ b/src/imageplugins/raindrop/Makefile.am @@ -0,0 +1,34 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_raindrop_la_SOURCES = imageplugin_raindrop.cpp \ + raindroptool.cpp raindrop.cpp + +digikamimageplugin_raindrop_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_raindrop_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_raindrop.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_raindrop.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_raindrop_ui.rc + diff --git a/src/imageplugins/raindrop/digikamimageplugin_raindrop.desktop b/src/imageplugins/raindrop/digikamimageplugin_raindrop.desktop new file mode 100644 index 00000000..847411b7 --- /dev/null +++ b/src/imageplugins/raindrop/digikamimageplugin_raindrop.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Name=ImagePlugin_RainDrop +Name[bg]=Приставка за снимки - Дъждовни капки +Name[da]=Billedplugin_Regndråber +Name[el]=ΠροσθετοΕικόνας_Βροχή +Name[fi]=Sadepisarat +Name[hr]=Kišne kapi +Name[it]=PluginImmagini_GocciaDiPioggia +Name[nl]=Afbeeldingsplugin_Regendruppels +Name[sr]=Кишне капи +Name[sr@Latn]=Kišne kapi +Name[sv]=Insticksprogram för regndroppar +Name[tr]=ResimEklentisi_YağmurDamlaları +Name[vi]=ImagePlugin_Perspective +Name[xx]=xxImagePlugin_RainDropxx +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=Rain dropping image effect plugin for digiKam +Comment[bg]=Приставка на digiKam за добавяне на дъждовни капки +Comment[ca]=Connector pel digiKam d'efecte d'imatge de gotes de pluja +Comment[da]=Plugin til regndråbeeffekt på billeder i Digikam +Comment[de]=digiKam-Modul zum Erzeugen eines Regentropfeneffektes +Comment[el]=Πρόσθετο εφέ πτώσης βροχής για το digiKam +Comment[es]=Plugin para digiKam de efectos de gotas de lluvia +Comment[et]=DigiKami vihmapiiskade pildiefektiplugin +Comment[fa]=وصلۀ جلوۀ تصویر بارش باران برای digiKam +Comment[fi]=Lisää kuvan pintaan sadepisaroita +Comment[gl]=Un plugin de digiKam para criar un efeito de pingas de chuvia +Comment[hr]=digiKam dodatak za efekt padanja kiše +Comment[is]=Íforrit fyrir digiKam sem setur inn regndropa!!! +Comment[it]=Plugin per l'effetto a goccia di pioggia delle immagini per digiKam +Comment[ja]=digiKam 雨滴効果プラグイン +Comment[ms]=Plugin kesan imej titis hujan untuk digiKam +Comment[nds]=digiKam-Moduul för Regendrüppeneffekten +Comment[nl]=Digikam-plugin voor regendruppels +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਕਣੀ ਚਿੱਤਰ ਪਰਭਾਵ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam dodająca efekt kropel deszczu na obrazie +Comment[pt]=Um 'plugin' do digiKam para criar um efeito de pingos de chuva +Comment[pt_BR]=Um 'plugin' do digiKam para criar um efeito de pingos de chuva +Comment[ru]=Модуль эффект "идущего дождя" для digiKam +Comment[sk]=digiKam plugin pre efekt padajúcich kvapiek +Comment[sr]=digiKam-ов прикључак за ефекат кишних капи у слици +Comment[sr@Latn]=digiKam-ov priključak za efekat kišnih kapi u slici +Comment[sv]=Digikam insticksprogram för regndroppsbildeffekt +Comment[tr]=digiKam için yağmur damlaları eklentisi +Comment[uk]=Втулок ефекту падання крапель для digiKam +Comment[vi]=Phần bổ sung hiệu ứng ảnh giọt mưa cho digiKam +Comment[xx]=xxRain dropping image effect plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_raindrop +author=Gilles Caulier, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/raindrop/digikamimageplugin_raindrop_ui.rc b/src/imageplugins/raindrop/digikamimageplugin_raindrop_ui.rc new file mode 100644 index 00000000..cf28a3f6 --- /dev/null +++ b/src/imageplugins/raindrop/digikamimageplugin_raindrop_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="5" name="digikamimageplugin_raindrop" > + + <MenuBar> + + <Menu name="Filters" ><text>F&ilters</text> + <Action name="imageplugin_raindrop" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action shortcut="" name="imageplugin_raindrop" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/raindrop/imageeffect_raindrop.cpp b/src/imageplugins/raindrop/imageeffect_raindrop.cpp new file mode 100644 index 00000000..8a82829d --- /dev/null +++ b/src/imageplugins/raindrop/imageeffect_raindrop.cpp @@ -0,0 +1,259 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-09-30 + * Description : a plugin to add rain drop over an image + * + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <tqlabel.h> +#include <tqwhatsthis.h> +#include <tqlayout.h> +#include <tqframe.h> +#include <tqimage.h> + +// KDE includes. + +#include <tdeconfig.h> +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <kstandarddirs.h> +#include <knuminput.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "raindrop.h" +#include "imageeffect_raindrop.h" +#include "imageeffect_raindrop.moc" + +namespace DigikamRainDropImagesPlugin +{ + +ImageEffect_RainDrop::ImageEffect_RainDrop(TQWidget* parent) + : Digikam::ImageGuideDlg(parent, i18n("Add Raindrops to Photograph"), + "raindrops", false, true, false, + Digikam::ImageGuideWidget::HVGuideMode) +{ + TQString whatsThis; + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Raindrops"), + digikam_version, + I18N_NOOP("A digiKam image plugin to add raindrops to an image."), + TDEAboutData::License_GPL, + "(c) 2004-2005, Gilles Caulier\n" + "(c) 2006-2008, Gilles Caulier and Marcel Wiesweg", + 0, + "http://www.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + about->addAuthor("Pieter Z. Voloshyn", I18N_NOOP("Raindrops algorithm"), + "pieter dot voloshyn at gmail dot com"); + + about->addAuthor("Marcel Wiesweg", I18N_NOOP("Developer"), + "marcel dot wiesweg at gmx dot de"); + + setAboutData(about); + + TQWhatsThis::add( m_imagePreviewWidget, i18n("<p>This is the preview of the Raindrop effect." + "<p>Note: if you have previously selected an area in the editor, " + "this will be unaffected by the filter. You can use this method to " + "disable the Raindrops effect on a human face, for example.") ); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(plainPage()); + TQGridLayout* gridSettings = new TQGridLayout( gboxSettings, 5, 2, spacingHint()); + + TQLabel *label1 = new TQLabel(i18n("Drop size:"), gboxSettings); + + m_dropInput = new KIntNumInput(gboxSettings); + m_dropInput->setRange(0, 200, 1, true); + m_dropInput->setValue(80); + TQWhatsThis::add( m_dropInput, i18n("<p>Set here the raindrops' size.")); + + gridSettings->addMultiCellWidget(label1, 0, 0, 0, 2); + gridSettings->addMultiCellWidget(m_dropInput, 1, 1, 0, 2); + + // ------------------------------------------------------------- + + TQLabel *label2 = new TQLabel(i18n("Number:"), gboxSettings); + + m_amountInput = new KIntNumInput(gboxSettings); + m_amountInput->setRange(1, 500, 1, true); + m_amountInput->setValue(150); + TQWhatsThis::add( m_amountInput, i18n("<p>This value controls the maximum number of raindrops.")); + + gridSettings->addMultiCellWidget(label2, 2, 2, 0, 2); + gridSettings->addMultiCellWidget(m_amountInput, 3, 3, 0, 2); + + // ------------------------------------------------------------- + + TQLabel *label3 = new TQLabel(i18n("Fish eyes:"), gboxSettings); + + m_coeffInput = new KIntNumInput(gboxSettings); + m_coeffInput->setRange(1, 100, 1, true); + m_coeffInput->setValue(30); + TQWhatsThis::add( m_coeffInput, i18n("<p>This value is the fish-eye-effect optical " + "distortion coefficient.")); + + gridSettings->addMultiCellWidget(label3, 4, 4, 0, 2); + gridSettings->addMultiCellWidget(m_coeffInput, 5, 5, 0, 2); + + setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + connect(m_dropInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_amountInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_coeffInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); +} + +ImageEffect_RainDrop::~ImageEffect_RainDrop() +{ +} + +void ImageEffect_RainDrop::renderingFinished() +{ + m_dropInput->setEnabled(true); + m_amountInput->setEnabled(true); + m_coeffInput->setEnabled(true); +} + +void ImageEffect_RainDrop::readUserSettings(void) +{ + TDEConfig *config = kapp->config(); + config->setGroup("raindrops Tool Dialog"); + + m_dropInput->blockSignals(true); + m_amountInput->blockSignals(true); + m_coeffInput->blockSignals(true); + + m_dropInput->setValue(config->readNumEntry("DropAdjustment", 80)); + m_amountInput->setValue(config->readNumEntry("AmountAdjustment", 150)); + m_coeffInput->setValue(config->readNumEntry("CoeffAdjustment", 30)); + + m_dropInput->blockSignals(false); + m_amountInput->blockSignals(false); + m_coeffInput->blockSignals(false); + + slotEffect(); +} + +void ImageEffect_RainDrop::writeUserSettings(void) +{ + TDEConfig *config = kapp->config(); + config->setGroup("raindrops Tool Dialog"); + config->writeEntry("DropAdjustment", m_dropInput->value()); + config->writeEntry("AmountAdjustment", m_amountInput->value()); + config->writeEntry("CoeffAdjustment", m_coeffInput->value()); + config->sync(); +} + +void ImageEffect_RainDrop::resetValues() +{ + m_dropInput->blockSignals(true); + m_amountInput->blockSignals(true); + m_coeffInput->blockSignals(true); + + m_dropInput->setValue(80); + m_amountInput->setValue(150); + m_coeffInput->setValue(30); + + m_dropInput->blockSignals(false); + m_amountInput->blockSignals(false); + m_coeffInput->blockSignals(false); +} + +void ImageEffect_RainDrop::prepareEffect() +{ + m_dropInput->setEnabled(false); + m_amountInput->setEnabled(false); + m_coeffInput->setEnabled(false); + + int d = m_dropInput->value(); + int a = m_amountInput->value(); + int c = m_coeffInput->value(); + + Digikam::ImageIface* iface = m_imagePreviewWidget->imageIface(); + + // Selected data from the image + TQRect selection( iface->selectedXOrg(), iface->selectedYOrg(), + iface->selectedWidth(), iface->selectedHeight() ); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new RainDrop(iface->getOriginalImg(), this, d, a, c, &selection)); +} + +void ImageEffect_RainDrop::prepareFinal() +{ + m_dropInput->setEnabled(false); + m_amountInput->setEnabled(false); + m_coeffInput->setEnabled(false); + + int d = m_dropInput->value(); + int a = m_amountInput->value(); + int c = m_coeffInput->value(); + + Digikam::ImageIface iface(0, 0); + + // Selected data from the image + TQRect selection( iface.selectedXOrg(), iface.selectedYOrg(), + iface.selectedWidth(), iface.selectedHeight() ); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new RainDrop(iface.getOriginalImg(), this, d, a, c, &selection)); +} + +void ImageEffect_RainDrop::putPreviewData(void) +{ + Digikam::ImageIface* iface = m_imagePreviewWidget->imageIface(); + + Digikam::DImg imDest = m_threadedFilter->getTargetImage() + .smoothScale(iface->previewWidth(), iface->previewHeight()); + iface->putPreviewImage(imDest.bits()); + + m_imagePreviewWidget->updatePreview(); +} + +void ImageEffect_RainDrop::putFinalData(void) +{ + Digikam::ImageIface iface(0, 0); + + iface.putOriginalImage(i18n("RainDrop"), + m_threadedFilter->getTargetImage().bits()); +} + +} // NameSpace DigikamRainDropImagesPlugin + diff --git a/src/imageplugins/raindrop/imageeffect_raindrop.h b/src/imageplugins/raindrop/imageeffect_raindrop.h new file mode 100644 index 00000000..fe567ba3 --- /dev/null +++ b/src/imageplugins/raindrop/imageeffect_raindrop.h @@ -0,0 +1,70 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-09-30 + * Description : a plugin to add rain drop over an image + * + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_RAINDROP_H +#define IMAGEEFFECT_RAINDROP_H + +// Digikam includes. + +#include "imageguidedlg.h" + +class KIntNumInput; + +namespace DigikamRainDropImagesPlugin +{ + +class ImageEffect_RainDrop : public Digikam::ImageGuideDlg +{ + TQ_OBJECT + + +public: + + ImageEffect_RainDrop(TQWidget *parent); + ~ImageEffect_RainDrop(); + +private slots: + + void readUserSettings(); + +private: + + void writeUserSettings(); + void resetValues(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + KIntNumInput *m_dropInput; + KIntNumInput *m_amountInput; + KIntNumInput *m_coeffInput; +}; + +} // NameSpace DigikamRainDropImagesPlugin + +#endif /* IMAGEEFFECT_RAINDROP_H */ diff --git a/src/imageplugins/raindrop/imageplugin_raindrop.cpp b/src/imageplugins/raindrop/imageplugin_raindrop.cpp new file mode 100644 index 00000000..20744961 --- /dev/null +++ b/src/imageplugins/raindrop/imageplugin_raindrop.cpp @@ -0,0 +1,69 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-09-30 + * Description : a plugin to add rain drop over an image + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> + +// Local includes. + +#include "ddebug.h" +#include "raindroptool.h" +#include "imageplugin_raindrop.h" +#include "imageplugin_raindrop.moc" + +using namespace DigikamRainDropImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_raindrop, + KGenericFactory<ImagePlugin_RainDrop>("digikamimageplugin_raindrop")); + +ImagePlugin_RainDrop::ImagePlugin_RainDrop(TQObject *parent, const char*, const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_RainDrop") +{ + m_raindropAction = new TDEAction(i18n("Raindrops..."), "raindrop", 0, + this, TQ_SLOT(slotRainDrop()), + actionCollection(), "imageplugin_raindrop"); + + setXMLFile( "digikamimageplugin_raindrop_ui.rc" ); + + DDebug() << "ImagePlugin_RainDrop plugin loaded" << endl; +} + +ImagePlugin_RainDrop::~ImagePlugin_RainDrop() +{ +} + +void ImagePlugin_RainDrop::setEnabledActions(bool enable) +{ + m_raindropAction->setEnabled(enable); +} + +void ImagePlugin_RainDrop::slotRainDrop() +{ + RainDropTool *raindrop = new RainDropTool(this); + loadTool(raindrop); +} diff --git a/src/imageplugins/raindrop/imageplugin_raindrop.h b/src/imageplugins/raindrop/imageplugin_raindrop.h new file mode 100644 index 00000000..a85076f8 --- /dev/null +++ b/src/imageplugins/raindrop/imageplugin_raindrop.h @@ -0,0 +1,56 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-09-30 + * Description : a plugin to add rain drop over an image + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_RAINDROP_H +#define IMAGEPLUGIN_RAINDROP_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_RainDrop : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_RainDrop(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_RainDrop(); + + void setEnabledActions(bool enable); + +private slots: + + void slotRainDrop(); + +private: + + TDEAction *m_raindropAction; +}; + +#endif /* IMAGEPLUGIN_RAINDROP_H */ diff --git a/src/imageplugins/raindrop/raindrop.cpp b/src/imageplugins/raindrop/raindrop.cpp new file mode 100644 index 00000000..7be977fc --- /dev/null +++ b/src/imageplugins/raindrop/raindrop.cpp @@ -0,0 +1,457 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : Raindrop threaded image filter. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * Original RainDrop algorithm copyrighted 2004-2005 by + * Pieter Z. Voloshyn <pieter dot voloshyn 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> +#include <cstdlib> + +// TQt includes. + +#include <tqdeepcopy.h> +#include <tqdatetime.h> +#include <tqrect.h> + +// Local includes. + +#include "dimg.h" +#include "dimgimagefilters.h" +#include "raindrop.h" + +namespace DigikamRainDropImagesPlugin +{ + +RainDrop::RainDrop(Digikam::DImg *orgImage, TQObject *parent, int drop, + int amount, int coeff, TQRect *selection) + : Digikam::DImgThreadedFilter(orgImage, parent, "RainDrop") +{ + m_drop = drop; + m_amount = amount; + m_coeff = coeff; + + m_selectedX = m_selectedY = m_selectedW = m_selectedH = 0; + + if ( selection ) + { + m_selectedX = selection->left(); + m_selectedY = selection->top(); + m_selectedW = selection->width(); + m_selectedH = selection->height(); + } + + initFilter(); +} + +void RainDrop::filterImage(void) +{ + int w = m_orgImage.width(); + int h = m_orgImage.height(); + + // If we have a region selection in image, use it to apply the filter modification around, + // else, applied the filter on the full image. + + if (m_selectedW && m_selectedH) + { + Digikam::DImg zone1, zone2, zone3, zone4, + zone1Dest, zone2Dest, zone3Dest, zone4Dest, + selectedImg; + selectedImg = m_orgImage.copy(m_selectedX, m_selectedY, m_selectedW, m_selectedH); + + // Cut the original image in 4 areas without clipping region. + + zone1 = m_orgImage.copy(0, 0, m_selectedX, w); + zone2 = m_orgImage.copy(m_selectedX, 0, m_selectedX + m_selectedW, m_selectedY); + zone3 = m_orgImage.copy(m_selectedX, m_selectedY + m_selectedH, m_selectedX + m_selectedW, h); + zone4 = m_orgImage.copy(m_selectedX + m_selectedW, 0, w, h); + + zone1Dest = Digikam::DImg(zone1.width(), zone1.height(), zone1.sixteenBit(), zone1.hasAlpha()); + zone2Dest = Digikam::DImg(zone2.width(), zone2.height(), zone2.sixteenBit(), zone2.hasAlpha()); + zone3Dest = Digikam::DImg(zone3.width(), zone3.height(), zone3.sixteenBit(), zone3.hasAlpha()); + zone4Dest = Digikam::DImg(zone4.width(), zone4.height(), zone4.sixteenBit(), zone4.hasAlpha()); + + // Apply effect on each area. + + rainDropsImage(&zone1, &zone1Dest, 0, m_drop, m_amount, m_coeff, true, 0, 25); + rainDropsImage(&zone2, &zone2Dest, 0, m_drop, m_amount, m_coeff, true, 25, 50); + rainDropsImage(&zone3, &zone3Dest, 0, m_drop, m_amount, m_coeff, true, 50, 75); + rainDropsImage(&zone4, &zone4Dest, 0, m_drop, m_amount, m_coeff, true, 75, 100); + + // Build the target image. + + m_destImage.bitBltImage(&zone1Dest, 0, 0); + m_destImage.bitBltImage(&zone2Dest, m_selectedX, 0); + m_destImage.bitBltImage(&zone3Dest, m_selectedX, m_selectedY + m_selectedH); + m_destImage.bitBltImage(&zone4Dest, m_selectedX + m_selectedW, 0); + m_destImage.bitBltImage(&selectedImg, m_selectedX, m_selectedY); + } + else + { + rainDropsImage(&m_orgImage, &m_destImage, 0, m_drop, m_amount, m_coeff, true, 0, 100); + } +} + +/* Function to apply the RainDrops effect backported from ImageProcessing version 2 + * + * orgImage => The image + * MinDropSize => It's the minimum random size for rain drop. + * MaxDropSize => It's the minimum random size for rain drop. + * Amount => It's the maximum number for rain drops inside the image. + * Coeff => It's the fisheye's coefficient. + * bLimitRange => If true, the drop will not be cut. + * progressMin => Min. value for progress bar (can be different if using clipping area). + * progressMax => Max. value for progress bar (can be different if using clipping area). + * + * Theory => This functions does several math's functions and the engine + * is simple to undestand, but a little hard to implement. A + * control will indicate if there is or not a raindrop in that + * area, if not, a fisheye effect with a random size (max=MaxDropSize) + * will be applied, after this, a shadow will be applied too. + * and after this, a blur function will finish the effect. + */ +void RainDrop::rainDropsImage(Digikam::DImg *orgImage, Digikam::DImg *destImage, int MinDropSize, int MaxDropSize, + int Amount, int Coeff, bool bLimitRange, int progressMin, int progressMax) +{ + bool bResp; + int nRandSize, i; + int nRandX, nRandY; + int nCounter = 0; + int nWidth = orgImage->width(); + int nHeight = orgImage->height(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar *data = orgImage->bits(); + uchar *pResBits = destImage->bits(); + + if (Amount <= 0) + return; + + if (MinDropSize >= MaxDropSize) + MaxDropSize = MinDropSize + 1; + + if (MaxDropSize <= 0) + return; + + uchar *pStatusBits = new uchar[nHeight * nWidth]; + memset(pStatusBits, 0, sizeof(nHeight * nWidth)); + + // Initially, copy all pixels to destination + + destImage->bitBltImage(orgImage, 0, 0); + + // Randomize. + + TQDateTime dt = TQDateTime::currentDateTime(); + TQDateTime Y2000( TQDate(2000, 1, 1), TQTime(0, 0, 0) ); + uint seed = dt.secsTo(Y2000); + + for (i = 0; !m_cancel && (i < Amount); i++) + { + nCounter = 0; + + do + { + nRandX = (int)(rand_r(&seed) * ((double)( nWidth - 1) / RAND_MAX)); + nRandY = (int)(rand_r(&seed) * ((double)(nHeight - 1) / RAND_MAX)); + + nRandSize = (rand() % (MaxDropSize - MinDropSize)) + MinDropSize; + + bResp = CreateRainDrop (data, nWidth, nHeight, sixteenBit, bytesDepth, + pResBits, pStatusBits, + nRandX, nRandY, nRandSize, Coeff, bLimitRange); + + nCounter++; + } + while ((bResp == false) && (nCounter < 10000) && !m_cancel); + + // Update the progress bar in dialog. + if (nCounter >= 10000) + { + i = Amount; + + postProgress(progressMax); + break; + } + + postProgress( (int)(progressMin + ((double)(i) * + (double)(progressMax-progressMin)) / (double)Amount) ); + } + + delete [] pStatusBits; +} + +bool RainDrop::CreateRainDrop(uchar *pBits, int Width, int Height, bool sixteenBit, int bytesDepth, + uchar *pResBits, uchar* pStatusBits, + int X, int Y, int DropSize, double Coeff, bool bLimitRange) +{ + int w, h, nw1, nh1, nw2, nh2; + int nHalfSize = DropSize / 2; + int nBright; + double lfRadius, lfOldRadius, lfAngle, lfDiv; + + Digikam::DColor imageData; + + uint nTotalR, nTotalG, nTotalB, offset; + int nBlurPixels, nBlurRadius; + + if (CanBeDropped(Width, Height, pStatusBits, X, Y, DropSize, bLimitRange)) + { + Coeff *= 0.01; + lfDiv = (double)nHalfSize / log (Coeff * (double)nHalfSize + 1.0); + + for (h = -nHalfSize; !m_cancel && (h <= nHalfSize); h++) + { + for (w = -nHalfSize; !m_cancel && (w <= nHalfSize); w++) + { + lfRadius = sqrt (h * h + w * w); + lfAngle = atan2 ((double)h, (double)w); + + if (lfRadius <= (double)nHalfSize) + { + lfOldRadius = lfRadius; + lfRadius = (exp (lfRadius / lfDiv) - 1.0) / Coeff; + + nw1 = (int)((double)X + lfRadius * cos (lfAngle)); + nh1 = (int)((double)Y + lfRadius * sin (lfAngle)); + + nw2 = X + w; + nh2 = Y + h; + + if (IsInside(Width, Height, nw1, nh1)) + { + if (IsInside(Width, Height, nw2, nh2)) + { + nBright = 0; + + if (lfOldRadius >= 0.9 * (double)nHalfSize) + { + if ((lfAngle >= 0.0) && (lfAngle < 2.25)) + nBright = -80; + else if ((lfAngle >= 2.25) && (lfAngle < 2.5)) + nBright = -40; + else if ((lfAngle >= -0.25) && (lfAngle < 0.0)) + nBright = -40; + } + + else if (lfOldRadius >= 0.8 * (double)nHalfSize) + { + if ((lfAngle >= 0.75) && (lfAngle < 1.50)) + nBright = -40; + else if ((lfAngle >= -0.10) && (lfAngle < 0.75)) + nBright = -30; + else if ((lfAngle >= 1.50) && (lfAngle < 2.35)) + nBright = -30; + } + + else if (lfOldRadius >= 0.7 * (double)nHalfSize) + { + if ((lfAngle >= 0.10) && (lfAngle < 2.0)) + nBright = -20; + else if ((lfAngle >= -2.50) && (lfAngle < -1.90)) + nBright = 60; + } + + else if (lfOldRadius >= 0.6 * (double)nHalfSize) + { + if ((lfAngle >= 0.50) && (lfAngle < 1.75)) + nBright = -20; + else if ((lfAngle >= 0.0) && (lfAngle < 0.25)) + nBright = 20; + else if ((lfAngle >= 2.0) && (lfAngle < 2.25)) + nBright = 20; + } + + else if (lfOldRadius >= 0.5 * (double)nHalfSize) + { + if ((lfAngle >= 0.25) && (lfAngle < 0.50)) + nBright = 30; + else if ((lfAngle >= 1.75 ) && (lfAngle < 2.0)) + nBright = 30; + } + + else if (lfOldRadius >= 0.4 * (double)nHalfSize) + { + if ((lfAngle >= 0.5) && (lfAngle < 1.75)) + nBright = 40; + } + + else if (lfOldRadius >= 0.3 * (double)nHalfSize) + { + if ((lfAngle >= 0.0) && (lfAngle < 2.25)) + nBright = 30; + } + + else if (lfOldRadius >= 0.2 * (double)nHalfSize) + { + if ((lfAngle >= 0.5) && (lfAngle < 1.75)) + nBright = 20; + } + + imageData.setColor(pBits + Offset(Width, nw1, nh1, bytesDepth), sixteenBit); + + if (sixteenBit) + { + // convert difference to 16-bit range + if (nBright > 0) + nBright = (nBright + 1) * 256 - 1; + else + nBright = (nBright - 1) * 256 + 1; + + imageData.setRed (LimitValues16(imageData.red() + nBright)); + imageData.setGreen(LimitValues16(imageData.green() + nBright)); + imageData.setBlue (LimitValues16(imageData.blue() + nBright)); + } + else + { + imageData.setRed (LimitValues8(imageData.red() + nBright)); + imageData.setGreen(LimitValues8(imageData.green() + nBright)); + imageData.setBlue (LimitValues8(imageData.blue() + nBright)); + } + + imageData.setPixel(pResBits + Offset(Width, nw2, nh2, bytesDepth)); + + } + } + } + } + } + + nBlurRadius = DropSize / 25 + 1; + + for (h = -nHalfSize - nBlurRadius; !m_cancel && (h <= nHalfSize + nBlurRadius); h++) + { + for (w = -nHalfSize - nBlurRadius; !m_cancel && (w <= nHalfSize + nBlurRadius); w++) + { + lfRadius = sqrt (h * h + w * w); + + if (lfRadius <= (double)nHalfSize * 1.1) + { + nTotalR = nTotalG = nTotalB = 0; + nBlurPixels = 0; + + for (nh1 = -nBlurRadius; !m_cancel && (nh1 <= nBlurRadius); nh1++) + { + for (nw1 = -nBlurRadius; !m_cancel && (nw1 <= nBlurRadius); nw1++) + { + nw2 = X + w + nw1; + nh2 = Y + h + nh1; + + if (IsInside (Width, Height, nw2, nh2)) + { + imageData.setColor(pResBits + Offset(Width, nw2, nh2, bytesDepth), sixteenBit); + + nTotalR += imageData.red(); + nTotalG += imageData.green(); + nTotalB += imageData.blue(); + nBlurPixels++; + } + } + } + + nw1 = X + w; + nh1 = Y + h; + + if (IsInside (Width, Height, nw1, nh1)) + { + offset = Offset(Width, nw1, nh1, bytesDepth); + + // to preserve alpha channel + imageData.setColor(pResBits + offset, sixteenBit); + + imageData.setRed (nTotalR / nBlurPixels); + imageData.setGreen(nTotalG / nBlurPixels); + imageData.setBlue (nTotalB / nBlurPixels); + + imageData.setPixel(pResBits + offset); + } + } + } + } + + SetDropStatusBits (Width, Height, pStatusBits, X, Y, DropSize); + } + else + return (false); + + return (true); +} + + +bool RainDrop::CanBeDropped(int Width, int Height, uchar *pStatusBits, int X, int Y, + int DropSize, bool bLimitRange) +{ + int w, h, i = 0; + int nHalfSize = DropSize / 2; + + if (pStatusBits == NULL) + return (true); + + for (h = Y - nHalfSize; h <= Y + nHalfSize; h++) + { + for (w = X - nHalfSize; w <= X + nHalfSize; w++) + { + if (IsInside (Width, Height, w, h)) + { + i = h * Width + w; + if (pStatusBits[i]) + return (false); + } + else + { + if (bLimitRange) + return (false); + } + } + } + + return (true); +} + +bool RainDrop::SetDropStatusBits (int Width, int Height, uchar *pStatusBits, + int X, int Y, int DropSize) +{ + int w, h, i = 0; + int nHalfSize = DropSize / 2; + + if (pStatusBits == NULL) + return (false); + + for (h = Y - nHalfSize; h <= Y + nHalfSize; h++) + { + for (w = X - nHalfSize; w <= X + nHalfSize; w++) + { + if (IsInside (Width, Height, w, h)) + { + i = h * Width + w; + pStatusBits[i] = 255; + } + } + } + + return (true); +} + +} // NameSpace DigikamRainDropImagesPlugin diff --git a/src/imageplugins/raindrop/raindrop.h b/src/imageplugins/raindrop/raindrop.h new file mode 100644 index 00000000..9baca0d1 --- /dev/null +++ b/src/imageplugins/raindrop/raindrop.h @@ -0,0 +1,105 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : Raindrop threaded image filter. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef RAINDROP_H +#define RAINDROP_H + +// Digikam includes. + +#include "dimgthreadedfilter.h" + +class TQRect; + +namespace DigikamRainDropImagesPlugin +{ + +class RainDrop : public Digikam::DImgThreadedFilter +{ + +public: + + RainDrop(Digikam::DImg *orgImage, TQObject *parent=0, int drop=80, + int amount=150, int coeff=30, TQRect *selection=0L); + + ~RainDrop(){}; + +private: + + virtual void filterImage(void); + + void rainDropsImage(Digikam::DImg *orgImage, Digikam::DImg *destImage, int MinDropSize, int MaxDropSize, + int Amount, int Coeff, bool bLimitRange, int progressMin, int progressMax); + + bool CreateRainDrop(uchar *pBits, int Width, int Height, bool sixteenBit, int bytesDepth, + uchar *pResBits, uchar* pStatusBits, + int X, int Y, int DropSize, double Coeff, bool bLimitRange); + + bool CanBeDropped(int Width, int Height, uchar *pStatusBits, int X, int Y, int DropSize, bool bLimitRange); + + bool SetDropStatusBits (int Width, int Height, uchar *pStatusBits, int X, int Y, int DropSize); + + // A color is represented in RGB value (e.g. 0xFFFFFF is white color). + // But R, G and B values has 256 values to be used so, this function analize + // the value and limits to this range. + inline int LimitValues8(int ColorValue) + { + if (ColorValue > 255) ColorValue = 255; + if (ColorValue < 0) ColorValue = 0; + return ColorValue; + }; + + inline int LimitValues16(int ColorValue) + { + if (ColorValue > 65535) ColorValue = 65535; + if (ColorValue < 0) ColorValue = 0; + return ColorValue; + }; + + inline bool IsInside (int Width, int Height, int X, int Y) + { + bool bIsWOk = ((X < 0) ? false : (X >= Width ) ? false : true); + bool bIsHOk = ((Y < 0) ? false : (Y >= Height) ? false : true); + return (bIsWOk && bIsHOk); + }; + + inline int Offset(int Width, int X, int Y, int bytesDepth) + { + return (Y * Width * bytesDepth + X * bytesDepth); + }; + +private: + + int m_drop; + int m_amount; + int m_coeff; + + int m_selectedX; + int m_selectedY; + int m_selectedW; + int m_selectedH; +}; + +} // NameSpace DigikamRainDropImagesPlugin + +#endif /* RAINDROP_H */ diff --git a/src/imageplugins/raindrop/raindroptool.cpp b/src/imageplugins/raindrop/raindroptool.cpp new file mode 100644 index 00000000..3d19238d --- /dev/null +++ b/src/imageplugins/raindrop/raindroptool.cpp @@ -0,0 +1,254 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-09-30 + * Description : a plugin to add rain drop over an image + * + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <tqframe.h> +#include <tqimage.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <kstandarddirs.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "editortoolsettings.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "raindrop.h" +#include "raindroptool.h" +#include "raindroptool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamRainDropImagesPlugin +{ + +RainDropTool::RainDropTool(TQObject* parent) + : EditorToolThreaded(parent) +{ + setName("raindrops"); + setToolName(i18n("Raindrops")); + setToolIcon(SmallIcon("raindrop")); + + m_previewWidget = new ImageWidget("raindrops Tool", 0, + i18n("<p>This is the preview of the Raindrop effect." + "<p>Note: if you have previously selected an area in the editor, " + "this will be unaffected by the filter. You can use this method to " + "disable the Raindrops effect on a human face, for example."), + false); + + setToolView(m_previewWidget); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel); + + TQGridLayout* gridSettings = new TQGridLayout( m_gboxSettings->plainPage(), 7, 2); + + TQLabel *label1 = new TQLabel(i18n("Drop size:"), m_gboxSettings->plainPage()); + + m_dropInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_dropInput->setRange(0, 200, 1); + m_dropInput->setDefaultValue(80); + TQWhatsThis::add( m_dropInput, i18n("<p>Set here the raindrops' size.")); + + // ------------------------------------------------------------- + + TQLabel *label2 = new TQLabel(i18n("Number:"), m_gboxSettings->plainPage()); + + m_amountInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_amountInput->setRange(1, 500, 1); + m_amountInput->setDefaultValue(150); + TQWhatsThis::add( m_amountInput, i18n("<p>This value controls the maximum number of raindrops.")); + + // ------------------------------------------------------------- + + TQLabel *label3 = new TQLabel(i18n("Fish eyes:"), m_gboxSettings->plainPage()); + + m_coeffInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_coeffInput->setRange(1, 100, 1); + m_coeffInput->setDefaultValue(30); + TQWhatsThis::add( m_coeffInput, i18n("<p>This value is the fish-eye-effect optical " + "distortion coefficient.")); + + gridSettings->addMultiCellWidget(label1, 0, 0, 0, 1); + gridSettings->addMultiCellWidget(m_dropInput, 1, 1, 0, 1); + gridSettings->addMultiCellWidget(label2, 2, 2, 0, 1); + gridSettings->addMultiCellWidget(m_amountInput, 3, 3, 0, 1); + gridSettings->addMultiCellWidget(label3, 4, 4, 0, 1); + gridSettings->addMultiCellWidget(m_coeffInput, 5, 5, 0, 1); + gridSettings->setRowStretch(6, 10); + + setToolSettings(m_gboxSettings); + init(); + + // ------------------------------------------------------------- + + connect(m_dropInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_amountInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_coeffInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); +} + +RainDropTool::~RainDropTool() +{ +} + +void RainDropTool::renderingFinished() +{ + m_dropInput->setEnabled(true); + m_amountInput->setEnabled(true); + m_coeffInput->setEnabled(true); +} + +void RainDropTool::readSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("raindrops Tool"); + + m_dropInput->blockSignals(true); + m_amountInput->blockSignals(true); + m_coeffInput->blockSignals(true); + + m_dropInput->setValue(config->readNumEntry("DropAdjustment", m_dropInput->defaultValue())); + m_amountInput->setValue(config->readNumEntry("AmountAdjustment", m_amountInput->defaultValue())); + m_coeffInput->setValue(config->readNumEntry("CoeffAdjustment", m_coeffInput->defaultValue())); + + m_dropInput->blockSignals(false); + m_amountInput->blockSignals(false); + m_coeffInput->blockSignals(false); + + slotEffect(); +} + +void RainDropTool::writeSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("raindrops Tool"); + config->writeEntry("DropAdjustment", m_dropInput->value()); + config->writeEntry("AmountAdjustment", m_amountInput->value()); + config->writeEntry("CoeffAdjustment", m_coeffInput->value()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void RainDropTool::slotResetSettings() +{ + m_dropInput->blockSignals(true); + m_amountInput->blockSignals(true); + m_coeffInput->blockSignals(true); + + m_dropInput->slotReset(); + m_amountInput->slotReset(); + m_coeffInput->slotReset(); + + m_dropInput->blockSignals(false); + m_amountInput->blockSignals(false); + m_coeffInput->blockSignals(false); + + slotEffect(); +} + +void RainDropTool::prepareEffect() +{ + m_dropInput->setEnabled(false); + m_amountInput->setEnabled(false); + m_coeffInput->setEnabled(false); + + int d = m_dropInput->value(); + int a = m_amountInput->value(); + int c = m_coeffInput->value(); + + ImageIface* iface = m_previewWidget->imageIface(); + + // Selected data from the image + TQRect selection(iface->selectedXOrg(), iface->selectedYOrg(), + iface->selectedWidth(), iface->selectedHeight()); + + setFilter(dynamic_cast<DImgThreadedFilter *> + (new RainDrop(iface->getOriginalImg(), this, d, a, c, &selection))); +} + +void RainDropTool::prepareFinal() +{ + m_dropInput->setEnabled(false); + m_amountInput->setEnabled(false); + m_coeffInput->setEnabled(false); + + int d = m_dropInput->value(); + int a = m_amountInput->value(); + int c = m_coeffInput->value(); + + ImageIface iface(0, 0); + + // Selected data from the image + TQRect selection(iface.selectedXOrg(), iface.selectedYOrg(), + iface.selectedWidth(), iface.selectedHeight()); + + setFilter(dynamic_cast<DImgThreadedFilter *> + (new RainDrop(iface.getOriginalImg(), this, d, a, c, &selection))); +} + +void RainDropTool::putPreviewData(void) +{ + ImageIface* iface = m_previewWidget->imageIface(); + + DImg imDest = filter()->getTargetImage() + .smoothScale(iface->previewWidth(), iface->previewHeight()); + iface->putPreviewImage(imDest.bits()); + + m_previewWidget->updatePreview(); +} + +void RainDropTool::putFinalData(void) +{ + ImageIface iface(0, 0); + + iface.putOriginalImage(i18n("RainDrop"), filter()->getTargetImage().bits()); +} + +} // NameSpace DigikamRainDropImagesPlugin + diff --git a/src/imageplugins/raindrop/raindroptool.h b/src/imageplugins/raindrop/raindroptool.h new file mode 100644 index 00000000..d083eb9c --- /dev/null +++ b/src/imageplugins/raindrop/raindroptool.h @@ -0,0 +1,82 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-09-30 + * Description : a plugin to add rain drop over an image + * + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef RAINDROPTOOL_H +#define RAINDROPTOOL_H + +// Digikam includes. + +#include "editortool.h" + +namespace KDcrawIface +{ +class RIntNumInput; +} + +namespace Digikam +{ +class ImageWidget; +} + +namespace DigikamRainDropImagesPlugin +{ + +class RainDropTool : public Digikam::EditorToolThreaded +{ + TQ_OBJECT + + +public: + + RainDropTool(TQObject *parent); + ~RainDropTool(); + +private slots: + + void slotResetSettings(); + +private: + + void readSettings(); + void writeSettings(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + KDcrawIface::RIntNumInput *m_dropInput; + KDcrawIface::RIntNumInput *m_amountInput; + KDcrawIface::RIntNumInput *m_coeffInput; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamRainDropImagesPlugin + +#endif /* RAINDROPTOOL_H */ diff --git a/src/imageplugins/restoration/Makefile.am b/src/imageplugins/restoration/Makefile.am new file mode 100644 index 00000000..695609be --- /dev/null +++ b/src/imageplugins/restoration/Makefile.am @@ -0,0 +1,35 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + -I$(top_srcdir)/src/libs/greycstoration \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_restoration_la_SOURCES = imageplugin_restoration.cpp \ + restorationtool.cpp + +digikamimageplugin_restoration_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_restoration_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -no-undefined -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_restoration.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_restoration.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_restoration_ui.rc + diff --git a/src/imageplugins/restoration/digikamimageplugin_restoration.desktop b/src/imageplugins/restoration/digikamimageplugin_restoration.desktop new file mode 100644 index 00000000..8d0e7bd8 --- /dev/null +++ b/src/imageplugins/restoration/digikamimageplugin_restoration.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Name=ImagePlugin_Restoration +Name[bg]=Приставка за снимки - Възстановяване +Name[da]=Plugin for billedrestaurering +Name[el]=ΠρόσθετοΕικόνας_Αποκατάσταση +Name[fi]=Restaurointi +Name[hr]=Obnavljanje +Name[it]=PluginImmagini_Restauro +Name[ms]=ImagePlugin_Pemulihan +Name[nl]=Afbeeldingsplugin_Restauratie +Name[sr]=Рестаурација +Name[sr@Latn]=Restauracija +Name[sv]=Insticksprogram för bildrestaurering +Name[tr]=ResimEklentisi_Onarım +Name[xx]=xxImagePlugin_Restorationxx + +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=digiKam plugin to restore a photograph +Comment[bg]=Приставка на digiKam за възстановяване на снимки +Comment[ca]=Connector pel digiKam per restaurar una fotografia +Comment[da]=Digikam plugin til restaurering af et fotografi +Comment[de]=digiKam-Modul zum Restaurieren eines Bildes +Comment[el]=Πρόσθετο του digiKam για αποκατάσταση μιας φωτογραφίας +Comment[es]=Plugin para digiKam para restaurar una fotografía +Comment[et]=DigiKami foto restaureerimimise plugin +Comment[fa]=وصلۀ digiKam برای ذخیرۀ یک عکس +Comment[fi]=Korjaa kuvassa esiintyviä virheitä +Comment[gl]=Un plugin de digiKam para restaurar unha fotografia +Comment[hr]=digiKam dodatak za obnavljanje fotografije +Comment[is]=Íforrit fyrir digiKam sem fjarlægir óhreinindi úr myndum +Comment[it]=Plugin di digiKam per restaurare una fotografia +Comment[ja]=digiKam 写真復元プラグイン +Comment[nds]=digiKam-Moduul för't Wedderherstellen vun Fotos +Comment[nl]=Digikam-plugin voor het herstellen van een foto +Comment[pa]=ਇੱਕ ਫੋਟੋ ਮੁੜ-ਸਟੋਰ ਕਰਨ ਲਈ ਡਿਜ਼ੀਕੈਮ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam umożliwiająca odrestaurowanie zdjęcia +Comment[pt]=Um 'plugin' do digiKam para restaurar uma fotografia +Comment[pt_BR]=Plugin digiKam para restaurar una fotografia +Comment[ru]=Модуль digiKam для восстановления фотографий +Comment[sk]=digiKam plugin pre obnovenie fotografie +Comment[sr]=digiKam-ов прикључак за поправку фотографија +Comment[sr@Latn]=digiKam-ov priključak za popravku fotografija +Comment[sv]=Digikam insticksprogram för restaurering av ett fotografi +Comment[tr]=Fotoğraf onarmak için digiKam eklentisi +Comment[uk]=Втулок відновлення фотографій для digiKam +Comment[vi]=Phần bổ sung xây dựng lại ảnh chụp như cũ cho digiKam +Comment[xx]=xxdigiKam plugin to restore a photographxx + +X-TDE-Library=digikamimageplugin_restoration +author=Gilles Caulier, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/restoration/digikamimageplugin_restoration_ui.rc b/src/imageplugins/restoration/digikamimageplugin_restoration_ui.rc new file mode 100644 index 00000000..27185294 --- /dev/null +++ b/src/imageplugins/restoration/digikamimageplugin_restoration_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="5" name="digikamimageplugin_restoration" > + + <MenuBar> + + <Menu name="Enhance" ><text>Enh&ance</text> + <Action name="imageplugin_restoration" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action shortcut="" name="imageplugin_restoration" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/restoration/imageeffect_restoration.cpp b/src/imageplugins/restoration/imageeffect_restoration.cpp new file mode 100644 index 00000000..825ef23d --- /dev/null +++ b/src/imageplugins/restoration/imageeffect_restoration.cpp @@ -0,0 +1,349 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-26 + * Description : a digiKam image editor plugin to restore + * a photograph + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqlabel.h> +#include <tqtooltip.h> +#include <tqwhatsthis.h> +#include <tqlayout.h> +#include <tqcombobox.h> +#include <tqtabwidget.h> +#include <tqfile.h> +#include <tqimage.h> + +// KDE includes. + +#include <kurllabel.h> +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <tdefiledialog.h> +#include <tdeglobalsettings.h> +#include <kstandarddirs.h> +#include <tdemessagebox.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "imageiface.h" +#include "greycstorationsettings.h" +#include "greycstorationwidget.h" +#include "greycstorationiface.h" +#include "imageeffect_restoration.h" +#include "imageeffect_restoration.moc" + +namespace DigikamRestorationImagesPlugin +{ + +ImageEffect_Restoration::ImageEffect_Restoration(TQWidget* parent) + : Digikam::CtrlPanelDlg(parent, i18n("Photograph Restoration"), + "restoration", true, true, true, + Digikam::ImagePannelWidget::SeparateViewAll) +{ + TQString whatsThis; + + // About data and help button. + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Photograph Restoration"), + digikam_version, + I18N_NOOP("A digiKam image plugin to restore a photograph."), + TDEAboutData::License_GPL, + "(c) 2005-2008, Gilles Caulier", + 0, + "http://www.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + about->addAuthor("David Tschumperle", I18N_NOOP("CImg library"), 0, + "http://cimg.sourceforge.net"); + + about->addAuthor("Gerhard Kulzer", I18N_NOOP("Feedback and plugin polishing"), + "gerhard at kulzer.net"); + + setAboutData(about); + + // ------------------------------------------------------------- + + m_mainTab = new TQTabWidget( m_imagePreviewWidget ); + + TQWidget* firstPage = new TQWidget( m_mainTab ); + TQGridLayout* grid = new TQGridLayout( firstPage, 2, 2, spacingHint()); + m_mainTab->addTab( firstPage, i18n("Preset") ); + + KURLLabel *cimgLogoLabel = new KURLLabel(firstPage); + cimgLogoLabel->setText(TQString()); + 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"); + cimgLogoLabel->setPixmap( TQPixmap( directory + "logo-cimg.png" ) ); + TQToolTip::add(cimgLogoLabel, i18n("Visit CImg library website")); + + TQLabel *typeLabel = new TQLabel(i18n("Filtering type:"), firstPage); + typeLabel->setAlignment ( TQt::AlignRight | TQt::AlignVCenter); + m_restorationTypeCB = new TQComboBox( false, firstPage ); + m_restorationTypeCB->insertItem( i18n("None") ); + m_restorationTypeCB->insertItem( i18n("Reduce Uniform Noise") ); + m_restorationTypeCB->insertItem( i18n("Reduce JPEG Artefacts") ); + m_restorationTypeCB->insertItem( i18n("Reduce Texturing") ); + TQWhatsThis::add( m_restorationTypeCB, i18n("<p>Select the filter preset to use for photograph restoration:<p>" + "<b>None</b>: Most common values. Puts settings to default.<p>" + "<b>Reduce Uniform Noise</b>: reduce small image artifacts like sensor noise.<p>" + "<b>Reduce JPEG Artefacts</b>: reduce large image artifacts like JPEG compression mosaic.<p>" + "<b>Reduce Texturing</b>: reduce image artifacts like paper texture or Moire patterns " + "of a scanned image.<p>")); + + grid->addMultiCellWidget(cimgLogoLabel, 0, 0, 1, 1); + grid->addMultiCellWidget(typeLabel, 1, 1, 0, 0); + grid->addMultiCellWidget(m_restorationTypeCB, 1, 1, 1, 1); + grid->setRowStretch(1, 10); + + // ------------------------------------------------------------- + + m_settingsWidget = new Digikam::GreycstorationWidget( m_mainTab ); + m_imagePreviewWidget->setUserAreaWidget(m_mainTab); + + // ------------------------------------------------------------- + + connect(cimgLogoLabel, TQ_SIGNAL(leftClickedURL(const TQString&)), + this, TQ_SLOT(processCImgURL(const TQString&))); + + connect(m_restorationTypeCB, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotResetValues(int))); +} + +ImageEffect_Restoration::~ImageEffect_Restoration() +{ +} + +void ImageEffect_Restoration::renderingFinished() +{ + m_imagePreviewWidget->setEnable(true); + m_mainTab->setEnabled(true); +} + +void ImageEffect_Restoration::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("restoration Tool Dialog"); + + Digikam::GreycstorationSettings settings; + settings.fastApprox = config->readBoolEntry("FastApprox", true); + settings.interp = config->readNumEntry("Interpolation", + Digikam::GreycstorationSettings::NearestNeighbor); + settings.amplitude = config->readDoubleNumEntry("Amplitude", 60.0); + settings.sharpness = config->readDoubleNumEntry("Sharpness", 0.7); + settings.anisotropy = config->readDoubleNumEntry("Anisotropy", 0.3); + settings.alpha = config->readDoubleNumEntry("Alpha", 0.6); + settings.sigma = config->readDoubleNumEntry("Sigma", 1.1); + settings.gaussPrec = config->readDoubleNumEntry("GaussPrec", 2.0); + settings.dl = config->readDoubleNumEntry("Dl", 0.8); + settings.da = config->readDoubleNumEntry("Da", 30.0); + settings.nbIter = config->readNumEntry("Iteration", 1); + settings.tile = config->readNumEntry("Tile", 512); + settings.btile = config->readNumEntry("BTile", 4); + m_settingsWidget->setSettings(settings); + + int p = config->readNumEntry("Preset", NoPreset); + m_restorationTypeCB->setCurrentItem(p); + if (p == NoPreset) + m_settingsWidget->setEnabled(true); + else + m_settingsWidget->setEnabled(false); +} + +void ImageEffect_Restoration::writeUserSettings() +{ + Digikam::GreycstorationSettings settings = m_settingsWidget->getSettings(); + TDEConfig* config = kapp->config(); + config->setGroup("restoration Tool Dialog"); + config->writeEntry("Preset", m_restorationTypeCB->currentItem()); + 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->sync(); +} + +void ImageEffect_Restoration::slotResetValues(int i) +{ + if (i == NoPreset) + m_settingsWidget->setEnabled(true); + else + m_settingsWidget->setEnabled(false); + + resetValues(); +} + +void ImageEffect_Restoration::resetValues() +{ + Digikam::GreycstorationSettings settings; + settings.setRestorationDefaultSettings(); + + switch(m_restorationTypeCB->currentItem()) + { + case ReduceUniformNoise: + { + settings.amplitude = 40.0; + break; + } + + case ReduceJPEGArtefacts: + { + settings.sharpness = 0.3; + settings.sigma = 1.0; + settings.amplitude = 100.0; + settings.nbIter = 2; + break; + } + + case ReduceTexturing: + { + settings.sharpness = 0.5; + settings.sigma = 1.5; + settings.amplitude = 100.0; + settings.nbIter = 2; + break; + } + } + + m_settingsWidget->setSettings(settings); +} + +void ImageEffect_Restoration::processCImgURL(const TQString& url) +{ + TDEApplication::kApplication()->invokeBrowser(url); +} + +void ImageEffect_Restoration::prepareEffect() +{ + m_mainTab->setEnabled(false); + + Digikam::DImg previewImage = m_imagePreviewWidget->getOriginalRegionImage(); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new Digikam::GreycstorationIface( + &previewImage, m_settingsWidget->getSettings(), + Digikam::GreycstorationIface::Restore, + 0, 0, 0, this)); +} + +void ImageEffect_Restoration::prepareFinal() +{ + m_mainTab->setEnabled(false); + + Digikam::ImageIface iface(0, 0); + uchar *data = iface.getOriginalImage(); + Digikam::DImg originalImage(iface.originalWidth(), iface.originalHeight(), + iface.originalSixteenBit(), iface.originalHasAlpha(), data); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new Digikam::GreycstorationIface( + &originalImage, m_settingsWidget->getSettings(), + Digikam::GreycstorationIface::Restore, + 0, 0, 0, this)); + + delete [] data; +} + +void ImageEffect_Restoration::putPreviewData(void) +{ + Digikam::DImg imDest = m_threadedFilter->getTargetImage(); + m_imagePreviewWidget->setPreviewImage(imDest); +} + +void ImageEffect_Restoration::putFinalData(void) +{ + Digikam::ImageIface iface(0, 0); + + iface.putOriginalImage(i18n("Restoration"), + m_threadedFilter->getTargetImage().bits()); +} + +void ImageEffect_Restoration::slotUser3() +{ + KURL loadRestorationFile = KFileDialog::getOpenURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), this, + TQString( i18n("Photograph Restoration Settings File to Load")) ); + if( loadRestorationFile.isEmpty() ) + return; + + TQFile file(loadRestorationFile.path()); + + if ( file.open(IO_ReadOnly) ) + { + if (!m_settingsWidget->loadSettings(file, TQString("# Photograph Restoration Configuration File V2"))) + { + KMessageBox::error(this, + i18n("\"%1\" is not a Photograph Restoration settings text file.") + .arg(loadRestorationFile.fileName())); + file.close(); + return; + } + + slotEffect(); + } + else + KMessageBox::error(this, i18n("Cannot load settings from the Photograph Restoration text file.")); + + file.close(); + m_restorationTypeCB->blockSignals(true); + m_restorationTypeCB->setCurrentItem(NoPreset); + m_restorationTypeCB->blockSignals(false); + m_settingsWidget->setEnabled(true); +} + +void ImageEffect_Restoration::slotUser2() +{ + KURL saveRestorationFile = KFileDialog::getSaveURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), this, + TQString( i18n("Photograph Restoration Settings File to Save")) ); + if( saveRestorationFile.isEmpty() ) + return; + + TQFile file(saveRestorationFile.path()); + + if ( file.open(IO_WriteOnly) ) + m_settingsWidget->saveSettings(file, TQString("# Photograph Restoration Configuration File V2")); + else + KMessageBox::error(this, i18n("Cannot save settings to the Photograph Restoration text file.")); + + file.close(); +} + +} // NameSpace DigikamRestorationImagesPlugin + diff --git a/src/imageplugins/restoration/imageeffect_restoration.h b/src/imageplugins/restoration/imageeffect_restoration.h new file mode 100644 index 00000000..7c28bd92 --- /dev/null +++ b/src/imageplugins/restoration/imageeffect_restoration.h @@ -0,0 +1,94 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-26 + * Description : a digiKam image editor plugin to restore + * a photograph + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_RESTORATION_H +#define IMAGEEFFECT_RESTORATION_H + +// TQt include. + +#include <tqstring.h> + +// Digikam includes. + +#include "ctrlpaneldlg.h" + +class TQComboBox; +class TQTabWidget; + +namespace Digikam +{ +class GreycstorationWidget; +} + +namespace DigikamRestorationImagesPlugin +{ + +class ImageEffect_Restoration : public Digikam::CtrlPanelDlg +{ + TQ_OBJECT + + +public: + + ImageEffect_Restoration(TQWidget* parent); + ~ImageEffect_Restoration(); + +private slots: + + void slotUser2(); + void slotUser3(); + void processCImgURL(const TQString&); + void readUserSettings(); + void slotResetValues(int); + +private: + + void writeUserSettings(); + void prepareEffect(void); + void prepareFinal(void); + void putPreviewData(void); + void putFinalData(void); + void resetValues(void); + void renderingFinished(void); + +private: + + enum RestorationFilteringPreset + { + NoPreset=0, + ReduceUniformNoise, + ReduceJPEGArtefacts, + ReduceTexturing + }; + + TQTabWidget *m_mainTab; + + TQComboBox *m_restorationTypeCB; + + Digikam::GreycstorationWidget *m_settingsWidget; +}; + +} // NameSpace DigikamRestorationImagesPlugin + +#endif /* IMAGEEFFECT_RESTORATION_H */ diff --git a/src/imageplugins/restoration/imageplugin_restoration.cpp b/src/imageplugins/restoration/imageplugin_restoration.cpp new file mode 100644 index 00000000..01cd52f7 --- /dev/null +++ b/src/imageplugins/restoration/imageplugin_restoration.cpp @@ -0,0 +1,71 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-26 + * Description : a digiKam image editor plugin to restore + * a photograph + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> +#include <tdeapplication.h> + +// Local includes. + +#include "ddebug.h" +#include "restorationtool.h" +#include "imageplugin_restoration.h" +#include "imageplugin_restoration.moc" + +using namespace DigikamRestorationImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_restoration, + KGenericFactory<ImagePlugin_Restoration>("digikamimageplugin_restoration")); + +ImagePlugin_Restoration::ImagePlugin_Restoration(TQObject *parent, const char*, const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_Restoration") +{ + m_restorationAction = new TDEAction(i18n("Restoration..."), "restoration", 0, + this, TQ_SLOT(slotRestoration()), + actionCollection(), "imageplugin_restoration"); + + setXMLFile( "digikamimageplugin_restoration_ui.rc" ); + + DDebug() << "ImagePlugin_Restoration plugin loaded" << endl; +} + +ImagePlugin_Restoration::~ImagePlugin_Restoration() +{ +} + +void ImagePlugin_Restoration::setEnabledActions(bool enable) +{ + m_restorationAction->setEnabled(enable); +} + +void ImagePlugin_Restoration::slotRestoration() +{ + RestorationTool *tool = new RestorationTool(this); + loadTool(tool); +} diff --git a/src/imageplugins/restoration/imageplugin_restoration.h b/src/imageplugins/restoration/imageplugin_restoration.h new file mode 100644 index 00000000..50ac8326 --- /dev/null +++ b/src/imageplugins/restoration/imageplugin_restoration.h @@ -0,0 +1,57 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-26 + * Description : a digiKam image editor plugin to restore + * a photograph + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_RESTORATION_H +#define IMAGEPLUGIN_RESTORATION_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_Restoration : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_Restoration(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_Restoration(); + + void setEnabledActions(bool enable); + +private slots: + + void slotRestoration(); + +private: + + TDEAction *m_restorationAction; +}; + +#endif /* IMAGEPLUGIN_RESTORATION_H */ diff --git a/src/imageplugins/restoration/restorationtool.cpp b/src/imageplugins/restoration/restorationtool.cpp new file mode 100644 index 00000000..a6896135 --- /dev/null +++ b/src/imageplugins/restoration/restorationtool.cpp @@ -0,0 +1,356 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-26 + * Description : a digiKam image editor plugin to restore + * a photograph + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqlabel.h> +#include <tqtooltip.h> +#include <tqwhatsthis.h> +#include <tqlayout.h> +#include <tqcombobox.h> +#include <tqtabwidget.h> +#include <tqfile.h> +#include <tqimage.h> + +// KDE includes. + +#include <kurllabel.h> +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <tdefiledialog.h> +#include <tdeglobalsettings.h> +#include <kstandarddirs.h> +#include <tdemessagebox.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "imageiface.h" +#include "imagepanelwidget.h" +#include "editortoolsettings.h" +#include "greycstorationsettings.h" +#include "greycstorationwidget.h" +#include "greycstorationiface.h" +#include "restorationtool.h" +#include "restorationtool.moc" + +using namespace Digikam; + +namespace DigikamRestorationImagesPlugin +{ + +RestorationTool::RestorationTool(TQObject* parent) + : EditorToolThreaded(parent) +{ + setName("restoration"); + setToolName(i18n("Restoration")); + setToolIcon(SmallIcon("restoration")); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel| + EditorToolSettings::Load| + EditorToolSettings::SaveAs| + EditorToolSettings::Try, + EditorToolSettings::PanIcon); + + TQGridLayout* gridSettings = new TQGridLayout(m_gboxSettings->plainPage(), 2, 1); + m_mainTab = new TQTabWidget( m_gboxSettings->plainPage() ); + + TQWidget* firstPage = new TQWidget( m_mainTab ); + TQGridLayout* grid = new TQGridLayout(firstPage, 2, 2); + m_mainTab->addTab( firstPage, i18n("Preset") ); + + KURLLabel *cimgLogoLabel = new KURLLabel(firstPage); + cimgLogoLabel->setText(TQString()); + 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"); + cimgLogoLabel->setPixmap( TQPixmap( directory + "logo-cimg.png" ) ); + TQToolTip::add(cimgLogoLabel, i18n("Visit CImg library website")); + + TQLabel *typeLabel = new TQLabel(i18n("Filtering type:"), firstPage); + typeLabel->setAlignment ( TQt::AlignRight | TQt::AlignVCenter); + m_restorationTypeCB = new TQComboBox(false, firstPage); + m_restorationTypeCB->insertItem( i18n("None") ); + m_restorationTypeCB->insertItem( i18n("Reduce Uniform Noise") ); + m_restorationTypeCB->insertItem( i18n("Reduce JPEG Artefacts") ); + m_restorationTypeCB->insertItem( i18n("Reduce Texturing") ); + TQWhatsThis::add( m_restorationTypeCB, i18n("<p>Select the filter preset to use for photograph restoration:<p>" + "<b>None</b>: Most common values. Puts settings to default.<p>" + "<b>Reduce Uniform Noise</b>: reduce small image artifacts like sensor noise.<p>" + "<b>Reduce JPEG Artefacts</b>: reduce large image artifacts like JPEG compression mosaic.<p>" + "<b>Reduce Texturing</b>: reduce image artifacts like paper texture or Moire patterns " + "of a scanned image.<p>")); + + grid->addMultiCellWidget(cimgLogoLabel, 0, 0, 1, 1); + grid->addMultiCellWidget(typeLabel, 1, 1, 0, 0); + grid->addMultiCellWidget(m_restorationTypeCB, 1, 1, 1, 1); + grid->setRowStretch(1, 10); + grid->setMargin(m_gboxSettings->spacingHint()); + grid->setSpacing(m_gboxSettings->spacingHint()); + + m_settingsWidget = new GreycstorationWidget( m_mainTab ); + gridSettings->addMultiCellWidget(m_mainTab, 0, 0, 1, 1); + gridSettings->addMultiCellWidget(new TQLabel(m_gboxSettings->plainPage()), 1, 1, 1, 1); + gridSettings->setMargin(m_gboxSettings->spacingHint()); + gridSettings->setSpacing(m_gboxSettings->spacingHint()); + gridSettings->setRowStretch(2, 10); + + setToolSettings(m_gboxSettings); + + // ------------------------------------------------------------- + + m_previewWidget = new ImagePanelWidget(470, 350, "restoration Tool", m_gboxSettings->panIconView()); + + setToolView(m_previewWidget); + init(); + + // ------------------------------------------------------------- + + connect(cimgLogoLabel, TQ_SIGNAL(leftClickedURL(const TQString&)), + this, TQ_SLOT(processCImgURL(const TQString&))); + + connect(m_restorationTypeCB, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotResetValues(int))); + + // ------------------------------------------------------------- + + GreycstorationSettings defaults; + defaults.setRestorationDefaultSettings(); + m_settingsWidget->setDefaultSettings(defaults); +} + +RestorationTool::~RestorationTool() +{ +} + +void RestorationTool::renderingFinished() +{ + m_previewWidget->setEnable(true); + m_mainTab->setEnabled(true); +} + +void RestorationTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("restoration Tool"); + + GreycstorationSettings settings; + GreycstorationSettings defaults; + defaults.setRestorationDefaultSettings(); + + 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); + m_settingsWidget->setSettings(settings); + + int p = config->readNumEntry("Preset", NoPreset); + m_restorationTypeCB->setCurrentItem(p); + if (p == NoPreset) + m_settingsWidget->setEnabled(true); + else + m_settingsWidget->setEnabled(false); +} + +void RestorationTool::writeSettings() +{ + GreycstorationSettings settings = m_settingsWidget->getSettings(); + TDEConfig* config = kapp->config(); + config->setGroup("restoration Tool"); + config->writeEntry("Preset", m_restorationTypeCB->currentItem()); + 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); + m_previewWidget->writeSettings(); + config->sync(); +} + +void RestorationTool::slotResetValues(int i) +{ + if (i == NoPreset) + m_settingsWidget->setEnabled(true); + else + m_settingsWidget->setEnabled(false); + + slotResetSettings(); +} + +void RestorationTool::slotResetSettings() +{ + GreycstorationSettings settings; + settings.setRestorationDefaultSettings(); + + switch(m_restorationTypeCB->currentItem()) + { + case ReduceUniformNoise: + { + settings.amplitude = 40.0; + break; + } + + case ReduceJPEGArtefacts: + { + settings.sharpness = 0.3; + settings.sigma = 1.0; + settings.amplitude = 100.0; + settings.nbIter = 2; + break; + } + + case ReduceTexturing: + { + settings.sharpness = 0.5; + settings.sigma = 1.5; + settings.amplitude = 100.0; + settings.nbIter = 2; + break; + } + } + + m_settingsWidget->setSettings(settings); +} + +void RestorationTool::processCImgURL(const TQString& url) +{ + TDEApplication::kApplication()->invokeBrowser(url); +} + +void RestorationTool::prepareEffect() +{ + m_mainTab->setEnabled(false); + + DImg previewImage = m_previewWidget->getOriginalRegionImage(); + + setFilter(dynamic_cast<DImgThreadedFilter*>(new GreycstorationIface(&previewImage, + m_settingsWidget->getSettings(), GreycstorationIface::Restore, + 0, 0, 0, this))); +} + +void RestorationTool::prepareFinal() +{ + m_mainTab->setEnabled(false); + + ImageIface iface(0, 0); + uchar *data = iface.getOriginalImage(); + DImg originalImage(iface.originalWidth(), iface.originalHeight(), + iface.originalSixteenBit(), iface.originalHasAlpha(), data); + + setFilter(dynamic_cast<DImgThreadedFilter*>(new GreycstorationIface(&originalImage, + m_settingsWidget->getSettings(), GreycstorationIface::Restore, + 0, 0, 0, this))); + + delete [] data; +} + +void RestorationTool::putPreviewData() +{ + DImg imDest = filter()->getTargetImage(); + m_previewWidget->setPreviewImage(imDest); +} + +void RestorationTool::putFinalData() +{ + ImageIface iface(0, 0); + iface.putOriginalImage(i18n("Restoration"), filter()->getTargetImage().bits()); +} + +void RestorationTool::slotLoadSettings() +{ + KURL loadRestorationFile = KFileDialog::getOpenURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), kapp->activeWindow(), + TQString( i18n("Photograph Restoration Settings File to Load")) ); + if( loadRestorationFile.isEmpty() ) + return; + + TQFile file(loadRestorationFile.path()); + + if ( file.open(IO_ReadOnly) ) + { + if (!m_settingsWidget->loadSettings(file, TQString("# Photograph Restoration Configuration File V2"))) + { + KMessageBox::error(kapp->activeWindow(), + i18n("\"%1\" is not a Photograph Restoration settings text file.") + .arg(loadRestorationFile.fileName())); + file.close(); + return; + } + + slotEffect(); + } + else + KMessageBox::error(kapp->activeWindow(), i18n("Cannot load settings from the Photograph Restoration text file.")); + + file.close(); + m_restorationTypeCB->blockSignals(true); + m_restorationTypeCB->setCurrentItem(NoPreset); + m_restorationTypeCB->blockSignals(false); + m_settingsWidget->setEnabled(true); +} + +void RestorationTool::slotSaveAsSettings() +{ + KURL saveRestorationFile = KFileDialog::getSaveURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), kapp->activeWindow(), + TQString( i18n("Photograph Restoration Settings File to Save")) ); + if( saveRestorationFile.isEmpty() ) + return; + + TQFile file(saveRestorationFile.path()); + + if ( file.open(IO_WriteOnly) ) + m_settingsWidget->saveSettings(file, TQString("# Photograph Restoration Configuration File V2")); + else + KMessageBox::error(kapp->activeWindow(), i18n("Cannot save settings to the Photograph Restoration text file.")); + + file.close(); +} + +} // NameSpace DigikamRestorationImagesPlugin + diff --git a/src/imageplugins/restoration/restorationtool.h b/src/imageplugins/restoration/restorationtool.h new file mode 100644 index 00000000..6242a2b6 --- /dev/null +++ b/src/imageplugins/restoration/restorationtool.h @@ -0,0 +1,100 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-26 + * Description : a digiKam image editor plugin to restore + * a photograph + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +#ifndef RESTORATIONTOOL_H +#define RESTORATIONTOOL_H + +// TQt includes. + +#include <tqstring.h> + +// Digikam includes. + +#include "editortool.h" + +class TQComboBox; +class TQTabWidget; + +namespace Digikam +{ +class GreycstorationWidget; +class EditorToolSettings; +class ImagePanelWidget; +} + +namespace DigikamRestorationImagesPlugin +{ + +class RestorationTool : public Digikam::EditorToolThreaded +{ + TQ_OBJECT + + +public: + + RestorationTool(TQObject* parent); + ~RestorationTool(); + +private slots: + + void slotSaveAsSettings(); + void slotLoadSettings(); + void slotResetSettings(); + void processCImgURL(const TQString&); + void slotResetValues(int); + +private: + + void readSettings(); + void writeSettings(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + enum RestorationFilteringPreset + { + NoPreset=0, + ReduceUniformNoise, + ReduceJPEGArtefacts, + ReduceTexturing + }; + + TQTabWidget *m_mainTab; + + TQComboBox *m_restorationTypeCB; + + Digikam::GreycstorationWidget *m_settingsWidget; + + Digikam::ImagePanelWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamRestorationImagesPlugin + +#endif /* RESTORATIONTOOL_H */ diff --git a/src/imageplugins/sheartool/Makefile.am b/src/imageplugins/sheartool/Makefile.am new file mode 100644 index 00000000..a601b8a5 --- /dev/null +++ b/src/imageplugins/sheartool/Makefile.am @@ -0,0 +1,33 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_sheartool_la_SOURCES = imageplugin_sheartool.cpp shear.cpp \ + sheartool.cpp + +digikamimageplugin_sheartool_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_sheartool_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_sheartool.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_sheartool.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_sheartool_ui.rc diff --git a/src/imageplugins/sheartool/digikamimageplugin_sheartool.desktop b/src/imageplugins/sheartool/digikamimageplugin_sheartool.desktop new file mode 100644 index 00000000..8884ef27 --- /dev/null +++ b/src/imageplugins/sheartool/digikamimageplugin_sheartool.desktop @@ -0,0 +1,53 @@ +[Desktop Entry] +Name=ImagePlugin_ShearTool +Name[bg]=Приставка за снимки - Инструмент за изрязване +Name[da]=Billedplugin_Forskydningsværktøj +Name[el]=ΠρόσθετοΕικόνας_ΕργαλείοΣτρέβλωσης +Name[fi]=Väännin +Name[hr]=Smicanje +Name[it]=PluginImmagini_DistorsioneCurvilinea +Name[ms]=ImagePlugin_AlatanPemotong +Name[nl]=Afbeeldingsplugin_SchuinTrekken +Name[sr]=Алат за искошавање +Name[sr@Latn]=Alat za iskošavanje +Name[sv]=Insticksprogram med skjuvningsverktyg +Name[tr]=ResimEklentisi_EğmeAracı +Name[xx]=xxImagePlugin_ShearToolxx + +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=Shear tool plugin for digiKam +Comment[bg]=Приставка на digiKam с инструмент за изрязване на снимки +Comment[ca]=Connector pel digiKam d'eina per retallar +Comment[da]=Forskydningsværktøjs-plugin for Digikam +Comment[de]=digiKam-Modul zum Scheren eines Bildes +Comment[el]=Πρόσθετο εργαλείο στρέβλωσης για το digiKam +Comment[es]=Plugin para digiKam con herramientas para cizallar una imagen +Comment[et]=DigiKami pildinihkeplugin +Comment[fa]=وصلۀ ابزار چیدن برای digiKam +Comment[fi]=Vääntää kuvaa vaaka- ja pystysuunnassa +Comment[gl]=Un plugin de digiKam para inclinar unha imaxe +Comment[hr]=digiKam dodatak za smicanje +Comment[is]=Íforrit fyrir digiKam sem snýr upp á myndir +Comment[it]=Plugin per lo strumento di distorsione curvilinea per digiKam +Comment[ja]=digiKam 剪断変形プラグイン +Comment[ms]=Templat plugin pemotong untuk digiKam +Comment[nds]=digiKam-Warktüüchmoduul för't Scheren +Comment[nl]=Digikam-plugin voor het schuintrekken van afbeeldingen +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਸ਼ੀਅਰ ਸੰਦ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam umożliwiająca pochylenie obrazu +Comment[pt]=Um 'plugin' do digiKam para inclinar uma imagem +Comment[pt_BR]=Um 'plugin' do digiKam para inclinar uma imagem +Comment[ru]=Модуль сдвига фрагментов для digiKam +Comment[sk]=digiKam plugin pre orezanie obrázku +Comment[sr]=digiKam-ов прикључак за искошавање +Comment[sr@Latn]=digiKam-ov priključak za iskošavanje +Comment[sv]=Digikam insticksprogram med skjuvningsverktyg +Comment[tr]=digiKam için eğme aracı eklentisi +Comment[uk]=Втулок засобу перекошення для digiKam +Comment[vi]=Phần bổ sung công cụ kéo cắt cho digiKam +Comment[xx]=xxShear tool plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_sheartool +author=Gilles Caulier, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/sheartool/digikamimageplugin_sheartool_ui.rc b/src/imageplugins/sheartool/digikamimageplugin_sheartool_ui.rc new file mode 100644 index 00000000..0a2cf60a --- /dev/null +++ b/src/imageplugins/sheartool/digikamimageplugin_sheartool_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="4" name="digikamimageplugin_sheartool" > + + <MenuBar> + + <Menu name="Transform" ><text>Tra&nsform</text> + <Action name="imageplugin_sheartool" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action shortcut="" name="imageplugin_sheartool" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/sheartool/imageeffect_sheartool.cpp b/src/imageplugins/sheartool/imageeffect_sheartool.cpp new file mode 100644 index 00000000..e65bd91b --- /dev/null +++ b/src/imageplugins/sheartool/imageeffect_sheartool.cpp @@ -0,0 +1,322 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-23 + * Description : a plugin to shear an image + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqlabel.h> +#include <tqcheckbox.h> +#include <tqwhatsthis.h> +#include <tqlayout.h> +#include <tqimage.h> + +// KDE includes. + +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <kstandarddirs.h> +#include <knuminput.h> +#include <kseparator.h> +#include <kcursor.h> +#include <tdeconfig.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "sheartool.h" +#include "imageeffect_sheartool.h" +#include "imageeffect_sheartool.moc" + +namespace DigikamShearToolImagesPlugin +{ + +ImageEffect_ShearTool::ImageEffect_ShearTool(TQWidget* parent) + : Digikam::ImageGuideDlg(parent, i18n("Shear Tool"), "sheartool", + false, true, true, + Digikam::ImageGuideWidget::HVGuideMode) +{ + // No need Abort button action. + showButton(User1, false); + + TQString whatsThis; + + // About data and help button. + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Shear Tool"), + digikam_version, + I18N_NOOP("A digiKam image plugin to shear an image."), + TDEAboutData::License_GPL, + "(c) 2004-2008, Gilles Caulier", + 0, + "http://www.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + about->addAuthor("Pieter Z. Voloshyn", I18N_NOOP("Shear algorithm"), + "pieter dot voloshyn at gmail dot com"); + + setAboutData(about); + + TQWhatsThis::add( m_imagePreviewWidget, i18n("<p>This is the shearing image operation preview. " + "If you move the mouse cursor on this preview, " + "a vertical and horizontal dashed line will be drawn " + "to guide you in adjusting the shearing correction. " + "Release the left mouse button to freeze the dashed " + "line's position.")); + + // ------------------------------------------------------------- + + TQString temp; + Digikam::ImageIface iface(0, 0); + + TQWidget *gboxSettings = new TQWidget(plainPage()); + TQGridLayout* gridSettings = new TQGridLayout( gboxSettings, 11, 2, spacingHint()); + + TQLabel *label1 = new TQLabel(i18n("New width:"), gboxSettings); + m_newWidthLabel = new TQLabel(temp.setNum( iface.originalWidth()) + i18n(" px"), gboxSettings); + m_newWidthLabel->setAlignment( AlignBottom | AlignRight ); + + TQLabel *label2 = new TQLabel(i18n("New height:"), gboxSettings); + m_newHeightLabel = new TQLabel(temp.setNum( iface.originalHeight()) + i18n(" px"), gboxSettings); + m_newHeightLabel->setAlignment( AlignBottom | AlignRight ); + + gridSettings->addMultiCellWidget(label1, 0, 0, 0, 0); + gridSettings->addMultiCellWidget(m_newWidthLabel, 0, 0, 1, 2); + gridSettings->addMultiCellWidget(label2, 1, 1, 0, 0); + gridSettings->addMultiCellWidget(m_newHeightLabel, 1, 1, 1, 2); + + KSeparator *line = new KSeparator(Horizontal, gboxSettings); + gridSettings->addMultiCellWidget(line, 2, 2, 0, 2); + + TQLabel *label3 = new TQLabel(i18n("Main horizontal angle:"), gboxSettings); + m_mainHAngleInput = new KIntNumInput(gboxSettings); + m_mainHAngleInput->setRange(-45, 45, 1, true); + m_mainHAngleInput->setValue(0); + TQWhatsThis::add( m_mainHAngleInput, i18n("<p>The main horizontal shearing angle, in degrees.")); + gridSettings->addMultiCellWidget(label3, 3, 3, 0, 2); + gridSettings->addMultiCellWidget(m_mainHAngleInput, 4, 4, 0, 2); + + TQLabel *label4 = new TQLabel(i18n("Fine horizontal angle:"), gboxSettings); + m_fineHAngleInput = new KDoubleNumInput(gboxSettings); + m_fineHAngleInput->setRange(-5.0, 5.0, 0.01, true); + m_fineHAngleInput->setValue(0); + TQWhatsThis::add( m_fineHAngleInput, i18n("<p>This value in degrees will be added to main horizontal angle value " + "to set fine adjustments.")); + gridSettings->addMultiCellWidget(label4, 5, 5, 0, 2); + gridSettings->addMultiCellWidget(m_fineHAngleInput, 6, 6, 0, 2); + + TQLabel *label5 = new TQLabel(i18n("Main vertical angle:"), gboxSettings); + m_mainVAngleInput = new KIntNumInput(gboxSettings); + m_mainVAngleInput->setRange(-45, 45, 1, true); + m_mainVAngleInput->setValue(0); + TQWhatsThis::add( m_mainVAngleInput, i18n("<p>The main vertical shearing angle, in degrees.")); + gridSettings->addMultiCellWidget(label5, 7, 7, 0, 0); + gridSettings->addMultiCellWidget(m_mainVAngleInput, 8, 8, 0, 2); + + TQLabel *label6 = new TQLabel(i18n("Fine vertical angle:"), gboxSettings); + m_fineVAngleInput = new KDoubleNumInput(gboxSettings); + m_fineVAngleInput->setRange(-5.0, 5.0, 0.01, true); + m_fineVAngleInput->setValue(0); + TQWhatsThis::add( m_fineVAngleInput, i18n("<p>This value in degrees will be added to main vertical angle value " + "to set fine adjustments.")); + gridSettings->addMultiCellWidget(label6, 9, 9, 0, 2); + gridSettings->addMultiCellWidget(m_fineVAngleInput, 10, 10, 0, 2); + + m_antialiasInput = new TQCheckBox(i18n("Anti-Aliasing"), gboxSettings); + TQWhatsThis::add( m_antialiasInput, i18n("<p>Enable this option to apply the anti-aliasing filter " + "to the sheared image. " + "To smooth the target image, it will be blurred a little.")); + gridSettings->addMultiCellWidget(m_antialiasInput, 11, 11, 0, 2); + + setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + connect(m_mainHAngleInput, TQ_SIGNAL(valueChanged (int)), + this, TQ_SLOT(slotTimer())); + + connect(m_fineHAngleInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_mainVAngleInput, TQ_SIGNAL(valueChanged (int)), + this, TQ_SLOT(slotTimer())); + + connect(m_fineVAngleInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_antialiasInput, TQ_SIGNAL(toggled (bool)), + this, TQ_SLOT(slotEffect())); +} + +ImageEffect_ShearTool::~ImageEffect_ShearTool() +{ +} + +void ImageEffect_ShearTool::readUserSettings(void) +{ + TDEConfig *config = kapp->config(); + config->setGroup("sheartool Tool Dialog"); + m_mainHAngleInput->setValue(config->readNumEntry("Main HAngle", 0)); + m_mainVAngleInput->setValue(config->readNumEntry("Main VAngle", 0)); + m_fineHAngleInput->setValue(config->readDoubleNumEntry("Fine HAngle", 0.0)); + m_fineVAngleInput->setValue(config->readDoubleNumEntry("Fine VAngle", 0.0)); + m_antialiasInput->setChecked(config->readBoolEntry("Anti Aliasing", true)); + slotEffect(); +} + +void ImageEffect_ShearTool::writeUserSettings(void) +{ + TDEConfig *config = kapp->config(); + config->setGroup("sheartool Tool Dialog"); + config->writeEntry("Main HAngle", m_mainHAngleInput->value()); + config->writeEntry("Main VAngle", m_mainVAngleInput->value()); + config->writeEntry("Fine HAngle", m_fineHAngleInput->value()); + config->writeEntry("Fine VAngle", m_fineVAngleInput->value()); + config->writeEntry("Anti Aliasing", m_antialiasInput->isChecked()); + config->sync(); +} + +void ImageEffect_ShearTool::resetValues() +{ + m_mainHAngleInput->blockSignals(true); + m_mainVAngleInput->blockSignals(true); + m_fineHAngleInput->blockSignals(true); + m_fineVAngleInput->blockSignals(true); + m_antialiasInput->blockSignals(true); + m_mainHAngleInput->setValue(0); + m_mainVAngleInput->setValue(0); + m_fineHAngleInput->setValue(0.0); + m_fineVAngleInput->setValue(0.0); + m_antialiasInput->setChecked(true); + m_mainHAngleInput->blockSignals(false); + m_mainVAngleInput->blockSignals(false); + m_fineHAngleInput->blockSignals(false); + m_fineVAngleInput->blockSignals(false); + m_antialiasInput->blockSignals(false); +} + +void ImageEffect_ShearTool::prepareEffect() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + m_mainHAngleInput->setEnabled(false); + m_mainVAngleInput->setEnabled(false); + m_fineHAngleInput->setEnabled(false); + m_fineVAngleInput->setEnabled(false); + m_antialiasInput->setEnabled(false); + + float hAngle = m_mainHAngleInput->value() + m_fineHAngleInput->value(); + float vAngle = m_mainVAngleInput->value() + m_fineVAngleInput->value(); + bool antialiasing = m_antialiasInput->isChecked(); + TQColor background = paletteBackgroundColor().rgb(); + + Digikam::ImageIface* iface = m_imagePreviewWidget->imageIface(); + int orgW = iface->originalWidth(); + int orgH = iface->originalHeight(); + + uchar *data = iface->getPreviewImage(); + Digikam::DImg image(iface->previewWidth(), iface->previewHeight(), iface->previewSixteenBit(), + iface->previewHasAlpha(), data); + delete [] data; + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new ShearTool(&image, this, hAngle, vAngle, antialiasing, background, orgW, orgH)); +} + +void ImageEffect_ShearTool::prepareFinal() +{ + m_mainHAngleInput->setEnabled(false); + m_mainVAngleInput->setEnabled(false); + m_fineHAngleInput->setEnabled(false); + m_fineVAngleInput->setEnabled(false); + m_antialiasInput->setEnabled(false); + + float hAngle = m_mainHAngleInput->value() + m_fineHAngleInput->value(); + float vAngle = m_mainVAngleInput->value() + m_fineVAngleInput->value(); + bool antialiasing = m_antialiasInput->isChecked(); + TQColor background = TQt::black; + + Digikam::ImageIface iface(0, 0); + int orgW = iface.originalWidth(); + int orgH = iface.originalHeight(); + + uchar *data = iface.getOriginalImage(); + Digikam::DImg orgImage(orgW, orgH, iface.originalSixteenBit(), + iface.originalHasAlpha(), data); + delete [] data; + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new ShearTool(&orgImage, this, hAngle, vAngle, antialiasing, background, orgW, orgH)); +} + +void ImageEffect_ShearTool::putPreviewData(void) +{ + Digikam::ImageIface* iface = m_imagePreviewWidget->imageIface(); + int w = iface->previewWidth(); + int h = iface->previewHeight(); + + Digikam::DImg imTemp = m_threadedFilter->getTargetImage().smoothScale(w, h, TQSize::ScaleMin); + Digikam::DImg imDest( w, h, m_threadedFilter->getTargetImage().sixteenBit(), + m_threadedFilter->getTargetImage().hasAlpha() ); + + imDest.fill( Digikam::DColor(paletteBackgroundColor().rgb(), + m_threadedFilter->getTargetImage().sixteenBit()) ); + imDest.bitBltImage(&imTemp, (w-imTemp.width())/2, (h-imTemp.height())/2); + + iface->putPreviewImage((imDest.smoothScale(iface->previewWidth(), + iface->previewHeight())).bits()); + + m_imagePreviewWidget->updatePreview(); + TQSize newSize = dynamic_cast<ShearTool *>(m_threadedFilter)->getNewSize(); + TQString temp; + m_newWidthLabel->setText(temp.setNum( newSize.width()) + i18n(" px") ); + m_newHeightLabel->setText(temp.setNum( newSize.height()) + i18n(" px") ); +} + +void ImageEffect_ShearTool::putFinalData(void) +{ + Digikam::ImageIface iface(0, 0); + Digikam::DImg targetImage = m_threadedFilter->getTargetImage(); + iface.putOriginalImage(i18n("Shear Tool"), + targetImage.bits(), + targetImage.width(), targetImage.height()); +} + +void ImageEffect_ShearTool::renderingFinished() +{ + m_mainHAngleInput->setEnabled(true); + m_mainVAngleInput->setEnabled(true); + m_fineHAngleInput->setEnabled(true); + m_fineVAngleInput->setEnabled(true); + m_antialiasInput->setEnabled(true); + kapp->restoreOverrideCursor(); +} + +} // NameSpace DigikamShearToolImagesPlugin + diff --git a/src/imageplugins/sheartool/imageeffect_sheartool.h b/src/imageplugins/sheartool/imageeffect_sheartool.h new file mode 100644 index 00000000..311b4e0d --- /dev/null +++ b/src/imageplugins/sheartool/imageeffect_sheartool.h @@ -0,0 +1,82 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-23 + * Description : a plugin to shear an image + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_SHEARTOOL_H +#define IMAGEEFFECT_SHEARTOOL_H + +// Local includes. + +#include "imageguidedlg.h" + +class TQFrame; +class TQPushButton; +class TQCheckBox; +class TQLabel; + +class KIntNumInput; +class KDoubleNumInput; + +namespace DigikamShearToolImagesPlugin +{ + +class ImageEffect_ShearTool : public Digikam::ImageGuideDlg +{ + TQ_OBJECT + + +public: + + ImageEffect_ShearTool(TQWidget* parent); + ~ImageEffect_ShearTool(); + +private slots: + + void readUserSettings(void); + +protected: + + void writeUserSettings(void); + void prepareEffect(void); + void prepareFinal(void); + void putPreviewData(void); + void putFinalData(void); + void resetValues(void); + void renderingFinished(void); + +private: + + TQLabel *m_newWidthLabel; + TQLabel *m_newHeightLabel; + + TQCheckBox *m_antialiasInput; + + KIntNumInput *m_mainHAngleInput; + KIntNumInput *m_mainVAngleInput; + + KDoubleNumInput *m_fineHAngleInput; + KDoubleNumInput *m_fineVAngleInput; +}; + +} // NameSpace DigikamShearToolImagesPlugin + +#endif /* IMAGEEFFECT_SHEARTOOL_H */ diff --git a/src/imageplugins/sheartool/imageplugin_sheartool.cpp b/src/imageplugins/sheartool/imageplugin_sheartool.cpp new file mode 100644 index 00000000..34030899 --- /dev/null +++ b/src/imageplugins/sheartool/imageplugin_sheartool.cpp @@ -0,0 +1,69 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-23 + * Description : a plugin to shear an image + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> + +// Local includes. + +#include "ddebug.h" +#include "sheartool.h" +#include "imageplugin_sheartool.h" +#include "imageplugin_sheartool.moc" + +using namespace DigikamShearToolImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_sheartool, + KGenericFactory<ImagePlugin_ShearTool>("digikamimageplugin_sheartool")); + +ImagePlugin_ShearTool::ImagePlugin_ShearTool(TQObject *parent, const char*, const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_ShearTool") +{ + m_sheartoolAction = new TDEAction(i18n("Shear..."), "shear", 0, + this, TQ_SLOT(slotShearTool()), + actionCollection(), "imageplugin_sheartool"); + + setXMLFile("digikamimageplugin_sheartool_ui.rc"); + + DDebug() << "ImagePlugin_ShearTool plugin loaded" << endl; +} + +ImagePlugin_ShearTool::~ImagePlugin_ShearTool() +{ +} + +void ImagePlugin_ShearTool::setEnabledActions(bool enable) +{ + m_sheartoolAction->setEnabled(enable); +} + +void ImagePlugin_ShearTool::slotShearTool() +{ + ShearTool *tool = new ShearTool(this); + loadTool(tool); +} diff --git a/src/imageplugins/sheartool/imageplugin_sheartool.h b/src/imageplugins/sheartool/imageplugin_sheartool.h new file mode 100644 index 00000000..2423a1b1 --- /dev/null +++ b/src/imageplugins/sheartool/imageplugin_sheartool.h @@ -0,0 +1,56 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-23 + * Description : a plugin to shear an image + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_SHEARTOOL_H +#define IMAGEPLUGIN_SHEARTOOL_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_ShearTool : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_ShearTool(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_ShearTool(); + + void setEnabledActions(bool enable); + +private slots: + + void slotShearTool(); + +private: + + TDEAction *m_sheartoolAction; +}; + +#endif /* IMAGEPLUGIN_SHEARTOOL_H */ diff --git a/src/imageplugins/sheartool/shear.cpp b/src/imageplugins/sheartool/shear.cpp new file mode 100644 index 00000000..29af5390 --- /dev/null +++ b/src/imageplugins/sheartool/shear.cpp @@ -0,0 +1,185 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-07-18 + * Description : Shear threaded image filter. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * Original Shear algorithms copyrighted 2005 by + * Pieter Z. Voloshyn <pieter dot voloshyn 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. + * + * ============================================================ */ + +// Degrees to radian convertion coeff (PI/180). To optimize computation. +#define DEG2RAD 0.017453292519943 + +// C++ includes. + +#include <cmath> +#include <cstdlib> + +// Local includes. + +#include "dimg.h" +#include "dimgimagefilters.h" +#include "shear.h" + +namespace DigikamShearToolImagesPlugin +{ + +Shear::Shear(Digikam::DImg *orgImage, TQObject *parent, float hAngle, float vAngle, + bool antialiasing, TQColor backgroundColor, int orgW, int orgH) + : Digikam::DImgThreadedFilter(orgImage, parent, "sheartool") +{ + m_hAngle = hAngle; + m_vAngle = vAngle; + m_orgW = orgW; + m_orgH = orgH; + m_antiAlias = antialiasing; + m_backgroundColor = backgroundColor; + + initFilter(); +} + +void Shear::filterImage(void) +{ + int progress; + int x, y, p = 0, pt; + int new_width, new_height; + double nx, ny, dx, dy; + double horz_factor, vert_factor; + double horz_add, vert_add; + double horz_beta_angle, vert_beta_angle; + + int nWidth = m_orgImage.width(); + int nHeight = m_orgImage.height(); + + uchar *pBits = m_orgImage.bits(); + unsigned short *pBits16 = (unsigned short*)m_orgImage.bits(); + + // get beta ( complementary ) angle for horizontal and vertical angles + horz_beta_angle = ( ( ( m_hAngle < 0.0 ) ? 180.0 : 90.0 ) - m_hAngle ) * DEG2RAD; + vert_beta_angle = ( ( ( m_vAngle < 0.0 ) ? 180.0 : 90.0 ) - m_vAngle ) * DEG2RAD; + + // get new distance for width and height values + horz_add = nHeight * ( ( m_hAngle < 0.0 ) ? sin( horz_beta_angle ) : cos( horz_beta_angle ) ); + vert_add = nWidth * ( ( m_vAngle < 0.0 ) ? sin( vert_beta_angle ) : cos( vert_beta_angle ) ); + + // get absolute values for the distances + horz_add = fabs( horz_add ); + vert_add = fabs( vert_add ); + + // get new image size ( original size + distance ) + new_width = (int)horz_add + nWidth; + new_height = (int)vert_add + nHeight; + + // get scale factor for width and height + horz_factor = horz_add / new_height; + vert_factor = vert_add / new_width; + + // if horizontal angle is greater than zero... + // else, initial distance is equal to maximum distance ( in negative form ) + if( m_hAngle > 0.0 ) + { + // initial distance is zero and scale is negative ( to decrease ) + dx = 0; + horz_factor *= -1.0; + } + else + { + dx = -horz_add; + } + + // if vertical angle is greater than zero... + // else, initial distance is equal to maximum distance ( in negative form ) + if( m_vAngle > 0.0 ) + { + // initial distance is zero and scale is negative ( to decrease ) + dy = 0; + vert_factor *= -1.0; + } + else + { + dy = -vert_add; + } + + // allocates a new image with the new size + + bool sixteenBit = m_orgImage.sixteenBit(); + + m_destImage = Digikam::DImg(new_width, new_height, sixteenBit, m_orgImage.hasAlpha()); + m_destImage.fill( Digikam::DColor(m_backgroundColor.rgb(), sixteenBit) ); + + uchar *pResBits = m_destImage.bits(); + unsigned short *pResBits16 = (unsigned short *)m_destImage.bits(); + + Digikam::DImgImageFilters filters; + + for( y = 0; y < new_height; y++) + { + for( x = 0; x < new_width; x++, p += 4 ) + { + // get new positions + nx = x + dx + y * horz_factor; + ny = y + dy + x * vert_factor; + + // if is inside the source image + if (isInside (nWidth, nHeight, ROUND( nx ), ROUND( ny ))) + { + if( m_antiAlias ) + { + if (!sixteenBit) + filters.pixelAntiAliasing(pBits, nWidth, nHeight, nx, ny, + &pResBits[p+3], &pResBits[p+2], + &pResBits[p+1], &pResBits[p]); + else + filters.pixelAntiAliasing16(pBits16, nWidth, nHeight, nx, ny, + &pResBits16[p+3], &pResBits16[p+2], + &pResBits16[p+1], &pResBits16[p]); + } + else + { + pt = setPosition (nWidth, ROUND( nx ), ROUND( ny )); + + for (int z = 0 ; z < 4 ; z++) + { + if (!sixteenBit) + pResBits[p+z] = pBits[pt+z]; + else + pResBits16[p+z] = pBits16[pt+z]; + } + } + } + } + + // Update the progress bar in dialog. + progress = (int)(((double)y * 100.0) / new_height); + if (progress%5 == 0) + postProgress( progress ); + } + + // To compute the rotated destination image size using original image dimensions. + int W = (int)(fabs(m_orgH * ( ( m_hAngle < 0.0 ) ? sin( horz_beta_angle ) : cos( horz_beta_angle ))))+ + m_orgW; + int H = (int)(fabs(m_orgW * ( ( m_vAngle < 0.0 ) ? sin( vert_beta_angle ) : cos( vert_beta_angle ))))+ + m_orgH; + + m_newSize.setWidth(W); + m_newSize.setHeight(H); +} + +} // NameSpace DigikamShearToolImagesPlugin diff --git a/src/imageplugins/sheartool/shear.h b/src/imageplugins/sheartool/shear.h new file mode 100644 index 00000000..480d1084 --- /dev/null +++ b/src/imageplugins/sheartool/shear.h @@ -0,0 +1,84 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-07-18 + * Description : Shear threaded image filter. + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +#ifndef SHEAR_H +#define SHEAR_H + +// TQt includes. + +#include <tqsize.h> +#include <tqcolor.h> + +// Digikam includes. + +#include "dimgthreadedfilter.h" + +namespace DigikamShearToolImagesPlugin +{ + +class Shear : public Digikam::DImgThreadedFilter +{ + +public: + + Shear(Digikam::DImg *orgImage, TQObject *parent=0, float hAngle=0.0, float vAngle=0.0, + bool antialiasing=true, TQColor backgroundColor=TQt::black, int orgW=0, int orgH=0); + + ~Shear(){}; + + TQSize getNewSize(void){ return m_newSize; }; + +private: + + virtual void filterImage(void); + + inline int setPosition (int Width, int X, int Y) + { + return (Y *Width*4 + 4*X); + }; + + inline bool isInside (int Width, int Height, int X, int Y) + { + bool bIsWOk = ((X < 0) ? false : (X >= Width ) ? false : true); + bool bIsHOk = ((Y < 0) ? false : (Y >= Height) ? false : true); + return (bIsWOk && bIsHOk); + }; + +private: + + bool m_antiAlias; + + int m_orgW; + int m_orgH; + + float m_hAngle; + float m_vAngle; + + TQColor m_backgroundColor; + + TQSize m_newSize; +}; + +} // NameSpace DigikamShearToolImagesPlugin + +#endif /* SHEAR_H */ diff --git a/src/imageplugins/sheartool/sheartool.cpp b/src/imageplugins/sheartool/sheartool.cpp new file mode 100644 index 00000000..9f65b6d3 --- /dev/null +++ b/src/imageplugins/sheartool/sheartool.cpp @@ -0,0 +1,331 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-23 + * Description : a plugin to shear an image + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqcheckbox.h> +#include <tqimage.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <kseparator.h> +#include <kstandarddirs.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "dimg.h" +#include "editortoolsettings.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "shear.h" +#include "sheartool.h" +#include "sheartool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamShearToolImagesPlugin +{ + +ShearTool::ShearTool(TQObject* parent) + : EditorToolThreaded(parent) +{ + setName("sheartool"); + setToolName(i18n("Shear Tool")); + setToolIcon(SmallIcon("sheartool")); + + m_previewWidget = new ImageWidget("sheartool Tool", 0, + i18n("<p>This is the shear operation preview. " + "If you move the mouse cursor on this preview, " + "a vertical and horizontal dashed line will be drawn " + "to guide you in adjusting the shear correction. " + "Release the left mouse button to freeze the dashed " + "line's position."), + false, ImageGuideWidget::HVGuideMode); + + setToolView(m_previewWidget); + + // ------------------------------------------------------------- + + TQString temp; + Digikam::ImageIface iface(0, 0); + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel, + EditorToolSettings::ColorGuide); + TQGridLayout* grid = new TQGridLayout(m_gboxSettings->plainPage(), 12, 2); + + TQLabel *label1 = new TQLabel(i18n("New width:"), m_gboxSettings->plainPage()); + m_newWidthLabel = new TQLabel(temp.setNum( iface.originalWidth()) + i18n(" px"), m_gboxSettings->plainPage()); + m_newWidthLabel->setAlignment( AlignBottom | AlignRight ); + + TQLabel *label2 = new TQLabel(i18n("New height:"), m_gboxSettings->plainPage()); + m_newHeightLabel = new TQLabel(temp.setNum( iface.originalHeight()) + i18n(" px"), m_gboxSettings->plainPage()); + m_newHeightLabel->setAlignment( AlignBottom | AlignRight ); + + KSeparator *line = new KSeparator(Horizontal, m_gboxSettings->plainPage()); + + TQLabel *label3 = new TQLabel(i18n("Main horizontal angle:"), m_gboxSettings->plainPage()); + m_mainHAngleInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_mainHAngleInput->setRange(-45, 45, 1); + m_mainHAngleInput->setDefaultValue(0); + TQWhatsThis::add( m_mainHAngleInput, i18n("<p>The main horizontal shearing angle, in degrees.")); + + TQLabel *label4 = new TQLabel(i18n("Fine horizontal angle:"), m_gboxSettings->plainPage()); + m_fineHAngleInput = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_fineHAngleInput->setRange(-5.0, 5.0, 0.01); + m_fineHAngleInput->setDefaultValue(0); + TQWhatsThis::add( m_fineHAngleInput, i18n("<p>This value in degrees will be added to main horizontal angle value " + "to set fine adjustments.")); + + TQLabel *label5 = new TQLabel(i18n("Main vertical angle:"), m_gboxSettings->plainPage()); + m_mainVAngleInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_mainVAngleInput->setRange(-45, 45, 1); + m_mainVAngleInput->setDefaultValue(0); + TQWhatsThis::add( m_mainVAngleInput, i18n("<p>The main vertical shearing angle, in degrees.")); + + TQLabel *label6 = new TQLabel(i18n("Fine vertical angle:"), m_gboxSettings->plainPage()); + m_fineVAngleInput = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_fineVAngleInput->setRange(-5.0, 5.0, 0.01); + m_fineVAngleInput->setDefaultValue(0); + TQWhatsThis::add( m_fineVAngleInput, i18n("<p>This value in degrees will be added to main vertical angle value " + "to set fine adjustments.")); + + m_antialiasInput = new TQCheckBox(i18n("Anti-Aliasing"), m_gboxSettings->plainPage()); + TQWhatsThis::add( m_antialiasInput, i18n("<p>Enable this option to apply the anti-aliasing filter " + "to the sheared image. " + "To smooth the target image, it will be blurred a little.")); + + grid->addMultiCellWidget(label1, 0, 0, 0, 0); + grid->addMultiCellWidget(m_newWidthLabel, 0, 0, 1, 2); + grid->addMultiCellWidget(label2, 1, 1, 0, 0); + grid->addMultiCellWidget(m_newHeightLabel, 1, 1, 1, 2); + grid->addMultiCellWidget(line, 2, 2, 0, 2); + grid->addMultiCellWidget(label3, 3, 3, 0, 2); + grid->addMultiCellWidget(m_mainHAngleInput, 4, 4, 0, 2); + grid->addMultiCellWidget(label4, 5, 5, 0, 2); + grid->addMultiCellWidget(m_fineHAngleInput, 6, 6, 0, 2); + grid->addMultiCellWidget(label5, 7, 7, 0, 0); + grid->addMultiCellWidget(m_mainVAngleInput, 8, 8, 0, 2); + grid->addMultiCellWidget(label6, 9, 9, 0, 2); + grid->addMultiCellWidget(m_fineVAngleInput, 10, 10, 0, 2); + grid->addMultiCellWidget(m_antialiasInput, 11, 11, 0, 2); + grid->setRowStretch(12, 10); + grid->setMargin(m_gboxSettings->spacingHint()); + grid->setSpacing(m_gboxSettings->spacingHint()); + + setToolSettings(m_gboxSettings); + init(); + + // ------------------------------------------------------------- + + connect(m_mainHAngleInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_fineHAngleInput, TQ_SIGNAL(valueChanged(double)), + this, TQ_SLOT(slotTimer())); + + connect(m_mainVAngleInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_fineVAngleInput, TQ_SIGNAL(valueChanged(double)), + this, TQ_SLOT(slotTimer())); + + connect(m_antialiasInput, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotEffect())); + + connect(m_gboxSettings, TQ_SIGNAL(signalColorGuideChanged()), + this, TQ_SLOT(slotColorGuideChanged())); +} + +ShearTool::~ShearTool() +{ +} + +void ShearTool::slotColorGuideChanged() +{ + m_previewWidget->slotChangeGuideColor(m_gboxSettings->guideColor()); + m_previewWidget->slotChangeGuideSize(m_gboxSettings->guideSize()); +} + +void ShearTool::readSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("sheartool Tool"); + m_mainHAngleInput->setValue(config->readNumEntry("Main HAngle", m_mainHAngleInput->defaultValue())); + m_mainVAngleInput->setValue(config->readNumEntry("Main VAngle", m_mainVAngleInput->defaultValue())); + m_fineHAngleInput->setValue(config->readDoubleNumEntry("Fine HAngle", m_fineHAngleInput->defaultValue())); + m_fineVAngleInput->setValue(config->readDoubleNumEntry("Fine VAngle", m_fineVAngleInput->defaultValue())); + m_antialiasInput->setChecked(config->readBoolEntry("Anti Aliasing", true)); + m_gboxSettings->setGuideColor(config->readColorEntry("Guide Color", &TQt::red)); + m_gboxSettings->setGuideSize(config->readNumEntry("Guide Width", 1)); + + slotColorGuideChanged(); + slotEffect(); +} + +void ShearTool::writeSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("sheartool Tool"); + config->writeEntry("Main HAngle", m_mainHAngleInput->value()); + config->writeEntry("Main VAngle", m_mainVAngleInput->value()); + config->writeEntry("Fine HAngle", m_fineHAngleInput->value()); + config->writeEntry("Fine VAngle", m_fineVAngleInput->value()); + config->writeEntry("Anti Aliasing", m_antialiasInput->isChecked()); + config->writeEntry("Guide Color", m_gboxSettings->guideColor()); + config->writeEntry("Guide Width", m_gboxSettings->guideSize()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void ShearTool::slotResetSettings() +{ + m_mainHAngleInput->blockSignals(true); + m_mainVAngleInput->blockSignals(true); + m_fineHAngleInput->blockSignals(true); + m_fineVAngleInput->blockSignals(true); + m_antialiasInput->blockSignals(true); + + m_mainHAngleInput->slotReset(); + m_mainVAngleInput->slotReset(); + m_fineHAngleInput->slotReset(); + m_fineVAngleInput->slotReset(); + m_antialiasInput->setChecked(true); + + m_mainHAngleInput->blockSignals(false); + m_mainVAngleInput->blockSignals(false); + m_fineHAngleInput->blockSignals(false); + m_fineVAngleInput->blockSignals(false); + m_antialiasInput->blockSignals(false); +} + +void ShearTool::prepareEffect() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + m_mainHAngleInput->setEnabled(false); + m_mainVAngleInput->setEnabled(false); + m_fineHAngleInput->setEnabled(false); + m_fineVAngleInput->setEnabled(false); + m_antialiasInput->setEnabled(false); + + float hAngle = m_mainHAngleInput->value() + m_fineHAngleInput->value(); + float vAngle = m_mainVAngleInput->value() + m_fineVAngleInput->value(); + bool antialiasing = m_antialiasInput->isChecked(); + TQColor background = m_previewWidget->paletteBackgroundColor().rgb(); + ImageIface* iface = m_previewWidget->imageIface(); + int orgW = iface->originalWidth(); + int orgH = iface->originalHeight(); + uchar *data = iface->getPreviewImage(); + DImg image(iface->previewWidth(), iface->previewHeight(), iface->previewSixteenBit(), + iface->previewHasAlpha(), data); + delete [] data; + + setFilter(dynamic_cast<DImgThreadedFilter*>(new Shear(&image, this, hAngle, vAngle, antialiasing, + background, orgW, orgH))); +} + +void ShearTool::prepareFinal() +{ + m_mainHAngleInput->setEnabled(false); + m_mainVAngleInput->setEnabled(false); + m_fineHAngleInput->setEnabled(false); + m_fineVAngleInput->setEnabled(false); + m_antialiasInput->setEnabled(false); + + float hAngle = m_mainHAngleInput->value() + m_fineHAngleInput->value(); + float vAngle = m_mainVAngleInput->value() + m_fineVAngleInput->value(); + bool antialiasing = m_antialiasInput->isChecked(); + TQColor background = TQt::black; + + ImageIface iface(0, 0); + int orgW = iface.originalWidth(); + int orgH = iface.originalHeight(); + + uchar *data = iface.getOriginalImage(); + DImg orgImage(orgW, orgH, iface.originalSixteenBit(), iface.originalHasAlpha(), data); + delete [] data; + + setFilter(dynamic_cast<DImgThreadedFilter*>(new Shear(&orgImage, this, hAngle, vAngle, antialiasing, + background, orgW, orgH))); +} + +void ShearTool::putPreviewData() +{ + ImageIface* iface = m_previewWidget->imageIface(); + int w = iface->previewWidth(); + int h = iface->previewHeight(); + DImg imTemp = filter()->getTargetImage().smoothScale(w, h, TQSize::ScaleMin); + DImg imDest( w, h, filter()->getTargetImage().sixteenBit(), + filter()->getTargetImage().hasAlpha() ); + + imDest.fill(DColor(m_previewWidget->paletteBackgroundColor().rgb(), + filter()->getTargetImage().sixteenBit()) ); + imDest.bitBltImage(&imTemp, (w-imTemp.width())/2, (h-imTemp.height())/2); + + iface->putPreviewImage((imDest.smoothScale(iface->previewWidth(), + iface->previewHeight())).bits()); + + m_previewWidget->updatePreview(); + TQSize newSize = dynamic_cast<Shear*>(filter())->getNewSize(); + TQString temp; + m_newWidthLabel->setText(temp.setNum( newSize.width()) + i18n(" px") ); + m_newHeightLabel->setText(temp.setNum( newSize.height()) + i18n(" px") ); +} + +void ShearTool::putFinalData() +{ + ImageIface iface(0, 0); + DImg targetImage = filter()->getTargetImage(); + iface.putOriginalImage(i18n("Shear Tool"), + targetImage.bits(), + targetImage.width(), targetImage.height()); +} + +void ShearTool::renderingFinished() +{ + m_mainHAngleInput->setEnabled(true); + m_mainVAngleInput->setEnabled(true); + m_fineHAngleInput->setEnabled(true); + m_fineVAngleInput->setEnabled(true); + m_antialiasInput->setEnabled(true); + kapp->restoreOverrideCursor(); +} + +} // NameSpace DigikamShearToolImagesPlugin diff --git a/src/imageplugins/sheartool/sheartool.h b/src/imageplugins/sheartool/sheartool.h new file mode 100644 index 00000000..1c8161b4 --- /dev/null +++ b/src/imageplugins/sheartool/sheartool.h @@ -0,0 +1,96 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-23 + * Description : a plugin to shear an image + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef SHEARTOOL_H +#define SHEARTOOL_H + +// Local includes. + +#include "editortool.h" + +class TQFrame; +class TQPushButton; +class TQCheckBox; +class TQLabel; + +namespace KDcrawIface +{ +class RIntNumInput; +class RDoubleNumInput; +} + +namespace Digikam +{ +class EditorToolSettings; +class ImageWidget; +} + +namespace DigikamShearToolImagesPlugin +{ + +class ShearTool : public Digikam::EditorToolThreaded +{ + TQ_OBJECT + + +public: + + ShearTool(TQObject* parent); + ~ShearTool(); + +private slots: + + void slotResetSettings(); + void slotColorGuideChanged(); + +private: + + void readSettings(); + void writeSettings(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + TQLabel *m_newWidthLabel; + TQLabel *m_newHeightLabel; + + TQCheckBox *m_antialiasInput; + + KDcrawIface::RIntNumInput *m_mainHAngleInput; + KDcrawIface::RIntNumInput *m_mainVAngleInput; + + KDcrawIface::RDoubleNumInput *m_fineHAngleInput; + KDcrawIface::RDoubleNumInput *m_fineVAngleInput; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamShearToolImagesPlugin + +#endif /* SHEARTOOL_H */ diff --git a/src/imageplugins/superimpose/Makefile.am b/src/imageplugins/superimpose/Makefile.am new file mode 100644 index 00000000..686eff2a --- /dev/null +++ b/src/imageplugins/superimpose/Makefile.am @@ -0,0 +1,35 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/libs/thumbbar \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_superimpose_la_SOURCES = superimposewidget.cpp superimpose.cpp dirselectwidget.cpp \ + imageplugin_superimpose.cpp superimposetool.cpp + + +digikamimageplugin_superimpose_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_superimpose_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_superimpose.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_superimpose.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_superimpose_ui.rc diff --git a/src/imageplugins/superimpose/digikamimageplugin_superimpose.desktop b/src/imageplugins/superimpose/digikamimageplugin_superimpose.desktop new file mode 100644 index 00000000..ef395a4a --- /dev/null +++ b/src/imageplugins/superimpose/digikamimageplugin_superimpose.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Name=ImagePlugin_SuperImpose +Name[bg]=Приставка за снимки - Налагане +Name[da]=Billedplugin_Indkopiering +Name[el]=ΠρόσθετοΕικόνας_Υπερέκθεση +Name[fi]=SuperImpose +Name[hr]=Presvlačenje +Name[it]=PluginImmagini_Sovrapposizione +Name[nl]=Afbeeldingsplugin_SjabloonAanbrengen +Name[sr]=Надоградња +Name[sr@Latn]=Nadogradnja +Name[sv]=Insticksprogram för överlagring +Name[tr]=ResimEklentisi_Büyüt +Name[xx]=xxImagePlugin_SuperImposexx + +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=Template superimpose plugin for digiKam +Comment[bg]=Приставка на digiKam за налагане на снимки една върху друга +Comment[ca]=Connector pel digiKam per sobreimposar una plantilla +Comment[da]=Plugin til skabelon-indkopiering i Digikam +Comment[de]=digiKam-Modul zum Anwenden von Schablonen auf ein Bild +Comment[el]=Πρόσθετο πρότυπης υπερέκθεσης για το digiKam +Comment[es]=Plugin de digiKam para superponer una plantilla sobre la imagen +Comment[et]=DigiKami pildile malli lisamise plugin +Comment[fa]=وصلۀ افزودن قالب برای digiKam +Comment[fi]=Liittää useampia kuvia päällekäin +Comment[gl]=Un plugin de digiKam para sobrepor modelos +Comment[hr]=digiKam dodatak za presvlačenje predloškom +Comment[is]=Íforrit fyrir digiKam sem hleður forsniðinni mynd ofan á þá sem unnið er með +Comment[it]=Plugin di sovrapposizione di modelli per digiKam +Comment[ja]=digiKam テンプレート重ね合わせプラグイン +Comment[ms]=Templat plugin superimpose untuk digiKam +Comment[nds]=digiKam-Moduul för't Vörblennen vun Vörlagen +Comment[nl]=Digikam-plugin voor het aanbrengen van een sjabloon op de afbeelding +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਨਮੂਨਾ ਸੁਪਰ-ਇਮਪੋਜ਼ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam umożliwiająca nałożenie szablonu na obraz +Comment[pt]=Um 'plugin' do digiKam para sobrepor modelos +Comment[pt_BR]=Um 'plugin' do digiKam para sobrepor modelos +Comment[ru]=Модуль накладывания шаблона для digiKam +Comment[sk]=digiKam plugin pre prekrytie fotografie šablónou +Comment[sr]=digiKam-ов прикључак надоградњу шаблонима +Comment[sr@Latn]=digiKam-ov priključak nadogradnju šablonima +Comment[sv]=Digikam insticksprogram för överlagringsmall +Comment[tr]=digiKam için şablon büyütme eklentisi +Comment[uk]=Втулок накладання шаблону для digiKam +Comment[vi]=Phần bổ sung đặt biểu mẫu trên cho digiKam +Comment[xx]=xxTemplate superimpose plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_superimpose +author=Gilles Caulier, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/superimpose/digikamimageplugin_superimpose_ui.rc b/src/imageplugins/superimpose/digikamimageplugin_superimpose_ui.rc new file mode 100644 index 00000000..ced7edac --- /dev/null +++ b/src/imageplugins/superimpose/digikamimageplugin_superimpose_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="4" name="digikamimageplugin_superimpose" > + + <MenuBar> + + <Menu name="Decorate" ><text>&Decorate</text> + <Action name="imageplugin_superimpose" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action shortcut="" name="imageplugin_superimpose" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/superimpose/dirselectwidget.cpp b/src/imageplugins/superimpose/dirselectwidget.cpp new file mode 100644 index 00000000..4856d73c --- /dev/null +++ b/src/imageplugins/superimpose/dirselectwidget.cpp @@ -0,0 +1,182 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-04 + * Description : a Digikam image editor plugin for superimpose a + * template to an image. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <tqlayout.h> +#include <tqheader.h> +#include <tqlistview.h> +#include <tqdir.h> + +// KDE includes. + +#include <tdelocale.h> + +// Local includes. + +#include "ddebug.h" +#include "dirselectwidget.h" +#include "dirselectwidget.moc" + +namespace DigikamSuperImposeImagesPlugin +{ + +struct DirSelectWidget::Private +{ + KFileTreeBranch* m_item; + TQStringList m_pendingPath; + TQString m_handled; + KURL m_rootUrl; +}; + +DirSelectWidget::DirSelectWidget(TQWidget* parent, const char* name, TQString headerLabel) + : KFileTreeView( parent, name) +{ + d = new Private; + + addColumn( headerLabel ); + + if ( headerLabel.isNull() ) + header()->hide(); + + setAlternateBackground(TQColor()); +} + +DirSelectWidget::DirSelectWidget(KURL rootUrl, KURL currentUrl, + TQWidget* parent, const char* name, TQString headerLabel) + : KFileTreeView( parent, name) +{ + d = new Private; + + addColumn( headerLabel ); + + if ( headerLabel.isNull() ) + header()->hide(); + + setAlternateBackground(TQColor()); + setRootPath(rootUrl, currentUrl); +} + +DirSelectWidget::~DirSelectWidget() +{ + delete d; +} + +KURL DirSelectWidget::path() const +{ + return currentURL(); +} + +void DirSelectWidget::load() +{ + if ( d->m_pendingPath.isEmpty() ) + { + disconnect( d->m_item, TQ_SIGNAL( populateFinished(KFileTreeViewItem *) ), + this, TQ_SLOT( load() ) ); + + emit folderItemSelected(currentURL()); + return; + } + + TQString item = d->m_pendingPath.front(); + d->m_pendingPath.pop_front(); + d->m_handled += item; + KFileTreeViewItem* branch = findItem( d->m_item, d->m_handled ); + + if ( !branch ) + { + DDebug() << "Unable to open " << d->m_handled << endl; + } + else + { + branch->setOpen( true ); + setSelected( branch, true ); + ensureItemVisible ( branch ); + d->m_handled += '/'; + + if ( branch->alreadyListed() ) + load(); + } +} + +void DirSelectWidget::setCurrentPath(KURL currentUrl) +{ + if ( !currentUrl.isValid() ) + return; + + TQString currentPath = TQDir::cleanDirPath(currentUrl.path()); + currentPath = currentPath.mid( d->m_rootUrl.path().length() ); + d->m_pendingPath.clear(); + d->m_handled = TQString(""); + d->m_pendingPath = TQStringList::split( "/", currentPath, true ); + + if ( !d->m_pendingPath[0].isEmpty() ) + d->m_pendingPath.prepend( "" ); // ensure we open the root first. + + connect( d->m_item, TQ_SIGNAL( populateFinished(KFileTreeViewItem *) ), + this, TQ_SLOT( load() ) ); + load(); +} + +void DirSelectWidget::setRootPath(KURL rootUrl, KURL currentUrl) +{ + d->m_rootUrl = rootUrl; + clear(); + TQString root = TQDir::cleanDirPath(rootUrl.path()); + + if ( !root.endsWith("/")) + root.append("/"); + + TQString currentPath = TQDir::cleanDirPath(currentUrl.isValid() ? currentUrl.path() : root); + + d->m_item = addBranch( rootUrl, rootUrl.fileName() ); + setDirOnlyMode( d->m_item, true ); + currentPath = currentPath.mid( root.length() ); + d->m_pendingPath = TQStringList::split( "/", currentPath, true ); + + if ( !d->m_pendingPath[0].isEmpty() ) + d->m_pendingPath.prepend( "" ); // ensure we open the root first. + + connect( d->m_item, TQ_SIGNAL( populateFinished(KFileTreeViewItem *) ), + this, TQ_SLOT( load() ) ); + + load(); + + connect( this, TQ_SIGNAL( executed(TQListViewItem *) ), + this, TQ_SLOT( slotFolderSelected(TQListViewItem *) ) ); +} + +KURL DirSelectWidget::rootPath(void) +{ + return d->m_rootUrl; +} + +void DirSelectWidget::slotFolderSelected(TQListViewItem *) +{ + emit folderItemSelected(currentURL()); +} + +} // NameSpace DigikamSuperImposeImagesPlugin + diff --git a/src/imageplugins/superimpose/dirselectwidget.h b/src/imageplugins/superimpose/dirselectwidget.h new file mode 100644 index 00000000..1ee4abc2 --- /dev/null +++ b/src/imageplugins/superimpose/dirselectwidget.h @@ -0,0 +1,78 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-04 + * Description : a Digikam image editor plugin for superimpose a + * template to an image. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef DIRSELECTWIDGET_H +#define DIRSELECTWIDGET_H + +// TQt includes. + +#include <tqwidget.h> +#include <tqstring.h> + +// KDE includes. + +#include <tdefiletreeview.h> +#include <kurl.h> + +namespace DigikamSuperImposeImagesPlugin +{ + +class DirSelectWidget : public KFileTreeView +{ +TQ_OBJECT + + +public: + + DirSelectWidget(TQWidget* parent, const char* name=0, TQString headerLabel=TQString()); + + DirSelectWidget(KURL rootUrl=KURL("/"), KURL currentUrl=KURL(), + TQWidget* parent=0, const char* name=0, TQString headerLabel=TQString()); + + ~DirSelectWidget(); + + KURL path() const; + KURL rootPath(void); + void setRootPath(KURL rootUrl, KURL currentUrl=KURL(TQString())); + void setCurrentPath(KURL currentUrl); + +signals : + + void folderItemSelected(const KURL &url); + +protected slots: + + void load(); + void slotFolderSelected(TQListViewItem *); + +private: + + struct Private; + Private* d; +}; + +} // NameSpace DigikamSuperImposeImagesPlugin + +#endif /* DIRSELECTWIDGET_H */ diff --git a/src/imageplugins/superimpose/imageeffect_superimpose.cpp b/src/imageplugins/superimpose/imageeffect_superimpose.cpp new file mode 100644 index 00000000..1cea3e08 --- /dev/null +++ b/src/imageplugins/superimpose/imageeffect_superimpose.cpp @@ -0,0 +1,280 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-04 + * Description : a Digikam image editor plugin for superimpose a + * template to an image. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <tqvgroupbox.h> +#include <tqgroupbox.h> +#include <tqlabel.h> +#include <tqpushbutton.h> +#include <tqpixmap.h> +#include <tqwhatsthis.h> +#include <tqtooltip.h> +#include <tqlayout.h> +#include <tqframe.h> +#include <tqdir.h> +#include <tqfile.h> +#include <tqhbuttongroup.h> + +// KDE includes. + +#include <kcursor.h> +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <khelpmenu.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <tdepopupmenu.h> +#include <kstandarddirs.h> +#include <kprogress.h> +#include <knuminput.h> +#include <kiconloader.h> +#include <tdefiledialog.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <tdeglobalsettings.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "thumbbar.h" +#include "superimposewidget.h" +#include "dirselectwidget.h" +#include "imageeffect_superimpose.h" +#include "imageeffect_superimpose.moc" + +namespace DigikamSuperImposeImagesPlugin +{ + +ImageEffect_SuperImpose::ImageEffect_SuperImpose(TQWidget* parent) + : Digikam::ImageDlgBase(parent, i18n("Template Superimpose to Photograph"), + "superimpose", false, false) +{ + TQString whatsThis; + + // About data and help button. + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Template Superimpose"), + digikam_version, + I18N_NOOP("A digiKam image plugin to superimpose a template onto a photograph."), + TDEAboutData::License_GPL, + "(c) 2005-2006, Gilles Caulier\n" + "(c) 2006-2008, Gilles Caulier and Marcel Wiesweg", + 0, + "http://www.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + about->addAuthor("Marcel Wiesweg", I18N_NOOP("Developer"), + "marcel dot wiesweg at gmx dot de"); + + setAboutData(about); + + // ------------------------------------------------------------- + + TQFrame *frame = new TQFrame(plainPage()); + frame->setFrameStyle(TQFrame::Panel|TQFrame::Sunken); + + TQGridLayout* gridFrame = new TQGridLayout( frame, 1, 2, spacingHint()); + m_previewWidget = new SuperImposeWidget(400, 300, frame); + gridFrame->addMultiCellWidget(m_previewWidget, 0, 0, 0, 2); + gridFrame->setRowStretch(0, 10); + TQWhatsThis::add( m_previewWidget, i18n("<p>This is the preview of the template " + "superimposed onto the image.") ); + + // ------------------------------------------------------------- + + TQHButtonGroup *bGroup = new TQHButtonGroup(frame); + TDEIconLoader icon; + bGroup->addSpace(0); + TQPushButton *zoomInButton = new TQPushButton( bGroup ); + bGroup->insert(zoomInButton, ZOOMIN); + zoomInButton->setPixmap( icon.loadIcon( "zoom-in", (TDEIcon::Group)TDEIcon::Toolbar ) ); + zoomInButton->setToggleButton(true); + TQToolTip::add( zoomInButton, i18n( "Zoom in" ) ); + bGroup->addSpace(20); + TQPushButton *zoomOutButton = new TQPushButton( bGroup ); + bGroup->insert(zoomOutButton, ZOOMOUT); + zoomOutButton->setPixmap( icon.loadIcon( "zoom-out", (TDEIcon::Group)TDEIcon::Toolbar ) ); + zoomOutButton->setToggleButton(true); + TQToolTip::add( zoomOutButton, i18n( "Zoom out" ) ); + bGroup->addSpace(20); + TQPushButton *moveButton = new TQPushButton( bGroup ); + bGroup->insert(moveButton, MOVE); + moveButton->setPixmap( icon.loadIcon( "move", (TDEIcon::Group)TDEIcon::Toolbar ) ); + moveButton->setToggleButton(true); + moveButton->setOn(true); + TQToolTip::add( moveButton, i18n( "Move" ) ); + bGroup->addSpace(20); + bGroup->setExclusive(true); + bGroup->setFrameShape(TQFrame::NoFrame); + gridFrame->addMultiCellWidget(bGroup, 1, 1, 1, 1); + gridFrame->setColStretch(0, 10); + gridFrame->setColStretch(2, 10); + + setPreviewAreaWidget(frame); + + // ------------------------------------------------------------- + + TQWidget *gbox2 = new TQWidget(plainPage()); + TQGridLayout* grid = new TQGridLayout( gbox2, 1, 1, marginHint(), spacingHint()); + + m_thumbnailsBar = new Digikam::ThumbBarView(gbox2); + m_dirSelect = new DirSelectWidget(gbox2); + TQPushButton *templateDirButton = new TQPushButton( i18n("Root Directory..."), gbox2 ); + TQWhatsThis::add( templateDirButton, i18n("<p>Set here the current templates' root directory.") ); + + grid->addMultiCellWidget(m_thumbnailsBar, 0, 1, 0, 0); + grid->addMultiCellWidget(m_dirSelect, 0, 0, 1, 1); + grid->addMultiCellWidget(templateDirButton, 1, 1, 1, 1); + grid->setColStretch(1, 10); + + setUserAreaWidget(gbox2); + + // ------------------------------------------------------------- + + connect(bGroup, TQ_SIGNAL(released(int)), + m_previewWidget, TQ_SLOT(slotEditModeChanged(int))); + + connect(m_thumbnailsBar, TQ_SIGNAL(signalURLSelected(const KURL&)), + m_previewWidget, TQ_SLOT(slotSetCurrentTemplate(const KURL&))); + + connect(m_dirSelect, TQ_SIGNAL(folderItemSelected(const KURL &)), + this, TQ_SLOT(slotTemplateDirChanged(const KURL &))); + + connect(templateDirButton, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotRootTemplateDirChanged())); + + // ------------------------------------------------------------- + + populateTemplates(); +} + +ImageEffect_SuperImpose::~ImageEffect_SuperImpose() +{ +} + +void ImageEffect_SuperImpose::populateTemplates(void) +{ + m_thumbnailsBar->clear(true); + + if (!m_templatesUrl.isValid() || !m_templatesUrl.isLocalFile()) + return; + + TQDir dir(m_templatesUrl.path(), "*.png *.PNG"); + + if (!dir.exists()) + return; + + dir.setFilter ( TQDir::Files | TQDir::NoSymLinks ); + + const TQFileInfoList* fileinfolist = dir.entryInfoList(); + if (!fileinfolist) + return; + + TQFileInfoListIterator it(*fileinfolist); + TQFileInfo* fi; + + while( (fi = it.current() ) ) + { + new Digikam::ThumbBarItem( m_thumbnailsBar, KURL(fi->filePath()) ); + ++it; + } +} + +void ImageEffect_SuperImpose::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("Album Settings"); + KURL albumDBUrl( config->readPathEntry("Album Path", TDEGlobalSettings::documentPath()) ); + config->setGroup("superimpose Tool Dialog"); + config->setGroup("Template Superimpose Tool Settings"); + m_templatesRootUrl.setPath( config->readEntry("Templates Root URL", albumDBUrl.path()) ); + m_templatesUrl.setPath( config->readEntry("Templates URL", albumDBUrl.path()) ); + m_dirSelect->setRootPath(m_templatesRootUrl, m_templatesUrl); +} + +void ImageEffect_SuperImpose::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("superimpose Tool Dialog"); + config->writeEntry( "Templates Root URL", m_dirSelect->rootPath().path() ); + config->writeEntry( "Templates URL", m_templatesUrl.path() ); + config->sync();} + +void ImageEffect_SuperImpose::resetValues() +{ + m_previewWidget->resetEdit(); +} + +void ImageEffect_SuperImpose::slotRootTemplateDirChanged(void) +{ + KURL url = KFileDialog::getExistingDirectory(m_templatesRootUrl.path(), kapp->activeWindow(), + i18n("Select Template Root Directory to Use")); + + if( url.isValid() ) + { + m_dirSelect->setRootPath(url); + m_templatesRootUrl = url; + m_templatesUrl = url; + populateTemplates(); + } +} + +void ImageEffect_SuperImpose::slotTemplateDirChanged(const KURL& url) +{ + if( url.isValid() ) + { + m_templatesUrl = url; + populateTemplates(); + } +} + +void ImageEffect_SuperImpose::finalRendering() +{ + setCursor(KCursor::waitCursor()); + m_previewWidget->setEnabled(false); + m_dirSelect->setEnabled(false); + m_thumbnailsBar->setEnabled(false); + + Digikam::ImageIface iface(0, 0); + Digikam::DImg img = m_previewWidget->makeSuperImpose(); + iface.putOriginalImage(i18n("Super Impose"), img.bits(), + img.width(), img.height() ); + + m_previewWidget->setEnabled(true); + m_dirSelect->setEnabled(true); + m_thumbnailsBar->setEnabled(true); + unsetCursor(); + accept(); +} + +} // NameSpace DigikamSuperImposeImagesPlugin + diff --git a/src/imageplugins/superimpose/imageeffect_superimpose.h b/src/imageplugins/superimpose/imageeffect_superimpose.h new file mode 100644 index 00000000..8eb8c18f --- /dev/null +++ b/src/imageplugins/superimpose/imageeffect_superimpose.h @@ -0,0 +1,87 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-04 + * Description : a Digikam image editor plugin for superimpose a + * template to an image. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_SUPERIMPOSE_H +#define IMAGEEFFECT_SUPERIMPOSE_H + +// KDE include. + +#include <kurl.h> + +// Digikam includes. + +#include "imagedlgbase.h" + +class TQPushButton; + +namespace Digikam +{ +class ThumbBarView; +} + +namespace DigikamSuperImposeImagesPlugin +{ + +class DirSelectWidget; +class SuperImposeWidget; + +class ImageEffect_SuperImpose : public Digikam::ImageDlgBase +{ + TQ_OBJECT + + +public: + + ImageEffect_SuperImpose(TQWidget* parent); + ~ImageEffect_SuperImpose(); + +private slots: + + void slotTemplateDirChanged(const KURL& url); + void slotRootTemplateDirChanged(void); + +private: + + void readUserSettings(); + void writeUserSettings(); + void resetValues(); + void populateTemplates(void); + void finalRendering(); + +private: + + KURL m_templatesUrl; + KURL m_templatesRootUrl; + + Digikam::ThumbBarView *m_thumbnailsBar; + + SuperImposeWidget *m_previewWidget; + + DirSelectWidget *m_dirSelect; +}; + +} // NameSpace DigikamSuperImposeImagesPlugin + +#endif /* IMAGEEFFECT_SUPERIMPOSE_H */ diff --git a/src/imageplugins/superimpose/imageplugin_superimpose.cpp b/src/imageplugins/superimpose/imageplugin_superimpose.cpp new file mode 100644 index 00000000..ceba44ef --- /dev/null +++ b/src/imageplugins/superimpose/imageplugin_superimpose.cpp @@ -0,0 +1,71 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-04 + * Description : a Digikam image editor plugin for superimpose a + * template to an image. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> + +// Local includes. + +#include "ddebug.h" +#include "superimposetool.h" +#include "imageplugin_superimpose.h" +#include "imageplugin_superimpose.moc" + +using namespace DigikamSuperImposeImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_superimpose, + KGenericFactory<ImagePlugin_SuperImpose>("digikamimageplugin_superimpose")); + +ImagePlugin_SuperImpose::ImagePlugin_SuperImpose(TQObject *parent, const char*, const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_SuperImpose") +{ + m_superimposeAction = new TDEAction(i18n("Template Superimpose..."), "superimpose", 0, + this, TQ_SLOT(slotSuperImpose()), + actionCollection(), "imageplugin_superimpose"); + + setXMLFile("digikamimageplugin_superimpose_ui.rc"); + + DDebug() << "ImagePlugin_SuperImpose plugin loaded" << endl; +} + +ImagePlugin_SuperImpose::~ImagePlugin_SuperImpose() +{ +} + +void ImagePlugin_SuperImpose::setEnabledActions(bool enable) +{ + m_superimposeAction->setEnabled(enable); +} + +void ImagePlugin_SuperImpose::slotSuperImpose() +{ + SuperImposeTool *tool = new SuperImposeTool(this); + loadTool(tool); +} diff --git a/src/imageplugins/superimpose/imageplugin_superimpose.h b/src/imageplugins/superimpose/imageplugin_superimpose.h new file mode 100644 index 00000000..6f3c3a69 --- /dev/null +++ b/src/imageplugins/superimpose/imageplugin_superimpose.h @@ -0,0 +1,58 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-04 + * Description : a Digikam image editor plugin for superimpose a + * template to an image. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_SUPERIMPOSE_H +#define IMAGEPLUGIN_SUPERIMPOSE_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_SuperImpose : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_SuperImpose(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_SuperImpose(); + + void setEnabledActions(bool enable); + +private slots: + + void slotSuperImpose(); + +private: + + TDEAction *m_superimposeAction; +}; + +#endif /* IMAGEPLUGIN_SUPERIMPOSE_H */ diff --git a/src/imageplugins/superimpose/superimpose.cpp b/src/imageplugins/superimpose/superimpose.cpp new file mode 100644 index 00000000..7c0ac74b --- /dev/null +++ b/src/imageplugins/superimpose/superimpose.cpp @@ -0,0 +1,70 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-18-03 + * Description : Superimpose filter. + * + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +// Local includes. + +#include "superimpose.h" + +namespace DigikamSuperImposeImagesPlugin +{ + +SuperImpose::SuperImpose(Digikam::DImg *orgImage, Digikam::DImg *templ, + TQRect orgImageSelection, + Digikam::DColorComposer::CompositingOperation compositeRule) +{ + m_orgImage = *orgImage; + m_template = *templ; + m_selection = orgImageSelection; + m_compositeRule = compositeRule; + + filterImage(); +} + +void SuperImpose::filterImage(void) +{ + if (m_template.isNull()) + return; + + int templateWidth = m_template.width(); + int templateHeight = m_template.height(); + + // take selection of src image and scale it to size of template + m_destImage = m_orgImage.smoothScaleSection(m_selection.x(), m_selection.y(), + m_selection.width(), m_selection.height(), templateWidth, templateHeight); + + // convert depth if necessary + m_template.convertToDepthOfImage(&m_destImage); + + // get composer for compositing rule + Digikam::DColorComposer *composer = Digikam::DColorComposer::getComposer(m_compositeRule); + Digikam::DColorComposer::MultiplicationFlags flags = Digikam::DColorComposer::NoMultiplication; + if (m_compositeRule != Digikam::DColorComposer::PorterDuffNone) + flags = Digikam::DColorComposer::MultiplicationFlagsDImg; + + // do alpha blending of template on dest image + m_destImage.bitBlendImage(composer, &m_template, 0, 0, templateWidth, templateHeight, 0, 0, flags); + + delete composer; +} + +} // namespace DigikamSuperImposeImagesPlugin diff --git a/src/imageplugins/superimpose/superimpose.h b/src/imageplugins/superimpose/superimpose.h new file mode 100644 index 00000000..a0b7b6da --- /dev/null +++ b/src/imageplugins/superimpose/superimpose.h @@ -0,0 +1,67 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-18-03 + * Description : Superimpose filter. + * + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef SUPERIMPOSE_H +#define SUPERIMPOSE_H + +// TQt includes. + +#include <tqrect.h> + +// Digikam includes. + +#include "dimg.h" +#include "dcolor.h" + +namespace DigikamSuperImposeImagesPlugin +{ + +class SuperImpose +{ + +public: + + SuperImpose(Digikam::DImg *orgImage, Digikam::DImg *templ, + TQRect orgImageSelection, + Digikam::DColorComposer::CompositingOperation + compositeRule = Digikam::DColorComposer::PorterDuffNone); + + Digikam::DImg getTargetImage() { return m_destImage; } + +private: + + void filterImage(void); + +private: + + TQRect m_selection; + + Digikam::DImg m_orgImage; + Digikam::DImg m_template; + Digikam::DImg m_destImage; + Digikam::DColorComposer::CompositingOperation m_compositeRule; +}; + +} // namespace DigikamSuperImposeImagesPlugin + +#endif /* SUPERIMPOSE_H */ diff --git a/src/imageplugins/superimpose/superimposetool.cpp b/src/imageplugins/superimpose/superimposetool.cpp new file mode 100644 index 00000000..f035559c --- /dev/null +++ b/src/imageplugins/superimpose/superimposetool.cpp @@ -0,0 +1,271 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-04 + * Description : a Digikam image editor plugin for superimpose a + * template to an image. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <tqvgroupbox.h> +#include <tqgroupbox.h> +#include <tqlabel.h> +#include <tqpushbutton.h> +#include <tqpixmap.h> +#include <tqwhatsthis.h> +#include <tqtooltip.h> +#include <tqlayout.h> +#include <tqframe.h> +#include <tqdir.h> +#include <tqfile.h> +#include <tqhbuttongroup.h> + +// KDE includes. + +#include <kcursor.h> +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <khelpmenu.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <tdepopupmenu.h> +#include <kstandarddirs.h> +#include <kprogress.h> +#include <knuminput.h> +#include <kiconloader.h> +#include <tdefiledialog.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <tdeglobalsettings.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "editortoolsettings.h" +#include "thumbbar.h" +#include "superimposewidget.h" +#include "dirselectwidget.h" +#include "superimposetool.h" +#include "superimposetool.moc" + +using namespace Digikam; + +namespace DigikamSuperImposeImagesPlugin +{ + +SuperImposeTool::SuperImposeTool(TQObject* parent) + : EditorTool(parent) +{ + setName("superimpose"); + setToolName(i18n("Template Superimpose")); + setToolIcon(SmallIcon("superimpose")); + + // ------------------------------------------------------------- + + TQFrame *frame = new TQFrame(0); + frame->setFrameStyle(TQFrame::Panel|TQFrame::Sunken); + + TQGridLayout* gridFrame = new TQGridLayout(frame, 1, 2); + m_previewWidget = new SuperImposeWidget(400, 300, frame); + TQWhatsThis::add( m_previewWidget, i18n("<p>This is the preview of the template " + "superimposed onto the image.") ); + + // ------------------------------------------------------------- + + TQHButtonGroup *bGroup = new TQHButtonGroup(frame); + TDEIconLoader icon; + bGroup->addSpace(0); + TQPushButton *zoomInButton = new TQPushButton( bGroup ); + bGroup->insert(zoomInButton, ZOOMIN); + zoomInButton->setPixmap( icon.loadIcon( "zoom-in", (TDEIcon::Group)TDEIcon::Toolbar ) ); + zoomInButton->setToggleButton(true); + TQToolTip::add( zoomInButton, i18n( "Zoom in" ) ); + bGroup->addSpace(20); + TQPushButton *zoomOutButton = new TQPushButton( bGroup ); + bGroup->insert(zoomOutButton, ZOOMOUT); + zoomOutButton->setPixmap( icon.loadIcon( "zoom-out", (TDEIcon::Group)TDEIcon::Toolbar ) ); + zoomOutButton->setToggleButton(true); + TQToolTip::add( zoomOutButton, i18n( "Zoom out" ) ); + bGroup->addSpace(20); + TQPushButton *moveButton = new TQPushButton( bGroup ); + bGroup->insert(moveButton, MOVE); + moveButton->setPixmap( icon.loadIcon( "move", (TDEIcon::Group)TDEIcon::Toolbar ) ); + moveButton->setToggleButton(true); + moveButton->setOn(true); + TQToolTip::add( moveButton, i18n( "Move" ) ); + bGroup->addSpace(20); + bGroup->setExclusive(true); + bGroup->setFrameShape(TQFrame::NoFrame); + + gridFrame->addMultiCellWidget(m_previewWidget, 0, 0, 0, 2); + gridFrame->addMultiCellWidget(bGroup, 1, 1, 1, 1); + gridFrame->setRowStretch(0, 10); + gridFrame->setColStretch(0, 10); + gridFrame->setColStretch(2, 10); + gridFrame->setMargin(0); + gridFrame->setSpacing(0); + + setToolView(frame); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel); + TQGridLayout* grid = new TQGridLayout(m_gboxSettings->plainPage(), 1, 1); + + m_thumbnailsBar = new ThumbBarView(m_gboxSettings->plainPage()); + m_dirSelect = new DirSelectWidget(m_gboxSettings->plainPage()); + TQPushButton *templateDirButton = new TQPushButton( i18n("Root Directory..."), m_gboxSettings->plainPage() ); + TQWhatsThis::add( templateDirButton, i18n("<p>Set here the current templates' root directory.") ); + + grid->addMultiCellWidget(m_thumbnailsBar, 0, 1, 0, 0); + grid->addMultiCellWidget(m_dirSelect, 0, 0, 1, 1); + grid->addMultiCellWidget(templateDirButton, 1, 1, 1, 1); + grid->setMargin(0); + grid->setSpacing(m_gboxSettings->spacingHint()); + grid->setColStretch(1, 10); + + setToolSettings(m_gboxSettings); + init(); + + // ------------------------------------------------------------- + + connect(bGroup, TQ_SIGNAL(released(int)), + m_previewWidget, TQ_SLOT(slotEditModeChanged(int))); + + connect(m_thumbnailsBar, TQ_SIGNAL(signalURLSelected(const KURL&)), + m_previewWidget, TQ_SLOT(slotSetCurrentTemplate(const KURL&))); + + connect(m_dirSelect, TQ_SIGNAL(folderItemSelected(const KURL &)), + this, TQ_SLOT(slotTemplateDirChanged(const KURL &))); + + connect(templateDirButton, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotRootTemplateDirChanged())); + + // ------------------------------------------------------------- + + populateTemplates(); +} + +SuperImposeTool::~SuperImposeTool() +{ +} + +void SuperImposeTool::populateTemplates() +{ + m_thumbnailsBar->clear(true); + + if (!m_templatesUrl.isValid() || !m_templatesUrl.isLocalFile()) + return; + + TQDir dir(m_templatesUrl.path(), "*.png *.PNG"); + + if (!dir.exists()) + return; + + dir.setFilter ( TQDir::Files | TQDir::NoSymLinks ); + + const TQFileInfoList* fileinfolist = dir.entryInfoList(); + if (!fileinfolist) + return; + + TQFileInfoListIterator it(*fileinfolist); + TQFileInfo* fi; + + while( (fi = it.current() ) ) + { + new ThumbBarItem( m_thumbnailsBar, KURL(fi->filePath()) ); + ++it; + } +} + +void SuperImposeTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("Album Settings"); + KURL albumDBUrl( config->readPathEntry("Album Path", TDEGlobalSettings::documentPath()) ); + config->setGroup("superimpose Tool"); + config->setGroup("Template Superimpose Tool Settings"); + m_templatesRootUrl.setPath( config->readEntry("Templates Root URL", albumDBUrl.path()) ); + m_templatesUrl.setPath( config->readEntry("Templates URL", albumDBUrl.path()) ); + m_dirSelect->setRootPath(m_templatesRootUrl, m_templatesUrl); +} + +void SuperImposeTool::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("superimpose Tool"); + config->writeEntry( "Templates Root URL", m_dirSelect->rootPath().path() ); + config->writeEntry( "Templates URL", m_templatesUrl.path() ); + config->sync(); +} + +void SuperImposeTool::slotResetSettings() +{ + m_previewWidget->resetEdit(); +} + +void SuperImposeTool::slotRootTemplateDirChanged() +{ + KURL url = KFileDialog::getExistingDirectory(m_templatesRootUrl.path(), kapp->activeWindow(), + i18n("Select Template Root Directory to Use")); + + if( url.isValid() ) + { + m_dirSelect->setRootPath(url); + m_templatesRootUrl = url; + m_templatesUrl = url; + populateTemplates(); + } +} + +void SuperImposeTool::slotTemplateDirChanged(const KURL& url) +{ + if( url.isValid() ) + { + m_templatesUrl = url; + populateTemplates(); + } +} + +void SuperImposeTool::finalRendering() +{ + kapp->setOverrideCursor(KCursor::waitCursor()); + m_previewWidget->setEnabled(false); + m_dirSelect->setEnabled(false); + m_thumbnailsBar->setEnabled(false); + + ImageIface iface(0, 0); + DImg img = m_previewWidget->makeSuperImpose(); + iface.putOriginalImage(i18n("Super Impose"), img.bits(), + img.width(), img.height() ); + + m_previewWidget->setEnabled(true); + m_dirSelect->setEnabled(true); + m_thumbnailsBar->setEnabled(true); + kapp->restoreOverrideCursor(); +} + +} // NameSpace DigikamSuperImposeImagesPlugin diff --git a/src/imageplugins/superimpose/superimposetool.h b/src/imageplugins/superimpose/superimposetool.h new file mode 100644 index 00000000..7501f23f --- /dev/null +++ b/src/imageplugins/superimpose/superimposetool.h @@ -0,0 +1,90 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-04 + * Description : a Digikam image editor plugin for superimpose a + * template to an image. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_SUPERIMPOSE_H +#define IMAGEEFFECT_SUPERIMPOSE_H + +// KDE includes. + +#include <kurl.h> + +// Digikam includes. + +#include "editortool.h" + +class TQPushButton; + +namespace Digikam +{ +class ThumbBarView; +class EditorToolSettings; +} + +namespace DigikamSuperImposeImagesPlugin +{ + +class DirSelectWidget; +class SuperImposeWidget; + +class SuperImposeTool : public Digikam::EditorTool +{ + TQ_OBJECT + + +public: + + SuperImposeTool(TQObject* parent); + ~SuperImposeTool(); + +private slots: + + void slotTemplateDirChanged(const KURL& url); + void slotRootTemplateDirChanged(); + void slotResetSettings(); + +private: + + void readSettings(); + void writeSettings(); + void populateTemplates(); + void finalRendering(); + +private: + + KURL m_templatesUrl; + KURL m_templatesRootUrl; + + Digikam::ThumbBarView *m_thumbnailsBar; + + Digikam::EditorToolSettings *m_gboxSettings; + + SuperImposeWidget *m_previewWidget; + + DirSelectWidget *m_dirSelect; +}; + +} // NameSpace DigikamSuperImposeImagesPlugin + +#endif /* IMAGEEFFECT_SUPERIMPOSE_H */ diff --git a/src/imageplugins/superimpose/superimposewidget.cpp b/src/imageplugins/superimpose/superimposewidget.cpp new file mode 100644 index 00000000..edae15aa --- /dev/null +++ b/src/imageplugins/superimpose/superimposewidget.cpp @@ -0,0 +1,329 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-04 + * Description : a Digikam image editor plugin for superimpose a + * template to an image. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <cstdio> + +// TQt includes. + +#include <tqpainter.h> + +// KDE includes. + +#include <kstandarddirs.h> +#include <kcursor.h> +#include <tdeglobal.h> + +// Local includes. + +#include "superimpose.h" +#include "superimposewidget.h" +#include "superimposewidget.moc" + +namespace DigikamSuperImposeImagesPlugin +{ + +SuperImposeWidget::SuperImposeWidget(int w, int h, TQWidget *parent) + : TQWidget(parent, 0, TQt::WDestructiveClose) +{ + m_pixmap = new TQPixmap(w, h); + m_editMode = MOVE; + + Digikam::ImageIface iface(0, 0); + m_w = iface.originalWidth(); + m_h = iface.originalHeight(); + + setBackgroundMode(TQt::NoBackground); + setMinimumSize(w, h); + setMouseTracking(true); + + resetEdit(); +} + +SuperImposeWidget::~SuperImposeWidget() +{ + if(m_pixmap) + delete m_pixmap; +} + +Digikam::DImg SuperImposeWidget::makeSuperImpose(void) +{ + Digikam::ImageIface iface(0, 0); + SuperImpose superimpose(iface.getOriginalImg(), &m_template, m_currentSelection); + return superimpose.getTargetImage(); +} + +void SuperImposeWidget::resetEdit(void) +{ + m_zoomFactor = 1.0; + m_currentSelection = TQRect(m_w/2 - m_rect.width()/2, m_h/2 - m_rect.height()/2, + m_rect.width(), m_rect.height()); + makePixmap(); + repaint(false); +} + +void SuperImposeWidget::makePixmap(void) +{ + Digikam::ImageIface iface(0, 0); + SuperImpose superimpose(iface.getOriginalImg(), &m_templateScaled, m_currentSelection); + Digikam::DImg image = superimpose.getTargetImage(); + + m_pixmap->fill(colorGroup().background()); + TQPainter p(m_pixmap); + TQPixmap imagePix = image.convertToPixmap(); + p.drawPixmap(m_rect.x(), m_rect.y(), imagePix, 0, 0, m_rect.width(), m_rect.height()); + p.end(); +} + +void SuperImposeWidget::resizeEvent(TQResizeEvent * e) +{ + blockSignals(true); + delete m_pixmap; + int w = e->size().width(); + int h = e->size().height(); + m_pixmap = new TQPixmap(w, h); + + if (!m_template.isNull()) + { + int templateWidth = m_template.width(); + int templateHeight = m_template.height(); + + if (templateWidth < templateHeight) + { + int neww = (int) ((float)height() / (float)templateHeight * (float)templateWidth); + m_rect = TQRect(width()/2-neww/2, 0, neww, height()); + } + else + { + int newh = (int) ((float)width() / (float)templateWidth * (float)templateHeight); + m_rect = TQRect(0, height()/2-newh/2, width(), newh); + } + + m_templateScaled = m_template.smoothScale(m_rect.width(), m_rect.height()); + makePixmap(); + } + else + { + m_rect = TQRect(); + m_pixmap->fill(colorGroup().background()); + } + + blockSignals(false); +} + +void SuperImposeWidget::paintEvent( TQPaintEvent * ) +{ + bitBlt(this, 0, 0, m_pixmap); +} + +void SuperImposeWidget::slotEditModeChanged(int mode) +{ + m_editMode = mode; +} + +void SuperImposeWidget::slotSetCurrentTemplate(const KURL& url) +{ + m_template.load(url.path()); + + if (m_template.isNull()) + { + m_rect = TQRect(); + return; + } + + int templateWidth = m_template.width(); + int templateHeight = m_template.height(); + + if (templateWidth < templateHeight) + { + int neww = (int) ((float)height() / (float)templateHeight * (float)templateWidth); + m_rect = TQRect(width()/2-neww/2, 0, neww, height()); + } + else + { + int newh = (int) ((float)width() / (float)templateWidth * (float)templateHeight); + m_rect = TQRect(0, height()/2-newh/2, width(), newh); + } + + m_templateScaled = m_template.smoothScale(m_rect.width(), m_rect.height()); + + m_currentSelection = TQRect(m_w/2 - m_rect.width()/2, m_h/2 - m_rect.height()/2, m_rect.width(), m_rect.height()); + zoomSelection(0); +} + +void SuperImposeWidget::moveSelection(int dx, int dy) +{ + TQRect selection = m_currentSelection; + float wf = (float)selection.width() / (float)m_rect.width(); + float hf = (float)selection.height() / (float)m_rect.height(); + + selection.moveBy( -(int)(wf*(float)dx), -(int)(hf*(float)dy) ); + + if (selection.left() < 0) + selection.moveLeft(0); + if (selection.top() < 0) + selection.moveTop(0); + if (selection.bottom() > m_h) + selection.moveBottom(m_h); + if (selection.right() > m_w) + selection.moveRight(m_w); + + m_currentSelection = selection; +} + +bool SuperImposeWidget::zoomSelection(float deltaZoomFactor) +{ + float newZoom = m_zoomFactor + deltaZoomFactor; + + if (newZoom < 0.0) + return false; + + TQRect selection = m_currentSelection; + int wf = (int)((float)m_rect.width() / newZoom); + int hf = (int)((float)m_rect.height() / newZoom); + int deltaX = (m_currentSelection.width() - wf) / 2; + int deltaY = (m_currentSelection.height() - hf) / 2; + + selection.setLeft(m_currentSelection.left() + deltaX); + selection.setTop(m_currentSelection.top() + deltaY); + selection.setWidth(wf); + selection.setHeight(hf); + + // check that selection is still inside original image + TQRect orgImageRect(0, 0, m_w, m_h); + if (!orgImageRect.contains(selection)) + { + // try to adjust + if (selection.left() < 0) + selection.moveLeft(0); + if (selection.top() < 0) + selection.moveTop(0); + if (selection.bottom() > m_h) + selection.moveBottom(m_h); + if (selection.right() > m_w) + selection.moveRight(m_w); + + // was it successful? + if (selection.contains(orgImageRect)) + return false; + + } + + m_zoomFactor = newZoom; + m_currentSelection = selection; + + makePixmap(); + repaint(false); + + return true; +} + +void SuperImposeWidget::mousePressEvent ( TQMouseEvent * e ) +{ + if ( isEnabled() && e->button() == TQt::LeftButton && + rect().contains( e->x(), e->y() ) ) + { + switch (m_editMode) + { + case ZOOMIN: + if (zoomSelection(+0.05)) + moveSelection(width()/2 - e->x(), height()/2 - e->y()); + break; + + case ZOOMOUT: + if (zoomSelection(-0.05)) + moveSelection(width()/2 - e->x(), height()/2 - e->y()); + break; + + case MOVE: + m_xpos = e->x(); + m_ypos = e->y(); + } + } +} + +void SuperImposeWidget::mouseReleaseEvent ( TQMouseEvent * ) +{ + setEditModeCursor(); +} + +void SuperImposeWidget::mouseMoveEvent ( TQMouseEvent * e ) +{ + if ( isEnabled() ) + { + if ( e->state() == TQt::LeftButton ) + { + switch (m_editMode) + { + case ZOOMIN: + case ZOOMOUT: + break; + + case MOVE: + int newxpos = e->x(); + int newypos = e->y(); + + if (newxpos < m_rect.left()) + newxpos = m_rect.left(); + if (newxpos > m_rect.right()) + newxpos = m_rect.right(); + if (newxpos < m_rect.top()) + newxpos = m_rect.top(); + if (newxpos > m_rect.bottom()) + newxpos = m_rect.bottom(); + + moveSelection(newxpos - m_xpos, newypos - m_ypos); + makePixmap(); + repaint(false); + + m_xpos = newxpos; + m_ypos = newypos; + setCursor( KCursor::handCursor() ); + break; + } + } + else if (rect().contains( e->x(), e->y() )) + { + setEditModeCursor(); + } + } +} + +void SuperImposeWidget::setEditModeCursor() +{ + switch (m_editMode) + { + case ZOOMIN: + case ZOOMOUT: + setCursor ( KCursor::crossCursor() ); + break; + + case MOVE: + setCursor ( KCursor::sizeAllCursor() ); + } +} + +} // NameSpace DigikamSuperImposeImagesPlugin diff --git a/src/imageplugins/superimpose/superimposewidget.h b/src/imageplugins/superimpose/superimposewidget.h new file mode 100644 index 00000000..8b3fb048 --- /dev/null +++ b/src/imageplugins/superimpose/superimposewidget.h @@ -0,0 +1,118 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-04 + * Description : a Digikam image editor plugin for superimpose a + * template to an image. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef SUPERIMPOSEWIDGET_H +#define SUPERIMPOSEWIDGET_H + +// TQt includes. + +#include <tqwidget.h> +#include <tqimage.h> +#include <tqrect.h> +#include <tqsize.h> +#include <tqpixmap.h> + +// KDE includes. + +#include <kurl.h> + +// Digikam includes. + +#include "imageiface.h" +#include "dimg.h" + +class TQPixmap; + +namespace Digikam +{ +class ImageIface; +} + +namespace DigikamSuperImposeImagesPlugin +{ + +enum Action +{ + ZOOMIN=0, + ZOOMOUT, + MOVE +}; + +class SuperImposeWidget : public TQWidget +{ +TQ_OBJECT + + +public: + + SuperImposeWidget(int w, int h, TQWidget *parent=0); + ~SuperImposeWidget(); + + void setEditMode(int mode); + void resetEdit(void); + TQRect getCurrentSelection(void); + TQSize getTemplateSize(void); + Digikam::DImg makeSuperImpose(void); + +public slots: + + void slotEditModeChanged(int mode); + void slotSetCurrentTemplate(const KURL& url); + +protected: + + void paintEvent( TQPaintEvent *e ); + void resizeEvent( TQResizeEvent * e ); + void mousePressEvent ( TQMouseEvent * e ); + void mouseReleaseEvent ( TQMouseEvent * e ); + void mouseMoveEvent ( TQMouseEvent * e ); + + bool zoomSelection(float deltaZoomFactor); + void moveSelection(int x, int y); + void makePixmap(void); + void setEditModeCursor(); + +private: + + int m_w; + int m_h; + + int m_xpos; + int m_ypos; + int m_editMode; + float m_zoomFactor; + + TQPixmap *m_pixmap; // For image region selection manipulations. + + TQRect m_rect; // For mouse drag position. + TQRect m_currentSelection; // Region selection in image displayed in the widget. + + Digikam::DImg m_template; // Full template data. + Digikam::DImg m_templateScaled; // Template scaled to preview widget +}; + +} // NameSpace DigikamSuperImposeImagesPlugin + +#endif /* SUPERIMPOSEWIDGET_H */ diff --git a/src/imageplugins/texture/Makefile.am b/src/imageplugins/texture/Makefile.am new file mode 100644 index 00000000..22697c65 --- /dev/null +++ b/src/imageplugins/texture/Makefile.am @@ -0,0 +1,35 @@ +METASOURCES = AUTO +SUBDIRS = patterns + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_texture_la_SOURCES = imageplugin_texture.cpp \ + texturetool.cpp texture.cpp + +digikamimageplugin_texture_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_texture_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_texture.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_texture.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_texture_ui.rc + diff --git a/src/imageplugins/texture/digikamimageplugin_texture.desktop b/src/imageplugins/texture/digikamimageplugin_texture.desktop new file mode 100644 index 00000000..4caf7e41 --- /dev/null +++ b/src/imageplugins/texture/digikamimageplugin_texture.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Name=ImagePlugin_Texture +Name[bg]=Приставка за снимки - Текстури +Name[el]=ΠρόσθετοΕικόνας_Υφή +Name[fi]=Taustapinta +Name[hr]=Tekstura +Name[it]=PluginImmagini_Trama +Name[ms]=ImagePlugin_Tekstur +Name[nl]=Afbeeldingsplugin_Textuur +Name[sr]=Текстуре +Name[sr@Latn]=Teksture +Name[sv]=Insticksprogram för struktur +Name[tr]=ResimEklentisi_Doku +Name[xx]=xxImagePlugin_Texturexx + +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=digiKam plugin to apply texture on image +Comment[bg]=Приставка на digiKam за добавяне на текстури към снимки +Comment[ca]=Connector pel digiKam per aplicar una textura a una imatge +Comment[da]=digiKam-plugin til at anvende tekstur på billedet +Comment[de]=digiKam-Modul für das Anwenden von Texturen auf ein Bild +Comment[el]=Πρόσθετο εφαρμογής υφής σε εικόνα για το digiKam +Comment[es]=Plugin para digiKam para aplicar una textura sobre una imagen +Comment[et]=DigiKami pildile tekstuuri lisamise plugin +Comment[fa]=وصلۀ digiKam جهت اعمال بافت در تصویر +Comment[fi]=Lisää kuvaan taustapinnan +Comment[fr]=Module externe pour appliquer une texture sur une image dans digiKam +Comment[gl]=Un plugin de digiKam para aplicar unha textura nunha imaxe +Comment[hr]=digiKam dodatak za primjenu teksture u slici +Comment[is]=Íforrit fyrir digiKam sem setur áferð á mynd +Comment[it]=Plugin di digiKam per applicare una trama su un'immagine +Comment[ja]=digiKam テクスチャ適用プラグイン +Comment[nds]=digiKam-Moduul för't Överdregen vun Texturen +Comment[nl]=Digikam-plugin voor het aanbrengen van textuur op een afbeelding +Comment[pa]=ਚਿੱਤਰ ਉੱਤੇ ਪਾਠ ਲਿਖਣ ਲਈ ਡਿਜ਼ੀਕੈਮ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam pozwalająca na nakładanie tekstury na obraz +Comment[pt]=Um 'plugin' do digiKam para aplicar uma textura numa imagem +Comment[pt_BR]=Um 'plugin' do digiKam para aplicar uma textura numa imagem +Comment[ru]=Модуль digiKam для наложения текстур на изображение +Comment[sk]=digiKam plugin pre aplikovanie textúry na obrázok +Comment[sr]=digiKam-ов прикључак за додавање текстура у слику +Comment[sr@Latn]=digiKam-ov priključak za dodavanje tekstura u sliku +Comment[sv]=Digikam insticksprogram för att lägga till struktur på en bild +Comment[tr]=Bir resme doku eklemek için digiKam eklentisi +Comment[uk]=Втулок застосування текстури для digiKam +Comment[vi]=Phần bổ sung áp dụng hoạ tiết trên ảnh cho digiKam +Comment[xx]=xxdigiKam plugin to apply texture on imagexx + +X-TDE-Library=digikamimageplugin_texture +author=Gilles Caulier, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/texture/digikamimageplugin_texture_ui.rc b/src/imageplugins/texture/digikamimageplugin_texture_ui.rc new file mode 100644 index 00000000..122833cc --- /dev/null +++ b/src/imageplugins/texture/digikamimageplugin_texture_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="4" name="digikamimageplugin_texture" > + + <MenuBar> + + <Menu name="Decorate" ><text>&Decorate</text> + <Action name="imageplugin_texture" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action shortcut="" name="imageplugin_texture" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/texture/imageeffect_texture.cpp b/src/imageplugins/texture/imageeffect_texture.cpp new file mode 100644 index 00000000..5f5d7e9f --- /dev/null +++ b/src/imageplugins/texture/imageeffect_texture.cpp @@ -0,0 +1,291 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-10 + * Description : a plugin to apply texture over an image + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <tqlabel.h> +#include <tqwhatsthis.h> +#include <tqlayout.h> +#include <tqcombobox.h> +#include <tqimage.h> + +// KDE includes. + +#include <tdeconfig.h> +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <kstandarddirs.h> +#include <knuminput.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "texture.h" +#include "imageeffect_texture.h" +#include "imageeffect_texture.moc" + +namespace DigikamTextureImagesPlugin +{ + +ImageEffect_Texture::ImageEffect_Texture(TQWidget* parent) + : Digikam::CtrlPanelDlg(parent, i18n("Apply Texture"), + "texture", false, false, true, + Digikam::ImagePannelWidget::SeparateViewAll) +{ + TQString whatsThis; + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Apply Texture"), + digikam_version, + I18N_NOOP("A digiKam image plugin to apply a decorative " + "texture to an image."), + TDEAboutData::License_GPL, + "(c) 2005, Gilles Caulier\n" + "(c) 2006-2008, Gilles Caulier and Marcel Wiesweg", + 0, + "http://www.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + about->addAuthor("Marcel Wiesweg", I18N_NOOP("Developer"), + "marcel dot wiesweg at gmx dot de"); + + setAboutData(about); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(m_imagePreviewWidget); + TQGridLayout* gridSettings = new TQGridLayout( gboxSettings, 2, 1, 0, spacingHint()); + TQLabel *label1 = new TQLabel(i18n("Type:"), gboxSettings); + + m_textureType = new TQComboBox( false, gboxSettings ); + m_textureType->insertItem( i18n("Paper") ); + m_textureType->insertItem( i18n("Paper 2") ); + m_textureType->insertItem( i18n("Fabric") ); + m_textureType->insertItem( i18n("Burlap") ); + m_textureType->insertItem( i18n("Bricks") ); + m_textureType->insertItem( i18n("Bricks 2") ); + m_textureType->insertItem( i18n("Canvas") ); + m_textureType->insertItem( i18n("Marble") ); + m_textureType->insertItem( i18n("Marble 2") ); + m_textureType->insertItem( i18n("Blue Jean") ); + m_textureType->insertItem( i18n("Cell Wood") ); + m_textureType->insertItem( i18n("Metal Wire") ); + m_textureType->insertItem( i18n("Modern") ); + m_textureType->insertItem( i18n("Wall") ); + m_textureType->insertItem( i18n("Moss") ); + m_textureType->insertItem( i18n("Stone") ); + TQWhatsThis::add( m_textureType, i18n("<p>Set here the texture type to apply to the image.")); + + gridSettings->addMultiCellWidget(label1, 0, 0, 0, 0); + gridSettings->addMultiCellWidget(m_textureType, 0, 0, 1, 1); + + // ------------------------------------------------------------- + + TQLabel *label2 = new TQLabel(i18n("Relief:"), gboxSettings); + + m_blendGain = new KIntNumInput(gboxSettings); + m_blendGain->setRange(1, 255, 1, true); + m_blendGain->setValue(200); + TQWhatsThis::add( m_blendGain, i18n("<p>Set here the relief gain used to merge texture and image.")); + + gridSettings->addMultiCellWidget(label2, 1, 1, 0, 1); + gridSettings->addMultiCellWidget(m_blendGain, 2, 2, 0, 1); + + m_imagePreviewWidget->setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + connect(m_textureType, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotEffect())); + + connect(m_blendGain, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); +} + +ImageEffect_Texture::~ImageEffect_Texture() +{ +} + +void ImageEffect_Texture::renderingFinished() +{ + m_textureType->setEnabled(true); + m_blendGain->setEnabled(true); +} + +void ImageEffect_Texture::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("texture Tool Dialog"); + m_textureType->blockSignals(true); + m_blendGain->blockSignals(true); + m_textureType->setCurrentItem(config->readNumEntry("TextureType", PaperTexture)); + m_blendGain->setValue(config->readNumEntry("BlendGain", 200)); + m_textureType->blockSignals(false); + m_blendGain->blockSignals(false); +} + +void ImageEffect_Texture::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("texture Tool Dialog"); + config->writeEntry("TextureType", m_textureType->currentItem()); + config->writeEntry("BlendGain", m_blendGain->value()); + config->sync(); +} + +void ImageEffect_Texture::resetValues() +{ + m_textureType->blockSignals(true); + m_blendGain->blockSignals(true); + m_textureType->setCurrentItem(PaperTexture); + m_blendGain->setValue(200); + m_textureType->blockSignals(false); + m_blendGain->blockSignals(false); +} + +void ImageEffect_Texture::prepareEffect() +{ + m_textureType->setEnabled(false); + m_blendGain->setEnabled(false); + + Digikam::DImg image = m_imagePreviewWidget->getOriginalRegionImage(); + TQString texture = getTexturePath( m_textureType->currentItem() ); + + int b = 255 - m_blendGain->value(); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new Texture(&image, this, b, texture)); +} + +void ImageEffect_Texture::prepareFinal() +{ + m_textureType->setEnabled(false); + m_blendGain->setEnabled(false); + + int b = 255 - m_blendGain->value(); + + Digikam::ImageIface iface(0, 0); + TQString texture = getTexturePath( m_textureType->currentItem() ); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new Texture(iface.getOriginalImg(), this, b, texture)); +} + +void ImageEffect_Texture::putPreviewData(void) +{ + m_imagePreviewWidget->setPreviewImage(m_threadedFilter->getTargetImage()); +} + +void ImageEffect_Texture::putFinalData(void) +{ + Digikam::ImageIface iface(0, 0); + iface.putOriginalImage(i18n("Texture"), m_threadedFilter->getTargetImage().bits()); +} + +TQString ImageEffect_Texture::getTexturePath(int texture) +{ + TQString pattern; + + switch (texture) + { + case PaperTexture: + pattern = "paper-texture"; + break; + + case Paper2Texture: + pattern = "paper2-texture"; + break; + + case FabricTexture: + pattern = "fabric-texture"; + break; + + case BurlapTexture: + pattern = "burlap-texture"; + break; + + case BricksTexture: + pattern = "bricks-texture"; + break; + + case Bricks2Texture: + pattern = "bricks2-texture"; + break; + + case CanvasTexture: + pattern = "canvas-texture"; + break; + + case MarbleTexture: + pattern = "marble-texture"; + break; + + case Marble2Texture: + pattern = "marble2-texture"; + break; + + case BlueJeanTexture: + pattern = "bluejean-texture"; + break; + + case CellWoodTexture: + pattern = "cellwood-texture"; + break; + + case MetalWireTexture: + pattern = "metalwire-texture"; + break; + + case ModernTexture: + pattern = "modern-texture"; + break; + + case WallTexture: + pattern = "wall-texture"; + break; + + case MossTexture: + pattern = "moss-texture"; + break; + + case StoneTexture: + pattern = "stone-texture"; + break; + } + + TDEGlobal::dirs()->addResourceType(pattern.ascii(), TDEGlobal::dirs()->kde_default("data") + + "digikam/data"); + return (TDEGlobal::dirs()->findResourceDir(pattern.ascii(), pattern + ".png") + pattern + ".png" ); +} + +} // NameSpace DigikamTextureImagesPlugin + diff --git a/src/imageplugins/texture/imageeffect_texture.h b/src/imageplugins/texture/imageeffect_texture.h new file mode 100644 index 00000000..d37068b6 --- /dev/null +++ b/src/imageplugins/texture/imageeffect_texture.h @@ -0,0 +1,100 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-10 + * Description : a plugin to apply texture over an image + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_TEXTURE_H +#define IMAGEEFFECT_TEXTURE_H + +// TQt includes. + +#include <tqstring.h> + +// Digikam includes. + +#include "ctrlpaneldlg.h" + +class TQComboBox; + +class KIntNumInput; + +namespace DigikamTextureImagesPlugin +{ + +class ImageEffect_Texture : public Digikam::CtrlPanelDlg +{ + TQ_OBJECT + + +public: + + ImageEffect_Texture(TQWidget* parent); + ~ImageEffect_Texture(); + +private: + + TQString getTexturePath(int texture); + +private slots: + + void readUserSettings(); + +private: + + void writeUserSettings(); + void resetValues(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + enum TextureTypes + { + PaperTexture=0, + Paper2Texture, + FabricTexture, + BurlapTexture, + BricksTexture, + Bricks2Texture, + CanvasTexture, + MarbleTexture, + Marble2Texture, + BlueJeanTexture, + CellWoodTexture, + MetalWireTexture, + ModernTexture, + WallTexture, + MossTexture, + StoneTexture + }; + + TQComboBox *m_textureType; + + KIntNumInput *m_blendGain; +}; + +} // NameSpace DigikamTextureImagesPlugin + +#endif /* IMAGEEFFECT_TEXTURE_H */ diff --git a/src/imageplugins/texture/imageplugin_texture.cpp b/src/imageplugins/texture/imageplugin_texture.cpp new file mode 100644 index 00000000..ec0e3ba8 --- /dev/null +++ b/src/imageplugins/texture/imageplugin_texture.cpp @@ -0,0 +1,70 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-10 + * Description : a plugin to apply texture over an image + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> +#include <tdeapplication.h> + +// Local includes. + +#include "ddebug.h" +#include "texturetool.h" +#include "imageplugin_texture.h" +#include "imageplugin_texture.moc" + +using namespace DigikamTextureImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_texture, + KGenericFactory<ImagePlugin_Texture>("digikamimageplugin_texture")); + +ImagePlugin_Texture::ImagePlugin_Texture(TQObject *parent, const char*, const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_Texture") +{ + m_textureAction = new TDEAction(i18n("Apply Texture..."), "texture", 0, + this, TQ_SLOT(slotTexture()), + actionCollection(), "imageplugin_texture"); + + setXMLFile( "digikamimageplugin_texture_ui.rc" ); + + DDebug() << "ImagePlugin_Texture plugin loaded" << endl; +} + +ImagePlugin_Texture::~ImagePlugin_Texture() +{ +} + +void ImagePlugin_Texture::setEnabledActions(bool enable) +{ + m_textureAction->setEnabled(enable); +} + +void ImagePlugin_Texture::slotTexture() +{ + TextureTool *tool = new TextureTool(this); + loadTool(tool); +} diff --git a/src/imageplugins/texture/imageplugin_texture.h b/src/imageplugins/texture/imageplugin_texture.h new file mode 100644 index 00000000..bae2ba5e --- /dev/null +++ b/src/imageplugins/texture/imageplugin_texture.h @@ -0,0 +1,56 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-10 + * Description : a plugin to apply texture over an image + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_TEXTURE_H +#define IMAGEPLUGIN_TEXTURE_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_Texture : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_Texture(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_Texture(); + + void setEnabledActions(bool enable); + +private slots: + + void slotTexture(); + +private: + + TDEAction *m_textureAction; +}; + +#endif /* IMAGEPLUGIN_TEXTURE_H */ diff --git a/src/imageplugins/texture/patterns/Makefile.am b/src/imageplugins/texture/patterns/Makefile.am new file mode 100644 index 00000000..414c7f20 --- /dev/null +++ b/src/imageplugins/texture/patterns/Makefile.am @@ -0,0 +1,5 @@ +borderpicsdir = $(kde_datadir)/digikam/data +borderpics_DATA = bricks2-texture.png bricks-texture.png burlap-texture.png canvas-texture.png \ + marble2-texture.png marble-texture.png paper-texture.png stone-texture.png \ + fabric-texture.png paper2-texture.png bluejean-texture.png cellwood-texture.png \ + metalwire-texture.png modern-texture.png wall-texture.png moss-texture.png
\ No newline at end of file diff --git a/src/imageplugins/texture/patterns/bluejean-texture.png b/src/imageplugins/texture/patterns/bluejean-texture.png Binary files differnew file mode 100644 index 00000000..3885d60b --- /dev/null +++ b/src/imageplugins/texture/patterns/bluejean-texture.png diff --git a/src/imageplugins/texture/patterns/bricks-texture.png b/src/imageplugins/texture/patterns/bricks-texture.png Binary files differnew file mode 100644 index 00000000..0ebfa881 --- /dev/null +++ b/src/imageplugins/texture/patterns/bricks-texture.png diff --git a/src/imageplugins/texture/patterns/bricks2-texture.png b/src/imageplugins/texture/patterns/bricks2-texture.png Binary files differnew file mode 100644 index 00000000..985c5e84 --- /dev/null +++ b/src/imageplugins/texture/patterns/bricks2-texture.png diff --git a/src/imageplugins/texture/patterns/burlap-texture.png b/src/imageplugins/texture/patterns/burlap-texture.png Binary files differnew file mode 100644 index 00000000..04494770 --- /dev/null +++ b/src/imageplugins/texture/patterns/burlap-texture.png diff --git a/src/imageplugins/texture/patterns/canvas-texture.png b/src/imageplugins/texture/patterns/canvas-texture.png Binary files differnew file mode 100644 index 00000000..6aa3df8e --- /dev/null +++ b/src/imageplugins/texture/patterns/canvas-texture.png diff --git a/src/imageplugins/texture/patterns/cellwood-texture.png b/src/imageplugins/texture/patterns/cellwood-texture.png Binary files differnew file mode 100644 index 00000000..b94f618c --- /dev/null +++ b/src/imageplugins/texture/patterns/cellwood-texture.png diff --git a/src/imageplugins/texture/patterns/fabric-texture.png b/src/imageplugins/texture/patterns/fabric-texture.png Binary files differnew file mode 100644 index 00000000..ac88eb74 --- /dev/null +++ b/src/imageplugins/texture/patterns/fabric-texture.png diff --git a/src/imageplugins/texture/patterns/marble-texture.png b/src/imageplugins/texture/patterns/marble-texture.png Binary files differnew file mode 100644 index 00000000..c22ab4ed --- /dev/null +++ b/src/imageplugins/texture/patterns/marble-texture.png diff --git a/src/imageplugins/texture/patterns/marble2-texture.png b/src/imageplugins/texture/patterns/marble2-texture.png Binary files differnew file mode 100644 index 00000000..45b77f05 --- /dev/null +++ b/src/imageplugins/texture/patterns/marble2-texture.png diff --git a/src/imageplugins/texture/patterns/metalwire-texture.png b/src/imageplugins/texture/patterns/metalwire-texture.png Binary files differnew file mode 100644 index 00000000..cf0b402c --- /dev/null +++ b/src/imageplugins/texture/patterns/metalwire-texture.png diff --git a/src/imageplugins/texture/patterns/modern-texture.png b/src/imageplugins/texture/patterns/modern-texture.png Binary files differnew file mode 100644 index 00000000..45ed8b7a --- /dev/null +++ b/src/imageplugins/texture/patterns/modern-texture.png diff --git a/src/imageplugins/texture/patterns/moss-texture.png b/src/imageplugins/texture/patterns/moss-texture.png Binary files differnew file mode 100644 index 00000000..9403189f --- /dev/null +++ b/src/imageplugins/texture/patterns/moss-texture.png diff --git a/src/imageplugins/texture/patterns/paper-texture.png b/src/imageplugins/texture/patterns/paper-texture.png Binary files differnew file mode 100644 index 00000000..c9c90205 --- /dev/null +++ b/src/imageplugins/texture/patterns/paper-texture.png diff --git a/src/imageplugins/texture/patterns/paper2-texture.png b/src/imageplugins/texture/patterns/paper2-texture.png Binary files differnew file mode 100644 index 00000000..36817ffd --- /dev/null +++ b/src/imageplugins/texture/patterns/paper2-texture.png diff --git a/src/imageplugins/texture/patterns/stone-texture.png b/src/imageplugins/texture/patterns/stone-texture.png Binary files differnew file mode 100644 index 00000000..6f26b474 --- /dev/null +++ b/src/imageplugins/texture/patterns/stone-texture.png diff --git a/src/imageplugins/texture/patterns/wall-texture.png b/src/imageplugins/texture/patterns/wall-texture.png Binary files differnew file mode 100644 index 00000000..d7322500 --- /dev/null +++ b/src/imageplugins/texture/patterns/wall-texture.png diff --git a/src/imageplugins/texture/texture.cpp b/src/imageplugins/texture/texture.cpp new file mode 100644 index 00000000..42477d5d --- /dev/null +++ b/src/imageplugins/texture/texture.cpp @@ -0,0 +1,181 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : Texture threaded image filter. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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> +#include <cstdlib> + +// Local includes. + +#include "dimg.h" +#include "ddebug.h" +#include "texture.h" + +namespace DigikamTextureImagesPlugin +{ + +Texture::Texture(Digikam::DImg *orgImage, TQObject *parent, int blendGain, TQString texturePath) + : Digikam::DImgThreadedFilter(orgImage, parent, "Texture") +{ + m_blendGain = blendGain; + m_texturePath = texturePath; + + initFilter(); +} + +// This method is based on the Simulate Texture Film tutorial from GimpGuru.org web site +// available at this url : http://www.gimpguru.org/Tutorials/SimulatedTexture/ + +//#define INT_MULT(a,b,t) ((t) = (a) * (b) + 0x80, ( ( (t >> 8) + t ) >> 8)) + +inline static int intMult8(uint a, uint b) +{ + uint t = a * b + 0x80; + return ((t >> 8) + t) >> 8; +} + +inline static int intMult16(uint a, uint b) +{ + uint t = a * b + 0x8000; + return ((t >> 16) + t) >> 16; +} + +void Texture::filterImage(void) +{ + // Texture tile. + + int w = m_orgImage.width(); + int h = m_orgImage.height(); + int bytesDepth = m_orgImage.bytesDepth(); + bool sixteenBit = m_orgImage.sixteenBit(); + + DDebug() << "Texture File: " << m_texturePath << endl; + Digikam::DImg texture(m_texturePath); + if ( texture.isNull() ) return; + + Digikam::DImg textureImg(w, h, m_orgImage.sixteenBit(), m_orgImage.hasAlpha()); + + texture.convertToDepthOfImage(&textureImg); + + for (int x = 0 ; x < w ; x+=texture.width()) + for (int y = 0 ; y < h ; y+=texture.height()) + textureImg.bitBltImage(&texture, x, y); + + // Apply texture. + + uchar* data = m_orgImage.bits(); + uchar* pTeData = textureImg.bits(); + uchar* pOutBits = m_destImage.bits(); + uint offset; + + Digikam::DColor teData, transData, inData, outData; + uchar *ptr, *dptr, *tptr; + int progress; + + int blendGain; + if (sixteenBit) + blendGain = (m_blendGain + 1) * 256 - 1; + else + blendGain = m_blendGain; + + // Make textured transparent layout. + + for (int x = 0; !m_cancel && x < w; x++) + { + for (int y = 0; !m_cancel && y < h; y++) + { + offset = x*bytesDepth + (y*w*bytesDepth); + ptr = data + offset; + tptr = pTeData + offset; + + // Read color + teData.setColor(tptr, sixteenBit); + + // in the old algorithm, this was + //teData.channel.red = (teData.channel.red * (255 - m_blendGain) + + // transData.channel.red * m_blendGain) >> 8; + // but transdata was uninitialized, its components were apparently 0, + // so I removed the part after the "+". + + if (sixteenBit) + { + teData.blendInvAlpha16(blendGain); + } + else + { + teData.blendInvAlpha8(blendGain); + } + + // Overwrite RGB. + teData.setPixel(tptr); + } + + // Update progress bar in dialog. + progress = (int) (((double)x * 50.0) / w); + + if (progress%5 == 0) + postProgress(progress); + } + + // Merge layout and image using overlay method. + + for (int x = 0; !m_cancel && x < w; x++) + { + for (int y = 0; !m_cancel && y < h; y++) + { + offset = x*bytesDepth + (y*w*bytesDepth); + ptr = data + offset; + dptr = pOutBits + offset; + tptr = pTeData + offset; + + inData.setColor (ptr, sixteenBit); + outData.setColor(dptr, sixteenBit); + teData.setColor (tptr, sixteenBit); + + if (sixteenBit) + { + outData.setRed ( intMult16 (inData.red(), inData.red() + intMult16(2 * teData.red(), 65535 - inData.red()) ) ); + outData.setGreen( intMult16 (inData.green(), inData.green() + intMult16(2 * teData.green(), 65535 - inData.green()) ) ); + outData.setBlue ( intMult16 (inData.blue(), inData.blue() + intMult16(2 * teData.blue(), 65535 - inData.blue()) ) ); + } + else + { + outData.setRed ( intMult8 (inData.red(), inData.red() + intMult8(2 * teData.red(), 255 - inData.red()) ) ); + outData.setGreen( intMult8 (inData.green(), inData.green() + intMult8(2 * teData.green(), 255 - inData.green()) ) ); + outData.setBlue ( intMult8 (inData.blue(), inData.blue() + intMult8(2 * teData.blue(), 255 - inData.blue()) ) ); + } + outData.setAlpha( inData.alpha() ); + outData.setPixel( dptr ); + } + + // Update progress bar in dialog. + progress = (int) (50.0 + ((double)x * 50.0) / w); + + if (progress%5 == 0) + postProgress(progress); + } +} + +} // NameSpace DigikamTextureImagesPlugin diff --git a/src/imageplugins/texture/texture.h b/src/imageplugins/texture/texture.h new file mode 100644 index 00000000..1bcda2ff --- /dev/null +++ b/src/imageplugins/texture/texture.h @@ -0,0 +1,62 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : Texture threaded image filter. + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef TEXTURE_H +#define TEXTURE_H + +// TQt includes. + +#include <tqstring.h> + +// Digikam includes. + +#include "dimgthreadedfilter.h" + +namespace DigikamTextureImagesPlugin +{ + +class Texture : public Digikam::DImgThreadedFilter +{ + +public: + + Texture(Digikam::DImg *orgImage, TQObject *parent=0, int blendGain=200, + TQString texturePath=TQString()); + + ~Texture(){}; + +private: + + virtual void filterImage(void); + +private: + + int m_blendGain; + + TQString m_texturePath; +}; + +} // NameSpace DigikamTextureImagesPlugin + +#endif /* TEXTURE_H */ diff --git a/src/imageplugins/texture/texturetool.cpp b/src/imageplugins/texture/texturetool.cpp new file mode 100644 index 00000000..71e29aea --- /dev/null +++ b/src/imageplugins/texture/texturetool.cpp @@ -0,0 +1,294 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-10 + * Description : a plugin to apply texture over an image + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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 <tqimage.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <kstandarddirs.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> +#include <libkdcraw/rcombobox.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "imagepanelwidget.h" +#include "editortoolsettings.h" +#include "texture.h" +#include "texturetool.h" +#include "texturetool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamTextureImagesPlugin +{ + +TextureTool::TextureTool(TQObject* parent) + : EditorToolThreaded(parent) +{ + setName("texture"); + setToolName(i18n("Texture")); + setToolIcon(SmallIcon("texture")); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel| + EditorToolSettings::PanIcon); + TQGridLayout* grid = new TQGridLayout( m_gboxSettings->plainPage(), 3, 1); + TQLabel *label1 = new TQLabel(i18n("Type:"), m_gboxSettings->plainPage()); + + m_textureType = new RComboBox(m_gboxSettings->plainPage()); + m_textureType->insertItem(i18n("Paper")); + m_textureType->insertItem(i18n("Paper 2")); + m_textureType->insertItem(i18n("Fabric")); + m_textureType->insertItem(i18n("Burlap")); + m_textureType->insertItem(i18n("Bricks")); + m_textureType->insertItem(i18n("Bricks 2")); + m_textureType->insertItem(i18n("Canvas")); + m_textureType->insertItem(i18n("Marble")); + m_textureType->insertItem(i18n("Marble 2")); + m_textureType->insertItem(i18n("Blue Jean")); + m_textureType->insertItem(i18n("Cell Wood")); + m_textureType->insertItem(i18n("Metal Wire")); + m_textureType->insertItem(i18n("Modern")); + m_textureType->insertItem(i18n("Wall")); + m_textureType->insertItem(i18n("Moss")); + m_textureType->insertItem(i18n("Stone")); + m_textureType->setDefaultItem(PaperTexture); + TQWhatsThis::add( m_textureType, i18n("<p>Set here the texture type to apply to the image.")); + + // ------------------------------------------------------------- + + TQLabel *label2 = new TQLabel(i18n("Relief:"), m_gboxSettings->plainPage()); + + m_blendGain = new RIntNumInput(m_gboxSettings->plainPage()); + m_blendGain->setRange(1, 255, 1); + m_blendGain->setDefaultValue(200); + TQWhatsThis::add( m_blendGain, i18n("<p>Set here the relief gain used to merge texture and image.")); + + grid->addMultiCellWidget(label1, 0, 0, 0, 0); + grid->addMultiCellWidget(m_textureType, 0, 0, 1, 1); + grid->addMultiCellWidget(label2, 1, 1, 0, 1); + grid->addMultiCellWidget(m_blendGain, 2, 2, 0, 1); + grid->setRowStretch(3, 10); + grid->setMargin(m_gboxSettings->spacingHint()); + grid->setSpacing(m_gboxSettings->spacingHint()); + + setToolSettings(m_gboxSettings); + + // ------------------------------------------------------------- + + m_previewWidget = new ImagePanelWidget(470, 350, "texture Tool", m_gboxSettings->panIconView()); + + setToolView(m_previewWidget); + init(); + + // ------------------------------------------------------------- + + connect(m_textureType, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotEffect())); + + connect(m_blendGain, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); +} + +TextureTool::~TextureTool() +{ +} + +void TextureTool::renderingFinished() +{ + m_textureType->setEnabled(true); + m_blendGain->setEnabled(true); +} + +void TextureTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("texture Tool"); + + m_textureType->blockSignals(true); + m_blendGain->blockSignals(true); + + m_textureType->setCurrentItem(config->readNumEntry("TextureType", m_textureType->defaultItem())); + m_blendGain->setValue(config->readNumEntry("BlendGain", m_blendGain->defaultValue())); + + m_textureType->blockSignals(false); + m_blendGain->blockSignals(false); +} + +void TextureTool::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("texture Tool"); + config->writeEntry("TextureType", m_textureType->currentItem()); + config->writeEntry("BlendGain", m_blendGain->value()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void TextureTool::slotResetSettings() +{ + m_textureType->blockSignals(true); + m_blendGain->blockSignals(true); + + m_textureType->slotReset(); + m_blendGain->slotReset(); + + m_textureType->blockSignals(false); + m_blendGain->blockSignals(false); +} + +void TextureTool::prepareEffect() +{ + m_textureType->setEnabled(false); + m_blendGain->setEnabled(false); + + DImg image = m_previewWidget->getOriginalRegionImage(); + TQString texture = getTexturePath( m_textureType->currentItem() ); + + int b = 255 - m_blendGain->value(); + + setFilter(dynamic_cast<DImgThreadedFilter*>(new Texture(&image, this, b, texture))); +} + +void TextureTool::prepareFinal() +{ + m_textureType->setEnabled(false); + m_blendGain->setEnabled(false); + + int b = 255 - m_blendGain->value(); + + ImageIface iface(0, 0); + TQString texture = getTexturePath( m_textureType->currentItem() ); + + setFilter(dynamic_cast<DImgThreadedFilter*>(new Texture(iface.getOriginalImg(), this, b, texture))); +} + +void TextureTool::putPreviewData() +{ + m_previewWidget->setPreviewImage(filter()->getTargetImage()); +} + +void TextureTool::putFinalData() +{ + ImageIface iface(0, 0); + iface.putOriginalImage(i18n("Texture"), filter()->getTargetImage().bits()); +} + +TQString TextureTool::getTexturePath(int texture) +{ + TQString pattern; + + switch (texture) + { + case PaperTexture: + pattern = "paper-texture"; + break; + + case Paper2Texture: + pattern = "paper2-texture"; + break; + + case FabricTexture: + pattern = "fabric-texture"; + break; + + case BurlapTexture: + pattern = "burlap-texture"; + break; + + case BricksTexture: + pattern = "bricks-texture"; + break; + + case Bricks2Texture: + pattern = "bricks2-texture"; + break; + + case CanvasTexture: + pattern = "canvas-texture"; + break; + + case MarbleTexture: + pattern = "marble-texture"; + break; + + case Marble2Texture: + pattern = "marble2-texture"; + break; + + case BlueJeanTexture: + pattern = "bluejean-texture"; + break; + + case CellWoodTexture: + pattern = "cellwood-texture"; + break; + + case MetalWireTexture: + pattern = "metalwire-texture"; + break; + + case ModernTexture: + pattern = "modern-texture"; + break; + + case WallTexture: + pattern = "wall-texture"; + break; + + case MossTexture: + pattern = "moss-texture"; + break; + + case StoneTexture: + pattern = "stone-texture"; + break; + } + + TDEGlobal::dirs()->addResourceType(pattern.ascii(), TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + return (TDEGlobal::dirs()->findResourceDir(pattern.ascii(), pattern + ".png") + pattern + ".png" ); +} + +} // NameSpace DigikamTextureImagesPlugin diff --git a/src/imageplugins/texture/texturetool.h b/src/imageplugins/texture/texturetool.h new file mode 100644 index 00000000..1287bb3e --- /dev/null +++ b/src/imageplugins/texture/texturetool.h @@ -0,0 +1,112 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-10 + * Description : a plugin to apply texture over an image + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef TEXTURETOOL_H +#define TEXTURETOOL_H + +// TQt includes. + +#include <tqstring.h> + +// Digikam includes. + +#include "editortool.h" + +namespace KDcrawIface +{ +class RIntNumInput; +class RComboBox; +} + +namespace Digikam +{ +class EditorToolSettings; +class ImagePanelWidget; +} + +namespace DigikamTextureImagesPlugin +{ + +class TextureTool : public Digikam::EditorToolThreaded +{ + TQ_OBJECT + + +public: + + TextureTool(TQObject* parent); + ~TextureTool(); + +private: + + TQString getTexturePath(int texture); + +private slots: + + void slotResetSettings(); + +private: + + void readSettings(); + void writeSettings(); + void prepareEffect(); + void prepareFinal(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + enum TextureTypes + { + PaperTexture=0, + Paper2Texture, + FabricTexture, + BurlapTexture, + BricksTexture, + Bricks2Texture, + CanvasTexture, + MarbleTexture, + Marble2Texture, + BlueJeanTexture, + CellWoodTexture, + MetalWireTexture, + ModernTexture, + WallTexture, + MossTexture, + StoneTexture + }; + + KDcrawIface::RComboBox *m_textureType; + + KDcrawIface::RIntNumInput *m_blendGain; + + Digikam::ImagePanelWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamTextureImagesPlugin + +#endif /* TEXTURETOOL_H */ diff --git a/src/imageplugins/whitebalance/Makefile.am b/src/imageplugins/whitebalance/Makefile.am new file mode 100644 index 00000000..b53cf65a --- /dev/null +++ b/src/imageplugins/whitebalance/Makefile.am @@ -0,0 +1,33 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_whitebalance_la_SOURCES = imageplugin_whitebalance.cpp \ + whitebalancetool.cpp + +digikamimageplugin_whitebalance_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_whitebalance_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_whitebalance.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_whitebalance.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_whitebalance_ui.rc diff --git a/src/imageplugins/whitebalance/digikamimageplugin_whitebalance.desktop b/src/imageplugins/whitebalance/digikamimageplugin_whitebalance.desktop new file mode 100644 index 00000000..df425c58 --- /dev/null +++ b/src/imageplugins/whitebalance/digikamimageplugin_whitebalance.desktop @@ -0,0 +1,53 @@ +[Desktop Entry] +Name=ImagePlugin_WhiteBalance +Name[bg]=Приставка за снимки - Баланс на бялото +Name[el]=ΠρόσθετοΕικόνας_ΙσορροπίαΛευκού +Name[fi]=Valkotasapaino +Name[hr]=Bijeli balans +Name[it]=PluginImmagini_BilanciamentoDelBianco +Name[ms]=ImagePlugin_ImbanganPutih +Name[nl]=Afbeeldingsplugin_Witbalans +Name[sr]=Баланс белог +Name[sr@Latn]=Balans belog +Name[sv]=Insticksprogram för vitbalans +Name[tr]=ResimEklentisi_BeyazDengesi +Name[xx]=xxImagePlugin_WhiteBalancexx + +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=White balance correction plugin for digiKam +Comment[bg]=Приставка на digiKam за промяна баланса на бялото +Comment[ca]=Connector pel digiKam per corregir el balanç de blancs +Comment[da]=Hvid balance rettelsesplugin for digiKam +Comment[de]=digiKam-Modul zur Korrektur des Weißabgleiches +Comment[el]=Πρόσθετο διόρθωσης ισορροπίας λευκού για το digiKam +Comment[es]=Plugin de digiKam para la corrección del equilibrio de blancos +Comment[et]=DigiKami valge tasakaalu korrigeerimise plugin +Comment[fa]=وصلۀ اصلاح تعادل سفید برای digiKam +Comment[fi]=Korjaa kuvan valkotasapainon +Comment[fr]=Module externe pour corriger la balance des blancs dans digiKam +Comment[gl]=Un plugin de digiKam para corrixir o balance do branco +Comment[hr]=digiKam dodatak za ispravljanje bijelog balansa +Comment[is]=Íforrit fyrir digiKam sem breytir hvítvægi mynda +Comment[it]=Plugin di correzione del bilanciamento del bianco per digiKam +Comment[ja]=digiKam ホワイトバランス補正プラグイン +Comment[ms]=Plugin pembetulan imbangan putih untuk digiKam +Comment[nds]=digiKam-Korrektuurmoduul för de Wittbalangs +Comment[nl]=Digikam-plugin voor het corrigeren van de witbalans +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਚਿੱਟਾ ਸਾਵਾਂ ਸੋਧ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam korygująca balans bieli +Comment[pt]=Um 'plugin' do digiKam para corrigir o balanceamento de branco +Comment[pt_BR]=Plugin para Correção de iluminação +Comment[ru]=Модуль коррекции баланса белого для digiKam +Comment[sk]=digiKam plugin na korekciu vyváženia bielej +Comment[sr]=digiKam-ов прикључак исправку баланса белог +Comment[sr@Latn]=digiKam-ov priključak ispravku balansa belog +Comment[sv]=Digikam insticksprogram för korrigering av vitbalans +Comment[tr]=digiKam için beyaz dengesi düzeltme eklentisi +Comment[uk]=Втулок виправлення балансу білого для digiKam +Comment[vi]=Phần bổ sung sửa cân bằng trắng cho digiKam +Comment[xx]=xxWhite balance correction plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_whitebalance +author=Gilles Caulier, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/whitebalance/digikamimageplugin_whitebalance_ui.rc b/src/imageplugins/whitebalance/digikamimageplugin_whitebalance_ui.rc new file mode 100644 index 00000000..9bdf8247 --- /dev/null +++ b/src/imageplugins/whitebalance/digikamimageplugin_whitebalance_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="5" name="digikamimageplugin_whitebalance" > + + <MenuBar> + + <Menu name="Color"><text>&Color</text> + <Action name="imageplugin_whitebalance" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action name="imageplugin_whitebalance" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/whitebalance/imageeffect_whitebalance.cpp b/src/imageplugins/whitebalance/imageeffect_whitebalance.cpp new file mode 100644 index 00000000..f72609dd --- /dev/null +++ b/src/imageplugins/whitebalance/imageeffect_whitebalance.cpp @@ -0,0 +1,842 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-11 + * Description : a digiKam image editor plugin to correct + * image white balance + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2008 by Guillaume Castagnino <casta at xwing dot info> + * + * 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 <tqhgroupbox.h> +#include <tqvgroupbox.h> +#include <tqlabel.h> +#include <tqpushbutton.h> +#include <tqhbuttongroup.h> +#include <tqwhatsthis.h> +#include <tqlayout.h> +#include <tqframe.h> +#include <tqcombobox.h> +#include <tqtimer.h> +#include <tqtooltip.h> +#include <tqpixmap.h> +#include <tqfile.h> +#include <tqtextstream.h> +#include <tqvbox.h> + +// KDE includes. + +#include <kcursor.h> +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <khelpmenu.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <tdepopupmenu.h> +#include <kstandarddirs.h> +#include <kprogress.h> +#include <tdemessagebox.h> +#include <knuminput.h> +#include <tdeglobalsettings.h> +#include <tdefiledialog.h> +#include <kseparator.h> +#include <tdeconfig.h> +#include <kactivelabel.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "dimg.h" +#include "dcolor.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "imagehistogram.h" +#include "whitebalance.h" +#include "colorgradientwidget.h" +#include "histogramwidget.h" +#include "dimgimagefilters.h" +#include "imageeffect_whitebalance.h" +#include "imageeffect_whitebalance.moc" + +namespace DigikamWhiteBalanceImagesPlugin +{ + +ImageEffect_WhiteBalance::ImageEffect_WhiteBalance(TQWidget* parent) + : Digikam::ImageDlgBase(parent, i18n("White Color Balance Correction"), + "whitebalance", true, false) +{ + TQString whatsThis; + + Digikam::ImageIface iface(0, 0); + + m_destinationPreviewData = 0L; + + // About data and help button. + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("White Color Balance Correction"), + digikam_version, + I18N_NOOP("A digiKam image plugin to correct white color balance."), + TDEAboutData::License_GPL, + "(c) 2005-2008, Gilles Caulier", + 0, + "http://wwww.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + about->addAuthor("Pawel T. Jochym", I18N_NOOP("White color balance correction algorithm"), + "jochym at ifj edu pl"); + + setAboutData(about); + + // ------------------------------------------------------------- + + m_previewWidget = new Digikam::ImageWidget("whitebalance Tool Dialog", plainPage(), + i18n("<p>You can see here the image's white-balance " + "adjustments preview. You can pick color on image to " + "see the color level corresponding on histogram.")); + setPreviewAreaWidget(m_previewWidget); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(plainPage()); + TQVBoxLayout* layout2 = new TQVBoxLayout( gboxSettings, spacingHint() ); + TQGridLayout *grid = new TQGridLayout( layout2, 2, 4, spacingHint()); + + TQLabel *label1 = new TQLabel(i18n("Channel:"), gboxSettings); + label1->setAlignment ( TQt::AlignRight | TQt::AlignVCenter ); + m_channelCB = new TQComboBox( false, gboxSettings ); + 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("<p>Select the histogram channel to display here:<p>" + "<b>Luminosity</b>: display the image's luminosity values.<p>" + "<b>Red</b>: display the red image-channel values.<p>" + "<b>Green</b>: display the green image-channel values.<p>" + "<b>Blue</b>: display the blue image-channel values.<p>")); + + m_scaleBG = new TQHButtonGroup(gboxSettings); + m_scaleBG->setExclusive(true); + m_scaleBG->setFrameShape(TQFrame::NoFrame); + m_scaleBG->setInsideMargin( 0 ); + TQWhatsThis::add( m_scaleBG, i18n("<p>Select the histogram scale here.<p>" + "If the image's maximal counts are small, you can use the linear scale.<p>" + "Logarithmic scale can be used when the maximal counts 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( "<p>Linear" ) ); + m_scaleBG->insert(linHistoButton, Digikam::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( "<p>Logarithmic" ) ); + m_scaleBG->insert(logHistoButton, Digikam::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); + + grid->addMultiCellLayout(l1, 0, 0, 0, 4); + + // ------------------------------------------------------------- + + TQVBox *histoBox = new TQVBox(gboxSettings); + m_histogramWidget = new Digikam::HistogramWidget(256, 140, histoBox, false, true, true); + TQWhatsThis::add( m_histogramWidget, i18n("<p>Here you can see the target preview image histogram " + "drawing of the selected image channel. This one is " + "re-computed at any filter settings changes.")); + TQLabel *space = new TQLabel(histoBox); + space->setFixedHeight(1); + m_hGradient = new Digikam::ColorGradientWidget( Digikam::ColorGradientWidget::Horizontal, 10, histoBox ); + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + + grid->addMultiCellWidget(histoBox, 1, 2, 0, 4); + + // ------------------------------------------------------------- + + TQGridLayout *grid2 = new TQGridLayout(layout2, 13, 5, spacingHint()); + + m_temperatureLabel = new KActiveLabel(i18n("<qt><a href='http://en.wikipedia.org/wiki/Color_temperature'>Color Temperature</a> " + " (K): </qt>"), gboxSettings); + m_adjTemperatureLabel = new TQLabel(i18n("Adjustment:"), gboxSettings); + m_temperatureInput = new KDoubleNumInput(gboxSettings); + m_temperatureInput->setPrecision(1); + m_temperatureInput->setRange(2000.0, 12000.0, 10.0, true); + TQWhatsThis::add( m_temperatureInput, i18n("<p>Set here the white balance color temperature in Kelvin.")); + + m_temperaturePresetLabel = new TQLabel(i18n("Preset:"), gboxSettings); + m_temperaturePresetCB = new TQComboBox( false, gboxSettings ); + m_temperaturePresetCB->insertItem( i18n("Candle") ); + m_temperaturePresetCB->insertItem( i18n("40W Lamp") ); + m_temperaturePresetCB->insertItem( i18n("100W Lamp") ); + m_temperaturePresetCB->insertItem( i18n("200W Lamp") ); + m_temperaturePresetCB->insertItem( i18n("Sunrise") ); + m_temperaturePresetCB->insertItem( i18n("Studio Lamp") ); + m_temperaturePresetCB->insertItem( i18n("Moonlight") ); + m_temperaturePresetCB->insertItem( i18n("Neutral") ); + m_temperaturePresetCB->insertItem( i18n("Daylight D50") ); + m_temperaturePresetCB->insertItem( i18n("Photo Flash") ); + m_temperaturePresetCB->insertItem( i18n("Sun") ); + m_temperaturePresetCB->insertItem( i18n("Xenon Lamp") ); + m_temperaturePresetCB->insertItem( i18n("Daylight D65") ); + m_temperaturePresetCB->insertItem( i18n("None") ); + TQWhatsThis::add( m_temperaturePresetCB, i18n("<p>Select the white balance color temperature " + "preset to use here:<p>" + "<b>Candle</b>: candle light (1850K).<p>" + "<b>40W Lamp</b>: 40 Watt incandescent lamp (2680K).<p>" + "<b>100W Lamp</b>: 100 Watt incandescent lamp (2800K).<p>" + "<b>200W Lamp</b>: 200 Watt incandescent lamp (3000K).<p>" + "<b>Sunrise</b>: sunrise or sunset light (3200K).<p>" + "<b>Studio Lamp</b>: tungsten lamp used in photo studio " + "or light at 1 hour from dusk/dawn (3400K).<p>" + "<b>Moonlight</b>: moon light (4100K).<p>" + "<b>Neutral</b>: neutral color temperature (4750K).<p>" + "<b>Daylight D50</b>: sunny daylight around noon (5000K).<p>" + "<b>Photo Flash</b>: electronic photo flash (5500K).<p>" + "<b>Sun</b>: effective sun temperature (5770K).<p>" + "<b>Xenon Lamp</b>: xenon lamp or light arc (6420K).<p>" + "<b>Daylight D65</b>: overcast sky light (6500K).<p>" + "<b>None</b>: no preset value.")); + m_pickTemperature = new TQPushButton(gboxSettings); + TDEGlobal::dirs()->addResourceType("color-picker-grey", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("color-picker-grey", "color-picker-grey.png"); + m_pickTemperature->setPixmap( TQPixmap( directory + "color-picker-grey.png" ) ); + m_pickTemperature->setToggleButton(true); + TQToolTip::add( m_pickTemperature, i18n( "Temperature tone color picker." ) ); + TQWhatsThis::add( m_pickTemperature, i18n("<p>With this button, you can pick the color from original " + "image used to set white color balance temperature and " + "green component.")); + + KSeparator *line = new KSeparator(Horizontal, gboxSettings); + + // ------------------------------------------------------------- + + m_blackLabel = new TQLabel(i18n("Black point:"), gboxSettings); + m_blackInput = new KDoubleNumInput(gboxSettings); + m_blackInput->setPrecision(2); + m_blackInput->setRange(0.0, 0.05, 0.01, true); + TQWhatsThis::add( m_blackInput, i18n("<p>Set here the black level value.")); + + m_darkLabel = new TQLabel(i18n("Shadows:"), gboxSettings); + m_darkInput = new KDoubleNumInput(gboxSettings); + m_darkInput->setPrecision(2); + m_darkInput->setRange(0.0, 1.0, 0.01, true); + TQWhatsThis::add( m_darkInput, i18n("<p>Set here the shadows noise suppresion level.")); + + m_saturationLabel = new TQLabel(i18n("Saturation:"), gboxSettings); + m_saturationInput = new KDoubleNumInput(gboxSettings); + m_saturationInput->setPrecision(2); + m_saturationInput->setRange(0.0, 2.0, 0.01, true); + TQWhatsThis::add( m_saturationInput, i18n("<p>Set here the saturation value.")); + + m_gammaLabel = new TQLabel(i18n("Gamma:"), gboxSettings); + m_gammaInput = new KDoubleNumInput(gboxSettings); + m_gammaInput->setPrecision(2); + m_gammaInput->setRange(0.1, 3.0, 0.01, true); + TQWhatsThis::add( m_gammaInput, i18n("<p>Set here the gamma correction value.")); + + m_greenLabel = new TQLabel(i18n("Green:"), gboxSettings); + m_greenInput = new KDoubleNumInput(gboxSettings); + m_greenInput->setPrecision(2); + m_greenInput->setRange(0.2, 2.5, 0.01, true); + TQWhatsThis::add(m_greenInput, i18n("<p>Set here the green component to set magenta color " + "cast removal level.")); + + KSeparator *line2 = new KSeparator(Horizontal, gboxSettings); + + // ------------------------------------------------------------- + + m_exposureLabel = new KActiveLabel(i18n("<qt><a href='http://en.wikipedia.org/wiki/Exposure_value'>Exposure Compensation</a> " + " (E.V): </qt>"), gboxSettings); + m_mainExposureLabel = new TQLabel(i18n("Main:"), gboxSettings); + m_autoAdjustExposure = new TQPushButton(gboxSettings); + m_autoAdjustExposure->setPixmap(kapp->iconLoader()->loadIcon("system-run", (TDEIcon::Group)TDEIcon::Toolbar)); + TQToolTip::add( m_autoAdjustExposure, i18n( "Auto exposure adjustments" ) ); + TQWhatsThis::add( m_autoAdjustExposure, i18n("<p>With this button, you can automatically adjust Exposure " + "and Black Point values.")); + m_mainExposureInput = new KDoubleNumInput(gboxSettings); + m_mainExposureInput->setPrecision(2); + m_mainExposureInput->setRange(-6.0, 8.0, 0.1, true); + TQWhatsThis::add( m_mainExposureInput, i18n("<p>Set here the main exposure compensation value in E.V.")); + + m_fineExposureLabel = new TQLabel(i18n("Fine:"), gboxSettings); + m_fineExposureInput = new KDoubleNumInput(gboxSettings); + m_fineExposureInput->setPrecision(2); + m_fineExposureInput->setRange(-0.5, 0.5, 0.01, true); + TQWhatsThis::add( m_fineExposureInput, i18n("<p>This value in E.V will be added to main exposure " + "compensation value to set fine exposure adjustment.")); + + // ------------------------------------------------------------- + + grid2->addMultiCellWidget(m_temperatureLabel, 0, 0, 0, 5); + grid2->addMultiCellWidget(m_adjTemperatureLabel, 1, 1, 0, 0); + grid2->addMultiCellWidget(m_pickTemperature, 1, 1, 1, 1); + grid2->addMultiCellWidget(m_temperatureInput, 1, 1, 2, 5); + grid2->addMultiCellWidget(m_temperaturePresetLabel, 2, 2, 0, 0); + grid2->addMultiCellWidget(m_temperaturePresetCB, 2, 2, 2, 5); + + grid2->addMultiCellWidget(line, 3, 3, 0, 5); + + grid2->addMultiCellWidget(m_blackLabel, 4, 4, 0, 0); + grid2->addMultiCellWidget(m_blackInput, 4, 4, 1, 5); + grid2->addMultiCellWidget(m_darkLabel, 5, 5, 0, 0); + grid2->addMultiCellWidget(m_darkInput, 5, 5, 1, 5); + grid2->addMultiCellWidget(m_saturationLabel, 6, 6, 0, 0); + grid2->addMultiCellWidget(m_saturationInput, 6, 6, 1, 5); + grid2->addMultiCellWidget(m_gammaLabel, 7, 7, 0, 0); + grid2->addMultiCellWidget(m_gammaInput, 7, 7, 1, 5); + grid2->addMultiCellWidget(m_greenLabel, 8, 8, 0, 0); + grid2->addMultiCellWidget(m_greenInput, 8, 8, 1, 5); + + grid2->addMultiCellWidget(line2, 9, 9, 0, 5); + + grid2->addMultiCellWidget(m_exposureLabel, 10, 10, 0, 5); + grid2->addMultiCellWidget(m_mainExposureLabel, 11, 11, 0, 0); + grid2->addMultiCellWidget(m_autoAdjustExposure, 11, 11, 1, 1); + grid2->addMultiCellWidget(m_mainExposureInput, 11, 11, 2, 5); + grid2->addMultiCellWidget(m_fineExposureLabel, 12, 12, 0, 1); + grid2->addMultiCellWidget(m_fineExposureInput, 12, 12, 2, 5); + grid2->setRowStretch(13, 10); + + setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + 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_previewWidget, TQ_SIGNAL(spotPositionChangedFromOriginal( const Digikam::DColor &, const TQPoint & )), + this, TQ_SLOT(slotColorSelectedFromOriginal( const Digikam::DColor & ))); + + connect(m_previewWidget, TQ_SIGNAL(spotPositionChangedFromTarget( const Digikam::DColor &, const TQPoint & )), + this, TQ_SLOT(slotColorSelectedFromTarget( const Digikam::DColor & ))); + + connect(m_previewWidget, TQ_SIGNAL(signalResized()), + this, TQ_SLOT(slotEffect())); + + // ------------------------------------------------------------- + // Correction Filter Slider controls. + + connect(m_temperaturePresetCB, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotTemperaturePresetChanged(int))); + + connect(m_temperatureInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTemperatureChanged(double))); + + connect(m_darkInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_blackInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_mainExposureInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_fineExposureInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_gammaInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_saturationInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_greenInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + // ------------------------------------------------------------- + // Bouttons slots. + + connect(m_autoAdjustExposure, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotAutoAdjustExposure())); + + connect(m_pickTemperature, TQ_SIGNAL(released()), + this, TQ_SLOT(slotPickerColorButtonActived())); +} + +ImageEffect_WhiteBalance::~ImageEffect_WhiteBalance() +{ + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + delete m_histogramWidget; +} + +void ImageEffect_WhiteBalance::slotTemperatureChanged(double temperature) +{ + switch((uint)temperature) + { + case 1850: + m_temperaturePresetCB->setCurrentItem(Candle); + break; + + case 2680: + m_temperaturePresetCB->setCurrentItem(Lamp40W); + break; + + case 2800: + m_temperaturePresetCB->setCurrentItem(Lamp100W); + break; + + case 3000: + m_temperaturePresetCB->setCurrentItem(Lamp200W); + break; + + case 3200: + m_temperaturePresetCB->setCurrentItem(Sunrise); + break; + + case 3400: + m_temperaturePresetCB->setCurrentItem(StudioLamp); + break; + + case 4100: + m_temperaturePresetCB->setCurrentItem(MoonLight); + break; + + case 4750: + m_temperaturePresetCB->setCurrentItem(Neutral); + break; + + case 5000: + m_temperaturePresetCB->setCurrentItem(DaylightD50); + break; + + case 5500: + m_temperaturePresetCB->setCurrentItem(Flash); + break; + + case 5770: + m_temperaturePresetCB->setCurrentItem(Sun); + break; + + case 6420: + m_temperaturePresetCB->setCurrentItem(XeonLamp); + break; + + case 6500: + m_temperaturePresetCB->setCurrentItem(DaylightD65); + break; + + default: + m_temperaturePresetCB->setCurrentItem(None); + break; + } + + slotTimer(); +} + +void ImageEffect_WhiteBalance::slotTemperaturePresetChanged(int tempPreset) +{ + switch(tempPreset) + { + case Candle: + m_temperatureInput->setValue(1850.0); + break; + + case Lamp40W: + m_temperatureInput->setValue(2680.0); + break; + + case Lamp100W: + m_temperatureInput->setValue(2800.0); + break; + + case Lamp200W: + m_temperatureInput->setValue(3000.0); + break; + + case Sunrise: + m_temperatureInput->setValue(3200.0); + break; + + case StudioLamp: + m_temperatureInput->setValue(3400.0); + break; + + case MoonLight: + m_temperatureInput->setValue(4100.0); + break; + + case Neutral: + m_temperatureInput->setValue(4750.0); + break; + + case DaylightD50: + m_temperatureInput->setValue(5000.0); + break; + + case Flash: + m_temperatureInput->setValue(5500.0); + break; + + case Sun: + m_temperatureInput->setValue(5770.0); + break; + + case XeonLamp: + m_temperatureInput->setValue(6420.0); + break; + + case DaylightD65: + m_temperatureInput->setValue(6500.0); + break; + + default: // None. + break; + } + + slotEffect(); +} + +void ImageEffect_WhiteBalance::slotPickerColorButtonActived() +{ + // Save previous rendering mode and toggle to original image. + m_currentPreviewMode = m_previewWidget->getRenderingPreviewMode(); + m_previewWidget->setRenderingPreviewMode(Digikam::ImageGuideWidget::PreviewOriginalImage); +} + +void ImageEffect_WhiteBalance::slotColorSelectedFromOriginal(const Digikam::DColor &color) +{ + if ( m_pickTemperature->isOn() ) + { + Digikam::DColor dc = color; + TQColor tc = dc.getTQColor(); + double temperatureLevel, greenLevel; + + Digikam::WhiteBalance::autoWBAdjustementFromColor(tc, temperatureLevel, greenLevel); + + m_temperatureInput->setValue(temperatureLevel); + m_greenInput->setValue(greenLevel); + m_pickTemperature->setOn(false); + } + else + return; + + // restore previous rendering mode. + m_previewWidget->setRenderingPreviewMode(m_currentPreviewMode); + + slotEffect(); +} + +void ImageEffect_WhiteBalance::slotColorSelectedFromTarget( const Digikam::DColor &color ) +{ + m_histogramWidget->setHistogramGuideByColor(color); +} + +void ImageEffect_WhiteBalance::slotScaleChanged(int scale) +{ + m_histogramWidget->m_scaleType = scale; + m_histogramWidget->repaint(false); +} + +void ImageEffect_WhiteBalance::slotChannelChanged(int channel) +{ + switch(channel) + { + case LuminosityChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::ValueHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + break; + + case RedChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::RedChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "red" ) ); + break; + + case GreenChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::GreenChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "green" ) ); + break; + + case BlueChannel: + m_histogramWidget->m_channelType = Digikam::HistogramWidget::BlueChannelHistogram; + m_hGradient->setColors( TQColor( "black" ), TQColor( "blue" ) ); + break; + } + + m_histogramWidget->repaint(false); +} + +void ImageEffect_WhiteBalance::slotAutoAdjustExposure() +{ + parentWidget()->setCursor( KCursor::waitCursor() ); + + Digikam::ImageIface* iface = m_previewWidget->imageIface(); + uchar *data = iface->getOriginalImage(); + int width = iface->originalWidth(); + int height = iface->originalHeight(); + bool sb = iface->originalSixteenBit(); + + double blackLevel; + double exposureLevel; + + Digikam::WhiteBalance::autoExposureAdjustement(data, width, height, sb, blackLevel, exposureLevel); + delete [] data; + + m_blackInput->setValue(blackLevel); + m_mainExposureInput->setValue(exposureLevel); + m_fineExposureInput->setValue(0.0); + + parentWidget()->unsetCursor(); + slotEffect(); +} + +void ImageEffect_WhiteBalance::slotEffect() +{ + Digikam::ImageIface* iface = m_previewWidget->imageIface(); + uchar *data = iface->getPreviewImage(); + int w = iface->previewWidth(); + int h = iface->previewHeight(); + bool sb = iface->previewSixteenBit(); + + // Create the new empty destination image data space. + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + m_destinationPreviewData = new uchar[w*h*(sb ? 8 : 4)]; + + double temperature = m_temperatureInput->value(); + double dark = m_darkInput->value(); + double black = m_blackInput->value(); + double mainExposure = m_mainExposureInput->value(); + double fineExposure = m_fineExposureInput->value(); + double gamma = m_gammaInput->value(); + double saturation = m_saturationInput->value(); + double green = m_greenInput->value(); + + Digikam::WhiteBalance wbFilter(sb); + wbFilter.whiteBalance(data, w, h, sb, + black, mainExposure + fineExposure, + temperature, green, dark, + gamma, saturation); + + iface->putPreviewImage(data); + m_previewWidget->updatePreview(); + + // Update histogram. + memcpy (m_destinationPreviewData, data, w*h*(sb ? 8 : 4)); + m_histogramWidget->updateData(m_destinationPreviewData, w, h, sb, 0, 0, 0, false); + delete [] data; +} + +void ImageEffect_WhiteBalance::finalRendering() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + Digikam::ImageIface* iface = m_previewWidget->imageIface(); + uchar *data = iface->getOriginalImage(); + int w = iface->originalWidth(); + int h = iface->originalHeight(); + bool sb = iface->originalSixteenBit(); + + double temperature = m_temperatureInput->value(); + double dark = m_darkInput->value(); + double black = m_blackInput->value(); + double mainExposure = m_mainExposureInput->value(); + double fineExposure = m_fineExposureInput->value(); + double gamma = m_gammaInput->value(); + double saturation = m_saturationInput->value(); + double green = m_greenInput->value(); + + Digikam::WhiteBalance wbFilter(sb); + wbFilter.whiteBalance(data, w, h, sb, + black, mainExposure + fineExposure, + temperature, green, dark, + gamma, saturation); + + iface->putOriginalImage(i18n("White Balance"), data); + delete [] data; + kapp->restoreOverrideCursor(); + accept(); +} + +void ImageEffect_WhiteBalance::resetValues() +{ + m_darkInput->blockSignals(true); + m_blackInput->blockSignals(true); + m_mainExposureInput->blockSignals(true); + m_fineExposureInput->blockSignals(true); + m_gammaInput->blockSignals(true); + m_saturationInput->blockSignals(true); + m_greenInput->blockSignals(true); + m_temperaturePresetCB->blockSignals(true); + + // Neutral color temperature settings is D65 + m_darkInput->setValue(0.5); + m_blackInput->setValue(0.0); + m_mainExposureInput->setValue(0.0); + m_fineExposureInput->setValue(0.0); + m_gammaInput->setValue(1.0); + m_saturationInput->setValue(1.0); + m_greenInput->setValue(1.0); + m_temperaturePresetCB->setCurrentItem(DaylightD65); + slotTemperaturePresetChanged(DaylightD65); + + m_previewWidget->resetSpotPosition(); + m_channelCB->setCurrentItem(LuminosityChannel); + slotChannelChanged(LuminosityChannel); + + m_histogramWidget->reset(); + + m_darkInput->blockSignals(false); + m_blackInput->blockSignals(false); + m_mainExposureInput->blockSignals(false); + m_fineExposureInput->blockSignals(false); + m_gammaInput->blockSignals(false); + m_saturationInput->blockSignals(false); + m_greenInput->blockSignals(false); + m_temperaturePresetCB->blockSignals(false); + slotEffect(); +} + +void ImageEffect_WhiteBalance::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("whitebalance Tool Dialog"); + m_channelCB->setCurrentItem(config->readNumEntry("Histogram Channel", 0)); // Luminosity. + m_scaleBG->setButton(config->readNumEntry("Histogram Scale", Digikam::HistogramWidget::LogScaleHistogram)); + + m_darkInput->setValue(config->readDoubleNumEntry("Dark", 0.5)); + m_blackInput->setValue(config->readDoubleNumEntry("Black", 0.0)); + m_mainExposureInput->setValue(config->readDoubleNumEntry("MainExposure", 0.0)); + m_fineExposureInput->setValue(config->readDoubleNumEntry("FineExposure", 0.0)); + m_gammaInput->setValue(config->readDoubleNumEntry("Gamma", 1.0)); + m_saturationInput->setValue(config->readDoubleNumEntry("Saturation", 1.0)); + m_greenInput->setValue(config->readDoubleNumEntry("Green", 1.0)); + m_temperatureInput->setValue(config->readDoubleNumEntry("Temperature", 6500.0)); + slotTemperatureChanged(m_temperatureInput->value()); + slotChannelChanged(m_channelCB->currentItem()); + slotScaleChanged(m_scaleBG->selectedId()); +} + +void ImageEffect_WhiteBalance::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("whitebalance Tool Dialog"); + config->writeEntry("Histogram Channel", m_channelCB->currentItem()); + config->writeEntry("Histogram Scale", m_scaleBG->selectedId()); + + config->writeEntry("Dark", m_darkInput->value()); + config->writeEntry("Black", m_blackInput->value()); + config->writeEntry("MainExposure", m_mainExposureInput->value()); + config->writeEntry("FineExposure", m_fineExposureInput->value()); + config->writeEntry("Gamma", m_gammaInput->value()); + config->writeEntry("Saturation", m_saturationInput->value()); + config->writeEntry("Green", m_greenInput->value()); + config->writeEntry("Temperature", m_temperatureInput->value()); + config->sync(); +} + +// Load all settings. +void ImageEffect_WhiteBalance::slotUser3() +{ + KURL loadWhiteBalanceFile = KFileDialog::getOpenURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), this, + TQString( i18n("White Color Balance Settings File to Load")) ); + if( loadWhiteBalanceFile.isEmpty() ) + return; + + TQFile file(loadWhiteBalanceFile.path()); + + if ( file.open(IO_ReadOnly) ) + { + TQTextStream stream( &file ); + + if ( stream.readLine() != "# White Color Balance Configuration File V2" ) + { + KMessageBox::error(this, + i18n("\"%1\" is not a White Color Balance settings text file.") + .arg(loadWhiteBalanceFile.fileName())); + file.close(); + return; + } + + blockSignals(true); + m_temperatureInput->setValue( stream.readLine().toDouble() ); + m_darkInput->setValue( stream.readLine().toDouble() ); + m_blackInput->setValue( stream.readLine().toDouble() ); + m_mainExposureInput->setValue( stream.readLine().toDouble() ); + m_fineExposureInput->setValue( stream.readLine().toDouble() ); + m_gammaInput->setValue( stream.readLine().toDouble() ); + m_saturationInput->setValue( stream.readLine().toDouble() ); + m_greenInput->setValue( stream.readLine().toDouble() ); + m_histogramWidget->reset(); + blockSignals(false); + slotEffect(); + } + else + KMessageBox::error(this, i18n("Cannot load settings from the White Color Balance text file.")); + + file.close(); +} + +// Save all settings. +void ImageEffect_WhiteBalance::slotUser2() +{ + KURL saveWhiteBalanceFile = KFileDialog::getSaveURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), this, + TQString( i18n("White Color Balance Settings File to Save")) ); + if( saveWhiteBalanceFile.isEmpty() ) + return; + + TQFile file(saveWhiteBalanceFile.path()); + + if ( file.open(IO_WriteOnly) ) + { + TQTextStream stream( &file ); + stream << "# White Color Balance Configuration File V2\n"; + stream << m_temperatureInput->value() << "\n"; + stream << m_darkInput->value() << "\n"; + stream << m_blackInput->value() << "\n"; + stream << m_mainExposureInput->value() << "\n"; + stream << m_fineExposureInput->value() << "\n"; + stream << m_gammaInput->value() << "\n"; + stream << m_saturationInput->value() << "\n"; + stream << m_greenInput->value() << "\n"; + } + else + KMessageBox::error(this, i18n("Cannot save settings to the White Color Balance text file.")); + + file.close(); +} + +} // NameSpace DigikamWhiteBalanceImagesPlugin + diff --git a/src/imageplugins/whitebalance/imageeffect_whitebalance.h b/src/imageplugins/whitebalance/imageeffect_whitebalance.h new file mode 100644 index 00000000..6bef5607 --- /dev/null +++ b/src/imageplugins/whitebalance/imageeffect_whitebalance.h @@ -0,0 +1,168 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-11 + * Description : a digiKam image editor plugin to correct + * image white balance + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2008 by Guillaume Castagnino <casta at xwing dot info> + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_WHITEBALANCE_H +#define IMAGEEFFECT_WHITEBALANCE_H + +// TQt include. + +#include <tqcolor.h> + +// Digikam includes. + +#include "imagedlgbase.h" + +class TQPushButton; +class TQLabel; +class TQComboBox; +class TQPushButton; +class TQHButtonGroup; + +class KDoubleNumInput; +class KActiveLabel; + +namespace Digikam +{ +class HistogramWidget; +class ColorGradientWidget; +class ImageWidget; +class DColor; +} + +namespace DigikamWhiteBalanceImagesPlugin +{ + +class ImageEffect_WhiteBalance : public Digikam::ImageDlgBase +{ + TQ_OBJECT + + +public: + + ImageEffect_WhiteBalance(TQWidget* parent); + ~ImageEffect_WhiteBalance(); + +protected: + + void finalRendering(); + +private slots: + + void slotUser2(); + void slotUser3(); + void slotEffect(); + void slotColorSelectedFromOriginal(const Digikam::DColor &color); + void slotColorSelectedFromTarget(const Digikam::DColor &color); + void slotScaleChanged(int scale); + void slotChannelChanged(int channel); + void slotTemperatureChanged(double temperature); + void slotTemperaturePresetChanged(int tempPreset); + void slotAutoAdjustExposure(void); + void slotPickerColorButtonActived(); + +private: + + void readUserSettings(); + void writeUserSettings(); + void resetValues(); + +private: + + enum HistogramScale + { + Linear=0, + Logarithmic + }; + + enum ColorChannel + { + LuminosityChannel=0, + RedChannel, + GreenChannel, + BlueChannel + }; + + enum TemperaturePreset + { + Candle=0, + Lamp40W, + Lamp100W, + Lamp200W, + Sunrise, + StudioLamp, + MoonLight, + Neutral, + DaylightD50, + Flash, + Sun, + XeonLamp, + DaylightD65, + None + }; + + uchar *m_destinationPreviewData; + + int m_currentPreviewMode; + + TQPushButton *m_pickTemperature; + TQPushButton *m_autoAdjustExposure; + + TQComboBox *m_temperaturePresetCB; + TQComboBox *m_channelCB; + + TQHButtonGroup *m_scaleBG; + + TQLabel *m_adjTemperatureLabel; + TQLabel *m_temperaturePresetLabel; + TQLabel *m_darkLabel; + TQLabel *m_blackLabel; + TQLabel *m_mainExposureLabel; + TQLabel *m_fineExposureLabel; + TQLabel *m_gammaLabel; + TQLabel *m_saturationLabel; + TQLabel *m_greenLabel; + + KActiveLabel *m_exposureLabel; + KActiveLabel *m_temperatureLabel; + + KDoubleNumInput *m_temperatureInput; + KDoubleNumInput *m_darkInput; + KDoubleNumInput *m_blackInput; + KDoubleNumInput *m_mainExposureInput; + KDoubleNumInput *m_fineExposureInput; + KDoubleNumInput *m_gammaInput; + KDoubleNumInput *m_saturationInput; + KDoubleNumInput *m_greenInput; + + Digikam::HistogramWidget *m_histogramWidget; + + Digikam::ColorGradientWidget *m_hGradient; + + Digikam::ImageWidget *m_previewWidget; +}; + +} // NameSpace DigikamWhiteBalanceImagesPlugin + +#endif /* IMAGEEFFECT_WHITEBALANCE_H */ diff --git a/src/imageplugins/whitebalance/imageplugin_whitebalance.cpp b/src/imageplugins/whitebalance/imageplugin_whitebalance.cpp new file mode 100644 index 00000000..071097fe --- /dev/null +++ b/src/imageplugins/whitebalance/imageplugin_whitebalance.cpp @@ -0,0 +1,71 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-11 + * Description : a digiKam image editor plugin to correct + * image white balance + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> + +// Local includes. + +#include "ddebug.h" +#include "whitebalancetool.h" +#include "imageplugin_whitebalance.h" +#include "imageplugin_whitebalance.moc" + +using namespace DigikamWhiteBalanceImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_whitebalance, + KGenericFactory<ImagePlugin_WhiteBalance>("digikamimageplugin_whitebalance")); + +ImagePlugin_WhiteBalance::ImagePlugin_WhiteBalance(TQObject *parent, const char*, const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_WhiteBalance") +{ + m_whitebalanceAction = new TDEAction(i18n("White Balance..."), "whitebalance", + CTRL+SHIFT+Key_W, + this, TQ_SLOT(slotWhiteBalance()), + actionCollection(), "imageplugin_whitebalance"); + + setXMLFile("digikamimageplugin_whitebalance_ui.rc"); + + DDebug() << "ImagePlugin_WhiteBalance plugin loaded" << endl; +} + +ImagePlugin_WhiteBalance::~ImagePlugin_WhiteBalance() +{ +} + +void ImagePlugin_WhiteBalance::setEnabledActions(bool enable) +{ + m_whitebalanceAction->setEnabled(enable); +} + +void ImagePlugin_WhiteBalance::slotWhiteBalance() +{ + WhiteBalanceTool *wb = new WhiteBalanceTool(this); + loadTool(wb); +} diff --git a/src/imageplugins/whitebalance/imageplugin_whitebalance.h b/src/imageplugins/whitebalance/imageplugin_whitebalance.h new file mode 100644 index 00000000..afc870c1 --- /dev/null +++ b/src/imageplugins/whitebalance/imageplugin_whitebalance.h @@ -0,0 +1,57 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-11 + * Description : a digiKam image editor plugin to correct + * image white balance + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_WHITEBALANCE_H +#define IMAGEPLUGIN_WHITEBALANCE_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_WhiteBalance : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_WhiteBalance(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_WhiteBalance(); + + void setEnabledActions(bool enable); + +private slots: + + void slotWhiteBalance(); + +private: + + TDEAction *m_whitebalanceAction; +}; + +#endif /* IMAGEPLUGIN_WHITEBALANCE_H */ diff --git a/src/imageplugins/whitebalance/whitebalancetool.cpp b/src/imageplugins/whitebalance/whitebalancetool.cpp new file mode 100644 index 00000000..fdbe723a --- /dev/null +++ b/src/imageplugins/whitebalance/whitebalancetool.cpp @@ -0,0 +1,850 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-11 + * Description : a digiKam image editor plugin to correct + * image white balance + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2008 by Guillaume Castagnino <casta at xwing dot info> + * + * 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 <tqcombobox.h> +#include <tqfile.h> +#include <tqframe.h> +#include <tqhbuttongroup.h> +#include <tqhgroupbox.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqpixmap.h> +#include <tqpushbutton.h> +#include <tqtextstream.h> +#include <tqtimer.h> +#include <tqtooltip.h> +#include <tqvbox.h> +#include <tqvgroupbox.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeaboutdata.h> +#include <kactivelabel.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <tdefiledialog.h> +#include <tdeglobalsettings.h> +#include <khelpmenu.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <tdepopupmenu.h> +#include <kprogress.h> +#include <kseparator.h> +#include <kstandarddirs.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> +#include <libkdcraw/rcombobox.h> + +// Digikam includes. + +#include "colorgradientwidget.h" +#include "daboutdata.h" +#include "dcolor.h" +#include "ddebug.h" +#include "dimg.h" +#include "dimgimagefilters.h" +#include "editortoolsettings.h" +#include "histogramwidget.h" +#include "imagehistogram.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "whitebalance.h" + +// Local includes. + +#include "whitebalancetool.h" +#include "whitebalancetool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamWhiteBalanceImagesPlugin +{ + +WhiteBalanceTool::WhiteBalanceTool(TQObject* parent) + : EditorTool(parent) +{ + setName("whitebalance"); + setToolName(i18n("White Balance")); + setToolIcon(SmallIcon("whitebalance")); + + m_destinationPreviewData = 0; + + // ------------------------------------------------------------- + + m_previewWidget = new ImageWidget("whitebalance Tool", 0, + i18n("<p>You can see here the image's white-balance " + "adjustments preview. You can pick color on image to " + "see the color level corresponding on histogram.")); + setToolView(m_previewWidget); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Load| + EditorToolSettings::SaveAs| + EditorToolSettings::Ok| + EditorToolSettings::Cancel); + + TQVBoxLayout* layout2 = new TQVBoxLayout(m_gboxSettings->plainPage(), m_gboxSettings->spacingHint()); + TQGridLayout *grid = new TQGridLayout(layout2, 2, 4); + + 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("<p>Select the histogram channel to display here:<p>" + "<b>Luminosity</b>: display the image's luminosity values.<p>" + "<b>Red</b>: display the red image-channel values.<p>" + "<b>Green</b>: display the green image-channel values.<p>" + "<b>Blue</b>: display the blue image-channel values.<p>")); + + 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("<p>Select the histogram scale here.<p>" + "If the image's maximal counts are small, you can use the linear scale.<p>" + "Logarithmic scale can be used when the maximal counts 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( "<p>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( "<p>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); + + // ------------------------------------------------------------- + + TQVBox *histoBox = new TQVBox(m_gboxSettings->plainPage()); + m_histogramWidget = new HistogramWidget(256, 140, histoBox, false, true, true); + TQWhatsThis::add( m_histogramWidget, i18n("<p>Here you can see the target preview image histogram " + "drawing of the selected image channel. This one is " + "re-computed at any filter settings changes.")); + TQLabel *space = new TQLabel(histoBox); + space->setFixedHeight(1); + m_hGradient = new ColorGradientWidget( ColorGradientWidget::Horizontal, 10, histoBox ); + m_hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + + grid->addMultiCellLayout(l1, 0, 0, 0, 4); + grid->addMultiCellWidget(histoBox, 1, 2, 0, 4); + grid->setMargin(m_gboxSettings->spacingHint()); + grid->setSpacing(m_gboxSettings->spacingHint()); + + // ------------------------------------------------------------- + + TQGridLayout *grid2 = new TQGridLayout(layout2, 13, 5); + + m_temperatureLabel = new KActiveLabel(i18n("<qt><a href='http://en.wikipedia.org/wiki/Color_temperature'>Color Temperature</a> " + " (K): </qt>"), m_gboxSettings->plainPage()); + m_adjTemperatureLabel = new TQLabel(i18n("Adjustment:"), m_gboxSettings->plainPage()); + m_temperatureInput = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_temperatureInput->setPrecision(1); + m_temperatureInput->setRange(1750.0, 12000.0, 10.0); + m_temperatureInput->setDefaultValue(6500.0); + TQWhatsThis::add( m_temperatureInput, i18n("<p>Set here the white balance color temperature in Kelvin.")); + + m_temperaturePresetLabel = new TQLabel(i18n("Preset:"), m_gboxSettings->plainPage()); + m_temperaturePresetCB = new RComboBox(m_gboxSettings->plainPage()); + m_temperaturePresetCB->insertItem(i18n("Candle")); + m_temperaturePresetCB->insertItem(i18n("40W Lamp")); + m_temperaturePresetCB->insertItem(i18n("100W Lamp")); + m_temperaturePresetCB->insertItem(i18n("200W Lamp")); + m_temperaturePresetCB->insertItem(i18n("Sunrise")); + m_temperaturePresetCB->insertItem(i18n("Studio Lamp")); + m_temperaturePresetCB->insertItem(i18n("Moonlight")); + m_temperaturePresetCB->insertItem(i18n("Neutral")); + m_temperaturePresetCB->insertItem(i18n("Daylight D50")); + m_temperaturePresetCB->insertItem(i18n("Photo Flash")); + m_temperaturePresetCB->insertItem(i18n("Sun")); + m_temperaturePresetCB->insertItem(i18n("Xenon Lamp")); + m_temperaturePresetCB->insertItem(i18n("Daylight D65")); + m_temperaturePresetCB->insertItem(i18n("None")); + m_temperaturePresetCB->setDefaultItem(DaylightD65); + TQWhatsThis::add( m_temperaturePresetCB, i18n("<p>Select the white balance color temperature " + "preset to use here:<p>" + "<b>Candle</b>: candle light (1850K).<p>" + "<b>40W Lamp</b>: 40 Watt incandescent lamp (2680K).<p>" + "<b>100W Lamp</b>: 100 Watt incandescent lamp (2800K).<p>" + "<b>200W Lamp</b>: 200 Watt incandescent lamp (3000K).<p>" + "<b>Sunrise</b>: sunrise or sunset light (3200K).<p>" + "<b>Studio Lamp</b>: tungsten lamp used in photo studio " + "or light at 1 hour from dusk/dawn (3400K).<p>" + "<b>Moonlight</b>: moon light (4100K).<p>" + "<b>Neutral</b>: neutral color temperature (4750K).<p>" + "<b>Daylight D50</b>: sunny daylight around noon (5000K).<p>" + "<b>Photo Flash</b>: electronic photo flash (5500K).<p>" + "<b>Sun</b>: effective sun temperature (5770K).<p>" + "<b>Xenon Lamp</b>: xenon lamp or light arc (6420K).<p>" + "<b>Daylight D65</b>: overcast sky light (6500K).<p>" + "<b>None</b>: no preset value.")); + m_pickTemperature = new TQPushButton(m_gboxSettings->plainPage()); + TDEGlobal::dirs()->addResourceType("color-picker-grey", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("color-picker-grey", "color-picker-grey.png"); + m_pickTemperature->setPixmap( TQPixmap( directory + "color-picker-grey.png" ) ); + m_pickTemperature->setToggleButton(true); + TQToolTip::add( m_pickTemperature, i18n( "Temperature tone color picker." ) ); + TQWhatsThis::add( m_pickTemperature, i18n("<p>With this button, you can pick the color from original " + "image used to set white color balance temperature and " + "green component.")); + + KSeparator *line = new KSeparator(Horizontal, m_gboxSettings->plainPage()); + + // ------------------------------------------------------------- + + m_blackLabel = new TQLabel(i18n("Black point:"), m_gboxSettings->plainPage()); + m_blackInput = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_blackInput->setPrecision(2); + m_blackInput->setRange(0.0, 0.05, 0.01); + m_blackInput->setDefaultValue(0.0); + TQWhatsThis::add( m_blackInput, i18n("<p>Set here the black level value.")); + + m_darkLabel = new TQLabel(i18n("Shadows:"), m_gboxSettings->plainPage()); + m_darkInput = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_darkInput->setPrecision(2); + m_darkInput->setRange(0.0, 1.0, 0.01); + m_darkInput->setDefaultValue(0.5); + TQWhatsThis::add( m_darkInput, i18n("<p>Set here the shadows noise suppresion level.")); + + m_saturationLabel = new TQLabel(i18n("Saturation:"), m_gboxSettings->plainPage()); + m_saturationInput = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_saturationInput->setPrecision(2); + m_saturationInput->setRange(0.0, 2.0, 0.01); + m_saturationInput->setDefaultValue(1.0); + TQWhatsThis::add( m_saturationInput, i18n("<p>Set here the saturation value.")); + + m_gammaLabel = new TQLabel(i18n("Gamma:"), m_gboxSettings->plainPage()); + m_gammaInput = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_gammaInput->setPrecision(2); + m_gammaInput->setRange(0.1, 3.0, 0.01); + m_gammaInput->setDefaultValue(1.0); + TQWhatsThis::add( m_gammaInput, i18n("<p>Set here the gamma correction value.")); + + m_greenLabel = new TQLabel(i18n("Green:"), m_gboxSettings->plainPage()); + m_greenInput = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_greenInput->setPrecision(2); + m_greenInput->setRange(0.2, 2.5, 0.01); + m_greenInput->setDefaultValue(1.0); + TQWhatsThis::add(m_greenInput, i18n("<p>Set here the green component to set magenta color " + "cast removal level.")); + + KSeparator *line2 = new KSeparator(Horizontal, m_gboxSettings->plainPage()); + + // ------------------------------------------------------------- + + m_exposureLabel = new KActiveLabel(i18n("<qt><a href='http://en.wikipedia.org/wiki/Exposure_value'>Exposure Compensation</a> " + " (E.V): </qt>"), m_gboxSettings->plainPage()); + m_mainExposureLabel = new TQLabel(i18n("Main:"), m_gboxSettings->plainPage()); + m_autoAdjustExposure = new TQPushButton(m_gboxSettings->plainPage()); + m_autoAdjustExposure->setPixmap(kapp->iconLoader()->loadIcon("system-run", (TDEIcon::Group)TDEIcon::Toolbar)); + TQToolTip::add( m_autoAdjustExposure, i18n( "Auto exposure adjustments" ) ); + TQWhatsThis::add( m_autoAdjustExposure, i18n("<p>With this button, you can automatically adjust Exposure " + "and Black Point values.")); + m_mainExposureInput = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_mainExposureInput->setPrecision(2); + m_mainExposureInput->setRange(-6.0, 8.0, 0.1); + m_mainExposureInput->setDefaultValue(0.0); + TQWhatsThis::add( m_mainExposureInput, i18n("<p>Set here the main exposure compensation value in E.V.")); + + m_fineExposureLabel = new TQLabel(i18n("Fine:"), m_gboxSettings->plainPage()); + m_fineExposureInput = new RDoubleNumInput(m_gboxSettings->plainPage()); + m_fineExposureInput->setPrecision(2); + m_fineExposureInput->setRange(-0.5, 0.5, 0.01); + m_fineExposureInput->setDefaultValue(0.0); + TQWhatsThis::add( m_fineExposureInput, i18n("<p>This value in E.V will be added to main exposure " + "compensation value to set fine exposure adjustment.")); + + // ------------------------------------------------------------- + + grid2->addMultiCellWidget(m_temperatureLabel, 0, 0, 0, 5); + grid2->addMultiCellWidget(m_adjTemperatureLabel, 1, 1, 0, 0); + grid2->addMultiCellWidget(m_pickTemperature, 1, 1, 1, 1); + grid2->addMultiCellWidget(m_temperatureInput, 1, 1, 2, 5); + grid2->addMultiCellWidget(m_temperaturePresetLabel, 2, 2, 0, 0); + grid2->addMultiCellWidget(m_temperaturePresetCB, 2, 2, 2, 5); + + grid2->addMultiCellWidget(line, 3, 3, 0, 5); + + grid2->addMultiCellWidget(m_blackLabel, 4, 4, 0, 0); + grid2->addMultiCellWidget(m_blackInput, 4, 4, 1, 5); + grid2->addMultiCellWidget(m_darkLabel, 5, 5, 0, 0); + grid2->addMultiCellWidget(m_darkInput, 5, 5, 1, 5); + grid2->addMultiCellWidget(m_saturationLabel, 6, 6, 0, 0); + grid2->addMultiCellWidget(m_saturationInput, 6, 6, 1, 5); + grid2->addMultiCellWidget(m_gammaLabel, 7, 7, 0, 0); + grid2->addMultiCellWidget(m_gammaInput, 7, 7, 1, 5); + grid2->addMultiCellWidget(m_greenLabel, 8, 8, 0, 0); + grid2->addMultiCellWidget(m_greenInput, 8, 8, 1, 5); + + grid2->addMultiCellWidget(line2, 9, 9, 0, 5); + + grid2->addMultiCellWidget(m_exposureLabel, 10, 10, 0, 5); + grid2->addMultiCellWidget(m_mainExposureLabel, 11, 11, 0, 0); + grid2->addMultiCellWidget(m_autoAdjustExposure, 11, 11, 1, 1); + grid2->addMultiCellWidget(m_mainExposureInput, 11, 11, 2, 5); + grid2->addMultiCellWidget(m_fineExposureLabel, 12, 12, 0, 1); + grid2->addMultiCellWidget(m_fineExposureInput, 12, 12, 2, 5); + grid2->setRowStretch(13, 10); + grid2->setMargin(m_gboxSettings->spacingHint()); + grid2->setSpacing(m_gboxSettings->spacingHint()); + + setToolSettings(m_gboxSettings); + init(); + + // ------------------------------------------------------------- + + 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_previewWidget, TQ_SIGNAL(spotPositionChangedFromOriginal(const Digikam::DColor&, const TQPoint&)), + this, TQ_SLOT(slotColorSelectedFromOriginal(const Digikam::DColor&))); + + connect(m_previewWidget, TQ_SIGNAL(spotPositionChangedFromTarget(const Digikam::DColor&, const TQPoint&)), + this, TQ_SLOT(slotColorSelectedFromTarget(const Digikam::DColor&))); + + connect(m_previewWidget, TQ_SIGNAL(signalResized()), + this, TQ_SLOT(slotEffect())); + + // ------------------------------------------------------------- + // Correction Filter Slider controls. + + connect(m_temperaturePresetCB, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotTemperaturePresetChanged(int))); + + connect(m_temperatureInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTemperatureChanged(double))); + + connect(m_darkInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_blackInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_mainExposureInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_fineExposureInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_gammaInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_saturationInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + connect(m_greenInput, TQ_SIGNAL(valueChanged (double)), + this, TQ_SLOT(slotTimer())); + + // ------------------------------------------------------------- + // Bouttons slots. + + connect(m_autoAdjustExposure, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotAutoAdjustExposure())); + + connect(m_pickTemperature, TQ_SIGNAL(released()), + this, TQ_SLOT(slotPickerColorButtonActived())); +} + +WhiteBalanceTool::~WhiteBalanceTool() +{ + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; +} + +void WhiteBalanceTool::slotTemperatureChanged(double temperature) +{ + switch((uint)temperature) + { + case 1850: + m_temperaturePresetCB->setCurrentItem(Candle); + break; + + case 2680: + m_temperaturePresetCB->setCurrentItem(Lamp40W); + break; + + case 2800: + m_temperaturePresetCB->setCurrentItem(Lamp100W); + break; + + case 3000: + m_temperaturePresetCB->setCurrentItem(Lamp200W); + break; + + case 3200: + m_temperaturePresetCB->setCurrentItem(Sunrise); + break; + + case 3400: + m_temperaturePresetCB->setCurrentItem(StudioLamp); + break; + + case 4100: + m_temperaturePresetCB->setCurrentItem(MoonLight); + break; + + case 4750: + m_temperaturePresetCB->setCurrentItem(Neutral); + break; + + case 5000: + m_temperaturePresetCB->setCurrentItem(DaylightD50); + break; + + case 5500: + m_temperaturePresetCB->setCurrentItem(Flash); + break; + + case 5770: + m_temperaturePresetCB->setCurrentItem(Sun); + break; + + case 6420: + m_temperaturePresetCB->setCurrentItem(XeonLamp); + break; + + case 6500: + m_temperaturePresetCB->setCurrentItem(DaylightD65); + break; + + default: + m_temperaturePresetCB->setCurrentItem(None); + break; + } + + slotTimer(); +} + +void WhiteBalanceTool::slotTemperaturePresetChanged(int tempPreset) +{ + switch(tempPreset) + { + case Candle: + m_temperatureInput->setValue(1850.0); + break; + + case Lamp40W: + m_temperatureInput->setValue(2680.0); + break; + + case Lamp100W: + m_temperatureInput->setValue(2800.0); + break; + + case Lamp200W: + m_temperatureInput->setValue(3000.0); + break; + + case Sunrise: + m_temperatureInput->setValue(3200.0); + break; + + case StudioLamp: + m_temperatureInput->setValue(3400.0); + break; + + case MoonLight: + m_temperatureInput->setValue(4100.0); + break; + + case Neutral: + m_temperatureInput->setValue(4750.0); + break; + + case DaylightD50: + m_temperatureInput->setValue(5000.0); + break; + + case Flash: + m_temperatureInput->setValue(5500.0); + break; + + case Sun: + m_temperatureInput->setValue(5770.0); + break; + + case XeonLamp: + m_temperatureInput->setValue(6420.0); + break; + + case DaylightD65: + m_temperatureInput->setValue(6500.0); + break; + + default: // None. + break; + } + + slotEffect(); +} + +void WhiteBalanceTool::slotPickerColorButtonActived() +{ + // Save previous rendering mode and toggle to original image. + m_currentPreviewMode = m_previewWidget->getRenderingPreviewMode(); + m_previewWidget->setRenderingPreviewMode(ImageGuideWidget::PreviewOriginalImage); +} + +void WhiteBalanceTool::slotColorSelectedFromOriginal(const DColor &color) +{ + if ( m_pickTemperature->isOn() ) + { + DColor dc = color; + TQColor tc = dc.getTQColor(); + double temperatureLevel, greenLevel; + + WhiteBalance::autoWBAdjustementFromColor(tc, temperatureLevel, greenLevel); + + m_temperatureInput->setValue(temperatureLevel); + m_greenInput->setValue(greenLevel); + m_pickTemperature->setOn(false); + } + else + return; + + // restore previous rendering mode. + m_previewWidget->setRenderingPreviewMode(m_currentPreviewMode); + + slotEffect(); +} + +void WhiteBalanceTool::slotColorSelectedFromTarget(const DColor& color) +{ + m_histogramWidget->setHistogramGuideByColor(color); +} + +void WhiteBalanceTool::slotScaleChanged(int scale) +{ + m_histogramWidget->m_scaleType = scale; + m_histogramWidget->repaint(false); +} + +void WhiteBalanceTool::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 WhiteBalanceTool::slotAutoAdjustExposure() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + + ImageIface* iface = m_previewWidget->imageIface(); + uchar *data = iface->getOriginalImage(); + int width = iface->originalWidth(); + int height = iface->originalHeight(); + bool sb = iface->originalSixteenBit(); + + double blackLevel; + double exposureLevel; + + WhiteBalance::autoExposureAdjustement(data, width, height, sb, blackLevel, exposureLevel); + delete [] data; + + m_blackInput->setValue(blackLevel); + m_mainExposureInput->setValue(exposureLevel); + m_fineExposureInput->setValue(0.0); + + kapp->restoreOverrideCursor(); + slotEffect(); +} + +void WhiteBalanceTool::slotEffect() +{ + ImageIface* iface = m_previewWidget->imageIface(); + uchar *data = iface->getPreviewImage(); + int w = iface->previewWidth(); + int h = iface->previewHeight(); + bool sb = iface->previewSixteenBit(); + + // Create the new empty destination image data space. + m_histogramWidget->stopHistogramComputation(); + + if (m_destinationPreviewData) + delete [] m_destinationPreviewData; + + m_destinationPreviewData = new uchar[w*h*(sb ? 8 : 4)]; + + double temperature = m_temperatureInput->value(); + double dark = m_darkInput->value(); + double black = m_blackInput->value(); + double mainExposure = m_mainExposureInput->value(); + double fineExposure = m_fineExposureInput->value(); + double gamma = m_gammaInput->value(); + double saturation = m_saturationInput->value(); + double green = m_greenInput->value(); + + WhiteBalance wbFilter(sb); + wbFilter.whiteBalance(data, w, h, sb, + black, mainExposure + fineExposure, + temperature, green, dark, + gamma, saturation); + + iface->putPreviewImage(data); + m_previewWidget->updatePreview(); + + // Update histogram. + memcpy (m_destinationPreviewData, data, w*h*(sb ? 8 : 4)); + m_histogramWidget->updateData(m_destinationPreviewData, w, h, sb, 0, 0, 0, false); + delete [] data; +} + +void WhiteBalanceTool::finalRendering() +{ + kapp->setOverrideCursor( KCursor::waitCursor() ); + ImageIface* iface = m_previewWidget->imageIface(); + uchar *data = iface->getOriginalImage(); + int w = iface->originalWidth(); + int h = iface->originalHeight(); + bool sb = iface->originalSixteenBit(); + + double temperature = m_temperatureInput->value(); + double dark = m_darkInput->value(); + double black = m_blackInput->value(); + double mainExposure = m_mainExposureInput->value(); + double fineExposure = m_fineExposureInput->value(); + double gamma = m_gammaInput->value(); + double saturation = m_saturationInput->value(); + double green = m_greenInput->value(); + + WhiteBalance wbFilter(sb); + wbFilter.whiteBalance(data, w, h, sb, + black, mainExposure + fineExposure, + temperature, green, dark, + gamma, saturation); + + iface->putOriginalImage(i18n("White Balance"), data); + delete [] data; + kapp->restoreOverrideCursor(); +} + +void WhiteBalanceTool::slotResetSettings() +{ + m_blackInput->blockSignals(true); + m_darkInput->blockSignals(true); + m_fineExposureInput->blockSignals(true); + m_gammaInput->blockSignals(true); + m_greenInput->blockSignals(true); + m_mainExposureInput->blockSignals(true); + m_saturationInput->blockSignals(true); + m_temperatureInput->blockSignals(true); + m_temperaturePresetCB->blockSignals(true); + + // Neutral color temperature settings is D65 + m_blackInput->slotReset(); + m_darkInput->slotReset(); + m_fineExposureInput->slotReset(); + m_gammaInput->slotReset(); + m_greenInput->slotReset(); + m_mainExposureInput->slotReset(); + m_saturationInput->slotReset(); + m_temperaturePresetCB->slotReset(); + slotTemperaturePresetChanged(m_temperaturePresetCB->defaultItem()); + m_temperatureInput->slotReset(); + + m_previewWidget->resetSpotPosition(); + m_channelCB->setCurrentItem(LuminosityChannel); + slotChannelChanged(LuminosityChannel); + + m_histogramWidget->reset(); + + m_blackInput->blockSignals(false); + m_darkInput->blockSignals(false); + m_fineExposureInput->blockSignals(false); + m_gammaInput->blockSignals(false); + m_greenInput->blockSignals(false); + m_mainExposureInput->blockSignals(false); + m_saturationInput->blockSignals(false); + m_temperatureInput->blockSignals(false); + m_temperaturePresetCB->blockSignals(false); + + slotEffect(); +} + +void WhiteBalanceTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("whitebalance Tool"); + m_channelCB->setCurrentItem(config->readNumEntry("Histogram Channel", 0)); // Luminosity. + m_scaleBG->setButton(config->readNumEntry("Histogram Scale", HistogramWidget::LogScaleHistogram)); + + m_darkInput->setValue(config->readDoubleNumEntry("Dark",m_darkInput->defaultValue())); + m_blackInput->setValue(config->readDoubleNumEntry("Black", m_blackInput->defaultValue())); + m_mainExposureInput->setValue(config->readDoubleNumEntry("MainExposure", m_mainExposureInput->defaultValue())); + m_fineExposureInput->setValue(config->readDoubleNumEntry("FineExposure", m_fineExposureInput->defaultValue())); + m_gammaInput->setValue(config->readDoubleNumEntry("Gamma", m_gammaInput->defaultValue())); + m_saturationInput->setValue(config->readDoubleNumEntry("Saturation", m_saturationInput->defaultValue())); + m_greenInput->setValue(config->readDoubleNumEntry("Green", m_greenInput->defaultValue())); + m_temperatureInput->setValue(config->readDoubleNumEntry("Temperature", m_temperatureInput->defaultValue())); + + slotTemperatureChanged(m_temperatureInput->value()); + m_histogramWidget->reset(); + slotChannelChanged(m_channelCB->currentItem()); + slotScaleChanged(m_scaleBG->selectedId()); +} + +void WhiteBalanceTool::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("whitebalance Tool"); + config->writeEntry("Histogram Channel", m_channelCB->currentItem()); + config->writeEntry("Histogram Scale", m_scaleBG->selectedId()); + + config->writeEntry("Dark", m_darkInput->value()); + config->writeEntry("Black", m_blackInput->value()); + config->writeEntry("MainExposure", m_mainExposureInput->value()); + config->writeEntry("FineExposure", m_fineExposureInput->value()); + config->writeEntry("Gamma", m_gammaInput->value()); + config->writeEntry("Saturation", m_saturationInput->value()); + config->writeEntry("Green", m_greenInput->value()); + config->writeEntry("Temperature", m_temperatureInput->value()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void WhiteBalanceTool::slotLoadSettings() +{ + KURL loadWhiteBalanceFile = KFileDialog::getOpenURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), kapp->activeWindow(), + TQString( i18n("White Color Balance Settings File to Load")) ); + if( loadWhiteBalanceFile.isEmpty() ) + return; + + TQFile file(loadWhiteBalanceFile.path()); + + if ( file.open(IO_ReadOnly) ) + { + TQTextStream stream( &file ); + + if ( stream.readLine() != "# White Color Balance Configuration File V2" ) + { + KMessageBox::error(kapp->activeWindow(), + i18n("\"%1\" is not a White Color Balance settings text file.") + .arg(loadWhiteBalanceFile.fileName())); + file.close(); + return; + } + + blockSignals(true); + m_temperatureInput->setValue( stream.readLine().toDouble() ); + m_darkInput->setValue( stream.readLine().toDouble() ); + m_blackInput->setValue( stream.readLine().toDouble() ); + m_mainExposureInput->setValue( stream.readLine().toDouble() ); + m_fineExposureInput->setValue( stream.readLine().toDouble() ); + m_gammaInput->setValue( stream.readLine().toDouble() ); + m_saturationInput->setValue( stream.readLine().toDouble() ); + m_greenInput->setValue( stream.readLine().toDouble() ); + m_histogramWidget->reset(); + blockSignals(false); + slotEffect(); + } + else + KMessageBox::error(kapp->activeWindow(), i18n("Cannot load settings from the White Color Balance text file.")); + + file.close(); +} + +void WhiteBalanceTool::slotSaveAsSettings() +{ + KURL saveWhiteBalanceFile = KFileDialog::getSaveURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), kapp->activeWindow(), + TQString( i18n("White Color Balance Settings File to Save")) ); + if( saveWhiteBalanceFile.isEmpty() ) + return; + + TQFile file(saveWhiteBalanceFile.path()); + + if ( file.open(IO_WriteOnly) ) + { + TQTextStream stream( &file ); + stream << "# White Color Balance Configuration File V2\n"; + stream << m_temperatureInput->value() << "\n"; + stream << m_darkInput->value() << "\n"; + stream << m_blackInput->value() << "\n"; + stream << m_mainExposureInput->value() << "\n"; + stream << m_fineExposureInput->value() << "\n"; + stream << m_gammaInput->value() << "\n"; + stream << m_saturationInput->value() << "\n"; + stream << m_greenInput->value() << "\n"; + } + else + KMessageBox::error(kapp->activeWindow(), i18n("Cannot save settings to the White Color Balance text file.")); + + file.close(); +} + +} // NameSpace DigikamWhiteBalanceImagesPlugin diff --git a/src/imageplugins/whitebalance/whitebalancetool.h b/src/imageplugins/whitebalance/whitebalancetool.h new file mode 100644 index 00000000..2df2877e --- /dev/null +++ b/src/imageplugins/whitebalance/whitebalancetool.h @@ -0,0 +1,174 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-11 + * Description : a digiKam image editor plugin to correct + * image white balance + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2008 by Guillaume Castagnino <casta at xwing dot info> + * + * 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. + * + * ============================================================ */ + +#ifndef WHITEBALANCETOOL_H +#define WHITEBALANCETOOL_H + +// TQt includes. + +#include <tqcolor.h> + +// Digikam includes. + +#include "editortool.h" + +class TQComboBox; +class TQPushButton; +class TQLabel; +class TQPushButton; +class TQHButtonGroup; + +class KActiveLabel; + +namespace KDcrawIface +{ +class RDoubleNumInput; +class RComboBox; +} + +namespace Digikam +{ +class HistogramWidget; +class ColorGradientWidget; +class ImageWidget; +class DColor; +class EditorToolSettings; +} + +namespace DigikamWhiteBalanceImagesPlugin +{ + +class WhiteBalanceTool : public Digikam::EditorTool +{ + TQ_OBJECT + + +public: + + WhiteBalanceTool(TQObject* parent); + ~WhiteBalanceTool(); + +private: + + void readSettings(); + void writeSettings(); + void finalRendering(); + +private slots: + + void slotSaveAsSettings(); + void slotLoadSettings(); + void slotEffect(); + void slotResetSettings(); + void slotColorSelectedFromOriginal(const Digikam::DColor &color); + void slotColorSelectedFromTarget(const Digikam::DColor &color); + void slotScaleChanged(int scale); + void slotChannelChanged(int channel); + void slotTemperatureChanged(double temperature); + void slotTemperaturePresetChanged(int tempPreset); + void slotAutoAdjustExposure(void); + void slotPickerColorButtonActived(); + +private: + + enum HistogramScale + { + Linear=0, + Logarithmic + }; + + enum ColorChannel + { + LuminosityChannel=0, + RedChannel, + GreenChannel, + BlueChannel + }; + + enum TemperaturePreset + { + Candle=0, + Lamp40W, + Lamp100W, + Lamp200W, + Sunrise, + StudioLamp, + MoonLight, + Neutral, + DaylightD50, + Flash, + Sun, + XeonLamp, + DaylightD65, + None + }; + + uchar *m_destinationPreviewData; + + int m_currentPreviewMode; + + TQComboBox *m_channelCB; + + TQPushButton *m_pickTemperature; + TQPushButton *m_autoAdjustExposure; + + KDcrawIface::RComboBox *m_temperaturePresetCB; + + TQHButtonGroup *m_scaleBG; + + TQLabel *m_adjTemperatureLabel; + TQLabel *m_temperaturePresetLabel; + TQLabel *m_darkLabel; + TQLabel *m_blackLabel; + TQLabel *m_mainExposureLabel; + TQLabel *m_fineExposureLabel; + TQLabel *m_gammaLabel; + TQLabel *m_saturationLabel; + TQLabel *m_greenLabel; + + KActiveLabel *m_exposureLabel; + KActiveLabel *m_temperatureLabel; + + KDcrawIface::RDoubleNumInput *m_temperatureInput; + KDcrawIface::RDoubleNumInput *m_darkInput; + KDcrawIface::RDoubleNumInput *m_blackInput; + KDcrawIface::RDoubleNumInput *m_mainExposureInput; + KDcrawIface::RDoubleNumInput *m_fineExposureInput; + KDcrawIface::RDoubleNumInput *m_gammaInput; + KDcrawIface::RDoubleNumInput *m_saturationInput; + KDcrawIface::RDoubleNumInput *m_greenInput; + + Digikam::HistogramWidget *m_histogramWidget; + + Digikam::ColorGradientWidget *m_hGradient; + + Digikam::ImageWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamWhiteBalanceImagesPlugin + +#endif /* WHITEBALANCETOOL_H */ |