From 87c87c2c06aaea40784ea4de11d4619b54fb8be2 Mon Sep 17 00:00:00 2001 From: Piotr Dziwinski Date: Thu, 13 Sep 2012 20:40:07 +0200 Subject: Image pixel read/write --- src/common/image.cpp | 142 +++++++++++++++++++++++++++++++++++++---- src/common/image.h | 17 ++++- src/common/test/CMakeLists.txt | 2 + src/common/test/image_test.cpp | 23 +++++++ 4 files changed, 167 insertions(+), 17 deletions(-) (limited to 'src/common') diff --git a/src/common/image.cpp b/src/common/image.cpp index 3d64377..50f6eee 100644 --- a/src/common/image.cpp +++ b/src/common/image.cpp @@ -21,6 +21,8 @@ #include #include #include +#include + #include #include #include @@ -88,21 +90,21 @@ bool PNGSaveSurface(const char *filename, SDL_Surface *surf) /* Opening output file */ fp = fopen(filename, "wb"); - if (fp == NULL) + if (fp == nullptr) { PNG_ERROR = std::string("Could not open file '") + std::string(filename) + std::string("' for saving"); return false; } /* Initializing png structures and callbacks */ - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, PNGUserError, NULL); - if (png_ptr == NULL) + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, PNGUserError, nullptr); + if (png_ptr == nullptr) return false; info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) + if (info_ptr == nullptr) { - png_destroy_write_struct(&png_ptr, static_cast(NULL)); + png_destroy_write_struct(&png_ptr, static_cast(nullptr)); PNG_ERROR = "png_create_info_struct() error!"; return false; } @@ -142,7 +144,7 @@ bool PNGSaveSurface(const char *filename, SDL_Surface *surf) CImage::CImage() { - m_data = NULL; + m_data = nullptr; } CImage::~CImage() @@ -150,22 +152,22 @@ CImage::~CImage() Free(); } -bool CImage::IsEmpty() +bool CImage::IsEmpty() const { - return m_data == NULL; + return m_data == nullptr; } void CImage::Free() { - if (m_data != NULL) + if (m_data != nullptr) { - if (m_data->surface != NULL) + if (m_data->surface != nullptr) { SDL_FreeSurface(m_data->surface); - m_data->surface = NULL; + m_data->surface = nullptr; } delete m_data; - m_data = NULL; + m_data = nullptr; } } @@ -174,6 +176,118 @@ ImageData* CImage::GetData() return m_data; } +Math::IntPoint CImage::GetSize() const +{ + if (m_data == nullptr) + return Math::IntPoint(); + + return Math::IntPoint(m_data->surface->w, m_data->surface->h); +} + +/** + * Image must be valid and pixel coords in valid range. + * + * \param pixel pixel coords (range x: 0..width-1 y: 0..height-1) + * \returns color + */ +Gfx::Color CImage::GetPixel(Math::IntPoint pixel) +{ + assert(m_data != nullptr); + assert(pixel.x >= 0 || pixel.x <= m_data->surface->w); + assert(pixel.y >= 0 || pixel.y <= m_data->surface->h); + + int bpp = m_data->surface->format->BytesPerPixel; + int index = pixel.y * m_data->surface->pitch + pixel.x * bpp; + Uint8* p = &static_cast(m_data->surface->pixels)[index]; + + Uint32 u = 0; + switch (bpp) + { + case 1: + u = *p; + break; + + case 2: + u = *reinterpret_cast(p); + break; + + case 3: + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) + u = (p[0] << 16) | (p[1] << 8) | p[2]; + else + u = p[0] | (p[1] << 8) | (p[2] << 16); + break; + + case 4: + u = *reinterpret_cast(p); + break; + + default: + assert(false); + } + + Uint8 r = 0, g = 0, b = 0, a = 0; + SDL_GetRGBA(u, m_data->surface->format, &r, &g, &b, &a); + + return Gfx::Color(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f); +} + +/** + * Image must be valid and pixel coords in valid range. + * + * \param pixel pixel coords (range x: 0..width-1 y: 0..height-1) + * \param color color + */ +void CImage::SetPixel(Math::IntPoint pixel, Gfx::Color color) +{ + assert(m_data != nullptr); + assert(pixel.x >= 0 || pixel.x <= m_data->surface->w); + assert(pixel.y >= 0 || pixel.y <= m_data->surface->h); + + int bpp = m_data->surface->format->BytesPerPixel; + int index = pixel.y * m_data->surface->pitch + pixel.x * bpp; + Uint8* p = &static_cast(m_data->surface->pixels)[index]; + + Uint8 r = static_cast(color.r * 255.0f); + Uint8 g = static_cast(color.g * 255.0f); + Uint8 b = static_cast(color.b * 255.0f); + Uint8 a = static_cast(color.a * 255.0f); + Uint32 u = SDL_MapRGBA(m_data->surface->format, r, g, b, a); + + switch(bpp) + { + case 1: + *p = u; + break; + + case 2: + *reinterpret_cast(p) = u; + break; + + case 3: + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) + { + p[0] = (u >> 16) & 0xFF; + p[1] = (u >> 8) & 0xFF; + p[2] = u & 0xFF; + } + else + { + p[0] = u & 0xFF; + p[1] = (u >> 8) & 0xFF; + p[2] = (u >> 16) & 0xFF; + } + break; + + case 4: + *reinterpret_cast(p) = u; + break; + + default: + assert(false); + } +} + std::string CImage::GetError() { return m_error; @@ -189,10 +303,10 @@ bool CImage::Load(const std::string& fileName) m_error = ""; m_data->surface = IMG_Load(fileName.c_str()); - if (m_data->surface == NULL) + if (m_data->surface == nullptr) { delete m_data; - m_data = NULL; + m_data = nullptr; m_error = std::string(IMG_GetError()); return false; diff --git a/src/common/image.h b/src/common/image.h index 7588ea9..93c7cab 100644 --- a/src/common/image.h +++ b/src/common/image.h @@ -21,6 +21,8 @@ #pragma once +#include "graphics/core/color.h" +#include "math/intpoint.h" #include #include @@ -64,12 +66,21 @@ public: //! Frees the allocated image data void Free(); - //! Returns whether the image is empty (has NULL data) - bool IsEmpty(); + //! Returns whether the image is empty (has null data) + bool IsEmpty() const; - //! Returns the image data; if empty - returns NULL + //! Returns the image data; if empty - returns nullptr ImageData* GetData(); + //! Returns the image size + Math::IntPoint GetSize() const; + + //! Sets the color at given pixel + void SetPixel(Math::IntPoint pixel, Gfx::Color color); + + //! Returns the color at given pixel + Gfx::Color GetPixel(Math::IntPoint pixel); + //! Loads an image from the specified file bool Load(const std::string &fileName); diff --git a/src/common/test/CMakeLists.txt b/src/common/test/CMakeLists.txt index d81acab..a1a7a50 100644 --- a/src/common/test/CMakeLists.txt +++ b/src/common/test/CMakeLists.txt @@ -7,6 +7,8 @@ include_directories("../../") include_directories("../../../") add_executable(image_test ../image.cpp image_test.cpp) +target_link_libraries(image_test -lpng -lSDL -lSDL_image) + add_executable(profile_test ../profile.cpp profile_test.cpp) add_test(profile_test ./profile_test) diff --git a/src/common/test/image_test.cpp b/src/common/test/image_test.cpp index 0ad1ee2..a98c9cc 100644 --- a/src/common/test/image_test.cpp +++ b/src/common/test/image_test.cpp @@ -22,6 +22,29 @@ int main(int argc, char *argv[]) printf("Error loading '%s': %s\n", err.c_str()); return 1; } + Gfx::Color color; + std::string str; + + color = image.GetPixel(Math::IntPoint(0, 0)); + str = color.ToString(); + printf("pixel @ (0,0): %s\n", str.c_str()); + + color = image.GetPixel(Math::IntPoint(0, 1)); + str = color.ToString(); + printf("pixel @ (0,1): %s\n", str.c_str()); + + color = image.GetPixel(Math::IntPoint(1, 0)); + str = color.ToString(); + printf("pixel @ (1,0): %s\n", str.c_str()); + + color = image.GetPixel(Math::IntPoint(1, 1)); + str = color.ToString(); + printf("pixel @ (1,1): %s\n", str.c_str()); + + image.SetPixel(Math::IntPoint(0, 0), Gfx::Color(0.1f, 0.2f, 0.3f, 0.0f)); + image.SetPixel(Math::IntPoint(1, 0), Gfx::Color(0.3f, 0.2f, 0.1f, 1.0f)); + image.SetPixel(Math::IntPoint(0, 1), Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f)); + image.SetPixel(Math::IntPoint(1, 1), Gfx::Color(0.0f, 0.0f, 0.0f, 1.0f)); if (! image.SavePNG(argv[2])) { -- cgit v1.2.3-1-g7c22