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 /************************************************************************/
344 //#define fileno _fileno
347 //#define close _close
353 //#define lseek _lseek
356 //#define creat _creat
360 // Fields with data size>8GB (having UINT_MAX short pixels) cannot be compressed using
361 // NKI_MODE2 struct because iOrgSize has type "unsigned int". In that case use NKI_MODE2_64BITS.
362 // The type of structure is indicated as follows:
364 // iOrgSize==0: NKI_MODE2_64BITS
365 // otherwise : NKI_MODE2
367 // Compression modes 1 and 3 (without CRCs) only use the first 2 members (iOrgSize and iMode).
371 unsigned int iOrgSize; /* in pixels (i.e. shorts) */
372 unsigned int iMode; /* 1, 2, 3 or 4 */
373 unsigned int iCompressedSize; /* in bytes, excluding header */
374 unsigned int iOrgCRC; /* CRC of the data (no coords etc) */
375 unsigned int iCompressedCRC; /* CRC of the compressed data, excluding this header */
380 unsigned int iOrgSize; /* in pixels (i.e. shorts) */
381 unsigned int iMode; /* 1, 2, 3 or 4 */
382 unsigned int iCompressedSize; /* in bytes, excluding header */
383 unsigned int iOrgCRC; /* CRC of the data (no coords etc) */
384 unsigned int iCompressedCRC; /* CRC of the compressed data, excluding this header */
385 unsigned int iPad; /* unused */
386 Q_UINT64 i64OrgSize; /* used for more than UINT_MAX pixels, indicated by iOrgSize==0 (0-vector not compressed) */
387 Q_UINT64 i64CompressedSize; /* value in BYTES, used for more than UINT_MAX PIXELS, indicated by iCompressedSize==0 */
394 // Changed next to static function in stead of macro so it can
395 // have a return value to check in the calling function.
396 // It could be made inline as well, but there is no real time
397 // punishment from the extra layer of function calls.
399 // note: some compilers do not like comments ending in a backslash.
400 // so use macro functions to exclude.
403 /************************************************************************/
404 /* GLOBAL VARIABLES */
405 /************************************************************************/
407 static const unsigned long CRC32_table[256] = {
408 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
409 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
410 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
411 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
412 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
413 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
414 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
415 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
416 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
417 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
418 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
419 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
420 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
421 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
422 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
423 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
424 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
425 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
426 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
427 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
428 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
429 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
430 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
431 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
432 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
433 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
434 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
435 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
436 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
437 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
438 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
439 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
440 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
441 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
442 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
443 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
444 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
445 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
446 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
447 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
448 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
449 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
450 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
453 /************************************************************************/
454 /* MODULE FUNCTIONS */
455 /************************************************************************/
460 int writefix(int file, const void *buf, unsigned int count)
463 for (unsigned i=0; i<count; i+=16384)
465 if (j>16384) j=16384;
467 k=write(file, (char *)buf+i, j);
480 Version of write() that takes special action in case of
481 standard output. Based on commented out macro above.
482 This function overloads the <cstdio> (or stdio.h for old style C++)
486 // Like the original macro, we do /not/ want writefix from mbfield.c.
490 static int wxdr_write(int handle, const void * buf, unsigned len)
492 // if (handle == 1) // stdout
493 if (handle == fileno(stdout))
496 // Behave as C standard library write(): return number of bytes
497 // written or -1 and errno set on error.
499 DWORD dwBytesWritten;
500 if (!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, len,
501 &dwBytesWritten, NULL))
503 // There is no simple 1-to-1 mapping between GetLastError()
504 // values that WriteFile() can return (quite a lot) and the two
505 // errno values that write() can return. So return EACCES in
507 switch (GetLastError())
508 { case ERROR_INVALID_HANDLE:
509 errno = EBADF ; break;
511 errno = EACCES; break;
516 return (int)dwBytesWritten; // May still be < len!
517 // And... write() may write a maximum of UINT_MAX-1 bytes, whereas
518 // WriteFile() may write UINT_MAX bytes at once. But since
519 // int(UINT_MAX) == -1 this will pose an actual problem in the
522 //const int oldmode = setmode(handle, O_BINARY);//commented out by joel
523 const int iBytesWritten = write(handle, buf, len);
524 const int saveerrno = errno; // setmode() may change errno.
525 //if (oldmode != -1) setmode(handle, oldmode); //commented out by joel
527 return iBytesWritten;
531 return write(handle, buf, len);
536 Behaves like win32 WriteFile() and returns a Boolean to indicate
537 success or failure, where failure almost invariably means disc full.
541 In case of failure, this function issues an AVS error message
542 and closes the file (if handle != 1). It is up to the calling
543 function to return the AVS_ERROR state and before that do things
544 like close other files, free memory etc. This way, there is less
545 chance of erroneously duplicated code, like in:
546 written = write(f, temp, strlen(temp));
547 if (written == -1 || written != strlen(temp))
549 if (f != fileno(stdout)) close(f);
552 written = write(f, buf, buflength)
553 if (written == -1 || written != strlen(temp)) {
554 // oops, wrong length copy'n'pasted
556 If more elaborate error handling is needed then the calling
557 functuon should use the (overloaded) write() and act on its return
558 value (and the value of errno) accordingly.
560 It does /not/ close stdout.
564 Note that checked_write() takes a size_t for len, whereas write() takes
565 an unsigned int of 4 bytes. On a 64 bits OS a size_t will be an 8 byte integer,
566 enabling more than UINT_MAX bytes to write at once.
568 static bool checked_write(int handle, const void * buf, size_t len, char **buffer)
569 { if (buffer && !handle)
570 { memcpy(*buffer, buf, len);
574 if (buffer && handle)
579 { for(int i=0; i<2; i++)
584 //If write fails, test if not related to big buffer problem
585 //Bug report http://support.microsoft.com/kb/899149 entitled
586 //"You cannot call the fwrite function to write to a buffer
587 // that is larger than 64 MB in Visual C++ 2005,
588 // in Visual C++ .NET 2003, or in Visual C++ .NET 2002"
589 // NB: same thing for write function in binary mode
592 // call wxdr_write (for handle!=fileno(stdout) a wrapper for write) several times
593 // to interpret the signed 32-bit return value correctly
595 { chunksize = (int)std::min(remaining, (size_t)INT_MAX);
596 byteswritten = wxdr_write(handle, buf, chunksize);
597 if (byteswritten == chunksize)
598 remaining -= chunksize;
600 break; // try writefix in the next round
607 // call writefix (in mbfield.c) several times to interpret the signed 32-bit
608 // return value correctly. writefix uses chunks of 16384 bytes
610 { chunksize = (int)std::min(remaining, (size_t)INT_MAX);
611 byteswritten = writefix(handle, buf, chunksize);
612 if (byteswritten == chunksize)
613 remaining -= chunksize;
615 break; // even writefix failed: return error
621 // Note: file is open in binary mode, no need to compensate
622 // for a value of byteswritten > len due to \n -> \r\n conversions.
623 // (write() on a text stream is implementation dependent.)
624 if (handle != fileno(stdout)) close(handle);
625 AVSerror("Avs_wxdr: write failed, disk full?");
630 /* coder for NKI private compressed pixel data
631 arguments: dest = (in) points to area where compressed destination data is written (byte)
632 src = (in) points to uncompressed source data (short)
633 npixels = (in) number of pixels to compress
635 The return value is the number of bytes in the compressed data (maximal 3*npixels+10, typical 0.52*npixels)
638 - The first 4 bytes contain the number of short-int pixels
639 - The following 4 bytes contain iMode=1
640 - The rest is the compressed image
643 - The first 4 bytes contain the number of short-int pixels
644 - The following 4 bytes contain iMode=2
645 - The following 4 bytes contain the size of the compressed image (in bytes)
646 - The following 4 bytes contain the CRC of the original image
647 - The following 4 bytes contain the CRC of the compressed image
648 - The rest is the compressed image
649 - The compressed size will be even (padded by a zero if necessary).
652 - The first 4 bytes contain the number of short-int pixels
653 - The following 4 bytes contain iMode=3
654 - The rest is the compressed image, including 4 bit differences
657 - The first 4 bytes contain the number of short-int pixels
658 - The following 4 bytes contain iMode=4
659 - The following 4 bytes contain the size of the compressed image (in bytes)
660 - The following 4 bytes contain the CRC of the original image
661 - The following 4 bytes contain 0
662 - The rest is the compressed image, including 4 bit differences
663 - The compressed size will be even (padded by a zero if necessary).
665 iMode 1 and iMode 2 are identical, except for the CRC data that is included for iMode 2
666 iMode 3 and iMode 4 are identical, except for the CRC data that is included for iMode 4
669 // optimized settings for the 4 bit run compressor (mode 3 and 4)
671 #define MINZEROS 5 // shortest RLE (2 byte overhead, but breaks 4bit run)
672 #define MIN4BIT 6 // shortest 4 bit run (6 bytes compressed to 5 bytes)
674 // This internal routine converts an 8 bit difference string into a 4 bit one
675 static signed char *recompress4bit(int n, signed char *dest)
676 { signed char *p, *q;
682 val = (((int)p[0])<<4) | (p[1]&15);
684 *dest++ = -0x40; // 192 (0xc0) does not fit between -128..127: maps to -64 (0x40) in 2's complement
685 *dest++ = (signed char)n;
689 { *dest++ = (signed char)((((int)p[0])<<4) | (p[1]&15));
693 q[0] = (signed char)val;
699 static size_t nki_private_compress(signed char *dest, short int *src, size_t npixels, int iMode)
700 { unsigned long iCRC;
702 unsigned int iHeaderSize=8; // value for iMode==1 and iMode==3
705 NKI_MODE2* pHeader = (NKI_MODE2*)dest;
706 NKI_MODE2_64BITS* pHeader_64bits = (NKI_MODE2_64BITS*)dest;
709 iBufferSize = (npixels / 2) * 3; // Buffer is sizeof(NKI_MODE2_64BITS) + 10 bytes larger
711 /* Up till now only Mode=1 .. 4 are supported */
712 if ((iMode < 1) || (iMode > 4))
715 /* Create the header */
716 pHeader->iMode = iMode;
718 if (sizeof(int*)>sizeof(int) && npixels>UINT_MAX) // On a 64 bits OS we want to store files>4GB
719 { pHeader_64bits->iOrgSize = 0; // This indicates>4GB file (0-vector is not compressed)
720 pHeader_64bits->i64OrgSize = npixels;
721 iHeaderSize = sizeof(NKI_MODE2_64BITS);
722 dest += sizeof(NKI_MODE2_64BITS);
725 { pHeader->iOrgSize = (unsigned int)(npixels & UINT_MAX); // store 32 bit number as first member
727 if (iMode==2 || iMode==4)
728 iHeaderSize = sizeof(NKI_MODE2);
732 /* Create the compressed image */
735 { *(short int *)dest = *src;
741 { val = src[1] - src[0];
744 if (val == 0) /* run length-encode zero differences */
746 { if (i>=npixels || src[i-1]!=src[-1] || i==256)
750 { *dest++ = -128; // hexadecimal 0x80
751 *dest++ = (signed char)(i-1);
759 else if (val >= -64 && val <= 63) /* small difference coded as one byte */
760 { *dest = (signed char)val;
763 else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
764 { dest[0] = (signed char)((val>>8) ^ 0x40);
765 dest[1] = (signed char)val;
768 else /* if very large differences code abs val as three bytes */
770 *dest++ = (signed char)(src[0]>>8);
771 *dest++ = (signed char)(src[0]);
773 /* Are we beyond the allocated memory? */
774 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
784 *(short int *)dest = val = *src;
785 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char) val ] ^ ((iCRC2 >> 8));
786 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
787 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) val ] ^ ((iCRC >> 8));
788 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(val>>8)] ^ ((iCRC >> 8));
793 { val = src[1] - src[0];
795 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
796 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
798 if (val == 0) /* run length-encode zero differences */
800 { if (i>=npixels || src[i-1]!=src[-1] || i==256)
803 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0 ] ^ ((iCRC2 >> 8));
806 { *dest++ = -128; // hexadecimal 0x80
807 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0x80 ] ^ ((iCRC2 >> 8));
808 *dest++ = (signed char)(i-1);
809 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (i-1)] ^ ((iCRC2 >> 8));
812 for (j=0; j<i-2; j++)
814 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
815 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
822 else if (val >= -64 && val <= 63) /* small difference coded as one byte */
823 { *dest = (signed char)val;
824 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val ] ^ ((iCRC2 >> 8));
827 else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
828 { dest[0] = (signed char)((val>>8) ^ 0x40);
829 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)dest[0] ] ^ ((iCRC2 >> 8));
830 dest[1] = (signed char)val;
831 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val ] ^ ((iCRC2 >> 8));
834 else /* if very large differences code abs val as three bytes */
836 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0x7f ] ^ ((iCRC2 >> 8));
838 dest[1] = (signed char)(val>>8);
839 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
840 dest[2] = (signed char)val;
841 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val ] ^ ((iCRC2 >> 8));
844 /* Are we beyond the allocated memory? */
845 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
850 if ((dest - (signed char*)pHeader - iHeaderSize)<UINT_MAX) // store 32 bit number as third member
851 pHeader->iCompressedSize =
852 (unsigned int)(dest - (signed char*)pHeader - iHeaderSize);
853 else // store 64 bit number in extended structure
854 pHeader_64bits->i64CompressedSize = dest - (signed char*)pHeader -iHeaderSize;
856 /* Pad it to get an even length */
857 if (pHeader->iCompressedSize & 1)
859 iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0] ^ ((iCRC2 >> 8));
860 pHeader->iCompressedSize++;
863 pHeader->iOrgCRC = iCRC;
864 pHeader->iCompressedCRC = iCRC2;
867 /* Create the compressed image - compressor with added 4 bit run */
871 *(short int *)dest = *src;
876 { val = src[1] - src[0];
879 if (val == 0) /* run length-encode zero differences */
881 { if (i>=npixels || src[i-1]!=src[-1] || i==256)
882 { if (i<=MINZEROS) /* too short run -> write zeros */
883 { for (j=0; j<i-1; j++)
887 if(n4bit>=254) /* maximum length 4 bit run */
888 { dest = recompress4bit(n4bit, dest);
894 { if (n4bit>=MIN4BIT) /* end (and write) 4 bit run */
895 dest = recompress4bit(n4bit, dest);
898 *dest++ = -128; // hexadecimal 0x80
899 *dest++ = (signed char)(i-1);
908 else if (val >= -63 && val <= 63) /* small difference coded as one byte */
909 { if (val >= -8 && val <= 7)
910 { *dest++ = (signed char)val;
913 if(n4bit>=254) /* maximum length 4 bit run */
914 { dest = recompress4bit(n4bit, dest);
918 else if(n4bit>=MIN4BIT) /* end and write 4 bit run */
920 dest = recompress4bit(n4bit, dest);
922 *dest++ = (signed char)j;
925 { *dest++ = (signed char)val; /* end 4 bit run */
929 else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
932 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
933 dest = recompress4bit(n4bit, dest);
936 dest[0] = (signed char)((j>>8) ^ 0x40);
937 dest[1] = (signed char)j;
940 else /* if very large differences code abs val as three bytes */
943 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
944 dest = recompress4bit(n4bit, dest);
948 *dest++ = (signed char)(j>>8);
949 *dest++ = (signed char)j;
951 /* Are we beyond the allocated memory? */
952 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
958 /* Create the compressed image - compressor with added 4 bit run and CRC */
964 *(short int *)dest = val = *src;
965 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) val ] ^ ((iCRC >> 8));
966 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(val>>8)] ^ ((iCRC >> 8));
971 { val = src[1] - src[0];
973 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
974 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
976 if (val == 0) /* run length-encode zero differences */
978 { if (i>=npixels || src[i-1]!=src[-1] || i==256)
979 { if (i<=MINZEROS) /* too short run -> write zeros */
980 { for (j=0; j<i-1; j++)
984 if(n4bit>=254) /* maximum length 4 bit run */
985 { dest = recompress4bit(n4bit, dest);
991 { if (n4bit>=MIN4BIT) /* end (and write) 4 bit run */
992 dest = recompress4bit(n4bit, dest);
995 *dest++ = -128; // hexadecimal 0x80
996 *dest++ = (signed char)(i-1);
1000 for (j=0; j<i-2; j++)
1002 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char) src[0] ] ^ ((iCRC >> 8));
1003 iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)(src[0]>>8)] ^ ((iCRC >> 8));
1009 else if (val >= -63 && val <= 63) /* small difference coded as one byte */
1010 { if (val >= -8 && val <= 7)
1011 { *dest++ = (signed char)val;
1014 if(n4bit>=254) /* maximum length 4 bit run */
1015 { dest = recompress4bit(n4bit, dest);
1019 else if(n4bit>=MIN4BIT) /* end and write 4 bit run */
1021 dest = recompress4bit(n4bit, dest);
1023 *dest++ = (signed char)j;
1026 { *dest++ = (signed char)val; /* end 4 bit run */
1030 else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
1033 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
1034 dest = recompress4bit(n4bit, dest);
1037 dest[0] = (signed char)((j>>8) ^ 0x40);
1038 dest[1] = (signed char)j;
1041 else /* if very large differences code abs val as three bytes */
1044 if(n4bit>=MIN4BIT) /* end (and write) 4 bit run */
1045 dest = recompress4bit(n4bit, dest);
1049 *dest++ = (signed char)(j>>8);
1050 *dest++ = (signed char)j;
1052 /* Are we beyond the allocated memory? */
1053 if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
1058 if ((dest - (signed char*)pHeader - iHeaderSize)<UINT_MAX) // store 32 bit number as third member
1059 pHeader->iCompressedSize =
1060 (unsigned int)(dest - (signed char*)pHeader - iHeaderSize);
1061 else // store 64 bit number in extended structure
1062 { pHeader_64bits->iCompressedSize = 0;
1063 pHeader_64bits->i64CompressedSize = dest - (signed char*)pHeader -iHeaderSize;
1066 /* Pad it to get an even length */
1067 if (pHeader->iCompressedSize & 1)
1069 pHeader->iCompressedSize++;
1072 pHeader->iOrgCRC = iCRC;
1073 pHeader->iCompressedCRC = 0;
1076 return dest - (signed char*)pHeader;
1080 void clitk::XdrImageIO::WriteImage(const char* file, char* headerinfo, char* headerfile, int raw,
1081 int offset, char bLittleEndian, int iNkiCompression,
1082 int wcoords, int append, int getsize, char *tobuffer, const void* data)
1091 long swap_test = 0x1000000;
1092 signed char* pCompressed = NULL;
1094 char **buffer = NULL;
1100 swap_test = 0x00000001;
1103 { swap_test = 0xffffffff; // never swap to save time
1104 buffer = (char **) &len;
1109 { buf2 = (char *)tobuffer;
1114 for (i=0; i<GetNumberOfDimensions(); i++)
1115 { total *= GetDimensions(i);
1116 coords += GetDimensions(i);
1119 /* Try allocate the compressed fielddata - compression disabled if alloc fails */
1120 if ((iNkiCompression > 0) &&
1121 (GetComponentType() == itk::ImageIOBase::SHORT) &&
1122 (GetPixelType() == itk::ImageIOBase::SCALAR))
1123 { pCompressed = (signed char *)malloc((total/2) * 3 + sizeof(NKI_MODE2_64BITS) + 10);
1124 if (pCompressed==NULL)
1125 { iNkiCompression = 0;
1126 AVSwarning("Avs_wxdr: not enough memory to compress data, saving uncompressed");
1130 if (!(tobuffer || getsize))
1132 { f = open(file, O_RDWR, 0);
1135 AVSerror("Avs_wxdr: Opening " << file << "failed.\n" << strerror(errno));
1139 lseek(f, offset, SEEK_SET);
1142 { if (strlen(file)==0)
1146 f = open(file, O_RDWR | O_APPEND, 0);
1148 f = creat(file, S_IWRITE | S_IREAD);
1152 { AVSerror("Avs_wxdr: Creating " << file << " failed.\n" << strerror(errno));
1160 { sprintf(temp, "# AVS wants to have the first line starting with its name\n");
1161 slen = strlen(temp);
1163 if (!checked_write(f, temp, slen, buffer))
1164 { free(pCompressed);
1169 slen = strlen(headerinfo);
1170 if (slen && !checked_write(f, headerinfo, slen, buffer))
1171 { free(pCompressed);
1176 if (!checked_write(f, "\n", 1, buffer))
1177 { free(pCompressed);
1182 if (strlen(headerfile))
1183 { fp = fopen(headerfile, "rt");
1186 { if (fgets(temp, 255, fp) == NULL) break;
1187 slen = strlen(temp);
1188 if (!checked_write(f, temp, slen, buffer))
1196 if (!checked_write(f, "\n", 1, buffer))
1197 { free(pCompressed);
1204 sprintf(temp, "ndim=%d\n", GetNumberOfDimensions());
1205 slen = strlen(temp);
1206 if (!checked_write(f, temp, slen, buffer))
1207 { free(pCompressed);
1213 for (i=0; i<GetNumberOfDimensions(); i++)
1215 { sprintf(temp, "dim%d=%d\n", i+1, GetDimensions(i));
1216 slen = strlen(temp);
1217 if (!checked_write(f, temp, slen, buffer))
1218 { free(pCompressed);
1226 { sprintf(temp, "nspace=%d\n", GetNumberOfDimensions());
1227 slen = strlen(temp);
1228 if (!checked_write(f, temp, slen, buffer))
1229 { free(pCompressed);
1234 sprintf(temp, "veclen=%d\n", GetNumberOfComponents());
1235 slen = strlen(temp);
1236 if (!checked_write(f, temp, slen, buffer))
1237 { free(pCompressed);
1242 switch(GetComponentType())
1243 { case itk::ImageIOBase::CHAR : strcpy(temp, "data=byte\n"); break;
1244 case itk::ImageIOBase::SHORT : strcpy(temp, "data=xdr_short\n"); break;
1245 case itk::ImageIOBase::INT : strcpy(temp, "data=xdr_integer\n"); break;
1246 case itk::ImageIOBase::FLOAT : strcpy(temp, "data=xdr_real\n"); break;
1247 case itk::ImageIOBase::DOUBLE : strcpy(temp, "data=xdr_double\n"); break;
1248 default : if (f != fileno(stdout)) close(f);
1252 slen = strlen(temp);
1253 if (!checked_write(f, temp, slen, buffer))
1254 { free(pCompressed);
1261 //FilePos = tell(f);
1265 //switch(input->uniform)
1267 strcpy(temp, "field=uniform\n");
1268 coords = GetNumberOfDimensions() * 2;
1270 // case RECTILINEAR : strcpy(temp, "field=rectilinear\n");
1272 // case IRREGULAR : strcpy(temp, "field=irregular\n");
1273 // coords = total * input->nspace;
1275 // default : if (f != fileno(stdout)) close(f);
1276 // free(pCompressed);
1281 { if (!checked_write(f, temp, strlen(temp), buffer))
1282 { free(pCompressed);
1286 if ((iNkiCompression > 0) &&
1287 (GetComponentType() == itk::ImageIOBase::SHORT) &&
1288 (GetPixelType() == itk::ImageIOBase::SCALAR))
1289 { sprintf(temp, "nki_compression=%d", iNkiCompression);
1290 if (!checked_write(f, temp, strlen(temp), buffer))
1291 { free(pCompressed);
1296 temp[0] = temp[1] = 12;
1297 if (!checked_write(f, temp, 2, buffer))
1298 { free(pCompressed);
1303 total *= GetPixelSize();
1305 if ((!raw) && (iNkiCompression > 0) &&
1306 (GetComponentType() == itk::ImageIOBase::SHORT) &&
1307 (GetPixelType() == itk::ImageIOBase::SCALAR))
1308 { size_t iCompressedLength;
1310 iCompressedLength = nki_private_compress(pCompressed,
1311 (short int *)(data), total/2, iNkiCompression);
1313 if (iCompressedLength > 0)
1314 { if (!checked_write(f, pCompressed, iCompressedLength, buffer))
1315 { free(pCompressed);
1322 /* Compressionratio was poor: let's write uncompressed */
1323 iNkiCompression = 0;
1327 lseek(f, (unsigned int)FilePos, SEEK_SET); // use _lseeki64 just in case header size > UINT_MAX bytes
1331 /* swap data if required (xdr is low-endian) */
1333 if (!(*(char *)(&swap_test)))
1334 { if (GetComponentSize()==2)
1336 for (i=0; i<total; i+=2)
1337 { cSwap = c[i]; c[i] = c[i+1]; c[i+1] = cSwap;
1340 else if (GetComponentSize()==4)
1342 for (i=0; i<total; i+=4)
1343 { cSwap = c[i]; c[i] = c[i+3]; c[i+3] = cSwap;
1344 cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1347 else if (GetComponentSize()==8)
1349 for (i=0; i<total; i+=8)
1350 { cSwap = c[i]; c[i] = c[i+7]; c[i+7] = cSwap;
1351 cSwap = c[i+1]; c[i+1] = c[i+6]; c[i+6] = cSwap;
1352 cSwap = c[i+2]; c[i+2] = c[i+5]; c[i+5] = cSwap;
1353 cSwap = c[i+3]; c[i+3] = c[i+4]; c[i+4] = cSwap;
1359 { if (!checked_write(f, data, total, buffer))
1363 /* swap data back if was swapped before writing */
1365 if (!(*(char *)(&swap_test)))
1366 { if (GetComponentSize()==2)
1368 for (i=0; i<total; i+=2)
1369 { cSwap = c[i]; c[i] = c[i+1]; c[i+1] = cSwap;
1372 else if (GetComponentSize()==4)
1374 for (i=0; i<total; i+=4)
1375 { cSwap = c[i]; c[i] = c[i+3]; c[i+3] = cSwap;
1376 cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1379 else if (GetComponentSize()==8)
1381 for (i=0; i<total; i+=8)
1382 { cSwap = c[i]; c[i] = c[i+7]; c[i+7] = cSwap;
1383 cSwap = c[i+1]; c[i+1] = c[i+6]; c[i+6] = cSwap;
1384 cSwap = c[i+2]; c[i+2] = c[i+5]; c[i+5] = cSwap;
1385 cSwap = c[i+3]; c[i+3] = c[i+4]; c[i+4] = cSwap;
1392 points = (float *)malloc(sizeof(float)*GetNumberOfDimensions()*2);
1393 for (i=0; i<GetNumberOfDimensions(); i++)
1395 points[i*2 ] = 0.1 * GetOrigin(i);
1396 points[i*2+1] = 0.1 * (GetOrigin(i) + GetSpacing(i)*(GetDimensions(i)-1));
1399 if (coords && !raw) /* write AVS coordinates ? */
1400 { coords *= sizeof(float);
1401 if (!(*(char *)(&swap_test)))
1402 { c = (char *)(points); /* swap bytes */
1403 for (i=0; i<coords; i+=4)
1404 { cSwap = c[i]; c[i] = c[i+3]; c[i+3] = cSwap;
1405 cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1409 if (!checked_write(f, points, coords, buffer))
1412 if (!(*(char *)(&swap_test)))
1413 { c = (char *)(points); /* swap bytes back */
1414 for (i=0; i<coords; i+=4)
1415 { cSwap = c[i]; c[i] = c[i+3]; c[i+3] = cSwap;
1416 cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1421 if (!(tobuffer || getsize))
1422 if (f != fileno(stdout)) close(f);
1424 if (getsize) return;