Implemented basic CPU image masking 35/132535/7
authorDavid Steele <david.steele@samsung.com>
Tue, 6 Jun 2017 09:18:36 +0000 (10:18 +0100)
committerDavid Steele <david.steele@samsung.com>
Fri, 9 Jun 2017 10:52:44 +0000 (11:52 +0100)
Given a PixelData containing an image and a PixelData to use as a mask,
this will apply the alpha channel of the mask to the image; either
multiplying into the image's alpha channel, or if it doesn't have one,
converting the image to RGBA888 and applying the mask's alpha channel.

If the mask is a different size than the image, then this will sample a
single pixel from a smaller mask, or use bilinear filtering to sample
from a larger mask.

Change-Id: I48b5d332627a4fb85899883868d278bcbc2b9c8e

12 files changed:
automated-tests/src/dali-internal/CMakeLists.txt
automated-tests/src/dali-internal/utc-Dali-Internal-PixelData.cpp [new file with mode: 0644]
automated-tests/src/dali/dali-test-suite-utils/test-compare-types.h
automated-tests/src/dali/utc-Dali-PixelData.cpp
dali/devel-api/file.list
dali/devel-api/images/pixel-data-mask.cpp [new file with mode: 0644]
dali/devel-api/images/pixel-data-mask.h [new file with mode: 0644]
dali/internal/event/images/pixel-data-impl.cpp
dali/internal/event/images/pixel-data-impl.h
dali/internal/event/images/pixel-manipulation.cpp [new file with mode: 0644]
dali/internal/event/images/pixel-manipulation.h [new file with mode: 0644]
dali/internal/file.list

