|
- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2015 - ROLI Ltd.
-
- Permission is granted to use this software under the terms of either:
- a) the GPL v2 (or any later version)
- b) the Affero GPL v3
-
- Details of these licenses can be found at: www.gnu.org/licenses
-
- JUCE 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.
-
- ------------------------------------------------------------------------------
-
- To release a closed-source product which uses JUCE, commercial licenses are
- available: visit www.juce.com for more information.
-
- ==============================================================================
- */
-
- ImageConvolutionKernel::ImageConvolutionKernel (const int size_)
- : values ((size_t) (size_ * size_)),
- size (size_)
- {
- clear();
- }
-
- ImageConvolutionKernel::~ImageConvolutionKernel()
- {
- }
-
- //==============================================================================
- float ImageConvolutionKernel::getKernelValue (const int x, const int y) const noexcept
- {
- if (isPositiveAndBelow (x, size) && isPositiveAndBelow (y, size))
- return values [x + y * size];
-
- jassertfalse;
- return 0;
- }
-
- void ImageConvolutionKernel::setKernelValue (const int x, const int y, const float value) noexcept
- {
- if (isPositiveAndBelow (x, size) && isPositiveAndBelow (y, size))
- {
- values [x + y * size] = value;
- }
- else
- {
- jassertfalse;
- }
- }
-
- void ImageConvolutionKernel::clear()
- {
- for (int i = size * size; --i >= 0;)
- values[i] = 0;
- }
-
- void ImageConvolutionKernel::setOverallSum (const float desiredTotalSum)
- {
- double currentTotal = 0.0;
-
- for (int i = size * size; --i >= 0;)
- currentTotal += values[i];
-
- rescaleAllValues ((float) (desiredTotalSum / currentTotal));
- }
-
- void ImageConvolutionKernel::rescaleAllValues (const float multiplier)
- {
- for (int i = size * size; --i >= 0;)
- values[i] *= multiplier;
- }
-
- //==============================================================================
- void ImageConvolutionKernel::createGaussianBlur (const float radius)
- {
- const double radiusFactor = -1.0 / (radius * radius * 2);
- const int centre = size >> 1;
-
- for (int y = size; --y >= 0;)
- {
- for (int x = size; --x >= 0;)
- {
- const int cx = x - centre;
- const int cy = y - centre;
-
- values [x + y * size] = (float) exp (radiusFactor * (cx * cx + cy * cy));
- }
- }
-
- setOverallSum (1.0f);
- }
-
- //==============================================================================
- void ImageConvolutionKernel::applyToImage (Image& destImage,
- const Image& sourceImage,
- const Rectangle<int>& destinationArea) const
- {
- if (sourceImage == destImage)
- {
- destImage.duplicateIfShared();
- }
- else
- {
- if (sourceImage.getWidth() != destImage.getWidth()
- || sourceImage.getHeight() != destImage.getHeight()
- || sourceImage.getFormat() != destImage.getFormat())
- {
- jassertfalse;
- return;
- }
- }
-
- const Rectangle<int> area (destinationArea.getIntersection (destImage.getBounds()));
-
- if (area.isEmpty())
- return;
-
- const int right = area.getRight();
- const int bottom = area.getBottom();
-
- const Image::BitmapData destData (destImage, area.getX(), area.getY(), area.getWidth(), area.getHeight(),
- Image::BitmapData::writeOnly);
- uint8* line = destData.data;
-
- const Image::BitmapData srcData (sourceImage, Image::BitmapData::readOnly);
-
- if (destData.pixelStride == 4)
- {
- for (int y = area.getY(); y < bottom; ++y)
- {
- uint8* dest = line;
- line += destData.lineStride;
-
- for (int x = area.getX(); x < right; ++x)
- {
- float c1 = 0;
- float c2 = 0;
- float c3 = 0;
- float c4 = 0;
-
- for (int yy = 0; yy < size; ++yy)
- {
- const int sy = y + yy - (size >> 1);
-
- if (sy >= srcData.height)
- break;
-
- if (sy >= 0)
- {
- int sx = x - (size >> 1);
- const uint8* src = srcData.getPixelPointer (sx, sy);
-
- for (int xx = 0; xx < size; ++xx)
- {
- if (sx >= srcData.width)
- break;
-
- if (sx >= 0)
- {
- const float kernelMult = values [xx + yy * size];
- c1 += kernelMult * *src++;
- c2 += kernelMult * *src++;
- c3 += kernelMult * *src++;
- c4 += kernelMult * *src++;
- }
- else
- {
- src += 4;
- }
-
- ++sx;
- }
- }
- }
-
- *dest++ = (uint8) jmin (0xff, roundToInt (c1));
- *dest++ = (uint8) jmin (0xff, roundToInt (c2));
- *dest++ = (uint8) jmin (0xff, roundToInt (c3));
- *dest++ = (uint8) jmin (0xff, roundToInt (c4));
- }
- }
- }
- else if (destData.pixelStride == 3)
- {
- for (int y = area.getY(); y < bottom; ++y)
- {
- uint8* dest = line;
- line += destData.lineStride;
-
- for (int x = area.getX(); x < right; ++x)
- {
- float c1 = 0;
- float c2 = 0;
- float c3 = 0;
-
- for (int yy = 0; yy < size; ++yy)
- {
- const int sy = y + yy - (size >> 1);
-
- if (sy >= srcData.height)
- break;
-
- if (sy >= 0)
- {
- int sx = x - (size >> 1);
- const uint8* src = srcData.getPixelPointer (sx, sy);
-
- for (int xx = 0; xx < size; ++xx)
- {
- if (sx >= srcData.width)
- break;
-
- if (sx >= 0)
- {
- const float kernelMult = values [xx + yy * size];
- c1 += kernelMult * *src++;
- c2 += kernelMult * *src++;
- c3 += kernelMult * *src++;
- }
- else
- {
- src += 3;
- }
-
- ++sx;
- }
- }
- }
-
- *dest++ = (uint8) roundToInt (c1);
- *dest++ = (uint8) roundToInt (c2);
- *dest++ = (uint8) roundToInt (c3);
- }
- }
- }
- else if (destData.pixelStride == 1)
- {
- for (int y = area.getY(); y < bottom; ++y)
- {
- uint8* dest = line;
- line += destData.lineStride;
-
- for (int x = area.getX(); x < right; ++x)
- {
- float c1 = 0;
-
- for (int yy = 0; yy < size; ++yy)
- {
- const int sy = y + yy - (size >> 1);
-
- if (sy >= srcData.height)
- break;
-
- if (sy >= 0)
- {
- int sx = x - (size >> 1);
- const uint8* src = srcData.getPixelPointer (sx, sy);
-
- for (int xx = 0; xx < size; ++xx)
- {
- if (sx >= srcData.width)
- break;
-
- if (sx >= 0)
- {
- const float kernelMult = values [xx + yy * size];
- c1 += kernelMult * *src++;
- }
- else
- {
- src += 3;
- }
-
- ++sx;
- }
- }
- }
-
- *dest++ = (uint8) roundToInt (c1);
- }
- }
- }
- }
|