/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <cstring>
// INTERNAL INCLUDES
-#include <dali/internal/imaging/common/pixel-manipulation.h>
#include <dali/internal/imaging/common/alpha-mask.h>
#include <dali/internal/imaging/common/gaussian-blur.h>
#include <dali/internal/imaging/common/image-operations.h>
+#include <dali/internal/imaging/common/pixel-manipulation.h>
namespace Dali
{
-
namespace Internal
{
-
namespace Adaptor
{
-
-PixelBuffer::PixelBuffer( unsigned char* buffer,
- unsigned int bufferSize,
- unsigned int width,
- unsigned int height,
- Dali::Pixel::Format pixelFormat )
+namespace
+{
+const float TWO_PI = 2.f * Math::PI; ///< 360 degrees in radians
+// based on W3C Recommendations (https://www.w3.org/TR/AERT/#color-contrast)
+constexpr uint32_t BRIGHTNESS_CONSTANT_R = 299;
+constexpr uint32_t BRIGHTNESS_CONSTANT_G = 587;
+constexpr uint32_t BRIGHTNESS_CONSTANT_B = 114;
+} // namespace
+
+PixelBuffer::PixelBuffer(unsigned char* buffer,
+ unsigned int bufferSize,
+ unsigned int width,
+ unsigned int height,
+ Dali::Pixel::Format pixelFormat)
: mMetadata(),
- mBuffer( buffer ),
- mBufferSize( bufferSize ),
- mWidth( width ),
- mHeight( height ),
- mPixelFormat( pixelFormat )
+ mBuffer(buffer),
+ mBufferSize(bufferSize),
+ mWidth(width),
+ mHeight(height),
+ mPixelFormat(pixelFormat),
+ mPreMultiplied(false)
{
}
ReleaseBuffer();
}
-PixelBufferPtr PixelBuffer::New( unsigned int width,
- unsigned int height,
- Dali::Pixel::Format pixelFormat )
+PixelBufferPtr PixelBuffer::New(unsigned int width,
+ unsigned int height,
+ Dali::Pixel::Format pixelFormat)
{
- unsigned int bufferSize = width * height * Dali::Pixel::GetBytesPerPixel( pixelFormat );
- unsigned char* buffer = NULL;
- if( bufferSize > 0 )
+ unsigned int bufferSize = width * height * Dali::Pixel::GetBytesPerPixel(pixelFormat);
+ unsigned char* buffer = NULL;
+ if(bufferSize > 0)
{
- buffer = static_cast<unsigned char*>( malloc ( bufferSize ) );
+ buffer = static_cast<unsigned char*>(malloc(bufferSize));
}
- return new PixelBuffer( buffer, bufferSize, width, height, pixelFormat );
+ return new PixelBuffer(buffer, bufferSize, width, height, pixelFormat);
}
-PixelBufferPtr PixelBuffer::New( unsigned char* buffer,
- unsigned int bufferSize,
- unsigned int width,
- unsigned int height,
- Dali::Pixel::Format pixelFormat )
+PixelBufferPtr PixelBuffer::New(unsigned char* buffer,
+ unsigned int bufferSize,
+ unsigned int width,
+ unsigned int height,
+ Dali::Pixel::Format pixelFormat)
{
- return new PixelBuffer( buffer, bufferSize, width, height, pixelFormat );
+ return new PixelBuffer(buffer, bufferSize, width, height, pixelFormat);
}
-Dali::PixelData PixelBuffer::Convert( PixelBuffer& pixelBuffer )
+Dali::PixelData PixelBuffer::Convert(PixelBuffer& pixelBuffer)
{
- Dali::PixelData pixelData = Dali::PixelData::New( pixelBuffer.mBuffer,
- pixelBuffer.mBufferSize,
- pixelBuffer.mWidth,
- pixelBuffer.mHeight,
- pixelBuffer.mPixelFormat,
- Dali::PixelData::FREE );
- pixelBuffer.mBuffer = NULL;
- pixelBuffer.mWidth = 0;
- pixelBuffer.mHeight = 0;
- pixelBuffer.mBufferSize = 0;
+ Dali::PixelData pixelData = Dali::PixelData::New(pixelBuffer.mBuffer,
+ pixelBuffer.mBufferSize,
+ pixelBuffer.mWidth,
+ pixelBuffer.mHeight,
+ pixelBuffer.mPixelFormat,
+ Dali::PixelData::FREE);
+ pixelBuffer.mBuffer = NULL;
+ pixelBuffer.mWidth = 0;
+ pixelBuffer.mHeight = 0;
+ pixelBuffer.mBufferSize = 0;
return pixelData;
}
return mBuffer;
}
+const unsigned char* const PixelBuffer::GetConstBuffer() const
+{
+ return mBuffer;
+}
+
unsigned int PixelBuffer::GetBufferSize() const
{
return mBufferSize;
{
unsigned char* destBuffer = NULL;
- if( mBufferSize > 0 )
+ if(mBufferSize > 0)
{
- destBuffer = static_cast<unsigned char*>( malloc( mBufferSize ) );
- memcpy( destBuffer, mBuffer, mBufferSize );
+ destBuffer = static_cast<unsigned char*>(malloc(mBufferSize));
+ memcpy(destBuffer, mBuffer, mBufferSize);
}
- Dali::PixelData pixelData = Dali::PixelData::New( destBuffer, mBufferSize,
- mWidth, mHeight,
- mPixelFormat,
- Dali::PixelData::FREE );
+ Dali::PixelData pixelData = Dali::PixelData::New(destBuffer, mBufferSize, mWidth, mHeight, mPixelFormat, Dali::PixelData::FREE);
return pixelData;
}
-void PixelBuffer::ApplyMask( const PixelBuffer& inMask, float contentScale, bool cropToMask )
+void PixelBuffer::ApplyMask(const PixelBuffer& inMask, float contentScale, bool cropToMask)
{
- if( cropToMask )
+ if(cropToMask)
{
// First scale this buffer by the contentScale, and crop to the mask size
// If it's too small, then scale the mask to match the image size
// Then apply the mask
- ScaleAndCrop( contentScale, ImageDimensions( inMask.GetWidth(), inMask.GetHeight() ) );
+ ScaleAndCrop(contentScale, ImageDimensions(inMask.GetWidth(), inMask.GetHeight()));
- if( inMask.mWidth > mWidth || inMask.mHeight > mHeight )
+ if(inMask.mWidth > mWidth || inMask.mHeight > mHeight)
{
- PixelBufferPtr mask = NewResize( inMask, ImageDimensions( mWidth, mHeight ) );
- ApplyMaskInternal( *mask );
+ PixelBufferPtr mask = NewResize(inMask, ImageDimensions(mWidth, mHeight));
+ ApplyMaskInternal(*mask);
}
else
{
- ApplyMaskInternal( inMask );
+ ApplyMaskInternal(inMask);
}
}
else
{
// First, scale the mask to match the image size,
// then apply the mask.
- PixelBufferPtr mask = NewResize( inMask, ImageDimensions( mWidth, mHeight ) );
- ApplyMaskInternal( *mask );
+ PixelBufferPtr mask = NewResize(inMask, ImageDimensions(mWidth, mHeight));
+ ApplyMaskInternal(*mask);
}
}
-void PixelBuffer::ApplyMaskInternal( const PixelBuffer& mask )
+void PixelBuffer::ApplyMaskInternal(const PixelBuffer& mask)
{
- int byteOffset=0;
- int bitMask=0;
+ int byteOffset = 0;
+ int bitMask = 0;
Dali::Pixel::GetAlphaOffsetAndMask(mPixelFormat, byteOffset, bitMask);
- if( Dali::Pixel::HasAlpha( mPixelFormat ) && bitMask == 255 )
+ if(Dali::Pixel::HasAlpha(mPixelFormat) && bitMask == 255)
{
- ApplyMaskToAlphaChannel( *this, mask );
+ ApplyMaskToAlphaChannel(*this, mask);
}
else
{
- PixelBufferPtr newPixelBuffer = CreateNewMaskedBuffer( *this, mask );
- TakeOwnershipOfBuffer( *newPixelBuffer );
+ PixelBufferPtr newPixelBuffer = CreateNewMaskedBuffer(*this, mask);
+ TakeOwnershipOfBuffer(*newPixelBuffer);
// On leaving scope, newPixelBuffer will get destroyed.
}
}
-void PixelBuffer::TakeOwnershipOfBuffer( PixelBuffer& pixelBuffer )
+void PixelBuffer::TakeOwnershipOfBuffer(PixelBuffer& pixelBuffer)
{
ReleaseBuffer();
// Take ownership of new buffer
- mBuffer = pixelBuffer.mBuffer;
+ mBuffer = pixelBuffer.mBuffer;
pixelBuffer.mBuffer = NULL;
- mBufferSize = pixelBuffer.mBufferSize;
- mWidth = pixelBuffer.mWidth;
- mHeight = pixelBuffer.mHeight;
- mPixelFormat = pixelBuffer.mPixelFormat;
+ mBufferSize = pixelBuffer.mBufferSize;
+ mWidth = pixelBuffer.mWidth;
+ mHeight = pixelBuffer.mHeight;
+ mPixelFormat = pixelBuffer.mPixelFormat;
}
void PixelBuffer::ReleaseBuffer()
{
- if( mBuffer )
+ if(mBuffer)
{
- free( mBuffer );
+ free(mBuffer);
}
}
-void PixelBuffer::AllocateFixedSize( uint32_t size )
+void PixelBuffer::AllocateFixedSize(uint32_t size)
{
ReleaseBuffer();
- mBuffer = reinterpret_cast<unsigned char*>(malloc( size ));
+ mBuffer = reinterpret_cast<unsigned char*>(malloc(size));
mBufferSize = size;
}
-void PixelBuffer::ScaleAndCrop( float scaleFactor, ImageDimensions cropDimensions )
+bool PixelBuffer::Rotate(Degree angle)
+{
+ // Check first if Rotate() can perform the operation in the current pixel buffer.
+
+ bool validPixelFormat = false;
+ switch(mPixelFormat)
+ {
+ case Pixel::A8:
+ case Pixel::L8:
+ case Pixel::LA88:
+ case Pixel::RGB888:
+ case Pixel::RGB8888:
+ case Pixel::BGR8888:
+ case Pixel::RGBA8888:
+ case Pixel::BGRA8888: // FALL THROUGH
+ {
+ validPixelFormat = true;
+ break;
+ }
+ default:
+ {
+ // This pixel format is not supported for this operation.
+ validPixelFormat = false;
+ break;
+ }
+ }
+
+ if(!validPixelFormat)
+ {
+ // Can't rotate the pixel buffer with the current pixel format.
+ DALI_LOG_ERROR("Can't rotate the pixel buffer with the current pixel format\n");
+ return false;
+ }
+
+ float radians = Radian(angle).radian;
+
+ // Transform the input angle into the range [0..2PI]
+ radians = fmod(radians, TWO_PI);
+ radians += (radians < 0.f) ? TWO_PI : 0.f;
+
+ if(radians < Dali::Math::MACHINE_EPSILON_10)
+ {
+ // Nothing to do if the angle is zero.
+ return true;
+ }
+
+ const unsigned int pixelSize = Pixel::GetBytesPerPixel(mPixelFormat);
+
+ uint8_t* pixelsOut = nullptr;
+ Platform::RotateByShear(mBuffer,
+ mWidth,
+ mHeight,
+ pixelSize,
+ radians,
+ pixelsOut,
+ mWidth,
+ mHeight);
+
+ // Check whether the rotation succedded and set the new pixel buffer data.
+ const bool success = nullptr != pixelsOut;
+
+ if(success)
+ {
+ // Release the memory of the current pixel buffer.
+ ReleaseBuffer();
+
+ // Set the new pixel buffer.
+ mBuffer = pixelsOut;
+ pixelsOut = nullptr;
+ mBufferSize = mWidth * mHeight * pixelSize;
+ }
+
+ return success;
+}
+
+void PixelBuffer::ScaleAndCrop(float scaleFactor, ImageDimensions cropDimensions)
{
- ImageDimensions outDimensions( float(mWidth) * scaleFactor,
- float(mHeight) * scaleFactor );
+ ImageDimensions outDimensions(float(mWidth) * scaleFactor,
+ float(mHeight) * scaleFactor);
- if( outDimensions.GetWidth() != mWidth || outDimensions.GetHeight() != mHeight )
+ if(outDimensions.GetWidth() != mWidth || outDimensions.GetHeight() != mHeight)
{
- Resize( outDimensions );
+ Resize(outDimensions);
}
ImageDimensions postCropDimensions(
std::min(cropDimensions.GetWidth(), outDimensions.GetWidth()),
std::min(cropDimensions.GetHeight(), outDimensions.GetHeight()));
- if( postCropDimensions.GetWidth() < outDimensions.GetWidth() ||
- postCropDimensions.GetHeight() < outDimensions.GetHeight() )
+ if(postCropDimensions.GetWidth() < outDimensions.GetWidth() ||
+ postCropDimensions.GetHeight() < outDimensions.GetHeight())
{
- uint16_t x = ( outDimensions.GetWidth() - postCropDimensions.GetWidth() ) / 2;
- uint16_t y = ( outDimensions.GetHeight() - postCropDimensions.GetHeight() ) / 2;
- Crop( x, y, postCropDimensions );
+ uint16_t x = (outDimensions.GetWidth() - postCropDimensions.GetWidth()) / 2;
+ uint16_t y = (outDimensions.GetHeight() - postCropDimensions.GetHeight()) / 2;
+ Crop(x, y, postCropDimensions);
}
}
-void PixelBuffer::Crop( uint16_t x, uint16_t y, ImageDimensions cropDimensions )
+void PixelBuffer::Crop(uint16_t x, uint16_t y, ImageDimensions cropDimensions)
{
- PixelBufferPtr outBuffer = NewCrop( *this, x, y, cropDimensions );
- TakeOwnershipOfBuffer( *outBuffer );
+ PixelBufferPtr outBuffer = NewCrop(*this, x, y, cropDimensions);
+ TakeOwnershipOfBuffer(*outBuffer);
}
-PixelBufferPtr PixelBuffer::NewCrop( const PixelBuffer& inBuffer, uint16_t x, uint16_t y, ImageDimensions cropDimensions )
+PixelBufferPtr PixelBuffer::NewCrop(const PixelBuffer& inBuffer, uint16_t x, uint16_t y, ImageDimensions cropDimensions)
{
- PixelBufferPtr outBuffer = PixelBuffer::New( cropDimensions.GetWidth(), cropDimensions.GetHeight(), inBuffer.GetPixelFormat() );
- int bytesPerPixel = Pixel::GetBytesPerPixel( inBuffer.mPixelFormat );
- int srcStride = inBuffer.mWidth * bytesPerPixel;
- int destStride = cropDimensions.GetWidth() * bytesPerPixel;
+ PixelBufferPtr outBuffer = PixelBuffer::New(cropDimensions.GetWidth(), cropDimensions.GetHeight(), inBuffer.GetPixelFormat());
+ int bytesPerPixel = Pixel::GetBytesPerPixel(inBuffer.mPixelFormat);
+ int srcStride = inBuffer.mWidth * bytesPerPixel;
+ int destStride = cropDimensions.GetWidth() * bytesPerPixel;
// Clamp crop to right edge
- if( x + cropDimensions.GetWidth() > inBuffer.mWidth )
+ if(x + cropDimensions.GetWidth() > inBuffer.mWidth)
{
- destStride = ( inBuffer.mWidth - x ) * bytesPerPixel;
+ destStride = (inBuffer.mWidth - x) * bytesPerPixel;
}
- int srcOffset = x * bytesPerPixel + y * srcStride;
- int destOffset = 0;
+ int srcOffset = x * bytesPerPixel + y * srcStride;
+ int destOffset = 0;
unsigned char* destBuffer = outBuffer->mBuffer;
// Clamp crop to last row
unsigned int endRow = y + cropDimensions.GetHeight();
- if( endRow > inBuffer.mHeight )
+ if(endRow > inBuffer.mHeight)
{
- endRow = inBuffer.mHeight - 1 ;
+ endRow = inBuffer.mHeight - 1;
}
- for( uint16_t row = y; row < endRow; ++row )
+ for(uint16_t row = y; row < endRow; ++row)
{
- memcpy(destBuffer + destOffset, inBuffer.mBuffer + srcOffset, destStride );
+ memcpy(destBuffer + destOffset, inBuffer.mBuffer + srcOffset, destStride);
srcOffset += srcStride;
destOffset += destStride;
}
return outBuffer;
-
}
-void PixelBuffer::SetMetadata( const Property::Map& map )
+void PixelBuffer::SetMetadata(const Property::Map& map)
{
mMetadata.reset(new Property::Map(map));
}
bool PixelBuffer::GetMetadata(Property::Map& outMetadata) const
{
- if( !mMetadata )
+ if(!mMetadata)
{
return false;
}
mMetadata = std::move(metadata);
}
-void PixelBuffer::Resize( ImageDimensions outDimensions )
+void PixelBuffer::Resize(ImageDimensions outDimensions)
{
- if( mWidth != outDimensions.GetWidth() || mHeight != outDimensions.GetHeight() )
+ if(mWidth != outDimensions.GetWidth() || mHeight != outDimensions.GetHeight())
{
- PixelBufferPtr outBuffer = NewResize( *this, outDimensions );
- TakeOwnershipOfBuffer( *outBuffer );
+ PixelBufferPtr outBuffer = NewResize(*this, outDimensions);
+ TakeOwnershipOfBuffer(*outBuffer);
}
}
-PixelBufferPtr PixelBuffer::NewResize( const PixelBuffer& inBuffer, ImageDimensions outDimensions )
+PixelBufferPtr PixelBuffer::NewResize(const PixelBuffer& inBuffer, ImageDimensions outDimensions)
{
- PixelBufferPtr outBuffer = PixelBuffer::New( outDimensions.GetWidth(), outDimensions.GetHeight(), inBuffer.GetPixelFormat() );
- ImageDimensions inDimensions( inBuffer.mWidth, inBuffer.mHeight );
+ PixelBufferPtr outBuffer = PixelBuffer::New(outDimensions.GetWidth(), outDimensions.GetHeight(), inBuffer.GetPixelFormat());
+ ImageDimensions inDimensions(inBuffer.mWidth, inBuffer.mHeight);
- bool hasAlpha = Pixel::HasAlpha( inBuffer.mPixelFormat );
- int bytesPerPixel = Pixel::GetBytesPerPixel( inBuffer.mPixelFormat );
+ bool hasAlpha = Pixel::HasAlpha(inBuffer.mPixelFormat);
+ int bytesPerPixel = Pixel::GetBytesPerPixel(inBuffer.mPixelFormat);
Resampler::Filter filterType = Resampler::LANCZOS4;
- if( inDimensions.GetWidth() < outDimensions.GetWidth() && inDimensions.GetHeight() < outDimensions.GetHeight() )
+ if(inDimensions.GetWidth() < outDimensions.GetWidth() && inDimensions.GetHeight() < outDimensions.GetHeight())
{
filterType = Resampler::MITCHELL;
}
// This method only really works for 8 bit wide channels.
// (But could be expanded to work)
- if( inBuffer.mPixelFormat == Pixel::A8 ||
- inBuffer.mPixelFormat == Pixel::L8 ||
- inBuffer.mPixelFormat == Pixel::LA88 ||
- inBuffer.mPixelFormat == Pixel::RGB888 ||
- inBuffer.mPixelFormat == Pixel::RGB8888 ||
- inBuffer.mPixelFormat == Pixel::BGR8888 ||
- inBuffer.mPixelFormat == Pixel::RGBA8888 ||
- inBuffer.mPixelFormat == Pixel::BGRA8888 )
+ if(inBuffer.mPixelFormat == Pixel::A8 ||
+ inBuffer.mPixelFormat == Pixel::L8 ||
+ inBuffer.mPixelFormat == Pixel::LA88 ||
+ inBuffer.mPixelFormat == Pixel::RGB888 ||
+ inBuffer.mPixelFormat == Pixel::RGB8888 ||
+ inBuffer.mPixelFormat == Pixel::BGR8888 ||
+ inBuffer.mPixelFormat == Pixel::RGBA8888 ||
+ inBuffer.mPixelFormat == Pixel::BGRA8888)
{
- Dali::Internal::Platform::Resample( inBuffer.mBuffer, inDimensions,
- outBuffer->GetBuffer(), outDimensions,
- filterType, bytesPerPixel, hasAlpha );
+ Dali::Internal::Platform::Resample(inBuffer.mBuffer, inDimensions, outBuffer->GetBuffer(), outDimensions, filterType, bytesPerPixel, hasAlpha);
}
else
{
- DALI_LOG_ERROR( "Trying to resize an image with too narrow a channel width" );
+ DALI_LOG_ERROR("Trying to resize an image with too narrow a channel width");
}
return outBuffer;
}
-void PixelBuffer::ApplyGaussianBlur( const float blurRadius )
+void PixelBuffer::ApplyGaussianBlur(const float blurRadius)
{
// This method only works for pixel buffer in RGBA format.
- if( mWidth > 0 && mHeight > 0 && mPixelFormat == Pixel::RGBA8888 )
+ if(mWidth > 0 && mHeight > 0 && mPixelFormat == Pixel::RGBA8888)
{
- if ( blurRadius > Math::MACHINE_EPSILON_1 )
+ if(blurRadius > Math::MACHINE_EPSILON_1)
{
- PerformGaussianBlurRGBA( *this, blurRadius );
+ PerformGaussianBlurRGBA(*this, blurRadius);
}
}
else
{
- DALI_LOG_ERROR( "Trying to apply gaussian blur to an empty pixel buffer or a pixel buffer not in RGBA format" );
+ DALI_LOG_ERROR("Trying to apply gaussian blur to an empty pixel buffer or a pixel buffer not in RGBA format");
}
}
void PixelBuffer::MultiplyColorByAlpha()
{
- auto bytesPerPixel = Pixel::GetBytesPerPixel( mPixelFormat );
+ auto bytesPerPixel = Pixel::GetBytesPerPixel(mPixelFormat);
// Compressed textures have unknown size of the pixel. Alpha premultiplication
// must be skipped in such case
- if( Pixel::GetBytesPerPixel(mPixelFormat) && Pixel::HasAlpha(mPixelFormat) )
+ if(Pixel::GetBytesPerPixel(mPixelFormat) && Pixel::HasAlpha(mPixelFormat))
{
- unsigned char* pixel = mBuffer;
+ unsigned char* pixel = mBuffer;
const unsigned int bufferSize = mWidth * mHeight;
- for( unsigned int i=0; i<bufferSize; ++i )
+ for(unsigned int i = 0; i < bufferSize; ++i)
{
- unsigned int alpha = ReadChannel( pixel, mPixelFormat, Adaptor::ALPHA );
+ unsigned int alpha = ReadChannel(pixel, mPixelFormat, Adaptor::ALPHA);
{
- auto red = ReadChannel( pixel, mPixelFormat, Adaptor::RED);
- auto green = ReadChannel( pixel, mPixelFormat, Adaptor::GREEN);
- auto blue = ReadChannel( pixel, mPixelFormat, Adaptor::BLUE);
- auto luminance = ReadChannel( pixel, mPixelFormat, Adaptor::LUMINANCE);
- WriteChannel( pixel, mPixelFormat, Adaptor::RED, red*alpha / 255 );
- WriteChannel( pixel, mPixelFormat, Adaptor::GREEN, green*alpha/255 );
- WriteChannel( pixel, mPixelFormat, Adaptor::BLUE, blue*alpha/255 );
- WriteChannel( pixel, mPixelFormat, Adaptor::LUMINANCE, luminance*alpha/255 );
+ auto red = ReadChannel(pixel, mPixelFormat, Adaptor::RED);
+ auto green = ReadChannel(pixel, mPixelFormat, Adaptor::GREEN);
+ auto blue = ReadChannel(pixel, mPixelFormat, Adaptor::BLUE);
+ auto luminance = ReadChannel(pixel, mPixelFormat, Adaptor::LUMINANCE);
+ WriteChannel(pixel, mPixelFormat, Adaptor::RED, red * alpha / 255);
+ WriteChannel(pixel, mPixelFormat, Adaptor::GREEN, green * alpha / 255);
+ WriteChannel(pixel, mPixelFormat, Adaptor::BLUE, blue * alpha / 255);
+ WriteChannel(pixel, mPixelFormat, Adaptor::LUMINANCE, luminance * alpha / 255);
}
pixel += bytesPerPixel;
}
}
+ mPreMultiplied = true;
+}
+
+bool PixelBuffer::IsAlphaPreMultiplied() const
+{
+ return mPreMultiplied;
}
+uint32_t PixelBuffer::GetBrightness() const
+{
+ uint32_t brightness = 0;
+
+ uint32_t bytesPerPixel = Pixel::GetBytesPerPixel(mPixelFormat);
+ if(bytesPerPixel)
+ {
+ unsigned char* pixel = mBuffer;
+ const uint32_t bufferSize = mWidth * mHeight;
+ uint64_t red = 0;
+ uint64_t green = 0;
+ uint64_t blue = 0;
+ for(uint32_t i = 0; i < bufferSize; ++i)
+ {
+ red += ReadChannel(pixel, mPixelFormat, Adaptor::RED);
+ green += ReadChannel(pixel, mPixelFormat, Adaptor::GREEN);
+ blue += ReadChannel(pixel, mPixelFormat, Adaptor::BLUE);
+ pixel += bytesPerPixel;
+ }
+ // http://www.w3.org/TR/AERT#color-contrast
+ brightness = (red * BRIGHTNESS_CONSTANT_R + green * BRIGHTNESS_CONSTANT_G + blue * BRIGHTNESS_CONSTANT_B) / (1000uLL * bufferSize);
+ }
+ return brightness;
+}
-}// namespace Adaptor
-}// namespace Internal
-}// namespace Dali
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali