Orfeo Toolbox  3.16
itkAnalyzeImageIO.cxx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkAnalyzeImageIO.cxx,v $
5  Language: C++
6  Date: $Date: 2010-05-28 11:09:30 $
7  Version: $Revision: 1.105 $
8 
9  Copyright (c) Insight Software Consortium. All rights reserved.
10  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
11 
12  This software is distributed WITHOUT ANY WARRANTY; without even
13  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14  PURPOSE. See the above copyright notices for more information.
15 
16 =========================================================================*/
17 
18 #include <nifti1_io.h> // Needed to make sure that the overlapping
19  // Analyze/Nifti readers do not overlap
20 #include "itkAnalyzeImageIO.h"
21 #include "itkIOCommon.h"
22 #include "itkExceptionObject.h"
23 #include "itkByteSwapper.h"
24 #include "itkMetaDataObject.h"
26 #include "itkRGBPixel.h"
27 #include <itksys/SystemTools.hxx>
28 #include "itkMacro.h"
29 #include "itk_zlib.h"
30 #include <stdio.h>
31 #include <stdlib.h>
32 
33 namespace itk
34 {
35 
36 const char *const ANALYZE_ScanNumber = "ANALYZE_ScanNumber";
37 const char *const ANALYZE_O_MAX = "ANALYZE_O_MAX";
38 const char *const ANALYZE_O_MIN = "ANALYZE_O_MIN";
39 const char *const ANALYZE_S_MAX = "ANALYZE_S_MAX";
40 const char *const ANALYZE_S_MIN = "ANALYZE_S_MIN";
41 const char *const ANALYZE_CAL_MAX = "ANALYZE_CAL_MAX";
42 const char *const ANALYZE_CAL_MIN = "ANALYZE_CAL_MIN";
43 const char *const ANALYZE_GLMAX = "ANALYZE_GLMAX";
44 const char *const ANALYZE_GLMIN = "ANALYZE_GLMIN";
45 const char *const ANALYZE_AUX_FILE_NAME = "ANALYZE_AUX_FILE_NAME";
46 const char *const ANALYZE_CALIBRATIONUNITS = "ANALYZE_CALIBRATIONUNITS";
47 //An array of the Analyze v7.5 known DataTypes
48 const char DataTypes[12][10]=
49 {
50  "UNKNOWN","BINARY","CHAR","SHORT", "INT","FLOAT",
51  "COMPLEX", "DOUBLE","RGB","ALL","USHORT","UINT"
52 };
53 
54 //An array with the corresponding number of bits for each image type.
55 //NOTE: the following two line should be equivalent.
56 const short int DataTypeSizes[12]={0,1,8,16,32,32,64,64,24,0,16,32};
57 
58 //An array with Data type key sizes
59 const short int DataTypeKey[12] =
60 {
61  ANALYZE_DT_UNKNOWN,
62  ANALYZE_DT_BINARY,
63  ANALYZE_DT_UNSIGNED_CHAR,
64  ANALYZE_DT_SIGNED_SHORT,
65  ANALYZE_DT_SIGNED_INT,
66  ANALYZE_DT_FLOAT,
67  ANALYZE_DT_COMPLEX,
68  ANALYZE_DT_DOUBLE,
69  ANALYZE_DT_RGB,
70  ANALYZE_DT_ALL,
71  SPMANALYZE_DT_UNSIGNED_SHORT,
72  SPMANALYZE_DT_UNSIGNED_INT
73 };
74 
75 // due to gzip and other io limitations this is the maximum size to
76 // read at one time
77 const unsigned int ANALYZE_MAXIMUM_IO_CHUNK = itk::NumericTraits<unsigned int>::max()/4;
78 
79 static std::string
80 GetExtension( const std::string& filename )
81 {
82  std::string fileExt(itksys::SystemTools::GetFilenameLastExtension(filename));
83  //If the last extension is .gz, then need to pull off 2 extensions.
84  //.gz is the only valid compression extension.
85  if(fileExt == std::string(".gz"))
86  {
87  fileExt=itksys::SystemTools::GetFilenameLastExtension(itksys::SystemTools::GetFilenameWithoutLastExtension(filename) );
88  fileExt += ".gz";
89  }
90  //Check that a valid extension was found.
91  if(fileExt != ".img.gz" && fileExt != ".img" && fileExt != ".hdr")
92  {
93  return( "" );
94  }
95  return( fileExt );
96 }
97 
98 static std::string
99 GetRootName( const std::string& filename )
100 {
101  const std::string fileExt = GetExtension(filename);
102  // Create a base filename
103  // i.e Image.hdr --> Image
104  if( fileExt.length() > 0 //Ensure that an extension was found
105  && filename.length() > fileExt.length() //Ensure that the filename does not contain only the extension
106  )
107  {
108  const std::string::size_type it = filename.find_last_of( fileExt );
109  const std::string baseName( filename, 0, it-(fileExt.length()-1) );
110  return( baseName );
111  }
112  //Default to return same as input when the extension is nothing (Analyze)
113  return( filename );
114 }
115 
116 
117 static std::string
118 GetHeaderFileName( const std::string & filename )
119 {
120  std::string ImageFileName = GetRootName(filename);
121  ImageFileName += ".hdr";
122  return( ImageFileName );
123 }
124 
125 //Returns the base image filename.
126 static std::string GetImageFileName( const std::string& filename )
127 {
128  std::string ImageFileName (filename);
129  const std::string fileExt = GetExtension(filename);
130  if(fileExt == ".hdr") //Default to uncompressed .img if .hdr is given as file name.
131  {
132  ImageFileName=GetRootName(filename);
133  ImageFileName += ".img";
134  }
135  return( ImageFileName );
136 }
137 
138 
139 void
141  SizeType _numberOfPixels )
142 {
143  // todo check for overflow error
144  size_t numberOfPixels = static_cast<size_t>( _numberOfPixels );
145  if ( m_ByteOrder == LittleEndian )
146  {
147  switch(m_ComponentType)
148  {
149  case CHAR:
151  numberOfPixels );
152  break;
153  case UCHAR:
155  ((unsigned char*)buffer, numberOfPixels );
156  break;
157  case SHORT:
159  ((short*)buffer, numberOfPixels );
160  break;
161  case USHORT:
163  ((unsigned short*)buffer, numberOfPixels );
164  break;
165  case INT:
167  ((int*)buffer, numberOfPixels );
168  break;
169  case UINT:
171  ((unsigned int*)buffer, numberOfPixels );
172  break;
173  case LONG:
175  ((long*)buffer, numberOfPixels );
176  break;
177  case ULONG:
179  ((unsigned long*)buffer, numberOfPixels );
180  break;
181  case FLOAT:
183  numberOfPixels );
184  break;
185  case DOUBLE:
187  ((double*)buffer, numberOfPixels );
188  break;
189  default:
190  itkExceptionMacro(<< "Pixel Type Unknown");
191  }
192  }
193  else
194  {
195  switch(m_ComponentType)
196  {
197  case CHAR:
199  numberOfPixels );
200  break;
201  case UCHAR:
203  ((unsigned char *)buffer, numberOfPixels );
204  break;
205  case SHORT:
207  ((short *)buffer, numberOfPixels );
208  break;
209  case USHORT:
211  ((unsigned short *)buffer, numberOfPixels );
212  break;
213  case INT:
215  ((int *)buffer, numberOfPixels );
216  break;
217  case UINT:
219  ((unsigned int *)buffer, numberOfPixels );
220  break;
221  case LONG:
223  ((long *)buffer, numberOfPixels );
224  break;
225  case ULONG:
227  ((unsigned long *)buffer, numberOfPixels );
228  break;
229  case FLOAT:
231  ((float *)buffer, numberOfPixels );
232  break;
233  case DOUBLE:
235  ((double *)buffer, numberOfPixels );
236  break;
237  default:
238  itkExceptionMacro(<< "Pixel Type Unknown");
239  }
240  }
241 }
242 
244 AnalyzeImageIO::CheckAnalyzeEndian(const struct dsr &temphdr)
245 {
246  ImageIOBase::ByteOrder returnvalue;
247  // Machine and header endianess is same
248 
249  // checking hk.extents only is NOT a good idea. Many programs do not set
250  // hk.extents correctly. Doing an additional check on hk.sizeof_hdr
251  // increases chance of correct result. --Juerg Tschirrin Univeristy of Iowa
252  // All properly constructed analyze images should have the extents feild
253  // set. It is part of the file format standard. While most headers of
254  // analyze images are 348 bytes long, The Analyze file format allows the
255  // header to have other lengths.
256  // This code will fail in the unlikely event that the extents feild is
257  // not set (invalid anlyze file anyway) and the header is not the normal
258  // size. Other peices of code have used a heuristic on the image
259  // dimensions. If the Image dimensions is greater
260  // than 16000 then the image is almost certainly byte-swapped-- Hans
261 
262  const ImageIOBase::ByteOrder systemOrder =
264 
265  if((temphdr.hk.extents == 16384) || (temphdr.hk.sizeof_hdr == 348))
266  {
267  returnvalue = systemOrder;
268  }
269  else
270  {
271  // File does not match machine
272  returnvalue = (systemOrder == BigEndian ) ? LittleEndian : BigEndian;
273  }
274  return returnvalue;
275 }
276 
277 void
278 AnalyzeImageIO::SwapHeaderBytesIfNecessary( struct dsr * const imageheader )
279 {
280  if ( m_ByteOrder == LittleEndian )
281  {
282  // NOTE: If machine order is little endian, and the data needs to be
283  // swapped, the SwapFromBigEndianToSystem is equivalent to
284  // SwapFromSystemToBigEndian.
286  &imageheader->hk.sizeof_hdr);
288  &imageheader->hk.extents );
290  &imageheader->hk.session_error );
292  &imageheader->dime.dim[0], 8 );
294  &imageheader->dime.unused1 );
296  &imageheader->dime.datatype );
298  &imageheader->dime.bitpix );
300  &imageheader->dime.dim_un0 );
301 
303  &imageheader->dime.pixdim[0],8 );
305  &imageheader->dime.vox_offset );
307  &imageheader->dime.roi_scale );
309  &imageheader->dime.funused1 );
311  &imageheader->dime.funused2 );
313  &imageheader->dime.cal_max );
315  &imageheader->dime.cal_min );
317  &imageheader->dime.compressed );
319  &imageheader->dime.verified );
321  &imageheader->dime.glmax );
323  &imageheader->dime.glmin );
324 
326  &imageheader->hist.views );
328  &imageheader->hist.vols_added );
330  &imageheader->hist.start_field );
332  &imageheader->hist.field_skip );
334  &imageheader->hist.omax );
336  &imageheader->hist.omin );
338  &imageheader->hist.smax );
340  &imageheader->hist.smin );
341  }
342  else if ( m_ByteOrder == BigEndian )
343  {
344  //NOTE: If machine order is little endian, and the data needs to be
345  // swapped, the SwapFromBigEndianToSystem is equivalent to
346  // SwapFromSystemToLittleEndian.
348  &imageheader->hk.sizeof_hdr );
350  &imageheader->hk.extents );
352  &imageheader->hk.session_error );
353 
355  &imageheader->dime.dim[0], 8 );
357  &imageheader->dime.unused1 );
359  &imageheader->dime.datatype );
361  &imageheader->dime.bitpix );
363  &imageheader->dime.dim_un0 );
364 
366  &imageheader->dime.pixdim[0],8 );
368  &imageheader->dime.vox_offset );
370  &imageheader->dime.roi_scale );
372  &imageheader->dime.funused1 );
374  &imageheader->dime.funused2 );
376  &imageheader->dime.cal_max );
378  &imageheader->dime.cal_min );
380  &imageheader->dime.compressed );
382  &imageheader->dime.verified );
384  &imageheader->dime.glmax );
386  &imageheader->dime.glmin );
387 
389  &imageheader->hist.views );
391  &imageheader->hist.vols_added );
393  &imageheader->hist.start_field );
395  &imageheader->hist.field_skip );
397  &imageheader->hist.omax );
399  &imageheader->hist.omin );
401  &imageheader->hist.smax );
403  &imageheader->hist.smin );
404  }
405  else
406  {
407  itkExceptionMacro(<< "Machine Endian Type Unknown");
408  }
409 }
410 
411 
413 {
414  // By default, only have 3 dimensions
415  this->SetNumberOfDimensions(3);
418  // Set m_MachineByteOrder to the ByteOrder of the machine
419  // Start out with file byte order == system byte order
420  // this will be changed if we're reading a file to whatever
421  // the file actually contains.
423  {
425  }
426  else
427  {
429  }
430 
431  // Set all values to a default value
432  // Must check again -- memset!!!!
433 
434  // Analyze stuff
435  // memset sets the first n bytes in memory area s to the value of c
436  // (cothis->m_Hdr.dime.dim[4]erted to an unsigned char). It returns s.
437  // void *memset (void *s, int c, size_t n);
438  memset(&(this->m_Hdr),0, sizeof(struct dsr));
439 
440  // strcpy(this->m_Hdr.hk.data_type,DataTypes[DT_INDEX_UNKNOWN]);
441  /* Acceptable this->m_Hdr.hk.data_type values are */
442  /* "UNKNOWN","BINARY","CHAR","SHORT","INT","FLOAT","COMPLEX","DOUBLE","RGB" */
443  this->m_Hdr.hk.sizeof_hdr = static_cast< int >( sizeof(struct dsr) );
444  this->m_Hdr.hk.db_name[0]='\0';
445  this->m_Hdr.hk.extents=16384;
446  this->m_Hdr.hk.session_error=0;
447  this->m_Hdr.hk.regular='r';
448  this->m_Hdr.hk.hkey_un0='\0';
449 
450  /* HeaderObj_dimension information*/
451  this->m_Hdr.dime.dim[0]=4; //Usually 4 x,y,z,time
452  this->m_Hdr.dime.dim[1]=1; //size_x;//number of columns
453  this->m_Hdr.dime.dim[2]=1; //size_y;//number of rows
454  this->m_Hdr.dime.dim[3]=1; //size_z;//number of slices
455  this->m_Hdr.dime.dim[4]=1; //size_t;//number of volumes
456  this->m_Hdr.dime.dim[5]=1;
457  this->m_Hdr.dime.dim[6]=1;
458  this->m_Hdr.dime.dim[7]=1;
459 
460  /* labels voxel spatial unit */
461  this->m_Hdr.dime.vox_units[0]='\0';
462  /* labels voxel calibration unit */
463  this->m_Hdr.dime.cal_units[0]='\0';
464 
465  this->m_Hdr.dime.unused1=0;
466  // Acceptable data values are DT_NONE, DT_UNKOWN, DT_BINARY,
467  // DT_UNSIGNED_CHAR
468  // DT_SIGNED_SHORT, DT_SIGNED_INT, DT_FLOAT, DT_COMPLEX, DT_DOUBLE,
469  // DT_RGB, DT_ALL
470  //this->m_Hdr.dime.datatype=DataTypeKey[DT_INDEX_UNKNOWN];
471 
472  // this->m_Hdr.dime.bitpix=DataTypeSizes[DT_INDEX_UNKNOWN];/*bits per pixel*/
473  this->m_Hdr.dime.dim_un0=0;
474 
475  // Set the voxel dimension fields:
476  // A value of 0.0 for these fields implies that the value is unknown.
477  // Change these values to what is appropriate for your data
478  // or pass additional commathis->m_Hdr.dime.dim[0] line arguments
479  this->m_Hdr.dime.pixdim[0]=0.0f;//Unused field
480  this->m_Hdr.dime.pixdim[1]=1.0f;//x_dimension
481  this->m_Hdr.dime.pixdim[2]=1.0f;//y_dimension
482  this->m_Hdr.dime.pixdim[3]=1.0f;//z_dimension
483  this->m_Hdr.dime.pixdim[4]=1.0f;//t_dimension
484  this->m_Hdr.dime.pixdim[5]=1.0f;
485  this->m_Hdr.dime.pixdim[6]=1.0f;
486  this->m_Hdr.dime.pixdim[7]=1.0f;
487  // Assume zero offset in .img file, byte at which pixel data starts in
488  // the HeaderObj file
489  // byte offset in the HeaderObj file which voxels start
490  this->m_Hdr.dime.vox_offset=0.0f;
491 
492  this->m_Hdr.dime.roi_scale=0.0f;
493  this->m_Hdr.dime.funused1=0.0f;
494  this->m_Hdr.dime.funused2=0.0f;
495  this->m_Hdr.dime.cal_max=0.0f; // specify range of calibration values
496  this->m_Hdr.dime.cal_min=0.0f; // specify range of calibration values
497  this->m_Hdr.dime.compressed=0; // specify that the data file with extension
498  // .img is not compressed
499  this->m_Hdr.dime.verified=0;
500  this->m_Hdr.dime.glmax=0; // max value for all of the data set
501  this->m_Hdr.dime.glmin=0; // min value for all of the data set
502 
503  /*data_history*/
504  this->m_Hdr.hist.descrip[0]='\0';
505  this->m_Hdr.hist.aux_file[0]='\0';
506  /*Acceptable values are*/
507  /*0-transverse unflipped*/
508  /*1-coronal unflipped*/
509  /*2-sagittal unfipped*/
510  /*3-transverse flipped*/
511  /*4-coronal flipped*/
512  /*5-sagittal flipped*/
513  // Default orientation is ITK_ANALYZE_TRANSVERSE
514  this->m_Hdr.hist.orient =
516 
517  this->m_Hdr.hist.originator[0]='\0';
518  this->m_Hdr.hist.generated[0]='\0';
519  this->m_Hdr.hist.scannum[0]='\0';
520  this->m_Hdr.hist.patient_id[0]='\0';
521  this->m_Hdr.hist.exp_date[0]='\0';
522  this->m_Hdr.hist.exp_time[0]='\0';
523  this->m_Hdr.hist.hist_un0[0]='\0';
524  this->m_Hdr.hist.views=0;
525  this->m_Hdr.hist.vols_added=0;
526  this->m_Hdr.hist.start_field=0;
527  this->m_Hdr.hist.field_skip=0;
528  this->m_Hdr.hist.omax=0;
529  this->m_Hdr.hist.omin=0;
530  this->m_Hdr.hist.smax=0;
531  this->m_Hdr.hist.smin=0;
532  this->AddSupportedWriteExtension(".hdr");
533  this->AddSupportedWriteExtension(".img");
534  this->AddSupportedWriteExtension(".img.gz");
535  this->AddSupportedReadExtension(".hdr");
536  this->AddSupportedReadExtension(".img");
537  this->AddSupportedReadExtension(".img.gz");
538 }
539 
541 {
542  //Purposefully left blank
543 }
544 
545 void AnalyzeImageIO::PrintSelf(std::ostream& os, Indent indent) const
546 {
547  Superclass::PrintSelf(os, indent);
548 }
549 
550 bool AnalyzeImageIO::CanWriteFile(const char * FileNameToWrite)
551 {
552  std::string filename(FileNameToWrite);
553  // Data file name given?
554  std::string::size_type imgPos = filename.rfind(".img");
555  if ((imgPos != std::string::npos)
556  && (imgPos == filename.length() - 4))
557  {
558  return true;
559  }
560 
561  // Header file given?
562  std::string::size_type hdrPos = filename.rfind(".hdr");
563  if ((hdrPos != std::string::npos)
564  && (hdrPos == filename.length() - 4))
565  {
566  return true;
567  }
568 
569  // Compressed image given?
570  std::string::size_type imggzPos = filename.rfind(".img.gz");
571  if ((imggzPos != std::string::npos)
572  && (imggzPos == filename.length() - 7))
573  {
574  return true;
575  }
576 
577  return false;
578 }
579 
580 
581 //Set Data Type Values and min/max values
583 // Programmer: Hans J. Johnson
584 // Date: 10/29/98
585 // Function: DefineHeaderObjDataType
586 // Algorithm: Set DataType Values appropriatly
587 // Func. Ret.:
588 // Output:
589 // Input: DataTypeIndex - Is one of the following
590 // DT_INDEX_UNSIGNED_CHAR
591 // DT_INDEX_SIGNED_SHORT DT_INDEX_SIGNED_INT
592 // DT_INDEX_FLOAT DT_INDEX_DOUBLE
593 // DT_INDEX_COMPLEX DT_INDEX_RGB
594 // DT_INDEX_BINARY DT_INDEX_UNKNOWN
597 {
598  enum DataTypeIndex eNewType;
599  switch(m_ComponentType)
600  {
601  case CHAR:
602  case UCHAR:
603  if(this->GetPixelType() == RGB)
604  {
605  eNewType = ANALYZE_DT_INDEX_RGB;
606  this->SetNumberOfComponents(3);
607  }
608  else
609  {
610  eNewType=ANALYZE_DT_INDEX_UNSIGNED_CHAR;
611  }
612  break;
613  case SHORT:
614  eNewType=ANALYZE_DT_INDEX_SIGNED_SHORT;
615  break;
616  case USHORT:
617  eNewType = SPMANALYZE_DT_INDEX_UNSIGNED_SHORT;
618  break;
619  case INT:
620  eNewType=ANALYZE_DT_INDEX_SIGNED_INT;
621  break;
622  case UINT:
623  eNewType=SPMANALYZE_DT_INDEX_UNSIGNED_INT;
624  break;
625  case FLOAT:
626  eNewType=ANALYZE_DT_INDEX_FLOAT;
627  break;
628  case DOUBLE:
629  eNewType=ANALYZE_DT_INDEX_DOUBLE;
630  break;
631  //case DATA_COMPLEX_FLOAT:
632  // eNewType=ANALYZE_DT_INDEX_COMPLEX;
633  // break;
634  //case DATA_RGBTRIPLE:
635  // eNewType=ANALYZE_DT_INDEX_RGB;
636  // break;
637  //case DATA_BINARY:
638  // eNewType=ANALYZE_DT_INDEX_BINARY;
639  // break;
640  // case
641  // DATA_UNKNOWN:
642  // eNewType=ANALYZE_DT_INDEX_UNKNOWN;
643  // break;
644  default:
645  eNewType=ANALYZE_DT_INDEX_UNKNOWN;
646  itkExceptionMacro(<< "Pixel Type Unknown");
647  }
648  m_Hdr.dime.datatype=DataTypeKey[eNewType];
649  m_Hdr.dime.bitpix=DataTypeSizes[eNewType];
650  strcpy(m_Hdr.hk.data_type,DataTypes[eNewType]);
651  switch(m_Hdr.dime.datatype)
652  {
653  case ANALYZE_DT_BINARY:
654  m_Hdr.dime.glmax=1; /*max value for all of the data set*/
655  m_Hdr.dime.glmin=0; /*min value for all of the data set*/
656  break;
657  case ANALYZE_DT_UNSIGNED_CHAR:
658  m_Hdr.dime.glmax=255;/*max value for all of the data set*/
659  m_Hdr.dime.glmin=0; /*min value for all of the data set*/
660  break;
661  case ANALYZE_DT_SIGNED_SHORT:
662  //m_Hdr.dime.glmax=0;/*max value for all of the data set*/
663  //m_Hdr.dime.glmin=0;/*min value for all of the data set*/
664  break;
665  case ANALYZE_DT_FLOAT:
666  //m_Hdr.dime.glmax=0;/*max value for all of the data set*/
667  //m_Hdr.dime.glmin=0;/*min value for all of the data set*/
668  break;
669  case ANALYZE_DT_DOUBLE:
670  //m_Hdr.dime.glmax=0;/*max value for all of the data set*/
671  //m_Hdr.dime.glmin=0;/*min value for all of the data set*/
672  break;
673  case ANALYZE_DT_RGB:
674  m_Hdr.dime.glmax=255;/*max value for all of the data set*/
675  m_Hdr.dime.glmin=0;/*min value for all of the data set*/
676  break;
677  default:
678  m_Hdr.dime.glmax=0; /*max value for all of the
679  data set*/
680  m_Hdr.dime.glmin=0; /*min value for all of
681  the data set*/
682  break;
683  }
684 }
685 
686 void AnalyzeImageIO::Read(void* buffer)
687 {
688 
689  //4 cases to handle
690  //1: given .hdr and image is .img
691  //2: given .img
692  //3: given .img.gz
693  //4: given .hdr and image is .img.gz
694  // Special processing needed for this case onl
695  // NOT NEEDED const std::string fileExt = GetExtension(m_FileName);
696 
697  /* Returns proper name for cases 1,2,3 */
698  std::string ImageFileName = GetImageFileName( m_FileName );
699  // NOTE: gzFile operations act just like FILE * operations when the
700  // files are not in gzip fromat.This greatly simplifies the
701  // following code, and gzFile types are used everywhere. In
702  // addition, it has the added benifit of reading gzip compressed
703  // image files that do not have a .gz ending.
705 
706  gzFile file_p = ::gzopen( ImageFileName.c_str(), "rb" );
707  try // try block to ensure we close the file
708  {
709  if( file_p == NULL )
710  {
711  /* Do a separate check to take care of case #4 */
712  ImageFileName += ".gz";
713  file_p = ::gzopen( ImageFileName.c_str(), "rb" );
714  if( file_p == NULL )
715  {
716  itkExceptionMacro( <<"Analyze Data File can not be read: "
717  << " The following files were attempted:\n "
718  << GetImageFileName( m_FileName ) << "\n"
719  << ImageFileName << "\n" );
720  }
721  }
722 
723  // Apply the offset if any.
724  // From itkAnalyzeDbh.h:
725  // Byte offset in the .img file at which voxels start.
726  // If value is negative specifies that the absolute value is
727  // applied for every image in the file.
728  z_off_t byteOffset = static_cast<z_off_t>(fabs(m_Hdr.dime.vox_offset));
729  if (byteOffset > 0)
730  {
731  if ( ::gzseek(file_p, byteOffset, SEEK_SET) == -1 )
732  {
733  itkExceptionMacro ( << "Analyze Data File can not be read: "
734  << " Unable to seek to the vox_offset: "
735  << byteOffset << "\n" );
736  }
737  }
738 
739 
740  // CAVEAT: gzread in particular only accepts "unsigned int" for the
741  // number of bytes to read, thus limiting the amount which may be
742  // read in a single operation on some platforms to a different limit
743  // than the corresponding fread operation.
744 
745  //size of the maximum chunk to read , if the file is larger than this it will be read as several chunks.
746  //This is due to the limitation of 'unsigned int' in the gzread() function.
747  static const unsigned int maxChunk = ANALYZE_MAXIMUM_IO_CHUNK;
748 
749  char * p = static_cast<char *>(buffer);
750 
751  SizeType bytesRemaining = this->GetImageSizeInBytes();
752  while ( bytesRemaining )
753  {
754  unsigned int bytesToRead = bytesRemaining > static_cast<SizeType>(maxChunk)
755  ? maxChunk : static_cast<unsigned int>(bytesRemaining);
756 
757  int retval = ::gzread( file_p, p, bytesToRead );
758 
759  //
760  // check for error from gzread
761  // careful .. due to unsigned/signed conversion the
762  // real return value could be -1 if a chunk equal to 2^32-1 is allowed!
763  //
764  if( retval != static_cast<int>(bytesToRead) )
765  {
766  itkExceptionMacro( << "Analyze Data File : gzread returned bad value: "
767  << retval << "\n" );
768 
769  }
770 
771  p += bytesToRead;
772  bytesRemaining -= bytesToRead;
773  }
774 
775  gzclose( file_p );
776  file_p = NULL;
777  SwapBytesIfNecessary( buffer, this->GetImageSizeInPixels() );
778  }
779  catch (...)
780  {
781  // close file and rethrow
782  if ( file_p != NULL )
783  {
784  gzclose( file_p );
785  }
786  throw;
787  }
788 }
789 
790 
791 // This method will only test if the header looks like an
792 // Analyze Header. Some code is redundant with ReadImageInformation
793 // a StateMachine could provide a better implementation
794 bool AnalyzeImageIO::CanReadFile( const char* FileNameToRead )
795 {
796  std::string filename(FileNameToRead);
797  // we check that the correct extension is given by the user
798  std::string filenameext = GetExtension(filename);
799  if(filenameext != std::string(".hdr")
800  && filenameext != std::string(".img.gz")
801  && filenameext != std::string(".img")
802  )
803  {
804  return false;
805  }
806 
807  const std::string HeaderFileName = GetHeaderFileName(filename);
808 
809  std::ifstream local_InputStream;
810  local_InputStream.open( HeaderFileName.c_str(),
811  std::ios::in | std::ios::binary );
812  if( local_InputStream.fail() )
813  {
814  return false;
815  }
816  if( ! this->ReadBufferAsBinary( local_InputStream,
817  (void *)&(this->m_Hdr),
818  sizeof(struct dsr) ) )
819  {
820  local_InputStream.close();
821  return false;
822  }
823  local_InputStream.close();
824 
825  // if the machine and file endianess are different
826  // perform the byte swapping on it
827  this->m_ByteOrder = this->CheckAnalyzeEndian(this->m_Hdr);
828  this->SwapHeaderBytesIfNecessary( &(this->m_Hdr) );
829 #ifdef OMIT_THIS_CODE
830  //It is OK for this flag to be set because the zlib will
831  //support the Unix compress files
832  if(this->m_Hdr.dime.compressed==1)
833  {
834  return false;
835  // ExceptionObject exception(__FILE__, __LINE__);
836  // exception.SetDescription("Unix compress file is not supported.");
837  // throw exception;
838  }
839 #endif
840  //The final check is to make sure that it is not a nifti
841  // version of the analyze file.
842  //Eventually the entire itkAnalyzeImageIO class will be
843  //subsumed by the nifti reader.
844  const bool NotNiftiTaggedFile=(is_nifti_file(FileNameToRead) == 0);
845  return NotNiftiTaggedFile;
846 }
847 
849 {
850  unsigned int dim;
851  const std::string HeaderFileName = GetHeaderFileName( m_FileName );
852  std::ifstream local_InputStream;
853  local_InputStream.open(HeaderFileName.c_str(),
854  std::ios::in | std::ios::binary);
855  if( local_InputStream.fail())
856  {
857  itkExceptionMacro(<< "File cannot be read");
858  }
859  if( ! this->ReadBufferAsBinary( local_InputStream,
860  (void *)&(this->m_Hdr),
861  sizeof(struct dsr) ) )
862  {
863  itkExceptionMacro(<< "Unexpected end of file");
864  }
865  local_InputStream.close();
866 
867  // if the machine and file endianess are different
868  // perform the byte swapping on it
869  this->m_ByteOrder=this->CheckAnalyzeEndian(this->m_Hdr);
870  if( this->m_MachineByteOrder != this->m_ByteOrder )
871  {
872  this->SwapHeaderBytesIfNecessary( &(this->m_Hdr) );
873  }
874 
875  // Check if any dimensions are 1. If they are, reduce dimensionality
876  // This shouldn't be necessary, but Analyse75 seems to require the first
877  // field to be 4. So when writing say a 50 x 27 2D image,
878  // m_Hdr.dime.dim[0] = 4;
879  // m_Hdr.dime.dim[1] = 50;
880  // m_Hdr.dime.dim[2] = 27;
881  // m_Hdr.dime.dim[3] = 1;
882  // m_Hdr.dime.dim[4] = 1;
883  unsigned int numberOfDimensions = this->m_Hdr.dime.dim[0];
884  if (numberOfDimensions == 0)
885  {
886  // If the dimension is 0, it may still contain valid dimension
887  // values. Let's try to compute the number of dimensions from
888  // other values. We will output a warning, but we may not want
889  // to throw an exception already.
890  const unsigned int maxNumberOfDimensions = 4;
891  for (unsigned int idx = 1;
892  (idx <= maxNumberOfDimensions) && (this->m_Hdr.dime.dim[idx]);
893  idx++)
894  {
895  if (this->m_Hdr.dime.dim[idx] > 0)
896  {
897  numberOfDimensions++;
898  }
899  else
900  {
901  itkWarningMacro( "AnalyzeImageIO is ignoring dimension " << idx << " with value " << this->m_Hdr.dime.dim[idx] );
902  }
903  }
904  }
905 
906  if (numberOfDimensions == 0)
907  {
908  itkExceptionMacro("AnalyzeImageIO cannot process file: "
909  << this->GetFileName()
910  << ". Number of dimensions is 0." <<std::endl
911  << "hdr.dime[0] = " << m_Hdr.dime.dim[0] << std::endl
912  << "hdr.dime[1] = " << m_Hdr.dime.dim[1] << std::endl
913  << "hdr.dime[2] = " << m_Hdr.dime.dim[2] << std::endl
914  << "hdr.dime[3] = " << m_Hdr.dime.dim[3] << std::endl
915  << "hdr.dime[4] = " << m_Hdr.dime.dim[4] << std::endl);
916  return;
917  }
918  while(this->m_Hdr.dime.dim[numberOfDimensions] <=1 )
919  {
920  --numberOfDimensions;
921  }
922 
923  this->SetNumberOfDimensions(numberOfDimensions);
924  this->SetNumberOfComponents(1); // default
925  switch( this->m_Hdr.dime.datatype )
926  {
927  case ANALYZE_DT_BINARY:
930  break;
931  case ANALYZE_DT_UNSIGNED_CHAR:
934  break;
935  case ANALYZE_DT_SIGNED_SHORT:
938  break;
939  case SPMANALYZE_DT_UNSIGNED_SHORT:
942  break;
943  case ANALYZE_DT_SIGNED_INT:
946  break;
947  case SPMANALYZE_DT_UNSIGNED_INT:
950  break;
951  case ANALYZE_DT_FLOAT:
954  break;
955  case ANALYZE_DT_DOUBLE:
958  break;
959  case ANALYZE_DT_RGB:
960  // DEBUG -- Assuming this is a triple, not quad
961  //image.setDataType( uiig::DATA_RGBQUAD );
963  m_PixelType = RGB;
964  this->SetNumberOfComponents(3);
965  break;
966  default:
967  break;
968  }
969  //
970  // set up the dimension stuff
971  for(dim = 0; dim < this->GetNumberOfDimensions(); dim++)
972  {
973  this->SetDimensions(dim,this->m_Hdr.dime.dim[dim+1]);
974  this->SetSpacing(dim,this->m_Hdr.dime.pixdim[dim+1]);
975  }
976  //
977  // figure out re-orientation required if not in Coronal
978  this->ComputeStrides();
979 
980  //Get Dictionary Information
981  //Insert Orientation.
982  // char temp[348];
983  //Important hk fields.
985  std::string classname(this->GetNameOfClass());
986  itk::EncapsulateMetaData<std::string>(thisDic,ITK_InputFilterName, classname);
987 
988  itk::EncapsulateMetaData<std::string>
989  (thisDic,ITK_ImageFileBaseName,std::string(this->m_Hdr.hk.db_name,18));
990 
991  //Important dime fields
992  itk::EncapsulateMetaData<std::string>
993  (thisDic,ITK_VoxelUnits,std::string(this->m_Hdr.dime.vox_units,4));
994  itk::EncapsulateMetaData<std::string>
995  (thisDic,ANALYZE_CALIBRATIONUNITS,
996  std::string(this->m_Hdr.dime.cal_units,8));
997  itk::EncapsulateMetaData<short int>
998  (thisDic,ITK_OnDiskBitPerPixel,this->m_Hdr.dime.bitpix);
999  itk::EncapsulateMetaData<float>
1000  (thisDic,SPM_ROI_SCALE,this->m_Hdr.dime.roi_scale);
1001  itk::EncapsulateMetaData<float>(thisDic,ANALYZE_CAL_MAX,
1002  this->m_Hdr.dime.cal_max);
1003  itk::EncapsulateMetaData<float>(thisDic,ANALYZE_CAL_MIN,
1004  this->m_Hdr.dime.cal_min);
1005  itk::EncapsulateMetaData<int>(thisDic,ANALYZE_GLMAX,this->m_Hdr.dime.glmax);
1006  itk::EncapsulateMetaData<int>(thisDic,ANALYZE_GLMIN,this->m_Hdr.dime.glmin);
1007 
1008  for (dim=this->GetNumberOfDimensions(); dim>0; dim--)
1009  {
1010  if (m_Hdr.dime.dim[dim] != 1)
1011  {
1012  break;
1013  }
1014  }
1015  itk::EncapsulateMetaData<int>(thisDic,ITK_NumberOfDimensions,dim);
1016 
1017  switch(this->m_Hdr.dime.datatype)
1018  {
1019  case ANALYZE_DT_BINARY:
1020  itk::EncapsulateMetaData<std::string>
1021  (thisDic,ITK_OnDiskStorageTypeName,std::string(typeid(char).name()));
1022  break;
1023  case ANALYZE_DT_UNSIGNED_CHAR:
1024  itk::EncapsulateMetaData<std::string>
1025  (thisDic,ITK_OnDiskStorageTypeName,
1026  std::string(typeid(unsigned char).name()));
1027  break;
1028  case ANALYZE_DT_SIGNED_SHORT:
1029  itk::EncapsulateMetaData<std::string>
1030  (thisDic,ITK_OnDiskStorageTypeName,
1031  std::string(typeid(short).name()));
1032  break;
1033  case SPMANALYZE_DT_UNSIGNED_SHORT:
1034  itk::EncapsulateMetaData<std::string>
1035  (thisDic,ITK_OnDiskStorageTypeName,
1036  std::string(typeid(unsigned short).name()));
1037  break;
1038  case ANALYZE_DT_SIGNED_INT:
1039  itk::EncapsulateMetaData<std::string>
1040  (thisDic,ITK_OnDiskStorageTypeName,
1041  std::string(typeid(long).name()));
1042  break;
1043  case SPMANALYZE_DT_UNSIGNED_INT:
1044  itk::EncapsulateMetaData<std::string>
1045  (thisDic,ITK_OnDiskStorageTypeName,
1046  std::string(typeid(unsigned long).name()));
1047  break;
1048  case ANALYZE_DT_FLOAT:
1049  itk::EncapsulateMetaData<std::string>
1050  (thisDic,ITK_OnDiskStorageTypeName,
1051  std::string(typeid(float).name()));
1052  break;
1053  case ANALYZE_DT_DOUBLE:
1054  itk::EncapsulateMetaData<std::string>
1055  (thisDic,ITK_OnDiskStorageTypeName,
1056  std::string(typeid(double).name()));
1057  break;
1058  case ANALYZE_DT_RGB:
1059  // DEBUG -- Assuming this is a triple, not quad
1060  //image.setDataType( uiig::DATA_RGBQUAD );
1061  itk::EncapsulateMetaData<std::string>
1062  (thisDic,ITK_OnDiskStorageTypeName,
1063  std::string(typeid(itk::RGBPixel<unsigned char>).name()));
1064  break;
1065  default:
1066  break;
1067  }
1068 
1069  //Important hist fields
1070  itk::EncapsulateMetaData<std::string>
1071  (thisDic,ITK_FileNotes,
1072  std::string(this->m_Hdr.hist.descrip,80));
1073  itk::EncapsulateMetaData<std::string>
1074  (thisDic,ANALYZE_AUX_FILE_NAME,
1075  std::string(this->m_Hdr.hist.aux_file,24));
1076 
1079  (this->m_Hdr.hist.orient);
1081  switch (temporient)
1082  {
1085  break;
1088  break;
1091  break;
1092  default:
1094  itkWarningMacro( "Unknown orientation in file " << m_FileName );
1095  }
1096  // An error was encountered in code that depends upon the
1097  // valid coord_orientation.
1098  typedef SpatialOrientationAdapter OrientAdapterType;
1100  OrientAdapterType().ToDirectionCosines(coord_orient);
1101  unsigned dims = this->GetNumberOfDimensions();
1102  // always have at least 3 dimensions for the purposes of
1103  // setting directions
1104 #define itkAnalzyeImageIO_MINDIMS_IS_THREE ( (dims < 3) ? 3 : dims)
1105  std::vector<double> dirx( itkAnalzyeImageIO_MINDIMS_IS_THREE,0),
1108 #undef itkAnalzyeImageIO_MINDIMS_IS_THREE
1109 
1110  dirx[0] = dir[0][0];
1111  dirx[1] = dir[1][0];
1112  dirx[2] = dir[2][0];
1113  diry[0] = dir[0][1];
1114  diry[1] = dir[1][1];
1115  diry[2] = dir[2][1];
1116  dirz[0] = dir[0][2];
1117  dirz[1] = dir[1][2];
1118  dirz[2] = dir[2][2];
1119  for(unsigned i = 3; i < dims; i++)
1120  {
1121  dirx[i] = diry[i] = dirz[i] = 0;
1122  }
1123  this->SetDirection(0,dirx);
1124  this->SetDirection(1,diry);
1125  if(numberOfDimensions > 2)
1126  {
1127  this->SetDirection(2,dirz);
1128  }
1129  else
1130  {
1131  //
1132  // don't allow degenerate direction cosines
1133  // This is a pure punt; it will prevent the exception being
1134  // thrown, but doesn't do the right thing at all -- replacing e.g
1135  // [0, 0, -1] with [0, 1] doesn't make any real sense.
1136  // On the other hand, programs that depend on 2D Direction Cosines
1137  // are pretty much guaranteed to be disappointed if they expect anything
1138  // meaningful in the direction cosines anyway.
1139  if(dirx[0] == 0.0 && dirx[1] == 0.0)
1140  {
1141  if(diry[0] != 0)
1142  {
1143  dirx[1] = 1.0;
1144  }
1145  else
1146  {
1147  dirx[0] = 1.0;
1148  }
1149  }
1150  else if(diry[0] == 0.0 && diry[1] == 0.0)
1151  {
1152  if(dirx[0] != 0)
1153  {
1154  diry[1] = 1.0;
1155  }
1156  else
1157  {
1158  diry[0] = 1.0;
1159  }
1160  }
1161  }
1162 #if defined(ITKIO_DEPRECATED_METADATA_ORIENTATION)
1165  (thisDic,ITK_CoordinateOrientation, coord_orient);
1166 #endif
1167 
1168  itk::EncapsulateMetaData<std::string>
1169  (thisDic,ITK_FileOriginator,
1170  std::string(this->m_Hdr.hist.originator,10));
1171  itk::EncapsulateMetaData<std::string>
1172  (thisDic,ITK_OriginationDate,
1173  std::string(this->m_Hdr.hist.generated,10));
1174  itk::EncapsulateMetaData<std::string>
1175  (thisDic,ANALYZE_ScanNumber,
1176  std::string(this->m_Hdr.hist.scannum,10));
1177  itk::EncapsulateMetaData<std::string>
1178  (thisDic,ITK_PatientID,
1179  std::string(this->m_Hdr.hist.patient_id,10));
1180  itk::EncapsulateMetaData<std::string>
1181  (thisDic,ITK_ExperimentDate,
1182  std::string(this->m_Hdr.hist.exp_date,10));
1183  itk::EncapsulateMetaData<std::string>
1184  (thisDic,ITK_ExperimentTime,
1185  std::string(this->m_Hdr.hist.exp_time,10));
1186 
1187  itk::EncapsulateMetaData<int>
1188  (thisDic,ANALYZE_O_MAX,
1189  this->m_Hdr.hist.omax);
1190  itk::EncapsulateMetaData<int>
1191  (thisDic,ANALYZE_O_MIN,
1192  this->m_Hdr.hist.omin);
1193  itk::EncapsulateMetaData<int>
1194  (thisDic,ANALYZE_S_MAX,
1195  this->m_Hdr.hist.smax);
1196  itk::EncapsulateMetaData<int>
1197  (thisDic,ANALYZE_S_MIN,
1198  this->m_Hdr.hist.smin);
1199  return;
1200 }
1201 
1205 void
1208 {
1209  // First of all we need to not go any further if there's
1210  // a dimension of the image that won't fit in a 16 bit short.
1211  for(unsigned int i = 0; i < this->GetNumberOfDimensions(); i++)
1212  {
1213  unsigned int curdim(this->GetDimensions(i));
1214  if(curdim > static_cast<unsigned int>(NumericTraits<short>::max()))
1215  {
1216  itkExceptionMacro( << "Dimension(" << i << ") = " << curdim
1217  << " is greater than maximum possible dimension "
1219 
1220  }
1221  }
1222  unsigned int dim;
1223  if(this->GetPixelType() == RGB)
1224  {
1225  if(this->GetComponentType() != UCHAR)
1226  {
1227  itkExceptionMacro(<< "Only unsigned char RGB files supported");
1228  }
1229  }
1230  else
1231  {
1232  if(this->GetNumberOfComponents() > 1)
1233  {
1234  itkExceptionMacro(<< "More than one component per pixel not supported");
1235  }
1236  }
1237 
1238  const std::string HeaderFileName = GetHeaderFileName( m_FileName );
1239  std::ofstream local_OutputStream;
1240  local_OutputStream.open( HeaderFileName.c_str(),
1241  std::ios::out | std::ios::binary );
1242  if( local_OutputStream.fail() )
1243  {
1244  itkExceptionMacro(<< "File cannot be written");
1245  }
1246  std::string temp;
1247  //
1248  // most likely NONE of this below does anything useful because
1249  // the MetaDataDictionary is basically not set with any of these fields
1250  // except by the image file reader.
1251  //Important hk fields.
1252  itk::MetaDataDictionary &thisDic=this->GetMetaDataDictionary();
1253 
1254  if(itk::ExposeMetaData<std::string>(thisDic,ITK_ImageFileBaseName,temp))
1255  {
1256  strncpy(this->m_Hdr.hk.db_name,temp.c_str(),18);
1257  }
1258  //Important dime fields
1259  if(itk::ExposeMetaData<std::string>(thisDic,ITK_VoxelUnits,temp))
1260  {
1261  strncpy(this->m_Hdr.dime.vox_units,temp.c_str(),4);
1262  }
1263 
1264  if(itk::ExposeMetaData<std::string>(thisDic,ANALYZE_CALIBRATIONUNITS,temp))
1265  {
1266  strncpy(this->m_Hdr.dime.cal_units,temp.c_str(),8);
1267  }
1268 
1269  itk::ExposeMetaData<short int>
1270  (thisDic,ITK_OnDiskBitPerPixel,
1271  this->m_Hdr.dime.bitpix);
1272  itk::ExposeMetaData<float>
1273  (thisDic,SPM_ROI_SCALE,
1274  this->m_Hdr.dime.roi_scale);
1275  itk::ExposeMetaData<float>
1276  (thisDic,ANALYZE_CAL_MAX,
1277  this->m_Hdr.dime.cal_max);
1278  itk::ExposeMetaData<float>
1279  (thisDic,ANALYZE_CAL_MIN,
1280  this->m_Hdr.dime.cal_min);
1281  itk::ExposeMetaData<int>
1282  (thisDic,ANALYZE_GLMAX,
1283  this->m_Hdr.dime.glmax);
1284  itk::ExposeMetaData<int>
1285  (thisDic,ANALYZE_GLMIN,
1286  this->m_Hdr.dime.glmin);
1287  //Important hist fields
1288  if(itk::ExposeMetaData<std::string>(thisDic,ITK_FileNotes,temp))
1289  {
1290  strncpy(this->m_Hdr.hist.descrip,temp.c_str(),80);
1291  }
1292 
1293  if(itk::ExposeMetaData<std::string>(thisDic,ANALYZE_AUX_FILE_NAME,temp))
1294  {
1295  strncpy(this->m_Hdr.hist.aux_file,temp.c_str(),24);
1296  }
1297 
1300 #if defined(ITKIO_DEPRECATED_METADATA_ORIENTATION)
1301  if ( !itk::ExposeMetaData
1303  (thisDic,ITK_CoordinateOrientation, coord_orient) )
1304  {
1305 #endif
1306  typedef itk::SpatialOrientationAdapter::DirectionType DirectionType;
1307  DirectionType dir;
1308  unsigned int dims = this->GetNumberOfDimensions();
1309  std::vector<double> dirx = this->GetDirection(0);
1310  std::vector<double> diry = this->GetDirection(1);
1311  std::vector<double> dirz;
1312  if(dims > 2)
1313  {
1314  dirz = this->GetDirection(2);
1315  }
1316  else
1317  {
1318  for(unsigned i = 0; i < 3; i++)
1319  {
1320  dirz.push_back(0.0);
1321  }
1322  }
1323  unsigned int i;
1324  for(i = 0; i < dims; i++)
1325  {
1326  dir[i][0] = dirx[i];
1327  dir[i][1] = diry[i];
1328  dir[i][2] = dirz[i];
1329  }
1330  for(; i < 3; i++)
1331  {
1332  dir[i][0] =
1333  dir[i][1] =
1334  dir[i][2] = 0;
1335  }
1336  coord_orient =
1338 #if defined(ITKIO_DEPRECATED_METADATA_ORIENTATION)
1339  }
1340 #endif
1341  switch (coord_orient)
1342  {
1344  this->m_Hdr.hist.orient =
1346  break;
1348  this->m_Hdr.hist.orient =
1350  break;
1352  this->m_Hdr.hist.orient =
1354  break;
1355  default:
1356  this->m_Hdr.hist.orient =
1358  itkWarningMacro( "ERROR: Analyze 7.5 File Format"
1359  " Only Allows RPI, PIR, and RIP Orientation " );
1360  }
1361 
1362  if(itk::ExposeMetaData<std::string>(thisDic,ITK_FileOriginator,temp))
1363  {
1364  strncpy(this->m_Hdr.hist.originator,temp.c_str(),10);
1365  }
1366 
1367  if(itk::ExposeMetaData<std::string>(thisDic,ITK_OriginationDate,temp))
1368  {
1369  strncpy(this->m_Hdr.hist.generated,temp.c_str(),10);
1370  }
1371 
1372  if(itk::ExposeMetaData<std::string>(thisDic,ANALYZE_ScanNumber,temp))
1373  {
1374  strncpy(this->m_Hdr.hist.scannum,temp.c_str(),10);
1375  }
1376 
1377  if(itk::ExposeMetaData<std::string>(thisDic,ITK_PatientID,temp))
1378  {
1379  strncpy(this->m_Hdr.hist.patient_id,temp.c_str(),10);
1380  }
1381 
1382  if(itk::ExposeMetaData<std::string>(thisDic,ITK_ExperimentDate,temp))
1383  {
1384  strncpy(this->m_Hdr.hist.exp_date,temp.c_str(),10);
1385  }
1386 
1387  if(itk::ExposeMetaData<std::string>(thisDic,ITK_ExperimentTime,temp))
1388  {
1389  strncpy(this->m_Hdr.hist.exp_time,temp.c_str(),10);
1390  }
1391 
1392  itk::ExposeMetaData<int>(thisDic,ANALYZE_O_MAX,this->m_Hdr.hist.omax);
1393  itk::ExposeMetaData<int>(thisDic,ANALYZE_O_MIN,this->m_Hdr.hist.omin);
1394  itk::ExposeMetaData<int>(thisDic,ANALYZE_S_MAX,this->m_Hdr.hist.smax);
1395  itk::ExposeMetaData<int>(thisDic,ANALYZE_S_MIN,this->m_Hdr.hist.smin);
1396 
1397  // Check for image dimensions to be smaller enough to fit in
1398  // a short int. First generate the number that is the maximum allowable.
1399  const SizeValueType maximumNumberOfPixelsAllowedInOneDimension =
1400  itk::NumericTraits<short>::max();
1401 
1402  for( dim=0; dim< this->GetNumberOfDimensions(); dim++ )
1403  {
1404  const SizeValueType numberOfPixelsAlongThisDimension = m_Dimensions[ dim ];
1405 
1406  if( numberOfPixelsAlongThisDimension > maximumNumberOfPixelsAllowedInOneDimension )
1407  {
1408  itkExceptionMacro("Number of pixels along dimension " << dim
1409  << " is " << numberOfPixelsAlongThisDimension <<
1410  " which exceeds maximum allowable dimension of " <<
1411  maximumNumberOfPixelsAllowedInOneDimension );
1412  }
1413 
1414  //NOTE: Analyze dim[0] are the number of dims, and dim[1..7] are
1415  // the actual dims.
1416  this->m_Hdr.dime.dim[dim+1] = numberOfPixelsAlongThisDimension;
1417  }
1418 
1419  //DEBUG--HACK It seems that analyze 7.5 requires 4 dimensions.
1420  this->m_Hdr.dime.dim[0]= 4;
1421  for( dim=this->GetNumberOfDimensions();(int)dim < this->m_Hdr.dime.dim[0];
1422  dim++ )
1423  {
1424  //NOTE: Analyze dim[0] are the number of dims,
1425  //and dim[1..7] are the actual dims.
1426  this->m_Hdr.dime.dim[dim+1] = 1; //Hardcoded to be 1;
1427  }
1428  for( dim=0; dim< this->GetNumberOfDimensions(); dim++ )
1429  {
1430  //NOTE: Analyze pixdim[0] is ignored, and the number of dims are
1431  //taken from dims[0], and pixdim[1..7] are the actual pixdims.
1432  this->m_Hdr.dime.pixdim[dim+1]= static_cast< float >( m_Spacing[ dim ] );
1433  }
1434  //The next funciton sets bitpix, and datatype, and data_type fields
1435  //Along with gl_min and gl_max fields.
1436  this->DefineHeaderObjectDataType();
1437 
1438  local_OutputStream.write( (const char *)&(this->m_Hdr), sizeof(struct dsr) );
1439  if( local_OutputStream.eof() )
1440  {
1441  itkExceptionMacro(<< "Unexpected end of file");
1442  }
1443  local_OutputStream.close();
1444  return;
1445 }
1446 
1447 
1451 std::vector<double>
1453 ::GetDirection( unsigned int k ) const
1454 {
1455  std::vector<double> correctedDirection = this->ImageIOBase::GetDirection(k);
1456  if( this->m_Dimensions.size() == correctedDirection.size() )
1457  {
1458  return correctedDirection;
1459  }
1460 
1461  // Apply corrections for 2D cases
1462  std::vector<double> direction0 = this->ImageIOBase::GetDirection(0);
1463  std::vector<double> direction1 = this->ImageIOBase::GetDirection(1);
1464 
1465  if( k == 0 )
1466  {
1467  if(direction0[0] == 0.0 && direction1[0] == 0)
1468  {
1469  if(direction0[1] == 0.0)
1470  {
1471  correctedDirection[0] = 1.0;
1472  }
1473  }
1474  }
1475 
1476  if( k == 1 )
1477  {
1478  if(direction0[0] == 0.0 && direction1[0] == 0)
1479  {
1480  if(direction1[1] == 0.0)
1481  {
1482  correctedDirection[0] = 1.0;
1483  }
1484  }
1485  else if(direction0[1] == 0.0 && direction1[1] == 0)
1486  {
1487  if(direction0[0] == 0.0)
1488  {
1489  correctedDirection[0] = 1.0;
1490  }
1491  if(direction1[0] == 0.0)
1492  {
1493  correctedDirection[1] = 1.0;
1494  }
1495  }
1496  }
1497 
1498  return correctedDirection;
1499 }
1500 
1501 
1505 std::vector<double>
1507 ::GetDefaultDirection( unsigned int k ) const
1508 {
1509  std::vector<double> defaultDirection = this->ImageIOBase::GetDefaultDirection(k);
1510 
1511  // Apply corrections for 2D cases
1512  std::vector<double> direction0 = this->GetDirection(0);
1513  std::vector<double> direction1 = this->GetDirection(1);
1514 
1515  if( k == 0 )
1516  {
1517  if(direction0[0] == 0.0 && direction1[0] == 0)
1518  {
1519  if(direction0[1] == 0.0)
1520  {
1521  defaultDirection[0] = 1.0;
1522  }
1523  }
1524  }
1525 
1526  if( k == 1 )
1527  {
1528  if(direction0[0] == 0.0 && direction1[0] == 0)
1529  {
1530  if(direction1[1] == 0.0)
1531  {
1532  defaultDirection[0] = 1.0;
1533  }
1534  }
1535  else if(direction0[1] == 0.0 && direction1[1] == 0)
1536  {
1537  if(direction0[0] == 0.0)
1538  {
1539  defaultDirection[0] = 1.0;
1540  }
1541  if(direction1[0] == 0.0)
1542  {
1543  defaultDirection[1] = 1.0;
1544  }
1545  }
1546  }
1547 
1548  return defaultDirection;
1549 }
1550 
1551 
1555 void
1557 ::Write( const void* buffer)
1558 {
1559  //Write the image Information before writing data
1560  this->WriteImageInformation();
1561 
1562  //NOTE: voidp is defined by zlib.h
1563  //NOTE: Need const_cast because voidp is "void*", so
1564  // "const voidp" is "void* const", not "const void*".
1565  voidp p = const_cast<voidp>(buffer);
1566  const std::string ImageFileName = GetImageFileName( m_FileName );
1567  const std::string fileExt = GetExtension( m_FileName );
1568  // Check case where image is acually a compressed image
1569 
1570  if(!fileExt.compare( ".img.gz" ))
1571  {
1572  // Open the *.img.gz file for writing.
1573  gzFile file_p = ::gzopen( ImageFileName.c_str(), "wb" );
1574  if( file_p==NULL )
1575  {
1576  itkExceptionMacro( << "Error, Can not write compressed image file for " << m_FileName );
1577  }
1578 
1579  try // try block to ensure file gets closed
1580  {
1581  // CAVEAT: gzwrite in particular only accepts "unsigned int" for the
1582  // number of bytes to read, thus limiting the amount which may be
1583  // read in a single operation on some platforms to a different limit
1584  // than the corresponding fread operation.
1585 
1586  static const unsigned int maxChunk = ANALYZE_MAXIMUM_IO_CHUNK;
1587 
1588  SizeType bytesRemaining = this->GetImageSizeInBytes();
1589  while ( bytesRemaining )
1590  {
1591  unsigned int bytesToWrite = bytesRemaining > static_cast<SizeType>(maxChunk)
1592  ? maxChunk : static_cast<unsigned int>(bytesRemaining);
1593 
1594  if( ::gzwrite(file_p, p, bytesToWrite ) != static_cast<int>(bytesToWrite) )
1595  {
1596  itkExceptionMacro( << "Error, Can not write compressed image file for "<< m_FileName );
1597  }
1598  p = static_cast<char *>( p ) + bytesToWrite;
1599  bytesRemaining -= bytesToWrite;
1600  }
1601  ::gzclose( file_p );
1602  file_p = NULL;
1603  }
1604  catch (...)
1605  {
1606  // close file and rethrow exception
1607  if ( file_p != NULL )
1608  {
1609  ::gzclose( file_p );
1610  }
1611  throw;
1612  }
1613 
1614  //RemoveFile FileNameToRead.img so that it does not get confused with
1615  //FileNameToRead.img.gz
1616  //The following is a hack that can be used to remove ambiguity when an
1617  //uncompressed image is read, and then written as compressed.
1618  //This results in one *.hdr file being assosiated with a *.img and a
1619  // *.img.gz image file.
1620  //DEBUG -- Will this work under windows?
1621  std::string unusedbaseimgname = GetRootName(GetHeaderFileName(m_FileName));
1622  unusedbaseimgname += ".img";
1623  itksys::SystemTools::RemoveFile(unusedbaseimgname.c_str());
1624  }
1625  else
1626  {
1627  //No compression
1628  std::ofstream local_OutputStream;
1629  local_OutputStream.open( ImageFileName.c_str(), std::ios::out | std::ios::binary );
1630  if( !local_OutputStream )
1631  {
1632  itkExceptionMacro( << "Error opening image data file for writing."
1633  << m_FileName );
1634  }
1635  local_OutputStream.write((const char *)p, static_cast< std::streamsize >( this->GetImageSizeInBytes() ) );
1636  bool success = !local_OutputStream.bad();
1637  local_OutputStream.close();
1638  if( !success )
1639  {
1640  itkExceptionMacro( << "Error writing image data."
1641  << m_FileName );
1642  }
1643  //RemoveFile FileNameToRead.img.gz so that it does not get confused with FileNameToRead.img
1644  //The following is a hack that can be used to remove ambiguity when an
1645  //uncompressed image is read, and then written as compressed.
1646  //This results in one *.hdr file being assosiated with a *.img and a *.img.gz image file.
1647  //DEBUG -- Will this work under windows?
1648  std::string unusedbaseimgname = GetRootName(GetHeaderFileName(m_FileName));
1649  unusedbaseimgname += ".img.gz";
1650  itksys::SystemTools::RemoveFile(unusedbaseimgname.c_str());
1651  }
1652 }
1653 
1654 } // end namespace itk

Generated at Sat May 18 2013 23:25:06 for Orfeo Toolbox with doxygen 1.8.3.1