Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 74 additions & 24 deletions Modules/IO/ImageBase/include/itkImageIOBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@

#include <fstream>
#include <string>
#include <type_traits> // For is_same_v and is_signed_v.

namespace itk
{
Expand Down Expand Up @@ -341,6 +342,27 @@ class ITKIOImageBase_EXPORT ImageIOBase : public LightProcessObject
* used for writing output files. */
static std::string GetComponentTypeAsString(IOComponentEnum);

/** Tells whether or not the specified component type is a floating point type. */
static constexpr bool
IsComponentTypeFloatingPoint(const IOComponentEnum componentEnum)
{
return GetComponentTypeTraits(componentEnum).isFloatingPoint;
}

/** Tells whether or not the specified component type is an unsigned integer type. */
static constexpr bool
IsComponentTypeUnsigned(const IOComponentEnum componentEnum)
{
return GetComponentTypeTraits(componentEnum).isUnsigned;
}

/** Returns the number of bits of the specified component type. */
static constexpr size_t
GetNumberOfBitsOfComponentType(const IOComponentEnum componentEnum)
{
return GetComponentTypeTraits(componentEnum).sizeOfComponent * CHAR_BIT;
}

/** Convenience method returns the IOComponentEnum corresponding to a string. */
static IOComponentEnum
GetComponentTypeFromString(const std::string & typeString);
Expand Down Expand Up @@ -582,8 +604,23 @@ class ITKIOImageBase_EXPORT ImageIOBase : public LightProcessObject
template <typename TPixel>
struct MapPixelType
{
static constexpr IOComponentEnum CType = IOComponentEnum::UNKNOWNCOMPONENTTYPE;
static constexpr IOComponentEnum CType =
std::is_same_v<TPixel, char> ? (std::is_signed_v<char> ? IOComponentEnum::CHAR : IOComponentEnum::UCHAR)
: std::is_same_v<TPixel, signed char> ? IOComponentEnum::CHAR
: std::is_same_v<TPixel, unsigned char> ? IOComponentEnum::UCHAR
: std::is_same_v<TPixel, short> ? IOComponentEnum::SHORT
: std::is_same_v<TPixel, unsigned short> ? IOComponentEnum::USHORT
: std::is_same_v<TPixel, int> ? IOComponentEnum::INT
: std::is_same_v<TPixel, unsigned int> ? IOComponentEnum::UINT
: std::is_same_v<TPixel, long> ? IOComponentEnum::LONG
: std::is_same_v<TPixel, unsigned long> ? IOComponentEnum::ULONG
: std::is_same_v<TPixel, long long> ? IOComponentEnum::LONGLONG
: std::is_same_v<TPixel, unsigned long long> ? IOComponentEnum::ULONGLONG
: std::is_same_v<TPixel, float> ? IOComponentEnum::FLOAT
: std::is_same_v<TPixel, double> ? IOComponentEnum::DOUBLE
: IOComponentEnum::UNKNOWNCOMPONENTTYPE;
};

template <typename TPixel>
void
SetPixelTypeInfo(const TPixel *)
Expand Down Expand Up @@ -921,6 +958,42 @@ class ITKIOImageBase_EXPORT ImageIOBase : public LightProcessObject
const ImageIORegion & pasteRegion) const;

private:
struct ComponentTypeTraits
{
bool isFloatingPoint;
bool isUnsigned;
size_t sizeOfComponent;

template <typename... TComponent>
static constexpr ComponentTypeTraits
Get(const IOComponentEnum componentEnum)
{
ComponentTypeTraits result{};
return ((MapPixelType<TComponent>::CType == componentEnum
? result = { std::is_floating_point_v<TComponent>, std::is_unsigned_v<TComponent>, sizeof(TComponent) }
: result),
...);
}
};


static constexpr ComponentTypeTraits
GetComponentTypeTraits(const IOComponentEnum componentEnum)
{
return ComponentTypeTraits::Get<char,
unsigned char,
short,
unsigned short,
int,
unsigned int,
long,
unsigned long,
long long,
unsigned long long,
float,
double>(componentEnum);
}

bool
HasSupportedExtension(const char *, const ArrayOfExtensionsType &, bool ignoreCase = true);

Expand All @@ -944,29 +1017,6 @@ ReadRawBytesAfterSwapping(IOComponentEnum componentType,
IOByteOrderEnum byteOrder,
SizeValueType numberOfComponents);

#define IMAGEIOBASE_TYPEMAP(type, ctype) \
template <> \
struct ImageIOBase::MapPixelType<type> \
{ \
static constexpr IOComponentEnum CType = ctype; \
}

