22 #ifndef otbImageFileWriter_hxx
23 #define otbImageFileWriter_hxx
26 #include "itkImageFileWriter.h"
28 #include "itkObjectFactoryBase.h"
30 #include "itkImageRegionMultidimensionalSplitter.h"
33 #include "itkImageRegionIterator.h"
35 #include "itkMetaDataObject.h"
39 #include "otbConfigure.h"
60 template <
class TInputImage>
62 : m_NumberOfDivisions(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),
77 m_ShiftOutputIndex.Fill(0);
81 this->SetAutomaticAdaptativeStreaming();
83 m_FilenameHelper = FNameHelperType::New();
89 template <
class TInputImage>
94 template <
class TInputImage>
98 typename NumberOfDivisionsStrippedStreamingManagerType::Pointer streamingManager = NumberOfDivisionsStrippedStreamingManagerType::New();
99 streamingManager->SetNumberOfDivisions(nbDivisions);
100 m_StreamingManager = streamingManager;
103 template <
class TInputImage>
107 typename NumberOfDivisionsTiledStreamingManagerType::Pointer streamingManager = NumberOfDivisionsTiledStreamingManagerType::New();
108 streamingManager->SetNumberOfDivisions(nbDivisions);
109 m_StreamingManager = streamingManager;
112 template <
class TInputImage>
116 typename NumberOfLinesStrippedStreamingManagerType::Pointer streamingManager = NumberOfLinesStrippedStreamingManagerType::New();
117 streamingManager->SetNumberOfLinesPerStrip(nbLinesPerStrip);
118 m_StreamingManager = streamingManager;
121 template <
class TInputImage>
125 typename RAMDrivenStrippedStreamingManagerType::Pointer streamingManager = RAMDrivenStrippedStreamingManagerType::New();
126 streamingManager->SetAvailableRAMInMB(availableRAM);
127 streamingManager->SetBias(bias);
128 m_StreamingManager = streamingManager;
131 template <
class TInputImage>
135 typename TileDimensionTiledStreamingManagerType::Pointer streamingManager = TileDimensionTiledStreamingManagerType::New();
136 streamingManager->SetTileDimension(tileDimension);
137 m_StreamingManager = streamingManager;
140 template <
class TInputImage>
144 typename RAMDrivenTiledStreamingManagerType::Pointer streamingManager = RAMDrivenTiledStreamingManagerType::New();
145 streamingManager->SetAvailableRAMInMB(availableRAM);
146 streamingManager->SetBias(bias);
147 m_StreamingManager = streamingManager;
150 template <
class TInputImage>
154 typename RAMDrivenAdaptativeStreamingManagerType::Pointer streamingManager = RAMDrivenAdaptativeStreamingManagerType::New();
155 streamingManager->SetAvailableRAMInMB(availableRAM);
156 streamingManager->SetBias(bias);
157 m_StreamingManager = streamingManager;
163 template <
class TInputImage>
166 Superclass::PrintSelf(os, indent);
168 os << indent <<
"File Name: " << (m_FileName.data() ? m_FileName.data() :
"(none)") << std::endl;
170 os << indent <<
"Image IO: ";
171 if (m_ImageIO.IsNull())
177 os << m_ImageIO <<
"\n";
180 os << indent <<
"IO Region: " << m_IORegion <<
"\n";
182 if (m_UseCompression)
184 os << indent <<
"Compression: On\n";
188 os << indent <<
"Compression: Off\n";
191 if (m_UseInputMetaDataDictionary)
193 os << indent <<
"UseInputMetaDataDictionary: On\n";
197 os << indent <<
"UseInputMetaDataDictionary: Off\n";
200 if (m_FactorySpecifiedImageIO)
202 os << indent <<
"FactorySpecifiedmageIO: On\n";
206 os << indent <<
"FactorySpecifiedmageIO: Off\n";
211 template <
class TInputImage>
214 if (m_IORegion != region)
218 m_UserSpecifiedIORegion =
true;
222 template <
class TInputImage>
225 this->ProcessObject::SetNthInput(0,
const_cast<InputImageType*
>(input));
228 template <
class TInputImage>
231 if (this->GetNumberOfInputs() < 1)
236 return static_cast<const InputImageType*
>(this->ProcessObject::GetInput(0));
240 template <
class TInputImage>
247 if (inputPtr.IsNull())
249 itkExceptionMacro(<<
"No input to writer");
255 if (m_FilenameHelper->StreamingTypeIsSet())
259 <<
"Streaming configuration through extended filename is used. Any previous streaming configuration (ram value, streaming mode ...) will be ignored.");
261 std::string type = m_FilenameHelper->GetStreamingType();
263 std::string sizemode =
"auto";
265 if (m_FilenameHelper->StreamingSizeModeIsSet())
267 sizemode = m_FilenameHelper->GetStreamingSizeMode();
270 unsigned int sizevalue = 0;
272 unsigned int oldDefaultRAM = m_StreamingManager->GetDefaultRAM();
273 if (sizemode ==
"auto")
275 sizevalue = oldDefaultRAM;
278 if (m_FilenameHelper->StreamingSizeValueIsSet())
280 sizevalue =
static_cast<unsigned int>(m_FilenameHelper->GetStreamingSizeValue());
285 if (sizemode !=
"auto")
287 otbLogMacro(Warning, <<
"In auto streaming type, the sizemode option will be ignored.");
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");
294 this->SetAutomaticAdaptativeStreaming(sizevalue);
296 else if (type ==
"tiled")
298 if (sizemode ==
"auto")
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");
305 this->SetAutomaticTiledStreaming(sizevalue);
307 else if (sizemode ==
"nbsplits")
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.");
314 this->SetNumberOfDivisionsTiledStreaming(sizevalue);
316 else if (sizemode ==
"height")
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.");
324 this->SetTileDimensionTiledStreaming(sizevalue);
327 else if (type ==
"stripped")
329 if (sizemode ==
"auto")
334 Warning, <<
"sizemode is auto but sizevalue is 0. Value will be fetched from configuration file if any, or from cmake configuration otherwise.");
337 this->SetAutomaticStrippedStreaming(sizevalue);
339 else if (sizemode ==
"nbsplits")
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.");
346 this->SetNumberOfDivisionsStrippedStreaming(sizevalue);
348 else if (sizemode ==
"height")
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.");
355 this->SetNumberOfLinesStrippedStreaming(sizevalue);
358 else if (type ==
"none")
360 if (sizemode !=
"" || sizevalue != 0)
362 otbLogMacro(Warning, <<
"Streaming is explicitly disabled, sizemode and sizevalue will be ignored.");
364 this->SetNumberOfDivisionsTiledStreaming(0);
369 m_StreamingManager->SetDefaultRAM(oldDefaultRAM);
373 if (m_FilenameHelper->StreamingSizeValueIsSet() || m_FilenameHelper->StreamingSizeModeIsSet())
375 otbLogMacro(Warning, <<
"No streaming type is set, streaming sizemode and sizevalue will be ignored.");
381 if (m_FileName ==
"")
384 itkExceptionMacro(<<
"No filename was specified");
394 if (m_ImageIO.IsNull())
398 m_FactorySpecifiedImageIO =
true;
402 if (!m_ImageIO->CanWriteFile(m_FileName.c_str()))
404 if (m_FactorySpecifiedImageIO)
407 m_FactorySpecifiedImageIO =
true;
412 if (m_ImageIO.IsNull())
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);
423 if ((strcmp(m_ImageIO->GetNameOfClass(),
"GDALImageIO") == 0) &&
424 (m_FilenameHelper->gdalCreationOptionsIsSet() || m_FilenameHelper->WriteRPCTagsIsSet() || m_FilenameHelper->NoDataValueIsSet() || m_FilenameHelper->SrsValueIsSet()))
428 if (imageIO.IsNull())
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());
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());
454 if (m_FilenameHelper->BoxIsSet())
456 std::vector<unsigned int> boxVector;
460 if (boxVector.size() != 4)
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);
470 typename InputImageRegionType::IndexType start;
471 typename InputImageRegionType::SizeType size;
472 start[0] = boxVector[0];
473 start[1] = boxVector[1];
474 size[0] = boxVector[2];
475 size[1] = boxVector[3];
477 inputRegion.SetSize(size);
478 inputRegion.SetIndex(start);
480 if (!inputRegion.Crop(inputPtr->GetLargestPossibleRegion()))
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);
492 otbLogMacro(Info, <<
"Writing user defined region [" << start[0] <<
", " << start[0] + size[0] - 1 <<
"]x[" << start[1] <<
", " << start[1] + size[1]
495 m_ShiftOutputIndex = inputRegion.GetIndex();
504 if (m_ImageIO->CanStreamWrite() ==
false)
506 otbLogMacro(Warning, <<
"The file format of " << m_FileName <<
" does not support streaming. All data will be loaded to memory");
507 this->SetNumberOfDivisionsStrippedStreaming(1);
514 else if (inputPtr->GetBufferedRegion() == inputRegion)
516 otbLogMacro(Debug, <<
"Buffered region is the largest possible region, there is no need for streaming.");
517 this->SetNumberOfDivisionsStrippedStreaming(1);
519 m_StreamingManager->PrepareStreaming(inputPtr, inputRegion);
520 m_NumberOfDivisions = m_StreamingManager->GetNumberOfSplits();
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]
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)
538 if (direction[i][i] < 0)
543 m_ImageIO->SetDimensions(i, inputRegion.GetSize(i));
544 m_ImageIO->SetSpacing(i, direction_sign * spacing[i]);
545 m_ImageIO->SetOrigin(i, origin[i]);
547 vnl_vector<double> axisDirection(TInputImage::ImageDimension);
550 for (
unsigned int j = 0; j < TInputImage::ImageDimension; ++j)
552 axisDirection[j] = direction_sign * direction[j][i];
554 m_ImageIO->SetDirection(i, axisDirection);
557 m_ImageIO->SetUseCompression(m_UseCompression);
558 m_ImageIO->SetMetaDataDictionary(inputPtr->GetMetaDataDictionary());
561 if (img_common !=
nullptr)
569 m_ImageIO->SetFileName(m_FileName);
571 m_ImageIO->WriteImageInformation();
577 template <
class TInputImage>
580 this->UpdateOutputInformation();
582 this->SetAbortGenerateData(0);
583 this->SetProgress(0.0);
588 this->InvokeEvent(itk::StartEvent());
590 this->UpdateProgress(0);
591 m_CurrentDivision = 0;
592 m_DivisionProgress = 0;
596 itk::ProcessObject* source = inputPtr->GetSource();
597 m_IsObserving =
false;
603 typedef itk::MemberCommand<Self> CommandType;
604 typedef typename CommandType::Pointer CommandPointerType;
606 CommandPointerType command = CommandType::New();
607 command->SetCallbackFunction(
this, &Self::ObserveSourceFilterProgress);
609 m_ObserverID = source->AddObserver(itk::ProgressEvent(), command);
610 m_IsObserving =
true;
614 otbLogMacro(Warning, <<
"Could not get the source process object. Progress report might be buggy");
623 for (m_CurrentDivision = 0; m_CurrentDivision < m_NumberOfDivisions && !this->GetAbortGenerateData();
624 m_CurrentDivision++, m_DivisionProgress = 0, this->UpdateFilterProgress())
626 streamRegion = m_StreamingManager->GetSplit(m_CurrentDivision);
628 inputPtr->SetRequestedRegion(streamRegion);
629 inputPtr->PropagateRequestedRegion();
630 inputPtr->UpdateOutputData();
633 itk::ImageIORegion ioRegion(TInputImage::ImageDimension);
634 for (
unsigned int i = 0; i < TInputImage::ImageDimension; ++i)
636 ioRegion.SetSize(i, streamRegion.GetSize(i));
638 ioRegion.SetIndex(i, streamRegion.GetIndex(i) - m_ShiftOutputIndex[i]);
640 this->SetIORegion(ioRegion);
641 m_ImageIO->SetIORegion(m_IORegion);
644 this->GenerateData();
651 if (!this->GetAbortGenerateData())
653 this->UpdateProgress(1.0);
657 itk::ProcessAborted e(__FILE__, __LINE__);
658 e.SetLocation(ITK_LOCATION);
659 e.SetDescription(
"Image writing has been aborted");
665 this->InvokeEvent(itk::EndEvent());
669 m_IsObserving =
false;
670 source->RemoveObserver(m_ObserverID);
676 this->ReleaseInputs();
680 m_ShiftOutputIndex = inputPtr->GetLargestPossibleRegion().GetIndex();
687 template <
class TInputImage>
698 if (strcmp(input->GetNameOfClass(),
"VectorImage") == 0)
700 typedef typename InputImageType::InternalPixelType VectorImagePixelType;
701 m_ImageIO->SetPixelTypeInfo(
typeid(VectorImagePixelType));
703 typedef typename InputImageType::AccessorFunctorType AccessorFunctorType;
704 m_ImageIO->SetNumberOfComponents(AccessorFunctorType::GetVectorLength(input));
706 m_IOComponents = m_ImageIO->GetNumberOfComponents();
708 if (m_FilenameHelper->BandRangeIsSet())
711 bool retBandRange = m_FilenameHelper->ResolveBandRange(m_FilenameHelper->GetBandRange(), m_IOComponents, m_BandList);
712 if (retBandRange ==
false || m_BandList.empty())
715 itkGenericExceptionMacro(
"The given band range is either empty or invalid for a " << m_IOComponents <<
" bands input image!");
728 const void* dataPtr = (
const void*)input->GetBufferPointer();
735 itk::ImageIORegionAdaptor<TInputImage::ImageDimension>::Convert(m_ImageIO->GetIORegion(), ioRegion, m_ShiftOutputIndex);
740 if ((bufferedRegion != ioRegion) || (m_FilenameHelper->BandRangeIsSet() && (m_IOComponents < m_BandList.size())))
742 if (m_NumberOfDivisions > 1 || m_UserSpecifiedIORegion)
744 cacheImage = InputImageType::New();
745 cacheImage->CopyInformation(input);
748 if (m_FilenameHelper->BandRangeIsSet() && (m_IOComponents < m_BandList.size()))
750 cacheImage->SetNumberOfComponentsPerPixel(m_BandList.size());
753 cacheImage->SetBufferedRegion(ioRegion);
754 cacheImage->Allocate();
757 if (m_FilenameHelper->BandRangeIsSet() && (m_IOComponents < m_BandList.size()))
759 cacheImage->SetNumberOfComponentsPerPixel(m_IOComponents);
762 typedef itk::ImageRegionConstIterator<TInputImage> ConstIteratorType;
763 typedef itk::ImageRegionIterator<TInputImage> IteratorType;
765 ConstIteratorType in(input, ioRegion);
766 IteratorType out(cacheImage, ioRegion);
769 for (in.GoToBegin(), out.GoToBegin(); !in.IsAtEnd(); ++in, ++out)
774 dataPtr = (
const void*)cacheImage->GetBufferPointer();
778 itk::ImageFileWriterException e(__FILE__, __LINE__);
779 std::ostringstream msg;
780 msg <<
"Did not get requested region!" << std::endl;
781 msg <<
"Requested:" << std::endl;
783 msg <<
"Actual:" << std::endl;
784 msg << bufferedRegion;
785 e.SetDescription(msg.str());
786 e.SetLocation(ITK_LOCATION);
791 if (m_FilenameHelper->BandRangeIsSet() && (!m_BandList.empty()))
795 m_ImageIO->DoMapBuffer(
const_cast<void*
>(dataPtr), bufferedRegion.GetNumberOfPixels(), this->m_BandList);
796 m_ImageIO->SetNumberOfComponents(m_BandList.size());
799 m_ImageIO->Write(dataPtr);
802 template <
class TInputImage>
805 this->m_FilenameHelper->SetExtendedFileName(extendedFileName);
806 m_FileName = this->m_FilenameHelper->GetSimpleFileName();
811 template <
class TInputImage>
814 return this->m_FilenameHelper->GetSimpleFileName();
817 template <
class TInputImage>
822 bool ret = Superclass::GetAbortGenerateData();
829 template <
class TInputImage>
833 Superclass::SetAbortGenerateData(val);