Skip to content

Commit

Permalink
Merge pull request #1173 from thewtex/mesh-glaze
Browse files Browse the repository at this point in the history
mesh glaze
  • Loading branch information
thewtex authored Jul 8, 2024
2 parents f65c2a8 + 17bca17 commit 7c87834
Show file tree
Hide file tree
Showing 60 changed files with 1,977 additions and 2,039 deletions.
6 changes: 3 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ FetchContent_Declare(
GIT_SHALLOW TRUE
)

set(glaze_GIT_REPOSITORY "https://github.com/stephenberry/glaze")
# glaze v2.9.3
set(glaze_GIT_TAG fe49c8e1a057d11484e0bd88ffcbe60277e356fd)
set(glaze_GIT_REPOSITORY "https://github.com/thewtex/glaze")
# glaze v2.9.5
set(glaze_GIT_TAG 19d492fa9fef206fcf61fc03f0981d17f8af8648)
FetchContent_Declare(
glaze
GIT_REPOSITORY ${glaze_GIT_REPOSITORY}
Expand Down
56 changes: 56 additions & 0 deletions include/itkComponentTypesJSON.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*=========================================================================
*
* Copyright NumFOCUS
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*=========================================================================*/
#ifndef itkComponentTypesJSON_h
#define itkComponentTypesJSON_h

#include "glaze/glaze.hpp"

namespace itk
{
enum class JSONComponentTypesEnum
{
int8,
uint8,
int16,
uint16,
int32,
uint32,
int64,
uint64,
float32,
float64
};
} // end namespace itk

template <>
struct glz::meta<itk::JSONComponentTypesEnum> {
using enum itk::JSONComponentTypesEnum;
static constexpr auto value = glz::enumerate(
int8,
uint8,
int16,
uint16,
int32,
uint32,
int64,
float32,
float64
);
};

#endif // itkComponentTypesJSON_h
2 changes: 0 additions & 2 deletions include/itkFloatTypesJSON.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
#ifndef itkFloatTypesJSON_h
#define itkFloatTypesJSON_h

#include <vector>

#include "glaze/glaze.hpp"

namespace itk
Expand Down
149 changes: 149 additions & 0 deletions include/itkImageJSON.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*=========================================================================
*
* Copyright NumFOCUS
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*=========================================================================*/
#ifndef itkImageJSON_h
#define itkImageJSON_h

#include "itkDefaultConvertPixelTraits.h"

#include "itkWasmMapComponentType.h"
#include "itkWasmMapPixelType.h"
#include "itkIntTypesJSON.h"
#include "itkFloatTypesJSON.h"
#include "itkPixelTypesJSON.h"
#include "itkWasmImage.h"
#include "itkMetaDataDictionaryJSON.h"

#include "glaze/glaze.hpp"

namespace itk
{
/** \class ImageTypeJSON
*
* \brief Image type JSON representation data structure.
*
* \ingroup WebAssemblyInterface
*/
struct ImageTypeJSON
{
unsigned int dimension { 2 };
JSONComponentTypesEnum componentType { JSONComponentTypesEnum::float32 };
JSONPixelTypesEnum pixelType { JSONPixelTypesEnum::Scalar };
unsigned int components { 1 };
};

/** \class ImageJSON
*
* \brief Image JSON representation data structure.
*
* \ingroup WebAssemblyInterface
*/
struct ImageJSON
{
ImageTypeJSON imageType;

std::string name { "Image" };

std::vector<double> origin { 0.0, 0.0 };
std::vector<double> spacing { 1.0, 1.0 };
std::string direction;
std::vector<size_t> size { 0, 0 };

MetadataJSON metadata;
std::string data;
};

template<typename TImage>
auto imageToImageJSON(const TImage * image, const WasmImage<TImage> * wasmImage, bool inMemory) -> ImageJSON
{
using ImageType = TImage;

ImageJSON imageJSON;

imageJSON.imageType.dimension = ImageType::ImageDimension;

using PointType = typename TImage::PointType;
using PixelType = typename TImage::PixelType;
using IOPixelType = typename TImage::IOPixelType;
using ConvertPixelTraits = DefaultConvertPixelTraits<IOPixelType>;
using ComponentType = typename ConvertPixelTraits::ComponentType;
imageJSON.imageType.componentType = wasm::MapComponentType<typename ConvertPixelTraits::ComponentType>::JSONComponentEnum;
imageJSON.imageType.pixelType = wasm::MapPixelType<PixelType>::JSONPixelEnum;
imageJSON.imageType.components = image->GetNumberOfComponentsPerPixel();

imageJSON.name = image->GetObjectName();
imageJSON.imageType.dimension = image->GetImageDimension();

const auto largestRegion = image->GetLargestPossibleRegion();

using PointType = typename ImageType::PointType;
PointType imageOrigin;
image->TransformIndexToPhysicalPoint(largestRegion.GetIndex(), imageOrigin);
imageJSON.origin.clear();
for (unsigned int ii = 0; ii < ImageType::ImageDimension; ++ii)
{
imageJSON.origin.push_back(imageOrigin[ii]);
}

imageJSON.spacing.clear();
const auto imageSpacing = image->GetSpacing();
for (unsigned int ii = 0; ii < ImageType::ImageDimension; ++ii)
{
imageJSON.spacing.push_back(imageSpacing[ii]);
}

if (inMemory)
{
const auto direction = reinterpret_cast< size_t >( image->GetDirection().GetVnlMatrix().begin() );
std::ostringstream directionStream;
directionStream << "data:application/vnd.itk.address,0:";
directionStream << direction;
imageJSON.direction = directionStream.str();
}
else
{
imageJSON.direction = "data:application/vnd.itk.path,data/direction.raw";
}

imageJSON.size.clear();
const auto imageSize = image->GetBufferedRegion().GetSize();
for (unsigned int ii = 0; ii < ImageType::ImageDimension; ++ii)
{
imageJSON.size.push_back(imageSize[ii]);
}

if (inMemory)
{
const auto data = reinterpret_cast< size_t >( image->GetBufferPointer() );
std::ostringstream dataStream;
dataStream << "data:application/vnd.itk.address,0:";
dataStream << data;
imageJSON.data = dataStream.str();
}
else
{
imageJSON.data = "data:application/vnd.itk.path,data/data.raw";
}

auto dictionary = image->GetMetaDataDictionary();
metaDataDictionaryToJSON(dictionary, imageJSON.metadata);

return imageJSON;
}
} // end namespace itk

#endif // itkImageJSON_h
108 changes: 19 additions & 89 deletions include/itkImageToWasmImageFilter.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@
#include "itkWasmMapComponentType.h"
#include "itkWasmMapPixelType.h"

#include "rapidjson/document.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"
#include "itkImageJSON.h"

// add the header for typeid
#include <typeinfo>

namespace itk
{
Expand Down Expand Up @@ -133,92 +134,21 @@ ImageToWasmImageFilter<TImage>
{
// Get the input and output pointers
const ImageType * image = this->GetInput();
WasmImageType * imageJSON = this->GetOutput();

imageJSON->SetImage(image);

using PointType = typename TImage::PointType;
using PixelType = typename TImage::PixelType;
using IOPixelType = typename TImage::IOPixelType;
using ConvertPixelTraits = DefaultConvertPixelTraits<IOPixelType>;
using ComponentType = typename ConvertPixelTraits::ComponentType;

rapidjson::Document document;
document.SetObject();
rapidjson::Document::AllocatorType& allocator = document.GetAllocator();

rapidjson::Value imageType;
imageType.SetObject();

const unsigned int dimension = image->GetImageDimension();
imageType.AddMember("dimension", rapidjson::Value(dimension).Move(), allocator );

rapidjson::Value componentType;
componentType.SetString( wasm::MapComponentType<ComponentType>::ComponentString.data(), allocator );
imageType.AddMember("componentType", componentType.Move(), allocator );

rapidjson::Value pixelType;
pixelType.SetString( wasm::MapPixelType<PixelType>::PixelString.data(), allocator );
imageType.AddMember("pixelType", pixelType.Move(), allocator );

imageType.AddMember("components", rapidjson::Value( image->GetNumberOfComponentsPerPixel() ).Move(), allocator );

document.AddMember( "imageType", imageType.Move(), allocator );

rapidjson::Value origin(rapidjson::kArrayType);

const auto largestRegion = image->GetLargestPossibleRegion();
PointType imageOrigin;
image->TransformIndexToPhysicalPoint(largestRegion.GetIndex(), imageOrigin);
for( unsigned int ii = 0; ii < dimension; ++ii )
{
origin.PushBack(rapidjson::Value().SetDouble(imageOrigin[ii]), allocator);
}
document.AddMember( "origin", origin.Move(), allocator );

rapidjson::Value spacing(rapidjson::kArrayType);
const auto imageSpacing = image->GetSpacing();
for( unsigned int ii = 0; ii < dimension; ++ii )
{
spacing.PushBack(rapidjson::Value().SetDouble(imageSpacing[ii]), allocator);
}
document.AddMember( "spacing", spacing.Move(), allocator );

const auto direction = reinterpret_cast< size_t >( image->GetDirection().GetVnlMatrix().begin() );
std::ostringstream directionStream;
directionStream << "data:application/vnd.itk.address,0:";
directionStream << direction;
rapidjson::Value directionString;
directionString.SetString( directionStream.str().c_str(), allocator );
document.AddMember( "direction", directionString.Move(), allocator );

rapidjson::Value size(rapidjson::kArrayType);
const auto imageSize = image->GetBufferedRegion().GetSize();
for( unsigned int ii = 0; ii < dimension; ++ii )
{
size.PushBack(rapidjson::Value().SetInt(imageSize[ii]), allocator);
}

document.AddMember( "size", size.Move(), allocator );

const auto data = reinterpret_cast< size_t >( image->GetBufferPointer() );
std::ostringstream dataStream;
dataStream << "data:application/vnd.itk.address,0:";
dataStream << data;
rapidjson::Value dataString;
dataString.SetString( dataStream.str().c_str(), allocator );
document.AddMember( "data", dataString.Move(), allocator );

auto dictionary = image->GetMetaDataDictionary();
rapidjson::Value metadataJson(rapidjson::kArrayType);
wasm::ConvertMetaDataDictionaryToJSON(dictionary, metadataJson, allocator);
document.AddMember( "metadata", metadataJson.Move(), allocator );

rapidjson::StringBuffer stringBuffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(stringBuffer);
document.Accept(writer);

imageJSON->SetJSON(stringBuffer.GetString());
WasmImageType * wasmImage = this->GetOutput();

wasmImage->SetImage(image);

constexpr bool inMemory = true;
const ImageJSON imageJSON = imageToImageJSON<ImageType>(image, wasmImage, inMemory);
std::string serialized{};
auto ec = glz::write<glz::opts{ .prettify = true, .concatenate = false }>(imageJSON, serialized);
if (ec)
{
itkExceptionMacro("Failed to serialize ImageJSON");
}
std::cout << "serialized: " << serialized << std::endl;

wasmImage->SetJSON(serialized);
}

template <typename TImage>
Expand Down
17 changes: 10 additions & 7 deletions include/itkInputImageIO.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,24 +73,27 @@ bool lexical_cast(const std::string &input, InputImageIO &inputImageIO)
#ifndef ITK_WASM_NO_MEMORY_IO
const unsigned int index = std::stoi(input);
auto json = getMemoryStoreInputJSON(0, index);
rapidjson::Document document;
document.Parse(json.c_str());
auto deserializedAttempt = glz::read_json<itk::ImageJSON>(json);
if (!deserializedAttempt)
{
const std::string descriptiveError = glz::format_error(deserializedAttempt, json);
throw std::runtime_error("Failed to deserialize ImageJSON: " + descriptiveError);
}
auto imageJSON = deserializedAttempt.value();

auto wasmImageIO = itk::WasmImageIO::New();
wasmImageIO->SetJSON(document);
wasmImageIO->SetJSON(imageJSON);

const unsigned int dimension = wasmImageIO->GetNumberOfDimensions();

auto wasmImageIOBase = itk::WasmImageIOBase::New();
const rapidjson::Value & directionJson = document["direction"];
const std::string directionString( directionJson.GetString() );
const std::string directionString = imageJSON.direction;
const double * directionPtr = reinterpret_cast< double * >( std::strtoull(directionString.substr(35).c_str(), nullptr, 10) );
WasmImageIOBase::DirectionContainerType * directionContainer = wasmImageIOBase->GetDirectionContainer();
directionContainer->resize(dimension*dimension);
directionContainer->assign(directionPtr, directionPtr + dimension*dimension);

const rapidjson::Value & dataJson = document["data"];
const std::string dataString( dataJson.GetString() );
const std::string dataString = imageJSON.data;
const char * dataPtr = reinterpret_cast< char * >( std::strtoull(dataString.substr(35).c_str(), nullptr, 10) );
if (dataPtr != nullptr)
{
Expand Down
Loading

0 comments on commit 7c87834

Please sign in to comment.