// the following typemaps are not platform independent
IMAGEIOBASE_TYPEMAP(signed char, IOComponentEnum::CHAR);
IMAGEIOBASE_TYPEMAP(char, std::numeric_limits<char>::is_signed ? IOComponentEnum::CHAR : IOComponentEnum::UCHAR);
IMAGEIOBASE_TYPEMAP(unsigned char, IOComponentEnum::UCHAR);
IMAGEIOBASE_TYPEMAP(short, IOComponentEnum::SHORT);
IMAGEIOBASE_TYPEMAP(unsigned short, IOComponentEnum::USHORT);
IMAGEIOBASE_TYPEMAP(int, IOComponentEnum::INT);
IMAGEIOBASE_TYPEMAP(unsigned int, IOComponentEnum::UINT);
IMAGEIOBASE_TYPEMAP(long, IOComponentEnum::LONG);
IMAGEIOBASE_TYPEMAP(unsigned long, IOComponentEnum::ULONG);
IMAGEIOBASE_TYPEMAP(long long, IOComponentEnum::LONGLONG);
IMAGEIOBASE_TYPEMAP(unsigned long long, IOComponentEnum::ULONGLONG);
IMAGEIOBASE_TYPEMAP(float, IOComponentEnum::FLOAT);
IMAGEIOBASE_TYPEMAP(double, IOComponentEnum::DOUBLE);
#undef IMAGIOBASE_TYPEMAP

} // end namespace itk

#endif // itkImageIOBase_h
79 changes: 77 additions & 2 deletions Modules/IO/ImageBase/test/itkImageIOBaseTest.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@

