diff --git a/README.md b/README.md index 5a2d5db..64bee5c 100644 --- a/README.md +++ b/README.md @@ -236,6 +236,57 @@ int main(void) { ![modified-penguin](images/modified-penguin.bmp) +

+Rotate, Flip The Penguin +
+ +```cpp +#include "BitmapPlusPlus.hpp" +#include + +int main(void) { + try { + bmp::Bitmap image; + + // Load the original bitmap + image.load(std::filesystem::path(ROOT_DIR) / "images" / "penguin.bmp"); + + // Test vertical flip + bmp::Bitmap flipped_v = image.flip_v(); + flipped_v.save(std::filesystem::path(ROOT_DIR) / "images" / "rotated" / "penguin_flipped_v.bmp"); + std::cout << "Vertical flip saved as penguin_flipped_v.bmp" << std::endl; + + // Test horizontal flip + bmp::Bitmap flipped_h = image.flip_h(); + flipped_h.save(std::filesystem::path(ROOT_DIR) / "images" / "rotated" / "penguin_flipped_h.bmp"); + std::cout << "Horizontal flip saved as penguin_flipped_h.bmp" << std::endl; + + // Test rotate 90 degrees to the right + bmp::Bitmap rotated_right = image.rotate_90_right(); + rotated_right.save(std::filesystem::path(ROOT_DIR) / "images" / "rotated" / "penguin_rotated_right.bmp"); + std::cout << "Rotated 90 degrees right saved as penguin_rotated_right.bmp" << std::endl; + + // Test rotate 90 degrees to the left + bmp::Bitmap rotated_left = image.rotate_90_left(); + rotated_left.save(std::filesystem::path(ROOT_DIR) / "images" / "rotated" / "penguin_rotated_left.bmp"); + std::cout << "Rotated 90 degrees left saved as penguin_rotated_left.bmp" << std::endl; + + return EXIT_SUCCESS; + } + catch (const bmp::Exception& e) { + std::cerr << "Error: " << e.what() << std::endl; + return EXIT_FAILURE; + } +} + +``` +![penguin](images/penguin.bmp) +![penguin_flipped_v](images/rotated/penguin_flipped_v.bmp) +![penguin_flipped_h](images/rotated/penguin_flipped_h.bmp) +![penguin_rotated_right](images/rotated/penguin_rotated_right.bmp) +![penguin_rotated_left](images/rotated/penguin_rotated_left.bmp) + +

Chess Board diff --git a/examples/rotation.cpp b/examples/rotation.cpp new file mode 100644 index 0000000..33f30bf --- /dev/null +++ b/examples/rotation.cpp @@ -0,0 +1,38 @@ +#include "BitmapPlusPlus.hpp" +#include + +int main(void) { + try { + bmp::Bitmap image; + + // Load the original bitmap + image.load(std::filesystem::path(ROOT_DIR) / "images" / "penguin.bmp"); + + // Test vertical flip + bmp::Bitmap flipped_v = image.flip_v(); + flipped_v.save(std::filesystem::path(ROOT_DIR) / "images" / "rotated" / "penguin_flipped_v.bmp"); + std::cout << "Vertical flip saved as penguin_flipped_v.bmp" << std::endl; + + // Test horizontal flip + bmp::Bitmap flipped_h = image.flip_h(); + flipped_h.save(std::filesystem::path(ROOT_DIR) / "images" / "rotated" / "penguin_flipped_h.bmp"); + std::cout << "Horizontal flip saved as penguin_flipped_h.bmp" << std::endl; + + // Test rotate 90 degrees to the right + bmp::Bitmap rotated_right = image.rotate_90_right(); + rotated_right.save(std::filesystem::path(ROOT_DIR) / "images" / "rotated" / "penguin_rotated_right.bmp"); + std::cout << "Rotated 90 degrees right saved as penguin_rotated_right.bmp" << std::endl; + + // Test rotate 90 degrees to the left + bmp::Bitmap rotated_left = image.rotate_90_left(); + rotated_left.save(std::filesystem::path(ROOT_DIR) / "images" / "rotated" / "penguin_rotated_left.bmp"); + std::cout << "Rotated 90 degrees left saved as penguin_rotated_left.bmp" << std::endl; + + return EXIT_SUCCESS; + } + catch (const bmp::Exception& e) { + std::cerr << "Error: " << e.what() << std::endl; + return EXIT_FAILURE; + } +} + diff --git a/images/rotated/penguin_flipped_h.bmp b/images/rotated/penguin_flipped_h.bmp new file mode 100644 index 0000000..90bbf7b Binary files /dev/null and b/images/rotated/penguin_flipped_h.bmp differ diff --git a/images/rotated/penguin_flipped_v.bmp b/images/rotated/penguin_flipped_v.bmp new file mode 100644 index 0000000..bf6a34d Binary files /dev/null and b/images/rotated/penguin_flipped_v.bmp differ diff --git a/images/rotated/penguin_rotated_left.bmp b/images/rotated/penguin_rotated_left.bmp new file mode 100644 index 0000000..ebecc75 Binary files /dev/null and b/images/rotated/penguin_rotated_left.bmp differ diff --git a/images/rotated/penguin_rotated_right.bmp b/images/rotated/penguin_rotated_right.bmp new file mode 100644 index 0000000..41cdf87 Binary files /dev/null and b/images/rotated/penguin_rotated_right.bmp differ diff --git a/lib/include/BitmapPlusPlus.hpp b/lib/include/BitmapPlusPlus.hpp index fe1336c..fc1b662 100644 --- a/lib/include/BitmapPlusPlus.hpp +++ b/lib/include/BitmapPlusPlus.hpp @@ -466,6 +466,70 @@ namespace bmp { m_pixels[IX(x, y)] = color; } + + /** + * Vertically flips the bitmap and returns the flipped version + * + */ + Bitmap flip_v() { + Bitmap finished(m_width, m_height); + for (std::int32_t x = 0; x < m_width; ++x) { + for (std::int32_t y = 0; y < m_height; ++y) { + // Calculate the reverse y-index + finished.m_pixels[IX(x, y)] = m_pixels[IX(x, m_height - 1 - y)]; + } + } + return finished; + } + + /** + * Horizontally flips the bitmap and returns the flipped version + * + */ + Bitmap flip_h() { + Bitmap finished(m_width, m_height); + for (std::int32_t y = 0; y < m_height; ++y) { + for (std::int32_t x = 0; x < m_width; ++x) { + // Calculate the reverse x-index + finished.m_pixels[IX(x, y)] = m_pixels[IX(m_width - 1 - x, y)]; + } + } + return finished; + } + + /** + * Rotates the bitmap to the right and returns the rotated version + * + */ + Bitmap rotate_90_left() { + Bitmap finished(m_height, m_width); // Swap dimensions + + for (std::int32_t y = 0; y < m_height; ++y) { + std::int32_t y_offset = y * m_width; // Precompute row start index + for (std::int32_t x = 0; x < m_width; ++x) { + // Original pixel at (x, y) moves to (y, m_width - 1 - x) + finished.m_pixels[(m_width - 1 - x) * m_height + y] = m_pixels[y_offset + x]; + } + } + + return finished; + } + + /** + * Rotates the bitmap to the left and returns the rotated version + * + */ + Bitmap rotate_90_right() { + Bitmap finished(m_height, m_width); // Swap dimensions + for (std::int32_t y = 0; y < m_height; ++y) { + std::int32_t y_offset = y * m_width; // Precompute row start index + for (std::int32_t x = 0; x < m_width; ++x) { + finished.m_pixels[x * m_height + (m_height - 1 - y)] = m_pixels[y_offset + x]; + } + } + + return finished; + } /** * Saves Bitmap pixels into a file * @throws bmp::Exception on error @@ -584,7 +648,12 @@ namespace bmp { [[nodiscard]] constexpr std::size_t IX(const std::int32_t x, const std::int32_t y) const noexcept { return static_cast(x) + static_cast(m_width) * static_cast(y); } - + /** + * Converts 2D x,y coords into 1D index, with changed width + */ + [[nodiscard]] constexpr std::size_t IX(const std::int32_t x, const std::int32_t y, const std::int32_t width) const noexcept { + return static_cast(x) + static_cast(m_width) * static_cast(y); + } /** * Returns true if x,y coords are within boundaries */