2 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
22 #include <dali/internal/imaging/common/gaussian-blur.h>
23 #include <dali/internal/imaging/common/pixel-buffer-impl.h>
36 void ConvoluteAndTranspose( unsigned char* inBuffer,
37 unsigned char* outBuffer,
38 const unsigned int bufferWidth,
39 const unsigned int bufferHeight,
40 const float blurRadius )
42 // Calculate the weights for gaussian blur
43 int radius = static_cast<int>( std::ceil( blurRadius ) );
44 int rows = radius * 2 + 1;
46 float sigma = ( blurRadius < Math::MACHINE_EPSILON_1 ) ? 0.0f : blurRadius * 0.4f + 0.6f; // The same equation used by Android
47 float sigma22 = 2.0f * sigma * sigma;
48 float sqrtSigmaPi2 = std::sqrt( 2.0f * Math::PI ) * sigma;
49 float radius2 = radius * radius;
50 float normalizeFactor = 0.0f;
52 float* weightMatrix = new float[rows];
55 for ( int row = -radius; row <= radius; row++ )
57 float distance = row * row;
58 if ( distance > radius2 )
60 weightMatrix[index] = 0.0f;
64 weightMatrix[index] = static_cast<float>( std::exp( -( distance ) / sigma22 ) / sqrtSigmaPi2 );
66 normalizeFactor += weightMatrix[index];
70 for ( int i = 0; i < rows; i++ )
72 weightMatrix[i] /= normalizeFactor;
75 // Perform the convolution and transposition using the weights
77 int columns2 = columns / 2;
78 for ( unsigned int y = 0; y < bufferHeight; y++ )
80 unsigned int targetPixelIndex = y;
81 unsigned int ioffset = y * bufferWidth;
82 for ( unsigned int x = 0; x < bufferWidth; x++ )
84 float r = 0.0f, g = 0.0f, b = 0.0f, a = 0.0f;
85 int weightColumnOffset = columns2;
86 for ( int column = -columns2; column <= columns2; column++ )
88 float weight = weightMatrix[weightColumnOffset + column];
89 if ( fabsf( weight ) > Math::MACHINE_EPSILON_1 )
92 ix = std::max( 0, std::min( ix, static_cast<int>( bufferWidth - 1 ) ) );
93 unsigned int sourcePixelIndex = ioffset + ix;
94 r += weight * inBuffer[sourcePixelIndex*4];
95 g += weight * inBuffer[sourcePixelIndex*4+1];
96 b += weight * inBuffer[sourcePixelIndex*4+2];
97 a += weight * inBuffer[sourcePixelIndex*4+3];
101 outBuffer[targetPixelIndex*4] = std::max( 0, std::min( static_cast<int>( r + 0.5f ), 255 ) );
102 outBuffer[targetPixelIndex*4+1] = std::max( 0, std::min( static_cast<int>( g + 0.5f ), 255 ) );
103 outBuffer[targetPixelIndex*4+2] = std::max( 0, std::min( static_cast<int>( b + 0.5f ), 255 ) );
104 outBuffer[targetPixelIndex*4+3] = std::max( 0, std::min( static_cast<int>( a + 0.5f ), 255 ) );
106 targetPixelIndex += bufferHeight;
110 delete [] weightMatrix;
113 void PerformGaussianBlurRGBA( PixelBuffer& buffer, const float blurRadius )
115 unsigned int bufferWidth = buffer.GetWidth();
116 unsigned int bufferHeight = buffer.GetHeight();
118 // Create a temporary buffer for the two-pass blur
119 PixelBufferPtr softShadowImageBuffer = PixelBuffer::New( bufferWidth, bufferHeight, Pixel::RGBA8888 );
120 memcpy( softShadowImageBuffer->GetBuffer(), buffer.GetBuffer(), 4u * bufferWidth * bufferHeight );
122 // We perform the blur first but write its output image buffer transposed, so that we
123 // can just do it in two passes. The first pass blurs horizontally and transposes, the
124 // second pass does the same, but as the image is now transposed, it's really doing a
125 // vertical blur. The second transposition makes the image the right way up again. This
126 // is much faster than doing a 2D convolution.
127 ConvoluteAndTranspose( buffer.GetBuffer(), softShadowImageBuffer->GetBuffer(), bufferWidth, bufferHeight, blurRadius );
128 ConvoluteAndTranspose( softShadowImageBuffer->GetBuffer(), buffer.GetBuffer(), bufferHeight, bufferWidth, blurRadius );
130 // On leaving scope, softShadowImageBuffer will get destroyed.
133 } //namespace Adaptor
135 }// namespace Internal