Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
mitkItkImageIO.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
13 #include "mitkItkImageIO.h"
14 
16 #include <mitkCoreServices.h>
17 #include <mitkCustomMimeType.h>
18 #include <mitkIOMimeTypes.h>
20 #include <mitkImage.h>
21 #include <mitkImageReadAccessor.h>
22 #include <mitkLocaleSwitch.h>
23 
24 #include <itkImage.h>
25 #include <itkImageFileReader.h>
26 #include <itkImageIOFactory.h>
27 #include <itkImageIORegion.h>
28 #include <itkMetaDataObject.h>
29 
30 #include <algorithm>
31 
32 namespace mitk
33 {
34  const char *const PROPERTY_NAME_TIMEGEOMETRY_TYPE = "org.mitk.timegeometry.type";
35  const char *const PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS = "org.mitk.timegeometry.timepoints";
36  const char *const PROPERTY_KEY_TIMEGEOMETRY_TYPE = "org_mitk_timegeometry_type";
37  const char *const PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS = "org_mitk_timegeometry_timepoints";
38 
40  : AbstractFileIO(other), m_ImageIO(dynamic_cast<itk::ImageIOBase *>(other.m_ImageIO->Clone().GetPointer()))
41  {
42  this->InitializeDefaultMetaDataKeys();
43  }
44 
45  std::vector<std::string> ItkImageIO::FixUpImageIOExtensions(const std::string &imageIOName)
46  {
47  std::vector<std::string> extensions;
48  // Try to fix-up some known ITK image IO classes
49  if (imageIOName == "GiplImageIO")
50  {
51  extensions.push_back("gipl");
52  extensions.push_back("gipl.gz");
53  }
54  else if (imageIOName == "GDCMImageIO")
55  {
56  extensions.push_back("gdcm");
57  extensions.push_back("dcm");
58  extensions.push_back("DCM");
59  extensions.push_back("dc3");
60  extensions.push_back("DC3");
61  extensions.push_back("ima");
62  extensions.push_back("img");
63  }
64  else if (imageIOName == "PNGImageIO")
65  {
66  extensions.push_back("png");
67  extensions.push_back("PNG");
68  }
69  else if (imageIOName == "StimulateImageIO")
70  {
71  extensions.push_back("spr");
72  }
73  else if (imageIOName == "HDF5ImageIO")
74  {
75  extensions.push_back("hdf");
76  extensions.push_back("h4");
77  extensions.push_back("hdf4");
78  extensions.push_back("h5");
79  extensions.push_back("hdf5");
80  extensions.push_back("he4");
81  extensions.push_back("he5");
82  extensions.push_back("hd5");
83  }
84  else if ("GE4ImageIO" == imageIOName || "GE5ImageIO" == imageIOName || "Bruker2dseqImageIO" == imageIOName)
85  {
86  extensions.push_back("");
87  }
88 
89  if (!extensions.empty())
90  {
91  MITK_DEBUG << "Fixing up known extensions for " << imageIOName;
92  }
93 
94  return extensions;
95  }
96 
97  void ItkImageIO::FixUpCustomMimeTypeName(const std::string &imageIOName, CustomMimeType &customMimeType)
98  {
99  if ("GE4ImageIO" == imageIOName)
100  {
101  customMimeType.SetName(this->AbstractFileReader::GetMimeTypePrefix() + "ge4");
102  }
103  else if ("GE5ImageIO" == imageIOName)
104  {
105  customMimeType.SetName(this->AbstractFileReader::GetMimeTypePrefix() + "ge5");
106  }
107  else if ("Bruker2dseqImageIO" == imageIOName)
108  {
109  customMimeType.SetName(this->AbstractFileReader::GetMimeTypePrefix() + "bruker2dseq");
110  }
111  }
112 
113  ItkImageIO::ItkImageIO(itk::ImageIOBase::Pointer imageIO)
114  : AbstractFileIO(Image::GetStaticNameOfClass()), m_ImageIO(imageIO)
115  {
116  if (m_ImageIO.IsNull())
117  {
118  mitkThrow() << "ITK ImageIOBase argument must not be nullptr";
119  }
120 
123 
124  std::vector<std::string> readExtensions = m_ImageIO->GetSupportedReadExtensions();
125 
126  if (readExtensions.empty())
127  {
128  std::string imageIOName = m_ImageIO->GetNameOfClass();
129  MITK_DEBUG << "ITK ImageIOBase " << imageIOName << " does not provide read extensions";
130  readExtensions = FixUpImageIOExtensions(imageIOName);
131  }
132 
133  CustomMimeType customReaderMimeType;
134  customReaderMimeType.SetCategory("Images");
135  for (std::vector<std::string>::const_iterator iter = readExtensions.begin(), endIter = readExtensions.end();
136  iter != endIter;
137  ++iter)
138  {
139  std::string extension = *iter;
140  if (!extension.empty() && extension[0] == '.')
141  {
142  extension.assign(iter->begin() + 1, iter->end());
143  }
144  customReaderMimeType.AddExtension(extension);
145  }
146 
147  auto extensions = customReaderMimeType.GetExtensions();
148  if (extensions.empty() || (extensions.size() == 1 && extensions[0].empty()))
149  {
150  std::string imageIOName = m_ImageIO->GetNameOfClass();
151  FixUpCustomMimeTypeName(imageIOName, customReaderMimeType);
152  }
153 
154  this->AbstractFileReader::SetMimeType(customReaderMimeType);
155 
156  std::vector<std::string> writeExtensions = imageIO->GetSupportedWriteExtensions();
157  if (writeExtensions.empty())
158  {
159  std::string imageIOName = imageIO->GetNameOfClass();
160  MITK_DEBUG << "ITK ImageIOBase " << imageIOName << " does not provide write extensions";
161  writeExtensions = FixUpImageIOExtensions(imageIOName);
162  }
163 
164  if (writeExtensions != readExtensions)
165  {
166  CustomMimeType customWriterMimeType;
167  customWriterMimeType.SetCategory("Images");
168  for (std::vector<std::string>::const_iterator iter = writeExtensions.begin(), endIter = writeExtensions.end();
169  iter != endIter;
170  ++iter)
171  {
172  std::string extension = *iter;
173  if (!extension.empty() && extension[0] == '.')
174  {
175  extension.assign(iter->begin() + 1, iter->end());
176  }
177  customWriterMimeType.AddExtension(extension);
178  }
179 
180  auto extensions = customWriterMimeType.GetExtensions();
181  if (extensions.empty() || (extensions.size() == 1 && extensions[0].empty()))
182  {
183  std::string imageIOName = m_ImageIO->GetNameOfClass();
184  FixUpCustomMimeTypeName(imageIOName, customWriterMimeType);
185  }
186 
187  this->AbstractFileWriter::SetMimeType(customWriterMimeType);
188  }
189 
190  std::string description = std::string("ITK ") + imageIO->GetNameOfClass();
191  this->SetReaderDescription(description);
192  this->SetWriterDescription(description);
193 
194  this->RegisterService();
195  }
196 
197  ItkImageIO::ItkImageIO(const CustomMimeType &mimeType, itk::ImageIOBase::Pointer imageIO, int rank)
198  : AbstractFileIO(Image::GetStaticNameOfClass(), mimeType, std::string("ITK ") + imageIO->GetNameOfClass()),
199  m_ImageIO(imageIO)
200  {
201  if (m_ImageIO.IsNull())
202  {
203  mitkThrow() << "ITK ImageIOBase argument must not be nullptr";
204  }
205 
208 
209  if (rank)
210  {
211  this->AbstractFileReader::SetRanking(rank);
212  this->AbstractFileWriter::SetRanking(rank);
213  }
214 
215  this->RegisterService();
216  }
217 
220  std::vector<TimePointType> ConvertMetaDataObjectToTimePointList(const itk::MetaDataObjectBase *data)
221  {
222  const auto *timeGeometryTimeData =
223  dynamic_cast<const itk::MetaDataObject<std::string> *>(data);
224  std::vector<TimePointType> result;
225 
226  if (timeGeometryTimeData)
227  {
228  std::string dataStr = timeGeometryTimeData->GetMetaDataObjectValue();
229  std::stringstream stream(dataStr);
230  TimePointType tp;
231  while (stream >> tp)
232  {
233  result.push_back(tp);
234  }
235  }
236 
237  return result;
238  };
239 
240  std::vector<BaseData::Pointer> ItkImageIO::Read()
241  {
242  std::vector<BaseData::Pointer> result;
243  mitk::LocaleSwitch localeSwitch("C");
244 
246 
247  const unsigned int MINDIM = 2;
248  const unsigned int MAXDIM = 4;
249 
250  const std::string path = this->GetLocalFileName();
251 
252  MITK_INFO << "loading " << path << " via itk::ImageIOFactory... " << std::endl;
253 
254  // Check to see if we can read the file given the name or prefix
255  if (path.empty())
256  {
257  mitkThrow() << "Empty filename in mitk::ItkImageIO ";
258  }
259 
260  // Got to allocate space for the image. Determine the characteristics of
261  // the image.
262  m_ImageIO->SetFileName(path);
263  m_ImageIO->ReadImageInformation();
264 
265  unsigned int ndim = m_ImageIO->GetNumberOfDimensions();
266  if (ndim < MINDIM || ndim > MAXDIM)
267  {
268  MITK_WARN << "Sorry, only dimensions 2, 3 and 4 are supported. The given file has " << ndim
269  << " dimensions! Reading as 4D.";
270  ndim = MAXDIM;
271  }
272 
273  itk::ImageIORegion ioRegion(ndim);
274  itk::ImageIORegion::SizeType ioSize = ioRegion.GetSize();
275  itk::ImageIORegion::IndexType ioStart = ioRegion.GetIndex();
276 
277  unsigned int dimensions[MAXDIM];
278  dimensions[0] = 0;
279  dimensions[1] = 0;
280  dimensions[2] = 0;
281  dimensions[3] = 0;
282 
283  ScalarType spacing[MAXDIM];
284  spacing[0] = 1.0f;
285  spacing[1] = 1.0f;
286  spacing[2] = 1.0f;
287  spacing[3] = 1.0f;
288 
289  Point3D origin;
290  origin.Fill(0);
291 
292  unsigned int i;
293  for (i = 0; i < ndim; ++i)
294  {
295  ioStart[i] = 0;
296  ioSize[i] = m_ImageIO->GetDimensions(i);
297  if (i < MAXDIM)
298  {
299  dimensions[i] = m_ImageIO->GetDimensions(i);
300  spacing[i] = m_ImageIO->GetSpacing(i);
301  if (spacing[i] <= 0)
302  spacing[i] = 1.0f;
303  }
304  if (i < 3)
305  {
306  origin[i] = m_ImageIO->GetOrigin(i);
307  }
308  }
309 
310  ioRegion.SetSize(ioSize);
311  ioRegion.SetIndex(ioStart);
312 
313  MITK_INFO << "ioRegion: " << ioRegion << std::endl;
314  m_ImageIO->SetIORegion(ioRegion);
315  void *buffer = new unsigned char[m_ImageIO->GetImageSizeInBytes()];
316  m_ImageIO->Read(buffer);
317 
318  image->Initialize(MakePixelType(m_ImageIO), ndim, dimensions);
319  image->SetImportChannel(buffer, 0, Image::ManageMemory);
320 
321  const itk::MetaDataDictionary &dictionary = m_ImageIO->GetMetaDataDictionary();
322 
323  // access direction of itk::Image and include spacing
324  mitk::Matrix3D matrix;
325  matrix.SetIdentity();
326  unsigned int j, itkDimMax3 = (ndim >= 3 ? 3 : ndim);
327  for (i = 0; i < itkDimMax3; ++i)
328  for (j = 0; j < itkDimMax3; ++j)
329  matrix[i][j] = m_ImageIO->GetDirection(j)[i];
330 
331  // re-initialize PlaneGeometry with origin and direction
332  PlaneGeometry *planeGeometry = image->GetSlicedGeometry(0)->GetPlaneGeometry(0);
333  planeGeometry->SetOrigin(origin);
334  planeGeometry->GetIndexToWorldTransform()->SetMatrix(matrix);
335 
336  // re-initialize SlicedGeometry3D
337  SlicedGeometry3D *slicedGeometry = image->GetSlicedGeometry(0);
338  slicedGeometry->InitializeEvenlySpaced(planeGeometry, image->GetDimension(2));
339  slicedGeometry->SetSpacing(spacing);
340 
341  MITK_INFO << slicedGeometry->GetCornerPoint(false, false, false);
342  MITK_INFO << slicedGeometry->GetCornerPoint(true, true, true);
343 
344  // re-initialize TimeGeometry
345  TimeGeometry::Pointer timeGeometry;
346 
347  if (dictionary.HasKey(PROPERTY_NAME_TIMEGEOMETRY_TYPE) || dictionary.HasKey(PROPERTY_KEY_TIMEGEOMETRY_TYPE))
348  { // also check for the name because of backwards compatibility. Past code version stored with the name and not with
349  // the key
350  itk::MetaDataObject<std::string>::ConstPointer timeGeometryTypeData = nullptr;
351  if (dictionary.HasKey(PROPERTY_NAME_TIMEGEOMETRY_TYPE))
352  {
353  timeGeometryTypeData =
354  dynamic_cast<const itk::MetaDataObject<std::string> *>(dictionary.Get(PROPERTY_NAME_TIMEGEOMETRY_TYPE));
355  }
356  else
357  {
358  timeGeometryTypeData =
359  dynamic_cast<const itk::MetaDataObject<std::string> *>(dictionary.Get(PROPERTY_KEY_TIMEGEOMETRY_TYPE));
360  }
361 
362  if (timeGeometryTypeData->GetMetaDataObjectValue() == ArbitraryTimeGeometry::GetStaticNameOfClass())
363  {
364  MITK_INFO << "used time geometry: " << ArbitraryTimeGeometry::GetStaticNameOfClass() << std::endl;
365  typedef std::vector<TimePointType> TimePointVector;
366  TimePointVector timePoints;
367 
368  if (dictionary.HasKey(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS))
369  {
370  timePoints = ConvertMetaDataObjectToTimePointList(dictionary.Get(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS));
371  }
372  else if (dictionary.HasKey(PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS))
373  {
374  timePoints = ConvertMetaDataObjectToTimePointList(dictionary.Get(PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS));
375  }
376 
377  if (timePoints.size() - 1 != image->GetDimension(3))
378  {
379  MITK_ERROR << "Stored timepoints (" << timePoints.size() - 1 << ") and size of image time dimension ("
380  << image->GetDimension(3) << ") do not match. Switch to ProportionalTimeGeometry fallback"
381  << std::endl;
382  }
383  else
384  {
386  TimePointVector::const_iterator pos = timePoints.begin();
387  auto prePos = pos++;
388 
389  for (; pos != timePoints.end(); ++prePos, ++pos)
390  {
391  arbitraryTimeGeometry->AppendNewTimeStepClone(slicedGeometry, *prePos, *pos);
392  }
393 
394  timeGeometry = arbitraryTimeGeometry;
395  }
396  }
397  }
398 
399  if (timeGeometry.IsNull())
400  { // Fallback. If no other valid time geometry has been created, create a ProportionalTimeGeometry
401  MITK_INFO << "used time geometry: " << ProportionalTimeGeometry::GetStaticNameOfClass() << std::endl;
403  propTimeGeometry->Initialize(slicedGeometry, image->GetDimension(3));
404  timeGeometry = propTimeGeometry;
405  }
406 
407  image->SetTimeGeometry(timeGeometry);
408 
409  buffer = nullptr;
410  MITK_INFO << "number of image components: " << image->GetPixelType().GetNumberOfComponents() << std::endl;
411 
412  for (auto iter = dictionary.Begin(), iterEnd = dictionary.End(); iter != iterEnd;
413  ++iter)
414  {
415  if (iter->second->GetMetaDataObjectTypeInfo() == typeid(std::string))
416  {
417  const std::string &key = iter->first;
418  std::string assumedPropertyName = key;
419  std::replace(assumedPropertyName.begin(), assumedPropertyName.end(), '_', '.');
420 
421  std::string mimeTypeName = GetMimeType()->GetName();
422 
423  // Check if there is already a info for the key and our mime type.
425 
426  auto predicate = [mimeTypeName](const PropertyPersistenceInfo::ConstPointer &x) {
427  return x.IsNotNull() && x->GetMimeTypeName() == mimeTypeName;
428  };
429  auto finding = std::find_if(infoList.begin(), infoList.end(), predicate);
430 
431  if (finding == infoList.end())
432  {
433  auto predicateWild = [](const PropertyPersistenceInfo::ConstPointer &x) {
434  return x.IsNotNull() && x->GetMimeTypeName() == PropertyPersistenceInfo::ANY_MIMETYPE_NAME();
435  };
436  finding = std::find_if(infoList.begin(), infoList.end(), predicateWild);
437  }
438 
440 
441  if (finding != infoList.end())
442  {
443  assumedPropertyName = (*finding)->GetName();
444  info = *finding;
445  }
446  else
447  { // we have not found anything suitable so we generate our own info
449  newInfo->SetNameAndKey(assumedPropertyName, key);
450  newInfo->SetMimeTypeName(PropertyPersistenceInfo::ANY_MIMETYPE_NAME());
451  info = newInfo;
452  }
453 
454  std::string value =
455  dynamic_cast<itk::MetaDataObject<std::string> *>(iter->second.GetPointer())->GetMetaDataObjectValue();
456 
457  mitk::BaseProperty::Pointer loadedProp = info->GetDeserializationFunction()(value);
458 
459  image->SetProperty(assumedPropertyName.c_str(), loadedProp);
460 
461  // Read properties should be persisted unless they are default properties
462  // which are written anyway
463  bool isDefaultKey(false);
464 
465  for (const auto &defaultKey : m_DefaultMetaDataKeys)
466  {
467  if (defaultKey.length() <= assumedPropertyName.length())
468  {
469  // does the start match the default key
470  if (assumedPropertyName.substr(0, defaultKey.length()).find(defaultKey) != std::string::npos)
471  {
472  isDefaultKey = true;
473  break;
474  }
475  }
476  }
477 
478  if (!isDefaultKey)
479  {
481  }
482  }
483  }
484 
485  MITK_INFO << "...finished!" << std::endl;
486 
487  result.push_back(image.GetPointer());
488  return result;
489  }
490 
492  {
493  return m_ImageIO->CanReadFile(GetLocalFileName().c_str()) ? IFileReader::Supported : IFileReader::Unsupported;
494  }
495 
497  {
498  const auto *image = dynamic_cast<const mitk::Image *>(this->GetInput());
499 
500  if (image == nullptr)
501  {
502  mitkThrow() << "Cannot write non-image data";
503  }
504 
505  // Switch the current locale to "C"
506  LocaleSwitch localeSwitch("C");
507 
508  // Clone the image geometry, because we might have to change it
509  // for writing purposes
510  BaseGeometry::Pointer geometry = image->GetGeometry()->Clone();
511 
512  // Check if geometry information will be lost
513  if (image->GetDimension() == 2 && !geometry->Is2DConvertable())
514  {
515  MITK_WARN << "Saving a 2D image with 3D geometry information. Geometry information will be lost! You might "
516  "consider using Convert2Dto3DImageFilter before saving.";
517 
518  // set matrix to identity
519  mitk::AffineTransform3D::Pointer affTrans = mitk::AffineTransform3D::New();
520  affTrans->SetIdentity();
521  mitk::Vector3D spacing = geometry->GetSpacing();
522  mitk::Point3D origin = geometry->GetOrigin();
523  geometry->SetIndexToWorldTransform(affTrans);
524  geometry->SetSpacing(spacing);
525  geometry->SetOrigin(origin);
526  }
527 
528  LocalFile localFile(this);
529  const std::string path = localFile.GetFileName();
530 
531  MITK_INFO << "Writing image: " << path << std::endl;
532 
533  try
534  {
535  // Implementation of writer using itkImageIO directly. This skips the use
536  // of templated itkImageFileWriter, which saves the multiplexing on MITK side.
537 
538  const unsigned int dimension = image->GetDimension();
539  const unsigned int *const dimensions = image->GetDimensions();
540  const mitk::PixelType pixelType = image->GetPixelType();
541  const mitk::Vector3D mitkSpacing = geometry->GetSpacing();
542  const mitk::Point3D mitkOrigin = geometry->GetOrigin();
543 
544  // Due to templating in itk, we are forced to save a 4D spacing and 4D Origin,
545  // though they are not supported in MITK
546  itk::Vector<double, 4u> spacing4D;
547  spacing4D[0] = mitkSpacing[0];
548  spacing4D[1] = mitkSpacing[1];
549  spacing4D[2] = mitkSpacing[2];
550  spacing4D[3] = 1; // There is no support for a 4D spacing. However, we should have a valid value here
551 
552  itk::Vector<double, 4u> origin4D;
553  origin4D[0] = mitkOrigin[0];
554  origin4D[1] = mitkOrigin[1];
555  origin4D[2] = mitkOrigin[2];
556  origin4D[3] = 0; // There is no support for a 4D origin. However, we should have a valid value here
557 
558  // Set the necessary information for imageIO
559  m_ImageIO->SetNumberOfDimensions(dimension);
560  m_ImageIO->SetPixelType(pixelType.GetPixelType());
561  m_ImageIO->SetComponentType(pixelType.GetComponentType() < PixelComponentUserType ?
562  static_cast<itk::ImageIOBase::IOComponentType>(pixelType.GetComponentType()) :
563  itk::ImageIOBase::UNKNOWNCOMPONENTTYPE);
564  m_ImageIO->SetNumberOfComponents(pixelType.GetNumberOfComponents());
565 
566  itk::ImageIORegion ioRegion(dimension);
567 
568  for (unsigned int i = 0; i < dimension; i++)
569  {
570  m_ImageIO->SetDimensions(i, dimensions[i]);
571  m_ImageIO->SetSpacing(i, spacing4D[i]);
572  m_ImageIO->SetOrigin(i, origin4D[i]);
573 
574  mitk::Vector3D mitkDirection;
575  mitkDirection.SetVnlVector(geometry->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(i));
576  itk::Vector<double, 4u> direction4D;
577  direction4D[0] = mitkDirection[0];
578  direction4D[1] = mitkDirection[1];
579  direction4D[2] = mitkDirection[2];
580 
581  // MITK only supports a 3x3 direction matrix. Due to templating in itk, however, we must
582  // save a 4x4 matrix for 4D images. in this case, add an homogneous component to the matrix.
583  if (i == 3)
584  {
585  direction4D[3] = 1; // homogenous component
586  }
587  else
588  {
589  direction4D[3] = 0;
590  }
591  vnl_vector<double> axisDirection(dimension);
592  for (unsigned int j = 0; j < dimension; j++)
593  {
594  axisDirection[j] = direction4D[j] / spacing4D[i];
595  }
596  m_ImageIO->SetDirection(i, axisDirection);
597 
598  ioRegion.SetSize(i, image->GetLargestPossibleRegion().GetSize(i));
599  ioRegion.SetIndex(i, image->GetLargestPossibleRegion().GetIndex(i));
600  }
601 
602  // use compression if available
603  m_ImageIO->UseCompressionOn();
604 
605  m_ImageIO->SetIORegion(ioRegion);
606  m_ImageIO->SetFileName(path);
607 
608  // Handle time geometry
609  const auto *arbitraryTG = dynamic_cast<const ArbitraryTimeGeometry *>(image->GetTimeGeometry());
610  if (arbitraryTG)
611  {
612  itk::EncapsulateMetaData<std::string>(m_ImageIO->GetMetaDataDictionary(),
615 
616  std::stringstream stream;
617  stream << arbitraryTG->GetTimeBounds(0)[0];
618  for (TimeStepType pos = 0; pos < arbitraryTG->CountTimeSteps(); ++pos)
619  {
620  stream << " " << arbitraryTG->GetTimeBounds(pos)[1];
621  }
622  std::string data = stream.str();
623 
624  itk::EncapsulateMetaData<std::string>(
625  m_ImageIO->GetMetaDataDictionary(), PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS, data);
626  }
627 
628  // Handle properties
629  mitk::PropertyList::Pointer imagePropertyList = image->GetPropertyList();
630 
631  for (const auto &property : *imagePropertyList->GetMap())
632  {
635 
636  if (infoList.empty())
637  {
638  continue;
639  }
640 
641  std::string value = infoList.front()->GetSerializationFunction()(property.second);
642 
644  {
645  continue;
646  }
647 
648  std::string key = infoList.front()->GetKey();
649 
650  itk::EncapsulateMetaData<std::string>(m_ImageIO->GetMetaDataDictionary(), key, value);
651  }
652  ImageReadAccessor imageAccess(image);
653  LocaleSwitch localeSwitch2("C");
654  m_ImageIO->Write(imageAccess.GetData());
655  }
656  catch (const std::exception &e)
657  {
658  mitkThrow() << e.what();
659  }
660  }
661 
663  {
664  // Check if the image dimension is supported
665  const auto *image = dynamic_cast<const Image *>(this->GetInput());
666  if (image == nullptr)
667  {
668  // We cannot write a null object, DUH!
670  }
671 
672  if (!m_ImageIO->SupportsDimension(image->GetDimension()))
673  {
674  // okay, dimension is not supported. We have to look at a special case:
675  // 3D-Image with one slice. We can treat that as a 2D image.
676  if ((image->GetDimension() == 3) && (image->GetSlicedGeometry()->GetSlices() == 1))
677  return IFileWriter::Supported;
678  else
680  }
681 
682  // Check if geometry information will be lost
683  if (image->GetDimension() == 2 && !image->GetGeometry()->Is2DConvertable())
684  {
686  }
687  return IFileWriter::Supported;
688  }
689 
690  ItkImageIO *ItkImageIO::IOClone() const { return new ItkImageIO(*this); }
692  {
693  this->m_DefaultMetaDataKeys.push_back("NRRD.space");
694  this->m_DefaultMetaDataKeys.push_back("NRRD.kinds");
695  this->m_DefaultMetaDataKeys.push_back(PROPERTY_NAME_TIMEGEOMETRY_TYPE);
696  this->m_DefaultMetaDataKeys.push_back(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS);
697  this->m_DefaultMetaDataKeys.push_back("ITK.InputFilterName");
698  }
699 }
static const char * GetStaticNameOfClass()
void SetSpacing(const mitk::Vector3D &aSpacing, bool enforceSetSpacing=false)
Set the spacing (m_Spacing).
#define MITK_INFO
Definition: mitkLogMacros.h:18
virtual InfoResultType GetInfoByKey(const std::string &persistenceKey, bool allowKeyRegEx=true) const =0
Get the persistence info that will use the specified key.
#define MITK_ERROR
Definition: mitkLogMacros.h:20
double ScalarType
vcl_size_t GetNumberOfComponents() const
Get the number of components of which each element consists.
const char *const PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS
std::string GetName() const
Returns the unique name for the MimeType.
ItkImageIO(itk::ImageIOBase::Pointer imageIO)
#define MITK_DEBUG
Definition: mitkLogMacros.h:22
STL namespace.
std::vector< TimePointType > ConvertMetaDataObjectToTimePointList(const itk::MetaDataObjectBase *data)
DataCollection - Class to facilitate loading/accessing structured data.
Point3D GetCornerPoint(int id) const
Get the position of the corner number id (in world coordinates)
virtual void InitializeEvenlySpaced(mitk::PlaneGeometry *geometry2D, unsigned int slices)
Completely initialize this instance as evenly-spaced with slices parallel to the provided PlaneGeomet...
static void info(const char *fmt,...)
Definition: svm.cpp:86
static const int PixelComponentUserType
void SetMimeType(const CustomMimeType &mimeType)
The CustomMimeType class represents a custom mime-type which may be registered as a service object...
int GetComponentType() const
Get the component type (the scalar (!) type). Each element may contain m_NumberOfComponents (more tha...
std::vector< std::string > GetExtensions() const
Returns all extensions that this MimeType can handle.
void SetRanking(int ranking)
Set the service ranking for this file writer.
std::string GetLocalFileName() const
Get a local file name for reading.
void SetMimeTypePrefix(const std::string &prefix)
ConfidenceLevel GetWriterConfidenceLevel() const override
void Write() override
Write the base data to the specified location or output stream.
MITKCORE_EXPORT mitk::PixelType MakePixelType(vtkImageData *vtkimagedata)
deduct the PixelType for a given vtk image
virtual void FixUpCustomMimeTypeName(const std::string &imageIOName, CustomMimeType &customMimeType)
static std::string DEFAULT_BASE_NAME()
#define MITK_WARN
Definition: mitkLogMacros.h:19
ConfidenceLevel
A confidence level describing the confidence of the reader or writer in handling the given data...
Definition: mitkIFileIO.h:45
Convenience class to temporarily change the current locale.
static IPropertyPersistence * GetPropertyPersistence(us::ModuleContext *context=us::GetModuleContext())
Get an IPropertyPersistence instance.
ConfidenceLevel GetReaderConfidenceLevel() const override
std::pair< us::ServiceRegistration< IFileReader >, us::ServiceRegistration< IFileWriter > > RegisterService(us::ModuleContext *context=us::GetModuleContext())
#define mitkThrow()
void SetOrigin(const Point3D &origin)
Set the origin, i.e. the upper-left corner of the plane.
virtual InfoResultType GetInfo(const std::string &propertyName, bool allowNameRegEx=true) const =0
Get the persistence info for a specific base data property.
virtual std::vector< std::string > FixUpImageIOExtensions(const std::string &imageIOName)
const BaseData * GetInput() const override
Get the input data set via SetInput().
Image class for storing images.
Definition: mitkImage.h:72
const char *const PROPERTY_NAME_TIMEGEOMETRY_TYPE
void SetReaderDescription(const std::string &description)
mitk::ScalarType TimePointType
A local file representation for streams.
std::vcl_size_t TimeStepType
static const std::string VALUE_CANNOT_BE_CONVERTED_TO_STRING
Default return value if a property which can not be returned as string.
itk::ImageIOBase::IOPixelType GetPixelType() const
mitk::Image::Pointer image
virtual void InitializeDefaultMetaDataKeys()
void AddExtension(const std::string &extension)
static Pointer New()
Describes the geometry of a data object consisting of slices.
void SetRanking(int ranking)
Set the service ranking for this file reader.
void SetWriterDescription(const std::string &description)
void SetCategory(const std::string &category)
std::vector< itk::SmartPointer< BaseData > > Read() override
Reads a path or stream and creates a list of BaseData objects.
const char *const PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS
TimeBounds GetTimeBounds() const override
Get the time bounds (in ms) it returns GetMinimumTimePoint() and GetMaximumTimePoint() results as bou...
static const char * replace[]
This is a dictionary to replace long names of classes, modules, etc. to shorter versions in the conso...
void SetMimeType(const CustomMimeType &mimeType)
static std::string GetName(std::string fileName, std::string suffix)
Describes a two-dimensional, rectangular plane.
virtual bool AddInfo(const PropertyPersistenceInfo *info, bool overwrite=false)=0
Add persistence info for a specific base data property. If there is already a property info instance ...
const char *const PROPERTY_KEY_TIMEGEOMETRY_TYPE
std::list< PropertyPersistenceInfo::ConstPointer > InfoResultType
ImageReadAccessor class to get locked read access for a particular image part.
static mitk::PlanarFigure::Pointer Clone(mitk::PlanarFigure::Pointer original)
Abstract class for implementing a reader and writer.
std::string GetMimeTypePrefix() const
const CustomMimeType * GetMimeType() const
Class for defining the data type of pixels.
Definition: mitkPixelType.h:51
mitk::AffineTransform3D * GetIndexToWorldTransform()
Get the transformation used to convert from index to world coordinates.
void SetName(const std::string &name)