OTB  6.7.0
Orfeo Toolbox
otbImageFileWriter.hxx
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES)
3  * Copyright (C) 2018 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 
31 #include "otbImageIOFactory.h"
32 
33 #include "itkImageRegionIterator.h"
34 
35 #include "itkMetaDataObject.h"
36 #include "otbImageKeywordlist.h"
37 #include "otbMetaDataKey.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>
63  : m_NumberOfDivisions(0),
64  m_CurrentDivision(0),
65  m_DivisionProgress(0.0),
66  m_UserSpecifiedImageIO(true),
67  m_UserSpecifiedIORegion(false),
68  m_FactorySpecifiedImageIO(false),
69  m_UseCompression(false),
70  m_UseInputMetaDataDictionary(false),
71  m_WriteGeomFile(false),
72  m_FilenameHelper(),
73  m_IsObserving(true),
74  m_ObserverID(0),
75  m_IOComponents(0)
76 {
77  //Init output index shift
78  m_ShiftOutputIndex.Fill(0);
79 
80  // By default, we use tiled streaming, with automatic tile size
81  // We don't set any parameter, so the memory size is retrieved from the OTB configuration options
82  this->SetAutomaticAdaptativeStreaming();
83 
84  m_FilenameHelper = FNameHelperType::New();
85 }
86 
90 template <class TInputImage>
93 {
94 }
95 
96 template <class TInputImage>
97 void
99 ::SetNumberOfDivisionsStrippedStreaming(unsigned int nbDivisions)
100 {
101  typedef NumberOfDivisionsStrippedStreamingManager<TInputImage> NumberOfDivisionsStrippedStreamingManagerType;
102  typename NumberOfDivisionsStrippedStreamingManagerType::Pointer streamingManager = NumberOfDivisionsStrippedStreamingManagerType::New();
103  streamingManager->SetNumberOfDivisions(nbDivisions);
104  m_StreamingManager = streamingManager;
105 }
106 
107 template <class TInputImage>
108 void
110 ::SetNumberOfDivisionsTiledStreaming(unsigned int nbDivisions)
111 {
112  typedef NumberOfDivisionsTiledStreamingManager<TInputImage> NumberOfDivisionsTiledStreamingManagerType;
113  typename NumberOfDivisionsTiledStreamingManagerType::Pointer streamingManager = NumberOfDivisionsTiledStreamingManagerType::New();
114  streamingManager->SetNumberOfDivisions(nbDivisions);
115  m_StreamingManager = streamingManager;
116 }
117 
118 template <class TInputImage>
119 void
121 ::SetNumberOfLinesStrippedStreaming(unsigned int nbLinesPerStrip)
122 {
123  typedef NumberOfLinesStrippedStreamingManager<TInputImage> NumberOfLinesStrippedStreamingManagerType;
124  typename NumberOfLinesStrippedStreamingManagerType::Pointer streamingManager = NumberOfLinesStrippedStreamingManagerType::New();
125  streamingManager->SetNumberOfLinesPerStrip(nbLinesPerStrip);
126  m_StreamingManager = streamingManager;
127 }
128 
129 template <class TInputImage>
130 void
132 ::SetAutomaticStrippedStreaming(unsigned int availableRAM, double bias)
133 {
134  typedef RAMDrivenStrippedStreamingManager<TInputImage> RAMDrivenStrippedStreamingManagerType;
135  typename RAMDrivenStrippedStreamingManagerType::Pointer streamingManager = RAMDrivenStrippedStreamingManagerType::New();
136  streamingManager->SetAvailableRAMInMB(availableRAM);
137  streamingManager->SetBias(bias);
138  m_StreamingManager = streamingManager;
139 }
140 
141 template <class TInputImage>
142 void
144 ::SetTileDimensionTiledStreaming(unsigned int tileDimension)
145 {
146  typedef TileDimensionTiledStreamingManager<TInputImage> TileDimensionTiledStreamingManagerType;
147  typename TileDimensionTiledStreamingManagerType::Pointer streamingManager = TileDimensionTiledStreamingManagerType::New();
148  streamingManager->SetTileDimension(tileDimension);
149  m_StreamingManager = streamingManager;
150 }
151 
152 template <class TInputImage>
153 void
155 ::SetAutomaticTiledStreaming(unsigned int availableRAM, double bias)
156 {
157  typedef RAMDrivenTiledStreamingManager<TInputImage> RAMDrivenTiledStreamingManagerType;
158  typename RAMDrivenTiledStreamingManagerType::Pointer streamingManager = RAMDrivenTiledStreamingManagerType::New();
159  streamingManager->SetAvailableRAMInMB(availableRAM);
160  streamingManager->SetBias(bias);
161  m_StreamingManager = streamingManager;
162 }
163 
164 template <class TInputImage>
165 void
167 ::SetAutomaticAdaptativeStreaming(unsigned int availableRAM, double bias)
168 {
169  typedef RAMDrivenAdaptativeStreamingManager<TInputImage> RAMDrivenAdaptativeStreamingManagerType;
170  typename RAMDrivenAdaptativeStreamingManagerType::Pointer streamingManager = RAMDrivenAdaptativeStreamingManagerType::New();
171  streamingManager->SetAvailableRAMInMB(availableRAM);
172  streamingManager->SetBias(bias);
173  m_StreamingManager = streamingManager;
174 }
175 
179 template <class TInputImage>
180 void
182 ::PrintSelf(std::ostream& os, itk::Indent indent) const
183 {
184  Superclass::PrintSelf(os, indent);
185 
186  os << indent << "File Name: "
187  << (m_FileName.data() ? m_FileName.data() : "(none)") << std::endl;
188 
189  os << indent << "Image IO: ";
190  if (m_ImageIO.IsNull())
191  {
192  os << "(none)\n";
193  }
194  else
195  {
196  os << m_ImageIO << "\n";
197  }
198 
199  os << indent << "IO Region: " << m_IORegion << "\n";
200 
201  if (m_UseCompression)
202  {
203  os << indent << "Compression: On\n";
204  }
205  else
206  {
207  os << indent << "Compression: Off\n";
208  }
209 
210  if (m_UseInputMetaDataDictionary)
211  {
212  os << indent << "UseInputMetaDataDictionary: On\n";
213  }
214  else
215  {
216  os << indent << "UseInputMetaDataDictionary: Off\n";
217  }
218 
219  if (m_FactorySpecifiedImageIO)
220  {
221  os << indent << "FactorySpecifiedmageIO: On\n";
222  }
223  else
224  {
225  os << indent << "FactorySpecifiedmageIO: Off\n";
226  }
227 }
228 
229 //---------------------------------------------------------
230 template<class TInputImage>
231 void
234 {
235  if (m_IORegion != region)
236  {
237  m_IORegion = region;
238  this->Modified();
239  m_UserSpecifiedIORegion = true;
240  }
241 }
242 
243 template<class TInputImage>
244 void
247 {
248  this->ProcessObject::SetNthInput(0,const_cast<InputImageType*>(input));
249 }
250 
251 template<class TInputImage>
252 const TInputImage*
255 {
256  if (this->GetNumberOfInputs() < 1)
257  {
258  return nullptr;
259  }
260 
261  return static_cast<const InputImageType*>(this->ProcessObject::GetInput(0));
262 }
263 
265 template<class TInputImage>
266 void
269 {
270  // Update output information on input image
271  InputImagePointer inputPtr =
272  const_cast<InputImageType *>(this->GetInput());
273 
274  // Make sure input is available
275  if ( inputPtr.IsNull() )
276  {
277  itkExceptionMacro(<< "No input to writer");
278  }
279 
280  otb::Logger::Instance()->LogSetupInformation();
281 
283  if(m_FilenameHelper->StreamingTypeIsSet())
284  {
285  otbLogMacro(Warning,<<"Streaming configuration through extended filename is used. Any previous streaming configuration (ram value, streaming mode ...) will be ignored.");
286 
287  std::string type = m_FilenameHelper->GetStreamingType();
288 
289  std::string sizemode = "auto";
290 
291  if(m_FilenameHelper->StreamingSizeModeIsSet())
292  {
293  sizemode = m_FilenameHelper->GetStreamingSizeMode();
294  }
295 
296  unsigned int sizevalue = 0;
297  // Save the DefaultRAM value for later
298  unsigned int oldDefaultRAM = m_StreamingManager->GetDefaultRAM();
299  if (sizemode == "auto")
300  {
301  sizevalue = oldDefaultRAM;
302  }
303 
304  if(m_FilenameHelper->StreamingSizeValueIsSet())
305  {
306  sizevalue = static_cast<unsigned int>(m_FilenameHelper->GetStreamingSizeValue());
307  }
308 
309  if(type == "auto")
310  {
311  if(sizemode != "auto")
312  {
313  otbLogMacro(Warning,<<"In auto streaming type, the sizemode option will be ignored.");
314  }
315  if(sizevalue == 0)
316  {
317  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 the default value");
318  }
319  this->SetAutomaticAdaptativeStreaming(sizevalue);
320  }
321  else if(type == "tiled")
322  {
323  if(sizemode == "auto")
324  {
325  if(sizevalue == 0)
326  {
327  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 the default value");
328  }
329  this->SetAutomaticTiledStreaming(sizevalue);
330  }
331  else if(sizemode == "nbsplits")
332  {
333  if(sizevalue == 0)
334  {
335  otbLogMacro(Warning,<<"Streaming sizemode is set to nbsplits but sizevalue is 0. This will result in upredicted behaviour. Please consider setting the sizevalue by using &streaming:sizevalue=x.");
336  }
337  this->SetNumberOfDivisionsTiledStreaming(sizevalue);
338  }
339  else if(sizemode == "height")
340  {
341  if(sizevalue == 0)
342  {
343  otbLogMacro(Warning,<<"Streaming sizemode is set to height but sizevalue is 0. This will result in upredicted behaviour. Please consider setting the sizevalue by using &streaming:sizevalue=x.");
344  }
345 
346  this->SetTileDimensionTiledStreaming(sizevalue);
347  }
348  }
349  else if(type == "stripped")
350  {
351  if(sizemode == "auto")
352  {
353  if(sizevalue == 0)
354  {
355  otbLogMacro(Warning,<<"sizemode is auto but sizevalue is 0. Value will be fetched from configuration file if any, or from cmake configuration otherwise.");
356  }
357 
358  this->SetAutomaticStrippedStreaming(sizevalue);
359  }
360  else if(sizemode == "nbsplits")
361  {
362  if(sizevalue == 0)
363  {
364  otbLogMacro(Warning,<<"Streaming sizemode is set to nbsplits but sizevalue is 0. This will result in upredicted behaviour. Please consider setting the sizevalue by using &streaming:sizevalue=x.");
365  }
366  this->SetNumberOfDivisionsStrippedStreaming(sizevalue);
367  }
368  else if(sizemode == "height")
369  {
370  if(sizevalue == 0)
371  {
372  otbLogMacro(Warning,<<"Streaming sizemode is set to height but sizevalue is 0. This will result in upredicted behaviour. Please consider setting the sizevalue by using &streaming:sizevalue=x.");
373  }
374  this->SetNumberOfLinesStrippedStreaming(sizevalue);
375  }
376 
377  }
378  else if (type == "none")
379  {
380  if(sizemode!="" || sizevalue!=0)
381  {
382  otbLogMacro(Warning,<<"Streaming is explicitly disabled, sizemode and sizevalue will be ignored.");
383  }
384  this->SetNumberOfDivisionsTiledStreaming(0);
385  }
386 
387  // since we change the m_StreamingManager under the hood, we copy the DefaultRAM
388  // value to the new streamingManager.
389  m_StreamingManager->SetDefaultRAM(oldDefaultRAM);
390  }
391  else
392  {
393  if(m_FilenameHelper->StreamingSizeValueIsSet() || m_FilenameHelper->StreamingSizeModeIsSet())
394  {
395  otbLogMacro(Warning,<<"No streaming type is set, streaming sizemode and sizevalue will be ignored.");
396  }
397  }
398 
401  if (m_FileName == "")
402  {
403  // Make sure that we can write the file given the name
404  itkExceptionMacro(<< "No filename was specified");
405  }
406 
407 
408  // Make sure CanWriteFile is called
409  // either from ImageIOFactory::CreateImageIO or directly in this file
410  // GDALImageIO uses it to store the filename
411  // and later answer to CanStreamWrite()
412  // This is a needed workaround to a defect in the itk::ImageIO interface
413 
414  if (m_ImageIO.IsNull()) //try creating via factory
415  {
416  this->SetImageIO(ImageIOFactory::CreateImageIO(m_FileName.c_str(),
418 
419  m_FactorySpecifiedImageIO = true;
420  }
421  else
422  {
423  if (!m_ImageIO->CanWriteFile(m_FileName.c_str()))
424  {
425  if (m_FactorySpecifiedImageIO)
426  {
427  m_ImageIO = ImageIOFactory::CreateImageIO(m_FileName.c_str(),
429  m_FactorySpecifiedImageIO = true;
430  }
431  }
432 
433  }
434 
435  if (m_ImageIO.IsNull())
436  {
437  itk::ImageFileWriterException e(__FILE__, __LINE__);
438  std::ostringstream msg;
439  msg << "Cannot write image " << m_FileName << ". Probably unsupported format or incorrect filename extension.";
440  e.SetDescription(msg.str());
441  e.SetLocation(ITK_LOCATION);
442  throw e;
443  }
444 
445  // Manage extended filename
446  if ((strcmp(m_ImageIO->GetNameOfClass(), "GDALImageIO") == 0)
447  && (m_FilenameHelper->gdalCreationOptionsIsSet() || m_FilenameHelper->WriteRPCTagsIsSet() || m_FilenameHelper->NoDataValueIsSet()) )
448  {
449  typename GDALImageIO::Pointer imageIO = dynamic_cast<GDALImageIO*>(m_ImageIO.GetPointer());
450 
451  if(imageIO.IsNull())
452  {
453  itk::ImageFileWriterException e(__FILE__, __LINE__);
454  std::ostringstream msg;
455  msg << " ImageIO is of kind GDALImageIO, but fails to dynamic_cast (this should never happen)."<< std::endl;
456  e.SetDescription(msg.str());
457  throw e;
458  }
459 
460  imageIO->SetOptions(m_FilenameHelper->GetgdalCreationOptions());
461  imageIO->SetWriteRPCTags(m_FilenameHelper->GetWriteRPCTags());
462  if (m_FilenameHelper->NoDataValueIsSet() )
463  imageIO->SetNoDataList(m_FilenameHelper->GetNoDataList());
464  }
465 
466 
472  InputImageRegionType inputRegion = inputPtr->GetLargestPossibleRegion();
473 
475  if(m_FilenameHelper->BoxIsSet())
476  {
477  std::vector<int> boxVector;
479  m_FilenameHelper->GetBox(), boxVector, "ExtendedFileName:box", ":");
481 
482  typename InputImageRegionType::IndexType start;
483  typename InputImageRegionType::SizeType size;
484 
485  start[0] = boxVector[0]; // first index on X
486  start[1] = boxVector[1]; // first index on Y
487  size[0] = boxVector[2]; // size along X
488  size[1] = boxVector[3]; // size along Y
489  inputRegion.SetSize(size);
490  inputRegion.SetIndex(start);
491 
492  if (!inputRegion.Crop(inputPtr->GetLargestPossibleRegion()))
493  {
494  // Couldn't crop the region (requested region is outside the largest
495  // possible region). Throw an exception.
496 
497  // build an exception
498  itk::InvalidRequestedRegionError e(__FILE__, __LINE__);
499  e.SetLocation(ITK_LOCATION);
500  e.SetDescription("Requested box region is (at least partially) outside the largest possible region.");
501  e.SetDataObject(inputPtr);
502  throw e;
503  }
504  otbLogMacro(Info,<<"Writing user defined region ["<<start[0]<<", "<<start[0]+size[0]-1<<"]x["<<start[1]<<", "<<start[1]+size[1]<<"]");
505  }
506  m_ShiftOutputIndex = inputRegion.GetIndex();
507 
515  if (m_ImageIO->CanStreamWrite() == false)
516  {
517  otbLogMacro(Warning,<<"The file format of " << m_FileName <<
518  " does not support streaming. All data will be loaded to memory");
519  this->SetNumberOfDivisionsStrippedStreaming(1);
520  }
522 
526  else if (inputPtr->GetBufferedRegion() == inputRegion)
527  {
528  otbLogMacro(Debug,<< "Buffered region is the largest possible region, there is no need for streaming.");
529  this->SetNumberOfDivisionsStrippedStreaming(1);
530  }
531  m_StreamingManager->PrepareStreaming(inputPtr, inputRegion);
532  m_NumberOfDivisions = m_StreamingManager->GetNumberOfSplits();
534 
535  const auto firstSplitSize = m_StreamingManager->GetSplit(0).GetSize();
536  otbLogMacro(Info,<<"File "<<m_FileName<<" will be written in "<<m_NumberOfDivisions<<" blocks of "<<firstSplitSize[0]<<"x"<<firstSplitSize[1]<<" pixels");
537 
538  //
539  // Setup the ImageIO with information from inputPtr
540  //
541  typename TInputImage::PointType origin;
542  inputPtr->TransformIndexToPhysicalPoint(inputRegion.GetIndex(), origin);
543  const typename TInputImage::SpacingType& spacing = inputPtr->GetSpacing();
544  const typename TInputImage::DirectionType& direction = inputPtr->GetDirection();
545  m_ImageIO->SetNumberOfDimensions(TInputImage::ImageDimension);
546  int direction_sign(0);
547  for (unsigned int i = 0; i < TInputImage::ImageDimension; ++i)
548  {
549  if ( direction[i][i] < 0 )
550  direction_sign = -1;
551  else
552  direction_sign = 1;
553  // Final image size
554  m_ImageIO->SetDimensions(i, inputRegion.GetSize(i));
555  m_ImageIO->SetSpacing(i, direction_sign * spacing[i]);
556  m_ImageIO->SetOrigin(i, origin[i]);
557 
558  vnl_vector<double> axisDirection(TInputImage::ImageDimension);
559  // Please note: direction cosines are stored as columns of the
560  // direction matrix
561  for (unsigned int j = 0; j < TInputImage::ImageDimension; ++j)
562  {
563  axisDirection[j] = direction_sign * direction[j][i];
564  }
565  m_ImageIO->SetDirection(i, axisDirection);
566  }
567 
568  m_ImageIO->SetUseCompression(m_UseCompression);
569  m_ImageIO->SetMetaDataDictionary(inputPtr->GetMetaDataDictionary());
570 
572  // Setup the image IO for writing.
573  //
574  m_ImageIO->SetFileName(m_FileName);
575 
576  m_ImageIO->WriteImageInformation();
577 }
578 
582 template<class TInputImage>
583 void
586 {
587  this->UpdateOutputInformation();
588 
589  this->SetAbortGenerateData(0);
590  this->SetProgress(0.0);
591 
595  this->InvokeEvent(itk::StartEvent());
596 
597  this->UpdateProgress(0);
598  m_CurrentDivision = 0;
599  m_DivisionProgress = 0;
600 
601  // Get the source process object
602  InputImagePointer inputPtr =
603  const_cast<InputImageType *>(this->GetInput());
604  itk::ProcessObject* source = inputPtr->GetSource();
605  m_IsObserving = false;
606  m_ObserverID = 0;
607 
608  // Check if source exists
609  if(source)
610  {
611  typedef itk::MemberCommand<Self> CommandType;
612  typedef typename CommandType::Pointer CommandPointerType;
613 
614  CommandPointerType command = CommandType::New();
615  command->SetCallbackFunction(this, &Self::ObserveSourceFilterProgress);
616 
617  m_ObserverID = source->AddObserver(itk::ProgressEvent(), command);
618  m_IsObserving = true;
619  }
620  else
621  {
622  otbLogMacro(Warning,<< "Could not get the source process object. Progress report might be buggy");
623  }
624 
629  InputImageRegionType streamRegion;
630 
631  for (m_CurrentDivision = 0;
632  m_CurrentDivision < m_NumberOfDivisions && !this->GetAbortGenerateData();
633  m_CurrentDivision++, m_DivisionProgress = 0, this->UpdateFilterProgress())
634  {
635  streamRegion = m_StreamingManager->GetSplit(m_CurrentDivision);
636 
637  inputPtr->SetRequestedRegion(streamRegion);
638  inputPtr->PropagateRequestedRegion();
639  inputPtr->UpdateOutputData();
640 
641  // Write the whole image
642  itk::ImageIORegion ioRegion(TInputImage::ImageDimension);
643  for (unsigned int i = 0; i < TInputImage::ImageDimension; ++i)
644  {
645  ioRegion.SetSize(i, streamRegion.GetSize(i));
646  //Set the ioRegion index using the shifted index ( (0,0 without box parameter))
647  ioRegion.SetIndex(i, streamRegion.GetIndex(i) - m_ShiftOutputIndex[i]);
648  }
649  this->SetIORegion(ioRegion);
650  m_ImageIO->SetIORegion(m_IORegion);
651 
652  // Start writing stream region in the image file
653  this->GenerateData();
654  }
655 
660  if (!this->GetAbortGenerateData())
661  {
662  this->UpdateProgress(1.0);
663  }
664  else
665  {
666  itk::ProcessAborted e(__FILE__, __LINE__);
667  e.SetLocation(ITK_LOCATION);
668  e.SetDescription("Image writing has been aborted");
669  throw e;
670  }
672 
673  // Notify end event observers
674  this->InvokeEvent(itk::EndEvent());
675 
676  if (m_IsObserving)
677  {
678  m_IsObserving = false;
679  source->RemoveObserver(m_ObserverID);
680  }
681 
682  // Write the image keyword list if any
683  // ossimKeywordlist geom_kwl;
684  // ImageKeywordlist otb_kwl;
685 
686  // itk::MetaDataDictionary dict = this->GetInput()->GetMetaDataDictionary();
687  // itk::ExposeMetaData<ImageKeywordlist>(dict, MetaDataKey::OSSIMKeywordlistKey, otb_kwl);
688  // otb_kwl.convertToOSSIMKeywordlist(geom_kwl);
689  //FIXME: why nothing is done with otb_kwl in that case???
690  // If required, put a call to WriteGeometry() here
691 
695  this->ReleaseInputs();
696 
697  //Reset global shift on input region (box parameter)
698  //It allows calling multiple update over the writer
699  m_ShiftOutputIndex = inputPtr->GetLargestPossibleRegion().GetIndex();
700 }
701 
702 
706 template<class TInputImage>
707 void
710 {
711  const InputImageType * input = this->GetInput();
712  InputImagePointer cacheImage;
714 
715  // Make sure that the image is the right type and no more than
716  // four components.
717  typedef typename InputImageType::PixelType ImagePixelType;
718 
719  if (strcmp(input->GetNameOfClass(), "VectorImage") == 0)
720  {
721  typedef typename InputImageType::InternalPixelType VectorImagePixelType;
722  m_ImageIO->SetPixelTypeInfo(typeid(VectorImagePixelType));
723 
724  typedef typename InputImageType::AccessorFunctorType AccessorFunctorType;
725  m_ImageIO->SetNumberOfComponents(AccessorFunctorType::GetVectorLength(input));
726 
727  m_IOComponents = m_ImageIO->GetNumberOfComponents();
728  m_BandList.clear();
729  if (m_FilenameHelper->BandRangeIsSet())
730  {
731  // get band range
732  bool retBandRange = m_FilenameHelper->ResolveBandRange(m_FilenameHelper->GetBandRange(), m_IOComponents, m_BandList);
733  if (retBandRange == false || m_BandList.empty())
734  {
735  // invalid range
736  itkGenericExceptionMacro("The given band range is either empty or invalid for a " << m_IOComponents <<" bands input image!");
737  }
738  }
739  }
740  else
741  {
742  // Set the pixel and component type; the number of components.
743  m_ImageIO->SetPixelTypeInfo(typeid(ImagePixelType));
744  }
745 
746  // Setup the image IO for writing.
747  //
748  //okay, now extract the data as a raw buffer pointer
749  const void* dataPtr = (const void*) input->GetBufferPointer();
750 
751  // check that the image's buffered region is the same as
752  // ImageIO is expecting and we requested
753  InputImageRegionType ioRegion;
754 
755  // No shift of the ioRegion from the buffered region is expected
757  Convert(m_ImageIO->GetIORegion(), ioRegion, m_ShiftOutputIndex);
758  InputImageRegionType bufferedRegion = input->GetBufferedRegion();
759 
760  // before this test, bad stuff would happened when they don't match.
761  // In case of the buffer has not enough components, adapt the region.
762  if ((bufferedRegion != ioRegion) || (m_FilenameHelper->BandRangeIsSet()
763  && (m_IOComponents < m_BandList.size())))
764  {
765  if ( m_NumberOfDivisions > 1 || m_UserSpecifiedIORegion)
766  {
767  cacheImage = InputImageType::New();
768  cacheImage->CopyInformation(input);
769 
770  // set number of components at the band range size
771  if (m_FilenameHelper->BandRangeIsSet() && (m_IOComponents < m_BandList.size()))
772  {
773  cacheImage->SetNumberOfComponentsPerPixel(m_BandList.size());
774  }
775 
776  cacheImage->SetBufferedRegion(ioRegion);
777  cacheImage->Allocate();
778 
779  // set number of components at the initial size
780  if (m_FilenameHelper->BandRangeIsSet() && (m_IOComponents < m_BandList.size()))
781  {
782  cacheImage->SetNumberOfComponentsPerPixel(m_IOComponents);
783  }
784 
785  typedef itk::ImageRegionConstIterator<TInputImage> ConstIteratorType;
786  typedef itk::ImageRegionIterator<TInputImage> IteratorType;
787 
788  ConstIteratorType in(input, ioRegion);
789  IteratorType out(cacheImage, ioRegion);
790 
791  // copy the data into a buffer to match the ioregion
792  for (in.GoToBegin(), out.GoToBegin(); !in.IsAtEnd(); ++in, ++out)
793  {
794  out.Set(in.Get());
795  }
796 
797  dataPtr = (const void*) cacheImage->GetBufferPointer();
798 
799  }
800  else
801  {
802  itk::ImageFileWriterException e(__FILE__, __LINE__);
803  std::ostringstream msg;
804  msg << "Did not get requested region!" << std::endl;
805  msg << "Requested:" << std::endl;
806  msg << ioRegion;
807  msg << "Actual:" << std::endl;
808  msg << bufferedRegion;
809  e.SetDescription(msg.str());
810  e.SetLocation(ITK_LOCATION);
811  throw e;
812  }
813  }
814 
815  if (m_FilenameHelper->BandRangeIsSet() && (!m_BandList.empty()))
816  {
817  // Adapt the image size with the region and take into account a potential
818  // remapping of the components. m_BandList is empty if no band range is set
819  m_ImageIO->DoMapBuffer(const_cast< void* >(dataPtr), bufferedRegion.GetNumberOfPixels(), this->m_BandList);
820  m_ImageIO->SetNumberOfComponents(m_BandList.size());
821  }
822 
823  m_ImageIO->Write(dataPtr);
824 
825  if (m_WriteGeomFile || m_FilenameHelper->GetWriteGEOMFile())
826  {
827  ImageKeywordlist otb_kwl;
828  itk::MetaDataDictionary dict = this->GetInput()->GetMetaDataDictionary();
829  itk::ExposeMetaData<ImageKeywordlist>(dict, MetaDataKey::OSSIMKeywordlistKey, otb_kwl);
830  WriteGeometry(otb_kwl, this->GetFileName());
831  }
832 }
833 
834 template <class TInputImage>
835 void
837 ::SetFileName(const std::string& extendedFileName)
838 {
839  this->m_FilenameHelper->SetExtendedFileName(extendedFileName);
840  m_FileName = this->m_FilenameHelper->GetSimpleFileName();
841  m_ImageIO = nullptr;
842  this->Modified();
843 }
844 
845 template <class TInputImage>
846 const char*
849 {
850 return this->m_FilenameHelper->GetSimpleFileName();
851 }
852 
853 template <class TInputImage>
854 const bool &
857 {
858  m_Lock.Lock();
859  // protected read here
860  bool ret = Superclass::GetAbortGenerateData();
861  m_Lock.Unlock();
862  if (ret) return otb::Utils::TrueConstant;
864 }
865 
866 template <class TInputImage>
867 void
870 {
871  m_Lock.Lock();
872  Superclass::SetAbortGenerateData(val);
873  m_Lock.Unlock();
874 }
875 
876 } // end namespace otb
877 
878 #endif
itk::Size< Monteverdi_DIMENSION > SizeType
Definition: mvdTypes.h:137
This class computes the divisions needed to stream an image according to the input image tiling schem...
void SetDataObject(DataObject *dobj)
This class computes the divisions needed to stream an image by strips, driven by a user-defined numbe...
void SetNumberOfLinesStrippedStreaming(unsigned int nbLinesPerStrip)
virtual void SetInput(const InputImageType *input)
Storage and conversion for OSSIM metadata.
virtual void SetDescription(const std::string &s)
virtual void SetLocation(const std::string &s)
void SetIORegion(const itk::ImageIORegion &region)
void SetAbortGenerateData(const bool val) override
This class computes the divisions needed to stream an image by strips, driven by a user-defined desir...
void RemoveObserver(unsigned long tag)
*brief Mask an image with the negative of a mask **This class is templated over the types of the *input image type
void ConvertStringToVector(std::string const &str, T &ret, std::string const &errmsg, const char *delims=" ")
OTBCommon_EXPORT bool const TrueConstant
const InputImageType * GetInput()
This class computes the divisions needed to stream an image by strips, according to a user-defined av...
InputImageType::RegionType InputImageRegionType
static ImageIOBasePointer CreateImageIO(const char *path, FileModeType mode)
static void Convert(const ImageRegionType &inImageRegion, ImageIORegionType &outIORegion, const ImageIndexType &largestRegionIndex)
OTBCommon_EXPORT bool const FalseConstant
unsigned long AddObserver(const EventObject &event, Command *)
virtual void SetFileName(const std::string &extendedFileName)
void SetTileDimensionTiledStreaming(unsigned int tileDimension)
This class computes the divisions needed to stream an image in square tiles, according to a user-defi...
itk::Index< Monteverdi_DIMENSION > IndexType
Definition: mvdTypes.h:133
void SetIndex(const IndexType &index)
void GenerateData(void) override
InputImageType::Pointer InputImagePointer
void SetAutomaticAdaptativeStreaming(unsigned int availableRAM=0, double bias=1.0)
#define otbLogMacro(level, msg)
Definition: otbMacro.h:54
bool IsNull() const
void SetAutomaticTiledStreaming(unsigned int availableRAM=0, double bias=1.0)
void SetSize(const SizeType &size)
void SetNumberOfDivisionsTiledStreaming(unsigned int nbDivisions)
This class computes the divisions needed to stream an image by strips, driven by a user-defined numbe...
OTBOSSIMAdapters_EXPORT void WriteGeometry(const ImageKeywordlist &otb_kwl, const std::string &filename)
static Logger * Instance()
void GenerateOutputInformation(void) override
This class computes the divisions needed to stream an image in square tiles, driven by a user-defined...
VectorImageType::SpacingType SpacingType
Definition: mvdTypes.h:181
void SetNumberOfDivisionsStrippedStreaming(unsigned int nbDivisions)
void PrintSelf(std::ostream &os, itk::Indent indent) const override
ImageIO object for reading and writing images with GDAL.
virtual const char * GetFileName() const
VectorImageType::PointType PointType
Definition: mvdTypes.h:189
const bool & GetAbortGenerateData() const override
OTBOSSIMAdapters_EXPORT char const * OSSIMKeywordlistKey
void SetAutomaticStrippedStreaming(unsigned int availableRAM=0, double bias=1.0)