Merge branch 'add-nifti-support'
This commit is contained in:
commit
3565808281
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
|
.pytest_cache
|
||||||
compile
|
compile
|
||||||
.pytest_cache
|
.pytest_cache
|
||||||
a.out
|
a.out
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
- add Mitchell kernel
|
- add Mitchell kernel
|
||||||
- pyramid builders have a choice of 2x2 shrinkers [harukizaemon]
|
- pyramid builders have a choice of 2x2 shrinkers [harukizaemon]
|
||||||
- add `palette` option to pngsave [felixbuenemann]
|
- add `palette` option to pngsave [felixbuenemann]
|
||||||
|
- add basic nifti load/save support
|
||||||
- support writing string-valued fields via libexif
|
- support writing string-valued fields via libexif
|
||||||
- paste in the test suite from pyvips
|
- paste in the test suite from pyvips
|
||||||
- get EXIF tag names from tag plus ifd [@Nan619]
|
- get EXIF tag names from tag plus ifd [@Nan619]
|
||||||
|
26
configure.ac
26
configure.ac
@ -516,6 +516,14 @@ PKG_CHECK_MODULES(WIN32_GET_COMMAND_LINE, glib-2.0 >= 2.40,
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# from 2.48 we have g_uint_checked_mul() etc.
|
||||||
|
PKG_CHECK_MODULES(HAVE_CHECKED_MUL, glib-2.0 >= 2.48,
|
||||||
|
[AC_DEFINE(HAVE_CHECKED_MUL,1,[define if your glib has checked multiply.])
|
||||||
|
],
|
||||||
|
[:
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
# check for gtk-doc
|
# check for gtk-doc
|
||||||
GTK_DOC_CHECK([1.14],[--flavour no-tmpl])
|
GTK_DOC_CHECK([1.14],[--flavour no-tmpl])
|
||||||
|
|
||||||
@ -842,6 +850,19 @@ if test x"$with_OpenEXR" != x"no"; then
|
|||||||
)
|
)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# nifti
|
||||||
|
AC_ARG_WITH([nifti],
|
||||||
|
AS_HELP_STRING([--without-nifti], [build without nifti (default: test)]))
|
||||||
|
|
||||||
|
if test x"$with_nifti" != x"no"; then
|
||||||
|
FIND_NIFTI([
|
||||||
|
with_nifti=yes
|
||||||
|
],[
|
||||||
|
with_nifti=no
|
||||||
|
]
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
|
||||||
# pdfium
|
# pdfium
|
||||||
AC_ARG_WITH([pdfium],
|
AC_ARG_WITH([pdfium],
|
||||||
AS_HELP_STRING([--without-pdfium], [build without pdfium (default: test)]))
|
AS_HELP_STRING([--without-pdfium], [build without pdfium (default: test)]))
|
||||||
@ -1284,8 +1305,8 @@ do
|
|||||||
done | sort -ru`
|
done | sort -ru`
|
||||||
VIPS_CFLAGS=`echo $VIPS_CFLAGS`
|
VIPS_CFLAGS=`echo $VIPS_CFLAGS`
|
||||||
VIPS_CFLAGS="$VIPS_DEBUG_FLAGS $VIPS_CFLAGS"
|
VIPS_CFLAGS="$VIPS_DEBUG_FLAGS $VIPS_CFLAGS"
|
||||||
VIPS_INCLUDES="$ZLIB_INCLUDES $PNG_INCLUDES $TIFF_INCLUDES $JPEG_INCLUDES"
|
VIPS_INCLUDES="$ZLIB_INCLUDES $PNG_INCLUDES $TIFF_INCLUDES $JPEG_INCLUDES $NIFTI_INCLUDES"
|
||||||
VIPS_LIBS="$ZLIB_LIBS $MAGICK_LIBS $PNG_LIBS $IMAGEQUANT_LIBS $TIFF_LIBS $JPEG_LIBS $GTHREAD_LIBS $REQUIRED_LIBS $EXPAT_LIBS $PANGOFT2_LIBS $GSF_LIBS $FFTW_LIBS $ORC_LIBS $LCMS_LIBS $GIFLIB_LIBS $RSVG_LIBS $PDFIUM_LIBS $POPPLER_LIBS $OPENEXR_LIBS $OPENSLIDE_LIBS $CFITSIO_LIBS $LIBWEBP_LIBS $LIBWEBPMUX_LIBS $MATIO_LIBS $EXIF_LIBS -lm"
|
VIPS_LIBS="$ZLIB_LIBS $MAGICK_LIBS $PNG_LIBS $IMAGEQUANT_LIBS $TIFF_LIBS $JPEG_LIBS $GTHREAD_LIBS $REQUIRED_LIBS $EXPAT_LIBS $PANGOFT2_LIBS $GSF_LIBS $FFTW_LIBS $ORC_LIBS $LCMS_LIBS $GIFLIB_LIBS $RSVG_LIBS $NIFTI_LIBS $PDFIUM_LIBS $POPPLER_LIBS $OPENEXR_LIBS $OPENSLIDE_LIBS $CFITSIO_LIBS $LIBWEBP_LIBS $LIBWEBPMUX_LIBS $MATIO_LIBS $EXIF_LIBS -lm"
|
||||||
|
|
||||||
AC_SUBST(VIPS_LIBDIR)
|
AC_SUBST(VIPS_LIBDIR)
|
||||||
|
|
||||||
@ -1375,6 +1396,7 @@ save with libMagick: $enable_magicksave
|
|||||||
accelerate loops with orc: $with_orc
|
accelerate loops with orc: $with_orc
|
||||||
(requires orc-0.4.11 or later)
|
(requires orc-0.4.11 or later)
|
||||||
ICC profile support with lcms: $with_lcms
|
ICC profile support with lcms: $with_lcms
|
||||||
|
file import with niftiio: $with_nifti
|
||||||
file import with OpenEXR: $with_OpenEXR
|
file import with OpenEXR: $with_OpenEXR
|
||||||
file import with OpenSlide: $with_openslide
|
file import with OpenSlide: $with_openslide
|
||||||
(requires openslide-3.3.0 or later)
|
(requires openslide-3.3.0 or later)
|
||||||
|
@ -2,6 +2,8 @@ noinst_LTLIBRARIES = libforeign.la
|
|||||||
|
|
||||||
libforeign_la_SOURCES = \
|
libforeign_la_SOURCES = \
|
||||||
pforeign.h \
|
pforeign.h \
|
||||||
|
niftiload.c \
|
||||||
|
niftisave.c \
|
||||||
quantise.c \
|
quantise.c \
|
||||||
exif.c \
|
exif.c \
|
||||||
gifload.c \
|
gifload.c \
|
||||||
|
@ -1836,6 +1836,8 @@ vips_foreign_operation_init( void )
|
|||||||
extern GType vips_foreign_load_svg_get_type( void );
|
extern GType vips_foreign_load_svg_get_type( void );
|
||||||
extern GType vips_foreign_load_svg_file_get_type( void );
|
extern GType vips_foreign_load_svg_file_get_type( void );
|
||||||
extern GType vips_foreign_load_svg_buffer_get_type( void );
|
extern GType vips_foreign_load_svg_buffer_get_type( void );
|
||||||
|
extern GType vips_foreign_load_nifti_get_type( void );
|
||||||
|
extern GType vips_foreign_save_nifti_get_type( void );
|
||||||
extern GType vips_foreign_load_gif_get_type( void );
|
extern GType vips_foreign_load_gif_get_type( void );
|
||||||
extern GType vips_foreign_load_gif_file_get_type( void );
|
extern GType vips_foreign_load_gif_file_get_type( void );
|
||||||
extern GType vips_foreign_load_gif_buffer_get_type( void );
|
extern GType vips_foreign_load_gif_buffer_get_type( void );
|
||||||
@ -1958,6 +1960,11 @@ vips_foreign_operation_init( void )
|
|||||||
vips_foreign_load_openexr_get_type();
|
vips_foreign_load_openexr_get_type();
|
||||||
#endif /*HAVE_OPENEXR*/
|
#endif /*HAVE_OPENEXR*/
|
||||||
|
|
||||||
|
#ifdef HAVE_NIFTI
|
||||||
|
vips_foreign_load_nifti_get_type();
|
||||||
|
vips_foreign_save_nifti_get_type();
|
||||||
|
#endif /*HAVE_NIFTI*/
|
||||||
|
|
||||||
vips__foreign_load_operation =
|
vips__foreign_load_operation =
|
||||||
g_quark_from_static_string( "vips-foreign-load-operation" );
|
g_quark_from_static_string( "vips-foreign-load-operation" );
|
||||||
}
|
}
|
||||||
|
652
libvips/foreign/niftiload.c
Normal file
652
libvips/foreign/niftiload.c
Normal file
@ -0,0 +1,652 @@
|
|||||||
|
/* load nifti from a file
|
||||||
|
*
|
||||||
|
* 29/6/18
|
||||||
|
* - from fitsload.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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
#define DEBUG
|
||||||
|
#define VIPS_DEBUG
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* TODO
|
||||||
|
*
|
||||||
|
* - for uncompressed images, we could do direct mapping of the input
|
||||||
|
* - perhaps we could stream compressed images? but only if ext is defined at
|
||||||
|
* the start of the file
|
||||||
|
* (yes, file format is magic number, 348-byte header, extension data,
|
||||||
|
* pixel data, then all gz'd)
|
||||||
|
* - we could use the much faster byteswap in glib?
|
||||||
|
* - I have not been able to test the ext stuff :(
|
||||||
|
*
|
||||||
|
* There should be at least a x2 speedup possible.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif /*HAVE_CONFIG_H*/
|
||||||
|
#include <vips/intl.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <vips/vips.h>
|
||||||
|
#include <vips/debug.h>
|
||||||
|
#include <vips/internal.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_NIFTI
|
||||||
|
|
||||||
|
#include <nifti1_io.h>
|
||||||
|
|
||||||
|
#include "pforeign.h"
|
||||||
|
|
||||||
|
typedef struct _VipsForeignLoadNifti {
|
||||||
|
VipsForeignLoad parent_object;
|
||||||
|
|
||||||
|
/* Filename for load.
|
||||||
|
*/
|
||||||
|
char *filename;
|
||||||
|
|
||||||
|
/* The NIFTI image loaded to memory.
|
||||||
|
*/
|
||||||
|
nifti_image *nim;
|
||||||
|
|
||||||
|
/* Wrap this VipsImage around the NIFTI pointer, then redirect read
|
||||||
|
* requests to that. Saves a copy.
|
||||||
|
*/
|
||||||
|
VipsImage *memory;
|
||||||
|
|
||||||
|
} VipsForeignLoadNifti;
|
||||||
|
|
||||||
|
typedef VipsForeignLoadClass VipsForeignLoadNiftiClass;
|
||||||
|
|
||||||
|
G_DEFINE_TYPE( VipsForeignLoadNifti, vips_foreign_load_nifti,
|
||||||
|
VIPS_TYPE_FOREIGN_LOAD );
|
||||||
|
|
||||||
|
static void
|
||||||
|
vips_foreign_load_nifti_dispose( GObject *gobject )
|
||||||
|
{
|
||||||
|
VipsForeignLoadNifti *nifti = (VipsForeignLoadNifti *) gobject;
|
||||||
|
|
||||||
|
VIPS_UNREF( nifti->memory );
|
||||||
|
VIPS_FREEF( nifti_image_free, nifti->nim );
|
||||||
|
|
||||||
|
G_OBJECT_CLASS( vips_foreign_load_nifti_parent_class )->
|
||||||
|
dispose( gobject );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
vips_foreign_load_nifti_is_a( const char *filename )
|
||||||
|
{
|
||||||
|
char *hfile;
|
||||||
|
znzFile fp;
|
||||||
|
nifti_1_header nhdr;
|
||||||
|
|
||||||
|
/* Unfortunately is_nifti_file() is very slow and produces lots of
|
||||||
|
* output. We have to make our own.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if( !(hfile = nifti_findhdrname( filename )) )
|
||||||
|
return( 0 );
|
||||||
|
|
||||||
|
fp = znzopen( hfile, "rb", nifti_is_gzfile( hfile ));
|
||||||
|
if( znz_isnull( fp ) ) {
|
||||||
|
free( hfile );
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
free( hfile );
|
||||||
|
|
||||||
|
(void) znzread( &nhdr, 1, sizeof( nhdr ), fp );
|
||||||
|
|
||||||
|
znzclose( fp );
|
||||||
|
|
||||||
|
/* Test for sanity both ways around. There's a thing to test for byte
|
||||||
|
* order in niftilib, but it's static :(
|
||||||
|
*/
|
||||||
|
if( nifti_hdr_looks_good( &nhdr ) )
|
||||||
|
return( 1 );
|
||||||
|
swap_nifti_header( &nhdr, FALSE );
|
||||||
|
if( nifti_hdr_looks_good( &nhdr ) )
|
||||||
|
return( 1 );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 },
|
||||||
|
{ DT_INT16, VIPS_FORMAT_SHORT },
|
||||||
|
{ DT_UINT32, VIPS_FORMAT_UINT },
|
||||||
|
{ DT_INT32, VIPS_FORMAT_INT },
|
||||||
|
{ DT_FLOAT32, VIPS_FORMAT_FLOAT },
|
||||||
|
{ DT_FLOAT64, VIPS_FORMAT_DOUBLE },
|
||||||
|
{ DT_COMPLEX64, VIPS_FORMAT_COMPLEX },
|
||||||
|
{ DT_COMPLEX128, VIPS_FORMAT_DPCOMPLEX },
|
||||||
|
{ DT_RGB, VIPS_FORMAT_UCHAR },
|
||||||
|
{ DT_RGBA32, VIPS_FORMAT_UCHAR }
|
||||||
|
};
|
||||||
|
|
||||||
|
VipsBandFormat
|
||||||
|
vips__foreign_nifti_datatype2BandFmt( int datatype )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
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().
|
||||||
|
*/
|
||||||
|
{ "ndim", G_TYPE_INT, G_STRUCT_OFFSET( nifti_image, ndim ) },
|
||||||
|
{ "nx", G_TYPE_INT, G_STRUCT_OFFSET( nifti_image, nx ) },
|
||||||
|
{ "ny", G_TYPE_INT, G_STRUCT_OFFSET( nifti_image, ny ) },
|
||||||
|
{ "nz", G_TYPE_INT, G_STRUCT_OFFSET( nifti_image, nz ) },
|
||||||
|
{ "nt", G_TYPE_INT, G_STRUCT_OFFSET( nifti_image, nt ) },
|
||||||
|
{ "nu", G_TYPE_INT, G_STRUCT_OFFSET( nifti_image, nu ) },
|
||||||
|
{ "nv", G_TYPE_INT, G_STRUCT_OFFSET( nifti_image, nv ) },
|
||||||
|
{ "nw", G_TYPE_INT, G_STRUCT_OFFSET( nifti_image, nw ) },
|
||||||
|
|
||||||
|
{ "dx", G_TYPE_FLOAT, G_STRUCT_OFFSET( nifti_image, dx ) },
|
||||||
|
{ "dy", G_TYPE_FLOAT, G_STRUCT_OFFSET( nifti_image, dy ) },
|
||||||
|
{ "dz", G_TYPE_FLOAT, G_STRUCT_OFFSET( nifti_image, dz ) },
|
||||||
|
{ "dt", G_TYPE_FLOAT, G_STRUCT_OFFSET( nifti_image, dt ) },
|
||||||
|
{ "du", G_TYPE_FLOAT, G_STRUCT_OFFSET( nifti_image, du ) },
|
||||||
|
{ "dv", G_TYPE_FLOAT, G_STRUCT_OFFSET( nifti_image, dv ) },
|
||||||
|
{ "dw", G_TYPE_FLOAT, G_STRUCT_OFFSET( nifti_image, dw ) },
|
||||||
|
|
||||||
|
{ "scl_slope", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, scl_slope ) },
|
||||||
|
{ "scl_inter", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, scl_inter ) },
|
||||||
|
|
||||||
|
{ "cal_min", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, cal_min ) },
|
||||||
|
{ "cal_max", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, cal_max ) },
|
||||||
|
|
||||||
|
{ "qform_code", G_TYPE_INT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, qform_code ) },
|
||||||
|
{ "sform_code", G_TYPE_INT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, sform_code ) },
|
||||||
|
|
||||||
|
{ "freq_dim", G_TYPE_INT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, freq_dim ) },
|
||||||
|
{ "phase_dim", G_TYPE_INT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, phase_dim ) },
|
||||||
|
{ "slice_dim", G_TYPE_INT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, slice_dim ) },
|
||||||
|
|
||||||
|
{ "slice_code", G_TYPE_INT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, slice_code ) },
|
||||||
|
{ "slice_start", G_TYPE_INT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, slice_start ) },
|
||||||
|
{ "slice_end", G_TYPE_INT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, slice_end ) },
|
||||||
|
{ "slice_duration", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, slice_duration ) },
|
||||||
|
|
||||||
|
{ "quatern_b", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, quatern_b ) },
|
||||||
|
{ "quatern_c", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, quatern_c ) },
|
||||||
|
{ "quatern_d", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, quatern_d ) },
|
||||||
|
{ "qoffset_x", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, qoffset_x ) },
|
||||||
|
{ "qoffset_y", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, qoffset_y ) },
|
||||||
|
{ "qoffset_z", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, qoffset_z ) },
|
||||||
|
{ "qfac", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, qfac ) },
|
||||||
|
|
||||||
|
{ "sto_xyz00", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, sto_xyz.m[0][0] ) },
|
||||||
|
{ "sto_xyz01", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, sto_xyz.m[0][1] ) },
|
||||||
|
{ "sto_xyz02", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, sto_xyz.m[0][2] ) },
|
||||||
|
{ "sto_xyz03", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, sto_xyz.m[0][3] ) },
|
||||||
|
|
||||||
|
{ "sto_xyz10", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, sto_xyz.m[1][0] ) },
|
||||||
|
{ "sto_xyz11", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, sto_xyz.m[1][1] ) },
|
||||||
|
{ "sto_xyz12", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, sto_xyz.m[1][2] ) },
|
||||||
|
{ "sto_xyz13", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, sto_xyz.m[1][3] ) },
|
||||||
|
|
||||||
|
{ "sto_xyz20", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, sto_xyz.m[2][0] ) },
|
||||||
|
{ "sto_xyz21", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, sto_xyz.m[2][1] ) },
|
||||||
|
{ "sto_xyz22", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, sto_xyz.m[2][2] ) },
|
||||||
|
{ "sto_xyz23", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, sto_xyz.m[2][3] ) },
|
||||||
|
|
||||||
|
{ "sto_xyz30", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, sto_xyz.m[3][0] ) },
|
||||||
|
{ "sto_xyz31", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, sto_xyz.m[3][1] ) },
|
||||||
|
{ "sto_xyz32", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, sto_xyz.m[3][2] ) },
|
||||||
|
{ "sto_xyz33", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, sto_xyz.m[3][3] ) },
|
||||||
|
|
||||||
|
{ "toffset", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, toffset ) },
|
||||||
|
|
||||||
|
{ "xyz_units", G_TYPE_INT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, xyz_units ) },
|
||||||
|
{ "time_units", G_TYPE_INT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, time_units ) },
|
||||||
|
|
||||||
|
{ "nifti_type", G_TYPE_INT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, nifti_type ) },
|
||||||
|
{ "intent_code", G_TYPE_INT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, intent_code ) },
|
||||||
|
{ "intent_p1", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, intent_p1 ) },
|
||||||
|
{ "intent_p2", G_TYPE_FLOAT,
|
||||||
|
G_STRUCT_OFFSET( nifti_image, intent_p2 ) },
|
||||||
|
{ "intent_p3", G_TYPE_FLOAT,
|
||||||
|
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 vips_foreign_nifti_fields above.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
vips_gvalue_read( GValue *value, void *p )
|
||||||
|
{
|
||||||
|
switch( G_VALUE_TYPE( value ) ) {
|
||||||
|
case G_TYPE_INT:
|
||||||
|
g_value_set_int( value, *((int *) p) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case G_TYPE_FLOAT:
|
||||||
|
g_value_set_float( value, *((float *) p) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
g_warning( "vips_gvalue_read: unsupported GType %s",
|
||||||
|
g_type_name( G_VALUE_TYPE( value ) ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
vips_foreign_load_nifti_set_header( VipsForeignLoadNifti *nifti,
|
||||||
|
nifti_image *nim, VipsImage *out )
|
||||||
|
{
|
||||||
|
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( nifti );
|
||||||
|
|
||||||
|
guint width;
|
||||||
|
guint height;
|
||||||
|
guint bands;
|
||||||
|
VipsBandFormat fmt;
|
||||||
|
double xres;
|
||||||
|
double yres;
|
||||||
|
int i;
|
||||||
|
char txt[256];
|
||||||
|
|
||||||
|
if( nim->ndim < 1 ||
|
||||||
|
nim->ndim > 7 ) {
|
||||||
|
vips_error( class->nickname,
|
||||||
|
_( "%d-dimensional images not supported" ),
|
||||||
|
nim->ndim );
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
for( i = 1; i < 8 && i < nim->ndim + 1; i++ ) {
|
||||||
|
if( nim->dim[i] <= 0 ) {
|
||||||
|
vips_error( class->nickname,
|
||||||
|
"%s", _( "invalid dimension" ) );
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we have several images in a dimension, the spacing must
|
||||||
|
* be non-zero or we'll get a /0 error in resolution
|
||||||
|
* calculation.
|
||||||
|
*/
|
||||||
|
if( nim->dim[i] > 1 &&
|
||||||
|
nim->pixdim[i] == 0 ) {
|
||||||
|
vips_error( class->nickname,
|
||||||
|
"%s", _( "invalid resolution" ) );
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unfold higher dimensions vertically. bands is updated below for
|
||||||
|
* DT_RGB. Be careful to avoid height going over 2^31.
|
||||||
|
*/
|
||||||
|
bands = 1;
|
||||||
|
width = (guint) nim->nx;
|
||||||
|
height = (guint) nim->ny;
|
||||||
|
for( i = 3; i < 8 && i < nim->ndim + 1; i++ )
|
||||||
|
if( !g_uint_checked_mul( &height, height, nim->dim[i] ) ) {
|
||||||
|
vips_error( class->nickname,
|
||||||
|
"%s", _( "dimension overflow" ) );
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
if( height > INT_MAX ) {
|
||||||
|
vips_error( class->nickname, "%s", _( "dimension overflow" ) );
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt = vips__foreign_nifti_datatype2BandFmt( nim->datatype );
|
||||||
|
if( fmt == VIPS_FORMAT_NOTSET ) {
|
||||||
|
vips_error( class->nickname,
|
||||||
|
_( "datatype %d not supported" ), nim->datatype );
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( nim->datatype == DT_RGB )
|
||||||
|
bands = 3;
|
||||||
|
if( nim->datatype == DT_RGBA32 )
|
||||||
|
bands = 4;
|
||||||
|
|
||||||
|
/* We fold y and z together, so they must have the same resolution..
|
||||||
|
*/
|
||||||
|
xres = 1.0;
|
||||||
|
yres = 1.0;
|
||||||
|
if( nim->nz == 1 ||
|
||||||
|
nim->dz == nim->dy )
|
||||||
|
switch( nim->xyz_units ) {
|
||||||
|
case NIFTI_UNITS_METER:
|
||||||
|
xres = 1000.0 / nim->dx;
|
||||||
|
yres = 1000.0 / nim->dy;
|
||||||
|
break;
|
||||||
|
case NIFTI_UNITS_MM:
|
||||||
|
xres = 1.0 / nim->dx;
|
||||||
|
yres = 1.0 / nim->dy;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NIFTI_UNITS_MICRON:
|
||||||
|
xres = 1.0 / (1000.0 * nim->dx);
|
||||||
|
yres = 1.0 / (1000.0 * nim->dy);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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*/
|
||||||
|
|
||||||
|
vips_image_pipelinev( out, VIPS_DEMAND_STYLE_SMALLTILE, NULL );
|
||||||
|
vips_image_init_fields( out,
|
||||||
|
width, height, bands, fmt,
|
||||||
|
VIPS_CODING_NONE,
|
||||||
|
bands == 1 ?
|
||||||
|
VIPS_INTERPRETATION_B_W : VIPS_INTERPRETATION_sRGB,
|
||||||
|
xres, yres );
|
||||||
|
|
||||||
|
/* Set some vips metadata for every nifti header field.
|
||||||
|
*/
|
||||||
|
if( vips__foreign_nifti_map( vips_foreign_load_nifti_set, nim, out ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
/* One byte longer than the spec to leave space for any extra
|
||||||
|
* '\0' termination.
|
||||||
|
*/
|
||||||
|
vips_strncpy( txt, nim->intent_name, 17 );
|
||||||
|
vips_image_set_string( out, "nifti-intent_name", txt );
|
||||||
|
vips_strncpy( txt, nim->descrip, 81 );
|
||||||
|
vips_image_set_string( out, "nifti-descrip", txt );
|
||||||
|
|
||||||
|
for( i = 0; i < nim->num_ext; i++ ) {
|
||||||
|
nifti1_extension *ext = &nim->ext_list[i];
|
||||||
|
char *data_copy;
|
||||||
|
|
||||||
|
vips_snprintf( txt, 256, "nifti-ext-%d-%d", i, ext->ecode );
|
||||||
|
if( !(data_copy = vips_malloc( NULL, ext->esize )) )
|
||||||
|
return( -1 );
|
||||||
|
memcpy( data_copy, ext->edata, ext->esize );
|
||||||
|
vips_image_set_blob( out, txt,
|
||||||
|
(VipsCallbackFn) vips_free, data_copy, ext->esize );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( nim->ny > 1 )
|
||||||
|
vips_image_set_int( out, VIPS_META_PAGE_HEIGHT, nim->ny );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
vips_foreign_load_nifti_header( VipsForeignLoad *load )
|
||||||
|
{
|
||||||
|
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( load );
|
||||||
|
VipsForeignLoadNifti *nifti = (VipsForeignLoadNifti *) load;
|
||||||
|
|
||||||
|
/* We can't use the (much faster) nifti_read_header() since it just
|
||||||
|
* reads the 348 bytes of the analyze struct and does not read any of
|
||||||
|
* the extension fields.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* FALSE means don't read data, just the header. Use
|
||||||
|
* nifti_image_load() later to pull the data in.
|
||||||
|
*/
|
||||||
|
if( !(nifti->nim = nifti_image_read( nifti->filename, FALSE )) ) {
|
||||||
|
vips_error( class->nickname,
|
||||||
|
"%s", _( "unable to read NIFTI header" ) );
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( vips_foreign_load_nifti_set_header( nifti,
|
||||||
|
nifti->nim, load->out ) ) {
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
VIPS_SETSTR( load->out->filename, nifti->filename );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
vips_foreign_load_nifti_load( VipsForeignLoad *load )
|
||||||
|
{
|
||||||
|
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( load );
|
||||||
|
VipsForeignLoadNifti *nifti = (VipsForeignLoadNifti *) load;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf( "vips_foreign_load_nifti_load: loading image\n" );
|
||||||
|
#endif /*DEBUG*/
|
||||||
|
|
||||||
|
/* We just read the entire image to memory.
|
||||||
|
*/
|
||||||
|
if( nifti_image_load( nifti->nim ) ) {
|
||||||
|
vips_error( class->nickname,
|
||||||
|
"%s", _( "unable to load NIFTI file" ) );
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !(nifti->memory = vips_image_new_from_memory(
|
||||||
|
nifti->nim->data, VIPS_IMAGE_SIZEOF_IMAGE( load->out ),
|
||||||
|
load->out->Xsize, load->out->Ysize,
|
||||||
|
load->out->Bands, load->out->BandFmt )) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
if( vips_copy( nifti->memory, &load->real, NULL ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *vips__nifti_suffs[] = {
|
||||||
|
".nii", ".nii.gz",
|
||||||
|
".hdr", ".hdr.gz",
|
||||||
|
".img", ".img.gz",
|
||||||
|
".nia", ".nia.gz",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
vips_foreign_load_nifti_class_init( VipsForeignLoadNiftiClass *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->dispose = vips_foreign_load_nifti_dispose;
|
||||||
|
gobject_class->set_property = vips_object_set_property;
|
||||||
|
gobject_class->get_property = vips_object_get_property;
|
||||||
|
|
||||||
|
object_class->nickname = "niftiload";
|
||||||
|
object_class->description = _( "load a NIFTI image" );
|
||||||
|
|
||||||
|
/* is_a() is not that quick ... lower the priority.
|
||||||
|
*/
|
||||||
|
foreign_class->priority = -50;
|
||||||
|
|
||||||
|
foreign_class->suffs = vips__nifti_suffs;
|
||||||
|
|
||||||
|
load_class->is_a = vips_foreign_load_nifti_is_a;
|
||||||
|
load_class->header = vips_foreign_load_nifti_header;
|
||||||
|
load_class->load = vips_foreign_load_nifti_load;
|
||||||
|
|
||||||
|
VIPS_ARG_STRING( class, "filename", 1,
|
||||||
|
_( "Filename" ),
|
||||||
|
_( "Filename to load from" ),
|
||||||
|
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||||
|
G_STRUCT_OFFSET( VipsForeignLoadNifti, filename ),
|
||||||
|
NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vips_foreign_load_nifti_init( VipsForeignLoadNifti *nifti )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /*HAVE_CFITSIO*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vips_niftiload:
|
||||||
|
* @filename: file to load
|
||||||
|
* @out: (out): decompressed image
|
||||||
|
* @...: %NULL-terminated list of optional named arguments
|
||||||
|
*
|
||||||
|
* Read a NIFTI image file into a VIPS image.
|
||||||
|
*
|
||||||
|
* NIFTI metadata is attached with the "nifti-" prefix.
|
||||||
|
*
|
||||||
|
* See also: vips_image_new_from_file().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
vips_niftiload( const char *filename, VipsImage **out, ... )
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
va_start( ap, out );
|
||||||
|
result = vips_call_split( "niftiload", ap, filename, out );
|
||||||
|
va_end( ap );
|
||||||
|
|
||||||
|
return( result );
|
||||||
|
}
|
486
libvips/foreign/niftisave.c
Normal file
486
libvips/foreign/niftisave.c
Normal file
@ -0,0 +1,486 @@
|
|||||||
|
/* save to nifti
|
||||||
|
*
|
||||||
|
* 5/7/18
|
||||||
|
* - from fitssave.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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
#define DEBUG_VERBOSE
|
||||||
|
#define DEBUG
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif /*HAVE_CONFIG_H*/
|
||||||
|
#include <vips/intl.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <vips/vips.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_NIFTI
|
||||||
|
|
||||||
|
#include <nifti1_io.h>
|
||||||
|
|
||||||
|
#include "pforeign.h"
|
||||||
|
|
||||||
|
typedef struct _VipsForeignSaveNifti {
|
||||||
|
VipsForeignSave parent_object;
|
||||||
|
|
||||||
|
/* Filename for save.
|
||||||
|
*/
|
||||||
|
char *filename;
|
||||||
|
|
||||||
|
nifti_image *nim;
|
||||||
|
|
||||||
|
} VipsForeignSaveNifti;
|
||||||
|
|
||||||
|
typedef VipsForeignSaveClass VipsForeignSaveNiftiClass;
|
||||||
|
|
||||||
|
G_DEFINE_TYPE( VipsForeignSaveNifti, vips_foreign_save_nifti,
|
||||||
|
VIPS_TYPE_FOREIGN_SAVE );
|
||||||
|
|
||||||
|
static void
|
||||||
|
vips_foreign_save_nifti_dispose( GObject *gobject )
|
||||||
|
{
|
||||||
|
VipsForeignSaveNifti *nifti = (VipsForeignSaveNifti *) gobject;
|
||||||
|
|
||||||
|
VIPS_FREEF( nifti_image_free, nifti->nim );
|
||||||
|
|
||||||
|
G_OBJECT_CLASS( vips_foreign_save_nifti_parent_class )->
|
||||||
|
dispose( gobject );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make ->nim from the vips header fields.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
vips_foreign_save_nifti_header_vips( VipsForeignSaveNifti *nifti,
|
||||||
|
VipsImage *image )
|
||||||
|
{
|
||||||
|
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( nifti );
|
||||||
|
|
||||||
|
int dims[8];
|
||||||
|
int datatype;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Most nifti images have this defaulted as 1.
|
||||||
|
*/
|
||||||
|
for( i = 0; i < VIPS_NUMBER( dims ); i++ )
|
||||||
|
dims[i] = 1;
|
||||||
|
|
||||||
|
dims[0] = 2;
|
||||||
|
dims[1] = image->Xsize;
|
||||||
|
dims[2] = image->Ysize;
|
||||||
|
|
||||||
|
if( vips_image_get_typeof( image, VIPS_META_PAGE_HEIGHT ) ) {
|
||||||
|
int page_height;
|
||||||
|
|
||||||
|
if( vips_image_get_int( image,
|
||||||
|
VIPS_META_PAGE_HEIGHT, &page_height ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
if( image->Ysize % page_height == 0 ) {
|
||||||
|
dims[0] = 3;
|
||||||
|
dims[2] = page_height;
|
||||||
|
dims[3] = image->Ysize / page_height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
datatype = vips__foreign_nifti_BandFmt2datatype( image->BandFmt );
|
||||||
|
if( datatype == -1 ) {
|
||||||
|
vips_error( class->nickname,
|
||||||
|
"%s", _( "unsupported libvips image type" ) );
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( image->Bands > 1 ) {
|
||||||
|
if( image->BandFmt != VIPS_FORMAT_UCHAR ) {
|
||||||
|
vips_error( class->nickname,
|
||||||
|
"%s", _( "8-bit colour images only" ) );
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( image->Bands == 3 )
|
||||||
|
datatype = DT_RGB;
|
||||||
|
else if( image->Bands == 4 )
|
||||||
|
datatype = DT_RGBA32;
|
||||||
|
else {
|
||||||
|
vips_error( class->nickname,
|
||||||
|
"%s", _( "3 or 4 band colour images only" ) );
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !(nifti->nim = nifti_make_new_nim( dims, datatype, FALSE )) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
nifti->nim->dx = 1.0 / image->Xres;
|
||||||
|
nifti->nim->dy = 1.0 / image->Yres;
|
||||||
|
nifti->nim->dz = 1.0 / image->Yres;
|
||||||
|
nifti->nim->xyz_units = NIFTI_UNITS_MM;
|
||||||
|
|
||||||
|
vips_snprintf( nifti->nim->descrip, sizeof( nifti->nim->descrip ),
|
||||||
|
"libvips-%s", VIPS_VERSION );
|
||||||
|
|
||||||
|
/* All other fields can stay at their default value.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct _VipsNdimInfo {
|
||||||
|
VipsImage *image;
|
||||||
|
nifti_image *nim;
|
||||||
|
int *dims;
|
||||||
|
int n;
|
||||||
|
} VipsNdimInfo;
|
||||||
|
|
||||||
|
static void *
|
||||||
|
vips_foreign_save_nifti_set_dims( const char *name,
|
||||||
|
GValue *value, glong offset, void *a, void *b )
|
||||||
|
{
|
||||||
|
VipsNdimInfo *info = (VipsNdimInfo *) a;
|
||||||
|
|
||||||
|
/* The first 8 members are the dims fields.
|
||||||
|
*/
|
||||||
|
if( info->n < 8 ) {
|
||||||
|
char vips_name[256];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
vips_snprintf( vips_name, 256, "nifti-%s", name );
|
||||||
|
if( vips_image_get_int( info->image, vips_name, &i ) ||
|
||||||
|
i <= 0 ||
|
||||||
|
i > VIPS_MAX_COORD )
|
||||||
|
return( info );
|
||||||
|
info->dims[info->n] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->n += 1;
|
||||||
|
|
||||||
|
return( NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* How I wish glib had something like this :( Just implement the ones we need
|
||||||
|
* for vips_foreign_nifti_fields above.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
vips_gvalue_write( GValue *value, void *p )
|
||||||
|
{
|
||||||
|
switch( G_VALUE_TYPE( value ) ) {
|
||||||
|
case G_TYPE_INT:
|
||||||
|
*((int *) p) = g_value_get_int( value );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case G_TYPE_FLOAT:
|
||||||
|
*((float *) p) = g_value_get_float( value );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
g_warning( "vips_gvalue_write: unsupported GType %s",
|
||||||
|
g_type_name( G_VALUE_TYPE( value ) ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
vips_foreign_save_nifti_set_fields( const char *name,
|
||||||
|
GValue *value, glong offset, void *a, void *b )
|
||||||
|
{
|
||||||
|
VipsNdimInfo *info = (VipsNdimInfo *) a;
|
||||||
|
|
||||||
|
/* The first 8 members are the dims fields. We set them above ^^^ --
|
||||||
|
* do the others in this pass.
|
||||||
|
*/
|
||||||
|
if( info->n >= 8 ) {
|
||||||
|
char vips_name[256];
|
||||||
|
GValue value_copy = { 0 };
|
||||||
|
|
||||||
|
vips_snprintf( vips_name, 256, "nifti-%s", name );
|
||||||
|
if( vips_image_get( info->image, vips_name, &value_copy ) )
|
||||||
|
return( info );
|
||||||
|
vips_gvalue_write( &value_copy, (gpointer) info->nim + offset );
|
||||||
|
g_value_unset( &value_copy );
|
||||||
|
}
|
||||||
|
|
||||||
|
info->n += 1;
|
||||||
|
|
||||||
|
return( NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
vips_foreign_save_nifti_ext( VipsImage *image,
|
||||||
|
const char *field, GValue *value, void *a )
|
||||||
|
{
|
||||||
|
nifti_image *nim = (nifti_image *) a;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
int ecode;
|
||||||
|
char *data;
|
||||||
|
size_t length;
|
||||||
|
|
||||||
|
if( !vips_isprefix( "nifti-ext-", field ) )
|
||||||
|
return( NULL );
|
||||||
|
|
||||||
|
/* The name is "nifti-ext-N-XX" where N is the index (discard this)
|
||||||
|
* and XX is the nifti ext ecode.
|
||||||
|
*/
|
||||||
|
if( sscanf( field, "nifti-ext-%d-%d", &i, &ecode ) != 2 ) {
|
||||||
|
vips_error( "niftisave",
|
||||||
|
"%s", _( "bad nifti-ext- field name" ) );
|
||||||
|
return( image );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( vips_image_get_blob( image, field, (void *) &data, &length ) )
|
||||||
|
return( image );
|
||||||
|
|
||||||
|
if( nifti_add_extension( nim, data, length, ecode ) ) {
|
||||||
|
vips_error( "niftisave",
|
||||||
|
"%s", _( "unable to attach nifti ext" ) );
|
||||||
|
return( image );
|
||||||
|
}
|
||||||
|
|
||||||
|
return( NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make ->nim from the nifti- fields.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
vips_foreign_save_nifti_header_nifti( VipsForeignSaveNifti *nifti,
|
||||||
|
VipsImage *image )
|
||||||
|
{
|
||||||
|
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( nifti );
|
||||||
|
|
||||||
|
VipsNdimInfo info;
|
||||||
|
int dims[8];
|
||||||
|
int datatype;
|
||||||
|
guint height;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Most nifti images have this defaulted as 1.
|
||||||
|
*/
|
||||||
|
for( i = 0; i < VIPS_NUMBER( dims ); i++ )
|
||||||
|
dims[i] = 1;
|
||||||
|
|
||||||
|
info.image = image;
|
||||||
|
info.dims = dims;
|
||||||
|
info.n = 0;
|
||||||
|
if( vips__foreign_nifti_map(
|
||||||
|
vips_foreign_save_nifti_set_dims, &info, NULL ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
/* page-height overrides ny if it makes sense. This might not be
|
||||||
|
* correct :(
|
||||||
|
*/
|
||||||
|
if( vips_image_get_typeof( image, VIPS_META_PAGE_HEIGHT ) ) {
|
||||||
|
int page_height;
|
||||||
|
|
||||||
|
if( vips_image_get_int( image,
|
||||||
|
VIPS_META_PAGE_HEIGHT, &page_height ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
if( image->Ysize % page_height == 0 ) {
|
||||||
|
dims[0] = 3;
|
||||||
|
dims[2] = page_height;
|
||||||
|
dims[3] = image->Ysize / page_height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
height = 1;
|
||||||
|
for( i = 2; i < VIPS_NUMBER( dims ) && i < dims[0] + 1; i++ )
|
||||||
|
if( !g_uint_checked_mul( &height, height, dims[i] ) ) {
|
||||||
|
vips_error( class->nickname,
|
||||||
|
"%s", _( "dimension overflow" ) );
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
if( image->Xsize != dims[1] ||
|
||||||
|
image->Ysize != height ) {
|
||||||
|
vips_error( class->nickname,
|
||||||
|
"%s", _( "bad image dimensions" ) );
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
datatype = vips__foreign_nifti_BandFmt2datatype( image->BandFmt );
|
||||||
|
if( datatype == -1 ) {
|
||||||
|
vips_error( class->nickname,
|
||||||
|
"%s", _( "unsupported libvips image type" ) );
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !(nifti->nim = nifti_make_new_nim( dims, datatype, FALSE )) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
info.image = image;
|
||||||
|
info.nim = nifti->nim;
|
||||||
|
info.n = 0;
|
||||||
|
if( vips__foreign_nifti_map(
|
||||||
|
vips_foreign_save_nifti_set_fields, &info, NULL ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
/* Attach any ext blocks.
|
||||||
|
*/
|
||||||
|
if( vips_image_map( image,
|
||||||
|
(VipsImageMapFn) vips_foreign_save_nifti_ext, nifti->nim ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
vips_foreign_save_nifti_build( VipsObject *object )
|
||||||
|
{
|
||||||
|
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
|
||||||
|
VipsForeignSave *save = (VipsForeignSave *) object;
|
||||||
|
VipsForeignSaveNifti *nifti = (VipsForeignSaveNifti *) object;
|
||||||
|
|
||||||
|
if( VIPS_OBJECT_CLASS( vips_foreign_save_nifti_parent_class )->
|
||||||
|
build( object ) )
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
|
if( nifti_set_filenames( nifti->nim, nifti->filename, FALSE, TRUE ) ) {
|
||||||
|
vips_error( class->nickname,
|
||||||
|
"%s", _( "unable to set nifti filename" ) );
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !(nifti->nim->data =
|
||||||
|
vips_image_write_to_memory( save->ready, NULL )) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
/* No return code!??!?!!
|
||||||
|
*/
|
||||||
|
nifti_image_write( nifti->nim );
|
||||||
|
|
||||||
|
/* We must free and NULL the pointer or nifti will try to free it for
|
||||||
|
* us.
|
||||||
|
*/
|
||||||
|
VIPS_FREE( nifti->nim->data );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save a bit of typing.
|
||||||
|
*/
|
||||||
|
#define UC VIPS_FORMAT_UCHAR
|
||||||
|
#define C VIPS_FORMAT_CHAR
|
||||||
|
#define US VIPS_FORMAT_USHORT
|
||||||
|
#define S VIPS_FORMAT_SHORT
|
||||||
|
#define UI VIPS_FORMAT_UINT
|
||||||
|
#define I VIPS_FORMAT_INT
|
||||||
|
#define F VIPS_FORMAT_FLOAT
|
||||||
|
#define X VIPS_FORMAT_COMPLEX
|
||||||
|
#define D VIPS_FORMAT_DOUBLE
|
||||||
|
#define DX VIPS_FORMAT_DPCOMPLEX
|
||||||
|
|
||||||
|
static int vips_nifti_bandfmt[10] = {
|
||||||
|
/* UC C US S UI I F X D DX */
|
||||||
|
UC, C, US, S, UI, I, F, X, D, DX
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
vips_foreign_save_nifti_class_init( VipsForeignSaveNiftiClass *class )
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
||||||
|
VipsObjectClass *object_class = (VipsObjectClass *) class;
|
||||||
|
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
|
||||||
|
VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class;
|
||||||
|
|
||||||
|
gobject_class->dispose = vips_foreign_save_nifti_dispose;
|
||||||
|
gobject_class->set_property = vips_object_set_property;
|
||||||
|
gobject_class->get_property = vips_object_get_property;
|
||||||
|
|
||||||
|
object_class->nickname = "niftisave";
|
||||||
|
object_class->description = _( "save image to nifti file" );
|
||||||
|
object_class->build = vips_foreign_save_nifti_build;
|
||||||
|
|
||||||
|
foreign_class->suffs = vips__nifti_suffs;
|
||||||
|
|
||||||
|
save_class->saveable = VIPS_SAVEABLE_ANY;
|
||||||
|
save_class->format_table = vips_nifti_bandfmt;
|
||||||
|
|
||||||
|
VIPS_ARG_STRING( class, "filename", 1,
|
||||||
|
_( "Filename" ),
|
||||||
|
_( "Filename to save to" ),
|
||||||
|
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||||
|
G_STRUCT_OFFSET( VipsForeignSaveNifti, filename ),
|
||||||
|
NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vips_foreign_save_nifti_init( VipsForeignSaveNifti *nifti )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /*HAVE_NIFTI*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vips_niftisave: (method)
|
||||||
|
* @in: image to save
|
||||||
|
* @filename: file to write to
|
||||||
|
* @...: %NULL-terminated list of optional named arguments
|
||||||
|
*
|
||||||
|
* Write a VIPS image to a file in NIFTI format.
|
||||||
|
*
|
||||||
|
* Use the various NIFTI suffixes to pick the nifti save format.
|
||||||
|
*
|
||||||
|
* See also: vips_image_write_to_file(), vips_niftiload().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
vips_niftisave( VipsImage *in, const char *filename, ... )
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
va_start( ap, filename );
|
||||||
|
result = vips_call_split( "niftisave", ap, in, filename );
|
||||||
|
va_end( ap );
|
||||||
|
|
||||||
|
return( result );
|
||||||
|
}
|
@ -35,6 +35,16 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif /*__cplusplus*/
|
#endif /*__cplusplus*/
|
||||||
|
|
||||||
|
/* 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*/
|
||||||
|
|
||||||
void vips__tiff_init( void );
|
void vips__tiff_init( void );
|
||||||
|
|
||||||
int vips__tiff_write( VipsImage *in, const char *filename,
|
int vips__tiff_write( VipsImage *in, const char *filename,
|
||||||
@ -256,6 +266,15 @@ int vips__quantise_image( VipsImage *in,
|
|||||||
VipsImage **index_out, VipsImage **palette_out,
|
VipsImage **index_out, VipsImage **palette_out,
|
||||||
int colours, int Q, double dither );
|
int colours, int Q, double dither );
|
||||||
|
|
||||||
|
extern const char *vips__nifti_suffs[];
|
||||||
|
|
||||||
|
VipsBandFormat vips__foreign_nifti_datatype2BandFmt( int datatype );
|
||||||
|
int vips__foreign_nifti_BandFmt2datatype( VipsBandFormat fmt );
|
||||||
|
|
||||||
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /*__cplusplus*/
|
#endif /*__cplusplus*/
|
||||||
|
@ -560,6 +560,11 @@ int vips_gifload( const char *filename, VipsImage **out, ... )
|
|||||||
int vips_gifload_buffer( void *buf, size_t len, VipsImage **out, ... )
|
int vips_gifload_buffer( void *buf, size_t len, VipsImage **out, ... )
|
||||||
__attribute__((sentinel));
|
__attribute__((sentinel));
|
||||||
|
|
||||||
|
int vips_niftiload( const char *filename, VipsImage **out, ... )
|
||||||
|
__attribute__((sentinel));
|
||||||
|
int vips_niftisave( VipsImage *in, const char *filename, ... )
|
||||||
|
__attribute__((sentinel));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* VipsForeignDzLayout:
|
* VipsForeignDzLayout:
|
||||||
* @VIPS_FOREIGN_DZ_LAYOUT_DZ: use DeepZoom directory layout
|
* @VIPS_FOREIGN_DZ_LAYOUT_DZ: use DeepZoom directory layout
|
||||||
|
@ -454,6 +454,26 @@ transform_save_string_double( const GValue *src_value, GValue *dest_value )
|
|||||||
NULL ) );
|
NULL ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
transform_float_save_string( const GValue *src_value, GValue *dest_value )
|
||||||
|
{
|
||||||
|
char buf[G_ASCII_DTOSTR_BUF_SIZE];
|
||||||
|
|
||||||
|
/* Need to be locale independent.
|
||||||
|
*/
|
||||||
|
g_ascii_dtostr( buf, G_ASCII_DTOSTR_BUF_SIZE,
|
||||||
|
g_value_get_float( src_value ) );
|
||||||
|
vips_value_set_save_string( dest_value, buf );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
transform_save_string_float( const GValue *src_value, GValue *dest_value )
|
||||||
|
{
|
||||||
|
g_value_set_float( dest_value,
|
||||||
|
g_ascii_strtod( vips_value_get_save_string( src_value ),
|
||||||
|
NULL ) );
|
||||||
|
}
|
||||||
|
|
||||||
/* Save meta fields to the header. We have a new string type for header fields
|
/* Save meta fields to the header. We have a new string type for header fields
|
||||||
* to save to XML and define transform functions to go from our meta types to
|
* to save to XML and define transform functions to go from our meta types to
|
||||||
* this string type.
|
* this string type.
|
||||||
@ -1847,4 +1867,8 @@ vips__meta_init_types( void )
|
|||||||
transform_double_save_string );
|
transform_double_save_string );
|
||||||
g_value_register_transform_func( VIPS_TYPE_SAVE_STRING, G_TYPE_DOUBLE,
|
g_value_register_transform_func( VIPS_TYPE_SAVE_STRING, G_TYPE_DOUBLE,
|
||||||
transform_save_string_double );
|
transform_save_string_double );
|
||||||
|
g_value_register_transform_func( G_TYPE_FLOAT, VIPS_TYPE_SAVE_STRING,
|
||||||
|
transform_float_save_string );
|
||||||
|
g_value_register_transform_func( VIPS_TYPE_SAVE_STRING, G_TYPE_FLOAT,
|
||||||
|
transform_save_string_float );
|
||||||
}
|
}
|
||||||
|
@ -840,6 +840,10 @@ build_xml_meta( VipsMeta *meta, VipsDbuf *dbuf )
|
|||||||
|
|
||||||
g_value_unset( &save_value );
|
g_value_unset( &save_value );
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
printf( "unable to convert %s for save\n",
|
||||||
|
g_type_name( type ) );
|
||||||
|
}
|
||||||
|
|
||||||
return( NULL );
|
return( NULL );
|
||||||
}
|
}
|
||||||
|
122
m4/nifti.m4
Normal file
122
m4/nifti.m4
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
dnl From FIND_MOTIF and ACX_PTHREAD, without much understanding
|
||||||
|
dnl
|
||||||
|
dnl FIND_NIFTI[ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]
|
||||||
|
dnl ------------------------------------------------
|
||||||
|
dnl
|
||||||
|
dnl Find NIFTI libraries and headers
|
||||||
|
dnl
|
||||||
|
dnl Put compile stuff in NIFTI_INCLUDES
|
||||||
|
dnl Put link stuff in NIFTI_LIBS
|
||||||
|
dnl Define HAVE_NIFTI if found
|
||||||
|
dnl
|
||||||
|
AC_DEFUN([FIND_NIFTI], [
|
||||||
|
AC_REQUIRE([AC_PATH_XTRA])
|
||||||
|
|
||||||
|
NIFTI_INCLUDES=""
|
||||||
|
NIFTI_LIBS=""
|
||||||
|
|
||||||
|
AC_ARG_WITH(nifti,
|
||||||
|
AS_HELP_STRING([--without-nifti], [build without nifti (default: test)]))
|
||||||
|
# Treat --without-nifti like --without-nifti-includes --without-nifti-libraries.
|
||||||
|
if test "$with_nifti" = "no"; then
|
||||||
|
NIFTI_INCLUDES=no
|
||||||
|
NIFTI_LIBS=no
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_ARG_WITH(nifti-includes,
|
||||||
|
AS_HELP_STRING([--with-nifti-includes=DIR], [libniftiio includes are in DIR]),
|
||||||
|
NIFTI_INCLUDES="-I$withval"
|
||||||
|
)
|
||||||
|
AC_ARG_WITH(nifti-libraries,
|
||||||
|
AS_HELP_STRING([--with-nifti-libraries=DIR],
|
||||||
|
[libniftiio libraries are in DIR]),
|
||||||
|
NIFTI_LIBS="-L$withval -lniftiio"
|
||||||
|
)
|
||||||
|
|
||||||
|
AC_MSG_CHECKING(for NIFTI)
|
||||||
|
|
||||||
|
# Look for nifti1_io.h ... usually in /usr/include/nifti
|
||||||
|
if test "$NIFTI_INCLUDES" = ""; then
|
||||||
|
nifti_save_CFLAGS="$CFLAGS"
|
||||||
|
|
||||||
|
# annoyingly, the header must be unqualified, so we have to add to the
|
||||||
|
# search path
|
||||||
|
CFLAGS="-I/usr/include/nifti $nifti_save_CFLAGS"
|
||||||
|
|
||||||
|
AC_TRY_COMPILE([#include <nifti1_io.h>],[int a;],[
|
||||||
|
NIFTI_INCLUDES="-I/usr/include/nifti"
|
||||||
|
], [
|
||||||
|
# not in the standard search path, try $prefix
|
||||||
|
CFLAGS="-I${prefix}/include/nifti $nifti_save_CFLAGS"
|
||||||
|
|
||||||
|
AC_TRY_COMPILE([#include <nifti1_io.h>],[int a;],[
|
||||||
|
NIFTI_INCLUDES="-I${prefix}/include/nifti"
|
||||||
|
], [
|
||||||
|
NIFTI_INCLUDES="no"
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
|
CFLAGS="$nifti_save_CFLAGS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Now for the libraries
|
||||||
|
if test "$NIFTI_LIBS" = ""; then
|
||||||
|
nifti_save_LIBS="$LIBS"
|
||||||
|
nifti_save_CFLAGS="$CFLAGS"
|
||||||
|
|
||||||
|
LIBS="-lniftiio -lm $nifti_save_LIBS"
|
||||||
|
CFLAGS="$NIFTI_INCLUDES $CFLAGS"
|
||||||
|
|
||||||
|
# Try the standard search path first
|
||||||
|
AC_TRY_LINK([#include <nifti1_io.h>],[is_nifti_file("")], [
|
||||||
|
NIFTI_LIBS="-lniftiio"
|
||||||
|
], [
|
||||||
|
# libniftiio is not in the standard search path, try $prefix
|
||||||
|
|
||||||
|
LIBS="-L${prefix}/lib $LIBS"
|
||||||
|
|
||||||
|
AC_TRY_LINK([#include <nifti1_io.h>],[is_nifti_file("")], [
|
||||||
|
NIFTI_LIBS="-L${prefix}/lib -lniftiio"
|
||||||
|
], [
|
||||||
|
NIFTI_LIBS=no
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
|
LIBS="$nifti_save_LIBS"
|
||||||
|
CFLAGS="$nifti_save_CFLAGS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_SUBST(NIFTI_LIBS)
|
||||||
|
AC_SUBST(NIFTI_INCLUDES)
|
||||||
|
|
||||||
|
# Print a helpful message
|
||||||
|
nifti_libraries_result="$NIFTI_LIBS"
|
||||||
|
nifti_includes_result="$NIFTI_INCLUDES"
|
||||||
|
|
||||||
|
if test x"$nifti_libraries_result" = x""; then
|
||||||
|
nifti_libraries_result="in default path"
|
||||||
|
fi
|
||||||
|
if test x"$nifti_includes_result" = x""; then
|
||||||
|
nifti_includes_result="in default path"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$nifti_libraries_result" = "no"; then
|
||||||
|
nifti_libraries_result="(none)"
|
||||||
|
fi
|
||||||
|
if test "$nifti_includes_result" = "no"; then
|
||||||
|
nifti_includes_result="(none)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_MSG_RESULT([libraries $nifti_libraries_result, headers $nifti_includes_result])
|
||||||
|
|
||||||
|
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
|
||||||
|
if test "$NIFTI_INCLUDES" != "no" && test "$NIFTI_LIBS" != "no"; then
|
||||||
|
AC_DEFINE(HAVE_NIFTI,1,[Define if you have nifti libraries and header files.])
|
||||||
|
$1
|
||||||
|
else
|
||||||
|
NIFTI_INCLUDES=""
|
||||||
|
NIFTI_LIBS=""
|
||||||
|
$2
|
||||||
|
fi
|
||||||
|
|
||||||
|
])dnl
|
@ -27,6 +27,7 @@ SVG_GZ_FILE = os.path.join(IMAGES, "vips-profile.svg.gz")
|
|||||||
GIF_ANIM_FILE = os.path.join(IMAGES, "cogs.gif")
|
GIF_ANIM_FILE = os.path.join(IMAGES, "cogs.gif")
|
||||||
DICOM_FILE = os.path.join(IMAGES, "dicom_test_image.dcm")
|
DICOM_FILE = os.path.join(IMAGES, "dicom_test_image.dcm")
|
||||||
BMP_FILE = os.path.join(IMAGES, "MARBLES.BMP")
|
BMP_FILE = os.path.join(IMAGES, "MARBLES.BMP")
|
||||||
|
NIFTI_FILE = os.path.join(IMAGES, "avg152T1_LR_nifti.nii.gz")
|
||||||
|
|
||||||
unsigned_formats = [pyvips.BandFormat.UCHAR,
|
unsigned_formats = [pyvips.BandFormat.UCHAR,
|
||||||
pyvips.BandFormat.USHORT,
|
pyvips.BandFormat.USHORT,
|
||||||
|
BIN
test/test-suite/images/avg152T1_LR_nifti.nii.gz
Normal file
BIN
test/test-suite/images/avg152T1_LR_nifti.nii.gz
Normal file
Binary file not shown.
@ -6,12 +6,12 @@ import tempfile
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import pyvips
|
import pyvips
|
||||||
from helpers import JPEG_FILE, SRGB_FILE, \
|
from helpers import \
|
||||||
MATLAB_FILE, PNG_FILE, TIF_FILE, OME_FILE, ANALYZE_FILE, \
|
JPEG_FILE, SRGB_FILE, MATLAB_FILE, PNG_FILE, TIF_FILE, OME_FILE, \
|
||||||
GIF_FILE, WEBP_FILE, EXR_FILE, FITS_FILE, OPENSLIDE_FILE, \
|
ANALYZE_FILE, GIF_FILE, WEBP_FILE, EXR_FILE, FITS_FILE, OPENSLIDE_FILE, \
|
||||||
PDF_FILE, SVG_FILE, SVGZ_FILE, SVG_GZ_FILE, GIF_ANIM_FILE, \
|
PDF_FILE, SVG_FILE, SVGZ_FILE, SVG_GZ_FILE, GIF_ANIM_FILE, DICOM_FILE, \
|
||||||
DICOM_FILE, BMP_FILE, temp_filename, assert_almost_equal_objects, have, \
|
BMP_FILE, NIFTI_FILE, \
|
||||||
skip_if_no
|
temp_filename, assert_almost_equal_objects, have, skip_if_no
|
||||||
|
|
||||||
|
|
||||||
class TestForeign:
|
class TestForeign:
|
||||||
@ -532,6 +532,25 @@ class TestForeign:
|
|||||||
self.file_loader("fitsload", FITS_FILE, fits_valid)
|
self.file_loader("fitsload", FITS_FILE, fits_valid)
|
||||||
self.save_load("%s.fits", self.mono)
|
self.save_load("%s.fits", self.mono)
|
||||||
|
|
||||||
|
@skip_if_no("niftiload")
|
||||||
|
def test_niftiload(self):
|
||||||
|
def nifti_valid(im):
|
||||||
|
a = im(30, 26)
|
||||||
|
assert_almost_equal_objects(a, [131])
|
||||||
|
assert im.width == 91
|
||||||
|
assert im.height == 9919
|
||||||
|
assert im.bands == 1
|
||||||
|
|
||||||
|
print("NIFTI_FILE =", NIFTI_FILE)
|
||||||
|
im = pyvips.Operation.call("niftiload", NIFTI_FILE)
|
||||||
|
print("width = ", im.width)
|
||||||
|
|
||||||
|
im = pyvips.Operation.call("niftiload", "test/images/avg152T1_LR_nifti.nii.gz")
|
||||||
|
print("width = ", im.width)
|
||||||
|
|
||||||
|
self.file_loader("niftiload", NIFTI_FILE, nifti_valid)
|
||||||
|
self.save_load("%s.nii.gz", self.mono)
|
||||||
|
|
||||||
@skip_if_no("openslideload")
|
@skip_if_no("openslideload")
|
||||||
def test_openslideload(self):
|
def test_openslideload(self):
|
||||||
def openslide_valid(im):
|
def openslide_valid(im):
|
||||||
|
Loading…
Reference in New Issue
Block a user