From 7496381fc9c69ecae07d9036bbd890c16df46663 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Fri, 13 Jul 2018 13:08:23 +0100 Subject: [PATCH] more getting ready for niftisave --- libvips/foreign/niftiload.c | 124 ++++++++++++++++++++++++++---------- libvips/foreign/niftisave.c | 34 +++++++--- libvips/foreign/pforeign.h | 22 ++----- 3 files changed, 123 insertions(+), 57 deletions(-) diff --git a/libvips/foreign/niftiload.c b/libvips/foreign/niftiload.c index e622fab3..4d9e544e 100644 --- a/libvips/foreign/niftiload.c +++ b/libvips/foreign/niftiload.c @@ -103,7 +103,14 @@ vips_foreign_load_nifti_dispose( GObject *gobject ) dispose( gobject ); } -VipsForeignDT2Vips vips_foreign_DT2Vips[] = { +/* Map DT_* datatype values to VipsBandFormat. + */ +typedef struct _VipsForeignDT2Vips { + int datatype; + VipsBandFormat fmt; +} VipsForeignDT2Vips ; + +static VipsForeignDT2Vips vips_foreign_nifti_DT2Vips[] = { { DT_UINT8, VIPS_FORMAT_UCHAR }, { DT_INT8, VIPS_FORMAT_CHAR }, { DT_UINT16, VIPS_FORMAT_USHORT }, @@ -118,17 +125,39 @@ VipsForeignDT2Vips vips_foreign_DT2Vips[] = { { DT_RGBA32, VIPS_FORMAT_UCHAR } }; -/* Slow and horrid version if there's no recent glib. - */ -#ifndef HAVE_CHECKED_MUL -#define g_uint_checked_mul( dest, a, b ) ( \ - ((guint64) a * b) > UINT_MAX ? \ - (*dest = UINT_MAX, FALSE) : \ - (*dest = a * b, TRUE) \ -) -#endif /*HAVE_CHECKED_MUL*/ +VipsBandFormat +vips__foreign_nifti_datatype2BandFmt( int datatype ) +{ + int i; -VipsForeignNiftiFields vips_foreign_nifti_fields[] = { + for( i = 0; i < VIPS_NUMBER( vips_foreign_nifti_DT2Vips ); i++ ) + if( vips_foreign_nifti_DT2Vips[i].datatype == datatype ) + return( vips_foreign_nifti_DT2Vips[i].fmt ); + + return( VIPS_FORMAT_NOTSET ); +} + +int +vips__foreign_nifti_BandFmt2datatype( VipsBandFormat fmt ) +{ + int i; + + for( i = 0; i < VIPS_NUMBER( vips_foreign_nifti_DT2Vips ); i++ ) + if( vips_foreign_nifti_DT2Vips[i].fmt == fmt ) + return( vips_foreign_nifti_DT2Vips[i].datatype ); + + return( -1 ); +} + +/* All the header fields we attach as metadata. + */ +typedef struct _VipsForeignNiftiFields { + char *name; + GType type; + glong offset; +} VipsForeignNiftiFields; + +static VipsForeignNiftiFields vips_foreign_nifti_fields[] = { /* The first 8 must be the dims[] fields, see * vips_foreign_save_nifti_make_nim(). */ @@ -251,8 +280,29 @@ VipsForeignNiftiFields vips_foreign_nifti_fields[] = { G_STRUCT_OFFSET( nifti_image, intent_p3 ) }, }; +void * +vips__foreign_nifti_map( VipsNiftiMapFn fn, void *a, void *b ) +{ + int i; + void *result; + + for( i = 0; i < VIPS_NUMBER( vips_foreign_nifti_fields ); i++ ) { + GValue value = { 0 }; + + g_value_init( &value, vips_foreign_nifti_fields[i].type ); + result = fn( vips_foreign_nifti_fields[i].name, &value, + vips_foreign_nifti_fields[i].offset, a, b ); + g_value_unset( &value ); + + if( result ) + return( result ); + } + + return( NULL ); +} + /* How I wish glib had something like this :( Just implement the ones we need - * for Field above. + * for vips_foreign_nifti_fields above. */ static void vips_gvalue_read( GValue *value, void *p ) @@ -272,6 +322,32 @@ vips_gvalue_read( GValue *value, void *p ) } } +static void * +vips_foreign_load_nifti_set( const char *name, GValue *value, glong offset, + void *a, void *b ) +{ + nifti_image *nim = (nifti_image *) a; + VipsImage *out = VIPS_IMAGE( b ); + + char vips_name[256]; + + vips_gvalue_read( value, (gpointer) nim + offset ); + vips_snprintf( vips_name, 256, "nifti-%s", name ); + vips_image_set( out, vips_name, value ); + + return( NULL ); +} + +/* Slow and horrid version if there's no recent glib. + */ +#ifndef HAVE_CHECKED_MUL +#define g_uint_checked_mul( dest, a, b ) ( \ + ((guint64) a * b) > UINT_MAX ? \ + (*dest = UINT_MAX, FALSE) : \ + (*dest = a * b, TRUE) \ +) +#endif /*HAVE_CHECKED_MUL*/ + static int vips_foreign_load_nifti_set_header( VipsForeignLoadNifti *nifti, nifti_image *nim, VipsImage *out ) @@ -330,15 +406,7 @@ vips_foreign_load_nifti_set_header( VipsForeignLoadNifti *nifti, return( 0 ); } - /* Decode voxel format. - */ - fmt = VIPS_FORMAT_UCHAR; - for( i = 0; i < VIPS_NUMBER( vips_DT2Vips ); i++ ) - if( nim->datatype == vips_DT2Vips[i].datatype ) { - fmt = vips_DT2Vips[i].fmt; - break; - } - if( i == VIPS_NUMBER( vips_DT2Vips ) ) { + if( !(fmt = vips__foreign_nifti_BandFmt2datatype( nim->datatype )) ) { vips_error( class->nickname, _( "datatype %d not supported" ), nim->datatype ); return( -1 ); @@ -389,17 +457,9 @@ vips_foreign_load_nifti_set_header( VipsForeignLoadNifti *nifti, VIPS_INTERPRETATION_B_W : VIPS_INTERPRETATION_sRGB, xres, yres ); - for( i = 0; i < VIPS_NUMBER( vips_foreign_nifti_fields ); i++ ) { - GValue value = { 0 }; - - g_value_init( &value, vips_foreign_nifti_fields[i].type ); - vips_gvalue_read( &value, - (gpointer) nim + vips_foreign_nifti_fields[i].offset ); - vips_snprintf( txt, 256, "nifti-%s", - vips_foreign_nifti_fields[i].name ); - vips_image_set( out, txt, &value ); - g_value_unset( &value ); - } + /* Set some vips metadata for every nifti header field. + */ + vips__foreign_nifti_map( vips_foreign_load_nifti_set, nim, out ); /* One byte longer than the spec to leave space for any extra * '\0' termination. diff --git a/libvips/foreign/niftisave.c b/libvips/foreign/niftisave.c index 80c51fa2..8d98a664 100644 --- a/libvips/foreign/niftisave.c +++ b/libvips/foreign/niftisave.c @@ -78,8 +78,19 @@ vips_foreign_save_nifti_dispose( GObject *gobject ) dispose( gobject ); } +/* Make ->nim from the vips header fields. + */ static int -vips_foreign_save_nifti_make_nim( VipsForeignSaveNifti *nifti, +vips_foreign_save_nifti_header_vips( VipsForeignSaveNifti *nifti, + VipsImage *image ) +{ + return( 0 ); +} + +/* Make ->nim from the nifti- fields. + */ +static int +vips_foreign_save_nifti_header_nifti( VipsForeignSaveNifti *nifti, VipsImage *image ) { int dims[8]; @@ -135,17 +146,24 @@ vips_foreign_save_nifti_build( VipsObject *object ) VipsImage **t = (VipsImage **) vips_object_local_array( VIPS_OBJECT( nifti ), 2 ); - struct nifti_1_header nhdr; - if( VIPS_OBJECT_CLASS( vips_foreign_save_nifti_parent_class )-> build( object ) ) return( -1 ); - if( vips_foreign_save_nifti_make_header( nifti, save->ready, &nhdr ) ) - return( -1 ); - - if( !(nifti->nim = nifti_convert_nhdr2nim( nhdr, nifti->filename )) ) - return( -1 ); + /* This could be an image (indirectly) from niftiload, or something + * like OME_TIFF, which does not have all the "nifti-ndim" fields. + * + * If it doesn't look like a nifti, try to make a nifti header from + * what we have. + */ + if( vips_image_get_typeof( save->ready, "nifti-ndim" ) ) { + if( vips_foreign_save_nifti_header_nifti( nifti, save->ready ) ) + return( -1 ); + } + else { + if( vips_foreign_save_nifti_header_vips( nifti, save->ready ) ) + return( -1 ); + } /* set ext, plus other stuff */ diff --git a/libvips/foreign/pforeign.h b/libvips/foreign/pforeign.h index 7179c501..a4864c19 100644 --- a/libvips/foreign/pforeign.h +++ b/libvips/foreign/pforeign.h @@ -256,24 +256,12 @@ int vips__quantise_image( VipsImage *in, VipsImage **index_out, VipsImage **palette_out, int colours, int Q, double dither ); -/* Map DT_* datatype values to VipsBandFormat. - */ -typedef struct _VipsForeignDT2Vips { - int datatype; - VipsBandFormat fmt; -} VipsForeignDT2Vips +VipsBandFormat vips__foreign_nifti_datatype2BandFmt( int datatype ); +int vips__foreign_nifti_BandFmt2datatype( VipsBandFormat fmt ); -extern VipsForeignDT2Vips vips_foreign_DT2Vips[]; - -/* All the header fields we attach as metadata. - */ -typedef struct _VipsForeignNiftiFields { - char *name; - GType type; - glong offset; -} VipsForeignNiftiFields; - -VipsForeignNiftiFields vips_foreign_nifti_fields[]; +typedef void *(*VipsNiftiMapFn)( const char *name, GValue *value, glong offset, + void *a, void *b ); +void *vips__foreign_nifti_map( VipsNiftiMapFn fn, void *a, void *b ); #ifdef __cplusplus }