It is now possible to create uninitialized images

This commit is contained in:
Leonetienne 2022-03-05 20:22:36 +01:00
parent b27068a6b6
commit f993241e9f
5 changed files with 133 additions and 4 deletions

View File

@ -4,8 +4,15 @@
#include <stdexcept> #include <stdexcept>
#include "BmpHeader.h" #include "BmpHeader.h"
#define CHECK_IF_INITIALIZED if (!isInitialized) throw std::runtime_error("Image not initialized!");
namespace Leonetienne::BmpPP { namespace Leonetienne::BmpPP {
BMP::BMP() {
// Do nothing
return;
}
BMP::BMP(const Eule::Vector2i &size, const Colormode& colormode) BMP::BMP(const Eule::Vector2i &size, const Colormode& colormode)
: :
size { size }, size { size },
@ -17,6 +24,8 @@ namespace Leonetienne::BmpPP {
} }
void BMP::ReInitialize(const Eule::Vector2i &size) { void BMP::ReInitialize(const Eule::Vector2i &size) {
isInitialized = true;
// Carry over new attributes // Carry over new attributes
this->size = size; this->size = size;
@ -28,6 +37,8 @@ namespace Leonetienne::BmpPP {
} }
void BMP::ReInitialize(const Eule::Vector2i &size, const Colormode &colormode) { void BMP::ReInitialize(const Eule::Vector2i &size, const Colormode &colormode) {
isInitialized = true;
// Carry over new attributes // Carry over new attributes
this->size = size; this->size = size;
this->colormode = colormode; this->colormode = colormode;
@ -40,6 +51,7 @@ namespace Leonetienne::BmpPP {
} }
bool BMP::Write(const std::string &filename) const { bool BMP::Write(const std::string &filename) const {
CHECK_IF_INITIALIZED
// Create the bmp header // Create the bmp header
BmpHeader bmpHeader; BmpHeader bmpHeader;
@ -158,6 +170,8 @@ namespace Leonetienne::BmpPP {
} }
std::uint8_t *BMP::GetPixel(const Eule::Vector2i &position) { std::uint8_t *BMP::GetPixel(const Eule::Vector2i &position) {
CHECK_IF_INITIALIZED
const std::size_t pixelIndex = const std::size_t pixelIndex =
(position.y * size.x + position.x) * GetNumColorChannels(); (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 { const std::uint8_t *BMP::GetPixel(const Eule::Vector2i &position) const {
CHECK_IF_INITIALIZED
const std::size_t pixelIndex = const std::size_t pixelIndex =
(position.y * size.x + position.x) * GetNumColorChannels(); (position.y * size.x + position.x) * GetNumColorChannels();
@ -181,7 +197,9 @@ namespace Leonetienne::BmpPP {
const std::uint8_t r, const std::uint8_t r,
const std::uint8_t g, const std::uint8_t g,
const std::uint8_t b, const std::uint8_t b,
const std::uint8_t a) { const std::uint8_t a)
{
CHECK_IF_INITIALIZED
std::uint8_t* pixel = GetPixel(position); std::uint8_t* pixel = GetPixel(position);
@ -204,22 +222,32 @@ namespace Leonetienne::BmpPP {
} }
std::uint8_t *BMP::data() { std::uint8_t *BMP::data() {
CHECK_IF_INITIALIZED
return pixelBuffer.data(); return pixelBuffer.data();
} }
const std::uint8_t *BMP::data() const { const std::uint8_t *BMP::data() const {
CHECK_IF_INITIALIZED
return pixelBuffer.data(); return pixelBuffer.data();
} }
const Eule::Vector2i &BMP::GetDimensions() const { const Eule::Vector2i &BMP::GetDimensions() const {
CHECK_IF_INITIALIZED
return size; return size;
} }
const Colormode &BMP::GetColormode() const { const Colormode &BMP::GetColormode() const {
CHECK_IF_INITIALIZED
return colormode; return colormode;
} }
std::size_t BMP::GetNumColorChannels() const { std::size_t BMP::GetNumColorChannels() const {
CHECK_IF_INITIALIZED
switch (colormode) { switch (colormode) {
case Colormode::RGB: case Colormode::RGB:
return 3; return 3;
@ -233,7 +261,15 @@ namespace Leonetienne::BmpPP {
} }
std::size_t BMP::GetPixelbufferSize() const { std::size_t BMP::GetPixelbufferSize() const {
CHECK_IF_INITIALIZED
return pixelBuffer.size(); return pixelBuffer.size();
} }
bool BMP::IsInitialized() const {
return isInitialized;
}
} }
#undef CHECK_IF_INITIALIZED

View File

@ -10,11 +10,9 @@ namespace Leonetienne::BmpPP {
class BMP { class BMP {
public: public:
BMP();
explicit BMP(const Eule::Vector2i& size, const Colormode& colormode = Colormode::RGBA); 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 //! Will return a pointer to the first byte of a pixel at a given position
std::uint8_t* GetPixel(const Eule::Vector2i& 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 //! Will return the size of the raw pixel buffer, in bytes
std::size_t GetPixelbufferSize() const; 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: private:
Eule::Vector2i size; Eule::Vector2i size;
Colormode colormode; Colormode colormode;
std::vector<std::uint8_t> pixelBuffer; std::vector<std::uint8_t> pixelBuffer;
bool isInitialized = false;
}; };
} }

View File

@ -20,4 +20,5 @@ add_executable(Test
BmpHeader.cpp BmpHeader.cpp
ReInitialize.cpp ReInitialize.cpp
Uninitialized.cpp
) )

View File

@ -30,3 +30,17 @@ TEST_CASE(__FILE__"/ReInitialize", "[ReInitialize]")
return; 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;
}

72
Test/Uninitialized.cpp Normal file
View File

@ -0,0 +1,72 @@
#include <Bmp.h>
#include <stdexcept>
#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;
}