1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkNIFTIImageHeader.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15
16 #include "vtkNIFTIImageHeader.h"
17 #include "vtkNIFTIImagePrivate.h"
18
19 #include "vtkObjectFactory.h"
20
21 #include <cctype>
22 #include <cfloat>
23 #include <cmath>
24 #include <cstring>
25
26 vtkStandardNewMacro(vtkNIFTIImageHeader);
27
28 //------------------------------------------------------------------------------
29 namespace
30 {
31
32 // utility function to normalize floats that are close to zero
vtkNIFTINormalizeFloat(double d)33 double vtkNIFTINormalizeFloat(double d)
34 {
35 return (fabs(d) < FLT_MIN ? 0.0 : d);
36 }
37
vtkNIFTINormalizeDouble(double d)38 double vtkNIFTINormalizeDouble(double d)
39 {
40 return (fabs(d) < DBL_MIN ? 0.0 : d);
41 }
42 } // end anonymous namespace
43
44 //------------------------------------------------------------------------------
vtkNIFTIImageHeader()45 vtkNIFTIImageHeader::vtkNIFTIImageHeader()
46 {
47 this->Initialize();
48 }
49
50 //------------------------------------------------------------------------------
51 vtkNIFTIImageHeader::~vtkNIFTIImageHeader() = default;
52
53 //------------------------------------------------------------------------------
Initialize()54 void vtkNIFTIImageHeader::Initialize()
55 {
56 memset(this->Magic, '\0', sizeof(this->Magic));
57 this->VoxOffset = 0;
58 this->DataType = 0;
59 this->BitPix = 0;
60 for (int i = 0; i < 8; i++)
61 {
62 this->Dim[i] = 0;
63 this->PixDim[i] = 0.0;
64 }
65 this->IntentCode = 0;
66 memset(this->IntentName, '\0', sizeof(this->IntentName));
67 this->IntentP1 = 0.0;
68 this->IntentP2 = 0.0;
69 this->IntentP3 = 0.0;
70 this->SclSlope = 0.0;
71 this->SclInter = 0.0;
72 this->CalMin = 0.0;
73 this->CalMax = 0.0;
74 this->SliceDuration = 0.0;
75 this->TOffset = 0.0;
76 this->SliceStart = 0;
77 this->SliceEnd = 0;
78 this->SliceCode = 0;
79 this->XYZTUnits = 0;
80 this->DimInfo = 0;
81 memset(this->Descrip, '\0', sizeof(this->Descrip));
82 memset(this->AuxFile, '\0', sizeof(this->AuxFile));
83 this->QFormCode = 0;
84 this->SFormCode = 0;
85 this->QuaternB = 0.0;
86 this->QuaternC = 0.0;
87 this->QuaternD = 0.0;
88 this->QOffsetX = 0.0;
89 this->QOffsetY = 0.0;
90 this->QOffsetZ = 0.0;
91 for (int i = 0; i < 4; i++)
92 {
93 this->SRowX[i] = 0.0;
94 this->SRowY[i] = 0.0;
95 this->SRowZ[i] = 0.0;
96 }
97 }
98
99 //------------------------------------------------------------------------------
SetHeader(const nifti_1_header * hdr)100 void vtkNIFTIImageHeader::SetHeader(const nifti_1_header* hdr)
101 {
102 // clear all fields (in case supplied header is Analyze 7.5)
103 this->Initialize();
104
105 // check if header is NIfTI (vs. Analyze 7.5)
106 bool isnifti = (hdr->magic[0] == 'n' && (hdr->magic[1] == '+' || hdr->magic[1] == 'i') &&
107 hdr->magic[2] == '1' && hdr->magic[3] == '\0');
108
109 if (isnifti)
110 {
111 memcpy(this->Magic, hdr->magic, sizeof(hdr->magic));
112 }
113 this->VoxOffset = static_cast<vtkTypeInt64>(hdr->vox_offset);
114 this->DataType = hdr->datatype;
115 this->BitPix = hdr->bitpix;
116 for (int i = 0; i < 8; i++)
117 {
118 this->Dim[i] = hdr->dim[i];
119 this->PixDim[i] = hdr->pixdim[i];
120 }
121 if (isnifti)
122 {
123 this->IntentCode = hdr->intent_code;
124 strncpy(this->IntentName, hdr->intent_name, sizeof(this->IntentName));
125 this->IntentP1 = hdr->intent_p1;
126 this->IntentP2 = hdr->intent_p2;
127 this->IntentP3 = hdr->intent_p3;
128 this->SclSlope = hdr->scl_slope;
129 this->SclInter = hdr->scl_inter;
130 }
131 this->CalMin = hdr->cal_min;
132 this->CalMax = hdr->cal_max;
133 if (isnifti)
134 {
135 this->SliceDuration = hdr->slice_duration;
136 this->TOffset = hdr->toffset;
137 this->SliceStart = hdr->slice_start;
138 this->SliceEnd = hdr->slice_end;
139 this->SliceCode = hdr->slice_code;
140 }
141 this->XYZTUnits = hdr->xyzt_units;
142 this->DimInfo = hdr->dim_info;
143 strncpy(this->Descrip, hdr->descrip, sizeof(this->Descrip));
144 strncpy(this->AuxFile, hdr->aux_file, sizeof(this->AuxFile));
145 if (isnifti)
146 {
147 this->QFormCode = hdr->qform_code;
148 this->SFormCode = hdr->sform_code;
149 this->QuaternB = hdr->quatern_b;
150 this->QuaternC = hdr->quatern_c;
151 this->QuaternD = hdr->quatern_d;
152 this->QOffsetX = hdr->qoffset_x;
153 this->QOffsetY = hdr->qoffset_y;
154 this->QOffsetZ = hdr->qoffset_z;
155 for (int i = 0; i < 4; i++)
156 {
157 this->SRowX[i] = hdr->srow_x[i];
158 this->SRowY[i] = hdr->srow_y[i];
159 this->SRowZ[i] = hdr->srow_z[i];
160 }
161 }
162 }
163
164 //------------------------------------------------------------------------------
GetHeader(nifti_1_header * hdr)165 void vtkNIFTIImageHeader::GetHeader(nifti_1_header* hdr)
166 {
167 hdr->sizeof_hdr = NIFTI1HeaderSize;
168 memcpy(hdr->magic, this->Magic, sizeof(hdr->magic));
169 memset(hdr->data_type, '\0', 10);
170 memset(hdr->db_name, '\0', 18);
171 hdr->extents = 0;
172 hdr->session_error = 0;
173 hdr->regular = 0;
174 hdr->dim_info = this->DimInfo;
175 hdr->intent_p1 = vtkNIFTINormalizeFloat(this->IntentP1);
176 hdr->intent_p2 = vtkNIFTINormalizeFloat(this->IntentP2);
177 hdr->intent_p3 = vtkNIFTINormalizeFloat(this->IntentP3);
178 hdr->intent_code = static_cast<short>(this->IntentCode);
179 hdr->datatype = static_cast<short>(this->DataType);
180 hdr->bitpix = static_cast<short>(this->BitPix);
181 hdr->slice_start = this->SliceStart;
182 for (int i = 0; i < 8; i++)
183 {
184 hdr->dim[i] = static_cast<short>(this->Dim[i]);
185 hdr->pixdim[i] = vtkNIFTINormalizeFloat(this->PixDim[i]);
186 }
187 hdr->vox_offset = static_cast<float>(this->VoxOffset);
188 strncpy(hdr->intent_name, this->IntentName, sizeof(hdr->intent_name) - 1);
189 hdr->intent_name[sizeof(hdr->intent_name) - 1] = '\0';
190 hdr->scl_slope = vtkNIFTINormalizeFloat(this->SclSlope);
191 hdr->scl_inter = vtkNIFTINormalizeFloat(this->SclInter);
192 hdr->cal_min = vtkNIFTINormalizeFloat(this->CalMin);
193 hdr->cal_max = vtkNIFTINormalizeFloat(this->CalMax);
194 hdr->slice_duration = vtkNIFTINormalizeFloat(this->SliceDuration);
195 hdr->toffset = vtkNIFTINormalizeFloat(this->TOffset);
196 hdr->glmax = 0;
197 hdr->glmin = 0;
198 hdr->slice_end = this->SliceEnd;
199 hdr->slice_code = this->SliceCode;
200 hdr->xyzt_units = this->XYZTUnits;
201 strncpy(hdr->descrip, this->Descrip, sizeof(hdr->descrip) - 1);
202 hdr->descrip[sizeof(hdr->descrip) - 1] = '\0';
203 strncpy(hdr->aux_file, this->AuxFile, sizeof(hdr->aux_file) - 1);
204 hdr->aux_file[sizeof(hdr->aux_file) - 1] = '\0';
205 hdr->qform_code = static_cast<short>(this->QFormCode);
206 hdr->sform_code = static_cast<short>(this->SFormCode);
207 hdr->quatern_b = vtkNIFTINormalizeFloat(this->QuaternB);
208 hdr->quatern_c = vtkNIFTINormalizeFloat(this->QuaternC);
209 hdr->quatern_d = vtkNIFTINormalizeFloat(this->QuaternD);
210 hdr->qoffset_x = vtkNIFTINormalizeFloat(this->QOffsetX);
211 hdr->qoffset_y = vtkNIFTINormalizeFloat(this->QOffsetY);
212 hdr->qoffset_z = vtkNIFTINormalizeFloat(this->QOffsetZ);
213 for (int i = 0; i < 4; i++)
214 {
215 hdr->srow_x[i] = vtkNIFTINormalizeFloat(this->SRowX[i]);
216 hdr->srow_y[i] = vtkNIFTINormalizeFloat(this->SRowY[i]);
217 hdr->srow_z[i] = vtkNIFTINormalizeFloat(this->SRowZ[i]);
218 }
219 }
220
221 //------------------------------------------------------------------------------
SetHeader(const nifti_2_header * hdr)222 void vtkNIFTIImageHeader::SetHeader(const nifti_2_header* hdr)
223 {
224 memcpy(this->Magic, hdr->magic, sizeof(hdr->magic));
225 this->VoxOffset = hdr->vox_offset;
226 this->DataType = hdr->datatype;
227 this->BitPix = hdr->bitpix;
228 for (int i = 0; i < 8; i++)
229 {
230 this->Dim[i] = hdr->dim[i];
231 this->PixDim[i] = hdr->pixdim[i];
232 }
233 this->IntentCode = hdr->intent_code;
234 strncpy(this->IntentName, hdr->intent_name, sizeof(this->IntentName));
235 this->IntentP1 = hdr->intent_p1;
236 this->IntentP2 = hdr->intent_p2;
237 this->IntentP3 = hdr->intent_p3;
238 this->SclSlope = hdr->scl_slope;
239 this->SclInter = hdr->scl_inter;
240 this->CalMin = hdr->cal_min;
241 this->CalMax = hdr->cal_max;
242 this->SliceDuration = hdr->slice_duration;
243 this->TOffset = hdr->toffset;
244 this->SliceStart = hdr->slice_start;
245 this->SliceEnd = hdr->slice_end;
246 this->SliceCode = hdr->slice_code;
247 this->XYZTUnits = hdr->xyzt_units;
248 this->DimInfo = hdr->dim_info;
249 strncpy(this->Descrip, hdr->descrip, sizeof(this->Descrip));
250 strncpy(this->AuxFile, hdr->aux_file, sizeof(this->AuxFile));
251 this->QFormCode = hdr->qform_code;
252 this->SFormCode = hdr->sform_code;
253 this->QuaternB = hdr->quatern_b;
254 this->QuaternC = hdr->quatern_c;
255 this->QuaternD = hdr->quatern_d;
256 this->QOffsetX = hdr->qoffset_x;
257 this->QOffsetY = hdr->qoffset_y;
258 this->QOffsetZ = hdr->qoffset_z;
259 for (int i = 0; i < 4; i++)
260 {
261 this->SRowX[i] = hdr->srow_x[i];
262 this->SRowY[i] = hdr->srow_y[i];
263 this->SRowZ[i] = hdr->srow_z[i];
264 }
265 }
266
267 //------------------------------------------------------------------------------
GetHeader(nifti_2_header * hdr)268 void vtkNIFTIImageHeader::GetHeader(nifti_2_header* hdr)
269 {
270 hdr->sizeof_hdr = NIFTI2HeaderSize;
271 memcpy(hdr->magic, this->Magic, sizeof(hdr->magic));
272 hdr->datatype = static_cast<short>(this->DataType);
273 hdr->bitpix = static_cast<short>(this->BitPix);
274 for (int i = 0; i < 8; i++)
275 {
276 hdr->dim[i] = static_cast<short>(this->Dim[i]);
277 hdr->pixdim[i] = vtkNIFTINormalizeDouble(this->PixDim[i]);
278 }
279 hdr->intent_p1 = vtkNIFTINormalizeDouble(this->IntentP1);
280 hdr->intent_p2 = vtkNIFTINormalizeDouble(this->IntentP2);
281 hdr->intent_p3 = vtkNIFTINormalizeDouble(this->IntentP3);
282 hdr->vox_offset = this->VoxOffset;
283 hdr->scl_slope = vtkNIFTINormalizeDouble(this->SclSlope);
284 hdr->scl_inter = vtkNIFTINormalizeDouble(this->SclInter);
285 hdr->cal_min = vtkNIFTINormalizeDouble(this->CalMin);
286 hdr->cal_max = vtkNIFTINormalizeDouble(this->CalMax);
287 hdr->slice_duration = vtkNIFTINormalizeDouble(this->SliceDuration);
288 hdr->toffset = vtkNIFTINormalizeDouble(this->TOffset);
289 hdr->slice_start = this->SliceStart;
290 hdr->slice_end = this->SliceEnd;
291 strncpy(hdr->descrip, this->Descrip, sizeof(hdr->descrip) - 1);
292 hdr->descrip[sizeof(hdr->descrip) - 1] = '\0';
293 strncpy(hdr->aux_file, this->AuxFile, sizeof(hdr->aux_file) - 1);
294 hdr->aux_file[sizeof(hdr->aux_file) - 1] = '\0';
295 hdr->qform_code = static_cast<short>(this->QFormCode);
296 hdr->sform_code = static_cast<short>(this->SFormCode);
297 hdr->quatern_b = vtkNIFTINormalizeDouble(this->QuaternB);
298 hdr->quatern_c = vtkNIFTINormalizeDouble(this->QuaternC);
299 hdr->quatern_d = vtkNIFTINormalizeDouble(this->QuaternD);
300 hdr->qoffset_x = vtkNIFTINormalizeDouble(this->QOffsetX);
301 hdr->qoffset_y = vtkNIFTINormalizeDouble(this->QOffsetY);
302 hdr->qoffset_z = vtkNIFTINormalizeDouble(this->QOffsetZ);
303 for (int i = 0; i < 4; i++)
304 {
305 hdr->srow_x[i] = vtkNIFTINormalizeDouble(this->SRowX[i]);
306 hdr->srow_y[i] = vtkNIFTINormalizeDouble(this->SRowY[i]);
307 hdr->srow_z[i] = vtkNIFTINormalizeDouble(this->SRowZ[i]);
308 }
309 hdr->slice_code = this->SliceCode;
310 hdr->xyzt_units = this->XYZTUnits;
311 hdr->intent_code = static_cast<short>(this->IntentCode);
312 strncpy(hdr->intent_name, this->IntentName, sizeof(hdr->intent_name) - 1);
313 hdr->intent_name[sizeof(hdr->intent_name) - 1] = '\0';
314 hdr->dim_info = static_cast<char>(this->DimInfo);
315 memset(hdr->unused_str, '\0', 15);
316 }
317
318 //------------------------------------------------------------------------------
DeepCopy(vtkNIFTIImageHeader * o)319 void vtkNIFTIImageHeader::DeepCopy(vtkNIFTIImageHeader* o)
320 {
321 if (o)
322 {
323 nifti_2_header hdr;
324 o->GetHeader(&hdr);
325 this->SetHeader(&hdr);
326 }
327 else
328 {
329 this->Initialize();
330 }
331 }
332
333 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)334 void vtkNIFTIImageHeader::PrintSelf(ostream& os, vtkIndent indent)
335 {
336 this->Superclass::PrintSelf(os, indent);
337
338 os.setf(std::ios::hex, std::ios::basefield);
339 os << indent << "DimInfo: 0x" << this->DimInfo << "\n";
340 os.unsetf(std::ios::hex);
341 os << indent << "Dim:";
342 for (int i = 0; i < 8; i++)
343 {
344 os << " " << this->Dim[i];
345 }
346 os << indent << "\n";
347 os << indent << "PixDim:";
348 for (int i = 0; i < 8; i++)
349 {
350 os << " " << this->PixDim[i];
351 }
352 os << indent << "\n";
353 os << indent << "VoxOffset:" << this->VoxOffset << "\n";
354 os << indent << "IntentP1: " << this->IntentP1 << "\n";
355 os << indent << "IntentP2: " << this->IntentP2 << "\n";
356 os << indent << "IntentP3: " << this->IntentP3 << "\n";
357 os << indent << "IntentCode: " << this->IntentCode << "\n";
358 os << indent << "DataType: " << this->DataType << "\n";
359 os << indent << "BitPix: " << this->BitPix << "\n";
360 os << indent << "SliceStart: " << this->SliceStart << "\n";
361 os << indent << "SclSlope: " << this->SclSlope << "\n";
362 os << indent << "SclInter: " << this->SclInter << "\n";
363 os << indent << "SliceEnd: " << this->SliceEnd << "\n";
364 os << indent << "SliceCode: " << static_cast<int>(this->SliceCode) << "\n";
365 os.setf(std::ios::hex, std::ios::basefield);
366 os << indent << "XYZTUnits: 0x" << static_cast<int>(this->XYZTUnits) << "\n";
367 os.unsetf(std::ios::hex);
368 os << indent << "CalMax: " << this->CalMax << "\n";
369 os << indent << "CalMin: " << this->CalMin << "\n";
370 os << indent << "SliceDuration: " << this->SliceDuration << "\n";
371 os << indent << "TOffset: " << this->TOffset << "\n";
372 os << indent << "Descrip: \"";
373 for (size_t j = 0; j < 80 && this->Descrip[j] != '\0'; j++)
374 {
375 os << (isprint(this->Descrip[j]) ? this->Descrip[j] : '?');
376 }
377 os << "\"\n";
378 os << indent << "AuxFile: \"";
379 for (size_t j = 0; j < 24 && this->AuxFile[j] != '\0'; j++)
380 {
381 os << (isprint(this->AuxFile[j]) ? this->AuxFile[j] : '?');
382 }
383 os << "\"\n";
384 os << indent << "QFormCode: " << this->QFormCode << "\n";
385 os << indent << "SFormCode: " << this->SFormCode << "\n";
386 os << indent << "QuaternB: " << this->QuaternB << "\n";
387 os << indent << "QuaternC: " << this->QuaternC << "\n";
388 os << indent << "QuaternD: " << this->QuaternD << "\n";
389 os << indent << "QOffsetX: " << this->QOffsetX << "\n";
390 os << indent << "QOffsetY: " << this->QOffsetY << "\n";
391 os << indent << "QOffsetZ: " << this->QOffsetZ << "\n";
392 os << indent << "SRowX:";
393 for (int i = 0; i < 4; i++)
394 {
395 os << " " << this->SRowX[i];
396 }
397 os << "\n";
398 os << indent << "SRowY:";
399 for (int i = 0; i < 4; i++)
400 {
401 os << " " << this->SRowY[i];
402 }
403 os << "\n";
404 os << indent << "SRowZ:";
405 for (int i = 0; i < 4; i++)
406 {
407 os << " " << this->SRowZ[i];
408 }
409 os << "\n";
410 os << indent << "IntentName: \"";
411 for (size_t j = 0; j < 16 && this->IntentName[j] != '\0'; j++)
412 {
413 os << (isprint(this->IntentName[j]) ? this->IntentName[j] : '?');
414 }
415 os << "\"\n";
416 os << indent << "Magic: \"";
417 for (size_t j = 0; j < 4 && this->Magic[j] != '\0'; j++)
418 {
419 os << (isprint(this->Magic[j]) ? this->Magic[j] : '?');
420 }
421 os << "\"\n";
422 }
423
424 //------------------------------------------------------------------------------
SetStringValue(char * x,const char * y,size_t n)425 void vtkNIFTIImageHeader::SetStringValue(char* x, const char* y, size_t n)
426 {
427 if (y == nullptr)
428 {
429 y = "";
430 }
431 if (strncmp(x, y, n) != 0)
432 {
433 strncpy(x, y, n);
434 x[n] = '\0';
435 this->Modified();
436 }
437 }
438
439 //------------------------------------------------------------------------------
SetIntentName(const char * val)440 void vtkNIFTIImageHeader::SetIntentName(const char* val)
441 {
442 this->SetStringValue(this->IntentName, val, 16);
443 }
444
445 //------------------------------------------------------------------------------
SetDescrip(const char * val)446 void vtkNIFTIImageHeader::SetDescrip(const char* val)
447 {
448 this->SetStringValue(this->Descrip, val, 80);
449 }
450
451 //------------------------------------------------------------------------------
SetAuxFile(const char * val)452 void vtkNIFTIImageHeader::SetAuxFile(const char* val)
453 {
454 this->SetStringValue(this->AuxFile, val, 24);
455 }
456