1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-11 23:54:18 +00:00
JUCE/src/gui/graphics/imaging/juce_ImageConvolutionKernel.cpp
2010-01-04 15:24:13 +00:00

260 lines
8.2 KiB
C++

/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-9 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online 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.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/
#include "../../../core/juce_StandardHeader.h"
BEGIN_JUCE_NAMESPACE
#include "juce_ImageConvolutionKernel.h"
//==============================================================================
ImageConvolutionKernel::ImageConvolutionKernel (const int size_)
: values (size_ * size_),
size (size_)
{
clear();
}
ImageConvolutionKernel::~ImageConvolutionKernel()
{
}
//==============================================================================
void ImageConvolutionKernel::setKernelValue (const int x,
const int y,
const float value)
{
if (((unsigned int) x) < (unsigned int) size
&& ((unsigned int) y) < (unsigned int) 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,
int dx,
int dy,
int dw,
int dh) const
{
ScopedPointer <Image> imageCreated;
if (sourceImage == 0)
{
sourceImage = imageCreated = destImage.createCopy();
}
else
{
jassert (sourceImage->getWidth() == destImage.getWidth()
&& sourceImage->getHeight() == destImage.getHeight()
&& sourceImage->getFormat() == destImage.getFormat());
if (sourceImage->getWidth() != destImage.getWidth()
|| sourceImage->getHeight() != destImage.getHeight()
|| sourceImage->getFormat() != destImage.getFormat())
return;
}
const int imageWidth = destImage.getWidth();
const int imageHeight = destImage.getHeight();
if (dx >= imageWidth || dy >= imageHeight)
return;
if (dx + dw > imageWidth)
dw = imageWidth - dx;
if (dy + dh > imageHeight)
dh = imageHeight - dy;
const int dx2 = dx + dw;
const int dy2 = dy + dh;
const Image::BitmapData destData (destImage, dx, dy, dw, dh, true);
uint8* line = destData.data;
const Image::BitmapData srcData (*sourceImage, 0, 0, sourceImage->getWidth(), sourceImage->getHeight());
if (destData.pixelStride == 4)
{
for (int y = dy; y < dy2; ++y)
{
uint8* dest = line;
line += destData.lineStride;
for (int x = dx; x < dx2; ++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 >= imageHeight)
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 >= imageWidth)
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, roundFloatToInt (c1));
*dest++ = (uint8) jmin (0xff, roundFloatToInt (c2));
*dest++ = (uint8) jmin (0xff, roundFloatToInt (c3));
*dest++ = (uint8) jmin (0xff, roundFloatToInt (c4));
}
}
}
else if (destData.pixelStride == 3)
{
for (int y = dy; y < dy2; ++y)
{
uint8* dest = line;
line += destData.lineStride;
for (int x = dx; x < dx2; ++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 >= imageHeight)
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 >= imageWidth)
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) roundFloatToInt (c1);
*dest++ = (uint8) roundFloatToInt (c2);
*dest++ = (uint8) roundFloatToInt (c3);
}
}
}
}
END_JUCE_NAMESPACE