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"
29 #include "clitkCommon.h"
34 #if !defined(unix) && !defined(__APPLE__)
35 //#define _read readfix
37 #define AVSINT std::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)
77 std::string filename(FileNameToWrite);
78 std::string filenameext = GetExtension(filename);
79 if (filenameext != std::string("xdr")) return false;
83 void clitk::XdrImageIO::Write(const void* buffer)
85 char *s = const_cast<char*>("");
86 WriteImage( m_FileName.c_str(), s, s, 0, -1, 0, 2, 0, 0, 0, 0, buffer);
89 // Based on a true story by the Nederlands Kanker Instituut (AVS_WXDR.CPP from the 20091216)
91 /************************************************************************/
93 /************************************************************************/
100 #if !defined(unix) && !defined(__APPLE__)
109 // don't use min() and max() macros indirectly defined by windows.h,
110 // but use portable std::min() and std:max() instead
117 /************************************************************************/
118 /* DEFINES, ENUMERATED TYPES AND CONSTANTS */
119 /************************************************************************/
123 // Fields with data size>8GB (having UINT_MAX short pixels) cannot be compressed using
124 // NKI_MODE2 struct because iOrgSize has type "unsigned int". In that case use NKI_MODE2_64BITS.
125 // The type of structure is indicated as follows:
127 // iOrgSize==0: NKI_MODE2_64BITS
128 // otherwise : NKI_MODE2
130 // Compression modes 1 and 3 (without CRCs) only use the first 2 members (iOrgSize and iMode).
133 unsigned int iOrgSize; /* in pixels (i.e. shorts) */
134 unsigned int iMode; /* 1, 2, 3 or 4 */
135 unsigned int iCompressedSize; /* in bytes, excluding header */
136 unsigned int iOrgCRC; /* CRC of the data (no coords etc) */
137 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)
225 for (unsigned i=0; i<count; i+=16384) {
227 if (j>16384) j=16384;
229 k=write(file, (char *)buf+i, j);
242 Version of write() that takes special action in case of
243 standard output. Based on commented out macro above.
244 This function overloads the <cstdio> (or stdio.h for old style C++)
248 // Like the original macro, we do /not/ want writefix from mbfield.c.
252 static int wxdr_write(int handle, const void * buf, unsigned len)
254 // if (handle == 1) // stdout
255 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)) {
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:
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;
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)
330 if (buffer && !handle) {
331 memcpy(*buffer, buf, len);
335 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
354 while (remaining>0) {
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
366 // call writefix (in mbfield.c) several times to interpret the signed 32-bit
367 // return value correctly. writefix uses chunks of 16384 bytes
368 while (remaining>0) {
369 chunksize = (int)std::min(remaining, (size_t)INT_MAX);
370 byteswritten = writefix(handle, buf, chunksize);
371 if (byteswritten == chunksize)
372 remaining -= chunksize;
374 break; // even writefix failed: return error
380 // Note: file is open in binary mode, no need to compensate
381 // for a value of byteswritten > len due to \n -> \r\n conversions.
382 // (write() on a text stream is implementation dependent.)
383 if (handle != fileno(stdout)) close(handle);
384 AVSerror("Avs_wxdr: write failed, disk full?");
389 /* coder for NKI private compressed pixel data
390 arguments: dest = (in) points to area where compressed destination data is written (byte)
391 src = (in) points to uncompressed source data (short)
392 npixels = (in) number of pixels to compress
394 The return value is the number of bytes in the compressed data (maximal 3*npixels+10, typical 0.52*npixels)
397 - The first 4 bytes contain the number of short-int pixels
398 - The following 4 bytes contain iMode=1
399 - The rest is the compressed image
402 - The first 4 bytes contain the number of short-int pixels
403 - The following 4 bytes contain iMode=2
404 - The following 4 bytes contain the size of the compressed image (in bytes)
405 - The following 4 bytes contain the CRC of the original image
406 - The following 4 bytes contain the CRC of the compressed image
407 - The rest is the compressed image
408 - The compressed size will be even (padded by a zero if necessary).
411 - The first 4 bytes contain the number of short-int pixels
412 - The following 4 bytes contain iMode=3
413 - The rest is the compressed image, including 4 bit differences
416 - The first 4 bytes contain the number of short-int pixels
417 - The following 4 bytes contain iMode=4
418 - The following 4 bytes contain the size of the compressed image (in bytes)
419 - The following 4 bytes contain the CRC of the original image
420 - The following 4 bytes contain 0
421 - The rest is the compressed image, including 4 bit differences
422 - The compressed size will be even (padded by a zero if necessary).
424 iMode 1 and iMode 2 are identical, except for the CRC data that is included for iMode 2
425 iMode 3 and iMode 4 are identical, except for the CRC data that is included for iMode 4
428 // optimized settings for the 4 bit run compressor (mode 3 and 4)
430 #define MINZEROS 5 // shortest RLE (2 byte overhead, but breaks 4bit run)
431 #define MIN4BIT 6 // shortest 4 bit run (6 bytes compressed to 5 bytes)
433 // This internal routine converts an 8 bit difference string into a 4 bit one
434 static signed char *recompress4bit(int n, signed char *dest)
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)
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);
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);
518 } else if (val >= -64 && val <= 63) { /* small difference coded as one byte */
519 *dest = (signed char)val;
521 } else if (val >= -0x3F00 && val <= 0x3EFF) { /* large differences coded as two bytes */
522 dest[0] = (signed char)((val>>8) ^ 0x40);
523 dest[1] = (signed char)val;
525 } else { /* if very large differences code abs val as three bytes */
527 *dest++ = (signed char)(src[0]>>8);
528 *dest++ = (signed char)(src[0]);
530 /* Are we beyond the allocated memory? */
531 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
536 else if (iMode == 2) {
540 *(short int *)dest = val = *src;
541 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char) val ] ^ ((iCRC2 >> 8));
542 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
543 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) val ] ^ ((iCRC >> 8));
544 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(val>>8)] ^ ((iCRC >> 8));
549 val = src[1] - src[0];
551 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
552 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
554 if (val == 0) { /* run length-encode zero differences */
556 if (i>=npixels || src[i-1]!=src[-1] || i==256) {
559 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0 ] ^ ((iCRC2 >> 8));
561 *dest++ = -128; // hexadecimal 0x80
562 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0x80 ] ^ ((iCRC2 >> 8));
563 *dest++ = (signed char)(i-1);
564 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (i-1)] ^ ((iCRC2 >> 8));
567 for (j=0; j<i-2; j++) {
569 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
570 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
576 } else if (val >= -64 && val <= 63) { /* small difference coded as one byte */
577 *dest = (signed char)val;
578 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val ] ^ ((iCRC2 >> 8));
580 } else if (val >= -0x3F00 && val <= 0x3EFF) { /* large differences coded as two bytes */
581 dest[0] = (signed char)((val>>8) ^ 0x40);
582 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)dest[0] ] ^ ((iCRC2 >> 8));
583 dest[1] = (signed char)val;
584 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val ] ^ ((iCRC2 >> 8));
586 } else { /* if very large differences code abs val as three bytes */
588 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0x7f ] ^ ((iCRC2 >> 8));
590 dest[1] = (signed char)(val>>8);
591 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
592 dest[2] = (signed char)val;
593 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val ] ^ ((iCRC2 >> 8));
596 /* Are we beyond the allocated memory? */
597 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
601 if ((dest - (signed char*)pHeader - iHeaderSize)<UINT_MAX) // store 32 bit number as third member
602 pHeader->iCompressedSize =
603 (unsigned int)(dest - (signed char*)pHeader - iHeaderSize);
604 else // store 64 bit number in extended structure
605 pHeader_64bits->i64CompressedSize = dest - (signed char*)pHeader -iHeaderSize;
607 /* Pad it to get an even length */
608 if (pHeader->iCompressedSize & 1) {
610 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0] ^ ((iCRC2 >> 8));
611 pHeader->iCompressedSize++;
614 pHeader->iOrgCRC = iCRC;
615 pHeader->iCompressedCRC = iCRC2;
618 /* Create the compressed image - compressor with added 4 bit run */
620 else if (iMode == 3) {
622 *(short int *)dest = *src;
627 val = src[1] - src[0];
630 if (val == 0) { /* run length-encode zero differences */
632 if (i>=npixels || src[i-1]!=src[-1] || i==256) {
633 if (i<=MINZEROS) { /* too short run -> write zeros */
634 for (j=0; j<i-1; j++) {
638 if(n4bit>=254) { /* maximum length 4 bit run */
639 dest = recompress4bit(n4bit, dest);
644 if (n4bit>=MIN4BIT) /* end (and write) 4 bit run */
645 dest = recompress4bit(n4bit, dest);
648 *dest++ = -128; // hexadecimal 0x80
649 *dest++ = (signed char)(i-1);
657 } else if (val >= -63 && val <= 63) { /* small difference coded as one byte */
658 if (val >= -8 && val <= 7) {
659 *dest++ = (signed char)val;
662 if(n4bit>=254) { /* maximum length 4 bit run */
663 dest = recompress4bit(n4bit, dest);
666 } else if(n4bit>=MIN4BIT) { /* end and write 4 bit run */
668 dest = recompress4bit(n4bit, dest);
670 *dest++ = (signed char)j;
672 *dest++ = (signed char)val; /* end 4 bit run */
675 } else if (val >= -0x3F00 && val <= 0x3EFF) { /* large differences coded as two bytes */
678 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
679 dest = recompress4bit(n4bit, dest);
682 dest[0] = (signed char)((j>>8) ^ 0x40);
683 dest[1] = (signed char)j;
685 } else { /* if very large differences code abs val as three bytes */
688 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
689 dest = recompress4bit(n4bit, dest);
693 *dest++ = (signed char)(j>>8);
694 *dest++ = (signed char)j;
696 /* Are we beyond the allocated memory? */
697 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
702 /* Create the compressed image - compressor with added 4 bit run and CRC */
704 else if (iMode == 4) {
708 *(short int *)dest = val = *src;
709 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) val ] ^ ((iCRC >> 8));
710 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(val>>8)] ^ ((iCRC >> 8));
715 val = src[1] - src[0];
717 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
718 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
720 if (val == 0) { /* run length-encode zero differences */
722 if (i>=npixels || src[i-1]!=src[-1] || i==256) {
723 if (i<=MINZEROS) { /* too short run -> write zeros */
724 for (j=0; j<i-1; j++) {
728 if(n4bit>=254) { /* maximum length 4 bit run */
729 dest = recompress4bit(n4bit, dest);
734 if (n4bit>=MIN4BIT) /* end (and write) 4 bit run */
735 dest = recompress4bit(n4bit, dest);
738 *dest++ = -128; // hexadecimal 0x80
739 *dest++ = (signed char)(i-1);
743 for (j=0; j<i-2; j++) {
745 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
746 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
751 } else if (val >= -63 && val <= 63) { /* small difference coded as one byte */
752 if (val >= -8 && val <= 7) {
753 *dest++ = (signed char)val;
756 if(n4bit>=254) { /* maximum length 4 bit run */
757 dest = recompress4bit(n4bit, dest);
760 } else if(n4bit>=MIN4BIT) { /* end and write 4 bit run */
762 dest = recompress4bit(n4bit, dest);
764 *dest++ = (signed char)j;
766 *dest++ = (signed char)val; /* end 4 bit run */
769 } else if (val >= -0x3F00 && val <= 0x3EFF) { /* large differences coded as two bytes */
772 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
773 dest = recompress4bit(n4bit, dest);
776 dest[0] = (signed char)((j>>8) ^ 0x40);
777 dest[1] = (signed char)j;
779 } else { /* if very large differences code abs val as three bytes */
782 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
783 dest = recompress4bit(n4bit, dest);
787 *dest++ = (signed char)(j>>8);
788 *dest++ = (signed char)j;
790 /* Are we beyond the allocated memory? */
791 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
795 if ((dest - (signed char*)pHeader - iHeaderSize)<UINT_MAX) // store 32 bit number as third member
796 pHeader->iCompressedSize =
797 (unsigned int)(dest - (signed char*)pHeader - iHeaderSize);
798 else { // store 64 bit number in extended structure
799 pHeader_64bits->iCompressedSize = 0;
800 pHeader_64bits->i64CompressedSize = dest - (signed char*)pHeader -iHeaderSize;
803 /* Pad it to get an even length */
804 if (pHeader->iCompressedSize & 1) {
806 pHeader->iCompressedSize++;
809 pHeader->iOrgCRC = iCRC;
810 pHeader->iCompressedCRC = 0;
813 return dest - (signed char*)pHeader;
817 void clitk::XdrImageIO::WriteImage(const char* file, char* headerinfo, char* headerfile, int raw,
818 int offset, char bLittleEndian, int iNkiCompression,
819 int wcoords, int append, int getsize, char *tobuffer, const void* data)
829 long swap_test = 0x1000000;
830 signed char* pCompressed = NULL;
832 char **buffer = NULL;
838 swap_test = 0x00000001;
841 swap_test = 0xffffffff; // never swap to save time
842 buffer = (char **) &len;
847 buf2 = (char *)tobuffer;
852 for (i=0; i<GetNumberOfDimensions(); i++) {
853 total *= GetDimensions(i);
854 coords += GetDimensions(i);
857 /* Try allocate the compressed fielddata - compression disabled if alloc fails */
858 if ((iNkiCompression > 0) &&
859 (GetComponentType() == itk::ImageIOBase::SHORT) &&
860 (GetPixelType() == itk::ImageIOBase::SCALAR)) {
861 pCompressed = (signed char *)malloc((total/2) * 3 + sizeof(NKI_MODE2_64BITS) + 10);
862 if (pCompressed==NULL) {
864 AVSwarning("Avs_wxdr: not enough memory to compress data, saving uncompressed");
868 if (!(tobuffer || getsize)) {
870 f = open(file, O_RDWR, 0);
872 AVSerror("Avs_wxdr: Opening " << file << "failed.\n" << strerror(errno));
876 lseek(f, offset, SEEK_SET);
882 f = open(file, O_RDWR | O_APPEND, 0);
884 f = creat(file, S_IWRITE | S_IREAD);
888 AVSerror("Avs_wxdr: Creating " << file << " failed.\n" << strerror(errno));
896 sprintf(temp, "# AVS wants to have the first line starting with its name\n");
899 if (!checked_write(f, temp, slen, buffer)) {
905 slen = strlen(headerinfo);
906 if (slen && !checked_write(f, headerinfo, slen, buffer)) {
912 if (!checked_write(f, "\n", 1, buffer)) {
918 if (strlen(headerfile)) {
919 fp = fopen(headerfile, "rt");
922 if (fgets(temp, 255, fp) == NULL) break;
924 if (!checked_write(f, temp, slen, buffer)) {
932 if (!checked_write(f, "\n", 1, buffer)) {
940 sprintf(temp, "ndim=%d\n", GetNumberOfDimensions());
942 if (!checked_write(f, temp, slen, buffer)) {
949 for (i=0; i<GetNumberOfDimensions(); i++) {
951 sprintf(temp, "dim%d=%d\n", i+1, GetDimensions(i));
953 if (!checked_write(f, temp, slen, buffer)) {
962 sprintf(temp, "nspace=%d\n", GetNumberOfDimensions());
964 if (!checked_write(f, temp, slen, buffer)) {
970 sprintf(temp, "veclen=%d\n", GetNumberOfComponents());
972 if (!checked_write(f, temp, slen, buffer)) {
978 switch(GetComponentType()) {
979 case itk::ImageIOBase::CHAR :
980 strcpy(temp, "data=byte\n");
982 case itk::ImageIOBase::SHORT :
983 strcpy(temp, "data=xdr_short\n");
985 case itk::ImageIOBase::INT :
986 strcpy(temp, "data=xdr_integer\n");
988 case itk::ImageIOBase::FLOAT :
989 strcpy(temp, "data=xdr_real\n");
991 case itk::ImageIOBase::DOUBLE :
992 strcpy(temp, "data=xdr_double\n");
995 if (f != fileno(stdout)) close(f);
1000 if (!checked_write(f, temp, slen, buffer)) {
1008 //FilePos = tell(f);
1012 //switch(input->uniform)
1014 strcpy(temp, "field=uniform\n");
1015 coords = GetNumberOfDimensions() * 2;
1017 // case RECTILINEAR : strcpy(temp, "field=rectilinear\n");
1019 // case IRREGULAR : strcpy(temp, "field=irregular\n");
1020 // coords = total * input->nspace;
1022 // default : if (f != fileno(stdout)) close(f);
1023 // free(pCompressed);
1028 if (!checked_write(f, temp, strlen(temp), buffer)) {
1033 if ((iNkiCompression > 0) &&
1034 (GetComponentType() == itk::ImageIOBase::SHORT) &&
1035 (GetPixelType() == itk::ImageIOBase::SCALAR)) {
1036 sprintf(temp, "nki_compression=%d", iNkiCompression);
1037 if (!checked_write(f, temp, strlen(temp), buffer)) {
1043 temp[0] = temp[1] = 12;
1044 if (!checked_write(f, temp, 2, buffer)) {
1050 total *= GetPixelSize();
1052 if ((!raw) && (iNkiCompression > 0) &&
1053 (GetComponentType() == itk::ImageIOBase::SHORT) &&
1054 (GetPixelType() == itk::ImageIOBase::SCALAR)) {
1055 size_t iCompressedLength;
1057 iCompressedLength = nki_private_compress(pCompressed,
1058 (short int *)(data), total/2, iNkiCompression);
1060 if (iCompressedLength > 0) {
1061 if (!checked_write(f, pCompressed, iCompressedLength, buffer)) {
1069 /* Compressionratio was poor: let's write uncompressed */
1070 iNkiCompression = 0;
1074 lseek(f, (unsigned int)FilePos, SEEK_SET); // use _lseeki64 just in case header size > UINT_MAX bytes
1078 /* swap data if required (xdr is low-endian) */
1080 if (!(*(char *)(&swap_test))) {
1081 if (GetComponentSize()==2) {
1083 for (i=0; i<total; i+=2) {
1088 } else if (GetComponentSize()==4) {
1090 for (i=0; i<total; i+=4) {
1098 } else if (GetComponentSize()==8) {
1100 for (i=0; i<total; i+=8) {
1118 if (!checked_write(f, data, total, buffer))
1122 /* swap data back if was swapped before writing */
1124 if (!(*(char *)(&swap_test))) {
1125 if (GetComponentSize()==2) {
1127 for (i=0; i<total; i+=2) {
1132 } else if (GetComponentSize()==4) {
1134 for (i=0; i<total; i+=4) {
1142 } else if (GetComponentSize()==8) {
1144 for (i=0; i<total; i+=8) {
1163 points = (float *)malloc(sizeof(float)*GetNumberOfDimensions()*2);
1164 for (i=0; i<GetNumberOfDimensions(); i++) {
1165 points[i*2 ] = 0.1 * GetOrigin(i);
1166 points[i*2+1] = 0.1 * (GetOrigin(i) + GetSpacing(i)*(GetDimensions(i)-1));
1169 if (coords && !raw) { /* write AVS coordinates ? */
1170 coords *= sizeof(float);
1171 if (!(*(char *)(&swap_test))) {
1172 c = (char *)(points); /* swap bytes */
1173 for (i=0; i<coords; i+=4) {
1183 if (!checked_write(f, points, coords, buffer))
1186 if (!(*(char *)(&swap_test))) {
1187 c = (char *)(points); /* swap bytes back */
1188 for (i=0; i<coords; i+=4) {
1199 if (!(tobuffer || getsize))
1200 if (f != fileno(stdout)) close(f);
1202 if (getsize) return;