1 /*=========================================================================
2 Program: vv http://www.creatis.insa-lyon.fr/rio/vv
5 - University of LYON http://www.universite-lyon.fr/
6 - Léon Bérard cancer center http://www.centreleonberard.fr
7 - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr
9 This software is distributed WITHOUT ANY WARRANTY; without even
10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 PURPOSE. See the copyright notices for more information.
13 It is distributed under dual licence
15 - BSD See included LICENSE.txt file
16 - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17 ===========================================================================**/
19 * @file clitkXdrImageIO.cxx
20 * @author Simon Rit <simon.rit@gmail.com>
21 * @date Sun Jun 1 22:12:20 2008
28 #include "clitkXdrImageIO.h"
41 #define memicmp _memicmp
43 #define memicmp strncasecmp
47 // Based on a true story by the Nederlands Kanker Instituut (AVS_RXDR.CPP from the 20080414)
54 /************************************************************************/
55 /* DEFINES, ENUMERATED TYPES AND CONSTANTS */
56 /************************************************************************/
76 unsigned int iOrgSize;
78 unsigned int iCompressedSize;
80 unsigned int iCompressedCRC; /* Excluding this header */
84 /************************************************************************/
85 /* GLOBAL VARIABLES */
86 /************************************************************************/
87 const char* gl_ErrorMsg[] = {
89 "Command or function not supported in this way.",
91 "XDR file header NDIM error",
92 "XDR file header DIMn error",
93 "XDR file header NSPACE error",
94 "XDR file header VECLEN error",
95 "XDR file header DATA(type) error",
96 "XDR file header FIELD(coordinate type) error",
97 "XDR file could not be opened",
98 "XDR file header contains no ^L",
99 "XDR file reading error",
101 "Decompression failed",
102 "Format not handled by clitkXdrImageIO (RECTILINEAR or IRREGULAR field)"
106 static const unsigned long CRC32_table[256] = {
107 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
108 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
109 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
110 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
111 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
112 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
113 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
114 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
115 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
116 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
117 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
118 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
119 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
120 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
121 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
122 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
123 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
124 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
125 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
126 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
127 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
128 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
129 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
130 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
131 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
132 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
133 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
134 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
135 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
136 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
137 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
138 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
139 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
140 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
141 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
142 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
143 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
144 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
145 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
146 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
147 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
148 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
149 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
153 /************************************************************************/
154 /* MODULE FUNCTIONS */
155 /************************************************************************/
157 /* simple XDR file reader */
159 /* help routine, scans XDR file header for keyword entry, returns NULL
160 if not found, else returns pointer to rest of line
163 static char *scan_header(const char *file, const char *name, int offset, int removespaces)
165 int i, j, iStringLength;
166 static char temp[512];
170 if ((f = fopen(file, "rt")) == NULL) return NULL;
171 if (offset) fseek(f, offset, SEEK_SET);
174 if (fgets(temp, 500, f) == NULL ) break; /* end of file */
178 p = q = temp; /* remove spaces */
179 iStringLength = strlen(temp);
180 for (j=0; j<iStringLength; j++)
181 if (*q!=' ' && *q!=8) *p++ = *q++;
186 if (temp[0] == 12 ) break; /* ^L end of header */
187 if (temp[0] != '#') i++; /* The first 200 non comment lines must be read before data is opened. */
188 if ((p = strchr(temp+1, '=')) == NULL) continue; /* no '=' */
189 if (memicmp(temp, name, p-temp) ) continue; /* no match */
191 p++; /* match, skip = */
192 if (p[strlen(p)-1] == '\n') /* remove \n */
203 static int get_nki_compressed_size(FILE *f)
208 fread((void *)&Header, sizeof(Header), 1 , f);
210 iMode = Header.iMode;
218 return Header.iCompressedSize + sizeof(Header);
224 /* decoder for NKI private compressed pixel data
225 arguments: dest = (in) points to area where destination data is written (short)
226 src = (in) points compressed source data (byte stream)
227 size = (in) number of bytes source data (safety)
229 The return value is the number of pixels that have been processed.
231 The compressed data looks like:
232 (number of pixels)-1 times:
233 OR 1 byte = LL 7 bits signed (difference pixel[1] - pixel[0]);
234 OR 2 bytes = HHLL 15 bits signed (difference pixel[1] - pixel[0]) xored with 0x4000;
235 OR 3 bytes = 7FHHLL 16 bits absolute pixel data if 15 bits difference is exceeded
236 OR 2 bytes = 80NN run length encode NN zero differences (max 255)
237 for mode 3 and 4 added:
238 OR 2 bytes = CONN encode NN 4 bit differences (max 255)
240 Performance on typical CT or MRI is >2x compression and a very good speed
242 This code is not valid on HIGHENDIAN (high byte first) machines
245 static int global_len;
247 static int nki_private_decompress(short int *dest, signed char *src, int size)
249 int npixels, retvalue, mode, iMode, val, j;
250 NKI_MODE2* pHeader = (NKI_MODE2*)src;
251 unsigned long iCRC=0, iCRC2=0;
252 //unsigned char* pDestStart = (unsigned char*)dest;
253 signed char *save, *end;
255 retvalue = npixels = pHeader->iOrgSize;
256 iMode = pHeader->iMode; // safety: this value is checked in case statement
258 if (npixels<1) return 0; // safety: check for invalid npixels value
260 /* Up till now only Mode=1, 2, 3, and 4 are supported */
266 src += 8; // mode 1 only has 8 bytes header: iOrgSize and iMode
267 end = src + size - 3; // for overflow check if we are close to end of input buffer
269 *dest = *(short int *)src;
274 if (src > end) { // check whether the last few messages fit in input buffer
275 if (src<end+3) val = *src;
278 if (val >= -64 && val <= 63) mode = 1; // 7 bit difference
279 else if (val==0x7f) mode = 3; // 16 bit value
280 else if ((val&0xff)==0x80) mode = 2; // run length encoding
283 if (src+mode > end+3)
284 return 0; // safety: overflow input data
289 if (val >= -64 && val <= 63) { // 7 bit difference
290 dest[1] = dest[0] + val;
293 } else if (val==0x7f) { // 16 bit value
294 dest[1] = val = ((int)(((unsigned char *)src)[1])<<8) + ((unsigned char*)src)[2];
297 } else if ((val&0xff)==0x80) { // run length encoding
298 mode = ((unsigned char *)src)[1];
300 if (npixels<=0) return 0; // safety: overflow output data
307 signed short diff = ((val^0x40)<<8) + (unsigned char)(src[1]);
308 dest[1] = dest[0] + diff; // 15 bit difference
314 global_len = src-save;
319 src += sizeof(NKI_MODE2);
321 end = src + pHeader->iCompressedSize - 3;
323 if (end > src + size - 3)
324 end = src + size - 3; // may occur if pHeader is corrupted
326 *dest = val = *(short int *)src;
327 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8));
328 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
334 if (src > end) { // check whether the last few messages fit in input buffer
335 if (src<end+3) val = *src;
338 if (val >= -64 && val <= 63) mode = 1; // 7 bit difference
339 else if (val==0x7f) mode = 3; // 16 bit value
340 else if ((val&0xff)==0x80) mode = 2; // run length encoding
343 if (src+mode > end+3)
344 break; // safety: overflow input data
349 if (val >= -64 && val <= 63) { // 7 bits difference
350 dest[1] = val = dest[0] + val;
351 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8));
352 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
355 } else if (val==0x7f) { // 16 bit value
356 dest[1] = val = ((int)(((unsigned char *)src)[1])<<8) + ((unsigned char*)src)[2];
358 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8));
359 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
362 } else if ((val&0xff)==0x80) { // run length encoding
363 mode = ((unsigned char *)src)[1];
365 if (npixels<=0) break; // safety: overflow output data
367 dest[1] = val = dest[0];
368 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8));
369 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
374 signed short diff = ((val^0x40)<<8) + ((unsigned char *)src)[1];
375 dest[1] = val = dest[0] + diff; // 15 bit difference
376 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8));
377 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
383 if (iCRC2 != pHeader->iOrgCRC) { // if error in output CRC:
384 src = save; // check input CRC
386 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)src[0]] ^ ((iCRC >> 8));
390 if (iCRC != pHeader->iCompressedCRC) {
391 AVSerror("XDR decompression: the file is corrupted");
394 AVSerror("XDR decompression: internal error");
399 global_len = sizeof(NKI_MODE2) + pHeader->iCompressedSize;
406 src += 8; // mode 3 only has 8 bytes header: iOrgSize and iMode
407 end = src + size - 3; // for overflow check if we are close to end of input buffer
409 *dest = *(short int *)src;
414 if (src > end) { // check whether the last few messages fit in input buffer
415 if (src<end+3) val = *src;
418 if (val >= -63 && val <= 63) mode = 1; // 7 bit difference
419 else if (val==0x7f) mode = 3; // 16 bit value
420 else if ((val&0xff)==0x80) mode = 2; // run length encoding
421 else if ((val&0xff)==0xC0) mode = 2; // 4 bit encoding
424 if (src+mode > end+3)
425 return 0; // safety: overflow input data
430 if (val >= -63 && val <= 63) { // 7 bit difference
431 dest[1] = dest[0] + val;
434 } else if (val==0x7f) { // 16 bit value
435 dest[1] = val = ((int)(((unsigned char *)src)[1])<<8) + ((unsigned char*)src)[2];
438 } else if ((val&0xff)==0x80) { // run length encoding
439 mode = ((unsigned char *)src)[1];
441 if (npixels<=0) return 0; // safety: overflow output data
447 } else if ((val&0xff)==0xC0) { // 4 bit run
448 mode = ((unsigned char *)src)[1];
452 if (npixels<=0) return 0; // safety: overflow output data
455 dest[1] = dest[0] + (val>>4);
457 if (val&8) val |= 0xfffffff0;
459 dest[1] = dest[0] + val;
463 signed short diff = ((val^0x40)<<8) + (unsigned char)(src[1]);
464 dest[1] = dest[0] + diff; // 15 bit difference
470 global_len = src-save;
475 src += sizeof(NKI_MODE2);
477 end = src + pHeader->iCompressedSize - 3;
479 if (end > src + size - 3)
480 end = src + size - 3; // may occur if pHeader is corrupted
482 *dest = val = *(short int *)src;
483 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8));
484 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
489 if (src > end) { // check whether the last few messages fit in input buffer
490 if (src<end+3) val = *src;
493 if (val >= -63 && val <= 63) mode = 1; // 7 bit difference
494 else if (val==0x7f) mode = 3; // 16 bit value
495 else if ((val&0xff)==0x80) mode = 2; // run length encoding
496 else if ((val&0xff)==0xC0) mode = 2; // 4 bit encoding
499 if (src+mode > end+3)
500 return 0; // safety: overflow input data
505 if (val >= -63 && val <= 63) { // 7 bit difference
506 dest[1] = val = dest[0] + val;
507 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8));
508 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
511 } else if (val==0x7f) { // 16 bit value
512 dest[1] = val = ((int)(((unsigned char *)src)[1])<<8) + ((unsigned char*)src)[2];
513 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8));
514 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
517 } else if ((val&0xff)==0x80) { // run length encoding
518 mode = ((unsigned char *)src)[1];
520 if (npixels<=0) return 0; // safety: overflow output data
522 dest[1] = val = dest[0];
523 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8));
524 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
528 } else if ((val&0xff)==0xC0) { // 4 bit run
529 mode = ((unsigned char *)src)[1];
533 if (npixels<=0) return 0; // safety: overflow output data
536 dest[1] = j = dest[0] + (val>>4);
537 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)j] ^ ((iCRC2 >> 8));
538 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(j>>8)] ^ ((iCRC2 >> 8));
540 if (val&8) val |= 0xfffffff0;
542 dest[1] = j = dest[0] + val;
543 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)j] ^ ((iCRC2 >> 8));
544 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(j>>8)] ^ ((iCRC2 >> 8));
548 signed short diff = ((val^0x40)<<8) + (unsigned char)(src[1]);
549 dest[1] = val = dest[0] + diff; // 15 bit difference
550 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8));
551 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
557 if (iCRC2 != pHeader->iOrgCRC) // if error in output CRC:
560 global_len = sizeof(NKI_MODE2) + pHeader->iCompressedSize;
566 AVSerror("XDR decompression: unsupported mode");
574 //====================================================================
575 // Read image information (copied from XDRreader)
576 int clitk::XdrImageIO::ReadImageInformationWithError()
579 itk::Vector<int,MAXDIM> dim;
582 unsigned int coords=0,i,j,ndim,nspace;
587 long swap_test = 0x1000000; /* first byte is 1 when low-endian */
589 char *file = const_cast<char *>(m_FileName.c_str());
590 AVSType field=UNIFORM;
593 fstream = fopen(file, "rt");
594 if (fstream == NULL) return ER_XDR_OPEN;
596 fgets(temp, 500, fstream);
599 if (memcmp(temp, "# AVS field file (produced by avs_nfwrite.c)", 44)==0) forcenoswap=1;
601 c = scan_header(file, "ndim", offset, 1);
602 if (!c) return ER_XDR_NDIM;
605 if (ndim<1 || ndim>MAXDIM) return ER_XDR_NDIM;
606 SetNumberOfDimensions(ndim);
610 for (i=0; i<ndim; i++) {
611 sprintf(temp, "dim%d", i+1);
612 c = scan_header(file, temp, offset, 1);
613 if (!c) return ER_XDR_DIM;
615 if (dim[i]<1) return ER_XDR_DIM;
620 for (i=0; i<ndim; i++) {
621 SetDimensions(i,dim[i]);
626 c = scan_header(file, "nspace", offset, 1);
627 if (c) nspace = atoi(c);
628 if (nspace<1 || ndim > MAXDIM) return ER_XDR_NSPACE;
629 if (nspace != ndim) return ER_NOT_HANDLED;
631 c = scan_header(file, "veclen", offset, 1);
632 if (c) veclen = atoi(c);
633 if (veclen<0 /*|| veclen>1000*/) return ER_XDR_VECLEN;
634 SetNumberOfComponents(veclen);
635 if (veclen==1) SetPixelType(itk::ImageIOBase::SCALAR);
636 else SetPixelType(itk::ImageIOBase::VECTOR);
638 c = scan_header(file, "data", offset, 1);
640 if (memicmp(c, "byte", 4) == 0 || memicmp(c, "xdr_byte", 8) == 0) SetComponentType(itk::ImageIOBase::CHAR);
641 else if (memicmp(c, "short", 5) == 0 || memicmp(c, "xdr_short", 9) == 0) SetComponentType(itk::ImageIOBase::SHORT);
642 else if (memicmp(c, "int" , 3) == 0 || memicmp(c, "xdr_int" , 7) == 0) SetComponentType(itk::ImageIOBase::INT);
643 else if (memicmp(c, "real", 4) == 0 || memicmp(c, "xdr_real", 8) == 0) SetComponentType(itk::ImageIOBase::FLOAT);
644 else if (memicmp(c, "float", 5) == 0 || memicmp(c, "xdr_float", 9) == 0) SetComponentType(itk::ImageIOBase::FLOAT);
645 else if (memicmp(c, "double",6) == 0 || memicmp(c, "xdr_double",10)== 0) SetComponentType(itk::ImageIOBase::DOUBLE);
646 else return ER_XDR_DATA;
648 if (memicmp(c, "xdr_", 4) == 0) forcenoswap=0;
652 c = scan_header(file, "field", offset, 1);
654 if (memicmp(c, "unifo", 5) == 0) field=UNIFORM, coords=nspace *2;
655 else if (memicmp(c, "recti", 5) == 0) field=RECTILINEAR;
656 else if (memicmp(c, "irreg", 5) == 0) field=IRREGULAR, coords=total*nspace;
657 else return ER_XDR_FIELD;
661 if (coords) { /* expect AVS coordinates ? */
662 coords *= sizeof(float);
663 fstream = fopen(m_FileName.c_str(), "rb");
664 if (fstream == NULL) return ER_XDR_OPEN;
666 float *points = (float *)malloc(coords);
667 if (points == NULL) return ER_OUTOFMEMORY;
669 //Seek to coordinates position in file
670 if (fseek(fstream,-static_cast<int>(coords),SEEK_END)) return ER_XDR_READ;
671 if (fread( /*(*output)->*/points, 1, coords, fstream ) == coords) {
672 /* swap data if read-ok and required (xdr is low-endian) */
673 if (!(*(char *)(&swap_test)) && !forcenoswap) {
674 c = (char *)/*(*output)->*/points;
675 for (i=0; i<coords; i+=4) {
689 for (i=0; i<GetNumberOfDimensions(); i++) {
690 SetSpacing(i,10.*(points[i*2+1]-points[i*2])/(GetDimensions(i)-1));
691 SetOrigin(i,10.*points[i*2]);
695 //Rectilinear is reinterpreted as uniform because ITK does not know rectilinear
697 for (i=0; i<GetNumberOfDimensions(); i++) {
698 //Compute mean spacing
699 SetSpacing(i,10*(p[GetDimensions(i)-1]-p[0])/(GetDimensions(i)-1));
700 SetOrigin(i,10*p[0]);
702 //Test if rectilinear image is actually uniform (tolerance 0.1 mm)
703 if(i<3) { // Only for first 3 dimensions because spacing is barely used in other dims
704 for (j=0; j<GetDimensions(i)-1; j++) {
705 if (fabs((p[j+1]-p[j])*10-GetSpacing(i))>0.1) {
708 return ER_NOT_HANDLED;
712 p += (int)GetDimensions(i);
718 return ER_NOT_HANDLED;
726 //====================================================================
727 // Read image information (copied from XDRreader)
728 void clitk::XdrImageIO::ReadImageInformation()
730 int result = ReadImageInformationWithError();
731 if (result) ITKError("clitk::XdrImageIO::ReadImageInformation",result);
735 //====================================================================
736 // Read Image Content (copied from Xdr reader)
737 int clitk::XdrImageIO::ReadWithError(void * buffer)
740 int /*ndim,*/ nspace/*, veclen=1, data=AVS_TYPE_BYTE, field=UNIFORM*/;
741 int iNkiCompression = 0;
742 int j, coords=0, datasize=0, HeaderSize;
743 unsigned int i,iNumRead,total=1;
748 //AVSfield FieldTemplate;
749 long swap_test = 0x1000000; /* first byte is 1 when low-endian */
751 char *file = const_cast<char *>(m_FileName.c_str());
753 // AVSType field=UNIFORM;
755 for (i=0; i<GetNumberOfDimensions(); i++) coords += GetDimensions(i);
757 total = GetImageSizeInPixels();
758 nspace = GetNumberOfDimensions();
760 c = scan_header(file, "field", offset, 1);
762 if (memicmp(c, "unifo", 5) == 0) /*field=UNIFORM,*/ coords=nspace*2;
763 else if (memicmp(c, "recti", 5) == 0) /*field=RECTILINEAR*/;
764 else if (memicmp(c, "irreg", 5) == 0) /*field=IRREGULAR,*/ coords=total*nspace;
765 else return ER_XDR_FIELD;
769 c = scan_header(file, "nki_compression", offset, 1);
770 if (c) iNkiCompression = atoi(c);
772 c = scan_header(file, "coord1[0]", offset, 1);
773 if (c) HeaderSize = 32768;
774 else HeaderSize = 2048;
776 fstream = fopen(file, "rb");
780 if (offset) fseek(fstream, offset, SEEK_SET);
783 if (fgets(temp, 500, fstream) == NULL )
784 return ER_XDR_NOCTRLL; /* end of file */
786 if (temp[0] == 10) continue;
789 fseek(fstream, -2, SEEK_CUR);
791 } /* ^L end of header */
793 if (temp[0] != '#') break;
796 buff = (char*)malloc(HeaderSize);
798 return ER_OUTOFMEMORY;
800 memset(buff, 0, HeaderSize);
801 iNumRead = fread(buff, 1, HeaderSize, fstream);
808 for (i=0; i<iNumRead; i++) {
809 if (buff[i] == 12) break;
814 if (i==iNumRead) return ER_XDR_NOCTRLL;
816 total = GetImageSizeInBytes();
818 //We add casts because the resulting quantity can be negative.
819 //There is no risk of looping because i and iNumRead are about the size of the header
820 fseek(fstream, static_cast<int>(i)+2-static_cast<int>(iNumRead), SEEK_CUR);
822 if (total && iNkiCompression) {
825 signed char* pCompressed;
827 /* Read or guess the size of the compressed data */
828 iCurPos = ftell(fstream);
829 iSize = get_nki_compressed_size(fstream);
832 fseek(fstream, 0, SEEK_END);
833 iSize = ftell(fstream);
834 iSize = iSize - iCurPos - coords;
836 // Get compressed size from header if possible; else use uncompressed size as safe estimate
837 if (iSize>total && offset) iSize=total+8;
840 fseek(fstream, iCurPos, SEEK_SET);
842 /* Allocate space for the compressed pixels */
843 pCompressed = (signed char*)malloc(iSize);
846 return ER_OUTOFMEMORY;
849 /* Read the compressed pixels */
850 if (fread( (void *)pCompressed, 1, iSize, fstream ) != iSize) {
855 if (!nki_private_decompress((short*)buffer, pCompressed, iSize)) {
857 return ER_DECOMPRESSION;
861 fseek(fstream, iCurPos + global_len, SEEK_SET);
869 if (fread( (void *)buffer, 1, total, fstream ) != total) {
875 /* swap data if required (xdr is low-endian) */
877 datasize = GetComponentSize();
878 if (!(*(char *)(&swap_test)) && !forcenoswap) {
881 for (i=0; i<total; i+=2) {
886 } else if (datasize==4) {
888 for (i=0; i<total; i+=4) {
896 } else if (datasize==8) {
898 for (i=0; i<total; i+=8) {
920 //====================================================================
921 // Read image information (copied from Xdr reader)
922 void clitk::XdrImageIO::Read(void * buffer)
924 int result = ReadWithError(buffer);
925 if (result) ITKError("clitk::XdrImageIO::Read",result);
928 //====================================================================
929 // Read Image Information
930 bool clitk::XdrImageIO::CanReadFile(const char* FileNameToRead)
935 fstream = fopen(FileNameToRead, "rt");
938 // AVSerror("Couldn't open file " << FileNameToRead);
941 fgets(temp, 500, fstream);
944 if (memcmp(temp, "# AVS", 5)==0)
950 void clitk::XdrImageIO::ITKError(std::string funcName, int msgID)
952 itkExceptionMacro(<< "Error in " << funcName << ". Message: " << gl_ErrorMsg[msgID]);