From 354529b934316d8ae7b688c9d7802c706cf25fe4 Mon Sep 17 00:00:00 2001 From: Jerome Lesaint Date: Fri, 7 Nov 2025 19:14:58 +0100 Subject: [PATCH 1/4] Attempt to add a NexusHdf5 IO --- common/CMakeLists.txt | 13 ++ common/clitkIO.cxx | 2 + common/rtkNexusHdf5ImageIO.cxx | 287 ++++++++++++++++++++++++++ common/rtkNexusHdf5ImageIO.h | 164 +++++++++++++++ common/rtkNexusHdf5ImageIOFactory.cxx | 0 common/rtkNexusHdf5ImageIOFactory.h | 0 6 files changed, 466 insertions(+) create mode 100644 common/rtkNexusHdf5ImageIO.cxx create mode 100644 common/rtkNexusHdf5ImageIO.h create mode 100644 common/rtkNexusHdf5ImageIOFactory.cxx create mode 100644 common/rtkNexusHdf5ImageIOFactory.h diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 6ef71539..5b299c48 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -18,6 +18,19 @@ set(clitkCommon_SRC clitkXdrImageIOReader.cxx clitkXdrImageIOWriter.cxx clitkXdrImageIOFactory.cxx + rtkHisImageIO.cxx + rtkHisImageIOFactory.cxx + rtkHndImageIO.cxx + rtkHndImageIOFactory.cxx + rtkEdfImageIO.cxx + rtkEdfImageIOFactory.cxx + rtkXRadImageIO.cxx + rtkXRadImageIOFactory.cxx + rtkImagXImageIO.cxx + rtkImagXImageIOFactory.cxx + rtkImagXXMLFileReader.cxx + rtkNexusHdf5ImageIO.cxx + rtkNexusHdf5ImageIOFactory.cxx clitkEsrfHstImageIO.cxx clitkEsrfHstImageIOFactory.cxx clitkEsrfHstXMLFileReader.cxx diff --git a/common/clitkIO.cxx b/common/clitkIO.cxx index 284afa94..e46bf87b 100644 --- a/common/clitkIO.cxx +++ b/common/clitkIO.cxx @@ -35,6 +35,7 @@ #include "rtkEdfImageIOFactory.h" #include "rtkImagXImageIOFactory.h" #include "rtkXRadImageIOFactory.h" +#include "rtkNexusHdf5ImageIOFactory.h" #include "clitkEsrfHstImageIOFactory.h" #include "clitkGateAsciiImageIOFactory.h" #include "clitkConfiguration.h" @@ -90,6 +91,7 @@ void clitk::RegisterClitkFactories() rtk::EdfImageIOFactory::RegisterOneFactory(); rtk::ImagXImageIOFactory::RegisterOneFactory(); rtk::XRadImageIOFactory::RegisterOneFactory(); + rtk::NexusHdf5ImageIOFactory::RegisterOneFactory(); clitk::EsrfHstImageIOFactory::RegisterOneFactory(); itk::BMPImageIOFactory::RegisterOneFactory(); itk::GDCMImageIOFactory::RegisterOneFactory(); diff --git a/common/rtkNexusHdf5ImageIO.cxx b/common/rtkNexusHdf5ImageIO.cxx new file mode 100644 index 00000000..575266ab --- /dev/null +++ b/common/rtkNexusHdf5ImageIO.cxx @@ -0,0 +1,287 @@ +/*========================================================================= + * + * Copyright RTK Consortium + * + * 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 + * + * http://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 "rtkNexusHdf5ImageIO.h" + +// itk include (for itkReadRawBytesAfterSwappingMacro) +#include +#include + +//-------------------------------------------------------------------- +/* Find value_ptr as pointer to the parameter of the given key in the header. + * Returns NULL on success. + */ +char* +rtk::NexusHdf5ImageIO::edf_findInHeader( char* header, const char* key ) +{ + char *value_ptr = strstr( header, key ); + + if (!value_ptr) return NULL; + /* an edf line is "key = value ;" */ + value_ptr = 1 + strchr( value_ptr + strlen(key), '=' ); + while (isspace(*value_ptr) ) value_ptr++; + return value_ptr; +} + +//-------------------------------------------------------------------- +// Read Image Information +void rtk::NexusHdf5ImageIO::ReadImageInformation() +{ + try { + // Open the existing file + H5File file(filename, H5F_ACC_RDONLY); + + // List of all entries + hsize_t n_objs = file.getNumObjs(); + std::vector groups; + for (hsize_t i = 0; i < n_objs; ++i) { + std::string name = file.getObjnameByIdx(i); + H5G_obj_t type = file.getObjTypeByIdx(i); + + if (type == H5G_GROUP) { + groups.push_back(name); + } + } + + // Take the first one + std::string entry = groups[0]; + m_Entry = entry; + Group entry_group = file.openGroup("/" + entry); + Attribute attr = entry_group.openAttribute("definition"); + DataType dtype = attr.getDataType(); + std::string entry_type; + attr.read(dtype, entry_type); + float spacing_x = 0.0; + float spacing_y = 0.0; + + // Fetch spacing information + if entry_type == "NXtomo" { + // Get projection spacing + DataSet spacing_x_ds = file.openDataSet( + "/" + entry + "/instrument/detector/x_pixel_size" + ); + spacing_x_ds.read(&spacing_x, PredType::NATIVE_FLOAT); + SetSpacing(0, spacing_x); + + DataSet spacing_y_ds = file.openDataSet( + "/" + entry + "/instrument/detector/y_pixel_size" + ); + spacing_y_ds.read(&spacing_y, PredType::NATIVE_FLOAT); + SetSpacing(1, spacing_y); + + // Spacing on the rotation angle axis is irrelevant + SetSpacing(2, 1.0); // + + } else if entry_type == "NXentry" { + DataSet voxel_size_ds = file.openDataSet( + "/" + entry + "/reconstruction/configuration/processing_options/reconstruction/voxel_size_cm" + ); + float voxel_size_mm = 0.0; + voxel_size_ds.read(&voxel_size_mm, PredType::NATIVE_FLOAT); + voxel_size_mm *= 10.0; // convert cm + SetSpacing(0, voxel_size_mm); + SetSpacing(1, voxel_size_mm); + SetSpacing(2, voxel_size_mm); + } else { + itkGenericExceptionMacro(<< entry_type + <<"is an invalid entry type: " + << "Valid types are NXtomo and NXentry" + <<" \""); + return 1; + } + + // Get datatype and dataspace + if (entry_type == "NXtomo") { + m_PathToData = "/" + entry + "/instrument/detector/data" + DataSet dataset = file.openDataSet( + m_PathToData + ); + + } else if (entry_type == "NXentry") { + m_PathToData = "/" + entry + "/reconstruction/results/data" + DataSet dataset = file.openDataSet( + m_PathToData + ); + } + + // Get dimensions + DataSpace dataspace = dataset.getSpace(); + int rank = dataspace.getSimpleExtentNdims(); + hsize_t dims[3]; + dataspace.getSimpleExtentDims(dims, nullptr); + + SetNumberOfDimensions(3); + SetDimensions(0, dims[0]); + SetDimensions(1, dims[1]); + SetDimensions(2, dims[2]); + + // Set origin to zero + SetOrigin(0, 0.); + SetOrigin(1, 0.); + SetOrigin(2, 0.); + + // Get the datatype + DataType dtype = dataset.getDataType(); + H5T_class_t type_class = dtype.getClass(); + + switch(type_class) { + case H5T_NO_CLASS: + itkGenericExceptionMacro( <<"H5T_NO_CLASS is incorrect datatype \""); + break; + case H5T_INTEGER: + SetComponentType(itk::ImageIOBase::INT); + break; + case H5T_FLOAT: + SetComponentType(itk::ImageIOBase::FLOAT); + break; + case H5T_TIME: + itkGenericExceptionMacro( <<"TIME data type is not handled\""); + break; + case H5T_STRING: + itkGenericExceptionMacro( <<"STRING data type is not handled\""); + break; + case H5T_BITFIELD: + itkGenericExceptionMacro( <<"BITFIELD data type is not handled\""); + break; + case H5T_OPAQUE: + itkGenericExceptionMacro( <<"BITFIELD data type is not handled\""); + break; + case H5T_COMPOUND: + itkGenericExceptionMacro( <<"COMPOUND data type is not handled\""); + break; + case H5T_REFERENCE: + itkGenericExceptionMacro( <<"REFERENCE data type is not handled\""); + break; + case H5T_ENUM: + itkGenericExceptionMacro( <<"ENUM data type is not handled\""); + break; + case H5T_VLEN: + itkGenericExceptionMacro( <<"VLEN data type is not handled\""); + break; + case H5T_ARRAY: + itkGenericExceptionMacro( <<"ARRAY data type is not handled\""); + break; + } + + dataspace.close(); + dataset.close(); + file.close(); + + } catch (FileIException &error) { + itkExceptionMacro("Cannot open HDF5 file: " << filename); + return 1; + } catch (DataSetIException &error) { + itkExceptionMacro("Dataset error: " << error.getCDetailMsg() << filename); + return 1; + } catch (DataSpaceIException &error) { + itkExceptionError("Dataspace error: " << error.getCDetailMsg()); + return 1; + } +} //// + +//-------------------------------------------------------------------- +// Read Image Information +bool rtk::NexusHdf5ImageIO::CanReadFile(const char* FileNameToRead) +{ + std::string filename(FileNameToRead); + const std::string::size_type it = filename.find_last_of( "." ); + std::string fileExt( filename, it+1, filename.length() ); + + if ( + fileExt != std::string("h5") && + fileExt != std::string("hdf5") && + fileExt != std::string("nx") + ) return false; + + // Try opening with HDF5 to verify + hid_t file_id = H5Fopen(filename, H5F_ACC_RDONLY, H5P_DEFAULT); + if (file_id < 0) + return false; + + H5Fclose(file_id); + return true; +} //// + +//-------------------------------------------------------------------- +// Read Image Content +void rtk::NexusHdf5ImageIO::Read(void * buffer) +{ + try { + DataSet dataset = file.openDataSet( + m_PathToData + ); + + DataSpace dataspace = dataset.getSpace(); + int rank = dataspace.getSimpleExtentNdims(); + hsize_t dims[3]; + dataspace.getSimpleExtentDims(dims, nullptr); + + // Get the datatype + DataType readType = dataset.getDataType(); + H5T_class_t type_class = dtype.getClass(); + dataset.read(buffer, type_class); + + dataspace.close(); + dataset.close(); + file.close(); + + } catch (FileIException &error) { + itkExceptionMacro("Cannot open HDF5 file: " << filename); + return 1; + } catch (DataSetIException &error) { + itkExceptionMacro("Dataset error: " << error.getCDetailMsg() << filename); + return 1; + } catch (DataSpaceIException &error) { + itkExceptionError("Dataspace error: " << error.getCDetailMsg()); + return 1; + } + +const std::string filename = this->GetFileName(); + hid_t file_id = H5Fopen(m_FileName.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); + if (file_id < 0) + itkExceptionMacro("Cannot open HDF5 file for reading"); + + hid_t dataset_id = H5Dopen(file_id, "image", H5P_DEFAULT); + if (dataset_id < 0) + itkExceptionMacro("Cannot open dataset 'image'"); + + herr_t status = H5Dread(dataset_id, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buffer); + if (status < 0) + itkExceptionMacro("Error reading HDF5 dataset"); + + H5Dclose(dataset_id); + H5Fclose(file_id);} + +//-------------------------------------------------------------------- +// Write Image Information +void rtk::NexusHdf5ImageIO::WriteImageInformation( bool itkNotUsed(keepOfStream) ) +{ +} + +//-------------------------------------------------------------------- +// Write Image Information +bool rtk::NexusHdf5ImageIO::CanWriteFile( const char* itkNotUsed(FileNameToWrite) ) +{ + return false; +} + +//-------------------------------------------------------------------- +// Write Image +void rtk::NexusHdf5ImageIO::Write( const void * itkNotUsed(buffer) ) +{ +} //// diff --git a/common/rtkNexusHdf5ImageIO.h b/common/rtkNexusHdf5ImageIO.h new file mode 100644 index 00000000..622f9de4 --- /dev/null +++ b/common/rtkNexusHdf5ImageIO.h @@ -0,0 +1,164 @@ +/*========================================================================= + * + * Copyright RTK Consortium + * + * 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 + * + * http://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 __rtkNexusHdf5ImageIO_h +#define __rtkNexusHdf5ImageIO_h + +#include +#include +#include + +#include +#include + +#include "clitkCommon.h" + +namespace rtk { + +/** \class NexusHdf5ImageIO + * \brief Class for reading NexusHdf5 image file format. NexusHdf5 is the format of + * X-ray projection images at the ESRF. + * + * \author Jerome Lesaint + * + * \ingroup IOFilters + */ +class NexusHdf5ImageIO : public itk::ImageIOBase +{ +public: + /** Standard class typedefs. */ + typedef NexusHdf5ImageIO Self; + typedef itk::ImageIOBase Superclass; + typedef itk::SmartPointer Pointer; + + NexusHdf5ImageIO() : Superclass() { + } + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(NexusHdf5ImageIO, ImageIOBase); + + /*-------- This part of the interface deals with reading data. ------ */ + virtual void ReadImageInformation() ITK_OVERRIDE; + + virtual bool CanReadFile( const char* FileNameToRead ) ITK_OVERRIDE; + + virtual void Read(void * buffer) ITK_OVERRIDE; + + /*-------- This part of the interfaces deals with writing data. ----- */ + virtual void WriteImageInformation(bool keepOfStream); + + virtual void WriteImageInformation() ITK_OVERRIDE { + WriteImageInformation(false); + } + + virtual bool CanWriteFile(const char* filename) ITK_OVERRIDE; + + virtual void Write(const void* buffer) ITK_OVERRIDE; + +protected: + std::string m_Entry; + std::string m_PathToData; + std::string m_BinaryFileName; + int m_BinaryFileSkip; + + static char* edf_findInHeader( char* header, const char* key ); + + /* List of EDF supported datatypes + */ + enum DataType { + U_CHAR_DATATYPE = 0, CHAR_DATATYPE, // 8 bits = 1 B + U_SHORT_DATATYPE, SHORT_DATATYPE, // 16 bits = 2 B + U_INT_DATATYPE, INT_DATATYPE, // 32 bits = 4 B + U_L_INT_DATATYPE, L_INT_DATATYPE, // 32 bits = 4 B + FLOAT_DATATYPE, DOUBLE_DATATYPE, // 4 B, 8 B + UNKNOWN_DATATYPE = -1 + }; + + /* Note - compatibility: + Unsigned8 = 1,Signed8, Unsigned16, Signed16, + Unsigned32, Signed32, Unsigned64, Signed64, + FloatIEEE32, DoubleIEEE64 + */ + + /*************************************************************************** + * Tables + ***************************************************************************/ + + // table key-value structure + struct table { + const char *key; + itk::ImageIOBase::IOByteOrderEnum value; + }; + + struct table3 { + const char *key; + int value; + short sajzof; + }; + + /* Returns index of the table tbl whose key matches the beginning of the + * search string search_str. + * It returns index into the table or -1 if there is no match. + */ + static int + lookup_table_nth( const struct table *tbl, const char *search_str ) + { + int k = -1; + + while (tbl[++k].key) + if (tbl[k].key && !strncmp(search_str, tbl[k].key, strlen(tbl[k].key) ) ) + return k; + return -1; // not found + } + + static int + lookup_table3_nth( const struct table3 *tbl, const char *search_str ) + { + int k = -1; + + while (tbl[++k].key) + if (tbl[k].key && !strncmp(search_str, tbl[k].key, strlen(tbl[k].key) ) ) + return k; + return -1; // not found + } + + ///* Orientation of axes of the raster, as the binary matrix is saved in + // * the file. (Determines the scanning direction, or the "fastest" index + // * of the matrix in the data file.) + // */ + //enum NexusHdf5RasterAxes { + //RASTER_AXES_XrightYdown, // matricial format: rows, columns + //RASTER_AXES_XrightYup // cartesian coordinate system + // // other 6 combinations not available (not needed until now) + //}; + + //static const struct table rasteraxes_table[] = + //{ + // { "XrightYdown", RASTER_AXES_XrightYdown }, + // { "XrightYup", RASTER_AXES_XrightYup }, + // { NULL, -1 } + //}; + +}; // end class NexusHdf5ImageIO + +} // end namespace + +#endif diff --git a/common/rtkNexusHdf5ImageIOFactory.cxx b/common/rtkNexusHdf5ImageIOFactory.cxx new file mode 100644 index 00000000..e69de29b diff --git a/common/rtkNexusHdf5ImageIOFactory.h b/common/rtkNexusHdf5ImageIOFactory.h new file mode 100644 index 00000000..e69de29b From 51f6d44f4c8e2f6c74abcbf07544098b858d60e9 Mon Sep 17 00:00:00 2001 From: Jerome Lesaint Date: Fri, 7 Nov 2025 22:04:13 +0100 Subject: [PATCH 2/4] Fix NexusHdf5 --- common/rtkNexusHdf5ImageIO.cxx | 129 ++++++++++++--------------------- common/rtkNexusHdf5ImageIO.h | 5 +- 2 files changed, 48 insertions(+), 86 deletions(-) diff --git a/common/rtkNexusHdf5ImageIO.cxx b/common/rtkNexusHdf5ImageIO.cxx index 575266ab..ab635e22 100644 --- a/common/rtkNexusHdf5ImageIO.cxx +++ b/common/rtkNexusHdf5ImageIO.cxx @@ -22,29 +22,13 @@ #include #include -//-------------------------------------------------------------------- -/* Find value_ptr as pointer to the parameter of the given key in the header. - * Returns NULL on success. - */ -char* -rtk::NexusHdf5ImageIO::edf_findInHeader( char* header, const char* key ) -{ - char *value_ptr = strstr( header, key ); - - if (!value_ptr) return NULL; - /* an edf line is "key = value ;" */ - value_ptr = 1 + strchr( value_ptr + strlen(key), '=' ); - while (isspace(*value_ptr) ) value_ptr++; - return value_ptr; -} - //-------------------------------------------------------------------- // Read Image Information void rtk::NexusHdf5ImageIO::ReadImageInformation() { try { // Open the existing file - H5File file(filename, H5F_ACC_RDONLY); + H5::H5File file(m_FileName, H5F_ACC_RDONLY); // List of all entries hsize_t n_objs = file.getNumObjs(); @@ -61,38 +45,38 @@ void rtk::NexusHdf5ImageIO::ReadImageInformation() // Take the first one std::string entry = groups[0]; m_Entry = entry; - Group entry_group = file.openGroup("/" + entry); - Attribute attr = entry_group.openAttribute("definition"); - DataType dtype = attr.getDataType(); + H5::Group entry_group = file.openGroup("/" + entry); + H5::Attribute attr = entry_group.openAttribute("definition"); + H5::DataType dtype = attr.getDataType(); std::string entry_type; attr.read(dtype, entry_type); float spacing_x = 0.0; float spacing_y = 0.0; // Fetch spacing information - if entry_type == "NXtomo" { + if (entry_type == "NXtomo") { // Get projection spacing - DataSet spacing_x_ds = file.openDataSet( + H5::DataSet spacing_x_ds = file.openDataSet( "/" + entry + "/instrument/detector/x_pixel_size" ); - spacing_x_ds.read(&spacing_x, PredType::NATIVE_FLOAT); + spacing_x_ds.read(&spacing_x, H5::PredType::NATIVE_FLOAT); SetSpacing(0, spacing_x); - DataSet spacing_y_ds = file.openDataSet( + H5::DataSet spacing_y_ds = file.openDataSet( "/" + entry + "/instrument/detector/y_pixel_size" ); - spacing_y_ds.read(&spacing_y, PredType::NATIVE_FLOAT); + spacing_y_ds.read(&spacing_y, H5::PredType::NATIVE_FLOAT); SetSpacing(1, spacing_y); // Spacing on the rotation angle axis is irrelevant SetSpacing(2, 1.0); // - } else if entry_type == "NXentry" { - DataSet voxel_size_ds = file.openDataSet( + } else if (entry_type == "NXentry") { + H5::DataSet voxel_size_ds = file.openDataSet( "/" + entry + "/reconstruction/configuration/processing_options/reconstruction/voxel_size_cm" ); float voxel_size_mm = 0.0; - voxel_size_ds.read(&voxel_size_mm, PredType::NATIVE_FLOAT); + voxel_size_ds.read(&voxel_size_mm, H5::PredType::NATIVE_FLOAT); voxel_size_mm *= 10.0; // convert cm SetSpacing(0, voxel_size_mm); SetSpacing(1, voxel_size_mm); @@ -102,25 +86,25 @@ void rtk::NexusHdf5ImageIO::ReadImageInformation() <<"is an invalid entry type: " << "Valid types are NXtomo and NXentry" <<" \""); - return 1; } // Get datatype and dataspace + H5::DataSet dataset; if (entry_type == "NXtomo") { - m_PathToData = "/" + entry + "/instrument/detector/data" - DataSet dataset = file.openDataSet( + m_PathToData = "/" + entry + "/instrument/detector/data"; + dataset = file.openDataSet( m_PathToData ); } else if (entry_type == "NXentry") { - m_PathToData = "/" + entry + "/reconstruction/results/data" - DataSet dataset = file.openDataSet( + m_PathToData = "/" + entry + "/reconstruction/results/data"; + dataset = file.openDataSet( m_PathToData ); } // Get dimensions - DataSpace dataspace = dataset.getSpace(); + H5::DataSpace dataspace = dataset.getSpace(); int rank = dataspace.getSimpleExtentNdims(); hsize_t dims[3]; dataspace.getSimpleExtentDims(dims, nullptr); @@ -136,8 +120,8 @@ void rtk::NexusHdf5ImageIO::ReadImageInformation() SetOrigin(2, 0.); // Get the datatype - DataType dtype = dataset.getDataType(); - H5T_class_t type_class = dtype.getClass(); + H5::DataType dtype2 = dataset.getDataType(); + H5T_class_t type_class = dtype2.getClass(); switch(type_class) { case H5T_NO_CLASS: @@ -182,15 +166,12 @@ void rtk::NexusHdf5ImageIO::ReadImageInformation() dataset.close(); file.close(); - } catch (FileIException &error) { - itkExceptionMacro("Cannot open HDF5 file: " << filename); - return 1; - } catch (DataSetIException &error) { - itkExceptionMacro("Dataset error: " << error.getCDetailMsg() << filename); - return 1; - } catch (DataSpaceIException &error) { - itkExceptionError("Dataspace error: " << error.getCDetailMsg()); - return 1; + } catch (H5::FileIException &error) { + itkExceptionMacro("Cannot open HDF5 file: " + m_FileName); + } catch (H5::DataSetIException &error) { + itkExceptionMacro("Dataset error: " + std::string(error.getCDetailMsg()) + m_FileName); + } catch (H5::DataSpaceIException &error) { + itkExceptionMacro("Dataspace error: " + std::string(error.getCDetailMsg())); } } //// @@ -198,9 +179,9 @@ void rtk::NexusHdf5ImageIO::ReadImageInformation() // Read Image Information bool rtk::NexusHdf5ImageIO::CanReadFile(const char* FileNameToRead) { - std::string filename(FileNameToRead); - const std::string::size_type it = filename.find_last_of( "." ); - std::string fileExt( filename, it+1, filename.length() ); + m_FileName = FileNameToRead; + const std::string::size_type it = m_FileName.find_last_of( "." ); + std::string fileExt( m_FileName, it+1, m_FileName.length() ); if ( fileExt != std::string("h5") && @@ -209,11 +190,11 @@ bool rtk::NexusHdf5ImageIO::CanReadFile(const char* FileNameToRead) ) return false; // Try opening with HDF5 to verify - hid_t file_id = H5Fopen(filename, H5F_ACC_RDONLY, H5P_DEFAULT); - if (file_id < 0) + try { + H5::H5File file(m_FileName, H5F_ACC_RDONLY); + } catch (H5::FileIException &error) { return false; - - H5Fclose(file_id); + } return true; } //// @@ -222,51 +203,35 @@ bool rtk::NexusHdf5ImageIO::CanReadFile(const char* FileNameToRead) void rtk::NexusHdf5ImageIO::Read(void * buffer) { try { - DataSet dataset = file.openDataSet( + // Open the existing file + H5::H5File file(m_FileName, H5F_ACC_RDONLY); + + H5::DataSet dataset = file.openDataSet( m_PathToData ); - DataSpace dataspace = dataset.getSpace(); + H5::DataSpace dataspace = dataset.getSpace(); int rank = dataspace.getSimpleExtentNdims(); hsize_t dims[3]; dataspace.getSimpleExtentDims(dims, nullptr); // Get the datatype - DataType readType = dataset.getDataType(); - H5T_class_t type_class = dtype.getClass(); + H5::DataType readType = dataset.getDataType(); + H5T_class_t type_class = readType.getClass(); dataset.read(buffer, type_class); dataspace.close(); dataset.close(); file.close(); - } catch (FileIException &error) { - itkExceptionMacro("Cannot open HDF5 file: " << filename); - return 1; - } catch (DataSetIException &error) { - itkExceptionMacro("Dataset error: " << error.getCDetailMsg() << filename); - return 1; - } catch (DataSpaceIException &error) { - itkExceptionError("Dataspace error: " << error.getCDetailMsg()); - return 1; + } catch (H5::FileIException &error) { + itkExceptionMacro("Cannot open HDF5 file: " + m_FileName); + } catch (H5::DataSetIException &error) { + itkExceptionMacro("Dataset error: " + std::string(error.getCDetailMsg()) + m_FileName); + } catch (H5::DataSpaceIException &error) { + itkExceptionMacro("Dataspace error: " + std::string(error.getCDetailMsg())); } - -const std::string filename = this->GetFileName(); - hid_t file_id = H5Fopen(m_FileName.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); - if (file_id < 0) - itkExceptionMacro("Cannot open HDF5 file for reading"); - - hid_t dataset_id = H5Dopen(file_id, "image", H5P_DEFAULT); - if (dataset_id < 0) - itkExceptionMacro("Cannot open dataset 'image'"); - - herr_t status = H5Dread(dataset_id, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buffer); - if (status < 0) - itkExceptionMacro("Error reading HDF5 dataset"); - - H5Dclose(dataset_id); - H5Fclose(file_id);} - +} //-------------------------------------------------------------------- // Write Image Information void rtk::NexusHdf5ImageIO::WriteImageInformation( bool itkNotUsed(keepOfStream) ) diff --git a/common/rtkNexusHdf5ImageIO.h b/common/rtkNexusHdf5ImageIO.h index 622f9de4..ac92479e 100644 --- a/common/rtkNexusHdf5ImageIO.h +++ b/common/rtkNexusHdf5ImageIO.h @@ -76,10 +76,7 @@ class NexusHdf5ImageIO : public itk::ImageIOBase protected: std::string m_Entry; std::string m_PathToData; - std::string m_BinaryFileName; - int m_BinaryFileSkip; - - static char* edf_findInHeader( char* header, const char* key ); + std::string m_FileName; /* List of EDF supported datatypes */ From 83ad9978beb43b81b0528f618c5647235c74424c Mon Sep 17 00:00:00 2001 From: Jerome Lesaint Date: Fri, 7 Nov 2025 22:09:49 +0100 Subject: [PATCH 3/4] Fix NexusHdf5ImageIOFactory.cxx --- common/rtkNexusHdf5ImageIOFactory.cxx | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/common/rtkNexusHdf5ImageIOFactory.cxx b/common/rtkNexusHdf5ImageIOFactory.cxx index e69de29b..e39d0a09 100644 --- a/common/rtkNexusHdf5ImageIOFactory.cxx +++ b/common/rtkNexusHdf5ImageIOFactory.cxx @@ -0,0 +1,29 @@ +/*========================================================================= + * + * Copyright RTK Consortium + * + * 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 + * + * http://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 "rtkNexusHdf5ImageIOFactory.h" + +//==================================================================== +rtk::NexusHdf5ImageIOFactory::NexusHdf5ImageIOFactory() +{ + this->RegisterOverride("itkImageIOBase", + "NexusHdf5ImageIO", + "NexusHdf5 Image IO", + 1, + itk::CreateObjectFunction::New() ); +} From c2543637066479735293d38ab93f1bb3ccef23c0 Mon Sep 17 00:00:00 2001 From: Jerome Lesaint Date: Thu, 13 Nov 2025 11:30:43 +0100 Subject: [PATCH 4/4] Use only H5Cpp and add IOFactory.h --- common/CMakeLists.txt | 11 ----- common/rtkNexusHdf5ImageIO.h | 2 +- common/rtkNexusHdf5ImageIOFactory.h | 77 +++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 12 deletions(-) diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 5b299c48..b1ea6c13 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -18,17 +18,6 @@ set(clitkCommon_SRC clitkXdrImageIOReader.cxx clitkXdrImageIOWriter.cxx clitkXdrImageIOFactory.cxx - rtkHisImageIO.cxx - rtkHisImageIOFactory.cxx - rtkHndImageIO.cxx - rtkHndImageIOFactory.cxx - rtkEdfImageIO.cxx - rtkEdfImageIOFactory.cxx - rtkXRadImageIO.cxx - rtkXRadImageIOFactory.cxx - rtkImagXImageIO.cxx - rtkImagXImageIOFactory.cxx - rtkImagXXMLFileReader.cxx rtkNexusHdf5ImageIO.cxx rtkNexusHdf5ImageIOFactory.cxx clitkEsrfHstImageIO.cxx diff --git a/common/rtkNexusHdf5ImageIO.h b/common/rtkNexusHdf5ImageIO.h index ac92479e..17737de0 100644 --- a/common/rtkNexusHdf5ImageIO.h +++ b/common/rtkNexusHdf5ImageIO.h @@ -23,7 +23,7 @@ #include #include -#include +//#include #include #include "clitkCommon.h" diff --git a/common/rtkNexusHdf5ImageIOFactory.h b/common/rtkNexusHdf5ImageIOFactory.h index e69de29b..992028b9 100644 --- a/common/rtkNexusHdf5ImageIOFactory.h +++ b/common/rtkNexusHdf5ImageIOFactory.h @@ -0,0 +1,77 @@ +/*========================================================================= + * + * Copyright RTK Consortium + * + * 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 + * + * http://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 __rtkNexusHdf5ImageIOFactory_h +#define __rtkNexusHdf5ImageIOFactory_h + +#include "rtkNexusHdf5ImageIO.h" +#include +#include +#include + +namespace rtk +{ + +/** \class NexusHdf5ImageIOFactory + * + * TODO + * + */ +class NexusHdf5ImageIOFactory : public itk::ObjectFactoryBase +{ +public: + /** Standard class typedefs. */ + typedef NexusHdf5ImageIOFactory Self; + typedef itk::ObjectFactoryBase Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Class methods used to interface with the registered factories. */ + const char* GetITKSourceVersion(void) const ITK_OVERRIDE { + return ITK_SOURCE_VERSION; + } + + const char* GetDescription(void) const ITK_OVERRIDE { + return "NexusHdf5 allows the loading of Nexus/Hdf5 images into insight"; + } + + /** Method for class instantiation. */ + itkFactorylessNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(NexusHdf5ImageIOFactory, ObjectFactoryBase); + + /** Register one factory of this type */ + static void RegisterOneFactory(void) { + ObjectFactoryBase::RegisterFactory( Self::New() ); + } + +protected: + NexusHdf5ImageIOFactory(); + ~NexusHdf5ImageIOFactory() {} + typedef NexusHdf5ImageIOFactory myProductType; + const myProductType* m_MyProduct; +private: + NexusHdf5ImageIOFactory(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + +}; + +} // end namespace + +#endif \ No newline at end of file