diff options
Diffstat (limited to 'chalk/plugins/filters/oilpaintfilter/kis_oilpaint_filter.cpp')
-rw-r--r-- | chalk/plugins/filters/oilpaintfilter/kis_oilpaint_filter.cpp | 256 |
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; +} + |