Orfeo Toolbox  4.2
itkStreamingImageIOBase.cxx
Go to the documentation of this file.
1 /*=========================================================================
2  *
3  * Copyright Insight Software Consortium
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  *=========================================================================*/
19 
20 #include "itksys/SystemTools.hxx"
21 
22 namespace itk
23 {
25  ImageIOBase()
26 {}
27 
28 void StreamingImageIOBase::PrintSelf(std::ostream & os, Indent indent) const
29 {
30  Superclass::PrintSelf(os, indent);
31 }
32 
34 ::StreamReadBufferAsBinary(std::istream & file, void *_buffer)
35 {
36  itkDebugMacro(<< "StreamingReadBufferAsBinary called");
37 
38  char *buffer = static_cast< char * >( _buffer );
39  // Offset into file
40  std::streampos dataPos = this->GetDataPosition();
41 
42  itkDebugStatement(
43  const std::streamsize sizeOfRegion = static_cast< std::streamsize >( m_IORegion.GetNumberOfPixels() )
44  * this->GetPixelSize();
45  );
46 
47  // compute the number of continuous bytes to be read
48  std::streamsize sizeOfChunk = 1;
49  unsigned int movingDirection = 0;
50  do
51  {
52  sizeOfChunk *= m_IORegion.GetSize(movingDirection);
53  ++movingDirection;
54  }
55  while ( movingDirection < m_IORegion.GetImageDimension()
56  && m_IORegion.GetSize(movingDirection - 1) == this->GetDimensions(movingDirection - 1) );
57  sizeOfChunk *= this->GetPixelSize();
58 
59  ImageIORegion::IndexType currentIndex = m_IORegion.GetIndex();
60 
61  while ( m_IORegion.IsInside(currentIndex) )
62  {
63  // calculate the position to seek to in the file
64  std::streampos seekPos = 0;
65  SizeValueType subDimensionQuantity = 1;
66  for ( unsigned int i = 0; i < m_IORegion.GetImageDimension(); ++i )
67  {
68  seekPos = seekPos + static_cast< std::streamoff >( subDimensionQuantity
69  * this->GetPixelSize()
70  * currentIndex[i] );
71  subDimensionQuantity *= this->GetDimensions(i);
72  }
73 
74  itkDebugMacro(
75  << "Reading " << sizeOfChunk << " of " << sizeOfRegion << " bytes for " << m_FileName << " at " << dataPos
76  + seekPos << " position in file");
77 
78  file.seekg(dataPos + seekPos, std::ios::beg);
79 
80  if ( ! this->ReadBufferAsBinary(file, buffer, sizeOfChunk) )
81  {
82  itkExceptionMacro( "Error reading in ReadBufferAsBinary!" );
83  }
84 
85  // increment the buffer pointer
86  buffer += sizeOfChunk;
87 
88  if ( file.fail() )
89  {
90  itkExceptionMacro(<< "Fail reading");
91  }
92 
93  if ( movingDirection == m_IORegion.GetImageDimension() )
94  {
95  break;
96  }
97 
98  // increment index to next chunk
99  ++currentIndex[movingDirection];
100  for ( unsigned int i = movingDirection; i < m_IORegion.GetImageDimension() - 1; ++i )
101  {
102  // when reaching the end of the moving index dimension carry to
103  // higher dimensions
104  if ( static_cast< ImageIORegion::SizeValueType >( currentIndex[i] - m_IORegion.GetIndex(i) ) >=
105  m_IORegion.GetSize(i) )
106  {
107  currentIndex[i] = m_IORegion.GetIndex(i);
108  ++currentIndex[i + 1];
109  }
110  }
111  }
112 
113  return true;
114 }
115 
117 {
118  // some systems have a limit of 2GB to be read at once
119  const SizeType maxChunk = 1024 * 1024 * 1024;
120 
121  std::streamsize bytesRemaining = static_cast< std::streamsize >( num );
122 
123  while ( bytesRemaining )
124  {
125  std::streamsize bytesToRead = bytesRemaining > maxChunk ? maxChunk : bytesRemaining;
126 
127  itkDebugMacro(<< "Reading " << bytesToRead << " of " << bytesRemaining << " bytes for " << m_FileName);
128 
129  is.read(static_cast< char * >( buffer ), bytesToRead);
130 
131  if ( ( is.gcount() != bytesToRead ) || is.fail() )
132  {
133  return false;
134  }
135  buffer = static_cast< char * >( buffer ) + bytesToRead;
136  bytesRemaining -= bytesToRead;
137  }
138 
139  return true;
140 }
141 
143  const void *buffer,
145 {
146  // some systems have a limit of 2GB to be written at once
147  const SizeType maxChunk = 1024 * 1024 * 1024;
148 
149  std::streamsize bytesRemaining = num;
150 
151  while ( bytesRemaining )
152  {
153  SizeType bytesToWrite = bytesRemaining > maxChunk ? maxChunk : bytesRemaining;
154 
155  itkDebugMacro(<< "Writing " << bytesToWrite << " of " << bytesRemaining << " bytes for " << m_FileName);
156 
157  os.write(static_cast< const char * >( buffer ), bytesToWrite);
158  if ( os.fail() )
159  {
160  return false;
161  }
162 
163  buffer = static_cast< const char * >( buffer ) + bytesToWrite;
164  bytesRemaining -= bytesToWrite;
165  }
166 
167  return true;
168 }
169 
170 bool StreamingImageIOBase::StreamWriteBufferAsBinary(std::ostream & file, const void *_buffer)
171 {
172  itkDebugMacro(<< "StreamingWriteBufferAsBinary called");
173 
174  const char *buffer = static_cast< const char * >( _buffer );
175  // Offset into file
176  std::streampos dataPos = this->GetDataPosition();
177 
178  // compute the number of continuous bytes to be written
179  std::streamsize sizeOfChunk = 1;
180  unsigned int movingDirection = 0;
181  do
182  {
183  sizeOfChunk *= m_IORegion.GetSize(movingDirection);
184  ++movingDirection;
185  }
186  while ( movingDirection < m_IORegion.GetImageDimension()
187  && m_IORegion.GetSize(movingDirection - 1) == this->GetDimensions(movingDirection - 1) );
188  sizeOfChunk *= this->GetPixelSize();
189 
191  while ( m_IORegion.IsInside(currentIndex) )
192  {
193  // calculate the position to seek to in the file
194  std::streampos seekPos = 0;
195  SizeValueType subDimensionQuantity = 1;
196  for ( unsigned int i = 0; i < m_IORegion.GetImageDimension(); ++i )
197  {
198  seekPos = seekPos + static_cast< std::streamoff >( subDimensionQuantity
199  * this->GetPixelSize()
200  * currentIndex[i] );
201  subDimensionQuantity *= this->GetDimensions(i);
202  }
203 
204  file.seekp(dataPos + seekPos, std::ios::beg);
205  if ( !this->WriteBufferAsBinary(file, buffer, sizeOfChunk) )
206  {
207  itkExceptionMacro( "Error reading in WriteBufferAsBinary!" );
208  }
209 
210  // increment the buffer pointer
211  buffer += sizeOfChunk;
212 
213  itkDebugMacro(
214  << "Writing " << sizeOfChunk << " of " << " ?? bytes for " << m_FileName << " at " << dataPos + seekPos
215  << " position in file");
216 
217  if ( file.fail() )
218  {
219  itkExceptionMacro(<< "Fail writing");
220  }
221 
222  if ( movingDirection == m_IORegion.GetImageDimension() )
223  {
224  break;
225  }
226 
227  // increment index to next chunk
228  ++currentIndex[movingDirection];
229  for ( unsigned int i = movingDirection; i < m_IORegion.GetImageDimension() - 1; ++i )
230  {
231  // when reaching the end of the movingDirection dimension carry to
232  // higher dimensions
233  if ( static_cast< ImageIORegion::SizeValueType >( currentIndex[i] - m_IORegion.GetIndex(i) )
234  >= m_IORegion.GetSize(i) )
235  {
236  currentIndex[i] = m_IORegion.GetIndex(i);
237  ++currentIndex[i + 1];
238  }
239  }
240  }
241 
242  return true;
243 }
244 
246 {
247  return true;
248 }
249 
251 {
252  return true;
253 }
254 
255 unsigned int
256 StreamingImageIOBase::GetActualNumberOfSplitsForWriting(unsigned int numberOfRequestedSplits,
257  const ImageIORegion & pasteRegion,
258  const ImageIORegion & largestPossibleRegion)
259 {
260  if ( !const_cast<StreamingImageIOBase*>(this)->CanStreamWrite() )
261  {
262  // ImageIOs may not always be able to stream,
263  // fall back to super classses non-streaming implementation
264  return ImageIOBase::GetActualNumberOfSplitsForWriting( numberOfRequestedSplits,
265  pasteRegion,
266  largestPossibleRegion );
267  }
268  else if ( !itksys::SystemTools::FileExists( m_FileName.c_str() ) )
269  {
270  // file doesn't exits so we don't have potential problems
271  }
272  else if ( pasteRegion != largestPossibleRegion )
273  {
274  // we are going to be pasting (may be streaming too)
275 
276  // need to check to see if the file is compatible
277  std::string errorMessage;
278  Pointer headerImageIOReader = dynamic_cast< StreamingImageIOBase * >( this->CreateAnother().GetPointer() );
279 
280  try
281  {
282  headerImageIOReader->SetFileName( m_FileName.c_str() );
283  headerImageIOReader->ReadImageInformation();
284  }
285  catch ( ... )
286  {
287  errorMessage = "Unable to read information from file: " + m_FileName;
288  }
289 
290  // we now need to check that the following match:
291  // 2)pixel type
292  // 3)dimensions
293  // 4)size/origin/spacing
294  // 5)direction cosines
295  //
296  // todo check for byte order
297 
298  if ( errorMessage.size() )
299  {
300  // 0) Can't read file
301  }
302  // 2)pixel type
303  // this->GetPixelType() is not verified because the metaio file format
304  // stores all multi-component types as arrays, so it does not
305  // distinguish between pixel types. Also as long as the compoent
306  // and number of compoents match we should be able to paste, that
307  // is the numbers should be the same it is just the interpretation
308  // that is not matching
309  else if ( headerImageIOReader->GetNumberOfComponents() != this->GetNumberOfComponents()
310  || headerImageIOReader->GetComponentType() != this->GetComponentType() )
311  {
312  errorMessage = "Component type does not match in file: " + m_FileName;
313  }
314  // 3)dimensions/size
315  else if ( headerImageIOReader->GetNumberOfDimensions() != this->GetNumberOfDimensions() )
316  {
317  errorMessage = "Dimensions does not match in file: " + m_FileName;
318  }
319  else
320  {
321  for ( unsigned int i = 0; i < this->GetNumberOfDimensions(); ++i )
322  {
323  // 4)size/origin/spacing
324  if ( headerImageIOReader->GetDimensions(i) != this->GetDimensions(i)
325  || headerImageIOReader->GetSpacing(i) != this->GetSpacing(i)
326  || headerImageIOReader->GetOrigin(i) != this->GetOrigin(i) )
327  {
328  errorMessage = "Size, spacing or origin does not match in file: " + m_FileName;
329  break;
330  }
331  // 5)direction cosines
332  if ( headerImageIOReader->GetDirection(i) != this->GetDirection(i) )
333  {
334  errorMessage = "Direction cosines does not match in file: " + m_FileName;
335  break;
336  }
337  }
338  }
339 
340  if ( errorMessage.size() )
341  {
342  itkExceptionMacro("Unable to paste because pasting file exists and is different. " << errorMessage);
343  }
344  else if ( headerImageIOReader->GetPixelType() != this->GetPixelType() )
345  {
346  // since there is currently poor support for pixel types in
347  // MetaIO we will just warn when it does not match
348  itkWarningMacro("Pixel types does not match file, but component type and number of components do.");
349  }
350  }
351  else if ( numberOfRequestedSplits != 1 )
352  {
353  // we are going be streaming
354 
355  // need to remove the file incase the file doesn't match our
356  // current header/meta data information
357  if ( !itksys::SystemTools::RemoveFile( m_FileName.c_str() ) )
358  {
359  itkExceptionMacro("Unable to remove file for streaming: " << m_FileName);
360  }
361  }
362 
363  return GetActualNumberOfSplitsForWritingCanStreamWrite(numberOfRequestedSplits, pasteRegion);
364 }
365 
367  const ImageIORegion & requestedRegion) const
368 {
369  // This implementation returns the requestedRegion if
370  // streaming is enabled and we are capable
371 
372  ImageIORegion streamableRegion(this->m_NumberOfDimensions);
373 
374  if ( !m_UseStreamedReading || !const_cast<StreamingImageIOBase*>(this)->CanStreamRead() )
375  {
377  }
378  else
379  {
380  streamableRegion = requestedRegion;
381  }
382 
383  return streamableRegion;
384 }
385 
387 {
388  // we choose the max dimension and then pad the smaller with ones
389  //
390  // This enables a 2D request from a 3D volume to get the first slice,
391  // and a 4D with a 1-sized 4th dimension to equal the 3D volume
392  // as well.
393  unsigned int maxNumberOfDimension = vnl_math_max( this->GetNumberOfDimensions(),
394  this->GetIORegion().GetImageDimension() );
395 
396  ImageIORegion ioregion(maxNumberOfDimension);
397  ImageIORegion largestRegion(maxNumberOfDimension);
398 
399  for ( unsigned int i = 0; i < maxNumberOfDimension; i++ )
400  {
401  largestRegion.SetIndex(i, 0);
402  if ( i < this->GetNumberOfDimensions() )
403  {
404  largestRegion.SetSize( i, this->GetDimensions(i) );
405  }
406  else
407  {
408  largestRegion.SetSize(i, 1);
409  }
410 
411  if ( i < this->GetIORegion().GetImageDimension() )
412  {
413  ioregion.SetIndex( i, this->GetIORegion().GetIndex(i) );
414  ioregion.SetSize( i, this->GetIORegion().GetSize(i) );
415  }
416  else
417  {
418  ioregion.SetIndex(i, 0);
419  ioregion.SetSize(i, 1);
420  }
421  }
422 
423  return ( largestRegion != ioregion );
424 }
425 } // namespace itk

Generated at Sat Aug 30 2014 15:41:28 for Orfeo Toolbox with doxygen 1.8.3.1