2 * @file clitkXdrImageIO.cxx
3 * @author Simon Rit <simon.rit@gmail.com>
4 * @date Sun Jun 1 22:12:20 2008
11 #include "clitkXdrImageIO.h"
12 #include "clitkCommon.h"
18 //#define _read readfix
20 #define AVSINT ptrdiff_t
27 #define setmode(a,b) 0
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. */
38 # define Q_INT64_FORMAT "I64"
40 # define Q_INT64_FORMAT "L"
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! */
48 # define Q_INT64_FORMAT "I64"
50 # define Q_INT64_FORMAT "L"
53 # error No 64 bit integers known for this compiler, edit portdefs.h.
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;
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);
69 /************************************************************************/
71 /* file : AVS_WXDR.C */
73 /* purpose : AVS module for writing XDR and RAW files */
75 /* author : Lambert Zijp (based on a true story by */
76 /* Marcel van Herk) */
80 /* portability: AVS requires sizeof(void *)==sizeof(int) */
81 /* This module assumes sizeof(int)>=4 */
83 /* notes : This module has been integrated in QUIRT */
85 /************************************************************************/
88 19980212 ljz Creation (i.e. Removed from 'mbfield4.c')
89 19980304 ljz Added QUIRT_NEXT_PARAMETER_FILE
90 19980310 ljz Fix: XDRs were written in text-mode when
91 quirt_init() is not called
92 19980319 ljz Undone last change: _fmode is set in DllEntryPoint
93 19980408 tp Moved M$-specific includes;
94 removed AVS portability anyway
95 19980611 mvh Added offset to write_raw (write into file)
96 20000214 lsp Check file handle returned by open before use
97 20000313 nd Two AVSerror messages added.
98 20000322 lsp Matched compute func declaration with desc func
99 20000630 ljz Added WRITE_RAW_LE, to write little-endian pixel-data
100 20000806 lsp Compute func now 'int', conformal to ANSI C++
101 20000821 ljz Added NkiCompression parameter to WRITE_XDR. If used,
102 mode 2 is recommended.
103 20000504 mvh Added write coordinates in header option to WRITE_XDR
104 20010720 mvh Added option to write to stdout: pass "" as filename
105 20010723 mvh Made it working by redefining write; setmode does not work
106 20010725 bb Changed include order of windows.h and mbavs2q.h
108 20020124 mvh+kg The datatype in the header is now e.g. "xdr_integer"
109 The datatypes as "integer" were intended as having native
110 byte order, while we wrote bigendian (high byte first). Our
111 older files read therefore OK on HP and SUN but not on linux.
112 20020124 mvh+kg On AVS5 xdr_byte is illegal. Replace only that one by 'byte'
113 20030311 bb Added check on write errors. Disc full errors during a
114 write have nasty side-effects for other programs' open files.
115 Added check on file handle to prevent closing of stdout.
116 20030430 mvh Added append mode for WRITE_XDR
117 20030717 ljz Added support for NkiCompressionModes 3 and 4 (4 is recommended)
118 20040426 mvh ELEKTA NKI-XVI0.1 RELEASE
119 20040910 mvh Write uncompressed and warn if the compress malloc fails, layout
120 20040920 mvh Fixed the above option (failed in append mode)
121 20040924 mvh Fixed warn in option
122 20041117 mvh ELEKTA NKI-XVI0.1g RELEASE
123 20050302 ljz Merant tracker ID #1867: Check on bad compression-ratio causing
125 20050308 ljz+mvh ELEKTA NKI-XVI0.1j RELEASE
126 20050411 mvh Fails on I178_s1_4H.3d mode 1: compression fails and written file corrupted
127 20060903 mvh Added WRITE_MEM_XDR and QUERY_MEM_XDR
128 20070330 mvh WRITE_XDR failed on G:\20605104_hypo lung\20605104_incl corr+doseab3.PACK
129 20071015 mvh ELEKTA NKI-XVI3.08 RELEASE
130 20080411 lsp+mw NULL->0 in WriteImage() ; __sun__ doesn't know <io.h>
131 20080825 mgw Corrected slash in sys/stat.h include
132 20081031 lsp+mvh ELEKTA NKI-XVI4.15 RELEASE
133 20081119 lsp+sr Removed tell(f) call for Linux
134 20081203 lsp __sun__ -> unix
135 20090114 mvh ELEKTA NKI-XVI4.22 RELEASE
136 20090529 lsp+sr Work around the 64 MB limitation of write() in Windows
137 20090802 mvh ELEKTA NKI-XVI4.29 RELEASE
138 20091209 lsp Added WRITE_MEM_RAW
139 20091214 lsp 64 bits adaptations: pass high address of buffer as well,
140 replaced int by AVSINT when requested, process buffer in chunks
141 to be able to interpret return value of write() (signed int) correctly,
142 replaced out-of-range constants 0xc0 and 0x80 by their signed equivalents
143 20091216 lsp+ljz Prepared compression for more than 4294967295 (UINT_MAX) shorts
144 by using bigger NKI_MODE2_64BITS struct (backwards compatible)
145 20091216 lsp Disabled #define write for clarity: checked_write() is used throughout
146 Use more space for pCompressed to be able to call WRITE_XDR with compression
147 on small fields (<10 pixels for mode 2 or 4, <2 pixels for mode 1 and 3)
150 /************************************************************************/
151 /* MODULE DOCUMENTATION */
152 /************************************************************************/
154 AVS Modules Lambert Zijp XDR writer & RAW writer
157 XDR writer - Module for writing XDR and RAW files
162 Availability : specify in which module libraries
164 Source AVS_WXDR (C++ interface)
168 QUIRT name WRITE_XDR & WRITE_RAW
170 Inputs Input field = field
174 Parameters Name Type Default Min Max
176 Header info string (WRITE_XDR only!)
177 Header file string (WRITE_XDR only!)
178 File Offset integer (WRITE_RAW only!)
179 NKI compression integer (WRITE_XDR only!)
180 Coords in header boolean (WRITE_XDR only!)
181 Append boolean (WRITE_XDR only!)
184 WRITE_RAW: No header, no coordinates.
185 Data only are written (high byte first); optionally into an
186 existing file (if you specify an offset)
188 WRITE_RAW_LE: No header, no coordinates.
189 Data only are written (low byte first);
190 optionally into an existing file (if you specify an offset)
192 WRITE_XDR: Successively is written to file:
193 - The string '#AVS wants ...'.
194 - The optional Header info
195 - The contents of the optional Header file
196 - An ascii description of the Input field
197 - Optionally the coordinates (coord%axis%[%pixel%]=%coord%)
198 (%axis% is 1 based, %pixel% 0 based, %coord% is float)
199 - Two bytes containing ascii character 0x0c
200 - The Data in binary (high byte first).
201 Or, if NKI_Compression is greater than zero, compressed data.
202 - The Coordinates in binary IEEE float (high byte first)
205 Input field (Required; field)
206 Describe input here....
210 A string described here....
213 A string described here....
216 A string described here....
219 An integer (default -1). If set, WRITE_RAW writes the data
220 into an existing file.
223 An integer described here....
225 Write coordinates in header
226 A boolean described here....
229 A boolean described here....
238 (optional): in which AVS libraries available
242 (optional): further specify type of Render / Output module
245 (optional): which type of files are read|written
248 The following network shows how .....
258 (optional): describe limitations here
261 Modules that can provide input:
263 Modules that could be used in place of XDR writer:
265 Modules that can take output:
269 (optional): The following files
270 {are needed for|are output from|give examples of|further document}
276 WRITE_XDR AVS module XDR writer
277 numerical_expression Input field = field
278 string_expression name of xdr file to create
279 string_expression extra header info (default "")
280 string_expression text file with more header info (default none)
281 numerical_expression NKI compression (default 0)
282 numerical_expression Coordinates in header (boolean, default 0)
283 numerical_expression Append to file (boolean, default 0)
285 WRITE_RAW AVS module Raw writer
286 numerical_expression Input field = field
287 string_expression name of file to write
288 numerical_expression Offset; if not -1 (default) writes into file at offset
290 WRITE_RAW_LE AVS module Raw writer little endian
291 numerical_expression Input field = field
292 string_expression name of file to write
293 numerical_expression Offset; if not -1 (default) writes into file at offset
296 numerical_expression Input field = field
297 numerical_expression point to buffer to write xdr data into (use QUERY_MEM_XDR to find length)
298 string_expression extra header info (default "")
299 string_expression text file with more header info (default none)
300 numerical_expression NKI compression (default 0)
301 numerical_expression Coordinates in header (boolean, default 0)
304 numerical_expression Input field = field
305 name recieves required length for data
306 string_expression extra header info (default "")
307 string_expression text file with more header info (default none)
308 numerical_expression NKI compression (default 0)
309 numerical_expression Coordinates in header (boolean, default 0)
311 Release 1.0 19980212 Lambert Zijp XDR writer & RAW writer
313 /************************************************************************/
315 /************************************************************************/
331 // don't use min() and max() macros indirectly defined by windows.h,
332 // but use portable std::min() and std:max() instead
339 /************************************************************************/
340 /* DEFINES, ENUMERATED TYPES AND CONSTANTS */
341 /************************************************************************/
345 // Fields with data size>8GB (having UINT_MAX short pixels) cannot be compressed using
346 // NKI_MODE2 struct because iOrgSize has type "unsigned int". In that case use NKI_MODE2_64BITS.
347 // The type of structure is indicated as follows:
349 // iOrgSize==0: NKI_MODE2_64BITS
350 // otherwise : NKI_MODE2
352 // Compression modes 1 and 3 (without CRCs) only use the first 2 members (iOrgSize and iMode).
356 unsigned int iOrgSize; /* in pixels (i.e. shorts) */
357 unsigned int iMode; /* 1, 2, 3 or 4 */
358 unsigned int iCompressedSize; /* in bytes, excluding header */
359 unsigned int iOrgCRC; /* CRC of the data (no coords etc) */
360 unsigned int iCompressedCRC; /* CRC of the compressed data, excluding this header */
365 unsigned int iOrgSize; /* in pixels (i.e. shorts) */
366 unsigned int iMode; /* 1, 2, 3 or 4 */
367 unsigned int iCompressedSize; /* in bytes, excluding header */
368 unsigned int iOrgCRC; /* CRC of the data (no coords etc) */
369 unsigned int iCompressedCRC; /* CRC of the compressed data, excluding this header */
370 unsigned int iPad; /* unused */
371 Q_UINT64 i64OrgSize; /* used for more than UINT_MAX pixels, indicated by iOrgSize==0 (0-vector not compressed) */
372 Q_UINT64 i64CompressedSize; /* value in BYTES, used for more than UINT_MAX PIXELS, indicated by iCompressedSize==0 */
379 // Changed next to static function in stead of macro so it can
380 // have a return value to check in the calling function.
381 // It could be made inline as well, but there is no real time
382 // punishment from the extra layer of function calls.
384 // note: some compilers do not like comments ending in a backslash.
385 // so use macro functions to exclude.
388 /************************************************************************/
389 /* GLOBAL VARIABLES */
390 /************************************************************************/
392 static const unsigned long CRC32_table[256] = {
393 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
394 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
395 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
396 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
397 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
398 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
399 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
400 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
401 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
402 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
403 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
404 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
405 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
406 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
407 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
408 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
409 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
410 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
411 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
412 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
413 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
414 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
415 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
416 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
417 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
418 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
419 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
420 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
421 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
422 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
423 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
424 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
425 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
426 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
427 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
428 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
429 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
430 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
431 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
432 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
433 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
434 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
435 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
438 /************************************************************************/
439 /* MODULE FUNCTIONS */
440 /************************************************************************/
445 int writefix(int file, const void *buf, unsigned int count)
448 for (unsigned i=0; i<count; i+=16384)
450 if (j>16384) j=16384;
452 k=write(file, (char *)buf+i, j);
465 Version of write() that takes special action in case of
466 standard output. Based on commented out macro above.
467 This function overloads the <cstdio> (or stdio.h for old style C++)
471 // Like the original macro, we do /not/ want writefix from mbfield.c.
475 static int wxdr_write(int handle, const void * buf, unsigned len)
477 // if (handle == 1) // stdout
478 if (handle == fileno(stdout))
481 // Behave as C standard library write(): return number of bytes
482 // written or -1 and errno set on error.
484 DWORD dwBytesWritten;
485 if (!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, len,
486 &dwBytesWritten, NULL))
488 // There is no simple 1-to-1 mapping between GetLastError()
489 // values that WriteFile() can return (quite a lot) and the two
490 // errno values that write() can return. So return EACCES in
492 switch (GetLastError())
493 { case ERROR_INVALID_HANDLE:
494 errno = EBADF ; break;
496 errno = EACCES; break;
501 return (int)dwBytesWritten; // May still be < len!
502 // And... write() may write a maximum of UINT_MAX-1 bytes, whereas
503 // WriteFile() may write UINT_MAX bytes at once. But since
504 // int(UINT_MAX) == -1 this will pose an actual problem in the
507 //const int oldmode = setmode(handle, O_BINARY);//commented out by joel
508 const int iBytesWritten = write(handle, buf, len);
509 const int saveerrno = errno; // setmode() may change errno.
510 //if (oldmode != -1) setmode(handle, oldmode); //commented out by joel
512 return iBytesWritten;
516 return write(handle, buf, len);
521 Behaves like win32 WriteFile() and returns a Boolean to indicate
522 success or failure, where failure almost invariably means disc full.
526 In case of failure, this function issues an AVS error message
527 and closes the file (if handle != 1). It is up to the calling
528 function to return the AVS_ERROR state and before that do things
529 like close other files, free memory etc. This way, there is less
530 chance of erroneously duplicated code, like in:
531 written = write(f, temp, strlen(temp));
532 if (written == -1 || written != strlen(temp))
534 if (f != fileno(stdout)) close(f);
537 written = write(f, buf, buflength)
538 if (written == -1 || written != strlen(temp)) {
539 // oops, wrong length copy'n'pasted
541 If more elaborate error handling is needed then the calling
542 functuon should use the (overloaded) write() and act on its return
543 value (and the value of errno) accordingly.
545 It does /not/ close stdout.
549 Note that checked_write() takes a size_t for len, whereas write() takes
550 an unsigned int of 4 bytes. On a 64 bits OS a size_t will be an 8 byte integer,
551 enabling more than UINT_MAX bytes to write at once.
553 static bool checked_write(int handle, const void * buf, size_t len, char **buffer)
554 { if (buffer && !handle)
555 { memcpy(*buffer, buf, len);
559 if (buffer && handle)
564 { for(int i=0; i<2; i++)
569 //If write fails, test if not related to big buffer problem
570 //Bug report http://support.microsoft.com/kb/899149 entitled
571 //"You cannot call the fwrite function to write to a buffer
572 // that is larger than 64 MB in Visual C++ 2005,
573 // in Visual C++ .NET 2003, or in Visual C++ .NET 2002"
574 // NB: same thing for write function in binary mode
577 // call wxdr_write (for handle!=fileno(stdout) a wrapper for write) several times
578 // to interpret the signed 32-bit return value correctly
580 { chunksize = (int)std::min(remaining, (size_t)INT_MAX);
581 byteswritten = wxdr_write(handle, buf, chunksize);
582 if (byteswritten == chunksize)
583 remaining -= chunksize;
585 break; // try writefix in the next round
592 // call writefix (in mbfield.c) several times to interpret the signed 32-bit
593 // return value correctly. writefix uses chunks of 16384 bytes
595 { chunksize = (int)std::min(remaining, (size_t)INT_MAX);
596 byteswritten = writefix(handle, buf, chunksize);
597 if (byteswritten == chunksize)
598 remaining -= chunksize;
600 break; // even writefix failed: return error
606 // Note: file is open in binary mode, no need to compensate
607 // for a value of byteswritten > len due to \n -> \r\n conversions.
608 // (write() on a text stream is implementation dependent.)
609 if (handle != fileno(stdout)) close(handle);
610 AVSerror("Avs_wxdr: write failed, disk full?");
615 /* coder for NKI private compressed pixel data
616 arguments: dest = (in) points to area where compressed destination data is written (byte)
617 src = (in) points to uncompressed source data (short)
618 npixels = (in) number of pixels to compress
620 The return value is the number of bytes in the compressed data (maximal 3*npixels+10, typical 0.52*npixels)
623 - The first 4 bytes contain the number of short-int pixels
624 - The following 4 bytes contain iMode=1
625 - The rest is the compressed image
628 - The first 4 bytes contain the number of short-int pixels
629 - The following 4 bytes contain iMode=2
630 - The following 4 bytes contain the size of the compressed image (in bytes)
631 - The following 4 bytes contain the CRC of the original image
632 - The following 4 bytes contain the CRC of the compressed image
633 - The rest is the compressed image
634 - The compressed size will be even (padded by a zero if necessary).
637 - The first 4 bytes contain the number of short-int pixels
638 - The following 4 bytes contain iMode=3
639 - The rest is the compressed image, including 4 bit differences
642 - The first 4 bytes contain the number of short-int pixels
643 - The following 4 bytes contain iMode=4
644 - The following 4 bytes contain the size of the compressed image (in bytes)
645 - The following 4 bytes contain the CRC of the original image
646 - The following 4 bytes contain 0
647 - The rest is the compressed image, including 4 bit differences
648 - The compressed size will be even (padded by a zero if necessary).
650 iMode 1 and iMode 2 are identical, except for the CRC data that is included for iMode 2
651 iMode 3 and iMode 4 are identical, except for the CRC data that is included for iMode 4
654 // optimized settings for the 4 bit run compressor (mode 3 and 4)
656 #define MINZEROS 5 // shortest RLE (2 byte overhead, but breaks 4bit run)
657 #define MIN4BIT 6 // shortest 4 bit run (6 bytes compressed to 5 bytes)
659 // This internal routine converts an 8 bit difference string into a 4 bit one
660 static signed char *recompress4bit(int n, signed char *dest)
661 { signed char *p, *q;
667 val = (((int)p[0])<<4) | (p[1]&15);
669 *dest++ = -0x40; // 192 (0xc0) does not fit between -128..127: maps to -64 (0x40) in 2's complement
670 *dest++ = (signed char)n;
674 { *dest++ = (signed char)((((int)p[0])<<4) | (p[1]&15));
678 q[0] = (signed char)val;
684 static size_t nki_private_compress(signed char *dest, short int *src, size_t npixels, int iMode)
685 { unsigned long iCRC;
687 unsigned int iHeaderSize=8; // value for iMode==1 and iMode==3
690 NKI_MODE2* pHeader = (NKI_MODE2*)dest;
691 NKI_MODE2_64BITS* pHeader_64bits = (NKI_MODE2_64BITS*)dest;
694 iBufferSize = (npixels / 2) * 3; // Buffer is sizeof(NKI_MODE2_64BITS) + 10 bytes larger
696 /* Up till now only Mode=1 .. 4 are supported */
697 if ((iMode < 1) || (iMode > 4))
700 /* Create the header */
701 pHeader->iMode = iMode;
703 if (sizeof(int*)>sizeof(int) && npixels>UINT_MAX) // On a 64 bits OS we want to store files>4GB
704 { pHeader_64bits->iOrgSize = 0; // This indicates>4GB file (0-vector is not compressed)
705 pHeader_64bits->i64OrgSize = npixels;
706 iHeaderSize = sizeof(NKI_MODE2_64BITS);
707 dest += sizeof(NKI_MODE2_64BITS);
710 { pHeader->iOrgSize = (unsigned int)(npixels & UINT_MAX); // store 32 bit number as first member
712 if (iMode==2 || iMode==4)
713 iHeaderSize = sizeof(NKI_MODE2);
717 /* Create the compressed image */
720 { *(short int *)dest = *src;
726 { val = src[1] - src[0];
729 if (val == 0) /* run length-encode zero differences */
731 { if (i>=npixels || src[i-1]!=src[-1] || i==256)
735 { *dest++ = -128; // hexadecimal 0x80
736 *dest++ = (signed char)(i-1);
744 else if (val >= -64 && val <= 63) /* small difference coded as one byte */
745 { *dest = (signed char)val;
748 else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
749 { dest[0] = (signed char)((val>>8) ^ 0x40);
750 dest[1] = (signed char)val;
753 else /* if very large differences code abs val as three bytes */
755 *dest++ = (signed char)(src[0]>>8);
756 *dest++ = (signed char)(src[0]);
758 /* Are we beyond the allocated memory? */
759 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
769 *(short int *)dest = val = *src;
770 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char) val ] ^ ((iCRC2 >> 8));
771 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
772 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) val ] ^ ((iCRC >> 8));
773 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(val>>8)] ^ ((iCRC >> 8));
778 { val = src[1] - src[0];
780 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
781 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
783 if (val == 0) /* run length-encode zero differences */
785 { if (i>=npixels || src[i-1]!=src[-1] || i==256)
788 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0 ] ^ ((iCRC2 >> 8));
791 { *dest++ = -128; // hexadecimal 0x80
792 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0x80 ] ^ ((iCRC2 >> 8));
793 *dest++ = (signed char)(i-1);
794 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (i-1)] ^ ((iCRC2 >> 8));
797 for (j=0; j<i-2; j++)
799 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
800 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
807 else if (val >= -64 && val <= 63) /* small difference coded as one byte */
808 { *dest = (signed char)val;
809 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val ] ^ ((iCRC2 >> 8));
812 else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
813 { dest[0] = (signed char)((val>>8) ^ 0x40);
814 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)dest[0] ] ^ ((iCRC2 >> 8));
815 dest[1] = (signed char)val;
816 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val ] ^ ((iCRC2 >> 8));
819 else /* if very large differences code abs val as three bytes */
821 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0x7f ] ^ ((iCRC2 >> 8));
823 dest[1] = (signed char)(val>>8);
824 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
825 dest[2] = (signed char)val;
826 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val ] ^ ((iCRC2 >> 8));
829 /* Are we beyond the allocated memory? */
830 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
835 if ((dest - (signed char*)pHeader - iHeaderSize)<UINT_MAX) // store 32 bit number as third member
836 pHeader->iCompressedSize =
837 (unsigned int)(dest - (signed char*)pHeader - iHeaderSize);
838 else // store 64 bit number in extended structure
839 pHeader_64bits->i64CompressedSize = dest - (signed char*)pHeader -iHeaderSize;
841 /* Pad it to get an even length */
842 if (pHeader->iCompressedSize & 1)
844 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0] ^ ((iCRC2 >> 8));
845 pHeader->iCompressedSize++;
848 pHeader->iOrgCRC = iCRC;
849 pHeader->iCompressedCRC = iCRC2;
852 /* Create the compressed image - compressor with added 4 bit run */
856 *(short int *)dest = *src;
861 { val = src[1] - src[0];
864 if (val == 0) /* run length-encode zero differences */
866 { if (i>=npixels || src[i-1]!=src[-1] || i==256)
867 { if (i<=MINZEROS) /* too short run -> write zeros */
868 { for (j=0; j<i-1; j++)
872 if(n4bit>=254) /* maximum length 4 bit run */
873 { dest = recompress4bit(n4bit, dest);
879 { if (n4bit>=MIN4BIT) /* end (and write) 4 bit run */
880 dest = recompress4bit(n4bit, dest);
883 *dest++ = -128; // hexadecimal 0x80
884 *dest++ = (signed char)(i-1);
893 else if (val >= -63 && val <= 63) /* small difference coded as one byte */
894 { if (val >= -8 && val <= 7)
895 { *dest++ = (signed char)val;
898 if(n4bit>=254) /* maximum length 4 bit run */
899 { dest = recompress4bit(n4bit, dest);
903 else if(n4bit>=MIN4BIT) /* end and write 4 bit run */
905 dest = recompress4bit(n4bit, dest);
907 *dest++ = (signed char)j;
910 { *dest++ = (signed char)val; /* end 4 bit run */
914 else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
917 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
918 dest = recompress4bit(n4bit, dest);
921 dest[0] = (signed char)((j>>8) ^ 0x40);
922 dest[1] = (signed char)j;
925 else /* if very large differences code abs val as three bytes */
928 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
929 dest = recompress4bit(n4bit, dest);
933 *dest++ = (signed char)(j>>8);
934 *dest++ = (signed char)j;
936 /* Are we beyond the allocated memory? */
937 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
943 /* Create the compressed image - compressor with added 4 bit run and CRC */
949 *(short int *)dest = val = *src;
950 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) val ] ^ ((iCRC >> 8));
951 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(val>>8)] ^ ((iCRC >> 8));
956 { val = src[1] - src[0];
958 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
959 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
961 if (val == 0) /* run length-encode zero differences */
963 { if (i>=npixels || src[i-1]!=src[-1] || i==256)
964 { if (i<=MINZEROS) /* too short run -> write zeros */
965 { for (j=0; j<i-1; j++)
969 if(n4bit>=254) /* maximum length 4 bit run */
970 { dest = recompress4bit(n4bit, dest);
976 { if (n4bit>=MIN4BIT) /* end (and write) 4 bit run */
977 dest = recompress4bit(n4bit, dest);
980 *dest++ = -128; // hexadecimal 0x80
981 *dest++ = (signed char)(i-1);
985 for (j=0; j<i-2; j++)
987 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
988 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
994 else if (val >= -63 && val <= 63) /* small difference coded as one byte */
995 { if (val >= -8 && val <= 7)
996 { *dest++ = (signed char)val;
999 if(n4bit>=254) /* maximum length 4 bit run */
1000 { dest = recompress4bit(n4bit, dest);
1004 else if(n4bit>=MIN4BIT) /* end and write 4 bit run */
1006 dest = recompress4bit(n4bit, dest);
1008 *dest++ = (signed char)j;
1011 { *dest++ = (signed char)val; /* end 4 bit run */
1015 else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
1018 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
1019 dest = recompress4bit(n4bit, dest);
1022 dest[0] = (signed char)((j>>8) ^ 0x40);
1023 dest[1] = (signed char)j;
1026 else /* if very large differences code abs val as three bytes */
1029 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
1030 dest = recompress4bit(n4bit, dest);
1034 *dest++ = (signed char)(j>>8);
1035 *dest++ = (signed char)j;
1037 /* Are we beyond the allocated memory? */
1038 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
1043 if ((dest - (signed char*)pHeader - iHeaderSize)<UINT_MAX) // store 32 bit number as third member
1044 pHeader->iCompressedSize =
1045 (unsigned int)(dest - (signed char*)pHeader - iHeaderSize);
1046 else // store 64 bit number in extended structure
1047 { pHeader_64bits->iCompressedSize = 0;
1048 pHeader_64bits->i64CompressedSize = dest - (signed char*)pHeader -iHeaderSize;
1051 /* Pad it to get an even length */
1052 if (pHeader->iCompressedSize & 1)
1054 pHeader->iCompressedSize++;
1057 pHeader->iOrgCRC = iCRC;
1058 pHeader->iCompressedCRC = 0;
1061 return dest - (signed char*)pHeader;
1065 void clitk::XdrImageIO::WriteImage(const char* file, char* headerinfo, char* headerfile, int raw,
1066 int offset, char bLittleEndian, int iNkiCompression,
1067 int wcoords, int append, int getsize, char *tobuffer, const void* data)
1076 long swap_test = 0x1000000;
1077 signed char* pCompressed = NULL;
1079 char **buffer = NULL;
1085 swap_test = 0x00000001;
1088 { swap_test = 0xffffffff; // never swap to save time
1089 buffer = (char **) &len;
1094 { buf2 = (char *)tobuffer;
1099 for (i=0; i<GetNumberOfDimensions(); i++)
1100 { total *= GetDimensions(i);
1101 coords += GetDimensions(i);
1104 /* Try allocate the compressed fielddata - compression disabled if alloc fails */
1105 if ((iNkiCompression > 0) &&
1106 (GetComponentType() == itk::ImageIOBase::SHORT) &&
1107 (GetPixelType() == itk::ImageIOBase::SCALAR))
1108 { pCompressed = (signed char *)malloc((total/2) * 3 + sizeof(NKI_MODE2_64BITS) + 10);
1109 if (pCompressed==NULL)
1110 { iNkiCompression = 0;
1111 AVSwarning("Avs_wxdr: not enough memory to compress data, saving uncompressed");
1115 if (!(tobuffer || getsize))
1117 { f = open(file, O_RDWR, 0);
1120 AVSerror("Avs_wxdr: Opening " << file << "failed.\n" << strerror(errno));
1124 lseek(f, offset, SEEK_SET);
1127 { if (strlen(file)==0)
1131 f = open(file, O_RDWR | O_APPEND, 0);
1133 f = creat(file, S_IWRITE | S_IREAD);
1137 { AVSerror("Avs_wxdr: Creating " << file << " failed.\n" << strerror(errno));
1145 { sprintf(temp, "# AVS wants to have the first line starting with its name\n");
1146 slen = strlen(temp);
1148 if (!checked_write(f, temp, slen, buffer))
1149 { free(pCompressed);
1154 slen = strlen(headerinfo);
1155 if (slen && !checked_write(f, headerinfo, slen, buffer))
1156 { free(pCompressed);
1161 if (!checked_write(f, "\n", 1, buffer))
1162 { free(pCompressed);
1167 if (strlen(headerfile))
1168 { fp = fopen(headerfile, "rt");
1171 { if (fgets(temp, 255, fp) == NULL) break;
1172 slen = strlen(temp);
1173 if (!checked_write(f, temp, slen, buffer))
1181 if (!checked_write(f, "\n", 1, buffer))
1182 { free(pCompressed);
1189 sprintf(temp, "ndim=%d\n", GetNumberOfDimensions());
1190 slen = strlen(temp);
1191 if (!checked_write(f, temp, slen, buffer))
1192 { free(pCompressed);
1198 for (i=0; i<GetNumberOfDimensions(); i++)
1200 { sprintf(temp, "dim%d=%d\n", i+1, GetDimensions(i));
1201 slen = strlen(temp);
1202 if (!checked_write(f, temp, slen, buffer))
1203 { free(pCompressed);
1211 { sprintf(temp, "nspace=%d\n", GetNumberOfDimensions());
1212 slen = strlen(temp);
1213 if (!checked_write(f, temp, slen, buffer))
1214 { free(pCompressed);
1219 sprintf(temp, "veclen=%d\n", GetNumberOfComponents());
1220 slen = strlen(temp);
1221 if (!checked_write(f, temp, slen, buffer))
1222 { free(pCompressed);
1227 switch(GetComponentType())
1228 { case itk::ImageIOBase::CHAR : strcpy(temp, "data=byte\n"); break;
1229 case itk::ImageIOBase::SHORT : strcpy(temp, "data=xdr_short\n"); break;
1230 case itk::ImageIOBase::INT : strcpy(temp, "data=xdr_integer\n"); break;
1231 case itk::ImageIOBase::FLOAT : strcpy(temp, "data=xdr_real\n"); break;
1232 case itk::ImageIOBase::DOUBLE : strcpy(temp, "data=xdr_double\n"); break;
1233 default : if (f != fileno(stdout)) close(f);
1237 slen = strlen(temp);
1238 if (!checked_write(f, temp, slen, buffer))
1239 { free(pCompressed);
1246 //FilePos = tell(f);
1250 //switch(input->uniform)
1252 strcpy(temp, "field=uniform\n");
1253 coords = GetNumberOfDimensions() * 2;
1255 // case RECTILINEAR : strcpy(temp, "field=rectilinear\n");
1257 // case IRREGULAR : strcpy(temp, "field=irregular\n");
1258 // coords = total * input->nspace;
1260 // default : if (f != fileno(stdout)) close(f);
1261 // free(pCompressed);
1266 { if (!checked_write(f, temp, strlen(temp), buffer))
1267 { free(pCompressed);
1271 if ((iNkiCompression > 0) &&
1272 (GetComponentType() == itk::ImageIOBase::SHORT) &&
1273 (GetPixelType() == itk::ImageIOBase::SCALAR))
1274 { sprintf(temp, "nki_compression=%d", iNkiCompression);
1275 if (!checked_write(f, temp, strlen(temp), buffer))
1276 { free(pCompressed);
1281 temp[0] = temp[1] = 12;
1282 if (!checked_write(f, temp, 2, buffer))
1283 { free(pCompressed);
1288 total *= GetPixelSize();
1290 if ((!raw) && (iNkiCompression > 0) &&
1291 (GetComponentType() == itk::ImageIOBase::SHORT) &&
1292 (GetPixelType() == itk::ImageIOBase::SCALAR))
1293 { size_t iCompressedLength;
1295 iCompressedLength = nki_private_compress(pCompressed,
1296 (short int *)(data), total/2, iNkiCompression);
1298 if (iCompressedLength > 0)
1299 { if (!checked_write(f, pCompressed, iCompressedLength, buffer))
1300 { free(pCompressed);
1307 /* Compressionratio was poor: let's write uncompressed */
1308 iNkiCompression = 0;
1312 lseek(f, (unsigned int)FilePos, SEEK_SET); // use _lseeki64 just in case header size > UINT_MAX bytes
1316 /* swap data if required (xdr is low-endian) */
1318 if (!(*(char *)(&swap_test)))
1319 { if (GetComponentSize()==2)
1321 for (i=0; i<total; i+=2)
1322 { cSwap = c[i]; c[i] = c[i+1]; c[i+1] = cSwap;
1325 else if (GetComponentSize()==4)
1327 for (i=0; i<total; i+=4)
1328 { cSwap = c[i]; c[i] = c[i+3]; c[i+3] = cSwap;
1329 cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1332 else if (GetComponentSize()==8)
1334 for (i=0; i<total; i+=8)
1335 { cSwap = c[i]; c[i] = c[i+7]; c[i+7] = cSwap;
1336 cSwap = c[i+1]; c[i+1] = c[i+6]; c[i+6] = cSwap;
1337 cSwap = c[i+2]; c[i+2] = c[i+5]; c[i+5] = cSwap;
1338 cSwap = c[i+3]; c[i+3] = c[i+4]; c[i+4] = cSwap;
1344 { if (!checked_write(f, data, total, buffer))
1348 /* swap data back if was swapped before writing */
1350 if (!(*(char *)(&swap_test)))
1351 { if (GetComponentSize()==2)
1353 for (i=0; i<total; i+=2)
1354 { cSwap = c[i]; c[i] = c[i+1]; c[i+1] = cSwap;
1357 else if (GetComponentSize()==4)
1359 for (i=0; i<total; i+=4)
1360 { cSwap = c[i]; c[i] = c[i+3]; c[i+3] = cSwap;
1361 cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1364 else if (GetComponentSize()==8)
1366 for (i=0; i<total; i+=8)
1367 { cSwap = c[i]; c[i] = c[i+7]; c[i+7] = cSwap;
1368 cSwap = c[i+1]; c[i+1] = c[i+6]; c[i+6] = cSwap;
1369 cSwap = c[i+2]; c[i+2] = c[i+5]; c[i+5] = cSwap;
1370 cSwap = c[i+3]; c[i+3] = c[i+4]; c[i+4] = cSwap;
1377 points = (float *)malloc(sizeof(float)*GetNumberOfDimensions()*2);
1378 for (i=0; i<GetNumberOfDimensions(); i++)
1380 points[i*2 ] = 0.1 * GetOrigin(i);
1381 points[i*2+1] = 0.1 * (GetOrigin(i) + GetSpacing(i)*(GetDimensions(i)-1));
1384 if (coords && !raw) /* write AVS coordinates ? */
1385 { coords *= sizeof(float);
1386 if (!(*(char *)(&swap_test)))
1387 { c = (char *)(points); /* swap bytes */
1388 for (i=0; i<coords; i+=4)
1389 { cSwap = c[i]; c[i] = c[i+3]; c[i+3] = cSwap;
1390 cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1394 if (!checked_write(f, points, coords, buffer))
1397 if (!(*(char *)(&swap_test)))
1398 { c = (char *)(points); /* swap bytes back */
1399 for (i=0; i<coords; i+=4)
1400 { cSwap = c[i]; c[i] = c[i+3]; c[i+3] = cSwap;
1401 cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1406 if (!(tobuffer || getsize))
1407 if (f != fileno(stdout)) close(f);
1409 if (getsize) return;