summaryrefslogtreecommitdiffstats
path: root/chalk/plugins/filters/oilpaintfilter/kis_oilpaint_filter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chalk/plugins/filters/oilpaintfilter/kis_oilpaint_filter.cpp')
-rw-r--r--chalk/plugins/filters/oilpaintfilter/kis_oilpaint_filter.cpp256
1 files changed, 256 insertions, 0 deletions
diff --git a/chalk/plugins/filters/oilpaintfilter/kis_oilpaint_filter.cpp b/chalk/plugins/filters/oilpaintfilter/kis_oilpaint_filter.cpp
new file mode 100644
index 000000000..de869a424
--- /dev/null
+++ b/chalk/plugins/filters/oilpaintfilter/kis_oilpaint_filter.cpp
@@ -0,0 +1,256 @@
+/*
+ * This file is part of Chalk
+ *
+ * Copyright (c) 2004 Michael Thaler <michael.thaler@physik.tu-muenchen.de>
+ *
+ * ported from digikam, Copyright 2004 by Gilles Caulier,
+ * Original Oilpaint algorithm copyrighted 2004 by
+ * Pieter Z. Voloshyn <pieter_voloshyn at ame.com.br>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <stdlib.h>
+#include <vector>
+
+#include <tqpoint.h>
+#include <tqspinbox.h>
+
+#include <tdelocale.h>
+#include <kiconloader.h>
+#include <kinstance.h>
+#include <tdemessagebox.h>
+#include <kstandarddirs.h>
+#include <tdetempfile.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <knuminput.h>
+
+#include <kis_doc.h>
+#include <kis_image.h>
+#include <kis_iterators_pixel.h>
+#include <kis_layer.h>
+#include <kis_filter_registry.h>
+#include <kis_global.h>
+#include <kis_types.h>
+#include <kis_progress_display_interface.h>
+
+#include "kis_multi_integer_filter_widget.h"
+#include "kis_oilpaint_filter.h"
+
+KisOilPaintFilter::KisOilPaintFilter() : KisFilter(id(), "artistic", i18n("&Oilpaint..."))
+{
+}
+
+void KisOilPaintFilter::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* configuration, const TQRect& rect)
+{
+
+ if (!configuration) {
+ kdWarning() << "No configuration object for oilpaint filter\n";
+ return;
+ }
+
+ Q_UNUSED(dst);
+
+ TQ_INT32 x = rect.x(), y = rect.y();
+ TQ_INT32 width = rect.width();
+ TQ_INT32 height = rect.height();
+
+ //read the filter configuration values from the KisFilterConfiguration object
+ TQ_UINT32 brushSize = ((KisOilPaintFilterConfiguration*)configuration)->brushSize();
+ TQ_UINT32 smooth = ((KisOilPaintFilterConfiguration*)configuration)->smooth();
+
+
+ OilPaint(src, dst, x, y, width, height, brushSize, smooth);
+}
+
+// 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 KisOilPaintFilter::OilPaint(KisPaintDeviceSP src, KisPaintDeviceSP dst, int x, int y, int w, int h, int BrushSize, int Smoothness)
+{
+ setProgressTotalSteps(h);
+ setProgressStage(i18n("Applying oilpaint filter..."),0);
+
+ TQRect bounds(x, y, w, h);
+
+ for (TQ_INT32 yOffset = 0; yOffset < h; yOffset++) {
+
+ KisHLineIteratorPixel it = src->createHLineIterator(x, y + yOffset, w, false);
+ KisHLineIteratorPixel dstIt = dst->createHLineIterator(x, y + yOffset, w, true);
+
+ while (!it.isDone() && !cancelRequested()) {
+
+ if (it.isSelected()) {
+
+ uint color = MostFrequentColor(src, bounds, it.x(), it.y(), BrushSize, Smoothness);
+ dst->colorSpace()->fromTQColor(TQColor(tqRed(color), tqGreen(color), tqBlue(color)), tqAlpha(color), dstIt.rawData());
+ }
+
+ ++it;
+ ++dstIt;
+ }
+
+ setProgress(yOffset);
+ }
+
+ setProgressDone();
+}
+
+// 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
+ */
+
+uint KisOilPaintFilter::MostFrequentColor (KisPaintDeviceSP src, const TQRect& bounds, int X, int Y, int Radius, int Intensity)
+{
+ uint color;
+ uint I;
+
+ double Scale = Intensity / 255.0;
+
+ // Alloc some arrays to be used
+ uchar *IntensityCount = new uchar[(Intensity + 1) * sizeof (uchar)];
+ uint *AverageColorR = new uint[(Intensity + 1) * sizeof (uint)];
+ uint *AverageColorG = new uint[(Intensity + 1) * sizeof (uint)];
+ uint *AverageColorB = new uint[(Intensity + 1) * sizeof (uint)];
+
+ // Erase the array
+ memset(IntensityCount, 0, (Intensity + 1) * sizeof (uchar));
+
+ /*for (i = 0; i <= Intensity; ++i)
+ IntensityCount[i] = 0;*/
+
+ KisRectIteratorPixel it = src->createRectIterator(X - Radius, Y - Radius, (2 * Radius) + 1, (2 * Radius) + 1, false);
+
+ while (!it.isDone()) {
+
+ if (bounds.contains(it.x(), it.y())) {
+
+// XXX: COLORSPACE_INDEPENDENCE
+
+ TQColor c;
+ src->colorSpace()->toTQColor(it.rawData(), &c);
+
+ // Swapping red and blue here is done because that gives the same
+ // output as digikam, even though it might be interpreted as a bug
+ // in both applications.
+ int b = c.red();
+ int g = c.green();
+ int r = c.blue();
+
+ I = (uint)(GetIntensity (r, g, b) * Scale);
+ IntensityCount[I]++;
+
+ if (IntensityCount[I] == 1)
+ {
+ AverageColorR[I] = r;
+ AverageColorG[I] = g;
+ AverageColorB[I] = b;
+ }
+ else
+ {
+ AverageColorR[I] += r;
+ AverageColorG[I] += g;
+ AverageColorB[I] += b;
+ }
+ }
+
+ ++it;
+ }
+
+ I = 0;
+ int MaxInstance = 0;
+
+ for (int i = 0 ; i <= Intensity ; ++i)
+ {
+ if (IntensityCount[i] > MaxInstance)
+ {
+ I = i;
+ MaxInstance = IntensityCount[i];
+ }
+ }
+
+ int R, G, B;
+ if (MaxInstance != 0) {
+ R = AverageColorR[I] / MaxInstance;
+ G = AverageColorG[I] / MaxInstance;
+ B = AverageColorB[I] / MaxInstance;
+ } else {
+ R = 0;
+ G = 0;
+ B = 0;
+ }
+
+ // Swap red and blue back to get the correct colour.
+ color = tqRgb (B, G, R);
+
+ delete [] IntensityCount; // free all the arrays
+ delete [] AverageColorR;
+ delete [] AverageColorG;
+ delete [] AverageColorB;
+
+ return (color); // return the most frequenty color
+}
+
+
+KisFilterConfigWidget * KisOilPaintFilter::createConfigurationWidget(TQWidget* parent, KisPaintDeviceSP /*dev*/)
+{
+ vKisIntegerWidgetParam param;
+ param.push_back( KisIntegerWidgetParam( 1, 5, 1, i18n("Brush size"), "brushSize" ) );
+ param.push_back( KisIntegerWidgetParam( 10, 255, 30, i18n("Smooth"), "smooth" ) );
+ return new KisMultiIntegerFilterWidget(parent, id().id().ascii(), id().id().ascii(), param );
+}
+
+KisFilterConfiguration* KisOilPaintFilter::configuration(TQWidget* nwidget)
+{
+ KisMultiIntegerFilterWidget* widget = (KisMultiIntegerFilterWidget*) nwidget;
+ if( widget == 0 )
+ {
+ return new KisOilPaintFilterConfiguration( 1, 30);
+ } else {
+ return new KisOilPaintFilterConfiguration( widget->valueAt( 0 ), widget->valueAt( 1 ) );
+ }
+}
+
+std::list<KisFilterConfiguration*> KisOilPaintFilter::listOfExamplesConfiguration(KisPaintDeviceSP )
+{
+ std::list<KisFilterConfiguration*> list;
+ list.insert(list.begin(), new KisOilPaintFilterConfiguration( 1, 30));
+ return list;
+}
+