[4.0] Rotate() method added to the PixelBuffer.
[platform/core/uifw/dali-adaptor.git] / adaptors / common / pixel-buffer-impl.cpp
index 1de5382..fbf72a1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
@@ -25,7 +25,9 @@
 // INTERNAL INCLUDES
 #include "pixel-manipulation.h"
 #include "alpha-mask.h"
+#include "gaussian-blur.h"
 #include <platform-abstractions/portable/image-operations.h>
+#include <platform-abstractions/portable/pixel-manipulation.h>
 
 namespace Dali
 {
@@ -36,12 +38,18 @@ namespace Internal
 namespace Adaptor
 {
 
+namespace
+{
+const float TWO_PI = 2.f * Math::PI; ///< 360 degrees in radians
+} // namespace
+
 PixelBuffer::PixelBuffer( unsigned char* buffer,
                           unsigned int bufferSize,
                           unsigned int width,
                           unsigned int height,
                           Dali::Pixel::Format pixelFormat )
-: mBuffer( buffer ),
+: mMetadata(),
+  mBuffer( buffer ),
   mBufferSize( bufferSize ),
   mWidth( width ),
   mHeight( height ),
@@ -201,6 +209,80 @@ void PixelBuffer::ReleaseBuffer()
   }
 }
 
+void PixelBuffer::AllocateFixedSize( uint32_t size )
+{
+  ReleaseBuffer();
+  mBuffer = reinterpret_cast<unsigned char*>(malloc( size ));
+  mBufferSize = size;
+}
+
+void 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;
+  }
+
+  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;
+  }
+
+  const unsigned int pixelSize = Pixel::GetBytesPerPixel( mPixelFormat );
+
+  uint8_t* pixelsOut = nullptr;
+  Platform::RotateByShear( mBuffer,
+                           mWidth,
+                           mHeight,
+                           pixelSize,
+                           radians,
+                           pixelsOut,
+                           mWidth,
+                           mHeight );
+
+  // Release the memory of the current pixel buffer.
+  ReleaseBuffer();
+
+  // Set the new pixel buffer.
+  mBuffer = pixelsOut;
+  pixelsOut = nullptr;
+  mBufferSize = mWidth * mHeight * pixelSize;
+}
+
 void PixelBuffer::ScaleAndCrop( float scaleFactor, ImageDimensions cropDimensions )
 {
   ImageDimensions outDimensions( float(mWidth) * scaleFactor,
@@ -263,6 +345,26 @@ PixelBufferPtr PixelBuffer::NewCrop( const PixelBuffer& inBuffer, uint16_t x, ui
 
 }
 
+void PixelBuffer::SetMetadata( const Property::Map& map )
+{
+  mMetadata.reset(new Property::Map(map));
+}
+
+bool PixelBuffer::GetMetadata(Property::Map& outMetadata) const
+{
+  if( !mMetadata )
+  {
+    return false;
+  }
+  outMetadata = *mMetadata;
+  return true;
+}
+
+void PixelBuffer::SetMetadata(std::unique_ptr<Property::Map> metadata)
+{
+  mMetadata = std::move(metadata);
+}
+
 void PixelBuffer::Resize( ImageDimensions outDimensions )
 {
   if( mWidth != outDimensions.GetWidth() || mHeight != outDimensions.GetHeight() )
@@ -309,6 +411,54 @@ PixelBufferPtr PixelBuffer::NewResize( const PixelBuffer& inBuffer, ImageDimensi
   return outBuffer;
 }
 
+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 ( blurRadius > Math::MACHINE_EPSILON_1 )
+    {
+      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" );
+  }
+}
+
+void PixelBuffer::MultiplyColorByAlpha()
+{
+  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) )
+  {
+    unsigned char* pixel = mBuffer;
+    const unsigned int bufferSize = mWidth * mHeight;
+
+    for( unsigned int i=0; i<bufferSize; ++i )
+    {
+      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 );
+      }
+      pixel += bytesPerPixel;
+    }
+  }
+}
+
+
+
+
 }// namespace Adaptor
 }// namespace Internal
 }// namespace Dali