00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <Poco/TemporaryFile.h>
00019 #include <Poco/Path.h>
00020 #include <Poco/Delegate.h>
00021 #include <Poco/Zip/Compress.h>
00022 #include <Poco/Zip/Decompress.h>
00023
00024 #include "mitkSceneIO.h"
00025 #include "mitkBaseDataSerializer.h"
00026 #include "mitkPropertyListSerializer.h"
00027 #include "mitkSceneReader.h"
00028
00029 #include "mitkProgressBar.h"
00030 #include "mitkBaseRenderer.h"
00031 #include "mitkRenderingManager.h"
00032 #include "mitkStandaloneDataStorage.h"
00033
00034 #include <itkObjectFactoryBase.h>
00035
00036 #include <tinyxml.h>
00037
00038 #include <fstream>
00039 #include <sstream>
00040
00041 #include "itksys/SystemTools.hxx"
00042
00043 mitk::SceneIO::SceneIO()
00044 :m_WorkingDirectory(""),
00045 m_UnzipErrors(0)
00046 {
00047 }
00048
00049 mitk::SceneIO::~SceneIO()
00050 {
00051 }
00052
00053 std::string mitk::SceneIO::CreateEmptyTempDirectory()
00054 {
00055 std::string uniquename = Poco::TemporaryFile::tempName();
00056 Poco::File tempdir( uniquename );
00057 try
00058 {
00059 if (!tempdir.createDirectory())
00060 {
00061 MITK_ERROR << "Could not create temporary directory " << uniquename;
00062 return "";
00063 }
00064 }
00065 catch( std::exception& e )
00066 {
00067 MITK_ERROR << "Could not create temporary directory " << uniquename << ":" << e.what();
00068 return "";
00069 }
00070
00071 return uniquename;
00072 }
00073
00074 mitk::DataStorage::Pointer mitk::SceneIO::LoadScene( const std::string& filename,
00075 DataStorage* pStorage,
00076 bool clearStorageFirst )
00077 {
00078
00079 DataStorage::Pointer storage = pStorage;
00080 if ( storage.IsNull() )
00081 {
00082 storage = StandaloneDataStorage::New().GetPointer();
00083 }
00084
00085 if ( clearStorageFirst )
00086 {
00087 try
00088 {
00089 storage->Remove( storage->GetAll() );
00090 }
00091 catch(...)
00092 {
00093 MITK_ERROR << "DataStorage cannot be cleared properly.";
00094 }
00095 }
00096
00097
00098 if ( filename.empty() )
00099 {
00100 MITK_ERROR << "No filename given. Not possible to load scene.";
00101 return NULL;
00102 }
00103
00104
00105 std::ifstream file( filename.c_str(), std::ios::binary );
00106 if (!file.good())
00107 {
00108 MITK_ERROR << "Cannot open '" << filename << "' for reading";
00109 return NULL;
00110 }
00111
00112
00113 m_WorkingDirectory = CreateEmptyTempDirectory();
00114 if (m_WorkingDirectory.empty())
00115 {
00116 MITK_ERROR << "Could not create temporary directory. Cannot open scene files.";
00117 return NULL;
00118 }
00119
00120
00121 m_UnzipErrors = 0;
00122 Poco::Zip::Decompress unzipper( file, Poco::Path( m_WorkingDirectory ) );
00123 unzipper.EError += Poco::Delegate<SceneIO, std::pair<const Poco::Zip::ZipLocalFileHeader, const std::string> >(this, &SceneIO::OnUnzipError);
00124 unzipper.EOk += Poco::Delegate<SceneIO, std::pair<const Poco::Zip::ZipLocalFileHeader, const Poco::Path> >(this, &SceneIO::OnUnzipOk);
00125 unzipper.decompressAllFiles();
00126 unzipper.EError -= Poco::Delegate<SceneIO, std::pair<const Poco::Zip::ZipLocalFileHeader, const std::string> >(this, &SceneIO::OnUnzipError);
00127 unzipper.EOk -= Poco::Delegate<SceneIO, std::pair<const Poco::Zip::ZipLocalFileHeader, const Poco::Path> >(this, &SceneIO::OnUnzipOk);
00128
00129 if ( m_UnzipErrors )
00130 {
00131 MITK_ERROR << "There were " << m_UnzipErrors << " errors unzipping '" << filename << "'. Will attempt to read whatever could be unzipped.";
00132 }
00133
00134
00135
00136 TiXmlDocument document( m_WorkingDirectory + Poco::Path::separator() + "index.xml" );
00137 if (!document.LoadFile())
00138 {
00139 MITK_ERROR << "Could not open/read/parse " << m_WorkingDirectory << "/index.xml\nTinyXML reports: " << document.ErrorDesc() << std::endl;
00140 return NULL;
00141 }
00142
00143 SceneReader::Pointer reader = SceneReader::New();
00144 if ( !reader->LoadScene( document, m_WorkingDirectory, storage ) )
00145 {
00146 MITK_ERROR << "There were errors while loding scene file " << filename << ". Your data may be corrupted";
00147 }
00148
00149
00150 try
00151 {
00152 Poco::File deleteDir( m_WorkingDirectory );
00153 deleteDir.remove(true);
00154 }
00155 catch(...)
00156 {
00157 MITK_ERROR << "Could not delete temporary directory " << m_WorkingDirectory;
00158 }
00159
00160
00161 return storage;
00162
00163 }
00164
00165 bool mitk::SceneIO::SaveScene( DataStorage::SetOfObjects::ConstPointer sceneNodes, const DataStorage* storage,
00166 const std::string& filename)
00167 {
00168 if (!sceneNodes)
00169 {
00170 MITK_ERROR << "No set of nodes given. Not possible to save scene.";
00171 return false;
00172 }
00173 if (!storage)
00174 {
00175 MITK_ERROR << "No data storage given. Not possible to save scene.";
00176 return false;
00177 }
00178
00179 if ( filename.empty() )
00180 {
00181 MITK_ERROR << "No filename given. Not possible to save scene.";
00182 return false;
00183 }
00184
00185 try
00186 {
00187
00188 m_FailedNodes = DataStorage::SetOfObjects::New();
00189 m_FailedProperties = PropertyList::New();
00190
00191
00192 TiXmlDocument document;
00193 TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "UTF-8", "" );
00194 document.LinkEndChild( decl );
00195
00196 TiXmlElement* version = new TiXmlElement("Version");
00197 version->SetAttribute("Writer", __FILE__ );
00198 version->SetAttribute("Revision", "$Revision: 17055 $" );
00199 version->SetAttribute("FileVersion", 1 );
00200 document.LinkEndChild(version);
00201
00202
00203
00204 if ( sceneNodes.IsNull() )
00205 {
00206 MITK_WARN << "Saving empty scene to " << filename;
00207 }
00208 else
00209 {
00210 if ( sceneNodes->size() == 0 )
00211 {
00212 MITK_WARN << "Saving empty scene to " << filename;
00213 }
00214
00215 MITK_INFO << "Storing scene with " << sceneNodes->size() << " objects to " << filename;
00216
00217 m_WorkingDirectory = CreateEmptyTempDirectory();
00218 if (m_WorkingDirectory.empty())
00219 {
00220 MITK_ERROR << "Could not create temporary directory. Cannot create scene files.";
00221 return false;
00222 }
00223
00224 ProgressBar::GetInstance()->AddStepsToDo( sceneNodes->size() );
00225
00226
00227 typedef std::map< DataNode*, std::string > UIDMapType;
00228 typedef std::map< DataNode*, std::list<std::string> > SourcesMapType;
00229
00230 UIDMapType nodeUIDs;
00231 SourcesMapType sourceUIDs;
00232
00233 UIDGenerator nodeUIDGen("OBJECT_");
00234
00235 for (DataStorage::SetOfObjects::const_iterator iter = sceneNodes->begin();
00236 iter != sceneNodes->end();
00237 ++iter)
00238 {
00239 DataNode* node = iter->GetPointer();
00240 if (!node)
00241 continue;
00242
00243
00244 DataStorage::SetOfObjects::ConstPointer sourceObjects = storage->GetSources( node );
00245 for ( mitk::DataStorage::SetOfObjects::const_iterator sourceIter = sourceObjects->begin();
00246 sourceIter != sourceObjects->end();
00247 ++sourceIter )
00248 {
00249 if ( std::find( sceneNodes->begin(), sceneNodes->end(), *sourceIter ) == sceneNodes->end() )
00250 continue;
00251
00252
00253 if ( nodeUIDs[ *sourceIter ].empty() )
00254 {
00255 nodeUIDs[ *sourceIter ] = nodeUIDGen.GetUID();
00256 }
00257
00258
00259 sourceUIDs[ node ].push_back( nodeUIDs[*sourceIter] );
00260 }
00261
00262 if ( nodeUIDs[ node ].empty() )
00263 {
00264 nodeUIDs[ node ] = nodeUIDGen.GetUID();
00265 }
00266 }
00267
00268
00269 for (DataStorage::SetOfObjects::const_iterator iter = sceneNodes->begin();
00270 iter != sceneNodes->end();
00271 ++iter)
00272 {
00273 DataNode* node = iter->GetPointer();
00274
00275 if (node)
00276 {
00277 TiXmlElement* nodeElement = new TiXmlElement("node");
00278 std::string filenameHint( node->GetName() );
00279 filenameHint = itksys::SystemTools::MakeCindentifier(filenameHint.c_str());
00280
00281
00282 UIDMapType::iterator searchUIDIter = nodeUIDs.find(node);
00283 if ( searchUIDIter != nodeUIDs.end() )
00284 {
00285
00286 nodeElement->SetAttribute("UID", searchUIDIter->second.c_str() );
00287 }
00288
00289 SourcesMapType::iterator searchSourcesIter = sourceUIDs.find(node);
00290 if ( searchSourcesIter != sourceUIDs.end() )
00291 {
00292
00293 for ( std::list<std::string>::iterator sourceUIDIter = searchSourcesIter->second.begin();
00294 sourceUIDIter != searchSourcesIter->second.end();
00295 ++sourceUIDIter )
00296 {
00297 TiXmlElement* uidElement = new TiXmlElement("source");
00298 uidElement->SetAttribute("UID", sourceUIDIter->c_str() );
00299 nodeElement->LinkEndChild( uidElement );
00300 }
00301 }
00302
00303
00304 if ( BaseData* data = node->GetData() )
00305 {
00306
00307 bool error(false);
00308 TiXmlElement* dataElement( SaveBaseData( data, filenameHint, error ) );
00309 if (error)
00310 {
00311 m_FailedNodes->push_back( node );
00312 }
00313
00314
00315 PropertyList* propertyList = data->GetPropertyList();
00316 if (propertyList && !propertyList->IsEmpty() )
00317 {
00318 TiXmlElement* baseDataPropertiesElement( SavePropertyList( propertyList, filenameHint + "-data") );
00319 dataElement->LinkEndChild( baseDataPropertiesElement );
00320 }
00321
00322 nodeElement->LinkEndChild( dataElement );
00323 }
00324
00325
00326 const RenderingManager::RenderWindowVector& allRenderWindows( RenderingManager::GetInstance()->GetAllRegisteredRenderWindows() );
00327 for ( RenderingManager::RenderWindowVector::const_iterator rw = allRenderWindows.begin();
00328 rw != allRenderWindows.end();
00329 ++rw)
00330 {
00331 if (vtkRenderWindow* renderWindow = *rw)
00332 {
00333 std::string renderWindowName( mitk::BaseRenderer::GetInstance(renderWindow)->GetName() );
00334 BaseRenderer* renderer = mitk::BaseRenderer::GetInstance(renderWindow);
00335 PropertyList* propertyList = node->GetPropertyList(renderer);
00336 if ( propertyList && !propertyList->IsEmpty() )
00337 {
00338 TiXmlElement* renderWindowPropertiesElement( SavePropertyList( propertyList, filenameHint + "-" + renderWindowName) );
00339 renderWindowPropertiesElement->SetAttribute("renderwindow", renderWindowName);
00340 nodeElement->LinkEndChild( renderWindowPropertiesElement );
00341 }
00342 }
00343 }
00344
00345
00346 PropertyList* propertyList = node->GetPropertyList();
00347 if ( propertyList && !propertyList->IsEmpty() )
00348 {
00349 TiXmlElement* propertiesElement( SavePropertyList( propertyList, filenameHint + "-node") );
00350 nodeElement->LinkEndChild( propertiesElement );
00351 }
00352 document.LinkEndChild( nodeElement );
00353 }
00354 else
00355 {
00356 MITK_WARN << "Ignoring NULL node during scene serialization.";
00357 }
00358
00359 ProgressBar::GetInstance()->Progress();
00360 }
00361
00362 }
00363
00364 if ( !document.SaveFile( m_WorkingDirectory + Poco::Path::separator() + "index.xml" ) )
00365 {
00366 MITK_ERROR << "Could not write scene to " << m_WorkingDirectory << Poco::Path::separator() << "index.xml" << "\nTinyXML reports '" << document.ErrorDesc() << "'";
00367 return false;
00368 }
00369 else
00370 {
00371 try
00372 {
00373 Poco::File deleteFile( filename.c_str() );
00374 if (deleteFile.exists())
00375 {
00376 deleteFile.remove();
00377 }
00378
00379
00380 std::ofstream file( filename.c_str(), std::ios::binary | std::ios::out);
00381 if (!file.good())
00382 {
00383 MITK_ERROR << "Could not open a zip file for writing: '" << filename << "'";
00384 }
00385 else
00386 {
00387 Poco::Zip::Compress zipper( file, true );
00388 Poco::Path tmpdir( m_WorkingDirectory );
00389 zipper.addRecursive( tmpdir );
00390 zipper.close();
00391 }
00392 try
00393 {
00394 Poco::File deleteDir( m_WorkingDirectory );
00395 deleteDir.remove(true);
00396 }
00397 catch(...)
00398 {
00399 MITK_ERROR << "Could not delete temporary directory " << m_WorkingDirectory;
00400 return false;
00401 }
00402 }
00403 catch(std::exception& e)
00404 {
00405 MITK_ERROR << "Could not create ZIP file from " << m_WorkingDirectory << "\nReason: " << e.what();
00406 return false;
00407 }
00408 return true;
00409 }
00410 }
00411 catch(std::exception& e)
00412 {
00413 MITK_ERROR << "Caught exception during saving temporary files to disk. Error description: '" << e.what() << "'";
00414 return false;
00415 }
00416 }
00417
00418
00419 TiXmlElement* mitk::SceneIO::SaveBaseData( BaseData* data, const std::string& filenamehint, bool& error )
00420 {
00421 assert(data);
00422 error = true;
00423
00424
00425
00426
00427
00428 TiXmlElement* element = new TiXmlElement("data");
00429 element->SetAttribute( "type", data->GetNameOfClass() );
00430
00431
00432 std::string serializername(data->GetNameOfClass());
00433 serializername += "Serializer";
00434
00435 std::list<itk::LightObject::Pointer> thingsThatCanSerializeThis = itk::ObjectFactoryBase::CreateAllInstance(serializername.c_str());
00436 if (thingsThatCanSerializeThis.size() < 1)
00437 {
00438 MITK_ERROR << "No serializer found for " << data->GetNameOfClass() << ". Skipping object";
00439 }
00440
00441 for ( std::list<itk::LightObject::Pointer>::iterator iter = thingsThatCanSerializeThis.begin();
00442 iter != thingsThatCanSerializeThis.end();
00443 ++iter )
00444 {
00445 if (BaseDataSerializer* serializer = dynamic_cast<BaseDataSerializer*>( iter->GetPointer() ) )
00446 {
00447 serializer->SetData(data);
00448 serializer->SetFilenameHint(filenamehint);
00449 serializer->SetWorkingDirectory( m_WorkingDirectory );
00450 try
00451 {
00452 std::string writtenfilename = serializer->Serialize();
00453 element->SetAttribute("file", writtenfilename);
00454 error = false;
00455 }
00456 catch (std::exception& e)
00457 {
00458 MITK_ERROR << "Serializer " << serializer->GetNameOfClass() << " failed: " << e.what();
00459 }
00460 break;
00461 }
00462 }
00463
00464 return element;
00465 }
00466
00467 TiXmlElement* mitk::SceneIO::SavePropertyList( PropertyList* propertyList, const std::string& filenamehint)
00468 {
00469 assert(propertyList);
00470
00471
00472 TiXmlElement* element = new TiXmlElement("properties");
00473
00474
00475 PropertyListSerializer::Pointer serializer = PropertyListSerializer::New();
00476
00477 serializer->SetPropertyList(propertyList);
00478 serializer->SetFilenameHint(filenamehint);
00479 serializer->SetWorkingDirectory( m_WorkingDirectory );
00480 try
00481 {
00482 std::string writtenfilename = serializer->Serialize();
00483 element->SetAttribute("file", writtenfilename);
00484 PropertyList::Pointer failedProperties = serializer->GetFailedProperties();
00485 if (failedProperties.IsNotNull())
00486 {
00487
00488 m_FailedProperties->ConcatenatePropertyList( failedProperties, true );
00489 }
00490 }
00491 catch (std::exception& e)
00492 {
00493 MITK_ERROR << "Serializer " << serializer->GetNameOfClass() << " failed: " << e.what();
00494 }
00495
00496 return element;
00497 }
00498
00499
00500 const mitk::SceneIO::FailedBaseDataListType* mitk::SceneIO::GetFailedNodes()
00501 {
00502 return m_FailedNodes.GetPointer();
00503 }
00504
00505 const mitk::PropertyList* mitk::SceneIO::GetFailedProperties()
00506 {
00507 return m_FailedProperties;
00508 }
00509
00510 void mitk::SceneIO::OnUnzipError(const void* , std::pair<const Poco::Zip::ZipLocalFileHeader, const std::string>& info)
00511 {
00512 ++m_UnzipErrors;
00513 MITK_ERROR << "Error while unzipping: " << info.second;
00514 }
00515
00516 void mitk::SceneIO::OnUnzipOk(const void* , std::pair<const Poco::Zip::ZipLocalFileHeader, const Poco::Path>& )
00517 {
00518
00519 }