// INTERNAL INCLUDES
#include "pixel-manipulation.h"
#include "alpha-mask.h"
+#include <platform-abstractions/portable/image-operations.h>
namespace Dali
{
return pixelData;
}
-void PixelBuffer::ApplyMask( const PixelBuffer& mask )
+void PixelBuffer::ApplyMask( const PixelBuffer& inMask, float contentScale, bool 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() ) );
+
+ if( inMask.mWidth > mWidth || inMask.mHeight > mHeight )
+ {
+ PixelBufferPtr mask = NewResize( inMask, ImageDimensions( mWidth, mHeight ) );
+ ApplyMaskInternal( *mask );
+ }
+ else
+ {
+ 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 );
+ }
+}
+
+void PixelBuffer::ApplyMaskInternal( const PixelBuffer& mask )
{
int byteOffset=0;
int bitMask=0;
Dali::Pixel::GetAlphaOffsetAndMask(mPixelFormat, byteOffset, bitMask);
-
if( Dali::Pixel::HasAlpha( mPixelFormat ) && bitMask == 255 )
{
ApplyMaskToAlphaChannel( *this, mask );
else
{
PixelBufferPtr newPixelBuffer = CreateNewMaskedBuffer( *this, mask );
- ReleaseBuffer();
-
- // Take ownership of new buffer
- mBuffer = newPixelBuffer->mBuffer;
- newPixelBuffer->mBuffer = NULL;
- mPixelFormat = newPixelBuffer->mPixelFormat;
- mBufferSize = newPixelBuffer->mBufferSize;
-
+ TakeOwnershipOfBuffer( *newPixelBuffer );
// On leaving scope, newPixelBuffer will get destroyed.
}
}
+void PixelBuffer::TakeOwnershipOfBuffer( PixelBuffer& pixelBuffer )
+{
+ ReleaseBuffer();
+
+ // Take ownership of new buffer
+ mBuffer = pixelBuffer.mBuffer;
+ pixelBuffer.mBuffer = NULL;
+ mBufferSize = pixelBuffer.mBufferSize;
+ mWidth = pixelBuffer.mWidth;
+ mHeight = pixelBuffer.mHeight;
+ mPixelFormat = pixelBuffer.mPixelFormat;
+}
+
void PixelBuffer::ReleaseBuffer()
{
if( mBuffer )
}
}
+void PixelBuffer::ScaleAndCrop( float scaleFactor, ImageDimensions cropDimensions )
+{
+ ImageDimensions outDimensions( float(mWidth) * scaleFactor,
+ float(mHeight) * scaleFactor );
+
+ if( outDimensions.GetWidth() != mWidth || outDimensions.GetHeight() != mHeight )
+ {
+ 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() )
+ {
+ 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 )
+{
+ PixelBufferPtr outBuffer = NewCrop( *this, x, y, cropDimensions );
+ TakeOwnershipOfBuffer( *outBuffer );
+}
+
+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;
+
+ // Clamp crop to right edge
+ if( x + cropDimensions.GetWidth() > inBuffer.mWidth )
+ {
+ destStride = ( inBuffer.mWidth - x ) * bytesPerPixel;
+ }
+
+ 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 )
+ {
+ endRow = inBuffer.mHeight - 1 ;
+ }
+ for( uint16_t row = y; row < endRow; ++row )
+ {
+ memcpy(destBuffer + destOffset, inBuffer.mBuffer + srcOffset, destStride );
+ srcOffset += srcStride;
+ destOffset += destStride;
+ }
+ return outBuffer;
+
+}
+
+void PixelBuffer::Resize( ImageDimensions outDimensions )
+{
+ if( mWidth != outDimensions.GetWidth() || mHeight != outDimensions.GetHeight() )
+ {
+ PixelBufferPtr outBuffer = NewResize( *this, outDimensions );
+ TakeOwnershipOfBuffer( *outBuffer );
+ }
+}
+
+PixelBufferPtr PixelBuffer::NewResize( const PixelBuffer& inBuffer, ImageDimensions outDimensions )
+{
+ 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 );
+
+ Resampler::Filter filterType = Resampler::LANCZOS4;
+ 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 )
+ {
+ 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" );
+ }
+
+ return outBuffer;
+}
}// namespace Adaptor
}// namespace Internal
// INTERNAL INCLUDES
#include <pixel-buffer.h>
+#include <dali/public-api/images/image-operations.h> // For ImageDimensions
#include <dali/public-api/images/pixel-data.h>
#include <dali/public-api/object/base-object.h>
* internal object - e.g. the new buffer may have a different pixel
* format - as an alpha channel may be added.
* @param[in] mask The mask to apply to this pixel buffer
+ * @param[in] contentScale The scaling factor to apply to the content
+ * @param[in] cropToMask Whether to crop the output to the mask size (true) or scale the
+ * mask to the content size (false)
*/
- void ApplyMask( const PixelBuffer& mask );
+ void ApplyMask( const PixelBuffer& mask, float contentScale, bool cropToMask );
private:
/*
PixelBuffer& operator= (const PixelBuffer& other);
/**
+ * Internal method to apply the mask to this buffer. Expects that they are the same size.
+ */
+ void ApplyMaskInternal( const PixelBuffer& mask );
+
+ /**
+ * Takes ownership of the other object's pixel buffer.
+ */
+ void TakeOwnershipOfBuffer( PixelBuffer& pixelBuffer );
+
+ /**
* Release the buffer
*/
void ReleaseBuffer();
+ /**
+ * Scales this buffer buffer by the given factor, and crops at the center to the
+ * given dimensions.
+ */
+ void ScaleAndCrop( float scaleFactor, ImageDimensions cropDimensions );
+
+ /**
+ * Creates a new buffer which is a crop of the passed in buffer,
+ * using the given crop rectangle. Assumes the crop rectangle is
+ * within the bounds of this size.
+ * @param[in] inBuffer The source buffer
+ * @param[in] x The top left corner's X
+ * @param[in] y The top left corner's y
+ * @param[in] cropDimensions The dimensions of the crop
+ * @return the new pixel buffer
+ */
+ static PixelBufferPtr NewCrop( const PixelBuffer& inBuffer, uint16_t x, uint16_t y, ImageDimensions cropDimensions );
+
+ /**
+ * Creates a new buffer which is a resized version of the passed in buffer.
+ * Uses either Lanczos4 for downscaling, or Mitchell for upscaling.
+ * @param[in] inBuffer The source buffer
+ * @param[in] outDimensions The new dimensions
+ * @return a new buffer of the given size.
+ */
+ static PixelBufferPtr NewResize( const PixelBuffer& inBuffer, ImageDimensions outDimensions );
+
+ /**
+ * Crops this buffer to the given crop rectangle. Assumes the crop rectangle
+ * is within the bounds of this size.
+ * @param[in] x The top left corner's X
+ * @param[in] y The top left corner's y
+ * @param[in] cropDimensions The dimensions of the crop
+ */
+ void Crop( uint16_t x, uint16_t y, ImageDimensions cropDimensions );
+
+ /**
+ * Resizes the buffer to the given dimensions. Uses either Lanczos4 for downscaling
+ * or Mitchell for upscaling
+ * @param[in] outDimensions The new dimensions
+ */
+ void Resize( ImageDimensions outDimensions );
+
private:
unsigned char* mBuffer; ///< The raw pixel data
return GetImplementation(*this).GetBuffer();
}
-void PixelBuffer::ApplyMask( PixelBuffer mask )
+void PixelBuffer::ApplyMask( PixelBuffer mask, float contentScale, bool cropToMask )
{
- GetImplementation(*this).ApplyMask( GetImplementation( mask ) );
+ GetImplementation(*this).ApplyMask( GetImplementation( mask ), contentScale, cropToMask );
}
} // namespace Devel
Pixel::Format GetPixelFormat() const;
/**
- * Apply the mask to this pixel data, and return a new pixel data
- * containing the masked image. If this PixelBuffer doesn't have an alpha channel,
- * then the resultant PixelBuffer will be converted to a format that
- * supports at least the width of the color channels and the alpha channel
- * from the mask.
+ * Apply the mask to this pixel data, and return a new pixel data containing
+ * the masked image. If this PixelBuffer doesn't have an alpha channel, then
+ * the resultant PixelBuffer will be converted to a format that supports at
+ * least the width of the color channels and the alpha channel from the mask.
+ *
+ * If cropToMask is set to true, then the contentScale is applied first to
+ * this buffer, and the target buffer is cropped to the size of the mask. If
+ * it's set to false, then the mask is scaled to match this buffer's size
+ * before the mask is applied.
+ *
* @param[in] mask The mask to apply.
+ * @param[in] contentScale The scaling factor to apply to the content
+ * @param[in] cropToMask Whether to crop the output to the mask size (true)
+ * or scale the mask to the content size (false)
*/
- void ApplyMask( PixelBuffer mask );
+ void ApplyMask( PixelBuffer mask, float contentScale=1.0f, bool cropToMask=false );
public:
../../../adaptors/tizen
../../../adaptors/ubuntu
../../../text
+ ../../../third-party/image-resampler
${${CAPI_LIB}_INCLUDE_DIRS}
../dali-adaptor/dali-test-suite-utils
)
}
}
+void MaskCenterSquare( Devel::PixelBuffer maskData )
+{
+ int width = maskData.GetWidth();
+ int height = maskData.GetHeight();
+ Pixel::Format pixelFormat = maskData.GetPixelFormat();
+ int bpp = Pixel::GetBytesPerPixel(pixelFormat);
+
+ unsigned char* maskBuffer = maskData.GetBuffer();
+ memset( maskBuffer, 0, width*height*bpp );
+ int offset=0;
+ for( int y=0; y<height; ++y)
+ {
+ for( int x=0; x<width; ++x)
+ {
+ if(x>=width/4 && x<3*width/4 &&
+ y>=height/4 && y<3*height/4 )
+ {
+ for(int b=0;b<bpp;++b)
+ {
+ maskBuffer[offset+b] = 0xff;
+ }
+ }
+ offset+=bpp;
+ }
+ }
+}
+
+void AlternateQuadrants( Devel::PixelBuffer buffer )
+{
+ int width = buffer.GetWidth();
+ int height = buffer.GetHeight();
+ Pixel::Format pixelFormat = buffer.GetPixelFormat();
+ int bpp = Pixel::GetBytesPerPixel(pixelFormat);
+ int stride=width*bpp;
+
+ unsigned char* pixels = buffer.GetBuffer();
+ memset( pixels, 0, width*height*bpp );
+
+ for( int x=0; x<width; ++x)
+ {
+ for( int y=0; y<height; ++y)
+ {
+ if( ( x < width/2 && y >= height/2 ) ||
+ ( x >= width/2 && y < height/2 ) )
+ {
+ for(int b=0;b<bpp;++b)
+ {
+ pixels[y*stride+x*bpp+b] = 0xff;
+ }
+ }
+ }
+ }
+}
+
+
void FillCheckerboard( Devel::PixelBuffer imageData )
{
int width = imageData.GetWidth();
}
}
+int GetAlphaAt( Devel::PixelBuffer buffer, int x, int y )
+{
+ unsigned char* pixels = buffer.GetBuffer();
+ int bpp = Pixel::GetBytesPerPixel(buffer.GetPixelFormat());
+ int stride = buffer.GetWidth() * bpp;
+ int byteOffset;
+ int bitMask;
+ GetAlphaOffsetAndMask( buffer.GetPixelFormat(), byteOffset, bitMask );
+ return int(pixels[stride * y + x*bpp + byteOffset]) & bitMask;
+}
+
int UtcDaliPixelBufferNew01P(void)
{
TestApplication application;
Devel::PixelBuffer imageData = Devel::PixelBuffer::New( width, height, pixelFormat );
FillCheckerboard(imageData);
- imageData.ApplyMask( maskData );
+ imageData.ApplyMask( maskData, 1.0f, false );
// Test that the pixel format has been promoted to RGBA8888
DALI_TEST_EQUALS( imageData.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION );
Devel::PixelBuffer imageData = Devel::PixelBuffer::New( width, height, pixelFormat );
FillCheckerboard(imageData);
- imageData.ApplyMask( maskData );
+ imageData.ApplyMask( maskData, 1.0f, false );
// Test that the pixel format has been promoted to RGBA8888
DALI_TEST_EQUALS( imageData.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION );
Devel::PixelBuffer imageData = Devel::PixelBuffer::New( width, height, format );
FillCheckerboard(imageData);
- imageData.ApplyMask( maskData );
+ imageData.ApplyMask( maskData, 1.0f, false );
// Test that the pixel format has been promoted to RGBA8888
DALI_TEST_EQUALS( imageData.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION );
Devel::PixelBuffer imageData = Devel::PixelBuffer::New( width, height, Pixel::RGBA8888 );
FillCheckerboard(imageData);
- imageData.ApplyMask( maskData );
+ imageData.ApplyMask( maskData, 1.0f, false );
// Test that the pixel format has been promoted to RGBA8888
DALI_TEST_EQUALS( imageData.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION );
Devel::PixelBuffer imageData = Devel::PixelBuffer::New( width, height, Pixel::RGBA8888 );
FillCheckerboard(imageData);
- imageData.ApplyMask( maskData );
+ imageData.ApplyMask( maskData, 1.0f, false );
// Test that the pixel format has been promoted to RGBA8888
DALI_TEST_EQUALS( imageData.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION );
Devel::PixelBuffer imageData = Devel::PixelBuffer::New( width, height, Pixel::RGBA8888 );
FillCheckerboard(imageData);
- imageData.ApplyMask( maskData );
+ imageData.ApplyMask( maskData, 1.0f, false );
// Test that the pixel format has been promoted to RGBA8888
DALI_TEST_EQUALS( imageData.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION );
END_TEST;
}
+
+
+int UtcDaliPixelBufferMask07(void)
+{
+ TestApplication application;
+ tet_infoline("Test scaling of source image to match alpha mask" );
+
+ unsigned int width = 20u;
+ unsigned int height = 20u;
+ Devel::PixelBuffer maskData = Devel::PixelBuffer::New( width, height, Pixel::RGBA8888 );
+ MaskCenterSquare(maskData);
+
+ // +----------+
+ // | XXXXXX |
+ // | XXXXXX |
+ // | XXXXXX |
+ // | XXXXXX |
+ // *----------+
+
+ width = 10u;
+ height = 10u;
+ Devel::PixelBuffer imageData = Devel::PixelBuffer::New( width, height, Pixel::RGBA8888 );
+ AlternateQuadrants( imageData );
+
+ // +-----XXXXX+
+ // | XXXXX|
+ // | XXXXX|
+ // |XXXXX |
+ // |XXXXX |
+ // *XXXXX-----+
+
+ imageData.ApplyMask( maskData, 2.0f, true );
+
+ // +----------+
+ // | XXX |
+ // | XXX |
+ // | XXX |
+ // | XXX |
+ // *----------+
+
+ tet_infoline("Test that the image has been scaled to match the alpha mask" );
+ DALI_TEST_EQUALS( imageData.GetWidth(), 20, TEST_LOCATION );
+ DALI_TEST_EQUALS( imageData.GetHeight(), 20, TEST_LOCATION );
+
+ tet_infoline( "Test that pixels in the outer eighths have no alpha\n" );
+
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 0, 0), 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 9, 4), 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 15, 4), 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 19, 4), 0x00u, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 0, 19), 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 8, 18), 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 15,17), 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 19,16), 0x00u, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 0, 1), 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 1, 7), 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 2, 10), 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 3, 19), 0x00u, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 19, 1), 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 18, 7), 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 17, 10), 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 16, 19), 0x00u, TEST_LOCATION );
+
+ tet_infoline( "Test that pixels in the center have full alpha\n" );
+
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 12, 8), 0xffu, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 8, 12), 0xffu, TEST_LOCATION );
+
+ END_TEST;
+}
+
+int UtcDaliPixelBufferMask08(void)
+{
+ TestApplication application;
+ tet_infoline("Test scaling of source image to larger than the alpha mask" );
+
+ unsigned int width = 32u;
+ unsigned int height = 20u;
+ Devel::PixelBuffer maskData = Devel::PixelBuffer::New( width, height, Pixel::RGBA8888 );
+ AlternateQuadrants( maskData );
+
+ // +-----XXXXX+
+ // | XXXXX|
+ // | XXXXX|
+ // |XXXXX |
+ // |XXXXX |
+ // *XXXXX-----+
+
+ width = 20u;
+ height = 16u;
+ Devel::PixelBuffer imageData = Devel::PixelBuffer::New( width, height, Pixel::RGBA8888 );
+ MaskCenterSquare(imageData);
+
+ // +----------+
+ // | XXXXXX |
+ // | XXXXXX |
+ // | XXXXXX |
+ // | XXXXXX |
+ // *----------+
+
+ imageData.ApplyMask( maskData, 4.0f, true );
+
+ // +-----XXXXX+ quadrant
+ // | XXXXX| 1 2
+ // | XXXXX|
+ // |XXXXX | 4 3
+ // |XXXXX |
+ // *XXXXX-----+
+
+ tet_infoline("Test that the image has been scaled and cropped to match the alpha mask" );
+ DALI_TEST_EQUALS( imageData.GetWidth(), 32, TEST_LOCATION );
+ DALI_TEST_EQUALS( imageData.GetHeight(), 20, TEST_LOCATION );
+
+ tet_infoline( "Test that the image has been resized (the center square should now fill the image)\n");
+ tet_infoline( "Test that the first quadrant has no alpha");
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 0, 0), 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 5, 4), 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 5, 8), 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 14, 8), 0x00u, TEST_LOCATION );
+
+ tet_infoline( "Test that the second quadrant has alpha and data");
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 18, 0), 0xffu, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 30, 1), 0xffu, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 30, 8), 0xffu, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 19, 8), 0xffu, TEST_LOCATION );
+
+ tet_infoline( "Test that the third quadrant has no alpha");
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 18, 12), 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 31, 12), 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 31, 19), 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 18, 19), 0x00u, TEST_LOCATION );
+
+ tet_infoline( "Test that the fourth quadrant has alpha and data");
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 1, 12), 0xffu, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 7, 12), 0xffu, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 7, 19), 0xffu, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 1, 19), 0xffu, TEST_LOCATION );
+
+ END_TEST;
+}
+
+
+int UtcDaliPixelBufferMask09(void)
+{
+ TestApplication application;
+ tet_infoline("Test scaling of large source image to larger than the alpha mask" );
+
+ unsigned int width = 32u;
+ unsigned int height = 20u;
+ Devel::PixelBuffer maskData = Devel::PixelBuffer::New( width, height, Pixel::RGBA8888 );
+ AlternateQuadrants( maskData );
+
+ // +-----XXXXX+
+ // | XXXXX|
+ // | XXXXX|
+ // |XXXXX |
+ // |XXXXX |
+ // *XXXXX-----+
+
+ width = 40u;
+ height = 50u;
+ Devel::PixelBuffer imageData = Devel::PixelBuffer::New( width, height, Pixel::RGBA8888 );
+ MaskCenterSquare(imageData);
+
+ // +----------+
+ // | XXXXXX |
+ // | XXXXXX |
+ // | XXXXXX |
+ // | XXXXXX |
+ // *----------+
+
+ imageData.ApplyMask( maskData, 1.6f, true );
+
+ // +-----XXXXX+ quadrant
+ // | XXXXX| 1 2
+ // | XXXXX|
+ // |XXXXX | 4 3
+ // |XXXXX |
+ // *XXXXX-----+
+
+ tet_infoline("Test that the image has been scaled and cropped to match the alpha mask" );
+ DALI_TEST_EQUALS( imageData.GetWidth(), 32, TEST_LOCATION );
+ DALI_TEST_EQUALS( imageData.GetHeight(), 20, TEST_LOCATION );
+
+ tet_infoline( "Test that the image has been resized (the center square should now fill the image)\n");
+ tet_infoline( "Test that the first quadrant has no alpha");
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 0, 0), 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 5, 4), 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 5, 8), 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 14, 8), 0x00u, TEST_LOCATION );
+
+ tet_infoline( "Test that the second quadrant has alpha and data");
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 18, 0), 0xffu, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 30, 1), 0xffu, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 30, 8), 0xffu, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 19, 8), 0xffu, TEST_LOCATION );
+
+ tet_infoline( "Test that the third quadrant has no alpha");
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 18, 12), 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 31, 12), 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 31, 19), 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 18, 19), 0x00u, TEST_LOCATION );
+
+ tet_infoline( "Test that the fourth quadrant has alpha and data");
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 1, 12), 0xffu, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 7, 12), 0xffu, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 7, 19), 0xffu, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetAlphaAt(imageData, 1, 19), 0xffu, TEST_LOCATION );
+
+ END_TEST;
+}
../../../
../../../adaptors/tizen
../../../platform-abstractions/tizen
+ ../../../third-party/image-resampler
${${CAPI_LIB}_INCLUDE_DIRS}
../dali-adaptor/dali-test-suite-utils
/usr/include/freetype2
namespace Adaptor
{
-PixelBufferPtr ResizeMask( const PixelBuffer& inMask, ImageDimensions outDimensions )
-{
- PixelBufferPtr mask;
-
- if( inMask.GetWidth() != outDimensions.GetWidth() || inMask.GetHeight() != outDimensions.GetHeight() )
- {
- mask = PixelBuffer::New( outDimensions.GetWidth(), outDimensions.GetHeight(), inMask.GetPixelFormat() );
- ImageDimensions inDimensions( inMask.GetWidth(), inMask.GetHeight() );
-
- if( Pixel::GetBytesPerPixel( inMask.GetPixelFormat() ) == 4 )
- {
- Dali::Internal::Platform::LanczosSample4BPP( inMask.GetBuffer(), inDimensions,
- mask->GetBuffer(), outDimensions );
- }
- else if( inMask.GetPixelFormat() == Pixel::L8 )
- {
- Dali::Internal::Platform::LanczosSample1BPP( inMask.GetBuffer(), inDimensions,
- mask->GetBuffer(), outDimensions );
- }
- }
- else
- {
- mask = const_cast<PixelBuffer*>(&inMask);
- }
- return mask;
-}
-
-void ApplyMaskToAlphaChannel( PixelBuffer& buffer, const PixelBuffer& inMask )
+void ApplyMaskToAlphaChannel( PixelBuffer& buffer, const PixelBuffer& mask )
{
int srcAlphaByteOffset=0;
int srcAlphaMask=0;
- Dali::Pixel::Format srcPixelFormat = inMask.GetPixelFormat();
-
- PixelBufferPtr mask = ResizeMask( inMask, ImageDimensions( buffer.GetWidth(), buffer.GetHeight() ) );
+ Dali::Pixel::Format srcPixelFormat = mask.GetPixelFormat();
if( Pixel::HasAlpha(srcPixelFormat) )
{
Dali::Pixel::GetAlphaOffsetAndMask( buffer.GetPixelFormat(), destAlphaByteOffset, destAlphaMask );
unsigned int srcBytesPerPixel = Dali::Pixel::GetBytesPerPixel( srcPixelFormat );
- unsigned char* srcBuffer = mask->GetBuffer();
+ unsigned char* srcBuffer = mask.GetBuffer();
unsigned char* destBuffer = buffer.GetBuffer();
unsigned int destBytesPerPixel = Dali::Pixel::GetBytesPerPixel( buffer.GetPixelFormat() );
}
}
-PixelBufferPtr CreateNewMaskedBuffer( const PixelBuffer& buffer, const PixelBuffer& inMask )
+PixelBufferPtr CreateNewMaskedBuffer( const PixelBuffer& buffer, const PixelBuffer& mask )
{
// Set up source alpha offsets
int srcAlphaByteOffset=0;
int srcAlphaMask=0;
- Dali::Pixel::Format srcPixelFormat = inMask.GetPixelFormat();
+ Dali::Pixel::Format srcPixelFormat = mask.GetPixelFormat();
- PixelBufferPtr mask = ResizeMask( inMask, ImageDimensions( buffer.GetWidth(), buffer.GetHeight() ) );
if( Pixel::HasAlpha(srcPixelFormat) )
{
Dali::Pixel::GetAlphaOffsetAndMask( srcPixelFormat, srcAlphaByteOffset, srcAlphaMask );
}
unsigned int srcBytesPerPixel = Dali::Pixel::GetBytesPerPixel( srcPixelFormat );
- unsigned char* srcBuffer = mask->GetBuffer();
+ unsigned char* srcBuffer = mask.GetBuffer();
// Set up source color offsets
Dali::Pixel::Format srcColorPixelFormat = buffer.GetPixelFormat();
namespace Adaptor
{
-
/**
* Apply the mask to a buffer's alpha channel
* @param[in] buffer The buffer to apply the mask to
*/
PixelBufferPtr CreateNewMaskedBuffer( const PixelBuffer& buffer, const PixelBuffer& mask );
-/**
- * Read a weighted sample from the given channel for a given coordinate
- * @param[in] buffer The buffer to read from
- * @param[in] pixelFormat The pixel format of the buffer
- * @param[in] stride The stride across the buffer
- * @param[in] x The x coordinate to sample from
- * @param[in] y The y coordinate to sample from
- * @param[in] width The width of the buffer in pixels
- * @param[in] height The height of the buffer in pixels
- * @param[in] channel The channel to read from
- * @return An averaged value from the 4 pixels around the given coordinate
- */
-float ReadWeightedSample( unsigned char* buffer, Pixel::Format pixelFormat, int stride, float x, float y, int width, int height, Channel channel );
-
} //namespace Adaptor
} //namespace Internal
} //namespace Dali
// Constants used by the ImageResampler.
const float DEFAULT_SOURCE_GAMMA = 1.75f; ///< Default source gamma value used in the Resampler() function. Partial gamma correction looks better on mips. Set to 1.0 to disable gamma correction.
const float FILTER_SCALE = 1.f; ///< Default filter scale value used in the Resampler() function. Filter scale - values < 1.0 cause aliasing, but create sharper looking mips.
-const Resampler::Filter FILTER_TYPE = Resampler::LANCZOS4; ///< Default filter used in the Resampler() function. Possible Lanczos filters are: lanczos3, lanczos4, lanczos6, lanczos12
using Integration::Bitmap;
using Integration::BitmapPtr;
LinearSampleGeneric<Pixel4Bytes, BilinearFilter4Bytes, true>( inPixels, inputDimensions, outPixels, desiredDimensions );
}
-void LanczosSample( const unsigned char * __restrict__ inPixels,
- ImageDimensions inputDimensions,
- unsigned char * __restrict__ outPixels,
- ImageDimensions desiredDimensions,
- int numChannels, bool hasAlpha )
+
+void Resample( const unsigned char * __restrict__ inPixels,
+ ImageDimensions inputDimensions,
+ unsigned char * __restrict__ outPixels,
+ ImageDimensions desiredDimensions,
+ Resampler::Filter filterType,
+ int numChannels, bool hasAlpha )
{
// Got from the test.cpp of the ImageResampler lib.
const float ONE_DIV_255 = 1.0f / 255.0f;
Resampler::BOUNDARY_CLAMP,
0.0f, // sample_low,
1.0f, // sample_high. Clamp output samples to specified range, or disable clamping if sample_low >= sample_high.
- FILTER_TYPE, // The type of filter. Currently Lanczos.
+ filterType, // The type of filter.
NULL, // Pclist_x,
NULL, // Pclist_y. Optional pointers to contributor lists from another instance of a Resampler.
FILTER_SCALE, // src_x_ofs,
Resampler::BOUNDARY_CLAMP,
0.0f,
1.0f,
- FILTER_TYPE,
+ filterType,
resamplers[0]->get_clist_x(),
resamplers[0]->get_clist_y(),
FILTER_SCALE,
unsigned char * __restrict__ outPixels,
ImageDimensions desiredDimensions )
{
- LanczosSample( inPixels, inputDimensions, outPixels, desiredDimensions, 4, true );
+ Resample( inPixels, inputDimensions, outPixels, desiredDimensions, Resampler::LANCZOS4, 4, true );
}
void LanczosSample1BPP( const unsigned char * __restrict__ inPixels,
ImageDimensions desiredDimensions )
{
// For L8 images
- LanczosSample( inPixels, inputDimensions, outPixels, desiredDimensions, 1, false );
+ Resample( inPixels, inputDimensions, outPixels, desiredDimensions, Resampler::LANCZOS4, 1, false );
}
// Dispatch to a format-appropriate linear sampling function:
// INTERNAL INCLUDES
#include <dali/integration-api/bitmap.h>
#include <dali/public-api/images/image-operations.h>
+#include <resampler.h>
namespace Dali
{
unsigned char * __restrict__ outPixels,
ImageDimensions desiredDimensions );
+/**
+ * @brief Resamples the input image with the Lanczos algorithm.
+ *
+ * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
+ * separate buffer from the output buffer.
+ *
+ * @param[in] inPixels Pointer to the input image buffer.
+ * @param[in] inputDimensions The input dimensions of the image.
+ * @param[out] outPixels Pointer to the output image buffer.
+ * @param[in] desiredDimensions The output dimensions of the image.
+ */
+void Resample( const unsigned char * __restrict__ inPixels,
+ ImageDimensions inputDimensions,
+ unsigned char * __restrict__ outPixels,
+ ImageDimensions desiredDimensions,
+ Resampler::Filter filterType,
+ int numChannels, bool hasAlpha );
+
+
/**@}*/
/**