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"
34 #if !defined(unix) && !defined(__APPLE__)
35 //#define _read readfix
37 #define AVSINT ptrdiff_t
42 #if defined(unix) || defined(__APPLE__)
44 #define setmode(a,b) 0
48 # if defined(__GNUC__) || defined(unix) || defined(__APPLE__)
50 typedef long long Q_INT64;
51 typedef unsigned long long Q_UINT64;
52 # define Q_INT64_CONST(x) (x##ll)
53 # define Q_UINT64_CONST(x) (x##llu) /* gcc also allows ull */
54 /* When using MINGW with MS(V)CRT DLL, use MS format modifier. */
56 # define Q_INT64_FORMAT "I64"
58 # define Q_INT64_FORMAT "L"
60 # elif defined(__BORLANDC__) || defined(__WATCOMC__) || defined(_MSC_VER)
61 typedef __int64 Q_INT64;
62 typedef unsigned __int64 Q_UINT64;
63 # define Q_INT64_CONST(x) (x##i64)
64 # define Q_UINT64_CONST(x) (x##ui64) /* i64u is not allowed! */
66 # define Q_INT64_FORMAT "I64"
68 # define Q_INT64_FORMAT "L"
71 # error No 64 bit integers known for this compiler, edit portdefs.h.
75 bool clitk::XdrImageIO::CanWriteFile(const char* FileNameToWrite)
76 { std::string filename(FileNameToWrite);
77 std::string filenameext = GetExtension(filename);
78 if (filenameext != std::string("xdr")) return false;
82 void clitk::XdrImageIO::Write(const void* buffer)
83 { char *s = const_cast<char*>("");
84 WriteImage( m_FileName.c_str(), s, s, 0, -1, 0, 2, 0, 0, 0, 0, buffer);
87 // Based on a true story by the Nederlands Kanker Instituut (AVS_WXDR.CPP from the 20091216)
89 /************************************************************************/
91 /************************************************************************/
98 #if !defined(unix) && !defined(__APPLE__)
107 // don't use min() and max() macros indirectly defined by windows.h,
108 // but use portable std::min() and std:max() instead
115 /************************************************************************/
116 /* DEFINES, ENUMERATED TYPES AND CONSTANTS */
117 /************************************************************************/
121 // Fields with data size>8GB (having UINT_MAX short pixels) cannot be compressed using
122 // NKI_MODE2 struct because iOrgSize has type "unsigned int". In that case use NKI_MODE2_64BITS.
123 // The type of structure is indicated as follows:
125 // iOrgSize==0: NKI_MODE2_64BITS
126 // otherwise : NKI_MODE2
128 // Compression modes 1 and 3 (without CRCs) only use the first 2 members (iOrgSize and iMode).
132 unsigned int iOrgSize; /* in pixels (i.e. shorts) */
133 unsigned int iMode; /* 1, 2, 3 or 4 */
134 unsigned int iCompressedSize; /* in bytes, excluding header */
135 unsigned int iOrgCRC; /* CRC of the data (no coords etc) */
136 unsigned int iCompressedCRC; /* CRC of the compressed data, excluding this header */
141 unsigned int iOrgSize; /* in pixels (i.e. shorts) */
142 unsigned int iMode; /* 1, 2, 3 or 4 */
143 unsigned int iCompressedSize; /* in bytes, excluding header */
144 unsigned int iOrgCRC; /* CRC of the data (no coords etc) */
145 unsigned int iCompressedCRC; /* CRC of the compressed data, excluding this header */
146 unsigned int iPad; /* unused */
147 Q_UINT64 i64OrgSize; /* used for more than UINT_MAX pixels, indicated by iOrgSize==0 (0-vector not compressed) */
148 Q_UINT64 i64CompressedSize; /* value in BYTES, used for more than UINT_MAX PIXELS, indicated by iCompressedSize==0 */
155 // Changed next to static function in stead of macro so it can
156 // have a return value to check in the calling function.
157 // It could be made inline as well, but there is no real time
158 // punishment from the extra layer of function calls.
160 // note: some compilers do not like comments ending in a backslash.
161 // so use macro functions to exclude.
164 /************************************************************************/
165 /* GLOBAL VARIABLES */
166 /************************************************************************/
168 static const unsigned long CRC32_table[256] = {
169 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
170 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
171 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
172 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
173 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
174 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
175 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
176 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
177 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
178 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
179 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
180 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
181 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
182 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
183 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
184 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
185 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
186 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
187 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
188 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
189 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
190 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
191 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
192 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
193 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
194 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
195 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
196 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
197 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
198 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
199 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
200 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
201 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
202 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
203 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
204 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
205 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
206 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
207 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
208 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
209 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
210 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
211 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
214 /************************************************************************/
215 /* MODULE FUNCTIONS */
216 /************************************************************************/
221 int writefix(int file, const void *buf, unsigned int count)
224 for (unsigned i=0; i<count; i+=16384)
226 if (j>16384) j=16384;
228 k=write(file, (char *)buf+i, j);
241 Version of write() that takes special action in case of
242 standard output. Based on commented out macro above.
243 This function overloads the <cstdio> (or stdio.h for old style C++)
247 // Like the original macro, we do /not/ want writefix from mbfield.c.
251 static int wxdr_write(int handle, const void * buf, unsigned len)
253 // if (handle == 1) // stdout
254 if (handle == fileno(stdout))
257 // Behave as C standard library write(): return number of bytes
258 // written or -1 and errno set on error.
260 DWORD dwBytesWritten;
261 if (!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, len,
262 &dwBytesWritten, NULL))
264 // There is no simple 1-to-1 mapping between GetLastError()
265 // values that WriteFile() can return (quite a lot) and the two
266 // errno values that write() can return. So return EACCES in
268 switch (GetLastError())
269 { case ERROR_INVALID_HANDLE:
270 errno = EBADF ; break;
272 errno = EACCES; break;
277 return (int)dwBytesWritten; // May still be < len!
278 // And... write() may write a maximum of UINT_MAX-1 bytes, whereas
279 // WriteFile() may write UINT_MAX bytes at once. But since
280 // int(UINT_MAX) == -1 this will pose an actual problem in the
283 //const int oldmode = setmode(handle, O_BINARY);//commented out by joel
284 const int iBytesWritten = write(handle, buf, len);
285 const int saveerrno = errno; // setmode() may change errno.
286 //if (oldmode != -1) setmode(handle, oldmode); //commented out by joel
288 return iBytesWritten;
292 return write(handle, buf, len);
297 Behaves like win32 WriteFile() and returns a Boolean to indicate
298 success or failure, where failure almost invariably means disc full.
302 In case of failure, this function issues an AVS error message
303 and closes the file (if handle != 1). It is up to the calling
304 function to return the AVS_ERROR state and before that do things
305 like close other files, free memory etc. This way, there is less
306 chance of erroneously duplicated code, like in:
307 written = write(f, temp, strlen(temp));
308 if (written == -1 || written != strlen(temp))
310 if (f != fileno(stdout)) close(f);
313 written = write(f, buf, buflength)
314 if (written == -1 || written != strlen(temp)) {
315 // oops, wrong length copy'n'pasted
317 If more elaborate error handling is needed then the calling
318 functuon should use the (overloaded) write() and act on its return
319 value (and the value of errno) accordingly.
321 It does /not/ close stdout.
325 Note that checked_write() takes a size_t for len, whereas write() takes
326 an unsigned int of 4 bytes. On a 64 bits OS a size_t will be an 8 byte integer,
327 enabling more than UINT_MAX bytes to write at once.
329 static bool checked_write(int handle, const void * buf, size_t len, char **buffer)
330 { if (buffer && !handle)
331 { memcpy(*buffer, buf, len);
335 if (buffer && handle)
340 { for(int i=0; i<2; i++)
345 //If write fails, test if not related to big buffer problem
346 //Bug report http://support.microsoft.com/kb/899149 entitled
347 //"You cannot call the fwrite function to write to a buffer
348 // that is larger than 64 MB in Visual C++ 2005,
349 // in Visual C++ .NET 2003, or in Visual C++ .NET 2002"
350 // NB: same thing for write function in binary mode
353 // call wxdr_write (for handle!=fileno(stdout) a wrapper for write) several times
354 // to interpret the signed 32-bit return value correctly
356 { chunksize = (int)std::min(remaining, (size_t)INT_MAX);
357 byteswritten = wxdr_write(handle, buf, chunksize);
358 if (byteswritten == chunksize)
359 remaining -= chunksize;
361 break; // try writefix in the next round
368 // call writefix (in mbfield.c) several times to interpret the signed 32-bit
369 // return value correctly. writefix uses chunks of 16384 bytes
371 { chunksize = (int)std::min(remaining, (size_t)INT_MAX);
372 byteswritten = writefix(handle, buf, chunksize);
373 if (byteswritten == chunksize)
374 remaining -= chunksize;
376 break; // even writefix failed: return error
382 // Note: file is open in binary mode, no need to compensate
383 // for a value of byteswritten > len due to \n -> \r\n conversions.
384 // (write() on a text stream is implementation dependent.)
385 if (handle != fileno(stdout)) close(handle);
386 AVSerror("Avs_wxdr: write failed, disk full?");
391 /* coder for NKI private compressed pixel data
392 arguments: dest = (in) points to area where compressed destination data is written (byte)
393 src = (in) points to uncompressed source data (short)
394 npixels = (in) number of pixels to compress
396 The return value is the number of bytes in the compressed data (maximal 3*npixels+10, typical 0.52*npixels)
399 - The first 4 bytes contain the number of short-int pixels
400 - The following 4 bytes contain iMode=1
401 - The rest is the compressed image
404 - The first 4 bytes contain the number of short-int pixels
405 - The following 4 bytes contain iMode=2
406 - The following 4 bytes contain the size of the compressed image (in bytes)
407 - The following 4 bytes contain the CRC of the original image
408 - The following 4 bytes contain the CRC of the compressed image
409 - The rest is the compressed image
410 - The compressed size will be even (padded by a zero if necessary).
413 - The first 4 bytes contain the number of short-int pixels
414 - The following 4 bytes contain iMode=3
415 - The rest is the compressed image, including 4 bit differences
418 - The first 4 bytes contain the number of short-int pixels
419 - The following 4 bytes contain iMode=4
420 - The following 4 bytes contain the size of the compressed image (in bytes)
421 - The following 4 bytes contain the CRC of the original image
422 - The following 4 bytes contain 0
423 - The rest is the compressed image, including 4 bit differences
424 - The compressed size will be even (padded by a zero if necessary).
426 iMode 1 and iMode 2 are identical, except for the CRC data that is included for iMode 2
427 iMode 3 and iMode 4 are identical, except for the CRC data that is included for iMode 4
430 // optimized settings for the 4 bit run compressor (mode 3 and 4)
432 #define MINZEROS 5 // shortest RLE (2 byte overhead, but breaks 4bit run)
433 #define MIN4BIT 6 // shortest 4 bit run (6 bytes compressed to 5 bytes)
435 // This internal routine converts an 8 bit difference string into a 4 bit one
436 static signed char *recompress4bit(int n, signed char *dest)
437 { signed char *p, *q;
443 val = (((int)p[0])<<4) | (p[1]&15);
445 *dest++ = -0x40; // 192 (0xc0) does not fit between -128..127: maps to -64 (0x40) in 2's complement
446 *dest++ = (signed char)n;
450 { *dest++ = (signed char)((((int)p[0])<<4) | (p[1]&15));
454 q[0] = (signed char)val;
460 static size_t nki_private_compress(signed char *dest, short int *src, size_t npixels, int iMode)
461 { unsigned long iCRC;
463 unsigned int iHeaderSize=8; // value for iMode==1 and iMode==3
466 NKI_MODE2* pHeader = (NKI_MODE2*)dest;
467 NKI_MODE2_64BITS* pHeader_64bits = (NKI_MODE2_64BITS*)dest;
470 iBufferSize = (npixels / 2) * 3; // Buffer is sizeof(NKI_MODE2_64BITS) + 10 bytes larger
472 /* Up till now only Mode=1 .. 4 are supported */
473 if ((iMode < 1) || (iMode > 4))
476 /* Create the header */
477 pHeader->iMode = iMode;
479 if (sizeof(int*)>sizeof(int) && npixels>UINT_MAX) // On a 64 bits OS we want to store files>4GB
480 { pHeader_64bits->iOrgSize = 0; // This indicates>4GB file (0-vector is not compressed)
481 pHeader_64bits->i64OrgSize = npixels;
482 iHeaderSize = sizeof(NKI_MODE2_64BITS);
483 dest += sizeof(NKI_MODE2_64BITS);
486 { pHeader->iOrgSize = (unsigned int)(npixels & UINT_MAX); // store 32 bit number as first member
488 if (iMode==2 || iMode==4)
489 iHeaderSize = sizeof(NKI_MODE2);
493 /* Create the compressed image */
496 { *(short int *)dest = *src;
502 { val = src[1] - src[0];
505 if (val == 0) /* run length-encode zero differences */
507 { if (i>=npixels || src[i-1]!=src[-1] || i==256)
511 { *dest++ = -128; // hexadecimal 0x80
512 *dest++ = (signed char)(i-1);
520 else if (val >= -64 && val <= 63) /* small difference coded as one byte */
521 { *dest = (signed char)val;
524 else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
525 { dest[0] = (signed char)((val>>8) ^ 0x40);
526 dest[1] = (signed char)val;
529 else /* if very large differences code abs val as three bytes */
531 *dest++ = (signed char)(src[0]>>8);
532 *dest++ = (signed char)(src[0]);
534 /* Are we beyond the allocated memory? */
535 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
545 *(short int *)dest = val = *src;
546 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char) val ] ^ ((iCRC2 >> 8));
547 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
548 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) val ] ^ ((iCRC >> 8));
549 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(val>>8)] ^ ((iCRC >> 8));
554 { val = src[1] - src[0];
556 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
557 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
559 if (val == 0) /* run length-encode zero differences */
561 { if (i>=npixels || src[i-1]!=src[-1] || i==256)
564 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0 ] ^ ((iCRC2 >> 8));
567 { *dest++ = -128; // hexadecimal 0x80
568 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0x80 ] ^ ((iCRC2 >> 8));
569 *dest++ = (signed char)(i-1);
570 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (i-1)] ^ ((iCRC2 >> 8));
573 for (j=0; j<i-2; j++)
575 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
576 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
583 else if (val >= -64 && val <= 63) /* small difference coded as one byte */
584 { *dest = (signed char)val;
585 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val ] ^ ((iCRC2 >> 8));
588 else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
589 { dest[0] = (signed char)((val>>8) ^ 0x40);
590 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)dest[0] ] ^ ((iCRC2 >> 8));
591 dest[1] = (signed char)val;
592 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val ] ^ ((iCRC2 >> 8));
595 else /* if very large differences code abs val as three bytes */
597 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0x7f ] ^ ((iCRC2 >> 8));
599 dest[1] = (signed char)(val>>8);
600 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
601 dest[2] = (signed char)val;
602 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val ] ^ ((iCRC2 >> 8));
605 /* Are we beyond the allocated memory? */
606 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
611 if ((dest - (signed char*)pHeader - iHeaderSize)<UINT_MAX) // store 32 bit number as third member
612 pHeader->iCompressedSize =
613 (unsigned int)(dest - (signed char*)pHeader - iHeaderSize);
614 else // store 64 bit number in extended structure
615 pHeader_64bits->i64CompressedSize = dest - (signed char*)pHeader -iHeaderSize;
617 /* Pad it to get an even length */
618 if (pHeader->iCompressedSize & 1)
620 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0] ^ ((iCRC2 >> 8));
621 pHeader->iCompressedSize++;
624 pHeader->iOrgCRC = iCRC;
625 pHeader->iCompressedCRC = iCRC2;
628 /* Create the compressed image - compressor with added 4 bit run */
632 *(short int *)dest = *src;
637 { val = src[1] - src[0];
640 if (val == 0) /* run length-encode zero differences */
642 { if (i>=npixels || src[i-1]!=src[-1] || i==256)
643 { if (i<=MINZEROS) /* too short run -> write zeros */
644 { for (j=0; j<i-1; j++)
648 if(n4bit>=254) /* maximum length 4 bit run */
649 { dest = recompress4bit(n4bit, dest);
655 { if (n4bit>=MIN4BIT) /* end (and write) 4 bit run */
656 dest = recompress4bit(n4bit, dest);
659 *dest++ = -128; // hexadecimal 0x80
660 *dest++ = (signed char)(i-1);
669 else if (val >= -63 && val <= 63) /* small difference coded as one byte */
670 { if (val >= -8 && val <= 7)
671 { *dest++ = (signed char)val;
674 if(n4bit>=254) /* maximum length 4 bit run */
675 { dest = recompress4bit(n4bit, dest);
679 else if(n4bit>=MIN4BIT) /* end and write 4 bit run */
681 dest = recompress4bit(n4bit, dest);
683 *dest++ = (signed char)j;
686 { *dest++ = (signed char)val; /* end 4 bit run */
690 else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
693 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
694 dest = recompress4bit(n4bit, dest);
697 dest[0] = (signed char)((j>>8) ^ 0x40);
698 dest[1] = (signed char)j;
701 else /* if very large differences code abs val as three bytes */
704 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
705 dest = recompress4bit(n4bit, dest);
709 *dest++ = (signed char)(j>>8);
710 *dest++ = (signed char)j;
712 /* Are we beyond the allocated memory? */
713 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
719 /* Create the compressed image - compressor with added 4 bit run and CRC */
725 *(short int *)dest = val = *src;
726 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) val ] ^ ((iCRC >> 8));
727 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(val>>8)] ^ ((iCRC >> 8));
732 { val = src[1] - src[0];
734 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
735 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
737 if (val == 0) /* run length-encode zero differences */
739 { if (i>=npixels || src[i-1]!=src[-1] || i==256)
740 { if (i<=MINZEROS) /* too short run -> write zeros */
741 { for (j=0; j<i-1; j++)
745 if(n4bit>=254) /* maximum length 4 bit run */
746 { dest = recompress4bit(n4bit, dest);
752 { if (n4bit>=MIN4BIT) /* end (and write) 4 bit run */
753 dest = recompress4bit(n4bit, dest);
756 *dest++ = -128; // hexadecimal 0x80
757 *dest++ = (signed char)(i-1);
761 for (j=0; j<i-2; j++)
763 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
764 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
770 else if (val >= -63 && val <= 63) /* small difference coded as one byte */
771 { if (val >= -8 && val <= 7)
772 { *dest++ = (signed char)val;
775 if(n4bit>=254) /* maximum length 4 bit run */
776 { dest = recompress4bit(n4bit, dest);
780 else if(n4bit>=MIN4BIT) /* end and write 4 bit run */
782 dest = recompress4bit(n4bit, dest);
784 *dest++ = (signed char)j;
787 { *dest++ = (signed char)val; /* end 4 bit run */
791 else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
794 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
795 dest = recompress4bit(n4bit, dest);
798 dest[0] = (signed char)((j>>8) ^ 0x40);
799 dest[1] = (signed char)j;
802 else /* if very large differences code abs val as three bytes */
805 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
806 dest = recompress4bit(n4bit, dest);
810 *dest++ = (signed char)(j>>8);
811 *dest++ = (signed char)j;
813 /* Are we beyond the allocated memory? */
814 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
819 if ((dest - (signed char*)pHeader - iHeaderSize)<UINT_MAX) // store 32 bit number as third member
820 pHeader->iCompressedSize =
821 (unsigned int)(dest - (signed char*)pHeader - iHeaderSize);
822 else // store 64 bit number in extended structure
823 { pHeader_64bits->iCompressedSize = 0;
824 pHeader_64bits->i64CompressedSize = dest - (signed char*)pHeader -iHeaderSize;
827 /* Pad it to get an even length */
828 if (pHeader->iCompressedSize & 1)
830 pHeader->iCompressedSize++;
833 pHeader->iOrgCRC = iCRC;
834 pHeader->iCompressedCRC = 0;
837 return dest - (signed char*)pHeader;
841 void clitk::XdrImageIO::WriteImage(const char* file, char* headerinfo, char* headerfile, int raw,
842 int offset, char bLittleEndian, int iNkiCompression,
843 int wcoords, int append, int getsize, char *tobuffer, const void* data)
852 long swap_test = 0x1000000;
853 signed char* pCompressed = NULL;
855 char **buffer = NULL;
861 swap_test = 0x00000001;
864 { swap_test = 0xffffffff; // never swap to save time
865 buffer = (char **) &len;
870 { buf2 = (char *)tobuffer;
875 for (i=0; i<GetNumberOfDimensions(); i++)
876 { total *= GetDimensions(i);
877 coords += GetDimensions(i);
880 /* Try allocate the compressed fielddata - compression disabled if alloc fails */
881 if ((iNkiCompression > 0) &&
882 (GetComponentType() == itk::ImageIOBase::SHORT) &&
883 (GetPixelType() == itk::ImageIOBase::SCALAR))
884 { pCompressed = (signed char *)malloc((total/2) * 3 + sizeof(NKI_MODE2_64BITS) + 10);
885 if (pCompressed==NULL)
886 { iNkiCompression = 0;
887 AVSwarning("Avs_wxdr: not enough memory to compress data, saving uncompressed");
891 if (!(tobuffer || getsize))
893 { f = open(file, O_RDWR, 0);
896 AVSerror("Avs_wxdr: Opening " << file << "failed.\n" << strerror(errno));
900 lseek(f, offset, SEEK_SET);
903 { if (strlen(file)==0)
907 f = open(file, O_RDWR | O_APPEND, 0);
909 f = creat(file, S_IWRITE | S_IREAD);
913 { AVSerror("Avs_wxdr: Creating " << file << " failed.\n" << strerror(errno));
921 { sprintf(temp, "# AVS wants to have the first line starting with its name\n");
924 if (!checked_write(f, temp, slen, buffer))
930 slen = strlen(headerinfo);
931 if (slen && !checked_write(f, headerinfo, slen, buffer))
937 if (!checked_write(f, "\n", 1, buffer))
943 if (strlen(headerfile))
944 { fp = fopen(headerfile, "rt");
947 { if (fgets(temp, 255, fp) == NULL) break;
949 if (!checked_write(f, temp, slen, buffer))
957 if (!checked_write(f, "\n", 1, buffer))
965 sprintf(temp, "ndim=%d\n", GetNumberOfDimensions());
967 if (!checked_write(f, temp, slen, buffer))
974 for (i=0; i<GetNumberOfDimensions(); i++)
976 { sprintf(temp, "dim%d=%d\n", i+1, GetDimensions(i));
978 if (!checked_write(f, temp, slen, buffer))
987 { sprintf(temp, "nspace=%d\n", GetNumberOfDimensions());
989 if (!checked_write(f, temp, slen, buffer))
995 sprintf(temp, "veclen=%d\n", GetNumberOfComponents());
997 if (!checked_write(f, temp, slen, buffer))
1003 switch(GetComponentType())
1004 { case itk::ImageIOBase::CHAR : strcpy(temp, "data=byte\n"); break;
1005 case itk::ImageIOBase::SHORT : strcpy(temp, "data=xdr_short\n"); break;
1006 case itk::ImageIOBase::INT : strcpy(temp, "data=xdr_integer\n"); break;
1007 case itk::ImageIOBase::FLOAT : strcpy(temp, "data=xdr_real\n"); break;
1008 case itk::ImageIOBase::DOUBLE : strcpy(temp, "data=xdr_double\n"); break;
1009 default : if (f != fileno(stdout)) close(f);
1013 slen = strlen(temp);
1014 if (!checked_write(f, temp, slen, buffer))
1015 { free(pCompressed);
1022 //FilePos = tell(f);
1026 //switch(input->uniform)
1028 strcpy(temp, "field=uniform\n");
1029 coords = GetNumberOfDimensions() * 2;
1031 // case RECTILINEAR : strcpy(temp, "field=rectilinear\n");
1033 // case IRREGULAR : strcpy(temp, "field=irregular\n");
1034 // coords = total * input->nspace;
1036 // default : if (f != fileno(stdout)) close(f);
1037 // free(pCompressed);
1042 { if (!checked_write(f, temp, strlen(temp), buffer))
1043 { free(pCompressed);
1047 if ((iNkiCompression > 0) &&
1048 (GetComponentType() == itk::ImageIOBase::SHORT) &&
1049 (GetPixelType() == itk::ImageIOBase::SCALAR))
1050 { sprintf(temp, "nki_compression=%d", iNkiCompression);
1051 if (!checked_write(f, temp, strlen(temp), buffer))
1052 { free(pCompressed);
1057 temp[0] = temp[1] = 12;
1058 if (!checked_write(f, temp, 2, buffer))
1059 { free(pCompressed);
1064 total *= GetPixelSize();
1066 if ((!raw) && (iNkiCompression > 0) &&
1067 (GetComponentType() == itk::ImageIOBase::SHORT) &&
1068 (GetPixelType() == itk::ImageIOBase::SCALAR))
1069 { size_t iCompressedLength;
1071 iCompressedLength = nki_private_compress(pCompressed,
1072 (short int *)(data), total/2, iNkiCompression);
1074 if (iCompressedLength > 0)
1075 { if (!checked_write(f, pCompressed, iCompressedLength, buffer))
1076 { free(pCompressed);
1083 /* Compressionratio was poor: let's write uncompressed */
1084 iNkiCompression = 0;
1088 lseek(f, (unsigned int)FilePos, SEEK_SET); // use _lseeki64 just in case header size > UINT_MAX bytes
1092 /* swap data if required (xdr is low-endian) */
1094 if (!(*(char *)(&swap_test)))
1095 { if (GetComponentSize()==2)
1097 for (i=0; i<total; i+=2)
1098 { cSwap = c[i]; c[i] = c[i+1]; c[i+1] = cSwap;
1101 else if (GetComponentSize()==4)
1103 for (i=0; i<total; i+=4)
1104 { cSwap = c[i]; c[i] = c[i+3]; c[i+3] = cSwap;
1105 cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1108 else if (GetComponentSize()==8)
1110 for (i=0; i<total; i+=8)
1111 { cSwap = c[i]; c[i] = c[i+7]; c[i+7] = cSwap;
1112 cSwap = c[i+1]; c[i+1] = c[i+6]; c[i+6] = cSwap;
1113 cSwap = c[i+2]; c[i+2] = c[i+5]; c[i+5] = cSwap;
1114 cSwap = c[i+3]; c[i+3] = c[i+4]; c[i+4] = cSwap;
1120 { if (!checked_write(f, data, total, buffer))
1124 /* swap data back if was swapped before writing */
1126 if (!(*(char *)(&swap_test)))
1127 { if (GetComponentSize()==2)
1129 for (i=0; i<total; i+=2)
1130 { cSwap = c[i]; c[i] = c[i+1]; c[i+1] = cSwap;
1133 else if (GetComponentSize()==4)
1135 for (i=0; i<total; i+=4)
1136 { cSwap = c[i]; c[i] = c[i+3]; c[i+3] = cSwap;
1137 cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1140 else if (GetComponentSize()==8)
1142 for (i=0; i<total; i+=8)
1143 { cSwap = c[i]; c[i] = c[i+7]; c[i+7] = cSwap;
1144 cSwap = c[i+1]; c[i+1] = c[i+6]; c[i+6] = cSwap;
1145 cSwap = c[i+2]; c[i+2] = c[i+5]; c[i+5] = cSwap;
1146 cSwap = c[i+3]; c[i+3] = c[i+4]; c[i+4] = cSwap;
1153 points = (float *)malloc(sizeof(float)*GetNumberOfDimensions()*2);
1154 for (i=0; i<GetNumberOfDimensions(); i++)
1156 points[i*2 ] = 0.1 * GetOrigin(i);
1157 points[i*2+1] = 0.1 * (GetOrigin(i) + GetSpacing(i)*(GetDimensions(i)-1));
1160 if (coords && !raw) /* write AVS coordinates ? */
1161 { coords *= sizeof(float);
1162 if (!(*(char *)(&swap_test)))
1163 { c = (char *)(points); /* swap bytes */
1164 for (i=0; i<coords; i+=4)
1165 { cSwap = c[i]; c[i] = c[i+3]; c[i+3] = cSwap;
1166 cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1170 if (!checked_write(f, points, coords, buffer))
1173 if (!(*(char *)(&swap_test)))
1174 { c = (char *)(points); /* swap bytes back */
1175 for (i=0; i<coords; i+=4)
1176 { cSwap = c[i]; c[i] = c[i+3]; c[i+3] = cSwap;
1177 cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1182 if (!(tobuffer || getsize))
1183 if (f != fileno(stdout)) close(f);
1185 if (getsize) return;