KOffice – TDE office suite
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

kis_oilpaint_filter.cc 8.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /*
  2. * This file is part of Chalk
  3. *
  4. * Copyright (c) 2004 Michael Thaler <michael.thaler@physik.tu-muenchen.de>
  5. *
  6. * ported from digikam, Copyright 2004 by Gilles Caulier,
  7. * Original Oilpaint algorithm copyrighted 2004 by
  8. * Pieter Z. Voloshyn <pieter_voloshyn at ame.com.br>.
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  23. */
  24. #include <stdlib.h>
  25. #include <vector>
  26. #include <tqpoint.h>
  27. #include <tqspinbox.h>
  28. #include <tdelocale.h>
  29. #include <kiconloader.h>
  30. #include <kinstance.h>
  31. #include <tdemessagebox.h>
  32. #include <kstandarddirs.h>
  33. #include <tdetempfile.h>
  34. #include <kdebug.h>
  35. #include <kgenericfactory.h>
  36. #include <knuminput.h>
  37. #include <kis_doc.h>
  38. #include <kis_image.h>
  39. #include <kis_iterators_pixel.h>
  40. #include <kis_layer.h>
  41. #include <kis_filter_registry.h>
  42. #include <kis_global.h>
  43. #include <kis_types.h>
  44. #include <kis_progress_display_interface.h>
  45. #include "kis_multi_integer_filter_widget.h"
  46. #include "kis_oilpaint_filter.h"
  47. KisOilPaintFilter::KisOilPaintFilter() : KisFilter(id(), "artistic", i18n("&Oilpaint..."))
  48. {
  49. }
  50. void KisOilPaintFilter::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* configuration, const TQRect& rect)
  51. {
  52. if (!configuration) {
  53. kdWarning() << "No configuration object for oilpaint filter\n";
  54. return;
  55. }
  56. Q_UNUSED(dst);
  57. TQ_INT32 x = rect.x(), y = rect.y();
  58. TQ_INT32 width = rect.width();
  59. TQ_INT32 height = rect.height();
  60. //read the filter configuration values from the KisFilterConfiguration object
  61. TQ_UINT32 brushSize = ((KisOilPaintFilterConfiguration*)configuration)->brushSize();
  62. TQ_UINT32 smooth = ((KisOilPaintFilterConfiguration*)configuration)->smooth();
  63. OilPaint(src, dst, x, y, width, height, brushSize, smooth);
  64. }
  65. // This method have been ported from Pieter Z. Voloshyn algorithm code.
  66. /* Function to apply the OilPaint effect.
  67. *
  68. * data => The image data in RGBA mode.
  69. * w => Width of image.
  70. * h => Height of image.
  71. * BrushSize => Brush size.
  72. * Smoothness => Smooth value.
  73. *
  74. * Theory => Using MostFrequentColor function we take the main color in
  75. * a matrix and simply write at the original position.
  76. */
  77. void KisOilPaintFilter::OilPaint(KisPaintDeviceSP src, KisPaintDeviceSP dst, int x, int y, int w, int h, int BrushSize, int Smoothness)
  78. {
  79. setProgressTotalSteps(h);
  80. setProgressStage(i18n("Applying oilpaint filter..."),0);
  81. TQRect bounds(x, y, w, h);
  82. for (TQ_INT32 yOffset = 0; yOffset < h; yOffset++) {
  83. KisHLineIteratorPixel it = src->createHLineIterator(x, y + yOffset, w, false);
  84. KisHLineIteratorPixel dstIt = dst->createHLineIterator(x, y + yOffset, w, true);
  85. while (!it.isDone() && !cancelRequested()) {
  86. if (it.isSelected()) {
  87. uint color = MostFrequentColor(src, bounds, it.x(), it.y(), BrushSize, Smoothness);
  88. dst->colorSpace()->fromTQColor(TQColor(tqRed(color), tqGreen(color), tqBlue(color)), tqAlpha(color), dstIt.rawData());
  89. }
  90. ++it;
  91. ++dstIt;
  92. }
  93. setProgress(yOffset);
  94. }
  95. setProgressDone();
  96. }
  97. // This method have been ported from Pieter Z. Voloshyn algorithm code.
  98. /* Function to determine the most frequent color in a matrix
  99. *
  100. * Bits => Bits array
  101. * Width => Image width
  102. * Height => Image height
  103. * X => Position horizontal
  104. * Y => Position vertical
  105. * Radius => Is the radius of the matrix to be analized
  106. * Intensity => Intensity to calcule
  107. *
  108. * Theory => This function creates a matrix with the analized pixel in
  109. * the center of this matrix and find the most frequenty color
  110. */
  111. uint KisOilPaintFilter::MostFrequentColor (KisPaintDeviceSP src, const TQRect& bounds, int X, int Y, int Radius, int Intensity)
  112. {
  113. uint color;
  114. uint I;
  115. double Scale = Intensity / 255.0;
  116. // Alloc some arrays to be used
  117. uchar *IntensityCount = new uchar[(Intensity + 1) * sizeof (uchar)];
  118. uint *AverageColorR = new uint[(Intensity + 1) * sizeof (uint)];
  119. uint *AverageColorG = new uint[(Intensity + 1) * sizeof (uint)];
  120. uint *AverageColorB = new uint[(Intensity + 1) * sizeof (uint)];
  121. // Erase the array
  122. memset(IntensityCount, 0, (Intensity + 1) * sizeof (uchar));
  123. /*for (i = 0; i <= Intensity; ++i)
  124. IntensityCount[i] = 0;*/
  125. KisRectIteratorPixel it = src->createRectIterator(X - Radius, Y - Radius, (2 * Radius) + 1, (2 * Radius) + 1, false);
  126. while (!it.isDone()) {
  127. if (bounds.contains(it.x(), it.y())) {
  128. // XXX: COLORSPACE_INDEPENDENCE
  129. TQColor c;
  130. src->colorSpace()->toTQColor(it.rawData(), &c);
  131. // Swapping red and blue here is done because that gives the same
  132. // output as digikam, even though it might be interpreted as a bug
  133. // in both applications.
  134. int b = c.red();
  135. int g = c.green();
  136. int r = c.blue();
  137. I = (uint)(GetIntensity (r, g, b) * Scale);
  138. IntensityCount[I]++;
  139. if (IntensityCount[I] == 1)
  140. {
  141. AverageColorR[I] = r;
  142. AverageColorG[I] = g;
  143. AverageColorB[I] = b;
  144. }
  145. else
  146. {
  147. AverageColorR[I] += r;
  148. AverageColorG[I] += g;
  149. AverageColorB[I] += b;
  150. }
  151. }
  152. ++it;
  153. }
  154. I = 0;
  155. int MaxInstance = 0;
  156. for (int i = 0 ; i <= Intensity ; ++i)
  157. {
  158. if (IntensityCount[i] > MaxInstance)
  159. {
  160. I = i;
  161. MaxInstance = IntensityCount[i];
  162. }
  163. }
  164. int R, G, B;
  165. if (MaxInstance != 0) {
  166. R = AverageColorR[I] / MaxInstance;
  167. G = AverageColorG[I] / MaxInstance;
  168. B = AverageColorB[I] / MaxInstance;
  169. } else {
  170. R = 0;
  171. G = 0;
  172. B = 0;
  173. }
  174. // Swap red and blue back to get the correct colour.
  175. color = tqRgb (B, G, R);
  176. delete [] IntensityCount; // free all the arrays
  177. delete [] AverageColorR;
  178. delete [] AverageColorG;
  179. delete [] AverageColorB;
  180. return (color); // return the most frequenty color
  181. }
  182. KisFilterConfigWidget * KisOilPaintFilter::createConfigurationWidget(TQWidget* parent, KisPaintDeviceSP /*dev*/)
  183. {
  184. vKisIntegerWidgetParam param;
  185. param.push_back( KisIntegerWidgetParam( 1, 5, 1, i18n("Brush size"), "brushSize" ) );
  186. param.push_back( KisIntegerWidgetParam( 10, 255, 30, i18n("Smooth"), "smooth" ) );
  187. return new KisMultiIntegerFilterWidget(parent, id().id().ascii(), id().id().ascii(), param );
  188. }
  189. KisFilterConfiguration* KisOilPaintFilter::configuration(TQWidget* nwidget)
  190. {
  191. KisMultiIntegerFilterWidget* widget = (KisMultiIntegerFilterWidget*) nwidget;
  192. if( widget == 0 )
  193. {
  194. return new KisOilPaintFilterConfiguration( 1, 30);
  195. } else {
  196. return new KisOilPaintFilterConfiguration( widget->valueAt( 0 ), widget->valueAt( 1 ) );
  197. }
  198. }
  199. std::list<KisFilterConfiguration*> KisOilPaintFilter::listOfExamplesConfiguration(KisPaintDeviceSP )
  200. {
  201. std::list<KisFilterConfiguration*> list;
  202. list.insert(list.begin(), new KisOilPaintFilterConfiguration( 1, 30));
  203. return list;
  204. }