index 56ae01c..91eb1f4 100644 (file)
@@ -12,6 +12,7 @@ SET(TC_SOURCES
         utc-Dali-Internal-MemoryPoolObjectAllocator.cpp
         utc-Dali-Internal-FrustumCulling.cpp
         utc-Dali-Internal-ActorDepth.cpp
+        utc-Dali-Internal-PixelData.cpp
 )
 
 LIST(APPEND TC_SOURCES
diff --git a/automated-tests/src/dali-internal/utc-Dali-Internal-PixelData.cpp b/automated-tests/src/dali-internal/utc-Dali-Internal-PixelData.cpp
new file mode 100644 (file)
index 0000000..47535ec
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <iostream>
+
+#include <stdlib.h>
+#include <dali/public-api/dali-core.h>
+
+#include <dali-test-suite-utils.h>
+
+// Internal headers are allowed here
+
+#include <dali/internal/event/images/pixel-manipulation.h>
+
+using namespace Dali;
+using namespace Dali::Internal::Pixel;
+void utc_dali_internal_pixel_data_startup()
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_internal_pixel_data_cleanup()
+{
+  test_return_value = TET_PASS;
+}
+
+const char* ChannelToString( Dali::Internal::Pixel::Channel channel )
+{
+  switch(channel)
+  {
+    case LUMINANCE: return "Luminance";
+    case RED: return "Red";
+    case GREEN: return "Green";
+    case BLUE: return "Blue";
+    case ALPHA: return "Alpha";
+    default:
+      return "Unknown";
+  }
+}
+
+const char* FormatToString( Dali::Pixel::Format format )
+{
+  switch(format)
+  {
+    case Dali::Pixel::A8: return "A8";
+    case Dali::Pixel::L8: return "L8";
+    case Dali::Pixel::LA88: return "LA88";
+    case Dali::Pixel::RGB565: return "RGB565";
+    case Dali::Pixel::BGR565: return "BGR565";
+    case Dali::Pixel::RGBA4444: return "RGBA4444";
+    case Dali::Pixel::BGRA4444: return "BGRA4444";
+    case Dali::Pixel::RGBA5551: return "RGBA5551";
+    case Dali::Pixel::BGRA5551: return "BGRA5551";
+
+    case Dali::Pixel::RGB888: return "RGB888";
+    case Dali::Pixel::RGBA8888: return "RGBA8888";
+    case Dali::Pixel::BGRA8888: return "BGRA8888";
+
+    default:
+      return "Unknown";
+  }
+}
+
+
+int UtcDaliPixelManipulation01(void)
+{
+  tet_infoline("Testing Dali::Internal::PixelManipulation HasChannel");
+
+  DALI_TEST_EQUALS( Dali::Internal::Pixel::HasChannel( Dali::Pixel::A8, Dali::Internal::Pixel::ALPHA ), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Pixel::HasChannel( Dali::Pixel::A8, Dali::Internal::Pixel::LUMINANCE ), false, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( Dali::Internal::Pixel::HasChannel( Dali::Pixel::L8, Dali::Internal::Pixel::LUMINANCE ), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Pixel::HasChannel( Dali::Pixel::L8, Dali::Internal::Pixel::ALPHA ), false, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( Dali::Internal::Pixel::HasChannel( Dali::Pixel::LA88, Dali::Internal::Pixel::LUMINANCE ), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Pixel::HasChannel( Dali::Pixel::LA88, Dali::Internal::Pixel::ALPHA ), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Pixel::HasChannel( Dali::Pixel::LA88, Dali::Internal::Pixel::RED ), false, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( Dali::Internal::Pixel::HasChannel( Dali::Pixel::RGB565, Dali::Internal::Pixel::RED ), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Pixel::HasChannel( Dali::Pixel::RGB565, Dali::Internal::Pixel::GREEN ), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Pixel::HasChannel( Dali::Pixel::RGB565, Dali::Internal::Pixel::BLUE ), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Pixel::HasChannel( Dali::Pixel::RGB565, Dali::Internal::Pixel::LUMINANCE ), false, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( Dali::Internal::Pixel::HasChannel( Dali::Pixel::RGBA8888, Dali::Internal::Pixel::RED ), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Pixel::HasChannel( Dali::Pixel::RGBA8888, Dali::Internal::Pixel::GREEN ), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Pixel::HasChannel( Dali::Pixel::RGBA8888, Dali::Internal::Pixel::BLUE ), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Pixel::HasChannel( Dali::Pixel::RGBA8888, Dali::Internal::Pixel::ALPHA ), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Pixel::HasChannel( Dali::Pixel::RGBA8888, Dali::Internal::Pixel::LUMINANCE ), false, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( Dali::Internal::Pixel::HasChannel( Dali::Pixel::COMPRESSED_RGBA_ASTC_10x6_KHR, Dali::Internal::Pixel::BLUE ), false, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+
+int UtcDaliPixelManipulation02(void)
+{
+  tet_infoline("Testing Dali::Internal::PixelManipulation Read/WriteChannel");
+
+  unsigned char pixel[4] = {0,0,0,0};
+
+  for( int formatIdx=1; formatIdx<Dali::Pixel::COMPRESSED_R11_EAC; ++formatIdx)
+  {
+    pixel[0] = 0xFF;
+    pixel[1] = 0xFF;
+    pixel[2] = 0xFF;
+    pixel[3] = 0xFF;
+
+    for( int channelIdx=0; channelIdx < Dali::Internal::Pixel::MAX_NUMBER_OF_CHANNELS; ++channelIdx )
+    {
+      Dali::Pixel::Format format = static_cast<Dali::Pixel::Format>(formatIdx);
+      Dali::Internal::Pixel::Channel channel = static_cast<Dali::Internal::Pixel::Channel>(channelIdx);
+      if( Dali::Internal::Pixel::HasChannel( format, channel ) )
+      {
+        Dali::Internal::Pixel::WriteChannel( &pixel[0], format, channel, 0x15);
+        unsigned int value = Dali::Internal::Pixel::ReadChannel( &pixel[0], format, channel );
+
+        tet_printf( "Testing writing and reading to %s channel in %s format:\n",
+                      ChannelToString(channel), FormatToString(format) );
+
+        if( channel == Dali::Internal::Pixel::ALPHA && (format == Dali::Pixel::RGBA5551 || format == Dali::Pixel::BGRA5551 ) )
+        {
+          DALI_TEST_EQUALS( value, 0x1, TEST_LOCATION );
+        }
+        else if( format == Dali::Pixel::RGBA4444 || format == Dali::Pixel::BGRA4444 )
+        {
+          DALI_TEST_EQUALS( value, 0x05, TEST_LOCATION );
+        }
+        else
+        {
+          DALI_TEST_EQUALS( value, 0x15, TEST_LOCATION );
+        }
+      }
+    }
+  }
+
+  END_TEST;
+}
+
+
+int UtcDaliPixelManipulation03N(void)
+{
+  tet_infoline("Testing Dali::Internal::PixelManipulation Read/WriteChannel");
+
+  unsigned char pixel[4] = {0,0,0,0};
+
+  for( int formatIdx=1; formatIdx<Dali::Pixel::COMPRESSED_R11_EAC; ++formatIdx)
+  {
+    pixel[0] = 0xFF;
+    pixel[1] = 0xFF;
+    pixel[2] = 0xFF;
+    pixel[3] = 0xFF;
+
+    for( int channelIdx=0; channelIdx < Dali::Internal::Pixel::MAX_NUMBER_OF_CHANNELS; ++channelIdx )
+    {
+      Dali::Pixel::Format format = static_cast<Dali::Pixel::Format>(formatIdx);
+      Dali::Internal::Pixel::Channel channel = static_cast<Dali::Internal::Pixel::Channel>(channelIdx);
+      if( ! Dali::Internal::Pixel::HasChannel( format, channel ) )
+      {
+        unsigned int value = Dali::Internal::Pixel::ReadChannel( &pixel[0], format, channel );
+
+        tet_printf( "Testing reading from %s channel in %s format:\n",
+                      ChannelToString(channel), FormatToString(format) );
+
+        DALI_TEST_EQUALS( value, 0x00, TEST_LOCATION );
+      }
+    }
+  }
+
+  END_TEST;
+}
index 248276e..dd6ba24 100644 (file)
@@ -173,9 +173,16 @@ inline bool CompareType<Property::Value>(Property::Value q1, Property::Value q2,
       result = CompareType<Quaternion>(a, b, epsilon);
       break;
     }
+    case Property::STRING:
+    {
+      std::string a, b;
+      q1.Get(a);
+      q2.Get(b);
+      result = (a.compare(b) == 0);
+      break;
+    }
     case Property::MATRIX:
     case Property::MATRIX3:
-    case Property::STRING:
     case Property::ARRAY:
     case Property::MAP:
     {
index 6151545..b9b3d87 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <dali/public-api/images/pixel.h>
 #include <dali/public-api/images/pixel-data.h>
+#include <dali/devel-api/images/pixel-data-mask.h>
 #include <dali/public-api/common/dali-vector.h>
 
 using namespace Dali;
@@ -98,3 +99,133 @@ int UtcDaliPixelDataAssignmentOperator(void)
   END_TEST;
 }
 
+
+int UtcDaliPixelDataMask01(void)
+{
+  TestApplication application;
+
+  unsigned int width = 10u;
+  unsigned int height = 10u;
+  unsigned int bufferSize = width*height*Pixel::GetBytesPerPixel( Pixel::L8 );
+  unsigned char* buffer = new unsigned char [ bufferSize ];
+  PixelData maskData = PixelData::New( buffer, bufferSize, width, height, Pixel::L8, PixelData::DELETE_ARRAY );
+
+  width = 20u;
+  height = 20u;
+  Pixel::Format pixelFormat = Pixel::RGBA5551;
+  bufferSize = width*height*Pixel::GetBytesPerPixel( pixelFormat );
+  buffer = new unsigned char [ bufferSize ];
+  PixelData imageData = PixelData::New( buffer, bufferSize, width, height, pixelFormat, PixelData::DELETE_ARRAY );
+
+  Dali::ApplyMask( imageData, maskData );
+
+  // Test that the pixel format has been promoted to RGBA8888
+  DALI_TEST_EQUALS( imageData.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPixelDataMask02(void)
+{
+  TestApplication application;
+
+  unsigned int width = 10u;
+  unsigned int height = 10u;
+  unsigned int bufferSize = width*height*Pixel::GetBytesPerPixel( Pixel::L8 );
+  unsigned char* buffer = new unsigned char [ bufferSize ];
+  PixelData maskData = PixelData::New( buffer, bufferSize, width, height, Pixel::L8, PixelData::DELETE_ARRAY );
+
+  width = 20u;
+  height = 20u;
+  Pixel::Format pixelFormat = Pixel::RGBA4444;
+  bufferSize = width*height*Pixel::GetBytesPerPixel( pixelFormat );
+  buffer = new unsigned char [ bufferSize ];
+  PixelData imageData = PixelData::New( buffer, bufferSize, width, height, pixelFormat, PixelData::DELETE_ARRAY );
+
+  Dali::ApplyMask( imageData, maskData );
+
+  // Test that the pixel format has been promoted to RGBA8888
+  DALI_TEST_EQUALS( imageData.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPixelDataMask03(void)
+{
+  TestApplication application;
+
+  unsigned int width = 20u;
+  unsigned int height = 20u;
+  unsigned int bufferSize = width*height*Pixel::GetBytesPerPixel( Pixel::L8 );
+  unsigned char* buffer = new unsigned char [ bufferSize ];
+  PixelData maskData = PixelData::New( buffer, bufferSize, width, height, Pixel::L8, PixelData::DELETE_ARRAY );
+
+  width = 10u;
+  height = 10u;
+  Pixel::Format format = Pixel::RGB565;
+  bufferSize = width*height*Pixel::GetBytesPerPixel( format );
+  buffer = new unsigned char [ bufferSize ];
+  PixelData imageData = PixelData::New( buffer, bufferSize, width, height, format, PixelData::DELETE_ARRAY );
+
+  Dali::ApplyMask( imageData, maskData );
+
+  // Test that the pixel format has been promoted to RGBA8888
+  DALI_TEST_EQUALS( imageData.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION );
+
+  // Can't test the final image directly...
+
+  END_TEST;
+}
+
+
+int UtcDaliPixelDataMask04(void)
+{
+  TestApplication application;
+
+  unsigned int width = 10u;
+  unsigned int height = 10u;
+  unsigned int bufferSize = width*height*Pixel::GetBytesPerPixel( Pixel::L8 );
+  unsigned char* buffer = new unsigned char [ bufferSize ];
+  PixelData maskData = PixelData::New( buffer, bufferSize, width, height, Pixel::L8, PixelData::DELETE_ARRAY );
+
+  width = 20u;
+  height = 20u;
+  bufferSize = width*height*Pixel::GetBytesPerPixel( Pixel::RGBA8888 );
+  buffer = new unsigned char [ bufferSize ];
+  PixelData imageData = PixelData::New( buffer, bufferSize, width, height, Pixel::RGBA8888, PixelData::DELETE_ARRAY );
+
+  Dali::ApplyMask( imageData, maskData );
+
+  // Test that the pixel format hasn't changed
+  DALI_TEST_EQUALS( imageData.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION );
+
+  // Can't test the final image directly...
+
+  END_TEST;
+}
+
+int UtcDaliPixelDataMask05(void)
+{
+  TestApplication application;
+
+  unsigned int width = 20u;
+  unsigned int height = 20u;
+  unsigned int bufferSize = width*height*Pixel::GetBytesPerPixel( Pixel::L8 );
+  unsigned char* buffer = new unsigned char [ bufferSize ];
+  PixelData maskData = PixelData::New( buffer, bufferSize, width, height, Pixel::L8, PixelData::DELETE_ARRAY );
+
+  width = 10u;
+  height = 10u;
+  bufferSize = width*height*Pixel::GetBytesPerPixel( Pixel::RGBA8888 );
+  buffer = new unsigned char [ bufferSize ];
+  PixelData imageData = PixelData::New( buffer, bufferSize, width, height, Pixel::RGBA8888, PixelData::DELETE_ARRAY );
+
+  Dali::ApplyMask( imageData, maskData );
+
+  // Test that the pixel format hasn't changed
+  DALI_TEST_EQUALS( imageData.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION );
+
+  // Can't test the final image directly...
+
+  END_TEST;
+}
index 2823573..b44c3f9 100644 (file)
@@ -9,6 +9,7 @@ devel_api_src_files = \
   $(devel_api_src_dir)/images/distance-field.cpp \
   $(devel_api_src_dir)/images/texture-set-image.cpp \
   $(devel_api_src_dir)/images/nine-patch-image.cpp \
+  $(devel_api_src_dir)/images/pixel-data-mask.cpp \
   $(devel_api_src_dir)/object/handle-devel.cpp \
   $(devel_api_src_dir)/object/weak-handle.cpp \
   $(devel_api_src_dir)/object/csharp-type-registry.cpp \
@@ -44,7 +45,8 @@ devel_api_core_images_header_files = \
   $(devel_api_src_dir)/images/distance-field.h \
   $(devel_api_src_dir)/images/native-image-interface-extension.h \
   $(devel_api_src_dir)/images/texture-set-image.h \
-  $(devel_api_src_dir)/images/nine-patch-image.h
+  $(devel_api_src_dir)/images/nine-patch-image.h \
+  $(devel_api_src_dir)/images/pixel-data-mask.h
 
 devel_api_core_object_header_files = \
   $(devel_api_src_dir)/object/csharp-type-info.h \
diff --git a/dali/devel-api/images/pixel-data-mask.cpp b/dali/devel-api/images/pixel-data-mask.cpp
new file mode 100644 (file)
index 0000000..448a286
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali/devel-api/images/pixel-data-mask.h>
+#include <dali/internal/event/images/pixel-data-impl.h>
+
+namespace Dali
+{
+
+void ApplyMask( PixelData image, PixelData mask )
+{
+  if( image && mask )
+  {
+    GetImplementation(image).ApplyMask( GetImplementation(mask) );
+  }
+}
+
+
+} // namespace Dali
diff --git a/dali/devel-api/images/pixel-data-mask.h b/dali/devel-api/images/pixel-data-mask.h
new file mode 100644 (file)
index 0000000..d0e8e56
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef DALI_DEVEL_API_IMAGES_PIXEL_DATA_MASK_H
+#define DALI_DEVEL_API_IMAGES_PIXEL_DATA_MASK_H
+
+/*
+ * Copyright (c) 2017 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali/public-api/images/pixel-data.h>
+
+namespace Dali
+{
+
+/**
+ * @brief Apply the mask to this pixel data.
+ * If the mask image size is larger, then this will sample from
+ * the mask using bilinear filtering.
+ * @param[in] image The pixel data of the image
+ * @param[in] mask The pixel data of the mask
+ */
+DALI_IMPORT_API void ApplyMask( PixelData image, PixelData mask );
+
+} // namespace Dali
+
+#endif // DALI_DEVEL_API_IMAGES_PIXEL_DATA_MASK_H
index 44a7e1d..41c0aed 100644 (file)
@@ -21,6 +21,9 @@
 // EXTERNAL INCLUDES
 #include <stdlib.h>
 
+// INTERNAL INCLUDES
+#include <dali/internal/event/images/pixel-manipulation.h>
+
 namespace Dali
 {
 
@@ -31,7 +34,7 @@ PixelData::PixelData( unsigned char* buffer,
                       unsigned int bufferSize,
                       unsigned int width,
                       unsigned int height,
-                      Pixel::Format pixelFormat,
+                      Dali::Pixel::Format pixelFormat,
                       Dali::PixelData::ReleaseFunction releaseFunction )
 : mBuffer( buffer ),
   mBufferSize( bufferSize ),
@@ -46,22 +49,15 @@ PixelData::~PixelData()
 {
   if( mBuffer )
   {
-    if( mReleaseFunction == Dali::PixelData::FREE)
-    {
-      free( mBuffer );
-    }
-    else
-    {
-      delete[] mBuffer;
-    }
+    ReleaseBuffer();
   }
- }
+}
 
 PixelDataPtr PixelData::New(unsigned char* buffer,
                             unsigned int bufferSize,
                             unsigned int width,
                             unsigned int height,
-                            Pixel::Format pixelFormat,
+                            Dali::Pixel::Format pixelFormat,
                             Dali::PixelData::ReleaseFunction releaseFunction)
 {
   return new PixelData( buffer, bufferSize, width, height, pixelFormat, releaseFunction );
@@ -77,7 +73,7 @@ unsigned int PixelData::GetHeight() const
   return mHeight;
 }
 
-Pixel::Format PixelData::GetPixelFormat() const
+Dali::Pixel::Format PixelData::GetPixelFormat() const
 {
   return mPixelFormat;
 }
@@ -92,6 +88,223 @@ unsigned int PixelData::GetBufferSize() const
   return mBufferSize;
 }
 
+void PixelData::ReleaseBuffer()
+{
+  if( mReleaseFunction == Dali::PixelData::FREE)
+  {
+    free( mBuffer );
+  }
+  else
+  {
+    delete[] mBuffer;
+  }
+}
+
+void PixelData::ApplyMask( const PixelData& mask )
+{
+  int byteOffset=0;
+  int bitMask=0;
+  Dali::Pixel::GetAlphaOffsetAndMask(mPixelFormat, byteOffset, bitMask);
+
+  if( Dali::Pixel::HasAlpha( mPixelFormat ) && bitMask == 255 )
+  {
+    ApplyMaskToAlphaChannel( mask );
+  }
+  else
+  {
+    AddAlphaChannel(mask);
+  }
+}
+
+void PixelData::ApplyMaskToAlphaChannel( const PixelData& mask )
+{
+  const float rowFactor = float(mask.mHeight) / (1.0f * mHeight);
+  const float colFactor = float(mask.mWidth) / (1.0f * mWidth) ;
+
+  int numSamples = 1;
+  if( mask.mHeight > mHeight || mask.mWidth > mWidth )
+  {
+    numSamples = 4;
+  }
+
+  int srcAlphaByteOffset=0;
+  int srcAlphaMask=0;
+  Dali::Pixel::GetAlphaOffsetAndMask( mask.mPixelFormat, srcAlphaByteOffset, srcAlphaMask );
+
+  int destAlphaByteOffset=0;
+  int destAlphaMask=0;
+  Dali::Pixel::GetAlphaOffsetAndMask( mPixelFormat, destAlphaByteOffset, destAlphaMask );
+
+  unsigned int srcBytesPerPixel = Dali::Pixel::GetBytesPerPixel( mask.mPixelFormat );
+  unsigned int destBytesPerPixel = Dali::Pixel::GetBytesPerPixel( mPixelFormat );
+  int srcStride = mask.mWidth * srcBytesPerPixel;
+
+  int srcOffset=0;
+  int destOffset=0;
+
+  float srcAlphaValue = 1.0f;
+
+  for( unsigned int row = 0; row < mHeight; ++row )
+  {
+    for( unsigned int col = 0; col < mWidth; ++col )
+    {
+      if( numSamples == 1 )
+      {
+        srcOffset = floorf(row * rowFactor) * srcStride + floorf(col * colFactor) * srcBytesPerPixel;
+        unsigned char alpha = mask.mBuffer[srcOffset + srcAlphaByteOffset] & srcAlphaMask;
+        srcAlphaValue = float(alpha)/255.0f;
+      }
+      else
+      {
+        srcAlphaValue = mask.ReadWeightedSample( col*colFactor, row*rowFactor );
+      }
+
+      unsigned char destAlpha = mBuffer[destOffset + destAlphaByteOffset] & destAlphaMask;
+      float destAlphaValue = Clamp(float(destAlpha) * srcAlphaValue, 0.0f, 255.0f);
+      destAlpha = destAlphaValue;
+      mBuffer[destOffset + destAlphaByteOffset] &= ~destAlphaMask;
+      mBuffer[destOffset + destAlphaByteOffset] |= ( destAlpha & destAlphaMask );
+
+      destOffset += destBytesPerPixel;
+    }
+  }
+}
+
+void PixelData::AddAlphaChannel( const PixelData& mask )
+{
+  const float rowFactor = float(mask.mHeight) / (1.0f * mHeight);
+  const float colFactor = float(mask.mWidth) / (1.0f * mWidth) ;
+
+  int numSamples = 1;
+  if( mask.mHeight > mHeight || mask.mWidth > mWidth )
+  {
+    numSamples = 4;
+  }
+
+  // Set up source alpha offsets
+  int srcAlphaByteOffset=0;
+  int srcAlphaMask=0;
+  Dali::Pixel::GetAlphaOffsetAndMask( mask.mPixelFormat, srcAlphaByteOffset, srcAlphaMask );
+
+  unsigned int srcAlphaBytesPerPixel = Dali::Pixel::GetBytesPerPixel( mask.mPixelFormat );
+  int srcAlphaStride = mask.mWidth * srcAlphaBytesPerPixel;
+
+  // Set up source color offsets
+  unsigned int srcColorBytesPerPixel = Dali::Pixel::GetBytesPerPixel( mPixelFormat );
+
+  // Setup destination offsets
+  Dali::Pixel::Format destPixelFormat = Dali::Pixel::RGBA8888;
+  unsigned int destBytesPerPixel = Dali::Pixel::GetBytesPerPixel( destPixelFormat );
+  int destAlphaByteOffset=0;
+  int destAlphaMask=0;
+  Dali::Pixel::GetAlphaOffsetAndMask( destPixelFormat, destAlphaByteOffset, destAlphaMask );
+
+  int destBufferSize = mWidth * mHeight * destBytesPerPixel;
+  unsigned char* destBuffer = static_cast<unsigned char*>( malloc( destBufferSize ) );
+
+  int srcAlphaOffset=0;
+  int srcColorOffset=0;
+  int destOffset=0;
+  bool hasAlpha = Dali::Pixel::HasAlpha(mPixelFormat);
+
+  float srcAlphaValue = 1.0f;
+  unsigned char destAlpha = 0;
+
+  for( unsigned int row = 0; row < mHeight; ++row )
+  {
+    for( unsigned int col = 0; col < mWidth; ++col )
+    {
+      if( numSamples == 1 )
+      {
+        srcAlphaOffset = floorf(row * rowFactor) * srcAlphaStride + floorf(col * colFactor) * srcAlphaBytesPerPixel;
+        unsigned char alpha = mask.mBuffer[srcAlphaOffset + srcAlphaByteOffset] & srcAlphaMask;
+        srcAlphaValue = float(alpha)/255.0f;
+      }
+      else
+      {
+        srcAlphaValue = mask.ReadWeightedSample( col*colFactor, row*rowFactor );
+      }
+
+      Pixel::ConvertColorChannelsToRGBA8888(mBuffer, srcColorOffset, mPixelFormat, destBuffer, destOffset );
+
+      if( hasAlpha )
+      {
+        destAlpha = mBuffer[destOffset + destAlphaByteOffset] & destAlphaMask;
+        float destAlphaValue = Clamp(float(destAlpha) * srcAlphaValue, 0.0f, 255.0f);
+        destAlpha = destAlphaValue;
+      }
+      else
+      {
+        destAlpha = floorf(Clamp(srcAlphaValue * 255.0f, 0.0f, 255.0f));
+      }
+
+      destBuffer[destOffset + destAlphaByteOffset] &= ~destAlphaMask;
+      destBuffer[destOffset + destAlphaByteOffset] |= ( destAlpha & destAlphaMask );
+
+      srcColorOffset += srcColorBytesPerPixel;
+      destOffset += destBytesPerPixel;
+    }
+  }
+
+  ReleaseBuffer();
+
+  mBuffer = destBuffer;
+  mBufferSize = destBufferSize;
+  mPixelFormat = Dali::Pixel::RGBA8888;
+  mReleaseFunction = Dali::PixelData::FREE;
+}
+
+float PixelData::ReadWeightedSample( float x, float y ) const
+{
+  unsigned int srcRow = floorf( y );
+  unsigned int srcCol = floorf( x );
+
+  int bytesPerPixel = Dali::Pixel::GetBytesPerPixel( mPixelFormat );
+  int stride = mWidth * bytesPerPixel;
+  int srcOffset = srcRow * stride + srcCol * bytesPerPixel;
+  float samples[4];
+
+  samples[0] = ReadChannel( mBuffer + srcOffset, mPixelFormat, Pixel::ALPHA );
+
+  if( srcCol < mWidth-1 )
+  {
+    samples[1] = ReadChannel( mBuffer + srcOffset+bytesPerPixel, mPixelFormat, Pixel::ALPHA );
+  }
+  else
+  {
+    samples[1] = samples[0];
+  }
+
+  if( srcRow < mHeight-1 )
+  {
+    samples[2] = ReadChannel( mBuffer + stride + srcOffset, mPixelFormat, Pixel::ALPHA );
+  }
+  else
+  {
+    samples[2] = samples[0];
+  }
+
+  if( srcRow < mHeight-1 && srcCol < mWidth-1 )
+  {
+    samples[3] = ReadChannel( mBuffer + stride + srcOffset + bytesPerPixel, mPixelFormat, Pixel::ALPHA );
+  }
+  else
+  {
+    samples[3] = samples[2];
+  }
+
+  // Bilinear interpolation:
+  float weight[4];
+  weight[0] = float(srcRow+1.0f) - y;
+  weight[1] = y - float(srcRow);
+  weight[2] = float(srcCol+1.0f) - x;
+  weight[3] = x - float(srcCol);
+
+  return ( weight[2] * (samples[0] * weight[0] + samples[1] * weight[1]) +
+           weight[3] * (samples[2] * weight[0] + samples[3] * weight[1]) ) / 256.0f;
+}
+
+
 }// namespace Internal
 
 }// namespace Dali
index 4d45f73..6c49ede 100644 (file)
@@ -110,9 +110,45 @@ public:
    */
   unsigned int GetBufferSize() const;
 
+  /**
+   * Apply the mask to this data
+   * @param[in] mask The mask to apply
+   */
+  void ApplyMask( const PixelData& mask );
+
 private:
+  /**
+   * Release the buffer
+   */
+  void ReleaseBuffer();
 
-  /*
+  /**
+   * Apply the mask to this data's alpha channel
+   * @param[in] mask The mask to apply
+   */
+  void ApplyMaskToAlphaChannel( const PixelData& mask );
+
+  /**
+   * Convert to RGBA8888 and apply the mask's alpha channel
+   * to this data's alpha channel
+   * @param[in] mask The mask to apply
+   */
+  void AddAlphaChannel( const PixelData& mask );
+
+  /**
+   * Apply the mask to this data's color channels (e.g. to apply vignette)
+   * @param[in] mask The mask to apply
+   */
+  void ApplyMaskToColorChannels( const PixelData& mask );
+
+  /**
+   * Read a weighted sample from a pixel (of unknown size)
+   * @param[in] x The x coordinate to sample from
+   * @param[in] y The y coordinate to sample from
+   */
+  float ReadWeightedSample( float x, float y ) const;
+
+   /*
    * Undefined copy constructor.
    */
   PixelData(const PixelData& other);
@@ -120,7 +156,7 @@ private:
   /*
    * Undefined assignment operator.
    */
-  PixelData& operator = (const PixelData& other);
+  PixelData& operator= (const PixelData& other);
 
 private:
 
diff --git a/dali/internal/event/images/pixel-manipulation.cpp b/dali/internal/event/images/pixel-manipulation.cpp
new file mode 100644 (file)
index 0000000..b8f5693
--- /dev/null
@@ -0,0 +1,693 @@
+/*
+ * Copyright (c) 2017 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include <dali/internal/event/images/pixel-manipulation.h>
+
+// INTERNAL HEADERS
+#include <dali/public-api/images/pixel.h>
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Pixel
+{
+
+struct Location
+{
+  unsigned int bitShift;
+  unsigned int bitMask;
+  bool available;
+};
+
+struct Locations
+{
+  Location luminance;
+  Location alpha;
+  Location red;
+  Location green;
+  Location blue;
+};
+
+
+bool HasChannel( Dali::Pixel::Format pixelFormat, Channel channel )
+{
+  switch (pixelFormat)
+  {
+    case Dali::Pixel::A8:
+    {
+      return (channel == ALPHA);
+    }
+    case Dali::Pixel::L8:
+    {
+      return (channel == LUMINANCE);
+    }
+    case Dali::Pixel::LA88:
+    {
+      return ( channel == LUMINANCE || channel == ALPHA );
+    }
+    case Dali::Pixel::RGB565:
+    case Dali::Pixel::BGR565:
+    case Dali::Pixel::RGB888:
+    case Dali::Pixel::RGB8888:
+    case Dali::Pixel::BGR8888:
+    {
+      return ( channel == RED || channel == GREEN || channel == BLUE );
+    }
+
+    case Dali::Pixel::RGBA8888:
+    case Dali::Pixel::BGRA8888:
+    case Dali::Pixel::RGBA4444:
+    case Dali::Pixel::BGRA4444:
+    case Dali::Pixel::RGBA5551:
+    case Dali::Pixel::BGRA5551:
+    {
+      return ( channel == RED || channel == GREEN || channel == BLUE || channel == ALPHA );
+    }
+
+    case Dali::Pixel::INVALID:
+    case Dali::Pixel::COMPRESSED_R11_EAC:
+    case Dali::Pixel::COMPRESSED_SIGNED_R11_EAC:
+    case Dali::Pixel::COMPRESSED_RG11_EAC:
+    case Dali::Pixel::COMPRESSED_SIGNED_RG11_EAC:
+    case Dali::Pixel::COMPRESSED_RGB8_ETC2:
+    case Dali::Pixel::COMPRESSED_SRGB8_ETC2:
+    case Dali::Pixel::COMPRESSED_RGB8_ETC1:
+    case Dali::Pixel::COMPRESSED_RGB_PVRTC_4BPPV1:
+    case Dali::Pixel::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+    case Dali::Pixel::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+    case Dali::Pixel::COMPRESSED_RGBA8_ETC2_EAC:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_4x4_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_5x4_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_5x5_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_6x5_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_6x6_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_8x5_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_8x6_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_8x8_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_10x5_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_10x6_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_10x8_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_10x10_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_12x10_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_12x12_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
+    {
+      DALI_LOG_ERROR("Pixel formats for compressed images are not compatible with simple channels.\n");
+      break;
+    }
+  }
+
+  return false;
+}
+
+unsigned int ReadChannel( unsigned char* pixelData,
+                          Dali::Pixel::Format pixelFormat,
+                          Channel channel )
+{
+  switch (pixelFormat)
+  {
+    case Dali::Pixel::A8:
+    {
+      if( channel == ALPHA )
+      {
+        return static_cast<unsigned int>(*pixelData);
+      }
+      else return 0u;
+    }
+    case Dali::Pixel::L8:
+    {
+      if( channel == LUMINANCE )
+      {
+        return static_cast<unsigned int>(*pixelData);
+      }
+      else return 0u;
+    }
+    case Dali::Pixel::LA88:
+    {
+      if( channel == LUMINANCE )
+      {
+        return static_cast<unsigned int>(*pixelData);
+      }
+      else if( channel == ALPHA )
+      {
+        return static_cast<unsigned int>(*(pixelData+1));
+      }
+      else return 0u;
+    }
+    case Dali::Pixel::RGB565:
+    {
+      if( channel == RED )
+      {
+        return (static_cast<unsigned int>(*pixelData) & 0xF8) >> 3;
+      }
+      else if( channel == GREEN )
+      {
+        return ((static_cast<unsigned int>(*pixelData) & 0x07) << 3) |
+          ((static_cast<unsigned int>(*(pixelData+1)) & 0xE0) >> 5);
+      }
+      else if( channel == BLUE )
+      {
+        return static_cast<unsigned int>(*(pixelData+1)) & 0x1F;
+      }
+      else return 0u;
+    }
+
+    case Dali::Pixel::BGR565:
+    {
+      if( channel == BLUE )
+      {
+        return (static_cast<unsigned int>(*pixelData) & 0xF8) >> 3;
+      }
+      else if( channel == GREEN )
+      {
+        return ((static_cast<unsigned int>(*pixelData) & 0x07) << 3) |
+          ((static_cast<unsigned int>(*(pixelData+1)) & 0xE0) >> 5);
+      }
+      else if( channel == RED )
+      {
+        return (static_cast<unsigned int>(*(pixelData+1) & 0x1F) );
+      }
+      else return 0u;
+    }
+
+    case Dali::Pixel::RGB888:
+    case Dali::Pixel::RGB8888:
+    {
+      if( channel == RED )
+      {
+        return static_cast<unsigned int>(*pixelData);
+      }
+      else if( channel == GREEN )
+      {
+        return static_cast<unsigned int>(*(pixelData+1));
+      }
+      else if( channel == BLUE )
+      {
+        return static_cast<unsigned int>(*(pixelData+2));
+      }
+      else return 0u;
+    }
+
+    case Dali::Pixel::BGR8888:
+    {
+      if( channel == BLUE )
+      {
+        return static_cast<unsigned int>(*pixelData);
+      }
+      else if( channel == GREEN )
+      {
+        return static_cast<unsigned int>(*(pixelData+1));
+      }
+      else if( channel == RED )
+      {
+        return static_cast<unsigned int>(*(pixelData+2));
+      }
+      else return 0u;
+    }
+
+    case Dali::Pixel::RGBA8888:
+    {
+      if( channel == RED )
+      {
+        return static_cast<unsigned int>(*pixelData);
+      }
+      else if( channel == GREEN )
+      {
+        return static_cast<unsigned int>(*(pixelData+1));
+      }
+      else if( channel == BLUE )
+      {
+        return static_cast<unsigned int>(*(pixelData+2));
+      }
+      else if( channel == ALPHA )
+      {
+        return static_cast<unsigned int>(*(pixelData+3));
+      }
+      else return 0u;
+    }
+
+    case Dali::Pixel::BGRA8888:
+    {
+      if( channel == BLUE )
+      {
+        return static_cast<unsigned int>(*pixelData);
+      }
+      else if( channel == GREEN )
+      {
+        return static_cast<unsigned int>(*(pixelData+1));
+      }
+      else if( channel == RED )
+      {
+        return static_cast<unsigned int>(*(pixelData+2));
+      }
+      else if( channel == ALPHA )
+      {
+        return static_cast<unsigned int>(*(pixelData+3));
+      }
+      else return 0u;
+    }
+
+    case Dali::Pixel::RGBA4444:
+    {
+      if( channel == RED )
+      {
+        return (static_cast<unsigned int>(*pixelData) & 0xF0) >> 4;
+      }
+      else if( channel == GREEN )
+      {
+        return (static_cast<unsigned int>(*pixelData) & 0x0F);
+      }
+      else if( channel == BLUE )
+      {
+        return (static_cast<unsigned int>(*(pixelData+1)) & 0xF0) >> 4;
+      }
+      else if( channel == ALPHA )
+      {
+        return (static_cast<unsigned int>(*(pixelData+1)) & 0x0F);
+      }
+      else return 0u;
+    }
+
+    case Dali::Pixel::BGRA4444:
+    {
+      if( channel == BLUE )
+      {
+        return (static_cast<unsigned int>(*pixelData) & 0xF0) >> 4;
+      }
+      else if( channel == GREEN )
+      {
+        return (static_cast<unsigned int>(*pixelData) & 0x0F);
+      }
+      else if( channel == RED )
+      {
+        return (static_cast<unsigned int>(*(pixelData+1)) & 0xF0) >> 4;
+      }
+      else if( channel == ALPHA )
+      {
+        return (static_cast<unsigned int>(*(pixelData+1)) & 0x0F);
+      }
+      else return 0u;
+    }
+
+    case Dali::Pixel::RGBA5551:
+    {
+      if( channel == RED )
+      {
+        return (static_cast<unsigned int>(*pixelData) & 0xF8) >> 3;
+      }
+      else if( channel == GREEN )
+      {
+        return ((static_cast<unsigned int>(*pixelData) & 0x07) << 2) |
+          ((static_cast<unsigned int>(*(pixelData+1)) & 0xC0) >> 6);
+      }
+      else if( channel == BLUE )
+      {
+        return (static_cast<unsigned int>(*(pixelData+1)) & 0x3E) >> 1;
+      }
+      else if( channel == ALPHA )
+      {
+        return static_cast<unsigned int>(*(pixelData+1)) & 0x01;
+      }
+
+      else return 0u;
+    }
+
+    case Dali::Pixel::BGRA5551:
+    {
+      if( channel == BLUE )
+      {
+        return (static_cast<unsigned int>(*pixelData) & 0xF8) >> 3;
+      }
+      else if( channel == GREEN )
+      {
+        return ((static_cast<unsigned int>(*pixelData) & 0x07) << 2) |
+          ((static_cast<unsigned int>(*(pixelData+1)) & 0xC0) >> 6);
+      }
+      else if( channel == RED )
+      {
+        return ( static_cast<unsigned int>(*(pixelData+1)) & 0x3E) >> 1;
+      }
+      else if( channel == ALPHA )
+      {
+        return static_cast<unsigned int>(*(pixelData+1)) & 0x01;
+      }
+
+      else return 0u;
+    }
+
+    default:
+    {
+      return 0u;
+    }
+  }
+}
+
+void WriteChannel( unsigned char* pixelData,
+                   Dali::Pixel::Format pixelFormat,
+                   Channel channel,
+                   unsigned int channelValue )
+{
+  switch (pixelFormat)
+  {
+    case Dali::Pixel::A8:
+    {
+      if( channel == ALPHA )
+      {
+        *pixelData = static_cast<unsigned char>( channelValue & 0xFF );
+      }
+      break;
+    }
+    case Dali::Pixel::L8:
+    {
+      if( channel == LUMINANCE )
+      {
+        *pixelData = static_cast<unsigned char>( channelValue & 0xFF );
+      }
+      break;
+    }
+    case Dali::Pixel::LA88:
+    {
+      if( channel == LUMINANCE )
+      {
+        *pixelData = static_cast<unsigned char>( channelValue & 0xFF );
+      }
+      else if( channel == ALPHA )
+      {
+        *(pixelData+1) = static_cast<unsigned char>( channelValue & 0xFF );
+      }
+      break;
+    }
+    case Dali::Pixel::RGB565:
+    {
+      if( channel == RED )
+      {
+        *pixelData &= ~0xF8;
+        *pixelData |= static_cast<unsigned char>( (channelValue << 3) & 0xF8 );
+      }
+      else if( channel == GREEN )
+      {
+        *pixelData &= ~0x07;
+        *pixelData |= static_cast<unsigned char>( (channelValue >> 3) & 0x07 );
+
+        *(pixelData+1) &= ~0xE0;
+        *(pixelData+1) |= static_cast<unsigned char>( (channelValue << 5) & 0xE0 );
+      }
+      else if( channel == BLUE )
+      {
+        *(pixelData+1) &= ~0x1F;
+        *(pixelData+1) |= static_cast<unsigned char>( channelValue & 0x1F );
+      }
+      break;
+    }
+
+    case Dali::Pixel::BGR565:
+    {
+      if( channel == BLUE )
+      {
+        *pixelData &= ~0xF8;
+        *pixelData |= static_cast<unsigned char>( (channelValue << 3) & 0xF8 );
+      }
+      else if( channel == GREEN )
+      {
+        *pixelData &= ~0x07;
+        *pixelData |= static_cast<unsigned char>( (channelValue >> 3) & 0x07 );
+
+        *(pixelData+1) &= ~0xE0;
+        *(pixelData+1) |= static_cast<unsigned char>( (channelValue << 5) & 0xE0 );
+      }
+      else if( channel == RED )
+      {
+        *(pixelData+1) &= ~0x1F;
+        *(pixelData+1) |= static_cast<unsigned char>( channelValue & 0x1F );
+      }
+      break;
+    }
+
+    case Dali::Pixel::RGB888:
+    case Dali::Pixel::RGB8888:
+    {
+      if( channel == RED )
+      {
+        *pixelData = static_cast<unsigned char>( channelValue & 0xFF );
+      }
+      else if( channel == GREEN )
+      {
+        *(pixelData+1) = static_cast<unsigned char>( channelValue & 0xFF );
+      }
+      else if( channel == BLUE )
+      {
+        *(pixelData+2) = static_cast<unsigned char>( channelValue & 0xFF );
+      }
+      break;
+    }
+
+    case Dali::Pixel::BGR8888:
+    {
+      if( channel == BLUE )
+      {
+        *pixelData = static_cast<unsigned char>( channelValue & 0xFF );
+      }
+      else if( channel == GREEN )
+      {
+        *(pixelData+1) = static_cast<unsigned char>( channelValue & 0xFF );
+      }
+      else if( channel == RED )
+      {
+        *(pixelData+2) = static_cast<unsigned char>( channelValue & 0xFF );
+      }
+      break;
+    }
+
+    case Dali::Pixel::RGBA8888:
+    {
+      if( channel == RED )
+      {
+        *pixelData = static_cast<unsigned char>( channelValue & 0xFF );
+      }
+      else if( channel == GREEN )
+      {
+        *(pixelData+1) = static_cast<unsigned char>( channelValue & 0xFF );
+      }
+      else if( channel == BLUE )
+      {
+        *(pixelData+2) = static_cast<unsigned char>( channelValue & 0xFF );
+      }
+      else if( channel == ALPHA )
+      {
+        *(pixelData+3) = static_cast<unsigned char>( channelValue & 0xFF );
+      }
+      break;
+    }
+
+    case Dali::Pixel::BGRA8888:
+    {
+      if( channel == BLUE )
+      {
+        *pixelData = static_cast<unsigned char>( channelValue & 0xFF );
+      }
+      else if( channel == GREEN )
+      {
+        *(pixelData+1) = static_cast<unsigned char>( channelValue & 0xFF );
+      }
+      else if( channel == RED )
+      {
+        *(pixelData+2) = static_cast<unsigned char>( channelValue & 0xFF );
+      }
+      else if( channel == ALPHA )
+      {
+        *(pixelData+3) = static_cast<unsigned char>( channelValue & 0xFF );
+      }
+      break;
+    }
+
+    case Dali::Pixel::RGBA4444:
+    {
+      if( channel == RED )
+      {
+        *pixelData &= ~0xF0;
+        *pixelData |= static_cast<unsigned char>( (channelValue << 4) & 0xF0 );
+      }
+      else if( channel == GREEN )
+      {
+        *pixelData &= ~0x0F;
+        *pixelData |= static_cast<unsigned char>( channelValue & 0x0F );
+      }
+      else if( channel == BLUE )
+      {
+        *(pixelData+1) &= ~0xF0;
+        *(pixelData+1) |= static_cast<unsigned char>( (channelValue << 4) & 0xF0 );
+      }
+      else if( channel == ALPHA )
+      {
+        *(pixelData+1) &= ~0x0F;
+        *(pixelData+1) |= static_cast<unsigned char>( channelValue & 0x0F );
+      }
+      break;
+    }
+
+    case Dali::Pixel::BGRA4444:
+    {
+      if( channel == BLUE )
+      {
+        *pixelData &= ~0xF0;
+        *pixelData |= static_cast<unsigned char>( (channelValue << 4) & 0xF0 );
+      }
+      else if( channel == GREEN )
+      {
+        *pixelData &= ~0x0F;
+        *pixelData |= static_cast<unsigned char>( channelValue & 0x0F );
+      }
+      else if( channel == RED )
+      {
+        *(pixelData+1) &= ~0xF0;
+        *(pixelData+1) |= static_cast<unsigned char>( (channelValue << 4) & 0xF0 );
+      }
+      else if( channel == ALPHA )
+      {
+        *(pixelData+1) &= ~0x0F;
+        *(pixelData+1) |= static_cast<unsigned char>( channelValue & 0x0F );
+      }
+      break;
+    }
+
+    case Dali::Pixel::RGBA5551:
+    {
+      // rrrrrggg ggbbbbba
+      //    F8  7 C0  3E 1
+      if( channel == RED )
+      {
+        *pixelData &= ~0xF8;
+        *pixelData |= static_cast<unsigned char>( (channelValue << 3) & 0xF8 );
+      }
+      else if( channel == GREEN )
+      {
+        *pixelData &= ~0x07;
+        *pixelData |= static_cast<unsigned char>( (channelValue >> 2) & 0x07 );
+
+        *(pixelData+1) &= ~0xC0;
+        *(pixelData+1) |= static_cast<unsigned char>( (channelValue << 6) & 0xC0 );
+      }
+      else if( channel == BLUE )
+      {
+        *(pixelData+1) &= ~0x3E;
+        *(pixelData+1) |= static_cast<unsigned char>( (channelValue << 1) & 0x3E );
+      }
+      else if( channel == ALPHA )
+      {
+        *(pixelData+1) &= ~0x01;
+        *(pixelData+1) |= static_cast<unsigned char>( channelValue & 0x01 );
+      }
+      break;
+    }
+
+    case Dali::Pixel::BGRA5551:
+    {
+      if( channel == BLUE )
+      {
+        *pixelData &= ~0xF8;
+        *pixelData |= static_cast<unsigned char>( (channelValue << 3) & 0xF8 );
+      }
+      else if( channel == GREEN )
+      {
+        *pixelData &= ~0x07;
+        *pixelData |= static_cast<unsigned char>( (channelValue >> 2) & 0x07 );
+
+        *(pixelData+1) &= ~0xC0;
+        *(pixelData+1) |= static_cast<unsigned char>( (channelValue << 6) & 0xC0 );
+      }
+      else if( channel == RED )
+      {
+        *(pixelData+1) &= ~0x3E;
+        *(pixelData+1) |= static_cast<unsigned char>( (channelValue << 1 ) & 0x3E );
+      }
+      else if( channel == ALPHA )
+      {
+        *(pixelData+1) &= ~0x01;
+        *(pixelData+1) |= static_cast<unsigned char>( channelValue & 0x01 );
+      }
+      break;
+    }
+
+    default:
+      break;
+  }
+}
+
+void ConvertColorChannelsToRGBA8888(
+  unsigned char* srcPixel,  int srcOffset,  Dali::Pixel::Format srcFormat,
+  unsigned char* destPixel, int destOffset )
+{
+  int red   = ReadChannel(srcPixel+srcOffset, srcFormat, RED );
+  int green = ReadChannel(srcPixel+srcOffset, srcFormat, GREEN );
+  int blue  = ReadChannel(srcPixel+srcOffset, srcFormat, BLUE );
+  switch( srcFormat )
+  {
+    case Dali::Pixel::RGB565:
+    case Dali::Pixel::BGR565:
+    {
+      red<<=3;
+      green<<=2;
+      blue<<=3;
+      break;
+    }
+    case Dali::Pixel::RGBA4444:
+    case Dali::Pixel::BGRA4444:
+    {
+      red<<=4;
+      green<<=4;
+      blue<<=4;
+      break;
+    }
+    case Dali::Pixel::RGBA5551:
+    case Dali::Pixel::BGRA5551:
+    {
+      red<<=3;
+      green<<=3;
+      blue<<=3;
+      break;
+    }
+    default:
+      break;
+  }
+  WriteChannel(destPixel+destOffset, Dali::Pixel::RGBA8888, RED, red);
+  WriteChannel(destPixel+destOffset, Dali::Pixel::RGBA8888, GREEN, green);
+  WriteChannel(destPixel+destOffset, Dali::Pixel::RGBA8888, BLUE, blue);
+}
+
+
+
+} // Pixel
+} // Internal
+} // Dali
diff --git a/dali/internal/event/images/pixel-manipulation.h b/dali/internal/event/images/pixel-manipulation.h
new file mode 100644 (file)
index 0000000..f9e6098
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef DALI_EVENT_IMAGES_PIXEL_MANIPULATION_H
+#define DALI_EVENT_IMAGES_PIXEL_MANIPULATION_H
+
+/*
+ * Copyright (c) 2017 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali/public-api/images/pixel.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Pixel
+{
+
+enum Channel
+{
+  LUMINANCE,
+  RED,
+  GREEN,
+  BLUE,
+  ALPHA,
+  MAX_NUMBER_OF_CHANNELS
+};
+
+/**
+ * Return true if the channel exists in the pixel format
+ * @param[in] pixelFormat The pixelFormat
+ * @param[in] channel The channel to test for
+ * @return true if the channel exists
+ */
+bool HasChannel( Dali::Pixel::Format pixelFormat, Channel channel );
+
+
+/**
+ * Read a colour channel from the pixel with the given pixel format.
+ * Returns zero if the format does not support the channel
+ * @param[in] pixelData Location of the pixel
+ * @param[in] pixelFormat The format of the pixel
+ * @param[in] channel The channel to read
+ * @return the channel value
+ */
+unsigned int ReadChannel( unsigned char* pixelData,
+                          Dali::Pixel::Format pixelFormat,
+                          Channel channel );
+
+/**
+ * Write a colour channel to the pixel with the given pixel format.
+ * @param[in] pixelData Location of the pixel
+ * @param[in] pixelFormat The format of the pixel
+ * @param[in] channel The channel to write
+ * @param[in] channelValue the value to write to the channel
+ */
+void WriteChannel( unsigned char* pixelData,
+                   Dali::Pixel::Format pixelFormat,
+                   Channel channel,
+                   unsigned int channelValue );
+
+void ConvertColorChannelsToRGBA8888(
+  unsigned char* srcPixel,  int srcOffset,  Dali::Pixel::Format srcFormat,
+  unsigned char* destPixel, int destOffset );
+
+} // Pixel
+} // Internal
+} // Dali
+
+
+#endif // DALI_EVENT_IMAGES_PIXEL_MANIPULATION_H
index 4b98598..cf4ac67 100644 (file)
@@ -74,6 +74,7 @@ internal_src_files = \
   $(internal_src_dir)/event/images/resource-image-impl.cpp \
   $(internal_src_dir)/event/images/native-image-impl.cpp \
   $(internal_src_dir)/event/images/pixel-data-impl.cpp \
+  $(internal_src_dir)/event/images/pixel-manipulation.cpp \
   $(internal_src_dir)/event/object/custom-object-internal.cpp \
   $(internal_src_dir)/event/render-tasks/render-task-impl.cpp \
   $(internal_src_dir)/event/render-tasks/render-task-list-impl.cpp \