The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

293 lines
8.9KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. ImageConvolutionKernel::ImageConvolutionKernel (const int size_)
  20. : values ((size_t) (size_ * size_)),
  21. size (size_)
  22. {
  23. clear();
  24. }
  25. ImageConvolutionKernel::~ImageConvolutionKernel()
  26. {
  27. }
  28. //==============================================================================
  29. float ImageConvolutionKernel::getKernelValue (const int x, const int y) const noexcept
  30. {
  31. if (isPositiveAndBelow (x, size) && isPositiveAndBelow (y, size))
  32. return values [x + y * size];
  33. jassertfalse;
  34. return 0;
  35. }
  36. void ImageConvolutionKernel::setKernelValue (const int x, const int y, const float value) noexcept
  37. {
  38. if (isPositiveAndBelow (x, size) && isPositiveAndBelow (y, size))
  39. {
  40. values [x + y * size] = value;
  41. }
  42. else
  43. {
  44. jassertfalse;
  45. }
  46. }
  47. void ImageConvolutionKernel::clear()
  48. {
  49. for (int i = size * size; --i >= 0;)
  50. values[i] = 0;
  51. }
  52. void ImageConvolutionKernel::setOverallSum (const float desiredTotalSum)
  53. {
  54. double currentTotal = 0.0;
  55. for (int i = size * size; --i >= 0;)
  56. currentTotal += values[i];
  57. rescaleAllValues ((float) (desiredTotalSum / currentTotal));
  58. }
  59. void ImageConvolutionKernel::rescaleAllValues (const float multiplier)
  60. {
  61. for (int i = size * size; --i >= 0;)
  62. values[i] *= multiplier;
  63. }
  64. //==============================================================================
  65. void ImageConvolutionKernel::createGaussianBlur (const float radius)
  66. {
  67. const double radiusFactor = -1.0 / (radius * radius * 2);
  68. const int centre = size >> 1;
  69. for (int y = size; --y >= 0;)
  70. {
  71. for (int x = size; --x >= 0;)
  72. {
  73. const int cx = x - centre;
  74. const int cy = y - centre;
  75. values [x + y * size] = (float) exp (radiusFactor * (cx * cx + cy * cy));
  76. }
  77. }
  78. setOverallSum (1.0f);
  79. }
  80. //==============================================================================
  81. void ImageConvolutionKernel::applyToImage (Image& destImage,
  82. const Image& sourceImage,
  83. const Rectangle<int>& destinationArea) const
  84. {
  85. if (sourceImage == destImage)
  86. {
  87. destImage.duplicateIfShared();
  88. }
  89. else
  90. {
  91. if (sourceImage.getWidth() != destImage.getWidth()
  92. || sourceImage.getHeight() != destImage.getHeight()
  93. || sourceImage.getFormat() != destImage.getFormat())
  94. {
  95. jassertfalse;
  96. return;
  97. }
  98. }
  99. const Rectangle<int> area (destinationArea.getIntersection (destImage.getBounds()));
  100. if (area.isEmpty())
  101. return;
  102. const int right = area.getRight();
  103. const int bottom = area.getBottom();
  104. const Image::BitmapData destData (destImage, area.getX(), area.getY(), area.getWidth(), area.getHeight(),
  105. Image::BitmapData::writeOnly);
  106. uint8* line = destData.data;
  107. const Image::BitmapData srcData (sourceImage, Image::BitmapData::readOnly);
  108. if (destData.pixelStride == 4)
  109. {
  110. for (int y = area.getY(); y < bottom; ++y)
  111. {
  112. uint8* dest = line;
  113. line += destData.lineStride;
  114. for (int x = area.getX(); x < right; ++x)
  115. {
  116. float c1 = 0;
  117. float c2 = 0;
  118. float c3 = 0;
  119. float c4 = 0;
  120. for (int yy = 0; yy < size; ++yy)
  121. {
  122. const int sy = y + yy - (size >> 1);
  123. if (sy >= srcData.height)
  124. break;
  125. if (sy >= 0)
  126. {
  127. int sx = x - (size >> 1);
  128. const uint8* src = srcData.getPixelPointer (sx, sy);
  129. for (int xx = 0; xx < size; ++xx)
  130. {
  131. if (sx >= srcData.width)
  132. break;
  133. if (sx >= 0)
  134. {
  135. const float kernelMult = values [xx + yy * size];
  136. c1 += kernelMult * *src++;
  137. c2 += kernelMult * *src++;
  138. c3 += kernelMult * *src++;
  139. c4 += kernelMult * *src++;
  140. }
  141. else
  142. {
  143. src += 4;
  144. }
  145. ++sx;
  146. }
  147. }
  148. }
  149. *dest++ = (uint8) jmin (0xff, roundToInt (c1));
  150. *dest++ = (uint8) jmin (0xff, roundToInt (c2));
  151. *dest++ = (uint8) jmin (0xff, roundToInt (c3));
  152. *dest++ = (uint8) jmin (0xff, roundToInt (c4));
  153. }
  154. }
  155. }
  156. else if (destData.pixelStride == 3)
  157. {
  158. for (int y = area.getY(); y < bottom; ++y)
  159. {
  160. uint8* dest = line;
  161. line += destData.lineStride;
  162. for (int x = area.getX(); x < right; ++x)
  163. {
  164. float c1 = 0;
  165. float c2 = 0;
  166. float c3 = 0;
  167. for (int yy = 0; yy < size; ++yy)
  168. {
  169. const int sy = y + yy - (size >> 1);
  170. if (sy >= srcData.height)
  171. break;
  172. if (sy >= 0)
  173. {
  174. int sx = x - (size >> 1);
  175. const uint8* src = srcData.getPixelPointer (sx, sy);
  176. for (int xx = 0; xx < size; ++xx)
  177. {
  178. if (sx >= srcData.width)
  179. break;
  180. if (sx >= 0)
  181. {
  182. const float kernelMult = values [xx + yy * size];
  183. c1 += kernelMult * *src++;
  184. c2 += kernelMult * *src++;
  185. c3 += kernelMult * *src++;
  186. }
  187. else
  188. {
  189. src += 3;
  190. }
  191. ++sx;
  192. }
  193. }
  194. }
  195. *dest++ = (uint8) roundToInt (c1);
  196. *dest++ = (uint8) roundToInt (c2);
  197. *dest++ = (uint8) roundToInt (c3);
  198. }
  199. }
  200. }
  201. else if (destData.pixelStride == 1)
  202. {
  203. for (int y = area.getY(); y < bottom; ++y)
  204. {
  205. uint8* dest = line;
  206. line += destData.lineStride;
  207. for (int x = area.getX(); x < right; ++x)
  208. {
  209. float c1 = 0;
  210. for (int yy = 0; yy < size; ++yy)
  211. {
  212. const int sy = y + yy - (size >> 1);
  213. if (sy >= srcData.height)
  214. break;
  215. if (sy >= 0)
  216. {
  217. int sx = x - (size >> 1);
  218. const uint8* src = srcData.getPixelPointer (sx, sy);
  219. for (int xx = 0; xx < size; ++xx)
  220. {
  221. if (sx >= srcData.width)
  222. break;
  223. if (sx >= 0)
  224. {
  225. const float kernelMult = values [xx + yy * size];
  226. c1 += kernelMult * *src++;
  227. }
  228. else
  229. {
  230. src += 3;
  231. }
  232. ++sx;
  233. }
  234. }
  235. }
  236. *dest++ = (uint8) roundToInt (c1);
  237. }
  238. }
  239. }
  240. }