From 25e42d1625cd03522e5cf8b9da7677d5886f20f3 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Wed, 14 Dec 2011 18:02:46 +0000 Subject: [PATCH] fix up new-style analyze load --- ChangeLog | 2 +- TODO | 2 + libvips/conversion/join.c | 1 - libvips/foreign/Makefile.am | 3 + .../foreign/{anlyze2vips.c => analyze2vips.c} | 55 +- libvips/foreign/analyze2vips.h | 2 +- libvips/foreign/analyzeload.c | 167 ++++++ libvips/foreign/foreign.c | 2 + libvips/format/Makefile.am | 1 - libvips/format/dbh.h | 98 --- libvips/format/im_analyze2vips.c | 563 +----------------- libvips/include/vips/foreign.h | 3 + 12 files changed, 221 insertions(+), 678 deletions(-) rename libvips/foreign/{anlyze2vips.c => analyze2vips.c} (94%) create mode 100644 libvips/foreign/analyzeload.c delete mode 100644 libvips/format/dbh.h diff --git a/ChangeLog b/ChangeLog index d5746fa8..b8a00e1d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,7 +14,7 @@ im_pow*(), im_exp*(), im_ifthenelse(), im_blend(), im_c2amph(), im_c2rect(), im_bandmean(), im_c2real(), im_c2imag(), im_ri2c(), im_jpeg*2vips(), im_vips2jpeg*(), im_tiff2vips(), im_vips2tiff(), im_exr2vips(), - im_fits2vips(), im_vips2fits() + im_fits2vips(), im_vips2fits(), im_analyze2vips() redone as classes - added argument priorites to help control arg ordering - generate has a 'stop' param to signal successful early termination diff --git a/TODO b/TODO index e17981f9..f1fa3cc5 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,7 @@ - suppression for the strspn() thing? +- test analyze load + - "header fred.png" does not work, since header uses im_open() which uses diff --git a/libvips/conversion/join.c b/libvips/conversion/join.c index c3af3d2b..b074a378 100644 --- a/libvips/conversion/join.c +++ b/libvips/conversion/join.c @@ -186,7 +186,6 @@ vips_join_build( VipsObject *object ) t = t2; } - if( vips_image_write( t, conversion->out ) ) { g_object_unref( t ); return( -1 ); diff --git a/libvips/foreign/Makefile.am b/libvips/foreign/Makefile.am index a26cb51f..8f9cd59f 100644 --- a/libvips/foreign/Makefile.am +++ b/libvips/foreign/Makefile.am @@ -3,6 +3,9 @@ noinst_LTLIBRARIES = libforeign.la libforeign_la_SOURCES = \ vipssave.c \ vipsload.c \ + analyzeload.c \ + analyze2vips.c \ + analyze2vips.h \ foreign.c EXTRA_DIST = diff --git a/libvips/foreign/anlyze2vips.c b/libvips/foreign/analyze2vips.c similarity index 94% rename from libvips/foreign/anlyze2vips.c rename to libvips/foreign/analyze2vips.c index 6bfaee4d..807c95f2 100644 --- a/libvips/foreign/anlyze2vips.c +++ b/libvips/foreign/analyze2vips.c @@ -41,8 +41,8 @@ */ /* - */ #define DEBUG + */ #ifdef HAVE_CONFIG_H #include @@ -58,6 +58,7 @@ #include #include "dbh.h" +#include "analyze2vips.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. @@ -219,13 +220,10 @@ static Field dsr_header[] = { 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 ); + vips__change_suffix( path, header, FILENAME_MAX, ".hdr", olds, 2 ); + vips__change_suffix( path, image, FILENAME_MAX, ".img", olds, 2 ); } /* str is a str which may not be NULL-terminated. Return a pointer to a static @@ -318,7 +316,7 @@ read_header( const char *header ) /* dsr headers are always SPARC byte order (MSB first). Do we need to * swap? */ - if( !im_amiMSBfirst() ) { + if( !vips_amiMSBfirst() ) { int i; for( i = 0; i < VIPS_NUMBER( dsr_header ); i++ ) { @@ -350,7 +348,7 @@ read_header( const char *header ) } if( (int) len != d->hk.sizeof_hdr ) { - im_free( d ); + vips_free( d ); return( NULL ); } @@ -361,7 +359,7 @@ read_header( const char *header ) */ static int get_vips_properties( struct dsr *d, - int *width, int *height, int *bands, int *fmt ) + int *width, int *height, int *bands, VipsBandFormat *fmt ) { int i; @@ -385,37 +383,37 @@ get_vips_properties( struct dsr *d, switch( d->dime.datatype ) { case DT_UNSIGNED_CHAR: *bands = 1; - *fmt = IM_BANDFMT_UCHAR; + *fmt = VIPS_FORMAT_UCHAR; break; case DT_SIGNED_SHORT: *bands = 1; - *fmt = IM_BANDFMT_SHORT; + *fmt = VIPS_FORMAT_SHORT; break; case DT_SIGNED_INT: *bands = 1; - *fmt = IM_BANDFMT_INT; + *fmt = VIPS_FORMAT_INT; break; case DT_FLOAT: *bands = 1; - *fmt = IM_BANDFMT_FLOAT; + *fmt = VIPS_FORMAT_FLOAT; break; case DT_COMPLEX: *bands = 1; - *fmt = IM_BANDFMT_COMPLEX; + *fmt = VIPS_FORMAT_COMPLEX; break; case DT_DOUBLE: *bands = 1; - *fmt = IM_BANDFMT_DOUBLE; + *fmt = VIPS_FORMAT_DOUBLE; break; case DT_RGB: *bands = 3; - *fmt = IM_BANDFMT_UCHAR; + *fmt = VIPS_FORMAT_UCHAR; break; default: @@ -489,7 +487,7 @@ vips__isanalyze( const char *filename ) struct dsr *d; int width, height; int bands; - int fmt; + VipsBandFormat fmt; generate_filenames( filename, header, image ); if( !vips_existsf( "%s", header ) ) @@ -518,7 +516,7 @@ vips__analyze_read_header( const char *filename, VipsImage *out ) struct dsr *d; int width, height; int bands; - int fmt; + VipsBandFormat fmt; generate_filenames( filename, header, image ); if( !(d = read_header( header )) ) @@ -529,7 +527,7 @@ vips__analyze_read_header( const char *filename, VipsImage *out ) #endif /*DEBUG*/ if( get_vips_properties( d, &width, &height, &bands, &fmt ) ) { - im_free( d ); + vips_free( d ); return( -1 ); } @@ -551,10 +549,10 @@ vips__analyze_read( const char *filename, VipsImage *out ) char header[FILENAME_MAX]; char image[FILENAME_MAX]; struct dsr *d; - IMAGE *t[2]; + VipsImage *t; int width, height; int bands; - int fmt; + VipsBandFormat fmt; generate_filenames( filename, header, image ); if( !(d = read_header( header )) ) @@ -565,14 +563,19 @@ vips__analyze_read( const char *filename, VipsImage *out ) #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 ) ) { + !(t = vips_image_new_from_file_raw( image, width, height, + bands * vips_format_sizeof( fmt ), 0 )) ) + return( -1 ); + + if( vips_copy( t, &t, + "bands", bands, "format", fmt, "swap", vips_amiMSBfirst(), + NULL ) || + vips_image_write( t, out ) ) { + g_object_unref( t ); vips_free( d ); return( -1 ); } + g_object_unref( t ); attach_meta( out, d ); diff --git a/libvips/foreign/analyze2vips.h b/libvips/foreign/analyze2vips.h index a2a8e206..a3ace9fd 100644 --- a/libvips/foreign/analyze2vips.h +++ b/libvips/foreign/analyze2vips.h @@ -36,7 +36,7 @@ extern "C" { 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 ) +int vips__analyze_read( const char *filename, VipsImage *out ); #ifdef __cplusplus } diff --git a/libvips/foreign/analyzeload.c b/libvips/foreign/analyzeload.c new file mode 100644 index 00000000..8700de8d --- /dev/null +++ b/libvips/foreign/analyzeload.c @@ -0,0 +1,167 @@ +/* load analyze from a file + * + * 5/12/11 + * - from openslideload.c + */ + +/* + + 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 "analyze2vips.h" + +typedef struct _VipsForeignLoadAnalyze { + VipsForeignLoad parent_object; + + /* Filename for load. + */ + char *filename; + +} VipsForeignLoadAnalyze; + +typedef VipsForeignLoadClass VipsForeignLoadAnalyzeClass; + +G_DEFINE_TYPE( VipsForeignLoadAnalyze, vips_foreign_load_analyze, + VIPS_TYPE_FOREIGN_LOAD ); + +static VipsForeignFlags +vips_foreign_load_analyze_get_flags_filename( const char *filename ) +{ + return( VIPS_FOREIGN_PARTIAL ); +} + +static VipsForeignFlags +vips_foreign_load_analyze_get_flags( VipsForeignLoad *load ) +{ + return( VIPS_FOREIGN_PARTIAL ); +} + +static int +vips_foreign_load_analyze_header( VipsForeignLoad *load ) +{ + VipsForeignLoadAnalyze *analyze = (VipsForeignLoadAnalyze *) load; + + if( vips__analyze_read_header( analyze->filename, load->out ) ) + return( -1 ); + + return( 0 ); +} + +static int +vips_foreign_load_analyze_load( VipsForeignLoad *load ) +{ + VipsForeignLoadAnalyze *analyze = (VipsForeignLoadAnalyze *) load; + + if( vips__analyze_read( analyze->filename, load->real ) ) + return( -1 ); + + return( 0 ); +} + +static const char *vips_foreign_analyze_suffs[] = { ".img", ".hdr", NULL }; + +static void +vips_foreign_load_analyze_class_init( VipsForeignLoadAnalyzeClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsForeignClass *foreign_class = (VipsForeignClass *) class; + VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + object_class->nickname = "analyzeload"; + object_class->description = _( "load an Analyze6 image" ); + + foreign_class->suffs = vips_foreign_analyze_suffs; + + load_class->is_a = vips__isanalyze; + load_class->get_flags_filename = + vips_foreign_load_analyze_get_flags_filename; + load_class->get_flags = vips_foreign_load_analyze_get_flags; + load_class->header = vips_foreign_load_analyze_header; + load_class->load = vips_foreign_load_analyze_load; + + VIPS_ARG_STRING( class, "filename", 1, + _( "Filename" ), + _( "Filename to load from" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsForeignLoadAnalyze, filename ), + NULL ); +} + +static void +vips_foreign_load_analyze_init( VipsForeignLoadAnalyze *analyze ) +{ +} + +/** + * vips_analyzeload: + * @filename: file to load + * @out: decompressed image + * @...: %NULL-terminated list of optional named arguments + * + * Load an Analyze 6.0 file. If @filename is "fred.img", this will look for + * an image header called "fred.hdr" and pixel data in "fred.img". You can + * also load "fred" or "fred.hdr". + * + * Images are + * loaded lazilly and byte-swapped, if necessary. The Analyze metadata is read + * and attached. + * + * See also: vips_image_new_from_file(). + * + * Returns: 0 on success, -1 on error. + */ +int +vips_analyzeload( const char *filename, VipsImage **out, ... ) +{ + va_list ap; + int result; + + va_start( ap, out ); + result = vips_call_split( "analyzeload", ap, filename, out ); + va_end( ap ); + + return( result ); +} diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index 84bf16b2..ed031f9a 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -1156,6 +1156,7 @@ vips_foreign_operation_init( void ) { extern GType vips_foreign_load_fits_get_type( void ); extern GType vips_foreign_save_fits_get_type( void ); + extern GType vips_foreign_load_analyze_get_type( void ); extern GType vips_foreign_load_openexr_get_type( void ); extern GType vips_foreign_load_openslide_get_type( void ); extern GType vips_foreign_load_jpeg_file_get_type( void ); @@ -1194,6 +1195,7 @@ vips_foreign_operation_init( void ) vips_foreign_load_openexr_get_type(); #endif /*HAVE_OPENEXR*/ + vips_foreign_load_analyze_get_type(); vips_foreign_load_vips_get_type(); vips_foreign_save_vips_get_type(); } diff --git a/libvips/format/Makefile.am b/libvips/format/Makefile.am index 337dcf61..ad5f0d81 100644 --- a/libvips/format/Makefile.am +++ b/libvips/format/Makefile.am @@ -1,7 +1,6 @@ noinst_LTLIBRARIES = libformat.la libformat_la_SOURCES = \ - dbh.h \ format.c \ format_dispatch.c \ im_analyze2vips.c \ diff --git a/libvips/format/dbh.h b/libvips/format/dbh.h deleted file mode 100644 index 782cbf67..00000000 --- a/libvips/format/dbh.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * - * (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 diff --git a/libvips/format/im_analyze2vips.c b/libvips/format/im_analyze2vips.c index 54f7ceb3..9fb8288b 100644 --- a/libvips/format/im_analyze2vips.c +++ b/libvips/format/im_analyze2vips.c @@ -1,15 +1,7 @@ /* 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 + * - just a compat stub now */ /* @@ -39,575 +31,46 @@ */ /* - */ #define DEBUG + */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include -#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 ) +static VipsFormatFlags +analyze_flags( const char *filename ) { - char name[FILENAME_MAX]; - char mode[FILENAME_MAX]; - - const char *olds[] = { ".img", ".hdr" }; - - /* Take off any modifiers. - */ - im_filename_split( path, name, mode ); - - im__change_suffix( name, header, FILENAME_MAX, ".hdr", olds, 2 ); - im__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; - - 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 < IM_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: - assert( 0 ); - } - } -} -#endif /*DEBUG*/ - -static struct dsr * -read_header( const char *header ) -{ - struct dsr *d; - unsigned int len; - - if( !(d = (struct dsr *) im__file_read_name( header, NULL, &len )) ) - return( NULL ); - if( len != sizeof( struct dsr ) ) { - im_free( d ); - im_error( "im_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 < IM_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: - 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 ) { - im_error( "im_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: - im_error( "im_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; - - im_meta_set_blob( out, "dsr", - (im_callback_fn) im_free, d, d->hk.sizeof_hdr ); - - for( i = 0; i < IM_NUMBER( dsr_header ); i++ ) { - switch( dsr_header[i].type ) { - case BYTE: - im_meta_set_int( out, dsr_header[i].name, - G_STRUCT_MEMBER( char, d, - dsr_header[i].offset ) ); - break; - - case SHORT: - im_meta_set_int( out, dsr_header[i].name, - G_STRUCT_MEMBER( short, d, - dsr_header[i].offset ) ); - break; - - case INT: - im_meta_set_int( out, dsr_header[i].name, - G_STRUCT_MEMBER( int, d, - dsr_header[i].offset ) ); - break; - - case FLOAT: - im_meta_set_double( out, dsr_header[i].name, - G_STRUCT_MEMBER( float, d, - dsr_header[i].offset ) ); - break; - - case STRING: - im_meta_set_string( out, dsr_header[i].name, - getstr( dsr_header[i].len, - &G_STRUCT_MEMBER( char, d, - dsr_header[i].offset ) ) ); - break; - - default: - assert( 0 ); - } - } + return( vips_foreign_flags( "analyzeload", filename ) ); } static int 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( !im_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 ) ) { - im_free( d ); - return( 0 ); - } - im_free( d ); - - return( 1 ); + return( vips_foreign_is_a( "analyzeload", filename ) ); } -static int -analyze2vips_header( const char *filename, IMAGE *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 ); - } - - im_initdesc( out, width, height, bands, im_bits_of_fmt( fmt ), fmt, - IM_CODING_NONE, - bands == 1 ? IM_TYPE_B_W : IM_TYPE_sRGB, - 1.0, 1.0, - 0, 0 ); - - attach_meta( out, d ); - - return( 0 ); -} - -/** - * im_analyze2vips: - * @filename: file to load - * @out: image to write to - * - * Load an Analyze 6.0 file. If @filename is "fred.img", this will look for - * an image header called "fred.hdr" and pixel data in "fred.img". You can - * also load "fred" or "fred.hdr". - * - * Images are - * loaded lazilly and byte-swapped, if necessary. The Analyze metadata is read - * and attached. - * - * See also: #VipsFormat, im_meta_get(), im_grid(). - * - * Returns: 0 on success, -1 on error. - */ int im_analyze2vips( const char *filename, IMAGE *out ) { - char header[FILENAME_MAX]; - char image[FILENAME_MAX]; - struct dsr *d; - IMAGE *t[2]; - int width, height; - int bands; - int fmt; + VipsImage *t; - generate_filenames( filename, header, image ); - if( !(d = read_header( header )) ) + if( vips_analyzeload( filename, &t, NULL ) ) 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, "im_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 ) ) { - im_free( d ); + if( vips_image_write( t, out ) ) { + g_object_unref( t ); return( -1 ); } - - attach_meta( out, d ); + g_object_unref( t ); return( 0 ); } static const char *analyze_suffs[] = { ".img", ".hdr", NULL }; -static VipsFormatFlags -analyze_flags( const char *filename ) -{ - return( VIPS_FORMAT_PARTIAL ); -} - -/* analyze format adds no new members. - */ typedef VipsFormat VipsFormatAnalyze; typedef VipsFormatClass VipsFormatAnalyzeClass; @@ -621,7 +84,7 @@ vips_format_analyze_class_init( VipsFormatAnalyzeClass *class ) object_class->description = _( "Analyze 6.0" ); format_class->is_a = isanalyze; - format_class->header = analyze2vips_header; + format_class->header = im_analyze2vips; format_class->load = im_analyze2vips; format_class->get_flags = analyze_flags; format_class->suffs = analyze_suffs; diff --git a/libvips/include/vips/foreign.h b/libvips/include/vips/foreign.h index 0308af97..15062bc0 100644 --- a/libvips/include/vips/foreign.h +++ b/libvips/include/vips/foreign.h @@ -328,6 +328,9 @@ int vips_fitsload( const char *filename, VipsImage **out, ... ) int vips_fitssave( VipsImage *in, const char *filename, ... ) __attribute__((sentinel)); +int vips_analyzeload( const char *filename, VipsImage **out, ... ) + __attribute__((sentinel)); + #ifdef __cplusplus } #endif /*__cplusplus*/