Skip to content

Commit eb24070

Browse files
iche033mergify[bot]
authored andcommitted
Handle color 16 bit images
Signed-off-by: Ian Chen <[email protected]> (cherry picked from commit 5d8d665)
1 parent e2fc459 commit eb24070

File tree

3 files changed

+117
-23
lines changed

3 files changed

+117
-23
lines changed

graphics/include/gz/common/Image.hh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ namespace gz
4343
"RGBA_INT8",
4444
"BGRA_INT8",
4545
"RGB_INT16",
46+
"RGBA_INT16",
4647
"RGB_INT32",
4748
"BGR_INT8",
4849
"BGR_INT16",
@@ -72,6 +73,7 @@ namespace gz
7273
RGBA_INT8,
7374
BGRA_INT8,
7475
RGB_INT16,
76+
RGBA_INT16,
7577
RGB_INT32,
7678
BGR_INT8,
7779
BGR_INT16,

graphics/src/Image.cc

Lines changed: 66 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -521,16 +521,23 @@ math::Color Image::Pixel(unsigned int _x, unsigned int _y) const
521521
if (!this->Valid())
522522
return clr;
523523

524+
if (_x >= this->Width() || _y >= this->Height())
525+
{
526+
gzerr << "Image: Coordinates out of range["
527+
<< _x << " " << _y << "] \n";
528+
return clr;
529+
}
530+
524531
FREE_IMAGE_COLOR_TYPE type = FreeImage_GetColorType(this->dataPtr->bitmap);
532+
FREE_IMAGE_TYPE imageType = FreeImage_GetImageType(this->dataPtr->bitmap);
525533

