/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
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 ) ;
}
}
}
}