diff --git a/Core/Code/IO/mitkAbstractFileIO.cpp b/Core/Code/IO/mitkAbstractFileIO.cpp index af6a7bf5db..dac8f06a6f 100644 --- a/Core/Code/IO/mitkAbstractFileIO.cpp +++ b/Core/Code/IO/mitkAbstractFileIO.cpp @@ -1,178 +1,154 @@ /*=================================================================== 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 "mitkAbstractFileIO.h" #include "mitkCustomMimeType.h" namespace mitk { AbstractFileIO::ReaderOptions AbstractFileIO::GetReaderOptions() const { return AbstractFileReader::GetOptions(); } us::Any AbstractFileIO::GetReaderOption(const std::string& name) const { return AbstractFileReader::GetOption(name); } void AbstractFileIO::SetReaderOptions(const AbstractFileIO::ReaderOptions& options) { AbstractFileReader::SetOptions(options); } void AbstractFileIO::SetReaderOption(const std::string& name, const us::Any& value) { AbstractFileReader::SetOption(name, value); } std::pair, us::ServiceRegistration > AbstractFileIO::RegisterService(us::ModuleContext* context) { std::pair, us::ServiceRegistration > result; result.first = this->AbstractFileReader::RegisterService(context); result.second = this->AbstractFileWriter::RegisterService(context); return result; } AbstractFileIO::AbstractFileIO(const AbstractFileIO& other) - : AbstractFileReader(other) - , AbstractFileWriter(other) + : AbstractFileIOReader(other) + , AbstractFileIOWriter(other) { } AbstractFileIO::AbstractFileIO(const std::string& baseDataType) - : AbstractFileReader() - , AbstractFileWriter(baseDataType) + : AbstractFileIOReader() + , AbstractFileIOWriter(baseDataType) { } AbstractFileIO::AbstractFileIO(const std::string& baseDataType, const CustomMimeType& mimeType, const std::string& description) - : AbstractFileReader(mimeType, description) - , AbstractFileWriter(baseDataType, mimeType, description) + : AbstractFileIOReader(mimeType, description) + , AbstractFileIOWriter(baseDataType, mimeType, description) { } AbstractFileIO::AbstractFileIO(const std::string& baseDataType, const std::string& extension, const std::string& description) - : AbstractFileReader(extension, description) - , AbstractFileWriter(baseDataType, extension, description) + : AbstractFileIOReader(extension, description) + , AbstractFileIOWriter(baseDataType, extension, description) { } -AbstractFileIO::ReaderConfidenceLevel AbstractFileIO::GetReaderConfidenceLevel(const std::string& /*path*/) const -{ - return IFileReader::Supported; -} - -AbstractFileIO::WriterConfidenceLevel AbstractFileIO::GetWriterConfidenceLevel(const BaseData* /*data*/) const -{ - return IFileWriter::Supported; -} - void AbstractFileIO::SetMimeType(const CustomMimeType& mimeType) { this->AbstractFileReader::SetMimeType(mimeType); this->AbstractFileWriter::SetMimeType(mimeType); } CustomMimeType AbstractFileIO::GetMimeType() const { CustomMimeType mimeType = this->AbstractFileReader::GetMimeType(); if (mimeType.GetName() != this->AbstractFileWriter::GetMimeType().GetName()) { MITK_WARN << "Reader and writer mime-tpyes are different, using the mime-type from IFileReader"; } return mimeType; } void AbstractFileIO::SetReaderDescription(const std::string& description) { this->AbstractFileReader::SetDescription(description); } std::string AbstractFileIO::GetReaderDescription() const { return this->AbstractFileReader::GetDescription(); } void AbstractFileIO::SetWriterDescription(const std::string& description) { this->AbstractFileWriter::SetDescription(description); } std::string AbstractFileIO::GetWriterDescription() const { return this->AbstractFileWriter::GetDescription(); } void AbstractFileIO::SetDefaultReaderOptions(const AbstractFileIO::ReaderOptions& defaultOptions) { this->AbstractFileReader::SetDefaultOptions(defaultOptions); } AbstractFileIO::ReaderOptions AbstractFileIO::GetDefaultReaderOptions() const { return this->AbstractFileReader::GetDefaultOptions(); } void AbstractFileIO::SetDefaultWriterOptions(const AbstractFileIO::WriterOptions& defaultOptions) { this->AbstractFileWriter::SetDefaultOptions(defaultOptions); } AbstractFileIO::WriterOptions AbstractFileIO::GetDefaultWriterOptions() const { return this->AbstractFileWriter::GetDefaultOptions(); } void AbstractFileIO::SetReaderRanking(int ranking) { this->AbstractFileReader::SetRanking(ranking); } int AbstractFileIO::GetReaderRanking() const { return this->AbstractFileReader::GetRanking(); } void AbstractFileIO::SetWriterRanking(int ranking) { this->AbstractFileWriter::SetRanking(ranking); } int AbstractFileIO::GetWriterRanking() const { return this->AbstractFileWriter::GetRanking(); } -AbstractFileIO::ReaderConfidenceLevel AbstractFileIO::GetConfidenceLevel(const std::string& path) const -{ - ReaderConfidenceLevel level = AbstractFileReader::GetConfidenceLevel(path); - if (level == IFileReader::Unsupported) return level; - return this->GetReaderConfidenceLevel(path); -} - -AbstractFileIO::WriterConfidenceLevel AbstractFileIO::GetConfidenceLevel(const BaseData* data) const -{ - WriterConfidenceLevel level = AbstractFileWriter::GetConfidenceLevel(data); - if (level == IFileWriter::Unsupported) return level; - return this->GetWriterConfidenceLevel(data); -} - } diff --git a/Core/Code/IO/mitkAbstractFileIO.h b/Core/Code/IO/mitkAbstractFileIO.h index 35434f1781..6124ca68ee 100644 --- a/Core/Code/IO/mitkAbstractFileIO.h +++ b/Core/Code/IO/mitkAbstractFileIO.h @@ -1,130 +1,174 @@ /*=================================================================== 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 MITKABSTRACTFILEIO_H #define MITKABSTRACTFILEIO_H #include "mitkAbstractFileReader.h" #include "mitkAbstractFileWriter.h" namespace mitk { -class MITK_CORE_EXPORT AbstractFileIO : public AbstractFileReader, public AbstractFileWriter +class AbstractFileIOReader : public AbstractFileReader +{ +public: + + virtual ConfidenceLevel GetReaderConfidenceLevel() const + { + return AbstractFileReader::GetConfidenceLevel(); + } + + virtual ConfidenceLevel GetConfidenceLevel() const + { + return this->GetReaderConfidenceLevel(); + } + +protected: + + AbstractFileIOReader() {} + + AbstractFileIOReader(const CustomMimeType& mimeType, const std::string& description) + : AbstractFileReader(mimeType, description) {} + + AbstractFileIOReader(const std::string& extension, const std::string& description) + : AbstractFileReader(extension, description) {} +}; + +struct AbstractFileIOWriter : public AbstractFileWriter +{ + virtual ConfidenceLevel GetWriterConfidenceLevel() const + { + return AbstractFileWriter::GetConfidenceLevel(); + } + + virtual ConfidenceLevel GetConfidenceLevel() const + { + return this->GetWriterConfidenceLevel(); + } + +protected: + + AbstractFileIOWriter(const std::string& baseDataType) : AbstractFileWriter(baseDataType) {} + + AbstractFileIOWriter(const std::string& baseDataType, const CustomMimeType& mimeType, + const std::string& description) + : AbstractFileWriter(baseDataType, mimeType, description) {} + + AbstractFileIOWriter(const std::string& baseDataType, const std::string& extension, + const std::string& description) + : AbstractFileWriter(baseDataType, extension, description) {} +}; + +class MITK_CORE_EXPORT AbstractFileIO : public AbstractFileIOReader, public AbstractFileIOWriter { public: typedef IFileReader::Options ReaderOptions; typedef IFileWriter::Options WriterOptions; typedef IFileReader::ConfidenceLevel ReaderConfidenceLevel; typedef IFileWriter::ConfidenceLevel WriterConfidenceLevel; ReaderOptions GetReaderOptions() const; us::Any GetReaderOption(const std::string &name) const; void SetReaderOptions(const ReaderOptions& options); void SetReaderOption(const std::string& name, const us::Any& value); std::pair, us::ServiceRegistration > RegisterService(us::ModuleContext* context = us::GetModuleContext()); protected: AbstractFileIO(const AbstractFileIO& other); AbstractFileIO(const std::string& baseDataType); /** * 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 AbstractFileIO(const std::string& baseDataType, const CustomMimeType& 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 on the CustomMimeType object returned by GetMimeType() and * setting the modified object again via SetMimeType(). * * @param extension The file extension (without a leading period) for which a registered * mime-type object is looked up and associated with this instance. * @param description A human readable description of this reader. * * @see RegisterService */ explicit AbstractFileIO(const std::string& baseDataType, const std::string& extension, const std::string& description); - virtual ReaderConfidenceLevel GetReaderConfidenceLevel(const std::string& path) const; - virtual WriterConfidenceLevel GetWriterConfidenceLevel(const BaseData* data) const; - void SetMimeType(const CustomMimeType& mimeType); /** * @return The mime-type this reader can handle. */ CustomMimeType GetMimeType() const; void SetReaderDescription(const std::string& description); std::string GetReaderDescription() const; void SetWriterDescription(const std::string& description); std::string GetWriterDescription() const; void SetDefaultReaderOptions(const ReaderOptions& defaultOptions); ReaderOptions GetDefaultReaderOptions() const; void SetDefaultWriterOptions(const WriterOptions& defaultOptions); WriterOptions GetDefaultWriterOptions() const; /** * \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 SetReaderRanking(int ranking); int GetReaderRanking() const; void SetWriterRanking(int ranking); int GetWriterRanking() const; private: AbstractFileIO& operator=(const AbstractFileIO& other); virtual AbstractFileIO* Clone() const = 0; - virtual ReaderConfidenceLevel GetConfidenceLevel(const std::string& path) const; - virtual WriterConfidenceLevel GetConfidenceLevel(const BaseData *data) const; - }; } #endif // MITKABSTRACTFILEIO_H diff --git a/Core/Code/IO/mitkAbstractFileReader.cpp b/Core/Code/IO/mitkAbstractFileReader.cpp index 53d5b92684..6a9cadc19f 100644 --- a/Core/Code/IO/mitkAbstractFileReader.cpp +++ b/Core/Code/IO/mitkAbstractFileReader.cpp @@ -1,346 +1,391 @@ /*=================================================================== 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 namespace mitk { +AbstractFileReader::InputStream::InputStream(IFileReader* reader, std::ios_base::openmode mode) + : std::istream() + , m_Stream(NULL) +{ + std::istream* stream = reader->GetInputStream(); + if (stream) + { + this->init(stream->rdbuf()); + } + else + { + m_Stream = new std::ifstream(reader->GetInputLocation().c_str(), mode); + this->init(m_Stream->rdbuf()); + } +} + +AbstractFileReader::InputStream::~InputStream() +{ + delete m_Stream; +} + class AbstractFileReader::Impl : public FileReaderWriterBase { public: Impl() : FileReaderWriterBase() + , m_Stream(NULL) , m_PrototypeFactory(NULL) {} Impl(const Impl& other) : FileReaderWriterBase(other) + , m_Stream(NULL) , m_PrototypeFactory(NULL) {} + std::string m_Location; + std::string m_TmpFile; + std::istream* m_Stream; + us::PrototypeServiceFactory* m_PrototypeFactory; us::ServiceRegistration m_Reg; }; AbstractFileReader::AbstractFileReader() : d(new Impl) { } AbstractFileReader::~AbstractFileReader() { UnregisterService(); delete d->m_PrototypeFactory; + + if (!d->m_TmpFile.empty()) + { + std::remove(d->m_TmpFile.c_str()); + } } AbstractFileReader::AbstractFileReader(const AbstractFileReader& other) : d(new Impl(*other.d.get())) { } AbstractFileReader::AbstractFileReader(const CustomMimeType& mimeType, const std::string& description) : d(new Impl) { d->SetMimeType(mimeType); d->SetDescription(description); } AbstractFileReader::AbstractFileReader(const std::string& extension, const std::string& description) : d(new Impl) { CustomMimeType customMimeType; customMimeType.AddExtension(extension); d->SetMimeType(customMimeType); d->SetDescription(description); } ////////////////////// 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(), std::ios_base::in | std::ios_base::binary); - try - { - return this->Read(stream); - } - catch (mitk::Exception& e) - { - mitkReThrow(e) << "Error reading file '" << path << "'"; - } - catch (const std::exception& e) - { - mitkThrow() << "Error reading file '" << path << "': " << e.what(); - } -} - -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; -} - -DataStorage::SetOfObjects::Pointer AbstractFileReader::Read(const std::string& path, DataStorage& ds) +DataStorage::SetOfObjects::Pointer AbstractFileReader::Read(DataStorage& ds) { DataStorage::SetOfObjects::Pointer result = DataStorage::SetOfObjects::New(); - std::vector data = this->Read(path); + std::vector data = this->Read(); for (std::vector::iterator iter = data.begin(); iter != data.end(); ++iter) { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(*iter); - this->SetDefaultDataNodeProperties(node, path); + this->SetDefaultDataNodeProperties(node, this->GetInputLocation()); ds.Add(node); result->InsertElement(result->Size(), node); } return result; } -DataStorage::SetOfObjects::Pointer AbstractFileReader::Read(std::istream& stream, DataStorage& ds) +IFileReader::ConfidenceLevel AbstractFileReader::GetConfidenceLevel() const { - DataStorage::SetOfObjects::Pointer result = DataStorage::SetOfObjects::New(); - std::vector data = this->Read(stream); - for (std::vector::iterator iter = data.begin(); - iter != data.end(); ++iter) + if (d->m_Stream) { - mitk::DataNode::Pointer node = mitk::DataNode::New(); - node->SetData(*iter); - this->SetDefaultDataNodeProperties(node, std::string()); - ds.Add(node); - result->InsertElement(result->Size(), node); + if (*d->m_Stream) return Supported; } - return result; -} - -IFileReader::ConfidenceLevel AbstractFileReader::GetConfidenceLevel(const std::string& path) const -{ - return itksys::SystemTools::FileExists(path.c_str(), true) ? Supported : Unsupported; + else + { + if (itksys::SystemTools::FileExists(this->GetInputLocation().c_str(), true)) + { + return Supported; + } + } + return Unsupported; } //////////// µS Registration & Properties ////////////// us::ServiceRegistration AbstractFileReader::RegisterService(us::ModuleContext* context) { if (d->m_PrototypeFactory) return us::ServiceRegistration(); if(context == NULL) { context = us::GetModuleContext(); } d->RegisterMimeType(context); if (this->GetMimeType().GetName().empty()) { MITK_WARN << "Not registering reader 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(); d->m_Reg = context->RegisterService(d->m_PrototypeFactory, props); return d->m_Reg; } void AbstractFileReader::UnregisterService() { try { d->m_Reg.Unregister(); } catch (const std::exception&) {} } us::ServiceProperties AbstractFileReader::GetServiceProperties() const { us::ServiceProperties result; result[IFileReader::PROP_DESCRIPTION()] = this->GetDescription(); result[IFileReader::PROP_MIMETYPE()] = this->GetMimeType().GetName(); result[us::ServiceConstants::SERVICE_RANKING()] = this->GetRanking(); return result; } us::ServiceRegistration AbstractFileReader::RegisterMimeType(us::ModuleContext* context) { return d->RegisterMimeType(context); } void AbstractFileReader::SetMimeType(const CustomMimeType& mimeType) { d->SetMimeType(mimeType); } void AbstractFileReader::SetDescription(const std::string& description) { d->SetDescription(description); } void AbstractFileReader::SetRanking(int ranking) { d->SetRanking(ranking); } int AbstractFileReader::GetRanking() const { return d->GetRanking(); } +std::string AbstractFileReader::GetLocalFileName() const +{ + std::string localFileName; + if (d->m_Stream) + { + if (d->m_TmpFile.empty()) + { + // write the stream contents to temporary file + std::string ext = itksys::SystemTools::GetFilenameExtension(this->GetInputLocation()); + std::ofstream tmpStream; + localFileName = mitk::IOUtil::CreateTemporaryFile(tmpStream, std::ios_base::out | std::ios_base::trunc | std::ios_base::binary, + "XXXXXX" + ext); + tmpStream << d->m_Stream->rdbuf(); + d->m_TmpFile = localFileName; + } + else + { + localFileName = d->m_TmpFile; + } + } + else + { + localFileName = d->m_Location; + } + return localFileName; +} + //////////////////////// Options /////////////////////// void AbstractFileReader::SetDefaultOptions(const IFileReader::Options& defaultOptions) { d->SetDefaultOptions(defaultOptions); } IFileReader::Options AbstractFileReader::GetDefaultOptions() const { return d->GetDefaultOptions(); } +void AbstractFileReader::SetInput(const std::string& location) +{ + d->m_Location = location; + d->m_Stream = NULL; +} + +void AbstractFileReader::SetInput(const std::string& location, std::istream* is) +{ + if (d->m_Stream != is && !d->m_TmpFile.empty()) + { + std::remove(d->m_TmpFile.c_str()); + d->m_TmpFile.clear(); + } + d->m_Location = location; + d->m_Stream = is; +} + +std::string AbstractFileReader::GetInputLocation() const +{ + return d->m_Location; +} + +std::istream*AbstractFileReader::GetInputStream() const +{ + return d->m_Stream; +} + IFileReader::Options AbstractFileReader::GetOptions() const { return d->GetOptions(); } us::Any AbstractFileReader::GetOption(const std::string& name) const { return d->GetOption(name); } void AbstractFileReader::SetOptions(const Options& options) { d->SetOptions(options); } void AbstractFileReader::SetOption(const std::string& name, const us::Any& value) { d->SetOption(name, value); } ////////////////// MISC ////////////////// void AbstractFileReader::AddProgressCallback(const ProgressCallback& callback) { d->AddProgressCallback(callback); } void AbstractFileReader::RemoveProgressCallback(const ProgressCallback& callback) { d->RemoveProgressCallback(callback); } ////////////////// µS related Getters ////////////////// CustomMimeType AbstractFileReader::GetMimeType() const { return d->GetMimeType(); } std::string AbstractFileReader::GetDescription() const { return d->GetDescription(); } void AbstractFileReader::SetDefaultDataNodeProperties(DataNode* node, const std::string& filePath) { // path if (!filePath.empty()) { mitk::StringProperty::Pointer pathProp = mitk::StringProperty::New( itksys::SystemTools::GetFilenamePath(filePath) ); node->SetProperty(StringProperty::PATH, pathProp); } // name already defined? mitk::StringProperty::Pointer nameProp = dynamic_cast(node->GetProperty("name")); if(nameProp.IsNull() || (strcmp(nameProp->GetValue(),"No Name!")==0)) { // 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)) { // name neither defined in node, nor in BaseData -> name = filebasename; nameProp = mitk::StringProperty::New(itksys::SystemTools::GetFilenameWithoutExtension(itksys::SystemTools::GetFilenameName(filePath))); node->SetProperty("name", nameProp); } else { // name defined in BaseData! nameProp = mitk::StringProperty::New(baseDataNameProp->GetValue()); node->SetProperty("name", nameProp); } } // visibility if(!node->GetProperty("visible")) { node->SetVisibility(true); } } } diff --git a/Core/Code/IO/mitkAbstractFileReader.h b/Core/Code/IO/mitkAbstractFileReader.h index 5c1b17dc4d..b55560cfda 100644 --- a/Core/Code/IO/mitkAbstractFileReader.h +++ b/Core/Code/IO/mitkAbstractFileReader.h @@ -1,185 +1,233 @@ /*=================================================================== 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 // Microservices #include #include #include namespace us { struct PrototypeServiceFactory; } namespace mitk { class CustomMimeType; /** * @brief Base class for creating mitk::BaseData objects from files or streams. - * @ingroup Process + * @ingroup IO */ class MITK_CORE_EXPORT AbstractFileReader : public mitk::IFileReader { public: + virtual void SetInput(const std::string& location); + + virtual void SetInput(const std::string &location, std::istream* is); + + virtual std::string GetInputLocation() const; + + virtual std::istream* GetInputStream() const; + /** - * @brief Reads the given \c path and creates a list BaseData objects. + * @brief Reads a path or stream and creates a list of BaseData objects. * - * The default implementation opens a std::ifstream in binary mode for reading - * and passed the stream to Read(std::istream&). + * This method must be implemented for each specific reader. Call + * GetInputStream() first and check for a non-null stream to read from. + * If the input stream is \c NULL, use GetInputLocation() to read from a local + * file-system path. * - * @param path The absolute path to a file include the file name extension. - * @return + * If the reader cannot use streams directly, use GetLocalFileName() instead. + * + * @return The created BaseData objects. + * @throws mitk::Exception + * + * @see GetLocalFileName() + * @see IFileReader::Read() */ - virtual std::vector > Read(const std::string& path); - - virtual std::vector > Read(std::istream& stream) = 0; + virtual std::vector > Read() = 0; - virtual DataStorage::SetOfObjects::Pointer Read(const std::string& path, mitk::DataStorage& ds); + virtual DataStorage::SetOfObjects::Pointer Read(mitk::DataStorage& ds); - virtual DataStorage::SetOfObjects::Pointer Read(std::istream& stream, mitk::DataStorage& ds); - - virtual ConfidenceLevel GetConfidenceLevel(const std::string &path) const; + virtual ConfidenceLevel GetConfidenceLevel() const; virtual Options GetOptions() const; virtual us::Any GetOption(const std::string &name) const; virtual void SetOptions(const Options& options); virtual void SetOption(const std::string& name, const us::Any& value); 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 * mime-type 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()); void UnregisterService(); protected: + /** + * @brief An input stream wrapper. + * + * If a reader can only work with input streams, use an instance + * of this class to either wrap the specified input stream or + * create a new input stream based on the input location in the + * file system. + */ + class InputStream : public std::istream + { + public: + InputStream(IFileReader* writer, std::ios_base::openmode mode = std::ios_base::in); + ~InputStream(); + private: + std::istream* m_Stream; + }; + 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 CustomMimeType& 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 * mime-type 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; /** * Registers a new CustomMimeType service object. * * This method is called from RegisterService and the default implementation * registers a new mime-type service object if all of the following conditions * are true: * * - TODO * * @param context * @return * @throws std::invalid_argument if \c context is NULL. */ virtual us::ServiceRegistration RegisterMimeType(us::ModuleContext* context); void SetMimeType(const CustomMimeType& mimeType); /** * @return The mime-type this reader can handle. */ CustomMimeType GetMimeType() const; void SetDescription(const std::string& description); std::string GetDescription() const; void SetDefaultOptions(const Options& defaultOptions); Options GetDefaultOptions() const; /** * \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; + /** + * @brief Get a local file name for reading. + * + * This is a convenience method for readers which cannot work natively + * with input streams. If no input stream has been been set, + * this method just returns the result of GetLocation(). However, if + * SetLocation(std::string, std::istream*) has been called with a non-null + * input stream, this method writes the contents of the stream to a temporary + * file and returns the name of the temporary file. + * + * The temporary file is deleted when either SetLocation(std::string, std::istream*) + * is called again with a different input stream or the destructor of this + * class is called. + * + * This method does not validate file names set via SetInput(std::string). + * + * @return A file path in the local file-system for reading. + */ + std::string GetLocalFileName() const; + virtual void SetDefaultDataNodeProperties(DataNode* node, const std::string& filePath); 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 index b54a9d5e9c..2d36eb6ed7 100644 --- a/Core/Code/IO/mitkAbstractFileWriter.cpp +++ b/Core/Code/IO/mitkAbstractFileWriter.cpp @@ -1,304 +1,374 @@ /*=================================================================== 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 { +struct AbstractFileWriter::LocalFile::Impl +{ + Impl(const std::string& location, std::ostream* os) + : m_Location(location) + , m_Stream(os) + {} + + std::string m_Location; + std::string m_TmpFileName; + std::ostream* m_Stream; +}; + +AbstractFileWriter::LocalFile::LocalFile(IFileWriter *writer) + : d(new Impl(writer->GetOutputLocation(), writer->GetOutputStream())) +{ +} + +AbstractFileWriter::LocalFile::~LocalFile() +{ + if (d->m_Stream && !d->m_TmpFileName.empty()) + { + std::ifstream ifs(d->m_TmpFileName.c_str(), std::ios_base::binary); + *d->m_Stream << ifs.rdbuf(); + d->m_Stream->flush(); + ifs.close(); + std::remove(d->m_TmpFileName.c_str()); + } +} + +std::string AbstractFileWriter::LocalFile::GetFileName() +{ + if (d->m_Stream == NULL) + { + return d->m_Location; + } + else if (d->m_TmpFileName.empty()) + { + std::string ext = itksys::SystemTools::GetFilenameExtension(d->m_Location); + d->m_TmpFileName = IOUtil::CreateTemporaryFile("XXXXXX" + ext); + } + return d->m_TmpFileName; +} + +AbstractFileWriter::OutputStream::OutputStream(IFileWriter* writer, std::ios_base::openmode mode) + : std::ostream() + , m_Stream(NULL) +{ + std::ostream* stream = writer->GetOutputStream(); + if (stream) + { + this->init(stream->rdbuf()); + } + else + { + m_Stream = new std::ofstream(writer->GetOutputLocation().c_str(), mode); + this->init(m_Stream->rdbuf()); + } +} + +AbstractFileWriter::OutputStream::~OutputStream() +{ + delete m_Stream; +} + + class AbstractFileWriter::Impl : public FileReaderWriterBase { public: Impl() : FileReaderWriterBase() + , m_BaseData(NULL) + , m_Stream(NULL) , m_PrototypeFactory(NULL) {} Impl(const Impl& other) : FileReaderWriterBase(other) , m_BaseDataType(other.m_BaseDataType) + , m_BaseData(NULL) + , m_Stream(NULL) , m_PrototypeFactory(NULL) {} std::string m_BaseDataType; + const BaseData* m_BaseData; + std::string m_Location; + std::ostream* m_Stream; us::PrototypeServiceFactory* m_PrototypeFactory; us::ServiceRegistration m_Reg; }; +void AbstractFileWriter::SetInput(const BaseData* data) +{ + d->m_BaseData = data; +} + +const BaseData* AbstractFileWriter::GetInput() const +{ + return d->m_BaseData; +} + +void AbstractFileWriter::SetOutputLocation(const std::string& location) +{ + d->m_Location = location; + d->m_Stream = NULL; +} + +std::string AbstractFileWriter::GetOutputLocation() const +{ + return d->m_Location; +} + +void AbstractFileWriter::SetOutputStream(const std::string& location, std::ostream* os) +{ + d->m_Location = location; + d->m_Stream = os; +} + +std::ostream* AbstractFileWriter::GetOutputStream() const +{ + return d->m_Stream; +} AbstractFileWriter::~AbstractFileWriter() { UnregisterService(); delete d->m_PrototypeFactory; } AbstractFileWriter::AbstractFileWriter(const AbstractFileWriter& other) : d(new Impl(*other.d.get())) { } AbstractFileWriter::AbstractFileWriter(const std::string& baseDataType) : d(new Impl) { d->m_BaseDataType = baseDataType; } AbstractFileWriter::AbstractFileWriter(const std::string& baseDataType, const CustomMimeType& mimeType, const std::string& description) : d(new Impl) { d->m_BaseDataType = baseDataType; d->SetMimeType(mimeType); d->SetDescription(description); } AbstractFileWriter::AbstractFileWriter(const std::string& baseDataType, const std::string& extension, const std::string& description) : d(new Impl) { d->m_BaseDataType = baseDataType; d->SetDescription(description); CustomMimeType customMimeType; customMimeType.AddExtension(extension); d->SetMimeType(customMimeType); } ////////////////////// Writing ///////////////////////// -void AbstractFileWriter::Write(const BaseData* data, const std::string& path) +IFileWriter::ConfidenceLevel AbstractFileWriter::GetConfidenceLevel() const { - std::ofstream stream; - stream.open(path.c_str()); - try - { - this->Write(data, stream); - } - catch(mitk::Exception& e) - { - mitkReThrow(e) << "Error writing file '" << path << "'"; - } - catch(const std::exception& e) - { - mitkThrow() << "Error writing file '" << path << "': " << e.what(); - } -} - -IFileWriter::ConfidenceLevel AbstractFileWriter::GetConfidenceLevel(const BaseData* data) const -{ - if (data == NULL) return Unsupported; + if (d->m_BaseData == NULL) return Unsupported; - if (data->GetNameOfClass() == d->m_BaseDataType) + if (d->m_BaseData->GetNameOfClass() == d->m_BaseDataType) { return Supported; } return Unsupported; } -void AbstractFileWriter::Write(const BaseData* data, std::ostream& stream) -{ - // Create a temporary file and write the data to it - std::ofstream tmpOutputStream; - std::string tmpFilePath = 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 AbstractFileWriter::RegisterService(us::ModuleContext* context) { if (d->m_PrototypeFactory) return us::ServiceRegistration(); if(context == NULL) { context = us::GetModuleContext(); } d->RegisterMimeType(context); if (this->GetMimeType().GetName().empty()) { MITK_WARN << "Not registering writer due to empty MIME type."; return us::ServiceRegistration(); } struct PrototypeFactory : public us::PrototypeServiceFactory { AbstractFileWriter* const m_Prototype; PrototypeFactory(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); } }; d->m_PrototypeFactory = new PrototypeFactory(this); us::ServiceProperties props = this->GetServiceProperties(); d->m_Reg = context->RegisterService(d->m_PrototypeFactory, props); return d->m_Reg; } void AbstractFileWriter::UnregisterService() { try { d->m_Reg.Unregister(); } catch (const std::exception&) {} } us::ServiceProperties AbstractFileWriter::GetServiceProperties() const { us::ServiceProperties result; result[IFileWriter::PROP_DESCRIPTION()] = this->GetDescription(); result[IFileWriter::PROP_MIMETYPE()] = this->GetMimeType().GetName(); result[IFileWriter::PROP_BASEDATA_TYPE()] = d->m_BaseDataType; result[us::ServiceConstants::SERVICE_RANKING()] = this->GetRanking(); // for (IFileWriter::OptionList::const_iterator it = d->m_Options.begin(); it != d->m_Options.end(); ++it) // { // result[it->first] = std::string("true"); // } return result; } CustomMimeType AbstractFileWriter::GetMimeType() const { return d->GetMimeType(); } us::ServiceRegistration AbstractFileWriter::RegisterMimeType(us::ModuleContext* context) { return d->RegisterMimeType(context); } void AbstractFileWriter::SetMimeType(const CustomMimeType& mimeType) { d->SetMimeType(mimeType); } void AbstractFileWriter::SetRanking(int ranking) { d->SetRanking(ranking); } //////////////////////// Options /////////////////////// void AbstractFileWriter::SetDefaultOptions(const IFileWriter::Options& defaultOptions) { d->SetDefaultOptions(defaultOptions); } IFileWriter::Options AbstractFileWriter::GetDefaultOptions() const { return d->GetDefaultOptions(); } IFileWriter::Options AbstractFileWriter::GetOptions() const { return d->GetOptions(); } us::Any AbstractFileWriter::GetOption(const std::string& name) const { return d->GetOption(name); } void AbstractFileWriter::SetOption(const std::string& name, const us::Any& value) { d->SetOption(name, value); } void AbstractFileWriter::SetOptions(const Options& options) { d->SetOptions(options); } ////////////////// MISC ////////////////// void AbstractFileWriter::AddProgressCallback(const ProgressCallback& callback) { d->AddProgressCallback(callback); } void AbstractFileWriter::RemoveProgressCallback(const ProgressCallback& callback) { d->RemoveProgressCallback(callback); } ////////////////// µS related Getters ////////////////// int AbstractFileWriter::GetRanking() const { return d->GetRanking(); } void AbstractFileWriter::SetBaseDataType(const std::string& baseDataType) { d->m_BaseDataType = baseDataType; } std::string AbstractFileWriter::GetDescription() const { return d->GetDescription(); } std::string AbstractFileWriter::GetBaseDataType() const { return d->m_BaseDataType; } void AbstractFileWriter::SetDescription(const std::string& description) { d->SetDescription(description); } } diff --git a/Core/Code/IO/mitkAbstractFileWriter.h b/Core/Code/IO/mitkAbstractFileWriter.h index ff54e219db..e9a08026d9 100644 --- a/Core/Code/IO/mitkAbstractFileWriter.h +++ b/Core/Code/IO/mitkAbstractFileWriter.h @@ -1,162 +1,226 @@ /*=================================================================== 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 #include namespace us { struct PrototypeServiceFactory; } namespace mitk { class CustomMimeType; /** * @brief Base class for writing mitk::BaseData objects to files or streams. * * In general, all file writers 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 one Write() * method and the Clone() method to be implemented. * - * @ingroup Process + * @ingroup IO */ 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); + virtual void SetInput(const BaseData* data); + virtual const BaseData* GetInput() const; + + virtual void SetOutputLocation(const std::string& location); + virtual std::string GetOutputLocation() const; + + virtual void SetOutputStream(const std::string& location, std::ostream* os); + virtual std::ostream* GetOutputStream() const; /** - * \brief Write the data in data to the the stream specified in stream + * \brief Write the base data to the specified location or output stream. + * + * This method must be implemented for each specific writer. Call + * GetOutputStream() first and check for a non-null stream to write to. + * If the output stream is \c NULL, use GetOutputLocation() to write + * to a local file-system path. + * + * If the reader cannot use streams directly, use GetLocalFile() to retrieve + * a temporary local file name instead. + * + * \throws mitk::Exception + * + * \see GetLocalFile() + * \see IFileWriter::Write() */ - virtual void Write(const BaseData* data, std::ostream& stream ) = 0; + virtual void Write() = 0; - virtual ConfidenceLevel GetConfidenceLevel(const BaseData *data) const; + virtual ConfidenceLevel GetConfidenceLevel() const; virtual Options GetOptions() const; virtual us::Any GetOption(const std::string &name) const; virtual void SetOptions(const Options& options); virtual void SetOption(const std::string& name, const us::Any& value); virtual void AddProgressCallback(const ProgressCallback& callback); virtual void RemoveProgressCallback(const ProgressCallback& callback); us::ServiceRegistration RegisterService(us::ModuleContext* context = us::GetModuleContext()); void UnregisterService(); protected: + /** + * @brief A local file representation for streams. + * + * If a writer can only work with local files, use an instance + * of this class to get either a temporary file name for writing + * to the specified output stream or the original output location + * if no output stream was set. + */ + class LocalFile + { + public: + LocalFile(IFileWriter* writer); + + // Writes to the ostream and removes the temporary file + ~LocalFile(); + + // Creates a temporary file for output operations. + std::string GetFileName(); + + private: + + // disabled + LocalFile(); + LocalFile(const LocalFile&); + LocalFile& operator=(const LocalFile& other); + + struct Impl; + std::auto_ptr d; + }; + + /** + * @brief An output stream wrapper. + * + * If a writer can only work with output streams, use an instance + * of this class to either wrap the specified output stream or + * create a new output stream based on the output location in the + * file system. + */ + class OutputStream : public std::ostream + { + public: + OutputStream(IFileWriter* writer, std::ios_base::openmode mode = std::ios_base::trunc | std::ios_base::out); + ~OutputStream(); + private: + std::ostream* m_Stream; + }; + ~AbstractFileWriter(); AbstractFileWriter(const AbstractFileWriter& other); AbstractFileWriter(const std::string& baseDataType); AbstractFileWriter(const std::string& baseDataType, const CustomMimeType& mimeType, const std::string& description); AbstractFileWriter(const std::string& baseDataType, const std::string& extension, const std::string& description); virtual us::ServiceProperties GetServiceProperties() const; /** * Registers a new CustomMimeType service object. * * This method is called from RegisterService and the default implementation * registers a new mime-type service object if all of the following conditions * are true: * * - TODO * * @param context * @return * @throws std::invalid_argument if \c context is NULL. */ virtual us::ServiceRegistration RegisterMimeType(us::ModuleContext* context); void SetMimeType(const CustomMimeType& mimeType); /** * @return Get the mime-type this writer can handle. */ CustomMimeType GetMimeType() const; /** * \brief Sets a human readable description of this writer. * * This will be used in file dialogs for example. */ void SetDescription(const std::string& description); std::string GetDescription() const; void SetDefaultOptions(const Options& defaultOptions); Options GetDefaultOptions() const; /** * \brief Set the service ranking for this file writer. * * Default is zero and should only be chosen differently for a reason. * The ranking is used to determine which writer to use if several * equivalent writers have been found. * It may be used to replace a default writer from MITK in your own project. * E.g. if you want to use your own writer for nrrd files instead of the default, * implement it and give it a higher ranking than zero. */ void SetRanking(int ranking); int GetRanking() const; /** * \brief Sets the name of the mitk::Basedata that this writer is able to handle. * * The correct value is the one given as the first parameter in the mitkNewMacro of that BaseData derivate. * You can also retrieve it by calling GetNameOfClass() on an instance of said data. */ void SetBaseDataType(const std::string& baseDataType); virtual std::string GetBaseDataType() const; private: AbstractFileWriter& operator=(const AbstractFileWriter& other); virtual mitk::IFileWriter* Clone() const = 0; class Impl; std::auto_ptr d; }; } // namespace mitk #endif /* AbstractFileWriter_H_HEADER_INCLUDED_C1E7E521 */ diff --git a/Core/Code/IO/mitkFileReaderSelector.cpp b/Core/Code/IO/mitkFileReaderSelector.cpp index 2f66010ea4..0c40998e14 100644 --- a/Core/Code/IO/mitkFileReaderSelector.cpp +++ b/Core/Code/IO/mitkFileReaderSelector.cpp @@ -1,265 +1,266 @@ /*=================================================================== 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 "mitkFileReaderSelector.h" #include #include #include #include #include #include namespace mitk { struct FileReaderSelector::Impl : us::SharedData { Impl() : m_BestId(-1) , m_SelectedId(m_BestId) {} Impl(const Impl& other) : us::SharedData(other) , m_BestId(-1) , m_SelectedId(m_BestId) {} FileReaderRegistry m_ReaderRegistry; std::map m_Items; std::vector m_MimeTypes; long m_BestId; long m_SelectedId; }; FileReaderSelector::FileReaderSelector(const FileReaderSelector& other) : m_Data(other.m_Data) { } FileReaderSelector::FileReaderSelector(const std::string& path) : m_Data(new Impl) { mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider()); // Get all mime types and associated readers for the given file path m_Data->m_MimeTypes = mimeTypeProvider->GetMimeTypesForFile(path); if (m_Data->m_MimeTypes.empty()) return; for (std::vector::const_iterator mimeTypeIter = m_Data->m_MimeTypes.begin(), mimeTypeIterEnd = m_Data->m_MimeTypes.end(); mimeTypeIter != mimeTypeIterEnd; ++mimeTypeIter) { std::vector refs = m_Data->m_ReaderRegistry.GetReferences(*mimeTypeIter); for (std::vector::const_iterator readerIter = refs.begin(), iterEnd = refs.end(); readerIter != iterEnd; ++readerIter) { IFileReader* reader = m_Data->m_ReaderRegistry.GetReader(*readerIter); if (reader == NULL) continue; try { + reader->SetInput(path); std::cout << "*** Checking confidence level of " << typeid(*reader).name() << " ... "; - IFileReader::ConfidenceLevel confidenceLevel = reader->GetConfidenceLevel(path); + IFileReader::ConfidenceLevel confidenceLevel = reader->GetConfidenceLevel(); std::cout << confidenceLevel << std::endl; if (confidenceLevel == IFileReader::Unsupported) { continue; } Item item; item.m_FileReaderRef = *readerIter; item.m_FileReader = reader; item.m_ConfidenceLevel = confidenceLevel; item.m_MimeType = *mimeTypeIter; item.m_Id = us::any_cast(readerIter->GetProperty(us::ServiceConstants::SERVICE_ID())); m_Data->m_Items.insert(std::make_pair(item.m_Id, item)); //m_Data->m_MimeTypes.insert(mimeType); } catch (const us::BadAnyCastException& e) { MITK_WARN << "Unexpected: " << e.what(); } catch (const std::exception& e) { // Log the error but continue MITK_WARN << "IFileWriter::GetConfidenceLevel exception: " << e.what(); } } } // get the "best" reader if (!m_Data->m_Items.empty()) { std::set sortedItems; for (std::map::const_iterator iter = m_Data->m_Items.begin(), iterEnd = m_Data->m_Items.end(); iter != iterEnd; ++iter) { sortedItems.insert(iter->second); } m_Data->m_BestId = sortedItems.rbegin()->GetServiceId(); m_Data->m_SelectedId = m_Data->m_BestId; } } FileReaderSelector::~FileReaderSelector() { } FileReaderSelector& FileReaderSelector::operator=(const FileReaderSelector& other) { m_Data = other.m_Data; return *this; } std::vector FileReaderSelector::GetMimeTypes() const { return m_Data->m_MimeTypes; } std::vector FileReaderSelector::Get() const { std::vector result; for (std::map::const_iterator iter = m_Data->m_Items.begin(), iterEnd = m_Data->m_Items.end(); iter != iterEnd; ++iter) { result.push_back(iter->second); } std::sort(result.begin(), result.end()); return result; } FileReaderSelector::Item FileReaderSelector::Get(long id) const { std::map::const_iterator iter = m_Data->m_Items.find(id); if (iter != m_Data->m_Items.end()) { return iter->second; } return Item(); } FileReaderSelector::Item FileReaderSelector::GetDefault() const { return Get(m_Data->m_BestId); } long FileReaderSelector::GetDefaultId() const { return m_Data->m_BestId; } FileReaderSelector::Item FileReaderSelector::GetSelected() const { return Get(m_Data->m_SelectedId); } long FileReaderSelector::GetSelectedId() const { return m_Data->m_SelectedId; } bool FileReaderSelector::Select(const FileReaderSelector::Item& item) { return Select(item.m_Id); } bool FileReaderSelector::Select(long id) { if (id > -1) { if (m_Data->m_Items.find(id) == m_Data->m_Items.end()) { return false; } m_Data->m_SelectedId = id; return true; } return false; } void FileReaderSelector::Swap(FileReaderSelector& fws) { m_Data.Swap(fws.m_Data); } IFileReader* FileReaderSelector::Item::GetReader() const { return m_FileReader; } std::string FileReaderSelector::Item::GetDescription() const { us::Any descr = m_FileReaderRef.GetProperty(IFileReader::PROP_DESCRIPTION()); if (descr.Empty()) return std::string(); return descr.ToString(); } IFileReader::ConfidenceLevel FileReaderSelector::Item::GetConfidenceLevel() const { return m_ConfidenceLevel; } MimeType FileReaderSelector::Item::GetMimeType() const { return m_MimeType; } us::ServiceReference FileReaderSelector::Item::GetReference() const { return m_FileReaderRef; } long FileReaderSelector::Item::GetServiceId() const { return m_Id; } bool FileReaderSelector::Item::operator<(const FileReaderSelector::Item& other) const { // sort by confidence level first (ascending) if (m_ConfidenceLevel == other.m_ConfidenceLevel) { // sort by mime-type ranking if (m_MimeType < other.m_MimeType) { return true; } else if (other.m_MimeType < m_MimeType) { return false; } else { // sort by file writer service ranking return m_FileReaderRef < other.m_FileReaderRef; } } return m_ConfidenceLevel < other.m_ConfidenceLevel; } FileReaderSelector::Item::Item() : m_FileReader(NULL) , m_Id(-1) {} void swap(FileReaderSelector& frs1, FileReaderSelector& frs2) { frs1.Swap(frs2); } } diff --git a/Core/Code/IO/mitkFileWriterSelector.cpp b/Core/Code/IO/mitkFileWriterSelector.cpp index daf039eac1..b4f6386acb 100644 --- a/Core/Code/IO/mitkFileWriterSelector.cpp +++ b/Core/Code/IO/mitkFileWriterSelector.cpp @@ -1,275 +1,276 @@ /*=================================================================== 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 "mitkFileWriterSelector.h" #include #include #include #include #include #include namespace mitk { struct FileWriterSelector::Impl : us::SharedData { Impl() : m_BestId(-1) , m_SelectedId(m_BestId) {} Impl(const Impl& other) : us::SharedData(other) , m_BestId(-1) , m_SelectedId(m_BestId) {} FileWriterRegistry m_WriterRegistry; std::map m_Items; std::set m_MimeTypes; long m_BestId; long m_SelectedId; }; FileWriterSelector::FileWriterSelector(const FileWriterSelector& other) : m_Data(other.m_Data) { } FileWriterSelector::FileWriterSelector(const BaseData* baseData, const std::string& destMimeType) : m_Data(new Impl) { mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider()); // Get all writers and their mime types for the given base data type std::vector refs = m_Data->m_WriterRegistry.GetReferences(baseData, destMimeType); us::ServiceReference bestRef; for (std::vector::const_iterator iter = refs.begin(), iterEnd = refs.end(); iter != iterEnd; ++iter) { std::string mimeTypeName = iter->GetProperty(IFileWriter::PROP_MIMETYPE()).ToString(); if (!mimeTypeName.empty()) { MimeType mimeType = mimeTypeProvider->GetMimeTypeForName(mimeTypeName); if (mimeType.IsValid()) { // There is a registered mime-type for this writer. Now get the confidence level // of this writer for writing the given base data object. IFileWriter* writer = m_Data->m_WriterRegistry.GetWriter(*iter); if (writer == NULL) continue; try { std::cout << "*** Checking confidence level of " << typeid(*writer).name() << " ... "; - IFileWriter::ConfidenceLevel confidenceLevel = writer->GetConfidenceLevel(baseData); + writer->SetInput(baseData); + IFileWriter::ConfidenceLevel confidenceLevel = writer->GetConfidenceLevel(); std::cout << confidenceLevel << std::endl; if (confidenceLevel == IFileWriter::Unsupported) { continue; } Item item; item.m_FileWriterRef = *iter; item.m_FileWriter = writer; item.m_ConfidenceLevel = confidenceLevel; item.m_MimeType = mimeType; item.m_Id = us::any_cast(iter->GetProperty(us::ServiceConstants::SERVICE_ID())); m_Data->m_Items.insert(std::make_pair(item.m_Id, item)); m_Data->m_MimeTypes.insert(mimeType); if (!bestRef || bestRef < *iter) { bestRef = *iter; } } catch (const us::BadAnyCastException& e) { MITK_WARN << "Unexpected: " << e.what(); } catch (const std::exception& e) { // Log the error but continue MITK_WARN << "IFileWriter::GetConfidenceLevel exception: " << e.what(); } } } } if (bestRef) { try { m_Data->m_BestId = us::any_cast(bestRef.GetProperty(us::ServiceConstants::SERVICE_ID())); m_Data->m_SelectedId = m_Data->m_BestId; } catch (const us::BadAnyCastException&) {} } } FileWriterSelector::~FileWriterSelector() { } FileWriterSelector& FileWriterSelector::operator=(const FileWriterSelector& other) { m_Data = other.m_Data; return *this; } std::vector FileWriterSelector::Get(const std::string& mimeType) const { std::vector result; for (std::map::const_iterator iter = m_Data->m_Items.begin(), iterEnd = m_Data->m_Items.end(); iter != iterEnd; ++iter) { if (mimeType.empty() || iter->second.GetMimeType().GetName() == mimeType) { result.push_back(iter->second); } } std::sort(result.begin(), result.end()); return result; } std::vector FileWriterSelector::Get() const { return Get(this->GetSelected().m_MimeType.GetName()); } FileWriterSelector::Item FileWriterSelector::Get(long id) const { std::map::const_iterator iter = m_Data->m_Items.find(id); if (iter != m_Data->m_Items.end()) { return iter->second; } return Item(); } FileWriterSelector::Item FileWriterSelector::GetDefault() const { return Get(m_Data->m_BestId); } long FileWriterSelector::GetDefaultId() const { return m_Data->m_BestId; } FileWriterSelector::Item FileWriterSelector::GetSelected() const { return Get(m_Data->m_SelectedId); } long FileWriterSelector::GetSelectedId() const { return m_Data->m_SelectedId; } bool FileWriterSelector::Select(const std::string& mimeType) { std::vector items = Get(mimeType); if (items.empty()) return false; return Select(items.back()); } bool FileWriterSelector::Select(const FileWriterSelector::Item& item) { return Select(item.m_Id); } bool FileWriterSelector::Select(long id) { if (id > -1) { if (m_Data->m_Items.find(id) == m_Data->m_Items.end()) { return false; } m_Data->m_SelectedId = id; return true; } return false; } std::vector FileWriterSelector::GetMimeTypes() const { std::vector result; result.reserve(m_Data->m_MimeTypes.size()); result.assign(m_Data->m_MimeTypes.begin(), m_Data->m_MimeTypes.end()); return result; } void FileWriterSelector::Swap(FileWriterSelector& fws) { m_Data.Swap(fws.m_Data); } IFileWriter* FileWriterSelector::Item::GetWriter() const { return m_FileWriter; } std::string FileWriterSelector::Item::GetDescription() const { us::Any descr = m_FileWriterRef.GetProperty(IFileWriter::PROP_DESCRIPTION()); if (descr.Empty()) return std::string(); return descr.ToString(); } IFileWriter::ConfidenceLevel FileWriterSelector::Item::GetConfidenceLevel() const { return m_ConfidenceLevel; } MimeType FileWriterSelector::Item::GetMimeType() const { return m_MimeType; } us::ServiceReference FileWriterSelector::Item::GetReference() const { return m_FileWriterRef; } long FileWriterSelector::Item::GetServiceId() const { return m_Id; } bool FileWriterSelector::Item::operator<(const FileWriterSelector::Item& other) const { // sort by confidence level first (ascending) if (m_ConfidenceLevel == other.m_ConfidenceLevel) { // sort by file writer service ranking return m_FileWriterRef < other.m_FileWriterRef; } return m_ConfidenceLevel < other.m_ConfidenceLevel; } FileWriterSelector::Item::Item() : m_FileWriter(NULL) , m_Id(-1) {} void swap(FileWriterSelector& fws1, FileWriterSelector& fws2) { fws1.Swap(fws2); } } diff --git a/Core/Code/IO/mitkIOUtil.cpp b/Core/Code/IO/mitkIOUtil.cpp index dc6e8150b9..54da62f0bd 100644 --- a/Core/Code/IO/mitkIOUtil.cpp +++ b/Core/Code/IO/mitkIOUtil.cpp @@ -1,1087 +1,1088 @@ /*=================================================================== 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 #include #include #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 //************************************************************** // mitk::IOUtil method definitions namespace mitk { const std::string IOUtil::DEFAULTIMAGEEXTENSION = ".nrrd"; const std::string IOUtil::DEFAULTSURFACEEXTENSION = ".stl"; const std::string IOUtil::DEFAULTPOINTSETEXTENSION = ".mps"; struct IOUtil::Impl { struct FixedReaderOptionsFunctor : public ReaderOptionsFunctorBase { FixedReaderOptionsFunctor(const IFileReader::Options& options) : m_Options(options) {} virtual bool operator()(LoadInfo& loadInfo) { IFileReader* reader = loadInfo.m_ReaderSelector.GetSelected().GetReader(); if (reader) { reader->SetOptions(m_Options); } return false; } private: const IFileReader::Options& m_Options; }; struct FixedWriterOptionsFunctor : public WriterOptionsFunctorBase { FixedWriterOptionsFunctor(const IFileReader::Options& options) : m_Options(options) {} virtual bool operator()(SaveInfo& saveInfo) { IFileWriter* writer = saveInfo.m_WriterSelector.GetSelected().GetWriter(); if (writer) { writer->SetOptions(m_Options); } return false; } private: const IFileWriter::Options& m_Options; }; static BaseData::Pointer LoadBaseDataFromFile(const std::string& path); static void SetDefaultDataNodeProperties(mitk::DataNode* node, const std::string& filePath = std::string()); }; #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 char IOUtil::GetDirectorySeparator() { #ifdef US_PLATFORM_WINDOWS return '\\'; #else return '/'; #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 += GetDirectorySeparator() + 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 += GetDirectorySeparator() + 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; } DataStorage::SetOfObjects::Pointer IOUtil::Load(const std::string& path, DataStorage& storage) { std::vector paths; paths.push_back(path); return Load(paths, storage); } DataStorage::SetOfObjects::Pointer IOUtil::Load(const std::string& path, const IFileReader::Options& options, DataStorage& storage) { std::vector loadInfos; loadInfos.push_back(LoadInfo(path)); DataStorage::SetOfObjects::Pointer nodeResult = DataStorage::SetOfObjects::New(); Impl::FixedReaderOptionsFunctor optionsCallback(options); std::string errMsg = Load(loadInfos, nodeResult, &storage, &optionsCallback); if (!errMsg.empty()) { mitkThrow() << errMsg; } return nodeResult; } std::vector IOUtil::Load(const std::string& path) { std::vector paths; paths.push_back(path); return Load(paths); } std::vector IOUtil::Load(const std::string& path, const IFileReader::Options& options) { std::vector loadInfos; loadInfos.push_back(LoadInfo(path)); Impl::FixedReaderOptionsFunctor optionsCallback(options); std::string errMsg = Load(loadInfos, NULL, NULL, &optionsCallback); if (!errMsg.empty()) { mitkThrow() << errMsg; } return loadInfos.front().m_Output; } DataStorage::SetOfObjects::Pointer IOUtil::Load(const std::vector& paths, DataStorage& storage) { DataStorage::SetOfObjects::Pointer nodeResult = DataStorage::SetOfObjects::New(); std::vector loadInfos; for (std::vector::const_iterator iter = paths.begin(), iterEnd = paths.end(); iter != iterEnd; ++iter) { LoadInfo loadInfo(*iter); loadInfos.push_back(loadInfo); } std::string errMsg = Load(loadInfos, nodeResult, &storage, NULL); if (!errMsg.empty()) { mitkThrow() << errMsg; } return nodeResult; } std::vector IOUtil::Load(const std::vector& paths) { std::vector result; std::vector loadInfos; for (std::vector::const_iterator iter = paths.begin(), iterEnd = paths.end(); iter != iterEnd; ++iter) { LoadInfo loadInfo(*iter); loadInfos.push_back(loadInfo); } std::string errMsg = Load(loadInfos, NULL, NULL, NULL); if (!errMsg.empty()) { mitkThrow() << errMsg; } for (std::vector::const_iterator iter = loadInfos.begin(), iterEnd = loadInfos.end(); iter != iterEnd; ++iter) { result.insert(result.end(), iter->m_Output.begin(), iter->m_Output.end()); } return result; } int IOUtil::LoadFiles(const std::vector &fileNames, DataStorage& ds) { return static_cast(Load(fileNames, ds)->Size()); } DataStorage::Pointer IOUtil::LoadFiles(const std::vector& fileNames) { mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); Load(fileNames, *ds); return ds.GetPointer(); } BaseData::Pointer IOUtil::LoadBaseData(const std::string& path) { return Impl::LoadBaseDataFromFile(path); } BaseData::Pointer IOUtil::Impl::LoadBaseDataFromFile(const std::string& path) { std::vector baseDataList = Load(path); // The Load(path) call above should throw an exception if nothing could be loaded assert(!baseDataList.empty()); return baseDataList.front(); } DataNode::Pointer IOUtil::LoadDataNode(const std::string& path) { BaseData::Pointer baseData = Impl::LoadBaseDataFromFile(path); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(baseData); Impl::SetDefaultDataNodeProperties(node, path); return node; } Image::Pointer IOUtil::LoadImage(const std::string& path) { BaseData::Pointer baseData = Impl::LoadBaseDataFromFile(path); mitk::Image::Pointer image = dynamic_cast(baseData.GetPointer()); if(image.IsNull()) { mitkThrow() << path << " is not a mitk::Image but a " << baseData->GetNameOfClass(); } return image; } Surface::Pointer IOUtil::LoadSurface(const std::string& path) { BaseData::Pointer baseData = Impl::LoadBaseDataFromFile(path); mitk::Surface::Pointer surface = dynamic_cast(baseData.GetPointer()); if(surface.IsNull()) { mitkThrow() << path << " is not a mitk::Surface but a " << baseData->GetNameOfClass(); } return surface; } PointSet::Pointer IOUtil::LoadPointSet(const std::string& path) { BaseData::Pointer baseData = Impl::LoadBaseDataFromFile(path); mitk::PointSet::Pointer pointset = dynamic_cast(baseData.GetPointer()); if(pointset.IsNull()) { mitkThrow() << path << " is not a mitk::PointSet but a " << baseData->GetNameOfClass(); } return pointset; } std::string IOUtil::Load(std::vector& loadInfos, DataStorage::SetOfObjects* nodeResult, DataStorage* ds, ReaderOptionsFunctorBase* optionsCallback) { if (loadInfos.empty()) { return "No input files given"; } int filesToRead = loadInfos.size(); mitk::ProgressBar::GetInstance()->AddStepsToDo(2*filesToRead); std::string errMsg; std::map usedReaderItems; for(std::vector::iterator infoIter = loadInfos.begin(), infoIterEnd = loadInfos.end(); infoIter != infoIterEnd; ++infoIter) { std::vector readers = infoIter->m_ReaderSelector.Get(); if (readers.empty()) { errMsg += "No reader available for '" + infoIter->m_Path + "'\n"; continue; } bool callOptionsCallback = readers.size() > 1 || !readers.front().GetReader()->GetOptions().empty(); // check if we already used a reader which should be re-used std::vector currMimeTypes = infoIter->m_ReaderSelector.GetMimeTypes(); std::string selectedMimeType; for (std::vector::const_iterator mimeTypeIter = currMimeTypes.begin(), mimeTypeIterEnd = currMimeTypes.end(); mimeTypeIter != mimeTypeIterEnd; ++mimeTypeIter) { std::map::const_iterator oldSelectedItemIter = usedReaderItems.find(mimeTypeIter->GetName()); if (oldSelectedItemIter != usedReaderItems.end()) { // we found an already used item for a mime-type which is contained // in the current reader set, check all current readers if there service // id equals the old reader for (std::vector::const_iterator currReaderItem = readers.begin(), currReaderItemEnd = readers.end(); currReaderItem != currReaderItemEnd; ++currReaderItem) { if (currReaderItem->GetMimeType().GetName() == mimeTypeIter->GetName() && currReaderItem->GetServiceId() == oldSelectedItemIter->second.GetServiceId() && currReaderItem->GetConfidenceLevel() >= oldSelectedItemIter->second.GetConfidenceLevel()) { // okay, we used the same reader already, re-use its options selectedMimeType = mimeTypeIter->GetName(); callOptionsCallback = false; infoIter->m_ReaderSelector.Select(oldSelectedItemIter->second.GetServiceId()); infoIter->m_ReaderSelector.GetSelected().GetReader()->SetOptions( oldSelectedItemIter->second.GetReader()->GetOptions()); break; } } if (!selectedMimeType.empty()) break; } } if (callOptionsCallback && optionsCallback) { callOptionsCallback = (*optionsCallback)(*infoIter); if (!callOptionsCallback && !infoIter->m_Cancel) { usedReaderItems.erase(selectedMimeType); FileReaderSelector::Item selectedItem = infoIter->m_ReaderSelector.GetSelected(); usedReaderItems.insert(std::make_pair(selectedItem.GetMimeType().GetName(), selectedItem)); } } if (infoIter->m_Cancel) { errMsg += "Reading operation(s) cancelled."; break; } IFileReader* reader = infoIter->m_ReaderSelector.GetSelected().GetReader(); if (reader == NULL) { errMsg += "Unexpected NULL reader."; break; } MITK_INFO << "******* USING READER " << typeid(*reader).name() << "*********"; // Do the actual reading try { DataStorage::SetOfObjects::Pointer nodes; if (ds != NULL) { - nodes = reader->Read(infoIter->m_Path, *ds); + nodes = reader->Read(*ds); } else { nodes = DataStorage::SetOfObjects::New(); - std::vector baseData = reader->Read(infoIter->m_Path); + std::vector baseData = reader->Read(); for (std::vector::iterator iter = baseData.begin(); iter != baseData.end(); ++iter) { if (iter->IsNotNull()) { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(*iter); nodes->InsertElement(nodes->Size(), node); } } } for (DataStorage::SetOfObjects::ConstIterator nodeIter = nodes->Begin(), nodeIterEnd = nodes->End(); nodeIter != nodeIterEnd; ++nodeIter) { const mitk::DataNode::Pointer& node = nodeIter->Value(); mitk::BaseData::Pointer data = node->GetData(); if (data.IsNull()) { continue; } mitk::StringProperty::Pointer pathProp = mitk::StringProperty::New(infoIter->m_Path); data->SetProperty("path", pathProp); infoIter->m_Output.push_back(data); if (nodeResult) { nodeResult->push_back(nodeIter->Value()); } } if (infoIter->m_Output.empty() || (nodeResult && nodeResult->Size() == 0)) { errMsg += "Unknown read error occurred reading " + infoIter->m_Path; } } catch (const std::exception& e) { errMsg += "Exception occured when reading file " + infoIter->m_Path + ":\n" + e.what() + "\n\n"; } mitk::ProgressBar::GetInstance()->Progress(2); --filesToRead; } if (!errMsg.empty()) { MITK_ERROR << errMsg; } mitk::ProgressBar::GetInstance()->Progress(2*filesToRead); return errMsg; } void IOUtil::Save(const BaseData* data, const std::string& path) { Save(data, path, IFileWriter::Options()); } void IOUtil::Save(const BaseData* data, const std::string& path, const IFileWriter::Options& options) { Save(data, std::string(), path, options); } void IOUtil::Save(const BaseData* data, const std::string& mimeType, const std::string& path, bool addExtension) { Save(data, mimeType, path, IFileWriter::Options(), addExtension); } void IOUtil::Save(const BaseData* data, const std::string& mimeType, const std::string& path, const IFileWriter::Options& options, bool addExtension) { std::string errMsg; if (options.empty()) { errMsg = Save(data, mimeType, path, NULL, addExtension); } else { Impl::FixedWriterOptionsFunctor optionsCallback(options); errMsg = Save(data, mimeType, path, &optionsCallback, addExtension); } if (!errMsg.empty()) { mitkThrow() << errMsg; } } void IOUtil::Save(std::vector& saveInfos) { std::string errMsg = Save(saveInfos, NULL); if (!errMsg.empty()) { mitkThrow() << errMsg; } } bool IOUtil::SaveImage(mitk::Image::Pointer image, const std::string& path) { Save(image, path); return true; } bool IOUtil::SaveSurface(Surface::Pointer surface, const std::string& path) { Save(surface, path); return true; } bool IOUtil::SavePointSet(PointSet::Pointer pointset, const std::string& path) { Save(pointset, path); return true; } bool IOUtil::SaveBaseData( mitk::BaseData* data, const std::string& path) { Save(data, path); return true; } std::string IOUtil::Save(const BaseData* data, const std::string& mimeTypeN, const std::string& path, WriterOptionsFunctorBase* optionsCallback, bool addExtension) { if (path.empty()) { return "No output filename given"; } mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider()); std::string mimeTypeName = mimeTypeN; // If no mime-type is provided, we try to get the mime-type from the // highest ranked IFileWriter object for the given BaseData type if (mimeTypeName.empty()) { std::vector refs = us::GetModuleContext()->GetServiceReferences( us::LDAPProp(us::ServiceConstants::OBJECTCLASS()) == us_service_interface_iid() && us::LDAPProp(IFileWriter::PROP_BASEDATA_TYPE()) == data->GetNameOfClass()); std::sort(refs.begin(), refs.end()); if (!refs.empty()) { us::Any mimeProp = refs.back().GetProperty(IFileWriter::PROP_MIMETYPE()); if (mimeProp.Type() == typeid(std::string)) { mimeTypeName = us::any_cast(mimeProp); } } } MimeType mimeType = mimeTypeProvider->GetMimeTypeForName(mimeTypeName); if (mimeType.IsValid()) { std::string ext = itksys::SystemTools::GetFilenameExtension(path); if (ext.empty() && addExtension) { ext = mimeType.GetExtensions().empty() ? std::string() : "." + mimeType.GetExtensions().front(); } std::vector infos; infos.push_back(SaveInfo(data, mimeType, path + ext)); return Save(infos, optionsCallback); } return "The mime-type '" + mimeTypeName + "' is not registered"; } std::string IOUtil::Save(std::vector& saveInfos, WriterOptionsFunctorBase* optionsCallback) { if (saveInfos.empty()) { return "No data for saving available"; } int filesToWrite = saveInfos.size(); mitk::ProgressBar::GetInstance()->AddStepsToDo(2*filesToWrite); std::string errMsg; std::set usedSaveInfos; for (std::vector::iterator infoIter = saveInfos.begin(), infoIterEnd = saveInfos.end(); infoIter != infoIterEnd; ++infoIter) { const std::string baseDataType = infoIter->m_BaseData->GetNameOfClass(); std::vector writers = infoIter->m_WriterSelector.Get(); // Error out if no compatible Writer was found if (writers.empty()) { errMsg += std::string("No writer available for ") + baseDataType + " data.\n"; continue; } bool callOptionsCallback = writers.size() > 1 || !writers[0].GetWriter()->GetOptions().empty(); // check if we already used a writer for this base data type // which should be re-used std::set::const_iterator oldSaveInfoIter = usedSaveInfos.find(*infoIter); if (oldSaveInfoIter != usedSaveInfos.end()) { // we previously saved a base data object of the same data with the same mime-type, // check if the same writer is contained in the current writer set and if the // confidence level matches FileWriterSelector::Item oldSelectedItem = oldSaveInfoIter->m_WriterSelector.Get(oldSaveInfoIter->m_WriterSelector.GetSelectedId()); for (std::vector::const_iterator currWriterItem = writers.begin(), currWriterItemEnd = writers.end(); currWriterItem != currWriterItemEnd; ++currWriterItem) { if (currWriterItem->GetServiceId() == oldSelectedItem.GetServiceId() && currWriterItem->GetConfidenceLevel() >= oldSelectedItem.GetConfidenceLevel()) { // okay, we used the same writer already, re-use its options callOptionsCallback = false; infoIter->m_WriterSelector.Select(oldSaveInfoIter->m_WriterSelector.GetSelectedId()); infoIter->m_WriterSelector.GetSelected().GetWriter()->SetOptions( oldSelectedItem.GetWriter()->GetOptions()); break; } } } if (callOptionsCallback && optionsCallback) { callOptionsCallback = (*optionsCallback)(*infoIter); if (!callOptionsCallback && !infoIter->m_Cancel) { usedSaveInfos.erase(*infoIter); usedSaveInfos.insert(*infoIter); } } if (infoIter->m_Cancel) { errMsg += "Writing operation(s) cancelled."; break; } IFileWriter* writer = infoIter->m_WriterSelector.GetSelected().GetWriter(); if (writer == NULL) { errMsg += "Unexpected NULL writer."; break; } MITK_INFO << "******* USING WRITER " << typeid(*writer).name() << "*********"; // Do the actual writing try { - writer->Write(infoIter->m_BaseData, infoIter->m_Path); + writer->SetOutputLocation(infoIter->m_Path); + writer->Write(); } catch(const std::exception& e) { errMsg += std::string("Exception occurred when writing to ") + infoIter->m_Path + ":\n" + e.what() + "\n"; } mitk::ProgressBar::GetInstance()->Progress(2); --filesToWrite; } if (!errMsg.empty()) { MITK_ERROR << errMsg; } mitk::ProgressBar::GetInstance()->Progress(2*filesToWrite); return errMsg; } // This method can be removed after the deprecated LoadDataNode() method was removed void IOUtil::Impl::SetDefaultDataNodeProperties(DataNode* node, const std::string& filePath) { // path mitk::StringProperty::Pointer pathProp = mitk::StringProperty::New( itksys::SystemTools::GetFilenamePath(filePath) ); node->SetProperty(StringProperty::PATH, pathProp); // name already defined? mitk::StringProperty::Pointer nameProp = dynamic_cast(node->GetProperty("name")); if(nameProp.IsNull() || (strcmp(nameProp->GetValue(),"No Name!")==0)) { // 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)) { // 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); } } // visibility if(!node->GetProperty("visible")) { node->SetVisibility(true); } } IOUtil::SaveInfo::SaveInfo(const BaseData* baseData) : m_BaseData(baseData) , m_WriterSelector(baseData, std::string()) , m_Cancel(false) { } IOUtil::SaveInfo::SaveInfo(const BaseData* baseData, const MimeType& mimeType, const std::string& path) : m_BaseData(baseData) , m_MimeType(mimeType) , m_WriterSelector(baseData, mimeType.IsValid() ? mimeType.GetName() : std::string()) , m_Path(path) , m_Cancel(false) { } bool IOUtil::SaveInfo::operator<(const IOUtil::SaveInfo& other) const { int r = strcmp(m_BaseData->GetNameOfClass(), other.m_BaseData->GetNameOfClass()); if (r == 0) { return m_WriterSelector.GetSelected().GetMimeType() < other.m_WriterSelector.GetSelected().GetMimeType(); } return r < 0; } IOUtil::LoadInfo::LoadInfo(const std::string& path) : m_Path(path) , m_ReaderSelector(path) , m_Cancel(false) { } } diff --git a/Core/Code/Interfaces/mitkIFileReader.h b/Core/Code/Interfaces/mitkIFileReader.h index 82486e0518..e9b5a993cf 100644 --- a/Core/Code/Interfaces/mitkIFileReader.h +++ b/Core/Code/Interfaces/mitkIFileReader.h @@ -1,159 +1,168 @@ /*=================================================================== 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 #include // MITK #include #include namespace mitk { class BaseData; } namespace itk { template class SmartPointer; } namespace mitk { /** * \brief The common interface for all MITK file readers. + * \ingroup IO * * 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 CustomMimeType 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. + * It is recommended to derive new implementations from AbstractFileReader or + * from AbstractFileIO (if both reader and writer is implemented), + * which provide correct service registration semantics. * * \sa AbstractFileReader + * \sa AbstractFileIO * \sa CustomMimeType * \sa FileReaderRegistry * \sa IFileWriter */ struct MITK_CORE_EXPORT IFileReader { // The order of the enum values is important: it is used // to rank writer implementations enum ConfidenceLevel { Unsupported = 0, PartiallySupported = 8, Supported = 16 }; virtual ~IFileReader(); typedef std::map Options; typedef mitk::MessageAbstractDelegate1 ProgressCallback; /** - * \brief Reads the specified file and returns its contents. + * \brief Set the input file name. + * \param location The file name to read from. */ - virtual std::vector > Read(const std::string& path) = 0; + virtual void SetInput(const std::string& location) = 0; - /** - * \brief Reads the specified input stream and returns its contents. - */ - virtual std::vector > Read(std::istream& stream) = 0; + virtual void SetInput(const std::string &location, std::istream* is) = 0; + + virtual std::string GetInputLocation() const = 0; + + virtual std::istream* GetInputStream() const = 0; /** - * \brief Reads the specified file, loading its contents into the provided DataStorage. + * \brief Reads the specified file or input stream and returns its contents. * - * \param path The absolute file path include the file name extension. - * \param ds The DataStorage to which the data is added. - * \return The set of add DataNodes to \c ds. + * \return A list of created BaseData objects. + * \throws mitk::Exception */ - virtual DataStorage::SetOfObjects::Pointer Read(const std::string& path, mitk::DataStorage& ds) = 0; + virtual std::vector > Read() = 0; /** - * \brief Reads the specified input stream and returns its contents. + * \brief Reads the specified file or input stream, loading its + * contents into the provided DataStorage. + * + * \param ds The DataStorage to which the data is added. + * \return The set of added DataNodes to \c ds. + * \throws mitk::Exception */ - virtual DataStorage::SetOfObjects::Pointer Read(std::istream& stream, mitk::DataStorage& ds) = 0; + virtual DataStorage::SetOfObjects::Pointer Read(mitk::DataStorage& ds) = 0; - virtual ConfidenceLevel GetConfidenceLevel(const std::string& path) const = 0; + virtual ConfidenceLevel GetConfidenceLevel() const = 0; /** * \brief returns a list of the supported Options * * Initially, the reader contains a set of standard options. These can be retrieved, * manipulated and set again. To activate or deactivate an option, just set it's bool * value accordingly. All supported options are in the default set, it does not * make sense to add strings artificially after retrieving a reader - the specific * implementation decides which options it wants to support. * If no options are supported, an empty list is returned. */ virtual Options GetOptions() const = 0; virtual us::Any GetOption(const std::string& name) const = 0; /** * \brief Sets the options for this reader * * The best way to use this method is to retireve the options via GetOptions, manipulate the bool values, * and then set the options again. */ virtual void SetOptions(const Options& options) = 0; virtual void SetOption(const std::string& name, const us::Any& value) = 0; virtual void AddProgressCallback(const ProgressCallback& callback) = 0; virtual void RemoveProgressCallback(const ProgressCallback& callback) = 0; /** * @brief Service property name for a description. * * The property value must be of type \c std::string. * * @return The property name. */ static std::string PROP_DESCRIPTION(); /** * @brief Service property name for the mime-type associated with this file reader. * * The property value must be of type \c std::string. * * @return The property name. */ static std::string PROP_MIMETYPE(); }; } // namespace mitk US_DECLARE_SERVICE_INTERFACE(mitk::IFileReader, "org.mitk.IFileReader") #endif /* IFileReader_H_HEADER_INCLUDED_C1E7E521 */ diff --git a/Core/Code/Interfaces/mitkIFileWriter.h b/Core/Code/Interfaces/mitkIFileWriter.h index dc743effc6..8f256fec12 100644 --- a/Core/Code/Interfaces/mitkIFileWriter.h +++ b/Core/Code/Interfaces/mitkIFileWriter.h @@ -1,137 +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 IFileWriter_H_HEADER_INCLUDED_C1E7E521 #define IFileWriter_H_HEADER_INCLUDED_C1E7E521 // Macro #include // Microservices #include #include // MITK #include namespace mitk { class BaseData; } namespace mitk { /** * \brief The common interface of all MITK file writers. * * 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 writer implementation is associated with a mime-type, specified * in the service property PROP_MIMETYPE() and a mitk::BaseData sub-class * as specified in the PROP_BASEDATA_TYPE() service property. * The specified mime-type should have a corresponding CustomMimeType service * object, registered by the reader or some other party. * - * It is recommended to derive new implementations from AbstractFileWriter, - * which provides correct service registration semantics. + * It is recommended to derive new implementations from AbstractFileWriter or + * AbstractFileIO (if both reader and writer is implemented), + * which provide correct service registration semantics. * * \sa AbstractFileWriter + * \sa AbstractFileIO * \sa CustomMimeType * \sa FileWriterRegistry * \sa IFileReader */ struct MITK_CORE_EXPORT IFileWriter { // The order of the enum values is important: it is used // to rank writer implementations enum ConfidenceLevel { Unsupported = 0, PartiallySupported = 8, Supported = 16 }; virtual ~IFileWriter(); typedef std::map Options; typedef mitk::MessageAbstractDelegate1 ProgressCallback; - virtual void Write(const BaseData* data, const std::string& path ) = 0; + virtual void SetInput(const BaseData* data) = 0; + virtual const BaseData* GetInput() const = 0; - virtual void Write(const BaseData* data, std::ostream& stream ) = 0; + virtual void SetOutputLocation(const std::string& location) = 0; + virtual std::string GetOutputLocation() const = 0; - virtual ConfidenceLevel GetConfidenceLevel(const BaseData* data) const = 0; + virtual void SetOutputStream(const std::string& location, std::ostream* os) = 0; + virtual std::ostream* GetOutputStream() const = 0; + + virtual void Write() = 0; + + virtual ConfidenceLevel GetConfidenceLevel() const = 0; /** * \brief returns a list of the supported Options * * Options are strings that are treated as flags when passed to the write method. */ virtual Options GetOptions() const = 0; virtual us::Any GetOption(const std::string& name) const = 0; virtual void SetOptions(const Options& options) = 0; virtual void SetOption(const std::string& name, const us::Any& value) = 0; /** * \brief Returns a value between 0 and 1 depending on the progress of the writing process. * This method need not necessarily be implemented meaningfully, always returning zero is accepted. */ virtual void AddProgressCallback(const ProgressCallback& callback) = 0; virtual void RemoveProgressCallback(const ProgressCallback& callback) = 0; // Microservice properties /** * @brief Service property name for the supported mitk::BaseData sub-class * * The property value must be of type \c std::string. * * @return The property name. */ static std::string PROP_BASEDATA_TYPE(); /** * @brief Service property name for a description. * * The property value must be of type \c std::string. * * @return The property name. */ static std::string PROP_DESCRIPTION(); /** * @brief Service property name for the mime-type associated with this file writer. * * The property value must be of type \c std::string. * * @return The property name. */ static std::string PROP_MIMETYPE(); }; } // namespace mitk US_DECLARE_SERVICE_INTERFACE(mitk::IFileWriter, "org.mitk.IFileWriter") #endif /* IFileWriter_H_HEADER_INCLUDED_C1E7E521 */ diff --git a/Core/Code/Internal/mitkItkImageIO.cpp b/Core/Code/Internal/mitkItkImageIO.cpp index 26c89810b2..0fff8400da 100644 --- a/Core/Code/Internal/mitkItkImageIO.cpp +++ b/Core/Code/Internal/mitkItkImageIO.cpp @@ -1,486 +1,481 @@ /*=================================================================== 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 "mitkItkImageIO.h" #include #include #include #include #include #include #include #include namespace mitk { ItkImageIO::ItkImageIO(const ItkImageIO& other) : AbstractFileIO(other) , m_ImageIO(dynamic_cast(other.m_ImageIO->Clone().GetPointer())) { } std::vector ItkImageIO::FixUpImageIOExtensions(const std::string& imageIOName) { std::vector extensions; // Try to fix-up some known ITK image IO classes if (imageIOName == "GiplImageIO") { extensions.push_back("gipl"); extensions.push_back("gipl.gz"); } else if (imageIOName == "GDCMImageIO") { extensions.push_back("gdcm"); } else if (imageIOName == "PNGImageIO") { extensions.push_back("png"); extensions.push_back("PNG"); } else if (imageIOName == "StimulateImageIO") { extensions.push_back("spr"); } else if (imageIOName == "HDF5ImageIO") { extensions.push_back("hdf"); extensions.push_back("h4"); extensions.push_back("hdf4"); extensions.push_back("h5"); extensions.push_back("hdf5"); extensions.push_back("he4"); extensions.push_back("he5"); extensions.push_back("hd5"); } if (!extensions.empty()) { MITK_WARN << "Fixing up known extensions for " << imageIOName; } return extensions; } ItkImageIO::ItkImageIO(itk::ImageIOBase::Pointer imageIO) : AbstractFileIO(Image::GetStaticNameOfClass()) , m_ImageIO(imageIO) { if (m_ImageIO.IsNull() ) { mitkThrow() << "ITK ImageIOBase argument must not be NULL"; } std::vector readExtensions = m_ImageIO->GetSupportedReadExtensions(); if (readExtensions.empty()) { std::string imageIOName = m_ImageIO->GetNameOfClass(); MITK_WARN << "ITK ImageIOBase " << imageIOName << " does not provide read extensions"; readExtensions = FixUpImageIOExtensions(imageIOName); } CustomMimeType customReaderMimeType; customReaderMimeType.SetCategory("Images"); for(std::vector::const_iterator iter = readExtensions.begin(), endIter = readExtensions.end(); iter != endIter; ++iter) { std::string extension = *iter; if (!extension.empty() && extension[0] == '.') { extension.assign(iter->begin()+1, iter->end()); } customReaderMimeType.AddExtension(extension); } this->AbstractFileReader::SetMimeType(customReaderMimeType); std::vector writeExtensions = imageIO->GetSupportedWriteExtensions(); if (writeExtensions.empty()) { std::string imageIOName = imageIO->GetNameOfClass(); MITK_WARN << "ITK ImageIOBase " << imageIOName << " does not provide write extensions"; writeExtensions = FixUpImageIOExtensions(imageIOName); } CustomMimeType customWriterMimeType; customWriterMimeType.SetCategory("Images"); if (writeExtensions == readExtensions) { customWriterMimeType.AddExtension(customReaderMimeType.GetExtensions().front()); } else { for(std::vector::const_iterator iter = writeExtensions.begin(), endIter = writeExtensions.end(); iter != endIter; ++iter) { std::string extension = *iter; if (!extension.empty() && extension[0] == '.') { extension.assign(iter->begin()+1, iter->end()); } customWriterMimeType.AddExtension(extension); } } this->AbstractFileWriter::SetMimeType(customWriterMimeType); std::string description = std::string("ITK ") + imageIO->GetNameOfClass(); this->SetReaderDescription(description); this->SetWriterDescription(description); this->RegisterService(); } -std::vector ItkImageIO::Read(std::istream& stream) -{ - return mitk::AbstractFileReader::Read(stream); -} - -std::vector ItkImageIO::Read(const std::string& path) +std::vector ItkImageIO::Read() { std::vector result; 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; } } Image::Pointer image = Image::New(); const unsigned int MINDIM = 2; const unsigned int MAXDIM = 4; + const std::string path = this->GetLocalFileName(); + MITK_INFO << "loading " << path << " via itk::ImageIOFactory... " << std::endl; // Check to see if we can read the file given the name or prefix if (path.empty()) { mitkThrow() << "Empty filename in mitk::ItkImageIO "; } // Got to allocate space for the image. Determine the characteristics of // the image. - m_ImageIO->SetFileName( path.c_str() ); + m_ImageIO->SetFileName( path ); m_ImageIO->ReadImageInformation(); unsigned int ndim = m_ImageIO->GetNumberOfDimensions(); if ( ndim < MINDIM || ndim > MAXDIM ) { MITK_WARN << "Sorry, only dimensions 2, 3 and 4 are supported. The given file has " << ndim << " dimensions! Reading as 4D."; ndim = MAXDIM; } itk::ImageIORegion ioRegion( ndim ); itk::ImageIORegion::SizeType ioSize = ioRegion.GetSize(); itk::ImageIORegion::IndexType ioStart = ioRegion.GetIndex(); unsigned int dimensions[ MAXDIM ]; dimensions[ 0 ] = 0; dimensions[ 1 ] = 0; dimensions[ 2 ] = 0; dimensions[ 3 ] = 0; ScalarType spacing[ MAXDIM ]; spacing[ 0 ] = 1.0f; spacing[ 1 ] = 1.0f; spacing[ 2 ] = 1.0f; spacing[ 3 ] = 1.0f; Point3D origin; origin.Fill(0); unsigned int i; for ( i = 0; i < ndim ; ++i ) { ioStart[ i ] = 0; ioSize[ i ] = m_ImageIO->GetDimensions( i ); if(iGetDimensions( i ); spacing[ i ] = m_ImageIO->GetSpacing( i ); if(spacing[ i ] <= 0) spacing[ i ] = 1.0f; } if(i<3) { origin[ i ] = m_ImageIO->GetOrigin( i ); } } ioRegion.SetSize( ioSize ); ioRegion.SetIndex( ioStart ); MITK_INFO << "ioRegion: " << ioRegion << std::endl; m_ImageIO->SetIORegion( ioRegion ); void* buffer = new unsigned char[m_ImageIO->GetImageSizeInBytes()]; m_ImageIO->Read( buffer ); image->Initialize( MakePixelType(m_ImageIO), ndim, dimensions ); image->SetImportChannel( buffer, 0, Image::ManageMemory ); // access direction of itk::Image and include spacing mitk::Matrix3D matrix; matrix.SetIdentity(); unsigned int j, itkDimMax3 = (ndim >= 3? 3 : ndim); for ( i=0; i < itkDimMax3; ++i) for( j=0; j < itkDimMax3; ++j ) matrix[i][j] = m_ImageIO->GetDirection(j)[i]; // re-initialize PlaneGeometry with origin and direction PlaneGeometry* planeGeometry = image->GetSlicedGeometry(0)->GetPlaneGeometry(0); planeGeometry->SetOrigin(origin); planeGeometry->GetIndexToWorldTransform()->SetMatrix(matrix); // re-initialize SlicedGeometry3D SlicedGeometry3D* slicedGeometry = image->GetSlicedGeometry(0); slicedGeometry->InitializeEvenlySpaced(planeGeometry, image->GetDimension(2)); slicedGeometry->SetSpacing(spacing); MITK_INFO << slicedGeometry->GetCornerPoint(false,false,false); MITK_INFO << slicedGeometry->GetCornerPoint(true,true,true); // re-initialize TimeGeometry ProportionalTimeGeometry::Pointer timeGeometry = ProportionalTimeGeometry::New(); timeGeometry->Initialize(slicedGeometry, image->GetDimension(3)); image->SetTimeGeometry(timeGeometry); buffer = NULL; MITK_INFO << "number of image components: "<< image->GetPixelType().GetNumberOfComponents() << std::endl; const itk::MetaDataDictionary& dictionary = m_ImageIO->GetMetaDataDictionary(); for (itk::MetaDataDictionary::ConstIterator iter = dictionary.Begin(), iterEnd = dictionary.End(); iter != iterEnd; ++iter) { std::string key = std::string("meta.") + iter->first; if (iter->second->GetMetaDataObjectTypeInfo() == typeid(std::string)) { std::string value = dynamic_cast*>(iter->second.GetPointer())->GetMetaDataObjectValue(); image->SetProperty(key.c_str(), mitk::StringProperty::New(value)); } } MITK_INFO << "...finished!" << std::endl; try { setlocale(LC_ALL, currLocale.c_str()); } catch(...) { MITK_INFO << "Could not reset locale " << currLocale; } result.push_back(image.GetPointer()); return result; } -AbstractFileIO::ReaderConfidenceLevel ItkImageIO::GetReaderConfidenceLevel(const std::string& path) const +AbstractFileIO::ReaderConfidenceLevel ItkImageIO::GetReaderConfidenceLevel() const { - return m_ImageIO->CanReadFile(path.c_str()) ? IFileReader::Supported : IFileReader::Unsupported; + return m_ImageIO->CanReadFile(GetLocalFileName().c_str()) ? IFileReader::Supported : IFileReader::Unsupported; } -void ItkImageIO::Write(const BaseData* data, const std::string& path) +void ItkImageIO::Write() { - const mitk::Image* image = dynamic_cast(data); + const mitk::Image* image = dynamic_cast(this->GetInput()); if (image == NULL) { mitkThrow() << "Cannot write non-image data"; } struct LocaleSwitch { LocaleSwitch(const std::string& newLocale) : m_OldLocale(std::setlocale(LC_ALL, NULL)) , m_NewLocale(newLocale) { if (m_OldLocale == NULL) { m_OldLocale = ""; } else if (m_NewLocale != m_OldLocale) { // set the locale if (std::setlocale(LC_ALL, m_NewLocale.c_str()) == NULL) { MITK_INFO << "Could not set locale " << m_NewLocale; m_OldLocale = NULL; } } } ~LocaleSwitch() { if (m_OldLocale != NULL && std::setlocale(LC_ALL, m_OldLocale) == NULL) { MITK_INFO << "Could not reset locale " << m_OldLocale; } } private: const char* m_OldLocale; const std::string m_NewLocale; }; // Switch the current locale to "C" LocaleSwitch localeSwitch("C"); // Clone the image geometry, because we might have to change it // for writing purposes BaseGeometry::Pointer geometry = image->GetGeometry()->Clone(); // Check if geometry information will be lost if (image->GetDimension() == 2 && !geometry->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 = geometry->GetSpacing(); mitk::Point3D origin = geometry->GetOrigin(); geometry->SetIndexToWorldTransform(affTrans); geometry->SetSpacing(spacing); geometry->SetOrigin(origin); } + LocalFile localFile(this); + const std::string path = localFile.GetFileName(); + MITK_INFO << "Writing image: " << path << std::endl; try { // Implementation of writer using itkImageIO directly. This skips the use // of templated itkImageFileWriter, which saves the multiplexing on MITK side. const unsigned int dimension = image->GetDimension(); const unsigned int* const dimensions = image->GetDimensions(); const mitk::PixelType pixelType = image->GetPixelType(); const mitk::Vector3D mitkSpacing = geometry->GetSpacing(); const mitk::Point3D mitkOrigin = geometry->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 a 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 a valid value here // Set the necessary information for imageIO m_ImageIO->SetNumberOfDimensions(dimension); m_ImageIO->SetPixelType(pixelType.GetPixelType()); m_ImageIO->SetComponentType(pixelType.GetComponentType() < PixelComponentUserType ? static_cast(pixelType.GetComponentType()) : itk::ImageIOBase::UNKNOWNCOMPONENTTYPE); m_ImageIO->SetNumberOfComponents( pixelType.GetNumberOfComponents() ); itk::ImageIORegion ioRegion( dimension ); for(unsigned int i = 0; i < dimension; i++) { m_ImageIO->SetDimensions(i, dimensions[i]); m_ImageIO->SetSpacing(i, spacing4D[i]); m_ImageIO->SetOrigin(i, origin4D[i]); mitk::Vector3D mitkDirection; mitkDirection.SetVnlVector(geometry->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 axisDirection(dimension); for(unsigned int j = 0; j < dimension; j++) { axisDirection[j] = direction4D[j] / spacing4D[i]; } m_ImageIO->SetDirection(i, axisDirection); ioRegion.SetSize(i, image->GetLargestPossibleRegion().GetSize(i)); ioRegion.SetIndex(i, image->GetLargestPossibleRegion().GetIndex(i)); } //use compression if available m_ImageIO->UseCompressionOn(); m_ImageIO->SetIORegion(ioRegion); m_ImageIO->SetFileName(path); // ***** Remove const_cast after bug 17952 is fixed **** ImageReadAccessor imageAccess(const_cast(image)); m_ImageIO->Write(imageAccess.GetData()); } catch (const std::exception& e) { mitkThrow() << e.what(); } } -void ItkImageIO::Write(const BaseData* data, std::ostream& stream) -{ - AbstractFileWriter::Write(data, stream); -} - -AbstractFileIO::WriterConfidenceLevel ItkImageIO::GetWriterConfidenceLevel(const BaseData* data) const +AbstractFileIO::WriterConfidenceLevel ItkImageIO::GetWriterConfidenceLevel() const { // Check if the image dimension is supported - const Image* image = dynamic_cast(data); + const Image* image = dynamic_cast(this->GetInput()); if (image == NULL || !m_ImageIO->SupportsDimension(image->GetDimension())) { return IFileWriter::Unsupported; } // Check if geometry information will be lost if (image->GetDimension() == 2 && !image->GetGeometry()->Is2DConvertable()) { return IFileWriter::PartiallySupported; } return IFileWriter::Supported; } ItkImageIO* ItkImageIO::Clone() const { return new ItkImageIO(*this); } } diff --git a/Core/Code/Internal/mitkItkImageIO.h b/Core/Code/Internal/mitkItkImageIO.h index 24736212a3..2625d009ce 100644 --- a/Core/Code/Internal/mitkItkImageIO.h +++ b/Core/Code/Internal/mitkItkImageIO.h @@ -1,64 +1,61 @@ /*=================================================================== 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 MITKITKFILEIO_H #define MITKITKFILEIO_H #include "mitkAbstractFileIO.h" #include namespace mitk { // This class wraps ITK image IO objects registered via the // ITK object factory system class ItkImageIO : public AbstractFileIO { public: ItkImageIO(itk::ImageIOBase::Pointer imageIO); // -------------- AbstractFileReader ------------- using AbstractFileReader::Read; - virtual std::vector > Read(const std::string& path); - virtual std::vector > Read(std::istream& stream); + virtual std::vector > Read(); - virtual ReaderConfidenceLevel GetReaderConfidenceLevel(const std::string& path) const; + virtual ReaderConfidenceLevel GetReaderConfidenceLevel() const; // -------------- AbstractFileWriter ------------- - virtual void Write(const BaseData* data, const std::string& path); - virtual void Write(const BaseData* data, std::ostream& stream); - - virtual WriterConfidenceLevel GetWriterConfidenceLevel(const BaseData *data) const; + virtual void Write(); + virtual WriterConfidenceLevel GetWriterConfidenceLevel() const; private: ItkImageIO(const ItkImageIO& other); ItkImageIO* Clone() const; std::vector FixUpImageIOExtensions(const std::string& imageIOName); itk::ImageIOBase::Pointer m_ImageIO; }; } // namespace mitk #endif /* MITKITKFILEIO_H */ diff --git a/Core/Code/Internal/mitkLegacyFileReaderService.cpp b/Core/Code/Internal/mitkLegacyFileReaderService.cpp index 4065e5b409..a7cb3bab48 100644 --- a/Core/Code/Internal/mitkLegacyFileReaderService.cpp +++ b/Core/Code/Internal/mitkLegacyFileReaderService.cpp @@ -1,133 +1,129 @@ /*=================================================================== 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 "mitkLegacyFileReaderService.h" #include #include #include #include mitk::LegacyFileReaderService::LegacyFileReaderService(const mitk::LegacyFileReaderService& other) : mitk::AbstractFileReader(other) { } mitk::LegacyFileReaderService::LegacyFileReaderService(const std::vector& extensions, const std::string& category) : AbstractFileReader() { CustomMimeType customMimeType; customMimeType.SetCategory(category); for(std::vector::const_iterator iter = extensions.begin(), endIter = extensions.end(); iter != endIter; ++iter) { std::string extension = *iter; if (!extension.empty() && extension[0] == '.') { extension.assign(extension.begin()+1, extension.end()); } customMimeType.AddExtension(extension); } this->SetDescription(category); this->SetMimeType(customMimeType); m_ServiceReg = this->RegisterService(); } mitk::LegacyFileReaderService::~LegacyFileReaderService() { try { m_ServiceReg.Unregister(); } catch (const std::exception&) {} } ////////////////////// Reading ///////////////////////// -std::vector > mitk::LegacyFileReaderService::Read(std::istream& stream) -{ - return mitk::AbstractFileReader::Read(stream); -} - -std::vector > mitk::LegacyFileReaderService::Read(const std::string& path) +std::vector > mitk::LegacyFileReaderService::Read() { std::vector result; std::list possibleIOAdapter; std::list allobjects = itk::ObjectFactoryBase::CreateAllInstance("mitkIOAdapter"); for( std::list::iterator i = allobjects.begin(); i != allobjects.end(); ++i) { IOAdapterBase* io = dynamic_cast(i->GetPointer()); if(io) { possibleIOAdapter.push_back(io); } else { MITK_ERROR << "Error BaseDataIO factory did not return an IOAdapterBase: " << (*i)->GetNameOfClass() << std::endl; } } + const std::string path = this->GetLocalFileName(); for( std::list::iterator k = possibleIOAdapter.begin(); k != possibleIOAdapter.end(); ++k ) { bool canReadFile = (*k)->CanReadFile(path, "", ""); // they could read the file if( canReadFile ) { BaseProcess::Pointer ioObject = (*k)->CreateIOProcessObject(path, "", ""); ioObject->Update(); int numberOfContents = static_cast(ioObject->GetNumberOfOutputs()); if (numberOfContents > 0) { BaseData::Pointer baseData; for(int i=0; i(ioObject->GetOutputs()[i].GetPointer()); if (baseData) // this is what's wanted, right? { result.push_back( baseData ); } } } break; } } if (result.empty()) { mitkThrow() << "Could not read file '" << path << "'"; } return result; } mitk::LegacyFileReaderService* mitk::LegacyFileReaderService::Clone() const { return new LegacyFileReaderService(*this); } diff --git a/Core/Code/Internal/mitkLegacyFileReaderService.h b/Core/Code/Internal/mitkLegacyFileReaderService.h index 7dad5335c3..238ac555d8 100644 --- a/Core/Code/Internal/mitkLegacyFileReaderService.h +++ b/Core/Code/Internal/mitkLegacyFileReaderService.h @@ -1,51 +1,50 @@ /*=================================================================== 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 MITKLEGACYFILEREADERSERVICE_H #define MITKLEGACYFILEREADERSERVICE_H #include namespace mitk { // This class wraps mitk::FileReader instances registered as // "mitkIOAdapter" via the ITK object factory system as a // micro service. class LegacyFileReaderService : public mitk::AbstractFileReader { public: LegacyFileReaderService(const LegacyFileReaderService& other); LegacyFileReaderService(const std::vector& extensions, const std::string& category); virtual ~LegacyFileReaderService(); using AbstractFileReader::Read; - virtual std::vector > Read(const std::string& path); - virtual std::vector > Read(std::istream& stream); + virtual std::vector > Read(); private: LegacyFileReaderService* Clone() const; us::ServiceRegistration m_ServiceReg; }; } // namespace mitk #endif /* MITKLEGACYFILEREADERSERVICE_H */ diff --git a/Core/Code/Internal/mitkPointSetReaderService.cpp b/Core/Code/Internal/mitkPointSetReaderService.cpp index f74dbdb5ac..05096ee086 100644 --- a/Core/Code/Internal/mitkPointSetReaderService.cpp +++ b/Core/Code/Internal/mitkPointSetReaderService.cpp @@ -1,127 +1,129 @@ /*=================================================================== 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. ===================================================================*/ // MITK #include "mitkPointSetReaderService.h" #include "mitkCustomMimeType.h" // STL #include #include #include #include mitk::PointSetReaderService::PointSetReaderService() : AbstractFileReader(CustomMimeType("application/vnd.mitk.pointset"), "MITK Point Set Reader") { RegisterService(); } mitk::PointSetReaderService::~PointSetReaderService() {} -std::vector< itk::SmartPointer > mitk::PointSetReaderService::Read(std::istream& stream) +std::vector< itk::SmartPointer > mitk::PointSetReaderService::Read() { std::locale::global(std::locale("C")); std::vector< itk::SmartPointer > result; + InputStream stream(this); + TiXmlDocument doc; stream >> doc; if (!doc.Error()) { TiXmlHandle docHandle( &doc ); //unsigned int pointSetCounter(0); for( TiXmlElement* currentPointSetElement = docHandle.FirstChildElement("point_set_file").FirstChildElement("point_set").ToElement(); currentPointSetElement != NULL; currentPointSetElement = currentPointSetElement->NextSiblingElement()) { mitk::PointSet::Pointer newPointSet = mitk::PointSet::New(); if(currentPointSetElement->FirstChildElement("time_series") != NULL) { for( TiXmlElement* currentTimeSeries = currentPointSetElement->FirstChildElement("time_series")->ToElement(); currentTimeSeries != NULL; currentTimeSeries = currentTimeSeries->NextSiblingElement()) { unsigned int currentTimeStep(0); TiXmlElement* currentTimeSeriesID = currentTimeSeries->FirstChildElement("time_series_id"); currentTimeStep = atoi(currentTimeSeriesID->GetText()); newPointSet = this->ReadPoint(newPointSet, currentTimeSeries, currentTimeStep); } } else { newPointSet = this->ReadPoint(newPointSet, currentPointSetElement, 0); } result.push_back( newPointSet.GetPointer() ); } } else { mitkThrow() << "Parsing error at line " << doc.ErrorRow() << ", col " << doc.ErrorCol() << ": " << doc.ErrorDesc(); } return result; } mitk::PointSet::Pointer mitk::PointSetReaderService::ReadPoint(mitk::PointSet::Pointer newPointSet, TiXmlElement* currentTimeSeries, unsigned int currentTimeStep) { if(currentTimeSeries->FirstChildElement("point") != NULL) { for( TiXmlElement* currentPoint = currentTimeSeries->FirstChildElement("point")->ToElement(); currentPoint != NULL; currentPoint = currentPoint->NextSiblingElement()) { unsigned int id(0); mitk::PointSpecificationType spec((mitk::PointSpecificationType) 0); double x(0.0); double y(0.0); double z(0.0); id = atoi(currentPoint->FirstChildElement("id")->GetText()); if(currentPoint->FirstChildElement("specification") != NULL) { spec = (mitk::PointSpecificationType) atoi(currentPoint->FirstChildElement("specification")->GetText()); } x = atof(currentPoint->FirstChildElement("x")->GetText()); y = atof(currentPoint->FirstChildElement("y")->GetText()); z = atof(currentPoint->FirstChildElement("z")->GetText()); mitk::Point3D point; mitk::FillVector3D(point, x, y, z); newPointSet->SetPoint(id, point, spec, currentTimeStep); } } else { if(currentTimeStep != newPointSet->GetTimeSteps()+1) { newPointSet->Expand(currentTimeStep+1); // expand time step series with empty time step } } return newPointSet; } mitk::PointSetReaderService::PointSetReaderService(const mitk::PointSetReaderService& other) : mitk::AbstractFileReader(other) { } mitk::PointSetReaderService* mitk::PointSetReaderService::Clone() const { return new mitk::PointSetReaderService(*this); } diff --git a/Core/Code/Internal/mitkPointSetReaderService.h b/Core/Code/Internal/mitkPointSetReaderService.h index cde707ee40..cfa4530b8d 100644 --- a/Core/Code/Internal/mitkPointSetReaderService.h +++ b/Core/Code/Internal/mitkPointSetReaderService.h @@ -1,63 +1,62 @@ /*=================================================================== 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_POINT_SET_READER_SERVICE__H_ #define _MITK_POINT_SET_READER_SERVICE__H_ // MITK #include #include class TiXmlElement; namespace mitk { /** * @brief reads xml representations of mitk::PointSets from a file * * Reader for xml files containing one or multiple xml represenations of * mitk::PointSet. If multiple mitk::PointSet objects are stored in one file, * these are assigned to multiple BaseData objects. * * The reader is able to read the old 3D Pointsets without the "specification" and "timeseries" tags and the new 4D Pointsets. * * @ingroup IO */ class PointSetReaderService: public AbstractFileReader { public: PointSetReaderService(); virtual ~PointSetReaderService(); using AbstractFileReader::Read; - - virtual std::vector< itk::SmartPointer > Read(std::istream& stream); + virtual std::vector< itk::SmartPointer > Read(); private: PointSetReaderService(const PointSetReaderService& other); mitk::PointSet::Pointer ReadPoint(mitk::PointSet::Pointer newPointSet, TiXmlElement* currentTimeSeries, unsigned int currentTimeStep); virtual PointSetReaderService* Clone() const; }; } #endif diff --git a/Core/Code/Internal/mitkPointSetWriterService.cpp b/Core/Code/Internal/mitkPointSetWriterService.cpp index d035bbe8c7..1188cc938f 100644 --- a/Core/Code/Internal/mitkPointSetWriterService.cpp +++ b/Core/Code/Internal/mitkPointSetWriterService.cpp @@ -1,190 +1,192 @@ /*=================================================================== 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 "mitkPointSetWriterService.h" #include "mitkCustomMimeType.h" #include #include #include // // Initialization of the xml tags. // const std::string mitk::PointSetWriterService::XML_POINT_SET_FILE = "point_set_file" ; const std::string mitk::PointSetWriterService::XML_FILE_VERSION = "file_version" ; const std::string mitk::PointSetWriterService::XML_POINT_SET = "point_set" ; const std::string mitk::PointSetWriterService::XML_TIME_SERIES = "time_series"; const std::string mitk::PointSetWriterService::XML_TIME_SERIES_ID = "time_series_id"; const std::string mitk::PointSetWriterService::XML_POINT = "point" ; const std::string mitk::PointSetWriterService::XML_ID = "id" ; const std::string mitk::PointSetWriterService::XML_SPEC = "specification" ; const std::string mitk::PointSetWriterService::XML_X = "x" ; const std::string mitk::PointSetWriterService::XML_Y = "y" ; const std::string mitk::PointSetWriterService::XML_Z = "z" ; const std::string mitk::PointSetWriterService::VERSION_STRING = "0.1" ; mitk::PointSetWriterService::PointSetWriterService() : AbstractFileWriter(PointSet::GetStaticNameOfClass(), CustomMimeType("application/vnd.mitk.pointset"), "MITK Point Set Writer") , m_IndentDepth(0) , m_Indent(2) { RegisterService(); } mitk::PointSetWriterService::PointSetWriterService(const mitk::PointSetWriterService& other) : AbstractFileWriter(other) , m_IndentDepth(other.m_IndentDepth) , m_Indent(other.m_Indent) { } mitk::PointSetWriterService::~PointSetWriterService() {} -void mitk::PointSetWriterService::Write( const BaseData* baseData, std::ostream& out ) +void mitk::PointSetWriterService::Write() { + OutputStream out(this); + if ( !out.good() ) { mitkThrow() << "Stream not good."; } std::locale previousLocale(out.getloc()); std::locale I("C"); out.imbue(I); // // Here the actual xml writing begins // WriteXMLHeader( out ); WriteStartElement( XML_POINT_SET_FILE, out ); WriteStartElement( XML_FILE_VERSION, out ); out << VERSION_STRING; WriteEndElement( XML_FILE_VERSION, out, false ); - WriteXML( static_cast(baseData), out ); + WriteXML( static_cast(this->GetInput()), out ); WriteEndElement( XML_POINT_SET_FILE, out ); out.imbue(previousLocale); if ( !out.good() ) // some error during output { mitkThrow() << "Some error during point set writing."; } } mitk::PointSetWriterService*mitk::PointSetWriterService::Clone() const { return new PointSetWriterService(*this); } void mitk::PointSetWriterService::WriteXML( const mitk::PointSet* pointSet, std::ostream& out ) { WriteStartElement( XML_POINT_SET, out ); unsigned int timecount = pointSet->GetTimeSteps(); for(unsigned int i=0; i< timecount; i++) { WriteStartElement( XML_TIME_SERIES, out ); WriteStartElement( XML_TIME_SERIES_ID, out ); out << ConvertToString( i ); WriteEndElement( XML_TIME_SERIES_ID, out, false ); mitk::PointSet::PointsContainer* pointsContainer = pointSet->GetPointSet(i)->GetPoints(); mitk::PointSet::PointsContainer::Iterator it; for ( it = pointsContainer->Begin(); it != pointsContainer->End(); ++it ) { WriteStartElement( XML_POINT, out ); WriteStartElement( XML_ID, out ); out << ConvertToString( it->Index() ); WriteEndElement( XML_ID, out, false ); mitk::PointSet::PointType point = it->Value(); WriteStartElement( XML_SPEC, out ); out << ConvertToString( pointSet->GetSpecificationTypeInfo(it->Index(), i) ); WriteEndElement( XML_SPEC, out, false ); WriteStartElement( XML_X, out ); out << ConvertToString( point[ 0 ] ); WriteEndElement( XML_X, out, false ); WriteStartElement( XML_Y, out ); out << ConvertToString( point[ 1 ] ); WriteEndElement( XML_Y, out, false ); WriteStartElement( XML_Z, out ); out << ConvertToString( point[ 2 ] ); WriteEndElement( XML_Z, out, false ); WriteEndElement( XML_POINT, out ); } WriteEndElement( XML_TIME_SERIES, out ); } WriteEndElement( XML_POINT_SET, out ); } template < typename T> std::string mitk::PointSetWriterService::ConvertToString( T value ) { std::ostringstream o; std::locale I("C"); o.imbue(I); if ( o << value ) { return o.str(); } else { return "conversion error"; } } void mitk::PointSetWriterService::WriteXMLHeader( std::ostream &file ) { file << ""; } void mitk::PointSetWriterService::WriteStartElement( const std::string& tag, std::ostream &file ) { file << std::endl; WriteIndent( file ); file << '<' << tag << '>'; m_IndentDepth++; } void mitk::PointSetWriterService::WriteEndElement( const std::string& tag, std::ostream &file, const bool& indent ) { m_IndentDepth--; if ( indent ) { file << std::endl; WriteIndent( file ); } file << '<' << '/' << tag << '>'; } void mitk::PointSetWriterService::WriteIndent( std::ostream& file ) { std::string spaces( m_IndentDepth * m_Indent, ' ' ); file << spaces; } diff --git a/Core/Code/Internal/mitkPointSetWriterService.h b/Core/Code/Internal/mitkPointSetWriterService.h index c217723519..53a676da99 100644 --- a/Core/Code/Internal/mitkPointSetWriterService.h +++ b/Core/Code/Internal/mitkPointSetWriterService.h @@ -1,110 +1,110 @@ /*=================================================================== 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_POINT_SET_WRITER_SERVICE__H_ #define _MITK_POINT_SET_WRITER_SERVICE__H_ #include #include namespace mitk { /** * @brief XML-based writer for mitk::PointSets * * XML-based writer for mitk::PointSet. Multiple PointSets can be written in * a single XML file by simply setting multiple inputs to the filter. * * @ingroup IO */ class PointSetWriterService : public AbstractFileWriter { public: PointSetWriterService(); virtual ~PointSetWriterService(); using AbstractFileWriter::Write; - virtual void Write(const BaseData* data, std::ostream& stream ); + virtual void Write(); private: PointSetWriterService(const PointSetWriterService& other); virtual mitk::PointSetWriterService* Clone() const; /** * Converts an arbitrary type to a string. The type has to * support the << operator. This works fine at least for integral * data types as float, int, long etc. * @param value the value to convert * @returns the string representation of value */ template < typename T> std::string ConvertToString( T value ); /** * Writes an XML representation of the given point set to * an outstream. The XML-Header an root node is not included! * @param pointSet the point set to be converted to xml * @param out the stream to write to. */ void WriteXML( const mitk::PointSet* pointSet, std::ostream& out ); /** * Writes an standard xml header to the given stream. * @param file the stream in which the header is written. */ void WriteXMLHeader( std::ostream &file ); /** * Write an end element tag * End-Elements following character data should pass indent = false. */ void WriteEndElement( const std::string& tag, std::ostream &file, const bool& indent = true ); /** Write a start element tag */ void WriteStartElement( const std::string &tag, std::ostream &file ); /** Write character data inside a tag. */ void WriteCharacterData( const std::string &data, std::ostream &file ); /** Writes empty spaces to the stream according to m_IndentDepth and m_Indent */ void WriteIndent( std::ostream& file ); unsigned int m_IndentDepth; const unsigned int m_Indent; static const std::string XML_POINT_SET; static const std::string XML_TIME_SERIES; static const std::string XML_TIME_SERIES_ID; static const std::string XML_POINT_SET_FILE; static const std::string XML_FILE_VERSION; static const std::string XML_POINT; static const std::string XML_SPEC; static const std::string XML_ID; static const std::string XML_X; static const std::string XML_Y; static const std::string XML_Z; static const std::string VERSION_STRING; }; } #endif diff --git a/Core/Code/Internal/mitkRawImageFileReader.cpp b/Core/Code/Internal/mitkRawImageFileReader.cpp index c9167e0b8d..cc2929554b 100644 --- a/Core/Code/Internal/mitkRawImageFileReader.cpp +++ b/Core/Code/Internal/mitkRawImageFileReader.cpp @@ -1,184 +1,181 @@ /*=================================================================== 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 "mitkRawImageFileReader.h" #include "mitkITKImageImport.h" #include "mitkImageCast.h" #include "mitkIOConstants.h" #include #include #include mitk::RawImageFileReader::RawImageFileReader() : AbstractFileReader("raw", "ITK raw image reader") { Options defaultOptions; defaultOptions[IOConstants::PIXEL_TYPE()] = IOConstants::PIXEL_TYPE_USHORT(); std::vector pixelEnum; pixelEnum.push_back(IOConstants::PIXEL_TYPE_UCHAR()); pixelEnum.push_back(IOConstants::PIXEL_TYPE_CHAR()); pixelEnum.push_back(IOConstants::PIXEL_TYPE_USHORT()); pixelEnum.push_back(IOConstants::PIXEL_TYPE_SHORT()); pixelEnum.push_back(IOConstants::PIXEL_TYPE_UINT()); pixelEnum.push_back(IOConstants::PIXEL_TYPE_INT()); pixelEnum.push_back(IOConstants::PIXEL_TYPE_FLOAT()); pixelEnum.push_back(IOConstants::PIXEL_TYPE_DOUBLE()); defaultOptions[IOConstants::PIXEL_TYPE_ENUM()] = pixelEnum; defaultOptions[IOConstants::DIMENSION()] = std::string("3"); std::vector dimEnum; dimEnum.push_back("2"); dimEnum.push_back("3"); defaultOptions[IOConstants::DIMENSION_ENUM()] = dimEnum; defaultOptions[IOConstants::ENDIANNESS()] = IOConstants::ENDIANNESS_LITTLE(); std::vector endianEnum; endianEnum.push_back(IOConstants::ENDIANNESS_LITTLE()); endianEnum.push_back(IOConstants::ENDIANNESS_BIG()); defaultOptions[IOConstants::ENDIANNESS_ENUM()] = endianEnum; defaultOptions[IOConstants::SIZE_X()] = 0; defaultOptions[IOConstants::SIZE_Y()] = 0; defaultOptions[IOConstants::SIZE_Z()] = 0; //defaultOptions[IOConstants::SIZE_T()] = 0; this->SetDefaultOptions(defaultOptions); this->RegisterService(); } mitk::RawImageFileReader::RawImageFileReader(const mitk::RawImageFileReader& other) : AbstractFileReader(other) { } -std::vector > mitk::RawImageFileReader::Read(const std::string& path) +std::vector > mitk::RawImageFileReader::Read() { std::vector result; + const std::string path = this->GetLocalFileName(); + const Options options = this->GetOptions(); const std::string dimensionality = options.find(IOConstants::DIMENSION())->second.ToString(); const std::string pixelType = options.find(IOConstants::PIXEL_TYPE())->second.ToString(); EndianityType endianity = options.find(IOConstants::ENDIANNESS())->second.ToString() == IOConstants::ENDIANNESS_LITTLE() ? LITTLE : BIG; int dimensions[4]; dimensions[0] = us::any_cast(options.find(IOConstants::SIZE_X())->second); dimensions[1] = us::any_cast(options.find(IOConstants::SIZE_Y())->second); dimensions[2] = us::any_cast(options.find(IOConstants::SIZE_Z())->second); dimensions[3] = 0 ;//us::any_cast(options.find(IOConstants::SIZE_T())->second); // check file dimensionality and pixel type and perform reading according to it if (dimensionality == "2") { if (pixelType == IOConstants::PIXEL_TYPE_CHAR()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_UCHAR()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_SHORT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_USHORT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_UINT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_INT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_FLOAT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_DOUBLE())result.push_back(TypedRead(path, endianity, dimensions)); else { MITK_INFO << "Error while reading raw file: Dimensionality or pixel type not supported or not properly set" << std::endl; } } else if (dimensionality == "3") { if (pixelType == IOConstants::PIXEL_TYPE_CHAR()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_UCHAR()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_SHORT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_USHORT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_UINT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_INT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_FLOAT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_DOUBLE()) result.push_back(TypedRead(path, endianity, dimensions)); else { MITK_INFO << "Error while reading raw file: Dimensionality or pixel type not supported or not properly set" << std::endl; } } else { MITK_INFO << "Error while reading raw file: Dimensionality not supported" << std::endl; } return result; } template < typename TPixel, unsigned int VImageDimensions > mitk::BaseData::Pointer mitk::RawImageFileReader::TypedRead(const std::string& path, EndianityType endianity, int* size) { typedef itk::Image< TPixel, VImageDimensions > ImageType; typedef itk::ImageFileReader< ImageType > ReaderType; typedef itk::RawImageIO< TPixel, VImageDimensions > IOType; typename ReaderType::Pointer reader = ReaderType::New(); typename IOType::Pointer io = IOType::New(); io->SetFileDimensionality(VImageDimensions); for (unsigned short int dim = 0; dim < VImageDimensions; ++dim) { io->SetDimensions(dim, size[dim] ); } if (endianity == LITTLE) { io->SetByteOrderToLittleEndian(); } else if (endianity == BIG) { io->SetByteOrderToBigEndian(); } else { MITK_INFO << "Warning: endianity not properly set. Resulting image might be incorrect"; } reader->SetImageIO( io ); reader->SetFileName(path); try { reader->Update(); } catch( itk::ExceptionObject & err ) { MITK_ERROR <<"An error occurred during the raw image reading process: "; MITK_INFO << err << std::endl; } mitk::Image::Pointer image = mitk::Image::New(); mitk::CastToMitkImage(reader->GetOutput(), image); image->SetVolume( reader->GetOutput()->GetBufferPointer()); return image.GetPointer(); } -std::vector > mitk::RawImageFileReader::Read(std::istream& stream) -{ - return AbstractFileReader::Read(stream); -} - mitk::RawImageFileReader*mitk::RawImageFileReader::Clone() const { return new RawImageFileReader(*this); } diff --git a/Core/Code/Internal/mitkRawImageFileReader.h b/Core/Code/Internal/mitkRawImageFileReader.h index 9a702e4735..01e0780430 100644 --- a/Core/Code/Internal/mitkRawImageFileReader.h +++ b/Core/Code/Internal/mitkRawImageFileReader.h @@ -1,75 +1,74 @@ /*=================================================================== 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 MITKRAWIMAGEFILEREADER_H_ #define MITKRAWIMAGEFILEREADER_H_ #include "mitkAbstractFileReader.h" namespace mitk { /** * The user must set the dimensionality, the dimensions and the pixel type. * If they are incorrect, the image will not be opened or the visualization will be incorrect. */ class RawImageFileReader : public AbstractFileReader { public: /** Supported pixel types. */ typedef enum {UCHAR,SCHAR,USHORT,SSHORT, UINT, SINT, FLOAT, DOUBLE} IOPixelType; /** Endianity of bits. */ typedef enum {LITTLE, BIG} EndianityType; RawImageFileReader(); protected: RawImageFileReader(const RawImageFileReader& other); - virtual std::vector > Read(const std::string &path); - virtual std::vector > Read(std::istream& stream); + virtual std::vector > Read(); using mitk::AbstractFileReader::Read; private: template mitk::BaseData::Pointer TypedRead(const std::string& path, EndianityType endianity, int* size); RawImageFileReader* Clone() const; /** Pixel type of image to be read. Must be of type IOPixelType. */ IOPixelType m_PixelType; /** Dimensionality of file to be read. Can be 2 or 3. */ int m_Dimensionality; /** Endianity. Must be set to LITTLE or BIG. Default is BIG. */ EndianityType m_Endianity; /** Vector containing dimensions of image to be read. */ itk::Vector m_Dimensions; }; } // namespace mitk #endif /* MITKRAWIMAGEFILEREADER_H_ */