00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "cmtkScalarImageIO.h"
00034
00035 #include <stdio.h>
00036
00037 #include <Base/cmtkTypes.h>
00038 #include <System/cmtkCompressedStream.h>
00039 #include <IO/cmtkFileHeader.h>
00040 #include <IO/cmtkAnalyze.h>
00041
00042 namespace
00043 cmtk
00044 {
00045
00048
00049 ScalarImage*
00050 ScalarImageIO::ReadAnalyze( const char* pathHdr )
00051 {
00052 #ifdef _MSC_VER
00053 FILE *hdrFile = fopen( pathHdr, "rb" );
00054 #else
00055 FILE *hdrFile = fopen( pathHdr, "r" );
00056 #endif
00057 if ( !hdrFile )
00058 {
00059 StdErr.printf( "ERROR: could not open Analyze header file %s\n",
00060 pathHdr );
00061 return NULL;
00062 }
00063
00064 char buffer[348];
00065 if ( 348 != fread( buffer, 1, 348, hdrFile ) )
00066 {
00067 StdErr.printf( "ERROR: could not read 348 bytes from header file %s\n", pathHdr );
00068 fclose( hdrFile );
00069 return NULL;
00070 }
00071 fclose( hdrFile );
00072
00073 const bool bigEndian = (buffer[3] == '\x5C');
00074 FileHeader header( buffer, bigEndian );
00075
00076 short ndims = header.GetField<short>( 40 );
00077 if ( ndims < 2 )
00078 {
00079 StdErr.printf( "ERROR: image dimension %d is smaller than 2 in file "
00080 "%s\n", ndims, pathHdr );
00081 return NULL;
00082 }
00083
00084 int dims[4];
00085 dims[0] = header.GetField<short>( 42 );
00086 dims[1] = header.GetField<short>( 44 );
00087 dims[2] = header.GetField<short>( 46 );
00088 dims[3] = header.GetField<short>( 48 );
00089
00090 if ( (ndims > 2) && ((dims[2] > 1) || (dims[3] > 1)) )
00091 {
00092 StdErr.printf( "WARNING: dimension %d is greater than 2 in file %s\n",
00093 ndims, pathHdr );
00094 }
00095
00096 float pixelDim[2];
00097 header.GetArray( pixelDim, 80, 2 );
00098
00099 ScalarImage* image = new ScalarImage( dims[0], dims[1] );
00100 image->SetPixelSize( pixelDim[0], pixelDim[1] );
00101
00102 ScalarDataType dtype;
00103 switch ( header.GetField<short>( 70 ) )
00104 {
00105 case cmtk::ANALYZE_TYPE_NONE:
00106 case cmtk::ANALYZE_TYPE_BINARY:
00107 case cmtk::ANALYZE_TYPE_COMPLEX:
00108 case cmtk::ANALYZE_TYPE_RGB:
00109 case cmtk::ANALYZE_TYPE_ALL:
00110 default:
00111 StdErr.printf( "ERROR: unsupported data type in Analyze file %s\n",
00112 pathHdr );
00113 return NULL;
00114 case cmtk::ANALYZE_TYPE_UNSIGNED_CHAR:
00115 dtype = TYPE_BYTE;
00116 break;
00117 case cmtk::ANALYZE_TYPE_SIGNED_SHORT:
00118 dtype = TYPE_SHORT;
00119 break;
00120 case cmtk::ANALYZE_TYPE_SIGNED_INT:
00121 dtype = TYPE_INT;
00122 break;
00123 case cmtk::ANALYZE_TYPE_FLOAT:
00124 dtype = TYPE_FLOAT;
00125 break;
00126 case cmtk::ANALYZE_TYPE_DOUBLE:
00127 dtype = TYPE_DOUBLE;
00128 break;
00129 }
00130 image->CreatePixelData( dtype );
00131
00132 size_t offset = static_cast<size_t>( header.GetField<float>( 108 ) );
00133
00134 char* pathImg = Memory::AllocateArray<char>( 4 + strlen( pathHdr ) );
00135 strcpy( pathImg, pathHdr );
00136 char* suffix = strstr( pathImg, ".hdr" );
00137 if ( suffix ) *suffix = 0;
00138 strcat( pathImg, ".img" );
00139
00140 CompressedStream stream( pathImg );
00141 if ( stream.IsValid() )
00142 {
00143 stream.Seek( offset, SEEK_CUR );
00144
00145 TypedArray::SmartPtr data = image->GetPixelData();
00146 stream.Read
00147 ( data->GetDataPtr(), data->GetItemSize(), data->GetDataSize() );
00148
00149 #ifdef WORDS_BIGENDIAN
00150 if ( ! bigEndian ) data->ChangeEndianness();
00151 #else
00152 if ( bigEndian ) data->ChangeEndianness();
00153 #endif
00154
00155 }
00156 else
00157 {
00158 StdErr.printf( "WARNING: could not open Analyze image file %s\n",
00159 pathImg );
00160 }
00161
00162 Memory::DeleteArray( pathImg );
00163
00164 return image;
00165 }
00166
00167 void
00168 ScalarImageIO::WriteAnalyze
00169 ( const char* pathHdr, const ScalarImage* image )
00170 {
00171 const TypedArray* data = image->GetPixelData();
00172 if ( ! data ) return;
00173
00174 char buffer[348];
00175 #ifdef WORDS_BIGENDIAN
00176 FileHeader header( buffer, true );
00177 #else
00178 FileHeader header( buffer, false );
00179 #endif
00180
00181 header.StoreField<int>( 0, 348 );
00182 header.StoreField<int>( 32, 16384 );
00183 header.StoreField<short>( 36, 0 );
00184 header.StoreField<char>( 38, 'r' );
00185
00186
00187 header.StoreField<short>( 40, 4 );
00188
00189
00190 header.StoreField<short>( 42, image->GetDims()[AXIS_X] );
00191 header.StoreField<short>( 44, image->GetDims()[AXIS_Y] );
00192 header.StoreField<short>( 46, 1 );
00193 header.StoreField<short>( 48, 1 );
00194 header.StoreField<short>( 50, 0 );
00195 header.StoreField<short>( 52, 0 );
00196 header.StoreField<short>( 54, 0 );
00197
00198 header.StoreField<float>( 68, 0.0 );
00199 switch ( data->GetType() )
00200 {
00201 default:
00202 header.StoreField<short>( 70, cmtk::ANALYZE_TYPE_NONE );
00203 header.StoreField<short>( 72, 0 );
00204 break;
00205 case TYPE_BYTE:
00206 header.StoreField<short>( 70, cmtk::ANALYZE_TYPE_UNSIGNED_CHAR );
00207 header.StoreField<short>( 72, 8 * sizeof( unsigned char ) );
00208 break;
00209 case TYPE_SHORT:
00210 case TYPE_USHORT:
00211 header.StoreField<short>( 70, cmtk::ANALYZE_TYPE_SIGNED_SHORT );
00212 header.StoreField<short>( 72, 8 * sizeof( short ) );
00213 break;
00214 case TYPE_INT:
00215 header.StoreField<short>( 70, cmtk::ANALYZE_TYPE_SIGNED_INT );
00216 header.StoreField<short>( 72, 8 * sizeof( int ) );
00217 break;
00218 case TYPE_FLOAT:
00219 header.StoreField<short>( 70, cmtk::ANALYZE_TYPE_FLOAT );
00220 header.StoreField<short>( 72, 8 * sizeof( float ) );
00221 break;
00222 case TYPE_DOUBLE:
00223 header.StoreField<short>( 70, cmtk::ANALYZE_TYPE_DOUBLE );
00224 header.StoreField<short>( 72, 8 * sizeof( double ) );
00225 break;
00226 }
00227
00228 header.StoreField<float>( 80, (float)image->GetPixelSize( AXIS_X ) );
00229 header.StoreField<float>( 84, (float)image->GetPixelSize( AXIS_Y ) );
00230 header.StoreField<float>( 88, 1.0f );
00231 header.StoreField<float>( 92, 1.0f );
00232 header.StoreField<float>( 96, 1.0f );
00233
00234
00235 header.StoreField<float>( 108, 0.0f );
00236
00237
00238 const Types::DataItemRange dataRange = data->GetRange();
00239
00240 header.StoreField<float>( 124, static_cast<float>( dataRange.m_UpperBound ) );
00241 header.StoreField<float>( 128, static_cast<float>( dataRange.m_LowerBound ) );
00242
00243 header.StoreField<int>( 140, static_cast<int>( dataRange.m_UpperBound ) );
00244 header.StoreField<int>( 144, static_cast<int>( dataRange.m_LowerBound ) );
00245
00246
00247 header.StoreField<byte>( 252, 0 );
00248
00249
00250 #ifdef MSC_VER
00251 FILE *hdrFile = fopen( pathHdr, "wb" );
00252 #else
00253 FILE *hdrFile = fopen( pathHdr, "w" );
00254 #endif
00255 if ( hdrFile )
00256 {
00257 if ( 348 != fwrite( buffer, 1, 348, hdrFile ) )
00258 {
00259 StdErr.printf( "ERROR: could not write 348 bytes to header file %s\n",
00260 pathHdr );
00261 }
00262 fclose( hdrFile );
00263 }
00264
00265
00266 char* pathImg = Memory::AllocateArray<char>( 4 + strlen( pathHdr ) );
00267 strcpy( pathImg, pathHdr );
00268 char* suffix = strstr( pathImg, ".hdr" );
00269 if ( suffix ) *suffix = 0;
00270 strcat( pathImg, ".img" );
00271
00272 #ifdef _MSC_VER
00273 FILE *imgFile = fopen( pathImg, "wb" );
00274 #else
00275 FILE *imgFile = fopen( pathImg, "w" );
00276 #endif
00277 if ( imgFile )
00278 {
00279 fwrite( data->GetDataPtr(), data->GetItemSize(), data->GetDataSize(), imgFile );
00280 fclose( imgFile );
00281 }
00282
00283 Memory::DeleteArray( pathImg );
00284 }
00285
00286 }