2 * Copyright (c) 2021 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.
19 #include <dali/internal/imaging/common/pixel-buffer-impl.h>
26 #include <dali/internal/imaging/common/alpha-mask.h>
27 #include <dali/internal/imaging/common/gaussian-blur.h>
28 #include <dali/internal/imaging/common/image-operations.h>
29 #include <dali/internal/imaging/common/pixel-manipulation.h>
39 const float TWO_PI = 2.f * Math::PI; ///< 360 degrees in radians
42 PixelBuffer::PixelBuffer(unsigned char* buffer,
43 unsigned int bufferSize,
46 Dali::Pixel::Format pixelFormat)
49 mBufferSize(bufferSize),
52 mPixelFormat(pixelFormat),
57 PixelBuffer::~PixelBuffer()
62 PixelBufferPtr PixelBuffer::New(unsigned int width,
64 Dali::Pixel::Format pixelFormat)
66 unsigned int bufferSize = width * height * Dali::Pixel::GetBytesPerPixel(pixelFormat);
67 unsigned char* buffer = NULL;
70 buffer = static_cast<unsigned char*>(malloc(bufferSize));
72 return new PixelBuffer(buffer, bufferSize, width, height, pixelFormat);
75 PixelBufferPtr PixelBuffer::New(unsigned char* buffer,
76 unsigned int bufferSize,
79 Dali::Pixel::Format pixelFormat)
81 return new PixelBuffer(buffer, bufferSize, width, height, pixelFormat);
84 Dali::PixelData PixelBuffer::Convert(PixelBuffer& pixelBuffer)
86 Dali::PixelData pixelData = Dali::PixelData::New(pixelBuffer.mBuffer,
87 pixelBuffer.mBufferSize,
90 pixelBuffer.mPixelFormat,
91 Dali::PixelData::FREE);
92 pixelBuffer.mBuffer = NULL;
93 pixelBuffer.mWidth = 0;
94 pixelBuffer.mHeight = 0;
95 pixelBuffer.mBufferSize = 0;
100 unsigned int PixelBuffer::GetWidth() const
105 unsigned int PixelBuffer::GetHeight() const
110 Dali::Pixel::Format PixelBuffer::GetPixelFormat() const
115 unsigned char* PixelBuffer::GetBuffer() const
120 const unsigned char* const PixelBuffer::GetConstBuffer() const
125 unsigned int PixelBuffer::GetBufferSize() const
130 Dali::PixelData PixelBuffer::CreatePixelData() const
132 unsigned char* destBuffer = NULL;
136 destBuffer = static_cast<unsigned char*>(malloc(mBufferSize));
137 memcpy(destBuffer, mBuffer, mBufferSize);
140 Dali::PixelData pixelData = Dali::PixelData::New(destBuffer, mBufferSize, mWidth, mHeight, mPixelFormat, Dali::PixelData::FREE);
144 void PixelBuffer::ApplyMask(const PixelBuffer& inMask, float contentScale, bool cropToMask)
148 // First scale this buffer by the contentScale, and crop to the mask size
149 // If it's too small, then scale the mask to match the image size
150 // Then apply the mask
151 ScaleAndCrop(contentScale, ImageDimensions(inMask.GetWidth(), inMask.GetHeight()));
153 if(inMask.mWidth > mWidth || inMask.mHeight > mHeight)
155 PixelBufferPtr mask = NewResize(inMask, ImageDimensions(mWidth, mHeight));
156 ApplyMaskInternal(*mask);
160 ApplyMaskInternal(inMask);
165 // First, scale the mask to match the image size,
166 // then apply the mask.
167 PixelBufferPtr mask = NewResize(inMask, ImageDimensions(mWidth, mHeight));
168 ApplyMaskInternal(*mask);
172 void PixelBuffer::ApplyMaskInternal(const PixelBuffer& mask)
177 Dali::Pixel::GetAlphaOffsetAndMask(mPixelFormat, byteOffset, bitMask);
178 if(Dali::Pixel::HasAlpha(mPixelFormat) && bitMask == 255)
180 ApplyMaskToAlphaChannel(*this, mask);
184 PixelBufferPtr newPixelBuffer = CreateNewMaskedBuffer(*this, mask);
185 TakeOwnershipOfBuffer(*newPixelBuffer);
186 // On leaving scope, newPixelBuffer will get destroyed.
190 void PixelBuffer::TakeOwnershipOfBuffer(PixelBuffer& pixelBuffer)
194 // Take ownership of new buffer
195 mBuffer = pixelBuffer.mBuffer;
196 pixelBuffer.mBuffer = NULL;
197 mBufferSize = pixelBuffer.mBufferSize;
198 mWidth = pixelBuffer.mWidth;
199 mHeight = pixelBuffer.mHeight;
200 mPixelFormat = pixelBuffer.mPixelFormat;
203 void PixelBuffer::ReleaseBuffer()
211 void PixelBuffer::AllocateFixedSize(uint32_t size)
214 mBuffer = reinterpret_cast<unsigned char*>(malloc(size));
218 bool PixelBuffer::Rotate(Degree angle)
220 // Check first if Rotate() can perform the operation in the current pixel buffer.
222 bool validPixelFormat = false;
231 case Pixel::RGBA8888:
232 case Pixel::BGRA8888: // FALL THROUGH
234 validPixelFormat = true;
239 // This pixel format is not supported for this operation.
240 validPixelFormat = false;
245 if(!validPixelFormat)
247 // Can't rotate the pixel buffer with the current pixel format.
248 DALI_LOG_ERROR("Can't rotate the pixel buffer with the current pixel format\n");
252 float radians = Radian(angle).radian;
254 // Transform the input angle into the range [0..2PI]
255 radians = fmod(radians, TWO_PI);
256 radians += (radians < 0.f) ? TWO_PI : 0.f;
258 if(radians < Dali::Math::MACHINE_EPSILON_10)
260 // Nothing to do if the angle is zero.
264 const unsigned int pixelSize = Pixel::GetBytesPerPixel(mPixelFormat);
266 uint8_t* pixelsOut = nullptr;
267 Platform::RotateByShear(mBuffer,
276 // Check whether the rotation succedded and set the new pixel buffer data.
277 const bool success = nullptr != pixelsOut;
281 // Release the memory of the current pixel buffer.
284 // Set the new pixel buffer.
287 mBufferSize = mWidth * mHeight * pixelSize;
293 void PixelBuffer::ScaleAndCrop(float scaleFactor, ImageDimensions cropDimensions)
295 ImageDimensions outDimensions(float(mWidth) * scaleFactor,
296 float(mHeight) * scaleFactor);
298 if(outDimensions.GetWidth() != mWidth || outDimensions.GetHeight() != mHeight)
300 Resize(outDimensions);
303 ImageDimensions postCropDimensions(
304 std::min(cropDimensions.GetWidth(), outDimensions.GetWidth()),
305 std::min(cropDimensions.GetHeight(), outDimensions.GetHeight()));
307 if(postCropDimensions.GetWidth() < outDimensions.GetWidth() ||
308 postCropDimensions.GetHeight() < outDimensions.GetHeight())
310 uint16_t x = (outDimensions.GetWidth() - postCropDimensions.GetWidth()) / 2;
311 uint16_t y = (outDimensions.GetHeight() - postCropDimensions.GetHeight()) / 2;
312 Crop(x, y, postCropDimensions);
316 void PixelBuffer::Crop(uint16_t x, uint16_t y, ImageDimensions cropDimensions)
318 PixelBufferPtr outBuffer = NewCrop(*this, x, y, cropDimensions);
319 TakeOwnershipOfBuffer(*outBuffer);
322 PixelBufferPtr PixelBuffer::NewCrop(const PixelBuffer& inBuffer, uint16_t x, uint16_t y, ImageDimensions cropDimensions)
324 PixelBufferPtr outBuffer = PixelBuffer::New(cropDimensions.GetWidth(), cropDimensions.GetHeight(), inBuffer.GetPixelFormat());
325 int bytesPerPixel = Pixel::GetBytesPerPixel(inBuffer.mPixelFormat);
326 int srcStride = inBuffer.mWidth * bytesPerPixel;
327 int destStride = cropDimensions.GetWidth() * bytesPerPixel;
329 // Clamp crop to right edge
330 if(x + cropDimensions.GetWidth() > inBuffer.mWidth)
332 destStride = (inBuffer.mWidth - x) * bytesPerPixel;
335 int srcOffset = x * bytesPerPixel + y * srcStride;
337 unsigned char* destBuffer = outBuffer->mBuffer;
339 // Clamp crop to last row
340 unsigned int endRow = y + cropDimensions.GetHeight();
341 if(endRow > inBuffer.mHeight)
343 endRow = inBuffer.mHeight - 1;
345 for(uint16_t row = y; row < endRow; ++row)
347 memcpy(destBuffer + destOffset, inBuffer.mBuffer + srcOffset, destStride);
348 srcOffset += srcStride;
349 destOffset += destStride;
354 void PixelBuffer::SetMetadata(const Property::Map& map)
356 mMetadata.reset(new Property::Map(map));
359 bool PixelBuffer::GetMetadata(Property::Map& outMetadata) const
365 outMetadata = *mMetadata;
369 void PixelBuffer::SetMetadata(std::unique_ptr<Property::Map> metadata)
371 mMetadata = std::move(metadata);
374 void PixelBuffer::Resize(ImageDimensions outDimensions)
376 if(mWidth != outDimensions.GetWidth() || mHeight != outDimensions.GetHeight())
378 PixelBufferPtr outBuffer = NewResize(*this, outDimensions);
379 TakeOwnershipOfBuffer(*outBuffer);
383 PixelBufferPtr PixelBuffer::NewResize(const PixelBuffer& inBuffer, ImageDimensions outDimensions)
385 PixelBufferPtr outBuffer = PixelBuffer::New(outDimensions.GetWidth(), outDimensions.GetHeight(), inBuffer.GetPixelFormat());
386 ImageDimensions inDimensions(inBuffer.mWidth, inBuffer.mHeight);
388 bool hasAlpha = Pixel::HasAlpha(inBuffer.mPixelFormat);
389 int bytesPerPixel = Pixel::GetBytesPerPixel(inBuffer.mPixelFormat);
391 Resampler::Filter filterType = Resampler::LANCZOS4;
392 if(inDimensions.GetWidth() < outDimensions.GetWidth() && inDimensions.GetHeight() < outDimensions.GetHeight())
394 filterType = Resampler::MITCHELL;
397 // This method only really works for 8 bit wide channels.
398 // (But could be expanded to work)
399 if(inBuffer.mPixelFormat == Pixel::A8 ||
400 inBuffer.mPixelFormat == Pixel::L8 ||
401 inBuffer.mPixelFormat == Pixel::LA88 ||
402 inBuffer.mPixelFormat == Pixel::RGB888 ||
403 inBuffer.mPixelFormat == Pixel::RGB8888 ||
404 inBuffer.mPixelFormat == Pixel::BGR8888 ||
405 inBuffer.mPixelFormat == Pixel::RGBA8888 ||
406 inBuffer.mPixelFormat == Pixel::BGRA8888)
408 Dali::Internal::Platform::Resample(inBuffer.mBuffer, inDimensions, outBuffer->GetBuffer(), outDimensions, filterType, bytesPerPixel, hasAlpha);
412 DALI_LOG_ERROR("Trying to resize an image with too narrow a channel width");
418 void PixelBuffer::ApplyGaussianBlur(const float blurRadius)
420 // This method only works for pixel buffer in RGBA format.
421 if(mWidth > 0 && mHeight > 0 && mPixelFormat == Pixel::RGBA8888)
423 if(blurRadius > Math::MACHINE_EPSILON_1)
425 PerformGaussianBlurRGBA(*this, blurRadius);
430 DALI_LOG_ERROR("Trying to apply gaussian blur to an empty pixel buffer or a pixel buffer not in RGBA format");
434 void PixelBuffer::MultiplyColorByAlpha()
436 auto bytesPerPixel = Pixel::GetBytesPerPixel(mPixelFormat);
438 // Compressed textures have unknown size of the pixel. Alpha premultiplication
439 // must be skipped in such case
440 if(Pixel::GetBytesPerPixel(mPixelFormat) && Pixel::HasAlpha(mPixelFormat))
442 unsigned char* pixel = mBuffer;
443 const unsigned int bufferSize = mWidth * mHeight;
445 for(unsigned int i = 0; i < bufferSize; ++i)
447 unsigned int alpha = ReadChannel(pixel, mPixelFormat, Adaptor::ALPHA);
449 auto red = ReadChannel(pixel, mPixelFormat, Adaptor::RED);
450 auto green = ReadChannel(pixel, mPixelFormat, Adaptor::GREEN);
451 auto blue = ReadChannel(pixel, mPixelFormat, Adaptor::BLUE);
452 auto luminance = ReadChannel(pixel, mPixelFormat, Adaptor::LUMINANCE);
453 WriteChannel(pixel, mPixelFormat, Adaptor::RED, red * alpha / 255);
454 WriteChannel(pixel, mPixelFormat, Adaptor::GREEN, green * alpha / 255);
455 WriteChannel(pixel, mPixelFormat, Adaptor::BLUE, blue * alpha / 255);
456 WriteChannel(pixel, mPixelFormat, Adaptor::LUMINANCE, luminance * alpha / 255);
458 pixel += bytesPerPixel;
461 mPreMultiplied = true;
464 bool PixelBuffer::IsAlphaPreMultiplied() const
466 return mPreMultiplied;
469 } // namespace Adaptor
470 } // namespace Internal