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