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__)
47 # if defined(__GNUC__) || defined(unix) || defined(__APPLE__)
49 typedef long long Q_INT64;
50 typedef unsigned long long Q_UINT64;
51 # define Q_INT64_CONST(x) (x##ll)
52 # define Q_UINT64_CONST(x) (x##llu) /* gcc also allows ull */
53 /* When using MINGW with MS(V)CRT DLL, use MS format modifier. */
55 # define Q_INT64_FORMAT "I64"
57 # define Q_INT64_FORMAT "L"
59 # elif defined(__BORLANDC__) || defined(__WATCOMC__) || defined(_MSC_VER)
60 typedef __int64 Q_INT64;
61 typedef unsigned __int64 Q_UINT64;
62 # define Q_INT64_CONST(x) (x##i64)
63 # define Q_UINT64_CONST(x) (x##ui64) /* i64u is not allowed! */
65 # define Q_INT64_FORMAT "I64"
67 # define Q_INT64_FORMAT "L"
70 # error No 64 bit integers known for this compiler, edit portdefs.h.
74 bool clitk::XdrImageIO::CanWriteFile(const char* FileNameToWrite)
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)
84 char *s = const_cast<char*>("");
85 WriteImage( m_FileName.c_str(), s, s, 0, -1, 0, 2, 0, 0, 0, 0, buffer);
88 // Based on a true story by the Nederlands Kanker Instituut (AVS_WXDR.CPP from the 20091216)
90 /************************************************************************/
92 /************************************************************************/
102 #if !defined(unix) && !defined(__APPLE__)
111 // don't use min() and max() macros indirectly defined by windows.h,
112 // but use portable std::min() and std:max() instead
119 /************************************************************************/
120 /* DEFINES, ENUMERATED TYPES AND CONSTANTS */
121 /************************************************************************/
125 // Fields with data size>8GB (having UINT_MAX short pixels) cannot be compressed using
126 // NKI_MODE2 struct because iOrgSize has type "unsigned int". In that case use NKI_MODE2_64BITS.
127 // The type of structure is indicated as follows:
129 // iOrgSize==0: NKI_MODE2_64BITS
130 // otherwise : NKI_MODE2
132 // Compression modes 1 and 3 (without CRCs) only use the first 2 members (iOrgSize and iMode).
135 unsigned int iOrgSize; /* in pixels (i.e. shorts) */
136 unsigned int iMode; /* 1, 2, 3 or 4 */
137 unsigned int iCompressedSize; /* in bytes, excluding header */
138 unsigned int iOrgCRC; /* CRC of the data (no coords etc) */
139 unsigned int iCompressedCRC; /* CRC of the compressed data, excluding this header */
143 unsigned int iOrgSize; /* in pixels (i.e. shorts) */
144 unsigned int iMode; /* 1, 2, 3 or 4 */
145 unsigned int iCompressedSize; /* in bytes, excluding header */
146 unsigned int iOrgCRC; /* CRC of the data (no coords etc) */
147 unsigned int iCompressedCRC; /* CRC of the compressed data, excluding this header */
148 unsigned int iPad; /* unused */
149 Q_UINT64 i64OrgSize; /* used for more than UINT_MAX pixels, indicated by iOrgSize==0 (0-vector not compressed) */
150 Q_UINT64 i64CompressedSize; /* value in BYTES, used for more than UINT_MAX PIXELS, indicated by iCompressedSize==0 */
157 // Changed next to static function in stead of macro so it can
158 // have a return value to check in the calling function.
159 // It could be made inline as well, but there is no real time
160 // punishment from the extra layer of function calls.
162 // note: some compilers do not like comments ending in a backslash.
163 // so use macro functions to exclude.
166 /************************************************************************/
167 /* GLOBAL VARIABLES */
168 /************************************************************************/
170 static const unsigned long CRC32_table[256] = {
171 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
172 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
173 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
174 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
175 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
176 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
177 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
178 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
179 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
180 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
181 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
182 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
183 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
184 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
185 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
186 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
187 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
188 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
189 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
190 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
191 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
192 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
193 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
194 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
195 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
196 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
197 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
198 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
199 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
200 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
201 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
202 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
203 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
204 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
205 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
206 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
207 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
208 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
209 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
210 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
211 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
212 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
213 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
216 /************************************************************************/
217 /* MODULE FUNCTIONS */
218 /************************************************************************/
223 int writefix(int file, const void *buf, unsigned int count)
227 for (unsigned i=0; i<count; i+=16384) {
229 if (j>16384) j=16384;
231 k=write(file, (char *)buf+i, j);
244 Version of write() that takes special action in case of
245 standard output. Based on commented out macro above.
246 This function overloads the <cstdio> (or stdio.h for old style C++)
250 // Like the original macro, we do /not/ want writefix from mbfield.c.
254 static int wxdr_write(int handle, const void * buf, unsigned len)
256 // if (handle == 1) // stdout
257 if (handle == fileno(stdout)) {
259 // Behave as C standard library write(): return number of bytes
260 // written or -1 and errno set on error.
262 DWORD dwBytesWritten;
263 if (!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, len,
264 &dwBytesWritten, NULL)) {
265 // There is no simple 1-to-1 mapping between GetLastError()
266 // values that WriteFile() can return (quite a lot) and the two
267 // errno values that write() can return. So return EACCES in
269 switch (GetLastError()) {
270 case ERROR_INVALID_HANDLE:
279 return (int)dwBytesWritten; // May still be < len!
280 // And... write() may write a maximum of UINT_MAX-1 bytes, whereas
281 // WriteFile() may write UINT_MAX bytes at once. But since
282 // int(UINT_MAX) == -1 this will pose an actual problem in the
285 //const int oldmode = setmode(handle, O_BINARY);//commented out by joel
286 const int iBytesWritten = write(handle, buf, len);
287 const int saveerrno = errno; // setmode() may change errno.
288 //if (oldmode != -1) setmode(handle, oldmode); //commented out by joel
290 return iBytesWritten;
293 return write(handle, buf, len);
298 Behaves like win32 WriteFile() and returns a Boolean to indicate
299 success or failure, where failure almost invariably means disc full.
303 In case of failure, this function issues an AVS error message
304 and closes the file (if handle != 1). It is up to the calling
305 function to return the AVS_ERROR state and before that do things
306 like close other files, free memory etc. This way, there is less
307 chance of erroneously duplicated code, like in:
308 written = write(f, temp, strlen(temp));
309 if (written == -1 || written != strlen(temp))
311 if (f != fileno(stdout)) close(f);
314 written = write(f, buf, buflength)
315 if (written == -1 || written != strlen(temp)) {
316 // oops, wrong length copy'n'pasted
318 If more elaborate error handling is needed then the calling
319 functuon should use the (overloaded) write() and act on its return
320 value (and the value of errno) accordingly.
322 It does /not/ close stdout.
326 Note that checked_write() takes a size_t for len, whereas write() takes
327 an unsigned int of 4 bytes. On a 64 bits OS a size_t will be an 8 byte integer,
328 enabling more than UINT_MAX bytes to write at once.
330 static bool checked_write(int handle, const void * buf, size_t len, char **buffer)
332 if (buffer && !handle) {
333 memcpy(*buffer, buf, len);
337 if (buffer && handle) {
341 for(int i=0; i<2; i++) {
346 //If write fails, test if not related to big buffer problem
347 //Bug report http://support.microsoft.com/kb/899149 entitled
348 //"You cannot call the fwrite function to write to a buffer
349 // that is larger than 64 MB in Visual C++ 2005,
350 // in Visual C++ .NET 2003, or in Visual C++ .NET 2002"
351 // NB: same thing for write function in binary mode
354 // call wxdr_write (for handle!=fileno(stdout) a wrapper for write) several times
355 // to interpret the signed 32-bit return value correctly
356 while (remaining>0) {
357 chunksize = (int)std::min(remaining, (size_t)INT_MAX);
358 byteswritten = wxdr_write(handle, buf, chunksize);
359 if (byteswritten == chunksize)
360 remaining -= chunksize;
362 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
370 while (remaining>0) {
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)
444 val = (((int)p[0])<<4) | (p[1]&15);
446 *dest++ = -0x40; // 192 (0xc0) does not fit between -128..127: maps to -64 (0x40) in 2's complement
447 *dest++ = (signed char)n;
451 *dest++ = (signed char)((((int)p[0])<<4) | (p[1]&15));
455 q[0] = (signed char)val;
461 static size_t nki_private_compress(signed char *dest, short int *src, size_t npixels, int iMode)
465 unsigned int iHeaderSize=8; // value for iMode==1 and iMode==3
468 NKI_MODE2* pHeader = (NKI_MODE2*)dest;
469 NKI_MODE2_64BITS* pHeader_64bits = (NKI_MODE2_64BITS*)dest;
472 iBufferSize = (npixels / 2) * 3; // Buffer is sizeof(NKI_MODE2_64BITS) + 10 bytes larger
474 /* Up till now only Mode=1 .. 4 are supported */
475 if ((iMode < 1) || (iMode > 4))
478 /* Create the header */
479 pHeader->iMode = iMode;
481 if (sizeof(int*)>sizeof(int) && npixels>UINT_MAX) { // On a 64 bits OS we want to store files>4GB
482 pHeader_64bits->iOrgSize = 0; // This indicates>4GB file (0-vector is not compressed)
483 pHeader_64bits->i64OrgSize = npixels;
484 iHeaderSize = sizeof(NKI_MODE2_64BITS);
485 dest += sizeof(NKI_MODE2_64BITS);
487 pHeader->iOrgSize = (unsigned int)(npixels & UINT_MAX); // store 32 bit number as first member
489 if (iMode==2 || iMode==4)
490 iHeaderSize = sizeof(NKI_MODE2);
494 /* Create the compressed image */
497 *(short int *)dest = *src;
503 val = src[1] - src[0];
506 if (val == 0) { /* run length-encode zero differences */
508 if (i>=npixels || src[i-1]!=src[-1] || i==256) {
512 *dest++ = -128; // hexadecimal 0x80
513 *dest++ = (signed char)(i-1);
520 } else if (val >= -64 && val <= 63) { /* small difference coded as one byte */
521 *dest = (signed char)val;
523 } else if (val >= -0x3F00 && val <= 0x3EFF) { /* large differences coded as two bytes */
524 dest[0] = (signed char)((val>>8) ^ 0x40);
525 dest[1] = (signed char)val;
527 } else { /* if very large differences code abs val as three bytes */
529 *dest++ = (signed char)(src[0]>>8);
530 *dest++ = (signed char)(src[0]);
532 /* Are we beyond the allocated memory? */
533 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
538 else if (iMode == 2) {
542 *(short int *)dest = val = *src;
543 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char) val ] ^ ((iCRC2 >> 8));
544 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
545 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) val ] ^ ((iCRC >> 8));
546 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(val>>8)] ^ ((iCRC >> 8));
551 val = src[1] - src[0];
553 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
554 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
556 if (val == 0) { /* run length-encode zero differences */
558 if (i>=npixels || src[i-1]!=src[-1] || i==256) {
561 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0 ] ^ ((iCRC2 >> 8));
563 *dest++ = -128; // hexadecimal 0x80
564 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0x80 ] ^ ((iCRC2 >> 8));
565 *dest++ = (signed char)(i-1);
566 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (i-1)] ^ ((iCRC2 >> 8));
569 for (j=0; j<i-2; j++) {
571 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
572 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
578 } else if (val >= -64 && val <= 63) { /* small difference coded as one byte */
579 *dest = (signed char)val;
580 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val ] ^ ((iCRC2 >> 8));
582 } else if (val >= -0x3F00 && val <= 0x3EFF) { /* large differences coded as two bytes */
583 dest[0] = (signed char)((val>>8) ^ 0x40);
584 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)dest[0] ] ^ ((iCRC2 >> 8));
585 dest[1] = (signed char)val;
586 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val ] ^ ((iCRC2 >> 8));
588 } else { /* if very large differences code abs val as three bytes */
590 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0x7f ] ^ ((iCRC2 >> 8));
592 dest[1] = (signed char)(val>>8);
593 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
594 dest[2] = (signed char)val;
595 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val ] ^ ((iCRC2 >> 8));
598 /* Are we beyond the allocated memory? */
599 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
603 if ((dest - (signed char*)pHeader - iHeaderSize)<UINT_MAX) // store 32 bit number as third member
604 pHeader->iCompressedSize =
605 (unsigned int)(dest - (signed char*)pHeader - iHeaderSize);
606 else // store 64 bit number in extended structure
607 pHeader_64bits->i64CompressedSize = dest - (signed char*)pHeader -iHeaderSize;
609 /* Pad it to get an even length */
610 if (pHeader->iCompressedSize & 1) {
612 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0] ^ ((iCRC2 >> 8));
613 pHeader->iCompressedSize++;
616 pHeader->iOrgCRC = iCRC;
617 pHeader->iCompressedCRC = iCRC2;
620 /* Create the compressed image - compressor with added 4 bit run */
622 else if (iMode == 3) {
624 *(short int *)dest = *src;
629 val = src[1] - src[0];
632 if (val == 0) { /* run length-encode zero differences */
634 if (i>=npixels || src[i-1]!=src[-1] || i==256) {
635 if (i<=MINZEROS) { /* too short run -> write zeros */
636 for (j=0; j<i-1; j++) {
640 if(n4bit>=254) { /* maximum length 4 bit run */
641 dest = recompress4bit(n4bit, dest);
646 if (n4bit>=MIN4BIT) /* end (and write) 4 bit run */
647 dest = recompress4bit(n4bit, dest);
650 *dest++ = -128; // hexadecimal 0x80
651 *dest++ = (signed char)(i-1);
659 } else if (val >= -63 && val <= 63) { /* small difference coded as one byte */
660 if (val >= -8 && val <= 7) {
661 *dest++ = (signed char)val;
664 if(n4bit>=254) { /* maximum length 4 bit run */
665 dest = recompress4bit(n4bit, dest);
668 } else if(n4bit>=MIN4BIT) { /* end and write 4 bit run */
670 dest = recompress4bit(n4bit, dest);
672 *dest++ = (signed char)j;
674 *dest++ = (signed char)val; /* end 4 bit run */
677 } else if (val >= -0x3F00 && val <= 0x3EFF) { /* large differences coded as two bytes */
680 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
681 dest = recompress4bit(n4bit, dest);
684 dest[0] = (signed char)((j>>8) ^ 0x40);
685 dest[1] = (signed char)j;
687 } else { /* if very large differences code abs val as three bytes */
690 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
691 dest = recompress4bit(n4bit, dest);
695 *dest++ = (signed char)(j>>8);
696 *dest++ = (signed char)j;
698 /* Are we beyond the allocated memory? */
699 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
704 /* Create the compressed image - compressor with added 4 bit run and CRC */
706 else if (iMode == 4) {
710 *(short int *)dest = val = *src;
711 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) val ] ^ ((iCRC >> 8));
712 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(val>>8)] ^ ((iCRC >> 8));
717 val = src[1] - src[0];
719 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
720 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
722 if (val == 0) { /* run length-encode zero differences */
724 if (i>=npixels || src[i-1]!=src[-1] || i==256) {
725 if (i<=MINZEROS) { /* too short run -> write zeros */
726 for (j=0; j<i-1; j++) {
730 if(n4bit>=254) { /* maximum length 4 bit run */
731 dest = recompress4bit(n4bit, dest);
736 if (n4bit>=MIN4BIT) /* end (and write) 4 bit run */
737 dest = recompress4bit(n4bit, dest);
740 *dest++ = -128; // hexadecimal 0x80
741 *dest++ = (signed char)(i-1);
745 for (j=0; j<i-2; j++) {
747 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
748 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
753 } else if (val >= -63 && val <= 63) { /* small difference coded as one byte */
754 if (val >= -8 && val <= 7) {
755 *dest++ = (signed char)val;
758 if(n4bit>=254) { /* maximum length 4 bit run */
759 dest = recompress4bit(n4bit, dest);
762 } else if(n4bit>=MIN4BIT) { /* end and write 4 bit run */
764 dest = recompress4bit(n4bit, dest);
766 *dest++ = (signed char)j;
768 *dest++ = (signed char)val; /* end 4 bit run */
771 } else if (val >= -0x3F00 && val <= 0x3EFF) { /* large differences coded as two bytes */
774 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
775 dest = recompress4bit(n4bit, dest);
778 dest[0] = (signed char)((j>>8) ^ 0x40);
779 dest[1] = (signed char)j;
781 } else { /* if very large differences code abs val as three bytes */
784 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
785 dest = recompress4bit(n4bit, dest);
789 *dest++ = (signed char)(j>>8);
790 *dest++ = (signed char)j;
792 /* Are we beyond the allocated memory? */
793 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
797 if ((dest - (signed char*)pHeader - iHeaderSize)<UINT_MAX) // store 32 bit number as third member
798 pHeader->iCompressedSize =
799 (unsigned int)(dest - (signed char*)pHeader - iHeaderSize);
800 else { // store 64 bit number in extended structure
801 pHeader_64bits->iCompressedSize = 0;
802 pHeader_64bits->i64CompressedSize = dest - (signed char*)pHeader -iHeaderSize;
805 /* Pad it to get an even length */
806 if (pHeader->iCompressedSize & 1) {
808 pHeader->iCompressedSize++;
811 pHeader->iOrgCRC = iCRC;
812 pHeader->iCompressedCRC = 0;
815 return dest - (signed char*)pHeader;
819 void clitk::XdrImageIO::WriteImage(const char* file, char* headerinfo, char* headerfile, int raw,
820 int offset, char bLittleEndian, int iNkiCompression,
821 int wcoords, int append, int getsize, char *tobuffer, const void* data)
831 long swap_test = 0x1000000;
832 signed char* pCompressed = NULL;
834 char **buffer = NULL;
841 _get_fmode(&oldFMode);
842 _set_fmode(O_BINARY); /* default binary i/o */
846 swap_test = 0x00000001;
849 swap_test = 0xffffffff; // never swap to save time
850 buffer = (char **) &len;
855 buf2 = (char *)tobuffer;
860 for (i=0; i<GetNumberOfDimensions(); i++) {
861 total *= GetDimensions(i);
862 coords += GetDimensions(i);
865 /* Try allocate the compressed fielddata - compression disabled if alloc fails */
866 if ((iNkiCompression > 0) &&
867 (GetComponentType() == itk::ImageIOBase::SHORT) &&
868 (GetPixelType() == itk::ImageIOBase::SCALAR)) {
869 pCompressed = (signed char *)malloc((total/2) * 3 + sizeof(NKI_MODE2_64BITS) + 10);
870 if (pCompressed==NULL) {
872 AVSwarning("Avs_wxdr: not enough memory to compress data, saving uncompressed");
876 if (!(tobuffer || getsize)) {
878 f = open(file, O_RDWR, 0);
880 AVSerror("Avs_wxdr: Opening " << file << "failed.\n" << strerror(errno));
884 lseek(f, offset, SEEK_SET);
890 f = open(file, O_RDWR | O_APPEND, 0);
892 f = creat(file, S_IWRITE | S_IREAD);
896 AVSerror("Avs_wxdr: Creating " << file << " failed.\n" << strerror(errno));
904 sprintf(temp, "# AVS wants to have the first line starting with its name\n");
907 if (!checked_write(f, temp, slen, buffer)) {
913 slen = strlen(headerinfo);
914 if (slen && !checked_write(f, headerinfo, slen, buffer)) {
920 if (!checked_write(f, "\n", 1, buffer)) {
926 if (strlen(headerfile)) {
927 fp = fopen(headerfile, "rt");
930 if (fgets(temp, 255, fp) == NULL) break;
932 if (!checked_write(f, temp, slen, buffer)) {
940 if (!checked_write(f, "\n", 1, buffer)) {
948 sprintf(temp, "ndim=%d\n", GetNumberOfDimensions());
950 if (!checked_write(f, temp, slen, buffer)) {
957 for (i=0; i<GetNumberOfDimensions(); i++) {
959 sprintf(temp, "dim%d=%d\n", i+1, GetDimensions(i));
961 if (!checked_write(f, temp, slen, buffer)) {
970 sprintf(temp, "nspace=%d\n", GetNumberOfDimensions());
972 if (!checked_write(f, temp, slen, buffer)) {
978 sprintf(temp, "veclen=%d\n", GetNumberOfComponents());
980 if (!checked_write(f, temp, slen, buffer)) {
986 switch(GetComponentType()) {
987 case itk::ImageIOBase::CHAR :
988 strcpy(temp, "data=byte\n");
990 case itk::ImageIOBase::SHORT :
991 strcpy(temp, "data=xdr_short\n");
993 case itk::ImageIOBase::INT :
994 strcpy(temp, "data=xdr_integer\n");
996 case itk::ImageIOBase::FLOAT :
997 strcpy(temp, "data=xdr_real\n");
999 case itk::ImageIOBase::DOUBLE :
1000 strcpy(temp, "data=xdr_double\n");
1003 if (f != fileno(stdout)) close(f);
1007 slen = strlen(temp);
1008 if (!checked_write(f, temp, slen, buffer)) {
1016 //FilePos = tell(f);
1020 //switch(input->uniform)
1022 strcpy(temp, "field=uniform\n");
1023 coords = GetNumberOfDimensions() * 2;
1025 // case RECTILINEAR : strcpy(temp, "field=rectilinear\n");
1027 // case IRREGULAR : strcpy(temp, "field=irregular\n");
1028 // coords = total * input->nspace;
1030 // default : if (f != fileno(stdout)) close(f);
1031 // free(pCompressed);
1036 if (!checked_write(f, temp, strlen(temp), buffer)) {
1041 if ((iNkiCompression > 0) &&
1042 (GetComponentType() == itk::ImageIOBase::SHORT) &&
1043 (GetPixelType() == itk::ImageIOBase::SCALAR)) {
1044 sprintf(temp, "nki_compression=%d", iNkiCompression);
1045 if (!checked_write(f, temp, strlen(temp), buffer)) {
1051 temp[0] = temp[1] = 12;
1052 if (!checked_write(f, temp, 2, buffer)) {
1058 total *= GetPixelSize();
1060 if ((!raw) && (iNkiCompression > 0) &&
1061 (GetComponentType() == itk::ImageIOBase::SHORT) &&
1062 (GetPixelType() == itk::ImageIOBase::SCALAR)) {
1063 size_t iCompressedLength;
1065 iCompressedLength = nki_private_compress(pCompressed,
1066 (short int *)(data), total/2, iNkiCompression);
1068 if (iCompressedLength > 0) {
1069 if (!checked_write(f, pCompressed, iCompressedLength, buffer)) {
1077 /* Compressionratio was poor: let's write uncompressed */
1078 iNkiCompression = 0;
1082 lseek(f, (unsigned int)FilePos, SEEK_SET); // use _lseeki64 just in case header size > UINT_MAX bytes
1086 /* swap data if required (xdr is low-endian) */
1088 if (!(*(char *)(&swap_test))) {
1089 if (GetComponentSize()==2) {
1091 for (i=0; i<total; i+=2) {
1096 } else if (GetComponentSize()==4) {
1098 for (i=0; i<total; i+=4) {
1106 } else if (GetComponentSize()==8) {
1108 for (i=0; i<total; i+=8) {
1126 if (!checked_write(f, data, total, buffer))
1130 /* swap data back if was swapped before writing */
1132 if (!(*(char *)(&swap_test))) {
1133 if (GetComponentSize()==2) {
1135 for (i=0; i<total; i+=2) {
1140 } else if (GetComponentSize()==4) {
1142 for (i=0; i<total; i+=4) {
1150 } else if (GetComponentSize()==8) {
1152 for (i=0; i<total; i+=8) {
1171 points = (float *)malloc(sizeof(float)*GetNumberOfDimensions()*2);
1172 for (i=0; i<GetNumberOfDimensions(); i++) {
1173 points[i*2 ] = 0.1 * GetOrigin(i);
1174 points[i*2+1] = 0.1 * (GetOrigin(i) + GetSpacing(i)*(GetDimensions(i)-1));
1177 if (coords && !raw) { /* write AVS coordinates ? */
1178 coords *= sizeof(float);
1179 if (!(*(char *)(&swap_test))) {
1180 c = (char *)(points); /* swap bytes */
1181 for (i=0; i<coords; i+=4) {
1191 if (!checked_write(f, points, coords, buffer))
1194 if (!(*(char *)(&swap_test))) {
1195 c = (char *)(points); /* swap bytes back */
1196 for (i=0; i<coords; i+=4) {
1207 if (!(tobuffer || getsize))
1208 if (f != fileno(stdout)) close(f);
1210 if (getsize) return;
1213 _set_fmode(oldFMode ? oldFMode : _O_TEXT); /* restore default binary i/o */