namespace
{
// Tests `MapPixelType<TPixel>::CType`
class TestMapPixelType : private itk::ImageIOBase
// Tests `MapPixelType<TPixel>::CType` and the estimation of component type traits.
class TestMapPixelTypeAndComponentTypeTraits : private itk::ImageIOBase
{
struct UnknownComponentType
{};
Expand Down Expand Up @@ -59,6 +59,81 @@ class TestMapPixelType : private itk::ImageIOBase
static_assert(MapPixelType<int64_t>::CType == IOComponentEnum::INT64);
static_assert(MapPixelType<float>::CType == IOComponentEnum::FLOAT32);
static_assert(MapPixelType<double>::CType == IOComponentEnum::FLOAT64);

// Tests IsComponentTypeFloatingPoint:
static_assert(!IsComponentTypeFloatingPoint(IOComponentEnum::UNKNOWNCOMPONENTTYPE));
static_assert(!IsComponentTypeFloatingPoint(IOComponentEnum::UCHAR));
static_assert(!IsComponentTypeFloatingPoint(IOComponentEnum::CHAR));
static_assert(!IsComponentTypeFloatingPoint(IOComponentEnum::USHORT));
static_assert(!IsComponentTypeFloatingPoint(IOComponentEnum::SHORT));
static_assert(!IsComponentTypeFloatingPoint(IOComponentEnum::UINT));
static_assert(!IsComponentTypeFloatingPoint(IOComponentEnum::INT));
static_assert(!IsComponentTypeFloatingPoint(IOComponentEnum::ULONG));
static_assert(!IsComponentTypeFloatingPoint(IOComponentEnum::LONG));
static_assert(!IsComponentTypeFloatingPoint(IOComponentEnum::LONGLONG));
static_assert(!IsComponentTypeFloatingPoint(IOComponentEnum::ULONGLONG));
static_assert(IsComponentTypeFloatingPoint(IOComponentEnum::FLOAT));
static_assert(IsComponentTypeFloatingPoint(IOComponentEnum::DOUBLE));
static_assert(!IsComponentTypeFloatingPoint(IOComponentEnum::UINT8));
static_assert(!IsComponentTypeFloatingPoint(IOComponentEnum::INT8));
static_assert(!IsComponentTypeFloatingPoint(IOComponentEnum::UINT16));
static_assert(!IsComponentTypeFloatingPoint(IOComponentEnum::INT16));
static_assert(!IsComponentTypeFloatingPoint(IOComponentEnum::UINT32));
static_assert(!IsComponentTypeFloatingPoint(IOComponentEnum::INT32));
static_assert(!IsComponentTypeFloatingPoint(IOComponentEnum::UINT64));
static_assert(!IsComponentTypeFloatingPoint(IOComponentEnum::INT64));
static_assert(IsComponentTypeFloatingPoint(IOComponentEnum::FLOAT32));
static_assert(IsComponentTypeFloatingPoint(IOComponentEnum::FLOAT64));

// Tests IsComponentTypeUnsigned:
static_assert(!IsComponentTypeUnsigned(IOComponentEnum::UNKNOWNCOMPONENTTYPE));
static_assert(IsComponentTypeUnsigned(IOComponentEnum::UCHAR));
static_assert(!IsComponentTypeUnsigned(IOComponentEnum::CHAR));
static_assert(IsComponentTypeUnsigned(IOComponentEnum::USHORT));
static_assert(!IsComponentTypeUnsigned(IOComponentEnum::SHORT));
static_assert(IsComponentTypeUnsigned(IOComponentEnum::UINT));
static_assert(!IsComponentTypeUnsigned(IOComponentEnum::INT));
static_assert(IsComponentTypeUnsigned(IOComponentEnum::ULONG));
static_assert(!IsComponentTypeUnsigned(IOComponentEnum::LONG));
static_assert(!IsComponentTypeUnsigned(IOComponentEnum::LONGLONG));
static_assert(IsComponentTypeUnsigned(IOComponentEnum::ULONGLONG));
static_assert(!IsComponentTypeUnsigned(IOComponentEnum::FLOAT));
static_assert(!IsComponentTypeUnsigned(IOComponentEnum::DOUBLE));
static_assert(IsComponentTypeUnsigned(IOComponentEnum::UINT8));
static_assert(!IsComponentTypeUnsigned(IOComponentEnum::INT8));
static_assert(IsComponentTypeUnsigned(IOComponentEnum::UINT16));
static_assert(!IsComponentTypeUnsigned(IOComponentEnum::INT16));
static_assert(IsComponentTypeUnsigned(IOComponentEnum::UINT32));
static_assert(!IsComponentTypeUnsigned(IOComponentEnum::INT32));
static_assert(IsComponentTypeUnsigned(IOComponentEnum::UINT64));
static_assert(!IsComponentTypeUnsigned(IOComponentEnum::INT64));
static_assert(!IsComponentTypeUnsigned(IOComponentEnum::FLOAT32));
static_assert(!IsComponentTypeUnsigned(IOComponentEnum::FLOAT64));

// Tests GetNumberOfBitsOfComponentType:
static_assert(GetNumberOfBitsOfComponentType(IOComponentEnum::UINT8) == 8);
static_assert(GetNumberOfBitsOfComponentType(IOComponentEnum::INT8) == 8);
static_assert(GetNumberOfBitsOfComponentType(IOComponentEnum::UINT16) == 16);
static_assert(GetNumberOfBitsOfComponentType(IOComponentEnum::INT16) == 16);
static_assert(GetNumberOfBitsOfComponentType(IOComponentEnum::UINT32) == 32);
static_assert(GetNumberOfBitsOfComponentType(IOComponentEnum::INT32) == 32);
static_assert(GetNumberOfBitsOfComponentType(IOComponentEnum::UINT64) == 64);
static_assert(GetNumberOfBitsOfComponentType(IOComponentEnum::INT64) == 64);
static_assert(GetNumberOfBitsOfComponentType(IOComponentEnum::FLOAT32) == 32);
static_assert(GetNumberOfBitsOfComponentType(IOComponentEnum::FLOAT64) == 64);
static_assert(GetNumberOfBitsOfComponentType(IOComponentEnum::UNKNOWNCOMPONENTTYPE) == 0);
static_assert(GetNumberOfBitsOfComponentType(IOComponentEnum::UCHAR) == sizeof(char) * CHAR_BIT);
static_assert(GetNumberOfBitsOfComponentType(IOComponentEnum::CHAR) == sizeof(char) * CHAR_BIT);
static_assert(GetNumberOfBitsOfComponentType(IOComponentEnum::USHORT) == sizeof(short) * CHAR_BIT);
static_assert(GetNumberOfBitsOfComponentType(IOComponentEnum::SHORT) == sizeof(short) * CHAR_BIT);
static_assert(GetNumberOfBitsOfComponentType(IOComponentEnum::UINT) == sizeof(int) * CHAR_BIT);
static_assert(GetNumberOfBitsOfComponentType(IOComponentEnum::INT) == sizeof(int) * CHAR_BIT);
static_assert(GetNumberOfBitsOfComponentType(IOComponentEnum::ULONG) == sizeof(long) * CHAR_BIT);
static_assert(GetNumberOfBitsOfComponentType(IOComponentEnum::LONG) == sizeof(long) * CHAR_BIT);
static_assert(GetNumberOfBitsOfComponentType(IOComponentEnum::LONGLONG) == sizeof(long long) * CHAR_BIT);
static_assert(GetNumberOfBitsOfComponentType(IOComponentEnum::ULONGLONG) == sizeof(long long) * CHAR_BIT);
static_assert(GetNumberOfBitsOfComponentType(IOComponentEnum::FLOAT) == sizeof(float) * CHAR_BIT);
static_assert(GetNumberOfBitsOfComponentType(IOComponentEnum::DOUBLE) == sizeof(double) * CHAR_BIT);
};
} // namespace

Expand Down
Loading