1919#endif
2020#include < FreeImage.h>
2121
22+ #include < cstdint>
2223#include < cstring>
2324#include < string>
2425
@@ -37,11 +38,17 @@ namespace gz
3738 class Image ::Implementation
3839 {
3940 // / \brief bitmap data
40- public: FIBITMAP *bitmap;
41+ public: FIBITMAP *bitmap{ nullptr } ;
4142
4243 // / \brief path name of the image file
4344 public: std::string fullName;
4445
46+ // / \brief Color type for this image
47+ public: FREE_IMAGE_COLOR_TYPE colorType{FIC_RGB};
48+
49+ // / \brief Image type, i.e. pixel format
50+ public: FREE_IMAGE_TYPE imageType{FIT_UNKNOWN};
51+
4552 // / \brief Implementation of Data, returns vector of bytes
4653 public: std::vector<unsigned char > DataImpl (FIBITMAP *_img) const ;
4754
@@ -150,6 +157,9 @@ int Image::Load(const std::string &_filename)
150157 return -1 ;
151158 }
152159
160+ this ->dataPtr ->colorType = FreeImage_GetColorType (this ->dataPtr ->bitmap );
161+ this ->dataPtr ->imageType = FreeImage_GetImageType (this ->dataPtr ->bitmap );
162+
153163 return 0 ;
154164 }
155165
@@ -257,6 +267,8 @@ void Image::SetFromData(const unsigned char *_data,
257267 this ->Height ());
258268 FreeImage_Unload (toDelete);
259269 }
270+ this ->dataPtr ->colorType = FreeImage_GetColorType (this ->dataPtr ->bitmap );
271+ this ->dataPtr ->imageType = FreeImage_GetImageType (this ->dataPtr ->bitmap );
260272}
261273
262274// ////////////////////////////////////////////////
@@ -285,6 +297,8 @@ void Image::SetFromCompressedData(unsigned char *_data,
285297 FIMEMORY *fiMem = FreeImage_OpenMemory (_data, _size);
286298 this ->dataPtr ->bitmap = FreeImage_LoadFromMemory (format, fiMem);
287299 FreeImage_CloseMemory (fiMem);
300+ this ->dataPtr ->colorType = FreeImage_GetColorType (this ->dataPtr ->bitmap );
301+ this ->dataPtr ->imageType = FreeImage_GetImageType (this ->dataPtr ->bitmap );
288302 }
289303 else
290304 {
@@ -415,16 +429,22 @@ math::Color Image::Pixel(unsigned int _x, unsigned int _y) const
415429 if (!this ->Valid ())
416430 return clr;
417431
418- FREE_IMAGE_COLOR_TYPE type = FreeImage_GetColorType (this ->dataPtr ->bitmap );
432+ if (_x >= this ->Width () || _y >= this ->Height ())
433+ {
434+ gzerr << " Image: Coordinates out of range["
435+ << _x << " , " << _y << " ] \n " ;
436+ return clr;
437+ }
419438
420- if (type == FIC_RGB || type == FIC_RGBALPHA)
439+ if ((this ->dataPtr ->colorType == FIC_RGB ||
440+ this ->dataPtr ->colorType == FIC_RGBALPHA) &&
441+ (this ->dataPtr ->imageType == FIT_BITMAP))
421442 {
422443 RGBQUAD firgb;
423-
424444 if (FreeImage_GetPixelColor (this ->dataPtr ->bitmap , _x, _y, &firgb) == FALSE )
425445 {
426- gzerr << " Image: Coordinates out of range ["
427- << _x << " " << _y << " ] \n " ;
446+ gzerr << " Failed to get pixel value at ["
447+ << _x << " , " << _y << " ] \n " ;
428448 return clr;
429449 }
430450 clr.Set (firgb.rgbRed / 255 .0f , firgb.rgbGreen / 255 .0f ,
@@ -435,8 +455,8 @@ math::Color Image::Pixel(unsigned int _x, unsigned int _y) const
435455 if (this ->dataPtr ->PixelIndex (
436456 this ->dataPtr ->bitmap , _x, _y, clr) == FALSE )
437457 {
438- gzerr << " Image: Coordinates out of range ["
439- << _x << " " << _y << " ] \n " ;
458+ gzerr << " Failed to get pixel value at ["
459+ << _x << " , " << _y << " ] \n " ;
440460 return clr;
441461 }
442462 }
@@ -473,64 +493,20 @@ math::Color Image::AvgColor() const
473493// ////////////////////////////////////////////////
474494math::Color Image::MaxColor () const
475495{
476- unsigned int x, y;
477- math::Color clr;
478496 math::Color maxClr;
479497
480- maxClr.Set (0 , 0 , 0 , 0 );
481-
482498 if (!this ->Valid ())
483- return clr;
484-
485- FREE_IMAGE_COLOR_TYPE type = FreeImage_GetColorType (this ->dataPtr ->bitmap );
486-
487- if (type == FIC_RGB || type == FIC_RGBALPHA)
488- {
489- RGBQUAD firgb;
499+ return maxClr;
490500
491- for (y = 0 ; y < this ->Height (); y++)
492- {
493- for (x = 0 ; x < this ->Width (); x++)
494- {
495- clr.Set (0 , 0 , 0 , 0 );
496-
497- if (FALSE ==
498- FreeImage_GetPixelColor (this ->dataPtr ->bitmap , x, y, &firgb))
499- {
500- gzerr << " Image: Coordinates out of range["
501- << x << " " << y << " ] \n " ;
502- continue ;
503- }
504- clr.Set (firgb.rgbRed / 255 .0f , firgb.rgbGreen / 255 .0f ,
505- firgb.rgbBlue / 255 .0f );
506-
507- if (clr.R () + clr.G () + clr.B () > maxClr.R () + maxClr.G () + maxClr.B ())
508- {
509- maxClr = clr;
510- }
511- }
512- }
513- }
514- else
501+ maxClr.Set (0 , 0 , 0 , 0 );
502+ for (unsigned int y = 0 ; y < this ->Height (); y++)
515503 {
516- for (y = 0 ; y < this ->Height (); y ++)
504+ for (unsigned int x = 0 ; x < this ->Width (); x ++)
517505 {
518- for (x = 0 ; x < this ->Width (); x++)
506+ math::Color clr = this ->Pixel (x, y);
507+ if (clr.R () + clr.G () + clr.B () > maxClr.R () + maxClr.G () + maxClr.B ())
519508 {
520- clr.Set (0 , 0 , 0 , 0 );
521-
522- if (this ->dataPtr ->PixelIndex (
523- this ->dataPtr ->bitmap , x, y, clr) == FALSE )
524- {
525- gzerr << " Image: Coordinates out of range ["
526- << x << " " << y << " ] \n " ;
527- continue ;
528- }
529-
530- if (clr.R () + clr.G () + clr.B () > maxClr.R () + maxClr.G () + maxClr.B ())
531- {
532- maxClr = clr;
533- }
509+ maxClr = clr;
534510 }
535511 }
536512 }
@@ -545,9 +521,11 @@ BOOL Image::Implementation::PixelIndex(
545521 if (!_dib)
546522 return FALSE ;
547523
548- FREE_IMAGE_TYPE imageType = FreeImage_GetImageType (_dib);
524+ if (_x >= FreeImage_GetWidth (_dib) || _y >= FreeImage_GetHeight (_dib))
525+ return FALSE ;
526+
549527 // 8 bit images
550- if (imageType == FIT_BITMAP)
528+ if (this -> imageType == FIT_BITMAP)
551529 {
552530 BYTE byteValue;
553531 // FreeImage_GetPixelIndex should also work with 1 and 4 bit images
@@ -563,21 +541,51 @@ BOOL Image::Implementation::PixelIndex(
563541 _color.Set (value, value, value);
564542 }
565543 // 16 bit images
566- else if (imageType == FIT_UINT16)
544+ else if (this -> imageType == FIT_UINT16)
567545 {
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- }
546+ WORD *bits = reinterpret_cast <WORD *>(FreeImage_GetScanLine (_dib, _y));
547+ uint16_t word = static_cast <uint16_t >(bits[_x]);
548+ // convert to float value between 0-1
549+ float value = word / static_cast <float >(math::MAX_UI16);
550+ _color.Set (value, value, value);
580551 }
552+ else if (this ->imageType == FIT_INT16)
553+ {
554+ WORD *bits = reinterpret_cast <WORD *>(FreeImage_GetScanLine (_dib, _y));
555+ int16_t word = static_cast <int16_t >(bits[_x]);
556+ // convert to float value between 0-1
557+ float value = word / static_cast <float >(math::MAX_I16);
558+ _color.Set (value, value, value);
559+ }
560+ else if (this ->imageType == FIT_RGB16)
561+ {
562+ const unsigned int channels = 3u ;
563+ WORD *bits = reinterpret_cast <WORD *>(FreeImage_GetScanLine (_dib, _y));
564+ uint16_t r = static_cast <uint16_t >(bits[_x * channels]);
565+ uint16_t g = static_cast <uint16_t >(bits[_x * channels + 1 ]);
566+ uint16_t b = static_cast <uint16_t >(bits[_x * channels + 2 ]);
567+ // convert to float value between 0-1
568+ float valueR = r / static_cast <float >(math::MAX_UI16);
569+ float valueG = g / static_cast <float >(math::MAX_UI16);
570+ float valueB = b / static_cast <float >(math::MAX_UI16);
571+ _color.Set (valueR, valueG, valueB);
572+ }
573+ else if (this ->imageType == FIT_RGBA16)
574+ {
575+ const unsigned int channels = 4u ;
576+ WORD *bits = reinterpret_cast <WORD *>(FreeImage_GetScanLine (_dib, _y));
577+ uint16_t r = static_cast <uint16_t >(bits[_x * channels]);
578+ uint16_t g = static_cast <uint16_t >(bits[_x * channels + 1 ]);
579+ uint16_t b = static_cast <uint16_t >(bits[_x * channels + 2 ]);
580+ uint16_t a = static_cast <uint16_t >(bits[_x * channels + 3 ]);
581+ // convert to float value between 0-1
582+ float valueR = r / static_cast <float >(math::MAX_UI16);
583+ float valueG = g / static_cast <float >(math::MAX_UI16);
584+ float valueB = b / static_cast <float >(math::MAX_UI16);
585+ float valueA = a / static_cast <float >(math::MAX_UI16);
586+ _color.Set (valueR, valueG, valueB, valueA);
587+ }
588+
581589 return TRUE ;
582590}
583591
@@ -634,6 +642,8 @@ Image::PixelFormatType Image::PixelFormat() const
634642 }
635643 else if (type == FIT_RGB16)
636644 fmt = RGB_INT16;
645+ else if (type == FIT_RGBA16)
646+ fmt = RGBA_INT16;
637647 else if (type == FIT_RGBF)
638648 fmt = RGB_FLOAT32;
639649 else if (type == FIT_UINT16 || type == FIT_INT16)
0 commit comments