vtk-m/vtkm/io/PixelTypes.h
2020-05-14 16:10:33 -04:00

202 lines
7.1 KiB
C++

//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#ifndef vtk_m_io_PixelTypes_h
#define vtk_m_io_PixelTypes_h
#include <vtkm/Types.h>
#include <vtkm/VecTraits.h>
VTKM_THIRDPARTY_PRE_INCLUDE
#include <vtkm/thirdparty/lodepng/vtkmlodepng/lodepng.h>
VTKM_THIRDPARTY_POST_INCLUDE
namespace vtkm
{
namespace io
{
// ----------------------------------------------------------------------
// Define custom SFINAE structures to calculate the VTKM types associated
// with provided BitDepths
template <const vtkm::Id size, typename = void>
struct ComponentTypeFromSize
{
};
template <const vtkm::Id size>
struct ComponentTypeFromSize<size, typename std::enable_if<(size == 8)>::type>
{
using type = vtkm::UInt8;
};
template <const vtkm::Id size>
struct ComponentTypeFromSize<size, typename std::enable_if<(size == 16)>::type>
{
using type = vtkm::UInt16;
};
// ----------------------------------------------------------------------
/// \brief Base type for more complex pixels (RGB, Greyscale, etc) that describes various values
/// such as bit-depth, channel width, bytes per pixel, and how various data should be polled
///
/// \c BasePixel takes BitDepth and Channels as template parameters. BitDepth describes the number
/// of bits in the pixel, while Channels describes the multiple of bits that are available.
/// BasePixel extends vtkm::Vec. The ComponentType is pulled from the ComponentTypeFromSize
/// SFINAE struct defined above. This helps with optimizing the pixel size for a given
/// bit-depth. The Size is pulled from the Channels param.
///
/// \c BasePixel requires BitDepths that are > 8 and powers of 2 at the moment. BitDepths of
/// 4, 2, or 1 bit are not correctly handled at the moment.
///
/// \c BasePixel describes how to populate itself from an unsigned char pointer (assuming that
/// the data stored within the pointer matches the bit-depth and channels described by the
/// BasePixel type), and how to fill in data for an unsigned char pointer. This is mostly
/// useful in serialization and deserialization to various image formats.
///
template <const vtkm::Id BitDepth, const vtkm::IdComponent Channels>
class BasePixel : public vtkm::Vec<typename ComponentTypeFromSize<BitDepth>::type, Channels>
{
static_assert(BitDepth >= 8, "BitDepth not >= 8");
static_assert(!(BitDepth & (BitDepth - 1)), "BitDepth not a power of 2");
public:
using Superclass = vtkm::Vec<typename ComponentTypeFromSize<BitDepth>::type, Channels>;
using ComponentType = typename Superclass::ComponentType;
using BaseType = BasePixel<BitDepth, Channels>;
static constexpr vtkm::IdComponent BIT_DEPTH = BitDepth;
static constexpr vtkm::IdComponent NUM_BYTES = BitDepth / 8;
static constexpr vtkm::IdComponent MAX_COLOR_VALUE = (1 << BitDepth) - 1;
static constexpr vtkm::IdComponent NUM_CHANNELS = Superclass::NUM_COMPONENTS;
static constexpr vtkm::IdComponent BYTES_PER_PIXEL = NUM_CHANNELS * NUM_BYTES;
using Superclass::Superclass;
BasePixel() = default;
/// Fills in this->Components by calling ConstructPixelFromImage. Requires
/// the base vec values to be zeroed out initially.
///
BasePixel(const unsigned char* imageData, const vtkm::Id index)
: Superclass(0)
{
ConstructPixelFromImage(imageData, index);
}
virtual ~BasePixel() = default;
/// Calculates this difference between two pixels as a single value.
///
virtual ComponentType Diff(const BaseType& pixel) const = 0;
/// Generates a Vec4f_32 from the current data available in the pixel
///
virtual vtkm::Vec4f_32 ToVec4f() const = 0;
/// Implement the << operator for this class type. Will call the overloaded
/// print method for the subclassed type.
///
friend std::ostream& operator<<(std::ostream& os, const BaseType& basePixel)
{
basePixel.print(os);
return os;
}
/// Takes an output imageData pointer and in index to a location in that dataset
/// and fills in the pixel data at the location. Utilizes BIT_DEPTH and
/// NUM_CHANNELS to fill in multiple bytes worth of data if necessary.
///
void FillImageAtIndexWithPixel(unsigned char* imageData, const vtkm::Id index);
protected:
/// Takes an input imageData pointer and an index to a location in that dataset
/// and fills in this->Components correctly using the provided BIT_DEPTH and
/// NUM_CHANNELS. Does NOT 0 out the current Components.
///
void ConstructPixelFromImage(const unsigned char* imageData, const vtkm::Id index);
virtual void print(std::ostream& os) const = 0;
};
template <const vtkm::Id BitDepth>
class RGBPixel : public BasePixel<BitDepth, 3>
{
public:
// RGB values are stored in a vtkm::Vec<ComponentType, 3>
using Superclass = BasePixel<BitDepth, 3>;
using ComponentType = typename Superclass::ComponentType;
static constexpr vtkm::png::LodePNGColorType PNG_COLOR_TYPE =
vtkm::png::LodePNGColorType::LCT_RGB;
using Superclass::Superclass;
RGBPixel() = default;
RGBPixel(vtkm::Vec4f_32 tuple)
: Superclass(static_cast<ComponentType>(tuple[0] * this->MAX_COLOR_VALUE),
static_cast<ComponentType>(tuple[1] * this->MAX_COLOR_VALUE),
static_cast<ComponentType>(tuple[2] * this->MAX_COLOR_VALUE))
{
}
virtual ~RGBPixel() = default;
ComponentType Diff(const Superclass& pixel) const override;
vtkm::Vec4f_32 ToVec4f() const override;
protected:
void print(std::ostream& os) const override
{
os << "(" << (int)this->Components[0] << "," << (int)this->Components[1] << ","
<< (int)this->Components[2] << ")";
}
};
// Default types for 8 and 16 bit RGB pixels
using RGBPixel_8 = RGBPixel<8>;
using RGBPixel_16 = RGBPixel<16>;
template <const vtkm::Id BitDepth>
class GreyPixel : public BasePixel<BitDepth, 1>
{
public:
// Grey values are stored in a vtkm::Vec<ComponentType, 1>
// Note: A vec of size 1 is used instead of just a `ComponentType`
// in order to simplify the pixel helper functions
using Superclass = BasePixel<BitDepth, 1>;
using ComponentType = typename Superclass::ComponentType;
static constexpr vtkm::png::LodePNGColorType PNG_COLOR_TYPE =
vtkm::png::LodePNGColorType::LCT_GREY;
using Superclass::Superclass;
GreyPixel() = default;
GreyPixel(vtkm::Vec4f_32 tuple)
: Superclass(
static_cast<ComponentType>((tuple[0] + tuple[1] + tuple[2]) * this->MAX_COLOR_VALUE / 3))
{
}
virtual ~GreyPixel() = default;
ComponentType Diff(const Superclass& pixel) const override;
vtkm::Vec4f_32 ToVec4f() const override;
protected:
void print(std::ostream& os) const override { os << "(" << (int)this->Components[0] << ")"; }
};
// Default types for 8 and 16 bit Grey pixels
using GreyPixel_16 = GreyPixel<16>;
using GreyPixel_8 = GreyPixel<8>;
} // namespace io
} // namespace vtkm
#include <vtkm/io/PixelTypes.hxx>
#endif //vtk_m_io_PixelTypes_h