Skip to content

Commit 5d8d665

Browse files
committed
Handle color 16 bit images
Signed-off-by: Ian Chen <[email protected]>
1 parent ac476aa commit 5d8d665

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
@@ -415,16 +415,23 @@ math::Color Image::Pixel(unsigned int _x, unsigned int _y) const
415415
if (!this->Valid())
416416
return clr;
417417

418+
if (_x >= this->Width() || _y >= this->Height())
419+
{
420+
gzerr << "Image: Coordinates out of range["
421+
<< _x << " " << _y << "] \n";
422+
return clr;
423+
}
424+
418425
FREE_IMAGE_COLOR_TYPE type = FreeImage_GetColorType(this->dataPtr->bitmap);
426+
FREE_IMAGE_TYPE imageType = FreeImage_GetImageType(this->dataPtr->bitmap);
419427

420-
if (type == FIC_RGB || type == FIC_RGBALPHA)
428+
if ((type == FIC_RGB || type == FIC_RGBALPHA) && (imageType == FIT_BITMAP))
421429
{
422430
RGBQUAD firgb;
423-
424431
if (FreeImage_GetPixelColor(this->dataPtr->bitmap, _x, _y, &firgb) == FALSE)
425432
{
426-
gzerr << "Image: Coordinates out of range["
427-
<< _x << " " << _y << "] \n";
433+
gzerr << "Failed to get pixel value at ["
434+
<< _x << " " << _y << "] \n";
428435
return clr;
429436
}
430437
clr.Set(firgb.rgbRed / 255.0f, firgb.rgbGreen / 255.0f,
@@ -435,8 +442,8 @@ math::Color Image::Pixel(unsigned int _x, unsigned int _y) const
435442
if (this->dataPtr->PixelIndex(
436443
this->dataPtr->bitmap, _x, _y, clr) == FALSE)
437444
{
438-
gzerr << "Image: Coordinates out of range ["
439-
<< _x << " " << _y << "] \n";
445+
gzerr << "Failed to get pixel value at ["
446+
<< _x << " " << _y << "] \n";
440447
return clr;
441448
}
442449
}
@@ -483,8 +490,9 @@ math::Color Image::MaxColor() const
483490
return clr;
484491

485492
FREE_IMAGE_COLOR_TYPE type = FreeImage_GetColorType(this->dataPtr->bitmap);
493+
FREE_IMAGE_TYPE imageType = FreeImage_GetImageType(this->dataPtr->bitmap);
486494

487-
if (type == FIC_RGB || type == FIC_RGBALPHA)
495+
if ((type == FIC_RGB || type == FIC_RGBALPHA) && (imageType == FIT_BITMAP))
488496
{
489497
RGBQUAD firgb;
490498

@@ -497,8 +505,8 @@ math::Color Image::MaxColor() const
497505
if (FALSE ==
498506
FreeImage_GetPixelColor(this->dataPtr->bitmap, x, y, &firgb))
499507
{
500-
gzerr << "Image: Coordinates out of range["
501-
<< x << " " << y << "] \n";
508+
gzerr << "Failed to get pixel value at ["
509+
<< x << " " << y << "] \n";
502510
continue;
503511
}
504512
clr.Set(firgb.rgbRed / 255.0f, firgb.rgbGreen / 255.0f,
@@ -522,8 +530,8 @@ math::Color Image::MaxColor() const
522530
if (this->dataPtr->PixelIndex(
523531
this->dataPtr->bitmap, x, y, clr) == FALSE)
524532
{
525-
gzerr << "Image: Coordinates out of range ["
526-
<< x << " " << y << "] \n";
533+
gzerr << "Failed to get pixel value at ["
534+
<< x << " " << y << "] \n";
527535
continue;
528536
}
529537

@@ -545,6 +553,9 @@ BOOL Image::Implementation::PixelIndex(
545553
if (!_dib)
546554
return FALSE;
547555

556+
if (_x >= FreeImage_GetWidth(_dib) || _y >= FreeImage_GetHeight(_dib))
557+
return FALSE;
558+
548559
FREE_IMAGE_TYPE imageType = FreeImage_GetImageType(_dib);
549560
// 8 bit images
550561
if (imageType == FIT_BITMAP)
@@ -565,19 +576,49 @@ BOOL Image::Implementation::PixelIndex(
565576
// 16 bit images
566577
else if (imageType == FIT_UINT16)
567578
{
568-
if ((_x < FreeImage_GetWidth(_dib)) && (_y < FreeImage_GetHeight(_dib)))
569-
{
570-
WORD *bits = reinterpret_cast<WORD *>(FreeImage_GetScanLine(_dib, _y));
571-
uint16_t word = static_cast<uint16_t>(bits[_x]);
572-
// convert to float value between 0-1
573-
float value = word / static_cast<float>(math::MAX_UI16);
574-
_color.Set(value, value, value);
575-
}
576-
else
577-
{
578-
return FALSE;
579-
}
579+
WORD *bits = reinterpret_cast<WORD *>(FreeImage_GetScanLine(_dib, _y));
580+
uint16_t word = static_cast<uint16_t>(bits[_x]);
581+
// convert to float value between 0-1
582+
float value = word / static_cast<float>(math::MAX_UI16);
583+
_color.Set(value, value, value);
580584
}
585+
else if (imageType == FIT_INT16)
586+
{
587+
WORD *bits = reinterpret_cast<WORD *>(FreeImage_GetScanLine(_dib, _y));
588+
int16_t word = static_cast<int16_t>(bits[_x]);
589+
// convert to float value between 0-1
590+
float value = word / static_cast<float>(math::MAX_I16);
591+
_color.Set(value, value, value);
592+
}
593+
else if (imageType == FIT_RGB16)
594+
{
595+
const unsigned int channels = 3u;
596+
WORD *bits = reinterpret_cast<WORD *>(FreeImage_GetScanLine(_dib, _y));
597+
uint16_t r = static_cast<uint16_t>(bits[_x * channels]);
598+
uint16_t g = static_cast<uint16_t>(bits[_x * channels + 1]);
599+
uint16_t b = static_cast<uint16_t>(bits[_x * channels + 2]);
600+
// convert to float value between 0-1
601+
float valueR = r / static_cast<float>(math::MAX_UI16);
602+
float valueG = g / static_cast<float>(math::MAX_UI16);
603+
float valueB = b / static_cast<float>(math::MAX_UI16);
604+
_color.Set(valueR, valueG, valueB);
605+
}
606+
else if (imageType == FIT_RGBA16)
607+
{
608+
const unsigned int channels = 4u;
609+
WORD *bits = reinterpret_cast<WORD *>(FreeImage_GetScanLine(_dib, _y));
610+
uint16_t r = static_cast<uint16_t>(bits[_x * channels]);
611+
uint16_t g = static_cast<uint16_t>(bits[_x * channels + 1]);
612+
uint16_t b = static_cast<uint16_t>(bits[_x * channels + 2]);
613+
uint16_t a = static_cast<uint16_t>(bits[_x * channels + 3]);
614+
// convert to float value between 0-1
615+
float valueR = r / static_cast<float>(math::MAX_UI16);
616+
float valueG = g / static_cast<float>(math::MAX_UI16);
617+
float valueB = b / static_cast<float>(math::MAX_UI16);
618+
float valueA = a / static_cast<float>(math::MAX_UI16);
619+
_color.Set(valueR, valueG, valueB, valueA);
620+
}
621+
581622
return TRUE;
582623
}
583624

@@ -634,6 +675,8 @@ Image::PixelFormatType Image::PixelFormat() const
634675
}
635676
else if (type == FIT_RGB16)
636677
fmt = RGB_INT16;
678+
else if (type == FIT_RGBA16)
679+
fmt = RGBA_INT16;
637680
else if (type == FIT_RGBF)
638681
fmt = RGB_FLOAT32;
639682
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
@@ -413,6 +413,8 @@ TEST_F(ImageTest, ConvertPixelFormat)
413413
Image::ConvertPixelFormat("RGBA_INT8"));
414414
EXPECT_EQ(Image::PixelFormatType::RGB_INT16,
415415
Image::ConvertPixelFormat("RGB_INT16"));
416+
EXPECT_EQ(Image::PixelFormatType::RGBA_INT16,
417+
Image::ConvertPixelFormat("RGBA_INT16"));
416418
EXPECT_EQ(Image::PixelFormatType::RGB_INT32,
417419
Image::ConvertPixelFormat("RGB_INT32"));
418420
EXPECT_EQ(Image::PixelFormatType::BGR_INT8,
@@ -673,6 +675,53 @@ TEST_F(ImageTest, Grayscale)
673675
}
674676
}
675677

678+
679+
/////////////////////////////////////////////////
680+
TEST_F(ImageTest, Color16bit)
681+
{
682+
{
683+
common::Image img;
684+
std::string fileName = common::testing::TestFile("data",
685+
"rgb_16bit.png");
686+
EXPECT_EQ(0, img.Load(fileName));
687+
unsigned int width = 4u;
688+
unsigned int height = 4u;
689+
unsigned int channels = 3u;
690+
unsigned int bpp = channels * 16u;
691+
EXPECT_TRUE(img.Valid());
692+
EXPECT_EQ(width, img.Width());
693+
EXPECT_EQ(height, img.Height());
694+
EXPECT_EQ(bpp, img.BPP());
695+
EXPECT_EQ(width * bpp / 8u, img.Pitch());
696+
EXPECT_EQ(common::Image::PixelFormatType::RGB_INT16, img.PixelFormat());
697+
math::Color maxColor(0.0f, 0.0f, 0.847f);
698+
EXPECT_NEAR(maxColor.R(), img.MaxColor().R(), 1e-3);
699+
EXPECT_NEAR(maxColor.G(), img.MaxColor().G(), 1e-3);
700+
EXPECT_NEAR(maxColor.B(), img.MaxColor().B(), 1e-3);
701+
}
702+
{
703+
common::Image img;
704+
std::string fileName = common::testing::TestFile("data",
705+
"rgba_16bit.png");
706+
EXPECT_EQ(0, img.Load(fileName));
707+
unsigned int width = 4u;
708+
unsigned int height = 4u;
709+
unsigned int channels = 4u;
710+
unsigned int bpp = channels * 16u;
711+
EXPECT_TRUE(img.Valid());
712+
EXPECT_EQ(width, img.Width());
713+
EXPECT_EQ(height, img.Height());
714+
EXPECT_EQ(bpp, img.BPP());
715+
EXPECT_EQ(width * bpp / 8u, img.Pitch());
716+
EXPECT_EQ(common::Image::PixelFormatType::RGBA_INT16, img.PixelFormat());
717+
math::Color maxColor(0.0f, 0.0f, 0.847f, 0.5f);
718+
EXPECT_NEAR(maxColor.R(), img.MaxColor().R(), 1e-3);
719+
EXPECT_NEAR(maxColor.G(), img.MaxColor().G(), 1e-3);
720+
EXPECT_NEAR(maxColor.B(), img.MaxColor().B(), 1e-3);
721+
EXPECT_NEAR(maxColor.A(), img.MaxColor().A(), 1e-3);
722+
}
723+
}
724+
676725
using string_int2 = std::tuple<const char *, unsigned int, unsigned int>;
677726

678727
class ImagePerformanceTest : public ImageTest,

0 commit comments

Comments
 (0)