diff --git a/Core/Code/Common/mitkCommon.h b/Core/Code/Common/mitkCommon.h index 590e46efd6..90e55a2cf9 100644 --- a/Core/Code/Common/mitkCommon.h +++ b/Core/Code/Common/mitkCommon.h @@ -1,145 +1,146 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITK_COMMON_H_DEFINED #define MITK_COMMON_H_DEFINED #ifdef _MSC_VER // This warns about truncation to 255 characters in debug/browse info #pragma warning (disable : 4786) #pragma warning (disable : 4068 ) /* disable unknown pragma warnings */ #endif //add only those headers here that are really necessary for all classes! #include "itkObject.h" #include "mitkConfig.h" #include "mitkLogMacros.h" #include "mitkExportMacros.h" #include "mitkExceptionMacro.h" #ifndef MITK_UNMANGLE_IPPIC #define mitkIpPicDescriptor mitkIpPicDescriptor #endif typedef unsigned int MapperSlotId; #define mitkClassMacro(className,SuperClassName) \ typedef className Self; \ typedef SuperClassName Superclass; \ typedef itk::SmartPointer Pointer; \ typedef itk::SmartPointer ConstPointer; \ + static const char* GetStaticNameOfClass() { return #className; } \ itkTypeMacro(className,SuperClassName) /** * Macro for Constructors with one parameter for classes derived from itk::Lightobject **/ #define mitkNewMacro1Param(classname,type) \ static Pointer New(type _arg) \ { \ Pointer smartPtr = new classname ( _arg ); \ smartPtr->UnRegister(); \ return smartPtr; \ } \ /** * Macro for Constructors with two parameters for classes derived from itk::Lightobject **/ #define mitkNewMacro2Param(classname,typea,typeb) \ static Pointer New(typea _arga, typeb _argb) \ { \ Pointer smartPtr = new classname ( _arga, _argb ); \ smartPtr->UnRegister(); \ return smartPtr; \ } \ /** * Macro for Constructors with three parameters for classes derived from itk::Lightobject **/ #define mitkNewMacro3Param(classname,typea,typeb,typec) \ static Pointer New(typea _arga, typeb _argb, typec _argc) \ { \ Pointer smartPtr = new classname ( _arga, _argb, _argc ); \ smartPtr->UnRegister(); \ return smartPtr; \ } \ /** * Macro for Constructors with four parameters for classes derived from itk::Lightobject **/ #define mitkNewMacro4Param(classname,typea,typeb,typec,typed) \ static Pointer New(typea _arga, typeb _argb, typec _argc, typed _argd) \ { \ Pointer smartPtr = new classname ( _arga, _argb, _argc, _argd ); \ smartPtr->UnRegister(); \ return smartPtr; \ } \ /** * Macro for Constructors with five parameters for classes derived from itk::Lightobject **/ #define mitkNewMacro5Param(classname,typea,typeb,typec,typed,typee) \ static Pointer New(typea _arga, typeb _argb, typec _argc, typed _argd, typee _arge) \ { \ Pointer smartPtr = new classname ( _arga, _argb, _argc, _argd, _arge ); \ smartPtr->UnRegister(); \ return smartPtr; \ } \ /** * Macro for Constructors with six parameters for classes derived from itk::Lightobject **/ #define mitkNewMacro6Param(classname,typea,typeb,typec,typed,typee, typef) \ static Pointer New(typea _arga, typeb _argb, typec _argc, typed _argd, typee _arge, typef _argf) \ { \ Pointer smartPtr = new classname ( _arga, _argb, _argc, _argd, _arge, _argf ); \ smartPtr->UnRegister(); \ return smartPtr; \ } \ /** Get a smart const pointer to an object. Creates the member * Get"name"() (e.g., GetPoints()). */ #define mitkGetObjectMacroConst(name,type) \ virtual type * Get##name () const \ { \ itkDebugMacro("returning " #name " address " << this->m_##name ); \ return this->m_##name.GetPointer(); \ } /** Creates a Clone() method for "Classname". Returns a smartPtr of a clone of the calling object*/ #define mitkCloneMacro(classname) \ virtual itk::LightObject::Pointer InternalClone() const \ { \ Pointer smartPtr = new classname(*this); \ smartPtr->UnRegister(); \ return smartPtr.GetPointer(); \ } /** cross-platform deprecation macro \todo maybe there is something in external toolkits (ITK, VTK,...) that we could reulse -- would be much preferable */ #ifdef MITK_NO_DEPRECATED_WARNINGS #define DEPRECATED(func) func #elif defined(__GNUC__) #define DEPRECATED(...) __VA_ARGS__ __attribute__((deprecated)) #elif defined(_MSC_VER) #define DEPRECATED(...) __declspec(deprecated) ##__VA_ARGS__ #else #pragma message("WARNING: You need to implement DEPRECATED for your compiler!") #define DEPRECATED(func) func #endif #endif // MITK_COMMON_H_DEFINED diff --git a/Core/Code/Common/mitkCoreObjectFactory.cpp b/Core/Code/Common/mitkCoreObjectFactory.cpp index 630b814b15..3f6e32fb5c 100644 --- a/Core/Code/Common/mitkCoreObjectFactory.cpp +++ b/Core/Code/Common/mitkCoreObjectFactory.cpp @@ -1,446 +1,457 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkConfig.h" #include "mitkCoreObjectFactory.h" #include "mitkAffineInteractor.h" #include "mitkColorProperty.h" #include "mitkDataNode.h" #include "mitkEnumerationProperty.h" #include "mitkPlaneGeometryData.h" #include "mitkPlaneGeometryDataMapper2D.h" #include "mitkPlaneGeometryDataVtkMapper3D.h" #include "mitkGeometry3D.h" #include "mitkGeometryData.h" #include "mitkImage.h" #include #include "mitkLevelWindowProperty.h" #include "mitkLookupTable.h" #include "mitkLookupTableProperty.h" #include "mitkPlaneGeometry.h" #include "mitkPointSet.h" #include "mitkPointSetVtkMapper2D.h" #include "mitkPointSetVtkMapper3D.h" #include "mitkProperties.h" #include "mitkPropertyList.h" #include "mitkSlicedGeometry3D.h" #include "mitkSmartPointerProperty.h" #include "mitkStringProperty.h" #include "mitkSurface.h" #include "mitkSurface.h" #include "mitkSurfaceGLMapper2D.h" #include "mitkSurfaceVtkMapper3D.h" #include "mitkTimeGeometry.h" #include "mitkTransferFunctionProperty.h" #include "mitkVolumeDataVtkMapper3D.h" #include "mitkVtkInterpolationProperty.h" #include "mitkVtkRepresentationProperty.h" #include "mitkVtkResliceInterpolationProperty.h" -//#include "mitkPicFileIOFactory.h" -#include "mitkPointSetIOFactory.h" -#include "mitkItkImageFileIOFactory.h" -#include "mitkSTLFileIOFactory.h" -#include "mitkVtkSurfaceIOFactory.h" -#include "mitkVtkImageIOFactory.h" -#include "mitkVtiFileIOFactory.h" -//#include "mitkPicVolumeTimeSeriesIOFactory.h" - -#include "mitkImageWriterFactory.h" -#include "mitkImageWriter.h" -#include "mitkPointSetWriterFactory.h" -#include "mitkSurfaceVtkWriterFactory.h" +// Legacy Support: +#include +#include +#include +#include +#include +#include + void mitk::CoreObjectFactory::RegisterExtraFactory(CoreObjectFactoryBase* factory) { MITK_DEBUG << "CoreObjectFactory: registering extra factory of type " << factory->GetNameOfClass(); m_ExtraFactories.insert(CoreObjectFactoryBase::Pointer(factory)); + // Register Legacy Reader and Writer + this->RegisterLegacyReaders(factory); + this->RegisterLegacyWriters(factory); } void mitk::CoreObjectFactory::UnRegisterExtraFactory(CoreObjectFactoryBase *factory) { MITK_DEBUG << "CoreObjectFactory: un-registering extra factory of type " << factory->GetNameOfClass(); try { m_ExtraFactories.erase(factory); } catch( std::exception const& e) { MITK_ERROR << "Caugt exception while unregistering: " << e.what(); } } mitk::CoreObjectFactory::Pointer mitk::CoreObjectFactory::GetInstance() { static mitk::CoreObjectFactory::Pointer instance; if (instance.IsNull()) { - instance = mitk::CoreObjectFactory::New(); + instance = mitk::CoreObjectFactory::New(); } return instance; } -#include +mitk::CoreObjectFactory::~CoreObjectFactory() +{ + for (std::list< mitk::LegacyFileReaderService* >::iterator it = m_LegacyReaders.begin(); + it != m_LegacyReaders.end(); ++it) + { + delete *it; + } + + for (std::list< mitk::LegacyFileWriterService* >::iterator it = m_LegacyWriters.begin(); + it != m_LegacyWriters.end(); ++it) + { + delete *it; + } +} void mitk::CoreObjectFactory::SetDefaultProperties(mitk::DataNode* node) { if(node==NULL) return; mitk::DataNode::Pointer nodePointer = node; mitk::Image::Pointer image = dynamic_cast(node->GetData()); if(image.IsNotNull() && image->IsInitialized()) { mitk::ImageVtkMapper2D::SetDefaultProperties(node); mitk::VolumeDataVtkMapper3D::SetDefaultProperties(node); } mitk::Surface::Pointer surface = dynamic_cast(node->GetData()); if(surface.IsNotNull()) { mitk::SurfaceGLMapper2D::SetDefaultProperties(node); mitk::SurfaceVtkMapper3D::SetDefaultProperties(node); } mitk::PointSet::Pointer pointSet = dynamic_cast(node->GetData()); if(pointSet.IsNotNull()) { mitk::PointSetVtkMapper2D::SetDefaultProperties(node); mitk::PointSetVtkMapper3D::SetDefaultProperties(node); } for (ExtraFactoriesContainer::iterator it = m_ExtraFactories.begin(); it != m_ExtraFactories.end() ; it++ ) { (*it)->SetDefaultProperties(node); } } mitk::CoreObjectFactory::CoreObjectFactory() - : m_PointSetIOFactory(PointSetIOFactory::New().GetPointer()) - , m_STLFileIOFactory(STLFileIOFactory::New().GetPointer()) - , m_VtkSurfaceIOFactory(VtkSurfaceIOFactory::New().GetPointer()) - , m_VtkImageIOFactory(VtkImageIOFactory::New().GetPointer()) - , m_VtiFileIOFactory(VtiFileIOFactory::New().GetPointer()) - , m_ItkImageFileIOFactory(ItkImageFileIOFactory::New().GetPointer()) - , m_SurfaceVtkWriterFactory(SurfaceVtkWriterFactory::New().GetPointer()) - , m_PointSetWriterFactory(PointSetWriterFactory::New().GetPointer()) - , m_ImageWriterFactory(ImageWriterFactory::New().GetPointer()) { static bool alreadyDone = false; if (!alreadyDone) { - MITK_DEBUG << "CoreObjectFactory c'tor" << std::endl; - - itk::ObjectFactoryBase::RegisterFactory( m_PointSetIOFactory ); - itk::ObjectFactoryBase::RegisterFactory( m_STLFileIOFactory ); - itk::ObjectFactoryBase::RegisterFactory( m_VtkSurfaceIOFactory ); - itk::ObjectFactoryBase::RegisterFactory( m_VtkImageIOFactory ); - itk::ObjectFactoryBase::RegisterFactory( m_VtiFileIOFactory ); - itk::ObjectFactoryBase::RegisterFactory( m_ItkImageFileIOFactory ); - - itk::ObjectFactoryBase::RegisterFactory( m_SurfaceVtkWriterFactory ); - itk::ObjectFactoryBase::RegisterFactory( m_PointSetWriterFactory ); - itk::ObjectFactoryBase::RegisterFactory( m_ImageWriterFactory ); - - m_FileWriters.push_back(mitk::ImageWriter::New().GetPointer()); - CreateFileExtensionsMap(); + RegisterLegacyReaders(this); + RegisterLegacyWriters(this); + alreadyDone = true; } } -mitk::CoreObjectFactory::~CoreObjectFactory() -{ - itk::ObjectFactoryBase::UnRegisterFactory( m_PointSetIOFactory ); - itk::ObjectFactoryBase::UnRegisterFactory( m_STLFileIOFactory ); - itk::ObjectFactoryBase::UnRegisterFactory( m_VtkSurfaceIOFactory ); - itk::ObjectFactoryBase::UnRegisterFactory( m_VtkImageIOFactory ); - itk::ObjectFactoryBase::UnRegisterFactory( m_VtiFileIOFactory ); - itk::ObjectFactoryBase::UnRegisterFactory( m_ItkImageFileIOFactory ); - - itk::ObjectFactoryBase::UnRegisterFactory( m_SurfaceVtkWriterFactory ); - itk::ObjectFactoryBase::UnRegisterFactory( m_PointSetWriterFactory ); - itk::ObjectFactoryBase::UnRegisterFactory( m_ImageWriterFactory ); -} - mitk::Mapper::Pointer mitk::CoreObjectFactory::CreateMapper(mitk::DataNode* node, MapperSlotId id) { mitk::Mapper::Pointer newMapper = NULL; mitk::Mapper::Pointer tmpMapper = NULL; // check whether extra factories provide mapper for (ExtraFactoriesContainer::iterator it = m_ExtraFactories.begin(); it != m_ExtraFactories.end() ; it++ ) { tmpMapper = (*it)->CreateMapper(node,id); if(tmpMapper.IsNotNull()) newMapper = tmpMapper; } if (newMapper.IsNull()) { mitk::BaseData *data = node->GetData(); if ( id == mitk::BaseRenderer::Standard2D ) { if((dynamic_cast(data)!=NULL)) { newMapper = mitk::ImageVtkMapper2D::New(); newMapper->SetDataNode(node); } else if((dynamic_cast(data)!=NULL)) { newMapper = mitk::PlaneGeometryDataMapper2D::New(); newMapper->SetDataNode(node); } else if((dynamic_cast(data)!=NULL)) { newMapper = mitk::SurfaceGLMapper2D::New(); // cast because SetDataNode is not virtual mitk::SurfaceGLMapper2D *castedMapper = dynamic_cast(newMapper.GetPointer()); castedMapper->SetDataNode(node); } else if((dynamic_cast(data)!=NULL)) { newMapper = mitk::PointSetVtkMapper2D::New(); newMapper->SetDataNode(node); } } else if ( id == mitk::BaseRenderer::Standard3D ) { if((dynamic_cast(data) != NULL)) { newMapper = mitk::VolumeDataVtkMapper3D::New(); newMapper->SetDataNode(node); } else if((dynamic_cast(data)!=NULL)) { newMapper = mitk::PlaneGeometryDataVtkMapper3D::New(); newMapper->SetDataNode(node); } else if((dynamic_cast(data)!=NULL)) { newMapper = mitk::SurfaceVtkMapper3D::New(); newMapper->SetDataNode(node); } else if((dynamic_cast(data)!=NULL)) { newMapper = mitk::PointSetVtkMapper3D::New(); newMapper->SetDataNode(node); } } } return newMapper; } -/* -// @deprecated -// -#define EXTERNAL_FILE_EXTENSIONS \ - "All known formats(*.dcm *.DCM *.dc3 *.DC3 *.gdcm *.ima *.mhd *.mps *.nii *.pic *.pic.gz *.bmp *.png *.jpg *.tiff *.pvtk *.stl *.vtk *.vtp *.vtu *.obj *.vti *.hdr *.nrrd *.nhdr );;" \ - "DICOM files(*.dcm *.DCM *.dc3 *.DC3 *.gdcm);;" \ - "DKFZ Pic (*.seq *.pic *.pic.gz *.seq.gz);;" \ - "NRRD Vector Images (*.nrrd *.nhdr);;" \ - "Point sets (*.mps);;" \ - "Sets of 2D slices (*.pic *.pic.gz *.bmp *.png *.dcm *.gdcm *.ima *.tiff);;" \ - "Surface files (*.stl *.vtk *.vtp *.obj);;" \ - "NIfTI format (*.nii)" - -#define SAVE_FILE_EXTENSIONS "all (*.pic *.mhd *.vtk *.vti *.hdr *.png *.tiff *.jpg *.hdr *.bmp *.dcm *.gipl *.nii *.nrrd *.nhdr *.spr *.lsm *.dwi *.hdwi *.qbi *.hqbi)" -*/ - -/** - * @brief This method gets the supported (open) file extensions as string. This string is can then used by the QT QFileDialog widget. - * @return The c-string that contains the file extensions - * - */ const char* mitk::CoreObjectFactory::GetFileExtensions() { MultimapType aMap; for (ExtraFactoriesContainer::iterator it = m_ExtraFactories.begin(); it != m_ExtraFactories.end() ; it++ ) { aMap = (*it)->GetFileExtensionsMap(); this->MergeFileExtensions(m_FileExtensionsMap, aMap); } this->CreateFileExtensions(m_FileExtensionsMap, m_FileExtensions); return m_FileExtensions.c_str(); } -/** - * @brief Merge the input map into the fileExtensionsMap. Duplicate entries are removed - * @param fileExtensionsMap the existing map, it contains value pairs like ("*.dcm", "DICOM files"),("*.dc3", "DICOM files"). - * This map is extented/merged with the values from the input map. - * @param inputMap the input map, it contains value pairs like ("*.dcm", "DICOM files"),("*.dc3", "DICOM files") returned by - * the extra factories. - * - */ void mitk::CoreObjectFactory::MergeFileExtensions(MultimapType& fileExtensionsMap, MultimapType inputMap) { bool duplicateFound = false; std::pair pairOfIter; for (MultimapType::iterator it = inputMap.begin(); it != inputMap.end(); ++it) { duplicateFound = false; pairOfIter = fileExtensionsMap.equal_range((*it).first); for (MultimapType::iterator it2 = pairOfIter.first; it2 != pairOfIter.second; ++it2) { //cout << " [" << (*it).first << ", " << (*it).second << "]" << endl; std::string aString = (*it2).second; if (aString.compare((*it).second) == 0) { //cout << " DUP!! [" << (*it).first << ", " << (*it).second << "]" << endl; duplicateFound = true; break; } } if (!duplicateFound) { fileExtensionsMap.insert(std::pair((*it).first, (*it).second)); } } } -/** - * @brief get the defined (open) file extension map - * @return the defined (open) file extension map - */ mitk::CoreObjectFactoryBase::MultimapType mitk::CoreObjectFactory::GetFileExtensionsMap() { return m_FileExtensionsMap; } -/** - * @brief initialize the file extension entries for open and save - */ void mitk::CoreObjectFactory::CreateFileExtensionsMap() { m_FileExtensionsMap.insert(std::pair("*.dcm", "DICOM files")); m_FileExtensionsMap.insert(std::pair("*.DCM", "DICOM files")); m_FileExtensionsMap.insert(std::pair("*.dc3", "DICOM files")); m_FileExtensionsMap.insert(std::pair("*.DC3", "DICOM files")); m_FileExtensionsMap.insert(std::pair("*.gdcm", "DICOM files")); m_FileExtensionsMap.insert(std::pair("*.seq", "DKFZ Pic")); m_FileExtensionsMap.insert(std::pair("*.pic", "DKFZ Pic")); m_FileExtensionsMap.insert(std::pair("*.pic.gz", "DKFZ Pic")); m_FileExtensionsMap.insert(std::pair("*.mhd", "MetaImage")); m_FileExtensionsMap.insert(std::pair("*.seq.gz", "DKFZ Pic")); m_FileExtensionsMap.insert(std::pair("*.hdr", "Analyze Format")); m_FileExtensionsMap.insert(std::pair("*.img", "Analyze Format")); m_FileExtensionsMap.insert(std::pair("*.img.gz", "Analyze Format")); m_FileExtensionsMap.insert(std::pair("*.nrrd", "Nearly Raw Raster Data")); m_FileExtensionsMap.insert(std::pair("*.nhdr", "NRRD with detached header")); m_FileExtensionsMap.insert(std::pair("*.mps", "Point sets")); m_FileExtensionsMap.insert(std::pair("*.pic", "Sets of 2D slices")); m_FileExtensionsMap.insert(std::pair("*.pic.gz", "Sets of 2D slices")); m_FileExtensionsMap.insert(std::pair("*.bmp", "Sets of 2D slices")); m_FileExtensionsMap.insert(std::pair("*.png", "Sets of 2D slices")); m_FileExtensionsMap.insert(std::pair("*.jpg", "Sets of 2D slices")); m_FileExtensionsMap.insert(std::pair("*.jpeg", "Sets of 2D slices")); m_FileExtensionsMap.insert(std::pair("*.dcm", "Sets of 2D slices")); m_FileExtensionsMap.insert(std::pair("*.gdcm", "Sets of 2D slices")); m_FileExtensionsMap.insert(std::pair("*.ima", "Sets of 2D slices")); m_FileExtensionsMap.insert(std::pair("*.tiff", "Sets of 2D slices")); m_FileExtensionsMap.insert(std::pair("*.tif", "Sets of 2D slices")); m_FileExtensionsMap.insert(std::pair("*.stl", "Surface files")); m_FileExtensionsMap.insert(std::pair("*.vtk", "Surface files")); m_FileExtensionsMap.insert(std::pair("*.vtp", "Surface files")); m_FileExtensionsMap.insert(std::pair("*.obj", "Surface files")); m_FileExtensionsMap.insert(std::pair("*.nii", "NIfTI format")); m_FileExtensionsMap.insert(std::pair("*.nii.gz", "NIfTI format")); m_FileExtensionsMap.insert(std::pair("*.gipl", "UMDS GIPL Format Files")); m_FileExtensionsMap.insert(std::pair("*.gipl.gz", "UMDS GIPL Format Files")); //m_SaveFileExtensionsMap.insert(std::pair("*.pic", "DKFZ Pic")); m_SaveFileExtensionsMap.insert(std::pair("*.mhd", "MetaImage")); m_SaveFileExtensionsMap.insert(std::pair("*.vtk", "Surface Files")); m_SaveFileExtensionsMap.insert(std::pair("*.vti", "VTK Image Data Files")); m_SaveFileExtensionsMap.insert(std::pair("*.hdr", "Analyze Format")); m_SaveFileExtensionsMap.insert(std::pair("*.png", "Sets of 2D slices")); m_SaveFileExtensionsMap.insert(std::pair("*.tiff", "Sets of 2D slices")); m_SaveFileExtensionsMap.insert(std::pair("*.tif", "Sets of 2D slices")); m_SaveFileExtensionsMap.insert(std::pair("*.jpg", "Sets of 2D slices")); m_SaveFileExtensionsMap.insert(std::pair("*.jpeg", "Sets of 2D slices")); m_SaveFileExtensionsMap.insert(std::pair("*.bmp", "Sets of 2D slices")); m_SaveFileExtensionsMap.insert(std::pair("*.dcm", "Sets of 2D slices")); m_SaveFileExtensionsMap.insert(std::pair("*.gipl", "UMDS GIPL Format Files")); m_SaveFileExtensionsMap.insert(std::pair("*.gipl.gz", "UMDS compressed GIPL Format Files")); m_SaveFileExtensionsMap.insert(std::pair("*.nii", "NIfTI format")); m_SaveFileExtensionsMap.insert(std::pair("*.nii.gz", "NIfTI compressed format")); m_SaveFileExtensionsMap.insert(std::pair("*.nrrd", "Nearly Raw Raster Data")); m_SaveFileExtensionsMap.insert(std::pair("*.nhdr", "NRRD with detached header")); m_SaveFileExtensionsMap.insert(std::pair("*.lsm", "Microscope Images")); m_SaveFileExtensionsMap.insert(std::pair("*.dwi", "Diffusion Weighted Images")); m_SaveFileExtensionsMap.insert(std::pair("*.hdwi", "Diffusion Weighted Images")); m_SaveFileExtensionsMap.insert(std::pair("*.qbi", "Q-Ball Images")); m_SaveFileExtensionsMap.insert(std::pair("*.hqbi", "Q-Ball Images")); } -/** - * @brief This method gets the supported (save) file extensions as string. This string is can then used by the QT QFileDialog widget. - * @return The c-string that contains the (save) file extensions - * - */ const char* mitk::CoreObjectFactory::GetSaveFileExtensions() { MultimapType aMap; for (ExtraFactoriesContainer::iterator it = m_ExtraFactories.begin(); it != m_ExtraFactories.end() ; it++ ) { aMap = (*it)->GetSaveFileExtensionsMap(); this->MergeFileExtensions(m_SaveFileExtensionsMap, aMap); } this->CreateFileExtensions(m_SaveFileExtensionsMap, m_SaveFileExtensions); return m_SaveFileExtensions.c_str(); -}; +} -/** - * @brief get the defined (save) file extension map - * @return the defined (save) file extension map - */ mitk::CoreObjectFactoryBase::MultimapType mitk::CoreObjectFactory::GetSaveFileExtensionsMap() { return m_SaveFileExtensionsMap; } mitk::CoreObjectFactory::FileWriterList mitk::CoreObjectFactory::GetFileWriters() { FileWriterList allWriters = m_FileWriters; //sort to merge lists later on typedef std::set FileWriterSet; FileWriterSet fileWritersSet; fileWritersSet.insert(allWriters.begin(), allWriters.end()); //collect all extra factories for (ExtraFactoriesContainer::iterator it = m_ExtraFactories.begin(); it != m_ExtraFactories.end(); it++ ) { FileWriterList list2 = (*it)->GetFileWriters(); //add them to the sorted set fileWritersSet.insert(list2.begin(), list2.end()); } //write back to allWriters to return a list allWriters.clear(); allWriters.insert(allWriters.end(), fileWritersSet.begin(), fileWritersSet.end()); return allWriters; } -void mitk::CoreObjectFactory::MapEvent(const mitk::Event*, const int) { +void mitk::CoreObjectFactory::MapEvent(const mitk::Event*, const int) +{ +} +std::string mitk::CoreObjectFactory::GetDescriptionForExtension(const std::string& extension) +{ + std::multimap fileExtensionMap = GetSaveFileExtensionsMap(); + for(std::multimap::iterator it = fileExtensionMap.begin(); it != fileExtensionMap.end(); it++) + if (it->first == extension) return it->second; + return ""; // If no matching extension was found, return emtpy string } +void mitk::CoreObjectFactory::RegisterLegacyReaders(mitk::CoreObjectFactoryBase* factory) +{ + // We are not really interested in the string, just call the method since + // many readers initialize the map the first time when this method is called + factory->GetFileExtensions(); + + std::map > extensionsByCategories; + std::multimap fileExtensionMap = factory->GetFileExtensionsMap(); + for(std::multimap::iterator it = fileExtensionMap.begin(); it != fileExtensionMap.end(); it++) + { + std::string extension = it->first; + // remove "*." + extension = extension.erase(0,2); + + extensionsByCategories[it->second].push_back(extension); + } + + for(std::map >::iterator iter = extensionsByCategories.begin(), + endIter = extensionsByCategories.end(); iter != endIter; ++iter) + { + m_LegacyReaders.push_back(new mitk::LegacyFileReaderService(iter->second, iter->first)); + } +} + +void mitk::CoreObjectFactory::RegisterLegacyWriters(mitk::CoreObjectFactoryBase* factory) +{ + // Get all external Writers + mitk::CoreObjectFactory::FileWriterList writers = factory->GetFileWriters(); + + // We are not really interested in the string, just call the method since + // many writers initialize the map the first time when this method is called + factory->GetSaveFileExtensions(); + + MultimapType fileExtensionMap = factory->GetSaveFileExtensionsMap(); + +// for(mitk::CoreObjectFactory::FileWriterList::iterator it = writers.begin(); it != writers.end(); it++) +// { +// std::vector extensions = (*it)->GetPossibleFileExtensions(); +// for(std::vector::iterator ext = extensions.begin(); ext != extensions.end(); ext++) +// { +// if (ext->empty()) continue; + +// std::string extension = *ext; +// std::string extensionWithStar = extension; +// if (extension.find_first_of('*') == 0) +// { +// // remove "*." +// extension = extension.substr(0, extension.size()-2); +// } +// else +// { +// extensionWithStar.insert(extensionWithStar.begin(), '*'); +// } + +// std::string description; +// for(MultimapType::iterator fileExtensionIter = fileExtensionMap.begin(); +// fileExtensionIter != fileExtensionMap.end(); fileExtensionIter++) +// { +// if (fileExtensionIter->first == extensionWithStar) +// { +// description = fileExtensionIter->second; +// break; +// } +// } + +// //extension = extension.erase(0,1); +// std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); +// mitk::LegacyFileWriterService* lfws = new mitk::LegacyFileWriterService(*it, "LegacyDataType", extension, description); +// m_LegacyWriters.push_back(lfws); +// } +// } +} diff --git a/Core/Code/Common/mitkCoreObjectFactory.h b/Core/Code/Common/mitkCoreObjectFactory.h index 585a3e9175..e3a98cf9fd 100644 --- a/Core/Code/Common/mitkCoreObjectFactory.h +++ b/Core/Code/Common/mitkCoreObjectFactory.h @@ -1,76 +1,145 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef COREOBJECTFACTORY_H_INCLUDED #define COREOBJECTFACTORY_H_INCLUDED #include #include #include "mitkCoreObjectFactoryBase.h" #include "mitkFileWriterWithInformation.h" namespace mitk { class Event; +class LegacyFileReaderService; +class LegacyFileWriterService; +class LegacyImageWriterService; class MITK_CORE_EXPORT CoreObjectFactory : public CoreObjectFactoryBase { - public: - mitkClassMacro(CoreObjectFactory,CoreObjectFactoryBase); - itkFactorylessNewMacro(CoreObjectFactory); - virtual Mapper::Pointer CreateMapper(mitk::DataNode* node, MapperSlotId slotId); - virtual void SetDefaultProperties(mitk::DataNode* node); - virtual const char* GetFileExtensions(); - virtual MultimapType GetFileExtensionsMap(); - virtual const char* GetSaveFileExtensions(); - virtual MultimapType GetSaveFileExtensionsMap(); - virtual FileWriterList GetFileWriters(); - virtual void MapEvent(const mitk::Event* event, const int eventID); - virtual void RegisterExtraFactory(CoreObjectFactoryBase* factory); - virtual void UnRegisterExtraFactory(CoreObjectFactoryBase* factory); - static Pointer GetInstance(); - - ~CoreObjectFactory(); - - protected: - - CoreObjectFactory(); - void MergeFileExtensions(MultimapType& fileExtensionsMap, MultimapType inputMap); - void CreateFileExtensionsMap(); - void CreateSaveFileExtensions(); - typedef std::set ExtraFactoriesContainer; - - ExtraFactoriesContainer m_ExtraFactories; - std::string m_FileExtensions; - MultimapType m_FileExtensionsMap; - std::string m_SaveFileExtensions; - MultimapType m_SaveFileExtensionsMap; - - itk::ObjectFactoryBase::Pointer m_PointSetIOFactory; - itk::ObjectFactoryBase::Pointer m_STLFileIOFactory; - itk::ObjectFactoryBase::Pointer m_VtkSurfaceIOFactory; - itk::ObjectFactoryBase::Pointer m_VtkImageIOFactory; - itk::ObjectFactoryBase::Pointer m_VtiFileIOFactory; - itk::ObjectFactoryBase::Pointer m_ItkImageFileIOFactory; - - itk::ObjectFactoryBase::Pointer m_SurfaceVtkWriterFactory; - itk::ObjectFactoryBase::Pointer m_PointSetWriterFactory; - itk::ObjectFactoryBase::Pointer m_ImageWriterFactory; +public: + + mitkClassMacro(CoreObjectFactory,CoreObjectFactoryBase) + itkFactorylessNewMacro(CoreObjectFactory) + + virtual Mapper::Pointer CreateMapper(mitk::DataNode* node, MapperSlotId slotId); + virtual void SetDefaultProperties(mitk::DataNode* node); + + virtual void MapEvent(const mitk::Event* event, const int eventID); + + virtual void RegisterExtraFactory(CoreObjectFactoryBase* factory); + virtual void UnRegisterExtraFactory(CoreObjectFactoryBase* factory); + + static Pointer GetInstance(); + + ~CoreObjectFactory(); + + /** + * @brief This method gets the supported (open) file extensions as string. + * + * This string can then used by the Qt QFileDialog widget. + * + * @return The c-string that contains the file extensions + * @deprecatedSince{2014_03} See mitk::FileReaderRegistry and QmitkIOUtil + */ + DEPRECATED(virtual const char* GetFileExtensions()); + + /** + * @brief get the defined (open) file extension map + * + * @return the defined (open) file extension map + * @deprecatedSince{2014_03} See mitk::FileReaderRegistry and QmitkIOUtil + */ + DEPRECATED(virtual MultimapType GetFileExtensionsMap()); + + /** + * @brief This method gets the supported (save) file extensions as string. + * + * This string can then used by the Qt QFileDialog widget. + * + * @return The c-string that contains the (save) file extensions + * @deprecatedSince{2014_03} See mitk::FileWriterRegistry and QmitkIOUtil + */ + DEPRECATED(virtual const char* GetSaveFileExtensions()); + + /** + * @brief get the defined (save) file extension map + * + * @return the defined (save) file extension map + * @deprecatedSince{2014_03} See mitk::FileWriterRegistry and QmitkIOUtil + */ + virtual MultimapType GetSaveFileExtensionsMap(); + + /** + * @deprecatedSince{2014_03} See mitk::FileWriterRegistry + */ + DEPRECATED(virtual FileWriterList GetFileWriters()); + + /** + * @deprecatedSince{2014_03} See mitk::FileWriterRegistry and QmitkIOUtil + */ + DEPRECATED(std::string GetDescriptionForExtension(const std::string& extension)); + +protected: + + CoreObjectFactory(); + + /** + * @brief Merge the input map into the fileExtensionsMap. Duplicate entries are removed + * + * @param fileExtensionsMap the existing map, it contains value pairs like + * ("*.dcm", "DICOM files"),("*.dc3", "DICOM files"). + * This map is extented/merged with the values from the input map. + * @param inputMap the input map, it contains value pairs like ("*.dcm", + * "DICOM files"),("*.dc3", "DICOM files") returned by the extra factories. + * @deprecatedSince{2014_03} + */ + void MergeFileExtensions(MultimapType& fileExtensionsMap, MultimapType inputMap); + + /** + * @brief initialize the file extension entries for open and save + * @deprecatedSince{2014_03} + */ + void CreateFileExtensionsMap(); + + /** + * @deprecatedSince{2014_03} + */ + DEPRECATED(void CreateSaveFileExtensions()); + + typedef std::set ExtraFactoriesContainer; + + ExtraFactoriesContainer m_ExtraFactories; + FileWriterList m_FileWriters; + std::string m_FileExtensions; + MultimapType m_FileExtensionsMap; + std::string m_SaveFileExtensions; + MultimapType m_SaveFileExtensionsMap; + +private: + + void RegisterLegacyReaders(mitk::CoreObjectFactoryBase* factory); + void RegisterLegacyWriters(mitk::CoreObjectFactoryBase* factory); + + std::list< mitk::LegacyFileReaderService* > m_LegacyReaders; + std::list< mitk::LegacyFileWriterService* > m_LegacyWriters; + }; } // namespace mitk #endif diff --git a/Core/Code/Common/mitkCoreObjectFactoryBase.h b/Core/Code/Common/mitkCoreObjectFactoryBase.h index 362c278481..eeede7eb5c 100644 --- a/Core/Code/Common/mitkCoreObjectFactoryBase.h +++ b/Core/Code/Common/mitkCoreObjectFactoryBase.h @@ -1,78 +1,107 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef COREOBJECTFACTORYBASE_H_INCLUDED #define COREOBJECTFACTORYBASE_H_INCLUDED // the mbilog header is necessary for CMake test drivers. // Since the EXTRA_INCLUDE parameter of CREATE_TEST_SOURCELIST only // allows one extra include file, we specify mitkLog.h here so it will // be available to all classes implementing this interface. #include "mitkLog.h" #include #include "mitkMapper.h" #include #include #include "mitkFileWriterWithInformation.h" namespace mitk { class DataNode; //## @brief base-class for factories of certain mitk objects. //## @ingroup Algorithms //## This interface can be implemented by factories which add new mapper classes or extend the //## data tree deserialization mechanism. class MITK_CORE_EXPORT CoreObjectFactoryBase : public itk::Object { public: + typedef std::list FileWriterList; typedef std::multimap MultimapType; - mitkClassMacro(CoreObjectFactoryBase,itk::Object); + + mitkClassMacro(CoreObjectFactoryBase,itk::Object) + virtual Mapper::Pointer CreateMapper(mitk::DataNode* node, MapperSlotId slotId) = 0; virtual void SetDefaultProperties(mitk::DataNode* node) = 0; + + /** + * @deprecatedSince{2014_03} See mitk::FileReaderRegistry and QmitkIOUtil + */ virtual const char* GetFileExtensions() = 0; + + /** + * @deprecatedSince{2014_03} See mitk::FileReaderRegistry and QmitkIOUtil + */ virtual MultimapType GetFileExtensionsMap() = 0; + + /** + * @deprecatedSince{2014_03} See mitk::FileWriterRegistry and QmitkIOUtil + */ virtual const char* GetSaveFileExtensions() = 0; + + /** + * @deprecatedSince{2014_03} See mitk::FileWriterRegistry and QmitkIOUtil + */ virtual MultimapType GetSaveFileExtensionsMap() = 0; + virtual const char* GetITKSourceVersion() const { return ITK_SOURCE_VERSION; } virtual const char* GetDescription() const { return "Core Object Factory"; } - FileWriterList GetFileWriters() { + + /** + * @deprecatedSince{2014_03} See mitk::FileWriterRegistry + */ + FileWriterList GetFileWriters() + { return m_FileWriters; } protected: /** * @brief create a string from a map that contains the file extensions * @param fileExtensionsMap input map with the file extensions, e.g. ("*.dcm", "DICOM files")("*.dc3", "DICOM files") * @param fileExtensions the converted output string, suitable for the QT QFileDialog widget * e.g. "all (*.dcm *.DCM *.dc3 ... *.vti *.hdr *.nrrd *.nhdr );;Q-Ball Images (*.hqbi *qbi)" + * + * @deprecatedSince{2014_03} */ static void CreateFileExtensions(MultimapType fileExtensionsMap, std::string& fileExtensions); FileWriterList m_FileWriters; + + friend class CoreObjectFactory; }; } #endif diff --git a/Core/Code/Common/mitkCoreServices.cpp b/Core/Code/Common/mitkCoreServices.cpp index ecdafcc32c..870f74185a 100644 --- a/Core/Code/Common/mitkCoreServices.cpp +++ b/Core/Code/Common/mitkCoreServices.cpp @@ -1,108 +1,123 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkCoreServices.h" +#include #include #include #include #include #include #include #include #include #include #include #include namespace mitk { -static itk::SimpleFastMutexLock s_ContextToServicesMapMutex; -static std::map > s_ContextToServicesMap; +itk::SimpleFastMutexLock& s_ContextToServicesMapMutex() +{ + static itk::SimpleFastMutexLock mutex; + return mutex; +} + +std::map >& s_ContextToServicesMap() +{ + static std::map > serviceMap; + return serviceMap; +} template static S* GetCoreService(us::ModuleContext* context) { - itk::MutexLockHolder l(s_ContextToServicesMapMutex); + itk::MutexLockHolder l(s_ContextToServicesMapMutex()); S* coreService = NULL; us::ServiceReference serviceRef = context->GetServiceReference(); if (serviceRef) { coreService = context->GetService(serviceRef); } assert(coreService && "Asserting non-NULL MITK core service"); - s_ContextToServicesMap[context].insert(std::make_pair(coreService,serviceRef)); + s_ContextToServicesMap()[context].insert(std::make_pair(coreService,serviceRef)); return coreService; } IShaderRepository* CoreServices::GetShaderRepository() { static us::ServiceTracker tracker(us::GetModuleContext()); tracker.Open(); return tracker.GetService(); } IPropertyAliases* CoreServices::GetPropertyAliases(us::ModuleContext* context) { return GetCoreService(context); } IPropertyDescriptions* CoreServices::GetPropertyDescriptions(us::ModuleContext* context) { return GetCoreService(context); } IPropertyExtensions* CoreServices::GetPropertyExtensions(us::ModuleContext* context) { return GetCoreService(context); } IPropertyFilters* CoreServices::GetPropertyFilters(us::ModuleContext* context) { return GetCoreService(context); } +IMimeTypeProvider* CoreServices::GetMimeTypeProvider(us::ModuleContext* context) +{ + return GetCoreService(context); +} + bool CoreServices::Unget(us::ModuleContext* context, const std::string& /*interfaceId*/, void* service) { bool success = false; - itk::MutexLockHolder l(s_ContextToServicesMapMutex); - std::map >::iterator iter = s_ContextToServicesMap.find(context); - if (iter != s_ContextToServicesMap.end()) + itk::MutexLockHolder l(s_ContextToServicesMapMutex()); + std::map >::iterator iter = s_ContextToServicesMap().find(context); + if (iter != s_ContextToServicesMap().end()) { std::map::iterator iter2 = iter->second.find(service); if (iter2 != iter->second.end()) { us::ServiceReferenceU serviceRef = iter2->second; if (serviceRef) { success = context->UngetService(serviceRef); if (success) { iter->second.erase(iter2); } } } } return success; } } diff --git a/Core/Code/Common/mitkCoreServices.h b/Core/Code/Common/mitkCoreServices.h index 3d27bb9d0f..752f5b7119 100644 --- a/Core/Code/Common/mitkCoreServices.h +++ b/Core/Code/Common/mitkCoreServices.h @@ -1,170 +1,178 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKCORESERVICES_H #define MITKCORESERVICES_H #include "MitkCoreExports.h" #include #include #include #include #include #include namespace mitk { +struct IMimeTypeProvider; struct IShaderRepository; class IPropertyAliases; class IPropertyDescriptions; class IPropertyExtensions; class IPropertyFilters; /** * @brief Access MITK core services. * * This class can be used to conveniently access common * MITK Core service objects. Some getter methods where implementations * exist in the core library are guaranteed to return a non-NULL service object. * * To ensure that CoreServices::Unget() is called after the caller * has finished using a service object, you should use the CoreServicePointer * helper class which calls Unget() when it goes out of scope: * * \code * CoreServicePointer shaderRepo(CoreServices::GetShaderRepository()); * // Do something with shaderRepo * \endcode * * @see CoreServicePointer */ class MITK_CORE_EXPORT CoreServices { public: /** * @brief Get an IShaderRepository instance. * @param context The module context of the module getting the service. * @return A IShaderRepository instance which can be NULL. */ static IShaderRepository* GetShaderRepository(); /** * @brief Get an IPropertyAliases instance. * @param context The module context of the module getting the service. * @return A non-NULL IPropertyAliases instance. */ static IPropertyAliases* GetPropertyAliases(us::ModuleContext* context = us::GetModuleContext()); /** * @brief Get an IPropertyDescriptions instance. * @param context The module context of the module getting the service. * @return A non-NULL IPropertyDescriptions instance. */ static IPropertyDescriptions* GetPropertyDescriptions(us::ModuleContext* context = us::GetModuleContext()); /** * @brief Get an IPropertyExtensions instance. * @param context The module context of the module getting the service. * @return A non-NULL IPropertyExtensions instance. */ static IPropertyExtensions* GetPropertyExtensions(us::ModuleContext* context = us::GetModuleContext()); /** * @brief Get an IPropertyFilters instance. * @param context The module context of the module getting the service. * @return A non-NULL IPropertyFilters instance. */ static IPropertyFilters* GetPropertyFilters(us::ModuleContext* context = us::GetModuleContext()); + /** + * @brief Get an IMimeTypeProvider instance. + * @param context The module context of the module getting the service. + * @return A non-NULL IMimeTypeProvider instance. + */ + static IMimeTypeProvider* GetMimeTypeProvider(us::ModuleContext* context = us::GetModuleContext()); + /** * @brief Unget a previously acquired service instance. * @param service The service instance to be released. * @return \c true if ungetting the service was successful, \c false otherwise. */ template static bool Unget(S* service, us::ModuleContext* context = us::GetModuleContext()) { return Unget(context, us_service_interface_iid(), service); } private: static bool Unget(us::ModuleContext* context, const std::string& interfaceId, void* service); // purposely not implemented CoreServices(); CoreServices(const CoreServices&); CoreServices& operator=(const CoreServices&); }; /** * @brief A RAII helper class for core service objects. * * This is class is intended for usage in local scopes; it calls * CoreServices::Unget(S*) in its destructor. You should not construct * multiple CoreServicePointer instances using the same service pointer, * unless it is retrieved by a new call to a CoreServices getter method. * * @see CoreServices */ template class CoreServicePointer { public: explicit CoreServicePointer(S* service) : m_service(service) { assert(m_service); } ~CoreServicePointer() { try { CoreServices::Unget(m_service); } catch (const std::exception& e) { MITK_ERROR << e.what(); } catch (...) { MITK_ERROR << "Ungetting core service failed."; } } S* operator->() const { return m_service; } private: // purposely not implemented CoreServicePointer(const CoreServicePointer&); CoreServicePointer& operator=(const CoreServicePointer&); S* const m_service; }; } #endif // MITKCORESERVICES_H diff --git a/Core/Code/IO/mitkLookupTableProperty.cpp b/Core/Code/DataManagement/mitkLookupTableProperty.cpp old mode 100755 new mode 100644 similarity index 100% rename from Core/Code/IO/mitkLookupTableProperty.cpp rename to Core/Code/DataManagement/mitkLookupTableProperty.cpp diff --git a/Core/Code/IO/mitkLookupTableProperty.h b/Core/Code/DataManagement/mitkLookupTableProperty.h old mode 100755 new mode 100644 similarity index 100% rename from Core/Code/IO/mitkLookupTableProperty.h rename to Core/Code/DataManagement/mitkLookupTableProperty.h diff --git a/Core/Code/IO/mitkAbstractFileReader.cpp b/Core/Code/IO/mitkAbstractFileReader.cpp new file mode 100644 index 0000000000..96cd0898a6 --- /dev/null +++ b/Core/Code/IO/mitkAbstractFileReader.cpp @@ -0,0 +1,411 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include + +namespace mitk { + +class AbstractFileReader::Impl +{ +public: + + Impl() + : m_Ranking(0) + , m_PrototypeFactory(NULL) + {} + + Impl(const Impl& other) + : m_MimeType(other.m_MimeType) + , m_Category(other.m_Category) + , m_Extensions(other.m_Extensions) + , m_Description(other.m_Description) + , m_Ranking(other.m_Ranking) + , m_Options(other.m_Options) + , m_PrototypeFactory(NULL) + {} + + // Minimal Service Properties: ALWAYS SET THESE IN CONSTRUCTOR OF DERIVED CLASSES! + std::string m_MimeType; + std::string m_Category; + std::vector m_Extensions; + std::string m_Description; + int m_Ranking; + + /** + * \brief Options supported by this reader. Set sensible default values! + * + * Can be left emtpy if no special options are required. + */ + IFileReader::OptionList m_Options; + + us::PrototypeServiceFactory* m_PrototypeFactory; + + mitk::Message1 m_ProgressMessage; + + mitk::SimpleMimeType m_SimpleMimeType; + us::ServiceRegistration m_MimeTypeReg; +}; + + +AbstractFileReader::AbstractFileReader() + : d(new Impl) +{ +} + +AbstractFileReader::~AbstractFileReader() +{ + delete d->m_PrototypeFactory; + + if (d->m_MimeTypeReg) + { + d->m_MimeTypeReg.Unregister(); + } +} + +AbstractFileReader::AbstractFileReader(const AbstractFileReader& other) + : d(new Impl(*other.d.get())) +{ +} + +AbstractFileReader::AbstractFileReader(const MimeType& mimeType, const std::string& description) + : d(new Impl) +{ + d->m_MimeType = mimeType; + d->m_Description = description; +} + +AbstractFileReader::AbstractFileReader(const std::string& extension, const std::string& description) + : d(new Impl) +{ + d->m_Description = description; + + d->m_Extensions.push_back(extension); +} + +////////////////////// Reading ///////////////////////// + +std::vector > AbstractFileReader::Read(const std::string& path) +{ + if (!itksys::SystemTools::FileExists(path.c_str())) + mitkThrow() << "File '" + path + "' not found."; + std::ifstream stream; + stream.open(path.c_str()); + return this->Read(stream); +} + +std::vector > AbstractFileReader::Read(std::istream& stream) +{ + // Create a temporary file and copy the data to it + std::ofstream tmpOutputStream; + std::string tmpFilePath = IOUtil::CreateTemporaryFile(tmpOutputStream); + tmpOutputStream << stream.rdbuf(); + tmpOutputStream.close(); + + // Now read from the temporary file + std::vector > result = this->Read(tmpFilePath); + std::remove(tmpFilePath.c_str()); + return result; +} + +std::vector,bool> > AbstractFileReader::Read(const std::string& path, DataStorage& /*ds*/) +{ + std::vector > result; + std::vector data = this->Read(path); + for (std::vector::iterator iter = data.begin(); + iter != data.end(); ++iter) + { + result.push_back(std::make_pair(*iter, false)); + } + return result; +} + +std::vector,bool> > AbstractFileReader::Read(std::istream& stream, DataStorage& /*ds*/) +{ + std::vector > result; + std::vector data = this->Read(stream); + for (std::vector::iterator iter = data.begin(); + iter != data.end(); ++iter) + { + result.push_back(std::make_pair(*iter, false)); + } + return result; +} + +//////////// µS Registration & Properties ////////////// + +us::ServiceRegistration AbstractFileReader::RegisterService(us::ModuleContext* context) +{ + if (d->m_PrototypeFactory) return us::ServiceRegistration(); + + if(context == NULL) + { + context = us::GetModuleContext(); + } + + d->m_MimeTypeReg = this->RegisterMimeType(context); + + if (this->GetMimeType().empty()) + { + MITK_WARN << "Not registering reader " << typeid(this).name() << " due to empty MIME type."; + return us::ServiceRegistration(); + } + + struct PrototypeFactory : public us::PrototypeServiceFactory + { + AbstractFileReader* const m_Prototype; + + PrototypeFactory(AbstractFileReader* prototype) + : m_Prototype(prototype) + {} + + us::InterfaceMap GetService(us::Module* /*module*/, const us::ServiceRegistrationBase& /*registration*/) + { + return us::MakeInterfaceMap(m_Prototype->Clone()); + } + + void UngetService(us::Module* /*module*/, const us::ServiceRegistrationBase& /*registration*/, + const us::InterfaceMap& service) + { + delete us::ExtractInterface(service); + } + }; + + d->m_PrototypeFactory = new PrototypeFactory(this); + us::ServiceProperties props = this->GetServiceProperties(); + return context->RegisterService(d->m_PrototypeFactory, props); +} + +us::ServiceProperties AbstractFileReader::GetServiceProperties() const +{ + if ( d->m_Description.empty() ) + MITK_WARN << "Registered a Reader with no description defined. Reader will have no human readable extension information.)"; + + us::ServiceProperties result; + + result[IFileReader::PROP_DESCRIPTION()] = this->GetDescription(); + result[IFileReader::PROP_MIMETYPE()] = this->GetMimeType(); + result[us::ServiceConstants::SERVICE_RANKING()] = this->GetRanking(); + + for (IFileReader::OptionList::const_iterator it = d->m_Options.begin(); it != d->m_Options.end(); ++it) { + if (it->second) + result[it->first] = std::string("true"); + else result[it->first] = std::string("false"); + } + return result; +} + +us::ServiceRegistration AbstractFileReader::RegisterMimeType(us::ModuleContext* context) +{ + if (context == NULL) throw std::invalid_argument("The context argument must not be NULL."); + + const std::string mimeType = this->GetMimeType(); + std::vector extensions = this->GetExtensions(); + const std::string primaryExtension = extensions.empty() ? "" : extensions.front(); + std::sort(extensions.begin(), extensions.end()); + extensions.erase(std::unique(extensions.begin(), extensions.end()), extensions.end()); + + us::ServiceProperties props; + + props[IMimeType::PROP_ID()] = mimeType; + props[IMimeType::PROP_CATEGORY()] = this->GetCategory(); + props[IMimeType::PROP_EXTENSIONS()] = extensions; + props[IMimeType::PROP_DESCRIPTION()] = std::string("Generated MIME type from mitk::AbstractFileReader"); + props[us::ServiceConstants::SERVICE_RANKING()] = this->GetRanking(); + + // If the mime type is set and the list of extensions is not empty, + // register a new IMimeType service + if (!mimeType.empty() && !extensions.empty()) + { + return context->RegisterService(&d->m_SimpleMimeType, props); + } + + // If the mime type is set and the list of extensions is empty, + // look up the mime type in the registry and print a warning if + // there is none + if (!mimeType.empty() && extensions.empty()) + { + if(us::GetModuleContext()->GetServiceReferences(us::LDAPProp(IMimeType::PROP_ID()) == mimeType).empty()) + { + MITK_WARN << "Registering a MITK reader with an unknown MIME type " << mimeType; + } + return us::ServiceRegistration(); + } + + // If the mime type is empty, get a mime type using the extensions list + assert(mimeType.empty()); + mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider()); + + if(extensions.empty()) + { + MITK_WARN << "Trying to register a MITK reader with an empty mime type and empty extension list."; + return us::ServiceRegistration(); + } + else if(extensions.size() == 1) + { + // If there is only one extension, try to look-up an existing mime tpye + std::vector mimeTypes = mimeTypeProvider->GetMimeTypesForExtension(extensions.front()); + if (!mimeTypes.empty()) + { + d->m_MimeType = mimeTypes.front(); + } + } + + if (d->m_MimeType.empty()) + { + // There is no registered mime type for the extension or the extensions + // list contains more than one entry. + // Register a new mime type by creating a synthetic mime type id from the + // first extension in the list + d->m_MimeType = "application/vnd.mitk." + primaryExtension; + props[IMimeType::PROP_ID()] = d->m_MimeType; + return context->RegisterService(&d->m_SimpleMimeType, props); + } + else + { + // A mime type for one of the listed extensions was found, do nothing. + return us::ServiceRegistration(); + } +} + +void AbstractFileReader::SetMimeType(const std::string& mimeType) +{ + d->m_MimeType = mimeType; +} + +void AbstractFileReader::SetCategory(const std::string& category) +{ + d->m_Category = category; +} + +void AbstractFileReader::AddExtension(const std::string& extension) +{ + d->m_Extensions.push_back(extension); +} + +void AbstractFileReader::SetDescription(const std::string& description) +{ + d->m_Description = description; +} + +void AbstractFileReader::SetRanking(int ranking) +{ + d->m_Ranking = ranking; +} + +int AbstractFileReader::GetRanking() const +{ + return d->m_Ranking; +} + +//////////////////////// Options /////////////////////// + +IFileReader::OptionList AbstractFileReader::GetOptions() const +{ + return d->m_Options; +} + +void AbstractFileReader::SetOptions(const OptionList& options) +{ + if (options.size() != d->m_Options.size()) MITK_WARN << "Number of set Options differs from Number of available Options, which is a sign of false usage. Please consult documentation"; + d->m_Options = options; +} + +////////////////// MISC ////////////////// + +bool AbstractFileReader::CanRead(const std::string& path) const +{ + if (!itksys::SystemTools::FileExists(path.c_str(), true)) + { + return false; + } + + // Default implementation only checks if extension is correct + std::string extension = itksys::SystemTools::GetFilenameExtension(path); + extension = extension.substr(1, extension.size()-1); + if (std::find(d->m_Extensions.begin(), d->m_Extensions.end(), extension) == d->m_Extensions.end()) + { + return false; + } + + std::ifstream stream(path.c_str()); + return this->CanRead(stream); +} + +bool AbstractFileReader::CanRead(std::istream& stream) const +{ + return stream.good(); +} + +void AbstractFileReader::AddProgressCallback(const ProgressCallback& callback) +{ + d->m_ProgressMessage += callback; +} + +void AbstractFileReader::RemoveProgressCallback(const ProgressCallback& callback) +{ + d->m_ProgressMessage -= callback; +} + +////////////////// µS related Getters ////////////////// + +std::string AbstractFileReader::GetCategory() const +{ + return d->m_Category; +} + +std::string AbstractFileReader::GetMimeType() const +{ + return d->m_MimeType; +} + +std::vector AbstractFileReader::GetExtensions() const +{ + return d->m_Extensions; +} + +std::string AbstractFileReader::GetDescription() const +{ + return d->m_Description; +} + +AbstractFileReader::MimeType::MimeType(const std::string& mimeType) + : std::string(mimeType) +{ + if (this->empty()) + { + throw std::invalid_argument("MIME type must not be empty."); + } +} + +AbstractFileReader::MimeType::MimeType() +{ +} + +} diff --git a/Core/Code/IO/mitkAbstractFileReader.h b/Core/Code/IO/mitkAbstractFileReader.h new file mode 100644 index 0000000000..c93f079f2a --- /dev/null +++ b/Core/Code/IO/mitkAbstractFileReader.h @@ -0,0 +1,202 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef AbstractFileReader_H_HEADER_INCLUDED_C1E7E521 +#define AbstractFileReader_H_HEADER_INCLUDED_C1E7E521 + +// Macro +#include + +// MITK +#include +#include +#include + +// Microservices +#include +#include +#include + +namespace us { + struct PrototypeServiceFactory; +} + +namespace mitk { + +/** + * @brief Interface class of readers that read from files + * @ingroup Process + */ +class MITK_CORE_EXPORT AbstractFileReader : public mitk::IFileReader +{ + +public: + + virtual std::vector > Read(const std::string& path); + + virtual std::vector > Read(std::istream& stream) = 0; + + virtual std::vector,bool> > Read(const std::string& path, mitk::DataStorage& ds); + + virtual std::vector,bool> > Read(std::istream& stream, mitk::DataStorage& ds); + + virtual OptionList GetOptions() const; + + virtual void SetOptions(const OptionList& options); + + /** + * @brief Checks if the specified path can be read. + * + * The default implementation checks if the path exists and contains a + * file extension associated with the mime-type of this reader. + * It then creates a std::ifstream object for the given path and + * calls CanRead(const std::istream&). + * + * @param path The absolute path to a file. + * @return \c true if the file can be read, \c false otherwise. + */ + virtual bool CanRead(const std::string& path) const; + + /** + * @brief Checks if the specified input stream can be read. + * + * @param stream The stream to be read. + * @return \c true if the stream is good, \c false otherwise. + */ + virtual bool CanRead(std::istream& stream) const; + + virtual void AddProgressCallback(const ProgressCallback& callback); + + virtual void RemoveProgressCallback(const ProgressCallback& callback); + + /** + * Associate this reader with the MIME type returned by the current IMimeTypeProvider + * service for the provided extension if the MIME type exists, otherwise registers + * a new MIME type when RegisterService() is called. + * + * If no MIME type for \c extension is already registered, a call to RegisterService() + * will register a new MIME type and associate this reader instance with it. The MIME + * type id can be set via SetMimeType() or it will be auto-generated using \c extension, + * having the form "application/vnd.mitk.". + * + * @param extension The file extension (without a leading period) for which a registered + * IMimeType object is looked up and associated with this reader instance. + * @param description A human readable description of this reader. + */ + us::ServiceRegistration RegisterService(us::ModuleContext* context = us::GetModuleContext()); + +protected: + + class MITK_CORE_EXPORT MimeType : public std::string + { + public: + MimeType(const std::string& mimeType); + + private: + MimeType(); + + friend class AbstractFileReader; + }; + + AbstractFileReader(); + ~AbstractFileReader(); + + AbstractFileReader(const AbstractFileReader& other); + + /** + * Associate this reader instance with the given MIME type. + * + * @param mimeType The mime type this reader can read. + * @param description A human readable description of this reader. + * + * @throws std::invalid_argument if \c mimeType is empty. + * + * @see RegisterService + */ + explicit AbstractFileReader(const MimeType& mimeType, const std::string& description); + + /** + * Associate this reader with the given file extension. + * + * Additonal file extensions can be added by sub-classes by calling AddExtension + * or SetExtensions. + * + * @param extension The file extension (without a leading period) for which a registered + * IMimeType object is looked up and associated with this reader instance. + * @param description A human readable description of this reader. + * + * @see RegisterService + */ + explicit AbstractFileReader(const std::string& extension, const std::string& description); + + virtual us::ServiceProperties GetServiceProperties() const; + + /** + * @brief Returns the mime-type this reader can handle. + * @return + */ + std::string GetMimeType() const; + + /** + * Registers a new IMimeType service object. + * + * This method is called from RegisterService and the default implementation + * registers a new IMimeType service object if all of the following conditions + * are true: + * + * - The reader + * + * @param context + * @return + * @throws std::invalid_argument if \c context is NULL. + */ + virtual us::ServiceRegistration RegisterMimeType(us::ModuleContext* context); + + void SetMimeType(const std::string& mimeType); + void SetCategory(const std::string& category); + void AddExtension(const std::string& extension); + void SetDescription(const std::string& description); + + /** + * \brief Set the service ranking for this file reader. + * + * Default is zero and should only be chosen differently for a reason. + * The ranking is used to determine which reader to use if several + * equivalent readers have been found. + * It may be used to replace a default reader from MITK in your own project. + * E.g. if you want to use your own reader for nrrd files instead of the default, + * implement it and give it a higher ranking than zero. + */ + void SetRanking(int ranking); + int GetRanking() const; + + std::string GetCategory() const; + std::vector GetExtensions() const; + std::string GetDescription() const; + +private: + + AbstractFileReader& operator=(const AbstractFileReader& other); + + virtual mitk::IFileReader* Clone() const = 0; + + class Impl; + std::auto_ptr d; +}; + +} // namespace mitk + +#endif /* AbstractFileReader_H_HEADER_INCLUDED_C1E7E521 */ diff --git a/Core/Code/IO/mitkAbstractFileWriter.cpp b/Core/Code/IO/mitkAbstractFileWriter.cpp new file mode 100644 index 0000000000..fa3eac51ff --- /dev/null +++ b/Core/Code/IO/mitkAbstractFileWriter.cpp @@ -0,0 +1,185 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include +#include +#include + +#include +#include +#include + +#include + +#include + +mitk::AbstractFileWriter::AbstractFileWriter() + : m_Priority (0) + , m_PrototypeFactory(NULL) +{ +} + +mitk::AbstractFileWriter::~AbstractFileWriter() +{ + delete m_PrototypeFactory; +} + +mitk::AbstractFileWriter::AbstractFileWriter(const mitk::AbstractFileWriter& other) + : m_Extension(other.m_Extension) + , m_BasedataType(other.m_BasedataType) + , m_Description(other.m_Description) + , m_Priority(other.m_Priority) + , m_Options(other.m_Options) + , m_PrototypeFactory(NULL) +{ +} + +mitk::AbstractFileWriter::AbstractFileWriter(const std::string& basedataType, const std::string& extension, + const std::string& description) + : m_Extension (extension) + , m_BasedataType(basedataType) + , m_Description (description) + , m_Priority (0) + , m_PrototypeFactory(NULL) +{ +} + +////////////////////// Writing ///////////////////////// + +void mitk::AbstractFileWriter::Write(const BaseData* data, const std::string& path) +{ + std::ofstream stream; + stream.open(path.c_str()); + this->Write(data, stream); +} + +void mitk::AbstractFileWriter::Write(const mitk::BaseData* data, std::ostream& stream) +{ + // Create a temporary file and write the data to it + std::ofstream tmpOutputStream; + std::string tmpFilePath = mitk::IOUtil::CreateTemporaryFile(tmpOutputStream); + this->Write(data, tmpFilePath); + tmpOutputStream.close(); + + // Now copy the contents + std::ifstream tmpInputStream(tmpFilePath.c_str(), std::ios_base::binary); + stream << tmpInputStream.rdbuf(); + tmpInputStream.close(); + std::remove(tmpFilePath.c_str()); +} + +//////////// µS Registration & Properties ////////////// + +us::ServiceRegistration mitk::AbstractFileWriter::RegisterService(us::ModuleContext* context) +{ + if (m_PrototypeFactory) return us::ServiceRegistration(); + + struct PrototypeFactory : public us::PrototypeServiceFactory + { + mitk::AbstractFileWriter* const m_Prototype; + + PrototypeFactory(mitk::AbstractFileWriter* prototype) + : m_Prototype(prototype) + {} + + us::InterfaceMap GetService(us::Module* /*module*/, const us::ServiceRegistrationBase& /*registration*/) + { + return us::MakeInterfaceMap(m_Prototype->Clone()); + } + + void UngetService(us::Module* /*module*/, const us::ServiceRegistrationBase& /*registration*/, + const us::InterfaceMap& service) + { + delete us::ExtractInterface(service); + } + }; + + m_PrototypeFactory = new PrototypeFactory(this); + us::ServiceProperties props = this->GetServiceProperties(); + return context->RegisterService(m_PrototypeFactory, props); +} + +us::ServiceProperties mitk::AbstractFileWriter::GetServiceProperties() const +{ + if ( m_Extension.empty() ) + MITK_WARN << "Registered a Writer with no extension defined (m_Extension is empty). Writer will not be found by calls from WriterManager.)"; + if ( m_BasedataType.empty() ) + MITK_WARN << "Registered a Writer with no BasedataType defined (m_BasedataType is empty). Writer will not be found by calls from WriterManager.)"; + if ( m_Description.empty() ) + MITK_WARN << "Registered a Writer with no description defined (m_Description is empty). Writer will have no human readable extension information in FileDialogs.)"; + + us::ServiceProperties result; + result[mitk::IFileWriter::PROP_EXTENSION()] = m_Extension; + result[mitk::IFileWriter::PROP_DESCRIPTION()] = m_Description; + result[mitk::IFileWriter::PROP_BASEDATA_TYPE()] = m_BasedataType; + result[us::ServiceConstants::SERVICE_RANKING()] = m_Priority; + + for (mitk::IFileWriter::OptionList::const_iterator it = m_Options.begin(); it != m_Options.end(); ++it) + { + result[it->first] = std::string("true"); + } + return result; +} + +//////////////////////// Options /////////////////////// + +mitk::IFileWriter::OptionList mitk::AbstractFileWriter::GetOptions() const +{ + return m_Options; +} + +void mitk::AbstractFileWriter::SetOptions(const OptionList& options) +{ + if (options.size() != m_Options.size()) MITK_WARN << "Number of set Options differs from Number of available Options, which is a sign of false usage. Please consult documentation"; + m_Options = options; +} + +////////////////// MISC ////////////////// + +bool mitk::AbstractFileWriter::CanWrite(const BaseData* data) const +{ + // Default implementation only checks if basedatatype is correct + std::string externalDataType = data->GetNameOfClass(); + return (externalDataType == m_BasedataType); +} + +float mitk::AbstractFileWriter::GetProgress() const +{ + // Default implementation always returns 1 (finished) + return 1; +} + +////////////////// µS related Getters ////////////////// + +int mitk::AbstractFileWriter::GetPriority() const +{ + return m_Priority; +} + +std::string mitk::AbstractFileWriter::GetExtension() const +{ + return m_Extension; +} + +std::string mitk::AbstractFileWriter::GetDescription() const +{ + return m_Description; +} + +std::string mitk::AbstractFileWriter::GetSupportedBasedataType() const +{ + return m_BasedataType; +} diff --git a/Core/Code/IO/mitkAbstractFileWriter.h b/Core/Code/IO/mitkAbstractFileWriter.h new file mode 100644 index 0000000000..7d110708a7 --- /dev/null +++ b/Core/Code/IO/mitkAbstractFileWriter.h @@ -0,0 +1,160 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef AbstractFileWriter_H_HEADER_INCLUDED_C1E7E521 +#define AbstractFileWriter_H_HEADER_INCLUDED_C1E7E521 + +// Macro +#include + +// MITK +#include + +// Microservices +#include +#include +#include + +namespace us { + struct PrototypeServiceFactory; +} + +namespace mitk { + /** + * @brief This abstract class gives a meaningful default implementations to most methods of mitkIFileWriter.h. + * + * In general, all FileWriters should derive from this class, this way it is made sure that the new implementation is + * exposed to the Microservice-Framework and that is automatically available troughout MITK. + * The default implementation only requires the two write + * methods and the Clone() method to be implemented. Be sure to set all important members in the constructor. These are: + *
    + *
  • m_Extension: To define which file extension can be written. + *
  • m_Description: To give a human readable name for this writer to be displayed in FileDialogs. + *
  • m_BasedataType: To define which type of Basedata this fileWriter can handle. + *
  • (Optional) m_Priority: To make this writer rank higher when choosing writers automatically + *
  • (Optional) m_SupportedOptions: To define which options this writer can handle. Options can modify writing behaviour (e.g. set a compression) + *
