From 03069261bbef2551f1d655b8233b05b2c725521b Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Wed, 14 Dec 2011 14:49:23 +0000 Subject: [PATCH] start moving analyze load over --- libvips/foreign/analyze2vips.h | 45 +++ libvips/foreign/anlyze2vips.c | 581 +++++++++++++++++++++++++++++++++ libvips/foreign/dbh.h | 98 ++++++ 3 files changed, 724 insertions(+) create mode 100644 libvips/foreign/analyze2vips.h create mode 100644 libvips/foreign/anlyze2vips.c create mode 100644 libvips/foreign/dbh.h diff --git a/libvips/foreign/analyze2vips.h b/libvips/foreign/analyze2vips.h new file mode 100644 index 00000000..a2a8e206 --- /dev/null +++ b/libvips/foreign/analyze2vips.h @@ -0,0 +1,45 @@ +/* common defs for tiff read/write + */ + +/* + + Copyright (C) 1991-2005 The National Gallery + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + */ + +/* + + These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk + + */ + +#ifndef VIPS_ANALYZE_H +#define VIPS_ANALYZE_H + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +int vips__isanalyze( const char *filename ); +int vips__analyze_read_header( const char *filename, VipsImage *out ); +int vips__analyze_read( const char *filename, VipsImage *out ) + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /*VIPS_ANALYZE_H*/ diff --git a/libvips/foreign/anlyze2vips.c b/libvips/foreign/anlyze2vips.c new file mode 100644 index 00000000..6bfaee4d --- /dev/null +++ b/libvips/foreign/anlyze2vips.c @@ -0,0 +1,581 @@ +/* Read a Analyze file. Old-style header (so called 7.5 format). + * + * 3/8/05 + * - dbh.h header from Ralph Myers + * 22/8/05 + * - better byteswapper + * 12/5/09 + * - fix signed/unsigned warning + * 13/1/09 + * - try harder not to generate error messages in "isanalyze" + * 4/2/10 + * - gtkdoc + * 14/12/11 + * - redo as a set of fns ready for wrapping in a new-style class + */ + +/* + + This file is part of VIPS. + + VIPS is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + */ + +/* + + These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk + + */ + +/* + */ +#define DEBUG + +#ifdef HAVE_CONFIG_H +#include +#endif /*HAVE_CONFIG_H*/ +#include + +#include +#include +#include +#include + +#include +#include + +#include "dbh.h" + +/* The things we can have in header fields. Can't use GType, since we want a + * static value we can use in a declaration. + */ +typedef enum { + BYTE, + SHORT, + INT, + FLOAT, + STRING +} Type; + +/* A field in the dsr header. + */ +typedef struct { + const char *name; /* Eg. "header_key.sizeof_hdr" */ + Type type; + glong offset; /* Offset in struct */ + int len; /* Sizeof ... useful for string types */ +} Field; + +static Field dsr_header[] = { + { "dsr-header_key.sizeof_hdr", INT, + G_STRUCT_OFFSET( struct dsr, hk.sizeof_hdr ), 4 }, + { "dsr-header_key.data_type", STRING, + G_STRUCT_OFFSET( struct dsr, hk.data_type ), 10 }, + { "dsr-header_key.db_name", STRING, + G_STRUCT_OFFSET( struct dsr, hk.db_name ), 18 }, + { "dsr-header_key.extents", INT, + G_STRUCT_OFFSET( struct dsr, hk.extents ), 4 }, + { "dsr-header_key.session_error", SHORT, + G_STRUCT_OFFSET( struct dsr, hk.session_error ), 2 }, + { "dsr-header_key.regular", BYTE, + G_STRUCT_OFFSET( struct dsr, hk.regular ), 1 }, + { "dsr-header_key.hkey_un0", BYTE, + G_STRUCT_OFFSET( struct dsr, hk.hkey_un0 ), 1 }, + + { "dsr-image_dimension.dim[0]", SHORT, + G_STRUCT_OFFSET( struct dsr, dime.dim[0] ), 2 }, + { "dsr-image_dimension.dim[1]", SHORT, + G_STRUCT_OFFSET( struct dsr, dime.dim[1] ), 2 }, + { "dsr-image_dimension.dim[2]", SHORT, + G_STRUCT_OFFSET( struct dsr, dime.dim[2] ), 2 }, + { "dsr-image_dimension.dim[3]", SHORT, + G_STRUCT_OFFSET( struct dsr, dime.dim[3] ), 2 }, + { "dsr-image_dimension.dim[4]", SHORT, + G_STRUCT_OFFSET( struct dsr, dime.dim[4] ), 2 }, + { "dsr-image_dimension.dim[5]", SHORT, + G_STRUCT_OFFSET( struct dsr, dime.dim[5] ), 2 }, + { "dsr-image_dimension.dim[6]", SHORT, + G_STRUCT_OFFSET( struct dsr, dime.dim[6] ), 2 }, + { "dsr-image_dimension.dim[7]", SHORT, + G_STRUCT_OFFSET( struct dsr, dime.dim[7] ), 2 }, + { "dsr-image_dimension.vox_units[0]", BYTE, + G_STRUCT_OFFSET( struct dsr, dime.vox_units[0] ), 1 }, + { "dsr-image_dimension.vox_units[1]", BYTE, + G_STRUCT_OFFSET( struct dsr, dime.vox_units[1] ), 1 }, + { "dsr-image_dimension.vox_units[2]", BYTE, + G_STRUCT_OFFSET( struct dsr, dime.vox_units[2] ), 1 }, + { "dsr-image_dimension.vox_units[3]", BYTE, + G_STRUCT_OFFSET( struct dsr, dime.vox_units[3] ), 1 }, + { "dsr-image_dimension.cal_units[0]", BYTE, + G_STRUCT_OFFSET( struct dsr, dime.cal_units[0] ), 1 }, + { "dsr-image_dimension.cal_units[1]", BYTE, + G_STRUCT_OFFSET( struct dsr, dime.cal_units[1] ), 1 }, + { "dsr-image_dimension.cal_units[2]", BYTE, + G_STRUCT_OFFSET( struct dsr, dime.cal_units[2] ), 1 }, + { "dsr-image_dimension.cal_units[3]", BYTE, + G_STRUCT_OFFSET( struct dsr, dime.cal_units[3] ), 1 }, + { "dsr-image_dimension.cal_units[4]", BYTE, + G_STRUCT_OFFSET( struct dsr, dime.cal_units[4] ), 1 }, + { "dsr-image_dimension.cal_units[5]", BYTE, + G_STRUCT_OFFSET( struct dsr, dime.cal_units[5] ), 1 }, + { "dsr-image_dimension.cal_units[6]", BYTE, + G_STRUCT_OFFSET( struct dsr, dime.cal_units[6] ), 1 }, + { "dsr-image_dimension.cal_units[7]", BYTE, + G_STRUCT_OFFSET( struct dsr, dime.cal_units[7] ), 1 }, + { "dsr-image_dimension.data_type", SHORT, + G_STRUCT_OFFSET( struct dsr, dime.datatype ), 2 }, + { "dsr-image_dimension.bitpix", SHORT, + G_STRUCT_OFFSET( struct dsr, dime.bitpix ), 2 }, + { "dsr-image_dimension.dim_un0", SHORT, + G_STRUCT_OFFSET( struct dsr, dime.dim_un0 ), 2 }, + { "dsr-image_dimension.pixdim[0]", FLOAT, + G_STRUCT_OFFSET( struct dsr, dime.pixdim[0] ), 4 }, + { "dsr-image_dimension.pixdim[1]", FLOAT, + G_STRUCT_OFFSET( struct dsr, dime.pixdim[1] ), 4 }, + { "dsr-image_dimension.pixdim[2]", FLOAT, + G_STRUCT_OFFSET( struct dsr, dime.pixdim[2] ), 4 }, + { "dsr-image_dimension.pixdim[3]", FLOAT, + G_STRUCT_OFFSET( struct dsr, dime.pixdim[3] ), 4 }, + { "dsr-image_dimension.pixdim[4]", FLOAT, + G_STRUCT_OFFSET( struct dsr, dime.pixdim[4] ), 4 }, + { "dsr-image_dimension.pixdim[5]", FLOAT, + G_STRUCT_OFFSET( struct dsr, dime.pixdim[5] ), 4 }, + { "dsr-image_dimension.pixdim[6]", FLOAT, + G_STRUCT_OFFSET( struct dsr, dime.pixdim[6] ), 4 }, + { "dsr-image_dimension.pixdim[7]", FLOAT, + G_STRUCT_OFFSET( struct dsr, dime.pixdim[7] ), 4 }, + { "dsr-image_dimension.vox_offset", FLOAT, + G_STRUCT_OFFSET( struct dsr, dime.vox_offset ), 4 }, + { "dsr-image_dimension.cal_max", FLOAT, + G_STRUCT_OFFSET( struct dsr, dime.cal_max ), 4 }, + { "dsr-image_dimension.cal_min", FLOAT, + G_STRUCT_OFFSET( struct dsr, dime.cal_min ), 4 }, + { "dsr-image_dimension.compressed", INT, + G_STRUCT_OFFSET( struct dsr, dime.compressed ), 4 }, + { "dsr-image_dimension.verified", INT, + G_STRUCT_OFFSET( struct dsr, dime.verified ), 4 }, + { "dsr-image_dimension.glmax", INT, + G_STRUCT_OFFSET( struct dsr, dime.glmax ), 4 }, + { "dsr-image_dimension.glmin", INT, + G_STRUCT_OFFSET( struct dsr, dime.glmin ), 4 }, + + { "dsr-data_history.descrip", STRING, + G_STRUCT_OFFSET( struct dsr, hist.descrip ), 80 }, + { "dsr-data_history.aux_file", STRING, + G_STRUCT_OFFSET( struct dsr, hist.aux_file ), 24 }, + { "dsr-data_history.orient", BYTE, + G_STRUCT_OFFSET( struct dsr, hist.orient ), 1 }, + { "dsr-data_history.originator", STRING, + G_STRUCT_OFFSET( struct dsr, hist.originator ), 10 }, + { "dsr-data_history.generated", STRING, + G_STRUCT_OFFSET( struct dsr, hist.generated ), 10 }, + { "dsr-data_history.scannum", STRING, + G_STRUCT_OFFSET( struct dsr, hist.scannum ), 10 }, + { "dsr-data_history.patient_id", STRING, + G_STRUCT_OFFSET( struct dsr, hist.patient_id ), 10 }, + { "dsr-data_history.exp_date", STRING, + G_STRUCT_OFFSET( struct dsr, hist.exp_date ), 10 }, + { "dsr-data_history.exp_time", STRING, + G_STRUCT_OFFSET( struct dsr, hist.exp_time ), 10 }, + { "dsr-data_history.hist_un0", STRING, + G_STRUCT_OFFSET( struct dsr, hist.hist_un0 ), 3 }, + { "dsr-data_history.views", INT, + G_STRUCT_OFFSET( struct dsr, hist.views ), 4 }, + { "dsr-data_history.vols_added", INT, + G_STRUCT_OFFSET( struct dsr, hist.vols_added ), 4 }, + { "dsr-data_history.start_field", INT, + G_STRUCT_OFFSET( struct dsr, hist.start_field ), 4 }, + { "dsr-data_history.field_skip", INT, + G_STRUCT_OFFSET( struct dsr, hist.field_skip ), 4 }, + { "dsr-data_history.omax", INT, + G_STRUCT_OFFSET( struct dsr, hist.omax ), 4 }, + { "dsr-data_history.omin", INT, + G_STRUCT_OFFSET( struct dsr, hist.omin ), 4 }, + { "dsr-data_history.smax", INT, + G_STRUCT_OFFSET( struct dsr, hist.smax ), 4 }, + { "dsr-data_history.smin", INT, + G_STRUCT_OFFSET( struct dsr, hist.smin ), 4 } +}; + +/* Given a filename, generate the names for the header and the image data. + * + * Eg. + * "fred" -> "fred.hdr", "fred.img" + * "fred.img" -> "fred.hdr", "fred.img" + */ +static void +generate_filenames( const char *path, char *header, char *image ) +{ + char name[FILENAME_MAX]; + char mode[FILENAME_MAX]; + + const char *olds[] = { ".img", ".hdr" }; + + vips__change_suffix( name, header, FILENAME_MAX, ".hdr", olds, 2 ); + vips__change_suffix( name, image, FILENAME_MAX, ".img", olds, 2 ); +} + +/* str is a str which may not be NULL-terminated. Return a pointer to a static + * buffer with a NULL-terminated version so we can safely printf() the string. + * Also, make sure the string is plain ascii. + */ +static char * +getstr( int mx, const char *str ) +{ + static char buf[256]; + int i; + + g_assert( mx < 256 ); + + strncpy( buf, str, mx ); + buf[mx]= '\0'; + + /* How annoying, patient_id has some funny ctrlchars in that mess up + * xml encode later. + */ + for( i = 0; i < mx && buf[i]; i++ ) + if( !isascii( buf[i] ) || buf[i] < 32 ) + buf[i] = '@'; + + return( buf ); +} + +#ifdef DEBUG +static void +print_dsr( struct dsr *d ) +{ + int i; + + for( i = 0; i < VIPS_NUMBER( dsr_header ); i++ ) { + printf( "%s = ", dsr_header[i].name ); + + switch( dsr_header[i].type ) { + case BYTE: + printf( "%d\n", G_STRUCT_MEMBER( char, d, + dsr_header[i].offset ) ); + break; + + case SHORT: + printf( "%d\n", G_STRUCT_MEMBER( short, d, + dsr_header[i].offset ) ); + break; + + case INT: + printf( "%d\n", G_STRUCT_MEMBER( int, d, + dsr_header[i].offset ) ); + break; + + case FLOAT: + printf( "%g\n", G_STRUCT_MEMBER( float, d, + dsr_header[i].offset ) ); + break; + + case STRING: + printf( "\"%s\"\n", getstr( dsr_header[i].len, + &G_STRUCT_MEMBER( char, d, + dsr_header[i].offset ) ) ); + break; + + default: + g_assert( 0 ); + } + } +} +#endif /*DEBUG*/ + +static struct dsr * +read_header( const char *header ) +{ + struct dsr *d; + unsigned int len; + + if( !(d = (struct dsr *) vips__file_read_name( header, NULL, &len )) ) + return( NULL ); + if( len != sizeof( struct dsr ) ) { + vips_free( d ); + vips_error( "analyze2vips", + "%s", _( "header file size incorrect" ) ); + return( NULL ); + } + + /* Ouch! Should check at configure time I guess. + */ + g_assert( sizeof( struct dsr ) == 348 ); + + /* dsr headers are always SPARC byte order (MSB first). Do we need to + * swap? + */ + if( !im_amiMSBfirst() ) { + int i; + + for( i = 0; i < VIPS_NUMBER( dsr_header ); i++ ) { + unsigned char *p; + + + switch( dsr_header[i].type ) { + case SHORT: + p = &G_STRUCT_MEMBER( unsigned char, d, + dsr_header[i].offset ); + vips__copy_2byte( TRUE, p, p ); + break; + + case INT: + case FLOAT: + p = &G_STRUCT_MEMBER( unsigned char, d, + dsr_header[i].offset ); + vips__copy_4byte( TRUE, p, p ); + break; + + case BYTE: + case STRING: + break; + + default: + g_assert( 0 ); + } + } + } + + if( (int) len != d->hk.sizeof_hdr ) { + im_free( d ); + return( NULL ); + } + + return( d ); +} + +/* Try to get VIPS header properties from a dsr. + */ +static int +get_vips_properties( struct dsr *d, + int *width, int *height, int *bands, int *fmt ) +{ + int i; + + if( d->dime.dim[0] < 2 || d->dime.dim[0] > 7 ) { + vips_error( "analyze2vips", + _( "%d-dimensional images not supported" ), + d->dime.dim[0] ); + return( -1 ); + } + + /* Size of base 2d images. + */ + *width = d->dime.dim[1]; + *height = d->dime.dim[2]; + + for( i = 3; i <= d->dime.dim[0]; i++ ) + *height *= d->dime.dim[i]; + + /* Check it's a datatype we can handle. + */ + switch( d->dime.datatype ) { + case DT_UNSIGNED_CHAR: + *bands = 1; + *fmt = IM_BANDFMT_UCHAR; + break; + + case DT_SIGNED_SHORT: + *bands = 1; + *fmt = IM_BANDFMT_SHORT; + break; + + case DT_SIGNED_INT: + *bands = 1; + *fmt = IM_BANDFMT_INT; + break; + + case DT_FLOAT: + *bands = 1; + *fmt = IM_BANDFMT_FLOAT; + break; + + case DT_COMPLEX: + *bands = 1; + *fmt = IM_BANDFMT_COMPLEX; + break; + + case DT_DOUBLE: + *bands = 1; + *fmt = IM_BANDFMT_DOUBLE; + break; + + case DT_RGB: + *bands = 3; + *fmt = IM_BANDFMT_UCHAR; + break; + + default: + vips_error( "analyze2vips", + _( "datatype %d not supported" ), d->dime.datatype ); + return( -1 ); + } + +#ifdef DEBUG + printf( "get_vips_properties: width = %d\n", *width ); + printf( "get_vips_properties: height = %d\n", *height ); + printf( "get_vips_properties: bands = %d\n", *bands ); + printf( "get_vips_properties: fmt = %d\n", *fmt ); +#endif /*DEBUG*/ + + return( 0 ); +} + +static void +attach_meta( IMAGE *out, struct dsr *d ) +{ + int i; + + vips_image_set_blob( out, "dsr", + (VipsCallbackFn) vips_free, d, d->hk.sizeof_hdr ); + + for( i = 0; i < VIPS_NUMBER( dsr_header ); i++ ) { + switch( dsr_header[i].type ) { + case BYTE: + vips_image_set_int( out, dsr_header[i].name, + G_STRUCT_MEMBER( char, d, + dsr_header[i].offset ) ); + break; + + case SHORT: + vips_image_set_int( out, dsr_header[i].name, + G_STRUCT_MEMBER( short, d, + dsr_header[i].offset ) ); + break; + + case INT: + vips_image_set_int( out, dsr_header[i].name, + G_STRUCT_MEMBER( int, d, + dsr_header[i].offset ) ); + break; + + case FLOAT: + vips_image_set_double( out, dsr_header[i].name, + G_STRUCT_MEMBER( float, d, + dsr_header[i].offset ) ); + break; + + case STRING: + vips_image_set_string( out, dsr_header[i].name, + getstr( dsr_header[i].len, + &G_STRUCT_MEMBER( char, d, + dsr_header[i].offset ) ) ); + break; + + default: + g_assert( 0 ); + } + } +} + +int +vips__isanalyze( const char *filename ) +{ + char header[FILENAME_MAX]; + char image[FILENAME_MAX]; + struct dsr *d; + int width, height; + int bands; + int fmt; + + generate_filenames( filename, header, image ); + if( !vips_existsf( "%s", header ) ) + return( 0 ); + if( !(d = read_header( header )) ) + return( 0 ); + +#ifdef DEBUG + print_dsr( d ); +#endif /*DEBUG*/ + + if( get_vips_properties( d, &width, &height, &bands, &fmt ) ) { + vips_free( d ); + return( 0 ); + } + vips_free( d ); + + return( 1 ); +} + +int +vips__analyze_read_header( const char *filename, VipsImage *out ) +{ + char header[FILENAME_MAX]; + char image[FILENAME_MAX]; + struct dsr *d; + int width, height; + int bands; + int fmt; + + generate_filenames( filename, header, image ); + if( !(d = read_header( header )) ) + return( -1 ); + +#ifdef DEBUG + print_dsr( d ); +#endif /*DEBUG*/ + + if( get_vips_properties( d, &width, &height, &bands, &fmt ) ) { + im_free( d ); + return( -1 ); + } + + vips_image_init_fields( out, + width, height, bands, fmt, + VIPS_CODING_NONE, + bands == 1 ? + VIPS_INTERPRETATION_B_W : VIPS_INTERPRETATION_sRGB, + 1.0, 1.0 ); + + attach_meta( out, d ); + + return( 0 ); +} + +int +vips__analyze_read( const char *filename, VipsImage *out ) +{ + char header[FILENAME_MAX]; + char image[FILENAME_MAX]; + struct dsr *d; + IMAGE *t[2]; + int width, height; + int bands; + int fmt; + + generate_filenames( filename, header, image ); + if( !(d = read_header( header )) ) + return( -1 ); + +#ifdef DEBUG + print_dsr( d ); +#endif /*DEBUG*/ + + if( get_vips_properties( d, &width, &height, &bands, &fmt ) || + im_open_local_array( out, t, 2, "analyze2vips", "p" ) || + im_raw2vips( image, t[0], width, height, + bands * im_bits_of_fmt( fmt ) / 8, 0 ) || + im_copy_morph( t[0], t[1], bands, fmt, IM_CODING_NONE ) || + im_copy_native( t[1], out, TRUE ) ) { + vips_free( d ); + return( -1 ); + } + + attach_meta( out, d ); + + return( 0 ); +} + diff --git a/libvips/foreign/dbh.h b/libvips/foreign/dbh.h new file mode 100644 index 00000000..782cbf67 --- /dev/null +++ b/libvips/foreign/dbh.h @@ -0,0 +1,98 @@ +/* + * + * (c) Copyright, 1986-1991 + * Biodynamics Research Unit + * Mayo Foundation + * + * dbh.h + * + * + * database sub-definitions + */ + +/* + * + * The previous-generation header for Analyze images. Although (c) Mayo + * Foundation, it has been in the public domain for many years. + * + * Analyze images have a 348 byte header stored in a file with a .hdr suffix, + * and a corresponding .img file containing just the pixel data. + * + */ + +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 */ + }; + +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 */ + }; /* total=200 */ + +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 */ + +/* Acceptable values for hdr.dime.datatype */ +#define DT_UNKNOWN 0 +#define DT_BINARY 1 +#define DT_UNSIGNED_CHAR 2 +#define DT_SIGNED_SHORT 4 +#define DT_SIGNED_INT 8 +#define DT_FLOAT 16 +#define DT_COMPLEX 32 +#define DT_DOUBLE 64 +#define DT_RGB 128