From d81379d756d756eb0d61ffdf34c20eae98b2a77c Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Wed, 3 Jul 2024 15:28:08 -0400 Subject: [PATCH 01/10] refactor(WasmMeshToMeshFilter): use glaze --- include/itkFloatTypesJSON.h | 2 - include/itkIntTypesJSON.h | 53 ++++++ include/itkMeshJSON.h | 161 ++++++++++++++++++ include/itkMeshToWasmMeshFilter.hxx | 144 +--------------- include/itkPixelTypesJSON.h | 69 ++++++++ include/itkTransformJSON.h | 4 +- include/itkWasmMapComponentType.h | 69 ++++++++ include/itkWasmMapPixelType.h | 17 ++ include/itkWasmMeshToMeshFilter.hxx | 98 +++++------ include/itkWasmTransformToTransformFilter.hxx | 6 +- .../itk-wasm/src/interface-types/mesh-type.ts | 14 +- src/itkWasmTransformIO.cxx | 3 +- 12 files changed, 436 insertions(+), 204 deletions(-) create mode 100644 include/itkIntTypesJSON.h create mode 100644 include/itkMeshJSON.h create mode 100644 include/itkPixelTypesJSON.h diff --git a/include/itkFloatTypesJSON.h b/include/itkFloatTypesJSON.h index e44a92089..e072a2256 100644 --- a/include/itkFloatTypesJSON.h +++ b/include/itkFloatTypesJSON.h @@ -18,8 +18,6 @@ #ifndef itkFloatTypesJSON_h #define itkFloatTypesJSON_h -#include - #include "glaze/glaze.hpp" namespace itk diff --git a/include/itkIntTypesJSON.h b/include/itkIntTypesJSON.h new file mode 100644 index 000000000..90ee43d8a --- /dev/null +++ b/include/itkIntTypesJSON.h @@ -0,0 +1,53 @@ +/*========================================================================= + * + * 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 itkIntTypesJSON_h +#define itkIntTypesJSON_h + +#include "glaze/glaze.hpp" + +namespace itk +{ + enum class JSONIntTypesEnum + { + int8, + uint8, + int16, + uint16, + int32, + uint32, + int64, + uint64 + }; +} // end namespace itk + +template <> +struct glz::meta { + using enum itk::JSONIntTypesEnum; + static constexpr auto value = glz::enumerate( + int8, + uint8, + int16, + uint16, + int32, + uint32, + int64, + uint64 + ); +}; + +#endif // itkIntTypesJSON_h diff --git a/include/itkMeshJSON.h b/include/itkMeshJSON.h new file mode 100644 index 000000000..f357b5471 --- /dev/null +++ b/include/itkMeshJSON.h @@ -0,0 +1,161 @@ +/*========================================================================= + * + * 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 itkMeshJSON_h +#define itkMeshJSON_h + +#include "itkMeshConvertPixelTraits.h" + +#include "itkWasmMapComponentType.h" +#include "itkWasmMapPixelType.h" +#include "itkIntTypesJSON.h" +#include "itkFloatTypesJSON.h" +#include "itkPixelTypesJSON.h" +#include "itkWasmMesh.h" + +#include "glaze/glaze.hpp" + +namespace itk +{ + /** \class MeshTypeJSON + * + * \brief Mesh type JSON representation data structure. + * + * \ingroup WebAssemblyInterface + */ + struct MeshTypeJSON + { + unsigned int dimension { 2 }; + JSONFloatTypesEnum pointComponentType { JSONFloatTypesEnum::float32 }; + JSONComponentTypesEnum pointPixelComponentType { JSONComponentTypesEnum::float32 }; + JSONPixelTypesEnum pointPixelType { JSONPixelTypesEnum::Scalar }; + unsigned int pointPixelComponents { 1 }; + JSONIntTypesEnum cellComponentType { JSONIntTypesEnum::uint32 }; + JSONComponentTypesEnum cellPixelComponentType { JSONComponentTypesEnum::float32 }; + JSONPixelTypesEnum cellPixelType { JSONPixelTypesEnum::Scalar }; + unsigned int cellPixelComponents { 1 }; + }; + + /** \class MeshJSON + * + * \brief Mesh JSON representation data structure. + * + * \ingroup WebAssemblyInterface + */ + struct MeshJSON + { + MeshTypeJSON meshType; + + std::string name; + + size_t numberOfPoints{ 0 }; + std::string points; + + size_t numberOfPointPixels{ 0 }; + std::string pointData; + + size_t numberOfCells{ 0 }; + std::string cells; + size_t cellBufferSize{ 0 }; + + size_t numberOfCellPixels{ 0 }; + std::string cellData; + }; + +template +auto meshToMeshJSON(const TMesh * mesh, const WasmMesh * wasmMesh, bool inMemory) -> MeshJSON +{ + using MeshType = TMesh; + + MeshJSON meshJSON; + + meshJSON.meshType.dimension = MeshType::PointDimension; + + meshJSON.meshType.pointComponentType = wasm::MapComponentType::JSONFloatTypeEnum; + using PointPixelType = typename TMesh::PixelType; + using ConvertPointPixelTraits = MeshConvertPixelTraits; + meshJSON.meshType.pointPixelComponentType = wasm::MapComponentType::JSONComponentEnum; + meshJSON.meshType.pointPixelType = wasm::MapPixelType::JSONPixelEnum; + meshJSON.meshType.pointPixelComponents = ConvertPointPixelTraits::GetNumberOfComponents(); + meshJSON.meshType.cellComponentType = wasm::MapComponentType::JSONIntTypeEnum; + using CellPixelType = typename TMesh::CellPixelType; + using ConvertCellPixelTraits = MeshConvertPixelTraits; + meshJSON.meshType.cellPixelComponentType = wasm::MapComponentType::JSONComponentEnum; + meshJSON.meshType.cellPixelType = wasm::MapPixelType::JSONPixelEnum; + meshJSON.meshType.cellPixelComponents = ConvertCellPixelTraits::GetNumberOfComponents(); + + meshJSON.name = mesh->GetObjectName(); + meshJSON.numberOfPoints = mesh->GetNumberOfPoints(); + if (mesh->GetPointData() == nullptr) + { + meshJSON.numberOfPointPixels = 0; + } + else + { + meshJSON.numberOfPointPixels = mesh->GetPointData()->Size(); + } + meshJSON.numberOfCells = mesh->GetNumberOfCells(); + if (mesh->GetCellData() == nullptr) + { + meshJSON.numberOfCellPixels = 0; + } + else + { + meshJSON.numberOfCellPixels = mesh->GetCellData()->Size(); + } + meshJSON.cellBufferSize = wasmMesh->GetCellBuffer()->Size(); + + const auto pointsAddress = reinterpret_cast< size_t >( &(mesh->GetPoints()->at(0)) ); + std::ostringstream pointsStream; + pointsStream << "data:application/vnd.itk.address,0:"; + pointsStream << pointsAddress; + meshJSON.points = pointsStream.str(); + size_t cellsAddress = 0; + if (mesh->GetNumberOfCells() > 0) + { + cellsAddress = reinterpret_cast< size_t >( &(wasmMesh->GetCellBuffer()->at(0)) ); + } + std::ostringstream cellsStream; + cellsStream << "data:application/vnd.itk.address,0:"; + cellsStream << cellsAddress; + meshJSON.cells = cellsStream.str(); + + size_t pointDataAddress = 0; + if (mesh->GetPointData() != nullptr && mesh->GetPointData()->Size() > 0) + { + pointDataAddress = reinterpret_cast< size_t >( &(mesh->GetPointData()->at(0)) ); + } + std::ostringstream pointDataStream; + pointDataStream << "data:application/vnd.itk.address,0:"; + pointDataStream << pointDataAddress; + meshJSON.pointData = pointDataStream.str(); + + size_t cellDataAddress = 0; + if (mesh->GetCellData() != nullptr && mesh->GetCellData()->Size() > 0) + { + cellDataAddress = reinterpret_cast< size_t >( &(mesh->GetCellData()->at(0)) ); + } + std::ostringstream cellDataStream; + cellDataStream << "data:application/vnd.itk.address,0:"; + cellDataStream << cellDataAddress; + meshJSON.cellData = cellDataStream.str(); + + return meshJSON; +} +} // end namespace itk + +#endif // itkMeshJSON_h diff --git a/include/itkMeshToWasmMeshFilter.hxx b/include/itkMeshToWasmMeshFilter.hxx index efb90245a..2ac5ef339 100644 --- a/include/itkMeshToWasmMeshFilter.hxx +++ b/include/itkMeshToWasmMeshFilter.hxx @@ -18,16 +18,7 @@ #ifndef itkMeshToWasmMeshFilter_hxx #define itkMeshToWasmMeshFilter_hxx -#include "itkMeshToWasmMeshFilter.h" - -#include "itkMeshConvertPixelTraits.h" - -#include "itkWasmMapComponentType.h" -#include "itkWasmMapPixelType.h" - -#include "rapidjson/document.h" -#include "rapidjson/stringbuffer.h" -#include "rapidjson/writer.h" +#include "glaze/glaze.hpp" namespace itk { @@ -135,134 +126,17 @@ MeshToWasmMeshFilter WasmMeshType * wasmMesh = this->GetOutput(); wasmMesh->SetMesh(mesh); - - rapidjson::Document document; - document.SetObject(); - rapidjson::Document::AllocatorType& allocator = document.GetAllocator(); - - rapidjson::Value meshType; - meshType.SetObject(); - - constexpr unsigned int dimension = MeshType::PointDimension; - meshType.AddMember("dimension", rapidjson::Value(dimension).Move(), allocator ); - - rapidjson::Value pointComponentType; - pointComponentType.SetString( wasm::MapComponentType::ComponentString.data(), allocator ); - meshType.AddMember("pointComponentType", pointComponentType.Move(), allocator ); - - using PointPixelType = typename TMesh::PixelType; - using ConvertPointPixelTraits = MeshConvertPixelTraits; - rapidjson::Value pointPixelComponentType; - pointPixelComponentType.SetString( wasm::MapComponentType::ComponentString.data(), allocator ); - meshType.AddMember("pointPixelComponentType", pointPixelComponentType.Move(), allocator ); - - rapidjson::Value pointPixelType; - pointPixelType.SetString( wasm::MapPixelType::PixelString.data(), allocator ); - meshType.AddMember("pointPixelType", pointPixelType.Move(), allocator ); - - meshType.AddMember("pointPixelComponents", rapidjson::Value( ConvertPointPixelTraits::GetNumberOfComponents() ).Move(), allocator ); - - rapidjson::Value cellComponentType; - cellComponentType.SetString( wasm::MapComponentType::ComponentString.data(),allocator ); - meshType.AddMember("cellComponentType", cellComponentType.Move(), allocator ); - - using CellPixelType = typename TMesh::CellPixelType; - using ConvertCellPixelTraits = MeshConvertPixelTraits; - rapidjson::Value cellPixelComponentType; - cellPixelComponentType.SetString( wasm::MapComponentType::ComponentString.data(), allocator ); - meshType.AddMember("cellPixelComponentType", cellPixelComponentType.Move(), allocator ); - - rapidjson::Value cellPixelType; - cellPixelType.SetString( wasm::MapPixelType::PixelString.data(), allocator ); - meshType.AddMember("cellPixelType", cellPixelType, allocator ); - - meshType.AddMember("cellPixelComponents", rapidjson::Value( ConvertCellPixelTraits::GetNumberOfComponents() ).Move(), allocator ); - - document.AddMember( "meshType", meshType.Move(), allocator ); - - rapidjson::Value numberOfPoints; - numberOfPoints.SetInt( mesh->GetNumberOfPoints() ); - document.AddMember( "numberOfPoints", numberOfPoints.Move(), allocator ); - - rapidjson::Value numberOfPointPixels; - if (mesh->GetPointData() == nullptr) - { - numberOfPointPixels.SetInt( 0 ); - } - else + constexpr bool inMemory = true; + const auto meshJSON = meshToMeshJSON(mesh, wasmMesh, inMemory); + std::string serialized{}; + auto ec = glz::write(meshJSON, serialized); + if (ec) { - numberOfPointPixels.SetInt( mesh->GetPointData()->Size() ); + itkExceptionMacro("Failed to serialize TransformListJSON"); } - document.AddMember( "numberOfPointPixels", numberOfPointPixels.Move(), allocator ); - - rapidjson::Value numberOfCells; - numberOfCells.SetInt( mesh->GetNumberOfCells() ); - document.AddMember( "numberOfCells", numberOfCells.Move(), allocator ); - - rapidjson::Value numberOfCellPixels; - if (mesh->GetCellData() == nullptr) - { - numberOfCellPixels.SetInt( 0 ); - } - else - { - numberOfCellPixels.SetInt( mesh->GetCellData()->Size() ); - } - document.AddMember( "numberOfCellPixels", numberOfCellPixels.Move(), allocator ); - - rapidjson::Value cellBufferSizeMember; - cellBufferSizeMember.SetInt( wasmMesh->GetCellBuffer()->Size() ); - document.AddMember( "cellBufferSize", cellBufferSizeMember.Move(), allocator ); - - const auto pointsAddress = reinterpret_cast< size_t >( &(mesh->GetPoints()->at(0)) ); - std::ostringstream pointsStream; - pointsStream << "data:application/vnd.itk.address,0:"; - pointsStream << pointsAddress; - rapidjson::Value pointsString; - pointsString.SetString( pointsStream.str().c_str(), allocator ); - document.AddMember( "points", pointsString.Move(), allocator ); - - size_t cellsAddress = 0; - if (mesh->GetNumberOfCells() > 0) - { - cellsAddress = reinterpret_cast< size_t >( &(wasmMesh->GetCellBuffer()->at(0)) ); - } - std::ostringstream cellsStream; - cellsStream << "data:application/vnd.itk.address,0:"; - cellsStream << cellsAddress; - rapidjson::Value cellsString; - cellsString.SetString( cellsStream.str().c_str(), allocator ); - document.AddMember( "cells", cellsString.Move(), allocator ); - - size_t pointDataAddress = 0; - if (mesh->GetPointData() != nullptr && mesh->GetPointData()->Size() > 0) - { - pointDataAddress = reinterpret_cast< size_t >( &(mesh->GetPointData()->at(0)) ); - } - std::ostringstream pointDataStream; - pointDataStream << "data:application/vnd.itk.address,0:"; - pointDataStream << pointDataAddress; - rapidjson::Value pointDataString; - pointDataString.SetString( pointDataStream.str().c_str(), allocator ); - document.AddMember( "pointData", pointDataString.Move(), allocator ); - - size_t cellDataAddress = 0; - if (mesh->GetCellData() != nullptr && mesh->GetCellData()->Size() > 0) - { - cellDataAddress = reinterpret_cast< size_t >( &(mesh->GetCellData()->at(0)) ); - } - std::ostringstream cellDataStream; - cellDataStream << "data:application/vnd.itk.address,0:"; - cellDataStream << cellDataAddress; - rapidjson::Value cellDataString; - cellDataString.SetString( cellDataStream.str().c_str(), allocator ); - document.AddMember( "cellData", cellDataString.Move(), allocator ); - - rapidjson::StringBuffer stringBuffer; - rapidjson::Writer writer(stringBuffer); - document.Accept(writer); + std::cout << "SERIALIZED: " << serialized << std::endl; - wasmMesh->SetJSON(stringBuffer.GetString()); + wasmMesh->SetJSON(serialized); } template diff --git a/include/itkPixelTypesJSON.h b/include/itkPixelTypesJSON.h new file mode 100644 index 000000000..558f8bc6a --- /dev/null +++ b/include/itkPixelTypesJSON.h @@ -0,0 +1,69 @@ +/*========================================================================= + * + * 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 itkPixelTypesJSON_h +#define itkPixelTypesJSON_h + +#include "glaze/glaze.hpp" + +namespace itk +{ + enum class JSONPixelTypesEnum + { + Unknown, + Scalar, + RGB, + RGBA, + Offset, + Vector, + Point, + CovariantVector, + SymmetricSecondRankTensor, + DiffusionTensor3D, + Complex, + FixedArray, + Array, + Matrix, + VariableLengthVector, + VariableSizeMatrix + }; +} // end namespace itk + +template <> +struct glz::meta { + using enum itk::JSONPixelTypesEnum; + static constexpr auto value = glz::enumerate( + Unknown, + Scalar, + RGB, + RGBA, + Offset, + Vector, + Point, + CovariantVector, + SymmetricSecondRankTensor, + DiffusionTensor3D, + Complex, + FixedArray, + Array, + Matrix, + VariableLengthVector, + VariableSizeMatrix + ); +}; + +#endif // itkPixelTypesJSON_h diff --git a/include/itkTransformJSON.h b/include/itkTransformJSON.h index f31089cb6..de9dc189e 100644 --- a/include/itkTransformJSON.h +++ b/include/itkTransformJSON.h @@ -87,8 +87,8 @@ namespace itk std::string name; std::string inputSpaceName; std::string outputSpaceName; - std::string fixedParameters{ "data:application/vnd.itk.path,data/fixed-parameters.raw" }; - std::string parameters{ "data:application/vnd.itk.path,data/parameters.raw" }; + std::string fixedParameters; + std::string parameters; }; /** \class TransformListJSON diff --git a/include/itkWasmMapComponentType.h b/include/itkWasmMapComponentType.h index d284f325f..da6e1c6fe 100644 --- a/include/itkWasmMapComponentType.h +++ b/include/itkWasmMapComponentType.h @@ -18,12 +18,31 @@ #ifndef itkWasmMapComponentType_h #define itkWasmMapComponentType_h +#include +#include #include + #include "itkIntTypes.h" +#include "itkIntTypesJSON.h" +#include "itkFloatTypesJSON.h" + namespace itk { +enum class JSONComponentTypesEnum +{ + int8, + uint8, + int16, + uint16, + int32, + uint32, + int64, + uint64, + float32, + float64 +}; namespace wasm { @@ -31,12 +50,17 @@ template struct MapComponentType { static constexpr std::string_view ComponentString = "Unknown"; + static constexpr JSONComponentTypesEnum JSONComponentEnum = JSONComponentTypesEnum::uint8; + static constexpr JSONIntTypesEnum JSONIntTypeEnum = JSONIntTypesEnum::uint8; + static constexpr JSONFloatTypesEnum JSONFloatTypeEnum = JSONFloatTypesEnum::float32; }; template <> struct MapComponentType { static constexpr std::string_view ComponentString = "int8"; + static constexpr JSONComponentTypesEnum JSONComponentEnum = JSONComponentTypesEnum::int8; + static constexpr JSONIntTypesEnum JSONIntTypeEnum = JSONIntTypesEnum::int8; }; template <> @@ -45,36 +69,48 @@ struct MapComponentType // Todo: does not compile: // std::numeric_limits::is_signed ? "int8" : "uint8_ static constexpr std::string_view ComponentString = "int8"; + static constexpr JSONComponentTypesEnum JSONComponentEnum = JSONComponentTypesEnum::int8; + static constexpr JSONIntTypesEnum JSONIntTypeEnum = JSONIntTypesEnum::int8; }; template <> struct MapComponentType { static constexpr std::string_view ComponentString = "uint8"; + static constexpr JSONComponentTypesEnum JSONComponentEnum = JSONComponentTypesEnum::uint8; + static constexpr JSONIntTypesEnum JSONIntTypeEnum = JSONIntTypesEnum::uint8; }; template <> struct MapComponentType { static constexpr std::string_view ComponentString = "int16"; + static constexpr JSONComponentTypesEnum JSONComponentEnum = JSONComponentTypesEnum::int16; + static constexpr JSONIntTypesEnum JSONIntTypeEnum = JSONIntTypesEnum::int16; }; template <> struct MapComponentType { static constexpr std::string_view ComponentString = "uint16"; + static constexpr JSONComponentTypesEnum JSONComponentEnum = JSONComponentTypesEnum::uint16; + static constexpr JSONIntTypesEnum JSONIntTypeEnum = JSONIntTypesEnum::uint16; }; template <> struct MapComponentType { static constexpr std::string_view ComponentString = "int32"; + static constexpr JSONComponentTypesEnum JSONComponentEnum = JSONComponentTypesEnum::int32; + static constexpr JSONIntTypesEnum JSONIntTypeEnum = JSONIntTypesEnum::int32; }; template <> struct MapComponentType { static constexpr std::string_view ComponentString = "uint32"; + static constexpr JSONComponentTypesEnum JSONComponentEnum = JSONComponentTypesEnum::uint32; + static constexpr JSONIntTypesEnum JSONIntTypeEnum = JSONIntTypesEnum::uint32; }; #if ((LLONG_MAX != LONG_MAX)) @@ -82,12 +118,16 @@ template <> struct MapComponentType { static constexpr std::string_view ComponentString = "int32"; + static constexpr JSONComponentTypesEnum JSONComponentEnum = JSONComponentTypesEnum::int32; + static constexpr JSONIntTypesEnum JSONIntTypeEnum = JSONIntTypesEnum::int32; }; #else template <> struct MapComponentType { static constexpr std::string_view ComponentString = "int64"; + static constexpr JSONComponentTypesEnum JSONComponentEnum = JSONComponentTypesEnum::int64; + static constexpr JSONIntTypesEnum JSONIntTypeEnum = JSONIntTypesEnum::int64; }; #endif @@ -96,12 +136,16 @@ template <> struct MapComponentType { static constexpr std::string_view ComponentString = "uint32"; + static constexpr JSONComponentTypesEnum JSONComponentEnum = JSONComponentTypesEnum::uint32; + static constexpr JSONIntTypesEnum JSONIntTypeEnum = JSONIntTypesEnum::uint32; }; #else template <> struct MapComponentType { static constexpr std::string_view ComponentString = "uint64"; + static constexpr JSONComponentTypesEnum JSONComponentEnum = JSONComponentTypesEnum::uint64; + static constexpr JSONIntTypesEnum JSONIntTypeEnum = JSONIntTypesEnum::uint64; }; #endif @@ -109,26 +153,51 @@ template <> struct MapComponentType { static constexpr std::string_view ComponentString = "int64"; + static constexpr JSONComponentTypesEnum JSONComponentEnum = JSONComponentTypesEnum::int64; + static constexpr JSONIntTypesEnum JSONIntTypeEnum = JSONIntTypesEnum::int64; }; template <> struct MapComponentType { static constexpr std::string_view ComponentString = "uint64"; + static constexpr JSONComponentTypesEnum JSONComponentEnum = JSONComponentTypesEnum::uint64; + static constexpr JSONIntTypesEnum JSONIntTypeEnum = JSONIntTypesEnum::uint64; }; template <> struct MapComponentType { static constexpr std::string_view ComponentString = "float32"; + static constexpr JSONComponentTypesEnum JSONComponentEnum = JSONComponentTypesEnum::float32; + static constexpr JSONFloatTypesEnum JSONFloatTypeEnum = JSONFloatTypesEnum::float32; }; template <> struct MapComponentType { static constexpr std::string_view ComponentString = "float64"; + static constexpr JSONComponentTypesEnum JSONComponentEnum = JSONComponentTypesEnum::float64; + static constexpr JSONFloatTypesEnum JSONFloatTypeEnum = JSONFloatTypesEnum::float64; }; } // end namespace wasm } // end namespace itk + +template <> +struct glz::meta { + using enum itk::JSONComponentTypesEnum; + static constexpr auto value = glz::enumerate( + int8, + uint8, + int16, + uint16, + int32, + uint32, + int64, + float32, + float64 + ); +}; + #endif // itkWasmMapComponentType_h diff --git a/include/itkWasmMapPixelType.h b/include/itkWasmMapPixelType.h index b2a881a55..26e27dca4 100644 --- a/include/itkWasmMapPixelType.h +++ b/include/itkWasmMapPixelType.h @@ -35,6 +35,8 @@ #include +#include "itkPixelTypesJSON.h" + namespace itk { @@ -46,84 +48,98 @@ struct MapPixelType { // scalar static constexpr std::string_view PixelString = "Scalar"; + static constexpr JSONPixelTypesEnum JSONPixelEnum = JSONPixelTypesEnum::Scalar; }; template struct MapPixelType> { static constexpr std::string_view PixelString = "RGB"; + static constexpr JSONPixelTypesEnum JSONPixelEnum = JSONPixelTypesEnum::RGB; }; template struct MapPixelType> { static constexpr std::string_view PixelString = "RGBA"; + static constexpr JSONPixelTypesEnum JSONPixelEnum = JSONPixelTypesEnum::RGBA; }; template struct MapPixelType> { static constexpr std::string_view PixelString = "Offset"; + static constexpr JSONPixelTypesEnum JSONPixelEnum = JSONPixelTypesEnum::Offset; }; template struct MapPixelType> { static constexpr std::string_view PixelString = "Vector"; + static constexpr JSONPixelTypesEnum JSONPixelEnum = JSONPixelTypesEnum::Vector; }; template struct MapPixelType> { static constexpr std::string_view PixelString = "Point"; + static constexpr JSONPixelTypesEnum JSONPixelEnum = JSONPixelTypesEnum::Point; }; template struct MapPixelType> { static constexpr std::string_view PixelString = "CovariantVector"; + static constexpr JSONPixelTypesEnum JSONPixelEnum = JSONPixelTypesEnum::CovariantVector; }; template struct MapPixelType> { static constexpr std::string_view PixelString = "SymmetricSecondRankTensor"; + static constexpr JSONPixelTypesEnum JSONPixelEnum = JSONPixelTypesEnum::SymmetricSecondRankTensor; }; template struct MapPixelType> { static constexpr std::string_view PixelString = "DiffusionTensor3D"; + static constexpr JSONPixelTypesEnum JSONPixelEnum = JSONPixelTypesEnum::DiffusionTensor3D; }; template struct MapPixelType> { static constexpr std::string_view PixelString = "Complex"; + static constexpr JSONPixelTypesEnum JSONPixelEnum = JSONPixelTypesEnum::Complex; }; template struct MapPixelType> { static constexpr std::string_view PixelString = "FixedArray"; + static constexpr JSONPixelTypesEnum JSONPixelEnum = JSONPixelTypesEnum::FixedArray; }; template struct MapPixelType> { static constexpr std::string_view PixelString = "Array"; + static constexpr JSONPixelTypesEnum JSONPixelEnum = JSONPixelTypesEnum::Array; }; template struct MapPixelType> { static constexpr std::string_view PixelString = "Matrix"; + static constexpr JSONPixelTypesEnum JSONPixelEnum = JSONPixelTypesEnum::Matrix; }; template struct MapPixelType> { static constexpr std::string_view PixelString = "VariableLengthVector"; + static constexpr JSONPixelTypesEnum JSONPixelEnum = JSONPixelTypesEnum::VariableLengthVector; }; @@ -131,6 +147,7 @@ template struct MapPixelType> { static constexpr std::string_view PixelString = "VariableSizeMatrix"; + static constexpr JSONPixelTypesEnum JSONPixelEnum = JSONPixelTypesEnum::VariableSizeMatrix; }; diff --git a/include/itkWasmMeshToMeshFilter.hxx b/include/itkWasmMeshToMeshFilter.hxx index a400a471d..f23342f00 100644 --- a/include/itkWasmMeshToMeshFilter.hxx +++ b/include/itkWasmMeshToMeshFilter.hxx @@ -36,7 +36,7 @@ #include "itkWasmMapPixelType.h" #include "itkMeshConvertPixelTraits.h" -#include "rapidjson/document.h" +#include "itkMeshJSON.h" namespace { @@ -360,8 +360,7 @@ WasmMeshToMeshFilter ::GenerateData() { // Get the input and output pointers - const WasmMeshType * meshJSON = this->GetInput(); - const std::string json(meshJSON->GetJSON()); + const WasmMeshType * wasmMesh = this->GetInput(); MeshType * mesh = this->GetOutput(); using PointPixelType = typename MeshType::PixelType; @@ -369,76 +368,72 @@ WasmMeshToMeshFilter using CellPixelType = typename MeshType::CellPixelType; using ConvertCellPixelTraits = MeshConvertPixelTraits; - rapidjson::Document document; - if (document.Parse(json.c_str()).HasParseError()) - { - throw std::runtime_error("Could not parse JSON"); - } - - const rapidjson::Value & meshType = document["meshType"]; - - const rapidjson::Value & numberOfPointsJson = document["numberOfPoints"]; - const SizeValueType numberOfPoints = numberOfPointsJson.GetInt(); - - const rapidjson::Value & numberOfPointPixelsJson = document["numberOfPointPixels"]; - const SizeValueType numberOfPointPixels = numberOfPointPixelsJson.GetInt(); - // const rapidjson::Value & pointPixelComponentsJson = meshType["pointPixelComponents"]; - // const SizeValueType pointPixelComponents = pointPixelComponentsJson.GetInt(); - - const rapidjson::Value & numberOfCellPixelsJson = document["numberOfCellPixels"]; - const SizeValueType numberOfCellPixels = numberOfCellPixelsJson.GetInt(); - // const rapidjson::Value & cellPixelComponentsJson = meshType["cellPixelComponents"]; - // const SizeValueType cellPixelComponents = cellPixelComponentsJson.GetInt(); + std::cout << "meshJSON: " << wasmMesh->GetJSON() << "\n"; + const std::string json(wasmMesh->GetJSON()); + auto deserializedAttempt = glz::read_json(json); + if (!deserializedAttempt) + { + const std::string descriptiveError = glz::format_error(deserializedAttempt, json); + itkExceptionMacro("Failed to deserialize meshJSON: " << descriptiveError); + } + auto meshJSON = deserializedAttempt.value(); + + const auto dimension = meshJSON.meshType.dimension; + const auto numberOfPointPixels = meshJSON.numberOfPointPixels; + const auto pointComponentType = meshJSON.meshType.pointComponentType; + const auto pointPixelComponentType = meshJSON.meshType.pointPixelComponentType; + const auto pointPixelType = meshJSON.meshType.pointPixelType; + const auto cellComponentType = meshJSON.meshType.cellComponentType; + const auto numberOfCellPixels = meshJSON.numberOfCellPixels; + const auto cellPixelComponentType = meshJSON.meshType.cellPixelComponentType; + const auto cellPixelType = meshJSON.meshType.cellPixelType; + const auto numberOfPoints = meshJSON.numberOfPoints; + const auto numberOfCells = meshJSON.numberOfCells; - const int dimension = meshType["dimension"].GetInt(); if (dimension != MeshType::PointDimension) { throw std::runtime_error("Unexpected dimension"); } - const std::string pointPixelComponentType( meshType["pointPixelComponentType"].GetString() ); - if (numberOfPointPixels && pointPixelComponentType != itk::wasm::MapComponentType::ComponentString ) + if (numberOfPointPixels && pointPixelComponentType != itk::wasm::MapComponentType::JSONComponentEnum ) { throw std::runtime_error("Unexpected point pixel component type"); } - const std::string pointPixelType( meshType["pointPixelType"].GetString() ); - if (numberOfPointPixels && pointPixelType != itk::wasm::MapPixelType::PixelString ) + if (numberOfPointPixels && pointPixelType != itk::wasm::MapPixelType::JSONPixelEnum ) { throw std::runtime_error("Unexpected point pixel type"); } - const std::string cellPixelComponentType( meshType["cellPixelComponentType"].GetString() ); - if (numberOfCellPixels && cellPixelComponentType != itk::wasm::MapComponentType::ComponentString ) + if (numberOfCellPixels && cellPixelComponentType != itk::wasm::MapComponentType::JSONComponentEnum ) { + std::cout << "numberOfCellPixels: " << numberOfCellPixels << "\n"; throw std::runtime_error("Unexpected cell pixel component type"); } - const std::string cellPixelType( meshType["cellPixelType"].GetString() ); - if (numberOfCellPixels && cellPixelType != itk::wasm::MapPixelType::PixelString ) + if (numberOfCellPixels && cellPixelType != itk::wasm::MapPixelType::JSONPixelEnum ) { throw std::runtime_error("Unexpected cell pixel type"); } - mesh->GetPoints()->resize(numberOfPoints); + mesh->SetObjectName(meshJSON.name); + mesh->GetPoints()->resize(meshJSON.numberOfPoints); using PointType = typename MeshType::PointType; - const rapidjson::Value & pointsJson = document["points"]; - const std::string pointsString( pointsJson.GetString() ); - const std::string pointComponentType( meshType["pointComponentType"].GetString() ); + const std::string pointsString = meshJSON.points; if (numberOfPoints) { - if (pointComponentType == itk::wasm::MapComponentType::ComponentString ) + if (pointComponentType == itk::wasm::MapComponentType::JSONFloatTypeEnum) { const auto * pointsPtr = reinterpret_cast< PointType * >( std::strtoull(pointsString.substr(35).c_str(), nullptr, 10) ); - mesh->GetPoints()->assign(pointsPtr, pointsPtr + numberOfPoints); + mesh->GetPoints()->assign(pointsPtr, pointsPtr + meshJSON.numberOfPoints); } - else if (pointComponentType == itk::wasm::MapComponentType::ComponentString) + else if (pointComponentType == itk::wasm::MapComponentType::JSONFloatTypeEnum) { auto * pointsPtr = reinterpret_cast< float * >( std::strtoull(pointsString.substr(35).c_str(), nullptr, 10) ); const size_t pointComponents = numberOfPoints * dimension; auto * pointsContainerPtr = reinterpret_cast(&(mesh->GetPoints()->at(0)) ); std::copy(pointsPtr, pointsPtr + pointComponents, pointsContainerPtr); } - else if (pointComponentType == itk::wasm::MapComponentType::ComponentString) + else if (pointComponentType == itk::wasm::MapComponentType::JSONFloatTypeEnum) { auto * pointsPtr = reinterpret_cast< double * >( std::strtoull(pointsString.substr(35).c_str(), nullptr, 10) ); const size_t pointComponents = numberOfPoints * dimension; @@ -452,19 +447,16 @@ WasmMeshToMeshFilter } - const rapidjson::Value & cellBufferSizeJson = document["cellBufferSize"]; - const SizeValueType cellBufferSize = cellBufferSizeJson.GetInt(); - const rapidjson::Value & cellsJson = document["cells"]; - const std::string cellsString( cellsJson.GetString() ); + const SizeValueType cellBufferSize = meshJSON.cellBufferSize; + const std::string cellsString = meshJSON.cells; using CellBufferType = typename WasmMeshType::CellBufferContainerType::Element; CellBufferType * cellsBufferPtr = reinterpret_cast< CellBufferType * >( static_cast< size_t >(std::strtoull(cellsString.substr(35).c_str(), nullptr, 10)) ); - const std::string cellComponentType( meshType["cellComponentType"].GetString() ); - if (cellComponentType == "uint32") + if (cellComponentType == JSONIntTypesEnum::uint32) { uint32_t * cellsBufferPtr = reinterpret_cast< uint32_t * >( static_cast< size_t >(std::strtoull(cellsString.substr(35).c_str(), nullptr, 10)) ); populateCells(mesh, cellBufferSize, cellsBufferPtr); } - else if (cellComponentType == "uint64") + else if (cellComponentType == JSONIntTypesEnum::uint64) { uint64_t * cellsBufferPtr = reinterpret_cast< uint64_t * >( static_cast< size_t >(std::strtoull(cellsString.substr(35).c_str(), nullptr, 10)) ); populateCells(mesh, cellBufferSize, cellsBufferPtr); @@ -474,25 +466,23 @@ WasmMeshToMeshFilter throw std::runtime_error("Unexpected cell component type"); } - const rapidjson::Value & pointDataJson = document["pointData"]; using PointPixelType = typename TMesh::PixelType; - const std::string pointDataString( pointDataJson.GetString() ); + const std::string pointDataString = meshJSON.pointData; auto pointDataPtr = reinterpret_cast< PointPixelType * >( std::strtoull(pointDataString.substr(35).c_str(), nullptr, 10) ); mesh->GetPointData()->resize(numberOfPointPixels); mesh->GetPointData()->assign(pointDataPtr, pointDataPtr + numberOfPointPixels); - const rapidjson::Value & cellDataJson = document["cellData"]; using CellPixelType = typename TMesh::CellPixelType; - const std::string cellDataString( cellDataJson.GetString() ); + const std::string cellDataString = meshJSON.cellData; auto cellDataPtr = reinterpret_cast< CellPixelType * >( std::strtoull(cellDataString.substr(35).c_str(), nullptr, 10) ); if (mesh->GetCellData() == nullptr) { mesh->SetCellData(MeshType::CellDataContainer::New()); } - if (numberOfCellPixels) + if (meshJSON.numberOfCellPixels) { - mesh->GetCellData()->resize(numberOfCellPixels); - mesh->GetCellData()->assign(cellDataPtr, cellDataPtr + numberOfCellPixels); + mesh->GetCellData()->resize(meshJSON.numberOfCellPixels); + mesh->GetCellData()->assign(cellDataPtr, cellDataPtr + meshJSON.numberOfCellPixels); } } diff --git a/include/itkWasmTransformToTransformFilter.hxx b/include/itkWasmTransformToTransformFilter.hxx index 4890d6dfa..c0cf3d7fd 100644 --- a/include/itkWasmTransformToTransformFilter.hxx +++ b/include/itkWasmTransformToTransformFilter.hxx @@ -135,10 +135,12 @@ WasmTransformToTransformFilter // Get the input and output pointers const WasmTransformType * wasmTransform = this->GetInput(); - auto deserializedAttempt = glz::read_json(wasmTransform->GetJSON()); + const std::string json(wasmTransform->GetJSON()); + auto deserializedAttempt = glz::read_json(json); if (!deserializedAttempt) { - itkExceptionMacro("Failed to deserialize TransformListJSON"); + const std::string descriptiveError = glz::format_error(deserializedAttempt, json); + itkExceptionMacro("Failed to deserialize TransformListJSON: " << descriptiveError); } auto transformListJSON = deserializedAttempt.value(); if (transformListJSON.size() < 1) diff --git a/packages/core/typescript/itk-wasm/src/interface-types/mesh-type.ts b/packages/core/typescript/itk-wasm/src/interface-types/mesh-type.ts index e9acb175c..79403e0f9 100644 --- a/packages/core/typescript/itk-wasm/src/interface-types/mesh-type.ts +++ b/packages/core/typescript/itk-wasm/src/interface-types/mesh-type.ts @@ -3,20 +3,18 @@ import FloatTypes from './float-types.js' import PixelTypes from './pixel-types.js' class MeshType { - constructor ( + constructor( public readonly dimension: number = 2, public readonly pointComponentType: (typeof FloatTypes)[keyof typeof FloatTypes] = FloatTypes.Float32, public readonly pointPixelComponentType: - | (typeof IntTypes)[keyof typeof IntTypes] - | (typeof FloatTypes)[keyof typeof FloatTypes] = FloatTypes.Float32, + | (typeof IntTypes)[keyof typeof IntTypes] + | (typeof FloatTypes)[keyof typeof FloatTypes] = FloatTypes.Float32, public readonly pointPixelType: (typeof PixelTypes)[keyof typeof PixelTypes] = PixelTypes.Scalar, public readonly pointPixelComponents: number = 1, - public readonly cellComponentType: - | (typeof IntTypes)[keyof typeof IntTypes] - | (typeof FloatTypes)[keyof typeof FloatTypes] = IntTypes.Int32, + public readonly cellComponentType: (typeof IntTypes)[keyof typeof IntTypes] = IntTypes.Int32, public readonly cellPixelComponentType: - | (typeof IntTypes)[keyof typeof IntTypes] - | (typeof FloatTypes)[keyof typeof FloatTypes] = FloatTypes.Float32, + | (typeof IntTypes)[keyof typeof IntTypes] + | (typeof FloatTypes)[keyof typeof FloatTypes] = FloatTypes.Float32, public readonly cellPixelType: (typeof PixelTypes)[keyof typeof PixelTypes] = PixelTypes.Scalar, public readonly cellPixelComponents: number = 1 ) {} diff --git a/src/itkWasmTransformIO.cxx b/src/itkWasmTransformIO.cxx index 64f3d4066..2d6f5cbf5 100644 --- a/src/itkWasmTransformIO.cxx +++ b/src/itkWasmTransformIO.cxx @@ -640,7 +640,8 @@ WasmTransformIOTemplate::ReadTransformInformation() -> con auto deserializedAttempt = glz::read_json(str); if (!deserializedAttempt) { - itkExceptionMacro("Failed to deserialize TransformListJSON"); + const std::string descriptiveError = glz::format_error(deserializedAttempt, str); + itkExceptionMacro("Failed to deserialize TransformListJSON: " << descriptiveError); } auto transformListJSON = deserializedAttempt.value(); From e0cf293f8de57de6bc8e12a483b53a3d43f47b16 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Fri, 5 Jul 2024 06:06:25 -0400 Subject: [PATCH 02/10] refactor(mesh): rapidjson to glaze --- include/itkComponentTypesJSON.h | 56 +++++++ include/itkInputMeshIO.h | 23 +-- include/itkMeshJSON.h | 74 +++++---- include/itkWasmMapComponentType.h | 30 +--- include/itkWasmMeshIO.h | 6 +- include/itkioComponentEnumFromJSON.h | 37 +++++ include/itkioPixelEnumFromJSON.h | 35 +++++ include/itkjsonFromIOComponentEnum.h | 43 ++++++ include/itkjsonFromIOPixelEnum.h | 35 +++++ src/CMakeLists.txt | 4 + src/itkWasmMeshIO.cxx | 218 +++++++++------------------ src/itkWasmMeshIOBase.cxx | 37 ++--- src/itkioComponentEnumFromJSON.cxx | 102 +++++++++++++ src/itkioPixelEnumFromJSON.cxx | 65 ++++++++ src/itkjsonFromIOComponentEnum.cxx | 105 +++++++++++++ src/itkjsonFromIOPixelEnum.cxx | 65 ++++++++ test/itkWasmMeshIOTest.cxx | 2 + 17 files changed, 695 insertions(+), 242 deletions(-) create mode 100644 include/itkComponentTypesJSON.h create mode 100644 include/itkioComponentEnumFromJSON.h create mode 100644 include/itkioPixelEnumFromJSON.h create mode 100644 include/itkjsonFromIOComponentEnum.h create mode 100644 include/itkjsonFromIOPixelEnum.h create mode 100644 src/itkioComponentEnumFromJSON.cxx create mode 100644 src/itkioPixelEnumFromJSON.cxx create mode 100644 src/itkjsonFromIOComponentEnum.cxx create mode 100644 src/itkjsonFromIOPixelEnum.cxx diff --git a/include/itkComponentTypesJSON.h b/include/itkComponentTypesJSON.h new file mode 100644 index 000000000..4f6f3faba --- /dev/null +++ b/include/itkComponentTypesJSON.h @@ -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 { + using enum itk::JSONComponentTypesEnum; + static constexpr auto value = glz::enumerate( + int8, + uint8, + int16, + uint16, + int32, + uint32, + int64, + float32, + float64 + ); +}; + +#endif // itkComponentTypesJSON_h diff --git a/include/itkInputMeshIO.h b/include/itkInputMeshIO.h index 5296f9849..8182bbd68 100644 --- a/include/itkInputMeshIO.h +++ b/include/itkInputMeshIO.h @@ -74,34 +74,36 @@ bool lexical_cast(const std::string &input, InputMeshIO &inputMeshIO) #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(json); + if (!deserializedAttempt) + { + const std::string descriptiveError = glz::format_error(deserializedAttempt, json); + throw std::runtime_error("Failed to deserialize MeshJSON: " + descriptiveError); + } + auto meshJSON = deserializedAttempt.value(); auto wasmMeshIO = itk::WasmMeshIO::New(); - wasmMeshIO->SetJSON(document); + wasmMeshIO->SetJSON(meshJSON); const unsigned int dimension = wasmMeshIO->GetPointDimension(); auto wasmMeshIOBase = itk::WasmMeshIOBase::New(); - const rapidjson::Value & pointsJson = document["points"]; - const std::string pointsString( pointsJson.GetString() ); + const std::string & pointsString = meshJSON.points; const char * pointsPtr = reinterpret_cast< char * >( std::strtoull(pointsString.substr(35).c_str(), nullptr, 10) ); WasmMeshIOBase::DataContainerType * pointsContainer = wasmMeshIOBase->GetPointsContainer(); SizeValueType numberOfBytes = wasmMeshIO->GetNumberOfPoints() * wasmMeshIO->GetPointDimension() * ITKComponentSize( wasmMeshIO->GetPointComponentType() ); pointsContainer->resize(numberOfBytes); pointsContainer->assign(pointsPtr, pointsPtr + numberOfBytes); - const rapidjson::Value & cellsJson = document["cells"]; - const std::string cellsString( cellsJson.GetString() ); + const std::string & cellsString = meshJSON.cells; const char * cellsPtr = reinterpret_cast< char * >( std::strtoull(cellsString.substr(35).c_str(), nullptr, 10) ); WasmMeshIOBase::DataContainerType * cellsContainer = wasmMeshIOBase->GetCellsContainer(); numberOfBytes = static_cast< SizeValueType >( wasmMeshIO->GetCellBufferSize() * ITKComponentSize( wasmMeshIO->GetCellComponentType() )); cellsContainer->resize(numberOfBytes); cellsContainer->assign(cellsPtr, cellsPtr + numberOfBytes); - const rapidjson::Value & pointDataJson = document["pointData"]; - const std::string pointDataString( pointDataJson.GetString() ); + const std::string & pointDataString = meshJSON.pointData; const char * pointDataPtr = reinterpret_cast< char * >( std::strtoull(pointDataString.substr(35).c_str(), nullptr, 10) ); WasmMeshIOBase::DataContainerType * pointDataContainer = wasmMeshIOBase->GetPointDataContainer(); numberOfBytes = @@ -111,8 +113,7 @@ bool lexical_cast(const std::string &input, InputMeshIO &inputMeshIO) pointDataContainer->resize(numberOfBytes); pointDataContainer->assign(pointDataPtr, pointDataPtr + numberOfBytes); - const rapidjson::Value & cellDataJson = document["cellData"]; - const std::string cellDataString( cellDataJson.GetString() ); + const std::string & cellDataString = meshJSON.cellData; const char * cellDataPtr = reinterpret_cast< char * >( std::strtoull(cellDataString.substr(35).c_str(), nullptr, 10) ); WasmMeshIOBase::DataContainerType * cellDataContainer = wasmMeshIOBase->GetCellDataContainer(); numberOfBytes = diff --git a/include/itkMeshJSON.h b/include/itkMeshJSON.h index f357b5471..121136d30 100644 --- a/include/itkMeshJSON.h +++ b/include/itkMeshJSON.h @@ -117,42 +117,52 @@ auto meshToMeshJSON(const TMesh * mesh, const WasmMesh * wasmMesh, bool i { meshJSON.numberOfCellPixels = mesh->GetCellData()->Size(); } - meshJSON.cellBufferSize = wasmMesh->GetCellBuffer()->Size(); - - const auto pointsAddress = reinterpret_cast< size_t >( &(mesh->GetPoints()->at(0)) ); - std::ostringstream pointsStream; - pointsStream << "data:application/vnd.itk.address,0:"; - pointsStream << pointsAddress; - meshJSON.points = pointsStream.str(); - size_t cellsAddress = 0; - if (mesh->GetNumberOfCells() > 0) + if (inMemory) { - cellsAddress = reinterpret_cast< size_t >( &(wasmMesh->GetCellBuffer()->at(0)) ); + meshJSON.cellBufferSize = wasmMesh->GetCellBuffer()->Size(); + + const auto pointsAddress = reinterpret_cast< size_t >( &(mesh->GetPoints()->at(0)) ); + std::ostringstream pointsStream; + pointsStream << "data:application/vnd.itk.address,0:"; + pointsStream << pointsAddress; + meshJSON.points = pointsStream.str(); + size_t cellsAddress = 0; + if (mesh->GetNumberOfCells() > 0) + { + cellsAddress = reinterpret_cast< size_t >( &(wasmMesh->GetCellBuffer()->at(0)) ); + } + std::ostringstream cellsStream; + cellsStream << "data:application/vnd.itk.address,0:"; + cellsStream << cellsAddress; + meshJSON.cells = cellsStream.str(); + + size_t pointDataAddress = 0; + if (mesh->GetPointData() != nullptr && mesh->GetPointData()->Size() > 0) + { + pointDataAddress = reinterpret_cast< size_t >( &(mesh->GetPointData()->at(0)) ); + } + std::ostringstream pointDataStream; + pointDataStream << "data:application/vnd.itk.address,0:"; + pointDataStream << pointDataAddress; + meshJSON.pointData = pointDataStream.str(); + + size_t cellDataAddress = 0; + if (mesh->GetCellData() != nullptr && mesh->GetCellData()->Size() > 0) + { + cellDataAddress = reinterpret_cast< size_t >( &(mesh->GetCellData()->at(0)) ); + } + std::ostringstream cellDataStream; + cellDataStream << "data:application/vnd.itk.address,0:"; + cellDataStream << cellDataAddress; + meshJSON.cellData = cellDataStream.str(); } - std::ostringstream cellsStream; - cellsStream << "data:application/vnd.itk.address,0:"; - cellsStream << cellsAddress; - meshJSON.cells = cellsStream.str(); - - size_t pointDataAddress = 0; - if (mesh->GetPointData() != nullptr && mesh->GetPointData()->Size() > 0) - { - pointDataAddress = reinterpret_cast< size_t >( &(mesh->GetPointData()->at(0)) ); - } - std::ostringstream pointDataStream; - pointDataStream << "data:application/vnd.itk.address,0:"; - pointDataStream << pointDataAddress; - meshJSON.pointData = pointDataStream.str(); - - size_t cellDataAddress = 0; - if (mesh->GetCellData() != nullptr && mesh->GetCellData()->Size() > 0) + else { - cellDataAddress = reinterpret_cast< size_t >( &(mesh->GetCellData()->at(0)) ); + meshJSON.points = "data:application/vnd.itk.path,data/points.raw"; + meshJSON.cells = "data:application/vnd.itk.path,data/cells.raw"; + meshJSON.pointData = "data:application/vnd.itk.path,data/point-data.raw"; + meshJSON.cellData = "data:application/vnd.itk.path,data/cell-data.raw"; } - std::ostringstream cellDataStream; - cellDataStream << "data:application/vnd.itk.address,0:"; - cellDataStream << cellDataAddress; - meshJSON.cellData = cellDataStream.str(); return meshJSON; } diff --git a/include/itkWasmMapComponentType.h b/include/itkWasmMapComponentType.h index da6e1c6fe..3c4414dd9 100644 --- a/include/itkWasmMapComponentType.h +++ b/include/itkWasmMapComponentType.h @@ -23,26 +23,15 @@ #include #include "itkIntTypes.h" +#include "itkIOCommon.h" #include "itkIntTypesJSON.h" #include "itkFloatTypesJSON.h" +#include "itkComponentTypesJSON.h" namespace itk { -enum class JSONComponentTypesEnum -{ - int8, - uint8, - int16, - uint16, - int32, - uint32, - int64, - uint64, - float32, - float64 -}; namespace wasm { @@ -184,20 +173,5 @@ struct MapComponentType } // end namespace wasm } // end namespace itk -template <> -struct glz::meta { - using enum itk::JSONComponentTypesEnum; - static constexpr auto value = glz::enumerate( - int8, - uint8, - int16, - uint16, - int32, - uint32, - int64, - float32, - float64 - ); -}; #endif // itkWasmMapComponentType_h diff --git a/include/itkWasmMeshIO.h b/include/itkWasmMeshIO.h index 1f7a55579..cb296fd08 100644 --- a/include/itkWasmMeshIO.h +++ b/include/itkWasmMeshIO.h @@ -22,7 +22,7 @@ #include "itkMeshIOBase.h" #include -#include "rapidjson/document.h" +#include "itkMeshJSON.h" #include "cbor.h" namespace itk @@ -70,7 +70,7 @@ class WebAssemblyInterface_EXPORT WasmMeshIO: public MeshIOBase void ReadCellData(void *buffer) override; /** Set the JSON representation of the image information. */ - void SetJSON(rapidjson::Document & json); + void SetJSON(const MeshJSON & json); /*-------- This part of the interfaces deals with writing data ----- */ @@ -92,7 +92,7 @@ class WebAssemblyInterface_EXPORT WasmMeshIO: public MeshIOBase #if !defined(ITK_WRAPPING_PARSER) /** Get the JSON representation of the mesh information. */ - rapidjson::Document GetJSON(); + auto GetJSON() -> MeshJSON; #endif protected: diff --git a/include/itkioComponentEnumFromJSON.h b/include/itkioComponentEnumFromJSON.h new file mode 100644 index 000000000..2187988a5 --- /dev/null +++ b/include/itkioComponentEnumFromJSON.h @@ -0,0 +1,37 @@ +/*========================================================================= + * + * 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 itkioComponentEnumFromJSON_h +#define itkioComponentEnumFromJSON_h + +#include "WebAssemblyInterfaceExport.h" + +#include "itkIOCommon.h" + +#include "itkIntTypesJSON.h" +#include "itkFloatTypesJSON.h" +#include "itkComponentTypesJSON.h" + + +namespace itk +{ + +WebAssemblyInterface_EXPORT IOComponentEnum +ioComponentEnumFromJSON(const std::variant & jsonComponentType); + +} // end namespace itk +#endif diff --git a/include/itkioPixelEnumFromJSON.h b/include/itkioPixelEnumFromJSON.h new file mode 100644 index 000000000..b714ed951 --- /dev/null +++ b/include/itkioPixelEnumFromJSON.h @@ -0,0 +1,35 @@ +/*========================================================================= + * + * 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 itkioPixelEnumFromJSON_h +#define itkioPixelEnumFromJSON_h + +#include "WebAssemblyInterfaceExport.h" + +#include "itkIOCommon.h" + +#include "itkPixelTypesJSON.h" + + +namespace itk +{ + +WebAssemblyInterface_EXPORT IOPixelEnum +ioPixelEnumFromJSON(const JSONPixelTypesEnum & jsonPixelType); + +} // end namespace itk +#endif diff --git a/include/itkjsonFromIOComponentEnum.h b/include/itkjsonFromIOComponentEnum.h new file mode 100644 index 000000000..824c35bf5 --- /dev/null +++ b/include/itkjsonFromIOComponentEnum.h @@ -0,0 +1,43 @@ +/*========================================================================= + * + * 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 itkjsonFromIOComponentEnum_h +#define itkjsonFromIOComponentEnum_h + +#include "WebAssemblyInterfaceExport.h" + +#include "itkIOCommon.h" + +#include "itkIntTypesJSON.h" +#include "itkFloatTypesJSON.h" +#include "itkComponentTypesJSON.h" + + +namespace itk +{ + +WebAssemblyInterface_EXPORT JSONIntTypesEnum +jsonIntTypeFromIOComponentEnum(const IOComponentEnum & ioComponent); + +WebAssemblyInterface_EXPORT JSONFloatTypesEnum +jsonFloatTypeFromIOComponentEnum(const IOComponentEnum & ioComponent); + +WebAssemblyInterface_EXPORT JSONComponentTypesEnum +jsonComponentTypeFromIOComponentEnum(const IOComponentEnum & ioComponent); + +} // end namespace itk +#endif diff --git a/include/itkjsonFromIOPixelEnum.h b/include/itkjsonFromIOPixelEnum.h new file mode 100644 index 000000000..83f4e8890 --- /dev/null +++ b/include/itkjsonFromIOPixelEnum.h @@ -0,0 +1,35 @@ +/*========================================================================= + * + * 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 itkjsonFromIOPixelEnum_h +#define itkjsonFromIOPixelEnum_h + +#include "WebAssemblyInterfaceExport.h" + +#include "itkIOCommon.h" + +#include "itkPixelTypesJSON.h" + + +namespace itk +{ + +WebAssemblyInterface_EXPORT JSONPixelTypesEnum +jsonFromIOPixelEnum(const IOPixelEnum & ioPixel); + +} // end namespace itk +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 31d662c05..7badbfeb0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,6 +27,10 @@ set(WebAssemblyInterface_SRCS itkSupportInputMeshTypes.cxx itkSupportInputPolyDataTypes.cxx itktransformParameterizationString.cxx + itkioComponentEnumFromJSON.cxx + itkioPixelEnumFromJSON.cxx + itkjsonFromIOComponentEnum.cxx + itkjsonFromIOPixelEnum.cxx ) itk_module_add_library(WebAssemblyInterface ${WebAssemblyInterface_SRCS}) target_link_libraries(WebAssemblyInterface LINK_PUBLIC cbor cpp-base64) diff --git a/src/itkWasmMeshIO.cxx b/src/itkWasmMeshIO.cxx index 6bb5a5fad..0464b4051 100644 --- a/src/itkWasmMeshIO.cxx +++ b/src/itkWasmMeshIO.cxx @@ -18,20 +18,20 @@ #include "itkWasmMeshIO.h" -#include "itkWasmComponentTypeFromIOComponentEnum.h" +#include "itkioComponentEnumFromJSON.h" +#include "itkioPixelEnumFromJSON.h" +#include "itkjsonFromIOComponentEnum.h" +#include "itkjsonFromIOPixelEnum.h" +#include "itkIOPixelEnumFromWasmPixelType.h" #include "itkIOComponentEnumFromWasmComponentType.h" +#include "itkWasmComponentTypeFromIOComponentEnum.h" #include "itkWasmPixelTypeFromIOPixelEnum.h" -#include "itkIOPixelEnumFromWasmPixelType.h" #include "itkWasmIOCommon.h" #include "itkMetaDataObject.h" #include "itkIOCommon.h" #include "itksys/SystemTools.hxx" -#include "rapidjson/document.h" -#include "rapidjson/prettywriter.h" -#include "rapidjson/ostreamwrapper.h" - #include "itksys/SystemTools.hxx" #include "cbor.h" @@ -269,148 +269,74 @@ ::ReadCBOR( void *buffer, unsigned char * cborBuffer, size_t cborBufferLength ) } } -rapidjson::Document +auto WasmMeshIO -::GetJSON() +::GetJSON() -> MeshJSON { - rapidjson::Document document; - document.SetObject(); - rapidjson::Document::AllocatorType& allocator = document.GetAllocator(); - - rapidjson::Value meshType; - meshType.SetObject(); - - const unsigned int dimension = this->GetPointDimension(); - meshType.AddMember("dimension", rapidjson::Value(dimension).Move(), allocator ); - - const std::string pointComponentString = WasmComponentTypeFromIOComponentEnum( this->GetPointComponentType() ); - rapidjson::Value pointComponentType; - pointComponentType.SetString( pointComponentString.c_str(), allocator ); - meshType.AddMember("pointComponentType", pointComponentType.Move(), allocator ); - - const std::string pointPixelComponentString = WasmComponentTypeFromIOComponentEnum( this->GetPointPixelComponentType() ); - rapidjson::Value pointPixelComponentType; - pointPixelComponentType.SetString( pointPixelComponentString.c_str(), allocator ); - meshType.AddMember("pointPixelComponentType", pointPixelComponentType.Move(), allocator ); - - rapidjson::Value pointPixelType; - pointPixelType.SetString( WasmPixelTypeFromIOPixelEnum( this->GetPointPixelType()).c_str(), allocator ); - meshType.AddMember("pointPixelType", pointPixelType.Move(), allocator ); - - meshType.AddMember("pointPixelComponents", rapidjson::Value( this->GetNumberOfPointPixelComponents() ).Move(), allocator ); - - const std::string cellComponentString = WasmComponentTypeFromIOComponentEnum( this->GetCellComponentType() ); - rapidjson::Value cellComponentType; - cellComponentType.SetString( cellComponentString.c_str(), allocator ); - meshType.AddMember("cellComponentType", cellComponentType.Move(), allocator ); - - const std::string cellPixelComponentString = WasmComponentTypeFromIOComponentEnum( this->GetCellPixelComponentType() ); - rapidjson::Value cellPixelComponentType; - cellPixelComponentType.SetString( cellPixelComponentString.c_str(), allocator ); - meshType.AddMember("cellPixelComponentType", cellPixelComponentType.Move(), allocator ); - - rapidjson::Value cellPixelType; - cellPixelType.SetString(WasmPixelTypeFromIOPixelEnum( this->GetCellPixelType() ).c_str(), allocator); - meshType.AddMember("cellPixelType", cellPixelType, allocator ); - - meshType.AddMember("cellPixelComponents", rapidjson::Value( this->GetNumberOfCellPixelComponents() ).Move(), allocator ); - - document.AddMember( "meshType", meshType.Move(), allocator ); - - rapidjson::Value numberOfPoints; - numberOfPoints.SetInt( this->GetNumberOfPoints() ); - document.AddMember( "numberOfPoints", numberOfPoints.Move(), allocator ); - - rapidjson::Value numberOfPointPixels; - numberOfPointPixels.SetInt( this->GetNumberOfPointPixels() ); - document.AddMember( "numberOfPointPixels", numberOfPointPixels.Move(), allocator ); - - rapidjson::Value numberOfCells; - numberOfCells.SetInt( this->GetNumberOfCells() ); - document.AddMember( "numberOfCells", numberOfCells.Move(), allocator ); - - rapidjson::Value numberOfCellPixels; - numberOfCellPixels.SetInt( this->GetNumberOfCellPixels() ); - document.AddMember( "numberOfCellPixels", numberOfCellPixels.Move(), allocator ); - - rapidjson::Value cellBufferSize; - cellBufferSize.SetInt( this->GetCellBufferSize() ); - document.AddMember( "cellBufferSize", cellBufferSize.Move(), allocator ); - - std::string pointsDataFileString( "data:application/vnd.itk.path,data/points.raw" ); - rapidjson::Value pointsDataFile; - pointsDataFile.SetString( pointsDataFileString.c_str(), allocator ); - document.AddMember( "points", pointsDataFile, allocator ); - - std::string cellsDataFileString( "data:application/vnd.itk.path,data/cells.raw" ); - rapidjson::Value cellsDataFile; - cellsDataFile.SetString( cellsDataFileString.c_str(), allocator ); - document.AddMember( "cells", cellsDataFile, allocator ); - - std::string pointDataDataFileString( "data:application/vnd.itk.path,data/point-data.raw" ); - rapidjson::Value pointDataDataFile; - pointDataDataFile.SetString( pointDataDataFileString.c_str(), allocator ); - document.AddMember( "pointData", pointDataDataFile, allocator ); - - std::string cellDataDataFileString( "data:application/vnd.itk.path,data/cell-data.raw" ); - rapidjson::Value cellDataDataFile; - cellDataDataFile.SetString( cellDataDataFileString.c_str(), allocator ); - document.AddMember( "cellData", cellDataDataFile, allocator ); - - return document; + MeshJSON meshJSON; + + meshJSON.meshType.dimension = this->GetPointDimension(); + + const auto pointIOComponentType = this->GetPointComponentType(); + meshJSON.meshType.pointComponentType = jsonFloatTypeFromIOComponentEnum( pointIOComponentType ); + const auto pointPixelIOComponentType = this->GetPointPixelComponentType(); + meshJSON.meshType.pointPixelComponentType = jsonComponentTypeFromIOComponentEnum( pointPixelIOComponentType ); + const auto pointIOPixelType = this->GetPointPixelType(); + meshJSON.meshType.pointPixelType = jsonFromIOPixelEnum( pointIOPixelType ); + meshJSON.meshType.pointPixelComponents = this->GetNumberOfPointPixelComponents(); + + const auto cellIOComponentType = this->GetCellComponentType(); + meshJSON.meshType.cellComponentType = jsonIntTypeFromIOComponentEnum( cellIOComponentType ); + const auto cellPixelIOComponentType = this->GetCellPixelComponentType(); + meshJSON.meshType.cellPixelComponentType = jsonComponentTypeFromIOComponentEnum( cellPixelIOComponentType ); + const auto cellIOPixelType = this->GetCellPixelType(); + meshJSON.meshType.cellPixelType = jsonFromIOPixelEnum( cellIOPixelType ); + meshJSON.meshType.cellPixelComponents = this->GetNumberOfCellPixelComponents(); + + meshJSON.numberOfPoints =this->GetNumberOfPoints(); + meshJSON.numberOfPointPixels = this->GetNumberOfPointPixels(); + meshJSON.numberOfCells = this->GetNumberOfCells(); + meshJSON.numberOfCellPixels = this->GetNumberOfCellPixels(); + meshJSON.cellBufferSize = this->GetCellBufferSize(); + + meshJSON.points = "data:application/vnd.itk.path,data/points.raw"; + meshJSON.cells = "data:application/vnd.itk.path,data/cells.raw"; + meshJSON.pointData = "data:application/vnd.itk.path,data/point-data.raw"; + meshJSON.cellData = "data:application/vnd.itk.path,data/cell-data.raw"; + + return meshJSON; } void WasmMeshIO -::SetJSON(rapidjson::Document & document) +::SetJSON(const MeshJSON & meshJSON) { - const rapidjson::Value & meshType = document["meshType"]; - const int dimension = meshType["dimension"].GetInt(); - this->SetPointDimension( dimension ); + const auto & meshType = meshJSON.meshType; + this->SetPointDimension( meshType.dimension ); - const std::string pointComponentType( meshType["pointComponentType"].GetString() ); - const CommonEnums::IOComponent pointIOComponentType = IOComponentEnumFromWasmComponentType( pointComponentType ); + const auto pointIOComponentType = ioComponentEnumFromJSON( meshType.pointComponentType ); this->SetPointComponentType( pointIOComponentType ); - - const std::string pointPixelComponentType( meshType["pointPixelComponentType"].GetString() ); - const CommonEnums::IOComponent pointPixelIOComponentType = IOComponentEnumFromWasmComponentType( pointPixelComponentType ); + const auto pointPixelIOComponentType = ioComponentEnumFromJSON( meshType.pointPixelComponentType ); this->SetPointPixelComponentType( pointPixelIOComponentType ); - - const std::string pointPixelType( meshType["pointPixelType"].GetString() ); - const CommonEnums::IOPixel pointIOPixelType = IOPixelEnumFromWasmPixelType( pointPixelType ); + const auto pointIOPixelType = ioPixelEnumFromJSON( meshType.pointPixelType ); this->SetPointPixelType( pointIOPixelType ); + this->SetNumberOfPointPixelComponents( meshType.pointPixelComponents ); - this->SetNumberOfPointPixelComponents( meshType["pointPixelComponents"].GetInt() ); - - const std::string cellComponentType( meshType["cellComponentType"].GetString() ); - const CommonEnums::IOComponent cellIOComponentType = IOComponentEnumFromWasmComponentType( cellComponentType ); + const auto cellIOComponentType = ioComponentEnumFromJSON( meshType.cellComponentType ); this->SetCellComponentType( cellIOComponentType ); - const std::string cellPixelComponentType( meshType["cellPixelComponentType"].GetString() ); - const CommonEnums::IOComponent cellPixelIOComponentType = IOComponentEnumFromWasmComponentType( cellPixelComponentType ); + const auto cellPixelIOComponentType = ioComponentEnumFromJSON( meshType.cellPixelComponentType ); this->SetCellPixelComponentType( cellPixelIOComponentType ); - - const std::string cellPixelType( meshType["cellPixelType"].GetString() ); - const CommonEnums::IOPixel cellIOPixelType = IOPixelEnumFromWasmPixelType( cellPixelType ); + const auto cellIOPixelType = ioPixelEnumFromJSON( meshType.cellPixelType ); this->SetCellPixelType( cellIOPixelType ); + this->SetNumberOfCellPixelComponents( meshType.cellPixelComponents ); - this->SetNumberOfCellPixelComponents( meshType["cellPixelComponents"].GetInt() ); - - const rapidjson::Value & numberOfPoints = document["numberOfPoints"]; - this->SetNumberOfPoints( numberOfPoints.GetInt() ); - - const rapidjson::Value & numberOfPointPixels = document["numberOfPointPixels"]; - this->SetNumberOfPointPixels( numberOfPointPixels.GetInt() ); - - const rapidjson::Value & numberOfCells = document["numberOfCells"]; - this->SetNumberOfCells( numberOfCells.GetInt() ); - - const rapidjson::Value & numberOfCellPixels = document["numberOfCellPixels"]; - this->SetNumberOfCellPixels( numberOfCellPixels.GetInt() ); - - const rapidjson::Value & cellBufferSize = document["cellBufferSize"]; - this->SetCellBufferSize( cellBufferSize.GetInt() ); + this->SetNumberOfPoints( meshJSON.numberOfPoints ); + this->SetNumberOfPointPixels( meshJSON.numberOfPointPixels ); + this->SetNumberOfCells( meshJSON.numberOfCells ); + this->SetNumberOfCellPixels( meshJSON.numberOfCellPixels ); + this->SetCellBufferSize( meshJSON.cellBufferSize ); } @@ -526,22 +452,22 @@ ::ReadMeshInformation() return; } - rapidjson::Document document; const std::string path = this->GetFileName(); const auto indexPath = path + "/index.json"; const auto dataPath = path + "/data"; std::ifstream inputStream; openFileForReading( inputStream, indexPath.c_str(), true ); - std::string str((std::istreambuf_iterator(inputStream)), - std::istreambuf_iterator()); - if (document.Parse(str.c_str()).HasParseError()) - { - itkExceptionMacro("Could not parse JSON"); - return; - } + std::string str((std::istreambuf_iterator(inputStream)), std::istreambuf_iterator()); + auto deserializedAttempt = glz::read_json(str); + if (!deserializedAttempt) + { + const std::string descriptiveError = glz::format_error(deserializedAttempt, str); + itkExceptionMacro("Failed to deserialize MeshJSON: " << descriptiveError); + } + auto meshJSON = deserializedAttempt.value(); - this->SetJSON(document); + this->SetJSON(meshJSON); if ( this->GetNumberOfPoints() ) { @@ -730,7 +656,7 @@ ::WriteMeshInformation() itksys::SystemTools::MakeDirectory(dataPath); } - rapidjson::Document document = this->GetJSON(); + const auto meshJSON = this->GetJSON(); if ( this->GetNumberOfPoints() ) { @@ -752,11 +678,15 @@ ::WriteMeshInformation() this->m_UpdateCellData = true; } + std::string serialized{}; + auto ec = glz::write(meshJSON, serialized); + if (ec) + { + itkExceptionMacro("Failed to serialize MeshJSON"); + } std::ofstream outputStream; - openFileForWriting( outputStream, indexPath.c_str(), true, true ); - rapidjson::OStreamWrapper ostreamWrapper( outputStream ); - rapidjson::PrettyWriter< rapidjson::OStreamWrapper > writer( ostreamWrapper ); - document.Accept( writer ); + openFileForWriting(outputStream, indexPath.c_str(), true, true); + outputStream << serialized; outputStream.close(); } diff --git a/src/itkWasmMeshIOBase.cxx b/src/itkWasmMeshIOBase.cxx index 96d82ada5..433736eba 100644 --- a/src/itkWasmMeshIOBase.cxx +++ b/src/itkWasmMeshIOBase.cxx @@ -21,7 +21,6 @@ #include "itkWasmIOCommon.h" #include -#include "rapidjson/prettywriter.h" namespace itk { @@ -62,8 +61,7 @@ WasmMeshIOBase::SetMeshIO(MeshIOBase * meshIO, bool readMesh) wasmMeshIO->SetNumberOfCellPixels(meshIO->GetNumberOfCellPixels()); wasmMeshIO->SetCellBufferSize(meshIO->GetCellBufferSize()); - rapidjson::Document document = wasmMeshIO->GetJSON(); - rapidjson::Document::AllocatorType& allocator = document.GetAllocator(); + auto meshJSON = wasmMeshIO->GetJSON(); size_t pointsAddress = 0; SizeValueType numberOfBytes = meshIO->GetNumberOfPoints() * meshIO->GetPointDimension() * ITKComponentSize( meshIO->GetPointComponentType() ); @@ -77,10 +75,7 @@ WasmMeshIOBase::SetMeshIO(MeshIOBase * meshIO, bool readMesh) std::ostringstream dataStream; dataStream << "data:application/vnd.itk.address,0:"; dataStream << pointsAddress; - rapidjson::Value pointsString; - pointsString.SetString( dataStream.str().c_str(), allocator ); - document.RemoveMember( "points" ); - document.AddMember( "points", pointsString.Move(), allocator ); + meshJSON.points = dataStream.str(); numberOfBytes = static_cast< SizeValueType >( meshIO->GetCellBufferSize() * ITKComponentSize( meshIO->GetCellComponentType() )); @@ -95,10 +90,7 @@ WasmMeshIOBase::SetMeshIO(MeshIOBase * meshIO, bool readMesh) dataStream.str(""); dataStream << "data:application/vnd.itk.address,0:"; dataStream << cellsAddress; - rapidjson::Value cellsString; - cellsString.SetString( dataStream.str().c_str(), allocator ); - document.RemoveMember( "cells" ); - document.AddMember( "cells", cellsString.Move(), allocator ); + meshJSON.cells = dataStream.str(); numberOfBytes = static_cast< SizeValueType >( meshIO->GetNumberOfPointPixels() * meshIO->GetNumberOfPointPixelComponents() * ITKComponentSize( meshIO->GetPointPixelComponentType() )); @@ -114,10 +106,7 @@ WasmMeshIOBase::SetMeshIO(MeshIOBase * meshIO, bool readMesh) dataStream.str(""); dataStream << "data:application/vnd.itk.address,0:"; dataStream << pointDataAddress; - rapidjson::Value pointDataString; - pointDataString.SetString( dataStream.str().c_str(), allocator ); - document.RemoveMember( "pointData" ); - document.AddMember( "pointData", pointDataString.Move(), allocator ); + meshJSON.pointData = dataStream.str(); numberOfBytes = static_cast< SizeValueType >( meshIO->GetNumberOfCellPixels() * meshIO->GetNumberOfCellPixelComponents() * ITKComponentSize( meshIO->GetCellPixelComponentType() )); @@ -133,15 +122,15 @@ WasmMeshIOBase::SetMeshIO(MeshIOBase * meshIO, bool readMesh) dataStream.str(""); dataStream << "data:application/vnd.itk.address,0:"; dataStream << cellDataAddress; - rapidjson::Value cellDataString; - cellDataString.SetString( dataStream.str().c_str(), allocator ); - document.RemoveMember( "cellData" ); - document.AddMember( "cellData", cellDataString.Move(), allocator ); - - rapidjson::StringBuffer stringBuffer; - rapidjson::Writer< rapidjson::StringBuffer > writer( stringBuffer ); - document.Accept( writer ); - this->SetJSON(stringBuffer.GetString()); + meshJSON.cellData = dataStream.str(); + + std::string serialized{}; + auto ec = glz::write(meshJSON, serialized); + if (ec) + { + itkExceptionMacro("Failed to serialize TransformListJSON"); + } + this->SetJSON(serialized); } void diff --git a/src/itkioComponentEnumFromJSON.cxx b/src/itkioComponentEnumFromJSON.cxx new file mode 100644 index 000000000..61d9adece --- /dev/null +++ b/src/itkioComponentEnumFromJSON.cxx @@ -0,0 +1,102 @@ +/*========================================================================= + * + * 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. + * + *=========================================================================*/ +#include "itkioComponentEnumFromJSON.h" + +namespace itk +{ + +IOComponentEnum +ioComponentEnumFromJSON(const std::variant & jsonComponentType) +{ + switch (jsonComponentType.index()) + { + case 0: + { + const auto intType = std::get(jsonComponentType); + switch (intType) { + case JSONIntTypesEnum::int8: + return IOComponentEnum::CHAR; + case JSONIntTypesEnum::uint8: + return IOComponentEnum::UCHAR; + case JSONIntTypesEnum::int16: + return IOComponentEnum::SHORT; + case JSONIntTypesEnum::uint16: + return IOComponentEnum::USHORT; + case JSONIntTypesEnum::int32: + return IOComponentEnum::INT; + case JSONIntTypesEnum::uint32: + return IOComponentEnum::UINT; + case JSONIntTypesEnum::int64: + return IOComponentEnum::LONGLONG; + case JSONIntTypesEnum::uint64: + return IOComponentEnum::ULONGLONG; + default: + return IOComponentEnum::UNKNOWNCOMPONENTTYPE; + } + break; + } + case 1: + { + const auto floatType = std::get(jsonComponentType); + switch (floatType) { + case JSONFloatTypesEnum::float32: + return IOComponentEnum::FLOAT; + case JSONFloatTypesEnum::float64: + return IOComponentEnum::DOUBLE; + default: + return IOComponentEnum::UNKNOWNCOMPONENTTYPE; + } + break; + } + case 2: + { + const auto componentType = std::get(jsonComponentType); + switch (componentType) + { + case JSONComponentTypesEnum::int8: + return IOComponentEnum::CHAR; + case JSONComponentTypesEnum::uint8: + return IOComponentEnum::UCHAR; + case JSONComponentTypesEnum::int16: + return IOComponentEnum::SHORT; + case JSONComponentTypesEnum::uint16: + return IOComponentEnum::USHORT; + case JSONComponentTypesEnum::int32: + return IOComponentEnum::INT; + case JSONComponentTypesEnum::uint32: + return IOComponentEnum::UINT; + case JSONComponentTypesEnum::int64: + return IOComponentEnum::LONGLONG; + case JSONComponentTypesEnum::uint64: + return IOComponentEnum::ULONGLONG; + case JSONComponentTypesEnum::float32: + return IOComponentEnum::FLOAT; + case JSONComponentTypesEnum::float64: + return IOComponentEnum::DOUBLE; + default: + return IOComponentEnum::UNKNOWNCOMPONENTTYPE; + } + break; + } + default: + return IOComponentEnum::UNKNOWNCOMPONENTTYPE; + } + return IOComponentEnum::UNKNOWNCOMPONENTTYPE; +} + +} // end namespace itk diff --git a/src/itkioPixelEnumFromJSON.cxx b/src/itkioPixelEnumFromJSON.cxx new file mode 100644 index 000000000..c178bda94 --- /dev/null +++ b/src/itkioPixelEnumFromJSON.cxx @@ -0,0 +1,65 @@ +/*========================================================================= + * + * 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. + * + *=========================================================================*/ +#include "itkioPixelEnumFromJSON.h" + +namespace itk +{ + +IOPixelEnum +ioPixelEnumFromJSON(const JSONPixelTypesEnum & jsonPixelType) +{ + switch (jsonPixelType) + { + case JSONPixelTypesEnum::Unknown: + return IOPixelEnum::UNKNOWNPIXELTYPE; + case JSONPixelTypesEnum::Scalar: + return IOPixelEnum::SCALAR; + case JSONPixelTypesEnum::RGB: + return IOPixelEnum::RGB; + case JSONPixelTypesEnum::RGBA: + return IOPixelEnum::RGBA; + case JSONPixelTypesEnum::Offset: + return IOPixelEnum::OFFSET; + case JSONPixelTypesEnum::Vector: + return IOPixelEnum::VECTOR; + case JSONPixelTypesEnum::Point: + return IOPixelEnum::POINT; + case JSONPixelTypesEnum::CovariantVector: + return IOPixelEnum::COVARIANTVECTOR; + case JSONPixelTypesEnum::SymmetricSecondRankTensor: + return IOPixelEnum::SYMMETRICSECONDRANKTENSOR; + case JSONPixelTypesEnum::DiffusionTensor3D: + return IOPixelEnum::DIFFUSIONTENSOR3D; + case JSONPixelTypesEnum::Complex: + return IOPixelEnum::COMPLEX; + case JSONPixelTypesEnum::FixedArray: + return IOPixelEnum::FIXEDARRAY; + case JSONPixelTypesEnum::Array: + return IOPixelEnum::ARRAY; + case JSONPixelTypesEnum::Matrix: + return IOPixelEnum::MATRIX; + case JSONPixelTypesEnum::VariableLengthVector: + return IOPixelEnum::VARIABLELENGTHVECTOR; + case JSONPixelTypesEnum::VariableSizeMatrix: + return IOPixelEnum::VARIABLESIZEMATRIX; + default: + return IOPixelEnum::UNKNOWNPIXELTYPE; + } +} + +} // end namespace itk diff --git a/src/itkjsonFromIOComponentEnum.cxx b/src/itkjsonFromIOComponentEnum.cxx new file mode 100644 index 000000000..0bf2f57e9 --- /dev/null +++ b/src/itkjsonFromIOComponentEnum.cxx @@ -0,0 +1,105 @@ +/*========================================================================= + * + * 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. + * + *=========================================================================*/ +#include "itkjsonFromIOComponentEnum.h" + +namespace itk +{ + +JSONIntTypesEnum +jsonIntTypeFromIOComponentEnum(const IOComponentEnum & ioComponent) +{ + switch (ioComponent) + { + case IOComponentEnum::UCHAR: + return JSONIntTypesEnum::uint8; + case IOComponentEnum::CHAR: + return JSONIntTypesEnum::int8; + case IOComponentEnum::USHORT: + return JSONIntTypesEnum::uint16; + case IOComponentEnum::SHORT: + return JSONIntTypesEnum::int16; + case IOComponentEnum::UINT: + return JSONIntTypesEnum::uint32; + case IOComponentEnum::INT: + return JSONIntTypesEnum::int32; + case IOComponentEnum::ULONG: + return JSONIntTypesEnum::uint64; + case IOComponentEnum::LONG: + return JSONIntTypesEnum::int64; + case IOComponentEnum::ULONGLONG: + return JSONIntTypesEnum::uint64; + case IOComponentEnum::LONGLONG: + return JSONIntTypesEnum::int64; + case IOComponentEnum::UNKNOWNCOMPONENTTYPE: + // default + return JSONIntTypesEnum::uint8; + default: + throw std::invalid_argument("Unknown IOComponentEnum"); + } +} + +JSONFloatTypesEnum +jsonFloatTypeFromIOComponentEnum(const IOComponentEnum & ioComponent) +{ + switch (ioComponent) + { + case IOComponentEnum::FLOAT: + return JSONFloatTypesEnum::float32; + case IOComponentEnum::DOUBLE: + return JSONFloatTypesEnum::float64; + case IOComponentEnum::UNKNOWNCOMPONENTTYPE: + // default + return JSONFloatTypesEnum::float32; + default: + throw std::invalid_argument("Unknown IOComponentEnum"); + } +} + +JSONComponentTypesEnum +jsonComponentTypeFromIOComponentEnum(const IOComponentEnum & ioComponent) +{ + switch (ioComponent) + { + case IOComponentEnum::UCHAR: + return JSONComponentTypesEnum::uint8; + case IOComponentEnum::CHAR: + return JSONComponentTypesEnum::int8; + case IOComponentEnum::USHORT: + return JSONComponentTypesEnum::uint16; + case IOComponentEnum::SHORT: + return JSONComponentTypesEnum::int16; + case IOComponentEnum::UINT: + return JSONComponentTypesEnum::uint32; + case IOComponentEnum::INT: + return JSONComponentTypesEnum::int32; + case IOComponentEnum::ULONGLONG: + return JSONComponentTypesEnum::uint64; + case IOComponentEnum::LONGLONG: + return JSONComponentTypesEnum::int64; + case IOComponentEnum::FLOAT: + return JSONComponentTypesEnum::float32; + case IOComponentEnum::DOUBLE: + return JSONComponentTypesEnum::float64; + case IOComponentEnum::UNKNOWNCOMPONENTTYPE: + // default + return JSONComponentTypesEnum::float32; + default: + throw std::invalid_argument("Unknown IOComponentEnum"); + } +} +} // end namespace itk diff --git a/src/itkjsonFromIOPixelEnum.cxx b/src/itkjsonFromIOPixelEnum.cxx new file mode 100644 index 000000000..2385715e7 --- /dev/null +++ b/src/itkjsonFromIOPixelEnum.cxx @@ -0,0 +1,65 @@ +/*========================================================================= + * + * 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. + * + *=========================================================================*/ +#include "itkioPixelEnumFromJSON.h" + +namespace itk +{ + +JSONPixelTypesEnum +jsonFromIOPixelEnum(const IOPixelEnum & ioPixel) +{ + switch (ioPixel) + { + case IOPixelEnum::UNKNOWNPIXELTYPE: + return JSONPixelTypesEnum::Unknown; + case IOPixelEnum::SCALAR: + return JSONPixelTypesEnum::Scalar; + case IOPixelEnum::RGB: + return JSONPixelTypesEnum::RGB; + case IOPixelEnum::RGBA: + return JSONPixelTypesEnum::RGBA; + case IOPixelEnum::OFFSET: + return JSONPixelTypesEnum::Offset; + case IOPixelEnum::VECTOR: + return JSONPixelTypesEnum::Vector; + case IOPixelEnum::POINT: + return JSONPixelTypesEnum::Point; + case IOPixelEnum::COVARIANTVECTOR: + return JSONPixelTypesEnum::CovariantVector; + case IOPixelEnum::SYMMETRICSECONDRANKTENSOR: + return JSONPixelTypesEnum::SymmetricSecondRankTensor; + case IOPixelEnum::DIFFUSIONTENSOR3D: + return JSONPixelTypesEnum::DiffusionTensor3D; + case IOPixelEnum::COMPLEX: + return JSONPixelTypesEnum::Complex; + case IOPixelEnum::FIXEDARRAY: + return JSONPixelTypesEnum::FixedArray; + case IOPixelEnum::ARRAY: + return JSONPixelTypesEnum::Array; + case IOPixelEnum::MATRIX: + return JSONPixelTypesEnum::Matrix; + case IOPixelEnum::VARIABLELENGTHVECTOR: + return JSONPixelTypesEnum::VariableLengthVector; + case IOPixelEnum::VARIABLESIZEMATRIX: + return JSONPixelTypesEnum::VariableSizeMatrix; + default: + return JSONPixelTypesEnum::Unknown; + } +} + +} // end namespace itk diff --git a/test/itkWasmMeshIOTest.cxx b/test/itkWasmMeshIOTest.cxx index ea99be566..65fbc6e32 100644 --- a/test/itkWasmMeshIOTest.cxx +++ b/test/itkWasmMeshIOTest.cxx @@ -49,6 +49,8 @@ itkWasmMeshIOTest(int argc, char * argv[]) meshReader->SetFileName(inputMeshFile); ITK_TRY_EXPECT_NO_EXCEPTION(meshReader->Update()); auto inputMesh = meshReader->GetOutput(); + std::cout << "inputMesh: " << inputMesh << std::endl; + inputMesh->Print(std::cout); auto meshIO = itk::WasmMeshIO::New(); From 079acfef9ef24443abdfce987aed6637fcb873eb Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Fri, 5 Jul 2024 06:42:12 -0400 Subject: [PATCH 03/10] refactor(polydata): rapidjson to glaze --- include/itkMeshJSON.h | 2 +- include/itkMeshToWasmMeshFilter.hxx | 3 +- include/itkPolyDataJSON.h | 210 ++++++++++++++++++ include/itkPolyDataToWasmPolyDataFilter.hxx | 200 +---------------- include/itkTransformJSON.h | 5 +- include/itkWasmMeshToMeshFilter.hxx | 2 - include/itkWasmPolyDataToPolyDataFilter.hxx | 83 +++---- .../itk-wasm/src/interface-types/image.ts | 2 +- .../itk-wasm/src/interface-types/mesh.ts | 2 +- .../itk-wasm/src/interface-types/poly-data.ts | 6 +- 10 files changed, 261 insertions(+), 254 deletions(-) create mode 100644 include/itkPolyDataJSON.h diff --git a/include/itkMeshJSON.h b/include/itkMeshJSON.h index 121136d30..e305d9cc2 100644 --- a/include/itkMeshJSON.h +++ b/include/itkMeshJSON.h @@ -60,7 +60,7 @@ namespace itk { MeshTypeJSON meshType; - std::string name; + std::string name { "mesh "}; size_t numberOfPoints{ 0 }; std::string points; diff --git a/include/itkMeshToWasmMeshFilter.hxx b/include/itkMeshToWasmMeshFilter.hxx index 2ac5ef339..b449e3786 100644 --- a/include/itkMeshToWasmMeshFilter.hxx +++ b/include/itkMeshToWasmMeshFilter.hxx @@ -132,9 +132,8 @@ MeshToWasmMeshFilter auto ec = glz::write(meshJSON, serialized); if (ec) { - itkExceptionMacro("Failed to serialize TransformListJSON"); + itkExceptionMacro("Failed to serialize MeshJSON"); } - std::cout << "SERIALIZED: " << serialized << std::endl; wasmMesh->SetJSON(serialized); } diff --git a/include/itkPolyDataJSON.h b/include/itkPolyDataJSON.h new file mode 100644 index 000000000..db45c97d1 --- /dev/null +++ b/include/itkPolyDataJSON.h @@ -0,0 +1,210 @@ +/*========================================================================= + * + * 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 itkPolyDataJSON_h +#define itkPolyDataJSON_h + +#include "itkMeshConvertPixelTraits.h" + +#include "itkWasmMapComponentType.h" +#include "itkWasmMapPixelType.h" +#include "itkIntTypesJSON.h" +#include "itkFloatTypesJSON.h" +#include "itkPixelTypesJSON.h" +#include "itkWasmPolyData.h" + +#include "glaze/glaze.hpp" + +namespace itk +{ + /** \class PolyDataTypeJSON + * + * \brief PolyData type JSON representation data structure. + * + * \ingroup WebAssemblyInterface + */ + struct PolyDataTypeJSON + { + JSONComponentTypesEnum pointPixelComponentType { JSONComponentTypesEnum::float32 }; + JSONPixelTypesEnum pointPixelType { JSONPixelTypesEnum::Scalar }; + unsigned int pointPixelComponents { 1 }; + JSONComponentTypesEnum cellPixelComponentType { JSONComponentTypesEnum::float32 }; + JSONPixelTypesEnum cellPixelType { JSONPixelTypesEnum::Scalar }; + unsigned int cellPixelComponents { 1 }; + }; + + /** \class PolyDataJSON + * + * \brief PolyData JSON representation data structure. + * + * \ingroup WebAssemblyInterface + */ + struct PolyDataJSON + { + PolyDataTypeJSON polyDataType; + + std::string name { "polydata" }; + + size_t numberOfPoints{ 0 }; + std::string points; + + size_t verticesBufferSize { 0 }; + std::string vertices; + + size_t linesBufferSize { 0 }; + std::string lines; + + size_t polygonsBufferSize { 0 }; + std::string polygons; + + size_t triangleStripsBufferSize { 0 }; + std::string triangleStrips; + + size_t numberOfPointPixels { 0 }; + std::string pointData; + + size_t numberOfCellPixels { 0 }; + std::string cellData; + }; + +template +auto polyDataToPolyDataJSON(const TPolyData * polyData, bool inMemory) -> PolyDataJSON +{ + using PolyDataType = TPolyData; + + PolyDataJSON polyDataJSON; + + using PointPixelType = typename TPolyData::PixelType; + using ConvertPointPixelTraits = MeshConvertPixelTraits; + polyDataJSON.polyDataType.pointPixelComponentType = wasm::MapComponentType::JSONComponentEnum; + polyDataJSON.polyDataType.pointPixelType = wasm::MapPixelType::JSONPixelEnum; + polyDataJSON.polyDataType.pointPixelComponents = ConvertPointPixelTraits::GetNumberOfComponents(); + + using CellPixelType = typename TPolyData::CellPixelType; + using ConvertCellPixelTraits = MeshConvertPixelTraits; + polyDataJSON.polyDataType.cellPixelComponentType = wasm::MapComponentType::JSONComponentEnum; + polyDataJSON.polyDataType.cellPixelType = wasm::MapPixelType::JSONPixelEnum; + polyDataJSON.polyDataType.cellPixelComponents = ConvertCellPixelTraits::GetNumberOfComponents(); + + polyDataJSON.name = polyData->GetObjectName(); + polyDataJSON.numberOfPoints = polyData->GetNumberOfPoints(); + + if (polyData->GetPointData() != nullptr) + { + polyDataJSON.verticesBufferSize = polyData->GetVertices()->Size(); + } + + if (polyData->GetPointData() != nullptr) + { + polyDataJSON.linesBufferSize = polyData->GetLines()->Size(); + } + + if (polyData->GetPointData() != nullptr) + { + polyDataJSON.polygonsBufferSize = polyData->GetPolygons()->Size(); + } + + if (polyData->GetPointData() != nullptr) + { + polyDataJSON.triangleStripsBufferSize = polyData->GetTriangleStrips()->Size(); + } + + if (polyData->GetPointData() != nullptr) + { + polyDataJSON.numberOfPointPixels = polyData->GetPointData()->Size(); + } + + if (polyData->GetCellData() != nullptr) + { + polyDataJSON.numberOfCellPixels = polyData->GetCellData()->Size(); + } + + size_t pointsAddress = 0; + if (polyData->GetNumberOfPoints()) + { + pointsAddress = reinterpret_cast< size_t >( &(polyData->GetPoints()->at(0)) ); + } + std::ostringstream pointsStream; + pointsStream << "data:application/vnd.itk.address,0:"; + pointsStream << pointsAddress; + polyDataJSON.points = pointsStream.str(); + + size_t verticesAddress = 0; + if (polyData->GetVertices() != nullptr && polyData->GetVertices()->Size() > 0) + { + verticesAddress = reinterpret_cast< size_t >( &(polyData->GetVertices()->at(0)) ); + } + std::ostringstream verticesStream; + verticesStream << "data:application/vnd.itk.address,0:"; + verticesStream << verticesAddress; + polyDataJSON.vertices = verticesStream.str(); + + size_t linesAddress = 0; + if (polyData->GetLines() != nullptr && polyData->GetLines()->Size() > 0) + { + linesAddress = reinterpret_cast< size_t >( &(polyData->GetLines()->at(0)) ); + } + std::ostringstream linesStream; + linesStream << "data:application/vnd.itk.address,0:"; + linesStream << linesAddress; + polyDataJSON.lines = linesStream.str(); + + size_t polygonsAddress = 0; + if (polyData->GetPolygons() != nullptr && polyData->GetPolygons()->Size() > 0) + { + polygonsAddress = reinterpret_cast< size_t >( &(polyData->GetPolygons()->at(0)) ); + } + std::ostringstream polygonsStream; + polygonsStream << "data:application/vnd.itk.address,0:"; + polygonsStream << polygonsAddress; + polyDataJSON.polygons = polygonsStream.str(); + + size_t triangleStripsAddress = 0; + if (polyData->GetTriangleStrips() != nullptr && polyData->GetTriangleStrips()->Size() > 0) + { + triangleStripsAddress = reinterpret_cast< size_t >( &(polyData->GetTriangleStrips()->at(0)) ); + } + std::ostringstream triangleStripsStream; + triangleStripsStream << "data:application/vnd.itk.address,0:"; + triangleStripsStream << triangleStripsAddress; + polyDataJSON.triangleStrips = triangleStripsStream.str(); + + size_t pointDataAddress = 0; + if (polyData->GetPointData() != nullptr && polyData->GetPointData()->Size() > 0) + { + pointDataAddress = reinterpret_cast< size_t >( &(polyData->GetPointData()->at(0)) ); + } + std::ostringstream pointDataStream; + pointDataStream << "data:application/vnd.itk.address,0:"; + pointDataStream << pointDataAddress; + polyDataJSON.pointData = pointDataStream.str(); + + size_t cellDataAddress = 0; + if (polyData->GetCellData() != nullptr && polyData->GetCellData()->Size() > 0) + { + cellDataAddress = reinterpret_cast< size_t >( &(polyData->GetCellData()->at(0)) ); + } + std::ostringstream cellDataStream; + cellDataStream << "data:application/vnd.itk.address,0:"; + cellDataStream << cellDataAddress; + polyDataJSON.cellData = cellDataStream.str(); + + return polyDataJSON; +} +} // end namespace itk + +#endif // itkPolyDataJSON_h diff --git a/include/itkPolyDataToWasmPolyDataFilter.hxx b/include/itkPolyDataToWasmPolyDataFilter.hxx index d277fc092..c390b62d8 100644 --- a/include/itkPolyDataToWasmPolyDataFilter.hxx +++ b/include/itkPolyDataToWasmPolyDataFilter.hxx @@ -25,9 +25,7 @@ #include "itkWasmMapComponentType.h" #include "itkWasmMapPixelType.h" -#include "rapidjson/document.h" -#include "rapidjson/stringbuffer.h" -#include "rapidjson/writer.h" +#include "itkPolyDataJSON.h" namespace itk { @@ -136,198 +134,16 @@ PolyDataToWasmPolyDataFilter wasmPolyData->SetPolyData(polyData); - rapidjson::Document document; - document.SetObject(); - rapidjson::Document::AllocatorType& allocator = document.GetAllocator(); - - rapidjson::Value polyDataType; - polyDataType.SetObject(); - - using PointPixelType = typename TPolyData::PixelType; - using ConvertPointPixelTraits = MeshConvertPixelTraits; - rapidjson::Value pointPixelComponentType; - pointPixelComponentType.SetString( wasm::MapComponentType::ComponentString.data(), allocator ); - polyDataType.AddMember("pointPixelComponentType", pointPixelComponentType.Move(), allocator ); - - rapidjson::Value pointPixelType; - pointPixelType.SetString( wasm::MapPixelType::PixelString.data(), allocator ); - polyDataType.AddMember("pointPixelType", pointPixelType.Move(), allocator ); - - polyDataType.AddMember("pointPixelComponents", rapidjson::Value( ConvertPointPixelTraits::GetNumberOfComponents() ).Move(), allocator ); - - using CellPixelType = typename TPolyData::CellPixelType; - using ConvertCellPixelTraits = MeshConvertPixelTraits; - rapidjson::Value cellPixelComponentType; - cellPixelComponentType.SetString( wasm::MapComponentType::ComponentString.data(), allocator ); - polyDataType.AddMember("cellPixelComponentType", cellPixelComponentType.Move(), allocator ); - - rapidjson::Value cellPixelType; - cellPixelType.SetString( wasm::MapPixelType::PixelString.data(), allocator ); - polyDataType.AddMember("cellPixelType", cellPixelType, allocator ); - - polyDataType.AddMember("cellPixelComponents", rapidjson::Value( ConvertCellPixelTraits::GetNumberOfComponents() ).Move(), allocator ); - - document.AddMember( "polyDataType", polyDataType.Move(), allocator ); - - rapidjson::Value numberOfPoints; - numberOfPoints.SetInt( polyData->GetNumberOfPoints() ); - document.AddMember( "numberOfPoints", numberOfPoints.Move(), allocator ); - - rapidjson::Value verticesBufferSize; - if (polyData->GetPointData() == nullptr) - { - verticesBufferSize.SetInt( 0 ); - } - else - { - verticesBufferSize.SetInt( polyData->GetVertices()->Size() ); - } - document.AddMember( "verticesBufferSize", verticesBufferSize.Move(), allocator ); - - rapidjson::Value linesBufferSize; - if (polyData->GetPointData() == nullptr) - { - linesBufferSize.SetInt( 0 ); - } - else - { - linesBufferSize.SetInt( polyData->GetLines()->Size() ); - } - document.AddMember( "linesBufferSize", linesBufferSize.Move(), allocator ); - - rapidjson::Value polygonsBufferSize; - if (polyData->GetPointData() == nullptr) - { - polygonsBufferSize.SetInt( 0 ); - } - else - { - polygonsBufferSize.SetInt( polyData->GetPolygons()->Size() ); - } - document.AddMember( "polygonsBufferSize", polygonsBufferSize.Move(), allocator ); - - rapidjson::Value triangleStripsBufferSize; - if (polyData->GetPointData() == nullptr) - { - triangleStripsBufferSize.SetInt( 0 ); - } - else - { - triangleStripsBufferSize.SetInt( polyData->GetTriangleStrips()->Size() ); - } - document.AddMember( "triangleStripsBufferSize", triangleStripsBufferSize.Move(), allocator ); - - rapidjson::Value numberOfPointPixels; - if (polyData->GetPointData() == nullptr) + constexpr bool inMemory = true; + const auto polyDataJSON = polyDataToPolyDataJSON(polyData, inMemory); + std::string serialized{}; + auto ec = glz::write(polyDataJSON, serialized); + if (ec) { - numberOfPointPixels.SetInt( 0 ); + itkExceptionMacro("Failed to serialize PolyDataJSON"); } - else - { - numberOfPointPixels.SetInt( polyData->GetPointData()->Size() ); - } - document.AddMember( "numberOfPointPixels", numberOfPointPixels.Move(), allocator ); - - rapidjson::Value numberOfCellPixels; - if (polyData->GetCellData() == nullptr) - { - numberOfCellPixels.SetInt( 0 ); - } - else - { - numberOfCellPixels.SetInt( polyData->GetCellData()->Size() ); - } - document.AddMember( "numberOfCellPixels", numberOfCellPixels.Move(), allocator ); - - size_t pointsAddress = 0; - if (polyData->GetNumberOfPoints()) - { - pointsAddress = reinterpret_cast< size_t >( &(polyData->GetPoints()->at(0)) ); - } - std::ostringstream pointsStream; - pointsStream << "data:application/vnd.itk.address,0:"; - pointsStream << pointsAddress; - rapidjson::Value pointsString; - pointsString.SetString( pointsStream.str().c_str(), allocator ); - document.AddMember( "points", pointsString.Move(), allocator ); - - size_t verticesAddress = 0; - if (polyData->GetVertices() != nullptr && polyData->GetVertices()->Size() > 0) - { - verticesAddress = reinterpret_cast< size_t >( &(polyData->GetVertices()->at(0)) ); - } - std::ostringstream verticesStream; - verticesStream << "data:application/vnd.itk.address,0:"; - verticesStream << verticesAddress; - rapidjson::Value verticesString; - verticesString.SetString( verticesStream.str().c_str(), allocator ); - document.AddMember( "vertices", verticesString.Move(), allocator ); - - size_t linesAddress = 0; - if (polyData->GetLines() != nullptr && polyData->GetLines()->Size() > 0) - { - linesAddress = reinterpret_cast< size_t >( &(polyData->GetLines()->at(0)) ); - } - std::ostringstream linesStream; - linesStream << "data:application/vnd.itk.address,0:"; - linesStream << linesAddress; - rapidjson::Value linesString; - linesString.SetString( linesStream.str().c_str(), allocator ); - document.AddMember( "lines", linesString.Move(), allocator ); - - size_t polygonsAddress = 0; - if (polyData->GetPolygons() != nullptr && polyData->GetPolygons()->Size() > 0) - { - polygonsAddress = reinterpret_cast< size_t >( &(polyData->GetPolygons()->at(0)) ); - } - std::ostringstream polygonsStream; - polygonsStream << "data:application/vnd.itk.address,0:"; - polygonsStream << polygonsAddress; - rapidjson::Value polygonsString; - polygonsString.SetString( polygonsStream.str().c_str(), allocator ); - document.AddMember( "polygons", polygonsString.Move(), allocator ); - - size_t triangleStripsAddress = 0; - if (polyData->GetTriangleStrips() != nullptr && polyData->GetTriangleStrips()->Size() > 0) - { - triangleStripsAddress = reinterpret_cast< size_t >( &(polyData->GetTriangleStrips()->at(0)) ); - } - std::ostringstream triangleStripsStream; - triangleStripsStream << "data:application/vnd.itk.address,0:"; - triangleStripsStream << triangleStripsAddress; - rapidjson::Value triangleStripsString; - triangleStripsString.SetString( triangleStripsStream.str().c_str(), allocator ); - document.AddMember( "triangleStrips", triangleStripsString.Move(), allocator ); - - size_t pointDataAddress = 0; - if (polyData->GetPointData() != nullptr && polyData->GetPointData()->Size() > 0) - { - pointDataAddress = reinterpret_cast< size_t >( &(polyData->GetPointData()->at(0)) ); - } - std::ostringstream pointDataStream; - pointDataStream << "data:application/vnd.itk.address,0:"; - pointDataStream << pointDataAddress; - rapidjson::Value pointDataString; - pointDataString.SetString( pointDataStream.str().c_str(), allocator ); - document.AddMember( "pointData", pointDataString.Move(), allocator ); - - size_t cellDataAddress = 0; - if (polyData->GetCellData() != nullptr && polyData->GetCellData()->Size() > 0) - { - cellDataAddress = reinterpret_cast< size_t >( &(polyData->GetCellData()->at(0)) ); - } - std::ostringstream cellDataStream; - cellDataStream << "data:application/vnd.itk.address,0:"; - cellDataStream << cellDataAddress; - rapidjson::Value cellDataString; - cellDataString.SetString( cellDataStream.str().c_str(), allocator ); - document.AddMember( "cellData", cellDataString.Move(), allocator ); - - rapidjson::StringBuffer stringBuffer; - rapidjson::Writer writer(stringBuffer); - document.Accept(writer); - wasmPolyData->SetJSON(stringBuffer.GetString()); + wasmPolyData->SetJSON(serialized); } template diff --git a/include/itkTransformJSON.h b/include/itkTransformJSON.h index de9dc189e..dd344f5aa 100644 --- a/include/itkTransformJSON.h +++ b/include/itkTransformJSON.h @@ -84,9 +84,12 @@ namespace itk TransformTypeJSON transformType; uint64_t numberOfFixedParameters{ 0 }; uint64_t numberOfParameters{ 0 }; - std::string name; + + std::string name { "transform" }; + std::string inputSpaceName; std::string outputSpaceName; + std::string fixedParameters; std::string parameters; }; diff --git a/include/itkWasmMeshToMeshFilter.hxx b/include/itkWasmMeshToMeshFilter.hxx index f23342f00..e0250b1c0 100644 --- a/include/itkWasmMeshToMeshFilter.hxx +++ b/include/itkWasmMeshToMeshFilter.hxx @@ -368,7 +368,6 @@ WasmMeshToMeshFilter using CellPixelType = typename MeshType::CellPixelType; using ConvertCellPixelTraits = MeshConvertPixelTraits; - std::cout << "meshJSON: " << wasmMesh->GetJSON() << "\n"; const std::string json(wasmMesh->GetJSON()); auto deserializedAttempt = glz::read_json(json); if (!deserializedAttempt) @@ -406,7 +405,6 @@ WasmMeshToMeshFilter if (numberOfCellPixels && cellPixelComponentType != itk::wasm::MapComponentType::JSONComponentEnum ) { - std::cout << "numberOfCellPixels: " << numberOfCellPixels << "\n"; throw std::runtime_error("Unexpected cell pixel component type"); } diff --git a/include/itkWasmPolyDataToPolyDataFilter.hxx b/include/itkWasmPolyDataToPolyDataFilter.hxx index 5edbe2c4c..dc97dc8d6 100644 --- a/include/itkWasmPolyDataToPolyDataFilter.hxx +++ b/include/itkWasmPolyDataToPolyDataFilter.hxx @@ -36,7 +36,7 @@ #include "itkWasmMapPixelType.h" #include "itkMeshConvertPixelTraits.h" -#include "rapidjson/document.h" +#include "itkPolyDataJSON.h" namespace itk { @@ -140,128 +140,109 @@ WasmPolyDataToPolyDataFilter ::GenerateData() { // Get the input and output pointers - const WasmPolyDataType * polyDataJSON = this->GetInput(); - const std::string json(polyDataJSON->GetJSON()); + const WasmPolyDataType * wasmPolyData = this->GetInput(); + const std::string json(wasmPolyData->GetJSON()); PolyDataType * polyData = this->GetOutput(); + using PointType = typename TPolyData::PointType; using PointPixelType = typename PolyDataType::PixelType; using ConvertPointPixelTraits = MeshConvertPixelTraits; using CellPixelType = typename PolyDataType::CellPixelType; using ConvertCellPixelTraits = MeshConvertPixelTraits; - rapidjson::Document document; - if (document.Parse(json.c_str()).HasParseError()) - { - throw std::runtime_error("Could not parse JSON"); - } - - const rapidjson::Value & polyDataType = document["polyDataType"]; + auto deserializedAttempt = glz::read_json(json); + if (!deserializedAttempt) + { + const std::string descriptiveError = glz::format_error(deserializedAttempt, json); + itkExceptionMacro("Failed to deserialize PolyDataJSON: " << descriptiveError); + } + const auto polyDataJSON = deserializedAttempt.value(); + const auto & polyDataType = polyDataJSON.polyDataType; - const std::string pointPixelComponentType( polyDataType["pointPixelComponentType"].GetString() ); - if ( pointPixelComponentType != itk::wasm::MapComponentType::ComponentString ) + if ( polyDataType.pointPixelComponentType != itk::wasm::MapComponentType::JSONComponentEnum ) { throw std::runtime_error("Unexpected point pixel component type"); } - const std::string pointPixelType( polyDataType["pointPixelType"].GetString() ); - if ( pointPixelType != itk::wasm::MapPixelType::PixelString ) + if ( polyDataType.pointPixelType != itk::wasm::MapPixelType::JSONPixelEnum ) { throw std::runtime_error("Unexpected point pixel type"); } - const std::string cellPixelComponentType( polyDataType["cellPixelComponentType"].GetString() ); - if ( cellPixelComponentType != itk::wasm::MapComponentType::ComponentString ) + if ( polyDataType.cellPixelComponentType != itk::wasm::MapComponentType::JSONComponentEnum ) { throw std::runtime_error("Unexpected cell pixel component type"); } - const std::string cellPixelType( polyDataType["cellPixelType"].GetString() ); - if ( cellPixelType != itk::wasm::MapPixelType::PixelString ) + if ( polyDataType.cellPixelType != itk::wasm::MapPixelType::JSONPixelEnum ) { throw std::runtime_error("Unexpected cell pixel type"); } - const rapidjson::Value & numberOfPointsJson = document["numberOfPoints"]; - const SizeValueType numberOfPoints = numberOfPointsJson.GetInt(); + const SizeValueType numberOfPoints = polyDataJSON.numberOfPoints; if (numberOfPoints) { - using PointType = typename PolyDataType::PointType; - const rapidjson::Value & pointsJson = document["points"]; - const std::string pointsString( pointsJson.GetString() ); + const std::string pointsString = polyDataJSON.points; const auto * pointsPtr = reinterpret_cast< PointType * >( std::strtoull(pointsString.substr(35).c_str(), nullptr, 10) ); polyData->GetPoints()->resize(numberOfPoints); polyData->GetPoints()->assign(pointsPtr, pointsPtr + numberOfPoints); } - const rapidjson::Value & verticesBufferSizeJson = document["verticesBufferSize"]; - const SizeValueType verticesBufferSize = verticesBufferSizeJson.GetInt(); + const SizeValueType verticesBufferSize = polyDataJSON.verticesBufferSize; if (verticesBufferSize) { - const rapidjson::Value & verticesJson = document["vertices"]; - const std::string verticesString( verticesJson.GetString() ); + const std::string verticesString = polyDataJSON.vertices; auto verticesPtr = reinterpret_cast< uint32_t * >( std::strtoull(verticesString.substr(35).c_str(), nullptr, 10) ); polyData->GetVertices()->resize(verticesBufferSize); polyData->GetVertices()->assign(verticesPtr, verticesPtr + verticesBufferSize); } - const rapidjson::Value & linesBufferSizeJson = document["linesBufferSize"]; - const SizeValueType linesBufferSize = linesBufferSizeJson.GetInt(); + const SizeValueType linesBufferSize = polyDataJSON.linesBufferSize; if (linesBufferSize) { - const rapidjson::Value & linesJson = document["lines"]; - const std::string linesString( linesJson.GetString() ); + const std::string linesString = polyDataJSON.lines; auto linesPtr = reinterpret_cast< uint32_t * >( std::strtoull(linesString.substr(35).c_str(), nullptr, 10) ); polyData->GetLines()->resize(linesBufferSize); polyData->GetLines()->assign(linesPtr, linesPtr + linesBufferSize); } - const rapidjson::Value & polygonsBufferSizeJson = document["polygonsBufferSize"]; - const SizeValueType polygonsBufferSize = polygonsBufferSizeJson.GetInt(); + const SizeValueType polygonsBufferSize = polyDataJSON.polygonsBufferSize; if (polygonsBufferSize) { - const rapidjson::Value & polygonsJson = document["polygons"]; - const std::string polygonsString( polygonsJson.GetString() ); + const std::string polygonsString = polyDataJSON.polygons; auto polygonsPtr = reinterpret_cast< uint32_t * >( std::strtoull(polygonsString.substr(35).c_str(), nullptr, 10) ); polyData->GetPolygons()->resize(polygonsBufferSize); polyData->GetPolygons()->assign(polygonsPtr, polygonsPtr + polygonsBufferSize); } - const rapidjson::Value & triangleStripsBufferSizeJson = document["triangleStripsBufferSize"]; - const SizeValueType triangleStripsBufferSize = triangleStripsBufferSizeJson.GetInt(); + const SizeValueType triangleStripsBufferSize = polyDataJSON.triangleStripsBufferSize; if (triangleStripsBufferSize) { - const rapidjson::Value & triangleStripsJson = document["triangleStrips"]; - const std::string triangleStripsString( triangleStripsJson.GetString() ); + const std::string triangleStripsString = polyDataJSON.triangleStrips; auto triangleStripsPtr = reinterpret_cast< uint32_t * >( std::strtoull(triangleStripsString.substr(35).c_str(), nullptr, 10) ); polyData->GetTriangleStrips()->resize(triangleStripsBufferSize); polyData->GetTriangleStrips()->assign(triangleStripsPtr, triangleStripsPtr + triangleStripsBufferSize); } - const rapidjson::Value & numberOfPointPixelsJson = document["numberOfPointPixels"]; - const SizeValueType numberOfPointPixels = numberOfPointPixelsJson.GetInt(); + const SizeValueType numberOfPointPixels = polyDataJSON.numberOfPointPixels; if (numberOfPointPixels) { - const rapidjson::Value & pointPixelComponentsJson = polyDataType["pointPixelComponents"]; - const SizeValueType pointPixelComponents = pointPixelComponentsJson.GetInt(); - const rapidjson::Value & pointDataJson = document["pointData"]; + const SizeValueType pointPixelComponents = polyDataType.pointPixelComponents; using PointPixelType = typename TPolyData::PixelType; using ConvertPointPixelTraits = MeshConvertPixelTraits; - const std::string pointDataString( pointDataJson.GetString() ); + const std::string pointDataString = polyDataJSON.pointData; auto pointDataPtr = reinterpret_cast< typename ConvertPointPixelTraits::ComponentType * >( std::strtoull(pointDataString.substr(35).c_str(), nullptr, 10) ); polyData->GetPointData()->resize(numberOfPointPixels * pointPixelComponents); polyData->GetPointData()->assign(pointDataPtr, pointDataPtr + numberOfPointPixels * pointPixelComponents); } - const rapidjson::Value & numberOfCellPixelsJson = document["numberOfCellPixels"]; - const SizeValueType numberOfCellPixels = numberOfCellPixelsJson.GetInt(); + const SizeValueType numberOfCellPixels = polyDataJSON.numberOfCellPixels; if (numberOfCellPixels) { - const rapidjson::Value & cellPixelComponentsJson = polyDataType["cellPixelComponents"]; - const SizeValueType cellPixelComponents = cellPixelComponentsJson.GetInt(); - const rapidjson::Value & cellDataJson = document["cellData"]; + const SizeValueType cellPixelComponents = polyDataType.cellPixelComponents; using CellPixelType = typename TPolyData::CellPixelType; using ConvertCellPixelTraits = MeshConvertPixelTraits; - const std::string cellDataString( cellDataJson.GetString() ); + const std::string cellDataString = polyDataJSON.cellData; auto cellDataPtr = reinterpret_cast< typename ConvertCellPixelTraits::ComponentType * >( std::strtoull(cellDataString.substr(35).c_str(), nullptr, 10) ); if (polyData->GetCellData() == nullptr) { diff --git a/packages/core/typescript/itk-wasm/src/interface-types/image.ts b/packages/core/typescript/itk-wasm/src/interface-types/image.ts index 8e6fc854d..656c6df43 100644 --- a/packages/core/typescript/itk-wasm/src/interface-types/image.ts +++ b/packages/core/typescript/itk-wasm/src/interface-types/image.ts @@ -18,7 +18,7 @@ class Image { data: null | TypedArray - constructor (public readonly imageType = new ImageType()) { + constructor(public readonly imageType = new ImageType()) { const dimension = imageType.dimension this.origin = new Array(dimension) this.origin.fill(0.0) diff --git a/packages/core/typescript/itk-wasm/src/interface-types/mesh.ts b/packages/core/typescript/itk-wasm/src/interface-types/mesh.ts index 458e1a236..4ec4836c3 100644 --- a/packages/core/typescript/itk-wasm/src/interface-types/mesh.ts +++ b/packages/core/typescript/itk-wasm/src/interface-types/mesh.ts @@ -17,7 +17,7 @@ class Mesh { numberOfCellPixels: number cellData: null | TypedArray - constructor (public readonly meshType = new MeshType()) { + constructor(public readonly meshType = new MeshType()) { this.name = 'mesh' this.numberOfPoints = 0 diff --git a/packages/core/typescript/itk-wasm/src/interface-types/poly-data.ts b/packages/core/typescript/itk-wasm/src/interface-types/poly-data.ts index ffca9bfab..a270a2fbd 100644 --- a/packages/core/typescript/itk-wasm/src/interface-types/poly-data.ts +++ b/packages/core/typescript/itk-wasm/src/interface-types/poly-data.ts @@ -2,7 +2,7 @@ import PolyDataType from './poly-data-type.js' import TypedArray from '../typed-array.js' class PolyData { - name: string = 'PolyData' + name: string = 'polydata' numberOfPoints: number points: Float32Array @@ -25,10 +25,10 @@ class PolyData { numberOfCellPixels: number cellData: null | TypedArray - constructor (public readonly polyDataType = new PolyDataType()) { + constructor(public readonly polyDataType = new PolyDataType()) { this.polyDataType = polyDataType - this.name = 'PolyData' + this.name = 'polydata' this.numberOfPoints = 0 this.points = new Float32Array() From 4fd25144ce4b1fa13018f63564162960b6232e96 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Fri, 5 Jul 2024 11:07:10 -0400 Subject: [PATCH 04/10] refactor(SupportInputMeshTypes): rapidjson to glaze --- include/itkSupportInputMeshTypes.h | 35 +++++++++----------- src/itkSupportInputMeshTypes.cxx | 53 +++++++++++++++--------------- 2 files changed, 42 insertions(+), 46 deletions(-) diff --git a/include/itkSupportInputMeshTypes.h b/include/itkSupportInputMeshTypes.h index 44ba7318c..d6c94a58b 100644 --- a/include/itkSupportInputMeshTypes.h +++ b/include/itkSupportInputMeshTypes.h @@ -29,22 +29,16 @@ #include "itkMeshIOFactory.h" #include "WebAssemblyInterfaceExport.h" +#include "itkMeshJSON.h" + namespace itk { +WebAssemblyInterface_EXPORT bool lexical_cast(const std::string &input, MeshTypeJSON & meshType); + namespace wasm { -struct InterfaceMeshType -{ - unsigned int dimension{2}; - std::string componentType{"uint8"}; - std::string pixelType{"Scalar"}; - unsigned int components{1}; -}; - -WebAssemblyInterface_EXPORT bool lexical_cast(const std::string &input, InterfaceMeshType & meshType); - /** \class SupportInputMeshTypes * * \brief Instantiatiate a Pipeline functor over multiple pixel types and dimensions and match to the input mesh type. @@ -100,7 +94,7 @@ SupportInputMeshTypes static int Dimensions(const std::string & inputMeshOptionName, Pipeline & pipeline) { - InterfaceMeshType meshType; + MeshTypeJSON meshType; const auto iwpArgc = pipeline.get_argc(); const auto iwpArgv = pipeline.get_argv(); @@ -130,17 +124,19 @@ SupportInputMeshTypes private: template static int - IteratePixelTypes(Pipeline & pipeline, const InterfaceMeshType & meshType, bool passThrough = false) + IteratePixelTypes(Pipeline & pipeline, const MeshTypeJSON & meshType, bool passThrough = false) { constexpr unsigned int Dimension = VDimension; using PixelType = TPixel; using ConvertPixelTraits = MeshConvertPixelTraits; - if (passThrough || meshType.components == 0 - || meshType.componentType == MapComponentType::ComponentString - && meshType.pixelType == MapPixelType::PixelString) + const auto components = meshType.pointPixelComponents ? meshType.pointPixelComponents : meshType.cellPixelComponents; + + if (passThrough || components == 0 + || meshType.pointPixelComponentType == MapComponentType::JSONComponentEnum + && meshType.pointPixelType == MapPixelType::JSONPixelEnum) { - if (meshType.pixelType == "VariableLengthVector" || meshType.pixelType == "VariableSizeMatrix" ) + if (meshType.pointPixelType == JSONPixelTypesEnum::VariableLengthVector || meshType.pointPixelType == JSONPixelTypesEnum::VariableSizeMatrix) { // todo: VectorMesh support for ImportMeshFilter? // using MeshType = itk::VectorMesh; @@ -148,7 +144,7 @@ SupportInputMeshTypes // using PipelineType = TPipelineFunctor; // return PipelineType()(pipeline); } - else if(passThrough || meshType.components == ConvertPixelTraits::GetNumberOfComponents() || meshType.components == 0 ) + else if(passThrough || components == ConvertPixelTraits::GetNumberOfComponents() || components == 0 ) { using MeshType = Mesh; @@ -162,14 +158,15 @@ SupportInputMeshTypes } std::ostringstream ostrm; - ostrm << "Unsupported pixel type: " << meshType.pixelType << " with component type: " << meshType.componentType << " and components: " << meshType.components; + std::string meshTypeString = glz::write_json(meshType).value_or("error"); + ostrm << "Unsupported mesh type: " << meshTypeString << std::endl; CLI::Error err("Runtime error", ostrm.str(), 1); return pipeline.exit(err); } template static int - IterateDimensions(Pipeline & pipeline, const InterfaceMeshType & meshType, bool passThrough = false) + IterateDimensions(Pipeline & pipeline, const MeshTypeJSON & meshType, bool passThrough = false) { if (passThrough || VDimension == meshType.dimension) { diff --git a/src/itkSupportInputMeshTypes.cxx b/src/itkSupportInputMeshTypes.cxx index cc874a9d1..4bddce8ce 100644 --- a/src/itkSupportInputMeshTypes.cxx +++ b/src/itkSupportInputMeshTypes.cxx @@ -18,36 +18,29 @@ #include "itkSupportInputMeshTypes.h" #include "itkWasmExports.h" -#include "rapidjson/document.h" +#include "itkjsonFromIOComponentEnum.h" +#include "itkjsonFromIOPixelEnum.h" +#include "itkMeshJSON.h" namespace itk { -namespace wasm -{ - -bool lexical_cast(const std::string &input, InterfaceMeshType & meshType) +bool lexical_cast(const std::string &input, MeshTypeJSON & meshType) { if (wasm::Pipeline::get_use_memory_io()) { #ifndef ITK_WASM_NO_MEMORY_IO const unsigned int index = std::stoi(input); - auto json = getMemoryStoreInputJSON(0, index); - rapidjson::Document document; - if (document.Parse(json.c_str()).HasParseError()) - { - throw std::runtime_error("Could not parse JSON"); - } - - const rapidjson::Value & jsonMeshType = document["meshType"]; - meshType.dimension = jsonMeshType["dimension"].GetInt(); - meshType.componentType = jsonMeshType["pointPixelComponentType"].GetString(); - meshType.pixelType = jsonMeshType["pointPixelType"].GetString(); - meshType.components = jsonMeshType["pointPixelComponents"].GetInt(); - if (meshType.components == 0) + auto json = wasm::getMemoryStoreInputJSON(0, index); + std::string deserialized; + auto deserializedAttempt = glz::read_json(json); + if (!deserializedAttempt) { - meshType.components = jsonMeshType["cellPixelComponents"].GetInt(); + const std::string descriptiveError = glz::format_error(deserializedAttempt, json); + throw std::runtime_error("Failed to deserialize MeshJSON: " + descriptiveError); } + auto meshJSON = deserializedAttempt.value(); + meshType = meshJSON.meshType; #else return false; #endif @@ -68,17 +61,24 @@ bool lexical_cast(const std::string &input, InterfaceMeshType & meshType) using IOComponentType = itk::IOComponentEnum; const IOComponentType ioComponentEnum = meshIO->GetPointPixelComponentType(); - meshType.componentType = WasmComponentTypeFromIOComponentEnum( ioComponentEnum ); + const auto pointIOComponentType = meshIO->GetPointComponentType(); + meshType.pointComponentType = itk::jsonFloatTypeFromIOComponentEnum( pointIOComponentType ); + const auto pointPixelIOComponentType = meshIO->GetPointPixelComponentType(); + meshType.pointPixelComponentType = itk::jsonComponentTypeFromIOComponentEnum( pointPixelIOComponentType ); + const auto pointIOPixelType = meshIO->GetPointPixelType(); + meshType.pointPixelType = itk::jsonFromIOPixelEnum( pointIOPixelType ); + meshType.pointPixelComponents = meshIO->GetNumberOfPointPixelComponents(); using IOPixelType = itk::IOPixelEnum; const IOPixelType ioPixelEnum = meshIO->GetPointPixelType(); - meshType.pixelType = WasmPixelTypeFromIOPixelEnum( ioPixelEnum ); - meshType.components = meshIO->GetNumberOfPointPixelComponents(); - if (meshType.components == 0) - { - meshType.components = meshIO->GetNumberOfPointPixelComponents(); - } + const auto cellIOComponentType = meshIO->GetCellComponentType(); + meshType.cellComponentType = itk::jsonIntTypeFromIOComponentEnum( cellIOComponentType ); + const auto cellPixelIOComponentType = meshIO->GetCellPixelComponentType(); + meshType.cellPixelComponentType = itk::jsonComponentTypeFromIOComponentEnum( cellPixelIOComponentType ); + const auto cellIOPixelType = meshIO->GetCellPixelType(); + meshType.cellPixelType = itk::jsonFromIOPixelEnum( cellIOPixelType ); + meshType.cellPixelComponents = meshIO->GetNumberOfCellPixelComponents(); #else return false; #endif @@ -86,5 +86,4 @@ bool lexical_cast(const std::string &input, InterfaceMeshType & meshType) return true; } -} // end namespace wasm } // end namespace itk From df7e98da54844083bd71ce1d0abb1d8384b24b4e Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Fri, 5 Jul 2024 11:33:40 -0400 Subject: [PATCH 05/10] refactor(SupportInputPolyDataTypes): rapidjson to glaze --- include/itkSupportInputPolyDataTypes.h | 33 +++++++++--------- src/itkSupportInputPolyDataTypes.cxx | 48 ++++++++++++-------------- 2 files changed, 38 insertions(+), 43 deletions(-) diff --git a/include/itkSupportInputPolyDataTypes.h b/include/itkSupportInputPolyDataTypes.h index 409e91937..8b44172ca 100644 --- a/include/itkSupportInputPolyDataTypes.h +++ b/include/itkSupportInputPolyDataTypes.h @@ -29,20 +29,15 @@ #include "itkMeshIOFactory.h" #include "WebAssemblyInterfaceExport.h" +#include "itkPolyDataJSON.h" + namespace itk { -namespace wasm -{ +WebAssemblyInterface_EXPORT bool lexical_cast(const std::string &input, PolyDataTypeJSON & polyDataType); -struct InterfacePolyDataType +namespace wasm { - std::string componentType{"uint8"}; - std::string pixelType{"Scalar"}; - unsigned int components{1}; -}; - -WebAssemblyInterface_EXPORT bool lexical_cast(const std::string &input, InterfacePolyDataType & polyDataType); /** \class SupportInputPolyDataTypes * @@ -96,7 +91,8 @@ SupportInputPolyDataTypes static int PixelTypes(const std::string & inputPolyDataOptionName, Pipeline & pipeline) { - InterfacePolyDataType polyDataType; + PolyDataTypeJSON polyDataType; + const auto iwpArgc = pipeline.get_argc(); const auto iwpArgv = pipeline.get_argv(); bool passThrough = false; @@ -125,16 +121,18 @@ SupportInputPolyDataTypes private: template static int - IteratePixelTypes(Pipeline & pipeline, const InterfacePolyDataType & polyDataType, bool passThrough = false) + IteratePixelTypes(Pipeline & pipeline, const PolyDataTypeJSON & polyDataType, bool passThrough = false) { using PixelType = TPixel; using ConvertPixelTraits = MeshConvertPixelTraits; - if (passThrough || polyDataType.components == 0 - || polyDataType.componentType == MapComponentType::ComponentString - && polyDataType.pixelType == MapPixelType::PixelString) + const auto components = polyDataType.pointPixelComponents ? polyDataType.pointPixelComponents : polyDataType.cellPixelComponents; + + if (passThrough || components == 0 + || polyDataType.pointPixelComponentType == MapComponentType::JSONComponentEnum + && polyDataType.pointPixelType == MapPixelType::JSONPixelEnum) { - if (polyDataType.pixelType == "VariableLengthVector" || polyDataType.pixelType == "VariableSizeMatrix" ) + if (polyDataType.pointPixelType == JSONPixelTypesEnum::VariableLengthVector || polyDataType.pointPixelType == JSONPixelTypesEnum::VariableSizeMatrix) { // todo: VectorMesh support for ImportMeshFilter? // using MeshType = itk::VectorMesh; @@ -142,7 +140,7 @@ SupportInputPolyDataTypes // using PipelineType = TPipelineFunctor; // return PipelineType()(pipeline); } - else if(passThrough || polyDataType.components == ConvertPixelTraits::GetNumberOfComponents() || polyDataType.components == 0 ) + else if(passThrough || components == ConvertPixelTraits::GetNumberOfComponents() || components == 0 ) { using PolyDataType = PolyData; @@ -156,7 +154,8 @@ SupportInputPolyDataTypes } std::ostringstream ostrm; - ostrm << "Unsupported pixel type: " << polyDataType.pixelType << " with component type: " << polyDataType.componentType << " and components: " << polyDataType.components; + std::string polyDataTypeString = glz::write_json(polyDataType).value_or("error"); + ostrm << "Unsupported polyData type: " << polyDataTypeString << std::endl; CLI::Error err("Runtime error", ostrm.str(), 1); return pipeline.exit(err); } diff --git a/src/itkSupportInputPolyDataTypes.cxx b/src/itkSupportInputPolyDataTypes.cxx index 40eba58d8..bc6e371fd 100644 --- a/src/itkSupportInputPolyDataTypes.cxx +++ b/src/itkSupportInputPolyDataTypes.cxx @@ -18,35 +18,29 @@ #include "itkSupportInputPolyDataTypes.h" #include "itkWasmExports.h" -#include "rapidjson/document.h" +#include "itkjsonFromIOComponentEnum.h" +#include "itkjsonFromIOPixelEnum.h" +#include "itkMeshJSON.h" namespace itk { -namespace wasm -{ - -bool lexical_cast(const std::string &input, InterfacePolyDataType & polyDataType) +bool lexical_cast(const std::string &input, PolyDataTypeJSON & polyDataType) { if (wasm::Pipeline::get_use_memory_io()) { #ifndef ITK_WASM_NO_MEMORY_IO const unsigned int index = std::stoi(input); - auto json = getMemoryStoreInputJSON(0, index); - rapidjson::Document document; - if (document.Parse(json.c_str()).HasParseError()) - { - throw std::runtime_error("Could not parse JSON"); - } - - const rapidjson::Value & jsonPolyDataType = document["polyDataType"]; - polyDataType.componentType = jsonPolyDataType["pointPixelComponentType"].GetString(); - polyDataType.pixelType = jsonPolyDataType["pointPixelType"].GetString(); - polyDataType.components = jsonPolyDataType["pointPixelComponents"].GetInt(); - if (polyDataType.components == 0) + auto json = wasm::getMemoryStoreInputJSON(0, index); + std::string deserialized; + auto deserializedAttempt = glz::read_json(json); + if (!deserializedAttempt) { - polyDataType.components = jsonPolyDataType["cellPixelComponents"].GetInt(); + const std::string descriptiveError = glz::format_error(deserializedAttempt, json); + throw std::runtime_error("Failed to deserialize PolyDataJSON: " + descriptiveError); } + auto polyDataJSON = deserializedAttempt.value(); + polyDataType = polyDataJSON.polyDataType; #else return false; #endif @@ -65,17 +59,20 @@ bool lexical_cast(const std::string &input, InterfacePolyDataType & polyDataType using IOComponentType = itk::IOComponentEnum; const IOComponentType ioComponentEnum = meshIO->GetPointPixelComponentType(); - polyDataType.componentType = WasmComponentTypeFromIOComponentEnum( ioComponentEnum ); + const auto pointPixelIOComponentType = meshIO->GetPointPixelComponentType(); + polyDataType.pointPixelComponentType = itk::jsonComponentTypeFromIOComponentEnum( pointPixelIOComponentType ); + const auto pointIOPixelType = meshIO->GetPointPixelType(); + polyDataType.pointPixelType = itk::jsonFromIOPixelEnum( pointIOPixelType ); + polyDataType.pointPixelComponents = meshIO->GetNumberOfPointPixelComponents(); using IOPixelType = itk::IOPixelEnum; const IOPixelType ioPixelEnum = meshIO->GetPointPixelType(); - polyDataType.pixelType = WasmPixelTypeFromIOPixelEnum( ioPixelEnum ); - polyDataType.components = meshIO->GetNumberOfPointPixelComponents(); - if (polyDataType.components == 0) - { - polyDataType.components = meshIO->GetNumberOfPointPixelComponents(); - } + const auto cellPixelIOComponentType = meshIO->GetCellPixelComponentType(); + polyDataType.cellPixelComponentType = itk::jsonComponentTypeFromIOComponentEnum( cellPixelIOComponentType ); + const auto cellIOPixelType = meshIO->GetCellPixelType(); + polyDataType.cellPixelType = itk::jsonFromIOPixelEnum( cellIOPixelType ); + polyDataType.cellPixelComponents = meshIO->GetNumberOfCellPixelComponents(); #else return false; #endif @@ -83,5 +80,4 @@ bool lexical_cast(const std::string &input, InterfacePolyDataType & polyDataType return true; } -} // end namespace wasm } // end namespace itk From bf694dd6d8674e4abf5f783aec787d675e96f24f Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Fri, 5 Jul 2024 15:34:17 -0400 Subject: [PATCH 06/10] refactor(Image): rapidjson to glaze --- CMakeLists.txt | 6 +- include/itkImageJSON.h | 149 ++++ include/itkImageToWasmImageFilter.hxx | 108 +-- include/itkInputImageIO.h | 17 +- include/itkMeshJSON.h | 2 +- include/itkMetaDataDictionaryJSON.h | 16 +- include/itkWasmImageIO.h | 7 +- include/itkWasmImageToImageFilter.hxx | 90 +-- .../downsample/typescript/src/index-common.ts | 3 - .../typescript/src/index-node-only.ts | 50 -- .../downsample/typescript/src/index-only.ts | 50 -- .../test/browser/demo-app/index.html | 210 ------ src/itkMetaDataDictionaryJSON.cxx | 684 +++--------------- src/itkWasmImageIO.cxx | 195 ++--- src/itkWasmImageIOBase.cxx | 25 +- src/itkWasmMeshIO.cxx | 2 +- 16 files changed, 437 insertions(+), 1177 deletions(-) create mode 100644 include/itkImageJSON.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 7fd8f336e..b2db320a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,9 +78,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} diff --git a/include/itkImageJSON.h b/include/itkImageJSON.h new file mode 100644 index 000000000..87a63bfc9 --- /dev/null +++ b/include/itkImageJSON.h @@ -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 origin { 0.0, 0.0 }; + std::vector spacing { 1.0, 1.0 }; + std::string direction; + std::vector size { 0, 0 }; + + MetadataJSON metadata; + std::string data; + }; + +template +auto imageToImageJSON(const TImage * image, const WasmImage * 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; + using ComponentType = typename ConvertPixelTraits::ComponentType; + imageJSON.imageType.componentType = wasm::MapComponentType::JSONComponentEnum; + imageJSON.imageType.pixelType = wasm::MapPixelType::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 diff --git a/include/itkImageToWasmImageFilter.hxx b/include/itkImageToWasmImageFilter.hxx index c77400319..0071ff74d 100644 --- a/include/itkImageToWasmImageFilter.hxx +++ b/include/itkImageToWasmImageFilter.hxx @@ -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 namespace itk { @@ -133,92 +134,21 @@ ImageToWasmImageFilter { // 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; - 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::ComponentString.data(), allocator ); - imageType.AddMember("componentType", componentType.Move(), allocator ); - - rapidjson::Value pixelType; - pixelType.SetString( wasm::MapPixelType::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 writer(stringBuffer); - document.Accept(writer); - - imageJSON->SetJSON(stringBuffer.GetString()); + WasmImageType * wasmImage = this->GetOutput(); + + wasmImage->SetImage(image); + + constexpr bool inMemory = true; + const ImageJSON imageJSON = imageToImageJSON(image, wasmImage, inMemory); + std::string serialized{}; + auto ec = glz::write(imageJSON, serialized); + if (ec) + { + itkExceptionMacro("Failed to serialize ImageJSON"); + } + std::cout << "serialized: " << serialized << std::endl; + + wasmImage->SetJSON(serialized); } template diff --git a/include/itkInputImageIO.h b/include/itkInputImageIO.h index 31f75da27..3ded2bd0d 100644 --- a/include/itkInputImageIO.h +++ b/include/itkInputImageIO.h @@ -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(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) { diff --git a/include/itkMeshJSON.h b/include/itkMeshJSON.h index e305d9cc2..12772c016 100644 --- a/include/itkMeshJSON.h +++ b/include/itkMeshJSON.h @@ -60,7 +60,7 @@ namespace itk { MeshTypeJSON meshType; - std::string name { "mesh "}; + std::string name { "mesh"}; size_t numberOfPoints{ 0 }; std::string points; diff --git a/include/itkMetaDataDictionaryJSON.h b/include/itkMetaDataDictionaryJSON.h index 8c95cfbfb..25d28c545 100644 --- a/include/itkMetaDataDictionaryJSON.h +++ b/include/itkMetaDataDictionaryJSON.h @@ -24,21 +24,25 @@ #include "itkArray.h" #include "itkMatrix.h" -#include "rapidjson/document.h" +#include +#include +#include #include "WebAssemblyInterfaceExport.h" +#include "glaze/glaze.hpp" + namespace itk { -namespace wasm -{ +using MetadataEntryJSON = std::tuple; +using MetadataJSON = std::vector; + -WebAssemblyInterface_EXPORT void ConvertMetaDataDictionaryToJSON(const itk::MetaDataDictionary & dictionary, rapidjson::Value & metadataJson, rapidjson::Document::AllocatorType& allocator); +WebAssemblyInterface_EXPORT void metaDataDictionaryToJSON(const itk::MetaDataDictionary & dictionary, MetadataJSON & metadataJson); -WebAssemblyInterface_EXPORT void ConvertJSONToMetaDataDictionary(const rapidjson::Value & metadataJson, itk::MetaDataDictionary & dictionary); +WebAssemblyInterface_EXPORT void jsonToMetaDataDictionary(const MetadataJSON & metadataJson, itk::MetaDataDictionary & dictionary); -} // end namespace wasm } // end namespace itk #endif diff --git a/include/itkWasmImageIO.h b/include/itkWasmImageIO.h index e89139f8a..cb1a0309a 100644 --- a/include/itkWasmImageIO.h +++ b/include/itkWasmImageIO.h @@ -21,7 +21,8 @@ #include "itkStreamingImageIOBase.h" #include -#include "rapidjson/document.h" + +#include "itkImageJSON.h" namespace itk { @@ -71,7 +72,7 @@ class WebAssemblyInterface_EXPORT WasmImageIO: public StreamingImageIOBase #if !defined(ITK_WRAPPING_PARSER) /** Set the JSON representation of the image information. */ - void SetJSON(rapidjson::Document & json); + void SetJSON(const ImageJSON & json); #endif /** Determine the file type. Returns true if this ImageIO can write the @@ -83,7 +84,7 @@ class WebAssemblyInterface_EXPORT WasmImageIO: public StreamingImageIOBase #if !defined(ITK_WRAPPING_PARSER) /** Get the JSON representation of the image information. */ - rapidjson::Document GetJSON(); + auto GetJSON() -> ImageJSON; #endif /** Writes the data to disk from the memory buffer provided. Make sure diff --git a/include/itkWasmImageToImageFilter.hxx b/include/itkWasmImageToImageFilter.hxx index 14bbcd27b..3b5d339ba 100644 --- a/include/itkWasmImageToImageFilter.hxx +++ b/include/itkWasmImageToImageFilter.hxx @@ -28,7 +28,7 @@ #include "itkDefaultConvertPixelTraits.h" #include "itkMetaDataObject.h" -#include "rapidjson/document.h" +#include "itkImageJSON.h" namespace itk { @@ -132,8 +132,8 @@ WasmImageToImageFilter ::GenerateData() { // Get the input and output pointers - const WasmImageType * imageJSON = this->GetInput(); - const std::string json(imageJSON->GetJSON()); + const WasmImageType * wasmImage = this->GetInput(); + const std::string json(wasmImage->GetJSON()); ImageType * image = this->GetOutput(); using IOPixelType = typename TImage::IOPixelType; @@ -141,26 +141,30 @@ WasmImageToImageFilter using ConvertPixelTraits = DefaultConvertPixelTraits; constexpr unsigned int Dimension = TImage::ImageDimension; - rapidjson::Document document; - if (document.Parse(json.c_str()).HasParseError()) - { - throw std::runtime_error("Could not parse JSON"); - } + auto deserializedAttempt = glz::read_json(json); + if (!deserializedAttempt) + { + const std::string descriptiveError = glz::format_error(deserializedAttempt, json); + itkExceptionMacro("Failed to deserialize imageJSON: " << descriptiveError); + } + auto imageJSON = deserializedAttempt.value(); + + const auto dimension = imageJSON.imageType.dimension; + const auto componentType = imageJSON.imageType.componentType; + const auto pixelType = imageJSON.imageType.pixelType; + const auto components = imageJSON.imageType.components; - const rapidjson::Value & imageType = document["imageType"]; - const int dimension = imageType["dimension"].GetInt(); if (dimension != Dimension) { throw std::runtime_error("Unexpected dimension"); } - const std::string componentType( imageType["componentType"].GetString() ); - if ( componentType != itk::wasm::MapComponentType::ComponentString ) + + if ( componentType != itk::wasm::MapComponentType::JSONComponentEnum ) { throw std::runtime_error("Unexpected component type"); } - const std::string pixelType( imageType["pixelType"].GetString() ); - if ( pixelType != itk::wasm::MapPixelType::PixelString ) + if ( pixelType != itk::wasm::MapPixelType::JSONPixelEnum ) { throw std::runtime_error("Unexpected pixel type"); } @@ -169,36 +173,29 @@ WasmImageToImageFilter auto filter = FilterType::New(); // Don't throw when PixelType is VariableLengthPixel where number of components is 0 - if (ConvertPixelTraits::GetNumberOfComponents() != 0 && imageType["components"].GetInt() != ConvertPixelTraits::GetNumberOfComponents() ) + if (ConvertPixelTraits::GetNumberOfComponents() != 0 && components != ConvertPixelTraits::GetNumberOfComponents() ) { throw std::runtime_error("Unexpected number of components"); } using OriginType = typename ImageType::PointType; OriginType origin; - const rapidjson::Value & originJson = document["origin"]; - int count = 0; - for( rapidjson::Value::ConstValueIterator itr = originJson.Begin(); itr != originJson.End(); ++itr ) - { - origin[count] = itr->GetDouble(); - ++count; - } + for (unsigned int i = 0; i < Dimension; ++i) + { + origin[i] = imageJSON.origin[i]; + } filter->SetOrigin( origin ); using SpacingType = typename ImageType::SpacingType; SpacingType spacing; - const rapidjson::Value & spacingJson = document["spacing"]; - count = 0; - for( rapidjson::Value::ConstValueIterator itr = spacingJson.Begin(); itr != spacingJson.End(); ++itr ) - { - spacing[count] = itr->GetDouble(); - ++count; - } + for (unsigned int i = 0; i < Dimension; ++i) + { + spacing[i] = imageJSON.spacing[i]; + } filter->SetSpacing( spacing ); using DirectionType = typename ImageType::DirectionType; - 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) ); using VnlMatrixType = typename DirectionType::InternalMatrixType; const VnlMatrixType vnlMatrix(directionPtr); @@ -207,42 +204,33 @@ WasmImageToImageFilter using SizeType = typename ImageType::SizeType; SizeType size; - const rapidjson::Value & sizeJson = document["size"]; - count = 0; SizeValueType totalSize = 1; - for( rapidjson::Value::ConstValueIterator itr = sizeJson.Begin(); itr != sizeJson.End(); ++itr ) - { - size[count] = itr->GetInt(); - totalSize *= size[count]; - ++count; - } + for (unsigned int i = 0; i < Dimension; ++i) + { + size[i] = imageJSON.size[i]; + totalSize *= size[i]; + } using RegionType = typename ImageType::RegionType; RegionType region; region.SetSize( size ); filter->SetRegion( region ); - const rapidjson::Value & dataJson = document["data"]; - const std::string dataString( dataJson.GetString() ); + const std::string dataString = imageJSON.data; IOPixelType * dataPtr = reinterpret_cast< IOPixelType * >( std::strtoull(dataString.substr(35).c_str(), nullptr, 10) ); const bool letImageContainerManageMemory = false; - if (pixelType == "VariableLengthVector" || pixelType == "VariableSizeMatrix") + if (pixelType == JSONPixelTypesEnum::VariableLengthVector || pixelType == JSONPixelTypesEnum::VariableSizeMatrix) { - filter->SetImportPointer( dataPtr, totalSize, letImageContainerManageMemory, imageType["components"].GetInt()); + filter->SetImportPointer(dataPtr, totalSize, letImageContainerManageMemory, components); } else { - filter->SetImportPointer( dataPtr, totalSize, letImageContainerManageMemory); + filter->SetImportPointer(dataPtr, totalSize, letImageContainerManageMemory); } filter->Update(); image->Graft(filter->GetOutput()); - if (document.HasMember("metadata")) - { - auto dictionary = image->GetMetaDataDictionary(); - const rapidjson::Value & metadataJson = document["metadata"]; - wasm::ConvertJSONToMetaDataDictionary(metadataJson, dictionary); - } - + auto dictionary = image->GetMetaDataDictionary(); + jsonToMetaDataDictionary(imageJSON.metadata, dictionary); } template diff --git a/packages/downsample/typescript/src/index-common.ts b/packages/downsample/typescript/src/index-common.ts index 5ae149f04..110f91ce9 100644 --- a/packages/downsample/typescript/src/index-common.ts +++ b/packages/downsample/typescript/src/index-common.ts @@ -1,6 +1,3 @@ // Generated file. To retain edits, remove this comment. export { default as version } from './version.js' - -export type { Image } from 'itk-wasm' -export type { JsonCompatible } from 'itk-wasm' diff --git a/packages/downsample/typescript/src/index-node-only.ts b/packages/downsample/typescript/src/index-node-only.ts index 1eb99854e..58cd9d3a7 100644 --- a/packages/downsample/typescript/src/index-node-only.ts +++ b/packages/downsample/typescript/src/index-node-only.ts @@ -1,52 +1,2 @@ // Generated file. To retain edits, remove this comment. - - -import DownsampleBinShrinkNodeResult from './downsample-bin-shrink-node-result.js' -export type { DownsampleBinShrinkNodeResult } - -import DownsampleBinShrinkNodeOptions from './downsample-bin-shrink-node-options.js' -export type { DownsampleBinShrinkNodeOptions } - -import downsampleBinShrinkNode from './downsample-bin-shrink-node.js' -export { downsampleBinShrinkNode } - - -import DownsampleLabelImageNodeResult from './downsample-label-image-node-result.js' -export type { DownsampleLabelImageNodeResult } - -import DownsampleLabelImageNodeOptions from './downsample-label-image-node-options.js' -export type { DownsampleLabelImageNodeOptions } - -import downsampleLabelImageNode from './downsample-label-image-node.js' -export { downsampleLabelImageNode } - - -import DownsampleSigmaNodeResult from './downsample-sigma-node-result.js' -export type { DownsampleSigmaNodeResult } - -import DownsampleSigmaNodeOptions from './downsample-sigma-node-options.js' -export type { DownsampleSigmaNodeOptions } - -import downsampleSigmaNode from './downsample-sigma-node.js' -export { downsampleSigmaNode } - - -import DownsampleNodeResult from './downsample-node-result.js' -export type { DownsampleNodeResult } - -import DownsampleNodeOptions from './downsample-node-options.js' -export type { DownsampleNodeOptions } - -import downsampleNode from './downsample-node.js' -export { downsampleNode } - - -import GaussianKernelRadiusNodeResult from './gaussian-kernel-radius-node-result.js' -export type { GaussianKernelRadiusNodeResult } - -import GaussianKernelRadiusNodeOptions from './gaussian-kernel-radius-node-options.js' -export type { GaussianKernelRadiusNodeOptions } - -import gaussianKernelRadiusNode from './gaussian-kernel-radius-node.js' -export { gaussianKernelRadiusNode } diff --git a/packages/downsample/typescript/src/index-only.ts b/packages/downsample/typescript/src/index-only.ts index 5e90078b2..8d37a213e 100644 --- a/packages/downsample/typescript/src/index-only.ts +++ b/packages/downsample/typescript/src/index-only.ts @@ -3,53 +3,3 @@ export * from './pipelines-base-url.js' export * from './pipeline-worker-url.js' export * from './default-web-worker.js' - - -import DownsampleBinShrinkResult from './downsample-bin-shrink-result.js' -export type { DownsampleBinShrinkResult } - -import DownsampleBinShrinkOptions from './downsample-bin-shrink-options.js' -export type { DownsampleBinShrinkOptions } - -import downsampleBinShrink from './downsample-bin-shrink.js' -export { downsampleBinShrink } - - -import DownsampleLabelImageResult from './downsample-label-image-result.js' -export type { DownsampleLabelImageResult } - -import DownsampleLabelImageOptions from './downsample-label-image-options.js' -export type { DownsampleLabelImageOptions } - -import downsampleLabelImage from './downsample-label-image.js' -export { downsampleLabelImage } - - -import DownsampleSigmaResult from './downsample-sigma-result.js' -export type { DownsampleSigmaResult } - -import DownsampleSigmaOptions from './downsample-sigma-options.js' -export type { DownsampleSigmaOptions } - -import downsampleSigma from './downsample-sigma.js' -export { downsampleSigma } - - -import DownsampleResult from './downsample-result.js' -export type { DownsampleResult } - -import DownsampleOptions from './downsample-options.js' -export type { DownsampleOptions } - -import downsample from './downsample.js' -export { downsample } - - -import GaussianKernelRadiusResult from './gaussian-kernel-radius-result.js' -export type { GaussianKernelRadiusResult } - -import GaussianKernelRadiusOptions from './gaussian-kernel-radius-options.js' -export type { GaussianKernelRadiusOptions } - -import gaussianKernelRadius from './gaussian-kernel-radius.js' -export { gaussianKernelRadius } diff --git a/packages/downsample/typescript/test/browser/demo-app/index.html b/packages/downsample/typescript/test/browser/demo-app/index.html index e5a57602c..fccdf835a 100644 --- a/packages/downsample/typescript/test/browser/demo-app/index.html +++ b/packages/downsample/typescript/test/browser/demo-app/index.html @@ -30,216 +30,6 @@

