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 /************************************************************************/
101 #if !defined(unix) && !defined(__APPLE__)
110 // don't use min() and max() macros indirectly defined by windows.h,
111 // but use portable std::min() and std:max() instead
118 /************************************************************************/
119 /* DEFINES, ENUMERATED TYPES AND CONSTANTS */
120 /************************************************************************/
124 // Fields with data size>8GB (having UINT_MAX short pixels) cannot be compressed using
125 // NKI_MODE2 struct because iOrgSize has type "unsigned int". In that case use NKI_MODE2_64BITS.
126 // The type of structure is indicated as follows:
128 // iOrgSize==0: NKI_MODE2_64BITS
129 // otherwise : NKI_MODE2
131 // Compression modes 1 and 3 (without CRCs) only use the first 2 members (iOrgSize and iMode).
134 unsigned int iOrgSize; /* in pixels (i.e. shorts) */
135 unsigned int iMode; /* 1, 2, 3 or 4 */
136 unsigned int iCompressedSize; /* in bytes, excluding header */
137 unsigned int iOrgCRC; /* CRC of the data (no coords etc) */
138 unsigned int iCompressedCRC; /* CRC of the compressed data, excluding this header */
142 unsigned int iOrgSize; /* in pixels (i.e. shorts) */
143 unsigned int iMode; /* 1, 2, 3 or 4 */
144 unsigned int iCompressedSize; /* in bytes, excluding header */
145 unsigned int iOrgCRC; /* CRC of the data (no coords etc) */
146 unsigned int iCompressedCRC; /* CRC of the compressed data, excluding this header */
147 unsigned int iPad; /* unused */
148 Q_UINT64 i64OrgSize; /* used for more than UINT_MAX pixels, indicated by iOrgSize==0 (0-vector not compressed) */
149 Q_UINT64 i64CompressedSize; /* value in BYTES, used for more than UINT_MAX PIXELS, indicated by iCompressedSize==0 */
156 // Changed next to static function in stead of macro so it can
157 // have a return value to check in the calling function.
158 // It could be made inline as well, but there is no real time
159 // punishment from the extra layer of function calls.
161 // note: some compilers do not like comments ending in a backslash.
162 // so use macro functions to exclude.
165 /************************************************************************/
166 /* GLOBAL VARIABLES */
167 /************************************************************************/
169 static const unsigned long CRC32_table[256] = {
170 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
171 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
172 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
173 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
174 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
175 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
176 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
177 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
178 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
179 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
180 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
181 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
182 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
183 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
184 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
185 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
186 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
187 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
188 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
189 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
190 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
191 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
192 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
193 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
194 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
195 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
196 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
197 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
198 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
199 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
200 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
201 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
202 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
203 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
204 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
205 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
206 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
207 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
208 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
209 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
210 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
211 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
212 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
215 /************************************************************************/
216 /* MODULE FUNCTIONS */
217 /************************************************************************/
222 int writefix(int file, const void *buf, unsigned int count)
226 for (unsigned i=0; i<count; i+=16384) {
228 if (j>16384) j=16384;
230 k=write(file, (char *)buf+i, j);
243 Version of write() that takes special action in case of
244 standard output. Based on commented out macro above.
245 This function overloads the <cstdio> (or stdio.h for old style C++)
249 // Like the original macro, we do /not/ want writefix from mbfield.c.
253 static int wxdr_write(int handle, const void * buf, unsigned len)
255 // if (handle == 1) // stdout
256 if (handle == fileno(stdout)) {
258 // Behave as C standard library write(): return number of bytes
259 // written or -1 and errno set on error.
261 DWORD dwBytesWritten;
262 if (!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, len,
263 &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:
278 return (int)dwBytesWritten; // May still be < len!
279 // And... write() may write a maximum of UINT_MAX-1 bytes, whereas
280 // WriteFile() may write UINT_MAX bytes at once. But since
281 // int(UINT_MAX) == -1 this will pose an actual problem in the
284 //const int oldmode = setmode(handle, O_BINARY);//commented out by joel
285 const int iBytesWritten = write(handle, buf, len);
286 const int saveerrno = errno; // setmode() may change errno.
287 //if (oldmode != -1) setmode(handle, oldmode); //commented out by joel
289 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)
331 if (buffer && !handle) {
332 memcpy(*buffer, buf, len);
336 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
355 while (remaining>0) {
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
367 // call writefix (in mbfield.c) several times to interpret the signed 32-bit
368 // return value correctly. writefix uses chunks of 16384 bytes
369 while (remaining>0) {
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)
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)
464 unsigned int iHeaderSize=8; // value for iMode==1 and iMode==3
467 NKI_MODE2* pHeader = (NKI_MODE2*)dest;
468 NKI_MODE2_64BITS* pHeader_64bits = (NKI_MODE2_64BITS*)dest;
471 iBufferSize = (npixels / 2) * 3; // Buffer is sizeof(NKI_MODE2_64BITS) + 10 bytes larger
473 /* Up till now only Mode=1 .. 4 are supported */
474 if ((iMode < 1) || (iMode > 4))
477 /* Create the header */
478 pHeader->iMode = iMode;
480 if (sizeof(int*)>sizeof(int) && npixels>UINT_MAX) { // On a 64 bits OS we want to store files>4GB
481 pHeader_64bits->iOrgSize = 0; // This indicates>4GB file (0-vector is not compressed)
482 pHeader_64bits->i64OrgSize = npixels;
483 iHeaderSize = sizeof(NKI_MODE2_64BITS);
484 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);
519 } else if (val >= -64 && val <= 63) { /* small difference coded as one byte */
520 *dest = (signed char)val;
522 } else if (val >= -0x3F00 && val <= 0x3EFF) { /* large differences coded as two bytes */
523 dest[0] = (signed char)((val>>8) ^ 0x40);
524 dest[1] = (signed char)val;
526 } else { /* if very large differences code abs val as three bytes */
528 *dest++ = (signed char)(src[0]>>8);
529 *dest++ = (signed char)(src[0]);
531 /* Are we beyond the allocated memory? */
532 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
537 else if (iMode == 2) {
541 *(short int *)dest = val = *src;
542 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char) val ] ^ ((iCRC2 >> 8));
543 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
544 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) val ] ^ ((iCRC >> 8));
545 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(val>>8)] ^ ((iCRC >> 8));
550 val = src[1] - src[0];
552 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
553 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
555 if (val == 0) { /* run length-encode zero differences */
557 if (i>=npixels || src[i-1]!=src[-1] || i==256) {
560 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0 ] ^ ((iCRC2 >> 8));
562 *dest++ = -128; // hexadecimal 0x80
563 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0x80 ] ^ ((iCRC2 >> 8));
564 *dest++ = (signed char)(i-1);
565 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (i-1)] ^ ((iCRC2 >> 8));
568 for (j=0; j<i-2; j++) {
570 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
571 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
577 } else if (val >= -64 && val <= 63) { /* small difference coded as one byte */
578 *dest = (signed char)val;
579 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val ] ^ ((iCRC2 >> 8));
581 } else if (val >= -0x3F00 && val <= 0x3EFF) { /* large differences coded as two bytes */
582 dest[0] = (signed char)((val>>8) ^ 0x40);
583 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)dest[0] ] ^ ((iCRC2 >> 8));
584 dest[1] = (signed char)val;
585 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val ] ^ ((iCRC2 >> 8));
587 } else { /* if very large differences code abs val as three bytes */
589 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0x7f ] ^ ((iCRC2 >> 8));
591 dest[1] = (signed char)(val>>8);
592 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
593 dest[2] = (signed char)val;
594 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val ] ^ ((iCRC2 >> 8));
597 /* Are we beyond the allocated memory? */
598 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
602 if ((dest - (signed char*)pHeader - iHeaderSize)<UINT_MAX) // store 32 bit number as third member
603 pHeader->iCompressedSize =
604 (unsigned int)(dest - (signed char*)pHeader - iHeaderSize);
605 else // store 64 bit number in extended structure
606 pHeader_64bits->i64CompressedSize = dest - (signed char*)pHeader -iHeaderSize;
608 /* Pad it to get an even length */
609 if (pHeader->iCompressedSize & 1) {
611 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0] ^ ((iCRC2 >> 8));
612 pHeader->iCompressedSize++;
615 pHeader->iOrgCRC = iCRC;
616 pHeader->iCompressedCRC = iCRC2;
619 /* Create the compressed image - compressor with added 4 bit run */
621 else if (iMode == 3) {
623 *(short int *)dest = *src;
628 val = src[1] - src[0];
631 if (val == 0) { /* run length-encode zero differences */
633 if (i>=npixels || src[i-1]!=src[-1] || i==256) {
634 if (i<=MINZEROS) { /* too short run -> write zeros */
635 for (j=0; j<i-1; j++) {
639 if(n4bit>=254) { /* maximum length 4 bit run */
640 dest = recompress4bit(n4bit, dest);
645 if (n4bit>=MIN4BIT) /* end (and write) 4 bit run */
646 dest = recompress4bit(n4bit, dest);
649 *dest++ = -128; // hexadecimal 0x80
650 *dest++ = (signed char)(i-1);
658 } else if (val >= -63 && val <= 63) { /* small difference coded as one byte */
659 if (val >= -8 && val <= 7) {
660 *dest++ = (signed char)val;
663 if(n4bit>=254) { /* maximum length 4 bit run */
664 dest = recompress4bit(n4bit, dest);
667 } else if(n4bit>=MIN4BIT) { /* end and write 4 bit run */
669 dest = recompress4bit(n4bit, dest);
671 *dest++ = (signed char)j;
673 *dest++ = (signed char)val; /* end 4 bit run */
676 } else if (val >= -0x3F00 && val <= 0x3EFF) { /* large differences coded as two bytes */
679 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
680 dest = recompress4bit(n4bit, dest);
683 dest[0] = (signed char)((j>>8) ^ 0x40);
684 dest[1] = (signed char)j;
686 } else { /* if very large differences code abs val as three bytes */
689 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
690 dest = recompress4bit(n4bit, dest);
694 *dest++ = (signed char)(j>>8);
695 *dest++ = (signed char)j;
697 /* Are we beyond the allocated memory? */
698 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
703 /* Create the compressed image - compressor with added 4 bit run and CRC */
705 else if (iMode == 4) {
709 *(short int *)dest = val = *src;
710 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) val ] ^ ((iCRC >> 8));
711 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(val>>8)] ^ ((iCRC >> 8));
716 val = src[1] - src[0];
718 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
719 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
721 if (val == 0) { /* run length-encode zero differences */
723 if (i>=npixels || src[i-1]!=src[-1] || i==256) {
724 if (i<=MINZEROS) { /* too short run -> write zeros */
725 for (j=0; j<i-1; j++) {
729 if(n4bit>=254) { /* maximum length 4 bit run */
730 dest = recompress4bit(n4bit, dest);
735 if (n4bit>=MIN4BIT) /* end (and write) 4 bit run */
736 dest = recompress4bit(n4bit, dest);
739 *dest++ = -128; // hexadecimal 0x80
740 *dest++ = (signed char)(i-1);
744 for (j=0; j<i-2; j++) {
746 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
747 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
752 } else if (val >= -63 && val <= 63) { /* small difference coded as one byte */
753 if (val >= -8 && val <= 7) {
754 *dest++ = (signed char)val;
757 if(n4bit>=254) { /* maximum length 4 bit run */
758 dest = recompress4bit(n4bit, dest);
761 } else if(n4bit>=MIN4BIT) { /* end and write 4 bit run */
763 dest = recompress4bit(n4bit, dest);
765 *dest++ = (signed char)j;
767 *dest++ = (signed char)val; /* end 4 bit run */
770 } else if (val >= -0x3F00 && val <= 0x3EFF) { /* large differences coded as two bytes */
773 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
774 dest = recompress4bit(n4bit, dest);
777 dest[0] = (signed char)((j>>8) ^ 0x40);
778 dest[1] = (signed char)j;
780 } else { /* if very large differences code abs val as three bytes */
783 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
784 dest = recompress4bit(n4bit, dest);
788 *dest++ = (signed char)(j>>8);
789 *dest++ = (signed char)j;
791 /* Are we beyond the allocated memory? */
792 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
796 if ((dest - (signed char*)pHeader - iHeaderSize)<UINT_MAX) // store 32 bit number as third member
797 pHeader->iCompressedSize =
798 (unsigned int)(dest - (signed char*)pHeader - iHeaderSize);
799 else { // store 64 bit number in extended structure
800 pHeader_64bits->iCompressedSize = 0;
801 pHeader_64bits->i64CompressedSize = dest - (signed char*)pHeader -iHeaderSize;
804 /* Pad it to get an even length */
805 if (pHeader->iCompressedSize & 1) {
807 pHeader->iCompressedSize++;
810 pHeader->iOrgCRC = iCRC;
811 pHeader->iCompressedCRC = 0;
814 return dest - (signed char*)pHeader;
818 void clitk::XdrImageIO::WriteImage(const char* file, char* headerinfo, char* headerfile, int raw,
819 int offset, char bLittleEndian, int iNkiCompression,
820 int wcoords, int append, int getsize, char *tobuffer, const void* data)
830 long swap_test = 0x1000000;
831 signed char* pCompressed = NULL;
833 char **buffer = NULL;
839 swap_test = 0x00000001;
842 swap_test = 0xffffffff; // never swap to save time
843 buffer = (char **) &len;
848 buf2 = (char *)tobuffer;
853 for (i=0; i<GetNumberOfDimensions(); i++) {
854 total *= GetDimensions(i);
855 coords += GetDimensions(i);
858 /* Try allocate the compressed fielddata - compression disabled if alloc fails */
859 if ((iNkiCompression > 0) &&
860 (GetComponentType() == itk::ImageIOBase::SHORT) &&
861 (GetPixelType() == itk::ImageIOBase::SCALAR)) {
862 pCompressed = (signed char *)malloc((total/2) * 3 + sizeof(NKI_MODE2_64BITS) + 10);
863 if (pCompressed==NULL) {
865 AVSwarning("Avs_wxdr: not enough memory to compress data, saving uncompressed");
869 if (!(tobuffer || getsize)) {
871 f = open(file, O_RDWR, 0);
873 AVSerror("Avs_wxdr: Opening " << file << "failed.\n" << strerror(errno));
877 lseek(f, offset, SEEK_SET);
883 f = open(file, O_RDWR | O_APPEND, 0);
885 f = creat(file, S_IWRITE | S_IREAD);
889 AVSerror("Avs_wxdr: Creating " << file << " failed.\n" << strerror(errno));
897 sprintf(temp, "# AVS wants to have the first line starting with its name\n");
900 if (!checked_write(f, temp, slen, buffer)) {
906 slen = strlen(headerinfo);
907 if (slen && !checked_write(f, headerinfo, slen, buffer)) {
913 if (!checked_write(f, "\n", 1, buffer)) {
919 if (strlen(headerfile)) {
920 fp = fopen(headerfile, "rt");
923 if (fgets(temp, 255, fp) == NULL) break;
925 if (!checked_write(f, temp, slen, buffer)) {
933 if (!checked_write(f, "\n", 1, buffer)) {
941 sprintf(temp, "ndim=%d\n", GetNumberOfDimensions());
943 if (!checked_write(f, temp, slen, buffer)) {
950 for (i=0; i<GetNumberOfDimensions(); i++) {
952 sprintf(temp, "dim%d=%d\n", i+1, GetDimensions(i));
954 if (!checked_write(f, temp, slen, buffer)) {
963 sprintf(temp, "nspace=%d\n", GetNumberOfDimensions());
965 if (!checked_write(f, temp, slen, buffer)) {
971 sprintf(temp, "veclen=%d\n", GetNumberOfComponents());
973 if (!checked_write(f, temp, slen, buffer)) {
979 switch(GetComponentType()) {
980 case itk::ImageIOBase::CHAR :
981 strcpy(temp, "data=byte\n");
983 case itk::ImageIOBase::SHORT :
984 strcpy(temp, "data=xdr_short\n");
986 case itk::ImageIOBase::INT :
987 strcpy(temp, "data=xdr_integer\n");
989 case itk::ImageIOBase::FLOAT :
990 strcpy(temp, "data=xdr_real\n");
992 case itk::ImageIOBase::DOUBLE :
993 strcpy(temp, "data=xdr_double\n");
996 if (f != fileno(stdout)) close(f);
1000 slen = strlen(temp);
1001 if (!checked_write(f, temp, slen, buffer)) {
1009 //FilePos = tell(f);
1013 //switch(input->uniform)
1015 strcpy(temp, "field=uniform\n");
1016 coords = GetNumberOfDimensions() * 2;
1018 // case RECTILINEAR : strcpy(temp, "field=rectilinear\n");
1020 // case IRREGULAR : strcpy(temp, "field=irregular\n");
1021 // coords = total * input->nspace;
1023 // default : if (f != fileno(stdout)) close(f);
1024 // free(pCompressed);
1029 if (!checked_write(f, temp, strlen(temp), buffer)) {
1034 if ((iNkiCompression > 0) &&
1035 (GetComponentType() == itk::ImageIOBase::SHORT) &&
1036 (GetPixelType() == itk::ImageIOBase::SCALAR)) {
1037 sprintf(temp, "nki_compression=%d", iNkiCompression);
1038 if (!checked_write(f, temp, strlen(temp), buffer)) {
1044 temp[0] = temp[1] = 12;
1045 if (!checked_write(f, temp, 2, buffer)) {
1051 total *= GetPixelSize();
1053 if ((!raw) && (iNkiCompression > 0) &&
1054 (GetComponentType() == itk::ImageIOBase::SHORT) &&
1055 (GetPixelType() == itk::ImageIOBase::SCALAR)) {
1056 size_t iCompressedLength;
1058 iCompressedLength = nki_private_compress(pCompressed,
1059 (short int *)(data), total/2, iNkiCompression);
1061 if (iCompressedLength > 0) {
1062 if (!checked_write(f, pCompressed, iCompressedLength, buffer)) {
1070 /* Compressionratio was poor: let's write uncompressed */
1071 iNkiCompression = 0;
1075 lseek(f, (unsigned int)FilePos, SEEK_SET); // use _lseeki64 just in case header size > UINT_MAX bytes
1079 /* swap data if required (xdr is low-endian) */
1081 if (!(*(char *)(&swap_test))) {
1082 if (GetComponentSize()==2) {
1084 for (i=0; i<total; i+=2) {
1089 } else if (GetComponentSize()==4) {
1091 for (i=0; i<total; i+=4) {
1099 } else if (GetComponentSize()==8) {
1101 for (i=0; i<total; i+=8) {
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) {
1133 } else if (GetComponentSize()==4) {
1135 for (i=0; i<total; i+=4) {
1143 } else if (GetComponentSize()==8) {
1145 for (i=0; i<total; i+=8) {
1164 points = (float *)malloc(sizeof(float)*GetNumberOfDimensions()*2);
1165 for (i=0; i<GetNumberOfDimensions(); i++) {
1166 points[i*2 ] = 0.1 * GetOrigin(i);
1167 points[i*2+1] = 0.1 * (GetOrigin(i) + GetSpacing(i)*(GetDimensions(i)-1));
1170 if (coords && !raw) { /* write AVS coordinates ? */
1171 coords *= sizeof(float);
1172 if (!(*(char *)(&swap_test))) {
1173 c = (char *)(points); /* swap bytes */
1174 for (i=0; i<coords; i+=4) {
1184 if (!checked_write(f, points, coords, buffer))
1187 if (!(*(char *)(&swap_test))) {
1188 c = (char *)(points); /* swap bytes back */
1189 for (i=0; i<coords; i+=4) {
1200 if (!(tobuffer || getsize))
1201 if (f != fileno(stdout)) close(f);
1203 if (getsize) return;