2 * Copyright (c) 2022 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.
18 #include <dali/integration-api/debug.h>
23 #include <dali/internal/imaging/common/gaussian-blur.h>
24 #include <dali/internal/imaging/common/pixel-buffer-impl.h>
32 void ConvoluteAndTranspose(unsigned char* inBuffer,
33 unsigned char* outBuffer,
34 const unsigned int bufferWidth,
35 const unsigned int bufferHeight,
36 const unsigned int inBufferStride,
37 const unsigned int outBufferStride,
38 const float blurRadius)
40 // Calculate the weights for gaussian blur
41 int radius = static_cast<int>(std::ceil(blurRadius));
42 int rows = radius * 2 + 1;
44 float sigma = (blurRadius < Math::MACHINE_EPSILON_1) ? 0.0f : blurRadius * 0.4f + 0.6f; // The same equation used by Android
45 float sigma22 = 2.0f * sigma * sigma;
46 float sqrtSigmaPi2 = std::sqrt(2.0f * Math::PI) * sigma;
47 float radius2 = radius * radius;
48 float normalizeFactor = 0.0f;
50 float* weightMatrix = new float[rows];
53 for(int row = -radius; row <= radius; row++)
55 float distance = row * row;
56 if(distance > radius2)
58 weightMatrix[index] = 0.0f;
62 weightMatrix[index] = static_cast<float>(std::exp(-(distance) / sigma22) / sqrtSigmaPi2);
64 normalizeFactor += weightMatrix[index];
68 for(int i = 0; i < rows; i++)
70 weightMatrix[i] /= normalizeFactor;
73 // Perform the convolution and transposition using the weights
75 int columns2 = columns / 2;
76 for(unsigned int y = 0; y < bufferHeight; y++)
78 unsigned int targetPixelIndex = y;
79 unsigned int ioffset = y * inBufferStride;
80 for(unsigned int x = 0; x < bufferWidth; x++)
82 float r = 0.0f, g = 0.0f, b = 0.0f, a = 0.0f;
83 int weightColumnOffset = columns2;
84 for(int column = -columns2; column <= columns2; column++)
86 float weight = weightMatrix[weightColumnOffset + column];
87 if(fabsf(weight) > Math::MACHINE_EPSILON_1)
90 ix = std::max(0, std::min(ix, static_cast<int>(bufferWidth - 1)));
91 unsigned int sourcePixelIndex = ioffset + ix;
92 r += weight * inBuffer[sourcePixelIndex * 4];
93 g += weight * inBuffer[sourcePixelIndex * 4 + 1];
94 b += weight * inBuffer[sourcePixelIndex * 4 + 2];
95 a += weight * inBuffer[sourcePixelIndex * 4 + 3];
99 outBuffer[targetPixelIndex * 4] = std::max(0, std::min(static_cast<int>(r + 0.5f), 255));
100 outBuffer[targetPixelIndex * 4 + 1] = std::max(0, std::min(static_cast<int>(g + 0.5f), 255));
101 outBuffer[targetPixelIndex * 4 + 2] = std::max(0, std::min(static_cast<int>(b + 0.5f), 255));
102 outBuffer[targetPixelIndex * 4 + 3] = std::max(0, std::min(static_cast<int>(a + 0.5f), 255));
104 targetPixelIndex += outBufferStride;
108 delete[] weightMatrix;
111 void PerformGaussianBlurRGBA(PixelBuffer& buffer, const float blurRadius)
113 unsigned int bufferWidth = buffer.GetWidth();
114 unsigned int bufferHeight = buffer.GetHeight();
115 unsigned int bufferStride = buffer.GetStride();
117 if(bufferWidth == 0 || bufferHeight == 0 || bufferStride == 0 || buffer.GetPixelFormat() != Pixel::RGBA8888)
119 DALI_LOG_ERROR("Invalid buffer!\n");
123 // Create a temporary buffer for the two-pass blur
124 PixelBufferPtr softShadowImageBuffer = PixelBuffer::New(bufferWidth, bufferHeight, Pixel::RGBA8888);
126 // We perform the blur first but write its output image buffer transposed, so that we
127 // can just do it in two passes. The first pass blurs horizontally and transposes, the
128 // second pass does the same, but as the image is now transposed, it's really doing a
129 // vertical blur. The second transposition makes the image the right way up again. This
130 // is much faster than doing a 2D convolution.
131 ConvoluteAndTranspose(buffer.GetBuffer(), softShadowImageBuffer->GetBuffer(), bufferWidth, bufferHeight, bufferStride, bufferHeight, blurRadius);
132 ConvoluteAndTranspose(softShadowImageBuffer->GetBuffer(), buffer.GetBuffer(), bufferHeight, bufferWidth, bufferHeight, bufferStride, blurRadius);
134 // On leaving scope, softShadowImageBuffer will get destroyed.
137 } //namespace Adaptor
139 } // namespace Internal