👨‍💻 Live API Demo ✨



- downsampleBinShrink - downsampleLabelImage - downsampleSigma - downsample - gaussianKernelRadius - - - - - Apply local averaging and subsample the input image.

- -
- - -

- -
- informationOnly - Generate output image information only. Do not process pixels. -

- -
Load sample inputs - Run

- -
- - -
- - - bmp - dcm - gipl - hdf5 - jpg - lsm - mnc - mnc.gz - mgh - mha - mrc - nii - nii.gz - png - nrrd - png - pic - tif - isq - fdf - vtk - - Download -

-
- -
- - - - - Subsample the input label image a according to weighted voting of local labels.

- -
- - -

- -
- -
- -
Load sample inputs - Run

- -
- - -
- - - bmp - dcm - gipl - hdf5 - jpg - lsm - mnc - mnc.gz - mgh - mha - mrc - nii - nii.gz - png - nrrd - png - pic - tif - isq - fdf - vtk - - Download -

-
- -
- - - - - Compute gaussian kernel sigma values in pixel units for downsampling.

- -
- -
- -
Load sample inputs - Run

- -
- - -
- - Download -

-
- -
- - - - - Apply a smoothing anti-alias filter and subsample the input image.

- -
- - -

- -
- -
- -
Load sample inputs - Run

