start moving analyze load over

This commit is contained in:
John Cupitt 2011-12-14 14:49:23 +00:00
parent bf88439c0a
commit 03069261bb
3 changed files with 724 additions and 0 deletions

View File

@ -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*/

View File

@ -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 <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <vips/vips.h>
#include <vips/internal.h>
#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 );
}

98
libvips/foreign/dbh.h Normal file
View File

@ -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