526-
if (type == FIC_RGB || type == FIC_RGBALPHA)
534+
if ((type == FIC_RGB || type == FIC_RGBALPHA) && (imageType == FIT_BITMAP))
527535
{
528536
RGBQUAD firgb;
529-
530537
if (FreeImage_GetPixelColor(this->dataPtr->bitmap, _x, _y, &firgb) == FALSE)
531538
{
532-
gzerr << "Image: Coordinates out of range["
533-
<< _x << " " << _y << "] \n";
539+
gzerr << "Failed to get pixel value at ["
540+
<< _x << " " << _y << "] \n";
534541
return clr;
535542
}
536543
clr.Set(firgb.rgbRed / 255.0f, firgb.rgbGreen / 255.0f,
@@ -541,8 +548,8 @@ math::Color Image::Pixel(unsigned int _x, unsigned int _y) const
541548
if (this->dataPtr->PixelIndex(
542549
this->dataPtr->bitmap, _x, _y, clr) == FALSE)
543550
{
544-
gzerr << "Image: Coordinates out of range ["
545-
<< _x << " " << _y << "] \n";
551+
gzerr << "Failed to get pixel value at ["
552+
<< _x << " " << _y << "] \n";
546553
return clr;
547554
}
548555
}
@@ -589,8 +596,9 @@ math::Color Image::MaxColor() const
589596
return clr;
590597

591598
FREE_IMAGE_COLOR_TYPE type = FreeImage_GetColorType(this->dataPtr->bitmap);
599+
FREE_IMAGE_TYPE imageType = FreeImage_GetImageType(this->dataPtr->bitmap);
592600

593-
if (type == FIC_RGB || type == FIC_RGBALPHA)
601+
if ((type == FIC_RGB || type == FIC_RGBALPHA) && (imageType == FIT_BITMAP))
594602
{
595603
RGBQUAD firgb;
596604

@@ -603,8 +611,8 @@ math::Color Image::MaxColor() const
603611
if (FALSE ==
604612
FreeImage_GetPixelColor(this->dataPtr->bitmap, x, y, &firgb))
605613
{
606-
gzerr << "Image: Coordinates out of range["
607-
<< x << " " << y << "] \n";
614+
gzerr << "Failed to get pixel value at ["
615+
<< x << " " << y << "] \n";
608616
continue;
609617
}
610618
clr.Set(firgb.rgbRed / 255.0f, firgb.rgbGreen / 255.0f,
@@ -628,8 +636,8 @@ math::Color Image::MaxColor() const
628636
if (this->dataPtr->PixelIndex(
629637
this->dataPtr->bitmap, x, y, clr) == FALSE)
630638
{
631-
gzerr << "Image: Coordinates out of range ["
632-
<< x << " " << y << "] \n";
639+
gzerr << "Failed to get pixel value at ["
640+
<< x << " " << y << "] \n";
633641
continue;
634642
}
635643

@@ -651,6 +659,9 @@ BOOL Image::Implementation::PixelIndex(
651659
if (!_dib)
652660
return FALSE;
653661

662+
if (_x >= FreeImage_GetWidth(_dib) || _y >= FreeImage_GetHeight(_dib))
663+
return FALSE;
664+
654665
FREE_IMAGE_TYPE imageType = FreeImage_GetImageType(_dib);
655666
// 8 bit images
656667
if (imageType == FIT_BITMAP)
@@ -671,19 +682,49 @@ BOOL Image::Implementation::PixelIndex(
671682
// 16 bit images
672683
else if (imageType == FIT_UINT16)
673684
{
674-
if ((_x < FreeImage_GetWidth(_dib)) && (_y < FreeImage_GetHeight(_dib)))
675-
{
676-
WORD *bits = reinterpret_cast<WORD *>(FreeImage_GetScanLine(_dib, _y));
677-
uint16_t word = static_cast<uint16_t>(bits[_x]);
678-
// convert to float value between 0-1
679-
float value = word / static_cast<float>(math::MAX_UI16);
680-
_color.Set(value, value, value);
681-
}
682-
else
683-
{
684-
return FALSE;
685-
}
685+
WORD *bits = reinterpret_cast<WORD *>(FreeImage_GetScanLine(_dib, _y));
686+
uint16_t word = static_cast<uint16_t>(bits[_x]);
687+
// convert to float value between 0-1
688+
float value = word / static_cast<float>(math::MAX_UI16);
689+
_color.Set(value, value, value);
690+
}
691+
else if (imageType == FIT_INT16)
692+
{
693+
WORD *bits = reinterpret_cast<WORD *>(FreeImage_GetScanLine(_dib, _y));
694+
int16_t word = static_cast<int16_t>(bits[_x]);
695+
// convert to float value between 0-1
696+
float value = word / static_cast<float>(math::MAX_I16);
697+
_color.Set(value, value, value);
698+
}
699+
else if (imageType == FIT_RGB16)
700+
{
701+
const unsigned int channels = 3u;
702+
WORD *bits = reinterpret_cast<WORD *>(FreeImage_GetScanLine(_dib, _y));
703+
uint16_t r = static_cast<uint16_t>(bits[_x * channels]);
704+
uint16_t g = static_cast<uint16_t>(bits[_x * channels + 1]);
705+
uint16_t b = static_cast<uint16_t>(bits[_x * channels + 2]);
706+
// convert to float value between 0-1
707+
float valueR = r / static_cast<float>(math::MAX_UI16);
708+
float valueG = g / static_cast<float>(math::MAX_UI16);
709+
float valueB = b / static_cast<float>(math::MAX_UI16);
710+
_color.Set(valueR, valueG, valueB);
711+
}
712+
else if (imageType == FIT_RGBA16)
713+
{
714+
const unsigned int channels = 4u;
715+
WORD *bits = reinterpret_cast<WORD *>(FreeImage_GetScanLine(_dib, _y));
716+
uint16_t r = static_cast<uint16_t>(bits[_x * channels]);
717+
uint16_t g = static_cast<uint16_t>(bits[_x * channels + 1]);
718+
uint16_t b = static_cast<uint16_t>(bits[_x * channels + 2]);
719+
uint16_t a = static_cast<uint16_t>(bits[_x * channels + 3]);
720+
// convert to float value between 0-1
721+
float valueR = r / static_cast<float>(math::MAX_UI16);
722+
float valueG = g / static_cast<float>(math::MAX_UI16);
723+
float valueB = b / static_cast<float>(math::MAX_UI16);
724+
float valueA = a / static_cast<float>(math::MAX_UI16);
725+
_color.Set(valueR, valueG, valueB, valueA);
686726
}
727+
687728
return TRUE;
688729
}
689730

@@ -740,6 +781,8 @@ Image::PixelFormatType Image::PixelFormat() const
740781
}
741782
else if (type == FIT_RGB16)
742783
fmt = RGB_INT16;
784+
else if (type == FIT_RGBA16)
785+
fmt = RGBA_INT16;
743786
else if (type == FIT_RGBF)
744787
fmt = RGB_FLOAT32;
745788
else if (type == FIT_UINT16 || type == FIT_INT16)

graphics/src/Image_TEST.cc

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,8 @@ TEST_F(ImageTest, ConvertPixelFormat)
468468
Image::ConvertPixelFormat("RGBA_INT8"));
469469
EXPECT_EQ(Image::PixelFormatType::RGB_INT16,
470470
Image::ConvertPixelFormat("RGB_INT16"));
471+
EXPECT_EQ(Image::PixelFormatType::RGBA_INT16,
472+
Image::ConvertPixelFormat("RGBA_INT16"));
471473
EXPECT_EQ(Image::PixelFormatType::RGB_INT32,
472474
Image::ConvertPixelFormat("RGB_INT32"));
473475
EXPECT_EQ(Image::PixelFormatType::BGR_INT8,
@@ -728,6 +730,53 @@ TEST_F(ImageTest, Grayscale)
728730
}
729731
}
730732

733+
734+
/////////////////////////////////////////////////
735+
TEST_F(ImageTest, Color16bit)
736+
{
737+
{
738+
common::Image img;
739+
std::string fileName = common::testing::TestFile("data",
740+
"rgb_16bit.png");
741+
EXPECT_EQ(0, img.Load(fileName));
742+
unsigned int width = 4u;
743+
unsigned int height = 4u;
744+
unsigned int channels = 3u;
745+
unsigned int bpp = channels * 16u;
746+
EXPECT_TRUE(img.Valid());
747+
EXPECT_EQ(width, img.Width());
748+
EXPECT_EQ(height, img.Height());
749+
EXPECT_EQ(bpp, img.BPP());
750+
EXPECT_EQ(width * bpp / 8u, img.Pitch());
751+
EXPECT_EQ(common::Image::PixelFormatType::RGB_INT16, img.PixelFormat());
752+
math::Color maxColor(0.0f, 0.0f, 0.847f);
753+
EXPECT_NEAR(maxColor.R(), img.MaxColor().R(), 1e-3);
754+
EXPECT_NEAR(maxColor.G(), img.MaxColor().G(), 1e-3);
755+
EXPECT_NEAR(maxColor.B(), img.MaxColor().B(), 1e-3);
756+
}
757+
{
758+
common::Image img;
759+
std::string fileName = common::testing::TestFile("data",
760+
"rgba_16bit.png");
761+
EXPECT_EQ(0, img.Load(fileName));
762+
unsigned int width = 4u;
763+
unsigned int height = 4u;
764+
unsigned int channels = 4u;
765+
unsigned int bpp = channels * 16u;
766+
EXPECT_TRUE(img.Valid());
767+
EXPECT_EQ(width, img.Width());
768+
EXPECT_EQ(height, img.Height());
769+
EXPECT_EQ(bpp, img.BPP());
770+
EXPECT_EQ(width * bpp / 8u, img.Pitch());
771+
EXPECT_EQ(common::Image::PixelFormatType::RGBA_INT16, img.PixelFormat());
772+
math::Color maxColor(0.0f, 0.0f, 0.847f, 0.5f);
773+
EXPECT_NEAR(maxColor.R(), img.MaxColor().R(), 1e-3);
774+
EXPECT_NEAR(maxColor.G(), img.MaxColor().G(), 1e-3);
775+
EXPECT_NEAR(maxColor.B(), img.MaxColor().B(), 1e-3);
776+
EXPECT_NEAR(maxColor.A(), img.MaxColor().A(), 1e-3);
777+
}
778+
}
779+
731780
using string_int2 = std::tuple<const char *, unsigned int, unsigned int>;
732781

733782
class ImagePerformanceTest : public ImageTest,

0 commit comments

Comments
 (0)