+ * You can also use the protected constructor for this. + * + * @ingroup Process + */ + class MITK_CORE_EXPORT AbstractFileWriter : public mitk::IFileWriter + { + public: + + /** + * \brief Write the data in data to the the location specified in path + */ + virtual void Write(const BaseData* data, const std::string& path); + + /** + * \brief Write the data in data to the the stream specified in stream + */ + virtual void Write(const BaseData* data, std::ostream& stream ) = 0; + + /** + * \brief Returns the priority which defined how 'good' the FileWriter can handle it's file format. + * + * Default is zero and should only be chosen differently for a reason. + * The priority is intended to be used by the MicroserviceFramework to determine + * which reader to use if several equivalent readers have been found. + * It may be used to replace a default reader from MITK in your own project. + * E.g. if you want to use your own reader for *.nrrd files instead of the default, + * implement it and give it a higher priority than zero. + * + * This method has a default implementation and need not be reimplemented, simply set m_Priority in the constructor. + */ + virtual int GetPriority() const; + + /** + * \brief returns the file extension that this FileWriter is able to handle. + * + * Please enter only the characters after the fullstop, e.g "nrrd" is correct + * while "*.nrrd" and ".nrrd" are incorrect. + * + * This method has a default implementation and need not be reimplemented, simply set m_Extension in the constructor. + */ + virtual std::string GetExtension() const; + + /** + * \brief returns the name of the itk Basedata that this FileWriter is able to handle. + * + * The correct value is the one given as the first parameter in the ItkNewMacro of that Basedata derivate. + * You can also retrieve it by calling GetNameOfClass() on an instance of said data. + * + * This method has a default implementation and need not be reimplemented, simply set m_BaseDataType in the constructor. + */ + virtual std::string GetSupportedBasedataType() const; + + /** + * \brief Returns a human readable description of the file format. + * + * This will be used in FileDialogs for example. + * This method has a default implementation and need not be reimplemented, simply set m_BaseDataType in the constructor. + */ + virtual std::string GetDescription() const; + + /** + * \brief returns a list of the supported Options + * + * Options are strings that are treated as flags when passed to the read method. + */ + virtual OptionList GetOptions() const; + + virtual void SetOptions(const OptionList& options); + + /** + * \brief Return true if this writer can confirm that it can read this file and false otherwise. + * + * The default implementation of AbstractFileWriter checks if the supplied filename is of the same extension as m_extension. + * Overwrite this method if you require more specific behaviour + */ + virtual bool CanWrite(const BaseData* data) const; + + /** + * \brief Returns a value between 0 and 1 depending on the progress of the writing process. + * This method need not necessarily be implemented, always returning zero is accepted. + */ + virtual float GetProgress() const; + + us::ServiceRegistration RegisterService(us::ModuleContext* context = us::GetModuleContext()); + + protected: + AbstractFileWriter(); + ~AbstractFileWriter(); + + AbstractFileWriter(const AbstractFileWriter& other); + + AbstractFileWriter(const std::string& basedataType, const std::string& extension, const std::string& description); + + // Minimal Service Properties: ALWAYS SET THESE IN CONSTRUCTOR OF DERIVED CLASSES! + std::string m_Extension; + std::string m_BasedataType; + std::string m_Description; + int m_Priority; + OptionList m_Options; // Options supported by this Writer. Can be left emtpy if no special options are required + + virtual us::ServiceProperties GetServiceProperties() const; + + private: + + us::PrototypeServiceFactory* m_PrototypeFactory; + + virtual mitk::IFileWriter* Clone() const = 0; + }; +} // namespace mitk + +#endif /* AbstractFileWriter_H_HEADER_INCLUDED_C1E7E521 */ diff --git a/Core/Code/IO/mitkCoreDataNodeReader.cpp b/Core/Code/IO/mitkCoreDataNodeReader.cpp deleted file mode 100644 index 2664e37207..0000000000 --- a/Core/Code/IO/mitkCoreDataNodeReader.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - - -#include "mitkCoreDataNodeReader.h" - -#include -#include - -namespace mitk { - -int CoreDataNodeReader::Read(const std::string &fileName, DataStorage &storage) -{ - mitk::DataNodeFactory::Pointer nodeReader = mitk::DataNodeFactory::New(); - - // the ITK Nrrd file reader cannot handle '/' in file path on Win 64bit - std::string name(fileName); - std::replace(name.begin(), name.end(), '\\', '/'); - nodeReader->SetFileName(name); - nodeReader->Update(); - int n = 0; - for ( unsigned int i = 0 ; i < nodeReader->GetNumberOfOutputs( ); ++i ) - { - mitk::DataNode::Pointer node; - node = nodeReader->GetOutput(i); - if ( node->GetData() != NULL ) - { - storage.Add(node); - ++n; - } - } - return n; -} - -} diff --git a/Core/Code/IO/mitkFileReader.h b/Core/Code/IO/mitkFileReader.h index fbf52d7465..086f47e62b 100644 --- a/Core/Code/IO/mitkFileReader.h +++ b/Core/Code/IO/mitkFileReader.h @@ -1,106 +1,107 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef FILEREADER_H_HEADER_INCLUDED_C1E7E521 #define FILEREADER_H_HEADER_INCLUDED_C1E7E521 #include namespace mitk { //##Documentation //## @brief Interface class of readers that read from files //## @ingroup Process +//## @deprecatedSince{2014_03} Use mitk::IFileReader instead. class MITK_CORE_EXPORT FileReader { public: //##Documentation //## @brief Get the specified the file to load. //## //## Either the FileName or FilePrefix plus FilePattern are used to read. virtual const char* GetFileName() const = 0; //##Documentation //## @brief Specify the file to load. //## //## Either the FileName or FilePrefix plus FilePattern are used to read. virtual void SetFileName(const char* aFileName) = 0; //##Documentation //## @brief Get the specified file prefix for the file(s) to load. //## //## You should specify either a FileName or FilePrefix. Use FilePrefix if //## the data is stored in multiple files. virtual const char* GetFilePrefix() const = 0; //##Documentation //## @brief Specify file prefix for the file(s) to load. //## //## You should specify either a FileName or FilePrefix. Use FilePrefix if //## the data is stored in multiple files. virtual void SetFilePrefix(const char* aFilePrefix) = 0; //##Documentation //## @brief Get the specified file pattern for the file(s) to load. The //## sprintf format used to build filename from FilePrefix and number. //## //## You should specify either a FileName or FilePrefix. Use FilePrefix if //## the data is stored in multiple files. virtual const char* GetFilePattern() const = 0; /** @brief Specified file pattern for the file(s) to load. The sprintf format used to build filename from FilePrefix and number. You should specify either a FileName or FilePrefix. Use FilePrefix if the data is stored in multiple files. */ virtual void SetFilePattern(const char* aFilePattern) = 0; /** @brief Specifies, whether the file reader also can read a file from a memory buffer */ virtual bool CanReadFromMemory( ); /** @brief Set/Get functions to advise the file reader to use a memory array for reading a file*/ virtual void SetReadFromMemory( bool read ); virtual bool GetReadFromMemory( ); /** @brief To be used along with a call of SetReadFromMemory(true). This sets the memory buffer and the size from which the reader will read.*/ virtual void SetMemoryBuffer(const char* dataArray, unsigned int size); protected: FileReader(); virtual ~FileReader(); bool m_CanReadFromMemory; bool m_ReadFromMemory; const char* m_MemoryBuffer; unsigned int m_MemorySize; public: protected: }; } // namespace mitk #endif /* FILEREADER_H_HEADER_INCLUDED_C1E7E521 */ diff --git a/Core/Code/IO/mitkFileReaderRegistry.cpp b/Core/Code/IO/mitkFileReaderRegistry.cpp new file mode 100644 index 0000000000..acfae6240a --- /dev/null +++ b/Core/Code/IO/mitkFileReaderRegistry.cpp @@ -0,0 +1,241 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkFileReaderRegistry.h" + +#include "mitkIMimeTypeProvider.h" +#include "mitkCoreServices.h" + +// Microservices +#include +#include +#include +#include + +#include "itksys/SystemTools.hxx" + +mitk::FileReaderRegistry::FileReaderRegistry() +{ +} + +mitk::FileReaderRegistry::~FileReaderRegistry() +{ + for (std::map >::iterator iter = m_ServiceObjects.begin(), + end = m_ServiceObjects.end(); iter != end; ++iter) + { + iter->second.UngetService(iter->first); + } +} + +//////////////////// READING DIRECTLY //////////////////// + +std::vector< mitk::BaseData::Pointer > mitk::FileReaderRegistry::Read(const std::string& path, us::ModuleContext* context) +{ + // Find extension + std::string extension = itksys::SystemTools::GetFilenameExtension(path); + if (!extension.empty()) + { + extension = extension.substr(1, extension.size()-1); + } + + // Get best Reader + FileReaderRegistry readerRegistry; + mitk::IFileReader* reader = readerRegistry.GetReader(extension, context); + // Throw exception if no compatible reader was found + if (reader == NULL) mitkThrow() << "Tried to directly read a file with extension '" + extension + "' via FileReaderRegistry, but no reader supporting this file type was found."; + return reader->Read(path); +} + +std::vector< mitk::BaseData::Pointer > mitk::FileReaderRegistry::ReadAll( + const std::vector& paths, std::vector* unreadableFiles, + us::ModuleContext* context) +{ + FileReaderRegistry readerRegistry; + std::vector< mitk::BaseData::Pointer > result; + for (std::vector::const_iterator iterator = paths.begin(), end = paths.end(); iterator != end; ++iterator) + { + try + { + std::string extension = itksys::SystemTools::GetFilenameExtension(*iterator); + if (!extension.empty()) + { + extension = extension.substr(1, extension.size()-1); + } + mitk::IFileReader* reader = readerRegistry.GetReader(extension, context); + // Throw exception if no compatible reader was found + if (reader == NULL) throw; + + std::vector baseDataList = reader->Read( *iterator ); + result.insert(result.end(), baseDataList.begin(), baseDataList.end()); + } + catch (...) + { + if (unreadableFiles) unreadableFiles->push_back( *iterator ); + } + } + return result; +} + + +//////////////////// GETTING READERS //////////////////// + +mitk::FileReaderRegistry::ReaderReference mitk::FileReaderRegistry::GetReaderReference(const std::string& mimeType, us::ModuleContext* context) +{ + std::vector refs = GetReaderReferences(mimeType, context); + if (refs.empty()) return ReaderReference(); + std::sort(refs.begin(), refs.end()); + return refs.back(); +} + +std::vector mitk::FileReaderRegistry::GetReaderReferences(const std::string& mimeType, us::ModuleContext* context) +{ + std::string filter = us::LDAPProp(us::ServiceConstants::OBJECTCLASS()) == us_service_interface_iid() && + us::LDAPProp(IFileReader::PROP_MIMETYPE()) == mimeType; + return context->GetServiceReferences(filter); +} + +mitk::IFileReader* mitk::FileReaderRegistry::GetReader(const mitk::FileReaderRegistry::ReaderReference& ref, us::ModuleContext* context) +{ + us::ServiceObjects serviceObjects = context->GetServiceObjects(ref); + mitk::IFileReader* reader = serviceObjects.GetService(); + m_ServiceObjects.insert(std::make_pair(reader, serviceObjects)); + return reader; +} + +mitk::IFileReader* mitk::FileReaderRegistry::GetReader(const std::string& extension, us::ModuleContext* context ) +{ + std::vector results = GetReaders(extension, context); + if (results.empty()) return NULL; + return results.front(); +} + +std::vector mitk::FileReaderRegistry::GetReaders(const std::string& extension, us::ModuleContext* context ) +{ + std::vector result; + const std::vector > refs = GetReaderList(extension, context); + result.reserve(refs.size()); + + // Translate List of ServiceRefs to List of Pointers + for (std::vector >::const_iterator iter = refs.begin(), end = refs.end(); + iter != end; ++iter) + { + us::ServiceObjects serviceObjects = context->GetServiceObjects(*iter); + mitk::IFileReader* reader = serviceObjects.GetService(); + m_ServiceObjects.insert(std::make_pair(reader, serviceObjects)); + result.push_back(reader); + } + + return result; +} + +mitk::IFileReader* mitk::FileReaderRegistry::GetReader( + const std::string& extension, const mitk::IFileReader::OptionNames& options, + us::ModuleContext* context ) +{ + std::vector matching = mitk::FileReaderRegistry::GetReaders(extension, options, context); + if (matching.empty()) return NULL; + return matching.front(); +} + +std::vector mitk::FileReaderRegistry::GetReaders( + const std::string& extension, const mitk::IFileReader::OptionNames& options, + us::ModuleContext* context ) +{ + const std::vector allReaders = mitk::FileReaderRegistry::GetReaders(extension, context); + std::vector result; + result.reserve(allReaders.size()); + // the list is already sorted by priority. Now find reader that supports all options + + for (std::vector ::const_iterator iter = allReaders.begin(), end = allReaders.end(); + iter != end; ++iter) + { + mitk::IFileReader * currentReader = *iter; + // Now see if this reader supports all options. If yes, push to results + if ( mitk::FileReaderRegistry::ReaderSupportsOptions(currentReader, options) ) + { + result.push_back(currentReader); + } + } + return result; +} + +void mitk::FileReaderRegistry::UngetReader(mitk::IFileReader* reader) +{ + std::map >::iterator readerIter = + m_ServiceObjects.find(reader); + if (readerIter != m_ServiceObjects.end()) + { + readerIter->second.UngetService(reader); + m_ServiceObjects.erase(readerIter); + } +} + +void mitk::FileReaderRegistry::UngetReaders(const std::vector& readers) +{ + for (std::vector::const_iterator iter = readers.begin(), end = readers.end(); + iter != end; ++iter) + { + this->UngetReader(*iter); + } +} + +//////////////////// INTERNAL CODE //////////////////// + +bool mitk::FileReaderRegistry::ReaderSupportsOptions(mitk::IFileReader* reader, + const mitk::IFileReader::OptionNames& options ) +{ + const mitk::IFileReader::OptionList readerOptions = reader->GetOptions(); + if (options.empty()) return true; // if no options were requested, return true unconditionally + if (readerOptions.empty()) return false; // if options were requested and reader supports no options, return false + + // For each of the strings in requested options, check if option is available in reader + for(mitk::IFileReader::OptionNames::const_iterator options_i = options.begin(), i_end = options.end(); options_i != i_end; ++options_i) + { + { + bool optionFound = false; + // Iterate over each available option from reader to check if one of them matches the current option + for(mitk::IFileReader::OptionList::const_iterator options_j = readerOptions.begin(), j_end = readerOptions.end(); + options_j != j_end; ++options_j) + { + if ( *options_i == options_j->first ) optionFound = true; + } + if (optionFound == false) return false; // If one option was not found, leave method and return false + } + } + return true; // if all options have been found, return true +} + +//////////////////// uS-INTERACTION //////////////////// + +std::vector< us::ServiceReference > mitk::FileReaderRegistry::GetReaderList(const std::string& extension, us::ModuleContext* context ) +{ + std::vector > result; + + // filter for mime type + std::string filter; + mitk::IMimeTypeProvider* mimeTypeProvider = mitk::CoreServices::GetMimeTypeProvider(context); + std::vector mimeTypes = mimeTypeProvider->GetMimeTypesForExtension(extension); + if (mimeTypes.empty()) + { + MITK_WARN << "No mime-type information for extension " << extension << " available."; + return result; + } + filter = us::LDAPProp(mitk::IFileReader::PROP_MIMETYPE()) == mimeTypes.front(); + result = context->GetServiceReferences(filter); + std::sort(result.begin(), result.end()); + std::reverse(result.begin(), result.end()); + return result; +} diff --git a/Core/Code/IO/mitkFileReaderRegistry.h b/Core/Code/IO/mitkFileReaderRegistry.h new file mode 100644 index 0000000000..09c2bfa286 --- /dev/null +++ b/Core/Code/IO/mitkFileReaderRegistry.h @@ -0,0 +1,114 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#ifndef FileReaderRegistry_H_HEADER_INCLUDED_C1E7E521 +#define FileReaderRegistry_H_HEADER_INCLUDED_C1E7E521 + +#include +#include + +#include + +// Microservices +#include +#include +#include + + +namespace mitk { + +/** + * @ingroup Process + * + * Provides convenient access to mitk::IFileReader instances and reading + * files into mitk::BaseData types. + * + * \note The life-time of all mitk::IFileReader objects returned by an + * instance of this class ends with the destruction of that instance. + */ +class MITK_CORE_EXPORT FileReaderRegistry +{ + +public: + + typedef us::ServiceReference ReaderReference; + + FileReaderRegistry(); + ~FileReaderRegistry(); + + /** + * Reads the file located at path and returns the + * contents as a DataNode. + * + * This method will select the best available reader in the service + * registry for the task. + * + * UnsupportedFileException: If no compatible reader was found + * FileNotFoundException: If no file was found at path + * FileReadException: If the selected reader failed to read the file + **/ + static std::vector< itk::SmartPointer > Read(const std::string& path, us::ModuleContext* context = us::GetModuleContext()); + + static std::vector< mitk::BaseData::Pointer > ReadAll(const std::vector& paths, std::vector* unreadableFiles = 0, + us::ModuleContext* context = us::GetModuleContext()); + + template + static itk::SmartPointer Read(const std::string& path, us::ModuleContext* context = us::GetModuleContext()) + { + std::vector basedatas = Read(path, context); + if (basedatas.empty()) return NULL; + T* result = dynamic_cast (basedatas.front().GetPointer()); + return result; + } + + static ReaderReference GetReaderReference(const std::string& mimeType, us::ModuleContext* context = us::GetModuleContext()); + + static std::vector GetReaderReferences(const std::string& mimeType, us::ModuleContext* context = us::GetModuleContext()); + + mitk::IFileReader* GetReader(const ReaderReference& ref, us::ModuleContext* context = us::GetModuleContext()); + + /** + * Returns a compatible Reader to the given file extension + **/ + mitk::IFileReader* GetReader(const std::string& extension, us::ModuleContext* context = us::GetModuleContext() ); + + mitk::IFileReader* GetReader(const std::string& extension, const mitk::IFileReader::OptionNames& options, us::ModuleContext* context = us::GetModuleContext() ); + + std::vector GetReaders(const std::string& extension, us::ModuleContext* context = us::GetModuleContext() ); + + std::vector GetReaders(const std::string& extension, const mitk::IFileReader::OptionNames& options, us::ModuleContext* context = us::GetModuleContext() ); + + void UngetReader(mitk::IFileReader* reader); + void UngetReaders(const std::vector& readers); + +protected: + + std::vector< us::ServiceReference > GetReaderList(const std::string& extension, us::ModuleContext* context); + + bool ReaderSupportsOptions(mitk::IFileReader* reader, const mitk::IFileReader::OptionNames& options); + +private: + + // purposely not implemented + FileReaderRegistry(const FileReaderRegistry&); + FileReaderRegistry& operator=(const FileReaderRegistry&); + + std::map > m_ServiceObjects; + +}; +} // namespace mitk +#endif /* FileReaderRegistry_H_HEADER_INCLUDED_C1E7E521 */ diff --git a/Core/Code/IO/mitkFileWriter.h b/Core/Code/IO/mitkFileWriter.h index b6f7c528ca..191e257fc4 100644 --- a/Core/Code/IO/mitkFileWriter.h +++ b/Core/Code/IO/mitkFileWriter.h @@ -1,160 +1,161 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef FILEWRITER_H_HEADER_INCLUDED #define FILEWRITER_H_HEADER_INCLUDED #include #include #include namespace mitk { //##Documentation //## @brief Interface class of writers that write data to files //## @ingroup Process +//## @deprecatedSince{2014_03} Use mitk::IFileWriter instead. class MITK_CORE_EXPORT FileWriter : public itk::ProcessObject { public: mitkClassMacro(FileWriter,itk::ProcessObject); //##Documentation //## @brief Get the specified the file to write //## //## Either the FileName or FilePrefix plus FilePattern are used to write. virtual const char* GetFileName() const = 0; //##Documentation //## @brief Specify the file to write. //## //## Either the FileName or FilePrefix plus FilePattern are used to write. virtual void SetFileName(const char* aFileName) = 0; //##Documentation //## @brief Get the specified file prefix for the file(s) to write. //## //## You should specify either a FileName or FilePrefix. Use FilePrefix if //## the data is stored in multiple files. virtual const char* GetFilePrefix() const = 0; //##Documentation //## @brief Specify file prefix for the file(s) to write. //## //## You should specify either a FileName or FilePrefix. Use FilePrefix if //## the data is stored in multiple files. virtual void SetFilePrefix(const char* aFilePrefix) = 0; //##Documentation //## @brief Get the specified file pattern for the file(s) to write. The //## sprintf format used to build filename from FilePrefix and number. //## //## You should specify either a FileName or FilePrefix. Use FilePrefix if //## the data is stored in multiple files. virtual const char* GetFilePattern() const = 0; //##Documentation //## @brief Specified file pattern for the file(s) to write. The sprintf //## format used to build filename from FilePrefix and number. //## //## You should specify either a FileName or FilePrefix. Use FilePrefix if //## the data is stored in multiple files. virtual void SetFilePattern(const char* aFilePattern) = 0; //##Documentation //## @brief Return the extension to be added to the filename. virtual std::string GetFileExtension(); //##Documentation //## @brief Checks if given extension is valid for file writer bool IsExtensionValid(std::string extension); //##Documentation //## @brief Return the possible file extensions for the data type associated with the writer virtual std::vector GetPossibleFileExtensions() = 0; //##Documentation //## @brief possible file extensions for the data type associated with the writer as string virtual std::string GetPossibleFileExtensionsAsString(); //##Documentation //## @brief Check if the Writer can write this type of data of the //## DataTreenode. virtual bool CanWriteDataType( DataNode* ); //##Documentation //## @brief Return the MimeType of the saved File. virtual std::string GetWritenMIMEType(); virtual void Write() = 0; /** @brief Specifies, whether the file writer also can write a file to a memory buffer */ virtual bool CanWriteToMemory( ); /** @brief Set/Get functions to advise the file writer to use tis internal memory array as file writing destination*/ virtual void SetWriteToMemory( bool write ); virtual bool GetWriteToMemory( ); /** @brief To be used along with a call of SetWriteToMemory(true). This returns the memory buffer where the file was written.*/ virtual const char* GetMemoryPointer(); /** @brief To be used along with a call of SetWriteToMemory(true). This returns the size of the memory buffer where the file was written.*/ virtual unsigned int GetMemorySize(); /** @brief CAUTION: It's up to the user to call this function to release the memory buffer after use in case the file writer has written to its memory array.*/ virtual void ReleaseMemory(); protected: FileWriter(); virtual ~FileWriter(); bool m_CanWriteToMemory; bool m_WriteToMemory; char * m_MemoryBuffer; unsigned int m_MemoryBufferSize; }; #define mitkWriterMacro \ virtual void Write() \ { \ if ( this->GetInput() == NULL ) \ { \ itkExceptionMacro(<<"Write:Please specify an input!"); \ return; \ } \ /* Fill in image information.*/ \ this->UpdateOutputInformation(); \ (*(this->GetInputs().begin()))->SetRequestedRegionToLargestPossibleRegion();\ this->PropagateRequestedRegion(NULL); \ this->UpdateOutputData(NULL); \ } \ \ virtual void Update() \ { \ Write(); \ } } // namespace mitk #endif /* FILEWRITER_H_HEADER_INCLUDED */ diff --git a/Core/Code/IO/mitkFileWriterRegistry.cpp b/Core/Code/IO/mitkFileWriterRegistry.cpp new file mode 100644 index 0000000000..d91c3974fc --- /dev/null +++ b/Core/Code/IO/mitkFileWriterRegistry.cpp @@ -0,0 +1,212 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#include "mitkFileWriterRegistry.h" + +// MITK +#include + +// ITK +#include + +// Microservices +#include +#include +#include +#include + +mitk::FileWriterRegistry::FileWriterRegistry() +{ +} + +mitk::FileWriterRegistry::~FileWriterRegistry() +{ + for (std::map >::iterator iter = m_ServiceObjects.begin(), + end = m_ServiceObjects.end(); iter != end; ++iter) + { + iter->second.UngetService(iter->first); + } +} + +//////////////////// WRITING DIRECTLY //////////////////// + +void mitk::FileWriterRegistry::Write(const mitk::BaseData* data, const std::string& path, us::ModuleContext* context) +{ + // Find extension + std::string extension = itksys::SystemTools::GetFilenameExtension(path); + if (!extension.empty()) + { + extension = extension.substr(1, extension.size()-1); + } + + // Get best Writer + FileWriterRegistry writerRegistry; + mitk::IFileWriter* writer = writerRegistry.GetWriter(data, extension, mitk::IFileWriter::OptionNames(), context); + // Throw exception if no compatible Writer was found + if (writer == NULL) + { + mitkThrow() << "Tried to directly write a file of type '" << data->GetNameOfClass() + << "' and extension '" << extension + << "' via FileWriterRegistry, but no writer supporting this file type was found."; + } + writer->Write(data, path); +} + +void mitk::FileWriterRegistry::Write(const mitk::BaseData* data, std::ostream& os, us::ModuleContext* context) +{ + // Get best Writer + FileWriterRegistry writerRegistry; + mitk::IFileWriter* writer = writerRegistry.GetWriter(data, std::string(), mitk::IFileWriter::OptionNames(), context); + // Throw exception if no compatible Writer was found + if (writer == NULL) + { + mitkThrow() << "Tried to directly write a file of type '" << data->GetNameOfClass() + << "' to a std::ostream via FileWriterRegistry, but no writer supporting this BaseData type was found."; + } + writer->Write(data, os); +} + + +//////////////////// GETTING WRITERS //////////////////// + +mitk::IFileWriter* mitk::FileWriterRegistry::GetWriter( + const mitk::BaseData* baseData, const std::string& extension, + const mitk::IFileWriter::OptionNames& options, us::ModuleContext* context) +{ + return GetWriter(baseData->GetNameOfClass(), extension, options, context); +} + +mitk::IFileWriter* mitk::FileWriterRegistry::GetWriter( + const std::string& baseDataType, const std::string& extension, + const mitk::IFileWriter::OptionNames& options, us::ModuleContext* context) +{ + std::vector results = GetWriters(baseDataType, extension, options, context); + if (results.empty()) return NULL; + return results.front(); +} + +std::vector mitk::FileWriterRegistry::GetWriters( + const mitk::BaseData* baseData, const std::string& extension, + const mitk::IFileWriter::OptionNames& options, us::ModuleContext* context) +{ + return GetWriters(baseData->GetNameOfClass(), extension, options, context); +} + +std::vector mitk::FileWriterRegistry::GetWriters( + const std::string& baseDataType, const std::string& extension, + const mitk::IFileWriter::OptionNames& options, us::ModuleContext* context) +{ + // filter for class and extension + std::string filter = us::LDAPProp(mitk::IFileWriter::PROP_BASEDATA_TYPE()) == baseDataType && + us::LDAPProp(mitk::IFileWriter::PROP_EXTENSION()) == extension; + + std::vector > refs = context->GetServiceReferences(filter); + std::sort(refs.begin(), refs.end()); + std::reverse(refs.begin(), refs.end()); + + std::vector result; + result.reserve(refs.size()); + + // Translate List of ServiceRefs to List of Pointers + for (std::vector >::const_iterator iter = refs.begin(), end = refs.end(); + iter != end; ++iter) + { + us::ServiceObjects serviceObjects = context->GetServiceObjects(*iter); + mitk::IFileWriter* writer = serviceObjects.GetService(); + + // Now see if this Writer supports all options. If yes, push to results + if (mitk::FileWriterRegistry::WriterSupportsOptions(writer, options)) + { + m_ServiceObjects.insert(std::make_pair(writer, serviceObjects)); + result.push_back(writer); + } + } + + return result; +} + + +//////////////////// GENERIC INFORMATION //////////////////// + +std::string mitk::FileWriterRegistry::GetSupportedExtensions(const std::string& extension, us::ModuleContext* context) +{ + std::string filter = us::LDAPProp(mitk::IFileWriter::PROP_EXTENSION()) == extension; + const std::vector > refs = context->GetServiceReferences(filter); + return CreateFileDialogString(refs); +} + +std::string mitk::FileWriterRegistry::GetSupportedWriters(const std::string& baseDataType, us::ModuleContext* context) +{ + std::string filter = us::LDAPProp(mitk::IFileWriter::PROP_BASEDATA_TYPE()) == baseDataType; + const std::vector > refs = context->GetServiceReferences(filter); + return CreateFileDialogString(refs); +} + + +//////////////////// INTERNAL CODE //////////////////// + +bool mitk::FileWriterRegistry::WriterSupportsOptions(mitk::IFileWriter* writer, const mitk::IFileWriter::OptionNames& options ) +{ + const mitk::IFileWriter::OptionList writerOptions = writer->GetOptions(); + if (options.empty()) return true; // if no options were requested, return true unconditionally + if (writerOptions.empty()) return false; // if options were requested and reader supports no options, return false + + // For each of the strings in requested options, check if option is available in reader + for(mitk::IFileWriter::OptionNames::const_iterator options_i = options.begin(), i_end = options.end(); options_i != i_end; ++options_i) + { + { + bool optionFound = false; + // Iterate over each available option from reader to check if one of them matches the current option + for(mitk::IFileWriter::OptionList::const_iterator options_j = writerOptions.begin(), j_end = writerOptions.end(); + options_j != j_end; ++options_j) + { + if ( *options_i == options_j->first ) optionFound = true; + } + if (optionFound == false) return false; // If one option was not found, leave method and return false + } + } + return true; // if all options have been found, return true +} + +std::string mitk::FileWriterRegistry::CreateFileDialogString(const std::vector >& refs) +{ + std::vector entries; // Will contain Description + Extension (Human readable) + entries.reserve(refs.size()); + std::string knownExtensions; // Will contain plain list of all known extensions (for the QFileDialog entry "All Known Extensions") + for (std::vector >::const_iterator iterator = refs.begin(), end = refs.end(); + iterator != end; ++iterator) + { + // Generate List of Extensions + if (iterator == refs.begin()) // First entry without semicolon + knownExtensions += "*" + iterator->GetProperty(mitk::IFileWriter::PROP_EXTENSION()).ToString(); + else // Ad semicolon for each following entry + knownExtensions += "; *" + iterator->GetProperty(mitk::IFileWriter::PROP_EXTENSION()).ToString(); + + // Generate List of human readable entries composed of Description + Extension + std::string entry = iterator->GetProperty(mitk::IFileWriter::PROP_DESCRIPTION()).ToString() + "(*" + iterator->GetProperty(mitk::IFileWriter::PROP_EXTENSION()).ToString() + ");;"; + entries.push_back(entry); + } + std::sort(entries.begin(), entries.end()); + + std::string result = "Known Extensions (" + knownExtensions + ");;All (*)"; + for (std::vector::const_iterator iterator = entries.begin(), end = entries.end(); + iterator != end; ++iterator) + { + result += ";;" + *iterator; + } + return result; +} diff --git a/Core/Code/IO/mitkFileWriterRegistry.h b/Core/Code/IO/mitkFileWriterRegistry.h new file mode 100644 index 0000000000..c65648cda1 --- /dev/null +++ b/Core/Code/IO/mitkFileWriterRegistry.h @@ -0,0 +1,108 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef FileWriterRegistry_H_HEADER_INCLUDED_C1E7E521 +#define FileWriterRegistry_H_HEADER_INCLUDED_C1E7E521 + +#include + +// Microservices +#include +#include +#include + +#include "mitkIFileWriter.h" + +// Temporarily disable warning until PIMPL pattern is implemented here +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4251) +#endif + +namespace mitk { + class BaseData; +} + +namespace mitk { + /** + * @ingroup Process + * + * Provides convenient access to mitk::IFileWriter instances and writing + * files from mitk::BaseData types. + * + * \note The life-time of all mitk::IFileWriter objects returned by an + * instance of this class ends with the destruction of that instance. + */ + class MITK_CORE_EXPORT FileWriterRegistry + { + public: + + FileWriterRegistry(); + ~FileWriterRegistry(); + + static void Write(const mitk::BaseData* data, const std::string& path, us::ModuleContext* context = us::GetModuleContext()); + + static void Write(const mitk::BaseData* data, std::ostream& os, us::ModuleContext* context = us::GetModuleContext()); + + /** + * Returns a compatible Writer to the given file extension + */ + mitk::IFileWriter* GetWriter(const std::string& baseDataType, const std::string& extension = std::string(), + const mitk::IFileWriter::OptionNames& options = mitk::IFileWriter::OptionNames(), + us::ModuleContext* context = us::GetModuleContext() ); + + mitk::IFileWriter* GetWriter(const mitk::BaseData* baseData, const std::string& extension = std::string(), + const mitk::IFileWriter::OptionNames& options = mitk::IFileWriter::OptionNames(), + us::ModuleContext* context = us::GetModuleContext() ); + + std::vector GetWriters(const std::string& baseDataType, const std::string& extension = std::string(), + const mitk::IFileWriter::OptionNames& options = mitk::IFileWriter::OptionNames(), + us::ModuleContext* context = us::GetModuleContext() ); + + std::vector GetWriters(const mitk::BaseData* baseData, const std::string& extension = std::string(), + const mitk::IFileWriter::OptionNames& options = mitk::IFileWriter::OptionNames(), + us::ModuleContext* context = us::GetModuleContext() ); + + void UngetWriter(mitk::IFileWriter* writer); + void UngetWriters(const std::vector& writers); + + // TODO: We should not generate GUI dependent strings here. Maybe just return a pair of extensions + // and descriptions. + std::string GetSupportedExtensions(const std::string& extension = std::string(), us::ModuleContext* context = us::GetModuleContext()); + + std::string GetSupportedWriters(const std::string& basedataType, us::ModuleContext* context = us::GetModuleContext()); + + protected: + + std::string CreateFileDialogString(const std::vector >& refs); + + bool WriterSupportsOptions(mitk::IFileWriter* writer, const mitk::IFileWriter::OptionNames& options); + + private: + + // purposely not implemented + FileWriterRegistry(const FileWriterRegistry&); + FileWriterRegistry& operator=(const FileWriterRegistry&); + + std::map > m_ServiceObjects; + }; +} // namespace mitk + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif /* FileWriterRegistry_H_HEADER_INCLUDED_C1E7E521 */ diff --git a/Core/Code/IO/mitkFileWriterWithInformation.h b/Core/Code/IO/mitkFileWriterWithInformation.h index 707b342f24..aad9b965e0 100644 --- a/Core/Code/IO/mitkFileWriterWithInformation.h +++ b/Core/Code/IO/mitkFileWriterWithInformation.h @@ -1,41 +1,41 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef FILEWRITERWITHINFORMATION_H_INCLUDED #define FILEWRITERWITHINFORMATION_H_INCLUDED #include "mitkFileWriter.h" #include "mitkBaseData.h" namespace mitk { /** * \brief Interface for FileWriters with extra information. * Should be merged into FileWriter. + * + * \deprecatedSince{2014_03} Use mitk::IFileWriter instead. */ -class MITK_CORE_EXPORT FileWriterWithInformation : public FileWriter { +class FileWriterWithInformation : public FileWriter { public: mitkClassMacro(FileWriterWithInformation,FileWriter); virtual const char *GetDefaultFilename() = 0; virtual const char *GetFileDialogPattern() = 0; virtual const char *GetDefaultExtension() = 0; virtual bool CanWriteBaseDataType(BaseData::Pointer data) = 0; virtual void DoWrite(BaseData::Pointer data) = 0; }; } #endif - - diff --git a/Core/Code/IO/mitkIOAdapter.h b/Core/Code/IO/mitkIOAdapter.h index 3f38cbede2..9fc3ea4997 100644 --- a/Core/Code/IO/mitkIOAdapter.h +++ b/Core/Code/IO/mitkIOAdapter.h @@ -1,93 +1,95 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __mitkIOAdapter_h #define __mitkIOAdapter_h #include "mitkBaseProcess.h" #include "itkObject.h" namespace mitk { //##Documentation //## @brief IOAdapterBase class is an abstract adapter class for IO process objects. //## //## @ingroup IO -class MITK_CORE_EXPORT IOAdapterBase: public itk::Object +//## @deprecatedSince{2014_03} Use mitk::IFileReader instead +class IOAdapterBase: public itk::Object { public: /** Standard typedefs. */ typedef IOAdapterBase Self; typedef itk::Object Superclass; typedef itk::SmartPointerPointer; typedef itk::SmartPointerConstPointer; /// Create an object and return a pointer to it as a mitk::BaseProcess. virtual itk::SmartPointer CreateIOProcessObject(const std::string filename, const std::string filePrefix, const std::string filePattern) = 0; virtual bool CanReadFile(const std::string filename, const std::string filePrefix, const std::string filePattern) = 0; protected: IOAdapterBase() {} ~IOAdapterBase() {} private: IOAdapterBase(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented }; //##Documentation //## @brief IOAdapter class is an adapter class for instantiation of IO process objects. //## Additional this interface defines the function CanReadFile(). //## This interface allows the target (object) the access to the adaptee (IO process object). //## @ingroup IO +//## @deprecatedSince{2014_03} Use mitk::IFileReader instead template class IOAdapter : public IOAdapterBase { public: /** Standard class typedefs. */ typedef IOAdapter Self; typedef itk::SmartPointer Pointer; /** Methods from mitk::BaseProcess. */ itkFactorylessNewMacro(Self); mitk::BaseProcess::Pointer CreateIOProcessObject(const std::string filename, const std::string filePrefix, const std::string filePattern) { typename T::Pointer ioProcessObject = T::New(); ioProcessObject->SetFileName(filename.c_str()); ioProcessObject->SetFilePrefix(filePrefix.c_str()); ioProcessObject->SetFilePattern(filePattern.c_str()); return ioProcessObject.GetPointer(); } virtual bool CanReadFile(const std::string filename, const std::string filePrefix, const std::string filePattern) { return T::CanReadFile(filename, filePrefix, filePattern); } protected: IOAdapter() {} ~IOAdapter() {} private: IOAdapter(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented }; } // end namespace mitk #endif diff --git a/Core/Code/IO/mitkIOUtil.cpp b/Core/Code/IO/mitkIOUtil.cpp index bf01ca9c70..910227eef7 100644 --- a/Core/Code/IO/mitkIOUtil.cpp +++ b/Core/Code/IO/mitkIOUtil.cpp @@ -1,768 +1,769 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkIOUtil.h" -#include "mitkDataNodeFactory.h" -#include "mitkImageWriter.h" -#include "mitkPointSetWriter.h" -#include "mitkSurfaceVtkWriter.h" #include #include #include #include #include #include #include +#include +#include //ITK #include //VTK #include #include #include #include #include static std::string GetLastErrorStr() { #ifdef US_PLATFORM_POSIX return std::string(strerror(errno)); #else // Retrieve the system error message for the last-error code LPVOID lpMsgBuf; DWORD dw = GetLastError(); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); std::string errMsg((LPCTSTR)lpMsgBuf); LocalFree(lpMsgBuf); return errMsg; #endif } #ifdef US_PLATFORM_WINDOWS #include #include // make the posix flags point to the obsolte bsd types on windows #define S_IRUSR S_IREAD #define S_IWUSR S_IWRITE #else #include #include #include #endif #include #include static const char validLetters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; // A cross-platform version of the mkstemps function static int mkstemps_compat(char* tmpl, int suffixlen) { static unsigned long long value = 0; int savedErrno = errno; // Lower bound on the number of temporary files to attempt to generate. #define ATTEMPTS_MIN (62 * 62 * 62) /* The number of times to attempt to generate a temporary file. To conform to POSIX, this must be no smaller than TMP_MAX. */ #if ATTEMPTS_MIN < TMP_MAX const unsigned int attempts = TMP_MAX; #else const unsigned int attempts = ATTEMPTS_MIN; #endif const int len = strlen(tmpl); if ((len - suffixlen) < 6 || strncmp(&tmpl[len - 6 - suffixlen], "XXXXXX", 6)) { errno = EINVAL; return -1; } /* This is where the Xs start. */ char* XXXXXX = &tmpl[len - 6 - suffixlen]; /* Get some more or less random data. */ #ifdef US_PLATFORM_WINDOWS { SYSTEMTIME stNow; FILETIME ftNow; // get system time GetSystemTime(&stNow); stNow.wMilliseconds = 500; if (!SystemTimeToFileTime(&stNow, &ftNow)) { errno = -1; return -1; } unsigned long long randomTimeBits = ((static_cast(ftNow.dwHighDateTime) << 32) | static_cast(ftNow.dwLowDateTime)); value = randomTimeBits ^ static_cast(GetCurrentThreadId()); } #else { struct timeval tv; gettimeofday(&tv, NULL); unsigned long long randomTimeBits = ((static_cast(tv.tv_usec) << 32) | static_cast(tv.tv_sec)); value = randomTimeBits ^ static_cast(getpid()); } #endif for (unsigned int count = 0; count < attempts; value += 7777, ++count) { unsigned long long v = value; /* Fill in the random bits. */ XXXXXX[0] = validLetters[v % 62]; v /= 62; XXXXXX[1] = validLetters[v % 62]; v /= 62; XXXXXX[2] = validLetters[v % 62]; v /= 62; XXXXXX[3] = validLetters[v % 62]; v /= 62; XXXXXX[4] = validLetters[v % 62]; v /= 62; XXXXXX[5] = validLetters[v % 62]; int fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); if (fd >= 0) { errno = savedErrno; return fd; } else if (errno != EEXIST) { return -1; } } /* We got out of the loop because we ran out of combinations to try. */ errno = EEXIST; return -1; } // A cross-platform version of the POSIX mkdtemp function static char* mkdtemps_compat(char* tmpl, int suffixlen) { static unsigned long long value = 0; int savedErrno = errno; // Lower bound on the number of temporary dirs to attempt to generate. #define ATTEMPTS_MIN (62 * 62 * 62) /* The number of times to attempt to generate a temporary dir. To conform to POSIX, this must be no smaller than TMP_MAX. */ #if ATTEMPTS_MIN < TMP_MAX const unsigned int attempts = TMP_MAX; #else const unsigned int attempts = ATTEMPTS_MIN; #endif const int len = strlen(tmpl); if ((len - suffixlen) < 6 || strncmp(&tmpl[len - 6 - suffixlen], "XXXXXX", 6)) { errno = EINVAL; return NULL; } /* This is where the Xs start. */ char* XXXXXX = &tmpl[len - 6 - suffixlen]; /* Get some more or less random data. */ #ifdef US_PLATFORM_WINDOWS { SYSTEMTIME stNow; FILETIME ftNow; // get system time GetSystemTime(&stNow); stNow.wMilliseconds = 500; if (!SystemTimeToFileTime(&stNow, &ftNow)) { errno = -1; return NULL; } unsigned long long randomTimeBits = ((static_cast(ftNow.dwHighDateTime) << 32) | static_cast(ftNow.dwLowDateTime)); value = randomTimeBits ^ static_cast(GetCurrentThreadId()); } #else { struct timeval tv; gettimeofday(&tv, NULL); unsigned long long randomTimeBits = ((static_cast(tv.tv_usec) << 32) | static_cast(tv.tv_sec)); value = randomTimeBits ^ static_cast(getpid()); } #endif unsigned int count = 0; for (; count < attempts; value += 7777, ++count) { unsigned long long v = value; /* Fill in the random bits. */ XXXXXX[0] = validLetters[v % 62]; v /= 62; XXXXXX[1] = validLetters[v % 62]; v /= 62; XXXXXX[2] = validLetters[v % 62]; v /= 62; XXXXXX[3] = validLetters[v % 62]; v /= 62; XXXXXX[4] = validLetters[v % 62]; v /= 62; XXXXXX[5] = validLetters[v % 62]; #ifdef US_PLATFORM_WINDOWS int fd = _mkdir (tmpl); //, _S_IREAD | _S_IWRITE | _S_IEXEC); #else int fd = mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR); #endif if (fd >= 0) { errno = savedErrno; return tmpl; } else if (errno != EEXIST) { return NULL; } } /* We got out of the loop because we ran out of combinations to try. */ errno = EEXIST; return NULL; } //#endif namespace mitk { const std::string IOUtil::DEFAULTIMAGEEXTENSION = ".nrrd"; const std::string IOUtil::DEFAULTSURFACEEXTENSION = ".stl"; const std::string IOUtil::DEFAULTPOINTSETEXTENSION = ".mps"; #ifdef US_PLATFORM_WINDOWS std::string IOUtil::GetProgramPath() { char path[512]; std::size_t index = std::string(path, GetModuleFileName(NULL, path, 512)).find_last_of('\\'); return std::string(path, index); } #elif defined(US_PLATFORM_APPLE) #include std::string IOUtil::GetProgramPath() { char path[512]; uint32_t size = sizeof(path); if (_NSGetExecutablePath(path, &size) == 0) { std::size_t index = std::string(path).find_last_of('/'); std::string strPath = std::string(path, index); //const char* execPath = strPath.c_str(); //mitk::StandardFileLocations::GetInstance()->AddDirectoryForSearch(execPath,false); return strPath; } return std::string(); } #else #include #include #include std::string IOUtil::GetProgramPath() { std::stringstream ss; ss << "/proc/" << getpid() << "/exe"; char proc[512] = {0}; ssize_t ch = readlink(ss.str().c_str(), proc, 512); if (ch == -1) return std::string(); std::size_t index = std::string(proc).find_last_of('/'); return std::string(proc, index); } #endif std::string IOUtil::GetTempPath() { static std::string result; if (result.empty()) { #ifdef US_PLATFORM_WINDOWS char tempPathTestBuffer[1]; DWORD bufferLength = ::GetTempPath(1, tempPathTestBuffer); if (bufferLength == 0) { mitkThrow() << GetLastErrorStr(); } std::vector tempPath(bufferLength); bufferLength = ::GetTempPath(bufferLength, &tempPath[0]); if (bufferLength == 0) { mitkThrow() << GetLastErrorStr(); } result.assign(tempPath.begin(), tempPath.begin() + static_cast(bufferLength)); #else result = "/tmp/"; #endif } return result; } std::string IOUtil::CreateTemporaryFile(const std::string& templateName, std::string path) { ofstream tmpOutputStream; std::string returnValue = CreateTemporaryFile(tmpOutputStream,templateName,path); tmpOutputStream.close(); return returnValue; } std::string IOUtil::CreateTemporaryFile(std::ofstream& f, const std::string& templateName, std::string path) { return CreateTemporaryFile(f, std::ios_base::out | std::ios_base::trunc, templateName, path); } std::string IOUtil::CreateTemporaryFile(std::ofstream& f, std::ios_base::openmode mode, const std::string& templateName, std::string path) { if (path.empty()) { path = GetTempPath(); } path += "/" + templateName; std::vector dst_path(path.begin(), path.end()); dst_path.push_back('\0'); std::size_t lastX = path.find_last_of('X'); std::size_t firstX = path.find_last_not_of('X', lastX); int firstNonX = firstX == std::string::npos ? - 1 : firstX - 1; while (lastX != std::string::npos && (lastX - firstNonX) < 6) { lastX = path.find_last_of('X', firstX); firstX = path.find_last_not_of('X', lastX); firstNonX = firstX == std::string::npos ? - 1 : firstX - 1; } std::size_t suffixlen = lastX == std::string::npos ? path.size() : path.size() - lastX - 1; int fd = mkstemps_compat(&dst_path[0], suffixlen); if(fd != -1) { path.assign(dst_path.begin(), dst_path.end() - 1); f.open(path.c_str(), mode | std::ios_base::out | std::ios_base::trunc); close(fd); } else { mitkThrow() << "Creating temporary file " << &dst_path[0] << " failed: " << GetLastErrorStr(); } return path; } std::string IOUtil::CreateTemporaryDirectory(const std::string& templateName, std::string path) { if (path.empty()) { path = GetTempPath(); } path += "/" + templateName; std::vector dst_path(path.begin(), path.end()); dst_path.push_back('\0'); std::size_t lastX = path.find_last_of('X'); std::size_t firstX = path.find_last_not_of('X', lastX); int firstNonX = firstX == std::string::npos ? - 1 : firstX - 1; while (lastX != std::string::npos && (lastX - firstNonX) < 6) { lastX = path.find_last_of('X', firstX); firstX = path.find_last_not_of('X', lastX); firstNonX = firstX == std::string::npos ? - 1 : firstX - 1; } std::size_t suffixlen = lastX == std::string::npos ? path.size() : path.size() - lastX - 1; if(mkdtemps_compat(&dst_path[0], suffixlen) == NULL) { mitkThrow() << "Creating temporary directory " << &dst_path[0] << " failed: " << GetLastErrorStr(); } path.assign(dst_path.begin(), dst_path.end() - 1); return path; } int IOUtil::LoadFiles(const std::vector &fileNames, DataStorage &ds) { // Get the set of registered mitk::IDataNodeReader services us::ModuleContext* context = us::GetModuleContext(); const std::vector > refs = context->GetServiceReferences(); std::vector services; services.reserve(refs.size()); for (std::vector >::const_iterator i = refs.begin(); i != refs.end(); ++i) { IDataNodeReader* s = context->GetService(*i); if (s != 0) { services.push_back(s); } } mitk::ProgressBar::GetInstance()->AddStepsToDo(2*fileNames.size()); // Iterate over all file names and use the IDataNodeReader services // to load them. int nodesRead = 0; for (std::vector::const_iterator i = fileNames.begin(); i != fileNames.end(); ++i) { for (std::vector::const_iterator readerIt = services.begin(); readerIt != services.end(); ++readerIt) { try { int n = (*readerIt)->Read(*i, ds); nodesRead += n; if (n > 0) break; } catch (const std::exception& e) { MITK_WARN << e.what(); } } mitk::ProgressBar::GetInstance()->Progress(2); } for (std::vector >::const_iterator i = refs.begin(); i != refs.end(); ++i) { context->UngetService(*i); } return nodesRead; } DataStorage::Pointer IOUtil::LoadFiles(const std::vector& fileNames) { mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); LoadFiles(fileNames, *ds); return ds.GetPointer(); } BaseData::Pointer IOUtil::LoadBaseData(const std::string& path) { return LoadDataNode(path)->GetData(); } DataNode::Pointer IOUtil::LoadDataNode(const std::string& path) { - mitk::DataNodeFactory::Pointer reader = mitk::DataNodeFactory::New(); - try - { - reader->SetFileName( path ); - reader->Update(); - - if((reader->GetNumberOfOutputs()<1)) - { - MITK_ERROR << "Could not find data '" << path << "'"; - mitkThrow() << "An exception occured during loading the file " << path << ". Exception says could not find data."; - } + try + { + mitk::FileReaderRegistry readerRegistry; + std::vector baseDataList = readerRegistry.Read(path); - mitk::DataNode::Pointer node = reader->GetOutput(); + BaseData::Pointer baseData; + if (!baseDataList.empty()) baseData = baseDataList.front(); - if(node.IsNull()) - { - MITK_ERROR << "Could not find path: '" << path << "'" << " datanode is NULL" ; - mitkThrow() << "An exception occured during loading the file " << path << ". Exception says datanode is NULL."; - } - - return reader->GetOutput( 0 ); - } - catch ( itk::ExceptionObject & e ) + if(baseData.IsNull()) { - MITK_ERROR << "Exception occured during load data of '" << path << "': Exception: " << e.what(); - mitkThrow() << "An exception occured during loading the file " << path << ". Exception says: " << e.what(); + MITK_ERROR << "Could not find data '" << path << "'"; + mitkThrow() << "An exception occured during loading the file " << path << ". Exception says could not find data."; } + + mitk::DataNode::Pointer node = mitk::DataNode::New(); + node->SetData(baseData); + SetDefaultDataNodeProperties(node, path); + + return node; + } + catch (const std::exception& e) + { + MITK_ERROR << "Exception occured during load data of '" << path << "': Exception: " << e.what(); + mitkThrow() << "An exception occured during loading the file " << path << ". Exception says: " << e.what(); + } } Image::Pointer IOUtil::LoadImage(const std::string& path) { mitk::DataNode::Pointer node = LoadDataNode(path); mitk::Image::Pointer image = dynamic_cast(node->GetData()); if(image.IsNull()) { MITK_ERROR << "Image is NULL '" << path << "'"; mitkThrow() << "An exception occured during loading the image " << path << ". Exception says: Image is NULL."; } return image; } Surface::Pointer IOUtil::LoadSurface(const std::string& path) { mitk::DataNode::Pointer node = LoadDataNode(path); mitk::Surface::Pointer surface = dynamic_cast(node->GetData()); if(surface.IsNull()) { MITK_ERROR << "Surface is NULL '" << path << "'"; mitkThrow() << "An exception occured during loading the file " << path << ". Exception says: Surface is NULL."; } return surface; } PointSet::Pointer IOUtil::LoadPointSet(const std::string& path) { mitk::DataNode::Pointer node = LoadDataNode(path); mitk::PointSet::Pointer pointset = dynamic_cast(node->GetData()); if(pointset.IsNull()) { MITK_ERROR << "PointSet is NULL '" << path << "'"; mitkThrow() << "An exception occured during loading the file " << path << ". Exception says: Pointset is NULL."; } return pointset; } bool IOUtil::SaveImage(mitk::Image::Pointer image, const std::string& path) { + return SaveBaseData(image, path); + /* std::string dir = itksys::SystemTools::GetFilenamePath( path ); std::string baseFilename = itksys::SystemTools::GetFilenameWithoutExtension( path ); std::string extension = itksys::SystemTools::GetFilenameExtension( path ); if (dir == "") dir = "."; std::string finalFileName = dir + "/" + baseFilename; mitk::ImageWriter::Pointer imageWriter = mitk::ImageWriter::New(); //check if an extension is given, else use the defaul extension if( extension == "" ) { MITK_WARN << extension << " extension is not set. Extension set to default: " << finalFileName << DEFAULTIMAGEEXTENSION; extension = DEFAULTIMAGEEXTENSION; } // check if extension is suitable for writing image data if (!imageWriter->IsExtensionValid(extension)) { MITK_WARN << extension << " extension is unknown. Extension set to default: " << finalFileName << DEFAULTIMAGEEXTENSION; extension = DEFAULTIMAGEEXTENSION; } try { //write the data imageWriter->SetInput(image); imageWriter->SetFileName(finalFileName.c_str()); imageWriter->SetExtension(extension.c_str()); imageWriter->Write(); } catch ( std::exception& e ) { MITK_ERROR << " during attempt to write '" << finalFileName + extension << "' Exception says:"; MITK_ERROR << e.what(); mitkThrow() << "An exception occured during writing the file " << finalFileName << ". Exception says " << e.what(); } return true; + */ } bool IOUtil::SaveSurface(Surface::Pointer surface, const std::string& path) { + return SaveBaseData(surface, path); + /* std::string dir = itksys::SystemTools::GetFilenamePath( path ); std::string baseFilename = itksys::SystemTools::GetFilenameWithoutLastExtension( path ); std::string extension = itksys::SystemTools::GetFilenameLastExtension( path ); if (dir == "") dir = "."; std::string finalFileName = dir + "/" + baseFilename; if (extension == "") // if no extension has been set we use the default extension { MITK_WARN << extension << " extension is not set. Extension set to default: " << finalFileName << DEFAULTSURFACEEXTENSION; extension = DEFAULTSURFACEEXTENSION; } try { finalFileName += extension; if(extension == ".stl" ) { mitk::SurfaceVtkWriter::Pointer surfaceWriter = mitk::SurfaceVtkWriter::New(); // check if surface actually consists of triangles; if not, the writer will not do anything; so, convert to triangles... vtkPolyData* polys = surface->GetVtkPolyData(); if( polys->GetNumberOfStrips() > 0 ) { vtkSmartPointer triangleFilter = vtkSmartPointer::New(); triangleFilter->SetInputData(polys); triangleFilter->Update(); polys = triangleFilter->GetOutput(); polys->Register(NULL); surface->SetVtkPolyData(polys); } surfaceWriter->SetInput( surface ); surfaceWriter->SetFileName( finalFileName.c_str() ); surfaceWriter->GetVtkWriter()->SetFileTypeToBinary(); surfaceWriter->Write(); } else if(extension == ".vtp") { mitk::SurfaceVtkWriter::Pointer surfaceWriter = mitk::SurfaceVtkWriter::New(); surfaceWriter->SetInput( surface ); surfaceWriter->SetFileName( finalFileName.c_str() ); surfaceWriter->GetVtkWriter()->SetDataModeToBinary(); surfaceWriter->Write(); } else if(extension == ".vtk") { mitk::SurfaceVtkWriter::Pointer surfaceWriter = mitk::SurfaceVtkWriter::New(); surfaceWriter->SetInput( surface ); surfaceWriter->SetFileName( finalFileName.c_str() ); surfaceWriter->Write(); } else { // file extension not suitable for writing specified data type MITK_ERROR << "File extension is not suitable for writing'" << finalFileName; mitkThrow() << "An exception occured during writing the file " << finalFileName << ". File extension " << extension << " is not suitable for writing."; } } catch(std::exception& e) { MITK_ERROR << " during attempt to write '" << finalFileName << "' Exception says:"; MITK_ERROR << e.what(); mitkThrow() << "An exception occured during writing the file " << finalFileName << ". Exception says " << e.what(); } return true; + */ } bool IOUtil::SavePointSet(PointSet::Pointer pointset, const std::string& path) { + return SaveBaseData(pointset, path); + /* mitk::PointSetWriter::Pointer pointSetWriter = mitk::PointSetWriter::New(); std::string dir = itksys::SystemTools::GetFilenamePath( path ); std::string baseFilename = itksys::SystemTools::GetFilenameWithoutLastExtension( path ); std::string extension = itksys::SystemTools::GetFilenameLastExtension( path ); if (dir == "") dir = "."; std::string finalFileName = dir + "/" + baseFilename; if (extension == "") // if no extension has been entered manually into the filename { MITK_WARN << extension << " extension is not set. Extension set to default: " << finalFileName << DEFAULTPOINTSETEXTENSION; extension = DEFAULTPOINTSETEXTENSION; } // check if extension is valid if (!pointSetWriter->IsExtensionValid(extension)) { MITK_WARN << extension << " extension is unknown. Extension set to default: " << finalFileName << DEFAULTPOINTSETEXTENSION; extension = DEFAULTPOINTSETEXTENSION; } try { pointSetWriter->SetInput( pointset ); finalFileName += extension; pointSetWriter->SetFileName( finalFileName.c_str() ); pointSetWriter->Update(); } catch( std::exception& e ) { MITK_ERROR << " during attempt to write '" << finalFileName << "' Exception says:"; MITK_ERROR << e.what(); mitkThrow() << "An exception occured during writing the file " << finalFileName << ". Exception says " << e.what(); } return true; + */ } bool IOUtil::SaveBaseData( mitk::BaseData* data, const std::string& path ) { if (data == NULL || path.empty()) return false; - std::string dir = itksys::SystemTools::GetFilenamePath( path ); - std::string baseFilename = itksys::SystemTools::GetFilenameWithoutExtension( path ); - std::string extension = itksys::SystemTools::GetFilenameExtension( path ); - if (dir == "") - dir = "."; - std::string fileNameWithoutExtension = dir + "/" + baseFilename; + try + { + mitk::FileWriterRegistry::Write(data, path); + } + catch(const std::exception& e) + { + MITK_ERROR << " Writing a " << data->GetNameOfClass() << " to " << path << " failed: " + << e.what(); + throw e; + } + + return true; +} - mitk::CoreObjectFactory::FileWriterList fileWriters = mitk::CoreObjectFactory::GetInstance()->GetFileWriters(); +void IOUtil::SetDefaultDataNodeProperties(DataNode* node, const std::string& filePath) +{ + // path + mitk::StringProperty::Pointer pathProp = mitk::StringProperty::New( itksys::SystemTools::GetFilenamePath(filePath) ); + node->SetProperty(StringProperty::PATH, pathProp); - for (mitk::CoreObjectFactory::FileWriterList::iterator it = fileWriters.begin() ; it != fileWriters.end() ; ++it) + // name already defined? + mitk::StringProperty::Pointer nameProp = dynamic_cast(node->GetProperty("name")); + if(nameProp.IsNull() || (strcmp(nameProp->GetValue(),"No Name!")==0)) { - if ( (*it)->CanWriteBaseDataType(data) ) + // name already defined in BaseData + mitk::StringProperty::Pointer baseDataNameProp = dynamic_cast(node->GetData()->GetProperty("name").GetPointer() ); + if(baseDataNameProp.IsNull() || (strcmp(baseDataNameProp->GetValue(),"No Name!")==0)) { - // Ensure a valid filename - if(baseFilename=="") - { - baseFilename = (*it)->GetDefaultFilename(); - } - // Check if an extension exists already and if not, append the default extension - if (extension=="" ) - { - extension=(*it)->GetDefaultExtension(); - } - else - { - if (!(*it)->IsExtensionValid(extension)) - { - MITK_WARN << extension << " extension is unknown"; - continue; - } - } - - std::string finalFileName = fileNameWithoutExtension + extension; - try - { - (*it)->SetFileName( finalFileName.c_str() ); - (*it)->DoWrite( data ); - return true; - } - catch( const std::exception& e ) - { - MITK_ERROR << " during attempt to write '" << finalFileName << "' Exception says:"; - MITK_ERROR << e.what(); - mitkThrow() << "An exception occured during writing the file " << finalFileName << ". Exception says " << e.what(); - } + // name neither defined in node, nor in BaseData -> name = filename + nameProp = mitk::StringProperty::New( itksys::SystemTools::GetFilenameWithoutExtension(filePath)); + node->SetProperty("name", nameProp); + } + else + { + // name defined in BaseData! + nameProp = mitk::StringProperty::New(baseDataNameProp->GetValue()); + node->SetProperty("name", nameProp); } } - return false; + // visibility + if(!node->GetProperty("visible")) + { + node->SetVisibility(true); + } } } diff --git a/Core/Code/IO/mitkIOUtil.h b/Core/Code/IO/mitkIOUtil.h index 215111d810..127850d7b1 100644 --- a/Core/Code/IO/mitkIOUtil.h +++ b/Core/Code/IO/mitkIOUtil.h @@ -1,267 +1,271 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKIOUTIL_H #define MITKIOUTIL_H #include #include #include #include #include #include namespace mitk { /** * \ingroup IO * * \brief A utility class to load and save data from/to the local file system. * * This method LoadFiles queries the MITK Micro Services registry for registered mitk::IDataNodeReader service * instances. The service instance with the highest ranking will be asked first to load the * given file. On error (exception thrown) or if no mitk::DataNode was constructed, the next * service instance is used. * * The methods LoadImage, LoadSurface, and LoadPointSet are convenience methods for general loading of * the three main data types in MITK. They all use the more generic method LoadDataNode. * * The methods SaveImage, SaveSurface, and SurfacePointSet are also meant for convenience (e.g. during testing). * Currently, there is no generic way to save a generic DataNode with an appropriate format. Thus, every method * initializes the corresponding instance of the special writer for the data type. * * \see mitk::IDataNodeReader */ class MITK_CORE_EXPORT IOUtil { public: /** * Get the file system path where the running executable is located. * * @return The location of the currently running executable, without the filename. */ static std::string GetProgramPath(); /** * Get the default temporary path. * * @return The default path for temporary data. */ static std::string GetTempPath(); /** * Create and open a temporary file. * * This method generates a unique temporary filename from \c templateName, creates * and opens the file using the output stream \c tmpStream and returns the name of * the newly create file. * * The \c templateName argument must contain six consective 'X' characters ("XXXXXX") * and these are replaced with a string that makes the filename unique. * * The file is created with read and write permissions for owner only. * * @param tmpStream The output stream for writing to the temporary file. * @param templateName An optional template for the filename. * @param path An optional path where the temporary file should be created. Defaults * to the default temp path as returned by GetTempPath(). * @return The filename of the created temporary file. * * @throw mitk::Exception if the temporary file could not be created. */ static std::string CreateTemporaryFile(std::ofstream& tmpStream, const std::string& templateName = "XXXXXX", std::string path = std::string()); /** * Create and open a temporary file. * * This method generates a unique temporary filename from \c templateName, creates * and opens the file using the output stream \c tmpStream and the specified open * mode \c mode and returns the name of the newly create file. The open mode is always * OR'd with \begin{code}std::ios_base::out | std::ios_base::trunc\end{code}. * * The \c templateName argument must contain six consective 'X' characters ("XXXXXX") * and these are replaced with a string that makes the filename unique. * * The file is created with read and write permissions for owner only. * * @param tmpStream The output stream for writing to the temporary file. * @param mode The open mode for the temporary file stream. * @param templateName An optional template for the filename. * @param path An optional path where the temporary file should be created. Defaults * to the default temp path as returned by GetTempPath(). * @return The filename of the created temporary file. * * @throw mitk::Exception if the temporary file could not be created. */ static std::string CreateTemporaryFile(std::ofstream& tmpStream, std::ios_base::openmode mode, const std::string& templateName = "XXXXXX", std::string path = std::string()); /** * Creates an empty temporary file. * * This method generates a unique temporary filename from \c templateName and creates * this file. * * The file is created with read and write permissions for owner only. * * --- * This version is potentially unsafe because the created temporary file is not kept open * and could be used by another process between calling this method and opening the returned * file path for reading or writing. * --- * * @return The filename of the created temporary file. * @param templateName An optional template for the filename. * @param path An optional path where the temporary file should be created. Defaults * to the default temp path as returned by GetTempPath(). * @throw mitk::Exception if the temporary file could not be created. */ static std::string CreateTemporaryFile(const std::string& templateName = "XXXXXX", std::string path = std::string()); /** * Create a temporary directory. * * This method generates a uniquely named temporary directory from \c templateName. * The last set of six consecutive 'X' characters in \c templateName is replaced * with a string that makes the directory name unique. * * The directory is created with read, write and executable permissions for owner only. * * @param templateName An optional template for the directory name. * @param path An optional path where the temporary directory should be created. Defaults * to the default temp path as returned by GetTempPath(). * @return The filename of the created temporary file. * * @throw mitk::Exception if the temporary directory could not be created. */ static std::string CreateTemporaryDirectory(const std::string& templateName = "XXXXXX", std::string path = std::string()); /** * Load a files in fileNames and add the constructed mitk::DataNode instances * to the mitk::DataStorage storage * * \param fileNames A list (vector) of absolute file name paths. * \param storage The data storage to which the constructed data nodes are added. * \return The number of added mitk::DataNode instances. */ static int LoadFiles(const std::vector&fileNames, DataStorage& storage); /** * This method will create a new mitk::DataStorage instance and pass it to * LoadFiles(std::vector,DataStorage). * * \param fileNames A list (vector) of absolute file name paths. * \return The new mitk::DataStorage containing the constructed data nodes. * * \see LoadFiles(std::vector,DataStorage) */ static DataStorage::Pointer LoadFiles(const std::vector& fileNames); /** * @brief Create a BaseData object from the given file. * @param path The path to the file including file name and file extension. * @throws mitk::Exception In case of an error when reading the file. * @return Returns the created BaseData object. */ static mitk::BaseData::Pointer LoadBaseData(const std::string& path); /** * @brief LoadDataNode Method to load an arbitrary DataNode. * @param path The path to the file including file name and file extension. * @throws mitk::Exception This exception is thrown when the DataNodeFactory is not able to read/find the file * or the DataNode is NULL. * @return Returns the DataNode. */ static mitk::DataNode::Pointer LoadDataNode(const std::string& path); /** * @brief LoadImage Convenience method to load an arbitrary mitkImage. * @param path The path to the image including file name and file extension. * @throws mitk::Exception This exception is thrown when the Image is NULL. * @return Returns the mitkImage. */ static mitk::Image::Pointer LoadImage(const std::string& path); /** * @brief LoadSurface Convenience method to load an arbitrary mitkSurface. * @param path The path to the surface including file name and file extension. * @throws mitk::Exception This exception is thrown when the Surface is NULL. * @return Returns the mitkSurface. */ static mitk::Surface::Pointer LoadSurface(const std::string& path); /** * @brief LoadPointSet Convenience method to load an arbitrary mitkPointSet. * @param path The path to the pointset including file name and file extension (currently, only .mps is supported). * @throws mitk::Exception This exception is thrown when the PointSet is NULL. * @return Returns the mitkPointSet. */ static mitk::PointSet::Pointer LoadPointSet(const std::string& path); /** * @brief SaveImage Convenience method to save an arbitrary mitkImage. * @param path The path to the image including file name and file extension. * If not extention is set, the default value (defined in DEFAULTIMAGEEXTENSION) is used. * @param image The image to save. * @throws mitk::Exception This exception is thrown when the writer is not able to write the image. * @return Returns true for success else false. */ static bool SaveImage(mitk::Image::Pointer image, const std::string& path); /** * @brief SaveBaseData Convenience method to save arbitrary baseData. * @param path The path to the image including file name and file extension. * If not extention is set, the default value (defined in DEFAULTIMAGEEXTENSION) is used. * @param data The data to save. * @throws mitk::Exception This exception is thrown when the writer is not able to write the image. * @return Returns true for success else false. */ static bool SaveBaseData(mitk::BaseData* data, const std::string& path); /** * @brief SaveSurface Convenience method to save an arbitrary mitkSurface. * @param path The path to the surface including file name and file extension. * If not extention is set, the default value (defined in DEFAULTSURFACEEXTENSION) is used. * @throws mitk::Exception This exception is thrown when the writer is not able to write the surface. * or if the fileextension is not suitable for writing. * @return Returns true for success else false. */ static bool SaveSurface(mitk::Surface::Pointer surface, const std::string& path); /** * @brief SavePointSet Convenience method to save an mitkPointSet. * @param path The path to the pointset including file name and file extension (currently, only .mps is supported). * If not extention is set, the default value (defined in DEFAULTPOINTSETEXTENSION) is used. * @throws mitk::Exception This exception is thrown when the writer is not able to write the pointset. * @return Returns true for success else false. */ static bool SavePointSet(mitk::PointSet::Pointer pointset, const std::string& path); static const std::string DEFAULTIMAGEEXTENSION; static const std::string DEFAULTSURFACEEXTENSION; static const std::string DEFAULTPOINTSETEXTENSION; +private: + + static void SetDefaultDataNodeProperties(mitk::DataNode* node, const std::string& filePath = std::string()); + }; } #endif // MITKIOUTIL_H diff --git a/Core/Code/IO/mitkImageWriter.cpp b/Core/Code/IO/mitkImageWriter.cpp deleted file mode 100644 index a4ce6ab7df..0000000000 --- a/Core/Code/IO/mitkImageWriter.cpp +++ /dev/null @@ -1,490 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -#include "mitkImageWriter.h" - -#include "mitkItkPictureWrite.h" -#include "mitkImage.h" -#include "mitkImageTimeSelector.h" -#include "mitkImageAccessByItk.h" -#include "mitkImageReadAccessor.h" - -#include -#include - -mitk::ImageWriter::ImageWriter() -{ - this->SetNumberOfRequiredInputs( 1 ); - m_MimeType = ""; - SetDefaultExtension(); -} - -mitk::ImageWriter::~ImageWriter() -{ -} - -void mitk::ImageWriter::SetFileName(const char* fileName) -{ - if ( fileName && ( fileName == this->m_FileName ) ) - { - return; - } - if ( fileName ) - { - this->m_FileName = fileName; - this->m_FileNameWithoutExtension = this->m_FileName; - this->m_Extension.clear(); - std::size_t pos = this->m_FileName.find_last_of("/\\"); - if (pos != std::string::npos) - { - std::size_t ppos = this->m_FileName.find_first_of('.', pos); - if (ppos != std::string::npos) - { - this->m_FileNameWithoutExtension = this->m_FileName.substr(0, ppos); - this->m_Extension = this->m_FileName.substr(ppos); - } - } - } - else - { - this->m_FileName.clear(); - this->m_FileNameWithoutExtension.clear(); - this->m_Extension.clear(); - } - this->Modified(); -} - -void mitk::ImageWriter::SetFileName(const std::string & fileName) -{ - this->SetFileName( fileName.c_str() ); -} - -void mitk::ImageWriter::SetExtension(const char* extension) -{ - if ( extension && ( extension == this->m_Extension ) ) - { - return; - } - if ( extension ) - { - this->m_Extension = extension; - this->m_FileName = this->m_FileNameWithoutExtension + this->m_Extension; - } - else - { - this->m_Extension.clear(); - this->m_FileName = this->m_FileNameWithoutExtension; - } - this->Modified(); -} - -void mitk::ImageWriter::SetExtension(const std::string & extension) -{ - this->SetFileName( extension.c_str() ); -} - -void mitk::ImageWriter::SetDefaultExtension() -{ - this->m_Extension = ".mhd"; - this->m_FileName = this->m_FileNameWithoutExtension + this->m_Extension; - this->Modified(); -} - -#include -#include -#include -static void writeVti(const char * filename, mitk::Image* image, int t=0) -{ - vtkXMLImageDataWriter * vtkwriter = vtkXMLImageDataWriter::New(); - vtkwriter->SetFileName( filename ); - vtkwriter->SetInputData(image->GetVtkImageData(t)); - vtkwriter->Write(); - vtkwriter->Delete(); -} - -#include - -void mitk::ImageWriter::WriteByITK(mitk::Image* image, const std::string& fileName) -{ - MITK_INFO << "Writing image: " << fileName << std::endl; - // Pictures and picture series like .png are written via a different mechanism then volume images. - // So, they are still multiplexed and thus not support vector images. - if (fileName.find(".png") != std::string::npos || fileName.find(".tif") != std::string::npos || fileName.find(".jpg") != std::string::npos || fileName.find(".bmp") != std::string::npos) - { - try - { - // switch processing of single/multi-component images - if( image->GetPixelType(0).GetNumberOfComponents() == 1) - { - AccessByItk_1( image, _mitkItkPictureWrite, fileName ); - } - else - { - AccessFixedPixelTypeByItk_1( image, _mitkItkPictureWriteComposite, MITK_ACCESSBYITK_PIXEL_TYPES_SEQ MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES_SEQ , fileName); - } - } - catch(itk::ExceptionObject &e) - { - std::cerr << "Caught " << e.what() << std::endl; - } - catch(std::exception &e) - { - std::cerr << "Caught std::exception " << e.what() << std::endl; - } - - return; - } - - // Implementation of writer using itkImageIO directly. This skips the use - // of templated itkImageFileWriter, which saves the multiplexing on MITK side. - - unsigned int dimension = image->GetDimension(); - unsigned int* dimensions = image->GetDimensions(); - mitk::PixelType pixelType = image->GetPixelType(); - mitk::Vector3D mitkSpacing = image->GetGeometry()->GetSpacing(); - mitk::Point3D mitkOrigin = image->GetGeometry()->GetOrigin(); - - // Due to templating in itk, we are forced to save a 4D spacing and 4D Origin, though they are not supported in MITK - itk::Vector spacing4D; - spacing4D[0] = mitkSpacing[0]; - spacing4D[1] = mitkSpacing[1]; - spacing4D[2] = mitkSpacing[2]; - spacing4D[3] = 1; // There is no support for a 4D spacing. However, we should have an valid value here - - itk::Vector origin4D; - origin4D[0] = mitkOrigin[0]; - origin4D[1] = mitkOrigin[1]; - origin4D[2] = mitkOrigin[2]; - origin4D[3] = 0; // There is no support for a 4D origin. However, we should have an valid value here - - itk::ImageIOBase::Pointer imageIO = itk::ImageIOFactory::CreateImageIO( fileName.c_str(), - itk::ImageIOFactory::WriteMode ); - - if(imageIO.IsNull()) - { - itkExceptionMacro(<< "Error: Could not create itkImageIO via factory for file " << fileName); - } - - // Set the necessary information for imageIO - imageIO->SetNumberOfDimensions(dimension); - imageIO->SetPixelType( pixelType.GetPixelType() ); - imageIO->SetComponentType( pixelType.GetComponentType() < PixelComponentUserType ? - static_cast(pixelType.GetComponentType()) : - itk::ImageIOBase::UNKNOWNCOMPONENTTYPE); - imageIO->SetNumberOfComponents( pixelType.GetNumberOfComponents() ); - - itk::ImageIORegion ioRegion( dimension ); - - for(unsigned int i=0; iSetDimensions(i,dimensions[i]); - imageIO->SetSpacing(i,spacing4D[i]); - imageIO->SetOrigin(i,origin4D[i]); - - mitk::Vector3D mitkDirection; - mitkDirection.SetVnlVector(image->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(i)); - itk::Vector direction4D; - direction4D[0] = mitkDirection[0]; - direction4D[1] = mitkDirection[1]; - direction4D[2] = mitkDirection[2]; - - // MITK only supports a 3x3 direction matrix. Due to templating in itk, however, we must - // save a 4x4 matrix for 4D images. in this case, add an homogneous component to the matrix. - if (i == 3) - direction4D[3] = 1; // homogenous component - else - direction4D[3] = 0; - - vnl_vector< double > axisDirection(dimension); - for(unsigned int j=0; jSetDirection( i, axisDirection ); - - ioRegion.SetSize(i, image->GetLargestPossibleRegion().GetSize(i) ); - ioRegion.SetIndex(i, image->GetLargestPossibleRegion().GetIndex(i) ); - } - - //use compression if available - imageIO->UseCompressionOn(); - - imageIO->SetIORegion(ioRegion); - imageIO->SetFileName(fileName); - - ImageReadAccessor imageAccess(image); - imageIO->Write(imageAccess.GetData()); -} - -void mitk::ImageWriter::GenerateData() -{ - const std::string& locale = "C"; - const std::string& currLocale = setlocale( LC_ALL, NULL ); - - if ( locale.compare(currLocale)!=0 ) - { - try - { - setlocale(LC_ALL, locale.c_str()); - } - catch(...) - { - MITK_INFO << "Could not set locale " << locale; - } - } - - if ( m_FileName == "" ) - { - itkWarningMacro( << "Sorry, filename has not been set!" ); - return ; - } - - FILE* tempFile = fopen(m_FileName.c_str(),"w"); - if (tempFile==NULL) - { - itkExceptionMacro(<<"File location not writeable"); - return; - } - fclose(tempFile); - remove(m_FileName.c_str()); - - // Creating clone of input image, since i might change the geometry - mitk::Image::Pointer input = const_cast(this->GetInput())->Clone(); - - // Check if geometry information will be lost - if (input->GetDimension() == 2) - { - if (!input->GetGeometry()->Is2DConvertable()) - { - MITK_WARN << "Saving a 2D image with 3D geometry information. Geometry information will be lost! You might consider using Convert2Dto3DImageFilter before saving."; - - // set matrix to identity - mitk::AffineTransform3D::Pointer affTrans = mitk::AffineTransform3D::New(); - affTrans->SetIdentity(); - mitk::Vector3D spacing = input->GetGeometry()->GetSpacing(); - mitk::Point3D origin = input->GetGeometry()->GetOrigin(); - input->GetGeometry()->SetIndexToWorldTransform(affTrans); - input->GetGeometry()->SetSpacing(spacing); - input->GetGeometry()->SetOrigin(origin); - } - } - - bool vti = (m_Extension.find(".vti") != std::string::npos); - - // If the extension is NOT .pic and NOT .nrrd and NOT .nii and NOT .nii.gz the following block is entered - if ( m_Extension.find(".pic") == std::string::npos - && m_Extension.find(".nrrd") == std::string::npos - && m_Extension.find(".nii") == std::string::npos - && m_Extension.find(".nii.gz") == std::string::npos - ) - { - if(input->GetDimension() > 3) - { - int t, timesteps; - - timesteps = input->GetDimension(3); - ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New(); - timeSelector->SetInput(input); - mitk::Image::Pointer image = timeSelector->GetOutput(); - for(t = 0; t < timesteps; ++t) - { - std::ostringstream filename; - timeSelector->SetTimeNr(t); - timeSelector->Update(); - if(input->GetTimeGeometry()->IsValidTimeStep(t)) - { - const mitk::TimeBounds& timebounds = input->GetTimeGeometry()->GetTimeBounds(t); - filename << m_FileNameWithoutExtension << "_S" << std::setprecision(0) << timebounds[0] << "_E" << std::setprecision(0) << timebounds[1] << "_T" << t << m_Extension; - } - else - { - itkWarningMacro(<<"Error on write: TimeGeometry invalid of image " << filename.str() << "."); - filename << m_FileNameWithoutExtension << "_T" << t << m_Extension; - } - if ( vti ) - { - writeVti(filename.str().c_str(), input, t); - } - else - { - WriteByITK(image, filename.str()); - } - } - } - else if ( vti ) - { - writeVti(m_FileName.c_str(), input); - } - else - { - WriteByITK(input, m_FileName); - } - } - else - { - // use the PicFileWriter for the .pic data type - if( m_Extension.find(".pic") != std::string::npos ) - { - /* PicFileWriter::Pointer picWriter = PicFileWriter::New(); - size_t found; - found = m_FileName.find( m_Extension ); // !!! HAS to be at the very end of the filename (not somewhere in the middle) - if( m_FileName.length() > 3 && found != m_FileName.length() - 4 ) - { - //if Extension not in Filename - std::ostringstream filename; - filename << m_FileName.c_str() << m_Extension; - picWriter->SetFileName( filename.str().c_str() ); - } - else - { - picWriter->SetFileName( m_FileName.c_str() ); - } - picWriter->SetInputImage( input ); - picWriter->Write(); - */ } - - // use the ITK .nrrd Image writer - if( m_Extension.find(".nrrd") != std::string::npos - || m_Extension.find(".nii") != std::string::npos - || m_Extension.find(".nii.gz") != std::string::npos - ) - { - WriteByITK(input, this->m_FileName); - } - } - m_MimeType = "application/MITK.Pic"; - - try - { - setlocale(LC_ALL, currLocale.c_str()); - } - catch(...) - { - MITK_INFO << "Could not reset locale " << currLocale; - } -} - -bool mitk::ImageWriter::CanWriteDataType( DataNode* input ) -{ - if ( input ) - { - return this->CanWriteBaseDataType(input->GetData()); - } - return false; -} - -void mitk::ImageWriter::SetInput( DataNode* input ) -{ - if( input && CanWriteDataType( input ) ) - this->ProcessObject::SetNthInput( 0, dynamic_cast( input->GetData() ) ); -} - -std::string mitk::ImageWriter::GetWritenMIMEType() -{ - return m_MimeType; -} - -std::vector mitk::ImageWriter::GetPossibleFileExtensions() -{ - std::vector possibleFileExtensions; - possibleFileExtensions.push_back(".pic"); - possibleFileExtensions.push_back(".pic.gz"); - possibleFileExtensions.push_back(".bmp"); - possibleFileExtensions.push_back(".dcm"); - possibleFileExtensions.push_back(".DCM"); - possibleFileExtensions.push_back(".dicom"); - possibleFileExtensions.push_back(".DICOM"); - possibleFileExtensions.push_back(".gipl"); - possibleFileExtensions.push_back(".gipl.gz"); - possibleFileExtensions.push_back(".mha"); - possibleFileExtensions.push_back(".nii"); - possibleFileExtensions.push_back(".nii.gz"); - possibleFileExtensions.push_back(".nrrd"); - possibleFileExtensions.push_back(".nhdr"); - possibleFileExtensions.push_back(".png"); - possibleFileExtensions.push_back(".PNG"); - possibleFileExtensions.push_back(".spr"); - possibleFileExtensions.push_back(".mhd"); - possibleFileExtensions.push_back(".vtk"); - possibleFileExtensions.push_back(".vti"); - possibleFileExtensions.push_back(".hdr"); - possibleFileExtensions.push_back(".img"); - possibleFileExtensions.push_back(".img.gz"); - possibleFileExtensions.push_back(".png"); - possibleFileExtensions.push_back(".tif"); - possibleFileExtensions.push_back(".jpg"); - return possibleFileExtensions; -} - -std::string mitk::ImageWriter::GetFileExtension() -{ - return m_Extension; -} - -void mitk::ImageWriter::SetInput( mitk::Image* image ) -{ - this->ProcessObject::SetNthInput( 0, image ); -} - -const mitk::Image* mitk::ImageWriter::GetInput() -{ - if ( this->GetNumberOfInputs() < 1 ) - { - return NULL; - } - else - { - return static_cast< const mitk::Image * >( this->ProcessObject::GetInput( 0 ) ); - } -} - -const char* mitk::ImageWriter::GetDefaultFilename() -{ - return "Image.nrrd"; -} - -const char* mitk::ImageWriter::GetFileDialogPattern() -{ - return - "Nearly Raw Raster Data (*.nrrd);;" - "NIfTI format (*.nii *.nii.gz);;" - "VTK Image Data Files (*.vti);;" - "NRRD with detached header (*.nhdr);;" - "Analyze Format (*.hdr);;" - "MetaImage (*.mhd);;" - "Sets of 2D slices (*.png *.tiff *.jpg *.jpeg *.bmp);;" - "DICOM (*.dcm *.DCM *.dicom *.DICOM);;" - "UMDS GIPL Format Files (*.gipl *.gipl.gz)"; -} - -const char *mitk::ImageWriter::GetDefaultExtension() -{ - return ".nrrd"; -} - -bool mitk::ImageWriter::CanWriteBaseDataType(BaseData::Pointer data) -{ - return dynamic_cast( data.GetPointer() ); -} - -void mitk::ImageWriter::DoWrite(BaseData::Pointer data) -{ - if (this->CanWriteBaseDataType(data)) - { - this->SetInput(dynamic_cast(data.GetPointer())); - this->Update(); - } -} \ No newline at end of file diff --git a/Core/Code/IO/mitkCoreDataNodeReader.h b/Core/Code/IO/mitkSimpleMimeType.cpp similarity index 63% copy from Core/Code/IO/mitkCoreDataNodeReader.h copy to Core/Code/IO/mitkSimpleMimeType.cpp index a396f45d8e..dcc76ca9b9 100644 --- a/Core/Code/IO/mitkCoreDataNodeReader.h +++ b/Core/Code/IO/mitkSimpleMimeType.cpp @@ -1,34 +1,22 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ +#include "mitkSimpleMimeType.h" -#ifndef MITKCOREDATANODEREADER_H -#define MITKCOREDATANODEREADER_H - -#include - -namespace mitk { - -class CoreDataNodeReader : public mitk::IDataNodeReader +std::string mitk::SimpleMimeType::GetMagicPatterns() const { -public: - - int Read(const std::string& fileName, mitk::DataStorage& storage); -}; - + return std::string(); } - -#endif // MITKCOREDATANODEREADER_H diff --git a/Core/Code/IO/mitkCoreDataNodeReader.h b/Core/Code/IO/mitkSimpleMimeType.h similarity index 67% copy from Core/Code/IO/mitkCoreDataNodeReader.h copy to Core/Code/IO/mitkSimpleMimeType.h index a396f45d8e..9b45a34f19 100644 --- a/Core/Code/IO/mitkCoreDataNodeReader.h +++ b/Core/Code/IO/mitkSimpleMimeType.h @@ -1,34 +1,35 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ +#ifndef MITKSIMPLEMIMETYPE_H +#define MITKSIMPLEMIMETYPE_H -#ifndef MITKCOREDATANODEREADER_H -#define MITKCOREDATANODEREADER_H - -#include +#include "mitkIMimeType.h" namespace mitk { -class CoreDataNodeReader : public mitk::IDataNodeReader +class MITK_CORE_EXPORT SimpleMimeType : public IMimeType { + public: - int Read(const std::string& fileName, mitk::DataStorage& storage); + virtual std::string GetMagicPatterns() const; + }; } -#endif // MITKCOREDATANODEREADER_H +#endif // MITKSIMPLEMIMETYPE_H diff --git a/Core/Code/Interfaces/mitkIDataNodeReader.h b/Core/Code/Interfaces/mitkIDataNodeReader.h index f9b198674c..183c6210e7 100644 --- a/Core/Code/Interfaces/mitkIDataNodeReader.h +++ b/Core/Code/Interfaces/mitkIDataNodeReader.h @@ -1,58 +1,60 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKIDATANODEREADER_H #define MITKIDATANODEREADER_H #include #include namespace mitk { class DataStorage; /** * \ingroup MicroServices_Interfaces * * This interface provides methods to load data from the local filesystem * into a given mitk::DataStorage. + * + * \deprecatedSince{2014_03} Use mitk::IFileReader instead */ struct IDataNodeReader { virtual ~IDataNodeReader() {} /** * Reads the local file given by fileName and constructs one or more * mitk::DataNode instances which are added to the given mitk::DataStorage storage. * * \param fileName The absolute path to a local file. * \param storage The mitk::DataStorage which will contain the constructed data nodes. * \return The number of constructed mitk::DataNode instances. * * \note Errors during reading the file or constructing the data node should be expressed by * throwing appropriate exceptions. * * \see mitk::DataNodeFactory */ virtual int Read(const std::string& fileName, mitk::DataStorage& storage) = 0; }; } US_DECLARE_SERVICE_INTERFACE(mitk::IDataNodeReader, "org.mitk.IDataNodeReader") #endif // MITKIDATANODEREADER_H diff --git a/Core/Code/IO/mitkCoreDataNodeReader.h b/Core/Code/Interfaces/mitkIFileReader.cpp similarity index 62% copy from Core/Code/IO/mitkCoreDataNodeReader.h copy to Core/Code/Interfaces/mitkIFileReader.cpp index a396f45d8e..139f2b2ace 100644 --- a/Core/Code/IO/mitkCoreDataNodeReader.h +++ b/Core/Code/Interfaces/mitkIFileReader.cpp @@ -1,34 +1,34 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#ifndef MITKCOREDATANODEREADER_H -#define MITKCOREDATANODEREADER_H +#include "mitkIFileReader.h" -#include - -namespace mitk { - -class CoreDataNodeReader : public mitk::IDataNodeReader +mitk::IFileReader::~IFileReader() { -public: - - int Read(const std::string& fileName, mitk::DataStorage& storage); -}; +} +std::string mitk::IFileReader::PROP_DESCRIPTION() +{ + static std::string s = "org.mitk.IFileReader.description"; + return s; } -#endif // MITKCOREDATANODEREADER_H +std::string mitk::IFileReader::PROP_MIMETYPE() +{ + static std::string s = "org.mitk.IFileReader.mimetype"; + return s; +} diff --git a/Core/Code/Interfaces/mitkIFileReader.h b/Core/Code/Interfaces/mitkIFileReader.h new file mode 100644 index 0000000000..e1107fb746 --- /dev/null +++ b/Core/Code/Interfaces/mitkIFileReader.h @@ -0,0 +1,156 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef IFileReader_H_HEADER_INCLUDED_C1E7E521 +#define IFileReader_H_HEADER_INCLUDED_C1E7E521 + +// Macro +#include + +// Microservices +#include + +// MITK +#include + + +namespace mitk { + class BaseData; + class DataStorage; +} + +namespace itk { + template class SmartPointer; +} + +namespace mitk { + /** + * \brief The common interface for all MITK file readers. + * + * Implementations of this interface must be registered as a service + * to make themselve available via the service registry. If the + * implementation is state-full, the service should be registered using + * a PrototypeServiceFactory. + * + * The file reader implementation is associated with a mime-type, specified + * in the service property PROP_MIMETYPE(). The specified mime-type should + * have a corresponding IMimeType service object, registered by the reader + * or some other party. + * + * It is recommended to derive new implementations from AbstractFileReader, + * which provides correct service registration semantics. + * + * \sa AbstractFileReader + * \sa IMimeType + * \sa FileReaderRegistry + */ + struct MITK_CORE_EXPORT IFileReader + { + virtual ~IFileReader(); + + typedef std::pair Option; + typedef std::vector OptionNames; + typedef std::vector