From 48c38e83680b54a7cb719f6662e56a7cdc140335 Mon Sep 17 00:00:00 2001 From: Victor Cebollada Date: Mon, 17 Sep 2018 10:53:24 +0100 Subject: [PATCH] PixelBuffer::Rotate() amendments. * The Rotate() method returns true if success. * Checks memory allocations to avoid issues with static code analyzers. * Some amendments in doxygen doc. Change-Id: I4b45b29d15ad0f6d05ff5f912e19c49b836300a3 Signed-off-by: Victor Cebollada --- dali/devel-api/adaptor-framework/pixel-buffer.cpp | 4 +- dali/devel-api/adaptor-framework/pixel-buffer.h | 6 +- dali/internal/imaging/common/image-operations.cpp | 164 +++++++++++++++------ dali/internal/imaging/common/image-operations.h | 5 + dali/internal/imaging/common/pixel-buffer-impl.cpp | 29 ++-- dali/internal/imaging/common/pixel-buffer-impl.h | 2 +- 6 files changed, 150 insertions(+), 60 deletions(-) diff --git a/dali/devel-api/adaptor-framework/pixel-buffer.cpp b/dali/devel-api/adaptor-framework/pixel-buffer.cpp index b041c96..f8d12b2 100644 --- a/dali/devel-api/adaptor-framework/pixel-buffer.cpp +++ b/dali/devel-api/adaptor-framework/pixel-buffer.cpp @@ -126,9 +126,9 @@ bool PixelBuffer::GetMetadata( Property::Map& metadata ) const return GetImplementation(*this).GetMetadata(metadata); } -void PixelBuffer::Rotate( Degree angle ) +bool PixelBuffer::Rotate( Degree angle ) { - GetImplementation(*this).Rotate( angle ); + return GetImplementation(*this).Rotate( angle ); } } // namespace Devel diff --git a/dali/devel-api/adaptor-framework/pixel-buffer.h b/dali/devel-api/adaptor-framework/pixel-buffer.h index 21a2c91..a63a623 100755 --- a/dali/devel-api/adaptor-framework/pixel-buffer.h +++ b/dali/devel-api/adaptor-framework/pixel-buffer.h @@ -221,13 +221,15 @@ public: /** * @brief Rotates the pixel buffer by the given angle. * - * @note Operation valid for pixel formats: A8, L8, LA88, RGB888, RGB8888, BGR8888, RGBA8888 and BGRA8888. Does nothing otherwise. + * @note Operation valid for pixel formats: A8, L8, LA88, RGB888, RGB8888, BGR8888, RGBA8888 and BGRA8888. Fails otherwise. * @note The operation does nothing for angles equivalent to 0 degrees: -360, 360, 720, etc. * @note If the pixel buffer does rotate, all the pointers to the internal pixel buffer retrieved by the method GetPixelBuffer() become invalid. * * @param[in] angle The angle in degrees. + * + * @return @e false if the rotation fails (invalid pixel format or memory issues). */ - void Rotate( Degree angle ); + bool Rotate( Degree angle ); public: diff --git a/dali/internal/imaging/common/image-operations.cpp b/dali/internal/imaging/common/image-operations.cpp index d4716b1..662d775 100755 --- a/dali/internal/imaging/common/image-operations.cpp +++ b/dali/internal/imaging/common/image-operations.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -502,6 +503,7 @@ ImageDimensions CalculateDesiredDimensions( unsigned int bitmapWidth, unsigned i * * @note It allocates memory for the returned @p pixelsOut buffer. * @note Code got from https://www.codeproject.com/Articles/202/High-quality-image-rotation-rotate-by-shear by Eran Yariv. + * @note It may fail if malloc() fails to allocate memory. * * @param[in] pixelsIn The input buffer. * @param[in] widthIn The width of the input buffer. @@ -510,8 +512,10 @@ ImageDimensions CalculateDesiredDimensions( unsigned int bitmapWidth, unsigned i * @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. + * + * @return Whether the rotation succeded. */ -void Rotate90( const uint8_t* const pixelsIn, +bool Rotate90( const uint8_t* const pixelsIn, unsigned int widthIn, unsigned int heightIn, unsigned int pixelSize, @@ -525,6 +529,14 @@ void Rotate90( const uint8_t* const pixelsIn, // Allocate memory for the rotated buffer. pixelsOut = static_cast( malloc ( widthOut * heightOut * pixelSize ) ); + if( nullptr == pixelsOut ) + { + widthOut = 0u; + heightOut = 0u; + + // Return if the memory allocations fails. + return false; + } // Rotate the buffer. for( unsigned int y = 0u; y < heightIn; ++y ) @@ -543,6 +555,8 @@ void Rotate90( const uint8_t* const pixelsIn, } } } + + return true; } /** @@ -550,14 +564,17 @@ void Rotate90( const uint8_t* const pixelsIn, * * @note It allocates memory for the returned @p pixelsOut buffer. * @note Code got from https://www.codeproject.com/Articles/202/High-quality-image-rotation-rotate-by-shear by Eran Yariv. + * @note It may fail if malloc() fails to allocate memory. * * @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] pixelSize The size of the pixel. * @param[out] pixelsOut The rotated output buffer. + * + * @return Whether the rotation succeded. */ -void Rotate180( const uint8_t* const pixelsIn, +bool Rotate180( const uint8_t* const pixelsIn, unsigned int widthIn, unsigned int heightIn, unsigned int pixelSize, @@ -565,6 +582,11 @@ void Rotate180( const uint8_t* const pixelsIn, { // Allocate memory for the rotated buffer. pixelsOut = static_cast( malloc ( widthIn * heightIn * pixelSize ) ); + if( nullptr == pixelsOut ) + { + // Return if the memory allocations fails. + return false; + } // Rotate the buffer. for( unsigned int y = 0u; y < heightIn; ++y ) @@ -583,6 +605,8 @@ void Rotate180( const uint8_t* const pixelsIn, } } } + + return true; } /** @@ -590,6 +614,7 @@ void Rotate180( const uint8_t* const pixelsIn, * * @note It allocates memory for the returned @p pixelsOut buffer. * @note Code got from https://www.codeproject.com/Articles/202/High-quality-image-rotation-rotate-by-shear by Eran Yariv. + * @note It may fail if malloc() fails to allocate memory. * * @param[in] pixelsIn The input buffer. * @param[in] widthIn The width of the input buffer. @@ -598,8 +623,10 @@ void Rotate180( const uint8_t* const pixelsIn, * @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. + * + * @return Whether the rotation succeded. */ -void Rotate270( const uint8_t* const pixelsIn, +bool Rotate270( const uint8_t* const pixelsIn, unsigned int widthIn, unsigned int heightIn, unsigned int pixelSize, @@ -613,6 +640,14 @@ void Rotate270( const uint8_t* const pixelsIn, // Allocate memory for the rotated buffer. pixelsOut = static_cast( malloc ( widthOut * heightOut * pixelSize ) ); + if( nullptr == pixelsOut ) + { + widthOut = 0u; + heightOut = 0u; + + // Return if the memory allocations fails. + return false; + } // Rotate the buffer. for( unsigned int y = 0u; y < heightIn; ++y ) @@ -631,6 +666,8 @@ void Rotate270( const uint8_t* const pixelsIn, } } } + + return true; } /** @@ -2127,15 +2164,21 @@ void RotateByShear( const uint8_t* const pixelsIn, // Rotate image by 90 degrees into temporary image, // so it requires only an extra rotation angle // of -45.0 .. +45.0 to complete rotation. - Rotate90( pixelsIn, - widthIn, - heightIn, - pixelSize, - pixelsOut, - widthOut, - heightOut ); + fastRotationPerformed = Rotate90( pixelsIn, + widthIn, + heightIn, + pixelSize, + pixelsOut, + widthOut, + heightOut ); + + if( !fastRotationPerformed ) + { + // The fast rotation failed. + return; + } + radians -= Math::PI_2; - fastRotationPerformed = true; } else if( ( radians > RAD_135 ) && ( radians <= RAD_225 ) ) { @@ -2144,15 +2187,21 @@ void RotateByShear( const uint8_t* const pixelsIn, // so it requires only an extra rotation angle // of -45.0 .. +45.0 to complete rotation. - Rotate180( pixelsIn, - widthIn, - heightIn, - pixelSize, - pixelsOut ); + fastRotationPerformed = Rotate180( pixelsIn, + widthIn, + heightIn, + pixelSize, + pixelsOut ); + + if( !fastRotationPerformed ) + { + // The fast rotation failed. + return; + } + radians -= Math::PI; widthOut = widthIn; heightOut = heightIn; - fastRotationPerformed = true; } else if( ( radians > RAD_225 ) && ( radians <= RAD_315 ) ) { @@ -2161,15 +2210,21 @@ void RotateByShear( const uint8_t* const pixelsIn, // so it requires only an extra rotation angle // of -45.0 .. +45.0 to complete rotation. - Rotate270( pixelsIn, - widthIn, - heightIn, - pixelSize, - pixelsOut, - widthOut, - heightOut ); + fastRotationPerformed = Rotate270( pixelsIn, + widthIn, + heightIn, + pixelSize, + pixelsOut, + widthOut, + heightOut ); + + if( !fastRotationPerformed ) + { + // The fast rotation failed. + return; + } + radians -= RAD_270; - fastRotationPerformed = true; } if( fabs( radians ) < Dali::Math::MACHINE_EPSILON_10 ) @@ -2181,8 +2236,8 @@ void RotateByShear( const uint8_t* const pixelsIn, return; } - const uint8_t* const firstHorizontalSkwePixelsIn = fastRotationPerformed ? pixelsOut : pixelsIn; - uint8_t* tmpFirstHorizontalSkwePixelsIn = fastRotationPerformed ? pixelsOut : nullptr; // keep the pointer to free the memory. + const uint8_t* const firstHorizontalSkewPixelsIn = fastRotationPerformed ? pixelsOut : pixelsIn; + std::unique_ptr tmpPixelsInPtr( ( fastRotationPerformed ? pixelsOut : nullptr ), free ); // Reset the input/output widthIn = widthOut; @@ -2205,18 +2260,26 @@ void RotateByShear( const uint8_t* const pixelsIn, // Allocate the buffer for the 1st shear pixelsOut = static_cast( malloc( widthOut * heightOut * pixelSize ) ); + if( nullptr == pixelsOut ) + { + widthOut = 0u; + heightOut = 0u; + + // The deleter of the tmpPixelsInPtr unique pointer is called freeing the memory allocated by the 'Fast rotations'. + // Nothing else to do if the memory allocation fails. + return; + } + for( unsigned int y = 0u; y < heightOut; ++y ) { const float shear = angleTangent * ( ( angleTangent >= 0.f ) ? ( 0.5f + static_cast( y ) ) : ( 0.5f + static_cast( y ) - static_cast( heightOut ) ) ); const int intShear = static_cast( floor( shear ) ); - HorizontalSkew( firstHorizontalSkwePixelsIn, widthIn, pixelSize, pixelsOut, widthOut, y, intShear, shear - static_cast( intShear ) ); + HorizontalSkew( firstHorizontalSkewPixelsIn, widthIn, pixelSize, pixelsOut, widthOut, y, intShear, shear - static_cast( intShear ) ); } - // Free the memory allocated by the 'Fast Rotations'. - free( tmpFirstHorizontalSkwePixelsIn ); - - uint8_t* tmpPixelsIn = pixelsOut; + // Reset the 'pixel in' pointer with the output of the 'First Horizontal Skew' and free the memory allocated by the 'Fast Rotations'. + tmpPixelsInPtr.reset( pixelsOut ); unsigned int tmpWidthIn = widthOut; unsigned int tmpHeightIn = heightOut; @@ -2233,6 +2296,16 @@ void RotateByShear( const uint8_t* const pixelsIn, // Allocate the buffer for the 2nd shear pixelsOut = static_cast( malloc( widthOut * heightOut * pixelSize ) ); + if( nullptr == pixelsOut ) + { + widthOut = 0u; + heightOut = 0u; + + // The deleter of the tmpPixelsInPtr unique pointer is called freeing the memory allocated by the 'First Horizontal Skew'. + // Nothing else to do if the memory allocation fails. + return; + } + // Variable skew offset float offset = angleSinus * ( ( angleSinus > 0.f ) ? static_cast( widthIn - 1u ) : -( static_cast( widthIn ) - static_cast( widthOut ) ) ); @@ -2240,14 +2313,11 @@ void RotateByShear( const uint8_t* const pixelsIn, for( column = 0u; column < widthOut; ++column, offset -= angleSinus ) { const int shear = static_cast( floor( offset ) ); - VerticalSkew( tmpPixelsIn, tmpWidthIn, tmpHeightIn, pixelSize, pixelsOut, widthOut, heightOut, column, shear, offset - static_cast( shear ) ); + VerticalSkew( tmpPixelsInPtr.get(), tmpWidthIn, tmpHeightIn, pixelSize, pixelsOut, widthOut, heightOut, column, shear, offset - static_cast( shear ) ); } - - // Free the memory allocated by the 'First Horizontal Skew'. - free( tmpPixelsIn ); - + // Reset the 'pixel in' pointer with the output of the 'Vertical Skew' and free the memory allocated by the 'First Horizontal Skew'. // Reset the input/output - tmpPixelsIn = pixelsOut; + tmpPixelsInPtr.reset( pixelsOut ); tmpWidthIn = widthOut; tmpHeightIn = heightOut; pixelsOut = nullptr; @@ -2262,18 +2332,26 @@ void RotateByShear( const uint8_t* const pixelsIn, // Allocate the buffer for the 3rd shear pixelsOut = static_cast( malloc( widthOut * heightOut * pixelSize ) ); + if( nullptr == pixelsOut ) + { + widthOut = 0u; + heightOut = 0u; + + // The deleter of the tmpPixelsInPtr unique pointer is called freeing the memory allocated by the 'Vertical Skew'. + // Nothing else to do if the memory allocation fails. + return; + } + offset = ( angleSinus >= 0.f ) ? -angleSinus * angleTangent * static_cast( widthIn - 1u ) : angleTangent * ( static_cast( widthIn - 1u ) * -angleSinus + ( 1.f - static_cast( heightOut ) ) ); for( unsigned int y = 0u; y < heightOut; ++y, offset += angleTangent ) { const int shear = static_cast( floor( offset ) ); - HorizontalSkew( tmpPixelsIn, tmpWidthIn, pixelSize, pixelsOut, widthOut, y, shear, offset - static_cast( shear ) ); + HorizontalSkew( tmpPixelsInPtr.get(), tmpWidthIn, pixelSize, pixelsOut, widthOut, y, shear, offset - static_cast( shear ) ); } - // Free the memory allocated by the 'First Horizontal Skew'. - free( tmpPixelsIn ); - - // @note Allocated memory by the last 'Horizontal Skew' has to be freed by the called to this function. + // The deleter of the tmpPixelsInPtr unique pointer is called freeing the memory allocated by the 'Vertical Skew'. + // @note Allocated memory by the last 'Horizontal Skew' has to be freed by the caller to this function. } } /* namespace Platform */ diff --git a/dali/internal/imaging/common/image-operations.h b/dali/internal/imaging/common/image-operations.h index 7226c16..c78f8fe 100644 --- a/dali/internal/imaging/common/image-operations.h +++ b/dali/internal/imaging/common/image-operations.h @@ -384,6 +384,11 @@ void Resample( const unsigned char * __restrict__ inPixels, /** * @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. diff --git a/dali/internal/imaging/common/pixel-buffer-impl.cpp b/dali/internal/imaging/common/pixel-buffer-impl.cpp index cef8aa3..3bcb4ef 100644 --- a/dali/internal/imaging/common/pixel-buffer-impl.cpp +++ b/dali/internal/imaging/common/pixel-buffer-impl.cpp @@ -215,7 +215,7 @@ void PixelBuffer::AllocateFixedSize( uint32_t size ) mBufferSize = size; } -void PixelBuffer::Rotate( Degree angle ) +bool PixelBuffer::Rotate( Degree angle ) { // Check first if Rotate() can perform the operation in the current pixel buffer. @@ -246,7 +246,7 @@ void PixelBuffer::Rotate( Degree angle ) { // Can't rotate the pixel buffer with the current pixel format. DALI_LOG_ERROR( "Can't rotate the pixel buffer with the current pixel format\n" ); - return; + return false; } float radians = Radian( angle ).radian; @@ -258,7 +258,7 @@ void PixelBuffer::Rotate( Degree angle ) if( radians < Dali::Math::MACHINE_EPSILON_10 ) { // Nothing to do if the angle is zero. - return; + return true; } const unsigned int pixelSize = Pixel::GetBytesPerPixel( mPixelFormat ); @@ -273,13 +273,21 @@ void PixelBuffer::Rotate( Degree angle ) mWidth, mHeight ); - // Release the memory of the current pixel buffer. - ReleaseBuffer(); + // Check whether the rotation succedded and set the new pixel buffer data. + const bool success = nullptr != pixelsOut; - // Set the new pixel buffer. - mBuffer = pixelsOut; - pixelsOut = nullptr; - mBufferSize = mWidth * mHeight * pixelSize; + if( success ) + { + // Release the memory of the current pixel buffer. + ReleaseBuffer(); + + // Set the new pixel buffer. + mBuffer = pixelsOut; + pixelsOut = nullptr; + mBufferSize = mWidth * mHeight * pixelSize; + } + + return success; } void PixelBuffer::ScaleAndCrop( float scaleFactor, ImageDimensions cropDimensions ) @@ -455,9 +463,6 @@ void PixelBuffer::MultiplyColorByAlpha() } } - - - }// namespace Adaptor }// namespace Internal }// namespace Dali diff --git a/dali/internal/imaging/common/pixel-buffer-impl.h b/dali/internal/imaging/common/pixel-buffer-impl.h index a6a3b75..b0fe5ce 100644 --- a/dali/internal/imaging/common/pixel-buffer-impl.h +++ b/dali/internal/imaging/common/pixel-buffer-impl.h @@ -215,7 +215,7 @@ public: /** * @copydoc Devel::PixelBuffer::Rotate() */ - void Rotate( Degree angle ); + bool Rotate( Degree angle ); private: /* -- 2.7.4