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 // comment by ds
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 /************************************************************************/
112 // don't use min() and max() macros indirectly defined by windows.h,
113 // but use portable std::min() and std:max() instead
120 /************************************************************************/
121 /* DEFINES, ENUMERATED TYPES AND CONSTANTS */
122 /************************************************************************/
126 // Fields with data size>8GB (having UINT_MAX short pixels) cannot be compressed using
127 // NKI_MODE2 struct because iOrgSize has type "unsigned int". In that case use NKI_MODE2_64BITS.
128 // The type of structure is indicated as follows:
130 // iOrgSize==0: NKI_MODE2_64BITS
131 // otherwise : NKI_MODE2
133 // Compression modes 1 and 3 (without CRCs) only use the first 2 members (iOrgSize and iMode).
136 unsigned int iOrgSize; /* in pixels (i.e. shorts) */
137 unsigned int iMode; /* 1, 2, 3 or 4 */
138 unsigned int iCompressedSize; /* in bytes, excluding header */
139 unsigned int iOrgCRC; /* CRC of the data (no coords etc) */
140 unsigned int iCompressedCRC; /* CRC of the compressed data, excluding this header */
144 unsigned int iOrgSize; /* in pixels (i.e. shorts) */
145 unsigned int iMode; /* 1, 2, 3 or 4 */
146 unsigned int iCompressedSize; /* in bytes, excluding header */
147 unsigned int iOrgCRC; /* CRC of the data (no coords etc) */
148 unsigned int iCompressedCRC; /* CRC of the compressed data, excluding this header */
149 unsigned int iPad; /* unused */
150 Q_UINT64 i64OrgSize; /* used for more than UINT_MAX pixels, indicated by iOrgSize==0 (0-vector not compressed) */
151 Q_UINT64 i64CompressedSize; /* value in BYTES, used for more than UINT_MAX PIXELS, indicated by iCompressedSize==0 */
158 // Changed next to static function in stead of macro so it can
159 // have a return value to check in the calling function.
160 // It could be made inline as well, but there is no real time
161 // punishment from the extra layer of function calls.
163 // note: some compilers do not like comments ending in a backslash.
164 // so use macro functions to exclude.
167 /************************************************************************/
168 /* GLOBAL VARIABLES */
169 /************************************************************************/
171 static const unsigned long CRC32_table[256] = {
172 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
173 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
174 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
175 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
176 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
177 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
178 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
179 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
180 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
181 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
182 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
183 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
184 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
185 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
186 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
187 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
188 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
189 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
190 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
191 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
192 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
193 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
194 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
195 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
196 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
197 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
198 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
199 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
200 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
201 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
202 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
203 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
204 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
205 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
206 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
207 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
208 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
209 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
210 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
211 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
212 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
213 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
214 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
217 /************************************************************************/
218 /* MODULE FUNCTIONS */
219 /************************************************************************/
224 int writefix(int file, const void *buf, unsigned int count)
228 for (unsigned i=0; i<count; i+=16384) {
230 if (j>16384) j=16384;
232 k=write(file, (char *)buf+i, j);
245 Version of write() that takes special action in case of
246 standard output. Based on commented out macro above.
247 This function overloads the <cstdio> (or stdio.h for old style C++)
251 // Like the original macro, we do /not/ want writefix from mbfield.c.
255 static int wxdr_write(int handle, const void * buf, unsigned len)
257 // if (handle == 1) // stdout
258 if (handle == fileno(stdout)) {
260 // Behave as C standard library write(): return number of bytes
261 // written or -1 and errno set on error.
263 DWORD dwBytesWritten;
264 if (!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, len,
265 &dwBytesWritten, NULL)) {
266 // There is no simple 1-to-1 mapping between GetLastError()
267 // values that WriteFile() can return (quite a lot) and the two
268 // errno values that write() can return. So return EACCES in
270 switch (GetLastError()) {
271 case ERROR_INVALID_HANDLE:
280 return (int)dwBytesWritten; // May still be < len!
281 // And... write() may write a maximum of UINT_MAX-1 bytes, whereas
282 // WriteFile() may write UINT_MAX bytes at once. But since
283 // int(UINT_MAX) == -1 this will pose an actual problem in the
286 //const int oldmode = setmode(handle, O_BINARY);//commented out by joel
287 const int iBytesWritten = write(handle, buf, len);
288 const int saveerrno = errno; // setmode() may change errno.
289 //if (oldmode != -1) setmode(handle, oldmode); //commented out by joel
291 return iBytesWritten;
294 return write(handle, buf, len);
299 Behaves like win32 WriteFile() and returns a Boolean to indicate
300 success or failure, where failure almost invariably means disc full.
304 In case of failure, this function issues an AVS error message
305 and closes the file (if handle != 1). It is up to the calling
306 function to return the AVS_ERROR state and before that do things
307 like close other files, free memory etc. This way, there is less
308 chance of erroneously duplicated code, like in:
309 written = write(f, temp, strlen(temp));
310 if (written == -1 || written != strlen(temp))
312 if (f != fileno(stdout)) close(f);
315 written = write(f, buf, buflength)
316 if (written == -1 || written != strlen(temp)) {
317 // oops, wrong length copy'n'pasted
319 If more elaborate error handling is needed then the calling
320 functuon should use the (overloaded) write() and act on its return
321 value (and the value of errno) accordingly.
323 It does /not/ close stdout.
327 Note that checked_write() takes a size_t for len, whereas write() takes
328 an unsigned int of 4 bytes. On a 64 bits OS a size_t will be an 8 byte integer,
329 enabling more than UINT_MAX bytes to write at once.
331 static bool checked_write(int handle, const void * buf, size_t len, char **buffer)
333 if (buffer && !handle) {
334 memcpy(*buffer, buf, len);
338 if (buffer && handle) {
342 for(int i=0; i<2; i++) {
347 //If write fails, test if not related to big buffer problem
348 //Bug report http://support.microsoft.com/kb/899149 entitled
349 //"You cannot call the fwrite function to write to a buffer
350 // that is larger than 64 MB in Visual C++ 2005,
351 // in Visual C++ .NET 2003, or in Visual C++ .NET 2002"
352 // NB: same thing for write function in binary mode
355 // call wxdr_write (for handle!=fileno(stdout) a wrapper for write) several times
356 // to interpret the signed 32-bit return value correctly
357 while (remaining>0) {
358 chunksize = (int)std::min(remaining, (size_t)INT_MAX);
359 byteswritten = wxdr_write(handle, buf, chunksize);
360 if (byteswritten == chunksize)
361 remaining -= chunksize;
363 break; // try writefix in the next round
369 // call writefix (in mbfield.c) several times to interpret the signed 32-bit
370 // return value correctly. writefix uses chunks of 16384 bytes
371 while (remaining>0) {
372 chunksize = (int)std::min(remaining, (size_t)INT_MAX);
373 byteswritten = writefix(handle, buf, chunksize);
374 if (byteswritten == chunksize)
375 remaining -= chunksize;
377 break; // even writefix failed: return error
383 // Note: file is open in binary mode, no need to compensate
384 // for a value of byteswritten > len due to \n -> \r\n conversions.
385 // (write() on a text stream is implementation dependent.)
386 if (handle != fileno(stdout)) close(handle);
387 AVSerror("Avs_wxdr: write failed, disk full?");
392 /* coder for NKI private compressed pixel data
393 arguments: dest = (in) points to area where compressed destination data is written (byte)
394 src = (in) points to uncompressed source data (short)
395 npixels = (in) number of pixels to compress
397 The return value is the number of bytes in the compressed data (maximal 3*npixels+10, typical 0.52*npixels)
400 - The first 4 bytes contain the number of short-int pixels
401 - The following 4 bytes contain iMode=1
402 - The rest is the compressed image
405 - The first 4 bytes contain the number of short-int pixels
406 - The following 4 bytes contain iMode=2
407 - The following 4 bytes contain the size of the compressed image (in bytes)
408 - The following 4 bytes contain the CRC of the original image
409 - The following 4 bytes contain the CRC of the compressed image
410 - The rest is the compressed image
411 - The compressed size will be even (padded by a zero if necessary).
414 - The first 4 bytes contain the number of short-int pixels
415 - The following 4 bytes contain iMode=3
416 - The rest is the compressed image, including 4 bit differences
419 - The first 4 bytes contain the number of short-int pixels
420 - The following 4 bytes contain iMode=4
421 - The following 4 bytes contain the size of the compressed image (in bytes)
422 - The following 4 bytes contain the CRC of the original image
423 - The following 4 bytes contain 0
424 - The rest is the compressed image, including 4 bit differences
425 - The compressed size will be even (padded by a zero if necessary).
427 iMode 1 and iMode 2 are identical, except for the CRC data that is included for iMode 2
428 iMode 3 and iMode 4 are identical, except for the CRC data that is included for iMode 4
431 // optimized settings for the 4 bit run compressor (mode 3 and 4)
433 #define MINZEROS 5 // shortest RLE (2 byte overhead, but breaks 4bit run)
434 #define MIN4BIT 6 // shortest 4 bit run (6 bytes compressed to 5 bytes)
436 // This internal routine converts an 8 bit difference string into a 4 bit one
437 static signed char *recompress4bit(int n, signed char *dest)
445 val = (((int)p[0])<<4) | (p[1]&15);
447 *dest++ = -0x40; // 192 (0xc0) does not fit between -128..127: maps to -64 (0x40) in 2's complement
448 *dest++ = (signed char)n;
452 *dest++ = (signed char)((((int)p[0])<<4) | (p[1]&15));
456 q[0] = (signed char)val;
462 static size_t nki_private_compress(signed char *dest, short int *src, size_t npixels, int iMode)
466 unsigned int iHeaderSize=8; // value for iMode==1 and iMode==3
469 NKI_MODE2* pHeader = (NKI_MODE2*)dest;
470 NKI_MODE2_64BITS* pHeader_64bits = (NKI_MODE2_64BITS*)dest;
473 iBufferSize = (npixels / 2) * 3; // Buffer is sizeof(NKI_MODE2_64BITS) + 10 bytes larger
475 /* Up till now only Mode=1 .. 4 are supported */
476 if ((iMode < 1) || (iMode > 4))
479 /* Create the header */
480 pHeader->iMode = iMode;
482 if (sizeof(int*)>sizeof(int) && npixels>UINT_MAX) { // On a 64 bits OS we want to store files>4GB
483 pHeader_64bits->iOrgSize = 0; // This indicates>4GB file (0-vector is not compressed)
484 pHeader_64bits->i64OrgSize = npixels;
485 iHeaderSize = sizeof(NKI_MODE2_64BITS);
486 dest += sizeof(NKI_MODE2_64BITS);
488 pHeader->iOrgSize = (unsigned int)(npixels & UINT_MAX); // store 32 bit number as first member
490 if (iMode==2 || iMode==4)
491 iHeaderSize = sizeof(NKI_MODE2);
495 /* Create the compressed image */
498 *(short int *)dest = *src;
504 val = src[1] - src[0];
507 if (val == 0) { /* run length-encode zero differences */
509 if (i>=npixels || src[i-1]!=src[-1] || i==256) {
513 *dest++ = -128; // hexadecimal 0x80
514 *dest++ = (signed char)(i-1);
521 } else if (val >= -64 && val <= 63) { /* small difference coded as one byte */
522 *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;
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)
539 else if (iMode == 2) {
543 *(short int *)dest = val = *src;
544 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char) val ] ^ ((iCRC2 >> 8));
545 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
546 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) val ] ^ ((iCRC >> 8));
547 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(val>>8)] ^ ((iCRC >> 8));
552 val = src[1] - src[0];
554 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
555 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
557 if (val == 0) { /* run length-encode zero differences */
559 if (i>=npixels || src[i-1]!=src[-1] || i==256) {
562 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0 ] ^ ((iCRC2 >> 8));
564 *dest++ = -128; // hexadecimal 0x80
565 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0x80 ] ^ ((iCRC2 >> 8));
566 *dest++ = (signed char)(i-1);
567 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (i-1)] ^ ((iCRC2 >> 8));
570 for (j=0; j<i-2; j++) {
572 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
573 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
579 } else if (val >= -64 && val <= 63) { /* small difference coded as one byte */
580 *dest = (signed char)val;
581 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val ] ^ ((iCRC2 >> 8));
583 } else if (val >= -0x3F00 && val <= 0x3EFF) { /* large differences coded as two bytes */
584 dest[0] = (signed char)((val>>8) ^ 0x40);
585 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)dest[0] ] ^ ((iCRC2 >> 8));
586 dest[1] = (signed char)val;
587 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val ] ^ ((iCRC2 >> 8));
589 } else { /* if very large differences code abs val as three bytes */
591 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0x7f ] ^ ((iCRC2 >> 8));
593 dest[1] = (signed char)(val>>8);
594 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
595 dest[2] = (signed char)val;
596 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val ] ^ ((iCRC2 >> 8));
599 /* Are we beyond the allocated memory? */
600 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
604 if ((dest - (signed char*)pHeader - iHeaderSize)<UINT_MAX) // store 32 bit number as third member
605 pHeader->iCompressedSize =
606 (unsigned int)(dest - (signed char*)pHeader - iHeaderSize);
607 else // store 64 bit number in extended structure
608 pHeader_64bits->i64CompressedSize = dest - (signed char*)pHeader -iHeaderSize;
610 /* Pad it to get an even length */
611 if (pHeader->iCompressedSize & 1) {
613 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0] ^ ((iCRC2 >> 8));
614 pHeader->iCompressedSize++;
617 pHeader->iOrgCRC = iCRC;
618 pHeader->iCompressedCRC = iCRC2;
621 /* Create the compressed image - compressor with added 4 bit run */
623 else if (iMode == 3) {
625 *(short int *)dest = *src;
630 val = src[1] - src[0];
633 if (val == 0) { /* run length-encode zero differences */
635 if (i>=npixels || src[i-1]!=src[-1] || i==256) {
636 if (i<=MINZEROS) { /* too short run -> write zeros */
637 for (j=0; j<i-1; j++) {
641 if(n4bit>=254) { /* maximum length 4 bit run */
642 dest = recompress4bit(n4bit, dest);
647 if (n4bit>=MIN4BIT) /* end (and write) 4 bit run */
648 dest = recompress4bit(n4bit, dest);
651 *dest++ = -128; // hexadecimal 0x80
652 *dest++ = (signed char)(i-1);
660 } else if (val >= -63 && val <= 63) { /* small difference coded as one byte */
661 if (val >= -8 && val <= 7) {
662 *dest++ = (signed char)val;
665 if(n4bit>=254) { /* maximum length 4 bit run */
666 dest = recompress4bit(n4bit, dest);
669 } else if(n4bit>=MIN4BIT) { /* end and write 4 bit run */
671 dest = recompress4bit(n4bit, dest);
673 *dest++ = (signed char)j;
675 *dest++ = (signed char)val; /* end 4 bit run */
678 } else if (val >= -0x3F00 && val <= 0x3EFF) { /* large differences coded as two bytes */
681 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
682 dest = recompress4bit(n4bit, dest);
685 dest[0] = (signed char)((j>>8) ^ 0x40);
686 dest[1] = (signed char)j;
688 } else { /* if very large differences code abs val as three bytes */
691 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
692 dest = recompress4bit(n4bit, dest);
696 *dest++ = (signed char)(j>>8);
697 *dest++ = (signed char)j;
699 /* Are we beyond the allocated memory? */
700 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
705 /* Create the compressed image - compressor with added 4 bit run and CRC */
707 else if (iMode == 4) {
711 *(short int *)dest = val = *src;
712 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) val ] ^ ((iCRC >> 8));
713 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(val>>8)] ^ ((iCRC >> 8));
718 val = src[1] - src[0];
720 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
721 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
723 if (val == 0) { /* run length-encode zero differences */
725 if (i>=npixels || src[i-1]!=src[-1] || i==256) {
726 if (i<=MINZEROS) { /* too short run -> write zeros */
727 for (j=0; j<i-1; j++) {
731 if(n4bit>=254) { /* maximum length 4 bit run */
732 dest = recompress4bit(n4bit, dest);
737 if (n4bit>=MIN4BIT) /* end (and write) 4 bit run */
738 dest = recompress4bit(n4bit, dest);
741 *dest++ = -128; // hexadecimal 0x80
742 *dest++ = (signed char)(i-1);
746 for (j=0; j<i-2; j++) {
748 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
749 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
754 } else if (val >= -63 && val <= 63) { /* small difference coded as one byte */
755 if (val >= -8 && val <= 7) {
756 *dest++ = (signed char)val;
759 if(n4bit>=254) { /* maximum length 4 bit run */
760 dest = recompress4bit(n4bit, dest);
763 } else if(n4bit>=MIN4BIT) { /* end and write 4 bit run */
765 dest = recompress4bit(n4bit, dest);
767 *dest++ = (signed char)j;
769 *dest++ = (signed char)val; /* end 4 bit run */
772 } else if (val >= -0x3F00 && val <= 0x3EFF) { /* large differences coded as two bytes */
775 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
776 dest = recompress4bit(n4bit, dest);
779 dest[0] = (signed char)((j>>8) ^ 0x40);
780 dest[1] = (signed char)j;
782 } else { /* if very large differences code abs val as three bytes */
785 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
786 dest = recompress4bit(n4bit, dest);
790 *dest++ = (signed char)(j>>8);
791 *dest++ = (signed char)j;
793 /* Are we beyond the allocated memory? */
794 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
798 if ((dest - (signed char*)pHeader - iHeaderSize)<UINT_MAX) // store 32 bit number as third member
799 pHeader->iCompressedSize =
800 (unsigned int)(dest - (signed char*)pHeader - iHeaderSize);
801 else { // store 64 bit number in extended structure
802 pHeader_64bits->iCompressedSize = 0;
803 pHeader_64bits->i64CompressedSize = dest - (signed char*)pHeader -iHeaderSize;
806 /* Pad it to get an even length */
807 if (pHeader->iCompressedSize & 1) {
809 pHeader->iCompressedSize++;
812 pHeader->iOrgCRC = iCRC;
813 pHeader->iCompressedCRC = 0;
816 return dest - (signed char*)pHeader;
820 void clitk::XdrImageIO::WriteImage(const char* file, char* headerinfo, char* headerfile, int raw,
821 int offset, char bLittleEndian, int iNkiCompression,
822 int wcoords, int append, int getsize, char *tobuffer, const void* data)
832 long swap_test = 0x1000000;
833 signed char* pCompressed = NULL;
835 char **buffer = NULL;
842 _get_fmode(&oldFMode);
843 _set_fmode(O_BINARY); /* default binary i/o */
847 swap_test = 0x00000001;
850 swap_test = 0xffffffff; // never swap to save time
851 buffer = (char **) &len;
856 buf2 = (char *)tobuffer;
861 for (i=0; i<GetNumberOfDimensions(); i++) {
862 total *= GetDimensions(i);
863 coords += GetDimensions(i);
866 /* Try allocate the compressed fielddata - compression disabled if alloc fails */
867 if ((iNkiCompression > 0) &&
868 (GetComponentType() == itk::ImageIOBase::SHORT) &&
869 (GetPixelType() == itk::ImageIOBase::SCALAR)) {
870 pCompressed = (signed char *)malloc((total/2) * 3 + sizeof(NKI_MODE2_64BITS) + 10);
871 if (pCompressed==NULL) {
873 AVSwarning("Avs_wxdr: not enough memory to compress data, saving uncompressed");
877 if (!(tobuffer || getsize)) {
879 f = open(file, O_RDWR, 0);
881 AVSerror("Avs_wxdr: Opening " << file << "failed.\n" << strerror(errno));
885 lseek(f, offset, SEEK_SET);
891 f = open(file, O_RDWR | O_APPEND, 0);
893 f = creat(file, S_IWRITE | S_IREAD);
897 AVSerror("Avs_wxdr: Creating " << file << " failed.\n" << strerror(errno));
905 sprintf(temp, "# AVS wants to have the first line starting with its name\n");
908 if (!checked_write(f, temp, slen, buffer)) {
914 slen = strlen(headerinfo);
915 if (slen && !checked_write(f, headerinfo, slen, buffer)) {
921 if (!checked_write(f, "\n", 1, buffer)) {
927 if (strlen(headerfile)) {
928 fp = fopen(headerfile, "rt");
931 if (fgets(temp, 255, fp) == NULL) break;
933 if (!checked_write(f, temp, slen, buffer)) {
941 if (!checked_write(f, "\n", 1, buffer)) {
949 sprintf(temp, "ndim=%d\n", GetNumberOfDimensions());
951 if (!checked_write(f, temp, slen, buffer)) {
958 for (i=0; i<GetNumberOfDimensions(); i++) {
960 sprintf(temp, "dim%d=%lu\n", i+1, GetDimensions(i));
962 if (!checked_write(f, temp, slen, buffer)) {
971 sprintf(temp, "nspace=%d\n", GetNumberOfDimensions());
973 if (!checked_write(f, temp, slen, buffer)) {
979 sprintf(temp, "veclen=%d\n", GetNumberOfComponents());
981 if (!checked_write(f, temp, slen, buffer)) {
987 switch(GetComponentType()) {
988 case itk::ImageIOBase::CHAR :
989 strcpy(temp, "data=byte\n");
991 case itk::ImageIOBase::SHORT :
992 strcpy(temp, "data=xdr_short\n");
994 case itk::ImageIOBase::INT :
995 strcpy(temp, "data=xdr_integer\n");
997 case itk::ImageIOBase::FLOAT :
998 strcpy(temp, "data=xdr_real\n");
1000 case itk::ImageIOBase::DOUBLE :
1001 strcpy(temp, "data=xdr_double\n");
1004 if (f != fileno(stdout)) close(f);
1008 slen = strlen(temp);
1009 if (!checked_write(f, temp, slen, buffer)) {
1017 //FilePos = tell(f);
1021 //switch(input->uniform)
1023 strcpy(temp, "field=uniform\n");
1024 coords = GetNumberOfDimensions() * 2;
1026 // case RECTILINEAR : strcpy(temp, "field=rectilinear\n");
1028 // case IRREGULAR : strcpy(temp, "field=irregular\n");
1029 // coords = total * input->nspace;
1031 // default : if (f != fileno(stdout)) close(f);
1032 // free(pCompressed);
1037 if (!checked_write(f, temp, strlen(temp), buffer)) {
1042 if ((iNkiCompression > 0) &&
1043 (GetComponentType() == itk::ImageIOBase::SHORT) &&
1044 (GetPixelType() == itk::ImageIOBase::SCALAR)) {
1045 sprintf(temp, "nki_compression=%d", iNkiCompression);
1046 if (!checked_write(f, temp, strlen(temp), buffer)) {
1052 temp[0] = temp[1] = 12;
1053 if (!checked_write(f, temp, 2, buffer)) {
1059 total *= GetPixelSize();
1061 if ((!raw) && (iNkiCompression > 0) &&
1062 (GetComponentType() == itk::ImageIOBase::SHORT) &&
1063 (GetPixelType() == itk::ImageIOBase::SCALAR)) {
1064 size_t iCompressedLength;
1066 iCompressedLength = nki_private_compress(pCompressed,
1067 (short int *)(data), total/2, iNkiCompression);
1069 if (iCompressedLength > 0) {
1070 if (!checked_write(f, pCompressed, iCompressedLength, buffer)) {
1078 /* Compressionratio was poor: let's write uncompressed */
1079 iNkiCompression = 0;
1083 lseek(f, (unsigned int)FilePos, SEEK_SET); // use _lseeki64 just in case header size > UINT_MAX bytes
1087 /* swap data if required (xdr is low-endian) */
1089 if (!(*(char *)(&swap_test))) {
1090 if (GetComponentSize()==2) {
1092 for (i=0; i<total; i+=2) {
1097 } else if (GetComponentSize()==4) {
1099 for (i=0; i<total; i+=4) {
1107 } else if (GetComponentSize()==8) {
1109 for (i=0; i<total; i+=8) {
1127 if (!checked_write(f, data, total, buffer))
1131 /* swap data back if was swapped before writing */
1133 if (!(*(char *)(&swap_test))) {
1134 if (GetComponentSize()==2) {
1136 for (i=0; i<total; i+=2) {
1141 } else if (GetComponentSize()==4) {
1143 for (i=0; i<total; i+=4) {
1151 } else if (GetComponentSize()==8) {
1153 for (i=0; i<total; i+=8) {
1172 points = (float *)malloc(sizeof(float)*GetNumberOfDimensions()*2);
1173 for (i=0; i<GetNumberOfDimensions(); i++) {
1174 points[i*2 ] = 0.1 * GetOrigin(i);
1175 points[i*2+1] = 0.1 * (GetOrigin(i) + GetSpacing(i)*(GetDimensions(i)-1));
1178 if (coords && !raw) { /* write AVS coordinates ? */
1179 coords *= sizeof(float);
1180 if (!(*(char *)(&swap_test))) {
1181 c = (char *)(points); /* swap bytes */
1182 for (i=0; i<coords; i+=4) {
1192 if (!checked_write(f, points, coords, buffer))
1195 if (!(*(char *)(&swap_test))) {
1196 c = (char *)(points); /* swap bytes back */
1197 for (i=0; i<coords; i+=4) {
1208 if (!(tobuffer || getsize))
1209 if (f != fileno(stdout)) close(f);
1211 if (getsize) return;
1214 _set_fmode(oldFMode ? oldFMode : _O_TEXT); /* restore default binary i/o */