mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-09-08 13:23:51 +00:00
Update image readers to style and library
Updated the image reader classes to better follow VTK-m naming convention (i.e. use `ImageReaderPNG` instead of `PNGReader`). The structure of the image reader class now also better matches the interface for the VTK reader. Also put the implementation of the image readers into the `vtkm_io` library so that it only has to be compiled once.
This commit is contained in:
parent
0f7a509cdb
commit
1e91b32ace
@ -13,7 +13,9 @@ set(headers
|
||||
ErrorIO.h
|
||||
DecodePNG.h
|
||||
EncodePNG.h
|
||||
ImageReader.h
|
||||
ImageReaderBase.h
|
||||
ImageReaderPNG.h
|
||||
ImageReaderPNM.h
|
||||
ImageWriter.h
|
||||
PixelTypes.h
|
||||
VTKDataSetReader.h
|
||||
@ -27,7 +29,6 @@ set(headers
|
||||
)
|
||||
|
||||
set(template_sources
|
||||
ImageReader.hxx
|
||||
ImageWriter.hxx
|
||||
PixelTypes.hxx
|
||||
)
|
||||
@ -43,6 +44,9 @@ set(sources
|
||||
# devices for ArrayHandle, and this requirement will go away.
|
||||
set(device_sources
|
||||
BOVDataSetReader.cxx
|
||||
ImageReaderBase.cxx
|
||||
ImageReaderPNG.cxx
|
||||
ImageReaderPNM.cxx
|
||||
VTKDataSetReader.cxx
|
||||
VTKDataSetReaderBase.cxx
|
||||
VTKDataSetWriter.cxx
|
||||
|
@ -1,155 +0,0 @@
|
||||
//============================================================================
|
||||
// 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_ImageReader_h
|
||||
#define vtk_m_io_ImageReader_h
|
||||
|
||||
#include <vtkm/Types.h>
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/DataSet.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
|
||||
// Forward Declare
|
||||
namespace rendering
|
||||
{
|
||||
class Canvas;
|
||||
} // namespace rendering
|
||||
|
||||
namespace io
|
||||
{
|
||||
|
||||
/// \brief Manages reading, and loading data from images
|
||||
///
|
||||
/// \c BaseImageReader implements methods for loading imaging data from a canvas or
|
||||
/// ArrayHandle and storing that data in a vtkm::cont::DataSet. Image rgb values
|
||||
/// are represented as a point field in a 2D uniform dataset.
|
||||
///
|
||||
/// \c BaseImageReader can be constructed from a file, canvas, or ArrayHandle. It can
|
||||
/// also be empy constructed and filled in with a dataset later.
|
||||
///
|
||||
/// \c BaseImageReader implements virtual methods for reading files. Ideally,
|
||||
/// these methods will be overriden in various subclasses to implement specific
|
||||
/// functionality for reading data to specific image file-types.
|
||||
///
|
||||
/// \c The templated type is used when Filling the ImageDataSet.
|
||||
///
|
||||
class BaseImageReader
|
||||
{
|
||||
public:
|
||||
/// Constructs an emtpy BaseImageReader.
|
||||
///
|
||||
BaseImageReader() = default;
|
||||
explicit BaseImageReader(const vtkm::Id& maxColorValue)
|
||||
: MaxColorValue(maxColorValue)
|
||||
{
|
||||
}
|
||||
~BaseImageReader() noexcept = default;
|
||||
|
||||
/// Reads image data from a file. Meant to be implemented in overriden
|
||||
/// image-specific classes
|
||||
///
|
||||
virtual vtkm::cont::DataSet ReadFromFile(const std::string& fileName) = 0;
|
||||
|
||||
/// Creates an ImageDataSet from a Canvas object
|
||||
///
|
||||
vtkm::cont::DataSet CreateImageDataSet(const vtkm::rendering::Canvas& canvas);
|
||||
|
||||
/// Creates an ImageDataSet from a RGBA 32bit float color buffer
|
||||
/// Assumes the color buffer is stored in row-major ordering
|
||||
///
|
||||
vtkm::cont::DataSet CreateImageDataSet(const vtkm::cont::ArrayHandle<vtkm::Vec4f_32>& colorBuffer,
|
||||
const vtkm::Id& width,
|
||||
const vtkm::Id& height);
|
||||
|
||||
const std::string& GetPointFieldName() const { return this->PointFieldName; }
|
||||
|
||||
protected:
|
||||
vtkm::cont::DataSet InitializeImageDataSet(const vtkm::Id& width, const vtkm::Id& height);
|
||||
|
||||
std::string PointFieldName = "pixel-data";
|
||||
vtkm::Id MaxColorValue{ 0 };
|
||||
};
|
||||
|
||||
/// \brief Manages reading images using the PNG format via lodepng
|
||||
///
|
||||
/// \c PNGReader extends BaseImageReader and implements reading images in a valid
|
||||
/// PNG format. It utilizes lodepng's decode file functions to read
|
||||
/// PNG images that are automatically compressed to optimal sizes relative to
|
||||
/// the actual bit complexity of the image.
|
||||
///
|
||||
/// \c PNGReader will automatically upsample/downsample read image data
|
||||
/// to a 16 bit RGB no matter how the image is compressed. It is up to the user to
|
||||
/// decide the pixel format for input PNGs
|
||||
class PNGReader : public BaseImageReader
|
||||
{
|
||||
using Superclass = BaseImageReader;
|
||||
|
||||
public:
|
||||
using Superclass::Superclass;
|
||||
PNGReader() = default;
|
||||
~PNGReader() noexcept = default;
|
||||
|
||||
/// Reads PNG data from the provided file and stores it
|
||||
/// as a 16bit RGB value
|
||||
///
|
||||
vtkm::cont::DataSet ReadFromFile(const std::string& fileName) override;
|
||||
|
||||
/// Reads PNG data from the provided file and stores it
|
||||
/// according to the method's templated PixelType
|
||||
///
|
||||
template <typename PixelType>
|
||||
vtkm::cont::DataSet ReadFromFile(const std::string& fileName);
|
||||
};
|
||||
|
||||
|
||||
/// \brief Manages reading images using the PNM format
|
||||
///
|
||||
/// \c PNMImage extends BaseImage, and implements reading images from a
|
||||
/// valid PNM format (for magic number P6). More details on the PNM
|
||||
/// format can be found here: http://netpbm.sourceforge.net/doc/ppm.html
|
||||
///
|
||||
/// When a file is read the parsed MagicNumber and MaxColorSize provided
|
||||
/// are utilized to correctly parse the bits from the file
|
||||
class PNMReader : public BaseImageReader
|
||||
{
|
||||
using Superclass = BaseImageReader;
|
||||
|
||||
public:
|
||||
using Superclass::Superclass;
|
||||
PNMReader() = default;
|
||||
~PNMReader() noexcept = default;
|
||||
|
||||
/// Attempts to read the provided file into a DataSet object.
|
||||
/// Will pull the image's MaxColorValue from the file and then Decode
|
||||
/// with the appropriate RGB PixelType bit depth.
|
||||
///
|
||||
vtkm::cont::DataSet ReadFromFile(const std::string& fileName) override;
|
||||
|
||||
protected:
|
||||
/// Reads image data from the provided inStream with the supplied width/height
|
||||
/// Stores the data in a vector of PixelType which is converted to an DataSet
|
||||
///
|
||||
template <typename PixelType>
|
||||
vtkm::cont::DataSet DecodeFile(std::ifstream& inStream,
|
||||
const vtkm::Id& width,
|
||||
const vtkm::Id& height);
|
||||
|
||||
// This is set to only work for P6 pnm image types for now (ie ppm)
|
||||
std::string MagicNumber{ "P6" };
|
||||
};
|
||||
|
||||
|
||||
} // namespace io
|
||||
} // namespace vtkm
|
||||
|
||||
#include <vtkm/io/ImageReader.hxx>
|
||||
|
||||
#endif
|
@ -1,172 +0,0 @@
|
||||
//============================================================================
|
||||
// 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_ImageReader_hxx
|
||||
#define vtk_m_io_ImageReader_hxx
|
||||
|
||||
#include <vtkm/cont/CellSetStructured.h>
|
||||
#include <vtkm/cont/DataSetBuilderUniform.h>
|
||||
#include <vtkm/io/ImageReader.h>
|
||||
#include <vtkm/io/PixelTypes.h>
|
||||
#include <vtkm/rendering/Canvas.h>
|
||||
|
||||
VTKM_THIRDPARTY_PRE_INCLUDE
|
||||
#include <vtkm/thirdparty/lodepng/vtkmlodepng/lodepng.h>
|
||||
VTKM_THIRDPARTY_POST_INCLUDE
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
// Start BaseReaderImage Class Template Implementations
|
||||
VTKM_CONT
|
||||
vtkm::cont::DataSet BaseImageReader::CreateImageDataSet(const vtkm::rendering::Canvas& canvas)
|
||||
{
|
||||
return this->CreateImageDataSet(canvas.GetColorBuffer(), canvas.GetWidth(), canvas.GetHeight());
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
vtkm::cont::DataSet BaseImageReader::CreateImageDataSet(
|
||||
const vtkm::cont::ArrayHandle<vtkm::Vec4f_32>& colorBuffer,
|
||||
const vtkm::Id& width,
|
||||
const vtkm::Id& height)
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec4f_32>::ReadPortalType colorPortal = colorBuffer.ReadPortal();
|
||||
std::vector<vtkm::Vec4f_32> fieldData;
|
||||
for (vtkm::Id yIndex = 0; yIndex < height; yIndex++)
|
||||
{
|
||||
for (vtkm::Id xIndex = 0; xIndex < width; xIndex++)
|
||||
{
|
||||
vtkm::Vec4f_32 tuple = colorPortal.Get(yIndex * width + xIndex);
|
||||
fieldData.push_back(tuple);
|
||||
}
|
||||
}
|
||||
auto dataSet = this->InitializeImageDataSet(width, height);
|
||||
dataSet.AddPointField(this->PointFieldName, fieldData);
|
||||
return dataSet;
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
vtkm::cont::DataSet BaseImageReader::InitializeImageDataSet(const vtkm::Id& width,
|
||||
const vtkm::Id& height)
|
||||
{
|
||||
vtkm::cont::DataSetBuilderUniform dsb;
|
||||
vtkm::Id2 dimensions(width, height);
|
||||
return dsb.Create(dimensions);
|
||||
}
|
||||
// End BaseReaderImage Class Template Implementations
|
||||
|
||||
// Start PNGReader Class Template Implementations
|
||||
VTKM_CONT
|
||||
vtkm::cont::DataSet PNGReader::ReadFromFile(const std::string& fileName)
|
||||
{
|
||||
return this->ReadFromFile<io::RGBPixel_16>(fileName);
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
template <typename PixelType>
|
||||
vtkm::cont::DataSet PNGReader::ReadFromFile(const std::string& fileName)
|
||||
{
|
||||
unsigned char* imageData;
|
||||
unsigned uwidth, uheight;
|
||||
vtkm::Id width, height;
|
||||
vtkm::png::lodepng_decode_file(&imageData,
|
||||
&uwidth,
|
||||
&uheight,
|
||||
fileName.c_str(),
|
||||
PixelType::PNG_COLOR_TYPE,
|
||||
PixelType::BIT_DEPTH);
|
||||
|
||||
width = static_cast<vtkm::Id>(uwidth);
|
||||
height = static_cast<vtkm::Id>(uheight);
|
||||
|
||||
// Fill in the data starting from the end (Images are read Top-Left to Bottom-Right,
|
||||
// but are stored from Bottom-Left to Top-Right)
|
||||
std::vector<vtkm::Vec4f_32> fieldData;
|
||||
for (vtkm::Id yIndex = static_cast<vtkm::Id>(height - 1); yIndex >= 0; yIndex--)
|
||||
{
|
||||
for (vtkm::Id xIndex = 0; xIndex < static_cast<vtkm::Id>(width); xIndex++)
|
||||
{
|
||||
vtkm::Id index = static_cast<vtkm::Id>(yIndex * width + xIndex);
|
||||
fieldData.push_back(PixelType(imageData, index).ToVec4f());
|
||||
}
|
||||
}
|
||||
|
||||
auto dataSet = this->InitializeImageDataSet(width, height);
|
||||
dataSet.AddPointField(this->PointFieldName, fieldData);
|
||||
|
||||
free(imageData);
|
||||
return dataSet;
|
||||
}
|
||||
// End PNGReader Class Template Implementations
|
||||
|
||||
// Start PNMReader Class Template Implementations
|
||||
VTKM_CONT
|
||||
vtkm::cont::DataSet PNMReader::ReadFromFile(const std::string& fileName)
|
||||
{
|
||||
std::ifstream inStream(fileName.c_str(), std::ios_base::binary | std::ios_base::in);
|
||||
vtkm::Id width;
|
||||
vtkm::Id height;
|
||||
std::string val;
|
||||
|
||||
inStream >> val;
|
||||
if (this->MagicNumber != val)
|
||||
{
|
||||
throw vtkm::cont::ErrorBadValue("MagicNumber: " + this->MagicNumber + " in file: " + fileName +
|
||||
" did not match: " + val);
|
||||
}
|
||||
|
||||
inStream >> width >> height >> this->MaxColorValue;
|
||||
inStream.get();
|
||||
|
||||
switch (this->MaxColorValue)
|
||||
{
|
||||
case 255:
|
||||
return this->DecodeFile<io::RGBPixel_8>(inStream, width, height);
|
||||
case 65535:
|
||||
return this->DecodeFile<io::RGBPixel_16>(inStream, width, height);
|
||||
default:
|
||||
throw vtkm::cont::ErrorBadValue("MaxColorValue: " + std::to_string(this->MaxColorValue) +
|
||||
" from file: " + fileName + " was not one of: {8, 16}");
|
||||
}
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
template <typename PixelType>
|
||||
vtkm::cont::DataSet PNMReader::DecodeFile(std::ifstream& inStream,
|
||||
const vtkm::Id& width,
|
||||
const vtkm::Id& height)
|
||||
{
|
||||
vtkm::UInt32 imageSize = static_cast<vtkm::UInt32>(width * height * PixelType::BYTES_PER_PIXEL);
|
||||
std::vector<unsigned char> imageData(imageSize);
|
||||
inStream.read((char*)imageData.data(), imageSize);
|
||||
|
||||
// Fill in the data starting from the end (Images are read Top-Left to Bottom-Right,
|
||||
// but are stored from Bottom-Left to Top-Right)
|
||||
std::vector<vtkm::Vec4f_32> fieldData;
|
||||
for (vtkm::Id yIndex = height - 1; yIndex >= 0; yIndex--)
|
||||
{
|
||||
for (vtkm::Id xIndex = 0; xIndex < width; xIndex++)
|
||||
{
|
||||
vtkm::Id index = yIndex * width + xIndex;
|
||||
fieldData.push_back(PixelType(imageData.data(), index).ToVec4f());
|
||||
}
|
||||
}
|
||||
|
||||
auto dataSet = this->InitializeImageDataSet(width, height);
|
||||
dataSet.AddPointField(this->PointFieldName, fieldData);
|
||||
return dataSet;
|
||||
}
|
||||
// End PNMReader Class Template Implementations
|
||||
|
||||
} // namespace io
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
51
vtkm/io/ImageReaderBase.cxx
Normal file
51
vtkm/io/ImageReaderBase.cxx
Normal file
@ -0,0 +1,51 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/io/ImageReaderBase.h>
|
||||
|
||||
#include <vtkm/cont/DataSetBuilderUniform.h>
|
||||
#include <vtkm/rendering/Canvas.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
ImageReaderBase::ImageReaderBase(const char* filename)
|
||||
: FileName(filename)
|
||||
{
|
||||
}
|
||||
|
||||
ImageReaderBase::ImageReaderBase(const std::string& filename)
|
||||
: FileName(filename)
|
||||
{
|
||||
}
|
||||
|
||||
ImageReaderBase::~ImageReaderBase() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
const vtkm::cont::DataSet& ImageReaderBase::ReadDataSet()
|
||||
{
|
||||
this->Read();
|
||||
return this->DataSet;
|
||||
}
|
||||
|
||||
void ImageReaderBase::InitializeImageDataSet(const vtkm::Id& width,
|
||||
const vtkm::Id& height,
|
||||
const ColorArrayType& pixels)
|
||||
{
|
||||
vtkm::cont::DataSetBuilderUniform dsb;
|
||||
vtkm::Id2 dimensions(width, height);
|
||||
this->DataSet = dsb.Create(dimensions);
|
||||
this->DataSet.AddPointField(this->PointFieldName, pixels);
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::io
|
65
vtkm/io/ImageReaderBase.h
Normal file
65
vtkm/io/ImageReaderBase.h
Normal file
@ -0,0 +1,65 @@
|
||||
//============================================================================
|
||||
// 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_ImageReaderBase_h
|
||||
#define vtk_m_io_ImageReaderBase_h
|
||||
|
||||
#include <vtkm/cont/DataSet.h>
|
||||
|
||||
#include <vtkm/io/vtkm_io_export.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
/// \brief Manages reading, and loading data from images
|
||||
///
|
||||
/// `ImageReaderBase` implements methods for loading imaging data from a canvas or
|
||||
/// ArrayHandle and storing that data in a vtkm::cont::DataSet. Image rgb values
|
||||
/// are represented as a point field in a 2D uniform dataset.
|
||||
///
|
||||
/// `ImageReaderBase` implements virtual methods for reading files. Ideally,
|
||||
/// these methods will be overriden in various subclasses to implement specific
|
||||
/// functionality for reading data to specific image file-types.
|
||||
///
|
||||
class VTKM_IO_EXPORT ImageReaderBase
|
||||
{
|
||||
public:
|
||||
using ColorArrayType = vtkm::cont::ArrayHandle<vtkm::Vec4f_32>;
|
||||
|
||||
explicit VTKM_CONT ImageReaderBase(const char* filename);
|
||||
explicit VTKM_CONT ImageReaderBase(const std::string& filename);
|
||||
virtual VTKM_CONT ~ImageReaderBase() noexcept;
|
||||
ImageReaderBase(const ImageReaderBase&) = delete;
|
||||
ImageReaderBase& operator=(const ImageReaderBase&) = delete;
|
||||
|
||||
VTKM_CONT const vtkm::cont::DataSet& ReadDataSet();
|
||||
|
||||
VTKM_CONT const vtkm::cont::DataSet& GetDataSet() const { return this->DataSet; }
|
||||
|
||||
VTKM_CONT const std::string& GetPointFieldName() const { return this->PointFieldName; }
|
||||
VTKM_CONT void SetPointFieldName(const std::string& name) { this->PointFieldName = name; }
|
||||
|
||||
protected:
|
||||
VTKM_CONT virtual void Read() = 0;
|
||||
|
||||
/// Resets the `DataSet` to hold the given pixels.
|
||||
void InitializeImageDataSet(const vtkm::Id& width,
|
||||
const vtkm::Id& height,
|
||||
const ColorArrayType& pixels);
|
||||
|
||||
std::string FileName;
|
||||
std::string PointFieldName = "color";
|
||||
vtkm::cont::DataSet DataSet;
|
||||
};
|
||||
}
|
||||
} // namespace vtkm::io
|
||||
|
||||
#endif //vtk_m_io_ImageReaderBase_h
|
103
vtkm/io/ImageReaderPNG.cxx
Normal file
103
vtkm/io/ImageReaderPNG.cxx
Normal file
@ -0,0 +1,103 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/io/ImageReaderPNG.h>
|
||||
|
||||
#include <vtkm/io/PixelTypes.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
VTKM_CONT
|
||||
template <typename PixelType>
|
||||
vtkm::io::ImageReaderBase::ColorArrayType ReadFromPNG(const std::string& fileName,
|
||||
vtkm::Id& width,
|
||||
vtkm::Id& height)
|
||||
{
|
||||
unsigned char* imageData;
|
||||
unsigned uwidth, uheight;
|
||||
vtkm::png::lodepng_decode_file(&imageData,
|
||||
&uwidth,
|
||||
&uheight,
|
||||
fileName.c_str(),
|
||||
PixelType::PNG_COLOR_TYPE,
|
||||
PixelType::BIT_DEPTH);
|
||||
|
||||
width = static_cast<vtkm::Id>(uwidth);
|
||||
height = static_cast<vtkm::Id>(uheight);
|
||||
|
||||
// Fill in the data starting from the end (Images are read Top-Left to Bottom-Right,
|
||||
// but are stored from Bottom-Left to Top-Right)
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec4f_32> array;
|
||||
array.Allocate(width * height);
|
||||
auto portal = array.WritePortal();
|
||||
vtkm::Id vtkmIndex = 0;
|
||||
for (vtkm::Id yIndex = static_cast<vtkm::Id>(height - 1); yIndex >= 0; yIndex--)
|
||||
{
|
||||
for (vtkm::Id xIndex = 0; xIndex < static_cast<vtkm::Id>(width); xIndex++)
|
||||
{
|
||||
vtkm::Id pngIndex = static_cast<vtkm::Id>(yIndex * width + xIndex);
|
||||
portal.Set(vtkmIndex, PixelType(imageData, pngIndex).ToVec4f());
|
||||
vtkmIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
free(imageData);
|
||||
return array;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
ImageReaderPNG::~ImageReaderPNG() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
const vtkm::cont::DataSet& ImageReaderPNG::ReadDataSet(PixelType pixelType)
|
||||
{
|
||||
this->Read(pixelType);
|
||||
return this->GetDataSet();
|
||||
}
|
||||
|
||||
void ImageReaderPNG::Read()
|
||||
{
|
||||
this->Read(PixelType::RGB_16);
|
||||
}
|
||||
|
||||
void ImageReaderPNG::Read(PixelType pixelType)
|
||||
{
|
||||
vtkm::io::ImageReaderBase::ColorArrayType pixelArray;
|
||||
vtkm::Id width;
|
||||
vtkm::Id height;
|
||||
|
||||
switch (pixelType)
|
||||
{
|
||||
case PixelType::RGB_8:
|
||||
pixelArray = ReadFromPNG<vtkm::io::RGBPixel_8>(this->FileName, width, height);
|
||||
break;
|
||||
case PixelType::RGB_16:
|
||||
pixelArray = ReadFromPNG<vtkm::io::RGBPixel_16>(this->FileName, width, height);
|
||||
break;
|
||||
case PixelType::GREY_8:
|
||||
pixelArray = ReadFromPNG<vtkm::io::GreyPixel_8>(this->FileName, width, height);
|
||||
break;
|
||||
case PixelType::GREY_16:
|
||||
pixelArray = ReadFromPNG<vtkm::io::GreyPixel_16>(this->FileName, width, height);
|
||||
break;
|
||||
}
|
||||
|
||||
this->InitializeImageDataSet(width, height, pixelArray);
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::io
|
60
vtkm/io/ImageReaderPNG.h
Normal file
60
vtkm/io/ImageReaderPNG.h
Normal file
@ -0,0 +1,60 @@
|
||||
//============================================================================
|
||||
// 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_ImageReaderPNG_h
|
||||
#define vtk_m_io_ImageReaderPNG_h
|
||||
|
||||
#include <vtkm/io/ImageReaderBase.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
/// \brief Manages reading images using the PNG format via lodepng
|
||||
///
|
||||
/// `ImageReaderPNG` extends `ImageReaderBase` and implements reading images in a valid
|
||||
/// PNG format. It utilizes lodepng's decode file functions to read
|
||||
/// PNG images that are automatically compressed to optimal sizes relative to
|
||||
/// the actual bit complexity of the image.
|
||||
///
|
||||
/// `ImageReaderPNG` will automatically upsample/downsample read image data
|
||||
/// to a 16 bit RGB no matter how the image is compressed. It is up to the user to
|
||||
/// decide the pixel format for input PNGs
|
||||
class VTKM_IO_EXPORT ImageReaderPNG : public ImageReaderBase
|
||||
{
|
||||
using Superclass = ImageReaderBase;
|
||||
|
||||
public:
|
||||
using Superclass::Superclass;
|
||||
VTKM_CONT ~ImageReaderPNG() noexcept override;
|
||||
ImageReaderPNG(const ImageReaderPNG&) = delete;
|
||||
ImageReaderPNG& operator=(const ImageReaderPNG&) = delete;
|
||||
|
||||
enum class PixelType
|
||||
{
|
||||
RGB_8,
|
||||
RGB_16,
|
||||
GREY_8,
|
||||
GREY_16
|
||||
};
|
||||
|
||||
/// Reads PNG data from the provided file and stores it
|
||||
/// according to the provided `PixelType`.
|
||||
///
|
||||
VTKM_CONT const vtkm::cont::DataSet& ReadDataSet(PixelType pixelType = PixelType::RGB_16);
|
||||
|
||||
protected:
|
||||
VTKM_CONT void Read() override;
|
||||
VTKM_CONT void Read(PixelType pixelType);
|
||||
};
|
||||
}
|
||||
} // namespace vtkm::io
|
||||
|
||||
#endif //vtk_m_io_ImageReaderPNG_h
|
93
vtkm/io/ImageReaderPNM.cxx
Normal file
93
vtkm/io/ImageReaderPNM.cxx
Normal file
@ -0,0 +1,93 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/io/ImageReaderPNM.h>
|
||||
|
||||
#include <vtkm/io/PixelTypes.h>
|
||||
|
||||
VTKM_THIRDPARTY_PRE_INCLUDE
|
||||
#include <vtkm/thirdparty/lodepng/vtkmlodepng/lodepng.h>
|
||||
VTKM_THIRDPARTY_POST_INCLUDE
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
ImageReaderPNM::~ImageReaderPNM() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
void ImageReaderPNM::Read()
|
||||
{
|
||||
std::ifstream inStream(this->FileName.c_str(), std::ios_base::binary | std::ios_base::in);
|
||||
|
||||
// Currently, the only magic number supported is P6
|
||||
std::string magicNum;
|
||||
inStream >> magicNum;
|
||||
if (magicNum != "P6")
|
||||
{
|
||||
throw vtkm::cont::ErrorBadValue("MagicNumber: " + magicNum + " in file: " + this->FileName +
|
||||
" did not match: P6");
|
||||
}
|
||||
|
||||
vtkm::Id width;
|
||||
vtkm::Id height;
|
||||
vtkm::Id maxColorValue;
|
||||
inStream >> width >> height >> maxColorValue;
|
||||
inStream.get();
|
||||
|
||||
if ((maxColorValue > 0) && (maxColorValue <= 255))
|
||||
{
|
||||
this->DecodeFile<vtkm::io::RGBPixel_8>(inStream, width, height);
|
||||
}
|
||||
else if ((maxColorValue > 255) && (maxColorValue <= 65535))
|
||||
{
|
||||
this->DecodeFile<vtkm::io::RGBPixel_16>(inStream, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw vtkm::cont::ErrorBadValue("MaxColorValue: " + std::to_string(maxColorValue) +
|
||||
" from file: " + this->FileName +
|
||||
" is not in valid range of [1, 65535]");
|
||||
}
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
template <typename PixelType>
|
||||
void ImageReaderPNM::DecodeFile(std::ifstream& inStream,
|
||||
const vtkm::Id& width,
|
||||
const vtkm::Id& height)
|
||||
{
|
||||
vtkm::UInt32 imageSize = static_cast<vtkm::UInt32>(width * height * PixelType::BYTES_PER_PIXEL);
|
||||
std::vector<unsigned char> imageData(imageSize);
|
||||
inStream.read(reinterpret_cast<char*>(imageData.data()), imageSize);
|
||||
|
||||
// Fill in the data starting from the end (Images are read Top-Left to Bottom-Right,
|
||||
// but are stored from Bottom-Left to Top-Right)
|
||||
vtkm::io::ImageReaderBase::ColorArrayType array;
|
||||
array.Allocate(width * height);
|
||||
auto portal = array.WritePortal();
|
||||
vtkm::Id vtkmIndex = 0;
|
||||
for (vtkm::Id yIndex = height - 1; yIndex >= 0; yIndex--)
|
||||
{
|
||||
for (vtkm::Id xIndex = 0; xIndex < width; xIndex++)
|
||||
{
|
||||
vtkm::Id pnmIndex = yIndex * width + xIndex;
|
||||
portal.Set(vtkmIndex, PixelType(imageData.data(), pnmIndex).ToVec4f());
|
||||
vtkmIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
this->InitializeImageDataSet(width, height, array);
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::io
|
50
vtkm/io/ImageReaderPNM.h
Normal file
50
vtkm/io/ImageReaderPNM.h
Normal file
@ -0,0 +1,50 @@
|
||||
//============================================================================
|
||||
// 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_ImageReaderPNM_h
|
||||
#define vtk_m_io_ImageReaderPNM_h
|
||||
|
||||
#include <vtkm/io/ImageReaderBase.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
/// \brief Manages reading images using the PNM format
|
||||
///
|
||||
/// `ImageReaderPNM` extends `ImageReaderBase`, and implements reading images from a
|
||||
/// valid PNM format (for magic number P6). More details on the PNM
|
||||
/// format can be found here: http://netpbm.sourceforge.net/doc/ppm.html
|
||||
///
|
||||
/// When a file is read the parsed MagicNumber and MaxColorSize provided
|
||||
/// are utilized to correctly parse the bits from the file
|
||||
class VTKM_IO_EXPORT ImageReaderPNM : public ImageReaderBase
|
||||
{
|
||||
using Superclass = ImageReaderBase;
|
||||
|
||||
public:
|
||||
using Superclass::Superclass;
|
||||
VTKM_CONT ~ImageReaderPNM() noexcept override;
|
||||
ImageReaderPNM(const ImageReaderPNM&) = delete;
|
||||
ImageReaderPNM& operator=(const ImageReaderPNM&) = delete;
|
||||
|
||||
protected:
|
||||
VTKM_CONT void Read() override;
|
||||
|
||||
/// Reads image data from the provided inStream with the supplied width/height
|
||||
/// Stores the data in a vector of PixelType which is converted to an DataSet
|
||||
///
|
||||
template <typename PixelType>
|
||||
void DecodeFile(std::ifstream& inStream, const vtkm::Id& width, const vtkm::Id& height);
|
||||
};
|
||||
}
|
||||
} // namespace vtkm::io
|
||||
|
||||
#endif //vtk_m_io_ImageReaderPNM_h
|
@ -9,7 +9,8 @@
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/cont/testing/Testing.h>
|
||||
#include <vtkm/io/ImageReader.h>
|
||||
#include <vtkm/io/ImageReaderPNG.h>
|
||||
#include <vtkm/io/ImageReaderPNM.h>
|
||||
#include <vtkm/io/ImageWriter.h>
|
||||
#include <vtkm/io/PixelTypes.h>
|
||||
#include <vtkm/rendering/Canvas.h>
|
||||
@ -58,22 +59,21 @@ void TestFilledImage(vtkm::cont::DataSet& dataSet,
|
||||
}
|
||||
|
||||
template <typename PixelType>
|
||||
void TestCreateImageDataSet(BaseImageReader& reader, const vtkm::rendering::Canvas& canvas)
|
||||
void TestCreateImageDataSet(const vtkm::rendering::Canvas& canvas)
|
||||
{
|
||||
auto dataSet = reader.CreateImageDataSet(canvas);
|
||||
TestFilledImage<PixelType>(dataSet, reader.GetPointFieldName(), canvas);
|
||||
auto dataSet = canvas.GetDataSet("pixel-color");
|
||||
TestFilledImage<PixelType>(dataSet, "pixel-color", canvas);
|
||||
}
|
||||
|
||||
template <typename PixelType>
|
||||
void TestReadAndWritePNG(const vtkm::rendering::Canvas& canvas, std::string image)
|
||||
void TestReadAndWritePNG(const vtkm::rendering::Canvas& canvas, std::string filename)
|
||||
{
|
||||
auto pngReader = PNGReader();
|
||||
auto pngWriter = PNGWriter();
|
||||
vtkm::cont::DataSet dataSet;
|
||||
bool throws = false;
|
||||
try
|
||||
{
|
||||
pngWriter.WriteToFile(image, dataSet);
|
||||
pngWriter.WriteToFile(filename, dataSet);
|
||||
}
|
||||
catch (const vtkm::cont::ErrorBadValue&)
|
||||
{
|
||||
@ -81,12 +81,21 @@ void TestReadAndWritePNG(const vtkm::rendering::Canvas& canvas, std::string imag
|
||||
}
|
||||
VTKM_TEST_ASSERT(throws, "Fill Image did not throw with empty data");
|
||||
|
||||
dataSet = pngReader.CreateImageDataSet(canvas);
|
||||
pngWriter.WriteToFile(image, dataSet);
|
||||
dataSet = pngReader.ReadFromFile(image);
|
||||
pngWriter.WriteToFile(image, dataSet);
|
||||
dataSet = pngReader.ReadFromFile(image);
|
||||
TestFilledImage<PixelType>(dataSet, pngReader.GetPointFieldName(), canvas);
|
||||
dataSet = canvas.GetDataSet(pngWriter.GetPointFieldName());
|
||||
pngWriter.WriteToFile(filename, dataSet);
|
||||
{
|
||||
vtkm::io::ImageReaderPNG reader(filename);
|
||||
dataSet = reader.ReadDataSet();
|
||||
// TODO: Fix this
|
||||
vtkm::cont::Field field = dataSet.GetField(reader.GetPointFieldName());
|
||||
dataSet.AddPointField(pngWriter.GetPointFieldName(), field.GetData());
|
||||
}
|
||||
pngWriter.WriteToFile(filename, dataSet);
|
||||
{
|
||||
vtkm::io::ImageReaderPNG reader(filename);
|
||||
dataSet = reader.ReadDataSet();
|
||||
TestFilledImage<PixelType>(dataSet, reader.GetPointFieldName(), canvas);
|
||||
}
|
||||
}
|
||||
|
||||
template <const vtkm::Id BitDepth>
|
||||
@ -94,7 +103,6 @@ void TestReadAndWritePNM(const vtkm::rendering::Canvas& canvas)
|
||||
{
|
||||
using PixelType = RGBPixel<BitDepth>;
|
||||
PNMWriter ppmWriter((1 << BitDepth) - 1);
|
||||
PNMReader ppmReader((1 << BitDepth) - 1);
|
||||
vtkm::cont::DataSet dataSet;
|
||||
bool throws = false;
|
||||
try
|
||||
@ -107,22 +115,30 @@ void TestReadAndWritePNM(const vtkm::rendering::Canvas& canvas)
|
||||
}
|
||||
VTKM_TEST_ASSERT(throws, "Fill Image did not throw with empty data");
|
||||
|
||||
dataSet = ppmReader.CreateImageDataSet(canvas);
|
||||
dataSet = canvas.GetDataSet(ppmWriter.GetPointFieldName());
|
||||
ppmWriter.WriteToFile("ppmTestFile.ppm", dataSet);
|
||||
dataSet = ppmReader.ReadFromFile("ppmTestFile.ppm");
|
||||
{
|
||||
vtkm::io::ImageReaderPNM reader("ppmTestFile.ppm");
|
||||
dataSet = reader.ReadDataSet();
|
||||
// TODO: Fix this
|
||||
vtkm::cont::Field field = dataSet.GetField(reader.GetPointFieldName());
|
||||
dataSet.AddPointField(ppmWriter.GetPointFieldName(), field.GetData());
|
||||
}
|
||||
ppmWriter.WriteToFile("ppmTestFile2.ppm", dataSet);
|
||||
dataSet = ppmReader.ReadFromFile("ppmTestFile2.ppm");
|
||||
TestFilledImage<PixelType>(dataSet, ppmReader.GetPointFieldName(), canvas);
|
||||
{
|
||||
vtkm::io::ImageReaderPNM reader("ppmTestFile2.ppm");
|
||||
dataSet = reader.ReadDataSet();
|
||||
TestFilledImage<PixelType>(dataSet, reader.GetPointFieldName(), canvas);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TestBaseImageMethods(const vtkm::rendering::Canvas& canvas)
|
||||
{
|
||||
auto reader = PNGReader();
|
||||
TestCreateImageDataSet<RGBPixel_8>(reader, canvas);
|
||||
TestCreateImageDataSet<RGBPixel_16>(reader, canvas);
|
||||
TestCreateImageDataSet<GreyPixel_8>(reader, canvas);
|
||||
TestCreateImageDataSet<GreyPixel_16>(reader, canvas);
|
||||
TestCreateImageDataSet<RGBPixel_8>(canvas);
|
||||
TestCreateImageDataSet<RGBPixel_16>(canvas);
|
||||
TestCreateImageDataSet<GreyPixel_8>(canvas);
|
||||
TestCreateImageDataSet<GreyPixel_16>(canvas);
|
||||
}
|
||||
|
||||
void TestPNMImage(const vtkm::rendering::Canvas& canvas)
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <vtkm/rendering/Canvas.h>
|
||||
|
||||
#include <vtkm/cont/ArrayHandleCounting.h>
|
||||
#include <vtkm/cont/DataSetBuilderUniform.h>
|
||||
#include <vtkm/cont/TryExecute.h>
|
||||
#include <vtkm/io/DecodePNG.h>
|
||||
#include <vtkm/io/EncodePNG.h>
|
||||
@ -272,6 +273,29 @@ Canvas::DepthBufferType& Canvas::GetDepthBuffer()
|
||||
return Internals->DepthBuffer;
|
||||
}
|
||||
|
||||
vtkm::cont::DataSet Canvas::GetDataSet(const std::string& colorFieldName,
|
||||
const std::string& depthFieldName) const
|
||||
{
|
||||
vtkm::cont::DataSetBuilderUniform builder;
|
||||
vtkm::cont::DataSet dataSet = builder.Create(vtkm::Id2(this->GetWidth(), this->GetHeight()));
|
||||
if (!colorFieldName.empty())
|
||||
{
|
||||
dataSet.AddPointField(colorFieldName, this->GetColorBuffer());
|
||||
}
|
||||
if (!depthFieldName.empty())
|
||||
{
|
||||
dataSet.AddPointField(depthFieldName, this->GetDepthBuffer());
|
||||
}
|
||||
return dataSet;
|
||||
}
|
||||
|
||||
vtkm::cont::DataSet Canvas::GetDataSet(const char* colorFieldName, const char* depthFieldName) const
|
||||
{
|
||||
return this->GetDataSet((colorFieldName != nullptr) ? std::string(colorFieldName) : std::string(),
|
||||
(depthFieldName != nullptr) ? std::string(depthFieldName)
|
||||
: std::string());
|
||||
}
|
||||
|
||||
const vtkm::rendering::Color& Canvas::GetBackgroundColor() const
|
||||
{
|
||||
return Internals->BackgroundColor;
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <vtkm/Matrix.h>
|
||||
#include <vtkm/Types.h>
|
||||
#include <vtkm/cont/ColorTable.h>
|
||||
#include <vtkm/cont/DataSet.h>
|
||||
#include <vtkm/rendering/BitmapFont.h>
|
||||
#include <vtkm/rendering/Camera.h>
|
||||
#include <vtkm/rendering/Color.h>
|
||||
@ -70,6 +71,22 @@ public:
|
||||
VTKM_CONT
|
||||
DepthBufferType& GetDepthBuffer();
|
||||
|
||||
///@{
|
||||
/// \brief Gets the image in this `Canvas` as a `vtkm::cont::DataSet`.
|
||||
///
|
||||
/// The returned `DataSet` will be a uniform structured 2D grid. The color and depth
|
||||
/// buffers will be attached as field with the given names. If the name for the color
|
||||
/// or depth field is empty, then that respective field will not be added.
|
||||
///
|
||||
/// The arrays of the color and depth buffer are shallow copied. Thus, changes in
|
||||
/// the `Canvas` may cause unexpected behavior in the `DataSet`.
|
||||
///
|
||||
VTKM_CONT vtkm::cont::DataSet GetDataSet(const std::string& colorFieldName = "color",
|
||||
const std::string& depthFieldName = "depth") const;
|
||||
VTKM_CONT vtkm::cont::DataSet GetDataSet(const char* colorFieldName,
|
||||
const char* depthFieldName = "depth") const;
|
||||
///@}
|
||||
|
||||
VTKM_CONT
|
||||
void ResizeBuffers(vtkm::Id width, vtkm::Id height);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user