/* ----------------------------------------------------------------------
* This is an interface for processing GEMS 4.x image files
* (see ge4_header.h for structure contents).
* ----------------------------------------------------------------------
* int ge4_read_header( char * filename, ge4_header * H )
*
* The basic point is to pass an empty ge4_header structure in,
* along with a file name. This function fills the structure.
*
* One exception: if H->image is non-null, this function will
* read the image into that location.
*
* - returns 0 on success
*
* R. Reynolds 2003 April 29
* ----------------------------------------------------------------------
*/
/* ----------------------------------------------------------------------
* history:
*
* June 12, 2003
* - fixed static warnings
*
* June 03, 2003
* - added doxygen style header (for ge4_read_header())
* - added get_image param to ge4_read_header()
* - swap bytes in image
* - added local static for swap_[24]()
* ----------------------------------------------------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ge4_header.h"
/* comes from either Imon.o or libmri.a */
extern long long THD_filesize ( char * pathname ); /* in thd_filestuff.c */
/* local protos */
static int swap_2 ( void * ptr );
static int swap_4 ( void * ptr );
static int swap_2_multi( void * ptr, int num_shorts );
/* ---------------------------------------------------------------------- */
/* series header value descriptions - for display */
static char * g_ge4_sl_im_modes[] =
{ "2D single", "2D multiple", "3D volume", "cine",
"spectroscopy" };
static char * g_ge4_sl_pulse_seqs[] =
{ "memp", "ir", "ps", "rm", "rmge", "gre", "vemp",
"mpgr", "mpgrv", "mpirs", "mpiri", "3d/gre",
"cine/gre", "spgr", "sspf", "cin/spgr", "3d/spgr",
"fse", "fve", "fspr", "fgr", "fmpspgr", "fmpgr",
"fmpir", "probe.s", "probe.p" };
static char * g_ge4_sl_orient[] = { "supine", "prone", "Lt", "Rt" };
/* ---------------------------------------------------------------------- */
/*! Validate and read header data from a GEMS 4.x formatted file.
\param filename is the name of the file to try to read
\param H is the address of a ge4_header struct to be initialized and filled
\param get_image specifies whether to allocate for and read in the image
\return 0 : on success
< 0 : on error
*/
int ge4_read_header( ge4_header * H, char * filename, int get_image )
{
ge4_image_t * ih;
ge4_series_t * sh;
ge4_study_t * st;
FILE * fp;
long long file_len;
int rres = 0; /* read result */
if ( filename == NULL || H == NULL )
{
fprintf( stderr, "** rg4h : bad params: %p, %p\n", filename, H );
return -1;
}
file_len = THD_filesize( filename );
/* file size must be fixed at 145408 bytes (142 KB) */
if ( file_len != (GE4_HEADER_LENGTH + GE4_IMAGE_SIZE) ) return 1;
/* clear structure */
memset( H, 0, sizeof(ge4_header) );
if ( (fp = fopen( filename, "r" )) == NULL )
{
fprintf( stderr, "ge4_read_header: failed to open '%s' for reading\n",
filename);
return -1;
}
/* quickly scan and validate titles */
sh = &H->ser_h; /* set helper pointer */
ih = &H->im_h; /* set helper pointer */
st = &H->std_h; /* set helper pointer */
fseek( fp, GE4_OFF_STDY_TITLE, SEEK_SET );
rres |= (1 - fread( st->title, GE4_L_STDY_TITLE, 1, fp ));
fseek( fp, GE4_OFF_SER_TITLE, SEEK_SET );
rres |= (1 - fread( sh->title, GE4_L_SER_TITLE, 1, fp ));
fseek( fp, GE4_OFF_IMG_TITLE, SEEK_SET );
rres |= (1 - fread( ih->title, GE4_L_IM_TITLE, 1, fp ));
/* if read failure or bad title fields, we're outta' here */
if ( rres ||
strncmp( st->title, GE4_STUDY_TITLE, GE4_L_STDY_TITLE ) ||
strncmp( sh->title, GE4_SERIES_TITLE, GE4_L_SER_TITLE ) ||
strncmp( ih->title, GE4_IMAGE_TITLE, GE4_L_IM_TITLE )
)
return 1;
/* study header fields */
fseek( fp, GE4_OFF_STDY_NUM, SEEK_SET );
rres |= (1 - fread( st->num, GE4_L_STDY_NUM, 1, fp ));
fseek( fp, GE4_OFF_STDY_DATE, SEEK_SET );
rres |= (1 - fread( st->date, GE4_L_STDY_DATE, 1, fp ));
fseek( fp, GE4_OFF_STDY_TIME, SEEK_SET );
rres |= (1 - fread( st->time, GE4_L_STDY_TIME, 1, fp ));
fseek( fp, GE4_OFF_STDY_PAT_NAME, SEEK_SET );
rres |= (1 - fread( st->pat_name, GE4_L_STDY_PAT_NAME, 1, fp ));
fseek( fp, GE4_OFF_STDY_PAT_ID, SEEK_SET );
rres |= (1 - fread( st->pat_id, GE4_L_STDY_PAT_ID, 1, fp ));
fseek( fp, GE4_OFF_STDY_AGE, SEEK_SET );
rres |= (1 - fread( st->age, GE4_L_STDY_AGE, 1, fp ));
fseek( fp, GE4_OFF_STDY_SEX, SEEK_SET );
rres |= (1 - fread( &st->sex, 1, 1, fp ));
/* series header fields */
fseek( fp, GE4_OFF_SER_SERIES_NUM, SEEK_SET );
rres |= (1 - fread( sh->series_num, GE4_L_SER_SER_NUM, 1, fp ));
fseek( fp, GE4_OFF_SER_PLANE_TYPE, SEEK_SET );
rres |= (1 - fread( &sh->plane_type, sizeof(sh->plane_type), 1, fp ));
fseek( fp, GE4_OFF_SER_PLANE_DESC, SEEK_SET );
rres |= (1 - fread( sh->plane_desc, GE4_L_SER_PL_DESC, 1, fp ));
fseek( fp, GE4_OFF_SER_IM_MODE, SEEK_SET );
rres |= (1 - fread( &sh->im_mode, sizeof(sh->im_mode), 1, fp ));
fseek( fp, GE4_OFF_SER_PULSE_SEQ, SEEK_SET );
rres |= (1 - fread( &sh->pulse_seq, sizeof(sh->pulse_seq), 1, fp ));
fseek( fp, GE4_OFF_SER_FOV, SEEK_SET );
rres |= (1 - fread( &sh->fov, sizeof(sh->fov), 1, fp ));
fseek( fp, GE4_OFF_SER_CENTER, SEEK_SET );
rres |= (1 - fread( sh->center, sizeof(sh->center), 1, fp ));
fseek( fp, GE4_OFF_SER_ORIENT, SEEK_SET );
rres |= (1 - fread( &sh->orient, sizeof(sh->orient), 1, fp ));
fseek( fp, GE4_OFF_SER_SCAN_MAT_X, SEEK_SET );
rres |= (1 - fread( &sh->scan_mat_x, sizeof(sh->scan_mat_x), 1, fp ));
fseek( fp, GE4_OFF_SER_SCAN_MAT_Y, SEEK_SET );
rres |= (1 - fread( &sh->scan_mat_y, sizeof(sh->scan_mat_y), 1, fp ));
fseek( fp, GE4_OFF_SER_IM_MAT, SEEK_SET );
rres |= (1 - fread( &sh->im_mat, sizeof(sh->im_mat), 1, fp ));
/* image header fields */
fseek( fp, GE4_OFF_IMG_IM_NUM, SEEK_SET );
rres |= (1 - fread( ih->im_num, GE4_L_IM_NUM, 1, fp ));
fseek( fp, GE4_OFF_IMG_IM_LOCN, SEEK_SET );
rres |= (1 - fread( &ih->im_loc, sizeof(ih->im_loc), 1, fp ));
fseek( fp, GE4_OFF_IMG_TABLE_POSN, SEEK_SET );
rres |= (1 - fread( &ih->table_posn, sizeof(ih->table_posn), 1, fp ));
fseek( fp, GE4_OFF_IMG_IM_THICK, SEEK_SET );
rres |= (1 - fread( &ih->im_thickness, sizeof(ih->im_thickness), 1, fp ));
fseek( fp, GE4_OFF_IMG_IM_SPACING, SEEK_SET );
rres |= (1 - fread( &ih->im_spacing, sizeof(ih->im_spacing), 1, fp ));
fseek( fp, GE4_OFF_IMG_TR, SEEK_SET );
rres |= (1 - fread( &ih->tr, sizeof(ih->tr), 1, fp ));
fseek( fp, GE4_OFF_IMG_TE, SEEK_SET );
rres |= (1 - fread( &ih->te, sizeof(ih->te), 1, fp ));
fseek( fp, GE4_OFF_IMG_TI, SEEK_SET );
rres |= (1 - fread( &ih->ti, sizeof(ih->ti), 1, fp ));
fseek( fp, GE4_OFF_IMG_NUM_ECHOS, SEEK_SET );
rres |= (1 - fread( &ih->num_echoes, sizeof(ih->num_echoes), 1, fp ));
fseek( fp, GE4_OFF_IMG_ECHO_NUM, SEEK_SET );
rres |= (1 - fread( &ih->echo_num, sizeof(ih->echo_num), 1, fp ));
fseek( fp, GE4_OFF_IMG_NEX_INT, SEEK_SET );
rres |= (1 - fread( &ih->iNEX, sizeof(ih->iNEX), 1, fp ));
fseek( fp, GE4_OFF_IMG_NEX_REAL, SEEK_SET );
rres |= (1 - fread( &ih->fNEX, sizeof(ih->fNEX), 1, fp ));
fseek( fp, GE4_OFF_IMG_FLIP_ANGLE, SEEK_SET );
rres |= (1 - fread( &ih->flip_angle, sizeof(ih->flip_angle), 1, fp ));
if ( rres )
{
fprintf( stderr, "** failed to read ge4 header for '%s'\n", filename );
return -1;
}
if ( ge4_validate_header( H ) )
return 1;
if ( get_image )
{
if ( (H->image = (short *)malloc( GE4_IMAGE_SIZE )) == NULL )
{
fprintf( stderr, "** failed to allocate %d bytes for image\n",
GE4_IMAGE_SIZE );
return -1;
}
fseek( fp, GE4_HEADER_LENGTH, SEEK_SET );
rres = fread( H->image, GE4_IMAGE_SIZE, 1, fp );
if ( rres != 1 )
{
fprintf( stderr, "** failed to read ge4 image for file '%s'\n",
filename );
free( H->image );
return -1;
}
H->im_bytes = GE4_IMAGE_SIZE; /* note it for "outsiders" */
if ( H->swap )
swap_2_multi( H->image, GE4_IMAGE_SIZE/2 );
}
return 0;
}
/*------------------------------------------------------------
* Check for valid data in the header.
*
* If values are out of range, try byte swapping.
*
* series header:
* plane_type : in {0..4}
* image_mode : in {0..4}
* pulse_seq : in {0..25}
*
* return 0 : valid
* else : invalid
*------------------------------------------------------------
*/
int ge4_validate_header( ge4_header * h )
{
ge4_series_t * s;
ge4_image_t * im;
if ( h == NULL )
return -1;
s = &h->ser_h;
im = &h->im_h;
/* note that titles have already been validated */
if ( (s->plane_type < 0) || (s->plane_type > 4) ||
(s->im_mode < 0) || (s->im_mode > 4) ||
(s->pulse_seq < 0) || (s->pulse_seq > 25) )
{
ge4_swap_all_bytes( h );
}
/* if these are still off, we are hosed... */
if ( (s->plane_type < 0) || (s->plane_type > 4) ||
(s->im_mode < 0) || (s->im_mode > 4) ||
(s->pulse_seq < 0) || (s->pulse_seq > 25) )
{
return -1;
}
return 0;
}
/*------------------------------------------------------------
* Swap all numeric fields in ge4_header sub-structs.
*------------------------------------------------------------
*/
int ge4_swap_all_bytes( ge4_header * h )
{
if ( h == NULL )
{
fprintf( stderr, "** ge4_SAB : no header!\n" );
return -1;
}
h->swap = 1; /* note that we have swapped */
/* series header */
swap_2( &h->ser_h.plane_type );
swap_2( &h->ser_h.im_mode );
swap_2( &h->ser_h.pulse_seq );
swap_4( &h->ser_h.fov );
swap_4( &h->ser_h.center[0] );
swap_4( &h->ser_h.center[1] );
swap_4( &h->ser_h.center[2] );
swap_2( &h->ser_h.orient );
swap_2( &h->ser_h.scan_mat_x );
swap_2( &h->ser_h.scan_mat_y );
swap_2( &h->ser_h.im_mat );
/* image header */
swap_4( &h->im_h.im_loc );
swap_4( &h->im_h.table_posn );
swap_4( &h->im_h.im_thickness );
swap_4( &h->im_h.im_spacing );
swap_4( &h->im_h.tr );
swap_4( &h->im_h.te );
swap_4( &h->im_h.ti );
swap_2( &h->im_h.num_echoes );
swap_2( &h->im_h.echo_num );
swap_2( &h->im_h.iNEX );
swap_4( &h->im_h.fNEX );
swap_2( &h->im_h.flip_angle );
return 0;
}
/*------------------------------------------------------------
* Display the contents of the ge4_image_t struct.
*------------------------------------------------------------
*/
int idisp_ge4_study_header( char * info, ge4_study_t * st )
{
if ( info )
fputs( info, stdout );
if ( st == NULL )
{
printf( "r_idisp_ge4_study_t: st == NULL" );
return -1;
}
printf( " ge4_study_t at %p :\n"
" title = %s\n"
" num = %s\n"
" date = %s\n"
" time = %s\n"
" pat_name = %s\n"
" pat_id = %s\n"
" age = %s\n"
" sex = %c\n",
st, st->title, st->num, st->date, st->time,
st->pat_name, st->pat_id, st->age, st->sex
);
return 0;
}
/*------------------------------------------------------------
* Display the contents of the ge4_image_t struct.
*------------------------------------------------------------
*/
int idisp_ge4_image_header( char * info, ge4_image_t * im )
{
if ( info )
fputs( info, stdout );
if ( im == NULL )
{
printf( "r_idisp_ge4_image_t: im == NULL" );
return -1;
}
printf( " ge4_image_t at %p :\n"
" title = %s\n"
" im_num = %s\n"
" im_loc = %.3f\n"
" table_posn = %.3f\n"
" im_thickness = %.3f\n"
" im_spacing = %.3f\n"
" tr (in ms) = %.3f\n"
" te (in ms) = %.3f\n"
" ti (in ms) = %.3f\n"
" num_echoes = %d\n"
" echo_num = %d\n"
" iNEX = %d\n"
" fNEX = %.3f\n"
" flip_angle = %d\n",
im, im->title, im->im_num, im->im_loc, im->table_posn,
im->im_thickness, im->im_spacing, im->tr, im->te, im->ti,
im->num_echoes, im->echo_num, im->iNEX, im->fNEX, im->flip_angle
);
return 0;
}
/*------------------------------------------------------------
* Display the contents of the ge4_series_t struct.
*------------------------------------------------------------
*/
int idisp_ge4_series_header( char * info, ge4_series_t * s )
{
if ( info )
fputs( info, stdout );
if ( s == NULL )
{
printf( "r_idisp_ge4_series_t: s == NULL" );
return -1;
}
printf( " ge4_series_t at %p :\n"
" title = %s\n"
" series_num = %s\n"
" plane_type, plane_desc = %d, %s\n"
" image_mode = %d (%s)\n"
" pulse_seq = %d (%s)\n"
" FOV (in mm) = %.3f\n"
" center[0], c[1], c[2] = %.3f, %.3f, %.3f\n"
" orient = %d (%s)\n"
" scan_mat_x, scan_mat_y = %d, %d\n"
" im_mat = %d\n",
s, s->title, s->series_num, s->plane_type, s->plane_desc,
s->im_mode, GE4M_IND2STR(s->im_mode, g_ge4_sl_im_modes),
s->pulse_seq, GE4M_IND2STR(s->pulse_seq, g_ge4_sl_pulse_seqs),
s->fov, s->center[0], s->center[1], s->center[2],
s->orient, GE4M_IND2STR(s->orient,g_ge4_sl_orient),
s->scan_mat_x, s->scan_mat_y, s->im_mat
);
return 0;
}
/*------------------------------------------------------------
* Swap multiple byte pairs.
*------------------------------------------------------------
*/
static int swap_2_multi( void * ptr, int num_shorts )
{
unsigned char * cp0, * cp1;
unsigned char tmpc;
int index;
if ( ptr == NULL ) return -1;
cp0 = (unsigned char *)ptr;
cp1 = cp0 + 1;
for ( index = 0; index < num_shorts; index++ )
{
tmpc = *cp0;
*cp0 = *cp1;
*cp1 = tmpc;
cp0 += 2;
cp1 += 2;
}
return 0;
}
/*------------------------------------------------------------
* Reverse the order of the 4 bytes at this address.
*------------------------------------------------------------
*/
static int swap_4( void * ptr ) /* destructive */
{
unsigned char * addr = ptr;
addr[0] ^= addr[3]; addr[3] ^= addr[0]; addr[0] ^= addr[3];
addr[1] ^= addr[2]; addr[2] ^= addr[1]; addr[1] ^= addr[2];
return 0;
}
/*------------------------------------------------------------
* Reverse the order of the 2 bytes at this address.
*------------------------------------------------------------
*/
static int swap_2( void * ptr ) /* destructive */
{
unsigned char * addr = ptr;
addr[0] ^= addr[1]; addr[1] ^= addr[0]; addr[0] ^= addr[1];
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1