From 08f1102a54a1f9f382a74a67f42da1742a956549 Mon Sep 17 00:00:00 2001 From: Luca Della Vedova Date: Thu, 9 Jun 2022 10:32:41 +0800 Subject: [PATCH 1/5] Add API to load compressed images and read RGBA data Signed-off-by: Luca Della Vedova --- graphics/include/gz/common/Image.hh | 15 +++++++++++ graphics/src/Image.cc | 39 +++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/graphics/include/gz/common/Image.hh b/graphics/include/gz/common/Image.hh index 052b43e6c..d47990b25 100644 --- a/graphics/include/gz/common/Image.hh +++ b/graphics/include/gz/common/Image.hh @@ -82,6 +82,7 @@ namespace gz BAYER_BGGR8, BAYER_GBRG8, BAYER_GRBG8, + COMPRESSED_PNG, PIXEL_FORMAT_COUNT }; @@ -122,6 +123,14 @@ namespace gz unsigned int _height, Image::PixelFormatType _format); + /// \brief Set the image from compressed (i.e. png) data + /// \param[in] _data Pointer to the raw image data + /// \param[in] _size Size of the buffer + /// \param[in] _format Pixel format of the provided data + public: void SetFromCompressedData(const unsigned char *_data, + unsigned int _size, + Image::PixelFormatType _format); + /// \brief Get the image as a data array /// \param[out] _data Pointer to a NULL array of char. /// \param[out] _count The resulting data array size @@ -133,6 +142,12 @@ namespace gz /// \param[out] _count The resulting data array size public: void RGBData(unsigned char **_data, unsigned int &_count) const; + /// \brief Get the RGBA data from the image. This will add an alpha + /// channel if one is not present. + /// \param[out] _data Pointer to a NULL array of char. + /// \param[out] _count The resulting data array size + public: void RGBAData(unsigned char **_data, unsigned int &_count) const; + /// \brief Get the width /// \return The image width public: unsigned int Width() const; diff --git a/graphics/src/Image.cc b/graphics/src/Image.cc index 256bc565f..c97d194b9 100644 --- a/graphics/src/Image.cc +++ b/graphics/src/Image.cc @@ -242,6 +242,28 @@ void Image::SetFromData(const unsigned char *_data, } } +////////////////////////////////////////////////// +void Image::SetFromCompressedData(const unsigned char *_data, + unsigned int _size, + Image::PixelFormatType _format) +{ + if (this->dataPtr->bitmap) + FreeImage_Unload(this->dataPtr->bitmap); + this->dataPtr->bitmap = nullptr; + + if (_format == COMPRESSED_PNG) + { + FIMEMORY *fiMem = FreeImage_OpenMemory(const_cast(_data), _size); + this->dataPtr->bitmap = FreeImage_LoadFromMemory(FIF_PNG, fiMem); + FreeImage_CloseMemory(fiMem); + } + else + { + gzerr << "Unable to handle format[" << _format << "]\n"; + return; + } +} + ////////////////////////////////////////////////// int Image::Pitch() const { @@ -265,6 +287,23 @@ void Image::RGBData(unsigned char **_data, unsigned int &_count) const FreeImage_Unload(tmp2); } +////////////////////////////////////////////////// +void Image::RGBAData(unsigned char **_data, unsigned int &_count) const +{ + FIBITMAP *tmp = this->dataPtr->bitmap; + FIBITMAP *tmp2 = nullptr; + if (this->dataPtr->ShouldSwapRedBlue()) + { + tmp = this->dataPtr->SwapRedBlue(this->Width(), this->Height()); + tmp2 = tmp; + } + tmp = FreeImage_ConvertTo32Bits(tmp); + this->dataPtr->DataImpl(_data, _count, tmp); + FreeImage_Unload(tmp); + if (tmp2) + FreeImage_Unload(tmp2); +} + ////////////////////////////////////////////////// void Image::Data(unsigned char **_data, unsigned int &_count) const { From 661823ce605e182074b10e7faec97acf063245e3 Mon Sep 17 00:00:00 2001 From: Luca Della Vedova Date: Thu, 9 Jun 2022 11:18:25 +0800 Subject: [PATCH 2/5] Add test Signed-off-by: Luca Della Vedova --- graphics/src/Image_TEST.cc | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/graphics/src/Image_TEST.cc b/graphics/src/Image_TEST.cc index 478e22741..bb4322e63 100644 --- a/graphics/src/Image_TEST.cc +++ b/graphics/src/Image_TEST.cc @@ -210,6 +210,39 @@ TEST_F(ImageTest, SetFromData) ASSERT_EQ(img2.MaxColor(), math::Color::Red); } +TEST_F(ImageTest, SetFromCompressedData) +{ + // Open file and move to end + std::ifstream ifs(kTestData, std::ios::binary | std::ios::ate); + std::ifstream::pos_type fileEnd = ifs.tellg(); + std::vector fileData(fileEnd); + + // Rewind to beginning of file and read data + ifs.seekg(0); + ifs.read(reinterpret_cast(&fileData[0]), fileEnd); + + common::Image img; + img.SetFromCompressedData(&fileData[0], fileEnd, + common::Image::PixelFormatType::COMPRESSED_PNG); + ASSERT_TRUE(img.Valid()); + + unsigned char *data = nullptr; + unsigned int size = 0; + img.RGBAData(&data, size); + ASSERT_EQ(39204u, size); + ASSERT_NE(nullptr, data); + + ASSERT_EQ(common::Image::PixelFormatType::RGBA_INT8, img.PixelFormat()); + ASSERT_EQ(121u, img.Width()); + ASSERT_EQ(81u, img.Height()); + ASSERT_EQ(32u, img.BPP()); + ASSERT_EQ(484, img.Pitch()); + ASSERT_EQ(img.Pixel(0, 0), math::Color::Red); + ASSERT_EQ(img.Pixel(85, 0), math::Color::Blue); + ASSERT_EQ(img.AvgColor(), math::Color(0.661157f, 0, 0.338843f, 1)); + ASSERT_EQ(img.MaxColor(), math::Color::Red); +} + /* // save image then reload and test colors std::string testSaveImage = From b5ab18fca619f115757270b04a92845f5e595214 Mon Sep 17 00:00:00 2001 From: Luca Della Vedova Date: Thu, 9 Jun 2022 11:37:38 +0800 Subject: [PATCH 3/5] Deallocate memory in tests Signed-off-by: Luca Della Vedova --- graphics/src/Image_TEST.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/graphics/src/Image_TEST.cc b/graphics/src/Image_TEST.cc index bb4322e63..3d68a5ca2 100644 --- a/graphics/src/Image_TEST.cc +++ b/graphics/src/Image_TEST.cc @@ -134,6 +134,7 @@ TEST_F(ImageTest, RGBData) } } } + delete[] data; } ///////////////////////////////////////////////// @@ -179,6 +180,7 @@ TEST_F(ImageTest, Data) } } } + delete[] data; } ///////////////////////////////////////////////// @@ -208,6 +210,7 @@ TEST_F(ImageTest, SetFromData) ASSERT_EQ(img2.Pixel(85, 0), math::Color::Blue); ASSERT_EQ(img2.AvgColor(), math::Color(0.661157f, 0, 0.338843f, 1)); ASSERT_EQ(img2.MaxColor(), math::Color::Red); + delete[] data; } TEST_F(ImageTest, SetFromCompressedData) @@ -241,6 +244,7 @@ TEST_F(ImageTest, SetFromCompressedData) ASSERT_EQ(img.Pixel(85, 0), math::Color::Blue); ASSERT_EQ(img.AvgColor(), math::Color(0.661157f, 0, 0.338843f, 1)); ASSERT_EQ(img.MaxColor(), math::Color::Red); + delete[] data; } /* From 8054b0d78433da3de936ffc9b81d87295207a26f Mon Sep 17 00:00:00 2001 From: Luca Della Vedova Date: Tue, 14 Jun 2022 10:24:41 +0800 Subject: [PATCH 4/5] Remove const_cast, change function to non const Signed-off-by: Luca Della Vedova --- graphics/include/gz/common/Image.hh | 2 +- graphics/src/Image.cc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/graphics/include/gz/common/Image.hh b/graphics/include/gz/common/Image.hh index d47990b25..c1bc9220c 100644 --- a/graphics/include/gz/common/Image.hh +++ b/graphics/include/gz/common/Image.hh @@ -127,7 +127,7 @@ namespace gz /// \param[in] _data Pointer to the raw image data /// \param[in] _size Size of the buffer /// \param[in] _format Pixel format of the provided data - public: void SetFromCompressedData(const unsigned char *_data, + public: void SetFromCompressedData(unsigned char *_data, unsigned int _size, Image::PixelFormatType _format); diff --git a/graphics/src/Image.cc b/graphics/src/Image.cc index c97d194b9..237716191 100644 --- a/graphics/src/Image.cc +++ b/graphics/src/Image.cc @@ -243,7 +243,7 @@ void Image::SetFromData(const unsigned char *_data, } ////////////////////////////////////////////////// -void Image::SetFromCompressedData(const unsigned char *_data, +void Image::SetFromCompressedData(unsigned char *_data, unsigned int _size, Image::PixelFormatType _format) { @@ -253,7 +253,7 @@ void Image::SetFromCompressedData(const unsigned char *_data, if (_format == COMPRESSED_PNG) { - FIMEMORY *fiMem = FreeImage_OpenMemory(const_cast(_data), _size); + FIMEMORY *fiMem = FreeImage_OpenMemory(_data, _size); this->dataPtr->bitmap = FreeImage_LoadFromMemory(FIF_PNG, fiMem); FreeImage_CloseMemory(fiMem); } From ccc483c8b552bf1323e18e0762415e6a830b2d92 Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Mon, 20 Jun 2022 14:24:19 -0500 Subject: [PATCH 5/5] Tests to increase coverage Signed-off-by: Michael Carroll --- graphics/src/Image_TEST.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/graphics/src/Image_TEST.cc b/graphics/src/Image_TEST.cc index 3d68a5ca2..8e326a3ca 100644 --- a/graphics/src/Image_TEST.cc +++ b/graphics/src/Image_TEST.cc @@ -245,6 +245,16 @@ TEST_F(ImageTest, SetFromCompressedData) ASSERT_EQ(img.AvgColor(), math::Color(0.661157f, 0, 0.338843f, 1)); ASSERT_EQ(img.MaxColor(), math::Color::Red); delete[] data; + + // Reloading the image should not cause any leaks. + img.SetFromCompressedData(&fileData[0], fileEnd, + common::Image::PixelFormatType::COMPRESSED_PNG); + ASSERT_TRUE(img.Valid()); + + // Loading from unsupported pixel format fails. + img.SetFromCompressedData(&fileData[0], fileEnd, + common::Image::PixelFormatType::UNKNOWN_PIXEL_FORMAT); + ASSERT_FALSE(img.Valid()); } /*