diff options
Diffstat (limited to 'src/imageplugins/colorfx')
-rw-r--r-- | src/imageplugins/colorfx/Makefile.am | 34 | ||||
-rw-r--r-- | src/imageplugins/colorfx/colorfxtool.cpp | 699 | ||||
-rw-r--r-- | src/imageplugins/colorfx/colorfxtool.h | 136 | ||||
-rw-r--r-- | src/imageplugins/colorfx/digikamimageplugin_colorfx.desktop | 40 | ||||
-rw-r--r-- | src/imageplugins/colorfx/digikamimageplugin_colorfx_ui.rc | 20 | ||||
-rw-r--r-- | src/imageplugins/colorfx/imageeffect_colorfx.cpp | 690 | ||||
-rw-r--r-- | src/imageplugins/colorfx/imageeffect_colorfx.h | 131 | ||||
-rw-r--r-- | src/imageplugins/colorfx/imageplugin_colorfx.cpp | 73 | ||||
-rw-r--r-- | src/imageplugins/colorfx/imageplugin_colorfx.h | 57 |
9 files changed, 1880 insertions, 0 deletions
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 */ |