841 lines
27 KiB
C
841 lines
27 KiB
C
|
// Copyright (c) 2005-2008 ASCLEPIOS Project, INRIA Sophia-Antipolis (France)
|
||
|
// All rights reserved.
|
||
|
//
|
||
|
// This file is part of the ImageIO Library, and as been adapted for CGAL (www.cgal.org).
|
||
|
//
|
||
|
// $URL: https://github.com/CGAL/cgal/blob/v5.1/CGAL_ImageIO/include/CGAL/ImageIO/analyze_impl.h $
|
||
|
// $Id: analyze_impl.h 0779373 2020-03-26T13:31:46+01:00 Sébastien Loriot
|
||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||
|
//
|
||
|
//
|
||
|
// Author(s) : ASCLEPIOS Project (INRIA Sophia-Antipolis), Laurent Rineau
|
||
|
|
||
|
#include <cstring>
|
||
|
|
||
|
#ifdef CGAL_HEADER_ONLY
|
||
|
#define CGAL_INLINE_FUNCTION inline
|
||
|
#else
|
||
|
#define CGAL_INLINE_FUNCTION
|
||
|
#endif
|
||
|
|
||
|
/* compile time endianness */
|
||
|
/* replaced by _getEndianness()
|
||
|
see below
|
||
|
#if (defined (_ALPHA_) || defined (_LINUX_))
|
||
|
#define ARCHITECTURE_ENDIANNESS END_LITTLE
|
||
|
#else
|
||
|
#define ARCHITECTURE_ENDIANNESS END_BIG
|
||
|
#endif
|
||
|
*/
|
||
|
|
||
|
/** Magic header for ANALYZE files written in little endian format */
|
||
|
#define ANALYZE_LE_MAGIC "\000\000\001\134"
|
||
|
/** Magic header for ANALYZE files written in big endian format */
|
||
|
#define ANALYZE_BE_MAGIC "\134\001\000\000"
|
||
|
|
||
|
#define DT_NONE 0
|
||
|
#define DT_UNKNOWN 0 /*Unknown data type*/
|
||
|
#define DT_BINARY 1 /*Binary (1 bit per voxel)*/
|
||
|
#define DT_UNSIGNED_CHAR 2 /*Unsigned character (8 bits per voxel)*/
|
||
|
#define DT_SIGNED_SHORT 4 /*Signed short (16 bits per voxel)*/
|
||
|
#define DT_SIGNED_INT 8 /*Signed integer (32 bits per voxel)*/
|
||
|
#define DT_FLOAT 16 /*Floating point (32 bits per voxel)*/
|
||
|
#define DT_COMPLEX 32 /*Complex (64 bits per voxel; 2 floating point numbers) */
|
||
|
#define DT_DOUBLE 64 /*Double precision (64 bits per voxel)*/
|
||
|
#define DT_RGB 128 /* */
|
||
|
#define DT_ALL 255 /* */
|
||
|
|
||
|
#include <cstring>
|
||
|
|
||
|
struct header_key /* header_key */
|
||
|
{ /* off + size*/
|
||
|
int sizeof_hdr; /* 0 + 4 */
|
||
|
char data_type[10]; /* 4 + 10 */
|
||
|
char db_name[18]; /* 14 + 18 */
|
||
|
int extents; /* 32 + 4 */
|
||
|
short int session_error; /* 36 + 2 */
|
||
|
char regular; /* 38 + 1 */
|
||
|
char hkey_un0; /* 39 + 1 */
|
||
|
}; /* total=40 */
|
||
|
|
||
|
struct image_dimension /* image_dimension */
|
||
|
{ /* off + size*/
|
||
|
short int dim[8]; /* 0 + 16 */
|
||
|
char vox_units[4]; /* 16 + 4 */
|
||
|
char cal_units[8]; /* 20 + 4 */
|
||
|
short int unused1; /* 24 + 2 */
|
||
|
short int datatype; /* 30 + 2 */
|
||
|
short int bitpix; /* 32 + 2 */
|
||
|
short int dim_un0; /* 34 + 2 */
|
||
|
float pixdim[8]; /* 36 + 32 */
|
||
|
/*
|
||
|
pixdim[] specifies the voxel dimensions:
|
||
|
pixdim[1] - voxel width
|
||
|
pixdim[2] - voxel height
|
||
|
pixdim[3] - interslice distance
|
||
|
..etc
|
||
|
*/
|
||
|
float vox_offset; /* 68 + 4 */
|
||
|
float funused1; /* 72 + 4 */
|
||
|
float funused2; /* 76 + 4 */
|
||
|
float funused3; /* 80 + 4 */
|
||
|
float cal_max; /* 84 + 4 */
|
||
|
float cal_min; /* 88 + 4 */
|
||
|
int compressed; /* 92 + 4 */
|
||
|
int verified; /* 96 + 4 */
|
||
|
int glmax, glmin; /* 100 + 8 */
|
||
|
}; /* total=108 */
|
||
|
|
||
|
struct data_history /* data_history */
|
||
|
{ /* off + size*/
|
||
|
char descrip[80]; /* 0 + 80 */
|
||
|
char aux_file[24]; /* 80 + 24 */
|
||
|
char orient; /* 104 + 1 */
|
||
|
char originator[10]; /* 105 + 10 */
|
||
|
char generated[10]; /* 115 + 10 */
|
||
|
char scannum[10]; /* 125 + 10 */
|
||
|
char patient_id[10]; /* 135 + 10 */
|
||
|
char exp_date[10]; /* 145 + 10 */
|
||
|
char exp_time[10]; /* 155 + 10 */
|
||
|
char hist_un0[3]; /* 165 + 3 */
|
||
|
int views; /* 168 + 4 */
|
||
|
int vols_added; /* 172 + 4 */
|
||
|
int start_field; /* 176 + 4 */
|
||
|
int field_skip; /* 180 + 4 */
|
||
|
int omax,omin; /* 184 + 8 */
|
||
|
int smax,smin; /* 192 + 8 */
|
||
|
};
|
||
|
|
||
|
|
||
|
struct dsr /* dsr */
|
||
|
{ /* off + size*/
|
||
|
struct header_key hk; /* 0 + 40 */
|
||
|
struct image_dimension dime; /* 40 + 108 */
|
||
|
struct data_history hist; /* 148 + 200 */
|
||
|
}; /* total=348 */
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*---------------- _swapLong ------------------------------------------------*/
|
||
|
CGAL_INLINE_FUNCTION
|
||
|
static void _swapLong( unsigned char *pntr)
|
||
|
{
|
||
|
unsigned char b0, b1, b2, b3;
|
||
|
|
||
|
b0 = *pntr;
|
||
|
b1 = *(pntr+1);
|
||
|
b2 = *(pntr+2);
|
||
|
b3 = *(pntr+3);
|
||
|
|
||
|
*pntr = b3;
|
||
|
*(pntr+1) = b2;
|
||
|
*(pntr+2) = b1;
|
||
|
*(pntr+3) = b0;
|
||
|
}
|
||
|
|
||
|
/*---------------- _swapShort -----------------------------------------------*/
|
||
|
CGAL_INLINE_FUNCTION
|
||
|
static void _swapShort( unsigned char *pntr)
|
||
|
{
|
||
|
unsigned char b0, b1;
|
||
|
|
||
|
b0 = *pntr;
|
||
|
b1 = *(pntr+1);
|
||
|
|
||
|
*pntr = b1;
|
||
|
*(pntr+1) = b0;
|
||
|
}
|
||
|
|
||
|
/*---------------- _swapAnalyzeHdr ------------------------------------------*/
|
||
|
CGAL_INLINE_FUNCTION
|
||
|
static void _swapAnalyzeHdr( struct dsr *pntr)
|
||
|
{
|
||
|
|
||
|
_swapLong((unsigned char*) &pntr->hk.sizeof_hdr) ;
|
||
|
_swapLong((unsigned char*) &pntr->hk.extents) ;
|
||
|
_swapShort((unsigned char*) &pntr->hk.session_error) ;
|
||
|
_swapShort((unsigned char*) &pntr->dime.dim[0]) ;
|
||
|
_swapShort((unsigned char*) &pntr->dime.dim[1]) ;
|
||
|
_swapShort((unsigned char*) &pntr->dime.dim[2]) ;
|
||
|
_swapShort((unsigned char*) &pntr->dime.dim[3]) ;
|
||
|
_swapShort((unsigned char*) &pntr->dime.dim[4]) ;
|
||
|
_swapShort((unsigned char*) &pntr->dime.dim[5]) ;
|
||
|
_swapShort((unsigned char*) &pntr->dime.dim[6]) ;
|
||
|
_swapShort((unsigned char*) &pntr->dime.dim[7]) ;
|
||
|
_swapShort((unsigned char*) &pntr->dime.unused1) ;
|
||
|
_swapShort((unsigned char*) &pntr->dime.datatype) ;
|
||
|
_swapShort((unsigned char*) &pntr->dime.bitpix) ;
|
||
|
_swapLong((unsigned char*) &pntr->dime.pixdim[0]) ;
|
||
|
_swapLong((unsigned char*) &pntr->dime.pixdim[1]) ;
|
||
|
_swapLong((unsigned char*) &pntr->dime.pixdim[2]) ;
|
||
|
_swapLong((unsigned char*) &pntr->dime.pixdim[3]) ;
|
||
|
_swapLong((unsigned char*) &pntr->dime.pixdim[4]) ;
|
||
|
_swapLong((unsigned char*) &pntr->dime.pixdim[5]) ;
|
||
|
_swapLong((unsigned char*) &pntr->dime.pixdim[6]) ;
|
||
|
_swapLong((unsigned char*) &pntr->dime.pixdim[7]) ;
|
||
|
_swapLong((unsigned char*) &pntr->dime.vox_offset) ;
|
||
|
_swapLong((unsigned char*) &pntr->dime.funused1) ;
|
||
|
_swapLong((unsigned char*) &pntr->dime.funused2) ;
|
||
|
_swapLong((unsigned char*) &pntr->dime.cal_max) ;
|
||
|
_swapLong((unsigned char*) &pntr->dime.cal_min) ;
|
||
|
_swapLong((unsigned char*) &pntr->dime.compressed) ;
|
||
|
_swapLong((unsigned char*) &pntr->dime.verified) ;
|
||
|
_swapShort((unsigned char*) &pntr->dime.dim_un0) ;
|
||
|
_swapLong((unsigned char*) &pntr->dime.glmax) ;
|
||
|
_swapLong((unsigned char*) &pntr->dime.glmin) ;
|
||
|
}
|
||
|
|
||
|
CGAL_INLINE_FUNCTION
|
||
|
PTRIMAGE_FORMAT createAnalyzeFormat() {
|
||
|
PTRIMAGE_FORMAT f=(PTRIMAGE_FORMAT) ImageIO_alloc(sizeof(IMAGE_FORMAT));
|
||
|
|
||
|
f->testImageFormat=&testAnalyzeHeader;
|
||
|
f->readImageHeader=&readAnalyzeHeader;
|
||
|
f->writeImage=&writeAnalyze;
|
||
|
strcpy(f->fileExtension,".hdr,.hdr.gz,.img,.img.gz");
|
||
|
strcpy(f->realName,"Analyze");
|
||
|
return f;
|
||
|
}
|
||
|
|
||
|
CGAL_INLINE_FUNCTION
|
||
|
int testAnalyzeHeader(char *magic,const char *) {
|
||
|
/* opened image is an ANALYZE */
|
||
|
if( !memcmp(magic,ANALYZE_LE_MAGIC,4) ||
|
||
|
!memcmp(magic,ANALYZE_BE_MAGIC,4))
|
||
|
return 0;
|
||
|
else
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
CGAL_INLINE_FUNCTION
|
||
|
int writeAnalyze( char *name, _image* im) {
|
||
|
char *outputName;
|
||
|
std::size_t length, extLength=0;
|
||
|
|
||
|
|
||
|
length=strlen(name);
|
||
|
outputName= (char *)ImageIO_alloc(length+8);
|
||
|
|
||
|
if ( strncmp( name+length-4, ".hdr", 4 ) == 0 ) {
|
||
|
extLength = 4;
|
||
|
}
|
||
|
else if ( strncmp( name+length-4, ".img", 4 ) == 0 ) {
|
||
|
extLength = 4;
|
||
|
}
|
||
|
else if ( strncmp( name+length-7, ".img.gz", 7 ) == 0 ) {
|
||
|
extLength = 7;
|
||
|
}
|
||
|
else if ( strncmp( name+length-7, ".hdr.gz", 7 ) == 0 ) {
|
||
|
extLength = 7;
|
||
|
}
|
||
|
|
||
|
strncpy( outputName, name, length-extLength );
|
||
|
if ( strncmp( name+length-7, ".hdr.gz", 7 ) == 0 )
|
||
|
strcpy( outputName+length-extLength, ".hdr.gz" );
|
||
|
else
|
||
|
strcpy( outputName+length-extLength, ".hdr" );
|
||
|
|
||
|
_openWriteImage(im, outputName);
|
||
|
if( !im->fd ) {
|
||
|
fprintf(stderr, "writeAnalyze: error: unable to open file \'%s\'\n", outputName);
|
||
|
if ( outputName != nullptr ) ImageIO_free( outputName );
|
||
|
return ImageIO_OPENING;
|
||
|
}
|
||
|
|
||
|
int res = writeAnalyzeHeader(im);
|
||
|
if ( res < 0 ) {
|
||
|
fprintf(stderr, "writeAnalyze: error: unable to write header of \'%s\'\n",
|
||
|
outputName);
|
||
|
if ( outputName != nullptr ) ImageIO_free( outputName );
|
||
|
ImageIO_close( im );
|
||
|
im->fd = nullptr;
|
||
|
im->openMode = OM_CLOSE;
|
||
|
return( res );
|
||
|
}
|
||
|
|
||
|
ImageIO_close(im);
|
||
|
|
||
|
strncpy( outputName, name, length-extLength );
|
||
|
if ( strncmp( name+length-3, ".gz", 3 ) == 0 ) {
|
||
|
strcpy( outputName+length-extLength, ".img.gz" );
|
||
|
}
|
||
|
else {
|
||
|
strcpy( outputName+length-extLength, ".img" );
|
||
|
}
|
||
|
|
||
|
_openWriteImage(im, outputName);
|
||
|
|
||
|
if( !im->fd ) {
|
||
|
fprintf(stderr, "writeAnalyze: error: unable to open file \'%s\'\n", outputName);
|
||
|
if ( outputName != nullptr ) ImageIO_free( outputName );
|
||
|
return ImageIO_OPENING;
|
||
|
}
|
||
|
|
||
|
res = writeAnalyzeData(im);
|
||
|
if (res < 0) {
|
||
|
fprintf(stderr, "writeAnalyze: error: unable to write data in \'%s\'\n",
|
||
|
outputName );
|
||
|
ImageIO_close( im );
|
||
|
im->fd = nullptr;
|
||
|
im->openMode = OM_CLOSE;
|
||
|
return( res );
|
||
|
}
|
||
|
|
||
|
if ( outputName != nullptr ) ImageIO_free( outputName );
|
||
|
ImageIO_close( im );
|
||
|
im->fd = nullptr;
|
||
|
im->openMode = OM_CLOSE;
|
||
|
|
||
|
return ( res );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
return:
|
||
|
-1: error
|
||
|
0: success
|
||
|
*/
|
||
|
|
||
|
CGAL_INLINE_FUNCTION
|
||
|
int _readAnalyzeHeader( _image* im, const char* name,
|
||
|
struct dsr *analyzeHeader )
|
||
|
{
|
||
|
|
||
|
unsigned int i ;
|
||
|
/* compile time endianness */
|
||
|
ENDIANNESS ARCHITECTURE_ENDIANNESS = _getEndianness();
|
||
|
|
||
|
if(im->openMode != OM_CLOSE) {
|
||
|
|
||
|
ImageIO_read( im, analyzeHeader, sizeof(struct dsr) );
|
||
|
|
||
|
if( analyzeHeader->hk.sizeof_hdr == sizeof(struct dsr) )
|
||
|
{
|
||
|
im->endianness = ARCHITECTURE_ENDIANNESS ;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_swapAnalyzeHdr( analyzeHeader );
|
||
|
if( analyzeHeader->hk.sizeof_hdr != sizeof(struct dsr) )
|
||
|
{
|
||
|
fprintf (stderr,
|
||
|
"_readAnalyzeHeader: error: unknown magic (%d)...\n",
|
||
|
analyzeHeader->hk.sizeof_hdr );
|
||
|
return -1;
|
||
|
}
|
||
|
if( ARCHITECTURE_ENDIANNESS == END_LITTLE )
|
||
|
{
|
||
|
im->endianness = END_BIG;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
im->endianness = END_LITTLE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( analyzeHeader->dime.dim[0] > 4 ) {
|
||
|
fprintf (stderr,
|
||
|
"_readAnalyzeHeader: error: dimensionality not supported (%d)...\n",
|
||
|
analyzeHeader->dime.dim[0] );
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
im->xdim = analyzeHeader->dime.dim[1];
|
||
|
im->ydim = analyzeHeader->dime.dim[2];
|
||
|
im->zdim = analyzeHeader->dime.dim[3];
|
||
|
|
||
|
/* 0 time-points is a convention for one volume only at MNI */
|
||
|
/* Corrected by X. Pennec following a bug report by Irina Kezele at MNI */
|
||
|
if( analyzeHeader->dime.dim[4] == 0 ){
|
||
|
fprintf (stderr,
|
||
|
"_readAnalyzeHeader: warning: time dimension / number if volume (dim[4]) is 0. Assuming this means 1 (otherwise there would be no image...). \n");
|
||
|
analyzeHeader->dime.dim[4] = 1;
|
||
|
}
|
||
|
|
||
|
/* Analyze doesn't support vector images.
|
||
|
The forth dimension relates to time. */
|
||
|
if( analyzeHeader->dime.dim[4] != 1 )
|
||
|
{
|
||
|
fprintf (stderr,
|
||
|
"_readAnalyzeHeader: error: time dimension not supported (%d)...\n",
|
||
|
analyzeHeader->dime.dim[4] );
|
||
|
return -1;
|
||
|
}
|
||
|
im->vectMode = VM_SCALAR;
|
||
|
|
||
|
im->vx = analyzeHeader->dime.pixdim[1];
|
||
|
im->vy = analyzeHeader->dime.pixdim[2];
|
||
|
im->vz = analyzeHeader->dime.pixdim[3];
|
||
|
|
||
|
if( im->vx == 0.0 ) im->vx = 1.0 ;
|
||
|
if( im->vy == 0.0 ) im->vy = im->vx ;
|
||
|
if( im->vz == 0.0 ) im->vz = im->vy ;
|
||
|
|
||
|
switch(analyzeHeader->dime.datatype)
|
||
|
{
|
||
|
case DT_BINARY:
|
||
|
case DT_UNSIGNED_CHAR:
|
||
|
case DT_SIGNED_SHORT:
|
||
|
case DT_SIGNED_INT:
|
||
|
case DT_FLOAT:
|
||
|
case DT_COMPLEX:
|
||
|
case DT_DOUBLE:
|
||
|
im->vdim = 1;
|
||
|
break ;
|
||
|
|
||
|
case DT_RGB:
|
||
|
im->vdim = 3;
|
||
|
break ;
|
||
|
|
||
|
default:
|
||
|
fprintf (stderr,
|
||
|
"_readAnalyzeHeader: error: data type not supported (%d)...\n",
|
||
|
analyzeHeader->dime.datatype );
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
switch(analyzeHeader->dime.datatype)
|
||
|
{
|
||
|
case DT_BINARY:
|
||
|
case DT_UNSIGNED_CHAR:
|
||
|
case DT_SIGNED_SHORT:
|
||
|
case DT_SIGNED_INT:
|
||
|
case DT_RGB:
|
||
|
im->wordKind = WK_FIXED;
|
||
|
break ;
|
||
|
|
||
|
case DT_FLOAT:
|
||
|
case DT_COMPLEX:
|
||
|
case DT_DOUBLE:
|
||
|
im->wordKind = WK_FLOAT;
|
||
|
break ;
|
||
|
|
||
|
default:
|
||
|
fprintf (stderr,
|
||
|
"_readAnalyzeHeader: error: data type not supported (%d)...\n",
|
||
|
analyzeHeader->dime.datatype );
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
switch(analyzeHeader->dime.datatype)
|
||
|
{
|
||
|
case DT_BINARY:
|
||
|
case DT_UNSIGNED_CHAR:
|
||
|
case DT_RGB:
|
||
|
im->sign = SGN_UNSIGNED;
|
||
|
break ;
|
||
|
|
||
|
case DT_SIGNED_SHORT:
|
||
|
case DT_SIGNED_INT:
|
||
|
case DT_FLOAT:
|
||
|
case DT_COMPLEX:
|
||
|
case DT_DOUBLE:
|
||
|
im->sign = SGN_SIGNED;
|
||
|
break ;
|
||
|
|
||
|
default:
|
||
|
fprintf (stderr,
|
||
|
"_readAnalyzeHeader: error: data type not supported (%d)...\n",
|
||
|
analyzeHeader->dime.datatype );
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
im->wdim = analyzeHeader->dime.bitpix;
|
||
|
if( analyzeHeader->dime.datatype == DT_RGB )
|
||
|
{
|
||
|
im->wdim /= 3 ;
|
||
|
}
|
||
|
if(im->wdim != 8 && im->wdim != 16 && im->wdim != 32 && im->wdim != 64)
|
||
|
{
|
||
|
fprintf (stderr,
|
||
|
"_readAnalyzeHeader: error: pixel size not supported (%d)...\n",
|
||
|
analyzeHeader->dime.bitpix );
|
||
|
return -1;
|
||
|
}
|
||
|
im->wdim >>= 3 ;
|
||
|
|
||
|
/* There are 17 optional data fields
|
||
|
be careful in the allocation
|
||
|
*/
|
||
|
im->nuser = 1 + 17 ;
|
||
|
im->user = (char **) ImageIO_alloc(im->nuser * sizeof(char *));
|
||
|
for ( i=0; i<im->nuser; i++ ) im->user[i] = nullptr;
|
||
|
i = 0 ;
|
||
|
|
||
|
im->user[i] = (char *) ImageIO_alloc((strlen("Data lost in the Analyze -> ImageIO conversion:") + 1));
|
||
|
sprintf( im->user[i++], "Data lost in the Analyze -> ImageIO conversion:" );
|
||
|
|
||
|
im->user[i] = (char *) ImageIO_alloc((strlen(" descrip: ") + 1 + strlen(analyzeHeader->hist.descrip) ));
|
||
|
sprintf( im->user[i++], " descrip: %s", analyzeHeader->hist.descrip );
|
||
|
|
||
|
im->user[i] = (char *) ImageIO_alloc((strlen(" aux_file: ") + 1 + strlen(analyzeHeader->hist.descrip) ));
|
||
|
sprintf( im->user[i++], " aux_file: %s", analyzeHeader->hist.descrip );
|
||
|
|
||
|
im->user[i] = (char *) ImageIO_alloc((strlen(" orient: ") + 1+ 2));
|
||
|
sprintf( im->user[i++], " orient: %d", analyzeHeader->hist.orient );
|
||
|
|
||
|
im->user[i] = (char *) ImageIO_alloc((strlen(" originator: ") + 1 + strlen(analyzeHeader->hist.originator) ));
|
||
|
sprintf( im->user[i++], " originator: %s", analyzeHeader->hist.originator );
|
||
|
|
||
|
im->user[i] = (char *) ImageIO_alloc((strlen(" generated: ") + 1 + strlen(analyzeHeader->hist.generated) ));
|
||
|
sprintf( im->user[i++], " generated: %s", analyzeHeader->hist.generated );
|
||
|
|
||
|
im->user[i] = (char *) ImageIO_alloc((strlen(" scannum: ") + 1 + strlen(analyzeHeader->hist.scannum) ));
|
||
|
sprintf( im->user[i++], " scannum: %s", analyzeHeader->hist.scannum );
|
||
|
|
||
|
im->user[i] = (char *) ImageIO_alloc((strlen(" patient_id: ") + 1 + strlen(analyzeHeader->hist.patient_id) ));
|
||
|
sprintf( im->user[i++], " patient_id: %s", analyzeHeader->hist.patient_id );
|
||
|
|
||
|
im->user[i] = (char *) ImageIO_alloc((strlen(" exp_date: ") + 1 + strlen(analyzeHeader->hist.exp_date) ));
|
||
|
sprintf( im->user[i++], " exp_date: %s", analyzeHeader->hist.exp_date );
|
||
|
|
||
|
im->user[i] = (char *) ImageIO_alloc((strlen(" exp_time: ") + 1 + strlen(analyzeHeader->hist.exp_time) ));
|
||
|
sprintf( im->user[i++], " exp_time: %s", analyzeHeader->hist.exp_time );
|
||
|
|
||
|
/* A 32 bit int doesn't print on more than 11 chars */
|
||
|
im->user[i] = (char *) ImageIO_alloc((strlen(" views: ") + 11 + 1));
|
||
|
sprintf( im->user[i++], " views: %d", analyzeHeader->hist.views );
|
||
|
|
||
|
im->user[i] = (char *) ImageIO_alloc((strlen(" vols_added: ") + 11 + 1));
|
||
|
sprintf( im->user[i++], " vols_added: %d", analyzeHeader->hist.vols_added );
|
||
|
|
||
|
im->user[i] = (char *) ImageIO_alloc((strlen(" start_field: ") + 11 + 1));
|
||
|
sprintf( im->user[i++], " start_field: %d", analyzeHeader->hist.start_field );
|
||
|
|
||
|
im->user[i] = (char *) ImageIO_alloc((strlen(" field_skip: ") + 11 + 1));
|
||
|
sprintf( im->user[i++], " field_skip: %d", analyzeHeader->hist.field_skip );
|
||
|
|
||
|
im->user[i] = (char *) ImageIO_alloc((strlen(" omax: ") + 11 + 1));
|
||
|
sprintf( im->user[i++], " omax: %d", analyzeHeader->hist.omax );
|
||
|
|
||
|
im->user[i] = (char *) ImageIO_alloc((strlen(" omin: ") + 11 + 1));
|
||
|
sprintf( im->user[i++], " omin: %d", analyzeHeader->hist.omin );
|
||
|
|
||
|
im->user[i] = (char *) ImageIO_alloc((strlen(" smax: ") + 11 + 1));
|
||
|
sprintf( im->user[i++], " smax: %d", analyzeHeader->hist.smax );
|
||
|
|
||
|
im->user[i] = (char *) ImageIO_alloc((strlen(" smin: ") + 11 + 1));
|
||
|
sprintf( im->user[i++], " smin: %d", analyzeHeader->hist.smin );
|
||
|
|
||
|
|
||
|
/* header is read. close header file and open data file. */
|
||
|
if( name != nullptr ) {
|
||
|
|
||
|
std::size_t length = strlen(name) ;
|
||
|
char* data_filename = (char *) ImageIO_alloc(length+4) ;
|
||
|
|
||
|
if( strcmp( name+length-4, ".hdr" ) )
|
||
|
{
|
||
|
fprintf (stderr,
|
||
|
"_readAnalyzeHeader: error: file header extension must be .hdr\n");
|
||
|
ImageIO_free( data_filename );
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
ImageIO_close(im);
|
||
|
|
||
|
strcpy(data_filename,name);
|
||
|
strcpy(data_filename+length-3, "img.gz");
|
||
|
_openReadImage(im,data_filename);
|
||
|
|
||
|
if(!im->fd) {
|
||
|
|
||
|
strcpy(data_filename,name);
|
||
|
strcpy(data_filename+length-3, "img");
|
||
|
_openReadImage(im,data_filename);
|
||
|
if(!im->fd) {
|
||
|
fprintf(stderr, "_readAnalyzeHeader: error: unable to open data file \'%s\'\n", data_filename);
|
||
|
ImageIO_free( data_filename );
|
||
|
return -1;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
ImageIO_free( data_filename );
|
||
|
}
|
||
|
|
||
|
/* check header validity */
|
||
|
if(im->xdim > 0 && im->ydim > 0 && im->zdim > 0 && im->vdim > 0 &&
|
||
|
im->vx > 0.0 && im->vy > 0.0 && im->vz > 0.0 &&
|
||
|
(im->wordKind == WK_FLOAT || (im->wordKind == WK_FIXED &&
|
||
|
im->sign != SGN_UNKNOWN)) &&
|
||
|
im->endianness != END_UNKNOWN) {
|
||
|
return 0;
|
||
|
}
|
||
|
else return -1;
|
||
|
}
|
||
|
else return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
CGAL_INLINE_FUNCTION
|
||
|
int readAnalyzeHeader( const char* name, _image* im)
|
||
|
{
|
||
|
struct dsr analyzeHeader ;
|
||
|
return( _readAnalyzeHeader( im, name, &analyzeHeader ) );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
CGAL_INLINE_FUNCTION
|
||
|
int
|
||
|
writeAnalyzeHeader( const _image* im )
|
||
|
{
|
||
|
const char *proc = "writeAnalyzeHeader";
|
||
|
struct dsr hdr;
|
||
|
int i ;
|
||
|
int imin = 0;
|
||
|
int imax = 0;
|
||
|
|
||
|
memset(&hdr,0, sizeof(struct dsr));
|
||
|
|
||
|
for(i=0;i<8;i++) {
|
||
|
hdr.dime.pixdim[i] = 0.0;
|
||
|
}
|
||
|
hdr.dime.vox_offset = 0.0;
|
||
|
hdr.dime.funused1 = 0.0;
|
||
|
hdr.dime.funused2 = 0.0;
|
||
|
hdr.dime.funused3 = 0.0;
|
||
|
hdr.dime.cal_max = 0.0;
|
||
|
hdr.dime.cal_min = 0.0;
|
||
|
|
||
|
hdr.dime.dim[0] = 4;
|
||
|
hdr.dime.dim[1] = short(im->xdim);
|
||
|
hdr.dime.dim[2] = short(im->ydim);
|
||
|
hdr.dime.dim[3] = short(im->zdim);
|
||
|
hdr.dime.dim[4] = 1 ;
|
||
|
|
||
|
if ( im->wordKind == WK_FIXED && im->sign == SGN_UNSIGNED ) {
|
||
|
if( im->wdim == 1 ) {
|
||
|
|
||
|
if ( im->vdim == 1 ) {
|
||
|
hdr.dime.datatype = DT_UNSIGNED_CHAR ;
|
||
|
}
|
||
|
else if ( im->vdim == 3 ) {
|
||
|
hdr.dime.datatype = DT_RGB ;
|
||
|
}
|
||
|
else {
|
||
|
fprintf( stderr, "%s: unsupported image type\n", proc );
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
{
|
||
|
unsigned char *buf = (unsigned char *)im->data;
|
||
|
std::size_t size = std::size_t(im->xdim) * im->ydim * im->zdim * im->vdim;
|
||
|
imin = imax = *buf;
|
||
|
for (std::size_t i=0; i<size; i++, buf++) {
|
||
|
if ( imax < *buf ) imax = *buf;
|
||
|
if ( imin > *buf ) imin = *buf;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else if ( im->wdim == 2 ) {
|
||
|
if ( im->vdim == 1 ) {
|
||
|
unsigned short int *buf = (unsigned short int*)im->data;
|
||
|
std::size_t size = std::size_t(im->xdim) * im->ydim *im->zdim;
|
||
|
imin = imax = *buf;
|
||
|
for (std::size_t i=0; i<size; i++, buf++) {
|
||
|
if ( imax < *buf ) imax = *buf;
|
||
|
if ( imin > *buf ) imin = *buf;
|
||
|
}
|
||
|
if ( imax < 32768 ) {
|
||
|
hdr.dime.datatype = DT_SIGNED_SHORT ;
|
||
|
}
|
||
|
else {
|
||
|
fprintf( stderr, "%s: conversion from unsigned short to short impossible, max=%d\n", proc, imax );
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
fprintf( stderr, "%s: unsupported image type\n", proc );
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
else {
|
||
|
fprintf( stderr, "%s: unsupported image type\n", proc );
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
} /* if ( im->wordKind == WK_FIXED && im->sign == SGN_UNSIGNED ) */
|
||
|
|
||
|
else if( im->wordKind == WK_FIXED && im->sign == SGN_SIGNED ) {
|
||
|
if ( im->vdim != 1 ) {
|
||
|
fprintf( stderr, "%s: unsupported image type\n", proc );
|
||
|
return -1;
|
||
|
}
|
||
|
if( im->wdim == 2 ) {
|
||
|
short int *buf = (short int*)im->data;
|
||
|
std::size_t size = std::size_t(im->xdim) * im->ydim *im->zdim;
|
||
|
imin = imax = *buf;
|
||
|
for (std::size_t i=0; i<size; i++, buf++) {
|
||
|
if ( imax < *buf ) imax = *buf;
|
||
|
if ( imin > *buf ) imin = *buf;
|
||
|
}
|
||
|
hdr.dime.datatype = DT_SIGNED_SHORT ;
|
||
|
}
|
||
|
else if( im->wdim == 4 ) {
|
||
|
int *buf = (int*)im->data;
|
||
|
std::size_t size = std::size_t(im->xdim) * im->ydim *im->zdim;
|
||
|
imin = imax = *buf;
|
||
|
for (std::size_t i=0; i<size; i++, buf++) {
|
||
|
if ( imax < *buf ) imax = *buf;
|
||
|
if ( imin > *buf ) imin = *buf;
|
||
|
}
|
||
|
hdr.dime.datatype = DT_SIGNED_INT ;
|
||
|
}
|
||
|
else {
|
||
|
fprintf( stderr, "%s: unsupported image type\n", proc );
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
else if( im->wordKind == WK_FLOAT ) {
|
||
|
if ( im->vdim != 1 ) {
|
||
|
fprintf( stderr, "%s: unsupported image type\n", proc );
|
||
|
return -1;
|
||
|
}
|
||
|
if( im->wdim == 4 ) {
|
||
|
hdr.dime.datatype = DT_FLOAT ;
|
||
|
}
|
||
|
else if( im->wdim == 8 ) {
|
||
|
hdr.dime.datatype = DT_DOUBLE ;
|
||
|
}
|
||
|
else {
|
||
|
fprintf( stderr, "%s: unsupported image type\n", proc );
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fprintf( stderr, "%s: unsupported image type\n", proc );
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
hdr.dime.bitpix = short(8*im->wdim*im->vdim) ;
|
||
|
|
||
|
hdr.hk.regular = 'r';
|
||
|
hdr.hk.sizeof_hdr = sizeof(struct dsr);
|
||
|
|
||
|
/* this is probably bad and should be changed to the
|
||
|
real values, but I'm too lazy to do it now. AG */
|
||
|
hdr.dime.glmax = 0 ; /* maximum voxel value */
|
||
|
hdr.dime.glmin = 0 ; /* minimum voxel value */
|
||
|
|
||
|
/* corrected GM
|
||
|
*/
|
||
|
hdr.dime.glmax = imax ; /* maximum voxel value */
|
||
|
hdr.dime.glmin = imin ; /* minimum voxel value */
|
||
|
|
||
|
/* Set the voxel dimension fields:
|
||
|
A value of 0.0 for these fields implies that the value is unknown.
|
||
|
Change these values to what is appropriate for your data
|
||
|
or pass additional command line arguments */
|
||
|
|
||
|
hdr.dime.pixdim[1] = (float)im->vx;
|
||
|
hdr.dime.pixdim[2] = (float)im->vy;
|
||
|
hdr.dime.pixdim[3] = (float)im->vz;
|
||
|
|
||
|
/* Assume zero offset in .img file, byte at which pixel
|
||
|
data starts in the image file */
|
||
|
|
||
|
hdr.dime.vox_offset = 0.0;
|
||
|
|
||
|
/* Planar Orientation; */
|
||
|
/* Movie flag OFF: 0 = transverse, 1 = coronal, 2 = sagittal
|
||
|
Movie flag ON: 3 = transverse, 4 = coronal, 5 = sagittal */
|
||
|
|
||
|
hdr.hist.orient = 0;
|
||
|
|
||
|
/* up to 3 characters for the voxels units label; i.e. mm., um., cm. */
|
||
|
|
||
|
strcpy(hdr.dime.vox_units,"mm.");
|
||
|
|
||
|
/* up to 7 characters for the calibration units label; i.e. HU */
|
||
|
|
||
|
strcpy(hdr.dime.cal_units," ");
|
||
|
|
||
|
/* Calibration maximum and minimum values;
|
||
|
values of 0.0 for both fields imply that no
|
||
|
calibration max and min values are used */
|
||
|
|
||
|
hdr.dime.cal_max = 0.0;
|
||
|
hdr.dime.cal_min = 0.0;
|
||
|
|
||
|
if(ImageIO_write(im, &hdr, sizeof(struct dsr)) !=sizeof(struct dsr) )
|
||
|
return -1;
|
||
|
|
||
|
return 1 ;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/* Writes the given image body in an already opened file.*/
|
||
|
CGAL_INLINE_FUNCTION
|
||
|
int writeAnalyzeData(const _image *im) {
|
||
|
std::size_t lineSize = std::size_t(im->wdim) * im->xdim * im->vdim ;
|
||
|
std::size_t size = lineSize * im->ydim * im->zdim;
|
||
|
std::size_t nwrt ;
|
||
|
|
||
|
if(im->openMode != OM_CLOSE) {
|
||
|
|
||
|
#ifdef _REVERSE_LINES_IN_ANALYZE_
|
||
|
char* data = (char *)im->data ;
|
||
|
char* buf = data + size - lineSize ;
|
||
|
|
||
|
while( buf >= data )
|
||
|
{
|
||
|
nwrt = ImageIO_write(im, buf, lineSize);
|
||
|
if(nwrt != lineSize) return -1;
|
||
|
buf -= lineSize ;
|
||
|
}
|
||
|
#else
|
||
|
nwrt = ImageIO_write(im, im->data, size);
|
||
|
if(nwrt != size) return -1;
|
||
|
#endif
|
||
|
|
||
|
return 1 ;
|
||
|
}
|
||
|
else return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Writes the given image body in an already opened file.*/
|
||
|
CGAL_INLINE_FUNCTION
|
||
|
int printAnalyzeHeader( const char* name )
|
||
|
{
|
||
|
_image *im;
|
||
|
struct dsr analyzeHeader ;
|
||
|
|
||
|
im = _initImage();
|
||
|
_openReadImage(im, name);
|
||
|
if(!im->fd) {
|
||
|
fprintf(stderr, "printAnalyzeHeader: error: unable to open file \'%s\'\n", name);
|
||
|
_freeImage(im);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if ( _readAnalyzeHeader( im, name, &analyzeHeader ) != 1 ) {
|
||
|
fprintf(stderr, "printAnalyzeHeader: error: unable to read header in file \'%s\'\n", name);
|
||
|
_freeImage(im);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
ImageIO_close(im);
|
||
|
im->fd = nullptr;
|
||
|
im->openMode = OM_CLOSE;
|
||
|
_freeImage(im);
|
||
|
return( 1 );
|
||
|
|
||
|
|
||
|
}
|