2022-03-05 16:15:00 +01:00
|
|
|
#include "BMP.h"
|
2022-03-05 19:30:41 +01:00
|
|
|
#include <stdexcept>
|
2022-03-05 20:40:49 +01:00
|
|
|
#include "BmpWriter.h"
|
2022-03-05 22:00:57 +01:00
|
|
|
#include "BmpReader.h"
|
2022-03-05 16:15:00 +01:00
|
|
|
|
2022-03-05 20:22:36 +01:00
|
|
|
#define CHECK_IF_INITIALIZED if (!isInitialized) throw std::runtime_error("Image not initialized!");
|
|
|
|
|
2022-03-05 16:15:00 +01:00
|
|
|
namespace Leonetienne::BmpPP {
|
|
|
|
|
2022-03-05 20:22:36 +01:00
|
|
|
BMP::BMP() {
|
|
|
|
// Do nothing
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-03-05 22:00:57 +01:00
|
|
|
|
|
|
|
BMP::BMP(const std::string &filename) {
|
|
|
|
if(!Read(filename))
|
|
|
|
throw std::runtime_error("Unable to read bmp image!");
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-03-05 16:15:00 +01:00
|
|
|
BMP::BMP(const Eule::Vector2i &size, const Colormode& colormode)
|
|
|
|
:
|
2022-03-05 19:30:41 +01:00
|
|
|
size { size },
|
|
|
|
colormode { colormode }
|
2022-03-05 16:15:00 +01:00
|
|
|
{
|
2022-03-05 19:51:57 +01:00
|
|
|
ReInitialize(size, colormode);
|
2022-03-05 16:15:00 +01:00
|
|
|
|
2022-03-05 19:51:57 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BMP::ReInitialize(const Eule::Vector2i &size) {
|
2022-03-05 20:22:36 +01:00
|
|
|
isInitialized = true;
|
|
|
|
|
2022-03-05 19:51:57 +01:00
|
|
|
// Carry over new attributes
|
|
|
|
this->size = size;
|
|
|
|
|
|
|
|
// Re-initialize the pixelbuffer
|
|
|
|
pixelBuffer.clear();
|
|
|
|
pixelBuffer.resize(size.x * size.y * GetNumColorChannels());
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BMP::ReInitialize(const Eule::Vector2i &size, const Colormode &colormode) {
|
2022-03-05 20:22:36 +01:00
|
|
|
isInitialized = true;
|
|
|
|
|
2022-03-05 19:51:57 +01:00
|
|
|
// Carry over new attributes
|
|
|
|
this->size = size;
|
|
|
|
this->colormode = colormode;
|
|
|
|
|
|
|
|
// Re-initialize the pixelbuffer
|
2022-03-05 16:15:00 +01:00
|
|
|
pixelBuffer.clear();
|
2022-03-05 19:37:02 +01:00
|
|
|
pixelBuffer.resize(size.x * size.y * GetNumColorChannels());
|
2022-03-05 16:15:00 +01:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-03-05 19:30:41 +01:00
|
|
|
bool BMP::Write(const std::string &filename) const {
|
2022-03-05 20:22:36 +01:00
|
|
|
CHECK_IF_INITIALIZED
|
2022-03-05 19:30:41 +01:00
|
|
|
|
2022-03-05 20:40:49 +01:00
|
|
|
return BmpWriter::Write(*this, filename);
|
|
|
|
}
|
2022-03-05 19:30:41 +01:00
|
|
|
|
2022-03-05 20:40:49 +01:00
|
|
|
bool BMP::Read(const std::string &filename) {
|
2022-03-05 22:00:57 +01:00
|
|
|
return BmpReader::Read(*this, filename);
|
2022-03-05 19:30:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
std::uint8_t *BMP::GetPixel(const Eule::Vector2i &position) {
|
2022-03-05 20:22:36 +01:00
|
|
|
CHECK_IF_INITIALIZED
|
|
|
|
|
2022-03-05 19:30:41 +01:00
|
|
|
const std::size_t pixelIndex =
|
2022-03-05 19:37:02 +01:00
|
|
|
(position.y * size.x + position.x) * GetNumColorChannels();
|
2022-03-05 19:30:41 +01:00
|
|
|
|
|
|
|
if (pixelIndex >= pixelBuffer.size())
|
|
|
|
throw std::runtime_error("Pixel index out of range!");
|
|
|
|
|
|
|
|
return pixelBuffer.data() + pixelIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::uint8_t *BMP::GetPixel(const Eule::Vector2i &position) const {
|
2022-03-05 20:22:36 +01:00
|
|
|
CHECK_IF_INITIALIZED
|
|
|
|
|
2022-03-05 19:30:41 +01:00
|
|
|
const std::size_t pixelIndex =
|
2022-03-05 19:37:02 +01:00
|
|
|
(position.y * size.x + position.x) * GetNumColorChannels();
|
2022-03-05 19:30:41 +01:00
|
|
|
|
|
|
|
if (pixelIndex >= pixelBuffer.size())
|
|
|
|
throw std::runtime_error("Pixel index out of range!");
|
|
|
|
|
|
|
|
return pixelBuffer.data() + pixelIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BMP::SetPixel(const Eule::Vector2i &position,
|
|
|
|
const std::uint8_t r,
|
|
|
|
const std::uint8_t g,
|
|
|
|
const std::uint8_t b,
|
2022-03-05 20:22:36 +01:00
|
|
|
const std::uint8_t a)
|
|
|
|
{
|
|
|
|
CHECK_IF_INITIALIZED
|
2022-03-05 19:30:41 +01:00
|
|
|
|
|
|
|
std::uint8_t* pixel = GetPixel(position);
|
|
|
|
|
|
|
|
switch (colormode) {
|
|
|
|
case Colormode::RGBA:
|
|
|
|
pixel[0] = r;
|
|
|
|
pixel[1] = g;
|
|
|
|
pixel[2] = b;
|
|
|
|
pixel[3] = a;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Colormode::RGB:
|
|
|
|
pixel[0] = r;
|
|
|
|
pixel[1] = g;
|
|
|
|
pixel[2] = b;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
2022-03-05 16:15:00 +01:00
|
|
|
}
|
|
|
|
|
2022-03-05 19:37:02 +01:00
|
|
|
std::uint8_t *BMP::data() {
|
2022-03-05 20:22:36 +01:00
|
|
|
CHECK_IF_INITIALIZED
|
|
|
|
|
2022-03-05 19:37:02 +01:00
|
|
|
return pixelBuffer.data();
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::uint8_t *BMP::data() const {
|
2022-03-05 20:22:36 +01:00
|
|
|
CHECK_IF_INITIALIZED
|
|
|
|
|
2022-03-05 19:37:02 +01:00
|
|
|
return pixelBuffer.data();
|
|
|
|
}
|
|
|
|
|
|
|
|
const Eule::Vector2i &BMP::GetDimensions() const {
|
2022-03-05 20:22:36 +01:00
|
|
|
CHECK_IF_INITIALIZED
|
|
|
|
|
2022-03-05 19:37:02 +01:00
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
const Colormode &BMP::GetColormode() const {
|
2022-03-05 20:22:36 +01:00
|
|
|
CHECK_IF_INITIALIZED
|
|
|
|
|
2022-03-05 19:37:02 +01:00
|
|
|
return colormode;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::size_t BMP::GetNumColorChannels() const {
|
2022-03-05 20:22:36 +01:00
|
|
|
CHECK_IF_INITIALIZED
|
|
|
|
|
2022-03-05 19:37:02 +01:00
|
|
|
switch (colormode) {
|
|
|
|
case Colormode::RGB:
|
|
|
|
return 3;
|
|
|
|
|
|
|
|
case Colormode::RGBA:
|
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unreachable
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::size_t BMP::GetPixelbufferSize() const {
|
2022-03-05 20:22:36 +01:00
|
|
|
CHECK_IF_INITIALIZED
|
|
|
|
|
2022-03-05 19:37:02 +01:00
|
|
|
return pixelBuffer.size();
|
|
|
|
}
|
|
|
|
|
2022-03-05 20:22:36 +01:00
|
|
|
bool BMP::IsInitialized() const {
|
|
|
|
return isInitialized;
|
|
|
|
}
|
|
|
|
|
2022-03-05 16:15:00 +01:00
|
|
|
}
|
2022-03-05 20:22:36 +01:00
|
|
|
|
|
|
|
#undef CHECK_IF_INITIALIZED
|