diff --git a/Src/BMP.cpp b/Src/BMP.cpp index a5ed26e..07a1e1b 100644 --- a/Src/BMP.cpp +++ b/Src/BMP.cpp @@ -293,6 +293,93 @@ namespace Leonetienne::BmpPP { return bmp; } + BMP BMP::Rotate90degClockwise() const { + CHECK_IF_INITIALIZED + + // Create a new image matching this ones metadata, but with width and height flipped + BMP bmp(Eule::Vector2i(size.y, size.x), colormode); + + // Now copy over the pixels, rotating it by 90 deg + const std::size_t numChannels = GetNumChannels(); + for (std::size_t y = 0; y < size.y; y++) { + for (std::size_t x = 0; x < size.x; x++) { + const std::size_t pixelIndex = (y * size.x + x) * numChannels; + const std::size_t rotatedPixelIndex = (x * size.y + (size.y - 1 - y)) * numChannels; + + // Copy over the whole pixel + std::copy( + pixelBuffer.cbegin() + pixelIndex, + pixelBuffer.cbegin() + pixelIndex + numChannels, + bmp.pixelBuffer.begin() + rotatedPixelIndex + ); + } + } + + // return it + return bmp; + } + + BMP BMP::Rotate90degCounterclockwise() const { + CHECK_IF_INITIALIZED + + // Create a new image matching this ones metadata, but with width and height flipped + BMP bmp(Eule::Vector2i(size.y, size.x), colormode); + + // Now copy over the pixels, rotating it by -90 deg + const std::size_t numChannels = GetNumChannels(); + for (std::size_t y = 0; y < size.y; y++) { + for (std::size_t x = 0; x < size.x; x++) { + const std::size_t pixelIndex = (y * size.x + x) * numChannels; + const std::size_t rotatedPixelIndex = ((size.x - 1 - x) * size.y + y) * numChannels; + + // Copy over the whole pixel + std::copy( + pixelBuffer.cbegin() + pixelIndex, + pixelBuffer.cbegin() + pixelIndex + numChannels, + bmp.pixelBuffer.begin() + rotatedPixelIndex + ); + } + } + + // return it + return bmp; + } + + BMP BMP::Rotate180deg() const { + CHECK_IF_INITIALIZED + + // Basically, what we're doing here, is mirroring + // the image horizontally and vertically at the same time + + // Create a new image matching this's metadata + BMP bmp(size, colormode); + + // Now copy over the pixels, mirroring it horizontally and vertically + const std::size_t numChannels = GetNumChannels(); + const std::size_t rowLength = size.x * numChannels; + + for (std::size_t y = 0; y < size.y; y++) { + const std::size_t rowIndex = y * rowLength; + const std::size_t flippedRowIndex = (size.y - 1 - y) * rowLength; + + for (std::size_t x = 0; x < size.x; x++) { + const std::size_t pixelIndex = rowIndex + x * numChannels; + const std::size_t rotatedPixelIndex = flippedRowIndex + (size.x - 1 - x) * numChannels; + + // Copy over the whole pixel + std::copy( + pixelBuffer.cbegin() + pixelIndex, + pixelBuffer.cbegin() + pixelIndex + numChannels, + bmp.pixelBuffer.begin() + rotatedPixelIndex + ); + } + + } + + // return it + return bmp; + } + } #undef CHECK_IF_INITIALIZED diff --git a/Test/CMakeLists.txt b/Test/CMakeLists.txt index 9c84f6e..ace6929 100644 --- a/Test/CMakeLists.txt +++ b/Test/CMakeLists.txt @@ -28,6 +28,7 @@ add_executable(Test MirrorHorizontally.cpp MirrorVertically.cpp SwapChannels.cpp + Rotate.cpp ) # Move test images to build dir diff --git a/Test/Rotate.cpp b/Test/Rotate.cpp new file mode 100644 index 0000000..1270172 --- /dev/null +++ b/Test/Rotate.cpp @@ -0,0 +1,54 @@ +#include +#include +#include "Catch2.h" + +using namespace Leonetienne::BmpPP; +using namespace Eule; + +// Tests that rotating works +TEST_CASE(__FILE__"/Mirroring produces the correct results", "[Rotate]") +{ + SECTION("90deg clockwise") { + // Read an image + BMP bmp("base_mateya.bmp"); + + // Rotate it + bmp = bmp.Rotate90degClockwise(); + + // Read reference image + const BMP reference("base_mateya_rot_90deg.bmp"); + + // Assert that they are equal + REQUIRE(bmp == reference); + } + + SECTION("90deg counterclockwise") { + // Read an image + BMP bmp("base_mateya.bmp"); + + // Rotate it + bmp = bmp.Rotate90degCounterclockwise(); + + // Read reference image + const BMP reference("base_mateya_rot_270deg.bmp"); + + // Assert that they are equal + REQUIRE(bmp == reference); + } + + SECTION("180deg") { + // Read an image + BMP bmp("base_mateya.bmp"); + + // Rotate it + bmp = bmp.Rotate180deg(); + + // Read reference image + const BMP reference("base_mateya_rot_180deg.bmp"); + + // Assert that they are equal + REQUIRE(bmp == reference); + } + + return; +} diff --git a/Test/TestAssets/base_mateya.bmp b/Test/TestAssets/base_mateya.bmp new file mode 100644 index 0000000..84964ad Binary files /dev/null and b/Test/TestAssets/base_mateya.bmp differ diff --git a/Test/TestAssets/base_mateya_rot_180deg.bmp b/Test/TestAssets/base_mateya_rot_180deg.bmp new file mode 100644 index 0000000..fcca1c8 Binary files /dev/null and b/Test/TestAssets/base_mateya_rot_180deg.bmp differ diff --git a/Test/TestAssets/base_mateya_rot_270deg.bmp b/Test/TestAssets/base_mateya_rot_270deg.bmp new file mode 100644 index 0000000..3e52a2e Binary files /dev/null and b/Test/TestAssets/base_mateya_rot_270deg.bmp differ diff --git a/Test/TestAssets/base_mateya_rot_90deg.bmp b/Test/TestAssets/base_mateya_rot_90deg.bmp new file mode 100644 index 0000000..b2f1f30 Binary files /dev/null and b/Test/TestAssets/base_mateya_rot_90deg.bmp differ