diff --git a/CMakeLists.txt b/CMakeLists.txt index dac479907..dd25f7198 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,23 @@ if(ELASTIX_USE_OPENCL) list(APPEND _GPU_depends ITKGPUCommon) endif() +set(_ITK_io_depends + ITKImageIO + ITKTransformIO + ITKMeshIO + ITKIOImageBase + ITKIOMeshBase + ITKIOMeshOBJ + ITKIOMeta + ITKIOTransformBase + ITKIOXML +) + +if(WASI OR EMSCRIPTEN) + # Keep Wasm binaries small + set(_ITK_io_depends) +endif() + # Find ITK. find_package(ITK 5.3 REQUIRED COMPONENTS ITKCommon @@ -43,12 +60,6 @@ find_package(ITK 5.3 REQUIRED COMPONENTS ITKImageGrid ITKImageIntensity ITKImageStatistics - ITKIOImageBase - ITKIOMeshBase - ITKIOMeshOBJ - ITKIOMeta - ITKIOTransformBase - ITKIOXML ITKMathematicalMorphology ITKMesh ITKOptimizers @@ -61,9 +72,7 @@ find_package(ITK 5.3 REQUIRED COMPONENTS ITKTransform ITKTransformFactory ${_GPU_depends} - ITKImageIO - ITKTransformIO - ITKMeshIO + ${_ITK_io_depends} ) include(${ITK_USE_FILE}) diff --git a/Common/ImageSamplers/itkImageToVectorContainerFilter.hxx b/Common/ImageSamplers/itkImageToVectorContainerFilter.hxx index d3d457427..eb28fef2e 100644 --- a/Common/ImageSamplers/itkImageToVectorContainerFilter.hxx +++ b/Common/ImageSamplers/itkImageToVectorContainerFilter.hxx @@ -18,8 +18,6 @@ #ifndef itkImageToVectorContainerFilter_hxx #define itkImageToVectorContainerFilter_hxx -#include "itkImageToVectorContainerFilter.h" - #include "itkMath.h" namespace itk diff --git a/Common/Transforms/elxTransformIO.cxx b/Common/Transforms/elxTransformIO.cxx index cfd5367f0..e5203ed87 100644 --- a/Common/Transforms/elxTransformIO.cxx +++ b/Common/Transforms/elxTransformIO.cxx @@ -32,8 +32,10 @@ #include #include +#ifndef __wasm32__ #include #include +#endif #include @@ -191,6 +193,11 @@ elastix::TransformIO::ConvertItkTransformBaseToSingleItkTransform(const itk::Tra void elastix::TransformIO::Write(const itk::Object & itkTransform, const std::string & fileName) { +#ifdef __wasm32__ + const std::string message = "File IO not supported in WebAssembly builds."; + log::error(message); + throw std::runtime_error(message); +#else try { const auto writer = itk::TransformFileWriter::New(); @@ -203,12 +210,20 @@ elastix::TransformIO::Write(const itk::Object & itkTransform, const std::string { log::error(std::ostringstream{} << "Error trying to write " << fileName << ":\n" << stdException.what()); } +#endif } itk::SmartPointer elastix::TransformIO::Read(const std::string & fileName) { +#ifdef __wasm32__ + const std::string message = "File IO not supported in WebAssembly builds."; + log::error(message); + throw std::runtime_error(message); + return nullptr; +#else + const auto reader = itk::TransformFileReader::New(); reader->SetFileName(fileName); @@ -221,6 +236,7 @@ elastix::TransformIO::Read(const std::string & fileName) assert(transformList->size() <= 1); return transformList->empty() ? nullptr : transformList->front(); +#endif } diff --git a/Common/itkComputeImageExtremaFilter.h b/Common/itkComputeImageExtremaFilter.h index 5eda9238b..cbf9b16f4 100644 --- a/Common/itkComputeImageExtremaFilter.h +++ b/Common/itkComputeImageExtremaFilter.h @@ -129,7 +129,9 @@ class ITK_TEMPLATE_EXPORT ComputeImageExtremaFilter : public StatisticsImageFilt PixelType m_ThreadMin{ 1 }; PixelType m_ThreadMax{ 1 }; +#ifndef __wasi__ std::mutex m_Mutex{}; +#endif }; // end of class } // end namespace itk diff --git a/Common/itkComputeImageExtremaFilter.hxx b/Common/itkComputeImageExtremaFilter.hxx index ef288d55d..f91aabfe5 100644 --- a/Common/itkComputeImageExtremaFilter.hxx +++ b/Common/itkComputeImageExtremaFilter.hxx @@ -176,7 +176,9 @@ ComputeImageExtremaFilter::ThreadedGenerateDataImageSpatialMask(con } // end for } // end if +#ifndef __wasi__ std::lock_guard mutexHolder(m_Mutex); +#endif m_ThreadSum += sum; m_SumOfSquares += sumOfSquares; m_Count += count; @@ -227,7 +229,9 @@ ComputeImageExtremaFilter::ThreadedGenerateDataImageMask(const Regi ++it; } // end while +#ifndef __wasi__ std::lock_guard mutexHolder(m_Mutex); +#endif m_ThreadSum += sum; m_SumOfSquares += sumOfSquares; m_Count += count; diff --git a/Common/itkMeshFileReaderBase.h b/Common/itkMeshFileReaderBase.h index c2b4da551..dbcef1bfc 100644 --- a/Common/itkMeshFileReaderBase.h +++ b/Common/itkMeshFileReaderBase.h @@ -20,7 +20,11 @@ #include "itkMeshSource.h" #include "itkMacro.h" -#include "itkMeshFileReader.h" // for MeshFileReaderException +#ifndef __wasm32__ +#include "itkMeshFileReaderException.h" +#else +#define MeshFileReaderException ExceptionObject +#endif namespace itk { diff --git a/Components/Metrics/MissingStructurePenalty/elxMissingStructurePenalty.h b/Components/Metrics/MissingStructurePenalty/elxMissingStructurePenalty.h index 53d9b4272..71e69897a 100644 --- a/Components/Metrics/MissingStructurePenalty/elxMissingStructurePenalty.h +++ b/Components/Metrics/MissingStructurePenalty/elxMissingStructurePenalty.h @@ -21,9 +21,6 @@ #include "elxIncludes.h" #include "itkMissingStructurePenalty.h" -#include "itkMeshFileReader.h" -#include "itkMeshFileWriter.h" - namespace elastix { diff --git a/Components/Metrics/MissingStructurePenalty/elxMissingStructurePenalty.hxx b/Components/Metrics/MissingStructurePenalty/elxMissingStructurePenalty.hxx index b335cfa7e..001f99113 100644 --- a/Components/Metrics/MissingStructurePenalty/elxMissingStructurePenalty.hxx +++ b/Components/Metrics/MissingStructurePenalty/elxMissingStructurePenalty.hxx @@ -21,6 +21,11 @@ #include "elxMissingStructurePenalty.h" #include "itkTimeProbe.h" +#ifndef __wasm32__ +#include "itkMeshFileReader.h" +#include "itkMeshFileWriter.h" +#endif + namespace elastix { @@ -145,6 +150,11 @@ MissingStructurePenalty::BeforeRegistration() fmeshArgument << ch << metricNumber; std::string fixedMeshName = this->GetConfiguration()->GetCommandLineArgument(fmeshArgument.str()); typename MeshType::Pointer fixedMesh; // default-constructed (null) +#ifdef __wasm32__ + const std::string message = "File IO not supported in WebAssembly builds."; + log::error(message); + itkExceptionMacro(<< message); +#else if (itksys::SystemTools::GetFilenameLastExtension(fixedMeshName) == ".txt") { this->ReadTransformixPoints(fixedMeshName, fixedMesh); @@ -153,6 +163,7 @@ MissingStructurePenalty::BeforeRegistration() { this->ReadMesh(fixedMeshName, fixedMesh); } +#endif meshPointerContainer->SetElement(meshNumber, fixedMesh.GetPointer()); } @@ -281,6 +292,12 @@ template unsigned int MissingStructurePenalty::ReadMesh(const std::string & meshFileName, typename FixedMeshType::Pointer & mesh) { +#ifdef __wasm32__ + const std::string message = "File IO not supported in WebAssembly builds."; + log::error(message); + itkExceptionMacro(<< message); + return 0; +#else /** Read the input mesh. */ auto meshReader = itk::MeshFileReader::New(); meshReader->SetFileName(meshFileName); @@ -300,6 +317,7 @@ MissingStructurePenalty::ReadMesh(const std::string & meshFileName, ty log::info(std::ostringstream{} << " Number of specified input points: " << nrofpoints); return nrofpoints; +#endif } // end ReadMesh() @@ -311,6 +329,11 @@ template void MissingStructurePenalty::WriteResultMesh(const std::string & filename, MeshIdType meshId) { +#ifdef __wasm32__ + const std::string message = "File IO not supported in WebAssembly builds."; + log::error(message); + itkExceptionMacro(<< message); +#else /** Setup the pipeline. */ /** Set the points of the latest transformation. */ @@ -376,7 +399,7 @@ MissingStructurePenalty::WriteResultMesh(const std::string & filename, // restore celldata as undefined mappedMesh->SetCellData(nullptr); } - +#endif } // end WriteResultMesh() @@ -389,6 +412,12 @@ unsigned int MissingStructurePenalty::ReadTransformixPoints(const std::string & filename, typename MeshType::Pointer & mesh) // const { +#ifdef __wasm32__ + const std::string message = "File IO not supported in WebAssembly builds."; + log::error(message); + itkExceptionMacro(<< message); + return 0; +#else /* FB: Majority of the code is copied from elxTransformBase.hxx: TransformPointsSomePoints() Function to read 2d structures by reading elastix point files (transformix format) and connecting @@ -528,6 +557,7 @@ the sequence of points to form a 2d connected polydata contour. } } return nrofpoints; +#endif } // end ReadTransformixPoints() diff --git a/Components/Metrics/PolydataDummyPenalty/elxPolydataDummyPenalty.h b/Components/Metrics/PolydataDummyPenalty/elxPolydataDummyPenalty.h index 86108f3e3..0fbe8eee8 100644 --- a/Components/Metrics/PolydataDummyPenalty/elxPolydataDummyPenalty.h +++ b/Components/Metrics/PolydataDummyPenalty/elxPolydataDummyPenalty.h @@ -23,9 +23,6 @@ //#include "elxMetricBase.h" -#include "itkMeshFileReader.h" -#include "itkMeshFileWriter.h" - namespace elastix { /** diff --git a/Components/Metrics/PolydataDummyPenalty/elxPolydataDummyPenalty.hxx b/Components/Metrics/PolydataDummyPenalty/elxPolydataDummyPenalty.hxx index d3f4a569b..fdf7f934c 100644 --- a/Components/Metrics/PolydataDummyPenalty/elxPolydataDummyPenalty.hxx +++ b/Components/Metrics/PolydataDummyPenalty/elxPolydataDummyPenalty.hxx @@ -20,6 +20,11 @@ #include +#ifndef __wasm32__ +#include "itkMeshFileReader.h" +#include "itkMeshFileWriter.h" +#endif + namespace elastix { @@ -270,6 +275,12 @@ template unsigned int PolydataDummyPenalty::ReadMesh(const std::string & meshFileName, typename FixedMeshType::Pointer & mesh) { +#ifdef __wasm32__ + const std::string message = "File IO not supported in WebAssembly builds."; + log::error(message); + itkExceptionMacro(<< message); + return 0; +#else /** Read the input mesh. */ auto meshReader = itk::MeshFileReader::New(); meshReader->SetFileName(meshFileName); @@ -291,6 +302,7 @@ PolydataDummyPenalty::ReadMesh(const std::string & meshFileName, typen log::info(std::ostringstream{} << " Number of specified input points: " << nrofpoints); return nrofpoints; +#endif } // end ReadMesh() @@ -302,6 +314,11 @@ template void PolydataDummyPenalty::WriteResultMesh(const std::string & filename, MeshIdType meshId) { +#ifdef __wasm32__ + const std::string message = "File IO not supported in WebAssembly builds."; + log::error(message); + itkExceptionMacro(<< message); +#else /** Set the points of the latest transformation. */ const MappedMeshContainerPointer mappedMeshContainer = this->GetModifiableMappedMeshContainer(); FixedMeshPointer mappedMesh = mappedMeshContainer->ElementAt(meshId); @@ -360,7 +377,7 @@ PolydataDummyPenalty::WriteResultMesh(const std::string & filename, Me { mappedMesh->SetCellData(nullptr); } - +#endif } // end WriteResultMesh() diff --git a/Components/Metrics/StatisticalShapePenalty/elxStatisticalShapePenalty.hxx b/Components/Metrics/StatisticalShapePenalty/elxStatisticalShapePenalty.hxx index 263a3e9fa..31e576035 100644 --- a/Components/Metrics/StatisticalShapePenalty/elxStatisticalShapePenalty.hxx +++ b/Components/Metrics/StatisticalShapePenalty/elxStatisticalShapePenalty.hxx @@ -25,7 +25,9 @@ #include "itkDefaultStaticMeshTraits.h" #include "itkTransformMeshFilter.h" #include +#ifndef __wasm32__ #include +#endif #include #include @@ -352,6 +354,12 @@ StatisticalShapePenalty::ReadShape(const std::string & typename PointSetType::Pointer & pointSet, const typename ImageType::ConstPointer image) { +#ifdef __wasm32__ + const std::string message = "File IO not supported in WebAssembly builds."; + log::error(message); + itkExceptionMacro(<< message); + return 0; +#else /** Typedef's. \todo test DummyIPPPixelType=bool. */ using DummyIPPPixelType = double; using MeshTraitsType = @@ -380,7 +388,7 @@ StatisticalShapePenalty::ReadShape(const std::string & pointSet = PointSetType::New(); pointSet->SetPoints(mesh->GetPoints()); return nrofpoints; - +#endif } // end ReadShape() diff --git a/Core/ComponentBaseClasses/elxFixedImagePyramidBase.hxx b/Core/ComponentBaseClasses/elxFixedImagePyramidBase.hxx index f9d881cd8..f39aff6ef 100644 --- a/Core/ComponentBaseClasses/elxFixedImagePyramidBase.hxx +++ b/Core/ComponentBaseClasses/elxFixedImagePyramidBase.hxx @@ -20,7 +20,10 @@ #include "elxFixedImagePyramidBase.h" #include "elxDeref.h" + +#ifndef __wasm32__ #include "itkImageFileCastWriter.h" +#endif namespace elastix { @@ -175,12 +178,17 @@ FixedImagePyramidBase::WritePyramidImage(const std::string & filename, /** Do the writing. */ log::to_stdout(" Writing fixed pyramid image ..."); +#ifndef __wasm32__ try { - itk::WriteCastedImage(*(this->GetAsITKBaseType()->GetOutput(level)), filename, resultImagePixelType, doCompression); + itk::WriteCastedImage(*(this->GetAsITKBaseType()->GetOutput(level)), filename, resultImagePixelType, doCompression); } catch (itk::ExceptionObject & excp) { +#else +// Always throw -- do not include support code or access filesystem with wasm + itk::ExceptionObject excp; +#endif /** Add information to the exception. */ excp.SetLocation("FixedImagePyramidBase - BeforeEachResolutionBase()"); std::string err_str = excp.GetDescription(); @@ -188,8 +196,12 @@ FixedImagePyramidBase::WritePyramidImage(const std::string & filename, excp.SetDescription(err_str); /** Pass the exception to an higher level. */ +#ifndef __wasm32__ throw; } +#else + throw excp; +#endif } // end WritePyramidImage() diff --git a/Core/ComponentBaseClasses/elxMovingImagePyramidBase.hxx b/Core/ComponentBaseClasses/elxMovingImagePyramidBase.hxx index de50added..2d4ff0dbe 100644 --- a/Core/ComponentBaseClasses/elxMovingImagePyramidBase.hxx +++ b/Core/ComponentBaseClasses/elxMovingImagePyramidBase.hxx @@ -21,7 +21,10 @@ #include "elxMovingImagePyramidBase.h" #include "elxDeref.h" + +#ifndef __wasm32__ #include "itkImageFileCastWriter.h" +#endif namespace elastix { @@ -176,12 +179,17 @@ MovingImagePyramidBase::WritePyramidImage(const std::string & filename /** Do the writing. */ log::to_stdout(" Writing moving pyramid image ..."); +#ifndef __wasm32__ try { itk::WriteCastedImage(*(this->GetAsITKBaseType()->GetOutput(level)), filename, resultImagePixelType, doCompression); } catch (itk::ExceptionObject & excp) { +#else +// Always throw -- do not include support code or access filesystem with wasm + itk::ExceptionObject excp; +#endif /** Add information to the exception. */ excp.SetLocation("MovingImagePyramidBase - BeforeEachResolutionBase()"); std::string err_str = excp.GetDescription(); @@ -189,8 +197,12 @@ MovingImagePyramidBase::WritePyramidImage(const std::string & filename excp.SetDescription(err_str); /** Pass the exception to an higher level. */ +#ifndef __wasm32__ throw; } +#else + throw excp; +#endif } // end WritePyramidImage() diff --git a/Core/ComponentBaseClasses/elxResamplerBase.hxx b/Core/ComponentBaseClasses/elxResamplerBase.hxx index 22ded08b6..4e963565e 100644 --- a/Core/ComponentBaseClasses/elxResamplerBase.hxx +++ b/Core/ComponentBaseClasses/elxResamplerBase.hxx @@ -22,7 +22,6 @@ #include "elxConversion.h" #include "elxDeref.h" -#include "itkImageFileCastWriter.h" #include "itkChangeInformationImageFilter.h" #include "itkAdvancedRayCastInterpolateImageFunction.h" #include "itkTimeProbe.h" @@ -396,12 +395,17 @@ ResamplerBase::WriteResultImage(OutputImageType * image, { log::to_stdout("\n Writing image ..."); } +#ifndef __wasm32__ try { - itk::WriteCastedImage(*(infoChanger->GetOutput()), filename, resultImagePixelType, doCompression); + itk::WriteCastedImage(*(infoChanger->GetOutput()), filename, resultImagePixelType, doCompression); } catch (itk::ExceptionObject & excp) { +#else +// Always throw -- do not include support code or access filesystem with wasm + itk::ExceptionObject excp; +#endif /** Add information to the exception. */ excp.SetLocation("ResamplerBase - AfterRegistrationBase()"); std::string err_str = excp.GetDescription(); @@ -409,8 +413,12 @@ ResamplerBase::WriteResultImage(OutputImageType * image, excp.SetDescription(err_str); /** Pass the exception to an higher level. */ +#ifndef __wasm32__ throw; } +#else + throw excp; +#endif } // end WriteResultImage() diff --git a/Core/ComponentBaseClasses/elxTransformBase.hxx b/Core/ComponentBaseClasses/elxTransformBase.hxx index 635a78cc7..766de2524 100644 --- a/Core/ComponentBaseClasses/elxTransformBase.hxx +++ b/Core/ComponentBaseClasses/elxTransformBase.hxx @@ -38,8 +38,10 @@ #include "itkContinuousIndex.h" #include "itkChangeInformationImageFilter.h" #include "itkMesh.h" +#ifndef __wasm32__ #include "itkMeshFileReader.h" #include "itkMeshFileWriter.h" +#endif #include "itkCommonEnums.h" #include @@ -924,6 +926,11 @@ template void TransformBase::TransformPointsSomePointsVTK(const std::string & filename) const { +#ifdef __wasm32__ + const std::string message = "File IO not supported in WebAssembly builds."; + log::error(message); + itkExceptionMacro(<< message); +#else /** Typedef's. \todo test DummyIPPPixelType=bool. */ using DummyIPPPixelType = float; using MeshTraitsType = @@ -982,7 +989,7 @@ TransformBase::TransformPointsSomePointsVTK(const std::string & filena log::error(std::ostringstream{} << " Error while saving points.\n" << err); } } - +#endif } // end TransformPointsSomePointsVTK() diff --git a/Core/Install/elxComponentLoader.cxx b/Core/Install/elxComponentLoader.cxx index fb55a9b93..e24344c75 100644 --- a/Core/Install/elxComponentLoader.cxx +++ b/Core/Install/elxComponentLoader.cxx @@ -23,9 +23,11 @@ #include "elxInstallAllComponents.h" // ITKFactoryRegistration headers: +#ifndef __wasm32__ #include #include #include +#endif #include #include @@ -133,12 +135,14 @@ ComponentLoader::InstallSupportedImageTypes() int ComponentLoader::LoadComponents() { +#ifndef __wasm32__ // Retrieve those IOFactoryRegisterManager instances, just to ensure that they are really constructed. const volatile auto ioFactoryRegisterManagerInstances = std::make_tuple(itk::ImageIOFactoryRegisterManagerInstance, itk::MeshIOFactoryRegisterManagerInstance, itk::TransformIOFactoryRegisterManagerInstance); (void)ioFactoryRegisterManagerInstances; +#endif int installReturnCode = 0; diff --git a/Core/Kernel/elxlog.cxx b/Core/Kernel/elxlog.cxx index 2633ef808..14a4974ab 100644 --- a/Core/Kernel/elxlog.cxx +++ b/Core/Kernel/elxlog.cxx @@ -22,7 +22,9 @@ #include #include #include +#ifndef __wasi__ #include +#endif namespace elastix { @@ -50,7 +52,9 @@ class logger void to_file(const std::string & message) { +#ifndef __wasi__ const std::lock_guard lock(m_file_mutex); +#endif if (!m_data.log_filename.empty()) { @@ -66,7 +70,9 @@ class logger void to_stdout(const std::string & message) { +#ifndef __wasi__ const std::lock_guard lock(m_stdout_mutex); +#endif std::cout << message << std::endl; } @@ -115,8 +121,10 @@ class logger data m_data{}; +#ifndef __wasi__ std::mutex m_file_mutex{}; std::mutex m_stdout_mutex{}; +#endif }; diff --git a/Core/Main/elxParameterObject.cxx b/Core/Main/elxParameterObject.cxx index badddfc09..b0430e748 100644 --- a/Core/Main/elxParameterObject.cxx +++ b/Core/Main/elxParameterObject.cxx @@ -21,7 +21,7 @@ #include "itkParameterFileParser.h" -#include "itkFileTools.h" +#include "itksys/SystemTools.hxx" #include #include #include diff --git a/Core/Main/itkElastixRegistrationMethod.hxx b/Core/Main/itkElastixRegistrationMethod.hxx index 4f2e6232c..97dc637b2 100644 --- a/Core/Main/itkElastixRegistrationMethod.hxx +++ b/Core/Main/itkElastixRegistrationMethod.hxx @@ -268,6 +268,7 @@ ElastixRegistrationMethod::GenerateData() { const auto transformFileName = "InitialTransform." + std::to_string(i) + '.' + outputFileNameExtension; +#ifndef __wasm32__ // Write the external transform to file. elx::TransformIO::Write(elx::Deref(externalTransform), m_OutputDirectory + transformFileName); @@ -275,6 +276,7 @@ ElastixRegistrationMethod::GenerateData() transformFound->second = { "File" }; transformParameterMap["TransformFileName"] = { transformFileName }; transformParameterMap.erase("TransformAddress"); +#endif } } diff --git a/Core/Main/itkTransformixFilter.hxx b/Core/Main/itkTransformixFilter.hxx index dd7e52ec8..851da0334 100644 --- a/Core/Main/itkTransformixFilter.hxx +++ b/Core/Main/itkTransformixFilter.hxx @@ -35,8 +35,6 @@ #ifndef itkTransformixFilter_hxx #define itkTransformixFilter_hxx -#include "itkTransformixFilter.h" - #include "elxLibUtilities.h" #include "elxPixelTypeToString.h" #include "elxTransformBase.h" @@ -44,6 +42,7 @@ #include "elxDefaultConstruct.h" #include +#include #include // For unique_ptr.