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://oncora1.lyon.fnclcc.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"
29 #include "clitkCommon.h"
35 //#define _read readfix
37 #define AVSINT ptrdiff_t
44 #define setmode(a,b) 0
48 # if defined(__GNUC__) || defined(unix)
49 typedef long long Q_INT64;
50 typedef unsigned long long Q_UINT64;
51 # define Q_INT64_CONST(x) (x##ll)
52 # define Q_UINT64_CONST(x) (x##llu) /* gcc also allows ull */
53 /* When using MINGW with MS(V)CRT DLL, use MS format modifier. */
55 # define Q_INT64_FORMAT "I64"
57 # define Q_INT64_FORMAT "L"
59 # elif defined(__BORLANDC__) || defined(__WATCOMC__) || defined(_MSC_VER)
60 typedef __int64 Q_INT64;
61 typedef unsigned __int64 Q_UINT64;
62 # define Q_INT64_CONST(x) (x##i64)
63 # define Q_UINT64_CONST(x) (x##ui64) /* i64u is not allowed! */
65 # define Q_INT64_FORMAT "I64"
67 # define Q_INT64_FORMAT "L"
70 # error No 64 bit integers known for this compiler, edit portdefs.h.
74 bool clitk::XdrImageIO::CanWriteFile(const char* FileNameToWrite)
75 { std::string filename(FileNameToWrite);
76 std::string filenameext = GetExtension(filename);
77 if (filenameext != std::string("xdr")) return false;
81 void clitk::XdrImageIO::Write(const void* buffer)
82 { char *s = const_cast<char*>("");
83 WriteImage( m_FileName.c_str(), s, s, 0, -1, 0, 2, 0, 0, 0, 0, buffer);
86 // Based on a true story by the Nederlands Kanker Instituut (AVS_WXDR.CPP from the 20091216)
88 /************************************************************************/
90 /************************************************************************/
106 // don't use min() and max() macros indirectly defined by windows.h,
107 // but use portable std::min() and std:max() instead
114 /************************************************************************/
115 /* DEFINES, ENUMERATED TYPES AND CONSTANTS */
116 /************************************************************************/
120 // Fields with data size>8GB (having UINT_MAX short pixels) cannot be compressed using
121 // NKI_MODE2 struct because iOrgSize has type "unsigned int". In that case use NKI_MODE2_64BITS.
122 // The type of structure is indicated as follows:
124 // iOrgSize==0: NKI_MODE2_64BITS
125 // otherwise : NKI_MODE2
127 // Compression modes 1 and 3 (without CRCs) only use the first 2 members (iOrgSize and iMode).
131 unsigned int iOrgSize; /* in pixels (i.e. shorts) */
132 unsigned int iMode; /* 1, 2, 3 or 4 */
133 unsigned int iCompressedSize; /* in bytes, excluding header */
134 unsigned int iOrgCRC; /* CRC of the data (no coords etc) */
135 unsigned int iCompressedCRC; /* CRC of the compressed data, excluding this header */
140 unsigned int iOrgSize; /* in pixels (i.e. shorts) */
141 unsigned int iMode; /* 1, 2, 3 or 4 */
142 unsigned int iCompressedSize; /* in bytes, excluding header */
143 unsigned int iOrgCRC; /* CRC of the data (no coords etc) */
144 unsigned int iCompressedCRC; /* CRC of the compressed data, excluding this header */
145 unsigned int iPad; /* unused */
146 Q_UINT64 i64OrgSize; /* used for more than UINT_MAX pixels, indicated by iOrgSize==0 (0-vector not compressed) */
147 Q_UINT64 i64CompressedSize; /* value in BYTES, used for more than UINT_MAX PIXELS, indicated by iCompressedSize==0 */
154 // Changed next to static function in stead of macro so it can
155 // have a return value to check in the calling function.
156 // It could be made inline as well, but there is no real time
157 // punishment from the extra layer of function calls.
159 // note: some compilers do not like comments ending in a backslash.
160 // so use macro functions to exclude.
163 /************************************************************************/
164 /* GLOBAL VARIABLES */
165 /************************************************************************/
167 static const unsigned long CRC32_table[256] = {
168 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
169 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
170 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
171 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
172 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
173 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
174 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
175 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
176 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
177 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
178 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
179 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
180 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
181 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
182 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
183 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
184 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
185 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
186 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
187 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
188 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
189 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
190 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
191 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
192 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
193 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
194 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
195 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
196 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
197 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
198 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
199 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
200 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
201 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
202 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
203 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
204 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
205 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
206 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
207 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
208 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
209 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
210 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
213 /************************************************************************/
214 /* MODULE FUNCTIONS */
215 /************************************************************************/
220 int writefix(int file, const void *buf, unsigned int count)
223 for (unsigned i=0; i<count; i+=16384)
225 if (j>16384) j=16384;
227 k=write(file, (char *)buf+i, j);
240 Version of write() that takes special action in case of
241 standard output. Based on commented out macro above.
242 This function overloads the <cstdio> (or stdio.h for old style C++)
246 // Like the original macro, we do /not/ want writefix from mbfield.c.
250 static int wxdr_write(int handle, const void * buf, unsigned len)
252 // if (handle == 1) // stdout
253 if (handle == fileno(stdout))
256 // Behave as C standard library write(): return number of bytes
257 // written or -1 and errno set on error.
259 DWORD dwBytesWritten;
260 if (!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, len,
261 &dwBytesWritten, NULL))
263 // There is no simple 1-to-1 mapping between GetLastError()
264 // values that WriteFile() can return (quite a lot) and the two
265 // errno values that write() can return. So return EACCES in
267 switch (GetLastError())
268 { case ERROR_INVALID_HANDLE:
269 errno = EBADF ; break;
271 errno = EACCES; break;
276 return (int)dwBytesWritten; // May still be < len!
277 // And... write() may write a maximum of UINT_MAX-1 bytes, whereas
278 // WriteFile() may write UINT_MAX bytes at once. But since
279 // int(UINT_MAX) == -1 this will pose an actual problem in the
282 //const int oldmode = setmode(handle, O_BINARY);//commented out by joel
283 const int iBytesWritten = write(handle, buf, len);
284 const int saveerrno = errno; // setmode() may change errno.
285 //if (oldmode != -1) setmode(handle, oldmode); //commented out by joel
287 return iBytesWritten;
291 return write(handle, buf, len);
296 Behaves like win32 WriteFile() and returns a Boolean to indicate
297 success or failure, where failure almost invariably means disc full.
301 In case of failure, this function issues an AVS error message
302 and closes the file (if handle != 1). It is up to the calling
303 function to return the AVS_ERROR state and before that do things
304 like close other files, free memory etc. This way, there is less
305 chance of erroneously duplicated code, like in:
306 written = write(f, temp, strlen(temp));
307 if (written == -1 || written != strlen(temp))
309 if (f != fileno(stdout)) close(f);
312 written = write(f, buf, buflength)
313 if (written == -1 || written != strlen(temp)) {
314 // oops, wrong length copy'n'pasted
316 If more elaborate error handling is needed then the calling
317 functuon should use the (overloaded) write() and act on its return
318 value (and the value of errno) accordingly.
320 It does /not/ close stdout.
324 Note that checked_write() takes a size_t for len, whereas write() takes
325 an unsigned int of 4 bytes. On a 64 bits OS a size_t will be an 8 byte integer,
326 enabling more than UINT_MAX bytes to write at once.
328 static bool checked_write(int handle, const void * buf, size_t len, char **buffer)
329 { if (buffer && !handle)
330 { memcpy(*buffer, buf, len);
334 if (buffer && handle)
339 { for(int i=0; i<2; i++)
344 //If write fails, test if not related to big buffer problem
345 //Bug report http://support.microsoft.com/kb/899149 entitled
346 //"You cannot call the fwrite function to write to a buffer
347 // that is larger than 64 MB in Visual C++ 2005,
348 // in Visual C++ .NET 2003, or in Visual C++ .NET 2002"
349 // NB: same thing for write function in binary mode
352 // call wxdr_write (for handle!=fileno(stdout) a wrapper for write) several times
353 // to interpret the signed 32-bit return value correctly
355 { chunksize = (int)std::min(remaining, (size_t)INT_MAX);
356 byteswritten = wxdr_write(handle, buf, chunksize);
357 if (byteswritten == chunksize)
358 remaining -= chunksize;
360 break; // try writefix in the next round
367 // call writefix (in mbfield.c) several times to interpret the signed 32-bit
368 // return value correctly. writefix uses chunks of 16384 bytes
370 { chunksize = (int)std::min(remaining, (size_t)INT_MAX);
371 byteswritten = writefix(handle, buf, chunksize);
372 if (byteswritten == chunksize)
373 remaining -= chunksize;
375 break; // even writefix failed: return error
381 // Note: file is open in binary mode, no need to compensate
382 // for a value of byteswritten > len due to \n -> \r\n conversions.
383 // (write() on a text stream is implementation dependent.)
384 if (handle != fileno(stdout)) close(handle);
385 AVSerror("Avs_wxdr: write failed, disk full?");
390 /* coder for NKI private compressed pixel data
391 arguments: dest = (in) points to area where compressed destination data is written (byte)
392 src = (in) points to uncompressed source data (short)
393 npixels = (in) number of pixels to compress
395 The return value is the number of bytes in the compressed data (maximal 3*npixels+10, typical 0.52*npixels)
398 - The first 4 bytes contain the number of short-int pixels
399 - The following 4 bytes contain iMode=1
400 - The rest is the compressed image
403 - The first 4 bytes contain the number of short-int pixels
404 - The following 4 bytes contain iMode=2
405 - The following 4 bytes contain the size of the compressed image (in bytes)
406 - The following 4 bytes contain the CRC of the original image
407 - The following 4 bytes contain the CRC of the compressed image
408 - The rest is the compressed image
409 - The compressed size will be even (padded by a zero if necessary).
412 - The first 4 bytes contain the number of short-int pixels
413 - The following 4 bytes contain iMode=3
414 - The rest is the compressed image, including 4 bit differences
417 - The first 4 bytes contain the number of short-int pixels
418 - The following 4 bytes contain iMode=4
419 - The following 4 bytes contain the size of the compressed image (in bytes)
420 - The following 4 bytes contain the CRC of the original image
421 - The following 4 bytes contain 0
422 - The rest is the compressed image, including 4 bit differences
423 - The compressed size will be even (padded by a zero if necessary).
425 iMode 1 and iMode 2 are identical, except for the CRC data that is included for iMode 2
426 iMode 3 and iMode 4 are identical, except for the CRC data that is included for iMode 4
429 // optimized settings for the 4 bit run compressor (mode 3 and 4)
431 #define MINZEROS 5 // shortest RLE (2 byte overhead, but breaks 4bit run)
432 #define MIN4BIT 6 // shortest 4 bit run (6 bytes compressed to 5 bytes)
434 // This internal routine converts an 8 bit difference string into a 4 bit one
435 static signed char *recompress4bit(int n, signed char *dest)
436 { signed char *p, *q;
442 val = (((int)p[0])<<4) | (p[1]&15);
444 *dest++ = -0x40; // 192 (0xc0) does not fit between -128..127: maps to -64 (0x40) in 2's complement
445 *dest++ = (signed char)n;
449 { *dest++ = (signed char)((((int)p[0])<<4) | (p[1]&15));
453 q[0] = (signed char)val;
459 static size_t nki_private_compress(signed char *dest, short int *src, size_t npixels, int iMode)
460 { unsigned long iCRC;
462 unsigned int iHeaderSize=8; // value for iMode==1 and iMode==3
465 NKI_MODE2* pHeader = (NKI_MODE2*)dest;
466 NKI_MODE2_64BITS* pHeader_64bits = (NKI_MODE2_64BITS*)dest;
469 iBufferSize = (npixels / 2) * 3; // Buffer is sizeof(NKI_MODE2_64BITS) + 10 bytes larger
471 /* Up till now only Mode=1 .. 4 are supported */
472 if ((iMode < 1) || (iMode > 4))
475 /* Create the header */
476 pHeader->iMode = iMode;
478 if (sizeof(int*)>sizeof(int) && npixels>UINT_MAX) // On a 64 bits OS we want to store files>4GB
479 { pHeader_64bits->iOrgSize = 0; // This indicates>4GB file (0-vector is not compressed)
480 pHeader_64bits->i64OrgSize = npixels;
481 iHeaderSize = sizeof(NKI_MODE2_64BITS);
482 dest += sizeof(NKI_MODE2_64BITS);
485 { pHeader->iOrgSize = (unsigned int)(npixels & UINT_MAX); // store 32 bit number as first member
487 if (iMode==2 || iMode==4)
488 iHeaderSize = sizeof(NKI_MODE2);
492 /* Create the compressed image */
495 { *(short int *)dest = *src;
501 { val = src[1] - src[0];
504 if (val == 0) /* run length-encode zero differences */
506 { if (i>=npixels || src[i-1]!=src[-1] || i==256)
510 { *dest++ = -128; // hexadecimal 0x80
511 *dest++ = (signed char)(i-1);
519 else if (val >= -64 && val <= 63) /* small difference coded as one byte */
520 { *dest = (signed char)val;
523 else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
524 { dest[0] = (signed char)((val>>8) ^ 0x40);
525 dest[1] = (signed char)val;
528 else /* if very large differences code abs val as three bytes */
530 *dest++ = (signed char)(src[0]>>8);
531 *dest++ = (signed char)(src[0]);
533 /* Are we beyond the allocated memory? */
534 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
544 *(short int *)dest = val = *src;
545 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char) val ] ^ ((iCRC2 >> 8));
546 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
547 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) val ] ^ ((iCRC >> 8));
548 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(val>>8)] ^ ((iCRC >> 8));
553 { val = src[1] - src[0];
555 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
556 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
558 if (val == 0) /* run length-encode zero differences */
560 { if (i>=npixels || src[i-1]!=src[-1] || i==256)
563 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0 ] ^ ((iCRC2 >> 8));
566 { *dest++ = -128; // hexadecimal 0x80
567 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0x80 ] ^ ((iCRC2 >> 8));
568 *dest++ = (signed char)(i-1);
569 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (i-1)] ^ ((iCRC2 >> 8));
572 for (j=0; j<i-2; j++)
574 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
575 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
582 else if (val >= -64 && val <= 63) /* small difference coded as one byte */
583 { *dest = (signed char)val;
584 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val ] ^ ((iCRC2 >> 8));
587 else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
588 { dest[0] = (signed char)((val>>8) ^ 0x40);
589 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)dest[0] ] ^ ((iCRC2 >> 8));
590 dest[1] = (signed char)val;
591 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val ] ^ ((iCRC2 >> 8));
594 else /* if very large differences code abs val as three bytes */
596 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0x7f ] ^ ((iCRC2 >> 8));
598 dest[1] = (signed char)(val>>8);
599 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
600 dest[2] = (signed char)val;
601 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val ] ^ ((iCRC2 >> 8));
604 /* Are we beyond the allocated memory? */
605 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
610 if ((dest - (signed char*)pHeader - iHeaderSize)<UINT_MAX) // store 32 bit number as third member
611 pHeader->iCompressedSize =
612 (unsigned int)(dest - (signed char*)pHeader - iHeaderSize);
613 else // store 64 bit number in extended structure
614 pHeader_64bits->i64CompressedSize = dest - (signed char*)pHeader -iHeaderSize;
616 /* Pad it to get an even length */
617 if (pHeader->iCompressedSize & 1)
619 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0] ^ ((iCRC2 >> 8));
620 pHeader->iCompressedSize++;
623 pHeader->iOrgCRC = iCRC;
624 pHeader->iCompressedCRC = iCRC2;
627 /* Create the compressed image - compressor with added 4 bit run */
631 *(short int *)dest = *src;
636 { val = src[1] - src[0];
639 if (val == 0) /* run length-encode zero differences */
641 { if (i>=npixels || src[i-1]!=src[-1] || i==256)
642 { if (i<=MINZEROS) /* too short run -> write zeros */
643 { for (j=0; j<i-1; j++)
647 if(n4bit>=254) /* maximum length 4 bit run */
648 { dest = recompress4bit(n4bit, dest);
654 { if (n4bit>=MIN4BIT) /* end (and write) 4 bit run */
655 dest = recompress4bit(n4bit, dest);
658 *dest++ = -128; // hexadecimal 0x80
659 *dest++ = (signed char)(i-1);
668 else if (val >= -63 && val <= 63) /* small difference coded as one byte */
669 { if (val >= -8 && val <= 7)
670 { *dest++ = (signed char)val;
673 if(n4bit>=254) /* maximum length 4 bit run */
674 { dest = recompress4bit(n4bit, dest);
678 else if(n4bit>=MIN4BIT) /* end and write 4 bit run */
680 dest = recompress4bit(n4bit, dest);
682 *dest++ = (signed char)j;
685 { *dest++ = (signed char)val; /* end 4 bit run */
689 else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
692 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
693 dest = recompress4bit(n4bit, dest);
696 dest[0] = (signed char)((j>>8) ^ 0x40);
697 dest[1] = (signed char)j;
700 else /* if very large differences code abs val as three bytes */
703 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
704 dest = recompress4bit(n4bit, dest);
708 *dest++ = (signed char)(j>>8);
709 *dest++ = (signed char)j;
711 /* Are we beyond the allocated memory? */
712 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
718 /* Create the compressed image - compressor with added 4 bit run and CRC */
724 *(short int *)dest = val = *src;
725 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) val ] ^ ((iCRC >> 8));
726 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(val>>8)] ^ ((iCRC >> 8));
731 { val = src[1] - src[0];
733 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
734 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
736 if (val == 0) /* run length-encode zero differences */
738 { if (i>=npixels || src[i-1]!=src[-1] || i==256)
739 { if (i<=MINZEROS) /* too short run -> write zeros */
740 { for (j=0; j<i-1; j++)
744 if(n4bit>=254) /* maximum length 4 bit run */
745 { dest = recompress4bit(n4bit, dest);
751 { if (n4bit>=MIN4BIT) /* end (and write) 4 bit run */
752 dest = recompress4bit(n4bit, dest);
755 *dest++ = -128; // hexadecimal 0x80
756 *dest++ = (signed char)(i-1);
760 for (j=0; j<i-2; j++)
762 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
763 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
769 else if (val >= -63 && val <= 63) /* small difference coded as one byte */
770 { if (val >= -8 && val <= 7)
771 { *dest++ = (signed char)val;
774 if(n4bit>=254) /* maximum length 4 bit run */
775 { dest = recompress4bit(n4bit, dest);
779 else if(n4bit>=MIN4BIT) /* end and write 4 bit run */
781 dest = recompress4bit(n4bit, dest);
783 *dest++ = (signed char)j;
786 { *dest++ = (signed char)val; /* end 4 bit run */
790 else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
793 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
794 dest = recompress4bit(n4bit, dest);
797 dest[0] = (signed char)((j>>8) ^ 0x40);
798 dest[1] = (signed char)j;
801 else /* if very large differences code abs val as three bytes */
804 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
805 dest = recompress4bit(n4bit, dest);
809 *dest++ = (signed char)(j>>8);
810 *dest++ = (signed char)j;
812 /* Are we beyond the allocated memory? */
813 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
818 if ((dest - (signed char*)pHeader - iHeaderSize)<UINT_MAX) // store 32 bit number as third member
819 pHeader->iCompressedSize =
820 (unsigned int)(dest - (signed char*)pHeader - iHeaderSize);
821 else // store 64 bit number in extended structure
822 { pHeader_64bits->iCompressedSize = 0;
823 pHeader_64bits->i64CompressedSize = dest - (signed char*)pHeader -iHeaderSize;
826 /* Pad it to get an even length */
827 if (pHeader->iCompressedSize & 1)
829 pHeader->iCompressedSize++;
832 pHeader->iOrgCRC = iCRC;
833 pHeader->iCompressedCRC = 0;
836 return dest - (signed char*)pHeader;
840 void clitk::XdrImageIO::WriteImage(const char* file, char* headerinfo, char* headerfile, int raw,
841 int offset, char bLittleEndian, int iNkiCompression,
842 int wcoords, int append, int getsize, char *tobuffer, const void* data)
851 long swap_test = 0x1000000;
852 signed char* pCompressed = NULL;
854 char **buffer = NULL;
860 swap_test = 0x00000001;
863 { swap_test = 0xffffffff; // never swap to save time
864 buffer = (char **) &len;
869 { buf2 = (char *)tobuffer;
874 for (i=0; i<GetNumberOfDimensions(); i++)
875 { total *= GetDimensions(i);
876 coords += GetDimensions(i);
879 /* Try allocate the compressed fielddata - compression disabled if alloc fails */
880 if ((iNkiCompression > 0) &&
881 (GetComponentType() == itk::ImageIOBase::SHORT) &&
882 (GetPixelType() == itk::ImageIOBase::SCALAR))
883 { pCompressed = (signed char *)malloc((total/2) * 3 + sizeof(NKI_MODE2_64BITS) + 10);
884 if (pCompressed==NULL)
885 { iNkiCompression = 0;
886 AVSwarning("Avs_wxdr: not enough memory to compress data, saving uncompressed");
890 if (!(tobuffer || getsize))
892 { f = open(file, O_RDWR, 0);
895 AVSerror("Avs_wxdr: Opening " << file << "failed.\n" << strerror(errno));
899 lseek(f, offset, SEEK_SET);
902 { if (strlen(file)==0)
906 f = open(file, O_RDWR | O_APPEND, 0);
908 f = creat(file, S_IWRITE | S_IREAD);
912 { AVSerror("Avs_wxdr: Creating " << file << " failed.\n" << strerror(errno));
920 { sprintf(temp, "# AVS wants to have the first line starting with its name\n");
923 if (!checked_write(f, temp, slen, buffer))
929 slen = strlen(headerinfo);
930 if (slen && !checked_write(f, headerinfo, slen, buffer))
936 if (!checked_write(f, "\n", 1, buffer))
942 if (strlen(headerfile))
943 { fp = fopen(headerfile, "rt");
946 { if (fgets(temp, 255, fp) == NULL) break;
948 if (!checked_write(f, temp, slen, buffer))
956 if (!checked_write(f, "\n", 1, buffer))
964 sprintf(temp, "ndim=%d\n", GetNumberOfDimensions());
966 if (!checked_write(f, temp, slen, buffer))
973 for (i=0; i<GetNumberOfDimensions(); i++)
975 { sprintf(temp, "dim%d=%d\n", i+1, GetDimensions(i));
977 if (!checked_write(f, temp, slen, buffer))
986 { sprintf(temp, "nspace=%d\n", GetNumberOfDimensions());
988 if (!checked_write(f, temp, slen, buffer))
994 sprintf(temp, "veclen=%d\n", GetNumberOfComponents());
996 if (!checked_write(f, temp, slen, buffer))
1002 switch(GetComponentType())
1003 { case itk::ImageIOBase::CHAR : strcpy(temp, "data=byte\n"); break;
1004 case itk::ImageIOBase::SHORT : strcpy(temp, "data=xdr_short\n"); break;
1005 case itk::ImageIOBase::INT : strcpy(temp, "data=xdr_integer\n"); break;
1006 case itk::ImageIOBase::FLOAT : strcpy(temp, "data=xdr_real\n"); break;
1007 case itk::ImageIOBase::DOUBLE : strcpy(temp, "data=xdr_double\n"); break;
1008 default : if (f != fileno(stdout)) close(f);
1012 slen = strlen(temp);
1013 if (!checked_write(f, temp, slen, buffer))
1014 { free(pCompressed);
1021 //FilePos = tell(f);
1025 //switch(input->uniform)
1027 strcpy(temp, "field=uniform\n");
1028 coords = GetNumberOfDimensions() * 2;
1030 // case RECTILINEAR : strcpy(temp, "field=rectilinear\n");
1032 // case IRREGULAR : strcpy(temp, "field=irregular\n");
1033 // coords = total * input->nspace;
1035 // default : if (f != fileno(stdout)) close(f);
1036 // free(pCompressed);
1041 { if (!checked_write(f, temp, strlen(temp), buffer))
1042 { free(pCompressed);
1046 if ((iNkiCompression > 0) &&
1047 (GetComponentType() == itk::ImageIOBase::SHORT) &&
1048 (GetPixelType() == itk::ImageIOBase::SCALAR))
1049 { sprintf(temp, "nki_compression=%d", iNkiCompression);
1050 if (!checked_write(f, temp, strlen(temp), buffer))
1051 { free(pCompressed);
1056 temp[0] = temp[1] = 12;
1057 if (!checked_write(f, temp, 2, buffer))
1058 { free(pCompressed);
1063 total *= GetPixelSize();
1065 if ((!raw) && (iNkiCompression > 0) &&
1066 (GetComponentType() == itk::ImageIOBase::SHORT) &&
1067 (GetPixelType() == itk::ImageIOBase::SCALAR))
1068 { size_t iCompressedLength;
1070 iCompressedLength = nki_private_compress(pCompressed,
1071 (short int *)(data), total/2, iNkiCompression);
1073 if (iCompressedLength > 0)
1074 { if (!checked_write(f, pCompressed, iCompressedLength, buffer))
1075 { free(pCompressed);
1082 /* Compressionratio was poor: let's write uncompressed */
1083 iNkiCompression = 0;
1087 lseek(f, (unsigned int)FilePos, SEEK_SET); // use _lseeki64 just in case header size > UINT_MAX bytes
1091 /* swap data if required (xdr is low-endian) */
1093 if (!(*(char *)(&swap_test)))
1094 { if (GetComponentSize()==2)
1096 for (i=0; i<total; i+=2)
1097 { cSwap = c[i]; c[i] = c[i+1]; c[i+1] = cSwap;
1100 else if (GetComponentSize()==4)
1102 for (i=0; i<total; i+=4)
1103 { cSwap = c[i]; c[i] = c[i+3]; c[i+3] = cSwap;
1104 cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1107 else if (GetComponentSize()==8)
1109 for (i=0; i<total; i+=8)
1110 { cSwap = c[i]; c[i] = c[i+7]; c[i+7] = cSwap;
1111 cSwap = c[i+1]; c[i+1] = c[i+6]; c[i+6] = cSwap;
1112 cSwap = c[i+2]; c[i+2] = c[i+5]; c[i+5] = cSwap;
1113 cSwap = c[i+3]; c[i+3] = c[i+4]; c[i+4] = cSwap;
1119 { if (!checked_write(f, data, total, buffer))
1123 /* swap data back if was swapped before writing */
1125 if (!(*(char *)(&swap_test)))
1126 { if (GetComponentSize()==2)
1128 for (i=0; i<total; i+=2)
1129 { cSwap = c[i]; c[i] = c[i+1]; c[i+1] = cSwap;
1132 else if (GetComponentSize()==4)
1134 for (i=0; i<total; i+=4)
1135 { cSwap = c[i]; c[i] = c[i+3]; c[i+3] = cSwap;
1136 cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1139 else if (GetComponentSize()==8)
1141 for (i=0; i<total; i+=8)
1142 { cSwap = c[i]; c[i] = c[i+7]; c[i+7] = cSwap;
1143 cSwap = c[i+1]; c[i+1] = c[i+6]; c[i+6] = cSwap;
1144 cSwap = c[i+2]; c[i+2] = c[i+5]; c[i+5] = cSwap;
1145 cSwap = c[i+3]; c[i+3] = c[i+4]; c[i+4] = cSwap;
1152 points = (float *)malloc(sizeof(float)*GetNumberOfDimensions()*2);
1153 for (i=0; i<GetNumberOfDimensions(); i++)
1155 points[i*2 ] = 0.1 * GetOrigin(i);
1156 points[i*2+1] = 0.1 * (GetOrigin(i) + GetSpacing(i)*(GetDimensions(i)-1));
1159 if (coords && !raw) /* write AVS coordinates ? */
1160 { coords *= sizeof(float);
1161 if (!(*(char *)(&swap_test)))
1162 { c = (char *)(points); /* swap bytes */
1163 for (i=0; i<coords; i+=4)
1164 { cSwap = c[i]; c[i] = c[i+3]; c[i+3] = cSwap;
1165 cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1169 if (!checked_write(f, points, coords, buffer))
1172 if (!(*(char *)(&swap_test)))
1173 { c = (char *)(points); /* swap bytes back */
1174 for (i=0; i<coords; i+=4)
1175 { cSwap = c[i]; c[i] = c[i+3]; c[i+3] = cSwap;
1176 cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1181 if (!(tobuffer || getsize))
1182 if (f != fileno(stdout)) close(f);
1184 if (getsize) return;