- -
- - -
- - - bmp - dcm - gipl - hdf5 - jpg - lsm - mnc - mnc.gz - mgh - mha - mrc - nii - nii.gz - png - nrrd - png - pic - tif - isq - fdf - vtk - - Download -

-
- -
- - - - - Radius in pixels required for effective discrete gaussian filtering.

- -
- -
- -
- -
- -
- -
Load sample inputs - Run

- -
- - -
- - Download -

-
- -
diff --git a/src/itkMetaDataDictionaryJSON.cxx b/src/itkMetaDataDictionaryJSON.cxx index ebd3cb65a..a997c55bd 100644 --- a/src/itkMetaDataDictionaryJSON.cxx +++ b/src/itkMetaDataDictionaryJSON.cxx @@ -20,36 +20,21 @@ namespace itk { -namespace wasm +void +metaDataDictionaryToJSON(const itk::MetaDataDictionary & dictionary, MetadataJSON & metaDataJSON) { + metaDataJSON.clear(); -void ConvertMetaDataDictionaryToJSON(const itk::MetaDataDictionary & dictionary, rapidjson::Value & metadataJson, rapidjson::Document::AllocatorType& allocator) -{ auto itr = dictionary.Begin(); auto end = dictionary.End(); while (itr != end) { - // rapidjson types + // glaze types using MetaDataBoolType = MetaDataObject; - using MetaDataIntType = MetaDataObject; - using MetaDataUintType = MetaDataObject; - using MetaDataInt64Type = MetaDataObject; - using MetaDataUint64Type = MetaDataObject; - using MetaDataFloatType = MetaDataObject; using MetaDataDoubleType = MetaDataObject; using MetaDataStringType = MetaDataObject; - using MetaDataVectorIntType = MetaDataObject>; - using MetaDataVectorUintType = MetaDataObject>; - using MetaDataVectorInt64Type = MetaDataObject>; - using MetaDataVectorUint64Type = MetaDataObject>; - using MetaDataVectorFloatType = MetaDataObject>; using MetaDataVectorDoubleType = MetaDataObject>; using MetaDataVectorStringType = MetaDataObject>; - using MetaDataVectorVectorIntType = MetaDataObject>>; - using MetaDataVectorVectorUintType = MetaDataObject>>; - using MetaDataVectorVectorInt64Type = MetaDataObject>>; - using MetaDataVectorVectorUint64Type = MetaDataObject>>; - using MetaDataVectorVectorFloatType = MetaDataObject>>; using MetaDataVectorVectorDoubleType = MetaDataObject>>; // Additional ITK used MetaDataDictionary types @@ -71,52 +56,13 @@ void ConvertMetaDataDictionaryToJSON(const itk::MetaDataDictionary & dictionary, using MetaDataMatrixDoubleType = MetaDataObject>; MetaDataObjectBase::Pointer entry = itr->second; - rapidjson::Value entryJson(rapidjson::kArrayType); const std::string key = itr->first; - entryJson.PushBack(rapidjson::Value().SetString(key.c_str(), allocator), allocator); const auto boolValue = dynamic_cast(entry.GetPointer()); if (boolValue) { const bool value = boolValue->GetMetaDataObjectValue(); - entryJson.PushBack(rapidjson::Value().SetBool(value), allocator); - metadataJson.PushBack(entryJson, allocator); - ++itr; - continue; - } - const auto intValue = dynamic_cast(entry.GetPointer()); - if (intValue) - { - const int value = intValue->GetMetaDataObjectValue(); - entryJson.PushBack(rapidjson::Value().SetInt(value), allocator); - metadataJson.PushBack(entryJson, allocator); - ++itr; - continue; - } - const auto uintValue = dynamic_cast(entry.GetPointer()); - if (uintValue) - { - const unsigned int value = uintValue->GetMetaDataObjectValue(); - entryJson.PushBack(rapidjson::Value().SetUint(value), allocator); - metadataJson.PushBack(entryJson, allocator); - ++itr; - continue; - } - const auto int64Value = dynamic_cast(entry.GetPointer()); - if (int64Value) - { - const int64_t value = int64Value->GetMetaDataObjectValue(); - entryJson.PushBack(rapidjson::Value().SetInt64(value), allocator); - metadataJson.PushBack(entryJson, allocator); - ++itr; - continue; - } - const auto uint64Value = dynamic_cast(entry.GetPointer()); - if (uint64Value) - { - const uint64_t value = uint64Value->GetMetaDataObjectValue(); - entryJson.PushBack(rapidjson::Value().SetUint64(value), allocator); - metadataJson.PushBack(entryJson, allocator); + metaDataJSON.push_back({ key, value }); ++itr; continue; } @@ -124,17 +70,7 @@ void ConvertMetaDataDictionaryToJSON(const itk::MetaDataDictionary & dictionary, if (doubleValue) { const double value = doubleValue->GetMetaDataObjectValue(); - entryJson.PushBack(rapidjson::Value().SetDouble(value), allocator); - metadataJson.PushBack(entryJson, allocator); - ++itr; - continue; - } - const auto floatValue = dynamic_cast(entry.GetPointer()); - if (floatValue) - { - const float value = floatValue->GetMetaDataObjectValue(); - entryJson.PushBack(rapidjson::Value().SetFloat(value), allocator); - metadataJson.PushBack(entryJson, allocator); + metaDataJSON.push_back({ key, value }); ++itr; continue; } @@ -142,93 +78,17 @@ void ConvertMetaDataDictionaryToJSON(const itk::MetaDataDictionary & dictionary, if (stringValue) { const std::string value = stringValue->GetMetaDataObjectValue(); - entryJson.PushBack(rapidjson::Value().SetString(value.c_str(), allocator), allocator); - metadataJson.PushBack(entryJson, allocator); + metaDataJSON.push_back({ key, value }); ++itr; continue; } - const auto intVectorValue = dynamic_cast(entry.GetPointer()); - if (intVectorValue) - { - const std::vector value = intVectorValue->GetMetaDataObjectValue(); - rapidjson::Value valueJson(rapidjson::kArrayType); - for(auto vv: value) - { - valueJson.PushBack(rapidjson::Value().SetInt(vv), allocator); - } - entryJson.PushBack(valueJson, allocator); - metadataJson.PushBack(entryJson, allocator); - ++itr; - continue; - } - const auto uintVectorValue = dynamic_cast(entry.GetPointer()); - if (uintVectorValue) - { - const std::vector value = uintVectorValue->GetMetaDataObjectValue(); - rapidjson::Value valueJson(rapidjson::kArrayType); - for(auto vv: value) - { - valueJson.PushBack(rapidjson::Value().SetUint(vv), allocator); - } - entryJson.PushBack(valueJson, allocator); - metadataJson.PushBack(entryJson, allocator); - ++itr; - continue; - } - const auto int64VectorValue = dynamic_cast(entry.GetPointer()); - if (int64VectorValue) - { - const std::vector value = int64VectorValue->GetMetaDataObjectValue(); - rapidjson::Value valueJson(rapidjson::kArrayType); - for(auto vv: value) - { - valueJson.PushBack(rapidjson::Value().SetInt64(vv), allocator); - } - entryJson.PushBack(valueJson, allocator); - metadataJson.PushBack(entryJson, allocator); - ++itr; - continue; - } - const auto uint64VectorValue = dynamic_cast(entry.GetPointer()); - if (uint64VectorValue) - { - const std::vector value = uint64VectorValue->GetMetaDataObjectValue(); - rapidjson::Value valueJson(rapidjson::kArrayType); - for(auto vv: value) - { - valueJson.PushBack(rapidjson::Value().SetUint64(vv), allocator); - } - entryJson.PushBack(valueJson, allocator); - metadataJson.PushBack(entryJson, allocator); - ++itr; - continue; - } const auto doubleVectorValue = dynamic_cast(entry.GetPointer()); if (doubleVectorValue) { const std::vector value = doubleVectorValue->GetMetaDataObjectValue(); - rapidjson::Value valueJson(rapidjson::kArrayType); - for(auto vv: value) - { - valueJson.PushBack(rapidjson::Value().SetDouble(vv), allocator); - } - entryJson.PushBack(valueJson, allocator); - metadataJson.PushBack(entryJson, allocator); - ++itr; - continue; - } - const auto floatVectorValue = dynamic_cast(entry.GetPointer()); - if (floatVectorValue) - { - const std::vector value = floatVectorValue->GetMetaDataObjectValue(); - rapidjson::Value valueJson(rapidjson::kArrayType); - for(auto vv: value) - { - valueJson.PushBack(rapidjson::Value().SetFloat(vv), allocator); - } - entryJson.PushBack(valueJson, allocator); - metadataJson.PushBack(entryJson, allocator); + const glz::json_t::array_t valueDouble(value.begin(), value.end()); + metaDataJSON.push_back({ key, valueDouble }); ++itr; continue; } @@ -236,146 +96,22 @@ void ConvertMetaDataDictionaryToJSON(const itk::MetaDataDictionary & dictionary, if (stringVectorValue) { const std::vector value = stringVectorValue->GetMetaDataObjectValue(); - rapidjson::Value valueJson(rapidjson::kArrayType); - for(auto vv: value) - { - valueJson.PushBack(rapidjson::Value().SetString(vv.c_str(), allocator), allocator); - } - entryJson.PushBack(valueJson, allocator); - metadataJson.PushBack(entryJson, allocator); + const glz::json_t::array_t valueString(value.begin(), value.end()); + metaDataJSON.push_back({ key, valueString }); ++itr; continue; } - const auto intVectorVectorValue = dynamic_cast(entry.GetPointer()); - if (intVectorVectorValue) - { - const std::vector> value = intVectorVectorValue->GetMetaDataObjectValue(); - rapidjson::Value valueJson(rapidjson::kArrayType); - for(auto aa: value) - { - rapidjson::Value vvJson(rapidjson::kArrayType); - for(auto vv: value) - { - for(auto uu: vv) - { - vvJson.PushBack(rapidjson::Value().SetInt(uu), allocator); - } - } - valueJson.PushBack(vvJson, allocator); - } - entryJson.PushBack(valueJson, allocator); - metadataJson.PushBack(entryJson, allocator); - ++itr; - continue; - } - const auto uintVectorVectorValue = dynamic_cast(entry.GetPointer()); - if (uintVectorVectorValue) - { - const std::vector> value = uintVectorVectorValue->GetMetaDataObjectValue(); - rapidjson::Value valueJson(rapidjson::kArrayType); - for(auto aa: value) - { - rapidjson::Value vvJson(rapidjson::kArrayType); - for(auto vv: value) - { - for(auto uu: vv) - { - vvJson.PushBack(rapidjson::Value().SetUint(uu), allocator); - } - } - valueJson.PushBack(vvJson, allocator); - } - entryJson.PushBack(valueJson, allocator); - metadataJson.PushBack(entryJson, allocator); - ++itr; - continue; - } - const auto int64VectorVectorValue = dynamic_cast(entry.GetPointer()); - if (int64VectorVectorValue) - { - const std::vector> value = int64VectorVectorValue->GetMetaDataObjectValue(); - rapidjson::Value valueJson(rapidjson::kArrayType); - for(auto aa: value) - { - rapidjson::Value vvJson(rapidjson::kArrayType); - for(auto vv: value) - { - for(auto uu: vv) - { - vvJson.PushBack(rapidjson::Value().SetInt64(uu), allocator); - } - } - valueJson.PushBack(vvJson, allocator); - } - entryJson.PushBack(valueJson, allocator); - metadataJson.PushBack(entryJson, allocator); - ++itr; - continue; - } - const auto uint64VectorVectorValue = dynamic_cast(entry.GetPointer()); - if (int64VectorVectorValue) - { - const std::vector> value = uint64VectorVectorValue->GetMetaDataObjectValue(); - rapidjson::Value valueJson(rapidjson::kArrayType); - for(auto aa: value) - { - rapidjson::Value vvJson(rapidjson::kArrayType); - for(auto vv: value) - { - for(auto uu: vv) - { - vvJson.PushBack(rapidjson::Value().SetUint64(uu), allocator); - } - } - valueJson.PushBack(vvJson, allocator); - } - entryJson.PushBack(valueJson, allocator); - metadataJson.PushBack(entryJson, allocator); - ++itr; - continue; - } const auto doubleVectorVectorValue = dynamic_cast(entry.GetPointer()); if (doubleVectorVectorValue) { const std::vector> value = doubleVectorVectorValue->GetMetaDataObjectValue(); - rapidjson::Value valueJson(rapidjson::kArrayType); - for(auto aa: value) + glz::json_t::array_t valueDouble; + for (const auto & v : value) { - rapidjson::Value vvJson(rapidjson::kArrayType); - for(auto vv: value) - { - for(auto uu: vv) - { - vvJson.PushBack(rapidjson::Value().SetDouble(uu), allocator); - } - } - valueJson.PushBack(vvJson, allocator); + valueDouble.push_back(glz::json_t::array_t(v.begin(), v.end())); } - entryJson.PushBack(valueJson, allocator); - metadataJson.PushBack(entryJson, allocator); - ++itr; - continue; - } - const auto floatVectorVectorValue = dynamic_cast(entry.GetPointer()); - if (floatVectorVectorValue) - { - const std::vector> value = floatVectorVectorValue->GetMetaDataObjectValue(); - rapidjson::Value valueJson(rapidjson::kArrayType); - for(auto aa: value) - { - rapidjson::Value vvJson(rapidjson::kArrayType); - for(auto vv: value) - { - for(auto uu: vv) - { - vvJson.PushBack(rapidjson::Value().SetFloat(uu), allocator); - } - } - valueJson.PushBack(vvJson, allocator); - } - entryJson.PushBack(valueJson, allocator); - metadataJson.PushBack(entryJson, allocator); + metaDataJSON.push_back({ key, valueDouble }); ++itr; continue; } @@ -384,8 +120,7 @@ void ConvertMetaDataDictionaryToJSON(const itk::MetaDataDictionary & dictionary, if (ucharValue) { const unsigned char value = ucharValue->GetMetaDataObjectValue(); - entryJson.PushBack(rapidjson::Value().SetUint(value), allocator); - metadataJson.PushBack(entryJson, allocator); + metaDataJSON.push_back({ key, static_cast(value) }); ++itr; continue; } @@ -393,8 +128,7 @@ void ConvertMetaDataDictionaryToJSON(const itk::MetaDataDictionary & dictionary, if (charValue) { const char value = charValue->GetMetaDataObjectValue(); - entryJson.PushBack(rapidjson::Value().SetInt(value), allocator); - metadataJson.PushBack(entryJson, allocator); + metaDataJSON.push_back({ key, static_cast(value) }); ++itr; continue; } @@ -402,8 +136,7 @@ void ConvertMetaDataDictionaryToJSON(const itk::MetaDataDictionary & dictionary, if (signedCharValue) { const signed char value = signedCharValue->GetMetaDataObjectValue(); - entryJson.PushBack(rapidjson::Value().SetInt(value), allocator); - metadataJson.PushBack(entryJson, allocator); + metaDataJSON.push_back({ key, static_cast(value) }); ++itr; continue; } @@ -411,8 +144,7 @@ void ConvertMetaDataDictionaryToJSON(const itk::MetaDataDictionary & dictionary, if (ushortValue) { const unsigned short value = ushortValue->GetMetaDataObjectValue(); - entryJson.PushBack(rapidjson::Value().SetUint(value), allocator); - metadataJson.PushBack(entryJson, allocator); + metaDataJSON.push_back({ key, static_cast(value) }); ++itr; continue; } @@ -420,8 +152,7 @@ void ConvertMetaDataDictionaryToJSON(const itk::MetaDataDictionary & dictionary, if (shortValue) { const short value = shortValue->GetMetaDataObjectValue(); - entryJson.PushBack(rapidjson::Value().SetInt(value), allocator); - metadataJson.PushBack(entryJson, allocator); + metaDataJSON.push_back({ key, static_cast(value) }); ++itr; continue; } @@ -429,8 +160,7 @@ void ConvertMetaDataDictionaryToJSON(const itk::MetaDataDictionary & dictionary, if (ulongValue) { const unsigned long value = ulongValue->GetMetaDataObjectValue(); - entryJson.PushBack(rapidjson::Value().SetUint64(value), allocator); - metadataJson.PushBack(entryJson, allocator); + metaDataJSON.push_back({ key, static_cast(value) }); ++itr; continue; } @@ -438,8 +168,7 @@ void ConvertMetaDataDictionaryToJSON(const itk::MetaDataDictionary & dictionary, if (longValue) { const long value = longValue->GetMetaDataObjectValue(); - entryJson.PushBack(rapidjson::Value().SetInt64(value), allocator); - metadataJson.PushBack(entryJson, allocator); + metaDataJSON.push_back({ key, static_cast(value) }); ++itr; continue; } @@ -447,8 +176,7 @@ void ConvertMetaDataDictionaryToJSON(const itk::MetaDataDictionary & dictionary, if (ulongLongValue) { const unsigned long long value = ulongLongValue->GetMetaDataObjectValue(); - entryJson.PushBack(rapidjson::Value().SetUint64(value), allocator); - metadataJson.PushBack(entryJson, allocator); + metaDataJSON.push_back({ key, static_cast(value) }); ++itr; continue; } @@ -456,350 +184,160 @@ void ConvertMetaDataDictionaryToJSON(const itk::MetaDataDictionary & dictionary, if (longLongValue) { const long long value = longLongValue->GetMetaDataObjectValue(); - entryJson.PushBack(rapidjson::Value().SetInt64(value), allocator); - metadataJson.PushBack(entryJson, allocator); + metaDataJSON.push_back({ key, static_cast(value) }); ++itr; continue; } const auto arrayCharValue = dynamic_cast(entry.GetPointer()); if (arrayCharValue) { - const Array value = arrayCharValue->GetMetaDataObjectValue(); - rapidjson::Value valueJson(rapidjson::kArrayType); - for(auto vv: value) - { - valueJson.PushBack(rapidjson::Value().SetInt(vv), allocator); - } - entryJson.PushBack(valueJson, allocator); - metadataJson.PushBack(entryJson, allocator); + const Array valueArray = arrayCharValue->GetMetaDataObjectValue(); + const glz::json_t::array_t valueDouble(valueArray.begin(), valueArray.end()); + metaDataJSON.push_back({ key, valueDouble }); ++itr; continue; } const auto arrayFloatValue = dynamic_cast(entry.GetPointer()); if (arrayFloatValue) { - const Array value = arrayFloatValue->GetMetaDataObjectValue(); - rapidjson::Value valueJson(rapidjson::kArrayType); - for(auto vv: value) - { - valueJson.PushBack(rapidjson::Value().SetFloat(vv), allocator); - } - entryJson.PushBack(valueJson, allocator); - metadataJson.PushBack(entryJson, allocator); + const Array valueArray = arrayFloatValue->GetMetaDataObjectValue(); + const glz::json_t::array_t valueDouble(valueArray.begin(), valueArray.end()); + metaDataJSON.push_back({ key, valueDouble }); ++itr; continue; } const auto arrayDoubleValue = dynamic_cast(entry.GetPointer()); if (arrayDoubleValue) { - const Array value = arrayDoubleValue->GetMetaDataObjectValue(); - rapidjson::Value valueJson(rapidjson::kArrayType); - for(auto vv: value) - { - valueJson.PushBack(rapidjson::Value().SetDouble(vv), allocator); - } - entryJson.PushBack(valueJson, allocator); - metadataJson.PushBack(entryJson, allocator); + const Array valueArray = arrayDoubleValue->GetMetaDataObjectValue(); + const glz::json_t::array_t valueDouble(valueArray.begin(), valueArray.end()); + metaDataJSON.push_back({ key, valueDouble }); ++itr; continue; } const auto matrixFloat44Value = dynamic_cast(entry.GetPointer()); if (matrixFloat44Value) { - const Matrix value = matrixFloat44Value->GetMetaDataObjectValue(); - rapidjson::Value valueJson(rapidjson::kArrayType); - for(unsigned int ii = 0; ii < 4; ii++) + const Matrix valueArray = matrixFloat44Value->GetMetaDataObjectValue(); + glz::json_t::array_t valueDouble; + for (unsigned int i = 0; i < 4; ++i) { - rapidjson::Value vvJson(rapidjson::kArrayType); - for(unsigned int jj = 0; jj < 4; jj++) - { - vvJson.PushBack(rapidjson::Value().SetFloat(value(ii, jj)), allocator); - } - valueJson.PushBack(vvJson, allocator); + valueDouble.push_back(glz::json_t::array_t(valueArray[i], valueArray[i] + 4)); } - entryJson.PushBack(valueJson, allocator); - metadataJson.PushBack(entryJson, allocator); + metaDataJSON.push_back({ key, valueDouble }); ++itr; continue; } const auto matrixDoubleValue = dynamic_cast(entry.GetPointer()); if (matrixDoubleValue) { - const Matrix value = matrixDoubleValue->GetMetaDataObjectValue(); - rapidjson::Value valueJson(rapidjson::kArrayType); - for(unsigned int ii = 0; ii < 3; ii++) + const Matrix valueArray = matrixDoubleValue->GetMetaDataObjectValue(); + glz::json_t::array_t valueDouble; + for (unsigned int i = 0; i < 3; ++i) { - rapidjson::Value vvJson(rapidjson::kArrayType); - for(unsigned int jj = 0; jj < 3; jj++) - { - vvJson.PushBack(rapidjson::Value().SetDouble(value(ii, jj)), allocator); - } - valueJson.PushBack(vvJson, allocator); + valueDouble.push_back(glz::json_t::array_t(valueArray[i], valueArray[i] + 3)); } - entryJson.PushBack(valueJson, allocator); - metadataJson.PushBack(entryJson, allocator); + metaDataJSON.push_back({ key, valueDouble }); ++itr; continue; } - ++itr; } - } -void ConvertJSONToMetaDataDictionary(const rapidjson::Value & metadataJson, itk::MetaDataDictionary & dictionary) +void +jsonToMetaDataDictionary(const MetadataJSON & metaDataJSON, itk::MetaDataDictionary & dictionary) { - if (metadataJson.IsArray()) + dictionary.Clear(); + + for (const auto metaDataEntry : metaDataJSON) { - for(rapidjson::SizeType ii = 0; ii < metadataJson.Size(); ++ii) + const std::string & key = std::get<0>(metaDataEntry); + const glz::json_t & value = std::get<1>(metaDataEntry); + + if (value.is_boolean()) + { + EncapsulateMetaData(dictionary, key, value.get_boolean()); + } + else if (value.is_number()) + { + EncapsulateMetaData(dictionary, key, value.get_number()); + } + else if (value.is_string()) + { + EncapsulateMetaData(dictionary, key, value.get_string()); + } + else if (value.is_array()) + { + if (value.size() > 0) { - const rapidjson::Value & entry = metadataJson[ii]; - const auto key = entry[0].GetString(); - std::cout << "Read key: " << key << std::endl; - const rapidjson::Value & value = entry[1]; - if (value.IsBool()) - { - EncapsulateMetaData(dictionary, key, value.GetBool()); - } - else if (value.IsInt()) - { - EncapsulateMetaData(dictionary, key, value.GetInt()); - } - else if (value.IsUint()) - { - EncapsulateMetaData(dictionary, key, value.GetUint()); - } - else if (value.IsInt64()) - { - EncapsulateMetaData(dictionary, key, value.GetInt64()); - } - else if (value.IsUint64()) + if (value[0].is_number()) { - EncapsulateMetaData(dictionary, key, value.GetUint64()); - } - else if (value.IsDouble()) - { - EncapsulateMetaData(dictionary, key, value.GetDouble()); - } - else if (value.IsFloat()) - { - EncapsulateMetaData(dictionary, key, value.GetFloat()); - } - else if (value.IsString()) - { - std::cout << "encapsulating: " << key << " , " << value.GetString() << std::endl; - EncapsulateMetaData(dictionary, key, value.GetString()); + std::vector valueDouble; + for (const auto & v : value.get_array()) + { + valueDouble.push_back(v.get_number()); + } + EncapsulateMetaData>(dictionary, key, valueDouble); } - else if (value.IsArray()) - { - if (value.Size() == 0) + else if (value[0].is_string()) { - using ValueType = std::vector; - ValueType val; - EncapsulateMetaData(dictionary, key, val); - continue; - } - if (value[0].IsString()) + std::vector valueString; + for (const auto & v : value.get_array()) { - using ValueType = std::vector; - ValueType val; - for(rapidjson::SizeType jj = 0; jj < value.Size(); ++jj) - { - val.push_back(value[jj].GetString()); - } - EncapsulateMetaData(dictionary, key, val); + valueString.push_back(v.get_string()); } - else if (value[0].IsNumber()) + EncapsulateMetaData>(dictionary, key, valueString); + } + else if (value[0].is_array()) + { + if (value[0].size() > 0) { - if (value[0].IsArray()) + if (value[0][0].is_number()) { - if (value[0].Size() == 0 || value[0][0].IsString()) + std::vector> valueDouble; + for (const auto & v : value.get_array()) { - using ValueType = std::vector>; - ValueType val; - for(rapidjson::SizeType jj = 0; jj < value[jj].Size(); ++jj) + std::vector valueDoubleInner; + for (const auto & vv : v.get_array()) { - std::vector ve; - for(rapidjson::SizeType kk = 0; kk < value[jj][kk].Size(); ++kk) - { - ve.push_back(value[jj][kk].GetString()); - } - val.push_back(ve); - } - EncapsulateMetaData(dictionary, key, val); - } - else if (value[0][0].IsNumber()) - { - if (value.IsInt()) - { - using ValueType = std::vector>; - ValueType val; - for(rapidjson::SizeType jj = 0; jj < value[jj].Size(); ++jj) - { - std::vector ve; - for(rapidjson::SizeType kk = 0; kk < value[jj][kk].Size(); ++kk) - { - ve.push_back(value[jj][kk].GetInt()); - } - val.push_back(ve); - } - EncapsulateMetaData(dictionary, key, val); - } - else if (value.IsUint()) - { - using ValueType = std::vector>; - ValueType val; - for(rapidjson::SizeType jj = 0; jj < value[jj].Size(); ++jj) - { - std::vector ve; - for(rapidjson::SizeType kk = 0; kk < value[jj][kk].Size(); ++kk) - { - ve.push_back(value[jj][kk].GetUint()); - } - val.push_back(ve); - } - EncapsulateMetaData(dictionary, key, val); - } - else if (value.IsInt64()) - { - using ValueType = std::vector>; - ValueType val; - for(rapidjson::SizeType jj = 0; jj < value[jj].Size(); ++jj) - { - std::vector ve; - for(rapidjson::SizeType kk = 0; kk < value[jj][kk].Size(); ++kk) - { - ve.push_back(value[jj][kk].GetInt64()); - } - val.push_back(ve); - } - EncapsulateMetaData(dictionary, key, val); - } - else if (value.IsUint64()) - { - using ValueType = std::vector>; - ValueType val; - for(rapidjson::SizeType jj = 0; jj < value[jj].Size(); ++jj) - { - std::vector ve; - for(rapidjson::SizeType kk = 0; kk < value[jj][kk].Size(); ++kk) - { - ve.push_back(value[jj][kk].GetUint64()); - } - val.push_back(ve); - } - EncapsulateMetaData(dictionary, key, val); - } - else if (value.IsDouble()) - { - using ValueType = std::vector>; - ValueType val; - for(rapidjson::SizeType jj = 0; jj < value[jj].Size(); ++jj) - { - std::vector ve; - for(rapidjson::SizeType kk = 0; kk < value[jj][kk].Size(); ++kk) - { - ve.push_back(value[jj][kk].GetDouble()); - } - val.push_back(ve); - } - EncapsulateMetaData(dictionary, key, val); - } - else if (value.IsFloat()) - { - using ValueType = std::vector>; - ValueType val; - for(rapidjson::SizeType jj = 0; jj < value[jj].Size(); ++jj) - { - std::vector ve; - for(rapidjson::SizeType kk = 0; kk < value[jj][kk].Size(); ++kk) - { - ve.push_back(value[jj][kk].GetFloat()); - } - val.push_back(ve); - } - EncapsulateMetaData(dictionary, key, val); + valueDoubleInner.push_back(vv.get_number()); } + valueDouble.push_back(valueDoubleInner); } + EncapsulateMetaData>>(dictionary, key, valueDouble); } - else + else if (value[0][0].is_string()) { - if (value.IsInt()) - { - using ValueType = std::vector; - ValueType val; - for(rapidjson::SizeType jj = 0; jj < value.Size(); ++jj) - { - val.push_back(value[jj].GetInt()); - } - EncapsulateMetaData(dictionary, key, val); - } - else if (value.IsUint()) - { - using ValueType = std::vector; - ValueType val; - for(rapidjson::SizeType jj = 0; jj < value.Size(); ++jj) - { - val.push_back(value[jj].GetUint()); - } - EncapsulateMetaData(dictionary, key, val); - } - else if (value.IsInt64()) + std::vector> valueString; + for (const auto & v : value.get_array()) { - using ValueType = std::vector; - ValueType val; - for(rapidjson::SizeType jj = 0; jj < value.Size(); ++jj) + std::vector valueStringInner; + for (const auto & vv : v.get_array()) { - val.push_back(value[jj].GetInt64()); + valueStringInner.push_back(vv.get_string()); } - EncapsulateMetaData(dictionary, key, val); - } - else if (value.IsUint64()) - { - using ValueType = std::vector; - ValueType val; - for(rapidjson::SizeType jj = 0; jj < value.Size(); ++jj) - { - val.push_back(value[jj].GetUint64()); - } - EncapsulateMetaData(dictionary, key, val); - } - else if (value.IsDouble()) - { - using ValueType = std::vector; - ValueType val; - for(rapidjson::SizeType jj = 0; jj < value.Size(); ++jj) - { - val.push_back(value[jj].GetDouble()); - } - EncapsulateMetaData(dictionary, key, val); - } - else if (value.IsFloat()) - { - using ValueType = std::vector; - ValueType val; - for(rapidjson::SizeType jj = 0; jj < value.Size(); ++jj) - { - val.push_back(value[jj].GetFloat()); - } - EncapsulateMetaData(dictionary, key, val); - } - else if (value.IsString()) - { - using ValueType = std::vector; - ValueType val; - for(rapidjson::SizeType jj = 0; jj < value.Size(); ++jj) - { - val.push_back(value[jj].GetString()); - } - EncapsulateMetaData(dictionary, key, val); + valueString.push_back(valueStringInner); } + EncapsulateMetaData>>(dictionary, key, valueString); } } + else + { + EncapsulateMetaData>>(dictionary, key, {}); + } } } + else + { + EncapsulateMetaData>(dictionary, key, {}); + } + } + else + { + itkGenericExceptionMacro("Unsupported MetadataObjectJSON type"); + } } } -} // end namespace wasm } // end namespace itk diff --git a/src/itkWasmImageIO.cxx b/src/itkWasmImageIO.cxx index 9ce2dbef1..efc30164f 100644 --- a/src/itkWasmImageIO.cxx +++ b/src/itkWasmImageIO.cxx @@ -18,6 +18,10 @@ #include "itkWasmImageIO.h" +#include "itkioComponentEnumFromJSON.h" +#include "itkioPixelEnumFromJSON.h" +#include "itkjsonFromIOComponentEnum.h" +#include "itkjsonFromIOPixelEnum.h" #include "itkWasmComponentTypeFromIOComponentEnum.h" #include "itkIOComponentEnumFromWasmComponentType.h" #include "itkWasmPixelTypeFromIOPixelEnum.h" @@ -31,9 +35,6 @@ #include "itksys/SystemTools.hxx" -#include "rapidjson/prettywriter.h" -#include "rapidjson/ostreamwrapper.h" - #include "cbor.h" namespace itk @@ -104,53 +105,56 @@ ::CanReadFile(const char *filename) void WasmImageIO -::SetJSON(rapidjson::Document & document) +::SetJSON(const ImageJSON & imageJSON) { - const rapidjson::Value & imageType = document["imageType"]; - const unsigned int dimension = imageType["dimension"].GetInt(); + const auto & imageType = imageJSON.imageType; + + const unsigned int dimension = imageType.dimension; this->SetNumberOfDimensions( dimension ); - const std::string componentType( imageType["componentType"].GetString() ); - const ImageIOBase::IOComponentEnum ioComponentType = IOComponentEnumFromWasmComponentType( componentType ); + const ImageIOBase::IOComponentEnum ioComponentType = ioComponentEnumFromJSON( imageType.componentType ); this->SetComponentType( ioComponentType ); - const std::string pixelType( imageType["pixelType"].GetString() ); - const IOPixelEnum ioPixelType = IOPixelEnumFromWasmPixelType( pixelType ); + const IOPixelEnum ioPixelType = ioPixelEnumFromJSON( imageType.pixelType ); this->SetPixelType( ioPixelType ); - this->SetNumberOfComponents( imageType["components"].GetInt() ); + this->SetNumberOfComponents( imageType.components ); - const rapidjson::Value & origin = document["origin"]; - int count = 0; - for( rapidjson::Value::ConstValueIterator itr = origin.Begin(); itr != origin.End(); ++itr ) - { - this->SetOrigin( count, itr->GetDouble() ); - ++count; - } + for (unsigned int i = 0; i < dimension; ++i) + { + this->SetOrigin(i, imageJSON.origin[i]); + } - const rapidjson::Value & spacing = document["spacing"]; - count = 0; - for( rapidjson::Value::ConstValueIterator itr = spacing.Begin(); itr != spacing.End(); ++itr ) - { - this->SetSpacing( count, itr->GetDouble() ); - ++count; - } + for (unsigned int i = 0; i < dimension; ++i) + { + this->SetSpacing(i, imageJSON.spacing[i]); + } - const rapidjson::Value & size = document["size"]; - count = 0; - for( rapidjson::Value::ConstValueIterator itr = size.Begin(); itr != size.End(); ++itr ) - { - this->SetDimensions( count, itr->GetInt() ); + const std::string path = this->GetFileName(); + const auto dataPath = path + "/data"; + const auto directionPath = dataPath + "/direction.raw"; + std::ifstream directionStream; + this->OpenFileForReading( directionStream, directionPath.c_str(), false ); + unsigned int count = 0; + for( unsigned int jj = 0; jj < dimension; ++jj ) + { + std::vector< double > direction( dimension ); + for( unsigned int ii = 0; ii < dimension; ++ii ) + { + directionStream.read(reinterpret_cast< char * >(&(direction[ii])), sizeof(double)); + } + this->SetDirection( count, direction ); ++count; - } + } - if (document.HasMember("metadata")) + for (unsigned int i = 0; i < dimension; ++i) { - auto dictionary = this->GetMetaDataDictionary(); - const rapidjson::Value & metadataJson = document["metadata"]; - wasm::ConvertJSONToMetaDataDictionary(metadataJson, dictionary); - this->SetMetaDataDictionary(dictionary); + this->SetDimensions(i, imageJSON.size[i]); } + + auto dictionary = this->GetMetaDataDictionary(); + jsonToMetaDataDictionary(imageJSON.metadata, dictionary); + this->SetMetaDataDictionary(dictionary); } @@ -506,37 +510,19 @@ ::ReadImageInformation() return; } - rapidjson::Document document; std::ifstream inputStream; const auto indexPath = path + "/index.json"; this->OpenFileForReading( inputStream, indexPath.c_str(), true ); - std::string str((std::istreambuf_iterator(inputStream)), - std::istreambuf_iterator()); - if (document.Parse(str.c_str()).HasParseError()) - { - itkExceptionMacro("Could not parse JSON"); - return; - } - this->SetJSON(document); - - const unsigned int dimension = this->GetNumberOfDimensions(); - const auto dataPath = path + "/data"; - int count = 0; - - const auto directionPath = dataPath + "/direction.raw"; - std::ifstream directionStream; - this->OpenFileForReading( directionStream, directionPath.c_str(), false ); - count = 0; - for( unsigned int jj = 0; jj < dimension; ++jj ) + std::string str((std::istreambuf_iterator(inputStream)), std::istreambuf_iterator()); + auto deserializedAttempt = glz::read_json(str); + if (!deserializedAttempt) { - std::vector< double > direction( dimension ); - for( unsigned int ii = 0; ii < dimension; ++ii ) - { - directionStream.read(reinterpret_cast< char * >(&(direction[ii])), sizeof(double)); - } - this->SetDirection( count, direction ); - ++count; + const std::string descriptiveError = glz::format_error(deserializedAttempt, str); + itkExceptionMacro("Failed to deserialize ImageJSON: " << descriptiveError); } + const auto imageJSON = deserializedAttempt.value(); + + this->SetJSON(imageJSON); } @@ -614,70 +600,45 @@ ::CanWriteFile(const char *name) } -rapidjson::Document +auto WasmImageIO -::GetJSON() +::GetJSON() -> ImageJSON { - rapidjson::Document document; - document.SetObject(); - rapidjson::Document::AllocatorType& allocator = document.GetAllocator(); - - rapidjson::Value imageType; - imageType.SetObject(); + ImageJSON imageJSON; const unsigned int dimension = this->GetNumberOfDimensions(); - imageType.AddMember("dimension", rapidjson::Value(dimension).Move(), allocator ); - - const std::string componentString = WasmComponentTypeFromIOComponentEnum( this->GetComponentType() ); - rapidjson::Value componentType; - componentType.SetString( componentString.c_str(), allocator ); - imageType.AddMember("componentType", componentType.Move(), allocator ); + imageJSON.imageType.dimension = dimension; - const std::string pixelString = WasmPixelTypeFromIOPixelEnum( this->GetPixelType() ); - rapidjson::Value pixelType; - pixelType.SetString( pixelString.c_str(), allocator ); - imageType.AddMember("pixelType", pixelType.Move(), allocator ); - - imageType.AddMember("components", rapidjson::Value( this->GetNumberOfComponents() ).Move(), allocator ); - - document.AddMember( "imageType", imageType.Move(), allocator ); + imageJSON.imageType.componentType = jsonComponentTypeFromIOComponentEnum( this->GetComponentType() ); + imageJSON.imageType.pixelType = jsonFromIOPixelEnum( this->GetPixelType() ); + imageJSON.imageType.components = this->GetNumberOfComponents(); - rapidjson::Value origin(rapidjson::kArrayType); + imageJSON.origin.clear(); for( unsigned int ii = 0; ii < dimension; ++ii ) - { - origin.PushBack(rapidjson::Value().SetDouble(this->GetOrigin( ii )), allocator); - } - document.AddMember( "origin", origin.Move(), allocator ); + { + imageJSON.origin.push_back(this->GetOrigin( ii )); + } - rapidjson::Value spacing(rapidjson::kArrayType); + imageJSON.spacing.clear(); for( unsigned int ii = 0; ii < dimension; ++ii ) - { - spacing.PushBack(rapidjson::Value().SetDouble(this->GetSpacing( ii )), allocator); - } - document.AddMember( "spacing", spacing.Move(), allocator ); + { + imageJSON.spacing.push_back(this->GetSpacing( ii )); + } - rapidjson::Value directionValue; - directionValue.SetString( "data:application/vnd.itk.path,data/direction.raw", allocator ); - document.AddMember( "direction", directionValue.Move(), allocator ); + imageJSON.direction = "data:application/vnd.itk.path,data/direction.raw"; - rapidjson::Value size(rapidjson::kArrayType); + imageJSON.size.clear(); for( unsigned int ii = 0; ii < dimension; ++ii ) - { - size.PushBack(rapidjson::Value().SetInt( this->GetDimensions( ii ) ), allocator); - } - document.AddMember( "size", size.Move(), allocator ); + { + imageJSON.size.push_back(this->GetDimensions( ii )); + } - std::string dataFileString( "data:application/vnd.itk.path,data/data.raw" ); - rapidjson::Value dataFile; - dataFile.SetString( dataFileString.c_str(), allocator ); - document.AddMember( "data", dataFile, allocator ); + imageJSON.data = "data:application/vnd.itk.path,data/data.raw"; auto dictionary = this->GetMetaDataDictionary(); - rapidjson::Value metadataJson(rapidjson::kArrayType); - wasm::ConvertMetaDataDictionaryToJSON(dictionary, metadataJson, allocator); - document.AddMember( "metadata", metadataJson.Move(), allocator ); + metaDataDictionaryToJSON(dictionary, imageJSON.metadata); - return document; + return imageJSON; } void @@ -703,7 +664,7 @@ ::WriteImageInformation() itksys::SystemTools::MakeDirectory(dataPath); } - rapidjson::Document document = this->GetJSON(); + const auto imageJSON = this->GetJSON(); const unsigned int dimension = this->GetNumberOfDimensions(); const auto directionPath = dataPath + "/direction.raw"; @@ -722,11 +683,15 @@ ::WriteImageInformation() } } + std::string serialized{}; + auto ec = glz::write(imageJSON, serialized); + if (ec) + { + itkExceptionMacro("Failed to serialize ImageJSON"); + } std::ofstream outputStream; - this->OpenFileForWriting( outputStream, indexPath.c_str(), true, true ); - rapidjson::OStreamWrapper ostreamWrapper( outputStream ); - rapidjson::PrettyWriter< rapidjson::OStreamWrapper > writer( ostreamWrapper ); - document.Accept( writer ); + openFileForWriting(outputStream, indexPath.c_str(), true, true); + outputStream << serialized; outputStream.close(); } diff --git a/src/itkWasmImageIOBase.cxx b/src/itkWasmImageIOBase.cxx index a515a0f92..f73cedc3b 100644 --- a/src/itkWasmImageIOBase.cxx +++ b/src/itkWasmImageIOBase.cxx @@ -20,7 +20,6 @@ #include "itkWasmImageIO.h" #include -#include "rapidjson/prettywriter.h" namespace itk { @@ -56,8 +55,7 @@ WasmImageIOBase::SetImageIO(ImageIOBase * imageIO, bool readImage) wasmImageIO->SetDimensions(dim, imageIO->GetDimensions(dim)); } - rapidjson::Document document = wasmImageIO->GetJSON(); - rapidjson::Document::AllocatorType& allocator = document.GetAllocator(); + auto imageJSON = wasmImageIO->GetJSON(); this->m_DirectionContainer->resize(dimension*dimension); for( unsigned int ii = 0; ii < dimension; ++ii ) @@ -72,10 +70,7 @@ WasmImageIOBase::SetImageIO(ImageIOBase * imageIO, bool readImage) std::ostringstream directionStream; directionStream << "data:application/vnd.itk.address,0:"; directionStream << directionAddress; - rapidjson::Value directionString; - directionString.SetString( directionStream.str().c_str(), allocator ); - document.RemoveMember( "direction" ); - document.AddMember( "direction", directionString.Move(), allocator ); + imageJSON.direction = directionStream.str(); ImageIORegion ioRegion( dimension ); for(unsigned int dim = 0; dim < dimension; ++dim) @@ -90,15 +85,15 @@ WasmImageIOBase::SetImageIO(ImageIOBase * imageIO, bool readImage) std::ostringstream dataStream; dataStream << "data:application/vnd.itk.address,0:"; dataStream << pixelDataAddress; - rapidjson::Value dataString; - dataString.SetString( dataStream.str().c_str(), allocator ); - document.RemoveMember( "data" ); - document.AddMember( "data", dataString.Move(), allocator ); + imageJSON.data = dataStream.str(); - rapidjson::StringBuffer stringBuffer; - rapidjson::Writer< rapidjson::StringBuffer > writer( stringBuffer ); - document.Accept( writer ); - this->SetJSON(stringBuffer.GetString()); + std::string serialized{}; + auto ec = glz::write(imageJSON, serialized); + if (ec) + { + itkExceptionMacro("Failed to serialize TransformListJSON"); + } + this->SetJSON(serialized); } void diff --git a/src/itkWasmMeshIO.cxx b/src/itkWasmMeshIO.cxx index 0464b4051..afde27ec0 100644 --- a/src/itkWasmMeshIO.cxx +++ b/src/itkWasmMeshIO.cxx @@ -465,7 +465,7 @@ ::ReadMeshInformation() const std::string descriptiveError = glz::format_error(deserializedAttempt, str); itkExceptionMacro("Failed to deserialize MeshJSON: " << descriptiveError); } - auto meshJSON = deserializedAttempt.value(); + const auto meshJSON = deserializedAttempt.value(); this->SetJSON(meshJSON); From 3fc591cf4a45fe502f72c8cfaf7493bf992d839c Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Sun, 7 Jul 2024 21:50:04 -0400 Subject: [PATCH 07/10] refactor(Pipeline): rapidjson to glaze --- include/itkPipeline.h | 16 ++--- src/itkPipeline.cxx | 138 +++++++++++++++++++++--------------------- 2 files changed, 74 insertions(+), 80 deletions(-) diff --git a/include/itkPipeline.h b/include/itkPipeline.h index e76281d10..6b06a69f0 100644 --- a/include/itkPipeline.h +++ b/include/itkPipeline.h @@ -26,7 +26,7 @@ #include "itkImage.h" #include "itkVectorImage.h" -#include "rapidjson/document.h" +#include "glaze/glaze.hpp" #include "WebAssemblyInterfaceExport.h" @@ -119,22 +119,16 @@ using CLI::Success; using CLI::Config; /** - * @brief Create a rapidjson kArrayType value from an STL style container. + * @brief Create a glaze arrat_t value from an STL style container. * * @tparam Iteratorable Any container type that supports STL style iterator. * @param container Container object. - * @param allocator Rapidjson allocator. - * @return rapidjson::Value rapidjson Value of kArrayType which contains all - * the values from the input container. + * @return glz::json_t::array_t with the values from the input container. */ template -rapidjson::Value getArrayJson(Iteratorable container, rapidjson::Document::AllocatorType& allocator) +glz::json_t::array_t getArrayJson(Iteratorable container) { - rapidjson::Value value(rapidjson::kArrayType); - for(auto iter = container.begin(); iter != container.end(); ++iter) - { - value.PushBack(rapidjson::Value(*iter), allocator); - } + glz::json_t::array_t value(container.begin(), container.end()); return value; } diff --git a/src/itkPipeline.cxx b/src/itkPipeline.cxx index 38bddd868..37861610c 100644 --- a/src/itkPipeline.cxx +++ b/src/itkPipeline.cxx @@ -20,9 +20,6 @@ #include #endif #include "CLI/Formatter.hpp" -#include "rapidjson/document.h" -#include "rapidjson/prettywriter.h" -#include "rapidjson/ostreamwrapper.h" namespace itk { @@ -282,82 +279,70 @@ Pipeline } +struct CLIOptionJSON +{ + std::string description; + std::string name; + std::string type; + bool required; + int itemsExpected; + int itemsExpectedMin; + int itemsExpectedMax; + std::string defaultStr; +}; + +struct InterfaceJSON +{ + std::string description; + std::string name; + std::string version; + std::vector inputs; + std::vector outputs; + std::vector parameters; +}; + void Pipeline ::interface_json() { - rapidjson::Document document; - document.SetObject(); - rapidjson::Document::AllocatorType& allocator = document.GetAllocator(); - - rapidjson::Value description; - description.SetString(this->get_description().c_str(), allocator); - document.AddMember("description", description.Move(), allocator); - rapidjson::Value name; - name.SetString(this->get_name().c_str(), allocator); - document.AddMember("name", name.Move(), allocator); + InterfaceJSON interfaceJSON; - rapidjson::Value version; - version.SetString(this->version().c_str(), allocator); - document.AddMember("version", version.Move(), allocator); + interfaceJSON.description = this->get_description(); + interfaceJSON.name = this->get_name(); + interfaceJSON.version = this->version(); - rapidjson::Value inputs(rapidjson::kArrayType); - rapidjson::Value outputs(rapidjson::kArrayType); - rapidjson::Value parameters(rapidjson::kArrayType); for(CLI::Option *opt : this->get_options({})) { - rapidjson::Value option; - option.SetObject(); - - rapidjson::Value optionDescription; - optionDescription.SetString(opt->get_description().c_str(), allocator); - option.AddMember("description", optionDescription.Move(), allocator); - - auto singleName = opt->get_single_name(); + CLIOptionJSON optionJSON; + optionJSON.description = opt->get_description(); + const auto singleName = opt->get_single_name(); if (singleName == "help") { continue; } - - rapidjson::Value optionName; - optionName.SetString(opt->get_single_name().c_str(), allocator); - option.AddMember("name", optionName.Move(), allocator); - - rapidjson::Value required; - required.SetBool(opt->get_required()); - option.AddMember("required", required.Move(), allocator); - - rapidjson::Value itemsExpected; - itemsExpected.SetInt(opt->get_items_expected()); - option.AddMember("itemsExpected", itemsExpected.Move(), allocator); - - rapidjson::Value itemsExpectedMin; - itemsExpectedMin.SetInt(opt->get_items_expected_min()); - option.AddMember("itemsExpectedMin", itemsExpectedMin.Move(), allocator); - - rapidjson::Value itemsExpectedMax; - itemsExpectedMax.SetInt(opt->get_items_expected_max()); - option.AddMember("itemsExpectedMax", itemsExpectedMax.Move(), allocator); - - auto typeName = opt->get_type_name(); - // flag + optionJSON.name = opt->get_single_name(); + optionJSON.required = opt->get_required(); + optionJSON.itemsExpected = opt->get_items_expected(); + optionJSON.itemsExpectedMin = opt->get_items_expected_min(); + optionJSON.itemsExpectedMax = opt->get_items_expected_max(); + optionJSON.type = opt->get_type_name(); if (!opt->get_items_expected()) { - typeName = "BOOL"; + optionJSON.type = "BOOL"; + } + if (!opt->get_default_str().empty()) + { + optionJSON.defaultStr = opt->get_default_str(); } - rapidjson::Value optionTypeName; - optionTypeName.SetString(typeName.c_str(), allocator); - option.AddMember("type", optionTypeName.Move(), allocator); - if (opt->get_positional()) { - if (typeName.rfind("OUTPUT", 0) != std::string::npos) + if (optionJSON.type.rfind("OUTPUT", 0) != std::string::npos) { - outputs.PushBack(option, allocator); + interfaceJSON.outputs.push_back(optionJSON); } else { - inputs.PushBack(option, allocator); + interfaceJSON.inputs.push_back(optionJSON); } } else @@ -370,24 +355,39 @@ ::interface_json() } if (!opt->get_default_str().empty()) { - rapidjson::Value defaultStr; - defaultStr.SetString(opt->get_default_str().c_str(), allocator); - option.AddMember("default", defaultStr.Move(), allocator); + optionJSON.defaultStr = opt->get_default_str(); } - parameters.PushBack(option, allocator); + interfaceJSON.parameters.push_back(optionJSON); } } - document.AddMember("inputs", inputs.Move(), allocator); - document.AddMember("outputs", outputs.Move(), allocator); - document.AddMember("parameters", parameters.Move(), allocator); - rapidjson::OStreamWrapper ostreamWrapper( std::cout ); - rapidjson::PrettyWriter< rapidjson::OStreamWrapper > writer( ostreamWrapper ); - document.Accept( writer ); - std::cout << std::endl; + std::string serialized{}; + auto ec = glz::write(interfaceJSON, serialized); + if (ec) + { + const std::string descriptiveError = glz::format_error(ec, serialized); + std::cerr << "Error during interface JSON serialization: " << descriptiveError << std::endl; + return; + } + std::cout << serialized << std::endl; } bool Pipeline::m_UseMemoryIO{false}; } // end namespace wasm } // end namespace itk + +template <> +struct glz::meta { + using T = itk::wasm::CLIOptionJSON; + static constexpr auto value = glz::object( + "description", &T::description, + "name", &T::name, + "type", &T::type, + "required", &T::required, + "itemsExpected", &T::itemsExpected, + "itemsExpectedMin", &T::itemsExpectedMin, + "itemsExpectedMax", &T::itemsExpectedMax, + "default", &T::defaultStr + ); +}; From ebf267a7cb88e1cd8e4b7230d1be4c001ef07492 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Sun, 7 Jul 2024 22:25:36 -0400 Subject: [PATCH 08/10] refactor(SupportInputImageTypes): rapidjson to glaze --- include/itkSupportInputImageTypes.h | 32 +++++++++++++------------- src/itkOutputBinaryStream.cxx | 1 - src/itkOutputTextStream.cxx | 1 - src/itkSupportInputImageTypes.cxx | 35 +++++++++++++---------------- 4 files changed, 30 insertions(+), 39 deletions(-) diff --git a/include/itkSupportInputImageTypes.h b/include/itkSupportInputImageTypes.h index c81659ad0..f6cfc2633 100644 --- a/include/itkSupportInputImageTypes.h +++ b/include/itkSupportInputImageTypes.h @@ -31,21 +31,15 @@ #include "itkSpecializedImagePipelineFunctor.h" #include "WebAssemblyInterfaceExport.h" +#include "itkImageJSON.h" + namespace itk { -namespace wasm -{ +WebAssemblyInterface_EXPORT bool lexical_cast(const std::string &input, ImageTypeJSON & imageType); -struct InterfaceImageType +namespace wasm { - unsigned int dimension{2}; - std::string componentType{"uint8"}; - std::string pixelType{"Scalar"}; - unsigned int components{1}; -}; - -WebAssemblyInterface_EXPORT bool lexical_cast(const std::string &input, InterfaceImageType & imageType); /** \class SupportInputImageTypes * @@ -98,7 +92,7 @@ SupportInputImageTypes static int Dimensions(const std::string & inputImageOptionName, Pipeline & pipeline) { - InterfaceImageType imageType; + ImageTypeJSON imageType; const auto iwpArgc = pipeline.get_argc(); const auto iwpArgv = pipeline.get_argv(); @@ -128,17 +122,20 @@ SupportInputImageTypes private: template static int - IteratePixelTypes(Pipeline & pipeline, const InterfaceImageType & imageType, bool passThrough = false) + IteratePixelTypes(Pipeline & pipeline, const ImageTypeJSON & imageType, bool passThrough = false) { constexpr unsigned int Dimension = VDimension; using PixelType = TPixel; using ConvertPixelTraits = DefaultConvertPixelTraits; if (passThrough || - imageType.componentType == MapComponentType::ComponentString && - imageType.pixelType == MapPixelType::PixelString) + imageType.componentType == MapComponentType::JSONComponentEnum && + imageType.pixelType == MapPixelType::JSONPixelEnum) { - if (passThrough || imageType.pixelType == "VariableLengthVector" || imageType.pixelType == "VariableSizeMatrix" || imageType.components == ConvertPixelTraits::GetNumberOfComponents() ) + if (passThrough || + imageType.pixelType == JSONPixelTypesEnum::VariableLengthVector || + imageType.pixelType == JSONPixelTypesEnum::VariableSizeMatrix || + imageType.components == ConvertPixelTraits::GetNumberOfComponents() ) { return SpecializedImagePipelineFunctor()(pipeline); } @@ -149,14 +146,15 @@ SupportInputImageTypes } std::ostringstream ostrm; - ostrm << "Unsupported pixel type: " << imageType.pixelType << " with component type: " << imageType.componentType << " and components: " << imageType.components; + std::string imageTypeString = glz::write_json(imageType).value_or("error"); + ostrm << "Unsupported image type: " << imageTypeString << std::endl; CLI::Error err("Runtime error", ostrm.str(), 1); return pipeline.exit(err); } template static int - IterateDimensions(Pipeline & pipeline, const InterfaceImageType & imageType, bool passThrough = false) + IterateDimensions(Pipeline & pipeline, const ImageTypeJSON & imageType, bool passThrough = false) { if (passThrough || VDimension == imageType.dimension) { diff --git a/src/itkOutputBinaryStream.cxx b/src/itkOutputBinaryStream.cxx index 03b284533..0398a95ce 100644 --- a/src/itkOutputBinaryStream.cxx +++ b/src/itkOutputBinaryStream.cxx @@ -21,7 +21,6 @@ #ifndef ITK_WASM_NO_MEMORY_IO #include "itkWasmExports.h" #include -#include "rapidjson/document.h" #include "itkWasmStringStream.h" #endif diff --git a/src/itkOutputTextStream.cxx b/src/itkOutputTextStream.cxx index 4d35cf446..c84dff4c4 100644 --- a/src/itkOutputTextStream.cxx +++ b/src/itkOutputTextStream.cxx @@ -21,7 +21,6 @@ #ifndef ITK_WASM_NO_MEMORY_IO #include "itkWasmExports.h" #include -#include "rapidjson/document.h" #include "itkWasmStringStream.h" #endif diff --git a/src/itkSupportInputImageTypes.cxx b/src/itkSupportInputImageTypes.cxx index 463e533b8..7ad059351 100644 --- a/src/itkSupportInputImageTypes.cxx +++ b/src/itkSupportInputImageTypes.cxx @@ -18,32 +18,28 @@ #include "itkSupportInputImageTypes.h" #include "itkWasmExports.h" -#include "rapidjson/document.h" +#include "itkjsonFromIOComponentEnum.h" +#include "itkjsonFromIOPixelEnum.h" namespace itk { -namespace wasm -{ - -bool lexical_cast(const std::string &input, InterfaceImageType & imageType) +bool lexical_cast(const std::string &input, ImageTypeJSON & imageType) { if (wasm::Pipeline::get_use_memory_io()) { #ifndef ITK_WASM_NO_MEMORY_IO const unsigned int index = std::stoi(input); - auto json = getMemoryStoreInputJSON(0, index); - rapidjson::Document document; - if (document.Parse(json.c_str()).HasParseError()) - { - throw std::runtime_error("Could not parse JSON"); - } - - const rapidjson::Value & jsonImageType = document["imageType"]; - imageType.dimension = jsonImageType["dimension"].GetInt(); - imageType.componentType = jsonImageType["componentType"].GetString(); - imageType.pixelType = jsonImageType["pixelType"].GetString(); - imageType.components = jsonImageType["components"].GetInt(); + auto json = wasm::getMemoryStoreInputJSON(0, index); + std::string deserialized; + auto deserializedAttempt = glz::read_json(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(); + imageType = imageJSON.imageType; #else return false; #endif @@ -64,11 +60,11 @@ bool lexical_cast(const std::string &input, InterfaceImageType & imageType) using IOComponentType = itk::IOComponentEnum; const IOComponentType ioComponentEnum = imageIO->GetComponentType(); - imageType.componentType = WasmComponentTypeFromIOComponentEnum( ioComponentEnum ); + imageType.componentType = itk::jsonComponentTypeFromIOComponentEnum( ioComponentEnum ); using IOPixelType = itk::IOPixelEnum; const IOPixelType ioPixelEnum = imageIO->GetPixelType(); - imageType.pixelType = WasmPixelTypeFromIOPixelEnum( ioPixelEnum ); + imageType.pixelType = itk::jsonFromIOPixelEnum( ioPixelEnum ); imageType.components = imageIO->GetNumberOfComponents(); #else @@ -78,5 +74,4 @@ bool lexical_cast(const std::string &input, InterfaceImageType & imageType) return true; } -} // end namespace wasm } // end namespace itk From 7b4f2455670b6f7f11cc8b9dbaa1d320653fdfa7 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Sun, 7 Jul 2024 22:34:30 -0400 Subject: [PATCH 09/10] refactor(WasmStringStream): rapidjson to glaze --- include/itkWasmStringStream.h | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/include/itkWasmStringStream.h b/include/itkWasmStringStream.h index 9489f642f..396f9fe46 100644 --- a/include/itkWasmStringStream.h +++ b/include/itkWasmStringStream.h @@ -19,13 +19,21 @@ #define itkWasmStringStream_h #include "itkWasmDataObject.h" -#include "rapidjson/document.h" #include #include "WebAssemblyInterfaceExport.h" +#include "glaze/glaze.hpp" + namespace itk { + +struct StringStreamJSON +{ + std::string data; + size_t size; +}; + /** *\class WasmStringStream * \brief JSON representation for a std::stringstream @@ -74,15 +82,17 @@ class WebAssemblyInterface_EXPORT WasmStringStream : public WasmDataObject void SetJSON(const char * jsonChar) override { std::string json(jsonChar); - rapidjson::Document document; - if (document.Parse(json.c_str()).HasParseError()) - { - throw std::runtime_error("Could not parse JSON"); - } - const rapidjson::Value & dataJson = document["data"]; - const std::string dataString( dataJson.GetString() ); + std::string deserialized; + auto deserializedAttempt = glz::read_json(json); + if (!deserializedAttempt) + { + const std::string descriptiveError = glz::format_error(deserializedAttempt, json); + throw std::runtime_error("Failed to deserialize StringStreamJSON: " + descriptiveError); + } + auto stringStream = deserializedAttempt.value(); + const std::string dataString = stringStream.data; const char * dataPtr = reinterpret_cast< char * >( std::strtoull(dataString.substr(35).c_str(), nullptr, 10) ); - size_t size = document["size"].GetInt(); + size_t size = stringStream.size; const std::string_view string(dataPtr, size); m_StringStream.str(std::string{string}); From 17bca176ca231d20cb0b665e947d78068e12867c Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Mon, 8 Jul 2024 05:35:09 -0400 Subject: [PATCH 10/10] fix(InterfaceTypes): consistent default name --- include/itkImageJSON.h | 2 +- include/itkMeshJSON.h | 2 +- include/itkPolyDataJSON.h | 2 +- .../itk-wasm/src/interface-types/image.ts | 4 ++-- .../itk-wasm/src/interface-types/mesh-type.ts | 10 ++++---- .../itk-wasm/src/interface-types/mesh.ts | 4 ++-- .../itk-wasm/src/interface-types/poly-data.ts | 4 ++-- .../test/node/interface-types/image-test.js | 24 +++++++++---------- .../node/interface-types/poly-data-test.js | 14 +++++------ 9 files changed, 33 insertions(+), 33 deletions(-) diff --git a/include/itkImageJSON.h b/include/itkImageJSON.h index 87a63bfc9..01f086f9f 100644 --- a/include/itkImageJSON.h +++ b/include/itkImageJSON.h @@ -56,7 +56,7 @@ namespace itk { ImageTypeJSON imageType; - std::string name { "image" }; + std::string name { "Image" }; std::vector origin { 0.0, 0.0 }; std::vector spacing { 1.0, 1.0 }; diff --git a/include/itkMeshJSON.h b/include/itkMeshJSON.h index 12772c016..2e16c39f4 100644 --- a/include/itkMeshJSON.h +++ b/include/itkMeshJSON.h @@ -60,7 +60,7 @@ namespace itk { MeshTypeJSON meshType; - std::string name { "mesh"}; + std::string name { "Mesh"}; size_t numberOfPoints{ 0 }; std::string points; diff --git a/include/itkPolyDataJSON.h b/include/itkPolyDataJSON.h index db45c97d1..eed3b00eb 100644 --- a/include/itkPolyDataJSON.h +++ b/include/itkPolyDataJSON.h @@ -57,7 +57,7 @@ namespace itk { PolyDataTypeJSON polyDataType; - std::string name { "polydata" }; + std::string name { "PolyData" }; size_t numberOfPoints{ 0 }; std::string points; diff --git a/packages/core/typescript/itk-wasm/src/interface-types/image.ts b/packages/core/typescript/itk-wasm/src/interface-types/image.ts index 656c6df43..56a58386e 100644 --- a/packages/core/typescript/itk-wasm/src/interface-types/image.ts +++ b/packages/core/typescript/itk-wasm/src/interface-types/image.ts @@ -4,7 +4,7 @@ import setMatrixElement from '../set-matrix-element.js' import Metadata from './metadata.js' class Image { - name: string = 'image' + name: string = 'Image' origin: number[] @@ -18,7 +18,7 @@ class Image { data: null | TypedArray - constructor(public readonly imageType = new ImageType()) { + constructor (public readonly imageType = new ImageType()) { const dimension = imageType.dimension this.origin = new Array(dimension) this.origin.fill(0.0) diff --git a/packages/core/typescript/itk-wasm/src/interface-types/mesh-type.ts b/packages/core/typescript/itk-wasm/src/interface-types/mesh-type.ts index 79403e0f9..4f24e93d7 100644 --- a/packages/core/typescript/itk-wasm/src/interface-types/mesh-type.ts +++ b/packages/core/typescript/itk-wasm/src/interface-types/mesh-type.ts @@ -3,18 +3,18 @@ import FloatTypes from './float-types.js' import PixelTypes from './pixel-types.js' class MeshType { - constructor( + constructor ( public readonly dimension: number = 2, public readonly pointComponentType: (typeof FloatTypes)[keyof typeof FloatTypes] = FloatTypes.Float32, public readonly pointPixelComponentType: - | (typeof IntTypes)[keyof typeof IntTypes] - | (typeof FloatTypes)[keyof typeof FloatTypes] = FloatTypes.Float32, + | (typeof IntTypes)[keyof typeof IntTypes] + | (typeof FloatTypes)[keyof typeof FloatTypes] = FloatTypes.Float32, public readonly pointPixelType: (typeof PixelTypes)[keyof typeof PixelTypes] = PixelTypes.Scalar, public readonly pointPixelComponents: number = 1, public readonly cellComponentType: (typeof IntTypes)[keyof typeof IntTypes] = IntTypes.Int32, public readonly cellPixelComponentType: - | (typeof IntTypes)[keyof typeof IntTypes] - | (typeof FloatTypes)[keyof typeof FloatTypes] = FloatTypes.Float32, + | (typeof IntTypes)[keyof typeof IntTypes] + | (typeof FloatTypes)[keyof typeof FloatTypes] = FloatTypes.Float32, public readonly cellPixelType: (typeof PixelTypes)[keyof typeof PixelTypes] = PixelTypes.Scalar, public readonly cellPixelComponents: number = 1 ) {} diff --git a/packages/core/typescript/itk-wasm/src/interface-types/mesh.ts b/packages/core/typescript/itk-wasm/src/interface-types/mesh.ts index 4ec4836c3..14b34d9cb 100644 --- a/packages/core/typescript/itk-wasm/src/interface-types/mesh.ts +++ b/packages/core/typescript/itk-wasm/src/interface-types/mesh.ts @@ -2,7 +2,7 @@ import MeshType from './mesh-type.js' import type TypedArray from '../typed-array.js' class Mesh { - name: string = 'mesh' + name: string = 'Mesh' numberOfPoints: number points: null | TypedArray @@ -17,7 +17,7 @@ class Mesh { numberOfCellPixels: number cellData: null | TypedArray - constructor(public readonly meshType = new MeshType()) { + constructor (public readonly meshType = new MeshType()) { this.name = 'mesh' this.numberOfPoints = 0 diff --git a/packages/core/typescript/itk-wasm/src/interface-types/poly-data.ts b/packages/core/typescript/itk-wasm/src/interface-types/poly-data.ts index a270a2fbd..70734ce61 100644 --- a/packages/core/typescript/itk-wasm/src/interface-types/poly-data.ts +++ b/packages/core/typescript/itk-wasm/src/interface-types/poly-data.ts @@ -2,7 +2,7 @@ import PolyDataType from './poly-data-type.js' import TypedArray from '../typed-array.js' class PolyData { - name: string = 'polydata' + name: string = 'PolyData' numberOfPoints: number points: Float32Array @@ -28,7 +28,7 @@ class PolyData { constructor(public readonly polyDataType = new PolyDataType()) { this.polyDataType = polyDataType - this.name = 'polydata' + this.name = 'PolyData' this.numberOfPoints = 0 this.points = new Float32Array() diff --git a/packages/core/typescript/itk-wasm/test/node/interface-types/image-test.js b/packages/core/typescript/itk-wasm/test/node/interface-types/image-test.js index af5dc832a..2307eccf4 100644 --- a/packages/core/typescript/itk-wasm/test/node/interface-types/image-test.js +++ b/packages/core/typescript/itk-wasm/test/node/interface-types/image-test.js @@ -2,18 +2,18 @@ import test from 'ava' import { Image, ImageType, IntTypes } from '../../../dist/index-node.js' -test('imageType should have the same imageType passed to the constructor', t => { +test('imageType should have the same imageType passed to the constructor', (t) => { const image = new Image() const defaultImageType = new ImageType() t.deepEqual(image.imageType, defaultImageType) }) -test('name should have the default value of "Image"', t => { +test('name should have the default value of "Image"', (t) => { const image = new Image() - t.deepEqual(image.name, 'image') + t.deepEqual(image.name, 'Image') }) -test('origin should have a length equal to the dimension', t => { +test('origin should have a length equal to the dimension', (t) => { let imageType = new ImageType(2, IntTypes.UInt8) let image = new Image(imageType) t.is(image.origin.length, 2) @@ -23,13 +23,13 @@ test('origin should have a length equal to the dimension', t => { t.is(image.origin.length, 3) }) -test('origin should have a default value of 0.0', t => { +test('origin should have a default value of 0.0', (t) => { const imageType = new ImageType(2, IntTypes.UInt8) const image = new Image(imageType) t.is(image.origin[0], 0.0) }) -test('spacing should have a length equal to the dimension', t => { +test('spacing should have a length equal to the dimension', (t) => { let imageType = new ImageType(2, IntTypes.UInt8) let image = new Image(imageType) t.is(image.spacing.length, 2) @@ -39,13 +39,13 @@ test('spacing should have a length equal to the dimension', t => { t.is(image.spacing.length, 3) }) -test('spacing should have a default value of 1.0', t => { +test('spacing should have a default value of 1.0', (t) => { const imageType = new ImageType(2, IntTypes.UInt8) const image = new Image(imageType) t.is(image.spacing[0], 1.0) }) -test('direction should be the identity by default', t => { +test('direction should be the identity by default', (t) => { const imageType = new ImageType(2) const image = new Image(imageType) t.is(image.direction[0], 1.0) @@ -54,7 +54,7 @@ test('direction should be the identity by default', t => { t.is(image.direction[3], 1.0) }) -test('size should have a length equal to the dimension', t => { +test('size should have a length equal to the dimension', (t) => { let imageType = new ImageType(2) let image = new Image(imageType) t.is(image.size.length, 2) @@ -64,19 +64,19 @@ test('size should have a length equal to the dimension', t => { t.is(image.size.length, 3) }) -test('size should have a default value of 0', t => { +test('size should have a default value of 0', (t) => { const imageType = new ImageType(2) const image = new Image(imageType) t.is(image.size[0], 0) }) -test('metadata should be an object', t => { +test('metadata should be an object', (t) => { const imageType = new ImageType(2) const image = new Image(imageType) t.is(typeof image.metadata, 'object') }) -test('data should have a default value of null', t => { +test('data should have a default value of null', (t) => { const imageType = new ImageType(2) const image = new Image(imageType) t.is(image.data, null) diff --git a/packages/core/typescript/itk-wasm/test/node/interface-types/poly-data-test.js b/packages/core/typescript/itk-wasm/test/node/interface-types/poly-data-test.js index f0851773a..e65c0ac62 100644 --- a/packages/core/typescript/itk-wasm/test/node/interface-types/poly-data-test.js +++ b/packages/core/typescript/itk-wasm/test/node/interface-types/poly-data-test.js @@ -2,37 +2,37 @@ import test from 'ava' import { PolyData } from '../../../dist/index-node.js' -test('name should have the default value of "PolyData"', t => { +test('name should have the default value of "PolyData"', (t) => { const polyData = new PolyData() t.deepEqual(polyData.name, 'PolyData') }) -test('points should be a Float32Array', t => { +test('points should be a Float32Array', (t) => { const polyData = new PolyData() t.assert(polyData.points instanceof Float32Array) }) -test('points should have a default length of 0', t => { +test('points should have a default length of 0', (t) => { const polyData = new PolyData() t.is(polyData.points.length, 0) }) -test('lines should have a default value of null', t => { +test('lines should have a default value of null', (t) => { const polyData = new PolyData() t.is(polyData.lines, null) }) -test('vertices should have a default value of null', t => { +test('vertices should have a default value of null', (t) => { const polyData = new PolyData() t.is(polyData.vertices, null) }) -test('polygons should have a default value of null', t => { +test('polygons should have a default value of null', (t) => { const polyData = new PolyData() t.is(polyData.polygons, null) }) -test('triangleStrips should have a default value of null', t => { +test('triangleStrips should have a default value of null', (t) => { const polyData = new PolyData() t.is(polyData.triangleStrips, null) })