From f993241e9f6d44ecb9b589016362a149af748bac Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sat, 5 Mar 2022 20:22:36 +0100 Subject: [PATCH] It is now possible to create uninitialized images --- Src/BMP.cpp | 38 +++++++++++++++++++++- Src/BMP.h | 12 +++++-- Test/CMakeLists.txt | 1 + Test/ReInitialize.cpp | 14 ++++++++ Test/Uninitialized.cpp | 72 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 133 insertions(+), 4 deletions(-) create mode 100644 Test/Uninitialized.cpp diff --git a/Src/BMP.cpp b/Src/BMP.cpp index 35ca8f9..8494c6d 100644 --- a/Src/BMP.cpp +++ b/Src/BMP.cpp @@ -4,8 +4,15 @@ #include #include "BmpHeader.h" +#define CHECK_IF_INITIALIZED if (!isInitialized) throw std::runtime_error("Image not initialized!"); + namespace Leonetienne::BmpPP { + BMP::BMP() { + // Do nothing + return; + } + BMP::BMP(const Eule::Vector2i &size, const Colormode& colormode) : size { size }, @@ -17,6 +24,8 @@ namespace Leonetienne::BmpPP { } void BMP::ReInitialize(const Eule::Vector2i &size) { + isInitialized = true; + // Carry over new attributes this->size = size; @@ -28,6 +37,8 @@ namespace Leonetienne::BmpPP { } void BMP::ReInitialize(const Eule::Vector2i &size, const Colormode &colormode) { + isInitialized = true; + // Carry over new attributes this->size = size; this->colormode = colormode; @@ -40,6 +51,7 @@ namespace Leonetienne::BmpPP { } bool BMP::Write(const std::string &filename) const { + CHECK_IF_INITIALIZED // Create the bmp header BmpHeader bmpHeader; @@ -158,6 +170,8 @@ namespace Leonetienne::BmpPP { } std::uint8_t *BMP::GetPixel(const Eule::Vector2i &position) { + CHECK_IF_INITIALIZED + const std::size_t pixelIndex = (position.y * size.x + position.x) * GetNumColorChannels(); @@ -168,6 +182,8 @@ namespace Leonetienne::BmpPP { } const std::uint8_t *BMP::GetPixel(const Eule::Vector2i &position) const { + CHECK_IF_INITIALIZED + const std::size_t pixelIndex = (position.y * size.x + position.x) * GetNumColorChannels(); @@ -181,7 +197,9 @@ namespace Leonetienne::BmpPP { const std::uint8_t r, const std::uint8_t g, const std::uint8_t b, - const std::uint8_t a) { + const std::uint8_t a) + { + CHECK_IF_INITIALIZED std::uint8_t* pixel = GetPixel(position); @@ -204,22 +222,32 @@ namespace Leonetienne::BmpPP { } std::uint8_t *BMP::data() { + CHECK_IF_INITIALIZED + return pixelBuffer.data(); } const std::uint8_t *BMP::data() const { + CHECK_IF_INITIALIZED + return pixelBuffer.data(); } const Eule::Vector2i &BMP::GetDimensions() const { + CHECK_IF_INITIALIZED + return size; } const Colormode &BMP::GetColormode() const { + CHECK_IF_INITIALIZED + return colormode; } std::size_t BMP::GetNumColorChannels() const { + CHECK_IF_INITIALIZED + switch (colormode) { case Colormode::RGB: return 3; @@ -233,7 +261,15 @@ namespace Leonetienne::BmpPP { } std::size_t BMP::GetPixelbufferSize() const { + CHECK_IF_INITIALIZED + return pixelBuffer.size(); } + bool BMP::IsInitialized() const { + return isInitialized; + } + } + +#undef CHECK_IF_INITIALIZED diff --git a/Src/BMP.h b/Src/BMP.h index c7318df..9019f16 100644 --- a/Src/BMP.h +++ b/Src/BMP.h @@ -10,11 +10,9 @@ namespace Leonetienne::BmpPP { class BMP { public: + BMP(); explicit BMP(const Eule::Vector2i& size, const Colormode& colormode = Colormode::RGBA); - //! Will write the bmp image to a file. - bool Write(const std::string& filename) const; - //! Will return a pointer to the first byte of a pixel at a given position std::uint8_t* GetPixel(const Eule::Vector2i& position); @@ -48,10 +46,18 @@ namespace Leonetienne::BmpPP { //! Will return the size of the raw pixel buffer, in bytes std::size_t GetPixelbufferSize() const; + //! Will return whether this image is initialized or not + bool IsInitialized() const; + + //! Will write the bmp image to a file. + //! Returns false, if unable to open the file + bool Write(const std::string& filename) const; + private: Eule::Vector2i size; Colormode colormode; std::vector pixelBuffer; + bool isInitialized = false; }; } diff --git a/Test/CMakeLists.txt b/Test/CMakeLists.txt index 032be23..7b85765 100644 --- a/Test/CMakeLists.txt +++ b/Test/CMakeLists.txt @@ -20,4 +20,5 @@ add_executable(Test BmpHeader.cpp ReInitialize.cpp + Uninitialized.cpp ) diff --git a/Test/ReInitialize.cpp b/Test/ReInitialize.cpp index 49a9987..5dec085 100644 --- a/Test/ReInitialize.cpp +++ b/Test/ReInitialize.cpp @@ -30,3 +30,17 @@ TEST_CASE(__FILE__"/ReInitialize", "[ReInitialize]") return; } + +// Tests that re-initializing images results in initialized images +TEST_CASE(__FILE__"/ReInitializingWillInitialize", "[ReInitialize]") +{ + // Create uninitialized image + BMP bmp; + REQUIRE_FALSE(bmp.IsInitialized()); + + // Now re-initialize it + bmp.ReInitialize({800, 600}); + REQUIRE(bmp.IsInitialized()); + + return; +} diff --git a/Test/Uninitialized.cpp b/Test/Uninitialized.cpp new file mode 100644 index 0000000..fb73221 --- /dev/null +++ b/Test/Uninitialized.cpp @@ -0,0 +1,72 @@ +#include +#include +#include "Catch2.h" + +using namespace Leonetienne::BmpPP; + +// Tests that trying to interrogate any getter/Write() on an uninitialized image results in a runtime error +TEST_CASE(__FILE__"/RuntimeErrorOnUninitialized", "[Uninitialized]") +{ + // Create uninitialized image + BMP bmp; + + REQUIRE_THROWS_AS( + bmp.GetPixel({50, 60}) + , std::runtime_error + ); + + REQUIRE_THROWS_AS( + bmp.SetPixel({50, 60}, 1,2,3,4) + , std::runtime_error + ); + + REQUIRE_THROWS_AS( + bmp.data() + , std::runtime_error + ); + + REQUIRE_THROWS_AS( + bmp.GetDimensions() + , std::runtime_error + ); + + REQUIRE_THROWS_AS( + bmp.GetColormode() + , std::runtime_error + ); + + REQUIRE_THROWS_AS( + bmp.GetNumColorChannels() + , std::runtime_error + ); + + REQUIRE_THROWS_AS( + bmp.GetPixelbufferSize() + , std::runtime_error + ); + + REQUIRE_THROWS_AS( + bmp.Write("foo.bmp") + , std::runtime_error + ); + + return; +} + +// Tests that an uninitialized image reports to be uninitialized +TEST_CASE(__FILE__"/UninitializedImageIsUninitialized", "[Uninitialized]") +{ + BMP bmp; + REQUIRE_FALSE(bmp.IsInitialized()); + + return; +} + +// Tests that an image constructed via dimensions is initialized +TEST_CASE(__FILE__"/ConstructedByDimensionsIsInitialized", "[Uninitialized]") +{ + BMP bmp({800, 600}); + REQUIRE(bmp.IsInitialized()); + + return; +}