OTB  9.0.0
Orfeo Toolbox
otbImageFileWriter.hxx
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-2022 Centre National d'Etudes Spatiales (CNES)
3  * Copyright (C) 2018-2020 CS Systemes d'Information (CS SI)
4  *
5  * This file is part of Orfeo Toolbox
6  *
7  * https://www.orfeo-toolbox.org/
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21 
22 #ifndef otbImageFileWriter_hxx
23 #define otbImageFileWriter_hxx
24 
25 #include "otbImageFileWriter.h"
26 #include "itkImageFileWriter.h"
27 
28 #include "itkObjectFactoryBase.h"
29 
30 #include "itkImageRegionMultidimensionalSplitter.h"
31 #include "otbImageIOFactory.h"
32 
33 #include "itkImageRegionIterator.h"
34 
35 #include "itkMetaDataObject.h"
36 #include "otbMetaDataKey.h"
37 #include "otbImageCommons.h"
38 
39 #include "otbConfigure.h"
40 
48 
50 
51 #include "otbStringUtils.h"
52 #include "otbUtils.h"
53 
54 namespace otb
55 {
56 
60 template <class TInputImage>
62  : m_NumberOfDivisions(0),
63  m_CurrentDivision(0),
64  m_DivisionProgress(0.0),
65  m_UserSpecifiedImageIO(true),
66  m_UserSpecifiedIORegion(false),
67  m_FactorySpecifiedImageIO(false),
68  m_UseCompression(false),
69  m_UseInputMetaDataDictionary(false),
70  m_WriteGeomFile(false),
71  m_FilenameHelper(),
72  m_IsObserving(true),
73  m_ObserverID(0),
74  m_IOComponents(0)
75 {
76  // Init output index shift
77  m_ShiftOutputIndex.Fill(0);
78 
79  // By default, we use tiled streaming, with automatic tile size
80  // We don't set any parameter, so the memory size is retrieved from the OTB configuration options
81  this->SetAutomaticAdaptativeStreaming();
82 
83  m_FilenameHelper = FNameHelperType::New();
84 }
85 
89 template <class TInputImage>
91 {
92 }
93 
94 template <class TInputImage>
96 {
97  typedef NumberOfDivisionsStrippedStreamingManager<TInputImage> NumberOfDivisionsStrippedStreamingManagerType;
98  typename NumberOfDivisionsStrippedStreamingManagerType::Pointer streamingManager = NumberOfDivisionsStrippedStreamingManagerType::New();
99  streamingManager->SetNumberOfDivisions(nbDivisions);
100  m_StreamingManager = streamingManager;
101 }
102 
103 template <class TInputImage>
105 {
106  typedef NumberOfDivisionsTiledStreamingManager<TInputImage> NumberOfDivisionsTiledStreamingManagerType;
107  typename NumberOfDivisionsTiledStreamingManagerType::Pointer streamingManager = NumberOfDivisionsTiledStreamingManagerType::New();
108  streamingManager->SetNumberOfDivisions(nbDivisions);
109  m_StreamingManager = streamingManager;
110 }
111 
112 template <class TInputImage>
114 {
115  typedef NumberOfLinesStrippedStreamingManager<TInputImage> NumberOfLinesStrippedStreamingManagerType;
116  typename NumberOfLinesStrippedStreamingManagerType::Pointer streamingManager = NumberOfLinesStrippedStreamingManagerType::New();
117  streamingManager->SetNumberOfLinesPerStrip(nbLinesPerStrip);
118  m_StreamingManager = streamingManager;
119 }
120 
121 template <class TInputImage>
122 void ImageFileWriter<TInputImage>::SetAutomaticStrippedStreaming(unsigned int availableRAM, double bias)
123 {
124  typedef RAMDrivenStrippedStreamingManager<TInputImage> RAMDrivenStrippedStreamingManagerType;
125  typename RAMDrivenStrippedStreamingManagerType::Pointer streamingManager = RAMDrivenStrippedStreamingManagerType::New();
126  streamingManager->SetAvailableRAMInMB(availableRAM);
127  streamingManager->SetBias(bias);
128  m_StreamingManager = streamingManager;
129 }
130 
131 template <class TInputImage>
133 {
134  typedef TileDimensionTiledStreamingManager<TInputImage> TileDimensionTiledStreamingManagerType;
135  typename TileDimensionTiledStreamingManagerType::Pointer streamingManager = TileDimensionTiledStreamingManagerType::New();
136  streamingManager->SetTileDimension(tileDimension);
137  m_StreamingManager = streamingManager;
138 }
139 
140 template <class TInputImage>
141 void ImageFileWriter<TInputImage>::SetAutomaticTiledStreaming(unsigned int availableRAM, double bias)
142 {
143  typedef RAMDrivenTiledStreamingManager<TInputImage> RAMDrivenTiledStreamingManagerType;
144  typename RAMDrivenTiledStreamingManagerType::Pointer streamingManager = RAMDrivenTiledStreamingManagerType::New();
145  streamingManager->SetAvailableRAMInMB(availableRAM);
146  streamingManager->SetBias(bias);
147  m_StreamingManager = streamingManager;
148 }
149 
150 template <class TInputImage>
151 void ImageFileWriter<TInputImage>::SetAutomaticAdaptativeStreaming(unsigned int availableRAM, double bias)
152 {
153  typedef RAMDrivenAdaptativeStreamingManager<TInputImage> RAMDrivenAdaptativeStreamingManagerType;
154  typename RAMDrivenAdaptativeStreamingManagerType::Pointer streamingManager = RAMDrivenAdaptativeStreamingManagerType::New();
155  streamingManager->SetAvailableRAMInMB(availableRAM);
156  streamingManager->SetBias(bias);
157  m_StreamingManager = streamingManager;
158 }
159 
163 template <class TInputImage>
164 void ImageFileWriter<TInputImage>::PrintSelf(std::ostream& os, itk::Indent indent) const
165 {
166  Superclass::PrintSelf(os, indent);
167 
168  os << indent << "File Name: " << (m_FileName.data() ? m_FileName.data() : "(none)") << std::endl;
169 
170  os << indent << "Image IO: ";
171  if (m_ImageIO.IsNull())
172  {
173  os << "(none)\n";
174  }
175  else
176  {
177  os << m_ImageIO << "\n";
178  }
179 
180  os << indent << "IO Region: " << m_IORegion << "\n";
181 
182  if (m_UseCompression)
183  {
184  os << indent << "Compression: On\n";
185  }
186  else
187  {
188  os << indent << "Compression: Off\n";
189  }
190 
191  if (m_UseInputMetaDataDictionary)
192  {
193  os << indent << "UseInputMetaDataDictionary: On\n";
194  }
195  else
196  {
197  os << indent << "UseInputMetaDataDictionary: Off\n";
198  }
199 
200  if (m_FactorySpecifiedImageIO)
201  {
202  os << indent << "FactorySpecifiedmageIO: On\n";
203  }
204  else
205  {
206  os << indent << "FactorySpecifiedmageIO: Off\n";
207  }
208 }
209 
210 //---------------------------------------------------------
211 template <class TInputImage>
212 void ImageFileWriter<TInputImage>::SetIORegion(const itk::ImageIORegion& region)
213 {
214  if (m_IORegion != region)
215  {
216  m_IORegion = region;
217  this->Modified();
218  m_UserSpecifiedIORegion = true;
219  }
220 }
221 
222 template <class TInputImage>
224 {
225  this->ProcessObject::SetNthInput(0, const_cast<InputImageType*>(input));
226 }
227 
228 template <class TInputImage>
230 {
231  if (this->GetNumberOfInputs() < 1)
232  {
233  return nullptr;
234  }
235 
236  return static_cast<const InputImageType*>(this->ProcessObject::GetInput(0));
237 }
238 
240 template <class TInputImage>
242 {
243  // Update output information on input image
244  InputImagePointer inputPtr = const_cast<InputImageType*>(this->GetInput());
245 
246  // Make sure input is available
247  if (inputPtr.IsNull())
248  {
249  itkExceptionMacro(<< "No input to writer");
250  }
251 
252  otb::Logger::Instance()->LogSetupInformation();
253 
255  if (m_FilenameHelper->StreamingTypeIsSet())
256  {
257  otbLogMacro(
258  Warning,
259  << "Streaming configuration through extended filename is used. Any previous streaming configuration (ram value, streaming mode ...) will be ignored.");
260 
261  std::string type = m_FilenameHelper->GetStreamingType();
262 
263  std::string sizemode = "auto";
264 
265  if (m_FilenameHelper->StreamingSizeModeIsSet())
266  {
267  sizemode = m_FilenameHelper->GetStreamingSizeMode();
268  }
269 
270  unsigned int sizevalue = 0;
271  // Save the DefaultRAM value for later
272  unsigned int oldDefaultRAM = m_StreamingManager->GetDefaultRAM();
273  if (sizemode == "auto")
274  {
275  sizevalue = oldDefaultRAM;
276  }
277 
278  if (m_FilenameHelper->StreamingSizeValueIsSet())
279  {
280  sizevalue = static_cast<unsigned int>(m_FilenameHelper->GetStreamingSizeValue());
281  }
282 
283  if (type == "auto")
284  {
285  if (sizemode != "auto")
286  {
287  otbLogMacro(Warning, << "In auto streaming type, the sizemode option will be ignored.");
288  }
289  if (sizevalue == 0)
290  {
291  otbLogMacro(Warning, << "sizemode is auto but sizevalue is 0. Value will be fetched from the OTB_MAX_RAM_HINT environment variable if set, or else use "
292  "the default value");
293  }
294  this->SetAutomaticAdaptativeStreaming(sizevalue);
295  }
296  else if (type == "tiled")
297  {
298  if (sizemode == "auto")
299  {
300  if (sizevalue == 0)
301  {
302  otbLogMacro(Warning, << "sizemode is auto but sizevalue is 0. Value will be fetched from the OTB_MAX_RAM_HINT environment variable if set, or else "
303  "use the default value");
304  }
305  this->SetAutomaticTiledStreaming(sizevalue);
306  }
307  else if (sizemode == "nbsplits")
308  {
309  if (sizevalue == 0)
310  {
311  otbLogMacro(Warning, << "Streaming sizemode is set to nbsplits but sizevalue is 0. This will result in undefined behaviour. Please consider setting "
312  "the sizevalue by using &streaming:sizevalue=x.");
313  }
314  this->SetNumberOfDivisionsTiledStreaming(sizevalue);
315  }
316  else if (sizemode == "height")
317  {
318  if (sizevalue == 0)
319  {
320  otbLogMacro(Warning, << "Streaming sizemode is set to height but sizevalue is 0. This will result in undefined behaviour. Please consider setting "
321  "the sizevalue by using &streaming:sizevalue=x.");
322  }
323 
324  this->SetTileDimensionTiledStreaming(sizevalue);
325  }
326  }
327  else if (type == "stripped")
328  {
329  if (sizemode == "auto")
330  {
331  if (sizevalue == 0)
332  {
333  otbLogMacro(
334  Warning, << "sizemode is auto but sizevalue is 0. Value will be fetched from configuration file if any, or from cmake configuration otherwise.");
335  }
336 
337  this->SetAutomaticStrippedStreaming(sizevalue);
338  }
339  else if (sizemode == "nbsplits")
340  {
341  if (sizevalue == 0)
342  {
343  otbLogMacro(Warning, << "Streaming sizemode is set to nbsplits but sizevalue is 0. This will result in undefined behaviour. Please consider setting "
344  "the sizevalue by using &streaming:sizevalue=x.");
345  }
346  this->SetNumberOfDivisionsStrippedStreaming(sizevalue);
347  }
348  else if (sizemode == "height")
349  {
350  if (sizevalue == 0)
351  {
352  otbLogMacro(Warning, << "Streaming sizemode is set to height but sizevalue is 0. This will result in undefined behaviour. Please consider setting "
353  "the sizevalue by using &streaming:sizevalue=x.");
354  }
355  this->SetNumberOfLinesStrippedStreaming(sizevalue);
356  }
357  }
358  else if (type == "none")
359  {
360  if (sizemode != "" || sizevalue != 0)
361  {
362  otbLogMacro(Warning, << "Streaming is explicitly disabled, sizemode and sizevalue will be ignored.");
363  }
364  this->SetNumberOfDivisionsTiledStreaming(0);
365  }
366 
367  // since we change the m_StreamingManager under the hood, we copy the DefaultRAM
368  // value to the new streamingManager.
369  m_StreamingManager->SetDefaultRAM(oldDefaultRAM);
370  }
371  else
372  {
373  if (m_FilenameHelper->StreamingSizeValueIsSet() || m_FilenameHelper->StreamingSizeModeIsSet())
374  {
375  otbLogMacro(Warning, << "No streaming type is set, streaming sizemode and sizevalue will be ignored.");
376  }
377  }
378 
381  if (m_FileName == "")
382  {
383  // Make sure that we can write the file given the name
384  itkExceptionMacro(<< "No filename was specified");
385  }
386 
387 
388  // Make sure CanWriteFile is called
389  // either from ImageIOFactory::CreateImageIO or directly in this file
390  // GDALImageIO uses it to store the filename
391  // and later answer to CanStreamWrite()
392  // This is a needed workaround to a defect in the itk::ImageIO interface
393 
394  if (m_ImageIO.IsNull()) // try creating via factory
395  {
396  this->SetImageIO(ImageIOFactory::CreateImageIO(m_FileName.c_str(), otb::ImageIOFactory::WriteMode));
397 
398  m_FactorySpecifiedImageIO = true;
399  }
400  else
401  {
402  if (!m_ImageIO->CanWriteFile(m_FileName.c_str()))
403  {
404  if (m_FactorySpecifiedImageIO)
405  {
406  m_ImageIO = ImageIOFactory::CreateImageIO(m_FileName.c_str(), otb::ImageIOFactory::WriteMode);
407  m_FactorySpecifiedImageIO = true;
408  }
409  }
410  }
411 
412  if (m_ImageIO.IsNull())
413  {
414  itk::ImageFileWriterException e(__FILE__, __LINE__);
415  std::ostringstream msg;
416  msg << "Cannot write image " << m_FileName << ". Probably unsupported format or incorrect filename extension.";
417  e.SetDescription(msg.str());
418  e.SetLocation(ITK_LOCATION);
419  throw e;
420  }
421 
422  // Manage extended filename
423  if ((strcmp(m_ImageIO->GetNameOfClass(), "GDALImageIO") == 0) &&
424  (m_FilenameHelper->gdalCreationOptionsIsSet() || m_FilenameHelper->WriteRPCTagsIsSet() || m_FilenameHelper->NoDataValueIsSet() || m_FilenameHelper->SrsValueIsSet()))
425  {
426  typename GDALImageIO::Pointer imageIO = dynamic_cast<GDALImageIO*>(m_ImageIO.GetPointer());
427 
428  if (imageIO.IsNull())
429  {
430  itk::ImageFileWriterException e(__FILE__, __LINE__);
431  std::ostringstream msg;
432  msg << " ImageIO is of kind GDALImageIO, but fails to dynamic_cast (this should never happen)." << std::endl;
433  e.SetDescription(msg.str());
434  throw e;
435  }
436 
437  imageIO->SetOptions(m_FilenameHelper->GetgdalCreationOptions());
438  imageIO->SetWriteRPCTags(m_FilenameHelper->GetWriteRPCTags());
439  if (m_FilenameHelper->NoDataValueIsSet())
440  imageIO->SetNoDataList(m_FilenameHelper->GetNoDataList());
441  if (m_FilenameHelper->SrsValueIsSet())
442  imageIO->SetEpsgCode(m_FilenameHelper->GetSrsValue());
443  }
444 
445 
451  InputImageRegionType inputRegion = inputPtr->GetLargestPossibleRegion();
452 
454  if (m_FilenameHelper->BoxIsSet())
455  {
456  std::vector<unsigned int> boxVector;
457  Utils::ConvertStringToVector(m_FilenameHelper->GetBox(), boxVector, "ExtendedFileName:box", ":");
459 
460  if (boxVector.size() != 4)
461  {
462  itk::ImageFileWriterException e(__FILE__, __LINE__);
463  std::ostringstream msg;
464  msg << "Invalid box option " << m_FilenameHelper->GetBox() << ". The box should contains four elements: startx:starty:sizex:sizey";
465  e.SetDescription(msg.str());
466  e.SetLocation(ITK_LOCATION);
467  throw e;
468  }
469 
470  typename InputImageRegionType::IndexType start;
471  typename InputImageRegionType::SizeType size;
472  start[0] = boxVector[0]; // first index on X
473  start[1] = boxVector[1]; // first index on Y
474  size[0] = boxVector[2]; // size along X
475  size[1] = boxVector[3]; // size along Y
476 
477  inputRegion.SetSize(size);
478  inputRegion.SetIndex(start);
479 
480  if (!inputRegion.Crop(inputPtr->GetLargestPossibleRegion()))
481  {
482  // Couldn't crop the region (requested region is outside the largest
483  // possible region). Throw an exception.
484 
485  // build an exception
486  itk::InvalidRequestedRegionError e(__FILE__, __LINE__);
487  e.SetLocation(ITK_LOCATION);
488  e.SetDescription("Requested box region is (at least partially) outside the largest possible region.");
489  e.SetDataObject(inputPtr);
490  throw e;
491  }
492  otbLogMacro(Info, << "Writing user defined region [" << start[0] << ", " << start[0] + size[0] - 1 << "]x[" << start[1] << ", " << start[1] + size[1]
493  << "]");
494  }
495  m_ShiftOutputIndex = inputRegion.GetIndex();
496 
504  if (m_ImageIO->CanStreamWrite() == false)
505  {
506  otbLogMacro(Warning, << "The file format of " << m_FileName << " does not support streaming. All data will be loaded to memory");
507  this->SetNumberOfDivisionsStrippedStreaming(1);
508  }
510 
514  else if (inputPtr->GetBufferedRegion() == inputRegion)
515  {
516  otbLogMacro(Debug, << "Buffered region is the largest possible region, there is no need for streaming.");
517  this->SetNumberOfDivisionsStrippedStreaming(1);
518  }
519  m_StreamingManager->PrepareStreaming(inputPtr, inputRegion);
520  m_NumberOfDivisions = m_StreamingManager->GetNumberOfSplits();
522 
523  const auto firstSplitSize = m_StreamingManager->GetSplit(0).GetSize();
524  otbLogMacro(Info, << "File " << m_FileName << " will be written in " << m_NumberOfDivisions << " blocks of " << firstSplitSize[0] << "x" << firstSplitSize[1]
525  << " pixels");
526 
527  //
528  // Setup the ImageIO with information from inputPtr
529  //
530  typename TInputImage::PointType origin;
531  inputPtr->TransformIndexToPhysicalPoint(inputRegion.GetIndex(), origin);
532  const typename TInputImage::SpacingType& spacing = inputPtr->GetSpacing();
533  const typename TInputImage::DirectionType& direction = inputPtr->GetDirection();
534  m_ImageIO->SetNumberOfDimensions(TInputImage::ImageDimension);
535  int direction_sign(0);
536  for (unsigned int i = 0; i < TInputImage::ImageDimension; ++i)
537  {
538  if (direction[i][i] < 0)
539  direction_sign = -1;
540  else
541  direction_sign = 1;
542  // Final image size
543  m_ImageIO->SetDimensions(i, inputRegion.GetSize(i));
544  m_ImageIO->SetSpacing(i, direction_sign * spacing[i]);
545  m_ImageIO->SetOrigin(i, origin[i]);
546 
547  vnl_vector<double> axisDirection(TInputImage::ImageDimension);
548  // Please note: direction cosines are stored as columns of the
549  // direction matrix
550  for (unsigned int j = 0; j < TInputImage::ImageDimension; ++j)
551  {
552  axisDirection[j] = direction_sign * direction[j][i];
553  }
554  m_ImageIO->SetDirection(i, axisDirection);
555  }
556 
557  m_ImageIO->SetUseCompression(m_UseCompression);
558  m_ImageIO->SetMetaDataDictionary(inputPtr->GetMetaDataDictionary());
559 
560  const ImageCommons* img_common = dynamic_cast<const ImageCommons*>(inputPtr.GetPointer());
561  if (img_common != nullptr)
562  {
563  m_ImageIO->SetImageMetadata(img_common->GetImageMetadata());
564  }
565 
567  // Setup the image IO for writing.
568  //
569  m_ImageIO->SetFileName(m_FileName);
570 
571  m_ImageIO->WriteImageInformation();
572 }
573 
577 template <class TInputImage>
579 {
580  this->UpdateOutputInformation();
581 
582  this->SetAbortGenerateData(0);
583  this->SetProgress(0.0);
584 
588  this->InvokeEvent(itk::StartEvent());
589 
590  this->UpdateProgress(0);
591  m_CurrentDivision = 0;
592  m_DivisionProgress = 0;
593 
594  // Get the source process object
595  InputImagePointer inputPtr = const_cast<InputImageType*>(this->GetInput());
596  itk::ProcessObject* source = inputPtr->GetSource();
597  m_IsObserving = false;
598  m_ObserverID = 0;
599 
600  // Check if source exists
601  if (source)
602  {
603  typedef itk::MemberCommand<Self> CommandType;
604  typedef typename CommandType::Pointer CommandPointerType;
605 
606  CommandPointerType command = CommandType::New();
607  command->SetCallbackFunction(this, &Self::ObserveSourceFilterProgress);
608 
609  m_ObserverID = source->AddObserver(itk::ProgressEvent(), command);
610  m_IsObserving = true;
611  }
612  else
613  {
614  otbLogMacro(Warning, << "Could not get the source process object. Progress report might be buggy");
615  }
616 
621  InputImageRegionType streamRegion;
622 
623  for (m_CurrentDivision = 0; m_CurrentDivision < m_NumberOfDivisions && !this->GetAbortGenerateData();
624  m_CurrentDivision++, m_DivisionProgress = 0, this->UpdateFilterProgress())
625  {
626  streamRegion = m_StreamingManager->GetSplit(m_CurrentDivision);
627 
628  inputPtr->SetRequestedRegion(streamRegion);
629  inputPtr->PropagateRequestedRegion();
630  inputPtr->UpdateOutputData();
631 
632  // Write the whole image
633  itk::ImageIORegion ioRegion(TInputImage::ImageDimension);
634  for (unsigned int i = 0; i < TInputImage::ImageDimension; ++i)
635  {
636  ioRegion.SetSize(i, streamRegion.GetSize(i));
637  // Set the ioRegion index using the shifted index ( (0,0 without box parameter))
638  ioRegion.SetIndex(i, streamRegion.GetIndex(i) - m_ShiftOutputIndex[i]);
639  }
640  this->SetIORegion(ioRegion);
641  m_ImageIO->SetIORegion(m_IORegion);
642 
643  // Start writing stream region in the image file
644  this->GenerateData();
645  }
646 
651  if (!this->GetAbortGenerateData())
652  {
653  this->UpdateProgress(1.0);
654  }
655  else
656  {
657  itk::ProcessAborted e(__FILE__, __LINE__);
658  e.SetLocation(ITK_LOCATION);
659  e.SetDescription("Image writing has been aborted");
660  throw e;
661  }
663 
664  // Notify end event observers
665  this->InvokeEvent(itk::EndEvent());
666 
667  if (m_IsObserving)
668  {
669  m_IsObserving = false;
670  source->RemoveObserver(m_ObserverID);
671  }
672 
676  this->ReleaseInputs();
677 
678  // Reset global shift on input region (box parameter)
679  // It allows calling multiple update over the writer
680  m_ShiftOutputIndex = inputPtr->GetLargestPossibleRegion().GetIndex();
681 }
682 
683 
687 template <class TInputImage>
689 {
690  const InputImageType* input = this->GetInput();
691  InputImagePointer cacheImage;
693 
694  // Make sure that the image is the right type and no more than
695  // four components.
696  typedef typename InputImageType::PixelType ImagePixelType;
697 
698  if (strcmp(input->GetNameOfClass(), "VectorImage") == 0)
699  {
700  typedef typename InputImageType::InternalPixelType VectorImagePixelType;
701  m_ImageIO->SetPixelTypeInfo(typeid(VectorImagePixelType));
702 
703  typedef typename InputImageType::AccessorFunctorType AccessorFunctorType;
704  m_ImageIO->SetNumberOfComponents(AccessorFunctorType::GetVectorLength(input));
705 
706  m_IOComponents = m_ImageIO->GetNumberOfComponents();
707  m_BandList.clear();
708  if (m_FilenameHelper->BandRangeIsSet())
709  {
710  // get band range
711  bool retBandRange = m_FilenameHelper->ResolveBandRange(m_FilenameHelper->GetBandRange(), m_IOComponents, m_BandList);
712  if (retBandRange == false || m_BandList.empty())
713  {
714  // invalid range
715  itkGenericExceptionMacro("The given band range is either empty or invalid for a " << m_IOComponents << " bands input image!");
716  }
717  }
718  }
719  else
720  {
721  // Set the pixel and component type; the number of components.
722  m_ImageIO->SetPixelTypeInfo(typeid(ImagePixelType));
723  }
724 
725  // Setup the image IO for writing.
726  //
727  // okay, now extract the data as a raw buffer pointer
728  const void* dataPtr = (const void*)input->GetBufferPointer();
729 
730  // check that the image's buffered region is the same as
731  // ImageIO is expecting and we requested
732  InputImageRegionType ioRegion;
733 
734  // No shift of the ioRegion from the buffered region is expected
735  itk::ImageIORegionAdaptor<TInputImage::ImageDimension>::Convert(m_ImageIO->GetIORegion(), ioRegion, m_ShiftOutputIndex);
736  InputImageRegionType bufferedRegion = input->GetBufferedRegion();
737 
738  // before this test, bad stuff would happened when they don't match.
739  // In case of the buffer has not enough components, adapt the region.
740  if ((bufferedRegion != ioRegion) || (m_FilenameHelper->BandRangeIsSet() && (m_IOComponents < m_BandList.size())))
741  {
742  if (m_NumberOfDivisions > 1 || m_UserSpecifiedIORegion)
743  {
744  cacheImage = InputImageType::New();
745  cacheImage->CopyInformation(input);
746 
747  // set number of components at the band range size
748  if (m_FilenameHelper->BandRangeIsSet() && (m_IOComponents < m_BandList.size()))
749  {
750  cacheImage->SetNumberOfComponentsPerPixel(m_BandList.size());
751  }
752 
753  cacheImage->SetBufferedRegion(ioRegion);
754  cacheImage->Allocate();
755 
756  // set number of components at the initial size
757  if (m_FilenameHelper->BandRangeIsSet() && (m_IOComponents < m_BandList.size()))
758  {
759  cacheImage->SetNumberOfComponentsPerPixel(m_IOComponents);
760  }
761 
762  typedef itk::ImageRegionConstIterator<TInputImage> ConstIteratorType;
763  typedef itk::ImageRegionIterator<TInputImage> IteratorType;
764 
765  ConstIteratorType in(input, ioRegion);
766  IteratorType out(cacheImage, ioRegion);
767 
768  // copy the data into a buffer to match the ioregion
769  for (in.GoToBegin(), out.GoToBegin(); !in.IsAtEnd(); ++in, ++out)
770  {
771  out.Set(in.Get());
772  }
773 
774  dataPtr = (const void*)cacheImage->GetBufferPointer();
775  }
776  else
777  {
778  itk::ImageFileWriterException e(__FILE__, __LINE__);
779  std::ostringstream msg;
780  msg << "Did not get requested region!" << std::endl;
781  msg << "Requested:" << std::endl;
782  msg << ioRegion;
783  msg << "Actual:" << std::endl;
784  msg << bufferedRegion;
785  e.SetDescription(msg.str());
786  e.SetLocation(ITK_LOCATION);
787  throw e;
788  }
789  }
790 
791  if (m_FilenameHelper->BandRangeIsSet() && (!m_BandList.empty()))
792  {
793  // Adapt the image size with the region and take into account a potential
794  // remapping of the components. m_BandList is empty if no band range is set
795  m_ImageIO->DoMapBuffer(const_cast<void*>(dataPtr), bufferedRegion.GetNumberOfPixels(), this->m_BandList);
796  m_ImageIO->SetNumberOfComponents(m_BandList.size());
797  }
798 
799  m_ImageIO->Write(dataPtr);
800 }
801 
802 template <class TInputImage>
803 void ImageFileWriter<TInputImage>::SetFileName(const std::string& extendedFileName)
804 {
805  this->m_FilenameHelper->SetExtendedFileName(extendedFileName);
806  m_FileName = this->m_FilenameHelper->GetSimpleFileName();
807  m_ImageIO = nullptr;
808  this->Modified();
809 }
810 
811 template <class TInputImage>
813 {
814  return this->m_FilenameHelper->GetSimpleFileName();
815 }
816 
817 template <class TInputImage>
819 {
820  m_Lock.Lock();
821  // protected read here
822  bool ret = Superclass::GetAbortGenerateData();
823  m_Lock.Unlock();
824  if (ret)
827 }
828 
829 template <class TInputImage>
831 {
832  m_Lock.Lock();
833  Superclass::SetAbortGenerateData(val);
834  m_Lock.Unlock();
835 }
836 
837 } // end namespace otb
838 
839 #endif
otb::NumberOfDivisionsTiledStreamingManager
This class computes the divisions needed to stream an image by strips, driven by a user-defined numbe...
Definition: otbNumberOfDivisionsTiledStreamingManager.h:42
otbImageIOFactory.h
otbTileDimensionTiledStreamingManager.h
otb::GDALImageIO::Pointer
itk::SmartPointer< Self > Pointer
Definition: otbGDALImageIO.h:88
otbNumberOfLinesStrippedStreamingManager.h
otb::NumberOfDivisionsStrippedStreamingManager
This class computes the divisions needed to stream an image by strips, driven by a user-defined numbe...
Definition: otbNumberOfDivisionsStrippedStreamingManager.h:43
otbRAMDrivenTiledStreamingManager.h
otb::ImageCommons::SetImageMetadata
void SetImageMetadata(ImageMetadata imd)
otb::RAMDrivenTiledStreamingManager
This class computes the divisions needed to stream an image in square tiles, according to a user-defi...
Definition: otbRAMDrivenTiledStreamingManager.h:43
otbLogMacro
#define otbLogMacro(level, msg)
Definition: otbMacro.h:52
otb::TileDimensionTiledStreamingManager
This class computes the divisions needed to stream an image in square tiles, driven by a user-defined...
Definition: otbTileDimensionTiledStreamingManager.h:46
otbUtils.h
otb::Wrapper::ImagePixelType
ImagePixelType
Definition: otbWrapperTypes.h:104
otb::Utils::FalseConstant
OTBCommon_EXPORT const bool FalseConstant
otb
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.
Definition: otbJoinContainer.h:32
otb::RAMDrivenStrippedStreamingManager
This class computes the divisions needed to stream an image by strips, according to a user-defined av...
Definition: otbRAMDrivenStrippedStreamingManager.h:44
otb::NumberOfLinesStrippedStreamingManager
This class computes the divisions needed to stream an image by strips, driven by a user-defined desir...
Definition: otbNumberOfLinesStrippedStreamingManager.h:43
otb::Logger::Instance
static Logger * Instance()
otb::GDALImageIO
ImageIO object for reading and writing images with GDAL.
Definition: otbGDALImageIO.h:77
otb::ImageIOFactory::WriteMode
@ WriteMode
Definition: otbImageIOFactory.h:53
otb::ImageCommons::GetImageMetadata
const ImageMetadata & GetImageMetadata() const
otb::ImageCommons
Definition: otbImageCommons.h:31
otb::RAMDrivenAdaptativeStreamingManager
This class computes the divisions needed to stream an image according to the input image tiling schem...
Definition: otbRAMDrivenAdaptativeStreamingManager.h:49
otbRAMDrivenStrippedStreamingManager.h
otb::Utils::TrueConstant
OTBCommon_EXPORT const bool TrueConstant
otbMetaDataKey.h
otbStringUtils.h
otb::Utils::ConvertStringToVector
void ConvertStringToVector(std::string const &str, T &ret, std::string const &errmsg, const char *delims=" ")
Definition: otbStringUtils.h:83
otb::ImageFileWriter
Writes image data to a single file with streaming process.
Definition: otbImageFileWriter.h:66
otbRAMDrivenAdaptativeStreamingManager.h
otb::ImageFileWriter::ImageFileWriter
ImageFileWriter()
Definition: otbImageFileWriter.hxx:61
otbNumberOfDivisionsStrippedStreamingManager.h
otbImageFileWriter.h
otb::ImageFileWriter< TImage >::InputImageType
TImage InputImageType
Definition: otbImageFileWriter.h:79
otb::ImageFileWriter< TImage >::InputImagePointer
InputImageType::Pointer InputImagePointer
Definition: otbImageFileWriter.h:83
otb_boost_tokenizer_header.h
otbNumberOfDivisionsTiledStreamingManager.h
otbImageCommons.h
otb::ImageFileWriter< TImage >::InputImageRegionType
InputImageType::RegionType InputImageRegionType
Definition: otbImageFileWriter.h:84