]> Creatis software - clitk.git/blob - common/clitkXdrImageIOWriter.cxx
*** empty log message ***
[clitk.git] / common / clitkXdrImageIOWriter.cxx
1 /**
2  * @file   clitkXdrImageIO.cxx
3  * @author Simon Rit <simon.rit@gmail.com>
4  * @date   Sun Jun  1 22:12:20 2008
5  *
6  * @brief
7  *
8  *
9  */
10
11 #include "clitkXdrImageIO.h"
12 #include "clitkCommon.h"
13
14 #include <sys/stat.h>
15
16 //From mbfield.h
17 #ifndef unix
18 //#define _read  readfix
19 #endif
20 #define AVSINT ptrdiff_t
21 #define AVS_ERROR
22 #define AVS_OK
23
24 //From portdefs.h
25 #ifdef unix
26 #define O_BINARY 0
27 #define setmode(a,b) 0
28 #endif
29
30 #ifndef __LARGE__
31 #  if defined(__GNUC__) || defined(unix)
32      typedef long long Q_INT64;
33      typedef unsigned long long Q_UINT64;
34 #    define Q_INT64_CONST(x) (x##ll)
35 #    define Q_UINT64_CONST(x) (x##llu) /* gcc also allows ull */
36      /* When using MINGW with MS(V)CRT DLL, use MS format modifier. */
37 #    ifdef __MSVCRT__
38 #      define Q_INT64_FORMAT "I64"
39 #    else
40 #      define Q_INT64_FORMAT "L"
41 #    endif
42 #  elif defined(__BORLANDC__) || defined(__WATCOMC__) || defined(_MSC_VER)
43      typedef __int64 Q_INT64;
44      typedef unsigned __int64 Q_UINT64;
45 #    define Q_INT64_CONST(x) (x##i64)
46 #    define Q_UINT64_CONST(x) (x##ui64) /* i64u is not allowed! */
47 #    ifdef _MSC_VER
48 #      define Q_INT64_FORMAT "I64"
49 #    else
50 #      define Q_INT64_FORMAT "L"
51 #    endif
52 #  else
53 #    error No 64 bit integers known for this compiler, edit portdefs.h.
54 #  endif
55 #endif
56
57 bool clitk::XdrImageIO::CanWriteFile(const char* FileNameToWrite)
58 { std::string filename(FileNameToWrite);
59   std::string filenameext = GetExtension(filename);
60   if (filenameext != std::string("xdr")) return false;
61   return true;
62 }
63
64 void clitk::XdrImageIO::Write(const void* buffer)
65 { char *s = const_cast<char*>("");
66   WriteImage( m_FileName.c_str(), s, s, 0, -1, 0, 2, 0, 0, 0, 0, buffer);
67 }
68
69 // Based on a true story by the Nederlands Kanker Instituut (AVS_WXDR.CPP from the 20091216)
70
71 /************************************************************************/
72 /*                             INCLUDE FILES                            */
73 /************************************************************************/
74
75 #include <string.h>
76 #include <stdio.h>
77 #include <math.h>
78 #include <stdlib.h>
79 #include <limits.h>
80 #ifndef unix
81 #include <io.h>
82 #endif
83 #include <fcntl.h>
84 #include <errno.h>
85
86 #include <algorithm>
87
88 #ifdef WIN32
89 // don't use min() and max() macros indirectly defined by windows.h, 
90 // but use portable std::min() and std:max() instead
91 #ifndef NOMINMAX
92 #define NOMINMAX
93 #endif
94 #include <windows.h>
95 #endif
96
97 /************************************************************************/
98 /*                    DEFINES, ENUMERATED TYPES AND CONSTANTS           */
99 /************************************************************************/
100
101 #pragma pack (1)
102
103 // Fields with data size>8GB (having UINT_MAX short pixels) cannot be compressed using
104 // NKI_MODE2 struct because iOrgSize has type "unsigned int". In that case use NKI_MODE2_64BITS.
105 // The type of structure is indicated as follows:
106 //
107 // iOrgSize==0: NKI_MODE2_64BITS
108 // otherwise  : NKI_MODE2
109 //
110 // Compression modes 1 and 3 (without CRCs) only use the first 2 members (iOrgSize and iMode).
111
112 typedef struct
113 {
114   unsigned int iOrgSize;          /* in pixels (i.e. shorts) */
115   unsigned int iMode;             /* 1, 2, 3 or 4 */
116   unsigned int iCompressedSize;   /* in bytes, excluding header */
117   unsigned int iOrgCRC;           /* CRC of the data (no coords etc) */
118   unsigned int iCompressedCRC;    /* CRC of the compressed data, excluding this header */
119 } NKI_MODE2;
120
121 typedef struct
122 {
123   unsigned int iOrgSize;          /* in pixels (i.e. shorts) */
124   unsigned int iMode;             /* 1, 2, 3 or 4 */
125   unsigned int iCompressedSize;   /* in bytes, excluding header */
126   unsigned int iOrgCRC;           /* CRC of the data (no coords etc) */
127   unsigned int iCompressedCRC;    /* CRC of the compressed data, excluding this header */
128   unsigned int iPad;              /* unused */
129   Q_UINT64     i64OrgSize;        /* used for more than UINT_MAX pixels, indicated by iOrgSize==0 (0-vector not compressed) */ 
130   Q_UINT64     i64CompressedSize; /* value in BYTES, used for more than UINT_MAX PIXELS, indicated by iCompressedSize==0 */ 
131   Q_UINT64     i64Future1;
132   Q_UINT64     i64Future2;
133 } NKI_MODE2_64BITS;
134
135 #pragma pack ()
136
137 // Changed next to static function in stead of macro so it can
138 // have a return value to check in the calling function.
139 // It could be made inline as well, but there is no real time
140 // punishment from the extra layer of function calls.
141
142 // note: some compilers do not like comments ending in a backslash.
143 // so use macro functions to exclude.
144
145
146 /************************************************************************/
147 /*                             GLOBAL VARIABLES                         */
148 /************************************************************************/
149
150 static const unsigned long CRC32_table[256] = {
151       0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
152       0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
153       0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
154       0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
155       0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
156       0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
157       0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
158       0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
159       0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
160       0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
161       0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
162       0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
163       0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
164       0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
165       0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
166       0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
167       0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
168       0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
169       0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
170       0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
171       0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
172       0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
173       0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
174       0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
175       0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
176       0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
177       0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
178       0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
179       0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
180       0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
181       0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
182       0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
183       0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
184       0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
185       0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
186       0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
187       0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
188       0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
189       0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
190       0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
191       0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
192       0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
193       0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
194 };
195
196 /************************************************************************/
197 /*                             MODULE FUNCTIONS                         */
198 /************************************************************************/
199
200 #ifdef __WATCOMC__
201 _WCRTLINK
202 #endif
203 int writefix(int file, const void *buf, unsigned int count)
204 { int j, k, total=0;
205
206   for (unsigned i=0; i<count; i+=16384)
207   { j = count - i;
208     if (j>16384) j=16384;
209
210     k=write(file, (char *)buf+i, j);
211     if (k < 0) return k;
212
213     total += k;
214
215     if (k != j) break;
216   }
217
218   return total;
219 }
220
221
222 /*
223   Version of write() that takes special action in case of
224   standard output.  Based on commented out macro above.
225   This function overloads the <cstdio> (or stdio.h for old style C++)
226   write() function.
227 */
228
229 // Like the original macro, we do /not/ want writefix from mbfield.c.
230 #ifdef write
231 #undef write
232 #endif
233 static int wxdr_write(int handle, const void * buf, unsigned len)
234 {
235   // if (handle == 1) // stdout
236   if (handle == fileno(stdout))
237   {
238 #ifdef WIN32
239     // Behave as C standard library write(): return number of bytes
240     // written or -1 and errno set on error.
241     fflush(stdout);
242     DWORD dwBytesWritten;
243     if (!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, len,
244                    &dwBytesWritten, NULL))
245     {
246       // There is no simple 1-to-1 mapping between GetLastError()
247       // values that WriteFile() can return (quite a lot) and the two
248       // errno values that write() can return.  So return EACCES in
249       // almost all cases.
250       switch (GetLastError())
251       { case ERROR_INVALID_HANDLE:
252           errno = EBADF ; break;
253         default:
254           errno = EACCES; break;
255       }
256       return -1;
257     }
258     else
259       return (int)dwBytesWritten; // May still be < len!
260       // And... write() may write a maximum of UINT_MAX-1 bytes, whereas
261       // WriteFile() may write UINT_MAX bytes at once.  But since
262       // int(UINT_MAX) == -1 this will pose an actual problem in the
263       // (far?) future.
264 #else // !WIN32
265     //const int oldmode = setmode(handle, O_BINARY);//commented out by joel
266     const int iBytesWritten = write(handle, buf, len);
267     const int saveerrno = errno; // setmode() may change errno.
268     //if (oldmode != -1) setmode(handle, oldmode); //commented out by joel
269     errno = saveerrno;
270     return iBytesWritten;
271 #endif // !WIN32
272   }
273   else
274     return write(handle, buf, len);
275 }
276
277 /*
278   Checked write().
279   Behaves like win32 WriteFile() and returns a Boolean to indicate
280   success or failure, where failure almost invariably means disc full.
281
282   !!! SIDE EFFECT !!!
283
284   In case of failure, this function issues an AVS error message
285   and closes the file (if handle != 1).  It is up to the calling
286   function to return the AVS_ERROR state and before that do things
287   like close other files, free memory etc.  This way, there is less
288   chance of erroneously duplicated code, like in:
289     written = write(f, temp, strlen(temp));
290     if (written == -1 || written != strlen(temp))
291     { AVSerror(...);
292       if (f != fileno(stdout)) close(f);
293       return AVS_ERROR;
294     }
295     written = write(f, buf, buflength)
296     if (written == -1 || written != strlen(temp)) {
297       // oops, wrong length copy'n'pasted
298
299   If more elaborate error handling is needed then the calling
300   functuon should use the (overloaded) write() and act on its return
301   value (and the value of errno) accordingly.
302
303   It does /not/ close stdout.
304
305   !!! SIDE EFFECT !!!
306
307   Note that checked_write() takes a size_t for len, whereas write() takes
308   an unsigned int of 4 bytes. On a 64 bits OS a size_t will be an 8 byte integer, 
309   enabling more than UINT_MAX bytes to write at once.
310 */
311 static bool checked_write(int handle, const void * buf, size_t len, char **buffer)
312 { if (buffer && !handle)
313   { memcpy(*buffer, buf, len);
314     (*buffer) += len;
315     return true;
316   }
317   if (buffer && handle)
318   { (*buffer) += len;
319     return true;
320   }
321   else
322   { for(int i=0; i<2; i++)
323     { int byteswritten;
324       size_t remaining;
325       int chunksize;
326
327       //If write fails, test if not related to big buffer problem
328       //Bug report http://support.microsoft.com/kb/899149 entitled
329       //"You cannot call the fwrite function to write to a buffer
330       // that is larger than 64 MB in Visual C++ 2005,
331       // in Visual C++ .NET 2003, or in Visual C++ .NET 2002"
332       // NB: same thing for write function in binary mode
333       if (i==0)
334       { remaining = len;
335         // call wxdr_write (for handle!=fileno(stdout) a wrapper for write) several times 
336         // to interpret the signed 32-bit return value correctly
337         while (remaining>0)
338         { chunksize = (int)std::min(remaining, (size_t)INT_MAX);
339           byteswritten = wxdr_write(handle, buf, chunksize);
340           if (byteswritten == chunksize)
341             remaining -= chunksize;
342           else
343             break; // try writefix in the next round
344         }
345         if (remaining == 0)
346           return true;
347       }
348       else
349       { remaining = len;   
350         // call writefix (in mbfield.c) several times to interpret the signed 32-bit 
351         // return value correctly. writefix uses chunks of 16384 bytes
352         while (remaining>0)
353         { chunksize = (int)std::min(remaining, (size_t)INT_MAX);
354           byteswritten = writefix(handle, buf, chunksize);
355           if (byteswritten == chunksize)
356             remaining -= chunksize;
357           else
358             break; // even writefix failed: return error        
359         }
360         if (remaining == 0)
361           return true;
362       }
363     }
364     // Note: file is open in binary mode, no need to compensate
365     // for a value of byteswritten > len due to \n -> \r\n conversions.
366     // (write() on a text stream is implementation dependent.)
367     if (handle != fileno(stdout)) close(handle);
368     AVSerror("Avs_wxdr: write failed, disk full?");
369     return false;
370   }
371 }
372
373 /* coder for NKI private compressed pixel data
374    arguments: dest    = (in) points to area where compressed destination data is written (byte)
375               src     = (in) points to uncompressed source data (short)
376               npixels = (in) number of pixels to compress
377
378    The return value is the number of bytes in the compressed data (maximal 3*npixels+10, typical 0.52*npixels)
379
380    if iMode == 1 then
381    - The first 4 bytes contain the number of short-int pixels
382    - The following 4 bytes contain iMode=1
383    - The rest is the compressed image
384
385    if iMode == 2 then
386    - The first 4 bytes contain the number of short-int pixels
387    - The following 4 bytes contain iMode=2
388    - The following 4 bytes contain the size of the compressed image (in bytes)
389    - The following 4 bytes contain the CRC of the original image
390    - The following 4 bytes contain the CRC of the compressed image
391    - The rest is the compressed image
392    - The compressed size will be even (padded by a zero if necessary).
393
394    if iMode == 3 then
395    - The first 4 bytes contain the number of short-int pixels
396    - The following 4 bytes contain iMode=3
397    - The rest is the compressed image, including 4 bit differences
398
399    if iMode == 4 then
400    - The first 4 bytes contain the number of short-int pixels
401    - The following 4 bytes contain iMode=4
402    - The following 4 bytes contain the size of the compressed image (in bytes)
403    - The following 4 bytes contain the CRC of the original image
404    - The following 4 bytes contain 0
405    - The rest is the compressed image, including 4 bit differences
406    - The compressed size will be even (padded by a zero if necessary).
407
408    iMode 1 and iMode 2 are identical, except for the CRC data that is included for iMode 2
409    iMode 3 and iMode 4 are identical, except for the CRC data that is included for iMode 4
410 */
411
412 // optimized settings for the 4 bit run compressor (mode 3 and 4)
413
414 #define MINZEROS 5              // shortest RLE (2 byte overhead, but breaks 4bit run)
415 #define MIN4BIT  6              // shortest 4 bit run (6 bytes compressed to 5 bytes)
416
417 // This internal routine converts an 8 bit difference string into a 4 bit one
418 static signed char *recompress4bit(int n, signed char *dest)
419 { signed char *p, *q;
420   int val;
421
422   n = n & 0xfe;
423   dest -= n;
424   p = dest;
425   val = (((int)p[0])<<4) | (p[1]&15);
426   p += 2;
427   *dest++ = -0x40; // 192 (0xc0) does not fit between -128..127: maps to -64 (0x40) in 2's complement
428   *dest++ = (signed char)n;
429   q = dest++;
430   n -= 2;
431   while(n>0)
432   { *dest++ = (signed char)((((int)p[0])<<4) | (p[1]&15));
433     p += 2;
434     n -= 2;
435   }
436   q[0] = (signed char)val;
437
438   return dest;
439 }
440
441
442 static size_t nki_private_compress(signed char  *dest, short int  *src, size_t npixels, int iMode)
443 { unsigned long         iCRC;
444   unsigned long         iCRC2;
445   unsigned int          iHeaderSize=8;                      // value for iMode==1 and iMode==3
446   register int          val;
447   size_t                i,j;
448   NKI_MODE2*            pHeader = (NKI_MODE2*)dest;
449   NKI_MODE2_64BITS*     pHeader_64bits = (NKI_MODE2_64BITS*)dest;
450   size_t                iBufferSize;
451
452   iBufferSize = (npixels / 2) * 3;                          // Buffer is sizeof(NKI_MODE2_64BITS) + 10 bytes larger
453
454   /* Up till now only Mode=1 .. 4 are supported */
455   if ((iMode < 1) || (iMode > 4))
456     return 0;
457
458   /* Create the header */
459   pHeader->iMode = iMode;
460
461   if (sizeof(int*)>sizeof(int) && npixels>UINT_MAX)         // On a 64 bits OS we want to store files>4GB 
462   { pHeader_64bits->iOrgSize   = 0;                         // This indicates>4GB file (0-vector is not compressed)
463     pHeader_64bits->i64OrgSize = npixels;    
464     iHeaderSize = sizeof(NKI_MODE2_64BITS);
465     dest += sizeof(NKI_MODE2_64BITS);
466   }
467   else
468   { pHeader->iOrgSize = (unsigned int)(npixels & UINT_MAX); // store 32 bit number as first member
469
470     if (iMode==2 || iMode==4)
471       iHeaderSize = sizeof(NKI_MODE2);
472     dest += iHeaderSize;
473   }
474
475   /* Create the compressed image */
476
477   if (iMode == 1)
478   { *(short int *)dest = *src;
479     dest+=2;
480
481     npixels--;
482
483     do
484     { val = src[1] - src[0];
485       src++;
486
487       if (val == 0)                            /* run length-encode zero differences */
488       { for (i=2;; i++)
489         { if (i>=npixels || src[i-1]!=src[-1] || i==256)
490           { if (i==2)
491               *dest++=0;
492             else
493             { *dest++  =  -128; // hexadecimal 0x80
494               *dest++  = (signed char)(i-1);
495               npixels -= (i-2);
496               src     += (i-2);
497             }
498             break;
499           }
500         }
501       }
502       else if (val >= -64 && val <= 63)         /* small difference coded as one byte */
503       { *dest = (signed char)val;
504         dest++;
505       }
506       else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
507       { dest[0] = (signed char)((val>>8) ^ 0x40);
508         dest[1] = (signed char)val;
509         dest+=2;
510       }
511       else                                      /* if very large differences code abs val as three bytes */
512       { *dest++ = 0x7F;
513         *dest++ = (signed char)(src[0]>>8);
514         *dest++ = (signed char)(src[0]);
515       }
516       /* Are we beyond the allocated memory? */
517       if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
518         return 0;
519     }
520     while (--npixels);
521   }
522
523   else if (iMode == 2)
524   { iCRC  = 0;
525     iCRC2 = 0;
526
527     *(short int *)dest = val = *src;
528     iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char) val    ] ^ ((iCRC2 >> 8));
529     iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
530     iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char) val    ] ^ ((iCRC  >> 8));
531     iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char)(val>>8)] ^ ((iCRC  >> 8));
532     dest+=2;
533     npixels--;
534
535     do
536     { val = src[1] - src[0];
537       src++;
538       iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char) src[0]    ] ^ ((iCRC  >> 8));
539       iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char)(src[0]>>8)] ^ ((iCRC  >> 8));
540
541       if (val == 0)                            /* run length-encode zero differences */
542       { for (i=2;; i++)
543         { if (i>=npixels || src[i-1]!=src[-1] || i==256)
544           { if (i==2)
545             { *dest++=0;
546               iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0    ] ^ ((iCRC2 >> 8));
547             }
548             else
549             { *dest++  =  -128; // hexadecimal 0x80
550               iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0x80 ] ^ ((iCRC2 >> 8));
551               *dest++  = (signed char)(i-1);
552               iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (i-1)] ^ ((iCRC2 >> 8));
553               npixels -= (i-2);
554
555               for (j=0; j<i-2; j++)
556               { src++;
557                 iCRC = CRC32_table[(unsigned char)iCRC  ^ (unsigned char) src[0]    ] ^ ((iCRC  >> 8));
558                 iCRC = CRC32_table[(unsigned char)iCRC  ^ (unsigned char)(src[0]>>8)] ^ ((iCRC  >> 8));
559               }
560             }
561             break;
562           }
563         }
564       }
565       else if (val >= -64 && val <= 63)         /* small difference coded as one byte */
566       { *dest = (signed char)val;
567         iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val     ] ^ ((iCRC2 >> 8));
568         dest++;
569       }
570       else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
571       { dest[0] = (signed char)((val>>8) ^ 0x40);
572         iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)dest[0] ] ^ ((iCRC2 >> 8));
573         dest[1] = (signed char)val;
574         iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val     ] ^ ((iCRC2 >> 8));
575         dest+=2;
576       }
577       else                                      /* if very large differences code abs val as three bytes */
578       { dest[0] = 0x7F;
579         iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0x7f                   ] ^ ((iCRC2 >> 8));
580         val     = src[0];
581         dest[1] = (signed char)(val>>8);
582         iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
583         dest[2] = (signed char)val;
584         iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val     ] ^ ((iCRC2 >> 8));
585         dest+=3;
586       }
587       /* Are we beyond the allocated memory? */
588       if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
589         return 0;
590     }
591     while (--npixels);
592     
593     if ((dest - (signed char*)pHeader - iHeaderSize)<UINT_MAX) // store 32 bit number as third member
594       pHeader->iCompressedSize = 
595         (unsigned int)(dest - (signed char*)pHeader - iHeaderSize);
596     else                                                       // store 64 bit number in extended structure
597       pHeader_64bits->i64CompressedSize = dest - (signed char*)pHeader -iHeaderSize;
598
599     /* Pad it to get an even length */
600     if (pHeader->iCompressedSize & 1)
601     { *dest++ = 0;
602       iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0] ^ ((iCRC2 >> 8));
603       pHeader->iCompressedSize++;
604     }
605
606     pHeader->iOrgCRC        = iCRC;
607     pHeader->iCompressedCRC = iCRC2;
608   }
609
610   /* Create the compressed image - compressor with added 4 bit run */
611
612   else if (iMode == 3)
613   { int n4bit=0;
614     *(short int *)dest = *src;
615     dest+=2;
616     npixels--;
617
618     do
619     { val = src[1] - src[0];
620       src++;
621
622       if (val == 0)                             /* run length-encode zero differences */
623       { for (i=2;; i++)
624         { if (i>=npixels || src[i-1]!=src[-1] || i==256)
625           { if (i<=MINZEROS)                    /* too short run -> write zeros */
626             { for (j=0; j<i-1; j++)
627               { *dest++=0;
628                 n4bit++;
629
630                 if(n4bit>=254)                  /* maximum length 4 bit run */
631                 { dest  = recompress4bit(n4bit, dest);
632                   n4bit = 0;
633                 }
634               }
635             }
636             else
637             { if (n4bit>=MIN4BIT)               /* end (and write) 4 bit run */
638                 dest  = recompress4bit(n4bit, dest);
639
640               n4bit=0;
641               *dest++  = -128; // hexadecimal 0x80
642               *dest++  = (signed char)(i-1);
643             }
644
645             npixels -= (i-2);
646             src     += (i-2);
647             break;
648           }
649         }
650       }
651       else if (val >= -63 && val <= 63)         /* small difference coded as one byte */
652       { if (val >= -8 && val <= 7)
653         { *dest++ = (signed char)val;
654           n4bit++;
655
656           if(n4bit>=254)                        /* maximum length 4 bit run */
657           { dest  = recompress4bit(n4bit, dest);
658             n4bit=0;
659           }
660         }
661         else if(n4bit>=MIN4BIT)                 /* end and write 4 bit run */
662         { j = val;
663           dest  = recompress4bit(n4bit, dest);
664           n4bit=0;
665           *dest++ = (signed char)j;
666         }
667         else
668         { *dest++ = (signed char)val;                   /* end 4 bit run */
669            n4bit  = 0;
670         }
671       }
672       else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
673       { j = val;
674
675         if(n4bit>=MIN4BIT)                      /* end (and write) 4 bit run */
676           dest  = recompress4bit(n4bit, dest);
677
678         n4bit=0;
679         dest[0] = (signed char)((j>>8) ^ 0x40);
680         dest[1] = (signed char)j;
681         dest+=2;
682       }
683       else                                      /* if very large differences code abs val as three bytes */
684       { j = src[0];
685
686         if(n4bit>=MIN4BIT)                      /* end (and write) 4 bit run */
687           dest  = recompress4bit(n4bit, dest);
688
689         n4bit=0;
690         *dest++ = 0x7F;
691         *dest++ = (signed char)(j>>8);
692         *dest++ = (signed char)j;
693       }
694       /* Are we beyond the allocated memory? */
695       if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
696         return 0;
697     }
698     while (--npixels);
699   }
700
701   /* Create the compressed image - compressor with added 4 bit run and CRC */
702
703   else if (iMode == 4)
704   { int n4bit=0;
705     iCRC  = 0;
706
707     *(short int *)dest = val = *src;
708     iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char) val    ] ^ ((iCRC  >> 8));
709     iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char)(val>>8)] ^ ((iCRC  >> 8));
710     dest+=2;
711     npixels--;
712
713     do
714     { val = src[1] - src[0];
715       src++;
716       iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char) src[0]    ] ^ ((iCRC  >> 8));
717       iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char)(src[0]>>8)] ^ ((iCRC  >> 8));
718
719       if (val == 0)                             /* run length-encode zero differences */
720       { for (i=2;; i++)
721         { if (i>=npixels || src[i-1]!=src[-1] || i==256)
722           { if (i<=MINZEROS)                    /* too short run -> write zeros */
723             { for (j=0; j<i-1; j++)
724               { *dest++=0;
725                 n4bit++;
726
727                 if(n4bit>=254)                  /* maximum length 4 bit run */
728                 { dest  = recompress4bit(n4bit, dest);
729                   n4bit = 0;
730                 }
731               }
732             }
733             else
734             { if (n4bit>=MIN4BIT)               /* end (and write) 4 bit run */
735                 dest  = recompress4bit(n4bit, dest);
736
737               n4bit=0;
738               *dest++  = -128; // hexadecimal 0x80
739               *dest++  = (signed char)(i-1);
740             }
741
742             npixels -= (i-2);
743             for (j=0; j<i-2; j++)
744             { src++;
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));
747             }
748             break;
749           }
750         }
751       }
752       else if (val >= -63 && val <= 63)         /* small difference coded as one byte */
753       { if (val >= -8 && val <= 7)
754         { *dest++ = (signed char)val;
755           n4bit++;
756
757           if(n4bit>=254)                        /* maximum length 4 bit run */
758           { dest  = recompress4bit(n4bit, dest);
759             n4bit=0;
760           }
761         }
762         else if(n4bit>=MIN4BIT)                 /* end and write 4 bit run */
763         { j = val;
764           dest  = recompress4bit(n4bit, dest);
765           n4bit=0;
766           *dest++ = (signed char)j;
767         }
768         else
769         { *dest++ = (signed char)val;           /* end 4 bit run */
770            n4bit  = 0;
771         }
772       }
773       else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
774       { j = val;
775
776         if(n4bit>=MIN4BIT)                      /* end (and write) 4 bit run */
777           dest  = recompress4bit(n4bit, dest);
778
779         n4bit=0;
780         dest[0] = (signed char)((j>>8) ^ 0x40);
781         dest[1] = (signed char)j;
782         dest+=2;
783       }
784       else                                      /* if very large differences code abs val as three bytes */
785       { j = src[0];
786
787         if(n4bit>=MIN4BIT)                      /* end (and write) 4 bit run */
788           dest  = recompress4bit(n4bit, dest);
789
790         n4bit=0;
791         *dest++ = 0x7F;
792         *dest++ = (signed char)(j>>8);
793         *dest++ = (signed char)j;
794       }
795       /* Are we beyond the allocated memory? */
796       if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
797         return 0;
798     }
799     while (--npixels);
800
801     if ((dest - (signed char*)pHeader - iHeaderSize)<UINT_MAX) // store 32 bit number as third member
802       pHeader->iCompressedSize = 
803         (unsigned int)(dest - (signed char*)pHeader - iHeaderSize);
804     else                                                       // store 64 bit number in extended structure
805     { pHeader_64bits->iCompressedSize = 0;
806       pHeader_64bits->i64CompressedSize = dest - (signed char*)pHeader -iHeaderSize;
807     }
808
809     /* Pad it to get an even length */
810     if (pHeader->iCompressedSize & 1)
811     { *dest++ = 0;
812       pHeader->iCompressedSize++;
813     }
814
815     pHeader->iOrgCRC        = iCRC;
816     pHeader->iCompressedCRC = 0;
817   }
818
819   return dest - (signed char*)pHeader;
820 }
821
822
823 void clitk::XdrImageIO::WriteImage(const char* file, char* headerinfo, char* headerfile, int raw,
824                                    int offset, char bLittleEndian, int iNkiCompression,
825                                    int wcoords, int append, int getsize, char *tobuffer, const void* data)
826 { AVSINT   total=1;
827   unsigned int      i;
828   AVSINT   coords=0;
829   int      f=0;
830   char     temp[256];
831   char     *c;
832   char     cSwap;
833   FILE     *fp;
834   long     swap_test = 0x1000000;
835   signed char*  pCompressed = NULL;
836   size_t   FilePos=0;
837   char     **buffer = NULL;
838   int      len=0;
839   char     *buf2;
840   size_t   slen;
841
842   if (bLittleEndian)
843     swap_test = 0x00000001;
844
845   if (getsize)
846   { swap_test = 0xffffffff;     // never swap to save time
847     buffer    = (char **) &len;
848     f         = 1;
849   }
850
851   if (tobuffer)
852   { buf2   = (char *)tobuffer;
853     buffer = &buf2;
854     f      = 0;
855   }
856
857   for (i=0; i<GetNumberOfDimensions(); i++)
858   { total  *= GetDimensions(i);
859     coords += GetDimensions(i);
860   }
861
862   /* Try allocate the compressed fielddata - compression disabled if alloc fails */
863   if ((iNkiCompression > 0) &&
864         (GetComponentType() == itk::ImageIOBase::SHORT) &&
865         (GetPixelType() == itk::ImageIOBase::SCALAR))
866   { pCompressed = (signed char *)malloc((total/2) * 3 + sizeof(NKI_MODE2_64BITS) + 10);
867     if (pCompressed==NULL)
868     { iNkiCompression = 0;
869       AVSwarning("Avs_wxdr: not enough memory to compress data, saving uncompressed");
870     }
871   }
872
873   if (!(tobuffer || getsize))
874   { if (offset != -1)
875     { f = open(file, O_RDWR, 0);
876       if (f < 0)
877       {
878         AVSerror("Avs_wxdr: Opening " << file << "failed.\n" << strerror(errno));
879         free(pCompressed);
880         return AVS_ERROR;
881       }
882       lseek(f, offset, SEEK_SET);
883     }
884     else
885     { if (strlen(file)==0)
886         f = fileno(stdout);
887       else
888       { if (append)
889           f = open(file, O_RDWR | O_APPEND, 0);
890         else
891           f = creat(file, S_IWRITE | S_IREAD);
892       }
893
894       if (f < 0)
895       { AVSerror("Avs_wxdr: Creating " << file << " failed.\n" << strerror(errno));
896         free(pCompressed);
897         return AVS_ERROR;
898       }
899     }
900   }
901
902   if (!raw)
903   { sprintf(temp, "# AVS wants to have the first line starting with its name\n");
904     slen = strlen(temp);
905
906     if (!checked_write(f, temp, slen, buffer))
907     { free(pCompressed);
908       return AVS_ERROR;
909     }
910     FilePos += slen;
911
912     slen = strlen(headerinfo);
913     if (slen && !checked_write(f, headerinfo, slen, buffer))
914     { free(pCompressed);
915       return AVS_ERROR;
916     }
917     FilePos += slen;
918
919     if (!checked_write(f, "\n", 1, buffer))
920     { free(pCompressed);
921       return AVS_ERROR;
922     }
923     FilePos++;
924
925     if (strlen(headerfile))
926     { fp = fopen(headerfile, "rt");
927       if (fp)
928       { for (;;)
929         { if (fgets(temp, 255, fp) == NULL) break;
930           slen = strlen(temp);
931           if (!checked_write(f, temp, slen, buffer))
932           { fclose(fp);
933             free(pCompressed);
934             return AVS_ERROR;
935           }
936           FilePos += slen;
937         }
938         fclose(fp);
939         if (!checked_write(f, "\n", 1, buffer))
940         { free(pCompressed);
941           return AVS_ERROR;
942         }
943         FilePos++;
944       }
945     }
946
947     sprintf(temp, "ndim=%d\n", GetNumberOfDimensions());
948     slen = strlen(temp);
949     if (!checked_write(f, temp, slen, buffer))
950     { free(pCompressed);
951       return AVS_ERROR;
952     }
953     FilePos += slen;
954   }
955
956   for (i=0; i<GetNumberOfDimensions(); i++)
957   { if (!raw)
958     { sprintf(temp, "dim%d=%d\n", i+1, GetDimensions(i));
959       slen = strlen(temp);
960       if (!checked_write(f, temp, slen, buffer))
961       { free(pCompressed);
962         return AVS_ERROR;
963       }
964       FilePos += slen;
965     }
966   }
967
968   if (!raw)
969   { sprintf(temp, "nspace=%d\n", GetNumberOfDimensions());
970     slen = strlen(temp);
971     if (!checked_write(f, temp, slen, buffer))
972     { free(pCompressed);
973       return AVS_ERROR;
974     }
975     FilePos += slen;
976
977     sprintf(temp, "veclen=%d\n", GetNumberOfComponents());
978     slen = strlen(temp);
979     if (!checked_write(f, temp, slen, buffer))
980     { free(pCompressed);
981       return AVS_ERROR;
982     }
983     FilePos += slen;
984
985     switch(GetComponentType())
986     { case itk::ImageIOBase::CHAR   : strcpy(temp, "data=byte\n"); break;
987       case itk::ImageIOBase::SHORT  : strcpy(temp, "data=xdr_short\n"); break;
988       case itk::ImageIOBase::INT    : strcpy(temp, "data=xdr_integer\n"); break;
989       case itk::ImageIOBase::FLOAT  : strcpy(temp, "data=xdr_real\n"); break;
990       case itk::ImageIOBase::DOUBLE : strcpy(temp, "data=xdr_double\n"); break;
991       default               : if (f != fileno(stdout)) close(f);
992                               free(pCompressed);
993                               return AVS_ERROR;
994     }
995     slen = strlen(temp);
996     if (!checked_write(f, temp, slen, buffer))
997     { free(pCompressed);
998       return AVS_ERROR;
999     }
1000     FilePos += slen;
1001   }
1002
1003
1004   //FilePos = tell(f);
1005 ONCE_AGAIN:
1006
1007
1008   //switch(input->uniform)
1009   //{ case UNIFORM     : 
1010   strcpy(temp, "field=uniform\n");
1011   coords = GetNumberOfDimensions() * 2;
1012                 //       break;
1013   //  case RECTILINEAR : strcpy(temp, "field=rectilinear\n");
1014                 //       break;
1015   //  case IRREGULAR   : strcpy(temp, "field=irregular\n");
1016                 //       coords = total * input->nspace;
1017                 //       break;
1018   //  default          : if (f != fileno(stdout)) close(f);
1019   //                     free(pCompressed);
1020   //                           return;
1021   //}
1022
1023   if (!raw)
1024   { if (!checked_write(f, temp, strlen(temp), buffer))
1025     { free(pCompressed);
1026       return AVS_ERROR;
1027     }
1028
1029     if ((iNkiCompression > 0) &&
1030       (GetComponentType() == itk::ImageIOBase::SHORT) &&
1031       (GetPixelType() == itk::ImageIOBase::SCALAR))
1032     { sprintf(temp, "nki_compression=%d", iNkiCompression);
1033       if (!checked_write(f, temp, strlen(temp), buffer))
1034       { free(pCompressed);
1035         return AVS_ERROR;
1036       }
1037     }
1038
1039     temp[0] = temp[1] = 12;
1040     if (!checked_write(f, temp, 2, buffer))
1041     { free(pCompressed);
1042       return AVS_ERROR;
1043     }
1044   }
1045
1046   total *= GetPixelSize();
1047
1048   if ((!raw) && (iNkiCompression > 0) &&
1049         (GetComponentType() == itk::ImageIOBase::SHORT) &&
1050         (GetPixelType() == itk::ImageIOBase::SCALAR))
1051   { size_t      iCompressedLength;
1052
1053     iCompressedLength = nki_private_compress(pCompressed,
1054       (short int *)(data), total/2, iNkiCompression);
1055
1056     if (iCompressedLength > 0)
1057     { if (!checked_write(f, pCompressed, iCompressedLength, buffer))
1058       { free(pCompressed);
1059         return AVS_ERROR;
1060       }
1061       free(pCompressed);
1062       goto WRITE_COORDS;
1063     }
1064
1065     /* Compressionratio was poor: let's write uncompressed */
1066     iNkiCompression = 0;
1067     total /= 2;
1068     free(pCompressed);
1069     pCompressed = NULL;
1070     lseek(f, (unsigned int)FilePos, SEEK_SET); // use _lseeki64 just in case header size > UINT_MAX bytes
1071     goto ONCE_AGAIN;
1072   }
1073
1074   /* swap data if required (xdr is low-endian) */
1075
1076   if (!(*(char *)(&swap_test)))
1077   { if (GetComponentSize()==2)
1078     { c = (char *)data;
1079       for (i=0; i<total; i+=2)
1080       { cSwap  = c[i];  c[i]   = c[i+1]; c[i+1] = cSwap;
1081       }
1082     }
1083     else if (GetComponentSize()==4)
1084     { c = (char *)data;
1085       for (i=0; i<total; i+=4)
1086       { cSwap = c[i];   c[i]   = c[i+3]; c[i+3] = cSwap;
1087         cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1088       }
1089     }
1090     else if (GetComponentSize()==8)
1091     { c = (char *)data;
1092       for (i=0; i<total; i+=8)
1093       { cSwap = c[i];   c[i]   = c[i+7]; c[i+7] = cSwap;
1094         cSwap = c[i+1]; c[i+1] = c[i+6]; c[i+6] = cSwap;
1095         cSwap = c[i+2]; c[i+2] = c[i+5]; c[i+5] = cSwap;
1096         cSwap = c[i+3]; c[i+3] = c[i+4]; c[i+4] = cSwap;
1097       }
1098     }
1099   }
1100
1101   if (total)
1102   { if (!checked_write(f, data, total, buffer))
1103       return AVS_ERROR;
1104   }
1105
1106   /* swap data back if was swapped before writing */
1107
1108   if (!(*(char *)(&swap_test)))
1109   { if (GetComponentSize()==2)
1110     { c = (char *)data;
1111       for (i=0; i<total; i+=2)
1112       { cSwap = c[i];   c[i]   = c[i+1]; c[i+1] = cSwap;
1113       }
1114     }
1115     else if (GetComponentSize()==4)
1116     { c = (char *)data;
1117       for (i=0; i<total; i+=4)
1118       { cSwap = c[i];   c[i]   = c[i+3]; c[i+3] = cSwap;
1119         cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1120       }
1121     }
1122     else if (GetComponentSize()==8)
1123     { c = (char *)data;
1124       for (i=0; i<total; i+=8)
1125       { cSwap = c[i];   c[i]   = c[i+7]; c[i+7] = cSwap;
1126         cSwap = c[i+1]; c[i+1] = c[i+6]; c[i+6] = cSwap;
1127         cSwap = c[i+2]; c[i+2] = c[i+5]; c[i+5] = cSwap;
1128         cSwap = c[i+3]; c[i+3] = c[i+4]; c[i+4] = cSwap;
1129       }
1130     }
1131   }
1132
1133 WRITE_COORDS:
1134   float *points;
1135   points = (float *)malloc(sizeof(float)*GetNumberOfDimensions()*2);
1136   for (i=0; i<GetNumberOfDimensions(); i++)
1137   {
1138     points[i*2  ] = 0.1 *  GetOrigin(i);
1139     points[i*2+1] = 0.1 * (GetOrigin(i) + GetSpacing(i)*(GetDimensions(i)-1));
1140   }
1141
1142   if (coords && !raw)                           /* write AVS coordinates ? */
1143   { coords *= sizeof(float);
1144     if (!(*(char *)(&swap_test)))
1145     { c = (char *)(points);              /* swap bytes */
1146       for (i=0; i<coords; i+=4)
1147       { cSwap = c[i];   c[i]   = c[i+3]; c[i+3] = cSwap;
1148         cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1149       }
1150     }
1151
1152     if (!checked_write(f, points, coords, buffer))
1153       return AVS_ERROR;
1154
1155     if (!(*(char *)(&swap_test)))
1156     { c = (char *)(points);              /* swap bytes back */
1157       for (i=0; i<coords; i+=4)
1158       { cSwap = c[i];   c[i]   = c[i+3]; c[i+3] = cSwap;
1159         cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1160       }
1161     }
1162   }
1163
1164   if (!(tobuffer || getsize))
1165     if (f != fileno(stdout)) close(f);
1166
1167   if (getsize) return;
1168   return AVS_OK;
1169 }