/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
*
*/
-#ifndef DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H_
-#define DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H_
+#ifndef DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H
+#define DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H
// EXTERNAL INCLUDES
#include <stdint.h>
// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
#include <dali/integration-api/bitmap.h>
#include <dali/public-api/images/image-operations.h>
#include <third-party/resampler/resampler.h>
-#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
namespace Dali
{
{
namespace Platform
{
-
/**
* @brief Identify which combination of x and y dimensions matter in terminating iterative box filtering.
*/
* @param[in] requestedDimensions Width and height of area to scale image into. Can be zero.
* @return Dimensions of area to scale image into after special rules are applied.
*/
-ImageDimensions CalculateDesiredDimensions( ImageDimensions rawDimensions, ImageDimensions requestedDimensions );
+ImageDimensions CalculateDesiredDimensions(ImageDimensions rawDimensions, ImageDimensions requestedDimensions);
/**
* @defgroup BitmapOperations Bitmap-to-Bitmap Image operations.
* bitmap passed-in, or the original bitmap passed in if the attributes
* have no effect.
*/
-Dali::Devel::PixelBuffer ApplyAttributesToBitmap( Dali::Devel::PixelBuffer bitmap, ImageDimensions dimensions, FittingMode::Type fittingMode = FittingMode::DEFAULT, SamplingMode::Type samplingMode = SamplingMode::DEFAULT );
+Dali::Devel::PixelBuffer ApplyAttributesToBitmap(Dali::Devel::PixelBuffer bitmap, ImageDimensions dimensions, FittingMode::Type fittingMode = FittingMode::DEFAULT, SamplingMode::Type samplingMode = SamplingMode::DEFAULT);
/**
* @brief Apply downscaling to a bitmap according to requested attributes.
* @note The input bitmap pixel buffer may be modified and used as scratch working space for efficiency, so it must be discarded.
**/
-Dali::Devel::PixelBuffer DownscaleBitmap( Dali::Devel::PixelBuffer bitmap,
- ImageDimensions desired,
- FittingMode::Type fittingMode,
- SamplingMode::Type samplingMode );
+Dali::Devel::PixelBuffer DownscaleBitmap(Dali::Devel::PixelBuffer bitmap,
+ ImageDimensions desired,
+ FittingMode::Type fittingMode,
+ SamplingMode::Type samplingMode);
/**@}*/
/**
* @param[in] pixelFormat The format of the image pointed at by pixels.
* @param[in] inputWidth The width of the input image.
* @param[in] inputHeight The height of the input image.
+ * @param[in] inputStride The stride of the input image.
* @param[in] desiredWidth The width the client is requesting.
* @param[in] desiredHeight The height the client is requesting.
* @param[out] outWidth The resulting width after downscaling.
* @param[out] outHeight The resulting height after downscaling.
- */
-void DownscaleInPlacePow2( unsigned char * const pixels,
- Pixel::Format pixelFormat,
- unsigned int inputWidth,
- unsigned int inputHeight,
- unsigned int desiredWidth,
- unsigned int desiredHeight,
- FittingMode::Type fittingMode,
- SamplingMode::Type samplingMode,
- unsigned& outWidth,
- unsigned& outHeight );
+ * @param[out] outStride The resulting stride after downscaling.
+ */
+void DownscaleInPlacePow2(unsigned char* const pixels,
+ Pixel::Format pixelFormat,
+ unsigned int inputWidth,
+ unsigned int inputHeight,
+ unsigned int inputStride,
+ unsigned int desiredWidth,
+ unsigned int desiredHeight,
+ FittingMode::Type fittingMode,
+ SamplingMode::Type samplingMode,
+ unsigned& outWidth,
+ unsigned& outHeight,
+ unsigned& outStride);
/**
* @brief Destructive in-place downscaling by a power of 2 factor.
* @param[in,out] pixels The buffer both to read from and write the result to.
* @param[in] inputWidth The width of the input image.
* @param[in] inputHeight The height of the input image.
+ * @param[in] inputStride The stride of the input image.
* @param[in] desiredWidth The width the client is requesting.
* @param[in] desiredHeight The height the client is requesting.
* @param[out] outWidth The resulting width after downscaling.
* @param[out] outHeight The resulting height after downscaling.
+ * @param[out] outStride The resulting stride after downscaling.
*/
-void DownscaleInPlacePow2RGB888( unsigned char * pixels,
- unsigned int inputWidth,
- unsigned int inputHeight,
- unsigned int desiredWidth,
- unsigned int desiredHeight,
- BoxDimensionTest dimensionTest,
- unsigned int& outWidth,
- unsigned int& outHeight );
+void DownscaleInPlacePow2RGB888(unsigned char* pixels,
+ unsigned int inputWidth,
+ unsigned int inputHeight,
+ unsigned int inputStride,
+ unsigned int desiredWidth,
+ unsigned int desiredHeight,
+ BoxDimensionTest dimensionTest,
+ unsigned int& outWidth,
+ unsigned int& outHeight,
+ unsigned int& outStride);
/**
* @copydoc DownscaleInPlacePow2RGB888
*/
-void DownscaleInPlacePow2RGBA8888( unsigned char * pixels,
- unsigned int inputWidth,
- unsigned int inputHeight,
- unsigned int desiredWidth,
- unsigned int desiredHeight,
- BoxDimensionTest dimensionTest,
- unsigned int& outWidth,
- unsigned int& outHeight );
+void DownscaleInPlacePow2RGBA8888(unsigned char* pixels,
+ unsigned int inputWidth,
+ unsigned int inputHeight,
+ unsigned int inputStride,
+ unsigned int desiredWidth,
+ unsigned int desiredHeight,
+ BoxDimensionTest dimensionTest,
+ unsigned int& outWidth,
+ unsigned int& outHeight,
+ unsigned int& outStride);
/**
* @copydoc DownscaleInPlacePow2RGB888
*
* For the 2-byte packed 16 bit format RGB565.
*/
-void DownscaleInPlacePow2RGB565( unsigned char * pixels,
- unsigned int inputWidth,
- unsigned int inputHeight,
- unsigned int desiredWidth,
- unsigned int desiredHeight,
- BoxDimensionTest dimensionTest,
- unsigned int& outWidth,
- unsigned int& outHeight );
+void DownscaleInPlacePow2RGB565(unsigned char* pixels,
+ unsigned int inputWidth,
+ unsigned int inputHeight,
+ unsigned int inputStride,
+ unsigned int desiredWidth,
+ unsigned int desiredHeight,
+ BoxDimensionTest dimensionTest,
+ unsigned int& outWidth,
+ unsigned int& outHeight,
+ unsigned int& outStride);
/**
* @copydoc DownscaleInPlacePow2RGB888
*
* For 2-byte formats such as lum8alpha8, but not packed 16 bit formats like RGB565.
*/
-void DownscaleInPlacePow2ComponentPair( unsigned char * pixels,
- unsigned int inputWidth,
- unsigned int inputHeight,
- unsigned int desiredWidth,
- unsigned int desiredHeight,
- BoxDimensionTest dimensionTest,
- unsigned int& outWidth,
- unsigned int& outHeight );
+void DownscaleInPlacePow2ComponentPair(unsigned char* pixels,
+ unsigned int inputWidth,
+ unsigned int inputHeight,
+ unsigned int inputStride,
+ unsigned int desiredWidth,
+ unsigned int desiredHeight,
+ BoxDimensionTest dimensionTest,
+ unsigned int& outWidth,
+ unsigned int& outHeight,
+ unsigned int& outStride);
/**
* @copydoc DownscaleInPlacePow2RGB888
*
* For single-byte formats such as lum8 or alpha8.
*/
-void DownscaleInPlacePow2SingleBytePerPixel( unsigned char * pixels,
- unsigned int inputWidth,
- unsigned int inputHeight,
- unsigned int desiredWidth,
- unsigned int desiredHeight,
- BoxDimensionTest dimensionTest,
- unsigned int& outWidth,
- unsigned int& outHeight );
+void DownscaleInPlacePow2SingleBytePerPixel(unsigned char* pixels,
+ unsigned int inputWidth,
+ unsigned int inputHeight,
+ unsigned int inputStride,
+ unsigned int desiredWidth,
+ unsigned int desiredHeight,
+ BoxDimensionTest dimensionTest,
+ unsigned int& outWidth,
+ unsigned int& outHeight,
+ unsigned int& outStride);
/**
* @brief Rescales an input image into the exact output dimensions passed-in.
* @note inPixels is allowed to alias outPixels if this is a downscaling,
* but not for upscaling.
*/
-void PointSample( const unsigned char * inPixels,
- unsigned int inputWidth,
- unsigned int inputHeight,
- Pixel::Format pixelFormat,
- unsigned char * outPixels,
- unsigned int desiredWidth,
- unsigned int desiredHeight );
+void PointSample(const unsigned char* inPixels,
+ unsigned int inputWidth,
+ unsigned int inputHeight,
+ unsigned int inputStride,
+ Pixel::Format pixelFormat,
+ unsigned char* outPixels,
+ unsigned int desiredWidth,
+ unsigned int desiredHeight);
/**
* @copydoc PointSample
*
* Specialised for 4-byte formats like RGBA8888 and BGRA8888.
*/
-void PointSample4BPP( const unsigned char * inPixels,
- unsigned int inputWidth,
- unsigned int inputHeight,
- unsigned char * outPixels,
- unsigned int desiredWidth,
- unsigned int desiredHeight );
+void PointSample4BPP(const unsigned char* inPixels,
+ unsigned int inputWidth,
+ unsigned int inputHeight,
+ unsigned int inputStride,
+ unsigned char* outPixels,
+ unsigned int desiredWidth,
+ unsigned int desiredHeight);
/**
* @copydoc PointSample
*
* Specialised for 3-byte formats like RGB888 and BGR888.
*/
-void PointSample3BPP( const unsigned char * inPixels,
- unsigned int inputWidth,
- unsigned int inputHeight,
- unsigned char * outPixels,
- unsigned int desiredWidth,
- unsigned int desiredHeight );
+void PointSample3BPP(const unsigned char* inPixels,
+ unsigned int inputWidth,
+ unsigned int inputHeight,
+ unsigned int inputStride,
+ unsigned char* outPixels,
+ unsigned int desiredWidth,
+ unsigned int desiredHeight);
/**
* @copydoc PointSample
*
* Specialised for 2-byte formats like LA88.
*/
-void PointSample2BPP( const unsigned char * inPixels,
- unsigned int inputWidth,
- unsigned int inputHeight,
- unsigned char * outPixels,
- unsigned int desiredWidth,
- unsigned int desiredHeight );
+void PointSample2BPP(const unsigned char* inPixels,
+ unsigned int inputWidth,
+ unsigned int inputHeight,
+ unsigned int inputStride,
+ unsigned char* outPixels,
+ unsigned int desiredWidth,
+ unsigned int desiredHeight);
/**
* @copydoc PointSample
*
* Specialised for 1-byte formats like L8 and A8.
*/
-void PointSample1BPP( const unsigned char * inPixels,
- unsigned int inputWidth,
- unsigned int inputHeight,
- unsigned char * outPixels,
- unsigned int desiredWidth,
- unsigned int desiredHeight );
+void PointSample1BPP(const unsigned char* inPixels,
+ unsigned int inputWidth,
+ unsigned int inputHeight,
+ unsigned int inputStride,
+ unsigned char* outPixels,
+ unsigned int desiredWidth,
+ unsigned int desiredHeight);
/**
* @brief Resample input image to output image using a bilinear filter.
* @pre inPixels must not alias outPixels. The input image should be a totally
* separate buffer from the input one.
*/
-void LinearSample( const unsigned char * __restrict__ inPixels,
- ImageDimensions inDimensions,
- Pixel::Format pixelFormat,
- unsigned char * __restrict__ outPixels,
- ImageDimensions outDimensions );
+void LinearSample(const unsigned char* __restrict__ inPixels,
+ ImageDimensions inDimensions,
+ unsigned int inStride,
+ Pixel::Format pixelFormat,
+ unsigned char* __restrict__ outPixels,
+ ImageDimensions outDimensions);
/**
* @copydoc LinearSample
*
* Specialised for one byte per pixel formats.
*/
-void LinearSample1BPP( const unsigned char * __restrict__ inPixels,
- ImageDimensions inputDimensions,
- unsigned char * __restrict__ outPixels,
- ImageDimensions desiredDimensions );
+void LinearSample1BPP(const unsigned char* __restrict__ inPixels,
+ ImageDimensions inputDimensions,
+ unsigned int inputStride,
+ unsigned char* __restrict__ outPixels,
+ ImageDimensions desiredDimensions);
/**
* @copydoc LinearSample
*
* Specialised for two byte per pixel formats.
*/
-void LinearSample2BPP( const unsigned char * __restrict__ inPixels,
- ImageDimensions inputDimensions,
- unsigned char * __restrict__ outPixels,
- ImageDimensions desiredDimensions );
+void LinearSample2BPP(const unsigned char* __restrict__ inPixels,
+ ImageDimensions inputDimensions,
+ unsigned int inputStride,
+ unsigned char* __restrict__ outPixels,
+ ImageDimensions desiredDimensions);
/**
* @copydoc LinearSample
*
* Specialised for RGB565 16 bit pixel format.
*/
-void LinearSampleRGB565( const unsigned char * __restrict__ inPixels,
- ImageDimensions inputDimensions,
- unsigned char * __restrict__ outPixels,
- ImageDimensions desiredDimensions );
+void LinearSampleRGB565(const unsigned char* __restrict__ inPixels,
+ ImageDimensions inputDimensions,
+ unsigned int inputStride,
+ unsigned char* __restrict__ outPixels,
+ ImageDimensions desiredDimensions);
/**
* @copydoc LinearSample
*
* Specialised for three byte per pixel formats like RGB888.
*/
-void LinearSample3BPP( const unsigned char * __restrict__ inPixels,
- ImageDimensions inputDimensions,
- unsigned char * __restrict__ outPixels,
- ImageDimensions desiredDimensions );
+void LinearSample3BPP(const unsigned char* __restrict__ inPixels,
+ ImageDimensions inputDimensions,
+ unsigned int inputStride,
+ unsigned char* __restrict__ outPixels,
+ ImageDimensions desiredDimensions);
/**
* @copydoc LinearSample
* Specialised for four byte per pixel formats like RGBA8888.
* @note, If used on RGBA8888, the A component will be blended independently.
*/
-void LinearSample4BPP( const unsigned char * __restrict__ inPixels,
- ImageDimensions inputDimensions,
- unsigned char * __restrict__ outPixels,
- ImageDimensions desiredDimensions );
+void LinearSample4BPP(const unsigned char* __restrict__ inPixels,
+ ImageDimensions inputDimensions,
+ unsigned int inputStride,
+ unsigned char* __restrict__ outPixels,
+ ImageDimensions desiredDimensions);
/**
* @brief Resamples the input image with the Lanczos algorithm.
*
* @param[in] inPixels Pointer to the input image buffer.
* @param[in] inputDimensions The input dimensions of the image.
+ * @param[in] inputStride The input stride of the image.
* @param[out] outPixels Pointer to the output image buffer.
* @param[in] desiredDimensions The output dimensions of the image.
*/
-void LanczosSample4BPP( const unsigned char * __restrict__ inPixels,
- ImageDimensions inputDimensions,
- unsigned char * __restrict__ outPixels,
- ImageDimensions desiredDimensions );
+void LanczosSample4BPP(const unsigned char* __restrict__ inPixels,
+ ImageDimensions inputDimensions,
+ unsigned int inputStride,
+ unsigned char* __restrict__ outPixels,
+ ImageDimensions desiredDimensions);
/**
* @brief Resamples the input image with the Lanczos algorithm.
*
* @param[in] inPixels Pointer to the input image buffer.
* @param[in] inputDimensions The input dimensions of the image.
+ * @param[in] inputStride The input stride of the image.
* @param[out] outPixels Pointer to the output image buffer.
* @param[in] desiredDimensions The output dimensions of the image.
*/
-void LanczosSample1BPP( const unsigned char * __restrict__ inPixels,
- ImageDimensions inputDimensions,
- unsigned char * __restrict__ outPixels,
- ImageDimensions desiredDimensions );
+void LanczosSample1BPP(const unsigned char* __restrict__ inPixels,
+ ImageDimensions inputDimensions,
+ unsigned int inputStride,
+ unsigned char* __restrict__ outPixels,
+ ImageDimensions desiredDimensions);
/**
* @brief Resamples the input image with the Lanczos algorithm.
*
* @param[in] inPixels Pointer to the input image buffer.
* @param[in] inputDimensions The input dimensions of the image.
+ * @param[in] inputStride The input stride 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 );
+void Resample(const unsigned char* __restrict__ inPixels,
+ ImageDimensions inputDimensions,
+ unsigned int inputStride,
+ unsigned char* __restrict__ outPixels,
+ ImageDimensions desiredDimensions,
+ Resampler::Filter filterType,
+ int numChannels,
+ bool hasAlpha);
+/**
+ * @brief Rotates the input image with an implementation of the 'Rotate by Shear' algorithm.
+ *
+ * @pre @p pixelsIn must not alias @p pixelsOut. The input image should be a totally
+ * separate buffer from the output buffer.
+ *
+ * @note This function allocates memory in @p pixelsOut which has to be released by calling @e free()
+ *
+ * @param[in] pixelsIn The input buffer.
+ * @param[in] widthIn The width of the input buffer.
+ * @param[in] heightIn The height of the input buffer.
+ * @param[in] strideIn The stride of the input buffer.
+ * @param[in] pixelSize The size of the pixel.
+ * @param[in] radians The rotation angle in radians.
+ * @param[out] pixelsOut The rotated output buffer.
+ * @param[out] widthOut The width of the output buffer.
+ * @param[out] heightOut The height of the output buffer.
+ */
+void RotateByShear(const uint8_t* const pixelsIn,
+ unsigned int widthIn,
+ unsigned int heightIn,
+ unsigned int strideIn,
+ unsigned int pixelSize,
+ float radians,
+ uint8_t*& pixelsOut,
+ unsigned int& widthOut,
+ unsigned int& heightOut);
+
+/**
+ * @brief Applies to the input image a horizontal shear transformation.
+ *
+ * @pre @p pixelsIn must not alias @p pixelsOut. The input image should be a totally
+ * separate buffer from the output buffer.
+ * @pre The maximun/minimum shear angle is +/-45 degrees (PI/4 around 0.79 radians).
+ *
+ * @note This function allocates memory in @p pixelsOut which has to be released by calling @e free()
+ *
+ * @param[in] pixelsIn The input buffer.
+ * @param[in] widthIn The width of the input buffer.
+ * @param[in] heightIn The height of the input buffer.
+ * @param[in] strideIn The stride of the input buffer.
+ * @param[in] pixelSize The size of the pixel.
+ * @param[in] radians The shear angle in radians.
+ * @param[out] pixelsOut The rotated output buffer.
+ * @param[out] widthOut The width of the output buffer.
+ * @param[out] heightOut The height of the output buffer.
+ */
+void HorizontalShear(const uint8_t* const pixelsIn,
+ unsigned int widthIn,
+ unsigned int heightIn,
+ unsigned int strideIn,
+ unsigned int pixelSize,
+ float radians,
+ uint8_t*& pixelsOut,
+ unsigned int& widthOut,
+ unsigned int& heightOut);
/**@}*/
* @param[in,out] pixels The array of pixels to work on.
* @param[i] width The number of pixels in the array passed-in.
*/
-void HalveScanlineInPlaceRGB888( unsigned char * pixels, unsigned int width );
+void HalveScanlineInPlaceRGB888(unsigned char* pixels, unsigned int width);
/**
* @copydoc HalveScanlineInPlaceRGB888
*/
-void HalveScanlineInPlaceRGBA8888( unsigned char * pixels, unsigned int width );
+void HalveScanlineInPlaceRGBA8888(unsigned char* pixels, unsigned int width);
/**
* @copydoc HalveScanlineInPlaceRGB888
*/
-void HalveScanlineInPlaceRGB565( unsigned char * pixels, unsigned int width );
+void HalveScanlineInPlaceRGB565(unsigned char* pixels, unsigned int width);
/**
* @copydoc HalveScanlineInPlaceRGB888
*/
-void HalveScanlineInPlace2Bytes( unsigned char * pixels, unsigned int width );
+void HalveScanlineInPlace2Bytes(unsigned char* pixels, unsigned int width);
/**
* @copydoc HalveScanlineInPlaceRGB888
*/
-void HalveScanlineInPlace1Byte( unsigned char * pixels, unsigned int width );
+void HalveScanlineInPlace1Byte(unsigned char* pixels, unsigned int width);
/**
* @brief Average pixels at corresponding offsets in two scanlines.
* @param[out] outputScanline Destination for the averaged pixels.
* @param[in] width The widths of all the scanlines passed-in.
*/
-void AverageScanlines1( const unsigned char * scanline1,
- const unsigned char * scanline2,
- unsigned char* outputScanline,
- /** Image width in pixels (1 byte == 1 pixel: e.g. lum8 or alpha8).*/
- unsigned int width );
+void AverageScanlines1(const unsigned char* scanline1,
+ const unsigned char* scanline2,
+ unsigned char* outputScanline,
+ /** Image width in pixels (1 byte == 1 pixel: e.g. lum8 or alpha8).*/
+ unsigned int width);
/**
* @copydoc AverageScanlines1
*/
-void AverageScanlines2( const unsigned char * scanline1,
- const unsigned char * scanline2,
- unsigned char* outputScanline,
- /** Image width in pixels (2 bytes == 1 pixel: e.g. lum8alpha8).*/
- unsigned int width );
+void AverageScanlines2(const unsigned char* scanline1,
+ const unsigned char* scanline2,
+ unsigned char* outputScanline,
+ /** Image width in pixels (2 bytes == 1 pixel: e.g. lum8alpha8).*/
+ unsigned int width);
/**
* @copydoc AverageScanlines1
*/
-void AverageScanlines3( const unsigned char * scanline1,
- const unsigned char * scanline2,
- unsigned char* outputScanline,
- /** Image width in pixels (3 bytes == 1 pixel: e.g. RGB888).*/
- unsigned int width );
+void AverageScanlines3(const unsigned char* scanline1,
+ const unsigned char* scanline2,
+ unsigned char* outputScanline,
+ /** Image width in pixels (3 bytes == 1 pixel: e.g. RGB888).*/
+ unsigned int width);
/**
* @copydoc AverageScanlines1
*/
-void AverageScanlinesRGBA8888( const unsigned char * scanline1,
- const unsigned char * scanline2,
- unsigned char * outputScanline,
- unsigned int width );
+void AverageScanlinesRGBA8888(const unsigned char* scanline1,
+ const unsigned char* scanline2,
+ unsigned char* outputScanline,
+ unsigned int width);
/**
* @copydoc AverageScanlines1
*/
-void AverageScanlinesRGB565( const unsigned char * scanline1,
- const unsigned char * scanline2,
- unsigned char* outputScanline,
- unsigned int width );
+void AverageScanlinesRGB565(const unsigned char* scanline1,
+ const unsigned char* scanline2,
+ unsigned char* outputScanline,
+ unsigned int width);
/**@}*/
/**
* @param[in] a First component to average.
* @param[in] b Second component to average.
**/
-inline unsigned int AverageComponent( unsigned int a, unsigned int b )
+inline unsigned int AverageComponent(unsigned int a, unsigned int b)
{
unsigned int avg = (a + b) >> 1u;
return avg;
* @param[in] a First pixel to average.
* @param[in] b Second pixel to average
**/
-inline uint32_t AveragePixelRGBA8888( uint32_t a, uint32_t b )
+inline uint32_t AveragePixelRGBA8888(uint32_t a, uint32_t b)
{
- const unsigned int avg =
- ((AverageComponent( (a & 0xff000000) >> 1u, (b & 0xff000000) >> 1u ) << 1u) & 0xff000000 ) +
- (AverageComponent( a & 0x00ff0000, b & 0x00ff0000 ) & 0x00ff0000 ) +
- (AverageComponent( a & 0x0000ff00, b & 0x0000ff00 ) & 0x0000ff00 ) +
- (AverageComponent( a & 0x000000ff, b & 0x000000ff ) );
- return avg;
- ///@ToDo: Optimise by trying return (((a ^ b) & 0xfefefefeUL) >> 1) + (a & b);
+ /**
+ * @code
+ * const unsigned int avg =
+ * (AverageComponent((a & 0xff000000) >> 1u, (b & 0xff000000) >> 1u) << 1u) & 0xff000000) +
+ * (AverageComponent(a & 0x00ff0000, b & 0x00ff0000) & 0x00ff0000) +
+ * (AverageComponent(a & 0x0000ff00, b & 0x0000ff00) & 0x0000ff00) +
+ * (AverageComponent(a & 0x000000ff, b & 0x000000ff);
+ * return avg;
+ * @endcode
+ */
+ return (((a ^ b) & 0xfefefefeu) >> 1) + (a & b);
///@ToDo: Optimise for ARM using the single ARMV6 instruction: UHADD8 R4, R0, R5. This is not Neon. It runs in the normal integer pipeline so there is no downside like a stall moving between integer and copro.
}
* @param b[in] Low 16 bits hold a color value as RGB565 to average with parameter a.
* @return The average color of the two RGB565 pixels passed in, in the low 16 bits of the returned value.
**/
-inline uint32_t AveragePixelRGB565( uint32_t a, uint32_t b )
+inline uint32_t AveragePixelRGB565(uint32_t a, uint32_t b)
{
- const unsigned int avg =
- (AverageComponent( a & 0xf800, b & 0xf800 ) & 0xf800 ) +
- (AverageComponent( a & 0x7e0, b & 0x7e0 ) & 0x7e0 ) +
- (AverageComponent( a & 0x1f, b & 0x1f ) );
- return avg;
+ /**
+ * @code
+ * const unsigned int avg =
+ * (AverageComponent(a & 0xf800, b & 0xf800) & 0xf800) +
+ * (AverageComponent(a & 0x7e0, b & 0x7e0) & 0x7e0) +
+ * (AverageComponent(a & 0x1f, b & 0x1f));
+ * return avg;
+ * @endcode
+ */
+ return (((a ^ b) & 0xf7deu) >> 1) + (a & b);
}
/** @return The weighted blend of two integers as a 16.16 fixed-point number, given a 0.16 fixed-point blending factor. */
-inline unsigned int WeightedBlendIntToFixed1616(unsigned int a, unsigned int b, unsigned int fractBlend )
+inline unsigned int WeightedBlendIntToFixed1616(unsigned int a, unsigned int b, unsigned int fractBlend)
{
- DALI_ASSERT_DEBUG( fractBlend <= 65535u && "Factor should be in 0.16 fixed-point." );
- const unsigned int weightedAFixed = a * (65535u - fractBlend);
- const unsigned int weightedBFixed = b * fractBlend;
- const unsigned blended = (weightedAFixed + weightedBFixed);
+ DALI_ASSERT_DEBUG(fractBlend <= 65535u && "Factor should be in 0.16 fixed-point.");
+ /**
+ * @code
+ * const unsigned int weightedAFixed = a * (65535u - fractBlend);
+ * const unsigned int weightedBFixed = b * fractBlend;
+ * const unsigned blended = (weightedAFixed + weightedBFixed);
+ * @endcode
+ */
+ const unsigned int blended = (a << 16) - a + (static_cast<int32_t>(b) - static_cast<int32_t>(a)) * fractBlend;
return blended;
}
/** @brief Blend two 16.16 inputs to give a 16.32 output. */
-inline uint64_t WeightedBlendFixed1616ToFixed1632(unsigned int a, unsigned int b, unsigned int fractBlend )
+inline uint64_t WeightedBlendFixed1616ToFixed1632(unsigned int a, unsigned int b, unsigned int fractBlend)
{
- DALI_ASSERT_DEBUG( fractBlend <= 65535u && "Factor should be in 0.16 fixed-point." );
- // Blend while promoting intermediates to 16.32 fixed point:
- const uint64_t weightedAFixed = uint64_t(a) * (65535u - fractBlend);
- const uint64_t weightedBFixed = uint64_t(b) * fractBlend;
- const uint64_t blended = (weightedAFixed + weightedBFixed);
+ DALI_ASSERT_DEBUG(fractBlend <= 65535u && "Factor should be in 0.16 fixed-point.");
+ /**
+ * @code
+ * // Blend while promoting intermediates to 16.32 fixed point:
+ * const uint64_t weightedAFixed = uint64_t(a) * (65535u - fractBlend);
+ * const uint64_t weightedBFixed = uint64_t(b) * fractBlend;
+ * const uint64_t blended = (weightedAFixed + weightedBFixed);
+ * @endcode
+ */
+ const uint64_t blended = (static_cast<uint64_t>(a) << 16) - a + (static_cast<int64_t>(b) - static_cast<int64_t>(a)) * fractBlend;
return blended;
}
/**
* @brief Blend 4 taps into one value using horizontal and vertical weights.
*/
-inline unsigned int BilinearFilter1Component(unsigned int tl, unsigned int tr, unsigned int bl, unsigned int br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
+inline unsigned int BilinearFilter1Component(unsigned int tl, unsigned int tr, unsigned int bl, unsigned int br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical)
{
- DALI_ASSERT_DEBUG( fractBlendHorizontal <= 65535u && "Factor should be in 0.16 fixed-point." );
- DALI_ASSERT_DEBUG( fractBlendVertical <= 65535u && "Factor should be in 0.16 fixed-point." );
-
- const unsigned int topBlend = WeightedBlendIntToFixed1616( tl, tr, fractBlendHorizontal );
- const unsigned int botBlend = WeightedBlendIntToFixed1616( bl, br, fractBlendHorizontal );
- const uint64_t blended2x2 = WeightedBlendFixed1616ToFixed1632( topBlend, botBlend, fractBlendVertical );
- const unsigned int rounded = (blended2x2 + (1u << 31u) ) >> 32u;
+ DALI_ASSERT_DEBUG(fractBlendHorizontal <= 65535u && "Factor should be in 0.16 fixed-point.");
+ DALI_ASSERT_DEBUG(fractBlendVertical <= 65535u && "Factor should be in 0.16 fixed-point.");
+
+ /**
+ * @code
+ * const unsigned int topBlend = WeightedBlendIntToFixed1616(tl, tr, fractBlendHorizontal);
+ * const unsigned int botBlend = WeightedBlendIntToFixed1616(bl, br, fractBlendHorizontal);
+ * const uint64_t blended2x2 = WeightedBlendFixed1616ToFixed1632(topBlend, botBlend, fractBlendVertical);
+ * const unsigned int rounded = (blended2x2 + (1u << 31u)) >> 32u;
+ * @endcode
+ */
+
+ /**
+ * Hard-coding optimize!
+ *
+ * Let p = 65536, s.t we can optimze it as << 16.
+ * Let x = fractBlendHorizontal, y = fractBlendVertical.
+ * topBlend = (tl*p - tl - tl*x + tr*x)
+ * botBlend = (bl*p - bl - bl*x + br*x)
+ * blended2x2 = topBlend*p - topBlend - topBlend*y + botBlend*y
+ *
+ * And now we can split all values.
+ * tl*p*p - tl*p - tl*x*p + tr*x*p - tl*p + tl + tl*x - tr*x - tl*y*p + tl*y + tl*x*y - tr*x*y + bl*y*p - bl*y - bl*x*y + br*x*y;
+ * --> (collect by p, x, and y)
+ * (tl)*p*p + (-2tl + (-tl + tr)*x + (-tl+bl)*y)*p + tl + (tl - tr)*x + (tl - bl)*y + (tl - tr - bl + br)*x*y
+ *
+ * A = (tl - tr) * x;
+ * B = (tl - bl) * y;
+ * C = (tl - tr - bl + br) * x * y;
+ * D = (2*tl + A + B)
+ * -->
+ * (tl << 32) - (D << 16) + tl + A + B + C
+ *
+ * Becareful of overflow and negative value.
+ */
+ const int32_t A = (static_cast<int32_t>(tl) - static_cast<int32_t>(tr)) * static_cast<int32_t>(fractBlendHorizontal);
+ const int32_t B = (static_cast<int32_t>(tl) - static_cast<int32_t>(bl)) * static_cast<int32_t>(fractBlendVertical);
+ const int64_t C = (static_cast<int64_t>(tl) - static_cast<int64_t>(tr) - static_cast<int64_t>(bl) + static_cast<int64_t>(br)) * static_cast<int64_t>(fractBlendHorizontal) * static_cast<int64_t>(fractBlendVertical);
+ const int64_t D = ((static_cast<int64_t>(tl) << 1) + A + B);
+
+ const uint64_t blended2x2 = (static_cast<int64_t>(tl) << 32u) - (D << 16u) + tl + A + B + C;
+ const unsigned int rounded = (blended2x2 + (1u << 31u)) >> 32u;
return rounded;
}
+/**
+ * @brief Fast multiply & divide by 255. It wiil be useful when we applying alpha value in color
+ *
+ * @param x The value between [0..255]
+ * @param y The value between [0..255]
+ * @return (x*y)/255
+ */
+inline uint8_t MultiplyAndNormalizeColor(const uint8_t& x, const uint8_t& y) noexcept
+{
+ const uint32_t xy = static_cast<const uint32_t>(x) * y;
+ return ((xy << 15) + (xy << 7) + xy) >> 23;
+}
+
/**@}*/
} /* namespace Platform */
} /* namespace Internal */
} /* namespace Dali */
-#endif /* DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H_ */
+#endif /* DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H */